]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.cc] all: merge master (b8fcae0) into dev.cc
authorRuss Cox <rsc@golang.org>
Wed, 4 Feb 2015 21:11:28 +0000 (16:11 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 4 Feb 2015 21:12:58 +0000 (16:12 -0500)
Change-Id: I2aa1d0b0c4cf7632a54e843810959b468e3812ab

338 files changed:
doc/go1.5.txt
doc/logo-153x55.png [deleted file]
doc/sieve.gif [deleted file]
include/link.h
include/u.h
misc/makerelease/makerelease.go
src/archive/tar/example_test.go
src/bytes/bytes.go
src/cmd/5a/a.h
src/cmd/5a/a.y
src/cmd/5a/lex.c
src/cmd/5a/y.tab.c
src/cmd/5a/y.tab.h
src/cmd/5g/cgen.c
src/cmd/5g/cgen64.c
src/cmd/5g/galign.c
src/cmd/5g/gg.h
src/cmd/5g/ggen.c
src/cmd/5g/gobj.c
src/cmd/5g/gsubr.c
src/cmd/5g/opt.h
src/cmd/5g/peep.c
src/cmd/5g/prog.c
src/cmd/5g/reg.c
src/cmd/5l/5.out.h
src/cmd/6a/a.h
src/cmd/6a/a.y
src/cmd/6a/lex.c
src/cmd/6a/y.tab.c
src/cmd/6g/cgen.c
src/cmd/6g/galign.c
src/cmd/6g/gg.h
src/cmd/6g/ggen.c
src/cmd/6g/gobj.c
src/cmd/6g/gsubr.c
src/cmd/6g/opt.h
src/cmd/6g/peep.c
src/cmd/6g/prog.c
src/cmd/6g/reg.c
src/cmd/6l/6.out.h
src/cmd/8a/a.h
src/cmd/8a/a.y
src/cmd/8a/lex.c
src/cmd/8a/y.tab.c
src/cmd/8a/y.tab.h
src/cmd/8g/cgen.c
src/cmd/8g/cgen64.c
src/cmd/8g/galign.c
src/cmd/8g/gg.h
src/cmd/8g/ggen.c
src/cmd/8g/gobj.c
src/cmd/8g/gsubr.c
src/cmd/8g/opt.h
src/cmd/8g/peep.c
src/cmd/8g/prog.c
src/cmd/8g/reg.c
src/cmd/8l/8.out.h
src/cmd/9a/a.h
src/cmd/9a/a.y
src/cmd/9a/lex.c
src/cmd/9a/y.tab.c
src/cmd/9a/y.tab.h
src/cmd/9g/cgen.c
src/cmd/9g/galign.c
src/cmd/9g/gg.h
src/cmd/9g/ggen.c
src/cmd/9g/gobj.c
src/cmd/9g/gsubr.c
src/cmd/9g/opt.h
src/cmd/9g/peep.c
src/cmd/9g/prog.c
src/cmd/9g/reg.c
src/cmd/9l/9.out.h
src/cmd/cgo/gcc.go
src/cmd/cgo/main.go
src/cmd/dist/build.go
src/cmd/dist/buildgc.go
src/cmd/dist/buildruntime.go
src/cmd/dist/vfp_arm.s
src/cmd/gc/align.c
src/cmd/gc/array.c
src/cmd/gc/builtin.c
src/cmd/gc/bv.c
src/cmd/gc/closure.c
src/cmd/gc/cplx.c
src/cmd/gc/dcl.c
src/cmd/gc/esc.c
src/cmd/gc/export.c
src/cmd/gc/fmt.c
src/cmd/gc/gen.c
src/cmd/gc/go.h
src/cmd/gc/inl.c
src/cmd/gc/lex.c
src/cmd/gc/obj.c
src/cmd/gc/order.c
src/cmd/gc/pgen.c
src/cmd/gc/plive.c
src/cmd/gc/popt.c
src/cmd/gc/popt.h [deleted file]
src/cmd/gc/racewalk.c
src/cmd/gc/range.c
src/cmd/gc/reflect.c
src/cmd/gc/runtime.go
src/cmd/gc/sinit.c
src/cmd/gc/subr.c
src/cmd/gc/swt.c
src/cmd/gc/typecheck.c
src/cmd/gc/unsafe.c
src/cmd/gc/walk.c
src/cmd/go/build.go
src/cmd/go/doc.go
src/cmd/go/fix.go
src/cmd/go/get.go
src/cmd/go/pkg.go
src/cmd/go/test.go
src/cmd/go/testflag.go
src/cmd/go/vet.go
src/cmd/ld/decodesym.c
src/cmd/ld/dwarf.c
src/cmd/ld/lib.c
src/crypto/ecdsa/ecdsa.go
src/crypto/ecdsa/ecdsa_test.go
src/crypto/tls/cipher_suites.go
src/crypto/tls/handshake_client.go
src/crypto/tls/handshake_client_test.go
src/crypto/tls/handshake_server.go
src/crypto/tls/handshake_server_test.go
src/crypto/tls/prf.go
src/crypto/tls/prf_test.go
src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
src/crypto/tls/testdata/Client-TLSv12-ALPN
src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 [new file with mode: 0644]
src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
src/crypto/tls/testdata/Server-TLSv12-ALPN
src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 [new file with mode: 0644]
src/crypto/x509/pkix/pkix.go
src/crypto/x509/x509.go
src/crypto/x509/x509_test.go
src/database/sql/sql.go
src/database/sql/sql_test.go
src/encoding/json/decode.go
src/encoding/json/decode_test.go
src/expvar/expvar.go
src/fmt/fmt_test.go
src/go/ast/filter.go
src/go/doc/exports.go
src/go/doc/testdata/blank.0.golden
src/go/doc/testdata/blank.1.golden
src/go/doc/testdata/blank.2.golden
src/go/doc/testdata/blank.go
src/go/parser/parser.go
src/go/parser/short_test.go
src/go/printer/nodes.go
src/go/printer/printer.go
src/go/printer/testdata/comments.golden
src/go/printer/testdata/comments.input
src/go/printer/testdata/declarations.golden
src/go/printer/testdata/declarations.input
src/html/template/doc.go
src/image/image.go
src/internal/syscall/getrandom_linux.go
src/lib9/tokenize.c
src/liblink/asm5.c
src/liblink/asm6.c
src/liblink/asm8.c
src/liblink/asm9.c
src/liblink/data.c
src/liblink/go.c
src/liblink/ld.c
src/liblink/list5.c
src/liblink/list6.c
src/liblink/list8.c
src/liblink/list9.c
src/liblink/obj5.c
src/liblink/obj6.c
src/liblink/obj8.c
src/liblink/obj9.c
src/liblink/objfile.c
src/liblink/objfilego.c
src/liblink/pass.c
src/liblink/pcln.c
src/liblink/sym.c
src/log/log.go
src/make.bash
src/make.rc
src/math/big/decimal.go [new file with mode: 0644]
src/math/big/decimal_test.go [new file with mode: 0644]
src/math/big/float.go [new file with mode: 0644]
src/math/big/float_test.go [new file with mode: 0644]
src/math/big/floatconv.go [new file with mode: 0644]
src/math/big/floatconv_test.go [new file with mode: 0644]
src/math/big/int.go
src/math/big/int_test.go
src/math/big/intconv.go [new file with mode: 0644]
src/math/big/intconv_test.go [new file with mode: 0644]
src/math/big/nat.go
src/math/big/nat_test.go
src/math/big/natconv.go [new file with mode: 0644]
src/math/big/natconv_test.go [new file with mode: 0644]
src/math/big/rat.go
src/math/big/rat_test.go
src/math/big/ratconv.go [new file with mode: 0644]
src/math/big/ratconv_test.go [new file with mode: 0644]
src/net/cgo_bsd.go
src/net/dnsclient.go
src/net/dnsmsg_test.go
src/net/fd_plan9.go
src/net/fd_poll_nacl.go
src/net/fd_poll_runtime.go
src/net/fd_unix.go
src/net/fd_windows.go
src/net/http/main_test.go
src/net/http/pprof/pprof.go
src/net/http/request.go
src/net/http/serve_test.go
src/net/http/server.go
src/net/interface_test.go
src/net/ip.go
src/net/ipraw_test.go
src/net/ipsock.go
src/net/mockicmp_test.go [deleted file]
src/net/net.go
src/net/packetconn_test.go
src/net/parse.go
src/net/protoconn_test.go
src/net/server_test.go
src/os/os_unix_test.go
src/os/path_test.go
src/os/stat_plan9.go
src/path/filepath/path.go
src/path/filepath/path_plan9.go
src/path/filepath/path_test.go
src/path/filepath/path_unix.go
src/path/filepath/path_windows.go
src/reflect/all_test.go
src/reflect/export_test.go
src/reflect/makefunc.go
src/reflect/type.go
src/reflect/value.go
src/regexp/exec_test.go
src/runtime/arch1_amd64.go
src/runtime/asm_386.s
src/runtime/asm_amd64.s
src/runtime/cgocall.go
src/runtime/chan.go
src/runtime/debug.go
src/runtime/defs_linux_arm.go
src/runtime/export_test.go
src/runtime/extern.go
src/runtime/hashmap.go
src/runtime/lock_futex.go
src/runtime/lock_sema.go
src/runtime/malloc.go
src/runtime/malloc1.go
src/runtime/malloc2.go
src/runtime/malloc_test.go
src/runtime/mbarrier.go
src/runtime/mem.go
src/runtime/mem_plan9.go
src/runtime/mfinal.go
src/runtime/mgc.go
src/runtime/mgc0.go
src/runtime/mheap.go
src/runtime/mprof.go
src/runtime/netpoll.go
src/runtime/panic.go
src/runtime/panic1.go
src/runtime/parfor.go
src/runtime/parfor_test.go
src/runtime/pprof/pprof.go
src/runtime/pprof/pprof_test.go
src/runtime/pprof/trace_parser_test.go [new file with mode: 0644]
src/runtime/pprof/trace_test.go [new file with mode: 0644]
src/runtime/print1_write_android.go
src/runtime/proc.go
src/runtime/proc1.go
src/runtime/proc_test.go
src/runtime/runtime.go
src/runtime/runtime1.go
src/runtime/runtime2.go
src/runtime/select.go
src/runtime/sema.go
src/runtime/stack1.go
src/runtime/string.go
src/runtime/string_test.go
src/runtime/stubs.go
src/runtime/stubs_android.go [new file with mode: 0644]
src/runtime/sys_dragonfly_amd64.s
src/runtime/sys_freebsd_amd64.s
src/runtime/sys_linux_amd64.s
src/runtime/sys_linux_arm.s
src/runtime/sys_netbsd_amd64.s
src/runtime/sys_openbsd_amd64.s
src/runtime/time.go
src/runtime/trace.go [new file with mode: 0644]
src/runtime/traceback.go
src/runtime/type.go
src/strings/strings.go
src/syscall/asm_linux_386.s
src/syscall/asm_linux_amd64.s
src/testing/quick/quick.go
src/testing/quick/quick_test.go
src/testing/testing.go
src/unsafe/unsafe.go
test/closure1.go [new file with mode: 0644]
test/closure2.go [new file with mode: 0644]
test/escape2.go
test/escape2n.go
test/fixedbugs/issue9537.dir/a.go [new file with mode: 0644]
test/fixedbugs/issue9537.dir/b.go [new file with mode: 0644]
test/fixedbugs/issue9537.go [new file with mode: 0644]
test/fixedbugs/issue9634.go [new file with mode: 0644]
test/fixedbugs/issue9691.go [new file with mode: 0644]
test/fixedbugs/issue9731.go [new file with mode: 0644]
test/fixedbugs/issue9738.go [new file with mode: 0644]
test/nosplit.go

index 19ce060164b104307dce0412bc24d53afbfcf42a..f1b443417dd28d0bad7f926931e8b83ce4fba067 100644 (file)
@@ -9,11 +9,12 @@ crypto/cipher: clarify what will happen if len(src) != len(dst) for the Stream i
 crypto/elliptic: add Name field to CurveParams struct (https://golang.org/cl/2133)
 crypto/tls: change default minimum version to TLS 1.0. (https://golang.org/cl/1791)
 encoding/base64: add unpadded encodings (https://golang.org/cl/1511)
-log: add global Output function (https://golang.org/cl/2686)
+log: add SetOutput functions (https://golang.org/cl/2686, https://golang.org/cl/3023)
 net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157)
 net/smtp: add TLSConnectionState accessor (https://golang.org/cl/2151)
 runtime, syscall: use SYSCALL instruction on FreeBSD (Go 1.5 now requires FreeBSD 8-STABLE+) (https://golang.org/cl/3020)
 strings: add Compare(x, y string) int, for symmetry with bytes.Compare (https://golang.org/cl/2828)
+testing/quick: support generation of arrays (https://golang.org/cl/3865)
 
 Tools:
 
diff --git a/doc/logo-153x55.png b/doc/logo-153x55.png
deleted file mode 100644 (file)
index 8ec22aa..0000000
Binary files a/doc/logo-153x55.png and /dev/null differ
diff --git a/doc/sieve.gif b/doc/sieve.gif
deleted file mode 100644 (file)
index 8018ae2..0000000
Binary files a/doc/sieve.gif and /dev/null differ
index 5dffe7bc6435516eda14ab541b93386bc9218735..bc0a96026a8f940c59193c69f4a49e11246775c2 100644 (file)
@@ -43,32 +43,156 @@ typedef    struct  Pcln    Pcln;
 typedef        struct  Pcdata  Pcdata;
 typedef        struct  Pciter  Pciter;
 
-// prevent incompatible type signatures between liblink and 8l on Plan 9
-#pragma incomplete struct Node
-
+// An Addr is an argument to an instruction.
+// The general forms and their encodings are:
+//
+//     sym±offset(symkind)(reg)(index*scale)
+//             Memory reference at address &sym(symkind) + offset + reg + index*scale.
+//             Any of sym(symkind), Â±offset, (reg), (index*scale), and *scale can be omitted.
+//             If (reg) and *scale are both omitted, the resulting expression (index) is parsed as (reg).
+//             To force a parsing as index*scale, write (index*1).
+//             Encoding:
+//                     type = TYPE_MEM
+//                     name = symkind (NAME_AUTO, ...) or 0 (NAME_NONE)
+//                     sym = sym
+//                     offset = Â±offset
+//                     reg = reg (REG_*)
+//                     index = index (REG_*)
+//                     scale = scale (1, 2, 4, 8)
+//
+//     $<mem>
+//             Effective address of memory reference <mem>, defined above.
+//             Encoding: same as memory reference, but type = TYPE_ADDR.
+//
+//     $<±integer value>
+//             This is a special case of $<mem>, in which only Â±offset is present.
+//             It has a separate type for easy recognition.
+//             Encoding:
+//                     type = TYPE_CONST
+//                     offset = Â±integer value
+//
+//     *<mem>
+//             Indirect reference through memory reference <mem>, defined above.
+//             Only used on x86 for CALL/JMP *sym(SB), which calls/jumps to a function
+//             pointer stored in the data word sym(SB), not a function named sym(SB).
+//             Encoding: same as above, but type = TYPE_INDIR.
+//
+//     $*$<mem>
+//             No longer used.
+//             On machines with actual SB registers, $*$<mem> forced the
+//             instruction encoding to use a full 32-bit constant, never a
+//             reference relative to SB.
+//
+//     $<floating point literal>
+//             Floating point constant value.
+//             Encoding:
+//                     type = TYPE_FCONST
+//                     u.dval = floating point value
+//
+//     $<string literal, up to 8 chars>
+//             String literal value (raw bytes used for DATA instruction).
+//             Encoding:
+//                     type = TYPE_SCONST
+//                     u.sval = string
+//
+//     <register name>
+//             Any register: integer, floating point, control, segment, and so on.
+//             If looking for specific register kind, must check type and reg value range.
+//             Encoding:
+//                     type = TYPE_REG
+//                     reg = reg (REG_*)
+//
+//     x(PC)
+//             Encoding:
+//                     type = TYPE_BRANCH
+//                     u.branch = Prog* reference OR ELSE offset = target pc (branch takes priority)
+//
+//     $±x-±y
+//             Final argument to TEXT, specifying local frame size x and argument size y.
+//             In this form, x and y are integer literals only, not arbitrary expressions.
+//             This avoids parsing ambiguities due to the use of - as a separator.
+//             The Â± are optional.
+//             If the final argument to TEXT omits the -±y, the encoding should still
+//             use TYPE_TEXTSIZE (not TYPE_CONST), with u.argsize = ArgsSizeUnknown.
+//             Encoding:
+//                     type = TYPE_TEXTSIZE
+//                     offset = x
+//                     u.argsize = y
+//
+//     reg<<shift, reg>>shift, reg->shift, reg@>shift
+//             Shifted register value, for ARM.
+//             In this form, reg must be a register and shift can be a register or an integer constant.
+//             Encoding:
+//                     type = TYPE_SHIFT
+//                     offset = (reg&15) | shifttype<<5 | count
+//                     shifttype = 0, 1, 2, 3 for <<, >>, ->, @>
+//                     count = (reg&15)<<8 | 1<<4 for a register shift count, (n&31)<<7 for an integer constant.
+//
+//     (reg, reg)
+//             A destination register pair. When used as the last argument of an instruction,
+//             this form makes clear that both registers are destinations.
+//             Encoding:
+//                     type = TYPE_REGREG
+//                     reg = first register
+//                     offset = second register
+//
+//     reg, reg
+//             TYPE_REGREG2, to be removed.
+//
 struct Addr
 {
-       vlong   offset;
-
+       int16   type; // could be int8
+       int16   reg;
+       int16   index;
+       int8    scale;
+       int8    name;
+       int64   offset;
+       LSym*   sym;
+       
        union
        {
                char    sval[8];
                float64 dval;
-               Prog*   branch; // for 5g, 6g, 8g, 9g
+               Prog*   branch;
+               int32   argsize;        // for 5l, 8l
+               uint64  bits; // raw union bits, for testing if anything has been written to any field
        } u;
 
-       LSym*   sym;
+       // gotype is the name of the Go type descriptor for sym.
+       // It cannot be set using assembly syntax.
+       // It is generated by the Go compiler for global declarations,
+       // to convey information about pointer locations to the back end
+       // and for use in generating debug information.
        LSym*   gotype;
-       short   type;
-       uint8   index;
-       int8    scale;
-       int8    reg;    // for 5l, 9l; GPRs and FPRs both start at 0
-       int8    name; // for 5l, 9l
-       int8    class;  // for 5l, 9l
-       uint8   etype; // for 5g, 6g, 8g
-       int32   offset2;        // for 5l, 8l
-       struct Node*    node; // for 5g, 6g, 8g
-       int64   width; // for 5g, 6g, 8g
+
+       int8    class;  // for internal use by liblink
+       uint8   etype; // for internal use by 5g, 6g, 8g
+       void*   node; // for internal use by 5g, 6g, 8g
+       int64   width; // for internal use by 5g, 6g, 8g
+};
+
+enum {
+       NAME_NONE = 0,
+       NAME_EXTERN,
+       NAME_STATIC,
+       NAME_AUTO,
+       NAME_PARAM,
+};
+
+enum {
+       TYPE_NONE = 0,
+       TYPE_BRANCH = 5, // avoid accidental conflicts with NAME_* 
+       TYPE_TEXTSIZE,
+       TYPE_MEM,
+       TYPE_CONST,
+       TYPE_FCONST,
+       TYPE_SCONST,
+       TYPE_REG,
+       TYPE_ADDR,
+       TYPE_SHIFT,
+       TYPE_REGREG,
+       TYPE_REGREG2,
+       TYPE_INDIR,
 };
 
 struct Reloc
@@ -84,6 +208,8 @@ struct       Reloc
        LSym*   xsym;
 };
 
+// TODO(rsc): Describe prog.
+// TODO(rsc): Describe TEXT/GLOBL flag in from3, DATA width in from3.
 struct Prog
 {
        vlong   pc;
@@ -94,33 +220,62 @@ struct     Prog
 
        // operands
        Addr    from;
-       uchar   reg; // arm, ppc64 only (e.g., ADD from, reg, to);
+       int16   reg; // arm, ppc64 only (e.g., ADD from, reg, to);
                     // starts at 0 for both GPRs and FPRs;
                     // also used for ADATA width on arm, ppc64
-       Addr    from3; // ppc64 only (e.g., RLWM/FMADD from, reg, from3, to)
+       Addr    from3; // addl source argument (e.g., RLWM/FMADD from, reg, from3, to)
        Addr    to;
        
        // for 5g, 6g, 8g internal use
        void*   opt;
 
-       // for 5l, 6l, 8l internal use
+       // for liblink internal use
        Prog*   forwd;
        Prog*   pcond;
-       Prog*   comefrom;       // 6l, 8l
-       Prog*   pcrel;  // 5l
+       Prog*   comefrom;       // amd64, 386
+       Prog*   pcrel;  // arm
        int32   spadj;
        uint16  mark;
-       uint16  optab;  // 5l, 9l
-       uchar   back;   // 6l, 8l
-       uchar   ft;     /* 6l, 8l oclass cache */
-       uchar   tt;     // 6l, 8l
-       uchar   isize;  // 6l, 8l
+       uint16  optab;  // arm, ppc64
+       uchar   back;   // amd64, 386
+       uchar   ft;     // oclass cache
+       uchar   tt;     // oclass cache
+       uchar   isize;  // amd64, 386
        uchar   printed;
 
        char    width;  /* fake for DATA */
        char    mode;   /* 16, 32, or 64 in 6l, 8l; internal use in 5g, 6g, 8g */
+};
+
+extern Prog zprog; // zeroed Prog
+
+// Prog.as opcodes.
+// These are the portable opcodes, common to all architectures.
+// Each architecture defines many more arch-specific opcodes,
+// with values starting at A_ARCHSPECIFIC.
+enum {
+       AXXX = 0,
+
+       ACALL,
+       ACHECKNIL,
+       ADATA,
+       ADUFFCOPY,
+       ADUFFZERO,
+       AEND,
+       AFUNCDATA,
+       AGLOBL,
+       AJMP,
+       ANOP,
+       APCDATA,
+       ARET,
+       ATEXT,
+       ATYPE,
+       AUNDEF,
+       AUSEFIELD,
+       AVARDEF,
+       AVARKILL,
        
-       /*c2go uchar TEXTFLAG; */
+       A_ARCHSPECIFIC, // first architecture-specific opcode value
 };
 
 // prevent incompatible type signatures between liblink and 8l on Plan 9
@@ -275,7 +430,7 @@ enum
        RV_TYPE_MASK = (RV_CHECK_OVERFLOW - 1),
 };
 
-// Auto.type
+// Auto.name
 enum
 {
        A_AUTO = 1,
@@ -287,7 +442,7 @@ struct      Auto
        LSym*   asym;
        Auto*   link;
        int32   aoffset;
-       int16   type;
+       int16   name;
        LSym*   gotype;
 };
 
@@ -472,47 +627,14 @@ struct LinkArch
        int     thechar;        // '5', '6', and so on
        int32   endian; // LittleEndian or BigEndian
 
-       void    (*addstacksplit)(Link*, LSym*);
+       void    (*preprocess)(Link*, LSym*);
        void    (*assemble)(Link*, LSym*);
-       int     (*datasize)(Prog*);
        void    (*follow)(Link*, LSym*);
-       int     (*iscall)(Prog*);
-       int     (*isdata)(Prog*);
-       Prog*   (*prg)(void);
        void    (*progedit)(Link*, Prog*);
-       void    (*settextflag)(Prog*, int);
-       int     (*symtype)(Addr*);
-       int     (*textflag)(Prog*);
 
        int     minlc;
        int     ptrsize;
        int     regsize;
-       
-       // TODO: Give these the same values on all systems.
-       int     D_ADDR;
-       int     D_AUTO;
-       int     D_BRANCH;
-       int     D_CONST;
-       int     D_EXTERN;
-       int     D_FCONST;
-       int     D_NONE;
-       int     D_PARAM;
-       int     D_SCONST;
-       int     D_STATIC;
-       int     D_OREG;
-
-       int     ACALL;
-       int     ADATA;
-       int     AEND;
-       int     AFUNCDATA;
-       int     AGLOBL;
-       int     AJMP;
-       int     ANOP;
-       int     APCDATA;
-       int     ARET;
-       int     ATEXT;
-       int     ATYPE;
-       int     AUSEFIELD;
 };
 
 /* executable header types */
@@ -589,6 +711,11 @@ void*      emallocz(long n);
 void*  erealloc(void *p, long n);
 char*  estrdup(char *p);
 char*  expandpkg(char *t0, char *pkg);
+void   linksetexp(void);
+char*  expstring(void);
+
+extern int     fieldtrack_enabled;
+extern int     framepointer_enabled;
 
 // ld.c
 void   addhist(Link *ctxt, int32 line, int type);
@@ -659,6 +786,9 @@ extern      LinkArch        linkarm;
 extern LinkArch        linkppc64;
 extern LinkArch        linkppc64le;
 
+extern int     linkbasepointer;
+extern void    linksetexp(void);
+
 #pragma        varargck        type    "A"     int
 #pragma        varargck        type    "E"     uint
 #pragma        varargck        type    "D"     Addr*
index 489b2a3886b568c6e848b8bb110fb2f6adfed1e4..f77aa9d897c4fab9262fff2e4e960c4891a6f4d4 100644 (file)
@@ -69,9 +69,12 @@ extern "C" {
 #include <stddef.h>
 #include <math.h>
 #include <ctype.h>     /* for tolower */
-#include <signal.h>
 #include <time.h>
 
+#ifdef _WIN32
+#include <signal.h>
+#endif
+
 /*
  * OS-specific crap
  */
index 4b6e866b4416b7623c53347cc8a1c9d2cc8e1a69..054cf6f7885582ff0f90d51129f7396cccc28090 100644 (file)
@@ -736,6 +736,7 @@ func (b *Build) Upload(version string, filename string) error {
                OS:       b.OS,
                Arch:     b.Arch,
                Checksum: sum,
+               Size:     len(file),
                Kind:     kind,
        })
        if err != nil {
@@ -760,6 +761,7 @@ type File struct {
        Arch     string
        Version  string
        Checksum string `datastore:",noindex"`
+       Size     int    `datastore:",noindex"`
        Kind     string // "archive", "installer", "source"
 }
 
index 351eaa0e6cc948b3627a6c1ca4f234a2763c445c..2317f44e9632436498980111d0f90f7080372d55 100644 (file)
@@ -31,6 +31,7 @@ func Example() {
        for _, file := range files {
                hdr := &tar.Header{
                        Name: file.Name,
+                       Mode: 0600,
                        Size: int64(len(file.Body)),
                }
                if err := tw.WriteHeader(hdr); err != nil {
index 7634707b3cb6e65e4d66cd7a5f295c0d476683c0..f24a071d14a03c2225ce3cfa1ff8e0d9d0cf4b54 100644 (file)
@@ -23,7 +23,7 @@ func equalPortable(a, b []byte) bool {
        return true
 }
 
-// explode splits s into a slice of UTF-8 sequences, one per Unicode character (still slices of bytes),
+// explode splits s into a slice of UTF-8 sequences, one per Unicode code point (still slices of bytes),
 // up to a maximum of n byte slices. Invalid UTF-8 sequences are chopped into individual bytes.
 func explode(s []byte, n int) [][]byte {
        if n <= 0 {
@@ -47,6 +47,7 @@ func explode(s []byte, n int) [][]byte {
 }
 
 // Count counts the number of non-overlapping instances of sep in s.
+// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
 func Count(s, sep []byte) int {
        n := len(sep)
        if n == 0 {
index df9838ad37cea770abf54cd705e812f6f81b5814..8a6764b1667db909a92e49abb6f2d6dc3d40da93 100644 (file)
@@ -94,8 +94,8 @@ enum
        CMACARG,
        CMACRO,
        CPREPROC,
-
-       Always  = 14,
+       
+       Always = C_SCOND_NONE,
 };
 
 EXTERN int     debug[256];
@@ -127,6 +127,7 @@ EXTERN      int32   thunk;
 EXTERN Biobuf  obuf;
 EXTERN Link*   ctxt;
 EXTERN Biobuf  bstdout;
+EXTERN Prog*   lastpc;
 
 void*  alloc(int32);
 void*  allocn(void*, int32, int32);
index d365c753433f1052d0b5d322e95f36d1750c0cef..429f7437c6e86d1a58fa215033efa313a49656f8 100644 (file)
@@ -51,7 +51,7 @@
 %left  '*' '/' '%'
 %token <lval>  LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
 %token <lval>  LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
-%token <lval>  LTYPEB LTYPEC LTYPED LTYPEE
+%token <lval>  LTYPEB LGLOBL LTYPEC LTYPED LTYPEE
 %token <lval>  LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
 %token <lval>  LTYPEL LTYPEM LTYPEN LTYPEBX LTYPEPLD
 %token <lval>  LCONST LSP LSB LFP LPC
@@ -62,7 +62,7 @@
 %token <sym>   LNAME LLAB LVAR
 %type  <lval>  con expr oexpr pointer offset sreg spreg creg
 %type  <lval>  rcon cond reglist
-%type  <addr>  gen rel reg regreg freg shift fcon frcon
+%type  <addr>  gen rel reg regreg freg shift fcon frcon textsize
 %type  <addr>  imm ximm name oreg ireg nireg ioreg imsr
 %%
 prog:
@@ -111,53 +111,53 @@ inst:
        }
 |      LTYPE1 cond imsr ',' reg
        {
-               outcode($1, $2, &$3, NREG, &$5);
+               outcode($1, $2, &$3, 0, &$5);
        }
 /*
  * MVN
  */
 |      LTYPE2 cond imsr ',' reg
        {
-               outcode($1, $2, &$3, NREG, &$5);
+               outcode($1, $2, &$3, 0, &$5);
        }
 /*
  * MOVW
  */
 |      LTYPE3 cond gen ',' gen
        {
-               outcode($1, $2, &$3, NREG, &$5);
+               outcode($1, $2, &$3, 0, &$5);
        }
 /*
  * B/BL
  */
 |      LTYPE4 cond comma rel
        {
-               outcode($1, $2, &nullgen, NREG, &$4);
+               outcode($1, $2, &nullgen, 0, &$4);
        }
 |      LTYPE4 cond comma nireg
        {
-               outcode($1, $2, &nullgen, NREG, &$4);
+               outcode($1, $2, &nullgen, 0, &$4);
        }
 /*
  * BX
  */
 |      LTYPEBX comma ireg
        {
-               outcode($1, Always, &nullgen, NREG, &$3);
+               outcode($1, Always, &nullgen, 0, &$3);
        }
 /*
  * BEQ
  */
 |      LTYPE5 comma rel
        {
-               outcode($1, Always, &nullgen, NREG, &$3);
+               outcode($1, Always, &nullgen, 0, &$3);
        }
 /*
  * SWI
  */
 |      LTYPE6 cond comma gen
        {
-               outcode($1, $2, &nullgen, NREG, &$4);
+               outcode($1, $2, &nullgen, 0, &$4);
        }
 /*
  * CMP
@@ -174,18 +174,18 @@ inst:
                Addr g;
 
                g = nullgen;
-               g.type = D_CONST;
+               g.type = TYPE_CONST;
                g.offset = $6;
-               outcode($1, $2, &$3, NREG, &g);
+               outcode($1, $2, &$3, 0, &g);
        }
 |      LTYPE8 cond '[' reglist ']' ',' ioreg
        {
                Addr g;
 
                g = nullgen;
-               g.type = D_CONST;
+               g.type = TYPE_CONST;
                g.offset = $4;
-               outcode($1, $2, &g, NREG, &$7);
+               outcode($1, $2, &g, 0, &$7);
        }
 /*
  * SWAP
@@ -207,63 +207,77 @@ inst:
  */
 |      LTYPEA cond comma
        {
-               outcode($1, $2, &nullgen, NREG, &nullgen);
+               outcode($1, $2, &nullgen, 0, &nullgen);
        }
 /*
- * TEXT/GLOBL
+ * TEXT
  */
-|      LTYPEB name ',' imm
+|      LTYPEB name ',' '$' textsize
        {
                settext($2.sym);
-               $4.type = D_CONST2;
-               $4.offset2 = ArgsSizeUnknown;
-               outcode($1, Always, &$2, 0, &$4);
+               outcode($1, Always, &$2, 0, &$5);
        }
-|      LTYPEB name ',' con ',' imm
+|      LTYPEB name ',' con ',' '$' textsize
        {
                settext($2.sym);
-               $6.type = D_CONST2;
-               $6.offset2 = ArgsSizeUnknown;
-               outcode($1, Always, &$2, $4, &$6);
+               outcode($1, Always, &$2, 0, &$7);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
-|      LTYPEB name ',' con ',' imm '-' con
+/*
+ * GLOBL
+ */
+|      LGLOBL name ',' imm
        {
                settext($2.sym);
-               $6.type = D_CONST2;
-               $6.offset2 = $8;
-               outcode($1, Always, &$2, $4, &$6);
+               outcode($1, Always, &$2, 0, &$4);
+       }
+|      LGLOBL name ',' con ',' imm
+       {
+               settext($2.sym);
+               outcode($1, Always, &$2, 0, &$6);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
 /*
  * DATA
  */
 |      LTYPEC name '/' con ',' ximm
        {
-               outcode($1, Always, &$2, $4, &$6);
+               outcode($1, Always, &$2, 0, &$6);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
 /*
  * CASE
  */
 |      LTYPED cond reg comma
        {
-               outcode($1, $2, &$3, NREG, &nullgen);
+               outcode($1, $2, &$3, 0, &nullgen);
        }
 /*
  * word
  */
 |      LTYPEH comma ximm
        {
-               outcode($1, Always, &nullgen, NREG, &$3);
+               outcode($1, Always, &nullgen, 0, &$3);
        }
 /*
  * floating-point coprocessor
  */
 |      LTYPEI cond freg ',' freg
        {
-               outcode($1, $2, &$3, NREG, &$5);
+               outcode($1, $2, &$3, 0, &$5);
        }
 |      LTYPEK cond frcon ',' freg
        {
-               outcode($1, $2, &$3, NREG, &$5);
+               outcode($1, $2, &$3, 0, &$5);
        }
 |      LTYPEK cond frcon ',' LFREG ',' freg
        {
@@ -281,11 +295,11 @@ inst:
                Addr g;
 
                g = nullgen;
-               g.type = D_CONST;
+               g.type = TYPE_CONST;
                g.offset =
                        (0xe << 24) |           /* opcode */
                        ($1 << 20) |            /* MCR/MRC */
-                       ($2 << 28) |            /* scond */
+                       (($2^C_SCOND_XOR) << 28) |              /* scond */
                        (($3 & 15) << 8) |      /* coprocessor number */
                        (($5 & 7) << 21) |      /* coprocessor operation */
                        (($7 & 15) << 12) |     /* arm register */
@@ -293,7 +307,7 @@ inst:
                        (($11 & 15) << 0) |     /* Crm */
                        (($12 & 7) << 5) |      /* coprocessor information */
                        (1<<4);                 /* must be set */
-               outcode(AMRC, Always, &nullgen, NREG, &g);
+               outcode(AMRC, Always, &nullgen, 0, &g);
        }
 /*
  * MULL r1,r2,(hi,lo)
@@ -308,7 +322,7 @@ inst:
  */
 |      LTYPEN cond reg ',' reg ',' reg ',' spreg
        {
-               $7.type = D_REGREG2;
+               $7.type = TYPE_REGREG2;
                $7.offset = $9;
                outcode($1, $2, &$3, $5.reg, &$7);
        }
@@ -317,34 +331,34 @@ inst:
  */
 |      LTYPEPLD oreg
        {
-               outcode($1, Always, &$2, NREG, &nullgen);
+               outcode($1, Always, &$2, 0, &nullgen);
        }
 /*
  * PCDATA
  */
 |      LTYPEPC gen ',' gen
        {
-               if($2.type != D_CONST || $4.type != D_CONST)
+               if($2.type != TYPE_CONST || $4.type != TYPE_CONST)
                        yyerror("arguments to PCDATA must be integer constants");
-               outcode($1, Always, &$2, NREG, &$4);
+               outcode($1, Always, &$2, 0, &$4);
        }
 /*
  * FUNCDATA
  */
 |      LTYPEF gen ',' gen
        {
-               if($2.type != D_CONST)
+               if($2.type != TYPE_CONST)
                        yyerror("index for FUNCDATA must be integer constant");
-               if($4.type != D_EXTERN && $4.type != D_STATIC && $4.type != D_OREG)
+               if($4.type != NAME_EXTERN && $4.type != NAME_STATIC && $4.type != TYPE_MEM)
                        yyerror("value for FUNCDATA must be symbol reference");
-               outcode($1, Always, &$2, NREG, &$4);
+               outcode($1, Always, &$2, 0, &$4);
        }
 /*
  * END
  */
 |      LTYPEE comma
        {
-               outcode($1, Always, &nullgen, NREG, &nullgen);
+               outcode($1, Always, &nullgen, 0, &nullgen);
        }
 
 cond:
@@ -367,7 +381,7 @@ rel:
        con '(' LPC ')'
        {
                $$ = nullgen;
-               $$.type = D_BRANCH;
+               $$.type = TYPE_BRANCH;
                $$.offset = $1 + pc;
        }
 |      LNAME offset
@@ -376,30 +390,55 @@ rel:
                $$ = nullgen;
                if(pass == 2 && $1->type != LLAB)
                        yyerror("undefined label: %s", $1->labelname);
-               $$.type = D_BRANCH;
+               $$.type = TYPE_BRANCH;
                $$.offset = $1->value + $2;
        }
 
+textsize:
+       LCONST
+       {
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = $1;
+               $$.u.argsize = ArgsSizeUnknown;
+       }
+|      '-' LCONST
+       {
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = -$2;
+               $$.u.argsize = ArgsSizeUnknown;
+       }
+|      LCONST '-' LCONST
+       {
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = $1;
+               $$.u.argsize = $3;
+       }
+|      '-' LCONST '-' LCONST
+       {
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = -$2;
+               $$.u.argsize = $4;
+       }
+
 ximm:  '$' con
        {
                $$ = nullgen;
-               $$.type = D_CONST;
+               $$.type = TYPE_CONST;
                $$.offset = $2;
        }
 |      '$' oreg
        {
                $$ = $2;
-               $$.type = D_CONST;
-       }
-|      '$' '*' '$' oreg
-       {
-               $$ = $4;
-               $$.type = D_OCONST;
+               $$.type = TYPE_ADDR;
        }
 |      '$' LSCONST
        {
                $$ = nullgen;
-               $$.type = D_SCONST;
+               $$.type = TYPE_SCONST;
                memcpy($$.u.sval, $2, sizeof($$.u.sval));
        }
 |      fcon
@@ -408,13 +447,13 @@ fcon:
        '$' LFCONST
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = $2;
        }
 |      '$' '-' LFCONST
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = -$3;
        }
 
@@ -449,19 +488,19 @@ gen:
 |      LPSR
        {
                $$ = nullgen;
-               $$.type = D_PSR;
+               $$.type = TYPE_REG;
                $$.reg = $1;
        }
 |      LFCR
        {
                $$ = nullgen;
-               $$.type = D_FPCR;
+               $$.type = TYPE_REG;
                $$.reg = $1;
        }
 |      con
        {
                $$ = nullgen;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.offset = $1;
        }
 |      oreg
@@ -472,7 +511,7 @@ nireg:
 |      name
        {
                $$ = $1;
-               if($1.name != D_EXTERN && $1.name != D_STATIC) {
+               if($1.name != NAME_EXTERN && $1.name != NAME_STATIC) {
                }
        }
 
@@ -480,7 +519,7 @@ ireg:
        '(' spreg ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.reg = $2;
                $$.offset = 0;
        }
@@ -490,7 +529,7 @@ ioreg:
 |      con '(' sreg ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.reg = $3;
                $$.offset = $1;
        }
@@ -500,7 +539,7 @@ oreg:
 |      name '(' sreg ')'
        {
                $$ = $1;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.reg = $3;
        }
 |      ioreg
@@ -513,7 +552,7 @@ imsr:
 imm:   '$' con
        {
                $$ = nullgen;
-               $$.type = D_CONST;
+               $$.type = TYPE_CONST;
                $$.offset = $2;
        }
 
@@ -521,7 +560,7 @@ reg:
        spreg
        {
                $$ = nullgen;
-               $$.type = D_REG;
+               $$.type = TYPE_REG;
                $$.reg = $1;
        }
 
@@ -529,7 +568,7 @@ regreg:
        '(' spreg ',' spreg ')'
        {
                $$ = nullgen;
-               $$.type = D_REGREG;
+               $$.type = TYPE_REGREG;
                $$.reg = $2;
                $$.offset = $4;
        }
@@ -538,33 +577,33 @@ shift:
        spreg '<' '<' rcon
        {
                $$ = nullgen;
-               $$.type = D_SHIFT;
-               $$.offset = $1 | $4 | (0 << 5);
+               $$.type = TYPE_SHIFT;
+               $$.offset = $1&15 | $4 | (0 << 5);
        }
 |      spreg '>' '>' rcon
        {
                $$ = nullgen;
-               $$.type = D_SHIFT;
-               $$.offset = $1 | $4 | (1 << 5);
+               $$.type = TYPE_SHIFT;
+               $$.offset = $1&15 | $4 | (1 << 5);
        }
 |      spreg '-' '>' rcon
        {
                $$ = nullgen;
-               $$.type = D_SHIFT;
-               $$.offset = $1 | $4 | (2 << 5);
+               $$.type = TYPE_SHIFT;
+               $$.offset = $1&15 | $4 | (2 << 5);
        }
 |      spreg LAT '>' rcon
        {
                $$ = nullgen;
-               $$.type = D_SHIFT;
-               $$.offset = $1 | $4 | (3 << 5);
+               $$.type = TYPE_SHIFT;
+               $$.offset = $1&15 | $4 | (3 << 5);
        }
 
 rcon:
        spreg
        {
-               if($$ < 0 || $$ >= 16)
-                       print("register value out of range\n");
+               if($$ < REG_R0 || $$ > REG_R15)
+                       print("register value out of range in shift\n");
                $$ = (($1&15) << 8) | (1 << 4);
        }
 |      con
@@ -583,8 +622,8 @@ sreg:
 |      LR '(' expr ')'
        {
                if($3 < 0 || $3 >= NREG)
-                       print("register value out of range\n");
-               $$ = $3;
+                       print("register value out of range in R(...)\n");
+               $$ = REG_R0 + $3;
        }
 
 spreg:
@@ -599,8 +638,8 @@ creg:
 |      LC '(' expr ')'
        {
                if($3 < 0 || $3 >= NREG)
-                       print("register value out of range\n");
-               $$ = $3;
+                       print("register value out of range in C(...)\n");
+               $$ = $3; // TODO(rsc): REG_C0+$3
        }
 
 frcon:
@@ -611,21 +650,21 @@ freg:
        LFREG
        {
                $$ = nullgen;
-               $$.type = D_FREG;
+               $$.type = TYPE_REG;
                $$.reg = $1;
        }
 |      LF '(' con ')'
        {
                $$ = nullgen;
-               $$.type = D_FREG;
-               $$.reg = $3;
+               $$.type = TYPE_REG;
+               $$.reg = REG_F0 + $3;
        }
 
 name:
        con '(' pointer ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.name = $3;
                $$.sym = nil;
                $$.offset = $1;
@@ -633,7 +672,7 @@ name:
 |      LNAME offset '(' pointer ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.name = $4;
                $$.sym = linklookup(ctxt, $1->name, 0);
                $$.offset = $2;
@@ -641,8 +680,8 @@ name:
 |      LNAME '<' '>' offset '(' LSB ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
-               $$.name = D_STATIC;
+               $$.type = TYPE_MEM;
+               $$.name = NAME_STATIC;
                $$.sym = linklookup(ctxt, $1->name, 1);
                $$.offset = $4;
        }
index 9273d669b489b31444a2b1d4f8268d1cf2bc4b2c..6f56922a4ea390c5cfbc375bfb0a2156cb3dd1b2 100644 (file)
@@ -187,47 +187,48 @@ struct
        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,
-       "g",            LREG,   10, // avoid unintentionally clobber g using R10
-       "R11",          LREG,   11,
-       "R12",          LREG,   12,
-       "R13",          LREG,   13,
-       "R14",          LREG,   14,
-       "R15",          LREG,   15,
-
-       "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,
+       "SP",           LSP,    NAME_AUTO,
+       "SB",           LSB,    NAME_EXTERN,
+       "FP",           LFP,    NAME_PARAM,
+       "PC",           LPC,    TYPE_BRANCH,
+
+       "R",            LR,     REG_F0,
+
+       "R0",           LREG,   REG_R0,
+       "R1",           LREG,   REG_R1,
+       "R2",           LREG,   REG_R2,
+       "R3",           LREG,   REG_R3,
+       "R4",           LREG,   REG_R4,
+       "R5",           LREG,   REG_R5,
+       "R6",           LREG,   REG_R6,
+       "R7",           LREG,   REG_R7,
+       "R8",           LREG,   REG_R8,
+       "R9",           LREG,   REG_R9,
+       "g",            LREG,   REG_R10, // avoid unintentionally clobber g using R10
+       "R11",          LREG,   REG_R11,
+       "R12",          LREG,   REG_R12,
+       "R13",          LREG,   REG_R13,
+       "R14",          LREG,   REG_R14,
+       "R15",          LREG,   REG_R15,
+
+       "F",            LF,     REG_F0,
+
+       "F0",           LFREG,  REG_F0,
+       "F1",           LFREG,  REG_F1,
+       "F2",           LFREG,  REG_F2,
+       "F3",           LFREG,  REG_F3,
+       "F4",           LFREG,  REG_F4,
+       "F5",           LFREG,  REG_F5,
+       "F6",           LFREG,  REG_F6,
+       "F7",           LFREG,  REG_F7,
+       "F8",           LFREG,  REG_F8,
+       "F9",           LFREG,  REG_F9,
+       "F10",          LFREG,  REG_F10,
+       "F11",          LFREG,  REG_F11,
+       "F12",          LFREG,  REG_F12,
+       "F13",          LFREG,  REG_F13,
+       "F14",          LFREG,  REG_F14,
+       "F15",          LFREG,  REG_F15,
 
        "C",            LC,     0,
 
@@ -248,29 +249,29 @@ struct
        "C14",          LCREG,  14,
        "C15",          LCREG,  15,
 
-       "CPSR",         LPSR,   0,
-       "SPSR",         LPSR,   1,
-
-       "FPSR",         LFCR,   0,
-       "FPCR",         LFCR,   1,
-
-       ".EQ",          LCOND,  0,
-       ".NE",          LCOND,  1,
-       ".CS",          LCOND,  2,
-       ".HS",          LCOND,  2,
-       ".CC",          LCOND,  3,
-       ".LO",          LCOND,  3,
-       ".MI",          LCOND,  4,
-       ".PL",          LCOND,  5,
-       ".VS",          LCOND,  6,
-       ".VC",          LCOND,  7,
-       ".HI",          LCOND,  8,
-       ".LS",          LCOND,  9,
-       ".GE",          LCOND,  10,
-       ".LT",          LCOND,  11,
-       ".GT",          LCOND,  12,
-       ".LE",          LCOND,  13,
-       ".AL",          LCOND,  Always,
+       "CPSR",         LPSR,   REG_CPSR,
+       "SPSR",         LPSR,   REG_SPSR,
+
+       "FPSR",         LFCR,   REG_FPSR,
+       "FPCR",         LFCR,   REG_FPCR,
+
+       ".EQ",          LCOND,  C_SCOND_EQ,
+       ".NE",          LCOND,  C_SCOND_NE,
+       ".CS",          LCOND,  C_SCOND_HS,
+       ".HS",          LCOND,  C_SCOND_HS,
+       ".CC",          LCOND,  C_SCOND_LO,
+       ".LO",          LCOND,  C_SCOND_LO,
+       ".MI",          LCOND,  C_SCOND_MI,
+       ".PL",          LCOND,  C_SCOND_PL,
+       ".VS",          LCOND,  C_SCOND_VS,
+       ".VC",          LCOND,  C_SCOND_VC,
+       ".HI",          LCOND,  C_SCOND_HI,
+       ".LS",          LCOND,  C_SCOND_LS,
+       ".GE",          LCOND,  C_SCOND_GE,
+       ".LT",          LCOND,  C_SCOND_LT,
+       ".GT",          LCOND,  C_SCOND_GT,
+       ".LE",          LCOND,  C_SCOND_LE,
+       ".AL",          LCOND,  C_SCOND_NONE,
 
        ".U",           LS,     C_UBIT,
        ".S",           LS,     C_SBIT,
@@ -405,7 +406,7 @@ struct
        "RFE",          LTYPEA, ARFE,
 
        "TEXT",         LTYPEB, ATEXT,
-       "GLOBL",        LTYPEB, AGLOBL,
+       "GLOBL",        LGLOBL, AGLOBL,
        "DATA",         LTYPEC, ADATA,
        "CASE",         LTYPED, ACASE,
        "END",          LTYPEE, AEND,
@@ -437,9 +438,8 @@ cinit(void)
        Sym *s;
        int i;
 
-       nullgen.type = D_NONE;
-       nullgen.name = D_NONE;
-       nullgen.reg = NREG;
+       nullgen.type = TYPE_NONE;
+       nullgen.name = NAME_NONE;
 
        nerrors = 0;
        iostack = I;
@@ -474,7 +474,7 @@ isreg(Addr *g)
 void
 cclean(void)
 {
-       outcode(AEND, Always, &nullgen, NREG, &nullgen);
+       outcode(AEND, Always, &nullgen, 0, &nullgen);
 }
 
 static int bcode[] =
@@ -497,8 +497,6 @@ static int bcode[] =
        ANOP,
 };
 
-static Prog *lastpc;
-
 void
 outcode(int a, int scond, Addr *g1, int reg, Addr *g2)
 {
@@ -507,8 +505,8 @@ outcode(int a, int scond, Addr *g1, int reg, Addr *g2)
 
        /* hack to make B.NE etc. work: turn it into the corresponding conditional */
        if(a == AB){
-               a = bcode[scond&0xf];
-               scond = (scond & ~0xf) | Always;
+               a = bcode[(scond^C_SCOND_XOR)&0xf];
+               scond = (scond & ~0xf) | C_SCOND_NONE;
        }
 
        if(pass == 1)
index ace80c7e0eb1325f90e60708ae1098569ad17ada..d9af383d787109a44f6c9abd7ee5e8bb899248db 100644 (file)
      LTYPE9 = 266,
      LTYPEA = 267,
      LTYPEB = 268,
-     LTYPEC = 269,
-     LTYPED = 270,
-     LTYPEE = 271,
-     LTYPEG = 272,
-     LTYPEH = 273,
-     LTYPEI = 274,
-     LTYPEJ = 275,
-     LTYPEK = 276,
-     LTYPEL = 277,
-     LTYPEM = 278,
-     LTYPEN = 279,
-     LTYPEBX = 280,
-     LTYPEPLD = 281,
-     LCONST = 282,
-     LSP = 283,
-     LSB = 284,
-     LFP = 285,
-     LPC = 286,
-     LTYPEX = 287,
-     LTYPEPC = 288,
-     LTYPEF = 289,
-     LR = 290,
-     LREG = 291,
-     LF = 292,
-     LFREG = 293,
-     LC = 294,
-     LCREG = 295,
-     LPSR = 296,
-     LFCR = 297,
-     LCOND = 298,
-     LS = 299,
-     LAT = 300,
-     LFCONST = 301,
-     LSCONST = 302,
-     LNAME = 303,
-     LLAB = 304,
-     LVAR = 305
+     LGLOBL = 269,
+     LTYPEC = 270,
+     LTYPED = 271,
+     LTYPEE = 272,
+     LTYPEG = 273,
+     LTYPEH = 274,
+     LTYPEI = 275,
+     LTYPEJ = 276,
+     LTYPEK = 277,
+     LTYPEL = 278,
+     LTYPEM = 279,
+     LTYPEN = 280,
+     LTYPEBX = 281,
+     LTYPEPLD = 282,
+     LCONST = 283,
+     LSP = 284,
+     LSB = 285,
+     LFP = 286,
+     LPC = 287,
+     LTYPEX = 288,
+     LTYPEPC = 289,
+     LTYPEF = 290,
+     LR = 291,
+     LREG = 292,
+     LF = 293,
+     LFREG = 294,
+     LC = 295,
+     LCREG = 296,
+     LPSR = 297,
+     LFCR = 298,
+     LCOND = 299,
+     LS = 300,
+     LAT = 301,
+     LFCONST = 302,
+     LSCONST = 303,
+     LNAME = 304,
+     LLAB = 305,
+     LVAR = 306
    };
 #endif
 /* Tokens.  */
 #define LTYPE9 266
 #define LTYPEA 267
 #define LTYPEB 268
-#define LTYPEC 269
-#define LTYPED 270
-#define LTYPEE 271
-#define LTYPEG 272
-#define LTYPEH 273
-#define LTYPEI 274
-#define LTYPEJ 275
-#define LTYPEK 276
-#define LTYPEL 277
-#define LTYPEM 278
-#define LTYPEN 279
-#define LTYPEBX 280
-#define LTYPEPLD 281
-#define LCONST 282
-#define LSP 283
-#define LSB 284
-#define LFP 285
-#define LPC 286
-#define LTYPEX 287
-#define LTYPEPC 288
-#define LTYPEF 289
-#define LR 290
-#define LREG 291
-#define LF 292
-#define LFREG 293
-#define LC 294
-#define LCREG 295
-#define LPSR 296
-#define LFCR 297
-#define LCOND 298
-#define LS 299
-#define LAT 300
-#define LFCONST 301
-#define LSCONST 302
-#define LNAME 303
-#define LLAB 304
-#define LVAR 305
+#define LGLOBL 269
+#define LTYPEC 270
+#define LTYPED 271
+#define LTYPEE 272
+#define LTYPEG 273
+#define LTYPEH 274
+#define LTYPEI 275
+#define LTYPEJ 276
+#define LTYPEK 277
+#define LTYPEL 278
+#define LTYPEM 279
+#define LTYPEN 280
+#define LTYPEBX 281
+#define LTYPEPLD 282
+#define LCONST 283
+#define LSP 284
+#define LSB 285
+#define LFP 286
+#define LPC 287
+#define LTYPEX 288
+#define LTYPEPC 289
+#define LTYPEF 290
+#define LR 291
+#define LREG 292
+#define LF 293
+#define LFREG 294
+#define LC 295
+#define LCREG 296
+#define LPSR 297
+#define LFCR 298
+#define LCOND 299
+#define LS 300
+#define LAT 301
+#define LFCONST 302
+#define LSCONST 303
+#define LNAME 304
+#define LLAB 305
+#define LVAR 306
 
 
 
@@ -208,7 +210,7 @@ typedef union YYSTYPE
        Addr    addr;
 }
 /* Line 193 of yacc.c.  */
-#line 212 "y.tab.c"
+#line 214 "y.tab.c"
        YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -221,7 +223,7 @@ typedef union YYSTYPE
 
 
 /* Line 216 of yacc.c.  */
-#line 225 "y.tab.c"
+#line 227 "y.tab.c"
 
 #ifdef short
 # undef short
@@ -436,20 +438,20 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  2
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   640
+#define YYLAST   655
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  71
+#define YYNTOKENS  72
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  34
+#define YYNNTS  35
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  130
+#define YYNRULES  134
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  333
+#define YYNSTATES  344
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   305
+#define YYMAXUTOK   306
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -460,16 +462,16 @@ static const yytype_uint8 yytranslate[] =
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,    69,    12,     5,     2,
-      67,    68,    10,     8,    64,     9,     2,    11,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    61,    63,
-       6,    62,     7,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,    68,    12,     5,     2,
+      69,    70,    10,     8,    65,     9,     2,    11,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    62,    64,
+       6,    63,     7,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    65,     2,    66,     4,     2,     2,     2,     2,     2,
+       2,    66,     2,    67,     4,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     3,     2,    70,     2,     2,     2,
+       2,     2,     2,     2,     3,     2,    71,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -487,7 +489,7 @@ static const yytype_uint8 yytranslate[] =
       25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
       35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
       45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-      55,    56,    57,    58,    59,    60
+      55,    56,    57,    58,    59,    60,    61
 };
 
 #if YYDEBUG
@@ -498,74 +500,75 @@ static const yytype_uint16 yyprhs[] =
        0,     0,     3,     4,     5,     9,    10,    15,    20,    25,
       27,    30,    33,    41,    48,    54,    60,    66,    71,    76,
       80,    84,    89,    96,   104,   112,   120,   127,   134,   138,
-     143,   150,   159,   166,   171,   175,   181,   187,   195,   202,
-     215,   223,   233,   236,   241,   246,   249,   250,   253,   256,
-     257,   260,   265,   268,   271,   274,   279,   282,   284,   287,
-     291,   293,   297,   301,   303,   305,   307,   312,   314,   316,
-     318,   320,   322,   324,   326,   330,   332,   337,   339,   344,
-     346,   348,   350,   352,   355,   357,   363,   368,   373,   378,
-     383,   385,   387,   389,   391,   396,   398,   400,   402,   407,
-     409,   411,   413,   418,   423,   429,   437,   438,   441,   444,
-     446,   448,   450,   452,   454,   457,   460,   463,   467,   468,
-     471,   473,   477,   481,   485,   489,   493,   498,   503,   507,
-     511
+     144,   152,   157,   164,   171,   176,   180,   186,   192,   200,
+     207,   220,   228,   238,   241,   246,   251,   254,   255,   258,
+     261,   262,   265,   270,   273,   275,   278,   282,   287,   290,
+     293,   296,   298,   301,   305,   307,   311,   315,   317,   319,
+     321,   326,   328,   330,   332,   334,   336,   338,   340,   344,
+     346,   351,   353,   358,   360,   362,   364,   366,   369,   371,
+     377,   382,   387,   392,   397,   399,   401,   403,   405,   410,
+     412,   414,   416,   421,   423,   425,   427,   432,   437,   443,
+     451,   452,   455,   458,   460,   462,   464,   466,   468,   471,
+     474,   477,   481,   482,   485,   487,   491,   495,   499,   503,
+     507,   512,   517,   521,   525
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      72,     0,    -1,    -1,    -1,    72,    73,    74,    -1,    -1,
-      58,    61,    75,    74,    -1,    58,    62,   104,    63,    -1,
-      60,    62,   104,    63,    -1,    63,    -1,    76,    63,    -1,
-       1,    63,    -1,    13,    77,    88,    64,    95,    64,    90,
-      -1,    13,    77,    88,    64,    95,    64,    -1,    13,    77,
-      88,    64,    90,    -1,    14,    77,    88,    64,    90,    -1,
-      15,    77,    83,    64,    83,    -1,    16,    77,    78,    79,
-      -1,    16,    77,    78,    84,    -1,    35,    78,    85,    -1,
-      17,    78,    79,    -1,    18,    77,    78,    83,    -1,    19,
-      77,    88,    64,    95,    78,    -1,    20,    77,    86,    64,
-      65,    82,    66,    -1,    20,    77,    65,    82,    66,    64,
-      86,    -1,    21,    77,    90,    64,    85,    64,    90,    -1,
-      21,    77,    90,    64,    85,    78,    -1,    21,    77,    78,
-      85,    64,    90,    -1,    22,    77,    78,    -1,    23,    99,
-      64,    89,    -1,    23,    99,    64,   102,    64,    89,    -1,
-      23,    99,    64,   102,    64,    89,     9,   102,    -1,    24,
-      99,    11,   102,    64,    80,    -1,    25,    77,    90,    78,
-      -1,    28,    78,    80,    -1,    29,    77,    98,    64,    98,
-      -1,    31,    77,    97,    64,    98,    -1,    31,    77,    97,
-      64,    48,    64,    98,    -1,    32,    77,    98,    64,    98,
-      78,    -1,    30,    77,   102,    64,   104,    64,    95,    64,
-      96,    64,    96,   103,    -1,    33,    77,    90,    64,    90,
-      64,    91,    -1,    34,    77,    90,    64,    90,    64,    90,
-      64,    95,    -1,    36,    87,    -1,    43,    83,    64,    83,
-      -1,    44,    83,    64,    83,    -1,    26,    78,    -1,    -1,
-      77,    53,    -1,    77,    54,    -1,    -1,    64,    78,    -1,
-     102,    67,    41,    68,    -1,    58,   100,    -1,    69,   102,
-      -1,    69,    87,    -1,    69,    10,    69,    87,    -1,    69,
-      57,    -1,    81,    -1,    69,    56,    -1,    69,     9,    56,
-      -1,    95,    -1,    95,     9,    95,    -1,    95,    78,    82,
-      -1,    90,    -1,    80,    -1,    92,    -1,    92,    67,    95,
-      68,    -1,    51,    -1,    52,    -1,   102,    -1,    87,    -1,
-      98,    -1,    85,    -1,    99,    -1,    67,    95,    68,    -1,
-      85,    -1,   102,    67,    94,    68,    -1,    99,    -1,    99,
-      67,    94,    68,    -1,    86,    -1,    90,    -1,    89,    -1,
-      92,    -1,    69,   102,    -1,    95,    -1,    67,    95,    64,
-      95,    68,    -1,    95,     6,     6,    93,    -1,    95,     7,
-       7,    93,    -1,    95,     9,     7,    93,    -1,    95,    55,
-       7,    93,    -1,    95,    -1,   102,    -1,    46,    -1,    41,
-      -1,    45,    67,   104,    68,    -1,    94,    -1,    38,    -1,
-      50,    -1,    49,    67,   104,    68,    -1,    98,    -1,    81,
-      -1,    48,    -1,    47,    67,   102,    68,    -1,   102,    67,
-     101,    68,    -1,    58,   100,    67,   101,    68,    -1,    58,
-       6,     7,   100,    67,    39,    68,    -1,    -1,     8,   102,
-      -1,     9,   102,    -1,    39,    -1,    38,    -1,    40,    -1,
-      37,    -1,    60,    -1,     9,   102,    -1,     8,   102,    -1,
-      70,   102,    -1,    67,   104,    68,    -1,    -1,    64,   104,
-      -1,   102,    -1,   104,     8,   104,    -1,   104,     9,   104,
-      -1,   104,    10,   104,    -1,   104,    11,   104,    -1,   104,
-      12,   104,    -1,   104,     6,     6,   104,    -1,   104,     7,
-       7,   104,    -1,   104,     5,   104,    -1,   104,     4,   104,
-      -1,   104,     3,   104,    -1
+      73,     0,    -1,    -1,    -1,    73,    74,    75,    -1,    -1,
+      59,    62,    76,    75,    -1,    59,    63,   106,    64,    -1,
+      61,    63,   106,    64,    -1,    64,    -1,    77,    64,    -1,
+       1,    64,    -1,    13,    78,    90,    65,    97,    65,    92,
+      -1,    13,    78,    90,    65,    97,    65,    -1,    13,    78,
+      90,    65,    92,    -1,    14,    78,    90,    65,    92,    -1,
+      15,    78,    85,    65,    85,    -1,    16,    78,    79,    80,
+      -1,    16,    78,    79,    86,    -1,    36,    79,    87,    -1,
+      17,    79,    80,    -1,    18,    78,    79,    85,    -1,    19,
+      78,    90,    65,    97,    79,    -1,    20,    78,    88,    65,
+      66,    84,    67,    -1,    20,    78,    66,    84,    67,    65,
+      88,    -1,    21,    78,    92,    65,    87,    65,    92,    -1,
+      21,    78,    92,    65,    87,    79,    -1,    21,    78,    79,
+      87,    65,    92,    -1,    22,    78,    79,    -1,    23,   101,
+      65,    68,    81,    -1,    23,   101,    65,   104,    65,    68,
+      81,    -1,    24,   101,    65,    91,    -1,    24,   101,    65,
+     104,    65,    91,    -1,    25,   101,    11,   104,    65,    82,
+      -1,    26,    78,    92,    79,    -1,    29,    79,    82,    -1,
+      30,    78,   100,    65,   100,    -1,    32,    78,    99,    65,
+     100,    -1,    32,    78,    99,    65,    49,    65,   100,    -1,
+      33,    78,   100,    65,   100,    79,    -1,    31,    78,   104,
+      65,   106,    65,    97,    65,    98,    65,    98,   105,    -1,
+      34,    78,    92,    65,    92,    65,    93,    -1,    35,    78,
+      92,    65,    92,    65,    92,    65,    97,    -1,    37,    89,
+      -1,    44,    85,    65,    85,    -1,    45,    85,    65,    85,
+      -1,    27,    79,    -1,    -1,    78,    54,    -1,    78,    55,
+      -1,    -1,    65,    79,    -1,   104,    69,    42,    70,    -1,
+      59,   102,    -1,    38,    -1,     9,    38,    -1,    38,     9,
+      38,    -1,     9,    38,     9,    38,    -1,    68,   104,    -1,
+      68,    89,    -1,    68,    58,    -1,    83,    -1,    68,    57,
+      -1,    68,     9,    57,    -1,    97,    -1,    97,     9,    97,
+      -1,    97,    79,    84,    -1,    92,    -1,    82,    -1,    94,
+      -1,    94,    69,    97,    70,    -1,    52,    -1,    53,    -1,
+     104,    -1,    89,    -1,   100,    -1,    87,    -1,   101,    -1,
+      69,    97,    70,    -1,    87,    -1,   104,    69,    96,    70,
+      -1,   101,    -1,   101,    69,    96,    70,    -1,    88,    -1,
+      92,    -1,    91,    -1,    94,    -1,    68,   104,    -1,    97,
+      -1,    69,    97,    65,    97,    70,    -1,    97,     6,     6,
+      95,    -1,    97,     7,     7,    95,    -1,    97,     9,     7,
+      95,    -1,    97,    56,     7,    95,    -1,    97,    -1,   104,
+      -1,    47,    -1,    42,    -1,    46,    69,   106,    70,    -1,
+      96,    -1,    39,    -1,    51,    -1,    50,    69,   106,    70,
+      -1,   100,    -1,    83,    -1,    49,    -1,    48,    69,   104,
+      70,    -1,   104,    69,   103,    70,    -1,    59,   102,    69,
+     103,    70,    -1,    59,     6,     7,   102,    69,    40,    70,
+      -1,    -1,     8,   104,    -1,     9,   104,    -1,    40,    -1,
+      39,    -1,    41,    -1,    38,    -1,    61,    -1,     9,   104,
+      -1,     8,   104,    -1,    71,   104,    -1,    69,   106,    70,
+      -1,    -1,    65,   106,    -1,   104,    -1,   106,     8,   106,
+      -1,   106,     9,   106,    -1,   106,    10,   106,    -1,   106,
+      11,   106,    -1,   106,    12,   106,    -1,   106,     6,     6,
+     106,    -1,   106,     7,     7,   106,    -1,   106,     5,   106,
+      -1,   106,     4,   106,    -1,   106,     3,   106,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
@@ -574,17 +577,17 @@ static const yytype_uint16 yyrline[] =
        0,    68,    68,    70,    69,    77,    76,    85,    90,    96,
       97,    98,   104,   108,   112,   119,   126,   133,   137,   144,
      151,   158,   165,   172,   181,   193,   197,   201,   208,   215,
-     222,   229,   239,   246,   253,   260,   264,   268,   272,   279,
-     301,   309,   318,   325,   334,   345,   351,   354,   358,   363,
-     364,   367,   373,   383,   389,   394,   399,   405,   408,   414,
-     422,   426,   435,   441,   442,   443,   444,   449,   455,   461,
-     467,   468,   471,   472,   480,   489,   490,   499,   500,   506,
-     509,   510,   511,   513,   521,   529,   538,   544,   550,   556,
-     564,   570,   578,   579,   583,   591,   592,   598,   599,   607,
-     608,   611,   617,   625,   633,   641,   651,   654,   658,   664,
-     665,   666,   669,   670,   674,   678,   682,   686,   692,   695,
-     701,   702,   706,   710,   714,   718,   722,   726,   730,   734,
-     738
+     220,   232,   237,   249,   260,   267,   274,   278,   282,   286,
+     293,   315,   323,   332,   339,   348,   359,   365,   368,   372,
+     377,   378,   381,   387,   398,   405,   412,   419,   427,   433,
+     438,   444,   447,   453,   461,   465,   474,   480,   481,   482,
+     483,   488,   494,   500,   506,   507,   510,   511,   519,   528,
+     529,   538,   539,   545,   548,   549,   550,   552,   560,   568,
+     577,   583,   589,   595,   603,   609,   617,   618,   622,   630,
+     631,   637,   638,   646,   647,   650,   656,   664,   672,   680,
+     690,   693,   697,   703,   704,   705,   708,   709,   713,   717,
+     721,   725,   731,   734,   740,   741,   745,   749,   753,   757,
+     761,   765,   769,   773,   777
 };
 #endif
 
@@ -596,16 +599,16 @@ static const char *const yytname[] =
   "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
   "'-'", "'*'", "'/'", "'%'", "LTYPE1", "LTYPE2", "LTYPE3", "LTYPE4",
   "LTYPE5", "LTYPE6", "LTYPE7", "LTYPE8", "LTYPE9", "LTYPEA", "LTYPEB",
-  "LTYPEC", "LTYPED", "LTYPEE", "LTYPEG", "LTYPEH", "LTYPEI", "LTYPEJ",
-  "LTYPEK", "LTYPEL", "LTYPEM", "LTYPEN", "LTYPEBX", "LTYPEPLD", "LCONST",
-  "LSP", "LSB", "LFP", "LPC", "LTYPEX", "LTYPEPC", "LTYPEF", "LR", "LREG",
-  "LF", "LFREG", "LC", "LCREG", "LPSR", "LFCR", "LCOND", "LS", "LAT",
-  "LFCONST", "LSCONST", "LNAME", "LLAB", "LVAR", "':'", "'='", "';'",
-  "','", "'['", "']'", "'('", "')'", "'$'", "'~'", "$accept", "prog", "@1",
-  "line", "@2", "inst", "cond", "comma", "rel", "ximm", "fcon", "reglist",
-  "gen", "nireg", "ireg", "ioreg", "oreg", "imsr", "imm", "reg", "regreg",
-  "shift", "rcon", "sreg", "spreg", "creg", "frcon", "freg", "name",
-  "offset", "pointer", "con", "oexpr", "expr", 0
+  "LGLOBL", "LTYPEC", "LTYPED", "LTYPEE", "LTYPEG", "LTYPEH", "LTYPEI",
+  "LTYPEJ", "LTYPEK", "LTYPEL", "LTYPEM", "LTYPEN", "LTYPEBX", "LTYPEPLD",
+  "LCONST", "LSP", "LSB", "LFP", "LPC", "LTYPEX", "LTYPEPC", "LTYPEF",
+  "LR", "LREG", "LF", "LFREG", "LC", "LCREG", "LPSR", "LFCR", "LCOND",
+  "LS", "LAT", "LFCONST", "LSCONST", "LNAME", "LLAB", "LVAR", "':'", "'='",
+  "';'", "','", "'['", "']'", "'$'", "'('", "')'", "'~'", "$accept",
+  "prog", "@1", "line", "@2", "inst", "cond", "comma", "rel", "textsize",
+  "ximm", "fcon", "reglist", "gen", "nireg", "ireg", "ioreg", "oreg",
+  "imsr", "imm", "reg", "regreg", "shift", "rcon", "sreg", "spreg", "creg",
+  "frcon", "freg", "name", "offset", "pointer", "con", "oexpr", "expr", 0
 };
 #endif
 
@@ -620,28 +623,28 @@ static const yytype_uint16 yytoknum[] =
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
      285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
      295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
-     305,    58,    61,    59,    44,    91,    93,    40,    41,    36,
-     126
+     305,   306,    58,    61,    59,    44,    91,    93,    36,    40,
+      41,   126
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    71,    72,    73,    72,    75,    74,    74,    74,    74,
-      74,    74,    76,    76,    76,    76,    76,    76,    76,    76,
-      76,    76,    76,    76,    76,    76,    76,    76,    76,    76,
-      76,    76,    76,    76,    76,    76,    76,    76,    76,    76,
-      76,    76,    76,    76,    76,    76,    77,    77,    77,    78,
-      78,    79,    79,    80,    80,    80,    80,    80,    81,    81,
-      82,    82,    82,    83,    83,    83,    83,    83,    83,    83,
-      83,    83,    84,    84,    85,    86,    86,    87,    87,    87,
-      88,    88,    88,    89,    90,    91,    92,    92,    92,    92,
-      93,    93,    94,    94,    94,    95,    95,    96,    96,    97,
-      97,    98,    98,    99,    99,    99,   100,   100,   100,   101,
-     101,   101,   102,   102,   102,   102,   102,   102,   103,   103,
-     104,   104,   104,   104,   104,   104,   104,   104,   104,   104,
-     104
+       0,    72,    73,    74,    73,    76,    75,    75,    75,    75,
+      75,    75,    77,    77,    77,    77,    77,    77,    77,    77,
+      77,    77,    77,    77,    77,    77,    77,    77,    77,    77,
+      77,    77,    77,    77,    77,    77,    77,    77,    77,    77,
+      77,    77,    77,    77,    77,    77,    77,    78,    78,    78,
+      79,    79,    80,    80,    81,    81,    81,    81,    82,    82,
+      82,    82,    83,    83,    84,    84,    84,    85,    85,    85,
+      85,    85,    85,    85,    85,    85,    86,    86,    87,    88,
+      88,    89,    89,    89,    90,    90,    90,    91,    92,    93,
+      94,    94,    94,    94,    95,    95,    96,    96,    96,    97,
+      97,    98,    98,    99,    99,   100,   100,   101,   101,   101,
+     102,   102,   102,   103,   103,   103,   104,   104,   104,   104,
+     104,   104,   105,   105,   106,   106,   106,   106,   106,   106,
+     106,   106,   106,   106,   106
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -649,18 +652,18 @@ static const yytype_uint8 yyr2[] =
 {
        0,     2,     0,     0,     3,     0,     4,     4,     4,     1,
        2,     2,     7,     6,     5,     5,     5,     4,     4,     3,
-       3,     4,     6,     7,     7,     7,     6,     6,     3,     4,
-       6,     8,     6,     4,     3,     5,     5,     7,     6,    12,
-       7,     9,     2,     4,     4,     2,     0,     2,     2,     0,
-       2,     4,     2,     2,     2,     4,     2,     1,     2,     3,
-       1,     3,     3,     1,     1,     1,     4,     1,     1,     1,
-       1,     1,     1,     1,     3,     1,     4,     1,     4,     1,
-       1,     1,     1,     2,     1,     5,     4,     4,     4,     4,
-       1,     1,     1,     1,     4,     1,     1,     1,     4,     1,
-       1,     1,     4,     4,     5,     7,     0,     2,     2,     1,
-       1,     1,     1,     1,     2,     2,     2,     3,     0,     2,
-       1,     3,     3,     3,     3,     3,     4,     4,     3,     3,
-       3
+       3,     4,     6,     7,     7,     7,     6,     6,     3,     5,
+       7,     4,     6,     6,     4,     3,     5,     5,     7,     6,
+      12,     7,     9,     2,     4,     4,     2,     0,     2,     2,
+       0,     2,     4,     2,     1,     2,     3,     4,     2,     2,
+       2,     1,     2,     3,     1,     3,     3,     1,     1,     1,
+       4,     1,     1,     1,     1,     1,     1,     1,     3,     1,
+       4,     1,     4,     1,     1,     1,     1,     2,     1,     5,
+       4,     4,     4,     4,     1,     1,     1,     1,     4,     1,
+       1,     1,     4,     1,     1,     1,     4,     4,     5,     7,
+       0,     2,     2,     1,     1,     1,     1,     1,     2,     2,
+       2,     3,     0,     2,     1,     3,     3,     3,     3,     3,
+       4,     4,     3,     3,     3
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -668,282 +671,287 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       2,     3,     1,     0,     0,    46,    46,    46,    46,    49,
-      46,    46,    46,    46,    46,     0,     0,    46,    49,    49,
-      46,    46,    46,    46,    46,    46,    49,     0,     0,     0,
-       0,     0,     9,     4,     0,    11,     0,     0,     0,    49,
-      49,     0,    49,     0,     0,    49,    49,     0,     0,   112,
-     106,   113,     0,     0,     0,     0,     0,     0,    45,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,    75,    79,
-      42,    77,     0,    96,    93,     0,    92,     0,   101,    67,
-      68,     0,    64,    57,     0,    70,    63,    65,    95,    84,
-      71,    69,     0,     5,     0,     0,    10,    47,    48,     0,
-       0,    81,    80,    82,     0,     0,     0,    50,   106,    20,
-       0,     0,     0,     0,     0,     0,     0,     0,    84,    28,
-     115,   114,     0,     0,     0,     0,   120,     0,   116,     0,
-       0,     0,    49,    34,     0,     0,     0,   100,     0,    99,
-       0,     0,     0,     0,    19,     0,     0,     0,     0,     0,
-       0,     0,    58,    56,    54,    53,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,    83,     0,     0,     0,
-     106,    17,    18,    72,    73,     0,    52,     0,    21,     0,
-       0,    49,     0,     0,     0,     0,   106,   107,   108,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     117,    29,     0,   110,   109,   111,     0,     0,    33,     0,
-       0,     0,     0,     0,     0,     0,    74,     0,     0,     0,
-       0,    59,     0,    43,     0,     0,     0,     0,     0,    44,
-       6,     7,     8,    14,    84,    15,    16,    52,     0,     0,
-      49,     0,     0,     0,     0,     0,    49,     0,     0,   130,
-     129,   128,     0,     0,   121,   122,   123,   124,   125,     0,
-     103,     0,    35,     0,   101,    36,    49,     0,     0,    78,
-      76,    94,   102,    55,    66,    86,    90,    91,    87,    88,
-      89,    13,    51,    22,     0,    61,    62,     0,    27,    49,
-      26,     0,   104,   126,   127,    30,    32,     0,     0,    38,
-       0,     0,    12,    24,    23,    25,     0,     0,     0,    37,
-       0,    40,     0,   105,    31,     0,     0,     0,     0,    97,
-       0,     0,    41,     0,     0,     0,     0,   118,    85,    98,
-       0,    39,   119
+       2,     3,     1,     0,     0,    47,    47,    47,    47,    50,
+      47,    47,    47,    47,    47,     0,     0,     0,    47,    50,
+      50,    47,    47,    47,    47,    47,    47,    50,     0,     0,
+       0,     0,     0,     9,     4,     0,    11,     0,     0,     0,
+      50,    50,     0,    50,     0,     0,    50,    50,     0,     0,
+     116,   110,   117,     0,     0,     0,     0,     0,     0,     0,
+      46,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      79,    83,    43,    81,     0,   100,    97,     0,    96,     0,
+     105,    71,    72,     0,    68,    61,     0,    74,    67,    69,
+      99,    88,    75,    73,     0,     5,     0,     0,    10,    48,
+      49,     0,     0,    85,    84,    86,     0,     0,     0,    51,
+     110,    20,     0,     0,     0,     0,     0,     0,     0,     0,
+      88,    28,   119,   118,     0,     0,     0,     0,   124,     0,
+     120,     0,     0,     0,     0,    50,    35,     0,     0,     0,
+     104,     0,   103,     0,     0,     0,     0,    19,     0,     0,
+       0,     0,     0,     0,    62,    60,    59,    58,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,    87,     0,
+       0,     0,   110,    17,    18,    76,    77,     0,    53,     0,
+      21,     0,     0,    50,     0,     0,     0,     0,   110,   111,
+     112,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   121,     0,     0,   114,   113,   115,     0,    31,
+       0,     0,    34,     0,     0,     0,     0,     0,     0,     0,
+      78,     0,     0,     0,     0,    63,    44,     0,     0,     0,
+       0,     0,    45,     6,     7,     8,    14,    88,    15,    16,
+      53,     0,     0,    50,     0,     0,     0,     0,     0,    50,
+       0,     0,   134,   133,   132,     0,     0,   125,   126,   127,
+     128,   129,     0,    54,    29,     0,   107,     0,     0,    36,
+       0,   105,    37,    50,     0,     0,    82,    80,    98,   106,
+      70,    90,    94,    95,    91,    92,    93,    13,    52,    22,
+       0,    65,    66,     0,    27,    50,    26,     0,   108,   130,
+     131,    55,     0,     0,    32,    33,     0,     0,    39,     0,
+       0,    12,    24,    23,    25,     0,     0,    56,    30,     0,
+      38,     0,    41,     0,   109,    57,     0,     0,     0,     0,
+     101,     0,     0,    42,     0,     0,     0,     0,   122,    89,
+     102,     0,    40,   123
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     1,     3,    33,   163,    34,    36,   107,   109,    82,
-      83,   180,    84,   172,    68,    69,    85,   100,   101,    86,
-     311,    87,   275,    88,   118,   320,   138,    90,    71,   125,
-     206,   126,   331,   127
+      -1,     1,     3,    34,   165,    35,    37,   109,   111,   264,
+      84,    85,   182,    86,   174,    70,    71,    87,   102,   103,
+      88,   322,    89,   281,    90,   120,   331,   141,    92,    73,
+     127,   208,   128,   342,   129
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -125
+#define YYPACT_NINF -130
 static const yytype_int16 yypact[] =
 {
-    -125,     7,  -125,   308,   -41,  -125,  -125,  -125,  -125,   -19,
-    -125,  -125,  -125,  -125,  -125,    80,    80,  -125,   -19,   -19,
-    -125,  -125,  -125,  -125,  -125,  -125,   -19,   405,   364,   364,
-     -31,   -15,  -125,  -125,    -2,  -125,   528,   528,   337,   -18,
-     -19,   409,   -18,   528,   230,   187,   -18,   448,   448,  -125,
-     257,  -125,   448,   448,    -6,    15,    94,   309,  -125,    49,
-      19,    44,    95,    19,   309,   309,    63,   391,  -125,  -125,
-    -125,    90,   137,  -125,  -125,   145,  -125,   146,  -125,  -125,
-    -125,    66,  -125,  -125,    52,  -125,  -125,   150,  -125,   147,
-    -125,   137,    57,  -125,   448,   448,  -125,  -125,  -125,   448,
-     167,  -125,  -125,  -125,   184,   200,   431,  -125,    47,  -125,
-     201,   364,   217,   189,   223,   221,    63,   228,  -125,  -125,
-    -125,  -125,   289,   448,   448,   231,  -125,   181,  -125,   411,
-      54,   448,   -19,  -125,   237,   238,    12,  -125,   240,  -125,
-     241,   244,   246,   189,  -125,   245,   114,   319,   448,   448,
-     417,   243,  -125,  -125,  -125,   137,   364,   189,   293,   312,
-     313,   341,   364,   308,   542,   552,  -125,   189,   189,   364,
-     257,  -125,  -125,  -125,  -125,   282,  -125,   315,  -125,   189,
-     287,    42,   296,   114,   303,    63,    47,  -125,  -125,    54,
-     448,   448,   448,   363,   369,   448,   448,   448,   448,   448,
-    -125,  -125,   306,  -125,  -125,  -125,   311,   316,  -125,    53,
-     448,   321,    65,    53,   189,   189,  -125,   318,   324,   250,
-     325,  -125,   405,  -125,   326,   391,   391,   391,   391,  -125,
-    -125,  -125,  -125,  -125,   317,  -125,  -125,   231,   130,   328,
-     -19,   323,   189,   189,   189,   189,   334,   336,   340,   602,
-     621,   628,   448,   448,   197,   197,  -125,  -125,  -125,   352,
-    -125,    49,  -125,   516,   359,  -125,   -19,   366,   371,  -125,
-    -125,  -125,  -125,  -125,  -125,  -125,  -125,  -125,  -125,  -125,
-    -125,   189,  -125,  -125,   474,  -125,  -125,   361,  -125,   165,
-    -125,   399,  -125,   235,   235,   432,  -125,   189,    53,  -125,
-     376,   189,  -125,  -125,  -125,  -125,   377,   448,   380,  -125,
-     189,  -125,   383,  -125,  -125,   112,   385,   189,   386,  -125,
-     388,   189,  -125,   448,   112,   382,   267,   395,  -125,  -125,
-     448,  -125,   613
+    -130,    12,  -130,   305,   -35,  -130,  -130,  -130,  -130,   -33,
+    -130,  -130,  -130,  -130,  -130,   427,   427,   427,  -130,   -33,
+     -33,  -130,  -130,  -130,  -130,  -130,  -130,   -33,   445,   370,
+     370,    10,   -24,  -130,  -130,   -30,  -130,   140,   140,   335,
+     -13,   -33,   449,   -13,   140,    70,   484,   -13,   359,   359,
+    -130,   114,  -130,   359,   359,    27,   -11,    62,    76,   167,
+    -130,     7,   171,   424,    64,   171,   167,   167,    65,   405,
+    -130,  -130,  -130,    68,    74,  -130,  -130,    78,  -130,    86,
+    -130,  -130,  -130,   402,  -130,  -130,    96,  -130,  -130,   107,
+    -130,    21,  -130,    74,   118,  -130,   359,   359,  -130,  -130,
+    -130,   359,   131,  -130,  -130,  -130,   150,   158,   473,  -130,
+      98,  -130,   155,   370,   187,    43,   192,   199,    65,   205,
+    -130,  -130,  -130,  -130,   262,   359,   359,   203,  -130,    90,
+    -130,   106,   164,   233,   359,   -33,  -130,   211,   223,    -3,
+    -130,   226,  -130,   231,   235,   240,    43,  -130,   220,   122,
+     608,   359,   359,   491,  -130,  -130,  -130,    74,   370,    43,
+     287,   291,   300,   301,   370,   305,   560,   582,  -130,    43,
+      43,   370,   114,  -130,  -130,  -130,  -130,   264,  -130,   267,
+    -130,    43,   279,    -4,   281,   122,   283,    65,    98,  -130,
+    -130,   164,   359,   359,   359,   345,   356,   359,   359,   359,
+     359,   359,  -130,    15,   306,  -130,  -130,  -130,   282,  -130,
+     307,   310,  -130,    32,   359,   308,   132,    32,    43,    43,
+    -130,   315,   316,   225,   321,  -130,  -130,   322,   405,   405,
+     405,   405,  -130,  -130,  -130,  -130,  -130,   311,  -130,  -130,
+     203,   204,   323,   -33,   333,    43,    43,    43,    43,   334,
+     331,   337,   631,   611,   547,   359,   359,   228,   228,  -130,
+    -130,  -130,   332,   371,  -130,   353,  -130,   357,     7,  -130,
+     350,   336,  -130,   -33,   340,   361,  -130,  -130,  -130,  -130,
+    -130,  -130,  -130,  -130,  -130,  -130,  -130,    43,  -130,  -130,
+     513,  -130,  -130,   360,  -130,   146,  -130,   384,  -130,   303,
+     303,   425,   399,    15,  -130,  -130,    43,    32,  -130,   373,
+      43,  -130,  -130,  -130,  -130,   375,   408,  -130,  -130,   383,
+    -130,    43,  -130,   385,  -130,  -130,   120,   390,    43,   380,
+    -130,   391,    43,  -130,   359,   120,   394,   275,   403,  -130,
+    -130,   359,  -130,   622
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-    -125,  -125,  -125,   292,  -125,  -125,   578,    45,   354,   -56,
-     400,   -48,   -25,  -125,    -7,   -42,   -21,    -5,  -124,     5,
-    -125,   -10,    89,  -118,   -28,   140,  -125,   -46,     4,   -90,
-     277,    -4,  -125,   -16
+    -130,  -130,  -130,   302,  -130,  -130,   589,    24,   362,   166,
+     -58,   411,   -57,    -8,  -130,   -61,   -43,    -7,    22,  -129,
+     -21,  -130,    72,    34,   -94,   -29,   137,  -130,   -51,     3,
+     -84,   286,    20,  -130,    61
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
    number is the opposite.  If zero, do what YYDEFACT says.
    If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -61
+#define YYTABLE_NINF -65
 static const yytype_int16 yytable[] =
 {
-      89,    89,   114,   133,    92,   201,    70,     2,    89,    89,
-      89,    55,    55,   105,   134,    89,   139,   140,   176,    54,
-      56,   211,    35,    72,    91,    91,   103,   103,   217,   218,
-      93,    94,   104,   103,    91,    97,    98,   110,   112,   145,
-     115,   102,   102,   120,   121,    40,    40,    95,   102,   128,
-     117,   242,    47,    48,    41,   123,   124,   135,   129,   144,
-     154,    96,   132,    58,    59,   218,    77,    78,   152,   141,
-     142,    66,    97,    98,    47,   150,   151,   155,   164,   165,
-     237,    49,   130,    89,   106,   181,   178,   111,    47,    48,
-     116,   119,   203,   204,   205,   166,   247,    97,    98,   173,
-      77,    78,   175,    49,    51,   131,    40,    91,   -60,   184,
-     174,    52,    77,   264,    53,   145,   156,    49,    81,   187,
-     188,   162,   152,   153,    50,   202,    51,   207,    89,   224,
-     143,   223,   219,    67,    89,   295,    53,   229,    50,   234,
-      51,    89,    77,    78,   236,   220,   121,    52,    97,    98,
-      53,   240,    91,   158,   159,    74,   160,   146,    91,    75,
-      76,   318,   319,   262,   136,    91,   265,   266,   203,   204,
-     205,   239,   233,   235,   249,   250,   251,   208,   246,   254,
-     255,   256,   257,   258,   190,   191,   192,   193,   194,   195,
-     196,   197,   198,   199,   263,   286,   287,   276,   276,   276,
-     276,   273,   161,    73,   147,   296,    74,   197,   198,   199,
-      75,    76,   148,   149,   285,   181,   181,   157,    72,   267,
-     268,   277,   277,   277,   277,    73,   243,    73,    74,    40,
-      74,   167,    75,    76,    75,    76,   293,   294,    47,    48,
-      97,    98,   303,   195,   196,   197,   198,   199,   168,   200,
-     288,    40,   309,   190,   191,   192,   193,   194,   195,   196,
-     197,   198,   199,   122,   169,   123,   124,    49,   177,   308,
-     190,   191,   192,   193,   194,   195,   196,   197,   198,   199,
-     115,   179,   316,    97,    98,   283,   302,   182,   183,   322,
-      51,   290,   185,   325,   305,   113,   186,    67,   189,   225,
-      53,   209,   210,   314,   212,   213,   312,   326,   214,     4,
-     215,   299,   222,   216,   332,   278,   279,   280,   271,   226,
-     227,     5,     6,     7,     8,     9,    10,    11,    12,    13,
-      14,    15,    16,    17,    18,   329,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    47,    48,    73,   228,   238,
-      74,    28,    29,   241,    75,    76,   239,   203,   204,   205,
-      74,   244,    97,    98,    75,    76,    30,   245,    31,   252,
-     259,    32,    47,    48,    49,    73,   253,   221,    74,   260,
-     261,   281,    75,    76,    77,    78,   269,   284,    79,    80,
-      97,    98,   270,   272,   274,    50,   282,    51,   289,    47,
-      48,    49,    73,   291,    67,    74,    81,    53,   292,    75,
-      76,    77,    78,    47,    48,    79,    80,    47,    48,    47,
-      48,    99,    50,   298,    51,    47,    48,   304,    49,    73,
-     300,    67,    74,    81,    53,   301,    75,    76,   306,    47,
-      48,   307,    49,   310,   315,   313,    49,   317,    49,   321,
-     328,    51,   324,   323,    49,   230,    47,    48,    52,   330,
-     171,    53,   137,    50,   327,    51,   248,   108,    49,    51,
-       0,    51,    67,   221,     0,    53,    52,    51,    52,    53,
-      99,    53,    47,    48,    52,    49,     0,    53,     0,   170,
-       0,    51,     0,     0,     0,     0,     0,     0,    67,     0,
-       0,    53,     0,     0,     0,     0,     0,     0,    51,     0,
-       0,    49,     0,     0,     0,    52,     0,     0,    53,   190,
-     191,   192,   193,   194,   195,   196,   197,   198,   199,     0,
-       0,     0,     0,     0,    51,     0,     0,     0,     0,     0,
-       0,    67,     0,     0,    53,   190,   191,   192,   193,   194,
-     195,   196,   197,   198,   199,   190,   191,   192,   193,   194,
-     195,   196,   197,   198,   199,     0,    73,     0,     0,    74,
-       0,     0,     0,    75,    76,     0,     0,     0,     0,     0,
-     297,    97,    98,     0,    37,    38,    39,     0,    42,    43,
-      44,    45,    46,     0,     0,    57,     0,    99,    60,    61,
-      62,    63,    64,    65,     0,   231,   191,   192,   193,   194,
-     195,   196,   197,   198,   199,   232,   190,   191,   192,   193,
-     194,   195,   196,   197,   198,   199,   192,   193,   194,   195,
-     196,   197,   198,   199,   193,   194,   195,   196,   197,   198,
-     199
+      91,    91,   116,   136,   209,   245,   215,   147,    91,    91,
+      91,   137,     2,   142,   143,    91,   104,   104,    55,    57,
+      58,    72,    94,   104,   262,   119,   178,   160,   161,    36,
+     162,   107,    41,    42,    98,    56,    56,    56,   135,    97,
+     148,    99,   100,    60,    61,   144,   145,   175,    74,    93,
+      93,    68,    41,   263,   154,   221,   222,   186,   132,    93,
+     106,    41,   112,   -64,   108,   117,   114,   113,   122,   123,
+     118,   121,    95,    96,   130,    83,   156,   163,    48,    49,
+      79,    80,    75,   138,    91,    76,   183,   134,   240,    77,
+      78,   222,   131,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,   157,   250,   180,   125,   126,    50,   105,
+     105,   176,    79,    80,    48,    49,   105,   148,    99,   100,
+     124,   168,   125,   126,    99,   100,   249,   133,   177,    91,
+     227,    52,   139,    93,   146,    91,   115,   149,   304,    69,
+     237,    54,    91,   150,    50,   189,   190,   151,   236,   238,
+     226,   204,   243,   210,   211,   152,   232,   166,   167,   212,
+     202,   158,   269,   239,    76,   272,   273,    52,    77,    78,
+     329,   330,   224,   123,   203,    53,   159,    54,    93,    75,
+      79,   271,    76,   164,    93,    75,    77,    78,    76,   292,
+     293,    93,    77,    78,    99,   100,   169,   274,   275,   282,
+     282,   282,   282,   205,   206,   207,    75,   246,   101,    76,
+     305,    41,   223,    77,    78,   170,   291,   183,   183,    79,
+      80,    99,   100,   171,   179,    99,   100,   294,   192,   193,
+     194,   195,   196,   197,   198,   199,   200,   201,   199,   200,
+     201,    48,    49,   205,   206,   207,   242,   312,   283,   283,
+     283,   283,   181,   252,   253,   254,   320,   184,   257,   258,
+     259,   260,   261,   284,   285,   286,   311,   289,   185,   188,
+     187,    50,   191,   296,   314,   270,   213,   319,   192,   193,
+     194,   195,   196,   197,   198,   199,   200,   201,   214,   323,
+     220,   216,   327,   228,    52,   278,   217,   308,   229,   333,
+     218,   101,    53,   336,    54,   219,     4,   230,   231,   242,
+     117,   197,   198,   199,   200,   201,   299,   300,     5,     6,
+       7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
+      17,    18,    19,   241,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    48,    49,   340,   244,   247,   248,    29,
+      30,   255,   266,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,   256,    31,   225,    32,    48,    49,    33,
+     301,   265,   267,    50,    75,   268,   287,    76,    48,    49,
+     302,    77,    78,    79,    80,   276,   277,    81,    82,    99,
+     100,   279,   280,   288,    51,   337,    52,    50,   290,   295,
+     297,   307,   343,    83,    69,   309,    54,   298,    50,    75,
+      48,   153,    76,    48,    49,   306,    77,    78,    79,    80,
+      52,   303,    81,    82,   315,   101,   310,   313,    53,    51,
+      54,    52,    48,    49,   316,    48,    49,   317,    83,    69,
+      50,    54,   321,    50,    75,   324,   325,    76,   326,   334,
+     328,    77,    78,    48,    49,   332,   335,    48,    49,   154,
+     155,    51,    50,    52,   339,    50,    52,   233,   341,   318,
+     173,    69,   338,    54,    53,   140,    54,   251,    99,   100,
+       0,    48,    49,    50,     0,    52,    51,    50,    52,     0,
+       0,     0,     0,    53,     0,    54,    53,     0,    54,    48,
+      49,     0,     0,     0,    51,     0,    52,     0,   110,     0,
+      52,    50,     0,     0,    69,     0,    54,     0,    53,     0,
+      54,    48,    49,    75,     0,     0,    76,     0,     0,    50,
+      77,    78,   172,     0,    52,     0,     0,     0,    99,   100,
+       0,     0,    69,     0,    54,     0,     0,     0,   225,    41,
+       0,    50,    52,   195,   196,   197,   198,   199,   200,   201,
+      53,     0,    54,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,     0,    52,     0,     0,     0,     0,     0,
+       0,     0,    69,     0,    54,   192,   193,   194,   195,   196,
+     197,   198,   199,   200,   201,    38,    39,    40,     0,    43,
+      44,    45,    46,    47,     0,     0,     0,    59,     0,     0,
+      62,    63,    64,    65,    66,    67,   194,   195,   196,   197,
+     198,   199,   200,   201,   234,   192,   193,   194,   195,   196,
+     197,   198,   199,   200,   201,   193,   194,   195,   196,   197,
+     198,   199,   200,   201,     0,     0,   235,   205,   206,   207,
+      76,     0,     0,     0,    77,    78
 };
 
 static const yytype_int16 yycheck[] =
 {
-      28,    29,    44,    59,    29,   129,    27,     0,    36,    37,
-      38,    15,    16,    38,    60,    43,    62,    63,   108,    15,
-      16,     9,    63,    27,    28,    29,    36,    37,   146,   147,
-      61,    62,    37,    43,    38,    53,    54,    41,    43,    67,
-      44,    36,    37,    47,    48,    64,    64,    62,    43,    53,
-      45,     9,     8,     9,     9,     8,     9,    61,    64,    66,
-      81,    63,    57,    18,    19,   183,    47,    48,    56,    64,
-      65,    26,    53,    54,     8,     9,    10,    81,    94,    95,
-     170,    37,    67,   111,    39,   113,   111,    42,     8,     9,
-      45,    46,    38,    39,    40,    99,   186,    53,    54,   106,
-      47,    48,   106,    37,    60,    11,    64,   111,    66,   116,
-     106,    67,    47,    48,    70,   143,    64,    37,    69,   123,
-     124,    64,    56,    57,    58,   129,    60,   131,   156,   157,
-      67,   156,   148,    67,   162,   259,    70,   162,    58,   167,
-      60,   169,    47,    48,   169,   149,   150,    67,    53,    54,
-      70,   179,   156,     6,     7,    41,     9,    67,   162,    45,
-      46,    49,    50,   209,    69,   169,   212,   213,    38,    39,
-      40,    41,   167,   168,   190,   191,   192,   132,   185,   195,
-     196,   197,   198,   199,     3,     4,     5,     6,     7,     8,
-       9,    10,    11,    12,   210,   243,   244,   225,   226,   227,
-     228,   222,    55,    38,    67,   261,    41,    10,    11,    12,
-      45,    46,    67,    67,   242,   243,   244,    67,   222,   214,
-     215,   225,   226,   227,   228,    38,   181,    38,    41,    64,
-      41,    64,    45,    46,    45,    46,   252,   253,     8,     9,
-      53,    54,   284,     8,     9,    10,    11,    12,    64,    68,
-     245,    64,   298,     3,     4,     5,     6,     7,     8,     9,
-      10,    11,    12,     6,    64,     8,     9,    37,    67,   297,
-       3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
-     284,    64,   310,    53,    54,   240,   281,    64,    67,   317,
-      60,   246,    64,   321,   289,    65,     7,    67,    67,     6,
-      70,    64,    64,   307,    64,    64,   301,   323,    64,     1,
-      64,   266,    69,    68,   330,   226,   227,   228,    68,     7,
-       7,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-      22,    23,    24,    25,    26,    68,    28,    29,    30,    31,
-      32,    33,    34,    35,    36,     8,     9,    38,     7,    67,
-      41,    43,    44,    66,    45,    46,    41,    38,    39,    40,
-      41,    65,    53,    54,    45,    46,    58,    64,    60,     6,
-      64,    63,     8,     9,    37,    38,     7,    56,    41,    68,
-      64,    64,    45,    46,    47,    48,    68,    64,    51,    52,
-      53,    54,    68,    68,    68,    58,    68,    60,    64,     8,
-       9,    37,    38,    67,    67,    41,    69,    70,    68,    45,
-      46,    47,    48,     8,     9,    51,    52,     8,     9,     8,
-       9,    69,    58,    64,    60,     8,     9,    66,    37,    38,
-      64,    67,    41,    69,    70,    64,    45,    46,    39,     8,
-       9,     9,    37,    67,    64,    68,    37,    64,    37,    64,
-      68,    60,    64,    67,    37,   163,     8,     9,    67,    64,
-     106,    70,    62,    58,   324,    60,   189,    58,    37,    60,
-      -1,    60,    67,    56,    -1,    70,    67,    60,    67,    70,
-      69,    70,     8,     9,    67,    37,    -1,    70,    -1,    58,
-      -1,    60,    -1,    -1,    -1,    -1,    -1,    -1,    67,    -1,
-      -1,    70,    -1,    -1,    -1,    -1,    -1,    -1,    60,    -1,
-      -1,    37,    -1,    -1,    -1,    67,    -1,    -1,    70,     3,
-       4,     5,     6,     7,     8,     9,    10,    11,    12,    -1,
-      -1,    -1,    -1,    -1,    60,    -1,    -1,    -1,    -1,    -1,
-      -1,    67,    -1,    -1,    70,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,    -1,    38,    -1,    -1,    41,
-      -1,    -1,    -1,    45,    46,    -1,    -1,    -1,    -1,    -1,
-      64,    53,    54,    -1,     6,     7,     8,    -1,    10,    11,
-      12,    13,    14,    -1,    -1,    17,    -1,    69,    20,    21,
-      22,    23,    24,    25,    -1,    63,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,    63,     3,     4,     5,     6,
-       7,     8,     9,    10,    11,    12,     5,     6,     7,     8,
-       9,    10,    11,    12,     6,     7,     8,     9,    10,    11,
-      12
+      29,    30,    45,    61,   133,     9,     9,    68,    37,    38,
+      39,    62,     0,    64,    65,    44,    37,    38,    15,    16,
+      17,    28,    30,    44,     9,    46,   110,     6,     7,    64,
+       9,    39,    65,     9,    64,    15,    16,    17,    59,    63,
+      69,    54,    55,    19,    20,    66,    67,   108,    28,    29,
+      30,    27,    65,    38,    57,   149,   150,   118,    69,    39,
+      38,    65,    42,    67,    40,    45,    44,    43,    48,    49,
+      46,    47,    62,    63,    54,    68,    83,    56,     8,     9,
+      48,    49,    39,    63,   113,    42,   115,    11,   172,    46,
+      47,   185,    65,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,    12,    83,   188,   113,     8,     9,    38,    37,
+      38,   108,    48,    49,     8,     9,    44,   146,    54,    55,
+       6,   101,     8,     9,    54,    55,   187,    65,   108,   158,
+     159,    61,    68,   113,    69,   164,    66,    69,   267,    69,
+     169,    71,   171,    69,    38,   125,   126,    69,   169,   170,
+     158,   131,   181,   133,   134,    69,   164,    96,    97,   135,
+      70,    65,   213,   171,    42,   216,   217,    61,    46,    47,
+      50,    51,   152,   153,    68,    69,    69,    71,   158,    39,
+      48,    49,    42,    65,   164,    39,    46,    47,    42,   246,
+     247,   171,    46,    47,    54,    55,    65,   218,   219,   228,
+     229,   230,   231,    39,    40,    41,    39,   183,    68,    42,
+     268,    65,   151,    46,    47,    65,   245,   246,   247,    48,
+      49,    54,    55,    65,    69,    54,    55,   248,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    10,    11,
+      12,     8,     9,    39,    40,    41,    42,   290,   228,   229,
+     230,   231,    65,   192,   193,   194,   307,    65,   197,   198,
+     199,   200,   201,   229,   230,   231,   287,   243,    69,     7,
+      65,    38,    69,   249,   295,   214,    65,   306,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    65,   310,
+      70,    65,   321,     6,    61,    70,    65,   273,     7,   328,
+      65,    68,    69,   332,    71,    65,     1,     7,     7,    42,
+     290,     8,     9,    10,    11,    12,   255,   256,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    69,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,     8,     9,    70,    67,    66,    65,    44,
+      45,     6,    70,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,    12,     7,    59,    57,    61,     8,     9,    64,
+      38,    65,    65,    38,    39,    65,    65,    42,     8,     9,
+       9,    46,    47,    48,    49,    70,    70,    52,    53,    54,
+      55,    70,    70,    70,    59,   334,    61,    38,    65,    65,
+      69,    65,   341,    68,    69,    65,    71,    70,    38,    39,
+       8,     9,    42,     8,     9,    65,    46,    47,    48,    49,
+      61,    68,    52,    53,    40,    68,    65,    67,    69,    59,
+      71,    61,     8,     9,     9,     8,     9,    38,    68,    69,
+      38,    71,    69,    38,    39,    70,    38,    42,    65,    69,
+      65,    46,    47,     8,     9,    65,    65,     8,     9,    57,
+      58,    59,    38,    61,    70,    38,    61,   165,    65,   303,
+     108,    69,   335,    71,    69,    64,    71,   191,    54,    55,
+      -1,     8,     9,    38,    -1,    61,    59,    38,    61,    -1,
+      -1,    -1,    -1,    69,    -1,    71,    69,    -1,    71,     8,
+       9,    -1,    -1,    -1,    59,    -1,    61,    -1,    59,    -1,
+      61,    38,    -1,    -1,    69,    -1,    71,    -1,    69,    -1,
+      71,     8,     9,    39,    -1,    -1,    42,    -1,    -1,    38,
+      46,    47,    59,    -1,    61,    -1,    -1,    -1,    54,    55,
+      -1,    -1,    69,    -1,    71,    -1,    -1,    -1,    57,    65,
+      -1,    38,    61,     6,     7,     8,     9,    10,    11,    12,
+      69,    -1,    71,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,    12,    -1,    61,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    69,    -1,    71,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,     6,     7,     8,    -1,    10,
+      11,    12,    13,    14,    -1,    -1,    -1,    18,    -1,    -1,
+      21,    22,    23,    24,    25,    26,     5,     6,     7,     8,
+       9,    10,    11,    12,    64,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,     4,     5,     6,     7,     8,
+       9,    10,    11,    12,    -1,    -1,    64,    39,    40,    41,
+      42,    -1,    -1,    -1,    46,    47
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    72,     0,    73,     1,    13,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    28,
-      29,    30,    31,    32,    33,    34,    35,    36,    43,    44,
-      58,    60,    63,    74,    76,    63,    77,    77,    77,    77,
-      64,    78,    77,    77,    77,    77,    77,     8,     9,    37,
-      58,    60,    67,    70,    99,   102,    99,    77,    78,    78,
-      77,    77,    77,    77,    77,    77,    78,    67,    85,    86,
-      87,    99,   102,    38,    41,    45,    46,    47,    48,    51,
-      52,    69,    80,    81,    83,    87,    90,    92,    94,    95,
-      98,   102,    83,    61,    62,    62,    63,    53,    54,    69,
-      88,    89,    90,    92,    88,    83,    78,    78,    58,    79,
-     102,    78,    88,    65,    86,   102,    78,    90,    95,    78,
-     102,   102,     6,     8,     9,   100,   102,   104,   102,    64,
-      67,    11,    90,    80,    98,   102,    69,    81,    97,    98,
-      98,    90,    90,    67,    85,    95,    67,    67,    67,    67,
-       9,    10,    56,    57,    87,   102,    64,    67,     6,     7,
-       9,    55,    64,    75,   104,   104,   102,    64,    64,    64,
-      58,    79,    84,    85,    99,   102,   100,    67,    83,    64,
-      82,    95,    64,    67,    85,    64,     7,   102,   102,    67,
-       3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
-      68,    89,   102,    38,    39,    40,   101,   102,    78,    64,
-      64,     9,    64,    64,    64,    64,    68,    94,    94,   104,
-     102,    56,    69,    83,    95,     6,     7,     7,     7,    83,
-      74,    63,    63,    90,    95,    90,    83,   100,    67,    41,
-      95,    66,     9,    78,    65,    64,    85,   100,   101,   104,
-     104,   104,     6,     7,   104,   104,   104,   104,   104,    64,
-      68,    64,    98,   104,    48,    98,    98,    90,    90,    68,
-      68,    68,    68,    87,    68,    93,    95,   102,    93,    93,
-      93,    64,    68,    78,    64,    95,    82,    82,    90,    64,
-      78,    67,    68,   104,   104,    89,    80,    64,    64,    78,
-      64,    64,    90,    86,    66,    90,    39,     9,    95,    98,
-      67,    91,    90,    68,   102,    64,    95,    64,    49,    50,
-      96,    64,    95,    67,    64,    95,   104,    96,    68,    68,
-      64,   103,   104
+       0,    73,     0,    74,     1,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      29,    30,    31,    32,    33,    34,    35,    36,    37,    44,
+      45,    59,    61,    64,    75,    77,    64,    78,    78,    78,
+      78,    65,    79,    78,    78,    78,    78,    78,     8,     9,
+      38,    59,    61,    69,    71,   101,   104,   101,   101,    78,
+      79,    79,    78,    78,    78,    78,    78,    78,    79,    69,
+      87,    88,    89,   101,   104,    39,    42,    46,    47,    48,
+      49,    52,    53,    68,    82,    83,    85,    89,    92,    94,
+      96,    97,   100,   104,    85,    62,    63,    63,    64,    54,
+      55,    68,    90,    91,    92,    94,    90,    85,    79,    79,
+      59,    80,   104,    79,    90,    66,    88,   104,    79,    92,
+      97,    79,   104,   104,     6,     8,     9,   102,   104,   106,
+     104,    65,    69,    65,    11,    92,    82,   100,   104,    68,
+      83,    99,   100,   100,    92,    92,    69,    87,    97,    69,
+      69,    69,    69,     9,    57,    58,    89,   104,    65,    69,
+       6,     7,     9,    56,    65,    76,   106,   106,   104,    65,
+      65,    65,    59,    80,    86,    87,   101,   104,   102,    69,
+      85,    65,    84,    97,    65,    69,    87,    65,     7,   104,
+     104,    69,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    70,    68,   104,    39,    40,    41,   103,    91,
+     104,   104,    79,    65,    65,     9,    65,    65,    65,    65,
+      70,    96,    96,   106,   104,    57,    85,    97,     6,     7,
+       7,     7,    85,    75,    64,    64,    92,    97,    92,    85,
+     102,    69,    42,    97,    67,     9,    79,    66,    65,    87,
+     102,   103,   106,   106,   106,     6,     7,   106,   106,   106,
+     106,   106,     9,    38,    81,    65,    70,    65,    65,   100,
+     106,    49,   100,   100,    92,    92,    70,    70,    70,    70,
+      70,    95,    97,   104,    95,    95,    95,    65,    70,    79,
+      65,    97,    84,    84,    92,    65,    79,    69,    70,   106,
+     106,    38,     9,    68,    91,    82,    65,    65,    79,    65,
+      65,    92,    88,    67,    92,    40,     9,    38,    81,    97,
+     100,    69,    93,    92,    70,    38,    65,    97,    65,    50,
+      51,    98,    65,    97,    69,    65,    97,   106,    98,    70,
+      70,    65,   105,   106
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1809,56 +1817,56 @@ yyreduce:
   case 14:
 #line 113 "a.y"
     {
-               outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
+               outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
        }
     break;
 
   case 15:
 #line 120 "a.y"
     {
-               outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
+               outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
        }
     break;
 
   case 16:
 #line 127 "a.y"
     {
-               outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
+               outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
        }
     break;
 
   case 17:
 #line 134 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 18:
 #line 138 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 19:
 #line 145 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+               outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, 0, &(yyvsp[(3) - (3)].addr));
        }
     break;
 
   case 20:
 #line 152 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+               outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, 0, &(yyvsp[(3) - (3)].addr));
        }
     break;
 
   case 21:
 #line 159 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
@@ -1875,9 +1883,9 @@ yyreduce:
                Addr g;
 
                g = nullgen;
-               g.type = D_CONST;
+               g.type = TYPE_CONST;
                g.offset = (yyvsp[(6) - (7)].lval);
-               outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), NREG, &g);
+               outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), 0, &g);
        }
     break;
 
@@ -1887,9 +1895,9 @@ yyreduce:
                Addr g;
 
                g = nullgen;
-               g.type = D_CONST;
+               g.type = TYPE_CONST;
                g.offset = (yyvsp[(4) - (7)].lval);
-               outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &g, NREG, &(yyvsp[(7) - (7)].addr));
+               outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &g, 0, &(yyvsp[(7) - (7)].addr));
        }
     break;
 
@@ -1917,100 +1925,114 @@ yyreduce:
   case 28:
 #line 209 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), (yyvsp[(2) - (3)].lval), &nullgen, NREG, &nullgen);
+               outcode((yyvsp[(1) - (3)].lval), (yyvsp[(2) - (3)].lval), &nullgen, 0, &nullgen);
        }
     break;
 
   case 29:
 #line 216 "a.y"
     {
-               settext((yyvsp[(2) - (4)].addr).sym);
-               (yyvsp[(4) - (4)].addr).type = D_CONST2;
-               (yyvsp[(4) - (4)].addr).offset2 = ArgsSizeUnknown;
-               outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
+               settext((yyvsp[(2) - (5)].addr).sym);
+               outcode((yyvsp[(1) - (5)].lval), Always, &(yyvsp[(2) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
        }
     break;
 
   case 30:
-#line 223 "a.y"
+#line 221 "a.y"
     {
-               settext((yyvsp[(2) - (6)].addr).sym);
-               (yyvsp[(6) - (6)].addr).type = D_CONST2;
-               (yyvsp[(6) - (6)].addr).offset2 = ArgsSizeUnknown;
-               outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               settext((yyvsp[(2) - (7)].addr).sym);
+               outcode((yyvsp[(1) - (7)].lval), Always, &(yyvsp[(2) - (7)].addr), 0, &(yyvsp[(7) - (7)].addr));
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (7)].lval);
+               }
        }
     break;
 
   case 31:
-#line 230 "a.y"
+#line 233 "a.y"
     {
-               settext((yyvsp[(2) - (8)].addr).sym);
-               (yyvsp[(6) - (8)].addr).type = D_CONST2;
-               (yyvsp[(6) - (8)].addr).offset2 = (yyvsp[(8) - (8)].lval);
-               outcode((yyvsp[(1) - (8)].lval), Always, &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].lval), &(yyvsp[(6) - (8)].addr));
+               settext((yyvsp[(2) - (4)].addr).sym);
+               outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 32:
-#line 240 "a.y"
+#line 238 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               settext((yyvsp[(2) - (6)].addr).sym);
+               outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
+               }
        }
     break;
 
   case 33:
-#line 247 "a.y"
+#line 250 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].addr), NREG, &nullgen);
+               outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
+               }
        }
     break;
 
   case 34:
-#line 254 "a.y"
+#line 261 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+               outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].addr), 0, &nullgen);
        }
     break;
 
   case 35:
-#line 261 "a.y"
+#line 268 "a.y"
     {
-               outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
+               outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, 0, &(yyvsp[(3) - (3)].addr));
        }
     break;
 
   case 36:
-#line 265 "a.y"
+#line 275 "a.y"
     {
-               outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
+               outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
        }
     break;
 
   case 37:
-#line 269 "a.y"
+#line 279 "a.y"
     {
-               outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr));
+               outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
        }
     break;
 
   case 38:
-#line 273 "a.y"
+#line 283 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr).reg, &nullgen);
+               outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr));
        }
     break;
 
   case 39:
-#line 280 "a.y"
+#line 287 "a.y"
+    {
+               outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr).reg, &nullgen);
+       }
+    break;
+
+  case 40:
+#line 294 "a.y"
     {
                Addr g;
 
                g = nullgen;
-               g.type = D_CONST;
+               g.type = TYPE_CONST;
                g.offset =
                        (0xe << 24) |           /* opcode */
                        ((yyvsp[(1) - (12)].lval) << 20) |              /* MCR/MRC */
-                       ((yyvsp[(2) - (12)].lval) << 28) |              /* scond */
+                       (((yyvsp[(2) - (12)].lval)^C_SCOND_XOR) << 28) |                /* scond */
                        (((yyvsp[(3) - (12)].lval) & 15) << 8) |        /* coprocessor number */
                        (((yyvsp[(5) - (12)].lval) & 7) << 21) |        /* coprocessor operation */
                        (((yyvsp[(7) - (12)].lval) & 15) << 12) |       /* arm register */
@@ -2018,163 +2040,195 @@ yyreduce:
                        (((yyvsp[(11) - (12)].lval) & 15) << 0) |       /* Crm */
                        (((yyvsp[(12) - (12)].lval) & 7) << 5) |        /* coprocessor information */
                        (1<<4);                 /* must be set */
-               outcode(AMRC, Always, &nullgen, NREG, &g);
+               outcode(AMRC, Always, &nullgen, 0, &g);
        }
     break;
 
-  case 40:
-#line 302 "a.y"
+  case 41:
+#line 316 "a.y"
     {
                outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr));
        }
     break;
 
-  case 41:
-#line 310 "a.y"
+  case 42:
+#line 324 "a.y"
     {
-               (yyvsp[(7) - (9)].addr).type = D_REGREG2;
+               (yyvsp[(7) - (9)].addr).type = TYPE_REGREG2;
                (yyvsp[(7) - (9)].addr).offset = (yyvsp[(9) - (9)].lval);
                outcode((yyvsp[(1) - (9)].lval), (yyvsp[(2) - (9)].lval), &(yyvsp[(3) - (9)].addr), (yyvsp[(5) - (9)].addr).reg, &(yyvsp[(7) - (9)].addr));
        }
     break;
 
-  case 42:
-#line 319 "a.y"
+  case 43:
+#line 333 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
+               outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].addr), 0, &nullgen);
        }
     break;
 
-  case 43:
-#line 326 "a.y"
+  case 44:
+#line 340 "a.y"
     {
-               if((yyvsp[(2) - (4)].addr).type != D_CONST || (yyvsp[(4) - (4)].addr).type != D_CONST)
+               if((yyvsp[(2) - (4)].addr).type != TYPE_CONST || (yyvsp[(4) - (4)].addr).type != TYPE_CONST)
                        yyerror("arguments to PCDATA must be integer constants");
-               outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
-  case 44:
-#line 335 "a.y"
+  case 45:
+#line 349 "a.y"
     {
-               if((yyvsp[(2) - (4)].addr).type != D_CONST)
+               if((yyvsp[(2) - (4)].addr).type != TYPE_CONST)
                        yyerror("index for FUNCDATA must be integer constant");
-               if((yyvsp[(4) - (4)].addr).type != D_EXTERN && (yyvsp[(4) - (4)].addr).type != D_STATIC && (yyvsp[(4) - (4)].addr).type != D_OREG)
+               if((yyvsp[(4) - (4)].addr).type != NAME_EXTERN && (yyvsp[(4) - (4)].addr).type != NAME_STATIC && (yyvsp[(4) - (4)].addr).type != TYPE_MEM)
                        yyerror("value for FUNCDATA must be symbol reference");
-               outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
-  case 45:
-#line 346 "a.y"
+  case 46:
+#line 360 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, NREG, &nullgen);
+               outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, 0, &nullgen);
        }
     break;
 
-  case 46:
-#line 351 "a.y"
+  case 47:
+#line 365 "a.y"
     {
                (yyval.lval) = Always;
        }
     break;
 
-  case 47:
-#line 355 "a.y"
+  case 48:
+#line 369 "a.y"
     {
                (yyval.lval) = ((yyvsp[(1) - (2)].lval) & ~C_SCOND) | (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 48:
-#line 359 "a.y"
+  case 49:
+#line 373 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (2)].lval) | (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 51:
-#line 368 "a.y"
+  case 52:
+#line 382 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_BRANCH;
+               (yyval.addr).type = TYPE_BRANCH;
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
        }
     break;
 
-  case 52:
-#line 374 "a.y"
+  case 53:
+#line 388 "a.y"
     {
                (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
                (yyval.addr) = nullgen;
                if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB)
                        yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname);
-               (yyval.addr).type = D_BRANCH;
+               (yyval.addr).type = TYPE_BRANCH;
                (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 53:
-#line 384 "a.y"
+  case 54:
+#line 399 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CONST;
-               (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).u.argsize = ArgsSizeUnknown;
        }
     break;
 
-  case 54:
-#line 390 "a.y"
+  case 55:
+#line 406 "a.y"
     {
-               (yyval.addr) = (yyvsp[(2) - (2)].addr);
-               (yyval.addr).type = D_CONST;
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = -(yyvsp[(2) - (2)].lval);
+               (yyval.addr).u.argsize = ArgsSizeUnknown;
        }
     break;
 
-  case 55:
-#line 395 "a.y"
+  case 56:
+#line 413 "a.y"
     {
-               (yyval.addr) = (yyvsp[(4) - (4)].addr);
-               (yyval.addr).type = D_OCONST;
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = (yyvsp[(1) - (3)].lval);
+               (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 56:
-#line 400 "a.y"
+  case 57:
+#line 420 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SCONST;
-               memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = -(yyvsp[(2) - (4)].lval);
+               (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval);
        }
     break;
 
   case 58:
-#line 409 "a.y"
+#line 428 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
-               (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
+               (yyval.addr).type = TYPE_CONST;
+               (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
        }
     break;
 
   case 59:
-#line 415 "a.y"
+#line 434 "a.y"
+    {
+               (yyval.addr) = (yyvsp[(2) - (2)].addr);
+               (yyval.addr).type = TYPE_ADDR;
+       }
+    break;
+
+  case 60:
+#line 439 "a.y"
+    {
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_SCONST;
+               memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
+       }
+    break;
+
+  case 62:
+#line 448 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
+               (yyval.addr).type = TYPE_FCONST;
+               (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
+       }
+    break;
+
+  case 63:
+#line 454 "a.y"
+    {
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_FCONST;
                (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
        }
     break;
 
-  case 60:
-#line 423 "a.y"
+  case 64:
+#line 462 "a.y"
     {
                (yyval.lval) = 1 << (yyvsp[(1) - (1)].lval);
        }
     break;
 
-  case 61:
-#line 427 "a.y"
+  case 65:
+#line 466 "a.y"
     {
                int i;
                (yyval.lval)=0;
@@ -2185,161 +2239,161 @@ yyreduce:
        }
     break;
 
-  case 62:
-#line 436 "a.y"
+  case 66:
+#line 475 "a.y"
     {
                (yyval.lval) = (1<<(yyvsp[(1) - (3)].lval)) | (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 66:
-#line 445 "a.y"
+  case 70:
+#line 484 "a.y"
     {
                (yyval.addr) = (yyvsp[(1) - (4)].addr);
                (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
        }
     break;
 
-  case 67:
-#line 450 "a.y"
+  case 71:
+#line 489 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_PSR;
+               (yyval.addr).type = TYPE_REG;
                (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
-  case 68:
-#line 456 "a.y"
+  case 72:
+#line 495 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FPCR;
+               (yyval.addr).type = TYPE_REG;
                (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
-  case 69:
-#line 462 "a.y"
+  case 73:
+#line 501 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
        }
     break;
 
-  case 73:
-#line 473 "a.y"
+  case 77:
+#line 512 "a.y"
     {
                (yyval.addr) = (yyvsp[(1) - (1)].addr);
-               if((yyvsp[(1) - (1)].addr).name != D_EXTERN && (yyvsp[(1) - (1)].addr).name != D_STATIC) {
+               if((yyvsp[(1) - (1)].addr).name != NAME_EXTERN && (yyvsp[(1) - (1)].addr).name != NAME_STATIC) {
                }
        }
     break;
 
-  case 74:
-#line 481 "a.y"
+  case 78:
+#line 520 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
                (yyval.addr).offset = 0;
        }
     break;
 
-  case 76:
-#line 491 "a.y"
+  case 80:
+#line 530 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
        }
     break;
 
-  case 78:
-#line 501 "a.y"
+  case 82:
+#line 540 "a.y"
     {
                (yyval.addr) = (yyvsp[(1) - (4)].addr);
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
        }
     break;
 
-  case 83:
-#line 514 "a.y"
+  case 87:
+#line 553 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CONST;
+               (yyval.addr).type = TYPE_CONST;
                (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 84:
-#line 522 "a.y"
+  case 88:
+#line 561 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_REG;
+               (yyval.addr).type = TYPE_REG;
                (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
-  case 85:
-#line 530 "a.y"
+  case 89:
+#line 569 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_REGREG;
+               (yyval.addr).type = TYPE_REGREG;
                (yyval.addr).reg = (yyvsp[(2) - (5)].lval);
                (yyval.addr).offset = (yyvsp[(4) - (5)].lval);
        }
     break;
 
-  case 86:
-#line 539 "a.y"
+  case 90:
+#line 578 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SHIFT;
-               (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (0 << 5);
+               (yyval.addr).type = TYPE_SHIFT;
+               (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (0 << 5);
        }
     break;
 
-  case 87:
-#line 545 "a.y"
+  case 91:
+#line 584 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SHIFT;
-               (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (1 << 5);
+               (yyval.addr).type = TYPE_SHIFT;
+               (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (1 << 5);
        }
     break;
 
-  case 88:
-#line 551 "a.y"
+  case 92:
+#line 590 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SHIFT;
-               (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (2 << 5);
+               (yyval.addr).type = TYPE_SHIFT;
+               (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (2 << 5);
        }
     break;
 
-  case 89:
-#line 557 "a.y"
+  case 93:
+#line 596 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SHIFT;
-               (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (3 << 5);
+               (yyval.addr).type = TYPE_SHIFT;
+               (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (3 << 5);
        }
     break;
 
-  case 90:
-#line 565 "a.y"
+  case 94:
+#line 604 "a.y"
     {
-               if((yyval.lval) < 0 || (yyval.lval) >= 16)
-                       print("register value out of range\n");
+               if((yyval.lval) < REG_R0 || (yyval.lval) > REG_R15)
+                       print("register value out of range in shift\n");
                (yyval.lval) = (((yyvsp[(1) - (1)].lval)&15) << 8) | (1 << 4);
        }
     break;
 
-  case 91:
-#line 571 "a.y"
+  case 95:
+#line 610 "a.y"
     {
                if((yyval.lval) < 0 || (yyval.lval) >= 32)
                        print("shift value out of range\n");
@@ -2347,224 +2401,224 @@ yyreduce:
        }
     break;
 
-  case 93:
-#line 580 "a.y"
+  case 97:
+#line 619 "a.y"
     {
                (yyval.lval) = REGPC;
        }
     break;
 
-  case 94:
-#line 584 "a.y"
+  case 98:
+#line 623 "a.y"
     {
                if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
-                       print("register value out of range\n");
-               (yyval.lval) = (yyvsp[(3) - (4)].lval);
+                       print("register value out of range in R(...)\n");
+               (yyval.lval) = REG_R0 + (yyvsp[(3) - (4)].lval);
        }
     break;
 
-  case 96:
-#line 593 "a.y"
+  case 100:
+#line 632 "a.y"
     {
                (yyval.lval) = REGSP;
        }
     break;
 
-  case 98:
-#line 600 "a.y"
+  case 102:
+#line 639 "a.y"
     {
                if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
-                       print("register value out of range\n");
-               (yyval.lval) = (yyvsp[(3) - (4)].lval);
+                       print("register value out of range in C(...)\n");
+               (yyval.lval) = (yyvsp[(3) - (4)].lval); // TODO(rsc): REG_C0+$3
        }
     break;
 
-  case 101:
-#line 612 "a.y"
+  case 105:
+#line 651 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FREG;
+               (yyval.addr).type = TYPE_REG;
                (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
-  case 102:
-#line 618 "a.y"
+  case 106:
+#line 657 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FREG;
-               (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = REG_F0 + (yyvsp[(3) - (4)].lval);
        }
     break;
 
-  case 103:
-#line 626 "a.y"
+  case 107:
+#line 665 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).name = (yyvsp[(3) - (4)].lval);
                (yyval.addr).sym = nil;
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
        }
     break;
 
-  case 104:
-#line 634 "a.y"
+  case 108:
+#line 673 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).name = (yyvsp[(4) - (5)].lval);
                (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
                (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
        }
     break;
 
-  case 105:
-#line 642 "a.y"
+  case 109:
+#line 681 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
-               (yyval.addr).name = D_STATIC;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).name = NAME_STATIC;
                (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
                (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
        }
     break;
 
-  case 106:
-#line 651 "a.y"
+  case 110:
+#line 690 "a.y"
     {
                (yyval.lval) = 0;
        }
     break;
 
-  case 107:
-#line 655 "a.y"
+  case 111:
+#line 694 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 108:
-#line 659 "a.y"
+  case 112:
+#line 698 "a.y"
     {
                (yyval.lval) = -(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 113:
-#line 671 "a.y"
+  case 117:
+#line 710 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
        }
     break;
 
-  case 114:
-#line 675 "a.y"
+  case 118:
+#line 714 "a.y"
     {
                (yyval.lval) = -(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 115:
-#line 679 "a.y"
+  case 119:
+#line 718 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 116:
-#line 683 "a.y"
+  case 120:
+#line 722 "a.y"
     {
                (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 117:
-#line 687 "a.y"
+  case 121:
+#line 726 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (3)].lval);
        }
     break;
 
-  case 118:
-#line 692 "a.y"
+  case 122:
+#line 731 "a.y"
     {
                (yyval.lval) = 0;
        }
     break;
 
-  case 119:
-#line 696 "a.y"
+  case 123:
+#line 735 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 121:
-#line 703 "a.y"
+  case 125:
+#line 742 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 122:
-#line 707 "a.y"
+  case 126:
+#line 746 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 123:
-#line 711 "a.y"
+  case 127:
+#line 750 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 124:
-#line 715 "a.y"
+  case 128:
+#line 754 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 125:
-#line 719 "a.y"
+  case 129:
+#line 758 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 126:
-#line 723 "a.y"
+  case 130:
+#line 762 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
        }
     break;
 
-  case 127:
-#line 727 "a.y"
+  case 131:
+#line 766 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
        }
     break;
 
-  case 128:
-#line 731 "a.y"
+  case 132:
+#line 770 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 129:
-#line 735 "a.y"
+  case 133:
+#line 774 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 130:
-#line 739 "a.y"
+  case 134:
+#line 778 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
        }
@@ -2572,7 +2626,7 @@ yyreduce:
 
 
 /* Line 1267 of yacc.c.  */
-#line 2576 "y.tab.c"
+#line 2630 "y.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
index f75cb22a752b821354419b6f5811d1611dbed157..fbbdbef99b0e48bdcf1b9929dbf713dc6fc35b4f 100644 (file)
      LTYPE9 = 266,
      LTYPEA = 267,
      LTYPEB = 268,
-     LTYPEC = 269,
-     LTYPED = 270,
-     LTYPEE = 271,
-     LTYPEG = 272,
-     LTYPEH = 273,
-     LTYPEI = 274,
-     LTYPEJ = 275,
-     LTYPEK = 276,
-     LTYPEL = 277,
-     LTYPEM = 278,
-     LTYPEN = 279,
-     LTYPEBX = 280,
-     LTYPEPLD = 281,
-     LCONST = 282,
-     LSP = 283,
-     LSB = 284,
-     LFP = 285,
-     LPC = 286,
-     LTYPEX = 287,
-     LTYPEPC = 288,
-     LTYPEF = 289,
-     LR = 290,
-     LREG = 291,
-     LF = 292,
-     LFREG = 293,
-     LC = 294,
-     LCREG = 295,
-     LPSR = 296,
-     LFCR = 297,
-     LCOND = 298,
-     LS = 299,
-     LAT = 300,
-     LFCONST = 301,
-     LSCONST = 302,
-     LNAME = 303,
-     LLAB = 304,
-     LVAR = 305
+     LGLOBL = 269,
+     LTYPEC = 270,
+     LTYPED = 271,
+     LTYPEE = 272,
+     LTYPEG = 273,
+     LTYPEH = 274,
+     LTYPEI = 275,
+     LTYPEJ = 276,
+     LTYPEK = 277,
+     LTYPEL = 278,
+     LTYPEM = 279,
+     LTYPEN = 280,
+     LTYPEBX = 281,
+     LTYPEPLD = 282,
+     LCONST = 283,
+     LSP = 284,
+     LSB = 285,
+     LFP = 286,
+     LPC = 287,
+     LTYPEX = 288,
+     LTYPEPC = 289,
+     LTYPEF = 290,
+     LR = 291,
+     LREG = 292,
+     LF = 293,
+     LFREG = 294,
+     LC = 295,
+     LCREG = 296,
+     LPSR = 297,
+     LFCR = 298,
+     LCOND = 299,
+     LS = 300,
+     LAT = 301,
+     LFCONST = 302,
+     LSCONST = 303,
+     LNAME = 304,
+     LLAB = 305,
+     LVAR = 306
    };
 #endif
 /* Tokens.  */
 #define LTYPE9 266
 #define LTYPEA 267
 #define LTYPEB 268
-#define LTYPEC 269
-#define LTYPED 270
-#define LTYPEE 271
-#define LTYPEG 272
-#define LTYPEH 273
-#define LTYPEI 274
-#define LTYPEJ 275
-#define LTYPEK 276
-#define LTYPEL 277
-#define LTYPEM 278
-#define LTYPEN 279
-#define LTYPEBX 280
-#define LTYPEPLD 281
-#define LCONST 282
-#define LSP 283
-#define LSB 284
-#define LFP 285
-#define LPC 286
-#define LTYPEX 287
-#define LTYPEPC 288
-#define LTYPEF 289
-#define LR 290
-#define LREG 291
-#define LF 292
-#define LFREG 293
-#define LC 294
-#define LCREG 295
-#define LPSR 296
-#define LFCR 297
-#define LCOND 298
-#define LS 299
-#define LAT 300
-#define LFCONST 301
-#define LSCONST 302
-#define LNAME 303
-#define LLAB 304
-#define LVAR 305
+#define LGLOBL 269
+#define LTYPEC 270
+#define LTYPED 271
+#define LTYPEE 272
+#define LTYPEG 273
+#define LTYPEH 274
+#define LTYPEI 275
+#define LTYPEJ 276
+#define LTYPEK 277
+#define LTYPEL 278
+#define LTYPEM 279
+#define LTYPEN 280
+#define LTYPEBX 281
+#define LTYPEPLD 282
+#define LCONST 283
+#define LSP 284
+#define LSB 285
+#define LFP 286
+#define LPC 287
+#define LTYPEX 288
+#define LTYPEPC 289
+#define LTYPEF 290
+#define LR 291
+#define LREG 292
+#define LF 293
+#define LFREG 294
+#define LC 295
+#define LCREG 296
+#define LPSR 297
+#define LFCR 298
+#define LCOND 299
+#define LS 300
+#define LAT 301
+#define LFCONST 302
+#define LSCONST 303
+#define LNAME 304
+#define LLAB 305
+#define LVAR 306
 
 
 
@@ -153,7 +155,7 @@ typedef union YYSTYPE
        Addr    addr;
 }
 /* Line 1529 of yacc.c.  */
-#line 157 "y.tab.h"
+#line 159 "y.tab.h"
        YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
index 87c64f6e8126147d2134e7eb449d5897e10c25ea..6acf6dfdf065513b3ad3afb8991c049afa10241d 100644 (file)
@@ -1029,7 +1029,7 @@ agenr(Node *n, Node *a, Node *res)
                        regalloc(&n3, types[tptr], res);
                        p1 = gins(AMOVW, N, &n3);
                        datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
-                       p1->from.type = D_CONST;
+                       p1->from.type = TYPE_ADDR;
                } else
                if(isslice(nl->type) || nl->type->etype == TSTRING) {
                        n1 = n3;
@@ -1552,7 +1552,7 @@ sgen(Node *n, Node *res, int64 w)
                regalloc(&nend, types[TUINT32], N);
 
                p = gins(AMOVW, &src, &nend);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_ADDR;
                if(dir < 0)
                        p->from.offset = dir;
                else
@@ -1562,24 +1562,24 @@ sgen(Node *n, Node *res, int64 w)
        // move src and dest to the end of block if necessary
        if(dir < 0) {
                p = gins(AMOVW, &src, &src);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_ADDR;
                p->from.offset = w + dir;
 
                p = gins(AMOVW, &dst, &dst);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_ADDR;
                p->from.offset = w + dir;
        }
        
        // move
        if(c >= 4) {
                p = gins(op, &src, &tmp);
-               p->from.type = D_OREG;
+               p->from.type = TYPE_MEM;
                p->from.offset = dir;
                p->scond |= C_PBIT;
                ploop = p;
 
                p = gins(op, &tmp, &dst);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.offset = dir;
                p->scond |= C_PBIT;
 
@@ -1591,12 +1591,12 @@ sgen(Node *n, Node *res, int64 w)
        } else {
                while(c-- > 0) {
                        p = gins(op, &src, &tmp);
-                       p->from.type = D_OREG;
+                       p->from.type = TYPE_MEM;
                        p->from.offset = dir;
                        p->scond |= C_PBIT;
        
                        p = gins(op, &tmp, &dst);
-                       p->to.type = D_OREG;
+                       p->to.type = TYPE_MEM;
                        p->to.offset = dir;
                        p->scond |= C_PBIT;
                }
index ef11e2adb94d231a86d6d4c50251a713e667732e..9abab4c6502eeb2d4e11aa5f75122dcc7e44f486 100644 (file)
@@ -163,30 +163,30 @@ cgen64(Node *n, Node *res)
 
                // bl * cl -> ah al
                p1 = gins(AMULLU, N, N);
-               p1->from.type = D_REG;
+               p1->from.type = TYPE_REG;
                p1->from.reg = bl.val.u.reg;
                p1->reg = cl.val.u.reg;
-               p1->to.type = D_REGREG;
+               p1->to.type = TYPE_REGREG;
                p1->to.reg = ah.val.u.reg;
                p1->to.offset = al.val.u.reg;
 //print("%P\n", p1);
 
                // bl * ch + ah -> ah
                p1 = gins(AMULA, N, N);
-               p1->from.type = D_REG;
+               p1->from.type = TYPE_REG;
                p1->from.reg = bl.val.u.reg;
                p1->reg = ch.val.u.reg;
-               p1->to.type = D_REGREG2;
+               p1->to.type = TYPE_REGREG2;
                p1->to.reg = ah.val.u.reg;
                p1->to.offset = ah.val.u.reg;
 //print("%P\n", p1);
 
                // bh * cl + ah -> ah
                p1 = gins(AMULA, N, N);
-               p1->from.type = D_REG;
+               p1->from.type = TYPE_REG;
                p1->from.reg = bh.val.u.reg;
                p1->reg = cl.val.u.reg;
-               p1->to.type = D_REGREG2;
+               p1->to.type = TYPE_REGREG2;
                p1->to.reg = ah.val.u.reg;
                p1->to.offset = ah.val.u.reg;
 //print("%P\n", p1);
index b4c45da6907403e2ae5b387b19f900e64ca14e29..85ad347833a157edd1c0f0d4e73e632d2d7e5337 100644 (file)
@@ -36,14 +36,67 @@ betypeinit(void)
        widthint = 4;
        widthreg = 4;
 
-       zprog.link = P;
-       zprog.as = AGOK;
-       zprog.scond = C_SCOND_NONE;
-       zprog.reg = NREG;
-       zprog.from.type = D_NONE;
-       zprog.from.name = D_NONE;
-       zprog.from.reg = NREG;
-       zprog.to = zprog.from;
-
        listinit5();
 }
+
+void
+main(int argc, char **argv)
+{
+       arch.thechar = thechar;
+       arch.thestring = thestring;
+       arch.thelinkarch = thelinkarch;
+       arch.typedefs = typedefs;
+       arch.MAXWIDTH = MAXWIDTH;
+       arch.afunclit = afunclit;
+       arch.anyregalloc = anyregalloc;
+       arch.betypeinit = betypeinit;
+       arch.bgen = bgen;
+       arch.cgen = cgen;
+       arch.cgen_asop = cgen_asop;
+       arch.cgen_call = cgen_call;
+       arch.cgen_callinter = cgen_callinter;
+       arch.cgen_ret = cgen_ret;
+       arch.clearfat = clearfat;
+       arch.clearp = clearp;
+       arch.defframe = defframe;
+       arch.dgostringptr = dgostringptr;
+       arch.dgostrlitptr = dgostrlitptr;
+       arch.dsname = dsname;
+       arch.dsymptr = dsymptr;
+       arch.dumpdata = dumpdata;
+       arch.dumpit = dumpit;
+       arch.excise = excise;
+       arch.expandchecks = expandchecks;
+       arch.fixautoused = fixautoused;
+       arch.gclean = gclean;
+       arch.gdata = gdata;
+       arch.gdatacomplex = gdatacomplex;
+       arch.gdatastring = gdatastring;
+       arch.ggloblnod = ggloblnod;
+       arch.ggloblsym = ggloblsym;
+       arch.ginit = ginit;
+       arch.gins = gins;
+       arch.ginscall = ginscall;
+       arch.gjmp = gjmp;
+       arch.gtrack = gtrack;
+       arch.gused = gused;
+       arch.igen = igen;
+       arch.isfat = isfat;
+       arch.linkarchinit = linkarchinit;
+       arch.markautoused = markautoused;
+       arch.naddr = naddr;
+       arch.newplist = newplist;
+       arch.nodarg = nodarg;
+       arch.patch = patch;
+       arch.proginfo = proginfo;
+       arch.regalloc = regalloc;
+       arch.regfree = regfree;
+       arch.regopt = regopt;
+       arch.regtyp = regtyp;
+       arch.sameaddr = sameaddr;
+       arch.smallindir = smallindir;
+       arch.stackaddr = stackaddr;
+       arch.unpatch = unpatch;
+       
+       gcmain(argc, argv);
+}
index 00914bfa34cafb5d3c317edb542a4e01c2356d41..8a75311d734857ac8240ed334187ecc7127f714b 100644 (file)
@@ -9,27 +9,18 @@
 #include "../gc/go.h"
 #include "../5l/5.out.h"
 
-#define TEXTFLAG reg
-
 enum
 {
-       REGALLOC_R0 = 0,
+       REGALLOC_R0 = REG_R0,
        REGALLOC_RMAX = REGEXT,
-       REGALLOC_F0 = NREG,
-       REGALLOC_FMAX = REGALLOC_F0 + FREGEXT,
+       REGALLOC_F0 = REG_F0,
+       REGALLOC_FMAX = FREGEXT,
 };
 
 EXTERN int32   dynloc;
 EXTERN uchar   reg[REGALLOC_FMAX+1];
 EXTERN int32   pcloc;          // instruction counter
 EXTERN Strlit  emptystring;
-EXTERN Prog    zprog;
-EXTERN Node*   newproc;
-EXTERN Node*   deferproc;
-EXTERN Node*   deferreturn;
-EXTERN Node*   panicindex;
-EXTERN Node*   panicslice;
-EXTERN Node*   throwreturn;
 extern long    unmappedzero;
 
 /*
@@ -121,3 +112,54 @@ void       datastring(char*, int, Addr*);
 void   listinit(void);
 
 void   zaddr(Biobuf*, Addr*, int, int);
+
+void afunclit(Addr*, Node*);
+int anyregalloc(void);
+void betypeinit(void);
+void bgen(Node*, int, int, Prog*);
+void cgen(Node*, Node*);
+void cgen_asop(Node*);
+void cgen_call(Node*, int);
+void cgen_callinter(Node*, Node*, int);
+void cgen_ret(Node*);
+void clearfat(Node*);
+void clearp(Prog*);
+void defframe(Prog*);
+int dgostringptr(Sym*, int, char*);
+int dgostrlitptr(Sym*, int, Strlit*);
+int dsname(Sym*, int, char*, int);
+int dsymptr(Sym*, int, Sym*, int);
+void dumpdata(void);
+void dumpit(char*, Flow*, int);
+void excise(Flow*);
+void expandchecks(Prog*);
+void fixautoused(Prog*);
+void gclean(void);
+void   gdata(Node*, Node*, int);
+void   gdatacomplex(Node*, Mpcplx*);
+void   gdatastring(Node*, Strlit*);
+void   ggloblnod(Node *nam);
+void   ggloblsym(Sym *s, int32 width, int8 flags);
+void ginit(void);
+Prog*  gins(int, Node*, Node*);
+void   ginscall(Node*, int);
+Prog*  gjmp(Prog*);
+void gtrack(Sym*);
+void   gused(Node*);
+void   igen(Node*, Node*, Node*);
+int isfat(Type*);
+void linkarchinit(void);
+void markautoused(Prog*);
+void naddr(Node*, Addr*, int);
+Plist* newplist(void);
+Node* nodarg(Type*, int);
+void patch(Prog*, Prog*);
+void proginfo(ProgInfo*, Prog*);
+void regalloc(Node*, Type*, Node*);
+void regfree(Node*);
+void regopt(Prog*);
+int regtyp(Addr*);
+int sameaddr(Addr*, Addr*);
+int smallindir(Addr*, Addr*);
+int stackaddr(Addr*);
+Prog* unpatch(Prog*);
index 55ede69e4a968706aaa3ce684ad9af3c818df0a4..b7c621be3287d6a2d50462576213ec1bf25eef50 100644 (file)
@@ -21,12 +21,10 @@ defframe(Prog *ptxt)
        NodeList *l;
        Node *n;
 
-       // fill in argument size
-       ptxt->to.type = D_CONST2;
-       ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
-
-       // fill in final stack size
-       frame = rnd(stksize+maxarg, widthptr);
+       // fill in argument size, stack size
+       ptxt->to.type = TYPE_TEXTSIZE;
+       ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr);
+       frame = rnd(stksize+maxarg, widthreg);
        ptxt->to.offset = frame;
        
        // insert code to contain ambiguously live variables
@@ -70,30 +68,30 @@ zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0)
        if(cnt == 0)
                return p;
        if(*r0 == 0) {
-               p = appendpp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0);
+               p = appendpp(p, AMOVW, TYPE_CONST, 0, 0, TYPE_REG, REG_R0, 0);
                *r0 = 1;
        }
        if(cnt < 4*widthptr) {
                for(i = 0; i < cnt; i += widthptr) 
-                       p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame+lo+i);
+                       p = appendpp(p, AMOVW, TYPE_REG, REG_R0, 0, TYPE_MEM, REGSP, 4+frame+lo+i);
        } else if(!nacl && (cnt <= 128*widthptr)) {
-               p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0);
+               p = appendpp(p, AADD, TYPE_CONST, 0, 4+frame+lo, TYPE_REG, REG_R1, 0);
                p->reg = REGSP;
-               p = appendpp(p, ADUFFZERO, D_NONE, NREG, 0, D_OREG, NREG, 0);
+               p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_MEM, 0, 0);
                f = sysfunc("duffzero");
                naddr(f, &p->to, 1);
                afunclit(&p->to, f);
                p->to.offset = 4*(128-cnt/widthptr);
        } else {
-               p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0);
+               p = appendpp(p, AADD, TYPE_CONST, 0, 4+frame+lo, TYPE_REG, REG_R1, 0);
                p->reg = REGSP;
-               p = appendpp(p, AADD, D_CONST, NREG, cnt, D_REG, 2, 0);
-               p->reg = 1;
-               p1 = p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4);
+               p = appendpp(p, AADD, TYPE_CONST, 0, cnt, TYPE_REG, REG_R2, 0);
+               p->reg = REG_R1;
+               p1 = p = appendpp(p, AMOVW, TYPE_REG, REG_R0, 0, TYPE_MEM, REG_R1, 4);
                p->scond |= C_PBIT;
-               p = appendpp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0);
-               p->reg = 2;
-               p = appendpp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0);
+               p = appendpp(p, ACMP, TYPE_REG, REG_R1, 0, TYPE_NONE, 0, 0);
+               p->reg = REG_R2;
+               p = appendpp(p, ABNE, TYPE_NONE, 0, 0, TYPE_BRANCH, 0, 0);
                patch(p, p1);
        }
        return p;
@@ -128,10 +126,10 @@ markautoused(Prog* p)
                        continue;
 
                if (p->from.node)
-                       p->from.node->used = 1;
+                       ((Node*)(p->from.node))->used = 1;
 
                if (p->to.node)
-                       p->to.node->used = 1;
+                       ((Node*)(p->to.node))->used = 1;
        }
 }
 
@@ -142,26 +140,24 @@ fixautoused(Prog* p)
        Prog **lp;
 
        for (lp=&p; (p=*lp) != P; ) {
-               if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) {
+               if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
                        *lp = p->link;
                        continue;
                }
-               if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) {
+               if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
                        // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
                        // VARDEFs are interspersed with other code, and a jump might be using the
                        // VARDEF as a target. Replace with a no-op instead. A later pass will remove
                        // the no-ops.
-                       p->to.type = D_NONE;
-                       p->to.node = N;
-                       p->as = ANOP;
+                       nopout(p);
                        continue;
                }
 
-               if (p->from.name == D_AUTO && p->from.node)
-                       p->from.offset += p->from.node->stkdelta;
+               if (p->from.name == NAME_AUTO && p->from.node)
+                       p->from.offset += ((Node*)(p->from.node))->stkdelta;
 
-               if (p->to.name == D_AUTO && p->to.node)
-                       p->to.offset += p->to.node->stkdelta;
+               if (p->to.name == NAME_AUTO && p->to.node)
+                       p->to.offset += ((Node*)(p->to.node))->stkdelta;
 
                lp = &p->link;
        }
@@ -208,7 +204,7 @@ ginscall(Node *f, int proc)
                                // ARM NOP 0x00000000 is really AND.EQ R0, R0, R0.
                                // Use the latter form because the NOP pseudo-instruction
                                // would be removed by the linker.
-                               nodreg(&r, types[TINT], 0);
+                               nodreg(&r, types[TINT], REG_R0);
                                p = gins(AAND, &r, &r);
                                p->scond = C_SCOND_EQ;
                        }
@@ -218,8 +214,8 @@ ginscall(Node *f, int proc)
                                gins(AUNDEF, N, N);
                        break;
                }
-               nodreg(&r, types[tptr], 7);
-               nodreg(&r1, types[tptr], 1);
+               nodreg(&r, types[tptr], REG_R7);
+               nodreg(&r1, types[tptr], REG_R1);
                gmove(f, &r);
                r.op = OINDREG;
                gmove(&r, &r1);
@@ -238,7 +234,7 @@ ginscall(Node *f, int proc)
                nodconst(&con, types[TINT32], argsize(f->type));
                gins(AMOVW, &con, &r);
                p = gins(AMOVW, &r, N);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.reg = REGSP;
                p->to.offset = 4;
 
@@ -247,7 +243,7 @@ ginscall(Node *f, int proc)
                n1.left = f;
                gins(AMOVW, &n1, &r);
                p = gins(AMOVW, &r, N);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.reg = REGSP;
                p->to.offset = 8;
 
@@ -261,7 +257,7 @@ ginscall(Node *f, int proc)
                if(proc == 2) {
                        nodconst(&con, types[TINT32], 0);
                        p = gins(ACMP, &con, N);
-                       p->reg = 0;
+                       p->reg = REG_R0;
                        p = gbranch(ABEQ, T, +1);
                        cgen_ret(N);
                        patch(p, pc);
@@ -337,7 +333,7 @@ cgen_callinter(Node *n, Node *res, int proc)
        } else {
                // go/defer. generate go func value.
                p = gins(AMOVW, &nodo, &nodr);
-               p->from.type = D_CONST; // REG = &(20+offset(REG)) -- i.tab->fun[f]
+               p->from.type = TYPE_ADDR;       // REG = &(20+offset(REG)) -- i.tab->fun[f]
        }
 
        nodr.type = n->left->type;
@@ -484,8 +480,8 @@ cgen_ret(Node *n)
        genlist(curfn->exit);
        p = gins(ARET, N, N);
        if(n != N && n->op == ORETJMP) {
-               p->to.name = D_EXTERN;
-               p->to.type = D_CONST;
+               p->to.name = NAME_EXTERN;
+               p->to.type = TYPE_ADDR;
                p->to.sym = linksym(n->left->sym);
        }
 }
@@ -674,7 +670,7 @@ cgen_hmul(Node *nl, Node *nr, Node *res)
                        p = gins(AMULLU, &n2, N);
                // n2 * n1 -> (n1 n2)
                p->reg = n1.val.u.reg;
-               p->to.type = D_REGREG;
+               p->to.type = TYPE_REGREG;
                p->to.reg = n1.val.u.reg;
                p->to.offset = n2.val.u.reg;
                break;
@@ -862,11 +858,11 @@ clearfat(Node *nl)
        if(q > 128) {
                regalloc(&end, types[tptr], N);
                p = gins(AMOVW, &dst, &end);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_ADDR;
                p->from.offset = q*4;
 
                p = gins(AMOVW, &nz, &dst);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.offset = 4;
                p->scond |= C_PBIT;
                pl = p;
@@ -885,7 +881,7 @@ clearfat(Node *nl)
        } else
        while(q > 0) {
                p = gins(AMOVW, &nz, &dst);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.offset = 4;
                p->scond |= C_PBIT;
 //print("1. %P\n", p);
@@ -894,7 +890,7 @@ clearfat(Node *nl)
 
        while(c > 0) {
                p = gins(AMOVB, &nz, &dst);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.offset = 1;
                p->scond |= C_PBIT;
 //print("2. %P\n", p);
@@ -917,7 +913,7 @@ expandchecks(Prog *firstp)
                        continue;
                if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
                        warnl(p->lineno, "generated nil check");
-               if(p->from.type != D_REG)
+               if(p->from.type != TYPE_REG)
                        fatal("invalid nil check %P", p);
                reg = p->from.reg;
                // check is
@@ -930,15 +926,15 @@ expandchecks(Prog *firstp)
                p1->lineno = p->lineno;
                p1->pc = 9999;
                p1->as = AMOVW;
-               p1->from.type = D_REG;
+               p1->from.type = TYPE_REG;
                p1->from.reg = reg;
-               p1->to.type = D_OREG;
+               p1->to.type = TYPE_MEM;
                p1->to.reg = reg;
                p1->to.offset = 0;
                p1->scond = C_SCOND_EQ;
                p->as = ACMP;
-               p->from.type = D_CONST;
-               p->from.reg = NREG;
+               p->from.type = TYPE_CONST;
+               p->from.reg = 0;
                p->from.offset = 0;
                p->reg = reg;
        }
index 65f731685e6eac2ed129bcdf4a237740a7c40323..13d06efe5576a2487d746eb203bef7b253855d40 100644 (file)
@@ -38,18 +38,19 @@ dsname(Sym *sym, int off, char *t, int n)
        Prog *p;
 
        p = gins(ADATA, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.etype = TINT32;
        p->from.offset = off;
-       p->from.reg = NREG;
+       p->from.reg = 0;
        p->from.sym = linksym(sym);
        
-       p->reg = n;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = n;
        
-       p->to.type = D_SCONST;
-       p->to.name = D_NONE;
-       p->to.reg = NREG;
+       p->to.type = TYPE_SCONST;
+       p->to.name = NAME_NONE;
+       p->to.reg = 0;
        p->to.offset = 0;
        memmove(p->to.u.sval, t, n);
        return off + n;
@@ -65,11 +66,11 @@ datastring(char *s, int len, Addr *a)
        Sym *sym;
        
        sym = stringsym(s, len);
-       a->type = D_OREG;
-       a->name = D_EXTERN;
+       a->type = TYPE_MEM;
+       a->name = NAME_EXTERN;
        a->etype = TINT32;
        a->offset = widthptr+4;  // skip header
-       a->reg = NREG;
+       a->reg = 0;
        a->sym = linksym(sym);
        a->node = sym->def;
 }
@@ -84,11 +85,11 @@ datagostring(Strlit *sval, Addr *a)
        Sym *sym;
        
        sym = stringsym(sval->s, sval->len);
-       a->type = D_OREG;
-       a->name = D_EXTERN;
+       a->type = TYPE_MEM;
+       a->name = NAME_EXTERN;
        a->etype = TSTRING;
        a->offset = 0;  // header
-       a->reg = NREG;
+       a->reg = 0;
        a->sym = linksym(sym);
        a->node = sym->def;
 }
@@ -113,14 +114,17 @@ gdata(Node *nam, Node *nr, int wid)
        if(wid == 8 && is64(nr->type)) {
                v = mpgetfix(nr->val.u.xval);
                p = gins(ADATA, nam, nodintconst(v));
-               p->reg = 4;
+               p->from3.type = TYPE_CONST;
+               p->from3.offset = 4;
                p = gins(ADATA, nam, nodintconst(v>>32));
-               p->reg = 4;
+               p->from3.type = TYPE_CONST;
+               p->from3.offset = 4;
                p->from.offset += 4;
                return;
        }
        p = gins(ADATA, nam, nr);
-       p->reg = wid;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = wid;
 }
 
 void
@@ -133,14 +137,16 @@ gdatacomplex(Node *nam, Mpcplx *cval)
        w = types[w]->width;
 
        p = gins(ADATA, nam, N);
-       p->reg = w;
-       p->to.type = D_FCONST;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = w;
+       p->to.type = TYPE_FCONST;
        p->to.u.dval = mpgetflt(&cval->real);
 
        p = gins(ADATA, nam, N);
-       p->reg = w;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = w;
        p->from.offset += w;
-       p->to.type = D_FCONST;
+       p->to.type = TYPE_FCONST;
        p->to.u.dval = mpgetflt(&cval->imag);
 }
 
@@ -152,14 +158,16 @@ gdatastring(Node *nam, Strlit *sval)
 
        p = gins(ADATA, nam, N);
        datastring(sval->s, sval->len, &p->to);
-       p->reg = types[tptr]->width;
-       p->to.type = D_CONST;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = types[tptr]->width;
+       p->to.type = TYPE_CONST;
        p->to.etype = TINT32;
 //print("%P\n", p);
 
        nodconst(&nod1, types[TINT32], sval->len);
        p = gins(ADATA, nam, &nod1);
-       p->reg = types[TINT32]->width;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = types[TINT32]->width;
        p->from.offset += types[tptr]->width;
 }
 
@@ -170,14 +178,15 @@ dstringptr(Sym *s, int off, char *str)
 
        off = rnd(off, widthptr);
        p = gins(ADATA, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->reg = widthptr;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
 
        datastring(str, strlen(str)+1, &p->to);
-       p->to.type = D_CONST;
+       p->to.type = TYPE_CONST;
        p->to.etype = TINT32;
        off += widthptr;
 
@@ -194,13 +203,14 @@ dgostrlitptr(Sym *s, int off, Strlit *lit)
 
        off = rnd(off, widthptr);
        p = gins(ADATA, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->reg = widthptr;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
        datagostring(lit, &p->to);
-       p->to.type = D_CONST;
+       p->to.type = TYPE_CONST;
        p->to.etype = TINT32;
        off += widthptr;
 
@@ -231,13 +241,14 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
        off = rnd(off, widthptr);
 
        p = gins(ADATA, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->reg = widthptr;
-       p->to.type = D_CONST;
-       p->to.name = D_EXTERN;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
+       p->to.type = TYPE_ADDR;
+       p->to.name = NAME_EXTERN;
        p->to.sym = linksym(x);
        p->to.offset = xoff;
        off += widthptr;
@@ -249,4 +260,8 @@ void
 nopout(Prog *p)
 {
        p->as = ANOP;
+       p->scond = zprog.scond;
+       p->from = zprog.from;
+       p->to = zprog.to;
+       p->reg = zprog.reg;
 }
index f09197963ca3e0215241520b8b9e7e98d059ce31..ef5a5091476df69b82af34075941ad3d66a335ed 100644 (file)
@@ -42,14 +42,14 @@ void
 clearp(Prog *p)
 {
        p->as = AEND;
-       p->reg = NREG;
+       p->reg = 0;
        p->scond = C_SCOND_NONE;
-       p->from.type = D_NONE;
-       p->from.name = D_NONE;
-       p->from.reg = NREG;
-       p->to.type = D_NONE;
-       p->to.name = D_NONE;
-       p->to.reg = NREG;
+       p->from.type = TYPE_NONE;
+       p->from.name = NAME_NONE;
+       p->from.reg = 0;
+       p->to.type = TYPE_NONE;
+       p->to.name = NAME_NONE;
+       p->to.reg = 0;
        p->pc = pcloc;
        pcloc++;
 }
@@ -124,7 +124,7 @@ gbranch(int as, Type *t, int likely)
        USED(likely);  // TODO: record this for linker
 
        p = prog(as);
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        p->to.u.branch = P;
        return p;
 }
@@ -135,7 +135,7 @@ gbranch(int as, Type *t, int likely)
 void
 patch(Prog *p, Prog *to)
 {
-       if(p->to.type != D_BRANCH)
+       if(p->to.type != TYPE_BRANCH)
                fatal("patch: not a branch");
        p->to.u.branch = to;
        p->to.offset = to->pc;
@@ -146,7 +146,7 @@ unpatch(Prog *p)
 {
        Prog *q;
 
-       if(p->to.type != D_BRANCH)
+       if(p->to.type != TYPE_BRANCH)
                fatal("unpatch: not a branch");
        q = p->to.u.branch;
        p->to.u.branch = P;
@@ -197,12 +197,12 @@ ggloblnod(Node *nam)
        p->lineno = nam->lineno;
        p->from.sym->gotype = linksym(ngotype(nam));
        p->to.sym = nil;
-       p->to.type = D_CONST;
+       p->to.type = TYPE_CONST;
        p->to.offset = nam->type->width;
        if(nam->readonly)
-               p->reg = RODATA;
+               p->from3.offset = RODATA;
        if(nam->type != T && !haspointers(nam->type))
-               p->reg |= NOPTR;
+               p->from3.offset |= NOPTR;
 }
 
 void
@@ -211,13 +211,13 @@ ggloblsym(Sym *s, int32 width, int8 flags)
        Prog *p;
 
        p = gins(AGLOBL, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
-       p->to.type = D_CONST;
-       p->to.name = D_NONE;
+       p->to.type = TYPE_CONST;
+       p->to.name = NAME_NONE;
        p->to.offset = width;
-       p->reg = flags;
+       p->from3.offset = flags;
 }
 
 void
@@ -226,8 +226,8 @@ gtrack(Sym *s)
        Prog *p;
        
        p = gins(AUSEFIELD, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
 }
 
@@ -249,13 +249,13 @@ isfat(Type *t)
  * naddr of func generates code for address of func.
  * if using opcode that can take address implicitly,
  * call afunclit to fix up the argument.
- * also fix up direct register references to be D_OREG.
+ * also fix up direct register references to be TYPE_MEM.
  */
 void
 afunclit(Addr *a, Node *n)
 {
-       if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) {
-               a->type = D_OREG;
+       if(a->type == TYPE_ADDR && a->name == NAME_EXTERN || a->type == TYPE_REG) {
+               a->type = TYPE_MEM;
                if(n->op == ONAME)
                        a->sym = linksym(n->sym);
        }
@@ -385,7 +385,7 @@ regalloc(Node *n, Type *t, Node *o)
        yyerror("regalloc: unknown type %T", t);
 
 err:
-       nodreg(n, t, 0);
+       nodreg(n, t, REG_R0);
        return;
 
 out:
@@ -852,9 +852,9 @@ gmove(Node *f, Node *t)
                regalloc(&r2, thi.type, N);
                gmove(f, &r1);
                p1 = gins(AMOVW, &r1, &r2);
-               p1->from.type = D_SHIFT;
-               p1->from.offset = 2 << 5 | 31 << 7 | r1.val.u.reg; // r1->31
-               p1->from.reg = NREG;
+               p1->from.type = TYPE_SHIFT;
+               p1->from.offset = 2 << 5 | 31 << 7 | (r1.val.u.reg&15); // r1->31
+               p1->from.reg = 0;
 //print("gmove: %P\n", p1);
                gins(AMOVW, &r1, &tlo);
                gins(AMOVW, &r2, &thi);
@@ -1124,12 +1124,12 @@ raddr(Node *n, Prog *p)
        Addr a;
 
        naddr(n, &a, 1);
-       if(a.type != D_REG && a.type != D_FREG) {
+       if(a.type != TYPE_REG) {
                if(n)
                        fatal("bad in raddr: %O", n->op);
                else
                        fatal("bad in raddr: <null>");
-               p->reg = NREG;
+               p->reg = 0;
        } else
                p->reg = a.reg;
 }
@@ -1164,8 +1164,8 @@ gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs)
        sval = sval&0x1f;
 
        p = gins(as, N, rhs);
-       p->from.type = D_SHIFT;
-       p->from.offset = stype | sval<<7 | lhs->val.u.reg;
+       p->from.type = TYPE_SHIFT;
+       p->from.offset = stype | sval<<7 | (lhs->val.u.reg&15);
        return p;
 }
 
@@ -1176,8 +1176,8 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
 {
        Prog *p;
        p = gins(as, N, rhs);
-       p->from.type = D_SHIFT;
-       p->from.offset = stype | reg->val.u.reg << 8 | 1<<4 | lhs->val.u.reg;
+       p->from.type = TYPE_SHIFT;
+       p->from.offset = stype | (reg->val.u.reg&15) << 8 | 1<<4 | (lhs->val.u.reg&15);
        return p;
 }
 
@@ -1190,9 +1190,9 @@ naddr(Node *n, Addr *a, int canemitcode)
 {
        Sym *s;
 
-       a->type = D_NONE;
-       a->name = D_NONE;
-       a->reg = NREG;
+       a->type = TYPE_NONE;
+       a->name = NAME_NONE;
+       a->reg = 0;
        a->gotype = nil;
        a->node = N;
        a->etype = 0;
@@ -1210,13 +1210,8 @@ naddr(Node *n, Addr *a, int canemitcode)
                break;
 
        case OREGISTER:
-               if(n->val.u.reg <= REGALLOC_RMAX) {
-                       a->type = D_REG;
-                       a->reg = n->val.u.reg;
-               } else {
-                       a->type = D_FREG;
-                       a->reg = n->val.u.reg - REGALLOC_F0;
-               }
+               a->type = TYPE_REG;
+               a->reg = n->val.u.reg;
                a->sym = nil;
                break;
 
@@ -1227,12 +1222,12 @@ naddr(Node *n, Addr *a, int canemitcode)
 //             if(a->type >= D_AX && a->type <= D_DI)
 //                     a->type += D_INDIR;
 //             else
-//             if(a->type == D_CONST)
-//                     a->type = D_NONE+D_INDIR;
+//             if(a->type == TYPE_ADDR)
+//                     a->type = TYPE_NONE+D_INDIR;
 //             else
-//             if(a->type == D_ADDR) {
+//             if(a->type == TYPE_ADDR) {
 //                     a->type = a->index;
-//                     a->index = D_NONE;
+//                     a->index = TYPE_NONE;
 //             } else
 //                     goto bad;
 //             if(n->op == OINDEX) {
@@ -1242,7 +1237,7 @@ naddr(Node *n, Addr *a, int canemitcode)
 //             break;
 
        case OINDREG:
-               a->type = D_OREG;
+               a->type = TYPE_MEM;
                a->reg = n->val.u.reg;
                a->sym = linksym(n->sym);
                a->offset = n->xoffset;
@@ -1255,16 +1250,16 @@ naddr(Node *n, Addr *a, int canemitcode)
                a->width = n->left->type->width;
                a->offset = n->xoffset;
                a->sym = linksym(n->left->sym);
-               a->type = D_OREG;
-               a->name = D_PARAM;
+               a->type = TYPE_MEM;
+               a->name = NAME_PARAM;
                a->node = n->left->orig;
                break;
        
        case OCLOSUREVAR:
                if(!curfn->needctxt)
                        fatal("closurevar without needctxt");
-               a->type = D_OREG;
-               a->reg = 7;
+               a->type = TYPE_MEM;
+               a->reg = REG_R7;
                a->offset = n->xoffset;
                a->sym = nil;
                break;          
@@ -1277,7 +1272,7 @@ naddr(Node *n, Addr *a, int canemitcode)
        case ONAME:
                a->etype = 0;
                a->width = 0;
-               a->reg = NREG;
+               a->reg = 0;
                if(n->type != T) {
                        a->etype = simtype[n->type->etype];
                        a->width = n->type->width;
@@ -1296,23 +1291,23 @@ naddr(Node *n, Addr *a, int canemitcode)
                                s = pkglookup(s->name, n->type->sym->pkg);
                }
 
-               a->type = D_OREG;
+               a->type = TYPE_MEM;
                switch(n->class) {
                default:
                        fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
                case PEXTERN:
-                       a->name = D_EXTERN;
+                       a->name = NAME_EXTERN;
                        break;
                case PAUTO:
-                       a->name = D_AUTO;
+                       a->name = NAME_AUTO;
                        break;
                case PPARAM:
                case PPARAMOUT:
-                       a->name = D_PARAM;
+                       a->name = NAME_PARAM;
                        break;
                case PFUNC:
-                       a->name = D_EXTERN;
-                       a->type = D_CONST;
+                       a->name = NAME_EXTERN;
+                       a->type = TYPE_ADDR;
                        s = funcsym(s);
                        break;
                }
@@ -1325,13 +1320,13 @@ naddr(Node *n, Addr *a, int canemitcode)
                        fatal("naddr: const %lT", n->type);
                        break;
                case CTFLT:
-                       a->type = D_FCONST;
+                       a->type = TYPE_FCONST;
                        a->u.dval = mpgetflt(n->val.u.fval);
                        break;
                case CTINT:
                case CTRUNE:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = mpgetfix(n->val.u.xval);
                        break;
                case CTSTR:
@@ -1339,12 +1334,12 @@ naddr(Node *n, Addr *a, int canemitcode)
                        break;
                case CTBOOL:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = n->val.u.bval;
                        break;
                case CTNIL:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = 0;
                        break;
                }
@@ -1354,7 +1349,7 @@ naddr(Node *n, Addr *a, int canemitcode)
                // itable of interface value
                naddr(n->left, a, canemitcode);
                a->etype = simtype[tptr];
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // len(nil)
                a->width = widthptr;
                break;
@@ -1362,7 +1357,7 @@ naddr(Node *n, Addr *a, int canemitcode)
        case OSPTR:
                // pointer in a string or slice
                naddr(n->left, a, canemitcode);
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // ptr(nil)
                a->etype = simtype[tptr];
                a->offset += Array_array;
@@ -1373,7 +1368,7 @@ naddr(Node *n, Addr *a, int canemitcode)
                // len of string or slice
                naddr(n->left, a, canemitcode);
                a->etype = TINT32;
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // len(nil)
                a->offset += Array_nel;
                break;
@@ -1382,7 +1377,7 @@ naddr(Node *n, Addr *a, int canemitcode)
                // cap of string or slice
                naddr(n->left, a, canemitcode);
                a->etype = TINT32;
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // cap(nil)
                a->offset += Array_cap;
                break;
@@ -1391,12 +1386,12 @@ naddr(Node *n, Addr *a, int canemitcode)
                naddr(n->left, a, canemitcode);
                a->etype = tptr;
                switch(a->type) {
-               case D_OREG:
-                       a->type = D_CONST;
+               case TYPE_MEM:
+                       a->type = TYPE_ADDR;
                        break;
 
-               case D_REG:
-               case D_CONST:
+               case TYPE_REG:
+               case TYPE_ADDR:
                        break;
                
                default:
@@ -1419,7 +1414,7 @@ optoas(int op, Type *t)
        if(t == T)
                fatal("optoas: t is nil");
 
-       a = AGOK;
+       a = AXXX;
        switch(CASE(op, simtype[t->etype])) {
        default:
                fatal("optoas: no entry %O-%T etype %T simtype %T", op, t, types[t->etype], types[simtype[t->etype]]);
@@ -1903,8 +1898,8 @@ odot:
                n1.xoffset = -(oary[i]+1);
        }
 
-       a->type = D_NONE;
-       a->name = D_NONE;
+       a->type = TYPE_NONE;
+       a->name = NAME_NONE;
        n1.type = n->type;
        naddr(&n1, a, 1);
        goto yes;
@@ -2022,7 +2017,7 @@ oindex:
        }
 
        naddr(reg1, a, 1);
-       a->type = D_OREG;
+       a->type = TYPE_MEM;
        a->reg = reg->val.u.reg;
        a->offset = 0;
        goto yes;
@@ -2069,8 +2064,8 @@ oindex_const:
        n2 = *reg;
        n2.op = OINDREG;
        n2.xoffset = v * (*w);
-       a->type = D_NONE;
-       a->name = D_NONE;
+       a->type = TYPE_NONE;
+       a->name = NAME_NONE;
        naddr(&n2, a, 1);
        goto yes;
 
index a606f1d3105e969afc034d7cafe42f2fa09653c0..524607419d256aeab55250e43bb19448d0a5cf24 100644 (file)
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include       "../gc/popt.h"
 
 #define        Z       N
 #define        Adr     Addr
 
-#define        D_HI    D_NONE
-#define        D_LO    D_NONE
+#define        D_HI    TYPE_NONE
+#define        D_LO    TYPE_NONE
 
 #define        BLOAD(r)        band(bnot(r->refbehind), r->refahead)
 #define        BSTORE(r)       band(bnot(r->calbehind), r->calahead)
@@ -53,8 +52,8 @@ typedef       struct  Rgn     Rgn;
 extern Node *Z;
 enum
 {
-       D_HI = D_NONE,
-       D_LO = D_NONE,
+       D_HI = TYPE_NONE,
+       D_LO = TYPE_NONE,
        CLOAD = 5,
        CREF = 5,
        CINF = 1000,
@@ -117,8 +116,6 @@ struct      Rgn
        short   regno;
 };
 
-EXTERN int32   exregoffset;            // not set
-EXTERN int32   exfregoffset;           // not set
 EXTERN Reg     zreg;
 EXTERN Reg*    freer;
 EXTERN Reg**   rpo2r;
@@ -127,7 +124,6 @@ EXTERN      Rgn*    rgp;
 EXTERN int     nregion;
 EXTERN int     nvar;
 EXTERN int32   regbits;
-EXTERN int32   exregbits;
 EXTERN Bits    externs;
 EXTERN Bits    params;
 EXTERN Bits    consts;
@@ -180,58 +176,4 @@ int        BtoF(uint32);
 /*
  * prog.c
  */
-typedef struct ProgInfo ProgInfo;
-struct ProgInfo
-{
-       uint32 flags; // the bits below
-};
-
-enum
-{
-       // Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
-       Pseudo = 1<<1,
-       
-       // There's nothing to say about the instruction,
-       // but it's still okay to see.
-       OK = 1<<2,
-
-       // Size of right-side write, or right-side read if no write.
-       SizeB = 1<<3,
-       SizeW = 1<<4,
-       SizeL = 1<<5,
-       SizeQ = 1<<6,
-       SizeF = 1<<7, // float aka float32
-       SizeD = 1<<8, // double aka float64
-
-       // Left side (Prog.from): address taken, read, write.
-       LeftAddr = 1<<9,
-       LeftRead = 1<<10,
-       LeftWrite = 1<<11,
-       
-       // Register in middle (Prog.reg); only ever read.
-       RegRead = 1<<12,
-       CanRegRead = 1<<13,
-       
-       // Right side (Prog.to): address taken, read, write.
-       RightAddr = 1<<14,
-       RightRead = 1<<15,
-       RightWrite = 1<<16,
-
-       // Instruction kinds
-       Move = 1<<17, // straight move
-       Conv = 1<<18, // size conversion
-       Cjmp = 1<<19, // conditional jump
-       Break = 1<<20, // breaks control flow (no fallthrough)
-       Call = 1<<21, // function call
-       Jump = 1<<22, // jump
-       Skip = 1<<23, // data instruction
-};
-
 void proginfo(ProgInfo*, Prog*);
-
-// To allow use of AJMP and ACALL in ../gc/popt.c.
-enum
-{
-       AJMP = AB,
-       ACALL = ABL,
-};
index 639f4c5f634569768a7d01258a2d4ecd5d8837a3..1a4df8d622490dc739b9f706601e9865eb85d9be 100644 (file)
@@ -46,6 +46,7 @@ static int    copysub1(Prog*, Adr*, Adr*, int);
 static Flow*   findpre(Flow *r, Adr *v);
 static int     copyau1(Prog *p, Adr *v);
 static int     isdconst(Addr *a);
+static int     isfloatreg(Addr*);
 
 static uint32  gactive;
 
@@ -54,6 +55,7 @@ int   shiftprop(Flow *r);
 void   constprop(Adr *c1, Adr *v1, Flow *r);
 void   predicate(Graph*);
 
+
 void
 peep(Prog *firstp)
 {
@@ -79,7 +81,7 @@ loop1:
                case ASRL:
                case ASRA:
                        /*
-                        * elide shift into D_SHIFT operand of subsequent instruction
+                        * elide shift into TYPE_SHIFT operand of subsequent instruction
                         */
 //                     if(shiftprop(r)) {
 //                             excise(r);
@@ -94,7 +96,7 @@ loop1:
                case AMOVF:
                case AMOVD:
                        if(regtyp(&p->from))
-                       if(p->from.type == p->to.type)
+                       if(p->from.type == p->to.type && isfloatreg(&p->from) == isfloatreg(&p->to))
                        if(p->scond == C_SCOND_NONE) {
                                if(copyprop(g, r)) {
                                        excise(r);
@@ -113,13 +115,14 @@ loop1:
                case AMOVHU:
                case AMOVBS:
                case AMOVBU:
-                       if(p->from.type == D_REG) {
+                       if(p->from.type == TYPE_REG) {
                                if(shortprop(r))
                                        t++;
                        }
                        break;
 
 #ifdef NOTDEF
+XXX
                        if(p->scond == C_SCOND_NONE)
                        if(regtyp(&p->to))
                        if(isdconst(&p->from)) {
@@ -141,12 +144,12 @@ loop1:
                         */
                        if(isdconst(&p->from) && p->from.offset == -1) {
                                p->as = AMVN;
-                               p->from.type = D_REG;
-                               if(p->reg != NREG)
+                               p->from.type = TYPE_REG;
+                               if(p->reg != 0)
                                        p->from.reg = p->reg;
                                else
                                        p->from.reg = p->to.reg;
-                               p->reg = NREG;
+                               p->reg = 0;
                        }
                        break;
                }
@@ -159,10 +162,10 @@ loop1:
                case AMOVB:
                case AMOVBS:
                case AMOVBU:
-                       if(p->from.type == D_OREG && p->from.offset == 0)
+                       if(p->from.type == TYPE_MEM && p->from.offset == 0)
                                xtramodes(g, r, &p->from);
                        else
-                       if(p->to.type == D_OREG && p->to.offset == 0)
+                       if(p->to.type == TYPE_MEM && p->to.offset == 0)
                                xtramodes(g, r, &p->to);
                        else
                                continue;
@@ -205,17 +208,17 @@ loop1:
 //                     if(r1 == nil)
 //                             continue;
 //                     p1 = r1->prog;
-//                     if(p1->to.type != D_REG)
+//                     if(p1->to.type != TYPE_REG)
 //                             continue;
 //                     if(p1->to.reg != p->reg)
-//                     if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
+//                     if(!(p1->as == AMOVW && p1->from.type == TYPE_REG && p1->from.reg == p->reg))
 //                             continue;
 //
 //                     switch(p1->as) {
 //                     default:
 //                             continue;
 //                     case AMOVW:
-//                             if(p1->from.type != D_REG)
+//                             if(p1->from.type != TYPE_REG)
 //                                     continue;
 //                     case AAND:
 //                     case AEOR:
@@ -245,12 +248,7 @@ loop1:
 int
 regtyp(Adr *a)
 {
-
-       if(a->type == D_REG)
-               return 1;
-       if(a->type == D_FREG)
-               return 1;
-       return 0;
+       return a->type == TYPE_REG && (REG_R0 <= a->reg && a->reg <= REG_R15 || REG_F0 <= a->reg && a->reg <= REG_F15);
 }
 
 /*
@@ -293,7 +291,7 @@ subprop(Flow *r0)
                if(info.flags & Call)
                        return 0;
 
-               if((info.flags & CanRegRead) && p->to.type == D_REG) {
+               if((info.flags & CanRegRead) && p->to.type == TYPE_REG) {
                        info.flags |= RegRead;
                        info.flags &= ~(CanRegRead | RightRead);
                        p->reg = p->to.reg;
@@ -575,12 +573,12 @@ shiftprop(Flow *r)
        Adr a;
 
        p = r->prog;
-       if(p->to.type != D_REG)
+       if(p->to.type != TYPE_REG)
                FAIL("BOTCH: result not reg");
        n = p->to.reg;
        a = zprog.from;
-       if(p->reg != NREG && p->reg != p->to.reg) {
-               a.type = D_REG;
+       if(p->reg != 0 && p->reg != p->to.reg) {
+               a.type = TYPE_REG;
                a.reg = p->reg;
        }
        if(debug['P'])
@@ -598,8 +596,8 @@ shiftprop(Flow *r)
                        print("\n%P", p1);
                switch(copyu(p1, &p->to, nil)) {
                case 0: /* not used or set */
-                       if((p->from.type == D_REG && copyu(p1, &p->from, nil) > 1) ||
-                          (a.type == D_REG && copyu(p1, &a, nil) > 1))
+                       if((p->from.type == TYPE_REG && copyu(p1, &p->from, nil) > 1) ||
+                          (a.type == TYPE_REG && copyu(p1, &a, nil) > 1))
                                FAIL("args modified");
                        continue;
                case 3: /* set, not used */
@@ -620,8 +618,8 @@ shiftprop(Flow *r)
        case ASBC:
        case ARSB:
        case ARSC:
-               if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
-                       if(p1->from.type != D_REG)
+               if(p1->reg == n || (p1->reg == 0 && p1->to.type == TYPE_REG && p1->to.reg == n)) {
+                       if(p1->from.type != TYPE_REG)
                                FAIL("can't swap");
                        p1->reg = p1->from.reg;
                        p1->from.reg = n;
@@ -648,12 +646,12 @@ shiftprop(Flow *r)
        case ACMN:
                if(p1->reg == n)
                        FAIL("can't swap");
-               if(p1->reg == NREG && p1->to.reg == n)
+               if(p1->reg == 0 && p1->to.reg == n)
                        FAIL("shift result used twice");
 //     case AMVN:
-               if(p1->from.type == D_SHIFT)
+               if(p1->from.type == TYPE_SHIFT)
                        FAIL("shift result used in shift");
-               if(p1->from.type != D_REG || p1->from.reg != n)
+               if(p1->from.type != TYPE_REG || p1->from.reg != n)
                        FAIL("BOTCH: where is it used?");
                break;
        }
@@ -679,18 +677,18 @@ shiftprop(Flow *r)
        }
 
        /* make the substitution */
-       p2->from.type = D_SHIFT;
-       p2->from.reg = NREG;
+       p2->from.reg = 0;
        o = p->reg;
-       if(o == NREG)
+       if(o == 0)
                o = p->to.reg;
+       o &= 15;
 
        switch(p->from.type){
-       case D_CONST:
+       case TYPE_CONST:
                o |= (p->from.offset&0x1f)<<7;
                break;
-       case D_REG:
-               o |= (1<<4) | (p->from.reg<<8);
+       case TYPE_REG:
+               o |= (1<<4) | ((p->from.reg&15)<<8);
                break;
        }
        switch(p->as){
@@ -704,6 +702,8 @@ shiftprop(Flow *r)
                o |= 2<<5;
                break;
        }
+       p2->from = zprog.from;
+       p2->from.type = TYPE_SHIFT;
        p2->from.offset = o;
        if(debug['P'])
                print("\t=>%P\tSUCCEED\n", p2);
@@ -774,16 +774,16 @@ nochange(Flow *r, Flow *r2, Prog *p)
        if(r == r2)
                return 1;
        n = 0;
-       if(p->reg != NREG && p->reg != p->to.reg) {
-               a[n].type = D_REG;
+       if(p->reg != 0 && p->reg != p->to.reg) {
+               a[n].type = TYPE_REG;
                a[n++].reg = p->reg;
        }
        switch(p->from.type) {
-       case D_SHIFT:
-               a[n].type = D_REG;
-               a[n++].reg = p->from.offset&0xf;
-       case D_REG:
-               a[n].type = D_REG;
+       case TYPE_SHIFT:
+               a[n].type = TYPE_REG;
+               a[n++].reg = REG_R0 + (p->from.offset&0xf);
+       case TYPE_REG:
+               a[n].type = TYPE_REG;
                a[n++].reg = p->from.reg;
        }
        if(n == 0)
@@ -851,55 +851,58 @@ xtramodes(Graph *g, Flow *r, Adr *a)
 
        p = r->prog;
        v = *a;
-       v.type = D_REG;
+       v.type = TYPE_REG;
        r1 = findpre(r, &v);
        if(r1 != nil) {
                p1 = r1->prog;
-               if(p1->to.type == D_REG && p1->to.reg == v.reg)
+               if(p1->to.type == TYPE_REG && p1->to.reg == v.reg)
                switch(p1->as) {
                case AADD:
                        if(p1->scond & C_SBIT)
                                // avoid altering ADD.S/ADC sequences.
                                break;
-                       if(p1->from.type == D_REG ||
-                          (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
+                       if(p1->from.type == TYPE_REG ||
+                          (p1->from.type == TYPE_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
                            ((p->as != AMOVB && p->as != AMOVBS) || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
-                          (p1->from.type == D_CONST &&
+                          ((p1->from.type == TYPE_ADDR || p1->from.type == TYPE_CONST) &&
                            p1->from.offset > -4096 && p1->from.offset < 4096))
                        if(nochange(uniqs(r1), r, p1)) {
                                if(a != &p->from || v.reg != p->to.reg)
                                if (finduse(g, r->s1, &v)) {
-                                       if(p1->reg == NREG || p1->reg == v.reg)
+                                       if(p1->reg == 0 || p1->reg == v.reg)
                                                /* pre-indexing */
                                                p->scond |= C_WBIT;
                                        else return 0;
                                }
                                switch (p1->from.type) {
-                               case D_REG:
+                               case TYPE_REG:
                                        /* register offset */
                                        if(nacl)
                                                return 0;
-                                       a->type = D_SHIFT;
-                                       a->offset = p1->from.reg;
+                                       *a = zprog.from;
+                                       a->type = TYPE_SHIFT;
+                                       a->offset = p1->from.reg&15;
                                        break;
-                               case D_SHIFT:
+                               case TYPE_SHIFT:
                                        /* scaled register offset */
                                        if(nacl)
                                                return 0;
-                                       a->type = D_SHIFT;
-                               case D_CONST:
+                                       *a = zprog.from;
+                                       a->type = TYPE_SHIFT;
+                               case TYPE_CONST:
+                               case TYPE_ADDR:
                                        /* immediate offset */
                                        a->offset = p1->from.offset;
                                        break;
                                }
-                               if(p1->reg != NREG)
+                               if(p1->reg != 0)
                                        a->reg = p1->reg;
                                excise(r1);
                                return 1;
                        }
                        break;
                case AMOVW:
-                       if(p1->from.type == D_REG)
+                       if(p1->from.type == TYPE_REG)
                        if((r2 = findinc(r1, r, &p1->from)) != nil) {
                        for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
                                ;
@@ -948,9 +951,9 @@ copyu(Prog *p, Adr *v, Adr *s)
                return 2;
 
        case AMOVM:
-               if(v->type != D_REG)
+               if(v->type != TYPE_REG)
                        return 0;
-               if(p->from.type == D_CONST) {   /* read reglist, read/rar */
+               if(p->from.type == TYPE_CONST) {        /* read reglist, read/rar */
                        if(s != nil) {
                                if(p->from.offset&(1<<v->reg))
                                        return 1;
@@ -1002,8 +1005,8 @@ copyu(Prog *p, Adr *v, Adr *s)
        case AMOVFD:
        case AMOVDF:
                if(p->scond&(C_WBIT|C_PBIT))
-               if(v->type == D_REG) {
-                       if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
+               if(v->type == TYPE_REG) {
+                       if(p->from.type == TYPE_MEM || p->from.type == TYPE_SHIFT) {
                                if(p->from.reg == v->reg)
                                        return 2;
                        } else {
@@ -1084,7 +1087,7 @@ copyu(Prog *p, Adr *v, Adr *s)
                if(copyas(&p->to, v)) {
                        if(p->scond != C_SCOND_NONE)
                                return 2;
-                       if(p->reg == NREG)
+                       if(p->reg == 0)
                                p->reg = p->to.reg;
                        if(copyau(&p->from, v))
                                return 4;
@@ -1143,16 +1146,20 @@ copyu(Prog *p, Adr *v, Adr *s)
                return 3;
 
        case ABL:       /* funny */
-               if(v->type == D_REG) {
-                       if(v->reg <= REGEXT && v->reg > exregoffset)
+               if(v->type == TYPE_REG) {
+                       // TODO(rsc): REG_R0 and REG_F0 used to be
+                       // (when register numbers started at 0) exregoffset and exfregoffset,
+                       // which are unset entirely. 
+                       // It's strange that this handles R0 and F0 differently from the other
+                       // registers. Possible failure to optimize?
+                       if(REG_R0 < v->reg && v->reg <= REGEXT)
                                return 2;
                        if(v->reg == REGARG)
                                return 2;
-               }
-               if(v->type == D_FREG)
-                       if(v->reg <= FREGEXT && v->reg > exfregoffset)
+                       if(REG_F0 < v->reg && v->reg <= FREGEXT)
                                return 2;
-               if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg)
+               }
+               if(p->from.type == TYPE_REG && v->type == TYPE_REG && p->from.reg == v->reg)
                        return 2;
 
                if(s != nil) {
@@ -1166,7 +1173,7 @@ copyu(Prog *p, Adr *v, Adr *s)
        case ADUFFZERO:
                // R0 is zero, used by DUFFZERO, cannot be substituted.
                // R1 is ptr to memory, used and set, cannot be substituted.
-               if(v->type == D_REG) {
+               if(v->type == TYPE_REG) {
                        if(v->reg == REGALLOC_R0)
                                return 1;
                        if(v->reg == REGALLOC_R0+1)
@@ -1176,7 +1183,7 @@ copyu(Prog *p, Adr *v, Adr *s)
        case ADUFFCOPY:
                // R0 is scratch, set by DUFFCOPY, cannot be substituted.
                // R1, R2 areptr to src, dst, used and set, cannot be substituted.
-               if(v->type == D_REG) {
+               if(v->type == TYPE_REG) {
                        if(v->reg == REGALLOC_R0)
                                return 3;
                        if(v->reg == REGALLOC_R0+1 || v->reg == REGALLOC_R0+2)
@@ -1185,7 +1192,7 @@ copyu(Prog *p, Adr *v, Adr *s)
                return 0;
                        
        case ATEXT:     /* funny */
-               if(v->type == D_REG)
+               if(v->type == TYPE_REG)
                        if(v->reg == REGARG)
                                return 3;
                return 0;
@@ -1212,7 +1219,7 @@ copyas(Adr *a, Adr *v)
                if(a->reg == v->reg)
                        return 1;
        } else
-       if(v->type == D_CONST) {                /* for constprop */
+       if(v->type == TYPE_CONST) {             /* for constprop */
                if(a->type == v->type)
                if(a->name == v->name)
                if(a->sym == v->sym)
@@ -1230,10 +1237,11 @@ sameaddr(Adr *a, Adr *v)
                return 0;
        if(regtyp(v) && a->reg == v->reg)
                return 1;
-       if(v->type == D_AUTO || v->type == D_PARAM) {
-               if(v->offset == a->offset)
-                       return 1;
-       }
+       // TODO(rsc): Change v->type to v->name and enable.
+       //if(v->type == NAME_AUTO || v->type == NAME_PARAM) {
+       //      if(v->offset == a->offset)
+       //              return 1;
+       //}
        return 0;
 }
 
@@ -1246,94 +1254,31 @@ copyau(Adr *a, Adr *v)
 
        if(copyas(a, v))
                return 1;
-       if(v->type == D_REG) {
-               if(a->type == D_CONST && a->reg != NREG) {
+       if(v->type == TYPE_REG) {
+               if(a->type == TYPE_ADDR && a->reg != 0) {
                        if(a->reg == v->reg)
                                return 1;
                } else
-               if(a->type == D_OREG) {
+               if(a->type == TYPE_MEM) {
                        if(a->reg == v->reg)
                                return 1;
                } else
-               if(a->type == D_REGREG || a->type == D_REGREG2) {
+               if(a->type == TYPE_REGREG || a->type == TYPE_REGREG2) {
                        if(a->reg == v->reg)
                                return 1;
                        if(a->offset == v->reg)
                                return 1;
                } else
-               if(a->type == D_SHIFT) {
-                       if((a->offset&0xf) == v->reg)
+               if(a->type == TYPE_SHIFT) {
+                       if((a->offset&0xf) == v->reg - REG_R0)
                                return 1;
-                       if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+                       if((a->offset&(1<<4)) && ((a->offset>>8)&0xf) == v->reg - REG_R0)
                                return 1;
                }
        }
        return 0;
 }
 
-static int
-a2type(Prog *p)
-{
-       if(p->reg == NREG)
-               return D_NONE;
-
-       switch(p->as) {
-       default:
-               fatal("a2type: unhandled %P", p);
-
-       case AAND:
-       case AEOR:
-       case ASUB:
-       case ARSB:
-       case AADD:
-       case AADC:
-       case ASBC:
-       case ARSC:
-       case ATST:
-       case ATEQ:
-       case ACMP:
-       case ACMN:
-       case AORR:
-       case ABIC:
-       case AMVN:
-       case ASRL:
-       case ASRA:
-       case ASLL:
-       case AMULU:
-       case ADIVU:
-       case AMUL:
-       case ADIV:
-       case AMOD:
-       case AMODU:
-       case AMULA:
-       case AMULL:
-       case AMULAL:
-       case AMULLU:
-       case AMULALU:
-       case AMULWT:
-       case AMULWB:
-       case AMULAWT:
-       case AMULAWB:
-               return D_REG;
-
-       case ACMPF:
-       case ACMPD:
-       case AADDF:
-       case AADDD:
-       case ASUBF:
-       case ASUBD:
-       case AMULF:
-       case AMULD:
-       case ADIVF:
-       case ADIVD:
-       case ASQRTF:
-       case ASQRTD:
-       case AABSF:
-       case AABSD:
-               return D_FREG;
-       }
-}
-
 /*
  * compare v to the center
  * register in p (p->reg)
@@ -1341,9 +1286,9 @@ a2type(Prog *p)
 static int
 copyau1(Prog *p, Adr *v)
 {
-       if(v->type == D_REG && v->reg == NREG)
+       if(v->type == TYPE_REG && v->reg == 0)
                return 0;
-       return p->reg == v->reg && a2type(p) == v->type;
+       return p->reg == v->reg;
 }
 
 /*
@@ -1356,13 +1301,13 @@ copysub(Adr *a, Adr *v, Adr *s, int f)
 
        if(f)
        if(copyau(a, v)) {
-               if(a->type == D_SHIFT) {
-                       if((a->offset&0xf) == v->reg)
-                               a->offset = (a->offset&~0xf)|s->reg;
-                       if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
-                               a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
+               if(a->type == TYPE_SHIFT) {
+                       if((a->offset&0xf) == v->reg - REG_R0)
+                               a->offset = (a->offset&~0xf)|(s->reg&0xf);
+                       if((a->offset&(1<<4)) && ((a->offset>>8)&0xf) == v->reg - REG_R0)
+                               a->offset = (a->offset&~(0xf<<8))|((s->reg&0xf)<<8);
                } else
-               if(a->type == D_REGREG || a->type == D_REGREG2) {
+               if(a->type == TYPE_REGREG || a->type == TYPE_REGREG2) {
                        if(a->offset == v->reg)
                                a->offset = s->reg;
                        if(a->reg == v->reg)
@@ -1444,10 +1389,6 @@ predicable(Prog *p)
        case AXXX:
        case ADATA:
        case AGLOBL:
-       case AGOK:
-       case AHISTORY:
-       case ANAME:
-       case ASIGNAME:
        case ATEXT:
        case AWORD:
        case ABCASE:
@@ -1609,9 +1550,13 @@ predicate(Graph *g)
 static int
 isdconst(Addr *a)
 {
-       if(a->type == D_CONST && a->reg == NREG)
-               return 1;
-       return 0;
+       return a->type == TYPE_CONST;
+}
+
+static int
+isfloatreg(Addr *a)
+{
+       return REG_F0 <= a->reg && a->reg <= REG_F15;
 }
 
 int
@@ -1623,7 +1568,7 @@ stackaddr(Addr *a)
 int
 smallindir(Addr *a, Addr *reg)
 {
-       return reg->type == D_REG && a->type == D_OREG &&
+       return reg->type == TYPE_REG && a->type == TYPE_MEM &&
                a->reg == reg->reg &&
                0 <= a->offset && a->offset < 4096;
 }
index 797bc0718ed18147ea1dfb1f42f5f332af5e4624..a77f2336e9697c1af2978c385486c7ada412bcc8 100644 (file)
@@ -136,12 +136,12 @@ proginfo(ProgInfo *info, Prog *p)
        if(info->flags == 0)
                fatal("unknown instruction %P", p);
 
-       if(p->from.type == D_CONST && p->from.sym != nil && (info->flags & LeftRead)) {
+       if(p->from.type == TYPE_ADDR && p->from.sym != nil && (info->flags & LeftRead)) {
                info->flags &= ~LeftRead;
                info->flags |= LeftAddr;
        }
 
-       if((info->flags & RegRead) && p->reg == NREG) {
+       if((info->flags & RegRead) && p->reg == 0) {
                info->flags &= ~RegRead;
                info->flags |= CanRegRead | RightRead;
        }
index 30fb816013213c0975023815802a2c7f63a3c088..93090ebe42dc695f3a73cc7fd34a215a4dd3e8af 100644 (file)
@@ -67,11 +67,7 @@ excise(Flow *r)
        Prog *p;
 
        p = r->prog;
-       p->as = ANOP;
-       p->scond = zprog.scond;
-       p->from = zprog.from;
-       p->to = zprog.to;
-       p->reg = zprog.reg;
+       nopout(p);
 }
 
 static void
@@ -199,7 +195,7 @@ regopt(Prog *firstp)
                proginfo(&info, p);
 
                // Avoid making variables for direct-called functions.
-               if(p->as == ABL && p->to.name == D_EXTERN)
+               if(p->as == ABL && p->to.name == NAME_EXTERN)
                        continue;
 
                bit = mkvar(r, &p->from);
@@ -209,12 +205,8 @@ regopt(Prog *firstp)
                if(info.flags & LeftAddr)
                        setaddrs(bit);
 
-               if(info.flags & RegRead) {      
-                       if(p->from.type != D_FREG)
-                               r->use1.b[0] |= RtoB(p->reg);
-                       else
-                               r->use1.b[0] |= FtoB(p->reg);
-               }
+               if(info.flags & RegRead)        
+                       r->use1.b[0] |= RtoB(p->reg);
 
                if(info.flags & (RightAddr | RightRead | RightWrite)) {
                        bit = mkvar(r, &p->to);
@@ -230,7 +222,7 @@ regopt(Prog *firstp)
 
                /* the mod/div runtime routines smash R12 */
                if(p->as == ADIV || p->as == ADIVU || p->as == AMOD || p->as == AMODU)
-                       r->set.b[0] |= RtoB(12);
+                       r->set.b[0] |= RtoB(REG_R12);
        }
        if(firstr == R)
                return;
@@ -274,7 +266,7 @@ regopt(Prog *firstp)
        }
        for(r = firstr; r != R; r = (Reg*)r->f.link) {
                p = r->f.prog;
-               if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
+               if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
                        active++;
                        walkvardef(p->to.node, r, active);
                }
@@ -463,18 +455,11 @@ brk:
                vreg = paint2(rgp->enter, rgp->varno, 0);
                vreg = allreg(vreg, rgp);
                if(debug['R']) {
-                       if(rgp->regno >= NREG)
-                               print("%L $%d F%d: %Q\n",
-                                       rgp->enter->f.prog->lineno,
-                                       rgp->cost,
-                                       rgp->regno-NREG,
-                                       bit);
-                       else
-                               print("%L $%d R%d: %Q\n",
-                                       rgp->enter->f.prog->lineno,
-                                       rgp->cost,
-                                       rgp->regno,
-                                       bit);
+                       print("%L $%d %R: %Q\n",
+                               rgp->enter->f.prog->lineno,
+                               rgp->cost,
+                               rgp->regno,
+                               bit);
                }
                if(rgp->regno != 0)
                        paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
@@ -529,7 +514,7 @@ brk:
        for(p = firstp; p != P; p = p->link) {
                while(p->link != P && p->link->as == ANOP)
                        p->link = p->link->link;
-               if(p->to.type == D_BRANCH)
+               if(p->to.type == TYPE_BRANCH)
                        while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
                                p->to.u.branch = p->to.u.branch->link;
                if(p->as == AMOVW && p->to.reg == 13) {
@@ -538,7 +523,7 @@ brk:
 //                             print("%P adjusting %d\n", p, vreg);
                                continue;
                        }
-                       if(p->from.type == D_CONST && p->to.type == D_REG) {
+                       if(p->from.type == TYPE_CONST && p->to.type == TYPE_REG) {
                                if(p->from.offset != vreg)
                                        print("in and out different\n");
 //                             print("%P finish %d\n", p, vreg);
@@ -546,18 +531,18 @@ brk:
                                continue;
                        }
 
-//                     print("%P %d %d from type\n", p, p->from.type, D_CONST);
-//                     print("%P %d %d to type\n\n", p, p->to.type, D_REG);
+//                     print("%P %d %d from type\n", p, p->from.type, TYPE_CONST);
+//                     print("%P %d %d to type\n\n", p, p->to.type, TYPE_REG);
                }
 
                if(p->as == AMOVW && vreg != 0) {
                        if(p->from.sym != nil)
-                       if(p->from.name == D_AUTO || p->from.name == D_PARAM) {
+                       if(p->from.name == NAME_AUTO || p->from.name == NAME_PARAM) {
                                p->from.offset += vreg;
 //                             print("%P adjusting from %d %d\n", p, vreg, p->from.type);
                        }
                        if(p->to.sym != nil)
-                       if(p->to.name == D_AUTO || p->to.name == D_PARAM) {
+                       if(p->to.name == NAME_AUTO || p->to.name == NAME_PARAM) {
                                p->to.offset += vreg;
 //                             print("%P adjusting to %d %d\n", p, vreg, p->from.type);
                        }
@@ -640,7 +625,7 @@ addmove(Reg *r, int bn, int rn, int f)
        // If there's a stack fixup coming (after BL newproc or BL deferproc),
        // delay the load until after the fixup.
        p2 = p->link;
-       if(p2 && p2->as == AMOVW && p2->from.type == D_CONST && p2->from.reg == REGSP && p2->to.reg == REGSP && p2->to.type == D_REG)
+       if(p2 && p2->as == AMOVW && p2->from.type == TYPE_ADDR && p2->from.reg == REGSP && p2->to.reg == REGSP && p2->to.type == TYPE_REG)
                p = p2;
 
        p1->link = p->link;
@@ -655,9 +640,11 @@ addmove(Reg *r, int bn, int rn, int f)
        a->sym = linksym(v->node->sym);
        a->offset = v->offset;
        a->etype = v->etype;
-       a->type = D_OREG;
-       if(a->etype == TARRAY || a->sym == nil)
-               a->type = D_CONST;
+       a->type = TYPE_MEM;
+       if(a->etype == TARRAY)
+               a->type = TYPE_ADDR;
+       else if(a->sym == nil)
+               a->type = TYPE_CONST;
 
        if(v->addr)
                fatal("addmove: shouldn't be doing this %A\n", a);
@@ -693,21 +680,13 @@ addmove(Reg *r, int bn, int rn, int f)
                break;
        }
 
-       p1->from.type = D_REG;
+       p1->from.type = TYPE_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->type = TYPE_REG;
                a->reg = rn;
-               if(rn >= NREG) {
-                       a->type = D_FREG;
-                       a->reg = rn-NREG;
-               }
                if(v->etype == TUINT8 || v->etype == TBOOL)
                        p1->as = AMOVBU;
                if(v->etype == TUINT16)
@@ -749,33 +728,38 @@ mkvar(Reg *r, Adr *a)
                print("type %d %d %D\n", t, a->name, a);
                goto none;
 
-       case D_NONE:
-       case D_FCONST:
-       case D_BRANCH:
+       case TYPE_NONE:
+       case TYPE_FCONST:
+       case TYPE_BRANCH:
                break;
 
 
-       case D_REGREG:
-       case D_REGREG2:
+       case TYPE_REGREG:
+       case TYPE_REGREG2:
                bit = zbits;
-               if(a->offset != NREG)
+               if(a->offset != 0)
                        bit.b[0] |= RtoB(a->offset);
-               if(a->reg != NREG)
+               if(a->reg != 0)
                        bit.b[0] |= RtoB(a->reg);
                return bit;
+       
+       case TYPE_CONST:
+               if(a->reg != 0)
+                       fatal("found CONST instead of ADDR: %D", a);
+               break;
 
-       case D_CONST:
-       case D_REG:
-       case D_SHIFT:
-               if(a->reg != NREG) {
+       case TYPE_ADDR:
+       case TYPE_REG:
+       case TYPE_SHIFT:
+               if(a->reg != 0) {
                        bit = zbits;
                        bit.b[0] = RtoB(a->reg);
                        return bit;
                }
                break;
 
-       case D_OREG:
-               if(a->reg != NREG) {
+       case TYPE_MEM:
+               if(a->reg != 0) {
                        if(a == &r->f.prog->from)
                                r->use1.b[0] |= RtoB(a->reg);
                        else
@@ -784,24 +768,16 @@ mkvar(Reg *r, Adr *a)
                                r->set.b[0] |= RtoB(a->reg);
                }
                break;
-
-       case D_FREG:
-               if(a->reg != NREG) {
-                       bit = zbits;
-                       bit.b[0] = FtoB(a->reg);
-                       return bit;
-               }
-               break;
        }
 
        switch(a->name) {
        default:
                goto none;
 
-       case D_EXTERN:
-       case D_STATIC:
-       case D_AUTO:
-       case D_PARAM:
+       case NAME_EXTERN:
+       case NAME_STATIC:
+       case NAME_AUTO:
+       case NAME_PARAM:
                n = a->name;
                break;
        }
@@ -878,10 +854,10 @@ mkvar(Reg *r, Adr *a)
        node->opt = v;
        
        bit = blsh(i);
-       if(n == D_EXTERN || n == D_STATIC)
+       if(n == NAME_EXTERN || n == NAME_STATIC)
                for(z=0; z<BITS; z++)
                        externs.b[z] |= bit.b[z];
-       if(n == D_PARAM)
+       if(n == NAME_PARAM)
                for(z=0; z<BITS; z++)
                        params.b[z] |= bit.b[z];
 
@@ -1103,8 +1079,8 @@ allreg(uint32 b, Rgn *r)
        case TFLOAT64:
                i = BtoF(~b);
                if(i && r->cost >= 0) {
-                       r->regno = i+NREG;
-                       return FtoB(i);
+                       r->regno = i;
+                       return RtoB(i);
                }
                break;
 
@@ -1329,13 +1305,9 @@ addreg(Adr *a, int rn)
 {
        a->sym = nil;
        a->node = nil;
-       a->name = D_NONE;
-       a->type = D_REG;
+       a->name = NAME_NONE;
+       a->type = TYPE_REG;
        a->reg = rn;
-       if(rn >= NREG) {
-               a->type = D_FREG;
-               a->reg = rn-NREG;
-       }
 }
 
 /*
@@ -1345,13 +1317,29 @@ addreg(Adr *a, int rn)
  *     ...     ...
  *     10      R10
  *     12  R12
+ *
+ *     bit     reg
+ *     18      F2
+ *     19      F3
+ *     ...     ...
+ *     31      F15
  */
 uint32
 RtoB(int r)
 {
-       if(r >= REGTMP-2 && r != 12)    // excluded R9 and R10 for m and g, but not R12
-               return 0;
-       return 1L << r;
+       if(REG_R0 <= r && r <= REG_R15) {
+               if(r >= REGTMP-2 && r != REG_R12)       // excluded R9 and R10 for m and g, but not R12
+                       return 0;
+               return 1L << (r - REG_R0);
+       }
+       
+       if(REG_F0 <= r && r <= REG_F15) {
+               if(r < REG_F2 || r > REG_F0+NFREG-1)
+                       return 0;
+               return 1L << ((r - REG_F0) + 16);
+       }
+       
+       return 0;
 }
 
 int
@@ -1362,33 +1350,16 @@ BtoR(uint32 b)
        b &= 0x11fcL;   // excluded R9 and R10 for m and g, but not R12
        if(b == 0)
                return 0;
-       return bitno(b);
-}
-
-/*
- *     bit     reg
- *     18      F2
- *     19      F3
- *     ...     ...
- *     31      F15
- */
-uint32
-FtoB(int f)
-{
-
-       if(f < 2 || f > NFREG-1)
-               return 0;
-       return 1L << (f + 16);
+       return bitno(b) + REG_R0;
 }
 
 int
 BtoF(uint32 b)
 {
-
        b &= 0xfffc0000L;
        if(b == 0)
                return 0;
-       return bitno(b) - 16;
+       return bitno(b) - 16 + REG_F0;
 }
 
 void
index 38a33db6429dd7f3503d7b07fb65ba614bbdc48c..fa1dcc34e8a73f2044cf09b2d5fe58a7710c3a7e 100644 (file)
@@ -42,24 +42,64 @@ enum
 
 enum
 {
-       REGRET = 0,
+       REG_R0 = 32, // must be 16-aligned
+       REG_R1,
+       REG_R2,
+       REG_R3,
+       REG_R4,
+       REG_R5,
+       REG_R6,
+       REG_R7,
+       REG_R8,
+       REG_R9,
+       REG_R10,
+       REG_R11,
+       REG_R12,
+       REG_R13,
+       REG_R14,
+       REG_R15,
+       
+       REG_F0, // must be 16-aligned
+       REG_F1,
+       REG_F2,
+       REG_F3,
+       REG_F4,
+       REG_F5,
+       REG_F6,
+       REG_F7,
+       REG_F8,
+       REG_F9,
+       REG_F10,
+       REG_F11,
+       REG_F12,
+       REG_F13,
+       REG_F14,
+       REG_F15,
+
+       REG_FPSR, // must be 2-aligned
+       REG_FPCR,
+
+       REG_CPSR, // must be 2-aligned
+       REG_SPSR,
+
+       REGRET = REG_R0,
        /* compiler allocates R1 up as temps */
        /* compiler allocates register variables R3 up */
        /* compiler allocates external registers R10 down */
-       REGEXT = 10,
+       REGEXT = REG_R10,
        /* these two registers are declared in runtime.h */
        REGG = REGEXT-0,
        REGM = REGEXT-1,
 
-       REGTMP = 11,
-       REGSP = 13,
-       REGLINK = 14,
-       REGPC = 15,
+       REGTMP = REG_R11,
+       REGSP = REG_R13,
+       REGLINK = REG_R14,
+       REGPC = REG_R15,
        
        NFREG = 16,
-       FREGRET = 0,
-       FREGEXT = 7,
-       FREGTMP = 15,
+       FREGRET = REG_F0,
+       FREGEXT = REG_F7,
+       FREGTMP = REG_F15,
 };
 /* compiler allocates register variables F0 up */
 /* compiler allocates external registers F7 down */
@@ -109,6 +149,7 @@ enum
        C_HREG,
 
        C_ADDR,         /* reference to relocatable address */
+       C_TEXTSIZE,
 
        C_GOK,
 
@@ -117,9 +158,7 @@ enum
 
 enum
 {
-       AXXX,
-
-       AAND,
+       AAND = A_ARCHSPECIFIC,
        AEOR,
        ASUB,
        ARSB,
@@ -136,9 +175,6 @@ enum
 
        AMVN,
 
-       AB,
-       ABL,
-
 /*
  * Do not reorder or fragment the conditional branch
  * opcodes, or the predication code will break
@@ -205,25 +241,14 @@ enum
        ASWPBU,
        ASWPW,
 
-       ANOP,
        ARFE,
        ASWI,
        AMULA,
 
-       ADATA,
-       AGLOBL,
-       AGOK,
-       AHISTORY,
-       ANAME,
-       ARET,
-       ATEXT,
        AWORD,
-       ADYNT_,
-       AINIT_,
        ABCASE,
        ACASE,
 
-       AEND,
 
        AMULL,
        AMULAL,
@@ -234,7 +259,6 @@ enum
        ABXRET,
        ADWORD,
 
-       ASIGNAME,
 
        ALDREX,
        ASTREX,
@@ -244,7 +268,6 @@ enum
 
        APLD,
 
-       AUNDEF,
 
        ACLZ,
 
@@ -253,21 +276,16 @@ enum
        AMULAWT,
        AMULAWB,
        
-       AUSEFIELD,
-       ATYPE,
-       AFUNCDATA,
-       APCDATA,
-       ACHECKNIL,
-       AVARDEF,
-       AVARKILL,
-       ADUFFCOPY,
-       ADUFFZERO,
        ADATABUNDLE,
        ADATABUNDLEEND,
 
        AMRC, // MRC/MCR
 
        ALAST,
+       
+       // aliases
+       AB = AJMP,
+       ABL = ACALL,
 };
 
 /* scond byte */
@@ -280,22 +298,27 @@ enum
        C_FBIT = 1<<7,  /* psr flags-only */
        C_UBIT = 1<<7,  /* up bit, unsigned bit */
 
-       C_SCOND_EQ = 0,
-       C_SCOND_NE = 1,
-       C_SCOND_HS = 2,
-       C_SCOND_LO = 3,
-       C_SCOND_MI = 4,
-       C_SCOND_PL = 5,
-       C_SCOND_VS = 6,
-       C_SCOND_VC = 7,
-       C_SCOND_HI = 8,
-       C_SCOND_LS = 9,
-       C_SCOND_GE = 10,
-       C_SCOND_LT = 11,
-       C_SCOND_GT = 12,
-       C_SCOND_LE = 13,
-       C_SCOND_NONE = 14,
-       C_SCOND_NV = 15,
+       // These constants are the ARM condition codes encodings,
+       // XORed with 14 so that C_SCOND_NONE has value 0,
+       // so that a zeroed Prog.scond means "always execute".
+       C_SCOND_XOR = 14,
+
+       C_SCOND_EQ = 0 ^ C_SCOND_XOR,
+       C_SCOND_NE = 1 ^ C_SCOND_XOR,
+       C_SCOND_HS = 2 ^ C_SCOND_XOR,
+       C_SCOND_LO = 3 ^ C_SCOND_XOR,
+       C_SCOND_MI = 4 ^ C_SCOND_XOR,
+       C_SCOND_PL = 5 ^ C_SCOND_XOR,
+       C_SCOND_VS = 6 ^ C_SCOND_XOR,
+       C_SCOND_VC = 7 ^ C_SCOND_XOR,
+       C_SCOND_HI = 8 ^ C_SCOND_XOR,
+       C_SCOND_LS = 9 ^ C_SCOND_XOR,
+       C_SCOND_GE = 10 ^ C_SCOND_XOR,
+       C_SCOND_LT = 11 ^ C_SCOND_XOR,
+       C_SCOND_GT = 12 ^ C_SCOND_XOR,
+       C_SCOND_LE = 13 ^ C_SCOND_XOR,
+       C_SCOND_NONE = 14 ^ C_SCOND_XOR,
+       C_SCOND_NV = 15 ^ C_SCOND_XOR,
 
        /* D_SHIFT type */
        SHIFT_LL = 0<<5,
@@ -304,43 +327,6 @@ enum
        SHIFT_RR = 3<<5,
 };
 
-enum
-{
-/* type/name */
-       D_GOK = 0,
-       D_NONE = 1,
-
-/* type */
-       D_BRANCH = (D_NONE+1),
-       D_OREG = (D_NONE+2),
-       D_CONST = (D_NONE+7),
-       D_FCONST = (D_NONE+8),
-       D_SCONST = (D_NONE+9),
-       D_PSR = (D_NONE+10),
-       D_REG = (D_NONE+12),
-       D_FREG = (D_NONE+13),
-       D_FILE = (D_NONE+16),
-       D_OCONST = (D_NONE+17),
-       D_FILE1 = (D_NONE+18),
-
-       D_SHIFT = (D_NONE+19),
-       D_FPCR = (D_NONE+20),
-       D_REGREG = (D_NONE+21), // (reg, reg)
-       D_ADDR = (D_NONE+22),
-
-       D_SBIG = (D_NONE+23),
-       D_CONST2 = (D_NONE+24),
-
-       D_REGREG2 = (D_NONE+25), // reg, reg
-
-/* name */
-       D_EXTERN = (D_NONE+3),
-       D_STATIC = (D_NONE+4),
-       D_AUTO = (D_NONE+5),
-       D_PARAM = (D_NONE+6),
-
-       D_LAST = (D_NONE+26),
-};
 
 /*
  * this is the ranlib header
index e1927b6d40e8505630a01af73157dddcc1b164f5..95c4babdfc9a31c64f4a0f795a4df88f9aadf1bc 100644 (file)
@@ -139,6 +139,7 @@ EXTERN      int32   thunk;
 EXTERN Biobuf  obuf;
 EXTERN Link*   ctxt;
 EXTERN Biobuf  bstdout;
+EXTERN Prog*   lastpc;
 
 void*  alloc(int32);
 void*  allocn(void*, int32, int32);
index 29011c7ffb05e478fd875918bc51f584132d6fde..df3ca40b2c0d27677614540b2461c3ad92befb9d 100644 (file)
 %token <dval>  LFCONST
 %token <sval>  LSCONST LSP
 %token <sym>   LNAME LLAB LVAR
-%type  <lval>  con con2 expr pointer offset
-%type  <addr>  mem imm imm2 reg nam rel rem rim rom omem nmem
+%type  <lval>  con expr pointer offset
+%type  <addr>  mem imm reg nam rel rem rim rom omem nmem textsize
 %type  <addr2> nonnon nonrel nonrem rimnon rimrem remrim
-%type  <addr2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
-%type  <addr2> spec10 spec11 spec12 spec13
+%type  <addr2> spec3 spec4 spec5 spec6 spec7 spec8 spec9
+%type  <addr2> spec10 spec12 spec13
 %%
 prog:
 |      prog 
@@ -102,8 +102,8 @@ inst:
 |      LTYPE3 rimrem   { outcode($1, &$2); }
 |      LTYPE4 remrim   { outcode($1, &$2); }
 |      LTYPER nonrel   { outcode($1, &$2); }
-|      LTYPED spec1    { outcode($1, &$2); }
-|      LTYPET spec2    { outcode($1, &$2); }
+|      spec1
+|      spec2
 |      LTYPEC spec3    { outcode($1, &$2); }
 |      LTYPEN spec4    { outcode($1, &$2); }
 |      LTYPES spec5    { outcode($1, &$2); }
@@ -112,7 +112,7 @@ inst:
 |      LTYPEXC spec8   { outcode($1, &$2); }
 |      LTYPEX spec9    { outcode($1, &$2); }
 |      LTYPERT spec10  { outcode($1, &$2); }
-|      LTYPEG spec11   { outcode($1, &$2); }
+|      spec11
 |      LTYPEPC spec12  { outcode($1, &$2); }
 |      LTYPEF spec13   { outcode($1, &$2); }
 
@@ -183,26 +183,60 @@ nonrel:
        }
 
 spec1: /* DATA */
-       nam '/' con ',' imm
+       LTYPED nam '/' con ',' imm
        {
-               $$.from = $1;
-               $$.from.scale = $3;
-               $$.to = $5;
+               Addr2 a;
+               a.from = $2;
+               a.to = $6;
+               outcode(ADATA, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
 
 spec2: /* TEXT */
-       mem ',' imm2
+       LTYPET mem ',' '$' textsize
        {
-               settext($1.sym);
-               $$.from = $1;
-               $$.to = $3;
+               Addr2 a;
+               settext($2.sym);
+               a.from = $2;
+               a.to = $5;
+               outcode(ATEXT, &a);
        }
-|      mem ',' con ',' imm2
+|      LTYPET mem ',' con ',' '$' textsize
        {
-               settext($1.sym);
-               $$.from = $1;
-               $$.from.scale = $3;
-               $$.to = $5;
+               Addr2 a;
+               settext($2.sym);
+               a.from = $2;
+               a.to = $7;
+               outcode(ATEXT, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
+       }
+
+spec11:        /* GLOBL */
+       LTYPEG mem ',' imm
+       {
+               Addr2 a;
+               settext($2.sym);
+               a.from = $2;
+               a.to = $4;
+               outcode(AGLOBL, &a);
+       }
+|      LTYPEG mem ',' con ',' imm
+       {
+               Addr2 a;
+               settext($2.sym);
+               a.from = $2;
+               a.to = $6;
+               outcode(AGLOBL, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
 
 spec3: /* JMP/CALL */
@@ -231,7 +265,7 @@ spec5:      /* SHL/SHR */
        {
                $$.from = $1;
                $$.to = $3;
-               if($$.from.index != D_NONE)
+               if($$.from.index != TYPE_NONE)
                        yyerror("dp shift with lhs index");
                $$.from.index = $5;
        }
@@ -246,7 +280,7 @@ spec6:      /* MOVW/MOVL */
        {
                $$.from = $1;
                $$.to = $3;
-               if($$.to.index != D_NONE)
+               if($$.to.index != TYPE_NONE)
                        yyerror("dp move with lhs index");
                $$.to.index = $5;
        }
@@ -281,7 +315,7 @@ spec9:      /* shufl */
        {
                $$.from = $3;
                $$.to = $5;
-               if($1.type != D_CONST)
+               if($1.type != TYPE_CONST)
                        yyerror("illegal constant");
                $$.to.offset = $1.offset;
        }
@@ -297,23 +331,10 @@ spec10:   /* RET/RETF */
                $$.to = nullgen;
        }
 
-spec11:        /* GLOBL */
-       mem ',' imm
-       {
-               $$.from = $1;
-               $$.to = $3;
-       }
-|      mem ',' con ',' imm
-       {
-               $$.from = $1;
-               $$.from.scale = $3;
-               $$.to = $5;
-       }
-
 spec12:        /* PCDATA */
        rim ',' rim
        {
-               if($1.type != D_CONST || $3.type != D_CONST)
+               if($1.type != TYPE_CONST || $3.type != TYPE_CONST)
                        yyerror("arguments to PCDATA must be integer constants");
                $$.from = $1;
                $$.to = $3;
@@ -322,9 +343,9 @@ spec12:     /* PCDATA */
 spec13:        /* FUNCDATA */
        rim ',' rim
        {
-               if($1.type != D_CONST)
+               if($1.type != TYPE_CONST)
                        yyerror("index for FUNCDATA must be integer constant");
-               if($3.type != D_EXTERN && $3.type != D_STATIC)
+               if($3.type != TYPE_MEM || ($3.name != NAME_EXTERN && $3.name != NAME_STATIC))
                        yyerror("value for FUNCDATA must be symbol reference");
                $$.from = $1;
                $$.to = $3;
@@ -356,7 +377,7 @@ rel:
        con '(' LPC ')'
        {
                $$ = nullgen;
-               $$.type = D_BRANCH;
+               $$.type = TYPE_BRANCH;
                $$.offset = $1 + pc;
        }
 |      LNAME offset
@@ -365,7 +386,7 @@ rel:
                $$ = nullgen;
                if(pass == 2 && $1->type != LLAB)
                        yyerror("undefined label: %s", $1->labelname);
-               $$.type = D_BRANCH;
+               $$.type = TYPE_BRANCH;
                $$.offset = $1->value + $2;
        }
 
@@ -373,58 +394,57 @@ reg:
        LBREG
        {
                $$ = nullgen;
-               $$.type = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 |      LFREG
        {
                $$ = nullgen;
-               $$.type = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 |      LLREG
        {
                $$ = nullgen;
-               $$.type = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 |      LMREG
        {
                $$ = nullgen;
-               $$.type = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 |      LSP
        {
                $$ = nullgen;
-               $$.type = D_SP;
+               $$.type = TYPE_REG;
+               $$.reg = REG_SP;
        }
 |      LSREG
        {
                $$ = nullgen;
-               $$.type = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 |      LXREG
        {
                $$ = nullgen;
-               $$.type = $1;
-       }
-imm2:
-       '$' con2
-       {
-               $$ = nullgen;
-               $$.type = D_CONST;
-               $$.offset = $2;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 
 imm:
        '$' con
        {
                $$ = nullgen;
-               $$.type = D_CONST;
+               $$.type = TYPE_CONST;
                $$.offset = $2;
        }
 |      '$' nam
        {
                $$ = $2;
-               $$.index = $2.type;
-               $$.type = D_ADDR;
+               $$.type = TYPE_ADDR;
                /*
                if($2.type == D_AUTO || $2.type == D_PARAM)
                        yyerror("constant cannot be automatic: %s",
@@ -434,31 +454,31 @@ imm:
 |      '$' LSCONST
        {
                $$ = nullgen;
-               $$.type = D_SCONST;
+               $$.type = TYPE_SCONST;
                memcpy($$.u.sval, $2, sizeof($$.u.sval));
        }
 |      '$' LFCONST
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = $2;
        }
 |      '$' '(' LFCONST ')'
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = $3;
        }
 |      '$' '(' '-' LFCONST ')'
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = -$4;
        }
 |      '$' '-' LFCONST
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = -$3;
        }
 
@@ -470,31 +490,34 @@ omem:
        con
        {
                $$ = nullgen;
-               $$.type = D_INDIR+D_NONE;
+               $$.type = TYPE_MEM;
                $$.offset = $1;
        }
 |      con '(' LLREG ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$3;
+               $$.type = TYPE_MEM;
+               $$.reg = $3;
                $$.offset = $1;
        }
 |      con '(' LSP ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+D_SP;
+               $$.type = TYPE_MEM;
+               $$.reg = REG_SP;
                $$.offset = $1;
        }
 |      con '(' LSREG ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$3;
+               $$.type = TYPE_MEM;
+               $$.reg = $3;
                $$.offset = $1;
        }
 |      con '(' LLREG '*' con ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+D_NONE;
+               $$.type = TYPE_MEM;
                $$.offset = $1;
                $$.index = $3;
                $$.scale = $5;
@@ -503,7 +526,8 @@ omem:
 |      con '(' LLREG ')' '(' LLREG '*' con ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$3;
+               $$.type = TYPE_MEM;
+               $$.reg = $3;
                $$.offset = $1;
                $$.index = $6;
                $$.scale = $8;
@@ -512,7 +536,8 @@ omem:
 |      con '(' LLREG ')' '(' LSREG '*' con ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$3;
+               $$.type = TYPE_MEM;
+               $$.reg = $3;
                $$.offset = $1;
                $$.index = $6;
                $$.scale = $8;
@@ -521,17 +546,19 @@ omem:
 |      '(' LLREG ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$2;
+               $$.type = TYPE_MEM;
+               $$.reg = $2;
        }
 |      '(' LSP ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+D_SP;
+               $$.type = TYPE_MEM;
+               $$.reg = REG_SP;
        }
 |      '(' LLREG '*' con ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+D_NONE;
+               $$.type = TYPE_MEM;
                $$.index = $2;
                $$.scale = $4;
                checkscale($$.scale);
@@ -539,7 +566,8 @@ omem:
 |      '(' LLREG ')' '(' LLREG '*' con ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$2;
+               $$.type = TYPE_MEM;
+               $$.reg = $2;
                $$.index = $5;
                $$.scale = $7;
                checkscale($$.scale);
@@ -562,14 +590,16 @@ nam:
        LNAME offset '(' pointer ')'
        {
                $$ = nullgen;
-               $$.type = $4;
+               $$.type = TYPE_MEM;
+               $$.name = $4;
                $$.sym = linklookup(ctxt, $1->name, 0);
                $$.offset = $2;
        }
 |      LNAME '<' '>' offset '(' LSB ')'
        {
                $$ = nullgen;
-               $$.type = D_STATIC;
+               $$.type = TYPE_MEM;
+               $$.name = NAME_STATIC;
                $$.sym = linklookup(ctxt, $1->name, 1);
                $$.offset = $4;
        }
@@ -591,7 +621,7 @@ pointer:
        LSB
 |      LSP
        {
-               $$ = D_AUTO;
+               $$ = NAME_AUTO;
        }
 |      LFP
 
@@ -618,26 +648,34 @@ con:
                $$ = $2;
        }
 
-con2:
+textsize:
        LCONST
        {
-               $$ = ($1 & 0xffffffffLL) +
-                       ((vlong)ArgsSizeUnknown << 32);
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = $1;
+               $$.u.argsize = ArgsSizeUnknown;
        }
 |      '-' LCONST
        {
-               $$ = (-$2 & 0xffffffffLL) +
-                       ((vlong)ArgsSizeUnknown << 32);
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = -$2;
+               $$.u.argsize = ArgsSizeUnknown;
        }
 |      LCONST '-' LCONST
        {
-               $$ = ($1 & 0xffffffffLL) +
-                       (($3 & 0xffffLL) << 32);
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = $1;
+               $$.u.argsize = $3;
        }
 |      '-' LCONST '-' LCONST
        {
-               $$ = (-$2 & 0xffffffffLL) +
-                       (($4 & 0xffffLL) << 32);
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = -$2;
+               $$.u.argsize = $4;
        }
 
 expr:
index 0a47bfad5a0c398ae4f71df785dc8afa307c3b68..c600796cd032d49a31554de67936ae94e8c678da 100644 (file)
@@ -204,135 +204,136 @@ struct
        ushort  value;
 } itab[] =
 {
-       "SP",           LSP,    D_AUTO,
-       "SB",           LSB,    D_EXTERN,
-       "FP",           LFP,    D_PARAM,
-       "PC",           LPC,    D_BRANCH,
+       "SP",           LSP,    NAME_AUTO,
+       "SB",           LSB,    NAME_EXTERN,
+       "FP",           LFP,    NAME_PARAM,
 
-       "AL",           LBREG,  D_AL,
-       "CL",           LBREG,  D_CL,
-       "DL",           LBREG,  D_DL,
-       "BL",           LBREG,  D_BL,
-/*     "SPB",          LBREG,  D_SPB,  */
-       "SIB",          LBREG,  D_SIB,
-       "DIB",          LBREG,  D_DIB,
-       "BPB",          LBREG,  D_BPB,
-       "R8B",          LBREG,  D_R8B,
-       "R9B",          LBREG,  D_R9B,
-       "R10B",         LBREG,  D_R10B,
-       "R11B",         LBREG,  D_R11B,
-       "R12B",         LBREG,  D_R12B,
-       "R13B",         LBREG,  D_R13B,
-       "R14B",         LBREG,  D_R14B,
-       "R15B",         LBREG,  D_R15B,
+       "PC",           LPC,    TYPE_BRANCH,
 
-       "AH",           LBREG,  D_AH,
-       "CH",           LBREG,  D_CH,
-       "DH",           LBREG,  D_DH,
-       "BH",           LBREG,  D_BH,
+       "AL",           LBREG,  REG_AL,
+       "CL",           LBREG,  REG_CL,
+       "DL",           LBREG,  REG_DL,
+       "BL",           LBREG,  REG_BL,
+/*     "SPB",          LBREG,  REG_SPB,        */
+       "SIB",          LBREG,  REG_SIB,
+       "DIB",          LBREG,  REG_DIB,
+       "BPB",          LBREG,  REG_BPB,
+       "R8B",          LBREG,  REG_R8B,
+       "R9B",          LBREG,  REG_R9B,
+       "R10B",         LBREG,  REG_R10B,
+       "R11B",         LBREG,  REG_R11B,
+       "R12B",         LBREG,  REG_R12B,
+       "R13B",         LBREG,  REG_R13B,
+       "R14B",         LBREG,  REG_R14B,
+       "R15B",         LBREG,  REG_R15B,
 
-       "AX",           LLREG,  D_AX,
-       "CX",           LLREG,  D_CX,
-       "DX",           LLREG,  D_DX,
-       "BX",           LLREG,  D_BX,
-/*     "SP",           LLREG,  D_SP,   */
-       "BP",           LLREG,  D_BP,
-       "SI",           LLREG,  D_SI,
-       "DI",           LLREG,  D_DI,
-       "R8",           LLREG,  D_R8,
-       "R9",           LLREG,  D_R9,
-       "R10",          LLREG,  D_R10,
-       "R11",          LLREG,  D_R11,
-       "R12",          LLREG,  D_R12,
-       "R13",          LLREG,  D_R13,
-       "R14",          LLREG,  D_R14,
-       "R15",          LLREG,  D_R15,
+       "AH",           LBREG,  REG_AH,
+       "CH",           LBREG,  REG_CH,
+       "DH",           LBREG,  REG_DH,
+       "BH",           LBREG,  REG_BH,
+
+       "AX",           LLREG,  REG_AX,
+       "CX",           LLREG,  REG_CX,
+       "DX",           LLREG,  REG_DX,
+       "BX",           LLREG,  REG_BX,
+/*     "SP",           LLREG,  REG_SP, */
+       "BP",           LLREG,  REG_BP,
+       "SI",           LLREG,  REG_SI,
+       "DI",           LLREG,  REG_DI,
+       "R8",           LLREG,  REG_R8,
+       "R9",           LLREG,  REG_R9,
+       "R10",          LLREG,  REG_R10,
+       "R11",          LLREG,  REG_R11,
+       "R12",          LLREG,  REG_R12,
+       "R13",          LLREG,  REG_R13,
+       "R14",          LLREG,  REG_R14,
+       "R15",          LLREG,  REG_R15,
 
        "RARG",         LLREG,  REGARG,
 
-       "F0",           LFREG,  D_F0+0,
-       "F1",           LFREG,  D_F0+1,
-       "F2",           LFREG,  D_F0+2,
-       "F3",           LFREG,  D_F0+3,
-       "F4",           LFREG,  D_F0+4,
-       "F5",           LFREG,  D_F0+5,
-       "F6",           LFREG,  D_F0+6,
-       "F7",           LFREG,  D_F0+7,
+       "F0",           LFREG,  REG_F0+0,
+       "F1",           LFREG,  REG_F0+1,
+       "F2",           LFREG,  REG_F0+2,
+       "F3",           LFREG,  REG_F0+3,
+       "F4",           LFREG,  REG_F0+4,
+       "F5",           LFREG,  REG_F0+5,
+       "F6",           LFREG,  REG_F0+6,
+       "F7",           LFREG,  REG_F0+7,
 
-       "M0",           LMREG,  D_M0+0,
-       "M1",           LMREG,  D_M0+1,
-       "M2",           LMREG,  D_M0+2,
-       "M3",           LMREG,  D_M0+3,
-       "M4",           LMREG,  D_M0+4,
-       "M5",           LMREG,  D_M0+5,
-       "M6",           LMREG,  D_M0+6,
-       "M7",           LMREG,  D_M0+7,
+       "M0",           LMREG,  REG_M0+0,
+       "M1",           LMREG,  REG_M0+1,
+       "M2",           LMREG,  REG_M0+2,
+       "M3",           LMREG,  REG_M0+3,
+       "M4",           LMREG,  REG_M0+4,
+       "M5",           LMREG,  REG_M0+5,
+       "M6",           LMREG,  REG_M0+6,
+       "M7",           LMREG,  REG_M0+7,
 
-       "X0",           LXREG,  D_X0+0,
-       "X1",           LXREG,  D_X0+1,
-       "X2",           LXREG,  D_X0+2,
-       "X3",           LXREG,  D_X0+3,
-       "X4",           LXREG,  D_X0+4,
-       "X5",           LXREG,  D_X0+5,
-       "X6",           LXREG,  D_X0+6,
-       "X7",           LXREG,  D_X0+7,
-       "X8",           LXREG,  D_X0+8,
-       "X9",           LXREG,  D_X0+9,
-       "X10",          LXREG,  D_X0+10,
-       "X11",          LXREG,  D_X0+11,
-       "X12",          LXREG,  D_X0+12,
-       "X13",          LXREG,  D_X0+13,
-       "X14",          LXREG,  D_X0+14,
-       "X15",          LXREG,  D_X0+15,
+       "X0",           LXREG,  REG_X0+0,
+       "X1",           LXREG,  REG_X0+1,
+       "X2",           LXREG,  REG_X0+2,
+       "X3",           LXREG,  REG_X0+3,
+       "X4",           LXREG,  REG_X0+4,
+       "X5",           LXREG,  REG_X0+5,
+       "X6",           LXREG,  REG_X0+6,
+       "X7",           LXREG,  REG_X0+7,
+       "X8",           LXREG,  REG_X0+8,
+       "X9",           LXREG,  REG_X0+9,
+       "X10",          LXREG,  REG_X0+10,
+       "X11",          LXREG,  REG_X0+11,
+       "X12",          LXREG,  REG_X0+12,
+       "X13",          LXREG,  REG_X0+13,
+       "X14",          LXREG,  REG_X0+14,
+       "X15",          LXREG,  REG_X0+15,
 
-       "CS",           LSREG,  D_CS,
-       "SS",           LSREG,  D_SS,
-       "DS",           LSREG,  D_DS,
-       "ES",           LSREG,  D_ES,
-       "FS",           LSREG,  D_FS,
-       "GS",           LSREG,  D_GS,
+       "CS",           LSREG,  REG_CS,
+       "SS",           LSREG,  REG_SS,
+       "DS",           LSREG,  REG_DS,
+       "ES",           LSREG,  REG_ES,
+       "FS",           LSREG,  REG_FS,
+       "GS",           LSREG,  REG_GS,
 
-       "GDTR",         LBREG,  D_GDTR,
-       "IDTR",         LBREG,  D_IDTR,
-       "LDTR",         LBREG,  D_LDTR,
-       "MSW",          LBREG,  D_MSW,
-       "TASK",         LBREG,  D_TASK,
+       "GDTR",         LBREG,  REG_GDTR,
+       "IDTR",         LBREG,  REG_IDTR,
+       "LDTR",         LBREG,  REG_LDTR,
+       "MSW",          LBREG,  REG_MSW,
+       "TASK",         LBREG,  REG_TASK,
 
-       "CR0",          LBREG,  D_CR+0,
-       "CR1",          LBREG,  D_CR+1,
-       "CR2",          LBREG,  D_CR+2,
-       "CR3",          LBREG,  D_CR+3,
-       "CR4",          LBREG,  D_CR+4,
-       "CR5",          LBREG,  D_CR+5,
-       "CR6",          LBREG,  D_CR+6,
-       "CR7",          LBREG,  D_CR+7,
-       "CR8",          LBREG,  D_CR+8,
-       "CR9",          LBREG,  D_CR+9,
-       "CR10",         LBREG,  D_CR+10,
-       "CR11",         LBREG,  D_CR+11,
-       "CR12",         LBREG,  D_CR+12,
-       "CR13",         LBREG,  D_CR+13,
-       "CR14",         LBREG,  D_CR+14,
-       "CR15",         LBREG,  D_CR+15,
+       "CR0",          LBREG,  REG_CR+0,
+       "CR1",          LBREG,  REG_CR+1,
+       "CR2",          LBREG,  REG_CR+2,
+       "CR3",          LBREG,  REG_CR+3,
+       "CR4",          LBREG,  REG_CR+4,
+       "CR5",          LBREG,  REG_CR+5,
+       "CR6",          LBREG,  REG_CR+6,
+       "CR7",          LBREG,  REG_CR+7,
+       "CR8",          LBREG,  REG_CR+8,
+       "CR9",          LBREG,  REG_CR+9,
+       "CR10",         LBREG,  REG_CR+10,
+       "CR11",         LBREG,  REG_CR+11,
+       "CR12",         LBREG,  REG_CR+12,
+       "CR13",         LBREG,  REG_CR+13,
+       "CR14",         LBREG,  REG_CR+14,
+       "CR15",         LBREG,  REG_CR+15,
 
-       "DR0",          LBREG,  D_DR+0,
-       "DR1",          LBREG,  D_DR+1,
-       "DR2",          LBREG,  D_DR+2,
-       "DR3",          LBREG,  D_DR+3,
-       "DR4",          LBREG,  D_DR+4,
-       "DR5",          LBREG,  D_DR+5,
-       "DR6",          LBREG,  D_DR+6,
-       "DR7",          LBREG,  D_DR+7,
+       "DR0",          LBREG,  REG_DR+0,
+       "DR1",          LBREG,  REG_DR+1,
+       "DR2",          LBREG,  REG_DR+2,
+       "DR3",          LBREG,  REG_DR+3,
+       "DR4",          LBREG,  REG_DR+4,
+       "DR5",          LBREG,  REG_DR+5,
+       "DR6",          LBREG,  REG_DR+6,
+       "DR7",          LBREG,  REG_DR+7,
 
-       "TR0",          LBREG,  D_TR+0,
-       "TR1",          LBREG,  D_TR+1,
-       "TR2",          LBREG,  D_TR+2,
-       "TR3",          LBREG,  D_TR+3,
-       "TR4",          LBREG,  D_TR+4,
-       "TR5",          LBREG,  D_TR+5,
-       "TR6",          LBREG,  D_TR+6,
-       "TR7",          LBREG,  D_TR+7,
-       "TLS",          LSREG,  D_TLS,
+       "TR0",          LBREG,  REG_TR+0,
+       "TR1",          LBREG,  REG_TR+1,
+       "TR2",          LBREG,  REG_TR+2,
+       "TR3",          LBREG,  REG_TR+3,
+       "TR4",          LBREG,  REG_TR+4,
+       "TR5",          LBREG,  REG_TR+5,
+       "TR6",          LBREG,  REG_TR+6,
+       "TR7",          LBREG,  REG_TR+7,
+       "TLS",          LSREG,  REG_TLS,
 
        "AAA",          LTYPE0, AAAA,
        "AAD",          LTYPE0, AAAD,
@@ -1052,8 +1053,8 @@ cinit(void)
        Sym *s;
        int i;
 
-       nullgen.type = D_NONE;
-       nullgen.index = D_NONE;
+       nullgen.type = TYPE_NONE;
+       nullgen.index = TYPE_NONE;
 
        nerrors = 0;
        iostack = I;
@@ -1103,8 +1104,6 @@ cclean(void)
        outcode(AEND, &g2);
 }
 
-static Prog *lastpc;
-
 void
 outcode(int a, Addr2 *g2)
 {
index a698079d23f7f8a02a358e4a868cf326a518ba6e..a3ee581d6923c7f9f734209dd56768d45d87df8f 100644 (file)
@@ -411,14 +411,14 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  2
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   549
+#define YYLAST   524
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  56
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  41
+#define YYNNTS  40
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  134
+#define YYNRULES  133
 /* YYNRULES -- Number of states.  */
 #define YYNSTATES  271
 
@@ -435,8 +435,8 @@ static const yytype_uint8 yytranslate[] =
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,    54,    12,     5,     2,
-      52,    53,    10,     8,    51,     9,     2,    11,     2,     2,
+       2,     2,     2,     2,     2,     2,    52,    12,     5,     2,
+      53,    54,    10,     8,    51,     9,     2,    11,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,    48,    49,
        6,    50,     7,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -470,19 +470,19 @@ static const yytype_uint8 yytranslate[] =
 static const yytype_uint16 yyprhs[] =
 {
        0,     0,     3,     4,     5,     9,    10,    15,    17,    20,
-      23,    27,    31,    34,    37,    40,    43,    46,    49,    52,
-      55,    58,    61,    64,    67,    70,    73,    76,    79,    82,
-      85,    88,    89,    91,    95,    99,   102,   104,   107,   109,
-     112,   114,   118,   124,   128,   134,   137,   139,   141,   143,
-     147,   153,   157,   163,   166,   168,   172,   178,   184,   185,
-     187,   191,   197,   201,   205,   207,   209,   211,   213,   216,
-     219,   221,   223,   225,   227,   232,   235,   237,   239,   241,
-     243,   245,   247,   249,   252,   255,   258,   261,   264,   269,
-     275,   279,   281,   283,   285,   290,   295,   300,   307,   317,
-     327,   331,   335,   341,   350,   352,   359,   365,   373,   374,
-     377,   380,   382,   384,   386,   388,   390,   393,   396,   399,
-     403,   405,   408,   412,   417,   419,   423,   427,   431,   435,
-     439,   444,   449,   453,   457
+      23,    27,    31,    34,    37,    40,    43,    46,    49,    51,
+      53,    56,    59,    62,    65,    68,    71,    74,    77,    79,
+      82,    85,    86,    88,    92,    96,    99,   101,   104,   106,
+     109,   111,   115,   122,   128,   136,   141,   148,   151,   153,
+     155,   157,   161,   167,   171,   177,   180,   182,   186,   192,
+     198,   199,   201,   205,   209,   211,   213,   215,   217,   220,
+     223,   225,   227,   229,   231,   236,   239,   241,   243,   245,
+     247,   249,   251,   253,   256,   259,   262,   265,   270,   276,
+     280,   282,   284,   286,   291,   296,   301,   308,   318,   328,
+     332,   336,   342,   351,   353,   360,   366,   374,   375,   378,
+     381,   383,   385,   387,   389,   391,   394,   397,   400,   404,
+     406,   409,   413,   418,   420,   424,   428,   432,   436,   440,
+     445,   450,   454,   458
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
@@ -490,51 +490,51 @@ static const yytype_int8 yyrhs[] =
 {
       57,     0,    -1,    -1,    -1,    57,    58,    59,    -1,    -1,
       45,    48,    60,    59,    -1,    49,    -1,    61,    49,    -1,
-       1,    49,    -1,    45,    50,    96,    -1,    47,    50,    96,
+       1,    49,    -1,    45,    50,    95,    -1,    47,    50,    95,
       -1,    13,    62,    -1,    14,    66,    -1,    15,    65,    -1,
-      16,    63,    -1,    17,    64,    -1,    21,    67,    -1,    19,
-      68,    -1,    22,    69,    -1,    18,    70,    -1,    20,    71,
-      -1,    25,    72,    -1,    26,    73,    -1,    27,    74,    -1,
-      28,    75,    -1,    29,    76,    -1,    30,    77,    -1,    23,
-      78,    -1,    24,    79,    -1,    31,    80,    -1,    -1,    51,
-      -1,    83,    51,    81,    -1,    81,    51,    83,    -1,    83,
-      51,    -1,    83,    -1,    51,    81,    -1,    81,    -1,    51,
-      84,    -1,    84,    -1,    87,    51,    84,    -1,    91,    11,
-      94,    51,    87,    -1,    88,    51,    86,    -1,    88,    51,
-      94,    51,    86,    -1,    51,    82,    -1,    82,    -1,    62,
-      -1,    66,    -1,    83,    51,    81,    -1,    83,    51,    81,
-      48,    37,    -1,    83,    51,    81,    -1,    83,    51,    81,
-      48,    38,    -1,    83,    51,    -1,    83,    -1,    83,    51,
-      81,    -1,    85,    51,    81,    51,    94,    -1,    87,    51,
-      81,    51,    85,    -1,    -1,    87,    -1,    88,    51,    87,
-      -1,    88,    51,    94,    51,    87,    -1,    83,    51,    83,
-      -1,    83,    51,    83,    -1,    85,    -1,    88,    -1,    84,
-      -1,    90,    -1,    10,    85,    -1,    10,    89,    -1,    85,
-      -1,    89,    -1,    81,    -1,    87,    -1,    94,    52,    34,
-      53,    -1,    45,    92,    -1,    36,    -1,    39,    -1,    37,
-      -1,    40,    -1,    44,    -1,    38,    -1,    41,    -1,    54,
-      95,    -1,    54,    94,    -1,    54,    91,    -1,    54,    43,
-      -1,    54,    42,    -1,    54,    52,    42,    53,    -1,    54,
-      52,     9,    42,    53,    -1,    54,     9,    42,    -1,    89,
-      -1,    90,    -1,    94,    -1,    94,    52,    37,    53,    -1,
-      94,    52,    44,    53,    -1,    94,    52,    38,    53,    -1,
-      94,    52,    37,    10,    94,    53,    -1,    94,    52,    37,
-      53,    52,    37,    10,    94,    53,    -1,    94,    52,    37,
-      53,    52,    38,    10,    94,    53,    -1,    52,    37,    53,
-      -1,    52,    44,    53,    -1,    52,    37,    10,    94,    53,
-      -1,    52,    37,    53,    52,    37,    10,    94,    53,    -1,
-      91,    -1,    91,    52,    37,    10,    94,    53,    -1,    45,
-      92,    52,    93,    53,    -1,    45,     6,     7,    92,    52,
-      35,    53,    -1,    -1,     8,    94,    -1,     9,    94,    -1,
-      35,    -1,    44,    -1,    33,    -1,    32,    -1,    47,    -1,
-       9,    94,    -1,     8,    94,    -1,    55,    94,    -1,    52,
-      96,    53,    -1,    32,    -1,     9,    32,    -1,    32,     9,
-      32,    -1,     9,    32,     9,    32,    -1,    94,    -1,    96,
-       8,    96,    -1,    96,     9,    96,    -1,    96,    10,    96,
-      -1,    96,    11,    96,    -1,    96,    12,    96,    -1,    96,
-       6,     6,    96,    -1,    96,     7,     7,    96,    -1,    96,
-       5,    96,    -1,    96,     4,    96,    -1,    96,     3,    96,
-      -1
+      16,    63,    -1,    17,    64,    -1,    21,    67,    -1,    68,
+      -1,    69,    -1,    18,    71,    -1,    20,    72,    -1,    25,
+      73,    -1,    26,    74,    -1,    27,    75,    -1,    28,    76,
+      -1,    29,    77,    -1,    30,    78,    -1,    70,    -1,    24,
+      79,    -1,    31,    80,    -1,    -1,    51,    -1,    83,    51,
+      81,    -1,    81,    51,    83,    -1,    83,    51,    -1,    83,
+      -1,    51,    81,    -1,    81,    -1,    51,    84,    -1,    84,
+      -1,    86,    51,    84,    -1,    19,    90,    11,    93,    51,
+      86,    -1,    22,    87,    51,    52,    94,    -1,    22,    87,
+      51,    93,    51,    52,    94,    -1,    23,    87,    51,    86,
+      -1,    23,    87,    51,    93,    51,    86,    -1,    51,    82,
+      -1,    82,    -1,    62,    -1,    66,    -1,    83,    51,    81,
+      -1,    83,    51,    81,    48,    37,    -1,    83,    51,    81,
+      -1,    83,    51,    81,    48,    38,    -1,    83,    51,    -1,
+      83,    -1,    83,    51,    81,    -1,    85,    51,    81,    51,
+      93,    -1,    86,    51,    81,    51,    85,    -1,    -1,    86,
+      -1,    83,    51,    83,    -1,    83,    51,    83,    -1,    85,
+      -1,    87,    -1,    84,    -1,    89,    -1,    10,    85,    -1,
+      10,    88,    -1,    85,    -1,    88,    -1,    81,    -1,    86,
+      -1,    93,    53,    34,    54,    -1,    45,    91,    -1,    36,
+      -1,    39,    -1,    37,    -1,    40,    -1,    44,    -1,    38,
+      -1,    41,    -1,    52,    93,    -1,    52,    90,    -1,    52,
+      43,    -1,    52,    42,    -1,    52,    53,    42,    54,    -1,
+      52,    53,     9,    42,    54,    -1,    52,     9,    42,    -1,
+      88,    -1,    89,    -1,    93,    -1,    93,    53,    37,    54,
+      -1,    93,    53,    44,    54,    -1,    93,    53,    38,    54,
+      -1,    93,    53,    37,    10,    93,    54,    -1,    93,    53,
+      37,    54,    53,    37,    10,    93,    54,    -1,    93,    53,
+      37,    54,    53,    38,    10,    93,    54,    -1,    53,    37,
+      54,    -1,    53,    44,    54,    -1,    53,    37,    10,    93,
+      54,    -1,    53,    37,    54,    53,    37,    10,    93,    54,
+      -1,    90,    -1,    90,    53,    37,    10,    93,    54,    -1,
+      45,    91,    53,    92,    54,    -1,    45,     6,     7,    91,
+      53,    35,    54,    -1,    -1,     8,    93,    -1,     9,    93,
+      -1,    35,    -1,    44,    -1,    33,    -1,    32,    -1,    47,
+      -1,     9,    93,    -1,     8,    93,    -1,    55,    93,    -1,
+      53,    95,    54,    -1,    32,    -1,     9,    32,    -1,    32,
+       9,    32,    -1,     9,    32,     9,    32,    -1,    93,    -1,
+      95,     8,    95,    -1,    95,     9,    95,    -1,    95,    10,
+      95,    -1,    95,    11,    95,    -1,    95,    12,    95,    -1,
+      95,     6,     6,    95,    -1,    95,     7,     7,    95,    -1,
+      95,     5,    95,    -1,    95,     4,    95,    -1,    95,     3,
+      95,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
@@ -544,16 +544,16 @@ static const yytype_uint16 yyrline[] =
       88,    93,    99,   100,   101,   102,   103,   104,   105,   106,
      107,   108,   109,   110,   111,   112,   113,   114,   115,   116,
      117,   120,   124,   131,   138,   145,   150,   157,   162,   169,
-     174,   179,   186,   194,   200,   209,   214,   221,   222,   225,
-     230,   240,   245,   255,   260,   265,   272,   280,   290,   294,
-     301,   306,   314,   323,   334,   335,   338,   339,   340,   344,
-     348,   349,   352,   353,   356,   362,   373,   378,   383,   388,
-     393,   398,   403,   409,   417,   423,   434,   440,   446,   452,
-     458,   466,   467,   470,   476,   482,   488,   494,   503,   512,
-     521,   526,   531,   539,   549,   553,   562,   569,   578,   581,
-     585,   591,   592,   596,   599,   600,   604,   608,   612,   616,
-     622,   627,   632,   637,   644,   645,   649,   653,   657,   661,
-     665,   669,   673,   677,   681
+     174,   179,   186,   199,   207,   221,   229,   243,   248,   255,
+     256,   259,   264,   274,   279,   289,   294,   299,   306,   314,
+     324,   328,   335,   344,   355,   356,   359,   360,   361,   365,
+     369,   370,   373,   374,   377,   383,   394,   400,   406,   412,
+     418,   424,   430,   438,   444,   454,   460,   466,   472,   478,
+     486,   487,   490,   496,   503,   510,   517,   526,   536,   546,
+     552,   558,   566,   577,   581,   590,   598,   608,   611,   615,
+     621,   622,   626,   629,   630,   634,   638,   642,   646,   652,
+     659,   666,   673,   682,   683,   687,   691,   695,   699,   703,
+     707,   711,   715,   719
 };
 #endif
 
@@ -568,12 +568,12 @@ static const char *const yytname[] =
   "LTYPEPC", "LTYPES", "LTYPEM", "LTYPEI", "LTYPEXC", "LTYPEX", "LTYPERT",
   "LTYPEF", "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG",
   "LFREG", "LMREG", "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB",
-  "LVAR", "':'", "';'", "'='", "','", "'('", "')'", "'$'", "'~'",
+  "LVAR", "':'", "';'", "'='", "','", "'$'", "'('", "')'", "'~'",
   "$accept", "prog", "@1", "line", "@2", "inst", "nonnon", "rimrem",
-  "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2", "spec3",
-  "spec4", "spec5", "spec6", "spec7", "spec8", "spec9", "spec10", "spec11",
-  "spec12", "spec13", "rem", "rom", "rim", "rel", "reg", "imm2", "imm",
-  "mem", "omem", "nmem", "nam", "offset", "pointer", "con", "con2", "expr", 0
+  "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2", "spec11",
+  "spec3", "spec4", "spec5", "spec6", "spec7", "spec8", "spec9", "spec10",
+  "spec12", "spec13", "rem", "rom", "rim", "rel", "reg", "imm", "mem",
+  "omem", "nmem", "nam", "offset", "pointer", "con", "textsize", "expr", 0
 };
 #endif
 
@@ -587,7 +587,7 @@ static const yytype_uint16 yytoknum[] =
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
      285,   286,   287,   288,   289,   290,   291,   292,    58,    59,
-      61,    44,    40,    41,    36,   126
+      61,    44,    36,    40,    41,   126
 };
 # endif
 
@@ -599,34 +599,34 @@ static const yytype_uint8 yyr1[] =
       61,    61,    61,    61,    61,    61,    61,    61,    61,    61,
       61,    62,    62,    63,    64,    65,    65,    66,    66,    67,
       67,    67,    68,    69,    69,    70,    70,    71,    71,    72,
-      72,    73,    73,    74,    74,    74,    75,    76,    77,    77,
+      72,    73,    73,    74,    74,    75,    75,    75,    76,    77,
       78,    78,    79,    80,    81,    81,    82,    82,    82,    82,
       82,    82,    83,    83,    84,    84,    85,    85,    85,    85,
-      85,    85,    85,    86,    87,    87,    87,    87,    87,    87,
-      87,    88,    88,    89,    89,    89,    89,    89,    89,    89,
-      89,    89,    89,    89,    90,    90,    91,    91,    92,    92,
-      92,    93,    93,    93,    94,    94,    94,    94,    94,    94,
-      95,    95,    95,    95,    96,    96,    96,    96,    96,    96,
-      96,    96,    96,    96,    96
+      85,    85,    85,    86,    86,    86,    86,    86,    86,    86,
+      87,    87,    88,    88,    88,    88,    88,    88,    88,    88,
+      88,    88,    88,    89,    89,    90,    90,    91,    91,    91,
+      92,    92,    92,    93,    93,    93,    93,    93,    93,    94,
+      94,    94,    94,    95,    95,    95,    95,    95,    95,    95,
+      95,    95,    95,    95
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
        0,     2,     0,     0,     3,     0,     4,     1,     2,     2,
-       3,     3,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       3,     3,     2,     2,     2,     2,     2,     2,     1,     1,
+       2,     2,     2,     2,     2,     2,     2,     2,     1,     2,
        2,     0,     1,     3,     3,     2,     1,     2,     1,     2,
-       1,     3,     5,     3,     5,     2,     1,     1,     1,     3,
-       5,     3,     5,     2,     1,     3,     5,     5,     0,     1,
-       3,     5,     3,     3,     1,     1,     1,     1,     2,     2,
+       1,     3,     6,     5,     7,     4,     6,     2,     1,     1,
+       1,     3,     5,     3,     5,     2,     1,     3,     5,     5,
+       0,     1,     3,     3,     1,     1,     1,     1,     2,     2,
        1,     1,     1,     1,     4,     2,     1,     1,     1,     1,
-       1,     1,     1,     2,     2,     2,     2,     2,     4,     5,
-       3,     1,     1,     1,     4,     4,     4,     6,     9,     9,
-       3,     3,     5,     8,     1,     6,     5,     7,     0,     2,
-       2,     1,     1,     1,     1,     1,     2,     2,     2,     3,
-       1,     2,     3,     4,     1,     3,     3,     3,     3,     3,
-       4,     4,     3,     3,     3
+       1,     1,     1,     2,     2,     2,     2,     4,     5,     3,
+       1,     1,     1,     4,     4,     4,     6,     9,     9,     3,
+       3,     5,     8,     1,     6,     5,     7,     0,     2,     2,
+       1,     1,     1,     1,     1,     2,     2,     2,     3,     1,
+       2,     3,     4,     1,     3,     3,     3,     3,     3,     4,
+       4,     3,     3,     3
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -636,87 +636,85 @@ static const yytype_uint8 yydefact[] =
 {
        2,     3,     1,     0,     0,    31,     0,     0,     0,     0,
        0,     0,    31,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,    58,     0,     0,     0,     7,     4,     0,     9,
-      32,    12,     0,     0,   114,    76,    78,    81,    77,    79,
-      82,    80,   108,   115,     0,     0,     0,    13,    38,    64,
-      65,    91,    92,   104,    93,     0,    14,    72,    36,    73,
-      15,     0,    16,     0,     0,   108,     0,    20,    46,    66,
-      70,    71,    67,    93,    18,     0,    32,    47,    48,    21,
-     108,     0,     0,    17,    40,     0,     0,    19,     0,    28,
-       0,    29,     0,    22,     0,    23,     0,    24,    54,    25,
-       0,    26,     0,    27,    59,    30,     0,     5,     0,     0,
-       8,   117,   116,     0,     0,     0,     0,    37,     0,     0,
-     124,     0,   118,     0,     0,     0,    87,    86,     0,    85,
-      84,    35,     0,     0,    68,    69,    75,    45,     0,     0,
-      75,    39,     0,     0,     0,     0,     0,     0,     0,    53,
-       0,     0,     0,     0,    10,    11,   108,   109,   110,     0,
-       0,   100,   101,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   119,     0,     0,     0,     0,    90,     0,
-       0,    33,    34,     0,     0,    41,     0,    43,     0,    60,
-       0,    62,    49,    51,    55,     0,     0,    63,     6,     0,
-     113,   111,   112,     0,     0,     0,   134,   133,   132,     0,
-       0,   125,   126,   127,   128,   129,     0,     0,    94,    96,
-      95,     0,    88,    74,     0,     0,   120,    83,     0,     0,
-       0,     0,     0,     0,     0,   106,   102,     0,   130,   131,
-       0,     0,     0,    89,    42,   121,     0,    44,    61,    50,
-      52,    56,    57,     0,     0,   105,    97,     0,     0,     0,
-     122,   107,     0,     0,     0,   123,   103,     0,     0,    98,
-      99
+       0,     0,    60,     0,     0,     0,     7,     4,     0,    18,
+      19,    28,     9,    32,    12,     0,     0,   113,    76,    78,
+      81,    77,    79,    82,    80,   107,   114,     0,     0,     0,
+      13,    38,    64,    65,    90,    91,   103,    92,     0,    14,
+      72,    36,    73,    15,     0,    16,     0,     0,   107,     0,
+      20,    48,    66,    70,    71,    67,    92,     0,    32,    49,
+      50,    21,   107,     0,     0,    17,    40,     0,     0,     0,
+       0,    29,     0,    22,     0,    23,     0,    24,    56,    25,
+       0,    26,     0,    27,    61,    30,     0,     5,     0,     0,
+       8,   116,   115,     0,     0,     0,     0,    37,     0,     0,
+     123,     0,   117,     0,     0,     0,    86,    85,     0,    84,
+      83,    35,     0,     0,    68,    69,    75,    47,     0,     0,
+      75,    39,     0,     0,     0,     0,     0,     0,     0,    55,
+       0,     0,     0,     0,    10,    11,   107,   108,   109,     0,
+       0,    99,   100,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   118,     0,     0,     0,     0,    89,     0,
+       0,    33,    34,     0,     0,    41,     0,     0,    45,     0,
+      62,    51,    53,    57,     0,     0,    63,     6,     0,   112,
+     110,   111,     0,     0,     0,   133,   132,   131,     0,     0,
+     124,   125,   126,   127,   128,     0,     0,    93,    95,    94,
+       0,    87,    74,     0,     0,   119,    43,     0,     0,     0,
+       0,     0,     0,     0,   105,   101,     0,   129,   130,     0,
+       0,     0,    88,    42,   120,     0,     0,    46,    52,    54,
+      58,    59,     0,     0,   104,    96,     0,     0,     0,   121,
+      44,   106,     0,     0,     0,   122,   102,     0,     0,    97,
+      98
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     1,     3,    27,   153,    28,    31,    60,    62,    56,
-      47,    83,    74,    87,    67,    79,    93,    95,    97,    99,
-     101,   103,    89,    91,   105,    57,    68,    58,    69,    49,
-     187,    59,    50,    51,    52,    53,   116,   203,    54,   227,
-     121
+      -1,     1,     3,    27,   153,    28,    34,    63,    65,    59,
+      50,    85,    29,    30,    31,    70,    81,    93,    95,    97,
+      99,   101,   103,    91,   105,    60,    71,    61,    72,    52,
+      62,    53,    54,    55,    56,   116,   202,    57,   226,   121
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -89
+#define YYPACT_NINF -87
 static const yytype_int16 yypact[] =
 {
-     -89,    18,   -89,   163,    -5,   -13,   219,   253,   253,   335,
-     194,    16,   274,   369,   418,   418,   253,   253,   253,   253,
-     240,     0,     0,   253,   -17,    19,   -89,   -89,    24,   -89,
-     -89,   -89,   479,   479,   -89,   -89,   -89,   -89,   -89,   -89,
-     -89,   -89,   111,   -89,   335,   397,   479,   -89,   -89,   -89,
-     -89,   -89,   -89,    33,    51,   390,   -89,   -89,    65,   -89,
-     -89,    72,   -89,    73,   356,   111,   314,   -89,   -89,   -89,
-     -89,   -89,   -89,    74,   -89,    30,   335,   -89,   -89,   -89,
-      70,   422,   479,   -89,   -89,    82,    86,   -89,    88,   -89,
-      89,   -89,    90,   -89,    91,   -89,    92,   -89,   101,   -89,
-     105,   -89,   114,   -89,   -89,   -89,   116,   -89,   479,   479,
-     -89,   -89,   -89,   118,   479,   479,   120,   -89,     5,   115,
-     -89,    83,   -89,   133,   -12,   404,   -89,   -89,   439,   -89,
-     -89,   -89,   335,   253,   -89,   -89,   120,   -89,     9,   479,
-     -89,   -89,   422,   141,   119,   452,   253,   335,   335,   335,
-     335,   335,   253,   163,   327,   327,    70,   -89,   -89,     4,
-     479,   143,   -89,   479,   479,   479,   190,   191,   479,   479,
-     479,   479,   479,   -89,   187,     6,   148,   152,   -89,   470,
-     156,   -89,   -89,   158,   162,   -89,     8,   -89,   164,   -89,
-     166,   -89,   170,   171,   -89,   169,   172,   -89,   -89,   173,
-     -89,   -89,   -89,   161,   176,   199,   102,   530,   537,   479,
-     479,    39,    39,   -89,   -89,   -89,   479,   479,   185,   -89,
-     -89,   189,   -89,   -89,     0,   208,   234,   -89,   193,     0,
-     211,   212,   479,   240,   217,   -89,   -89,   255,    55,    55,
-     214,   215,    59,   -89,   -89,   260,   241,   -89,   -89,   -89,
-     -89,   -89,   -89,   222,   479,   -89,   -89,   262,   276,   256,
-     -89,   -89,   242,   479,   479,   -89,   -89,   243,   246,   -89,
-     -89
+     -87,    24,   -87,   211,    20,    -5,   236,   256,   256,   330,
+     156,    25,   290,    55,   364,   364,   256,   256,   256,   256,
+     145,    29,    29,   256,    17,    46,   -87,   -87,    26,   -87,
+     -87,   -87,   -87,   -87,   -87,   451,   451,   -87,   -87,   -87,
+     -87,   -87,   -87,   -87,   -87,    27,   -87,   330,   270,   451,
+     -87,   -87,   -87,   -87,   -87,   -87,    39,    44,    48,   -87,
+     -87,    65,   -87,   -87,    66,   -87,    68,   350,    27,   310,
+     -87,   -87,   -87,   -87,   -87,   -87,    71,   110,   330,   -87,
+     -87,   -87,    23,   384,   451,   -87,   -87,    75,    72,    77,
+      82,   -87,    85,   -87,    87,   -87,    88,   -87,    89,   -87,
+      90,   -87,    91,   -87,   -87,   -87,    92,   -87,   451,   451,
+     -87,   -87,   -87,   120,   451,   451,    98,   -87,     7,   113,
+     -87,   168,   -87,   115,     5,   391,   -87,   -87,   398,   -87,
+     -87,   -87,   330,   256,   -87,   -87,    98,   -87,     3,   451,
+     -87,   -87,   384,   122,   416,   426,   256,   330,   330,   330,
+     330,   330,   256,   211,   504,   504,    23,   -87,   -87,    76,
+     451,   117,   -87,   451,   451,   451,   162,   180,   451,   451,
+     451,   451,   451,   -87,   181,     8,   136,   148,   -87,   433,
+     150,   -87,   -87,   154,   159,   -87,    12,   163,   -87,   165,
+     -87,   169,   170,   -87,   204,   206,   -87,   -87,   160,   -87,
+     -87,   -87,   205,   207,   182,   485,   512,   240,   451,   451,
+     102,   102,   -87,   -87,   -87,   451,   451,   209,   -87,   -87,
+     212,   -87,   -87,    29,   231,   258,   -87,   217,    29,   233,
+     244,   451,   145,   249,   -87,   -87,   261,    42,    42,   232,
+     250,   -22,   -87,   -87,   276,   273,    12,   -87,   -87,   -87,
+     -87,   -87,   252,   451,   -87,   -87,   280,   300,   281,   -87,
+     -87,   -87,   262,   451,   451,   -87,   -87,   267,   278,   -87,
+     -87
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-     -89,   -89,   -89,   134,   -89,   -89,   289,   -89,   -89,   -89,
-     290,   -89,   -89,   -89,   -89,   -89,   -89,   -89,   -89,   -89,
-     -89,   -89,   -89,   -89,   -89,    -2,   237,    11,   -11,    -9,
-      76,    -8,    87,    -4,     2,    -3,   -56,   -89,   -10,   -89,
-     -88
+     -87,   -87,   -87,   171,   -87,   -87,   303,   -87,   -87,   -87,
+     321,   -87,   -87,   -87,   -87,   -87,   -87,   -87,   -87,   -87,
+     -87,   -87,   -87,   -87,   -87,    -2,   243,    11,   -11,    -9,
+      -8,    74,    -1,     2,    -3,   -62,   -87,   -10,    94,   -86
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -726,120 +724,116 @@ static const yytype_int16 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint16 yytable[] =
 {
-      73,    70,    84,    86,    48,    85,    71,    63,    75,   136,
-      48,   100,    72,   102,   104,   160,   217,   225,     2,    61,
-     154,   155,   111,   112,   140,   175,   176,    92,    94,    96,
-      98,   107,   177,   108,   106,   120,   122,   200,    30,   201,
-     226,   139,   117,   183,    29,   130,   175,   176,   202,   170,
-     171,   172,   129,   177,    55,   134,    73,    70,   161,   218,
-     135,    42,    71,   168,   169,   170,   171,   172,    72,   109,
-     141,    86,   120,   110,   117,   206,   207,   208,   114,   115,
-     211,   212,   213,   214,   215,   123,   163,   164,   165,   166,
-     167,   168,   169,   170,   171,   172,   257,   258,   120,   120,
-     199,    88,    90,   124,   157,   158,   164,   165,   166,   167,
-     168,   169,   170,   171,   172,   112,   131,   113,   120,   114,
-     115,   238,   239,   132,   133,   156,   138,    32,    33,   184,
-     181,   185,    86,   142,   188,   190,   173,   189,   143,   144,
-     145,   146,   147,   148,   182,   192,   193,   194,   195,   196,
-     204,    34,   149,   120,   120,   120,   150,   191,   120,   120,
-     120,   120,   120,   197,     4,   151,    43,   152,   162,   112,
-     174,    82,   159,   186,    46,   183,     5,     6,     7,     8,
-       9,    10,    11,    12,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,    23,   205,   209,   216,   210,   120,
-     120,   219,    32,    33,    64,   220,   240,   241,    24,   222,
-      25,   223,    26,   224,   235,   228,   244,   229,   230,   231,
-     232,   248,   251,   233,   252,   234,    34,    32,    33,   236,
-      35,    36,    37,    38,    39,    40,   237,   242,    41,    65,
-     245,    43,   243,   246,   262,    66,    45,   186,   249,    46,
-     250,    34,   253,   267,   268,    35,    36,    37,    38,    39,
-      40,    32,    33,    41,    42,   254,    43,   255,   256,   259,
-      44,    45,   263,   260,    46,   261,    35,    36,    37,    38,
-      39,    40,    32,    33,    41,    34,   264,   198,   265,    35,
-      36,    37,    38,    39,    40,   266,   269,    41,    42,   270,
-      43,    77,    78,   137,   247,    45,    34,    55,    46,     0,
-      35,    36,    37,    38,    39,    40,     0,     0,    41,    42,
-       0,    43,    32,    33,    64,    76,    45,     0,     0,    46,
-     163,   164,   165,   166,   167,   168,   169,   170,   171,   172,
-       0,     0,     0,    32,    33,     0,    34,     0,     0,     0,
-      35,    36,    37,    38,    39,    40,     0,     0,    41,    65,
-       0,    43,     0,     0,    32,    33,    45,    34,     0,    46,
-       0,    35,    36,    37,    38,    39,    40,    32,    33,    41,
-      42,     0,    43,     0,     0,     0,     0,    45,    34,     0,
-      46,     0,    35,    36,    37,    38,    39,    40,    32,   125,
-      41,    34,     0,    43,     0,    32,    33,     0,    45,     0,
-       0,    46,    32,    33,    80,     0,    43,     0,     0,     0,
-      81,    82,    34,    55,    46,     0,    32,    33,     0,    34,
-      32,    33,   126,   127,   118,    42,    34,    43,     0,     0,
-       0,   119,   128,     0,    43,    46,   178,    32,   179,    82,
-      34,    43,    46,     0,    34,     0,    82,     0,     0,    46,
-      32,    33,     0,    42,     0,    43,     0,    80,     0,    43,
-      45,    34,     0,    46,    82,     0,     0,    46,    32,    33,
-       0,   180,     0,     0,    34,     0,    43,    32,    33,     0,
-       0,    82,     0,     0,    46,     0,     0,     0,     0,    43,
-       0,     0,    34,     0,    82,     0,    55,    46,     0,     0,
-       0,    34,   221,     0,     0,     0,     0,    43,     0,     0,
-       0,     0,    82,     0,     0,    46,    43,     0,     0,     0,
-       0,    82,     0,     0,    46,   165,   166,   167,   168,   169,
-     170,   171,   172,   166,   167,   168,   169,   170,   171,   172
+      76,    73,    86,    88,    51,    87,   136,    66,    77,    74,
+      51,   100,    75,   102,   104,   256,   257,   160,   216,    64,
+     140,   224,   154,   155,     2,   111,   112,    92,    94,    96,
+      98,   114,   115,   113,   106,   114,   115,   183,   120,   122,
+     175,   176,   175,   176,   225,   117,    33,   177,   130,   177,
+     168,   169,   170,   171,   172,   129,    35,   125,   134,    76,
+      73,   161,   217,    35,    36,   107,   135,   108,    74,    32,
+      45,    75,   141,    88,   120,   110,   117,   205,   206,   207,
+      37,    58,   210,   211,   212,   213,   214,    37,    89,    90,
+     126,   127,   123,    45,   198,    46,   109,   124,   120,   120,
+      82,   128,    46,    49,   157,   158,    83,    58,    84,   199,
+      49,   200,   170,   171,   172,   112,   131,   132,   120,   133,
+     201,   139,   237,   238,   138,   143,   142,   156,   144,   184,
+     181,   185,    88,   145,   187,   189,   146,   188,   147,   148,
+     149,   150,   151,   152,   182,   191,   192,   193,   194,   195,
+     203,   159,   174,   120,   120,   120,   183,   190,   120,   120,
+     120,   120,   120,   196,    35,    36,    67,   162,   208,   112,
+     204,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+     172,    38,    39,    40,    41,    42,    43,   209,    37,    44,
+     218,   215,    38,    39,    40,    41,    42,    43,   120,   120,
+      44,    68,   219,    46,   221,   239,   240,    69,   222,    48,
+     223,    49,     4,   233,   227,   243,   228,   229,   230,   236,
+     247,   250,   173,   251,     5,     6,     7,     8,     9,    10,
+      11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,   262,    35,    36,   166,   167,   168,   169,
+     170,   171,   172,   267,   268,   231,    24,   232,    25,   234,
+      26,   235,   241,   244,    35,    36,   242,   245,    37,   246,
+     248,   253,    38,    39,    40,    41,    42,    43,    35,    36,
+      44,    45,   249,    46,   252,   258,   254,    47,    37,    48,
+     263,    49,    38,    39,    40,    41,    42,    43,    35,    36,
+      44,    45,    37,    46,   255,   259,   261,   118,    58,    48,
+     264,    49,   137,   265,   119,    79,   266,    46,    35,    36,
+      67,   269,    37,    84,   197,    49,    38,    39,    40,    41,
+      42,    43,   270,    80,    44,    45,     0,    46,    35,    36,
+     260,    78,    37,    48,     0,    49,    38,    39,    40,    41,
+      42,    43,     0,     0,    44,    68,     0,    46,    35,    36,
+       0,     0,    37,    48,     0,    49,    38,    39,    40,    41,
+      42,    43,    35,    36,    44,    45,     0,    46,     0,     0,
+       0,     0,    37,    48,     0,    49,    38,    39,    40,    41,
+      42,    43,    35,    36,    44,     0,    37,    46,     0,    35,
+      36,     0,     0,    48,     0,    49,    35,   179,     0,    45,
+       0,    46,     0,     0,     0,     0,    37,    48,     0,    49,
+       0,     0,     0,    37,    35,    36,     0,     0,     0,    82,
+      37,    46,     0,   178,    35,    36,     0,    84,    46,    49,
+     180,    35,    36,     0,    84,    46,    49,     0,    37,     0,
+       0,    84,     0,    49,     0,     0,     0,     0,    37,    35,
+      36,     0,     0,    46,     0,    37,     0,     0,   186,    84,
+       0,    49,     0,    46,     0,   220,     0,     0,    58,    84,
+      46,    49,     0,    37,     0,     0,    84,     0,    49,   164,
+     165,   166,   167,   168,   169,   170,   171,   172,    46,     0,
+       0,     0,     0,     0,    84,     0,    49,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,   172,   165,   166,   167,
+     168,   169,   170,   171,   172
 };
 
 static const yytype_int16 yycheck[] =
 {
-      10,    10,    13,    13,     6,    13,    10,     9,    11,    65,
-      12,    20,    10,    21,    22,    10,    10,     9,     0,     8,
-     108,   109,    32,    33,    80,    37,    38,    16,    17,    18,
-      19,    48,    44,    50,    23,    45,    46,    33,    51,    35,
-      32,    11,    44,    34,    49,    55,    37,    38,    44,    10,
-      11,    12,    55,    44,    54,    64,    66,    66,    53,    53,
-      64,    45,    66,     8,     9,    10,    11,    12,    66,    50,
-      81,    81,    82,    49,    76,   163,   164,   165,     8,     9,
-     168,   169,   170,   171,   172,    52,     3,     4,     5,     6,
-       7,     8,     9,    10,    11,    12,    37,    38,   108,   109,
-     156,    14,    15,    52,   114,   115,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,   125,    51,     6,   128,     8,
-       9,   209,   210,    51,    51,     7,    52,     8,     9,   139,
-     132,   142,   142,    51,   144,   145,    53,   145,    52,    51,
+      10,    10,    13,    13,     6,    13,    68,     9,    11,    10,
+      12,    20,    10,    21,    22,    37,    38,    10,    10,     8,
+      82,     9,   108,   109,     0,    35,    36,    16,    17,    18,
+      19,     8,     9,     6,    23,     8,     9,    34,    48,    49,
+      37,    38,    37,    38,    32,    47,    51,    44,    58,    44,
+       8,     9,    10,    11,    12,    58,     8,     9,    67,    69,
+      69,    54,    54,     8,     9,    48,    67,    50,    69,    49,
+      45,    69,    83,    83,    84,    49,    78,   163,   164,   165,
+      32,    52,   168,   169,   170,   171,   172,    32,    14,    15,
+      42,    43,    53,    45,   156,    47,    50,    53,   108,   109,
+      45,    53,    47,    55,   114,   115,    51,    52,    53,    33,
+      55,    35,    10,    11,    12,   125,    51,    51,   128,    51,
+      44,    11,   208,   209,    53,    53,    51,     7,    51,   139,
+     132,   142,   142,    51,   144,   145,    51,   145,    51,    51,
       51,    51,    51,    51,   133,   147,   148,   149,   150,   151,
-     160,    32,    51,   163,   164,   165,    51,   146,   168,   169,
-     170,   171,   172,   152,     1,    51,    47,    51,    53,   179,
-      37,    52,    52,    54,    55,    34,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-      27,    28,    29,    30,    31,    52,     6,    10,     7,   209,
-     210,    53,     8,     9,    10,    53,   216,   217,    45,    53,
-      47,    53,    49,    51,    53,    51,   224,    51,    48,    48,
-      51,   229,   232,    51,   233,    52,    32,     8,     9,    53,
-      36,    37,    38,    39,    40,    41,    37,    52,    44,    45,
-      32,    47,    53,     9,   254,    51,    52,    54,    37,    55,
-      38,    32,    35,   263,   264,    36,    37,    38,    39,    40,
-      41,     8,     9,    44,    45,    10,    47,    53,    53,     9,
-      51,    52,    10,    32,    55,    53,    36,    37,    38,    39,
-      40,    41,     8,     9,    44,    32,    10,   153,    32,    36,
-      37,    38,    39,    40,    41,    53,    53,    44,    45,    53,
-      47,    12,    12,    66,   228,    52,    32,    54,    55,    -1,
-      36,    37,    38,    39,    40,    41,    -1,    -1,    44,    45,
-      -1,    47,     8,     9,    10,    51,    52,    -1,    -1,    55,
-       3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
-      -1,    -1,    -1,     8,     9,    -1,    32,    -1,    -1,    -1,
-      36,    37,    38,    39,    40,    41,    -1,    -1,    44,    45,
-      -1,    47,    -1,    -1,     8,     9,    52,    32,    -1,    55,
-      -1,    36,    37,    38,    39,    40,    41,     8,     9,    44,
-      45,    -1,    47,    -1,    -1,    -1,    -1,    52,    32,    -1,
-      55,    -1,    36,    37,    38,    39,    40,    41,     8,     9,
-      44,    32,    -1,    47,    -1,     8,     9,    -1,    52,    -1,
-      -1,    55,     8,     9,    45,    -1,    47,    -1,    -1,    -1,
-      51,    52,    32,    54,    55,    -1,     8,     9,    -1,    32,
-       8,     9,    42,    43,    37,    45,    32,    47,    -1,    -1,
-      -1,    44,    52,    -1,    47,    55,    42,     8,     9,    52,
-      32,    47,    55,    -1,    32,    -1,    52,    -1,    -1,    55,
-       8,     9,    -1,    45,    -1,    47,    -1,    45,    -1,    47,
-      52,    32,    -1,    55,    52,    -1,    -1,    55,     8,     9,
-      -1,    42,    -1,    -1,    32,    -1,    47,     8,     9,    -1,
-      -1,    52,    -1,    -1,    55,    -1,    -1,    -1,    -1,    47,
-      -1,    -1,    32,    -1,    52,    -1,    54,    55,    -1,    -1,
-      -1,    32,    42,    -1,    -1,    -1,    -1,    47,    -1,    -1,
-      -1,    -1,    52,    -1,    -1,    55,    47,    -1,    -1,    -1,
-      -1,    52,    -1,    -1,    55,     5,     6,     7,     8,     9,
-      10,    11,    12,     6,     7,     8,     9,    10,    11,    12
+     160,    53,    37,   163,   164,   165,    34,   146,   168,   169,
+     170,   171,   172,   152,     8,     9,    10,    54,     6,   179,
+      53,     3,     4,     5,     6,     7,     8,     9,    10,    11,
+      12,    36,    37,    38,    39,    40,    41,     7,    32,    44,
+      54,    10,    36,    37,    38,    39,    40,    41,   208,   209,
+      44,    45,    54,    47,    54,   215,   216,    51,    54,    53,
+      51,    55,     1,    53,    51,   223,    51,    48,    48,    37,
+     228,   231,    54,   232,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,   253,     8,     9,     6,     7,     8,     9,
+      10,    11,    12,   263,   264,    51,    45,    51,    47,    54,
+      49,    54,    53,    32,     8,     9,    54,     9,    32,    52,
+      37,    10,    36,    37,    38,    39,    40,    41,     8,     9,
+      44,    45,    38,    47,    35,     9,    54,    51,    32,    53,
+      10,    55,    36,    37,    38,    39,    40,    41,     8,     9,
+      44,    45,    32,    47,    54,    32,    54,    37,    52,    53,
+      10,    55,    69,    32,    44,    12,    54,    47,     8,     9,
+      10,    54,    32,    53,   153,    55,    36,    37,    38,    39,
+      40,    41,    54,    12,    44,    45,    -1,    47,     8,     9,
+     246,    51,    32,    53,    -1,    55,    36,    37,    38,    39,
+      40,    41,    -1,    -1,    44,    45,    -1,    47,     8,     9,
+      -1,    -1,    32,    53,    -1,    55,    36,    37,    38,    39,
+      40,    41,     8,     9,    44,    45,    -1,    47,    -1,    -1,
+      -1,    -1,    32,    53,    -1,    55,    36,    37,    38,    39,
+      40,    41,     8,     9,    44,    -1,    32,    47,    -1,     8,
+       9,    -1,    -1,    53,    -1,    55,     8,     9,    -1,    45,
+      -1,    47,    -1,    -1,    -1,    -1,    32,    53,    -1,    55,
+      -1,    -1,    -1,    32,     8,     9,    -1,    -1,    -1,    45,
+      32,    47,    -1,    42,     8,     9,    -1,    53,    47,    55,
+      42,     8,     9,    -1,    53,    47,    55,    -1,    32,    -1,
+      -1,    53,    -1,    55,    -1,    -1,    -1,    -1,    32,     8,
+       9,    -1,    -1,    47,    -1,    32,    -1,    -1,    52,    53,
+      -1,    55,    -1,    47,    -1,    42,    -1,    -1,    52,    53,
+      47,    55,    -1,    32,    -1,    -1,    53,    -1,    55,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    47,    -1,
+      -1,    -1,    -1,    -1,    53,    -1,    55,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,     5,     6,     7,
+       8,     9,    10,    11,    12
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -848,32 +842,32 @@ static const yytype_uint8 yystos[] =
 {
        0,    57,     0,    58,     1,    13,    14,    15,    16,    17,
       18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    45,    47,    49,    59,    61,    49,
-      51,    62,     8,     9,    32,    36,    37,    38,    39,    40,
-      41,    44,    45,    47,    51,    52,    55,    66,    81,    85,
-      88,    89,    90,    91,    94,    54,    65,    81,    83,    87,
-      63,    83,    64,    81,    10,    45,    51,    70,    82,    84,
-      85,    89,    90,    94,    68,    91,    51,    62,    66,    71,
-      45,    51,    52,    67,    84,    87,    94,    69,    88,    78,
-      88,    79,    83,    72,    83,    73,    83,    74,    83,    75,
-      85,    76,    87,    77,    87,    80,    83,    48,    50,    50,
-      49,    94,    94,     6,     8,     9,    92,    81,    37,    44,
-      94,    96,    94,    52,    52,     9,    42,    43,    52,    91,
-      94,    51,    51,    51,    85,    89,    92,    82,    52,    11,
-      92,    84,    51,    52,    51,    51,    51,    51,    51,    51,
-      51,    51,    51,    60,    96,    96,     7,    94,    94,    52,
-      10,    53,    53,     3,     4,     5,     6,     7,     8,     9,
-      10,    11,    12,    53,    37,    37,    38,    44,    42,     9,
-      42,    81,    83,    34,    94,    84,    54,    86,    94,    87,
-      94,    83,    81,    81,    81,    81,    81,    83,    59,    92,
-      33,    35,    44,    93,    94,    52,    96,    96,    96,     6,
-       7,    96,    96,    96,    96,    96,    10,    10,    53,    53,
-      53,    42,    53,    53,    51,     9,    32,    95,    51,    51,
-      48,    48,    51,    51,    52,    53,    53,    37,    96,    96,
-      94,    94,    52,    53,    87,    32,     9,    86,    87,    37,
-      38,    94,    85,    35,    10,    53,    53,    37,    38,     9,
-      32,    53,    94,    10,    10,    32,    53,    94,    94,    53,
-      53
+      28,    29,    30,    31,    45,    47,    49,    59,    61,    68,
+      69,    70,    49,    51,    62,     8,     9,    32,    36,    37,
+      38,    39,    40,    41,    44,    45,    47,    51,    53,    55,
+      66,    81,    85,    87,    88,    89,    90,    93,    52,    65,
+      81,    83,    86,    63,    83,    64,    81,    10,    45,    51,
+      71,    82,    84,    85,    88,    89,    93,    90,    51,    62,
+      66,    72,    45,    51,    53,    67,    84,    86,    93,    87,
+      87,    79,    83,    73,    83,    74,    83,    75,    83,    76,
+      85,    77,    86,    78,    86,    80,    83,    48,    50,    50,
+      49,    93,    93,     6,     8,     9,    91,    81,    37,    44,
+      93,    95,    93,    53,    53,     9,    42,    43,    53,    90,
+      93,    51,    51,    51,    85,    88,    91,    82,    53,    11,
+      91,    84,    51,    53,    51,    51,    51,    51,    51,    51,
+      51,    51,    51,    60,    95,    95,     7,    93,    93,    53,
+      10,    54,    54,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,    12,    54,    37,    37,    38,    44,    42,     9,
+      42,    81,    83,    34,    93,    84,    52,    93,    86,    93,
+      83,    81,    81,    81,    81,    81,    83,    59,    91,    33,
+      35,    44,    92,    93,    53,    95,    95,    95,     6,     7,
+      95,    95,    95,    95,    95,    10,    10,    54,    54,    54,
+      42,    54,    54,    51,     9,    32,    94,    51,    51,    48,
+      48,    51,    51,    53,    54,    54,    37,    95,    95,    93,
+      93,    53,    54,    86,    32,     9,    52,    86,    37,    38,
+      93,    85,    35,    10,    54,    54,    37,    38,     9,    32,
+      94,    54,    93,    10,    10,    32,    54,    93,    93,    54,
+      54
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1752,16 +1746,6 @@ yyreduce:
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
-  case 18:
-#line 105 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 19:
-#line 106 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
   case 20:
 #line 107 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
@@ -1802,11 +1786,6 @@ yyreduce:
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
-  case 28:
-#line 115 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
   case 29:
 #line 116 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
@@ -1908,111 +1887,149 @@ yyreduce:
   case 42:
 #line 187 "a.y"
     {
-               (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-               (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-               (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
+               Addr2 a;
+               a.from = (yyvsp[(2) - (6)].addr);
+               a.to = (yyvsp[(6) - (6)].addr);
+               outcode(ADATA, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
+               }
        }
     break;
 
   case 43:
-#line 195 "a.y"
+#line 200 "a.y"
     {
-               settext((yyvsp[(1) - (3)].addr).sym);
-               (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-               (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+               Addr2 a;
+               settext((yyvsp[(2) - (5)].addr).sym);
+               a.from = (yyvsp[(2) - (5)].addr);
+               a.to = (yyvsp[(5) - (5)].addr);
+               outcode(ATEXT, &a);
        }
     break;
 
   case 44:
-#line 201 "a.y"
-    {
-               settext((yyvsp[(1) - (5)].addr).sym);
-               (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-               (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-               (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
+#line 208 "a.y"
+    {
+               Addr2 a;
+               settext((yyvsp[(2) - (7)].addr).sym);
+               a.from = (yyvsp[(2) - (7)].addr);
+               a.to = (yyvsp[(7) - (7)].addr);
+               outcode(ATEXT, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (7)].lval);
+               }
        }
     break;
 
   case 45:
-#line 210 "a.y"
+#line 222 "a.y"
+    {
+               Addr2 a;
+               settext((yyvsp[(2) - (4)].addr).sym);
+               a.from = (yyvsp[(2) - (4)].addr);
+               a.to = (yyvsp[(4) - (4)].addr);
+               outcode(AGLOBL, &a);
+       }
+    break;
+
+  case 46:
+#line 230 "a.y"
+    {
+               Addr2 a;
+               settext((yyvsp[(2) - (6)].addr).sym);
+               a.from = (yyvsp[(2) - (6)].addr);
+               a.to = (yyvsp[(6) - (6)].addr);
+               outcode(AGLOBL, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
+               }
+       }
+    break;
+
+  case 47:
+#line 244 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
        }
     break;
 
-  case 46:
-#line 215 "a.y"
+  case 48:
+#line 249 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
        }
     break;
 
-  case 49:
-#line 226 "a.y"
+  case 51:
+#line 260 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
        }
     break;
 
-  case 50:
-#line 231 "a.y"
+  case 52:
+#line 265 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
-               if((yyval.addr2).from.index != D_NONE)
+               if((yyval.addr2).from.index != TYPE_NONE)
                        yyerror("dp shift with lhs index");
                (yyval.addr2).from.index = (yyvsp[(5) - (5)].lval);
        }
     break;
 
-  case 51:
-#line 241 "a.y"
+  case 53:
+#line 275 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
        }
     break;
 
-  case 52:
-#line 246 "a.y"
+  case 54:
+#line 280 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
-               if((yyval.addr2).to.index != D_NONE)
+               if((yyval.addr2).to.index != TYPE_NONE)
                        yyerror("dp move with lhs index");
                (yyval.addr2).to.index = (yyvsp[(5) - (5)].lval);
        }
     break;
 
-  case 53:
-#line 256 "a.y"
+  case 55:
+#line 290 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
                (yyval.addr2).to = nullgen;
        }
     break;
 
-  case 54:
-#line 261 "a.y"
+  case 56:
+#line 295 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
                (yyval.addr2).to = nullgen;
        }
     break;
 
-  case 55:
-#line 266 "a.y"
+  case 57:
+#line 300 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
        }
     break;
 
-  case 56:
-#line 273 "a.y"
+  case 58:
+#line 307 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
@@ -2020,54 +2037,37 @@ yyreduce:
        }
     break;
 
-  case 57:
-#line 281 "a.y"
+  case 59:
+#line 315 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(3) - (5)].addr);
                (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-               if((yyvsp[(1) - (5)].addr).type != D_CONST)
+               if((yyvsp[(1) - (5)].addr).type != TYPE_CONST)
                        yyerror("illegal constant");
                (yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset;
        }
     break;
 
-  case 58:
-#line 290 "a.y"
+  case 60:
+#line 324 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = nullgen;
        }
     break;
 
-  case 59:
-#line 295 "a.y"
+  case 61:
+#line 329 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
                (yyval.addr2).to = nullgen;
        }
     break;
 
-  case 60:
-#line 302 "a.y"
-    {
-               (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-               (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-       }
-    break;
-
-  case 61:
-#line 307 "a.y"
-    {
-               (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-               (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-               (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-       }
-    break;
-
   case 62:
-#line 315 "a.y"
+#line 336 "a.y"
     {
-               if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST)
+               if((yyvsp[(1) - (3)].addr).type != TYPE_CONST || (yyvsp[(3) - (3)].addr).type != TYPE_CONST)
                        yyerror("arguments to PCDATA must be integer constants");
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
@@ -2075,11 +2075,11 @@ yyreduce:
     break;
 
   case 63:
-#line 324 "a.y"
+#line 345 "a.y"
     {
-               if((yyvsp[(1) - (3)].addr).type != D_CONST)
+               if((yyvsp[(1) - (3)].addr).type != TYPE_CONST)
                        yyerror("index for FUNCDATA must be integer constant");
-               if((yyvsp[(3) - (3)].addr).type != D_EXTERN && (yyvsp[(3) - (3)].addr).type != D_STATIC)
+               if((yyvsp[(3) - (3)].addr).type != TYPE_MEM || ((yyvsp[(3) - (3)].addr).name != NAME_EXTERN && (yyvsp[(3) - (3)].addr).name != NAME_STATIC))
                        yyerror("value for FUNCDATA must be symbol reference");
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
@@ -2087,120 +2087,117 @@ yyreduce:
     break;
 
   case 68:
-#line 341 "a.y"
+#line 362 "a.y"
     {
                (yyval.addr) = (yyvsp[(2) - (2)].addr);
        }
     break;
 
   case 69:
-#line 345 "a.y"
+#line 366 "a.y"
     {
                (yyval.addr) = (yyvsp[(2) - (2)].addr);
        }
     break;
 
   case 74:
-#line 357 "a.y"
+#line 378 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_BRANCH;
+               (yyval.addr).type = TYPE_BRANCH;
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
        }
     break;
 
   case 75:
-#line 363 "a.y"
+#line 384 "a.y"
     {
                (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
                (yyval.addr) = nullgen;
                if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB)
                        yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname);
-               (yyval.addr).type = D_BRANCH;
+               (yyval.addr).type = TYPE_BRANCH;
                (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
        }
     break;
 
   case 76:
-#line 374 "a.y"
+#line 395 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 77:
-#line 379 "a.y"
+#line 401 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 78:
-#line 384 "a.y"
+#line 407 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 79:
-#line 389 "a.y"
+#line 413 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 80:
-#line 394 "a.y"
+#line 419 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SP;
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = REG_SP;
        }
     break;
 
   case 81:
-#line 399 "a.y"
+#line 425 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 82:
-#line 404 "a.y"
+#line 431 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 83:
-#line 410 "a.y"
+#line 439 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CONST;
+               (yyval.addr).type = TYPE_CONST;
                (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
        }
     break;
 
   case 84:
-#line 418 "a.y"
-    {
-               (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CONST;
-               (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
-       }
-    break;
-
-  case 85:
-#line 424 "a.y"
+#line 445 "a.y"
     {
                (yyval.addr) = (yyvsp[(2) - (2)].addr);
-               (yyval.addr).index = (yyvsp[(2) - (2)].addr).type;
-               (yyval.addr).type = D_ADDR;
+               (yyval.addr).type = TYPE_ADDR;
                /*
                if($2.type == D_AUTO || $2.type == D_PARAM)
                        yyerror("constant cannot be automatic: %s",
@@ -2209,92 +2206,95 @@ yyreduce:
        }
     break;
 
-  case 86:
-#line 435 "a.y"
+  case 85:
+#line 455 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SCONST;
+               (yyval.addr).type = TYPE_SCONST;
                memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
        }
     break;
 
-  case 87:
-#line 441 "a.y"
+  case 86:
+#line 461 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
+               (yyval.addr).type = TYPE_FCONST;
                (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
        }
     break;
 
-  case 88:
-#line 447 "a.y"
+  case 87:
+#line 467 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
+               (yyval.addr).type = TYPE_FCONST;
                (yyval.addr).u.dval = (yyvsp[(3) - (4)].dval);
        }
     break;
 
-  case 89:
-#line 453 "a.y"
+  case 88:
+#line 473 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
+               (yyval.addr).type = TYPE_FCONST;
                (yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval);
        }
     break;
 
-  case 90:
-#line 459 "a.y"
+  case 89:
+#line 479 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
+               (yyval.addr).type = TYPE_FCONST;
                (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
        }
     break;
 
-  case 93:
-#line 471 "a.y"
+  case 92:
+#line 491 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+D_NONE;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
        }
     break;
 
-  case 94:
-#line 477 "a.y"
+  case 93:
+#line 497 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
        }
     break;
 
-  case 95:
-#line 483 "a.y"
+  case 94:
+#line 504 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+D_SP;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = REG_SP;
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
        }
     break;
 
-  case 96:
-#line 489 "a.y"
+  case 95:
+#line 511 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
        }
     break;
 
-  case 97:
-#line 495 "a.y"
+  case 96:
+#line 518 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+D_NONE;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).offset = (yyvsp[(1) - (6)].lval);
                (yyval.addr).index = (yyvsp[(3) - (6)].lval);
                (yyval.addr).scale = (yyvsp[(5) - (6)].lval);
@@ -2302,11 +2302,12 @@ yyreduce:
        }
     break;
 
-  case 98:
-#line 504 "a.y"
+  case 97:
+#line 527 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(3) - (9)].lval);
                (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
                (yyval.addr).index = (yyvsp[(6) - (9)].lval);
                (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
@@ -2314,11 +2315,12 @@ yyreduce:
        }
     break;
 
-  case 99:
-#line 513 "a.y"
+  case 98:
+#line 537 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(3) - (9)].lval);
                (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
                (yyval.addr).index = (yyvsp[(6) - (9)].lval);
                (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
@@ -2326,53 +2328,56 @@ yyreduce:
        }
     break;
 
-  case 100:
-#line 522 "a.y"
+  case 99:
+#line 547 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
        }
     break;
 
-  case 101:
-#line 527 "a.y"
+  case 100:
+#line 553 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+D_SP;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = REG_SP;
        }
     break;
 
-  case 102:
-#line 532 "a.y"
+  case 101:
+#line 559 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+D_NONE;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).index = (yyvsp[(2) - (5)].lval);
                (yyval.addr).scale = (yyvsp[(4) - (5)].lval);
                checkscale((yyval.addr).scale);
        }
     break;
 
-  case 103:
-#line 540 "a.y"
+  case 102:
+#line 567 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(2) - (8)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(2) - (8)].lval);
                (yyval.addr).index = (yyvsp[(5) - (8)].lval);
                (yyval.addr).scale = (yyvsp[(7) - (8)].lval);
                checkscale((yyval.addr).scale);
        }
     break;
 
-  case 104:
-#line 550 "a.y"
+  case 103:
+#line 578 "a.y"
     {
                (yyval.addr) = (yyvsp[(1) - (1)].addr);
        }
     break;
 
-  case 105:
-#line 554 "a.y"
+  case 104:
+#line 582 "a.y"
     {
                (yyval.addr) = (yyvsp[(1) - (6)].addr);
                (yyval.addr).index = (yyvsp[(3) - (6)].lval);
@@ -2381,186 +2386,196 @@ yyreduce:
        }
     break;
 
-  case 106:
-#line 563 "a.y"
+  case 105:
+#line 591 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(4) - (5)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).name = (yyvsp[(4) - (5)].lval);
                (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
                (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
        }
     break;
 
-  case 107:
-#line 570 "a.y"
+  case 106:
+#line 599 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_STATIC;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).name = NAME_STATIC;
                (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
                (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
        }
     break;
 
-  case 108:
-#line 578 "a.y"
+  case 107:
+#line 608 "a.y"
     {
                (yyval.lval) = 0;
        }
     break;
 
-  case 109:
-#line 582 "a.y"
+  case 108:
+#line 612 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 110:
-#line 586 "a.y"
+  case 109:
+#line 616 "a.y"
     {
                (yyval.lval) = -(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 112:
-#line 593 "a.y"
+  case 111:
+#line 623 "a.y"
     {
-               (yyval.lval) = D_AUTO;
+               (yyval.lval) = NAME_AUTO;
        }
     break;
 
-  case 115:
-#line 601 "a.y"
+  case 114:
+#line 631 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
        }
     break;
 
-  case 116:
-#line 605 "a.y"
+  case 115:
+#line 635 "a.y"
     {
                (yyval.lval) = -(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 117:
-#line 609 "a.y"
+  case 116:
+#line 639 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 118:
-#line 613 "a.y"
+  case 117:
+#line 643 "a.y"
     {
                (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 119:
-#line 617 "a.y"
+  case 118:
+#line 647 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (3)].lval);
        }
     break;
 
-  case 120:
-#line 623 "a.y"
+  case 119:
+#line 653 "a.y"
     {
-               (yyval.lval) = ((yyvsp[(1) - (1)].lval) & 0xffffffffLL) +
-                       ((vlong)ArgsSizeUnknown << 32);
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).u.argsize = ArgsSizeUnknown;
        }
     break;
 
-  case 121:
-#line 628 "a.y"
+  case 120:
+#line 660 "a.y"
     {
-               (yyval.lval) = (-(yyvsp[(2) - (2)].lval) & 0xffffffffLL) +
-                       ((vlong)ArgsSizeUnknown << 32);
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = -(yyvsp[(2) - (2)].lval);
+               (yyval.addr).u.argsize = ArgsSizeUnknown;
        }
     break;
 
-  case 122:
-#line 633 "a.y"
+  case 121:
+#line 667 "a.y"
     {
-               (yyval.lval) = ((yyvsp[(1) - (3)].lval) & 0xffffffffLL) +
-                       (((yyvsp[(3) - (3)].lval) & 0xffffLL) << 32);
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = (yyvsp[(1) - (3)].lval);
+               (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 123:
-#line 638 "a.y"
+  case 122:
+#line 674 "a.y"
     {
-               (yyval.lval) = (-(yyvsp[(2) - (4)].lval) & 0xffffffffLL) +
-                       (((yyvsp[(4) - (4)].lval) & 0xffffLL) << 32);
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = -(yyvsp[(2) - (4)].lval);
+               (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval);
        }
     break;
 
-  case 125:
-#line 646 "a.y"
+  case 124:
+#line 684 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 126:
-#line 650 "a.y"
+  case 125:
+#line 688 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 127:
-#line 654 "a.y"
+  case 126:
+#line 692 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 128:
-#line 658 "a.y"
+  case 127:
+#line 696 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 129:
-#line 662 "a.y"
+  case 128:
+#line 700 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 130:
-#line 666 "a.y"
+  case 129:
+#line 704 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
        }
     break;
 
-  case 131:
-#line 670 "a.y"
+  case 130:
+#line 708 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
        }
     break;
 
-  case 132:
-#line 674 "a.y"
+  case 131:
+#line 712 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 133:
-#line 678 "a.y"
+  case 132:
+#line 716 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 134:
-#line 682 "a.y"
+  case 133:
+#line 720 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
        }
@@ -2568,7 +2583,7 @@ yyreduce:
 
 
 /* Line 1267 of yacc.c.  */
-#line 2572 "y.tab.c"
+#line 2587 "y.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
index d13c98dad9f13ff9f4e6dddeb0341a564a87c2fb..d1645cc56820f99da2dcfeb37c2d5c9ef65c17dd 100644 (file)
@@ -759,9 +759,10 @@ agenr(Node *n, Node *a, Node *res)
                        // nothing to do
                } else if(w == 1 || w == 2 || w == 4 || w == 8) {
                        p1 = gins(ALEAQ, &n2, &n3);
+                       p1->from.type = TYPE_MEM;
                        p1->from.scale = w;
-                       p1->from.index = p1->from.type;
-                       p1->from.type = p1->to.type + D_INDIR;
+                       p1->from.index = p1->from.reg;
+                       p1->from.reg = p1->to.reg;
                } else {
                        ginscon(optoas(OMUL, t), w, &n2);
                        gins(optoas(OADD, types[tptr]), &n2, &n3);
@@ -941,7 +942,7 @@ igen(Node *n, Node *a, Node *res)
        case OINDREG:
                // Increase the refcount of the register so that igen's caller
                // has to call regfree.
-               if(n->val.u.reg != D_SP)
+               if(n->val.u.reg != REG_SP)
                        reg[n->val.u.reg]++;
                *a = *n;
                return;
@@ -979,7 +980,7 @@ igen(Node *n, Node *a, Node *res)
                fp = structfirst(&flist, getoutarg(n->left->type));
                memset(a, 0, sizeof *a);
                a->op = OINDREG;
-               a->val.u.reg = D_SP;
+               a->val.u.reg = REG_SP;
                a->addable = 1;
                a->xoffset = fp->width;
                a->type = n->type;
@@ -1401,8 +1402,8 @@ sgen(Node *n, Node *ns, int64 w)
                agenr(n, &nodr, N);
        }
        
-       nodreg(&noddi, types[tptr], D_DI);
-       nodreg(&nodsi, types[tptr], D_SI);
+       nodreg(&noddi, types[tptr], REG_DI);
+       nodreg(&nodsi, types[tptr], REG_SI);
        gmove(&nodl, &noddi);
        gmove(&nodr, &nodsi);
        regfree(&nodl);
@@ -1411,7 +1412,7 @@ sgen(Node *n, Node *ns, int64 w)
        c = w % 8;      // bytes
        q = w / 8;      // quads
 
-       savex(D_CX, &cx, &oldcx, N, types[TINT64]);
+       savex(REG_CX, &cx, &oldcx, N, types[TINT64]);
 
        // if we are copying forward on the stack and
        // the src and dst overlap, then reverse direction
@@ -1419,23 +1420,23 @@ sgen(Node *n, Node *ns, int64 w)
                // reverse direction
                gins(ASTD, N, N);               // set direction flag
                if(c > 0) {
-                       gconreg(addptr, w-1, D_SI);
-                       gconreg(addptr, w-1, D_DI);
+                       gconreg(addptr, w-1, REG_SI);
+                       gconreg(addptr, w-1, REG_DI);
 
-                       gconreg(movptr, c, D_CX);
+                       gconreg(movptr, c, REG_CX);
                        gins(AREP, N, N);       // repeat
                        gins(AMOVSB, N, N);     // MOVB *(SI)-,*(DI)-
                }
 
                if(q > 0) {
                        if(c > 0) {
-                               gconreg(addptr, -7, D_SI);
-                               gconreg(addptr, -7, D_DI);
+                               gconreg(addptr, -7, REG_SI);
+                               gconreg(addptr, -7, REG_DI);
                        } else {
-                               gconreg(addptr, w-8, D_SI);
-                               gconreg(addptr, w-8, D_DI);
+                               gconreg(addptr, w-8, REG_SI);
+                               gconreg(addptr, w-8, REG_DI);
                        }
-                       gconreg(movptr, q, D_CX);
+                       gconreg(movptr, q, REG_CX);
                        gins(AREP, N, N);       // repeat
                        gins(AMOVSQ, N, N);     // MOVQ *(SI)-,*(DI)-
                }
@@ -1444,12 +1445,12 @@ sgen(Node *n, Node *ns, int64 w)
        } else {
                // normal direction
                if(q > 128 || (nacl && q >= 4)) {
-                       gconreg(movptr, q, D_CX);
+                       gconreg(movptr, q, REG_CX);
                        gins(AREP, N, N);       // repeat
                        gins(AMOVSQ, N, N);     // MOVQ *(SI)+,*(DI)+
                } else if (q >= 4) {
                        p = gins(ADUFFCOPY, N, N);
-                       p->to.type = D_ADDR;
+                       p->to.type = TYPE_ADDR;
                        p->to.sym = linksym(pkglookup("duffcopy", runtimepkg));
                        // 14 and 128 = magic constants: see ../../runtime/asm_amd64.s
                        p->to.offset = 14*(128-q);
index 5670e6fac87bc2195899acfc04e8d41c1514c73f..83833e189b5f24b960367074a928fb6ecf60f095 100644 (file)
@@ -13,8 +13,12 @@ LinkArch*    thelinkarch = &linkamd64;
 void
 linkarchinit(void)
 {
-       if(strcmp(getgoarch(), "amd64p32") == 0)
+       if(strcmp(getgoarch(), "amd64p32") == 0) {
                thelinkarch = &linkamd64p32;
+               arch.thelinkarch = thelinkarch;
+               thestring = "amd64p32";
+               arch.thestring = "amd64p32";
+       }
 }
 
 vlong MAXWIDTH = 1LL<<50;
@@ -55,12 +59,67 @@ betypeinit(void)
                
        }
 
-       zprog.link = P;
-       zprog.as = AGOK;
-       zprog.from.type = D_NONE;
-       zprog.from.index = D_NONE;
-       zprog.from.scale = 0;
-       zprog.to = zprog.from;
-
        listinit6();
 }
+
+void
+main(int argc, char **argv)
+{
+       arch.thechar = thechar;
+       arch.thestring = thestring;
+       arch.thelinkarch = thelinkarch;
+       arch.typedefs = typedefs;
+       arch.MAXWIDTH = MAXWIDTH;
+       arch.afunclit = afunclit;
+       arch.anyregalloc = anyregalloc;
+       arch.betypeinit = betypeinit;
+       arch.bgen = bgen;
+       arch.cgen = cgen;
+       arch.cgen_asop = cgen_asop;
+       arch.cgen_call = cgen_call;
+       arch.cgen_callinter = cgen_callinter;
+       arch.cgen_ret = cgen_ret;
+       arch.clearfat = clearfat;
+       arch.clearp = clearp;
+       arch.defframe = defframe;
+       arch.dgostringptr = dgostringptr;
+       arch.dgostrlitptr = dgostrlitptr;
+       arch.dsname = dsname;
+       arch.dsymptr = dsymptr;
+       arch.dumpdata = dumpdata;
+       arch.dumpit = dumpit;
+       arch.excise = excise;
+       arch.expandchecks = expandchecks;
+       arch.fixautoused = fixautoused;
+       arch.gclean = gclean;
+       arch.gdata = gdata;
+       arch.gdatacomplex = gdatacomplex;
+       arch.gdatastring = gdatastring;
+       arch.ggloblnod = ggloblnod;
+       arch.ggloblsym = ggloblsym;
+       arch.ginit = ginit;
+       arch.gins = gins;
+       arch.ginscall = ginscall;
+       arch.gjmp = gjmp;
+       arch.gtrack = gtrack;
+       arch.gused = gused;
+       arch.igen = igen;
+       arch.isfat = isfat;
+       arch.linkarchinit = linkarchinit;
+       arch.markautoused = markautoused;
+       arch.naddr = naddr;
+       arch.newplist = newplist;
+       arch.nodarg = nodarg;
+       arch.patch = patch;
+       arch.proginfo = proginfo;
+       arch.regalloc = regalloc;
+       arch.regfree = regfree;
+       arch.regopt = regopt;
+       arch.regtyp = regtyp;
+       arch.sameaddr = sameaddr;
+       arch.smallindir = smallindir;
+       arch.stackaddr = stackaddr;
+       arch.unpatch = unpatch;
+       
+       gcmain(argc, argv);
+}
index fe69d5c968d0cd27d951ee0ca31e1a41b9ed305e..7a09f673ef1e85994057637b349e03dccc8bb1a9 100644 (file)
@@ -9,20 +9,11 @@
 #include "../gc/go.h"
 #include "../6l/6.out.h"
 
-#define TEXTFLAG from.scale
-
 EXTERN int32   dynloc;
-EXTERN uchar   reg[D_NONE];
+EXTERN uchar   reg[MAXREG];
 EXTERN int32   pcloc;          // instruction counter
 EXTERN Strlit  emptystring;
-EXTERN Prog    zprog;
-EXTERN Node*   newproc;
-EXTERN Node*   deferproc;
-EXTERN Node*   deferreturn;
-EXTERN Node*   panicindex;
-EXTERN Node*   panicslice;
 EXTERN Node*   panicdiv;
-EXTERN Node*   throwreturn;
 extern vlong   unmappedzero;
 extern int     addptr;
 extern int     cmpptr;
@@ -120,3 +111,55 @@ void       datagostring(Strlit*, Addr*);
 void   listinit(void);
 
 void   zaddr(Biobuf*, Addr*, int, int);
+
+void afunclit(Addr*, Node*);
+int anyregalloc(void);
+void betypeinit(void);
+void bgen(Node*, int, int, Prog*);
+void cgen(Node*, Node*);
+void cgen_asop(Node*);
+void cgen_call(Node*, int);
+void cgen_callinter(Node*, Node*, int);
+void cgen_ret(Node*);
+void clearfat(Node*);
+void clearp(Prog*);
+void defframe(Prog*);
+int dgostringptr(Sym*, int, char*);
+int dgostrlitptr(Sym*, int, Strlit*);
+int dsname(Sym*, int, char*, int);
+int dsymptr(Sym*, int, Sym*, int);
+void dumpdata(void);
+void dumpit(char*, Flow*, int);
+void excise(Flow*);
+void expandchecks(Prog*);
+void fixautoused(Prog*);
+void gclean(void);
+void   gdata(Node*, Node*, int);
+void   gdatacomplex(Node*, Mpcplx*);
+void   gdatastring(Node*, Strlit*);
+void   ggloblnod(Node *nam);
+void   ggloblsym(Sym *s, int32 width, int8 flags);
+void ginit(void);
+Prog*  gins(int, Node*, Node*);
+void   ginscall(Node*, int);
+Prog*  gjmp(Prog*);
+void gtrack(Sym*);
+void   gused(Node*);
+void   igen(Node*, Node*, Node*);
+int isfat(Type*);
+void linkarchinit(void);
+void markautoused(Prog*);
+void naddr(Node*, Addr*, int);
+Plist* newplist(void);
+Node* nodarg(Type*, int);
+void patch(Prog*, Prog*);
+void proginfo(ProgInfo*, Prog*);
+void regalloc(Node*, Type*, Node*);
+void regfree(Node*);
+void regopt(Prog*);
+int regtyp(Addr*);
+int sameaddr(Addr*, Addr*);
+int smallindir(Addr*, Addr*);
+int stackaddr(Addr*);
+Prog* unpatch(Prog*);
+
index 02e6dc2af50d3657e4d99ddf2b016c4387796f98..9f4b4d4ae391b3d8022d8ee6d669791e6585d2e1 100644 (file)
@@ -9,7 +9,7 @@
 #include "gg.h"
 #include "opt.h"
 
-static Prog *appendpp(Prog*, int, int, vlong, int, vlong);
+static Prog *appendpp(Prog*, int, int, int, vlong, int, int, vlong);
 static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
 
 void
@@ -21,13 +21,11 @@ defframe(Prog *ptxt)
        NodeList *l;
        Node *n;
 
-       // fill in argument size
-       ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
-
-       // fill in final stack size
-       ptxt->to.offset <<= 32;
+       // fill in argument size, stack size
+       ptxt->to.type = TYPE_TEXTSIZE;
+       ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr);
        frame = rnd(stksize+maxarg, widthreg);
-       ptxt->to.offset |= frame;
+       ptxt->to.offset = frame;
        
        // insert code to zero ambiguously live variables
        // so that the garbage collector only sees initialized values
@@ -70,45 +68,47 @@ zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax)
        if(cnt == 0)
                return p;
        if(*ax == 0) {
-               p = appendpp(p, AMOVQ, D_CONST, 0, D_AX, 0);
+               p = appendpp(p, AMOVQ, TYPE_CONST, 0, 0, TYPE_REG, REG_AX, 0);
                *ax = 1;
        }
        if(cnt % widthreg != 0) {
                // should only happen with nacl
                if(cnt % widthptr != 0)
                        fatal("zerorange count not a multiple of widthptr %d", cnt);
-               p = appendpp(p, AMOVL, D_AX, 0, D_SP+D_INDIR, frame+lo);
+               p = appendpp(p, AMOVL, TYPE_REG, REG_AX, 0, TYPE_MEM, REG_SP, frame+lo);
                lo += widthptr;
                cnt -= widthptr;
        }
        if(cnt <= 4*widthreg) {
                for(i = 0; i < cnt; i += widthreg) {
-                       p = appendpp(p, AMOVQ, D_AX, 0, D_SP+D_INDIR, frame+lo+i);
+                       p = appendpp(p, AMOVQ, TYPE_REG, REG_AX, 0, TYPE_MEM, REG_SP, frame+lo+i);
                }
        } else if(!nacl && (cnt <= 128*widthreg)) {
-               p = appendpp(p, leaptr, D_SP+D_INDIR, frame+lo, D_DI, 0);
-               p = appendpp(p, ADUFFZERO, D_NONE, 0, D_ADDR, 2*(128-cnt/widthreg));
+               p = appendpp(p, leaptr, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0);
+               p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_ADDR, 0, 2*(128-cnt/widthreg));
                p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
        } else {
-               p = appendpp(p, AMOVQ, D_CONST, cnt/widthreg, D_CX, 0);
-               p = appendpp(p, leaptr, D_SP+D_INDIR, frame+lo, D_DI, 0);
-               p = appendpp(p, AREP, D_NONE, 0, D_NONE, 0);
-               p = appendpp(p, ASTOSQ, D_NONE, 0, D_NONE, 0);
+               p = appendpp(p, AMOVQ, TYPE_CONST, 0, cnt/widthreg, TYPE_REG, REG_CX, 0);
+               p = appendpp(p, leaptr, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0);
+               p = appendpp(p, AREP, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0);
+               p = appendpp(p, ASTOSQ, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0);
        }
        return p;
 }
 
 static Prog*   
-appendpp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset)  
+appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset)      
 {
        Prog *q;
        q = mal(sizeof(*q));    
        clearp(q);      
        q->as = as;     
        q->lineno = p->lineno;  
-       q->from.type = ftype;   
+       q->from.type = ftype;
+       q->from.reg = freg;
        q->from.offset = foffset;       
        q->to.type = ttype;     
+       q->to.reg = treg;
        q->to.offset = toffset; 
        q->link = p->link;      
        p->link = q;    
@@ -124,10 +124,10 @@ markautoused(Prog* p)
                        continue;
 
                if (p->from.node)
-                       p->from.node->used = 1;
+                       ((Node*)(p->from.node))->used = 1;
 
                if (p->to.node)
-                       p->to.node->used = 1;
+                       ((Node*)(p->to.node))->used = 1;
        }
 }
 
@@ -138,25 +138,23 @@ fixautoused(Prog *p)
        Prog **lp;
 
        for (lp=&p; (p=*lp) != P; ) {
-               if (p->as == ATYPE && p->from.node && p->from.type == D_AUTO && !p->from.node->used) {
+               if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
                        *lp = p->link;
                        continue;
                }
-               if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) {
+               if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
                        // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
                        // VARDEFs are interspersed with other code, and a jump might be using the
                        // VARDEF as a target. Replace with a no-op instead. A later pass will remove
                        // the no-ops.
-                       p->to.type = D_NONE;
-                       p->to.node = N;
-                       p->as = ANOP;
+                       nopout(p);
                        continue;
                }
-               if (p->from.type == D_AUTO && p->from.node)
-                       p->from.offset += p->from.node->stkdelta;
+               if (p->from.name == NAME_AUTO && p->from.node)
+                       p->from.offset += ((Node*)(p->from.node))->stkdelta;
 
-               if (p->to.type == D_AUTO && p->to.node)
-                       p->to.offset += p->to.node->stkdelta;
+               if (p->to.name == NAME_AUTO && p->to.node)
+                       p->to.offset += ((Node*)(p->to.node))->stkdelta;
 
                lp = &p->link;
        }
@@ -205,7 +203,7 @@ ginscall(Node *f, int proc)
                                // x86 NOP 0x90 is really XCHG AX, AX; use that description
                                // because the NOP pseudo-instruction would be removed by
                                // the linker.
-                               nodreg(&reg, types[TINT], D_AX);
+                               nodreg(&reg, types[TINT], REG_AX);
                                gins(AXCHGL, &reg, &reg);
                        }
                        p = gins(ACALL, N, f);
@@ -214,8 +212,8 @@ ginscall(Node *f, int proc)
                                gins(AUNDEF, N, N);
                        break;
                }
-               nodreg(&reg, types[tptr], D_DX);
-               nodreg(&r1, types[tptr], D_BX);
+               nodreg(&reg, types[tptr], REG_DX);
+               nodreg(&r1, types[tptr], REG_BX);
                gmove(f, &reg);
                reg.op = OINDREG;
                gmove(&reg, &r1);
@@ -231,7 +229,7 @@ ginscall(Node *f, int proc)
        case 2: // deferred call (defer)
                memset(&stk, 0, sizeof(stk));
                stk.op = OINDREG;
-               stk.val.u.reg = D_SP;
+               stk.val.u.reg = REG_SP;
                stk.xoffset = 0;
 
                if(widthptr == 8) {
@@ -240,7 +238,7 @@ ginscall(Node *f, int proc)
 
                        // FuncVal* at 8(SP)
                        stk.xoffset = widthptr;
-                       nodreg(&reg, types[TINT64], D_AX);
+                       nodreg(&reg, types[TINT64], REG_AX);
                        gmove(f, &reg);
                        gins(AMOVQ, &reg, &stk);
                } else {
@@ -249,7 +247,7 @@ ginscall(Node *f, int proc)
 
                        // FuncVal* at 4(SP)
                        stk.xoffset = widthptr;
-                       nodreg(&reg, types[TINT32], D_AX);
+                       nodreg(&reg, types[TINT32], REG_AX);
                        gmove(f, &reg);
                        gins(AMOVL, &reg, &stk);
                }
@@ -262,7 +260,7 @@ ginscall(Node *f, int proc)
                        ginscall(deferproc, 0);
                }
                if(proc == 2) {
-                       nodreg(&reg, types[TINT32], D_AX);
+                       nodreg(&reg, types[TINT32], REG_AX);
                        gins(ATESTL, &reg, &reg);
                        p = gbranch(AJEQ, T, +1);
                        cgen_ret(N);
@@ -304,8 +302,8 @@ cgen_callinter(Node *n, Node *res, int proc)
        // register to hold its address.
        igen(i, &nodi, res);            // REG = &inter
 
-       nodindreg(&nodsp, types[tptr], D_SP);
-        nodsp.xoffset = 0;
+       nodindreg(&nodsp, types[tptr], REG_SP);
+       nodsp.xoffset = 0;
        if(proc != 0)
                nodsp.xoffset += 2 * widthptr; // leave room for size & fn
        nodi.type = types[tptr];
@@ -412,7 +410,7 @@ cgen_callret(Node *n, Node *res)
 
        memset(&nod, 0, sizeof(nod));
        nod.op = OINDREG;
-       nod.val.u.reg = D_SP;
+       nod.val.u.reg = REG_SP;
        nod.addable = 1;
 
        nod.xoffset = fp->width;
@@ -442,7 +440,7 @@ cgen_aret(Node *n, Node *res)
 
        memset(&nod1, 0, sizeof(nod1));
        nod1.op = OINDREG;
-       nod1.val.u.reg = D_SP;
+       nod1.val.u.reg = REG_SP;
        nod1.addable = 1;
 
        nod1.xoffset = fp->width;
@@ -473,7 +471,8 @@ cgen_ret(Node *n)
        genlist(curfn->exit);
        p = gins(ARET, N, N);
        if(n != N && n->op == ORETJMP) {
-               p->to.type = D_EXTERN;
+               p->to.type = TYPE_MEM;
+               p->to.name = NAME_EXTERN;
                p->to.sym = linksym(n->left->sym);
        }
 }
@@ -676,14 +675,14 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
 
        regalloc(&n3, t0, N);
        if(nl->ullman >= nr->ullman) {
-               savex(D_AX, &ax, &oldax, res, t0);
+               savex(REG_AX, &ax, &oldax, res, t0);
                cgen(nl, &ax);
                regalloc(&ax, t0, &ax); // mark ax live during cgen
                cgen(nr, &n3);
                regfree(&ax);
        } else {
                cgen(nr, &n3);
-               savex(D_AX, &ax, &oldax, res, t0);
+               savex(REG_AX, &ax, &oldax, res, t0);
                cgen(nl, &ax);
        }
        if(t != t0) {
@@ -725,7 +724,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
                p2 = gbranch(AJMP, T, 0);
                patch(p1, pc);
        }
-       savex(D_DX, &dx, &olddx, res, t);
+       savex(REG_DX, &dx, &olddx, res, t);
        if(!issigned[t->etype]) {
                nodconst(&n4, t, 0);
                gmove(&n4, &dx);
@@ -929,7 +928,7 @@ cgen_hmul(Node *nl, Node *nr, Node *res)
        }
        cgenr(nl, &n1, res);
        cgenr(nr, &n2, N);
-       nodreg(&ax, t, D_AX);
+       nodreg(&ax, t, REG_AX);
        gmove(&n1, &ax);
        gins(a, &n2, N);
        regfree(&n2);
@@ -937,11 +936,11 @@ cgen_hmul(Node *nl, Node *nr, Node *res)
 
        if(t->width == 1) {
                // byte multiply behaves differently.
-               nodreg(&ax, t, D_AH);
-               nodreg(&dx, t, D_DX);
+               nodreg(&ax, t, REG_AH);
+               nodreg(&dx, t, REG_DX);
                gmove(&ax, &dx);
        }
-       nodreg(&dx, t, D_DX);
+       nodreg(&dx, t, REG_DX);
        gmove(&dx, res);
 }
 
@@ -988,8 +987,8 @@ cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
                nr = &n5;
        }
 
-       rcx = reg[D_CX];
-       nodreg(&n1, types[TUINT32], D_CX);
+       rcx = reg[REG_CX];
+       nodreg(&n1, types[TUINT32], REG_CX);
        
        // Allow either uint32 or uint64 as shift type,
        // to avoid unnecessary conversion from uint32 to uint64
@@ -1001,7 +1000,7 @@ cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
        regalloc(&n1, nr->type, &n1);           // to hold the shift type in CX
        regalloc(&n3, tcount, &n1);     // to clear high bits of CX
 
-       nodreg(&cx, types[TUINT64], D_CX);
+       nodreg(&cx, types[TUINT64], REG_CX);
        memset(&oldcx, 0, sizeof oldcx);
        if(rcx > 0 && !samereg(&cx, res)) {
                regalloc(&oldcx, types[TUINT64], N);
@@ -1148,19 +1147,19 @@ clearfat(Node *nl)
                return;
        }
 
-       savex(D_DI, &n1, &oldn1, N, types[tptr]);
+       savex(REG_DI, &n1, &oldn1, N, types[tptr]);
        agen(nl, &n1);
 
-       savex(D_AX, &ax, &oldax, N, types[tptr]);
-       gconreg(AMOVL, 0, D_AX);
+       savex(REG_AX, &ax, &oldax, N, types[tptr]);
+       gconreg(AMOVL, 0, REG_AX);
 
        if(q > 128 || nacl) {
-               gconreg(movptr, q, D_CX);
+               gconreg(movptr, q, REG_CX);
                gins(AREP, N, N);       // repeat
                gins(ASTOSQ, N, N);     // STOQ AL,*(DI)+
        } else {
                p = gins(ADUFFZERO, N, N);
-               p->to.type = D_ADDR;
+               p->to.type = TYPE_ADDR;
                p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
                // 2 and 128 = magic constants: see ../../runtime/asm_amd64.s
                p->to.offset = 2*(128-q);
@@ -1221,22 +1220,26 @@ expandchecks(Prog *firstp)
                p1->pc = 9999;
                p2->pc = 9999;
                p->as = cmpptr;
-               p->to.type = D_CONST;
+               p->to.type = TYPE_CONST;
                p->to.offset = 0;
                p1->as = AJNE;
-               p1->from.type = D_CONST;
+               p1->from.type = TYPE_CONST;
                p1->from.offset = 1; // likely
-               p1->to.type = D_BRANCH;
+               p1->to.type = TYPE_BRANCH;
                p1->to.u.branch = p2->link;
                // crash by write to memory address 0.
                // if possible, since we know arg is 0, use 0(arg),
                // which will be shorter to encode than plain 0.
                p2->as = AMOVL;
-               p2->from.type = D_AX;
-               if(regtyp(&p->from))
-                       p2->to.type = p->from.type + D_INDIR;
-               else
-                       p2->to.type = D_INDIR+D_NONE;
+               p2->from.type = TYPE_REG;
+               p2->from.reg = REG_AX;
+               if(regtyp(&p->from)) {
+                       p2->to.type = TYPE_MEM;
+                       p2->to.reg = p->from.reg;
+               } else {
+                       p2->to.type = TYPE_MEM;
+                       p2->to.reg = REG_NONE;
+               }
                p2->to.offset = 0;
        }
 }
index dbb4ff62c488aad7b3d46ceecc91f77f04861ade..33ee4d65c44e31e5688a7214e9b4a42d4ae762e6 100644 (file)
@@ -38,14 +38,14 @@ dsname(Sym *s, int off, char *t, int n)
        Prog *p;
 
        p = gins(ADATA, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.offset = off;
-       p->from.scale = n;
        p->from.sym = linksym(s);
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = n;
        
-       p->to.type = D_SCONST;
-       p->to.index = D_NONE;
+       p->to.type = TYPE_SCONST;
        memmove(p->to.u.sval, t, n);
        return off + n;
 }
@@ -60,7 +60,8 @@ datastring(char *s, int len, Addr *a)
        Sym *sym;
        
        sym = stringsym(s, len);
-       a->type = D_EXTERN;
+       a->type = TYPE_MEM;
+       a->name = NAME_EXTERN;
        a->sym = linksym(sym);
        a->node = sym->def;
        a->offset = widthptr+widthint;  // skip header
@@ -77,7 +78,8 @@ datagostring(Strlit *sval, Addr *a)
        Sym *sym;
 
        sym = stringsym(sval->s, sval->len);
-       a->type = D_EXTERN;
+       a->type = TYPE_MEM;
+       a->name = NAME_EXTERN;
        a->sym = linksym(sym);
        a->node = sym->def;
        a->offset = 0;  // header
@@ -100,7 +102,8 @@ gdata(Node *nam, Node *nr, int wid)
                }
        }
        p = gins(ADATA, nam, nr);
-       p->from.scale = wid;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = wid;
 }
 
 void
@@ -113,14 +116,16 @@ gdatacomplex(Node *nam, Mpcplx *cval)
        w = types[w]->width;
 
        p = gins(ADATA, nam, N);
-       p->from.scale = w;
-       p->to.type = D_FCONST;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = w;
+       p->to.type = TYPE_FCONST;
        p->to.u.dval = mpgetflt(&cval->real);
 
        p = gins(ADATA, nam, N);
-       p->from.scale = w;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = w;
        p->from.offset += w;
-       p->to.type = D_FCONST;
+       p->to.type = TYPE_FCONST;
        p->to.u.dval = mpgetflt(&cval->imag);
 }
 
@@ -132,14 +137,15 @@ gdatastring(Node *nam, Strlit *sval)
 
        p = gins(ADATA, nam, N);
        datastring(sval->s, sval->len, &p->to);
-       p->from.scale = types[tptr]->width;
-       p->to.index = p->to.type;
-       p->to.type = D_ADDR;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = types[tptr]->width;
+       p->to.type = TYPE_ADDR;
 //print("%P\n", p);
 
        nodconst(&nod1, types[TINT], sval->len);
        p = gins(ADATA, nam, &nod1);
-       p->from.scale = widthint;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthint;
        p->from.offset += widthptr;
 }
 
@@ -150,15 +156,15 @@ dstringptr(Sym *s, int off, char *str)
 
        off = rnd(off, widthptr);
        p = gins(ADATA, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->from.scale = widthptr;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
 
        datastring(str, strlen(str)+1, &p->to);
-       p->to.index = p->to.type;
-       p->to.type = D_ADDR;
+       p->to.type = TYPE_ADDR;
        p->to.etype = simtype[TINT];
        off += widthptr;
 
@@ -175,14 +181,14 @@ dgostrlitptr(Sym *s, int off, Strlit *lit)
 
        off = rnd(off, widthptr);
        p = gins(ADATA, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->from.scale = widthptr;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
        datagostring(lit, &p->to);
-       p->to.index = p->to.type;
-       p->to.type = D_ADDR;
+       p->to.type = TYPE_ADDR;
        p->to.etype = simtype[TINT];
        off += widthptr;
 
@@ -213,13 +219,14 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
        off = rnd(off, widthptr);
 
        p = gins(ADATA, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->from.scale = widthptr;
-       p->to.type = D_ADDR;
-       p->to.index = D_EXTERN;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
+       p->to.type = TYPE_ADDR;
+       p->to.name = NAME_EXTERN;
        p->to.sym = linksym(x);
        p->to.offset = xoff;
        off += widthptr;
@@ -231,5 +238,7 @@ void
 nopout(Prog *p)
 {
        p->as = ANOP;
+       p->from = zprog.from;
+       p->to = zprog.to;
 }
 
index 146ead11345caf9bc61ea957e4e745912cb16e1e..697016c6f3fba6e5d46e996d9cbf4be84213ed26 100644 (file)
@@ -42,10 +42,10 @@ void
 clearp(Prog *p)
 {
        p->as = AEND;
-       p->from.type = D_NONE;
-       p->from.index = D_NONE;
-       p->to.type = D_NONE;
-       p->to.index = D_NONE;
+       p->from.type = TYPE_NONE;
+       p->from.index = TYPE_NONE;
+       p->to.type = TYPE_NONE;
+       p->to.index = TYPE_NONE;
        p->pc = pcloc;
        pcloc++;
 }
@@ -118,10 +118,10 @@ gbranch(int as, Type *t, int likely)
        USED(t);
 
        p = prog(as);
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        p->to.u.branch = P;
        if(as != AJMP && likely != 0) {
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = likely > 0;
        }
        return p;
@@ -133,7 +133,7 @@ gbranch(int as, Type *t, int likely)
 void
 patch(Prog *p, Prog *to)
 {
-       if(p->to.type != D_BRANCH)
+       if(p->to.type != TYPE_BRANCH)
                fatal("patch: not a branch");
        p->to.u.branch = to;
        p->to.offset = to->pc;
@@ -144,7 +144,7 @@ unpatch(Prog *p)
 {
        Prog *q;
 
-       if(p->to.type != D_BRANCH)
+       if(p->to.type != TYPE_BRANCH)
                fatal("unpatch: not a branch");
        q = p->to.u.branch;
        p->to.u.branch = P;
@@ -195,12 +195,12 @@ ggloblnod(Node *nam)
        p->lineno = nam->lineno;
        p->from.sym->gotype = linksym(ngotype(nam));
        p->to.sym = nil;
-       p->to.type = D_CONST;
+       p->to.type = TYPE_CONST;
        p->to.offset = nam->type->width;
        if(nam->readonly)
-               p->from.scale = RODATA;
+               p->from3.offset = RODATA;
        if(nam->type != T && !haspointers(nam->type))
-               p->from.scale |= NOPTR;
+               p->from3.offset |= NOPTR;
 }
 
 void
@@ -209,8 +209,8 @@ gtrack(Sym *s)
        Prog *p;
        
        p = gins(AUSEFIELD, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
 }
 
@@ -220,13 +220,12 @@ ggloblsym(Sym *s, int32 width, int8 flags)
        Prog *p;
 
        p = gins(AGLOBL, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
-       p->to.type = D_CONST;
-       p->to.index = D_NONE;
+       p->to.type = TYPE_CONST;
        p->to.offset = width;
-       p->from.scale = flags;
+       p->from3.offset = flags;
 }
 
 int
@@ -251,22 +250,21 @@ isfat(Type *t)
 void
 afunclit(Addr *a, Node *n)
 {
-       if(a->type == D_ADDR && a->index == D_EXTERN) {
-               a->type = D_EXTERN;
-               a->index = D_NONE;
+       if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
+               a->type = TYPE_MEM;
                a->sym = linksym(n->sym);
        }
 }
 
 static int     resvd[] =
 {
-       D_DI,   // for movstring
-       D_SI,   // for movstring
+       REG_DI, // for movstring
+       REG_SI, // for movstring
 
-       D_AX,   // for divide
-       D_CX,   // for shift
-       D_DX,   // for divide
-       D_SP,   // for stack
+       REG_AX, // for divide
+       REG_CX, // for shift
+       REG_DX, // for divide
+       REG_SP, // for stack
 };
 
 void
@@ -276,17 +274,20 @@ ginit(void)
 
        for(i=0; i<nelem(reg); i++)
                reg[i] = 1;
-       for(i=D_AX; i<=D_R15; i++)
+       for(i=REG_AX; i<=REG_R15; i++)
                reg[i] = 0;
-       for(i=D_X0; i<=D_X15; i++)
+       for(i=REG_X0; i<=REG_X15; i++)
                reg[i] = 0;
 
        for(i=0; i<nelem(resvd); i++)
                reg[resvd[i]]++;
        
        if(nacl) {
-               reg[D_BP]++;
-               reg[D_R15]++;
+               reg[REG_BP]++;
+               reg[REG_R15]++;
+       } else if(framepointer_enabled) {
+               // BP is part of the calling convention of framepointer_enabled.
+               reg[REG_BP]++;
        }
 }
 
@@ -298,15 +299,17 @@ gclean(void)
        for(i=0; i<nelem(resvd); i++)
                reg[resvd[i]]--;
        if(nacl) {
-               reg[D_BP]--;
-               reg[D_R15]--;
+               reg[REG_BP]--;
+               reg[REG_R15]--;
+       } else if(framepointer_enabled) {
+               reg[REG_BP]--;
        }
 
 
-       for(i=D_AX; i<=D_R15; i++)
+       for(i=REG_AX; i<=REG_R15; i++)
                if(reg[i])
                        yyerror("reg %R left allocated\n", i);
-       for(i=D_X0; i<=D_X15; i++)
+       for(i=REG_X0; i<=REG_X15; i++)
                if(reg[i])
                        yyerror("reg %R left allocated\n", i);
 }
@@ -316,7 +319,7 @@ anyregalloc(void)
 {
        int i, j;
 
-       for(i=D_AX; i<=D_R15; i++) {
+       for(i=REG_AX; i<=REG_R15; i++) {
                if(reg[i] == 0)
                        goto ok;
                for(j=0; j<nelem(resvd); j++)
@@ -328,7 +331,7 @@ anyregalloc(void)
        return 0;
 }
 
-static uintptr regpc[D_R15+1 - D_AX];
+static uintptr regpc[REG_R15+1 - REG_AX];
 
 /*
  * allocate register of type t, leave in n.
@@ -358,17 +361,17 @@ regalloc(Node *n, Type *t, Node *o)
        case TBOOL:
                if(o != N && o->op == OREGISTER) {
                        i = o->val.u.reg;
-                       if(i >= D_AX && i <= D_R15)
+                       if(i >= REG_AX && i <= REG_R15)
                                goto out;
                }
-               for(i=D_AX; i<=D_R15; i++)
+               for(i=REG_AX; i<=REG_R15; i++)
                        if(reg[i] == 0) {
-                               regpc[i-D_AX] = (uintptr)getcallerpc(&n);
+                               regpc[i-REG_AX] = (uintptr)getcallerpc(&n);
                                goto out;
                        }
 
                flusherrors();
-               for(i=0; i+D_AX<=D_R15; i++)
+               for(i=0; i+REG_AX<=REG_R15; i++)
                        print("%d %p\n", i, regpc[i]);
                fatal("out of fixed registers");
 
@@ -376,10 +379,10 @@ regalloc(Node *n, Type *t, Node *o)
        case TFLOAT64:
                if(o != N && o->op == OREGISTER) {
                        i = o->val.u.reg;
-                       if(i >= D_X0 && i <= D_X15)
+                       if(i >= REG_X0 && i <= REG_X15)
                                goto out;
                }
-               for(i=D_X0; i<=D_X15; i++)
+               for(i=REG_X0; i<=REG_X15; i++)
                        if(reg[i] == 0)
                                goto out;
                fatal("out of floating registers");
@@ -407,15 +410,15 @@ regfree(Node *n)
        if(n->op != OREGISTER && n->op != OINDREG)
                fatal("regfree: not a register");
        i = n->val.u.reg;
-       if(i == D_SP)
+       if(i == REG_SP)
                return;
        if(i < 0 || i >= nelem(reg))
                fatal("regfree: reg out of range");
        if(reg[i] <= 0)
                fatal("regfree: reg not allocated");
        reg[i]--;
-       if(reg[i] == 0 && D_AX <= i && i <= D_R15)
-               regpc[i - D_AX] = 0;
+       if(reg[i] == 0 && REG_AX <= i && i <= REG_R15)
+               regpc[i - REG_AX] = 0;
 }
 
 /*
@@ -499,7 +502,7 @@ fp:
        switch(fp) {
        case 0:         // output arg
                n->op = OINDREG;
-               n->val.u.reg = D_SP;
+               n->val.u.reg = REG_SP;
                break;
 
        case 1:         // input arg
@@ -509,7 +512,7 @@ fp:
        case 2:         // offset output arg
 fatal("shouldn't be used");
                n->op = OINDREG;
-               n->val.u.reg = D_SP;
+               n->val.u.reg = REG_SP;
                n->xoffset += types[tptr]->width;
                break;
        }
@@ -1079,6 +1082,8 @@ gins(int as, Node *f, Node *t)
                dump("t", t);
                fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
        }
+       if(p->to.type == TYPE_ADDR && w > 0)
+               fatal("bad use of addr: %P", p);
 
        return p;
 }
@@ -1092,7 +1097,7 @@ fixlargeoffset(Node *n)
                return;
        if(n->op != OINDREG)
                return;
-       if(n->val.u.reg == D_SP) // stack offset cannot be large
+       if(n->val.u.reg == REG_SP) // stack offset cannot be large
                return;
        if(n->xoffset != (int32)n->xoffset) {
                // offset too large, add to register instead.
@@ -1116,8 +1121,10 @@ naddr(Node *n, Addr *a, int canemitcode)
        Sym *s;
 
        a->scale = 0;
-       a->index = D_NONE;
-       a->type = D_NONE;
+       a->reg = REG_NONE;
+       a->index = REG_NONE;
+       a->type = TYPE_NONE;
+       a->name = NAME_NONE;
        a->gotype = nil;
        a->node = N;
        a->width = 0;
@@ -1135,32 +1142,14 @@ naddr(Node *n, Addr *a, int canemitcode)
                break;
 
        case OREGISTER:
-               a->type = n->val.u.reg;
+               a->type = TYPE_REG;
+               a->reg = n->val.u.reg;
                a->sym = nil;
                break;
 
-//     case OINDEX:
-//     case OIND:
-//             naddr(n->left, a);
-//             if(a->type >= D_AX && a->type <= D_DI)
-//                     a->type += D_INDIR;
-//             else
-//             if(a->type == D_CONST)
-//                     a->type = D_NONE+D_INDIR;
-//             else
-//             if(a->type == D_ADDR) {
-//                     a->type = a->index;
-//                     a->index = D_NONE;
-//             } else
-//                     goto bad;
-//             if(n->op == OINDEX) {
-//                     a->index = idx.reg;
-//                     a->scale = n->scale;
-//             }
-//             break;
-
        case OINDREG:
-               a->type = n->val.u.reg+D_INDIR;
+               a->type = TYPE_MEM;
+               a->reg = n->val.u.reg;
                a->sym = linksym(n->sym);
                a->offset = n->xoffset;
                if(a->offset != (int32)a->offset)
@@ -1174,14 +1163,16 @@ naddr(Node *n, Addr *a, int canemitcode)
                a->width = n->left->type->width;
                a->offset = n->xoffset;
                a->sym = linksym(n->left->sym);
-               a->type = D_PARAM;
+               a->type = TYPE_MEM;
+               a->name = NAME_PARAM;
                a->node = n->left->orig;
                break;
        
        case OCLOSUREVAR:
                if(!curfn->needctxt)
                        fatal("closurevar without needctxt");
-               a->type = D_DX+D_INDIR;
+               a->type = TYPE_MEM;
+               a->reg = REG_DX;
                a->sym = nil;
                a->offset = n->xoffset;
                break;
@@ -1209,22 +1200,23 @@ naddr(Node *n, Addr *a, int canemitcode)
                                s = pkglookup(s->name, n->type->sym->pkg);
                }
 
+               a->type = TYPE_MEM;
                switch(n->class) {
                default:
                        fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
                case PEXTERN:
-                       a->type = D_EXTERN;
+                       a->name = NAME_EXTERN;
                        break;
                case PAUTO:
-                       a->type = D_AUTO;
+                       a->name = NAME_AUTO;
                        break;
                case PPARAM:
                case PPARAMOUT:
-                       a->type = D_PARAM;
+                       a->name = NAME_PARAM;
                        break;
                case PFUNC:
-                       a->index = D_EXTERN;
-                       a->type = D_ADDR;
+                       a->name = NAME_EXTERN;
+                       a->type = TYPE_ADDR;
                        a->width = widthptr;
                        s = funcsym(s);                 
                        break;
@@ -1238,13 +1230,13 @@ naddr(Node *n, Addr *a, int canemitcode)
                        fatal("naddr: const %lT", n->type);
                        break;
                case CTFLT:
-                       a->type = D_FCONST;
+                       a->type = TYPE_FCONST;
                        a->u.dval = mpgetflt(n->val.u.fval);
                        break;
                case CTINT:
                case CTRUNE:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = mpgetfix(n->val.u.xval);
                        break;
                case CTSTR:
@@ -1252,12 +1244,12 @@ naddr(Node *n, Addr *a, int canemitcode)
                        break;
                case CTBOOL:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = n->val.u.bval;
                        break;
                case CTNIL:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = 0;
                        break;
                }
@@ -1266,23 +1258,15 @@ naddr(Node *n, Addr *a, int canemitcode)
        case OADDR:
                naddr(n->left, a, canemitcode);
                a->width = widthptr;
-               if(a->type >= D_INDIR) {
-                       a->type -= D_INDIR;
-                       break;
-               }
-               if(a->type == D_EXTERN || a->type == D_STATIC ||
-                  a->type == D_AUTO || a->type == D_PARAM)
-                       if(a->index == D_NONE) {
-                               a->index = a->type;
-                               a->type = D_ADDR;
-                               break;
-                       }
-               fatal("naddr: OADDR\n");
+               if(a->type != TYPE_MEM)
+                       fatal("naddr: OADDR %D", a);
+               a->type = TYPE_ADDR;
+               break;
        
        case OITAB:
                // itable of interface value
                naddr(n->left, a, canemitcode);
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // itab(nil)
                a->etype = tptr;
                a->width = widthptr;
@@ -1291,7 +1275,7 @@ naddr(Node *n, Addr *a, int canemitcode)
        case OSPTR:
                // pointer in a string or slice
                naddr(n->left, a, canemitcode);
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // ptr(nil)
                a->etype = simtype[tptr];
                a->offset += Array_array;
@@ -1301,7 +1285,7 @@ naddr(Node *n, Addr *a, int canemitcode)
        case OLEN:
                // len of string or slice
                naddr(n->left, a, canemitcode);
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // len(nil)
                a->etype = simtype[TUINT];
                a->offset += Array_nel;
@@ -1311,7 +1295,7 @@ naddr(Node *n, Addr *a, int canemitcode)
        case OCAP:
                // cap of string or slice
                naddr(n->left, a, canemitcode);
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // cap(nil)
                a->etype = simtype[TUINT];
                a->offset += Array_cap;
@@ -1345,7 +1329,7 @@ optoas(int op, Type *t)
        if(t == T)
                fatal("optoas: t is nil");
 
-       a = AGOK;
+       a = AXXX;
        switch(CASE(op, simtype[t->etype])) {
        default:
                fatal("optoas: no entry %O-%T", op, t);
@@ -2067,8 +2051,8 @@ odot:
                n1.xoffset = -(oary[i]+1);
        }
 
-       a->type = D_NONE;
-       a->index = D_NONE;
+       a->type = TYPE_NONE;
+       a->index = TYPE_NONE;
        fixlargeoffset(&n1);
        naddr(&n1, a, 1);
        goto yes;
@@ -2178,14 +2162,16 @@ oindex:
                naddr(reg1, a, 1);
                a->offset = 0;
                a->scale = w;
-               a->index = a->type;
-               a->type = reg->val.u.reg + D_INDIR;
+               a->index = a->reg;
+               a->type = TYPE_MEM;
+               a->reg = reg->val.u.reg;
        } else {
                naddr(reg1, a, 1);
                a->offset = 0;
                a->scale = w;
-               a->index = a->type;
-               a->type = reg->val.u.reg + D_INDIR;
+               a->index = a->reg;
+               a->type = TYPE_MEM;
+               a->reg = reg->val.u.reg;
        }
 
        goto yes;
@@ -2232,8 +2218,8 @@ oindex_const:
                n2.op = OINDREG;
                n2.xoffset = v*w;
                fixlargeoffset(&n2);
-               a->type = D_NONE;
-               a->index = D_NONE;
+               a->type = TYPE_NONE;
+               a->index = TYPE_NONE;
                naddr(&n2, a, 1);
                goto yes;
        }
@@ -2245,8 +2231,8 @@ oindex_const:
        }
        n1.xoffset += v*w;
        fixlargeoffset(&n1);
-       a->type = D_NONE;
-       a->index= D_NONE;
+       a->type = TYPE_NONE;
+       a->index= TYPE_NONE;
        naddr(&n1, a, 1);
        goto yes;
 
@@ -2281,8 +2267,8 @@ oindex_const_sudo:
        n2.op = OINDREG;
        n2.xoffset = v*w;
        fixlargeoffset(&n2);
-       a->type = D_NONE;
-       a->index = D_NONE;
+       a->type = TYPE_NONE;
+       a->index = TYPE_NONE;
        naddr(&n2, a, 1);
        goto yes;
 
index 493171ef82db80ff7b6ba1bb8a9662ee06dce717..11befb6ad1129ba881f14ed4d817fd5aaa66882a 100644 (file)
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include       "../gc/popt.h"
 
 #define        Z       N
 #define        Adr     Addr
 
-#define        D_HI    D_NONE
-#define        D_LO    D_NONE
+#define        D_HI    TYPE_NONE
+#define        D_LO    TYPE_NONE
 
 #define        BLOAD(r)        band(bnot(r->refbehind), r->refahead)
 #define        BSTORE(r)       band(bnot(r->calbehind), r->calahead)
@@ -53,8 +52,8 @@ typedef       struct  Rgn     Rgn;
 extern Node *Z;
 enum
 {
-       D_HI = D_NONE,
-       D_LO = D_NONE,
+       D_HI = TYPE_NONE,
+       D_LO = TYPE_NONE,
        CLOAD = 5,
        CREF = 5,
        CINF = 1000,
@@ -177,60 +176,5 @@ int        BtoF(uint32);
 /*
  * prog.c
  */
-typedef struct ProgInfo ProgInfo;
-struct ProgInfo
-{
-       uint32 flags; // the bits below
-       uint32 reguse; // registers implicitly used by this instruction
-       uint32 regset; // registers implicitly set by this instruction
-       uint32 regindex; // registers used by addressing mode
-};
-
-enum
-{
-       // Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
-       Pseudo = 1<<1,
-       
-       // There's nothing to say about the instruction,
-       // but it's still okay to see.
-       OK = 1<<2,
-
-       // Size of right-side write, or right-side read if no write.
-       SizeB = 1<<3,
-       SizeW = 1<<4,
-       SizeL = 1<<5,
-       SizeQ = 1<<6,
-       SizeF = 1<<7, // float aka float32
-       SizeD = 1<<8, // double aka float64
-
-       // Left side (Prog.from): address taken, read, write.
-       LeftAddr = 1<<9,
-       LeftRead = 1<<10,
-       LeftWrite = 1<<11,
-       
-       // Right side (Prog.to): address taken, read, write.
-       RightAddr = 1<<12,
-       RightRead = 1<<13,
-       RightWrite = 1<<14,
-
-       // Set, use, or kill of carry bit.
-       // Kill means we never look at the carry bit after this kind of instruction.
-       SetCarry = 1<<15,
-       UseCarry = 1<<16,
-       KillCarry = 1<<17,
-
-       // Instruction kinds
-       Move = 1<<18, // straight move
-       Conv = 1<<19, // size conversion
-       Cjmp = 1<<20, // conditional jump
-       Break = 1<<21, // breaks control flow (no fallthrough)
-       Call = 1<<22, // function call
-       Jump = 1<<23, // jump
-       Skip = 1<<24, // data instruction
-
-       // Special cases for register use.
-       ShiftCX = 1<<25, // possible shift by CX
-       ImulAXDX = 1<<26, // possible multiply into DX:AX
-};
 
 void proginfo(ProgInfo*, Prog*);
index 2445081e3e767e33f5b9eceb84e9bb458f155422..e05a06087f0d6e9e4f122717ed9dda09de440b4c 100644 (file)
@@ -73,7 +73,7 @@ rnops(Flow *r)
        if(r != nil)
        for(;;) {
                p = r->prog;
-               if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+               if(p->as != ANOP || p->from.type != TYPE_NONE || p->to.type != TYPE_NONE)
                        break;
                r1 = uniqs(r);
                if(r1 == nil)
@@ -110,7 +110,7 @@ peep(Prog *firstp)
                case ALEAQ:
                        if(regtyp(&p->to))
                        if(p->from.sym != nil)
-                       if(p->from.index == D_NONE || p->from.index == D_CONST)
+                       if(p->from.index == REG_NONE)
                                conprop(r);
                        break;
 
@@ -121,7 +121,7 @@ peep(Prog *firstp)
                case AMOVSS:
                case AMOVSD:
                        if(regtyp(&p->to))
-                       if(p->from.type == D_CONST || p->from.type == D_FCONST)
+                       if(p->from.type == TYPE_CONST || p->from.type == TYPE_FCONST)
                                conprop(r);
                        break;
                }
@@ -160,7 +160,7 @@ loop1:
                                r1 = rnops(uniqs(r));
                                if(r1 != nil) {
                                        p1 = r1->prog;
-                                       if(p->as == p1->as && p->to.type == p1->from.type){
+                                       if(p->as == p1->as && p->to.type == p1->from.type && p->to.reg == p1->from.reg){
                                                p1->as = AMOVL;
                                                t++;
                                        }
@@ -179,7 +179,7 @@ loop1:
                                r1 = rnops(uniqs(r));
                                if(r1 != nil) {
                                        p1 = r1->prog;
-                                       if(p->as == p1->as && p->to.type == p1->from.type){
+                                       if(p->as == p1->as && p->to.type == p1->from.type && p->to.reg == p1->from.reg){
                                                p1->as = AMOVQ;
                                                t++;
                                        }
@@ -190,7 +190,7 @@ loop1:
                case AADDL:
                case AADDQ:
                case AADDW:
-                       if(p->from.type != D_CONST || needc(p->link))
+                       if(p->from.type != TYPE_CONST || needc(p->link))
                                break;
                        if(p->from.offset == -1){
                                if(p->as == AADDQ)
@@ -218,7 +218,7 @@ loop1:
                case ASUBL:
                case ASUBQ:
                case ASUBW:
-                       if(p->from.type != D_CONST || needc(p->link))
+                       if(p->from.type != TYPE_CONST || needc(p->link))
                                break;
                        if(p->from.offset == -1) {
                                if(p->as == ASUBQ)
@@ -264,8 +264,8 @@ loop1:
                p = r->prog;
                if(p->as == AMOVLQZX)
                if(regtyp(&p->from))
-               if(p->from.type == p->to.type)
-               if(prevl(r, p->from.type))
+               if(p->from.type == p->to.type && p->from.reg == p->to.reg)
+               if(prevl(r, p->from.reg))
                        excise(r);
                
                if(p->as == AMOVSD)
@@ -369,9 +369,7 @@ excise(Flow *r)
        if(debug['P'] && debug['v'])
                print("%P ===delete===\n", p);
 
-       p->as = ANOP;
-       p->from = zprog.from;
-       p->to = zprog.to;
+       nopout(p);
 
        ostats.ndelmov++;
 }
@@ -379,14 +377,7 @@ excise(Flow *r)
 int
 regtyp(Adr *a)
 {
-       int t;
-
-       t = a->type;
-       if(t >= D_AX && t <= D_R15)
-               return 1;
-       if(t >= D_X0 && t <= D_X15)
-               return 1;
-       return 0;
+       return a->type == TYPE_REG && (REG_AX <= a->reg && a->reg <= REG_R15 || REG_X0 <= a->reg && a->reg <= REG_X15);
 }
 
 // movb elimination.
@@ -426,7 +417,7 @@ elimshortmov(Graph *g)
                                p->as = ANOTQ;
                                break;
                        }
-                       if(regtyp(&p->from) || p->from.type == D_CONST) {
+                       if(regtyp(&p->from) || p->from.type == TYPE_CONST) {
                                // move or artihmetic into partial register.
                                // from another register or constant can be movl.
                                // we don't switch to 64-bit arithmetic if it can
@@ -471,7 +462,7 @@ elimshortmov(Graph *g)
                                        p->as = ASHLQ;
                                        break;
                                }
-                       } else if(p->from.type >= D_NONE) {
+                       } else if(p->from.type != TYPE_REG) {
                                // explicit zero extension, but don't
                                // do that if source is a byte register
                                // (only AH can occur and it's forbidden).
@@ -495,10 +486,10 @@ regconsttyp(Adr *a)
        if(regtyp(a))
                return 1;
        switch(a->type) {
-       case D_CONST:
-       case D_FCONST:
-       case D_SCONST:
-       case D_ADDR:
+       case TYPE_CONST:
+       case TYPE_FCONST:
+       case TYPE_SCONST:
+       case TYPE_ADDR: // TODO(rsc): Not all TYPE_ADDRs are constants.
                return 1;
        }
        return 0;
@@ -514,7 +505,7 @@ prevl(Flow *r0, int reg)
 
        for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
                p = r->prog;
-               if(p->to.type == reg) {
+               if(p->to.type == TYPE_REG && p->to.reg == reg) {
                        proginfo(&info, p);
                        if(info.flags & RightWrite) {
                                if(info.flags & SizeL)
@@ -588,7 +579,7 @@ subprop(Flow *r0)
                        return 0;
                }
 
-               if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
+               if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type && p->to.reg == v1->reg)
                        goto gotit;
 
                if(copyau(&p->from, v2) ||
@@ -612,7 +603,7 @@ 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)
+               if(p->from.type == v2->type && p->from.reg == v2->reg)
                        print(" excise");
                print("\n");
        }
@@ -623,9 +614,9 @@ gotit:
                if(debug['P'])
                        print("%P\n", r->prog);
        }
-       t = v1->type;
-       v1->type = v2->type;
-       v2->type = t;
+       t = v1->reg;
+       v1->reg = v2->reg;
+       v2->reg = t;
        if(debug['P'])
                print("%P last\n", r->prog);
        return 1;
@@ -768,11 +759,11 @@ copyu(Prog *p, Adr *v, Adr *s)
                return 3;
 
        case ACALL:
-               if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
+               if(REGEXT && v->type == TYPE_REG && v->reg <= REGEXT && v->reg > exregoffset)
                        return 2;
-               if(REGARG >= 0 && v->type == (uchar)REGARG)
+               if(REGARG >= 0 && v->type == TYPE_REG && v->reg == (uchar)REGARG)
                        return 2;
-               if(v->type == p->from.type)
+               if(v->type == p->from.type && v->reg == p->from.reg)
                        return 2;
 
                if(s != nil) {
@@ -785,7 +776,7 @@ copyu(Prog *p, Adr *v, Adr *s)
                return 3;
 
        case ATEXT:
-               if(REGARG >= 0 && v->type == (uchar)REGARG)
+               if(REGARG >= 0 && v->type == TYPE_REG && v->reg == (uchar)REGARG)
                        return 3;
                return 0;
        }
@@ -794,7 +785,7 @@ copyu(Prog *p, Adr *v, Adr *s)
                return 0;
        proginfo(&info, p);
 
-       if((info.reguse|info.regset) & RtoB(v->type))
+       if((info.reguse|info.regset) & RtoB(v->reg))
                return 2;
                
        if(info.flags & LeftAddr)
@@ -838,16 +829,16 @@ copyu(Prog *p, Adr *v, Adr *s)
 static int
 copyas(Adr *a, Adr *v)
 {
-       if(D_AL <= a->type && a->type <= D_R15B)
+       if(REG_AL <= a->reg && a->reg <= REG_R15B)
                fatal("use of byte register");
-       if(D_AL <= v->type && v->type <= D_R15B)
+       if(REG_AL <= v->reg && v->reg <= REG_R15B)
                fatal("use of byte register");
 
-       if(a->type != v->type)
+       if(a->type != v->type || a->name != v->name || a->reg != v->reg)
                return 0;
        if(regtyp(v))
                return 1;
-       if(v->type == D_AUTO || v->type == D_PARAM)
+       if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM))
                if(v->offset == a->offset)
                        return 1;
        return 0;
@@ -856,11 +847,11 @@ copyas(Adr *a, Adr *v)
 int
 sameaddr(Addr *a, Addr *v)
 {
-       if(a->type != v->type)
+       if(a->type != v->type || a->name != v->name || a->reg != v->reg)
                return 0;
        if(regtyp(v))
                return 1;
-       if(v->type == D_AUTO || v->type == D_PARAM)
+       if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM))
                if(v->offset == a->offset)
                        return 1;
        return 0;
@@ -879,12 +870,12 @@ copyau(Adr *a, Adr *v)
                return 1;
        }
        if(regtyp(v)) {
-               if(a->type-D_INDIR == v->type) {
+               if(a->type == TYPE_MEM && a->reg == v->reg) {
                        if(debug['P'] && debug['v'])
                                print("\tcopyau: found indir use - return 1\n");
                        return 1;
                }
-               if(a->index == v->type) {
+               if(a->index == v->reg) {
                        if(debug['P'] && debug['v'])
                                print("\tcopyau: found index use - return 1\n");
                        return 1;
@@ -900,28 +891,28 @@ copyau(Adr *a, Adr *v)
 static int
 copysub(Adr *a, Adr *v, Adr *s, int f)
 {
-       int t;
+       int reg;
 
        if(copyas(a, v)) {
-               t = s->type;
-               if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
+               reg = s->reg;
+               if(reg >= REG_AX && reg <= REG_R15 || reg >= REG_X0 && reg <= REG_X0+15) {
                        if(f)
-                               a->type = t;
+                               a->reg = reg;
                }
                return 0;
        }
        if(regtyp(v)) {
-               t = v->type;
-               if(a->type == t+D_INDIR) {
-                       if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
+               reg = v->reg;
+               if(a->type == TYPE_MEM && a->reg == reg) {
+                       if((s->reg == REG_BP || s->reg == REG_R13) && a->index != REG_NONE)
                                return 1;       /* can't use BP-base with index */
                        if(f)
-                               a->type = s->type+D_INDIR;
+                               a->reg = s->reg;
 //                     return 0;
                }
-               if(a->index == t) {
+               if(a->index == reg) {
                        if(f)
-                               a->index = s->type;
+                               a->index = s->reg;
                        return 0;
                }
                return 0;
@@ -962,10 +953,11 @@ loop:
        case 3: // set
                if(p->as == p0->as)
                if(p->from.type == p0->from.type)
+               if(p->from.reg == p0->from.reg)
                if(p->from.node == p0->from.node)
                if(p->from.offset == p0->from.offset)
                if(p->from.scale == p0->from.scale)
-               if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval)
+               if(p->from.type == TYPE_FCONST && p->from.u.dval == p0->from.u.dval)
                if(p->from.index == p0->from.index) {
                        excise(r);
                        goto loop;
@@ -978,13 +970,13 @@ int
 smallindir(Addr *a, Addr *reg)
 {
        return regtyp(reg) &&
-               a->type == D_INDIR + reg->type &&
-               a->index == D_NONE &&
+               a->type == TYPE_MEM && a->reg == reg->reg &&
+               a->index == REG_NONE &&
                0 <= a->offset && a->offset < 4096;
 }
 
 int
 stackaddr(Addr *a)
 {
-       return regtyp(a) && a->type == D_SP;
+       return a->type == TYPE_REG && a->reg == REG_SP;
 }
index ee68399d5adf13ef34e866c9ffa1553abc453bb8..32d5256f8c83f86b5789a14b1586059424e5d9a4 100644 (file)
@@ -8,15 +8,15 @@
 #include "opt.h"
 
 // Matches real RtoB but can be used in global initializer.
-#define RtoB(r) (1<<((r)-D_AX))
+#define RtoB(r) (1<<((r)-REG_AX))
 
 enum {
-       AX = RtoB(D_AX),
-       BX = RtoB(D_BX),
-       CX = RtoB(D_CX),
-       DX = RtoB(D_DX),
-       DI = RtoB(D_DI),
-       SI = RtoB(D_SI),
+       AX = RtoB(REG_AX),
+       BX = RtoB(REG_BX),
+       CX = RtoB(REG_CX),
+       DX = RtoB(REG_DX),
+       DI = RtoB(REG_DI),
+       SI = RtoB(REG_SI),
        
        LeftRdwr = LeftRead | LeftWrite,
        RightRdwr = RightRead | RightWrite,
@@ -294,11 +294,11 @@ proginfo(ProgInfo *info, Prog *p)
        if(info->flags == 0)
                fatal("unknown instruction %P", p);
 
-       if((info->flags & ShiftCX) && p->from.type != D_CONST)
+       if((info->flags & ShiftCX) && p->from.type != TYPE_CONST)
                info->reguse |= CX;
 
        if(info->flags & ImulAXDX) {
-               if(p->to.type == D_NONE) {
+               if(p->to.type == TYPE_NONE) {
                        info->reguse |= AX;
                        info->regset |= AX | DX;
                } else {
@@ -307,12 +307,12 @@ proginfo(ProgInfo *info, Prog *p)
        }
 
        // Addressing makes some registers used.
-       if(p->from.type >= D_INDIR)
-               info->regindex |= RtoB(p->from.type-D_INDIR);
-       if(p->from.index != D_NONE)
+       if(p->from.type == TYPE_MEM && p->from.name == NAME_NONE)
+               info->regindex |= RtoB(p->from.reg);
+       if(p->from.index != REG_NONE)
                info->regindex |= RtoB(p->from.index);
-       if(p->to.type >= D_INDIR)
-               info->regindex |= RtoB(p->to.type-D_INDIR);
-       if(p->to.index != D_NONE)
+       if(p->to.type == TYPE_MEM && p->to.name == NAME_NONE)
+               info->regindex |= RtoB(p->to.reg);
+       if(p->to.index != REG_NONE)
                info->regindex |= RtoB(p->to.index);
 }
index f3dc59b146db996350f958069caa5ea48081a16e..7db44245f1d6804ec8135d5ba8f6d43ccc91258d 100644 (file)
@@ -134,7 +134,7 @@ regopt(Prog *firstp)
 
        if(first) {
                fmtinstall('Q', Qconv);
-               exregoffset = D_R15;
+               exregoffset = REG_R15;
                first = 0;
        }
 
@@ -153,7 +153,7 @@ regopt(Prog *firstp)
                var[i].node = regnodes[i];
        }
 
-       regbits = RtoB(D_SP);
+       regbits = RtoB(REG_SP);
        for(z=0; z<BITS; z++) {
                externs.b[z] = 0;
                params.b[z] = 0;
@@ -185,7 +185,7 @@ regopt(Prog *firstp)
                proginfo(&info, p);
 
                // Avoid making variables for direct-called functions.
-               if(p->as == ACALL && p->to.type == D_EXTERN)
+               if(p->as == ACALL && p->to.type == TYPE_MEM && p->to.name == NAME_EXTERN)
                        continue;
 
                r->use1.b[0] |= info.reguse | info.regindex;
@@ -255,7 +255,7 @@ regopt(Prog *firstp)
        }
        for(r = firstr; r != R; r = (Reg*)r->f.link) {
                p = r->f.prog;
-               if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
+               if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
                        active++;
                        walkvardef(p->to.node, r, active);
                }
@@ -440,7 +440,7 @@ brk:
        for(p=firstp; p!=P; p=p->link) {
                while(p->link != P && p->link->as == ANOP)
                        p->link = p->link->link;
-               if(p->to.type == D_BRANCH)
+               if(p->to.type == TYPE_BRANCH)
                        while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
                                p->to.u.branch = p->to.u.branch->link;
        }
@@ -523,7 +523,8 @@ addmove(Reg *r, int bn, int rn, int f)
        a = &p1->to;
        a->offset = v->offset;
        a->etype = v->etype;
-       a->type = v->name;
+       a->type = TYPE_MEM;
+       a->name = v->name;
        a->node = v->node;
        a->sym = linksym(v->node->sym);
 
@@ -559,11 +560,14 @@ addmove(Reg *r, int bn, int rn, int f)
                break;
        }
 
-       p1->from.type = rn;
+       p1->from.type = TYPE_REG;
+       p1->from.reg = rn;
+       p1->from.name = NAME_NONE;
        if(!f) {
                p1->from = *a;
                *a = zprog.from;
-               a->type = rn;
+               a->type = TYPE_REG;
+               a->reg = rn;
                if(v->etype == TUINT8)
                        p1->as = AMOVB;
                if(v->etype == TUINT16)
@@ -580,18 +584,16 @@ doregbits(int r)
        uint32 b;
 
        b = 0;
-       if(r >= D_INDIR)
-               r -= D_INDIR;
-       if(r >= D_AX && r <= D_R15)
+       if(r >= REG_AX && r <= REG_R15)
                b |= RtoB(r);
        else
-       if(r >= D_AL && r <= D_R15B)
-               b |= RtoB(r-D_AL+D_AX);
+       if(r >= REG_AL && r <= REG_R15B)
+               b |= RtoB(r-REG_AL+REG_AX);
        else
-       if(r >= D_AH && r <= D_BH)
-               b |= RtoB(r-D_AH+D_AX);
+       if(r >= REG_AH && r <= REG_BH)
+               b |= RtoB(r-REG_AH+REG_AX);
        else
-       if(r >= D_X0 && r <= D_X0+15)
+       if(r >= REG_X0 && r <= REG_X0+15)
                b |= FtoB(r);
        return b;
 }
@@ -614,7 +616,7 @@ Bits
 mkvar(Reg *r, Adr *a)
 {
        Var *v;
-       int i, t, n, et, z, flag;
+       int i, n, et, z, flag;
        int64 w;
        uint32 regu;
        int64 o;
@@ -624,39 +626,40 @@ mkvar(Reg *r, Adr *a)
        /*
         * mark registers used
         */
-       t = a->type;
-       if(t == D_NONE)
+       if(a->type == TYPE_NONE)
                goto none;
 
        if(r != R)
                r->use1.b[0] |= doregbits(a->index);
 
-       if(t >= D_INDIR && t < 2*D_INDIR)
-               goto none;
-
-       switch(t) {
+       switch(a->type) {
        default:
-               regu = doregbits(t);
+               regu = doregbits(a->reg);
                if(regu == 0)
                        goto none;
                bit = zbits;
                bit.b[0] = regu;
                return bit;
 
-       case D_ADDR:
-               a->type = a->index;
+       case TYPE_ADDR:
+               a->type = TYPE_MEM;
                bit = mkvar(r, a);
                setaddrs(bit);
-               a->type = t;
+               a->type = TYPE_ADDR;
                ostats.naddr++;
                goto none;
 
-       case D_EXTERN:
-       case D_STATIC:
-       case D_PARAM:
-       case D_AUTO:
-               n = t;
-               break;
+       case TYPE_MEM:
+               switch(a->name) {
+               default:
+                       goto none;
+               case NAME_EXTERN:
+               case NAME_STATIC:
+               case NAME_PARAM:
+               case NAME_AUTO:
+                       n = a->name;
+                       break;
+               }
        }
 
        node = a->node;
@@ -730,10 +733,10 @@ mkvar(Reg *r, Adr *a)
        node->opt = v;
 
        bit = blsh(i);
-       if(n == D_EXTERN || n == D_STATIC)
+       if(n == NAME_EXTERN || n == NAME_STATIC)
                for(z=0; z<BITS; z++)
                        externs.b[z] |= bit.b[z];
-       if(n == D_PARAM)
+       if(n == NAME_PARAM)
                for(z=0; z<BITS; z++)
                        params.b[z] |= bit.b[z];
 
@@ -1161,7 +1164,9 @@ addreg(Adr *a, int rn)
        a->sym = nil;
        a->node = nil;
        a->offset = 0;
-       a->type = rn;
+       a->type = TYPE_REG;
+       a->reg = rn;
+       a->name = 0;
 
        ostats.ncvtreg++;
 }
@@ -1170,9 +1175,9 @@ uint32
 RtoB(int r)
 {
 
-       if(r < D_AX || r > D_R15)
+       if(r < REG_AX || r > REG_R15)
                return 0;
-       return 1L << (r-D_AX);
+       return 1L << (r-REG_AX);
 }
 
 int
@@ -1180,10 +1185,13 @@ BtoR(uint32 b)
 {
        b &= 0xffffL;
        if(nacl)
-               b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX)));
+               b &= ~((1<<(REG_BP-REG_AX)) | (1<<(REG_R15-REG_AX)));
+       else if(framepointer_enabled)
+               // BP is part of the calling convention if framepointer_enabled.
+               b &= ~(1<<(REG_BP-REG_AX));
        if(b == 0)
                return 0;
-       return bitno(b) + D_AX;
+       return bitno(b) + REG_AX;
 }
 
 /*
@@ -1195,9 +1203,9 @@ BtoR(uint32 b)
 uint32
 FtoB(int f)
 {
-       if(f < D_X0 || f > D_X15)
+       if(f < REG_X0 || f > REG_X15)
                return 0;
-       return 1L << (f - D_X0 + 16);
+       return 1L << (f - REG_X0 + 16);
 }
 
 int
@@ -1207,7 +1215,7 @@ BtoF(uint32 b)
        b &= 0xFFFF0000L;
        if(b == 0)
                return 0;
-       return bitno(b) - 16 + D_X0;
+       return bitno(b) - 16 + REG_X0;
 }
 
 void
index c09ac282424d543ca59dcaf91464dc189877e271..01d9bb753500b40fed6bcd336655f6449ae969ac 100644 (file)
@@ -38,8 +38,7 @@
 
 enum
 {
-       AXXX,
-       AAAA,
+       AAAA = A_ARCHSPECIFIC,
        AAAD,
        AAAM,
        AAAS,
@@ -69,7 +68,6 @@ enum
        ABTSL,
        ABTSW,
        ABYTE,
-       ACALL,
        ACLC,
        ACLD,
        ACLI,
@@ -83,7 +81,6 @@ enum
        ACMPSW,
        ADAA,
        ADAS,
-       ADATA,
        ADECB,
        ADECL,
        ADECQ,
@@ -92,9 +89,6 @@ enum
        ADIVL,
        ADIVW,
        AENTER,
-       AGLOBL,
-       AGOK,
-       AHISTORY,
        AHLT,
        AIDIVB,
        AIDIVL,
@@ -127,7 +121,6 @@ enum
        AJLS,
        AJLT,
        AJMI,
-       AJMP,
        AJNE,
        AJOC,
        AJOS,
@@ -170,11 +163,9 @@ enum
        AMULB,
        AMULL,
        AMULW,
-       ANAME,
        ANEGB,
        ANEGL,
        ANEGW,
-       ANOP,
        ANOTB,
        ANOTL,
        ANOTW,
@@ -208,7 +199,6 @@ enum
        ARCRW,
        AREP,
        AREPN,
-       ARET,
        AROLB,
        AROLL,
        AROLW,
@@ -265,7 +255,6 @@ enum
        ATESTB,
        ATESTL,
        ATESTW,
-       ATEXT,
        AVERR,
        AVERW,
        AWAIT,
@@ -386,12 +375,8 @@ enum
        AFYL2X,
        AFYL2XP1,
 
-       AEND,
 
-       ADYNT_,
-       AINIT_,
 
-       ASIGNAME,
 
        /* extra 32-bit operations */
        ACMPXCHGB,
@@ -745,7 +730,6 @@ enum
        ABSWAPL,
        ABSWAPQ,
        
-       AUNDEF,
 
        AAESENC,
        AAESENCLAST,
@@ -757,115 +741,102 @@ enum
        APSHUFD,
        APCLMULQDQ,
        
-       AUSEFIELD,
-       ATYPE,
-       AFUNCDATA,
-       APCDATA,
-       ACHECKNIL,
-       AVARDEF,
-       AVARKILL,
-       ADUFFCOPY,
-       ADUFFZERO,
        
        ALAST
 };
 
 enum
 {
+       REG_NONE        = 0,
+
+       REG_AL          = 0+16,
+       REG_CL,
+       REG_DL,
+       REG_BL,
+       REG_SPB,
+       REG_BPB,
+       REG_SIB,
+       REG_DIB,
+       REG_R8B,
+       REG_R9B,
+       REG_R10B,
+       REG_R11B,
+       REG_R12B,
+       REG_R13B,
+       REG_R14B,
+       REG_R15B,
+
+       REG_AX          = 16+16,
+       REG_CX,
+       REG_DX,
+       REG_BX,
+       REG_SP,
+       REG_BP,
+       REG_SI,
+       REG_DI,
+       REG_R8,
+       REG_R9,
+       REG_R10,
+       REG_R11,
+       REG_R12,
+       REG_R13,
+       REG_R14,
+       REG_R15,
+
+       REG_AH          = 32+16,
+       REG_CH,
+       REG_DH,
+       REG_BH,
+
+       REG_F0          = 36+16,
+
+       REG_M0          = 44+16,
+
+       REG_X0          = 52+16,
+       REG_X1,
+       REG_X2,
+       REG_X3,
+       REG_X4,
+       REG_X5,
+       REG_X6,
+       REG_X7,
+       REG_X8,
+       REG_X9,
+       REG_X10,
+       REG_X11,
+       REG_X12,
+       REG_X13,
+       REG_X14,
+       REG_X15,
+
+       REG_CS          = 68+16,
+       REG_SS,
+       REG_DS,
+       REG_ES,
+       REG_FS,
+       REG_GS,
+
+       REG_GDTR,               /* global descriptor table register */
+       REG_IDTR,               /* interrupt descriptor table register */
+       REG_LDTR,               /* local descriptor table register */
+       REG_MSW,                /* machine status word */
+       REG_TASK,               /* task register */
+
+       REG_CR          = 79+16,
+       REG_DR          = 95+16,
+       REG_TR          = 103+16,
+
+       REG_TLS         = 111+16,
+       MAXREG,
 
-       D_AL            = 0,
-       D_CL,
-       D_DL,
-       D_BL,
-       D_SPB,
-       D_BPB,
-       D_SIB,
-       D_DIB,
-       D_R8B,
-       D_R9B,
-       D_R10B,
-       D_R11B,
-       D_R12B,
-       D_R13B,
-       D_R14B,
-       D_R15B,
-
-       D_AX            = 16,
-       D_CX,
-       D_DX,
-       D_BX,
-       D_SP,
-       D_BP,
-       D_SI,
-       D_DI,
-       D_R8,
-       D_R9,
-       D_R10,
-       D_R11,
-       D_R12,
-       D_R13,
-       D_R14,
-       D_R15,
-
-       D_AH            = 32,
-       D_CH,
-       D_DH,
-       D_BH,
-
-       D_F0            = 36,
-
-       D_M0            = 44,
-
-       D_X0            = 52,
-       D_X1,
-       D_X2,
-       D_X3,
-       D_X4,
-       D_X5,
-       D_X6,
-       D_X7,
-       D_X8,
-       D_X9,
-       D_X10,
-       D_X11,
-       D_X12,
-       D_X13,
-       D_X14,
-       D_X15,
-
-       D_CS            = 68,
-       D_SS,
-       D_DS,
-       D_ES,
-       D_FS,
-       D_GS,
-
-       D_GDTR,         /* global descriptor table register */
-       D_IDTR,         /* interrupt descriptor table register */
-       D_LDTR,         /* local descriptor table register */
-       D_MSW,          /* machine status word */
-       D_TASK,         /* task register */
-
-       D_CR            = 79,
-       D_DR            = 95,
-       D_TR            = 103,
-
-       D_TLS           = 111,
-       D_NONE          = 112,
-
-       D_BRANCH        = 113,
-       D_EXTERN        = 114,
-       D_STATIC        = 115,
-       D_AUTO          = 116,
-       D_PARAM         = 117,
-       D_CONST         = 118,
-       D_FCONST        = 119,
-       D_SCONST        = 120,
-       D_ADDR          = 121,
-
-       D_INDIR,        /* additive */
-
-       D_LAST,
+       REGARG          = -1,
+       REGRET          = REG_AX,
+       FREGRET         = REG_X0,
+       REGSP           = REG_SP,
+       REGTMP          = REG_DI,
+       REGEXT          = REG_R15,      /* compiler allocates external registers R15 down */
+       FREGMIN         = REG_X0+5,     /* first register variable */
+       FREGEXT         = REG_X0+15,    /* first external register */
 
        T_TYPE          = 1<<0,
        T_INDEX         = 1<<1,
@@ -875,15 +846,6 @@ enum
        T_SCONST        = 1<<5,
        T_64            = 1<<6,
        T_GOTYPE        = 1<<7,
-
-       REGARG          = -1,
-       REGRET          = D_AX,
-       FREGRET         = D_X0,
-       REGSP           = D_SP,
-       REGTMP          = D_DI,
-       REGEXT          = D_R15,        /* compiler allocates external registers R15 down */
-       FREGMIN         = D_X0+5,       /* first register variable */
-       FREGEXT         = D_X0+15       /* first external register */
 };
 
 /*
index a1aca07aea7445458bcbed85d6f6c71d17925901..24654b0ab848ea6cc2c8d8018073cbf8cd3b3d20 100644 (file)
@@ -139,6 +139,7 @@ EXTERN      int32   thunk;
 EXTERN Biobuf  obuf;
 EXTERN Link*   ctxt;
 EXTERN Biobuf  bstdout;
+EXTERN Prog*   lastpc;
 
 void*  alloc(int32);
 void*  allocn(void*, int32, int32);
index c810d385779d4ddb8ad4061688bff0c51bfe6434..1a3ab72ff21ba793d65032e7a3d3b38878f86f16 100644 (file)
 %union {
        Sym     *sym;
        int32   lval;
-       struct {
-               int32 v1;
-               int32 v2;
-       } con2;
        double  dval;
        char    sval[8];
        Addr    addr;
 %token <sval>  LSCONST LSP
 %token <sym>   LNAME LLAB LVAR
 %type  <lval>  con expr pointer offset
-%type  <con2>  con2
-%type  <addr>  mem imm imm2 reg nam rel rem rim rom omem nmem
+%type  <addr>  mem imm reg nam rel rem rim rom omem nmem textsize
 %type  <addr2> nonnon nonrel nonrem rimnon rimrem remrim
-%type  <addr2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10 spec11 spec12
+%type  <addr2> spec3 spec4 spec5 spec6 spec7 spec9 spec10 spec11 spec12
 %%
 prog:
 |      prog
@@ -105,14 +100,14 @@ inst:
 |      LTYPE3 rimrem   { outcode($1, &$2); }
 |      LTYPE4 remrim   { outcode($1, &$2); }
 |      LTYPER nonrel   { outcode($1, &$2); }
-|      LTYPED spec1    { outcode($1, &$2); }
-|      LTYPET spec2    { outcode($1, &$2); }
+|      spec1
+|      spec2
 |      LTYPEC spec3    { outcode($1, &$2); }
 |      LTYPEN spec4    { outcode($1, &$2); }
 |      LTYPES spec5    { outcode($1, &$2); }
 |      LTYPEM spec6    { outcode($1, &$2); }
 |      LTYPEI spec7    { outcode($1, &$2); }
-|      LTYPEG spec8    { outcode($1, &$2); }
+|      spec8
 |      LTYPEXC spec9   { outcode($1, &$2); }
 |      LTYPEX spec10   { outcode($1, &$2); }
 |      LTYPEPC spec11  { outcode($1, &$2); }
@@ -185,26 +180,60 @@ nonrel:
        }
 
 spec1: /* DATA */
-       nam '/' con ',' imm
+       LTYPED nam '/' con ',' imm
        {
-               $$.from = $1;
-               $$.from.scale = $3;
-               $$.to = $5;
+               Addr2 a;
+               a.from = $2;
+               a.to = $6;
+               outcode(ADATA, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
 
 spec2: /* TEXT */
-       mem ',' imm2
+       LTYPET mem ',' '$' textsize
        {
-               settext($1.sym);
-               $$.from = $1;
-               $$.to = $3;
+               Addr2 a;
+               settext($2.sym);
+               a.from = $2;
+               a.to = $5;
+               outcode(ATEXT, &a);
        }
-|      mem ',' con ',' imm2
+|      LTYPET mem ',' con ',' '$' textsize
        {
-               settext($1.sym);
-               $$.from = $1;
-               $$.from.scale = $3;
-               $$.to = $5;
+               Addr2 a;
+               settext($2.sym);
+               a.from = $2;
+               a.to = $7;
+               outcode(ATEXT, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
+       }
+
+spec8: /* GLOBL */
+       LTYPEG mem ',' imm
+       {
+               Addr2 a;
+               settext($2.sym);
+               a.from = $2;
+               a.to = $4;
+               outcode(AGLOBL, &a);
+       }
+|      LTYPEG mem ',' con ',' imm
+       {
+               Addr2 a;
+               settext($2.sym);
+               a.from = $2;
+               a.to = $6;
+               outcode(AGLOBL, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
 
 spec3: /* JMP/CALL */
@@ -222,8 +251,7 @@ spec3:      /* JMP/CALL */
        {
                $$.from = nullgen;
                $$.to = $2;
-               $$.to.index = $2.type;
-               $$.to.type = D_INDIR+D_ADDR;
+               $$.to.type = TYPE_INDIR;
        }
 
 spec4: /* NOP */
@@ -240,7 +268,7 @@ spec5:      /* SHL/SHR */
        {
                $$.from = $1;
                $$.to = $3;
-               if($$.from.index != D_NONE)
+               if($$.from.index != TYPE_NONE)
                        yyerror("dp shift with lhs index");
                $$.from.index = $5;
        }
@@ -255,7 +283,7 @@ spec6:      /* MOVW/MOVL */
        {
                $$.from = $1;
                $$.to = $3;
-               if($$.to.index != D_NONE)
+               if($$.to.index != TYPE_NONE)
                        yyerror("dp move with lhs index");
                $$.to.index = $5;
        }
@@ -277,19 +305,6 @@ spec7:
                $$.to = $3;
        }
 
-spec8: /* GLOBL */
-       mem ',' imm
-       {
-               $$.from = $1;
-               $$.to = $3;
-       }
-|      mem ',' con ',' imm
-       {
-               $$.from = $1;
-               $$.from.scale = $3;
-               $$.to = $5;
-       }
-
 spec9: /* CMPPS/CMPPD */
        reg ',' rem ',' con
        {
@@ -303,7 +318,7 @@ spec10:     /* PINSRD */
        {
                $$.from = $3;
                $$.to = $5;
-               if($1.type != D_CONST)
+               if($1.type != TYPE_CONST)
                        yyerror("illegal constant");
                $$.to.offset = $1.offset;
        }
@@ -311,7 +326,7 @@ spec10:     /* PINSRD */
 spec11:        /* PCDATA */
        rim ',' rim
        {
-               if($1.type != D_CONST || $3.type != D_CONST)
+               if($1.type != TYPE_CONST || $3.type != TYPE_CONST)
                        yyerror("arguments to PCDATA must be integer constants");
                $$.from = $1;
                $$.to = $3;
@@ -320,9 +335,9 @@ spec11:     /* PCDATA */
 spec12:        /* FUNCDATA */
        rim ',' rim
        {
-               if($1.type != D_CONST)
+               if($1.type != TYPE_CONST)
                        yyerror("index for FUNCDATA must be integer constant");
-               if($3.type != D_EXTERN && $3.type != D_STATIC)
+               if($3.type != TYPE_MEM || ($3.name != NAME_EXTERN && $3.name != NAME_STATIC))
                        yyerror("value for FUNCDATA must be symbol reference");
                $$.from = $1;
                $$.to = $3;
@@ -355,7 +370,7 @@ rel:
        con '(' LPC ')'
        {
                $$ = nullgen;
-               $$.type = D_BRANCH;
+               $$.type = TYPE_BRANCH;
                $$.offset = $1 + pc;
        }
 |      LNAME offset
@@ -364,7 +379,7 @@ rel:
                $$ = nullgen;
                if(pass == 2 && $1->type != LLAB)
                        yyerror("undefined label: %s", $1->labelname);
-               $$.type = D_BRANCH;
+               $$.type = TYPE_BRANCH;
                $$.offset = $1->value + $2;
        }
 
@@ -372,48 +387,53 @@ reg:
        LBREG
        {
                $$ = nullgen;
-               $$.type = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 |      LFREG
        {
                $$ = nullgen;
-               $$.type = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 |      LLREG
        {
                $$ = nullgen;
-               $$.type = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 |      LXREG
        {
                $$ = nullgen;
-               $$.type = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 |      LSP
        {
                $$ = nullgen;
-               $$.type = D_SP;
+               $$.type = TYPE_REG;
+               $$.reg = REG_SP;
        }
 |      LSREG
        {
                $$ = nullgen;
-               $$.type = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 
 imm:
        '$' con
        {
                $$ = nullgen;
-               $$.type = D_CONST;
+               $$.type = TYPE_CONST;
                $$.offset = $2;
        }
 |      '$' nam
        {
                $$ = $2;
-               $$.index = $2.type;
-               $$.type = D_ADDR;
+               $$.type = TYPE_ADDR;
                /*
-               if($2.type == D_AUTO || $2.type == D_PARAM)
+               if($2.name == NAME_AUTO || $2.name == NAME_PARAM)
                        yyerror("constant cannot be automatic: %s",
                                $2.sym->name);
                 */
@@ -421,63 +441,62 @@ imm:
 |      '$' LSCONST
        {
                $$ = nullgen;
-               $$.type = D_SCONST;
+               $$.type = TYPE_SCONST;
                memcpy($$.u.sval, $2, sizeof($$.u.sval));
        }
 |      '$' LFCONST
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = $2;
        }
 |      '$' '(' LFCONST ')'
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = $3;
        }
 |      '$' '(' '-' LFCONST ')'
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = -$4;
        }
 |      '$' '-' LFCONST
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = -$3;
        }
 
-imm2:
-       '$' con2
-       {
-               $$ = nullgen;
-               $$.type = D_CONST2;
-               $$.offset = $2.v1;
-               $$.offset2 = $2.v2;
-       }
-
-con2:
+textsize:
        LCONST
        {
-               $$.v1 = $1;
-               $$.v2 = ArgsSizeUnknown;
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = $1;
+               $$.u.argsize = ArgsSizeUnknown;
        }
 |      '-' LCONST
        {
-               $$.v1 = -$2;
-               $$.v2 = ArgsSizeUnknown;
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = -$2;
+               $$.u.argsize = ArgsSizeUnknown;
        }
 |      LCONST '-' LCONST
        {
-               $$.v1 = $1;
-               $$.v2 = $3;
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = $1;
+               $$.u.argsize = $3;
        }
 |      '-' LCONST '-' LCONST
        {
-               $$.v1 = -$2;
-               $$.v2 = $4;
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = -$2;
+               $$.u.argsize = $4;
        }
 
 mem:
@@ -488,25 +507,29 @@ omem:
        con
        {
                $$ = nullgen;
-               $$.type = D_INDIR+D_NONE;
+               $$.type = TYPE_MEM;
+               $$.reg = REG_NONE;
                $$.offset = $1;
        }
 |      con '(' LLREG ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$3;
+               $$.type = TYPE_MEM;
+               $$.reg = $3;
                $$.offset = $1;
        }
 |      con '(' LSP ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+D_SP;
+               $$.type = TYPE_MEM;
+               $$.reg = REG_SP;
                $$.offset = $1;
        }
 |      con '(' LLREG '*' con ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+D_NONE;
+               $$.type = TYPE_MEM;
+               $$.reg = REG_NONE;
                $$.offset = $1;
                $$.index = $3;
                $$.scale = $5;
@@ -515,7 +538,8 @@ omem:
 |      con '(' LLREG ')' '(' LLREG '*' con ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$3;
+               $$.type = TYPE_MEM;
+               $$.reg = $3;
                $$.offset = $1;
                $$.index = $6;
                $$.scale = $8;
@@ -524,7 +548,8 @@ omem:
 |      con '(' LLREG ')' '(' LSREG '*' con ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$3;
+               $$.type = TYPE_MEM;
+               $$.reg = $3;
                $$.offset = $1;
                $$.index = $6;
                $$.scale = $8;
@@ -533,23 +558,27 @@ omem:
 |      '(' LLREG ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$2;
+               $$.type = TYPE_MEM;
+               $$.reg = $2;
        }
 |      '(' LSP ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+D_SP;
+               $$.type = TYPE_MEM;
+               $$.reg = REG_SP;
        }
 |      con '(' LSREG ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$3;
+               $$.type = TYPE_MEM;
+               $$.reg = $3;
                $$.offset = $1;
        }
 |      '(' LLREG '*' con ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+D_NONE;
+               $$.type = TYPE_MEM;
+               $$.reg = REG_NONE;
                $$.index = $2;
                $$.scale = $4;
                checkscale($$.scale);
@@ -557,7 +586,8 @@ omem:
 |      '(' LLREG ')' '(' LLREG '*' con ')'
        {
                $$ = nullgen;
-               $$.type = D_INDIR+$2;
+               $$.type = TYPE_MEM;
+               $$.reg = $2;
                $$.index = $5;
                $$.scale = $7;
                checkscale($$.scale);
@@ -580,14 +610,16 @@ nam:
        LNAME offset '(' pointer ')'
        {
                $$ = nullgen;
-               $$.type = $4;
+               $$.type = TYPE_MEM;
+               $$.name = $4;
                $$.sym = linklookup(ctxt, $1->name, 0);
                $$.offset = $2;
        }
 |      LNAME '<' '>' offset '(' LSB ')'
        {
                $$ = nullgen;
-               $$.type = D_STATIC;
+               $$.type = TYPE_MEM;
+               $$.name = NAME_STATIC;
                $$.sym = linklookup(ctxt, $1->name, 1);
                $$.offset = $4;
        }
@@ -609,7 +641,7 @@ pointer:
        LSB
 |      LSP
        {
-               $$ = D_AUTO;
+               $$ = NAME_AUTO;
        }
 |      LFP
 
index 49a58c630d320158089c0596bde2dd813400f081..846f6c6dafbe311bd9a9824bda4c95f561d2c580 100644 (file)
@@ -192,87 +192,88 @@ struct
        ushort  value;
 } itab[] =
 {
-       "SP",           LSP,    D_AUTO,
-       "SB",           LSB,    D_EXTERN,
-       "FP",           LFP,    D_PARAM,
-       "PC",           LPC,    D_BRANCH,
-
-       "AL",           LBREG,  D_AL,
-       "CL",           LBREG,  D_CL,
-       "DL",           LBREG,  D_DL,
-       "BL",           LBREG,  D_BL,
-       "AH",           LBREG,  D_AH,
-       "CH",           LBREG,  D_CH,
-       "DH",           LBREG,  D_DH,
-       "BH",           LBREG,  D_BH,
-
-       "AX",           LLREG,  D_AX,
-       "CX",           LLREG,  D_CX,
-       "DX",           LLREG,  D_DX,
-       "BX",           LLREG,  D_BX,
-/*     "SP",           LLREG,  D_SP,   */
-       "BP",           LLREG,  D_BP,
-       "SI",           LLREG,  D_SI,
-       "DI",           LLREG,  D_DI,
-
-       "F0",           LFREG,  D_F0+0,
-       "F1",           LFREG,  D_F0+1,
-       "F2",           LFREG,  D_F0+2,
-       "F3",           LFREG,  D_F0+3,
-       "F4",           LFREG,  D_F0+4,
-       "F5",           LFREG,  D_F0+5,
-       "F6",           LFREG,  D_F0+6,
-       "F7",           LFREG,  D_F0+7,
-
-       "X0",           LXREG,  D_X0+0,
-       "X1",           LXREG,  D_X0+1,
-       "X2",           LXREG,  D_X0+2,
-       "X3",           LXREG,  D_X0+3,
-       "X4",           LXREG,  D_X0+4,
-       "X5",           LXREG,  D_X0+5,
-       "X6",           LXREG,  D_X0+6,
-       "X7",           LXREG,  D_X0+7,
-
-       "CS",           LSREG,  D_CS,
-       "SS",           LSREG,  D_SS,
-       "DS",           LSREG,  D_DS,
-       "ES",           LSREG,  D_ES,
-       "FS",           LSREG,  D_FS,
-       "GS",           LSREG,  D_GS,
-       "TLS",          LSREG,  D_TLS,
-
-       "GDTR",         LBREG,  D_GDTR,
-       "IDTR",         LBREG,  D_IDTR,
-       "LDTR",         LBREG,  D_LDTR,
-       "MSW",          LBREG,  D_MSW,
-       "TASK",         LBREG,  D_TASK,
-
-       "CR0",          LBREG,  D_CR+0,
-       "CR1",          LBREG,  D_CR+1,
-       "CR2",          LBREG,  D_CR+2,
-       "CR3",          LBREG,  D_CR+3,
-       "CR4",          LBREG,  D_CR+4,
-       "CR5",          LBREG,  D_CR+5,
-       "CR6",          LBREG,  D_CR+6,
-       "CR7",          LBREG,  D_CR+7,
-
-       "DR0",          LBREG,  D_DR+0,
-       "DR1",          LBREG,  D_DR+1,
-       "DR2",          LBREG,  D_DR+2,
-       "DR3",          LBREG,  D_DR+3,
-       "DR4",          LBREG,  D_DR+4,
-       "DR5",          LBREG,  D_DR+5,
-       "DR6",          LBREG,  D_DR+6,
-       "DR7",          LBREG,  D_DR+7,
-
-       "TR0",          LBREG,  D_TR+0,
-       "TR1",          LBREG,  D_TR+1,
-       "TR2",          LBREG,  D_TR+2,
-       "TR3",          LBREG,  D_TR+3,
-       "TR4",          LBREG,  D_TR+4,
-       "TR5",          LBREG,  D_TR+5,
-       "TR6",          LBREG,  D_TR+6,
-       "TR7",          LBREG,  D_TR+7,
+       "SP",           LSP,    NAME_AUTO,
+       "SB",           LSB,    NAME_EXTERN,
+       "FP",           LFP,    NAME_PARAM,
+
+       "PC",           LPC,    TYPE_BRANCH,
+
+       "AL",           LBREG,  REG_AL,
+       "CL",           LBREG,  REG_CL,
+       "DL",           LBREG,  REG_DL,
+       "BL",           LBREG,  REG_BL,
+       "AH",           LBREG,  REG_AH,
+       "CH",           LBREG,  REG_CH,
+       "DH",           LBREG,  REG_DH,
+       "BH",           LBREG,  REG_BH,
+
+       "AX",           LLREG,  REG_AX,
+       "CX",           LLREG,  REG_CX,
+       "DX",           LLREG,  REG_DX,
+       "BX",           LLREG,  REG_BX,
+/*     "SP",           LLREG,  REG_SP, */
+       "BP",           LLREG,  REG_BP,
+       "SI",           LLREG,  REG_SI,
+       "DI",           LLREG,  REG_DI,
+
+       "F0",           LFREG,  REG_F0+0,
+       "F1",           LFREG,  REG_F0+1,
+       "F2",           LFREG,  REG_F0+2,
+       "F3",           LFREG,  REG_F0+3,
+       "F4",           LFREG,  REG_F0+4,
+       "F5",           LFREG,  REG_F0+5,
+       "F6",           LFREG,  REG_F0+6,
+       "F7",           LFREG,  REG_F0+7,
+
+       "X0",           LXREG,  REG_X0+0,
+       "X1",           LXREG,  REG_X0+1,
+       "X2",           LXREG,  REG_X0+2,
+       "X3",           LXREG,  REG_X0+3,
+       "X4",           LXREG,  REG_X0+4,
+       "X5",           LXREG,  REG_X0+5,
+       "X6",           LXREG,  REG_X0+6,
+       "X7",           LXREG,  REG_X0+7,
+
+       "CS",           LSREG,  REG_CS,
+       "SS",           LSREG,  REG_SS,
+       "DS",           LSREG,  REG_DS,
+       "ES",           LSREG,  REG_ES,
+       "FS",           LSREG,  REG_FS,
+       "GS",           LSREG,  REG_GS,
+       "TLS",          LSREG,  REG_TLS,
+
+       "GDTR",         LBREG,  REG_GDTR,
+       "IDTR",         LBREG,  REG_IDTR,
+       "LDTR",         LBREG,  REG_LDTR,
+       "MSW",          LBREG,  REG_MSW,
+       "TASK",         LBREG,  REG_TASK,
+
+       "CR0",          LBREG,  REG_CR+0,
+       "CR1",          LBREG,  REG_CR+1,
+       "CR2",          LBREG,  REG_CR+2,
+       "CR3",          LBREG,  REG_CR+3,
+       "CR4",          LBREG,  REG_CR+4,
+       "CR5",          LBREG,  REG_CR+5,
+       "CR6",          LBREG,  REG_CR+6,
+       "CR7",          LBREG,  REG_CR+7,
+
+       "DR0",          LBREG,  REG_DR+0,
+       "DR1",          LBREG,  REG_DR+1,
+       "DR2",          LBREG,  REG_DR+2,
+       "DR3",          LBREG,  REG_DR+3,
+       "DR4",          LBREG,  REG_DR+4,
+       "DR5",          LBREG,  REG_DR+5,
+       "DR6",          LBREG,  REG_DR+6,
+       "DR7",          LBREG,  REG_DR+7,
+
+       "TR0",          LBREG,  REG_TR+0,
+       "TR1",          LBREG,  REG_TR+1,
+       "TR2",          LBREG,  REG_TR+2,
+       "TR3",          LBREG,  REG_TR+3,
+       "TR4",          LBREG,  REG_TR+4,
+       "TR5",          LBREG,  REG_TR+5,
+       "TR6",          LBREG,  REG_TR+6,
+       "TR7",          LBREG,  REG_TR+7,
 
        "AAA",          LTYPE0, AAAA,
        "AAD",          LTYPE0, AAAD,
@@ -829,8 +830,8 @@ cinit(void)
        Sym *s;
        int i;
 
-       nullgen.type = D_NONE;
-       nullgen.index = D_NONE;
+       nullgen.type = TYPE_NONE;
+       nullgen.index = TYPE_NONE;
 
        nerrors = 0;
        iostack = I;
@@ -880,8 +881,6 @@ cclean(void)
        outcode(AEND, &g2);
 }
 
-static Prog *lastpc;
-
 void
 outcode(int a, Addr2 *g2)
 {
index f284d8ea2eca10f7cf7b97b22c61bdda5f9820a8..d80f0ee4de72b02f9cd1ab990e64c7388bdb2ddc 100644 (file)
@@ -173,17 +173,13 @@ typedef union YYSTYPE
 {
        Sym     *sym;
        int32   lval;
-       struct {
-               int32 v1;
-               int32 v2;
-       } con2;
        double  dval;
        char    sval[8];
        Addr    addr;
        Addr2   addr2;
 }
 /* Line 193 of yacc.c.  */
-#line 187 "y.tab.c"
+#line 183 "y.tab.c"
        YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -196,7 +192,7 @@ typedef union YYSTYPE
 
 
 /* Line 216 of yacc.c.  */
-#line 200 "y.tab.c"
+#line 196 "y.tab.c"
 
 #ifdef short
 # undef short
@@ -411,14 +407,14 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  2
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   561
+#define YYLAST   544
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  54
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  40
+#define YYNNTS  39
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  132
+#define YYNRULES  131
 /* YYNRULES -- Number of states.  */
 #define YYNSTATES  270
 
@@ -435,8 +431,8 @@ static const yytype_uint8 yytranslate[] =
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,    52,    12,     5,     2,
-      50,    51,    10,     8,    49,     9,     2,    11,     2,     2,
+       2,     2,     2,     2,     2,     2,    50,    12,     5,     2,
+      51,    52,    10,     8,    49,     9,     2,    11,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,    46,    47,
        6,    48,     7,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -470,19 +466,19 @@ static const yytype_uint8 yytranslate[] =
 static const yytype_uint16 yyprhs[] =
 {
        0,     0,     3,     4,     5,     9,    10,    15,    17,    20,
-      23,    27,    31,    34,    37,    40,    43,    46,    49,    52,
-      55,    58,    61,    64,    67,    70,    73,    76,    79,    82,
-      85,    86,    88,    92,    96,    99,   101,   104,   106,   109,
-     111,   115,   121,   125,   131,   134,   136,   139,   141,   143,
-     147,   153,   157,   163,   166,   168,   172,   176,   182,   188,
-     194,   198,   202,   204,   206,   208,   210,   213,   216,   218,
-     220,   222,   224,   226,   231,   234,   236,   238,   240,   242,
-     244,   246,   249,   252,   255,   258,   263,   269,   273,   276,
-     278,   281,   285,   290,   292,   294,   296,   301,   306,   313,
-     323,   333,   337,   341,   346,   352,   361,   363,   370,   376,
-     384,   385,   388,   391,   393,   395,   397,   399,   401,   404,
-     407,   410,   414,   416,   420,   424,   428,   432,   436,   441,
-     446,   450,   454
+      23,    27,    31,    34,    37,    40,    43,    46,    49,    51,
+      53,    56,    59,    62,    65,    68,    70,    73,    76,    79,
+      82,    83,    85,    89,    93,    96,    98,   101,   103,   106,
+     108,   112,   119,   125,   133,   138,   145,   148,   150,   153,
+     155,   157,   161,   167,   171,   177,   180,   182,   186,   192,
+     198,   202,   206,   208,   210,   212,   214,   217,   220,   222,
+     224,   226,   228,   230,   235,   238,   240,   242,   244,   246,
+     248,   250,   253,   256,   259,   262,   267,   273,   277,   279,
+     282,   286,   291,   293,   295,   297,   302,   307,   314,   324,
+     334,   338,   342,   347,   353,   362,   364,   371,   377,   385,
+     386,   389,   392,   394,   396,   398,   400,   402,   405,   408,
+     411,   415,   417,   421,   425,   429,   433,   437,   442,   447,
+     451,   455
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
@@ -490,69 +486,69 @@ static const yytype_int8 yyrhs[] =
 {
       55,     0,    -1,    -1,    -1,    55,    56,    57,    -1,    -1,
       43,    46,    58,    57,    -1,    47,    -1,    59,    47,    -1,
-       1,    47,    -1,    43,    48,    93,    -1,    45,    48,    93,
+       1,    47,    -1,    43,    48,    92,    -1,    45,    48,    92,
       -1,    13,    60,    -1,    14,    64,    -1,    15,    63,    -1,
-      16,    61,    -1,    17,    62,    -1,    21,    65,    -1,    19,
-      66,    -1,    22,    67,    -1,    18,    68,    -1,    20,    69,
-      -1,    23,    70,    -1,    24,    71,    -1,    25,    72,    -1,
-      26,    73,    -1,    27,    74,    -1,    28,    75,    -1,    29,
-      76,    -1,    30,    77,    -1,    -1,    49,    -1,    80,    49,
-      78,    -1,    78,    49,    80,    -1,    80,    49,    -1,    80,
-      -1,    49,    78,    -1,    78,    -1,    49,    81,    -1,    81,
-      -1,    83,    49,    81,    -1,    89,    11,    92,    49,    83,
-      -1,    86,    49,    84,    -1,    86,    49,    92,    49,    84,
-      -1,    49,    79,    -1,    79,    -1,    10,    89,    -1,    60,
-      -1,    64,    -1,    80,    49,    78,    -1,    80,    49,    78,
-      46,    36,    -1,    80,    49,    78,    -1,    80,    49,    78,
-      46,    37,    -1,    80,    49,    -1,    80,    -1,    80,    49,
-      78,    -1,    86,    49,    83,    -1,    86,    49,    92,    49,
-      83,    -1,    82,    49,    78,    49,    92,    -1,    83,    49,
-      78,    49,    82,    -1,    80,    49,    80,    -1,    80,    49,
-      80,    -1,    82,    -1,    86,    -1,    81,    -1,    88,    -1,
-      10,    82,    -1,    10,    87,    -1,    82,    -1,    87,    -1,
-      83,    -1,    78,    -1,    83,    -1,    92,    50,    33,    51,
-      -1,    43,    90,    -1,    35,    -1,    38,    -1,    36,    -1,
-      39,    -1,    42,    -1,    37,    -1,    52,    92,    -1,    52,
-      89,    -1,    52,    41,    -1,    52,    40,    -1,    52,    50,
-      40,    51,    -1,    52,    50,     9,    40,    51,    -1,    52,
-       9,    40,    -1,    52,    85,    -1,    31,    -1,     9,    31,
-      -1,    31,     9,    31,    -1,     9,    31,     9,    31,    -1,
-      87,    -1,    88,    -1,    92,    -1,    92,    50,    36,    51,
-      -1,    92,    50,    42,    51,    -1,    92,    50,    36,    10,
-      92,    51,    -1,    92,    50,    36,    51,    50,    36,    10,
-      92,    51,    -1,    92,    50,    36,    51,    50,    37,    10,
-      92,    51,    -1,    50,    36,    51,    -1,    50,    42,    51,
-      -1,    92,    50,    37,    51,    -1,    50,    36,    10,    92,
-      51,    -1,    50,    36,    51,    50,    36,    10,    92,    51,
-      -1,    89,    -1,    89,    50,    36,    10,    92,    51,    -1,
-      43,    90,    50,    91,    51,    -1,    43,     6,     7,    90,
-      50,    34,    51,    -1,    -1,     8,    92,    -1,     9,    92,
-      -1,    34,    -1,    42,    -1,    32,    -1,    31,    -1,    45,
-      -1,     9,    92,    -1,     8,    92,    -1,    53,    92,    -1,
-      50,    93,    51,    -1,    92,    -1,    93,     8,    93,    -1,
-      93,     9,    93,    -1,    93,    10,    93,    -1,    93,    11,
-      93,    -1,    93,    12,    93,    -1,    93,     6,     6,    93,
-      -1,    93,     7,     7,    93,    -1,    93,     5,    93,    -1,
-      93,     4,    93,    -1,    93,     3,    93,    -1
+      16,    61,    -1,    17,    62,    -1,    21,    65,    -1,    66,
+      -1,    67,    -1,    18,    69,    -1,    20,    70,    -1,    23,
+      71,    -1,    24,    72,    -1,    25,    73,    -1,    68,    -1,
+      27,    74,    -1,    28,    75,    -1,    29,    76,    -1,    30,
+      77,    -1,    -1,    49,    -1,    80,    49,    78,    -1,    78,
+      49,    80,    -1,    80,    49,    -1,    80,    -1,    49,    78,
+      -1,    78,    -1,    49,    81,    -1,    81,    -1,    83,    49,
+      81,    -1,    19,    88,    11,    91,    49,    83,    -1,    22,
+      85,    49,    50,    84,    -1,    22,    85,    49,    91,    49,
+      50,    84,    -1,    26,    85,    49,    83,    -1,    26,    85,
+      49,    91,    49,    83,    -1,    49,    79,    -1,    79,    -1,
+      10,    88,    -1,    60,    -1,    64,    -1,    80,    49,    78,
+      -1,    80,    49,    78,    46,    36,    -1,    80,    49,    78,
+      -1,    80,    49,    78,    46,    37,    -1,    80,    49,    -1,
+      80,    -1,    80,    49,    78,    -1,    82,    49,    78,    49,
+      91,    -1,    83,    49,    78,    49,    82,    -1,    80,    49,
+      80,    -1,    80,    49,    80,    -1,    82,    -1,    85,    -1,
+      81,    -1,    87,    -1,    10,    82,    -1,    10,    86,    -1,
+      82,    -1,    86,    -1,    83,    -1,    78,    -1,    83,    -1,
+      91,    51,    33,    52,    -1,    43,    89,    -1,    35,    -1,
+      38,    -1,    36,    -1,    39,    -1,    42,    -1,    37,    -1,
+      50,    91,    -1,    50,    88,    -1,    50,    41,    -1,    50,
+      40,    -1,    50,    51,    40,    52,    -1,    50,    51,     9,
+      40,    52,    -1,    50,     9,    40,    -1,    31,    -1,     9,
+      31,    -1,    31,     9,    31,    -1,     9,    31,     9,    31,
+      -1,    86,    -1,    87,    -1,    91,    -1,    91,    51,    36,
+      52,    -1,    91,    51,    42,    52,    -1,    91,    51,    36,
+      10,    91,    52,    -1,    91,    51,    36,    52,    51,    36,
+      10,    91,    52,    -1,    91,    51,    36,    52,    51,    37,
+      10,    91,    52,    -1,    51,    36,    52,    -1,    51,    42,
+      52,    -1,    91,    51,    37,    52,    -1,    51,    36,    10,
+      91,    52,    -1,    51,    36,    52,    51,    36,    10,    91,
+      52,    -1,    88,    -1,    88,    51,    36,    10,    91,    52,
+      -1,    43,    89,    51,    90,    52,    -1,    43,     6,     7,
+      89,    51,    34,    52,    -1,    -1,     8,    91,    -1,     9,
+      91,    -1,    34,    -1,    42,    -1,    32,    -1,    31,    -1,
+      45,    -1,     9,    91,    -1,     8,    91,    -1,    53,    91,
+      -1,    51,    92,    52,    -1,    91,    -1,    92,     8,    92,
+      -1,    92,     9,    92,    -1,    92,    10,    92,    -1,    92,
+      11,    92,    -1,    92,    12,    92,    -1,    92,     6,     6,
+      92,    -1,    92,     7,     7,    92,    -1,    92,     5,    92,
+      -1,    92,     4,    92,    -1,    92,     3,    92,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,    69,    69,    71,    70,    78,    77,    86,    87,    88,
-      91,    96,   102,   103,   104,   105,   106,   107,   108,   109,
-     110,   111,   112,   113,   114,   115,   116,   117,   118,   119,
-     122,   126,   133,   140,   147,   152,   159,   164,   171,   176,
-     181,   188,   196,   202,   211,   216,   221,   230,   231,   234,
-     239,   249,   254,   264,   269,   274,   281,   286,   294,   302,
-     312,   321,   332,   333,   336,   337,   338,   342,   346,   347,
-     348,   351,   352,   355,   361,   372,   377,   382,   387,   392,
-     397,   404,   410,   421,   427,   433,   439,   445,   453,   462,
-     467,   472,   477,   484,   485,   488,   494,   500,   506,   515,
-     524,   533,   538,   543,   549,   557,   567,   571,   580,   587,
-     596,   599,   603,   609,   610,   614,   617,   618,   622,   626,
-     630,   634,   640,   641,   645,   649,   653,   657,   661,   665,
-     669,   673,   677
+       0,    64,    64,    66,    65,    73,    72,    81,    82,    83,
+      86,    91,    97,    98,    99,   100,   101,   102,   103,   104,
+     105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
+     117,   121,   128,   135,   142,   147,   154,   159,   166,   171,
+     176,   183,   196,   204,   218,   226,   240,   245,   250,   258,
+     259,   262,   267,   277,   282,   292,   297,   302,   309,   317,
+     327,   336,   347,   348,   351,   352,   353,   357,   361,   362,
+     363,   366,   367,   370,   376,   387,   393,   399,   405,   411,
+     417,   425,   431,   441,   447,   453,   459,   465,   473,   480,
+     487,   494,   503,   504,   507,   514,   521,   528,   538,   548,
+     558,   564,   570,   577,   586,   597,   601,   610,   618,   628,
+     631,   635,   641,   642,   646,   649,   650,   654,   658,   662,
+     666,   672,   673,   677,   681,   685,   689,   693,   697,   701,
+     705,   709
 };
 #endif
 
@@ -567,12 +563,12 @@ static const char *const yytname[] =
   "LTYPEM", "LTYPEI", "LTYPEG", "LTYPEXC", "LTYPEX", "LTYPEPC", "LTYPEF",
   "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG", "LFREG",
   "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB", "LVAR", "':'",
-  "';'", "'='", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog", "@1",
+  "';'", "'='", "','", "'$'", "'('", "')'", "'~'", "$accept", "prog", "@1",
   "line", "@2", "inst", "nonnon", "rimrem", "remrim", "rimnon", "nonrem",
-  "nonrel", "spec1", "spec2", "spec3", "spec4", "spec5", "spec6", "spec7",
-  "spec8", "spec9", "spec10", "spec11", "spec12", "rem", "rom", "rim",
-  "rel", "reg", "imm", "imm2", "con2", "mem", "omem", "nmem", "nam",
-  "offset", "pointer", "con", "expr", 0
+  "nonrel", "spec1", "spec2", "spec8", "spec3", "spec4", "spec5", "spec6",
+  "spec7", "spec9", "spec10", "spec11", "spec12", "rem", "rom", "rim",
+  "rel", "reg", "imm", "textsize", "mem", "omem", "nmem", "nam", "offset",
+  "pointer", "con", "expr", 0
 };
 #endif
 
@@ -586,7 +582,7 @@ static const yytype_uint16 yytoknum[] =
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
      285,   286,   287,   288,   289,   290,    58,    59,    61,    44,
-      40,    41,    36,   126
+      36,    40,    41,   126
 };
 # endif
 
@@ -597,35 +593,35 @@ static const yytype_uint8 yyr1[] =
       59,    59,    59,    59,    59,    59,    59,    59,    59,    59,
       59,    59,    59,    59,    59,    59,    59,    59,    59,    59,
       60,    60,    61,    62,    63,    63,    64,    64,    65,    65,
-      65,    66,    67,    67,    68,    68,    68,    69,    69,    70,
-      70,    71,    71,    72,    72,    72,    73,    73,    74,    75,
+      65,    66,    67,    67,    68,    68,    69,    69,    69,    70,
+      70,    71,    71,    72,    72,    73,    73,    73,    74,    75,
       76,    77,    78,    78,    79,    79,    79,    79,    79,    79,
       79,    80,    80,    81,    81,    82,    82,    82,    82,    82,
-      82,    83,    83,    83,    83,    83,    83,    83,    84,    85,
-      85,    85,    85,    86,    86,    87,    87,    87,    87,    87,
-      87,    87,    87,    87,    87,    87,    88,    88,    89,    89,
-      90,    90,    90,    91,    91,    91,    92,    92,    92,    92,
-      92,    92,    93,    93,    93,    93,    93,    93,    93,    93,
-      93,    93,    93
+      82,    83,    83,    83,    83,    83,    83,    83,    84,    84,
+      84,    84,    85,    85,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    87,    87,    88,    88,    89,
+      89,    89,    90,    90,    90,    91,    91,    91,    91,    91,
+      91,    92,    92,    92,    92,    92,    92,    92,    92,    92,
+      92,    92
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
        0,     2,     0,     0,     3,     0,     4,     1,     2,     2,
-       3,     3,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       3,     3,     2,     2,     2,     2,     2,     2,     1,     1,
+       2,     2,     2,     2,     2,     1,     2,     2,     2,     2,
        0,     1,     3,     3,     2,     1,     2,     1,     2,     1,
-       3,     5,     3,     5,     2,     1,     2,     1,     1,     3,
-       5,     3,     5,     2,     1,     3,     3,     5,     5,     5,
+       3,     6,     5,     7,     4,     6,     2,     1,     2,     1,
+       1,     3,     5,     3,     5,     2,     1,     3,     5,     5,
        3,     3,     1,     1,     1,     1,     2,     2,     1,     1,
        1,     1,     1,     4,     2,     1,     1,     1,     1,     1,
-       1,     2,     2,     2,     2,     4,     5,     3,     2,     1,
-       2,     3,     4,     1,     1,     1,     4,     4,     6,     9,
-       9,     3,     3,     4,     5,     8,     1,     6,     5,     7,
-       0,     2,     2,     1,     1,     1,     1,     1,     2,     2,
-       2,     3,     1,     3,     3,     3,     3,     3,     4,     4,
-       3,     3,     3
+       1,     2,     2,     2,     2,     4,     5,     3,     1,     2,
+       3,     4,     1,     1,     1,     4,     4,     6,     9,     9,
+       3,     3,     4,     5,     8,     1,     6,     5,     7,     0,
+       2,     2,     1,     1,     1,     1,     1,     2,     2,     2,
+       3,     1,     3,     3,     3,     3,     3,     4,     4,     3,
+       3,     3
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -635,83 +631,83 @@ static const yytype_uint8 yydefact[] =
 {
        2,     3,     1,     0,     0,    30,     0,     0,     0,     0,
        0,     0,    30,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     7,     4,     0,     9,    31,
-      12,     0,     0,   116,    75,    77,    80,    76,    78,    79,
-     110,   117,     0,     0,     0,    13,    37,    62,    63,    93,
-      94,   106,    95,     0,    14,    71,    35,    72,    15,     0,
-      16,     0,     0,   110,     0,    20,    45,    64,    68,    70,
-      69,    65,    95,    18,     0,    31,    47,    48,    21,   110,
-       0,     0,    17,    39,     0,     0,    19,     0,    22,     0,
-      23,     0,    24,    54,    25,     0,    26,     0,    27,     0,
-      28,     0,    29,     0,     5,     0,     0,     8,   119,   118,
-       0,     0,     0,     0,    36,     0,     0,   122,     0,   120,
+       0,     0,     0,     0,     0,     7,     4,     0,    18,    19,
+      25,     9,    31,    12,     0,     0,   115,    75,    77,    80,
+      76,    78,    79,   109,   116,     0,     0,     0,    13,    37,
+      62,    63,    92,    93,   105,    94,     0,    14,    71,    35,
+      72,    15,     0,    16,     0,     0,   109,     0,    20,    47,
+      64,    68,    70,    69,    65,    94,     0,    31,    49,    50,
+      21,   109,     0,     0,    17,    39,     0,     0,     0,    22,
+       0,    23,     0,    24,    56,     0,    26,     0,    27,     0,
+      28,     0,    29,     0,     5,     0,     0,     8,   118,   117,
+       0,     0,     0,     0,    36,     0,     0,   121,     0,   119,
        0,     0,     0,    84,    83,     0,    82,    81,    34,     0,
-       0,    66,    67,    46,    74,     0,    44,     0,     0,    74,
-      38,     0,     0,     0,     0,     0,    53,     0,     0,     0,
-       0,     0,     0,    10,    11,   110,   111,   112,     0,     0,
-     101,   102,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   121,     0,     0,     0,     0,    87,     0,     0,
-      32,    33,     0,     0,    40,     0,    42,     0,    49,    51,
-      55,    56,     0,     0,     0,    60,    61,     6,     0,   115,
-     113,   114,     0,     0,     0,   132,   131,   130,     0,     0,
-     123,   124,   125,   126,   127,     0,     0,    96,   103,    97,
-       0,    85,    73,     0,     0,    89,    88,     0,     0,     0,
-       0,     0,     0,     0,   108,   104,     0,   128,   129,     0,
-       0,     0,    86,    41,    90,     0,    43,    50,    52,    57,
-      58,    59,     0,     0,   107,    98,     0,     0,     0,    91,
-     109,     0,     0,     0,    92,   105,     0,     0,    99,   100
+       0,    66,    67,    48,    74,     0,    46,     0,     0,    74,
+      38,     0,     0,     0,     0,     0,    55,     0,     0,     0,
+       0,     0,     0,    10,    11,   109,   110,   111,     0,     0,
+     100,   101,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   120,     0,     0,     0,     0,    87,     0,     0,
+      32,    33,     0,     0,    40,     0,     0,    51,    53,    57,
+      44,     0,     0,     0,    60,    61,     6,     0,   114,   112,
+     113,     0,     0,     0,   131,   130,   129,     0,     0,   122,
+     123,   124,   125,   126,     0,     0,    95,   102,    96,     0,
+      85,    73,     0,     0,    88,    42,     0,     0,     0,     0,
+       0,     0,     0,   107,   103,     0,   127,   128,     0,     0,
+       0,    86,    41,    89,     0,     0,    52,    54,    45,    58,
+      59,     0,     0,   106,    97,     0,     0,     0,    90,    43,
+     108,     0,     0,     0,    91,   104,     0,     0,    98,    99
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     1,     3,    26,   152,    27,    30,    58,    60,    54,
-      45,    82,    73,    86,    65,    78,    88,    90,    92,    94,
-      96,    98,   100,   102,    55,    66,    56,    67,    47,    57,
-     186,   226,    48,    49,    50,    51,   113,   202,    52,   118
+      -1,     1,     3,    26,   152,    27,    33,    61,    63,    57,
+      48,    84,    28,    29,    30,    68,    80,    89,    91,    93,
+      96,    98,   100,   102,    58,    69,    59,    70,    50,    60,
+     225,    51,    52,    53,    54,   113,   201,    55,   118
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -89
+#define YYPACT_NINF -87
 static const yytype_int16 yypact[] =
 {
-     -89,     8,   -89,   211,   -33,   -23,   288,   308,   308,   360,
-     236,   -11,   340,    54,    41,   308,   308,   308,    41,   106,
-     -13,   308,   308,    62,    -4,   -89,   -89,    45,   -89,   -89,
-     -89,   484,   484,   -89,   -89,   -89,   -89,   -89,   -89,   -89,
-      81,   -89,   360,   413,   484,   -89,   -89,   -89,   -89,   -89,
-     -89,    38,    48,   407,   -89,   -89,    -2,   -89,   -89,    64,
-     -89,    78,   360,    81,   256,   -89,   -89,   -89,   -89,   -89,
-     -89,   -89,    61,   -89,   107,   360,   -89,   -89,   -89,    59,
-     431,   484,   -89,   -89,    86,    79,   -89,    87,   -89,    89,
-     -89,    91,   -89,    97,   -89,   102,   -89,   116,   -89,   120,
-     -89,   148,   -89,   151,   -89,   484,   484,   -89,   -89,   -89,
-     123,   484,   484,   105,   -89,     1,   150,   -89,   169,   -89,
-     166,     9,    69,   -89,   -89,   456,   -89,   -89,   -89,   360,
-     308,   -89,   -89,   -89,   105,   392,   -89,   -17,   484,   -89,
-     -89,   431,   170,   460,   360,   360,   360,   469,   360,   360,
-     308,   308,   211,   179,   179,    59,   -89,   -89,     6,   484,
-     154,   -89,   484,   484,   484,   201,   149,   484,   484,   484,
-     484,   484,   -89,   198,    13,   158,   159,   -89,   480,   160,
-     -89,   -89,   162,   165,   -89,     0,   -89,   167,   171,   172,
-     -89,   -89,   193,   199,   200,   -89,   -89,   -89,   197,   -89,
-     -89,   -89,   168,   204,   214,   534,   542,   549,   484,   484,
-     113,   113,   -89,   -89,   -89,   484,   484,   207,   -89,   -89,
-     208,   -89,   -89,   -13,   220,   251,   -89,   209,   226,   231,
-     -13,   484,   106,   229,   -89,   -89,   259,   184,   184,   219,
-     225,    80,   -89,   -89,   268,   249,   -89,   -89,   -89,   -89,
-     -89,   -89,   232,   484,   -89,   -89,   272,   274,   269,   -89,
-     -89,   239,   484,   484,   -89,   -89,   252,   253,   -89,   -89
+     -87,    35,   -87,   242,     2,    -4,   164,   313,   313,   361,
+     265,     8,   337,    60,   410,   313,   313,   313,   410,   241,
+     -11,   313,   313,   -31,    17,   -87,   -87,    23,   -87,   -87,
+     -87,   -87,   -87,   -87,   474,   474,   -87,   -87,   -87,   -87,
+     -87,   -87,   -87,    20,   -87,   361,   401,   474,   -87,   -87,
+     -87,   -87,   -87,   -87,    16,    28,   185,   -87,   -87,    22,
+     -87,   -87,    25,   -87,    31,   361,    20,   289,   -87,   -87,
+     -87,   -87,   -87,   -87,   -87,    48,    29,   361,   -87,   -87,
+     -87,    13,   417,   474,   -87,   -87,    51,    53,    57,   -87,
+      58,   -87,    59,   -87,    70,    71,   -87,    75,   -87,    80,
+     -87,    86,   -87,   102,   -87,   474,   474,   -87,   -87,   -87,
+      37,   474,   474,    76,   -87,     1,   103,   -87,   175,   -87,
+     126,    50,    85,   -87,   -87,   426,   -87,   -87,   -87,   361,
+     313,   -87,   -87,   -87,    76,   385,   -87,    81,   474,   -87,
+     -87,   417,   130,   436,   361,   361,   361,   464,   361,   361,
+     313,   313,   242,   525,   525,    13,   -87,   -87,    18,   474,
+     113,   -87,   474,   474,   474,   165,   167,   474,   474,   474,
+     474,   474,   -87,   186,     3,   123,   156,   -87,   467,   158,
+     -87,   -87,   159,   163,   -87,     7,   169,   173,   177,   -87,
+     -87,   182,   183,   184,   -87,   -87,   -87,   178,   -87,   -87,
+     -87,   172,   187,   198,   136,   239,   532,   474,   474,    78,
+      78,   -87,   -87,   -87,   474,   474,   189,   -87,   -87,   202,
+     -87,   -87,   -11,   204,   228,   -87,   191,   245,   247,   -11,
+     474,   241,   248,   -87,   -87,   276,   180,   180,   236,   238,
+      -5,   -87,   -87,   282,   261,     7,   -87,   -87,   -87,   -87,
+     -87,   243,   474,   -87,   -87,   283,   284,   274,   -87,   -87,
+     -87,   254,   474,   474,   -87,   -87,   257,   259,   -87,   -87
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-     -89,   -89,   -89,   153,   -89,   -89,   290,   -89,   -89,   -89,
-     295,   -89,   -89,   -89,   -89,   -89,   -89,   -89,   -89,   -89,
-     -89,   -89,   -89,   -89,    18,   246,    20,    -7,    -9,    -8,
-      84,   -89,    51,    -3,    -6,     4,   -50,   -89,   -10,   -88
+     -87,   -87,   -87,   160,   -87,   -87,   301,   -87,   -87,   -87,
+     305,   -87,   -87,   -87,   -87,   -87,   -87,   -87,   -87,   -87,
+     -87,   -87,   -87,   -87,    21,   252,    26,    -7,    -9,    -8,
+      84,     0,    -3,    -6,    -2,   -58,   -87,   -10,   -86
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -721,124 +717,120 @@ static const yytype_int16 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint16 yytable[] =
 {
-      72,    68,    69,    85,    71,    84,    83,    70,     2,   224,
-      97,   159,    99,   134,    28,    74,   182,   153,   154,   174,
-     175,   108,   109,   216,    46,   176,    29,    61,    59,   139,
-      46,   225,    40,   117,   119,    89,    91,    93,   199,    53,
-     200,   101,   103,   127,   106,   174,   175,   128,   201,    31,
-      32,   176,   160,   131,    72,    68,    69,   126,    71,   132,
-     114,    70,    31,    32,   217,    87,   133,   111,   112,    95,
-      85,   117,    33,   140,   205,   206,   207,    31,    32,   210,
-     211,   212,   213,   214,    40,    33,    41,   110,   120,   111,
-     112,    43,   107,   114,    44,   117,   117,    79,   121,    41,
-      33,   156,   157,    80,    81,   198,    53,    44,   104,   177,
-     105,   137,   109,   129,    41,   117,   256,   257,   138,    81,
-     237,   238,    44,   169,   170,   171,   131,   130,   183,   142,
-     155,    85,   132,   187,   184,   141,   143,   192,   144,   191,
-     145,    34,    35,    36,    37,    38,   146,   180,    39,   203,
-     181,   147,   117,   117,   117,   158,   209,   117,   117,   117,
-     117,   117,   188,   189,   190,   148,   193,   194,   109,   149,
-     195,   196,   162,   163,   164,   165,   166,   167,   168,   169,
-     170,   171,   162,   163,   164,   165,   166,   167,   168,   169,
-     170,   171,   167,   168,   169,   170,   171,   150,   117,   117,
-     151,   161,   173,   182,   204,   239,   240,   208,   215,   218,
-     219,   221,     4,   222,   223,   243,   227,   228,   229,   234,
-     172,   250,   249,   251,     5,     6,     7,     8,     9,    10,
-      11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,   230,   261,    31,    32,    62,   233,   231,   232,
-     236,   244,   266,   267,    23,   235,    24,   241,    25,   242,
-     245,   185,   247,   252,    31,    32,   135,    33,   248,   253,
-     254,    34,    35,    36,    37,    38,   255,   258,    39,    63,
-     259,    41,   262,   260,   263,    64,    43,    33,    53,    44,
-     265,    34,    35,    36,    37,    38,    31,    32,    39,    63,
-     264,    41,    76,   268,   269,   197,    43,    77,    53,    44,
-     136,   246,     0,     0,     0,     0,    31,    32,     0,    33,
-       0,     0,     0,    34,    35,    36,    37,    38,     0,     0,
-      39,    40,     0,    41,     0,     0,     0,    42,    43,    33,
-       0,    44,     0,    34,    35,    36,    37,    38,    31,    32,
-      39,    40,     0,    41,     0,     0,     0,     0,    43,     0,
-      53,    44,     0,     0,     0,     0,     0,     0,    31,    32,
-       0,    33,     0,     0,     0,    34,    35,    36,    37,    38,
-       0,     0,    39,    40,     0,    41,     0,     0,     0,    75,
-      43,    33,     0,    44,     0,    34,    35,    36,    37,    38,
-      31,    32,    39,    40,     0,    41,     0,     0,     0,     0,
-      43,     0,     0,    44,     0,    31,   122,     0,     0,     0,
-       0,    31,    32,    33,     0,     0,     0,    34,    35,    36,
-      37,    38,     0,     0,    39,     0,     0,    41,    33,    31,
-      32,     0,    43,     0,    33,    44,     0,   123,   124,   115,
-      40,     0,    41,     0,     0,   116,     0,   125,    41,     0,
-      44,     0,    33,    81,    31,   178,    44,     0,    31,    32,
-       0,     0,     0,     0,    79,     0,    41,    31,    32,     0,
-       0,    81,     0,     0,    44,     0,     0,    33,    31,    32,
-       0,    33,    31,    32,     0,     0,   179,     0,     0,     0,
-      33,    41,     0,     0,     0,    41,    81,     0,     0,    44,
-      81,    33,   185,    44,    41,    33,     0,     0,     0,    81,
-     220,    53,    44,     0,     0,    41,     0,     0,     0,    41,
-      81,     0,     0,    44,    81,     0,     0,    44,   163,   164,
-     165,   166,   167,   168,   169,   170,   171,   164,   165,   166,
-     167,   168,   169,   170,   171,   165,   166,   167,   168,   169,
-     170,   171
+      75,    71,    72,    87,    74,    86,    85,    73,   134,    76,
+      97,   159,    99,   215,    88,   104,   223,   105,    95,   153,
+     154,   111,   112,   139,   108,   109,   110,    49,   111,   112,
+      64,   255,   256,    49,    62,     2,   117,   119,   224,    56,
+     138,    90,    92,    94,   155,    32,   127,   101,   103,    31,
+     198,    43,   199,   160,   126,   216,   131,    75,    71,    72,
+     200,    74,   132,   133,    73,   106,   114,   120,    34,    35,
+     107,   128,    87,   117,   129,   140,   204,   205,   206,   121,
+     130,   209,   210,   211,   212,   213,   174,   175,   169,   170,
+     171,    36,   176,    34,    35,   117,   117,   197,   114,   137,
+     141,   156,   157,    81,   142,    44,   143,   144,   145,    82,
+      56,    83,   109,    47,   182,   117,    36,   174,   175,   146,
+     147,   236,   237,   176,   148,   177,   131,   158,   183,   149,
+      44,    87,   132,   186,   184,   150,    83,   191,    47,   190,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,   202,
+     180,   151,   117,   117,   117,   161,   181,   117,   117,   117,
+     117,   117,   173,   182,   203,   187,   188,   189,   109,   192,
+     193,   207,    34,    35,   208,   217,   194,   195,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,   167,   168,
+     169,   170,   171,    34,   122,    36,   214,   117,   117,    37,
+      38,    39,    40,    41,   238,   239,    42,    43,   218,    44,
+     220,   221,   222,    45,   242,    46,    36,    47,   226,   227,
+     249,   248,   250,   228,   233,   123,   124,   172,    43,   232,
+      44,   229,   230,   231,   235,   243,   125,   244,    47,   234,
+     240,   245,   261,     4,   164,   165,   166,   167,   168,   169,
+     170,   171,   266,   267,   241,     5,     6,     7,     8,     9,
+      10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    34,    35,    65,    37,    38,    39,    40,
+      41,   246,   251,    42,   247,    23,   252,    24,   253,    25,
+     254,   257,   258,   262,   263,   260,    36,    34,    35,   135,
+      37,    38,    39,    40,    41,   264,   265,    42,    66,   268,
+      44,   269,   196,    78,    67,    56,    46,    79,    47,   136,
+      36,    34,    35,     0,    37,    38,    39,    40,    41,   259,
+       0,    42,    66,     0,    44,     0,     0,     0,     0,    56,
+      46,     0,    47,     0,    36,    34,    35,     0,    37,    38,
+      39,    40,    41,     0,     0,    42,    43,     0,    44,     0,
+       0,     0,     0,    56,    46,     0,    47,     0,    36,    34,
+      35,     0,    37,    38,    39,    40,    41,     0,     0,    42,
+      43,     0,    44,     0,     0,     0,    77,     0,    46,     0,
+      47,     0,    36,    34,    35,     0,    37,    38,    39,    40,
+      41,     0,     0,    42,    43,     0,    44,     0,     0,    34,
+      35,     0,    46,     0,    47,     0,    36,     0,    34,    35,
+      37,    38,    39,    40,    41,    34,    35,    42,     0,     0,
+      44,     0,    36,     0,    34,   178,    46,   115,    47,     0,
+       0,    36,     0,   116,    34,    35,    44,     0,    36,     0,
+       0,     0,    83,    43,    47,    44,     0,    36,     0,     0,
+      81,    46,    44,    47,     0,     0,   179,    36,    83,     0,
+      47,    44,    34,    35,     0,    34,    35,    83,     0,    47,
+       0,    44,    34,    35,     0,     0,   185,    83,     0,    47,
+       0,     0,     0,     0,     0,    36,     0,     0,    36,     0,
+       0,     0,     0,     0,     0,    36,     0,   219,     0,    44,
+       0,     0,    44,     0,    56,    83,     0,    47,    83,    44,
+      47,     0,     0,     0,     0,    83,     0,    47,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,   165,   166,
+     167,   168,   169,   170,   171
 };
 
 static const yytype_int16 yycheck[] =
 {
-      10,    10,    10,    13,    10,    13,    13,    10,     0,     9,
-      19,    10,    20,    63,    47,    11,    33,   105,   106,    36,
-      37,    31,    32,    10,     6,    42,    49,     9,     8,    79,
-      12,    31,    43,    43,    44,    15,    16,    17,    32,    52,
-      34,    21,    22,    53,    48,    36,    37,    49,    42,     8,
-       9,    42,    51,    62,    64,    64,    64,    53,    64,    62,
-      42,    64,     8,     9,    51,    14,    62,     8,     9,    18,
-      80,    81,    31,    80,   162,   163,   164,     8,     9,   167,
-     168,   169,   170,   171,    43,    31,    45,     6,    50,     8,
-       9,    50,    47,    75,    53,   105,   106,    43,    50,    45,
-      31,   111,   112,    49,    50,   155,    52,    53,    46,    40,
-      48,    50,   122,    49,    45,   125,    36,    37,    11,    50,
-     208,   209,    53,    10,    11,    12,   135,    49,   138,    50,
-       7,   141,   135,   143,   141,    49,    49,   147,    49,   147,
-      49,    35,    36,    37,    38,    39,    49,   129,    42,   159,
-     130,    49,   162,   163,   164,    50,     7,   167,   168,   169,
-     170,   171,   144,   145,   146,    49,   148,   149,   178,    49,
-     150,   151,     3,     4,     5,     6,     7,     8,     9,    10,
-      11,    12,     3,     4,     5,     6,     7,     8,     9,    10,
-      11,    12,     8,     9,    10,    11,    12,    49,   208,   209,
-      49,    51,    36,    33,    50,   215,   216,     6,    10,    51,
-      51,    51,     1,    51,    49,   223,    49,    46,    46,    51,
-      51,   231,   230,   232,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-      29,    30,    49,   253,     8,     9,    10,    50,    49,    49,
-      36,    31,   262,   263,    43,    51,    45,    50,    47,    51,
-       9,    52,    36,    34,     8,     9,    10,    31,    37,    10,
-      51,    35,    36,    37,    38,    39,    51,     9,    42,    43,
-      31,    45,    10,    51,    10,    49,    50,    31,    52,    53,
-      51,    35,    36,    37,    38,    39,     8,     9,    42,    43,
-      31,    45,    12,    51,    51,   152,    50,    12,    52,    53,
-      64,   227,    -1,    -1,    -1,    -1,     8,     9,    -1,    31,
-      -1,    -1,    -1,    35,    36,    37,    38,    39,    -1,    -1,
-      42,    43,    -1,    45,    -1,    -1,    -1,    49,    50,    31,
-      -1,    53,    -1,    35,    36,    37,    38,    39,     8,     9,
-      42,    43,    -1,    45,    -1,    -1,    -1,    -1,    50,    -1,
-      52,    53,    -1,    -1,    -1,    -1,    -1,    -1,     8,     9,
-      -1,    31,    -1,    -1,    -1,    35,    36,    37,    38,    39,
-      -1,    -1,    42,    43,    -1,    45,    -1,    -1,    -1,    49,
-      50,    31,    -1,    53,    -1,    35,    36,    37,    38,    39,
-       8,     9,    42,    43,    -1,    45,    -1,    -1,    -1,    -1,
-      50,    -1,    -1,    53,    -1,     8,     9,    -1,    -1,    -1,
-      -1,     8,     9,    31,    -1,    -1,    -1,    35,    36,    37,
-      38,    39,    -1,    -1,    42,    -1,    -1,    45,    31,     8,
-       9,    -1,    50,    -1,    31,    53,    -1,    40,    41,    36,
-      43,    -1,    45,    -1,    -1,    42,    -1,    50,    45,    -1,
-      53,    -1,    31,    50,     8,     9,    53,    -1,     8,     9,
-      -1,    -1,    -1,    -1,    43,    -1,    45,     8,     9,    -1,
-      -1,    50,    -1,    -1,    53,    -1,    -1,    31,     8,     9,
-      -1,    31,     8,     9,    -1,    -1,    40,    -1,    -1,    -1,
-      31,    45,    -1,    -1,    -1,    45,    50,    -1,    -1,    53,
-      50,    31,    52,    53,    45,    31,    -1,    -1,    -1,    50,
-      40,    52,    53,    -1,    -1,    45,    -1,    -1,    -1,    45,
-      50,    -1,    -1,    53,    50,    -1,    -1,    53,     4,     5,
-       6,     7,     8,     9,    10,    11,    12,     5,     6,     7,
-       8,     9,    10,    11,    12,     6,     7,     8,     9,    10,
-      11,    12
+      10,    10,    10,    13,    10,    13,    13,    10,    66,    11,
+      19,    10,    20,    10,    14,    46,     9,    48,    18,   105,
+     106,     8,     9,    81,    34,    35,     6,     6,     8,     9,
+       9,    36,    37,    12,     8,     0,    46,    47,    31,    50,
+      11,    15,    16,    17,     7,    49,    56,    21,    22,    47,
+      32,    43,    34,    52,    56,    52,    65,    67,    67,    67,
+      42,    67,    65,    65,    67,    48,    45,    51,     8,     9,
+      47,    49,    82,    83,    49,    82,   162,   163,   164,    51,
+      49,   167,   168,   169,   170,   171,    36,    37,    10,    11,
+      12,    31,    42,     8,     9,   105,   106,   155,    77,    51,
+      49,   111,   112,    43,    51,    45,    49,    49,    49,    49,
+      50,    51,   122,    53,    33,   125,    31,    36,    37,    49,
+      49,   207,   208,    42,    49,    40,   135,    51,   138,    49,
+      45,   141,   135,   143,   141,    49,    51,   147,    53,   147,
+       4,     5,     6,     7,     8,     9,    10,    11,    12,   159,
+     129,    49,   162,   163,   164,    52,   130,   167,   168,   169,
+     170,   171,    36,    33,    51,   144,   145,   146,   178,   148,
+     149,     6,     8,     9,     7,    52,   150,   151,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,     8,     9,
+      10,    11,    12,     8,     9,    31,    10,   207,   208,    35,
+      36,    37,    38,    39,   214,   215,    42,    43,    52,    45,
+      52,    52,    49,    49,   222,    51,    31,    53,    49,    46,
+     230,   229,   231,    46,    52,    40,    41,    52,    43,    51,
+      45,    49,    49,    49,    36,    31,    51,     9,    53,    52,
+      51,    50,   252,     1,     5,     6,     7,     8,     9,    10,
+      11,    12,   262,   263,    52,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    30,     8,     9,    10,    35,    36,    37,    38,
+      39,    36,    34,    42,    37,    43,    10,    45,    52,    47,
+      52,     9,    31,    10,    10,    52,    31,     8,     9,    10,
+      35,    36,    37,    38,    39,    31,    52,    42,    43,    52,
+      45,    52,   152,    12,    49,    50,    51,    12,    53,    67,
+      31,     8,     9,    -1,    35,    36,    37,    38,    39,   245,
+      -1,    42,    43,    -1,    45,    -1,    -1,    -1,    -1,    50,
+      51,    -1,    53,    -1,    31,     8,     9,    -1,    35,    36,
+      37,    38,    39,    -1,    -1,    42,    43,    -1,    45,    -1,
+      -1,    -1,    -1,    50,    51,    -1,    53,    -1,    31,     8,
+       9,    -1,    35,    36,    37,    38,    39,    -1,    -1,    42,
+      43,    -1,    45,    -1,    -1,    -1,    49,    -1,    51,    -1,
+      53,    -1,    31,     8,     9,    -1,    35,    36,    37,    38,
+      39,    -1,    -1,    42,    43,    -1,    45,    -1,    -1,     8,
+       9,    -1,    51,    -1,    53,    -1,    31,    -1,     8,     9,
+      35,    36,    37,    38,    39,     8,     9,    42,    -1,    -1,
+      45,    -1,    31,    -1,     8,     9,    51,    36,    53,    -1,
+      -1,    31,    -1,    42,     8,     9,    45,    -1,    31,    -1,
+      -1,    -1,    51,    43,    53,    45,    -1,    31,    -1,    -1,
+      43,    51,    45,    53,    -1,    -1,    40,    31,    51,    -1,
+      53,    45,     8,     9,    -1,     8,     9,    51,    -1,    53,
+      -1,    45,     8,     9,    -1,    -1,    50,    51,    -1,    53,
+      -1,    -1,    -1,    -1,    -1,    31,    -1,    -1,    31,    -1,
+      -1,    -1,    -1,    -1,    -1,    31,    -1,    40,    -1,    45,
+      -1,    -1,    45,    -1,    50,    51,    -1,    53,    51,    45,
+      53,    -1,    -1,    -1,    -1,    51,    -1,    53,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,     6,     7,
+       8,     9,    10,    11,    12
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -847,31 +839,31 @@ static const yytype_uint8 yystos[] =
 {
        0,    55,     0,    56,     1,    13,    14,    15,    16,    17,
       18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    43,    45,    47,    57,    59,    47,    49,
-      60,     8,     9,    31,    35,    36,    37,    38,    39,    42,
-      43,    45,    49,    50,    53,    64,    78,    82,    86,    87,
-      88,    89,    92,    52,    63,    78,    80,    83,    61,    80,
-      62,    78,    10,    43,    49,    68,    79,    81,    82,    83,
-      87,    88,    92,    66,    89,    49,    60,    64,    69,    43,
-      49,    50,    65,    81,    83,    92,    67,    86,    70,    80,
-      71,    80,    72,    80,    73,    86,    74,    82,    75,    83,
-      76,    80,    77,    80,    46,    48,    48,    47,    92,    92,
-       6,     8,     9,    90,    78,    36,    42,    92,    93,    92,
-      50,    50,     9,    40,    41,    50,    89,    92,    49,    49,
-      49,    82,    87,    89,    90,    10,    79,    50,    11,    90,
-      81,    49,    50,    49,    49,    49,    49,    49,    49,    49,
-      49,    49,    58,    93,    93,     7,    92,    92,    50,    10,
-      51,    51,     3,     4,     5,     6,     7,     8,     9,    10,
-      11,    12,    51,    36,    36,    37,    42,    40,     9,    40,
-      78,    80,    33,    92,    81,    52,    84,    92,    78,    78,
-      78,    83,    92,    78,    78,    80,    80,    57,    90,    32,
-      34,    42,    91,    92,    50,    93,    93,    93,     6,     7,
-      93,    93,    93,    93,    93,    10,    10,    51,    51,    51,
-      40,    51,    51,    49,     9,    31,    85,    49,    46,    46,
-      49,    49,    49,    50,    51,    51,    36,    93,    93,    92,
-      92,    50,    51,    83,    31,     9,    84,    36,    37,    83,
-      92,    82,    34,    10,    51,    51,    36,    37,     9,    31,
-      51,    92,    10,    10,    31,    51,    92,    92,    51,    51
+      28,    29,    30,    43,    45,    47,    57,    59,    66,    67,
+      68,    47,    49,    60,     8,     9,    31,    35,    36,    37,
+      38,    39,    42,    43,    45,    49,    51,    53,    64,    78,
+      82,    85,    86,    87,    88,    91,    50,    63,    78,    80,
+      83,    61,    80,    62,    78,    10,    43,    49,    69,    79,
+      81,    82,    83,    86,    87,    91,    88,    49,    60,    64,
+      70,    43,    49,    51,    65,    81,    83,    91,    85,    71,
+      80,    72,    80,    73,    80,    85,    74,    82,    75,    83,
+      76,    80,    77,    80,    46,    48,    48,    47,    91,    91,
+       6,     8,     9,    89,    78,    36,    42,    91,    92,    91,
+      51,    51,     9,    40,    41,    51,    88,    91,    49,    49,
+      49,    82,    86,    88,    89,    10,    79,    51,    11,    89,
+      81,    49,    51,    49,    49,    49,    49,    49,    49,    49,
+      49,    49,    58,    92,    92,     7,    91,    91,    51,    10,
+      52,    52,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    52,    36,    36,    37,    42,    40,     9,    40,
+      78,    80,    33,    91,    81,    50,    91,    78,    78,    78,
+      83,    91,    78,    78,    80,    80,    57,    89,    32,    34,
+      42,    90,    91,    51,    92,    92,    92,     6,     7,    92,
+      92,    92,    92,    92,    10,    10,    52,    52,    52,    40,
+      52,    52,    49,     9,    31,    84,    49,    46,    46,    49,
+      49,    49,    51,    52,    52,    36,    92,    92,    91,    91,
+      51,    52,    83,    31,     9,    50,    36,    37,    83,    91,
+      82,    34,    10,    52,    52,    36,    37,     9,    31,    84,
+      52,    91,    10,    10,    31,    52,    91,    91,    52,    52
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1686,14 +1678,14 @@ yyreduce:
   switch (yyn)
     {
         case 3:
-#line 71 "a.y"
+#line 66 "a.y"
     {
                stmtline = lineno;
        }
     break;
 
   case 5:
-#line 78 "a.y"
+#line 73 "a.y"
     {
                (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
                if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc)
@@ -1704,7 +1696,7 @@ yyreduce:
     break;
 
   case 10:
-#line 92 "a.y"
+#line 87 "a.y"
     {
                (yyvsp[(1) - (3)].sym)->type = LVAR;
                (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
@@ -1712,7 +1704,7 @@ yyreduce:
     break;
 
   case 11:
-#line 97 "a.y"
+#line 92 "a.y"
     {
                if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
                        yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
@@ -1721,97 +1713,82 @@ yyreduce:
     break;
 
   case 12:
-#line 102 "a.y"
+#line 97 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 13:
-#line 103 "a.y"
+#line 98 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 14:
-#line 104 "a.y"
+#line 99 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 15:
-#line 105 "a.y"
+#line 100 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 16:
-#line 106 "a.y"
+#line 101 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 17:
-#line 107 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 18:
-#line 108 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 19:
-#line 109 "a.y"
+#line 102 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 20:
-#line 110 "a.y"
+#line 105 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 21:
-#line 111 "a.y"
+#line 106 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 22:
-#line 112 "a.y"
+#line 107 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 23:
-#line 113 "a.y"
+#line 108 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 24:
-#line 114 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 25:
-#line 115 "a.y"
+#line 109 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 26:
-#line 116 "a.y"
+#line 111 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 27:
-#line 117 "a.y"
+#line 112 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 28:
-#line 118 "a.y"
+#line 113 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 29:
-#line 119 "a.y"
+#line 114 "a.y"
     { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
     break;
 
   case 30:
-#line 122 "a.y"
+#line 117 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = nullgen;
@@ -1819,7 +1796,7 @@ yyreduce:
     break;
 
   case 31:
-#line 127 "a.y"
+#line 122 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = nullgen;
@@ -1827,7 +1804,7 @@ yyreduce:
     break;
 
   case 32:
-#line 134 "a.y"
+#line 129 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
@@ -1835,7 +1812,7 @@ yyreduce:
     break;
 
   case 33:
-#line 141 "a.y"
+#line 136 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
@@ -1843,7 +1820,7 @@ yyreduce:
     break;
 
   case 34:
-#line 148 "a.y"
+#line 143 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
                (yyval.addr2).to = nullgen;
@@ -1851,7 +1828,7 @@ yyreduce:
     break;
 
   case 35:
-#line 153 "a.y"
+#line 148 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
                (yyval.addr2).to = nullgen;
@@ -1859,7 +1836,7 @@ yyreduce:
     break;
 
   case 36:
-#line 160 "a.y"
+#line 155 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
@@ -1867,7 +1844,7 @@ yyreduce:
     break;
 
   case 37:
-#line 165 "a.y"
+#line 160 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
@@ -1875,7 +1852,7 @@ yyreduce:
     break;
 
   case 38:
-#line 172 "a.y"
+#line 167 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
@@ -1883,7 +1860,7 @@ yyreduce:
     break;
 
   case 39:
-#line 177 "a.y"
+#line 172 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
@@ -1891,7 +1868,7 @@ yyreduce:
     break;
 
   case 40:
-#line 182 "a.y"
+#line 177 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
@@ -1899,140 +1876,160 @@ yyreduce:
     break;
 
   case 41:
-#line 189 "a.y"
-    {
-               (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-               (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-               (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
+#line 184 "a.y"
+    {
+               Addr2 a;
+               a.from = (yyvsp[(2) - (6)].addr);
+               a.to = (yyvsp[(6) - (6)].addr);
+               outcode(ADATA, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
+               }
        }
     break;
 
   case 42:
 #line 197 "a.y"
     {
-               settext((yyvsp[(1) - (3)].addr).sym);
-               (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-               (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+               Addr2 a;
+               settext((yyvsp[(2) - (5)].addr).sym);
+               a.from = (yyvsp[(2) - (5)].addr);
+               a.to = (yyvsp[(5) - (5)].addr);
+               outcode(ATEXT, &a);
        }
     break;
 
   case 43:
-#line 203 "a.y"
-    {
-               settext((yyvsp[(1) - (5)].addr).sym);
-               (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-               (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-               (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
+#line 205 "a.y"
+    {
+               Addr2 a;
+               settext((yyvsp[(2) - (7)].addr).sym);
+               a.from = (yyvsp[(2) - (7)].addr);
+               a.to = (yyvsp[(7) - (7)].addr);
+               outcode(ATEXT, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (7)].lval);
+               }
        }
     break;
 
   case 44:
-#line 212 "a.y"
+#line 219 "a.y"
+    {
+               Addr2 a;
+               settext((yyvsp[(2) - (4)].addr).sym);
+               a.from = (yyvsp[(2) - (4)].addr);
+               a.to = (yyvsp[(4) - (4)].addr);
+               outcode(AGLOBL, &a);
+       }
+    break;
+
+  case 45:
+#line 227 "a.y"
+    {
+               Addr2 a;
+               settext((yyvsp[(2) - (6)].addr).sym);
+               a.from = (yyvsp[(2) - (6)].addr);
+               a.to = (yyvsp[(6) - (6)].addr);
+               outcode(AGLOBL, &a);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
+               }
+       }
+    break;
+
+  case 46:
+#line 241 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
        }
     break;
 
-  case 45:
-#line 217 "a.y"
+  case 47:
+#line 246 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
        }
     break;
 
-  case 46:
-#line 222 "a.y"
+  case 48:
+#line 251 "a.y"
     {
                (yyval.addr2).from = nullgen;
                (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
-               (yyval.addr2).to.index = (yyvsp[(2) - (2)].addr).type;
-               (yyval.addr2).to.type = D_INDIR+D_ADDR;
+               (yyval.addr2).to.type = TYPE_INDIR;
        }
     break;
 
-  case 49:
-#line 235 "a.y"
+  case 51:
+#line 263 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
        }
     break;
 
-  case 50:
-#line 240 "a.y"
+  case 52:
+#line 268 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
-               if((yyval.addr2).from.index != D_NONE)
+               if((yyval.addr2).from.index != TYPE_NONE)
                        yyerror("dp shift with lhs index");
                (yyval.addr2).from.index = (yyvsp[(5) - (5)].lval);
        }
     break;
 
-  case 51:
-#line 250 "a.y"
+  case 53:
+#line 278 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
        }
     break;
 
-  case 52:
-#line 255 "a.y"
+  case 54:
+#line 283 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
-               if((yyval.addr2).to.index != D_NONE)
+               if((yyval.addr2).to.index != TYPE_NONE)
                        yyerror("dp move with lhs index");
                (yyval.addr2).to.index = (yyvsp[(5) - (5)].lval);
        }
     break;
 
-  case 53:
-#line 265 "a.y"
+  case 55:
+#line 293 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
                (yyval.addr2).to = nullgen;
        }
     break;
 
-  case 54:
-#line 270 "a.y"
+  case 56:
+#line 298 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
                (yyval.addr2).to = nullgen;
        }
     break;
 
-  case 55:
-#line 275 "a.y"
-    {
-               (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-               (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-       }
-    break;
-
-  case 56:
-#line 282 "a.y"
+  case 57:
+#line 303 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
        }
     break;
 
-  case 57:
-#line 287 "a.y"
-    {
-               (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-               (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-               (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-       }
-    break;
-
   case 58:
-#line 295 "a.y"
+#line 310 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
@@ -2041,20 +2038,20 @@ yyreduce:
     break;
 
   case 59:
-#line 303 "a.y"
+#line 318 "a.y"
     {
                (yyval.addr2).from = (yyvsp[(3) - (5)].addr);
                (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-               if((yyvsp[(1) - (5)].addr).type != D_CONST)
+               if((yyvsp[(1) - (5)].addr).type != TYPE_CONST)
                        yyerror("illegal constant");
                (yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset;
        }
     break;
 
   case 60:
-#line 313 "a.y"
+#line 328 "a.y"
     {
-               if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST)
+               if((yyvsp[(1) - (3)].addr).type != TYPE_CONST || (yyvsp[(3) - (3)].addr).type != TYPE_CONST)
                        yyerror("arguments to PCDATA must be integer constants");
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
@@ -2062,11 +2059,11 @@ yyreduce:
     break;
 
   case 61:
-#line 322 "a.y"
+#line 337 "a.y"
     {
-               if((yyvsp[(1) - (3)].addr).type != D_CONST)
+               if((yyvsp[(1) - (3)].addr).type != TYPE_CONST)
                        yyerror("index for FUNCDATA must be integer constant");
-               if((yyvsp[(3) - (3)].addr).type != D_EXTERN && (yyvsp[(3) - (3)].addr).type != D_STATIC)
+               if((yyvsp[(3) - (3)].addr).type != TYPE_MEM || ((yyvsp[(3) - (3)].addr).name != NAME_EXTERN && (yyvsp[(3) - (3)].addr).name != NAME_STATIC))
                        yyerror("value for FUNCDATA must be symbol reference");
                (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
                (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
@@ -2074,105 +2071,110 @@ yyreduce:
     break;
 
   case 66:
-#line 339 "a.y"
+#line 354 "a.y"
     {
                (yyval.addr) = (yyvsp[(2) - (2)].addr);
        }
     break;
 
   case 67:
-#line 343 "a.y"
+#line 358 "a.y"
     {
                (yyval.addr) = (yyvsp[(2) - (2)].addr);
        }
     break;
 
   case 73:
-#line 356 "a.y"
+#line 371 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_BRANCH;
+               (yyval.addr).type = TYPE_BRANCH;
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
        }
     break;
 
   case 74:
-#line 362 "a.y"
+#line 377 "a.y"
     {
                (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
                (yyval.addr) = nullgen;
                if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB)
                        yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname);
-               (yyval.addr).type = D_BRANCH;
+               (yyval.addr).type = TYPE_BRANCH;
                (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
        }
     break;
 
   case 75:
-#line 373 "a.y"
+#line 388 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 76:
-#line 378 "a.y"
+#line 394 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 77:
-#line 383 "a.y"
+#line 400 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 78:
-#line 388 "a.y"
+#line 406 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 79:
-#line 393 "a.y"
+#line 412 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SP;
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = REG_SP;
        }
     break;
 
   case 80:
-#line 398 "a.y"
+#line 418 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 81:
-#line 405 "a.y"
+#line 426 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CONST;
+               (yyval.addr).type = TYPE_CONST;
                (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
        }
     break;
 
   case 82:
-#line 411 "a.y"
+#line 432 "a.y"
     {
                (yyval.addr) = (yyvsp[(2) - (2)].addr);
-               (yyval.addr).index = (yyvsp[(2) - (2)].addr).type;
-               (yyval.addr).type = D_ADDR;
+               (yyval.addr).type = TYPE_ADDR;
                /*
-               if($2.type == D_AUTO || $2.type == D_PARAM)
+               if($2.name == NAME_AUTO || $2.name == NAME_PARAM)
                        yyerror("constant cannot be automatic: %s",
                                $2.sym->name);
                 */
@@ -2180,124 +2182,126 @@ yyreduce:
     break;
 
   case 83:
-#line 422 "a.y"
+#line 442 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SCONST;
+               (yyval.addr).type = TYPE_SCONST;
                memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
        }
     break;
 
   case 84:
-#line 428 "a.y"
+#line 448 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
+               (yyval.addr).type = TYPE_FCONST;
                (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
        }
     break;
 
   case 85:
-#line 434 "a.y"
+#line 454 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
+               (yyval.addr).type = TYPE_FCONST;
                (yyval.addr).u.dval = (yyvsp[(3) - (4)].dval);
        }
     break;
 
   case 86:
-#line 440 "a.y"
+#line 460 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
+               (yyval.addr).type = TYPE_FCONST;
                (yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval);
        }
     break;
 
   case 87:
-#line 446 "a.y"
+#line 466 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
+               (yyval.addr).type = TYPE_FCONST;
                (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
        }
     break;
 
   case 88:
-#line 454 "a.y"
+#line 474 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CONST2;
-               (yyval.addr).offset = (yyvsp[(2) - (2)].con2).v1;
-               (yyval.addr).offset2 = (yyvsp[(2) - (2)].con2).v2;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).u.argsize = ArgsSizeUnknown;
        }
     break;
 
   case 89:
-#line 463 "a.y"
+#line 481 "a.y"
     {
-               (yyval.con2).v1 = (yyvsp[(1) - (1)].lval);
-               (yyval.con2).v2 = ArgsSizeUnknown;
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = -(yyvsp[(2) - (2)].lval);
+               (yyval.addr).u.argsize = ArgsSizeUnknown;
        }
     break;
 
   case 90:
-#line 468 "a.y"
+#line 488 "a.y"
     {
-               (yyval.con2).v1 = -(yyvsp[(2) - (2)].lval);
-               (yyval.con2).v2 = ArgsSizeUnknown;
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = (yyvsp[(1) - (3)].lval);
+               (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval);
        }
     break;
 
   case 91:
-#line 473 "a.y"
-    {
-               (yyval.con2).v1 = (yyvsp[(1) - (3)].lval);
-               (yyval.con2).v2 = (yyvsp[(3) - (3)].lval);
-       }
-    break;
-
-  case 92:
-#line 478 "a.y"
+#line 495 "a.y"
     {
-               (yyval.con2).v1 = -(yyvsp[(2) - (4)].lval);
-               (yyval.con2).v2 = (yyvsp[(4) - (4)].lval);
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = -(yyvsp[(2) - (4)].lval);
+               (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval);
        }
     break;
 
-  case 95:
-#line 489 "a.y"
+  case 94:
+#line 508 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+D_NONE;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = REG_NONE;
                (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
        }
     break;
 
-  case 96:
-#line 495 "a.y"
+  case 95:
+#line 515 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
        }
     break;
 
-  case 97:
-#line 501 "a.y"
+  case 96:
+#line 522 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+D_SP;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = REG_SP;
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
        }
     break;
 
-  case 98:
-#line 507 "a.y"
+  case 97:
+#line 529 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+D_NONE;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = REG_NONE;
                (yyval.addr).offset = (yyvsp[(1) - (6)].lval);
                (yyval.addr).index = (yyvsp[(3) - (6)].lval);
                (yyval.addr).scale = (yyvsp[(5) - (6)].lval);
@@ -2305,11 +2309,12 @@ yyreduce:
        }
     break;
 
-  case 99:
-#line 516 "a.y"
+  case 98:
+#line 539 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(3) - (9)].lval);
                (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
                (yyval.addr).index = (yyvsp[(6) - (9)].lval);
                (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
@@ -2317,11 +2322,12 @@ yyreduce:
        }
     break;
 
-  case 100:
-#line 525 "a.y"
+  case 99:
+#line 549 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(3) - (9)].lval);
                (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
                (yyval.addr).index = (yyvsp[(6) - (9)].lval);
                (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
@@ -2329,62 +2335,67 @@ yyreduce:
        }
     break;
 
-  case 101:
-#line 534 "a.y"
+  case 100:
+#line 559 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
        }
     break;
 
-  case 102:
-#line 539 "a.y"
+  case 101:
+#line 565 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+D_SP;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = REG_SP;
        }
     break;
 
-  case 103:
-#line 544 "a.y"
+  case 102:
+#line 571 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
        }
     break;
 
-  case 104:
-#line 550 "a.y"
+  case 103:
+#line 578 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+D_NONE;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = REG_NONE;
                (yyval.addr).index = (yyvsp[(2) - (5)].lval);
                (yyval.addr).scale = (yyvsp[(4) - (5)].lval);
                checkscale((yyval.addr).scale);
        }
     break;
 
-  case 105:
-#line 558 "a.y"
+  case 104:
+#line 587 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_INDIR+(yyvsp[(2) - (8)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).reg = (yyvsp[(2) - (8)].lval);
                (yyval.addr).index = (yyvsp[(5) - (8)].lval);
                (yyval.addr).scale = (yyvsp[(7) - (8)].lval);
                checkscale((yyval.addr).scale);
        }
     break;
 
-  case 106:
-#line 568 "a.y"
+  case 105:
+#line 598 "a.y"
     {
                (yyval.addr) = (yyvsp[(1) - (1)].addr);
        }
     break;
 
-  case 107:
-#line 572 "a.y"
+  case 106:
+#line 602 "a.y"
     {
                (yyval.addr) = (yyvsp[(1) - (6)].addr);
                (yyval.addr).index = (yyvsp[(3) - (6)].lval);
@@ -2393,154 +2404,156 @@ yyreduce:
        }
     break;
 
-  case 108:
-#line 581 "a.y"
+  case 107:
+#line 611 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(4) - (5)].lval);
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).name = (yyvsp[(4) - (5)].lval);
                (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
                (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
        }
     break;
 
-  case 109:
-#line 588 "a.y"
+  case 108:
+#line 619 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_STATIC;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).name = NAME_STATIC;
                (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
                (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
        }
     break;
 
-  case 110:
-#line 596 "a.y"
+  case 109:
+#line 628 "a.y"
     {
                (yyval.lval) = 0;
        }
     break;
 
-  case 111:
-#line 600 "a.y"
+  case 110:
+#line 632 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 112:
-#line 604 "a.y"
+  case 111:
+#line 636 "a.y"
     {
                (yyval.lval) = -(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 114:
-#line 611 "a.y"
+  case 113:
+#line 643 "a.y"
     {
-               (yyval.lval) = D_AUTO;
+               (yyval.lval) = NAME_AUTO;
        }
     break;
 
-  case 117:
-#line 619 "a.y"
+  case 116:
+#line 651 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
        }
     break;
 
-  case 118:
-#line 623 "a.y"
+  case 117:
+#line 655 "a.y"
     {
                (yyval.lval) = -(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 119:
-#line 627 "a.y"
+  case 118:
+#line 659 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 120:
-#line 631 "a.y"
+  case 119:
+#line 663 "a.y"
     {
                (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 121:
-#line 635 "a.y"
+  case 120:
+#line 667 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (3)].lval);
        }
     break;
 
-  case 123:
-#line 642 "a.y"
+  case 122:
+#line 674 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 124:
-#line 646 "a.y"
+  case 123:
+#line 678 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 125:
-#line 650 "a.y"
+  case 124:
+#line 682 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 126:
-#line 654 "a.y"
+  case 125:
+#line 686 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 127:
-#line 658 "a.y"
+  case 126:
+#line 690 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 128:
-#line 662 "a.y"
+  case 127:
+#line 694 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
        }
     break;
 
-  case 129:
-#line 666 "a.y"
+  case 128:
+#line 698 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
        }
     break;
 
-  case 130:
-#line 670 "a.y"
+  case 129:
+#line 702 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 131:
-#line 674 "a.y"
+  case 130:
+#line 706 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 132:
-#line 678 "a.y"
+  case 131:
+#line 710 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
        }
@@ -2548,7 +2561,7 @@ yyreduce:
 
 
 /* Line 1267 of yacc.c.  */
-#line 2552 "y.tab.c"
+#line 2565 "y.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
index d1914554872e43653a8fb7c46a666cb9e28ced42..3ab1bfa0f48523f54c6ac36c1c7752932c08e818 100644 (file)
@@ -118,17 +118,13 @@ typedef union YYSTYPE
 {
        Sym     *sym;
        int32   lval;
-       struct {
-               int32 v1;
-               int32 v2;
-       } con2;
        double  dval;
        char    sval[8];
        Addr    addr;
        Addr2   addr2;
 }
 /* Line 1529 of yacc.c.  */
-#line 132 "y.tab.h"
+#line 128 "y.tab.h"
        YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
index 2735fb6a56603ae3507762fa0aa27cc059e855dd..eabf52ae81c63cfddcc07fb9d9e1ddb4a172422d 100644 (file)
@@ -715,8 +715,9 @@ agen(Node *n, Node *res)
                        // LEAL (n3)(n2*w), n3
                        p1 = gins(ALEAL, &n2, &n3);
                        p1->from.scale = w;
-                       p1->from.index = p1->from.type;
-                       p1->from.type = p1->to.type + D_INDIR;
+                       p1->from.type = TYPE_MEM;
+                       p1->from.index = p1->from.reg;
+                       p1->from.reg = p1->to.reg;
                } else {
                        nodconst(&tmp, types[TUINT32], w);
                        gins(optoas(OMUL, types[TUINT32]), &tmp, &n2);
@@ -805,7 +806,7 @@ igen(Node *n, Node *a, Node *res)
        case OINDREG:
                // Increase the refcount of the register so that igen's caller
                // has to call regfree.
-               if(n->val.u.reg != D_SP)
+               if(n->val.u.reg != REG_SP)
                        reg[n->val.u.reg]++;
                *a = *n;
                return;
@@ -856,7 +857,7 @@ igen(Node *n, Node *a, Node *res)
                fp = structfirst(&flist, getoutarg(n->left->type));
                memset(a, 0, sizeof *a);
                a->op = OINDREG;
-               a->val.u.reg = D_SP;
+               a->val.u.reg = REG_SP;
                a->addable = 1;
                a->xoffset = fp->width;
                a->type = n->type;
@@ -1262,8 +1263,8 @@ sgen(Node *n, Node *res, int64 w)
                return;
        }
 
-       nodreg(&dst, types[tptr], D_DI);
-       nodreg(&src, types[tptr], D_SI);
+       nodreg(&dst, types[tptr], REG_DI);
+       nodreg(&src, types[tptr], REG_SI);
 
        tempname(&tsrc, types[tptr]);
        tempname(&tdst, types[tptr]);
@@ -1293,23 +1294,23 @@ sgen(Node *n, Node *res, int64 w)
                // reverse direction
                gins(ASTD, N, N);               // set direction flag
                if(c > 0) {
-                       gconreg(AADDL, w-1, D_SI);
-                       gconreg(AADDL, w-1, D_DI);
+                       gconreg(AADDL, w-1, REG_SI);
+                       gconreg(AADDL, w-1, REG_DI);
 
-                       gconreg(AMOVL, c, D_CX);
+                       gconreg(AMOVL, c, REG_CX);
                        gins(AREP, N, N);       // repeat
                        gins(AMOVSB, N, N);     // MOVB *(SI)-,*(DI)-
                }
 
                if(q > 0) {
                        if(c > 0) {
-                               gconreg(AADDL, -3, D_SI);
-                               gconreg(AADDL, -3, D_DI);
+                               gconreg(AADDL, -3, REG_SI);
+                               gconreg(AADDL, -3, REG_DI);
                        } else {
-                               gconreg(AADDL, w-4, D_SI);
-                               gconreg(AADDL, w-4, D_DI);
+                               gconreg(AADDL, w-4, REG_SI);
+                               gconreg(AADDL, w-4, REG_DI);
                        }
-                       gconreg(AMOVL, q, D_CX);
+                       gconreg(AMOVL, q, REG_CX);
                        gins(AREP, N, N);       // repeat
                        gins(AMOVSL, N, N);     // MOVL *(SI)-,*(DI)-
                }
@@ -1319,12 +1320,12 @@ sgen(Node *n, Node *res, int64 w)
                gins(ACLD, N, N);       // paranoia.  TODO(rsc): remove?
                // normal direction
                if(q > 128 || (q >= 4 && nacl)) {
-                       gconreg(AMOVL, q, D_CX);
+                       gconreg(AMOVL, q, REG_CX);
                        gins(AREP, N, N);       // repeat
                        gins(AMOVSL, N, N);     // MOVL *(SI)+,*(DI)+
                } else if(q >= 4) {
                        p = gins(ADUFFCOPY, N, N);
-                       p->to.type = D_ADDR;
+                       p->to.type = TYPE_ADDR;
                        p->to.sym = linksym(pkglookup("duffcopy", runtimepkg));
                        // 10 and 128 = magic constants: see ../../runtime/asm_386.s
                        p->to.offset = 10*(128-q);
index dc50a409b35be44d969091a362ab7721f9433233..d9e812f384c615b40441eea9c2ce4cf9d3147aa2 100644 (file)
@@ -73,9 +73,9 @@ cgen64(Node *n, Node *res)
                r = &t2;
        }
 
-       nodreg(&ax, types[TINT32], D_AX);
-       nodreg(&cx, types[TINT32], D_CX);
-       nodreg(&dx, types[TINT32], D_DX);
+       nodreg(&ax, types[TINT32], REG_AX);
+       nodreg(&cx, types[TINT32], REG_CX);
+       nodreg(&dx, types[TINT32], REG_DX);
 
        // Setup for binary operation.
        split64(l, &lo1, &hi1);
@@ -159,10 +159,10 @@ cgen64(Node *n, Node *res)
                } else {
                        gins(AMOVL, &dx, &cx);
                        p1 = gins(ASHLL, ncon(v), &dx);
-                       p1->from.index = D_AX;  // double-width shift
+                       p1->from.index = REG_AX;        // double-width shift
                        p1->from.scale = 0;
                        p1 = gins(ASHLL, ncon(v), &ax);
-                       p1->from.index = D_CX;  // double-width shift
+                       p1->from.index = REG_CX;        // double-width shift
                        p1->from.scale = 0;
                }
                break;
@@ -198,7 +198,7 @@ cgen64(Node *n, Node *res)
                        gins(AMOVL, &lo1, &ax);
                        gins(AMOVL, &hi1, &dx);
                        p1 = gins(ASHLL, ncon(v), &dx);
-                       p1->from.index = D_AX;  // double-width shift
+                       p1->from.index = REG_AX;        // double-width shift
                        p1->from.scale = 0;
                        gins(ASHLL, ncon(v), &ax);
                        break;
@@ -240,7 +240,7 @@ cgen64(Node *n, Node *res)
 
                // general shift
                p1 = gins(ASHLL, &cx, &dx);
-               p1->from.index = D_AX;  // double-width shift
+               p1->from.index = REG_AX;        // double-width shift
                p1->from.scale = 0;
                gins(ASHLL, &cx, &ax);
                patch(p2, pc);
@@ -287,7 +287,7 @@ cgen64(Node *n, Node *res)
                        gins(AMOVL, &lo1, &ax);
                        gins(AMOVL, &hi1, &dx);
                        p1 = gins(ASHRL, ncon(v), &ax);
-                       p1->from.index = D_DX;  // double-width shift
+                       p1->from.index = REG_DX;        // double-width shift
                        p1->from.scale = 0;
                        gins(optoas(ORSH, hi1.type), ncon(v), &dx);
                        break;
@@ -339,7 +339,7 @@ cgen64(Node *n, Node *res)
 
                // general shift
                p1 = gins(ASHRL, &cx, &ax);
-               p1->from.index = D_DX;  // double-width shift
+               p1->from.index = REG_DX;        // double-width shift
                p1->from.scale = 0;
                gins(optoas(ORSH, hi1.type), &cx, &dx);
                patch(p2, pc);
index a0eb3493759605391d578226d870db0c4421beb8..83c323516d68942b7ec0d85eddd35bd1893ff194 100644 (file)
@@ -36,12 +36,67 @@ betypeinit(void)
        widthint = 4;
        widthreg = 4;
 
-       zprog.link = P;
-       zprog.as = AGOK;
-       zprog.from.type = D_NONE;
-       zprog.from.index = D_NONE;
-       zprog.from.scale = 0;
-       zprog.to = zprog.from;
-
        listinit8();
 }
+
+void
+main(int argc, char **argv)
+{
+       arch.thechar = thechar;
+       arch.thestring = thestring;
+       arch.thelinkarch = thelinkarch;
+       arch.typedefs = typedefs;
+       arch.MAXWIDTH = MAXWIDTH;
+       arch.afunclit = afunclit;
+       arch.anyregalloc = anyregalloc;
+       arch.betypeinit = betypeinit;
+       arch.bgen = bgen;
+       arch.cgen = cgen;
+       arch.cgen_asop = cgen_asop;
+       arch.cgen_call = cgen_call;
+       arch.cgen_callinter = cgen_callinter;
+       arch.cgen_ret = cgen_ret;
+       arch.clearfat = clearfat;
+       arch.clearp = clearp;
+       arch.defframe = defframe;
+       arch.dgostringptr = dgostringptr;
+       arch.dgostrlitptr = dgostrlitptr;
+       arch.dsname = dsname;
+       arch.dsymptr = dsymptr;
+       arch.dumpdata = dumpdata;
+       arch.dumpit = dumpit;
+       arch.excise = excise;
+       arch.expandchecks = expandchecks;
+       arch.fixautoused = fixautoused;
+       arch.gclean = gclean;
+       arch.gdata = gdata;
+       arch.gdatacomplex = gdatacomplex;
+       arch.gdatastring = gdatastring;
+       arch.ggloblnod = ggloblnod;
+       arch.ggloblsym = ggloblsym;
+       arch.ginit = ginit;
+       arch.gins = gins;
+       arch.ginscall = ginscall;
+       arch.gjmp = gjmp;
+       arch.gtrack = gtrack;
+       arch.gused = gused;
+       arch.igen = igen;
+       arch.isfat = isfat;
+       arch.linkarchinit = linkarchinit;
+       arch.markautoused = markautoused;
+       arch.naddr = naddr;
+       arch.newplist = newplist;
+       arch.nodarg = nodarg;
+       arch.patch = patch;
+       arch.proginfo = proginfo;
+       arch.regalloc = regalloc;
+       arch.regfree = regfree;
+       arch.regopt = regopt;
+       arch.regtyp = regtyp;
+       arch.sameaddr = sameaddr;
+       arch.smallindir = smallindir;
+       arch.stackaddr = stackaddr;
+       arch.unpatch = unpatch;
+       
+       gcmain(argc, argv);
+}
index 238f9276567d85c3f3c93c51a1acbb798b163dcd..b2b1178a522c0b5d28bb96f724a1ceda0d1348fe 100644 (file)
@@ -9,8 +9,6 @@
 #include "../gc/go.h"
 #include "../8l/8.out.h"
 
-#define TEXTFLAG from.scale
-
 // foptoas flags
 enum
 {
@@ -20,17 +18,10 @@ enum
 };
 
 EXTERN int32   dynloc;
-EXTERN uchar   reg[D_NONE];
+EXTERN uchar   reg[MAXREG];
 EXTERN int32   pcloc;          // instruction counter
 EXTERN Strlit  emptystring;
-EXTERN Prog    zprog;
-EXTERN Node*   newproc;
-EXTERN Node*   deferproc;
-EXTERN Node*   deferreturn;
-EXTERN Node*   panicindex;
-EXTERN Node*   panicslice;
 EXTERN Node*   panicdiv;
-EXTERN Node*   throwreturn;
 extern uint32  unmappedzero;
 
 
@@ -133,3 +124,54 @@ void       datagostring(Strlit*, Addr*);
 void   listinit(void);
 
 void   zaddr(Biobuf*, Addr*, int, int);
+
+void afunclit(Addr*, Node*);
+int anyregalloc(void);
+void betypeinit(void);
+void bgen(Node*, int, int, Prog*);
+void cgen(Node*, Node*);
+void cgen_asop(Node*);
+void cgen_call(Node*, int);
+void cgen_callinter(Node*, Node*, int);
+void cgen_ret(Node*);
+void clearfat(Node*);
+void clearp(Prog*);
+void defframe(Prog*);
+int dgostringptr(Sym*, int, char*);
+int dgostrlitptr(Sym*, int, Strlit*);
+int dsname(Sym*, int, char*, int);
+int dsymptr(Sym*, int, Sym*, int);
+void dumpdata(void);
+void dumpit(char*, Flow*, int);
+void excise(Flow*);
+void expandchecks(Prog*);
+void fixautoused(Prog*);
+void gclean(void);
+void   gdata(Node*, Node*, int);
+void   gdatacomplex(Node*, Mpcplx*);
+void   gdatastring(Node*, Strlit*);
+void   ggloblnod(Node *nam);
+void   ggloblsym(Sym *s, int32 width, int8 flags);
+void ginit(void);
+Prog*  gins(int, Node*, Node*);
+void   ginscall(Node*, int);
+Prog*  gjmp(Prog*);
+void gtrack(Sym*);
+void   gused(Node*);
+void   igen(Node*, Node*, Node*);
+int isfat(Type*);
+void linkarchinit(void);
+void markautoused(Prog*);
+void naddr(Node*, Addr*, int);
+Plist* newplist(void);
+Node* nodarg(Type*, int);
+void patch(Prog*, Prog*);
+void proginfo(ProgInfo*, Prog*);
+void regalloc(Node*, Type*, Node*);
+void regfree(Node*);
+void regopt(Prog*);
+int regtyp(Addr*);
+int sameaddr(Addr*, Addr*);
+int smallindir(Addr*, Addr*);
+int stackaddr(Addr*);
+Prog* unpatch(Prog*);
index d2597b40fc4c297470fce9393b9c015910e6f0f0..2fd4a601ff793450b73c3c6bfa8bcbc79fa5636a 100644 (file)
@@ -9,7 +9,7 @@
 #include "gg.h"
 #include "opt.h"
 
-static Prog *appendpp(Prog*, int, int, vlong, int, vlong);
+static Prog *appendpp(Prog*, int, int, int, vlong, int, int, vlong);
 static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
 
 void
@@ -21,11 +21,10 @@ defframe(Prog *ptxt)
        NodeList *l;
        Node *n;
 
-       // fill in argument size
-       ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
-
-       // fill in final stack size
-       frame = rnd(stksize+maxarg, widthptr);
+       // fill in argument size, stack size
+       ptxt->to.type = TYPE_TEXTSIZE;
+       ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr);
+       frame = rnd(stksize+maxarg, widthreg);
        ptxt->to.offset = frame;
        
        // insert code to zero ambiguously live variables
@@ -68,28 +67,28 @@ zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax)
        if(cnt == 0)
                return p;
        if(*ax == 0) {
-               p = appendpp(p, AMOVL, D_CONST, 0, D_AX, 0);
+               p = appendpp(p, AMOVL, TYPE_CONST, 0, 0, TYPE_REG, REG_AX, 0);
                *ax = 1;
        }
        if(cnt <= 4*widthreg) {
                for(i = 0; i < cnt; i += widthreg) {
-                       p = appendpp(p, AMOVL, D_AX, 0, D_SP+D_INDIR, frame+lo+i);
+                       p = appendpp(p, AMOVL, TYPE_REG, REG_AX, 0, TYPE_MEM, REG_SP, frame+lo+i);
                }
        } else if(!nacl && cnt <= 128*widthreg) {
-               p = appendpp(p, ALEAL, D_SP+D_INDIR, frame+lo, D_DI, 0);
-               p = appendpp(p, ADUFFZERO, D_NONE, 0, D_ADDR, 1*(128-cnt/widthreg));
+               p = appendpp(p, ALEAL, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0);
+               p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_ADDR, 0, 1*(128-cnt/widthreg));
                p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
        } else {
-               p = appendpp(p, AMOVL, D_CONST, cnt/widthreg, D_CX, 0);
-               p = appendpp(p, ALEAL, D_SP+D_INDIR, frame+lo, D_DI, 0);
-               p = appendpp(p, AREP, D_NONE, 0, D_NONE, 0);
-               p = appendpp(p, ASTOSL, D_NONE, 0, D_NONE, 0);
+               p = appendpp(p, AMOVL, TYPE_CONST, 0, cnt/widthreg, TYPE_REG, REG_CX, 0);
+               p = appendpp(p, ALEAL, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0);
+               p = appendpp(p, AREP, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0);
+               p = appendpp(p, ASTOSL, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0);
        }
        return p;
 }
 
 static Prog*   
-appendpp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset)  
+appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset)      
 {
        Prog *q;
        q = mal(sizeof(*q));    
@@ -97,8 +96,10 @@ appendpp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset)
        q->as = as;     
        q->lineno = p->lineno;  
        q->from.type = ftype;   
+       q->from.reg = freg;
        q->from.offset = foffset;       
        q->to.type = ttype;     
+       q->to.reg = treg;
        q->to.offset = toffset; 
        q->link = p->link;      
        p->link = q;    
@@ -114,10 +115,10 @@ markautoused(Prog* p)
                        continue;
 
                if (p->from.node)
-                       p->from.node->used = 1;
+                       ((Node*)(p->from.node))->used = 1;
 
                if (p->to.node)
-                       p->to.node->used = 1;
+                       ((Node*)(p->to.node))->used = 1;
        }
 }
 
@@ -128,26 +129,24 @@ fixautoused(Prog* p)
        Prog **lp;
 
        for (lp=&p; (p=*lp) != P; ) {
-               if (p->as == ATYPE && p->from.node && p->from.type == D_AUTO && !p->from.node->used) {
+               if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
                        *lp = p->link;
                        continue;
                }
-               if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) {
+               if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
                        // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
                        // VARDEFs are interspersed with other code, and a jump might be using the
                        // VARDEF as a target. Replace with a no-op instead. A later pass will remove
                        // the no-ops.
-                       p->to.type = D_NONE;
-                       p->to.node = N;
-                       p->as = ANOP;
+                       nopout(p);
                        continue;
                }
 
-               if (p->from.type == D_AUTO && p->from.node)
-                       p->from.offset += p->from.node->stkdelta;
+               if (p->from.type == TYPE_MEM && p->from.name == NAME_AUTO && p->from.node)
+                       p->from.offset += ((Node*)(p->from.node))->stkdelta;
 
-               if (p->to.type == D_AUTO && p->to.node)
-                       p->to.offset += p->to.node->stkdelta;
+               if (p->to.type == TYPE_MEM && p->to.name == NAME_AUTO && p->to.node)
+                       p->to.offset += ((Node*)(p->to.node))->stkdelta;
 
                lp = &p->link;
        }
@@ -198,17 +197,17 @@ clearfat(Node *nl)
                return;
        }
 
-       nodreg(&n1, types[tptr], D_DI);
+       nodreg(&n1, types[tptr], REG_DI);
        agen(nl, &n1);
-       gconreg(AMOVL, 0, D_AX);
+       gconreg(AMOVL, 0, REG_AX);
 
        if(q > 128 || (q >= 4 && nacl)) {
-               gconreg(AMOVL, q, D_CX);
+               gconreg(AMOVL, q, REG_CX);
                gins(AREP, N, N);       // repeat
                gins(ASTOSL, N, N);     // STOL AL,*(DI)+
        } else if(q >= 4) {
                p = gins(ADUFFZERO, N, N);
-               p->to.type = D_ADDR;
+               p->to.type = TYPE_ADDR;
                p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
                // 1 and 128 = magic constants: see ../../runtime/asm_386.s
                p->to.offset = 1*(128-q);
@@ -265,7 +264,7 @@ ginscall(Node *f, int proc)
                                // x86 NOP 0x90 is really XCHG AX, AX; use that description
                                // because the NOP pseudo-instruction will be removed by
                                // the linker.
-                               nodreg(&reg, types[TINT], D_AX);
+                               nodreg(&reg, types[TINT], REG_AX);
                                gins(AXCHGL, &reg, &reg);
                        }
                        p = gins(ACALL, N, f);
@@ -274,8 +273,8 @@ ginscall(Node *f, int proc)
                                gins(AUNDEF, N, N);
                        break;
                }
-               nodreg(&reg, types[tptr], D_DX);
-               nodreg(&r1, types[tptr], D_BX);
+               nodreg(&reg, types[tptr], REG_DX);
+               nodreg(&r1, types[tptr], REG_BX);
                gmove(f, &reg);
                reg.op = OINDREG;
                gmove(&reg, &r1);
@@ -291,7 +290,7 @@ ginscall(Node *f, int proc)
        case 2: // deferred call (defer)
                memset(&stk, 0, sizeof(stk));
                stk.op = OINDREG;
-               stk.val.u.reg = D_SP;
+               stk.val.u.reg = REG_SP;
                stk.xoffset = 0;
 
                // size of arguments at 0(SP)
@@ -307,7 +306,7 @@ ginscall(Node *f, int proc)
                else
                        ginscall(deferproc, 0);
                if(proc == 2) {
-                       nodreg(&reg, types[TINT32], D_AX);
+                       nodreg(&reg, types[TINT32], REG_AX);
                        gins(ATESTL, &reg, &reg);
                        p = gbranch(AJEQ, T, +1);
                        cgen_ret(N);
@@ -349,7 +348,7 @@ cgen_callinter(Node *n, Node *res, int proc)
        // register to hold its address.
        igen(i, &nodi, res);            // REG = &inter
 
-       nodindreg(&nodsp, types[tptr], D_SP);
+       nodindreg(&nodsp, types[tptr], REG_SP);
        nodsp.xoffset = 0;
        if(proc != 0)
                nodsp.xoffset += 2 * widthptr; // leave room for size & fn
@@ -458,7 +457,7 @@ cgen_callret(Node *n, Node *res)
 
        memset(&nod, 0, sizeof(nod));
        nod.op = OINDREG;
-       nod.val.u.reg = D_SP;
+       nod.val.u.reg = REG_SP;
        nod.addable = 1;
 
        nod.xoffset = fp->width;
@@ -488,7 +487,7 @@ cgen_aret(Node *n, Node *res)
 
        memset(&nod1, 0, sizeof(nod1));
        nod1.op = OINDREG;
-       nod1.val.u.reg = D_SP;
+       nod1.val.u.reg = REG_SP;
        nod1.addable = 1;
 
        nod1.xoffset = fp->width;
@@ -519,7 +518,8 @@ cgen_ret(Node *n)
        genlist(curfn->exit);
        p = gins(ARET, N, N);
        if(n != N && n->op == ORETJMP) {
-               p->to.type = D_EXTERN;
+               p->to.type = TYPE_MEM;
+               p->to.name = NAME_EXTERN;
                p->to.sym = linksym(n->left->sym);
        }
 }
@@ -830,8 +830,8 @@ cgen_div(int op, Node *nl, Node *nr, Node *res)
                t = types[TINT32];
        else
                t = types[TUINT32];
-       savex(D_AX, &ax, &oldax, res, t);
-       savex(D_DX, &dx, &olddx, res, t);
+       savex(REG_AX, &ax, &oldax, res, t);
+       savex(REG_DX, &dx, &olddx, res, t);
        dodiv(op, nl, nr, res, &ax, &dx);
        restx(&dx, &olddx);
        restx(&ax, &oldax);
@@ -875,8 +875,8 @@ cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
        }
 
        memset(&oldcx, 0, sizeof oldcx);
-       nodreg(&cx, types[TUINT32], D_CX);
-       if(reg[D_CX] > 1 && !samereg(&cx, res)) {
+       nodreg(&cx, types[TUINT32], REG_CX);
+       if(reg[REG_CX] > 1 && !samereg(&cx, res)) {
                tempname(&oldcx, types[TUINT32]);
                gmove(&cx, &oldcx);
        }
@@ -885,7 +885,7 @@ cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
                tempname(&nt, nr->type);
                n1 = nt;
        } else {
-               nodreg(&n1, types[TUINT32], D_CX);
+               nodreg(&n1, types[TUINT32], REG_CX);
                regalloc(&n1, nr->type, &n1);           // to hold the shift type in CX
        }
 
@@ -905,7 +905,7 @@ cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
        if(bounded) {
                if(nr->type->width > 4) {
                        // delayed reg alloc
-                       nodreg(&n1, types[TUINT32], D_CX);
+                       nodreg(&n1, types[TUINT32], REG_CX);
                        regalloc(&n1, types[TUINT32], &n1);             // to hold the shift type in CX
                        split64(&nt, &lo, &hi);
                        gmove(&lo, &n1);
@@ -914,7 +914,7 @@ cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
        } else {
                if(nr->type->width > 4) {
                        // delayed reg alloc
-                       nodreg(&n1, types[TUINT32], D_CX);
+                       nodreg(&n1, types[TUINT32], REG_CX);
                        regalloc(&n1, types[TUINT32], &n1);             // to hold the shift type in CX
                        split64(&nt, &lo, &hi);
                        gmove(&lo, &n1);
@@ -1005,18 +1005,18 @@ cgen_hmul(Node *nl, Node *nr, Node *res)
        cgen(nr, &n2);
 
        // multiply.
-       nodreg(&ax, t, D_AX);
+       nodreg(&ax, t, REG_AX);
        gmove(&n2, &ax);
        gins(a, &n1, N);
        regfree(&n2);
 
        if(t->width == 1) {
                // byte multiply behaves differently.
-               nodreg(&ax, t, D_AH);
-               nodreg(&dx, t, D_DX);
+               nodreg(&ax, t, REG_AH);
+               nodreg(&dx, t, REG_DX);
                gmove(&ax, &dx);
        }
-       nodreg(&dx, t, D_DX);
+       nodreg(&dx, t, REG_DX);
        gmove(&dx, res);
 }
 
@@ -1083,8 +1083,8 @@ cgen_float387(Node *n, Node *res)
 
        nl = n->left;
        nr = n->right;
-       nodreg(&f0, nl->type, D_F0);
-       nodreg(&f1, n->type, D_F0+1);
+       nodreg(&f0, nl->type, REG_F0);
+       nodreg(&f1, n->type, REG_F0+1);
        if(nr != N)
                goto flt2;
 
@@ -1223,9 +1223,9 @@ x87:
                a = brrev(a);
        }
 
-       nodreg(&tmp, nr->type, D_F0);
-       nodreg(&n2, nr->type, D_F0 + 1);
-       nodreg(&ax, types[TUINT16], D_AX);
+       nodreg(&tmp, nr->type, REG_F0);
+       nodreg(&n2, nr->type, REG_F0 + 1);
+       nodreg(&ax, types[TUINT16], REG_AX);
        et = simsimtype(nr->type);
        if(et == TFLOAT64) {
                if(nl->ullman > nr->ullman) {
@@ -1336,22 +1336,24 @@ expandchecks(Prog *firstp)
                p1->pc = 9999;
                p2->pc = 9999;
                p->as = ACMPL;
-               p->to.type = D_CONST;
+               p->to.type = TYPE_CONST;
                p->to.offset = 0;
                p1->as = AJNE;
-               p1->from.type = D_CONST;
+               p1->from.type = TYPE_CONST;
                p1->from.offset = 1; // likely
-               p1->to.type = D_BRANCH;
+               p1->to.type = TYPE_BRANCH;
                p1->to.u.branch = p2->link;
                // crash by write to memory address 0.
                // if possible, since we know arg is 0, use 0(arg),
                // which will be shorter to encode than plain 0.
                p2->as = AMOVL;
-               p2->from.type = D_AX;
-               if(regtyp(&p->from))
-                       p2->to.type = p->from.type + D_INDIR;
-               else
-                       p2->to.type = D_INDIR+D_NONE;
+               p2->from.type = TYPE_REG;
+               p2->from.reg = REG_AX;
+               if(regtyp(&p->from)) {
+                       p2->to.type = TYPE_MEM;
+                       p2->to.reg = p->from.reg;
+               } else
+                       p2->to.type = TYPE_MEM;
                p2->to.offset = 0;
        }
 }
index af287f702349df87c1afe619ffcc8233d5e16985..b59d2268dd6686fe7c24d47903708b00f0c11633 100644 (file)
@@ -38,14 +38,14 @@ dsname(Sym *s, int off, char *t, int n)
        Prog *p;
 
        p = gins(ADATA, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.offset = off;
-       p->from.scale = n;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = n;
        p->from.sym = linksym(s);
        
-       p->to.type = D_SCONST;
-       p->to.index = D_NONE;
+       p->to.type = TYPE_SCONST;
        memmove(p->to.u.sval, t, n);
        return off + n;
 }
@@ -60,7 +60,8 @@ datastring(char *s, int len, Addr *a)
        Sym *sym;
        
        sym = stringsym(s, len);
-       a->type = D_EXTERN;
+       a->type = TYPE_MEM;
+       a->name = NAME_EXTERN;
        a->sym = linksym(sym);
        a->node = sym->def;
        a->offset = widthptr+4;  // skip header
@@ -77,7 +78,8 @@ datagostring(Strlit *sval, Addr *a)
        Sym *sym;
        
        sym = stringsym(sval->s, sval->len);
-       a->type = D_EXTERN;
+       a->type = TYPE_MEM;
+       a->name = NAME_EXTERN;
        a->sym = linksym(sym);
        a->node = sym->def;
        a->offset = 0;  // header
@@ -104,14 +106,17 @@ gdata(Node *nam, Node *nr, int wid)
        if(wid == 8 && is64(nr->type)) {
                v = mpgetfix(nr->val.u.xval);
                p = gins(ADATA, nam, nodintconst(v));
-               p->from.scale = 4;
+               p->from3.type = TYPE_CONST;
+               p->from3.offset = 4;
                p = gins(ADATA, nam, nodintconst(v>>32));
-               p->from.scale = 4;
+               p->from3.type = TYPE_CONST;
+               p->from3.offset = 4;
                p->from.offset += 4;
                return;
        }
        p = gins(ADATA, nam, nr);
-       p->from.scale = wid;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = wid;
 }
 
 void
@@ -124,14 +129,16 @@ gdatacomplex(Node *nam, Mpcplx *cval)
        w = types[w]->width;
 
        p = gins(ADATA, nam, N);
-       p->from.scale = w;
-       p->to.type = D_FCONST;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = w;
+       p->to.type = TYPE_FCONST;
        p->to.u.dval = mpgetflt(&cval->real);
 
        p = gins(ADATA, nam, N);
-       p->from.scale = w;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = w;
        p->from.offset += w;
-       p->to.type = D_FCONST;
+       p->to.type = TYPE_FCONST;
        p->to.u.dval = mpgetflt(&cval->imag);
 }
 
@@ -143,14 +150,15 @@ gdatastring(Node *nam, Strlit *sval)
 
        p = gins(ADATA, nam, N);
        datastring(sval->s, sval->len, &p->to);
-       p->from.scale = types[tptr]->width;
-       p->to.index = p->to.type;
-       p->to.type = D_ADDR;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = types[tptr]->width;
+       p->to.type = TYPE_ADDR;
 //print("%P\n", p);
 
        nodconst(&nod1, types[TINT32], sval->len);
        p = gins(ADATA, nam, &nod1);
-       p->from.scale = types[TINT32]->width;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = types[TINT32]->width;
        p->from.offset += types[tptr]->width;
 }
 
@@ -161,15 +169,15 @@ dstringptr(Sym *s, int off, char *str)
 
        off = rnd(off, widthptr);
        p = gins(ADATA, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->from.scale = widthptr;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
 
        datastring(str, strlen(str)+1, &p->to);
-       p->to.index = p->to.type;
-       p->to.type = D_ADDR;
+       p->to.type = TYPE_ADDR;
        p->to.etype = TINT32;
        off += widthptr;
 
@@ -186,14 +194,14 @@ dgostrlitptr(Sym *s, int off, Strlit *lit)
 
        off = rnd(off, widthptr);
        p = gins(ADATA, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->from.scale = widthptr;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
        datagostring(lit, &p->to);
-       p->to.index = p->to.type;
-       p->to.type = D_ADDR;
+       p->to.type = TYPE_ADDR;
        p->to.etype = TINT32;
        off += widthptr;
 
@@ -224,13 +232,14 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
        off = rnd(off, widthptr);
 
        p = gins(ADATA, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->from.scale = widthptr;
-       p->to.type = D_ADDR;
-       p->to.index = D_EXTERN;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
+       p->to.type = TYPE_ADDR;
+       p->to.name = NAME_EXTERN;
        p->to.sym = linksym(x);
        p->to.offset = xoff;
        off += widthptr;
@@ -242,5 +251,7 @@ void
 nopout(Prog *p)
 {
        p->as = ANOP;
+       p->from = zprog.from;
+       p->to = zprog.to;
 }
 
index 3077e0ad9c4aa254de7b7265441f0b5de424d377..dd75e9f092a6921f77b6d997fa211c42d4db3d11 100644 (file)
@@ -45,10 +45,10 @@ void
 clearp(Prog *p)
 {
        p->as = AEND;
-       p->from.type = D_NONE;
-       p->from.index = D_NONE;
-       p->to.type = D_NONE;
-       p->to.index = D_NONE;
+       p->from.type = TYPE_NONE;
+       p->from.index = TYPE_NONE;
+       p->to.type = TYPE_NONE;
+       p->to.index = TYPE_NONE;
        p->pc = pcloc;
        pcloc++;
 }
@@ -120,10 +120,10 @@ gbranch(int as, Type *t, int likely)
 
        USED(t);
        p = prog(as);
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        p->to.u.branch = P;
        if(likely != 0) {
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = likely > 0;
        }
        return p;
@@ -135,7 +135,7 @@ gbranch(int as, Type *t, int likely)
 void
 patch(Prog *p, Prog *to)
 {
-       if(p->to.type != D_BRANCH)
+       if(p->to.type != TYPE_BRANCH)
                fatal("patch: not a branch");
        p->to.u.branch = to;
        p->to.offset = to->pc;
@@ -146,7 +146,7 @@ unpatch(Prog *p)
 {
        Prog *q;
 
-       if(p->to.type != D_BRANCH)
+       if(p->to.type != TYPE_BRANCH)
                fatal("unpatch: not a branch");
        q = p->to.u.branch;
        p->to.u.branch = P;
@@ -197,12 +197,12 @@ ggloblnod(Node *nam)
        p->lineno = nam->lineno;
        p->from.sym->gotype = linksym(ngotype(nam));
        p->to.sym = nil;
-       p->to.type = D_CONST;
+       p->to.type = TYPE_CONST;
        p->to.offset = nam->type->width;
        if(nam->readonly)
-               p->from.scale = RODATA;
+               p->from3.offset = RODATA;
        if(nam->type != T && !haspointers(nam->type))
-               p->from.scale |= NOPTR;
+               p->from3.offset |= NOPTR;
 }
 
 void
@@ -211,13 +211,14 @@ ggloblsym(Sym *s, int32 width, int8 flags)
        Prog *p;
 
        p = gins(AGLOBL, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
+       p->from.index = REG_NONE;
        p->from.sym = linksym(s);
-       p->to.type = D_CONST;
-       p->to.index = D_NONE;
+       p->to.type = TYPE_CONST;
+       p->to.index = REG_NONE;
        p->to.offset = width;
-       p->from.scale = flags;
+       p->from3.offset = flags;
 }
 
 void
@@ -226,8 +227,8 @@ gtrack(Sym *s)
        Prog *p;
        
        p = gins(AUSEFIELD, N, N);
-       p->from.type = D_EXTERN;
-       p->from.index = D_NONE;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
 }
 
@@ -253,9 +254,8 @@ isfat(Type *t)
 void
 afunclit(Addr *a, Node *n)
 {
-       if(a->type == D_ADDR && a->index == D_EXTERN) {
-               a->type = D_EXTERN;
-               a->index = D_NONE;
+       if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
+               a->type = TYPE_MEM;
                a->sym = linksym(n->sym);
        }
 }
@@ -271,7 +271,7 @@ optoas(int op, Type *t)
        if(t == T)
                fatal("optoas: t is nil");
 
-       a = AGOK;
+       a = AXXX;
        switch(CASE(op, simtype[t->etype])) {
        default:
                fatal("optoas: no entry %O-%T", op, t);
@@ -690,7 +690,7 @@ foptoas(int op, Type *t, int flg)
 {
        int et, a;
 
-       a = AGOK;
+       a = AXXX;
        et = simtype[t->etype];
 
        if(use_sse)
@@ -833,16 +833,16 @@ sse:
 
 static int     resvd[] =
 {
-//     D_DI,   // for movstring
-//     D_SI,   // for movstring
+//     REG_DI, // for movstring
+//     REG_SI, // for movstring
 
-       D_AX,   // for divide
-       D_CX,   // for shift
-       D_DX,   // for divide
-       D_SP,   // for stack
+       REG_AX, // for divide
+       REG_CX, // for shift
+       REG_DX, // for divide
+       REG_SP, // for stack
 
-       D_BL,   // because D_BX can be allocated
-       D_BH,
+       REG_BL, // because REG_BX can be allocated
+       REG_BH,
 };
 
 void
@@ -852,15 +852,15 @@ ginit(void)
 
        for(i=0; i<nelem(reg); i++)
                reg[i] = 1;
-       for(i=D_AX; i<=D_DI; i++)
+       for(i=REG_AX; i<=REG_DI; i++)
                reg[i] = 0;
-       for(i=D_X0; i<=D_X7; i++)
+       for(i=REG_X0; i<=REG_X7; i++)
                reg[i] = 0;
        for(i=0; i<nelem(resvd); i++)
                reg[resvd[i]]++;
 }
 
-uintptr regpc[D_NONE];
+uintptr regpc[MAXREG];
 
 void
 gclean(void)
@@ -870,10 +870,10 @@ gclean(void)
        for(i=0; i<nelem(resvd); i++)
                reg[resvd[i]]--;
 
-       for(i=D_AX; i<=D_DI; i++)
+       for(i=REG_AX; i<=REG_DI; i++)
                if(reg[i])
                        yyerror("reg %R left allocated at %ux", i, regpc[i]);
-       for(i=D_X0; i<=D_X7; i++)
+       for(i=REG_X0; i<=REG_X7; i++)
                if(reg[i])
                        yyerror("reg %R left allocated\n", i);
 }
@@ -883,7 +883,7 @@ anyregalloc(void)
 {
        int i, j;
 
-       for(i=D_AX; i<=D_DI; i++) {
+       for(i=REG_AX; i<=REG_DI; i++) {
                if(reg[i] == 0)
                        goto ok;
                for(j=0; j<nelem(resvd); j++)
@@ -892,7 +892,7 @@ anyregalloc(void)
                return 1;
        ok:;
        }
-       for(i=D_X0; i<=D_X7; i++)
+       for(i=REG_X0; i<=REG_X7; i++)
                if(reg[i])
                        return 1;
        return 0;
@@ -928,15 +928,15 @@ regalloc(Node *n, Type *t, Node *o)
        case TBOOL:
                if(o != N && o->op == OREGISTER) {
                        i = o->val.u.reg;
-                       if(i >= D_AX && i <= D_DI)
+                       if(i >= REG_AX && i <= REG_DI)
                                goto out;
                }
-               for(i=D_AX; i<=D_DI; i++)
+               for(i=REG_AX; i<=REG_DI; i++)
                        if(reg[i] == 0)
                                goto out;
 
                fprint(2, "registers allocated at\n");
-               for(i=D_AX; i<=D_DI; i++)
+               for(i=REG_AX; i<=REG_DI; i++)
                        fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
                fatal("out of fixed registers");
                goto err;
@@ -944,19 +944,19 @@ regalloc(Node *n, Type *t, Node *o)
        case TFLOAT32:
        case TFLOAT64:
                if(!use_sse) {
-                       i = D_F0;
+                       i = REG_F0;
                        goto out;
                }
                if(o != N && o->op == OREGISTER) {
                        i = o->val.u.reg;
-                       if(i >= D_X0 && i <= D_X7)
+                       if(i >= REG_X0 && i <= REG_X7)
                                goto out;
                }
-               for(i=D_X0; i<=D_X7; i++)
+               for(i=REG_X0; i<=REG_X7; i++)
                        if(reg[i] == 0)
                                goto out;
                fprint(2, "registers allocated at\n");
-               for(i=D_X0; i<=D_X7; i++)
+               for(i=REG_X0; i<=REG_X7; i++)
                        fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
                fatal("out of floating registers");
        }
@@ -967,11 +967,11 @@ err:
        return;
 
 out:
-       if (i == D_SP)
+       if(i == REG_SP)
                print("alloc SP\n");
        if(reg[i] == 0) {
                regpc[i] = (uintptr)getcallerpc(&n);
-               if(i == D_AX || i == D_CX || i == D_DX || i == D_SP) {
+               if(i == REG_AX || i == REG_CX || i == REG_DX || i == REG_SP) {
                        dump("regalloc-o", o);
                        fatal("regalloc %R", i);
                }
@@ -990,14 +990,14 @@ regfree(Node *n)
        if(n->op != OREGISTER && n->op != OINDREG)
                fatal("regfree: not a register");
        i = n->val.u.reg;
-       if(i == D_SP)
+       if(i == REG_SP)
                return;
        if(i < 0 || i >= nelem(reg))
                fatal("regfree: reg out of range");
        if(reg[i] <= 0)
                fatal("regfree: reg not allocated");
        reg[i]--;
-       if(reg[i] == 0 && (i == D_AX || i == D_CX || i == D_DX || i == D_SP))
+       if(reg[i] == 0 && (i == REG_AX || i == REG_CX || i == REG_DX || i == REG_SP))
                fatal("regfree %R", i);
 }
 
@@ -1088,7 +1088,7 @@ nodarg(Type *t, int fp)
 
        case 0:         // output arg
                n->op = OINDREG;
-               n->val.u.reg = D_SP;
+               n->val.u.reg = REG_SP;
                break;
 
        case 1:         // input arg
@@ -1349,7 +1349,7 @@ gmove(Node *f, Node *t)
        case CASE(TINT64, TUINT8):
        case CASE(TUINT64, TUINT8):
                split64(f, &flo, &fhi);
-               nodreg(&r1, t->type, D_AX);
+               nodreg(&r1, t->type, REG_AX);
                gmove(&flo, &r1);
                gins(AMOVB, &r1, t);
                splitclean();
@@ -1374,7 +1374,7 @@ gmove(Node *f, Node *t)
        case CASE(TINT64, TUINT16):
        case CASE(TUINT64, TUINT16):
                split64(f, &flo, &fhi);
-               nodreg(&r1, t->type, D_AX);
+               nodreg(&r1, t->type, REG_AX);
                gmove(&flo, &r1);
                gins(AMOVW, &r1, t);
                splitclean();
@@ -1392,7 +1392,7 @@ gmove(Node *f, Node *t)
        case CASE(TINT64, TUINT32):
        case CASE(TUINT64, TUINT32):
                split64(f, &flo, &fhi);
-               nodreg(&r1, t->type, D_AX);
+               nodreg(&r1, t->type, REG_AX);
                gmove(&flo, &r1);
                gins(AMOVL, &r1, t);
                splitclean();
@@ -1408,8 +1408,8 @@ gmove(Node *f, Node *t)
                        gins(AMOVL, &flo, &tlo);
                        gins(AMOVL, &fhi, &thi);
                } else {
-                       nodreg(&r1, t->type, D_AX);
-                       nodreg(&r2, t->type, D_DX);
+                       nodreg(&r1, t->type, REG_AX);
+                       nodreg(&r2, t->type, REG_DX);
                        gins(AMOVL, &flo, &r1);
                        gins(AMOVL, &fhi, &r2);
                        gins(AMOVL, &r1, &tlo);
@@ -1469,8 +1469,8 @@ gmove(Node *f, Node *t)
        case CASE(TINT32, TINT64):      // sign extend int32
        case CASE(TINT32, TUINT64):
                split64(t, &tlo, &thi);
-               nodreg(&flo, tlo.type, D_AX);
-               nodreg(&fhi, thi.type, D_DX);
+               nodreg(&flo, tlo.type, REG_AX);
+               nodreg(&fhi, thi.type, REG_DX);
                gmove(f, &flo);
                gins(ACDQ, N, N);
                gins(AMOVL, &flo, &tlo);
@@ -1571,7 +1571,7 @@ floatmove(Node *f, Node *t)
                        cvt = f->type;
                        goto hardmem;
                }
-               nodreg(&r1, types[ft], D_F0);
+               nodreg(&r1, types[ft], REG_F0);
                if(ft == TFLOAT32)
                        gins(AFMOVF, f, &r1);
                else
@@ -1599,9 +1599,9 @@ floatmove(Node *f, Node *t)
                        goto hardmem;
                }
                bignodes();
-               nodreg(&f0, types[ft], D_F0);
-               nodreg(&f1, types[ft], D_F0 + 1);
-               nodreg(&ax, types[TUINT16], D_AX);
+               nodreg(&f0, types[ft], REG_F0);
+               nodreg(&f1, types[ft], REG_F0 + 1);
+               nodreg(&ax, types[TUINT16], REG_AX);
 
                if(ft == TFLOAT32)
                        gins(AFMOVF, f, &f0);
@@ -1663,7 +1663,7 @@ floatmove(Node *f, Node *t)
        case CASE(TINT64, TFLOAT64):
                if(t->op == OREGISTER)
                        goto hardmem;
-               nodreg(&f0, t->type, D_F0);
+               nodreg(&f0, t->type, REG_F0);
                gins(AFMOVV, f, &f0);
                if(tt == TFLOAT32)
                        gins(AFMOVFP, &f0, t);
@@ -1676,16 +1676,16 @@ floatmove(Node *f, Node *t)
                // algorithm is:
                //      if small enough, use native int64 -> float64 conversion.
                //      otherwise, halve (rounding to odd?), convert, and double.
-               nodreg(&ax, types[TUINT32], D_AX);
-               nodreg(&dx, types[TUINT32], D_DX);
-               nodreg(&cx, types[TUINT32], D_CX);
+               nodreg(&ax, types[TUINT32], REG_AX);
+               nodreg(&dx, types[TUINT32], REG_DX);
+               nodreg(&cx, types[TUINT32], REG_CX);
                tempname(&t1, f->type);
                split64(&t1, &tlo, &thi);
                gmove(f, &t1);
                gins(ACMPL, &thi, ncon(0));
                p1 = gbranch(AJLT, T, 0);
                // native
-               nodreg(&r1, types[tt], D_F0);
+               nodreg(&r1, types[tt], REG_F0);
                gins(AFMOVV, &t1, &r1);
                if(tt == TFLOAT32)
                        gins(AFMOVFP, &r1, t);
@@ -1697,7 +1697,7 @@ floatmove(Node *f, Node *t)
                gmove(&tlo, &ax);
                gmove(&thi, &dx);
                p1 = gins(ASHRL, ncon(1), &ax);
-               p1->from.index = D_DX;  // double-width shift DX -> AX
+               p1->from.index = REG_DX;        // double-width shift DX -> AX
                p1->from.scale = 0;
                gins(AMOVL, ncon(0), &cx);
                gins(ASETCC, N, &cx);
@@ -1705,8 +1705,8 @@ floatmove(Node *f, Node *t)
                gins(ASHRL, ncon(1), &dx);
                gmove(&dx, &thi);
                gmove(&ax, &tlo);
-               nodreg(&r1, types[tt], D_F0);
-               nodreg(&r2, types[tt], D_F0 + 1);
+               nodreg(&r1, types[tt], REG_F0);
+               nodreg(&r2, types[tt], REG_F0 + 1);
                gins(AFMOVV, &t1, &r1);
                gins(AFMOVD, &r1, &r1);
                gins(AFADDDP, &r1, &r2);
@@ -1762,7 +1762,7 @@ floatmove_387(Node *f, Node *t)
        case CASE(TFLOAT64, TINT64):
                if(t->op == OREGISTER)
                        goto hardmem;
-               nodreg(&r1, types[ft], D_F0);
+               nodreg(&r1, types[ft], REG_F0);
                if(f->op != OREGISTER) {
                        if(ft == TFLOAT32)
                                gins(AFMOVF, f, &r1);
@@ -1890,7 +1890,7 @@ floatmove_387(Node *f, Node *t)
                if(ismem(f) && ismem(t))
                        goto hard;
                if(f->op == OREGISTER && t->op == OREGISTER) {
-                       if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
+                       if(f->val.u.reg != REG_F0 || t->val.u.reg != REG_F0)
                                goto fatal;
                        return;
                }
@@ -1898,7 +1898,7 @@ floatmove_387(Node *f, Node *t)
                if(ft == TFLOAT64)
                        a = AFMOVD;
                if(ismem(t)) {
-                       if(f->op != OREGISTER || f->val.u.reg != D_F0)
+                       if(f->op != OREGISTER || f->val.u.reg != REG_F0)
                                fatal("gmove %N", f);
                        a = AFMOVFP;
                        if(ft == TFLOAT64)
@@ -1910,7 +1910,7 @@ floatmove_387(Node *f, Node *t)
                if(ismem(f) && ismem(t))
                        goto hard;
                if(f->op == OREGISTER && t->op == OREGISTER) {
-                       if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
+                       if(f->val.u.reg != REG_F0 || t->val.u.reg != REG_F0)
                                goto fatal;
                        return;
                }
@@ -2110,7 +2110,7 @@ gins(int as, Node *f, Node *t)
                fatal("gins MOVF reg, reg");
        if(as == ACVTSD2SS && f && f->op == OLITERAL)
                fatal("gins CVTSD2SS const");
-       if(as == AMOVSD && t && t->op == OREGISTER && t->val.u.reg == D_F0)
+       if(as == AMOVSD && t && t->op == OREGISTER && t->val.u.reg == REG_F0)
                fatal("gins MOVSD into F0");
 
        switch(as) {
@@ -2159,6 +2159,8 @@ gins(int as, Node *f, Node *t)
                dump("bad width to:", t);
                fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
        }
+       if(p->to.type == TYPE_ADDR && w > 0)
+               fatal("bad use of addr: %P", p);
 
        return p;
 }
@@ -2173,8 +2175,10 @@ naddr(Node *n, Addr *a, int canemitcode)
        Sym *s;
 
        a->scale = 0;
-       a->index = D_NONE;
-       a->type = D_NONE;
+       a->reg = REG_NONE;
+       a->index = REG_NONE;
+       a->type = TYPE_NONE;
+       a->name = NAME_NONE;
        a->gotype = nil;
        a->node = N;
        if(n == N)
@@ -2186,12 +2190,14 @@ naddr(Node *n, Addr *a, int canemitcode)
                break;
 
        case OREGISTER:
-               a->type = n->val.u.reg;
+               a->type = TYPE_REG;
+               a->reg = n->val.u.reg;
                a->sym = nil;
                break;
 
        case OINDREG:
-               a->type = n->val.u.reg+D_INDIR;
+               a->type = TYPE_MEM;
+               a->reg = n->val.u.reg;
                a->sym = linksym(n->sym);
                a->offset = n->xoffset;
                break;
@@ -2203,14 +2209,16 @@ naddr(Node *n, Addr *a, int canemitcode)
                a->width = n->left->type->width;
                a->offset = n->xoffset;
                a->sym = linksym(n->left->sym);
-               a->type = D_PARAM;
+               a->type = TYPE_MEM;
+               a->name = NAME_PARAM;
                a->node = n->left->orig;
                break;
 
        case OCLOSUREVAR:
                if(!curfn->needctxt)
                        fatal("closurevar without needctxt");
-               a->type = D_DX+D_INDIR;
+               a->type = TYPE_MEM;
+               a->reg = REG_DX;
                a->offset = n->xoffset;
                a->sym = nil;
                break;
@@ -2246,18 +2254,21 @@ naddr(Node *n, Addr *a, int canemitcode)
                default:
                        fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
                case PEXTERN:
-                       a->type = D_EXTERN;
+                       a->type = TYPE_MEM;
+                       a->name = NAME_EXTERN;
                        break;
                case PAUTO:
-                       a->type = D_AUTO;
+                       a->type = TYPE_MEM;
+                       a->name = NAME_AUTO;
                        break;
                case PPARAM:
                case PPARAMOUT:
-                       a->type = D_PARAM;
+                       a->type = TYPE_MEM;
+                       a->name = NAME_PARAM;
                        break;
                case PFUNC:
-                       a->index = D_EXTERN;
-                       a->type = D_ADDR;
+                       a->type = TYPE_ADDR;
+                       a->name = NAME_EXTERN;
                        s = funcsym(s);
                        break;
                }
@@ -2270,13 +2281,13 @@ naddr(Node *n, Addr *a, int canemitcode)
                        fatal("naddr: const %lT", n->type);
                        break;
                case CTFLT:
-                       a->type = D_FCONST;
+                       a->type = TYPE_FCONST;
                        a->u.dval = mpgetflt(n->val.u.fval);
                        break;
                case CTINT:
                case CTRUNE:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = mpgetfix(n->val.u.xval);
                        break;
                case CTSTR:
@@ -2284,12 +2295,12 @@ naddr(Node *n, Addr *a, int canemitcode)
                        break;
                case CTBOOL:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = n->val.u.bval;
                        break;
                case CTNIL:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = 0;
                        break;
                }
@@ -2297,23 +2308,15 @@ naddr(Node *n, Addr *a, int canemitcode)
 
        case OADDR:
                naddr(n->left, a, canemitcode);
-               if(a->type >= D_INDIR) {
-                       a->type -= D_INDIR;
-                       break;
-               }
-               if(a->type == D_EXTERN || a->type == D_STATIC ||
-                  a->type == D_AUTO || a->type == D_PARAM)
-                       if(a->index == D_NONE) {
-                               a->index = a->type;
-                               a->type = D_ADDR;
-                               break;
-                       }
-               fatal("naddr: OADDR\n");
+               if(a->type != TYPE_MEM)
+                       fatal("naddr: OADDR %D", a);
+               a->type = TYPE_ADDR;
+               break;
        
        case OITAB:
                // itable of interface value
                naddr(n->left, a, canemitcode);
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // len(nil)
                a->etype = tptr;
                a->width = widthptr;
@@ -2322,7 +2325,7 @@ naddr(Node *n, Addr *a, int canemitcode)
        case OSPTR:
                // pointer in a string or slice
                naddr(n->left, a, canemitcode);
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // ptr(nil)
                a->etype = simtype[tptr];
                a->offset += Array_array;
@@ -2332,7 +2335,7 @@ naddr(Node *n, Addr *a, int canemitcode)
        case OLEN:
                // len of string or slice
                naddr(n->left, a, canemitcode);
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // len(nil)
                a->etype = TUINT32;
                a->offset += Array_nel;
@@ -2342,7 +2345,7 @@ naddr(Node *n, Addr *a, int canemitcode)
        case OCAP:
                // cap of string or slice
                naddr(n->left, a, canemitcode);
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // cap(nil)
                a->etype = TUINT32;
                a->offset += Array_cap;
index 5445f91275e792fa8c76534a57e743e017053ded..8378d5d456b997cb00b3efbd44aab0f6f4c05ba1 100644 (file)
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include       "../gc/popt.h"
 
 #define        Z       N
 #define        Adr     Addr
 
-#define        D_HI    D_NONE
-#define        D_LO    D_NONE
-
 #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])
@@ -53,8 +49,6 @@ typedef       struct  Rgn     Rgn;
 extern Node *Z;
 enum
 {
-       D_HI = D_NONE,
-       D_LO = D_NONE,
        CLOAD = 5,
        CREF = 5,
        CINF = 1000,
@@ -195,60 +189,4 @@ int        BtoF(uint32);
 /*
  * prog.c
  */
-typedef struct ProgInfo ProgInfo;
-struct ProgInfo
-{
-       uint32 flags; // the bits below
-       uint32 reguse; // registers implicitly used by this instruction
-       uint32 regset; // registers implicitly set by this instruction
-       uint32 regindex; // registers used by addressing mode
-};
-
-enum
-{
-       // Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
-       Pseudo = 1<<1,
-       
-       // There's nothing to say about the instruction,
-       // but it's still okay to see.
-       OK = 1<<2,
-
-       // Size of right-side write, or right-side read if no write.
-       SizeB = 1<<3,
-       SizeW = 1<<4,
-       SizeL = 1<<5,
-       SizeQ = 1<<6,
-       SizeF = 1<<7, // float aka float32
-       SizeD = 1<<8, // double aka float64
-
-       // Left side (Prog.from): address taken, read, write.
-       LeftAddr = 1<<9,
-       LeftRead = 1<<10,
-       LeftWrite = 1<<11,
-       
-       // Right side (Prog.to): address taken, read, write.
-       RightAddr = 1<<12,
-       RightRead = 1<<13,
-       RightWrite = 1<<14,
-
-       // Set, use, or kill of carry bit.
-       // Kill means we never look at the carry bit after this kind of instruction.
-       SetCarry = 1<<15,
-       UseCarry = 1<<16,
-       KillCarry = 1<<17,
-
-       // Instruction kinds
-       Move = 1<<18, // straight move
-       Conv = 1<<19, // size conversion
-       Cjmp = 1<<20, // conditional jump
-       Break = 1<<21, // breaks control flow (no fallthrough)
-       Call = 1<<22, // function call
-       Jump = 1<<23, // jump
-       Skip = 1<<24, // data instruction
-
-       // Special cases for register use.
-       ShiftCX = 1<<25, // possible shift by CX
-       ImulAXDX = 1<<26, // possible multiply into DX:AX
-};
-
 void proginfo(ProgInfo*, Prog*);
index c9b489cd2bfa26716a7700e3bc35f7ffc2decac9..6c0865a7e83e83d237506ba9bec1f03b59a5960a 100644 (file)
@@ -74,7 +74,7 @@ rnops(Flow *r)
        if(r != nil)
        for(;;) {
                p = r->prog;
-               if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+               if(p->as != ANOP || p->from.type != TYPE_NONE || p->to.type != TYPE_NONE)
                        break;
                r1 = uniqs(r);
                if(r1 == nil)
@@ -110,7 +110,7 @@ peep(Prog *firstp)
                case ALEAL:
                        if(regtyp(&p->to))
                        if(p->from.sym != nil)
-                       if(p->from.index == D_NONE || p->from.index == D_CONST)
+                       if(p->from.index == REG_NONE)
                                conprop(r);
                        break;
 
@@ -120,7 +120,7 @@ peep(Prog *firstp)
                case AMOVSS:
                case AMOVSD:
                        if(regtyp(&p->to))
-                       if(p->from.type == D_CONST || p->from.type == D_FCONST)
+                       if(p->from.type == TYPE_CONST || p->from.type == TYPE_FCONST)
                                conprop(r);
                        break;
                }
@@ -158,7 +158,7 @@ loop1:
                                r1 = rnops(uniqs(r));
                                if(r1 != nil) {
                                        p1 = r1->prog;
-                                       if(p->as == p1->as && p->to.type == p1->from.type){
+                                       if(p->as == p1->as && p->to.type == p1->from.type && p->to.reg == p1->from.reg){
                                                p1->as = AMOVL;
                                                t++;
                                        }
@@ -168,7 +168,7 @@ loop1:
 
                case AADDL:
                case AADDW:
-                       if(p->from.type != D_CONST || needc(p->link))
+                       if(p->from.type != TYPE_CONST || needc(p->link))
                                break;
                        if(p->from.offset == -1){
                                if(p->as == AADDL)
@@ -190,7 +190,7 @@ loop1:
 
                case ASUBL:
                case ASUBW:
-                       if(p->from.type != D_CONST || needc(p->link))
+                       if(p->from.type != TYPE_CONST || needc(p->link))
                                break;
                        if(p->from.offset == -1) {
                                if(p->as == ASUBL)
@@ -239,9 +239,7 @@ excise(Flow *r)
        if(debug['P'] && debug['v'])
                print("%P ===delete===\n", p);
 
-       p->as = ANOP;
-       p->from = zprog.from;
-       p->to = zprog.to;
+       nopout(p);
 
        ostats.ndelmov++;
 }
@@ -249,14 +247,7 @@ excise(Flow *r)
 int
 regtyp(Adr *a)
 {
-       int t;
-
-       t = a->type;
-       if(t >= D_AX && t <= D_DI)
-               return 1;
-       if(t >= D_X0 && t <= D_X7)
-               return 1;
-       return 0;
+       return a->type == TYPE_REG && (REG_AX <= a->reg && a->reg <= REG_DI || REG_X0 <= a->reg && a->reg <= REG_X7);
 }
 
 // movb elimination.
@@ -293,7 +284,7 @@ elimshortmov(Graph *g)
                                p->as = ANOTL;
                                break;
                        }
-                       if(regtyp(&p->from) || p->from.type == D_CONST) {
+                       if(regtyp(&p->from) || p->from.type == TYPE_CONST) {
                                // move or artihmetic into partial register.
                                // from another register or constant can be movl.
                                // we don't switch to 32-bit arithmetic if it can
@@ -398,7 +389,7 @@ subprop(Flow *r0)
                if(info.reguse | info.regset)
                        return 0;
 
-               if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
+               if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type && p->to.reg == v1->reg)
                        goto gotit;
 
                if(copyau(&p->from, v2) || copyau(&p->to, v2))
@@ -412,7 +403,7 @@ 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)
+               if(p->from.type == v2->type && p->from.reg == v2->reg)
                        print(" excise");
                print("\n");
        }
@@ -423,9 +414,9 @@ gotit:
                if(debug['P'])
                        print("%P\n", r->prog);
        }
-       t = v1->type;
-       v1->type = v2->type;
-       v2->type = t;
+       t = v1->reg;
+       v1->reg = v2->reg;
+       v2->reg = t;
        if(debug['P'])
                print("%P last\n", r->prog);
        return 1;
@@ -566,11 +557,11 @@ copyu(Prog *p, Adr *v, Adr *s)
                return 3;
 
        case ACALL:
-               if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
+               if(REGEXT && v->type == TYPE_REG && v->reg <= REGEXT && v->reg > exregoffset)
                        return 2;
-               if(REGARG >= 0 && v->type == (uchar)REGARG)
+               if(REGARG >= 0 && v->type == TYPE_REG && v->reg == (uchar)REGARG)
                        return 2;
-               if(v->type == p->from.type)
+               if(v->type == p->from.type && v->reg == p->from.reg)
                        return 2;
 
                if(s != nil) {
@@ -583,7 +574,7 @@ copyu(Prog *p, Adr *v, Adr *s)
                return 3;
 
        case ATEXT:
-               if(REGARG >= 0 && v->type == (uchar)REGARG)
+               if(REGARG >= 0 && v->type == TYPE_REG && v->reg == (uchar)REGARG)
                        return 3;
                return 0;
        }
@@ -592,7 +583,7 @@ copyu(Prog *p, Adr *v, Adr *s)
                return 0;
        proginfo(&info, p);
 
-       if((info.reguse|info.regset) & RtoB(v->type))
+       if((info.reguse|info.regset) & RtoB(v->reg))
                return 2;
                
        if(info.flags & LeftAddr)
@@ -636,16 +627,16 @@ copyu(Prog *p, Adr *v, Adr *s)
 static int
 copyas(Adr *a, Adr *v)
 {
-       if(D_AL <= a->type && a->type <= D_BL)
+       if(REG_AL <= a->reg && a->reg <= REG_BL)
                fatal("use of byte register");
-       if(D_AL <= v->type && v->type <= D_BL)
+       if(REG_AL <= v->reg && v->reg <= REG_BL)
                fatal("use of byte register");
 
-       if(a->type != v->type)
+       if(a->type != v->type || a->name != v->name || a->reg != v->reg)
                return 0;
        if(regtyp(v))
                return 1;
-       if(v->type == D_AUTO || v->type == D_PARAM)
+       if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM))
                if(v->offset == a->offset)
                        return 1;
        return 0;
@@ -654,11 +645,11 @@ copyas(Adr *a, Adr *v)
 int
 sameaddr(Addr *a, Addr *v)
 {
-       if(a->type != v->type)
+       if(a->type != v->type || a->name != v->name || a->reg != v->reg)
                return 0;
        if(regtyp(v))
                return 1;
-       if(v->type == D_AUTO || v->type == D_PARAM)
+       if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM))
                if(v->offset == a->offset)
                        return 1;
        return 0;
@@ -674,9 +665,9 @@ copyau(Adr *a, Adr *v)
        if(copyas(a, v))
                return 1;
        if(regtyp(v)) {
-               if(a->type-D_INDIR == v->type)
+               if(a->type == TYPE_MEM && a->reg == v->reg)
                        return 1;
-               if(a->index == v->type)
+               if(a->index == v->reg)
                        return 1;
        }
        return 0;
@@ -689,28 +680,28 @@ copyau(Adr *a, Adr *v)
 static int
 copysub(Adr *a, Adr *v, Adr *s, int f)
 {
-       int t;
+       int reg;
 
        if(copyas(a, v)) {
-               t = s->type;
-               if(t >= D_AX && t <= D_DI || t >= D_X0 && t <= D_X7) {
+               reg = s->reg;
+               if(reg >= REG_AX && reg <= REG_DI || reg >= REG_X0 && reg <= REG_X7) {
                        if(f)
-                               a->type = t;
+                               a->reg = reg;
                }
                return 0;
        }
        if(regtyp(v)) {
-               t = v->type;
-               if(a->type == t+D_INDIR) {
-                       if((s->type == D_BP) && a->index != D_NONE)
+               reg = v->reg;
+               if(a->type == TYPE_MEM && a->reg == reg) {
+                       if((s->reg == REG_BP) && a->index != TYPE_NONE)
                                return 1;       /* can't use BP-base with index */
                        if(f)
-                               a->type = s->type+D_INDIR;
+                               a->reg = s->reg;
 //                     return 0;
                }
-               if(a->index == t) {
+               if(a->index == reg) {
                        if(f)
-                               a->index = s->type;
+                               a->index = s->reg;
                        return 0;
                }
                return 0;
@@ -751,10 +742,11 @@ loop:
        case 3: // set
                if(p->as == p0->as)
                if(p->from.type == p0->from.type)
+               if(p->from.reg == p0->from.reg)
                if(p->from.node == p0->from.node)
                if(p->from.offset == p0->from.offset)
                if(p->from.scale == p0->from.scale)
-               if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval)
+               if(p->from.type == TYPE_FCONST && p->from.u.dval == p0->from.u.dval)
                if(p->from.index == p0->from.index) {
                        excise(r);
                        goto loop;
@@ -767,13 +759,13 @@ int
 smallindir(Addr *a, Addr *reg)
 {
        return regtyp(reg) &&
-               a->type == D_INDIR + reg->type &&
-               a->index == D_NONE &&
+               a->type == TYPE_MEM && a->reg == reg->reg &&
+               a->index == REG_NONE &&
                0 <= a->offset && a->offset < 4096;
 }
 
 int
 stackaddr(Addr *a)
 {
-       return regtyp(a) && a->type == D_SP;
+       return a->type == TYPE_REG && a->reg == REG_SP;
 }
index 8eed67f6d2432befafd6654449a880bfa3134de0..8a7371b5c409e9ac01d80705a60bfd4455d9ca0c 100644 (file)
@@ -8,15 +8,15 @@
 #include "opt.h"
 
 // Matches real RtoB but can be used in global initializer.
-#define RtoB(r) (1<<((r)-D_AX))
+#define RtoB(r) (1<<((r)-REG_AX))
 
 enum {
-       AX = RtoB(D_AX),
-       BX = RtoB(D_BX),
-       CX = RtoB(D_CX),
-       DX = RtoB(D_DX),
-       DI = RtoB(D_DI),
-       SI = RtoB(D_SI),
+       AX = RtoB(REG_AX),
+       BX = RtoB(REG_BX),
+       CX = RtoB(REG_CX),
+       DX = RtoB(REG_DX),
+       DI = RtoB(REG_DI),
+       SI = RtoB(REG_SI),
        
        LeftRdwr = LeftRead | LeftWrite,
        RightRdwr = RightRead | RightWrite,
@@ -325,11 +325,11 @@ proginfo(ProgInfo *info, Prog *p)
        if(info->flags == 0)
                fatal("unknown instruction %P", p);
 
-       if((info->flags & ShiftCX) && p->from.type != D_CONST)
+       if((info->flags & ShiftCX) && p->from.type != TYPE_CONST)
                info->reguse |= CX;
 
        if(info->flags & ImulAXDX) {
-               if(p->to.type == D_NONE) {
+               if(p->to.type == TYPE_NONE) {
                        info->reguse |= AX;
                        info->regset |= AX | DX;
                } else {
@@ -338,12 +338,12 @@ proginfo(ProgInfo *info, Prog *p)
        }
 
        // Addressing makes some registers used.
-       if(p->from.type >= D_INDIR)
-               info->regindex |= RtoB(p->from.type-D_INDIR);
-       if(p->from.index != D_NONE)
+       if(p->from.type == TYPE_MEM && p->from.name == NAME_NONE)
+               info->regindex |= RtoB(p->from.reg);
+       if(p->from.index != REG_NONE)
                info->regindex |= RtoB(p->from.index);
-       if(p->to.type >= D_INDIR)
-               info->regindex |= RtoB(p->to.type-D_INDIR);
-       if(p->to.index != D_NONE)
+       if(p->to.type == TYPE_MEM && p->to.name == NAME_NONE)
+               info->regindex |= RtoB(p->to.reg);
+       if(p->to.index != REG_NONE)
                info->regindex |= RtoB(p->to.index);
 }
index d7394a16d254c7f4cd8ad33c07a38892ffa7ec00..7d2de5354937166046a87221777fbca27af5c21a 100644 (file)
@@ -104,7 +104,7 @@ regopt(Prog *firstp)
 
        if(first) {
                fmtinstall('Q', Qconv);
-               exregoffset = D_DI;     // no externals
+               exregoffset = REG_DI;   // no externals
                first = 0;
        }
 
@@ -123,7 +123,7 @@ regopt(Prog *firstp)
                var[i].node = regnodes[i];
        }
 
-       regbits = RtoB(D_SP);
+       regbits = RtoB(REG_SP);
        for(z=0; z<BITS; z++) {
                externs.b[z] = 0;
                params.b[z] = 0;
@@ -155,7 +155,7 @@ regopt(Prog *firstp)
                proginfo(&info, p);
 
                // Avoid making variables for direct-called functions.
-               if(p->as == ACALL && p->to.type == D_EXTERN)
+               if(p->as == ACALL && p->to.type == TYPE_MEM && p->to.name == NAME_EXTERN)
                        continue;
 
                r->use1.b[0] |= info.reguse | info.regindex;
@@ -227,7 +227,7 @@ regopt(Prog *firstp)
        }
        for(r = firstr; r != R; r = (Reg*)r->f.link) {
                p = r->f.prog;
-               if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
+               if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
                        active++;
                        walkvardef(p->to.node, r, active);
                }
@@ -401,17 +401,17 @@ brk:
        for(p=firstp; p!=P; p=p->link) {
                while(p->link != P && p->link->as == ANOP)
                        p->link = p->link->link;
-               if(p->to.type == D_BRANCH)
+               if(p->to.type == TYPE_BRANCH)
                        while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
                                p->to.u.branch = p->to.u.branch->link;
        }
 
        if(!use_sse)
        for(p=firstp; p!=P; p=p->link) {
-               if(p->from.type >= D_X0 && p->from.type <= D_X7)
-                       fatal("invalid use of %R with GO386=387: %P", p->from.type, p);
-               if(p->to.type >= D_X0 && p->to.type <= D_X7)
-                       fatal("invalid use of %R with GO386=387: %P", p->to.type, p);
+               if(p->from.reg >= REG_X0 && p->from.reg <= REG_X7)
+                       fatal("invalid use of %R with GO386=387: %P", p->from.reg, p);
+               if(p->to.reg >= REG_X0 && p->to.reg <= REG_X7)
+                       fatal("invalid use of %R with GO386=387: %P", p->to.reg, p);
        }
 
        if(debug['R']) {
@@ -492,7 +492,8 @@ addmove(Reg *r, int bn, int rn, int f)
        a = &p1->to;
        a->offset = v->offset;
        a->etype = v->etype;
-       a->type = v->name;
+       a->type = TYPE_MEM;
+       a->name = v->name;
        a->node = v->node;
        a->sym = linksym(v->node->sym);
 
@@ -525,11 +526,14 @@ addmove(Reg *r, int bn, int rn, int f)
                break;
        }
 
-       p1->from.type = rn;
+       p1->from.type = TYPE_REG;
+       p1->from.reg = rn;
+       p1->from.name = 0;
        if(!f) {
                p1->from = *a;
                *a = zprog.from;
-               a->type = rn;
+               a->type = TYPE_REG;
+               a->reg = rn;
                if(v->etype == TUINT8)
                        p1->as = AMOVB;
                if(v->etype == TUINT16)
@@ -546,18 +550,16 @@ doregbits(int r)
        uint32 b;
 
        b = 0;
-       if(r >= D_INDIR)
-               r -= D_INDIR;
-       if(r >= D_AX && r <= D_DI)
+       if(r >= REG_AX && r <= REG_DI)
                b |= RtoB(r);
        else
-       if(r >= D_AL && r <= D_BL)
-               b |= RtoB(r-D_AL+D_AX);
+       if(r >= REG_AL && r <= REG_BL)
+               b |= RtoB(r-REG_AL+REG_AX);
        else
-       if(r >= D_AH && r <= D_BH)
-               b |= RtoB(r-D_AH+D_AX);
+       if(r >= REG_AH && r <= REG_BH)
+               b |= RtoB(r-REG_AH+REG_AX);
        else
-       if(r >= D_X0 && r <= D_X0+7)
+       if(r >= REG_X0 && r <= REG_X0+7)
                b |= FtoB(r);
        return b;
 }
@@ -580,7 +582,7 @@ Bits
 mkvar(Reg *r, Adr *a)
 {
        Var *v;
-       int i, t, n, et, z, w, flag, regu;
+       int i, n, et, z, w, flag, regu;
        int32 o;
        Bits bit;
        Node *node;
@@ -588,36 +590,40 @@ mkvar(Reg *r, Adr *a)
        /*
         * mark registers used
         */
-       t = a->type;
-       if(t == D_NONE)
+       if(a->type == TYPE_NONE)
                goto none;
 
        if(r != R)
                r->use1.b[0] |= doregbits(a->index);
 
-       switch(t) {
+       switch(a->type) {
        default:
-               regu = doregbits(t);
+               regu = doregbits(a->reg);
                if(regu == 0)
                        goto none;
                bit = zbits;
                bit.b[0] = regu;
                return bit;
 
-       case D_ADDR:
-               a->type = a->index;
+       case TYPE_ADDR:
+               a->type = TYPE_MEM;
                bit = mkvar(r, a);
                setaddrs(bit);
-               a->type = t;
+               a->type = TYPE_ADDR;
                ostats.naddr++;
                goto none;
 
-       case D_EXTERN:
-       case D_STATIC:
-       case D_PARAM:
-       case D_AUTO:
-               n = t;
-               break;
+       case TYPE_MEM:
+               switch(a->name) {
+               default:
+                       goto none;
+               case NAME_EXTERN:
+               case NAME_STATIC:
+               case NAME_PARAM:
+               case NAME_AUTO:
+                       n = a->name;
+                       break;
+               }
        }
 
        node = a->node;
@@ -693,10 +699,10 @@ mkvar(Reg *r, Adr *a)
        node->opt = v;
 
        bit = blsh(i);
-       if(n == D_EXTERN || n == D_STATIC)
+       if(n == NAME_EXTERN || n == NAME_STATIC)
                for(z=0; z<BITS; z++)
                        externs.b[z] |= bit.b[z];
-       if(n == D_PARAM)
+       if(n == NAME_PARAM)
                for(z=0; z<BITS; z++)
                        params.b[z] |= bit.b[z];
                
@@ -967,13 +973,13 @@ paint1(Reg *r, int bn)
                        if(r->use1.b[z] & bb) {
                                change += CREF * r->f.loop;
                                if(p->as == AFMOVL || p->as == AFMOVW)
-                                       if(BtoR(bb) != D_F0)
+                                       if(BtoR(bb) != REG_F0)
                                                change = -CINF;
                        }
                        if((r->use2.b[z]|r->set.b[z]) & bb) {
                                change += CREF * r->f.loop;
                                if(p->as == AFMOVL || p->as == AFMOVW)
-                                       if(BtoR(bb) != D_F0)
+                                       if(BtoR(bb) != REG_F0)
                                                change = -CINF;
                        }
                }
@@ -981,7 +987,7 @@ paint1(Reg *r, int bn)
                if(STORE(r) & r->regdiff.b[z] & bb) {
                        change -= CLOAD * r->f.loop;
                        if(p->as == AFMOVL || p->as == AFMOVW)
-                               if(BtoR(bb) != D_F0)
+                               if(BtoR(bb) != REG_F0)
                                        change = -CINF;
                }
 
@@ -1139,7 +1145,9 @@ addreg(Adr *a, int rn)
        a->sym = nil;
        a->node = nil;
        a->offset = 0;
-       a->type = rn;
+       a->type = TYPE_REG;
+       a->reg = rn;
+       a->name = 0;
 
        ostats.ncvtreg++;
 }
@@ -1148,9 +1156,9 @@ uint32
 RtoB(int r)
 {
 
-       if(r < D_AX || r > D_DI)
+       if(r < REG_AX || r > REG_DI)
                return 0;
-       return 1L << (r-D_AX);
+       return 1L << (r-REG_AX);
 }
 
 int
@@ -1160,15 +1168,15 @@ BtoR(uint32 b)
        b &= 0xffL;
        if(b == 0)
                return 0;
-       return bitno(b) + D_AX;
+       return bitno(b) + REG_AX;
 }
 
 uint32
 FtoB(int f)
 {
-       if(f < D_X0 || f > D_X7)
+       if(f < REG_X0 || f > REG_X7)
                return 0;
-       return 1L << (f - D_X0 + 8);
+       return 1L << (f - REG_X0 + 8);
 }
 
 int
@@ -1177,7 +1185,7 @@ BtoF(uint32 b)
        b &= 0xFF00L;
        if(b == 0)
                return 0;
-       return bitno(b) - 8 + D_X0;
+       return bitno(b) - 8 + REG_X0;
 }
 
 void
index 3aa4775bfb52309c77af6d84cd88e1a5530183a1..28d7dab7fb12a6a884fb23494af1a3b833e5a345 100644 (file)
@@ -34,8 +34,7 @@
 
 enum
 {
-       AXXX,
-       AAAA,
+       AAAA = A_ARCHSPECIFIC,
        AAAD,
        AAAM,
        AAAS,
@@ -65,7 +64,6 @@ enum
        ABTSL,
        ABTSW,
        ABYTE,
-       ACALL,
        ACLC,
        ACLD,
        ACLI,
@@ -79,7 +77,6 @@ enum
        ACMPSW,
        ADAA,
        ADAS,
-       ADATA,
        ADECB,
        ADECL,
        ADECW,
@@ -87,9 +84,6 @@ enum
        ADIVL,
        ADIVW,
        AENTER,
-       AGLOBL,
-       AGOK,
-       AHISTORY,
        AHLT,
        AIDIVB,
        AIDIVL,
@@ -122,7 +116,6 @@ enum
        AJLS,
        AJLT,
        AJMI,
-       AJMP,
        AJNE,
        AJOC,
        AJOS,
@@ -162,11 +155,9 @@ enum
        AMULB,
        AMULL,
        AMULW,
-       ANAME,
        ANEGB,
        ANEGL,
        ANEGW,
-       ANOP,
        ANOTB,
        ANOTL,
        ANOTW,
@@ -200,7 +191,6 @@ enum
        ARCRW,
        AREP,
        AREPN,
-       ARET,
        AROLB,
        AROLL,
        AROLW,
@@ -257,7 +247,6 @@ enum
        ATESTB,
        ATESTL,
        ATESTW,
-       ATEXT,
        AVERR,
        AVERW,
        AWAIT,
@@ -382,12 +371,8 @@ enum
        AFYL2X,
        AFYL2XP1,
 
-       AEND,
 
-       ADYNT_,
-       AINIT_,
 
-       ASIGNAME,
 
        ACMPXCHGB,
        ACMPXCHGL,
@@ -457,7 +442,6 @@ enum
        
        ABSWAPL,
        
-       AUNDEF,
 
        // SSE2
        AADDPD,
@@ -577,87 +561,64 @@ enum
        APINSRD,
        APSHUFB,
 
-       AUSEFIELD,
-       ATYPE,
-       AFUNCDATA,
-       APCDATA,
-       ACHECKNIL,
-       AVARDEF,
-       AVARKILL,
-       ADUFFCOPY,
-       ADUFFZERO,
        
        ALAST
 };
 
 enum
 {
-       D_AL            = 0,
-       D_CL,
-       D_DL,
-       D_BL,
-
-       D_AH            = 4,
-       D_CH,
-       D_DH,
-       D_BH,
-
-       D_AX            = 8,
-       D_CX,
-       D_DX,
-       D_BX,
-       D_SP,
-       D_BP,
-       D_SI,
-       D_DI,
-
-       D_F0            = 16,
-       D_F7            = D_F0 + 7,
-
-       D_CS            = 24,
-       D_SS,
-       D_DS,
-       D_ES,
-       D_FS,
-       D_GS,
-
-       D_GDTR,         /* global descriptor table register */
-       D_IDTR,         /* interrupt descriptor table register */
-       D_LDTR,         /* local descriptor table register */
-       D_MSW,          /* machine status word */
-       D_TASK,         /* task register */
-
-       D_CR            = 35,
-       D_DR            = 43,
-       D_TR            = 51,
-
-       D_X0            = 59,
-       D_X1,
-       D_X2,
-       D_X3,
-       D_X4,
-       D_X5,
-       D_X6,
-       D_X7,
+       REG_NONE        = 0,
+
+       REG_AL          = 0+16,
+       REG_CL,
+       REG_DL,
+       REG_BL,
+
+       REG_AH          = 4+16,
+       REG_CH,
+       REG_DH,
+       REG_BH,
+
+       REG_AX          = 8+16,
+       REG_CX,
+       REG_DX,
+       REG_BX,
+       REG_SP,
+       REG_BP,
+       REG_SI,
+       REG_DI,
+
+       REG_F0          = 16+16,
+       REG_F7          = REG_F0 + 7+16,
+
+       REG_CS          = 24+16,
+       REG_SS,
+       REG_DS,
+       REG_ES,
+       REG_FS,
+       REG_GS,
+
+       REG_GDTR,               /* global descriptor table register */
+       REG_IDTR,               /* interrupt descriptor table register */
+       REG_LDTR,               /* local descriptor table register */
+       REG_MSW,                /* machine status word */
+       REG_TASK,               /* task register */
+
+       REG_CR          = 35+16,
+       REG_DR          = 43+16,
+       REG_TR          = 51+16,
+
+       REG_X0          = 59+16,
+       REG_X1,
+       REG_X2,
+       REG_X3,
+       REG_X4,
+       REG_X5,
+       REG_X6,
+       REG_X7,
        
-       D_TLS           = 67,
-       D_NONE          = 68,
-
-       D_BRANCH        = 69,
-       D_EXTERN        = 70,
-       D_STATIC        = 71,
-       D_AUTO          = 72,
-       D_PARAM         = 73,
-       D_CONST         = 74,
-       D_FCONST        = 75,
-       D_SCONST        = 76,
-       D_ADDR          = 77,
-
-       D_INDIR,        /* additive */
-
-       D_CONST2 = D_INDIR+D_INDIR,
-
-       D_LAST,
+       REG_TLS         = 67+16,
+       MAXREG          = 68+16,
 
        T_TYPE          = 1<<0,
        T_INDEX         = 1<<1,
@@ -669,10 +630,10 @@ enum
        T_GOTYPE        = 1<<7,
 
        REGARG          = -1,
-       REGRET          = D_AX,
-       FREGRET         = D_F0,
-       REGSP           = D_SP,
-       REGTMP          = D_DI,
+       REGRET          = REG_AX,
+       FREGRET         = REG_F0,
+       REGSP           = REG_SP,
+       REGTMP          = REG_DI,
 };
 
 /*
index 7a01fc9479edcc9e22aa348d74563d533720e435..a2280b1e986b3a823955e551c65b75eb755ce4ea 100644 (file)
@@ -126,6 +126,7 @@ EXTERN      int32   thunk;
 EXTERN Biobuf  obuf;
 EXTERN Link*   ctxt;
 EXTERN Biobuf  bstdout;
+EXTERN Prog*   lastpc;
 
 void*  alloc(int32);
 void*  allocn(void*, int32, int32);
index b366146156af610e9bf4a52c8325888f94148340..71d714b0d149a7facf5f91778b004a7b23c887ee 100644 (file)
@@ -50,7 +50,7 @@
 %left  '*' '/' '%'
 %token <lval>  LMOVW LMOVB LABS LLOGW LSHW LADDW LCMP LCROP
 %token <lval>  LBRA LFMOV LFCONV LFCMP LFADD LFMA LTRAP LXORW
-%token <lval>  LNOP LEND LRETT LWORD LTEXT LDATA LRETRN
+%token <lval>  LNOP LEND LRETT LWORD LTEXT LGLOBL LDATA LRETRN
 %token <lval>  LCONST LSP LSB LFP LPC LCREG LFLUSH
 %token <lval>  LREG LFREG LR LCR LF LFPSCR
 %token <lval>  LLR LCTR LSPR LSPREG LSEG LMSR
@@ -60,8 +60,8 @@
 %token <sval>  LSCONST
 %token <sym>   LNAME LLAB LVAR
 %type  <lval>  con expr pointer offset sreg
-%type  <addr>  addr rreg regaddr name creg freg xlreg lr ctr
-%type  <addr>  imm ximm fimm rel psr lcr cbit fpscr fpscrf msr mask
+%type  <addr>  addr rreg regaddr name creg freg xlreg lr ctr textsize
+%type  <addr>  imm ximm fimm rel psr lcr cbit fpscr msr mask
 %%
 prog:
 |      prog line
@@ -101,107 +101,103 @@ inst:
  */
        LMOVW rreg ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW addr ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW regaddr ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVB rreg ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVB addr ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVB regaddr ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 /*
  * load floats
  */
 |      LFMOV addr ',' freg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LFMOV regaddr ',' freg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LFMOV fimm ',' freg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LFMOV freg ',' freg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LFMOV freg ',' addr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LFMOV freg ',' regaddr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 /*
  * store ints and bytes
  */
 |      LMOVW rreg ',' addr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW rreg ',' regaddr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVB rreg ',' addr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVB rreg ',' regaddr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 /*
  * store floats
  */
 |      LMOVW freg ',' addr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW freg ',' regaddr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 /*
  * floating point status
  */
 |      LMOVW fpscr ',' freg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW freg ','  fpscr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW freg ',' imm ',' fpscr
        {
-               outgcode($1, &$2, NREG, &$4, &$6);
+               outgcode($1, &$2, 0, &$4, &$6);
        }
 |      LMOVW fpscr ',' creg
        {
-               outcode($1, &$2, NREG, &$4);
-       }
-|      LMOVW imm ',' fpscrf
-       {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMTFSB imm ',' con
        {
@@ -212,15 +208,15 @@ inst:
  */
 |      LMOVW rreg ',' imm ',' lcr
        {
-               outgcode($1, &$2, NREG, &$4, &$6);
+               outgcode($1, &$2, 0, &$4, &$6);
        }
 |      LMOVW rreg ',' creg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW rreg ',' lcr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 /*
  * integer operations
@@ -238,15 +234,15 @@ inst:
        }
 |      LADDW rreg ',' imm ',' rreg
        {
-               outgcode($1, &$2, NREG, &$4, &$6);
+               outgcode($1, &$2, 0, &$4, &$6);
        }
 |      LADDW rreg ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LADDW imm ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LLOGW rreg ',' sreg ',' rreg
        {
@@ -254,7 +250,7 @@ inst:
        }
 |      LLOGW rreg ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LSHW rreg ',' sreg ',' rreg
        {
@@ -262,7 +258,7 @@ inst:
        }
 |      LSHW rreg ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LSHW imm ',' sreg ',' rreg
        {
@@ -270,15 +266,15 @@ inst:
        }
 |      LSHW imm ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LABS rreg ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LABS rreg
        {
-               outcode($1, &$2, NREG, &$2);
+               outcode($1, &$2, 0, &$2);
        }
 /*
  * multiply-accumulate
@@ -292,11 +288,11 @@ inst:
  */
 |      LMOVW imm ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW ximm ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 /*
  * condition register operations
@@ -315,35 +311,35 @@ inst:
  */
 |      LMOVW creg ',' creg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW psr ',' creg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW lcr ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW psr ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW xlreg ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW rreg ',' xlreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW creg ',' psr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVW rreg ',' psr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 /*
  * branch, branch conditional
@@ -352,39 +348,39 @@ inst:
  */
 |      LBRA rel
        {
-               outcode($1, &nullgen, NREG, &$2);
+               outcode($1, &nullgen, 0, &$2);
        }
 |      LBRA addr
        {
-               outcode($1, &nullgen, NREG, &$2);
+               outcode($1, &nullgen, 0, &$2);
        }
 |      LBRA '(' xlreg ')'
        {
-               outcode($1, &nullgen, NREG, &$3);
+               outcode($1, &nullgen, 0, &$3);
        }
 |      LBRA ',' rel
        {
-               outcode($1, &nullgen, NREG, &$3);
+               outcode($1, &nullgen, 0, &$3);
        }
 |      LBRA ',' addr
        {
-               outcode($1, &nullgen, NREG, &$3);
+               outcode($1, &nullgen, 0, &$3);
        }
 |      LBRA ',' '(' xlreg ')'
        {
-               outcode($1, &nullgen, NREG, &$4);
+               outcode($1, &nullgen, 0, &$4);
        }
 |      LBRA creg ',' rel
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LBRA creg ',' addr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LBRA creg ',' '(' xlreg ')'
        {
-               outcode($1, &$2, NREG, &$5);
+               outcode($1, &$2, 0, &$5);
        }
 |      LBRA con ',' rel
        {
@@ -402,25 +398,25 @@ inst:
        {
                Addr g;
                g = nullgen;
-               g.type = D_CONST;
+               g.type = TYPE_CONST;
                g.offset = $2;
-               outcode($1, &g, $4, &$6);
+               outcode($1, &g, REG_R0+$4, &$6);
        }
 |      LBRA con ',' con ',' addr
        {
                Addr g;
                g = nullgen;
-               g.type = D_CONST;
+               g.type = TYPE_CONST;
                g.offset = $2;
-               outcode($1, &g, $4, &$6);
+               outcode($1, &g, REG_R0+$4, &$6);
        }
 |      LBRA con ',' con ',' '(' xlreg ')'
        {
                Addr g;
                g = nullgen;
-               g.type = D_CONST;
+               g.type = TYPE_CONST;
                g.offset = $2;
-               outcode($1, &g, $4, &$7);
+               outcode($1, &g, REG_R0+$4, &$7);
        }
 /*
  * conditional trap
@@ -435,22 +431,22 @@ inst:
        }
 |      LTRAP rreg comma
        {
-               outcode($1, &$2, NREG, &nullgen);
+               outcode($1, &$2, 0, &nullgen);
        }
 |      LTRAP comma
        {
-               outcode($1, &nullgen, NREG, &nullgen);
+               outcode($1, &nullgen, 0, &nullgen);
        }
 /*
  * floating point operate
  */
 |      LFCONV freg ',' freg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LFADD freg ',' freg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LFADD freg ',' freg ',' freg
        {
@@ -462,7 +458,7 @@ inst:
        }
 |      LFCMP freg ',' freg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LFCMP freg ',' freg ',' creg
        {
@@ -473,11 +469,11 @@ inst:
  */
 |      LCMP rreg ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LCMP rreg ',' imm
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LCMP rreg ',' rreg ',' creg
        {
@@ -511,11 +507,11 @@ inst:
  */
 |      LMOVMW addr ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LMOVMW rreg ',' addr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 /*
  * various indexed load/store
@@ -523,147 +519,172 @@ inst:
  */
 |      LXLD regaddr ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LXLD regaddr ',' imm ',' rreg
        {
-               outgcode($1, &$2, NREG, &$4, &$6);
+               outgcode($1, &$2, 0, &$4, &$6);
        }
 |      LXST rreg ',' regaddr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LXST rreg ',' imm ',' regaddr
        {
-               outgcode($1, &$2, NREG, &$4, &$6);
+               outgcode($1, &$2, 0, &$4, &$6);
        }
 |      LXMV regaddr ',' rreg
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LXMV rreg ',' regaddr
        {
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 |      LXOP regaddr
        {
-               outcode($1, &$2, NREG, &nullgen);
+               outcode($1, &$2, 0, &nullgen);
        }
 /*
  * NOP
  */
 |      LNOP comma
        {
-               outcode($1, &nullgen, NREG, &nullgen);
+               outcode($1, &nullgen, 0, &nullgen);
        }
 |      LNOP rreg comma
        {
-               outcode($1, &$2, NREG, &nullgen);
+               outcode($1, &$2, 0, &nullgen);
        }
 |      LNOP freg comma
        {
-               outcode($1, &$2, NREG, &nullgen);
+               outcode($1, &$2, 0, &nullgen);
        }
 |      LNOP ',' rreg
        {
-               outcode($1, &nullgen, NREG, &$3);
+               outcode($1, &nullgen, 0, &$3);
        }
 |      LNOP ',' freg
        {
-               outcode($1, &nullgen, NREG, &$3);
+               outcode($1, &nullgen, 0, &$3);
        }
 |      LNOP imm /* SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards. */
        {
-               outcode($1, &$2, NREG, &nullgen);
+               outcode($1, &$2, 0, &nullgen);
        }
 /*
  * word
  */
 |      LWORD imm comma
        {
-               outcode($1, &$2, NREG, &nullgen);
+               outcode($1, &$2, 0, &nullgen);
        }
 |      LWORD ximm comma
        {
-               outcode($1, &$2, NREG, &nullgen);
+               outcode($1, &$2, 0, &nullgen);
        }
 /*
  * PCDATA
  */
 |      LPCDAT imm ',' imm
        {
-               if($2.type != D_CONST || $4.type != D_CONST)
+               if($2.type != TYPE_CONST || $4.type != TYPE_CONST)
                        yyerror("arguments to PCDATA must be integer constants");
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 /*
  * FUNCDATA
  */
 |      LFUNCDAT imm ',' addr
        {
-               if($2.type != D_CONST)
+               if($2.type != TYPE_CONST)
                        yyerror("index for FUNCDATA must be integer constant");
-               if($4.type != D_EXTERN && $4.type != D_STATIC && $4.type != D_OREG)
+               if($4.type != NAME_EXTERN && $4.type != NAME_STATIC && $4.type != TYPE_MEM)
                        yyerror("value for FUNCDATA must be symbol reference");
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$4);
        }
 /*
  * END
  */
 |      LEND comma
        {
-               outcode($1, &nullgen, NREG, &nullgen);
+               outcode($1, &nullgen, 0, &nullgen);
        }
 /*
- * TEXT/GLOBL
+ * TEXT
  */
-|      LTEXT name ',' imm
+|      LTEXT name ',' '$' textsize
        {
                settext($2.sym);
-               outcode($1, &$2, NREG, &$4);
+               outcode($1, &$2, 0, &$5);
        }
-|      LTEXT name ',' con ',' imm
+|      LTEXT name ',' con ',' '$' textsize
        {
                settext($2.sym);
-               $6.offset &= 0xffffffffull;
-               $6.offset |= (vlong)ArgsSizeUnknown << 32;
-               outcode($1, &$2, $4, &$6);
+               outcode($1, &$2, 0, &$7);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
-|      LTEXT name ',' con ',' imm '-' con
+/*
+ * GLOBL
+ */
+|      LGLOBL name ',' imm
        {
                settext($2.sym);
-               $6.offset &= 0xffffffffull;
-               $6.offset |= ($8 & 0xffffffffull) << 32;
-               outcode($1, &$2, $4, &$6);
+               outcode($1, &$2, 0, &$4);
        }
+|      LGLOBL name ',' con ',' imm
+       {
+               settext($2.sym);
+               outcode($1, &$2, 0, &$6);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
+       }
+
 /*
  * DATA
  */
 |      LDATA name '/' con ',' imm
        {
-               outcode($1, &$2, $4, &$6);
+               outcode($1, &$2, 0, &$6);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
 |      LDATA name '/' con ',' ximm
        {
-               outcode($1, &$2, $4, &$6);
+               outcode($1, &$2, 0, &$6);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
 |      LDATA name '/' con ',' fimm
        {
-               outcode($1, &$2, $4, &$6);
+               outcode($1, &$2, 0, &$6);
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = $4;
+               }
        }
 /*
  * RETURN
  */
 |      LRETRN  comma
        {
-               outcode($1, &nullgen, NREG, &nullgen);
+               outcode($1, &nullgen, 0, &nullgen);
        }
 
 rel:
        con '(' LPC ')'
        {
                $$ = nullgen;
-               $$.type = D_BRANCH;
+               $$.type = TYPE_BRANCH;
                $$.offset = $1 + pc;
        }
 |      LNAME offset
@@ -672,7 +693,7 @@ rel:
                $$ = nullgen;
                if(pass == 2 && $1->type != LLAB)
                        yyerror("undefined label: %s", $1->labelname);
-               $$.type = D_BRANCH;
+               $$.type = TYPE_BRANCH;
                $$.offset = $1->value + $2;
        }
 
@@ -680,7 +701,7 @@ rreg:
        sreg
        {
                $$ = nullgen;
-               $$.type = D_REG;
+               $$.type = TYPE_REG;
                $$.reg = $1;
        }
 
@@ -692,45 +713,48 @@ lr:
        LLR
        {
                $$ = nullgen;
-               $$.type = D_SPR;
-               $$.offset = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 
 lcr:
        LCR
        {
                $$ = nullgen;
-               $$.type = D_CREG;
-               $$.reg = NREG;  /* whole register */
+               $$.type = TYPE_REG;
+               $$.reg = $1;    /* whole register */
        }
 
 ctr:
        LCTR
        {
                $$ = nullgen;
-               $$.type = D_SPR;
-               $$.offset = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 
 msr:
        LMSR
        {
                $$ = nullgen;
-               $$.type = D_MSR;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 
 psr:
        LSPREG
        {
                $$ = nullgen;
-               $$.type = D_SPR;
-               $$.offset = $1;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 |      LSPR '(' con ')'
        {
+               if($3 < 0 || $3 >= 1024)
+                       yyerror("SPR/DCR out of range");
                $$ = nullgen;
-               $$.type = $1;
-               $$.offset = $3;
+               $$.type = TYPE_REG;
+               $$.reg = $1 + $3;
        }
 |      msr
 
@@ -738,51 +762,43 @@ fpscr:
        LFPSCR
        {
                $$ = nullgen;
-               $$.type = D_FPSCR;
-               $$.reg = NREG;
-       }
-
-fpscrf:
-       LFPSCR '(' con ')'
-       {
-               $$ = nullgen;
-               $$.type = D_FPSCR;
-               $$.reg = $3;
+               $$.type = TYPE_REG;
+               $$.reg = $1;
        }
 
 freg:
        LFREG
        {
                $$ = nullgen;
-               $$.type = D_FREG;
+               $$.type = TYPE_REG;
                $$.reg = $1;
        }
 |      LF '(' con ')'
        {
                $$ = nullgen;
-               $$.type = D_FREG;
-               $$.reg = $3;
+               $$.type = TYPE_REG;
+               $$.reg = REG_F0 + $3;
        }
 
 creg:
        LCREG
        {
                $$ = nullgen;
-               $$.type = D_CREG;
+               $$.type = TYPE_REG;
                $$.reg = $1;
        }
 |      LCR '(' con ')'
        {
                $$ = nullgen;
-               $$.type = D_CREG;
-               $$.reg = $3;
+               $$.type = TYPE_REG;
+               $$.reg = REG_C0 + $3;
        }
 
 
 cbit:  con
        {
                $$ = nullgen;
-               $$.type = D_REG;
+               $$.type = TYPE_REG;
                $$.reg = $1;
        }
 
@@ -793,7 +809,7 @@ mask:
                uint32 v;
 
                $$ = nullgen;
-               $$.type = D_CONST;
+               $$.type = TYPE_CONST;
                mb = $1;
                me = $3;
                if(mb < 0 || mb > 31 || me < 0 || me > 31){
@@ -807,16 +823,46 @@ mask:
                $$.offset = v;
        }
 
+textsize:
+       LCONST
+       {
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = $1;
+               $$.u.argsize = ArgsSizeUnknown;
+       }
+|      '-' LCONST
+       {
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = -$2;
+               $$.u.argsize = ArgsSizeUnknown;
+       }
+|      LCONST '-' LCONST
+       {
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = $1;
+               $$.u.argsize = $3;
+       }
+|      '-' LCONST '-' LCONST
+       {
+               $$ = nullgen;
+               $$.type = TYPE_TEXTSIZE;
+               $$.offset = -$2;
+               $$.u.argsize = $4;
+       }
+
 ximm:
        '$' addr
        {
                $$ = $2;
-               $$.type = D_CONST;
+               $$.type = TYPE_ADDR;
        }
 |      '$' LSCONST
        {
                $$ = nullgen;
-               $$.type = D_SCONST;
+               $$.type = TYPE_SCONST;
                memcpy($$.u.sval, $2, sizeof($$.u.sval));
        }
 
@@ -824,20 +870,20 @@ fimm:
        '$' LFCONST
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = $2;
        }
 |      '$' '-' LFCONST
        {
                $$ = nullgen;
-               $$.type = D_FCONST;
+               $$.type = TYPE_FCONST;
                $$.u.dval = -$3;
        }
 
 imm:   '$' con
        {
                $$ = nullgen;
-               $$.type = D_CONST;
+               $$.type = TYPE_CONST;
                $$.offset = $2;
        }
 
@@ -847,21 +893,21 @@ sreg:
        {
                if($$ < 0 || $$ >= NREG)
                        print("register value out of range\n");
-               $$ = $3;
+               $$ = REG_R0 + $3;
        }
 
 regaddr:
        '(' sreg ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.reg = $2;
                $$.offset = 0;
        }
 |      '(' sreg '+' sreg ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.reg = $2;
                $$.scale = $4;
                $$.offset = 0;
@@ -872,7 +918,7 @@ addr:
 |      con '(' sreg ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.reg = $3;
                $$.offset = $1;
        }
@@ -881,7 +927,7 @@ name:
        con '(' pointer ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.name = $3;
                $$.sym = nil;
                $$.offset = $1;
@@ -889,7 +935,7 @@ name:
 |      LNAME offset '(' pointer ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
+               $$.type = TYPE_MEM;
                $$.name = $4;
                $$.sym = linklookup(ctxt, $1->name, 0);
                $$.offset = $2;
@@ -897,8 +943,8 @@ name:
 |      LNAME '<' '>' offset '(' LSB ')'
        {
                $$ = nullgen;
-               $$.type = D_OREG;
-               $$.name = D_STATIC;
+               $$.type = TYPE_MEM;
+               $$.name = NAME_STATIC;
                $$.sym = linklookup(ctxt, $1->name, 0);
                $$.offset = $4;
        }
index e93365909eedc60b5e813ccfea11ad5be09cfec2..942791247e45762437fe38df4e4b0a8901b5a951 100644 (file)
@@ -197,97 +197,97 @@ struct
        ushort  value;
 } itab[] =
 {
-       "SP",           LSP,    D_AUTO,
-       "SB",           LSB,    D_EXTERN,
-       "FP",           LFP,    D_PARAM,
-       "PC",           LPC,    D_BRANCH,
-
-       "LR",           LLR,    D_LR,
-       "CTR",          LCTR,   D_CTR,
-
-       "XER",          LSPREG, D_XER,
-       "MSR",          LMSR,   D_MSR,
-       "FPSCR",        LFPSCR, D_FPSCR,
-       "SPR",          LSPR,   D_SPR,
-       "DCR",          LSPR,   D_DCR,
-
-       "CR",           LCR,    0,
-       "CR0",          LCREG,  0,
-       "CR1",          LCREG,  1,
-       "CR2",          LCREG,  2,
-       "CR3",          LCREG,  3,
-       "CR4",          LCREG,  4,
-       "CR5",          LCREG,  5,
-       "CR6",          LCREG,  6,
-       "CR7",          LCREG,  7,
+       "SP",           LSP,    NAME_AUTO,
+       "SB",           LSB,    NAME_EXTERN,
+       "FP",           LFP,    NAME_PARAM,
+       "PC",           LPC,    TYPE_BRANCH,
+
+       "LR",           LLR,    REG_LR,
+       "CTR",          LCTR,   REG_CTR,
+
+       "XER",          LSPREG, REG_XER,
+       "MSR",          LMSR,   REG_MSR,
+       "FPSCR",        LFPSCR, REG_FPSCR,
+       "SPR",          LSPR,   REG_SPR0,
+       "DCR",          LSPR,   REG_DCR0,
+
+       "CR",           LCR,    REG_CR,
+       "CR0",          LCREG,  REG_C0,
+       "CR1",          LCREG,  REG_C1,
+       "CR2",          LCREG,  REG_C2,
+       "CR3",          LCREG,  REG_C3,
+       "CR4",          LCREG,  REG_C4,
+       "CR5",          LCREG,  REG_C5,
+       "CR6",          LCREG,  REG_C6,
+       "CR7",          LCREG,  REG_C7,
 
        "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,
-       "g",            LREG,   30, // avoid unintentionally clobbering g using R30
-       "R31",          LREG,   31,
+       "R0",           LREG,   REG_R0,
+       "R1",           LREG,   REG_R1,
+       "R2",           LREG,   REG_R2,
+       "R3",           LREG,   REG_R3,
+       "R4",           LREG,   REG_R4,
+       "R5",           LREG,   REG_R5,
+       "R6",           LREG,   REG_R6,
+       "R7",           LREG,   REG_R7,
+       "R8",           LREG,   REG_R8,
+       "R9",           LREG,   REG_R9,
+       "R10",          LREG,   REG_R10,
+       "R11",          LREG,   REG_R11,
+       "R12",          LREG,   REG_R12,
+       "R13",          LREG,   REG_R13,
+       "R14",          LREG,   REG_R14,
+       "R15",          LREG,   REG_R15,
+       "R16",          LREG,   REG_R16,
+       "R17",          LREG,   REG_R17,
+       "R18",          LREG,   REG_R18,
+       "R19",          LREG,   REG_R19,
+       "R20",          LREG,   REG_R20,
+       "R21",          LREG,   REG_R21,
+       "R22",          LREG,   REG_R22,
+       "R23",          LREG,   REG_R23,
+       "R24",          LREG,   REG_R24,
+       "R25",          LREG,   REG_R25,
+       "R26",          LREG,   REG_R26,
+       "R27",          LREG,   REG_R27,
+       "R28",          LREG,   REG_R28,
+       "R29",          LREG,   REG_R29,
+       "g",            LREG,   REG_R30, // avoid unintentionally clobbering g using R30
+       "R31",          LREG,   REG_R31,
 
        "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,
+       "F0",           LFREG,  REG_F0,
+       "F1",           LFREG,  REG_F1,
+       "F2",           LFREG,  REG_F2,
+       "F3",           LFREG,  REG_F3,
+       "F4",           LFREG,  REG_F4,
+       "F5",           LFREG,  REG_F5,
+       "F6",           LFREG,  REG_F6,
+       "F7",           LFREG,  REG_F7,
+       "F8",           LFREG,  REG_F8,
+       "F9",           LFREG,  REG_F9,
+       "F10",          LFREG,  REG_F10,
+       "F11",          LFREG,  REG_F11,
+       "F12",          LFREG,  REG_F12,
+       "F13",          LFREG,  REG_F13,
+       "F14",          LFREG,  REG_F14,
+       "F15",          LFREG,  REG_F15,
+       "F16",          LFREG,  REG_F16,
+       "F17",          LFREG,  REG_F17,
+       "F18",          LFREG,  REG_F18,
+       "F19",          LFREG,  REG_F19,
+       "F20",          LFREG,  REG_F20,
+       "F21",          LFREG,  REG_F21,
+       "F22",          LFREG,  REG_F22,
+       "F23",          LFREG,  REG_F23,
+       "F24",          LFREG,  REG_F24,
+       "F25",          LFREG,  REG_F25,
+       "F26",          LFREG,  REG_F26,
+       "F27",          LFREG,  REG_F27,
+       "F28",          LFREG,  REG_F28,
+       "F29",          LFREG,  REG_F29,
+       "F30",          LFREG,  REG_F30,
+       "F31",          LFREG,  REG_F31,
 
        "CREQV",        LCROP, ACREQV,
        "CRXOR",        LCROP, ACRXOR,
@@ -454,7 +454,7 @@ struct
        "FMOVS",        LFMOV, AFMOVS,
        "FMOVDCC",      LFCONV, AFMOVDCC,       /* fmr. */
 
-       "GLOBL",        LTEXT, AGLOBL,
+       "GLOBL",        LGLOBL, AGLOBL,
 
        "MOVB",         LMOVB, AMOVB,
        "MOVBZ",        LMOVB, AMOVBZ,
@@ -616,10 +616,10 @@ cinit(void)
        Sym *s;
        int i;
 
-       nullgen.type = D_NONE;
-       nullgen.name = D_NONE;
-       nullgen.reg = NREG;
-       nullgen.scale = NREG; // replaced Gen.xreg with Prog.scale
+       nullgen.type = TYPE_NONE;
+       nullgen.name = NAME_NONE;
+       nullgen.reg = 0;
+       nullgen.scale = 0; // replaced Gen.xreg with Prog.scale
 
        nerrors = 0;
        iostack = I;
@@ -647,11 +647,9 @@ void
 cclean(void)
 {
 
-       outcode(AEND, &nullgen, NREG, &nullgen);
+       outcode(AEND, &nullgen, 0, &nullgen);
 }
 
-static Prog *lastpc;
-
 void
 outcode(int a, Addr *g1, int reg, Addr *g2)
 {
@@ -661,18 +659,18 @@ outcode(int a, Addr *g1, int reg, Addr *g2)
        if(pass == 1)
                goto out;
 
-       if(g1->scale != NREG) {
-               if(reg != NREG || g2->scale != NREG)
+       if(g1->scale != 0) {
+               if(reg != 0 || g2->scale != 0)
                        yyerror("bad addressing modes");
                reg = g1->scale;
        } else
-       if(g2->scale != NREG) {
-               if(reg != NREG)
+       if(g2->scale != 0) {
+               if(reg != 0)
                        yyerror("bad addressing modes");
                reg = g2->scale;
        }
 
-       p = ctxt->arch->prg();
+       p = emallocz(sizeof(Prog));
        p->as = a;
        p->lineno = lineno;
        if(nosched)
@@ -702,7 +700,7 @@ outgcode(int a, Addr *g1, int reg, Addr *g2, Addr *g3)
        if(pass == 1)
                goto out;
 
-       p = ctxt->arch->prg();
+       p = emallocz(sizeof(Prog));
        p->as = a;
        p->lineno = lineno;
        if(nosched)
index 6025a2402c18035c2fc4d8f88430066e842946f3..178dfe1bca75fe65e10cf05da03b14ac50fe49aa 100644 (file)
      LRETT = 276,
      LWORD = 277,
      LTEXT = 278,
-     LDATA = 279,
-     LRETRN = 280,
-     LCONST = 281,
-     LSP = 282,
-     LSB = 283,
-     LFP = 284,
-     LPC = 285,
-     LCREG = 286,
-     LFLUSH = 287,
-     LREG = 288,
-     LFREG = 289,
-     LR = 290,
-     LCR = 291,
-     LF = 292,
-     LFPSCR = 293,
-     LLR = 294,
-     LCTR = 295,
-     LSPR = 296,
-     LSPREG = 297,
-     LSEG = 298,
-     LMSR = 299,
-     LPCDAT = 300,
-     LFUNCDAT = 301,
-     LSCHED = 302,
-     LXLD = 303,
-     LXST = 304,
-     LXOP = 305,
-     LXMV = 306,
-     LRLWM = 307,
-     LMOVMW = 308,
-     LMOVEM = 309,
-     LMOVFL = 310,
-     LMTFSB = 311,
-     LMA = 312,
-     LFCONST = 313,
-     LSCONST = 314,
-     LNAME = 315,
-     LLAB = 316,
-     LVAR = 317
+     LGLOBL = 279,
+     LDATA = 280,
+     LRETRN = 281,
+     LCONST = 282,
+     LSP = 283,
+     LSB = 284,
+     LFP = 285,
+     LPC = 286,
+     LCREG = 287,
+     LFLUSH = 288,
+     LREG = 289,
+     LFREG = 290,
+     LR = 291,
+     LCR = 292,
+     LF = 293,
+     LFPSCR = 294,
+     LLR = 295,
+     LCTR = 296,
+     LSPR = 297,
+     LSPREG = 298,
+     LSEG = 299,
+     LMSR = 300,
+     LPCDAT = 301,
+     LFUNCDAT = 302,
+     LSCHED = 303,
+     LXLD = 304,
+     LXST = 305,
+     LXOP = 306,
+     LXMV = 307,
+     LRLWM = 308,
+     LMOVMW = 309,
+     LMOVEM = 310,
+     LMOVFL = 311,
+     LMTFSB = 312,
+     LMA = 313,
+     LFCONST = 314,
+     LSCONST = 315,
+     LNAME = 316,
+     LLAB = 317,
+     LVAR = 318
    };
 #endif
 /* Tokens.  */
 #define LRETT 276
 #define LWORD 277
 #define LTEXT 278
-#define LDATA 279
-#define LRETRN 280
-#define LCONST 281
-#define LSP 282
-#define LSB 283
-#define LFP 284
-#define LPC 285
-#define LCREG 286
-#define LFLUSH 287
-#define LREG 288
-#define LFREG 289
-#define LR 290
-#define LCR 291
-#define LF 292
-#define LFPSCR 293
-#define LLR 294
-#define LCTR 295
-#define LSPR 296
-#define LSPREG 297
-#define LSEG 298
-#define LMSR 299
-#define LPCDAT 300
-#define LFUNCDAT 301
-#define LSCHED 302
-#define LXLD 303
-#define LXST 304
-#define LXOP 305
-#define LXMV 306
-#define LRLWM 307
-#define LMOVMW 308
-#define LMOVEM 309
-#define LMOVFL 310
-#define LMTFSB 311
-#define LMA 312
-#define LFCONST 313
-#define LSCONST 314
-#define LNAME 315
-#define LLAB 316
-#define LVAR 317
+#define LGLOBL 279
+#define LDATA 280
+#define LRETRN 281
+#define LCONST 282
+#define LSP 283
+#define LSB 284
+#define LFP 285
+#define LPC 286
+#define LCREG 287
+#define LFLUSH 288
+#define LREG 289
+#define LFREG 290
+#define LR 291
+#define LCR 292
+#define LF 293
+#define LFPSCR 294
+#define LLR 295
+#define LCTR 296
+#define LSPR 297
+#define LSPREG 298
+#define LSEG 299
+#define LMSR 300
+#define LPCDAT 301
+#define LFUNCDAT 302
+#define LSCHED 303
+#define LXLD 304
+#define LXST 305
+#define LXOP 306
+#define LXMV 307
+#define LRLWM 308
+#define LMOVMW 309
+#define LMOVEM 310
+#define LMOVFL 311
+#define LMTFSB 312
+#define LMA 313
+#define LFCONST 314
+#define LSCONST 315
+#define LNAME 316
+#define LLAB 317
+#define LVAR 318
 
 
 
@@ -232,7 +234,7 @@ typedef union YYSTYPE
        Addr    addr;
 }
 /* Line 193 of yacc.c.  */
-#line 236 "y.tab.c"
+#line 238 "y.tab.c"
        YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -245,7 +247,7 @@ typedef union YYSTYPE
 
 
 /* Line 216 of yacc.c.  */
-#line 249 "y.tab.c"
+#line 251 "y.tab.c"
 
 #ifdef short
 # undef short
@@ -460,20 +462,20 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  2
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   862
+#define YYLAST   932
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  81
+#define YYNTOKENS  82
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  31
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  183
+#define YYNRULES  186
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  453
+#define YYNSTATES  462
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   317
+#define YYMAXUTOK   318
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -484,16 +486,16 @@ static const yytype_uint8 yytranslate[] =
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,    79,    12,     5,     2,
-      77,    78,    10,     8,    76,     9,     2,    11,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    73,    75,
-       6,    74,     7,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,    80,    12,     5,     2,
+      78,    79,    10,     8,    77,     9,     2,    11,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    74,    76,
+       6,    75,     7,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     4,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     3,     2,    80,     2,     2,     2,
+       2,     2,     2,     2,     3,     2,    81,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -512,7 +514,7 @@ static const yytype_uint8 yytranslate[] =
       35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
       45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
       55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
-      65,    66,    67,    68,    69,    70,    71,    72
+      65,    66,    67,    68,    69,    70,    71,    72,    73
 };
 
 #if YYDEBUG
@@ -523,112 +525,113 @@ static const yytype_uint16 yyprhs[] =
        0,     0,     3,     4,     7,     8,    13,    18,    23,    26,
       28,    31,    34,    39,    44,    49,    54,    59,    64,    69,
       74,    79,    84,    89,    94,    99,   104,   109,   114,   119,
-     124,   129,   134,   141,   146,   151,   156,   163,   168,   173,
-     180,   187,   194,   199,   204,   211,   216,   223,   228,   235,
-     240,   245,   248,   255,   260,   265,   270,   277,   282,   287,
-     292,   297,   302,   307,   312,   317,   320,   323,   328,   332,
-     336,   342,   347,   352,   359,   364,   369,   376,   383,   390,
-     399,   404,   409,   413,   416,   421,   426,   433,   442,   447,
-     454,   459,   464,   471,   478,   487,   496,   505,   514,   519,
-     524,   529,   536,   541,   548,   553,   558,   561,   564,   568,
-     572,   576,   580,   583,   587,   591,   596,   601,   604,   609,
-     616,   625,   632,   639,   646,   649,   654,   657,   659,   661,
-     663,   665,   667,   669,   671,   673,   678,   680,   682,   687,
-     689,   694,   696,   701,   703,   707,   710,   713,   716,   720,
-     723,   725,   730,   734,   740,   742,   747,   752,   758,   766,
-     767,   769,   770,   773,   776,   778,   780,   782,   784,   786,
-     789,   792,   795,   799,   801,   805,   809,   813,   817,   821,
-     826,   831,   835,   839
+     124,   129,   134,   141,   146,   151,   158,   163,   168,   175,
+     182,   189,   194,   199,   206,   211,   218,   223,   230,   235,
+     240,   243,   250,   255,   260,   265,   272,   277,   282,   287,
+     292,   297,   302,   307,   312,   315,   318,   323,   327,   331,
+     337,   342,   347,   354,   359,   364,   371,   378,   385,   394,
+     399,   404,   408,   411,   416,   421,   428,   437,   442,   449,
+     454,   459,   466,   473,   482,   491,   500,   509,   514,   519,
+     524,   531,   536,   543,   548,   553,   556,   559,   563,   567,
+     571,   575,   578,   582,   586,   591,   596,   599,   605,   613,
+     618,   625,   632,   639,   646,   649,   654,   657,   659,   661,
+     663,   665,   667,   669,   671,   673,   678,   680,   682,   684,
+     689,   691,   696,   698,   702,   704,   707,   711,   716,   719,
+     722,   725,   729,   732,   734,   739,   743,   749,   751,   756,
+     761,   767,   775,   776,   778,   779,   782,   785,   787,   789,
+     791,   793,   795,   798,   801,   804,   808,   810,   814,   818,
+     822,   826,   830,   835,   840,   844,   848
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      82,     0,    -1,    -1,    82,    83,    -1,    -1,    70,    73,
-      84,    83,    -1,    70,    74,   111,    75,    -1,    72,    74,
-     111,    75,    -1,    57,    75,    -1,    75,    -1,    85,    75,
-      -1,     1,    75,    -1,    13,    87,    76,    87,    -1,    13,
-     105,    76,    87,    -1,    13,   104,    76,    87,    -1,    14,
-      87,    76,    87,    -1,    14,   105,    76,    87,    -1,    14,
-     104,    76,    87,    -1,    22,   105,    76,    96,    -1,    22,
-     104,    76,    96,    -1,    22,   101,    76,    96,    -1,    22,
-      96,    76,    96,    -1,    22,    96,    76,   105,    -1,    22,
-      96,    76,   104,    -1,    13,    87,    76,   105,    -1,    13,
-      87,    76,   104,    -1,    14,    87,    76,   105,    -1,    14,
-      87,    76,   104,    -1,    13,    96,    76,   105,    -1,    13,
-      96,    76,   104,    -1,    13,    94,    76,    96,    -1,    13,
-      96,    76,    94,    -1,    13,    96,    76,   102,    76,    94,
-      -1,    13,    94,    76,    97,    -1,    13,   102,    76,    95,
-      -1,    66,   102,    76,   110,    -1,    13,    87,    76,   102,
-      76,    90,    -1,    13,    87,    76,    97,    -1,    13,    87,
-      76,    90,    -1,    18,    87,    76,   103,    76,    87,    -1,
-      18,   102,    76,   103,    76,    87,    -1,    18,    87,    76,
-     102,    76,    87,    -1,    18,    87,    76,    87,    -1,    18,
-     102,    76,    87,    -1,    16,    87,    76,   103,    76,    87,
-      -1,    16,    87,    76,    87,    -1,    17,    87,    76,   103,
-      76,    87,    -1,    17,    87,    76,    87,    -1,    17,   102,
-      76,   103,    76,    87,    -1,    17,   102,    76,    87,    -1,
-      15,    87,    76,    87,    -1,    15,    87,    -1,    67,    87,
-      76,   103,    76,    87,    -1,    13,   102,    76,    87,    -1,
-      13,   100,    76,    87,    -1,    20,    98,    76,    98,    -1,
-      20,    98,    76,   110,    76,    98,    -1,    13,    97,    76,
-      97,    -1,    13,    93,    76,    97,    -1,    13,    90,    76,
-      87,    -1,    13,    93,    76,    87,    -1,    13,    88,    76,
-      87,    -1,    13,    87,    76,    88,    -1,    13,    97,    76,
-      93,    -1,    13,    87,    76,    93,    -1,    21,    86,    -1,
-      21,   105,    -1,    21,    77,    88,    78,    -1,    21,    76,
-      86,    -1,    21,    76,   105,    -1,    21,    76,    77,    88,
-      78,    -1,    21,    97,    76,    86,    -1,    21,    97,    76,
-     105,    -1,    21,    97,    76,    77,    88,    78,    -1,    21,
-     110,    76,    86,    -1,    21,   110,    76,   105,    -1,    21,
-     110,    76,    77,    88,    78,    -1,    21,   110,    76,   110,
-      76,    86,    -1,    21,   110,    76,   110,    76,   105,    -1,
-      21,   110,    76,   110,    76,    77,    88,    78,    -1,    27,
-      87,    76,   103,    -1,    27,   102,    76,   103,    -1,    27,
-      87,   107,    -1,    27,   107,    -1,    23,    96,    76,    96,
-      -1,    25,    96,    76,    96,    -1,    25,    96,    76,    96,
-      76,    96,    -1,    26,    96,    76,    96,    76,    96,    76,
-      96,    -1,    24,    96,    76,    96,    -1,    24,    96,    76,
-      96,    76,    97,    -1,    19,    87,    76,    87,    -1,    19,
-      87,    76,   102,    -1,    19,    87,    76,    87,    76,    97,
-      -1,    19,    87,    76,   102,    76,    97,    -1,    62,   102,
-      76,    87,    76,   102,    76,    87,    -1,    62,   102,    76,
-      87,    76,    99,    76,    87,    -1,    62,    87,    76,    87,
-      76,   102,    76,    87,    -1,    62,    87,    76,    87,    76,
-      99,    76,    87,    -1,    63,   105,    76,    87,    -1,    63,
-      87,    76,   105,    -1,    58,   104,    76,    87,    -1,    58,
-     104,    76,   102,    76,    87,    -1,    59,    87,    76,   104,
-      -1,    59,    87,    76,   102,    76,   104,    -1,    61,   104,
-      76,    87,    -1,    61,    87,    76,   104,    -1,    60,   104,
-      -1,    29,   107,    -1,    29,    87,   107,    -1,    29,    96,
-     107,    -1,    29,    76,    87,    -1,    29,    76,    96,    -1,
-      29,   102,    -1,    32,   102,   107,    -1,    32,   100,   107,
-      -1,    55,   102,    76,   102,    -1,    56,   102,    76,   105,
-      -1,    30,   107,    -1,    33,   106,    76,   102,    -1,    33,
-     106,    76,   110,    76,   102,    -1,    33,   106,    76,   110,
-      76,   102,     9,   110,    -1,    34,   106,    11,   110,    76,
-     102,    -1,    34,   106,    11,   110,    76,   100,    -1,    34,
-     106,    11,   110,    76,   101,    -1,    35,   107,    -1,   110,
-      77,    40,    78,    -1,    70,   108,    -1,   103,    -1,    89,
-      -1,    91,    -1,    49,    -1,    46,    -1,    50,    -1,    54,
-      -1,    52,    -1,    51,    77,   110,    78,    -1,    92,    -1,
-      48,    -1,    48,    77,   110,    78,    -1,    44,    -1,    47,
-      77,   110,    78,    -1,    41,    -1,    46,    77,   110,    78,
-      -1,   110,    -1,   110,    76,   110,    -1,    79,   105,    -1,
-      79,    69,    -1,    79,    68,    -1,    79,     9,    68,    -1,
-      79,   110,    -1,    43,    -1,    45,    77,   110,    78,    -1,
-      77,   103,    78,    -1,    77,   103,     8,   103,    78,    -1,
-     106,    -1,   110,    77,   103,    78,    -1,   110,    77,   109,
-      78,    -1,    70,   108,    77,   109,    78,    -1,    70,     6,
-       7,   108,    77,    38,    78,    -1,    -1,    76,    -1,    -1,
-       8,   110,    -1,     9,   110,    -1,    38,    -1,    37,    -1,
-      39,    -1,    36,    -1,    72,    -1,     9,   110,    -1,     8,
-     110,    -1,    80,   110,    -1,    77,   111,    78,    -1,   110,
-      -1,   111,     8,   111,    -1,   111,     9,   111,    -1,   111,
-      10,   111,    -1,   111,    11,   111,    -1,   111,    12,   111,
-      -1,   111,     6,     6,   111,    -1,   111,     7,     7,   111,
-      -1,   111,     5,   111,    -1,   111,     4,   111,    -1,   111,
-       3,   111,    -1
+      83,     0,    -1,    -1,    83,    84,    -1,    -1,    71,    74,
+      85,    84,    -1,    71,    75,   112,    76,    -1,    73,    75,
+     112,    76,    -1,    58,    76,    -1,    76,    -1,    86,    76,
+      -1,     1,    76,    -1,    13,    88,    77,    88,    -1,    13,
+     106,    77,    88,    -1,    13,   105,    77,    88,    -1,    14,
+      88,    77,    88,    -1,    14,   106,    77,    88,    -1,    14,
+     105,    77,    88,    -1,    22,   106,    77,    96,    -1,    22,
+     105,    77,    96,    -1,    22,   102,    77,    96,    -1,    22,
+      96,    77,    96,    -1,    22,    96,    77,   106,    -1,    22,
+      96,    77,   105,    -1,    13,    88,    77,   106,    -1,    13,
+      88,    77,   105,    -1,    14,    88,    77,   106,    -1,    14,
+      88,    77,   105,    -1,    13,    96,    77,   106,    -1,    13,
+      96,    77,   105,    -1,    13,    95,    77,    96,    -1,    13,
+      96,    77,    95,    -1,    13,    96,    77,   103,    77,    95,
+      -1,    13,    95,    77,    97,    -1,    67,   103,    77,   111,
+      -1,    13,    88,    77,   103,    77,    91,    -1,    13,    88,
+      77,    97,    -1,    13,    88,    77,    91,    -1,    18,    88,
+      77,   104,    77,    88,    -1,    18,   103,    77,   104,    77,
+      88,    -1,    18,    88,    77,   103,    77,    88,    -1,    18,
+      88,    77,    88,    -1,    18,   103,    77,    88,    -1,    16,
+      88,    77,   104,    77,    88,    -1,    16,    88,    77,    88,
+      -1,    17,    88,    77,   104,    77,    88,    -1,    17,    88,
+      77,    88,    -1,    17,   103,    77,   104,    77,    88,    -1,
+      17,   103,    77,    88,    -1,    15,    88,    77,    88,    -1,
+      15,    88,    -1,    68,    88,    77,   104,    77,    88,    -1,
+      13,   103,    77,    88,    -1,    13,   101,    77,    88,    -1,
+      20,    98,    77,    98,    -1,    20,    98,    77,   111,    77,
+      98,    -1,    13,    97,    77,    97,    -1,    13,    94,    77,
+      97,    -1,    13,    91,    77,    88,    -1,    13,    94,    77,
+      88,    -1,    13,    89,    77,    88,    -1,    13,    88,    77,
+      89,    -1,    13,    97,    77,    94,    -1,    13,    88,    77,
+      94,    -1,    21,    87,    -1,    21,   106,    -1,    21,    78,
+      89,    79,    -1,    21,    77,    87,    -1,    21,    77,   106,
+      -1,    21,    77,    78,    89,    79,    -1,    21,    97,    77,
+      87,    -1,    21,    97,    77,   106,    -1,    21,    97,    77,
+      78,    89,    79,    -1,    21,   111,    77,    87,    -1,    21,
+     111,    77,   106,    -1,    21,   111,    77,    78,    89,    79,
+      -1,    21,   111,    77,   111,    77,    87,    -1,    21,   111,
+      77,   111,    77,   106,    -1,    21,   111,    77,   111,    77,
+      78,    89,    79,    -1,    27,    88,    77,   104,    -1,    27,
+     103,    77,   104,    -1,    27,    88,   108,    -1,    27,   108,
+      -1,    23,    96,    77,    96,    -1,    25,    96,    77,    96,
+      -1,    25,    96,    77,    96,    77,    96,    -1,    26,    96,
+      77,    96,    77,    96,    77,    96,    -1,    24,    96,    77,
+      96,    -1,    24,    96,    77,    96,    77,    97,    -1,    19,
+      88,    77,    88,    -1,    19,    88,    77,   103,    -1,    19,
+      88,    77,    88,    77,    97,    -1,    19,    88,    77,   103,
+      77,    97,    -1,    63,   103,    77,    88,    77,   103,    77,
+      88,    -1,    63,   103,    77,    88,    77,    99,    77,    88,
+      -1,    63,    88,    77,    88,    77,   103,    77,    88,    -1,
+      63,    88,    77,    88,    77,    99,    77,    88,    -1,    64,
+     106,    77,    88,    -1,    64,    88,    77,   106,    -1,    59,
+     105,    77,    88,    -1,    59,   105,    77,   103,    77,    88,
+      -1,    60,    88,    77,   105,    -1,    60,    88,    77,   103,
+      77,   105,    -1,    62,   105,    77,    88,    -1,    62,    88,
+      77,   105,    -1,    61,   105,    -1,    29,   108,    -1,    29,
+      88,   108,    -1,    29,    96,   108,    -1,    29,    77,    88,
+      -1,    29,    77,    96,    -1,    29,   103,    -1,    32,   103,
+     108,    -1,    32,   101,   108,    -1,    56,   103,    77,   103,
+      -1,    57,   103,    77,   106,    -1,    30,   108,    -1,    33,
+     107,    77,    80,   100,    -1,    33,   107,    77,   111,    77,
+      80,   100,    -1,    34,   107,    77,   103,    -1,    34,   107,
+      77,   111,    77,   103,    -1,    35,   107,    11,   111,    77,
+     103,    -1,    35,   107,    11,   111,    77,   101,    -1,    35,
+     107,    11,   111,    77,   102,    -1,    36,   108,    -1,   111,
+      78,    41,    79,    -1,    71,   109,    -1,   104,    -1,    90,
+      -1,    92,    -1,    50,    -1,    47,    -1,    51,    -1,    55,
+      -1,    53,    -1,    52,    78,   111,    79,    -1,    93,    -1,
+      49,    -1,    45,    -1,    48,    78,   111,    79,    -1,    42,
+      -1,    47,    78,   111,    79,    -1,   111,    -1,   111,    77,
+     111,    -1,    37,    -1,     9,    37,    -1,    37,     9,    37,
+      -1,     9,    37,     9,    37,    -1,    80,   106,    -1,    80,
+      70,    -1,    80,    69,    -1,    80,     9,    69,    -1,    80,
+     111,    -1,    44,    -1,    46,    78,   111,    79,    -1,    78,
+     104,    79,    -1,    78,   104,     8,   104,    79,    -1,   107,
+      -1,   111,    78,   104,    79,    -1,   111,    78,   110,    79,
+      -1,    71,   109,    78,   110,    79,    -1,    71,     6,     7,
+     109,    78,    39,    79,    -1,    -1,    77,    -1,    -1,     8,
+     111,    -1,     9,   111,    -1,    39,    -1,    38,    -1,    40,
+      -1,    37,    -1,    73,    -1,     9,   111,    -1,     8,   111,
+      -1,    81,   111,    -1,    78,   112,    79,    -1,   111,    -1,
+     112,     8,   112,    -1,   112,     9,   112,    -1,   112,    10,
+     112,    -1,   112,    11,   112,    -1,   112,    12,   112,    -1,
+     112,     6,     6,   112,    -1,   112,     7,     7,   112,    -1,
+     112,     5,   112,    -1,   112,     4,   112,    -1,   112,     3,
+     112,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
@@ -637,22 +640,22 @@ static const yytype_uint16 yyrline[] =
        0,    66,    66,    67,    71,    70,    79,    84,    90,    94,
       95,    96,   102,   106,   110,   114,   118,   122,   129,   133,
      137,   141,   145,   149,   156,   160,   164,   168,   175,   179,
-     186,   190,   194,   198,   202,   206,   213,   217,   221,   231,
+     186,   190,   194,   198,   202,   209,   213,   217,   227,   231,
      235,   239,   243,   247,   251,   255,   259,   263,   267,   271,
-     275,   279,   286,   293,   297,   304,   308,   316,   320,   324,
-     328,   332,   336,   340,   344,   353,   357,   361,   365,   369,
-     373,   377,   381,   385,   389,   393,   397,   401,   409,   417,
-     428,   432,   436,   440,   447,   451,   455,   459,   463,   467,
-     474,   478,   482,   486,   493,   497,   501,   505,   512,   516,
-     524,   528,   532,   536,   540,   544,   548,   555,   559,   563,
-     567,   571,   575,   582,   586,   593,   602,   613,   620,   625,
-     632,   642,   646,   650,   657,   663,   669,   680,   688,   689,
-     692,   700,   708,   716,   723,   729,   735,   738,   746,   754,
-     760,   768,   774,   782,   790,   811,   816,   824,   830,   837,
-     845,   846,   854,   861,   871,   872,   881,   889,   897,   906,
-     907,   910,   913,   917,   923,   924,   925,   928,   929,   933,
-     937,   941,   945,   951,   952,   956,   960,   964,   968,   972,
-     976,   980,   984,   988
+     275,   282,   289,   293,   300,   304,   312,   316,   320,   324,
+     328,   332,   336,   340,   349,   353,   357,   361,   365,   369,
+     373,   377,   381,   385,   389,   393,   397,   405,   413,   424,
+     428,   432,   436,   443,   447,   451,   455,   459,   463,   470,
+     474,   478,   482,   489,   493,   497,   501,   508,   512,   520,
+     524,   528,   532,   536,   540,   544,   551,   555,   559,   563,
+     567,   571,   578,   582,   589,   598,   609,   616,   621,   633,
+     638,   651,   659,   667,   678,   684,   690,   701,   709,   710,
+     713,   721,   729,   737,   745,   751,   759,   762,   770,   776,
+     784,   790,   798,   806,   827,   834,   841,   848,   857,   862,
+     870,   876,   883,   891,   892,   900,   907,   917,   918,   927,
+     935,   943,   952,   953,   956,   959,   963,   969,   970,   971,
+     974,   975,   979,   983,   987,   991,   997,   998,  1002,  1006,
+    1010,  1014,  1018,  1022,  1026,  1030,  1034
 };
 #endif
 
@@ -665,16 +668,16 @@ static const char *const yytname[] =
   "'-'", "'*'", "'/'", "'%'", "LMOVW", "LMOVB", "LABS", "LLOGW", "LSHW",
   "LADDW", "LCMP", "LCROP", "LBRA", "LFMOV", "LFCONV", "LFCMP", "LFADD",
   "LFMA", "LTRAP", "LXORW", "LNOP", "LEND", "LRETT", "LWORD", "LTEXT",
-  "LDATA", "LRETRN", "LCONST", "LSP", "LSB", "LFP", "LPC", "LCREG",
-  "LFLUSH", "LREG", "LFREG", "LR", "LCR", "LF", "LFPSCR", "LLR", "LCTR",
-  "LSPR", "LSPREG", "LSEG", "LMSR", "LPCDAT", "LFUNCDAT", "LSCHED", "LXLD",
-  "LXST", "LXOP", "LXMV", "LRLWM", "LMOVMW", "LMOVEM", "LMOVFL", "LMTFSB",
-  "LMA", "LFCONST", "LSCONST", "LNAME", "LLAB", "LVAR", "':'", "'='",
-  "';'", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog", "line",
-  "@1", "inst", "rel", "rreg", "xlreg", "lr", "lcr", "ctr", "msr", "psr",
-  "fpscr", "fpscrf", "freg", "creg", "cbit", "mask", "ximm", "fimm", "imm",
-  "sreg", "regaddr", "addr", "name", "comma", "offset", "pointer", "con",
-  "expr", 0
+  "LGLOBL", "LDATA", "LRETRN", "LCONST", "LSP", "LSB", "LFP", "LPC",
+  "LCREG", "LFLUSH", "LREG", "LFREG", "LR", "LCR", "LF", "LFPSCR", "LLR",
+  "LCTR", "LSPR", "LSPREG", "LSEG", "LMSR", "LPCDAT", "LFUNCDAT", "LSCHED",
+  "LXLD", "LXST", "LXOP", "LXMV", "LRLWM", "LMOVMW", "LMOVEM", "LMOVFL",
+  "LMTFSB", "LMA", "LFCONST", "LSCONST", "LNAME", "LLAB", "LVAR", "':'",
+  "'='", "';'", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog",
+  "line", "@1", "inst", "rel", "rreg", "xlreg", "lr", "lcr", "ctr", "msr",
+  "psr", "fpscr", "freg", "creg", "cbit", "mask", "textsize", "ximm",
+  "fimm", "imm", "sreg", "regaddr", "addr", "name", "comma", "offset",
+  "pointer", "con", "expr", 0
 };
 #endif
 
@@ -690,33 +693,33 @@ static const yytype_uint16 yytoknum[] =
      285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
      295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
      305,   306,   307,   308,   309,   310,   311,   312,   313,   314,
-     315,   316,   317,    58,    61,    59,    44,    40,    41,    36,
-     126
+     315,   316,   317,   318,    58,    61,    59,    44,    40,    41,
+      36,   126
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    81,    82,    82,    84,    83,    83,    83,    83,    83,
-      83,    83,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
-      85,    85,    85,    85,    85,    86,    86,    87,    88,    88,
-      89,    90,    91,    92,    93,    93,    93,    94,    95,    96,
-      96,    97,    97,    98,    99,   100,   100,   101,   101,   102,
-     103,   103,   104,   104,   105,   105,   106,   106,   106,   107,
-     107,   108,   108,   108,   109,   109,   109,   110,   110,   110,
-     110,   110,   110,   111,   111,   111,   111,   111,   111,   111,
-     111,   111,   111,   111
+       0,    82,    83,    83,    85,    84,    84,    84,    84,    84,
+      84,    84,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+      86,    86,    86,    86,    86,    87,    87,    88,    89,    89,
+      90,    91,    92,    93,    94,    94,    94,    95,    96,    96,
+      97,    97,    98,    99,   100,   100,   100,   100,   101,   101,
+     102,   102,   103,   104,   104,   105,   105,   106,   106,   107,
+     107,   107,   108,   108,   109,   109,   109,   110,   110,   110,
+     111,   111,   111,   111,   111,   111,   112,   112,   112,   112,
+     112,   112,   112,   112,   112,   112,   112
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -725,22 +728,22 @@ static const yytype_uint8 yyr2[] =
        0,     2,     0,     2,     0,     4,     4,     4,     2,     1,
        2,     2,     4,     4,     4,     4,     4,     4,     4,     4,
        4,     4,     4,     4,     4,     4,     4,     4,     4,     4,
-       4,     4,     6,     4,     4,     4,     6,     4,     4,     6,
-       6,     6,     4,     4,     6,     4,     6,     4,     6,     4,
-       4,     2,     6,     4,     4,     4,     6,     4,     4,     4,
-       4,     4,     4,     4,     4,     2,     2,     4,     3,     3,
-       5,     4,     4,     6,     4,     4,     6,     6,     6,     8,
-       4,     4,     3,     2,     4,     4,     6,     8,     4,     6,
-       4,     4,     6,     6,     8,     8,     8,     8,     4,     4,
-       4,     6,     4,     6,     4,     4,     2,     2,     3,     3,
-       3,     3,     2,     3,     3,     4,     4,     2,     4,     6,
-       8,     6,     6,     6,     2,     4,     2,     1,     1,     1,
-       1,     1,     1,     1,     1,     4,     1,     1,     4,     1,
-       4,     1,     4,     1,     3,     2,     2,     2,     3,     2,
-       1,     4,     3,     5,     1,     4,     4,     5,     7,     0,
-       1,     0,     2,     2,     1,     1,     1,     1,     1,     2,
-       2,     2,     3,     1,     3,     3,     3,     3,     3,     4,
-       4,     3,     3,     3
+       4,     4,     6,     4,     4,     6,     4,     4,     6,     6,
+       6,     4,     4,     6,     4,     6,     4,     6,     4,     4,
+       2,     6,     4,     4,     4,     6,     4,     4,     4,     4,
+       4,     4,     4,     4,     2,     2,     4,     3,     3,     5,
+       4,     4,     6,     4,     4,     6,     6,     6,     8,     4,
+       4,     3,     2,     4,     4,     6,     8,     4,     6,     4,
+       4,     6,     6,     8,     8,     8,     8,     4,     4,     4,
+       6,     4,     6,     4,     4,     2,     2,     3,     3,     3,
+       3,     2,     3,     3,     4,     4,     2,     5,     7,     4,
+       6,     6,     6,     6,     2,     4,     2,     1,     1,     1,
+       1,     1,     1,     1,     1,     4,     1,     1,     1,     4,
+       1,     4,     1,     3,     1,     2,     3,     4,     2,     2,
+       2,     3,     2,     1,     4,     3,     5,     1,     4,     4,
+       5,     7,     0,     1,     0,     2,     2,     1,     1,     1,
+       1,     1,     2,     2,     2,     3,     1,     3,     3,     3,
+       3,     3,     4,     4,     3,     3,     3
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -749,122 +752,124 @@ static const yytype_uint8 yyr2[] =
 static const yytype_uint8 yydefact[] =
 {
        2,     0,     1,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   159,   159,
-     159,     0,     0,     0,   159,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     9,     3,
-       0,    11,     0,     0,   167,   141,   150,   139,     0,   131,
-       0,   137,   130,   132,     0,   134,   133,   161,   168,     0,
-       0,     0,     0,     0,   128,     0,   129,   136,     0,     0,
-       0,     0,     0,     0,   127,     0,     0,   154,     0,     0,
-       0,     0,    51,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   143,     0,   161,     0,     0,    65,     0,    66,
+       0,     0,     0,     0,     0,     0,     0,     0,   162,   162,
+     162,     0,     0,     0,     0,   162,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     9,
+       3,     0,    11,     0,     0,   170,   140,   153,   138,     0,
+     131,     0,   137,   130,   132,     0,   134,   133,   164,   171,
+       0,     0,     0,     0,     0,   128,     0,   129,   136,     0,
+       0,     0,     0,     0,     0,   127,     0,     0,   157,     0,
+       0,     0,     0,    50,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   142,     0,   164,     0,     0,    64,     0,
+      65,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   163,   162,     0,    82,   163,   162,   162,   111,   106,
+     116,   162,   162,     0,     0,     0,     0,   124,     0,     0,
+       8,     0,     0,     0,   105,     0,     0,     0,     0,     0,
+       0,     0,     0,     4,     0,     0,    10,   173,   172,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   176,     0,
+     149,   148,   152,   174,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     160,   159,     0,    83,   160,   159,   159,   112,   107,   117,
-     159,   159,     0,     0,     0,   124,     0,     0,     8,     0,
-       0,     0,   106,     0,     0,     0,     0,     0,     0,     0,
-       0,     4,     0,     0,    10,   170,   169,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   173,     0,   146,   145,
-     149,   171,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,   149,
-       0,     0,     0,     0,     0,     0,   126,     0,    68,    69,
-       0,     0,     0,     0,     0,     0,   147,     0,     0,     0,
-       0,     0,     0,     0,     0,   160,    82,     0,   110,   111,
-     108,   109,   114,   113,     0,     0,     0,     0,     0,     0,
+       0,   152,     0,     0,     0,     0,     0,     0,   126,     0,
+      67,    68,     0,     0,     0,     0,     0,     0,   150,     0,
+       0,     0,     0,     0,     0,     0,     0,   163,    81,     0,
+     109,   110,   107,   108,   113,   112,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   161,   162,   163,     0,
-       0,   152,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   172,    12,    62,    38,    64,    37,     0,    25,
-      24,    61,    59,    60,    58,    30,    33,    31,     0,    29,
-      28,    63,    57,    54,     0,    53,    34,    14,    13,   165,
-     164,   166,     0,     0,    15,    27,    26,    17,    16,    50,
-      45,   127,    47,   127,    49,   127,    42,     0,   127,    43,
-     127,    90,    91,    55,   143,     0,    67,     0,    71,    72,
-       0,    74,    75,     0,     0,   148,    21,    23,    22,    20,
-      19,    18,    84,    88,    85,     0,    80,    81,   118,     0,
-       0,   115,   116,   100,     0,     0,   102,   105,   104,     0,
-       0,    99,    98,    35,     0,     5,     6,     7,   151,   142,
-     140,   135,     0,     0,     0,   183,   182,   181,     0,     0,
-     174,   175,   176,   177,   178,     0,     0,     0,   155,   156,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,    70,
-       0,     0,     0,   125,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   157,   153,   179,   180,   131,
-      36,    32,     0,    44,    46,    48,    41,    39,    40,    92,
-      93,    56,    73,    76,     0,    77,    78,    89,    86,     0,
-     119,     0,   122,   123,   121,   101,   103,     0,     0,     0,
-       0,     0,    52,     0,   138,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,   158,    79,    87,   120,    97,    96,
-     144,    95,    94
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   164,
+     165,   166,     0,     0,   155,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   175,    12,    61,    37,    63,
+      36,     0,    25,    24,    60,    58,    59,    57,    30,    33,
+      31,     0,    29,    28,    62,    56,    53,    52,    14,    13,
+     168,   167,   169,     0,     0,    15,    27,    26,    17,    16,
+      49,    44,   127,    46,   127,    48,   127,    41,     0,   127,
+      42,   127,    89,    90,    54,   142,     0,    66,     0,    70,
+      71,     0,    73,    74,     0,     0,   151,    21,    23,    22,
+      20,    19,    18,    83,    87,    84,     0,    79,    80,     0,
+       0,   119,     0,     0,   114,   115,    99,     0,     0,   101,
+     104,   103,     0,     0,    98,    97,    34,     0,     5,     6,
+       7,   154,   141,   139,   135,     0,     0,     0,   186,   185,
+     184,     0,     0,   177,   178,   179,   180,   181,     0,     0,
+     158,   159,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    69,     0,     0,     0,   125,     0,     0,     0,     0,
+     144,   117,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   160,   156,   182,   183,   131,    35,    32,    43,    45,
+      47,    40,    38,    39,    91,    92,    55,    72,    75,     0,
+      76,    77,    88,    85,     0,   145,     0,     0,   120,     0,
+     122,   123,   121,   100,   102,     0,     0,     0,     0,     0,
+      51,     0,     0,     0,     0,   146,   118,     0,     0,     0,
+       0,     0,     0,   161,    78,    86,   147,    96,    95,   143,
+      94,    93
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     1,    39,   229,    40,    97,    62,    63,    64,    65,
-      66,    67,    68,    69,   276,    70,    71,    91,   427,    72,
-     103,    73,    74,    75,   159,    77,   113,   154,   283,   156,
-     157
+      -1,     1,    40,   232,    41,    98,    63,    64,    65,    66,
+      67,    68,    69,    70,    71,    72,    92,   435,   391,    73,
+     104,    74,    75,    76,   161,    78,   114,   156,   284,   158,
+     159
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -176
+#define YYPACT_NINF -179
 static const yytype_int16 yypact[] =
 {
-    -176,   464,  -176,   -63,   560,   637,    97,    97,   -24,   -24,
-      97,   556,   317,   618,    12,    12,    12,    12,   -27,    47,
-     -47,   -29,   725,   725,   -47,   -26,   -26,   -43,   -17,    97,
-     -17,   -23,   -24,   658,   -26,    97,    51,   -11,  -176,  -176,
-      -2,  -176,   556,   556,  -176,  -176,  -176,  -176,    -1,     2,
-      11,  -176,  -176,  -176,    24,  -176,  -176,    91,  -176,    26,
-     716,   556,    57,    65,  -176,    85,  -176,  -176,    92,    98,
-     104,   110,   119,   134,  -176,   155,   160,  -176,    69,   162,
-     165,   170,   172,   176,   556,   179,   180,   182,   183,   185,
-     556,   187,  -176,     2,    91,   736,   326,  -176,   196,  -176,
-      52,     6,   197,   198,   202,   203,   215,   216,   217,   222,
-    -176,   223,   235,  -176,    73,   -47,   -47,  -176,  -176,  -176,
-     -47,   -47,   239,    79,   178,  -176,   240,   246,  -176,    97,
-     247,   248,  -176,   252,   253,   255,   262,   263,   266,   267,
-     268,  -176,   556,   556,  -176,  -176,  -176,   556,   556,   556,
-     556,   193,   556,   556,   166,     9,  -176,   278,  -176,  -176,
-      69,  -176,   607,    97,    97,   109,    20,   683,    61,    97,
-      27,    97,    97,   340,   637,    97,    97,    97,    97,  -176,
-      97,    97,   -24,    97,   -24,   556,   166,   326,  -176,  -176,
-     199,   152,   742,   762,   153,   283,  -176,   696,    12,    12,
-      12,    12,    12,    12,    12,    97,  -176,    97,  -176,  -176,
-    -176,  -176,  -176,  -176,   382,     4,   556,   -26,   725,   -24,
-      72,   -17,    97,    97,    97,   725,    97,   556,    97,   527,
-     436,   567,   274,   276,   277,   279,   154,  -176,  -176,     4,
-      97,  -176,   556,   556,   556,   353,   339,   556,   556,   556,
-     556,   556,  -176,  -176,  -176,  -176,  -176,  -176,   284,  -176,
-    -176,  -176,  -176,  -176,  -176,  -176,  -176,  -176,   295,  -176,
-    -176,  -176,  -176,  -176,   303,  -176,  -176,  -176,  -176,  -176,
-    -176,  -176,   304,   308,  -176,  -176,  -176,  -176,  -176,  -176,
-    -176,   305,  -176,   316,  -176,   323,  -176,   325,   333,  -176,
-     334,   335,   336,  -176,   343,   342,  -176,   326,  -176,  -176,
-     326,  -176,  -176,   139,   344,  -176,  -176,  -176,  -176,  -176,
-    -176,  -176,  -176,   345,   348,   349,  -176,  -176,  -176,   354,
-     355,  -176,  -176,  -176,   356,   357,  -176,  -176,  -176,   360,
-     373,  -176,  -176,  -176,   374,  -176,  -176,  -176,  -176,  -176,
-    -176,  -176,   327,   377,   379,   298,   612,   506,   556,   556,
-     125,   125,  -176,  -176,  -176,   405,   410,   556,  -176,  -176,
-      97,    97,    97,    97,    97,    97,    -8,    -8,   556,  -176,
-     385,   388,   782,  -176,    -8,    12,    12,   -26,   381,    97,
-     -17,   382,   382,    97,   429,  -176,  -176,   498,   498,  -176,
-    -176,  -176,   390,  -176,  -176,  -176,  -176,  -176,  -176,  -176,
-    -176,  -176,  -176,  -176,   326,  -176,  -176,  -176,  -176,   393,
-     462,   712,  -176,  -176,  -176,  -176,  -176,   398,   399,   416,
-     419,   426,  -176,   451,  -176,   454,    12,   556,   328,    97,
-      97,   556,    97,    97,  -176,  -176,  -176,  -176,  -176,  -176,
-    -176,  -176,  -176
+    -179,   484,  -179,   -64,   581,   686,    74,    74,   -24,   -24,
+      74,   845,   641,   656,   -29,   -29,   -29,   -29,    19,   -11,
+     -54,   -38,   747,   747,   747,   -54,   -19,   -19,   -50,    -6,
+      74,    -6,   -14,   -24,   707,   -19,    74,   -36,    18,  -179,
+    -179,     2,  -179,   845,   845,  -179,  -179,  -179,  -179,    24,
+      27,    48,  -179,  -179,  -179,    61,  -179,  -179,   188,  -179,
+     717,   738,   845,    79,    81,  -179,    93,  -179,  -179,    99,
+     107,   116,   126,   127,   130,  -179,   132,   133,  -179,    87,
+     136,   138,   157,   159,   171,   845,   176,   179,   182,   184,
+     186,   845,   194,  -179,    27,   188,   762,   764,  -179,   196,
+    -179,    66,     8,   198,   200,   201,   202,   203,   206,   215,
+     216,  -179,   217,   219,  -179,   181,   -54,   -54,  -179,  -179,
+    -179,   -54,   -54,   220,   167,   221,   178,  -179,   223,   224,
+    -179,    74,   225,   226,  -179,   227,   231,   232,   233,   234,
+     236,   237,   238,  -179,   845,   845,  -179,  -179,  -179,   845,
+     845,   845,   845,   242,   845,   845,   229,     3,  -179,   377,
+    -179,  -179,    87,  -179,   629,    74,    74,   172,    26,   732,
+      39,    74,    74,    74,    74,   230,   686,    74,    74,    74,
+      74,  -179,    74,    74,   -24,    74,   -24,   845,   229,   764,
+    -179,  -179,   241,   243,   784,   814,   111,   254,  -179,    67,
+     -29,   -29,   -29,   -29,   -29,   -29,   -29,    74,  -179,    74,
+    -179,  -179,  -179,  -179,  -179,  -179,   821,    45,   830,   845,
+     -19,   747,   -24,    49,    -6,    74,    74,    74,   747,    74,
+     845,    74,   548,   463,   518,   246,   247,   248,   249,   155,
+    -179,  -179,    45,    74,  -179,   845,   845,   845,   323,   325,
+     845,   845,   845,   845,   845,  -179,  -179,  -179,  -179,  -179,
+    -179,   259,  -179,  -179,  -179,  -179,  -179,  -179,  -179,  -179,
+    -179,   260,  -179,  -179,  -179,  -179,  -179,  -179,  -179,  -179,
+    -179,  -179,  -179,   265,   266,  -179,  -179,  -179,  -179,  -179,
+    -179,  -179,   269,  -179,   270,  -179,   272,  -179,   278,   279,
+    -179,   280,   283,   284,  -179,   285,   275,  -179,   764,  -179,
+    -179,   764,  -179,  -179,   105,   286,  -179,  -179,  -179,  -179,
+    -179,  -179,  -179,  -179,   289,   296,   297,  -179,  -179,     9,
+     299,  -179,   301,   319,  -179,  -179,  -179,   320,   321,  -179,
+    -179,  -179,   324,   327,  -179,  -179,  -179,   328,  -179,  -179,
+    -179,  -179,  -179,  -179,  -179,   329,   333,   334,   591,   430,
+     451,   845,   845,    78,    78,  -179,  -179,  -179,   316,   353,
+    -179,  -179,    74,    74,    74,    74,    74,    74,    20,    20,
+     845,  -179,   335,   336,   841,  -179,    20,   -29,   -29,   369,
+     399,  -179,   338,   -19,   339,    74,    -6,   830,   830,    74,
+     382,  -179,  -179,   277,   277,  -179,  -179,  -179,  -179,  -179,
+    -179,  -179,  -179,  -179,  -179,  -179,  -179,  -179,  -179,   764,
+    -179,  -179,  -179,  -179,   345,   414,   387,     9,  -179,   322,
+    -179,  -179,  -179,  -179,  -179,   350,   351,   352,   354,   355,
+    -179,   366,   372,   -29,   393,  -179,  -179,   851,    74,    74,
+     845,    74,    74,  -179,  -179,  -179,  -179,  -179,  -179,  -179,
+    -179,  -179
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-    -176,  -176,   306,  -176,  -176,   -88,    -5,   -73,  -176,  -154,
-    -176,  -176,  -137,  -158,  -176,    67,    39,  -175,   141,   -15,
-     149,   113,   167,    80,    32,   200,   124,   -83,   299,    35,
-      70
+    -179,  -179,   222,  -179,  -179,   -72,    -5,   -61,  -179,  -157,
+    -179,  -179,  -149,  -161,    38,    31,  -178,    50,    28,   -15,
+      58,    98,   168,    82,    96,   112,    25,   -85,   211,    36,
+      88
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -874,236 +879,251 @@ static const yytype_int16 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint16 yytable[] =
 {
-      79,    82,    83,    85,    87,    89,   120,   188,   255,   267,
-     303,   186,    41,   111,   115,   195,    46,   240,    48,    46,
-      46,    48,    48,   191,   131,   256,   133,   135,   137,   110,
-     140,   271,   128,    45,    42,    43,    76,    81,    93,    78,
-      78,   279,   280,   281,    99,   105,    92,   100,    78,   110,
-      60,    98,    84,    84,   129,    84,    47,   123,   123,    50,
-     129,    45,    44,   143,    47,   138,    93,    50,    78,    46,
-      46,    48,    48,   144,   196,   274,   147,   145,   146,   148,
-     102,   106,   107,   108,   109,    80,   116,   241,   149,   254,
-      46,    47,    48,   104,    50,   160,   161,   151,    58,   152,
-     153,   150,    45,    90,   308,   311,    61,    93,   130,   208,
-     132,   134,    54,    55,   305,    56,    46,    47,    48,   179,
-      50,    86,    88,   114,   141,   142,    84,   189,   193,   194,
-     190,   112,   117,   162,   121,   249,   250,   251,   126,   127,
-      46,   163,    48,   118,   119,   136,   173,   139,   125,   129,
-      45,    84,    46,   352,    48,    93,   215,   253,   261,   262,
-     263,   164,   152,   153,   273,   275,   277,   278,   165,   284,
-     287,   288,   289,   290,   166,   292,   294,   296,   299,   301,
-     167,   209,   232,   233,   234,   235,   168,   237,   238,   216,
-     279,   280,   281,   314,   260,   169,    46,    78,    48,   270,
-     236,   257,    78,   411,   264,   266,   286,   272,   401,    78,
-     170,   400,   230,   231,   333,   382,   194,   338,   339,   340,
-     304,   342,   122,   124,   309,   312,   155,   190,   313,   318,
-     306,   171,    78,   265,   380,   206,   172,   381,   174,   210,
-     211,   175,   259,   239,   212,   213,   176,   269,   177,   329,
-     332,   330,   178,    78,   285,   180,   181,   341,   182,   183,
-      78,   184,   343,   185,   316,   319,   320,   321,   322,   323,
-     324,   325,   192,   197,   198,   258,   194,   317,   199,   200,
-     268,   242,   243,   244,   245,   246,   247,   248,   249,   250,
-     251,   201,   202,   203,   415,   297,   155,   302,   204,   205,
-     336,   337,   243,   244,   245,   246,   247,   248,   249,   250,
-     251,   207,   355,   356,   357,   214,   217,   360,   361,   362,
-     363,   364,   218,   219,   220,    42,    43,   328,   221,   222,
-     331,   223,   334,   335,    42,    43,    42,    43,   224,   225,
-     282,   435,   226,   227,   228,   291,   359,   293,   295,   298,
-     300,   315,   348,    44,   349,   350,   252,   351,    45,   358,
-     365,   282,    44,    93,    44,   403,   404,   405,   406,   407,
-     408,   366,   326,   422,   327,    52,    53,   279,   280,   281,
-     367,   370,   368,    46,   425,    48,   369,    94,   432,    58,
-      42,    43,   371,    95,    96,   344,   315,    61,    58,   372,
-      58,   373,   402,    90,   394,    90,    61,   354,    61,   374,
-     375,   376,   377,    92,   416,   409,   410,   190,    44,   378,
-     379,   384,   383,   417,   385,   386,   429,   429,   397,   398,
-     387,   388,   389,   390,   448,   449,   391,   451,   452,   242,
-     243,   244,   245,   246,   247,   248,   249,   250,   251,   392,
-     393,   399,   418,   419,    58,   395,   160,   396,    51,    90,
-     421,    84,    61,   412,     2,     3,   413,   433,   434,   436,
-     426,   437,   447,   146,   439,   440,   450,     4,     5,     6,
+      80,    83,    84,    86,    88,    90,   121,   258,   270,   304,
+     188,   243,    42,   112,   116,   259,    48,   197,   389,    51,
+      47,   274,    49,   111,   190,   133,   130,   135,   137,   139,
+      47,   142,    49,    47,    48,    49,   193,    51,   143,   144,
+      79,    79,    61,    99,   119,   120,   390,    93,   101,    79,
+     127,   103,   107,   108,   109,   110,    85,   117,   124,   124,
+     124,    85,    46,    47,   131,    49,   115,    94,    46,    85,
+      79,    48,   131,    94,    51,    43,    44,   198,   146,   147,
+     148,    46,   244,   280,   281,   282,    94,    81,   252,   253,
+     254,    55,    56,   145,    57,   105,   111,   162,   163,    85,
+      77,    82,   149,   257,    45,   150,    87,    89,   100,   106,
+     210,   132,    48,   134,   136,    51,   113,   118,    47,   122,
+      49,   181,   309,   312,   128,   129,   151,   131,   306,    85,
+     140,   138,   192,   141,   123,   125,   126,   208,    58,   152,
+      59,   212,   213,   195,   196,    60,   214,   215,    62,   280,
+     281,   282,   315,   211,   355,    47,   164,    49,   165,   256,
+     264,   265,   266,   154,   155,   175,   276,   277,   278,   279,
+     166,   285,   288,   289,   290,   291,   167,   293,   295,   297,
+     300,   302,   384,   196,   168,   235,   236,   237,   238,   219,
+     240,   241,   191,   169,   153,   260,   154,   155,   267,   269,
+      79,   275,   416,   170,   171,    79,   268,   172,   407,   173,
+     174,   406,    79,   176,    46,   177,    47,   336,    49,    94,
+     341,   342,   343,   305,   345,    47,    48,    49,   157,    51,
+     192,   314,   233,   234,   178,    79,   179,   317,   320,   321,
+     322,   323,   324,   325,   326,   217,   262,   382,   180,   239,
+     383,   272,   330,   182,   332,   333,   183,    79,   286,   184,
+     263,   185,   261,   186,    79,   273,   346,   271,   280,   281,
+     282,   187,   287,   194,    47,   199,    49,   200,   201,   202,
+     203,   318,   298,   204,   303,   250,   251,   252,   253,   254,
+     310,   313,   205,   206,   207,   319,   209,   216,   218,   157,
+     220,   221,   222,   223,   224,   339,   340,   242,   225,   226,
+     227,   228,   420,   229,   230,   231,   331,   335,   334,   196,
+     337,   338,   307,   316,   344,   351,   352,   353,   354,   361,
+      43,   447,   362,   358,   359,   360,   368,   369,   363,   364,
+     365,   366,   367,   283,   370,   371,   372,   373,   292,   374,
+     294,   296,   299,   301,   381,   375,   376,   377,   442,    45,
+     378,   379,   380,   405,   283,   385,   386,   408,   409,   410,
+     411,   412,   413,   387,   388,   327,   392,   328,   393,   430,
+     245,   246,   247,   248,   249,   250,   251,   252,   253,   254,
+     433,   198,   160,    58,   440,    59,   394,   395,   396,   347,
+      91,   397,    52,    62,   398,   399,   425,   400,   426,   414,
+     415,   357,   401,   402,   417,   418,    93,   422,   427,   429,
+     192,   441,   443,   444,   445,   423,   424,   448,   449,   450,
+     456,   451,   452,   437,   437,   247,   248,   249,   250,   251,
+     252,   253,   254,   457,   458,   453,   460,   461,   438,   403,
+     404,   454,   431,   356,   348,   446,   255,   248,   249,   250,
+     251,   252,   253,   254,     0,   162,   245,   246,   247,   248,
+     249,   250,   251,   252,   253,   254,     0,     0,   434,     0,
+     421,   455,     0,   148,     2,     3,   459,     0,     0,     0,
+       0,   428,   432,     0,     0,   436,   439,     4,     5,     6,
        7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
-      17,    18,   441,    19,    20,   442,    21,    22,    23,    24,
-     420,   424,   443,   446,   428,   431,   247,   248,   249,   250,
-     251,   346,   245,   246,   247,   248,   249,   250,   251,    25,
-      26,    27,    28,    29,    30,    31,    32,    33,     3,   444,
-      34,    35,   445,   430,    36,   345,    37,   423,   353,    38,
-       4,     5,     6,     7,     8,     9,    10,    11,    12,    13,
-      14,    15,    16,    17,    18,     0,    19,    20,     0,    21,
-      22,    23,    24,     0,    42,    43,     0,     0,    42,    43,
-     242,   243,   244,   245,   246,   247,   248,   249,   250,   251,
-       0,     0,    25,    26,    27,    28,    29,    30,    31,    32,
-      33,     0,    44,    34,    35,     0,    44,    36,     0,    37,
-       0,    45,    38,    46,    47,    48,    49,    50,    51,    52,
-      53,    54,    55,     0,    56,    42,    43,   244,   245,   246,
-     247,   248,   249,   250,   251,     0,    42,    43,    58,     0,
-      57,     0,    58,    90,     0,     0,    61,    59,     0,    60,
-      61,     0,   347,    44,     0,    42,    43,     0,    45,     0,
-      46,     0,    48,    49,    44,     0,    52,    53,    54,    55,
-       0,    56,    47,     0,     0,    50,    42,    43,     0,     0,
-       0,     0,     0,    44,     0,     0,     0,    57,     0,    58,
-      46,     0,    48,     0,    59,     0,    84,    61,    57,     0,
-      58,    42,    43,     0,    44,    59,     0,   101,    61,     0,
-       0,    46,     0,    48,    42,    43,     0,    57,     0,    58,
-       0,     0,     0,     0,    59,     0,     0,    61,     0,    44,
-      42,   438,     0,     0,    42,    43,     0,     0,    57,     0,
-      58,    51,    44,    42,    43,    90,     0,     0,    61,     0,
-      47,     0,     0,    50,    42,    43,     0,     0,    44,     0,
-      42,    43,    44,    57,     0,    58,     0,     0,     0,     0,
-      59,    44,    84,    61,     0,     0,    57,     0,    58,     0,
-      42,    43,    44,    59,     0,     0,    61,     0,    44,     0,
-     196,   158,    57,     0,    58,   158,    57,     0,    58,    90,
-      42,    43,    61,    90,     0,    57,    61,    58,    44,     0,
-       0,     0,    90,     0,     0,    61,    94,     0,    58,     0,
-       0,     0,    94,   187,    58,     0,    61,     0,    44,   307,
-       0,     0,    61,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,    94,     0,    58,     0,     0,     0,     0,   310,
-       0,     0,    61,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,    94,     0,    58,     0,     0,     0,     0,   414,
-       0,     0,    61
+      17,    18,     0,    19,    20,     0,    21,    22,    23,    24,
+      25,   245,   246,   247,   248,   249,   250,   251,   252,   253,
+     254,     0,     0,     0,     0,     0,     0,     0,     0,   349,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,     3,
+       0,    35,    36,     0,     0,    37,     0,    38,     0,     0,
+      39,     4,     5,     6,     7,     8,     9,    10,    11,    12,
+      13,    14,    15,    16,    17,    18,     0,    19,    20,     0,
+      21,    22,    23,    24,    25,     0,     0,     0,     0,    43,
+      44,     0,     0,     0,   350,   246,   247,   248,   249,   250,
+     251,   252,   253,   254,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,     0,     0,    35,    36,     0,    45,    37,
+       0,    38,     0,    46,    39,    47,    48,    49,    50,    51,
+      52,    53,    54,    55,    56,     0,    57,    43,    44,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    43,
+      44,     0,    58,     0,    59,     0,     0,     0,     0,    60,
+       0,    61,    62,     0,    43,    44,    45,     0,     0,     0,
+       0,    46,     0,    47,     0,    49,    50,     0,    45,    53,
+      54,    55,    56,    46,    57,     0,     0,     0,    94,     0,
+       0,     0,     0,    45,    43,    44,     0,     0,     0,     0,
+      58,    48,    59,     0,    51,     0,     0,    60,     0,    85,
+      62,     0,    95,     0,    59,    43,    44,     0,    96,    97,
+       0,     0,    62,    45,     0,    43,    44,    58,     0,    59,
+      47,     0,    49,     0,    60,     0,   102,    62,     0,     0,
+      43,    44,     0,     0,    45,     0,    43,    44,     0,     0,
+       0,    47,     0,    49,    45,    43,    44,    58,     0,    59,
+       0,    47,     0,    49,    60,     0,     0,    62,     0,    45,
+      43,    44,    43,    44,     0,    45,     0,     0,    58,     0,
+      59,    52,     0,     0,    45,    91,     0,     0,    62,     0,
+      59,     0,    43,    44,     0,    91,     0,     0,    62,    45,
+       0,    45,     0,    58,     0,    59,     0,     0,   160,    58,
+      60,    59,    85,    62,    53,    54,    91,     0,    58,    62,
+      59,    45,    43,    44,     0,    91,     0,     0,    62,    43,
+      44,     0,     0,    95,     0,    59,     0,    59,    43,    44,
+     189,     0,    91,    62,     0,    62,     0,     0,     0,    43,
+      44,    45,     0,    43,    44,    95,     0,    59,    45,    43,
+      44,     0,   308,     0,     0,    62,     0,    45,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,    45,     0,
+       0,     0,    45,     0,     0,    95,     0,    59,    45,     0,
+       0,     0,   311,     0,    59,    62,     0,     0,     0,    91,
+       0,   329,    62,    59,     0,     0,     0,     0,    91,     0,
+      85,    62,    95,     0,    59,     0,     0,     0,    59,   419,
+     316,     0,    62,    91,    59,     0,    62,     0,     0,    91,
+       0,     0,    62
 };
 
 static const yytype_int16 yycheck[] =
 {
-       5,     6,     7,     8,     9,    10,    21,    95,   162,   167,
-     185,    94,    75,    18,    19,     9,    43,     8,    45,    43,
-      43,    45,    45,    96,    29,   162,    31,    32,    33,    76,
-      35,   168,    75,    41,     8,     9,     4,     5,    46,     4,
-       5,    37,    38,    39,    12,    13,    11,    12,    13,    76,
-      79,    12,    79,    79,    77,    79,    44,    22,    23,    47,
-      77,    41,    36,    74,    44,    33,    46,    47,    33,    43,
-      43,    45,    45,    75,    68,    48,    77,    42,    43,    77,
-      13,    14,    15,    16,    17,     5,    19,    78,    77,   162,
-      43,    44,    45,    13,    47,    60,    61,     6,    72,     8,
-       9,    77,    41,    77,   192,   193,    80,    46,    28,   114,
-      30,    31,    51,    52,   187,    54,    43,    44,    45,    84,
-      47,     8,     9,    76,    73,    74,    79,    95,    76,    77,
-      95,    18,    19,    76,    21,    10,    11,    12,    25,    26,
-      43,    76,    45,    19,    20,    32,    77,    34,    24,    77,
-      41,    79,    43,   236,    45,    46,    77,   162,   163,   164,
-     165,    76,     8,     9,   169,   170,   171,   172,    76,   174,
-     175,   176,   177,   178,    76,   180,   181,   182,   183,   184,
-      76,   114,   147,   148,   149,   150,    76,   152,   153,    11,
-      37,    38,    39,    40,   162,    76,    43,   162,    45,   167,
-       7,   162,   167,   378,   165,   166,   174,   168,   366,   174,
-      76,   365,   142,   143,   219,    76,    77,   222,   223,   224,
-     185,   226,    22,    23,   192,   193,    59,   192,   193,   197,
-      78,    76,   197,   166,   307,   111,    76,   310,    76,   115,
-     116,    76,   162,    77,   120,   121,    76,   167,    76,   214,
-     218,   216,    76,   218,   174,    76,    76,   225,    76,    76,
-     225,    76,   227,    76,   197,   198,   199,   200,   201,   202,
-     203,   204,    76,    76,    76,   162,    77,   197,    76,    76,
-     167,     3,     4,     5,     6,     7,     8,     9,    10,    11,
-      12,    76,    76,    76,   382,   182,   129,   184,    76,    76,
-     220,   221,     4,     5,     6,     7,     8,     9,    10,    11,
-      12,    76,   242,   243,   244,    76,    76,   247,   248,   249,
-     250,   251,    76,    76,    76,     8,     9,   214,    76,    76,
-     217,    76,   219,   220,     8,     9,     8,     9,    76,    76,
-     173,   414,    76,    76,    76,   178,     7,   180,   181,   182,
-     183,    68,    78,    36,    78,    78,    78,    78,    41,     6,
-      76,   194,    36,    46,    36,   370,   371,   372,   373,   374,
-     375,    76,   205,   388,   207,    49,    50,    37,    38,    39,
-      77,    76,    78,    43,   389,    45,    78,    70,   393,    72,
-       8,     9,    76,    76,    77,   228,    68,    80,    72,    76,
-      72,    76,   367,    77,    77,    77,    80,   240,    80,    76,
-      76,    76,    76,   378,   382,   376,   377,   382,    36,    76,
-      78,    76,    78,   384,    76,    76,   391,   392,   358,   359,
-      76,    76,    76,    76,   439,   440,    76,   442,   443,     3,
-       4,     5,     6,     7,     8,     9,    10,    11,    12,    76,
-      76,    46,   385,   386,    72,    78,   421,    78,    48,    77,
-      79,    79,    80,    78,     0,     1,    78,    38,    78,    76,
-     390,     9,   437,   438,    76,    76,   441,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
-      26,    27,    76,    29,    30,    76,    32,    33,    34,    35,
-     387,   388,    76,   436,   391,   392,     8,     9,    10,    11,
-      12,    75,     6,     7,     8,     9,    10,    11,    12,    55,
-      56,    57,    58,    59,    60,    61,    62,    63,     1,    78,
-      66,    67,    78,   392,    70,   229,    72,   388,   239,    75,
-      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    -1,    29,    30,    -1,    32,
-      33,    34,    35,    -1,     8,     9,    -1,    -1,     8,     9,
+       5,     6,     7,     8,     9,    10,    21,   164,   169,   187,
+      95,     8,    76,    18,    19,   164,    45,     9,     9,    48,
+      44,   170,    46,    77,    96,    30,    76,    32,    33,    34,
+      44,    36,    46,    44,    45,    46,    97,    48,    74,    75,
+       4,     5,    80,    12,    19,    20,    37,    11,    12,    13,
+      25,    13,    14,    15,    16,    17,    80,    19,    22,    23,
+      24,    80,    42,    44,    78,    46,    77,    47,    42,    80,
+      34,    45,    78,    47,    48,     8,     9,    69,    76,    43,
+      44,    42,    79,    38,    39,    40,    47,     5,    10,    11,
+      12,    52,    53,    75,    55,    13,    77,    61,    62,    80,
+       4,     5,    78,   164,    37,    78,     8,     9,    12,    13,
+     115,    29,    45,    31,    32,    48,    18,    19,    44,    21,
+      46,    85,   194,   195,    26,    27,    78,    78,   189,    80,
+      34,    33,    96,    35,    22,    23,    24,   112,    71,    78,
+      73,   116,   117,    77,    78,    78,   121,   122,    81,    38,
+      39,    40,    41,   115,   239,    44,    77,    46,    77,   164,
+     165,   166,   167,     8,     9,    78,   171,   172,   173,   174,
+      77,   176,   177,   178,   179,   180,    77,   182,   183,   184,
+     185,   186,    77,    78,    77,   149,   150,   151,   152,    11,
+     154,   155,    96,    77,     6,   164,     8,     9,   167,   168,
+     164,   170,   380,    77,    77,   169,   168,    77,   369,    77,
+      77,   368,   176,    77,    42,    77,    44,   222,    46,    47,
+     225,   226,   227,   187,   229,    44,    45,    46,    60,    48,
+     194,   195,   144,   145,    77,   199,    77,   199,   200,   201,
+     202,   203,   204,   205,   206,    78,   164,   308,    77,     7,
+     311,   169,   216,    77,   218,   219,    77,   221,   176,    77,
+     164,    77,   164,    77,   228,   169,   230,   169,    38,    39,
+      40,    77,   176,    77,    44,    77,    46,    77,    77,    77,
+      77,   199,   184,    77,   186,     8,     9,    10,    11,    12,
+     194,   195,    77,    77,    77,   199,    77,    77,    77,   131,
+      77,    77,    77,    77,    77,   223,   224,    78,    77,    77,
+      77,    77,   384,    77,    77,    77,   218,   221,   220,    78,
+     222,   223,    79,    69,   228,    79,    79,    79,    79,     6,
+       8,     9,     7,   245,   246,   247,    77,    77,   250,   251,
+     252,   253,   254,   175,    79,    79,    77,    77,   180,    77,
+     182,   183,   184,   185,    79,    77,    77,    77,   419,    37,
+      77,    77,    77,    47,   196,    79,    77,   372,   373,   374,
+     375,   376,   377,    77,    77,   207,    77,   209,    77,   394,
        3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
-      -1,    -1,    55,    56,    57,    58,    59,    60,    61,    62,
-      63,    -1,    36,    66,    67,    -1,    36,    70,    -1,    72,
-      -1,    41,    75,    43,    44,    45,    46,    47,    48,    49,
-      50,    51,    52,    -1,    54,     8,     9,     5,     6,     7,
-       8,     9,    10,    11,    12,    -1,     8,     9,    72,    -1,
-      70,    -1,    72,    77,    -1,    -1,    80,    77,    -1,    79,
-      80,    -1,    75,    36,    -1,     8,     9,    -1,    41,    -1,
-      43,    -1,    45,    46,    36,    -1,    49,    50,    51,    52,
-      -1,    54,    44,    -1,    -1,    47,     8,     9,    -1,    -1,
-      -1,    -1,    -1,    36,    -1,    -1,    -1,    70,    -1,    72,
-      43,    -1,    45,    -1,    77,    -1,    79,    80,    70,    -1,
-      72,     8,     9,    -1,    36,    77,    -1,    79,    80,    -1,
-      -1,    43,    -1,    45,     8,     9,    -1,    70,    -1,    72,
-      -1,    -1,    -1,    -1,    77,    -1,    -1,    80,    -1,    36,
-       8,     9,    -1,    -1,     8,     9,    -1,    -1,    70,    -1,
-      72,    48,    36,     8,     9,    77,    -1,    -1,    80,    -1,
-      44,    -1,    -1,    47,     8,     9,    -1,    -1,    36,    -1,
-       8,     9,    36,    70,    -1,    72,    -1,    -1,    -1,    -1,
-      77,    36,    79,    80,    -1,    -1,    70,    -1,    72,    -1,
-       8,     9,    36,    77,    -1,    -1,    80,    -1,    36,    -1,
-      68,    69,    70,    -1,    72,    69,    70,    -1,    72,    77,
-       8,     9,    80,    77,    -1,    70,    80,    72,    36,    -1,
-      -1,    -1,    77,    -1,    -1,    80,    70,    -1,    72,    -1,
-      -1,    -1,    70,    77,    72,    -1,    80,    -1,    36,    77,
-      -1,    -1,    80,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    70,    -1,    72,    -1,    -1,    -1,    -1,    77,
-      -1,    -1,    80,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    70,    -1,    72,    -1,    -1,    -1,    -1,    77,
-      -1,    -1,    80
+     395,    69,    70,    71,   399,    73,    77,    77,    77,   231,
+      78,    77,    49,    81,    77,    77,    37,    78,     9,   378,
+     379,   243,    79,    79,    79,    79,   380,   386,    80,    80,
+     384,    39,    77,     9,    37,   387,   388,    77,    77,    77,
+      37,    77,    77,   397,   398,     5,     6,     7,     8,     9,
+      10,    11,    12,   448,   449,    79,   451,   452,   398,   361,
+     362,    79,   394,   242,   232,   427,    79,     6,     7,     8,
+       9,    10,    11,    12,    -1,   429,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,    -1,    -1,   396,    -1,
+     384,   443,    -1,   447,     0,     1,   450,    -1,    -1,    -1,
+      -1,   393,   394,    -1,    -1,   397,   398,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    -1,    29,    30,    -1,    32,    33,    34,    35,
+      36,     3,     4,     5,     6,     7,     8,     9,    10,    11,
+      12,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    76,
+      56,    57,    58,    59,    60,    61,    62,    63,    64,     1,
+      -1,    67,    68,    -1,    -1,    71,    -1,    73,    -1,    -1,
+      76,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    23,    24,    25,    26,    27,    -1,    29,    30,    -1,
+      32,    33,    34,    35,    36,    -1,    -1,    -1,    -1,     8,
+       9,    -1,    -1,    -1,    76,     4,     5,     6,     7,     8,
+       9,    10,    11,    12,    56,    57,    58,    59,    60,    61,
+      62,    63,    64,    -1,    -1,    67,    68,    -1,    37,    71,
+      -1,    73,    -1,    42,    76,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    -1,    55,     8,     9,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     8,
+       9,    -1,    71,    -1,    73,    -1,    -1,    -1,    -1,    78,
+      -1,    80,    81,    -1,     8,     9,    37,    -1,    -1,    -1,
+      -1,    42,    -1,    44,    -1,    46,    47,    -1,    37,    50,
+      51,    52,    53,    42,    55,    -1,    -1,    -1,    47,    -1,
+      -1,    -1,    -1,    37,     8,     9,    -1,    -1,    -1,    -1,
+      71,    45,    73,    -1,    48,    -1,    -1,    78,    -1,    80,
+      81,    -1,    71,    -1,    73,     8,     9,    -1,    77,    78,
+      -1,    -1,    81,    37,    -1,     8,     9,    71,    -1,    73,
+      44,    -1,    46,    -1,    78,    -1,    80,    81,    -1,    -1,
+       8,     9,    -1,    -1,    37,    -1,     8,     9,    -1,    -1,
+      -1,    44,    -1,    46,    37,     8,     9,    71,    -1,    73,
+      -1,    44,    -1,    46,    78,    -1,    -1,    81,    -1,    37,
+       8,     9,     8,     9,    -1,    37,    -1,    -1,    71,    -1,
+      73,    49,    -1,    -1,    37,    78,    -1,    -1,    81,    -1,
+      73,    -1,     8,     9,    -1,    78,    -1,    -1,    81,    37,
+      -1,    37,    -1,    71,    -1,    73,    -1,    -1,    70,    71,
+      78,    73,    80,    81,    50,    51,    78,    -1,    71,    81,
+      73,    37,     8,     9,    -1,    78,    -1,    -1,    81,     8,
+       9,    -1,    -1,    71,    -1,    73,    -1,    73,     8,     9,
+      78,    -1,    78,    81,    -1,    81,    -1,    -1,    -1,     8,
+       9,    37,    -1,     8,     9,    71,    -1,    73,    37,     8,
+       9,    -1,    78,    -1,    -1,    81,    -1,    37,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    37,    -1,
+      -1,    -1,    37,    -1,    -1,    71,    -1,    73,    37,    -1,
+      -1,    -1,    78,    -1,    73,    81,    -1,    -1,    -1,    78,
+      -1,    80,    81,    73,    -1,    -1,    -1,    -1,    78,    -1,
+      80,    81,    71,    -1,    73,    -1,    -1,    -1,    73,    78,
+      69,    -1,    81,    78,    73,    -1,    81,    -1,    -1,    78,
+      -1,    -1,    81
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    82,     0,     1,    13,    14,    15,    16,    17,    18,
+       0,    83,     0,     1,    13,    14,    15,    16,    17,    18,
       19,    20,    21,    22,    23,    24,    25,    26,    27,    29,
-      30,    32,    33,    34,    35,    55,    56,    57,    58,    59,
-      60,    61,    62,    63,    66,    67,    70,    72,    75,    83,
-      85,    75,     8,     9,    36,    41,    43,    44,    45,    46,
-      47,    48,    49,    50,    51,    52,    54,    70,    72,    77,
-      79,    80,    87,    88,    89,    90,    91,    92,    93,    94,
-      96,    97,   100,   102,   103,   104,   105,   106,   110,    87,
-     104,   105,    87,    87,    79,    87,   102,    87,   102,    87,
-      77,    98,   110,    46,    70,    76,    77,    86,    97,   105,
-     110,    79,    96,   101,   104,   105,    96,    96,    96,    96,
-      76,    87,   102,   107,    76,    87,    96,   102,   107,   107,
-     100,   102,   106,   110,   106,   107,   102,   102,    75,    77,
-     104,    87,   104,    87,   104,    87,   102,    87,   105,   102,
-      87,    73,    74,    74,    75,   110,   110,    77,    77,    77,
-      77,     6,     8,     9,   108,   103,   110,   111,    69,   105,
-     110,   110,    76,    76,    76,    76,    76,    76,    76,    76,
-      76,    76,    76,    77,    76,    76,    76,    76,    76,   110,
-      76,    76,    76,    76,    76,    76,   108,    77,    86,   105,
-     110,    88,    76,    76,    77,     9,    68,    76,    76,    76,
-      76,    76,    76,    76,    76,    76,   107,    76,    87,    96,
-     107,   107,   107,   107,    76,    77,    11,    76,    76,    76,
-      76,    76,    76,    76,    76,    76,    76,    76,    76,    84,
-     111,   111,   110,   110,   110,   110,     7,   110,   110,    77,
-       8,    78,     3,     4,     5,     6,     7,     8,     9,    10,
-      11,    12,    78,    87,    88,    90,    93,    97,   102,   104,
-     105,    87,    87,    87,    97,    96,    97,    94,   102,   104,
-     105,    93,    97,    87,    48,    87,    95,    87,    87,    37,
-      38,    39,   103,   109,    87,   104,   105,    87,    87,    87,
-      87,   103,    87,   103,    87,   103,    87,   102,   103,    87,
-     103,    87,   102,    98,   110,    88,    78,    77,    86,   105,
-      77,    86,   105,   110,    40,    68,    96,   104,   105,    96,
-      96,    96,    96,    96,    96,    96,   103,   103,   102,   110,
-     110,   102,   105,    87,   102,   102,   104,   104,    87,    87,
-      87,   105,    87,   110,   103,    83,    75,    75,    78,    78,
-      78,    78,   108,   109,   103,   111,   111,   111,     6,     7,
-     111,   111,   111,   111,   111,    76,    76,    77,    78,    78,
-      76,    76,    76,    76,    76,    76,    76,    76,    76,    78,
-      88,    88,    76,    78,    76,    76,    76,    76,    76,    76,
-      76,    76,    76,    76,    77,    78,    78,   111,   111,    46,
-      90,    94,   110,    87,    87,    87,    87,    87,    87,    97,
-      97,    98,    78,    78,    77,    86,   105,    97,    96,    96,
-     102,    79,   100,   101,   102,    87,   104,    99,   102,   110,
-      99,   102,    87,    38,    78,    88,    76,     9,     9,    76,
-      76,    76,    76,    76,    78,    78,    96,   110,    87,    87,
-     110,    87,    87
+      30,    32,    33,    34,    35,    36,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    67,    68,    71,    73,    76,
+      84,    86,    76,     8,     9,    37,    42,    44,    45,    46,
+      47,    48,    49,    50,    51,    52,    53,    55,    71,    73,
+      78,    80,    81,    88,    89,    90,    91,    92,    93,    94,
+      95,    96,    97,   101,   103,   104,   105,   106,   107,   111,
+      88,   105,   106,    88,    88,    80,    88,   103,    88,   103,
+      88,    78,    98,   111,    47,    71,    77,    78,    87,    97,
+     106,   111,    80,    96,   102,   105,   106,    96,    96,    96,
+      96,    77,    88,   103,   108,    77,    88,    96,   103,   108,
+     108,   101,   103,   107,   111,   107,   107,   108,   103,   103,
+      76,    78,   105,    88,   105,    88,   105,    88,   103,    88,
+     106,   103,    88,    74,    75,    75,    76,   111,   111,    78,
+      78,    78,    78,     6,     8,     9,   109,   104,   111,   112,
+      70,   106,   111,   111,    77,    77,    77,    77,    77,    77,
+      77,    77,    77,    77,    77,    78,    77,    77,    77,    77,
+      77,   111,    77,    77,    77,    77,    77,    77,   109,    78,
+      87,   106,   111,    89,    77,    77,    78,     9,    69,    77,
+      77,    77,    77,    77,    77,    77,    77,    77,   108,    77,
+      88,    96,   108,   108,   108,   108,    77,    78,    77,    11,
+      77,    77,    77,    77,    77,    77,    77,    77,    77,    77,
+      77,    77,    85,   112,   112,   111,   111,   111,   111,     7,
+     111,   111,    78,     8,    79,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    79,    88,    89,    91,    94,
+      97,   103,   105,   106,    88,    88,    88,    97,    96,    97,
+      95,   103,   105,   106,    94,    97,    88,    88,    88,    88,
+      38,    39,    40,   104,   110,    88,   105,   106,    88,    88,
+      88,    88,   104,    88,   104,    88,   104,    88,   103,   104,
+      88,   104,    88,   103,    98,   111,    89,    79,    78,    87,
+     106,    78,    87,   106,   111,    41,    69,    96,   105,   106,
+      96,    96,    96,    96,    96,    96,    96,   104,   104,    80,
+     111,   103,   111,   111,   103,   106,    88,   103,   103,   105,
+     105,    88,    88,    88,   106,    88,   111,   104,    84,    76,
+      76,    79,    79,    79,    79,   109,   110,   104,   112,   112,
+     112,     6,     7,   112,   112,   112,   112,   112,    77,    77,
+      79,    79,    77,    77,    77,    77,    77,    77,    77,    77,
+      77,    79,    89,    89,    77,    79,    77,    77,    77,     9,
+      37,   100,    77,    77,    77,    77,    77,    77,    77,    77,
+      78,    79,    79,   112,   112,    47,    91,    95,    88,    88,
+      88,    88,    88,    88,    97,    97,    98,    79,    79,    78,
+      87,   106,    97,    96,    96,    37,     9,    80,   103,    80,
+     101,   102,   103,    88,   105,    99,   103,   111,    99,   103,
+      88,    39,    89,    77,     9,    37,   100,     9,    77,    77,
+      77,    77,    77,    79,    79,    96,    37,    88,    88,   111,
+      88,    88
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1955,189 +1975,189 @@ yyreduce:
   case 12:
 #line 103 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 13:
 #line 107 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 14:
 #line 111 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 15:
 #line 115 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 16:
 #line 119 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 17:
 #line 123 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 18:
 #line 130 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 19:
 #line 134 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 20:
 #line 138 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 21:
 #line 142 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 22:
 #line 146 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 23:
 #line 150 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 24:
 #line 157 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 25:
 #line 161 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 26:
 #line 165 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 27:
 #line 169 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 28:
 #line 176 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 29:
 #line 180 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 30:
 #line 187 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 31:
 #line 191 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 32:
 #line 195 "a.y"
     {
-               outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
+               outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 33:
 #line 199 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 34:
 #line 203 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
        }
     break;
 
   case 35:
-#line 207 "a.y"
+#line 210 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
+               outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 36:
 #line 214 "a.y"
     {
-               outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 37:
 #line 218 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 38:
-#line 222 "a.y"
+#line 228 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
@@ -2151,238 +2171,238 @@ yyreduce:
   case 40:
 #line 236 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 41:
 #line 240 "a.y"
     {
-               outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 42:
 #line 244 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 43:
 #line 248 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 44:
 #line 252 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 45:
 #line 256 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 46:
 #line 260 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 47:
 #line 264 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 48:
 #line 268 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 49:
 #line 272 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 50:
 #line 276 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), 0, &(yyvsp[(2) - (2)].addr));
        }
     break;
 
   case 51:
-#line 280 "a.y"
+#line 283 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), NREG, &(yyvsp[(2) - (2)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 52:
-#line 287 "a.y"
+#line 290 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 53:
 #line 294 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 54:
-#line 298 "a.y"
+#line 301 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].addr).reg, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 55:
 #line 305 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].addr).reg, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 56:
-#line 309 "a.y"
+#line 313 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 57:
 #line 317 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 58:
 #line 321 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 59:
 #line 325 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 60:
 #line 329 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 61:
 #line 333 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 62:
 #line 337 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 63:
 #line 341 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 64:
-#line 345 "a.y"
+#line 350 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &(yyvsp[(2) - (2)].addr));
        }
     break;
 
   case 65:
 #line 354 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &(yyvsp[(2) - (2)].addr));
+               outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &(yyvsp[(2) - (2)].addr));
        }
     break;
 
   case 66:
 #line 358 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &(yyvsp[(2) - (2)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &nullgen, 0, &(yyvsp[(3) - (4)].addr));
        }
     break;
 
   case 67:
 #line 362 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &nullgen, NREG, &(yyvsp[(3) - (4)].addr));
+               outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr));
        }
     break;
 
   case 68:
 #line 366 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+               outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr));
        }
     break;
 
   case 69:
 #line 370 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+               outcode((yyvsp[(1) - (5)].lval), &nullgen, 0, &(yyvsp[(4) - (5)].addr));
        }
     break;
 
   case 70:
 #line 374 "a.y"
     {
-               outcode((yyvsp[(1) - (5)].lval), &nullgen, NREG, &(yyvsp[(4) - (5)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 71:
 #line 378 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 72:
 #line 382 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(5) - (6)].addr));
        }
     break;
 
   case 73:
 #line 386 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(5) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &nullgen, (yyvsp[(2) - (4)].lval), &(yyvsp[(4) - (4)].addr));
        }
     break;
 
@@ -2396,47 +2416,47 @@ yyreduce:
   case 75:
 #line 394 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &nullgen, (yyvsp[(2) - (4)].lval), &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &nullgen, (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr));
        }
     break;
 
   case 76:
 #line 398 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &nullgen, (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr));
+               Addr g;
+               g = nullgen;
+               g.type = TYPE_CONST;
+               g.offset = (yyvsp[(2) - (6)].lval);
+               outcode((yyvsp[(1) - (6)].lval), &g, REG_R0+(yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 77:
-#line 402 "a.y"
+#line 406 "a.y"
     {
                Addr g;
                g = nullgen;
-               g.type = D_CONST;
+               g.type = TYPE_CONST;
                g.offset = (yyvsp[(2) - (6)].lval);
-               outcode((yyvsp[(1) - (6)].lval), &g, (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &g, REG_R0+(yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 78:
-#line 410 "a.y"
+#line 414 "a.y"
     {
                Addr g;
                g = nullgen;
-               g.type = D_CONST;
-               g.offset = (yyvsp[(2) - (6)].lval);
-               outcode((yyvsp[(1) - (6)].lval), &g, (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               g.type = TYPE_CONST;
+               g.offset = (yyvsp[(2) - (8)].lval);
+               outcode((yyvsp[(1) - (8)].lval), &g, REG_R0+(yyvsp[(4) - (8)].lval), &(yyvsp[(7) - (8)].addr));
        }
     break;
 
   case 79:
-#line 418 "a.y"
+#line 425 "a.y"
     {
-               Addr g;
-               g = nullgen;
-               g.type = D_CONST;
-               g.offset = (yyvsp[(2) - (8)].lval);
-               outcode((yyvsp[(1) - (8)].lval), &g, (yyvsp[(4) - (8)].lval), &(yyvsp[(7) - (8)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
        }
     break;
 
@@ -2450,77 +2470,77 @@ yyreduce:
   case 81:
 #line 433 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
+               outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen);
        }
     break;
 
   case 82:
 #line 437 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+               outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen);
        }
     break;
 
   case 83:
-#line 441 "a.y"
+#line 444 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 84:
 #line 448 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 85:
 #line 452 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 86:
 #line 456 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr));
+               outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
        }
     break;
 
   case 87:
 #line 460 "a.y"
     {
-               outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 88:
 #line 464 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
        }
     break;
 
   case 89:
-#line 468 "a.y"
+#line 471 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 90:
 #line 475 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 91:
 #line 479 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
        }
     break;
 
@@ -2532,9 +2552,9 @@ yyreduce:
     break;
 
   case 93:
-#line 487 "a.y"
+#line 490 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
+               outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
        }
     break;
 
@@ -2560,368 +2580,379 @@ yyreduce:
     break;
 
   case 97:
-#line 506 "a.y"
+#line 509 "a.y"
     {
-               outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 98:
 #line 513 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 99:
-#line 517 "a.y"
+#line 521 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 100:
 #line 525 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 101:
 #line 529 "a.y"
     {
-               outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 102:
 #line 533 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
        }
     break;
 
   case 103:
 #line 537 "a.y"
     {
-               outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 104:
 #line 541 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 105:
 #line 545 "a.y"
     {
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), 0, &nullgen);
        }
     break;
 
   case 106:
-#line 549 "a.y"
+#line 552 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
+               outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen);
        }
     break;
 
   case 107:
 #line 556 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+               outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen);
        }
     break;
 
   case 108:
 #line 560 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+               outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen);
        }
     break;
 
   case 109:
 #line 564 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+               outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr));
        }
     break;
 
   case 110:
 #line 568 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+               outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr));
        }
     break;
 
   case 111:
 #line 572 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+               outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), 0, &nullgen);
        }
     break;
 
   case 112:
-#line 576 "a.y"
+#line 579 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
+               outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen);
        }
     break;
 
   case 113:
 #line 583 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+               outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen);
        }
     break;
 
   case 114:
-#line 587 "a.y"
+#line 590 "a.y"
     {
-               outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+               if((yyvsp[(2) - (4)].addr).type != TYPE_CONST || (yyvsp[(4) - (4)].addr).type != TYPE_CONST)
+                       yyerror("arguments to PCDATA must be integer constants");
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 115:
-#line 594 "a.y"
+#line 599 "a.y"
     {
-               if((yyvsp[(2) - (4)].addr).type != D_CONST || (yyvsp[(4) - (4)].addr).type != D_CONST)
-                       yyerror("arguments to PCDATA must be integer constants");
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               if((yyvsp[(2) - (4)].addr).type != TYPE_CONST)
+                       yyerror("index for FUNCDATA must be integer constant");
+               if((yyvsp[(4) - (4)].addr).type != NAME_EXTERN && (yyvsp[(4) - (4)].addr).type != NAME_STATIC && (yyvsp[(4) - (4)].addr).type != TYPE_MEM)
+                       yyerror("value for FUNCDATA must be symbol reference");
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 116:
-#line 603 "a.y"
+#line 610 "a.y"
     {
-               if((yyvsp[(2) - (4)].addr).type != D_CONST)
-                       yyerror("index for FUNCDATA must be integer constant");
-               if((yyvsp[(4) - (4)].addr).type != D_EXTERN && (yyvsp[(4) - (4)].addr).type != D_STATIC && (yyvsp[(4) - (4)].addr).type != D_OREG)
-                       yyerror("value for FUNCDATA must be symbol reference");
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen);
        }
     break;
 
   case 117:
-#line 614 "a.y"
+#line 617 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+               settext((yyvsp[(2) - (5)].addr).sym);
+               outcode((yyvsp[(1) - (5)].lval), &(yyvsp[(2) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
        }
     break;
 
   case 118:
-#line 621 "a.y"
+#line 622 "a.y"
     {
-               settext((yyvsp[(2) - (4)].addr).sym);
-               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+               settext((yyvsp[(2) - (7)].addr).sym);
+               outcode((yyvsp[(1) - (7)].lval), &(yyvsp[(2) - (7)].addr), 0, &(yyvsp[(7) - (7)].addr));
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (7)].lval);
+               }
        }
     break;
 
   case 119:
-#line 626 "a.y"
+#line 634 "a.y"
     {
-               settext((yyvsp[(2) - (6)].addr).sym);
-               (yyvsp[(6) - (6)].addr).offset &= 0xffffffffull;
-               (yyvsp[(6) - (6)].addr).offset |= (vlong)ArgsSizeUnknown << 32;
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               settext((yyvsp[(2) - (4)].addr).sym);
+               outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
        }
     break;
 
   case 120:
-#line 633 "a.y"
+#line 639 "a.y"
     {
-               settext((yyvsp[(2) - (8)].addr).sym);
-               (yyvsp[(6) - (8)].addr).offset &= 0xffffffffull;
-               (yyvsp[(6) - (8)].addr).offset |= ((yyvsp[(8) - (8)].lval) & 0xffffffffull) << 32;
-               outcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].lval), &(yyvsp[(6) - (8)].addr));
+               settext((yyvsp[(2) - (6)].addr).sym);
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
+               }
        }
     break;
 
   case 121:
-#line 643 "a.y"
+#line 652 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
+               }
        }
     break;
 
   case 122:
-#line 647 "a.y"
+#line 660 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
+               }
        }
     break;
 
   case 123:
-#line 651 "a.y"
+#line 668 "a.y"
     {
-               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+               outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
+               if(pass > 1) {
+                       lastpc->from3.type = TYPE_CONST;
+                       lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
+               }
        }
     break;
 
   case 124:
-#line 658 "a.y"
+#line 679 "a.y"
     {
-               outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+               outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen);
        }
     break;
 
   case 125:
-#line 664 "a.y"
+#line 685 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_BRANCH;
+               (yyval.addr).type = TYPE_BRANCH;
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
        }
     break;
 
   case 126:
-#line 670 "a.y"
+#line 691 "a.y"
     {
                (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
                (yyval.addr) = nullgen;
                if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB)
                        yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname);
-               (yyval.addr).type = D_BRANCH;
+               (yyval.addr).type = TYPE_BRANCH;
                (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
        }
     break;
 
   case 127:
-#line 681 "a.y"
+#line 702 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_REG;
+               (yyval.addr).type = TYPE_REG;
                (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 130:
-#line 693 "a.y"
+#line 714 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SPR;
-               (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 131:
-#line 701 "a.y"
+#line 722 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CREG;
-               (yyval.addr).reg = NREG;        /* whole register */
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);     /* whole register */
        }
     break;
 
   case 132:
-#line 709 "a.y"
+#line 730 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SPR;
-               (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 133:
-#line 717 "a.y"
+#line 738 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_MSR;
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 134:
-#line 724 "a.y"
+#line 746 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SPR;
-               (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 135:
-#line 730 "a.y"
+#line 752 "a.y"
     {
+               if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= 1024)
+                       yyerror("SPR/DCR out of range");
                (yyval.addr) = nullgen;
-               (yyval.addr).type = (yyvsp[(1) - (4)].lval);
-               (yyval.addr).offset = (yyvsp[(3) - (4)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (4)].lval) + (yyvsp[(3) - (4)].lval);
        }
     break;
 
   case 137:
-#line 739 "a.y"
+#line 763 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FPSCR;
-               (yyval.addr).reg = NREG;
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 138:
-#line 747 "a.y"
+#line 771 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FPSCR;
-               (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 139:
-#line 755 "a.y"
+#line 777 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FREG;
-               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = REG_F0 + (yyvsp[(3) - (4)].lval);
        }
     break;
 
   case 140:
-#line 761 "a.y"
+#line 785 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FREG;
-               (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
   case 141:
-#line 769 "a.y"
+#line 791 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CREG;
-               (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).type = TYPE_REG;
+               (yyval.addr).reg = REG_C0 + (yyvsp[(3) - (4)].lval);
        }
     break;
 
   case 142:
-#line 775 "a.y"
-    {
-               (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CREG;
-               (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
-       }
-    break;
-
-  case 143:
-#line 783 "a.y"
+#line 799 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_REG;
+               (yyval.addr).type = TYPE_REG;
                (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
        }
     break;
 
-  case 144:
-#line 791 "a.y"
+  case 143:
+#line 807 "a.y"
     {
                int mb, me;
                uint32 v;
 
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CONST;
+               (yyval.addr).type = TYPE_CONST;
                mb = (yyvsp[(1) - (3)].lval);
                me = (yyvsp[(3) - (3)].lval);
                if(mb < 0 || mb > 31 || me < 0 || me > 31){
@@ -2936,244 +2967,284 @@ yyreduce:
        }
     break;
 
+  case 144:
+#line 828 "a.y"
+    {
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+               (yyval.addr).u.argsize = ArgsSizeUnknown;
+       }
+    break;
+
   case 145:
-#line 812 "a.y"
+#line 835 "a.y"
     {
-               (yyval.addr) = (yyvsp[(2) - (2)].addr);
-               (yyval.addr).type = D_CONST;
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = -(yyvsp[(2) - (2)].lval);
+               (yyval.addr).u.argsize = ArgsSizeUnknown;
        }
     break;
 
   case 146:
-#line 817 "a.y"
+#line 842 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_SCONST;
-               memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = (yyvsp[(1) - (3)].lval);
+               (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval);
        }
     break;
 
   case 147:
-#line 825 "a.y"
+#line 849 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
-               (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
+               (yyval.addr).type = TYPE_TEXTSIZE;
+               (yyval.addr).offset = -(yyvsp[(2) - (4)].lval);
+               (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval);
        }
     break;
 
   case 148:
-#line 831 "a.y"
+#line 858 "a.y"
+    {
+               (yyval.addr) = (yyvsp[(2) - (2)].addr);
+               (yyval.addr).type = TYPE_ADDR;
+       }
+    break;
+
+  case 149:
+#line 863 "a.y"
+    {
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_SCONST;
+               memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
+       }
+    break;
+
+  case 150:
+#line 871 "a.y"
+    {
+               (yyval.addr) = nullgen;
+               (yyval.addr).type = TYPE_FCONST;
+               (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
+       }
+    break;
+
+  case 151:
+#line 877 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_FCONST;
+               (yyval.addr).type = TYPE_FCONST;
                (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
        }
     break;
 
-  case 149:
-#line 838 "a.y"
+  case 152:
+#line 884 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_CONST;
+               (yyval.addr).type = TYPE_CONST;
                (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 151:
-#line 847 "a.y"
+  case 154:
+#line 893 "a.y"
     {
                if((yyval.lval) < 0 || (yyval.lval) >= NREG)
                        print("register value out of range\n");
-               (yyval.lval) = (yyvsp[(3) - (4)].lval);
+               (yyval.lval) = REG_R0 + (yyvsp[(3) - (4)].lval);
        }
     break;
 
-  case 152:
-#line 855 "a.y"
+  case 155:
+#line 901 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
                (yyval.addr).offset = 0;
        }
     break;
 
-  case 153:
-#line 862 "a.y"
+  case 156:
+#line 908 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).reg = (yyvsp[(2) - (5)].lval);
                (yyval.addr).scale = (yyvsp[(4) - (5)].lval);
                (yyval.addr).offset = 0;
        }
     break;
 
-  case 155:
-#line 873 "a.y"
+  case 158:
+#line 919 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
        }
     break;
 
-  case 156:
-#line 882 "a.y"
+  case 159:
+#line 928 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).name = (yyvsp[(3) - (4)].lval);
                (yyval.addr).sym = nil;
                (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
        }
     break;
 
-  case 157:
-#line 890 "a.y"
+  case 160:
+#line 936 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
+               (yyval.addr).type = TYPE_MEM;
                (yyval.addr).name = (yyvsp[(4) - (5)].lval);
                (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
                (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
        }
     break;
 
-  case 158:
-#line 898 "a.y"
+  case 161:
+#line 944 "a.y"
     {
                (yyval.addr) = nullgen;
-               (yyval.addr).type = D_OREG;
-               (yyval.addr).name = D_STATIC;
+               (yyval.addr).type = TYPE_MEM;
+               (yyval.addr).name = NAME_STATIC;
                (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 0);
                (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
        }
     break;
 
-  case 161:
-#line 910 "a.y"
+  case 164:
+#line 956 "a.y"
     {
                (yyval.lval) = 0;
        }
     break;
 
-  case 162:
-#line 914 "a.y"
+  case 165:
+#line 960 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 163:
-#line 918 "a.y"
+  case 166:
+#line 964 "a.y"
     {
                (yyval.lval) = -(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 168:
-#line 930 "a.y"
+  case 171:
+#line 976 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
        }
     break;
 
-  case 169:
-#line 934 "a.y"
+  case 172:
+#line 980 "a.y"
     {
                (yyval.lval) = -(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 170:
-#line 938 "a.y"
+  case 173:
+#line 984 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 171:
-#line 942 "a.y"
+  case 174:
+#line 988 "a.y"
     {
                (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
        }
     break;
 
-  case 172:
-#line 946 "a.y"
+  case 175:
+#line 992 "a.y"
     {
                (yyval.lval) = (yyvsp[(2) - (3)].lval);
        }
     break;
 
-  case 174:
-#line 953 "a.y"
+  case 177:
+#line 999 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 175:
-#line 957 "a.y"
+  case 178:
+#line 1003 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 176:
-#line 961 "a.y"
+  case 179:
+#line 1007 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 177:
-#line 965 "a.y"
+  case 180:
+#line 1011 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 178:
-#line 969 "a.y"
+  case 181:
+#line 1015 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 179:
-#line 973 "a.y"
+  case 182:
+#line 1019 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
        }
     break;
 
-  case 180:
-#line 977 "a.y"
+  case 183:
+#line 1023 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
        }
     break;
 
-  case 181:
-#line 981 "a.y"
+  case 184:
+#line 1027 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 182:
-#line 985 "a.y"
+  case 185:
+#line 1031 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
        }
     break;
 
-  case 183:
-#line 989 "a.y"
+  case 186:
+#line 1035 "a.y"
     {
                (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
        }
@@ -3181,7 +3252,7 @@ yyreduce:
 
 
 /* Line 1267 of yacc.c.  */
-#line 3185 "y.tab.c"
+#line 3256 "y.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
index e6b93a2ece9a1f85112d052152ec7511190635cf..e7b00330fa5a788921be29a927e383b40dd04bff 100644 (file)
      LRETT = 276,
      LWORD = 277,
      LTEXT = 278,
-     LDATA = 279,
-     LRETRN = 280,
-     LCONST = 281,
-     LSP = 282,
-     LSB = 283,
-     LFP = 284,
-     LPC = 285,
-     LCREG = 286,
-     LFLUSH = 287,
-     LREG = 288,
-     LFREG = 289,
-     LR = 290,
-     LCR = 291,
-     LF = 292,
-     LFPSCR = 293,
-     LLR = 294,
-     LCTR = 295,
-     LSPR = 296,
-     LSPREG = 297,
-     LSEG = 298,
-     LMSR = 299,
-     LPCDAT = 300,
-     LFUNCDAT = 301,
-     LSCHED = 302,
-     LXLD = 303,
-     LXST = 304,
-     LXOP = 305,
-     LXMV = 306,
-     LRLWM = 307,
-     LMOVMW = 308,
-     LMOVEM = 309,
-     LMOVFL = 310,
-     LMTFSB = 311,
-     LMA = 312,
-     LFCONST = 313,
-     LSCONST = 314,
-     LNAME = 315,
-     LLAB = 316,
-     LVAR = 317
+     LGLOBL = 279,
+     LDATA = 280,
+     LRETRN = 281,
+     LCONST = 282,
+     LSP = 283,
+     LSB = 284,
+     LFP = 285,
+     LPC = 286,
+     LCREG = 287,
+     LFLUSH = 288,
+     LREG = 289,
+     LFREG = 290,
+     LR = 291,
+     LCR = 292,
+     LF = 293,
+     LFPSCR = 294,
+     LLR = 295,
+     LCTR = 296,
+     LSPR = 297,
+     LSPREG = 298,
+     LSEG = 299,
+     LMSR = 300,
+     LPCDAT = 301,
+     LFUNCDAT = 302,
+     LSCHED = 303,
+     LXLD = 304,
+     LXST = 305,
+     LXOP = 306,
+     LXMV = 307,
+     LRLWM = 308,
+     LMOVMW = 309,
+     LMOVEM = 310,
+     LMOVFL = 311,
+     LMTFSB = 312,
+     LMA = 313,
+     LFCONST = 314,
+     LSCONST = 315,
+     LNAME = 316,
+     LLAB = 317,
+     LVAR = 318
    };
 #endif
 /* Tokens.  */
 #define LRETT 276
 #define LWORD 277
 #define LTEXT 278
-#define LDATA 279
-#define LRETRN 280
-#define LCONST 281
-#define LSP 282
-#define LSB 283
-#define LFP 284
-#define LPC 285
-#define LCREG 286
-#define LFLUSH 287
-#define LREG 288
-#define LFREG 289
-#define LR 290
-#define LCR 291
-#define LF 292
-#define LFPSCR 293
-#define LLR 294
-#define LCTR 295
-#define LSPR 296
-#define LSPREG 297
-#define LSEG 298
-#define LMSR 299
-#define LPCDAT 300
-#define LFUNCDAT 301
-#define LSCHED 302
-#define LXLD 303
-#define LXST 304
-#define LXOP 305
-#define LXMV 306
-#define LRLWM 307
-#define LMOVMW 308
-#define LMOVEM 309
-#define LMOVFL 310
-#define LMTFSB 311
-#define LMA 312
-#define LFCONST 313
-#define LSCONST 314
-#define LNAME 315
-#define LLAB 316
-#define LVAR 317
+#define LGLOBL 279
+#define LDATA 280
+#define LRETRN 281
+#define LCONST 282
+#define LSP 283
+#define LSB 284
+#define LFP 285
+#define LPC 286
+#define LCREG 287
+#define LFLUSH 288
+#define LREG 289
+#define LFREG 290
+#define LR 291
+#define LCR 292
+#define LF 293
+#define LFPSCR 294
+#define LLR 295
+#define LCTR 296
+#define LSPR 297
+#define LSPREG 298
+#define LSEG 299
+#define LMSR 300
+#define LPCDAT 301
+#define LFUNCDAT 302
+#define LSCHED 303
+#define LXLD 304
+#define LXST 305
+#define LXOP 306
+#define LXMV 307
+#define LRLWM 308
+#define LMOVMW 309
+#define LMOVEM 310
+#define LMOVFL 311
+#define LMTFSB 312
+#define LMA 313
+#define LFCONST 314
+#define LSCONST 315
+#define LNAME 316
+#define LLAB 317
+#define LVAR 318
 
 
 
@@ -177,7 +179,7 @@ typedef union YYSTYPE
        Addr    addr;
 }
 /* Line 1529 of yacc.c.  */
-#line 181 "y.tab.h"
+#line 183 "y.tab.h"
        YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
index e3893600167a67502f96ef8662e648d8e161be0f..706658de0e56effd458ae3d7c57e6692e307a71d 100644 (file)
@@ -731,7 +731,7 @@ agenr(Node *n, Node *a, Node *res)
                                else {
                                        regalloc(&n4, types[TUINT64], N);
                                        p1 = gins(AMOVD, N, &n4);
-                                       p1->from.type = D_CONST;
+                                       p1->from.type = TYPE_CONST;
                                        p1->from.offset = nl->type->bound;
                                }
                        }
@@ -749,7 +749,7 @@ agenr(Node *n, Node *a, Node *res)
                        regalloc(&n3, types[tptr], res);
                        p1 = gins(AMOVD, N, &n3);
                        datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
-                       p1->from.type = D_CONST;
+                       p1->from.type = TYPE_ADDR;
                } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
                        n1 = n3;
                        n1.op = OINDREG;
@@ -968,7 +968,7 @@ igen(Node *n, Node *a, Node *res)
        case OINDREG:
                // Increase the refcount of the register so that igen's caller
                // has to call regfree.
-               if(n->val.u.reg != D_R0+REGSP)
+               if(n->val.u.reg != REGSP)
                        reg[n->val.u.reg]++;
                *a = *n;
                return;
@@ -1006,7 +1006,7 @@ igen(Node *n, Node *a, Node *res)
                fp = structfirst(&flist, getoutarg(n->left->type));
                memset(a, 0, sizeof *a);
                a->op = OINDREG;
-               a->val.u.reg = D_R0+REGSP;
+               a->val.u.reg = REGSP;
                a->addable = 1;
                a->xoffset = fp->width + widthptr; // +widthptr: saved lr at 0(SP)
                a->type = n->type;
@@ -1465,25 +1465,25 @@ sgen(Node *n, Node *ns, int64 w)
                }
 
                p = gins(AADD, N, &src);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = w;
 
                p = gins(AADD, N, &dst);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = w;
        } else {
                p = gins(AADD, N, &src);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = -dir;
 
                p = gins(AADD, N, &dst);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = -dir;
 
                if(c >= 4) {
                        regalloc(&nend, types[tptr], N);
                        p = gins(AMOVD, &src, &nend);
-                       p->from.type = D_CONST;
+                       p->from.type = TYPE_ADDR;
                        p->from.offset = w;
                }
        }
@@ -1493,12 +1493,12 @@ sgen(Node *n, Node *ns, int64 w)
        // TODO: enable duffcopy for larger copies.
        if(c >= 4) {
                p = gins(op, &src, &tmp);
-               p->from.type = D_OREG;
+               p->from.type = TYPE_MEM;
                p->from.offset = dir;
                ploop = p;
 
                p = gins(op, &tmp, &dst);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.offset = dir;
 
                p = gins(ACMP, &src, &nend);
@@ -1506,13 +1506,18 @@ sgen(Node *n, Node *ns, int64 w)
                patch(gbranch(ABNE, T, 0), ploop);
                regfree(&nend);
        } else {
+               // TODO(austin): Instead of generating ADD $-8,R8; ADD
+               // $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just
+               // generate the offsets directly and eliminate the
+               // ADDs.  That will produce shorter, more
+               // pipeline-able code.
                while(c-- > 0) {
                        p = gins(op, &src, &tmp);
-                       p->from.type = D_OREG;
+                       p->from.type = TYPE_MEM;
                        p->from.offset = dir;
        
                        p = gins(op, &tmp, &dst);
-                       p->to.type = D_OREG;
+                       p->to.type = TYPE_MEM;
                        p->to.offset = dir;
                }
        }
index 67514faa47ecd746d10ee0bfa1339d0b9b8d8ce8..df4291e90e6d1376070fe9fb1a9038c0758a6f26 100644 (file)
@@ -14,10 +14,12 @@ void
 linkarchinit(void)
 {
        thestring = getgoarch();
+       arch.thestring = thestring;
        if(strcmp(thestring, "ppc64le") == 0)
                thelinkarch = &linkppc64le;
        else
                thelinkarch = &linkppc64;
+       arch.thelinkarch = thelinkarch;
 }
 
 vlong MAXWIDTH = 1LL<<50;
@@ -41,14 +43,67 @@ betypeinit(void)
        widthint = 8;
        widthreg = 8;
 
-       zprog.link = P;
-       zprog.as = AGOK;
-       zprog.reg = NREG;
-       zprog.from.name = D_NONE;
-       zprog.from.type = D_NONE;
-       zprog.from.reg = NREG;
-       zprog.to = zprog.from;
-       zprog.from3 = zprog.from;
-
        listinit9();
 }
+
+void
+main(int argc, char **argv)
+{
+       arch.thechar = thechar;
+       arch.thestring = thestring;
+       arch.thelinkarch = thelinkarch;
+       arch.typedefs = typedefs;
+       arch.MAXWIDTH = MAXWIDTH;
+       arch.afunclit = afunclit;
+       arch.anyregalloc = anyregalloc;
+       arch.betypeinit = betypeinit;
+       arch.bgen = bgen;
+       arch.cgen = cgen;
+       arch.cgen_asop = cgen_asop;
+       arch.cgen_call = cgen_call;
+       arch.cgen_callinter = cgen_callinter;
+       arch.cgen_ret = cgen_ret;
+       arch.clearfat = clearfat;
+       arch.clearp = clearp;
+       arch.defframe = defframe;
+       arch.dgostringptr = dgostringptr;
+       arch.dgostrlitptr = dgostrlitptr;
+       arch.dsname = dsname;
+       arch.dsymptr = dsymptr;
+       arch.dumpdata = dumpdata;
+       arch.dumpit = dumpit;
+       arch.excise = excise;
+       arch.expandchecks = expandchecks;
+       arch.fixautoused = fixautoused;
+       arch.gclean = gclean;
+       arch.gdata = gdata;
+       arch.gdatacomplex = gdatacomplex;
+       arch.gdatastring = gdatastring;
+       arch.ggloblnod = ggloblnod;
+       arch.ggloblsym = ggloblsym;
+       arch.ginit = ginit;
+       arch.gins = gins;
+       arch.ginscall = ginscall;
+       arch.gjmp = gjmp;
+       arch.gtrack = gtrack;
+       arch.gused = gused;
+       arch.igen = igen;
+       arch.isfat = isfat;
+       arch.linkarchinit = linkarchinit;
+       arch.markautoused = markautoused;
+       arch.naddr = naddr;
+       arch.newplist = newplist;
+       arch.nodarg = nodarg;
+       arch.patch = patch;
+       arch.proginfo = proginfo;
+       arch.regalloc = regalloc;
+       arch.regfree = regfree;
+       arch.regopt = regopt;
+       arch.regtyp = regtyp;
+       arch.sameaddr = sameaddr;
+       arch.smallindir = smallindir;
+       arch.stackaddr = stackaddr;
+       arch.unpatch = unpatch;
+       
+       gcmain(argc, argv);
+}
index 703fbd0a8715d99e50d0ee7f52e83680469c6f32..367a858e860b1f8fa51b001161347b33291b289e 100644 (file)
 // TODO(minux): Remove when no longer used.
 #define noimpl sysfatal("%s not implemented (%s:%d).", __func__, __FILE__, __LINE__)
 
-#define TEXTFLAG reg
-
 EXTERN int32   dynloc;
 EXTERN uchar   reg[NREG+NFREG];
 EXTERN int32   pcloc;          // instruction counter
 EXTERN Strlit  emptystring;
-EXTERN Prog    zprog;
-EXTERN Node*   newproc;
-EXTERN Node*   deferproc;
-EXTERN Node*   deferreturn;
-EXTERN Node*   panicindex;
-EXTERN Node*   panicslice;
 EXTERN Node*   panicdiv;
-EXTERN Node*   throwreturn;
 extern vlong   unmappedzero;
 
 /*
@@ -115,3 +106,55 @@ void       datagostring(Strlit*, Addr*);
 void   listinit(void);
 
 void   zaddr(Biobuf*, Addr*, int, int);
+
+void afunclit(Addr*, Node*);
+int anyregalloc(void);
+void betypeinit(void);
+void bgen(Node*, int, int, Prog*);
+void cgen(Node*, Node*);
+void cgen_asop(Node*);
+void cgen_call(Node*, int);
+void cgen_callinter(Node*, Node*, int);
+void cgen_ret(Node*);
+void clearfat(Node*);
+void clearp(Prog*);
+void defframe(Prog*);
+int dgostringptr(Sym*, int, char*);
+int dgostrlitptr(Sym*, int, Strlit*);
+int dsname(Sym*, int, char*, int);
+int dsymptr(Sym*, int, Sym*, int);
+void dumpdata(void);
+void dumpit(char*, Flow*, int);
+void excise(Flow*);
+void expandchecks(Prog*);
+void fixautoused(Prog*);
+void gclean(void);
+void   gdata(Node*, Node*, int);
+void   gdatacomplex(Node*, Mpcplx*);
+void   gdatastring(Node*, Strlit*);
+void   ggloblnod(Node *nam);
+void   ggloblsym(Sym *s, int32 width, int8 flags);
+void ginit(void);
+Prog*  gins(int, Node*, Node*);
+void   ginscall(Node*, int);
+Prog*  gjmp(Prog*);
+void gtrack(Sym*);
+void   gused(Node*);
+void   igen(Node*, Node*, Node*);
+int isfat(Type*);
+void linkarchinit(void);
+void markautoused(Prog*);
+void naddr(Node*, Addr*, int);
+Plist* newplist(void);
+Node* nodarg(Type*, int);
+void patch(Prog*, Prog*);
+void proginfo(ProgInfo*, Prog*);
+void regalloc(Node*, Type*, Node*);
+void regfree(Node*);
+void regopt(Prog*);
+int regtyp(Addr*);
+int sameaddr(Addr*, Addr*);
+int smallindir(Addr*, Addr*);
+int stackaddr(Addr*);
+Prog* unpatch(Prog*);
+
index 89348bf2b0292f289be0e06b260de942770e32aa..3865051018e0e5d7b2332adba10edd3b8fd33288 100644 (file)
@@ -21,13 +21,11 @@ defframe(Prog *ptxt)
        NodeList *l;
        Node *n;
 
-       // fill in argument size
-       ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
-
-       // fill in final stack size
-       ptxt->to.offset <<= 32;
+       // fill in argument size, stack size
+       ptxt->to.type = TYPE_TEXTSIZE;
+       ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr);
        frame = rnd(stksize+maxarg, widthreg);
-       ptxt->to.offset |= frame;
+       ptxt->to.offset = frame;
        
        // insert code to zero ambiguously live variables
        // so that the garbage collector only sees initialized values
@@ -72,25 +70,25 @@ zerorange(Prog *p, vlong frame, vlong lo, vlong hi)
                return p;
        if(cnt < 4*widthptr) {
                for(i = 0; i < cnt; i += widthptr)
-                       p = appendpp(p, AMOVD, D_REG, REGZERO, 0, D_OREG, REGSP, 8+frame+lo+i);
+                       p = appendpp(p, AMOVD, TYPE_REG, REGZERO, 0, TYPE_MEM, REGSP, 8+frame+lo+i);
        } else if(cnt <= 128*widthptr) {
-               p = appendpp(p, AADD, D_CONST, NREG, 8+frame+lo-8, D_REG, REGRT1, 0);
+               p = appendpp(p, AADD, TYPE_CONST, 0, 8+frame+lo-8, TYPE_REG, REGRT1, 0);
                p->reg = REGSP;
-               p = appendpp(p, ADUFFZERO, D_NONE, NREG, 0, D_OREG, NREG, 0);
+               p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_MEM, 0, 0);
                f = sysfunc("duffzero");
                naddr(f, &p->to, 1);
                afunclit(&p->to, f);
                p->to.offset = 4*(128-cnt/widthptr);
        } else {
-               p = appendpp(p, AMOVD, D_CONST, NREG, 8+frame+lo-8, D_REG, REGTMP, 0);
-               p = appendpp(p, AADD, D_REG, REGTMP, 0, D_REG, REGRT1, 0);
+               p = appendpp(p, AMOVD, TYPE_CONST, 0, 8+frame+lo-8, TYPE_REG, REGTMP, 0);
+               p = appendpp(p, AADD, TYPE_REG, REGTMP, 0, TYPE_REG, REGRT1, 0);
                p->reg = REGSP;
-               p = appendpp(p, AMOVD, D_CONST, NREG, cnt, D_REG, REGTMP, 0);
-               p = appendpp(p, AADD, D_REG, REGTMP, 0, D_REG, REGRT2, 0);
+               p = appendpp(p, AMOVD, TYPE_CONST, 0, cnt, TYPE_REG, REGTMP, 0);
+               p = appendpp(p, AADD, TYPE_REG, REGTMP, 0, TYPE_REG, REGRT2, 0);
                p->reg = REGRT1;
-               p1 = p = appendpp(p, AMOVDU, D_REG, REGZERO, 0, D_OREG, REGRT1, widthptr);
-               p = appendpp(p, ACMP, D_REG, REGRT1, 0, D_REG, REGRT2, 0);
-               p = appendpp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0);
+               p1 = p = appendpp(p, AMOVDU, TYPE_REG, REGZERO, 0, TYPE_MEM, REGRT1, widthptr);
+               p = appendpp(p, ACMP, TYPE_REG, REGRT1, 0, TYPE_REG, REGRT2, 0);
+               p = appendpp(p, ABNE, TYPE_NONE, 0, 0, TYPE_BRANCH, 0, 0);
                patch(p, p1);
        }
        return p;
@@ -124,10 +122,10 @@ markautoused(Prog *p)
                        continue;
 
                if (p->from.node)
-                       p->from.node->used = 1;
+                       ((Node*)(p->from.node))->used = 1;
 
                if (p->to.node)
-                       p->to.node->used = 1;
+                       ((Node*)(p->to.node))->used = 1;
        }
 }
 
@@ -138,25 +136,23 @@ fixautoused(Prog *p)
        Prog **lp;
 
        for (lp=&p; (p=*lp) != P; ) {
-               if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) {
+               if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
                        *lp = p->link;
                        continue;
                }
-               if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) {
+               if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
                        // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
                        // VARDEFs are interspersed with other code, and a jump might be using the
                        // VARDEF as a target. Replace with a no-op instead. A later pass will remove
                        // the no-ops.
-                       p->to.type = D_NONE;
-                       p->to.node = N;
-                       p->as = ANOP;
+                       nopout(p);
                        continue;
                }
-               if (p->from.name == D_AUTO && p->from.node)
-                       p->from.offset += p->from.node->stkdelta;
+               if (p->from.name == NAME_AUTO && p->from.node)
+                       p->from.offset += ((Node*)(p->from.node))->stkdelta;
 
-               if (p->to.name == D_AUTO && p->to.node)
-                       p->to.offset += p->to.node->stkdelta;
+               if (p->to.name == NAME_AUTO && p->to.node)
+                       p->to.offset += ((Node*)(p->to.node))->stkdelta;
 
                lp = &p->link;
        }
@@ -172,11 +168,11 @@ ginsBL(Node *reg, Node *f)
 {
        Prog *p;
        p = gins(AMOVD, f, N);
-       p->to.type = D_SPR;
-       p->to.offset = D_CTR;
+       p->to.type = TYPE_REG;
+       p->to.reg = REG_CTR;
        p = gins(ABL, reg, N);
-       p->to.type = D_SPR;
-       p->to.offset = D_CTR;
+       p->to.type = TYPE_REG;
+       p->to.reg = REG_CTR;
 }
 
 /*
@@ -221,7 +217,7 @@ ginscall(Node *f, int proc)
                                // The ppc64 NOP is really or r0, r0, r0; use that description
                                // because the NOP pseudo-instruction would be removed by
                                // the linker.
-                               nodreg(&reg, types[TINT], D_R0);
+                               nodreg(&reg, types[TINT], REG_R0);
                                gins(AOR, &reg, &reg);
                        }
                        p = gins(ABL, N, f);
@@ -230,8 +226,8 @@ ginscall(Node *f, int proc)
                                gins(AUNDEF, N, N);
                        break;
                }
-               nodreg(&reg, types[tptr], D_R0+REGENV);
-               nodreg(&r1, types[tptr], D_R0+3);
+               nodreg(&reg, types[tptr], REGENV);
+               nodreg(&r1, types[tptr], REG_R3);
                gmove(f, &reg);
                reg.op = OINDREG;
                gmove(&reg, &r1);
@@ -246,18 +242,18 @@ ginscall(Node *f, int proc)
        case 1: // call in new proc (go)
        case 2: // deferred call (defer)
                nodconst(&con, types[TINT64], argsize(f->type));
-               nodreg(&reg, types[TINT64], D_R0+3);
-               nodreg(&reg2, types[TINT64], D_R0+4);
+               nodreg(&reg, types[TINT64], REG_R3);
+               nodreg(&reg2, types[TINT64], REG_R4);
                gmove(f, &reg);
 
                gmove(&con, &reg2);
                p = gins(AMOVW, &reg2, N);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.reg = REGSP;
                p->to.offset = 8;
 
                p = gins(AMOVD, &reg, N);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.reg = REGSP;
                p->to.offset = 16;
 
@@ -270,10 +266,10 @@ ginscall(Node *f, int proc)
                }
 
                if(proc == 2) {
-                       nodreg(&reg, types[TINT64], D_R0+3);
+                       nodreg(&reg, types[TINT64], REG_R3);
                        p = gins(ACMP, &reg, N);
-                       p->to.type = D_REG;
-                       p->to.reg = D_R0;
+                       p->to.type = TYPE_REG;
+                       p->to.reg = REG_R0;
                        p = gbranch(ABEQ, T, +1);
                        cgen_ret(N);
                        patch(p, pc);
@@ -315,7 +311,7 @@ cgen_callinter(Node *n, Node *res, int proc)
        // register to hold its address.
        igen(i, &nodi, res);            // REG = &inter
 
-       nodindreg(&nodsp, types[tptr], D_R0+REGSP);
+       nodindreg(&nodsp, types[tptr], REGSP);
        nodsp.xoffset = widthptr;
        if(proc != 0)
                nodsp.xoffset += 2 * widthptr; // leave room for size & fn
@@ -342,7 +338,7 @@ cgen_callinter(Node *n, Node *res, int proc)
        } else {
                // go/defer. generate go func value.
                p = gins(AMOVD, &nodo, &nodr);  // REG = &(32+offset(REG)) -- i.tab->fun[f]
-               p->from.type = D_CONST;
+               p->from.type = TYPE_ADDR;
        }
 
        nodr.type = n->left->type;
@@ -424,7 +420,7 @@ cgen_callret(Node *n, Node *res)
 
        memset(&nod, 0, sizeof(nod));
        nod.op = OINDREG;
-       nod.val.u.reg = D_R0+REGSP;
+       nod.val.u.reg = REGSP;
        nod.addable = 1;
 
        nod.xoffset = fp->width + widthptr; // +widthptr: saved LR at 0(R1)
@@ -454,7 +450,7 @@ cgen_aret(Node *n, Node *res)
 
        memset(&nod1, 0, sizeof(nod1));
        nod1.op = OINDREG;
-       nod1.val.u.reg = D_R0 + REGSP;
+       nod1.val.u.reg = REGSP;
        nod1.addable = 1;
 
        nod1.xoffset = fp->width + widthptr; // +widthptr: saved lr at 0(SP)
@@ -485,8 +481,8 @@ cgen_ret(Node *n)
        genlist(curfn->exit);
        p = gins(ARET, N, N);
        if(n != N && n->op == ORETJMP) {
-               p->to.name = D_EXTERN;
-               p->to.type = D_CONST;
+               p->to.name = NAME_EXTERN;
+               p->to.type = TYPE_ADDR;
                p->to.sym = linksym(n->left->sym);
        }
 }
@@ -575,7 +571,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
 
        // Handle divide-by-zero panic.
        p1 = gins(optoas(OCMP, t), &tr, N);
-       p1->to.type = D_REG;
+       p1->to.type = TYPE_REG;
        p1->to.reg = REGZERO;
        p1 = gbranch(optoas(ONE, t), T, +1);
        if(panicdiv == N)
@@ -774,7 +770,7 @@ cgen_hmul(Node *nl, Node *nr, Node *res)
        case TINT32:
                gins(optoas(OMUL, t), &n2, &n1);
                p = gins(ASRAD, N, &n1);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = w;
                break;
        case TUINT8:
@@ -782,7 +778,7 @@ cgen_hmul(Node *nl, Node *nr, Node *res)
        case TUINT32:
                gins(optoas(OMUL, t), &n2, &n1);
                p = gins(ASRD, N, &n1);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = w;
                break;
        case TINT64:
@@ -915,23 +911,23 @@ clearfat(Node *nl)
        if(reg[REGRT1] > 0)
                fatal("R%d in use during clearfat", REGRT1);
 
-       nodreg(&r0, types[TUINT64], 0); // r0 is always zero
-       nodreg(&dst, types[tptr], D_R0+REGRT1);
+       nodreg(&r0, types[TUINT64], REG_R0); // r0 is always zero
+       nodreg(&dst, types[tptr], REGRT1);
        reg[REGRT1]++;
        agen(nl, &dst);
 
        if(q > 128) {
                p = gins(ASUB, N, &dst);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = 8;
 
                regalloc(&end, types[tptr], N);
                p = gins(AMOVD, &dst, &end);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_ADDR;
                p->from.offset = q*8;
 
                p = gins(AMOVDU, &r0, &dst);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.offset = 8;
                pl = p;
 
@@ -943,7 +939,7 @@ clearfat(Node *nl)
                boff = 8;
        } else if(q >= 4) {
                p = gins(ASUB, N, &dst);
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = 8;
                f = sysfunc("duffzero");
                p = gins(ADUFFZERO, N, f);
@@ -955,7 +951,7 @@ clearfat(Node *nl)
        } else {
                for(t = 0; t < q; t++) {
                        p = gins(AMOVD, &r0, &dst);
-                       p->to.type = D_OREG;
+                       p->to.type = TYPE_MEM;
                        p->to.offset = 8*t;
                }
                boff = 8*q;
@@ -963,7 +959,7 @@ clearfat(Node *nl)
 
        for(t = 0; t < c; t++) {
                p = gins(AMOVB, &r0, &dst);
-               p->to.type = D_OREG;
+               p->to.type = TYPE_MEM;
                p->to.offset = t+boff;
        }
        reg[REGRT1]--;
@@ -983,7 +979,7 @@ expandchecks(Prog *firstp)
                        continue;
                if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
                        warnl(p->lineno, "generated nil check");
-               if(p->from.type != D_REG)
+               if(p->from.type != TYPE_REG)
                        fatal("invalid nil check %P\n", p);
                /*
                // check is
@@ -994,11 +990,11 @@ expandchecks(Prog *firstp)
                reg = p->from.reg;
                p->as = ATD;
                p->from = p->to = p->from3 = zprog.from;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = 4;
-               p->from.reg = NREG;
-               p->reg = 0;
-               p->to.type = D_REG;
+               p->from.reg = 0;
+               p->reg = REG_R0;
+               p->to.type = TYPE_REG;
                p->to.reg = reg;
                */
                // check is
@@ -1017,19 +1013,19 @@ expandchecks(Prog *firstp)
                p1->pc = 9999;
                p2->pc = 9999;
                p->as = ACMP;
-               p->to.type = D_REG;
+               p->to.type = TYPE_REG;
                p->to.reg = REGZERO;
                p1->as = ABNE;
-               //p1->from.type = D_CONST;
+               //p1->from.type = TYPE_CONST;
                //p1->from.offset = 1; // likely
-               p1->to.type = D_BRANCH;
+               p1->to.type = TYPE_BRANCH;
                p1->to.u.branch = p2->link;
                // crash by write to memory address 0.
                p2->as = AMOVD;
-               p2->from.type = D_REG;
-               p2->from.reg = 0;
-               p2->to.type = D_OREG;
-               p2->to.reg = 0;
+               p2->from.type = TYPE_REG;
+               p2->from.reg = REG_R0;
+               p2->to.type = TYPE_MEM;
+               p2->to.reg = REG_R0;
                p2->to.offset = 0;
        }
 }
index 3da55878a763c379845a2530e88e603309547ea4..35e4f458f1180ced33aade06b3df5d55d2e9cba8 100644 (file)
@@ -38,17 +38,16 @@ dsname(Sym *s, int off, char *t, int n)
        Prog *p;
 
        p = gins(ADATA, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.offset = off;
-       p->from.reg = NREG;
        p->from.sym = linksym(s);
 
-       p->reg = n;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = n;
        
-       p->to.type = D_SCONST;
-       p->to.name = D_NONE;
-       p->to.reg = NREG;
+       p->to.type = TYPE_SCONST;
+       p->to.name = NAME_NONE;
        p->to.offset = 0;
        memmove(p->to.u.sval, t, n);
        return off + n;
@@ -64,11 +63,11 @@ datastring(char *s, int len, Addr *a)
        Sym *sym;
        
        sym = stringsym(s, len);
-       a->type = D_OREG;
-       a->name = D_EXTERN;
+       a->type = TYPE_MEM;
+       a->name = NAME_EXTERN;
        a->etype = simtype[TINT];
        a->offset = widthptr+widthint;  // skip header
-       a->reg = NREG;
+       a->reg = 0;
        a->sym = linksym(sym);
        a->node = sym->def;
 }
@@ -83,10 +82,10 @@ datagostring(Strlit *sval, Addr *a)
        Sym *sym;
 
        sym = stringsym(sval->s, sval->len);
-       a->type = D_OREG;
-       a->name = D_EXTERN;
+       a->type = TYPE_MEM;
+       a->name = NAME_EXTERN;
        a->sym = linksym(sym);
-       a->reg = NREG;
+       a->reg = 0;
        a->node = sym->def;
        a->offset = 0;  // header
        a->etype = TSTRING;
@@ -108,7 +107,8 @@ gdata(Node *nam, Node *nr, int wid)
                }
        }
        p = gins(ADATA, nam, nr);
-       p->reg = wid;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = wid;
 }
 
 void
@@ -121,14 +121,16 @@ gdatacomplex(Node *nam, Mpcplx *cval)
        w = types[w]->width;
 
        p = gins(ADATA, nam, N);
-       p->reg = w;
-       p->to.type = D_FCONST;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = w;
+       p->to.type = TYPE_FCONST;
        p->to.u.dval = mpgetflt(&cval->real);
 
        p = gins(ADATA, nam, N);
-       p->reg = w;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = w;
        p->from.offset += w;
-       p->to.type = D_FCONST;
+       p->to.type = TYPE_FCONST;
        p->to.u.dval = mpgetflt(&cval->imag);
 }
 
@@ -140,13 +142,15 @@ gdatastring(Node *nam, Strlit *sval)
 
        p = gins(ADATA, nam, N);
        datastring(sval->s, sval->len, &p->to);
-       p->reg = types[tptr]->width;
-       p->to.type = D_CONST;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = types[tptr]->width;
+       p->to.type = TYPE_ADDR;
        p->to.etype = simtype[tptr];
 
        nodconst(&nod1, types[TINT], sval->len);
        p = gins(ADATA, nam, &nod1);
-       p->reg = widthint;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthint;
        p->from.offset += widthptr;
 }
 
@@ -157,14 +161,15 @@ dstringptr(Sym *s, int off, char *str)
 
        off = rnd(off, widthptr);
        p = gins(ADATA, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->reg = widthptr;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
 
        datastring(str, strlen(str)+1, &p->to);
-       p->to.type = D_CONST;
+       p->to.type = TYPE_CONST;
        p->to.etype = simtype[TINT];
        off += widthptr;
 
@@ -181,13 +186,14 @@ dgostrlitptr(Sym *s, int off, Strlit *lit)
 
        off = rnd(off, widthptr);
        p = gins(ADATA, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->reg = widthptr;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
        datagostring(lit, &p->to);
-       p->to.type = D_CONST;
+       p->to.type = TYPE_ADDR;
        p->to.etype = simtype[TINT];
        off += widthptr;
 
@@ -218,13 +224,14 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
        off = rnd(off, widthptr);
 
        p = gins(ADATA, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
        p->from.offset = off;
-       p->reg = widthptr;
-       p->to.type = D_CONST;
-       p->to.name = D_EXTERN;
+       p->from3.type = TYPE_CONST;
+       p->from3.offset = widthptr;
+       p->to.type = TYPE_ADDR;
+       p->to.name = NAME_EXTERN;
        p->to.sym = linksym(x);
        p->to.offset = xoff;
        off += widthptr;
@@ -236,5 +243,8 @@ void
 nopout(Prog *p)
 {
        p->as = ANOP;
+       p->from = zprog.from;
+       p->from3 = zprog.from3;
+       p->reg = zprog.reg;
+       p->to = zprog.to;
 }
-
index 8abbde45319bdd20766c0a12c51c24d804c5b5f9..49f184d51ee3900f10141f8b99ae584954983713 100644 (file)
@@ -116,14 +116,14 @@ gbranch(int as, Type *t, int likely)
        USED(t);
 
        p = prog(as);
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        p->to.u.branch = P;
        // TODO(minux): Enable this code.
        // Note: liblink used Bcc CR0, label form, so we need another way
        // to set likely/unlikely flag. Also note the y bit is not exactly
        // likely/unlikely bit.
        if(0 && as != ABR && likely != 0) {
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = likely > 0;
        }
        return p;
@@ -135,7 +135,7 @@ gbranch(int as, Type *t, int likely)
 void
 patch(Prog *p, Prog *to)
 {
-       if(p->to.type != D_BRANCH)
+       if(p->to.type != TYPE_BRANCH)
                fatal("patch: not a branch");
        p->to.u.branch = to;
        p->to.offset = to->pc;
@@ -146,7 +146,7 @@ unpatch(Prog *p)
 {
        Prog *q;
 
-       if(p->to.type != D_BRANCH)
+       if(p->to.type != TYPE_BRANCH)
                fatal("unpatch: not a branch");
        q = p->to.u.branch;
        p->to.u.branch = P;
@@ -197,12 +197,12 @@ ggloblnod(Node *nam)
        p->lineno = nam->lineno;
        p->from.sym->gotype = linksym(ngotype(nam));
        p->to.sym = nil;
-       p->to.type = D_CONST;
+       p->to.type = TYPE_CONST;
        p->to.offset = nam->type->width;
        if(nam->readonly)
-               p->reg = RODATA;
+               p->from3.offset = RODATA;
        if(nam->type != T && !haspointers(nam->type))
-               p->reg |= NOPTR;
+               p->from3.offset |= NOPTR;
 }
 
 void
@@ -211,8 +211,8 @@ gtrack(Sym *s)
        Prog *p;
        
        p = gins(AUSEFIELD, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
 }
 
@@ -222,13 +222,13 @@ ggloblsym(Sym *s, int32 width, int8 flags)
        Prog *p;
 
        p = gins(AGLOBL, N, N);
-       p->from.type = D_OREG;
-       p->from.name = D_EXTERN;
+       p->from.type = TYPE_MEM;
+       p->from.name = NAME_EXTERN;
        p->from.sym = linksym(s);
-       p->to.type = D_CONST;
-       p->to.name = D_NONE;
+       p->to.type = TYPE_CONST;
+       p->to.name = NAME_NONE;
        p->to.offset = width;
-       p->reg = flags;
+       p->from3.offset = flags;
 }
 
 int
@@ -253,8 +253,8 @@ isfat(Type *t)
 void
 afunclit(Addr *a, Node *n)
 {
-       if(a->type == D_CONST && a->name == D_EXTERN) {
-               a->type = D_OREG;
+       if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
+               a->type = TYPE_MEM;
                a->sym = linksym(n->sym);
        }
 }
@@ -272,11 +272,11 @@ static    int     resvd[] =
        // TODO(austin): Consolidate REGTLS and REGG?
        REGG,
        REGTMP, // REGTMP
-       FREGCVI+NREG,
-       FREGZERO+NREG,
-       FREGHALF+NREG,
-       FREGONE+NREG,
-       FREGTWO+NREG,
+       FREGCVI,
+       FREGZERO,
+       FREGHALF,
+       FREGONE,
+       FREGTWO,
 };
 
 void
@@ -286,13 +286,11 @@ ginit(void)
 
        for(i=0; i<nelem(reg); i++)
                reg[i] = 1;
-       for(i=0; i<NREG; i++)
-               reg[i] = 0;
-       for(i=NREG; i<NREG+NREG; i++)
+       for(i=0; i<NREG+NFREG; i++)
                reg[i] = 0;
 
        for(i=0; i<nelem(resvd); i++)
-               reg[resvd[i]]++;
+               reg[resvd[i] - REG_R0]++;
 }
 
 static uintptr regpc[nelem(reg)];
@@ -303,11 +301,11 @@ gclean(void)
        int i;
 
        for(i=0; i<nelem(resvd); i++)
-               reg[resvd[i]]--;
+               reg[resvd[i] - REG_R0]--;
 
        for(i=0; i<nelem(reg); i++)
                if(reg[i])
-                       yyerror("reg %R left allocated, %p\n", i, regpc[i]);
+                       yyerror("reg %R left allocated, %p\n", i+REG_R0, regpc[i]);
 }
 
 int32
@@ -345,9 +343,9 @@ regalloc(Node *n, Type *t, Node *o)
        if(debug['r']) {
                fixfree = 0;
                fltfree = 0;
-               for(i = D_R0; i < D_F0+NREG; i++)
-                       if(reg[i] == 0) {
-                               if(i < D_F0)
+               for(i = REG_R0; i < REG_F31; i++)
+                       if(reg[i - REG_R0] == 0) {
+                               if(i < REG_F0)
                                        fixfree++;
                                else
                                        fltfree++;
@@ -369,34 +367,34 @@ regalloc(Node *n, Type *t, Node *o)
        case TBOOL:
                if(o != N && o->op == OREGISTER) {
                        i = o->val.u.reg;
-                       if(i >= D_R0+REGMIN && i <= D_R0+REGMAX)
+                       if(i >= REGMIN && i <= REGMAX)
                                goto out;
                }
-               for(i=D_R0+REGMIN; i<=D_R0+REGMAX; i++)
-                       if(reg[i] == 0) {
-                               regpc[i] = (uintptr)getcallerpc(&n);
+               for(i=REGMIN; i<=REGMAX; i++)
+                       if(reg[i - REG_R0] == 0) {
+                               regpc[i - REG_R0] = (uintptr)getcallerpc(&n);
                                goto out;
                        }
                flusherrors();
-               for(i=D_R0; i<D_R0+NREG; i++)
-                       print("R%d %p\n", i, regpc[i]);
+               for(i=REG_R0; i<REG_R0+NREG; i++)
+                       print("R%d %p\n", i, regpc[i - REG_R0]);
                fatal("out of fixed registers");
 
        case TFLOAT32:
        case TFLOAT64:
                if(o != N && o->op == OREGISTER) {
                        i = o->val.u.reg;
-                       if(i >= D_F0+FREGMIN && i <= D_F0+FREGMAX)
+                       if(i >= FREGMIN && i <= FREGMAX)
                                goto out;
                }
-               for(i=D_F0+FREGMIN; i<=D_F0+FREGMAX; i++)
-                       if(reg[i] == 0) {
-                               regpc[i] = (uintptr)getcallerpc(&n);
+               for(i=FREGMIN; i<=FREGMAX; i++)
+                       if(reg[i - REG_R0] == 0) {
+                               regpc[i - REG_R0] = (uintptr)getcallerpc(&n);
                                goto out;
                        }
                flusherrors();
-               for(i=D_F0; i<D_F0+NREG; i++)
-                       print("F%d %p\n", i, regpc[i]);
+               for(i=REG_F0; i<REG_F0+NREG; i++)
+                       print("F%d %p\n", i, regpc[i - REG_R0]);
                fatal("out of floating registers");
 
        case TCOMPLEX64:
@@ -408,7 +406,7 @@ regalloc(Node *n, Type *t, Node *o)
        return;
 
 out:
-       reg[i]++;
+       reg[i - REG_R0]++;
        nodreg(n, t, i);
 }
 
@@ -421,8 +419,8 @@ regfree(Node *n)
                return;
        if(n->op != OREGISTER && n->op != OINDREG)
                fatal("regfree: not a register");
-       i = n->val.u.reg;
-       if(i == D_R0 + REGSP)
+       i = n->val.u.reg - REG_R0;
+       if(i == REGSP - REG_R0)
                return;
        if(i < 0 || i >= nelem(reg))
                fatal("regfree: reg out of range");
@@ -517,7 +515,7 @@ fp:
 
        case 0:         // output arg for calling another function
                n->op = OINDREG;
-               n->val.u.reg = D_R0+REGSP;
+               n->val.u.reg = REGSP;
                n->xoffset += 8;
                break;
 
@@ -528,7 +526,7 @@ fp:
        case 2:         // offset output arg
 fatal("shouldn't be used");
                n->op = OINDREG;
-               n->val.u.reg = D_R0 + REGSP;
+               n->val.u.reg = REGSP;
                n->xoffset += types[tptr]->width;
                break;
        }
@@ -883,18 +881,18 @@ gmove(Node *f, Node *t)
                regalloc(&r3, types[TINT64], t);
                gins(AFCTIDZ, &r1, &r2);
                p1 = gins(AFMOVD, &r2, N);
-               p1->to.type = D_OREG;
+               p1->to.type = TYPE_MEM;
                p1->to.reg = REGSP;
                p1->to.offset = -8;
                p1 = gins(AMOVD, N, &r3);
-               p1->from.type = D_OREG;
+               p1->from.type = TYPE_MEM;
                p1->from.reg = REGSP;
                p1->from.offset = -8;
                regfree(&r2);
                regfree(&r1);
                if(tt == TUINT64) {
                        p1 = gbranch(optoas(OLT, types[TFLOAT64]), T, +1); // use CR0 here again
-                       nodreg(&r1, types[TINT64], D_R0+REGTMP);
+                       nodreg(&r1, types[TINT64], REGTMP);
                        gins(AMOVD, &bigi, &r1);
                        gins(AADD, &r1, &r3);
                        patch(p1, pc);
@@ -931,29 +929,29 @@ gmove(Node *f, Node *t)
                regalloc(&r1, types[TINT64], N);
                gmove(f, &r1);
                if(ft == TUINT64) {
-                       nodreg(&r2, types[TUINT64], D_R0+REGTMP);
+                       nodreg(&r2, types[TUINT64], REGTMP);
                        gmove(&bigi, &r2);
                        gins(ACMPU, &r1, &r2);
                        p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1);
                        p2 = gins(ASRD, N, &r1);
-                       p2->from.type = D_CONST;
+                       p2->from.type = TYPE_CONST;
                        p2->from.offset = 1;
                        patch(p1, pc);
                }
                regalloc(&r2, types[TFLOAT64], t);
                p1 = gins(AMOVD, &r1, N);
-               p1->to.type = D_OREG;
+               p1->to.type = TYPE_MEM;
                p1->to.reg = REGSP;
                p1->to.offset = -8;
                p1 = gins(AFMOVD, N, &r2);
-               p1->from.type = D_OREG;
+               p1->from.type = TYPE_MEM;
                p1->from.reg = REGSP;
                p1->from.offset = -8;
                gins(AFCFID, &r2, &r2);
                regfree(&r1);
                if(ft == TUINT64) {
                        p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1); // use CR0 here again
-                       nodreg(&r1, types[TFLOAT64], D_F0+FREGTWO);
+                       nodreg(&r1, types[TFLOAT64], FREGTWO);
                        gins(AFMUL, &r1, &r2);
                        patch(p1, pc);
                }
@@ -1026,8 +1024,6 @@ gins(int as, Node *f, Node *t)
                p->from = af;
        if(t != N)
                p->to = at;
-       if(as == ATEXT)
-               p->reg = 0;
        if(debug['g'])
                print("%P\n", p);
 
@@ -1053,12 +1049,12 @@ gins(int as, Node *f, Node *t)
                break;
        case AMOVD:
        case AMOVDU:
-               if(af.type == D_CONST)
+               if(af.type == TYPE_CONST || af.type == TYPE_ADDR)
                        break;
                w = 8;
                break;
        }
-       if(w != 0 && ((f != N && af.width < w) || (t != N && at.type != D_REG && at.width > w))) {
+       if(w != 0 && ((f != N && af.width < w) || (t != N && at.type != TYPE_REG && at.width > w))) {
                dump("f", f);
                dump("t", t);
                fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
@@ -1076,7 +1072,7 @@ fixlargeoffset(Node *n)
                return;
        if(n->op != OINDREG)
                return;
-       if(n->val.u.reg == D_R0+REGSP) // stack offset cannot be large
+       if(n->val.u.reg == REGSP) // stack offset cannot be large
                return;
        if(n->xoffset != (int32)n->xoffset) {
                // TODO(minux): offset too large, move into R31 and add to R31 instead.
@@ -1102,9 +1098,9 @@ naddr(Node *n, Addr *a, int canemitcode)
 {
        Sym *s;
 
-       a->type = D_NONE;
-       a->name = D_NONE;
-       a->reg = NREG;
+       a->type = TYPE_NONE;
+       a->name = NAME_NONE;
+       a->reg = 0;
        a->gotype = nil;
        a->node = N;
        a->etype = 0;
@@ -1124,7 +1120,7 @@ naddr(Node *n, Addr *a, int canemitcode)
 
        case ONAME:
                a->etype = 0;
-               a->reg = NREG;
+               a->reg = 0;
                if(n->type != T)
                        a->etype = simtype[n->type->etype];
                a->offset = n->xoffset;
@@ -1141,23 +1137,23 @@ naddr(Node *n, Addr *a, int canemitcode)
                                s = pkglookup(s->name, n->type->sym->pkg);
                }
 
-               a->type = D_OREG;
+               a->type = TYPE_MEM;
                switch(n->class) {
                default:
                        fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
                case PEXTERN:
-                       a->name = D_EXTERN;
+                       a->name = NAME_EXTERN;
                        break;
                case PAUTO:
-                       a->name = D_AUTO;
+                       a->name = NAME_AUTO;
                        break;
                case PPARAM:
                case PPARAMOUT:
-                       a->name = D_PARAM;
+                       a->name = NAME_PARAM;
                        break;
                case PFUNC:
-                       a->name = D_EXTERN;
-                       a->type = D_CONST;
+                       a->name = NAME_EXTERN;
+                       a->type = TYPE_ADDR;
                        a->width = widthptr;
                        s = funcsym(s);
                        break;
@@ -1171,13 +1167,13 @@ naddr(Node *n, Addr *a, int canemitcode)
                        fatal("naddr: const %lT", n->type);
                        break;
                case CTFLT:
-                       a->type = D_FCONST;
+                       a->type = TYPE_FCONST;
                        a->u.dval = mpgetflt(n->val.u.fval);
                        break;
                case CTINT:
                case CTRUNE:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = mpgetfix(n->val.u.xval);
                        break;
                case CTSTR:
@@ -1185,30 +1181,25 @@ naddr(Node *n, Addr *a, int canemitcode)
                        break;
                case CTBOOL:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = n->val.u.bval;
                        break;
                case CTNIL:
                        a->sym = nil;
-                       a->type = D_CONST;
+                       a->type = TYPE_CONST;
                        a->offset = 0;
                        break;
                }
                break;
 
        case OREGISTER:
-               if(n->val.u.reg < D_F0) {
-                       a->type = D_REG;
-                       a->reg = n->val.u.reg;
-               } else {
-                       a->type = D_FREG;
-                       a->reg = n->val.u.reg - D_F0;
-               }
+               a->type = TYPE_REG;
+               a->reg = n->val.u.reg;
                a->sym = nil;
                break;
 
        case OINDREG:
-               a->type = D_OREG;
+               a->type = TYPE_MEM;
                a->reg = n->val.u.reg;
                a->sym = linksym(n->sym);
                a->offset = n->xoffset;
@@ -1223,15 +1214,15 @@ naddr(Node *n, Addr *a, int canemitcode)
                a->width = n->left->type->width;
                a->offset = n->xoffset;
                a->sym = linksym(n->left->sym);
-               a->type = D_OREG;
-               a->name = D_PARAM;
+               a->type = TYPE_MEM;
+               a->name = NAME_PARAM;
                a->node = n->left->orig;
                break;
 
        case OCLOSUREVAR:
                if(!curfn->needctxt)
                        fatal("closurevar without needctxt");
-               a->type = D_OREG;
+               a->type = TYPE_MEM;
                a->reg = REGENV;
                a->offset = n->xoffset;
                a->sym = nil;
@@ -1246,7 +1237,7 @@ naddr(Node *n, Addr *a, int canemitcode)
                // itable of interface value
                naddr(n->left, a, canemitcode);
                a->etype = simtype[tptr];
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // itab(nil)
                a->width = widthptr;
                break;
@@ -1255,7 +1246,7 @@ naddr(Node *n, Addr *a, int canemitcode)
                // pointer in a string or slice
                naddr(n->left, a, canemitcode);
                a->etype = simtype[tptr];
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // ptr(nil)
                a->offset += Array_array;
                a->width = widthptr;
@@ -1265,7 +1256,7 @@ naddr(Node *n, Addr *a, int canemitcode)
                // len of string or slice
                naddr(n->left, a, canemitcode);
                a->etype = simtype[TINT];
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // len(nil)
                a->offset += Array_nel;
                a->width = widthint;
@@ -1275,7 +1266,7 @@ naddr(Node *n, Addr *a, int canemitcode)
                // cap of string or slice
                naddr(n->left, a, canemitcode);
                a->etype = simtype[TINT];
-               if(a->type == D_CONST && a->offset == 0)
+               if(a->type == TYPE_CONST && a->offset == 0)
                        break;  // cap(nil)
                a->offset += Array_cap;
                a->width = widthint;
@@ -1285,12 +1276,12 @@ naddr(Node *n, Addr *a, int canemitcode)
                naddr(n->left, a, canemitcode);
                a->etype = tptr;
                switch(a->type) {
-               case D_OREG:
-                       a->type = D_CONST;
+               case TYPE_MEM:
+                       a->type = TYPE_ADDR;
                        break;
 
-               case D_REG:
-               case D_CONST:
+               case TYPE_REG:
+               case TYPE_CONST:
                        break;
 
                default:
@@ -1311,7 +1302,7 @@ optoas(int op, Type *t)
        if(t == T)
                fatal("optoas: t is nil");
 
-       a = AGOK;
+       a = AXXX;
        switch(CASE(op, simtype[t->etype])) {
        default:
                fatal("optoas: no entry for op=%O type=%T", op, t);
index 6a07b268f212d7866ec81f03fe68ad9acc4b17e2..25b670327988d5d5b912b89222218b2ec5388e42 100644 (file)
@@ -28,7 +28,6 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include       "../gc/popt.h"
 
 #define        Z       N
 #define        Adr     Addr
@@ -170,59 +169,6 @@ int        BtoF(uint64);
 /*
  * prog.c
  */
-typedef struct ProgInfo ProgInfo;
-struct ProgInfo
-{
-       uint32 flags; // the bits below
-       uint64 reguse; // registers implicitly used by this instruction
-       uint64 regset; // registers implicitly set by this instruction
-       uint64 regindex; // registers used by addressing mode
-};
-
-enum
-{
-       // Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
-       Pseudo = 1<<1,
-       
-       // There's nothing to say about the instruction,
-       // but it's still okay to see.
-       OK = 1<<2,
-
-       // Size of right-side write, or right-side read if no write.
-       SizeB = 1<<3,
-       SizeW = 1<<4,
-       SizeL = 1<<5,
-       SizeQ = 1<<6,
-       SizeF = 1<<7, // float aka float32
-       SizeD = 1<<8, // double aka float64
-
-       // Left side (Prog.from): address taken, read, write.
-       LeftAddr = 1<<9,
-       LeftRead = 1<<10,
-       LeftWrite = 1<<11,
-
-       // Register in middle (Prog.reg); only ever read.
-       RegRead = 1<<12,
-       CanRegRead = 1<<13,
-
-       // Right side (Prog.to): address taken, read, write.
-       RightAddr = 1<<14,
-       RightRead = 1<<15,
-       RightWrite = 1<<16,
-
-       // Instruction updates whichever of from/to is type D_OREG
-       PostInc = 1<<17,
-
-       // Instruction kinds
-       Move = 1<<18, // straight move
-       Conv = 1<<19, // size conversion
-       Cjmp = 1<<20, // conditional jump
-       Break = 1<<21, // breaks control flow (no fallthrough)
-       Call = 1<<22, // function call
-       Jump = 1<<23, // jump
-       Skip = 1<<24, // data instruction
-};
-
 void proginfo(ProgInfo*, Prog*);
 
 // Many Power ISA arithmetic and logical instructions come in four
@@ -234,11 +180,3 @@ enum {
 
 int as2variant(int);
 int variant2as(int, int);
-
-// To allow use of AJMP, ACALL, ARET in ../gc/popt.c.
-enum
-{
-       AJMP = ABR,
-       ACALL = ABL,
-       ARET = ARETURN,
-};
index 4e636b14840fa6ed835840e3ab0ddb3f1ea955f4..95ff0b4d5842a3eaf5374607504fa521d32a9469 100644 (file)
@@ -88,8 +88,8 @@ loop1:
                        // Convert uses to $0 to uses of R0 and
                        // propagate R0
                        if(regzer(&p->from))
-                       if(p->to.type == D_REG) {
-                               p->from.type = D_REG;
+                       if(p->to.type == TYPE_REG) {
+                               p->from.type = TYPE_REG;
                                p->from.reg = REGZERO;
                                if(copyprop(r)) {
                                        excise(r);
@@ -119,7 +119,7 @@ loop1:
                case AMOVBZ:
                case AMOVW:
                case AMOVWZ:
-                       if(p->to.type != D_REG)
+                       if(p->to.type != TYPE_REG)
                                continue;
                        break;
                }
@@ -129,9 +129,9 @@ loop1:
                p1 = r1->prog;
                if(p1->as != p->as)
                        continue;
-               if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+               if(p1->from.type != TYPE_REG || p1->from.reg != p->to.reg)
                        continue;
-               if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+               if(p1->to.type != TYPE_REG || p1->to.reg != p->to.reg)
                        continue;
                excise(r1);
        }
@@ -177,7 +177,7 @@ loop1:
                        if(r1 == nil)
                                continue;
                        p1 = r1->prog;
-                       if(p1->to.type != D_REG || p1->to.reg != p->from.reg)
+                       if(p1->to.type != TYPE_REG || p1->to.reg != p->from.reg)
                                continue;
                        switch(p1->as) {
                        case ASUB:
@@ -185,7 +185,7 @@ loop1:
                        case AXOR:
                        case AOR:
                                /* irregular instructions */
-                               if(p1->from.type == D_CONST)
+                               if(p1->from.type == TYPE_CONST || p1->from.type == TYPE_ADDR)
                                        continue;
                                break;
                        }
@@ -194,7 +194,7 @@ loop1:
                                continue;
                        case AMOVW:
                        case AMOVD:
-                               if(p1->from.type != D_REG)
+                               if(p1->from.type != TYPE_REG)
                                        continue;
                                continue;
                        case AANDCC:
@@ -327,15 +327,12 @@ ret:
 void
 excise(Flow *r)
 {
-       Prog *p, *l;
+       Prog *p;
 
        p = r->prog;
        if(debug['P'] && debug['v'])
                print("%P ===delete===\n", p);
-       l = p->link;
-       *p = zprog;
-       p->as = ANOP;
-       p->link = l;
+       nopout(p);
        ostats.ndelmov++;
 }
 
@@ -345,11 +342,11 @@ excise(Flow *r)
 static int
 regzer(Addr *a)
 {
-       if(a->type == D_CONST)
-               if(a->sym == nil && a->reg == NREG)
+       if(a->type == TYPE_CONST || a->type == TYPE_ADDR)
+               if(a->sym == nil && a->reg == 0)
                        if(a->offset == 0)
                                return 1;
-       if(a->type == D_REG)
+       if(a->type == TYPE_REG)
                if(a->reg == REGZERO)
                        return 1;
        return 0;
@@ -358,15 +355,8 @@ regzer(Addr *a)
 int
 regtyp(Adr *a)
 {
-       switch(a->type) {
-       default:
-               return 0;
-       case D_REG:
-               if(a->reg == REGZERO)
-                       return 0;
-       case D_FREG:
-               return 1;
-       }
+       // TODO(rsc): Floating point register exclusions?
+       return a->type == TYPE_REG && REG_R0 <= a->reg && a->reg <= REG_F31 && a->reg != REGZERO;
 }
 
 /*
@@ -581,7 +571,7 @@ copy1(Addr *v1, Addr *v2, Flow *r, int f)
 int
 copyu(Prog *p, Addr *v, Addr *s)
 {
-       if(p->from3.type != D_NONE)
+       if(p->from3.type != TYPE_NONE)
                // 9g never generates a from3
                print("copyu: from3 (%D) not implemented\n", p->from3);
 
@@ -633,7 +623,7 @@ copyu(Prog *p, Addr *v, Addr *s)
                }
                if(copyas(&p->to, v)) {
                        // Fix up implicit from
-                       if(p->from.type == D_NONE)
+                       if(p->from.type == TYPE_NONE)
                                p->from = p->to;
                        if(copyau(&p->from, v))
                                return 4;
@@ -652,7 +642,7 @@ copyu(Prog *p, Addr *v, Addr *s)
        case AMOVHZU:
        case AMOVWZU:
        case AMOVDU:
-               if(p->from.type == D_OREG) {
+               if(p->from.type == TYPE_MEM) {
                        if(copyas(&p->from, v))
                                // No s!=nil check; need to fail
                                // anyway in that case
@@ -664,7 +654,7 @@ copyu(Prog *p, Addr *v, Addr *s)
                        }
                        if(copyas(&p->to, v))
                                return 3;
-               } else if (p->to.type == D_OREG) {
+               } else if (p->to.type == TYPE_MEM) {
                        if(copyas(&p->to, v))
                                return 2;
                        if(s != nil) {
@@ -743,7 +733,7 @@ copyu(Prog *p, Addr *v, Addr *s)
                        return 0;
                }
                if(copyas(&p->to, v)) {
-                       if(p->reg == NREG)
+                       if(p->reg == 0)
                                // Fix up implicit reg (e.g., ADD
                                // R3,R4 -> ADD R3,R4,R4) so we can
                                // update reg and to separately.
@@ -811,17 +801,20 @@ copyu(Prog *p, Addr *v, Addr *s)
                return 3;
 
        case ABL:       /* funny */
-               if(v->type == D_REG) {
-                       if(v->reg <= REGEXT && v->reg > exregoffset)
+               if(v->type == TYPE_REG) {
+                       // TODO(rsc): REG_R0 and REG_F0 used to be
+                       // (when register numbers started at 0) exregoffset and exfregoffset,
+                       // which are unset entirely. 
+                       // It's strange that this handles R0 and F0 differently from the other
+                       // registers. Possible failure to optimize?
+                       if(REG_R0 < v->reg && v->reg <= REGEXT)
                                return 2;
                        if(v->reg == REGARG)
                                return 2;
-               }
-               if(v->type == D_FREG) {
-                       if(v->reg <= FREGEXT && v->reg > exfregoffset)
+                       if(REG_F0 < v->reg && v->reg <= FREGEXT)
                                return 2;
                }
-               if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg)
+               if(p->from.type == TYPE_REG && v->type == TYPE_REG && p->from.reg == v->reg)
                        return 2;
 
                if(s != nil) {
@@ -836,7 +829,7 @@ copyu(Prog *p, Addr *v, Addr *s)
        case ADUFFZERO:
                // R0 is zero, used by DUFFZERO, cannot be substituted.
                // R3 is ptr to memory, used and set, cannot be substituted.
-               if(v->type == D_REG) {
+               if(v->type == TYPE_REG) {
                        if(v->reg == 0)
                                return 1;
                        if(v->reg == 3)
@@ -847,7 +840,7 @@ copyu(Prog *p, Addr *v, Addr *s)
        case ADUFFCOPY:
                // R3, R4 are ptr to src, dst, used and set, cannot be substituted.
                // R5 is scratch, set by DUFFCOPY, cannot be substituted.
-               if(v->type == D_REG) {
+               if(v->type == TYPE_REG) {
                        if(v->reg == 3 || v->reg == 4)
                                return 2;
                        if(v->reg == 5)
@@ -856,7 +849,7 @@ copyu(Prog *p, Addr *v, Addr *s)
                return 0;
 
        case ATEXT:     /* funny */
-               if(v->type == D_REG)
+               if(v->type == TYPE_REG)
                        if(v->reg == REGARG)
                                return 3;
                return 0;
@@ -869,18 +862,6 @@ copyu(Prog *p, Addr *v, Addr *s)
        }
 }
 
-int
-a2type(Prog *p)
-{
-       ProgInfo info;
-       proginfo(&info, p);
-       if(info.flags & (SizeB|SizeW|SizeL|SizeQ))
-               return D_REG;
-       if(info.flags & (SizeF|SizeD))
-               return D_FREG;
-       return D_NONE;
-}
-
 // copyas returns 1 if a and v address the same register.
 //
 // If a is the from operand, this means this operation reads the
@@ -908,8 +889,8 @@ copyau(Addr *a, Addr *v)
 {
        if(copyas(a, v))
                return 1;
-       if(v->type == D_REG)
-               if(a->type == D_OREG || (a->type == D_CONST && a->reg != NREG))
+       if(v->type == TYPE_REG)
+               if(a->type == TYPE_MEM || (a->type == TYPE_ADDR && a->reg != 0))
                        if(v->reg == a->reg)
                                return 1;
        return 0;
@@ -920,17 +901,9 @@ copyau(Addr *a, Addr *v)
 static int
 copyau1(Prog *p, Addr *v)
 {
-       if(regtyp(v))
-               if(p->from.type == v->type || p->to.type == v->type)
-               if(p->reg == v->reg) {
-                       // Whether p->reg is a GPR or an FPR is
-                       // implied by the instruction (both are
-                       // numbered from 0).  But the type should
-                       // match v->type.  Sanity check this.
-                       if(a2type(p) != v->type)
-                               print("botch a2type %P\n", p);
+       if(regtyp(v) && v->reg != 0)
+               if(p->reg == v->reg)
                        return 1;
-               }
        return 0;
 }
 
@@ -963,7 +936,7 @@ sameaddr(Addr *a, Addr *v)
                return 0;
        if(regtyp(v) && a->reg == v->reg)
                return 1;
-       if(v->type == D_AUTO || v->type == D_PARAM)
+       if(v->type == NAME_AUTO || v->type == NAME_PARAM)
                if(v->offset == a->offset)
                        return 1;
        return 0;
@@ -972,7 +945,7 @@ sameaddr(Addr *a, Addr *v)
 int
 smallindir(Addr *a, Addr *reg)
 {
-       return reg->type == D_REG && a->type == D_OREG &&
+       return reg->type == TYPE_REG && a->type == TYPE_MEM &&
                a->reg == reg->reg &&
                0 <= a->offset && a->offset < 4096;
 }
@@ -980,5 +953,5 @@ smallindir(Addr *a, Addr *reg)
 int
 stackaddr(Addr *a)
 {
-       return a->type == D_REG && a->reg == REGSP;
+       return a->type == TYPE_REG && a->reg == REGSP;
 }
index 7c0f0c7959e8913400c1532602ca57375e2650d5..1775993a97da7a82d2e58ce7b218d64b67e4568b 100644 (file)
@@ -137,37 +137,37 @@ proginfo(ProgInfo *info, Prog *p)
                fatal("proginfo: unknown instruction %P", p);
        }
 
-       if((info->flags & RegRead) && p->reg == NREG) {
+       if((info->flags & RegRead) && p->reg == 0) {
                info->flags &= ~RegRead;
                info->flags |= /*CanRegRead |*/ RightRead;
        }
 
-       if((p->from.type == D_OREG || p->from.type == D_CONST) && p->from.reg != NREG) {
+       if((p->from.type == TYPE_MEM || p->from.type == TYPE_ADDR) && p->from.reg != 0) {
                info->regindex |= RtoB(p->from.reg);
                if(info->flags & PostInc) {
                        info->regset |= RtoB(p->from.reg);
                }
        }
-       if((p->to.type == D_OREG || p->to.type == D_CONST) && p->to.reg != NREG) {
+       if((p->to.type == TYPE_MEM || p->to.type == TYPE_ADDR) && p->to.reg != 0) {
                info->regindex |= RtoB(p->to.reg);
                if(info->flags & PostInc) {
                        info->regset |= RtoB(p->to.reg);
                }
        }
 
-       if(p->from.type == D_CONST && p->from.sym != nil && (info->flags & LeftRead)) {
+       if(p->from.type == TYPE_ADDR && p->from.sym != nil && (info->flags & LeftRead)) {
                info->flags &= ~LeftRead;
                info->flags |= LeftAddr;
        }
 
        if(p->as == ADUFFZERO) {
-               info->reguse |= (1<<D_R0) | RtoB(3);
-               info->regset |= RtoB(3);
+               info->reguse |= (1<<0) | RtoB(REG_R3);
+               info->regset |= RtoB(REG_R3);
        }
        if(p->as == ADUFFCOPY) {
                // TODO(austin) Revisit when duffcopy is implemented
-               info->reguse |= RtoB(3) | RtoB(4) | RtoB(5);
-               info->regset |= RtoB(3) | RtoB(4);
+               info->reguse |= RtoB(REG_R3) | RtoB(REG_R4) | RtoB(REG_R5);
+               info->regset |= RtoB(REG_R3) | RtoB(REG_R4);
        }
 }
 
index 6d40127ecc623b800b948a2adfd24a25ddb00c3e..a7ee07e5473e95a3695b101ba2a38e780b641828 100644 (file)
@@ -185,9 +185,9 @@ regopt(Prog *firstp)
        }
 
        // Exclude registers with fixed functions
-       regbits = (1<<D_R0)|RtoB(REGSP)|RtoB(REGG)|RtoB(REGTLS);
+       regbits = (1<<0)|RtoB(REGSP)|RtoB(REGG)|RtoB(REGTLS);
        // Also exclude floating point registers with fixed constants
-       regbits |= FtoB(D_F0+27)|FtoB(D_F0+28)|FtoB(D_F0+29)|FtoB(D_F0+30)|FtoB(D_F0+31);
+       regbits |= RtoB(REG_F27)|RtoB(REG_F28)|RtoB(REG_F29)|RtoB(REG_F30)|RtoB(REG_F31);
        externs = zbits;
        params = zbits;
        consts = zbits;
@@ -217,7 +217,7 @@ regopt(Prog *firstp)
                proginfo(&info, p);
 
                // Avoid making variables for direct-called functions.
-               if(p->as == ABL && p->to.name == D_EXTERN)
+               if(p->as == ABL && p->to.name == NAME_EXTERN)
                        continue;
 
                // from vs to doesn't matter for registers
@@ -233,16 +233,12 @@ regopt(Prog *firstp)
                                r->use1.b[z] |= bit.b[z];
 
                // Compute used register for reg
-               if(info.flags & RegRead) {
-                       if(p->from.type != D_FREG)
-                               r->use1.b[0] |= RtoB(p->reg);
-                       else
-                               r->use1.b[0] |= FtoB(D_F0+p->reg);
-               }
+               if(info.flags & RegRead)
+                       r->use1.b[0] |= RtoB(p->reg);
 
                // Currently we never generate three register forms.
                // If we do, this will need to change.
-               if(p->from3.type != D_NONE)
+               if(p->from3.type != TYPE_NONE)
                        fatal("regopt not implemented for from3");
 
                // Compute used register for to
@@ -296,7 +292,7 @@ regopt(Prog *firstp)
        }
        for(r = firstr; r != R; r = (Reg*)r->f.link) {
                p = r->f.prog;
-               if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
+               if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
                        active++;
                        walkvardef(p->to.node, r, active);
                }
@@ -484,7 +480,7 @@ brk:
        for(p=firstp; p!=P; p=p->link) {
                while(p->link != P && p->link->as == ANOP)
                        p->link = p->link->link;
-               if(p->to.type == D_BRANCH)
+               if(p->to.type == TYPE_BRANCH)
                        while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
                                p->to.u.branch = p->to.u.branch->link;
        }
@@ -556,7 +552,7 @@ addmove(Reg *r, int bn, int rn, int f)
        // If there's a stack fixup coming (ADD $n,R1 after BL newproc or BL deferproc),
        // delay the load until after the fixup.
        p2 = p->link;
-       if(p2 && p2->as == AADD && p2->to.reg == REGSP && p2->to.type == D_REG)
+       if(p2 && p2->as == AADD && p2->to.reg == REGSP && p2->to.type == TYPE_REG)
                p = p2;
 
        p1->link = p->link;
@@ -571,9 +567,11 @@ addmove(Reg *r, int bn, int rn, int f)
        a->sym = linksym(v->node->sym);
        a->offset = v->offset;
        a->etype = v->etype;
-       a->type = D_OREG;
-       if(a->etype == TARRAY || a->sym == nil)
-               a->type = D_CONST;
+       a->type = TYPE_MEM;
+       if(a->etype == TARRAY)
+               a->type = TYPE_ADDR;
+       else if(a->sym == nil)
+               a->type = TYPE_CONST;
 
        if(v->addr)
                fatal("addmove: shouldn't be doing this %A\n", a);
@@ -616,21 +614,13 @@ addmove(Reg *r, int bn, int rn, int f)
                break;
        }
 
-       p1->from.type = D_REG;
+       p1->from.type = TYPE_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->type = TYPE_REG;
                a->reg = rn;
-               if(rn >= NREG) {
-                       a->type = D_FREG;
-                       a->reg = rn-NREG;
-               }
                if(v->etype == TUINT8 || v->etype == TBOOL)
                        p1->as = AMOVBZ;
                if(v->etype == TUINT16)
@@ -673,42 +663,34 @@ mkvar(Reg *r, Adr *a)
                print("type %d %d %D\n", t, a->name, a);
                goto none;
 
-       case D_NONE:
+       case TYPE_NONE:
                goto none;
 
-       case D_BRANCH:
-       case D_CONST:
-       case D_FCONST:
-       case D_SCONST:
-       case D_SPR:
-       case D_OREG:
+       case TYPE_BRANCH:
+       case TYPE_CONST:
+       case TYPE_FCONST:
+       case TYPE_SCONST:
+       case TYPE_MEM:
+       case TYPE_ADDR:
                break;
 
-       case D_REG:
-               if(a->reg != NREG) {
+       case TYPE_REG:
+               if(a->reg != 0) {
                        bit = zbits;
                        bit.b[0] = RtoB(a->reg);
                        return bit;
                }
                break;
-
-       case D_FREG:
-               if(a->reg != NREG) {
-                       bit = zbits;
-                       bit.b[0] = FtoB(D_F0+a->reg);
-                       return bit;
-               }
-               break;
        }
 
        switch(a->name) {
        default:
                goto none;
 
-       case D_EXTERN:
-       case D_STATIC:
-       case D_AUTO:
-       case D_PARAM:
+       case NAME_EXTERN:
+       case NAME_STATIC:
+       case NAME_AUTO:
+       case NAME_PARAM:
                n = a->name;
                break;
        }
@@ -784,10 +766,10 @@ mkvar(Reg *r, Adr *a)
        node->opt = v;
 
        bit = blsh(i);
-       if(n == D_EXTERN || n == D_STATIC)
+       if(n == NAME_EXTERN || n == NAME_STATIC)
                for(z=0; z<BITS; z++)
                        externs.b[z] |= bit.b[z];
-       if(n == D_PARAM)
+       if(n == NAME_PARAM)
                for(z=0; z<BITS; z++)
                        params.b[z] |= bit.b[z];
 
@@ -1014,7 +996,7 @@ allreg(uint64 b, Rgn *r)
                i = BtoF(~b);
                if(i && r->cost > 0) {
                        r->regno = i;
-                       return FtoB(i);
+                       return RtoB(i);
                }
                break;
        }
@@ -1213,13 +1195,9 @@ addreg(Adr *a, int rn)
 {
        a->sym = nil;
        a->node = nil;
-       a->name = D_NONE;
-       a->type = D_REG;
+       a->name = NAME_NONE;
+       a->type = TYPE_REG;
        a->reg = rn;
-       if(rn >= NREG) {
-               a->type = D_FREG;
-               a->reg = rn-NREG;
-       }
 
        ostats.ncvtreg++;
 }
@@ -1239,8 +1217,10 @@ addreg(Adr *a, int rn)
 uint64
 RtoB(int r)
 {
-       if(r > D_R0 && r <= D_R0+31)
-               return 1ULL << (r - D_R0);
+       if(r > REG_R0 && r <= REG_R31)
+               return 1ULL << (r - REG_R0);
+       if(r >= REG_F0 && r <= REG_F31)
+               return 1ULL << (32 + r - REG_F0);
        return 0;
 }
 
@@ -1250,15 +1230,7 @@ BtoR(uint64 b)
        b &= 0xffffffffull;
        if(b == 0)
                return 0;
-       return bitno(b) + D_R0;
-}
-
-uint64
-FtoB(int r)
-{
-       if(r >= D_F0 && r <= D_F0+31)
-               return 1ULL << (32 + r - D_F0);
-       return 0;
+       return bitno(b) + REG_R0;
 }
 
 int
@@ -1267,7 +1239,7 @@ BtoF(uint64 b)
        b >>= 32;
        if(b == 0)
                return 0;
-       return bitno(b) + D_F0;
+       return bitno(b) + REG_F0;
 }
 
 void
index dbb2e0a76809bc58636818dc53bdaa9d6df5dc7f..b99e7e6f4d5b5d852debff3c33f181784628f96d 100644 (file)
@@ -40,32 +40,186 @@ enum
 
 #include "../ld/textflag.h"
 
+// avoid conflict with ucontext.h. sigh.
+#undef REG_R0
+#undef REG_R1
+#undef REG_R2
+#undef REG_R3
+#undef REG_R4
+#undef REG_R5
+#undef REG_R6
+#undef REG_R7
+#undef REG_R8
+#undef REG_R9
+#undef REG_R10
+#undef REG_R11
+#undef REG_R12
+#undef REG_R13
+#undef REG_R14
+#undef REG_R15
+#undef REG_R16
+#undef REG_R17
+#undef REG_R18
+#undef REG_R19
+#undef REG_R20
+#undef REG_R21
+#undef REG_R22
+#undef REG_R23
+#undef REG_R24
+#undef REG_R25
+#undef REG_R26
+#undef REG_R27
+#undef REG_R28
+#undef REG_R29
+#undef REG_R30
+#undef REG_R31
+#define REG_R0 GO_REG_R0
+#define REG_R1 GO_REG_R1
+#define REG_R2 GO_REG_R2
+#define REG_R3 GO_REG_R3
+#define REG_R4 GO_REG_R4
+#define REG_R5 GO_REG_R5
+#define REG_R6 GO_REG_R6
+#define REG_R7 GO_REG_R7
+#define REG_R8 GO_REG_R8
+#define REG_R9 GO_REG_R9
+#define REG_R10 GO_REG_R10
+#define REG_R11 GO_REG_R11
+#define REG_R12 GO_REG_R12
+#define REG_R13 GO_REG_R13
+#define REG_R14 GO_REG_R14
+#define REG_R15 GO_REG_R15
+#define REG_R16 GO_REG_R16
+#define REG_R17 GO_REG_R17
+#define REG_R18 GO_REG_R18
+#define REG_R19 GO_REG_R19
+#define REG_R20 GO_REG_R20
+#define REG_R21 GO_REG_R21
+#define REG_R22 GO_REG_R22
+#define REG_R23 GO_REG_R23
+#define REG_R24 GO_REG_R24
+#define REG_R25 GO_REG_R25
+#define REG_R26 GO_REG_R26
+#define REG_R27 GO_REG_R27
+#define REG_R28 GO_REG_R28
+#define REG_R29 GO_REG_R29
+#define REG_R30 GO_REG_R30
+#define REG_R31 GO_REG_R31
+
 enum
 {
-       REGZERO         = 0,    /* set to zero */
-       REGSP           = 1,
-       REGSB           = 2,
-       REGRET          = 3,
+       REG_R0 = 32,
+       REG_R1,
+       REG_R2,
+       REG_R3,
+       REG_R4,
+       REG_R5,
+       REG_R6,
+       REG_R7,
+       REG_R8,
+       REG_R9,
+       REG_R10,
+       REG_R11,
+       REG_R12,
+       REG_R13,
+       REG_R14,
+       REG_R15,
+       REG_R16,
+       REG_R17,
+       REG_R18,
+       REG_R19,
+       REG_R20,
+       REG_R21,
+       REG_R22,
+       REG_R23,
+       REG_R24,
+       REG_R25,
+       REG_R26,
+       REG_R27,
+       REG_R28,
+       REG_R29,
+       REG_R30,
+       REG_R31,
+
+       REG_F0 = 64,
+       REG_F1,
+       REG_F2,
+       REG_F3,
+       REG_F4,
+       REG_F5,
+       REG_F6,
+       REG_F7,
+       REG_F8,
+       REG_F9,
+       REG_F10,
+       REG_F11,
+       REG_F12,
+       REG_F13,
+       REG_F14,
+       REG_F15,
+       REG_F16,
+       REG_F17,
+       REG_F18,
+       REG_F19,
+       REG_F20,
+       REG_F21,
+       REG_F22,
+       REG_F23,
+       REG_F24,
+       REG_F25,
+       REG_F26,
+       REG_F27,
+       REG_F28,
+       REG_F29,
+       REG_F30,
+       REG_F31,
+       
+       REG_SPECIAL = 96,
+
+       REG_C0 = 96,
+       REG_C1,
+       REG_C2,
+       REG_C3,
+       REG_C4,
+       REG_C5,
+       REG_C6,
+       REG_C7,
+       
+       REG_MSR = 104,
+       REG_FPSCR,
+       REG_CR,
+
+       REG_SPR0 = 1024, // first of 1024 registers
+       REG_DCR0 = 2048, // first of 1024 registers
+       
+       REG_XER = REG_SPR0 + 1,
+       REG_LR = REG_SPR0 + 8,
+       REG_CTR = REG_SPR0 + 9,
+
+       REGZERO         = REG_R0,       /* set to zero */
+       REGSP           = REG_R1,
+       REGSB           = REG_R2,
+       REGRET          = REG_R3,
        REGARG          = -1,   /* -1 disables passing the first argument in register */
-       REGRT1          = 3,    /* reserved for runtime, duffzero and duffcopy */
-       REGRT2          = 4,    /* reserved for runtime, duffcopy */
-       REGMIN          = 7,    /* register variables allocated from here to REGMAX */
-       REGENV          = 11,   /* environment for closures */
-       REGTLS          = 13,   /* C ABI TLS base pointer */
-       REGMAX          = 27,
-       REGEXT          = 30,   /* external registers allocated from here down */
-       REGG            = 30,   /* G */
-       REGTMP          = 31,   /* used by the linker */
+       REGRT1          = REG_R3,       /* reserved for runtime, duffzero and duffcopy */
+       REGRT2          = REG_R4,       /* reserved for runtime, duffcopy */
+       REGMIN          = REG_R7,       /* register variables allocated from here to REGMAX */
+       REGENV          = REG_R11,      /* environment for closures */
+       REGTLS          = REG_R13,      /* C ABI TLS base pointer */
+       REGMAX          = REG_R27,
+       REGEXT          = REG_R30,      /* external registers allocated from here down */
+       REGG            = REG_R30,      /* G */
+       REGTMP          = REG_R31,      /* used by the linker */
 
-       FREGRET         = 0,
-       FREGMIN         = 17,   /* first register variable */
-       FREGMAX         = 26,   /* last register variable for 9g only */
-       FREGEXT         = 26,   /* first external register */
-       FREGCVI         = 27,   /* floating conversion constant */
-       FREGZERO        = 28,   /* both float and double */
-       FREGHALF        = 29,   /* double */
-       FREGONE         = 30,   /* double */
-       FREGTWO         = 31    /* double */
+       FREGRET         = REG_F0,
+       FREGMIN         = REG_F17,      /* first register variable */
+       FREGMAX         = REG_F26,      /* last register variable for 9g only */
+       FREGEXT         = REG_F26,      /* first external register */
+       FREGCVI         = REG_F27,      /* floating conversion constant */
+       FREGZERO        = REG_F28,      /* both float and double */
+       FREGHALF        = REG_F29,      /* double */
+       FREGONE         = REG_F30,      /* double */
+       FREGTWO         = REG_F31       /* double */
 /*
  * GENERAL:
  *
@@ -132,14 +286,14 @@ enum
        C_ANY,
        C_GOK,
        C_ADDR,
+       C_TEXTSIZE,
 
        C_NCLASS,       /* must be the last */
 };
 
 enum
 {
-       AXXX,
-       AADD,
+       AADD = A_ARCHSPECIFIC,
        AADDCC,
        AADDV,
        AADDVCC,
@@ -168,11 +322,9 @@ enum
        ABEQ,
        ABGE,
        ABGT,
-       ABL,
        ABLE,
        ABLT,
        ABNE,
-       ABR,
        ABVC,
        ABVS,
        ACMP,
@@ -356,19 +508,7 @@ enum
        ATW,
 
        ASYSCALL,
-       ADATA,
-       AGLOBL,
-       AGOK,
-       AHISTORY,
-       ANAME,
-       ANOP,
-       ARETURN,
-       ATEXT,
        AWORD,
-       AEND,
-       ADYNT,
-       AINIT,
-       ASIGNAME,
 
        ARFCI,
 
@@ -457,62 +597,12 @@ enum
        /* more 64-bit operations */
        AHRFID,
 
-       AUNDEF,
-       AUSEFIELD,
-       ATYPE,
-       AFUNCDATA,
-       APCDATA,
-       ACHECKNIL,
-       AVARDEF,
-       AVARKILL,
-       ADUFFCOPY,
-       ADUFFZERO,
-
-       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_FPSCR,
-       D_MSR,
-       D_FREG,
-       D_CREG,
-       D_SPR,
-       D_OPT,  /* branch/trap option */
-       D_FILE,
-       D_FILE1,
-       D_DCR,  /* device control register */
-       D_DCONST,
-       D_ADDR, // not used, use D_CONST with non-empty sym.
-
-       D_LAST,
-
-/* reg names for 9g OREGISTER */
-       D_R0 = 0, // type is D_REG
-       D_F0 = D_R0+NREG, // type is D_FREG
-
-/* reg names in offset field iff type is D_SPR */
-       D_XER   = 1,
-       D_LR    = 8,
-       D_CTR   = 9
-       /* and many supervisor level registers */
+       ALAST,
+       
+       // aliases
+       ABR = AJMP,
+       ABL = ACALL,
+       ARETURN = ARET,
 };
 
 /*
index e217ddcf0b75f695cf660b415d2b35ad56948ec9..4bc4d794c848b2b78306c4cfbd0f6489b047c27b 100644 (file)
@@ -739,6 +739,10 @@ func (p *Package) gccMachine() []string {
                return []string{"-m32"}
        case "arm":
                return []string{"-marm"} // not thumb
+       case "s390":
+               return []string{"-m31"}
+       case "s390x":
+               return []string{"-m64"}
        }
        return nil
 }
index ad8b960e2f73d0602ec5a070c0770ede0863b6ed..4dbcf6270961d877847a2be7ade97466d8e2ea08 100644 (file)
@@ -135,6 +135,8 @@ var ptrSizeMap = map[string]int64{
        "arm":     4,
        "ppc64":   8,
        "ppc64le": 8,
+       "s390":    4,
+       "s390x":   8,
 }
 
 var intSizeMap = map[string]int64{
@@ -143,6 +145,8 @@ var intSizeMap = map[string]int64{
        "arm":     4,
        "ppc64":   8,
        "ppc64le": 8,
+       "s390":    4,
+       "s390x":   4,
 }
 
 var cPrefix string
index 86f5d219e4dad5c752b2aced03abfb1e022e32ac..152655b5086fb51c3eb5219ea43656dbbdef69ba 100644 (file)
@@ -518,43 +518,18 @@ var deptab = []struct {
                "anames9.c",
        }},
        {"cmd/gc", []string{
-               "-cplx.c",
-               "-pgen.c",
-               "-plive.c",
-               "-popt.c",
-               "-y1.tab.c", // makefile dreg
                "opnames.h",
        }},
        {"cmd/5g", []string{
-               "../gc/cplx.c",
-               "../gc/pgen.c",
-               "../gc/plive.c",
-               "../gc/popt.c",
-               "../gc/popt.h",
                "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
        }},
        {"cmd/6g", []string{
-               "../gc/cplx.c",
-               "../gc/pgen.c",
-               "../gc/plive.c",
-               "../gc/popt.c",
-               "../gc/popt.h",
                "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
        }},
        {"cmd/8g", []string{
-               "../gc/cplx.c",
-               "../gc/pgen.c",
-               "../gc/plive.c",
-               "../gc/popt.c",
-               "../gc/popt.h",
                "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
        }},
        {"cmd/9g", []string{
-               "../gc/cplx.c",
-               "../gc/pgen.c",
-               "../gc/plive.c",
-               "../gc/popt.c",
-               "../gc/popt.h",
                "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
        }},
        {"cmd/5l", []string{
@@ -578,7 +553,6 @@ var deptab = []struct {
                "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/lib9.a",
        }},
        {"runtime", []string{
-               "zaexperiment.h",
                "zversion.go",
        }},
 }
@@ -603,7 +577,6 @@ var gentab = []struct {
        {"anames9.c", mkanames},
        {"zdefaultcc.go", mkzdefaultcc},
        {"zversion.go", mkzversion},
-       {"zaexperiment.h", mkzexperiment},
 
        // not generated anymore, but delete the file if we see it
        {"enam.c", nil},
@@ -948,8 +921,8 @@ func install(dir string) {
                                )
                        }
 
-                       // gc/lex.c records the GOEXPERIMENT setting used during the build.
-                       if name == "lex.c" {
+                       // liblink/go.c records the GOEXPERIMENT setting used during the build.
+                       if name == "go.c" {
                                compile = append(compile,
                                        "-D", fmt.Sprintf("GOEXPERIMENT=%q", os.Getenv("GOEXPERIMENT")))
                        }
index b1b5d5e7ba5869428fddff627a36378debf7d417..bc1898e04ea2e344cb0384238355829a2b410084 100644 (file)
@@ -7,7 +7,6 @@ package main
 import (
        "bytes"
        "fmt"
-       "strconv"
        "strings"
 )
 
@@ -50,12 +49,11 @@ func gcopnames(dir, file string) {
 
 // mkanames reads [5689].out.h and writes anames[5689].c
 // The format is much the same as the Go opcodes above.
-// It also writes out cnames array for C_* constants and the dnames
-// array for D_* constants.
+// It also writes out cnames array for C_* constants.
 func mkanames(dir, file string) {
        ch := file[len(file)-3]
        targ := pathf("%s/../cmd/%cl/%c.out.h", dir, ch, ch)
-       in := readfile(targ)
+       in := readfile(pathf("%s/../../include/link.h", dir)) + readfile(targ)
        lines := splitlines(in)
 
        // Include link.h so that the extern declaration there is
@@ -71,10 +69,20 @@ func mkanames(dir, file string) {
 
        fmt.Fprintf(&out, "char*        anames%c[] = {\n", ch)
        for _, line := range lines {
-               if strings.HasPrefix(line, "\tA") {
+               // Use all A names found in the headers,
+               // except don't use A_ARCHSPECIFIC (left to arch to define),
+               // and don't use any aliases (= A...),
+               // except do use the arch-defined alias for A_ARCHSPECIFIC.
+               if strings.Contains(line, ";") {
+                       continue
+               }
+               if strings.HasPrefix(line, "\tA") && !strings.Contains(line, "\tA_") && (!strings.Contains(line, "= A") || strings.Contains(line, "= A_ARCHSPECIFIC")) {
                        if i := strings.Index(line, ","); i >= 0 {
                                line = line[:i]
                        }
+                       if i := strings.Index(line, "="); i >= 0 {
+                               line = line[:i]
+                       }
                        if i := strings.Index(line, "\n"); i >= 0 {
                                line = line[:i]
                        }
@@ -105,66 +113,5 @@ func mkanames(dir, file string) {
                out.Write(out2.Bytes())
        }
 
-       var dnames [128][]string
-       j = 0
-       unknown := false
-       n := -1
-       for _, line := range lines {
-               if strings.HasPrefix(line, "\tD_") {
-                       if i := strings.Index(line, ","); i >= 0 {
-                               line = line[:i]
-                       }
-
-                       // Parse explicit value, if any
-                       if i := strings.Index(line, "="); i >= 0 {
-                               value := strings.TrimSpace(line[i+1:])
-                               line = strings.TrimSpace(line[:i])
-                               var err error
-                               n, err = strconv.Atoi(value)
-                               if err != nil {
-                                       // We can't do anything about
-                                       // non-numeric values or anything that
-                                       // follows.
-                                       unknown = true
-                                       continue
-                               }
-                               unknown = false
-                       } else {
-                               n++
-                       }
-
-                       if unknown || n < 0 || n >= len(dnames) {
-                               continue
-                       }
-
-                       line = strings.TrimSpace(line)
-                       line = line[len("D_"):]
-
-                       if strings.Contains(line, "LAST") {
-                               continue
-                       }
-                       dnames[n] = append(dnames[n], line)
-                       j++
-               }
-       }
-
-       if j > 0 {
-               fmt.Fprintf(&out, "char*        dnames%c[D_LAST] = {\n", ch)
-               for _, d := range dnames {
-                       if len(d) == 0 {
-                               continue
-                       }
-                       fmt.Fprintf(&out, "\t[D_%s] = \"", d[0])
-                       for k, name := range d {
-                               if k > 0 {
-                                       fmt.Fprintf(&out, "/")
-                               }
-                               fmt.Fprintf(&out, "%s", name)
-                       }
-                       fmt.Fprintf(&out, "\",\n")
-               }
-               fmt.Fprintf(&out, "};\n")
-       }
-
        writefile(out.String(), file, 0)
 }
index 5e2605966b881518780b8ace2e16c312b57651ad..ff2a489b5594642d26587d09047d7999829ec6fb 100644 (file)
@@ -27,21 +27,8 @@ func mkzversion(dir, file string) {
                        "\n"+
                        "const defaultGoroot = `%s`\n"+
                        "const theVersion = `%s`\n"+
-                       "\n"+
-                       "var buildVersion = theVersion\n", goroot_final, goversion)
-
-       writefile(out, file, 0)
-}
-
-// mkzexperiment writes zaexperiment.h (sic):
-//
-//     #define GOEXPERIMENT "experiment string"
-//
-func mkzexperiment(dir, file string) {
-       out := fmt.Sprintf(
-               "// auto generated by go tool dist\n"+
-                       "\n"+
-                       "#define GOEXPERIMENT \"%s\"\n", os.Getenv("GOEXPERIMENT"))
+                       "const goexperiment = `%s`\n"+
+                       "var buildVersion = theVersion\n", goroot_final, goversion, os.Getenv("GOEXPERIMENT"))
 
        writefile(out, file, 0)
 }
index 2dbc59a5fb4d2e6691106c6953299b9210a868cf..39052dbb30c5f4511515198d10d803237c00c135 100644 (file)
@@ -6,10 +6,10 @@
 
 // try to run "vmov.f64 d0, d0" instruction
 TEXT Â·useVFPv1(SB),NOSPLIT,$0
-       WORD $0xeeb00b40        // vomv.f64 d0, d0
+       WORD $0xeeb00b40        // vmov.f64 d0, d0
        RET
 
 // try to run VFPv3-only "vmov.f64 d0, #112" instruction
 TEXT Â·useVFPv3(SB),NOSPLIT,$0
-        WORD $0xeeb70b00       // vmov.f64 d0, #112
+       WORD $0xeeb70b00        // vmov.f64 d0, #112
        RET
index 57daaa974558d6a4a7e57a47a1e278bdceef11e2..26d72e87fcb572a2832a321458e0621de897c9fd 100644 (file)
@@ -19,7 +19,7 @@ vlong
 rnd(vlong o, vlong r)
 {
        if(r < 1 || r > 8 || (r&(r-1)) != 0)
-               fatal("rnd");
+               fatal("rnd %lld", r);
        return (o+r-1)&~(r-1);
 }
 
@@ -35,7 +35,7 @@ offmod(Type *t)
                        fatal("offmod: not TFIELD: %lT", f);
                f->width = o;
                o += widthptr;
-               if(o >= MAXWIDTH) {
+               if(o >= arch.MAXWIDTH) {
                        yyerror("interface too large");
                        o = widthptr;
                }
@@ -86,7 +86,7 @@ widstruct(Type *errtype, Type *t, vlong o, int flag)
                if(w == 0)
                        lastzero = o;
                o += w;
-               if(o >= MAXWIDTH) {
+               if(o >= arch.MAXWIDTH) {
                        yyerror("type %lT too large", errtype);
                        o = 8;  // small but nonzero
                }
@@ -260,7 +260,7 @@ dowidth(Type *t)
 
                        dowidth(t->type);
                        if(t->type->width != 0) {
-                               cap = (MAXWIDTH-1) / t->type->width;
+                               cap = (arch.MAXWIDTH-1) / t->type->width;
                                if(t->bound > cap)
                                        yyerror("type %lT larger than address space", t);
                        }
@@ -613,15 +613,15 @@ typeinit(void)
        simtype[TFUNC] = tptr;
        simtype[TUNSAFEPTR] = tptr;
 
-       /* pick up the backend typedefs */
-       for(i=0; typedefs[i].name; i++) {
-               s = lookup(typedefs[i].name);
-               s1 = pkglookup(typedefs[i].name, builtinpkg);
+       /* pick up the backend arch.typedefs */
+       for(i=0; arch.typedefs[i].name; i++) {
+               s = lookup(arch.typedefs[i].name);
+               s1 = pkglookup(arch.typedefs[i].name, builtinpkg);
 
-               etype = typedefs[i].etype;
+               etype = arch.typedefs[i].etype;
                if(etype < 0 || etype >= nelem(types))
                        fatal("typeinit: %s bad etype", s->name);
-               sameas = typedefs[i].sameas;
+               sameas = arch.typedefs[i].sameas;
                if(sameas < 0 || sameas >= nelem(types))
                        fatal("typeinit: %s bad sameas", s->name);
                simtype[etype] = sameas;
index 611fc9fbd406d2ee408585559d9715b3388384a7..d5d9646d6a90f62d1e90b84bca429e7f4650166c 100644 (file)
@@ -10,16 +10,8 @@ enum {
        DEFAULTCAPACITY = 16,
 };
 
-struct Array
-{
-       int32   length;  // number of elements
-       int32   size;  // element size
-       int32   capacity;  // size of data in elements
-       char    *data;  // element storage
-};
-
 Array*
-arraynew(int32 capacity, int32 size)
+arraynew(int capacity, int32 size)
 {
        Array *result;
 
@@ -48,14 +40,14 @@ arrayfree(Array *array)
        free(array);
 }
 
-int32
+int
 arraylength(Array *array)
 {
        return array->length;
 }
 
 void*
-arrayget(Array *array, int32 index)
+arrayget(Array *array, int index)
 {
        if(array == nil)
                fatal("arrayget: array is nil\n");
@@ -65,7 +57,7 @@ arrayget(Array *array, int32 index)
 }
 
 void
-arrayset(Array *array, int32 index, void *element)
+arrayset(Array *array, int index, void *element)
 {
        if(array == nil)
                fatal("arrayset: array is nil\n");
@@ -77,7 +69,7 @@ arrayset(Array *array, int32 index, void *element)
 }
 
 static void
-ensurecapacity(Array *array, int32 capacity)
+ensurecapacity(Array *array, int capacity)
 {
        int32 newcapacity;
        char *newdata;
index e2e14f03d2b887e1f1f64f64b3465e7f3e9b3768..f154ae70b1c5bfe8f9627a1355db710e63f648ef 100644 (file)
@@ -26,18 +26,19 @@ char *runtimeimport =
        "func @\"\".printsp ()\n"
        "func @\"\".printlock ()\n"
        "func @\"\".printunlock ()\n"
-       "func @\"\".concatstring2 (? string, ? string) (? string)\n"
-       "func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n"
-       "func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n"
-       "func @\"\".concatstring5 (? string, ? string, ? string, ? string, ? string) (? string)\n"
-       "func @\"\".concatstrings (? []string) (? string)\n"
+       "func @\"\".concatstring2 (? *[32]byte, ? string, ? string) (? string)\n"
+       "func @\"\".concatstring3 (? *[32]byte, ? string, ? string, ? string) (? string)\n"
+       "func @\"\".concatstring4 (? *[32]byte, ? string, ? string, ? string, ? string) (? string)\n"
+       "func @\"\".concatstring5 (? *[32]byte, ? string, ? string, ? string, ? string, ? string) (? string)\n"
+       "func @\"\".concatstrings (? *[32]byte, ? []string) (? string)\n"
        "func @\"\".cmpstring (? string, ? string) (? int)\n"
        "func @\"\".eqstring (? string, ? string) (? bool)\n"
-       "func @\"\".intstring (? int64) (? string)\n"
-       "func @\"\".slicebytetostring (? []byte) (? string)\n"
+       "func @\"\".intstring (? *[4]byte, ? int64) (? string)\n"
+       "func @\"\".slicebytetostring (? *[32]byte, ? []byte) (? string)\n"
        "func @\"\".slicebytetostringtmp (? []byte) (? string)\n"
        "func @\"\".slicerunetostring (? []rune) (? string)\n"
        "func @\"\".stringtoslicebyte (? string) (? []byte)\n"
+       "func @\"\".stringtoslicebytetmp (? string) (? []byte)\n"
        "func @\"\".stringtoslicerune (? string) (? []rune)\n"
        "func @\"\".stringiter (? string, ? int) (? int)\n"
        "func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n"
index cfd1cd2811164a2c08d95440595535f8d3bf82f7..2428006c8afae23619c01fa82c7f818ec8945e38 100644 (file)
@@ -7,7 +7,7 @@
 #include "go.h"
 
 enum {
-       WORDSIZE = sizeof(uint32),
+       WORDSIZE = 4,
        WORDBITS = 32,
        WORDMASK = WORDBITS - 1,
        WORDSHIFT = 5,
index ad4e5bd02b02ad5b0dc324c841c3af4fd6c22b07..5d25ffe4ad133e8f8d7b22d873f7cfaafe232fda 100644 (file)
@@ -70,7 +70,7 @@ closurebody(NodeList *body)
        for(l=func->cvars; l; l=l->next) {
                v = l->n;
                v->closure->closure = v->outer;
-               v->heapaddr = nod(OADDR, oldname(v->sym), N);
+               v->outerexpr = oldname(v->sym);
        }
 
        return func;
@@ -81,48 +81,46 @@ static Node* makeclosure(Node *func);
 void
 typecheckclosure(Node *func, int top)
 {
-       Node *oldfn;
+       Node *oldfn, *n;
        NodeList *l;
-       Node *v;
+       int olddd;
+
+       for(l=func->cvars; l; l=l->next) {
+               n = l->n->closure;
+               if(!n->captured) {
+                       n->captured = 1;
+                       if(n->decldepth == 0)
+                               fatal("typecheckclosure: var %hN does not have decldepth assigned", n);
+                       // Ignore assignments to the variable in straightline code
+                       // preceding the first capturing by a closure.
+                       if(n->decldepth == decldepth)
+                               n->assigned = 0;
+               }
+       }
+
+       for(l=func->dcl; l; l=l->next)
+               if(l->n->op == ONAME && (l->n->class == PPARAM || l->n->class == PPARAMOUT))
+                       l->n->decldepth = 1;
 
        oldfn = curfn;
        typecheck(&func->ntype, Etype);
        func->type = func->ntype->type;
-       
+
        // Type check the body now, but only if we're inside a function.
        // At top level (in a variable initialization: curfn==nil) we're not
        // ready to type check code yet; we'll check it later, because the
        // underlying closure function we create is added to xtop.
        if(curfn && func->type != T) {
                curfn = func;
+               olddd = decldepth;
+               decldepth = 1;
                typechecklist(func->nbody, Etop);
+               decldepth = olddd;
                curfn = oldfn;
        }
 
-       // type check the & of closed variables outside the closure,
-       // so that the outer frame also grabs them and knows they
-       // escape.
-       func->enter = nil;
-       for(l=func->cvars; l; l=l->next) {
-               v = l->n;
-               if(v->type == T) {
-                       // if v->type is nil, it means v looked like it was
-                       // going to be used in the closure but wasn't.
-                       // this happens because when parsing a, b, c := f()
-                       // the a, b, c gets parsed as references to older
-                       // a, b, c before the parser figures out this is a
-                       // declaration.
-                       v->op = 0;
-                       continue;
-               }
-               // For a closure that is called in place, but not
-               // inside a go statement, avoid moving variables to the heap.
-               if ((top & (Ecall|Eproc)) == Ecall)
-                       v->heapaddr->etype = 1;
-               typecheck(&v->heapaddr, Erv);
-               func->enter = list(func->enter, v->heapaddr);
-               v->heapaddr = N;
-       }
+       // Remember closure context for capturevars.
+       func->etype = (top & (Ecall|Eproc)) == Ecall;
 
        // Create top-level function 
        xtop = list(xtop, makeclosure(func));
@@ -131,11 +129,8 @@ typecheckclosure(Node *func, int top)
 static Node*
 makeclosure(Node *func)
 {
-       Node *xtype, *v, *addr, *xfunc, *cv;
-       NodeList *l, *body;
+       Node *xtype, *xfunc;
        static int closgen;
-       char *p;
-       vlong offset;
 
        /*
         * wrap body in external function
@@ -156,16 +151,82 @@ makeclosure(Node *func)
        xfunc->nname->funcdepth = func->funcdepth;
        xfunc->funcdepth = func->funcdepth;
        xfunc->endlineno = func->endlineno;
+
+       xfunc->nbody = func->nbody;
+       xfunc->dcl = concat(func->dcl, xfunc->dcl);
+       if(xfunc->nbody == nil)
+               fatal("empty body - won't generate any code");
+       typecheck(&xfunc, Etop);
+
+       xfunc->closure = func;
+       func->closure = xfunc;
        
-       // declare variables holding addresses taken from closure
-       // and initialize in entry prologue.
+       func->nbody = nil;
+       func->list = nil;
+       func->rlist = nil;
+
+       return xfunc;
+}
+
+// capturevars is called in a separate phase after all typechecking is done.
+// It decides whether each variable captured by a closure should be captured
+// by value or by reference.
+// We use value capturing for values <= 128 bytes that are never reassigned
+// after declaration.
+void
+capturevars(Node *xfunc)
+{
+       Node *func, *v, *addr, *cv, *outer;
+       NodeList *l, *body;
+       char *p;
+       vlong offset;
+       int nvar, lno;
+
+       lno = lineno;
+       lineno = xfunc->lineno;
+
+       nvar = 0;
        body = nil;
        offset = widthptr;
-       xfunc->needctxt = func->cvars != nil;
+       func = xfunc->closure;
+       func->enter = nil;
        for(l=func->cvars; l; l=l->next) {
                v = l->n;
-               if(v->op == 0)
+               if(v->type == T) {
+                       // if v->type is nil, it means v looked like it was
+                       // going to be used in the closure but wasn't.
+                       // this happens because when parsing a, b, c := f()
+                       // the a, b, c gets parsed as references to older
+                       // a, b, c before the parser figures out this is a
+                       // declaration.
+                       v->op = OXXX;
                        continue;
+               }
+               nvar++;
+
+               // type check the & of closed variables outside the closure,
+               // so that the outer frame also grabs them and knows they escape.
+               dowidth(v->type);
+               outer = v->outerexpr;
+               v->outerexpr = N;
+               // out parameters will be assigned to implicitly upon return.
+               if(outer->class != PPARAMOUT && !v->closure->addrtaken && !v->closure->assigned && v->type->width <= 128)
+                       v->byval = 1;
+               else {
+                       outer = nod(OADDR, outer, N);
+                       // For a closure that is called in place, but not
+                       // inside a go statement, avoid moving variables to the heap.
+                       outer->etype = func->etype;
+               }
+               if(debug['m'] > 1)
+                       warnl(v->lineno, "%S capturing by %s: %S (addr=%d assign=%d width=%d)",
+                               (v->curfn && v->curfn->nname) ? v->curfn->nname->sym : S, v->byval ? "value" : "ref",
+                               v->sym, v->closure->addrtaken, v->closure->assigned, (int32)v->type->width);
+               typecheck(&outer, Erv);
+               func->enter = list(func->enter, outer);
+
+               // declare variables holding addresses taken from closure
+               // and initialize in entry prologue.
                addr = nod(ONAME, N, N);
                p = smprint("&%s", v->sym->name);
                addr->sym = lookup(p);
@@ -179,38 +240,35 @@ makeclosure(Node *func)
                xfunc->dcl = list(xfunc->dcl, addr);
                v->heapaddr = addr;
                cv = nod(OCLOSUREVAR, N, N);
-               cv->type = ptrto(v->type);
-               cv->xoffset = offset;
-               body = list(body, nod(OAS, addr, cv));
-               offset += widthptr;
+               if(v->byval) {
+                       cv->type = v->type;
+                       offset = rnd(offset, v->type->align);
+                       cv->xoffset = offset;
+                       offset += v->type->width;
+                       body = list(body, nod(OAS, addr, nod(OADDR, cv, N)));
+               } else {
+                       v->closure->addrtaken = 1;
+                       cv->type = ptrto(v->type);
+                       offset = rnd(offset, widthptr);
+                       cv->xoffset = offset;
+                       offset += widthptr;
+                       body = list(body, nod(OAS, addr, cv));
+               }
        }
        typechecklist(body, Etop);
        walkstmtlist(body);
        xfunc->enter = body;
+       xfunc->needctxt = nvar > 0;
+       func->etype = 0;
 
-       xfunc->nbody = func->nbody;
-       xfunc->dcl = concat(func->dcl, xfunc->dcl);
-       if(xfunc->nbody == nil)
-               fatal("empty body - won't generate any code");
-       typecheck(&xfunc, Etop);
-
-       xfunc->closure = func;
-       func->closure = xfunc;
-       
-       func->nbody = nil;
-       func->list = nil;
-       func->rlist = nil;
-
-       return xfunc;
+       lineno = lno;
 }
 
 Node*
 walkclosure(Node *func, NodeList **init)
 {
-       Node *clos, *typ;
+       Node *clos, *typ, *typ1, *v;
        NodeList *l;
-       char buf[20];
-       int narg;
 
        // If no closure vars, don't bother wrapping.
        if(func->cvars == nil)
@@ -230,14 +288,16 @@ walkclosure(Node *func, NodeList **init)
        // the struct is unnamed so that closures in multiple packages with the
        // same struct type can share the descriptor.
 
-       narg = 0;
        typ = nod(OTSTRUCT, N, N);
        typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
        for(l=func->cvars; l; l=l->next) {
-               if(l->n->op == 0)
+               v = l->n;
+               if(v->op == OXXX)
                        continue;
-               snprint(buf, sizeof buf, "A%d", narg++);
-               typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup(buf)), l->n->heapaddr->ntype));
+               typ1 = typenod(v->type);
+               if(!v->byval)
+                       typ1 = nod(OIND, typ1, N);
+               typ->list = list(typ->list, nod(ODCLFIELD, newname(v->sym), typ1));
        }
 
        clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
@@ -315,7 +375,7 @@ makepartialcall(Node *fn, Type *t0, Node *meth)
                spkg = basetype->sym->pkg;
        if(spkg == nil) {
                if(gopkg == nil)
-                       gopkg = mkpkg(strlit("go"));
+                       gopkg = mkpkg(newstrlit("go"));
                spkg = gopkg;
        }
        sym = pkglookup(p, spkg);
index c9bab7a7686c69e20ed025dfc731b6677b2c4b5f..d3fb9525584da00f299c4616fda80ffed92d1352 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <u.h>
 #include <libc.h>
-#include "gg.h"
+#include "go.h"
 
 static void    subnode(Node *nr, Node *ni, Node *nc);
 static void    minus(Node *nl, Node *res);
@@ -14,6 +14,14 @@ static       void    minus(Node *nl, Node *res);
 
 #define        CASE(a,b)       (((a)<<16)|((b)<<0))
 
+/*c2go
+static int
+CASE(int a, int b)
+{
+       return a<<16 | b;
+}
+*/
+
 static int
 overlap(Node *f, Node *t)
 {
@@ -70,8 +78,8 @@ complexmove(Node *f, Node *t)
                subnode(&n1, &n2, f);
                subnode(&n3, &n4, t);
 
-               cgen(&n1, &n3);
-               cgen(&n2, &n4);
+               arch.cgen(&n1, &n3);
+               arch.cgen(&n2, &n4);
                break;
        }
 }
@@ -143,9 +151,9 @@ complexgen(Node *n, Node *res)
                if(res->addable) {
                        subnode(&n1, &n2, res);
                        tempname(&tmp, n1.type);
-                       cgen(n->left, &tmp);
-                       cgen(n->right, &n2);
-                       cgen(&tmp, &n1);
+                       arch.cgen(n->left, &tmp);
+                       arch.cgen(n->right, &n2);
+                       arch.cgen(&tmp, &n1);
                        return;
                }
                break;
@@ -160,10 +168,10 @@ complexgen(Node *n, Node *res)
                }
                subnode(&n1, &n2, nl);
                if(n->op == OREAL) {
-                       cgen(&n1, res);
+                       arch.cgen(&n1, res);
                        return;
                }
-               cgen(&n2, res);
+               arch.cgen(&n2, res);
                return;
        }
 
@@ -183,9 +191,9 @@ complexgen(Node *n, Node *res)
        }
 
        if(!res->addable) {
-               igen(res, &n1, N);
-               cgen(n, &n1);
-               regfree(&n1);
+               arch.igen(res, &n1, N);
+               arch.cgen(n, &n1);
+               arch.regfree(&n1);
                return;
        }
        if(n->addable) {
@@ -206,9 +214,9 @@ complexgen(Node *n, Node *res)
        case OCALLFUNC:
        case OCALLMETH:
        case OCALLINTER:
-               igen(n, &n1, res);
+               arch.igen(n, &n1, res);
                complexmove(&n1, res);
-               regfree(&n1);
+               arch.regfree(&n1);
                return;
 
        case OCONV:
@@ -231,18 +239,18 @@ complexgen(Node *n, Node *res)
        if(nr != N) {
                if(nl->ullman > nr->ullman && !nl->addable) {
                        tempname(&tnl, nl->type);
-                       cgen(nl, &tnl);
+                       arch.cgen(nl, &tnl);
                        nl = &tnl;
                }
                if(!nr->addable) {
                        tempname(&tnr, nr->type);
-                       cgen(nr, &tnr);
+                       arch.cgen(nr, &tnr);
                        nr = &tnr;
                }
        }
        if(!nl->addable) {
                tempname(&tnl, nl->type);
-               cgen(nl, &tnl);
+               arch.cgen(nl, &tnl);
                nl = &tnl;
        }
 
@@ -281,18 +289,18 @@ complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to)
        if(nr != N) {
                if(nl->ullman > nr->ullman && !nl->addable) {
                        tempname(&tnl, nl->type);
-                       cgen(nl, &tnl);
+                       arch.cgen(nl, &tnl);
                        nl = &tnl;
                }
                if(!nr->addable) {
                        tempname(&tnr, nr->type);
-                       cgen(nr, &tnr);
+                       arch.cgen(nr, &tnr);
                        nr = &tnr;
                }
        }
        if(!nl->addable) {
                tempname(&tnl, nl->type);
-               cgen(nl, &tnl);
+               arch.cgen(nl, &tnl);
                nl = &tnl;
        }
 
@@ -308,13 +316,13 @@ complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to)
        na.right = &nc;
        na.type = types[TBOOL];
 
-       memset(&nb, 0, sizeof(na));
+       memset(&nb, 0, sizeof(nb));
        nb.op = OEQ;
        nb.left = &n1;
        nb.right = &n3;
        nb.type = types[TBOOL];
 
-       memset(&nc, 0, sizeof(na));
+       memset(&nc, 0, sizeof(nc));
        nc.op = OEQ;
        nc.left = &n2;
        nc.right = &n4;
@@ -323,7 +331,7 @@ complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to)
        if(op == ONE)
                true = !true;
 
-       bgen(&na, true, likely, to);
+       arch.bgen(&na, true, likely, to);
 }
 
 void
@@ -379,7 +387,7 @@ minus(Node *nl, Node *res)
        ra.op = OMINUS;
        ra.left = nl;
        ra.type = nl->type;
-       cgen(&ra, res);
+       arch.cgen(&ra, res);
 }
 
 // build and execute tree
@@ -416,14 +424,14 @@ complexadd(int op, Node *nl, Node *nr, Node *res)
        ra.left = &n1;
        ra.right = &n3;
        ra.type = n1.type;
-       cgen(&ra, &n5);
+       arch.cgen(&ra, &n5);
 
        memset(&ra, 0, sizeof(ra));
        ra.op = op;
        ra.left = &n2;
        ra.right = &n4;
        ra.type = n2.type;
-       cgen(&ra, &n6);
+       arch.cgen(&ra, &n6);
 }
 
 // build and execute tree
@@ -442,13 +450,13 @@ complexmul(Node *nl, Node *nr, Node *res)
        tempname(&tmp, n5.type);
 
        // real part -> tmp
-       memset(&rm1, 0, sizeof(ra));
+       memset(&rm1, 0, sizeof(rm1));
        rm1.op = OMUL;
        rm1.left = &n1;
        rm1.right = &n3;
        rm1.type = n1.type;
 
-       memset(&rm2, 0, sizeof(ra));
+       memset(&rm2, 0, sizeof(rm2));
        rm2.op = OMUL;
        rm2.left = &n2;
        rm2.right = &n4;
@@ -459,16 +467,16 @@ complexmul(Node *nl, Node *nr, Node *res)
        ra.left = &rm1;
        ra.right = &rm2;
        ra.type = rm1.type;
-       cgen(&ra, &tmp);
+       arch.cgen(&ra, &tmp);
 
        // imag part
-       memset(&rm1, 0, sizeof(ra));
+       memset(&rm1, 0, sizeof(rm1));
        rm1.op = OMUL;
        rm1.left = &n1;
        rm1.right = &n4;
        rm1.type = n1.type;
 
-       memset(&rm2, 0, sizeof(ra));
+       memset(&rm2, 0, sizeof(rm2));
        rm2.op = OMUL;
        rm2.left = &n2;
        rm2.right = &n3;
@@ -479,8 +487,8 @@ complexmul(Node *nl, Node *nr, Node *res)
        ra.left = &rm1;
        ra.right = &rm2;
        ra.type = rm1.type;
-       cgen(&ra, &n6);
+       arch.cgen(&ra, &n6);
 
        // tmp ->real part
-       cgen(&tmp, &n5);
+       arch.cgen(&tmp, &n5);
 }
index dfcf47520ac3d3e0d0f1030ad8881e15c0cc0714..f47ca2b50ede8493ec63ec3ea31b465e591b10db 100644 (file)
@@ -452,7 +452,6 @@ oldname(Sym *s)
                        c->funcdepth = funcdepth;
                        c->outer = n->closure;
                        n->closure = c;
-                       n->addrtaken = 1;
                        c->closure = n;
                        c->xoffset = 0;
                        curfn->cvars = list(curfn->cvars, c);
@@ -1284,7 +1283,7 @@ methodsym(Sym *nsym, Type *t0, int iface)
        }
        if(spkg == nil) {
                if(toppkg == nil)
-                       toppkg = mkpkg(strlit("go"));
+                       toppkg = mkpkg(newstrlit("go"));
                spkg = toppkg;
        }
        s = pkglookup(p, spkg);
@@ -1413,7 +1412,7 @@ addmethod(Sym *sf, Type *t, int local, int nointerface)
        for(f=pa->method; f!=T; f=f->down) {
                d = f;
                if(f->etype != TFIELD)
-                       fatal("addmethod: not TFIELD: %N", f);
+                       fatal("addmethod: not TFIELD: %lT", f);
                if(strcmp(sf->name, f->sym->name) != 0)
                        continue;
                if(!eqtype(t, f->type))
index 324f24fcf89f3f39f17ab3097e9f6aa5c4667e49..4f77983926613d577e55c17ebc3cd5b4e4d5b1c4 100644 (file)
@@ -241,7 +241,7 @@ mktag(int mask)
                return tags[mask];
 
        snprint(buf, sizeof buf, "esc:0x%x", mask);
-       s = strlit(buf);
+       s = newstrlit(buf);
        if(mask < nelem(tags))
                tags[mask] = s;
        return s;
@@ -429,7 +429,7 @@ esc(EscState *e, Node *n, Node *up)
 {
        int lno;
        NodeList *ll, *lr;
-       Node *a;
+       Node *a, *v;
 
        if(n == N)
                return;
@@ -511,6 +511,36 @@ esc(EscState *e, Node *n, Node *up)
 
        case OAS:
        case OASOP:
+               // Filter out the following special case.
+               //
+               //      func (b *Buffer) Foo() {
+               //              n, m := ...
+               //              b.buf = b.buf[n:m]
+               //      }
+               //
+               // This assignment is a no-op for escape analysis,
+               // it does not store any new pointers into b that were not already there.
+               // However, without this special case b will escape, because we assign to OIND/ODOTPTR.
+               if((n->left->op == OIND || n->left->op == ODOTPTR) && n->left->left->op == ONAME && // dst is ONAME dereference
+                       (n->right->op == OSLICE || n->right->op == OSLICE3 || n->right->op == OSLICESTR) && // src is slice operation
+                       (n->right->left->op == OIND || n->right->left->op == ODOTPTR) && n->right->left->left->op == ONAME && // slice is applied to ONAME dereference
+                       n->left->left == n->right->left->left) { // dst and src reference the same base ONAME
+                       // Here we also assume that the statement will not contain calls,
+                       // that is, that order will move any calls to init.
+                       // Otherwise base ONAME value could change between the moments
+                       // when we evaluate it for dst and for src.
+                       //
+                       // Note, this optimization does not apply to OSLICEARR,
+                       // because it does introduce a new pointer into b that was not already there
+                       // (pointer to b itself). After such assignment, if b contents escape,
+                       // b escapes as well. If we ignore such OSLICEARR, we will conclude
+                       // that b does not escape when b contents do.
+                       if(debug['m']) {
+                               warnl(n->lineno, "%S ignoring self-assignment to %hN",
+                                       (n->curfn && n->curfn->nname) ? n->curfn->nname->sym : S, n->left);
+                       }
+                       break;
+               }
                escassign(e, n->left, n->right);
                break;
 
@@ -615,15 +645,15 @@ esc(EscState *e, Node *n, Node *up)
                for(ll=n->list; ll; ll=ll->next)
                        escassign(e, n, ll->n->right);
                break;
-       
+
        case OPTRLIT:
                n->esc = EscNone;  // until proven otherwise
                e->noesc = list(e->noesc, n);
                n->escloopdepth = e->loopdepth;
-               // Contents make it to memory, lose track.
-               escassign(e, &e->theSink, n->left);
+               // Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too.
+               escassign(e, n, n->left);
                break;
-       
+
        case OCALLPART:
                n->esc = EscNone; // until proven otherwise
                e->noesc = list(e->noesc, n);
@@ -646,12 +676,16 @@ esc(EscState *e, Node *n, Node *up)
        case OCLOSURE:
                // Link addresses of captured variables to closure.
                for(ll=n->cvars; ll; ll=ll->next) {
-                       if(ll->n->op == OXXX)  // unnamed out argument; see dcl.c:/^funcargs
+                       v = ll->n;
+                       if(v->op == OXXX)  // unnamed out argument; see dcl.c:/^funcargs
                                continue;
-                       a = nod(OADDR, ll->n->closure, N);
-                       a->lineno = ll->n->lineno;
-                       a->escloopdepth = e->loopdepth;
-                       typecheck(&a, Erv);
+                       a = v->closure;
+                       if(!v->byval) {
+                               a = nod(OADDR, a, N);
+                               a->lineno = v->lineno;
+                               a->escloopdepth = e->loopdepth;
+                               typecheck(&a, Erv);
+                       }
                        escassign(e, n, a);
                }
                // fallthrough
@@ -664,6 +698,20 @@ esc(EscState *e, Node *n, Node *up)
                e->noesc = list(e->noesc, n);
                break;
 
+       case OARRAYBYTESTR:
+       case ORUNESTR:
+               n->escloopdepth = e->loopdepth;
+               n->esc = EscNone;  // until proven otherwise
+               e->noesc = list(e->noesc, n);
+               break;
+
+       case OADDSTR:
+               n->escloopdepth = e->loopdepth;
+               n->esc = EscNone;  // until proven otherwise
+               e->noesc = list(e->noesc, n);
+               // Arguments of OADDSTR do not escape.
+               break;
+
        case OADDR:
                n->esc = EscNone;  // until proven otherwise
                e->noesc = list(e->noesc, n);
@@ -730,6 +778,7 @@ escassign(EscState *e, Node *dst, Node *src)
        case OCONVNOP:
        case OMAPLIT:
        case OSTRUCTLIT:
+       case OPTRLIT:
        case OCALLPART:
                break;
 
@@ -775,9 +824,12 @@ escassign(EscState *e, Node *dst, Node *src)
        case OMAKECHAN:
        case OMAKEMAP:
        case OMAKESLICE:
+       case OARRAYBYTESTR:
+       case OADDSTR:
        case ONEW:
        case OCLOSURE:
        case OCALLPART:
+       case ORUNESTR:
                escflows(e, dst, src);
                break;
 
@@ -806,6 +858,7 @@ escassign(EscState *e, Node *dst, Node *src)
        case OSLICE3:
        case OSLICEARR:
        case OSLICE3ARR:
+       case OSLICESTR:
                // Conversions, field access, slice all preserve the input value.
                escassign(e, dst, src->left);
                break;
@@ -1196,10 +1249,13 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
        case OMAKECHAN:
        case OMAKEMAP:
        case OMAKESLICE:
+       case OARRAYBYTESTR:
+       case OADDSTR:
        case OMAPLIT:
        case ONEW:
        case OCLOSURE:
        case OCALLPART:
+       case ORUNESTR:
                if(leaks) {
                        src->esc = EscHeap;
                        if(debug['m'])
@@ -1212,6 +1268,7 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
        case OSLICEARR:
        case OSLICE3:
        case OSLICE3ARR:
+       case OSLICESTR:
                escwalk(e, level, dst, src->left);
                break;
 
index 47c0545d55a9c0e872d53698133e404081ed51fb..8685aa0def47d727fc39fa61282249b379a7c8fe 100644 (file)
@@ -256,7 +256,7 @@ dumpexportvar(Sym *s)
 }
 
 static int
-methcmp(const void *va, const void *vb)
+methodbyname(const void *va, const void *vb)
 {
        Type *a, *b;
        
@@ -297,7 +297,7 @@ dumpexporttype(Type *t)
        i = 0;
        for(f=t->method; f!=T; f=f->down)
                m[i++] = f;
-       qsort(m, n, sizeof m[0], methcmp);
+       qsort(m, n, sizeof m[0], methodbyname);
 
        Bprint(bout, "\ttype %#S %#lT\n", t->sym, t);
        for(i=0; i<n; i++) {
@@ -538,7 +538,7 @@ dumpasmhdr(void)
        b = Bopen(asmhdr, OWRITE);
        if(b == nil)
                fatal("open %s: %r", asmhdr);
-       Bprint(b, "// generated by %cg -asmhdr from package %s\n\n", thechar, localpkg->name);
+       Bprint(b, "// generated by %cg -asmhdr from package %s\n\n", arch.thechar, localpkg->name);
        for(l=asmlist; l; l=l->next) {
                n = l->n;
                if(isblanksym(n->sym))
index 89d2a140461d462c1a57d69ba86f5262a3b692f5..f9eb0ba2b3806cd2a673a22e4c8cd6d1d5b84af0 100644 (file)
@@ -278,6 +278,12 @@ Jconv(Fmt *fp)
        if(n->embedded != 0)
                fmtprint(fp, " embedded(%d)", n->embedded);
 
+       if(n->addrtaken != 0)
+               fmtprint(fp, " addrtaken");
+
+       if(n->assigned != 0)
+               fmtprint(fp, " assigned");
+
        if(!c && n->used != 0)
                fmtprint(fp, " used(%d)", n->used);
        return 0;
index c7c9fcdaff8763fc347cd7219f6b9024859c0444..20c17bd46a10bc60f0ee8cced31d21fba01c887b 100644 (file)
@@ -265,7 +265,7 @@ gen(Node *n)
 //dump("gen", n);
 
        lno = setlineno(n);
-       wasregalloc = anyregalloc();
+       wasregalloc = arch.anyregalloc();
 
        if(n == N)
                goto ret;
@@ -304,8 +304,8 @@ gen(Node *n)
 
                // if there are pending gotos, resolve them all to the current pc.
                for(p1=lab->gotopc; p1; p1=p2) {
-                       p2 = unpatch(p1);
-                       patch(p1, pc);
+                       p2 = arch.unpatch(p1);
+                       arch.patch(p1, pc);
                }
                lab->gotopc = P;
                if(lab->labelpc == P)
@@ -332,9 +332,9 @@ gen(Node *n)
                // of the label in the OLABEL case above.)
                lab = newlab(n);
                if(lab->labelpc != P)
-                       gjmp(lab->labelpc);
+                       arch.gjmp(lab->labelpc);
                else
-                       lab->gotopc = gjmp(lab->gotopc);
+                       lab->gotopc = arch.gjmp(lab->gotopc);
                break;
 
        case OBREAK:
@@ -349,14 +349,14 @@ gen(Node *n)
                                yyerror("invalid break label %S", n->left->sym);
                                break;
                        }
-                       gjmp(lab->breakpc);
+                       arch.gjmp(lab->breakpc);
                        break;
                }
                if(breakpc == P) {
                        yyerror("break is not in a loop");
                        break;
                }
-               gjmp(breakpc);
+               arch.gjmp(breakpc);
                break;
 
        case OCONTINUE:
@@ -371,20 +371,20 @@ gen(Node *n)
                                yyerror("invalid continue label %S", n->left->sym);
                                break;
                        }
-                       gjmp(lab->continpc);
+                       arch.gjmp(lab->continpc);
                        break;
                }
                if(continpc == P) {
                        yyerror("continue is not in a loop");
                        break;
                }
-               gjmp(continpc);
+               arch.gjmp(continpc);
                break;
 
        case OFOR:
                sbreak = breakpc;
-               p1 = gjmp(P);                   //              goto test
-               breakpc = gjmp(P);              // break:       goto done
+               p1 = arch.gjmp(P);                      //              goto test
+               breakpc = arch.gjmp(P);         // break:       goto done
                scontin = continpc;
                continpc = pc;
 
@@ -394,11 +394,11 @@ gen(Node *n)
                        lab->continpc = continpc;
                }
                gen(n->nincr);                          // contin:      incr
-               patch(p1, pc);                          // test:
-               bgen(n->ntest, 0, -1, breakpc);         //              if(!test) goto break
+               arch.patch(p1, pc);                             // test:
+               arch.bgen(n->ntest, 0, -1, breakpc);            //              if(!test) goto break
                genlist(n->nbody);                              //              body
-               gjmp(continpc);
-               patch(breakpc, pc);                     // done:
+               arch.gjmp(continpc);
+               arch.patch(breakpc, pc);                        // done:
                continpc = scontin;
                breakpc = sbreak;
                if(lab) {
@@ -408,29 +408,29 @@ gen(Node *n)
                break;
 
        case OIF:
-               p1 = gjmp(P);                   //              goto test
-               p2 = gjmp(P);                   // p2:          goto else
-               patch(p1, pc);                          // test:
-               bgen(n->ntest, 0, -n->likely, p2);              //              if(!test) goto p2
+               p1 = arch.gjmp(P);                      //              goto test
+               p2 = arch.gjmp(P);                      // p2:          goto else
+               arch.patch(p1, pc);                             // test:
+               arch.bgen(n->ntest, 0, -n->likely, p2);         //              if(!test) goto p2
                genlist(n->nbody);                              //              then
-               p3 = gjmp(P);                   //              goto done
-               patch(p2, pc);                          // else:
+               p3 = arch.gjmp(P);                      //              goto done
+               arch.patch(p2, pc);                             // else:
                genlist(n->nelse);                              //              else
-               patch(p3, pc);                          // done:
+               arch.patch(p3, pc);                             // done:
                break;
 
        case OSWITCH:
                sbreak = breakpc;
-               p1 = gjmp(P);                   //              goto test
-               breakpc = gjmp(P);              // break:       goto done
+               p1 = arch.gjmp(P);                      //              goto test
+               breakpc = arch.gjmp(P);         // break:       goto done
 
                // define break label
                if((lab = stmtlabel(n)) != L)
                        lab->breakpc = breakpc;
 
-               patch(p1, pc);                          // test:
+               arch.patch(p1, pc);                             // test:
                genlist(n->nbody);                              //              switch(test) body
-               patch(breakpc, pc);                     // done:
+               arch.patch(breakpc, pc);                        // done:
                breakpc = sbreak;
                if(lab != L)
                        lab->breakpc = P;
@@ -438,23 +438,23 @@ gen(Node *n)
 
        case OSELECT:
                sbreak = breakpc;
-               p1 = gjmp(P);                   //              goto test
-               breakpc = gjmp(P);              // break:       goto done
+               p1 = arch.gjmp(P);                      //              goto test
+               breakpc = arch.gjmp(P);         // break:       goto done
 
                // define break label
                if((lab = stmtlabel(n)) != L)
                        lab->breakpc = breakpc;
 
-               patch(p1, pc);                          // test:
+               arch.patch(p1, pc);                             // test:
                genlist(n->nbody);                              //              select() body
-               patch(breakpc, pc);                     // done:
+               arch.patch(breakpc, pc);                        // done:
                breakpc = sbreak;
                if(lab != L)
                        lab->breakpc = P;
                break;
 
        case OASOP:
-               cgen_asop(n);
+               arch.cgen_asop(n);
                break;
 
        case ODCL:
@@ -472,11 +472,11 @@ gen(Node *n)
                break;
 
        case OCALLINTER:
-               cgen_callinter(n, N, 0);
+               arch.cgen_callinter(n, N, 0);
                break;
 
        case OCALLFUNC:
-               cgen_call(n, 0);
+               arch.cgen_call(n, 0);
                break;
 
        case OPROC:
@@ -489,7 +489,7 @@ gen(Node *n)
 
        case ORETURN:
        case ORETJMP:
-               cgen_ret(n);
+               arch.cgen_ret(n);
                break;
        
        case OCHECKNIL:
@@ -502,7 +502,7 @@ gen(Node *n)
        }
 
 ret:
-       if(anyregalloc() != wasregalloc) {
+       if(arch.anyregalloc() != wasregalloc) {
                dump("node", n);
                fatal("registers left allocated");
        }
@@ -536,7 +536,7 @@ cgen_callmeth(Node *n, int proc)
 
        if(n2.left->op == ONAME)
                n2.left->class = PFUNC;
-       cgen_call(&n2, proc);
+       arch.cgen_call(&n2, proc);
 }
 
 /*
@@ -554,11 +554,11 @@ cgen_proc(Node *n, int proc)
                break;
 
        case OCALLINTER:
-               cgen_callinter(n->left, N, proc);
+               arch.cgen_callinter(n->left, N, proc);
                break;
 
        case OCALLFUNC:
-               cgen_call(n->left, proc);
+               arch.cgen_call(n->left, proc);
                break;
        }
 
@@ -601,7 +601,7 @@ cgen_discard(Node *nr)
        switch(nr->op) {
        case ONAME:
                if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
-                       gused(nr);
+                       arch.gused(nr);
                break;
 
        // unary
@@ -643,7 +643,7 @@ cgen_discard(Node *nr)
        default:
                tempname(&tmp, nr->type);
                cgen_as(&tmp, nr);
-               gused(&tmp);
+               arch.gused(&tmp);
        }
 }
 
@@ -705,7 +705,7 @@ clearslim(Node *n)
        }
 
        ullmancalc(&z);
-       cgen(&z, n);
+       arch.cgen(&z, n);
 }
 
 /*
@@ -739,10 +739,10 @@ cgen_as(Node *nl, Node *nr)
                tl = nl->type;
                if(tl == T)
                        return;
-               if(isfat(tl)) {
+               if(arch.isfat(tl)) {
                        if(nl->op == ONAME)
                                gvardef(nl);
-                       clearfat(nl);
+                       arch.clearfat(nl);
                        return;
                }
                clearslim(nl);
@@ -753,7 +753,7 @@ cgen_as(Node *nl, Node *nr)
        if(tl == T)
                return;
 
-       cgen(nr, nl);
+       arch.cgen(nr, nl);
 }
 
 /*
@@ -773,17 +773,17 @@ cgen_eface(Node *n, Node *res)
        Node *tmp;
 
        tmp = temp(types[tptr]);
-       cgen(n->right, tmp);
+       arch.cgen(n->right, tmp);
 
        gvardef(res);
 
        dst = *res;
        dst.type = types[tptr];
        dst.xoffset += widthptr;
-       cgen(tmp, &dst);
+       arch.cgen(tmp, &dst);
 
        dst.xoffset -= widthptr;
-       cgen(n->left, &dst);
+       arch.cgen(n->left, &dst);
 }
 
 /*
@@ -824,7 +824,7 @@ cgen_slice(Node *n, Node *res)
 
        if(isnil(n->left)) {
                tempname(&src, n->left->type);
-               cgen(n->left, &src);
+               arch.cgen(n->left, &src);
        } else
                src = *n->left;
        if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR)
@@ -833,11 +833,11 @@ cgen_slice(Node *n, Node *res)
        if(n->op == OSLICEARR || n->op == OSLICE3ARR) {
                if(!isptr[n->left->type->etype])
                        fatal("slicearr is supposed to work on pointer: %+N\n", n);
-               cgen(&src, base);
+               arch.cgen(&src, base);
                cgen_checknil(base);
        } else {
                src.type = types[tptr];
-               cgen(&src, base);
+               arch.cgen(&src, base);
        }
        
        // committed to the update
@@ -846,9 +846,9 @@ cgen_slice(Node *n, Node *res)
        // compute len and cap.
        // len = n-i, cap = m-i, and offs = i*width.
        // computing offs last lets the multiply overwrite i.
-       cgen(len, tmplen);
+       arch.cgen(len, tmplen);
        if(n->op != OSLICESTR)
-               cgen(cap, tmpcap);
+               arch.cgen(cap, tmpcap);
 
        // if new cap != 0 { base += add }
        // This avoids advancing base past the end of the underlying array/string,
@@ -857,40 +857,40 @@ cgen_slice(Node *n, Node *res)
        // In essence we are replacing x[i:j:k] where i == j == k
        // or x[i:j] where i == j == cap(x) with x[0:0:0].
        if(offs != N) {
-               p1 = gjmp(P);
-               p2 = gjmp(P);
-               patch(p1, pc);
+               p1 = arch.gjmp(P);
+               p2 = arch.gjmp(P);
+               arch.patch(p1, pc);
 
                nodconst(&con, tmpcap->type, 0);
                cmp = nod(OEQ, tmpcap, &con);
                typecheck(&cmp, Erv);
-               bgen(cmp, 1, -1, p2);
+               arch.bgen(cmp, 1, -1, p2);
 
                add = nod(OADD, base, offs);
                typecheck(&add, Erv);
-               cgen(add, base);
+               arch.cgen(add, base);
 
-               patch(p2, pc);
+               arch.patch(p2, pc);
        }
 
        // dst.array = src.array  [ + lo *width ]
        dst = *res;
        dst.xoffset += Array_array;
        dst.type = types[tptr];
-       cgen(base, &dst);
+       arch.cgen(base, &dst);
 
        // dst.len = hi [ - lo ]
        dst = *res;
        dst.xoffset += Array_nel;
        dst.type = types[simtype[TUINT]];
-       cgen(tmplen, &dst);
+       arch.cgen(tmplen, &dst);
 
        if(n->op != OSLICESTR) {
                // dst.cap = cap [ - lo ]
                dst = *res;
                dst.xoffset += Array_cap;
                dst.type = types[simtype[TUINT]];
-               cgen(tmpcap, &dst);
+               arch.cgen(tmpcap, &dst);
        }
 }
 
index 21cf8b894d1daae400a94629f424ab03aa5af182..2aa7838c93dcbbb038f0b1dda22f5c5e191795d5 100644 (file)
@@ -67,8 +67,6 @@ enum
        MaxStackVarSize = 10*1024*1024,
 };
 
-extern vlong   MAXWIDTH;
-
 /*
  * note this is the representation
  * of the compilers string literals,
@@ -128,10 +126,6 @@ struct     Val
                Strlit* sval;           // string CTSTR
        } u;
 };
-
-// prevent incompatible type signatures between libgc and 8g on Plan 9
-#pragma incomplete struct Array
-
 typedef        struct  Array   Array;
 typedef        struct  Bvec    Bvec;
 typedef        struct  Pkg Pkg;
@@ -141,6 +135,14 @@ typedef    struct  NodeList        NodeList;
 typedef        struct  Type    Type;
 typedef        struct  Label   Label;
 
+struct Array
+{
+       int32   length;  // number of elements
+       int32   size;  // element size
+       int32   capacity;  // size of data in elements
+       char    *data;  // element storage
+};
+
 struct Type
 {
        uchar   etype;
@@ -282,6 +284,9 @@ struct      Node
        uchar   readonly;
        uchar   implicit;
        uchar   addrtaken;      // address taken, even if not moved to heap
+       uchar   assigned;       // is the variable ever assigned to
+       uchar   captured;       // is the variable captured by a closure
+       uchar   byval;          // is the variable captured by value or by reference
        uchar   dupok;  // duplicate definitions ok (for func)
        uchar   wrapper;        // is method wrapper (for func)
        uchar   reslice;        // this is a reslice x = x[0:y] or x = append(x, ...)
@@ -315,9 +320,11 @@ struct     Node
        Node*   pack;   // real package for import . names
        Node*   curfn;  // function for local variables
        Type*   paramfld; // TFIELD for this PPARAM; also for ODOT, curfn
+       int     decldepth;      // declaration loop depth, increased for every loop or label
 
        // ONAME func param with PHEAP
        Node*   heapaddr;       // temp holding heap address of param
+       Node*   outerexpr;      // expression copied into closure for variable
        Node*   stackparam;     // OPARAM node referring to stack copy of param
        Node*   alloc;  // allocation call
 
@@ -460,6 +467,7 @@ enum
        OARRAYBYTESTRTMP, // string(bytes) ephemeral
        OARRAYRUNESTR,  // string(runes)
        OSTRARRAYBYTE,  // []byte(s)
+       OSTRARRAYBYTETMP,       // []byte(s) ephemeral
        OSTRARRAYRUNE,  // []rune(s)
        OAS,    // x = y or x := y
        OAS2,   // x, y, z = xx, yy, zz
@@ -708,8 +716,10 @@ enum
        Ecomplit = 1<<11,       // type in composite literal
 };
 
-#define        BITS    3
-#define        NVAR    (BITS*sizeof(uint64)*8)
+enum {
+       BITS = 3,
+       NVAR =  (BITS*64)
+};
 
 typedef        struct  Bits    Bits;
 struct Bits
@@ -747,8 +757,6 @@ struct      Typedef
        int     sameas;
 };
 
-extern Typedef typedefs[];
-
 typedef        struct  Sig     Sig;
 struct Sig
 {
@@ -872,6 +880,7 @@ EXTERN      Biobuf* bout;
 EXTERN int     nerrors;
 EXTERN int     nsavederrors;
 EXTERN int     nsyntaxerrors;
+EXTERN int     decldepth;
 EXTERN int     safemode;
 EXTERN int     nolocalimports;
 EXTERN char    namebuf[NSYMB];
@@ -941,7 +950,6 @@ EXTERN      Mpflt*  maxfltval[NTYPE];
 
 EXTERN NodeList*       xtop;
 EXTERN NodeList*       externdcl;
-EXTERN NodeList*       closures;
 EXTERN NodeList*       exportlist;
 EXTERN NodeList*       importlist;     // imported functions and methods with inlinable bodies
 EXTERN NodeList*       funcsyms;
@@ -969,9 +977,6 @@ EXTERN      int     widthreg;
 EXTERN Node*   typesw;
 EXTERN Node*   nblank;
 
-extern int     thechar;
-extern char*   thestring;
-extern LinkArch*       thelinkarch;
 EXTERN int     use_sse;
 
 EXTERN char*   hunk;
@@ -982,6 +987,7 @@ EXTERN      int     funcdepth;
 EXTERN int     typecheckok;
 EXTERN int     compiling_runtime;
 EXTERN int     compiling_wrappers;
+EXTERN int     inl_nonlocal;
 EXTERN int     use_writebarrier;
 EXTERN int     pure_go;
 EXTERN char*   flag_installsuffix;
@@ -994,8 +1000,6 @@ EXTERN     int     debuglive;
 EXTERN Link*   ctxt;
 
 EXTERN int     nointerface;
-EXTERN int     fieldtrack_enabled;
-EXTERN int     precisestack_enabled;
 EXTERN int     writearchive;
 
 EXTERN Biobuf  bstdout;
@@ -1070,6 +1074,7 @@ void      bvset(Bvec *bv, int32 i);
 Node*  closurebody(NodeList *body);
 void   closurehdr(Node *ntype);
 void   typecheckclosure(Node *func, int top);
+void   capturevars(Node *func);
 Node*  walkclosure(Node *func, NodeList **init);
 void   typecheckpartialcall(Node*, Node*);
 Node*  walkpartialcall(Node*, NodeList**);
@@ -1288,7 +1293,6 @@ int       duint32(Sym *s, int off, uint32 v);
 int    duint64(Sym *s, int off, uint64 v);
 int    duint8(Sym *s, int off, uint8 v);
 int    duintptr(Sym *s, int off, uint64 v);
-int    dsname(Sym *s, int off, char *dat, int ndat);
 void   dumpobj(void);
 Sym*   stringsym(char*, int);
 void   slicebytes(Node*, char*, int);
@@ -1425,7 +1429,7 @@ int       simsimtype(Type *t);
 void   smagic(Magic *m);
 Type*  sortinter(Type *t);
 uint32 stringhash(char *p);
-Strlit*        strlit(char *s);
+Strlit*        newstrlit(char *s);
 int    structcount(Type *t);
 Type*  structfirst(Iter *s, Type **nn);
 Type*  structnext(Iter *s);
@@ -1457,6 +1461,7 @@ void      typechecklist(NodeList *l, int top);
 Node*  typecheckdef(Node *n);
 void   copytype(Node *n, Type *t);
 void   checkreturn(Node*);
+void   checkassign(Node *stmt, Node*);
 void   queuemethod(Node *n);
 
 /*
@@ -1500,47 +1505,16 @@ EXTERN  Node*   nodfp;
 EXTERN int     disable_checknil;
 EXTERN vlong   zerosize;
 
-int    anyregalloc(void);
-void   betypeinit(void);
-void   bgen(Node *n, int true, int likely, Prog *to);
 void   checknil(Node*, NodeList**);
-void   expandchecks(Prog*);
-void   cgen(Node*, Node*);
-void   cgen_asop(Node *n);
-void   cgen_call(Node *n, int proc);
-void   cgen_callinter(Node *n, Node *res, int proc);
 void   cgen_checknil(Node*);
-void   cgen_ret(Node *n);
-void   clearfat(Node *n);
 void   compile(Node*);
-void   defframe(Prog*);
-int    dgostringptr(Sym*, int off, char *str);
-int    dgostrlitptr(Sym*, int off, Strlit*);
-int    dstringptr(Sym *s, int off, char *str);
-int    dsymptr(Sym *s, int off, Sym *x, int xoff);
 int    duintxx(Sym *s, int off, uint64 v, int wid);
-void   dumpdata(void);
-void   fixautoused(Prog*);
-void   gdata(Node*, Node*, int);
-void   gdatacomplex(Node*, Mpcplx*);
-void   gdatastring(Node*, Strlit*);
-void   ggloblnod(Node *nam);
-void   ggloblsym(Sym *s, int32 width, int8 flags);
 void   gvardef(Node*);
 void   gvarkill(Node*);
-Prog*  gjmp(Prog*);
-void   gused(Node*);
 void   movelarge(NodeList*);
-int    isfat(Type*);
-void   linkarchinit(void);
 void   liveness(Node*, Prog*, Sym*, Sym*);
 void   twobitwalktype1(Type*, vlong*, Bvec*);
-void   markautoused(Prog*);
-Plist* newplist(void);
-Node*  nodarg(Type*, int);
 void   nopout(Prog*);
-void   patch(Prog*, Prog*);
-Prog*  unpatch(Prog*);
 
 #pragma        varargck        type    "B"     Mpint*
 #pragma        varargck        type    "E"     int
@@ -1566,3 +1540,186 @@ Prog*   unpatch(Prog*);
  *     racewalk.c
  */
 void   racewalk(Node *fn);
+
+/*
+ *     flow.c
+ */
+typedef struct Flow Flow;
+typedef struct Graph Graph;
+
+struct Flow {
+       Prog*   prog;           // actual instruction
+       Flow*   p1;             // predecessors of this instruction: p1,
+       Flow*   p2;             // and then p2 linked though p2link.
+       Flow*   p2link;
+       Flow*   s1;             // successors of this instruction (at most two: s1 and s2).
+       Flow*   s2;
+       Flow*   link;           // next instruction in function code
+       
+       int32   active; // usable by client
+
+       int32   rpo;            // reverse post ordering
+       uint16  loop;           // x5 for every loop
+       uchar   refset;         // diagnostic generated
+};
+
+struct Graph
+{
+       Flow*   start;
+       int     num;
+       
+       // After calling flowrpo, rpo lists the flow nodes in reverse postorder,
+       // and each non-dead Flow node f has g->rpo[f->rpo] == f.
+       Flow**  rpo;
+};
+
+void   fixjmp(Prog*);
+Graph* flowstart(Prog*, int);
+void   flowrpo(Graph*);
+void   flowend(Graph*);
+void   mergetemp(Prog*);
+void   nilopt(Prog*);
+int    noreturn(Prog*);
+Flow*  uniqp(Flow*);
+Flow*  uniqs(Flow*);
+
+/*
+ *     interface to back end
+ */
+
+typedef struct ProgInfo ProgInfo;
+struct ProgInfo
+{
+       uint32 flags; // the bits below
+       uint64 reguse; // registers implicitly used by this instruction
+       uint64 regset; // registers implicitly set by this instruction
+       uint64 regindex; // registers used by addressing mode
+};
+
+enum
+{
+       // Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
+       Pseudo = 1<<1,
+       
+       // There's nothing to say about the instruction,
+       // but it's still okay to see.
+       OK = 1<<2,
+
+       // Size of right-side write, or right-side read if no write.
+       SizeB = 1<<3,
+       SizeW = 1<<4,
+       SizeL = 1<<5,
+       SizeQ = 1<<6,
+       SizeF = 1<<7, // float aka float32
+       SizeD = 1<<8, // double aka float64
+
+       // Left side (Prog.from): address taken, read, write.
+       LeftAddr = 1<<9,
+       LeftRead = 1<<10,
+       LeftWrite = 1<<11,
+       
+       // Register in middle (Prog.reg); only ever read. (arm, ppc64)
+       RegRead = 1<<12,
+       CanRegRead = 1<<13,
+       
+       // Right side (Prog.to): address taken, read, write.
+       RightAddr = 1<<14,
+       RightRead = 1<<15,
+       RightWrite = 1<<16,
+
+       // Instruction kinds
+       Move = 1<<17, // straight move
+       Conv = 1<<18, // size conversion
+       Cjmp = 1<<19, // conditional jump
+       Break = 1<<20, // breaks control flow (no fallthrough)
+       Call = 1<<21, // function call
+       Jump = 1<<22, // jump
+       Skip = 1<<23, // data instruction
+
+       // Set, use, or kill of carry bit.
+       // Kill means we never look at the carry bit after this kind of instruction.
+       SetCarry = 1<<24,
+       UseCarry = 1<<25,
+       KillCarry = 1<<26,
+
+       // Special cases for register use. (amd64, 386)
+       ShiftCX = 1<<27, // possible shift by CX
+       ImulAXDX = 1<<28, // possible multiply into DX:AX
+
+       // Instruction updates whichever of from/to is type D_OREG. (ppc64)
+       PostInc = 1<<29,
+};
+
+typedef struct Arch Arch;
+
+struct Arch
+{
+       int thechar;
+       char *thestring;
+       LinkArch *thelinkarch;
+       Typedef *typedefs;
+
+       vlong MAXWIDTH;
+
+       void (*afunclit)(Addr*, Node*);
+       int (*anyregalloc)(void);
+       void (*betypeinit)(void);
+       void (*bgen)(Node*, int, int, Prog*);
+       void (*cgen)(Node*, Node*);
+       void (*cgen_asop)(Node*);
+       void (*cgen_call)(Node*, int);
+       void (*cgen_callinter)(Node*, Node*, int);
+       void (*cgen_ret)(Node*);
+       void (*clearfat)(Node*);
+       void (*clearp)(Prog*);
+       void (*defframe)(Prog*);
+       int (*dgostringptr)(Sym*, int, char*);
+       int (*dgostrlitptr)(Sym*, int, Strlit*);
+       int (*dsname)(Sym*, int, char*, int);
+       int (*dsymptr)(Sym*, int, Sym*, int);
+       void (*dumpdata)(void);
+       void (*dumpit)(char*, Flow*, int);
+       void (*excise)(Flow*);
+       void (*expandchecks)(Prog*);
+       void (*fixautoused)(Prog*);
+       void (*gclean)(void);
+       void    (*gdata)(Node*, Node*, int);
+       void    (*gdatacomplex)(Node*, Mpcplx*);
+       void    (*gdatastring)(Node*, Strlit*);
+       void    (*ggloblnod)(Node*);
+       void    (*ggloblsym)(Sym*, int32, int8);
+       void (*ginit)(void);
+       Prog*   (*gins)(int, Node*, Node*);
+       void    (*ginscall)(Node*, int);
+       Prog*   (*gjmp)(Prog*);
+       void (*gtrack)(Sym*);
+       void    (*gused)(Node*);
+       void    (*igen)(Node*, Node*, Node*);
+       int (*isfat)(Type*);
+       void (*linkarchinit)(void);
+       void (*markautoused)(Prog*);
+       void (*naddr)(Node*, Addr*, int);
+       Plist* (*newplist)(void);
+       Node* (*nodarg)(Type*, int);
+       void (*patch)(Prog*, Prog*);
+       void (*proginfo)(ProgInfo*, Prog*);
+       void (*regalloc)(Node*, Type*, Node*);
+       void (*regfree)(Node*);
+       void (*regopt)(Prog*);
+       int (*regtyp)(Addr*);
+       int (*sameaddr)(Addr*, Addr*);
+       int (*smallindir)(Addr*, Addr*);
+       int (*stackaddr)(Addr*);
+       Prog* (*unpatch)(Prog*);
+};
+
+EXTERN Arch arch;
+
+EXTERN Node *newproc;
+EXTERN Node *deferproc;
+EXTERN Node *deferreturn;
+EXTERN Node *panicindex;
+EXTERN Node *panicslice;
+EXTERN Node *throwreturn;
+
+int    gcmain(int, char**);
index cf89b00902804fa301a0e810a44b2d9253f4c029..45e15bb9b7c92114c117994a3c5e23bec8f9482f 100644 (file)
@@ -804,9 +804,12 @@ inlvar(Node *var)
        n->curfn = curfn;   // the calling function, not the called one
        n->addrtaken = var->addrtaken;
 
-       // esc pass wont run if we're inlining into a iface wrapper
-       // luckily, we can steal the results from the target func
-       if(var->esc == EscHeap)
+       // Esc pass wont run if we're inlining into a iface wrapper.
+       // Luckily, we can steal the results from the target func.
+       // If inlining a function defined in another package after
+       // escape analysis is done, treat all local vars as escaping.
+       // See issue 9537.
+       if(var->esc == EscHeap || (inl_nonlocal && var->op == ONAME))
                addrescapes(n);
 
        curfn->dcl = list(curfn->dcl, n);
index 006ded20e872937cfa87bdce35c11f259772adea..042099bd5e75e9ae3ed243bdd4c0ade1b702430e 100644 (file)
@@ -8,6 +8,10 @@
 #include       "y.tab.h"
 #include       <ar.h>
 
+#ifndef PLAN9
+#include       <signal.h>
+#endif
+
 #undef getc
 #undef ungetc
 #define        getc    ccgetc
@@ -33,19 +37,6 @@ static char *goos, *goarch, *goroot;
 
 #define        BOM     0xFEFF
 
-// Compiler experiments.
-// These are controlled by the GOEXPERIMENT environment
-// variable recorded when the compiler is built.
-static struct {
-       char *name;
-       int *val;
-} exper[] = {
-//     {"rune32", &rune32},
-       {"fieldtrack", &fieldtrack_enabled},
-       {"precisestack", &precisestack_enabled},
-       {nil, nil},
-};
-
 // Debug arguments.
 // These can be specified with the -d flag, as in "-d nil"
 // to set the debug_checknil variable. In general the list passed
@@ -55,55 +46,8 @@ static struct {
        int *val;
 } debugtab[] = {
        {"nil", &debug_checknil},
-       {nil, nil},
 };
 
-static void
-addexp(char *s)
-{
-       int i;
-
-       for(i=0; exper[i].name != nil; i++) {
-               if(strcmp(exper[i].name, s) == 0) {
-                       *exper[i].val = 1;
-                       return;
-               }
-       }
-       
-       print("unknown experiment %s\n", s);
-       exits("unknown experiment");
-}
-
-static void
-setexp(void)
-{
-       char *f[20];
-       int i, nf;
-
-       precisestack_enabled = 1; // on by default
-
-       // cmd/dist #defines GOEXPERIMENT for us.
-       nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
-       for(i=0; i<nf; i++)
-               addexp(f[i]);
-}
-
-char*
-expstring(void)
-{
-       int i;
-       static char buf[512];
-
-       strcpy(buf, "X");
-       for(i=0; exper[i].name != nil; i++)
-               if(*exper[i].val)
-                       seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
-       if(strlen(buf) == 1)
-               strcpy(buf, "X,none");
-       buf[1] = ':';
-       return buf;
-}
-
 // Our own isdigit, isspace, isalpha, isalnum that take care 
 // of EOF and other out of range arguments.
 static int
@@ -151,7 +95,7 @@ enum
 void
 usage(void)
 {
-       print("usage: %cg [options] file.go...\n", thechar);
+       print("usage: %cg [options] file.go...\n", arch.thechar);
        flagprint(1);
        exits("usage");
 }
@@ -188,22 +132,25 @@ catcher(void *v, char *s)
 void
 doversion(void)
 {
-       char *p;
+       char *p, *sep;
 
        p = expstring();
        if(strcmp(p, "X:none") == 0)
                p = "";
-       print("%cg version %s%s%s\n", thechar, getgoversion(), *p ? " " : "", p);
+       sep = "";
+       if(*p)
+               sep = " ";
+       print("%cg version %s%s%s\n", arch.thechar, getgoversion(), sep, p);
        exits(0);
 }
 
 int
-main(int argc, char *argv[])
+gcmain(int argc, char *argv[])
 {
        int i;
        NodeList *l;
        char *p;
-
+       
 #ifdef SIGBUS  
        signal(SIGBUS, fault);
        signal(SIGSEGV, fault);
@@ -214,55 +161,55 @@ main(int argc, char *argv[])
        // Tell the FPU to handle all exceptions.
        setfcr(FPPDBL|FPRNR);
 #endif
-       // Allow GOARCH=thestring or GOARCH=thestringsuffix,
+       // Allow GOARCH=arch.thestring or GOARCH=arch.thestringsuffix,
        // but not other values.        
        p = getgoarch();
-       if(strncmp(p, thestring, strlen(thestring)) != 0)
-               sysfatal("cannot use %cg with GOARCH=%s", thechar, p);
+       if(strncmp(p, arch.thestring, strlen(arch.thestring)) != 0)
+               sysfatal("cannot use %cg with GOARCH=%s", arch.thechar, p);
        goarch = p;
 
-       linkarchinit();
-       ctxt = linknew(thelinkarch);
+       arch.linkarchinit();
+       ctxt = linknew(arch.thelinkarch);
        ctxt->diag = yyerror;
        ctxt->bso = &bstdout;
        Binit(&bstdout, 1, OWRITE);
 
-       localpkg = mkpkg(strlit(""));
+       localpkg = mkpkg(newstrlit(""));
        localpkg->prefix = "\"\"";
        
        // pseudo-package, for scoping
-       builtinpkg = mkpkg(strlit("go.builtin"));
+       builtinpkg = mkpkg(newstrlit("go.builtin"));
 
        // pseudo-package, accessed by import "unsafe"
-       unsafepkg = mkpkg(strlit("unsafe"));
+       unsafepkg = mkpkg(newstrlit("unsafe"));
        unsafepkg->name = "unsafe";
 
        // real package, referred to by generated runtime calls
-       runtimepkg = mkpkg(strlit("runtime"));
+       runtimepkg = mkpkg(newstrlit("runtime"));
        runtimepkg->name = "runtime";
 
        // pseudo-packages used in symbol tables
-       gostringpkg = mkpkg(strlit("go.string"));
+       gostringpkg = mkpkg(newstrlit("go.string"));
        gostringpkg->name = "go.string";
        gostringpkg->prefix = "go.string";      // not go%2estring
 
-       itabpkg = mkpkg(strlit("go.itab"));
+       itabpkg = mkpkg(newstrlit("go.itab"));
        itabpkg->name = "go.itab";
        itabpkg->prefix = "go.itab";    // not go%2eitab
 
-       weaktypepkg = mkpkg(strlit("go.weak.type"));
+       weaktypepkg = mkpkg(newstrlit("go.weak.type"));
        weaktypepkg->name = "go.weak.type";
        weaktypepkg->prefix = "go.weak.type";  // not go%2eweak%2etype
        
-       typelinkpkg = mkpkg(strlit("go.typelink"));
+       typelinkpkg = mkpkg(newstrlit("go.typelink"));
        typelinkpkg->name = "go.typelink";
        typelinkpkg->prefix = "go.typelink"; // not go%2etypelink
 
-       trackpkg = mkpkg(strlit("go.track"));
+       trackpkg = mkpkg(newstrlit("go.track"));
        trackpkg->name = "go.track";
        trackpkg->prefix = "go.track";  // not go%2etrack
 
-       typepkg = mkpkg(strlit("type"));
+       typepkg = mkpkg(newstrlit("type"));
        typepkg->name = "type";
 
        goroot = getgoroot();
@@ -272,8 +219,6 @@ main(int argc, char *argv[])
        if(nacl)
                flag_largemodel = 1;
 
-       setexp();
-       
        fmtstrinit(&pragcgobuf);
        quotefmtinstall();
 
@@ -322,7 +267,7 @@ main(int argc, char *argv[])
        flagcount("wb", "enable write barrier", &use_writebarrier);
        flagcount("x", "debug lexer", &debug['x']);
        flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']);
-       if(thechar == '6')
+       if(arch.thechar == '6')
                flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
 
        flagparse(&argc, &argv, usage);
@@ -333,7 +278,7 @@ main(int argc, char *argv[])
                usage();
 
        if(flag_race) {
-               racepkg = mkpkg(strlit("runtime/race"));
+               racepkg = mkpkg(newstrlit("runtime/race"));
                racepkg->name = "race";
        }
        
@@ -344,13 +289,14 @@ main(int argc, char *argv[])
                
                nf = getfields(debugstr, f, nelem(f), 1, ",");
                for(i=0; i<nf; i++) {
-                       for(j=0; debugtab[j].name != nil; j++) {
+                       for(j=0; j<nelem(debugtab); j++) {
                                if(strcmp(debugtab[j].name, f[i]) == 0) {
-                                       *debugtab[j].val = 1;
+                                       if(debugtab[j].val != nil)
+                                               *debugtab[j].val = 1;
                                        break;
                                }
                        }
-                       if(debugtab[j].name == nil)
+                       if(j >= nelem(debugtab))
                                sysfatal("unknown debug information -d '%s'\n", f[i]);
                }
        }
@@ -362,7 +308,7 @@ main(int argc, char *argv[])
        if(debug['l'] <= 1)
                debug['l'] = 1 - debug['l'];
 
-       if(thechar == '8') {
+       if(arch.thechar == '8') {
                p = getgo386();
                if(strcmp(p, "387") == 0)
                        use_sse = 0;
@@ -373,7 +319,7 @@ main(int argc, char *argv[])
        }
 
        fmtinstallgo();
-       betypeinit();
+       arch.betypeinit();
        if(widthptr == 0)
                fatal("betypeinit failed");
 
@@ -449,6 +395,7 @@ main(int argc, char *argv[])
        for(l=xtop; l; l=l->next) {
                if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) {
                        curfn = l->n;
+                       decldepth = 1;
                        saveerrors();
                        typechecklist(l->n->nbody, Etop);
                        checkreturn(l->n);
@@ -457,12 +404,21 @@ main(int argc, char *argv[])
                }
        }
 
+       // Phase 4: Decide how to capture variables
+       // and transform closure bodies accordingly.
+       for(l=xtop; l; l=l->next) {
+               if(l->n->op == ODCLFUNC && l->n->closure) {
+                       curfn = l->n;
+                       capturevars(l->n);
+               }
+       }
+
        curfn = nil;
        
        if(nsavederrors+nerrors)
                errorexit();
 
-       // Phase 4: Inlining
+       // Phase 5: Inlining
        if(debug['l'] > 1) {
                // Typecheck imported function bodies if debug['l'] > 1,
                // otherwise lazily when used or re-exported.
@@ -488,7 +444,7 @@ main(int argc, char *argv[])
                                inlcalls(l->n);
        }
 
-       // Phase 5: Escape analysis.
+       // Phase 6: Escape analysis.
        // Required for moving heap allocations onto stack,
        // which in turn is required by the closure implementation,
        // which stores the addresses of stack variables into the closure.
@@ -500,7 +456,7 @@ main(int argc, char *argv[])
        // Move large values off stack too.
        movelarge(xtop);
 
-       // Phase 6: Compile top level functions.
+       // Phase 7: Compile top level functions.
        for(l=xtop; l; l=l->next)
                if(l->n->op == ODCLFUNC)
                        funccompile(l->n, 0);
@@ -508,7 +464,7 @@ main(int argc, char *argv[])
        if(nsavederrors+nerrors == 0)
                fninit(xtop);
 
-       // Phase 7: Check external declarations.
+       // Phase 8: Check external declarations.
        for(l=externdcl; l; l=l->next)
                if(l->n->op == ONAME)
                        typecheck(&l->n, Erv);
@@ -632,7 +588,7 @@ findpkg(Strlit *name)
                snprint(namebuf, sizeof(namebuf), "%Z.a", name);
                if(access(namebuf, 0) >= 0)
                        return 1;
-               snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thechar);
+               snprint(namebuf, sizeof(namebuf), "%Z.%c", name, arch.thechar);
                if(access(namebuf, 0) >= 0)
                        return 1;
                return 0;
@@ -654,7 +610,7 @@ findpkg(Strlit *name)
                snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
                if(access(namebuf, 0) >= 0)
                        return 1;
-               snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thechar);
+               snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, arch.thechar);
                if(access(namebuf, 0) >= 0)
                        return 1;
        }
@@ -671,7 +627,7 @@ findpkg(Strlit *name)
                snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.a", goroot, goos, goarch, suffixsep, suffix, name);
                if(access(namebuf, 0) >= 0)
                        return 1;
-               snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.%c", goroot, goos, goarch, suffixsep, suffix, name, thechar);
+               snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.%c", goroot, goos, goarch, suffixsep, suffix, name, arch.thechar);
                if(access(namebuf, 0) >= 0)
                        return 1;
        }
@@ -681,7 +637,7 @@ findpkg(Strlit *name)
 static void
 fakeimport(void)
 {
-       importpkg = mkpkg(strlit("fake"));
+       importpkg = mkpkg(newstrlit("fake"));
        cannedimports("fake.6", "$$\n");
 }
 
@@ -754,7 +710,7 @@ importfile(Val *f, int line)
                strcat(cleanbuf, "/");
                strcat(cleanbuf, path->s);
                cleanname(cleanbuf);
-               path = strlit(cleanbuf);
+               path = newstrlit(cleanbuf);
                
                if(isbadimport(path)) {
                        fakeimport();
@@ -1323,7 +1279,7 @@ talph:
                if(c >= Runeself) {
                        ungetc(c);
                        rune = getr();
-                       // 0xb7 Â· is used for internal names
+                       // 0xb7 Ã‚· is used for internal names
                        if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
                                yyerror("invalid identifier character U+%04x", rune);
                        cp += runetochar(cp, &rune);
@@ -2314,10 +2270,10 @@ lexfini(void)
        }
 
        // backend-specific builtin types (e.g. int).
-       for(i=0; typedefs[i].name; i++) {
-               s = lookup(typedefs[i].name);
+       for(i=0; arch.typedefs[i].name; i++) {
+               s = lookup(arch.typedefs[i].name);
                if(s->def == N) {
-                       s->def = typenod(types[typedefs[i].etype]);
+                       s->def = typenod(types[arch.typedefs[i].etype]);
                        s->origpkg = builtinpkg;
                }
        }
@@ -2615,6 +2571,6 @@ mkpackage(char* pkgname)
                p = strrchr(namebuf, '.');
                if(p != nil)
                        *p = 0;
-               outfile = smprint("%s.%c", namebuf, thechar);
+               outfile = smprint("%s.%c", namebuf, arch.thechar);
        }
 }
index 7e4e97854a8748e8c40c56daed1f9abffb42bd97..a4d470615a67d87fc1f0dfe859e86ad927648aa0 100644 (file)
@@ -95,9 +95,9 @@ dumpobj(void)
        externdcl = tmp;
 
        zero = pkglookup("zerovalue", runtimepkg);
-       ggloblsym(zero, zerosize, DUPOK|RODATA);
+       arch.ggloblsym(zero, zerosize, DUPOK|RODATA);
 
-       dumpdata();
+       arch.dumpdata();
        writeobj(ctxt, bout);
 
        if(writearchive) {
@@ -106,7 +106,7 @@ dumpobj(void)
                if(size&1)
                        Bputc(bout, 0);
                Bseek(bout, startobj - ArhdrSize, 0);
-               snprint(namebuf, sizeof namebuf, "_go_.%c", thechar);
+               snprint(namebuf, sizeof namebuf, "_go_.%c", arch.thechar);
                formathdr(arhdr, namebuf, size);
                Bwrite(bout, arhdr, ArhdrSize);
        }
@@ -133,13 +133,13 @@ dumpglobls(void)
                        continue;
                dowidth(n->type);
 
-               ggloblnod(n);
+               arch.ggloblnod(n);
        }
        
        for(l=funcsyms; l; l=l->next) {
                n = l->n;
-               dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
-               ggloblsym(n->sym, widthptr, DUPOK|RODATA);
+               arch.dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
+               arch.ggloblsym(n->sym, widthptr, DUPOK|RODATA);
        }
        
        // Do not reprocess funcsyms on next dumpglobls call.
@@ -250,7 +250,7 @@ stringsym(char *s, int len)
        off = 0;
        
        // string header
-       off = dsymptr(sym, off, sym, widthptr+widthint);
+       off = arch.dsymptr(sym, off, sym, widthptr+widthint);
        off = duintxx(sym, off, len, widthint);
        
        // string data
@@ -258,11 +258,11 @@ stringsym(char *s, int len)
                m = 8;
                if(m > len-n)
                        m = len-n;
-               off = dsname(sym, off, s+n, m);
+               off = arch.dsname(sym, off, s+n, m);
        }
        off = duint8(sym, off, 0);  // terminating NUL for runtime
        off = (off+widthptr-1)&~(widthptr-1);  // round to pointer alignment
-       ggloblsym(sym, off, DUPOK|RODATA);
+       arch.ggloblsym(sym, off, DUPOK|RODATA);
 
        return sym;     
 }
@@ -283,14 +283,14 @@ slicebytes(Node *nam, char *s, int len)
                m = 8;
                if(m > len-n)
                        m = len-n;
-               off = dsname(sym, off, s+n, m);
+               off = arch.dsname(sym, off, s+n, m);
        }
-       ggloblsym(sym, off, NOPTR);
+       arch.ggloblsym(sym, off, NOPTR);
        
        if(nam->op != ONAME)
                fatal("slicebytes %N", nam);
        off = nam->xoffset;
-       off = dsymptr(nam->sym, off, sym, 0);
+       off = arch.dsymptr(nam->sym, off, sym, 0);
        off = duintxx(nam->sym, off, len, widthint);
        duintxx(nam->sym, off, len, widthint);
 }
index a1aa1bd300cc33fcd99add5de23a4c300d240ffd..255c94a804961c1ec95b0f668270bd2579359561 100644 (file)
@@ -58,6 +58,13 @@ static void  orderexprlistinplace(NodeList*, Order*);
 void
 order(Node *fn)
 {
+       char s[50];
+
+       if(debug['W'] > 1) {
+               snprint(s, sizeof(s), "\nbefore order %S", fn->nname->sym);
+               dumplist(s, fn->nbody);
+       }
+
        orderblock(&fn->nbody);
 }
 
@@ -750,6 +757,10 @@ orderstmt(Node *n, Order *order)
                default:
                        fatal("orderstmt range %T", n->type);
                case TARRAY:
+                       // Mark []byte(str) range expression to reuse string backing storage.
+                       // It is safe because the storage cannot be mutated.
+                       if(n->right->op == OSTRARRAYBYTE)
+                               n->right->op = OSTRARRAYBYTETMP;
                        if(count(n->list) < 2 || isblank(n->list->next->n)) {
                                // for i := range x will only use x once, to compute len(x).
                                // No need to copy it.
@@ -974,7 +985,7 @@ orderexpr(Node **np, Order *order)
        Node *n;
        NodeList *mark, *l;
        Type *t;
-       int lno;
+       int lno, haslit, hasbyte;
 
        n = *np;
        if(n == N)
@@ -1002,6 +1013,38 @@ orderexpr(Node **np, Order *order)
                        t->type = types[TSTRING];
                        n->alloc = ordertemp(t, order, 0);
                }
+
+               // Mark string(byteSlice) arguments to reuse byteSlice backing
+               // buffer during conversion. String concatenation does not
+               // memorize the strings for later use, so it is safe.
+               // However, we can do it only if there is at least one non-empty string literal.
+               // Otherwise if all other arguments are empty strings,
+               // concatstrings will return the reference to the temp string
+               // to the caller.
+               hasbyte = 0;
+               haslit = 0;
+               for(l=n->list; l != nil; l=l->next) {
+                       hasbyte |= l->n->op == OARRAYBYTESTR;
+                       haslit |= l->n->op == OLITERAL && l->n->val.u.sval->len != 0;
+               }
+               if(haslit && hasbyte) {
+                       for(l=n->list; l != nil; l=l->next) {
+                               if(l->n->op == OARRAYBYTESTR)
+                                       l->n->op = OARRAYBYTESTRTMP;
+                       }
+               }
+               break;
+
+       case OCMPSTR:
+               orderexpr(&n->left, order);
+               orderexpr(&n->right, order);
+               // Mark string(byteSlice) arguments to reuse byteSlice backing
+               // buffer during conversion. String comparison does not
+               // memorize the strings for later use, so it is safe.
+               if(n->left->op == OARRAYBYTESTR)
+                       n->left->op = OARRAYBYTESTRTMP;
+               if(n->right->op == OARRAYBYTESTR)
+                       n->right->op = OARRAYBYTESTRTMP;
                break;
 
        case OINDEXMAP:
index 259cec85a31531b6bafb04b1348466113b0bb67f..ec1628651e501c085c60296b0f9fb714c7a8e74c 100644 (file)
@@ -9,9 +9,10 @@
 #include       <u.h>
 #include       <libc.h>
 #include       "md5.h"
-#include       "gg.h"
-#include       "opt.h"
+#include       "go.h"
+//#include     "opt.h"
 #include       "../../runtime/funcdata.h"
+#include       "../ld/textflag.h"
 
 static void allocauto(Prog* p);
 static void emitptrargsmap(void);
@@ -29,7 +30,7 @@ makefuncdatasym(char *namefmt, int64 funcdatakind)
        pnod = newname(sym);
        pnod->class = PEXTERN;
        nodconst(&nod, types[TINT32], funcdatakind);
-       gins(AFUNCDATA, &nod, pnod);
+       arch.gins(AFUNCDATA, &nod, pnod);
        return sym;
 }
 
@@ -38,7 +39,7 @@ makefuncdatasym(char *namefmt, int64 funcdatakind)
 // where a complete initialization (definition) of a variable begins.
 // Since the liveness analysis can see initialization of single-word
 // variables quite easy, gvardef is usually only called for multi-word
-// or 'fat' variables, those satisfying isfat(n->type).
+// or 'fat' variables, those satisfying arch.isfat(n->type).
 // However, gvardef is also called when a non-fat variable is initialized
 // via a block move; the only time this happens is when you have
 //     return f()
@@ -102,7 +103,7 @@ gvardefx(Node *n, int as)
        case PAUTO:
        case PPARAM:
        case PPARAMOUT:
-               gins(as, N, n);
+               arch.gins(as, N, n);
        }
 }
 
@@ -126,7 +127,7 @@ removevardef(Prog *firstp)
        for(p = firstp; p != P; p = p->link) {
                while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL))
                        p->link = p->link->link;
-               if(p->to.type == D_BRANCH)
+               if(p->to.type == TYPE_BRANCH)
                        while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL))
                                p->to.u.branch = p->to.u.branch->link;
        }
@@ -222,39 +223,39 @@ compile(Node *fn)
        continpc = P;
        breakpc = P;
 
-       pl = newplist();
+       pl = arch.newplist();
        pl->name = linksym(curfn->nname->sym);
 
        setlineno(curfn);
 
        nodconst(&nod1, types[TINT32], 0);
-       ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
+       ptxt = arch.gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
        if(fn->dupok)
-               ptxt->TEXTFLAG |= DUPOK;
+               ptxt->from3.offset |= DUPOK;
        if(fn->wrapper)
-               ptxt->TEXTFLAG |= WRAPPER;
+               ptxt->from3.offset |= WRAPPER;
        if(fn->needctxt)
-               ptxt->TEXTFLAG |= NEEDCTXT;
+               ptxt->from3.offset |= NEEDCTXT;
        if(fn->nosplit)
-               ptxt->TEXTFLAG |= NOSPLIT;
+               ptxt->from3.offset |= NOSPLIT;
 
        // Clumsy but important.
        // See test/recover.go for test cases and src/reflect/value.go
        // for the actual functions being considered.
        if(myimportpath != nil && strcmp(myimportpath, "reflect") == 0) {
                if(strcmp(curfn->nname->sym->name, "callReflect") == 0 || strcmp(curfn->nname->sym->name, "callMethod") == 0)
-                       ptxt->TEXTFLAG |= WRAPPER;
+                       ptxt->from3.offset |= WRAPPER;
        }       
        
-       afunclit(&ptxt->from, curfn->nname);
+       arch.afunclit(&ptxt->from, curfn->nname);
 
-       ginit();
+       arch.ginit();
 
        gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
        gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
 
        for(t=curfn->paramfld; t; t=t->down)
-               gtrack(tracksym(t->type));
+               arch.gtrack(tracksym(t->type));
 
        for(l=fn->dcl; l; l=l->next) {
                n = l->n;
@@ -265,7 +266,7 @@ compile(Node *fn)
                case PPARAM:
                case PPARAMOUT:
                        nodconst(&nod1, types[TUINTPTR], l->n->type->width);
-                       p = gins(ATYPE, l->n, &nod1);
+                       p = arch.gins(ATYPE, l->n, &nod1);
                        p->from.gotype = linksym(ngotype(l->n));
                        break;
                }
@@ -273,7 +274,7 @@ compile(Node *fn)
 
        genlist(curfn->enter);
        genlist(curfn->nbody);
-       gclean();
+       arch.gclean();
        checklabels();
        if(nerrors != 0)
                goto ret;
@@ -281,18 +282,18 @@ compile(Node *fn)
                lineno = curfn->endlineno;
 
        if(curfn->type->outtuple != 0)
-               ginscall(throwreturn, 0);
+               arch.ginscall(throwreturn, 0);
 
-       ginit();
+       arch.ginit();
        // TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
-       cgen_ret(nil);
+       arch.cgen_ret(nil);
        if(hasdefer) {
                // deferreturn pretends to have one uintptr argument.
                // Reserve space for it so stack scanner is happy.
                if(maxarg < widthptr)
                        maxarg = widthptr;
        }
-       gclean();
+       arch.gclean();
        if(nerrors != 0)
                goto ret;
 
@@ -301,10 +302,10 @@ compile(Node *fn)
 
        fixjmp(ptxt);
        if(!debug['N'] || debug['R'] || debug['P']) {
-               regopt(ptxt);
+               arch.regopt(ptxt);
                nilopt(ptxt);
        }
-       expandchecks(ptxt);
+       arch.expandchecks(ptxt);
 
        oldstksize = stksize;
        allocauto(ptxt);
@@ -324,7 +325,7 @@ compile(Node *fn)
        gcsymdup(gcargs);
        gcsymdup(gclocals);
 
-       defframe(ptxt);
+       arch.defframe(ptxt);
 
        if(0)
                frame(0);
@@ -368,7 +369,7 @@ emitptrargsmap(void)
                for(j = 0; j < bv->n; j += 32)
                        off = duint32(sym, off, bv->b[j/32]);
        }
-       ggloblsym(sym, off, RODATA);
+       arch.ggloblsym(sym, off, RODATA);
        free(bv);
 }
 
@@ -385,8 +386,11 @@ cmpstackvar(Node *a, Node *b)
 {
        int ap, bp;
 
-       if (a->class != b->class)
-               return (a->class == PAUTO) ? +1 : -1;
+       if (a->class != b->class) {
+               if(a->class == PAUTO)
+                       return +1;
+               return -1;
+       }
        if (a->class != PAUTO) {
                if (a->xoffset < b->xoffset)
                        return -1;
@@ -434,7 +438,7 @@ allocauto(Prog* ptxt)
                if (ll->n->class == PAUTO)
                        ll->n->used = 0;
 
-       markautoused(ptxt);
+       arch.markautoused(ptxt);
 
        listsort(&curfn->dcl, cmpstackvar);
 
@@ -444,7 +448,7 @@ allocauto(Prog* ptxt)
        if (n->class == PAUTO && n->op == ONAME && !n->used) {
                // No locals used at all
                curfn->dcl = nil;
-               fixautoused(ptxt);
+               arch.fixautoused(ptxt);
                return;
        }
 
@@ -465,13 +469,13 @@ allocauto(Prog* ptxt)
 
                dowidth(n->type);
                w = n->type->width;
-               if(w >= MAXWIDTH || w < 0)
+               if(w >= arch.MAXWIDTH || w < 0)
                        fatal("bad width");
                stksize += w;
                stksize = rnd(stksize, n->type->align);
                if(haspointers(n->type))
                        stkptrsize = stksize;
-               if(thechar == '5' || thechar == '9')
+               if(arch.thechar == '5' || arch.thechar == '9')
                        stksize = rnd(stksize, widthptr);
                if(stksize >= (1ULL<<31)) {
                        setlineno(curfn);
@@ -482,7 +486,7 @@ allocauto(Prog* ptxt)
        stksize = rnd(stksize, widthreg);
        stkptrsize = rnd(stkptrsize, widthreg);
 
-       fixautoused(ptxt);
+       arch.fixautoused(ptxt);
 
        // The debug information needs accurate offsets on the symbols.
        for(ll = curfn->dcl; ll != nil; ll=ll->next) {
@@ -528,12 +532,12 @@ cgen_checknil(Node *n)
                dump("checknil", n);
                fatal("bad checknil");
        }
-       if(((thechar == '5' || thechar == '9') && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
-               regalloc(&reg, types[tptr], n);
-               cgen(n, &reg);
-               gins(ACHECKNIL, &reg, N);
-               regfree(&reg);
+       if(((arch.thechar == '5' || arch.thechar == '9') && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
+               arch.regalloc(&reg, types[tptr], n);
+               arch.cgen(n, &reg);
+               arch.gins(ACHECKNIL, &reg, N);
+               arch.regfree(&reg);
                return;
        }
-       gins(ACHECKNIL, n, N);
+       arch.gins(ACHECKNIL, n, N);
 }
index 3bfa69b1f02084078f8e1ea6b7444bc08d858933..0461085b5b6bc14a25577284f344a1591ecd9d04 100644 (file)
@@ -15,8 +15,7 @@
 
 #include <u.h>
 #include <libc.h>
-#include "gg.h"
-#include "opt.h"
+#include "go.h"
 #include "../ld/textflag.h"
 #include "../../runtime/funcdata.h"
 #include "../../runtime/mgc0.h"
@@ -513,7 +512,7 @@ newcfg(Prog *firstp)
        bb = newblock(firstp);
        arrayadd(cfg, &bb);
        for(p = firstp; p != P; p = p->link) {
-               if(p->to.type == D_BRANCH) {
+               if(p->to.type == TYPE_BRANCH) {
                        if(p->to.u.branch == nil)
                                fatal("prog branch to nil");
                        if(p->to.u.branch->opt == nil) {
@@ -552,19 +551,13 @@ newcfg(Prog *firstp)
                        if(isselectgocall(p))
                                arrayadd(selectgo, &bb);
                }
-               if(bb->last->to.type == D_BRANCH)
+               if(bb->last->to.type == TYPE_BRANCH)
                        addedge(bb, bb->last->to.u.branch->opt);
                if(bb->last->link != nil) {
                        // Add a fall-through when the instruction is
                        // not an unconditional control transfer.
-                       switch(bb->last->as) {
-                       case AJMP:
-                       case ARET:
-                       case AUNDEF:
-                               break;
-                       default:
+                       if(bb->last->as != AJMP && bb->last->as != ARET && bb->last->as != AUNDEF)
                                addedge(bb, bb->last->link->opt);
-                       }
                }
        }
 
@@ -625,15 +618,15 @@ freecfg(Array *cfg)
        BasicBlock *bb0;
        Prog *p;
        int32 i;
-       int32 len;
+       int32 n;
 
-       len = arraylength(cfg);
-       if(len > 0) {
+       n = arraylength(cfg);
+       if(n > 0) {
                bb0 = *(BasicBlock**)arrayget(cfg, 0);
                for(p = bb0->first; p != P; p = p->link) {
                        p->opt = nil;
                }
-               for(i = 0; i < len; i++) {
+               for(i = 0; i < n; i++) {
                        bb = *(BasicBlock**)arrayget(cfg, i);
                        freeblock(bb);
                }
@@ -684,7 +677,7 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
        bvresetall(varkill);
        bvresetall(avarinit);
 
-       proginfo(&info, prog);
+       arch.proginfo(&info, prog);
        if(prog->as == ARET) {
                // Return instructions implicitly read all the arguments.  For
                // the sake of correctness, out arguments must be read.  For the
@@ -708,10 +701,10 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
                                // If we added it to uevar too, we'd not see any kill
                                // and decide that the varible was live entry, which it is not.
                                // So only use uevar in the non-addrtaken case.
-                               // The p->to.type == D_NONE limits the bvset to
+                               // The p->to.type == arch.D_NONE limits the bvset to
                                // non-tail-call return instructions; see note above
                                // the for loop for details.
-                               if(!node->addrtaken && prog->to.type == D_NONE)
+                               if(!node->addrtaken && prog->to.type == TYPE_NONE)
                                        bvset(uevar, i);
                                break;
                        }
@@ -735,23 +728,23 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
        }
        if(info.flags & (LeftRead | LeftWrite | LeftAddr)) {
                from = &prog->from;
-               if (from->node != nil && from->sym != nil && from->node->curfn == curfn) {
-                       switch(from->node->class & ~PHEAP) {
+               if (from->node != nil && from->sym != nil && ((Node*)(from->node))->curfn == curfn) {
+                       switch(((Node*)(from->node))->class & ~PHEAP) {
                        case PAUTO:
                        case PPARAM:
                        case PPARAMOUT:
-                               pos = (int)(uintptr)from->node->opt - 1; // index in vars
+                               pos = (int)(uintptr)((Node*)(from->node))->opt - 1; // index in vars
                                if(pos == -1)
                                        goto Next;
                                if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != from->node)
                                        fatal("bad bookkeeping in liveness %N %d", from->node, pos);
-                               if(from->node->addrtaken) {
+                               if(((Node*)(from->node))->addrtaken) {
                                        bvset(avarinit, pos);
                                } else {
                                        if(info.flags & (LeftRead | LeftAddr))
                                                bvset(uevar, pos);
                                        if(info.flags & LeftWrite)
-                                               if(from->node != nil && !isfat(from->node->type))
+                                               if(from->node != nil && !arch.isfat(((Node*)(from->node))->type))
                                                        bvset(varkill, pos);
                                }
                        }
@@ -760,17 +753,17 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
 Next:
        if(info.flags & (RightRead | RightWrite | RightAddr)) {
                to = &prog->to;
-               if (to->node != nil && to->sym != nil && to->node->curfn == curfn) {
-                       switch(to->node->class & ~PHEAP) {
+               if (to->node != nil && to->sym != nil && ((Node*)(to->node))->curfn == curfn) {
+                       switch(((Node*)(to->node))->class & ~PHEAP) {
                        case PAUTO:
                        case PPARAM:
                        case PPARAMOUT:
-                               pos = (int)(uintptr)to->node->opt - 1; // index in vars
+                               pos = (int)(uintptr)((Node*)(to->node))->opt - 1; // index in vars
                                if(pos == -1)
                                        goto Next1;
                                if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != to->node)
                                        fatal("bad bookkeeping in liveness %N %d", to->node, pos);
-                               if(to->node->addrtaken) {
+                               if(((Node*)(to->node))->addrtaken) {
                                        if(prog->as != AVARKILL)
                                                bvset(avarinit, pos);
                                        if(prog->as == AVARDEF || prog->as == AVARKILL)
@@ -787,7 +780,7 @@ Next:
                                        if((info.flags & RightRead) || (info.flags & (RightAddr|RightWrite)) == RightAddr)
                                                bvset(uevar, pos);
                                        if(info.flags & RightWrite)
-                                               if(to->node != nil && (!isfat(to->node->type) || prog->as == AVARDEF))
+                                               if(to->node != nil && (!arch.isfat(((Node*)(to->node))->type) || prog->as == AVARDEF))
                                                        bvset(varkill, pos);
                                }
                        }
@@ -898,8 +891,12 @@ printnode(Node *node)
        char *p;
        char *a;
 
-       p = haspointers(node->type) ? "^" : "";
-       a = node->addrtaken ? "@" : "";
+       p = "";
+       if(haspointers(node->type))
+               p = "^";
+       a = "";
+       if(node->addrtaken)
+               a = "@";
        print(" %N%s%s", node, p, a);
 }
 
@@ -990,6 +987,10 @@ checkauto(Node *fn, Prog *p, Node *n)
                if(l->n->op == ONAME && l->n->class == PAUTO && l->n == n)
                        return;
 
+       if(n == nil) {
+               print("%L: checkauto %N: nil node in %P\n", p->lineno, curfn, p);
+               return;
+       }
        print("checkauto %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p);
        for(l = fn->dcl; l != nil; l = l->next)
                print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class);
@@ -1021,13 +1022,13 @@ checkparam(Node *fn, Prog *p, Node *n)
 static void
 checkprog(Node *fn, Prog *p)
 {
-       if(p->from.type == D_AUTO)
+       if(p->from.name == NAME_AUTO)
                checkauto(fn, p, p->from.node);
-       if(p->from.type == D_PARAM)
+       if(p->from.name == NAME_PARAM)
                checkparam(fn, p, p->from.node);
-       if(p->to.type == D_AUTO)
+       if(p->to.name == NAME_AUTO)
                checkauto(fn, p, p->to.node);
-       if(p->to.type == D_PARAM)
+       if(p->to.name == NAME_PARAM)
                checkparam(fn, p, p->to.node);
 }
 
@@ -1047,15 +1048,8 @@ checkptxt(Node *fn, Prog *firstp)
        for(p = firstp; p != P; p = p->link) {
                if(0)
                        print("analyzing '%P'\n", p);
-               switch(p->as) {
-               case ADATA:
-               case AGLOBL:
-               case ANAME:
-               case ASIGNAME:
-               case ATYPE:
-                       continue;
-               }
-               checkprog(fn, p);
+               if(p->as != ADATA && p->as != AGLOBL && p->as != ATYPE)
+                       checkprog(fn, p);
        }
 }
 
@@ -1224,7 +1218,7 @@ unlinkedprog(int as)
        Prog *p;
 
        p = mal(sizeof(*p));
-       clearp(p);
+       arch.clearp(p);
        p->as = as;
        return p;
 }
@@ -1241,8 +1235,8 @@ newpcdataprog(Prog *prog, int32 index)
        nodconst(&to, types[TINT32], index);
        pcdata = unlinkedprog(APCDATA);
        pcdata->lineno = prog->lineno;
-       naddr(&from, &pcdata->from, 0);
-       naddr(&to, &pcdata->to, 0);
+       arch.naddr(&from, &pcdata->from, 0);
+       arch.naddr(&to, &pcdata->to, 0);
        return pcdata;
 }
 
@@ -1487,25 +1481,21 @@ livenessepilogue(Liveness *lv)
                                // Annotate ambiguously live variables so that they can
                                // be zeroed at function entry.
                                // livein and liveout are dead here and used as temporaries.
-                               // For now, only enabled when using GOEXPERIMENT=precisestack
-                               // during make.bash / all.bash.
-                               if(precisestack_enabled) {
-                                       bvresetall(livein);
-                                       bvandnot(liveout, any, all);
-                                       if(!bvisempty(liveout)) {
-                                               for(pos = 0; pos < liveout->n; pos++) {
-                                                       if(!bvget(liveout, pos))
-                                                               continue;
-                                                       bvset(all, pos); // silence future warnings in this block
-                                                       n = *(Node**)arrayget(lv->vars, pos);
-                                                       if(!n->needzero) {
-                                                               n->needzero = 1;
-                                                               if(debuglive >= 1)
-                                                                       warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n);
-                                                               // Record in 'ambiguous' bitmap.
-                                                               xoffset = n->xoffset + stkptrsize;
-                                                               twobitwalktype1(n->type, &xoffset, ambig);
-                                                       }
+                               bvresetall(livein);
+                               bvandnot(liveout, any, all);
+                               if(!bvisempty(liveout)) {
+                                       for(pos = 0; pos < liveout->n; pos++) {
+                                               if(!bvget(liveout, pos))
+                                                       continue;
+                                               bvset(all, pos); // silence future warnings in this block
+                                               n = *(Node**)arrayget(lv->vars, pos);
+                                               if(!n->needzero) {
+                                                       n->needzero = 1;
+                                                       if(debuglive >= 1)
+                                                               warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n);
+                                                       // Record in 'ambiguous' bitmap.
+                                                       xoffset = n->xoffset + stkptrsize;
+                                                       twobitwalktype1(n->type, &xoffset, ambig);
                                                }
                                        }
                                }
@@ -1608,11 +1598,11 @@ livenessepilogue(Liveness *lv)
                                        fmtstrinit(&fmt);
                                        fmtprint(&fmt, "%L: live at ", p->lineno);
                                        if(p->as == ACALL && p->to.node)
-                                               fmtprint(&fmt, "call to %s:", p->to.node->sym->name);
+                                               fmtprint(&fmt, "call to %s:", ((Node*)(p->to.node))->sym->name);
                                        else if(p->as == ACALL)
                                                fmtprint(&fmt, "indirect call:");
                                        else
-                                               fmtprint(&fmt, "entry to %s:", p->from.node->sym->name);
+                                               fmtprint(&fmt, "entry to %s:", ((Node*)(p->from.node))->sym->name);
                                        numlive = 0;
                                        for(j = 0; j < arraylength(lv->vars); j++) {
                                                n = *(Node**)arrayget(lv->vars, j);
@@ -1684,12 +1674,17 @@ enum
 static uint32
 hashbitmap(uint32 h, Bvec *bv)
 {
-       uchar *p, *ep;
+       int i, n;
+       uint32 w;
        
-       p = (uchar*)bv->b;
-       ep = p + 4*((bv->n+31)/32);
-       while(p < ep)
-               h = (h*Hp) ^ *p++;
+       n = (bv->n+31)/32;
+       for(i=0; i<n; i++) {
+               w = bv->b[i];
+               h = (h*Hp) ^ (w&0xff);
+               h = (h*Hp) ^ ((w>>8)&0xff);
+               h = (h*Hp) ^ ((w>>16)&0xff);
+               h = (h*Hp) ^ ((w>>24)&0xff);
+       }
        return h;
 }
 
@@ -1937,7 +1932,7 @@ twobitwritesymbol(Array *arr, Sym *sym)
                }
        }
        duint32(sym, 0, i); // number of bitmaps
-       ggloblsym(sym, off, RODATA);
+       arch.ggloblsym(sym, off, RODATA);
 }
 
 static void
index 993bb24821d21b59d56ce809ac23d2e9cad49573..f71702431a859e2fa455387bc174277f811e44d9 100644 (file)
@@ -34,8 +34,7 @@
 
 #include       <u.h>
 #include       <libc.h>
-#include       "gg.h"
-#include       "opt.h"
+#include       "go.h"
 
 // p is a call instruction. Does the call fail to return?
 int
@@ -58,7 +57,7 @@ noreturn(Prog *p)
 
        if(p->to.node == nil)
                return 0;
-       s = p->to.node->sym;
+       s = ((Node*)(p->to.node))->sym;
        if(s == S)
                return 0;
        for(i=0; symlist[i]!=S; i++)
@@ -82,7 +81,7 @@ chasejmp(Prog *p, int *jmploop)
        int n;
 
        n = 0;
-       while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
+       while(p != P && p->as == AJMP && p->to.type == TYPE_BRANCH) {
                if(++n > 10) {
                        *jmploop = 1;
                        break;
@@ -113,7 +112,7 @@ mark(Prog *firstp)
                if(p->opt != dead)
                        break;
                p->opt = alive;
-               if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch)
+               if(p->as != ACALL && p->to.type == TYPE_BRANCH && p->to.u.branch)
                        mark(p->to.u.branch);
                if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
                        break;
@@ -134,7 +133,7 @@ fixjmp(Prog *firstp)
        for(p=firstp; p; p=p->link) {
                if(debug['R'] && debug['v'])
                        print("%P\n", p);
-               if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
+               if(p->as != ACALL && p->to.type == TYPE_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
                        p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
                        if(debug['R'] && debug['v'])
                                print("->%P\n", p);
@@ -177,7 +176,7 @@ fixjmp(Prog *firstp)
        if(!jmploop) {
                last = nil;
                for(p=firstp; p; p=p->link) {
-                       if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
+                       if(p->as == AJMP && p->to.type == TYPE_BRANCH && p->to.u.branch == p->link) {
                                if(debug['R'] && debug['v'])
                                        print("del %P\n", p);
                                continue;
@@ -233,7 +232,7 @@ flowstart(Prog *firstp, int size)
        nf = 0;
        for(p = firstp; p != P; p = p->link) {
                p->opt = nil; // should be already, but just in case
-               proginfo(&info, p);
+               arch.proginfo(&info, p);
                if(info.flags & Skip)
                        continue;
                p->opt = (void*)1;
@@ -270,13 +269,13 @@ flowstart(Prog *firstp, int size)
        // Fill in pred/succ information.
        for(f = start; f != nil; f = f->link) {
                p = f->prog;
-               proginfo(&info, p);
+               arch.proginfo(&info, p);
                if(!(info.flags & Break)) {
                        f1 = f->link;
                        f->s1 = f1;
                        f1->p1 = f;
                }
-               if(p->to.type == D_BRANCH) {
+               if(p->to.type == TYPE_BRANCH) {
                        if(p->to.u.branch == P)
                                fatal("pnil %P", p);
                        f1 = p->to.u.branch->opt;
@@ -384,6 +383,10 @@ loophead(int32 *idom, Flow *r)
        return 0;
 }
 
+enum {
+       LOOP = 3,
+};
+
 static void
 loopmark(Flow **rpo2r, int32 head, Flow *r)
 {
@@ -584,12 +587,16 @@ mergetemp(Prog *firstp)
        // single-use (that's why we have so many!).
        for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
                p = r->f.prog;
-               proginfo(&info, p);
+               arch.proginfo(&info, p);
 
-               if(p->from.node != N && p->from.node->opt && p->to.node != N && p->to.node->opt)
+               if(p->from.node != N && ((Node*)(p->from.node))->opt && p->to.node != N && ((Node*)(p->to.node))->opt)
                        fatal("double node %P", p);
-               if((n = p->from.node) != N && (v = n->opt) != nil ||
-                  (n = p->to.node) != N && (v = n->opt) != nil) {
+               v = nil;
+               if((n = p->from.node) != N)
+                       v = n->opt;
+               if(v == nil && (n = p->to.node) != N)
+                       v = n->opt;
+               if(v != nil) {
                        if(v->def == nil)
                                v->def = r;
                        r->uselink = v->use;
@@ -600,7 +607,7 @@ mergetemp(Prog *firstp)
        }
        
        if(Debug > 1)
-               dumpit("before", g->start, 0);
+               arch.dumpit("before", g->start, 0);
        
        nkill = 0;
 
@@ -611,7 +618,7 @@ mergetemp(Prog *firstp)
                // Used in only one instruction, which had better be a write.
                if((r = v->use) != nil && r->uselink == nil) {
                        p = r->f.prog;
-                       proginfo(&info, p);
+                       arch.proginfo(&info, p);
                        if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) {
                                p->as = ANOP;
                                p->to = zprog.to;
@@ -628,9 +635,9 @@ mergetemp(Prog *firstp)
                // no jumps to the next instruction. Happens mainly in 386 compiler.
                if((r = v->use) != nil && r->f.link == &r->uselink->f && r->uselink->uselink == nil && uniqp(r->f.link) == &r->f) {
                        p = r->f.prog;
-                       proginfo(&info, p);
+                       arch.proginfo(&info, p);
                        p1 = r->f.link->prog;
-                       proginfo(&info1, p1);
+                       arch.proginfo(&info1, p1);
                        enum {
                                SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD,
                        };
@@ -638,7 +645,7 @@ mergetemp(Prog *firstp)
                           !((info.flags|info1.flags) & (LeftAddr|RightAddr)) &&
                           (info.flags & SizeAny) == (info1.flags & SizeAny)) {
                                p1->from = p->from;
-                               excise(&r->f);
+                               arch.excise(&r->f);
                                v->removed = 1;
                                if(Debug)
                                        print("drop immediate-use %S\n", v->node->sym);
@@ -734,7 +741,7 @@ mergetemp(Prog *firstp)
                }
        
                if(Debug > 1)
-                       dumpit("after", g->start, 0);
+                       arch.dumpit("after", g->start, 0);
        }
 
        // Update node references to use merged temporaries.
@@ -852,16 +859,16 @@ nilopt(Prog *firstp)
                return;
 
        if(debug_checknil > 1 /* || strcmp(curfn->nname->sym->name, "f1") == 0 */)
-               dumpit("nilopt", g->start, 0);
+               arch.dumpit("nilopt", g->start, 0);
 
        ncheck = 0;
        nkill = 0;
        for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
                p = r->f.prog;
-               if(p->as != ACHECKNIL || !regtyp(&p->from))
+               if(p->as != ACHECKNIL || !arch.regtyp(&p->from))
                        continue;
                ncheck++;
-               if(stackaddr(&p->from)) {
+               if(arch.stackaddr(&p->from)) {
                        if(debug_checknil && p->lineno > 1)
                                warnl(p->lineno, "removed nil check of SP address");
                        r->kill = 1;
@@ -884,7 +891,7 @@ nilopt(Prog *firstp)
        for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
                if(r->kill) {
                        nkill++;
-                       excise(&r->f);
+                       arch.excise(&r->f);
                }
        }
 
@@ -903,13 +910,13 @@ nilwalkback(NilFlow *rcheck)
        
        for(r = rcheck; r != nil; r = (NilFlow*)uniqp(&r->f)) {
                p = r->f.prog;
-               proginfo(&info, p);
-               if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) {
+               arch.proginfo(&info, p);
+               if((info.flags & RightWrite) && arch.sameaddr(&p->to, &rcheck->f.prog->from)) {
                        // Found initialization of value we're checking for nil.
                        // without first finding the check, so this one is unchecked.
                        return;
                }
-               if(r != rcheck && p->as == ACHECKNIL && sameaddr(&p->from, &rcheck->f.prog->from)) {
+               if(r != rcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from)) {
                        rcheck->kill = 1;
                        return;
                }
@@ -930,11 +937,11 @@ nilwalkback(NilFlow *rcheck)
                
                // If same check, stop this loop but still check
                // alternate predecessors up to this point.
-               if(r1 != rcheck && p->as == ACHECKNIL && sameaddr(&p->from, &rcheck->f.prog->from))
+               if(r1 != rcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from))
                        break;
 
-               proginfo(&info, p);
-               if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) {
+               arch.proginfo(&info, p);
+               if((info.flags & RightWrite) && arch.sameaddr(&p->to, &rcheck->f.prog->from)) {
                        // Found initialization of value we're checking for nil.
                        // without first finding the check, so this one is unchecked.
                        rcheck->kill = 0;
@@ -944,8 +951,8 @@ nilwalkback(NilFlow *rcheck)
                if(r1->f.p1 == nil && r1->f.p2 == nil) {
                        print("lost pred for %P\n", rcheck->f.prog);
                        for(r1=r0; r1!=nil; r1=(NilFlow*)r1->f.p1) {
-                               proginfo(&info, r1->f.prog);
-                               print("\t%P %d %d %D %D\n", r1->f.prog, info.flags&RightWrite, sameaddr(&r1->f.prog->to, &rcheck->f.prog->from), &r1->f.prog->to, &rcheck->f.prog->from);
+                               arch.proginfo(&info, r1->f.prog);
+                               print("\t%P %d %d %D %D\n", r1->f.prog, info.flags&RightWrite, arch.sameaddr(&r1->f.prog->to, &rcheck->f.prog->from), &r1->f.prog->to, &rcheck->f.prog->from);
                        }
                        fatal("lost pred trail");
                }
@@ -974,13 +981,13 @@ nilwalkfwd(NilFlow *rcheck)
        last = nil;
        for(r = (NilFlow*)uniqs(&rcheck->f); r != nil; r = (NilFlow*)uniqs(&r->f)) {
                p = r->f.prog;
-               proginfo(&info, p);
+               arch.proginfo(&info, p);
                
-               if((info.flags & LeftRead) && smallindir(&p->from, &rcheck->f.prog->from)) {
+               if((info.flags & LeftRead) && arch.smallindir(&p->from, &rcheck->f.prog->from)) {
                        rcheck->kill = 1;
                        return;
                }
-               if((info.flags & (RightRead|RightWrite)) && smallindir(&p->to, &rcheck->f.prog->from)) {
+               if((info.flags & (RightRead|RightWrite)) && arch.smallindir(&p->to, &rcheck->f.prog->from)) {
                        rcheck->kill = 1;
                        return;
                }
@@ -989,10 +996,10 @@ nilwalkfwd(NilFlow *rcheck)
                if(p->as == ACHECKNIL)
                        return;
                // Stop if value is lost.
-               if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from))
+               if((info.flags & RightWrite) && arch.sameaddr(&p->to, &rcheck->f.prog->from))
                        return;
                // Stop if memory write.
-               if((info.flags & RightWrite) && !regtyp(&p->to))
+               if((info.flags & RightWrite) && !arch.regtyp(&p->to))
                        return;
                // Stop if we jump backward.
                // This test is valid because all the NilFlow* are pointers into
diff --git a/src/cmd/gc/popt.h b/src/cmd/gc/popt.h
deleted file mode 100644 (file)
index 8d5dfff..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-typedef struct Flow Flow;
-typedef struct Graph Graph;
-
-struct Flow {
-       Prog*   prog;           // actual instruction
-       Flow*   p1;             // predecessors of this instruction: p1,
-       Flow*   p2;             // and then p2 linked though p2link.
-       Flow*   p2link;
-       Flow*   s1;             // successors of this instruction (at most two: s1 and s2).
-       Flow*   s2;
-       Flow*   link;           // next instruction in function code
-       
-       int32   active; // usable by client
-
-       int32   rpo;            // reverse post ordering
-       uint16  loop;           // x5 for every loop
-       uchar   refset;         // diagnostic generated
-};
-
-struct Graph
-{
-       Flow*   start;
-       int     num;
-       
-       // After calling flowrpo, rpo lists the flow nodes in reverse postorder,
-       // and each non-dead Flow node f has g->rpo[f->rpo] == f.
-       Flow**  rpo;
-};
-
-void   fixjmp(Prog*);
-Graph* flowstart(Prog*, int);
-void   flowrpo(Graph*);
-void   flowend(Graph*);
-void   mergetemp(Prog*);
-void   nilopt(Prog*);
-int    noreturn(Prog*);
-int    regtyp(Addr*);
-int    sameaddr(Addr*, Addr*);
-int    smallindir(Addr*, Addr*);
-int    stackaddr(Addr*);
-Flow*  uniqp(Flow*);
-Flow*  uniqs(Flow*);
index de9e32b2a8b3c0fe964072cdf8af4ea5c2761812..f3134dab23d21e7170d3a93340b386d1a645c4a6 100644 (file)
@@ -474,6 +474,7 @@ isartificial(Node *n)
 static int
 callinstr(Node **np, NodeList **init, int wr, int skip)
 {
+       char *name;
        Node *f, *b, *n;
        Type *t;
        int class, hascalls;
@@ -508,10 +509,16 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
                n = treecopy(n);
                makeaddable(n);
                if(t->etype == TSTRUCT || isfixedarray(t)) {
-                       f = mkcall(wr ? "racewriterange" : "racereadrange", T, init, uintptraddr(n),
-                                       nodintconst(t->width));
-               } else
-                       f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n));
+                       name = "racereadrange";
+                       if(wr)
+                               name = "racewriterange";
+                       f = mkcall(name, T, init, uintptraddr(n), nodintconst(t->width));
+               } else {
+                       name = "raceread";
+                       if(wr)
+                               name = "racewrite";
+                       f = mkcall(name, T, init, uintptraddr(n));
+               }
                *init = list(*init, f);
                return 1;
        }
index 55fadae72387c335d331edadb64ad4fabc4f9641..ff05820b58b00d0dd0c34f7d5a27a689f46e3154 100644 (file)
@@ -18,14 +18,25 @@ typecheckrange(Node *n)
        Node *v1, *v2;
        NodeList *ll;
 
+       // Typechecking order is important here:
+       // 0. first typecheck range expression (slice/map/chan),
+       //      it is evaluated only once and so logically it is not part of the loop.
+       // 1. typcheck produced values,
+       //      this part can declare new vars and so it must be typechecked before body,
+       //      because body can contain a closure that captures the vars.
+       // 2. decldepth++ to denote loop body.
+       // 3. typecheck body.
+       // 4. decldepth--.
+
+       typecheck(&n->right, Erv);
+       if((t = n->right->type) == T)
+               goto out;
+
        // delicate little dance.  see typecheckas2
        for(ll=n->list; ll; ll=ll->next)
                if(ll->n->defn != n)
                        typecheck(&ll->n, Erv | Easgn);
 
-       typecheck(&n->right, Erv);
-       if((t = n->right->type) == T)
-               goto out;
        if(isptr[t->etype] && isfixedarray(t->type))
                t = t->type;
        n->type = t;
@@ -89,22 +100,26 @@ typecheckrange(Node *n)
                        v1->type = t1;
                else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
                        yyerror("cannot assign type %T to %lN in range%s", t1, v1, why);
+               checkassign(n, v1);
        }
        if(v2) {
                if(v2->defn == n)
                        v2->type = t2;
                else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
                        yyerror("cannot assign type %T to %lN in range%s", t2, v2, why);
+               checkassign(n, v2);
        }
 
 out:
-       typechecklist(n->nbody, Etop);
-
        // second half of dance
        n->typecheck = 1;
        for(ll=n->list; ll; ll=ll->next)
                if(ll->n->typecheck == 0)
                        typecheck(&ll->n, Erv | Easgn);
+
+       decldepth++;
+       typechecklist(n->nbody, Etop);
+       decldepth--;
 }
 
 void
index fde473ac49c1413f88932f45bee073cfbe131599..61a63c0528bd2b95d2a9cd44faeb038e99852afe 100644 (file)
@@ -181,6 +181,10 @@ mapbucket(Type *t)
        valuesfield->down = overflowfield;
        overflowfield->down = T;
 
+       // See comment on hmap.overflow in ../../runtime/hashmap.go.
+       if(!haspointers(t->type) && !haspointers(t->down))
+               bucket->haspointers = 1;  // no pointers
+
        bucket->width = offset;
        bucket->local = t->local;
        t->bucket = bucket;
@@ -197,7 +201,7 @@ static Type*
 hmap(Type *t)
 {
        Type *h, *bucket;
-       Type *bucketsfield, *oldbucketsfield;
+       Type *bucketsfield, *oldbucketsfield, *overflowfield;
        int32 offset;
 
        if(t->hmap != T)
@@ -208,9 +212,10 @@ hmap(Type *t)
        h->noalg = 1;
 
        offset = widthint; // count
-       offset += 4;       // flags
-       offset += 4;       // hash0
+       offset += 1;       // flags
        offset += 1;       // B
+       offset += 2;       // padding
+       offset += 4;       // hash0
        offset = (offset + widthptr - 1) / widthptr * widthptr;
        
        bucketsfield = typ(TFIELD);
@@ -227,12 +232,20 @@ hmap(Type *t)
        oldbucketsfield->sym->name = "oldbuckets";
        offset += widthptr;
 
-       offset += widthptr; // nevacuate (last field in Hmap)
+       offset += widthptr; // nevacuate
+
+       overflowfield = typ(TFIELD);
+       overflowfield->type = types[TUNSAFEPTR];
+       overflowfield->width = offset;
+       overflowfield->sym = mal(sizeof(Sym));
+       overflowfield->sym->name = "overflow";
+       offset += widthptr;
 
        // link up fields
        h->type = bucketsfield;
        bucketsfield->down = oldbucketsfield;
-       oldbucketsfield->down = T;
+       oldbucketsfield->down = overflowfield;
+       overflowfield->down = T;
 
        h->width = offset;
        h->local = t->local;
@@ -245,7 +258,7 @@ Type*
 hiter(Type *t)
 {
        int32 n, off;
-       Type *field[7];
+       Type *field[9];
        Type *i;
 
        if(t->hiter != T)
@@ -259,6 +272,7 @@ hiter(Type *t)
        //    h *Hmap
        //    buckets *Bucket
        //    bptr *Bucket
+       //    overflow unsafe.Pointer
        //    other [4]uintptr
        // }
        // must match ../../runtime/hashmap.c:hash_iter.
@@ -292,29 +306,39 @@ hiter(Type *t)
        field[5]->sym = mal(sizeof(Sym));
        field[5]->sym->name = "bptr";
        
-       // all other non-pointer fields
        field[6] = typ(TFIELD);
-       field[6]->type = typ(TARRAY);
-       field[6]->type->type = types[TUINTPTR];
-       field[6]->type->bound = 4;
-       field[6]->type->width = 4 * widthptr;
+       field[6]->type = types[TUNSAFEPTR];
        field[6]->sym = mal(sizeof(Sym));
-       field[6]->sym->name = "other";
+       field[6]->sym->name = "overflow0";
+
+       field[7] = typ(TFIELD);
+       field[7]->type = types[TUNSAFEPTR];
+       field[7]->sym = mal(sizeof(Sym));
+       field[7]->sym->name = "overflow1";
+
+       // all other non-pointer fields
+       field[8] = typ(TFIELD);
+       field[8]->type = typ(TARRAY);
+       field[8]->type->type = types[TUINTPTR];
+       field[8]->type->bound = 4;
+       field[8]->type->width = 4 * widthptr;
+       field[8]->sym = mal(sizeof(Sym));
+       field[8]->sym->name = "other";
        
        // build iterator struct holding the above fields
        i = typ(TSTRUCT);
        i->noalg = 1;
        i->type = field[0];
        off = 0;
-       for(n = 0; n < 6; n++) {
+       for(n = 0; n < nelem(field)-1; n++) {
                field[n]->down = field[n+1];
                field[n]->width = off;
                off += field[n]->type->width;
        }
-       field[6]->down = T;
-       off += field[6]->type->width;
-       if(off != 10 * widthptr)
-               yyerror("hash_iter size not correct %d %d", off, 10 * widthptr);
+       field[nelem(field)-1]->down = T;
+       off += field[nelem(field)-1]->type->width;
+       if(off != 12 * widthptr)
+               yyerror("hash_iter size not correct %d %d", off, 11 * widthptr);
        t->hiter = i;
        i->map = t;
        return i;
@@ -511,7 +535,7 @@ dimportpath(Pkg *p)
                return;
 
        if(gopkg == nil) {
-               gopkg = mkpkg(strlit("go"));
+               gopkg = mkpkg(newstrlit("go"));
                gopkg->name = "go";
        }
        nam = smprint("importpath.%s.", p->prefix);
@@ -523,15 +547,15 @@ dimportpath(Pkg *p)
        n->xoffset = 0;
        p->pathsym = n->sym;
 
-       gdatastring(n, p->path);
-       ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA);
+       arch.gdatastring(n, p->path);
+       arch.ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA);
 }
 
 static int
 dgopkgpath(Sym *s, int ot, Pkg *pkg)
 {
        if(pkg == nil)
-               return dgostringptr(s, ot, nil);
+               return arch.dgostringptr(s, ot, nil);
 
        // Emit reference to go.importpath.""., which 6l will
        // rewrite using the correct import path.  Every package
@@ -540,12 +564,12 @@ dgopkgpath(Sym *s, int ot, Pkg *pkg)
                static Sym *ns;
 
                if(ns == nil)
-                       ns = pkglookup("importpath.\"\".", mkpkg(strlit("go")));
-               return dsymptr(s, ot, ns, 0);
+                       ns = pkglookup("importpath.\"\".", mkpkg(newstrlit("go")));
+               return arch.dsymptr(s, ot, ns, 0);
        }
 
        dimportpath(pkg);
-       return dsymptr(s, ot, pkg->pathsym, 0);
+       return arch.dsymptr(s, ot, pkg->pathsym, 0);
 }
 
 /*
@@ -565,7 +589,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
 
        // fill in *extraType pointer in header
        off = rnd(off, widthptr);
-       dsymptr(sym, ptroff, sym, off);
+       arch.dsymptr(sym, ptroff, sym, off);
 
        n = 0;
        for(a=m; a; a=a->link) {
@@ -576,18 +600,18 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
        ot = off;
        s = sym;
        if(t->sym) {
-               ot = dgostringptr(s, ot, t->sym->name);
+               ot = arch.dgostringptr(s, ot, t->sym->name);
                if(t != types[t->etype] && t != errortype)
                        ot = dgopkgpath(s, ot, t->sym->pkg);
                else
-                       ot = dgostringptr(s, ot, nil);
+                       ot = arch.dgostringptr(s, ot, nil);
        } else {
-               ot = dgostringptr(s, ot, nil);
-               ot = dgostringptr(s, ot, nil);
+               ot = arch.dgostringptr(s, ot, nil);
+               ot = arch.dgostringptr(s, ot, nil);
        }
 
        // slice header
-       ot = dsymptr(s, ot, s, ot + widthptr + 2*widthint);
+       ot = arch.dsymptr(s, ot, s, ot + widthptr + 2*widthint);
        ot = duintxx(s, ot, n, widthint);
        ot = duintxx(s, ot, n, widthint);
 
@@ -595,16 +619,16 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
        for(a=m; a; a=a->link) {
                // method
                // ../../runtime/type.go:/method
-               ot = dgostringptr(s, ot, a->name);
+               ot = arch.dgostringptr(s, ot, a->name);
                ot = dgopkgpath(s, ot, a->pkg);
-               ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
-               ot = dsymptr(s, ot, dtypesym(a->type), 0);
+               ot = arch.dsymptr(s, ot, dtypesym(a->mtype), 0);
+               ot = arch.dsymptr(s, ot, dtypesym(a->type), 0);
                if(a->isym)
-                       ot = dsymptr(s, ot, a->isym, 0);
+                       ot = arch.dsymptr(s, ot, a->isym, 0);
                else
                        ot = duintptr(s, ot, 0);
                if(a->tsym)
-                       ot = dsymptr(s, ot, a->tsym, 0);
+                       ot = arch.dsymptr(s, ot, a->tsym, 0);
                else
                        ot = duintptr(s, ot, 0);
        }
@@ -792,17 +816,17 @@ dcommontype(Sym *s, int ot, Type *t)
                i |= KindGCProg;
        ot = duint8(s, ot, i);  // kind
        if(algsym == S)
-               ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
+               ot = arch.dsymptr(s, ot, algarray, alg*sizeofAlg);
        else
-               ot = dsymptr(s, ot, algsym, 0);
+               ot = arch.dsymptr(s, ot, algsym, 0);
        // gc
        if(gcprog) {
                gengcprog(t, &gcprog0, &gcprog1);
                if(gcprog0 != S)
-                       ot = dsymptr(s, ot, gcprog0, 0);
+                       ot = arch.dsymptr(s, ot, gcprog0, 0);
                else
                        ot = duintptr(s, ot, 0);
-               ot = dsymptr(s, ot, gcprog1, 0);
+               ot = arch.dsymptr(s, ot, gcprog1, 0);
        } else {
                gengcmask(t, gcmask);
                x1 = 0;
@@ -821,14 +845,14 @@ dcommontype(Sym *s, int ot, Type *t)
                        sbits->flags |= SymUniq;
                        for(i = 0; i < 2*widthptr; i++)
                                duint8(sbits, i, gcmask[i]);
-                       ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
+                       arch.ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
                }
-               ot = dsymptr(s, ot, sbits, 0);
+               ot = arch.dsymptr(s, ot, sbits, 0);
                ot = duintptr(s, ot, 0);
        }
        p = smprint("%-uT", t);
        //print("dcommontype: %s\n", p);
-       ot = dgostringptr(s, ot, p);    // string
+       ot = arch.dgostringptr(s, ot, p);       // string
        free(p);
 
        // skip pointer to extraType,
@@ -837,8 +861,8 @@ dcommontype(Sym *s, int ot, Type *t)
        // otherwise linker will assume 0.
        ot += widthptr;
 
-       ot = dsymptr(s, ot, sptr, 0);  // ptrto type
-       ot = dsymptr(s, ot, zero, 0);  // ptr to zero value
+       ot = arch.dsymptr(s, ot, sptr, 0);  // ptrto type
+       ot = arch.dsymptr(s, ot, zero, 0);  // ptr to zero value
        return ot;
 }
 
@@ -1068,15 +1092,15 @@ ok:
                        s2 = dtypesym(t2);
                        ot = dcommontype(s, ot, t);
                        xt = ot - 3*widthptr;
-                       ot = dsymptr(s, ot, s1, 0);
-                       ot = dsymptr(s, ot, s2, 0);
+                       ot = arch.dsymptr(s, ot, s1, 0);
+                       ot = arch.dsymptr(s, ot, s2, 0);
                        ot = duintptr(s, ot, t->bound);
                } else {
                        // ../../runtime/type.go:/SliceType
                        s1 = dtypesym(t->type);
                        ot = dcommontype(s, ot, t);
                        xt = ot - 3*widthptr;
-                       ot = dsymptr(s, ot, s1, 0);
+                       ot = arch.dsymptr(s, ot, s1, 0);
                }
                break;
 
@@ -1085,7 +1109,7 @@ ok:
                s1 = dtypesym(t->type);
                ot = dcommontype(s, ot, t);
                xt = ot - 3*widthptr;
-               ot = dsymptr(s, ot, s1, 0);
+               ot = arch.dsymptr(s, ot, s1, 0);
                ot = duintptr(s, ot, t->chan);
                break;
 
@@ -1106,21 +1130,21 @@ ok:
 
                // two slice headers: in and out.
                ot = rnd(ot, widthptr);
-               ot = dsymptr(s, ot, s, ot+2*(widthptr+2*widthint));
+               ot = arch.dsymptr(s, ot, s, ot+2*(widthptr+2*widthint));
                n = t->thistuple + t->intuple;
                ot = duintxx(s, ot, n, widthint);
                ot = duintxx(s, ot, n, widthint);
-               ot = dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr);
+               ot = arch.dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr);
                ot = duintxx(s, ot, t->outtuple, widthint);
                ot = duintxx(s, ot, t->outtuple, widthint);
 
                // slice data
                for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
-                       ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+                       ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
                for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
-                       ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+                       ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
                for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
-                       ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+                       ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
                break;
 
        case TINTER:
@@ -1134,14 +1158,14 @@ ok:
                // ../../runtime/type.go:/InterfaceType
                ot = dcommontype(s, ot, t);
                xt = ot - 3*widthptr;
-               ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
+               ot = arch.dsymptr(s, ot, s, ot+widthptr+2*widthint);
                ot = duintxx(s, ot, n, widthint);
                ot = duintxx(s, ot, n, widthint);
                for(a=m; a; a=a->link) {
                        // ../../runtime/type.go:/imethod
-                       ot = dgostringptr(s, ot, a->name);
+                       ot = arch.dgostringptr(s, ot, a->name);
                        ot = dgopkgpath(s, ot, a->pkg);
-                       ot = dsymptr(s, ot, dtypesym(a->type), 0);
+                       ot = arch.dsymptr(s, ot, dtypesym(a->type), 0);
                }
                break;
 
@@ -1153,10 +1177,10 @@ ok:
                s4 = dtypesym(hmap(t));
                ot = dcommontype(s, ot, t);
                xt = ot - 3*widthptr;
-               ot = dsymptr(s, ot, s1, 0);
-               ot = dsymptr(s, ot, s2, 0);
-               ot = dsymptr(s, ot, s3, 0);
-               ot = dsymptr(s, ot, s4, 0);
+               ot = arch.dsymptr(s, ot, s1, 0);
+               ot = arch.dsymptr(s, ot, s2, 0);
+               ot = arch.dsymptr(s, ot, s3, 0);
+               ot = arch.dsymptr(s, ot, s4, 0);
                if(t->down->width > MAXKEYSIZE) {
                        ot = duint8(s, ot, widthptr);
                        ot = duint8(s, ot, 1); // indirect
@@ -1186,7 +1210,7 @@ ok:
                s1 = dtypesym(t->type);
                ot = dcommontype(s, ot, t);
                xt = ot - 3*widthptr;
-               ot = dsymptr(s, ot, s1, 0);
+               ot = arch.dsymptr(s, ot, s1, 0);
                break;
 
        case TSTRUCT:
@@ -1199,32 +1223,32 @@ ok:
                }
                ot = dcommontype(s, ot, t);
                xt = ot - 3*widthptr;
-               ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
+               ot = arch.dsymptr(s, ot, s, ot+widthptr+2*widthint);
                ot = duintxx(s, ot, n, widthint);
                ot = duintxx(s, ot, n, widthint);
                for(t1=t->type; t1!=T; t1=t1->down) {
                        // ../../runtime/type.go:/structField
                        if(t1->sym && !t1->embedded) {
-                               ot = dgostringptr(s, ot, t1->sym->name);
+                               ot = arch.dgostringptr(s, ot, t1->sym->name);
                                if(exportname(t1->sym->name))
-                                       ot = dgostringptr(s, ot, nil);
+                                       ot = arch.dgostringptr(s, ot, nil);
                                else
                                        ot = dgopkgpath(s, ot, t1->sym->pkg);
                        } else {
-                               ot = dgostringptr(s, ot, nil);
+                               ot = arch.dgostringptr(s, ot, nil);
                                if(t1->type->sym != S && t1->type->sym->pkg == builtinpkg)
                                        ot = dgopkgpath(s, ot, localpkg);
                                else
-                                       ot = dgostringptr(s, ot, nil);
+                                       ot = arch.dgostringptr(s, ot, nil);
                        }
-                       ot = dsymptr(s, ot, dtypesym(t1->type), 0);
-                       ot = dgostrlitptr(s, ot, t1->note);
+                       ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
+                       ot = arch.dgostrlitptr(s, ot, t1->note);
                        ot = duintptr(s, ot, t1->width);        // field offset
                }
                break;
        }
        ot = dextratype(s, ot, t, xt);
-       ggloblsym(s, ot, dupok|RODATA);
+       arch.ggloblsym(s, ot, dupok|RODATA);
 
        // generate typelink.foo pointing at s = type.foo.
        // The linker will leave a table of all the typelinks for
@@ -1237,8 +1261,8 @@ ok:
                case TCHAN:
                case TMAP:
                        slink = typelinksym(t);
-                       dsymptr(slink, 0, s, 0);
-                       ggloblsym(slink, widthptr, dupok|RODATA);
+                       arch.dsymptr(slink, 0, s, 0);
+                       arch.ggloblsym(slink, widthptr, dupok|RODATA);
                }
        }
 
@@ -1302,7 +1326,7 @@ dumptypestructs(void)
                dimportpath(runtimepkg);
                if(flag_race)
                        dimportpath(racepkg);
-               dimportpath(mkpkg(strlit("main")));
+               dimportpath(mkpkg(newstrlit("main")));
        }
 }
 
@@ -1330,18 +1354,18 @@ dalgsym(Type *t)
                hashfunc = pkglookup(p, typepkg);
                free(p);
                ot = 0;
-               ot = dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0);
+               ot = arch.dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0);
                ot = duintxx(hashfunc, ot, t->width, widthptr); // size encoded in closure
-               ggloblsym(hashfunc, ot, DUPOK|RODATA);
+               arch.ggloblsym(hashfunc, ot, DUPOK|RODATA);
 
                // make equality closure
                p = smprint(".eqfunc%lld", t->width);
                eqfunc = pkglookup(p, typepkg);
                free(p);
                ot = 0;
-               ot = dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0);
+               ot = arch.dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0);
                ot = duintxx(eqfunc, ot, t->width, widthptr);
-               ggloblsym(eqfunc, ot, DUPOK|RODATA);
+               arch.ggloblsym(eqfunc, ot, DUPOK|RODATA);
        } else {
                // generate an alg table specific to this type
                s = typesymprefix(".alg", t);
@@ -1354,16 +1378,16 @@ dalgsym(Type *t)
                geneq(eq, t);
 
                // make Go funcs (closures) for calling hash and equal from Go
-               dsymptr(hashfunc, 0, hash, 0);
-               ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
-               dsymptr(eqfunc, 0, eq, 0);
-               ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
+               arch.dsymptr(hashfunc, 0, hash, 0);
+               arch.ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
+               arch.dsymptr(eqfunc, 0, eq, 0);
+               arch.ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
        }
        // ../../runtime/alg.go:/typeAlg
        ot = 0;
-       ot = dsymptr(s, ot, hashfunc, 0);
-       ot = dsymptr(s, ot, eqfunc, 0);
-       ggloblsym(s, ot, DUPOK|RODATA);
+       ot = arch.dsymptr(s, ot, hashfunc, 0);
+       ot = arch.dsymptr(s, ot, eqfunc, 0);
+       arch.ggloblsym(s, ot, DUPOK|RODATA);
        return s;
 }
 
@@ -1411,7 +1435,7 @@ gengcmask(Type *t, uint8 gcmask[16])
 
        // Unfold the mask for the GC bitmap format:
        // 4 bits per word, 2 high bits encode pointer info.
-       pos = (uint8*)gcmask;
+       pos = gcmask;
        nptr = (t->width+widthptr-1)/widthptr;
        half = 0;
        // If number of words is odd, repeat the mask.
@@ -1546,7 +1570,7 @@ gengcprog(Type *t, Sym **pgc0, Sym **pgc1)
        // Don't generate it if it's too large, runtime will unroll directly into GC bitmap.
        if(size <= MaxGCMask) {
                gc0 = typesymprefix(".gc", t);
-               ggloblsym(gc0, size, DUPOK|NOPTR);
+               arch.ggloblsym(gc0, size, DUPOK|NOPTR);
                *pgc0 = gc0;
        }
 
@@ -1556,7 +1580,7 @@ gengcprog(Type *t, Sym **pgc0, Sym **pgc1)
        xoffset = 0;
        gengcprog1(&g, t, &xoffset);
        ot = proggenfini(&g);
-       ggloblsym(gc1, ot, DUPOK|RODATA);
+       arch.ggloblsym(gc1, ot, DUPOK|RODATA);
        *pgc1 = gc1;
 }
 
index 463bb3a76da7896fe956709034db632976d82ecb..80550f856dd71b5515ef18a4162953a072a884e3 100644 (file)
@@ -39,19 +39,20 @@ func printsp()
 func printlock()
 func printunlock()
 
-func concatstring2(string, string) string
-func concatstring3(string, string, string) string
-func concatstring4(string, string, string, string) string
-func concatstring5(string, string, string, string, string) string
-func concatstrings([]string) string
+func concatstring2(*[32]byte, string, string) string
+func concatstring3(*[32]byte, string, string, string) string
+func concatstring4(*[32]byte, string, string, string, string) string
+func concatstring5(*[32]byte, string, string, string, string, string) string
+func concatstrings(*[32]byte, []string) string
 
 func cmpstring(string, string) int
 func eqstring(string, string) bool
-func intstring(int64) string
-func slicebytetostring([]byte) string
+func intstring(*[4]byte, int64) string
+func slicebytetostring(*[32]byte, []byte) string
 func slicebytetostringtmp([]byte) string
 func slicerunetostring([]rune) string
 func stringtoslicebyte(string) []byte
+func stringtoslicebytetmp(string) []byte
 func stringtoslicerune(string) []rune
 func stringiter(string, int) int
 func stringiter2(string, int) (retk int, retv rune)
index 8c24c122d6882fc04e5153555fca440ec8d49948..3d303eda09583493b7dfb20f7c7df5bc8a29cac3 100644 (file)
@@ -302,13 +302,13 @@ staticcopy(Node *l, Node *r, NodeList **out)
        case OLITERAL:
                if(iszero(r))
                        return 1;
-               gdata(l, r, l->type->width);
+               arch.gdata(l, r, l->type->width);
                return 1;
 
        case OADDR:
                switch(r->left->op) {
                case ONAME:
-                       gdata(l, r, l->type->width);
+                       arch.gdata(l, r, l->type->width);
                        return 1;
                }
                break;
@@ -322,7 +322,7 @@ staticcopy(Node *l, Node *r, NodeList **out)
                case OSTRUCTLIT:
                case OMAPLIT:
                        // copy pointer
-                       gdata(l, nod(OADDR, r->nname, N), l->type->width);
+                       arch.gdata(l, nod(OADDR, r->nname, N), l->type->width);
                        return 1;
                }
                break;
@@ -333,11 +333,11 @@ staticcopy(Node *l, Node *r, NodeList **out)
                        a = r->nname;
                        n1 = *l;
                        n1.xoffset = l->xoffset + Array_array;
-                       gdata(&n1, nod(OADDR, a, N), widthptr);
+                       arch.gdata(&n1, nod(OADDR, a, N), widthptr);
                        n1.xoffset = l->xoffset + Array_nel;
-                       gdata(&n1, r->right, widthint);
+                       arch.gdata(&n1, r->right, widthint);
                        n1.xoffset = l->xoffset + Array_cap;
-                       gdata(&n1, r->right, widthint);
+                       arch.gdata(&n1, r->right, widthint);
                        return 1;
                }
                // fall through
@@ -349,7 +349,7 @@ staticcopy(Node *l, Node *r, NodeList **out)
                        n1.xoffset = l->xoffset + e->xoffset;
                        n1.type = e->expr->type;
                        if(e->expr->op == OLITERAL)
-                               gdata(&n1, e->expr, n1.type->width);
+                               arch.gdata(&n1, e->expr, n1.type->width);
                        else {
                                ll = nod(OXXX, N, N);
                                *ll = n1;
@@ -394,14 +394,14 @@ staticassign(Node *l, Node *r, NodeList **out)
        case OLITERAL:
                if(iszero(r))
                        return 1;
-               gdata(l, r, l->type->width);
+               arch.gdata(l, r, l->type->width);
                return 1;
 
        case OADDR:
                if(stataddr(&nam, r->left)) {
                        n1 = *r;
                        n1.left = &nam;
-                       gdata(l, &n1, l->type->width);
+                       arch.gdata(l, &n1, l->type->width);
                        return 1;
                }
        
@@ -417,7 +417,7 @@ staticassign(Node *l, Node *r, NodeList **out)
                        // Init pointer.
                        a = staticname(r->left->type, 1);
                        r->nname = a;
-                       gdata(l, nod(OADDR, a, N), l->type->width);
+                       arch.gdata(l, nod(OADDR, a, N), l->type->width);
                        // Init underlying literal.
                        if(!staticassign(a, r->left, out))
                                *out = list(*out, nod(OAS, a, r->left));
@@ -444,11 +444,11 @@ staticassign(Node *l, Node *r, NodeList **out)
                        r->nname = a;
                        n1 = *l;
                        n1.xoffset = l->xoffset + Array_array;
-                       gdata(&n1, nod(OADDR, a, N), widthptr);
+                       arch.gdata(&n1, nod(OADDR, a, N), widthptr);
                        n1.xoffset = l->xoffset + Array_nel;
-                       gdata(&n1, r->right, widthint);
+                       arch.gdata(&n1, r->right, widthint);
                        n1.xoffset = l->xoffset + Array_cap;
-                       gdata(&n1, r->right, widthint);
+                       arch.gdata(&n1, r->right, widthint);
                        // Fall through to init underlying array.
                        l = a;
                }
@@ -462,7 +462,7 @@ staticassign(Node *l, Node *r, NodeList **out)
                        n1.xoffset = l->xoffset + e->xoffset;
                        n1.type = e->expr->type;
                        if(e->expr->op == OLITERAL)
-                               gdata(&n1, e->expr, n1.type->width);
+                               arch.gdata(&n1, e->expr, n1.type->width);
                        else {
                                a = nod(OXXX, N, N);
                                *a = n1;
@@ -1223,7 +1223,7 @@ stataddr(Node *nam, Node *n)
                if(l < 0)
                        break;
                // Check for overflow.
-               if(n->type->width != 0 && MAXWIDTH/n->type->width <= l)
+               if(n->type->width != 0 && arch.MAXWIDTH/n->type->width <= l)
                        break;
                nam->xoffset += l*n->type->width;
                nam->type = n->type;
@@ -1303,16 +1303,16 @@ gen_as_init(Node *n)
        case TPTR64:
        case TFLOAT32:
        case TFLOAT64:
-               gdata(&nam, nr, nr->type->width);
+               arch.gdata(&nam, nr, nr->type->width);
                break;
 
        case TCOMPLEX64:
        case TCOMPLEX128:
-               gdatacomplex(&nam, nr->val.u.cval);
+               arch.gdatacomplex(&nam, nr->val.u.cval);
                break;
 
        case TSTRING:
-               gdatastring(&nam, nr->val.u.sval);
+               arch.gdatastring(&nam, nr->val.u.sval);
                break;
        }
 
@@ -1320,7 +1320,7 @@ yes:
        return 1;
 
 slice:
-       gused(N); // in case the data is the dest of a goto
+       arch.gused(N); // in case the data is the dest of a goto
        nl = nr;
        if(nr == N || nr->op != OADDR)
                goto no;
@@ -1333,14 +1333,14 @@ slice:
                goto no;
 
        nam.xoffset += Array_array;
-       gdata(&nam, nl, types[tptr]->width);
+       arch.gdata(&nam, nl, types[tptr]->width);
 
        nam.xoffset += Array_nel-Array_array;
        nodconst(&nod1, types[TINT], nr->type->bound);
-       gdata(&nam, &nod1, widthint);
+       arch.gdata(&nam, &nod1, widthint);
 
        nam.xoffset += Array_cap-Array_nel;
-       gdata(&nam, &nod1, widthint);
+       arch.gdata(&nam, &nod1, widthint);
 
        goto yes;
 
index a8acae1fd270ee00c648776e2f53566f9ac4690c..3ed194ee8f4aa5faca8f33d6f245dd5f1da9a0c9 100644 (file)
@@ -708,7 +708,7 @@ static int
 methcmp(const void *va, const void *vb)
 {
        Type *a, *b;
-       int i;
+       int k;
        
        a = *(Type**)va;
        b = *(Type**)vb;
@@ -718,13 +718,13 @@ methcmp(const void *va, const void *vb)
                return -1;
        if(b->sym == S)
                return 1;
-       i = strcmp(a->sym->name, b->sym->name);
-       if(i != 0)
-               return i;
+       k = strcmp(a->sym->name, b->sym->name);
+       if(k != 0)
+               return k;
        if(!exportname(a->sym->name)) {
-               i = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s);
-               if(i != 0)
-                       return i;
+               k = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s);
+               if(k != 0)
+                       return k;
        }
        return 0;
 }
@@ -1979,7 +1979,7 @@ brcom(int a)
        case OLE:       return OGT;
        case OGE:       return OLT;
        }
-       fatal("brcom: no com for %A\n", a);
+       fatal("brcom: no com for %O\n", a);
        return a;
 }
 
@@ -1998,7 +1998,7 @@ brrev(int a)
        case OLE:       return OGE;
        case OGE:       return OLE;
        }
-       fatal("brcom: no rev for %A\n", a);
+       fatal("brcom: no rev for %O\n", a);
        return a;
 }
 
@@ -2121,10 +2121,10 @@ setmaxarg(Type *t, int32 extra)
 
        dowidth(t);
        w = t->argwid;
-       if(w >= MAXWIDTH)
+       if(w >= arch.MAXWIDTH)
                fatal("bad argwid %T", t);
        w += extra;
-       if(w >= MAXWIDTH)
+       if(w >= arch.MAXWIDTH)
                fatal("bad argwid %d + %T", extra, t);
        if(w > maxarg)
                maxarg = w;
@@ -2566,11 +2566,11 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
                // so no space cost to use them here.
                l = nil;
                v.ctype = CTSTR;
-               v.u.sval = strlit(rcvr->type->sym->pkg->name);  // package name
+               v.u.sval = newstrlit(rcvr->type->sym->pkg->name);  // package name
                l = list(l, nodlit(v));
-               v.u.sval = strlit(rcvr->type->sym->name);  // type name
+               v.u.sval = newstrlit(rcvr->type->sym->name);  // type name
                l = list(l, nodlit(v));
-               v.u.sval = strlit(method->sym->name);
+               v.u.sval = newstrlit(method->sym->name);
                l = list(l, nodlit(v));  // method name
                call = nod(OCALL, syslook("panicwrap", 0), N);
                call->list = l;
@@ -2617,7 +2617,16 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
                fn->dupok = 1;
        typecheck(&fn, Etop);
        typechecklist(fn->nbody, Etop);
+
+       // Set inl_nonlocal to whether we are calling a method on a
+       // type defined in a different package.  Checked in inlvar.
+       if(!methodrcvr->local)
+               inl_nonlocal = 1;
+
        inlcalls(fn);
+
+       inl_nonlocal = 0;
+
        curfn = nil;
        funccompile(fn, 0);
 }
@@ -3714,7 +3723,7 @@ mkpkg(Strlit *path)
 }
 
 Strlit*
-strlit(char *s)
+newstrlit(char *s)
 {
        Strlit *t;
        
index e1d8af8786deed1ddfadbaa0e0fe9e0ed4aa6624..ca5455d4790143829be8bbdcd2a88ab82ae495b1 100644 (file)
@@ -939,6 +939,8 @@ typecheckswitch(Node *n)
                                        // multiple entry type switch or default
                                        nvar->ntype = typenod(n->type);
                                }
+                               typecheck(&nvar, Erv | Easgn);
+                               ncase->nname = nvar;
                        }
                }
                typechecklist(ncase->nbody, Etop);
index 8a3b486bd6686013229c3a0acb9ab570ee5ba662..635d2c4170a3f966a9d5af4893ba8ccc5fda0466 100644 (file)
@@ -27,8 +27,7 @@ static void   typecheckas2(Node*);
 static void    typecheckas(Node*);
 static void    typecheckfunc(Node*);
 static void    checklvalue(Node*, char*);
-static void    checkassign(Node*);
-static void    checkassignlist(NodeList*);
+static void    checkassignlist(Node*, NodeList*);
 static void    stringtoarraylit(Node**);
 static Node*   resolve(Node*);
 static void    checkdefergo(Node*);
@@ -349,6 +348,8 @@ reswitch:
                goto ret;
 
        case ONAME:
+               if(n->decldepth == 0)
+                       n->decldepth = decldepth;
                if(n->etype != 0) {
                        ok |= Ecall;
                        goto ret;
@@ -522,8 +523,8 @@ reswitch:
        case OASOP:
                ok |= Etop;
                l = typecheck(&n->left, Erv);
-               checkassign(n->left);
                r = typecheck(&n->right, Erv);
+               checkassign(n, n->left);
                if(l->type == T || r->type == T)
                        goto error;
                op = n->etype;
@@ -586,7 +587,9 @@ reswitch:
                                l->typecheck = 1;
                                n->left = l;
                                t = l->type;
-                       } else if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
+                               goto converted;
+                       }
+                       if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
                                if(isinter(l->type) && !isinter(r->type) && algtype1(r->type, nil) == ANOEQ) {
                                        yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(r->type));
                                        goto error;
@@ -597,6 +600,7 @@ reswitch:
                                n->right = r;
                                t = r->type;
                        }
+               converted:
                        et = t->etype;
                }
                if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
@@ -739,11 +743,16 @@ reswitch:
                        goto error;
                checklvalue(n->left, "take the address of");
                r = outervalue(n->left);
-               for(l = n->left; l != r; l = l->left)
+               for(l = n->left; l != r; l = l->left) {
                        l->addrtaken = 1;
+                       if(l->closure)
+                               l->closure->addrtaken = 1;
+               }
                if(l->orig != l && l->op == ONAME)
                        fatal("found non-orig name node %N", l);
                l->addrtaken = 1;
+               if(l->closure)
+                       l->closure->addrtaken = 1;
                defaultlit(&n->left, T);
                l = n->left;
                if((t = l->type) == T)
@@ -1346,7 +1355,7 @@ reswitch:
                        goto error;
 
                // Unpack multiple-return result before type-checking.
-               if(istype(t, TSTRUCT)) {
+               if(istype(t, TSTRUCT) && t->funarg) {
                        t = t->type;
                        if(istype(t, TFIELD))
                                t = t->type;
@@ -1663,6 +1672,9 @@ reswitch:
        case OAS:
                ok |= Etop;
                typecheckas(n);
+               // Code that creates temps does not bother to set defn, so do it here.
+               if(n->left->op == ONAME && strncmp(n->left->sym->name, "autotmp_", 8) == 0)
+                       n->left->defn = n;
                goto ret;
 
        case OAS2:
@@ -1675,12 +1687,16 @@ reswitch:
        case ODCL:
        case OEMPTY:
        case OGOTO:
-       case OLABEL:
        case OXFALL:
        case OVARKILL:
                ok |= Etop;
                goto ret;
 
+       case OLABEL:
+               ok |= Etop;
+               decldepth++;
+               goto ret;
+
        case ODEFER:
                ok |= Etop;
                typecheck(&n->left, Etop|Erv);
@@ -1697,11 +1713,13 @@ reswitch:
        case OFOR:
                ok |= Etop;
                typechecklist(n->ninit, Etop);
+               decldepth++;
                typecheck(&n->ntest, Erv);
                if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
                        yyerror("non-bool %lN used as for condition", n->ntest);
                typecheck(&n->nincr, Etop);
                typechecklist(n->nbody, Etop);
+               decldepth--;
                goto ret;
 
        case OIF:
@@ -2346,7 +2364,7 @@ toomany:
  */
 
 static void
-fielddup(Node *n, Node *hash[], ulong nhash)
+fielddup(Node *n, Node **hash, ulong nhash)
 {
        uint h;
        char *s;
@@ -2367,7 +2385,7 @@ fielddup(Node *n, Node *hash[], ulong nhash)
 }
 
 static void
-keydup(Node *n, Node *hash[], ulong nhash)
+keydup(Node *n, Node **hash, ulong nhash)
 {
        uint h;
        ulong b;
@@ -2434,7 +2452,7 @@ keydup(Node *n, Node *hash[], ulong nhash)
 }
 
 static void
-indexdup(Node *n, Node *hash[], ulong nhash)
+indexdup(Node *n, Node **hash, ulong nhash)
 {
        uint h;
        Node *a;
@@ -2549,7 +2567,7 @@ static void
 typecheckcomplit(Node **np)
 {
        int bad, i, nerr;
-       int64 len;
+       int64 length;
        Node *l, *n, *norig, *r, **hash;
        NodeList *ll;
        Type *t, *f;
@@ -2603,7 +2621,7 @@ typecheckcomplit(Node **np)
        case TARRAY:
                nhash = inithash(n, &hash, autohash, nelem(autohash));
 
-               len = 0;
+               length = 0;
                i = 0;
                for(ll=n->list; ll; ll=ll->next) {
                        l = ll->n;
@@ -2626,11 +2644,11 @@ typecheckcomplit(Node **np)
                        if(i >= 0)
                                indexdup(l->left, hash, nhash);
                        i++;
-                       if(i > len) {
-                               len = i;
-                               if(t->bound >= 0 && len > t->bound) {
+                       if(i > length) {
+                               length = i;
+                               if(t->bound >= 0 && length > t->bound) {
                                        setlineno(l);
-                                       yyerror("array index %lld out of bounds [0:%lld]", len-1, t->bound);
+                                       yyerror("array index %lld out of bounds [0:%lld]", length-1, t->bound);
                                        t->bound = -1;  // no more errors
                                }
                        }
@@ -2642,9 +2660,9 @@ typecheckcomplit(Node **np)
                        l->right = assignconv(r, t->type, "array element");
                }
                if(t->bound == -100)
-                       t->bound = len;
+                       t->bound = length;
                if(t->bound < 0)
-                       n->right = nodintconst(len);
+                       n->right = nodintconst(length);
                n->op = OARRAYLIT;
                break;
 
@@ -2805,9 +2823,24 @@ checklvalue(Node *n, char *verb)
                yyerror("cannot %s %N", verb, n);
 }
 
-static void
-checkassign(Node *n)
+void
+checkassign(Node *stmt, Node *n)
 {
+       Node *r, *l;
+
+       // Variables declared in ORANGE are assigned on every iteration.
+       if(n->defn != stmt || stmt->op == ORANGE) {
+               r = outervalue(n);
+               for(l = n; l != r; l = l->left) {
+                       l->assigned = 1;
+                       if(l->closure)
+                               l->closure->assigned = 1;
+               }
+               l->assigned = 1;
+               if(l->closure)
+                       l->closure->assigned = 1;
+       }
+
        if(islvalue(n))
                return;
        if(n->op == OINDEXMAP) {
@@ -2823,10 +2856,10 @@ checkassign(Node *n)
 }
 
 static void
-checkassignlist(NodeList *l)
+checkassignlist(Node *stmt, NodeList *l)
 {
        for(; l; l=l->next)
-               checkassign(l->n);
+               checkassign(stmt, l->n);
 }
 
 // Check whether l and r are the same side effect-free expression,
@@ -2876,8 +2909,8 @@ typecheckas(Node *n)
        if(n->left->defn != n || n->left->ntype)
                typecheck(&n->left, Erv | Easgn);
 
-       checkassign(n->left);
        typecheck(&n->right, Erv);
+       checkassign(n, n->left);
        if(n->right && n->right->type != T) {
                if(n->left->type != T)
                        n->right = assignconv(n->right, n->left->type, "assignment");
@@ -2948,11 +2981,11 @@ typecheckas2(Node *n)
        }
        cl = count(n->list);
        cr = count(n->rlist);
-       checkassignlist(n->list);
        if(cl > 1 && cr == 1)
                typecheck(&n->rlist->n, Erv | Efnstruct);
        else
                typechecklist(n->rlist, Erv);
+       checkassignlist(n, n->list);
 
        if(cl == cr) {
                // easy
@@ -3043,6 +3076,7 @@ static void
 typecheckfunc(Node *n)
 {
        Type *t, *rcvr;
+       NodeList *l;
 
        typecheck(&n->nname, Erv | Easgn);
        if((t = n->nname->type) == T)
@@ -3052,6 +3086,10 @@ typecheckfunc(Node *n)
        rcvr = getthisx(t)->type;
        if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
                addmethod(n->shortname->sym, t, 1, n->nname->nointerface);
+
+       for(l=n->dcl; l; l=l->next)
+               if(l->n->op == ONAME && (l->n->class == PPARAM || l->n->class == PPARAMOUT))
+                       l->n->decldepth = 1;
 }
 
 static void
index ff08c0eef1d19c46be109ea30c3edc045da704b3..95d212e92bea7806d5abc2b7a0806eeea0e827bd 100644 (file)
@@ -27,7 +27,9 @@ unsafenmagic(Node *nn)
        fn = nn->left;
        args = nn->list;
 
-       if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S)
+       if(safemode || fn == N || fn->op != ONAME)
+               goto no;
+       if((s = fn->sym) == S)
                goto no;
        if(s->pkg != unsafepkg)
                goto no;
index 48dd17a6af129c51ae23f62133f2456a047b699e..efb283a1b8f659982503574c13233048e92c3f26 100644 (file)
@@ -35,6 +35,12 @@ static       int     bounded(Node*, int64);
 static Mpint   mpzero;
 static void    walkprintfunc(Node**, NodeList**);
 
+// The constant is known to runtime.
+enum
+{
+       tmpstringbufsize = 32,
+};
+
 void
 walk(Node *fn)
 {
@@ -417,7 +423,7 @@ walkexpr(Node **np, NodeList **init)
        int32 lno;
        Node *n, *fn, *n1, *n2;
        Sym *sym;
-       char buf[100], *p;
+       char buf[100], *p, *from, *to;
 
        n = *np;
 
@@ -672,14 +678,17 @@ walkexpr(Node **np, NodeList **init)
                        n1 = nod(OADDR, n->left, N);
                        r = n->right; // i.(T)
 
-                       strcpy(buf, "assertI2T");
+                       from = "I";
+                       to = "T";
                        if(isnilinter(r->left->type))
-                               buf[6] = 'E';
+                               from = "E";
                        if(isnilinter(r->type))
-                               buf[8] = 'E';
+                               to = "E";
                        else if(isinter(r->type))
-                               buf[8] = 'I';
+                               to = "I";
                        
+                       snprint(buf, sizeof buf, "assert%s2%s", from, to);
+
                        fn = syslook(buf, 1);
                        argtype(fn, r->left->type);
                        argtype(fn, r->type);
@@ -850,13 +859,15 @@ walkexpr(Node **np, NodeList **init)
                        n1 = nod(OADDR, n->list->n, N);
                n1->etype = 1; // addr does not escape
 
-               strcpy(buf, "assertI2T2");
+               from = "I";
+               to = "T";
                if(isnilinter(r->left->type))
-                       buf[6] = 'E';
+                       from = "E";
                if(isnilinter(r->type))
-                       buf[8] = 'E';
+                       to = "E";
                else if(isinter(r->type))
-                       buf[8] = 'I';
+                       to = "I";
+               snprint(buf, sizeof buf, "assert%s2%s2", from, to);
                
                fn = syslook(buf, 1);
                argtype(fn, r->left->type);
@@ -878,8 +889,8 @@ walkexpr(Node **np, NodeList **init)
        case OCONVIFACE:
                walkexpr(&n->left, init);
 
-               // Optimize convT2E as a two-word copy when T is uintptr-shaped.
-               if(isnilinter(n->type) && isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) {
+               // Optimize convT2E as a two-word copy when T is pointer-shaped.
+               if(isnilinter(n->type) && isdirectiface(n->left->type)) {
                        l = nod(OEFACE, typename(n->left->type), n->left);
                        l->type = n->type;
                        l->typecheck = n->typecheck;
@@ -890,20 +901,15 @@ walkexpr(Node **np, NodeList **init)
                // Build name of function: convI2E etc.
                // Not all names are possible
                // (e.g., we'll never generate convE2E or convE2I).
-               strcpy(buf, "conv");
-               p = buf+strlen(buf);
+               from = "T";
+               to = "I";
                if(isnilinter(n->left->type))
-                       *p++ = 'E';
+                       from = "E";
                else if(isinter(n->left->type))
-                       *p++ = 'I';
-               else
-                       *p++ = 'T';
-               *p++ = '2';
+                       from = "I";
                if(isnilinter(n->type))
-                       *p++ = 'E';
-               else
-                       *p++ = 'I';
-               *p = '\0';
+                       to = "E";
+               snprint(buf, sizeof buf, "conv%s2%s", from, to);
 
                fn = syslook(buf, 1);
                ll = nil;
@@ -921,13 +927,13 @@ walkexpr(Node **np, NodeList **init)
                                l->class = PEXTERN;
                                l->xoffset = 0;
                                sym->def = l;
-                               ggloblsym(sym, widthptr, DUPOK|NOPTR);
+                               arch.ggloblsym(sym, widthptr, DUPOK|NOPTR);
                        }
                        l = nod(OADDR, sym->def, N);
                        l->addable = 1;
                        ll = list(ll, l);
 
-                       if(isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) {
+                       if(isdirectiface(n->left->type)) {
                                /* For pointer types, we can make a special form of optimization
                                 *
                                 * These statements are put onto the expression init list:
@@ -989,7 +995,7 @@ walkexpr(Node **np, NodeList **init)
 
        case OCONV:
        case OCONVNOP:
-               if(thechar == '5') {
+               if(arch.thechar == '5') {
                        if(isfloat[n->left->type->etype]) {
                                if(n->type->etype == TINT64) {
                                        n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
@@ -1364,14 +1370,25 @@ walkexpr(Node **np, NodeList **init)
                goto ret;
 
        case ORUNESTR:
-               // sys_intstring(v)
-               n = mkcall("intstring", n->type, init,
-                       conv(n->left, types[TINT64]));
+               a = nodnil();
+               if(n->esc == EscNone) {
+                       t = aindex(nodintconst(4), types[TUINT8]);
+                       var = temp(t);
+                       a = nod(OADDR, var, N);
+               }
+               // intstring(*[4]byte, rune)
+               n = mkcall("intstring", n->type, init, a, conv(n->left, types[TINT64]));
                goto ret;
 
        case OARRAYBYTESTR:
-               // slicebytetostring([]byte) string;
-               n = mkcall("slicebytetostring", n->type, init, n->left);
+               a = nodnil();
+               if(n->esc == EscNone) {
+                       // Create temporary buffer for string on stack.
+                       t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]);
+                       a = nod(OADDR, temp(t), N);
+               }
+               // slicebytetostring(*[32]byte, []byte) string;
+               n = mkcall("slicebytetostring", n->type, init, a, n->left);
                goto ret;
 
        case OARRAYBYTESTRTMP:
@@ -1389,6 +1406,11 @@ walkexpr(Node **np, NodeList **init)
                n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING]));
                goto ret;
 
+       case OSTRARRAYBYTETMP:
+               // stringtoslicebytetmp(string) []byte;
+               n = mkcall("stringtoslicebytetmp", n->type, init, conv(n->left, types[TSTRING]));
+               goto ret;
+
        case OSTRARRAYRUNE:
                // stringtoslicerune(string) []rune
                n = mkcall("stringtoslicerune", n->type, init, n->left);
@@ -1579,7 +1601,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
                        l = tmp;
                }
 
-               a = nod(OAS, l, nodarg(r, fp));
+               a = nod(OAS, l, arch.nodarg(r, fp));
                a = convas(a, init);
                ullmancalc(a);
                if(a->ullman >= UINF) {
@@ -1632,7 +1654,7 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, Nod
                walkexpr(&n, init);
        }
 
-       a = nod(OAS, nodarg(l, fp), n);
+       a = nod(OAS, arch.nodarg(l, fp), n);
        nn = list(nn, convas(a, init));
        return nn;
 }
@@ -1712,7 +1734,7 @@ ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeL
        if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
                // optimization - can do block copy
                if(eqtypenoname(r->type, *nl)) {
-                       a = nodarg(*nl, fp);
+                       a = arch.nodarg(*nl, fp);
                        r = nod(OCONVNOP, r, N);
                        r->type = a->type;
                        nn = list1(convas(nod(OAS, a, r), init));
@@ -1749,7 +1771,7 @@ loop:
                // argument to a ddd parameter then it is
                // passed thru unencapsulated
                if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) {
-                       a = nod(OAS, nodarg(l, fp), r);
+                       a = nod(OAS, arch.nodarg(l, fp), r);
                        a = convas(a, init);
                        nn = list(nn, a);
                        goto ret;
@@ -1774,7 +1796,7 @@ loop:
                goto ret;
        }
 
-       a = nod(OAS, nodarg(l, fp), r);
+       a = nod(OAS, arch.nodarg(l, fp), r);
        a = convas(a, init);
        nn = list(nn, a);
 
@@ -1920,9 +1942,19 @@ callnew(Type *t)
 static int
 isstack(Node *n)
 {
+       Node *defn;
+
        while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
                n = n->left;
-       
+
+       // If n is *autotmp and autotmp = &foo, replace n with foo.
+       // We introduce such temps when initializing struct literals.
+       if(n->op == OIND && n->left->op == ONAME && strncmp(n->left->sym->name, "autotmp_", 8) == 0) {
+               defn = n->left->defn;
+               if(defn != N && defn->op == OAS && defn->right->op == OADDR)
+                       n = defn->right->left;
+       }
+
        switch(n->op) {
        case OINDREG:
                // OINDREG only ends up in walk if it's indirect of SP.
@@ -1946,7 +1978,7 @@ isglobal(Node *n)
 {
        while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
                n = n->left;
-       
+
        switch(n->op) {
        case ONAME:
                switch(n->class) {
@@ -2521,13 +2553,13 @@ paramstoheap(Type **argin, int out)
                v = t->nname;
                if(v && v->sym && v->sym->name[0] == '~' && v->sym->name[1] == 'r') // unnamed result
                        v = N;
-               // In precisestack mode, the garbage collector assumes results
+               // For precise stacks, the garbage collector assumes results
                // are always live, so zero them always.
-               if(out && (precisestack_enabled || (v == N && hasdefer))) {
+               if(out) {
                        // Defer might stop a panic and show the
                        // return values as they exist at the time of panic.
                        // Make sure to zero them on entry to the function.
-                       nn = list(nn, nod(OAS, nodarg(t, 1), N));
+                       nn = list(nn, nod(OAS, arch.nodarg(t, 1), N));
                }
                if(v == N || !(v->class & PHEAP))
                        continue;
@@ -2710,9 +2742,10 @@ writebarrierfn(char *name, Type *l, Type *r)
 static Node*
 addstr(Node *n, NodeList **init)
 {
-       Node *r, *cat, *slice;
+       Node *r, *cat, *slice, *buf;
        NodeList *args, *l;
        int c;
+       vlong sz;
        Type *t;
 
        // orderexpr rewrote OADDSTR to have a list of strings.
@@ -2720,8 +2753,23 @@ addstr(Node *n, NodeList **init)
        if(c < 2)
                yyerror("addstr count %d too small", c);
 
+       buf = nodnil();
+       if(n->esc == EscNone) {
+               sz = 0;
+               for(l=n->list; l != nil; l=l->next) {
+                       if(n->op == OLITERAL)
+                               sz += n->val.u.sval->len;
+               }
+               // Don't allocate the buffer if the result won't fit.
+               if(sz < tmpstringbufsize) {
+                       // Create temporary buffer for result string on stack.
+                       t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]);
+                       buf = nod(OADDR, temp(t), N);
+               }
+       }
+
        // build list of string arguments
-       args = nil;
+       args = list1(buf);
        for(l=n->list; l != nil; l=l->next)
                args = list(args, conv(l->n, types[TSTRING]));
 
@@ -2737,9 +2785,10 @@ addstr(Node *n, NodeList **init)
                t->bound = -1;
                slice = nod(OCOMPLIT, N, typenod(t));
                slice->alloc = n->alloc;
-               slice->list = args;
+               slice->list = args->next; // skip buf arg
+               args = list1(buf);
+               args = list(args, slice);
                slice->esc = EscNone;
-               args = list1(slice);
        }
        cat = syslook(namebuf, 1);
        r = nod(OCALL, cat, N);
@@ -3398,7 +3447,7 @@ walkrotate(Node **np)
        Node *l, *r;
        Node *n;
 
-       if(thechar == '9')
+       if(arch.thechar == '9')
                return;
        
        n = *np;
@@ -3526,7 +3575,7 @@ walkdiv(Node **np, NodeList **init)
        Magic m;
 
        // TODO(minux)
-       if(thechar == '9')
+       if(arch.thechar == '9')
                return;
 
        n = *np;
index 2d3ba41cba05e3dfbcbd8bd29f2fe661edf9fd26..d6abd6860576ea4bd80c11846caf82e4f3686003 100644 (file)
@@ -74,25 +74,27 @@ and test commands:
        -x
                print the commands.
 
-       -ccflags 'arg list'
-               arguments to pass on each 5c, 6c, or 8c compiler invocation.
        -compiler name
                name of compiler to use, as in runtime.Compiler (gccgo or gc).
        -gccgoflags 'arg list'
                arguments to pass on each gccgo compiler/linker invocation.
        -gcflags 'arg list'
-               arguments to pass on each 5g, 6g, or 8g compiler invocation.
+               arguments to pass on each 5g, 6g, 8g, or 9g compiler invocation.
        -installsuffix suffix
                a suffix to use in the name of the package installation directory,
                in order to keep output separate from default builds.
                If using the -race flag, the install suffix is automatically set to race
                or, if set explicitly, has _race appended to it.
        -ldflags 'flag list'
-               arguments to pass on each 5l, 6l, or 8l linker invocation.
+               arguments to pass on each 5l, 6l, 8l, or 9l linker invocation.
        -tags 'tag list'
                a list of build tags to consider satisfied during the build.
                For more information about build tags, see the description of
                build constraints in the documentation for the go/build package.
+       -toolexec 'cmd args'
+               a program to use to invoke toolchain programs like 5a, 5g, and 5l.
+               For example, instead of running 5g, the go command will run
+               'cmd args /path/to/5g <arguments for 5g>'.
 
 The list flags accept a space-separated list of strings. To embed spaces
 in an element in the list, surround it with either single or double quotes.
@@ -127,10 +129,10 @@ var buildI bool               // -i flag
 var buildO = cmdBuild.Flag.String("o", "", "output file")
 var buildWork bool           // -work flag
 var buildGcflags []string    // -gcflags flag
-var buildCcflags []string    // -ccflags flag
 var buildLdflags []string    // -ldflags flag
 var buildGccgoflags []string // -gccgoflags flag
 var buildRace bool           // -race flag
+var buildToolExec []string   // -toolexec flag
 
 var buildContext = build.Default
 var buildToolchain toolchain = noToolchain{}
@@ -178,12 +180,12 @@ func addBuildFlags(cmd *Command) {
        cmd.Flag.BoolVar(&buildX, "x", false, "")
        cmd.Flag.BoolVar(&buildWork, "work", false, "")
        cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
-       cmd.Flag.Var((*stringsFlag)(&buildCcflags), "ccflags", "")
        cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
        cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
        cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
        cmd.Flag.Var(buildCompiler{}, "compiler", "")
        cmd.Flag.BoolVar(&buildRace, "race", false, "")
+       cmd.Flag.Var((*stringsFlag)(&buildToolExec), "toolexec", "")
 }
 
 func addBuildFlagsNX(cmd *Command) {
@@ -1229,6 +1231,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
 //     go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go
 func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName string) error {
        return b.run(a.objdir, "cover "+a.p.ImportPath, nil,
+               buildToolExec,
                tool("cover"),
                "-mode", a.p.coverMode,
                "-var", varName,
@@ -1657,7 +1660,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
                gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
        }
 
-       args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
+       args := stringList(buildToolExec, tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
        if ofile == archive {
                args = append(args, "-pack")
        }
@@ -1681,7 +1684,7 @@ func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
        // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
        inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
        sfile = mkAbs(p.Dir, sfile)
-       args := []interface{}{tool(archChar + "a"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, sfile}
+       args := []interface{}{buildToolExec, tool(archChar + "a"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, sfile}
        if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
                return err
        }
@@ -1744,7 +1747,7 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
 
        // Need actual pack.
        cmdline[0] = tool("pack")
-       return b.run(p.Dir, p.ImportPath, nil, cmdline)
+       return b.run(p.Dir, p.ImportPath, nil, buildToolExec, cmdline)
 }
 
 func packInternal(b *builder, afile string, ofiles []string) error {
@@ -1852,7 +1855,7 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
                }
        }
        ldflags = append(ldflags, buildLdflags...)
-       return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg)
+       return b.run(".", p.ImportPath, nil, stringList(buildToolExec, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg))
 }
 
 func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
@@ -2241,7 +2244,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
                }
                objExt = "o"
        }
-       if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, p.CgoFiles); err != nil {
+       if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, p.CgoFiles); err != nil {
                return nil, nil, err
        }
        outGo = append(outGo, gofiles...)
@@ -2373,7 +2376,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
        if p.Standard && p.ImportPath == "runtime/cgo" {
                cgoflags = append(cgoflags, "-dynlinker") // record path to dynamic linker
        }
-       if err := b.run(p.Dir, p.ImportPath, nil, cgoExe, "-objdir", obj, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags); err != nil {
+       if err := b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-objdir", obj, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags); err != nil {
                return nil, nil, err
        }
        outGo = append(outGo, importGo)
@@ -2670,7 +2673,6 @@ func raceInit() {
        }
        buildGcflags = append(buildGcflags, "-race")
        buildLdflags = append(buildLdflags, "-race")
-       buildCcflags = append(buildCcflags, "-D", "RACE")
        if buildContext.InstallSuffix != "" {
                buildContext.InstallSuffix += "_"
        }
index d0d8a8a5b2e8d298b544e295360ebf7923ab1658..398f83d113b2126ea517e1f866db0c4d4cab0160 100644 (file)
@@ -93,25 +93,27 @@ and test commands:
        -x
                print the commands.
 
-       -ccflags 'arg list'
-               arguments to pass on each 5c, 6c, or 8c compiler invocation.
        -compiler name
                name of compiler to use, as in runtime.Compiler (gccgo or gc).
        -gccgoflags 'arg list'
                arguments to pass on each gccgo compiler/linker invocation.
        -gcflags 'arg list'
-               arguments to pass on each 5g, 6g, or 8g compiler invocation.
+               arguments to pass on each 5g, 6g, 8g, or 9g compiler invocation.
        -installsuffix suffix
                a suffix to use in the name of the package installation directory,
                in order to keep output separate from default builds.
                If using the -race flag, the install suffix is automatically set to race
                or, if set explicitly, has _race appended to it.
        -ldflags 'flag list'
-               arguments to pass on each 5l, 6l, or 8l linker invocation.
+               arguments to pass on each 5l, 6l, 8l, or 9l linker invocation.
        -tags 'tag list'
                a list of build tags to consider satisfied during the build.
                For more information about build tags, see the description of
                build constraints in the documentation for the go/build package.
+       -toolexec 'cmd args'
+               a program to use to invoke toolchain programs like 5a, 5g, and 5l.
+               For example, instead of running 5g, the go command will run
+               'cmd args /path/to/5g <arguments for 5g>'.
 
 The list flags accept a space-separated list of strings. To embed spaces
 in an element in the list, surround it with either single or double quotes.
@@ -1059,6 +1061,10 @@ control the execution of any test:
        -timeout t
            If a test runs longer than t, panic.
 
+       -trace trace.out
+           Write an execution trace to the specified file before exiting.
+           Writes test binary as -c would.
+
        -v
            Verbose output: log all tests as they are run. Also print all
            text from Log and Logf calls even if the test succeeds.
index 8736cce3e2a18f1a7096cd2bd7041d64481687f3..858feab24b77a904450d6d5ac859b91eeeee5e83 100644 (file)
@@ -25,6 +25,6 @@ func runFix(cmd *Command, args []string) {
                // Use pkg.gofiles instead of pkg.Dir so that
                // the command only applies to this package,
                // not to packages in subdirectories.
-               run(stringList(tool("fix"), relPaths(pkg.allgofiles)))
+               run(stringList(buildToolExec, tool("fix"), relPaths(pkg.allgofiles)))
        }
 }
index 50e0ca93bf42053466b83543c63cccf45bae90e4..01ca4b2acdf6cfef0040b25cb625884542c3dd3e 100644 (file)
@@ -223,7 +223,7 @@ func download(arg string, stk *importStack, getTestDeps bool) {
        // due to wildcard expansion.
        for _, p := range pkgs {
                if *getFix {
-                       run(stringList(tool("fix"), relPaths(p.allgofiles)))
+                       run(buildToolExec, stringList(tool("fix"), relPaths(p.allgofiles)))
 
                        // The imports might have changed, so reload again.
                        p = reloadPackage(arg, stk)
index 9e0f1f6c6c09ec11153277a9678d0d4939e8a335..ecb39d900ab5b96c2ecb256dcf8844adbd669407 100644 (file)
@@ -530,6 +530,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
                if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
                        importPaths = append(importPaths, "runtime/race")
                }
+               // On ARM with GOARM=5, everything depends on math for the link.
+               if p.ImportPath == "main" && goarch == "arm" {
+                       importPaths = append(importPaths, "math")
+               }
        }
 
        // Build list of full paths to all Go files in the package,
index c81e40639ecc5135c2562db381cc1ed3e16a8818..60f6b16c9a530a3e456cb69389e8106ead71ed58 100644 (file)
@@ -206,6 +206,10 @@ control the execution of any test:
        -timeout t
            If a test runs longer than t, panic.
 
+       -trace trace.out
+           Write an execution trace to the specified file before exiting.
+           Writes test binary as -c would.
+
        -v
            Verbose output: log all tests as they are run. Also print all
            text from Log and Logf calls even if the test succeeds.
index 6da74b99677f92be2f09f15809d13130d47d8a06..b3479e1b2338ec9a739d7d1b2ae8c89baebec19f 100644 (file)
@@ -42,6 +42,7 @@ var usageMessage = `Usage of go test:
   -run="": passes -test.run to test
   -short=false: passes -test.short to test
   -timeout=0: passes -test.timeout to test
+  -trace="": passes -test.trace to test
   -v=false: passes -test.v to test
 `
 
@@ -76,7 +77,6 @@ var testFlagDefn = []*testFlagSpec{
        {name: "x", boolVar: &buildX},
        {name: "i", boolVar: &buildI},
        {name: "work", boolVar: &buildWork},
-       {name: "ccflags"},
        {name: "gcflags"},
        {name: "exec"},
        {name: "ldflags"},
@@ -103,6 +103,7 @@ var testFlagDefn = []*testFlagSpec{
        {name: "run", passToTest: true},
        {name: "short", boolVar: new(bool), passToTest: true},
        {name: "timeout", passToTest: true},
+       {name: "trace", passToTest: true},
        {name: "v", boolVar: &testV, passToTest: true},
 }
 
@@ -163,11 +164,6 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                        if err != nil {
                                fatalf("invalid flag argument for -%s: %v", f.name, err)
                        }
-               case "ccflags":
-                       buildCcflags, err = splitQuotedFields(value)
-                       if err != nil {
-                               fatalf("invalid flag argument for -%s: %v", f.name, err)
-                       }
                case "gcflags":
                        buildGcflags, err = splitQuotedFields(value)
                        if err != nil {
@@ -192,7 +188,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                        testBench = true
                case "timeout":
                        testTimeout = value
-               case "blockprofile", "cpuprofile", "memprofile":
+               case "blockprofile", "cpuprofile", "memprofile", "trace":
                        testProfile = true
                        testNeedBinary = true
                case "coverpkg":
index 02ff54b2ac89ce93c42f57ce6b8ca739a848c05b..2634536afffc81aa1acea1d482c8b0e1b2cea456 100644 (file)
@@ -46,5 +46,5 @@ func runVetFiles(p *Package, files []string) {
        for i := range files {
                files[i] = filepath.Join(p.Dir, files[i])
        }
-       run(tool("vet"), relPaths(files))
+       run(buildToolExec, tool("vet"), relPaths(files))
 }
index 037263dce766b89f8fcd4c2c2f89cda9deaa593d..eedb2467890a60cc8069a324ae9d26c803f821ca 100644 (file)
@@ -7,7 +7,7 @@
 #include       "../../runtime/typekind.h"
 
 // Decoding the type.* symbols.         This has to be in sync with
-// ../../runtime/type.go, or more specificaly, with what
+// ../../runtime/type.go, or more specifically, with what
 // ../gc/reflect.c stuffs in these.
 
 static Reloc*
index b5331e829f1dc595d316659dc2c9da34403583da..061171ea0b12b47acd0c9abdd1b852404dc58679 100644 (file)
@@ -1658,7 +1658,7 @@ writelines(void)
                dwfunc->hash = varhash;  // enable indexing of children by name
                memset(varhash, 0, sizeof varhash);
                for(a = s->autom; a; a = a->link) {
-                       switch (a->type) {
+                       switch (a->name) {
                        case A_AUTO:
                                dt = DW_ABRV_AUTO;
                                offs = a->aoffset - PtrSize;
index 925274bfd34eec408a7f889216b61e55a60a574f..fa08bc5f031716e5a72a14038a423dd4224fa2ed 100644 (file)
@@ -1411,11 +1411,11 @@ genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
                for(a=s->autom; a; a=a->link) {
                        // Emit a or p according to actual offset, even if label is wrong.
                        // This avoids negative offsets, which cannot be encoded.
-                       if(a->type != A_AUTO && a->type != A_PARAM)
+                       if(a->name != A_AUTO && a->name != A_PARAM)
                                continue;
                        
                        // compute offset relative to FP
-                       if(a->type == A_PARAM)
+                       if(a->name == A_PARAM)
                                off = a->aoffset;
                        else
                                off = a->aoffset - PtrSize;
index d6135531bff762ec43edfbb928bc0a6df9234961..59902014df55fbfcf861d41c608e93e0a0d0f1fd 100644 (file)
@@ -4,6 +4,10 @@
 
 // Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
 // defined in FIPS 186-3.
+//
+// This implementation  derives the nonce from an AES-CTR CSPRNG keyed by
+// ChopMD(256, SHA2-512(priv.D || entropy || hash)). The CSPRNG key is IRO by
+// a result of Coron; the AES-CTR stream is IRO under standard assumptions.
 package ecdsa
 
 // References:
@@ -14,12 +18,19 @@ package ecdsa
 
 import (
        "crypto"
+       "crypto/aes"
+       "crypto/cipher"
        "crypto/elliptic"
+       "crypto/sha512"
        "encoding/asn1"
        "io"
        "math/big"
 )
 
+const (
+       aesIV = "IV for ECDSA CTR"
+)
+
 // PublicKey represents an ECDSA public key.
 type PublicKey struct {
        elliptic.Curve
@@ -123,6 +134,38 @@ func fermatInverse(k, N *big.Int) *big.Int {
 // pair of integers. The security of the private key depends on the entropy of
 // rand.
 func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
+       // Get max(log2(q) / 2, 256) bits of entropy from rand.
+       entropylen := (priv.Curve.Params().BitSize + 7) / 16
+       if entropylen > 32 {
+               entropylen = 32
+       }
+       entropy := make([]byte, entropylen)
+       _, err = rand.Read(entropy)
+       if err != nil {
+               return
+       }
+
+       // Initialize an SHA-512 hash context; digest ...
+       md := sha512.New()
+       md.Write(priv.D.Bytes()) // the private key,
+       md.Write(entropy)        // the entropy,
+       md.Write(hash)           // and the input hash;
+       key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
+       // which is an indifferentiable MAC.
+
+       // Create an AES-CTR instance to use as a CSPRNG.
+       block, err := aes.NewCipher(key)
+       if err != nil {
+               return nil, nil, err
+       }
+
+       // Create a CSPRNG that xors a stream of zeros with
+       // the output of the AES-CTR instance.
+       csprng := cipher.StreamReader{
+               R: zeroReader,
+               S: cipher.NewCTR(block, []byte(aesIV)),
+       }
+
        // See [NSA] 3.4.1
        c := priv.PublicKey.Curve
        N := c.Params().N
@@ -130,7 +173,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
        var k, kInv *big.Int
        for {
                for {
-                       k, err = randFieldElement(c, rand)
+                       k, err = randFieldElement(c, csprng)
                        if err != nil {
                                r = nil
                                return
@@ -187,3 +230,17 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
        x.Mod(x, N)
        return x.Cmp(r) == 0
 }
+
+type zr struct {
+       io.Reader
+}
+
+// Read replaces the contents of dst with zeros.
+func (z *zr) Read(dst []byte) (n int, err error) {
+       for i := range dst {
+               dst[i] = 0
+       }
+       return len(dst), nil
+}
+
+var zeroReader = &zr{}
index 0c064319324e09d7b99334d16b1e3cafbd7bd48a..169944dfb27b2207cd1076aed95dc2a037a21328 100644 (file)
@@ -72,6 +72,78 @@ func TestSignAndVerify(t *testing.T) {
        testSignAndVerify(t, elliptic.P521(), "p521")
 }
 
+func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
+       priv, _ := GenerateKey(c, rand.Reader)
+
+       hashed := []byte("testing")
+       r0, s0, err := Sign(zeroReader, priv, hashed)
+       if err != nil {
+               t.Errorf("%s: error signing: %s", tag, err)
+               return
+       }
+
+       hashed = []byte("testing...")
+       r1, s1, err := Sign(zeroReader, priv, hashed)
+       if err != nil {
+               t.Errorf("%s: error signing: %s", tag, err)
+               return
+       }
+
+       if s0.Cmp(s1) == 0 {
+               // This should never happen.
+               t.Errorf("%s: the signatures on two different messages were the same")
+       }
+
+       if r0.Cmp(r1) == 0 {
+               t.Errorf("%s: the nonce used for two diferent messages was the same")
+       }
+}
+
+func TestNonceSafety(t *testing.T) {
+       testNonceSafety(t, elliptic.P224(), "p224")
+       if testing.Short() {
+               return
+       }
+       testNonceSafety(t, elliptic.P256(), "p256")
+       testNonceSafety(t, elliptic.P384(), "p384")
+       testNonceSafety(t, elliptic.P521(), "p521")
+}
+
+func testINDCCA(t *testing.T, c elliptic.Curve, tag string) {
+       priv, _ := GenerateKey(c, rand.Reader)
+
+       hashed := []byte("testing")
+       r0, s0, err := Sign(rand.Reader, priv, hashed)
+       if err != nil {
+               t.Errorf("%s: error signing: %s", tag, err)
+               return
+       }
+
+       r1, s1, err := Sign(rand.Reader, priv, hashed)
+       if err != nil {
+               t.Errorf("%s: error signing: %s", tag, err)
+               return
+       }
+
+       if s0.Cmp(s1) == 0 {
+               t.Errorf("%s: two signatures of the same message produced the same result")
+       }
+
+       if r0.Cmp(r1) == 0 {
+               t.Errorf("%s: two signatures of the same message produced the same nonce")
+       }
+}
+
+func TestINDCCA(t *testing.T) {
+       testINDCCA(t, elliptic.P224(), "p224")
+       if testing.Short() {
+               return
+       }
+       testINDCCA(t, elliptic.P256(), "p256")
+       testINDCCA(t, elliptic.P384(), "p384")
+       testINDCCA(t, elliptic.P521(), "p521")
+}
+
 func fromHex(s string) *big.Int {
        r, ok := new(big.Int).SetString(s, 16)
        if !ok {
index 226e06d68d63acb4b314b38210e747565a85f65c..4b4695ad8e354caaa84190d3c6c9577e04cbb69e 100644 (file)
@@ -5,6 +5,7 @@
 package tls
 
 import (
+       "crypto"
        "crypto/aes"
        "crypto/cipher"
        "crypto/des"
@@ -60,28 +61,31 @@ type cipherSuite struct {
        ivLen  int
        ka     func(version uint16) keyAgreement
        // flags is a bitmask of the suite* values, above.
-       flags  int
-       cipher func(key, iv []byte, isRead bool) interface{}
-       mac    func(version uint16, macKey []byte) macFunction
-       aead   func(key, fixedNonce []byte) cipher.AEAD
+       flags     int
+       cipher    func(key, iv []byte, isRead bool) interface{}
+       mac       func(version uint16, macKey []byte) macFunction
+       aead      func(key, fixedNonce []byte) cipher.AEAD
+       tls12Hash crypto.Hash
 }
 
 var cipherSuites = []*cipherSuite{
        // Ciphersuite order is chosen so that ECDHE comes before plain RSA
        // and RC4 comes before AES (because of the Lucky13 attack).
-       {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
-       {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
-       {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil},
-       {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherRC4, macSHA1, nil},
-       {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
-       {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
-       {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
-       {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
-       {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil},
-       {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
-       {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
-       {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
-       {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
+       {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA256},
+       {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA256},
+       {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA384},
+       {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA384},
+       {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil, crypto.SHA256},
+       {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherRC4, macSHA1, nil, crypto.SHA256},
+       {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil, crypto.SHA256},
+       {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil, crypto.SHA256},
+       {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil, crypto.SHA256},
+       {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil, crypto.SHA256},
+       {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil, crypto.SHA256},
+       {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil, crypto.SHA256},
+       {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil, crypto.SHA256},
+       {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil, crypto.SHA256},
+       {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil, crypto.SHA256},
 }
 
 func cipherRC4(key, iv []byte, isRead bool) interface{} {
@@ -267,6 +271,8 @@ const (
        TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA      uint16 = 0xc014
        TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   uint16 = 0xc02f
        TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
+       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384   uint16 = 0xc030
+       TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
 
        // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
        // that the client is doing version fallback. See
index 7f662e9c9f3501f5ded4b276dda1edaea958d926..3ebf7db4e30b40003fc67a596a28bad03c855c14 100644 (file)
@@ -168,7 +168,7 @@ NextCipherSuite:
                serverHello:  serverHello,
                hello:        hello,
                suite:        suite,
-               finishedHash: newFinishedHash(c.vers),
+               finishedHash: newFinishedHash(c.vers, suite.tls12Hash),
                session:      session,
        }
 
@@ -457,7 +457,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
                c.writeRecord(recordTypeHandshake, certVerify.marshal())
        }
 
-       hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.hello.random, hs.serverHello.random)
+       hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite.tls12Hash, preMasterSecret, hs.hello.random, hs.serverHello.random)
        return nil
 }
 
@@ -465,7 +465,7 @@ func (hs *clientHandshakeState) establishKeys() error {
        c := hs.c
 
        clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
-               keysFromMasterSecret(c.vers, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+               keysFromMasterSecret(c.vers, hs.suite.tls12Hash, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
        var clientCipher, serverCipher interface{}
        var clientHash, serverHash macFunction
        if hs.suite.cipher != nil {
index e5eaa7de20830b91f48dc6a05fbf7108208c8c89..96b63cddf22a0704caeb90eb1daa7ccb0e19ad26 100644 (file)
@@ -127,7 +127,6 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
        // connection.
        var tcpConn net.Conn
        for i := uint(0); i < 5; i++ {
-               var err error
                tcpConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{
                        IP:   net.IPv4(127, 0, 0, 1),
                        Port: serverPort,
@@ -137,7 +136,7 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
                }
                time.Sleep((1 << i) * 5 * time.Millisecond)
        }
-       if tcpConn == nil {
+       if err != nil {
                close(stdin)
                out.WriteTo(os.Stdout)
                cmd.Process.Kill()
@@ -190,7 +189,7 @@ func (test *clientTest) run(t *testing.T, write bool) {
        doneChan := make(chan bool)
        go func() {
                if _, err := client.Write([]byte("hello\n")); err != nil {
-                       t.Logf("Client.Write failed: %s", err)
+                       t.Errorf("Client.Write failed: %s", err)
                }
                if test.validate != nil {
                        if err := test.validate(client.ConnectionState()); err != nil {
@@ -311,6 +310,16 @@ func TestHandshakeClientECDHEECDSAAESGCM(t *testing.T) {
        runClientTestTLS12(t, test)
 }
 
+func TestHandshakeClientAES256GCMSHA384(t *testing.T) {
+       test := &clientTest{
+               name:    "ECDHE-ECDSA-AES256-GCM-SHA384",
+               command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES256-GCM-SHA384"},
+               cert:    testECDSACertificate,
+               key:     testECDSAPrivateKey,
+       }
+       runClientTestTLS12(t, test)
+}
+
 func TestHandshakeClientCertRSA(t *testing.T) {
        config := *testConfig
        cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
index 8f0ed1f70b47affd49dbd5b102d06eee3273b41a..a46133439d42eed5b15b822d05d37f1220017e92 100644 (file)
@@ -47,6 +47,8 @@ func (c *Conn) serverHandshake() error {
        if err != nil {
                return err
        }
+       hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite.tls12Hash)
+       hs.finishedHash.Write(hs.clientHello.marshal())
 
        // For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
        if isResume {
@@ -111,9 +113,6 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
        }
        c.haveVers = true
 
-       hs.finishedHash = newFinishedHash(c.vers)
-       hs.finishedHash.Write(hs.clientHello.marshal())
-
        hs.hello = new(serverHelloMsg)
 
        supportedCurve := false
@@ -248,7 +247,8 @@ func (hs *serverHandshakeState) checkForResumption() bool {
        }
 
        var ok bool
-       if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok {
+       var sessionTicket = append([]uint8{}, hs.clientHello.sessionTicket...)
+       if hs.sessionState, ok = c.decryptTicket(sessionTicket); !ok {
                return false
        }
 
@@ -463,13 +463,12 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 
                hs.finishedHash.Write(certVerify.marshal())
        }
-
        preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
        if err != nil {
                c.sendAlert(alertHandshakeFailure)
                return err
        }
-       hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.clientHello.random, hs.hello.random)
+       hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite.tls12Hash, preMasterSecret, hs.clientHello.random, hs.hello.random)
 
        return nil
 }
@@ -478,7 +477,7 @@ func (hs *serverHandshakeState) establishKeys() error {
        c := hs.c
 
        clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
-               keysFromMasterSecret(c.vers, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+               keysFromMasterSecret(c.vers, hs.suite.tls12Hash, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
 
        var clientCipher, serverCipher interface{}
        var clientHash, serverHash macFunction
index 62051160120e161788b4a59c2564133921f94891..46a90d3a365cb5122318fffa720cf9712874a2d4 100644 (file)
@@ -564,6 +564,14 @@ func TestHandshakeServerAESGCM(t *testing.T) {
        runServerTestTLS12(t, test)
 }
 
+func TestHandshakeServerAES256GCMSHA384(t *testing.T) {
+       test := &serverTest{
+               name:    "RSA-AES256-GCM-SHA384",
+               command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384"},
+       }
+       runServerTestTLS12(t, test)
+}
+
 func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
        config := *testConfig
        config.Certificates = make([]Certificate, 1)
index fb8b3ab4d1e398045b6cdde4c48ed7b8618dfc5a..58eb97ff6922d9c12c97f6c9fd3019381807cdef 100644 (file)
@@ -9,7 +9,6 @@ import (
        "crypto/hmac"
        "crypto/md5"
        "crypto/sha1"
-       "crypto/sha256"
        "hash"
 )
 
@@ -64,13 +63,15 @@ func prf10(result, secret, label, seed []byte) {
        }
 }
 
-// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
-func prf12(result, secret, label, seed []byte) {
-       labelAndSeed := make([]byte, len(label)+len(seed))
-       copy(labelAndSeed, label)
-       copy(labelAndSeed[len(label):], seed)
-
-       pHash(result, secret, labelAndSeed, sha256.New)
+// prf12New returns a function implementing the TLS 1.2 pseudo-random function,
+// as defined in RFC 5246, section 5, using the given hash.
+func prf12New(tls12Hash crypto.Hash) func(result, secret, label, seed []byte) {
+       return func(result, secret, label, seed []byte) {
+               labelAndSeed := make([]byte, len(label)+len(seed))
+               copy(labelAndSeed, label)
+               copy(labelAndSeed[len(label):], seed)
+               pHash(result, secret, labelAndSeed, tls12Hash.New)
+       }
 }
 
 // prf30 implements the SSL 3.0 pseudo-random function, as defined in
@@ -117,14 +118,14 @@ var keyExpansionLabel = []byte("key expansion")
 var clientFinishedLabel = []byte("client finished")
 var serverFinishedLabel = []byte("server finished")
 
-func prfForVersion(version uint16) func(result, secret, label, seed []byte) {
+func prfForVersion(version uint16, tls12Hash crypto.Hash) func(result, secret, label, seed []byte) {
        switch version {
        case VersionSSL30:
                return prf30
        case VersionTLS10, VersionTLS11:
                return prf10
        case VersionTLS12:
-               return prf12
+               return prf12New(tls12Hash)
        default:
                panic("unknown version")
        }
@@ -132,26 +133,26 @@ func prfForVersion(version uint16) func(result, secret, label, seed []byte) {
 
 // masterFromPreMasterSecret generates the master secret from the pre-master
 // secret. See http://tools.ietf.org/html/rfc5246#section-8.1
-func masterFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serverRandom []byte) []byte {
+func masterFromPreMasterSecret(version uint16, tls12Hash crypto.Hash, preMasterSecret, clientRandom, serverRandom []byte) []byte {
        var seed [tlsRandomLength * 2]byte
        copy(seed[0:len(clientRandom)], clientRandom)
        copy(seed[len(clientRandom):], serverRandom)
        masterSecret := make([]byte, masterSecretLength)
-       prfForVersion(version)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+       prfForVersion(version, tls12Hash)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
        return masterSecret
 }
 
 // keysFromMasterSecret generates the connection keys from the master
 // secret, given the lengths of the MAC key, cipher key and IV, as defined in
 // RFC 2246, section 6.3.
-func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+func keysFromMasterSecret(version uint16, tls12Hash crypto.Hash, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
        var seed [tlsRandomLength * 2]byte
        copy(seed[0:len(clientRandom)], serverRandom)
        copy(seed[len(serverRandom):], clientRandom)
 
        n := 2*macLen + 2*keyLen + 2*ivLen
        keyMaterial := make([]byte, n)
-       prfForVersion(version)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+       prfForVersion(version, tls12Hash)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
        clientMAC = keyMaterial[:macLen]
        keyMaterial = keyMaterial[macLen:]
        serverMAC = keyMaterial[:macLen]
@@ -166,11 +167,11 @@ func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRand
        return
 }
 
-func newFinishedHash(version uint16) finishedHash {
+func newFinishedHash(version uint16, tls12Hash crypto.Hash) finishedHash {
        if version >= VersionTLS12 {
-               return finishedHash{sha256.New(), sha256.New(), nil, nil, version}
+               return finishedHash{tls12Hash.New(), tls12Hash.New(), nil, nil, version, prfForVersion(version, tls12Hash)}
        }
-       return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), version}
+       return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), version, prfForVersion(version, tls12Hash)}
 }
 
 // A finishedHash calculates the hash of a set of handshake messages suitable
@@ -184,6 +185,7 @@ type finishedHash struct {
        serverMD5 hash.Hash
 
        version uint16
+       prf     func(result, secret, label, seed []byte)
 }
 
 func (h finishedHash) Write(msg []byte) (n int, err error) {
@@ -242,12 +244,12 @@ func (h finishedHash) clientSum(masterSecret []byte) []byte {
        out := make([]byte, finishedVerifyLength)
        if h.version >= VersionTLS12 {
                seed := h.client.Sum(nil)
-               prf12(out, masterSecret, clientFinishedLabel, seed)
+               h.prf(out, masterSecret, clientFinishedLabel, seed)
        } else {
                seed := make([]byte, 0, md5.Size+sha1.Size)
                seed = h.clientMD5.Sum(seed)
                seed = h.client.Sum(seed)
-               prf10(out, masterSecret, clientFinishedLabel, seed)
+               h.prf(out, masterSecret, clientFinishedLabel, seed)
        }
        return out
 }
@@ -262,12 +264,12 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte {
        out := make([]byte, finishedVerifyLength)
        if h.version >= VersionTLS12 {
                seed := h.server.Sum(nil)
-               prf12(out, masterSecret, serverFinishedLabel, seed)
+               h.prf(out, masterSecret, serverFinishedLabel, seed)
        } else {
                seed := make([]byte, 0, md5.Size+sha1.Size)
                seed = h.serverMD5.Sum(seed)
                seed = h.server.Sum(seed)
-               prf10(out, masterSecret, serverFinishedLabel, seed)
+               h.prf(out, masterSecret, serverFinishedLabel, seed)
        }
        return out
 }
index a9b6c9e4c79d8bc60aff785e161b09d0b5172c9e..1d21741f6208fb7502d9b2a271034475c5a22d60 100644 (file)
@@ -5,6 +5,7 @@
 package tls
 
 import (
+       "crypto"
        "encoding/hex"
        "testing"
 )
@@ -35,6 +36,7 @@ func TestSplitPreMasterSecret(t *testing.T) {
 
 type testKeysFromTest struct {
        version                    uint16
+       hash                       crypto.Hash
        preMasterSecret            string
        clientRandom, serverRandom string
        masterSecret               string
@@ -49,13 +51,13 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
                clientRandom, _ := hex.DecodeString(test.clientRandom)
                serverRandom, _ := hex.DecodeString(test.serverRandom)
 
-               masterSecret := masterFromPreMasterSecret(test.version, in, clientRandom, serverRandom)
+               masterSecret := masterFromPreMasterSecret(test.version, test.hash, in, clientRandom, serverRandom)
                if s := hex.EncodeToString(masterSecret); s != test.masterSecret {
                        t.Errorf("#%d: bad master secret %s, want %s", i, s, test.masterSecret)
                        continue
                }
 
-               clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
+               clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, test.hash, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
                clientMACString := hex.EncodeToString(clientMAC)
                serverMACString := hex.EncodeToString(serverMAC)
                clientKeyString := hex.EncodeToString(clientKey)
@@ -73,6 +75,7 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
 var testKeysFromTests = []testKeysFromTest{
        {
                VersionTLS10,
+               crypto.SHA1,
                "0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
                "4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
                "4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
@@ -86,6 +89,7 @@ var testKeysFromTests = []testKeysFromTest{
        },
        {
                VersionTLS10,
+               crypto.SHA1,
                "03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
                "4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
                "4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
@@ -99,6 +103,7 @@ var testKeysFromTests = []testKeysFromTest{
        },
        {
                VersionTLS10,
+               crypto.SHA1,
                "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
                "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
                "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
@@ -112,6 +117,7 @@ var testKeysFromTests = []testKeysFromTest{
        },
        {
                VersionSSL30,
+               crypto.SHA1,
                "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
                "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
                "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
index 00722cba945f875effd1353c2f1eebb6011c38fa..588090a798786df6a652539fbff989a02bc090ff 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 03 46  |....Y...U..S...F|
-00000010  0f 84 c4 cb 55 ef 85 f6  4f d7 0e e1 4b 10 d4 bb  |....U...O...K...|
-00000020  35 87 2d f3 d7 18 ec 4e  95 4b f4 20 28 82 94 d9  |5.-....N.K. (...|
-00000030  df c4 fc ee 21 23 c1 e2  76 3e 7b 09 af 2c 39 23  |....!#..v>{..,9#|
-00000040  f8 46 6c 31 88 42 f0 79  de 37 2b 00 c0 09 00 00  |.Fl1.B.y.7+.....|
+00000000  16 03 01 00 59 02 00 00  55 03 01 43 60 d4 9a c4  |....Y...U..C`...|
+00000010  28 6c b9 56 de 43 c6 e4  05 f5 ab 71 87 ef ae b8  |(l.V.C.....q....|
+00000020  cf da 13 b5 98 b7 ab cc  35 44 48 20 2c 7f 10 60  |........5DH ,..`|
+00000030  98 a8 13 4d a8 7c d6 45  48 aa c5 aa f2 f7 bb 98  |...M.|.EH.......|
+00000040  53 6e 5d 3f 56 de 17 ba  c9 a8 d1 81 c0 09 00 00  |Sn]?V...........|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 4f  |*............A.O|
-00000280  47 16 72 98 9e 9f 2e 8e  78 e9 0f fe 95 83 7b aa  |G.r.....x.....{.|
-00000290  e5 3d c0 7d cf 83 bd 22  0b fd 48 f1 a7 49 a5 7d  |.=.}..."..H..I.}|
-000002a0  8e 0c 83 7f e1 2d 71 03  cc 90 09 ab f7 35 81 48  |.....-q......5.H|
-000002b0  a4 1e 7d 87 21 23 12 58  2c 47 f3 af c7 6c 71 00  |..}.!#.X,G...lq.|
-000002c0  8a 30 81 87 02 42 00 b4  03 38 60 43 d9 32 ef 64  |.0...B...8`C.2.d|
-000002d0  5a 9c 91 95 0d 10 21 53  c7 78 f8 bf 50 ed 13 5d  |Z.....!S.x..P..]|
-000002e0  c3 e7 71 d6 11 04 f1 e4  9d ce 17 99 8d 1a 87 1f  |..q.............|
-000002f0  cb dd f8 1b ae cd bc 4a  77 ab 7c 50 bf 73 c3 ea  |.......Jw.|P.s..|
-00000300  d6 df 88 56 f6 b1 03 83  02 41 66 3d fb 4e 7e af  |...V.....Af=.N~.|
-00000310  4e c1 60 fe 09 fa 7e 74  99 66 7f de b4 b2 74 89  |N.`...~t.f....t.|
-00000320  1c a4 cf 74 1a 55 a5 be  74 f9 36 21 3d ae c8 c3  |...t.U..t.6!=...|
-00000330  24 8e ad db a3 26 67 8f  98 27 e3 93 ee d9 5c fb  |$....&g..'....\.|
-00000340  85 82 e2 13 c3 50 ab e9  f6 39 2b 16 03 01 00 0e  |.....P...9+.....|
-00000350  0d 00 00 06 03 01 02 40  00 00 0e 00 00 00        |.......@......|
+00000270  2a 16 03 01 00 d4 0c 00  00 d0 03 00 17 41 04 ef  |*............A..|
+00000280  89 a9 4f 05 2f ee ee c9  cb 73 d0 57 cc c9 45 ca  |..O./....s.W..E.|
+00000290  d8 61 4d 0d 5b cf 83 c1  19 bd 6d a7 49 de ba 6c  |.aM.[.....m.I..l|
+000002a0  63 b5 88 c9 4d a8 44 9f  f2 ec 3c 88 d6 ec 20 f3  |c...M.D...<... .|
+000002b0  6f 25 cd 99 0a 42 71 19  67 6d dd 65 6a 52 f8 00  |o%...Bq.gm.ejR..|
+000002c0  89 30 81 86 02 41 42 4f  70 eb fa 2a bf 06 0f 16  |.0...ABOp..*....|
+000002d0  62 d8 25 d5 d4 c4 bb 2e  d1 f9 84 3b a0 57 78 7f  |b.%........;.Wx.|
+000002e0  fe 29 50 49 e1 f0 a1 c6  1f 87 98 7f d5 63 b9 72  |.)PI.........c.r|
+000002f0  f5 2f 70 a8 bc 5f 45 22  57 07 99 e1 f8 51 30 b0  |./p.._E"W....Q0.|
+00000300  2f 6e 6d 8c b5 4a 34 02  41 05 86 7d e4 16 b2 bf  |/nm..J4.A..}....|
+00000310  70 de 5a 69 43 6e e2 ec  a2 4f 97 b0 ae 99 07 08  |p.ZiCn...O......|
+00000320  32 d2 9d f4 56 80 71 d7  96 94 36 59 b5 95 7f 10  |2...V.q...6Y....|
+00000330  8a aa a5 90 db cc a3 47  02 53 b1 9e 2d c7 db bc  |.......G.S..-...|
+00000340  58 1d b5 01 07 9c 9c 74  b5 a7 16 03 01 00 0e 0d  |X......t........|
+00000350  00 00 06 03 01 02 40 00  00 0e 00 00 00           |......@......|
 >>> Flow 3 (client to server)
 00000000  16 03 01 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
 00000230  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 00000240  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
 00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 01 00 90 0f  |.h.A.Vk.Z.......|
-00000260  00 00 8c 00 8a 30 81 87  02 42 00 c6 85 8e 06 b7  |.....0...B......|
-00000270  04 04 e9 cd 9e 3e cb 66  23 95 b4 42 9c 64 81 39  |.....>.f#..B.d.9|
-00000280  05 3f b5 21 f8 28 af 60  6b 4d 3d ba a1 4b 5e 77  |.?.!.(.`kM=..K^w|
-00000290  ef e7 59 28 fe 1d c1 27  a2 ff a8 de 33 48 b3 c1  |..Y(...'....3H..|
-000002a0  85 6a 42 9b f9 7e 7e 31  c2 e5 bd 66 02 41 4b 49  |.jB..~~1...f.AKI|
-000002b0  c6 cd 02 e3 83 f7 03 50  18 6d b4 c9 51 02 c0 ab  |.......P.m..Q...|
-000002c0  87 bc e0 3e 4b 89 53 3a  e2 65 89 97 02 c1 87 f1  |...>K.S:.e......|
-000002d0  67 d0 f2 06 28 4e 51 4e  fd f0 01 be 41 3c 52 42  |g...(NQN....A<RB|
-000002e0  10 44 73 88 3e 44 24 bb  2e 77 01 77 6f a8 ac 14  |.Ds.>D$..w.wo...|
-000002f0  03 01 00 01 01 16 03 01  00 30 a3 da 45 22 96 83  |.........0..E"..|
-00000300  59 90 e9 6b ec 3b 77 50  05 89 e6 0c 61 d1 1d 2b  |Y..k.;wP....a..+|
-00000310  da d4 49 bf b9 c6 dd ad  c3 9c 82 bd 53 62 e8 57  |..I.........Sb.W|
-00000320  a4 6a e7 9f b1 d5 39 77  88 6d                    |.j....9w.m|
+00000260  00 00 8c 00 8a 30 81 87  02 42 01 0f 51 63 8f 2e  |.....0...B..Qc..|
+00000270  fa 3a 3a 15 a9 4b 7f 04  c9 23 73 be 44 f5 28 37  |.::..K...#s.D.(7|
+00000280  2c 00 34 20 86 e6 94 00  bf 11 40 ec de a9 54 03  |,.4 ......@...T.|
+00000290  dc 9d 19 67 39 22 5e c4  55 3b f4 b6 9a a8 4f 6e  |...g9"^.U;....On|
+000002a0  21 20 f0 9a 9a 10 a8 01  3a 20 ac 8b 02 41 34 ad  |! ......: ...A4.|
+000002b0  89 da ec cc 8b b7 d7 5a  6c fe 6f 13 fa 58 40 2e  |.......Zl.o..X@.|
+000002c0  a6 bf 32 69 97 a5 21 44  7c 3d d2 51 b3 b3 bb 9c  |..2i..!D|=.Q....|
+000002d0  ed fa 5d bd 09 f3 c0 71  ee 3d 98 24 13 e1 e2 c8  |..]....q.=.$....|
+000002e0  e7 75 fc ac c3 61 9a f3  47 b2 7c 97 01 99 2d 14  |.u...a..G.|...-.|
+000002f0  03 01 00 01 01 16 03 01  00 30 d7 d1 c3 57 a3 f8  |.........0...W..|
+00000300  71 eb 97 9d a8 ac 15 88  f4 b4 f7 e6 8c 2e eb fe  |q...............|
+00000310  25 d1 77 82 20 06 d1 36  20 3d bc 82 ab 30 4d 85  |%.w. ..6 =...0M.|
+00000320  1b 7b c2 9e 60 8f 7e 05  73 3e                    |.{..`.~.s>|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 a4 45 dd 99 df  |..........0.E...|
-00000010  66 ae f5 c7 bd 1a eb 6a  ff ac a6 38 14 81 b5 07  |f......j...8....|
-00000020  86 24 80 f1 09 59 ad 33  3d 43 ed 9e 43 b1 1e 9f  |.$...Y.3=C..C...|
-00000030  bd 8c b3 e0 41 83 a1 34  91 c5 a1                 |....A..4...|
+00000000  14 03 01 00 01 01 16 03  01 00 30 7a 5e 9e 4b 7d  |..........0z^.K}|
+00000010  44 8f 70 5f fd a9 50 a9  d8 52 cf 89 f9 b0 08 ea  |D.p_..P..R......|
+00000020  bb a2 80 44 73 09 da 81  98 33 b1 44 88 0c ef e3  |...Ds....3.D....|
+00000030  c6 8b 2f 28 9b e1 f7 59  26 9c 54                 |../(...Y&.T|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 ae e3 ae  7f 2d e3 a2 f7 1b 4e 69  |.... ....-....Ni|
-00000010  cb 18 c6 68 42 f8 de 61  92 4c fa d6 19 7c 8c 09  |...hB..a.L...|..|
-00000020  82 e2 f2 32 19 17 03 01  00 20 2a 77 65 1f c1 fd  |...2..... *we...|
-00000030  5e 37 b7 15 f6 1f 4c 7f  5f 89 52 b4 32 27 4d 17  |^7....L._.R.2'M.|
-00000040  33 c6 e8 50 ac 70 c8 b9  2d 0a 15 03 01 00 20 e0  |3..P.p..-..... .|
-00000050  cb ce 07 80 55 a0 46 ca  a7 25 4c 5f 9d 7c 73 37  |....U.F..%L_.|s7|
-00000060  de 72 6d 36 a8 e4 be fd  2a e7 f8 8d 14 80 b7     |.rm6....*......|
+00000000  17 03 01 00 20 f1 61 1b  1f 1e 91 85 c1 ce 93 38  |.... .a........8|
+00000010  6b d0 ee c5 2e 00 f0 42  e3 a9 f0 82 92 a6 9b df  |k......B........|
+00000020  ac 3c e3 18 aa 17 03 01  00 20 2a 72 5b 1a 57 10  |.<....... *r[.W.|
+00000030  cb 64 c4 5f b2 2d f9 03  41 ca 8d 72 93 f7 ae 19  |.d._.-..A..r....|
+00000040  37 3a 8c d5 f5 ad d8 83  20 9c 15 03 01 00 20 f9  |7:...... ..... .|
+00000050  53 1a 9f 34 27 91 f1 3f  7c 33 eb 1f 5d 0e bc 89  |S..4'..?|3..]...|
+00000060  5e 08 20 9e 5c e4 a0 70  8d 03 63 c6 9a 62 14     |^. .\..p..c..b.|
index c0be82491e250c453a659cc65e06a0506c251267..84632afbfb8a35b6b5d5c25eb71f1e380ddecbeb 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 53 04 f1 02 ed  |....Q...M..S....|
-00000010  86 9c 56 84 5a d3 7d d7  f3 4e 6f 2c 69 0d f0 59  |..V.Z.}..No,i..Y|
-00000020  a5 d1 de 2d 03 2f dd 63  c3 ab fa 20 30 d6 5a 24  |...-./.c... 0.Z$|
-00000030  5c 31 67 36 8d 4c 43 e1  64 c4 8a 2c a5 fd 39 92  |\1g6.LC.d..,..9.|
-00000040  c5 6f 58 47 a3 fe 63 14  98 92 11 90 00 05 00 00  |.oXG..c.........|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 8b 2e 89 18 f7  |....Q...M.......|
+00000010  c8 0f 16 f0 81 91 e7 88  7c e8 20 a2 de 0e 28 ce  |........|. ...(.|
+00000020  f3 12 54 68 79 ec b2 05  0b d1 74 20 bc c6 22 fd  |..Thy.....t ..".|
+00000030  45 00 2c a6 bf 65 38 fd  2f 6e 71 9c b8 14 7a 0a  |E.,..e8./nq...z.|
+00000040  5b 8e 71 c9 b6 32 99 41  f7 43 91 ad 00 05 00 00  |[.q..2.A.C......|
 00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
 00000270  bd 77 82 6f 23 b6 e0 bd  a2 92 b7 3a ac e8 56 f1  |.w.o#......:..V.|
 00000280  af 54 5e 46 87 e9 3b 33  e7 b8 28 b7 d6 c8 90 35  |.T^F..;3..(....5|
 00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 01 00 90 0f  |..C.0oUN.p......|
-000002a0  00 00 8c 00 8a 30 81 87  02 42 00 c6 85 8e 06 b7  |.....0...B......|
-000002b0  04 04 e9 cd 9e 3e cb 66  23 95 b4 42 9c 64 81 39  |.....>.f#..B.d.9|
-000002c0  05 3f b5 21 f8 28 af 60  6b 4d 3d ba a1 4b 5e 77  |.?.!.(.`kM=..K^w|
-000002d0  ef e7 59 28 fe 1d c1 27  a2 ff a8 de 33 48 b3 c1  |..Y(...'....3H..|
-000002e0  85 6a 42 9b f9 7e 7e 31  c2 e5 bd 66 02 41 4b 49  |.jB..~~1...f.AKI|
-000002f0  c6 cd 02 e3 83 f7 03 50  18 6d b4 c9 51 02 c0 ab  |.......P.m..Q...|
-00000300  87 bc e0 3e 4b 89 53 3a  e2 65 89 97 02 c1 87 f1  |...>K.S:.e......|
-00000310  67 d0 f2 06 28 4e 51 4e  fd f0 01 47 e7 c9 d9 23  |g...(NQN...G...#|
-00000320  21 6b 87 d2 55 e3 c9 f7  eb 86 d5 1e 50 df d5 14  |!k..U.......P...|
-00000330  03 01 00 01 01 16 03 01  00 24 95 62 42 be 90 39  |.........$.bB..9|
-00000340  68 ae f5 77 47 21 14 b9  ac ee 81 2d e3 9e c7 34  |h..wG!.....-...4|
-00000350  3a 00 5c c9 12 1d c0 5a  7c e7 ef e0 cd fd        |:.\....Z|.....|
+000002a0  00 00 8c 00 8a 30 81 87  02 41 59 10 98 e1 27 39  |.....0...AY...'9|
+000002b0  62 42 32 98 8d 04 14 6a  95 27 b0 3b 62 46 f3 8e  |bB2....j.'.;bF..|
+000002c0  5a 86 28 4f 3d a8 49 44  85 d8 8d 02 15 52 72 4f  |Z.(O=.ID.....RrO|
+000002d0  87 4c 16 73 98 f6 6f 93  bb 9a c3 11 be 7f 35 81  |.L.s..o.......5.|
+000002e0  52 9f 17 6e 10 5e 33 ad  c9 24 ad 02 42 01 c3 cb  |R..n.^3..$..B...|
+000002f0  e7 4f a9 c5 b1 5f ab c7  d2 42 92 05 a0 9b ca a6  |.O..._...B......|
+00000300  33 ad 5c bd 22 94 c2 f7  d3 b4 3a 25 ae b4 bc c4  |3.\.".....:%....|
+00000310  f3 b6 38 8a a2 aa e7 e8  55 d9 8a 32 1f c7 05 a0  |..8.....U..2....|
+00000320  55 58 46 aa 78 37 d8 c6  57 bc 9b 2a 31 b4 15 14  |UXF.x7..W..*1...|
+00000330  03 01 00 01 01 16 03 01  00 24 fd 98 09 ef 50 d2  |.........$....P.|
+00000340  a5 90 9c 55 eb aa 67 33  24 a3 1e db 4b 2e 6b cb  |...U..g3$...K.k.|
+00000350  b5 17 8b c0 c1 2e a6 c6  49 7d 84 0c d7 96        |........I}....|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 ea 98 c0 fb 86  |..........$.....|
-00000010  87 7a 2e e1 c7 68 61 3e  5b cc da 1f d6 7b ab 5a  |.z...ha>[....{.Z|
-00000020  a0 ae a2 cf d0 54 44 19  12 db 75 2b 8c 73 8c     |.....TD...u+.s.|
+00000000  14 03 01 00 01 01 16 03  01 00 24 b3 e4 bb 70 4b  |..........$...pK|
+00000010  21 71 de 80 27 48 7f 15  60 23 65 a5 3f 94 b3 e7  |!q..'H..`#e.?...|
+00000020  91 3a fe 4c 70 60 22 6c  67 ca 85 85 23 f4 83     |.:.Lp`"lg...#..|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a f3 28 77  31 33 4c b3 7c 4b 75 61  |......(w13L.|Kua|
-00000010  38 69 6b ae c9 36 ab 2e  56 16 29 6a 9a 00 2f 15  |8ik..6..V.)j../.|
-00000020  03 01 00 16 6b ed 68 18  ed ff 44 39 9b 4a e4 a2  |....k.h...D9.J..|
-00000030  cd 79 ef 2a 3e 5a 4d b1  5d 56                    |.y.*>ZM.]V|
+00000000  17 03 01 00 1a d6 19 a3  b8 82 ff dc 69 4f ee 36  |............iO.6|
+00000010  2b 95 c8 c0 e6 d8 84 ea  e7 d9 40 39 10 ba 33 15  |+.........@9..3.|
+00000020  03 01 00 16 85 1b 41 3b  e8 71 07 3c 6e 9f b9 e0  |......A;.q.<n...|
+00000030  0d 67 77 d8 b2 84 9f 76  05 9e                    |.gw....v..|
index 3e6dbc271a963c1856a9097a8a0feb32b2a94927..9dfec4d6fa97e4ff0cda2f1fbccaeb3adbc20300 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 02 4f  |....Y...U..S...O|
-00000010  73 06 2d 72 41 36 a1 b2  d3 50 97 55 8c c5 f1 43  |s.-rA6...P.U...C|
-00000020  37 1f 1a 2a fe 51 70 0b  2f 25 9e 20 50 61 86 80  |7..*.Qp./%. Pa..|
-00000030  9a 9c 6d 6f c9 ea 5c ce  0c b7 7c ce e3 be d0 e5  |..mo..\...|.....|
-00000040  be d0 c4 80 78 c3 c7 17  0c 2d 8e c8 c0 09 00 00  |....x....-......|
+00000000  16 03 01 00 59 02 00 00  55 03 01 60 fd 2a c3 90  |....Y...U..`.*..|
+00000010  e3 1d e7 96 4a e7 2c d3  c7 35 80 67 7f 7e 57 8f  |....J.,..5.g.~W.|
+00000020  f1 9c 65 35 36 cd e3 98  ae ed 1e 20 58 3f 0d 2f  |..e56...... X?./|
+00000030  77 10 eb 1a b6 03 96 09  f3 6d 22 9f 4b 96 21 06  |w........m".K.!.|
+00000040  84 d2 da 9a 14 09 b4 d8  be 62 45 91 c0 09 00 00  |.........bE.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 01 00 d6 0c 00  00 d2 03 00 17 41 04 b1  |*............A..|
-00000280  0f 0f 4a 18 ed 25 32 b3  a3 19 ed 4b 61 b6 eb e4  |..J..%2....Ka...|
-00000290  d3 f7 77 13 ac 9f 60 c7  8d 6d cb f1 ee 99 1a 71  |..w...`..m.....q|
-000002a0  68 aa d3 a7 70 7f 38 d0  f6 23 ab 9a f6 dd 19 4f  |h...p.8..#.....O|
-000002b0  ce 10 ef d5 cf 64 85 2f  75 f6 20 06 4b f0 b9 00  |.....d./u. .K...|
-000002c0  8b 30 81 88 02 42 01 00  b9 6b 80 91 59 0a 48 3f  |.0...B...k..Y.H?|
-000002d0  72 16 96 8f 21 2c 28 e4  6d 03 74 66 35 16 7d ec  |r...!,(.m.tf5.}.|
-000002e0  c7 08 9b 52 b5 05 d9 38  d8 b7 51 42 a7 4a 9f 9b  |...R...8..QB.J..|
-000002f0  1a 37 14 de c5 f5 16 96  83 81 58 d3 a6 1e ce 8a  |.7........X.....|
-00000300  bc 19 47 30 fe c5 85 55  02 42 01 4f 61 59 68 85  |..G0...U.B.OaYh.|
-00000310  c7 64 23 22 f6 83 53 cc  58 38 25 b5 ce 74 c1 68  |.d#"..S.X8%..t.h|
-00000320  9f 32 72 33 ea c9 62 e0  26 63 92 e3 5f 34 10 0b  |.2r3..b.&c.._4..|
-00000330  3c d5 83 fe 9f 67 69 ef  33 6b 19 c1 ec d6 6c 35  |<....gi.3k....l5|
-00000340  89 33 17 d3 9d 93 e2 e5  6e 89 9a a1 16 03 01 00  |.3......n.......|
-00000350  0e 0d 00 00 06 03 01 02  40 00 00 0e 00 00 00     |........@......|
+00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 b2  |*............A..|
+00000280  dd fb 15 7b ac 21 6d 89  5f 18 69 18 d7 b2 ef f7  |...{.!m._.i.....|
+00000290  b6 83 99 2d 06 98 38 72  5b 58 b6 6d 09 d3 00 2e  |...-..8r[X.m....|
+000002a0  a0 06 02 46 4d c6 d0 1f  a8 cb c9 74 7e e1 1e 0d  |...FM......t~...|
+000002b0  f4 36 2b 38 b7 ab 29 bd  39 73 a8 b8 55 2a b1 00  |.6+8..).9s..U*..|
+000002c0  8a 30 81 87 02 41 7d 26  e5 9f 73 c4 eb ea d7 59  |.0...A}&..s....Y|
+000002d0  ab b8 7a b9 b7 f6 70 6d  9e 8b a6 4a c2 fc 73 5a  |..z...pm...J..sZ|
+000002e0  78 2c 27 ef ff 52 91 4a  74 12 43 2f 49 d7 55 18  |x,'..R.Jt.C/I.U.|
+000002f0  9f 72 c6 a6 25 0a 2a 94  47 5d 66 08 13 e8 ef af  |.r..%.*.G]f.....|
+00000300  df 12 fa 70 91 86 87 02  42 00 dc 98 50 24 fa 27  |...p....B...P$.'|
+00000310  95 cb 01 c1 ee e9 18 7e  5b b0 b1 e3 f9 e2 56 ff  |.......~[.....V.|
+00000320  d7 d7 41 f3 f1 b1 28 1f  a1 19 62 29 74 1d 0e 4d  |..A...(...b)t..M|
+00000330  57 3f 99 50 c6 a8 78 57  4d 36 1a 42 6b 64 1c 14  |W?.P..xWM6.Bkd..|
+00000340  e8 36 c6 a8 cc f7 75 f7  f7 7d c9 16 03 01 00 0e  |.6....u..}......|
+00000350  0d 00 00 06 03 01 02 40  00 00 0e 00 00 00        |.......@......|
 >>> Flow 3 (client to server)
 00000000  16 03 01 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
 00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
 00000220  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000230  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000240  a6 b5 68 1a 41 03 56 6b  dc 5a 89 16 03 01 00 86  |..h.A.Vk.Z......|
-00000250  0f 00 00 82 00 80 20 2c  5a 08 3a 00 33 50 19 b2  |...... ,Z.:.3P..|
-00000260  0f ba 6c 76 7f 5c 92 e2  78 55 3e 32 32 bb 33 bc  |..lv.\..xU>22.3.|
-00000270  ab a9 34 e0 83 cf 82 cd  9e 6b 3f 9d e6 49 61 29  |..4......k?..Ia)|
-00000280  8b b4 ed e8 12 cd a9 52  86 11 48 64 08 61 72 8d  |.......R..Hd.ar.|
-00000290  d6 6a ac 42 cc e4 07 5f  08 56 9f 2f c5 35 d3 9b  |.j.B..._.V./.5..|
-000002a0  e9 0d 91 82 c0 e9 bb 9f  a9 8f df 96 85 08 9a 69  |...............i|
-000002b0  a4 93 b3 72 37 ba f9 b1  a4 0b b0 9f 43 6a 15 ec  |...r7.......Cj..|
-000002c0  79 b8 fd 9c 1f 5f 0d 2c  56 33 c7 15 d5 4a b7 82  |y...._.,V3...J..|
-000002d0  ea 44 80 20 c5 80 14 03  01 00 01 01 16 03 01 00  |.D. ............|
-000002e0  30 c9 c0 7c d7 57 d3 00  ab 87 eb 78 56 6b a1 69  |0..|.W.....xVk.i|
-000002f0  1d fa ec ae 38 f3 ef 5d  49 19 0d 4b f0 73 63 af  |....8..]I..K.sc.|
-00000300  89 b6 cb 76 cf fb b9 c1  99 98 06 0a 54 67 a0 6e  |...v........Tg.n|
-00000310  e7                                                |.|
+00000250  0f 00 00 82 00 80 1c 5e  19 d9 f9 4f 97 8d 92 a5  |.......^...O....|
+00000260  73 87 be 46 df 6b 39 be  2c f2 13 73 da a4 04 47  |s..F.k9.,..s...G|
+00000270  44 11 72 6f ea a9 2d ea  fc 6a aa e4 e5 85 d3 60  |D.ro..-..j.....`|
+00000280  3c aa 2f 81 dd bc 4f 7b  bb 77 58 f7 78 15 6f 21  |<./...O{.wX.x.o!|
+00000290  7c c4 bb 95 af 85 49 ab  3f 68 cf bd 18 be e1 3e  ||.....I.?h.....>|
+000002a0  9e 59 64 47 39 37 d5 cf  ba 84 44 2a 4b 8b 2d cb  |.YdG97....D*K.-.|
+000002b0  36 24 87 c4 c5 ba 96 91  b2 b3 d0 30 87 b3 7e 2d  |6$.........0..~-|
+000002c0  8f 51 0e 47 af c6 0c 33  48 fd 37 d8 bb f2 95 2c  |.Q.G...3H.7....,|
+000002d0  72 ca c6 3c ab 8d 14 03  01 00 01 01 16 03 01 00  |r..<............|
+000002e0  30 52 e6 b2 ba 4c be e7  e9 ad bf 9b 86 2d fb 90  |0R...L.......-..|
+000002f0  1c 90 86 55 7e 3e 75 63  df 38 54 d6 20 25 37 ae  |...U~>uc.8T. %7.|
+00000300  ab 4f ab 85 84 03 61 f7  eb 56 bd 1a 17 f3 da f6  |.O....a..V......|
+00000310  6d                                                |m|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 20 db fd ed ed  |..........0 ....|
-00000010  7c d5 bf 8f 06 3b 86 1b  c1 60 7d a4 74 e9 a6 c9  ||....;...`}.t...|
-00000020  f5 7c c7 f4 65 91 06 d5  53 88 d7 57 a4 22 b6 1f  |.|..e...S..W."..|
-00000030  f1 02 e9 79 36 e6 a1 22  51 3a 4c                 |...y6.."Q:L|
+00000000  14 03 01 00 01 01 16 03  01 00 30 ae 6b 02 f3 d5  |..........0.k...|
+00000010  ff 91 fb 05 87 22 c6 f7  ac a8 83 d8 2a 10 89 69  |....."......*..i|
+00000020  e8 16 83 a9 5c 64 14 d2  15 40 94 ac 14 15 8f 75  |....\d...@.....u|
+00000030  27 19 a7 75 e9 8d e7 48  8b 62 0c                 |'..u...H.b.|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 00 66 51  6a 14 ca ea e2 21 48 74  |.... .fQj....!Ht|
-00000010  c4 c1 6e b9 8b 23 af 7c  33 c9 00 f8 0b ec ab 35  |..n..#.|3......5|
-00000020  e7 42 0a d1 ae 17 03 01  00 20 00 1c 6d 60 75 5d  |.B....... ..m`u]|
-00000030  b3 fb 40 2e e0 b7 0d 48  f4 87 ac d4 bf ea 01 0d  |..@....H........|
-00000040  fe 10 0d 05 04 43 6b 19  ed f2 15 03 01 00 20 f8  |.....Ck....... .|
-00000050  03 ac 62 4b 1f db 2e d2  4e 00 c3 a4 57 3c 0a 62  |..bK....N...W<.b|
-00000060  05 a0 ef bd 2b 9b 9a 63  27 72 d7 d8 f1 8d 84     |....+..c'r.....|
+00000000  17 03 01 00 20 09 0e f5  bb d9 7a 54 db 9e e6 22  |.... .....zT..."|
+00000010  ea 9d 98 7e e6 af ba b1  dc c3 55 ad cc 4a f0 fa  |...~......U..J..|
+00000020  0d 3a 9f 49 80 17 03 01  00 20 d0 96 b0 1d 37 42  |.:.I..... ....7B|
+00000030  0d 03 64 1d 87 24 84 ff  f1 62 28 e3 6b 86 a1 54  |..d..$...b(.k..T|
+00000040  f2 65 5e ae 01 db 59 77  b1 c3 15 03 01 00 20 a0  |.e^...Yw...... .|
+00000050  88 b0 60 07 a6 05 13 dd  cd f4 7c e7 57 09 b1 98  |..`.......|.W...|
+00000060  bf b1 93 f1 02 cb 86 67  36 c5 e2 a8 81 c8 8f     |.......g6......|
index 94e686004f99d3b86261d90a3cbbc97463be5643..776b3d670b907e9f2eb7e9f8422e2e17470513a6 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 53 04 f1 02 73  |....Q...M..S...s|
-00000010  ee 5f 70 a4 aa 0d be d7  46 a3 25 3f e3 5d ef 7b  |._p.....F.%?.].{|
-00000020  73 49 7c b6 82 4d 99 2f  31 fc 8b 20 2d a3 33 7c  |sI|..M./1.. -.3||
-00000030  a5 c3 85 86 ba 61 4d 05  b0 5e d3 5e 88 6e c3 4b  |.....aM..^.^.n.K|
-00000040  95 d3 e9 67 f1 96 24 58  7a 6f e6 c5 00 05 00 00  |...g..$Xzo......|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 ba 22 84 d4 ec  |....Q...M..."...|
+00000010  cb 49 cc 28 17 ea 00 19  6f 89 6f 4a c7 36 32 f2  |.I.(....o.oJ.62.|
+00000020  db da de 60 a7 93 b9 4e  64 9e ee 20 48 76 9f d5  |...`...Nd.. Hv..|
+00000030  c9 8a 74 95 ef 4b 7c 92  fd da 04 88 76 d3 6f 5a  |..t..K|.....v.oZ|
+00000040  b5 7f fa f3 3a d0 c3 b2  b1 19 09 a6 00 05 00 00  |....:...........|
 00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
 00000260  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000270  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000280  35 d4 1c 43 d1 30 6f 55  4e 0a 70 16 03 01 00 86  |5..C.0oUN.p.....|
-00000290  0f 00 00 82 00 80 0f 4c  d2 b2 f0 94 6d 61 d1 2c  |.......L....ma.,|
-000002a0  db 6f 79 03 bd 40 b2 d2  1d 61 ef 83 1b 4a 0c 7b  |.oy..@...a...J.{|
-000002b0  c5 73 1e 1a 81 e7 67 0a  d6 aa 2d 04 04 cc 0e 4b  |.s....g...-....K|
-000002c0  2e da 96 7f 15 6c 05 ee  c4 53 7e 33 89 28 7d db  |.....l...S~3.(}.|
-000002d0  a1 77 43 ba a3 51 a9 1c  b9 f5 ec 9a 8d eb 2c 46  |.wC..Q........,F|
-000002e0  5c 33 59 6b 16 af de f4  9b 80 76 a3 22 30 5d bb  |\3Yk......v."0].|
-000002f0  02 b9 77 96 8a db 36 9f  54 95 00 d8 58 e1 aa 04  |..w...6.T...X...|
-00000300  98 c9 0c 32 ae 62 81 12  0c f6 1b 76 c6 58 a7 8c  |...2.b.....v.X..|
-00000310  0e d8 b7 8e ed 0f 14 03  01 00 01 01 16 03 01 00  |................|
-00000320  24 1d c0 20 02 2d da 69  54 29 8c ff af 5c 56 a8  |$.. .-.iT)...\V.|
-00000330  eb d0 09 95 29 8f 52 8c  e2 7b 9f 36 3e 47 a0 33  |....).R..{.6>G.3|
-00000340  2e 63 a2 24 93                                    |.c.$.|
+00000290  0f 00 00 82 00 80 20 f0  61 14 6c 45 b1 29 c0 56  |...... .a.lE.).V|
+000002a0  9d 26 45 01 50 d5 56 04  6d cd 66 79 81 e0 cf 5c  |.&E.P.V.m.fy...\|
+000002b0  ee bc 39 f0 a1 a1 3a 43  9d 1f 8f a2 52 6e 5c 77  |..9...:C....Rn\w|
+000002c0  90 2e b3 56 37 ec 78 bd  79 53 a2 a4 8e 7d 49 13  |...V7.x.yS...}I.|
+000002d0  3a cb 88 0c d4 d8 9d d9  33 ef 47 dd d8 08 64 4a  |:.......3.G...dJ|
+000002e0  69 33 84 c4 c4 78 59 6b  84 50 70 2c d9 f8 8a 39  |i3...xYk.Pp,...9|
+000002f0  37 78 3c b4 c3 70 73 8d  ff aa be 8e 93 54 05 7d  |7x<..ps......T.}|
+00000300  a2 cd 8b ef 8c 8c 64 7a  b3 2a af 3e 20 67 a1 7b  |......dz.*.> g.{|
+00000310  a3 07 3b f1 d3 88 14 03  01 00 01 01 16 03 01 00  |..;.............|
+00000320  24 93 a0 0a 95 c2 ee 2c  4b 92 f2 09 e0 a6 80 c8  |$......,K.......|
+00000330  95 fb b1 ef a0 41 bb 27  e6 ad c9 d2 11 29 8a e4  |.....A.'.....)..|
+00000340  1e 9a d6 92 2b                                    |....+|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 99 e8 fb 65 f4  |..........$...e.|
-00000010  95 ae 8b 71 cc 5d a4 95  a7 27 98 fd 16 3f 7a 1a  |...q.]...'...?z.|
-00000020  b6 bd bf 0a 58 72 77 97  1f 8e b1 dd 4b 12 12     |....Xrw.....K..|
+00000000  14 03 01 00 01 01 16 03  01 00 24 a4 54 34 b8 11  |..........$.T4..|
+00000010  2b ad bc 55 7d 8b 71 e3  c5 7a a1 9b 0b 7f c3 48  |+..U}.q..z.....H|
+00000020  69 32 5a 8d 0a f4 43 a0  c6 b7 e8 7d a4 f4 62     |i2Z...C....}..b|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a 42 70 c0  89 78 12 5c 91 7e 88 2d  |.....Bp..x.\.~.-|
-00000010  2f 8f be f2 f2 12 9d 81  ae 78 08 38 5e 6d 1b 15  |/........x.8^m..|
-00000020  03 01 00 16 1a 64 b1 6f  8a ff d3 63 6a c7 b8 95  |.....d.o...cj...|
-00000030  3d b0 87 bc 62 e9 88 5b  26 bd                    |=...b..[&.|
+00000000  17 03 01 00 1a 26 c4 9a  35 54 80 41 f6 28 6b 0e  |.....&..5T.A.(k.|
+00000010  d9 e2 3d 37 ad fa db 91  3b fc 1b 5b 82 da 72 15  |..=7....;..[..r.|
+00000020  03 01 00 16 99 b3 54 b5  20 f4 3e bf e2 00 0e 4e  |......T. .>....N|
+00000030  2a 1e 37 55 56 c2 3b 30  62 20                    |*.7UV.;0b |
index 30c4c6b831af9000b001cba1c8526aa6a28fa1c0..f67801202ed22b845d4ccd3ce7ab22b43c6fc40f 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 02 b2  |....Y...U..S....|
-00000010  e0 f6 f6 b5 c9 5b 28 d0  5d 58 1b 6f 4e 2b 9d 05  |.....[(.]X.oN+..|
-00000020  2a b9 b4 da 45 cf f3 10  b2 23 44 20 f8 4d 59 05  |*...E....#D .MY.|
-00000030  ad 27 f2 a0 ee 7f ec cc  20 dc e7 a2 1b 07 b3 a5  |.'...... .......|
-00000040  37 7e 61 3d d6 5c 03 cf  cc f5 9b ca c0 09 00 00  |7~a=.\..........|
+00000000  16 03 01 00 59 02 00 00  55 03 01 49 fe 00 1f fb  |....Y...U..I....|
+00000010  be ed 3e 36 55 b8 01 4b  a0 ea 7f e4 0e db 8a d0  |..>6U..K........|
+00000020  70 b3 0f 51 47 f3 d6 bd  1f f0 fa 20 60 0c b2 85  |p..QG...... `...|
+00000030  e3 f3 b9 90 25 e5 35 d2  9a 75 31 86 d6 7e 6c b6  |....%.5..u1..~l.|
+00000040  75 96 1c 35 54 10 3a 79  85 7d 3c ce c0 09 00 00  |u..5T.:y.}<.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 da  |*............A..|
-00000280  5a fd 09 e5 d6 c0 70 41  5e 3a 87 eb df 0c ad 90  |Z.....pA^:......|
-00000290  22 8a 2f 90 81 0c 24 00  68 92 f3 d5 95 2f 93 43  |"./...$.h..../.C|
-000002a0  e9 58 2d 18 28 62 ee 33  5b 21 2e 49 87 21 4d 32  |.X-.(b.3[!.I.!M2|
-000002b0  32 19 b3 ba fe 2d 9a 85  12 0e a1 77 08 06 75 00  |2....-.....w..u.|
-000002c0  8a 30 81 87 02 42 01 91  14 fc 68 74 95 10 4b d4  |.0...B....ht..K.|
-000002d0  67 60 12 46 bb b0 f6 98  77 a3 41 b8 01 5c 49 54  |g`.F....w.A..\IT|
-000002e0  9e 3e 81 e7 97 a3 b9 73  6e 15 74 67 be e5 d9 eb  |.>.....sn.tg....|
-000002f0  8b 87 c5 22 ab ab 58 28  4f d1 b6 80 94 1b f5 f7  |..."..X(O.......|
-00000300  12 43 ef 0a c7 3e 1a 76  02 41 7a 00 49 cb 9f 3b  |.C...>.v.Az.I..;|
-00000310  91 6e 38 58 0a d3 d0 d1  ee 67 f0 b6 5d cd fa 23  |.n8X.....g..]..#|
-00000320  b6 98 43 af 9c 71 90 1e  1d 50 a2 6e 61 5b f2 92  |..C..q...P.na[..|
-00000330  b4 69 73 f2 3b 54 bf 1c  9d 05 19 97 e4 4e 41 9e  |.is.;T.......NA.|
-00000340  f2 9a 76 77 9a 86 43 1f  1f 30 a2 16 03 01 00 04  |..vw..C..0......|
+00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 f3  |*............A..|
+00000280  35 bb 79 ff 75 d2 57 d2  e8 8f ac b5 4b 39 ae fa  |5.y.u.W.....K9..|
+00000290  d4 22 b0 74 57 c3 55 aa  cd 26 b8 e0 8c f9 35 85  |.".tW.U..&....5.|
+000002a0  da 55 95 e0 cd e1 49 2c  ff 4b 20 de 88 de c2 4c  |.U....I,.K ....L|
+000002b0  36 e3 ca c6 69 cc 04 c6  ca 99 52 60 7f b4 cb 00  |6...i.....R`....|
+000002c0  8a 30 81 87 02 42 01 e0  54 72 b0 6b 7e 33 73 68  |.0...B..Tr.k~3sh|
+000002d0  8f 3f 81 4b c5 4c a7 bd  78 01 f4 15 54 1a 23 3a  |.?.K.L..x...T.#:|
+000002e0  dd 58 90 a9 27 5d b0 06  fa e5 b8 e7 f5 aa e8 0a  |.X..']..........|
+000002f0  fe 16 14 5e b8 0d 13 9e  8f 5a 29 a8 e2 c4 fd 34  |...^.....Z)....4|
+00000300  78 89 44 42 24 98 d9 24  02 41 2a b0 f6 1a f8 9d  |x.DB$..$.A*.....|
+00000310  60 8a 5f 3e f2 d4 cd bd  d2 73 6f 83 cf b4 87 1d  |`._>.....so.....|
+00000320  29 e5 e2 f0 d5 0c 49 96  82 2f bf ce ab b2 bd e7  |).....I../......|
+00000330  6a ab 1b fe 1a 32 94 43  55 5c b1 76 61 e4 00 c1  |j....2.CU\.va...|
+00000340  f3 cf b2 74 fe b6 a1 ac  f8 1f 11 16 03 01 00 04  |...t............|
 00000350  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
 00000000  16 03 01 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 01 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 01 00 30 88 60  65 b2 d7 51 1f ad 96 56  |.....0.`e..Q...V|
-00000060  4e 0a 20 eb b5 b0 1a dd  4c f6 1a cf d4 5c 47 c4  |N. .....L....\G.|
-00000070  9c 7c a0 36 dd d1 1b 96  91 99 c0 a7 2d 9a 7c 42  |.|.6........-.|B|
-00000080  51 d1 de 87 2b a4                                 |Q...+.|
+00000050  01 16 03 01 00 30 fd 33  1e 7c cb c1 58 78 d3 ab  |.....0.3.|..Xx..|
+00000060  d9 a0 1b d8 d2 e6 1d ff  f0 4e 07 9f e5 dc eb be  |.........N......|
+00000070  b9 49 b6 d9 26 53 96 c4  70 f1 ea 01 ec c9 49 2f  |.I..&S..p.....I/|
+00000080  63 9e ed c1 d3 16                                 |c.....|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 86 6c b5 94 69  |..........0.l..i|
-00000010  2e e0 55 a2 4d a8 63 f2  5b 1f ae 34 21 c8 21 6a  |..U.M.c.[..4!.!j|
-00000020  00 b6 56 ed 4e 2a b0 ff  01 2f da ce a1 c0 41 03  |..V.N*.../....A.|
-00000030  a9 1b 6e 2e e1 88 50 ba  62 14 88                 |..n...P.b..|
+00000000  14 03 01 00 01 01 16 03  01 00 30 b9 bc fb cc 21  |..........0....!|
+00000010  b7 06 cd 88 a4 f5 36 c9  ef 0a 77 fe 11 25 30 83  |......6...w..%0.|
+00000020  a7 34 9b 1e bb 67 80 89  3c 43 a9 4d b6 70 fd cf  |.4...g..<C.M.p..|
+00000030  f6 86 7e ba 09 26 19 2f  25 9e 3a                 |..~..&./%.:|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 a6 63 0a  2f a5 dc e1 fb cb 7b 1f  |.... .c./.....{.|
-00000010  f2 da 74 c3 ff e9 f5 8b  9c 5f 0c d3 f7 1f 44 e6  |..t......_....D.|
-00000020  90 13 5c 48 50 17 03 01  00 20 c7 75 b5 ff bc 09  |..\HP.... .u....|
-00000030  34 f2 45 db 0d 22 08 8e  f1 35 cd b6 0f b0 eb 2a  |4.E.."...5.....*|
-00000040  b7 1a d0 8e 14 a4 54 84  f9 dc 15 03 01 00 20 e0  |......T....... .|
-00000050  36 3d aa b3 a9 b4 20 23  ca 9e 8c 5d fc a8 c8 b7  |6=.... #...]....|
-00000060  f5 c2 b6 d0 5a e2 ce a5  7b 68 a0 48 86 95 6a     |....Z...{h.H..j|
+00000000  17 03 01 00 20 aa 90 92  5c a6 07 91 99 3e 54 0b  |.... ...\....>T.|
+00000010  dd 9c 59 4a 9e 91 f9 4f  e4 fb 14 9e 65 18 ef 1a  |..YJ...O....e...|
+00000020  8c ad a7 d4 b9 17 03 01  00 20 d7 73 8a 1a fe cb  |......... .s....|
+00000030  fd f7 fc 3e 03 5e 2f 03  97 12 a2 a9 31 df e4 76  |...>.^/.....1..v|
+00000040  88 c4 32 5a 90 6e bb 40  49 5c 15 03 01 00 20 c1  |..2Z.n.@I\.... .|
+00000050  92 ce bd 9e 23 50 8e da  96 d4 98 98 bc 18 e6 e7  |....#P..........|
+00000060  33 74 be 8b b7 d8 d4 19  62 1d e8 f1 4c fd 1c     |3t......b...L..|
index 868f0ceb0e5ec00eac528b31abd27607633420a7..84e02682a2b1dbdc9bcbecb78d06c391a5c0807e 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 02 21  |....Y...U..S...!|
-00000010  67 b5 2b 34 fb 62 d7 36  4f cf 68 2e 29 39 d0 28  |g.+4.b.6O.h.)9.(|
-00000020  3a 02 32 82 8f 95 de 62  d6 03 77 20 e6 98 56 cd  |:.2....b..w ..V.|
-00000030  96 24 d1 b9 4d eb 51 19  bb b7 71 f4 9c 29 32 d4  |.$..M.Q...q..)2.|
-00000040  e5 c6 0a 54 e0 4a 20 29  3e bd 06 0d c0 13 00 00  |...T.J )>.......|
+00000000  16 03 01 00 59 02 00 00  55 03 01 52 5c cd ba 77  |....Y...U..R\..w|
+00000010  cd 8e 48 de c2 b6 d7 eb  88 c2 e3 b3 8e fd 36 37  |..H...........67|
+00000020  71 c6 79 43 89 13 48 99  98 dc 78 20 cd 26 72 7b  |q.yC..H...x .&r{|
+00000030  84 c3 dd 55 e3 83 99 af  da 65 a7 5f 10 ef 8b 3a  |...U.....e._...:|
+00000040  4c 59 7b 11 d6 6a 61 68  d6 20 3c 3e c0 13 00 00  |LY{..jah. <>....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
 00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
 000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
 00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
 00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
-00000320  d9 16 03 01 00 cb 0c 00  00 c7 03 00 17 41 04 05  |.............A..|
-00000330  45 33 f8 4b e9 96 0e 4a  fd ec 54 76 21 9b 24 8a  |E3.K...J..Tv!.$.|
-00000340  75 0b 80 84 c7 30 2b 22  f0 85 57 a4 a9 79 d6 f6  |u....0+"..W..y..|
-00000350  6d 80 b0 71 d9 66 c9 6c  dd 76 fc 32 d0 c6 bc 52  |m..q.f.l.v.2...R|
-00000360  2f f1 c9 62 17 53 76 ec  be a6 1c 93 f2 b4 5d 00  |/..b.Sv.......].|
-00000370  80 72 d9 20 52 70 7c 03  b1 33 fa 51 23 cd 05 97  |.r. Rp|..3.Q#...|
-00000380  6f d6 89 2f 8d 2e 3a 17  32 eb f2 ff 6b 39 70 5e  |o../..:.2...k9p^|
-00000390  21 41 8d 69 02 c8 9a 17  19 e4 48 9b 51 c3 7f 9b  |!A.i......H.Q...|
-000003a0  8d 4a 83 97 07 0e 30 f1  8b 6b e9 92 12 01 d6 96  |.J....0..k......|
-000003b0  f2 1a a2 10 7f 59 87 16  1a fb 55 67 68 fc 78 c6  |.....Y....Ugh.x.|
-000003c0  57 ac 05 dd f3 6f 77 84  eb ae b0 33 2d 19 2c ba  |W....ow....3-.,.|
-000003d0  b8 ae 9f 95 69 85 95 45  5e 37 f4 17 17 9b 03 c1  |....i..E^7......|
-000003e0  50 b1 36 42 bd 60 5c 8b  d8 b6 f3 c8 34 c8 9d 9d  |P.6B.`\.....4...|
-000003f0  75 16 03 01 00 04 0e 00  00 00                    |u.........|
+00000320  d9 16 03 01 00 cb 0c 00  00 c7 03 00 17 41 04 25  |.............A.%|
+00000330  0b 65 90 de 1c eb d0 7c  fe cb 71 2c 62 dd f9 7c  |.e.....|..q,b..||
+00000340  bd bc f5 bd a9 79 df a1  38 36 2a 98 7b 5d ce 17  |.....y..86*.{]..|
+00000350  67 a7 71 b9 9e 0a f2 02  f4 f3 19 a6 96 bc 53 45  |g.q...........SE|
+00000360  2e e0 df f1 e6 50 8b a2  36 a1 e9 59 1e d2 8f 00  |.....P..6..Y....|
+00000370  80 5a c1 19 13 94 5e ee  89 33 4a 22 e6 5d fa bc  |.Z....^..3J".]..|
+00000380  78 20 f2 5d 73 39 c9 84  1f e0 de 77 99 72 2b 77  |x .]s9.....w.r+w|
+00000390  58 f2 b6 a7 6e 3d e3 f9  95 b6 23 6e 27 36 45 f7  |X...n=....#n'6E.|
+000003a0  75 87 ff 4a 49 e1 d0 ea  83 52 97 b1 77 c6 00 8e  |u..JI....R..w...|
+000003b0  62 af 4f d0 cd 5e a4 9b  2f 72 ca dc 87 96 6b 73  |b.O..^../r....ks|
+000003c0  08 2c a5 75 d8 9d d5 a3  ba 25 45 78 07 db f1 86  |.,.u.....%Ex....|
+000003d0  08 4a 56 26 9d da f6 10  43 74 c1 93 ae 89 17 f1  |.JV&....Ct......|
+000003e0  1c 22 10 15 30 81 47 78  25 de fe 30 6d da 7d 0f  |."..0.Gx%..0m.}.|
+000003f0  36 16 03 01 00 04 0e 00  00 00                    |6.........|
 >>> Flow 3 (client to server)
 00000000  16 03 01 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 01 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 01 00 30 ca d1  1b 08 27 9b 44 e7 e9 b4  |.....0....'.D...|
-00000060  90 16 4d 30 4e 65 5c 0d  47 ba 46 86 cf c9 80 e7  |..M0Ne\.G.F.....|
-00000070  64 31 f5 a1 9e dc 39 15  d3 be 16 4f c7 90 b6 62  |d1....9....O...b|
-00000080  5d 6d 7f 41 4e 3e                                 |]m.AN>|
+00000050  01 16 03 01 00 30 fa 12  bd 34 6f ca 53 e6 9a 77  |.....0...4o.S..w|
+00000060  ec 0c de 3e 96 ab fe ac  52 7b 04 61 21 29 ab 86  |...>....R{.a!)..|
+00000070  7a 0b 4f 4b 9a f2 2d fe  89 96 07 a5 20 38 71 8b  |z.OK..-..... 8q.|
+00000080  2e 76 9c 4e de 26                                 |.v.N.&|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 98 81 24 8e cd  |..........0..$..|
-00000010  b6 48 2f 80 de 8e 24 3c  cd 02 67 80 34 97 d7 92  |.H/...$<..g.4...|
-00000020  78 c2 44 3d 5d 05 eb 88  76 79 46 7a c3 fa ca 73  |x.D=]...vyFz...s|
-00000030  45 82 ad c1 81 00 ca 40  c1 2f 13                 |E......@./.|
+00000000  14 03 01 00 01 01 16 03  01 00 30 54 5d dc 18 0e  |..........0T]...|
+00000010  76 37 48 8c 06 e6 6c 26  6d af 3d 57 fa 57 4f 6b  |v7H...l&m.=W.WOk|
+00000020  3d 00 e5 d6 81 ac 86 ae  1c 82 9c 08 4d 37 fd fc  |=...........M7..|
+00000030  27 d4 38 1e 28 8e 2b 0e  50 23 80                 |'.8.(.+.P#.|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 ee 19 59  67 67 a9 8b db 99 87 50  |.... ..Ygg.....P|
-00000010  01 e2 02 c1 d5 6d 36 79  af aa ec 1b 80 0e b6 5e  |.....m6y.......^|
-00000020  5f fa 03 01 cc 17 03 01  00 20 ec e2 04 b7 3b a5  |_........ ....;.|
-00000030  f2 e0 13 1f 17 48 e7 6e  d3 eb f0 fa 36 ef 6e 2e  |.....H.n....6.n.|
-00000040  fb ea c8 39 c4 5f 4b 28  d4 50 15 03 01 00 20 c7  |...9._K(.P.... .|
-00000050  45 ff fb c7 07 0c d8 0e  35 a3 c5 31 47 b7 03 0e  |E.......5..1G...|
-00000060  14 c8 29 fd 53 70 5f 15  ac d2 1c 4c 69 fb d6     |..).Sp_....Li..|
+00000000  17 03 01 00 20 28 98 f6  dd a7 6f 74 c6 5c 6d 54  |.... (....ot.\mT|
+00000010  8a 69 99 c8 db 88 73 9e  94 a6 d7 81 9e be 5f ba  |.i....s......._.|
+00000020  9e 6d 46 72 be 17 03 01  00 20 a9 d1 38 e1 eb 0f  |.mFr..... ..8...|
+00000030  7a fd c7 81 12 8b 5e 8e  4e e8 e2 8b 40 af 74 e3  |z.....^.N...@.t.|
+00000040  80 6d 52 40 13 d5 d4 a0  d9 29 15 03 01 00 20 7c  |.mR@.....).... ||
+00000050  3f d7 27 13 2b d5 41 4e  17 93 10 79 20 f2 f6 21  |?.'.+.AN...y ..!|
+00000060  c7 21 08 f4 bc 5f 97 61  46 2e 4f 35 86 15 79     |.!..._.aF.O5..y|
index 395d53bbabb0fb1e4b09974a1abba3c6506df36d..b7070128019ca7a846fe8c18a88a34e162ecae34 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 53 04 f1 02 76  |....Q...M..S...v|
-00000010  e8 45 7f 57 f3 42 4b 33  0b 06 fa a6 fa c4 3d 84  |.E.W.BK3......=.|
-00000020  5a 45 dc 93 41 a5 8d 79  6e 8f 11 20 e7 c6 29 2b  |ZE..A..yn.. ..)+|
-00000030  ff 4a 6e 63 67 a6 10 cb  49 19 46 1e 5e 0a d5 70  |.Jncg...I.F.^..p|
-00000040  96 88 9a 32 48 ef c3 4a  45 4c 6d e0 00 05 00 00  |...2H..JELm.....|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 5c 40 79 8d 40  |....Q...M..\@y.@|
+00000010  c0 fd 1f 3c 2d 85 e1 19  12 c8 dc 95 8a 52 44 a5  |...<-........RD.|
+00000020  3a c1 9a 41 9a 72 9d cf  d8 8e 3c 20 76 d2 7d 3d  |:..A.r....< v.}=|
+00000030  b9 0f a9 b0 05 a6 c7 ac  53 7a fa 0f 7a d5 25 ec  |........Sz..z.%.|
+00000040  51 5f fb da a4 9e f2 45  10 40 38 13 00 05 00 00  |Q_.....E.@8.....|
 00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
 00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 01 00 01  |5..C.0oUN.p.....|
-00000090  01 16 03 01 00 24 cd c0  68 dc 2e 69 cc c7 5b c5  |.....$..h..i..[.|
-000000a0  3f bd 40 cf a0 0f 41 34  ce 16 37 10 26 c8 3f d1  |?.@...A4..7.&.?.|
-000000b0  46 3b ad 7b b0 31 f3 c5  36 e7                    |F;.{.1..6.|
+00000090  01 16 03 01 00 24 c0 e9  f1 c2 c5 a1 75 6b b8 84  |.....$......uk..|
+000000a0  cf d8 46 e6 e1 d4 a0 65  d9 89 29 55 91 4c 38 5e  |..F....e..)U.L8^|
+000000b0  8c 90 ac 2e db 28 68 e6  00 b4                    |.....(h...|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 ea 77 6f 3c 42  |..........$.wo<B|
-00000010  12 16 51 de e8 b6 f9 85  06 d9 6d 05 75 50 2b 27  |..Q.......m.uP+'|
-00000020  93 b7 6b 65 e9 14 99 48  53 3e be e4 be 03 5d     |..ke...HS>....]|
+00000000  14 03 01 00 01 01 16 03  01 00 24 20 d1 dd c0 6f  |..........$ ...o|
+00000010  2c f2 1e 30 c6 8c 59 e9  5b 31 e6 a6 ce ea 57 06  |,..0..Y.[1....W.|
+00000020  59 39 a2 b9 78 6e a4 fc  cb 0c 9c 26 05 3b 16     |Y9..xn.....&.;.|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a 9e ae ca  55 df c4 d9 47 04 55 dd  |........U...G.U.|
-00000010  3b 33 e1 a6 16 6f a1 94  b1 9b 4d 0d cb 6c 3b 15  |;3...o....M..l;.|
-00000020  03 01 00 16 92 5d 76 07  e9 b7 31 29 09 c5 b1 09  |.....]v...1)....|
-00000030  2d 64 3d 85 8d f1 d1 40  54 b8                    |-d=....@T.|
+00000000  17 03 01 00 1a 25 ef 34  80 3d 18 91 ae ba 40 79  |.....%.4.=....@y|
+00000010  0e 2e 59 ac 30 0d 47 77  bd 61 b8 16 a7 08 b0 15  |..Y.0.Gw.a......|
+00000020  03 01 00 16 54 73 7f 48  c4 49 55 97 2a 2d 00 71  |....Ts.H.IU.*-.q|
+00000030  fc 82 c8 7a 63 2a ea 9e  8d 6f                    |...zc*...o|
index 9f941f8ef18578130f61081153c3b7a461a64c72..5d2528a0dc569f072acab7dfdc855a3f1a9c6f60 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 59 02 00 00  55 03 02 53 04 f1 02 1c  |....Y...U..S....|
-00000010  d1 1c 6a 5f 7a 5c 26 69  92 cd ee c3 57 ed 96 90  |..j_z\&i....W...|
-00000020  e3 c5 f1 ee 8b ee 99 5f  46 2c e6 20 c8 50 6a a4  |......._F,. .Pj.|
-00000030  4b 93 e6 da ba 6d d4 87  f6 75 a8 9d 44 db b5 43  |K....m...u..D..C|
-00000040  df 12 57 de a4 f1 bc fb  b8 7a 3f 6a c0 09 00 00  |..W......z?j....|
+00000000  16 03 02 00 59 02 00 00  55 03 02 48 99 38 25 1c  |....Y...U..H.8%.|
+00000010  df 79 d9 78 68 90 92 ad  3f e7 a0 38 b2 d8 ab 50  |.y.xh...?..8...P|
+00000020  2c fb b0 16 00 5a 5c 87  a6 dc 16 20 70 3f 2a fd  |,....Z\.... p?*.|
+00000030  ef 14 aa 68 d5 08 c4 1e  4c 04 7a 08 63 ec cb 0d  |...h....L.z.c...|
+00000040  1f 2b 08 17 f2 29 7c da  a3 d0 6f 07 c0 09 00 00  |.+...)|...o.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  02 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 02 00 d4 0c 00  00 d0 03 00 17 41 04 7b  |*............A.{|
-00000280  c4 00 37 35 51 de c3 f2  a4 95 2c 19 21 3e a6 94  |..75Q.....,.!>..|
-00000290  7b fd 04 d7 b7 1c 56 e6  af 3c ee 36 cb 55 e6 f0  |{.....V..<.6.U..|
-000002a0  e6 24 34 6b 8a 02 66 71  f9 e2 f5 a6 c9 d7 6c dc  |.$4k..fq......l.|
-000002b0  65 59 ff 1c c9 ec a9 8b  07 d6 52 2c 01 3c c3 00  |eY........R,.<..|
-000002c0  89 30 81 86 02 41 74 89  1a 31 72 e6 8b c0 4a ce  |.0...At..1r...J.|
-000002d0  8f 5a 49 a7 52 2d 6d b9  8b 50 17 62 2a 99 d6 3b  |.ZI.R-m..P.b*..;|
-000002e0  02 85 41 4d 34 53 b5 09  bd e3 ac 16 c1 9b e9 83  |..AM4S..........|
-000002f0  cc 83 e3 9c 23 34 67 71  72 d4 05 a2 34 f7 08 29  |....#4gqr...4..)|
-00000300  62 43 2e cc bc 08 01 02  41 59 de 5a d0 dd d7 6b  |bC......AY.Z...k|
-00000310  db 9c 35 29 79 f8 96 91  56 74 1f 18 7b ee 25 83  |..5)y...Vt..{.%.|
-00000320  f2 37 0e 77 ab 38 fb 5e  04 0b 09 d9 b4 1f 3f be  |.7.w.8.^......?.|
-00000330  2e e3 60 e3 96 f3 29 c1  6d 8f 56 1b fd 62 14 48  |..`...).m.V..b.H|
-00000340  e3 d9 2a ea 2f be 93 d0  8b 31 16 03 02 00 04 0e  |..*./....1......|
-00000350  00 00 00                                          |...|
+00000270  2a 16 03 02 00 d6 0c 00  00 d2 03 00 17 41 04 5f  |*............A._|
+00000280  ea cb dd 6a 2c 16 40 15  d1 e7 ea 41 19 08 5d 1c  |...j,.@....A..].|
+00000290  e8 f2 f2 75 84 96 f5 d4  c8 5b fd 4b ba 3b 79 8c  |...u.....[.K.;y.|
+000002a0  86 a3 2a ce 77 2d 97 ea  39 3d 52 8e a4 c7 da bd  |..*.w-..9=R.....|
+000002b0  52 68 46 b4 f2 ba 1f 73  30 29 2f 29 d4 82 66 00  |RhF....s0)/)..f.|
+000002c0  8b 30 81 88 02 42 00 c3  d3 8d 5e f9 a8 03 27 d8  |.0...B....^...'.|
+000002d0  be 19 80 53 8e 5a 58 4f  13 2a 04 25 8c 73 71 9a  |...S.ZXO.*.%.sq.|
+000002e0  15 7e 05 09 d4 a2 8d 3e  16 0e 2d a8 73 97 bc 1a  |.~.....>..-.s...|
+000002f0  b4 48 81 f0 c9 2a e7 c2  39 13 5d 25 3e b1 82 d1  |.H...*..9.]%>...|
+00000300  cf 3e 46 f5 f6 f8 e3 e2  02 42 01 a2 ba f5 05 eb  |.>F......B......|
+00000310  84 26 34 06 f2 85 ae e0  54 95 cd f9 8a 2e 01 a5  |.&4.....T.......|
+00000320  65 d0 ab da cd ec 33 7a  12 51 1c 75 3f 4f be 7f  |e.....3z.Q.u?O..|
+00000330  f7 a6 02 81 2e 6d 3b 58  d6 5f 2d 53 d0 43 61 2d  |.....m;X._-S.Ca-|
+00000340  0c d8 7d e5 08 48 48 da  51 47 8b a5 16 03 02 00  |..}..HH.QG......|
+00000350  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
 00000000  16 03 02 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 02 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 02 00 40 00 00  00 00 00 00 00 00 00 00  |.....@..........|
-00000060  00 00 00 00 00 00 b6 98  a2 a9 48 34 12 6b 0a 94  |..........H4.k..|
-00000070  89 fc 38 04 63 5a 6f 63  36 3e d9 35 12 64 8c 28  |..8.cZoc6>.5.d.(|
-00000080  99 a6 cf 2e 57 e3 14 6d  0a 8a ab f0 a6 58 37 7c  |....W..m.....X7||
-00000090  96 04 d3 71 bc d4                                 |...q..|
+00000060  00 00 00 00 00 00 20 a1  aa ad 8d db ed 19 63 64  |...... .......cd|
+00000070  60 73 8a 59 0d 59 81 51  b8 44 7b c8 86 ac fe db  |`s.Y.Y.Q.D{.....|
+00000080  9f da 5e af fd 54 a3 6e  c6 f0 d6 45 fe 93 70 f1  |..^..T.n...E..p.|
+00000090  45 99 06 3e 6a 28                                 |E..>j(|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 40 c5 01 c9 0a b0  |..........@.....|
-00000010  d8 ca 5e c1 19 dc 37 6c  2e a0 b3 11 a8 87 65 5a  |..^...7l......eZ|
-00000020  09 41 b9 fe 53 c4 c9 76  97 6d 7f ac c0 be d2 07  |.A..S..v.m......|
-00000030  84 e5 5b 78 37 34 ee da  3b cb 3e 82 52 79 91 44  |..[x74..;.>.Ry.D|
-00000040  b4 e4 1c ec 3a c0 c0 9d  cd ff 13                 |....:......|
+00000000  14 03 02 00 01 01 16 03  02 00 40 b7 6f dc 1c 48  |..........@.o..H|
+00000010  cc 3d ac 1d 6b b2 bc 9c  dd 25 02 9d b0 77 8d ca  |.=..k....%...w..|
+00000020  5a 4c d6 d3 c0 e0 a6 8c  03 00 e5 85 3a 2f 5e df  |ZL..........:/^.|
+00000030  17 5b 9a 2e e3 54 20 60  fe 39 ef 51 23 bc 13 ea  |.[...T `.9.Q#...|
+00000040  86 6f 4f e5 8c 5f a0 3e  ae e9 69                 |.oO.._.>..i|
 >>> Flow 5 (client to server)
 00000000  17 03 02 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 46 60 13  39 2b 2f 72 95 ed 0e aa  |.....F`.9+/r....|
-00000020  69 6e b4 64 3e 83 43 d0  f9 7f 37 7c 1d b9 ce 11  |in.d>.C...7|....|
-00000030  d9 41 66 60 6d 15 03 02  00 30 00 00 00 00 00 00  |.Af`m....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 b1 26 d0 5d 08 98  |...........&.]..|
-00000050  eb 28 42 74 31 58 42 95  c5 ad 1a 92 0a f5 5f ed  |.(Bt1XB......._.|
-00000060  45 98 e0 90 e5 a3 b6 8b  8d 18                    |E.........|
+00000010  00 00 00 00 00 31 e9 1b  b8 b7 ed a1 dd 34 87 9c  |.....1.......4..|
+00000020  3c 8a 0d 41 8c d3 3f 0e  54 62 d5 31 07 4a a5 8f  |<..A..?.Tb.1.J..|
+00000030  0e 07 3d da 91 15 03 02  00 30 00 00 00 00 00 00  |..=......0......|
+00000040  00 00 00 00 00 00 00 00  00 00 d2 62 91 56 10 c8  |...........b.V..|
+00000050  c9 f8 25 3f ef ab b1 a7  88 a6 85 2b 1b 02 47 36  |..%?.......+..G6|
+00000060  3a 08 b0 63 da c1 cb ea  11 2c                    |:..c.....,|
index fc723396a4f746d72d1c390331a0b22e50dcb24c..23d977114225a66e03685086a6b1ac48bbf3cf6e 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 59 02 00 00  55 03 02 53 04 f1 02 fe  |....Y...U..S....|
-00000010  17 8b 79 ad 93 2e d3 89  66 9b 5d 9b b4 03 3e ba  |..y.....f.]...>.|
-00000020  65 2a f1 55 f9 3c 33 de  2c a7 47 20 fa 4f 82 11  |e*.U.<3.,.G .O..|
-00000030  96 81 d0 70 2e 65 b3 68  2e 3a 6d d7 6c 74 22 33  |...p.e.h.:m.lt"3|
-00000040  d4 ae 6c aa c8 f0 c7 20  8b 10 21 e7 c0 13 00 00  |..l.... ..!.....|
+00000000  16 03 02 00 59 02 00 00  55 03 02 95 77 16 4d 9c  |....Y...U...w.M.|
+00000010  0c e7 a4 de e2 49 a2 28  d5 5b ec 44 24 89 7c 47  |.....I.(.[.D$.|G|
+00000020  f2 a6 03 d4 76 08 92 99  5f 3f af 20 f9 55 14 a9  |....v..._?. .U..|
+00000030  de 8c 1a 77 37 9c 1b d9  95 30 e6 25 93 9a 3f 6f  |...w7....0.%..?o|
+00000040  cc c0 27 4c 4a cd 61 eb  53 a0 b2 59 c0 13 00 00  |..'LJ.a.S..Y....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  02 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
 00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
 000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
 00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
 00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
-00000320  d9 16 03 02 00 cb 0c 00  00 c7 03 00 17 41 04 26  |.............A.&|
-00000330  56 18 02 e5 66 d4 aa 24  7e ae 39 e5 ca 78 6c c1  |V...f..$~.9..xl.|
-00000340  90 02 c3 c4 ad 79 2c 47  a8 bf 54 e2 8a 22 b6 ef  |.....y,G..T.."..|
-00000350  99 d4 7a 7f 8f 78 6a 78  4e 14 2a 16 0d bb 54 38  |..z..xjxN.*...T8|
-00000360  59 1f 7a 53 1b c7 73 10  89 4b de c3 66 39 7a 00  |Y.zS..s..K..f9z.|
-00000370  80 3a 88 38 c8 15 07 ab  2f 0f 0d cb 19 07 84 ac  |.:.8..../.......|
-00000380  24 fd 8b d2 9d 05 45 c6  11 c3 d6 84 58 95 5a 08  |$.....E.....X.Z.|
-00000390  b9 a4 2c c0 41 4e 34 e0  b2 24 98 94 b7 67 27 50  |..,.AN4..$...g'P|
-000003a0  ba 82 35 28 a9 bf 16 ee  e3 7b 49 9c 4c 81 80 69  |..5(.....{I.L..i|
-000003b0  d7 aa ed 46 ea 9a 68 c4  97 b7 11 d4 35 91 74 5e  |...F..h.....5.t^|
-000003c0  54 10 34 83 cd c4 06 18  49 7d 7a 28 c9 53 06 73  |T.4.....I}z(.S.s|
-000003d0  00 7b 04 b6 d8 36 a7 4b  67 7f 81 30 94 de 40 4d  |.{...6.Kg..0..@M|
-000003e0  18 f8 c4 b7 02 00 44 8e  bc 72 06 24 53 15 74 72  |......D..r.$S.tr|
-000003f0  8d 16 03 02 00 04 0e 00  00 00                    |..........|
+00000320  d9 16 03 02 00 cb 0c 00  00 c7 03 00 17 41 04 cc  |.............A..|
+00000330  93 4b 67 67 12 37 c6 c4  77 3d 6b 3e ce 16 04 82  |.Kgg.7..w=k>....|
+00000340  09 9d b0 bc 67 a8 43 e8  06 ab 9d 8b dd fe ad 00  |....g.C.........|
+00000350  9e 32 19 f3 5f d8 2d de  18 76 1d 46 18 f1 1f ac  |.2.._.-..v.F....|
+00000360  19 79 9b 6c 5b c8 92 d4  6b 91 e9 58 f7 92 b6 00  |.y.l[...k..X....|
+00000370  80 0c d6 d5 6c 2c 89 fa  8b a6 59 f8 48 cb f2 9d  |....l,....Y.H...|
+00000380  02 61 b0 2d 83 5e e6 5f  41 b9 91 96 30 fb 09 85  |.a.-.^._A...0...|
+00000390  4f 9f ea 92 1a dc a2 c3  59 49 6c 46 85 91 b0 2f  |O.......YIlF.../|
+000003a0  80 47 bc f2 ab 3a 0c 33  5f 46 ef fb bf 2e b7 14  |.G...:.3_F......|
+000003b0  03 ae 6d ac d6 3f 7f 0c  8e c8 18 c3 0d fd ba f3  |..m..?..........|
+000003c0  dd b1 8b a8 c9 ed 53 7c  9c d2 31 91 cc 05 2a f1  |......S|..1...*.|
+000003d0  86 f3 79 c8 d0 55 0d 9d  80 fd 0f 6f 1a 15 c4 dd  |..y..U.....o....|
+000003e0  f3 37 41 2e 4f 51 10 27  80 11 82 c4 a8 4b 7f a3  |.7A.OQ.'.....K..|
+000003f0  e2 16 03 02 00 04 0e 00  00 00                    |..........|
 >>> Flow 3 (client to server)
 00000000  16 03 02 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 02 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 02 00 40 00 00  00 00 00 00 00 00 00 00  |.....@..........|
-00000060  00 00 00 00 00 00 8a 87  81 38 35 c0 4c bb f8 12  |.........85.L...|
-00000070  fa 75 04 cd 1e 3a 61 96  93 c8 fb 07 d1 6d b4 55  |.u...:a......m.U|
-00000080  0f b5 0f 07 35 0a 96 ce  5c 6f 24 62 d3 68 e4 b0  |....5...\o$b.h..|
-00000090  5d be 81 37 c2 9c                                 |]..7..|
+00000060  00 00 00 00 00 00 cc 4d  33 16 3b 7e 8d 15 6f cf  |.......M3.;~..o.|
+00000070  00 7b e2 5c 00 34 5e 53  30 92 2c 0b 5f 5a df bc  |.{.\.4^S0.,._Z..|
+00000080  05 a1 eb e5 9b 2b 2a 94  26 60 57 cd 81 74 9f 31  |.....+*.&`W..t.1|
+00000090  55 64 b5 52 89 c8                                 |Ud.R..|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 40 66 36 8d f8 8c  |..........@f6...|
-00000010  7f db 38 e8 39 df f8 2f  cb 88 9c 14 d9 89 10 b4  |..8.9../........|
-00000020  be 59 88 d7 f3 73 62 af  a3 42 66 6e 74 38 64 9f  |.Y...sb..Bfnt8d.|
-00000030  16 79 09 d7 14 7e 91 8a  70 73 63 28 30 58 fe cc  |.y...~..psc(0X..|
-00000040  42 45 d6 37 fb 9e 8c c1  01 af 34                 |BE.7......4|
+00000000  14 03 02 00 01 01 16 03  02 00 40 10 4d 3e ad a3  |..........@.M>..|
+00000010  6a c6 06 43 7f 5a b6 99  b0 70 22 fe dc 8e a9 a0  |j..C.Z...p".....|
+00000020  9e 0a 8f 0d ed d6 de 8d  16 18 df f9 cc 81 55 a5  |..............U.|
+00000030  56 6b 00 81 c1 8f eb 29  cb 46 16 e5 0f 10 9f 57  |Vk.....).F.....W|
+00000040  b9 28 6e c1 51 d7 c2 e3  46 ee 0b                 |.(n.Q...F..|
 >>> Flow 5 (client to server)
 00000000  17 03 02 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 31 0b e3  9d 2a 05 83 19 7d 10 36  |.....1...*...}.6|
-00000020  23 dc da fe 00 ab d3 aa  8f ce 28 5f 08 fd b7 59  |#.........(_...Y|
-00000030  1e 00 2e 25 5a 15 03 02  00 30 00 00 00 00 00 00  |...%Z....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 10 91 fd fa 59 07  |..............Y.|
-00000050  df 2c 92 25 15 7b 7c 83  44 89 0d 4f 65 43 99 2e  |.,.%.{|.D..OeC..|
-00000060  41 5d 51 c9 09 89 ed 02  08 bc                    |A]Q.......|
+00000010  00 00 00 00 00 9e 9c cb  3c 7c b9 d9 03 1b b9 2c  |........<|.....,|
+00000020  6b e8 d9 eb 9a 9d 29 5f  00 77 a2 f5 b7 cc 0e f1  |k.....)_.w......|
+00000030  78 cb 5d 3f e0 15 03 02  00 30 00 00 00 00 00 00  |x.]?.....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 ca af f9 d3 73 44  |..............sD|
+00000050  f2 43 cc ad 30 5c 41 d4  c8 03 bc 77 96 76 ef 8d  |.C..0\A....w.v..|
+00000060  3c 61 3c bf f3 ae 0d 41  80 96                    |<a<....A..|
index f7be3f7e93ac838ddd0a4227b63d03279d0da8f6..a0d2c62669a058170870104cc526eefb125cf23e 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 51 02 00 00  4d 03 02 53 04 f1 02 d4  |....Q...M..S....|
-00000010  69 65 aa 96 3d 42 96 eb  9e 7d 8a 18 af 4c 7c 5d  |ie..=B...}...L|]|
-00000020  fb 97 5f da 94 62 13 69  1f 66 06 20 aa 52 e3 08  |.._..b.i.f. .R..|
-00000030  35 0a 87 d5 ef 93 49 ab  1a 74 dd 90 bd 69 70 d1  |5.....I..t...ip.|
-00000040  e9 f1 44 17 3a dc 33 98  f5 e5 ab 93 00 05 00 00  |..D.:.3.........|
+00000000  16 03 02 00 51 02 00 00  4d 03 02 4d 2e 22 e8 40  |....Q...M..M.".@|
+00000010  e2 be 4a dd cc 74 ce 49  40 04 76 fa 30 11 04 64  |..J..t.I@.v.0..d|
+00000020  d3 d8 28 cc ef cb 1b 08  70 ca 28 20 74 90 27 2e  |..(.....p.( t.'.|
+00000030  c7 bb 53 66 93 49 da 00  d9 96 06 cf ac 08 40 66  |..Sf.I........@f|
+00000040  41 eb 6e c8 32 2d 10 a6  42 7b 0d 5e 00 05 00 00  |A.n.2-..B{.^....|
 00000050  05 ff 01 00 01 00 16 03  02 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
 00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 02 00 01  |5..C.0oUN.p.....|
-00000090  01 16 03 02 00 24 07 9f  dc df 2d c3 a6 88 06 28  |.....$....-....(|
-000000a0  21 e0 e0 d3 31 99 fc 89  b8 82 6e 95 f4 4b 9e e2  |!...1.....n..K..|
-000000b0  d9 36 5c 14 ce d7 db e2  78 4e                    |.6\.....xN|
+00000090  01 16 03 02 00 24 2b 06  10 fe 60 26 58 7d 59 47  |.....$+...`&X}YG|
+000000a0  83 2d 84 43 e3 8d fe ab  e6 c0 3b b8 68 78 e3 73  |.-.C......;.hx.s|
+000000b0  6c 59 d8 53 86 81 42 69  22 74                    |lY.S..Bi"t|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 24 81 72 75 80 d4  |..........$.ru..|
-00000010  1b 1a 32 00 89 bf 9e 79  30 b9 6b 67 e0 8e c7 eb  |..2....y0.kg....|
-00000020  73 f2 e4 93 51 65 9b 5f  91 b1 b4 b1 f7 44 76     |s...Qe._.....Dv|
+00000000  14 03 02 00 01 01 16 03  02 00 24 62 dc 82 ed 69  |..........$b...i|
+00000010  cc e2 19 72 9c 1b 84 15  77 d8 a0 35 7d b7 47 55  |...r....w..5}.GU|
+00000020  95 4f 67 ad f1 8f 91 01  c0 31 2f 54 64 40 35     |.Og......1/Td@5|
 >>> Flow 5 (client to server)
-00000000  17 03 02 00 1a b2 91 39  63 c0 38 3c 4d 25 fd 14  |.......9c.8<M%..|
-00000010  b9 b6 e1 23 21 b4 8d 17  9e 1f d8 33 92 69 c2 15  |...#!......3.i..|
-00000020  03 02 00 16 4b 10 25 4d  9d 09 c2 11 96 be f7 5b  |....K.%M.......[|
-00000030  c2 9b 99 fd 1f 8e af 0f  2c 51                    |........,Q|
+00000000  17 03 02 00 1a 63 52 52  39 6a 98 7a a8 41 cd b4  |.....cRR9j.z.A..|
+00000010  e4 de 75 32 76 9a ee 44  96 d0 e9 66 b8 0a b5 15  |..u2v..D...f....|
+00000020  03 02 00 16 9f 06 3f 07  78 12 b7 70 db 48 fc ef  |......?.x..p.H..|
+00000030  ff 6e a7 4f e5 82 7f 0c  f2 35                    |.n.O.....5|
index f09a4f106c147bb44b275fac669f57bfefe8574a..a30f1a2ab2d705a935c53c567fcd3f4613d6ed23 100644 (file)
@@ -1,20 +1,20 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 8d 01 00 00  89 03 03 00 00 00 00 00  |................|
+00000000  16 03 01 00 91 01 00 00  8d 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 46 33 74 00 00  |./.5.......F3t..|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00 00 10  |................|
-00000080  00 10 00 0e 06 70 72 6f  74 6f 32 06 70 72 6f 74  |.....proto2.prot|
-00000090  6f 31                                             |o1|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 46  |...../.5.......F|
+00000050  33 74 00 00 00 05 00 05  01 00 00 00 00 00 0a 00  |3t..............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0a 00 08 04 01 04  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 10 00 10 00 0e  06 70 72 6f 74 6f 32 06  |.........proto2.|
+00000090  70 72 6f 74 6f 31                                 |proto1|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 66 02 00 00  62 03 03 77 a9 7d 9c 4b  |....f...b..w.}.K|
-00000010  69 65 aa dc 95 cb 78 08  3d d2 1a 0a 45 69 23 73  |ie....x.=...Ei#s|
-00000020  4f 41 4f 24 12 2e 57 47  b7 53 64 20 82 9a f8 e7  |OAO$..WG.Sd ....|
-00000030  79 f8 13 2c 9d cd b5 cb  cb 9a 95 56 0e e9 cb a8  |y..,.......V....|
-00000040  e4 a2 8a d6 bc dc fa 25  b3 57 cc cf c0 2f 00 00  |.......%.W.../..|
+00000000  16 03 03 00 66 02 00 00  62 03 03 7e 48 0b 4a 89  |....f...b..~H.J.|
+00000010  d3 3a a1 8a 8c 8b 11 bb  ea c5 21 5c df 3c 81 2b  |.:........!\.<.+|
+00000020  c5 c0 7c f9 fd d7 cb 10  1b dd d4 20 b4 8a a5 07  |..|........ ....|
+00000030  32 e7 04 9c 1c 73 87 cd  e3 ae ff 8b 5c d7 56 6c  |2....s......\.Vl|
+00000040  03 24 7d 35 4c ad 31 52  c3 cd 5c b0 c0 2f 00 00  |.$}5L.1R..\../..|
 00000050  1a ff 01 00 01 00 00 0b  00 04 03 00 01 02 00 10  |................|
 00000060  00 09 00 07 06 70 72 6f  74 6f 31 16 03 03 02 be  |.....proto1.....|
 00000070  0b 00 02 ba 00 02 b7 00  02 b4 30 82 02 b0 30 82  |..........0...0.|
 00000300  b6 d8 c9 75 90 96 8c 0f  52 98 b5 cd 98 1f 89 20  |...u....R...... |
 00000310  5f f2 a0 1c a3 1b 96 94  dd a9 fd 57 e9 70 e8 26  |_..........W.p.&|
 00000320  6d 71 99 9b 26 6e 38 50  29 6c 90 a7 bd d9 16 03  |mq..&n8P)l......|
-00000330  03 00 cd 0c 00 00 c9 03  00 17 41 04 1b 42 c3 ae  |..........A..B..|
-00000340  44 19 d3 84 7c 6c 98 cb  b9 22 a2 67 63 95 aa cc  |D...|l...".gc...|
-00000350  bd e4 1e f8 08 e6 60 f3  bc 83 9f 81 da 9c 1c 8c  |......`.........|
-00000360  ff 6f f4 3e 1e e5 3b f6  49 61 f9 70 43 7f c1 69  |.o.>..;.Ia.pC..i|
-00000370  de 73 98 4b bd 5c c3 78  24 18 a8 ec 04 01 00 80  |.s.K.\.x$.......|
-00000380  70 d2 5b e1 39 cf 4d 54  de d2 74 4e 5e a8 b3 ca  |p.[.9.MT..tN^...|
-00000390  e1 f2 4e 76 3c 77 8b ef  f7 d1 df b9 ad c1 70 39  |..Nv<w........p9|
-000003a0  c7 a3 1e 0f 7b 6c 78 2e  c1 86 d2 67 36 d8 25 e0  |....{lx....g6.%.|
-000003b0  e8 e5 cc 35 a2 96 a1 b4  b7 06 68 1e aa c7 06 97  |...5......h.....|
-000003c0  b7 c2 83 ce c0 17 dd 4f  9e 6f 7a bd cd c7 6e 7f  |.......O.oz...n.|
-000003d0  cb 80 d1 7d 06 2d f9 f1  fb 5f cc bb d8 62 5b f0  |...}.-..._...b[.|
-000003e0  27 12 57 d5 9b 55 aa 55  4b 9a 5a f6 a5 aa c1 82  |'.W..U.UK.Z.....|
-000003f0  39 11 6b dc 83 7f a8 47  28 5a 0f 3d 3f 0f c2 22  |9.k....G(Z.=?.."|
+00000330  03 00 cd 0c 00 00 c9 03  00 17 41 04 36 ae 35 52  |..........A.6.5R|
+00000340  e2 d1 7b 5f 96 91 06 73  30 0c c8 cb 42 e3 95 11  |..{_...s0...B...|
+00000350  52 02 5a 8a 8a a4 b3 f9  03 f0 6d 8b 23 3e 73 44  |R.Z.......m.#>sD|
+00000360  2d 3e fb 05 ac c2 0a f4  96 07 58 aa fc 9f f4 8b  |->........X.....|
+00000370  38 af 46 6a a6 87 b7 6d  65 eb 75 17 04 01 00 80  |8.Fj...me.u.....|
+00000380  44 0d 99 2f 79 3d 66 0b  7c 76 f8 95 14 78 90 f9  |D../y=f.|v...x..|
+00000390  ee bb 74 9b 01 25 62 a3  58 d6 8d 4b 43 0a 18 16  |..t..%b.X..KC...|
+000003a0  4d 44 fa 01 13 de 32 36  16 6a 4d 9a 6d ab dd e5  |MD....26.jM.m...|
+000003b0  a8 9d 9e 4a f8 18 fd da  95 99 02 20 29 b3 79 f6  |...J....... ).y.|
+000003c0  c7 c4 eb 81 45 ef 20 5f  2b ed 5f 72 a5 5f 99 0b  |....E. _+._r._..|
+000003d0  54 25 0d db 11 7f 64 ec  5a 2f 38 c7 74 29 77 f0  |T%....d.Z/8.t)w.|
+000003e0  4b 9c 92 72 02 4c f3 bf  ee ba e1 51 fb b4 ac e6  |K..r.L.....Q....|
+000003f0  0c 4c 19 bc 9a b7 e9 fd  8a 86 bf 37 d5 0b 1d 2a  |.L.........7...*|
 00000400  16 03 03 00 04 0e 00 00  00                       |.........|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 35 9d  |.....(........5.|
-00000060  92 e8 bf df 7f a7 77 1b  cf 03 2a bf e2 6c 62 2b  |......w...*..lb+|
-00000070  26 f0 fb 93 d3 df fd 55  84 d3 ed 88 31 cb        |&......U....1.|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 27 e5  |.....(........'.|
+00000060  ee c8 9a 3e d6 70 d6 1a  1b ad d2 1a 88 be 77 fd  |...>.p........w.|
+00000070  bc e2 33 13 22 52 df be  67 30 da 10 5c cf        |..3."R..g0..\.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 c8 c0 78 09 73  |..........(..x.s|
-00000010  58 41 73 66 88 cf db f3  fe c6 57 ab 45 be 2e d8  |XAsf......W.E...|
-00000020  4e e5 ff 42 57 13 74 d2  cc c2 62 07 39 8b 06 46  |N..BW.t...b.9..F|
-00000030  1d 8f 88                                          |...|
+00000000  14 03 03 00 01 01 16 03  03 00 28 81 ad 88 a5 2e  |..........(.....|
+00000010  1f 26 3c 53 16 a7 d4 c2  13 08 52 6e ac 3b 00 9d  |.&<S......Rn.;..|
+00000020  d9 ee d4 93 86 3f 8a 0e  d8 06 d9 61 a6 6f bf f9  |.....?.....a.o..|
+00000030  a9 1f fe                                          |...|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 10 c3 5f  |..............._|
-00000010  3f c8 92 6c 7a a7 23 05  f3 d8 31 20 01 52 f1 99  |?..lz.#...1 .R..|
-00000020  33 c1 2a 15 03 03 00 1a  00 00 00 00 00 00 00 02  |3.*.............|
-00000030  cc ef eb 78 e4 e1 9d 90  05 6d 95 ac f2 49 ba 8e  |...x.....m...I..|
-00000040  6b 8d                                             |k.|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 ab b6 ac  |................|
+00000010  55 5d 72 b0 7a a1 0e 17  8d 1b 71 77 79 ef 32 6b  |U]r.z.....qwy.2k|
+00000020  4e c2 df 15 03 03 00 1a  00 00 00 00 00 00 00 02  |N...............|
+00000030  34 1e 22 35 71 60 cd cf  75 2b 73 94 b6 5f 09 1d  |4."5q`..u+s.._..|
+00000040  1b b5                                             |..|
index f24a70cc8281d6046fdd03dae6e1121f744501d2..57f2f361b8d5128386f2dcd7e612d8eacc5c4a4c 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 86 01 00 00  82 03 03 00 00 00 00 00  |................|
+00000000  16 03 01 00 8a 01 00 00  86 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 3f 33 74 00 00  |./.5.......?3t..|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00 00 10  |................|
-00000080  00 09 00 07 06 70 72 6f  74 6f 33                 |.....proto3|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 3f  |...../.5.......?|
+00000050  33 74 00 00 00 05 00 05  01 00 00 00 00 00 0a 00  |3t..............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0a 00 08 04 01 04  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 10 00 09 00 07  06 70 72 6f 74 6f 33     |.........proto3|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 69 84 d1 d3 44  |....Y...U..i...D|
-00000010  e9 66 08 48 bc 70 d8 ae  40 0b 17 69 e7 27 f6 7a  |.f.H.p..@..i.'.z|
-00000020  d5 ee 86 74 54 9e a8 bb  79 76 89 20 57 53 1b 02  |...tT...yv. WS..|
-00000030  5b 70 81 a6 f1 53 bc 9d  b7 42 5e ac 92 93 b5 20  |[p...S...B^.... |
-00000040  8a bb 36 cc 8f cb 7e a0  61 a2 e8 ef c0 2f 00 00  |..6...~.a..../..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 f0 ff a6 91 ca  |....Y...U.......|
+00000010  e9 d7 bc 31 4c 5e 15 b0  24 41 78 17 87 a8 1c 7d  |...1L^..$Ax....}|
+00000020  eb bd 28 f6 57 7f 01 ab  b4 02 a7 20 38 08 43 7e  |..(.W...... 8.C~|
+00000030  ca 3c 5f ba 62 bb b0 10  30 f3 f2 03 68 ef 01 43  |.<_.b...0...h..C|
+00000040  3b 70 2c 37 80 fe 1c af  bc f5 db 60 c0 2f 00 00  |;p,7.......`./..|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
 00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
 000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
 00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
 00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
-00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 04  |.............A..|
-00000330  be 27 08 6f 12 83 1b 04  76 fa 5f 16 d6 e3 64 76  |.'.o....v._...dv|
-00000340  ad 0a 77 37 71 64 44 4c  3f 1a be dc 85 ce 46 c8  |..w7qdDL?.....F.|
-00000350  29 a1 e2 24 78 66 1f 35  90 05 46 c0 91 d1 fd dd  |)..$xf.5..F.....|
-00000360  b5 5b 87 d7 6d 9d 77 a7  f7 b3 df 68 27 fd 6d 04  |.[..m.w....h'.m.|
-00000370  01 00 80 7b 9b fd 0d 62  57 07 ef 97 f5 ff a9 00  |...{...bW.......|
-00000380  a0 89 35 5a 8a e6 e7 ae  7b 55 c5 dc 21 64 87 6e  |..5Z....{U..!d.n|
-00000390  0f ab 85 6d 82 e8 83 fd  7d 3b 49 a7 ae 92 5f 6d  |...m....};I..._m|
-000003a0  a3 42 ce ff ef a6 00 6a  33 32 1f 7b eb b7 c2 5c  |.B.....j32.{...\|
-000003b0  2d 38 cf 10 4b 59 69 4d  15 e0 68 49 39 ba cb 2a  |-8..KYiM..hI9..*|
-000003c0  d9 b9 f3 fe 33 01 4f 7e  ac 69 02 35 a5 e0 33 8d  |....3.O~.i.5..3.|
-000003d0  b3 74 34 14 45 9c 89 ad  41 2d d0 27 22 90 58 c6  |.t4.E...A-.'".X.|
-000003e0  e0 2c b4 6e 19 04 e4 46  26 ec 13 35 48 a6 3f 64  |.,.n...F&..5H.?d|
-000003f0  dc 85 2b 16 03 03 00 04  0e 00 00 00              |..+.........|
+00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 4e  |.............A.N|
+00000330  38 ec 28 ce cb f6 6b 74  96 74 92 46 9a 41 4a 02  |8.(...kt.t.F.AJ.|
+00000340  33 cb f0 d9 24 20 fd e0  d4 8b 24 b2 1f 24 ac 38  |3...$ ....$..$.8|
+00000350  79 cc ec ff 25 c9 30 f6  85 84 51 ee cb 59 8b 0d  |y...%.0...Q..Y..|
+00000360  e2 38 3d e0 24 83 84 da  ef 67 f5 f7 8a 0a c0 04  |.8=.$....g......|
+00000370  01 00 80 82 72 af cb 74  fb 8c 02 d5 d4 d9 26 04  |....r..t......&.|
+00000380  06 59 64 f0 50 ce cf ed  15 b4 24 95 47 8a c6 17  |.Yd.P.....$.G...|
+00000390  b0 da a4 13 20 88 e9 b8  ef cd b2 f1 35 5a 88 81  |.... .......5Z..|
+000003a0  19 03 ee f4 74 a2 23 27  bc e9 bf f2 06 06 58 f3  |....t.#'......X.|
+000003b0  ef b6 5e de 76 58 8c ec  a6 d0 d3 1e 44 ec ac 61  |..^.vX......D..a|
+000003c0  62 91 a6 9e 36 ef 64 e9  a5 2e e8 88 69 30 0f b3  |b...6.d.....i0..|
+000003d0  84 0a b4 d1 3b a5 fe 9e  96 1a ad 7b 8a 24 7e a7  |....;......{.$~.|
+000003e0  af 5b 6d 11 be 1f 2b 7a  5f 62 f7 ae be 2e 99 ec  |.[m...+z_b......|
+000003f0  05 b6 7c 16 03 03 00 04  0e 00 00 00              |..|.........|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 88 0d  |.....(..........|
-00000060  04 8b 8e 93 55 58 d6 75  ca 16 26 42 a3 60 20 67  |....UX.u..&B.` g|
-00000070  84 cf d7 b3 10 fe 63 6c  2f 40 64 0c d6 78        |......cl/@d..x|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 d4 91  |.....(..........|
+00000060  e7 17 05 14 7a ce cf 0c  3b c1 a6 a7 4a 57 70 9a  |....z...;...JWp.|
+00000070  cf 0e ec 59 19 d3 ba 90  97 51 8b 60 8e 03        |...Y.....Q.`..|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 bd 6c 2f 70 b9  |..........(.l/p.|
-00000010  2f 9c 29 70 af 34 49 4c  5b 25 c3 14 b6 6d 28 81  |/.)p.4IL[%...m(.|
-00000020  ff 54 d9 71 8d 2c c7 38  dd 44 27 6b 54 1e 53 7b  |.T.q.,.8.D'kT.S{|
-00000030  22 cb 65                                          |".e|
+00000000  14 03 03 00 01 01 16 03  03 00 28 55 64 22 e3 20  |..........(Ud". |
+00000010  eb 69 63 44 b4 68 89 29  d6 c8 83 d8 6c 30 2f af  |.icD.h.)....l0/.|
+00000020  2a 86 b0 ea ce 57 b8 9c  69 9a e3 fe 86 7e 0a bf  |*....W..i....~..|
+00000030  08 f1 fe                                          |...|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 7f 0d d7  |................|
-00000010  d9 4b 87 7b 36 fb 24 92  69 22 43 50 1e 46 fb c4  |.K.{6.$.i"CP.F..|
-00000020  86 64 6f 15 03 03 00 1a  00 00 00 00 00 00 00 02  |.do.............|
-00000030  37 d5 2d 0a be c5 a8 ae  d4 bd 2b 09 34 18 a0 87  |7.-.......+.4...|
-00000040  08 a6                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 29 39 41  |.............)9A|
+00000010  c4 ff e3 3e 38 bf 06 09  d2 d9 05 84 66 60 58 e8  |...>8.......f`X.|
+00000020  3a 74 f5 15 03 03 00 1a  00 00 00 00 00 00 00 02  |:t..............|
+00000030  b4 1f e4 7b 84 1e 87 57  97 f6 f2 12 df 40 85 fe  |...{...W.....@..|
+00000040  d0 d1                                             |..|
index 20732703647551c4f5aca8d99d663ba0a24220dc..7871a05ed98f2dbedc073cfc29987536434f2c82 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 03 6f  |....Y...U..S...o|
-00000010  c6 4b 55 27 fe e8 fe 4d  7c 0e d4 20 98 b8 7c 81  |.KU'...M|.. ..|.|
-00000020  3d 31 f8 35 66 2f 0a 0b  f1 2c e3 20 86 4d 12 32  |=1.5f/...,. .M.2|
-00000030  73 e3 ba be 25 50 a4 a2  a1 7b f1 9a 76 7a 75 fb  |s...%P...{..vzu.|
-00000040  e2 64 a2 12 ec f3 e7 9d  9a 24 6e 94 c0 09 00 00  |.d.......$n.....|
+00000000  16 03 03 00 59 02 00 00  55 03 03 e1 64 a4 cd 65  |....Y...U...d..e|
+00000010  5a 19 5f 07 68 cb af f2  74 76 a2 99 18 e4 9e 00  |Z._.h...tv......|
+00000020  6a 72 6b 84 dd 1c ec cd  64 45 34 20 96 c3 54 88  |jrk.....dE4 ..T.|
+00000030  00 ec aa 32 95 2c ad 08  47 64 fd 2e d4 1f 8e 5e  |...2.,..Gd.....^|
+00000040  ec 39 aa ba 6a 3c 8c c7  a6 63 55 8e c0 09 00 00  |.9..j<...cU.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 a3  |*............A..|
-00000280  03 8c de d2 b0 68 c8 25  0e 85 ea d7 ae 13 0d 79  |.....h.%.......y|
-00000290  ec 59 0d b5 4d 51 96 d9  7f 64 36 fb 4c d5 6a 26  |.Y..MQ...d6.L.j&|
-000002a0  ae 0e 48 61 df 5c 2b d4  ff 09 41 15 c4 14 8e 1b  |..Ha.\+...A.....|
-000002b0  84 a8 c8 cd ef 10 97 95  66 67 85 dd fd dc 2a 04  |........fg....*.|
-000002c0  03 00 8a 30 81 87 02 41  11 75 5d bc bd 08 28 d4  |...0...A.u]...(.|
-000002d0  5b 1b 45 7f 9c d3 8d 0b  91 fa f6 82 ba 59 bd 3e  |[.E..........Y.>|
-000002e0  96 01 c6 1d 38 db fe 08  e7 56 89 fc 10 b0 37 6a  |....8....V....7j|
-000002f0  3d d6 c9 50 16 53 f7 c2  a2 60 67 82 1f 74 b8 d5  |=..P.S...`g..t..|
-00000300  bc 02 ec 96 db 82 18 8c  87 02 42 01 0d df f7 b7  |..........B.....|
-00000310  05 3c 8c 56 f0 1d 33 18  cf c5 4c 80 7e 0b d9 f9  |.<.V..3...L.~...|
-00000320  f0 51 69 fe 5d b8 0b 64  c0 c7 0d f4 75 65 ae 07  |.Qi.]..d....ue..|
-00000330  9d cf f4 4b ad 52 f6 b8  10 26 18 bd d6 e2 0d a8  |...K.R...&......|
-00000340  80 10 50 34 15 cd 72 0b  7d a9 94 de 4c 16 03 03  |..P4..r.}...L...|
-00000350  00 30 0d 00 00 28 03 01  02 40 00 20 06 01 06 02  |.0...(...@. ....|
-00000360  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000370  03 02 03 03 02 01 02 02  02 03 01 01 00 00 0e 00  |................|
-00000380  00 00                                             |..|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 bb  |*............A..|
+00000280  6d 5c 62 98 a7 6c bd f1  9b 4b 09 16 31 59 6a 51  |m\b..l...K..1YjQ|
+00000290  83 c8 9f 75 9c f8 09 b0  ee 39 01 e3 7a 25 9d 66  |...u.....9..z%.f|
+000002a0  fe 14 14 15 45 1b 51 a4  47 fe 1e 58 01 28 96 13  |....E.Q.G..X.(..|
+000002b0  2a 0e 0b 40 b2 22 db 2f  e6 f4 88 0a 58 92 10 04  |*..@."./....X...|
+000002c0  03 00 8b 30 81 88 02 42  01 13 f5 38 52 04 f7 3b  |...0...B...8R..;|
+000002d0  55 96 ef 39 77 be 4f 85  07 18 e9 47 49 b4 bb 57  |U..9w.O....GI..W|
+000002e0  c9 c0 93 2e 9e b2 5e 3f  14 ce 43 f0 93 b5 a4 66  |......^?..C....f|
+000002f0  8c fe 3a 06 fc a7 bb 9d  87 46 b8 20 1f 0a 31 c6  |..:......F. ..1.|
+00000300  80 b0 2d fa e5 06 5f 78  b2 da 02 42 01 c0 bd 12  |..-..._x...B....|
+00000310  5b ec 79 dd bf a4 54 f1  3b a8 b8 9a 50 ac a9 7c  |[.y...T.;...P..||
+00000320  d2 a6 b5 dd 84 ee dd eb  3e c7 52 1c 65 ac 1e 37  |........>.R.e..7|
+00000330  4f a8 87 fa 05 8a a4 69  c9 59 53 65 ee 8e 4c 1b  |O......i.YSe..L.|
+00000340  6c d0 88 b8 65 de 85 f8  fe f9 27 96 b8 c0 16 03  |l...e.....'.....|
+00000350  03 00 2e 0d 00 00 26 03  01 02 40 00 1e 06 01 06  |......&...@.....|
+00000360  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000370  01 03 02 03 03 02 01 02  02 02 03 00 00 0e 00 00  |................|
+00000380  00                                                |.|
 >>> Flow 3 (client to server)
 00000000  16 03 03 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
 00000220  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
 00000230  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 00000240  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 03 00 92 0f  |.h.A.Vk.Z.......|
-00000260  00 00 8e 04 03 00 8a 30  81 87 02 42 00 c6 85 8e  |.......0...B....|
-00000270  06 b7 04 04 e9 cd 9e 3e  cb 66 23 95 b4 42 9c 64  |.......>.f#..B.d|
-00000280  81 39 05 3f b5 21 f8 28  af 60 6b 4d 3d ba a1 4b  |.9.?.!.(.`kM=..K|
-00000290  5e 77 ef e7 59 28 fe 1d  c1 27 a2 ff a8 de 33 48  |^w..Y(...'....3H|
-000002a0  b3 c1 85 6a 42 9b f9 7e  7e 31 c2 e5 bd 66 02 41  |...jB..~~1...f.A|
-000002b0  4b 49 c6 cd 02 e3 83 f7  03 50 18 6d b4 c9 51 02  |KI.......P.m..Q.|
-000002c0  c0 ab 87 bc e0 3e 4b 89  53 3a e2 65 89 97 02 c1  |.....>K.S:.e....|
-000002d0  88 0d 64 db 8e 4f 73 4e  ea 29 0b ed a0 f5 ce 3d  |..d..OsN.).....=|
-000002e0  5f cc 20 ef 0a 22 02 82  f2 14 2a b7 42 68 bd c7  |_. .."....*.Bh..|
-000002f0  4d 14 03 03 00 01 01 16  03 03 00 40 00 00 00 00  |M..........@....|
-00000300  00 00 00 00 00 00 00 00  00 00 00 00 f0 cc 4f c7  |..............O.|
-00000310  b6 0f c9 38 4d 4b 97 2c  4f be 53 08 4c d6 5b 4e  |...8MK.,O.S.L.[N|
-00000320  24 70 30 81 82 3a 7f 62  95 03 4d fc 54 78 ec 13  |$p0..:.b..M.Tx..|
-00000330  b2 a1 00 85 2b 04 e4 1d  7b 6e 87 60              |....+...{n.`|
+00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 03 00 93 0f  |.h.A.Vk.Z.......|
+00000260  00 00 8f 04 03 00 8b 30  81 88 02 42 00 e9 db 80  |.......0...B....|
+00000270  e2 67 5d 00 21 88 67 99  7f df de 90 77 86 1e b7  |.g].!.g.....w...|
+00000280  28 b1 2d 08 8d 02 de 9a  29 2b ca b9 9c 48 ad bd  |(.-.....)+...H..|
+00000290  58 16 68 ad a3 0f 08 4c  01 52 e7 54 97 7c 06 0a  |X.h....L.R.T.|..|
+000002a0  9e c8 97 61 e6 a9 53 62  fb b1 e3 b1 d7 03 02 42  |...a..Sb.......B|
+000002b0  01 f3 99 af dc e6 69 af  1d fb d5 d0 63 bd d1 17  |......i.....c...|
+000002c0  d2 ca a5 10 97 1a 94 93  df c4 94 27 53 77 1a 9e  |...........'Sw..|
+000002d0  9b a5 e6 dd 0d cf 49 46  4c 5b 83 a4 52 f2 8b d6  |......IFL[..R...|
+000002e0  b2 5f 40 e5 c3 d6 7f a2  2c 50 4d 4c 81 54 80 5b  |._@.....,PML.T.[|
+000002f0  72 c7 14 03 03 00 01 01  16 03 03 00 40 00 00 00  |r...........@...|
+00000300  00 00 00 00 00 00 00 00  00 00 00 00 00 96 9f 5a  |...............Z|
+00000310  9c e3 d0 6c 5f 11 c4 cf  e4 34 1a 54 7e dc ec 1d  |...l_....4.T~...|
+00000320  cd 08 eb 5c b4 32 1b d0  e5 12 1f 7a e7 86 16 56  |...\.2.....z...V|
+00000330  a7 10 20 e1 59 31 65 63  12 7d 45 2d 2a           |.. .Y1ec.}E-*|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 d5 2a 76 79 1c  |..........@.*vy.|
-00000010  e7 d5 b1 5c 65 6b d1 45  73 53 4c 05 3a 6c 5d 81  |...\ek.EsSL.:l].|
-00000020  dd 2f f0 74 62 e4 8e f8  ed 21 99 c7 4f d6 28 40  |./.tb....!..O.(@|
-00000030  63 d9 6d e5 b0 04 73 27  7a 1d 08 19 31 10 da ef  |c.m...s'z...1...|
-00000040  79 26 33 fb 45 23 be a4  7c 03 66                 |y&3.E#..|.f|
+00000000  14 03 03 00 01 01 16 03  03 00 40 54 bd b1 39 e6  |..........@T..9.|
+00000010  a7 d0 76 5e 7e 91 0d 81  d1 c6 82 05 79 90 24 fc  |..v^~.......y.$.|
+00000020  26 b7 ec e6 b8 72 05 59  bd 00 99 f7 dd f4 44 1e  |&....r.Y......D.|
+00000030  79 4d 6d a1 22 4a e3 2c  41 05 ec 5a f7 32 17 ff  |yMm."J.,A..Z.2..|
+00000040  d3 1b ee 21 71 98 99 b7  85 34 b3                 |...!q....4.|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 e2 53 bd  c0 ef 9e e6 44 94 ea 5d  |......S.....D..]|
-00000020  f5 c5 a9 4b ed eb 1c 49  9f 79 44 f9 cd d7 de 02  |...K...I.yD.....|
-00000030  51 10 ae 87 7d 15 03 03  00 30 00 00 00 00 00 00  |Q...}....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 d3 95 13 7f 5f 58  |.............._X|
-00000050  ab d6 17 ea 01 2c 2a ea  5d 7c 44 61 4a 27 97 52  |.....,*.]|DaJ'.R|
-00000060  cc 9b 86 f6 37 42 2b 94  01 49                    |....7B+..I|
+00000010  00 00 00 00 00 b9 81 3f  48 14 95 9b 39 85 2a 9e  |.......?H...9.*.|
+00000020  44 ec bb cf c2 29 a9 44  f7 8a 6b 3f 92 13 dd 0e  |D....).D..k?....|
+00000030  c6 6b a1 51 79 15 03 03  00 30 00 00 00 00 00 00  |.k.Qy....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 1c 93 91 23 12 11  |.............#..|
+00000050  cc 30 fb 22 9e 23 b7 60  8a 3d 4c e6 52 2b 3e 6b  |.0.".#.`.=L.R+>k|
+00000060  8e 47 91 b1 68 50 07 8a  d1 6f                    |.G..hP...o|
index c3b753a7b44dd8028631c20b30a1bd9c005e3583..24c1b9acdd2846d33192f240452a53abd154e33e 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 53 04 f1 03 b0  |....Q...M..S....|
-00000010  43 00 97 24 a7 a8 ea b2  24 fe 96 24 a1 49 64 fd  |C..$....$..$.Id.|
-00000020  1c a3 30 35 2d 85 a7 40  42 86 6b 20 af 27 7f ac  |..05-..@B.k .'..|
-00000030  8b 16 89 6c 78 b7 f5 29  02 58 a6 8b 61 43 c2 b0  |...lx..).X..aC..|
-00000040  e0 a8 96 c8 fa 2b 26 ad  9a 5f 2d d6 00 05 00 00  |.....+&.._-.....|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 7a 6c c2 d1 69  |....Q...M..zl..i|
+00000010  af 86 6f 03 3c e4 70 ae  03 39 fd c6 3a a9 a4 b2  |..o.<.p..9..:...|
+00000020  96 1e 50 f2 f4 16 50 e4  a2 f2 41 20 f8 83 3b 45  |..P...P...A ..;E|
+00000030  0d 5b 88 bc 87 6c 81 23  e3 1d e0 7e 22 f5 6d 95  |.[...l.#...~".m.|
+00000040  58 63 39 cf 4f 80 80 cc  41 bb b1 4c 00 05 00 00  |Xc9.O...A..L....|
 00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
 000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
 000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
 00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 30 0d 00  |n8P)l........0..|
-00000320  00 28 03 01 02 40 00 20  06 01 06 02 06 03 05 01  |.(...@. ........|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 2e 0d 00  |n8P)l...........|
+00000320  00 26 03 01 02 40 00 1e  06 01 06 02 06 03 05 01  |.&...@..........|
 00000330  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-00000340  02 01 02 02 02 03 01 01  00 00 0e 00 00 00        |..............|
+00000340  02 01 02 02 02 03 00 00  0e 00 00 00              |............|
 >>> Flow 3 (client to server)
 00000000  16 03 03 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
 00000260  ce 39 4c 9c 86 00 08 c2  4b e2 c6 ec 2f f7 ce e6  |.9L.....K.../...|
 00000270  bd 77 82 6f 23 b6 e0 bd  a2 92 b7 3a ac e8 56 f1  |.w.o#......:..V.|
 00000280  af 54 5e 46 87 e9 3b 33  e7 b8 28 b7 d6 c8 90 35  |.T^F..;3..(....5|
-00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 03 00 92 0f  |..C.0oUN.p......|
-000002a0  00 00 8e 04 03 00 8a 30  81 87 02 42 00 c6 85 8e  |.......0...B....|
-000002b0  06 b7 04 04 e9 cd 9e 3e  cb 66 23 95 b4 42 9c 64  |.......>.f#..B.d|
-000002c0  81 39 05 3f b5 21 f8 28  af 60 6b 4d 3d ba a1 4b  |.9.?.!.(.`kM=..K|
-000002d0  5e 77 ef e7 59 28 fe 1d  c1 27 a2 ff a8 de 33 48  |^w..Y(...'....3H|
-000002e0  b3 c1 85 6a 42 9b f9 7e  7e 31 c2 e5 bd 66 02 41  |...jB..~~1...f.A|
-000002f0  4b 49 c6 cd 02 e3 83 f7  03 50 18 6d b4 c9 51 02  |KI.......P.m..Q.|
-00000300  c0 ab 87 bc e0 3e 4b 89  53 3a e2 65 89 97 02 c1  |.....>K.S:.e....|
-00000310  88 5a 97 82 3e 55 6b 7c  d8 db b8 cc 1b 30 84 0a  |.Z..>Uk|.....0..|
-00000320  7a 97 71 e4 10 bb a4 39  8c 2a cf f5 88 c7 d1 95  |z.q....9.*......|
-00000330  73 14 03 03 00 01 01 16  03 03 00 24 9f 1e f0 72  |s..........$...r|
-00000340  92 ea dc f7 56 96 37 e4  69 db db 66 1d f6 94 c4  |....V.7.i..f....|
-00000350  18 31 4f d0 5d c5 f4 53  21 aa 98 b1 dc 08 94 94  |.1O.]..S!.......|
+00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 03 00 93 0f  |..C.0oUN.p......|
+000002a0  00 00 8f 04 03 00 8b 30  81 88 02 42 00 87 a3 50  |.......0...B...P|
+000002b0  77 2a 46 97 68 1e ca 47  d2 46 a3 f7 37 e7 1c 3c  |w*F.h..G.F..7..<|
+000002c0  e3 16 dc b9 93 b9 76 af  da 46 b1 da 47 bc 8b 9c  |......v..F..G...|
+000002d0  ff 61 76 45 2b cf a6 85  4a 45 d4 51 98 18 31 c5  |.avE+...JE.Q..1.|
+000002e0  61 54 3b ae 88 ca 56 ac  90 29 de f2 20 a6 02 42  |aT;...V..).. ..B|
+000002f0  01 0d 54 c6 a5 14 c2 c0  83 5d ee 32 d3 c6 05 d7  |..T......].2....|
+00000300  0c 40 42 ca 8a 69 5e cc  9b f5 c4 9b 7c 81 e9 b7  |.@B..i^.....|...|
+00000310  dd 01 c0 e5 93 de 75 d2  6b 26 dd 16 2a ec d0 0e  |......u.k&..*...|
+00000320  50 76 ee 36 ac 42 a3 0b  64 dd 4d 47 18 3e 5c 18  |Pv.6.B..d.MG.>\.|
+00000330  16 3b 14 03 03 00 01 01  16 03 03 00 24 c2 c7 3a  |.;..........$..:|
+00000340  a2 9b 93 ea 75 1c b6 47  60 2e 15 cf b8 63 73 8a  |....u..G`....cs.|
+00000350  2c b8 86 a8 12 1d cb 30  e2 38 fe 0f 02 57 43 f0  |,......0.8...WC.|
+00000360  07                                                |.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 ee 68 c1 87 9f  |..........$.h...|
-00000010  d7 90 94 f1 3b 6d 26 0b  3d 89 7a 45 3b 52 5d 3c  |....;m&.=.zE;R]<|
-00000020  dd 7c c1 4e 57 3e a9 ee  91 be cf 2b a3 98 9d     |.|.NW>.....+...|
+00000000  14 03 03 00 01 01 16 03  03 00 24 ca e7 84 5c 1b  |..........$...\.|
+00000010  94 4c d8 78 6f 3f 80 b2  f9 9f fd c5 a5 fd 6f 89  |.L.xo?........o.|
+00000020  d7 50 a1 81 bf d0 9d eb  75 10 69 97 35 74 06     |.P......u.i.5t.|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a 88 33 3e  2b 22 6b 92 d0 bb 8a 1e  |......3>+"k.....|
-00000010  9b f4 9e aa 91 8b 2b 95  ea 53 c8 03 0a 93 58 15  |......+..S....X.|
-00000020  03 03 00 16 c4 67 79 ba  ec cf 90 b1 f9 ac ec 64  |.....gy........d|
-00000030  72 01 08 8f 3a 98 aa 66  25 00                    |r...:..f%.|
+00000000  17 03 03 00 1a 4a 11 45  18 75 a7 47 d3 36 ad 24  |.....J.E.u.G.6.$|
+00000010  fc d0 68 44 f2 9a 05 54  a2 44 e3 a7 33 74 99 15  |..hD...T.D..3t..|
+00000020  03 03 00 16 d5 d5 75 a9  a9 ef f5 31 50 f7 00 08  |......u....1P...|
+00000030  78 0a 00 1f c8 42 db c7  15 6b                    |x....B...k|
index 0037af61a03a9af5717cf6229db657120b6e1225..e77002665fbaf4cf444ab0a6cd5353b8225cfbd8 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 fd  |....Y...U..S....|
-00000010  41 bd ef ee f3 da fc 1a  31 8c 77 f2 e9 66 54 a0  |A.......1.w..fT.|
-00000020  f4 15 b1 1c 84 0d 6d 74  87 ac 7d 20 78 17 8b 08  |......mt..} x...|
-00000030  10 20 c9 44 e4 8a 43 af  4a c7 b8 3d 99 f2 f7 af  |. .D..C.J..=....|
-00000040  bb a3 21 2f 40 cc ed b6  da a8 a1 d5 c0 09 00 00  |..!/@...........|
+00000000  16 03 03 00 59 02 00 00  55 03 03 ef cd 72 a3 35  |....Y...U....r.5|
+00000010  e7 11 9f 67 a4 42 9e 34  03 b4 ab e1 0d 4f a4 09  |...g.B.4.....O..|
+00000020  4e e1 8d 52 d2 d0 0e 0e  f0 7a 74 20 da 3f 9c d8  |N..R.....zt .?..|
+00000030  e3 c6 5c a1 e8 5e a0 48  50 e8 70 aa 96 a7 84 4a  |..\..^.HP.p....J|
+00000040  3a b3 c3 21 24 30 6c 7a  d5 b4 9b 9c c0 09 00 00  |:..!$0lz........|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 a9  |*............A..|
-00000280  19 8b d9 9b 5c 7c 6a 7d  85 d2 70 4e 89 7e 0b 5b  |....\|j}..pN.~.[|
-00000290  dd 5e a1 63 8d 15 bc 0b  0c 47 3d 4d e8 a7 56 88  |.^.c.....G=M..V.|
-000002a0  2e f6 7f e2 4d fc ed cc  03 ed a1 2d ac ae 81 a5  |....M......-....|
-000002b0  e2 6d 7f 9f a3 93 e9 10  c1 0e 48 1b f3 f4 38 04  |.m........H...8.|
-000002c0  03 00 8b 30 81 88 02 42  00 87 fe 7e 63 82 14 57  |...0...B...~c..W|
-000002d0  dc 7d e2 0f cc 97 2d ba  3c a7 56 4a 17 a8 09 6a  |.}....-.<.VJ...j|
-000002e0  28 2e f2 66 1a 3f 2d 48  2b 6f 79 a1 60 cd 5e 10  |(..f.?-H+oy.`.^.|
-000002f0  0b 0a 28 f2 5f e4 3f 4f  f9 c9 91 34 d9 dc bc fc  |..(._.?O...4....|
-00000300  98 ea 77 0b 99 f8 a2 11  c4 bd 02 42 01 a0 b0 dc  |..w........B....|
-00000310  db 5b c2 09 99 bd ee a0  b9 aa 31 b9 10 84 22 be  |.[........1...".|
-00000320  5a 63 12 5a 43 00 8e c1  33 cc 91 bb c2 70 7a 63  |Zc.ZC...3....pzc|
-00000330  19 82 c0 74 48 a1 c7 3d  1f f1 6f 4a 6f 6a 8c 3f  |...tH..=..oJoj.?|
-00000340  28 31 a8 0c 65 19 26 62  4b 7a 7c 4b ea 1a 16 03  |(1..e.&bKz|K....|
-00000350  03 00 30 0d 00 00 28 03  01 02 40 00 20 06 01 06  |..0...(...@. ...|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 7e  |*............A.~|
+00000280  3b ae 99 3d b7 3b da 7a  44 b1 b3 0d 41 36 c5 47  |;..=.;.zD...A6.G|
+00000290  b2 b9 65 44 79 2a c4 a9  e3 a8 ee 6a 77 3b ee d8  |..eDy*.....jw;..|
+000002a0  ee 11 0a 20 61 9b be 03  54 29 63 b3 fb 91 6f 34  |... a...T)c...o4|
+000002b0  cb ad 6c 5e 00 5f 0a c7  fd 70 d4 d6 de 5a 00 04  |..l^._...p...Z..|
+000002c0  03 00 8b 30 81 88 02 42  00 c2 21 72 c5 61 07 2f  |...0...B..!r.a./|
+000002d0  0e af fd d5 22 43 e5 2e  06 51 29 73 c2 ec 50 34  |...."C...Q)s..P4|
+000002e0  76 ab 67 fe 37 49 68 54  4b 16 d2 7a 4c 04 02 b2  |v.g.7IhTK..zL...|
+000002f0  0a 66 28 fb b5 bf 5b 00  4b dc bf e2 9e 99 a7 0c  |.f(...[.K.......|
+00000300  7c 64 36 79 d6 4e 99 70  5f 97 02 42 01 bb 4b 10  ||d6y.N.p_..B..K.|
+00000310  36 f1 38 c1 42 de e9 68  41 2d 0a 4b 19 eb 3c 6b  |6.8.B..hA-.K..<k|
+00000320  cd 11 3e 20 3f 95 c3 c7  ba 18 0c 4a 6a da 45 77  |..> ?......Jj.Ew|
+00000330  8c 8d f4 01 d3 15 91 3e  64 22 16 bd b5 2a 07 52  |.......>d"...*.R|
+00000340  63 e5 de 0c 22 90 2e 2f  e9 b4 3f ab b8 27 16 03  |c..."../..?..'..|
+00000350  03 00 2e 0d 00 00 26 03  01 02 40 00 1e 06 01 06  |......&...@.....|
 00000360  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
-00000370  01 03 02 03 03 02 01 02  02 02 03 01 01 00 00 0e  |................|
-00000380  00 00 00                                          |...|
+00000370  01 03 02 03 03 02 01 02  02 02 03 00 00 0e 00 00  |................|
+00000380  00                                                |.|
 >>> Flow 3 (client to server)
 00000000  16 03 03 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
 00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
 00000220  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000230  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000240  a6 b5 68 1a 41 03 56 6b  dc 5a 89 16 03 03 00 88  |..h.A.Vk.Z......|
-00000250  0f 00 00 84 04 01 00 80  38 f2 16 e5 b5 86 16 62  |........8......b|
-00000260  86 e1 7d 01 f1 a8 e1 f7  e7 85 b1 a0 17 ee 84 25  |..}............%|
-00000270  cb 3c 46 61 1a 78 7b 1e  ee 32 bc d9 6c fa 6b 76  |.<Fa.x{..2..l.kv|
-00000280  67 a7 9e c8 7a 4c e8 79  0d 22 27 ad e7 98 6a 98  |g...zL.y."'...j.|
-00000290  89 88 8b a9 69 5b 6f c6  00 48 9a 21 77 a9 7c 15  |....i[o..H.!w.|.|
-000002a0  ba 47 16 74 8d 6c 67 dc  6d f1 98 b6 61 e8 bc 08  |.G.t.lg.m...a...|
-000002b0  18 53 a6 93 bf fc 27 5e  b7 4d d2 eb 68 e9 23 ee  |.S....'^.M..h.#.|
-000002c0  d2 70 d2 55 2c c7 99 7d  c0 66 b5 1c ea 38 71 5c  |.p.U,..}.f...8q\|
-000002d0  a6 57 1f 52 e4 8e e8 51  14 03 03 00 01 01 16 03  |.W.R...Q........|
+00000250  0f 00 00 84 04 01 00 80  07 7e 14 14 83 b9 d9 52  |.........~.....R|
+00000260  fd db c0 a4 79 37 b7 91  0b bb d6 ab d0 d1 c8 2e  |....y7..........|
+00000270  35 5b 58 3f ce 6b f6 a9  01 95 34 a9 8b da 6b 23  |5[X?.k....4...k#|
+00000280  b7 99 11 75 3e f8 db bc  ab 9b d4 8f 4f 89 12 d9  |...u>.......O...|
+00000290  2d 18 0e 54 2d 61 ff 9a  0e 3d 50 66 1d c2 e0 f6  |-..T-a...=Pf....|
+000002a0  4d 65 ca e2 08 af 29 cf  6d ab 63 72 ad 7c 03 a1  |Me....).m.cr.|..|
+000002b0  1e a1 f4 75 f5 54 58 28  3b 7d f7 21 d5 67 ec 60  |...u.TX(;}.!.g.`|
+000002c0  3b 59 81 ac f5 9a c6 cb  6a af da 7e 29 c4 c2 68  |;Y......j..~)..h|
+000002d0  53 34 aa b8 0e 58 61 24  14 03 03 00 01 01 16 03  |S4...Xa$........|
 000002e0  03 00 40 00 00 00 00 00  00 00 00 00 00 00 00 00  |..@.............|
-000002f0  00 00 00 5e e7 6e 1c a2  02 24 34 f0 a6 b6 27 ea  |...^.n...$4...'.|
-00000300  69 d5 0e 2e a8 ad 5c ad  6c 06 78 68 39 92 27 f1  |i.....\.l.xh9.'.|
-00000310  e8 35 49 67 4d fb 5d 8a  31 2e 4e 3f 19 ed ea 30  |.5IgM.].1.N?...0|
-00000320  20 60 e1                                          | `.|
+000002f0  00 00 00 a4 af 4b 95 ec  53 cf 49 8d b4 6c e0 3b  |.....K..S.I..l.;|
+00000300  76 60 23 9b 2a f3 2c 12  61 18 cf 56 7c 1d 8c 01  |v`#.*.,.a..V|...|
+00000310  a8 bb 19 4d 1f ff ff 73  a2 90 e5 87 7b 85 d3 1b  |...M...s....{...|
+00000320  74 6d 36                                          |tm6|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 ee a8 82 bc 3f  |..........@....?|
-00000010  bf ab a6 e4 30 e0 3d f1  2f 19 a2 ac 7a 81 57 f1  |....0.=./...z.W.|
-00000020  ee 67 3f 55 2b 30 fa 72  b5 10 03 ec 8d 0a 8f bb  |.g?U+0.r........|
-00000030  24 f5 45 f5 4e 53 4b 93  a5 0d 42 6c 46 69 98 fb  |$.E.NSK...BlFi..|
-00000040  63 c5 9f 95 65 d1 b6 f0  a4 15 bd                 |c...e......|
+00000000  14 03 03 00 01 01 16 03  03 00 40 fb 28 05 0a 99  |..........@.(...|
+00000010  61 d1 c7 52 a7 9e 95 a5  c1 11 3c 81 ee f2 b8 68  |a..R......<....h|
+00000020  a6 35 e2 7e bb 3c e7 7b  61 72 08 29 3a a5 e9 d3  |.5.~.<.{ar.):...|
+00000030  39 9c d2 0f 38 12 9b 92  79 36 58 bc f3 23 85 76  |9...8...y6X..#.v|
+00000040  1c 7b 6c 49 0c bc 00 61  20 1b ff                 |.{lI...a ..|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 cb 4e bc  d1 a9 58 ef c8 39 a9 36  |......N...X..9.6|
-00000020  f4 35 05 96 8e a4 50 bc  f4 15 06 f9 fd 41 6d 1e  |.5....P......Am.|
-00000030  5e 7c 82 63 94 15 03 03  00 30 00 00 00 00 00 00  |^|.c.....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 bd 77 87 a5 5a d4  |...........w..Z.|
-00000050  b8 59 e6 6b 0f dd ea f9  ed 18 b2 9f a9 61 b4 3a  |.Y.k.........a.:|
-00000060  47 15 15 3b 83 ef e1 6d  db a8                    |G..;...m..|
+00000010  00 00 00 00 00 fa f6 0b  1f f6 28 c7 4c 6c c8 8d  |..........(.Ll..|
+00000020  9c 97 5f 3d 22 bb 45 fc  07 ae 3a 7e 74 01 7c 71  |.._=".E...:~t.|q|
+00000030  39 45 15 d3 c7 15 03 03  00 30 00 00 00 00 00 00  |9E.......0......|
+00000040  00 00 00 00 00 00 00 00  00 00 a1 43 03 79 a4 4e  |...........C.y.N|
+00000050  bd 0f 17 c4 d0 29 1a 8a  dd 7b e7 48 3c e4 4b 8a  |.....)...{.H<.K.|
+00000060  53 3d 1d 18 f9 05 fd 4b  73 4a                    |S=.....KsJ|
index df3eaa4406e1e2ad8cc8e220b5935d7e601354f3..66a661c41ab62680f5a47c54687e9851acbb6e7f 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 53 04 f1 02 1d  |....Q...M..S....|
-00000010  0e dc 86 e5 a9 07 71 46  15 34 af 47 15 3f 03 9c  |......qF.4.G.?..|
-00000020  fc d6 fd 44 7c f4 f1 c7  8d 6f f8 20 28 ea 3c dc  |...D|....o. (.<.|
-00000030  b2 4c b7 ba 20 88 c4 db  a5 73 ea 93 ab 3a 85 a6  |.L.. ....s...:..|
-00000040  8f 59 49 d9 a9 31 14 d5  a6 2b 4f d1 00 05 00 00  |.YI..1...+O.....|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 32 d8 c5 23 e3  |....Q...M..2..#.|
+00000010  c7 4c d9 e9 d9 bd 1d d4  70 60 df 01 46 dc ca c5  |.L......p`..F...|
+00000020  d3 1b 57 28 f0 c4 4b 1c  b3 8d 13 20 4a b8 d7 eb  |..W(..K.... J...|
+00000030  70 9e e5 6d 6f 8c d4 0d  a4 25 3a ce 91 e0 25 68  |p..mo....%:...%h|
+00000040  6f 25 38 0d 91 57 af 28  39 9c 61 85 00 05 00 00  |o%8..W.(9.a.....|
 00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
 000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
 000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
 00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 30 0d 00  |n8P)l........0..|
-00000320  00 28 03 01 02 40 00 20  06 01 06 02 06 03 05 01  |.(...@. ........|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 2e 0d 00  |n8P)l...........|
+00000320  00 26 03 01 02 40 00 1e  06 01 06 02 06 03 05 01  |.&...@..........|
 00000330  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-00000340  02 01 02 02 02 03 01 01  00 00 0e 00 00 00        |..............|
+00000340  02 01 02 02 02 03 00 00  0e 00 00 00              |............|
 >>> Flow 3 (client to server)
 00000000  16 03 03 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
 00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
 00000260  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000270  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000280  35 d4 1c 43 d1 30 6f 55  4e 0a 70 16 03 03 00 88  |5..C.0oUN.p.....|
-00000290  0f 00 00 84 04 01 00 80  2a 1f ae 48 9f 86 16 dc  |........*..H....|
-000002a0  c2 55 1f 5f 95 81 ed 56  00 5d 35 46 e5 b6 57 d5  |.U._...V.]5F..W.|
-000002b0  a6 3e 32 38 8b e2 c6 1c  b9 b1 38 b2 da 66 45 ed  |.>28......8..fE.|
-000002c0  58 6a 7f 43 41 93 a5 09  da b9 04 ce 3f 13 8a 19  |Xj.CA.......?...|
-000002d0  13 e9 2c 1f c5 e7 35 b4  2d ea 7c 81 90 33 c0 66  |..,...5.-.|..3.f|
-000002e0  dc 41 8b 23 08 8f 69 d4  d6 a2 5f c1 bd 26 e6 2e  |.A.#..i..._..&..|
-000002f0  7f c8 7c a8 2d d4 08 95  ce 6e 58 54 04 a2 a6 63  |..|.-....nXT...c|
-00000300  54 72 67 f2 7f 61 0a 6b  58 46 d4 88 95 38 37 f2  |Trg..a.kXF...87.|
-00000310  93 95 48 56 14 a7 b9 7c  14 03 03 00 01 01 16 03  |..HV...|........|
-00000320  03 00 24 64 bb 41 3a cb  a2 2f 95 53 5c 2f f7 83  |..$d.A:../.S\/..|
-00000330  a2 35 18 f6 d0 8d 6f e2  54 ed 2f 07 10 f4 36 e2  |.5....o.T./...6.|
-00000340  3d e5 30 1d e3 63 01                              |=.0..c.|
+00000290  0f 00 00 84 04 01 00 80  3a 55 0a c6 97 2d 71 bc  |........:U...-q.|
+000002a0  9d e1 ec 5b cb 3d de 64  8e fd 99 c0 55 1f d5 d1  |...[.=.d....U...|
+000002b0  ae 74 79 b8 1d 25 3e 4d  19 32 62 ca 04 82 f4 3f  |.ty..%>M.2b....?|
+000002c0  7c 2b 7a 82 a6 86 2b d3  ba b0 ad 48 c4 c9 33 e6  ||+z...+....H..3.|
+000002d0  c8 2c 4a 06 75 a6 e7 49  65 53 54 33 27 55 7a 30  |.,J.u..IeST3'Uz0|
+000002e0  55 64 ef a0 d9 96 29 69  3f 90 ba b3 e4 aa 4e 5f  |Ud....)i?.....N_|
+000002f0  1d 00 c2 90 c2 04 f9 9b  7f f1 e5 fd f2 1e 57 fd  |..............W.|
+00000300  fc 0b 70 81 71 9a 43 9b  80 ff 96 42 f5 8d ff 2f  |..p.q.C....B.../|
+00000310  4f d9 48 e2 6e bf 9e f2  14 03 03 00 01 01 16 03  |O.H.n...........|
+00000320  03 00 24 32 b3 61 bd 9a  e1 21 79 60 f0 4b 6c 26  |..$2.a...!y`.Kl&|
+00000330  15 91 14 6d bc 42 9b c0  21 5f 93 2d d0 f7 db 9f  |...m.B..!_.-....|
+00000340  81 60 bd d6 34 fa 31                              |.`..4.1|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 0a 22 b6 bc da  |..........$."...|
-00000010  34 38 53 8e 80 e2 25 7b  31 2f 70 8e 3a db e8 a3  |48S...%{1/p.:...|
-00000020  70 0e 88 22 b4 a8 be d4  a3 e3 cc 13 94 ef 47     |p.."..........G|
+00000000  14 03 03 00 01 01 16 03  03 00 24 5c 99 fe 86 6f  |..........$\...o|
+00000010  89 c3 e1 ed 24 1f a5 81  a8 fd 2a 8d 28 01 cd 86  |....$.....*.(...|
+00000020  11 48 5c 13 fe f4 29 dd  ff 15 70 da 68 3b d8     |.H\...)...p.h;.|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a b4 9c b1  57 ea 01 03 fe 01 e7 1e  |........W.......|
-00000010  c4 a7 0f 25 14 99 00 4f  88 51 c1 98 6e 99 01 15  |...%...O.Q..n...|
-00000020  03 03 00 16 2e c4 11 8b  1a fc 37 81 18 33 e4 9f  |..........7..3..|
-00000030  48 a3 29 e3 ad 9b 9b ec  9f 99                    |H.).......|
+00000000  17 03 03 00 1a a9 5b 30  f3 9d 98 b0 a6 a6 4c 52  |......[0......LR|
+00000010  35 c9 aa 88 24 12 0f b0  53 88 21 8a 39 56 62 15  |5...$...S.!.9Vb.|
+00000020  03 03 00 16 ff 5f 0a cf  48 2a bd 2f e9 db 50 bc  |....._..H*./..P.|
+00000030  11 3c c8 d2 61 69 6c 84  22 bf                    |.<..ail.".|
index 76445903bac0ba846ae084e9b10236c710ba5616..9ff4d3ccf1b438ebd74c976cacc28940e01ef569 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 a0  |....Y...U..S....|
-00000010  5f bd a4 8d 98 93 b8 da  08 86 9f b2 be 9a a4 91  |_...............|
-00000020  2b 3c 1f 18 f0 75 7c a9  a8 a0 f7 20 4a 89 9a d2  |+<...u|.... J...|
-00000030  34 3b d9 b1 c2 fd 61 bd  97 19 22 ce b9 d1 5b a7  |4;....a..."...[.|
-00000040  83 80 9c 19 d0 f5 a0 aa  4c ac 06 20 c0 09 00 00  |........L.. ....|
+00000000  16 03 03 00 59 02 00 00  55 03 03 97 dc 20 65 0f  |....Y...U.... e.|
+00000010  3f 83 4a 55 06 27 32 2f  68 81 f9 4a 6d 0a 8c 3e  |?.JU.'2/h..Jm..>|
+00000020  c0 aa c1 c2 e1 09 a8 a0  a5 e3 42 20 7b ed 80 22  |..........B {.."|
+00000030  22 f9 84 ab 6d f5 63 18  bc f8 dc 7d 13 31 6b 4b  |"...m.c....}.1kK|
+00000040  85 c0 63 8d e5 d8 29 c8  ad 09 d7 b7 c0 09 00 00  |..c...).........|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 3c  |*............A.<|
-00000280  8f 35 1e 47 5d 7b ad 13  0c e9 5c c0 97 c7 83 06  |.5.G]{....\.....|
-00000290  49 0f 6c cf e5 4d 3b ed  f7 1b c6 96 8d ba 54 35  |I.l..M;.......T5|
-000002a0  7f df 35 e3 6e 28 e9 71  f2 24 b5 ab 17 2b 4b 2b  |..5.n(.q.$...+K+|
-000002b0  0c 8f 9f 48 89 73 8f 09  69 84 af 7f ec 43 7a 04  |...H.s..i....Cz.|
-000002c0  03 00 8a 30 81 87 02 41  79 84 43 0c 78 fa 7e e2  |...0...Ay.C.x.~.|
-000002d0  c5 51 c1 60 88 c4 4a 59  7d 02 fa dc 19 68 33 ed  |.Q.`..JY}....h3.|
-000002e0  19 ef a1 df ef 6b 21 a6  98 aa ba a9 13 70 91 0f  |.....k!......p..|
-000002f0  cc 6c 5c 1e 99 53 1b 42  51 6c 06 a7 3c c4 04 22  |.l\..S.BQl..<.."|
-00000300  5d 0d c1 30 ab e3 ec b4  54 02 42 01 15 15 1a 6e  |]..0....T.B....n|
-00000310  6f f1 c6 b1 10 84 2c c8  04 de 2b 52 d5 b4 f7 c9  |o.....,...+R....|
-00000320  4f 6d 0e 0e 26 45 1d 7a  28 59 2b 8b f6 92 3a 23  |Om..&E.z(Y+...:#|
-00000330  7a 39 9c d5 4e cc 5d c5  45 92 9c d0 5f 33 12 e3  |z9..N.].E..._3..|
-00000340  2b 29 39 52 bb 16 aa e1  72 9e b5 fe 99 16 03 03  |+)9R....r.......|
-00000350  00 04 0e 00 00 00                                 |......|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 dd  |*............A..|
+00000280  34 64 e4 ba 63 e0 25 f2  6b cd 24 21 58 8b e1 08  |4d..c.%.k.$!X...|
+00000290  eb 09 6f 93 e2 cd 19 13  d0 e6 5a 0c ee 57 b9 ab  |..o.......Z..W..|
+000002a0  21 be 8d b5 47 1e a8 01  a4 de c4 de a7 d5 eb dd  |!...G...........|
+000002b0  d9 bd 66 1a 71 0a b7 a1  3d 10 8e b6 2d 73 ba 04  |..f.q...=...-s..|
+000002c0  03 00 8b 30 81 88 02 42  01 c6 4a 64 2b 66 7f cb  |...0...B..Jd+f..|
+000002d0  28 eb ad 05 d4 86 a0 d6  0f 12 52 03 fc 66 3f 76  |(.........R..f?v|
+000002e0  db 85 8f b4 f1 45 04 f5  10 27 b3 76 62 9a bc 7b  |.....E...'.vb..{|
+000002f0  f9 6e f6 45 fb 15 9c eb  5c 70 ca b2 40 00 f8 18  |.n.E....\p..@...|
+00000300  b9 e4 28 fc e4 b7 d8 15  70 1a 02 42 01 d3 8f 53  |..(.....p..B...S|
+00000310  57 b5 e4 f5 84 97 a2 e9  07 5a f8 67 bd 03 02 6d  |W........Z.g...m|
+00000320  ea 4e 14 da 12 2c d0 7c  89 a0 93 97 46 c9 62 ee  |.N...,.|....F.b.|
+00000330  c0 d3 d6 bf 04 11 af 19  96 6b a9 86 f8 2c 2f ab  |.........k...,/.|
+00000340  89 20 45 94 b6 d1 43 64  fc eb 2e ff 80 37 16 03  |. E...Cd.....7..|
+00000350  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 03 00 40 00 00  00 00 00 00 00 00 00 00  |.....@..........|
-00000060  00 00 00 00 00 00 20 a3  f8 5a e2 ea f3 09 19 3e  |...... ..Z.....>|
-00000070  4a 54 69 70 06 5b 17 35  0f ed e7 30 3b 6f eb a1  |JTip.[.5...0;o..|
-00000080  cb 9c 35 81 10 2e 34 f7  12 a5 e4 63 20 b2 65 31  |..5...4....c .e1|
-00000090  19 da 30 43 39 59                                 |..0C9Y|
+00000060  00 00 00 00 00 00 21 2a  44 9c f5 f7 b5 0f 43 f4  |......!*D.....C.|
+00000070  19 03 02 64 c0 9a a0 d1  50 89 f2 f2 dd a1 dc 72  |...d....P......r|
+00000080  da 08 d1 5c 75 fa 54 ee  bf c8 76 5f 57 df 62 2b  |...\u.T...v_W.b+|
+00000090  36 48 40 c4 a4 ac                                 |6H@...|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 8d 4d 31 07 df  |..........@.M1..|
-00000010  ab 41 f5 19 9c 1a 57 fc  33 ab 5f e6 bd 45 b9 fa  |.A....W.3._..E..|
-00000020  7f db c0 df 72 f2 3b ef  aa d4 5e 34 e6 3d 44 7c  |....r.;...^4.=D||
-00000030  12 05 c7 57 da 54 b1 e3  66 f0 0a ab cd 15 a5 bf  |...W.T..f.......|
-00000040  c5 c2 07 a9 d9 a7 2e 5e  29 da da                 |.......^)..|
+00000000  14 03 03 00 01 01 16 03  03 00 40 72 a7 fe d8 23  |..........@r...#|
+00000010  6a 4f 4c 11 09 5d 0e d3  86 4e d6 e8 96 cb ac 71  |jOL..]...N.....q|
+00000020  68 e2 50 94 eb e4 d2 9b  61 56 e2 17 50 5e fb b2  |h.P.....aV..P^..|
+00000030  fe a0 1f 8d 74 2c c6 d0  ba 5e f7 73 b8 00 8d b5  |....t,...^.s....|
+00000040  57 e1 41 90 21 15 91 6d  69 25 83                 |W.A.!..mi%.|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 dc 03 7b  29 2c 49 64 58 2d dc f7  |.......{),IdX-..|
-00000020  26 a1 3b ec 2d e8 30 c4  6c a3 ff e2 bc b5 a4 a6  |&.;.-.0.l.......|
-00000030  93 ce 14 bd da 15 03 03  00 30 00 00 00 00 00 00  |.........0......|
-00000040  00 00 00 00 00 00 00 00  00 00 a6 77 10 30 15 eb  |...........w.0..|
-00000050  ed cf 73 5b 74 5d 09 52  4a 5b e2 f0 e4 67 f8 7a  |..s[t].RJ[...g.z|
-00000060  5e 5e fc ba 7f 80 0a d2  f4 fb                    |^^........|
+00000010  00 00 00 00 00 80 70 b8  c4 f1 ef 0c 2e 87 5c fc  |......p.......\.|
+00000020  fb 54 19 4d 42 42 09 32  32 dd 54 b9 6e 35 ea 13  |.T.MBB.22.T.n5..|
+00000030  e1 2b 4c 7e e6 15 03 03  00 30 00 00 00 00 00 00  |.+L~.....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 3e aa 24 38 78 63  |..........>.$8xc|
+00000050  ae 5c d4 28 2d 3b 7c 1b  66 2f 07 02 00 e1 78 dd  |.\.(-;|.f/....x.|
+00000060  6e 43 e7 23 da 55 55 33  a2 d8                    |nC.#.UU3..|
index fb5af17f0c4392762de38a5633dc8ff98d29b6c2..9b7d61d1ea42f52fd5abd0e5b7a4907c619fa591 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 48  |....Y...U..S...H|
-00000010  03 36 01 05 56 6f f0 54  d2 c3 d3 41 c2 e2 69 7b  |.6..Vo.T...A..i{|
-00000020  50 f8 03 ef 3f 5d 7c e6  9c cb fe 20 82 a0 81 fd  |P...?]|.... ....|
-00000030  72 4b b8 e6 29 76 3b 0f  1d 0a b7 82 9d 0b cf a0  |rK..)v;.........|
-00000040  65 b1 56 53 c9 d5 58 7b  f0 b6 2d cf c0 2b 00 00  |e.VS..X{..-..+..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 c9 39 e6 18 c8  |....Y...U...9...|
+00000010  4a 7f f3 23 75 99 22 80  48 bc e3 a7 eb 49 d5 95  |J..#u.".H....I..|
+00000020  b1 ec 1d 9e 44 09 6e d9  b7 b2 f8 20 30 fd 2b 50  |....D.n.... 0.+P|
+00000030  d2 91 de c3 d0 84 a9 d5  ba c0 45 0f 18 c4 98 73  |..........E....s|
+00000040  4b cf c6 82 dd 88 0d 35  28 8e f8 d3 c0 2b 00 00  |K......5(....+..|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 86  |*............A..|
-00000280  36 b4 78 76 87 70 ed ae  0d 34 70 3d 16 e5 a4 db  |6.xv.p...4p=....|
-00000290  ae 28 58 4c 01 5a 56 73  a7 0d 34 59 a7 04 75 69  |.(XL.ZVs..4Y..ui|
-000002a0  f2 55 24 40 b0 33 c6 93  ff ae e0 14 f5 4b ce a8  |.U$@.3.......K..|
-000002b0  e2 e6 9a 67 1d 66 fb 8f  fd 56 59 e7 73 f2 2c 04  |...g.f...VY.s.,.|
-000002c0  03 00 8a 30 81 87 02 41  73 ab a8 3c 64 17 69 9f  |...0...As..<d.i.|
-000002d0  4d b2 9b 55 12 60 33 94  cf f3 83 40 2b 7b 1b af  |M..U.`3....@+{..|
-000002e0  5c f4 cd 02 66 fb 83 04  35 fd ab 74 98 1a 7d f6  |\...f...5..t..}.|
-000002f0  9e 50 98 c3 98 e8 56 9c  f2 2a b0 30 9d 05 14 58  |.P....V..*.0...X|
-00000300  68 6a 88 04 49 07 78 bf  3a 02 42 01 be b2 05 9e  |hj..I.x.:.B.....|
-00000310  67 da 1e e9 5a 36 98 52  21 9f 43 75 43 ba bb 9a  |g...Z6.R!.CuC...|
-00000320  e6 e2 65 f4 e0 44 45 08  5a 1e 54 06 dd 5f 60 2e  |..e..DE.Z.T.._`.|
-00000330  7d e7 55 08 d3 7b 4e 0a  c7 da d4 27 34 d4 bd b0  |}.U..{N....'4...|
-00000340  12 2f 41 7a ed 71 32 ef  ee 12 74 66 00 16 03 03  |./Az.q2...tf....|
-00000350  00 04 0e 00 00 00                                 |......|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 91  |*............A..|
+00000280  d0 f0 1b df 51 57 74 f3  62 ee d5 9e e8 7d bd 65  |....QWt.b....}.e|
+00000290  69 0a 5a 2b 75 c3 3c f7  24 3f 91 26 34 fe d8 8f  |i.Z+u.<.$?.&4...|
+000002a0  fa d3 7e f6 f5 01 89 7b  f5 69 5c c2 52 41 81 93  |..~....{.i\.RA..|
+000002b0  c4 9e 01 5d 96 fa db 41  3d 0b 78 58 ad 29 b5 04  |...]...A=.xX.)..|
+000002c0  03 00 8b 30 81 88 02 42  01 92 7c 0a 7c 79 d1 41  |...0...B..|.|y.A|
+000002d0  98 b7 57 37 10 d9 31 41  2e fe d5 a8 94 26 fa 59  |..W7..1A.....&.Y|
+000002e0  78 bf 15 c0 cf e7 a9 09  a8 6f 97 45 1b 3f e6 60  |x........o.E.?.`|
+000002f0  2d 78 dc ec 99 0f 92 43  64 20 c4 6b 59 16 df 66  |-x.....Cd .kY..f|
+00000300  83 a0 f1 d1 91 c1 8a 29  ce 4d 02 42 01 61 a2 6c  |.......).M.B.a.l|
+00000310  84 58 58 0b 74 fa 9e 4c  33 6a b5 b1 a9 da ad 1c  |.XX.t..L3j......|
+00000320  d9 33 25 91 59 a0 f2 21  ae b1 14 15 4a d1 65 50  |.3%.Y..!....J.eP|
+00000330  0e 1d 1e bc f6 29 da 22  09 20 de 75 30 ac 0a 1e  |.....).". .u0...|
+00000340  7e 46 98 89 dd 6d e4 6a  9b 83 b5 85 f3 74 16 03  |~F...m.j.....t..|
+00000350  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 87 7a  |.....(.........z|
-00000060  82 d7 46 25 1d a6 bb c2  a8 a8 4e a5 d1 f8 02 db  |..F%......N.....|
-00000070  33 33 ca 78 b6 d3 bd 77  8a 33 23 a7 95 fb        |33.x...w.3#...|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 b0 4d  |.....(.........M|
+00000060  e2 ad 33 40 f2 44 e3 c7  ad a5 c6 c7 e5 00 07 68  |..3@.D.........h|
+00000070  72 80 d5 89 f0 aa 72 2b  36 5a 51 f6 f0 6a        |r.....r+6ZQ..j|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 ce a1 9d 01 c0  |..........(.....|
-00000010  31 e5 d5 57 16 e1 a6 b3  8b 25 58 0f fa 2a de 3e  |1..W.....%X..*.>|
-00000020  0c d9 06 11 a6 b0 d7 b0  33 ad 31 73 5b 26 b4 d2  |........3.1s[&..|
-00000030  12 56 c8                                          |.V.|
+00000000  14 03 03 00 01 01 16 03  03 00 28 5d b6 1b 59 71  |..........(]..Yq|
+00000010  f0 7a 2c 4f d5 f0 7b a7  ab 56 48 4d b4 f7 5c bc  |.z,O..{..VHM..\.|
+00000020  34 d6 cc 02 4f 1f 45 b2  e9 ff 96 0e a2 47 d6 4e  |4...O.E......G.N|
+00000030  47 83 68                                          |G.h|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 d5 04 4c  |...............L|
-00000010  7b 35 b4 d7 90 ae fe 00  d2 f2 4b 76 f1 36 5e 24  |{5........Kv.6^$|
-00000020  4a aa 94 15 03 03 00 1a  00 00 00 00 00 00 00 02  |J...............|
-00000030  d3 1c 41 37 ab f6 17 79  f0 01 a4 19 a5 75 7a 8e  |..A7...y.....uz.|
-00000040  a3 b2                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 2f f1 95  |............./..|
+00000010  75 5e 0d fb 48 9b 40 10  6d bb 81 7e d2 ca 68 ae  |u^..H.@.m..~..h.|
+00000020  84 47 d2 15 03 03 00 1a  00 00 00 00 00 00 00 02  |.G..............|
+00000030  26 87 82 85 fa 5f a2 b2  19 b2 4e 81 f6 0f c6 c5  |&...._....N.....|
+00000040  e0 3e                                             |.>|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
new file mode 100644 (file)
index 0000000..068b402
--- /dev/null
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 d2 dd 5a 60 0d  |....Y...U....Z`.|
+00000010  25 72 ed e6 89 6e 4d d8  1c 75 76 e4 37 5f 06 80  |%r...nM..uv.7_..|
+00000020  26 23 48 02 cd c6 b1 e5  59 89 b2 20 99 9e e6 31  |&#H.....Y.. ...1|
+00000030  8f ca b2 aa 68 b2 6b 2e  c0 f3 f8 e9 56 f4 60 90  |....h.k.....V.`.|
+00000040  bb 5d 79 fd 4f f5 71 15  5b e7 31 20 c0 2c 00 00  |.]y.O.q.[.1 .,..|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
+00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
+00000080  30 09 06 07 2a 86 48 ce  3d 04 01 30 45 31 0b 30  |0...*.H.=..0E1.0|
+00000090  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000000a0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000000b0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000000c0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000000d0  74 64 30 1e 17 0d 31 32  31 31 32 32 31 35 30 36  |td0...1211221506|
+000000e0  33 32 5a 17 0d 32 32 31  31 32 30 31 35 30 36 33  |32Z..22112015063|
+000000f0  32 5a 30 45 31 0b 30 09  06 03 55 04 06 13 02 41  |2Z0E1.0...U....A|
+00000100  55 31 13 30 11 06 03 55  04 08 13 0a 53 6f 6d 65  |U1.0...U....Some|
+00000110  2d 53 74 61 74 65 31 21  30 1f 06 03 55 04 0a 13  |-State1!0...U...|
+00000120  18 49 6e 74 65 72 6e 65  74 20 57 69 64 67 69 74  |.Internet Widgit|
+00000130  73 20 50 74 79 20 4c 74  64 30 81 9b 30 10 06 07  |s Pty Ltd0..0...|
+00000140  2a 86 48 ce 3d 02 01 06  05 2b 81 04 00 23 03 81  |*.H.=....+...#..|
+00000150  86 00 04 00 c4 a1 ed be  98 f9 0b 48 73 36 7e c3  |...........Hs6~.|
+00000160  16 56 11 22 f2 3d 53 c3  3b 4d 21 3d cd 6b 75 e6  |.V.".=S.;M!=.ku.|
+00000170  f6 b0 dc 9a df 26 c1 bc  b2 87 f0 72 32 7c b3 64  |.....&.....r2|.d|
+00000180  2f 1c 90 bc ea 68 23 10  7e fe e3 25 c0 48 3a 69  |/....h#.~..%.H:i|
+00000190  e0 28 6d d3 37 00 ef 04  62 dd 0d a0 9c 70 62 83  |.(m.7...b....pb.|
+000001a0  d8 81 d3 64 31 aa 9e 97  31 bd 96 b0 68 c0 9b 23  |...d1...1...h..#|
+000001b0  de 76 64 3f 1a 5c 7f e9  12 0e 58 58 b6 5f 70 dd  |.vd?.\....XX._p.|
+000001c0  9b d8 ea d5 d7 f5 d5 cc  b9 b6 9f 30 66 5b 66 9a  |...........0f[f.|
+000001d0  20 e2 27 e5 bf fe 3b 30  09 06 07 2a 86 48 ce 3d  | .'...;0...*.H.=|
+000001e0  04 01 03 81 8c 00 30 81  88 02 42 01 88 a2 4f eb  |......0...B...O.|
+000001f0  e2 45 c5 48 7d 1b ac f5  ed 98 9d ae 47 70 c0 5e  |.E.H}.......Gp.^|
+00000200  1b b6 2f bd f1 b6 4d b7  61 40 d3 11 a2 ce ee 0b  |../...M.a@......|
+00000210  7e 92 7e ff 76 9d c3 3b  7e a5 3f ce fa 10 e2 59  |~.~.v..;~.?....Y|
+00000220  ec 47 2d 7c ac da 4e 97  0e 15 a0 6f d0 02 42 01  |.G-|..N....o..B.|
+00000230  4d fc be 67 13 9c 2d 05  0e bd 3f a3 8c 25 c1 33  |M..g..-...?..%.3|
+00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
+00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
+00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 16  |*............A..|
+00000280  80 a7 71 18 d7 2e 0e 9b  a0 ae 58 8b ff 56 c5 21  |..q.......X..V.!|
+00000290  44 b1 ff 7e 2a 1a c4 39  91 d8 f5 cb 67 6c eb 24  |D..~*..9....gl.$|
+000002a0  86 e3 2f 79 ca 07 a4 6a  ad 92 3e 36 79 f0 00 25  |../y...j..>6y..%|
+000002b0  b5 b8 31 e5 3c 2e f1 5e  16 23 69 c4 14 a5 93 04  |..1.<..^.#i.....|
+000002c0  03 00 8b 30 81 88 02 42  01 68 cb 9b f4 22 71 10  |...0...B.h..."q.|
+000002d0  c5 5f 02 7c ab b4 db 6e  af 35 89 3b ad 4d 6b 40  |._.|...n.5.;.Mk@|
+000002e0  62 64 8b e5 6c e1 9a bd  21 05 25 cb e9 b4 7a 31  |bd..l...!.%...z1|
+000002f0  2e 63 4f 77 4c 3f ab 7b  67 21 02 ae 8b 0a 7b 7e  |.cOwL?.{g!....{~|
+00000300  f9 0f a8 df b1 14 0e ef  5e 66 02 42 01 c7 50 11  |........^f.B..P.|
+00000310  28 e9 aa 1d ea 52 60 af  37 35 73 13 bd f9 dd 54  |(....R`.75s....T|
+00000320  8e 34 db 9a 78 20 61 d4  6c 7f 72 06 4e 7a 58 07  |.4..x a.l.r.NzX.|
+00000330  d9 87 01 82 b8 dc 39 72  48 41 a4 ef 58 8e dd c6  |......9rHA..X...|
+00000340  8c 0d d3 c1 c6 36 79 e1  d0 78 dd 1c 89 9a 16 03  |.....6y..x......|
+00000350  03 00 04 0e 00 00 00                              |.......|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 5f f3  |.....(........_.|
+00000060  89 d5 29 18 bb 58 6f 28  f6 15 46 a2 1b 0a 49 9a  |..)..Xo(..F...I.|
+00000070  66 ab 83 31 36 f7 f6 74  35 45 2e db 80 b9        |f..16..t5E....|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 ef 24 92 74 6b  |..........(.$.tk|
+00000010  d1 a7 26 2a 52 6e 15 70  10 65 e4 a9 89 8d 56 04  |..&*Rn.p.e....V.|
+00000020  29 d1 36 f5 aa 64 9b 34  b9 53 df fa de 47 c4 1b  |).6..d.4.S...G..|
+00000030  36 59 88                                          |6Y.|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 36 2e 40  |.............6.@|
+00000010  ed b9 f0 05 2e 08 64 28  3a da 3f 4b 80 26 6b e3  |......d(:.?K.&k.|
+00000020  97 0e 43 15 03 03 00 1a  00 00 00 00 00 00 00 02  |..C.............|
+00000030  bd 85 57 7c 08 f1 76 bf  57 16 fe 5f f7 b4 de 43  |..W|..v.W.._...C|
+00000040  64 36                                             |d6|
index 5336bbbad8f862751dbe474994181c3aef82a2ec..3c7516148e3a25679ac25fea0b8c4d17a72b25db 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 41  |....Y...U..S...A|
-00000010  95 cc 56 30 65 46 24 75  d5 9e 3c a7 5b 6c 99 fe  |..V0eF$u..<.[l..|
-00000020  86 35 23 42 3a 8f 4d 4c  b9 98 7d 20 a7 46 43 72  |.5#B:.ML..} .FCr|
-00000030  66 bb b6 ad ff ad cf 63  37 fe 6b b4 78 94 08 49  |f......c7.k.x..I|
-00000040  54 06 ed f4 85 73 38 4a  c6 fe b6 98 c0 13 00 00  |T....s8J........|
+00000000  16 03 03 00 59 02 00 00  55 03 03 81 ab f4 92 ec  |....Y...U.......|
+00000010  b8 99 85 43 62 31 8e 58  63 c0 04 03 82 b4 f5 49  |...Cb1.Xc......I|
+00000020  d5 2d cd 24 de a0 24 29  39 93 90 20 ad 9c 35 ad  |.-.$..$)9.. ..5.|
+00000030  20 1d 35 0a 6e 29 99 48  72 e6 fc 19 ae e6 7f 4f  | .5.n).Hr......O|
+00000040  47 01 24 f4 9d 9e d7 0e  06 25 a8 93 c0 13 00 00  |G.$......%......|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
 00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
 000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
 00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
 00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
-00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 48  |.............A.H|
-00000330  68 d8 8a 10 b4 bf eb 8d  d1 98 b0 a6 f4 47 5d 91  |h............G].|
-00000340  61 da 50 d9 85 7b 5d 90  02 2c 38 c9 af 81 d3 55  |a.P..{]..,8....U|
-00000350  07 62 b1 62 58 7f 39 94  d7 91 96 a8 1f 47 60 a5  |.b.bX.9......G`.|
-00000360  c0 04 f2 fb cb 15 75 a6  16 3f 94 53 7c ff dd 04  |......u..?.S|...|
-00000370  01 00 80 b9 82 fa 0b f8  8c 94 2c 6e 05 81 7d 80  |..........,n..}.|
-00000380  5d 9a 77 78 af c8 33 5d  89 7e 2e 3c e5 72 66 a8  |].wx..3].~.<.rf.|
-00000390  f1 5c 02 04 02 70 76 7b  45 ff 0d 29 a0 cb 0d db  |.\...pv{E..)....|
-000003a0  7a 4c c4 13 19 cd 47 b2  f1 c9 43 4f 95 d2 f1 c6  |zL....G...CO....|
-000003b0  bc ae 31 4a 9d de 80 b2  a4 b7 b6 dd 8c 03 3e 2a  |..1J..........>*|
-000003c0  46 5e d1 e7 5b c5 9e 06  58 f3 55 b2 77 09 f3 98  |F^..[...X.U.w...|
-000003d0  d5 7f 5a 74 64 7e 48 22  8f 7d a8 68 b6 1d 90 df  |..Ztd~H".}.h....|
-000003e0  2c 91 d7 c5 07 3d d1 6f  e9 c1 91 03 3c 23 5a 56  |,....=.o....<#ZV|
-000003f0  3b b2 c2 16 03 03 00 04  0e 00 00 00              |;...........|
+00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 a3  |.............A..|
+00000330  b7 75 d0 ba b1 e1 4e aa  08 36 e2 90 52 3c e8 8c  |.u....N..6..R<..|
+00000340  78 54 61 e6 ec 60 ad 95  9b 1e a0 de a4 14 95 31  |xTa..`.........1|
+00000350  fb fc 23 5b e7 22 da 68  a1 c4 68 da 7e 62 08 6e  |..#[.".h..h.~b.n|
+00000360  40 0a 3d ac 28 f2 70 17  44 24 43 b6 12 f0 0e 04  |@.=.(.p.D$C.....|
+00000370  01 00 80 3c 1e 25 16 dc  f0 d0 ac 3e 63 d3 c6 ee  |...<.%.....>c...|
+00000380  ed 1b 1c 8b 9d ec 41 d9  10 56 f6 19 35 61 49 fc  |......A..V..5aI.|
+00000390  e6 03 f5 29 89 a1 61 46  78 0b 9b 4e f9 26 18 58  |...)..aFx..N.&.X|
+000003a0  50 64 c2 a6 fb 61 d0 29  e2 f9 b1 56 07 91 69 8d  |Pd...a.)...V..i.|
+000003b0  ec 69 0e ab 91 70 a9 82  52 4f b1 d8 31 28 e2 49  |.i...p..RO..1(.I|
+000003c0  fa fa 26 c7 f9 cf 30 6e  01 59 3f de 0d 56 c8 9e  |..&...0n.Y?..V..|
+000003d0  ae fd 49 2a 66 a0 bb 0b  b4 f8 02 7f c8 b2 53 14  |..I*f.........S.|
+000003e0  f1 7f a9 3a 02 cd 33 04  cf 73 8b 5a 61 f3 d3 5e  |...:..3..s.Za..^|
+000003f0  24 78 43 16 03 03 00 04  0e 00 00 00              |$xC.........|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 03 00 40 00 00  00 00 00 00 00 00 00 00  |.....@..........|
-00000060  00 00 00 00 00 00 59 e6  92 05 27 ec 09 2c b0 a5  |......Y...'..,..|
-00000070  2a fb 7e f1 03 53 16 63  68 a1 86 13 bb da 98 27  |*.~..S.ch......'|
-00000080  6d 42 08 35 6a ec 58 61  2a 4d 44 ec ae c5 b9 d2  |mB.5j.Xa*MD.....|
-00000090  76 57 1f 75 9f 8d                                 |vW.u..|
+00000060  00 00 00 00 00 00 58 40  67 61 f4 eb d6 54 b5 f4  |......X@ga...T..|
+00000070  08 d8 27 18 ff 7f c5 58  d1 1e 43 d3 92 74 fe a8  |..'....X..C..t..|
+00000080  a6 f8 09 4e 44 0e 0e 6a  3b 72 7e 12 1f b2 bd 9c  |...ND..j;r~.....|
+00000090  f8 f3 c0 f0 4e 5e                                 |....N^|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 6e 03 d0 e6 98  |..........@n....|
-00000010  1f f5 39 7b 06 9f 95 f0  7a 88 35 7c 55 db c3 2f  |..9{....z.5|U../|
-00000020  00 ef 5b d3 62 87 a2 94  da 2f f6 4a 89 c9 a8 3d  |..[.b..../.J...=|
-00000030  3a 92 db 77 35 92 01 4b  f5 c5 6b 95 09 9f cd 79  |:..w5..K..k....y|
-00000040  3c af 37 5b 27 bf 93 3e  04 55 71                 |<.7['..>.Uq|
+00000000  14 03 03 00 01 01 16 03  03 00 40 ac 13 13 7a 41  |..........@...zA|
+00000010  ef 34 2e 9c 03 52 01 84  6b c3 f4 67 48 f5 32 fb  |.4...R..k..gH.2.|
+00000020  07 b2 6a cf a8 57 c5 7a  16 03 02 b5 9f 90 4c 28  |..j..W.z......L(|
+00000030  65 48 0d e6 43 48 f2 06  22 88 db 90 d9 6e da 07  |eH..CH.."....n..|
+00000040  59 1f 1c 6e af 74 ab 83  68 12 15                 |Y..n.t..h..|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 bc c9 d0  8e 80 14 de 32 18 49 e8  |............2.I.|
-00000020  20 dc 5e 6c e4 6d 14 00  df 51 71 fb 86 95 16 4c  | .^l.m...Qq....L|
-00000030  04 8e 71 e1 48 15 03 03  00 30 00 00 00 00 00 00  |..q.H....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 b7 6d 30 72 61 53  |...........m0raS|
-00000050  d8 0a d4 1d ae e5 d4 22  46 c9 d5 4e 4a 86 f5 ac  |......."F..NJ...|
-00000060  72 98 c6 db 38 29 97 2c  84 0b                    |r...8).,..|
+00000010  00 00 00 00 00 87 cf e1  7e 13 ec 82 ca 75 e0 4d  |........~....u.M|
+00000020  ca 17 a3 de c0 2a 54 b3  3e 4d cf 73 46 c8 a3 cf  |.....*T.>M.sF...|
+00000030  ad 54 1c 74 46 15 03 03  00 30 00 00 00 00 00 00  |.T.tF....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 d3 9d a4 fd 16 8d  |................|
+00000050  83 1b 7c c2 53 8e 10 7b  e3 3c d5 23 8e c4 9c 74  |..|.S..{.<.#...t|
+00000060  86 9e 66 59 81 41 a1 14  8e 59                    |..fY.A...Y|
index 0377f052ae60c0de239dd0b82c32a635e2bb4381..b3c112e83d900738324dcb2b1d2c7fd15bf07082 100644 (file)
@@ -1,18 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 53 04 f1 02 9d  |....Q...M..S....|
-00000010  2e 4e d9 17 4a 35 fa 9d  94 f6 45 0a f6 6b 5d 1c  |.N..J5....E..k].|
-00000020  1e 15 19 8d 6d 94 cc 90  d9 39 94 20 8b 4b de 76  |....m....9. .K.v|
-00000030  d5 64 5d b7 19 df e7 eb  7e a0 22 c4 09 38 a0 12  |.d].....~."..8..|
-00000040  d5 59 10 c8 31 06 dc fc  e4 9d d1 80 00 05 00 00  |.Y..1...........|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 39 d1 22 07 3f  |....Q...M..9.".?|
+00000010  57 87 49 e1 92 8f c8 45  b6 8d 49 f2 dd 91 e0 6f  |W.I....E..I....o|
+00000020  86 cd 38 c4 f5 8f d1 f2  ff 13 19 20 5f 98 f8 87  |..8........ _...|
+00000030  8e 6b 63 53 67 65 88 fc  e4 02 47 4d 0b 52 bc 0c  |.kcSge....GM.R..|
+00000040  8a 08 23 45 74 89 ce 77  ac 15 1c 16 00 05 00 00  |..#Et..w........|
 00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
 00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 03 00 01  |5..C.0oUN.p.....|
-00000090  01 16 03 03 00 24 37 14  b2 97 7b b5 f0 9a 38 05  |.....$7...{...8.|
-000000a0  22 35 69 9c 95 2f 86 4b  37 98 22 db 4e 9a 46 9c  |"5i../.K7.".N.F.|
-000000b0  b9 81 74 72 58 18 53 0c  5c 3c                    |..trX.S.\<|
+00000090  01 16 03 03 00 24 d3 d5  a4 0c ae 33 1e d4 d8 ba  |.....$.....3....|
+000000a0  67 e5 93 31 e2 e9 08 c8  9e 27 d8 9b 20 d5 59 4d  |g..1.....'.. .YM|
+000000b0  d0 f9 d9 bd 82 f7 62 7c  95 0b                    |......b|..|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 3c b3 e7 77 5a  |..........$<..wZ|
-00000010  7c 36 5a 74 74 26 8d 5b  5a 09 96 60 e8 24 45 2f  ||6Ztt&.[Z..`.$E/|
-00000020  c2 39 14 5e db 58 12 49  ad a8 b6 ea ef 58 16     |.9.^.X.I.....X.|
+00000000  14 03 03 00 01 01 16 03  03 00 24 b2 af 7d da e2  |..........$..}..|
+00000010  b4 4f 9e ee 68 d4 bf eb  d3 09 63 de 61 e1 c2 12  |.O..h.....c.a...|
+00000020  ba 56 d8 dc 5f 9e 31 fe  1c d4 70 2a 1a 80 3c     |.V.._.1...p*..<|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a 6d 29 d7  ba 2f 85 02 b6 f0 82 64  |.....m)../.....d|
-00000010  6c 55 ae ab f6 fd 14 ff  b8 38 f0 f8 a6 ea cc 15  |lU.......8......|
-00000020  03 03 00 16 10 c5 d9 41  7b e2 89 67 dc 29 8e f8  |.......A{..g.)..|
-00000030  b5 ab 32 91 44 2c 27 84  49 f7                    |..2.D,'.I.|
+00000000  17 03 03 00 1a 43 f5 b5  0e 1b 1f 20 2a 09 27 e5  |.....C..... *.'.|
+00000010  dc 11 cf e6 07 31 2b fc  60 52 86 2b 41 b0 c2 15  |.....1+.`R.+A...|
+00000020  03 03 00 16 6a b9 06 9b  c6 e9 6d ad ed 2d cc 0f  |....j.....m..-..|
+00000030  bc 0a f1 0c 2d 0d 74 29  17 6b                    |....-.t).k|
index 9b8cb4d9b62912047640a95afa52dade7405e9c6..f81ffc28c0e585f3c3e4882139ac4f2c079ee4ce 100644 (file)
@@ -1,12 +1,13 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 76 01 00 00  72 03 01 53 04 f0 f9 4b  |....v...r..S...K|
-00000010  30 a8 68 d0 79 13 14 69  ee 3b 5d 05 cb 71 63 43  |0.h.y..i.;]..qcC|
-00000020  4a 55 6b 05 25 53 19 ba  e0 2f b1 00 00 04 c0 0a  |JUk.%S.../......|
-00000030  00 ff 01 00 00 45 00 0b  00 04 03 00 01 02 00 0a  |.....E..........|
-00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
-00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
-00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
-00000070  00 0f 00 10 00 11 00 0f  00 01 01                 |...........|
+00000000  16 03 01 00 7d 01 00 00  79 03 01 65 14 3f 40 e4  |....}...y..e.?@.|
+00000010  2f 74 65 7e d0 c8 87 03  59 61 9d c3 84 5e c9 62  |/te~....Ya...^.b|
+00000020  e6 46 b8 0c 4a 5e 3f 33  43 a5 dd 00 00 04 c0 0a  |.F..J^?3C.......|
+00000030  00 ff 02 01 00 00 4b 00  0b 00 04 03 00 01 02 00  |......K.........|
+00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
+00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
+00000060  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
+00000070  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0f 00  |................|
+00000080  01 01                                             |..|
 >>> Flow 2 (server to client)
 00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000260  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
 00000270  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
 00000280  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
-00000290  41 03 56 6b dc 5a 89 00  8b 30 81 88 02 42 00 c6  |A.Vk.Z...0...B..|
-000002a0  85 8e 06 b7 04 04 e9 cd  9e 3e cb 66 23 95 b4 42  |.........>.f#..B|
-000002b0  9c 64 81 39 05 3f b5 21  f8 28 af 60 6b 4d 3d ba  |.d.9.?.!.(.`kM=.|
-000002c0  a1 4b 5e 77 ef e7 59 28  fe 1d c1 27 a2 ff a8 de  |.K^w..Y(...'....|
-000002d0  33 48 b3 c1 85 6a 42 9b  f9 7e 7e 31 c2 e5 bd 66  |3H...jB..~~1...f|
-000002e0  02 42 00 ad 7d 06 35 ab  ec 8d ac d4 ba 1b 49 5e  |.B..}.5.......I^|
-000002f0  05 5f f0 97 93 82 b8 2b  8d 91 98 63 8e b4 14 62  |._.....+...c...b|
-00000300  db 1e c9 2b 30 f8 41 9b  a6 e6 bc de 0e 68 30 21  |...+0.A......h0!|
-00000310  d8 ef 2f 05 42 da f2 e0  2c 06 33 1d 0d 9a 1a 75  |../.B...,.3....u|
-00000320  59 a7 3a bc 16 03 01 00  04 0e 00 00 00           |Y.:..........|
+00000290  41 03 56 6b dc 5a 89 00  8b 30 81 88 02 42 01 3e  |A.Vk.Z...0...B.>|
+000002a0  79 81 6e 89 cd 3e 3f ec  e4 b5 75 17 28 ee fb 09  |y.n..>?...u.(...|
+000002b0  21 19 6f 3c e6 ca 1e f2  18 b6 47 f8 37 05 1c 85  |!.o<......G.7...|
+000002c0  0f a4 b8 6b 40 04 50 77  e3 05 9b 24 b8 93 e8 4d  |...k@.Pw...$...M|
+000002d0  ef 30 cd 51 90 58 a2 49  71 b3 3f b9 46 ab a9 72  |.0.Q.X.Iq.?.F..r|
+000002e0  02 42 01 58 ef 20 c1 0a  33 f8 fd 50 9e 65 f5 ef  |.B.X. ..3..P.e..|
+000002f0  f4 91 49 2d d2 de 66 2b  97 69 7d b1 d0 ef d6 91  |..I-..f+.i}.....|
+00000300  0f fc 57 2b 73 b9 49 01  33 d2 1b 5b 9a 2c 51 35  |..W+s.I.3..[.,Q5|
+00000310  0e eb 38 53 fa 20 07 84  52 b3 43 24 09 5a 32 c0  |..8S. ..R.C$.Z2.|
+00000320  32 17 34 6c 16 03 01 00  04 0e 00 00 00           |2.4l.........|
 >>> Flow 3 (client to server)
-00000000  16 03 01 00 46 10 00 00  42 41 04 08 28 cf bd 3c  |....F...BA..(..<|
-00000010  3c cc 98 9e 73 3f 92 a7  cb 22 83 3b c7 61 46 0e  |<...s?...".;.aF.|
-00000020  4d 7c 30 b5 06 85 2f 01  be b5 40 e2 64 1e 45 c1  |M|0.../...@.d.E.|
-00000030  9d 73 95 d5 65 92 0b 9b  e7 6f c6 91 ab b6 fa be  |.s..e....o......|
-00000040  61 83 a7 f2 eb f5 65 31  fe 24 7b 14 03 01 00 01  |a.....e1.${.....|
-00000050  01 16 03 01 00 30 15 d1  c4 ca 0b 01 84 13 5a ba  |.....0........Z.|
-00000060  89 04 87 73 7c bb d8 89  7e 10 27 ba 6f 5d dc d3  |...s|...~.'.o]..|
-00000070  b5 ef 32 86 58 cc fb eb  5c 32 9e 95 ef 01 1c ac  |..2.X...\2......|
-00000080  dc 8e df 7f fe 0a                                 |......|
+00000000  16 03 01 00 46 10 00 00  42 41 04 31 74 f8 f6 18  |....F...BA.1t...|
+00000010  55 6a 9b 3b 78 0a 0e f0  c9 91 aa 8e 77 39 0a 88  |Uj.;x.......w9..|
+00000020  a4 d4 f6 04 9d de 89 18  b6 50 12 72 26 9c 8f e1  |.........P.r&...|
+00000030  f0 b2 e6 df ce 3b 46 be  e9 2a 9a e3 7f d1 d5 92  |.....;F..*......|
+00000040  ff e3 ae 0a 2d a1 3b 07  f6 04 59 14 03 01 00 01  |....-.;...Y.....|
+00000050  01 16 03 01 00 30 02 4f  df 41 30 97 6f f7 18 ca  |.....0.O.A0.o...|
+00000060  05 35 17 a1 a2 a5 71 61  b1 d8 dd 9a c6 f3 54 53  |.5....qa......TS|
+00000070  84 f6 fb 93 1e 0e 9d e7  fe 35 85 9e 73 d0 2e a1  |.........5..s...|
+00000080  a7 63 d9 40 c6 ac                                 |.c.@..|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 e8 48 86 81 3c  |..........0.H..<|
-00000010  f5 25 5c 94 a9 06 c4 5c  71 62 b1 43 76 ec 2c 44  |.%\....\qb.Cv.,D|
-00000020  95 b5 8c 95 d2 ff 82 92  b6 fc 52 75 03 c6 a1 f0  |..........Ru....|
-00000030  99 6d b1 ed ec 68 6c d7  9f 18 50 17 03 01 00 20  |.m...hl...P.... |
-00000040  32 d9 26 8a 81 b8 9d a5  7b fd d5 4e 7a db 2e 29  |2.&.....{..Nz..)|
-00000050  58 9a 4f 6a 27 18 bc dc  c2 49 b8 65 cb 8e 16 5a  |X.Oj'....I.e...Z|
-00000060  17 03 01 00 30 c4 56 0a  ad 9a 82 cb 3e 32 f1 7c  |....0.V.....>2.||
-00000070  95 6e dd cd e9 4d f0 e5  2d c9 a3 f7 de bb d7 fd  |.n...M..-.......|
-00000080  84 bb df 34 8c 64 1f 03  58 64 19 4a 5b 7a a8 81  |...4.d..Xd.J[z..|
-00000090  52 bb 51 0a 43 15 03 01  00 20 89 18 7a 40 ec 49  |R.Q.C.... ..z@.I|
-000000a0  52 d5 d3 20 ac 07 eb e9  4a 78 23 cf e7 21 32 74  |R.. ....Jx#..!2t|
-000000b0  ec 40 8d a8 f4 33 1c ae  93 cf                    |.@...3....|
+00000000  14 03 01 00 01 01 16 03  01 00 30 07 7e 4e 9c 19  |..........0.~N..|
+00000010  f0 35 cd 02 b7 a6 0a 1a  b1 a8 11 a3 f9 b1 35 7b  |.5............5{|
+00000020  96 7f e6 e1 00 c6 6d 9e  e6 8a bb a2 b8 bd a3 9d  |......m.........|
+00000030  05 22 1b f1 f5 28 4a 00  6e f1 71 17 03 01 00 20  |."...(J.n.q.... |
+00000040  ad c7 4c dc f4 81 1a 39  3d 86 5e 8e f5 0d a3 33  |..L....9=.^....3|
+00000050  88 32 e7 be 8b 6a 8d 44  29 7b 47 fd e5 33 01 1e  |.2...j.D){G..3..|
+00000060  17 03 01 00 30 61 47 ee  ae 89 25 ac 85 3b 8a 84  |....0aG...%..;..|
+00000070  47 61 ea 3e 4c 70 57 07  d6 f1 1c 21 cb 44 7e de  |Ga.>LpW....!.D~.|
+00000080  b5 01 9e fb fe ad bc be  74 c0 65 a0 6b c1 0c 8c  |........t.e.k...|
+00000090  2b 00 24 c6 b7 15 03 01  00 20 b7 8b 6b e5 77 ab  |+.$...... ..k.w.|
+000000a0  f6 50 9e 88 4d 56 a8 25  8d 02 db cb 68 8b 3f 62  |.P..MV.%....h.?b|
+000000b0  be aa 02 24 75 b1 e5 4b  18 c9                    |...$u..K..|
index 106244d5a22e62eac5ad1387e854c3d6bdca6d0e..ca804295da31d3e46c8ac151090756a7e394f32a 100644 (file)
@@ -1,33 +1,32 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 8a 01 00 01  86 03 03 34 54 69 f3 d7  |...........4Ti..|
-00000010  20 9d 1d 74 db 72 e9 2f  51 7c c2 82 0a 9b cb 6d  | ..t.r./Q|.....m|
-00000020  90 b4 8e a2 1f 2f c7 66  74 8f 33 00 00 d6 c0 30  |...../.ft.3....0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 c0 20  |.,.(.$.....".!. |
-00000040  00 a5 00 a3 00 a1 00 9f  00 6b 00 6a 00 69 00 68  |.........k.j.i.h|
-00000050  00 39 00 38 00 37 00 36  00 88 00 87 00 86 00 85  |.9.8.7.6........|
-00000060  c0 32 c0 2e c0 2a c0 26  c0 0f c0 05 00 9d 00 3d  |.2...*.&.......=|
-00000070  00 35 00 84 c0 2f c0 2b  c0 27 c0 23 c0 13 c0 09  |.5.../.+.'.#....|
-00000080  c0 1f c0 1e c0 1d 00 a4  00 a2 00 a0 00 9e 00 67  |...............g|
-00000090  00 40 00 3f 00 3e 00 33  00 32 00 31 00 30 00 9a  |.@.?.>.3.2.1.0..|
-000000a0  00 99 00 98 00 97 00 45  00 44 00 43 00 42 c0 31  |.......E.D.C.B.1|
-000000b0  c0 2d c0 29 c0 25 c0 0e  c0 04 00 9c 00 3c 00 2f  |.-.).%.......<./|
-000000c0  00 96 00 41 00 07 c0 11  c0 07 c0 0c c0 02 00 05  |...A............|
-000000d0  00 04 c0 12 c0 08 c0 1c  c0 1b c0 1a 00 16 00 13  |................|
-000000e0  00 10 00 0d c0 0d c0 03  00 0a 00 15 00 12 00 0f  |................|
-000000f0  00 0c 00 09 00 14 00 11  00 0e 00 0b 00 08 00 06  |................|
-00000100  00 03 00 ff 01 00 00 87  00 0b 00 04 03 00 01 02  |................|
-00000110  00 0a 00 3a 00 38 00 0e  00 0d 00 19 00 1c 00 0b  |...:.8..........|
-00000120  00 0c 00 1b 00 18 00 09  00 0a 00 1a 00 16 00 17  |................|
-00000130  00 08 00 06 00 07 00 14  00 15 00 04 00 05 00 12  |................|
-00000140  00 13 00 01 00 02 00 03  00 0f 00 10 00 11 00 23  |...............#|
-00000150  00 00 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |..... ..........|
-00000160  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-00000170  02 01 02 02 02 03 00 0f  00 01 01 00 10 00 10 00  |................|
-00000180  0e 06 70 72 6f 74 6f 32  06 70 72 6f 74 6f 31     |..proto2.proto1|
+00000000  16 03 01 01 78 01 00 01  74 03 03 73 99 93 cd 3d  |....x...t..s...=|
+00000010  e8 60 23 0d 6a e8 f5 e3  46 ca 38 44 85 ca 79 c8  |.`#.j...F.8D..y.|
+00000020  96 be 94 bd 43 d5 14 2b  20 da 5c 00 00 c4 c0 30  |....C..+ .\....0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
+00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
+00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
+00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
+00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
+00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g.@.?.>.3.2.1|
+00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
+000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
+000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
+000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
+000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
+000000e0  00 09 00 14 00 11 00 0e  00 0b 00 08 00 06 00 03  |................|
+000000f0  00 ff 01 00 00 87 00 0b  00 04 03 00 01 02 00 0a  |................|
+00000100  00 3a 00 38 00 0e 00 0d  00 19 00 1c 00 0b 00 0c  |.:.8............|
+00000110  00 1b 00 18 00 09 00 0a  00 1a 00 16 00 17 00 08  |................|
+00000120  00 06 00 07 00 14 00 15  00 04 00 05 00 12 00 13  |................|
+00000130  00 01 00 02 00 03 00 0f  00 10 00 11 00 23 00 00  |.............#..|
+00000140  00 0d 00 20 00 1e 06 01  06 02 06 03 05 01 05 02  |... ............|
+00000150  05 03 04 01 04 02 04 03  03 01 03 02 03 03 02 01  |................|
+00000160  02 02 02 03 00 0f 00 01  01 00 10 00 10 00 0e 06  |................|
+00000170  70 72 6f 74 6f 32 06 70  72 6f 74 6f 31           |proto2.proto1|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 42 02 00 00  3e 03 03 00 00 00 00 00  |....B...>.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 14 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 30 00 00  |.............0..|
 00000030  16 00 23 00 00 ff 01 00  01 00 00 10 00 09 00 07  |..#.............|
 00000040  06 70 72 6f 74 6f 31 16  03 03 02 be 0b 00 02 ba  |.proto1.........|
 00000050  00 02 b7 00 02 b4 30 82  02 b0 30 82 02 19 a0 03  |......0...0.....|
 00000320  35 75 71 b5 e5 54 5b 12  2e 8f 09 67 fd a7 24 20  |5uq..T[....g..$ |
 00000330  3e b2 56 1c ce 97 28 5e  f8 2b 2d 4f 9e f1 07 9f  |>.V...(^.+-O....|
 00000340  6c 4b 5b 83 56 e2 32 42  e9 58 b6 d7 49 a6 b5 68  |lK[.V.2B.X..I..h|
-00000350  1a 41 03 56 6b dc 5a 89  04 01 00 80 2d a0 6e 47  |.A.Vk.Z.....-.nG|
-00000360  93 a2 19 17 32 f5 42 58  93 f6 4f d4 e9 4d a4 0f  |....2.BX..O..M..|
-00000370  fe 4e d7 2c 62 b6 fb 83  37 a3 09 60 4b 69 e2 4c  |.N.,b...7..`Ki.L|
-00000380  fc b8 4c d1 a6 9a 89 a0  c5 76 f5 62 b7 e8 eb c2  |..L......v.b....|
-00000390  fa 0f 0e 61 86 bc 70 da  13 72 8d 87 94 16 9a 8d  |...a..p..r......|
-000003a0  5f 80 82 92 77 37 4f 9e  55 5d dc 35 42 a3 75 5c  |_...w7O.U].5B.u\|
-000003b0  ec a4 58 78 66 97 97 da  49 67 2e b6 7e 11 de fb  |..Xxf...Ig..~...|
-000003c0  e3 8f e8 bf 1d 91 1e 91  20 1b 2a df c6 58 e4 82  |........ .*..X..|
-000003d0  ce 37 dd 6f a5 ac 51 3d  65 db 3f f5 16 03 03 00  |.7.o..Q=e.?.....|
+00000350  1a 41 03 56 6b dc 5a 89  04 01 00 80 52 f3 4c 3f  |.A.Vk.Z.....R.L?|
+00000360  c4 82 3c 4f 8f dc f5 33  c5 12 41 80 dc ea f2 84  |..<O...3..A.....|
+00000370  cf e4 50 f6 27 90 bb d0  09 ef 9c 9a 34 58 5c 38  |..P.'.......4X\8|
+00000380  53 27 72 e5 07 86 bb 4d  6c 17 6f 79 60 bd ca cb  |S'r....Ml.oy`...|
+00000390  be 05 f1 0c 46 4b 1f 19  74 67 cd d9 64 2a fa 5f  |....FK..tg..d*._|
+000003a0  b8 47 fb 98 47 a9 1f d5  20 95 19 48 70 1a 1c 57  |.G..G... ..Hp..W|
+000003b0  81 46 2a 8c 56 35 69 48  c9 23 a0 4e 7f f0 c0 fc  |.F*.V5iH.#.N....|
+000003c0  eb 28 8a d3 99 45 39 cc  2b 2a 93 1f c3 0b 68 60  |.(...E9.+*....h`|
+000003d0  91 14 5e 6d be e6 40 19  38 76 d1 4c 16 03 03 00  |..^m..@.8v.L....|
 000003e0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 f3 fc ea d8 50  |....F...BA.....P|
-00000010  e6 15 b0 e7 11 c7 6d ee  09 ad 80 d5 54 eb 4f 62  |......m.....T.Ob|
-00000020  7d bb a7 2d 28 0c 66 33  42 09 cf 2b 58 f8 58 41  |}..-(.f3B..+X.XA|
-00000030  bd 46 51 0a f0 7d 8c 0c  98 9e 26 77 20 fd 5e c1  |.FQ..}....&w .^.|
-00000040  a9 b3 e5 c3 6c 05 97 e3  81 fd db 14 03 03 00 01  |....l...........|
-00000050  01 16 03 03 00 40 02 2a  28 41 e3 9c 5d 45 d4 45  |.....@.*(A..]E.E|
-00000060  51 8c 7a c0 ba b1 8e a4  84 2c f3 83 cd c4 55 5c  |Q.z......,....U\|
-00000070  d6 5c 6f 72 ab 89 7a c6  d7 9c 2a 54 f0 c4 20 ee  |.\or..z...*T.. .|
-00000080  37 74 9b b6 8c f7 e4 37  2c eb d4 9f 5c 5e 55 a0  |7t.....7,...\^U.|
-00000090  e2 5a fe 1e c8 67                                 |.Z...g|
+00000000  16 03 03 00 46 10 00 00  42 41 04 e2 86 c1 a0 c0  |....F...BA......|
+00000010  45 9a da 1a 70 a1 3e b6  9c b7 2e ec dd 2b 0a c6  |E...p.>......+..|
+00000020  50 59 95 fe 8e 54 83 06  b6 68 42 60 56 de b2 b3  |PY...T...hB`V...|
+00000030  b9 14 f0 e0 e2 2e a3 7f  ec 01 4d 10 8a 43 ab 33  |..........M..C.3|
+00000040  18 f4 b9 5d 6c ae cd 90  3e f4 64 14 03 03 00 01  |...]l...>.d.....|
+00000050  01 16 03 03 00 28 47 e5  15 81 5b f4 a0 6a 61 d6  |.....(G...[..ja.|
+00000060  df 5e 60 f1 d4 dc 55 45  84 0b ef 56 42 0b 42 1d  |.^`...UE...VB.B.|
+00000070  28 b4 90 a6 2a 47 41 97  3b 91 5c 74 ab 02        |(...*GA.;.\t..|
 >>> Flow 4 (server to client)
 00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
-00000020  ea 8b c0 ef ba 59 31 75  33 96 f1 f8 c9 e1 ef 30  |.....Y1u3......0|
-00000030  00 a3 a9 1d ab c8 4b 29  94 f2 c8 c8 8d 03 57 ab  |......K)......W.|
-00000040  56 df 0f 4e 0d 30 13 09  c9 e4 fa 51 4e b3 26 ad  |V..N.0.....QN.&.|
-00000050  43 9f ae 62 d5 59 23 05  9b 69 8f 5b a8 ba 39 f1  |C..b.Y#..i.[..9.|
-00000060  90 84 35 bf 8f 8d d5 39  93 98 ee b9 75 03 3f 91  |..5....9....u.?.|
-00000070  e8 56 0b cb 44 a6 7a 14  03 03 00 01 01 16 03 03  |.V..D.z.........|
-00000080  00 40 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |.@..............|
-00000090  00 00 f9 a0 8e 23 34 f1  61 15 a8 4e ae c4 f3 2a  |.....#4.a..N...*|
-000000a0  a6 f8 ee 1b 65 c4 c0 ff  93 14 74 ed 82 ae 48 a8  |....e.....t...H.|
-000000b0  42 fb a9 24 5d dd fd 98  b8 65 73 03 88 99 e1 ed  |B..$]....es.....|
-000000c0  02 95 17 03 03 00 40 00  00 00 00 00 00 00 00 00  |......@.........|
-000000d0  00 00 00 00 00 00 00 b9  b3 f5 41 84 3b 2a a9 c3  |..........A.;*..|
-000000e0  9c e3 d4 38 90 76 c1 8c  f0 4f 10 1b 04 b5 07 fe  |...8.v...O......|
-000000f0  79 3d 7b 77 a4 17 0f 4e  df 64 70 70 9e 34 8e b6  |y={w...N.dpp.4..|
-00000100  db b2 b6 fd 41 fe b3 15  03 03 00 30 00 00 00 00  |....A......0....|
-00000110  00 00 00 00 00 00 00 00  00 00 00 00 02 73 de fe  |.............s..|
-00000120  fa 4b 69 6d 30 69 79 96  7e 4f 2f 04 67 36 96 27  |.Kim0iy.~O/.g6.'|
-00000130  67 23 2b dc 7a c4 6c 34  ea fc 79 fd              |g#+.z.l4..y.|
+00000020  ea 8b e4 ef ba 19 39 3a  95 90 2b 6d 0d 59 ac 36  |......9:..+m.Y.6|
+00000030  be 71 eb b4 25 51 86 cc  80 43 ea 60 e0 53 30 ba  |.q..%Q...C.`.S0.|
+00000040  3e b9 c3 29 9b 26 94 5a  43 36 d0 65 be a7 f1 06  |>..).&.ZC6.e....|
+00000050  99 e3 c5 d7 f2 59 23 11  c5 99 27 5c 7f 43 94 0e  |.....Y#...'\.C..|
+00000060  b3 35 7a 66 d9 c4 49 53  2a 28 b6 3d e7 0f c5 d5  |.5zf..IS*(.=....|
+00000070  a2 d8 15 a8 3a 88 f7 14  03 03 00 01 01 16 03 03  |....:...........|
+00000080  00 28 00 00 00 00 00 00  00 00 07 2e 75 1d 9a 12  |.(..........u...|
+00000090  9f e9 7e 0b 42 dd 7b 8e  ae 58 ac 49 78 8d fb 3f  |..~.B.{..X.Ix..?|
+000000a0  21 e8 ef 91 3c 02 a6 23  d5 cc 17 03 03 00 25 00  |!...<..#......%.|
+000000b0  00 00 00 00 00 00 01 bb  04 db f2 86 63 96 01 60  |............c..`|
+000000c0  bb f4 68 f9 50 2a f0 15  82 f8 a1 73 bf cd 5f 4d  |..h.P*.....s.._M|
+000000d0  1a 73 67 91 15 03 03 00  1a 00 00 00 00 00 00 00  |.sg.............|
+000000e0  02 02 79 34 67 e2 67 d5  52 59 91 76 90 10 c8 41  |..y4g.g.RY.v...A|
+000000f0  c5 56 c9                                          |.V.|
index db5881b768524aafd6e6c230ae0cc55d3ff5a04b..54f2fe864b5ded823a0b471714553247e58b33b7 100644 (file)
@@ -1,33 +1,32 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 8a 01 00 01  86 03 03 0a a8 82 53 61  |..............Sa|
-00000010  68 e0 83 91 71 36 f9 c1  19 ff e8 09 fc 21 9f 03  |h...q6.......!..|
-00000020  31 f3 87 4a 04 8c 3d c2  6e 00 32 00 00 d6 c0 30  |1..J..=.n.2....0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 c0 20  |.,.(.$.....".!. |
-00000040  00 a5 00 a3 00 a1 00 9f  00 6b 00 6a 00 69 00 68  |.........k.j.i.h|
-00000050  00 39 00 38 00 37 00 36  00 88 00 87 00 86 00 85  |.9.8.7.6........|
-00000060  c0 32 c0 2e c0 2a c0 26  c0 0f c0 05 00 9d 00 3d  |.2...*.&.......=|
-00000070  00 35 00 84 c0 2f c0 2b  c0 27 c0 23 c0 13 c0 09  |.5.../.+.'.#....|
-00000080  c0 1f c0 1e c0 1d 00 a4  00 a2 00 a0 00 9e 00 67  |...............g|
-00000090  00 40 00 3f 00 3e 00 33  00 32 00 31 00 30 00 9a  |.@.?.>.3.2.1.0..|
-000000a0  00 99 00 98 00 97 00 45  00 44 00 43 00 42 c0 31  |.......E.D.C.B.1|
-000000b0  c0 2d c0 29 c0 25 c0 0e  c0 04 00 9c 00 3c 00 2f  |.-.).%.......<./|
-000000c0  00 96 00 41 00 07 c0 11  c0 07 c0 0c c0 02 00 05  |...A............|
-000000d0  00 04 c0 12 c0 08 c0 1c  c0 1b c0 1a 00 16 00 13  |................|
-000000e0  00 10 00 0d c0 0d c0 03  00 0a 00 15 00 12 00 0f  |................|
-000000f0  00 0c 00 09 00 14 00 11  00 0e 00 0b 00 08 00 06  |................|
-00000100  00 03 00 ff 01 00 00 87  00 0b 00 04 03 00 01 02  |................|
-00000110  00 0a 00 3a 00 38 00 0e  00 0d 00 19 00 1c 00 0b  |...:.8..........|
-00000120  00 0c 00 1b 00 18 00 09  00 0a 00 1a 00 16 00 17  |................|
-00000130  00 08 00 06 00 07 00 14  00 15 00 04 00 05 00 12  |................|
-00000140  00 13 00 01 00 02 00 03  00 0f 00 10 00 11 00 23  |...............#|
-00000150  00 00 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |..... ..........|
-00000160  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-00000170  02 01 02 02 02 03 00 0f  00 01 01 00 10 00 10 00  |................|
-00000180  0e 06 70 72 6f 74 6f 32  06 70 72 6f 74 6f 31     |..proto2.proto1|
+00000000  16 03 01 01 78 01 00 01  74 03 03 ba 93 c5 44 7d  |....x...t.....D}|
+00000010  cf bf e3 d4 ad 9a ff 3a  48 ec 46 11 1a e5 68 87  |.......:H.F...h.|
+00000020  d1 f0 3b 7c da 86 b9 8f  5d a7 59 00 00 c4 c0 30  |..;|....].Y....0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
+00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
+00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
+00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
+00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
+00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g.@.?.>.3.2.1|
+00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
+000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
+000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
+000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
+000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
+000000e0  00 09 00 14 00 11 00 0e  00 0b 00 08 00 06 00 03  |................|
+000000f0  00 ff 01 00 00 87 00 0b  00 04 03 00 01 02 00 0a  |................|
+00000100  00 3a 00 38 00 0e 00 0d  00 19 00 1c 00 0b 00 0c  |.:.8............|
+00000110  00 1b 00 18 00 09 00 0a  00 1a 00 16 00 17 00 08  |................|
+00000120  00 06 00 07 00 14 00 15  00 04 00 05 00 12 00 13  |................|
+00000130  00 01 00 02 00 03 00 0f  00 10 00 11 00 23 00 00  |.............#..|
+00000140  00 0d 00 20 00 1e 06 01  06 02 06 03 05 01 05 02  |... ............|
+00000150  05 03 04 01 04 02 04 03  03 01 03 02 03 03 02 01  |................|
+00000160  02 02 02 03 00 0f 00 01  01 00 10 00 10 00 0e 06  |................|
+00000170  70 72 6f 74 6f 32 06 70  72 6f 74 6f 31           |proto2.proto1|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 14 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 30 00 00  |.............0..|
 00000030  09 00 23 00 00 ff 01 00  01 00 16 03 03 02 be 0b  |..#.............|
 00000040  00 02 ba 00 02 b7 00 02  b4 30 82 02 b0 30 82 02  |.........0...0..|
 00000050  19 a0 03 02 01 02 02 09  00 85 b0 bb a4 8a 7f b8  |................|
 00000310  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000320  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000330  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
-00000340  a6 b5 68 1a 41 03 56 6b  dc 5a 89 04 01 00 80 b9  |..h.A.Vk.Z......|
-00000350  0f 79 8a 16 f4 da 8f 27  b4 16 fc c0 51 db ae d1  |.y.....'....Q...|
-00000360  af 79 77 d5 d5 a2 13 05  45 20 cc eb ac ed cb 30  |.yw.....E .....0|
-00000370  32 2e 2c bd fa 1c 4d b5  32 a6 37 43 c8 5c 2d f8  |2.,...M.2.7C.\-.|
-00000380  6e 85 f5 cd 54 92 29 ad  13 7d d5 9e 8c 1d b7 d0  |n...T.)..}......|
-00000390  c1 c7 3d e8 ba 4a 0f 9a  a6 3e 25 5f 27 62 b1 00  |..=..J...>%_'b..|
-000003a0  91 d9 23 48 3f 10 fe c5  e3 07 9a 58 57 6d cc 10  |..#H?......XWm..|
-000003b0  3b f8 1a d5 6e 8b 1f 03  6f 82 84 98 b5 f7 71 5d  |;...n...o.....q]|
-000003c0  c2 ad 60 14 c1 88 07 5a  3d 99 fd a8 c9 9a 03 16  |..`....Z=.......|
+00000340  a6 b5 68 1a 41 03 56 6b  dc 5a 89 04 01 00 80 52  |..h.A.Vk.Z.....R|
+00000350  78 35 42 fa 35 a6 19 22  d1 03 f4 ed 65 31 ff fe  |x5B.5.."....e1..|
+00000360  d6 83 d5 db a1 6b 7d 88  2f 53 7a e8 2a cf a7 e4  |.....k}./Sz.*...|
+00000370  83 0f e7 b6 60 60 91 65  ee ce b0 e9 5c bb 8c fd  |....``.e....\...|
+00000380  10 5e c7 17 cb 1b bc db  19 59 23 5d 76 3a f8 87  |.^.......Y#]v:..|
+00000390  d8 2d a7 a2 d8 7b cc e5  f8 82 7c ed bf 08 c4 67  |.-...{....|....g|
+000003a0  c5 f6 a6 5a 2f 9f 59 cb  62 f6 b4 f3 3c d6 f5 dc  |...Z/.Y.b...<...|
+000003b0  20 27 d9 14 36 5c a9 8d  f6 7b c2 db 9f 84 fc 0d  | '..6\...{......|
+000003c0  d3 3a d2 bf 4a 3b 3c 3e  13 eb f9 03 d2 cf 6f 16  |.:..J;<>......o.|
 000003d0  03 03 00 04 0e 00 00 00                           |........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 76 aa 4e b9 f9  |....F...BA.v.N..|
-00000010  68 85 81 74 7c d9 f9 64  7f bd 09 83 08 5b 4f 76  |h..t|..d.....[Ov|
-00000020  6e be 79 b6 4e 97 17 63  e4 b5 1c 77 e5 85 76 8a  |n.y.N..c...w..v.|
-00000030  5d 9f f1 21 88 ec f9 a7  7c 41 af f9 c5 fe 11 81  |]..!....|A......|
-00000040  11 51 8e a7 20 33 5f cf  e7 90 90 14 03 03 00 01  |.Q.. 3_.........|
-00000050  01 16 03 03 00 40 44 3e  32 01 71 ac 5a b5 1f 2c  |.....@D>2.q.Z..,|
-00000060  37 d9 4b 70 72 91 89 d4  d7 c2 c3 e7 ff dc 72 2a  |7.Kpr.........r*|
-00000070  ba f5 30 b0 e9 dd 48 10  3d cd 98 48 a3 e3 ca de  |..0...H.=..H....|
-00000080  15 0e 90 8e e5 04 14 74  42 b8 b0 12 cc 68 7b 7d  |.......tB....h{}|
-00000090  6c 43 72 60 05 0d                                 |lCr`..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 f2 52 42 97 0a  |....F...BA..RB..|
+00000010  df a1 e0 cb 4e 5e 3c e5  45 0e de b3 eb 3d cd c2  |....N^<.E....=..|
+00000020  78 77 ff ec 6e 74 c2 e5  9e 89 58 6f 2b bc 41 5b  |xw..nt....Xo+.A[|
+00000030  d5 8f d0 ea ce c6 c9 11  74 0a c1 33 2a 52 c2 30  |........t..3*R.0|
+00000040  73 08 5f 20 f2 0a 45 95  81 a8 eb 14 03 03 00 01  |s._ ..E.........|
+00000050  01 16 03 03 00 28 52 9e  4c 11 49 07 9f b5 4b 2f  |.....(R.L.I...K/|
+00000060  45 79 0c d9 cb ae 45 7d  17 1e c2 5a d3 ea bd 8b  |Ey....E}...Z....|
+00000070  0d 94 b1 40 a2 56 6e a5  f8 a2 5b f8 63 73        |...@.Vn...[.cs|
 >>> Flow 4 (server to client)
 00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
-00000020  ea 8b c0 ef ba 12 45 17  61 24 cd d2 4c 22 bb 3b  |......E.a$..L".;|
-00000030  e3 0e d0 ff 83 e9 7c b7  8f 10 3c 16 1c fc c2 44  |......|...<....D|
-00000040  ef 45 f8 27 30 56 db ea  eb ae f5 b6 17 b2 ef f9  |.E.'0V..........|
-00000050  96 0d 2d db e4 59 23 0a  fc fa e3 13 48 57 e5 b3  |..-..Y#.....HW..|
-00000060  3a d1 f5 5e ca ef d7 3f  7b b5 f4 69 85 c3 bd da  |:..^...?{..i....|
-00000070  fd 9c 50 05 2f 86 ce 14  03 03 00 01 01 16 03 03  |..P./...........|
-00000080  00 40 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |.@..............|
-00000090  00 00 60 25 1c ed 6f c6  a5 bd b2 29 39 4e 09 d1  |..`%..o....)9N..|
-000000a0  64 cc 75 cd df 91 a8 90  9d 03 aa 92 07 f2 d0 8a  |d.u.............|
-000000b0  60 bb 3e 85 21 22 fe f8  dc 52 3c 4e 82 77 14 14  |`.>.!"...R<N.w..|
-000000c0  0f 1f 17 03 03 00 40 00  00 00 00 00 00 00 00 00  |......@.........|
-000000d0  00 00 00 00 00 00 00 0b  87 12 62 3e e5 3e 7d 74  |..........b>.>}t|
-000000e0  0d ac c4 a9 df 67 1c 5a  ad 3e 01 34 03 88 2f 39  |.....g.Z.>.4../9|
-000000f0  f7 3c 06 e4 f6 81 43 66  b1 1b ed a5 e5 b6 a8 43  |.<....Cf.......C|
-00000100  7f 36 2f b2 da 45 9a 15  03 03 00 30 00 00 00 00  |.6/..E.....0....|
-00000110  00 00 00 00 00 00 00 00  00 00 00 00 fa 63 4e c5  |.............cN.|
-00000120  77 89 71 56 e3 0a cf 98  da 2f 89 8f 74 8e 76 24  |w.qV...../..t.v$|
-00000130  e2 40 a5 9f 29 1b b2 11  ef 7a 55 7f              |.@..)....zU.|
+00000020  ea 8b e4 ef ba f6 cb 68  be 7f f0 66 1a c6 3c c6  |.......h...f..<.|
+00000030  ee 5f 60 3a 62 20 c5 e8  ea 99 92 84 c1 45 a1 76  |._`:b .......E.v|
+00000040  7c a7 f2 cd 40 72 9b 38  51 77 f2 ae 54 dd 67 37  ||...@r.8Qw..T.g7|
+00000050  f8 98 43 2e 55 59 23 3b  50 26 87 ca 6b 2d 45 d6  |..C.UY#;P&..k-E.|
+00000060  3c 85 29 f4 52 58 83 98  ae ad a9 64 8b d1 cc 9c  |<.).RX.....d....|
+00000070  88 3f a8 f9 d2 d3 33 14  03 03 00 01 01 16 03 03  |.?....3.........|
+00000080  00 28 00 00 00 00 00 00  00 00 84 6d 6d 57 fb dc  |.(.........mmW..|
+00000090  09 54 c4 9a fc d7 dd 45  f5 c3 57 fd e9 16 76 ab  |.T.....E..W...v.|
+000000a0  a8 85 eb 34 e7 21 30 85  56 ed 17 03 03 00 25 00  |...4.!0.V.....%.|
+000000b0  00 00 00 00 00 00 01 05  62 69 79 cb c0 74 ad 64  |........biy..t.d|
+000000c0  0a 0c 2a 10 2a b7 8e e2  92 6e 12 3b d7 64 df d7  |..*.*....n.;.d..|
+000000d0  4f da 52 c6 15 03 03 00  1a 00 00 00 00 00 00 00  |O.R.............|
+000000e0  02 b9 dc 49 b9 2a 12 58  3a 4b 4c e0 c8 b2 e9 d9  |...I.*.X:KL.....|
+000000f0  dc 48 17                                          |.H.|
index 0ab8b8d74c56d40fdabfac023cc11a29b84b9145..cc06d5f838b23fefa13e1c51d06892220ffb6936 100644 (file)
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 ca 01 00 00  c6 03 03 53 04 f1 3f 5f  |...........S..?_|
-00000010  f4 ef 1f b3 41 0b 54 e4  4d 56 0a 31 22 b8 5c 73  |....A.T.MV.1".\s|
-00000020  a3 cb b5 b2 9d 43 f1 83  bc d3 bd 00 00 32 c0 30  |.....C.......2.0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 00 a3  |.,.(.$.....".!..|
-00000040  00 9f 00 6b 00 6a 00 39  00 38 00 88 00 87 c0 32  |...k.j.9.8.....2|
-00000050  c0 2e c0 2a c0 26 c0 0f  c0 05 00 9d 00 3d 00 35  |...*.&.......=.5|
-00000060  01 00 00 6b 00 0b 00 04  03 00 01 02 00 0a 00 34  |...k...........4|
-00000070  00 32 00 0e 00 0d 00 19  00 0b 00 0c 00 18 00 09  |.2..............|
-00000080  00 0a 00 16 00 17 00 08  00 06 00 07 00 14 00 15  |................|
-00000090  00 04 00 05 00 12 00 13  00 01 00 02 00 03 00 0f  |................|
-000000a0  00 10 00 11 00 0d 00 22  00 20 06 01 06 02 06 03  |.......". ......|
-000000b0  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
-000000c0  03 03 02 01 02 02 02 03  01 01 00 0f 00 01 01     |...............|
+00000000  16 03 01 01 61 01 00 01  5d 03 03 47 c5 84 0f 55  |....a...]..G...U|
+00000010  83 4d 4a 1c 48 51 15 e4  74 72 84 70 2f 24 e9 ab  |.MJ.HQ..tr.p/$..|
+00000020  42 1e 01 e1 85 27 2f b5  c1 43 14 00 00 c4 c0 30  |B....'/..C.....0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
+00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
+00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
+00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
+00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
+00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g.@.?.>.3.2.1|
+00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
+000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
+000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
+000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
+000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
+000000e0  00 09 00 14 00 11 00 0e  00 0b 00 08 00 06 00 03  |................|
+000000f0  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
+00000100  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
+00000110  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
+00000120  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
+00000130  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0d 00  |................|
+00000140  20 00 1e 06 01 06 02 06  03 05 01 05 02 05 03 04  | ...............|
+00000150  01 04 02 04 03 03 01 03  02 03 03 02 01 02 02 02  |................|
+00000160  03 00 0f 00 01 01                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 2a 02 00 00  26 03 03 00 00 00 00 00  |....*...&.......|
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 0a 00 16  |................|
-00000030  03 03 02 0e 0b 00 02 0a  00 02 07 00 02 04 30 82  |..............0.|
-00000040  02 00 30 82 01 62 02 09  00 b8 bf 2d 47 a0 d2 eb  |..0..b.....-G...|
-00000050  f4 30 09 06 07 2a 86 48  ce 3d 04 01 30 45 31 0b  |.0...*.H.=..0E1.|
-00000060  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000070  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000080  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-00000090  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000a0  4c 74 64 30 1e 17 0d 31  32 31 31 32 32 31 35 30  |Ltd0...121122150|
-000000b0  36 33 32 5a 17 0d 32 32  31 31 32 30 31 35 30 36  |632Z..2211201506|
-000000c0  33 32 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |32Z0E1.0...U....|
-000000d0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000e0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-000000f0  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000100  74 73 20 50 74 79 20 4c  74 64 30 81 9b 30 10 06  |ts Pty Ltd0..0..|
-00000110  07 2a 86 48 ce 3d 02 01  06 05 2b 81 04 00 23 03  |.*.H.=....+...#.|
-00000120  81 86 00 04 00 c4 a1 ed  be 98 f9 0b 48 73 36 7e  |............Hs6~|
-00000130  c3 16 56 11 22 f2 3d 53  c3 3b 4d 21 3d cd 6b 75  |..V.".=S.;M!=.ku|
-00000140  e6 f6 b0 dc 9a df 26 c1  bc b2 87 f0 72 32 7c b3  |......&.....r2|.|
-00000150  64 2f 1c 90 bc ea 68 23  10 7e fe e3 25 c0 48 3a  |d/....h#.~..%.H:|
-00000160  69 e0 28 6d d3 37 00 ef  04 62 dd 0d a0 9c 70 62  |i.(m.7...b....pb|
-00000170  83 d8 81 d3 64 31 aa 9e  97 31 bd 96 b0 68 c0 9b  |....d1...1...h..|
-00000180  23 de 76 64 3f 1a 5c 7f  e9 12 0e 58 58 b6 5f 70  |#.vd?.\....XX._p|
-00000190  dd 9b d8 ea d5 d7 f5 d5  cc b9 b6 9f 30 66 5b 66  |............0f[f|
-000001a0  9a 20 e2 27 e5 bf fe 3b  30 09 06 07 2a 86 48 ce  |. .'...;0...*.H.|
-000001b0  3d 04 01 03 81 8c 00 30  81 88 02 42 01 88 a2 4f  |=......0...B...O|
-000001c0  eb e2 45 c5 48 7d 1b ac  f5 ed 98 9d ae 47 70 c0  |..E.H}.......Gp.|
-000001d0  5e 1b b6 2f bd f1 b6 4d  b7 61 40 d3 11 a2 ce ee  |^../...M.a@.....|
-000001e0  0b 7e 92 7e ff 76 9d c3  3b 7e a5 3f ce fa 10 e2  |.~.~.v..;~.?....|
-000001f0  59 ec 47 2d 7c ac da 4e  97 0e 15 a0 6f d0 02 42  |Y.G-|..N....o..B|
-00000200  01 4d fc be 67 13 9c 2d  05 0e bd 3f a3 8c 25 c1  |.M..g..-...?..%.|
-00000210  33 13 83 0d 94 06 bb d4  37 7a f6 ec 7a c9 86 2e  |3.......7z..z...|
-00000220  dd d7 11 69 7f 85 7c 56  de fb 31 78 2b e4 c7 78  |...i..|V..1x+..x|
-00000230  0d ae cb be 9e 4e 36 24  31 7b 6a 0f 39 95 12 07  |.....N6$1{j.9...|
-00000240  8f 2a 16 03 03 00 d8 0c  00 00 d4 03 00 17 41 04  |.*............A.|
-00000250  1e 18 37 ef 0d 19 51 88  35 75 71 b5 e5 54 5b 12  |..7...Q.5uq..T[.|
-00000260  2e 8f 09 67 fd a7 24 20  3e b2 56 1c ce 97 28 5e  |...g..$ >.V...(^|
-00000270  f8 2b 2d 4f 9e f1 07 9f  6c 4b 5b 83 56 e2 32 42  |.+-O....lK[.V.2B|
-00000280  e9 58 b6 d7 49 a6 b5 68  1a 41 03 56 6b dc 5a 89  |.X..I..h.A.Vk.Z.|
-00000290  04 03 00 8b 30 81 88 02  42 00 c6 85 8e 06 b7 04  |....0...B.......|
-000002a0  04 e9 cd 9e 3e cb 66 23  95 b4 42 9c 64 81 39 05  |....>.f#..B.d.9.|
-000002b0  3f b5 21 f8 28 af 60 6b  4d 3d ba a1 4b 5e 77 ef  |?.!.(.`kM=..K^w.|
-000002c0  e7 59 28 fe 1d c1 27 a2  ff a8 de 33 48 b3 c1 85  |.Y(...'....3H...|
-000002d0  6a 42 9b f9 7e 7e 31 c2  e5 bd 66 02 42 00 ad 7d  |jB..~~1...f.B..}|
-000002e0  06 35 ab ec 8d ac d4 ba  1b 49 5e 05 5f f0 97 93  |.5.......I^._...|
-000002f0  82 b8 2b 8d 91 98 63 8e  b4 14 62 db 1e c9 2b 64  |..+...c...b...+d|
-00000300  e9 e6 bf 15 5b 67 c2 40  90 c6 1f b7 92 db 4b f6  |....[g.@......K.|
-00000310  f4 db ae 82 f1 4f 02 75  52 40 38 10 ff 35 f0 16  |.....O.uR@8..5..|
-00000320  03 03 00 04 0e 00 00 00                           |........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 0a 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  03 02 0e 0b 00 02 0a 00  |................|
+00000040  02 07 00 02 04 30 82 02  00 30 82 01 62 02 09 00  |.....0...0..b...|
+00000050  b8 bf 2d 47 a0 d2 eb f4  30 09 06 07 2a 86 48 ce  |..-G....0...*.H.|
+00000060  3d 04 01 30 45 31 0b 30  09 06 03 55 04 06 13 02  |=..0E1.0...U....|
+00000070  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000080  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000090  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+000000a0  74 73 20 50 74 79 20 4c  74 64 30 1e 17 0d 31 32  |ts Pty Ltd0...12|
+000000b0  31 31 32 32 31 35 30 36  33 32 5a 17 0d 32 32 31  |1122150632Z..221|
+000000c0  31 32 30 31 35 30 36 33  32 5a 30 45 31 0b 30 09  |120150632Z0E1.0.|
+000000d0  06 03 55 04 06 13 02 41  55 31 13 30 11 06 03 55  |..U....AU1.0...U|
+000000e0  04 08 13 0a 53 6f 6d 65  2d 53 74 61 74 65 31 21  |....Some-State1!|
+000000f0  30 1f 06 03 55 04 0a 13  18 49 6e 74 65 72 6e 65  |0...U....Interne|
+00000100  74 20 57 69 64 67 69 74  73 20 50 74 79 20 4c 74  |t Widgits Pty Lt|
+00000110  64 30 81 9b 30 10 06 07  2a 86 48 ce 3d 02 01 06  |d0..0...*.H.=...|
+00000120  05 2b 81 04 00 23 03 81  86 00 04 00 c4 a1 ed be  |.+...#..........|
+00000130  98 f9 0b 48 73 36 7e c3  16 56 11 22 f2 3d 53 c3  |...Hs6~..V.".=S.|
+00000140  3b 4d 21 3d cd 6b 75 e6  f6 b0 dc 9a df 26 c1 bc  |;M!=.ku......&..|
+00000150  b2 87 f0 72 32 7c b3 64  2f 1c 90 bc ea 68 23 10  |...r2|.d/....h#.|
+00000160  7e fe e3 25 c0 48 3a 69  e0 28 6d d3 37 00 ef 04  |~..%.H:i.(m.7...|
+00000170  62 dd 0d a0 9c 70 62 83  d8 81 d3 64 31 aa 9e 97  |b....pb....d1...|
+00000180  31 bd 96 b0 68 c0 9b 23  de 76 64 3f 1a 5c 7f e9  |1...h..#.vd?.\..|
+00000190  12 0e 58 58 b6 5f 70 dd  9b d8 ea d5 d7 f5 d5 cc  |..XX._p.........|
+000001a0  b9 b6 9f 30 66 5b 66 9a  20 e2 27 e5 bf fe 3b 30  |...0f[f. .'...;0|
+000001b0  09 06 07 2a 86 48 ce 3d  04 01 03 81 8c 00 30 81  |...*.H.=......0.|
+000001c0  88 02 42 01 88 a2 4f eb  e2 45 c5 48 7d 1b ac f5  |..B...O..E.H}...|
+000001d0  ed 98 9d ae 47 70 c0 5e  1b b6 2f bd f1 b6 4d b7  |....Gp.^../...M.|
+000001e0  61 40 d3 11 a2 ce ee 0b  7e 92 7e ff 76 9d c3 3b  |a@......~.~.v..;|
+000001f0  7e a5 3f ce fa 10 e2 59  ec 47 2d 7c ac da 4e 97  |~.?....Y.G-|..N.|
+00000200  0e 15 a0 6f d0 02 42 01  4d fc be 67 13 9c 2d 05  |...o..B.M..g..-.|
+00000210  0e bd 3f a3 8c 25 c1 33  13 83 0d 94 06 bb d4 37  |..?..%.3.......7|
+00000220  7a f6 ec 7a c9 86 2e dd  d7 11 69 7f 85 7c 56 de  |z..z......i..|V.|
+00000230  fb 31 78 2b e4 c7 78 0d  ae cb be 9e 4e 36 24 31  |.1x+..x.....N6$1|
+00000240  7b 6a 0f 39 95 12 07 8f  2a 16 03 03 00 d7 0c 00  |{j.9....*.......|
+00000250  00 d3 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
+00000260  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
+00000270  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
+00000280  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
+00000290  41 03 56 6b dc 5a 89 04  03 00 8a 30 81 87 02 42  |A.Vk.Z.....0...B|
+000002a0  00 e5 db 39 b2 73 2b 4b  19 66 d6 d6 de d2 ed ae  |...9.s+K.f......|
+000002b0  0c ac 74 96 12 b2 e0 87  73 7c 63 18 8c 58 3f 56  |..t.....s|c..X?V|
+000002c0  4c fe 0f a5 2d b9 b8 1c  7d 4d 49 b9 ca f0 52 01  |L...-...}MI...R.|
+000002d0  12 e2 a9 54 9f 4d ab b7  93 71 3c 1b 96 b0 87 8b  |...T.M...q<.....|
+000002e0  87 c3 02 41 79 c3 50 88  2f 9a b8 a3 f0 14 63 ee  |...Ay.P./.....c.|
+000002f0  d6 76 dd d4 1d 1c ce 4c  ba 53 40 ac 01 d9 62 a7  |.v.....L.S@...b.|
+00000300  bc ee 66 67 fc da f4 b3  0f fd 50 5d 31 0e 2d 41  |..fg......P]1.-A|
+00000310  64 d5 51 30 a3 0e ee 20  f9 9d 0e 11 df 68 a6 f4  |d.Q0... .....h..|
+00000320  54 d4 54 7a 05 16 03 03  00 04 0e 00 00 00        |T.Tz..........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 d8 94 c4 05 26  |....F...BA.....&|
-00000010  76 29 2d 0e ec 47 b6 50  d5 a3 da 2a ba 02 11 37  |v)-..G.P...*...7|
-00000020  3d ef e6 2a db d0 47 47  a7 9a 5f 43 2d 98 78 26  |=..*..GG.._C-.x&|
-00000030  81 e2 f1 ba fe f7 66 c6  61 cb c1 b7 60 62 34 a5  |......f.a...`b4.|
-00000040  78 67 50 3d 9a 0e 4a 8c  8f d7 10 14 03 03 00 01  |xgP=..J.........|
-00000050  01 16 03 03 00 40 5e 46  b0 5d 30 f6 da 8f 9e 67  |.....@^F.]0....g|
-00000060  f5 3e bd fe c9 b8 53 b2  10 d5 7c 0e 34 e3 93 6d  |.>....S...|.4..m|
-00000070  0e 8e 8a 2b df fb 9a 0f  a5 23 55 e7 0a 4b e2 d3  |...+.....#U..K..|
-00000080  db 15 e8 52 74 26 78 b3  b0 56 65 63 ac ae 1e c0  |...Rt&x..Vec....|
-00000090  0b f4 92 56 a9 04                                 |...V..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 00 a1 de 66 1d  |....F...BA....f.|
+00000010  05 57 3b d2 0e 5f ba 4d  e9 b7 93 0a 3e bd 25 98  |.W;.._.M....>.%.|
+00000020  76 a4 8a c9 d3 c8 04 85  f6 8d 4f 3e 32 4c 25 cb  |v.........O>2L%.|
+00000030  b5 57 86 b5 04 9d f6 ba  f3 17 c8 43 cb eb 8b d0  |.W.........C....|
+00000040  ed 99 23 c7 4d 63 95 e2  cd 52 ba 14 03 03 00 01  |..#.Mc...R......|
+00000050  01 16 03 03 00 40 33 b4  f5 4a 64 88 ef dc b6 e5  |.....@3..Jd.....|
+00000060  b6 1e 40 3e 64 5a 2c 11  97 69 4c b6 7a 4c 9a 8a  |..@>dZ,..iL.zL..|
+00000070  71 f2 60 e9 39 db 96 2a  a3 33 1b 7f 43 15 8b 99  |q.`.9..*.3..C...|
+00000080  0b 52 c2 92 86 fe 57 0d  da fe 62 44 89 ce 65 4f  |.R....W...bD..eO|
+00000090  a5 8d 29 8e 10 50                                 |..)..P|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |..........@.....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 16 a9 63 0a 99  |.............c..|
-00000020  21 8a fc 5c b3 ee 05 71  4e 75 c0 d9 40 54 0d 3e  |!..\...qNu..@T.>|
-00000030  4e 5d 44 b7 4b 5d a9 e7  5a 30 ed b6 d5 08 50 b1  |N]D.K]..Z0....P.|
-00000040  e8 8c 54 eb 1b 39 7a f9  3b ac 2e 17 03 03 00 40  |..T..9z.;......@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 29 56 67 0c 28  |...........)Vg.(|
+00000020  ca 74 e1 ae c6 e2 30 3b  f2 8b f0 fd c2 eb 11 c0  |.t....0;........|
+00000030  0e 50 eb d8 4e de e3 32  6b 69 77 d8 d7 bd 94 30  |.P..N..2kiw....0|
+00000040  1e bf 03 f0 31 98 d8 07  c0 27 4b 17 03 03 00 40  |....1....'K....@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  96 03 20 2b 20 c4 c1 9a  76 7b f3 96 bd 33 ed e6  |.. + ...v{...3..|
-00000070  38 48 ea 53 d5 e0 62 b5  7e 1a 36 a8 dd 9f 2d 4b  |8H.S..b.~.6...-K|
-00000080  06 0d ae f6 bc 99 14 b3  93 14 27 63 e2 a0 c8 76  |..........'c...v|
+00000060  97 7f df af a3 9e cc a1  64 5f ab 91 8a 6f fd 19  |........d_...o..|
+00000070  be 94 95 6d bb de 12 a9  54 10 b5 95 f3 68 77 73  |...m....T....hws|
+00000080  14 09 b7 3b ca b8 88 6d  fd 0a 2d 24 c1 94 ce ce  |...;...m..-$....|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 48 af e1  e4 11 e1 b7 03 19 b0 e3  |.....H..........|
-000000b0  e6 a9 66 d8 ac af aa 03  f6 0d 51 df 9a 27 78 3a  |..f.......Q..'x:|
-000000c0  56 5a 03 1a 4c                                    |VZ..L|
+000000a0  00 00 00 00 00 04 6d b7  9e 15 51 c7 f8 de ab d0  |......m...Q.....|
+000000b0  a0 45 7f 4f bc 59 73 45  e9 a8 b1 0e 9b c3 36 c7  |.E.O.YsE......6.|
+000000c0  cb db 55 19 db                                    |..U..|
index 88abb15a7e6c83c67c14f6f553e72fefc1116eb1..0d9bb0c8b7a1be6623615180551c37c9927246aa 100644 (file)
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 ca 01 00 00  c6 03 03 53 04 f1 3f cc  |...........S..?.|
-00000010  41 74 00 07 cb ae 3b 30  79 48 51 60 41 a3 8c ab  |At....;0yHQ`A...|
-00000020  dc 76 f9 74 52 1e c5 fb  a9 69 c2 00 00 32 c0 30  |.v.tR....i...2.0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 00 a3  |.,.(.$.....".!..|
-00000040  00 9f 00 6b 00 6a 00 39  00 38 00 88 00 87 c0 32  |...k.j.9.8.....2|
-00000050  c0 2e c0 2a c0 26 c0 0f  c0 05 00 9d 00 3d 00 35  |...*.&.......=.5|
-00000060  01 00 00 6b 00 0b 00 04  03 00 01 02 00 0a 00 34  |...k...........4|
-00000070  00 32 00 0e 00 0d 00 19  00 0b 00 0c 00 18 00 09  |.2..............|
-00000080  00 0a 00 16 00 17 00 08  00 06 00 07 00 14 00 15  |................|
-00000090  00 04 00 05 00 12 00 13  00 01 00 02 00 03 00 0f  |................|
-000000a0  00 10 00 11 00 0d 00 22  00 20 06 01 06 02 06 03  |.......". ......|
-000000b0  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
-000000c0  03 03 02 01 02 02 02 03  01 01 00 0f 00 01 01     |...............|
+00000000  16 03 01 01 61 01 00 01  5d 03 03 17 83 43 01 d8  |....a...]....C..|
+00000010  14 04 ed 55 41 35 99 cd  f6 50 e6 47 10 60 7d d9  |...UA5...P.G.`}.|
+00000020  d1 f4 0f a1 bf 27 ab 0c  44 56 a5 00 00 c4 c0 30  |.....'..DV.....0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
+00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
+00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
+00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
+00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
+00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g.@.?.>.3.2.1|
+00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
+000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
+000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
+000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
+000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
+000000e0  00 09 00 14 00 11 00 0e  00 0b 00 08 00 06 00 03  |................|
+000000f0  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
+00000100  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
+00000110  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
+00000120  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
+00000130  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0d 00  |................|
+00000140  20 00 1e 06 01 06 02 06  03 05 01 05 02 05 03 04  | ...............|
+00000150  01 04 02 04 03 03 01 03  02 03 03 02 01 02 02 02  |................|
+00000160  03 00 0f 00 01 01                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 2a 02 00 00  26 03 03 00 00 00 00 00  |....*...&.......|
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 14 00 16  |................|
-00000030  03 03 02 be 0b 00 02 ba  00 02 b7 00 02 b4 30 82  |..............0.|
-00000040  02 b0 30 82 02 19 a0 03  02 01 02 02 09 00 85 b0  |..0.............|
-00000050  bb a4 8a 7f b8 ca 30 0d  06 09 2a 86 48 86 f7 0d  |......0...*.H...|
-00000060  01 01 05 05 00 30 45 31  0b 30 09 06 03 55 04 06  |.....0E1.0...U..|
-00000070  13 02 41 55 31 13 30 11  06 03 55 04 08 13 0a 53  |..AU1.0...U....S|
-00000080  6f 6d 65 2d 53 74 61 74  65 31 21 30 1f 06 03 55  |ome-State1!0...U|
-00000090  04 0a 13 18 49 6e 74 65  72 6e 65 74 20 57 69 64  |....Internet Wid|
-000000a0  67 69 74 73 20 50 74 79  20 4c 74 64 30 1e 17 0d  |gits Pty Ltd0...|
-000000b0  31 30 30 34 32 34 30 39  30 39 33 38 5a 17 0d 31  |100424090938Z..1|
-000000c0  31 30 34 32 34 30 39 30  39 33 38 5a 30 45 31 0b  |10424090938Z0E1.|
-000000d0  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-000000e0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-000000f0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-00000100  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-00000110  4c 74 64 30 81 9f 30 0d  06 09 2a 86 48 86 f7 0d  |Ltd0..0...*.H...|
-00000120  01 01 01 05 00 03 81 8d  00 30 81 89 02 81 81 00  |.........0......|
-00000130  bb 79 d6 f5 17 b5 e5 bf  46 10 d0 dc 69 be e6 2b  |.y......F...i..+|
-00000140  07 43 5a d0 03 2d 8a 7a  43 85 b7 14 52 e7 a5 65  |.CZ..-.zC...R..e|
-00000150  4c 2c 78 b8 23 8c b5 b4  82 e5 de 1f 95 3b 7e 62  |L,x.#........;~b|
-00000160  a5 2c a5 33 d6 fe 12 5c  7a 56 fc f5 06 bf fa 58  |.,.3...\zV.....X|
-00000170  7b 26 3f b5 cd 04 d3 d0  c9 21 96 4a c7 f4 54 9f  |{&?......!.J..T.|
-00000180  5a bf ef 42 71 00 fe 18  99 07 7f 7e 88 7d 7d f1  |Z..Bq......~.}}.|
-00000190  04 39 c4 a2 2e db 51 c9  7c e3 c0 4c 3b 32 66 01  |.9....Q.|..L;2f.|
-000001a0  cf af b1 1d b8 71 9a 1d  db db 89 6b ae da 2d 79  |.....q.....k..-y|
-000001b0  02 03 01 00 01 a3 81 a7  30 81 a4 30 1d 06 03 55  |........0..0...U|
-000001c0  1d 0e 04 16 04 14 b1 ad  e2 85 5a cf cb 28 db 69  |..........Z..(.i|
-000001d0  ce 23 69 de d3 26 8e 18  88 39 30 75 06 03 55 1d  |.#i..&...90u..U.|
-000001e0  23 04 6e 30 6c 80 14 b1  ad e2 85 5a cf cb 28 db  |#.n0l......Z..(.|
-000001f0  69 ce 23 69 de d3 26 8e  18 88 39 a1 49 a4 47 30  |i.#i..&...9.I.G0|
-00000200  45 31 0b 30 09 06 03 55  04 06 13 02 41 55 31 13  |E1.0...U....AU1.|
-00000210  30 11 06 03 55 04 08 13  0a 53 6f 6d 65 2d 53 74  |0...U....Some-St|
-00000220  61 74 65 31 21 30 1f 06  03 55 04 0a 13 18 49 6e  |ate1!0...U....In|
-00000230  74 65 72 6e 65 74 20 57  69 64 67 69 74 73 20 50  |ternet Widgits P|
-00000240  74 79 20 4c 74 64 82 09  00 85 b0 bb a4 8a 7f b8  |ty Ltd..........|
-00000250  ca 30 0c 06 03 55 1d 13  04 05 30 03 01 01 ff 30  |.0...U....0....0|
-00000260  0d 06 09 2a 86 48 86 f7  0d 01 01 05 05 00 03 81  |...*.H..........|
-00000270  81 00 08 6c 45 24 c7 6b  b1 59 ab 0c 52 cc f2 b0  |...lE$.k.Y..R...|
-00000280  14 d7 87 9d 7a 64 75 b5  5a 95 66 e4 c5 2b 8e ae  |....zdu.Z.f..+..|
-00000290  12 66 1f eb 4f 38 b3 6e  60 d3 92 fd f7 41 08 b5  |.f..O8.n`....A..|
-000002a0  25 13 b1 18 7a 24 fb 30  1d ba ed 98 b9 17 ec e7  |%...z$.0........|
-000002b0  d7 31 59 db 95 d3 1d 78  ea 50 56 5c d5 82 5a 2d  |.1Y....x.PV\..Z-|
-000002c0  5a 5f 33 c4 b6 d8 c9 75  90 96 8c 0f 52 98 b5 cd  |Z_3....u....R...|
-000002d0  98 1f 89 20 5f f2 a0 1c  a3 1b 96 94 dd a9 fd 57  |... _..........W|
-000002e0  e9 70 e8 26 6d 71 99 9b  26 6e 38 50 29 6c 90 a7  |.p.&mq..&n8P)l..|
-000002f0  bd d9 16 03 03 00 cd 0c  00 00 c9 03 00 17 41 04  |..............A.|
-00000300  1e 18 37 ef 0d 19 51 88  35 75 71 b5 e5 54 5b 12  |..7...Q.5uq..T[.|
-00000310  2e 8f 09 67 fd a7 24 20  3e b2 56 1c ce 97 28 5e  |...g..$ >.V...(^|
-00000320  f8 2b 2d 4f 9e f1 07 9f  6c 4b 5b 83 56 e2 32 42  |.+-O....lK[.V.2B|
-00000330  e9 58 b6 d7 49 a6 b5 68  1a 41 03 56 6b dc 5a 89  |.X..I..h.A.Vk.Z.|
-00000340  04 01 00 80 9d 84 09 35  73 fb f6 ea 94 7b 49 fb  |.......5s....{I.|
-00000350  c2 70 b1 11 64 5b 93 9f  d9 8c f5 56 98 f6 d3 66  |.p..d[.....V...f|
-00000360  a6 1d 18 56 88 87 71 3f  b0 38 9d 44 1f ad 2c 0d  |...V..q?.8.D..,.|
-00000370  3a a7 e8 d4 3e 33 3c 41  20 f3 3f 5c e5 fb e3 23  |:...>3<A .?\...#|
-00000380  12 48 ff d2 c4 30 7c 8a  51 3f 9f 19 6e 34 d7 60  |.H...0|.Q?..n4.`|
-00000390  7d 12 8a aa 90 0f 50 d9  0b 9a b2 d7 66 b1 c6 84  |}.....P.....f...|
-000003a0  af 5c e2 5e 16 3e 36 61  73 84 64 89 b3 c1 6d 50  |.\.^.>6as.d...mP|
-000003b0  33 55 c7 e1 c5 a5 4c 32  5c 95 dc 07 43 60 49 11  |3U....L2\...C`I.|
-000003c0  e9 98 cc ba 16 03 03 00  04 0e 00 00 00           |.............|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 14 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 cd 0c 00  |n8P)l...........|
+00000300  00 c9 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
+00000310  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
+00000320  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
+00000330  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
+00000340  41 03 56 6b dc 5a 89 04  01 00 80 7f 65 76 11 35  |A.Vk.Z......ev.5|
+00000350  e1 9c c6 0c 21 41 d6 b4  22 2f a3 02 57 5c 40 5c  |....!A.."/..W\@\|
+00000360  2e 0c 5f 07 01 d1 78 29  a3 7b 65 37 1c c6 51 a8  |.._...x).{e7..Q.|
+00000370  e1 70 b4 73 9a cf 37 73  c8 ce 7c 8b 60 9e 0f e4  |.p.s..7s..|.`...|
+00000380  d7 2e 2a a8 fd 5a 0c 8a  e7 e0 4c ca 0b 28 6d ea  |..*..Z....L..(m.|
+00000390  39 da 9f ac 6c 23 f0 c6  fe 21 a8 ad fb e8 c9 6d  |9...l#...!.....m|
+000003a0  96 86 75 4d 88 f0 e8 71  e0 dc 32 b9 81 f9 f3 fe  |..uM...q..2.....|
+000003b0  64 e1 34 62 dc e2 0a 21  a3 7e 70 0d b0 f3 9d 13  |d.4b...!.~p.....|
+000003c0  5c 81 58 24 97 a9 fb 1d  99 60 a7 16 03 03 00 04  |\.X$.....`......|
+000003d0  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 28 02 84 d5 b4  |....F...BA.(....|
-00000010  58 07 47 d5 a0 d6 0b 1d  37 91 e6 34 a4 ad 0b ad  |X.G.....7..4....|
-00000020  22 01 82 77 a7 32 86 78  83 3a da 75 2f e5 68 7a  |"..w.2.x.:.u/.hz|
-00000030  de e4 05 e0 02 47 40 4e  38 d2 2c c3 7b da 53 73  |.....G@N8.,.{.Ss|
-00000040  19 cb 8b 73 34 72 4d 33  71 39 c8 14 03 03 00 01  |...s4rM3q9......|
-00000050  01 16 03 03 00 40 10 63  43 76 83 bd 36 e4 1e 4d  |.....@.cCv..6..M|
-00000060  7e 13 b0 ac aa c8 ec 90  31 df 84 46 49 68 39 5a  |~.......1..FIh9Z|
-00000070  05 8b 73 32 86 15 3a 18  57 d8 e2 2c 2d 05 89 93  |..s2..:.W..,-...|
-00000080  37 b8 dd 73 33 92 ff a7  b2 53 27 94 b7 25 56 64  |7..s3....S'..%Vd|
-00000090  a1 d3 2c f7 6b 71                                 |..,.kq|
+00000000  16 03 03 00 46 10 00 00  42 41 04 27 9e 27 b7 bf  |....F...BA.'.'..|
+00000010  b1 a9 b0 5b 7d 1c 9a 02  51 6e 03 ba 60 5a a2 50  |...[}...Qn..`Z.P|
+00000020  17 a6 2a e4 02 cd 6f ed  a2 97 49 49 0c 36 70 53  |..*...o...II.6pS|
+00000030  ce 0c 79 49 14 55 9a 7f  a6 0a 10 65 4f e4 c6 10  |..yI.U.....eO...|
+00000040  c2 31 68 5c 0e 5c ab 8a  a8 1c 52 14 03 03 00 01  |.1h\.\....R.....|
+00000050  01 16 03 03 00 40 25 59  40 9e 5b 9a d5 95 a1 59  |.....@%Y@.[....Y|
+00000060  d4 1d ea 0c 02 d1 66 29  c2 d5 d4 24 7a c7 9e 47  |......f)...$z..G|
+00000070  f7 79 a1 5f 72 fb c8 10  61 81 e8 e3 fb 16 7e 30  |.y._r...a.....~0|
+00000080  e2 cc 95 d2 24 2a 0f 94  96 b6 0a 27 1a 87 c9 36  |....$*.....'...6|
+00000090  c7 b4 e9 21 d1 94                                 |...!..|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |..........@.....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 21 5c 31 b1 4b  |...........!\1.K|
-00000020  96 96 30 8f 79 35 3a 3a  2d 26 67 d0 70 48 be 30  |..0.y5::-&g.pH.0|
-00000030  f8 3e e8 c1 cb 1d d5 89  f6 9c 72 bb 1c f9 4d 90  |.>........r...M.|
-00000040  9c d7 c6 fa 40 76 a5 61  46 61 24 17 03 03 00 40  |....@v.aFa$....@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 fe 1d f1 25 18  |..............%.|
+00000020  dd 7a 1e 10 f0 86 7f 75  74 44 a5 89 92 c8 21 ff  |.z.....utD....!.|
+00000030  b8 1b bf 79 3f 19 8e 12  04 65 58 a7 e5 96 52 3a  |...y?....eX...R:|
+00000040  15 af 57 d8 9e 46 6f 3f  0d 89 67 17 03 03 00 40  |..W..Fo?..g....@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  94 8a 14 04 06 b9 30 a0  67 fd b2 4c 84 f4 10 93  |......0.g..L....|
-00000070  7d d4 2b 23 f0 e9 62 93  c2 20 a2 f2 7c 07 21 4b  |}.+#..b.. ..|.!K|
-00000080  94 ba 7b 7d cb 77 da 85  93 bd 53 ee ca db 9b 3e  |..{}.w....S....>|
+00000060  1b fb 13 e3 c0 eb 94 bb  4f e1 9e 47 6a ce 9b 6c  |........O..Gj..l|
+00000070  03 2f bf 0b 2f 08 36 48  b2 00 26 ab fb cc 3c 2f  |./../.6H..&...</|
+00000080  8d 99 82 86 a1 b7 15 04  f0 59 97 d7 50 61 1c a1  |.........Y..Pa..|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 17 3f 53  8d b3 35 b4 84 ed bb 12  |......?S..5.....|
-000000b0  cf 73 25 25 7c c3 d3 bb  1f 5a 6b 73 9a 8a b1 a2  |.s%%|....Zks....|
-000000c0  ba 99 f8 0e 43                                    |....C|
+000000a0  00 00 00 00 00 95 ed 23  80 9e f5 f2 37 ac 2d 50  |.......#....7.-P|
+000000b0  3d 30 de 68 be 25 c0 72  cc c9 2d 80 41 82 f7 0e  |=0.h.%.r..-.A...|
+000000c0  2e 86 0e 07 41                                    |....A|
index aacbb86705a07a1cbd5c6dddc62bff957d3c1cd0..0e480be437d7ee89530534176fa29b2e2c6cad96 100644 (file)
@@ -1,15 +1,15 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 9c 01 00 00  98 03 03 53 04 f0 f9 09  |...........S....|
-00000010  13 56 01 37 84 b1 32 59  4c 73 b1 8e bb 02 1a 32  |.V.7..2YLs.....2|
-00000020  db ab 8c e6 ed ad 7f 52  9a 59 39 00 00 04 c0 0a  |.......R.Y9.....|
-00000030  00 ff 01 00 00 6b 00 0b  00 04 03 00 01 02 00 0a  |.....k..........|
-00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
-00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
-00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
-00000070  00 0f 00 10 00 11 00 0d  00 22 00 20 06 01 06 02  |.........". ....|
-00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000090  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-000000a0  01                                                |.|
+00000000  16 03 01 00 a1 01 00 00  9d 03 03 eb 02 58 55 90  |.............XU.|
+00000010  a0 ba 80 52 28 a5 36 35  ee 6d eb e1 b0 d3 5d 89  |...R(.65.m....].|
+00000020  e8 2d a3 5e b1 83 e8 2f  00 f2 1e 00 00 04 c0 0a  |.-.^.../........|
+00000030  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
+00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
+00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
+00000060  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
+00000070  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0d 00  |................|
+00000080  20 00 1e 06 01 06 02 06  03 05 01 05 02 05 03 04  | ...............|
+00000090  01 04 02 04 03 03 01 03  02 03 03 02 01 02 02 02  |................|
+000000a0  03 00 0f 00 01 01                                 |......|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000210  0e bd 3f a3 8c 25 c1 33  13 83 0d 94 06 bb d4 37  |..?..%.3.......7|
 00000220  7a f6 ec 7a c9 86 2e dd  d7 11 69 7f 85 7c 56 de  |z..z......i..|V.|
 00000230  fb 31 78 2b e4 c7 78 0d  ae cb be 9e 4e 36 24 31  |.1x+..x.....N6$1|
-00000240  7b 6a 0f 39 95 12 07 8f  2a 16 03 03 00 d8 0c 00  |{j.9....*.......|
-00000250  00 d4 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
+00000240  7b 6a 0f 39 95 12 07 8f  2a 16 03 03 00 d7 0c 00  |{j.9....*.......|
+00000250  00 d3 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
 00000260  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
 00000270  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
 00000280  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
-00000290  41 03 56 6b dc 5a 89 04  03 00 8b 30 81 88 02 42  |A.Vk.Z.....0...B|
-000002a0  00 c6 85 8e 06 b7 04 04  e9 cd 9e 3e cb 66 23 95  |...........>.f#.|
-000002b0  b4 42 9c 64 81 39 05 3f  b5 21 f8 28 af 60 6b 4d  |.B.d.9.?.!.(.`kM|
-000002c0  3d ba a1 4b 5e 77 ef e7  59 28 fe 1d c1 27 a2 ff  |=..K^w..Y(...'..|
-000002d0  a8 de 33 48 b3 c1 85 6a  42 9b f9 7e 7e 31 c2 e5  |..3H...jB..~~1..|
-000002e0  bd 66 02 42 00 ad 7d 06  35 ab ec 8d ac d4 ba 1b  |.f.B..}.5.......|
-000002f0  49 5e 05 5f f0 97 93 82  b8 2b 8d 91 98 63 8e b4  |I^._.....+...c..|
-00000300  14 62 db 1e c9 2c 13 ae  b7 d3 17 38 23 2f f6 7f  |.b...,.....8#/..|
-00000310  0c 4d d3 33 d2 79 d1 77  ee cb b1 c2 fc 34 b8 69  |.M.3.y.w.....4.i|
-00000320  f9 10 8b 61 89 85 16 03  03 00 04 0e 00 00 00     |...a...........|
+00000290  41 03 56 6b dc 5a 89 04  03 00 8a 30 81 87 02 41  |A.Vk.Z.....0...A|
+000002a0  68 cb cd c0 12 5e 1e b3  cc d9 47 e7 b5 11 5e be  |h....^....G...^.|
+000002b0  74 5b 90 93 3f 4c 07 20  a1 94 50 bb 23 82 fc 5b  |t[..?L. ..P.#..[|
+000002c0  78 87 a3 a1 fe 7c 6f 84  93 8f b8 f7 2e 56 65 85  |x....|o......Ve.|
+000002d0  1d 9e 8e 52 b0 89 b0 a7  66 58 98 55 30 64 94 91  |...R....fX.U0d..|
+000002e0  8e 02 42 01 3d 74 eb a4  64 9e 7c 8b 05 57 5c f7  |..B.=t..d.|..W\.|
+000002f0  fe a7 58 f4 21 7b 75 ea  51 1e 1c be 80 4e 00 d1  |..X.!{u.Q....N..|
+00000300  06 80 58 90 c2 f3 47 da  22 8b a2 6b f0 2e 34 d0  |..X...G."..k..4.|
+00000310  1a 84 54 87 62 96 b9 2c  91 9f 3f 93 24 df 6c a3  |..T.b..,..?.$.l.|
+00000320  77 1f d2 e4 30 16 03 03  00 04 0e 00 00 00        |w...0.........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 dd 22 68 a1 4e  |....F...BA.."h.N|
-00000010  04 1b 47 f9 c5 7d 04 1d  d8 fe 84 fa be 31 2e a7  |..G..}.......1..|
-00000020  f8 e5 b8 14 92 44 99 11  0e 34 97 fc e5 b1 91 cf  |.....D...4......|
-00000030  a4 d1 3f b4 71 94 c6 06  16 f0 98 c0 3e 05 f9 2f  |..?.q.......>../|
-00000040  0a 97 78 3d ef dc fa a2  d7 ee 7d 14 03 03 00 01  |..x=......}.....|
-00000050  01 16 03 03 00 40 90 bf  7f e9 c9 6e d1 80 f5 12  |.....@.....n....|
-00000060  6d c5 b7 c5 15 4b 18 a5  d3 18 1e f8 8c 4d 7e 6d  |m....K.......M~m|
-00000070  03 60 29 7c 45 7c b2 ca  8c 07 71 70 aa 23 fa 6e  |.`)|E|....qp.#.n|
-00000080  d9 0b 0a 32 4c 9e e5 00  f9 19 9b b6 8d dc d3 67  |...2L..........g|
-00000090  3d 0f bb b8 4b 9e                                 |=...K.|
+00000000  16 03 03 00 46 10 00 00  42 41 04 04 12 72 83 8c  |....F...BA...r..|
+00000010  55 75 c4 34 48 5d d4 e3  9a 34 54 46 83 2f 69 36  |Uu.4H]...4TF./i6|
+00000020  e2 98 65 4d d2 b3 d4 6e  35 93 42 80 02 bd 26 a4  |..eM...n5.B...&.|
+00000030  ca 53 8d 50 c8 78 ec e3  0d 68 31 12 11 fe 76 52  |.S.P.x...h1...vR|
+00000040  0d 2f 63 76 43 74 5b 55  bd 9a 01 14 03 03 00 01  |./cvCt[U........|
+00000050  01 16 03 03 00 40 5f b8  b6 b9 cd 93 37 67 53 6f  |.....@_.....7gSo|
+00000060  cd 2d c6 c2 92 28 d6 ab  b7 31 ab 75 99 c8 83 7d  |.-...(...1.u...}|
+00000070  99 69 03 2d 52 6f ae 06  ec 34 05 fc 3b dd d0 0b  |.i.-Ro...4..;...|
+00000080  22 4a 84 cd 86 6c 11 10  3d 0d 9c 0f c8 c9 24 a6  |"J...l..=.....$.|
+00000090  f3 e6 e7 87 31 13                                 |....1.|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |..........@.....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 a1 6e e5 d1 ca  |............n...|
-00000020  03 f4 77 dc ec ee 5d f0  22 5e 7f 55 1a 8d ad 45  |..w...]."^.U...E|
-00000030  09 f1 3b b2 61 36 dc 3d  2a 1e 1f e5 a7 84 76 a9  |..;.a6.=*.....v.|
-00000040  41 5b 86 03 ac 22 18 20  9b a9 29 17 03 03 00 40  |A[...". ..)....@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 a9 71 da 7a 3d  |............q.z=|
+00000020  c1 17 da fa 05 ac ed a6  79 79 31 67 83 de 86 92  |........yy1g....|
+00000030  de 7e 6f 5c dc d7 e8 29  df 51 15 a1 6f 38 84 a5  |.~o\...).Q..o8..|
+00000040  a6 e4 f2 56 8a cc bf ad  f4 b8 0c 17 03 03 00 40  |...V...........@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  f5 cb 28 1e b5 bc 82 7f  82 38 54 14 e8 b9 6d 3b  |..(......8T...m;|
-00000070  bc 99 d6 0e f9 00 96 99  a8 92 2e 86 9d 62 4e 90  |.............bN.|
-00000080  27 52 58 45 20 93 90 a1  f3 a8 89 2b e7 21 24 16  |'RXE ......+.!$.|
+00000060  b1 a6 a1 eb f4 26 ef e9  25 7d c8 b5 a5 4b dc c8  |.....&..%}...K..|
+00000070  32 58 d6 c3 94 e7 f7 20  10 9e a1 db 10 db e4 42  |2X..... .......B|
+00000080  3c c5 26 e7 70 f2 d7 f0  38 10 a7 63 61 22 1b 57  |<.&.p...8..ca".W|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 a8 2a ab  8f b0 ce 49 8b fd a5 c9  |......*....I....|
-000000b0  11 b2 04 83 18 f3 1d 6c  82 34 1d df dd 2f 45 3b  |.......l.4.../E;|
-000000c0  27 8a 0f 16 69                                    |'...i|
+000000a0  00 00 00 00 00 29 ea 96  ea 08 88 6c 5d 67 91 f7  |.....).....l]g..|
+000000b0  31 8e b8 3a 9a d5 87 2a  81 2f 80 fb 7f b5 80 03  |1..:...*./......|
+000000c0  9c 8b 7e 39 7b                                    |..~9{|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
new file mode 100644 (file)
index 0000000..1c979c3
--- /dev/null
@@ -0,0 +1,92 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 9a 01 00 00  96 03 03 37 7c 30 6d df  |...........7|0m.|
+00000010  4d 94 90 04 59 df ec 01  11 77 29 b6 4f 95 50 ef  |M...Y....w).O.P.|
+00000020  ca d0 0f f4 a6 35 98 3b  ee 16 72 00 00 04 c0 30  |.....5.;..r....0|
+00000030  00 ff 01 00 00 69 00 0b  00 04 03 00 01 02 00 0a  |.....i..........|
+00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
+00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
+00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
+00000070  00 0f 00 10 00 11 00 0d  00 20 00 1e 06 01 06 02  |......... ......|
+00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000090  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 30 00 00  |.............0..|
+00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 cd 0c 00  |n8P)l...........|
+00000300  00 c9 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
+00000310  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
+00000320  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
+00000330  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
+00000340  41 03 56 6b dc 5a 89 04  01 00 80 4f 66 0e d5 7f  |A.Vk.Z.....Of...|
+00000350  a8 99 4d dc 5b a7 b0 32  67 b2 8a 2e ca 90 58 f0  |..M.[..2g.....X.|
+00000360  8d f1 fd 74 c1 3c 84 28  9d 25 7e 0a 61 f8 90 2d  |...t.<.(.%~.a..-|
+00000370  99 f3 90 c9 26 ab a7 d2  38 87 e1 2b 12 6e 93 17  |....&...8..+.n..|
+00000380  3c 2f 11 8c d8 67 73 11  68 b9 d0 a7 ad 44 83 72  |</...gs.h....D.r|
+00000390  fc e4 6b ce 7f 02 7e 33  89 4b f3 dc 30 42 c0 4b  |..k...~3.K..0B.K|
+000003a0  2b 29 eb e6 1c 43 bb a7  27 b9 3e f4 76 ec 69 4d  |+)...C..'.>.v.iM|
+000003b0  df 49 d4 f6 b4 ac f6 0b  1d d1 68 61 30 b1 52 07  |.I........ha0.R.|
+000003c0  a5 6d 31 5e 13 24 8c 32  cd 76 57 16 03 03 00 04  |.m1^.$.2.vW.....|
+000003d0  0e 00 00 00                                       |....|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 08 73 d7 79 87  |....F...BA..s.y.|
+00000010  39 45 dd 69 33 71 a0 48  a0 8b 6e 2f 99 dc a1 4f  |9E.i3q.H..n/...O|
+00000020  21 ca 70 b3 98 fe cc 5a  94 04 1b 8d 4d a4 46 24  |!.p....Z....M.F$|
+00000030  c6 61 bd e1 49 92 83 8d  ea 22 fb b1 43 90 24 7e  |.a..I...."..C.$~|
+00000040  d0 e5 4b cb c3 8a 41 f7  fd d1 9f 14 03 03 00 01  |..K...A.........|
+00000050  01 16 03 03 00 28 e3 99  f0 d3 65 4e 29 dd d6 eb  |.....(....eN)...|
+00000060  c0 b3 f9 e2 8b bb 68 61  b2 7f 63 db de fb ae d2  |......ha..c.....|
+00000070  94 b7 45 9b 34 cb a4 26  3f 04 92 34 02 89        |..E.4..&?..4..|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 00 00 00 00 00  |..........(.....|
+00000010  00 00 00 5e 63 30 5d 4d  2b 87 3f 7b 9c 06 2e 44  |...^c0]M+.?{...D|
+00000020  92 c5 d0 e8 07 fa 9f db  a7 2c dc ec 16 78 bd 37  |.........,...x.7|
+00000030  8a f7 24 17 03 03 00 25  00 00 00 00 00 00 00 01  |..$....%........|
+00000040  0b af 29 75 f0 67 6b 78  8c 3a 65 44 53 25 9e d5  |..)u.gkx.:eDS%..|
+00000050  8e 7e 24 5f c9 95 a1 3e  63 d2 52 09 32 15 03 03  |.~$_...>c.R.2...|
+00000060  00 1a 00 00 00 00 00 00  00 02 0b f2 f7 93 57 b3  |..............W.|
+00000070  5b 19 fd e7 a1 0f e9 41  ca f5 74 17              |[......A..t.|
index 0589264b54ea9d9de4819d674be1bdb240297eba..5add4e5d3e0d0d5aab1a6be905fd2f6a68383bf6 100644 (file)
@@ -46,14 +46,17 @@ type Extension struct {
 }
 
 // Name represents an X.509 distinguished name. This only includes the common
-// elements of a DN.  Additional elements in the name are ignored.
+// elements of a DN. When parsing, all elements are stored in Names and
+// non-standard elements can be extracted from there. When marshaling, elements
+// in ExtraNames are appended and override other values with the same OID.
 type Name struct {
        Country, Organization, OrganizationalUnit []string
        Locality, Province                        []string
        StreetAddress, PostalCode                 []string
        SerialNumber, CommonName                  string
 
-       Names []AttributeTypeAndValue
+       Names      []AttributeTypeAndValue
+       ExtraNames []AttributeTypeAndValue
 }
 
 func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
@@ -110,8 +113,8 @@ var (
 // and returns the new value. The relativeDistinguishedNameSET contains an
 // attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
 // search for AttributeTypeAndValue.
-func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
-       if len(values) == 0 {
+func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
+       if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) {
                return in
        }
 
@@ -125,23 +128,37 @@ func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNS
 }
 
 func (n Name) ToRDNSequence() (ret RDNSequence) {
-       ret = appendRDNs(ret, n.Country, oidCountry)
-       ret = appendRDNs(ret, n.Organization, oidOrganization)
-       ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
-       ret = appendRDNs(ret, n.Locality, oidLocality)
-       ret = appendRDNs(ret, n.Province, oidProvince)
-       ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
-       ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
+       ret = n.appendRDNs(ret, n.Country, oidCountry)
+       ret = n.appendRDNs(ret, n.Organization, oidOrganization)
+       ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+       ret = n.appendRDNs(ret, n.Locality, oidLocality)
+       ret = n.appendRDNs(ret, n.Province, oidProvince)
+       ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+       ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode)
        if len(n.CommonName) > 0 {
-               ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
+               ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName)
        }
        if len(n.SerialNumber) > 0 {
-               ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
+               ret = n.appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
+       }
+       for _, atv := range n.ExtraNames {
+               ret = append(ret, []AttributeTypeAndValue{atv})
        }
 
        return ret
 }
 
+// oidInAttributeTypeAndValue returns whether a type with the given OID exists
+// in atv.
+func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool {
+       for _, a := range atv {
+               if a.Type.Equal(oid) {
+                       return true
+               }
+       }
+       return false
+}
+
 // CertificateList represents the ASN.1 structure of the same name. See RFC
 // 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
 // signature.
index fd5b8da1cf975b66c076c31d47720b788d5e524c..be61fd5607f67aaa76d3551ad90df7372c89eddc 100644 (file)
@@ -12,7 +12,7 @@ import (
        "crypto/ecdsa"
        "crypto/elliptic"
        "crypto/rsa"
-       "crypto/sha1"
+       "crypto/sha1"
        _ "crypto/sha256"
        _ "crypto/sha512"
        "crypto/x509/pkix"
@@ -1389,14 +1389,14 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
        return asn1.Marshal(cert.Subject.ToRDNSequence())
 }
 
-// signingParamsForPrivateKey returns the parameters to use for signing with
+// signingParamsForPublicKey returns the parameters to use for signing with
 // priv. If requestedSigAlgo is not zero then it overrides the default
 // signature algorithm.
-func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
        var pubType PublicKeyAlgorithm
 
-       switch priv := priv.(type) {
-       case *rsa.PrivateKey:
+       switch pub := pub.(type) {
+       case *rsa.PublicKey:
                pubType = RSA
                hashFunc = crypto.SHA256
                sigAlgo.Algorithm = oidSignatureSHA256WithRSA
@@ -1404,10 +1404,10 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
                        Tag: 5,
                }
 
-       case *ecdsa.PrivateKey:
+       case *ecdsa.PublicKey:
                pubType = ECDSA
 
-               switch priv.Curve {
+               switch pub.Curve {
                case elliptic.P224(), elliptic.P256():
                        hashFunc = crypto.SHA256
                        sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
@@ -1422,7 +1422,7 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
                }
 
        default:
-               err = errors.New("x509: only RSA and ECDSA private keys supported")
+               err = errors.New("x509: only RSA and ECDSA keys supported")
        }
 
        if err != nil {
@@ -1469,21 +1469,22 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
 //
 // The returned slice is the certificate in DER encoding.
 //
-// The only supported key types are RSA and ECDSA (*rsa.PublicKey or
-// *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PrivateKey for priv).
-func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) {
-       hashFunc, signatureAlgorithm, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
-       if err != nil {
-               return nil, err
+// All keys types that are implemented via crypto.Signer are supported (This
+// includes *rsa.PublicKey and *ecdsa.PublicKey.)
+func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
+       key, ok := priv.(crypto.Signer)
+       if !ok {
+               return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
        }
 
-       publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
+       hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
        if err != nil {
                return nil, err
        }
 
+       publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
        if err != nil {
-               return
+               return nil, err
        }
 
        if len(parent.SubjectKeyId) > 0 {
@@ -1529,30 +1530,17 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf
        digest := h.Sum(nil)
 
        var signature []byte
-
-       switch priv := priv.(type) {
-       case *rsa.PrivateKey:
-               signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest)
-       case *ecdsa.PrivateKey:
-               var r, s *big.Int
-               if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil {
-                       signature, err = asn1.Marshal(ecdsaSignature{r, s})
-               }
-       default:
-               panic("internal error")
-       }
-
+       signature, err = key.Sign(rand, digest, hashFunc)
        if err != nil {
                return
        }
 
-       cert, err = asn1.Marshal(certificate{
+       return asn1.Marshal(certificate{
                nil,
                c,
                signatureAlgorithm,
                asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
        })
-       return
 }
 
 // pemCRLPrefix is the magic string that indicates that we have a PEM encoded
@@ -1588,44 +1576,56 @@ func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
 
 // CreateCRL returns a DER encoded CRL, signed by this Certificate, that
 // contains the given list of revoked certificates.
-//
-// The only supported key type is RSA (*rsa.PrivateKey for priv).
 func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
-       rsaPriv, ok := priv.(*rsa.PrivateKey)
+       key, ok := priv.(crypto.Signer)
        if !ok {
-               return nil, errors.New("x509: non-RSA private keys not supported")
+               return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
        }
+
+       hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0)
+       if err != nil {
+               return nil, err
+       }
+
        tbsCertList := pkix.TBSCertificateList{
-               Version: 1,
-               Signature: pkix.AlgorithmIdentifier{
-                       Algorithm: oidSignatureSHA1WithRSA,
-               },
+               Version:             1,
+               Signature:           signatureAlgorithm,
                Issuer:              c.Subject.ToRDNSequence(),
                ThisUpdate:          now.UTC(),
                NextUpdate:          expiry.UTC(),
                RevokedCertificates: revokedCerts,
        }
 
+       // Authority Key Id
+       if len(c.SubjectKeyId) > 0 {
+               var aki pkix.Extension
+               aki.Id = oidExtensionAuthorityKeyId
+               aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId})
+               if err != nil {
+                       return
+               }
+               tbsCertList.Extensions = append(tbsCertList.Extensions, aki)
+       }
+
        tbsCertListContents, err := asn1.Marshal(tbsCertList)
        if err != nil {
                return
        }
 
-       h := sha1.New()
+       h := hashFunc.New()
        h.Write(tbsCertListContents)
        digest := h.Sum(nil)
 
-       signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest)
+       var signature []byte
+       signature, err = key.Sign(rand, digest, hashFunc)
        if err != nil {
                return
        }
 
        return asn1.Marshal(pkix.CertificateList{
-               TBSCertList: tbsCertList,
-               SignatureAlgorithm: pkix.AlgorithmIdentifier{
-                       Algorithm: oidSignatureSHA1WithRSA,
-               },
-               SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+               TBSCertList:        tbsCertList,
+               SignatureAlgorithm: signatureAlgorithm,
+               SignatureValue:     asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
        })
 }
 
@@ -1699,26 +1699,24 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
 //
 // The returned slice is the certificate request in DER encoding.
 //
-// The only supported key types are RSA (*rsa.PrivateKey) and ECDSA
-// (*ecdsa.PrivateKey).
+// All keys types that are implemented via crypto.Signer are supported (This
+// includes *rsa.PublicKey and *ecdsa.PublicKey.)
 func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) {
-       hashFunc, sigAlgo, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
+       key, ok := priv.(crypto.Signer)
+       if !ok {
+               return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+       }
+
+       var hashFunc crypto.Hash
+       var sigAlgo pkix.AlgorithmIdentifier
+       hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
        if err != nil {
                return nil, err
        }
 
        var publicKeyBytes []byte
        var publicKeyAlgorithm pkix.AlgorithmIdentifier
-
-       switch priv := priv.(type) {
-       case *rsa.PrivateKey:
-               publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey)
-       case *ecdsa.PrivateKey:
-               publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey)
-       default:
-               panic("internal error")
-       }
-
+       publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public())
        if err != nil {
                return nil, err
        }
@@ -1830,18 +1828,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
        digest := h.Sum(nil)
 
        var signature []byte
-       switch priv := priv.(type) {
-       case *rsa.PrivateKey:
-               signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest)
-       case *ecdsa.PrivateKey:
-               var r, s *big.Int
-               if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil {
-                       signature, err = asn1.Marshal(ecdsaSignature{r, s})
-               }
-       default:
-               panic("internal error")
-       }
-
+       signature, err = key.Sign(rand, digest, hashFunc)
        if err != nil {
                return
        }
index f275375ba76e6ff7b5b6148f22090daceb954697..bd7cbed8a27848621cbe3bf664a65e4b7626cf54 100644 (file)
@@ -326,6 +326,18 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
                        Subject: pkix.Name{
                                CommonName:   commonName,
                                Organization: []string{"Σ Acme Co"},
+                               Country:      []string{"US"},
+                               ExtraNames: []pkix.AttributeTypeAndValue{
+                                       {
+                                               Type:  []int{2, 5, 4, 42},
+                                               Value: "Gopher",
+                                       },
+                                       // This should override the Country, above.
+                                       {
+                                               Type:  []int{2, 5, 4, 6},
+                                               Value: "NL",
+                                       },
+                               },
                        },
                        NotBefore: time.Unix(1000, 0),
                        NotAfter:  time.Unix(100000, 0),
@@ -391,6 +403,21 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
                        t.Errorf("%s: subject wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Subject.CommonName, commonName)
                }
 
+               if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "NL" {
+                       t.Errorf("%s: ExtraNames didn't override Country", test.name)
+               }
+
+               found := false
+               for _, atv := range cert.Subject.Names {
+                       if atv.Type.Equal([]int{2, 5, 4, 42}) {
+                               found = true
+                               break
+                       }
+               }
+               if !found {
+                       t.Errorf("%s: Names didn't contain oid 2.5.4.42 from ExtraNames", test.name)
+               }
+
                if cert.Issuer.CommonName != commonName {
                        t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName)
                }
index 8db9c785713a33eb8bc84ec02e5dfcd223a6f615..1ce679d8a6edea29acfb268653799c2b03b89229 100644 (file)
@@ -20,6 +20,7 @@ import (
        "runtime"
        "sort"
        "sync"
+       "sync/atomic"
 )
 
 var drivers = make(map[string]driver.Driver)
@@ -211,6 +212,10 @@ var ErrNoRows = errors.New("sql: no rows in result set")
 type DB struct {
        driver driver.Driver
        dsn    string
+       // numClosed is an atomic counter which represents a total number of
+       // closed connections. Stmt.openStmt checks it before cleaning closed
+       // connections in Stmt.css.
+       numClosed uint64
 
        mu           sync.Mutex // protects following fields
        freeConn     []*driverConn
@@ -246,7 +251,7 @@ type driverConn struct {
        // guarded by db.mu
        inUse      bool
        onPut      []func() // code (with db.mu held) run when conn is next returned
-       dbmuClosed bool     // same as closed, but guarded by db.mu, for connIfFree
+       dbmuClosed bool     // same as closed, but guarded by db.mu, for removeClosedStmtLocked
 }
 
 func (dc *driverConn) releaseConn(err error) {
@@ -329,6 +334,7 @@ func (dc *driverConn) finalClose() error {
        dc.db.maybeOpenNewConnections()
        dc.db.mu.Unlock()
 
+       atomic.AddUint64(&dc.db.numClosed, 1)
        return err
 }
 
@@ -683,42 +689,6 @@ var (
        errConnBusy   = errors.New("database/sql: internal sentinel error: conn is busy")
 )
 
-// connIfFree returns (wanted, nil) if wanted is still a valid conn and
-// isn't in use.
-//
-// The error is errConnClosed if the connection if the requested connection
-// is invalid because it's been closed.
-//
-// The error is errConnBusy if the connection is in use.
-func (db *DB) connIfFree(wanted *driverConn) (*driverConn, error) {
-       db.mu.Lock()
-       defer db.mu.Unlock()
-       if wanted.dbmuClosed {
-               return nil, errConnClosed
-       }
-       if wanted.inUse {
-               return nil, errConnBusy
-       }
-       idx := -1
-       for ii, v := range db.freeConn {
-               if v == wanted {
-                       idx = ii
-                       break
-               }
-       }
-       if idx >= 0 {
-               db.freeConn = append(db.freeConn[:idx], db.freeConn[idx+1:]...)
-               wanted.inUse = true
-               return wanted, nil
-       }
-       // TODO(bradfitz): shouldn't get here. After Go 1.1, change this to:
-       // panic("connIfFree call requested a non-closed, non-busy, non-free conn")
-       // Which passes all the tests, but I'm too paranoid to include this
-       // late in Go 1.1.
-       // Instead, treat it like a busy connection:
-       return nil, errConnBusy
-}
-
 // putConnHook is a hook for testing.
 var putConnHook func(*DB, *driverConn)
 
@@ -856,9 +826,10 @@ func (db *DB) prepare(query string) (*Stmt, error) {
                return nil, err
        }
        stmt := &Stmt{
-               db:    db,
-               query: query,
-               css:   []connStmt{{dc, si}},
+               db:            db,
+               query:         query,
+               css:           []connStmt{{dc, si}},
+               lastNumClosed: atomic.LoadUint64(&db.numClosed),
        }
        db.addDep(stmt, stmt)
        db.putConn(dc, nil)
@@ -1293,6 +1264,10 @@ type Stmt struct {
        // used if tx == nil and one is found that has idle
        // connections.  If tx != nil, txsi is always used.
        css []connStmt
+
+       // lastNumClosed is copied from db.numClosed when Stmt is created
+       // without tx and closed connections in css are removed.
+       lastNumClosed uint64
 }
 
 // Exec executes a prepared statement with the given arguments and
@@ -1346,6 +1321,32 @@ func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
        return driverResult{ds.Locker, resi}, nil
 }
 
+// removeClosedStmtLocked removes closed conns in s.css.
+//
+// To avoid lock contention on DB.mu, we do it only when
+// s.db.numClosed - s.lastNum is large enough.
+func (s *Stmt) removeClosedStmtLocked() {
+       t := len(s.css)/2 + 1
+       if t > 10 {
+               t = 10
+       }
+       dbClosed := atomic.LoadUint64(&s.db.numClosed)
+       if dbClosed-s.lastNumClosed < uint64(t) {
+               return
+       }
+
+       s.db.mu.Lock()
+       for i := 0; i < len(s.css); i++ {
+               if s.css[i].dc.dbmuClosed {
+                       s.css[i] = s.css[len(s.css)-1]
+                       s.css = s.css[:len(s.css)-1]
+                       i--
+               }
+       }
+       s.db.mu.Unlock()
+       s.lastNumClosed = dbClosed
+}
+
 // connStmt returns a free driver connection on which to execute the
 // statement, a function to call to release the connection, and a
 // statement bound to that connection.
@@ -1372,35 +1373,15 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
                return ci, releaseConn, s.txsi.si, nil
        }
 
-       for i := 0; i < len(s.css); i++ {
-               v := s.css[i]
-               _, err := s.db.connIfFree(v.dc)
-               if err == nil {
-                       s.mu.Unlock()
-                       return v.dc, v.dc.releaseConn, v.si, nil
-               }
-               if err == errConnClosed {
-                       // Lazily remove dead conn from our freelist.
-                       s.css[i] = s.css[len(s.css)-1]
-                       s.css = s.css[:len(s.css)-1]
-                       i--
-               }
-
-       }
+       s.removeClosedStmtLocked()
        s.mu.Unlock()
 
-       // If all connections are busy, either wait for one to become available (if
-       // we've already hit the maximum number of open connections) or create a
-       // new one.
-       //
        // TODO(bradfitz): or always wait for one? make configurable later?
        dc, err := s.db.conn()
        if err != nil {
                return nil, nil, nil, err
        }
 
-       // Do another pass over the list to see whether this statement has
-       // already been prepared on the connection assigned to us.
        s.mu.Lock()
        for _, v := range s.css {
                if v.dc == dc {
index 34efdf254c65309f9ea0c48a6921ff2a9add9f97..60bdefa07625f5c4431cbe096c0768e0c3f29a89 100644 (file)
@@ -1764,56 +1764,6 @@ func doConcurrentTest(t testing.TB, ct concurrentTest) {
        wg.Wait()
 }
 
-func manyConcurrentQueries(t testing.TB) {
-       maxProcs, numReqs := 16, 500
-       if testing.Short() {
-               maxProcs, numReqs = 4, 50
-       }
-       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
-
-       db := newTestDB(t, "people")
-       defer closeDB(t, db)
-
-       stmt, err := db.Prepare("SELECT|people|name|")
-       if err != nil {
-               t.Fatal(err)
-       }
-       defer stmt.Close()
-
-       var wg sync.WaitGroup
-       wg.Add(numReqs)
-
-       reqs := make(chan bool)
-       defer close(reqs)
-
-       for i := 0; i < maxProcs*2; i++ {
-               go func() {
-                       for range reqs {
-                               rows, err := stmt.Query()
-                               if err != nil {
-                                       t.Errorf("error on query:  %v", err)
-                                       wg.Done()
-                                       continue
-                               }
-
-                               var name string
-                               for rows.Next() {
-                                       rows.Scan(&name)
-                               }
-                               rows.Close()
-
-                               wg.Done()
-                       }
-               }()
-       }
-
-       for i := 0; i < numReqs; i++ {
-               reqs <- true
-       }
-
-       wg.Wait()
-}
-
 func TestIssue6081(t *testing.T) {
        db := newTestDB(t, "people")
        defer closeDB(t, db)
@@ -1985,3 +1935,31 @@ func BenchmarkConcurrentRandom(b *testing.B) {
                doConcurrentTest(b, ct)
        }
 }
+
+func BenchmarkManyConcurrentQueries(b *testing.B) {
+       b.ReportAllocs()
+       // To see lock contention in Go 1.4, 16~ cores and 128~ goroutines are required.
+       const parallelism = 16
+
+       db := newTestDB(b, "magicquery")
+       defer closeDB(b, db)
+       db.SetMaxIdleConns(runtime.GOMAXPROCS(0) * parallelism)
+
+       stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
+       if err != nil {
+               b.Fatal(err)
+       }
+       defer stmt.Close()
+
+       b.SetParallelism(parallelism)
+       b.RunParallel(func(pb *testing.PB) {
+               for pb.Next() {
+                       rows, err := stmt.Query("sleep", 1)
+                       if err != nil {
+                               b.Error(err)
+                               return
+                       }
+                       rows.Close()
+               }
+       })
+}
index 212365cede65da42c19ffc8572b44f73eb067cbf..f26a7d49f00f98b23b1266e826216857dd436ac3 100644 (file)
@@ -90,8 +90,9 @@ type Unmarshaler interface {
 // An UnmarshalTypeError describes a JSON value that was
 // not appropriate for a value of a specific Go type.
 type UnmarshalTypeError struct {
-       Value string       // description of JSON value - "bool", "array", "number -5"
-       Type  reflect.Type // type of Go value it could not be assigned to
+       Value  string       // description of JSON value - "bool", "array", "number -5"
+       Type   reflect.Type // type of Go value it could not be assigned to
+       Offset int64        // error occurred after reading Offset bytes
 }
 
 func (e *UnmarshalTypeError) Error() string {
@@ -377,7 +378,7 @@ func (d *decodeState) array(v reflect.Value) {
                return
        }
        if ut != nil {
-               d.saveError(&UnmarshalTypeError{"array", v.Type()})
+               d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
                d.off--
                d.next()
                return
@@ -396,7 +397,7 @@ func (d *decodeState) array(v reflect.Value) {
                // Otherwise it's invalid.
                fallthrough
        default:
-               d.saveError(&UnmarshalTypeError{"array", v.Type()})
+               d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
                d.off--
                d.next()
                return
@@ -485,7 +486,7 @@ func (d *decodeState) object(v reflect.Value) {
                return
        }
        if ut != nil {
-               d.saveError(&UnmarshalTypeError{"object", v.Type()})
+               d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
                d.off--
                d.next() // skip over { } in input
                return
@@ -504,7 +505,7 @@ func (d *decodeState) object(v reflect.Value) {
                // map must have string kind
                t := v.Type()
                if t.Key().Kind() != reflect.String {
-                       d.saveError(&UnmarshalTypeError{"object", v.Type()})
+                       d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
                        d.off--
                        d.next() // skip over { } in input
                        return
@@ -515,7 +516,7 @@ func (d *decodeState) object(v reflect.Value) {
        case reflect.Struct:
 
        default:
-               d.saveError(&UnmarshalTypeError{"object", v.Type()})
+               d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
                d.off--
                d.next() // skip over { } in input
                return
@@ -646,7 +647,7 @@ func (d *decodeState) convertNumber(s string) (interface{}, error) {
        }
        f, err := strconv.ParseFloat(s, 64)
        if err != nil {
-               return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0)}
+               return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)}
        }
        return f, nil
 }
@@ -679,7 +680,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                        if fromQuoted {
                                d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
                        } else {
-                               d.saveError(&UnmarshalTypeError{"string", v.Type()})
+                               d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
                        }
                }
                s, ok := unquoteBytes(item)
@@ -713,7 +714,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                        if fromQuoted {
                                d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
                        } else {
-                               d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+                               d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
                        }
                case reflect.Bool:
                        v.SetBool(value)
@@ -721,7 +722,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                        if v.NumMethod() == 0 {
                                v.Set(reflect.ValueOf(value))
                        } else {
-                               d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+                               d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
                        }
                }
 
@@ -736,10 +737,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                }
                switch v.Kind() {
                default:
-                       d.saveError(&UnmarshalTypeError{"string", v.Type()})
+                       d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
                case reflect.Slice:
                        if v.Type() != byteSliceType {
-                               d.saveError(&UnmarshalTypeError{"string", v.Type()})
+                               d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
                                break
                        }
                        b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
@@ -755,7 +756,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                        if v.NumMethod() == 0 {
                                v.Set(reflect.ValueOf(string(s)))
                        } else {
-                               d.saveError(&UnmarshalTypeError{"string", v.Type()})
+                               d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
                        }
                }
 
@@ -777,7 +778,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                        if fromQuoted {
                                d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
                        } else {
-                               d.error(&UnmarshalTypeError{"number", v.Type()})
+                               d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
                        }
                case reflect.Interface:
                        n, err := d.convertNumber(s)
@@ -786,7 +787,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                                break
                        }
                        if v.NumMethod() != 0 {
-                               d.saveError(&UnmarshalTypeError{"number", v.Type()})
+                               d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
                                break
                        }
                        v.Set(reflect.ValueOf(n))
@@ -794,7 +795,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
                        n, err := strconv.ParseInt(s, 10, 64)
                        if err != nil || v.OverflowInt(n) {
-                               d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+                               d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
                                break
                        }
                        v.SetInt(n)
@@ -802,7 +803,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
                        n, err := strconv.ParseUint(s, 10, 64)
                        if err != nil || v.OverflowUint(n) {
-                               d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+                               d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
                                break
                        }
                        v.SetUint(n)
@@ -810,7 +811,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                case reflect.Float32, reflect.Float64:
                        n, err := strconv.ParseFloat(s, v.Type().Bits())
                        if err != nil || v.OverflowFloat(n) {
-                               d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+                               d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
                                break
                        }
                        v.SetFloat(n)
index 83b9d39ad672f538c24467bfd4be63d96b0d7427..7ecc8f440225396b2e35df818c4e45d5523f9718 100644 (file)
@@ -231,7 +231,7 @@ var unmarshalTests = []unmarshalTest{
        {in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
        {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
        {in: "null", ptr: new(interface{}), out: nil},
-       {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf("")}},
+       {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}},
        {in: `{"x": 1}`, ptr: new(tx), out: tx{}},
        {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
        {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
@@ -411,7 +411,7 @@ var unmarshalTests = []unmarshalTest{
        {
                in:  `{"2009-11-10T23:00:00Z": "hello world"}`,
                ptr: &map[time.Time]string{},
-               err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{})},
+               err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{}), 1},
        },
 }
 
index 9b6dab487cb6209e9b3e407dce9f90ce23bca372..2cb515a6784567621a922443f7dcda5bd3cf3b69 100644 (file)
@@ -32,6 +32,7 @@ import (
        "sort"
        "strconv"
        "sync"
+       "sync/atomic"
 )
 
 // Var is an abstract type for all exported variables.
@@ -41,26 +42,19 @@ type Var interface {
 
 // Int is a 64-bit integer variable that satisfies the Var interface.
 type Int struct {
-       mu sync.RWMutex
-       i  int64
+       i int64
 }
 
 func (v *Int) String() string {
-       v.mu.RLock()
-       defer v.mu.RUnlock()
-       return strconv.FormatInt(v.i, 10)
+       return strconv.FormatInt(atomic.LoadInt64(&v.i), 10)
 }
 
 func (v *Int) Add(delta int64) {
-       v.mu.Lock()
-       defer v.mu.Unlock()
-       v.i += delta
+       atomic.AddInt64(&v.i, delta)
 }
 
 func (v *Int) Set(value int64) {
-       v.mu.Lock()
-       defer v.mu.Unlock()
-       v.i = value
+       atomic.StoreInt64(&v.i, value)
 }
 
 // Float is a 64-bit float variable that satisfies the Var interface.
index c933e849fe20cc70f17b4b699443b7ab051a428e..d7161c291ded3fac5e82d47b9adfb0a719b97955 100644 (file)
@@ -869,6 +869,15 @@ func BenchmarkFprintInt(b *testing.B) {
        }
 }
 
+func BenchmarkFprintfBytes(b *testing.B) {
+       data := []byte(string("0123456789"))
+       var buf bytes.Buffer
+       for i := 0; i < b.N; i++ {
+               buf.Reset()
+               Fprintf(&buf, "%s", data)
+       }
+}
+
 func BenchmarkFprintIntNoAlloc(b *testing.B) {
        var x interface{} = 123456
        var buf bytes.Buffer
index fc3eeb4a1db73d5c9c5b42f0688df43cd9746596..50e576ec044393635a25ee18c41cfb3a539ab087 100644 (file)
@@ -221,8 +221,8 @@ func filterDecl(decl Decl, f Filter, export bool) bool {
 // names from top-level declarations (including struct field and
 // interface method names, but not from parameter lists) that don't
 // pass through the filter f. If the declaration is empty afterwards,
-// the declaration is removed from the AST. The File.Comments list
-// is not changed.
+// the declaration is removed from the AST. Import declarations are
+// always removed. The File.Comments list is not changed.
 //
 // FilterFile returns true if there are any top-level declarations
 // left after filtering; it returns false otherwise.
index 06789bc1081289b7c2bfcbeebe9cf3e7b279d8b4..6aa38f15287e05415b515834189c5bf8e0bbd155 100644 (file)
@@ -12,13 +12,12 @@ import (
 )
 
 // filterIdentList removes unexported names from list in place
-// and returns the resulting list. If blankOk is set, blank
-// identifiers are considered exported names.
+// and returns the resulting list.
 //
-func filterIdentList(list []*ast.Ident, blankOk bool) []*ast.Ident {
+func filterIdentList(list []*ast.Ident) []*ast.Ident {
        j := 0
        for _, x := range list {
-               if ast.IsExported(x.Name) || (blankOk && x.Name == "_") {
+               if ast.IsExported(x.Name) {
                        list[j] = x
                        j++
                }
@@ -26,11 +25,11 @@ func filterIdentList(list []*ast.Ident, blankOk bool) []*ast.Ident {
        return list[0:j]
 }
 
-// hasExportedOrBlankName reports whether list contains any exported or blank names.
+// hasExportedName reports whether list contains any exported names.
 //
-func hasExportedOrBlankName(list []*ast.Ident) bool {
+func hasExportedName(list []*ast.Ident) bool {
        for _, x := range list {
-               if x.IsExported() || x.Name == "_" {
+               if x.IsExported() {
                        return true
                }
        }
@@ -89,7 +88,7 @@ func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp
                                r.remember(ityp)
                        }
                } else {
-                       field.Names = filterIdentList(field.Names, false)
+                       field.Names = filterIdentList(field.Names)
                        if len(field.Names) < n {
                                removedFields = true
                        }
@@ -157,9 +156,7 @@ func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool {
                // always keep imports so we can collect them
                return true
        case *ast.ValueSpec:
-               // special case: consider blank constants as exported
-               // (work-around for issue 5397)
-               s.Names = filterIdentList(s.Names, tok == token.CONST)
+               s.Names = filterIdentList(s.Names)
                if len(s.Names) > 0 {
                        r.filterType(nil, s.Type)
                        return true
@@ -207,9 +204,8 @@ func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec {
                                // provide current spec with an explicit type
                                spec.Type = copyConstType(prevType, spec.Pos())
                        }
-                       if hasExportedOrBlankName(spec.Names) {
-                               // both exported and blank names are preserved
-                               // so there's no need to propagate the type
+                       if hasExportedName(spec.Names) {
+                               // exported names are preserved so there's no need to propagate the type
                                prevType = nil
                        } else {
                                prevType = spec.Type
index 5f34038426b9fd933229abf5b90ed083c065ca64..c2987cf140ec4dfa0a9e78e647b698f52c38f75c 100644 (file)
@@ -30,8 +30,7 @@ CONSTANTS
 
        // Package constants. 
        const (
-               _       int     = iota
-               I1
+               I1      int
                I2
        )
 
@@ -50,8 +49,7 @@ TYPES
 
        // T constants counting from a blank constant. 
        const (
-               _       T       = iota
-               T1
+               T1      T
                T2
        )
 
index af5328fbb6904aa5eea872e14ced6baeedd3cb20..ee5054a4ed616f73169eadfe5741a06012d9b242 100644 (file)
@@ -38,6 +38,12 @@ CONSTANTS
                WideOpen                        = 0777
        )
 
+       // Unexported constants counting from blank iota. See issue 9615. 
+       const (
+               _       = iota
+               one     = iota + 1
+       )
+
 
 VARIABLES
        // 
index 5f34038426b9fd933229abf5b90ed083c065ca64..c2987cf140ec4dfa0a9e78e647b698f52c38f75c 100644 (file)
@@ -30,8 +30,7 @@ CONSTANTS
 
        // Package constants. 
        const (
-               _       int     = iota
-               I1
+               I1      int
                I2
        )
 
@@ -50,8 +49,7 @@ TYPES
 
        // T constants counting from a blank constant. 
        const (
-               _       T       = iota
-               T1
+               T1      T
                T2
        )
 
index 83e42ed39fa9cd509b06b95408d6dbcc671b7a8f..419a78f7d5116f0779f3f9d2381fe771ba3cbac7 100644 (file)
@@ -44,6 +44,13 @@ const (
        I2
 )
 
+// Unexported constants counting from blank iota.
+// See issue 9615.
+const (
+       _   = iota
+       one = iota + 1
+)
+
 // Blanks not in doc output:
 
 // S has a padding field.
index c9dbd06ad24114497ae44f06b6e4d3b4d9276169..0409122c81787dcd1d8df2c95255f7e1f99b0bf0 100644 (file)
@@ -2228,6 +2228,7 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota
                defer un(trace(p, keyword.String()+"Spec"))
        }
 
+       pos := p.pos
        idents := p.parseIdentList()
        typ := p.tryType()
        var values []ast.Expr
@@ -2238,6 +2239,17 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota
        }
        p.expectSemi() // call before accessing p.linecomment
 
+       switch keyword {
+       case token.VAR:
+               if typ == nil && values == nil {
+                       p.error(pos, "missing variable type or initialization")
+               }
+       case token.CONST:
+               if values == nil && (iota == 0 || typ != nil) {
+                       p.error(pos, "missing constant value")
+               }
+       }
+
        // Go spec: The scope of a constant or variable identifier declared inside
        // a function begins at the end of the ConstSpec or VarSpec and ends at
        // the end of the innermost containing block.
index 7d12170c0e43ab3b0623130c86109bad6b78c5fd..14a14d5a5928b1b02d7c57b91ec2959655a60b3e 100644 (file)
@@ -43,6 +43,7 @@ var valids = []string{
        `package p; func _() { map[int]int{}[0]++; map[int]int{}[0] += 1 }`,
        `package p; func _(x interface{f()}) { interface{f()}(x).f() }`,
        `package p; func _(x chan int) { chan int(x) <- 0 }`,
+       `package p; const (x = 0; y; z)`, // issue 9639
 }
 
 func TestValid(t *testing.T) {
@@ -97,7 +98,11 @@ var invalids = []string{
        `package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`,
        `package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`,
        `package p; func f() { go func() { func() { f(x func /* ERROR "expected '\)'" */ (){}) } } }`,
-       `package p; func f() (a b string /* ERROR "expected '\)'" */ , ok bool) // issue 8656`,
+       `package p; func f() (a b string /* ERROR "expected '\)'" */ , ok bool)`,         // issue 8656
+       `package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`, // issue 9639
+       `package p; const x /* ERROR "missing constant value" */ ;`,                      // issue 9639
+       `package p; const x /* ERROR "missing constant value" */ int;`,                   // issue 9639
+       `package p; const (x = 0; y; z /* ERROR "missing constant value" */ int);`,       // issue 9639
 }
 
 func TestInvalid(t *testing.T) {
index d5a69349beba8bdcf72ea914e8ed2a74a84ad983..fe047053afb01a934e66eb710051f7acea2b2876 100644 (file)
@@ -12,6 +12,9 @@ import (
        "bytes"
        "go/ast"
        "go/token"
+       "strconv"
+       "strings"
+       "unicode"
        "unicode/utf8"
 )
 
@@ -1334,6 +1337,49 @@ func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
        }
 }
 
+func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit {
+       // Note: An unmodified AST generated by go/parser will already
+       // contain a backward- or double-quoted path string that does
+       // not contain any invalid characters, and most of the work
+       // here is not needed. However, a modified or generated AST
+       // may possibly contain non-canonical paths. Do the work in
+       // all cases since it's not too hard and not speed-critical.
+
+       // if we don't have a proper string, be conservative and return whatever we have
+       if lit.Kind != token.STRING {
+               return lit
+       }
+       s, err := strconv.Unquote(lit.Value)
+       if err != nil {
+               return lit
+       }
+
+       // if the string is an invalid path, return whatever we have
+       //
+       // spec: "Implementation restriction: A compiler may restrict
+       // ImportPaths to non-empty strings using only characters belonging
+       // to Unicode's L, M, N, P, and S general categories (the Graphic
+       // characters without spaces) and may also exclude the characters
+       // !"#$%&'()*,:;<=>?[\]^`{|} and the Unicode replacement character
+       // U+FFFD."
+       if s == "" {
+               return lit
+       }
+       const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+       for _, r := range s {
+               if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+                       return lit
+               }
+       }
+
+       // otherwise, return the double-quoted path
+       s = strconv.Quote(s)
+       if s == lit.Value {
+               return lit // nothing wrong with lit
+       }
+       return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: token.STRING, Value: s}
+}
+
 // The parameter n is the number of specs in the group. If doIndent is set,
 // multi-line identifier lists in the spec are indented when the first
 // linebreak is encountered.
@@ -1346,7 +1392,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
                        p.expr(s.Name)
                        p.print(blank)
                }
-               p.expr(s.Path)
+               p.expr(sanitizeImportPath(s.Path))
                p.setComment(s.Comment)
                p.print(s.EndPos)
 
index 280c697a0dd7caced68425182c1c11a4da0c9074..36f9439a284be4cdcba7d1df3a7ecdfbe5b4074e 100644 (file)
@@ -496,29 +496,33 @@ func stripCommonPrefix(lines []string) {
        // Compute maximum common white prefix of all but the first,
        // last, and blank lines, and replace blank lines with empty
        // lines (the first line starts with /* and has no prefix).
-       // In case of two-line comments, consider the last line for
-       // the prefix computation since otherwise the prefix would
-       // be empty.
+       // In cases where only the first and last lines are not blank,
+       // such as two-line comments, or comments where all inner lines
+       // are blank, consider the last line for the prefix computation
+       // since otherwise the prefix would be empty.
        //
        // Note that the first and last line are never empty (they
        // contain the opening /* and closing */ respectively) and
        // thus they can be ignored by the blank line check.
-       var prefix string
+       prefix := ""
+       prefixSet := false
        if len(lines) > 2 {
-               first := true
                for i, line := range lines[1 : len(lines)-1] {
-                       switch {
-                       case isBlank(line):
+                       if isBlank(line) {
                                lines[1+i] = "" // range starts with lines[1]
-                       case first:
-                               prefix = commonPrefix(line, line)
-                               first = false
-                       default:
+                       } else {
+                               if !prefixSet {
+                                       prefix = line
+                                       prefixSet = true
+                               }
                                prefix = commonPrefix(prefix, line)
                        }
+
                }
-       } else { // len(lines) == 2, lines cannot be blank (contain /* and */)
-               line := lines[1]
+       }
+       // If we don't have a prefix yet, consider the last line.
+       if !prefixSet {
+               line := lines[len(lines)-1]
                prefix = commonPrefix(line, line)
        }
 
index b1af7958a96fd93e12ea9b3b181006011030dba5..849fa624489a61eeeea84bd66b6bce63fea9670f 100644 (file)
@@ -413,6 +413,68 @@ func _() {
                aligned line */
 }
 
+// Issue 9751.
+func _() {
+       /*a string
+
+       b string*/
+
+       /*A string
+
+
+
+       Z string*/
+
+       /*a string
+
+       b string
+
+       c string*/
+
+       {
+               /*a string
+               b string*/
+
+               /*a string
+
+               b string*/
+
+               /*a string
+
+               b string
+
+               c string*/
+       }
+
+       {
+               /*a string
+               b string*/
+
+               /*a string
+
+               b string*/
+
+               /*a string
+
+               b string
+
+               c string*/
+       }
+
+       /*
+        */
+
+       /*
+
+        */
+
+       /*
+
+        * line
+
+        */
+}
+
 /*
  * line
  * of
index 983e2b2c97e25a54bd0b96ba1d7e7a05985ebeb0..30cd23c6dd4cd006ca348d172aea0181e951e7be 100644 (file)
@@ -418,6 +418,68 @@ func _() {
                aligned line */
 }
 
+// Issue 9751.
+func _() {
+       /*a string
+
+       b string*/
+
+       /*A string
+
+
+
+       Z string*/
+
+       /*a string
+
+       b string
+
+       c string*/
+
+       {
+               /*a string
+b string*/
+
+               /*a string
+
+b string*/
+
+               /*a string
+
+b string
+
+c string*/
+       }
+
+       {
+               /*a string
+                               b string*/
+
+               /*a string
+
+                               b string*/
+
+               /*a string
+
+                               b string
+
+                               c string*/
+       }
+
+       /*
+       */
+
+       /*
+
+       */
+
+       /*
+
+        * line
+
+       */
+}
+
 /*
  * line
  * of
index 9acd41b7d288626f124ef7028dea85800ac7a12c..82f5e0f9147be69128d1a0183bfb058d65443b55 100644 (file)
@@ -110,6 +110,15 @@ import (
        "package_dddd"  // comment
 )
 
+// print import paths as double-quoted strings
+// (we would like more test cases but the go/parser
+// already excludes most incorrect paths, and we don't
+// bother setting up test-ASTs manually)
+import (
+       "fmt"
+       "math"
+)
+
 // at least one empty line between declarations of different kind
 import _ "io"
 
index 45beec25fc7ff4f182d16e6bf9e3ef58497be2c6..a0a3783b846fbed661713caee409bdc41ec1afef 100644 (file)
@@ -111,6 +111,15 @@ import (
        "package_dddd" // comment
 )
 
+// print import paths as double-quoted strings
+// (we would like more test cases but the go/parser
+// already excludes most incorrect paths, and we don't
+// bother setting up test-ASTs manually)
+import (
+       `fmt`
+       "math"
+)
+
 // at least one empty line between declarations of different kind
 import _ "io"
 var _ int
index d422ada37a78350ecfcfa23714c5dbed07e78956..1827403aa38a167c72e6e70433abf520e9f9f51f 100644 (file)
@@ -151,7 +151,7 @@ The template
 
 can be invoked with
 
-  tmpl.Execute(out, HTML(`<b>World</b>`))
+  tmpl.Execute(out, template.HTML(`<b>World</b>`))
 
 to produce
 
index 6b8e5c4877e27b5fef3bab8d5bfb1c0da956a5cb..e0ecd92baaccc104747d534d229706222e8e5b69 100644 (file)
@@ -570,7 +570,7 @@ func NewAlpha(r Rectangle) *Alpha {
        return &Alpha{pix, 1 * w, r}
 }
 
-// Alpha16 is an in-memory image whose At method returns color.Alpha64 values.
+// Alpha16 is an in-memory image whose At method returns color.Alpha16 values.
 type Alpha16 struct {
        // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
        // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
index 944bab3f5d44938f5ff718fcc5d86427756347cd..36d5a1ccb0c013105f3ef0c8b3636a176debdeda 100644 (file)
@@ -12,9 +12,11 @@ import (
 )
 
 var randomTrap = map[string]uintptr{
-       "386":   355,
-       "amd64": 318,
-       "arm":   384,
+       "386":     355,
+       "amd64":   318,
+       "arm":     384,
+       "ppc64":   359,
+       "ppc64le": 359,
 }[runtime.GOARCH]
 
 var randomUnsupported int32 // atomic
index a095fcda9c3b8e47f8c2103d8cfdf926392698c9..a9b5935670e830e21eba41e79ebfca039a3fe5fc 100644 (file)
@@ -1,5 +1,3 @@
-// +build !plan9
-
 /*
 Inferno lib9/tokenize.c
 http://code.google.com/p/inferno-os/source/browse/lib9/tokenize.c
index 9d4fe404240e55b968a6d306cf47ed1f0b2c3ce3..8d597750b71a2e0a4574299c132f51bef91a865f 100644 (file)
@@ -71,8 +71,7 @@ static Optab  optab[] =
 {
        /* struct Optab:
          OPCODE,       from, prog->reg, to,             type,size,param,flag */
-       { ATEXT,        C_ADDR, C_NONE, C_LCON,          0, 0, 0 },
-       { ATEXT,        C_ADDR, C_REG,  C_LCON,          0, 0, 0 },
+       { ATEXT,        C_ADDR, C_NONE, C_TEXTSIZE,      0, 0, 0 },
 
        { AADD,         C_REG,  C_REG,  C_REG,           1, 4, 0 },
        { AADD,         C_REG,  C_NONE, C_REG,           1, 4, 0 },
@@ -352,22 +351,6 @@ static uint32      opbra(Link*, int, int);
 static Oprang  oprange[ALAST];
 static uchar   xcmp[C_GOK+1][C_GOK+1];
 
-static Prog zprg = {
-       .as = AGOK,
-       .scond = C_SCOND_NONE,
-       .reg = NREG,
-       .from = {
-               .name = D_NONE,
-               .type = D_NONE,
-               .reg = NREG,
-       },
-       .to = {
-               .name = D_NONE,
-               .type = D_NONE,
-               .reg = NREG,
-       },
-};
-
 static LSym *deferreturn;
 
 static void
@@ -399,6 +382,11 @@ casesz(Link *ctxt, Prog *p)
 
 static void buildop(Link*);
 
+// Note about encoding: Prog.scond holds the condition encoding,
+// but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0.
+// The code that shifts the value << 28 has the responsibility
+// for XORing with C_SCOND_XOR too.
+
 // asmoutnacl assembles the instruction p. It replaces asmout for NaCl.
 // It returns the total number of bytes put in out, and it can change
 // p->pc if extra padding is necessary.
@@ -441,20 +429,20 @@ asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
                break;
        case AB:
        case ABL:
-               if(p->to.type != D_OREG) {
+               if(p->to.type != TYPE_MEM) {
                        if(out != nil)
                                asmout(ctxt, p, o, out);
                } else {
-                       if(p->to.offset != 0 || size != 4 || p->to.reg >= 16 || p->to.reg < 0)
+                       if(p->to.offset != 0 || size != 4 || p->to.reg > REG_R15 || p->to.reg < REG_R0)
                                ctxt->diag("unsupported instruction: %P", p);
                        if((p->pc&15) == 12)
                                p->pc += 4;
                        if(out != nil) {
-                               out[0] = ((p->scond&C_SCOND)<<28) | 0x03c0013f | (p->to.reg << 12) | (p->to.reg << 16); // BIC $0xc000000f, Rx
+                               out[0] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x03c0013f | ((p->to.reg&15) << 12) | ((p->to.reg&15) << 16); // BIC $0xc000000f, Rx
                                if(p->as == AB)
-                                       out[1] = ((p->scond&C_SCOND)<<28) | 0x012fff10 | p->to.reg; // BX Rx
+                                       out[1] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x012fff10 | (p->to.reg&15)<<0; // BX Rx
                                else // ABL
-                                       out[1] = ((p->scond&C_SCOND)<<28) | 0x012fff30 | p->to.reg; // BLX Rx
+                                       out[1] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x012fff30 | (p->to.reg&15)<<0; // BLX Rx
                        }
                        size = 8;
                }
@@ -482,7 +470,7 @@ asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
        case AMOVW:
        case ASTREX:
        case ASTREXD:
-               if(p->to.type == D_REG && p->to.reg == 15 && p->from.reg == 13) { // MOVW.W x(R13), PC
+               if(p->to.type == TYPE_REG && p->to.reg == REG_R15 && p->from.reg == REG_R13) { // MOVW.W x(R13), PC
                        if(out != nil)
                                asmout(ctxt, p, o, out);
                        if(size == 4) {
@@ -490,8 +478,8 @@ asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
                                        // Note: 5c and 5g reg.c know that DIV/MOD smashes R12
                                        // so that this return instruction expansion is valid.
                                        out[0] = out[0] & ~0x3000; // change PC to R12
-                                       out[1] = ((p->scond&C_SCOND)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
-                                       out[2] = ((p->scond&C_SCOND)<<28) | 0x012fff1c; // BX R12
+                                       out[1] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
+                                       out[2] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x012fff1c; // BX R12
                                }
                                size += 8;
                                if(((p->pc+size) & 15) == 4)
@@ -502,9 +490,9 @@ asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
                                // offset to update R13, so we need to additionally mask R13.
                                if(out != nil) {
                                        out[size/4-1] &= ~0x3000; // change PC to R12
-                                       out[size/4] = ((p->scond&C_SCOND)<<28) | 0x03cdd103; // BIC $0xc0000000, R13
-                                       out[size/4+1] = ((p->scond&C_SCOND)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
-                                       out[size/4+2] = ((p->scond&C_SCOND)<<28) | 0x012fff1c; // BX R12
+                                       out[size/4] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x03cdd103; // BIC $0xc0000000, R13
+                                       out[size/4+1] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
+                                       out[size/4+2] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x012fff1c; // BX R12
                                }
                                // p->pc+size is only ok at 4 or 12 mod 16.
                                if((p->pc+size)%8 == 0)
@@ -514,19 +502,19 @@ asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
                        }
                }
 
-               if(p->to.type == D_REG && p->to.reg == 15)
+               if(p->to.type == TYPE_REG && p->to.reg == REG_R15)
                        ctxt->diag("unsupported instruction (move to another register and use indirect jump instead): %P", p);
 
-               if(p->to.type == D_OREG && p->to.reg == 13 && (p->scond & C_WBIT) && size > 4) {
+               if(p->to.type == TYPE_MEM && p->to.reg == REG_R13 && (p->scond & C_WBIT) && size > 4) {
                        // function prolog with very large frame size: MOVW.W R14,-100004(R13)
                        // split it into two instructions:
                        //      ADD $-100004, R13
                        //      MOVW R14, 0(R13)
-                       q = ctxt->arch->prg();
+                       q = emallocz(sizeof(Prog));
                        p->scond &= ~C_WBIT;
                        *q = *p;
                        a = &p->to;
-                       if(p->to.type == D_OREG)
+                       if(p->to.type == TYPE_MEM)
                                a2 = &q->to;
                        else
                                a2 = &q->from;
@@ -539,37 +527,37 @@ asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
                        // make p into ADD $X, R13
                        p->as = AADD;
                        p->from = *a;
-                       p->from.reg = NREG;
-                       p->from.type = D_CONST;
-                       p->to = zprg.to;
-                       p->to.type = D_REG;
-                       p->to.reg = 13;
+                       p->from.reg = 0;
+                       p->from.type = TYPE_CONST;
+                       p->to = zprog.to;
+                       p->to.type = TYPE_REG;
+                       p->to.reg = REG_R13;
                        // make q into p but load/store from 0(R13)
                        q->spadj = 0;
-                       *a2 = zprg.from;
-                       a2->type = D_OREG;
-                       a2->reg = 13;
+                       *a2 = zprog.from;
+                       a2->type = TYPE_MEM;
+                       a2->reg = REG_R13;
                        a2->sym = nil;
                        a2->offset = 0;
                        size = oplook(ctxt, p)->size;
                        break;
                }
 
-               if((p->to.type == D_OREG && p->to.reg != 13 && p->to.reg != 9) || // MOVW Rx, X(Ry), y != 13 && y != 9
-                  (p->from.type == D_OREG && p->from.reg != 13 && p->from.reg != 9)) { // MOVW X(Rx), Ry, x != 13 && x != 9
-                       if(p->to.type == D_OREG)
+               if((p->to.type == TYPE_MEM && p->to.reg != REG_R13 && p->to.reg != REG_R9) || // MOVW Rx, X(Ry), y != 13 && y != 9
+                  (p->from.type == TYPE_MEM && p->from.reg != REG_R13 && p->from.reg != REG_R9)) { // MOVW X(Rx), Ry, x != 13 && x != 9
+                       if(p->to.type == TYPE_MEM)
                                a = &p->to;
                        else
                                a = &p->from;
                        reg = a->reg;
                        if(size == 4) {
-                               // if addr.reg == NREG, then it is probably load from x(FP) with small x, no need to modify.
-                               if(reg == NREG) {
+                               // if addr.reg == 0, then it is probably load from x(FP) with small x, no need to modify.
+                               if(reg == 0) {
                                        if(out != nil)
                                                asmout(ctxt, p, o, out);
                                } else {
                                        if(out != nil)
-                                               out[0] = ((p->scond&C_SCOND)<<28) | 0x03c00103 | (reg << 16) | (reg << 12); // BIC $0xc0000000, Rx
+                                               out[0] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x03c00103 | ((reg&15) << 16) | ((reg&15) << 12); // BIC $0xc0000000, Rx
                                        if((p->pc&15) == 12)
                                                p->pc += 4;
                                        size += 4;
@@ -585,9 +573,9 @@ asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
                                // This won't handle .W/.P, so we should reject such code.
                                if(p->scond & (C_PBIT|C_WBIT))
                                        ctxt->diag("unsupported instruction (.P/.W): %P", p);
-                               q = ctxt->arch->prg();
+                               q = emallocz(sizeof(Prog));
                                *q = *p;
-                               if(p->to.type == D_OREG)
+                               if(p->to.type == TYPE_MEM)
                                        a2 = &q->to;
                                else
                                        a2 = &q->from;
@@ -600,14 +588,14 @@ asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
                                // make p into MOVW $X(R), R11
                                p->as = AMOVW;
                                p->from = *a;
-                               p->from.type = D_CONST;
-                               p->to = zprg.to;
-                               p->to.type = D_REG;
-                               p->to.reg = 11;
+                               p->from.type = TYPE_ADDR;
+                               p->to = zprog.to;
+                               p->to.type = TYPE_REG;
+                               p->to.reg = REG_R11;
                                // make q into p but load/store from 0(R11)
-                               *a2 = zprg.from;
-                               a2->type = D_OREG;
-                               a2->reg = 11;
+                               *a2 = zprog.from;
+                               a2->type = TYPE_MEM;
+                               a2->reg = REG_R11;
                                a2->sym = nil;
                                a2->offset = 0;
                                size = oplook(ctxt, p)->size;
@@ -619,12 +607,12 @@ asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
        }
 
        // destination register specific
-       if(p->to.type == D_REG) {
+       if(p->to.type == TYPE_REG) {
                switch(p->to.reg) {
-               case 9:
+               case REG_R9:
                        ctxt->diag("invalid instruction, cannot write to R9: %P", p);
                        break;
-               case 13:
+               case REG_R13:
                        if(out != nil)
                                out[size/4] = 0xe3cdd103; // BIC $0xc0000000, R13
                        if(((p->pc+size) & 15) == 0)
@@ -707,7 +695,7 @@ span5(Link *ctxt, LSym *cursym)
                                flushpool(ctxt, p, 0, 0);
                        break;
                }
-               if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == C_SCOND_NONE)
+               if(p->as==AMOVW && p->to.type==TYPE_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == C_SCOND_NONE)
                        flushpool(ctxt, p, 0, 0);
                c += m;
        }
@@ -738,18 +726,18 @@ span5(Link *ctxt, LSym *cursym)
                                if(otxt < 0)
                                        otxt = -otxt;
                                if(otxt >= (1L<<17) - 10) {
-                                       q = ctxt->arch->prg();
+                                       q = emallocz(sizeof(Prog));
                                        q->link = p->link;
                                        p->link = q;
                                        q->as = AB;
-                                       q->to.type = D_BRANCH;
+                                       q->to.type = TYPE_BRANCH;
                                        q->pcond = p->pcond;
                                        p->pcond = q;
-                                       q = ctxt->arch->prg();
+                                       q = emallocz(sizeof(Prog));
                                        q->link = p->link;
                                        p->link = q;
                                        q->as = AB;
-                                       q->to.type = D_BRANCH;
+                                       q->to.type = TYPE_BRANCH;
                                        q->pcond = q->link->link;
                                        bflag = 1;
                                }
@@ -863,9 +851,9 @@ flushpool(Link *ctxt, Prog *p, int skip, int force)
        if(ctxt->blitrl) {
                if(skip){
                        if(0 && skip==1)print("note: flush literal pool at %llux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
-                       q = ctxt->arch->prg();
+                       q = emallocz(sizeof(Prog));
                        q->as = AB;
-                       q->to.type = D_BRANCH;
+                       q->to.type = TYPE_BRANCH;
                        q->pcond = p->link;
                        q->link = ctxt->blitrl;
                        q->lineno = p->lineno;
@@ -875,7 +863,7 @@ flushpool(Link *ctxt, Prog *p, int skip, int force)
                        return 0;
                if(ctxt->headtype == Hnacl && pool.size % 16 != 0) {
                        // if pool is not multiple of 16 bytes, add an alignment marker
-                       q = ctxt->arch->prg();
+                       q = emallocz(sizeof(Prog));
                        q->as = ADATABUNDLEEND;
                        ctxt->elitrl->link = q;
                        ctxt->elitrl = q;
@@ -907,7 +895,7 @@ addpool(Link *ctxt, Prog *p, Addr *a)
 
        c = aclass(ctxt, a);
 
-       t = zprg;
+       t = zprog;
        t.as = AWORD;
 
        switch(c) {
@@ -931,7 +919,7 @@ addpool(Link *ctxt, Prog *p, Addr *a)
        case C_SAUTO:
        case C_LAUTO:
        case C_LACON:
-               t.to.type = D_CONST;
+               t.to.type = TYPE_CONST;
                t.to.offset = ctxt->instoffset;
                break;
        }
@@ -946,8 +934,8 @@ addpool(Link *ctxt, Prog *p, Addr *a)
 
        if(ctxt->headtype == Hnacl && pool.size%16 == 0) {
                // start a new data bundle
-               q = ctxt->arch->prg();
-               *q = zprg;
+               q = emallocz(sizeof(Prog));
+               *q = zprog;
                q->as = ADATABUNDLE;
                q->pc = pool.size;
                pool.size += 4;
@@ -960,7 +948,7 @@ addpool(Link *ctxt, Prog *p, Addr *a)
                ctxt->elitrl = q;
        }
 
-       q = ctxt->arch->prg();
+       q = emallocz(sizeof(Prog));
        *q = t;
        q->pc = pool.size;
 
@@ -1038,31 +1026,33 @@ aclass(Link *ctxt, Addr *a)
        int t;
 
        switch(a->type) {
-       case D_NONE:
+       case TYPE_NONE:
                return C_NONE;
 
-       case D_REG:
-               return C_REG;
+       case TYPE_REG:
+               if(REG_R0 <= a->reg && a->reg <= REG_R15)
+                       return C_REG;
+               if(REG_F0 <= a->reg && a->reg <= REG_F15)
+                       return C_FREG;
+               if(a->reg == REG_FPSR || a->reg == REG_FPCR)
+                       return C_FCR;
+               if(a->reg == REG_CPSR || a->reg == REG_SPSR)
+                       return C_PSR;
+               return C_GOK;
 
-       case D_REGREG:
+       case TYPE_REGREG:
                return C_REGREG;
 
-       case D_REGREG2:
+       case TYPE_REGREG2:
                return C_REGREG2;
 
-       case D_SHIFT:
+       case TYPE_SHIFT:
                return C_SHIFT;
 
-       case D_FREG:
-               return C_FREG;
-
-       case D_FPCR:
-               return C_FCR;
-
-       case D_OREG:
+       case TYPE_MEM:
                switch(a->name) {
-               case D_EXTERN:
-               case D_STATIC:
+               case NAME_EXTERN:
+               case NAME_STATIC:
                        if(a->sym == 0 || a->sym->name == 0) {
                                print("null sym external\n");
                                return C_GOK;
@@ -1070,7 +1060,7 @@ aclass(Link *ctxt, Addr *a)
                        ctxt->instoffset = 0;   // s.b. unused but just in case
                        return C_ADDR;
 
-               case D_AUTO:
+               case NAME_AUTO:
                        ctxt->instoffset = ctxt->autosize + a->offset;
                        t = immaddr(ctxt->instoffset);
                        if(t){
@@ -1085,7 +1075,7 @@ aclass(Link *ctxt, Addr *a)
                        }
                        return C_LAUTO;
 
-               case D_PARAM:
+               case NAME_PARAM:
                        ctxt->instoffset = ctxt->autosize + a->offset + 4L;
                        t = immaddr(ctxt->instoffset);
                        if(t){
@@ -1099,7 +1089,7 @@ aclass(Link *ctxt, Addr *a)
                                return C_SAUTO;
                        }
                        return C_LAUTO;
-               case D_NONE:
+               case TYPE_NONE:
                        ctxt->instoffset = a->offset;
                        t = immaddr(ctxt->instoffset);
                        if(t) {
@@ -1124,32 +1114,23 @@ aclass(Link *ctxt, Addr *a)
                }
                return C_GOK;
 
-       case D_PSR:
-               return C_PSR;
-
-       case D_OCONST:
-               switch(a->name) {
-               case D_EXTERN:
-               case D_STATIC:
-                       ctxt->instoffset = 0;   // s.b. unused but just in case
-                       return C_ADDR;
-               }
-               return C_GOK;
-
-       case D_FCONST:
+       case TYPE_FCONST:
                if(chipzero5(ctxt, a->u.dval) >= 0)
                        return C_ZFCON;
                if(chipfloat5(ctxt, a->u.dval) >= 0)
                        return C_SFCON;
                return C_LFCON;
 
-       case D_CONST:
-       case D_CONST2:
+       case TYPE_TEXTSIZE:
+               return C_TEXTSIZE;
+
+       case TYPE_CONST:
+       case TYPE_ADDR:
                switch(a->name) {
 
-               case D_NONE:
+               case TYPE_NONE:
                        ctxt->instoffset = a->offset;
-                       if(a->reg != NREG)
+                       if(a->reg != 0)
                                return aconsize(ctxt);
 
                        t = immrot(ctxt->instoffset);
@@ -1160,25 +1141,25 @@ aclass(Link *ctxt, Addr *a)
                                return C_NCON;
                        return C_LCON;
 
-               case D_EXTERN:
-               case D_STATIC:
+               case NAME_EXTERN:
+               case NAME_STATIC:
                        s = a->sym;
                        if(s == nil)
                                break;
                        ctxt->instoffset = 0;   // s.b. unused but just in case
                        return C_LCONADDR;
 
-               case D_AUTO:
+               case NAME_AUTO:
                        ctxt->instoffset = ctxt->autosize + a->offset;
                        return aconsize(ctxt);
 
-               case D_PARAM:
+               case NAME_PARAM:
                        ctxt->instoffset = ctxt->autosize + a->offset + 4L;
                        return aconsize(ctxt);
                }
                return C_GOK;
 
-       case D_BRANCH:
+       case TYPE_BRANCH:
                return C_SBRA;
        }
        return C_GOK;
@@ -1224,7 +1205,7 @@ oplook(Link *ctxt, Prog *p)
        }
        a3--;
        a2 = C_NONE;
-       if(p->reg != NREG)
+       if(p->reg != 0)
                a2 = C_REG;
        r = p->as;
        o = oprange[r].start;
@@ -1535,14 +1516,14 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                rf = p->from.reg;
                rt = p->to.reg;
                r = p->reg;
-               if(p->to.type == D_NONE)
+               if(p->to.type == TYPE_NONE)
                        rt = 0;
                if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN)
                        r = 0;
                else
-               if(r == NREG)
+               if(r == 0)
                        r = rt;
-               o1 |= rf | (r<<16) | (rt<<12);
+               o1 |= ((rf&15)<<0) | ((r&15)<<16) | ((rt&15)<<12);
                break;
 
        case 2:         /* movbu $I,[R],R */
@@ -1551,13 +1532,13 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                o1 |= immrot(ctxt->instoffset);
                rt = p->to.reg;
                r = p->reg;
-               if(p->to.type == D_NONE)
+               if(p->to.type == TYPE_NONE)
                        rt = 0;
                if(p->as == AMOVW || p->as == AMVN)
                        r = 0;
-               else if(r == NREG)
+               else if(r == 0)
                        r = rt;
-               o1 |= (r<<16) | (rt<<12);
+               o1 |= ((r&15)<<16) | ((rt&15)<<12);
                break;
 
        case 3:         /* add R<<[IR],[R],R */
@@ -1569,10 +1550,10 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                o1 = oprrr(ctxt, AADD, p->scond);
                o1 |= immrot(ctxt->instoffset);
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
-               o1 |= r << 16;
-               o1 |= p->to.reg << 12;
+               o1 |= (r&15) << 16;
+               o1 |= (p->to.reg&15) << 12;
                break;
 
        case 5:         /* bra s */
@@ -1597,8 +1578,8 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                aclass(ctxt, &p->to);
                o1 = oprrr(ctxt, AADD, p->scond);
                o1 |= immrot(ctxt->instoffset);
-               o1 |= p->to.reg << 16;
-               o1 |= REGPC << 12;
+               o1 |= (p->to.reg&15) << 16;
+               o1 |= (REGPC&15) << 12;
                break;
 
        case 7:         /* bl (R) -> blx R */
@@ -1606,7 +1587,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                if(ctxt->instoffset != 0)
                        ctxt->diag("%P: doesn't support BL offset(REG) where offset != 0", p);
                o1 = oprrr(ctxt, ABL, p->scond);
-               o1 |= p->to.reg;
+               o1 |= (p->to.reg&15) << 0;
                rel = addrel(ctxt->cursym);
                rel->off = ctxt->pc;
                rel->siz = 0;
@@ -1617,26 +1598,26 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                aclass(ctxt, &p->from);
                o1 = oprrr(ctxt, p->as, p->scond);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
-               o1 |= r;
+               o1 |= (r&15) << 0;
                o1 |= (ctxt->instoffset&31) << 7;
-               o1 |= p->to.reg << 12;
+               o1 |= (p->to.reg&15) << 12;
                break;
 
        case 9:         /* sll R,[R],R -> mov (R<<R),R */
                o1 = oprrr(ctxt, p->as, p->scond);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
-               o1 |= r;
-               o1 |= (p->from.reg << 8) | (1<<4);
-               o1 |= p->to.reg << 12;
+               o1 |= (r&15) << 0;
+               o1 |= ((p->from.reg&15) << 8) | (1<<4);
+               o1 |= (p->to.reg&15) << 12;
                break;
 
        case 10:        /* swi [$con] */
                o1 = oprrr(ctxt, p->as, p->scond);
-               if(p->to.type != D_NONE) {
+               if(p->to.type != TYPE_NONE) {
                        aclass(ctxt, &p->to);
                        o1 |= ctxt->instoffset & 0xffffff;
                }
@@ -1676,7 +1657,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
        case 12:        /* movw $lcon, reg */
                o1 = omvl(ctxt, p, &p->from, p->to.reg);
                if(o->flag & LPCREL) {
-                       o2 = oprrr(ctxt, AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12;
+                       o2 = oprrr(ctxt, AADD, p->scond) | (p->to.reg&15) << 0 | (REGPC&15) << 16 | (p->to.reg&15) << 12;
                }
                break;
 
@@ -1685,15 +1666,15 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                if(!o1)
                        break;
                o2 = oprrr(ctxt, p->as, p->scond);
-               o2 |= REGTMP;
+               o2 |= (REGTMP&15);
                r = p->reg;
                if(p->as == AMOVW || p->as == AMVN)
                        r = 0;
-               else if(r == NREG)
+               else if(r == 0)
                        r = p->to.reg;
-               o2 |= r << 16;
-               if(p->to.type != D_NONE)
-                       o2 |= p->to.reg << 12;
+               o2 |= (r&15) << 16;
+               if(p->to.type != TYPE_NONE)
+                       o2 |= (p->to.reg&15) << 12;
                break;
 
        case 14:        /* movb/movbu/movh/movhu R,R */
@@ -1705,8 +1686,8 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                        o2 = oprrr(ctxt, ASRA, p->scond);
 
                r = p->to.reg;
-               o1 |= (p->from.reg)|(r<<12);
-               o2 |= (r)|(r<<12);
+               o1 |= ((p->from.reg&15)<<0)|((r&15)<<12);
+               o2 |= (r&15)|((r&15)<<12);
                if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) {
                        o1 |= (24<<7);
                        o2 |= (24<<7);
@@ -1721,18 +1702,18 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                rf = p->from.reg;
                rt = p->to.reg;
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = rt;
                if(rt == r) {
                        r = rf;
                        rf = rt;
                }
                if(0)
-               if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
+               if(rt == r || rf == (REGPC&15) || r == (REGPC&15) || rt == (REGPC&15)) {
                        ctxt->diag("bad registers in MUL");
                        prasm(p);
                }
-               o1 |= (rf<<8) | r | (rt<<16);
+               o1 |= ((rf&15)<<8) | ((r&15)<<0) | ((rt&15)<<16);
                break;
 
 
@@ -1747,13 +1728,13 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                rt = p->to.reg;
                rt2 = p->to.offset;
                r = p->reg;
-               o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
+               o1 |= ((rf&15)<<8) | ((r&15)<<0) | ((rt&15)<<16) | ((rt2&15)<<12);
                break;
 
        case 20:        /* mov/movb/movbu R,O(R) */
                aclass(ctxt, &p->to);
                r = p->to.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                o1 = osr(ctxt, p->as, p->from.reg, ctxt->instoffset, r, p->scond);
                break;
@@ -1761,7 +1742,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
        case 21:        /* mov/movbu O(R),R -> lr */
                aclass(ctxt, &p->from);
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                o1 = olr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond);
                if(p->as != AMOVW)
@@ -1773,9 +1754,9 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                if(!o1)
                        break;
                r = p->to.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
-               o2 = osrr(ctxt, p->from.reg, REGTMP,r, p->scond);
+               o2 = osrr(ctxt, p->from.reg, REGTMP&15, r, p->scond);
                if(p->as != AMOVW)
                        o2 |= 1<<22;
                break;
@@ -1785,9 +1766,9 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                if(!o1)
                        break;
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
-               o2 = olrr(ctxt, REGTMP,r, p->to.reg, p->scond);
+               o2 = olrr(ctxt, REGTMP&15, r, p->to.reg, p->scond);
                if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
                        o2 |= 1<<22;
                break;
@@ -1798,29 +1779,29 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                        break;
 
                o2 = oprrr(ctxt, AADD, p->scond);
-               o2 |= REGTMP;
+               o2 |= (REGTMP&15);
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
-               o2 |= r << 16;
-               if(p->to.type != D_NONE)
-                       o2 |= p->to.reg << 12;
+               o2 |= (r&15) << 16;
+               if(p->to.type != TYPE_NONE)
+                       o2 |= (p->to.reg&15) << 12;
                break;
 
        case 35:        /* mov PSR,R */
                o1 = (2<<23) | (0xf<<16) | (0<<0);
-               o1 |= (p->scond & C_SCOND) << 28;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                o1 |= (p->from.reg & 1) << 22;
-               o1 |= p->to.reg << 12;
+               o1 |= (p->to.reg&15) << 12;
                break;
 
        case 36:        /* mov R,PSR */
                o1 = (2<<23) | (0x29f<<12) | (0<<4);
                if(p->scond & C_FBIT)
                        o1 ^= 0x010 << 12;
-               o1 |= (p->scond & C_SCOND) << 28;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                o1 |= (p->to.reg & 1) << 22;
-               o1 |= p->from.reg << 0;
+               o1 |= (p->from.reg&15) << 0;
                break;
 
        case 37:        /* mov $con,PSR */
@@ -1828,10 +1809,10 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                o1 = (2<<23) | (0x29f<<12) | (0<<4);
                if(p->scond & C_FBIT)
                        o1 ^= 0x010 << 12;
-               o1 |= (p->scond & C_SCOND) << 28;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                o1 |= immrot(ctxt->instoffset);
                o1 |= (p->to.reg & 1) << 22;
-               o1 |= p->from.reg << 0;
+               o1 |= (p->from.reg&15) << 0;
                break;
 
        case 38:
@@ -1840,20 +1821,20 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                case 38:        /* movm $con,oreg -> stm */
                        o1 = (0x4 << 25);
                        o1 |= p->from.offset & 0xffff;
-                       o1 |= p->to.reg << 16;
+                       o1 |= (p->to.reg&15) << 16;
                        aclass(ctxt, &p->to);
                        break;
        
                case 39:        /* movm oreg,$con -> ldm */
                        o1 = (0x4 << 25) | (1 << 20);
                        o1 |= p->to.offset & 0xffff;
-                       o1 |= p->from.reg << 16;
+                       o1 |= (p->from.reg&15) << 16;
                        aclass(ctxt, &p->from);
                        break;
                }
                if(ctxt->instoffset != 0)
                        ctxt->diag("offset must be zero in MOVM; %P", p);
-               o1 |= (p->scond & C_SCOND) << 28;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                if(p->scond & C_PBIT)
                        o1 |= 1 << 24;
                if(p->scond & C_UBIT)
@@ -1871,10 +1852,10 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                o1 = (0x2<<23) | (0x9<<4);
                if(p->as != ASWPW)
                        o1 |= 1 << 22;
-               o1 |= p->from.reg << 16;
-               o1 |= p->reg << 0;
-               o1 |= p->to.reg << 12;
-               o1 |= (p->scond & C_SCOND) << 28;
+               o1 |= (p->from.reg&15) << 16;
+               o1 |= (p->reg&15) << 0;
+               o1 |= (p->to.reg&15) << 12;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                break;
 
        case 41:        /* rfe -> movm.s.w.u 0(r13),[r15] */
@@ -1884,7 +1865,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
        case 50:        /* floating point store */
                v = regoff(ctxt, &p->to);
                r = p->to.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                o1 = ofsr(ctxt, p->as, p->from.reg, v, r, p->scond, p);
                break;
@@ -1892,7 +1873,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
        case 51:        /* floating point load */
                v = regoff(ctxt, &p->from);
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                o1 = ofsr(ctxt, p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
                break;
@@ -1902,9 +1883,9 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                if(!o1)
                        break;
                r = p->to.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
-               o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+               o2 = oprrr(ctxt, AADD, p->scond) | ((REGTMP&15) << 12) | ((REGTMP&15) << 16) | ((r&15) << 0);
                o3 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p);
                break;
 
@@ -1913,10 +1894,10 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                if(!o1)
                        break;
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
-               o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
-               o3 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+               o2 = oprrr(ctxt, AADD, p->scond) | ((REGTMP&15) << 12) | ((REGTMP&15) << 16) | ((r&15) << 0);
+               o3 = ofsr(ctxt, p->as, p->to.reg, 0, (REGTMP&15), p->scond, p) | (1<<20);
                break;
 
        case 54:        /* floating point arith */
@@ -1924,38 +1905,38 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                rf = p->from.reg;
                rt = p->to.reg;
                r = p->reg;
-               if(r == NREG) {
+               if(r == 0) {
                        r = rt;
                        if(p->as == AMOVF || p->as == AMOVD || p->as == AMOVFD || p->as == AMOVDF ||
                                p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD)
                                r = 0;
                }
-               o1 |= rf | (r<<16) | (rt<<12);
+               o1 |= ((rf&15)<<0) | ((r&15)<<16) | ((rt&15)<<12);
                break;
 
        case 56:        /* move to FP[CS]R */
-               o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
-               o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
+               o1 = (((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28) | (0xe << 24) | (1<<8) | (1<<4);
+               o1 |= (((p->to.reg&1)+1)<<21) | ((p->from.reg&15) << 12);
                break;
 
        case 57:        /* move from FP[CS]R */
-               o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
-               o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
+               o1 = (((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28) | (0xe << 24) | (1<<8) | (1<<4);
+               o1 |= (((p->from.reg&1)+1)<<21) | ((p->to.reg&15)<<12) | (1<<20);
                break;
        case 58:        /* movbu R,R */
                o1 = oprrr(ctxt, AAND, p->scond);
                o1 |= immrot(0xff);
                rt = p->to.reg;
                r = p->from.reg;
-               if(p->to.type == D_NONE)
+               if(p->to.type == TYPE_NONE)
                        rt = 0;
-               if(r == NREG)
+               if(r == 0)
                        r = rt;
-               o1 |= (r<<16) | (rt<<12);
+               o1 |= ((r&15)<<16) | ((rt&15)<<12);
                break;
 
        case 59:        /* movw/bu R<<I(R),R -> ldr indexed */
-               if(p->from.reg == NREG) {
+               if(p->from.reg == 0) {
                        if(p->as != AMOVW)
                                ctxt->diag("byte MOV from shifter operand");
                        o1 = mov(ctxt, p);
@@ -1969,7 +1950,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                break;
 
        case 60:        /* movb R(R),R -> ldrsb indexed */
-               if(p->from.reg == NREG) {
+               if(p->from.reg == 0) {
                        ctxt->diag("byte MOV from shifter operand");
                        o1 = mov(ctxt, p);
                        break;
@@ -1981,7 +1962,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                break;
 
        case 61:        /* movw/b/bu R,R<<[IR](R) -> str indexed */
-               if(p->to.reg == NREG)
+               if(p->to.reg == 0)
                        ctxt->diag("MOV to shifter operand");
                o1 = osrr(ctxt, p->from.reg, p->to.offset, p->to.reg, p->scond);
                if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU)
@@ -1990,12 +1971,12 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
 
        case 62:        /* case R -> movw       R<<2(PC),PC */
                if(o->flag & LPCREL) {
-                       o1 = oprrr(ctxt, AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12;
-                       o2 = olrr(ctxt, REGTMP, REGPC, REGTMP, p->scond);
+                       o1 = oprrr(ctxt, AADD, p->scond) | immrot(1) | (p->from.reg&15) << 16 | (REGTMP&15) << 12;
+                       o2 = olrr(ctxt, REGTMP&15, REGPC, REGTMP, p->scond);
                        o2 |= 2<<7;
-                       o3 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12;
+                       o3 = oprrr(ctxt, AADD, p->scond) | (REGTMP&15) | (REGPC&15) << 16 | (REGPC&15) << 12;
                } else {
-                       o1 = olrr(ctxt, p->from.reg, REGPC, REGPC, p->scond);
+                       o1 = olrr(ctxt, p->from.reg&15, REGPC, REGPC, p->scond);
                        o1 |= 2<<7;
                }
                break;
@@ -2029,7 +2010,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                o2 = osr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond);
                if(o->flag & LPCREL) {
                        o3 = o2;
-                       o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+                       o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP&15) | (REGPC&15) << 16 | (REGTMP&15) << 12;
                }
                break;
 
@@ -2042,7 +2023,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                        o2 |= 1<<22;
                if(o->flag & LPCREL) {
                        o3 = o2;
-                       o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+                       o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP&15) | (REGPC&15) << 16 | (REGTMP&15) << 12;
                }
                break;
 
@@ -2053,7 +2034,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                o2 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p);
                if(o->flag & LPCREL) {
                        o3 = o2;
-                       o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+                       o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP&15) | (REGPC&15) << 16 | (REGTMP&15) << 12;
                }
                break;
 
@@ -2061,10 +2042,10 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                o1 = omvl(ctxt, p, &p->from, REGTMP);
                if(!o1)
                        break;
-               o2 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+               o2 = ofsr(ctxt, p->as, p->to.reg, 0, (REGTMP&15), p->scond, p) | (1<<20);
                if(o->flag & LPCREL) {
                        o3 = o2;
-                       o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+                       o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP&15) | (REGPC&15) << 16 | (REGTMP&15) << 12;
                }
                break;
 
@@ -2072,14 +2053,14 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
        case 70:        /* movh/movhu R,O(R) -> strh */
                aclass(ctxt, &p->to);
                r = p->to.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                o1 = oshr(ctxt, p->from.reg, ctxt->instoffset, r, p->scond);
                break;
        case 71:        /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
                aclass(ctxt, &p->from);
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                o1 = olhr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond);
                if(p->as == AMOVB || p->as == AMOVBS)
@@ -2092,18 +2073,18 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                if(!o1)
                        break;
                r = p->to.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
-               o2 = oshrr(ctxt, p->from.reg, REGTMP,r, p->scond);
+               o2 = oshrr(ctxt, p->from.reg, REGTMP&15, r, p->scond);
                break;
        case 73:        /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
                o1 = omvl(ctxt, p, &p->from, REGTMP);
                if(!o1)
                        break;
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
-               o2 = olhrr(ctxt, REGTMP, r, p->to.reg, p->scond);
+               o2 = olhrr(ctxt, REGTMP&15, r, p->to.reg, p->scond);
                if(p->as == AMOVB || p->as == AMOVBS)
                        o2 ^= (1<<5)|(1<<6);
                else if(p->as == AMOVH || p->as == AMOVHS)
@@ -2117,16 +2098,16 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                if(ctxt->instoffset != 0)
                        ctxt->diag("non-zero offset in ABX");
 /*
-               o1 =    oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12);  // mov PC, LR
-               o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg;              // BX R
+               o1 =    oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12);        // mov PC, LR
+               o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0);          // BX R
 */
                // p->to.reg may be REGLINK
                o1 = oprrr(ctxt, AADD, p->scond);
                o1 |= immrot(ctxt->instoffset);
-               o1 |= p->to.reg << 16;
-               o1 |= REGTMP << 12;
-               o2 = oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12);     // mov PC, LR
-               o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP;         // BX Rtmp
+               o1 |= (p->to.reg&15) << 16;
+               o1 |= (REGTMP&15) << 12;
+               o2 = oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12);   // mov PC, LR
+               o3 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | (REGTMP&15);            // BX Rtmp
                break;
        case 76:        /* bx O(R) when returning from fn*/
                ctxt->diag("ABXRET");
@@ -2136,19 +2117,19 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                if(ctxt->instoffset != 0)
                        ctxt->diag("offset must be zero in LDREX");
                o1 = (0x19<<20) | (0xf9f);
-               o1 |= p->from.reg << 16;
-               o1 |= p->to.reg << 12;
-               o1 |= (p->scond & C_SCOND) << 28;
+               o1 |= (p->from.reg&15) << 16;
+               o1 |= (p->to.reg&15) << 12;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                break;
        case 78:        /* strex reg,oreg,reg */
                aclass(ctxt, &p->from);
                if(ctxt->instoffset != 0)
                        ctxt->diag("offset must be zero in STREX");
                o1 = (0x18<<20) | (0xf90);
-               o1 |= p->from.reg << 16;
-               o1 |= p->reg << 0;
-               o1 |= p->to.reg << 12;
-               o1 |= (p->scond & C_SCOND) << 28;
+               o1 |= (p->from.reg&15) << 16;
+               o1 |= (p->reg&15) << 0;
+               o1 |= (p->to.reg&15) << 12;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                break;
        case 80:        /* fmov zfcon,freg */
                if(p->as == AMOVD) {
@@ -2159,99 +2140,99 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                        o2 = oprrr(ctxt, ASUBF, p->scond);
                }
                v = 0x70;       // 1.0
-               r = p->to.reg;
+               r = (p->to.reg&15) << 0;
 
                // movf $1.0, r
-               o1 |= (p->scond & C_SCOND) << 28;
-               o1 |= r << 12;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
+               o1 |= (r&15) << 12;
                o1 |= (v&0xf) << 0;
                o1 |= (v&0xf0) << 12;
 
                // subf r,r,r
-               o2 |= r | (r<<16) | (r<<12);
+               o2 |= ((r&15)<<0) | ((r&15)<<16) | ((r&15)<<12);
                break;
        case 81:        /* fmov sfcon,freg */
                o1 = 0x0eb00a00;                // VMOV imm 32
                if(p->as == AMOVD)
                        o1 = 0xeeb00b00;        // VMOV imm 64
-               o1 |= (p->scond & C_SCOND) << 28;
-               o1 |= p->to.reg << 12;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
+               o1 |= (p->to.reg&15) << 12;
                v = chipfloat5(ctxt, p->from.u.dval);
                o1 |= (v&0xf) << 0;
                o1 |= (v&0xf0) << 12;
                break;
        case 82:        /* fcmp freg,freg, */
                o1 = oprrr(ctxt, p->as, p->scond);
-               o1 |= (p->reg<<12) | (p->from.reg<<0);
+               o1 |= ((p->reg&15)<<12) | ((p->from.reg&15)<<0);
                o2 = 0x0ef1fa10;        // VMRS R15
-               o2 |= (p->scond & C_SCOND) << 28;
+               o2 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                break;
        case 83:        /* fcmp freg,, */
                o1 = oprrr(ctxt, p->as, p->scond);
-               o1 |= (p->from.reg<<12) | (1<<16);
+               o1 |= ((p->from.reg&15)<<12) | (1<<16);
                o2 = 0x0ef1fa10;        // VMRS R15
-               o2 |= (p->scond & C_SCOND) << 28;
+               o2 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                break;
        case 84:        /* movfw freg,freg - truncate float-to-fix */
                o1 = oprrr(ctxt, p->as, p->scond);
-               o1 |= (p->from.reg<<0);
-               o1 |= (p->to.reg<<12);
+               o1 |= ((p->from.reg&15)<<0);
+               o1 |= ((p->to.reg&15)<<12);
                break;
        case 85:        /* movwf freg,freg - fix-to-float */
                o1 = oprrr(ctxt, p->as, p->scond);
-               o1 |= (p->from.reg<<0);
-               o1 |= (p->to.reg<<12);
+               o1 |= ((p->from.reg&15)<<0);
+               o1 |= ((p->to.reg&15)<<12);
                break;
        case 86:        /* movfw freg,reg - truncate float-to-fix */
                // macro for movfw freg,FTMP; movw FTMP,reg
                o1 = oprrr(ctxt, p->as, p->scond);
-               o1 |= (p->from.reg<<0);
-               o1 |= (FREGTMP<<12);
-               o2 = oprrr(ctxt, AMOVFW+AEND, p->scond);
-               o2 |= (FREGTMP<<16);
-               o2 |= (p->to.reg<<12);
+               o1 |= ((p->from.reg&15)<<0);
+               o1 |= ((FREGTMP&15)<<12);
+               o2 = oprrr(ctxt, AMOVFW+ALAST, p->scond);
+               o2 |= ((FREGTMP&15)<<16);
+               o2 |= ((p->to.reg&15)<<12);
                break;
        case 87:        /* movwf reg,freg - fix-to-float */
                // macro for movw reg,FTMP; movwf FTMP,freg
-               o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
-               o1 |= (p->from.reg<<12);
-               o1 |= (FREGTMP<<16);
+               o1 = oprrr(ctxt, AMOVWF+ALAST, p->scond);
+               o1 |= ((p->from.reg&15)<<12);
+               o1 |= ((FREGTMP&15)<<16);
                o2 = oprrr(ctxt, p->as, p->scond);
-               o2 |= (FREGTMP<<0);
-               o2 |= (p->to.reg<<12);
+               o2 |= ((FREGTMP&15)<<0);
+               o2 |= ((p->to.reg&15)<<12);
                break;
        case 88:        /* movw reg,freg  */
-               o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
-               o1 |= (p->from.reg<<12);
-               o1 |= (p->to.reg<<16);
+               o1 = oprrr(ctxt, AMOVWF+ALAST, p->scond);
+               o1 |= ((p->from.reg&15)<<12);
+               o1 |= ((p->to.reg&15)<<16);
                break;
        case 89:        /* movw freg,reg  */
-               o1 = oprrr(ctxt, AMOVFW+AEND, p->scond);
-               o1 |= (p->from.reg<<16);
-               o1 |= (p->to.reg<<12);
+               o1 = oprrr(ctxt, AMOVFW+ALAST, p->scond);
+               o1 |= ((p->from.reg&15)<<16);
+               o1 |= ((p->to.reg&15)<<12);
                break;
        case 90:        /* tst reg  */
-               o1 = oprrr(ctxt, ACMP+AEND, p->scond);
-               o1 |= p->from.reg<<16;
+               o1 = oprrr(ctxt, ACMP+ALAST, p->scond);
+               o1 |= (p->from.reg&15)<<16;
                break;
        case 91:        /* ldrexd oreg,reg */
                aclass(ctxt, &p->from);
                if(ctxt->instoffset != 0)
                        ctxt->diag("offset must be zero in LDREX");
                o1 = (0x1b<<20) | (0xf9f);
-               o1 |= p->from.reg << 16;
-               o1 |= p->to.reg << 12;
-               o1 |= (p->scond & C_SCOND) << 28;
+               o1 |= (p->from.reg&15) << 16;
+               o1 |= (p->to.reg&15) << 12;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                break;
        case 92:        /* strexd reg,oreg,reg */
                aclass(ctxt, &p->from);
                if(ctxt->instoffset != 0)
                        ctxt->diag("offset must be zero in STREX");
                o1 = (0x1a<<20) | (0xf90);
-               o1 |= p->from.reg << 16;
-               o1 |= p->reg << 0;
-               o1 |= p->to.reg << 12;
-               o1 |= (p->scond & C_SCOND) << 28;
+               o1 |= (p->from.reg&15) << 16;
+               o1 |= (p->reg&15) << 0;
+               o1 |= (p->to.reg&15) << 12;
+               o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
                break;
        case 93:        /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
                o1 = omvl(ctxt, p, &p->from, REGTMP);
@@ -2264,7 +2245,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                        o2 ^= (1<<6);
                if(o->flag & LPCREL) {
                        o3 = o2;
-                       o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+                       o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP&15) | (REGPC&15) << 16 | (REGTMP&15) << 12;
                }
                break;
        case 94:        /* movh/movhu R,addr -> strh */
@@ -2274,12 +2255,12 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                o2 = oshr(ctxt, p->from.reg, 0, REGTMP, p->scond);
                if(o->flag & LPCREL) {
                        o3 = o2;
-                       o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+                       o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP&15) | (REGPC&15) << 16 | (REGTMP&15) << 12;
                }
                break;
        case 95:        /* PLD off(reg) */
                o1 = 0xf5d0f000;
-               o1 |= p->from.reg << 16;
+               o1 |= (p->from.reg&15) << 16;
                if(p->from.offset < 0) {
                        o1 &= ~(1 << 23);
                        o1 |= (-p->from.offset) & 0xfff;
@@ -2296,21 +2277,21 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
                break;
        case 97:        /* CLZ Rm, Rd */
                o1 = oprrr(ctxt, p->as, p->scond);
-               o1 |= p->to.reg << 12;
-               o1 |= p->from.reg;
+               o1 |= (p->to.reg&15) << 12;
+               o1 |= (p->from.reg&15) << 0;
                break;
        case 98:        /* MULW{T,B} Rs, Rm, Rd */
                o1 = oprrr(ctxt, p->as, p->scond);
-               o1 |= p->to.reg << 16;
-               o1 |= p->from.reg << 8;
-               o1 |= p->reg;
+               o1 |= (p->to.reg&15) << 16;
+               o1 |= (p->from.reg&15) << 8;
+               o1 |= (p->reg&15) << 0;
                break;
        case 99:        /* MULAW{T,B} Rs, Rm, Rn, Rd */
                o1 = oprrr(ctxt, p->as, p->scond);
-               o1 |= p->to.reg << 12;
-               o1 |= p->from.reg << 8;
-               o1 |= p->reg;
-               o1 |= p->to.offset << 16;
+               o1 |= (p->to.reg&15) << 12;
+               o1 |= (p->from.reg&15) << 8;
+               o1 |= (p->reg&15) << 0;
+               o1 |= (p->to.offset&15) << 16;
                break;
        case 100:
                // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
@@ -2339,14 +2320,14 @@ mov(Link *ctxt, Prog *p)
        o1 = oprrr(ctxt, p->as, p->scond);
        o1 |= p->from.offset;
        rt = p->to.reg;
-       r = p->reg;
-       if(p->to.type == D_NONE)
+       if(p->to.type == TYPE_NONE)
                rt = 0;
+       r = p->reg;
        if(p->as == AMOVW || p->as == AMVN)
                r = 0;
-       else if(r == NREG)
+       else if(r == 0)
                r = rt;
-       o1 |= (r<<16) | (rt<<12);
+       o1 |= ((r&15)<<16) | ((rt&15)<<12);
        return o1;
 }
 
@@ -2355,7 +2336,7 @@ oprrr(Link *ctxt, int a, int sc)
 {
        uint32 o;
 
-       o = (sc & C_SCOND) << 28;
+       o = ((sc & C_SCOND) ^ C_SCOND_XOR) << 28;
        if(sc & C_SBIT)
                o |= 1 << 20;
        if(sc & (C_PBIT|C_WBIT))
@@ -2436,11 +2417,11 @@ oprrr(Link *ctxt, int a, int sc)
                        return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
                                (1<<18) | (1<<8) | (1<<7);      // toint, double, trunc
 
-       case AMOVWF+AEND:       // copy WtoF
+       case AMOVWF+ALAST:      // copy WtoF
                return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
-       case AMOVFW+AEND:       // copy FtoW
+       case AMOVFW+ALAST:      // copy FtoW
                return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
-       case ACMP+AEND: // cmp imm
+       case ACMP+ALAST:        // cmp imm
                return o | (0x3<<24) | (0x5<<20);
 
        case ACLZ:
@@ -2471,6 +2452,7 @@ opbra(Link *ctxt, int a, int sc)
        if(sc & (C_SBIT|C_PBIT|C_WBIT))
                ctxt->diag(".nil/.nil/.W on bra instruction");
        sc &= C_SCOND;
+       sc ^= C_SCOND_XOR;
        if(a == ABL || a == ADUFFZERO || a == ADUFFCOPY)
                return (sc<<28)|(0x5<<25)|(0x1<<24);
        if(sc != 0xe)
@@ -2506,7 +2488,7 @@ olr(Link *ctxt, int32 v, int b, int r, int sc)
 
        if(sc & C_SBIT)
                ctxt->diag(".nil on LDR/STR instruction");
-       o = (sc & C_SCOND) << 28;
+       o = ((sc & C_SCOND) ^ C_SCOND_XOR) << 28;
        if(!(sc & C_PBIT))
                o |= 1 << 24;
        if(!(sc & C_UBIT))
@@ -2523,8 +2505,8 @@ olr(Link *ctxt, int32 v, int b, int r, int sc)
        if(v >= (1<<12) || v < 0)
                ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp);
        o |= v;
-       o |= b << 16;
-       o |= r << 12;
+       o |= (b&15) << 16;
+       o |= (r&15) << 12;
        return o;
 }
 
@@ -2535,7 +2517,7 @@ olhr(Link *ctxt, int32 v, int b, int r, int sc)
 
        if(sc & C_SBIT)
                ctxt->diag(".nil on LDRH/STRH instruction");
-       o = (sc & C_SCOND) << 28;
+       o = ((sc & C_SCOND) ^ C_SCOND_XOR) << 28;
        if(!(sc & C_PBIT))
                o |= 1 << 24;
        if(sc & C_WBIT)
@@ -2548,8 +2530,8 @@ olhr(Link *ctxt, int32 v, int b, int r, int sc)
        if(v >= (1<<8) || v < 0)
                ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp);
        o |= (v&0xf)|((v>>4)<<8)|(1<<22);
-       o |= b << 16;
-       o |= r << 12;
+       o |= (b&15) << 16;
+       o |= (r&15) << 12;
        return o;
 }
 
@@ -2607,7 +2589,7 @@ ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
 
        if(sc & C_SBIT)
                ctxt->diag(".nil on FLDR/FSTR instruction");
-       o = (sc & C_SCOND) << 28;
+       o = ((sc & C_SCOND) ^ C_SCOND_XOR) << 28;
        if(!(sc & C_PBIT))
                o |= 1 << 24;
        if(sc & C_WBIT)
@@ -2623,8 +2605,8 @@ ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
        if(v >= (1<<10) || v < 0)
                ctxt->diag("literal span too large: %d\n%P", v, p);
        o |= (v>>2) & 0xFF;
-       o |= b << 16;
-       o |= r << 12;
+       o |= (b&15) << 16;
+       o |= (r&15) << 12;
 
        switch(a) {
        default:
@@ -2652,7 +2634,7 @@ omvl(Link *ctxt, Prog *p, Addr *a, int dr)
                }
                o1 = oprrr(ctxt, AMVN, p->scond&C_SCOND);
                o1 |= v;
-               o1 |= dr << 12;
+               o1 |= (dr&15) << 12;
        } else {
                v = p->pcond->pc - p->pc - 8;
                o1 = olr(ctxt, v, REGPC, dr, p->scond&C_SCOND);
index 5107da96971b54cba12eaf9196ade86f5c7430c5..bc66c0b9a80e987e2fcf9996f857a075abb49ad5 100644 (file)
@@ -113,6 +113,7 @@ enum
        Ymr, Ymm,
        Yxr, Yxm,
        Ytls,
+       Ytextsize,
        Ymax,
 
        Zxxx            = 0,
@@ -186,8 +187,8 @@ enum
 };
 
 static uchar ycover[Ymax*Ymax];
-static int     reg[D_NONE];
-static int     regrex[D_NONE+1];
+static int     reg[MAXREG];
+static int     regrex[MAXREG+1];
 static void    asmins(Link *ctxt, Prog *p);
 
 static uchar   ynone[] =
@@ -197,7 +198,7 @@ static uchar        ynone[] =
 };
 static uchar   ytext[] =
 {
-       Ymb,    Yi64,   Zpseudo,1,
+       Ymb,    Ytextsize,      Zpseudo,1,
        0
 };
 static uchar   ynop[] =
@@ -989,8 +990,6 @@ static Optab optab[] =
        { AFXRSTOR64,   ysvrs,  Pw, {0x0f,0xae,(01),0x0f,0xae,(01)} },
        { AFXSAVE64,    ysvrs,  Pw, {0x0f,0xae,(00),0x0f,0xae,(00)} },
        { AGLOBL },
-       { AGOK },
-       { AHISTORY },
        { AHLT,         ynone,  Px, {0xf4} },
        { AIDIVB,       ydivb,  Pb, {0xf6,(07)} },
        { AIDIVL,       ydivl,  Px, {0xf7,(07)} },
@@ -1115,7 +1114,6 @@ static Optab optab[] =
        { AMULSD,       yxm,    Pf2, {0x59} },
        { AMULSS,       yxm,    Pf3, {0x59} },
        { AMULW,        ydivl,  Pe, {0xf7,(04)} },
-       { ANAME },
        { ANEGB,        yscond, Pb, {0xf6,(03)} },
        { ANEGL,        yscond, Px, {0xf7,(03)} },
        { ANEGQ,        yscond, Pw, {0xf7,(03)} },
@@ -1614,16 +1612,12 @@ span6(Link *ctxt, LSym *s)
                instinit();
        
        for(p = ctxt->cursym->text; p != nil; p = p->link) {
-               n = 0;
-               if(p->to.type == D_BRANCH)
+               if(p->to.type == TYPE_BRANCH)
                        if(p->pcond == nil)
                                p->pcond = p;
-               if((q = p->pcond) != nil)
-                       if(q->back != 2)
-                               n = 1;
-               p->back = n;
                if(p->as == AADJSP) {
-                       p->to.type = D_SP;
+                       p->to.type = TYPE_REG;
+                       p->to.reg = REG_SP;
                        v = -p->from.offset;
                        p->from.offset = v;
                        p->as = spadjop(ctxt, p, AADDL, AADDQ);
@@ -1645,7 +1639,8 @@ span6(Link *ctxt, LSym *s)
                }
 
                if(p->as == AADJSP) {
-                       p->to.type = D_SP;
+                       p->to.type = TYPE_REG;
+                       p->to.reg = REG_SP;
                        v = -p->from.offset;
                        p->from.offset = v;
                        p->as = spadjop(ctxt, p, AADDL, AADDQ);
@@ -1852,32 +1847,32 @@ instinit(void)
        ycover[Ym*Ymax + Yxm] = 1;
        ycover[Yxr*Ymax + Yxm] = 1;
 
-       for(i=0; i<D_NONE; i++) {
+       for(i=0; i<MAXREG; i++) {
                reg[i] = -1;
-               if(i >= D_AL && i <= D_R15B) {
-                       reg[i] = (i-D_AL) & 7;
-                       if(i >= D_SPB && i <= D_DIB)
+               if(i >= REG_AL && i <= REG_R15B) {
+                       reg[i] = (i-REG_AL) & 7;
+                       if(i >= REG_SPB && i <= REG_DIB)
                                regrex[i] = 0x40;
-                       if(i >= D_R8B && i <= D_R15B)
+                       if(i >= REG_R8B && i <= REG_R15B)
                                regrex[i] = Rxr | Rxx | Rxb;
                }
-               if(i >= D_AH && i<= D_BH)
-                       reg[i] = 4 + ((i-D_AH) & 7);
-               if(i >= D_AX && i <= D_R15) {
-                       reg[i] = (i-D_AX) & 7;
-                       if(i >= D_R8)
+               if(i >= REG_AH && i<= REG_BH)
+                       reg[i] = 4 + ((i-REG_AH) & 7);
+               if(i >= REG_AX && i <= REG_R15) {
+                       reg[i] = (i-REG_AX) & 7;
+                       if(i >= REG_R8)
                                regrex[i] = Rxr | Rxx | Rxb;
                }
-               if(i >= D_F0 && i <= D_F0+7)
-                       reg[i] = (i-D_F0) & 7;
-               if(i >= D_M0 && i <= D_M0+7)
-                       reg[i] = (i-D_M0) & 7;
-               if(i >= D_X0 && i <= D_X0+15) {
-                       reg[i] = (i-D_X0) & 7;
-                       if(i >= D_X0+8)
+               if(i >= REG_F0 && i <= REG_F0+7)
+                       reg[i] = (i-REG_F0) & 7;
+               if(i >= REG_M0 && i <= REG_M0+7)
+                       reg[i] = (i-REG_M0) & 7;
+               if(i >= REG_X0 && i <= REG_X0+15) {
+                       reg[i] = (i-REG_X0) & 7;
+                       if(i >= REG_X0+8)
                                regrex[i] = Rxr | Rxx | Rxb;
                }
-               if(i >= D_CR+8 && i <= D_CR+15)
+               if(i >= REG_CR+8 && i <= REG_CR+15)
                        regrex[i] = Rxr;
        }
 }
@@ -1885,48 +1880,50 @@ instinit(void)
 static int
 prefixof(Link *ctxt, Addr *a)
 {
-       switch(a->type) {
-       case D_INDIR+D_CS:
-               return 0x2e;
-       case D_INDIR+D_DS:
-               return 0x3e;
-       case D_INDIR+D_ES:
-               return 0x26;
-       case D_INDIR+D_FS:
-               return 0x64;
-       case D_INDIR+D_GS:
-               return 0x65;
-       case D_INDIR+D_TLS:
-               // NOTE: Systems listed here should be only systems that
-               // support direct TLS references like 8(TLS) implemented as
-               // direct references from FS or GS. Systems that require
-               // the initial-exec model, where you load the TLS base into
-               // a register and then index from that register, do not reach
-               // this code and should not be listed.
-               switch(ctxt->headtype) {
-               default:
-                       sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
-               case Hdragonfly:
-               case Hfreebsd:
-               case Hlinux:
-               case Hnetbsd:
-               case Hopenbsd:
-               case Hsolaris:
-                       return 0x64; // FS
-               case Hdarwin:
-                       return 0x65; // GS
+       if(a->type == TYPE_MEM && a->name == NAME_NONE) {
+               switch(a->reg) {
+               case REG_CS:
+                       return 0x2e;
+               case REG_DS:
+                       return 0x3e;
+               case REG_ES:
+                       return 0x26;
+               case REG_FS:
+                       return 0x64;
+               case REG_GS:
+                       return 0x65;
+               case REG_TLS:
+                       // NOTE: Systems listed here should be only systems that
+                       // support direct TLS references like 8(TLS) implemented as
+                       // direct references from FS or GS. Systems that require
+                       // the initial-exec model, where you load the TLS base into
+                       // a register and then index from that register, do not reach
+                       // this code and should not be listed.
+                       switch(ctxt->headtype) {
+                       default:
+                               sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
+                       case Hdragonfly:
+                       case Hfreebsd:
+                       case Hlinux:
+                       case Hnetbsd:
+                       case Hopenbsd:
+                       case Hsolaris:
+                               return 0x64; // FS
+                       case Hdarwin:
+                               return 0x65; // GS
+                       }
                }
        }
        switch(a->index) {
-       case D_CS:
+       case REG_CS:
                return 0x2e;
-       case D_DS:
+       case REG_DS:
                return 0x3e;
-       case D_ES:
+       case REG_ES:
                return 0x26;
-       case D_FS:
+       case REG_FS:
                return 0x64;
-       case D_GS:
+       case REG_GS:
                return 0x65;
        }
        return 0;
@@ -1937,196 +1934,212 @@ oclass(Link *ctxt, Addr *a)
 {
        vlong v;
        int32 l;
+       
+       // TODO(rsc): This special case is for SHRQ $3, AX:DX,
+       // which encodes as SHRQ $32(DX*0), AX.
+       // Similarly SHRQ CX, AX:DX is really SHRQ CX(DX*0), AX.
+       // Change encoding and remove.
+       if((a->type == TYPE_CONST || a->type == TYPE_REG) && a->index != REG_NONE && a->scale == 0)
+               return Ycol;
 
-       if(a->type >= D_INDIR || a->index != D_NONE) {
-               if(a->index != D_NONE && a->scale == 0) {
-                       if(a->type == D_ADDR) {
-                               switch(a->index) {
-                               case D_EXTERN:
-                               case D_STATIC:
-                                       if(a->sym != nil && isextern(a->sym))
-                                               return Yi32;
-                                       return Yiauto; // use pc-relative addressing
-                               case D_AUTO:
-                               case D_PARAM:
-                                       return Yiauto;
-                               }
-                               return Yxxx;
-                       }
-                       return Ycol;
-               }
+       switch(a->type) {
+       case TYPE_NONE:
+               return Ynone;
+
+       case TYPE_BRANCH:
+               return Ybr;
+
+       case TYPE_MEM:
                return Ym;
+
+       case TYPE_ADDR:
+               switch(a->name) {
+               case NAME_EXTERN:
+               case NAME_STATIC:
+                       if(a->sym != nil && isextern(a->sym))
+                               return Yi32;
+                       return Yiauto; // use pc-relative addressing
+               case NAME_AUTO:
+               case NAME_PARAM:
+                       return Yiauto;
+               }
+
+               // TODO(rsc): DUFFZERO/DUFFCOPY encoding forgot to set a->index
+               // and got Yi32 in an earlier version of this code.
+               // Keep doing that until we fix yduff etc.
+               if(a->sym != nil && strncmp(a->sym->name, "runtime.duff", 12) == 0)
+                       return Yi32;
+               
+               if(a->sym != nil || a->name != NAME_NONE)
+                       ctxt->diag("unexpected addr: %D", a);
+               // fall through
+
+       case TYPE_CONST:
+               if(a->sym != nil)
+                       ctxt->diag("TYPE_CONST with symbol: %D", a);
+
+               v = a->offset;
+               if(v == 0)
+                       return Yi0;
+               if(v == 1)
+                       return Yi1;
+               if(v >= -128 && v <= 127)
+                       return Yi8;
+               l = v;
+               if((vlong)l == v)
+                       return Ys32;    /* can sign extend */
+               if((v>>32) == 0)
+                       return Yi32;    /* unsigned */
+               return Yi64;
+
+       case TYPE_TEXTSIZE:
+               return Ytextsize;
+       }
+       
+       if(a->type != TYPE_REG) {
+               ctxt->diag("unexpected addr1: type=%d %D", a->type, a);
+               return Yxxx;
        }
-       switch(a->type)
-       {
-       case D_AL:
+
+       switch(a->reg) {
+       case REG_AL:
                return Yal;
 
-       case D_AX:
+       case REG_AX:
                return Yax;
 
 /*
-       case D_SPB:
+       case REG_SPB:
 */
-       case D_BPB:
-       case D_SIB:
-       case D_DIB:
-       case D_R8B:
-       case D_R9B:
-       case D_R10B:
-       case D_R11B:
-       case D_R12B:
-       case D_R13B:
-       case D_R14B:
-       case D_R15B:
+       case REG_BPB:
+       case REG_SIB:
+       case REG_DIB:
+       case REG_R8B:
+       case REG_R9B:
+       case REG_R10B:
+       case REG_R11B:
+       case REG_R12B:
+       case REG_R13B:
+       case REG_R14B:
+       case REG_R15B:
                if(ctxt->asmode != 64)
                        return Yxxx;
-       case D_DL:
-       case D_BL:
-       case D_AH:
-       case D_CH:
-       case D_DH:
-       case D_BH:
+       case REG_DL:
+       case REG_BL:
+       case REG_AH:
+       case REG_CH:
+       case REG_DH:
+       case REG_BH:
                return Yrb;
 
-       case D_CL:
+       case REG_CL:
                return Ycl;
 
-       case D_CX:
+       case REG_CX:
                return Ycx;
 
-       case D_DX:
-       case D_BX:
+       case REG_DX:
+       case REG_BX:
                return Yrx;
 
-       case D_R8:      /* not really Yrl */
-       case D_R9:
-       case D_R10:
-       case D_R11:
-       case D_R12:
-       case D_R13:
-       case D_R14:
-       case D_R15:
+       case REG_R8:    /* not really Yrl */
+       case REG_R9:
+       case REG_R10:
+       case REG_R11:
+       case REG_R12:
+       case REG_R13:
+       case REG_R14:
+       case REG_R15:
                if(ctxt->asmode != 64)
                        return Yxxx;
-       case D_SP:
-       case D_BP:
-       case D_SI:
-       case D_DI:
+       case REG_SP:
+       case REG_BP:
+       case REG_SI:
+       case REG_DI:
                return Yrl;
 
-       case D_F0+0:
+       case REG_F0+0:
                return  Yf0;
 
-       case D_F0+1:
-       case D_F0+2:
-       case D_F0+3:
-       case D_F0+4:
-       case D_F0+5:
-       case D_F0+6:
-       case D_F0+7:
+       case REG_F0+1:
+       case REG_F0+2:
+       case REG_F0+3:
+       case REG_F0+4:
+       case REG_F0+5:
+       case REG_F0+6:
+       case REG_F0+7:
                return  Yrf;
 
-       case D_M0+0:
-       case D_M0+1:
-       case D_M0+2:
-       case D_M0+3:
-       case D_M0+4:
-       case D_M0+5:
-       case D_M0+6:
-       case D_M0+7:
+       case REG_M0+0:
+       case REG_M0+1:
+       case REG_M0+2:
+       case REG_M0+3:
+       case REG_M0+4:
+       case REG_M0+5:
+       case REG_M0+6:
+       case REG_M0+7:
                return  Ymr;
 
-       case D_X0+0:
-       case D_X0+1:
-       case D_X0+2:
-       case D_X0+3:
-       case D_X0+4:
-       case D_X0+5:
-       case D_X0+6:
-       case D_X0+7:
-       case D_X0+8:
-       case D_X0+9:
-       case D_X0+10:
-       case D_X0+11:
-       case D_X0+12:
-       case D_X0+13:
-       case D_X0+14:
-       case D_X0+15:
+       case REG_X0+0:
+       case REG_X0+1:
+       case REG_X0+2:
+       case REG_X0+3:
+       case REG_X0+4:
+       case REG_X0+5:
+       case REG_X0+6:
+       case REG_X0+7:
+       case REG_X0+8:
+       case REG_X0+9:
+       case REG_X0+10:
+       case REG_X0+11:
+       case REG_X0+12:
+       case REG_X0+13:
+       case REG_X0+14:
+       case REG_X0+15:
                return  Yxr;
 
-       case D_NONE:
-               return Ynone;
-
-       case D_CS:      return  Ycs;
-       case D_SS:      return  Yss;
-       case D_DS:      return  Yds;
-       case D_ES:      return  Yes;
-       case D_FS:      return  Yfs;
-       case D_GS:      return  Ygs;
-       case D_TLS:     return  Ytls;
-
-       case D_GDTR:    return  Ygdtr;
-       case D_IDTR:    return  Yidtr;
-       case D_LDTR:    return  Yldtr;
-       case D_MSW:     return  Ymsw;
-       case D_TASK:    return  Ytask;
-
-       case D_CR+0:    return  Ycr0;
-       case D_CR+1:    return  Ycr1;
-       case D_CR+2:    return  Ycr2;
-       case D_CR+3:    return  Ycr3;
-       case D_CR+4:    return  Ycr4;
-       case D_CR+5:    return  Ycr5;
-       case D_CR+6:    return  Ycr6;
-       case D_CR+7:    return  Ycr7;
-       case D_CR+8:    return  Ycr8;
-
-       case D_DR+0:    return  Ydr0;
-       case D_DR+1:    return  Ydr1;
-       case D_DR+2:    return  Ydr2;
-       case D_DR+3:    return  Ydr3;
-       case D_DR+4:    return  Ydr4;
-       case D_DR+5:    return  Ydr5;
-       case D_DR+6:    return  Ydr6;
-       case D_DR+7:    return  Ydr7;
-
-       case D_TR+0:    return  Ytr0;
-       case D_TR+1:    return  Ytr1;
-       case D_TR+2:    return  Ytr2;
-       case D_TR+3:    return  Ytr3;
-       case D_TR+4:    return  Ytr4;
-       case D_TR+5:    return  Ytr5;
-       case D_TR+6:    return  Ytr6;
-       case D_TR+7:    return  Ytr7;
-
-       case D_EXTERN:
-       case D_STATIC:
-       case D_AUTO:
-       case D_PARAM:
-               return Ym;
-
-       case D_CONST:
-       case D_ADDR:
-               if(a->sym == nil) {
-                       v = a->offset;
-                       if(v == 0)
-                               return Yi0;
-                       if(v == 1)
-                               return Yi1;
-                       if(v >= -128 && v <= 127)
-                               return Yi8;
-                       l = v;
-                       if((vlong)l == v)
-                               return Ys32;    /* can sign extend */
-                       if((v>>32) == 0)
-                               return Yi32;    /* unsigned */
-                       return Yi64;
-               }
-               return Yi32;
+       case REG_CS:    return  Ycs;
+       case REG_SS:    return  Yss;
+       case REG_DS:    return  Yds;
+       case REG_ES:    return  Yes;
+       case REG_FS:    return  Yfs;
+       case REG_GS:    return  Ygs;
+       case REG_TLS:   return  Ytls;
+
+       case REG_GDTR:  return  Ygdtr;
+       case REG_IDTR:  return  Yidtr;
+       case REG_LDTR:  return  Yldtr;
+       case REG_MSW:   return  Ymsw;
+       case REG_TASK:  return  Ytask;
+
+       case REG_CR+0:  return  Ycr0;
+       case REG_CR+1:  return  Ycr1;
+       case REG_CR+2:  return  Ycr2;
+       case REG_CR+3:  return  Ycr3;
+       case REG_CR+4:  return  Ycr4;
+       case REG_CR+5:  return  Ycr5;
+       case REG_CR+6:  return  Ycr6;
+       case REG_CR+7:  return  Ycr7;
+       case REG_CR+8:  return  Ycr8;
+
+       case REG_DR+0:  return  Ydr0;
+       case REG_DR+1:  return  Ydr1;
+       case REG_DR+2:  return  Ydr2;
+       case REG_DR+3:  return  Ydr3;
+       case REG_DR+4:  return  Ydr4;
+       case REG_DR+5:  return  Ydr5;
+       case REG_DR+6:  return  Ydr6;
+       case REG_DR+7:  return  Ydr7;
+
+       case REG_TR+0:  return  Ytr0;
+       case REG_TR+1:  return  Ytr1;
+       case REG_TR+2:  return  Ytr2;
+       case REG_TR+3:  return  Ytr3;
+       case REG_TR+4:  return  Ytr4;
+       case REG_TR+5:  return  Ytr5;
+       case REG_TR+6:  return  Ytr6;
+       case REG_TR+7:  return  Ytr7;
 
-       case D_BRANCH:
-               return Ybr;
        }
        return Yxxx;
 }
@@ -2140,27 +2153,27 @@ asmidx(Link *ctxt, int scale, int index, int base)
        default:
                goto bad;
 
-       case D_NONE:
+       case REG_NONE:
                i = 4 << 3;
                goto bas;
 
-       case D_R8:
-       case D_R9:
-       case D_R10:
-       case D_R11:
-       case D_R12:
-       case D_R13:
-       case D_R14:
-       case D_R15:
+       case REG_R8:
+       case REG_R9:
+       case REG_R10:
+       case REG_R11:
+       case REG_R12:
+       case REG_R13:
+       case REG_R14:
+       case REG_R15:
                if(ctxt->asmode != 64)
                        goto bad;
-       case D_AX:
-       case D_CX:
-       case D_DX:
-       case D_BX:
-       case D_BP:
-       case D_SI:
-       case D_DI:
+       case REG_AX:
+       case REG_CX:
+       case REG_DX:
+       case REG_BX:
+       case REG_BP:
+       case REG_SI:
+       case REG_DI:
                i = reg[index] << 3;
                break;
        }
@@ -2183,27 +2196,27 @@ bas:
        switch(base) {
        default:
                goto bad;
-       case D_NONE:    /* must be mod=00 */
+       case REG_NONE:  /* must be mod=00 */
                i |= 5;
                break;
-       case D_R8:
-       case D_R9:
-       case D_R10:
-       case D_R11:
-       case D_R12:
-       case D_R13:
-       case D_R14:
-       case D_R15:
+       case REG_R8:
+       case REG_R9:
+       case REG_R10:
+       case REG_R11:
+       case REG_R12:
+       case REG_R13:
+       case REG_R14:
+       case REG_R15:
                if(ctxt->asmode != 64)
                        goto bad;
-       case D_AX:
-       case D_CX:
-       case D_DX:
-       case D_BX:
-       case D_SP:
-       case D_BP:
-       case D_SI:
-       case D_DI:
+       case REG_AX:
+       case REG_CX:
+       case REG_DX:
+       case REG_BX:
+       case REG_SP:
+       case REG_BP:
+       case REG_SI:
+       case REG_DI:
                i |= reg[base];
                break;
        }
@@ -2277,8 +2290,6 @@ relput8(Prog *p, Addr *a)
 static vlong
 vaddr(Link *ctxt, Prog *p, Addr *a, Reloc *r)
 {
-       int t;
-       vlong v;
        LSym *s;
        
        USED(p);
@@ -2286,13 +2297,9 @@ vaddr(Link *ctxt, Prog *p, Addr *a, Reloc *r)
        if(r != nil)
                memset(r, 0, sizeof *r);
 
-       t = a->type;
-       v = a->offset;
-       if(t == D_ADDR)
-               t = a->index;
-       switch(t) {
-       case D_STATIC:
-       case D_EXTERN:
+       switch(a->name) {
+       case NAME_STATIC:
+       case NAME_EXTERN:
                s = a->sym;
                if(r == nil) {
                        ctxt->diag("need reloc for %D", a);
@@ -2307,16 +2314,16 @@ vaddr(Link *ctxt, Prog *p, Addr *a, Reloc *r)
                }
                r->off = -1;    // caller must fill in
                r->sym = s;
-               r->add = v;
-               v = 0;
+               r->add = a->offset;
                if(s->type == STLSBSS) {
                        r->xadd = r->add - r->siz;
                        r->type = R_TLS;
                        r->xsym = s;
                }
-               break;
+               return 0;
+       }
        
-       case D_INDIR+D_TLS:
+       if((a->type == TYPE_MEM || a->type == TYPE_ADDR) && a->reg == REG_TLS) {
                if(r == nil) {
                        ctxt->diag("need reloc for %D", a);
                        sysfatal("reloc");
@@ -2324,18 +2331,18 @@ vaddr(Link *ctxt, Prog *p, Addr *a, Reloc *r)
                r->type = R_TLS_LE;
                r->siz = 4;
                r->off = -1;    // caller must fill in
-               r->add = v;
-               v = 0;
-               break;
+               r->add = a->offset;
+               return 0;
        }
-       return v;
+
+       return a->offset;
 }
 
 static void
 asmandsz(Link *ctxt, Prog *p, Addr *a, int r, int rex, int m64)
 {
        int32 v;
-       int t, scale;
+       int base;
        Reloc rel;
 
        USED(m64);
@@ -2343,80 +2350,88 @@ asmandsz(Link *ctxt, Prog *p, Addr *a, int r, int rex, int m64)
 
        rex &= (0x40 | Rxr);
        v = a->offset;
-       t = a->type;
        rel.siz = 0;
-       if(a->index != D_NONE && a->index != D_TLS) {
-               if(t < D_INDIR) { 
-                       switch(t) {
-                       default:
+
+       switch(a->type) {
+       case TYPE_ADDR:
+               if(a->name == NAME_NONE)
+                       ctxt->diag("unexpected TYPE_ADDR with NAME_NONE");
+               if(a->index == REG_TLS)
+                       ctxt->diag("unexpected TYPE_ADDR with index==REG_TLS");
+               goto bad;
+       
+       case TYPE_REG:
+               if(a->reg < REG_AL || REG_X0+15 < a->reg)
+                       goto bad;
+               if(v)
+                       goto bad;
+               *ctxt->andptr++ = (3 << 6) | (reg[a->reg] << 0) | (r << 3);
+               ctxt->rexflag |= (regrex[a->reg] & (0x40 | Rxb)) | rex;
+               return;
+       }
+
+       if(a->type != TYPE_MEM)
+               goto bad;
+
+       if(a->index != REG_NONE && a->index != REG_TLS) {
+               base = a->reg;
+               switch(a->name) {
+               case NAME_EXTERN:
+               case NAME_STATIC:
+                       if(!isextern(a->sym))
                                goto bad;
-                       case D_EXTERN:
-                       case D_STATIC:
-                               if(!isextern(a->sym))
-                                       goto bad;
-                               t = D_NONE;
-                               v = vaddr(ctxt, p, a, &rel);
-                               break;
-                       case D_AUTO:
-                       case D_PARAM:
-                               t = D_SP;
-                               break;
-                       }
-               } else
-                       t -= D_INDIR;
-               ctxt->rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
-               if(t == D_NONE) {
+                       base = REG_NONE;
+                       v = vaddr(ctxt, p, a, &rel);
+                       break;
+               case NAME_AUTO:
+               case NAME_PARAM:
+                       base = REG_SP;
+                       break;
+               }
+               
+               ctxt->rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[base] & Rxb) | rex;
+               if(base == REG_NONE) {
                        *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
-                       asmidx(ctxt, a->scale, a->index, t);
+                       asmidx(ctxt, a->scale, a->index, base);
                        goto putrelv;
                }
-               if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
+               if(v == 0 && rel.siz == 0 && base != REG_BP && base != REG_R13) {
                        *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
-                       asmidx(ctxt, a->scale, a->index, t);
+                       asmidx(ctxt, a->scale, a->index, base);
                        return;
                }
                if(v >= -128 && v < 128 && rel.siz == 0) {
                        *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
-                       asmidx(ctxt, a->scale, a->index, t);
+                       asmidx(ctxt, a->scale, a->index, base);
                        *ctxt->andptr++ = v;
                        return;
                }
                *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
-               asmidx(ctxt, a->scale, a->index, t);
+               asmidx(ctxt, a->scale, a->index, base);
                goto putrelv;
        }
-       if(t >= D_AL && t <= D_X0+15) {
-               if(v)
-                       goto bad;
-               *ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
-               ctxt->rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
-               return;
-       }
-       
-       scale = a->scale;
-       if(t < D_INDIR) {
-               switch(a->type) {
-               default:
-                       goto bad;
-               case D_STATIC:
-               case D_EXTERN:
-                       t = D_NONE;
-                       v = vaddr(ctxt, p, a, &rel);
-                       break;
-               case D_AUTO:
-               case D_PARAM:
-                       t = D_SP;
-                       break;
-               }
-               scale = 1;
-       } else
-               t -= D_INDIR;
-       if(t == D_TLS)
+
+       base = a->reg;
+       switch(a->name) {
+       case NAME_STATIC:
+       case NAME_EXTERN:
+               if(a->sym == nil)
+                       ctxt->diag("bad addr: %P", p);
+               base = REG_NONE;
                v = vaddr(ctxt, p, a, &rel);
+               break;
+       case NAME_AUTO:
+       case NAME_PARAM:
+               base = REG_SP;
+               break;
+       }
 
-       ctxt->rexflag |= (regrex[t] & Rxb) | rex;
-       if(t == D_NONE || (D_CS <= t && t <= D_GS) || t == D_TLS) {
-               if((a->sym == nil || !isextern(a->sym)) && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || ctxt->asmode != 64) {
+       if(base == REG_TLS)
+               v = vaddr(ctxt, p, a, &rel);
+       
+       ctxt->rexflag |= (regrex[base] & Rxb) | rex;
+       if(base == REG_NONE || (REG_CS <= base && base <= REG_GS) || base == REG_TLS) {
+               if((a->sym == nil || !isextern(a->sym)) && base == REG_NONE && (a->name == NAME_STATIC || a->name == NAME_EXTERN) || ctxt->asmode != 64) {
                        *ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
                        goto putrelv;
                }
@@ -2425,24 +2440,26 @@ asmandsz(Link *ctxt, Prog *p, Addr *a, int r, int rex, int m64)
                *ctxt->andptr++ = (0 << 6) | (4 << 3) | (5 << 0);       /* DS:d32 */
                goto putrelv;
        }
-       if(t == D_SP || t == D_R12) {
+
+       if(base == REG_SP || base == REG_R12) {
                if(v == 0) {
-                       *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
-                       asmidx(ctxt, scale, D_NONE, t);
+                       *ctxt->andptr++ = (0 << 6) | (reg[base] << 0) | (r << 3);
+                       asmidx(ctxt, a->scale, REG_NONE, base);
                        return;
                }
                if(v >= -128 && v < 128) {
-                       *ctxt->andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
-                       asmidx(ctxt, scale, D_NONE, t);
+                       *ctxt->andptr++ = (1 << 6) | (reg[base] << 0) | (r << 3);
+                       asmidx(ctxt, a->scale, REG_NONE, base);
                        *ctxt->andptr++ = v;
                        return;
                }
-               *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
-               asmidx(ctxt, scale, D_NONE, t);
+               *ctxt->andptr++ = (2 << 6) | (reg[base] << 0) | (r << 3);
+               asmidx(ctxt, a->scale, REG_NONE, base);
                goto putrelv;
        }
-       if(t >= D_AX && t <= D_R15) {
-               if(a->index == D_TLS) {
+
+       if(REG_AX <= base && base <= REG_R15) {
+               if(a->index == REG_TLS) {
                        memset(&rel, 0, sizeof rel);
                        rel.type = R_TLS_IE;
                        rel.siz = 4;
@@ -2450,19 +2467,20 @@ asmandsz(Link *ctxt, Prog *p, Addr *a, int r, int rex, int m64)
                        rel.add = v;
                        v = 0;
                }
-               if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
-                       *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+               if(v == 0 && rel.siz == 0 && base != REG_BP && base != REG_R13) {
+                       *ctxt->andptr++ = (0 << 6) | (reg[base] << 0) | (r << 3);
                        return;
                }
                if(v >= -128 && v < 128 && rel.siz == 0) {
-                       ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+                       ctxt->andptr[0] = (1 << 6) | (reg[base] << 0) | (r << 3);
                        ctxt->andptr[1] = v;
                        ctxt->andptr += 2;
                        return;
                }
-               *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+               *ctxt->andptr++ = (2 << 6) | (reg[base] << 0) | (r << 3);
                goto putrelv;
        }
+
        goto bad;
        
 putrelv:
@@ -2489,7 +2507,7 @@ bad:
 static void
 asmand(Link *ctxt, Prog *p, Addr *a, Addr *ra)
 {
-       asmandsz(ctxt, p, a, reg[ra->type], regrex[ra->type], 0);
+       asmandsz(ctxt, p, a, reg[ra->reg], regrex[ra->reg], 0);
 }
 
 static void
@@ -2501,8 +2519,8 @@ asmando(Link *ctxt, Prog *p, Addr *a, int o)
 static void
 bytereg(Addr *a, uint8 *t)
 {
-       if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) {
-               a->type = D_AL + (a->type-D_AX);
+       if(a->type == TYPE_REG && a->index == REG_NONE && (REG_AX <= a->reg && a->reg <= REG_R15)) {
+               a->reg += REG_AL - REG_AX;
                *t = 0;
        }
 }
@@ -2647,15 +2665,13 @@ static Movtab   ymovtab[] =
 static int
 isax(Addr *a)
 {
-
-       switch(a->type) {
-       case D_AX:
-       case D_AL:
-       case D_AH:
-       case D_INDIR+D_AX:
+       switch(a->reg) {
+       case REG_AX:
+       case REG_AL:
+       case REG_AH:
                return 1;
        }
-       if(a->index == D_AX)
+       if(a->index == REG_AX)
                return 1;
        return 0;
 }
@@ -2663,27 +2679,28 @@ isax(Addr *a)
 static void
 subreg(Prog *p, int from, int to)
 {
-
-       if(0 /*debug['Q']*/)
+       if(0 /* debug['Q'] */)
                print("\n%P     s/%R/%R/\n", p, from, to);
 
-       if(p->from.type == from)
-               p->from.type = to;
-       if(p->to.type == from)
-               p->to.type = to;
+       if(p->from.reg == from) {
+               p->from.reg = to;
+               p->ft = 0;
+       }
+       if(p->to.reg == from) {
+               p->to.reg = to;
+               p->tt = 0;
+       }
 
-       if(p->from.index == from)
+       if(p->from.index == from) {
                p->from.index = to;
-       if(p->to.index == from)
+               p->ft = 0;
+       }
+       if(p->to.index == from) {
                p->to.index = to;
+               p->tt = 0;
+       }
 
-       from += D_INDIR;
-       if(p->from.type == from)
-               p->from.type = to+D_INDIR;
-       if(p->to.type == from)
-               p->to.type = to+D_INDIR;
-
-       if(0 /*debug['Q']*/)
+       if(0 /* debug['Q'] */)
                print("%P\n", p);
 }
 
@@ -2730,7 +2747,7 @@ doasm(Link *ctxt, Prog *p)
                ctxt->diag("asmins: missing op %P", p);
                return;
        }
-       
+
        pre = prefixof(ctxt, &p->from);
        if(pre)
                *ctxt->andptr++ = pre;
@@ -2878,13 +2895,11 @@ found:
 
        case Zaut_r:
                *ctxt->andptr++ = 0x8d; /* leal */
-               if(p->from.type != D_ADDR)
+               if(p->from.type != TYPE_ADDR)
                        ctxt->diag("asmins: Zaut sb type ADDR");
-               p->from.type = p->from.index;
-               p->from.index = D_NONE;
+               p->from.type = TYPE_MEM;
                asmand(ctxt, p, &p->from, &p->to);
-               p->from.index = p->from.type;
-               p->from.type = D_ADDR;
+               p->from.type = TYPE_ADDR;
                break;
 
        case Zm_o:
@@ -2959,14 +2974,14 @@ found:
                break;
 
        case Zib_rp:
-               ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
-               *ctxt->andptr++ = op + reg[p->to.type];
+               ctxt->rexflag |= regrex[p->to.reg] & (Rxb|0x40);
+               *ctxt->andptr++ = op + reg[p->to.reg];
                *ctxt->andptr++ = vaddr(ctxt, p, &p->from, nil);
                break;
 
        case Zil_rp:
-               ctxt->rexflag |= regrex[p->to.type] & Rxb;
-               *ctxt->andptr++ = op + reg[p->to.type];
+               ctxt->rexflag |= regrex[p->to.reg] & Rxb;
+               *ctxt->andptr++ = op + reg[p->to.reg];
                if(o->prefix == Pe) {
                        v = vaddr(ctxt, p, &p->from, nil);
                        *ctxt->andptr++ = v;
@@ -2978,7 +2993,7 @@ found:
 
        case Zo_iw:
                *ctxt->andptr++ = op;
-               if(p->from.type != D_NONE){
+               if(p->from.type != TYPE_NONE){
                        v = vaddr(ctxt, p, &p->from, nil);
                        *ctxt->andptr++ = v;
                        *ctxt->andptr++ = v>>8;
@@ -2992,8 +3007,8 @@ found:
                        //p->mark |= 0100;
                        //print("zero: %llux %P\n", v, p);
                        ctxt->rexflag &= ~(0x40|Rxw);
-                       ctxt->rexflag |= regrex[p->to.type] & Rxb;
-                       *ctxt->andptr++ = 0xb8 + reg[p->to.type];
+                       ctxt->rexflag |= regrex[p->to.reg] & Rxb;
+                       *ctxt->andptr++ = 0xb8 + reg[p->to.reg];
                        if(rel.type != 0) {
                                r = addrel(ctxt->cursym);
                                *r = rel;
@@ -3008,8 +3023,8 @@ found:
                        put4(ctxt, v);
                }else{  /* need all 8 */
                        //print("all: %llux %P\n", v, p);
-                       ctxt->rexflag |= regrex[p->to.type] & Rxb;
-                       *ctxt->andptr++ = op + reg[p->to.type];
+                       ctxt->rexflag |= regrex[p->to.reg] & Rxb;
+                       *ctxt->andptr++ = op + reg[p->to.reg];
                        if(rel.type != 0) {
                                r = addrel(ctxt->cursym);
                                *r = rel;
@@ -3073,13 +3088,13 @@ found:
                break;
 
        case Z_rp:
-               ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
-               *ctxt->andptr++ = op + reg[p->to.type];
+               ctxt->rexflag |= regrex[p->to.reg] & (Rxb|0x40);
+               *ctxt->andptr++ = op + reg[p->to.reg];
                break;
 
        case Zrp_:
-               ctxt->rexflag |= regrex[p->from.type] & (Rxb|0x40);
-               *ctxt->andptr++ = op + reg[p->from.type];
+               ctxt->rexflag |= regrex[p->from.reg] & (Rxb|0x40);
+               *ctxt->andptr++ = op + reg[p->from.reg];
                break;
 
        case Zclr:
@@ -3239,44 +3254,44 @@ bad:
                 * instruction with the operands renamed.
                 */
                pp = *p;
-               z = p->from.type;
-               if(z >= D_BP && z <= D_DI) {
-                       if(isax(&p->to) || p->to.type == D_NONE) {
+               z = p->from.reg;
+               if(p->from.type == TYPE_REG && z >= REG_BP && z <= REG_DI) {
+                       if(isax(&p->to) || p->to.type == TYPE_NONE) {
                                // We certainly don't want to exchange
                                // with AX if the op is MUL or DIV.
                                *ctxt->andptr++ = 0x87;                 /* xchg lhs,bx */
-                               asmando(ctxt, p, &p->from, reg[D_BX]);
-                               subreg(&pp, z, D_BX);
+                               asmando(ctxt, p, &p->from, reg[REG_BX]);
+                               subreg(&pp, z, REG_BX);
                                doasm(ctxt, &pp);
                                *ctxt->andptr++ = 0x87;                 /* xchg lhs,bx */
-                               asmando(ctxt, p, &p->from, reg[D_BX]);
+                               asmando(ctxt, p, &p->from, reg[REG_BX]);
                        } else {
                                *ctxt->andptr++ = 0x90 + reg[z];                /* xchg lsh,ax */
-                               subreg(&pp, z, D_AX);
+                               subreg(&pp, z, REG_AX);
                                doasm(ctxt, &pp);
                                *ctxt->andptr++ = 0x90 + reg[z];                /* xchg lsh,ax */
                        }
                        return;
                }
-               z = p->to.type;
-               if(z >= D_BP && z <= D_DI) {
+               z = p->to.reg;
+               if(p->to.type == TYPE_REG && z >= REG_BP && z <= REG_DI) {
                        if(isax(&p->from)) {
                                *ctxt->andptr++ = 0x87;                 /* xchg rhs,bx */
-                               asmando(ctxt, p, &p->to, reg[D_BX]);
-                               subreg(&pp, z, D_BX);
+                               asmando(ctxt, p, &p->to, reg[REG_BX]);
+                               subreg(&pp, z, REG_BX);
                                doasm(ctxt, &pp);
                                *ctxt->andptr++ = 0x87;                 /* xchg rhs,bx */
-                               asmando(ctxt, p, &p->to, reg[D_BX]);
+                               asmando(ctxt, p, &p->to, reg[REG_BX]);
                        } else {
                                *ctxt->andptr++ = 0x90 + reg[z];                /* xchg rsh,ax */
-                               subreg(&pp, z, D_AX);
+                               subreg(&pp, z, REG_AX);
                                doasm(ctxt, &pp);
                                *ctxt->andptr++ = 0x90 + reg[z];                /* xchg rsh,ax */
                        }
                        return;
                }
        }
-       ctxt->diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
+       ctxt->diag("doasm: notfound ft=%d tt=%d %P %d %d", p->ft, p->tt, p, oclass(ctxt, &p->from), oclass(ctxt, &p->to));
        return;
 
 mfound:
@@ -3304,14 +3319,14 @@ mfound:
                *ctxt->andptr++ = t[0];
                *ctxt->andptr++ = t[1];
                asmando(ctxt, p, &p->to, t[2]);
-               ctxt->rexflag |= regrex[p->from.type] & (Rxr|0x40);
+               ctxt->rexflag |= regrex[p->from.reg] & (Rxr|0x40);
                break;
 
        case 4: /* m,r - 2op */
                *ctxt->andptr++ = t[0];
                *ctxt->andptr++ = t[1];
                asmando(ctxt, p, &p->from, t[2]);
-               ctxt->rexflag |= regrex[p->to.type] & (Rxr|0x40);
+               ctxt->rexflag |= regrex[p->to.reg] & (Rxr|0x40);
                break;
 
        case 5: /* load full pointer, trash heap */
@@ -3320,21 +3335,21 @@ mfound:
                switch(p->to.index) {
                default:
                        goto bad;
-               case D_DS:
+               case REG_DS:
                        *ctxt->andptr++ = 0xc5;
                        break;
-               case D_SS:
+               case REG_SS:
                        *ctxt->andptr++ = 0x0f;
                        *ctxt->andptr++ = 0xb2;
                        break;
-               case D_ES:
+               case REG_ES:
                        *ctxt->andptr++ = 0xc4;
                        break;
-               case D_FS:
+               case REG_FS:
                        *ctxt->andptr++ = 0x0f;
                        *ctxt->andptr++ = 0xb4;
                        break;
-               case D_GS:
+               case REG_GS:
                        *ctxt->andptr++ = 0x0f;
                        *ctxt->andptr++ = 0xb5;
                        break;
@@ -3352,22 +3367,26 @@ mfound:
                        *ctxt->andptr++ = Pe;
                        t++;
                }
-               z = p->from.type;
-               switch(z) {
+               switch(p->from.type) {
                default:
                        goto bad;
-               case D_CONST:
+               case TYPE_CONST:
                        *ctxt->andptr++ = 0x0f;
                        *ctxt->andptr++ = t[0];
                        asmandsz(ctxt, p, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
                        *ctxt->andptr++ = p->from.offset;
                        break;
-               case D_CL:
-               case D_CX:
-                       *ctxt->andptr++ = 0x0f;
-                       *ctxt->andptr++ = t[1];
-                       asmandsz(ctxt, p, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
-                       break;
+               case TYPE_REG:
+                       switch(p->from.reg) {
+                       default:
+                               goto bad;
+                       case REG_CL:
+                       case REG_CX:
+                               *ctxt->andptr++ = 0x0f;
+                               *ctxt->andptr++ = t[1];
+                               asmandsz(ctxt, p, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+                               break;
+                       }
                }
                break;
        
@@ -3384,10 +3403,11 @@ mfound:
                        if(ctxt->plan9privates == nil)
                                ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
                        memset(&pp.from, 0, sizeof pp.from);
-                       pp.from.type = D_EXTERN;
+                       pp.from.type = TYPE_MEM;
+                       pp.from.name = NAME_EXTERN;
                        pp.from.sym = ctxt->plan9privates;
                        pp.from.offset = 0;
-                       pp.from.index = D_NONE;
+                       pp.from.index = REG_NONE;
                        ctxt->rexflag |= Pw;
                        *ctxt->andptr++ = 0x8B;
                        asmand(ctxt, p, &pp.from, &p->to);
@@ -3396,9 +3416,11 @@ mfound:
                case Hsolaris: // TODO(rsc): Delete Hsolaris from list. Should not use this code. See progedit in obj6.c.
                        // TLS base is 0(FS).
                        pp.from = p->from;
-                       pp.from.type = D_INDIR+D_NONE;
+                       pp.from.type = TYPE_MEM;
+                       pp.from.name = NAME_NONE;
+                       pp.from.reg = REG_NONE;
                        pp.from.offset = 0;
-                       pp.from.index = D_NONE;
+                       pp.from.index = REG_NONE;
                        pp.from.scale = 0;
                        ctxt->rexflag |= Pw;
                        *ctxt->andptr++ = 0x64; // FS
@@ -3409,9 +3431,11 @@ mfound:
                case Hwindows:
                        // Windows TLS base is always 0x28(GS).
                        pp.from = p->from;
-                       pp.from.type = D_INDIR+D_GS;
+                       pp.from.type = TYPE_MEM;
+                       pp.from.name = NAME_NONE;
+                       pp.from.reg = REG_GS;
                        pp.from.offset = 0x28;
-                       pp.from.index = D_NONE;
+                       pp.from.index = REG_NONE;
                        pp.from.scale = 0;
                        ctxt->rexflag |= Pw;
                        *ctxt->andptr++ = 0x65; // GS
@@ -3454,9 +3478,9 @@ static uchar naclstos[] = {
 static void
 nacltrunc(Link *ctxt, int reg)
 {      
-       if(reg >= D_R8)
+       if(reg >= REG_R8)
                *ctxt->andptr++ = 0x45;
-       reg = (reg - D_AX) & 7;
+       reg = (reg - REG_AX) & 7;
        *ctxt->andptr++ = 0x89;
        *ctxt->andptr++ = (3<<6) | (reg<<3) | reg;
 }
@@ -3494,9 +3518,9 @@ asmins(Link *ctxt, Prog *p)
                        return;
                }
                if(p->as != ALEAQ && p->as != ALEAL) {
-                       if(p->from.index != D_NONE && p->from.scale > 0)
+                       if(p->from.index != TYPE_NONE && p->from.scale > 0)
                                nacltrunc(ctxt, p->from.index);
-                       if(p->to.index != D_NONE && p->to.scale > 0)
+                       if(p->to.index != TYPE_NONE && p->to.scale > 0)
                                nacltrunc(ctxt, p->to.index);
                }
                switch(p->as) {
@@ -3506,26 +3530,26 @@ asmins(Link *ctxt, Prog *p)
                        return;
                case ACALL:
                case AJMP:
-                       if(D_AX <= p->to.type && p->to.type <= D_DI) {
+                       if(p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_DI) {
                                // ANDL $~31, reg
                                *ctxt->andptr++ = 0x83;
-                               *ctxt->andptr++ = 0xe0 | (p->to.type - D_AX);
+                               *ctxt->andptr++ = 0xe0 | (p->to.reg - REG_AX);
                                *ctxt->andptr++ = 0xe0;
                                // ADDQ R15, reg
                                *ctxt->andptr++ = 0x4c;
                                *ctxt->andptr++ = 0x01;
-                               *ctxt->andptr++ = 0xf8 | (p->to.type - D_AX);
+                               *ctxt->andptr++ = 0xf8 | (p->to.reg - REG_AX);
                        }
-                       if(D_R8 <= p->to.type && p->to.type <= D_R15) {
+                       if(p->to.type == TYPE_REG && REG_R8 <= p->to.reg && p->to.reg <= REG_R15) {
                                // ANDL $~31, reg
                                *ctxt->andptr++ = 0x41;
                                *ctxt->andptr++ = 0x83;
-                               *ctxt->andptr++ = 0xe0 | (p->to.type - D_R8);
+                               *ctxt->andptr++ = 0xe0 | (p->to.reg - REG_R8);
                                *ctxt->andptr++ = 0xe0;
                                // ADDQ R15, reg
                                *ctxt->andptr++ = 0x4d;
                                *ctxt->andptr++ = 0x01;
-                               *ctxt->andptr++ = 0xf8 | (p->to.type - D_R8);
+                               *ctxt->andptr++ = 0xf8 | (p->to.reg - REG_R8);
                        }
                        break;
                case AINT:
@@ -3599,13 +3623,13 @@ asmins(Link *ctxt, Prog *p)
                        r->add -= p->pc + n - (r->off + r->siz);
        }
 
-       if(ctxt->headtype == Hnacl && p->as != ACMPL && p->as != ACMPQ) {
-               switch(p->to.type) {
-               case D_SP:
+       if(ctxt->headtype == Hnacl && p->as != ACMPL && p->as != ACMPQ && p->to.type == TYPE_REG) {
+               switch(p->to.reg) {
+               case REG_SP:
                        memmove(ctxt->andptr, naclspfix, sizeof naclspfix);
                        ctxt->andptr += sizeof naclspfix;
                        break;
-               case D_BP:
+               case REG_BP:
                        memmove(ctxt->andptr, naclbpfix, sizeof naclbpfix);
                        ctxt->andptr += sizeof naclbpfix;
                        break;
index 3bb761b9ae08a325f0ea479a5ce2c7c4b6a40a64..1678958f2f9d589152af2147bd45535727f91c5d 100644 (file)
@@ -53,6 +53,8 @@ struct        Optab
        uchar   op[13];
 };
 
+static Optab*  opindex[ALAST+1];
+
 enum
 {
        Yxxx            = 0,
@@ -76,6 +78,7 @@ enum
        Ym,
        Ybr,
        Ycol,
+       Ytextsize,
        Ytls,
 
        Ycs,    Yss,    Yds,    Yes,    Yfs,    Ygs,
@@ -140,7 +143,7 @@ enum
 };
 
 static uchar   ycover[Ymax*Ymax];
-static int     reg[D_NONE];
+static int     reg[MAXREG];
 static void    asmins(Link *ctxt, Prog *p);
 
 static uchar   ynone[] =
@@ -150,7 +153,7 @@ static uchar        ynone[] =
 };
 static uchar   ytext[] =
 {
-       Ymb,    Yi32,   Zpseudo,1,
+       Ymb,    Ytextsize,      Zpseudo,1,
        0
 };
 static uchar   ynop[] =
@@ -674,8 +677,6 @@ static Optab optab[] =
        { ADIVW,        ydivl,  Pe, {0xf7,(06)} },
        { AENTER },                             /* botch */
        { AGLOBL },
-       { AGOK },
-       { AHISTORY },
        { AHLT,         ynone,  Px, {0xf4} },
        { AIDIVB,       ydivb,  Pb, {0xf6,(07)} },
        { AIDIVL,       ydivl,  Px, {0xf7,(07)} },
@@ -748,14 +749,13 @@ static Optab optab[] =
        { AMULB,        ydivb,  Pb, {0xf6,(04)} },
        { AMULL,        ydivl,  Px, {0xf7,(04)} },
        { AMULW,        ydivl,  Pe, {0xf7,(04)} },
-       { ANAME },
        { ANEGB,        yscond, Px, {0xf6,(03)} },
-       { ANEGL,        yscond, Px, {0xf7,(03)} },
-       { ANEGW,        yscond, Pe, {0xf7,(03)} },
+       { ANEGL,        yscond, Px, {0xf7,(03)} }, // TODO(rsc): yscond is wrong here.
+       { ANEGW,        yscond, Pe, {0xf7,(03)} }, // TODO(rsc): yscond is wrong here.
        { ANOP,         ynop,   Px, {0,0} },
        { ANOTB,        yscond, Px, {0xf6,(02)} },
-       { ANOTL,        yscond, Px, {0xf7,(02)} },
-       { ANOTW,        yscond, Pe, {0xf7,(02)} },
+       { ANOTL,        yscond, Px, {0xf7,(02)} }, // TODO(rsc): yscond is wrong here.
+       { ANOTW,        yscond, Pe, {0xf7,(02)} }, // TODO(rsc): yscond is wrong here.
        { AORB,         yxorb,  Pb, {0x0c,0x80,(01),0x08,0x0a} },
        { AORL,         yxorl,  Px, {0x83,(01),0x0d,0x81,(01),0x09,0x0b} },
        { AORW,         yxorl,  Pe, {0x83,(01),0x0d,0x81,(01),0x09,0x0b} },
@@ -967,13 +967,10 @@ static Optab optab[] =
        { AFYL2X,       ynone,  Px, {0xd9, 0xf1} },
        { AFYL2XP1,     ynone,  Px, {0xd9, 0xf9} },
        { AEND },
-       { ADYNT_ },
-       { AINIT_ },
-       { ASIGNAME },
        { ACMPXCHGB,    yrb_mb, Pm, {0xb0} },
        { ACMPXCHGL,    yrl_ml, Pm, {0xb1} },
        { ACMPXCHGW,    yrl_ml, Pm, {0xb1} },
-       { ACMPXCHG8B,   yscond, Pm, {0xc7,(01)} },
+       { ACMPXCHG8B,   yscond, Pm, {0xc7,(01)} }, // TODO(rsc): yscond is wrong here.
 
        { ACPUID,       ynone,  Pm, {0xa2} },
        { ARDTSC,       ynone,  Pm, {0x31} },
@@ -1230,16 +1227,12 @@ span8(Link *ctxt, LSym *s)
                instinit();
 
        for(p = s->text; p != nil; p = p->link) {
-               n = 0;
-               if(p->to.type == D_BRANCH)
+               if(p->to.type == TYPE_BRANCH)
                        if(p->pcond == nil)
                                p->pcond = p;
-               if((q = p->pcond) != nil)
-                       if(q->back != 2)
-                               n = 1;
-               p->back = n;
                if(p->as == AADJSP) {
-                       p->to.type = D_SP;
+                       p->to.type = TYPE_REG;
+                       p->to.reg = REG_SP;
                        v = -p->from.offset;
                        p->from.offset = v;
                        p->as = AADDL;
@@ -1259,7 +1252,8 @@ span8(Link *ctxt, LSym *s)
                        p->back |= 1;   // backward jump
 
                if(p->as == AADJSP) {
-                       p->to.type = D_SP;
+                       p->to.type = TYPE_REG;
+                       p->to.reg = REG_SP;
                        v = -p->from.offset;
                        p->from.offset = v;
                        p->as = AADDL;
@@ -1382,11 +1376,14 @@ span8(Link *ctxt, LSym *s)
 static void
 instinit(void)
 {
-       int i;
+       int i, c;
 
-       for(i=1; optab[i].as; i++)
-               if(i != optab[i].as)
-                       sysfatal("phase error in optab: at %A found %A", i, optab[i].as);
+       for(i=1; optab[i].as; i++) {
+               c = optab[i].as;
+               if(opindex[c] != nil)
+                       sysfatal("phase error in optab: %d (%A)", i, c);
+               opindex[c] = &optab[i];
+       }
 
        for(i=0; i<Ymax; i++)
                ycover[i*Ymax + i] = 1;
@@ -1437,196 +1434,218 @@ instinit(void)
        ycover[Ym*Ymax + Yxm] = 1;
        ycover[Yxr*Ymax + Yxm] = 1;
 
-       for(i=0; i<D_NONE; i++) {
+       for(i=0; i<MAXREG; i++) {
                reg[i] = -1;
-               if(i >= D_AL && i <= D_BH)
-                       reg[i] = (i-D_AL) & 7;
-               if(i >= D_AX && i <= D_DI)
-                       reg[i] = (i-D_AX) & 7;
-               if(i >= D_F0 && i <= D_F0+7)
-                       reg[i] = (i-D_F0) & 7;
-               if(i >= D_X0 && i <= D_X0+7)
-                       reg[i] = (i-D_X0) & 7;
+               if(i >= REG_AL && i <= REG_BH)
+                       reg[i] = (i-REG_AL) & 7;
+               if(i >= REG_AX && i <= REG_DI)
+                       reg[i] = (i-REG_AX) & 7;
+               if(i >= REG_F0 && i <= REG_F0+7)
+                       reg[i] = (i-REG_F0) & 7;
+               if(i >= REG_X0 && i <= REG_X0+7)
+                       reg[i] = (i-REG_X0) & 7;
        }
 }
 
 static int
 prefixof(Link *ctxt, Addr *a)
 {
-       switch(a->type) {
-       case D_INDIR+D_CS:
-               return 0x2e;
-       case D_INDIR+D_DS:
-               return 0x3e;
-       case D_INDIR+D_ES:
-               return 0x26;
-       case D_INDIR+D_FS:
-               return 0x64;
-       case D_INDIR+D_GS:
-               return 0x65;
-       case D_INDIR+D_TLS:
-               // NOTE: Systems listed here should be only systems that
-               // support direct TLS references like 8(TLS) implemented as
-               // direct references from FS or GS. Systems that require
-               // the initial-exec model, where you load the TLS base into
-               // a register and then index from that register, do not reach
-               // this code and should not be listed.
-               switch(ctxt->headtype) {
-               default:
-                       sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
-               case Hdarwin:
-               case Hdragonfly:
-               case Hfreebsd:
-               case Hnetbsd:
-               case Hopenbsd:
-                       return 0x65; // GS
+       if(a->type == TYPE_MEM && a->name == NAME_NONE) {
+               switch(a->reg) {
+               case REG_CS:
+                       return 0x2e;
+               case REG_DS:
+                       return 0x3e;
+               case REG_ES:
+                       return 0x26;
+               case REG_FS:
+                       return 0x64;
+               case REG_GS:
+                       return 0x65;
+               case REG_TLS:
+                       // NOTE: Systems listed here should be only systems that
+                       // support direct TLS references like 8(TLS) implemented as
+                       // direct references from FS or GS. Systems that require
+                       // the initial-exec model, where you load the TLS base into
+                       // a register and then index from that register, do not reach
+                       // this code and should not be listed.
+                       switch(ctxt->headtype) {
+                       default:
+                               sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
+                       case Hdarwin:
+                       case Hdragonfly:
+                       case Hfreebsd:
+                       case Hnetbsd:
+                       case Hopenbsd:
+                               return 0x65; // GS
+                       }
                }
        }
        return 0;
 }
 
 static int
-oclass(Addr *a)
+oclass(Link *ctxt, Addr *a)
 {
        int32 v;
 
-       if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) {
-               if(a->index != D_NONE && a->scale == 0) {
-                       if(a->type == D_ADDR) {
-                               switch(a->index) {
-                               case D_EXTERN:
-                               case D_STATIC:
-                                       return Yi32;
-                               case D_AUTO:
-                               case D_PARAM:
-                                       return Yiauto;
-                               }
-                               return Yxxx;
-                       }
-                       //if(a->type == D_INDIR+D_ADDR)
-                       //      print("*Ycol\n");
+       // TODO(rsc): This special case is for SHRQ $3, AX:DX,
+       // which encodes as SHRQ $32(DX*0), AX.
+       // Similarly SHRQ CX, AX:DX is really SHRQ CX(DX*0), AX.
+       // Change encoding and remove.
+       if((a->type == TYPE_CONST || a->type == TYPE_REG) && a->index != REG_NONE && a->scale == 0)
+               return Ycol;
+
+       switch(a->type) {
+       case TYPE_NONE:
+               return Ynone;
+
+       case TYPE_BRANCH:
+               return Ybr;
+       
+       case TYPE_INDIR:
+               // TODO(rsc): Why this is also Ycol is a mystery. Should split the two meanings.
+               if(a->name != NAME_NONE && a->reg == REG_NONE && a->index == REG_NONE && a->scale == 0)
                        return Ycol;
-               }
+               return Yxxx;
+
+       case TYPE_MEM:
                return Ym;
+
+       case TYPE_ADDR:
+               switch(a->name) {
+               case NAME_EXTERN:
+               case NAME_STATIC:
+                       return Yi32;
+               case NAME_AUTO:
+               case NAME_PARAM:
+                       return Yiauto;
+               }
+
+               // DUFFZERO/DUFFCOPY encoding forgot to set a->index
+               // and got Yi32 in an earlier version of this code.
+               // Keep doing that until we fix yduff etc.
+               if(a->sym != nil && strncmp(a->sym->name, "runtime.duff", 12) == 0)
+                       return Yi32;
+               
+               if(a->sym != nil || a->name != NAME_NONE)
+                       ctxt->diag("unexpected addr: %D", a);
+               // fall through
+
+       case TYPE_CONST:
+               if(a->sym != nil)
+                       ctxt->diag("TYPE_CONST with symbol: %D", a);
+
+               v = a->offset;
+               if(v == 0)
+                       return Yi0;
+               if(v == 1)
+                       return Yi1;
+               if(v >= -128 && v <= 127)
+                       return Yi8;
+               return Yi32;
+
+       case TYPE_TEXTSIZE:
+               return Ytextsize;
+       }
+
+       if(a->type != TYPE_REG) {
+               ctxt->diag("unexpected addr1: type=%d %D", a->type, a);
+               return Yxxx;
        }
-       switch(a->type)
-       {
-       case D_AL:
+
+       switch(a->reg) {
+       case REG_AL:
                return Yal;
 
-       case D_AX:
+       case REG_AX:
                return Yax;
 
-       case D_CL:
-       case D_DL:
-       case D_BL:
-       case D_AH:
-       case D_CH:
-       case D_DH:
-       case D_BH:
+       case REG_CL:
+       case REG_DL:
+       case REG_BL:
+       case REG_AH:
+       case REG_CH:
+       case REG_DH:
+       case REG_BH:
                return Yrb;
 
-       case D_CX:
+       case REG_CX:
                return Ycx;
 
-       case D_DX:
-       case D_BX:
+       case REG_DX:
+       case REG_BX:
                return Yrx;
 
-       case D_SP:
-       case D_BP:
-       case D_SI:
-       case D_DI:
+       case REG_SP:
+       case REG_BP:
+       case REG_SI:
+       case REG_DI:
                return Yrl;
 
-       case D_F0+0:
+       case REG_F0+0:
                return  Yf0;
 
-       case D_F0+1:
-       case D_F0+2:
-       case D_F0+3:
-       case D_F0+4:
-       case D_F0+5:
-       case D_F0+6:
-       case D_F0+7:
+       case REG_F0+1:
+       case REG_F0+2:
+       case REG_F0+3:
+       case REG_F0+4:
+       case REG_F0+5:
+       case REG_F0+6:
+       case REG_F0+7:
                return  Yrf;
 
-       case D_X0+0:
-       case D_X0+1:
-       case D_X0+2:
-       case D_X0+3:
-       case D_X0+4:
-       case D_X0+5:
-       case D_X0+6:
-       case D_X0+7:
+       case REG_X0+0:
+       case REG_X0+1:
+       case REG_X0+2:
+       case REG_X0+3:
+       case REG_X0+4:
+       case REG_X0+5:
+       case REG_X0+6:
+       case REG_X0+7:
                return  Yxr;
 
-       case D_NONE:
-               return Ynone;
-
-       case D_CS:      return  Ycs;
-       case D_SS:      return  Yss;
-       case D_DS:      return  Yds;
-       case D_ES:      return  Yes;
-       case D_FS:      return  Yfs;
-       case D_GS:      return  Ygs;
-       case D_TLS:     return  Ytls;
-
-       case D_GDTR:    return  Ygdtr;
-       case D_IDTR:    return  Yidtr;
-       case D_LDTR:    return  Yldtr;
-       case D_MSW:     return  Ymsw;
-       case D_TASK:    return  Ytask;
-
-       case D_CR+0:    return  Ycr0;
-       case D_CR+1:    return  Ycr1;
-       case D_CR+2:    return  Ycr2;
-       case D_CR+3:    return  Ycr3;
-       case D_CR+4:    return  Ycr4;
-       case D_CR+5:    return  Ycr5;
-       case D_CR+6:    return  Ycr6;
-       case D_CR+7:    return  Ycr7;
-
-       case D_DR+0:    return  Ydr0;
-       case D_DR+1:    return  Ydr1;
-       case D_DR+2:    return  Ydr2;
-       case D_DR+3:    return  Ydr3;
-       case D_DR+4:    return  Ydr4;
-       case D_DR+5:    return  Ydr5;
-       case D_DR+6:    return  Ydr6;
-       case D_DR+7:    return  Ydr7;
-
-       case D_TR+0:    return  Ytr0;
-       case D_TR+1:    return  Ytr1;
-       case D_TR+2:    return  Ytr2;
-       case D_TR+3:    return  Ytr3;
-       case D_TR+4:    return  Ytr4;
-       case D_TR+5:    return  Ytr5;
-       case D_TR+6:    return  Ytr6;
-       case D_TR+7:    return  Ytr7;
-
-       case D_EXTERN:
-       case D_STATIC:
-       case D_AUTO:
-       case D_PARAM:
-               return Ym;
+       case REG_CS:    return  Ycs;
+       case REG_SS:    return  Yss;
+       case REG_DS:    return  Yds;
+       case REG_ES:    return  Yes;
+       case REG_FS:    return  Yfs;
+       case REG_GS:    return  Ygs;
+       case REG_TLS:   return  Ytls;
+
+       case REG_GDTR:  return  Ygdtr;
+       case REG_IDTR:  return  Yidtr;
+       case REG_LDTR:  return  Yldtr;
+       case REG_MSW:   return  Ymsw;
+       case REG_TASK:  return  Ytask;
+
+       case REG_CR+0:  return  Ycr0;
+       case REG_CR+1:  return  Ycr1;
+       case REG_CR+2:  return  Ycr2;
+       case REG_CR+3:  return  Ycr3;
+       case REG_CR+4:  return  Ycr4;
+       case REG_CR+5:  return  Ycr5;
+       case REG_CR+6:  return  Ycr6;
+       case REG_CR+7:  return  Ycr7;
+
+       case REG_DR+0:  return  Ydr0;
+       case REG_DR+1:  return  Ydr1;
+       case REG_DR+2:  return  Ydr2;
+       case REG_DR+3:  return  Ydr3;
+       case REG_DR+4:  return  Ydr4;
+       case REG_DR+5:  return  Ydr5;
+       case REG_DR+6:  return  Ydr6;
+       case REG_DR+7:  return  Ydr7;
+
+       case REG_TR+0:  return  Ytr0;
+       case REG_TR+1:  return  Ytr1;
+       case REG_TR+2:  return  Ytr2;
+       case REG_TR+3:  return  Ytr3;
+       case REG_TR+4:  return  Ytr4;
+       case REG_TR+5:  return  Ytr5;
+       case REG_TR+6:  return  Ytr6;
+       case REG_TR+7:  return  Ytr7;
 
-       case D_CONST:
-       case D_CONST2:
-       case D_ADDR:
-               if(a->sym == nil) {
-                       v = a->offset;
-                       if(v == 0)
-                               return Yi0;
-                       if(v == 1)
-                               return Yi1;
-                       if(v >= -128 && v <= 127)
-                               return Yi8;
-               }
-               return Yi32;
-
-       case D_BRANCH:
-               return Ybr;
        }
        return Yxxx;
 }
@@ -1640,17 +1659,17 @@ asmidx(Link *ctxt, int scale, int index, int base)
        default:
                goto bad;
 
-       case D_NONE:
+       case TYPE_NONE:
                i = 4 << 3;
                goto bas;
 
-       case D_AX:
-       case D_CX:
-       case D_DX:
-       case D_BX:
-       case D_BP:
-       case D_SI:
-       case D_DI:
+       case REG_AX:
+       case REG_CX:
+       case REG_DX:
+       case REG_BX:
+       case REG_BP:
+       case REG_SI:
+       case REG_DI:
                i = reg[index] << 3;
                break;
        }
@@ -1673,17 +1692,17 @@ bas:
        switch(base) {
        default:
                goto bad;
-       case D_NONE:    /* must be mod=00 */
+       case REG_NONE:  /* must be mod=00 */
                i |= 5;
                break;
-       case D_AX:
-       case D_CX:
-       case D_DX:
-       case D_BX:
-       case D_SP:
-       case D_BP:
-       case D_SI:
-       case D_DI:
+       case REG_AX:
+       case REG_CX:
+       case REG_DX:
+       case REG_BX:
+       case REG_SP:
+       case REG_BP:
+       case REG_SI:
+       case REG_DI:
                i |= reg[base];
                break;
        }
@@ -1725,8 +1744,6 @@ relput4(Link *ctxt, Prog *p, Addr *a)
 static int32
 vaddr(Link *ctxt, Prog *p, Addr *a, Reloc *r)
 {
-       int t;
-       int32 v;
        LSym *s;
        
        USED(p);
@@ -1734,13 +1751,9 @@ vaddr(Link *ctxt, Prog *p, Addr *a, Reloc *r)
        if(r != nil)
                memset(r, 0, sizeof *r);
 
-       t = a->type;
-       v = a->offset;
-       if(t == D_ADDR)
-               t = a->index;
-       switch(t) {
-       case D_STATIC:
-       case D_EXTERN:
+       switch(a->name) {
+       case NAME_STATIC:
+       case NAME_EXTERN:
                s = a->sym;
                if(s != nil) {
                        if(r == nil) {
@@ -1751,12 +1764,13 @@ vaddr(Link *ctxt, Prog *p, Addr *a, Reloc *r)
                        r->siz = 4;
                        r->off = -1;
                        r->sym = s;
-                       r->add = v;
-                       v = 0;
+                       r->add = a->offset;
+                       return 0;
                }
-               break;
+               return a->offset;
+       }
        
-       case D_INDIR+D_TLS:
+       if((a->type == TYPE_MEM || a->type == TYPE_ADDR) && a->reg == REG_TLS) {
                if(r == nil) {
                        ctxt->diag("need reloc for %D", a);
                        sysfatal("bad code");
@@ -1764,113 +1778,120 @@ vaddr(Link *ctxt, Prog *p, Addr *a, Reloc *r)
                r->type = R_TLS_LE;
                r->siz = 4;
                r->off = -1; // caller must fill in
-               r->add = v;
-               v = 0;
-               break;
+               r->add = a->offset;
+               return 0;
        }
-       return v;
+
+       return a->offset;
 }
 
 static void
 asmand(Link *ctxt, Prog *p, Addr *a, int r)
 {
        int32 v;
-       int t, scale;
+       int base;
        Reloc rel;
        
        USED(p);
 
        v = a->offset;
-       t = a->type;
        rel.siz = 0;
-       if(a->index != D_NONE && a->index != D_TLS) {
-               if(t < D_INDIR || t >= 2*D_INDIR) {
-                       switch(t) {
-                       default:
-                               goto bad;
-                       case D_STATIC:
-                       case D_EXTERN:
-                               t = D_NONE;
-                               v = vaddr(ctxt, p, a, &rel);
-                               break;
-                       case D_AUTO:
-                       case D_PARAM:
-                               t = D_SP;
-                               break;
-                       }
-               } else
-                       t -= D_INDIR;
 
-               if(t == D_NONE) {
+       switch(a->type) {
+       case TYPE_ADDR:
+               if(a->name == NAME_NONE)
+                       ctxt->diag("unexpected TYPE_ADDR with NAME_NONE");
+               if(a->index == REG_TLS)
+                       ctxt->diag("unexpected TYPE_ADDR with index==REG_TLS");
+               goto bad;
+       
+       case TYPE_REG:
+               if((a->reg < REG_AL || REG_F7 < a->reg) && (a->reg < REG_X0 || REG_X0+7 < a->reg))
+                       goto bad;
+               if(v)
+                       goto bad;
+               *ctxt->andptr++ = (3 << 6) | (reg[a->reg] << 0) | (r << 3);
+               return;
+       }
+
+       if(a->type != TYPE_MEM)
+               goto bad;
+
+       if(a->index != REG_NONE && a->index != REG_TLS) {
+               base = a->reg;
+               switch(a->name) {
+               case NAME_EXTERN:
+               case NAME_STATIC:
+                       base = REG_NONE;
+                       v = vaddr(ctxt, p, a, &rel);
+                       break;
+               case NAME_AUTO:
+               case NAME_PARAM:
+                       base = REG_SP;
+                       break;
+               }
+
+               if(base == REG_NONE) {
                        *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
-                       asmidx(ctxt, a->scale, a->index, t);
+                       asmidx(ctxt, a->scale, a->index, base);
                        goto putrelv;
                }
-               if(v == 0 && rel.siz == 0 && t != D_BP) {
+               if(v == 0 && rel.siz == 0 && base != REG_BP) {
                        *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
-                       asmidx(ctxt, a->scale, a->index, t);
+                       asmidx(ctxt, a->scale, a->index, base);
                        return;
                }
                if(v >= -128 && v < 128 && rel.siz == 0) {
                        *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
-                       asmidx(ctxt, a->scale, a->index, t);
+                       asmidx(ctxt, a->scale, a->index, base);
                        *ctxt->andptr++ = v;
                        return;
                }
                *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
-               asmidx(ctxt, a->scale, a->index, t);
+               asmidx(ctxt, a->scale, a->index, base);
                goto putrelv;
        }
-       if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) {
-               if(v)
-                       goto bad;
-               *ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
-               return;
+
+       base = a->reg;
+       switch(a->name) {
+       case NAME_STATIC:
+       case NAME_EXTERN:
+               base = REG_NONE;
+               v = vaddr(ctxt, p, a, &rel);
+               break;
+       case NAME_AUTO:
+       case NAME_PARAM:
+               base = REG_SP;
+               break;
        }
        
-       scale = a->scale;
-       if(t < D_INDIR || t >= 2*D_INDIR) {
-               switch(a->type) {
-               default:
-                       goto bad;
-               case D_STATIC:
-               case D_EXTERN:
-                       t = D_NONE;
-                       v = vaddr(ctxt, p, a, &rel);
-                       break;
-               case D_AUTO:
-               case D_PARAM:
-                       t = D_SP;
-                       break;
-               }
-               scale = 1;
-       } else
-               t -= D_INDIR;
-       if(t == D_TLS)
+       if(base == REG_TLS)
                v = vaddr(ctxt, p, a, &rel);
-
-       if(t == D_NONE || (D_CS <= t && t <= D_GS) || t == D_TLS) {
+       
+       if(base == REG_NONE || (REG_CS <= base && base <= REG_GS) || base == REG_TLS) {
                *ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
                goto putrelv;
        }
-       if(t == D_SP) {
+
+       if(base == REG_SP) {
                if(v == 0 && rel.siz == 0) {
                        *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
-                       asmidx(ctxt, scale, D_NONE, t);
+                       asmidx(ctxt, a->scale, REG_NONE, base);
                        return;
                }
                if(v >= -128 && v < 128 && rel.siz == 0) {
                        *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
-                       asmidx(ctxt, scale, D_NONE, t);
+                       asmidx(ctxt, a->scale, REG_NONE, base);
                        *ctxt->andptr++ = v;
                        return;
                }
                *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
-               asmidx(ctxt, scale, D_NONE, t);
+               asmidx(ctxt, a->scale, REG_NONE, base);
                goto putrelv;
        }
-       if(t >= D_AX && t <= D_DI) {
-               if(a->index == D_TLS) {
+
+       if(REG_AX <= base && base <= REG_DI) {
+               if(a->index == REG_TLS) {
                        memset(&rel, 0, sizeof rel);
                        rel.type = R_TLS_IE;
                        rel.siz = 4;
@@ -1878,17 +1899,17 @@ asmand(Link *ctxt, Prog *p, Addr *a, int r)
                        rel.add = v;
                        v = 0;
                }
-               if(v == 0 && rel.siz == 0 && t != D_BP) {
-                       *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+               if(v == 0 && rel.siz == 0 && base != REG_BP) {
+                       *ctxt->andptr++ = (0 << 6) | (reg[base] << 0) | (r << 3);
                        return;
                }
                if(v >= -128 && v < 128 && rel.siz == 0)  {
-                       ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+                       ctxt->andptr[0] = (1 << 6) | (reg[base] << 0) | (r << 3);
                        ctxt->andptr[1] = v;
                        ctxt->andptr += 2;
                        return;
                }
-               *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+               *ctxt->andptr++ = (2 << 6) | (reg[base] << 0) | (r << 3);
                goto putrelv;
        }
        goto bad;
@@ -2028,7 +2049,7 @@ static uchar      ymovtab[] =
 };
 
 // byteswapreg returns a byte-addressable register (AX, BX, CX, DX)
-// which is not referenced in a->type.
+// which is not referenced in a.
 // If a is empty, it returns BX to account for MULB-like instructions
 // that might use DX and AX.
 static int
@@ -2038,57 +2059,60 @@ byteswapreg(Link *ctxt, Addr *a)
 
        cana = canb = canc = cand = 1;
 
-       switch(a->type) {
-       case D_NONE:
+       if(a->type == TYPE_NONE)
                cana = cand = 0;
-               break;
-       case D_AX:
-       case D_AL:
-       case D_AH:
-       case D_INDIR+D_AX:
-               cana = 0;
-               break;
-       case D_BX:
-       case D_BL:
-       case D_BH:
-       case D_INDIR+D_BX:
-               canb = 0;
-               break;
-       case D_CX:
-       case D_CL:
-       case D_CH:
-       case D_INDIR+D_CX:
-               canc = 0;
-               break;
-       case D_DX:
-       case D_DL:
-       case D_DH:
-       case D_INDIR+D_DX:
-               cand = 0;
-               break;
+
+       if(a->type == TYPE_REG || ((a->type == TYPE_MEM || a->type == TYPE_ADDR) && a->name == NAME_NONE)) {
+               switch(a->reg) {
+               case REG_NONE:
+                       cana = cand = 0;
+                       break;
+               case REG_AX:
+               case REG_AL:
+               case REG_AH:
+                       cana = 0;
+                       break;
+               case REG_BX:
+               case REG_BL:
+               case REG_BH:
+                       canb = 0;
+                       break;
+               case REG_CX:
+               case REG_CL:
+               case REG_CH:
+                       canc = 0;
+                       break;
+               case REG_DX:
+               case REG_DL:
+               case REG_DH:
+                       cand = 0;
+                       break;
+               }
        }
-       switch(a->index) {
-       case D_AX:
-               cana = 0;
-               break;
-       case D_BX:
-               canb = 0;
-               break;
-       case D_CX:
-               canc = 0;
-               break;
-       case D_DX:
-               cand = 0;
-               break;
+       if(a->type == TYPE_MEM || a->type == TYPE_ADDR) {
+               switch(a->index) {
+               case REG_AX:
+                       cana = 0;
+                       break;
+               case REG_BX:
+                       canb = 0;
+                       break;
+               case REG_CX:
+                       canc = 0;
+                       break;
+               case REG_DX:
+                       cand = 0;
+                       break;
+               }
        }
        if(cana)
-               return D_AX;
+               return REG_AX;
        if(canb)
-               return D_BX;
+               return REG_BX;
        if(canc)
-               return D_CX;
+               return REG_CX;
        if(cand)
-               return D_DX;
+               return REG_DX;
 
        ctxt->diag("impossible byte register");
        sysfatal("bad code");
@@ -2098,16 +2122,15 @@ byteswapreg(Link *ctxt, Addr *a)
 static void
 subreg(Prog *p, int from, int to)
 {
-
        if(0 /* debug['Q'] */)
                print("\n%P     s/%R/%R/\n", p, from, to);
 
-       if(p->from.type == from) {
-               p->from.type = to;
+       if(p->from.reg == from) {
+               p->from.reg = to;
                p->ft = 0;
        }
-       if(p->to.type == from) {
-               p->to.type = to;
+       if(p->to.reg == from) {
+               p->to.reg = to;
                p->tt = 0;
        }
 
@@ -2120,16 +2143,6 @@ subreg(Prog *p, int from, int to)
                p->tt = 0;
        }
 
-       from += D_INDIR;
-       if(p->from.type == from) {
-               p->from.type = to+D_INDIR;
-               p->ft = 0;
-       }
-       if(p->to.type == from) {
-               p->to.type = to+D_INDIR;
-               p->tt = 0;
-       }
-
        if(0 /* debug['Q'] */)
                print("%P\n", p);
 }
@@ -2179,13 +2192,13 @@ doasm(Link *ctxt, Prog *p)
                *ctxt->andptr++ = pre;
 
        if(p->ft == 0)
-               p->ft = oclass(&p->from);
+               p->ft = oclass(ctxt, &p->from);
        if(p->tt == 0)
-               p->tt = oclass(&p->to);
+               p->tt = oclass(ctxt, &p->to);
 
        ft = p->ft * Ymax;
        tt = p->tt * Ymax;
-       o = &optab[p->as];
+       o = opindex[p->as];
        t = o->ytab;
        if(t == 0) {
                ctxt->diag("asmins: noproto %P", p);
@@ -2239,48 +2252,46 @@ found:
        case Zlitm_r:
                for(; op = o->op[z]; z++)
                        *ctxt->andptr++ = op;
-               asmand(ctxt, p, &p->from, reg[p->to.type]);
+               asmand(ctxt, p, &p->from, reg[p->to.reg]);
                break;
 
        case Zm_r:
                *ctxt->andptr++ = op;
-               asmand(ctxt, p, &p->from, reg[p->to.type]);
+               asmand(ctxt, p, &p->from, reg[p->to.reg]);
                break;
 
        case Zm2_r:
                *ctxt->andptr++ = op;
                *ctxt->andptr++ = o->op[z+1];
-               asmand(ctxt, p, &p->from, reg[p->to.type]);
+               asmand(ctxt, p, &p->from, reg[p->to.reg]);
                break;
 
        case Zm_r_xm:
                mediaop(ctxt, o, op, t[3], z);
-               asmand(ctxt, p, &p->from, reg[p->to.type]);
+               asmand(ctxt, p, &p->from, reg[p->to.reg]);
                break;
 
        case Zm_r_i_xm:
                mediaop(ctxt, o, op, t[3], z);
-               asmand(ctxt, p, &p->from, reg[p->to.type]);
+               asmand(ctxt, p, &p->from, reg[p->to.reg]);
                *ctxt->andptr++ = p->to.offset;
                break;
 
        case Zibm_r:
                while ((op = o->op[z++]) != 0)
                        *ctxt->andptr++ = op;
-               asmand(ctxt, p, &p->from, reg[p->to.type]);
+               asmand(ctxt, p, &p->from, reg[p->to.reg]);
                *ctxt->andptr++ = p->to.offset;
                break;
 
        case Zaut_r:
                *ctxt->andptr++ = 0x8d; /* leal */
-               if(p->from.type != D_ADDR)
+               if(p->from.type != TYPE_ADDR)
                        ctxt->diag("asmins: Zaut sb type ADDR");
-               p->from.type = p->from.index;
-               p->from.index = D_NONE;
+               p->from.type = TYPE_MEM;
                p->ft = 0;
-               asmand(ctxt, p, &p->from, reg[p->to.type]);
-               p->from.index = p->from.type;
-               p->from.type = D_ADDR;
+               asmand(ctxt, p, &p->from, reg[p->to.reg]);
+               p->from.type = TYPE_ADDR;
                p->ft = 0;
                break;
 
@@ -2291,17 +2302,17 @@ found:
 
        case Zr_m:
                *ctxt->andptr++ = op;
-               asmand(ctxt, p, &p->to, reg[p->from.type]);
+               asmand(ctxt, p, &p->to, reg[p->from.reg]);
                break;
 
        case Zr_m_xm:
                mediaop(ctxt, o, op, t[3], z);
-               asmand(ctxt, p, &p->to, reg[p->from.type]);
+               asmand(ctxt, p, &p->to, reg[p->from.reg]);
                break;
 
        case Zr_m_i_xm:
                mediaop(ctxt, o, op, t[3], z);
-               asmand(ctxt, p, &p->to, reg[p->from.type]);
+               asmand(ctxt, p, &p->to, reg[p->from.reg]);
                *ctxt->andptr++ = p->from.offset;
                break;
 
@@ -2340,12 +2351,12 @@ found:
                break;
 
        case Zib_rp:
-               *ctxt->andptr++ = op + reg[p->to.type];
+               *ctxt->andptr++ = op + reg[p->to.reg];
                *ctxt->andptr++ = vaddr(ctxt, p, &p->from, nil);
                break;
 
        case Zil_rp:
-               *ctxt->andptr++ = op + reg[p->to.type];
+               *ctxt->andptr++ = op + reg[p->to.reg];
                if(o->prefix == Pe) {
                        v = vaddr(ctxt, p, &p->from, nil);
                        *ctxt->andptr++ = v;
@@ -2357,7 +2368,7 @@ found:
 
        case Zib_rr:
                *ctxt->andptr++ = op;
-               asmand(ctxt, p, &p->to, reg[p->to.type]);
+               asmand(ctxt, p, &p->to, reg[p->to.reg]);
                *ctxt->andptr++ = vaddr(ctxt, p, &p->from, nil);
                break;
 
@@ -2398,7 +2409,7 @@ found:
 
        case Zil_rr:
                *ctxt->andptr++ = op;
-               asmand(ctxt, p, &p->to, reg[p->to.type]);
+               asmand(ctxt, p, &p->to, reg[p->to.reg]);
                if(o->prefix == Pe) {
                        v = vaddr(ctxt, p, &p->from, nil);
                        *ctxt->andptr++ = v;
@@ -2409,16 +2420,16 @@ found:
                break;
 
        case Z_rp:
-               *ctxt->andptr++ = op + reg[p->to.type];
+               *ctxt->andptr++ = op + reg[p->to.reg];
                break;
 
        case Zrp_:
-               *ctxt->andptr++ = op + reg[p->from.type];
+               *ctxt->andptr++ = op + reg[p->from.reg];
                break;
 
        case Zclr:
                *ctxt->andptr++ = op;
-               asmand(ctxt, p, &p->to, reg[p->to.type]);
+               asmand(ctxt, p, &p->to, reg[p->to.reg]);
                break;
        
        case Zcall:
@@ -2570,9 +2581,9 @@ bad:
         * instruction with the operands renamed.
         */
        pp = *p;
-       z = p->from.type;
-       if(z >= D_BP && z <= D_DI) {
-               if((breg = byteswapreg(ctxt, &p->to)) != D_AX) {
+       z = p->from.reg;
+       if(p->from.type == TYPE_REG && z >= REG_BP && z <= REG_DI) {
+               if((breg = byteswapreg(ctxt, &p->to)) != REG_AX) {
                        *ctxt->andptr++ = 0x87;                 /* xchg lhs,bx */
                        asmand(ctxt, p, &p->from, reg[breg]);
                        subreg(&pp, z, breg);
@@ -2581,15 +2592,15 @@ bad:
                        asmand(ctxt, p, &p->from, reg[breg]);
                } else {
                        *ctxt->andptr++ = 0x90 + reg[z];                /* xchg lsh,ax */
-                       subreg(&pp, z, D_AX);
+                       subreg(&pp, z, REG_AX);
                        doasm(ctxt, &pp);
                        *ctxt->andptr++ = 0x90 + reg[z];                /* xchg lsh,ax */
                }
                return;
        }
-       z = p->to.type;
-       if(z >= D_BP && z <= D_DI) {
-               if((breg = byteswapreg(ctxt, &p->from)) != D_AX) {
+       z = p->to.reg;
+       if(p->to.type == TYPE_REG && z >= REG_BP && z <= REG_DI) {
+               if((breg = byteswapreg(ctxt, &p->from)) != REG_AX) {
                        *ctxt->andptr++ = 0x87;                 /* xchg rhs,bx */
                        asmand(ctxt, p, &p->to, reg[breg]);
                        subreg(&pp, z, breg);
@@ -2598,13 +2609,13 @@ bad:
                        asmand(ctxt, p, &p->to, reg[breg]);
                } else {
                        *ctxt->andptr++ = 0x90 + reg[z];                /* xchg rsh,ax */
-                       subreg(&pp, z, D_AX);
+                       subreg(&pp, z, REG_AX);
                        doasm(ctxt, &pp);
                        *ctxt->andptr++ = 0x90 + reg[z];                /* xchg rsh,ax */
                }
                return;
        }
-       ctxt->diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
+       ctxt->diag("doasm: notfound t2=%d from=%d to=%d %P", t[2], p->ft, p->tt, p);
        return;
 
 mfound:
@@ -2646,44 +2657,51 @@ mfound:
                switch(p->to.index) {
                default:
                        goto bad;
-               case D_DS:
+               case REG_DS:
                        *ctxt->andptr++ = 0xc5;
                        break;
-               case D_SS:
+               case REG_SS:
                        *ctxt->andptr++ = 0x0f;
                        *ctxt->andptr++ = 0xb2;
                        break;
-               case D_ES:
+               case REG_ES:
                        *ctxt->andptr++ = 0xc4;
                        break;
-               case D_FS:
+               case REG_FS:
                        *ctxt->andptr++ = 0x0f;
                        *ctxt->andptr++ = 0xb4;
                        break;
-               case D_GS:
+               case REG_GS:
                        *ctxt->andptr++ = 0x0f;
                        *ctxt->andptr++ = 0xb5;
                        break;
                }
-               asmand(ctxt, p, &p->from, reg[p->to.type]);
+               asmand(ctxt, p, &p->from, reg[p->to.reg]);
                break;
 
        case 6: /* double shift */
-               z = p->from.type;
-               switch(z) {
+               switch(p->from.type) {
                default:
                        goto bad;
-               case D_CONST:
+
+               case TYPE_CONST:
                        *ctxt->andptr++ = 0x0f;
                        *ctxt->andptr++ = t[4];
                        asmand(ctxt, p, &p->to, reg[p->from.index]);
                        *ctxt->andptr++ = p->from.offset;
                        break;
-               case D_CL:
-               case D_CX:
-                       *ctxt->andptr++ = 0x0f;
-                       *ctxt->andptr++ = t[5];
-                       asmand(ctxt, p, &p->to, reg[p->from.index]);
+               
+               case TYPE_REG:
+                       switch(p->from.reg) {
+                       default:
+                               goto bad;
+                       case REG_CL:
+                       case REG_CX:
+                               *ctxt->andptr++ = 0x0f;
+                               *ctxt->andptr++ = t[5];
+                               asmand(ctxt, p, &p->to, reg[p->from.index]);
+                               break;
+                       }
                        break;
                }
                break;
@@ -2695,7 +2713,7 @@ mfound:
                } else
                        *ctxt->andptr++ = t[4];
                *ctxt->andptr++ = t[5];
-               asmand(ctxt, p, &p->from, reg[p->to.type]);
+               asmand(ctxt, p, &p->from, reg[p->to.reg]);
                break;
        
        case 8: /* mov tls, r */
@@ -2711,37 +2729,40 @@ mfound:
                case Hnacl:
                        // ELF TLS base is 0(GS).
                        pp.from = p->from;
-                       pp.from.type = D_INDIR+D_GS;
+                       pp.from.type = TYPE_MEM;
+                       pp.from.reg = REG_GS;
                        pp.from.offset = 0;
-                       pp.from.index = D_NONE;
+                       pp.from.index = REG_NONE;
                        pp.from.scale = 0;
                        *ctxt->andptr++ = 0x65; // GS
                        *ctxt->andptr++ = 0x8B;
-                       asmand(ctxt, p, &pp.from, reg[p->to.type]);
+                       asmand(ctxt, p, &pp.from, reg[p->to.reg]);
                        break;
                
                case Hplan9:
                        if(ctxt->plan9privates == nil)
                                ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
                        memset(&pp.from, 0, sizeof pp.from);
-                       pp.from.type = D_EXTERN;
+                       pp.from.type = TYPE_MEM;
+                       pp.from.name = NAME_EXTERN;
                        pp.from.sym = ctxt->plan9privates;
                        pp.from.offset = 0;
-                       pp.from.index = D_NONE;
+                       pp.from.index = REG_NONE;
                        *ctxt->andptr++ = 0x8B;
-                       asmand(ctxt, p, &pp.from, reg[p->to.type]);
+                       asmand(ctxt, p, &pp.from, reg[p->to.reg]);
                        break;
 
                case Hwindows:
                        // Windows TLS base is always 0x14(FS).
                        pp.from = p->from;
-                       pp.from.type = D_INDIR+D_FS;
+                       pp.from.type = TYPE_MEM;
+                       pp.from.reg = REG_FS;
                        pp.from.offset = 0x14;
-                       pp.from.index = D_NONE;
+                       pp.from.index = REG_NONE;
                        pp.from.scale = 0;
                        *ctxt->andptr++ = 0x64; // FS
                        *ctxt->andptr++ = 0x8B;
-                       asmand(ctxt, p, &pp.from, reg[p->to.type]);
+                       asmand(ctxt, p, &pp.from, reg[p->to.reg]);
                        break;
                }
                break;
@@ -2779,9 +2800,9 @@ asmins(Link *ctxt, Prog *p)
                        return;
                case ACALL:
                case AJMP:
-                       if(D_AX <= p->to.type && p->to.type <= D_DI) {
+                       if(p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_DI) {
                                *ctxt->andptr++ = 0x83;
-                               *ctxt->andptr++ = 0xe0 | (p->to.type - D_AX);
+                               *ctxt->andptr++ = 0xe0 | (p->to.reg - REG_AX);
                                *ctxt->andptr++ = 0xe0;
                        }
                        break;
index f604395a7a1be333d09a54bc12b1bff723183455..742d204b5b544348d3d50f87c7279dca81402bd5 100644 (file)
@@ -59,14 +59,10 @@ struct      Optab
 };
 
 static Optab   optab[] = {
-       { ATEXT,        C_LEXT, C_NONE, C_NONE,         C_LCON,          0, 0, 0 },
-       { ATEXT,        C_LEXT, C_REG, C_NONE,  C_LCON,          0, 0, 0 },
-       { ATEXT,        C_LEXT, C_NONE, C_LCON,         C_LCON,          0, 0, 0 },
-       { ATEXT,        C_LEXT, C_REG, C_LCON,  C_LCON,          0, 0, 0 },
-       { ATEXT,        C_ADDR, C_NONE, C_NONE,         C_LCON,          0, 0, 0 },
-       { ATEXT,        C_ADDR, C_REG, C_NONE,  C_LCON,          0, 0, 0 },
-       { ATEXT,        C_ADDR, C_NONE, C_LCON,         C_LCON,          0, 0, 0 },
-       { ATEXT,        C_ADDR, C_REG, C_LCON,  C_LCON,          0, 0, 0 },
+       { ATEXT,        C_LEXT, C_NONE, C_NONE,         C_TEXTSIZE,      0, 0, 0 },
+       { ATEXT,        C_LEXT, C_NONE, C_LCON,         C_TEXTSIZE,      0, 0, 0 },
+       { ATEXT,        C_ADDR, C_NONE, C_NONE,         C_TEXTSIZE,      0, 0, 0 },
+       { ATEXT,        C_ADDR, C_NONE, C_LCON,         C_TEXTSIZE,      0, 0, 0 },
 
        /* move register */
        { AMOVD,        C_REG,  C_NONE, C_NONE,         C_REG,           1, 4, 0 },
@@ -497,7 +493,7 @@ span9(Link *ctxt, LSym *cursym)
        if(p == nil || p->link == nil) // handle external functions and ELF section symbols
                return;
        ctxt->cursym = cursym;
-       ctxt->autosize = (int32)(p->to.offset & 0xffffffffll) + 8;
+       ctxt->autosize = p->to.offset + 8;
 
        if(oprange[AANDN].start == nil)
                buildop(ctxt);
@@ -539,18 +535,18 @@ span9(Link *ctxt, LSym *cursym)
                        if((o->type == 16 || o->type == 17) && p->pcond) {
                                otxt = p->pcond->pc - c;
                                if(otxt < -(1L<<15)+10 || otxt >= (1L<<15)-10) {
-                                       q = ctxt->arch->prg();
+                                       q = emallocz(sizeof(Prog));
                                        q->link = p->link;
                                        p->link = q;
                                        q->as = ABR;
-                                       q->to.type = D_BRANCH;
+                                       q->to.type = TYPE_BRANCH;
                                        q->pcond = p->pcond;
                                        p->pcond = q;
-                                       q = ctxt->arch->prg();
+                                       q = emallocz(sizeof(Prog));
                                        q->link = p->link;
                                        p->link = q;
                                        q->as = ABR;
-                                       q->to.type = D_BRANCH;
+                                       q->to.type = TYPE_BRANCH;
                                        q->pcond = q->link->link;
                                        //addnop(p->link);
                                        //addnop(p);
@@ -614,57 +610,56 @@ aclass(Link *ctxt, Addr *a)
        LSym *s;
 
        switch(a->type) {
-       case D_NONE:
+       case TYPE_NONE:
                return C_NONE;
 
-       case D_REG:
-               return C_REG;
-
-       case D_FREG:
-               return C_FREG;
-
-       case D_CREG:
-               return C_CREG;
-
-       case D_SPR:
-               if(a->offset == D_LR)
-                       return C_LR;
-               if(a->offset == D_XER)
-                       return C_XER;
-               if(a->offset == D_CTR)
-                       return C_CTR;
-               return C_SPR;
-
-       case D_DCR:
-               return C_SPR;
-
-       case D_FPSCR:
-               return C_FPSCR;
-
-       case D_MSR:
-               return C_MSR;
+       case TYPE_REG:
+               if(REG_R0 <= a->reg && a->reg <= REG_R31)
+                       return C_REG;
+               if(REG_F0 <= a->reg && a->reg <= REG_F31)
+                       return C_FREG;
+               if(REG_C0 <= a->reg && a->reg <= REG_C7 || a->reg == REG_CR)
+                       return C_CREG;
+               if(REG_SPR0 <= a->reg && a->reg <= REG_SPR0+1023) {
+                       switch(a->reg) {
+                       case REG_LR:
+                               return C_LR;
+                       case REG_XER:
+                               return C_XER;
+                       case REG_CTR:
+                               return C_CTR;
+                       }
+                       return C_SPR;
+               }
+               if(REG_DCR0 <= a->reg && a->reg <= REG_DCR0+1023)
+                       return C_SPR;
+               if(a->reg == REG_FPSCR)
+                       return C_FPSCR;
+               if(a->reg == REG_MSR)
+                       return C_MSR;
+               return C_GOK;
 
-       case D_OREG:
+       case TYPE_MEM:
                switch(a->name) {
-               case D_EXTERN:
-               case D_STATIC:
+               case NAME_EXTERN:
+               case NAME_STATIC:
                        if(a->sym == nil)
                                break;
                        ctxt->instoffset = a->offset;
                        if(a->sym != nil) // use relocation
                                return C_ADDR;
                        return C_LEXT;
-               case D_AUTO:
+               case NAME_AUTO:
                        ctxt->instoffset = ctxt->autosize + a->offset;
                        if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
                                return C_SAUTO;
                        return C_LAUTO;
-               case D_PARAM:
+               case NAME_PARAM:
                        ctxt->instoffset = ctxt->autosize + a->offset + 8L;
                        if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
                                return C_SAUTO;
                        return C_LAUTO;
-               case D_NONE:
+               case TYPE_NONE:
                        ctxt->instoffset = a->offset;
                        if(ctxt->instoffset == 0)
                                return C_ZOREG;
@@ -674,17 +669,15 @@ aclass(Link *ctxt, Addr *a)
                }
                return C_GOK;
 
-       case D_OPT:
-               ctxt->instoffset = a->offset & 31L;
-               if(a->name == D_NONE)
-                       return C_SCON;
-               return C_GOK;
+       case TYPE_TEXTSIZE:
+               return C_TEXTSIZE;
 
-       case D_CONST:
+       case TYPE_CONST:
+       case TYPE_ADDR:
                switch(a->name) {
-               case D_NONE:
+               case TYPE_NONE:
                        ctxt->instoffset = a->offset;
-                       if(a->reg != NREG) {
+                       if(a->reg != 0) {
                                if(-BIG <= ctxt->instoffset && ctxt->instoffset <= BIG)
                                        return C_SACON;
                                if(isint32(ctxt->instoffset))
@@ -693,8 +686,8 @@ aclass(Link *ctxt, Addr *a)
                        }
                        goto consize;
 
-               case D_EXTERN:
-               case D_STATIC:
+               case NAME_EXTERN:
+               case NAME_STATIC:
                        s = a->sym;
                        if(s == nil)
                                break;
@@ -706,13 +699,13 @@ aclass(Link *ctxt, Addr *a)
                        /* not sure why this barfs */
                        return C_LCON;
 
-               case D_AUTO:
+               case NAME_AUTO:
                        ctxt->instoffset = ctxt->autosize + a->offset;
                        if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
                                return C_SACON;
                        return C_LACON;
 
-               case D_PARAM:
+               case NAME_PARAM:
                        ctxt->instoffset = ctxt->autosize + a->offset + 8L;
                        if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
                                return C_SACON;
@@ -742,7 +735,7 @@ aclass(Link *ctxt, Addr *a)
                        return C_LCON;
                return C_DCON;
 
-       case D_BRANCH:
+       case TYPE_BRANCH:
                return C_SBRA;
        }
        return C_GOK;
@@ -783,7 +776,7 @@ oplook(Link *ctxt, Prog *p)
        }
        a4--;
        a2 = C_NONE;
-       if(p->reg != NREG)
+       if(p->reg != 0)
                a2 = C_REG;
 //print("oplook %P %d %d %d %d\n", p, a1, a2, a3, a4);
        r = p->as;
@@ -1515,7 +1508,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                break;
 
        case 1:         /* mov r1,r2 ==> OR Rs,Rs,Ra */
-               if(p->to.reg == REGZERO && p->from.type == D_CONST) {
+               if(p->to.reg == REGZERO && p->from.type == TYPE_CONST) {
                        v = regoff(ctxt, &p->from);
                        if(r0iszero && v != 0) {
                                //nerrors--;
@@ -1529,7 +1522,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 2:         /* int/cr/fp op Rb,[Ra],Rd */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, p->from.reg);
                break;
@@ -1538,7 +1531,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                d = vregoff(ctxt, &p->from);
                v = d;
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                if(r0iszero && p->to.reg == 0 && (r != 0 || v != 0))
                        ctxt->diag("literal operation on R0\n%P", p);
@@ -1562,7 +1555,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
        case 4:         /* add/mul $scon,[r1],r2 */
                v = regoff(ctxt, &p->from);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                if(r0iszero && p->to.reg == 0)
                        ctxt->diag("literal operation on R0\n%P", p);
@@ -1577,17 +1570,17 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 6:         /* logical op Rb,[Rs,]Ra; no literal */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                o1 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, p->from.reg);
                break;
 
        case 7:         /* mov r, soreg ==> stw o(r) */
                r = p->to.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                v = regoff(ctxt, &p->to);
-               if(p->to.type == D_OREG && p->reg != NREG) {
+               if(p->to.type == TYPE_MEM && p->reg != 0) {
                        if(v)
                                ctxt->diag("illegal indexed instruction\n%P", p);
                        o1 = AOP_RRR(opstorex(ctxt, p->as), p->from.reg, p->reg, r);
@@ -1600,10 +1593,10 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 8:         /* mov soreg, r ==> lbz/lhz/lwz o(r) */
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                v = regoff(ctxt, &p->from);
-               if(p->from.type == D_OREG && p->reg != NREG) {
+               if(p->from.type == TYPE_MEM && p->reg != 0) {
                        if(v)
                                ctxt->diag("illegal indexed instruction\n%P", p);
                        o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, p->reg, r);
@@ -1616,10 +1609,10 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 9:         /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                v = regoff(ctxt, &p->from);
-               if(p->from.type == D_OREG && p->reg != NREG) {
+               if(p->from.type == TYPE_MEM && p->reg != 0) {
                        if(v)
                                ctxt->diag("illegal indexed instruction\n%P", p);
                        o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, p->reg, r);
@@ -1630,7 +1623,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 10:                /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, p->from.reg, r);
                break;
@@ -1663,7 +1656,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                break;
 
        case 12:        /* movb r,r (extsb); movw r,r (extsw) */
-               if(p->to.reg == REGZERO && p->from.type == D_CONST) {
+               if(p->to.reg == REGZERO && p->from.type == TYPE_CONST) {
                        v = regoff(ctxt, &p->from);
                        if(r0iszero && v != 0) {
                                ctxt->diag("literal operation on R0\n%P", p);
@@ -1692,7 +1685,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 14:        /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                d = vregoff(ctxt, &p->from3);
                maskgen64(ctxt, p, mask, d);
@@ -1720,10 +1713,10 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
        case 17:        /* bc bo,bi,lbra (same for now) */
        case 16:        /* bc bo,bi,sbra */
                a = 0;
-               if(p->from.type == D_CONST)
+               if(p->from.type == TYPE_CONST)
                        a = regoff(ctxt, &p->from);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = 0;
                v = 0;
                if(p->pcond)
@@ -1743,9 +1736,9 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                else
                        v = 20; /* unconditional */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = 0;
-               o1 = AOP_RRR(OP_MTSPR, p->to.reg, 0, 0) | ((D_LR&0x1f)<<16) | (((D_LR>>5)&0x1f)<<11);
+               o1 = AOP_RRR(OP_MTSPR, p->to.reg, 0, 0) | ((REG_LR&0x1f)<<16) | (((REG_LR>>5)&0x1f)<<11);
                o2 = OPVCC(19, 16, 0, 0);
                if(p->as == ABL || p->as == ABCL)
                        o2 |= 1;
@@ -1758,7 +1751,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                else
                        v = 20; /* unconditional */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = 0;
                switch(oclass(&p->to)) {
                case C_CTR:
@@ -1792,11 +1785,11 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
        case 20:        /* add $ucon,,r */
                v = regoff(ctxt, &p->from);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                if(p->as == AADD && (!r0iszero && p->reg == 0 || r0iszero && p->to.reg == 0))
                        ctxt->diag("literal operation on R0\n%P", p);
-               o1 = AOP_IRR(opirr(ctxt, p->as+AEND), p->to.reg, r, v>>16);
+               o1 = AOP_IRR(opirr(ctxt, p->as+ALAST), p->to.reg, r, v>>16);
                break;
 
        case 22:        /* add $lcon,r1,r2 ==> cau+or+add */    /* could do add/sub more efficiently */
@@ -1806,7 +1799,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                o1 = loadu32(REGTMP, d);
                o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (int32)d);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                o3 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, REGTMP, r);
                if(p->from.sym != nil)
@@ -1821,7 +1814,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                o1 = loadu32(REGTMP, d);
                o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (int32)d);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                o3 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, REGTMP, r);
                if(p->from.sym != nil)
@@ -1837,7 +1830,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                else if(v > 63)
                        v = 63;
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                switch(p->as){
                case ASLD: case ASLDCC:
@@ -1869,7 +1862,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                        ctxt->diag("can't synthesize large constant\n%P", p);
                v = regoff(ctxt, &p->from);
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v));
                o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, v);
@@ -1961,7 +1954,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 32:        /* fmul frc,fra,frd */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, 0)|((p->from.reg&31L)<<6);
                break;
@@ -1980,7 +1973,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
        case 35:        /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
                v = regoff(ctxt, &p->to);
                r = p->to.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v));
                o2 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, REGTMP, v);
@@ -1989,7 +1982,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
        case 36:        /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */
                v = regoff(ctxt, &p->from);
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v));
                o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
@@ -1998,7 +1991,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
        case 37:        /* movb lext/lauto/lreg,r ==> lbz o(reg),r; extsb r */
                v = regoff(ctxt, &p->from);
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = o->param;
                o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v));
                o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
@@ -2019,20 +2012,20 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 43:        /* unary indexed source: dcbf (b); dcbf (a+b) */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = 0;
                o1 = AOP_RRR(oprrr(ctxt, p->as), 0, r, p->from.reg);
                break;
 
        case 44:        /* indexed store */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = 0;
                o1 = AOP_RRR(opstorex(ctxt, p->as), p->from.reg, r, p->to.reg);
                break;
        case 45:        /* indexed load */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = 0;
                o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, r, p->from.reg);
                break;
@@ -2043,20 +2036,20 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 47:        /* op Ra, Rd; also op [Ra,] Rd */
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, 0);
                break;
 
        case 48:        /* op Rs, Ra */
                r = p->from.reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                o1 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, 0);
                break;
 
        case 49:        /* op Rb; op $n, Rb */
-               if(p->from.type != D_REG){      /* tlbie $L, rB */
+               if(p->from.type != TYPE_REG){   /* tlbie $L, rB */
                        v = regoff(ctxt, &p->from) & 1;
                        o1 = AOP_RRR(oprrr(ctxt, p->as), 0, 0, p->to.reg) | (v<<21);
                }else
@@ -2065,7 +2058,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 50:        /* rem[u] r1[,r2],r3 */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                v = oprrr(ctxt, p->as);
                t = v & ((1<<10)|1);    /* OE|Rc */
@@ -2081,7 +2074,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
 
        case 51:        /* remd[u] r1[,r2],r3 */
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                v = oprrr(ctxt, p->as);
                t = v & ((1<<10)|1);    /* OE|Rc */
@@ -2116,7 +2109,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
        case 56:        /* sra $sh,[s,]a; srd $sh,[s,]a */
                v = regoff(ctxt, &p->from);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                o1 = AOP_RRR(opirr(ctxt, p->as), r, p->to.reg, v&31L);
                if(p->as == ASRAD && (v&0x20))
@@ -2126,7 +2119,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
        case 57:        /* slw $sh,[s,]a -> rlwinm ... */
                v = regoff(ctxt, &p->from);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                /*
                 * Let user (gs) shoot himself in the foot. 
@@ -2155,7 +2148,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
        case 58:                /* logical $andcon,[s],a */
                v = regoff(ctxt, &p->from);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
                o1 = LOP_IRR(opirr(ctxt, p->as), p->to.reg, r, v);
                break;
@@ -2163,9 +2156,9 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
        case 59:        /* or/and $ucon,,r */
                v = regoff(ctxt, &p->from);
                r = p->reg;
-               if(r == NREG)
+               if(r == 0)
                        r = p->to.reg;
-               o1 = LOP_IRR(opirr(ctxt, p->as+AEND), p->to.reg, r, v>>16);     /* oris, xoris, andis */
+               o1 = LOP_IRR(opirr(ctxt, p->as+ALAST), p->to.reg, r, v>>16);    /* oris, xoris, andis */
                break;
 
        case 60:        /* tw to,a,b */
@@ -2193,7 +2186,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                break;
 
        case 64:        /* mtfsf fr[, $m] {,fpcsr} */
-               if(p->from3.type != D_NONE)
+               if(p->from3.type != TYPE_NONE)
                        v = regoff(ctxt, &p->from3)&255L;
                else
                        v = 255;
@@ -2201,23 +2194,23 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                break;
 
        case 65:        /* MOVFL $imm,FPSCR(n) => mtfsfi crfd,imm */
-               if(p->to.reg == NREG)
+               if(p->to.reg == 0)
                        ctxt->diag("must specify FPSCR(n)\n%P", p);
                o1 = OP_MTFSFI | ((p->to.reg&15L)<<23) | ((regoff(ctxt, &p->from)&31L)<<12);
                break;
 
        case 66:        /* mov spr,r1; mov r1,spr, also dcr */
-               if(p->from.type == D_REG) {
+               if(REG_R0 <= p->from.reg && p->from.reg <= REG_R31) {
                        r = p->from.reg;
-                       v = p->to.offset;
-                       if(p->to.type == D_DCR)
+                       v = p->to.reg;
+                       if(REG_DCR0 <= v && v <= REG_DCR0+1023)
                                o1 = OPVCC(31,451,0,0); /* mtdcr */
                        else
                                o1 = OPVCC(31,467,0,0); /* mtspr */
                } else {
                        r = p->to.reg;
-                       v = p->from.offset;
-                       if(p->from.type == D_DCR)
+                       v = p->from.reg;
+                       if(REG_DCR0 <= v && v <= REG_DCR0+1023)
                                o1 = OPVCC(31,323,0,0); /* mfdcr */
                        else
                                o1 = OPVCC(31,339,0,0); /* mfspr */
@@ -2226,14 +2219,14 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                break;
 
        case 67:        /* mcrf crfD,crfS */
-               if(p->from.type != D_CREG || p->from.reg == NREG ||
-                  p->to.type != D_CREG || p->to.reg == NREG)
+               if(p->from.type != TYPE_REG || p->from.reg < REG_C0 || REG_C7 < p->from.reg ||
+                  p->to.type != TYPE_REG || p->to.reg < REG_C0 || REG_C7 < p->to.reg)
                        ctxt->diag("illegal CR field number\n%P", p);
                o1 = AOP_RRR(OP_MCRF, ((p->to.reg&7L)<<2), ((p->from.reg&7)<<2), 0);
                break;
 
        case 68:        /* mfcr rD; mfocrf CRM,rD */
-               if(p->from.type == D_CREG && p->from.reg != NREG){
+               if(p->from.type == TYPE_REG && REG_C0 <= p->from.reg && p->from.reg <= REG_C7) {
                        v = 1<<(7-(p->to.reg&7));       /* CR(n) */
                        o1 = AOP_RRR(OP_MFCR, p->to.reg, 0, 0) | (1<<20) | (v<<12);     /* new form, mfocrf */
                }else
@@ -2241,12 +2234,12 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                break;
 
        case 69:        /* mtcrf CRM,rS */
-               if(p->from3.type != D_NONE) {
-                       if(p->to.reg != NREG)
+               if(p->from3.type != TYPE_NONE) {
+                       if(p->to.reg != 0)
                                ctxt->diag("can't use both mask and CR(n)\n%P", p);
                        v = regoff(ctxt, &p->from3) & 0xff;
                } else {
-                       if(p->to.reg == NREG)
+                       if(p->to.reg == 0)
                                v = 0xff;       /* CR */
                        else
                                v = 1<<(7-(p->to.reg&7));       /* CR(n) */
@@ -2255,7 +2248,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                break;
 
        case 70:        /* [f]cmp r,r,cr*/
-               if(p->reg == NREG)
+               if(p->reg == 0)
                        r = 0;
                else
                        r = (p->reg&7)<<2;
@@ -2263,7 +2256,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                break;
 
        case 71:        /* cmp[l] r,i,cr*/
-               if(p->reg == NREG)
+               if(p->reg == 0)
                        r = 0;
                else
                        r = (p->reg&7)<<2;
@@ -2275,18 +2268,18 @@ asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
                break;
 
        case 73:        /* mcrfs crfD,crfS */
-               if(p->from.type != D_FPSCR || p->from.reg == NREG ||
-                  p->to.type != D_CREG || p->to.reg == NREG)
+               if(p->from.type != TYPE_REG || p->from.reg != REG_FPSCR ||
+                  p->to.type != TYPE_REG || p->to.reg < REG_C0 || REG_C7 < p->to.reg)
                        ctxt->diag("illegal FPSCR/CR field number\n%P", p);
-               o1 = AOP_RRR(OP_MCRFS, ((p->to.reg&7L)<<2), ((p->from.reg&7)<<2), 0);
+               o1 = AOP_RRR(OP_MCRFS, ((p->to.reg&7L)<<2), ((0&7)<<2), 0);
                break;
 
        case 77:        /* syscall $scon, syscall Rx */
-               if(p->from.type == D_CONST) {
+               if(p->from.type == TYPE_CONST) {
                        if(p->from.offset > BIG || p->from.offset < -BIG)
                                ctxt->diag("illegal syscall, sysnum too large: %P", p);
                        o1 = AOP_IRR(OP_ADDI, REGZERO, REGZERO, p->from.offset);
-               } else if(p->from.type == D_REG) {
+               } else if(p->from.type == TYPE_REG) {
                        o1 = LOP_RRR(OP_OR, REGZERO, p->from.reg, p->from.reg);
                } else {
                        ctxt->diag("illegal syscall: %P", p);
@@ -2640,10 +2633,10 @@ opirr(Link *ctxt, int a)
        case AADD:      return OPVCC(14,0,0,0);
        case AADDC:     return OPVCC(12,0,0,0);
        case AADDCCC:   return OPVCC(13,0,0,0);
-       case AADD+AEND: return OPVCC(15,0,0,0);         /* ADDIS/CAU */
+       case AADD+ALAST:        return OPVCC(15,0,0,0);         /* ADDIS/CAU */
 
        case AANDCC:    return OPVCC(28,0,0,0);
-       case AANDCC+AEND:       return OPVCC(29,0,0,0);         /* ANDIS./ANDIU. */
+       case AANDCC+ALAST:      return OPVCC(29,0,0,0);         /* ANDIS./ANDIU. */
 
        case ABR:       return OPVCC(18,0,0,0);
        case ABL:       return OPVCC(18,0,0,0) | 1;
@@ -2670,7 +2663,7 @@ opirr(Link *ctxt, int a)
        case AMULLW:    return OPVCC(7,0,0,0);
 
        case AOR:       return OPVCC(24,0,0,0);
-       case AOR+AEND:  return OPVCC(25,0,0,0);         /* ORIS/ORIU */
+       case AOR+ALAST: return OPVCC(25,0,0,0);         /* ORIS/ORIU */
 
        case ARLWMI:    return OPVCC(20,0,0,0);         /* rlwimi */
        case ARLWMICC:  return OPVCC(20,0,0,1);
@@ -2700,7 +2693,7 @@ opirr(Link *ctxt, int a)
        case ATD:       return OPVCC(2,0,0,0);
 
        case AXOR:      return OPVCC(26,0,0,0);         /* XORIL */
-       case AXOR+AEND: return OPVCC(27,0,0,0);         /* XORIU */
+       case AXOR+ALAST:        return OPVCC(27,0,0,0);         /* XORIU */
        }
        ctxt->diag("bad opcode i/r %A", a);
        return 0;
index e5efa2eb2da8ac42ccc51d66fc4d004f541d5b39..e9dbc966b9919171dab56411dcb2682c06841435 100644 (file)
@@ -80,14 +80,14 @@ savedata(Link *ctxt, LSym *s, Prog *p, char *pn)
        Reloc *r;
 
        off = p->from.offset;
-       siz = ctxt->arch->datasize(p);
+       siz = p->from3.offset;
        if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
                mangle(pn);
        if(ctxt->enforce_data_order && off < s->np)
                ctxt->diag("data out of order (already have %d)\n%P", p);
        symgrow(ctxt, s, off+siz);
 
-       if(p->to.type == ctxt->arch->D_FCONST) {
+       if(p->to.type == TYPE_FCONST) {
                switch(siz) {
                default:
                case 4:
@@ -102,10 +102,10 @@ savedata(Link *ctxt, LSym *s, Prog *p, char *pn)
                                s->p[off+i] = cast[fnuxi8[i]];
                        break;
                }
-       } else if(p->to.type == ctxt->arch->D_SCONST) {
+       } else if(p->to.type == TYPE_SCONST) {
                for(i=0; i<siz; i++)
                        s->p[off+i] = p->to.u.sval[i];
-       } else if(p->to.type == ctxt->arch->D_CONST) {
+       } else if(p->to.type == TYPE_CONST) {
                if(p->to.sym)
                        goto addr;
                o = p->to.offset;
@@ -132,7 +132,7 @@ savedata(Link *ctxt, LSym *s, Prog *p, char *pn)
                                s->p[off+i] = cast[inuxi8[i]];
                        break;
                }
-       } else if(p->to.type == ctxt->arch->D_ADDR) {
+       } else if(p->to.type == TYPE_ADDR) {
        addr:
                r = addrel(s);
                r->off = off;
index 9f5a423d3881e81f44351d1568db5b22498a016b..754a7cc15e43cfc2a8ffa9b207b35217f85116a8 100644 (file)
@@ -9,6 +9,67 @@
 #include <bio.h>
 #include <link.h>
 
+int framepointer_enabled;
+int fieldtrack_enabled;
+Prog zprog;
+
+// Toolchain experiments.
+// These are controlled by the GOEXPERIMENT environment
+// variable recorded when the toolchain is built.
+// This list is also known to cmd/gc.
+static struct {
+       char *name;
+       int *val;
+} exper[] = {
+       {"fieldtrack", &fieldtrack_enabled},
+       {"framepointer", &framepointer_enabled},
+};
+
+static void
+addexp(char *s)
+{
+       int i;
+
+       for(i=0; i < nelem(exper); i++ ) {
+               if(strcmp(exper[i].name, s) == 0) {
+                       if(exper[i].val != nil)
+                               *exper[i].val = 1;
+                       return;
+               }
+       }
+       
+       print("unknown experiment %s\n", s);
+       exits("unknown experiment");
+}
+
+void
+linksetexp(void)
+{
+       char *f[20];
+       int i, nf;
+
+       // cmd/dist #defines GOEXPERIMENT for us.
+       nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
+       for(i=0; i<nf; i++)
+               addexp(f[i]);
+}
+
+char*
+expstring(void)
+{
+       int i;
+       static char buf[512];
+
+       strcpy(buf, "X");
+       for(i=0; i<nelem(exper); i++)
+               if(*exper[i].val)
+                       seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
+       if(strlen(buf) == 1)
+               strcpy(buf, "X,none");
+       buf[1] = ':';
+       return buf;
+}
+
 // replace all "". with pkg.
 char*
 expandpkg(char *t0, char *pkg)
index 6d0fe4a2a4d05d5615329144e1e83aea9826476d..e055829142b6b439a66a61a60852f513081d9b53 100644 (file)
@@ -217,7 +217,8 @@ copyp(Link *ctxt, Prog *q)
 {
        Prog *p;
 
-       p = ctxt->arch->prg();
+       USED(ctxt);
+       p = emallocz(sizeof(Prog));
        *p = *q;
        return p;
 }
@@ -227,7 +228,8 @@ appendp(Link *ctxt, Prog *q)
 {
        Prog *p;
 
-       p = ctxt->arch->prg();
+       USED(ctxt);
+       p = emallocz(sizeof(Prog));
        p->link = q->link;
        q->link = p;
        p->lineno = q->lineno;
index a91df55e695386fb9858c400549b0bc5d877e288..3d3e8e7d122853ba91d3b833e73fd1f79fb87b26 100644 (file)
@@ -33,6 +33,7 @@
 #include <bio.h>
 #include <link.h>
 #include "../cmd/5l/5.out.h"
+#include "../runtime/funcdata.h"
 
 enum
 {
@@ -89,7 +90,7 @@ Pconv(Fmt *fp)
        bigP = p;
        a = p->as;
        s = p->scond;
-       strcpy(sc, extra[s & C_SCOND]);
+       strcpy(sc, extra[(s & C_SCOND) ^ C_SCOND_XOR]);
        if(s & C_SBIT)
                strcat(sc, ".S");
        if(s & C_PBIT)
@@ -99,27 +100,24 @@ Pconv(Fmt *fp)
        if(s & C_UBIT)          /* ambiguous with FBIT */
                strcat(sc, ".U");
        if(a == AMOVM) {
-               if(p->from.type == D_CONST)
+               if(p->from.type == TYPE_CONST)
                        sprint(str, "%.5lld (%L)        %A%s    %@,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
                else
-               if(p->to.type == D_CONST)
+               if(p->to.type == TYPE_CONST)
                        sprint(str, "%.5lld (%L)        %A%s    %D,%@", p->pc, p->lineno, a, sc, &p->from, &p->to);
                else
                        sprint(str, "%.5lld (%L)        %A%s    %D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
        } else
        if(a == ADATA)
-               sprint(str, "%.5lld (%L)        %A      %D/%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
+               sprint(str, "%.5lld (%L)        %A      %D/%lld,%D", p->pc, p->lineno, a, &p->from, p->from3.offset, &p->to);
        else
        if(p->as == ATEXT)
-               sprint(str, "%.5lld (%L)        %A      %D,%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
+               sprint(str, "%.5lld (%L)        %A      %D,%lld,%D", p->pc, p->lineno, a, &p->from, p->from3.offset, &p->to);
        else
-       if(p->reg == NREG)
+       if(p->reg == 0)
                sprint(str, "%.5lld (%L)        %A%s    %D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
        else
-       if(p->from.type != D_FREG)
-               sprint(str, "%.5lld (%L)        %A%s    %D,R%d,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
-       else
-               sprint(str, "%.5lld (%L)        %A%s    %D,F%d,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
+               sprint(str, "%.5lld (%L)        %A%s    %D,%R,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
        bigP = nil;
        return fmtstrcpy(fp, str);
 }
@@ -152,60 +150,52 @@ Dconv(Fmt *fp)
                sprint(str, "GOK-type(%d)", a->type);
                break;
 
-       case D_NONE:
+       case TYPE_NONE:
                str[0] = 0;
-               if(a->name != D_NONE || a->reg != NREG || a->sym != nil)
-                       sprint(str, "%M(R%d)(NONE)", a, a->reg);
+               if(a->name != TYPE_NONE || a->reg != 0 || a->sym != nil)
+                       sprint(str, "%M(%R)(NONE)", a, a->reg);
                break;
 
-       case D_CONST:
-               if(a->reg != NREG)
-                       sprint(str, "$%M(R%d)", a, a->reg);
+       case TYPE_CONST:
+       case TYPE_ADDR:
+               if(a->reg != 0)
+                       sprint(str, "$%M(%R)", a, a->reg);
                else
                        sprint(str, "$%M", a);
                break;
 
-       case D_CONST2:
-               sprint(str, "$%lld-%d", a->offset, a->offset2);
+       case TYPE_TEXTSIZE:
+               if(a->u.argsize == ArgsSizeUnknown)
+                       sprint(str, "$%lld", a->offset);
+               else
+                       sprint(str, "$%lld-%lld", a->offset, a->u.argsize);
                break;
 
-       case D_SHIFT:
+       case TYPE_SHIFT:
                v = a->offset;
                op = &"<<>>->@>"[(((v>>5) & 3) << 1)];
                if(v & (1<<4))
                        sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
                else
                        sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
-               if(a->reg != NREG)
-                       sprint(str+strlen(str), "(R%d)", a->reg);
+               if(a->reg != 0)
+                       sprint(str+strlen(str), "(%R)", a->reg);
                break;
 
-       case D_OREG:
-               if(a->reg != NREG)
-                       sprint(str, "%M(R%d)", a, a->reg);
+       case TYPE_MEM:
+               if(a->reg != 0)
+                       sprint(str, "%M(%R)", a, a->reg);
                else
                        sprint(str, "%M", a);
                break;
 
-       case D_REG:
-               sprint(str, "R%d", a->reg);
-               if(a->name != D_NONE || a->sym != nil)
-                       sprint(str, "%M(R%d)(REG)", a, a->reg);
-               break;
-
-       case D_FREG:
-               sprint(str, "F%d", a->reg);
-               if(a->name != D_NONE || a->sym != nil)
-                       sprint(str, "%M(R%d)(REG)", a, a->reg);
-               break;
-
-       case D_PSR:
-               sprint(str, "PSR");
-               if(a->name != D_NONE || a->sym != nil)
-                       sprint(str, "%M(PSR)(REG)", a);
+       case TYPE_REG:
+               sprint(str, "%R", a->reg);
+               if(a->name != TYPE_NONE || a->sym != nil)
+                       sprint(str, "%M(%R)(REG)", a, a->reg);
                break;
 
-       case D_BRANCH:
+       case TYPE_BRANCH:
                if(a->sym != nil)
                        sprint(str, "%s(SB)", a->sym->name);
                else if(bigP != nil && bigP->pcond != nil)
@@ -216,11 +206,11 @@ Dconv(Fmt *fp)
                        sprint(str, "%lld(PC)", a->offset/*-pc*/);
                break;
 
-       case D_FCONST:
+       case TYPE_FCONST:
                sprint(str, "$%.17g", a->u.dval);
                break;
 
-       case D_SCONST:
+       case TYPE_SCONST:
                sprint(str, "$\"%$\"", a->u.sval);
                break;
        }
@@ -237,9 +227,8 @@ RAconv(Fmt *fp)
        a = va_arg(fp->args, Addr*);
        sprint(str, "GOK-reglist");
        switch(a->type) {
-       case D_CONST:
-       case D_CONST2:
-               if(a->reg != NREG)
+       case TYPE_CONST:
+               if(a->reg != 0)
                        break;
                if(a->sym != nil)
                        break;
@@ -310,11 +299,27 @@ static int
 Rconv(Fmt *fp)
 {
        int r;
-       char str[STRINGSZ];
 
        r = va_arg(fp->args, int);
-       sprint(str, "R%d", r);
-       return fmtstrcpy(fp, str);
+       if(r == 0)
+               return fmtstrcpy(fp, "NONE");
+       if(REG_R0 <= r && r <= REG_R15)
+               return fmtprint(fp, "R%d", r-REG_R0);
+       if(REG_F0 <= r && r <= REG_F15)
+               return fmtprint(fp, "F%d", r-REG_F0);
+
+       switch(r) {
+       case REG_FPSR:
+               return fmtstrcpy(fp, "FPSR");
+       case REG_FPCR:
+               return fmtstrcpy(fp, "FPCR");
+       case REG_CPSR:
+               return fmtstrcpy(fp, "CPSR");
+       case REG_SPSR:
+               return fmtstrcpy(fp, "SPSR");
+       }
+
+       return fmtprint(fp, "badreg(%d)", r);
 }
 
 static int
@@ -348,23 +353,23 @@ Mconv(Fmt *fp)
                sprint(str, "GOK-name(%d)", a->name);
                break;
 
-       case D_NONE:
+       case NAME_NONE:
                sprint(str, "%lld", a->offset);
                break;
 
-       case D_EXTERN:
+       case NAME_EXTERN:
                sprint(str, "%s+%d(SB)", s->name, (int)a->offset);
                break;
 
-       case D_STATIC:
+       case NAME_STATIC:
                sprint(str, "%s<>+%d(SB)", s->name, (int)a->offset);
                break;
 
-       case D_AUTO:
+       case NAME_AUTO:
                sprint(str, "%s-%d(SP)", s->name, (int)-a->offset);
                break;
 
-       case D_PARAM:
+       case NAME_PARAM:
                sprint(str, "%s+%d(FP)", s->name, (int)a->offset);
                break;
        }
index dc685158d24c8578f26621e614a19b67d3626c6c..db8b0011affa4d8884d04cf68a35a73ad81b63bc 100644 (file)
 #include <bio.h>
 #include <link.h>
 #include "../cmd/6l/6.out.h"
+#include "../runtime/funcdata.h"
 
 //
 // Format conversions
 //     %A int          Opcodes (instruction mnemonics)
 //
 //     %D Addr*        Addresses (instruction operands)
-//             Flags: "%lD": seperate the high and low words of a constant by "-"
 //
 //     %P Prog*        Instructions
 //
@@ -85,17 +85,17 @@ Pconv(Fmt *fp)
 
        switch(p->as) {
        case ADATA:
-               sprint(str, "%.5lld (%L)        %A      %D/%d,%D",
-                       p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
+               sprint(str, "%.5lld (%L)        %A      %D/%lld,%D",
+                       p->pc, p->lineno, p->as, &p->from, p->from3.offset, &p->to);
                break;
 
        case ATEXT:
-               if(p->from.scale) {
-                       sprint(str, "%.5lld (%L)        %A      %D,%d,%lD",
-                               p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
+               if(p->from3.offset) {
+                       sprint(str, "%.5lld (%L)        %A      %D,%lld,%D",
+                               p->pc, p->lineno, p->as, &p->from, p->from3.offset, &p->to);
                        break;
                }
-               sprint(str, "%.5lld (%L)        %A      %D,%lD",
+               sprint(str, "%.5lld (%L)        %A      %D,%D",
                        p->pc, p->lineno, p->as, &p->from, &p->to);
                break;
 
@@ -122,41 +122,31 @@ Dconv(Fmt *fp)
 {
        char str[STRINGSZ], s[STRINGSZ];
        Addr *a;
-       int i;
 
        a = va_arg(fp->args, Addr*);
-       i = a->type;
-
-       if(fp->flags & FmtLong) {
-               if(i == D_CONST)
-                       sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32);
-               else {
-                       // ATEXT dst is not constant
-                       sprint(str, "!!%D", a);
-               }
-               goto brk;
-       }
 
-       if(i >= D_INDIR) {
-               if(a->offset)
-                       sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
-               else
-                       sprint(str, "(%R)", i-D_INDIR);
-               goto brk;
-       }
-       switch(i) {
+       switch(a->type) {
        default:
-               if(a->offset)
-                       sprint(str, "$%lld,%R", a->offset, i);
-               else
-                       sprint(str, "%R", i);
+               sprint(str, "type=%d", a->type);
                break;
 
-       case D_NONE:
+       case TYPE_NONE:
                str[0] = 0;
                break;
+       
+       case TYPE_REG:
+               // TODO(rsc): This special case is for instructions like
+               //      PINSRQ  CX,$1,X6
+               // where the $1 is included in the p->to Addr.
+               // Move into a new field.
+               if(a->offset != 0) {
+                       sprint(str, "$%lld,%R", a->offset, a->reg);
+                       break;
+               }
+               sprint(str, "%R", a->reg);
+               break;
 
-       case D_BRANCH:
+       case TYPE_BRANCH:
                if(a->sym != nil)
                        sprint(str, "%s(SB)", a->sym->name);
                else if(bigP != nil && bigP->pcond != nil)
@@ -167,54 +157,74 @@ Dconv(Fmt *fp)
                        sprint(str, "%lld(PC)", a->offset);
                break;
 
-       case D_EXTERN:
-               sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
-               break;
-
-       case D_STATIC:
-               sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
+       case TYPE_MEM:
+               switch(a->name) {
+               default:
+                       sprint(str, "name=%d", a->name);
+                       break;
+               case NAME_NONE:
+                       if(a->offset)
+                               sprint(str, "%lld(%R)", a->offset, a->reg);
+                       else
+                               sprint(str, "(%R)", a->reg);
+                       break;
+               case NAME_EXTERN:
+                       sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
+                       break;
+               case NAME_STATIC:
+                       sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
+                       break;
+               case NAME_AUTO:
+                       if(a->sym)
+                               sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
+                       else
+                               sprint(str, "%lld(SP)", a->offset);
+                       break;
+               case NAME_PARAM:
+                       if(a->sym)
+                               sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
+                       else
+                               sprint(str, "%lld(FP)", a->offset);
+                       break;
+               }
+               if(a->index != REG_NONE) {
+                       sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+                       strcat(str, s);
+               }
                break;
 
-       case D_AUTO:
-               if(a->sym)
-                       sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
-               else
-                       sprint(str, "%lld(SP)", a->offset);
+       case TYPE_CONST:
+               sprint(str, "$%lld", a->offset);
+               // TODO(rsc): This special case is for SHRQ $32, AX:DX, which encodes as
+               //      SHRQ $32(DX*0), AX
+               // Remove.
+               if(a->index != REG_NONE) {
+                       sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+                       strcat(str, s);
+               }
                break;
-
-       case D_PARAM:
-               if(a->sym)
-                       sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
+       
+       case TYPE_TEXTSIZE:
+               if(a->u.argsize == ArgsSizeUnknown)
+                       sprint(str, "$%lld", a->offset);
                else
-                       sprint(str, "%lld(FP)", a->offset);
-               break;
-
-       case D_CONST:
-               sprint(str, "$%lld", a->offset);
+                       sprint(str, "$%lld-%lld", a->offset, a->u.argsize);
                break;
 
-       case D_FCONST:
+       case TYPE_FCONST:
                sprint(str, "$(%.17g)", a->u.dval);
                break;
 
-       case D_SCONST:
+       case TYPE_SCONST:
                sprint(str, "$\"%$\"", a->u.sval);
                break;
 
-       case D_ADDR:
-               a->type = a->index;
-               a->index = D_NONE;
+       case TYPE_ADDR:
+               a->type = TYPE_MEM;
                sprint(str, "$%D", a);
-               a->index = a->type;
-               a->type = D_ADDR;
-               goto conv;
-       }
-brk:
-       if(a->index != D_NONE) {
-               sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
-               strcat(str, s);
+               a->type = TYPE_ADDR;
+               break;
        }
-conv:
        return fmtstrcpy(fp, str);
 }
 
@@ -343,7 +353,7 @@ static char*        regstr[] =
        "TR7",
 
        "TLS",  /* [D_TLS] */
-       "NONE", /* [D_NONE] */
+       "MAXREG",       /* [MAXREG] */
 };
 
 static int
@@ -353,8 +363,11 @@ Rconv(Fmt *fp)
        int r;
 
        r = va_arg(fp->args, int);
-       if(r >= D_AL && r <= D_NONE)
-               sprint(str, "%s", regstr[r-D_AL]);
+       if(r == REG_NONE)
+               return fmtstrcpy(fp, "NONE");
+
+       if(REG_AL <= r && r-REG_AL < nelem(regstr))
+               sprint(str, "%s", regstr[r-REG_AL]);
        else
                sprint(str, "gok(%d)", r);
 
index 63d96b9f972e778b24fe49f8c459aec1bfb229c8..66db2f1d786ccfca3f62385113dd430d96785c67 100644 (file)
@@ -33,6 +33,7 @@
 #include <bio.h>
 #include <link.h>
 #include "../cmd/8l/8.out.h"
+#include "../runtime/funcdata.h"
 
 static int     Aconv(Fmt *fp);
 static int     Dconv(Fmt *fp);
@@ -71,17 +72,17 @@ Pconv(Fmt *fp)
        bigP = p;
        switch(p->as) {
        case ADATA:
-               sprint(str, "%.5lld (%L)        %A      %D/%d,%D",
-                       p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
+               sprint(str, "%.5lld (%L)        %A      %D/%lld,%D",
+                       p->pc, p->lineno, p->as, &p->from, p->from3.offset, &p->to);
                break;
 
        case ATEXT:
-               if(p->from.scale) {
-                       sprint(str, "%.5lld (%L)        %A      %D,%d,%lD",
-                               p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
+               if(p->from3.offset) {
+                       sprint(str, "%.5lld (%L)        %A      %D,%lld,%D",
+                               p->pc, p->lineno, p->as, &p->from, p->from3.offset, &p->to);
                        break;
                }
-               sprint(str, "%.5lld (%L)        %A      %D,%lD",
+               sprint(str, "%.5lld (%L)        %A      %D,%D",
                        p->pc, p->lineno, p->as, &p->from, &p->to);
                break;
 
@@ -108,41 +109,38 @@ Dconv(Fmt *fp)
 {
        char str[STRINGSZ], s[STRINGSZ];
        Addr *a;
-       int i;
 
        a = va_arg(fp->args, Addr*);
-       i = a->type;
-
-       if(fp->flags & FmtLong) {
-               if(i == D_CONST2)
-                       sprint(str, "$%lld-%d", a->offset, a->offset2);
-               else {
-                       // ATEXT dst is not constant
-                       sprint(str, "!!%D", a);
-               }
-               goto brk;
-       }
-
-       if(i >= D_INDIR) {
-               if(a->offset)
-                       sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
-               else
-                       sprint(str, "(%R)", i-D_INDIR);
-               goto brk;
-       }
-       switch(i) {
+       
+       switch(a->type) {
        default:
-               if(a->offset)
-                       sprint(str, "$%lld,%R", a->offset, i);
-               else
-                       sprint(str, "%R", i);
+               sprint(str, "type=%d", a->type);
                break;
 
-       case D_NONE:
+       case TYPE_NONE:
                str[0] = 0;
                break;
+       
+       case TYPE_REG:
+               // TODO(rsc): This special case is for instructions like
+               //      PINSRQ  CX,$1,X6
+               // where the $1 is included in the p->to Addr.
+               // Move into a new field.
+               if(a->offset != 0) {
+                       sprint(str, "$%lld,%R", a->offset, a->reg);
+                       break;
+               }
+               sprint(str, "%R", a->reg);
+               // TODO(rsc): This special case is for SHRQ $32, AX:DX, which encodes as
+               //      SHRQ $32(DX*0), AX
+               // Remove.
+               if(a->index != REG_NONE) {
+                       sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+                       strcat(str, s);
+               }
+               break;
 
-       case D_BRANCH:
+       case TYPE_BRANCH:
                if(a->sym != nil)
                        sprint(str, "%s(SB)", a->sym->name);
                else if(bigP != nil && bigP->pcond != nil)
@@ -153,67 +151,81 @@ Dconv(Fmt *fp)
                        sprint(str, "%lld(PC)", a->offset);
                break;
 
-       case D_EXTERN:
-               sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
-               break;
-
-       case D_STATIC:
-               sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
-               break;
-
-       case D_AUTO:
-               if(a->sym)
-                       sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
-               else
-                       sprint(str, "%lld(SP)", a->offset);
-               break;
-
-       case D_PARAM:
-               if(a->sym)
-                       sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
-               else
-                       sprint(str, "%lld(FP)", a->offset);
+       case TYPE_MEM:
+               switch(a->name) {
+               default:
+                       sprint(str, "name=%d", a->name);
+                       break;
+               case NAME_NONE:
+                       if(a->offset)
+                               sprint(str, "%lld(%R)", a->offset, a->reg);
+                       else
+                               sprint(str, "(%R)", a->reg);
+                       break;
+               case NAME_EXTERN:
+                       sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
+                       break;
+               case NAME_STATIC:
+                       sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
+                       break;
+               case NAME_AUTO:
+                       if(a->sym)
+                               sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
+                       else
+                               sprint(str, "%lld(SP)", a->offset);
+                       break;
+               case NAME_PARAM:
+                       if(a->sym)
+                               sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
+                       else
+                               sprint(str, "%lld(FP)", a->offset);
+                       break;
+               }
+               if(a->index != REG_NONE) {
+                       sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+                       strcat(str, s);
+               }
                break;
 
-       case D_CONST:
+       case TYPE_CONST:
                sprint(str, "$%lld", a->offset);
+               // TODO(rsc): This special case is for SHRQ $32, AX:DX, which encodes as
+               //      SHRQ $32(DX*0), AX
+               // Remove.
+               if(a->index != REG_NONE) {
+                       sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+                       strcat(str, s);
+               }
                break;
 
-       case D_CONST2:
-               if(!(fp->flags & FmtLong)) {
-                       // D_CONST2 outside of ATEXT should not happen
-                       sprint(str, "!!$%lld-%d", a->offset, a->offset2);
-               }
+       case TYPE_TEXTSIZE:
+               if(a->u.argsize == ArgsSizeUnknown)
+                       sprint(str, "$%lld", a->offset);
+               else
+                       sprint(str, "$%lld-%lld", a->offset, a->u.argsize);
                break;
 
-       case D_FCONST:
+       case TYPE_FCONST:
                sprint(str, "$(%.17g)", a->u.dval);
                break;
 
-       case D_SCONST:
+       case TYPE_SCONST:
                sprint(str, "$\"%$\"", a->u.sval);
                break;
 
-       case D_ADDR:
-               a->type = a->index;
-               a->index = D_NONE;
+       case TYPE_ADDR:
+               a->type = TYPE_MEM;
                sprint(str, "$%D", a);
-               a->index = a->type;
-               a->type = D_ADDR;
-               goto conv;
-       }
-brk:
-       if(a->index != D_NONE) {
-               sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
-               strcat(str, s);
+               a->type = TYPE_ADDR;
+               break;
        }
-conv:
+
        return fmtstrcpy(fp, str);
 }
 
 static char*   regstr[] =
 {
-       "AL",   /* [D_AL] */
+       "AL",   /* [REG_AL] */
        "CL",
        "DL",
        "BL",
@@ -222,7 +234,7 @@ static char*        regstr[] =
        "DH",
        "BH",
 
-       "AX",   /* [D_AX] */
+       "AX",   /* [REG_AX] */
        "CX",
        "DX",
        "BX",
@@ -231,7 +243,7 @@ static char*        regstr[] =
        "SI",
        "DI",
 
-       "F0",   /* [D_F0] */
+       "F0",   /* [REG_F0] */
        "F1",
        "F2",
        "F3",
@@ -240,20 +252,20 @@ static char*      regstr[] =
        "F6",
        "F7",
 
-       "CS",   /* [D_CS] */
+       "CS",   /* [REG_CS] */
        "SS",
        "DS",
        "ES",
        "FS",
        "GS",
 
-       "GDTR", /* [D_GDTR] */
-       "IDTR", /* [D_IDTR] */
-       "LDTR", /* [D_LDTR] */
-       "MSW",  /* [D_MSW] */
-       "TASK", /* [D_TASK] */
+       "GDTR", /* [REG_GDTR] */
+       "IDTR", /* [REG_IDTR] */
+       "LDTR", /* [REG_LDTR] */
+       "MSW",  /* [REG_MSW] */
+       "TASK", /* [REG_TASK] */
 
-       "CR0",  /* [D_CR] */
+       "CR0",  /* [REG_CR] */
        "CR1",
        "CR2",
        "CR3",
@@ -262,7 +274,7 @@ static char*        regstr[] =
        "CR6",
        "CR7",
 
-       "DR0",  /* [D_DR] */
+       "DR0",  /* [REG_DR] */
        "DR1",
        "DR2",
        "DR3",
@@ -271,7 +283,7 @@ static char*        regstr[] =
        "DR6",
        "DR7",
 
-       "TR0",  /* [D_TR] */
+       "TR0",  /* [REG_TR] */
        "TR1",
        "TR2",
        "TR3",
@@ -280,7 +292,7 @@ static char*        regstr[] =
        "TR6",
        "TR7",
 
-       "X0",   /* [D_X0] */
+       "X0",   /* [REG_X0] */
        "X1",
        "X2",
        "X3",
@@ -289,8 +301,8 @@ static char*        regstr[] =
        "X6",
        "X7",
 
-       "TLS",  /* [D_TLS] */
-       "NONE", /* [D_NONE] */
+       "TLS",  /* [REG_TLS] */
+       "MAXREG",       /* [MAXREG] */
 };
 
 static int
@@ -300,8 +312,10 @@ Rconv(Fmt *fp)
        int r;
 
        r = va_arg(fp->args, int);
-       if(r >= D_AL && r <= D_NONE)
-               sprint(str, "%s", regstr[r-D_AL]);
+       if(r == REG_NONE)
+               return fmtstrcpy(fp, "NONE");
+       if(r >= REG_AL && r-REG_AL < nelem(regstr))
+               sprint(str, "%s", regstr[r-REG_AL]);
        else
                sprint(str, "gok(%d)", r);
 
index b63099a5aba93d8d8aff515cc0c446d1bf5815f4..a45e73e61e136e6fd5c09b43809ff6b762ad2d48 100644 (file)
@@ -32,6 +32,7 @@
 #include <bio.h>
 #include <link.h>
 #include "../cmd/9l/9.out.h"
+#include "../runtime/funcdata.h"
 
 enum
 {
@@ -51,7 +52,6 @@ static int    DRconv(Fmt*);
 //     %A int          Opcodes (instruction mnemonics)
 //
 //     %D Addr*        Addresses (instruction operands)
-//             Flags: "%lD": seperate the high and low words of a constant by "-"
 //
 //     %P Prog*        Instructions
 //
@@ -86,46 +86,38 @@ Pconv(Fmt *fp)
 {
        char str[STRINGSZ];
        Prog *p;
-       int a, ch;
+       int a;
 
        p = va_arg(fp->args, Prog*);
        bigP = p;
        a = p->as;
 
-       if(a == ADATA || a == AINIT || a == ADYNT)
-               sprint(str, "%.5lld (%L)        %A      %D/%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
-       else if(a == ATEXT) {
-               if(p->reg != 0)
-                       sprint(str, "%.5lld (%L)        %A      %D,%d,%lD", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
-               else
-                       sprint(str, "%.5lld (%L)        %A      %D,%lD", p->pc, p->lineno, a, &p->from, &p->to);
-       } else if(a == AGLOBL) {
-               if(p->reg != 0)
-                       sprint(str, "%.5lld (%L)        %A      %D,%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
+       str[0] = 0;
+       if(a == ADATA)
+               sprint(str, "%.5lld (%L)        %A      %D/%lld,%D", p->pc, p->lineno, a, &p->from, p->from3.offset, &p->to);
+       else if(a == ATEXT || a == AGLOBL) {
+               if(p->from3.offset != 0)
+                       sprint(str, "%.5lld (%L)        %A      %D,%lld,%D", p->pc, p->lineno, a, &p->from, p->from3.offset, &p->to);
                else
-                       sprint(str, "%.5lld (%L)        %A      %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
+                       sprint(str, "%.5lld (%L)        %A      %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
        } else {
                if(p->mark & NOSCHED)
                        sprint(strchr(str, 0), "*");
-               if(p->reg == NREG && p->from3.type == D_NONE)
+               if(p->reg == 0 && p->from3.type == TYPE_NONE)
                        sprint(strchr(str, 0), "%.5lld (%L)     %A      %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
                else
-               if(a != ATEXT && p->from.type == D_OREG) {
-                       sprint(strchr(str, 0), "%.5lld (%L)     %A      %lld(R%d+R%d),%D", p->pc, p->lineno, a,
+               if(a != ATEXT && p->from.type == TYPE_MEM) {
+                       sprint(strchr(str, 0), "%.5lld (%L)     %A      %lld(%R+%R),%D", p->pc, p->lineno, a,
                                p->from.offset, p->from.reg, p->reg, &p->to);
                } else
-               if(p->to.type == D_OREG) {
-                       sprint(strchr(str, 0), "%.5lld (%L)     %A      %D,%lld(R%d+R%d)", p->pc, p->lineno, a,
+               if(p->to.type == TYPE_MEM) {
+                       sprint(strchr(str, 0), "%.5lld (%L)     %A      %D,%lld(%R+%R)", p->pc, p->lineno, a,
                                        &p->from, p->to.offset, p->to.reg, p->reg);
                } else {
                        sprint(strchr(str, 0), "%.5lld (%L)     %A      %D", p->pc, p->lineno, a, &p->from);
-                       if(p->reg != NREG) {
-                               ch = 'R';
-                               if(p->from.type == D_FREG)
-                                       ch = 'F';
-                               sprint(strchr(str, 0), ",%c%d", ch, p->reg);
-                       }
-                       if(p->from3.type != D_NONE)
+                       if(p->reg != 0)
+                               sprint(strchr(str, 0), ",%R", p->reg);
+                       if(p->from3.type != TYPE_NONE)
                                sprint(strchr(str, 0), ",%D", &p->from3);
                        sprint(strchr(str, 0), ",%D", &p->to);
                }
@@ -157,104 +149,46 @@ Dconv(Fmt *fp)
 
        a = va_arg(fp->args, Addr*);
 
-       if(fp->flags & FmtLong) {
-               if(a->type == D_CONST)
-                       sprint(str, "$%d-%d", (int32)a->offset, (int32)(a->offset>>32));
-               else {
-                       // ATEXT dst is not constant
-                       sprint(str, "!!%D", a);
-               }
-               goto ret;
-       }
-
        switch(a->type) {
        default:
                sprint(str, "GOK-type(%d)", a->type);
                break;
 
-       case D_NONE:
+       case TYPE_NONE:
                str[0] = 0;
-               if(a->name != D_NONE || a->reg != NREG || a->sym != nil)
-                       sprint(str, "%M(R%d)(NONE)", a, a->reg);
+               if(a->name != TYPE_NONE || a->reg != 0 || a->sym != nil)
+                       sprint(str, "%M(%R)(NONE)", a, a->reg);
                break;
 
-       case D_CONST:
-       case D_DCONST:
-               if(a->reg != NREG)
-                       sprint(str, "$%M(R%d)", a, a->reg);
+       case TYPE_CONST:
+       case TYPE_ADDR:
+               if(a->reg != 0)
+                       sprint(str, "$%M(%R)", a, a->reg);
                else
                        sprint(str, "$%M", a);
                break;
 
-       case D_OREG:
-               if(a->reg != NREG)
-                       sprint(str, "%M(R%d)", a, a->reg);
-               else
-                       sprint(str, "%M", a);
-               break;
-
-       case D_REG:
-               sprint(str, "R%d", a->reg);
-               if(a->name != D_NONE || a->sym != nil)
-                       sprint(str, "%M(R%d)(REG)", a, a->reg);
-               break;
-
-       case D_FREG:
-               sprint(str, "F%d", a->reg);
-               if(a->name != D_NONE || a->sym != nil)
-                       sprint(str, "%M(F%d)(REG)", a, a->reg);
-               break;
-
-       case D_CREG:
-               if(a->reg == NREG)
-                       strcpy(str, "CR");
+       case TYPE_TEXTSIZE:
+               if(a->u.argsize == ArgsSizeUnknown)
+                       sprint(str, "$%lld", a->offset);
                else
-                       sprint(str, "CR%d", a->reg);
-               if(a->name != D_NONE || a->sym != nil)
-                       sprint(str, "%M(C%d)(REG)", a, a->reg);
+                       sprint(str, "$%lld-%lld", a->offset, a->u.argsize);
                break;
 
-       case D_SPR:
-               if(a->name == D_NONE && a->sym == nil) {
-                       switch((ulong)a->offset) {
-                       case D_XER: sprint(str, "XER"); break;
-                       case D_LR: sprint(str, "LR"); break;
-                       case D_CTR: sprint(str, "CTR"); break;
-                       default: sprint(str, "SPR(%lld)", a->offset); break;
-                       }
-                       break;
-               }
-               sprint(str, "SPR-GOK(%d)", a->reg);
-               if(a->name != D_NONE || a->sym != nil)
-                       sprint(str, "%M(SPR-GOK%d)(REG)", a, a->reg);
-               break;
-
-       case D_DCR:
-               if(a->name == D_NONE && a->sym == nil) {
-                       sprint(str, "DCR(%lld)", a->offset);
-                       break;
-               }
-               sprint(str, "DCR-GOK(%d)", a->reg);
-               if(a->name != D_NONE || a->sym != nil)
-                       sprint(str, "%M(DCR-GOK%d)(REG)", a, a->reg);
-               break;
-
-       case D_OPT:
-               sprint(str, "OPT(%d)", a->reg);
-               break;
-
-       case D_FPSCR:
-               if(a->reg == NREG)
-                       strcpy(str, "FPSCR");
+       case TYPE_MEM:
+               if(a->reg != 0)
+                       sprint(str, "%M(%R)", a, a->reg);
                else
-                       sprint(str, "FPSCR(%d)", a->reg);
+                       sprint(str, "%M", a);
                break;
 
-       case D_MSR:
-               sprint(str, "MSR");
+       case TYPE_REG:
+               sprint(str, "%R", a->reg);
+               if(a->name != TYPE_NONE || a->sym != nil)
+                       sprint(str, "%M(%R)(REG)", a, a->reg);
                break;
 
-       case D_BRANCH:
+       case TYPE_BRANCH:
                if(bigP->pcond != nil) {
                        v = bigP->pcond->pc;
                        //if(v >= INITTEXT)
@@ -271,17 +205,16 @@ Dconv(Fmt *fp)
                        sprint(str, "%lld(APC)", a->offset);
                break;
 
-       case D_FCONST:
+       case TYPE_FCONST:
                //sprint(str, "$%lux-%lux", a->ieee.h, a->ieee.l);
                sprint(str, "$%.17g", a->u.dval);
                break;
 
-       case D_SCONST:
+       case TYPE_SCONST:
                sprint(str, "$\"%$\"", a->u.sval);
                break;
        }
 
-ret:
        return fmtstrcpy(fp, str);
 }
 
@@ -308,7 +241,7 @@ Mconv(Fmt *fp)
                sprint(str, "GOK-name(%d)", a->name);
                break;
 
-       case D_NONE:
+       case TYPE_NONE:
                l = a->offset;
                if((vlong)l != a->offset)
                        sprint(str, "0x%llux", a->offset);
@@ -316,25 +249,25 @@ Mconv(Fmt *fp)
                        sprint(str, "%lld", a->offset);
                break;
 
-       case D_EXTERN:
+       case NAME_EXTERN:
                if(a->offset != 0)
                        sprint(str, "%s+%lld(SB)", s->name, a->offset);
                else
                        sprint(str, "%s(SB)", s->name);
                break;
 
-       case D_STATIC:
+       case NAME_STATIC:
                sprint(str, "%s<>+%lld(SB)", s->name, a->offset);
                break;
 
-       case D_AUTO:
+       case NAME_AUTO:
                if(s == nil)
                        sprint(str, "%lld(SP)", -a->offset);
                else
                        sprint(str, "%s-%lld(SP)", s->name, -a->offset);
                break;
 
-       case D_PARAM:
+       case NAME_PARAM:
                if(s == nil)
                        sprint(str, "%lld(FP)", a->offset);
                else
@@ -348,15 +281,38 @@ Mconv(Fmt *fp)
 static int
 Rconv(Fmt *fp)
 {
-       char str[STRINGSZ];
        int r;
 
        r = va_arg(fp->args, int);
-       if(r < NREG)
-               sprint(str, "r%d", r);
-       else
-               sprint(str, "f%d", r-NREG);
-       return fmtstrcpy(fp, str);
+       if(r == 0)
+               return fmtstrcpy(fp, "NONE");
+       if(REG_R0 <= r && r <= REG_R31)
+               return fmtprint(fp, "R%d", r-REG_R0);
+       if(REG_F0 <= r && r <= REG_F31)
+               return fmtprint(fp, "F%d", r-REG_F0);
+       if(REG_C0 <= r && r <= REG_C7)
+               return fmtprint(fp, "C%d", r-REG_C0);
+       if(r == REG_CR)
+               return fmtstrcpy(fp, "CR");
+       if(REG_SPR0 <= r && r <= REG_SPR0+1023) {
+               switch(r) {
+               case REG_XER:
+                       return fmtstrcpy(fp, "XER");
+               case REG_LR:
+                       return fmtstrcpy(fp, "LR");
+               case REG_CTR:
+                       return fmtstrcpy(fp, "CTR");
+               }
+               return fmtprint(fp, "SPR(%d)", r-REG_SPR0);
+       }
+       if(REG_DCR0 <= r && r <= REG_DCR0+1023)
+               return fmtprint(fp, "DCR(%d)", r-REG_DCR0);
+       if(r == REG_FPSCR)
+               return fmtstrcpy(fp, "FPSCR");
+       if(r == REG_MSR)
+               return fmtstrcpy(fp, "MSR");
+
+       return fmtprint(fp, "badreg(%d)", r);
 }
 
 static int
index 86cb902f9c5a01718a4213a8c680dc90f9198b55..805d7a59c230e9a9b7eaa25d3e2e6ca5ca9f19b5 100644 (file)
 #include "../cmd/5l/5.out.h"
 #include "../runtime/stack.h"
 
-static Prog zprg5 = {
-       .as = AGOK,
-       .scond = C_SCOND_NONE,
-       .reg = NREG,
-       .from = {
-               .name = D_NONE,
-               .type = D_NONE,
-               .reg = NREG,
-       },
-       .to = {
-               .name = D_NONE,
-               .type = D_NONE,
-               .reg = NREG,
-       },
-};
-
-static int
-symtype(Addr *a)
-{
-       return a->name;
-}
-
-static int
-isdata(Prog *p)
-{
-       return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
-       return p->as == ABL;
-}
-
-static int
-datasize(Prog *p)
-{
-       return p->reg;
-}
-
-static int
-textflag(Prog *p)
-{
-       return p->reg;
-}
-
-static void
-settextflag(Prog *p, int f)
-{
-       p->reg = f;
-}
-
 static void
 progedit(Link *ctxt, Prog *p)
 {
@@ -97,14 +45,14 @@ progedit(Link *ctxt, Prog *p)
        p->from.class = 0;
        p->to.class = 0;
 
-       // Rewrite B/BL to symbol as D_BRANCH.
+       // Rewrite B/BL to symbol as TYPE_BRANCH.
        switch(p->as) {
        case AB:
        case ABL:
        case ADUFFZERO:
        case ADUFFCOPY:
-               if(p->to.type == D_OREG && (p->to.name == D_EXTERN || p->to.name == D_STATIC) && p->to.sym != nil)
-                       p->to.type = D_BRANCH;
+               if(p->to.type == TYPE_MEM && (p->to.name == NAME_EXTERN || p->to.name == NAME_STATIC) && p->to.sym != nil)
+                       p->to.type = TYPE_BRANCH;
                break;
        }
 
@@ -124,24 +72,24 @@ progedit(Link *ctxt, Prog *p)
                                        tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0);
                                // MOVW LR, R11
                                p->as = AMOVW;
-                               p->from.type = D_REG;
+                               p->from.type = TYPE_REG;
                                p->from.reg = REGLINK;
-                               p->to.type = D_REG;
+                               p->to.type = TYPE_REG;
                                p->to.reg = REGTMP;
 
                                // BL   runtime.read_tls_fallback(SB)
                                p = appendp(ctxt, p);
                                p->as = ABL;
-                               p->to.type = D_BRANCH;
+                               p->to.type = TYPE_BRANCH;
                                p->to.sym = tlsfallback;
                                p->to.offset = 0;
 
                                // MOVW R11, LR
                                p = appendp(ctxt, p);
                                p->as = AMOVW;
-                               p->from.type = D_REG;
+                               p->from.type = TYPE_REG;
                                p->from.reg = REGTMP;
-                               p->to.type = D_REG;
+                               p->to.type = TYPE_REG;
                                p->to.reg = REGLINK;
                                break;
                        }
@@ -154,7 +102,7 @@ progedit(Link *ctxt, Prog *p)
        // Rewrite float constants to values stored in memory.
        switch(p->as) {
        case AMOVF:
-               if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
+               if(p->from.type == TYPE_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
                   (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
                        uint32 i32;
                        float32 f32;
@@ -167,15 +115,15 @@ progedit(Link *ctxt, Prog *p)
                                adduint32(ctxt, s, i32);
                                s->reachable = 0;
                        }
-                       p->from.type = D_OREG;
+                       p->from.type = TYPE_MEM;
                        p->from.sym = s;
-                       p->from.name = D_EXTERN;
+                       p->from.name = NAME_EXTERN;
                        p->from.offset = 0;
                }
                break;
 
        case AMOVD:
-               if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
+               if(p->from.type == TYPE_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
                   (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
                        uint64 i64;
                        memmove(&i64, &p->from.u.dval, 8);
@@ -186,9 +134,9 @@ progedit(Link *ctxt, Prog *p)
                                adduint64(ctxt, s, i64);
                                s->reachable = 0;
                        }
-                       p->from.type = D_OREG;
+                       p->from.type = TYPE_MEM;
                        p->from.sym = s;
-                       p->from.name = D_EXTERN;
+                       p->from.name = NAME_EXTERN;
                        p->from.offset = 0;
                }
                break;
@@ -203,23 +151,13 @@ progedit(Link *ctxt, Prog *p)
                if(ctxt->tlsg == nil)
                        ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
 
-               if(p->from.type == D_CONST && p->from.name == D_EXTERN && p->from.sym == ctxt->tlsg)
-                       p->from.type = D_OREG;
-               if(p->to.type == D_CONST && p->to.name == D_EXTERN && p->to.sym == ctxt->tlsg)
-                       p->to.type = D_OREG;
+               if(p->from.type == TYPE_ADDR && p->from.name == NAME_EXTERN && p->from.sym == ctxt->tlsg)
+                       p->from.type = TYPE_MEM;
+               if(p->to.type == TYPE_ADDR && p->to.name == NAME_EXTERN && p->to.sym == ctxt->tlsg)
+                       p->to.type = TYPE_MEM;
        }
 }
 
-static Prog*
-prg(void)
-{
-       Prog *p;
-
-       p = emallocz(sizeof(*p));
-       *p = zprg5;
-       return p;
-}
-
 static Prog*   stacksplit(Link*, Prog*, int32, int);
 static void            initdiv(Link*);
 static void    softfloat(Link*, LSym*);
@@ -255,7 +193,7 @@ nocache5(Prog *p)
 }
 
 static void
-addstacksplit(Link *ctxt, LSym *cursym)
+preprocess(Link *ctxt, LSym *cursym)
 {
        Prog *p, *pl, *p1, *p2, *q, *q1, *q2;
        int o;
@@ -282,35 +220,35 @@ addstacksplit(Link *ctxt, LSym *cursym)
        if(autoffset < 0)
                autoffset = 0;
        cursym->locals = autoffset;
-       cursym->args = p->to.offset2;
+       cursym->args = p->to.u.argsize;
 
        if(ctxt->debugzerostack) {
-               if(autoffset && !(p->reg&NOSPLIT)) {
+               if(autoffset && !(p->from3.offset&NOSPLIT)) {
                        // MOVW $4(R13), R1
                        p = appendp(ctxt, p);
                        p->as = AMOVW;
-                       p->from.type = D_CONST;
-                       p->from.reg = 13;
+                       p->from.type = TYPE_ADDR;
+                       p->from.reg = REG_R13;
                        p->from.offset = 4;
-                       p->to.type = D_REG;
-                       p->to.reg = 1;
+                       p->to.type = TYPE_REG;
+                       p->to.reg = REG_R1;
        
                        // MOVW $n(R13), R2
                        p = appendp(ctxt, p);
                        p->as = AMOVW;
-                       p->from.type = D_CONST;
-                       p->from.reg = 13;
+                       p->from.type = TYPE_ADDR;
+                       p->from.reg = REG_R13;
                        p->from.offset = 4 + autoffset;
-                       p->to.type = D_REG;
-                       p->to.reg = 2;
+                       p->to.type = TYPE_REG;
+                       p->to.reg = REG_R2;
        
                        // MOVW $0, R3
                        p = appendp(ctxt, p);
                        p->as = AMOVW;
-                       p->from.type = D_CONST;
+                       p->from.type = TYPE_CONST;
                        p->from.offset = 0;
-                       p->to.type = D_REG;
-                       p->to.reg = 3;
+                       p->to.type = TYPE_REG;
+                       p->to.reg = REG_R3;
        
                        // L:
                        //      MOVW.nil R3, 0(R1) +4
@@ -318,22 +256,22 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        //      BNE L
                        p = pl = appendp(ctxt, p);
                        p->as = AMOVW;
-                       p->from.type = D_REG;
-                       p->from.reg = 3;
-                       p->to.type = D_OREG;
-                       p->to.reg = 1;
+                       p->from.type = TYPE_REG;
+                       p->from.reg = REG_R3;
+                       p->to.type = TYPE_MEM;
+                       p->to.reg = REG_R1;
                        p->to.offset = 4;
                        p->scond |= C_PBIT;
        
                        p = appendp(ctxt, p);
                        p->as = ACMP;
-                       p->from.type = D_REG;
-                       p->from.reg = 1;
-                       p->reg = 2;
+                       p->from.type = TYPE_REG;
+                       p->from.reg = REG_R1;
+                       p->reg = REG_R2;
        
                        p = appendp(ctxt, p);
                        p->as = ABNE;
-                       p->to.type = D_BRANCH;
+                       p->to.type = TYPE_BRANCH;
                        p->pcond = pl;
                }
        }
@@ -438,21 +376,21 @@ addstacksplit(Link *ctxt, LSym *cursym)
                                        break;
                        }
 
-                       if(!(p->reg & NOSPLIT))
-                               p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
+                       if(!(p->from3.offset & NOSPLIT))
+                               p = stacksplit(ctxt, p, autosize, !(cursym->text->from3.offset&NEEDCTXT)); // emit split check
                        
                        // MOVW.W               R14,$-autosize(SP)
                        p = appendp(ctxt, p);
                        p->as = AMOVW;
                        p->scond |= C_WBIT;
-                       p->from.type = D_REG;
+                       p->from.type = TYPE_REG;
                        p->from.reg = REGLINK;
-                       p->to.type = D_OREG;
+                       p->to.type = TYPE_MEM;
                        p->to.offset = -autosize;
                        p->to.reg = REGSP;
                        p->spadj = autosize;
                        
-                       if(cursym->text->reg & WRAPPER) {
+                       if(cursym->text->from3.offset & WRAPPER) {
                                // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
                                //
                                //      MOVW g_panic(g), R1
@@ -472,64 +410,64 @@ addstacksplit(Link *ctxt, LSym *cursym)
 
                                p = appendp(ctxt, p);
                                p->as = AMOVW;
-                               p->from.type = D_OREG;
+                               p->from.type = TYPE_MEM;
                                p->from.reg = REGG;
                                p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
-                               p->to.type = D_REG;
-                               p->to.reg = 1;
+                               p->to.type = TYPE_REG;
+                               p->to.reg = REG_R1;
                        
                                p = appendp(ctxt, p);
                                p->as = ACMP;
-                               p->from.type = D_CONST;
+                               p->from.type = TYPE_CONST;
                                p->from.offset = 0;
-                               p->reg = 1;
+                               p->reg = REG_R1;
                        
                                p = appendp(ctxt, p);
                                p->as = ABEQ;
-                               p->to.type = D_BRANCH;
+                               p->to.type = TYPE_BRANCH;
                                p1 = p;
                                
                                p = appendp(ctxt, p);
                                p->as = AMOVW;
-                               p->from.type = D_OREG;
-                               p->from.reg = 1;
+                               p->from.type = TYPE_MEM;
+                               p->from.reg = REG_R1;
                                p->from.offset = 0; // Panic.argp
-                               p->to.type = D_REG;
-                               p->to.reg = 2;
+                               p->to.type = TYPE_REG;
+                               p->to.reg = REG_R2;
                        
                                p = appendp(ctxt, p);
                                p->as = AADD;
-                               p->from.type = D_CONST;
+                               p->from.type = TYPE_CONST;
                                p->from.offset = autosize+4;
-                               p->reg = 13;
-                               p->to.type = D_REG;
-                               p->to.reg = 3;
+                               p->reg = REG_R13;
+                               p->to.type = TYPE_REG;
+                               p->to.reg = REG_R3;
 
                                p = appendp(ctxt, p);
                                p->as = ACMP;
-                               p->from.type = D_REG;
-                               p->from.reg = 2;
-                               p->reg = 3;
+                               p->from.type = TYPE_REG;
+                               p->from.reg = REG_R2;
+                               p->reg = REG_R3;
 
                                p = appendp(ctxt, p);
                                p->as = ABNE;
-                               p->to.type = D_BRANCH;
+                               p->to.type = TYPE_BRANCH;
                                p2 = p;
                        
                                p = appendp(ctxt, p);
                                p->as = AADD;
-                               p->from.type = D_CONST;
+                               p->from.type = TYPE_CONST;
                                p->from.offset = 4;
-                               p->reg = 13;
-                               p->to.type = D_REG;
-                               p->to.reg = 4;
+                               p->reg = REG_R13;
+                               p->to.type = TYPE_REG;
+                               p->to.reg = REG_R4;
 
                                p = appendp(ctxt, p);
                                p->as = AMOVW;
-                               p->from.type = D_REG;
-                               p->from.reg = 4;
-                               p->to.type = D_OREG;
-                               p->to.reg = 1;
+                               p->from.type = TYPE_REG;
+                               p->from.reg = REG_R4;
+                               p->to.type = TYPE_MEM;
+                               p->to.reg = REG_R1;
                                p->to.offset = 0; // Panic.argp
 
                                p = appendp(ctxt, p);
@@ -544,11 +482,11 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        if(cursym->text->mark & LEAF) {
                                if(!autosize) {
                                        p->as = AB;
-                                       p->from = zprg5.from;
+                                       p->from = zprog.from;
                                        if(p->to.sym) { // retjmp
-                                               p->to.type = D_BRANCH;
+                                               p->to.type = TYPE_BRANCH;
                                        } else {
-                                               p->to.type = D_OREG;
+                                               p->to.type = TYPE_MEM;
                                                p->to.offset = 0;
                                                p->to.reg = REGLINK;
                                        }
@@ -558,10 +496,10 @@ addstacksplit(Link *ctxt, LSym *cursym)
 
                        p->as = AMOVW;
                        p->scond |= C_PBIT;
-                       p->from.type = D_OREG;
+                       p->from.type = TYPE_MEM;
                        p->from.offset = autosize;
                        p->from.reg = REGSP;
-                       p->to.type = D_REG;
+                       p->to.type = TYPE_REG;
                        p->to.reg = REGPC;
                        // If there are instructions following
                        // this ARET, they come from a branch
@@ -571,7 +509,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
                                p->to.reg = REGLINK;
                                q2 = appendp(ctxt, p);
                                q2->as = AB;
-                               q2->to.type = D_BRANCH;
+                               q2->to.type = TYPE_BRANCH;
                                q2->to.sym = p->to.sym;
                                p->to.sym = nil;
                                p = q2;
@@ -579,12 +517,12 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        break;
 
                case AADD:
-                       if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
+                       if(p->from.type == TYPE_CONST && p->from.reg == 0 && p->to.type == TYPE_REG && p->to.reg == REGSP)
                                p->spadj = -p->from.offset;
                        break;
 
                case ASUB:
-                       if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
+                       if(p->from.type == TYPE_CONST && p->from.reg == 0 && p->to.type == TYPE_REG && p->to.reg == REGSP)
                                p->spadj = p->from.offset;
                        break;
 
@@ -594,9 +532,9 @@ addstacksplit(Link *ctxt, LSym *cursym)
                case AMODU:
                        if(ctxt->debugdivmod)
                                break;
-                       if(p->from.type != D_REG)
+                       if(p->from.type != TYPE_REG)
                                break;
-                       if(p->to.type != D_REG)
+                       if(p->to.type != TYPE_REG)
                                break;
                        q1 = p;
 
@@ -604,9 +542,9 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        p = appendp(ctxt, p);
                        p->as = AMOVW;
                        p->lineno = q1->lineno;
-                       p->from.type = D_REG;
+                       p->from.type = TYPE_REG;
                        p->from.reg = q1->from.reg;
-                       p->to.type = D_OREG;
+                       p->to.type = TYPE_MEM;
                        p->to.reg = REGSP;
                        p->to.offset = 4;
 
@@ -614,11 +552,11 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        p = appendp(ctxt, p);
                        p->as = AMOVW;
                        p->lineno = q1->lineno;
-                       p->from.type = D_REG;
+                       p->from.type = TYPE_REG;
                        p->from.reg = q1->reg;
-                       if(q1->reg == NREG)
+                       if(q1->reg == 0)
                                p->from.reg = q1->to.reg;
-                       p->to.type = D_REG;
+                       p->to.type = TYPE_REG;
                        p->to.reg = REGTMP;
                        p->to.offset = 0;
 
@@ -626,7 +564,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        p = appendp(ctxt, p);
                        p->as = ABL;
                        p->lineno = q1->lineno;
-                       p->to.type = D_BRANCH;
+                       p->to.type = TYPE_BRANCH;
                        switch(o) {
                        case ADIV:
                                p->to.sym = ctxt->sym_div;
@@ -646,21 +584,21 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        p = appendp(ctxt, p);
                        p->as = AMOVW;
                        p->lineno = q1->lineno;
-                       p->from.type = D_REG;
+                       p->from.type = TYPE_REG;
                        p->from.reg = REGTMP;
                        p->from.offset = 0;
-                       p->to.type = D_REG;
+                       p->to.type = TYPE_REG;
                        p->to.reg = q1->to.reg;
 
                        /* ADD $8,SP */
                        p = appendp(ctxt, p);
                        p->as = AADD;
                        p->lineno = q1->lineno;
-                       p->from.type = D_CONST;
-                       p->from.reg = NREG;
+                       p->from.type = TYPE_CONST;
+                       p->from.reg = 0;
                        p->from.offset = 8;
-                       p->reg = NREG;
-                       p->to.type = D_REG;
+                       p->reg = 0;
+                       p->to.type = TYPE_REG;
                        p->to.reg = REGSP;
                        p->spadj = -8;
 
@@ -668,20 +606,20 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */
                        /* TODO: Remove SP adjustments; see issue 6699. */
                        q1->as = AMOVW;
-                       q1->from.type = D_OREG;
+                       q1->from.type = TYPE_MEM;
                        q1->from.reg = REGSP;
                        q1->from.offset = 0;
-                       q1->reg = NREG;
-                       q1->to.type = D_REG;
+                       q1->reg = 0;
+                       q1->to.type = TYPE_REG;
                        q1->to.reg = REGTMP;
 
                        /* SUB $8,SP */
                        q1 = appendp(ctxt, q1);
                        q1->as = AMOVW;
-                       q1->from.type = D_REG;
+                       q1->from.type = TYPE_REG;
                        q1->from.reg = REGTMP;
-                       q1->reg = NREG;
-                       q1->to.type = D_OREG;
+                       q1->reg = 0;
+                       q1->to.type = TYPE_MEM;
                        q1->to.reg = REGSP;
                        q1->to.offset = -8;
                        q1->scond |= C_WBIT;
@@ -689,17 +627,23 @@ addstacksplit(Link *ctxt, LSym *cursym)
 
                        break;
                case AMOVW:
-                       if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
+                       if((p->scond & C_WBIT) && p->to.type == TYPE_MEM && p->to.reg == REGSP)
                                p->spadj = -p->to.offset;
-                       if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
+                       if((p->scond & C_PBIT) && p->from.type == TYPE_MEM && p->from.reg == REGSP && p->to.reg != REGPC)
                                p->spadj = -p->from.offset;
-                       if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
+                       if(p->from.type == TYPE_ADDR && p->from.reg == REGSP && p->to.type == TYPE_REG && p->to.reg == REGSP)
                                p->spadj = -p->from.offset;
                        break;
                }
        }
 }
 
+static int
+isfloatreg(Addr *a)
+{
+       return a->type == TYPE_REG && REG_F0 <= a->reg && a->reg <= REG_F15;
+}
+
 static void
 softfloat(Link *ctxt, LSym *cursym)
 {
@@ -719,7 +663,7 @@ softfloat(Link *ctxt, LSym *cursym)
        for(p = cursym->text; p != nil; p = p->link) {
                switch(p->as) {
                case AMOVW:
-                       if(p->to.type == D_FREG || p->from.type == D_FREG)
+                       if(isfloatreg(&p->to) || isfloatreg(&p->from))
                                goto soft;
                        goto notsoft;
 
@@ -754,14 +698,14 @@ softfloat(Link *ctxt, LSym *cursym)
 
        soft:
                if (!wasfloat || (p->mark&LABEL)) {
-                       next = ctxt->arch->prg();
+                       next = emallocz(sizeof(Prog));
                        *next = *p;
 
                        // BL _sfloat(SB)
-                       *p = zprg5;
+                       *p = zprog;
                        p->link = next;
                        p->as = ABL;
-                               p->to.type = D_BRANCH;
+                               p->to.type = TYPE_BRANCH;
                        p->to.sym = symsfloat;
                        p->lineno = next->lineno;
 
@@ -781,21 +725,21 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
        // MOVW                 g_stackguard(g), R1
        p = appendp(ctxt, p);
        p->as = AMOVW;
-       p->from.type = D_OREG;
+       p->from.type = TYPE_MEM;
        p->from.reg = REGG;
        p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
        if(ctxt->cursym->cfunc)
                p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
-       p->to.type = D_REG;
-       p->to.reg = 1;
+       p->to.type = TYPE_REG;
+       p->to.reg = REG_R1;
        
        if(framesize <= StackSmall) {
                // small stack: SP < stackguard
                //      CMP     stackguard, SP
                p = appendp(ctxt, p);
                p->as = ACMP;
-               p->from.type = D_REG;
-               p->from.reg = 1;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_R1;
                p->reg = REGSP;
        } else if(framesize <= StackBig) {
                // large stack: SP-framesize < stackguard-StackSmall
@@ -803,17 +747,17 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
                //      CMP stackguard, R2
                p = appendp(ctxt, p);
                p->as = AMOVW;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_ADDR;
                p->from.reg = REGSP;
                p->from.offset = -framesize;
-               p->to.type = D_REG;
-               p->to.reg = 2;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_R2;
                
                p = appendp(ctxt, p);
                p->as = ACMP;
-               p->from.type = D_REG;
-               p->from.reg = 1;
-               p->reg = 2;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_R1;
+               p->reg = REG_R2;
        } else {
                // Such a large stack we need to protect against wraparound
                // if SP is close to zero.
@@ -827,40 +771,40 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
                //      CMP.NE R3, R2
                p = appendp(ctxt, p);
                p->as = ACMP;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = (uint32)StackPreempt;
-               p->reg = 1;
+               p->reg = REG_R1;
 
                p = appendp(ctxt, p);
                p->as = AMOVW;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_ADDR;
                p->from.reg = REGSP;
                p->from.offset = StackGuard;
-               p->to.type = D_REG;
-               p->to.reg = 2;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_R2;
                p->scond = C_SCOND_NE;
                
                p = appendp(ctxt, p);
                p->as = ASUB;
-               p->from.type = D_REG;
-               p->from.reg = 1;
-               p->to.type = D_REG;
-               p->to.reg = 2;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_R1;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_R2;
                p->scond = C_SCOND_NE;
                
                p = appendp(ctxt, p);
                p->as = AMOVW;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_ADDR;
                p->from.offset = framesize + (StackGuard - StackSmall);
-               p->to.type = D_REG;
-               p->to.reg = 3;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_R3;
                p->scond = C_SCOND_NE;
                
                p = appendp(ctxt, p);
                p->as = ACMP;
-               p->from.type = D_REG;
-               p->from.reg = 3;
-               p->reg = 2;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_R3;
+               p->reg = REG_R2;
                p->scond = C_SCOND_NE;
        }
        
@@ -868,16 +812,16 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
        p = appendp(ctxt, p);
        p->as = AMOVW;
        p->scond = C_SCOND_LS;
-       p->from.type = D_REG;
+       p->from.type = TYPE_REG;
        p->from.reg = REGLINK;
-       p->to.type = D_REG;
-       p->to.reg = 3;
+       p->to.type = TYPE_REG;
+       p->to.reg = REG_R3;
 
        // BL.LS                runtime.morestack(SB) // modifies LR, returns with LO still asserted
        p = appendp(ctxt, p);
        p->as = ABL;
        p->scond = C_SCOND_LS;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        if(ctxt->cursym->cfunc)
                p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
        else
@@ -886,7 +830,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
        // BLS  start
        p = appendp(ctxt, p);
        p->as = ABLS;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        p->pcond = ctxt->cursym->text->link;
        
        return p;
@@ -912,7 +856,7 @@ follow(Link *ctxt, LSym *s)
 
        ctxt->cursym = s;
 
-       firstp = ctxt->arch->prg();
+       firstp = emallocz(sizeof(Prog));
        lastp = firstp;
        xfol(ctxt, s->text, &lastp);
        lastp->link = nil;
@@ -980,7 +924,7 @@ loop:
                                continue;
                copy:
                        for(;;) {
-                               r = ctxt->arch->prg();
+                               r = emallocz(sizeof(Prog));
                                *r = *p;
                                if(!(r->mark&FOLL))
                                        print("can't happen 1\n");
@@ -1008,10 +952,10 @@ loop:
                        }
                }
                a = AB;
-               q = ctxt->arch->prg();
+               q = emallocz(sizeof(Prog));
                q->as = a;
                q->lineno = p->lineno;
-               q->to.type = D_BRANCH;
+               q->to.type = TYPE_BRANCH;
                q->to.offset = p->pc;
                q->pcond = p;
                p = q;
@@ -1051,44 +995,12 @@ LinkArch linkarm = {
        .thechar = '5',
        .endian = LittleEndian,
 
-       .addstacksplit = addstacksplit,
+       .preprocess = preprocess,
        .assemble = span5,
-       .datasize = datasize,
        .follow = follow,
-       .iscall = iscall,
-       .isdata = isdata,
-       .prg = prg,
        .progedit = progedit,
-       .settextflag = settextflag,
-       .symtype = symtype,
-       .textflag = textflag,
 
        .minlc = 4,
        .ptrsize = 4,
        .regsize = 4,
-
-       .D_ADDR = D_ADDR,
-       .D_AUTO = D_AUTO,
-       .D_BRANCH = D_BRANCH,
-       .D_CONST = D_CONST,
-       .D_EXTERN = D_EXTERN,
-       .D_FCONST = D_FCONST,
-       .D_NONE = D_NONE,
-       .D_PARAM = D_PARAM,
-       .D_SCONST = D_SCONST,
-       .D_STATIC = D_STATIC,
-       .D_OREG = D_OREG,
-
-       .ACALL = ABL,
-       .ADATA = ADATA,
-       .AEND = AEND,
-       .AFUNCDATA = AFUNCDATA,
-       .AGLOBL = AGLOBL,
-       .AJMP = AB,
-       .ANOP = ANOP,
-       .APCDATA = APCDATA,
-       .ARET = ARET,
-       .ATEXT = ATEXT,
-       .ATYPE = ATYPE,
-       .AUSEFIELD = AUSEFIELD,
 };
index 700800978caaea5cac964553cfd5c1b2047079ac..cddc723bf2d23b1437c717de3a890bf19d787783 100644 (file)
 #include "../cmd/6l/6.out.h"
 #include "../runtime/stack.h"
 
-static Prog zprg = {
-       .back = 2,
-       .as = AGOK,
-       .from = {
-               .type = D_NONE,
-               .index = D_NONE,
-       },
-       .to = {
-               .type = D_NONE,
-               .index = D_NONE,
-       },
-};
-
 static void
 nopout(Prog *p)
 {
        p->as = ANOP;
-       p->from.type = D_NONE;
-       p->to.type = D_NONE;
-}
-
-static int
-symtype(Addr *a)
-{
-       int t;
-
-       t = a->type;
-       if(t == D_ADDR)
-               t = a->index;
-       return t;
-}
-
-static int
-isdata(Prog *p)
-{
-       return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
-       return p->as == ACALL;
-}
-
-static int
-datasize(Prog *p)
-{
-       return p->from.scale;
-}
-
-static int
-textflag(Prog *p)
-{
-       return p->from.scale;
-}
-
-static void
-settextflag(Prog *p, int f)
-{
-       p->from.scale = f;
+       p->from.type = TYPE_NONE;
+       p->from.reg = 0;
+       p->from.name = 0;
+       p->to.type = TYPE_NONE;
+       p->to.reg = 0;
+       p->to.name = 0;
 }
 
 static void nacladdr(Link*, Prog*, Addr*);
@@ -162,17 +112,17 @@ progedit(Link *ctxt, Prog *p)
                // TODO(rsc): Remove the Hsolaris special case. It exists only to
                // guarantee we are producing byte-identical binaries as before this code.
                // But it should be unnecessary.
-               if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_R15 && ctxt->headtype != Hsolaris)
+               if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == TYPE_REG && p->from.reg == REG_TLS && p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_R15 && ctxt->headtype != Hsolaris)
                        nopout(p);
-               if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_R15) {
-                       p->from.type = D_INDIR+D_TLS;
+               if(p->from.type == TYPE_MEM && p->from.index == REG_TLS && REG_AX <= p->from.reg && p->from.reg <= REG_R15) {
+                       p->from.reg = REG_TLS;
                        p->from.scale = 0;
-                       p->from.index = D_NONE;
+                       p->from.index = REG_NONE;
                }
-               if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_R15) {
-                       p->to.type = D_INDIR+D_TLS;
+               if(p->to.type == TYPE_MEM && p->to.index == REG_TLS && REG_AX <= p->to.reg && p->to.reg <= REG_R15) {
+                       p->to.reg = REG_TLS;
                        p->to.scale = 0;
-                       p->to.index = D_NONE;
+                       p->to.index = REG_NONE;
                }
        } else {
                // As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
@@ -182,25 +132,27 @@ progedit(Link *ctxt, Prog *p)
                //      MOVQ TLS, BX
                //      MOVQ off(BX)(TLS*1), BX
                // This allows the C compilers to emit references to m and g using the direct off(TLS) form.
-               if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_R15) {
+               if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == TYPE_MEM && p->from.reg == REG_TLS && p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_R15) {
                        q = appendp(ctxt, p);
                        q->as = p->as;
                        q->from = p->from;
-                       q->from.type = D_INDIR + p->to.type;
-                       q->from.index = D_TLS;
+                       q->from.type = TYPE_MEM;
+                       q->from.reg = p->to.reg;
+                       q->from.index = REG_TLS;
                        q->from.scale = 2; // TODO: use 1
                        q->to = p->to;
-                       p->from.type = D_TLS;
-                       p->from.index = D_NONE;
+                       p->from.type = TYPE_REG;
+                       p->from.reg = REG_TLS;
+                       p->from.index = REG_NONE;
                        p->from.offset = 0;
                }
        }
 
        // TODO: Remove.
        if(ctxt->headtype == Hwindows || ctxt->headtype == Hplan9) {
-               if(p->from.scale == 1 && p->from.index == D_TLS)
+               if(p->from.scale == 1 && p->from.index == REG_TLS)
                        p->from.scale = 2;
-               if(p->to.scale == 1 && p->to.index == D_TLS)
+               if(p->to.scale == 1 && p->to.index == REG_TLS)
                        p->to.scale = 2;
        }
 
@@ -216,7 +168,7 @@ progedit(Link *ctxt, Prog *p)
        
        switch(p->as) {
        case AMODE:
-               if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE) {
+               if(p->from.type == TYPE_CONST || (p->from.type == TYPE_MEM && p->from.reg == REG_NONE)) {
                        switch((int)p->from.offset) {
                        case 16:
                        case 32:
@@ -229,13 +181,13 @@ progedit(Link *ctxt, Prog *p)
                break;
        }
        
-       // Rewrite CALL/JMP/RET to symbol as D_BRANCH.
+       // Rewrite CALL/JMP/RET to symbol as TYPE_BRANCH.
        switch(p->as) {
        case ACALL:
        case AJMP:
        case ARET:
-               if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
-                       p->to.type = D_BRANCH;
+               if(p->to.type == TYPE_MEM && (p->to.name == NAME_EXTERN || p->to.name == NAME_STATIC) && p->to.sym != nil)
+                       p->to.type = TYPE_BRANCH;
                break;
        }
 
@@ -243,13 +195,11 @@ progedit(Link *ctxt, Prog *p)
        switch(p->as) {
        case AMOVSS:
                // Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
-               if(p->from.type == D_FCONST)
+               if(p->from.type == TYPE_FCONST)
                if(p->from.u.dval == 0)
-               if(p->to.type >= D_X0)
-               if(p->to.type <= D_X15) {
+               if(p->to.type == TYPE_REG && REG_X0 <= p->to.reg && p->to.reg <= REG_X15) {
                        p->as = AXORPS;
-                       p->from.type = p->to.type;
-                       p->from.index = p->to.index;
+                       p->from = p->to;
                        break;
                }
                // fallthrough
@@ -269,7 +219,7 @@ progedit(Link *ctxt, Prog *p)
        case ADIVSS:
        case ACOMISS:
        case AUCOMISS:
-               if(p->from.type == D_FCONST) {
+               if(p->from.type == TYPE_FCONST) {
                        uint32 i32;
                        float32 f32;
                        f32 = p->from.u.dval;
@@ -281,7 +231,8 @@ progedit(Link *ctxt, Prog *p)
                                adduint32(ctxt, s, i32);
                                s->reachable = 0;
                        }
-                       p->from.type = D_EXTERN;
+                       p->from.type = TYPE_MEM;
+                       p->from.name = NAME_EXTERN;
                        p->from.sym = s;
                        p->from.offset = 0;
                }
@@ -289,13 +240,11 @@ progedit(Link *ctxt, Prog *p)
 
        case AMOVSD:
                // Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
-               if(p->from.type == D_FCONST)
+               if(p->from.type == TYPE_FCONST)
                if(p->from.u.dval == 0)
-               if(p->to.type >= D_X0)
-               if(p->to.type <= D_X15) {
+               if(p->to.type == TYPE_REG && REG_X0 <= p->to.reg && p->to.reg <= REG_X15) {
                        p->as = AXORPS;
-                       p->from.type = p->to.type;
-                       p->from.index = p->to.index;
+                       p->from = p->to;
                        break;
                }
                // fallthrough
@@ -315,7 +264,7 @@ progedit(Link *ctxt, Prog *p)
        case ADIVSD:
        case ACOMISD:
        case AUCOMISD:
-               if(p->from.type == D_FCONST) {
+               if(p->from.type == TYPE_FCONST) {
                        uint64 i64;
                        memmove(&i64, &p->from.u.dval, 8);
                        sprint(literal, "$f64.%016llux", i64);
@@ -325,7 +274,8 @@ progedit(Link *ctxt, Prog *p)
                                adduint64(ctxt, s, i64);
                                s->reachable = 0;
                        }
-                       p->from.type = D_EXTERN;
+                       p->from.type = TYPE_MEM;
+                       p->from.name = NAME_EXTERN;
                        p->from.sym = s;
                        p->from.offset = 0;
                }
@@ -339,28 +289,26 @@ nacladdr(Link *ctxt, Prog *p, Addr *a)
        if(p->as == ALEAL || p->as == ALEAQ)
                return;
        
-       if(a->type == D_BP || a->type == D_INDIR+D_BP) {
+       if(a->reg == REG_BP) {
                ctxt->diag("invalid address: %P", p);
                return;
        }
-       if(a->type == D_INDIR+D_TLS)
-               a->type = D_INDIR+D_BP;
-       else if(a->type == D_TLS)
-               a->type = D_BP;
-       if(D_INDIR <= a->type && a->type <= D_INDIR+D_INDIR) {
-               switch(a->type) {
-               case D_INDIR+D_BP:
-               case D_INDIR+D_SP:
-               case D_INDIR+D_R15:
+       if(a->reg == REG_TLS)
+               a->reg = REG_BP;
+       if(a->type == TYPE_MEM && a->name == NAME_NONE) {
+               switch(a->reg) {
+               case REG_BP:
+               case REG_SP:
+               case REG_R15:
                        // all ok
                        break;
                default:
-                       if(a->index != D_NONE)
+                       if(a->index != REG_NONE)
                                ctxt->diag("invalid address %P", p);
-                       a->index = a->type - D_INDIR;
-                       if(a->index != D_NONE)
+                       a->index = a->reg;
+                       if(a->index != REG_NONE)
                                a->scale = 1;
-                       a->type = D_INDIR+D_R15;
+                       a->reg = REG_R15;
                        break;
                }
        }
@@ -371,25 +319,12 @@ static Prog*      stacksplit(Link*, Prog*, int32, int32, int, Prog**);
 static void    indir_cx(Link*, Addr*);
 
 static void
-parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg)
-{
-       *textstksiz = arg & 0xffffffffLL;
-       if(*textstksiz & 0x80000000LL)
-               *textstksiz = -(-*textstksiz & 0xffffffffLL);
-
-       *textarg = (arg >> 32) & 0xffffffffLL;
-       if(*textarg & 0x80000000LL)
-               *textarg = 0;
-       *textarg = (*textarg+7) & ~7LL;
-}
-
-static void
-addstacksplit(Link *ctxt, LSym *cursym)
+preprocess(Link *ctxt, LSym *cursym)
 {
        Prog *p, *q, *p1, *p2;
        int32 autoffset, deltasp;
-       int a, pcsize;
-       vlong textstksiz, textarg;
+       int a, pcsize, bpsize;
+       vlong textarg;
 
        if(ctxt->tlsg == nil)
                ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
@@ -407,39 +342,50 @@ addstacksplit(Link *ctxt, LSym *cursym)
                return;                         
 
        p = cursym->text;
-       parsetextconst(p->to.offset, &textstksiz, &textarg);
-       autoffset = textstksiz;
+       autoffset = p->to.offset;
        if(autoffset < 0)
                autoffset = 0;
        
-       cursym->args = p->to.offset>>32;
-       cursym->locals = textstksiz;
+       if(framepointer_enabled && autoffset > 0) {
+               // Make room for to save a base pointer.  If autoffset == 0,
+               // this might do something special like a tail jump to
+               // another function, so in that case we omit this.
+               bpsize = ctxt->arch->ptrsize;
+               autoffset += bpsize;
+               p->to.offset += bpsize;
+       } else {
+               bpsize = 0;
+       }
+
+       textarg = p->to.u.argsize;
+       cursym->args = textarg;
+       cursym->locals = p->to.offset;
 
-       if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
+       if(autoffset < StackSmall && !(p->from3.offset & NOSPLIT)) {
                for(q = p; q != nil; q = q->link) {
                        if(q->as == ACALL)
                                goto noleaf;
                        if((q->as == ADUFFCOPY || q->as == ADUFFZERO) && autoffset >= StackSmall - 8)
                                goto noleaf;
                }
-               p->from.scale |= NOSPLIT;
+               p->from3.offset |= NOSPLIT;
        noleaf:;
        }
 
        q = nil;
-       if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
+       if(!(p->from3.offset & NOSPLIT) || (p->from3.offset & WRAPPER)) {
                p = appendp(ctxt, p);
                p = load_g_cx(ctxt, p); // load g into CX
        }
-       if(!(cursym->text->from.scale & NOSPLIT))
-               p = stacksplit(ctxt, p, autoffset, textarg, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
+       if(!(cursym->text->from3.offset & NOSPLIT))
+               p = stacksplit(ctxt, p, autoffset, textarg, !(cursym->text->from3.offset&NEEDCTXT), &q); // emit split check
 
        if(autoffset) {
                if(autoffset%ctxt->arch->regsize != 0)
                        ctxt->diag("unaligned stack size %d", autoffset);
                p = appendp(ctxt, p);
                p->as = AADJSP;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = autoffset;
                p->spadj = autoffset;
        } else {
@@ -456,8 +402,30 @@ addstacksplit(Link *ctxt, LSym *cursym)
        if(q != nil)
                q->pcond = p;
        deltasp = autoffset;
+
+       if(bpsize > 0) {
+               // Save caller's BP
+               p = appendp(ctxt, p);
+               p->as = AMOVQ;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_BP;
+               p->to.type = TYPE_MEM;
+               p->to.reg = REG_SP;
+               p->to.scale = 1;
+               p->to.offset = autoffset - bpsize;
+
+               // Move current frame to BP
+               p = appendp(ctxt, p);
+               p->as = ALEAQ;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_SP;
+               p->from.scale = 1;
+               p->from.offset = autoffset - bpsize;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_BP;
+       }
        
-       if(cursym->text->from.scale & WRAPPER) {
+       if(cursym->text->from3.offset & WRAPPER) {
                // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
                //
                //      MOVQ g_panic(CX), BX
@@ -475,63 +443,76 @@ addstacksplit(Link *ctxt, LSym *cursym)
 
                p = appendp(ctxt, p);
                p->as = AMOVQ;
-               p->from.type = D_INDIR+D_CX;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_CX;
                p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
-               p->to.type = D_BX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_BX;
                if(ctxt->headtype == Hnacl) {
                        p->as = AMOVL;
-                       p->from.type = D_INDIR+D_R15;
+                       p->from.type = TYPE_MEM;
+                       p->from.reg = REG_R15;
                        p->from.scale = 1;
-                       p->from.index = D_CX;
+                       p->from.index = REG_CX;
                }
 
                p = appendp(ctxt, p);
                p->as = ATESTQ;
-               p->from.type = D_BX;
-               p->to.type = D_BX;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_BX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_BX;
                if(ctxt->headtype == Hnacl)
                        p->as = ATESTL;
 
                p = appendp(ctxt, p);
                p->as = AJEQ;
-               p->to.type = D_BRANCH;
+               p->to.type = TYPE_BRANCH;
                p1 = p;
 
                p = appendp(ctxt, p);
                p->as = ALEAQ;
-               p->from.type = D_INDIR+D_SP;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_SP;
                p->from.offset = autoffset+8;
-               p->to.type = D_DI;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_DI;
                if(ctxt->headtype == Hnacl)
                        p->as = ALEAL;
 
                p = appendp(ctxt, p);
                p->as = ACMPQ;
-               p->from.type = D_INDIR+D_BX;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_BX;
                p->from.offset = 0; // Panic.argp
-               p->to.type = D_DI;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_DI;
                if(ctxt->headtype == Hnacl) {
                        p->as = ACMPL;
-                       p->from.type = D_INDIR+D_R15;
+                       p->from.type = TYPE_MEM;
+                       p->from.reg = REG_R15;
                        p->from.scale = 1;
-                       p->from.index = D_BX;
+                       p->from.index = REG_BX;
                }
 
                p = appendp(ctxt, p);
                p->as = AJNE;
-               p->to.type = D_BRANCH;
+               p->to.type = TYPE_BRANCH;
                p2 = p;
 
                p = appendp(ctxt, p);
                p->as = AMOVQ;
-               p->from.type = D_SP;
-               p->to.type = D_INDIR+D_BX;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_SP;
+               p->to.type = TYPE_MEM;
+               p->to.reg = REG_BX;
                p->to.offset = 0; // Panic.argp
                if(ctxt->headtype == Hnacl) {
                        p->as = AMOVL;
-                       p->to.type = D_INDIR+D_R15;
+                       p->to.type = TYPE_MEM;
+                       p->to.reg = REG_R15;
                        p->to.scale = 1;
-                       p->to.index = D_BX;
+                       p->to.index = REG_BX;
                }
 
                p = appendp(ctxt, p);
@@ -540,26 +521,30 @@ addstacksplit(Link *ctxt, LSym *cursym)
                p2->pcond = p;
        }
 
-       if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
+       if(ctxt->debugzerostack && autoffset && !(cursym->text->from3.offset&NOSPLIT)) {
                // 6l -Z means zero the stack frame on entry.
                // This slows down function calls but can help avoid
                // false positives in garbage collection.
                p = appendp(ctxt, p);
                p->as = AMOVQ;
-               p->from.type = D_SP;
-               p->to.type = D_DI;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_SP;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_DI;
                
                p = appendp(ctxt, p);
                p->as = AMOVQ;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = autoffset/8;
-               p->to.type = D_CX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_CX;
                
                p = appendp(ctxt, p);
                p->as = AMOVQ;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = 0;
-               p->to.type = D_AX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_AX;
                
                p = appendp(ctxt, p);
                p->as = AREP;
@@ -570,15 +555,15 @@ addstacksplit(Link *ctxt, LSym *cursym)
        
        for(; p != nil; p = p->link) {
                pcsize = p->mode/8;
-               a = p->from.type;
-               if(a == D_AUTO)
-                       p->from.offset += deltasp;
-               if(a == D_PARAM)
+               a = p->from.name;
+               if(a == NAME_AUTO)
+                       p->from.offset += deltasp - bpsize;
+               if(a == NAME_PARAM)
                        p->from.offset += deltasp + pcsize;
-               a = p->to.type;
-               if(a == D_AUTO)
-                       p->to.offset += deltasp;
-               if(a == D_PARAM)
+               a = p->to.name;
+               if(a == NAME_AUTO)
+                       p->to.offset += deltasp - bpsize;
+               if(a == NAME_PARAM)
                        p->to.offset += deltasp + pcsize;
 
                switch(p->as) {
@@ -622,8 +607,20 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        ctxt->diag("unbalanced PUSH/POP");
 
                if(autoffset) {
+                       if(bpsize > 0) {
+                               // Restore caller's BP
+                               p->as = AMOVQ;
+                               p->from.type = TYPE_MEM;
+                               p->from.reg = REG_SP;
+                               p->from.scale = 1;
+                               p->from.offset = autoffset - bpsize;
+                               p->to.type = TYPE_REG;
+                               p->to.reg = REG_BP;
+                               p = appendp(ctxt, p);
+                       }
+
                        p->as = AADJSP;
-                       p->from.type = D_CONST;
+                       p->from.type = TYPE_CONST;
                        p->from.offset = -autoffset;
                        p->spadj = -autoffset;
                        p = appendp(ctxt, p);
@@ -643,13 +640,15 @@ static void
 indir_cx(Link *ctxt, Addr *a)
 {
        if(ctxt->headtype == Hnacl) {
-               a->type = D_INDIR + D_R15;
-               a->index = D_CX;
+               a->type = TYPE_MEM;
+               a->reg = REG_R15;
+               a->index = REG_CX;
                a->scale = 1;
                return;
        }
 
-       a->type = D_INDIR+D_CX;
+       a->type = TYPE_MEM;
+       a->reg = REG_CX;
 }
 
 // Append code to p to load g into cx.
@@ -665,16 +664,18 @@ load_g_cx(Link *ctxt, Prog *p)
        p->as = AMOVQ;
        if(ctxt->arch->ptrsize == 4)
                p->as = AMOVL;
-       p->from.type = D_INDIR+D_TLS;
+       p->from.type = TYPE_MEM;
+       p->from.reg = REG_TLS;
        p->from.offset = 0;
-       p->to.type = D_CX;
+       p->to.type = TYPE_REG;
+       p->to.reg = REG_CX;
        
        next = p->link;
        progedit(ctxt, p);
        while(p->link != next)
                p = p->link;
        
-       if(p->from.index == D_TLS)
+       if(p->from.index == REG_TLS)
                p->from.scale = 2;
 
        return p;
@@ -711,7 +712,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog
                //      CMPQ SP, stackguard
                p = appendp(ctxt, p);
                p->as = cmp;
-               p->from.type = D_SP;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_SP;
                indir_cx(ctxt, &p->to);
                p->to.offset = 2*ctxt->arch->ptrsize;   // G.stackguard0
                if(ctxt->cursym->cfunc)
@@ -722,13 +724,16 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog
                //      CMPQ AX, stackguard
                p = appendp(ctxt, p);
                p->as = lea;
-               p->from.type = D_INDIR+D_SP;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_SP;
                p->from.offset = -(framesize-StackSmall);
-               p->to.type = D_AX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_AX;
 
                p = appendp(ctxt, p);
                p->as = cmp;
-               p->from.type = D_AX;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_AX;
                indir_cx(ctxt, &p->to);
                p->to.offset = 2*ctxt->arch->ptrsize;   // G.stackguard0
                if(ctxt->cursym->cfunc)
@@ -755,46 +760,53 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog
                p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
                if(ctxt->cursym->cfunc)
                        p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
-               p->to.type = D_SI;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_SI;
 
                p = appendp(ctxt, p);
                p->as = cmp;
-               p->from.type = D_SI;
-               p->to.type = D_CONST;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_SI;
+               p->to.type = TYPE_CONST;
                p->to.offset = StackPreempt;
 
                p = appendp(ctxt, p);
                p->as = AJEQ;
-               p->to.type = D_BRANCH;
+               p->to.type = TYPE_BRANCH;
                q1 = p;
 
                p = appendp(ctxt, p);
                p->as = lea;
-               p->from.type = D_INDIR+D_SP;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_SP;
                p->from.offset = StackGuard;
-               p->to.type = D_AX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_AX;
                
                p = appendp(ctxt, p);
                p->as = sub;
-               p->from.type = D_SI;
-               p->to.type = D_AX;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_SI;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_AX;
                
                p = appendp(ctxt, p);
                p->as = cmp;
-               p->from.type = D_AX;
-               p->to.type = D_CONST;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_AX;
+               p->to.type = TYPE_CONST;
                p->to.offset = framesize+(StackGuard-StackSmall);
        }                                       
 
        // common
        p = appendp(ctxt, p);
        p->as = AJHI;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        q = p;
 
        p = appendp(ctxt, p);
        p->as = ACALL;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        if(ctxt->cursym->cfunc)
                p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
        else
@@ -802,7 +814,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog
        
        p = appendp(ctxt, p);
        p->as = AJMP;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        p->pcond = ctxt->cursym->text->link;
        
        if(q != nil)
@@ -823,7 +835,7 @@ follow(Link *ctxt, LSym *s)
 
        ctxt->cursym = s;
 
-       firstp = ctxt->arch->prg();
+       firstp = emallocz(sizeof(Prog));
        lastp = firstp;
        xfol(ctxt, s->text, &lastp);
        lastp->link = nil;
@@ -957,10 +969,10 @@ loop:
                                goto loop;
                        }
                } /* */
-               q = ctxt->arch->prg();
+               q = emallocz(sizeof(Prog));
                q->as = AJMP;
                q->lineno = p->lineno;
-               q->to.type = D_BRANCH;
+               q->to.type = TYPE_BRANCH;
                q->to.offset = p->pc;
                q->pcond = p;
                p = q;
@@ -985,7 +997,7 @@ loop:
                        p->pcond = q;
                if((q = brchain(ctxt, p->link)) != nil)
                        p->link = q;
-               if(p->from.type == D_CONST) {
+               if(p->from.type == TYPE_CONST) {
                        if(p->from.offset == 1) {
                                /*
                                 * expect conditional jump to be taken.
@@ -1015,60 +1027,19 @@ loop:
        goto loop;
 }
 
-static Prog*
-prg(void)
-{
-       Prog *p;
-
-       p = emallocz(sizeof(*p));
-       *p = zprg;
-       return p;
-}
-
 LinkArch linkamd64 = {
        .name = "amd64",
        .thechar = '6',
        .endian = LittleEndian,
 
-       .addstacksplit = addstacksplit,
+       .preprocess = preprocess,
        .assemble = span6,
-       .datasize = datasize,
        .follow = follow,
-       .iscall = iscall,
-       .isdata = isdata,
-       .prg = prg,
        .progedit = progedit,
-       .settextflag = settextflag,
-       .symtype = symtype,
-       .textflag = textflag,
 
        .minlc = 1,
        .ptrsize = 8,
        .regsize = 8,
-
-       .D_ADDR = D_ADDR,
-       .D_AUTO = D_AUTO,
-       .D_BRANCH = D_BRANCH,
-       .D_CONST = D_CONST,
-       .D_EXTERN = D_EXTERN,
-       .D_FCONST = D_FCONST,
-       .D_NONE = D_NONE,
-       .D_PARAM = D_PARAM,
-       .D_SCONST = D_SCONST,
-       .D_STATIC = D_STATIC,
-
-       .ACALL = ACALL,
-       .ADATA = ADATA,
-       .AEND = AEND,
-       .AFUNCDATA = AFUNCDATA,
-       .AGLOBL = AGLOBL,
-       .AJMP = AJMP,
-       .ANOP = ANOP,
-       .APCDATA = APCDATA,
-       .ARET = ARET,
-       .ATEXT = ATEXT,
-       .ATYPE = ATYPE,
-       .AUSEFIELD = AUSEFIELD,
 };
 
 LinkArch linkamd64p32 = {
@@ -1076,43 +1047,12 @@ LinkArch linkamd64p32 = {
        .thechar = '6',
        .endian = LittleEndian,
 
-       .addstacksplit = addstacksplit,
+       .preprocess = preprocess,
        .assemble = span6,
-       .datasize = datasize,
        .follow = follow,
-       .iscall = iscall,
-       .isdata = isdata,
-       .prg = prg,
        .progedit = progedit,
-       .settextflag = settextflag,
-       .symtype = symtype,
-       .textflag = textflag,
 
        .minlc = 1,
        .ptrsize = 4,
        .regsize = 8,
-
-       .D_ADDR = D_ADDR,
-       .D_AUTO = D_AUTO,
-       .D_BRANCH = D_BRANCH,
-       .D_CONST = D_CONST,
-       .D_EXTERN = D_EXTERN,
-       .D_FCONST = D_FCONST,
-       .D_NONE = D_NONE,
-       .D_PARAM = D_PARAM,
-       .D_SCONST = D_SCONST,
-       .D_STATIC = D_STATIC,
-
-       .ACALL = ACALL,
-       .ADATA = ADATA,
-       .AEND = AEND,
-       .AFUNCDATA = AFUNCDATA,
-       .AGLOBL = AGLOBL,
-       .AJMP = AJMP,
-       .ANOP = ANOP,
-       .APCDATA = APCDATA,
-       .ARET = ARET,
-       .ATEXT = ATEXT,
-       .ATYPE = ATYPE,
-       .AUSEFIELD = AUSEFIELD,
 };
index 4e28709b8182dce2cf278f19f887b9a6b588c67e..eb8e318762728b6c127b54e1aea5d3eca0a9caf7 100644 (file)
 #include "../cmd/8l/8.out.h"
 #include "../runtime/stack.h"
 
-static Prog zprg = {
-       .back = 2,
-       .as = AGOK,
-       .from = {
-               .type = D_NONE,
-               .index = D_NONE,
-               .scale = 1,
-       },
-       .to = {
-               .type = D_NONE,
-               .index = D_NONE,
-               .scale = 1,
-       },
-};
-
-static int
-symtype(Addr *a)
-{
-       int t;
-
-       t = a->type;
-       if(t == D_ADDR)
-               t = a->index;
-       return t;
-}
-
-static int
-isdata(Prog *p)
-{
-       return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
-       return p->as == ACALL;
-}
-
-static int
-datasize(Prog *p)
-{
-       return p->from.scale;
-}
-
-static int
-textflag(Prog *p)
-{
-       return p->from.scale;
-}
-
-static void
-settextflag(Prog *p, int f)
-{
-       p->from.scale = f;
-}
-
 static int
 canuselocaltls(Link *ctxt)
 {
@@ -120,20 +64,22 @@ progedit(Link *ctxt, Prog *p)
                // become
                //      NOP
                //      ... off(TLS) ...
-               if(p->as == AMOVL && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
+               if(p->as == AMOVL && p->from.type == TYPE_REG && p->from.reg == REG_TLS && p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_DI) {
                        p->as = ANOP;
-                       p->from.type = D_NONE;
-                       p->to.type = D_NONE;
+                       p->from.type = TYPE_NONE;
+                       p->to.type = TYPE_NONE;
                }
-               if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_DI) {
-                       p->from.type = D_INDIR+D_TLS;
+               if(p->from.type == TYPE_MEM && p->from.index == REG_TLS && REG_AX <= p->from.reg && p->from.reg <= REG_DI) {
+                       p->from.type = TYPE_MEM;
+                       p->from.reg = REG_TLS;
                        p->from.scale = 0;
-                       p->from.index = D_NONE;
+                       p->from.index = REG_NONE;
                }
-               if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_DI) {
-                       p->to.type = D_INDIR+D_TLS;
+               if(p->to.type == TYPE_MEM && p->to.index == REG_TLS && REG_AX <= p->to.reg && p->to.reg <= REG_DI) {
+                       p->to.type = TYPE_MEM;
+                       p->to.reg = REG_TLS;
                        p->to.scale = 0;
-                       p->to.index = D_NONE;
+                       p->to.index = REG_NONE;
                }
        } else {
                // As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
@@ -143,35 +89,36 @@ progedit(Link *ctxt, Prog *p)
                //      MOVL TLS, BX
                //      MOVL off(BX)(TLS*1), BX
                // This allows the C compilers to emit references to m and g using the direct off(TLS) form.
-               if(p->as == AMOVL && p->from.type == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
+               if(p->as == AMOVL && p->from.type == TYPE_MEM && p->from.reg == REG_TLS && p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_DI) {
                        q = appendp(ctxt, p);
                        q->as = p->as;
-                       q->from = p->from;
-                       q->from.type = D_INDIR + p->to.type;
-                       q->from.index = D_TLS;
+                       q->from.type = TYPE_MEM;
+                       q->from.reg = p->to.reg;
+                       q->from.index = REG_TLS;
                        q->from.scale = 2; // TODO: use 1
                        q->to = p->to;
-                       p->from.type = D_TLS;
-                       p->from.index = D_NONE;
+                       p->from.type = TYPE_REG;
+                       p->from.reg = REG_TLS;
+                       p->from.index = REG_NONE;
                        p->from.offset = 0;
                }
        }
 
        // TODO: Remove.
        if(ctxt->headtype == Hplan9) {
-               if(p->from.scale == 1 && p->from.index == D_TLS)
+               if(p->from.scale == 1 && p->from.index == REG_TLS)
                        p->from.scale = 2;
-               if(p->to.scale == 1 && p->to.index == D_TLS)
+               if(p->to.scale == 1 && p->to.index == REG_TLS)
                        p->to.scale = 2;
        }
 
-       // Rewrite CALL/JMP/RET to symbol as D_BRANCH.
+       // Rewrite CALL/JMP/RET to symbol as TYPE_BRANCH.
        switch(p->as) {
        case ACALL:
        case AJMP:
        case ARET:
-               if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
-                       p->to.type = D_BRANCH;
+               if(p->to.type == TYPE_MEM && (p->to.name == NAME_EXTERN || p->to.name == NAME_STATIC) && p->to.sym != nil)
+                       p->to.type = TYPE_BRANCH;
                break;
        }
 
@@ -179,13 +126,11 @@ progedit(Link *ctxt, Prog *p)
        switch(p->as) {
        case AMOVSS:
                // Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
-               if(p->from.type == D_FCONST)
+               if(p->from.type == TYPE_FCONST)
                if(p->from.u.dval == 0)
-               if(p->to.type >= D_X0)
-               if(p->to.type <= D_X7) {
+               if(p->to.type == TYPE_REG && REG_X0 <= p->to.reg && p->to.reg <= REG_X7) {
                        p->as = AXORPS;
-                       p->from.type = p->to.type;
-                       p->from.index = p->to.index;
+                       p->from = p->to;
                        break;
                }
                // fallthrough
@@ -205,7 +150,7 @@ progedit(Link *ctxt, Prog *p)
        case ADIVSS:
        case ACOMISS:
        case AUCOMISS:
-               if(p->from.type == D_FCONST) {
+               if(p->from.type == TYPE_FCONST) {
                        uint32 i32;
                        float32 f32;
                        f32 = p->from.u.dval;
@@ -217,7 +162,8 @@ progedit(Link *ctxt, Prog *p)
                                adduint32(ctxt, s, i32);
                                s->reachable = 0;
                        }
-                       p->from.type = D_EXTERN;
+                       p->from.type = TYPE_MEM;
+                       p->from.name = NAME_EXTERN;
                        p->from.sym = s;
                        p->from.offset = 0;
                }
@@ -225,13 +171,11 @@ progedit(Link *ctxt, Prog *p)
 
        case AMOVSD:
                // Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
-               if(p->from.type == D_FCONST)
+               if(p->from.type == TYPE_FCONST)
                if(p->from.u.dval == 0)
-               if(p->to.type >= D_X0)
-               if(p->to.type <= D_X7) {
+               if(p->to.type == TYPE_REG && REG_X0 <= p->to.reg && p->to.reg <= REG_X7) {
                        p->as = AXORPS;
-                       p->from.type = p->to.type;
-                       p->from.index = p->to.index;
+                       p->from = p->to;
                        break;
                }
                // fallthrough
@@ -251,7 +195,7 @@ progedit(Link *ctxt, Prog *p)
        case ADIVSD:
        case ACOMISD:
        case AUCOMISD:
-               if(p->from.type == D_FCONST) {
+               if(p->from.type == TYPE_FCONST) {
                        uint64 i64;
                        memmove(&i64, &p->from.u.dval, 8);
                        sprint(literal, "$f64.%016llux", i64);
@@ -261,7 +205,8 @@ progedit(Link *ctxt, Prog *p)
                                adduint64(ctxt, s, i64);
                                s->reachable = 0;
                        }
-                       p->from.type = D_EXTERN;
+                       p->from.type = TYPE_MEM;
+                       p->from.name = NAME_EXTERN;
                        p->from.sym = s;
                        p->from.offset = 0;
                }
@@ -269,21 +214,11 @@ progedit(Link *ctxt, Prog *p)
        }
 }
 
-static Prog*
-prg(void)
-{
-       Prog *p;
-
-       p = emallocz(sizeof(*p));
-       *p = zprg;
-       return p;
-}
-
 static Prog*   load_g_cx(Link*, Prog*);
 static Prog*   stacksplit(Link*, Prog*, int32, int, Prog**);
 
 static void
-addstacksplit(Link *ctxt, LSym *cursym)
+preprocess(Link *ctxt, LSym *cursym)
 {
        Prog *p, *q, *p1, *p2;
        int32 autoffset, deltasp;
@@ -308,21 +243,21 @@ addstacksplit(Link *ctxt, LSym *cursym)
                autoffset = 0;
        
        cursym->locals = autoffset;
-       cursym->args = p->to.offset2;
+       cursym->args = p->to.u.argsize;
 
        q = nil;
 
-       if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
+       if(!(p->from3.offset & NOSPLIT) || (p->from3.offset & WRAPPER)) {
                p = appendp(ctxt, p);
                p = load_g_cx(ctxt, p); // load g into CX
        }
-       if(!(cursym->text->from.scale & NOSPLIT))
-               p = stacksplit(ctxt, p, autoffset, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
+       if(!(cursym->text->from3.offset & NOSPLIT))
+               p = stacksplit(ctxt, p, autoffset, !(cursym->text->from3.offset&NEEDCTXT), &q); // emit split check
 
        if(autoffset) {
                p = appendp(ctxt, p);
                p->as = AADJSP;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = autoffset;
                p->spadj = autoffset;
        } else {
@@ -340,7 +275,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
                q->pcond = p;
        deltasp = autoffset;
        
-       if(cursym->text->from.scale & WRAPPER) {
+       if(cursym->text->from3.offset & WRAPPER) {
                // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
                //
                //      MOVL g_panic(CX), BX
@@ -358,41 +293,51 @@ addstacksplit(Link *ctxt, LSym *cursym)
 
                p = appendp(ctxt, p);
                p->as = AMOVL;
-               p->from.type = D_INDIR+D_CX;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_CX;
                p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
-               p->to.type = D_BX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_BX;
 
                p = appendp(ctxt, p);
                p->as = ATESTL;
-               p->from.type = D_BX;
-               p->to.type = D_BX;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_BX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_BX;
 
                p = appendp(ctxt, p);
                p->as = AJEQ;
-               p->to.type = D_BRANCH;
+               p->to.type = TYPE_BRANCH;
                p1 = p;
 
                p = appendp(ctxt, p);
                p->as = ALEAL;
-               p->from.type = D_INDIR+D_SP;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_SP;
                p->from.offset = autoffset+4;
-               p->to.type = D_DI;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_DI;
 
                p = appendp(ctxt, p);
                p->as = ACMPL;
-               p->from.type = D_INDIR+D_BX;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_BX;
                p->from.offset = 0; // Panic.argp
-               p->to.type = D_DI;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_DI;
 
                p = appendp(ctxt, p);
                p->as = AJNE;
-               p->to.type = D_BRANCH;
+               p->to.type = TYPE_BRANCH;
                p2 = p;
 
                p = appendp(ctxt, p);
                p->as = AMOVL;
-               p->from.type = D_SP;
-               p->to.type = D_INDIR+D_BX;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_SP;
+               p->to.type = TYPE_MEM;
+               p->to.reg = REG_BX;
                p->to.offset = 0; // Panic.argp
 
                p = appendp(ctxt, p);
@@ -401,26 +346,30 @@ addstacksplit(Link *ctxt, LSym *cursym)
                p2->pcond = p;
        }
        
-       if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
+       if(ctxt->debugzerostack && autoffset && !(cursym->text->from3.offset&NOSPLIT)) {
                // 8l -Z means zero the stack frame on entry.
                // This slows down function calls but can help avoid
                // false positives in garbage collection.
                p = appendp(ctxt, p);
                p->as = AMOVL;
-               p->from.type = D_SP;
-               p->to.type = D_DI;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_SP;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_DI;
                
                p = appendp(ctxt, p);
                p->as = AMOVL;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = autoffset/4;
-               p->to.type = D_CX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_CX;
                
                p = appendp(ctxt, p);
                p->as = AMOVL;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = 0;
-               p->to.type = D_AX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_AX;
                
                p = appendp(ctxt, p);
                p->as = AREP;
@@ -430,15 +379,15 @@ addstacksplit(Link *ctxt, LSym *cursym)
        }
        
        for(; p != nil; p = p->link) {
-               a = p->from.type;
-               if(a == D_AUTO)
+               a = p->from.name;
+               if(a == NAME_AUTO)
                        p->from.offset += deltasp;
-               if(a == D_PARAM)
+               if(a == NAME_PARAM)
                        p->from.offset += deltasp + 4;
-               a = p->to.type;
-               if(a == D_AUTO)
+               a = p->to.name;
+               if(a == NAME_AUTO)
                        p->to.offset += deltasp;
-               if(a == D_PARAM)
+               if(a == NAME_PARAM)
                        p->to.offset += deltasp + 4;
 
                switch(p->as) {
@@ -473,7 +422,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
 
                if(autoffset) {
                        p->as = AADJSP;
-                       p->from.type = D_CONST;
+                       p->from.type = TYPE_CONST;
                        p->from.offset = -autoffset;
                        p->spadj = -autoffset;
                        p = appendp(ctxt, p);
@@ -500,16 +449,18 @@ load_g_cx(Link *ctxt, Prog *p)
        Prog *next;
 
        p->as = AMOVL;
-       p->from.type = D_INDIR+D_TLS;
+       p->from.type = TYPE_MEM;
+       p->from.reg = REG_TLS;
        p->from.offset = 0;
-       p->to.type = D_CX;
+       p->to.type = TYPE_REG;
+       p->to.reg = REG_CX;
 
        next = p->link;
        progedit(ctxt, p);
        while(p->link != next)
                p = p->link;
        
-       if(p->from.index == D_TLS)
+       if(p->from.index == REG_TLS)
                p->from.scale = 2;
 
        return p;
@@ -534,19 +485,21 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
                // catches out-of-sync stack guard info.
                p = appendp(ctxt, p);
                p->as = ACMPL;
-               p->from.type = D_INDIR+D_CX;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_CX;
                p->from.offset = 4;
-               p->to.type = D_SP;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_SP;
 
                p = appendp(ctxt, p);
                p->as = AJCC;
-               p->to.type = D_BRANCH;
+               p->to.type = TYPE_BRANCH;
                p->to.offset = 4;
                q1 = p;
 
                p = appendp(ctxt, p);
                p->as = AINT;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = 3;
                
                p = appendp(ctxt, p);
@@ -560,8 +513,10 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
                //      CMPL SP, stackguard
                p = appendp(ctxt, p);
                p->as = ACMPL;
-               p->from.type = D_SP;
-               p->to.type = D_INDIR+D_CX;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_SP;
+               p->to.type = TYPE_MEM;
+               p->to.reg = REG_CX;
                p->to.offset = 2*ctxt->arch->ptrsize;   // G.stackguard0
                if(ctxt->cursym->cfunc)
                        p->to.offset = 3*ctxt->arch->ptrsize;   // G.stackguard1
@@ -571,14 +526,18 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
                //      CMPL AX, stackguard
                p = appendp(ctxt, p);
                p->as = ALEAL;
-               p->from.type = D_INDIR+D_SP;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_SP;
                p->from.offset = -(framesize-StackSmall);
-               p->to.type = D_AX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_AX;
 
                p = appendp(ctxt, p);
                p->as = ACMPL;
-               p->from.type = D_AX;
-               p->to.type = D_INDIR+D_CX;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_AX;
+               p->to.type = TYPE_MEM;
+               p->to.reg = REG_CX;
                p->to.offset = 2*ctxt->arch->ptrsize;   // G.stackguard0
                if(ctxt->cursym->cfunc)
                        p->to.offset = 3*ctxt->arch->ptrsize;   // G.stackguard1
@@ -599,53 +558,61 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
                //      CMPL    AX, $(framesize+(StackGuard-StackSmall))
                p = appendp(ctxt, p);
                p->as = AMOVL;
-               p->from.type = D_INDIR+D_CX;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_CX;
                p->from.offset = 0;
                p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
                if(ctxt->cursym->cfunc)
                        p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
-               p->to.type = D_SI;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_SI;
 
                p = appendp(ctxt, p);
                p->as = ACMPL;
-               p->from.type = D_SI;
-               p->to.type = D_CONST;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_SI;
+               p->to.type = TYPE_CONST;
                p->to.offset = (uint32)StackPreempt;
 
                p = appendp(ctxt, p);
                p->as = AJEQ;
-               p->to.type = D_BRANCH;
+               p->to.type = TYPE_BRANCH;
                q1 = p;
 
                p = appendp(ctxt, p);
                p->as = ALEAL;
-               p->from.type = D_INDIR+D_SP;
+               p->from.type = TYPE_MEM;
+               p->from.reg = REG_SP;
                p->from.offset = StackGuard;
-               p->to.type = D_AX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_AX;
                
                p = appendp(ctxt, p);
                p->as = ASUBL;
-               p->from.type = D_SI;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_SI;
                p->from.offset = 0;
-               p->to.type = D_AX;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_AX;
                
                p = appendp(ctxt, p);
                p->as = ACMPL;
-               p->from.type = D_AX;
-               p->to.type = D_CONST;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_AX;
+               p->to.type = TYPE_CONST;
                p->to.offset = framesize+(StackGuard-StackSmall);
        }               
                        
        // common
        p = appendp(ctxt, p);
        p->as = AJHI;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        p->to.offset = 4;
        q = p;
 
        p = appendp(ctxt, p);
        p->as = ACALL;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        if(ctxt->cursym->cfunc)
                p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
        else
@@ -653,7 +620,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
 
        p = appendp(ctxt, p);
        p->as = AJMP;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        p->pcond = ctxt->cursym->text->link;
 
        if(q != nil)
@@ -674,7 +641,7 @@ follow(Link *ctxt, LSym *s)
 
        ctxt->cursym = s;
 
-       firstp = ctxt->arch->prg();
+       firstp = emallocz(sizeof(Prog));
        lastp = firstp;
        xfol(ctxt, s->text, &lastp);
        lastp->link = nil;
@@ -801,10 +768,10 @@ loop:
                                goto loop;
                        }
                } /* */
-               q = ctxt->arch->prg();
+               q = emallocz(sizeof(Prog));
                q->as = AJMP;
                q->lineno = p->lineno;
-               q->to.type = D_BRANCH;
+               q->to.type = TYPE_BRANCH;
                q->to.offset = p->pc;
                q->pcond = p;
                p = q;
@@ -829,7 +796,7 @@ loop:
                        p->pcond = q;
                if((q = brchain(ctxt, p->link)) != nil)
                        p->link = q;
-               if(p->from.type == D_CONST) {
+               if(p->from.type == TYPE_CONST) {
                        if(p->from.offset == 1) {
                                /*
                                 * expect conditional jump to be taken.
@@ -864,43 +831,12 @@ LinkArch link386 = {
        .thechar = '8',
        .endian = LittleEndian,
 
-       .addstacksplit = addstacksplit,
+       .preprocess = preprocess,
        .assemble = span8,
-       .datasize = datasize,
        .follow = follow,
-       .iscall = iscall,
-       .isdata = isdata,
-       .prg = prg,
        .progedit = progedit,
-       .settextflag = settextflag,
-       .symtype = symtype,
-       .textflag = textflag,
 
        .minlc = 1,
        .ptrsize = 4,
        .regsize = 4,
-
-       .D_ADDR = D_ADDR,
-       .D_AUTO = D_AUTO,
-       .D_BRANCH = D_BRANCH,
-       .D_CONST = D_CONST,
-       .D_EXTERN = D_EXTERN,
-       .D_FCONST = D_FCONST,
-       .D_NONE = D_NONE,
-       .D_PARAM = D_PARAM,
-       .D_SCONST = D_SCONST,
-       .D_STATIC = D_STATIC,
-
-       .ACALL = ACALL,
-       .ADATA = ADATA,
-       .AEND = AEND,
-       .AFUNCDATA = AFUNCDATA,
-       .AGLOBL = AGLOBL,
-       .AJMP = AJMP,
-       .ANOP = ANOP,
-       .APCDATA = APCDATA,
-       .ARET = ARET,
-       .ATEXT = ATEXT,
-       .ATYPE = ATYPE,
-       .AUSEFIELD = AUSEFIELD,
 };
index 5ac575593d59812f30dd5b3120137cec8f5f05f0..450ed00306eac45cb153bd97d183ef9f9a62d6fe 100644 (file)
 #include "../runtime/stack.h"
 #include "../runtime/funcdata.h"
 
-static Prog zprg = {
-       .as = AGOK,
-       .reg = NREG,
-       .from = {
-               .name = D_NONE,
-               .type = D_NONE,
-               .reg = NREG,
-       },
-       .from3 = {
-               .name = D_NONE,
-               .type = D_NONE,
-               .reg = NREG,
-       },
-       .to = {
-               .name = D_NONE,
-               .type = D_NONE,
-               .reg = NREG,
-       },
-};
-
-static int
-symtype(Addr *a)
-{
-       return a->name;
-}
-
-static int
-isdata(Prog *p)
-{
-       return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
-       return p->as == ABL;
-}
-
-static int
-datasize(Prog *p)
-{
-       return p->reg;
-}
-
-static int
-textflag(Prog *p)
-{
-       return p->reg;
-}
-
-static void
-settextflag(Prog *p, int f)
-{
-       p->reg = f;
-}
-
 static void
 progedit(Link *ctxt, Prog *p)
 {
@@ -102,7 +46,7 @@ progedit(Link *ctxt, Prog *p)
        p->from.class = 0;
        p->to.class = 0;
 
-       // Rewrite BR/BL to symbol as D_BRANCH.
+       // Rewrite BR/BL to symbol as TYPE_BRANCH.
        switch(p->as) {
        case ABR:
        case ABL:
@@ -110,14 +54,14 @@ progedit(Link *ctxt, Prog *p)
        case ADUFFZERO:
        case ADUFFCOPY:
                if(p->to.sym != nil)
-                       p->to.type = D_BRANCH;
+                       p->to.type = TYPE_BRANCH;
                break;
        }
 
        // Rewrite float constants to values stored in memory.
        switch(p->as) {
        case AFMOVS:
-               if(p->from.type == D_FCONST) {
+               if(p->from.type == TYPE_FCONST) {
                        uint32 i32;
                        float32 f32;
                        f32 = p->from.u.dval;
@@ -125,34 +69,34 @@ progedit(Link *ctxt, Prog *p)
                        sprint(literal, "$f32.%08ux", i32);
                        s = linklookup(ctxt, literal, 0);
                        s->size = 4;
-                       p->from.type = D_OREG;
+                       p->from.type = TYPE_MEM;
                        p->from.sym = s;
-                       p->from.name = D_EXTERN;
+                       p->from.name = NAME_EXTERN;
                        p->from.offset = 0;
                }
                break;
        case AFMOVD:
-               if(p->from.type == D_FCONST) {
+               if(p->from.type == TYPE_FCONST) {
                        uint64 i64;
                        memmove(&i64, &p->from.u.dval, 8);
                        sprint(literal, "$f64.%016llux", i64);
                        s = linklookup(ctxt, literal, 0);
                        s->size = 8;
-                       p->from.type = D_OREG;
+                       p->from.type = TYPE_MEM;
                        p->from.sym = s;
-                       p->from.name = D_EXTERN;
+                       p->from.name = NAME_EXTERN;
                        p->from.offset = 0;
                }
                break;
        case AMOVD:
                // Put >32-bit constants in memory and load them
-               if(p->from.type == D_CONST && p->from.name == D_NONE && p->from.reg == NREG && (int32)p->from.offset != p->from.offset) {
+               if(p->from.type == TYPE_CONST && p->from.name == NAME_NONE && p->from.reg == 0 && (int32)p->from.offset != p->from.offset) {
                        sprint(literal, "$i64.%016llux", (uvlong)p->from.offset);
                        s = linklookup(ctxt, literal, 0);
                        s->size = 8;
-                       p->from.type = D_OREG;
+                       p->from.type = TYPE_MEM;
                        p->from.sym = s;
-                       p->from.name = D_EXTERN;
+                       p->from.name = NAME_EXTERN;
                        p->from.offset = 0;
                }
        }
@@ -160,21 +104,21 @@ progedit(Link *ctxt, Prog *p)
        // Rewrite SUB constants into ADD.
        switch(p->as) {
        case ASUBC:
-               if(p->from.type == D_CONST) {
+               if(p->from.type == TYPE_CONST) {
                        p->from.offset = -p->from.offset;
                        p->as = AADDC;
                }
                break;
 
        case ASUBCCC:
-               if(p->from.type == D_CONST) {
+               if(p->from.type == TYPE_CONST) {
                        p->from.offset = -p->from.offset;
                        p->as = AADDCCC;
                }
                break;
 
        case ASUB:
-               if(p->from.type == D_CONST) {
+               if(p->from.type == TYPE_CONST) {
                        p->from.offset = -p->from.offset;
                        p->as = AADD;
                }
@@ -185,24 +129,11 @@ progedit(Link *ctxt, Prog *p)
 static Prog*   stacksplit(Link*, Prog*, int32, int);
 
 static void
-parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg)
-{
-       *textstksiz = arg & 0xffffffffLL;
-       if(*textstksiz & 0x80000000LL)
-               *textstksiz = -(-*textstksiz & 0xffffffffLL);
-
-       *textarg = (arg >> 32) & 0xffffffffLL;
-       if(*textarg & 0x80000000LL)
-               *textarg = 0;
-       *textarg = (*textarg+7) & ~7LL;
-}
-
-static void
-addstacksplit(Link *ctxt, LSym *cursym)
+preprocess(Link *ctxt, LSym *cursym)
 {
        Prog *p, *q, *p1, *p2, *q1;
        int o, mov, aoffset;
-       vlong textstksiz, textarg;
+       vlong textstksiz;
        int32 autosize;
 
        if(ctxt->symmorestack[0] == nil) {
@@ -217,9 +148,9 @@ addstacksplit(Link *ctxt, LSym *cursym)
                return;                         
 
        p = cursym->text;
-       parsetextconst(p->to.offset, &textstksiz, &textarg);
+       textstksiz = p->to.offset;
        
-       cursym->args = p->to.offset>>32;
+       cursym->args = p->to.u.argsize;
        cursym->locals = textstksiz;
 
        /*
@@ -246,7 +177,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
 
                case ANOR:
                        q = p;
-                       if(p->to.type == D_REG)
+                       if(p->to.type == TYPE_REG)
                                if(p->to.reg == REGZERO)
                                        p->mark |= LABEL|SYNC;
                        break;
@@ -288,22 +219,8 @@ addstacksplit(Link *ctxt, LSym *cursym)
                case AMOVWZ:
                case AMOVD:
                        q = p;
-                       switch(p->from.type) {
-                       case D_MSR:
-                       case D_SPR:
-                       case D_FPSCR:
-                       case D_CREG:
-                       case D_DCR:
-                               p->mark |= LABEL|SYNC;
-                       }
-                       switch(p->to.type) {
-                       case D_MSR:
-                       case D_SPR:
-                       case D_FPSCR:
-                       case D_CREG:
-                       case D_DCR:
+                       if(p->from.reg >= REG_SPECIAL || p->to.reg >= REG_SPECIAL)
                                p->mark |= LABEL|SYNC;
-                       }
                        continue;
 
                case AFABS:
@@ -414,10 +331,10 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        else
                                if(autosize & 4)
                                        autosize += 4;
-                       p->to.offset = ((uint64)p->to.offset & (0xffffffffull<<32)) | (uint32)(autosize-8);
+                       p->to.offset = autosize-8;
 
-                       if(!(p->reg & NOSPLIT))
-                               p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
+                       if(!(p->from3.offset & NOSPLIT))
+                               p = stacksplit(ctxt, p, autosize, !(cursym->text->from3.offset&NEEDCTXT)); // emit split check
 
                        q = p;
                        if(autosize) {
@@ -429,9 +346,9 @@ addstacksplit(Link *ctxt, LSym *cursym)
                                        q = appendp(ctxt, p);
                                        q->as = AADD;
                                        q->lineno = p->lineno;
-                                       q->from.type = D_CONST;
+                                       q->from.type = TYPE_CONST;
                                        q->from.offset = -autosize;
-                                       q->to.type = D_REG;
+                                       q->to.type = TYPE_REG;
                                        q->to.reg = REGSP;
                                        q->spadj = +autosize;
                                }
@@ -453,23 +370,23 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        q = appendp(ctxt, q);
                        q->as = AMOVD;
                        q->lineno = p->lineno;
-                       q->from.type = D_SPR;
-                       q->from.offset = D_LR;
-                       q->to.type = D_REG;
+                       q->from.type = TYPE_REG;
+                       q->from.reg = REG_LR;
+                       q->to.type = TYPE_REG;
                        q->to.reg = REGTMP;
 
                        q = appendp(ctxt, q);
                        q->as = mov;
                        q->lineno = p->lineno;
-                       q->from.type = D_REG;
+                       q->from.type = TYPE_REG;
                        q->from.reg = REGTMP;
-                       q->to.type = D_OREG;
+                       q->to.type = TYPE_MEM;
                        q->to.offset = aoffset;
                        q->to.reg = REGSP;
                        if(q->as == AMOVDU)
                                q->spadj = -aoffset;
 
-                       if(cursym->text->reg & WRAPPER) {
+                       if(cursym->text->from3.offset & WRAPPER) {
                                // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
                                //
                                //      MOVD g_panic(g), R3
@@ -490,66 +407,66 @@ addstacksplit(Link *ctxt, LSym *cursym)
 
                                q = appendp(ctxt, q);
                                q->as = AMOVD;
-                               q->from.type = D_OREG;
+                               q->from.type = TYPE_MEM;
                                q->from.reg = REGG;
                                q->from.offset = 4*ctxt->arch->ptrsize; // G.panic
-                               q->to.type = D_REG;
-                               q->to.reg = 3;
+                               q->to.type = TYPE_REG;
+                               q->to.reg = REG_R3;
 
                                q = appendp(ctxt, q);
                                q->as = ACMP;
-                               q->from.type = D_REG;
-                               q->from.reg = 0;
-                               q->to.type = D_REG;
-                               q->to.reg = 3;
+                               q->from.type = TYPE_REG;
+                               q->from.reg = REG_R0;
+                               q->to.type = TYPE_REG;
+                               q->to.reg = REG_R3;
 
                                q = appendp(ctxt, q);
                                q->as = ABEQ;
-                               q->to.type = D_BRANCH;
+                               q->to.type = TYPE_BRANCH;
                                p1 = q;
 
                                q = appendp(ctxt, q);
                                q->as = AMOVD;
-                               q->from.type = D_OREG;
-                               q->from.reg = 3;
+                               q->from.type = TYPE_MEM;
+                               q->from.reg = REG_R3;
                                q->from.offset = 0; // Panic.argp
-                               q->to.type = D_REG;
-                               q->to.reg = 4;
+                               q->to.type = TYPE_REG;
+                               q->to.reg = REG_R4;
 
                                q = appendp(ctxt, q);
                                q->as = AADD;
-                               q->from.type = D_CONST;
+                               q->from.type = TYPE_CONST;
                                q->from.offset = autosize+8;
                                q->reg = REGSP;
-                               q->to.type = D_REG;
-                               q->to.reg = 5;
+                               q->to.type = TYPE_REG;
+                               q->to.reg = REG_R5;
 
                                q = appendp(ctxt, q);
                                q->as = ACMP;
-                               q->from.type = D_REG;
-                               q->from.reg = 4;
-                               q->to.type = D_REG;
-                               q->to.reg = 5;
+                               q->from.type = TYPE_REG;
+                               q->from.reg = REG_R4;
+                               q->to.type = TYPE_REG;
+                               q->to.reg = REG_R5;
 
                                q = appendp(ctxt, q);
                                q->as = ABNE;
-                               q->to.type = D_BRANCH;
+                               q->to.type = TYPE_BRANCH;
                                p2 = q;
 
                                q = appendp(ctxt, q);
                                q->as = AADD;
-                               q->from.type = D_CONST;
+                               q->from.type = TYPE_CONST;
                                q->from.offset = 8;
                                q->reg = REGSP;
-                               q->to.type = D_REG;
-                               q->to.reg = 6;
+                               q->to.type = TYPE_REG;
+                               q->to.reg = REG_R6;
 
                                q = appendp(ctxt, q);
                                q->as = AMOVD;
-                               q->from.type = D_REG;
-                               q->from.reg = 6;
-                               q->to.type = D_OREG;
-                               q->to.reg = 3;
+                               q->from.type = TYPE_REG;
+                               q->from.reg = REG_R6;
+                               q->to.type = TYPE_MEM;
+                               q->to.reg = REG_R3;
                                q->to.offset = 0; // Panic.argp
 
                                q = appendp(ctxt, q);
@@ -561,37 +478,37 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        break;
 
                case ARETURN:
-                       if(p->from.type == D_CONST) {
+                       if(p->from.type == TYPE_CONST) {
                                ctxt->diag("using BECOME (%P) is not supported!", p);
                                break;
                        }
                        if(p->to.sym) { // retjmp
                                p->as = ABR;
-                               p->to.type = D_BRANCH;
+                               p->to.type = TYPE_BRANCH;
                                break;
                        }
                        if(cursym->text->mark & LEAF) {
                                if(!autosize) {
                                        p->as = ABR;
-                                       p->from = zprg.from;
-                                       p->to.type = D_SPR;
-                                       p->to.offset = D_LR;
+                                       p->from = zprog.from;
+                                       p->to.type = TYPE_REG;
+                                       p->to.reg = REG_LR;
                                        p->mark |= BRANCH;
                                        break;
                                }
 
                                p->as = AADD;
-                               p->from.type = D_CONST;
+                               p->from.type = TYPE_CONST;
                                p->from.offset = autosize;
-                               p->to.type = D_REG;
+                               p->to.type = TYPE_REG;
                                p->to.reg = REGSP;
                                p->spadj = -autosize;
 
-                               q = ctxt->arch->prg();
+                               q = emallocz(sizeof(Prog));
                                q->as = ABR;
                                q->lineno = p->lineno;
-                               q->to.type = D_SPR;
-                               q->to.offset = D_LR;
+                               q->to.type = TYPE_REG;
+                               q->to.reg = REG_LR;
                                q->mark |= BRANCH;
                                q->spadj = +autosize;
 
@@ -601,19 +518,19 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        }
 
                        p->as = AMOVD;
-                       p->from.type = D_OREG;
+                       p->from.type = TYPE_MEM;
                        p->from.offset = 0;
                        p->from.reg = REGSP;
-                       p->to.type = D_REG;
+                       p->to.type = TYPE_REG;
                        p->to.reg = REGTMP;
 
-                       q = ctxt->arch->prg();
+                       q = emallocz(sizeof(Prog));
                        q->as = AMOVD;
                        q->lineno = p->lineno;
-                       q->from.type = D_REG;
+                       q->from.type = TYPE_REG;
                        q->from.reg = REGTMP;
-                       q->to.type = D_SPR;
-                       q->to.offset = D_LR;
+                       q->to.type = TYPE_REG;
+                       q->to.reg = REG_LR;
 
                        q->link = p->link;
                        p->link = q;
@@ -621,13 +538,13 @@ addstacksplit(Link *ctxt, LSym *cursym)
 
                        if(0) {
                                // Debug bad returns
-                               q = ctxt->arch->prg();
+                               q = emallocz(sizeof(Prog));
                                q->as = AMOVD;
                                q->lineno = p->lineno;
-                               q->from.type = D_OREG;
+                               q->from.type = TYPE_MEM;
                                q->from.offset = 0;
                                q->from.reg = REGTMP;
-                               q->to.type = D_REG;
+                               q->to.type = TYPE_REG;
                                q->to.reg = REGTMP;
 
                                q->link = p->link;
@@ -636,12 +553,12 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        }
 
                        if(autosize) {
-                               q = ctxt->arch->prg();
+                               q = emallocz(sizeof(Prog));
                                q->as = AADD;
                                q->lineno = p->lineno;
-                               q->from.type = D_CONST;
+                               q->from.type = TYPE_CONST;
                                q->from.offset = autosize;
-                               q->to.type = D_REG;
+                               q->to.type = TYPE_REG;
                                q->to.reg = REGSP;
                                q->spadj = -autosize;
 
@@ -649,11 +566,11 @@ addstacksplit(Link *ctxt, LSym *cursym)
                                p->link = q;
                        }
 
-                       q1 = ctxt->arch->prg();
+                       q1 = emallocz(sizeof(Prog));
                        q1->as = ABR;
                        q1->lineno = p->lineno;
-                       q1->to.type = D_SPR;
-                       q1->to.offset = D_LR;
+                       q1->to.type = TYPE_REG;
+                       q1->to.reg = REG_LR;
                        q1->mark |= BRANCH;
                        q1->spadj = +autosize;
 
@@ -662,7 +579,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
                        break;
 
                case AADD:
-                       if(p->to.type == D_REG && p->to.reg == REGSP && p->from.type == D_CONST)
+                       if(p->to.type == TYPE_REG && p->to.reg == REGSP && p->from.type == TYPE_CONST)
                                p->spadj = -p->from.offset;
                        break;
                }
@@ -723,13 +640,13 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
        // MOVD g_stackguard(g), R3
        p = appendp(ctxt, p);
        p->as = AMOVD;
-       p->from.type = D_OREG;
+       p->from.type = TYPE_MEM;
        p->from.reg = REGG;
        p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
        if(ctxt->cursym->cfunc)
                p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
-       p->to.type = D_REG;
-       p->to.reg = 3;
+       p->to.type = TYPE_REG;
+       p->to.reg = REG_R3;
 
        q = nil;
        if(framesize <= StackSmall) {
@@ -737,9 +654,9 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
                //      CMP     stackguard, SP
                p = appendp(ctxt, p);
                p->as = ACMPU;
-               p->from.type = D_REG;
-               p->from.reg = 3;
-               p->to.type = D_REG;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_R3;
+               p->to.type = TYPE_REG;
                p->to.reg = REGSP;
        } else if(framesize <= StackBig) {
                // large stack: SP-framesize < stackguard-StackSmall
@@ -747,18 +664,18 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
                //      CMP stackguard, R4
                p = appendp(ctxt, p);
                p->as = AADD;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = -framesize;
                p->reg = REGSP;
-               p->to.type = D_REG;
-               p->to.reg = 4;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_R4;
 
                p = appendp(ctxt, p);
                p->as = ACMPU;
-               p->from.type = D_REG;
-               p->from.reg = 3;
-               p->to.type = D_REG;
-               p->to.reg = 4;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_R3;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_R4;
        } else {
                // Such a large stack we need to protect against wraparound.
                // If SP is close to zero:
@@ -777,64 +694,64 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
                //      CMPU    R31, R4
                p = appendp(ctxt, p);
                p->as = ACMP;
-               p->from.type = D_REG;
-               p->from.reg = 3;
-               p->to.type = D_CONST;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_R3;
+               p->to.type = TYPE_CONST;
                p->to.offset = StackPreempt;
 
                q = p = appendp(ctxt, p);
                p->as = ABEQ;
-               p->to.type = D_BRANCH;
+               p->to.type = TYPE_BRANCH;
 
                p = appendp(ctxt, p);
                p->as = AADD;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = StackGuard;
                p->reg = REGSP;
-               p->to.type = D_REG;
-               p->to.reg = 4;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_R4;
 
                p = appendp(ctxt, p);
                p->as = ASUB;
-               p->from.type = D_REG;
-               p->from.reg = 3;
-               p->to.type = D_REG;
-               p->to.reg = 4;
+               p->from.type = TYPE_REG;
+               p->from.reg = REG_R3;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_R4;
 
                p = appendp(ctxt, p);
                p->as = AMOVD;
-               p->from.type = D_CONST;
+               p->from.type = TYPE_CONST;
                p->from.offset = framesize + StackGuard - StackSmall;
-               p->to.type = D_REG;
+               p->to.type = TYPE_REG;
                p->to.reg = REGTMP;
 
                p = appendp(ctxt, p);
                p->as = ACMPU;
-               p->from.type = D_REG;
+               p->from.type = TYPE_REG;
                p->from.reg = REGTMP;
-               p->to.type = D_REG;
-               p->to.reg = 4;
+               p->to.type = TYPE_REG;
+               p->to.reg = REG_R4;
        }
 
        // q1: BLT      done
        q1 = p = appendp(ctxt, p);
        p->as = ABLT;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
 
        // MOVD LR, R5
        p = appendp(ctxt, p);
        p->as = AMOVD;
-       p->from.type = D_SPR;
-       p->from.offset = D_LR;
-       p->to.type = D_REG;
-       p->to.reg = 5;
+       p->from.type = TYPE_REG;
+       p->from.reg = REG_LR;
+       p->to.type = TYPE_REG;
+       p->to.reg = REG_R5;
        if(q)
                q->pcond = p;
 
        // BL   runtime.morestack(SB)
        p = appendp(ctxt, p);
        p->as = ABL;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        if(ctxt->cursym->cfunc)
                p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
        else
@@ -843,7 +760,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
        // BR   start
        p = appendp(ctxt, p);
        p->as = ABR;
-       p->to.type = D_BRANCH;
+       p->to.type = TYPE_BRANCH;
        p->pcond = ctxt->cursym->text->link;
 
        // placeholder for q1's jump target
@@ -863,7 +780,7 @@ follow(Link *ctxt, LSym *s)
 
        ctxt->cursym = s;
 
-       firstp = ctxt->arch->prg();
+       firstp = emallocz(sizeof(Prog));
        lastp = firstp;
        xfol(ctxt, s->text, &lastp);
        lastp->link = nil;
@@ -939,7 +856,7 @@ loop:
                                continue;
                copy:
                        for(;;) {
-                               r = ctxt->arch->prg();
+                               r = emallocz(sizeof(Prog));
                                *r = *p;
                                if(!(r->mark&FOLL))
                                        print("cant happen 1\n");
@@ -966,10 +883,10 @@ loop:
                }
 
                a = ABR;
-               q = ctxt->arch->prg();
+               q = emallocz(sizeof(Prog));
                q->as = a;
                q->lineno = p->lineno;
-               q->to.type = D_BRANCH;
+               q->to.type = TYPE_BRANCH;
                q->to.offset = p->pc;
                q->pcond = p;
                p = q;
@@ -996,61 +913,19 @@ loop:
        goto loop;
 }
 
-static Prog*
-prg(void)
-{
-       Prog *p;
-
-       p = emallocz(sizeof(*p));
-       *p = zprg;
-       return p;
-}
-
 LinkArch linkppc64 = {
        .name = "ppc64",
        .thechar = '9',
        .endian = BigEndian,
 
-       .addstacksplit = addstacksplit,
+       .preprocess = preprocess,
        .assemble = span9,
-       .datasize = datasize,
        .follow = follow,
-       .iscall = iscall,
-       .isdata = isdata,
-       .prg = prg,
        .progedit = progedit,
-       .settextflag = settextflag,
-       .symtype = symtype,
-       .textflag = textflag,
 
        .minlc = 4,
        .ptrsize = 8,
        .regsize = 8,
-
-       .D_ADDR = D_ADDR,
-       .D_AUTO = D_AUTO,
-       .D_BRANCH = D_BRANCH,
-       .D_CONST = D_CONST,
-       .D_EXTERN = D_EXTERN,
-       .D_FCONST = D_FCONST,
-       .D_NONE = D_NONE,
-       .D_PARAM = D_PARAM,
-       .D_SCONST = D_SCONST,
-       .D_STATIC = D_STATIC,
-       .D_OREG = D_OREG,
-
-       .ACALL = ABL,
-       .ADATA = ADATA,
-       .AEND = AEND,
-       .AFUNCDATA = AFUNCDATA,
-       .AGLOBL = AGLOBL,
-       .AJMP = ABR,
-       .ANOP = ANOP,
-       .APCDATA = APCDATA,
-       .ARET = ARETURN,
-       .ATEXT = ATEXT,
-       .ATYPE = ATYPE,
-       .AUSEFIELD = AUSEFIELD,
 };
 
 LinkArch linkppc64le = {
@@ -1058,44 +933,12 @@ LinkArch linkppc64le = {
        .thechar = '9',
        .endian = LittleEndian,
 
-       .addstacksplit = addstacksplit,
+       .preprocess = preprocess,
        .assemble = span9,
-       .datasize = datasize,
        .follow = follow,
-       .iscall = iscall,
-       .isdata = isdata,
-       .prg = prg,
        .progedit = progedit,
-       .settextflag = settextflag,
-       .symtype = symtype,
-       .textflag = textflag,
 
        .minlc = 4,
        .ptrsize = 8,
        .regsize = 8,
-
-       .D_ADDR = D_ADDR,
-       .D_AUTO = D_AUTO,
-       .D_BRANCH = D_BRANCH,
-       .D_CONST = D_CONST,
-       .D_EXTERN = D_EXTERN,
-       .D_FCONST = D_FCONST,
-       .D_NONE = D_NONE,
-       .D_PARAM = D_PARAM,
-       .D_SCONST = D_SCONST,
-       .D_STATIC = D_STATIC,
-       .D_OREG = D_OREG,
-
-       .ACALL = ABL,
-       .ADATA = ADATA,
-       .AEND = AEND,
-       .AFUNCDATA = AFUNCDATA,
-       .AGLOBL = AGLOBL,
-       .AJMP = ABR,
-       .ANOP = ANOP,
-       .APCDATA = APCDATA,
-       .ARET = ARETURN,
-       .ATEXT = ATEXT,
-       .ATYPE = ATYPE,
-       .AUSEFIELD = AUSEFIELD,
 };
index a238fce57d35a81b44dc584ae9d1ac77e9b9f789..99f5e97607b4757629b0518a17a18e0ad09e7596 100644 (file)
@@ -184,14 +184,14 @@ writeobjdirect(Link *ctxt, Biobuf *b)
        for(pl = ctxt->plist; pl != nil; pl = pl->link) {
                for(p = pl->firstpc; p != nil; p = plink) {
                        if(ctxt->debugasm && ctxt->debugvlog)
-                               print("obj: %p %P\n", p, p);
+                               print("obj: %P\n", p);
                        plink = p->link;
                        p->link = nil;
 
-                       if(p->as == ctxt->arch->AEND)
+                       if(p->as == AEND)
                                continue;
 
-                       if(p->as == ctxt->arch->ATYPE) {
+                       if(p->as == ATYPE) {
                                // Assume each TYPE instruction describes
                                // a different local variable or parameter,
                                // so no dedup.
@@ -208,14 +208,14 @@ writeobjdirect(Link *ctxt, Biobuf *b)
                                a = emallocz(sizeof *a);
                                a->asym = p->from.sym;
                                a->aoffset = p->from.offset;
-                               a->type = ctxt->arch->symtype(&p->from);
+                               a->name = p->from.name;
                                a->gotype = p->from.gotype;
                                a->link = curtext->autom;
                                curtext->autom = a;
                                continue;
                        }
 
-                       if(p->as == ctxt->arch->AGLOBL) {
+                       if(p->as == AGLOBL) {
                                s = p->from.sym;
                                if(s->seenglobl++)
                                        print("duplicate %P\n", p);
@@ -230,7 +230,7 @@ writeobjdirect(Link *ctxt, Biobuf *b)
                                s->size = p->to.offset;
                                if(s->type == 0 || s->type == SXREF)
                                        s->type = SBSS;
-                               flag = ctxt->arch->textflag(p);
+                               flag = p->from3.offset;
                                if(flag & DUPOK)
                                        s->dupok = 1;
                                if(flag & RODATA)
@@ -241,12 +241,12 @@ writeobjdirect(Link *ctxt, Biobuf *b)
                                continue;
                        }
 
-                       if(p->as == ctxt->arch->ADATA) {
+                       if(p->as == ADATA) {
                                savedata(ctxt, p->from.sym, p, "<input>");
                                continue;
                        }
 
-                       if(p->as == ctxt->arch->ATEXT) {
+                       if(p->as == ATEXT) {
                                s = p->from.sym;
                                if(s == nil) {
                                        // func _() { }
@@ -263,7 +263,7 @@ writeobjdirect(Link *ctxt, Biobuf *b)
                                else
                                        etext->next = s;
                                etext = s;
-                               flag = ctxt->arch->textflag(p);
+                               flag = p->from3.offset;
                                if(flag & DUPOK)
                                        s->dupok = 1;
                                if(flag & NOSPLIT)
@@ -276,12 +276,12 @@ writeobjdirect(Link *ctxt, Biobuf *b)
                                continue;
                        }
                        
-                       if(p->as == ctxt->arch->AFUNCDATA) {
+                       if(p->as == AFUNCDATA) {
                                // Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
                                if(curtext == nil) // func _() {}
                                        continue;
                                if(strcmp(p->to.sym->name, "go_args_stackmap") == 0) {
-                                       if(p->from.type != ctxt->arch->D_CONST || p->from.offset != FUNCDATA_ArgsPointerMaps)
+                                       if(p->from.type != TYPE_CONST || p->from.offset != FUNCDATA_ArgsPointerMaps)
                                                ctxt->diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps");
                                        p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", curtext->name), curtext->version);
                                }
@@ -301,22 +301,18 @@ writeobjdirect(Link *ctxt, Biobuf *b)
                        continue;
                found = 0;
                for(p = s->text; p != nil; p = p->link) {
-                       if(p->as == ctxt->arch->AFUNCDATA && p->from.type == ctxt->arch->D_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) {
+                       if(p->as == AFUNCDATA && p->from.type == TYPE_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) {
                                found = 1;
                                break;
                        }
                }
                if(!found) {
                        p = appendp(ctxt, s->text);
-                       p->as = ctxt->arch->AFUNCDATA;
-                       p->from.type = ctxt->arch->D_CONST;
+                       p->as = AFUNCDATA;
+                       p->from.type = TYPE_CONST;
                        p->from.offset = FUNCDATA_ArgsPointerMaps;
-                       if(ctxt->arch->thechar == '6' || ctxt->arch->thechar == '8')
-                               p->to.type = ctxt->arch->D_EXTERN;
-                       else {
-                               p->to.type = ctxt->arch->D_OREG;
-                               p->to.name = ctxt->arch->D_EXTERN;
-                       }
+                       p->to.type = TYPE_MEM;
+                       p->to.name = NAME_EXTERN;
                        p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", s->name), s->version);
                }
        }
@@ -326,7 +322,7 @@ writeobjdirect(Link *ctxt, Biobuf *b)
                mkfwd(s);
                linkpatch(ctxt, s);
                ctxt->arch->follow(ctxt, s);
-               ctxt->arch->addstacksplit(ctxt, s);
+               ctxt->arch->preprocess(ctxt, s);
                ctxt->arch->assemble(ctxt, s);
                linkpcln(ctxt, s);
        }
@@ -448,12 +444,12 @@ writesym(Link *ctxt, Biobuf *b, LSym *s)
                for(a = s->autom; a != nil; a = a->link) {
                        wrsym(b, a->asym);
                        wrint(b, a->aoffset);
-                       if(a->type == ctxt->arch->D_AUTO)
+                       if(a->name == NAME_AUTO)
                                wrint(b, A_AUTO);
-                       else if(a->type == ctxt->arch->D_PARAM)
+                       else if(a->name == NAME_PARAM)
                                wrint(b, A_PARAM);
                        else
-                               sysfatal("%s: invalid local variable type %d", s->name, a->type);
+                               sysfatal("%s: invalid local variable type %d", s->name, a->name);
                        wrsym(b, a->gotype);
                }
 
@@ -690,7 +686,7 @@ overwrite:
                        a = emallocz(sizeof *a);
                        a->asym = rdsym(ctxt, f, pkg);
                        a->aoffset = rdint(f);
-                       a->type = rdint(f);
+                       a->name = rdint(f);
                        a->gotype = rdsym(ctxt, f, pkg);
                        a->link = s->autom;
                        s->autom = a;
index 0dd1a6ef0940b36f5699f2f92b81a19100776282..406019312d0ffd7fc5872a63eff27837d3f2c61c 100644 (file)
@@ -274,9 +274,9 @@ printprog(Link *ctxt, Biobuf *bw, Prog *p0)
        
        q = p;
        for(p=p0; p!=q; p=p->link) {
-               if(p->from.type == ctxt->arch->D_BRANCH)
+               if(p->from.type == TYPE_BRANCH)
                        printprog(ctxt, bw, p->from.u.branch);
-               if(p->to.type == ctxt->arch->D_BRANCH)
+               if(p->to.type == TYPE_BRANCH)
                        printprog(ctxt, bw, p->to.u.branch);
        }
 }
@@ -288,7 +288,7 @@ printaddr(Link *ctxt, Biobuf *bw, Addr *a)
 
        printtype(ctxt, bw, TypeAddr);
        printint(ctxt, bw, a->offset);
-       if(a->type == ctxt->arch->D_FCONST) {
+       if(a->type == TYPE_FCONST) {
                uint64 u;
                float64 f;
                f = a->u.dval;
@@ -296,11 +296,11 @@ printaddr(Link *ctxt, Biobuf *bw, Addr *a)
                printint(ctxt, bw, u);
        } else
                printint(ctxt, bw, 0);
-       if(a->type == ctxt->arch->D_SCONST)
+       if(a->type == TYPE_SCONST)
                Bwrite(bw, a->u.sval, 8);
        else
                Bwrite(bw, zero, 8);
-       if(a->type == ctxt->arch->D_BRANCH)
+       if(a->type == TYPE_BRANCH)
                printptr(ctxt, bw, a->u.branch);
        else    
                printptr(ctxt, bw, nil);
@@ -313,7 +313,10 @@ printaddr(Link *ctxt, Biobuf *bw, Addr *a)
        printint(ctxt, bw, a->name);
        printint(ctxt, bw, a->class);
        printint(ctxt, bw, a->etype);
-       printint(ctxt, bw, a->offset2);
+       if(a->type == TYPE_TEXTSIZE)
+               printint(ctxt, bw, a->u.argsize);
+       else
+               printint(ctxt, bw, 0);
        printint(ctxt, bw, a->width);
 }
 
index 6d4db2757a48d76b242e635ad5e82858eb61c96b..db5c4ebd1381193488876e271f9aa84d2966a21a 100644 (file)
@@ -40,8 +40,9 @@ brchain(Link *ctxt, Prog *p)
 {
        int i;
 
+       USED(ctxt);
        for(i=0; i<20; i++) {
-               if(p == nil || p->as != ctxt->arch->AJMP || p->pcond == nil)
+               if(p == nil || p->as != AJMP || p->pcond == nil)
                        return p;
                p = p->pcond;
        }
@@ -54,9 +55,10 @@ brloop(Link *ctxt, Prog *p)
        int c;
        Prog *q;
 
+       USED(ctxt);
        c = 0;
        for(q = p; q != nil; q = q->pcond) {
-               if(q->as != ctxt->arch->AJMP || q->pcond == nil)
+               if(q->as != AJMP || q->pcond == nil)
                        break;
                c++;
                if(c >= 5000)
@@ -65,6 +67,83 @@ brloop(Link *ctxt, Prog *p)
        return q;
 }
 
+static void
+checkaddr(Link *ctxt, Prog *p, Addr *a)
+{
+       // Check expected encoding, especially TYPE_CONST vs TYPE_ADDR.
+       switch(a->type) {
+       case TYPE_NONE:
+               return;
+
+       case TYPE_BRANCH:
+               if(a->reg != 0 || a->index != 0 || a->scale != 0 || a->name != 0)
+                       break;
+               return;
+
+       case TYPE_TEXTSIZE:
+               if(a->reg != 0 || a->index != 0 || a->scale != 0 || a->name != 0)
+                       break;
+               return;
+
+       case TYPE_MEM:
+               //if(a->u.bits != 0)
+               //      break;
+               return;
+
+       case TYPE_CONST:
+               // TODO(rsc): After fixing SHRQ, check a->index != 0 too.
+               if(a->name != 0 || a->sym != 0 || a->reg != 0) {
+                       ctxt->diag("argument %D is TYPE_CONST, should be TYPE_ADDR, in %P", a, p);
+                       return;
+               }
+               if(a->reg != 0 || a->scale != 0 || a->name != 0 || a->sym != nil || a->u.bits != 0)
+                       break;
+               return;
+
+       case TYPE_FCONST:
+       case TYPE_SCONST:
+               if(a->reg != 0 || a->index != 0 || a->scale != 0 || a->name != 0 || a->offset != 0 || a->sym != nil)
+                       break;
+               return;
+
+       case TYPE_REG:
+               // TODO(rsc): After fixing PINSRQ, check a->offset != 0 too.
+               // TODO(rsc): After fixing SHRQ, check a->index != 0 too.
+               if(a->scale != 0 || a->name != 0 || a->sym != nil)
+                       break;
+               return;
+
+       case TYPE_ADDR:
+               if(a->u.bits != 0)
+                       break;
+               if(a->reg == 0 && a->index == 0 && a->scale == 0 && a->name == 0 && a->sym == nil)
+                       ctxt->diag("argument %D is TYPE_ADDR, should be TYPE_CONST, in %P", a, p);
+               return;
+
+       case TYPE_SHIFT:
+               if(a->index != 0 || a->scale != 0 || a->name != 0 || a->sym != nil || a->u.bits != 0)
+                       break;
+               return;
+
+       case TYPE_REGREG:
+               if(a->index != 0 || a->scale != 0 || a->name != 0 || a->sym != nil || a->u.bits != 0)
+                       break;
+               return;
+
+       case TYPE_REGREG2:
+               return;
+
+       case TYPE_INDIR:
+               // Expect sym and name to be set, nothing else.
+               // Technically more is allowed, but this is only used for *name(SB).
+               if(a->reg != 0 || a->index != 0 || a->scale != 0 || a->name == 0 || a->offset != 0 || a->sym == nil || a->u.bits != 0)
+                       break;
+               return;
+       }
+
+       ctxt->diag("invalid encoding for argument %D in %P", a, p);
+}
+
 void
 linkpatch(Link *ctxt, LSym *sym)
 {
@@ -75,9 +154,13 @@ linkpatch(Link *ctxt, LSym *sym)
        ctxt->cursym = sym;
        
        for(p = sym->text; p != nil; p = p->link) {
+               checkaddr(ctxt, p, &p->from);
+               checkaddr(ctxt, p, &p->from3);
+               checkaddr(ctxt, p, &p->to);
+
                if(ctxt->arch->progedit)
                        ctxt->arch->progedit(ctxt, p);
-               if(p->to.type != ctxt->arch->D_BRANCH)
+               if(p->to.type != TYPE_BRANCH)
                        continue;
                if(p->to.u.branch != nil) {
                        // TODO: Remove to.u.branch in favor of p->pcond.
@@ -100,7 +183,7 @@ linkpatch(Link *ctxt, LSym *sym)
                        if(p->to.sym)
                                name = p->to.sym->name;
                        ctxt->diag("branch out of range (%#ux)\n%P [%s]", c, p, name);
-                       p->to.type = ctxt->arch->D_NONE;
+                       p->to.type = TYPE_NONE;
                }
                p->to.u.branch = q;
                p->pcond = q;
@@ -111,7 +194,7 @@ linkpatch(Link *ctxt, LSym *sym)
                if(p->pcond != nil) {
                        p->pcond = brloop(ctxt, p->pcond);
                        if(p->pcond != nil)
-                       if(p->to.type == ctxt->arch->D_BRANCH)
+                       if(p->to.type == TYPE_BRANCH)
                                p->to.offset = p->pcond->pc;
                }
        }
index f0ee1dc6726c9cdc5adcdd1a61b039c667576b44..93e4127a1e5f21929cfec3d3d7a0b744fc20d348 100644 (file)
@@ -160,7 +160,7 @@ pctofileline(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *ar
 
        USED(sym);
 
-       if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1)
+       if(p->as == ATEXT || p->as == ANOP || p->as == AUSEFIELD || p->lineno == 0 || phase == 1)
                return oldval;
        linkgetline(ctxt, p->lineno, &f, &l);
        if(f == nil) {
@@ -223,7 +223,7 @@ pctopcdata(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
 {
        USED(sym);
 
-       if(phase == 0 || p->as != ctxt->arch->APCDATA || p->from.offset != (uintptr)arg)
+       if(phase == 0 || p->as != APCDATA || p->from.offset != (uintptr)arg)
                return oldval;
        if((int32)p->to.offset != p->to.offset) {
                ctxt->diag("overflow in PCDATA instruction: %P", p);
@@ -248,9 +248,9 @@ linkpcln(Link *ctxt, LSym *cursym)
        npcdata = 0;
        nfuncdata = 0;
        for(p = cursym->text; p != nil; p = p->link) {
-               if(p->as == ctxt->arch->APCDATA && p->from.offset >= npcdata)
+               if(p->as == APCDATA && p->from.offset >= npcdata)
                        npcdata = p->from.offset+1;
-               if(p->as == ctxt->arch->AFUNCDATA && p->from.offset >= nfuncdata)
+               if(p->as == AFUNCDATA && p->from.offset >= nfuncdata)
                        nfuncdata = p->from.offset+1;
        }
 
@@ -269,12 +269,12 @@ linkpcln(Link *ctxt, LSym *cursym)
        havepc = emallocz(n);
        havefunc = havepc + (npcdata+31)/32;
        for(p = cursym->text; p != nil; p = p->link) {
-               if(p->as == ctxt->arch->AFUNCDATA) {
+               if(p->as == AFUNCDATA) {
                        if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
                                ctxt->diag("multiple definitions for FUNCDATA $%d", p->from.offset);
                        havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
                }
-               if(p->as == ctxt->arch->APCDATA)
+               if(p->as == APCDATA)
                        havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
        }
        // pcdata.
@@ -288,10 +288,10 @@ linkpcln(Link *ctxt, LSym *cursym)
        // funcdata
        if(nfuncdata > 0) {
                for(p = cursym->text; p != nil; p = p->link) {
-                       if(p->as == ctxt->arch->AFUNCDATA) {
+                       if(p->as == AFUNCDATA) {
                                i = p->from.offset;
                                pcln->funcdataoff[i] = p->to.offset;
-                               if(p->to.type != ctxt->arch->D_CONST) {
+                               if(p->to.type != TYPE_CONST) {
                                        // TODO: Dedup.
                                        //funcdata_bytes += p->to.sym->size;
                                        pcln->funcdata[i] = p->to.sym;
index e06837118a30ce3d2a55369783fae391cd4cb495..079f600aa9f48d57647747562fd1d5055d966fd7 100644 (file)
@@ -44,12 +44,12 @@ static struct {
        char *name;
        int val;
 } headers[] = {
-       {"android",     Hlinux},
        {"darwin",      Hdarwin},
        {"dragonfly",   Hdragonfly},
        {"elf",         Helf},
        {"freebsd",     Hfreebsd},
        {"linux",       Hlinux},
+       {"android",     Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
        {"nacl",                Hnacl},
        {"netbsd",      Hnetbsd},
        {"openbsd",     Hopenbsd},
@@ -90,6 +90,7 @@ linknew(LinkArch *arch)
        char *p;
        char buf[1024];
 
+       linksetexp();
        nuxiinit(arch);
        
        ctxt = emallocz(sizeof *ctxt);
index 0ef05d8f94bf5ec30db26941404d61c579192ba5..17646a12fa8872877e5c282ace6c1d01c981fc42 100644 (file)
@@ -60,6 +60,13 @@ func New(out io.Writer, prefix string, flag int) *Logger {
        return &Logger{out: out, prefix: prefix, flag: flag}
 }
 
+// SetOutput sets the output destination for the logger.
+func (l *Logger) SetOutput(w io.Writer) {
+       l.mu.Lock()
+       defer l.mu.Unlock()
+       l.out = w
+}
+
 var std = New(os.Stderr, "", LstdFlags)
 
 // Cheap integer to fixed-width decimal ASCII.  Give a negative width to avoid zero-padding.
index e6c3fd02d0f1dc197de7749a907b9f7adb744b59..215fedd6eefaf45a5512f29830d2373eda89e924 100755 (executable)
@@ -25,9 +25,6 @@
 # GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
 # building the commands.
 #
-# GO_CCFLAGS: Additional 5c/6c/8c arguments to use when
-# building.
-#
 # CGO_ENABLED: Controls cgo usage during the build. Set it to 1
 # to include all cgo related files, .c and .go file with "cgo"
 # build directive, in the build. Set it to 0 to ignore them.
@@ -156,12 +153,12 @@ if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
        # CC_FOR_TARGET is recorded as the default compiler for the go tool. When building for the host, however,
        # use the host compiler, CC, from `cmd/dist/dist env` instead.
        CC=$CC GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
-               "$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
+               "$GOTOOLDIR"/go_bootstrap install -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
        echo
 fi
 
 echo "##### Building packages and commands for $GOOS/$GOARCH."
-CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
+CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
 echo
 
 rm -f "$GOTOOLDIR"/go_bootstrap
index 593ebc8f2fe55b424a92c0a9ac65187620fb3726..f4302739f7e5ae14d8ac0d7d482ac6cc52dd8670 100755 (executable)
@@ -25,9 +25,6 @@
 # GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
 # building the commands.
 #
-# GO_CCFLAGS: Additional 5c/6c/8c arguments to use when
-# building.
-#
 # CGO_ENABLED: Controls cgo usage during the build. Set it to 1
 # to include all cgo related files, .c and .go file with "cgo"
 # build directive, in the build. Set it to 0 to ignore them.
@@ -87,12 +84,12 @@ if(~ $sysname vx32)
 if(! ~ $GOHOSTARCH $GOARCH || ! ~ $GOHOSTOS $GOOS){
        echo '# Building packages and commands for host,' $GOHOSTOS/$GOHOSTARCH^.
        GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
-               $GOTOOLDIR/go_bootstrap install -ccflags $"GO_CCFLAGS -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std
+               $GOTOOLDIR/go_bootstrap install -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std
        echo
 }
 
 echo '# Building packages and commands for' $GOOS/$GOARCH^.
-$GOTOOLDIR/go_bootstrap install -ccflags $"GO_CCFLAGS -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std
+$GOTOOLDIR/go_bootstrap install -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std
 echo
 
 rm -f $GOTOOLDIR/go_bootstrap
diff --git a/src/math/big/decimal.go b/src/math/big/decimal.go
new file mode 100644 (file)
index 0000000..670668b
--- /dev/null
@@ -0,0 +1,255 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements multi-precision decimal numbers.
+// The implementation is for float to decimal conversion only;
+// not general purpose use.
+// The only operations are precise conversion from binary to
+// decimal and rounding.
+//
+// The key observation and some code (shr) is borrowed from
+// strconv/decimal.go: conversion of binary fractional values can be done
+// precisely in multi-precision decimal because 2 divides 10 (required for
+// >> of mantissa); but conversion of decimal floating-point values cannot
+// be done precisely in binary representation.
+//
+// In contrast to strconv/decimal.go, only right shift is implemented in
+// decimal format - left shift can be done precisely in binary format.
+
+package big
+
+// A decimal represents a floating-point number in decimal representation.
+// The value of a decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1,
+// with the most-significant mantissa digit at index 0.
+type decimal struct {
+       mant []byte // mantissa ASCII digits, big-endian
+       exp  int    // exponent, valid if len(mant) > 0
+}
+
+// Maximum shift amount that can be done in one pass without overflow.
+// A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
+const maxShift = _W - 4
+
+// TODO(gri) Since we know the desired decimal precision when converting
+// a floating-point number, we may be able to limit the number of decimal
+// digits that need to be computed by init by providing an additional
+// precision argument and keeping track of when a number was truncated early
+// (equivalent of "sticky bit" in binary rounding).
+
+// Init initializes x to the decimal representation of m << shift (for
+// shift >= 0), or m >> -shift (for shift < 0).
+func (x *decimal) init(m nat, shift int) {
+       // special case 0
+       if len(m) == 0 {
+               x.mant = x.mant[:0]
+               return
+       }
+
+       // Optimization: If we need to shift right, first remove any trailing
+       // zero bits from m to reduce shift amount that needs to be done in
+       // decimal format (since that is likely slower).
+       if shift < 0 {
+               ntz := m.trailingZeroBits()
+               s := uint(-shift)
+               if s >= ntz {
+                       s = ntz // shift at most ntz bits
+               }
+               m = nat(nil).shr(m, s)
+               shift += int(s)
+       }
+
+       // Do any shift left in binary representation.
+       if shift > 0 {
+               m = nat(nil).shl(m, uint(shift))
+               shift = 0
+       }
+
+       // Convert mantissa into decimal representation.
+       s := m.decimalString() // TODO(gri) avoid string conversion here
+       n := len(s)
+       x.exp = n
+       // Trim trailing zeros; instead the exponent is tracking
+       // the decimal point independent of the number of digits.
+       for n > 0 && s[n-1] == '0' {
+               n--
+       }
+       x.mant = append(x.mant[:0], s[:n]...)
+
+       // Do any (remaining) shift right in decimal representation.
+       if shift < 0 {
+               for shift < -maxShift {
+                       shr(x, maxShift)
+                       shift += maxShift
+               }
+               shr(x, uint(-shift))
+       }
+}
+
+// Possibly optimization: The current implementation of nat.string takes
+// a charset argument. When a right shift is needed, we could provide
+// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and
+// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a
+// single +'0' pass at the end).
+
+// shr implements x >> s, for s <= maxShift.
+func shr(x *decimal, s uint) {
+       // Division by 1<<s using shift-and-subtract algorithm.
+
+       // pick up enough leading digits to cover first shift
+       r := 0 // read index
+       var n Word
+       for n>>s == 0 && r < len(x.mant) {
+               ch := Word(x.mant[r])
+               r++
+               n = n*10 + ch - '0'
+       }
+       if n == 0 {
+               // x == 0; shouldn't get here, but handle anyway
+               x.mant = x.mant[:0]
+               return
+       }
+       for n>>s == 0 {
+               r++
+               n *= 10
+       }
+       x.exp += 1 - r
+
+       // read a digit, write a digit
+       w := 0 // write index
+       for r < len(x.mant) {
+               ch := Word(x.mant[r])
+               r++
+               d := n >> s
+               n -= d << s
+               x.mant[w] = byte(d + '0')
+               w++
+               n = n*10 + ch - '0'
+       }
+
+       // write extra digits that still fit
+       for n > 0 && w < len(x.mant) {
+               d := n >> s
+               n -= d << s
+               x.mant[w] = byte(d + '0')
+               w++
+               n = n * 10
+       }
+       x.mant = x.mant[:w] // the number may be shorter (e.g. 1024 >> 10)
+
+       // append additional digits that didn't fit
+       for n > 0 {
+               d := n >> s
+               n -= d << s
+               x.mant = append(x.mant, byte(d+'0'))
+               n = n * 10
+       }
+
+       trim(x)
+}
+
+func (x *decimal) String() string {
+       if len(x.mant) == 0 {
+               return "0"
+       }
+
+       var buf []byte
+       switch {
+       case x.exp <= 0:
+               // 0.00ddd
+               buf = append(buf, "0."...)
+               buf = appendZeros(buf, -x.exp)
+               buf = append(buf, x.mant...)
+
+       case /* 0 < */ x.exp < len(x.mant):
+               // dd.ddd
+               buf = append(buf, x.mant[:x.exp]...)
+               buf = append(buf, '.')
+               buf = append(buf, x.mant[x.exp:]...)
+
+       default: // len(x.mant) <= x.exp
+               // ddd00
+               buf = append(buf, x.mant...)
+               buf = appendZeros(buf, x.exp-len(x.mant))
+       }
+
+       return string(buf)
+}
+
+// appendZeros appends n 0 digits to buf and returns buf.
+func appendZeros(buf []byte, n int) []byte {
+       for ; n > 0; n-- {
+               buf = append(buf, '0')
+       }
+       return buf
+}
+
+// shouldRoundUp reports if x should be rounded up
+// if shortened to n digits. n must be a valid index
+// for x.mant.
+func shouldRoundUp(x *decimal, n int) bool {
+       if x.mant[n] == '5' && n+1 == len(x.mant) {
+               // exactly halfway - round to even
+               return n > 0 && (x.mant[n-1]-'0')&1 != 0
+       }
+       // not halfway - digit tells all (x.mant has no trailing zeros)
+       return x.mant[n] >= '5'
+}
+
+// round sets x to (at most) n mantissa digits by rounding it
+// to the nearest even value with n (or fever) mantissa digits.
+// If n < 0, x remains unchanged.
+func (x *decimal) round(n int) {
+       if n < 0 || n >= len(x.mant) {
+               return // nothing to do
+       }
+
+       if shouldRoundUp(x, n) {
+               x.roundUp(n)
+       } else {
+               x.roundDown(n)
+       }
+}
+
+func (x *decimal) roundUp(n int) {
+       if n < 0 || n >= len(x.mant) {
+               return // nothing to do
+       }
+       // 0 <= n < len(x.mant)
+
+       // find first digit < '9'
+       for n > 0 && x.mant[n-1] >= '9' {
+               n--
+       }
+
+       if n == 0 {
+               // all digits are '9's => round up to '1' and update exponent
+               x.mant[0] = '1' // ok since len(x.mant) > n
+               x.mant = x.mant[:1]
+               x.exp++
+               return
+       }
+
+       // n > 0 && x.mant[n-1] < '9'
+       x.mant[n-1]++
+       x.mant = x.mant[:n]
+       // x already trimmed
+}
+
+func (x *decimal) roundDown(n int) {
+       if n < 0 || n >= len(x.mant) {
+               return // nothing to do
+       }
+       x.mant = x.mant[:n]
+       trim(x)
+}
+
+// trim cuts off any trailing zeros from x's mantissa;
+// they are meaningless for the value of x.
+func trim(x *decimal) {
+       i := len(x.mant)
+       for i > 0 && x.mant[i-1] == '0' {
+               i--
+       }
+       x.mant = x.mant[:i]
+}
diff --git a/src/math/big/decimal_test.go b/src/math/big/decimal_test.go
new file mode 100644 (file)
index 0000000..81e022a
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import "testing"
+
+func TestDecimalString(t *testing.T) {
+       for _, test := range []struct {
+               x    decimal
+               want string
+       }{
+               {want: "0"},
+               {decimal{nil, 1000}, "0"}, // exponent of 0 is ignored
+               {decimal{[]byte("12345"), 0}, "0.12345"},
+               {decimal{[]byte("12345"), -3}, "0.00012345"},
+               {decimal{[]byte("12345"), +3}, "123.45"},
+               {decimal{[]byte("12345"), +10}, "1234500000"},
+       } {
+               if got := test.x.String(); got != test.want {
+                       t.Errorf("%v == %s; want %s", test.x, got, test.want)
+               }
+       }
+}
+
+func TestDecimalInit(t *testing.T) {
+       for _, test := range []struct {
+               x     Word
+               shift int
+               want  string
+       }{
+               {0, 0, "0"},
+               {0, -100, "0"},
+               {0, 100, "0"},
+               {1, 0, "1"},
+               {1, 10, "1024"},
+               {1, 100, "1267650600228229401496703205376"},
+               {1, -100, "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625"},
+               {12345678, 8, "3160493568"},
+               {12345678, -8, "48225.3046875"},
+               {195312, 9, "99999744"},
+               {1953125, 9, "1000000000"},
+       } {
+               var d decimal
+               d.init(nat{test.x}.norm(), test.shift)
+               if got := d.String(); got != test.want {
+                       t.Errorf("%d << %d == %s; want %s", test.x, test.shift, got, test.want)
+               }
+       }
+}
+
+func TestDecimalRounding(t *testing.T) {
+       for _, test := range []struct {
+               x              uint64
+               n              int
+               down, even, up string
+       }{
+               {0, 0, "0", "0", "0"},
+               {0, 1, "0", "0", "0"},
+
+               {1, 0, "0", "0", "10"},
+               {5, 0, "0", "0", "10"},
+               {9, 0, "0", "10", "10"},
+
+               {15, 1, "10", "20", "20"},
+               {45, 1, "40", "40", "50"},
+               {95, 1, "90", "100", "100"},
+
+               {12344999, 4, "12340000", "12340000", "12350000"},
+               {12345000, 4, "12340000", "12340000", "12350000"},
+               {12345001, 4, "12340000", "12350000", "12350000"},
+               {23454999, 4, "23450000", "23450000", "23460000"},
+               {23455000, 4, "23450000", "23460000", "23460000"},
+               {23455001, 4, "23450000", "23460000", "23460000"},
+
+               {99994999, 4, "99990000", "99990000", "100000000"},
+               {99995000, 4, "99990000", "100000000", "100000000"},
+               {99999999, 4, "99990000", "100000000", "100000000"},
+
+               {12994999, 4, "12990000", "12990000", "13000000"},
+               {12995000, 4, "12990000", "13000000", "13000000"},
+               {12999999, 4, "12990000", "13000000", "13000000"},
+       } {
+               x := nat(nil).setUint64(test.x)
+
+               var d decimal
+               d.init(x, 0)
+               d.roundDown(test.n)
+               if got := d.String(); got != test.down {
+                       t.Errorf("roundDown(%d, %d) = %s; want %s", test.x, test.n, got, test.down)
+               }
+
+               d.init(x, 0)
+               d.round(test.n)
+               if got := d.String(); got != test.even {
+                       t.Errorf("round(%d, %d) = %s; want %s", test.x, test.n, got, test.even)
+               }
+
+               d.init(x, 0)
+               d.roundUp(test.n)
+               if got := d.String(); got != test.up {
+                       t.Errorf("roundUp(%d, %d) = %s; want %s", test.x, test.n, got, test.up)
+               }
+       }
+}
diff --git a/src/math/big/float.go b/src/math/big/float.go
new file mode 100644 (file)
index 0000000..ea42a91
--- /dev/null
@@ -0,0 +1,957 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements multi-precision floating-point numbers.
+// Like in the GNU MPFR library (http://www.mpfr.org/), operands
+// can be of mixed precision. Unlike MPFR, the rounding mode is
+// not specified with each operation, but with each operand. The
+// rounding mode of the result operand determines the rounding
+// mode of an operation. This is a from-scratch implementation.
+
+// CAUTION: WORK IN PROGRESS - ANY ASPECT OF THIS IMPLEMENTATION MAY CHANGE!
+
+package big
+
+import (
+       "fmt"
+       "math"
+)
+
+// TODO(gri): Determine if there's a more natural way to set the precision.
+// Should there be a special meaning for prec 0? Such as "full precision"?
+// (would be possible for all ops except quotient).
+
+const debugFloat = true // enable for debugging
+
+// Internal representation: A floating-point value x != 0 consists
+// of a sign (x.neg), mantissa (x.mant), and exponent (x.exp) such
+// that
+//
+//   x = sign * 0.mantissa * 2**exponent
+//
+// and the mantissa is interpreted as a value between 0.5 and 1:
+//
+//  0.5 <= mantissa < 1.0
+//
+// The mantissa bits are stored in the shortest nat slice long enough
+// to hold x.prec mantissa bits. The mantissa is normalized such that
+// the msb of x.mant == 1. Thus, if the precision is not a multiple of
+// the Word size _W, x.mant[0] contains trailing zero bits. The number
+// 0 is represented by an empty mantissa and a zero exponent.
+
+// A Float represents a multi-precision floating point number
+// of the form
+//
+//   sign * mantissa * 2**exponent
+//
+// Each value also has a precision, rounding mode, and accuracy value:
+// The precision is the number of mantissa bits used to represent a
+// value, and the result of operations is rounded to that many bits
+// according to the value's rounding mode (unless specified othewise).
+// The accuracy value indicates the rounding error with respect to the
+// exact (not rounded) value.
+//
+// The zero value for a Float represents the number 0.
+//
+// By setting the desired precision to 24 (or 53) and using ToNearestEven
+// rounding, Float arithmetic operations emulate the corresponding float32
+// or float64 IEEE-754 operations (except for denormalized numbers and NaNs).
+//
+// CAUTION: THIS IS WORK IN PROGRESS - USE AT YOUR OWN RISK.
+//
+type Float struct {
+       mode RoundingMode
+       acc  Accuracy
+       neg  bool
+       mant nat
+       exp  int32
+       prec uint // TODO(gri) make this a 32bit field
+}
+
+// NewFloat returns a new Float with value x rounded
+// to prec bits according to the given rounding mode.
+func NewFloat(x float64, prec uint, mode RoundingMode) *Float {
+       // TODO(gri) should make this more efficient
+       z := new(Float).SetFloat64(x)
+       return z.Round(z, prec, mode)
+}
+
+// infExp is the exponent value for infinity.
+const infExp = 1<<31 - 1
+
+// NewInf returns a new Float with value positive infinity (sign >= 0),
+// or negative infinity (sign < 0).
+func NewInf(sign int) *Float {
+       return &Float{neg: sign < 0, exp: infExp}
+}
+
+func (z *Float) setExp(e int64) {
+       e32 := int32(e)
+       if int64(e32) != e {
+               panic("exponent overflow") // TODO(gri) handle this gracefully
+       }
+       z.exp = e32
+}
+
+// Accuracy describes the rounding error produced by the most recent
+// operation that generated a Float value, relative to the exact value:
+//
+//  -1: below exact value
+//   0: exact value
+//  +1: above exact value
+//
+type Accuracy int8
+
+// Constants describing the Accuracy of a Float.
+const (
+       Below Accuracy = -1
+       Exact Accuracy = 0
+       Above Accuracy = +1
+)
+
+func (a Accuracy) String() string {
+       switch {
+       case a < 0:
+               return "below"
+       default:
+               return "exact"
+       case a > 0:
+               return "above"
+       }
+}
+
+// RoundingMode determines how a Float value is rounded to the
+// desired precision. Rounding may change the Float value; the
+// rounding error is described by the Float's Accuracy.
+type RoundingMode uint8
+
+// The following rounding modes are supported.
+const (
+       ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven
+       ToNearestAway                     // == IEEE 754-2008 roundTiesToAway
+       ToZero                            // == IEEE 754-2008 roundTowardZero
+       AwayFromZero                      // no IEEE 754-2008 equivalent
+       ToNegativeInf                     // == IEEE 754-2008 roundTowardNegative
+       ToPositiveInf                     // == IEEE 754-2008 roundTowardPositive
+)
+
+func (mode RoundingMode) String() string {
+       switch mode {
+       case ToNearestEven:
+               return "ToNearestEven"
+       case ToNearestAway:
+               return "ToNearestAway"
+       case ToZero:
+               return "ToZero"
+       case AwayFromZero:
+               return "AwayFromZero"
+       case ToNegativeInf:
+               return "ToNegativeInf"
+       case ToPositiveInf:
+               return "ToPositiveInf"
+       }
+       panic("unreachable")
+}
+
+// Precision returns the mantissa precision of x in bits.
+// The precision may be 0 if x == 0. // TODO(gri) Determine a better approach.
+func (x *Float) Precision() uint {
+       return uint(x.prec)
+}
+
+// Accuracy returns the accuracy of x produced by the most recent operation.
+func (x *Float) Accuracy() Accuracy {
+       return x.acc
+}
+
+// Mode returns the rounding mode of x.
+func (x *Float) Mode() RoundingMode {
+       return x.mode
+}
+
+// debugging support
+func (x *Float) validate() {
+       // assumes x != 0
+       const msb = 1 << (_W - 1)
+       m := len(x.mant)
+       if x.mant[m-1]&msb == 0 {
+               panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Format('p', 0)))
+       }
+       if x.prec <= 0 {
+               panic(fmt.Sprintf("invalid precision %d", x.prec))
+       }
+}
+
+// round rounds z according to z.mode to z.prec bits and sets z.acc accordingly.
+// sbit must be 0 or 1 and summarizes any "sticky bit" information one might
+// have before calling round. z's mantissa must be normalized, with the msb set.
+func (z *Float) round(sbit uint) {
+       z.acc = Exact
+
+       // handle zero
+       m := uint(len(z.mant)) // mantissa length in words for current precision
+       if m == 0 {
+               z.exp = 0
+               return
+       }
+
+       if debugFloat {
+               z.validate()
+       }
+       // z.prec > 0
+
+       bits := m * _W // available mantissa bits
+       if bits == z.prec {
+               // mantissa fits Exactly => nothing to do
+               return
+       }
+
+       n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision
+       if bits < z.prec {
+               // mantissa too small => extend
+               if m < n {
+                       // slice too short => extend slice
+                       if int(n) <= cap(z.mant) {
+                               // reuse existing slice
+                               z.mant = z.mant[:n]
+                               copy(z.mant[n-m:], z.mant[:m])
+                               z.mant[:n-m].clear()
+                       } else {
+                               // n > cap(z.mant) => allocate new slice
+                               const e = 4 // extra capacity (see nat.make)
+                               new := make(nat, n, n+e)
+                               copy(new[n-m:], z.mant)
+                       }
+               }
+               return
+       }
+
+       // Rounding is based on two bits: the rounding bit (rbit) and the
+       // sticky bit (sbit). The rbit is the bit immediately before the
+       // mantissa bits (the "0.5"). The sbit is set if any of the bits
+       // before the rbit are set (the "0.25", "0.125", etc.):
+       //
+       //   rbit  sbit  => "fractional part"
+       //
+       //   0     0        == 0
+       //   0     1        >  0  , < 0.5
+       //   1     0        == 0.5
+       //   1     1        >  0.5, < 1.0
+
+       // bits > z.prec: mantissa too large => round
+       r := bits - z.prec - 1 // rounding bit position; r >= 0
+       rbit := z.mant.bit(r)  // rounding bit
+       if sbit == 0 {
+               sbit = z.mant.sticky(r)
+       }
+       if debugFloat && sbit&^1 != 0 {
+               panic(fmt.Sprintf("invalid sbit %#x", sbit))
+       }
+
+       // convert ToXInf rounding modes
+       mode := z.mode
+       switch mode {
+       case ToNegativeInf:
+               mode = ToZero
+               if z.neg {
+                       mode = AwayFromZero
+               }
+       case ToPositiveInf:
+               mode = AwayFromZero
+               if z.neg {
+                       mode = ToZero
+               }
+       }
+
+       // cut off extra words
+       if m > n {
+               copy(z.mant, z.mant[m-n:]) // move n last words to front
+               z.mant = z.mant[:n]
+       }
+
+       // determine number of trailing zero bits t
+       t := n*_W - z.prec // 0 <= t < _W
+       lsb := Word(1) << t
+
+       // make rounding decision
+       // TODO(gri) This can be simplified (see roundBits in float_test.go).
+       switch mode {
+       case ToZero:
+               // nothing to do
+       case ToNearestEven, ToNearestAway:
+               if rbit == 0 {
+                       // rounding bits == 0b0x
+                       mode = ToZero
+               } else if sbit == 1 {
+                       // rounding bits == 0b11
+                       mode = AwayFromZero
+               }
+       case AwayFromZero:
+               if rbit|sbit == 0 {
+                       mode = ToZero
+               }
+       default:
+               // ToXInf modes have been converted to ToZero or AwayFromZero
+               panic("unreachable")
+       }
+
+       // round and determine accuracy
+       switch mode {
+       case ToZero:
+               if rbit|sbit != 0 {
+                       z.acc = Below
+               }
+
+       case ToNearestEven, ToNearestAway:
+               if debugFloat && rbit != 1 {
+                       panic("internal error in rounding")
+               }
+               if mode == ToNearestEven && sbit == 0 && z.mant[0]&lsb == 0 {
+                       z.acc = Below
+                       break
+               }
+               // mode == ToNearestAway || sbit == 1 || z.mant[0]&lsb != 0
+               fallthrough
+
+       case AwayFromZero:
+               // add 1 to mantissa
+               if addVW(z.mant, z.mant, lsb) != 0 {
+                       // overflow => shift mantissa right by 1 and add msb
+                       shrVU(z.mant, z.mant, 1)
+                       z.mant[n-1] |= 1 << (_W - 1)
+                       // adjust exponent
+                       z.exp++
+               }
+               z.acc = Above
+       }
+
+       // zero out trailing bits in least-significant word
+       z.mant[0] &^= lsb - 1
+
+       // update accuracy
+       if z.neg {
+               z.acc = -z.acc
+       }
+
+       if debugFloat {
+               z.validate()
+       }
+
+       return
+}
+
+// Round sets z to the value of x rounded according to mode to prec bits and returns z.
+func (z *Float) Round(x *Float, prec uint, mode RoundingMode) *Float {
+       z.Set(x)
+       z.prec = prec
+       z.mode = mode
+       z.round(0)
+       return z
+}
+
+// nlz returns the number of leading zero bits in x.
+func nlz(x Word) uint {
+       return _W - uint(bitLen(x))
+}
+
+func nlz64(x uint64) uint {
+       // TODO(gri) this can be done more nicely
+       if _W == 32 {
+               if x>>32 == 0 {
+                       return 32 + nlz(Word(x))
+               }
+               return nlz(Word(x >> 32))
+       }
+       if _W == 64 {
+               return nlz(Word(x))
+       }
+       panic("unreachable")
+}
+
+// SetUint64 sets z to x and returns z.
+// Precision is set to 64 bits.
+func (z *Float) SetUint64(x uint64) *Float {
+       z.neg = false
+       z.prec = 64
+       if x == 0 {
+               z.mant = z.mant[:0]
+               z.exp = 0
+               return z
+       }
+       s := nlz64(x)
+       z.mant = z.mant.setUint64(x << s)
+       z.exp = int32(64 - s)
+       return z
+}
+
+// SetInt64 sets z to x and returns z.
+// Precision is set to 64 bits.
+func (z *Float) SetInt64(x int64) *Float {
+       u := x
+       if u < 0 {
+               u = -u
+       }
+       z.SetUint64(uint64(u))
+       z.neg = x < 0
+       return z
+}
+
+// SetFloat64 sets z to x and returns z.
+// Precision is set to 53 bits.
+// TODO(gri) test denormals, +/-Inf, disallow NaN.
+func (z *Float) SetFloat64(x float64) *Float {
+       z.prec = 53
+       z.neg = math.Signbit(x) // handle -0 correctly (-0 == 0)
+       if x == 0 {
+               z.mant = z.mant[:0]
+               z.exp = 0
+               return z
+       }
+       fmant, exp := math.Frexp(x) // get normalized mantissa
+       z.mant = z.mant.setUint64(1<<63 | math.Float64bits(fmant)<<11)
+       z.exp = int32(exp)
+       return z
+}
+
+// fnorm normalizes mantissa m by shifting it to the left
+// such that the msb of the most-significant word (msw)
+// is 1. It returns the shift amount.
+// It assumes that m is not the zero nat.
+func fnorm(m nat) uint {
+       if debugFloat && (len(m) == 0 || m[len(m)-1] == 0) {
+               panic("msw of mantissa is 0")
+       }
+       s := nlz(m[len(m)-1])
+       if s > 0 {
+               c := shlVU(m, m, s)
+               if debugFloat && c != 0 {
+                       panic("nlz or shlVU incorrect")
+               }
+       }
+       return s
+}
+
+// SetInt sets z to x and returns z.
+// Precision is set to the number of bits required to represent x accurately.
+// TODO(gri) what about precision for x == 0?
+func (z *Float) SetInt(x *Int) *Float {
+       if len(x.abs) == 0 {
+               z.neg = false
+               z.mant = z.mant[:0]
+               z.exp = 0
+               // z.prec = ?
+               return z
+       }
+       // x != 0
+       z.neg = x.neg
+       z.mant = z.mant.set(x.abs)
+       e := uint(len(z.mant))*_W - fnorm(z.mant)
+       z.exp = int32(e)
+       z.prec = e
+       return z
+}
+
+// SetRat sets z to x rounded to the precision of z and returns z.
+func (z *Float) SetRat(x *Rat, prec uint) *Float {
+       panic("unimplemented")
+}
+
+// Set sets z to x, with the same precision as x, and returns z.
+func (z *Float) Set(x *Float) *Float {
+       if z != x {
+               z.neg = x.neg
+               z.exp = x.exp
+               z.mant = z.mant.set(x.mant)
+               z.prec = x.prec
+       }
+       return z
+}
+
+func high64(x nat) uint64 {
+       i := len(x)
+       if i == 0 {
+               return 0
+       }
+       // i > 0
+       v := uint64(x[i-1])
+       if _W == 32 {
+               v <<= 32
+               if i > 1 {
+                       v |= uint64(x[i-2])
+               }
+       }
+       return v
+}
+
+// TODO(gri) FIX THIS (rounding mode, errors, accuracy, etc.)
+func (x *Float) Uint64() uint64 {
+       m := high64(x.mant)
+       s := x.exp
+       if s >= 0 {
+               return m >> (64 - uint(s))
+       }
+       return 0 // imprecise
+}
+
+// TODO(gri) FIX THIS (rounding mode, errors, etc.)
+func (x *Float) Int64() int64 {
+       v := int64(x.Uint64())
+       if x.neg {
+               return -v
+       }
+       return v
+}
+
+// Float64 returns the closest float64 value of x
+// by rounding to nearest with 53 bits precision.
+// TODO(gri) implement/document error scenarios.
+func (x *Float) Float64() (float64, Accuracy) {
+       if len(x.mant) == 0 {
+               return 0, Exact
+       }
+       // x != 0
+       r := new(Float).Round(x, 53, ToNearestEven)
+       var s uint64
+       if r.neg {
+               s = 1 << 63
+       }
+       e := uint64(1022+r.exp) & 0x7ff // TODO(gri) check for overflow
+       m := high64(r.mant) >> 11 & (1<<52 - 1)
+       return math.Float64frombits(s | e<<52 | m), r.acc
+}
+
+func (x *Float) Int() *Int {
+       if len(x.mant) == 0 {
+               return new(Int)
+       }
+       panic("unimplemented")
+}
+
+func (x *Float) Rat() *Rat {
+       panic("unimplemented")
+}
+
+func (x *Float) IsInt() bool {
+       if len(x.mant) == 0 {
+               return true
+       }
+       if x.exp <= 0 {
+               return false
+       }
+       if uint(x.exp) >= x.prec {
+               return true
+       }
+       panic("unimplemented")
+}
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+// TODO(gri) should Abs (and Neg) below ignore z's precision and rounding mode?
+func (z *Float) Abs(x *Float) *Float {
+       z.Set(x)
+       z.neg = false
+       return z
+}
+
+// Neg sets z to x with its sign negated, and returns z.
+func (z *Float) Neg(x *Float) *Float {
+       z.Set(x)
+       z.neg = !z.neg
+       return z
+}
+
+// z = x + y, ignoring signs of x and y.
+// x and y must not be 0.
+func (z *Float) uadd(x, y *Float) {
+       // Note: This implementation requires 2 shifts most of the
+       // time. It is also inefficient if exponents or precisions
+       // differ by wide margins. The following article describes
+       // an efficient (but much more complicated) implementation
+       // compatible with the internal representation used here:
+       //
+       // Vincent Lefèvre: "The Generic Multiple-Precision Floating-
+       // Point Addition With Exact Rounding (as in the MPFR Library)"
+       // http://www.vinc17.net/research/papers/rnc6.pdf
+
+       if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
+               panic("uadd called with 0 argument")
+       }
+
+       // compute exponents ex, ey for mantissa with "binary point"
+       // on the right (mantissa.0) - use int64 to avoid overflow
+       ex := int64(x.exp) - int64(len(x.mant))*_W
+       ey := int64(y.exp) - int64(len(y.mant))*_W
+
+       // TODO(gri) having a combined add-and-shift primitive
+       //           could make this code significantly faster
+       switch {
+       case ex < ey:
+               t := z.mant.shl(y.mant, uint(ey-ex))
+               z.mant = t.add(x.mant, t)
+       default:
+               // ex == ey, no shift needed
+               z.mant = z.mant.add(x.mant, y.mant)
+       case ex > ey:
+               t := z.mant.shl(x.mant, uint(ex-ey))
+               z.mant = t.add(t, y.mant)
+               ex = ey
+       }
+       // len(z.mant) > 0
+
+       z.setExp(ex + int64(len(z.mant))*_W - int64(fnorm(z.mant)))
+       z.round(0)
+}
+
+// z = x - y for x >= y, ignoring signs of x and y.
+// x and y must not be zero.
+func (z *Float) usub(x, y *Float) {
+       // This code is symmetric to uadd.
+       // We have not factored the common code out because
+       // eventually uadd (and usub) should be optimized
+       // by special-casing, and the code will diverge.
+
+       if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
+               panic("usub called with 0 argument")
+       }
+
+       ex := int64(x.exp) - int64(len(x.mant))*_W
+       ey := int64(y.exp) - int64(len(y.mant))*_W
+
+       switch {
+       case ex < ey:
+               t := z.mant.shl(y.mant, uint(ey-ex))
+               z.mant = t.sub(x.mant, t)
+       default:
+               // ex == ey, no shift needed
+               z.mant = z.mant.sub(x.mant, y.mant)
+       case ex > ey:
+               t := z.mant.shl(x.mant, uint(ex-ey))
+               z.mant = t.sub(t, y.mant)
+               ex = ey
+       }
+
+       // operands may have cancelled each other out
+       if len(z.mant) == 0 {
+               z.acc = Exact
+               z.setExp(0)
+               return
+       }
+       // len(z.mant) > 0
+
+       z.setExp(ex + int64(len(z.mant))*_W - int64(fnorm(z.mant)))
+       z.round(0)
+}
+
+// z = x * y, ignoring signs of x and y.
+// x and y must not be zero.
+func (z *Float) umul(x, y *Float) {
+       if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
+               panic("umul called with 0 argument")
+       }
+
+       // Note: This is doing too much work if the precision
+       // of z is less than the sum of the precisions of x
+       // and y which is often the case (e.g., if all floats
+       // have the same precision).
+       // TODO(gri) Optimize this for the common case.
+
+       e := int64(x.exp) + int64(y.exp)
+       z.mant = z.mant.mul(x.mant, y.mant)
+
+       // normalize mantissa
+       z.setExp(e - int64(fnorm(z.mant)))
+       z.round(0)
+}
+
+// z = x / y, ignoring signs of x and y.
+// x and y must not be zero.
+func (z *Float) uquo(x, y *Float) {
+       if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
+               panic("uquo called with 0 argument")
+       }
+
+       // mantissa length in words for desired result precision + 1
+       // (at least one extra bit so we get the rounding bit after
+       // the division)
+       n := int(z.prec/_W) + 1
+
+       // compute adjusted x.mant such that we get enough result precision
+       xadj := x.mant
+       if d := n - len(x.mant) + len(y.mant); d > 0 {
+               // d extra words needed => add d "0 digits" to x
+               xadj = make(nat, len(x.mant)+d)
+               copy(xadj[d:], x.mant)
+       }
+       // TODO(gri): If we have too many digits (d < 0), we should be able
+       // to shorten x for faster division. But we must be extra careful
+       // with rounding in that case.
+
+       // divide
+       var r nat
+       z.mant, r = z.mant.div(nil, xadj, y.mant)
+
+       // determine exponent
+       e := int64(x.exp) - int64(y.exp) - int64(len(xadj)-len(y.mant)-len(z.mant))*_W
+
+       // normalize mantissa
+       z.setExp(e - int64(fnorm(z.mant)))
+
+       // The result is long enough to include (at least) the rounding bit.
+       // If there's a non-zero remainder, the corresponding fractional part
+       // (if it were computed), would have a non-zero sticky bit (if it were
+       // zero, it couldn't have a non-zero remainder).
+       var sbit uint
+       if len(r) > 0 {
+               sbit = 1
+       }
+       z.round(sbit)
+}
+
+// ucmp returns -1, 0, or 1, depending on whether x < y, x == y, or x > y,
+// while ignoring the signs of x and y. x and y must not be zero.
+func (x *Float) ucmp(y *Float) int {
+       if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
+               panic("ucmp called with 0 argument")
+       }
+
+       switch {
+       case x.exp < y.exp:
+               return -1
+       case x.exp > y.exp:
+               return 1
+       }
+       // x.exp == y.exp
+
+       // compare mantissas
+       i := len(x.mant)
+       j := len(y.mant)
+       for i > 0 || j > 0 {
+               var xm, ym Word
+               if i > 0 {
+                       i--
+                       xm = x.mant[i]
+               }
+               if j > 0 {
+                       j--
+                       ym = y.mant[j]
+               }
+               switch {
+               case xm < ym:
+                       return -1
+               case xm > ym:
+                       return 1
+               }
+       }
+
+       return 0
+}
+
+// Handling of sign bit as defined by IEEE 754-2008,
+// section 6.3 (note that there are no NaN Floats):
+//
+// When neither the inputs nor result are NaN, the sign of a product or
+// quotient is the exclusive OR of the operands’ signs; the sign of a sum,
+// or of a difference x−y regarded as a sum x+(−y), differs from at most
+// one of the addends’ signs; and the sign of the result of conversions,
+// the quantize operation, the roundToIntegral operations, and the
+// roundToIntegralExact (see 5.3.1) is the sign of the first or only operand.
+// These rules shall apply even when operands or results are zero or infinite.
+//
+// When the sum of two operands with opposite signs (or the difference of
+// two operands with like signs) is exactly zero, the sign of that sum (or
+// difference) shall be +0 in all rounding-direction attributes except
+// roundTowardNegative; under that attribute, the sign of an exact zero
+// sum (or difference) shall be âˆ’0. However, x+x = x−(−x) retains the same
+// sign as x even when x is zero.
+
+// Add sets z to the rounded sum x+y and returns z.
+// Rounding is performed according to z's precision
+// and rounding mode; and z's accuracy reports the
+// result error relative to the exact (not rounded)
+// result.
+func (z *Float) Add(x, y *Float) *Float {
+       // TODO(gri) what about -0?
+       if len(y.mant) == 0 {
+               return z.Round(x, z.prec, z.mode)
+       }
+       if len(x.mant) == 0 {
+               return z.Round(y, z.prec, z.mode)
+       }
+
+       // x, y != 0
+       neg := x.neg
+       if x.neg == y.neg {
+               // x + y == x + y
+               // (-x) + (-y) == -(x + y)
+               z.uadd(x, y)
+       } else {
+               // x + (-y) == x - y == -(y - x)
+               // (-x) + y == y - x == -(x - y)
+               if x.ucmp(y) >= 0 {
+                       z.usub(x, y)
+               } else {
+                       neg = !neg
+                       z.usub(y, x)
+               }
+       }
+       z.neg = neg
+       return z
+}
+
+// Sub sets z to the rounded difference x-y and returns z.
+// Rounding is performed according to z's precision
+// and rounding mode; and z's accuracy reports the
+// result error relative to the exact (not rounded)
+// result.
+func (z *Float) Sub(x, y *Float) *Float {
+       // TODO(gri) what about -0?
+       if len(y.mant) == 0 {
+               return z.Round(x, z.prec, z.mode)
+       }
+       if len(x.mant) == 0 {
+               prec := z.prec
+               mode := z.mode
+               z.Neg(y)
+               return z.Round(z, prec, mode)
+       }
+
+       // x, y != 0
+       neg := x.neg
+       if x.neg != y.neg {
+               // x - (-y) == x + y
+               // (-x) - y == -(x + y)
+               z.uadd(x, y)
+       } else {
+               // x - y == x - y == -(y - x)
+               // (-x) - (-y) == y - x == -(x - y)
+               if x.ucmp(y) >= 0 {
+                       z.usub(x, y)
+               } else {
+                       neg = !neg
+                       z.usub(y, x)
+               }
+       }
+       z.neg = neg
+       return z
+}
+
+// Mul sets z to the rounded product x*y and returns z.
+// Rounding is performed according to z's precision
+// and rounding mode; and z's accuracy reports the
+// result error relative to the exact (not rounded)
+// result.
+func (z *Float) Mul(x, y *Float) *Float {
+       // TODO(gri) what about -0?
+       if len(x.mant) == 0 || len(y.mant) == 0 {
+               z.neg = false
+               z.mant = z.mant[:0]
+               z.exp = 0
+               z.acc = Exact
+               return z
+       }
+
+       // x, y != 0
+       z.umul(x, y)
+       z.neg = x.neg != y.neg
+       return z
+}
+
+// Quo sets z to the rounded quotient x/y and returns z.
+// If y == 0, a division-by-zero run-time panic occurs. TODO(gri) this should become Inf
+// Rounding is performed according to z's precision
+// and rounding mode; and z's accuracy reports the
+// result error relative to the exact (not rounded)
+// result.
+func (z *Float) Quo(x, y *Float) *Float {
+       // TODO(gri) what about -0?
+       if len(x.mant) == 0 {
+               z.neg = false
+               z.mant = z.mant[:0]
+               z.exp = 0
+               z.acc = Exact
+               return z
+       }
+       if len(y.mant) == 0 {
+               panic("division-by-zero") // TODO(gri) handle this better
+       }
+
+       // x, y != 0
+       z.uquo(x, y)
+       z.neg = x.neg != y.neg
+       return z
+}
+
+// Lsh sets z to the rounded x * (1<<s) and returns z.
+// Rounding is performed according to z's precision
+// and rounding mode; and z's accuracy reports the
+// result error relative to the exact (not rounded)
+// result.
+func (z *Float) Lsh(x *Float, s uint, mode RoundingMode) *Float {
+       z.Round(x, z.prec, mode)
+       z.setExp(int64(z.exp) + int64(s))
+       return z
+}
+
+// Rsh sets z to the rounded x / (1<<s) and returns z.
+// Rounding is performed according to z's precision
+// and rounding mode; and z's accuracy reports the
+// result error relative to the exact (not rounded)
+// result.
+func (z *Float) Rsh(x *Float, s uint, mode RoundingMode) *Float {
+       z.Round(x, z.prec, mode)
+       z.setExp(int64(z.exp) - int64(s))
+       return z
+}
+
+// Cmp compares x and y and returns:
+//
+//   -1 if x <  y
+//    0 if x == y (incl. -0 == 0)
+//   +1 if x >  y
+//
+func (x *Float) Cmp(y *Float) int {
+       // special cases
+       switch {
+       case len(x.mant) == 0:
+               // 0 cmp y == -sign(y)
+               return -y.Sign()
+       case len(y.mant) == 0:
+               // x cmp 0 == sign(x)
+               return x.Sign()
+       }
+       // x != 0 && y != 0
+
+       // x cmp y == x cmp y
+       // x cmp (-y) == 1
+       // (-x) cmp y == -1
+       // (-x) cmp (-y) == -(x cmp y)
+       switch {
+       case x.neg == y.neg:
+               r := x.ucmp(y)
+               if x.neg {
+                       r = -r
+               }
+               return r
+       case x.neg:
+               return -1
+       default:
+               return 1
+       }
+       return 0
+}
+
+// Sign returns:
+//
+//     -1 if x <  0
+//      0 if x == 0 (incl. x == -0)
+//     +1 if x >  0
+//
+func (x *Float) Sign() int {
+       if len(x.mant) == 0 {
+               return 0
+       }
+       if x.neg {
+               return -1
+       }
+       return 1
+}
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go
new file mode 100644 (file)
index 0000000..ec67a6d
--- /dev/null
@@ -0,0 +1,684 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+       "fmt"
+       "sort"
+       "strconv"
+       "testing"
+)
+
+func fromBinary(s string) int64 {
+       x, err := strconv.ParseInt(s, 2, 64)
+       if err != nil {
+               panic(err)
+       }
+       return x
+}
+
+func toBinary(x int64) string {
+       return strconv.FormatInt(x, 2)
+}
+
+func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) {
+       // verify test data
+       var ok bool
+       switch mode {
+       case ToNearestEven, ToNearestAway:
+               ok = true // nothing to do for now
+       case ToZero:
+               if x < 0 {
+                       ok = r >= x
+               } else {
+                       ok = r <= x
+               }
+       case AwayFromZero:
+               if x < 0 {
+                       ok = r <= x
+               } else {
+                       ok = r >= x
+               }
+       case ToNegativeInf:
+               ok = r <= x
+       case ToPositiveInf:
+               ok = r >= x
+       default:
+               panic("unreachable")
+       }
+       if !ok {
+               t.Fatalf("incorrect test data for prec = %d, %s: x = %s, r = %s", prec, mode, toBinary(x), toBinary(r))
+       }
+
+       // compute expected accuracy
+       a := Exact
+       switch {
+       case r < x:
+               a = Below
+       case r > x:
+               a = Above
+       }
+
+       // round
+       f := new(Float).SetInt64(x)
+       f.Round(f, prec, mode)
+
+       // check result
+       r1 := f.Int64()
+       p1 := f.Precision()
+       a1 := f.Accuracy()
+       if r1 != r || p1 != prec || a1 != a {
+               t.Errorf("Round(%s, %d, %s): got %s (%d bits, %s); want %s (%d bits, %s)",
+                       toBinary(x), prec, mode,
+                       toBinary(r1), p1, a1,
+                       toBinary(r), prec, a)
+       }
+}
+
+// TestFloatRound tests basic rounding.
+func TestFloatRound(t *testing.T) {
+       for _, test := range []struct {
+               prec                        uint
+               x, zero, neven, naway, away string // input, results rounded to prec bits
+       }{
+               {5, "1000", "1000", "1000", "1000", "1000"},
+               {5, "1001", "1001", "1001", "1001", "1001"},
+               {5, "1010", "1010", "1010", "1010", "1010"},
+               {5, "1011", "1011", "1011", "1011", "1011"},
+               {5, "1100", "1100", "1100", "1100", "1100"},
+               {5, "1101", "1101", "1101", "1101", "1101"},
+               {5, "1110", "1110", "1110", "1110", "1110"},
+               {5, "1111", "1111", "1111", "1111", "1111"},
+
+               {4, "1000", "1000", "1000", "1000", "1000"},
+               {4, "1001", "1001", "1001", "1001", "1001"},
+               {4, "1010", "1010", "1010", "1010", "1010"},
+               {4, "1011", "1011", "1011", "1011", "1011"},
+               {4, "1100", "1100", "1100", "1100", "1100"},
+               {4, "1101", "1101", "1101", "1101", "1101"},
+               {4, "1110", "1110", "1110", "1110", "1110"},
+               {4, "1111", "1111", "1111", "1111", "1111"},
+
+               {3, "1000", "1000", "1000", "1000", "1000"},
+               {3, "1001", "1000", "1000", "1010", "1010"},
+               {3, "1010", "1010", "1010", "1010", "1010"},
+               {3, "1011", "1010", "1100", "1100", "1100"},
+               {3, "1100", "1100", "1100", "1100", "1100"},
+               {3, "1101", "1100", "1100", "1110", "1110"},
+               {3, "1110", "1110", "1110", "1110", "1110"},
+               {3, "1111", "1110", "10000", "10000", "10000"},
+
+               {3, "1000001", "1000000", "1000000", "1000000", "1010000"},
+               {3, "1001001", "1000000", "1010000", "1010000", "1010000"},
+               {3, "1010001", "1010000", "1010000", "1010000", "1100000"},
+               {3, "1011001", "1010000", "1100000", "1100000", "1100000"},
+               {3, "1100001", "1100000", "1100000", "1100000", "1110000"},
+               {3, "1101001", "1100000", "1110000", "1110000", "1110000"},
+               {3, "1110001", "1110000", "1110000", "1110000", "10000000"},
+               {3, "1111001", "1110000", "10000000", "10000000", "10000000"},
+
+               {2, "1000", "1000", "1000", "1000", "1000"},
+               {2, "1001", "1000", "1000", "1000", "1100"},
+               {2, "1010", "1000", "1000", "1100", "1100"},
+               {2, "1011", "1000", "1100", "1100", "1100"},
+               {2, "1100", "1100", "1100", "1100", "1100"},
+               {2, "1101", "1100", "1100", "1100", "10000"},
+               {2, "1110", "1100", "10000", "10000", "10000"},
+               {2, "1111", "1100", "10000", "10000", "10000"},
+
+               {2, "1000001", "1000000", "1000000", "1000000", "1100000"},
+               {2, "1001001", "1000000", "1000000", "1000000", "1100000"},
+               {2, "1010001", "1000000", "1100000", "1100000", "1100000"},
+               {2, "1011001", "1000000", "1100000", "1100000", "1100000"},
+               {2, "1100001", "1100000", "1100000", "1100000", "10000000"},
+               {2, "1101001", "1100000", "1100000", "1100000", "10000000"},
+               {2, "1110001", "1100000", "10000000", "10000000", "10000000"},
+               {2, "1111001", "1100000", "10000000", "10000000", "10000000"},
+
+               {1, "1000", "1000", "1000", "1000", "1000"},
+               {1, "1001", "1000", "1000", "1000", "10000"},
+               {1, "1010", "1000", "1000", "1000", "10000"},
+               {1, "1011", "1000", "1000", "1000", "10000"},
+               {1, "1100", "1000", "10000", "10000", "10000"},
+               {1, "1101", "1000", "10000", "10000", "10000"},
+               {1, "1110", "1000", "10000", "10000", "10000"},
+               {1, "1111", "1000", "10000", "10000", "10000"},
+
+               {1, "1000001", "1000000", "1000000", "1000000", "10000000"},
+               {1, "1001001", "1000000", "1000000", "1000000", "10000000"},
+               {1, "1010001", "1000000", "1000000", "1000000", "10000000"},
+               {1, "1011001", "1000000", "1000000", "1000000", "10000000"},
+               {1, "1100001", "1000000", "10000000", "10000000", "10000000"},
+               {1, "1101001", "1000000", "10000000", "10000000", "10000000"},
+               {1, "1110001", "1000000", "10000000", "10000000", "10000000"},
+               {1, "1111001", "1000000", "10000000", "10000000", "10000000"},
+       } {
+               x := fromBinary(test.x)
+               z := fromBinary(test.zero)
+               e := fromBinary(test.neven)
+               n := fromBinary(test.naway)
+               a := fromBinary(test.away)
+               prec := test.prec
+
+               testFloatRound(t, x, z, prec, ToZero)
+               testFloatRound(t, x, e, prec, ToNearestEven)
+               testFloatRound(t, x, n, prec, ToNearestAway)
+               testFloatRound(t, x, a, prec, AwayFromZero)
+
+               testFloatRound(t, x, z, prec, ToNegativeInf)
+               testFloatRound(t, x, a, prec, ToPositiveInf)
+
+               testFloatRound(t, -x, -a, prec, ToNegativeInf)
+               testFloatRound(t, -x, -z, prec, ToPositiveInf)
+       }
+}
+
+// TestFloatRound24 tests that rounding a float64 to 24 bits
+// matches IEEE-754 rounding to nearest when converting a
+// float64 to a float32.
+func TestFloatRound24(t *testing.T) {
+       const x0 = 1<<26 - 0x10 // 11...110000 (26 bits)
+       for d := 0; d <= 0x10; d++ {
+               x := float64(x0 + d)
+               f := new(Float).SetFloat64(x)
+               f.Round(f, 24, ToNearestEven)
+               got, _ := f.Float64()
+               want := float64(float32(x))
+               if got != want {
+                       t.Errorf("Round(%g, 24) = %g; want %g", x, got, want)
+               }
+       }
+}
+
+func TestFloatSetUint64(t *testing.T) {
+       for _, want := range []uint64{
+               0,
+               1,
+               2,
+               10,
+               100,
+               1<<32 - 1,
+               1 << 32,
+               1<<64 - 1,
+       } {
+               f := new(Float).SetUint64(want)
+               if got := f.Uint64(); got != want {
+                       t.Errorf("got %d (%s); want %d", got, f.Format('p', 0), want)
+               }
+       }
+}
+
+func TestFloatSetInt64(t *testing.T) {
+       for _, want := range []int64{
+               0,
+               1,
+               2,
+               10,
+               100,
+               1<<32 - 1,
+               1 << 32,
+               1<<63 - 1,
+       } {
+               for i := range [2]int{} {
+                       if i&1 != 0 {
+                               want = -want
+                       }
+                       f := new(Float).SetInt64(want)
+                       if got := f.Int64(); got != want {
+                               t.Errorf("got %d (%s); want %d", got, f.Format('p', 0), want)
+                       }
+               }
+       }
+}
+
+func TestFloatSetFloat64(t *testing.T) {
+       for _, want := range []float64{
+               0,
+               1,
+               2,
+               12345,
+               1e10,
+               1e100,
+               3.14159265e10,
+               2.718281828e-123,
+               1.0 / 3,
+       } {
+               for i := range [2]int{} {
+                       if i&1 != 0 {
+                               want = -want
+                       }
+                       f := new(Float).SetFloat64(want)
+                       if got, _ := f.Float64(); got != want {
+                               t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want)
+                       }
+               }
+       }
+}
+
+func TestFloatSetInt(t *testing.T) {
+       // TODO(gri) implement
+}
+
+// Selected precisions with which to run various tests.
+var precList = [...]uint{1, 2, 5, 8, 10, 16, 23, 24, 32, 50, 53, 64, 100, 128, 500, 511, 512, 513, 1000, 10000}
+
+// Selected bits with which to run various tests.
+// Each entry is a list of bits representing a floating-point number (see fromBits).
+var bitsList = [...][]int{
+       {},           // = 0
+       {0},          // = 1
+       {1},          // = 2
+       {-1},         // = 1/2
+       {10},         // = 2**10 == 1024
+       {-10},        // = 2**-10 == 1/1024
+       {100, 10, 1}, // = 2**100 + 2**10 + 2**1
+       {0, -1, -2, -10},
+       // TODO(gri) add more test cases
+}
+
+// TestFloatAdd tests Float.Add/Sub by comparing the result of a "manual"
+// addition/subtraction of arguments represented by bits lists with the
+// respective floating-point addition/subtraction for a variety of precisions
+// and rounding modes.
+func TestFloatAdd(t *testing.T) {
+       for _, xbits := range bitsList {
+               for _, ybits := range bitsList {
+                       // exact values
+                       x := fromBits(xbits...)
+                       y := fromBits(ybits...)
+                       zbits := append(xbits, ybits...)
+                       z := fromBits(zbits...)
+
+                       for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
+                               for _, prec := range precList {
+                                       got := NewFloat(0, prec, mode)
+                                       got.Add(x, y)
+                                       want := roundBits(zbits, prec, mode)
+                                       if got.Cmp(want) != 0 {
+                                               t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t+    %s %v\n\t=    %s\n\twant %s",
+                                                       i, prec, mode, x, xbits, y, ybits, got, want)
+                                               return
+                                       }
+
+                                       got.Sub(z, x)
+                                       want = roundBits(ybits, prec, mode)
+                                       if got.Cmp(want) != 0 {
+                                               t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t-    %s %v\n\t=    %s\n\twant %s",
+                                                       i, prec, mode, z, zbits, x, xbits, got, want)
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+// TestFloatAdd32 tests that Float.Add/Sub of numbers with
+// 24bit mantissa behaves like float32 addition/subtraction.
+func TestFloatAdd32(t *testing.T) {
+       // TODO(gri) fix test for 32bit platforms
+       if _W == 32 {
+               return
+       }
+
+       // chose base such that we cross the mantissa precision limit
+       const base = 1<<26 - 0x10 // 11...110000 (26 bits)
+       for d := 0; d <= 0x10; d++ {
+               for i := range [2]int{} {
+                       x0, y0 := float64(base), float64(d)
+                       if i&1 != 0 {
+                               x0, y0 = y0, x0
+                       }
+
+                       x := new(Float).SetFloat64(x0)
+                       y := new(Float).SetFloat64(y0)
+                       z := NewFloat(0, 24, ToNearestEven)
+
+                       z.Add(x, y)
+                       got, acc := z.Float64()
+                       want := float64(float32(y0) + float32(x0))
+                       if got != want || acc != Exact {
+                               t.Errorf("d = %d: %g + %g = %g (%s); want %g exactly", d, x0, y0, got, acc, want)
+                       }
+
+                       z.Sub(z, y)
+                       got, acc = z.Float64()
+                       want = float64(float32(want) - float32(y0))
+                       if got != want || acc != Exact {
+                               t.Errorf("d = %d: %g - %g = %g (%s); want %g exactly", d, x0+y0, y0, got, acc, want)
+                       }
+               }
+       }
+}
+
+// TestFloatAdd64 tests that Float.Add/Sub of numbers with
+// 53bit mantissa behaves like float64 addition/subtraction.
+func TestFloatAdd64(t *testing.T) {
+       // chose base such that we cross the mantissa precision limit
+       const base = 1<<55 - 0x10 // 11...110000 (55 bits)
+       for d := 0; d <= 0x10; d++ {
+               for i := range [2]int{} {
+                       x0, y0 := float64(base), float64(d)
+                       if i&1 != 0 {
+                               x0, y0 = y0, x0
+                       }
+
+                       x := new(Float).SetFloat64(x0)
+                       y := new(Float).SetFloat64(y0)
+                       z := NewFloat(0, 53, ToNearestEven)
+
+                       z.Add(x, y)
+                       got, acc := z.Float64()
+                       want := x0 + y0
+                       if got != want || acc != Exact {
+                               t.Errorf("d = %d: %g + %g = %g (%s); want %g exactly", d, x0, y0, got, acc, want)
+                       }
+
+                       z.Sub(z, y)
+                       got, acc = z.Float64()
+                       want -= y0
+                       if got != want || acc != Exact {
+                               t.Errorf("d = %d: %g - %g = %g (%s); want %g exactly", d, x0+y0, y0, got, acc, want)
+                       }
+               }
+       }
+}
+
+func TestFloatMul(t *testing.T) {
+}
+
+// TestFloatMul64 tests that Float.Mul/Quo of numbers with
+// 53bit mantissa behaves like float64 multiplication/division.
+func TestFloatMul64(t *testing.T) {
+       for _, test := range []struct {
+               x, y float64
+       }{
+               {0, 0},
+               {0, 1},
+               {1, 1},
+               {1, 1.5},
+               {1.234, 0.5678},
+               {2.718281828, 3.14159265358979},
+               {2.718281828e10, 3.14159265358979e-32},
+               {1.0 / 3, 1e200},
+       } {
+               for i := range [8]int{} {
+                       x0, y0 := test.x, test.y
+                       if i&1 != 0 {
+                               x0 = -x0
+                       }
+                       if i&2 != 0 {
+                               y0 = -y0
+                       }
+                       if i&4 != 0 {
+                               x0, y0 = y0, x0
+                       }
+
+                       x := new(Float).SetFloat64(x0)
+                       y := new(Float).SetFloat64(y0)
+                       z := NewFloat(0, 53, ToNearestEven)
+
+                       z.Mul(x, y)
+                       got, _ := z.Float64()
+                       want := x0 * y0
+                       if got != want {
+                               t.Errorf("%g * %g = %g; want %g", x0, y0, got, want)
+                       }
+
+                       if y0 == 0 {
+                               continue // avoid division-by-zero
+                       }
+                       z.Quo(z, y)
+                       got, _ = z.Float64()
+                       want /= y0
+                       if got != want {
+                               t.Errorf("%g / %g = %g; want %g", x0*y0, y0, got, want)
+                       }
+               }
+       }
+}
+
+func TestIssue6866(t *testing.T) {
+       for _, prec := range precList {
+               two := NewFloat(2, prec, ToNearestEven)
+               one := NewFloat(1, prec, ToNearestEven)
+               three := NewFloat(3, prec, ToNearestEven)
+               msix := NewFloat(-6, prec, ToNearestEven)
+               psix := NewFloat(+6, prec, ToNearestEven)
+
+               p := NewFloat(0, prec, ToNearestEven)
+               z1 := NewFloat(0, prec, ToNearestEven)
+               z2 := NewFloat(0, prec, ToNearestEven)
+
+               // z1 = 2 + 1.0/3*-6
+               p.Quo(one, three)
+               p.Mul(p, msix)
+               z1.Add(two, p)
+
+               // z2 = 2 - 1.0/3*+6
+               p.Quo(one, three)
+               p.Mul(p, psix)
+               z2.Sub(two, p)
+
+               if z1.Cmp(z2) != 0 {
+                       t.Fatalf("prec %d: got z1 = %s != z2 = %s; want z1 == z2\n", prec, z1, z2)
+               }
+               if z1.Sign() != 0 {
+                       t.Errorf("prec %d: got z1 = %s; want 0", prec, z1)
+               }
+               if z2.Sign() != 0 {
+                       t.Errorf("prec %d: got z2 = %s; want 0", prec, z2)
+               }
+       }
+}
+
+func TestFloatQuo(t *testing.T) {
+       // TODO(gri) make the test vary these precisions
+       preci := 200 // precision of integer part
+       precf := 20  // precision of fractional part
+
+       for i := 0; i < 8; i++ {
+               // compute accurate (not rounded) result z
+               bits := []int{preci - 1}
+               if i&3 != 0 {
+                       bits = append(bits, 0)
+               }
+               if i&2 != 0 {
+                       bits = append(bits, -1)
+               }
+               if i&1 != 0 {
+                       bits = append(bits, -precf)
+               }
+               z := fromBits(bits...)
+
+               // compute accurate x as z*y
+               y := new(Float).SetFloat64(3.14159265358979323e123)
+
+               x := NewFloat(0, z.Precision()+y.Precision(), ToZero)
+               x.Mul(z, y)
+
+               // leave for debugging
+               // fmt.Printf("x = %s\ny = %s\nz = %s\n", x, y, z)
+
+               if got := x.Accuracy(); got != Exact {
+                       t.Errorf("got acc = %s; want exact", got)
+               }
+
+               // round accurate z for a variety of precisions and
+               // modes and compare against result of x / y.
+               for _, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
+                       for d := -5; d < 5; d++ {
+                               prec := uint(preci + d)
+                               got := NewFloat(0, prec, mode).Quo(x, y)
+                               want := roundBits(bits, prec, mode)
+                               if got.Cmp(want) != 0 {
+                                       t.Errorf("i = %d, prec = %d, %s:\n\t     %s\n\t/    %s\n\t=    %s\n\twant %s",
+                                               i, prec, mode, x, y, got, want)
+                               }
+                       }
+               }
+       }
+}
+
+// normBits returns the normalized bits for x: It
+// removes multiple equal entries by treating them
+// as an addition (e.g., []int{5, 5} => []int{6}),
+// and it sorts the result list for reproducible
+// results.
+func normBits(x []int) []int {
+       m := make(map[int]bool)
+       for _, b := range x {
+               for m[b] {
+                       m[b] = false
+                       b++
+               }
+               m[b] = true
+       }
+       var z []int
+       for b, set := range m {
+               if set {
+                       z = append(z, b)
+               }
+       }
+       sort.Ints(z)
+       return z
+}
+
+func TestNormBits(t *testing.T) {
+       for _, test := range []struct {
+               x, want []int
+       }{
+               {nil, nil},
+               {[]int{}, []int{}},
+               {[]int{0}, []int{0}},
+               {[]int{0, 0}, []int{1}},
+               {[]int{3, 1, 1}, []int{2, 3}},
+               {[]int{10, 9, 8, 7, 6, 6}, []int{11}},
+       } {
+               got := fmt.Sprintf("%v", normBits(test.x))
+               want := fmt.Sprintf("%v", test.want)
+               if got != want {
+                       t.Errorf("normBits(%v) = %s; want %s", test.x, got, want)
+               }
+
+       }
+}
+
+// roundBits returns the Float value rounded to prec bits
+// according to mode from the bit set x.
+func roundBits(x []int, prec uint, mode RoundingMode) *Float {
+       x = normBits(x)
+
+       // determine range
+       var min, max int
+       for i, b := range x {
+               if i == 0 || b < min {
+                       min = b
+               }
+               if i == 0 || b > max {
+                       max = b
+               }
+       }
+       prec0 := uint(max + 1 - min)
+       if prec >= prec0 {
+               return fromBits(x...)
+       }
+       // prec < prec0
+
+       // determine bit 0, rounding, and sticky bit, and result bits z
+       var bit0, rbit, sbit uint
+       var z []int
+       r := max - int(prec)
+       for _, b := range x {
+               switch {
+               case b == r:
+                       rbit = 1
+               case b < r:
+                       sbit = 1
+               default:
+                       // b > r
+                       if b == r+1 {
+                               bit0 = 1
+                       }
+                       z = append(z, b)
+               }
+       }
+
+       // round
+       f := fromBits(z...) // rounded to zero
+       if mode == ToNearestAway {
+               panic("not yet implemented")
+       }
+       if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero {
+               // round away from zero
+               f.Round(f, prec, ToZero) // extend precision // TODO(gri) better approach?
+               f.Add(f, fromBits(int(r)+1))
+       }
+       return f
+}
+
+// fromBits returns the *Float z of the smallest possible precision
+// such that z = sum(2**bits[i]), with i = range bits.
+// If multiple bits[i] are equal, they are added: fromBits(0, 1, 0)
+// == 2**1 + 2**0 + 2**0 = 4.
+func fromBits(bits ...int) *Float {
+       // handle 0
+       if len(bits) == 0 {
+               return new(Float)
+               // z.prec = ?
+       }
+       // len(bits) > 0
+
+       // determine lsb exponent
+       var min int
+       for i, b := range bits {
+               if i == 0 || b < min {
+                       min = b
+               }
+       }
+
+       // create bit pattern
+       x := NewInt(0)
+       for _, b := range bits {
+               badj := b - min
+               // propagate carry if necessary
+               for x.Bit(badj) != 0 {
+                       x.SetBit(x, badj, 0)
+                       badj++
+               }
+               x.SetBit(x, badj, 1)
+       }
+
+       // create corresponding float
+       z := new(Float).SetInt(x) // normalized
+       z.setExp(int64(z.exp) + int64(min))
+       return z
+}
+
+func TestFromBits(t *testing.T) {
+       for _, test := range []struct {
+               bits []int
+               want string
+       }{
+               // all different bit numbers
+               {nil, "0"},
+               {[]int{0}, "0x.8p1"},
+               {[]int{1}, "0x.8p2"},
+               {[]int{-1}, "0x.8p0"},
+               {[]int{63}, "0x.8p64"},
+               {[]int{33, -30}, "0x.8000000000000001p34"},
+               {[]int{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p256"},
+
+               // multiple equal bit numbers
+               {[]int{0, 0}, "0x.8p2"},
+               {[]int{0, 0, 0, 0}, "0x.8p3"},
+               {[]int{0, 1, 0}, "0x.8p3"},
+               {append([]int{2, 1, 0} /* 7 */, []int{3, 1} /* 10 */ ...), "0x.88p5" /* 17 */},
+       } {
+               f := fromBits(test.bits...)
+               if got := f.Format('p', 0); got != test.want {
+                       t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
+               }
+       }
+}
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
new file mode 100644 (file)
index 0000000..06c1f14
--- /dev/null
@@ -0,0 +1,255 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements float-to-string conversion functions.
+
+package big
+
+import (
+       "fmt"
+       "io"
+       "strconv"
+       "strings"
+)
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s must be a floating-point number of the same format as accepted
+// by Scan, with number prefixes permitted.
+func (z *Float) SetString(s string) (*Float, bool) {
+       r := strings.NewReader(s)
+
+       f, _, err := z.Scan(r, 0)
+       if err != nil {
+               return nil, false
+       }
+
+       // there should be no unread characters left
+       if _, _, err = r.ReadRune(); err != io.EOF {
+               return nil, false
+       }
+
+       return f, true
+}
+
+// Scan scans the number corresponding to the longest possible prefix
+// of r representing a floating-point number with a mantissa in the
+// given conversion base (the exponent is always a decimal number).
+// It returns the corresponding Float f, the actual base b, and an
+// error err, if any. The number must be of the form:
+//
+//     number   = [ sign ] [ prefix ] mantissa [ exponent ] .
+//     sign     = "+" | "-" .
+//      prefix   = "0" ( "x" | "X" | "b" | "B" ) .
+//     mantissa = digits | digits "." [ digits ] | "." digits .
+//     exponent = ( "E" | "e" | "p" ) [ sign ] digits .
+//     digits   = digit { digit } .
+//     digit    = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
+//
+// The base argument must be 0 or a value between 2 through MaxBase.
+//
+// For base 0, the number prefix determines the actual base: A prefix of
+// ``0x'' or ``0X'' selects base 16, and a ``0b'' or ``0B'' prefix selects
+// base 2; otherwise, the actual base is 10 and no prefix is permitted.
+// The octal prefix ``0'' is not supported.
+//
+// A "p" exponent indicates power of 2 for the exponent; for instance "1.2p3"
+// with base 0 or 10 corresponds to the value 1.2 * 2**3.
+//
+// BUG(gri) This signature conflicts with Scan(s fmt.ScanState, ch rune) error.
+func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
+       // sign
+       z.neg, err = scanSign(r)
+       if err != nil {
+               return
+       }
+
+       // mantissa
+       var ecorr int // decimal exponent correction; valid if <= 0
+       z.mant, b, ecorr, err = z.mant.scan(r, base, true)
+       if err != nil {
+               return
+       }
+
+       // exponent
+       var exp int64
+       var ebase int
+       exp, ebase, err = scanExponent(r)
+       if err != nil {
+               return
+       }
+       // special-case 0
+       if len(z.mant) == 0 {
+               z.exp = 0
+               f = z
+               return
+       }
+       // len(z.mant) > 0
+
+       // determine binary (exp2) and decimal (exp) exponent
+       exp2 := int64(len(z.mant)*_W - int(fnorm(z.mant)))
+       if ebase == 2 {
+               exp2 += exp
+               exp = 0
+       }
+       if ecorr < 0 {
+               exp += int64(ecorr)
+       }
+
+       z.setExp(exp2)
+       if exp == 0 {
+               // no decimal exponent
+               z.round(0)
+               f = z
+               return
+       }
+       // exp != 0
+
+       // compute decimal exponent power
+       expabs := exp
+       if expabs < 0 {
+               expabs = -expabs
+       }
+       powTen := new(Float).SetInt(new(Int).SetBits(nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)))
+
+       // correct result
+       if exp < 0 {
+               z.uquo(z, powTen)
+       } else {
+               z.umul(z, powTen)
+       }
+
+       f = z
+       return
+}
+
+// Parse is like z.Scan(r, base), but instead of reading from an
+// io.ByteScanner, it parses the string s. An error is returned if the
+// string contains invalid or trailing characters not belonging to the
+// number.
+//
+// TODO(gri) define possible errors more precisely
+func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
+       r := strings.NewReader(s)
+
+       if f, b, err = z.Scan(r, base); err != nil {
+               return
+       }
+
+       // entire string must have been consumed
+       var ch byte
+       if ch, err = r.ReadByte(); err != io.EOF {
+               if err == nil {
+                       err = fmt.Errorf("expected end of string, found %q", ch)
+               }
+       }
+
+       return
+}
+
+// ScanFloat is like f.Scan(r, base) with f set to the given precision
+// and rounding mode.
+func ScanFloat(r io.ByteScanner, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
+       return NewFloat(0, prec, mode).Scan(r, base)
+}
+
+// ParseFloat is like f.Parse(s, base) with f set to the given precision
+// and rounding mode.
+func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
+       return NewFloat(0, prec, mode).Parse(s, base)
+}
+
+// Format converts the floating-point number x to a string according
+// to the given format and precision prec. The format is one of:
+//
+//     'e'     -d.dddde±dd, decimal exponent
+//     'E'     -d.ddddE±dd, decimal exponent
+//     'f'     -ddddd.dddd, no exponent
+//     'g'     like 'e' for large exponents, like 'f' otherwise
+//     'G'     like 'E' for large exponents, like 'f' otherwise
+//     'b'     -ddddddp±dd, binary exponent
+//     'p'     -0x.dddp±dd, binary exponent, hexadecimal mantissa
+//
+// For the binary exponent formats, the mantissa is printed in normalized form:
+//
+//     'b'     decimal integer mantissa using x.Precision() bits, or -0
+//     'p'     hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
+//
+// The precision prec controls the number of digits (excluding the exponent)
+// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
+// it is the number of digits after the decimal point. For 'g' and 'G' it is
+// the total number of digits. A negative precision selects the smallest
+// number of digits necessary such that ParseFloat will return f exactly.
+// The prec value is ignored for the 'b' or 'p' format.
+//
+// BUG(gri) Currently, Format only accepts the 'b' and 'p' format.
+func (x *Float) Format(format byte, prec int) string {
+       const extra = 10 // TODO(gri) determine a good/better value here
+       return string(x.Append(make([]byte, 0, prec+extra), format, prec))
+}
+
+// Append appends the string form of the floating-point number x,
+// as generated by x.Format, to buf and returns the extended buffer.
+func (x *Float) Append(buf []byte, format byte, prec int) []byte {
+       switch format {
+       case 'b':
+               return x.bstring(buf)
+       case 'p':
+               return x.pstring(buf)
+       }
+       return append(buf, fmt.Sprintf(`%%!c`, format)...)
+}
+
+// BUG(gri): Currently, String uses the 'p' (rather than 'g') format.
+func (x *Float) String() string {
+       return x.Format('p', 0)
+}
+
+// bstring appends the string of x in the format ["-"] mantissa "p" exponent
+// with a decimal mantissa and a binary exponent, or ["-"] "0" if x is zero,
+// and returns the extended buffer.
+// The mantissa is normalized such that is uses x.Precision() bits in binary
+// representation.
+func (x *Float) bstring(buf []byte) []byte {
+       // TODO(gri) handle Inf
+       if x.neg {
+               buf = append(buf, '-')
+       }
+       if len(x.mant) == 0 {
+               return append(buf, '0')
+       }
+       // x != 0
+       // normalize mantissa
+       m := x.mant
+       t := uint(len(x.mant)*_W) - x.prec // 0 <= t < _W
+       if t > 0 {
+               m = nat(nil).shr(m, t)
+       }
+       buf = append(buf, m.decimalString()...)
+       buf = append(buf, 'p')
+       e := int64(x.exp) - int64(x.prec)
+       if e >= 0 {
+               buf = append(buf, '+')
+       }
+       return strconv.AppendInt(buf, e, 10)
+}
+
+// pstring appends the string of x in the format ["-"] "0x." mantissa "p" exponent
+// with a hexadecimal mantissa and a binary exponent, or ["-"] "0" if x is zero,
+// ad returns the extended buffer.
+// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
+func (x *Float) pstring(buf []byte) []byte {
+       // TODO(gri) handle Inf
+       if x.neg {
+               buf = append(buf, '-')
+       }
+       if len(x.mant) == 0 {
+               return append(buf, '0')
+       }
+       // x != 0
+       // mantissa is stored in normalized form
+       buf = append(buf, "0x."...)
+       buf = append(buf, strings.TrimRight(x.mant.hexString(), "0")...)
+       buf = append(buf, 'p')
+       return strconv.AppendInt(buf, int64(x.exp), 10)
+}
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
new file mode 100644 (file)
index 0000000..0e8bfb3
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+       "strconv"
+       "testing"
+)
+
+func TestFloatSetFloat64String(t *testing.T) {
+       for _, test := range []struct {
+               s string
+               x float64
+       }{
+               {"0", 0},
+               {"-0", -0},
+               {"+0", 0},
+               {"1", 1},
+               {"-1", -1},
+               {"+1", 1},
+               {"1.234", 1.234},
+               {"-1.234", -1.234},
+               {"+1.234", 1.234},
+               {".1", 0.1},
+               {"1.", 1},
+               {"+1.", 1},
+
+               {"0e100", 0},
+               {"-0e+100", 0},
+               {"+0e-100", 0},
+               {"0E100", 0},
+               {"-0E+100", 0},
+               {"+0E-100", 0},
+               {"0p100", 0},
+               {"-0p+100", 0},
+               {"+0p-100", 0},
+
+               {"1.e10", 1e10},
+               {"1e+10", 1e10},
+               {"+1e-10", 1e-10},
+               {"1E10", 1e10},
+               {"1.E+10", 1e10},
+               {"+1E-10", 1e-10},
+               {"1p10", 1 << 10},
+               {"1p+10", 1 << 10},
+               {"+1.p-10", 1.0 / (1 << 10)},
+
+               {"-687436.79457e-245", -687436.79457e-245},
+               {"-687436.79457E245", -687436.79457e245},
+               {"1024.p-12", 0.25},
+               {"-1.p10", -1024},
+               {"0.25p2", 1},
+
+               {".0000000000000000000000000000000000000001", 1e-40},
+               {"+10000000000000000000000000000000000000000e-0", 1e40},
+       } {
+               var x Float
+               x.prec = 53 // TODO(gri) find better solution
+               _, ok := x.SetString(test.s)
+               if !ok {
+                       t.Errorf("%s: parse error", test.s)
+                       continue
+               }
+               f, _ := x.Float64()
+               want := new(Float).SetFloat64(test.x)
+               if x.Cmp(want) != 0 {
+                       t.Errorf("%s: got %s (%v); want %v", test.s, &x, f, test.x)
+               }
+       }
+}
+
+func TestFloatFormat(t *testing.T) {
+       for _, test := range []struct {
+               x      string
+               format byte
+               prec   int
+               want   string
+       }{
+               {"0", 'b', 0, "0"},
+               {"-0", 'b', 0, "-0"},
+               {"1.0", 'b', 0, "4503599627370496p-52"},
+               {"-1.0", 'b', 0, "-4503599627370496p-52"},
+               {"4503599627370496", 'b', 0, "4503599627370496p+0"},
+
+               {"0", 'p', 0, "0"},
+               {"-0", 'p', 0, "-0"},
+               {"1024.0", 'p', 0, "0x.8p11"},
+               {"-1024.0", 'p', 0, "-0x.8p11"},
+       } {
+               f64, err := strconv.ParseFloat(test.x, 64)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+
+               f := new(Float).SetFloat64(f64)
+               got := f.Format(test.format, test.prec)
+               if got != test.want {
+                       t.Errorf("%v: got %s; want %s", test, got, test.want)
+               }
+
+               if test.format == 'b' && f64 == 0 {
+                       continue // 'b' format in strconv.Float requires knowledge of bias for 0.0
+               }
+               if test.format == 'p' {
+                       continue // 'p' format not supported in strconv.Format
+               }
+
+               // verify that Float format matches strconv format
+               want := strconv.FormatFloat(f64, test.format, test.prec, 64)
+               if got != want {
+                       t.Errorf("%v: got %s; want %s", test, got, want)
+               }
+       }
+}
index 38297707436e845a9b72a888dd2bc054e35b18be..5c1b2cd7653fa55a21eddbd7bc68d4cdd965919a 100644 (file)
@@ -321,195 +321,6 @@ func (x *Int) Cmp(y *Int) (r int) {
        return
 }
 
-func (x *Int) String() string {
-       switch {
-       case x == nil:
-               return "<nil>"
-       case x.neg:
-               return "-" + x.abs.decimalString()
-       }
-       return x.abs.decimalString()
-}
-
-func charset(ch rune) string {
-       switch ch {
-       case 'b':
-               return lowercaseDigits[0:2]
-       case 'o':
-               return lowercaseDigits[0:8]
-       case 'd', 's', 'v':
-               return lowercaseDigits[0:10]
-       case 'x':
-               return lowercaseDigits[0:16]
-       case 'X':
-               return uppercaseDigits[0:16]
-       }
-       return "" // unknown format
-}
-
-// write count copies of text to s
-func writeMultiple(s fmt.State, text string, count int) {
-       if len(text) > 0 {
-               b := []byte(text)
-               for ; count > 0; count-- {
-                       s.Write(b)
-               }
-       }
-}
-
-// Format is a support routine for fmt.Formatter. It accepts
-// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
-// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
-// Also supported are the full suite of package fmt's format
-// verbs for integral types, including '+', '-', and ' '
-// for sign control, '#' for leading zero in octal and for
-// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
-// respectively, specification of minimum digits precision,
-// output field width, space or zero padding, and left or
-// right justification.
-//
-func (x *Int) Format(s fmt.State, ch rune) {
-       cs := charset(ch)
-
-       // special cases
-       switch {
-       case cs == "":
-               // unknown format
-               fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
-               return
-       case x == nil:
-               fmt.Fprint(s, "<nil>")
-               return
-       }
-
-       // determine sign character
-       sign := ""
-       switch {
-       case x.neg:
-               sign = "-"
-       case s.Flag('+'): // supersedes ' ' when both specified
-               sign = "+"
-       case s.Flag(' '):
-               sign = " "
-       }
-
-       // determine prefix characters for indicating output base
-       prefix := ""
-       if s.Flag('#') {
-               switch ch {
-               case 'o': // octal
-                       prefix = "0"
-               case 'x': // hexadecimal
-                       prefix = "0x"
-               case 'X':
-                       prefix = "0X"
-               }
-       }
-
-       // determine digits with base set by len(cs) and digit characters from cs
-       digits := x.abs.string(cs)
-
-       // number of characters for the three classes of number padding
-       var left int   // space characters to left of digits for right justification ("%8d")
-       var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
-       var right int  // space characters to right of digits for left justification ("%-8d")
-
-       // determine number padding from precision: the least number of digits to output
-       precision, precisionSet := s.Precision()
-       if precisionSet {
-               switch {
-               case len(digits) < precision:
-                       zeroes = precision - len(digits) // count of zero padding
-               case digits == "0" && precision == 0:
-                       return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
-               }
-       }
-
-       // determine field pad from width: the least number of characters to output
-       length := len(sign) + len(prefix) + zeroes + len(digits)
-       if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
-               switch d := width - length; {
-               case s.Flag('-'):
-                       // pad on the right with spaces; supersedes '0' when both specified
-                       right = d
-               case s.Flag('0') && !precisionSet:
-                       // pad with zeroes unless precision also specified
-                       zeroes = d
-               default:
-                       // pad on the left with spaces
-                       left = d
-               }
-       }
-
-       // print number as [left pad][sign][prefix][zero pad][digits][right pad]
-       writeMultiple(s, " ", left)
-       writeMultiple(s, sign, 1)
-       writeMultiple(s, prefix, 1)
-       writeMultiple(s, "0", zeroes)
-       writeMultiple(s, digits, 1)
-       writeMultiple(s, " ", right)
-}
-
-// scan sets z to the integer value corresponding to the longest possible prefix
-// read from r representing a signed integer number in a given conversion base.
-// It returns z, the actual conversion base used, and an error, if any. In the
-// error case, the value of z is undefined but the returned value is nil. The
-// syntax follows the syntax of integer literals in Go.
-//
-// The base argument must be 0 or a value from 2 through MaxBase. If the base
-// is 0, the string prefix determines the actual conversion base. A prefix of
-// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
-// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
-//
-func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, error) {
-       // determine sign
-       ch, _, err := r.ReadRune()
-       if err != nil {
-               return nil, 0, err
-       }
-       neg := false
-       switch ch {
-       case '-':
-               neg = true
-       case '+': // nothing to do
-       default:
-               r.UnreadRune()
-       }
-
-       // determine mantissa
-       z.abs, base, err = z.abs.scan(r, base)
-       if err != nil {
-               return nil, base, err
-       }
-       z.neg = len(z.abs) > 0 && neg // 0 has no sign
-
-       return z, base, nil
-}
-
-// Scan is a support routine for fmt.Scanner; it sets z to the value of
-// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
-// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
-func (z *Int) Scan(s fmt.ScanState, ch rune) error {
-       s.SkipSpace() // skip leading space characters
-       base := 0
-       switch ch {
-       case 'b':
-               base = 2
-       case 'o':
-               base = 8
-       case 'd':
-               base = 10
-       case 'x', 'X':
-               base = 16
-       case 's', 'v':
-               // let scan determine the base
-       default:
-               return errors.New("Int.Scan: invalid verb")
-       }
-       _, _, err := z.scan(s, base)
-       return err
-}
-
 // low32 returns the least significant 32 bits of z.
 func low32(z nat) uint32 {
        if len(z) == 0 {
@@ -561,7 +372,7 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
        if err != nil {
                return nil, false
        }
-       _, _, err = r.ReadRune()
+       _, err = r.ReadByte()
        if err != io.EOF {
                return nil, false
        }
@@ -736,7 +547,7 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
 
 // ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
 // If it returns true, x is prime with probability 1 - 1/4^n.
-// If it returns false, x is not prime. n must be >0.
+// If it returns false, x is not prime. n must be > 0.
 func (x *Int) ProbablyPrime(n int) bool {
        if n <= 0 {
                panic("non-positive n for ProbablyPrime")
index 520fcb31d5802ad89601d2370d59f1c8d6d2095f..1418dca3352adeaa49ed032e822f29770049eda4 100644 (file)
@@ -219,337 +219,6 @@ func TestMulRangeZ(t *testing.T) {
        }
 }
 
-var stringTests = []struct {
-       in   string
-       out  string
-       base int
-       val  int64
-       ok   bool
-}{
-       {in: "", ok: false},
-       {in: "a", ok: false},
-       {in: "z", ok: false},
-       {in: "+", ok: false},
-       {in: "-", ok: false},
-       {in: "0b", ok: false},
-       {in: "0x", ok: false},
-       {in: "2", base: 2, ok: false},
-       {in: "0b2", base: 0, ok: false},
-       {in: "08", ok: false},
-       {in: "8", base: 8, ok: false},
-       {in: "0xg", base: 0, ok: false},
-       {in: "g", base: 16, ok: false},
-       {"0", "0", 0, 0, true},
-       {"0", "0", 10, 0, true},
-       {"0", "0", 16, 0, true},
-       {"+0", "0", 0, 0, true},
-       {"-0", "0", 0, 0, true},
-       {"10", "10", 0, 10, true},
-       {"10", "10", 10, 10, true},
-       {"10", "10", 16, 16, true},
-       {"-10", "-10", 16, -16, true},
-       {"+10", "10", 16, 16, true},
-       {"0x10", "16", 0, 16, true},
-       {in: "0x10", base: 16, ok: false},
-       {"-0x10", "-16", 0, -16, true},
-       {"+0x10", "16", 0, 16, true},
-       {"00", "0", 0, 0, true},
-       {"0", "0", 8, 0, true},
-       {"07", "7", 0, 7, true},
-       {"7", "7", 8, 7, true},
-       {"023", "19", 0, 19, true},
-       {"23", "23", 8, 19, true},
-       {"cafebabe", "cafebabe", 16, 0xcafebabe, true},
-       {"0b0", "0", 0, 0, true},
-       {"-111", "-111", 2, -7, true},
-       {"-0b111", "-7", 0, -7, true},
-       {"0b1001010111", "599", 0, 0x257, true},
-       {"1001010111", "1001010111", 2, 0x257, true},
-}
-
-func format(base int) string {
-       switch base {
-       case 2:
-               return "%b"
-       case 8:
-               return "%o"
-       case 16:
-               return "%x"
-       }
-       return "%d"
-}
-
-func TestGetString(t *testing.T) {
-       z := new(Int)
-       for i, test := range stringTests {
-               if !test.ok {
-                       continue
-               }
-               z.SetInt64(test.val)
-
-               if test.base == 10 {
-                       s := z.String()
-                       if s != test.out {
-                               t.Errorf("#%da got %s; want %s", i, s, test.out)
-                       }
-               }
-
-               s := fmt.Sprintf(format(test.base), z)
-               if s != test.out {
-                       t.Errorf("#%db got %s; want %s", i, s, test.out)
-               }
-       }
-}
-
-func TestSetString(t *testing.T) {
-       tmp := new(Int)
-       for i, test := range stringTests {
-               // initialize to a non-zero value so that issues with parsing
-               // 0 are detected
-               tmp.SetInt64(1234567890)
-               n1, ok1 := new(Int).SetString(test.in, test.base)
-               n2, ok2 := tmp.SetString(test.in, test.base)
-               expected := NewInt(test.val)
-               if ok1 != test.ok || ok2 != test.ok {
-                       t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
-                       continue
-               }
-               if !ok1 {
-                       if n1 != nil {
-                               t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
-                       }
-                       continue
-               }
-               if !ok2 {
-                       if n2 != nil {
-                               t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
-                       }
-                       continue
-               }
-
-               if ok1 && !isNormalized(n1) {
-                       t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
-               }
-               if ok2 && !isNormalized(n2) {
-                       t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
-               }
-
-               if n1.Cmp(expected) != 0 {
-                       t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
-               }
-               if n2.Cmp(expected) != 0 {
-                       t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
-               }
-       }
-}
-
-var formatTests = []struct {
-       input  string
-       format string
-       output string
-}{
-       {"<nil>", "%x", "<nil>"},
-       {"<nil>", "%#x", "<nil>"},
-       {"<nil>", "%#y", "%!y(big.Int=<nil>)"},
-
-       {"10", "%b", "1010"},
-       {"10", "%o", "12"},
-       {"10", "%d", "10"},
-       {"10", "%v", "10"},
-       {"10", "%x", "a"},
-       {"10", "%X", "A"},
-       {"-10", "%X", "-A"},
-       {"10", "%y", "%!y(big.Int=10)"},
-       {"-10", "%y", "%!y(big.Int=-10)"},
-
-       {"10", "%#b", "1010"},
-       {"10", "%#o", "012"},
-       {"10", "%#d", "10"},
-       {"10", "%#v", "10"},
-       {"10", "%#x", "0xa"},
-       {"10", "%#X", "0XA"},
-       {"-10", "%#X", "-0XA"},
-       {"10", "%#y", "%!y(big.Int=10)"},
-       {"-10", "%#y", "%!y(big.Int=-10)"},
-
-       {"1234", "%d", "1234"},
-       {"1234", "%3d", "1234"},
-       {"1234", "%4d", "1234"},
-       {"-1234", "%d", "-1234"},
-       {"1234", "% 5d", " 1234"},
-       {"1234", "%+5d", "+1234"},
-       {"1234", "%-5d", "1234 "},
-       {"1234", "%x", "4d2"},
-       {"1234", "%X", "4D2"},
-       {"-1234", "%3x", "-4d2"},
-       {"-1234", "%4x", "-4d2"},
-       {"-1234", "%5x", " -4d2"},
-       {"-1234", "%-5x", "-4d2 "},
-       {"1234", "%03d", "1234"},
-       {"1234", "%04d", "1234"},
-       {"1234", "%05d", "01234"},
-       {"1234", "%06d", "001234"},
-       {"-1234", "%06d", "-01234"},
-       {"1234", "%+06d", "+01234"},
-       {"1234", "% 06d", " 01234"},
-       {"1234", "%-6d", "1234  "},
-       {"1234", "%-06d", "1234  "},
-       {"-1234", "%-06d", "-1234 "},
-
-       {"1234", "%.3d", "1234"},
-       {"1234", "%.4d", "1234"},
-       {"1234", "%.5d", "01234"},
-       {"1234", "%.6d", "001234"},
-       {"-1234", "%.3d", "-1234"},
-       {"-1234", "%.4d", "-1234"},
-       {"-1234", "%.5d", "-01234"},
-       {"-1234", "%.6d", "-001234"},
-
-       {"1234", "%8.3d", "    1234"},
-       {"1234", "%8.4d", "    1234"},
-       {"1234", "%8.5d", "   01234"},
-       {"1234", "%8.6d", "  001234"},
-       {"-1234", "%8.3d", "   -1234"},
-       {"-1234", "%8.4d", "   -1234"},
-       {"-1234", "%8.5d", "  -01234"},
-       {"-1234", "%8.6d", " -001234"},
-
-       {"1234", "%+8.3d", "   +1234"},
-       {"1234", "%+8.4d", "   +1234"},
-       {"1234", "%+8.5d", "  +01234"},
-       {"1234", "%+8.6d", " +001234"},
-       {"-1234", "%+8.3d", "   -1234"},
-       {"-1234", "%+8.4d", "   -1234"},
-       {"-1234", "%+8.5d", "  -01234"},
-       {"-1234", "%+8.6d", " -001234"},
-
-       {"1234", "% 8.3d", "    1234"},
-       {"1234", "% 8.4d", "    1234"},
-       {"1234", "% 8.5d", "   01234"},
-       {"1234", "% 8.6d", "  001234"},
-       {"-1234", "% 8.3d", "   -1234"},
-       {"-1234", "% 8.4d", "   -1234"},
-       {"-1234", "% 8.5d", "  -01234"},
-       {"-1234", "% 8.6d", " -001234"},
-
-       {"1234", "%.3x", "4d2"},
-       {"1234", "%.4x", "04d2"},
-       {"1234", "%.5x", "004d2"},
-       {"1234", "%.6x", "0004d2"},
-       {"-1234", "%.3x", "-4d2"},
-       {"-1234", "%.4x", "-04d2"},
-       {"-1234", "%.5x", "-004d2"},
-       {"-1234", "%.6x", "-0004d2"},
-
-       {"1234", "%8.3x", "     4d2"},
-       {"1234", "%8.4x", "    04d2"},
-       {"1234", "%8.5x", "   004d2"},
-       {"1234", "%8.6x", "  0004d2"},
-       {"-1234", "%8.3x", "    -4d2"},
-       {"-1234", "%8.4x", "   -04d2"},
-       {"-1234", "%8.5x", "  -004d2"},
-       {"-1234", "%8.6x", " -0004d2"},
-
-       {"1234", "%+8.3x", "    +4d2"},
-       {"1234", "%+8.4x", "   +04d2"},
-       {"1234", "%+8.5x", "  +004d2"},
-       {"1234", "%+8.6x", " +0004d2"},
-       {"-1234", "%+8.3x", "    -4d2"},
-       {"-1234", "%+8.4x", "   -04d2"},
-       {"-1234", "%+8.5x", "  -004d2"},
-       {"-1234", "%+8.6x", " -0004d2"},
-
-       {"1234", "% 8.3x", "     4d2"},
-       {"1234", "% 8.4x", "    04d2"},
-       {"1234", "% 8.5x", "   004d2"},
-       {"1234", "% 8.6x", "  0004d2"},
-       {"1234", "% 8.7x", " 00004d2"},
-       {"1234", "% 8.8x", " 000004d2"},
-       {"-1234", "% 8.3x", "    -4d2"},
-       {"-1234", "% 8.4x", "   -04d2"},
-       {"-1234", "% 8.5x", "  -004d2"},
-       {"-1234", "% 8.6x", " -0004d2"},
-       {"-1234", "% 8.7x", "-00004d2"},
-       {"-1234", "% 8.8x", "-000004d2"},
-
-       {"1234", "%-8.3d", "1234    "},
-       {"1234", "%-8.4d", "1234    "},
-       {"1234", "%-8.5d", "01234   "},
-       {"1234", "%-8.6d", "001234  "},
-       {"1234", "%-8.7d", "0001234 "},
-       {"1234", "%-8.8d", "00001234"},
-       {"-1234", "%-8.3d", "-1234   "},
-       {"-1234", "%-8.4d", "-1234   "},
-       {"-1234", "%-8.5d", "-01234  "},
-       {"-1234", "%-8.6d", "-001234 "},
-       {"-1234", "%-8.7d", "-0001234"},
-       {"-1234", "%-8.8d", "-00001234"},
-
-       {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
-
-       {"0", "%.d", ""},
-       {"0", "%.0d", ""},
-       {"0", "%3.d", ""},
-}
-
-func TestFormat(t *testing.T) {
-       for i, test := range formatTests {
-               var x *Int
-               if test.input != "<nil>" {
-                       var ok bool
-                       x, ok = new(Int).SetString(test.input, 0)
-                       if !ok {
-                               t.Errorf("#%d failed reading input %s", i, test.input)
-                       }
-               }
-               output := fmt.Sprintf(test.format, x)
-               if output != test.output {
-                       t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
-               }
-       }
-}
-
-var scanTests = []struct {
-       input     string
-       format    string
-       output    string
-       remaining int
-}{
-       {"1010", "%b", "10", 0},
-       {"0b1010", "%v", "10", 0},
-       {"12", "%o", "10", 0},
-       {"012", "%v", "10", 0},
-       {"10", "%d", "10", 0},
-       {"10", "%v", "10", 0},
-       {"a", "%x", "10", 0},
-       {"0xa", "%v", "10", 0},
-       {"A", "%X", "10", 0},
-       {"-A", "%X", "-10", 0},
-       {"+0b1011001", "%v", "89", 0},
-       {"0xA", "%v", "10", 0},
-       {"0 ", "%v", "0", 1},
-       {"2+3", "%v", "2", 2},
-       {"0XABC 12", "%v", "2748", 3},
-}
-
-func TestScan(t *testing.T) {
-       var buf bytes.Buffer
-       for i, test := range scanTests {
-               x := new(Int)
-               buf.Reset()
-               buf.WriteString(test.input)
-               if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
-                       t.Errorf("#%d error: %s", i, err)
-               }
-               if x.String() != test.output {
-                       t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
-               }
-               if buf.Len() != test.remaining {
-                       t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
-               }
-       }
-}
-
 // Examples from the Go Language Spec, section "Arithmetic operators"
 var divisionSignsTests = []struct {
        x, y int64
@@ -621,6 +290,44 @@ func TestDivisionSigns(t *testing.T) {
        }
 }
 
+var bitsTests = []nat{
+       nil,
+       {0},
+       {1},
+       {0, 1, 2, 3, 4},
+       {4, 3, 2, 1, 0},
+       {4, 3, 2, 1, 0, 0, 0, 0},
+}
+
+func norm(x nat) nat {
+       i := len(x)
+       for i > 0 && x[i-1] == 0 {
+               i--
+       }
+       return x[:i]
+}
+
+func TestBits(t *testing.T) {
+       for _, test := range bitsTests {
+               var z Int
+               z.neg = true
+               got := z.SetBits(test)
+               want := norm(test)
+               if got.abs.cmp(want) != 0 {
+                       t.Errorf("SetBits(%v) = %v; want %v", test, got.abs, want)
+               }
+
+               if got.neg {
+                       t.Errorf("SetBits(%v): got negative result")
+               }
+
+               bits := nat(z.Bits())
+               if bits.cmp(want) != 0 {
+                       t.Errorf("%v.Bits() = %v; want %v", z.abs, bits, want)
+               }
+       }
+}
+
 func checkSetBytes(b []byte) bool {
        hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
        hex2 := hex.EncodeToString(b)
@@ -962,6 +669,8 @@ var primes = []string{
 }
 
 var composites = []string{
+       "0",
+       "1",
        "21284175091214687912771199898307297748211672914763848041968395774954376176754",
        "6084766654921918907427900243509372380954290099172559290432744450051395395951",
        "84594350493221918389213352992032324280367711247940675652888030554255915464401",
diff --git a/src/math/big/intconv.go b/src/math/big/intconv.go
new file mode 100644 (file)
index 0000000..9c68a22
--- /dev/null
@@ -0,0 +1,228 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements int-to-string conversion functions.
+
+package big
+
+import (
+       "errors"
+       "fmt"
+       "io"
+)
+
+func (x *Int) String() string {
+       switch {
+       case x == nil:
+               return "<nil>"
+       case x.neg:
+               return "-" + x.abs.decimalString()
+       }
+       return x.abs.decimalString()
+}
+
+func charset(ch rune) string {
+       switch ch {
+       case 'b':
+               return lowercaseDigits[0:2]
+       case 'o':
+               return lowercaseDigits[0:8]
+       case 'd', 's', 'v':
+               return lowercaseDigits[0:10]
+       case 'x':
+               return lowercaseDigits[0:16]
+       case 'X':
+               return uppercaseDigits[0:16]
+       }
+       return "" // unknown format
+}
+
+// write count copies of text to s
+func writeMultiple(s fmt.State, text string, count int) {
+       if len(text) > 0 {
+               b := []byte(text)
+               for ; count > 0; count-- {
+                       s.Write(b)
+               }
+       }
+}
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
+// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+// Also supported are the full suite of package fmt's format
+// verbs for integral types, including '+', '-', and ' '
+// for sign control, '#' for leading zero in octal and for
+// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
+// respectively, specification of minimum digits precision,
+// output field width, space or zero padding, and left or
+// right justification.
+//
+func (x *Int) Format(s fmt.State, ch rune) {
+       cs := charset(ch)
+
+       // special cases
+       switch {
+       case cs == "":
+               // unknown format
+               fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
+               return
+       case x == nil:
+               fmt.Fprint(s, "<nil>")
+               return
+       }
+
+       // determine sign character
+       sign := ""
+       switch {
+       case x.neg:
+               sign = "-"
+       case s.Flag('+'): // supersedes ' ' when both specified
+               sign = "+"
+       case s.Flag(' '):
+               sign = " "
+       }
+
+       // determine prefix characters for indicating output base
+       prefix := ""
+       if s.Flag('#') {
+               switch ch {
+               case 'o': // octal
+                       prefix = "0"
+               case 'x': // hexadecimal
+                       prefix = "0x"
+               case 'X':
+                       prefix = "0X"
+               }
+       }
+
+       // determine digits with base set by len(cs) and digit characters from cs
+       digits := x.abs.string(cs)
+
+       // number of characters for the three classes of number padding
+       var left int   // space characters to left of digits for right justification ("%8d")
+       var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
+       var right int  // space characters to right of digits for left justification ("%-8d")
+
+       // determine number padding from precision: the least number of digits to output
+       precision, precisionSet := s.Precision()
+       if precisionSet {
+               switch {
+               case len(digits) < precision:
+                       zeroes = precision - len(digits) // count of zero padding
+               case digits == "0" && precision == 0:
+                       return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
+               }
+       }
+
+       // determine field pad from width: the least number of characters to output
+       length := len(sign) + len(prefix) + zeroes + len(digits)
+       if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
+               switch d := width - length; {
+               case s.Flag('-'):
+                       // pad on the right with spaces; supersedes '0' when both specified
+                       right = d
+               case s.Flag('0') && !precisionSet:
+                       // pad with zeroes unless precision also specified
+                       zeroes = d
+               default:
+                       // pad on the left with spaces
+                       left = d
+               }
+       }
+
+       // print number as [left pad][sign][prefix][zero pad][digits][right pad]
+       writeMultiple(s, " ", left)
+       writeMultiple(s, sign, 1)
+       writeMultiple(s, prefix, 1)
+       writeMultiple(s, "0", zeroes)
+       writeMultiple(s, digits, 1)
+       writeMultiple(s, " ", right)
+}
+
+// scan sets z to the integer value corresponding to the longest possible prefix
+// read from r representing a signed integer number in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined but the returned value is nil. The
+// syntax follows the syntax of integer literals in Go.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) {
+       // determine sign
+       neg, err := scanSign(r)
+       if err != nil {
+               return nil, 0, err
+       }
+
+       // determine mantissa
+       z.abs, base, _, err = z.abs.scan(r, base, false)
+       if err != nil {
+               return nil, base, err
+       }
+       z.neg = len(z.abs) > 0 && neg // 0 has no sign
+
+       return z, base, nil
+}
+
+func scanSign(r io.ByteScanner) (neg bool, err error) {
+       var ch byte
+       if ch, err = r.ReadByte(); err != nil {
+               return false, err
+       }
+       switch ch {
+       case '-':
+               neg = true
+       case '+':
+               // nothing to do
+       default:
+               r.UnreadByte()
+       }
+       return
+}
+
+// byteReader is a local wrapper around fmt.ScanState;
+// it implements the ByteReader interface.
+type byteReader struct {
+       fmt.ScanState
+}
+
+func (r byteReader) ReadByte() (byte, error) {
+       ch, size, err := r.ReadRune()
+       if size != 1 && err == nil {
+               err = fmt.Errorf("invalid rune %#U", ch)
+       }
+       return byte(ch), err
+}
+
+func (r byteReader) UnreadByte() error {
+       return r.UnreadRune()
+}
+
+// Scan is a support routine for fmt.Scanner; it sets z to the value of
+// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
+// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+func (z *Int) Scan(s fmt.ScanState, ch rune) error {
+       s.SkipSpace() // skip leading space characters
+       base := 0
+       switch ch {
+       case 'b':
+               base = 2
+       case 'o':
+               base = 8
+       case 'd':
+               base = 10
+       case 'x', 'X':
+               base = 16
+       case 's', 'v':
+               // let scan determine the base
+       default:
+               return errors.New("Int.Scan: invalid verb")
+       }
+       _, _, err := z.scan(byteReader{s}, base)
+       return err
+}
diff --git a/src/math/big/intconv_test.go b/src/math/big/intconv_test.go
new file mode 100644 (file)
index 0000000..2deb84b
--- /dev/null
@@ -0,0 +1,342 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+       "bytes"
+       "fmt"
+       "testing"
+)
+
+var stringTests = []struct {
+       in   string
+       out  string
+       base int
+       val  int64
+       ok   bool
+}{
+       {in: "", ok: false},
+       {in: "a", ok: false},
+       {in: "z", ok: false},
+       {in: "+", ok: false},
+       {in: "-", ok: false},
+       {in: "0b", ok: false},
+       {in: "0x", ok: false},
+       {in: "2", base: 2, ok: false},
+       {in: "0b2", base: 0, ok: false},
+       {in: "08", ok: false},
+       {in: "8", base: 8, ok: false},
+       {in: "0xg", base: 0, ok: false},
+       {in: "g", base: 16, ok: false},
+       {"0", "0", 0, 0, true},
+       {"0", "0", 10, 0, true},
+       {"0", "0", 16, 0, true},
+       {"+0", "0", 0, 0, true},
+       {"-0", "0", 0, 0, true},
+       {"10", "10", 0, 10, true},
+       {"10", "10", 10, 10, true},
+       {"10", "10", 16, 16, true},
+       {"-10", "-10", 16, -16, true},
+       {"+10", "10", 16, 16, true},
+       {"0x10", "16", 0, 16, true},
+       {in: "0x10", base: 16, ok: false},
+       {"-0x10", "-16", 0, -16, true},
+       {"+0x10", "16", 0, 16, true},
+       {"00", "0", 0, 0, true},
+       {"0", "0", 8, 0, true},
+       {"07", "7", 0, 7, true},
+       {"7", "7", 8, 7, true},
+       {"023", "19", 0, 19, true},
+       {"23", "23", 8, 19, true},
+       {"cafebabe", "cafebabe", 16, 0xcafebabe, true},
+       {"0b0", "0", 0, 0, true},
+       {"-111", "-111", 2, -7, true},
+       {"-0b111", "-7", 0, -7, true},
+       {"0b1001010111", "599", 0, 0x257, true},
+       {"1001010111", "1001010111", 2, 0x257, true},
+}
+
+func format(base int) string {
+       switch base {
+       case 2:
+               return "%b"
+       case 8:
+               return "%o"
+       case 16:
+               return "%x"
+       }
+       return "%d"
+}
+
+func TestGetString(t *testing.T) {
+       z := new(Int)
+       for i, test := range stringTests {
+               if !test.ok {
+                       continue
+               }
+               z.SetInt64(test.val)
+
+               if test.base == 10 {
+                       s := z.String()
+                       if s != test.out {
+                               t.Errorf("#%da got %s; want %s", i, s, test.out)
+                       }
+               }
+
+               s := fmt.Sprintf(format(test.base), z)
+               if s != test.out {
+                       t.Errorf("#%db got %s; want %s", i, s, test.out)
+               }
+       }
+}
+
+func TestSetString(t *testing.T) {
+       tmp := new(Int)
+       for i, test := range stringTests {
+               // initialize to a non-zero value so that issues with parsing
+               // 0 are detected
+               tmp.SetInt64(1234567890)
+               n1, ok1 := new(Int).SetString(test.in, test.base)
+               n2, ok2 := tmp.SetString(test.in, test.base)
+               expected := NewInt(test.val)
+               if ok1 != test.ok || ok2 != test.ok {
+                       t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
+                       continue
+               }
+               if !ok1 {
+                       if n1 != nil {
+                               t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
+                       }
+                       continue
+               }
+               if !ok2 {
+                       if n2 != nil {
+                               t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
+                       }
+                       continue
+               }
+
+               if ok1 && !isNormalized(n1) {
+                       t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
+               }
+               if ok2 && !isNormalized(n2) {
+                       t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
+               }
+
+               if n1.Cmp(expected) != 0 {
+                       t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
+               }
+               if n2.Cmp(expected) != 0 {
+                       t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
+               }
+       }
+}
+
+var formatTests = []struct {
+       input  string
+       format string
+       output string
+}{
+       {"<nil>", "%x", "<nil>"},
+       {"<nil>", "%#x", "<nil>"},
+       {"<nil>", "%#y", "%!y(big.Int=<nil>)"},
+
+       {"10", "%b", "1010"},
+       {"10", "%o", "12"},
+       {"10", "%d", "10"},
+       {"10", "%v", "10"},
+       {"10", "%x", "a"},
+       {"10", "%X", "A"},
+       {"-10", "%X", "-A"},
+       {"10", "%y", "%!y(big.Int=10)"},
+       {"-10", "%y", "%!y(big.Int=-10)"},
+
+       {"10", "%#b", "1010"},
+       {"10", "%#o", "012"},
+       {"10", "%#d", "10"},
+       {"10", "%#v", "10"},
+       {"10", "%#x", "0xa"},
+       {"10", "%#X", "0XA"},
+       {"-10", "%#X", "-0XA"},
+       {"10", "%#y", "%!y(big.Int=10)"},
+       {"-10", "%#y", "%!y(big.Int=-10)"},
+
+       {"1234", "%d", "1234"},
+       {"1234", "%3d", "1234"},
+       {"1234", "%4d", "1234"},
+       {"-1234", "%d", "-1234"},
+       {"1234", "% 5d", " 1234"},
+       {"1234", "%+5d", "+1234"},
+       {"1234", "%-5d", "1234 "},
+       {"1234", "%x", "4d2"},
+       {"1234", "%X", "4D2"},
+       {"-1234", "%3x", "-4d2"},
+       {"-1234", "%4x", "-4d2"},
+       {"-1234", "%5x", " -4d2"},
+       {"-1234", "%-5x", "-4d2 "},
+       {"1234", "%03d", "1234"},
+       {"1234", "%04d", "1234"},
+       {"1234", "%05d", "01234"},
+       {"1234", "%06d", "001234"},
+       {"-1234", "%06d", "-01234"},
+       {"1234", "%+06d", "+01234"},
+       {"1234", "% 06d", " 01234"},
+       {"1234", "%-6d", "1234  "},
+       {"1234", "%-06d", "1234  "},
+       {"-1234", "%-06d", "-1234 "},
+
+       {"1234", "%.3d", "1234"},
+       {"1234", "%.4d", "1234"},
+       {"1234", "%.5d", "01234"},
+       {"1234", "%.6d", "001234"},
+       {"-1234", "%.3d", "-1234"},
+       {"-1234", "%.4d", "-1234"},
+       {"-1234", "%.5d", "-01234"},
+       {"-1234", "%.6d", "-001234"},
+
+       {"1234", "%8.3d", "    1234"},
+       {"1234", "%8.4d", "    1234"},
+       {"1234", "%8.5d", "   01234"},
+       {"1234", "%8.6d", "  001234"},
+       {"-1234", "%8.3d", "   -1234"},
+       {"-1234", "%8.4d", "   -1234"},
+       {"-1234", "%8.5d", "  -01234"},
+       {"-1234", "%8.6d", " -001234"},
+
+       {"1234", "%+8.3d", "   +1234"},
+       {"1234", "%+8.4d", "   +1234"},
+       {"1234", "%+8.5d", "  +01234"},
+       {"1234", "%+8.6d", " +001234"},
+       {"-1234", "%+8.3d", "   -1234"},
+       {"-1234", "%+8.4d", "   -1234"},
+       {"-1234", "%+8.5d", "  -01234"},
+       {"-1234", "%+8.6d", " -001234"},
+
+       {"1234", "% 8.3d", "    1234"},
+       {"1234", "% 8.4d", "    1234"},
+       {"1234", "% 8.5d", "   01234"},
+       {"1234", "% 8.6d", "  001234"},
+       {"-1234", "% 8.3d", "   -1234"},
+       {"-1234", "% 8.4d", "   -1234"},
+       {"-1234", "% 8.5d", "  -01234"},
+       {"-1234", "% 8.6d", " -001234"},
+
+       {"1234", "%.3x", "4d2"},
+       {"1234", "%.4x", "04d2"},
+       {"1234", "%.5x", "004d2"},
+       {"1234", "%.6x", "0004d2"},
+       {"-1234", "%.3x", "-4d2"},
+       {"-1234", "%.4x", "-04d2"},
+       {"-1234", "%.5x", "-004d2"},
+       {"-1234", "%.6x", "-0004d2"},
+
+       {"1234", "%8.3x", "     4d2"},
+       {"1234", "%8.4x", "    04d2"},
+       {"1234", "%8.5x", "   004d2"},
+       {"1234", "%8.6x", "  0004d2"},
+       {"-1234", "%8.3x", "    -4d2"},
+       {"-1234", "%8.4x", "   -04d2"},
+       {"-1234", "%8.5x", "  -004d2"},
+       {"-1234", "%8.6x", " -0004d2"},
+
+       {"1234", "%+8.3x", "    +4d2"},
+       {"1234", "%+8.4x", "   +04d2"},
+       {"1234", "%+8.5x", "  +004d2"},
+       {"1234", "%+8.6x", " +0004d2"},
+       {"-1234", "%+8.3x", "    -4d2"},
+       {"-1234", "%+8.4x", "   -04d2"},
+       {"-1234", "%+8.5x", "  -004d2"},
+       {"-1234", "%+8.6x", " -0004d2"},
+
+       {"1234", "% 8.3x", "     4d2"},
+       {"1234", "% 8.4x", "    04d2"},
+       {"1234", "% 8.5x", "   004d2"},
+       {"1234", "% 8.6x", "  0004d2"},
+       {"1234", "% 8.7x", " 00004d2"},
+       {"1234", "% 8.8x", " 000004d2"},
+       {"-1234", "% 8.3x", "    -4d2"},
+       {"-1234", "% 8.4x", "   -04d2"},
+       {"-1234", "% 8.5x", "  -004d2"},
+       {"-1234", "% 8.6x", " -0004d2"},
+       {"-1234", "% 8.7x", "-00004d2"},
+       {"-1234", "% 8.8x", "-000004d2"},
+
+       {"1234", "%-8.3d", "1234    "},
+       {"1234", "%-8.4d", "1234    "},
+       {"1234", "%-8.5d", "01234   "},
+       {"1234", "%-8.6d", "001234  "},
+       {"1234", "%-8.7d", "0001234 "},
+       {"1234", "%-8.8d", "00001234"},
+       {"-1234", "%-8.3d", "-1234   "},
+       {"-1234", "%-8.4d", "-1234   "},
+       {"-1234", "%-8.5d", "-01234  "},
+       {"-1234", "%-8.6d", "-001234 "},
+       {"-1234", "%-8.7d", "-0001234"},
+       {"-1234", "%-8.8d", "-00001234"},
+
+       {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
+
+       {"0", "%.d", ""},
+       {"0", "%.0d", ""},
+       {"0", "%3.d", ""},
+}
+
+func TestFormat(t *testing.T) {
+       for i, test := range formatTests {
+               var x *Int
+               if test.input != "<nil>" {
+                       var ok bool
+                       x, ok = new(Int).SetString(test.input, 0)
+                       if !ok {
+                               t.Errorf("#%d failed reading input %s", i, test.input)
+                       }
+               }
+               output := fmt.Sprintf(test.format, x)
+               if output != test.output {
+                       t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
+               }
+       }
+}
+
+var scanTests = []struct {
+       input     string
+       format    string
+       output    string
+       remaining int
+}{
+       {"1010", "%b", "10", 0},
+       {"0b1010", "%v", "10", 0},
+       {"12", "%o", "10", 0},
+       {"012", "%v", "10", 0},
+       {"10", "%d", "10", 0},
+       {"10", "%v", "10", 0},
+       {"a", "%x", "10", 0},
+       {"0xa", "%v", "10", 0},
+       {"A", "%X", "10", 0},
+       {"-A", "%X", "-10", 0},
+       {"+0b1011001", "%v", "89", 0},
+       {"0xA", "%v", "10", 0},
+       {"0 ", "%v", "0", 1},
+       {"2+3", "%v", "2", 2},
+       {"0XABC 12", "%v", "2748", 3},
+}
+
+func TestScan(t *testing.T) {
+       var buf bytes.Buffer
+       for i, test := range scanTests {
+               x := new(Int)
+               buf.Reset()
+               buf.WriteString(test.input)
+               if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
+                       t.Errorf("#%d error: %s", i, err)
+               }
+               if x.String() != test.output {
+                       t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
+               }
+               if buf.Len() != test.remaining {
+                       t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
+               }
+       }
+}
index 6e65ea1cb44adb9d312740eb483dc1f4ff0ddb36..db730d1356b2f70106b6a64336f65006cc0c7e9a 100644 (file)
@@ -5,18 +5,22 @@
 // Package big implements multi-precision arithmetic (big numbers).
 // The following numeric types are supported:
 //
-//     - Int   signed integers
-//     - Rat   rational numbers
+//   Int    signed integers
+//   Rat    rational numbers
+//   Float  floating-point numbers
 //
 // Methods are typically of the form:
 //
-//     func (z *Int) Op(x, y *Int) *Int        (similar for *Rat)
+//   func (z *T) Unary(x *T) *T        // z = op x
+//   func (z *T) Binary(x, y *T) *T    // z = x op y
+//   func (x *T) M() T1                // v = x.M()
 //
-// and implement operations z = x Op y with the result as receiver; if it
-// is one of the operands it may be overwritten (and its memory reused).
+// with T one of Int, Rat, or Float. For unary and binary operations, the
+// result is the receiver (usually named z in that case); if it is one of
+// the operands x or y it may be overwritten (and its memory reused).
 // To enable chaining of operations, the result is also returned. Methods
-// returning a result other than *Int or *Rat take one of the operands as
-// the receiver.
+// returning a result other than *Int, *Rat, or *Float take an operand as
+// the receiver (usually named x in that case).
 //
 package big
 
@@ -24,13 +28,7 @@ package big
 // These are the building blocks for the operations on signed integers
 // and rationals.
 
-import (
-       "errors"
-       "io"
-       "math"
-       "math/rand"
-       "sync"
-)
+import "math/rand"
 
 // An unsigned integer x of the form
 //
@@ -68,7 +66,7 @@ func (z nat) norm() nat {
 
 func (z nat) make(n int) nat {
        if n <= cap(z) {
-               return z[0:n] // reuse z
+               return z[:n] // reuse z
        }
        // Choosing a good value for e has significant performance impact
        // because it increases the chance that a value can be reused.
@@ -78,7 +76,7 @@ func (z nat) make(n int) nat {
 
 func (z nat) setWord(x Word) nat {
        if x == 0 {
-               return z.make(0)
+               return z[:0]
        }
        z = z.make(1)
        z[0] = x
@@ -122,7 +120,7 @@ func (z nat) add(x, y nat) nat {
                return z.add(y, x)
        case m == 0:
                // n == 0 because m >= n; result is 0
-               return z.make(0)
+               return z[:0]
        case n == 0:
                // result is x
                return z.set(x)
@@ -148,7 +146,7 @@ func (z nat) sub(x, y nat) nat {
                panic("underflow")
        case m == 0:
                // n == 0 because m >= n; result is 0
-               return z.make(0)
+               return z[:0]
        case n == 0:
                // result is x
                return z.set(x)
@@ -384,7 +382,7 @@ func (z nat) mul(x, y nat) nat {
        case m < n:
                return z.mul(y, x)
        case m == 0 || n == 0:
-               return z.make(0)
+               return z[:0]
        case n == 1:
                return z.mulAddWW(x, y[0], 0)
        }
@@ -488,7 +486,7 @@ func (z nat) divW(x nat, y Word) (q nat, r Word) {
                q = z.set(x) // result is x
                return
        case m == 0:
-               q = z.make(0) // result is 0
+               q = z[:0] // result is 0
                return
        }
        // m > 0
@@ -504,7 +502,7 @@ func (z nat) div(z2, u, v nat) (q, r nat) {
        }
 
        if u.cmp(v) < 0 {
-               q = z.make(0)
+               q = z[:0]
                r = z2.set(u)
                return
        }
@@ -543,7 +541,7 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
                u = nil // u is an alias for uIn or v - cannot reuse
        }
        u = u.make(len(uIn) + 1)
-       u.clear()
+       u.clear() // TODO(gri) no need to clear if we allocated a new u
 
        // D1.
        shift := leadingZeros(v[n-1])
@@ -606,385 +604,6 @@ func (x nat) bitLen() int {
        return 0
 }
 
-// MaxBase is the largest number base accepted for string conversions.
-const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1
-
-func hexValue(ch rune) Word {
-       d := int(MaxBase + 1) // illegal base
-       switch {
-       case '0' <= ch && ch <= '9':
-               d = int(ch - '0')
-       case 'a' <= ch && ch <= 'z':
-               d = int(ch - 'a' + 10)
-       case 'A' <= ch && ch <= 'Z':
-               d = int(ch - 'A' + 10)
-       }
-       return Word(d)
-}
-
-// scan sets z to the natural number corresponding to the longest possible prefix
-// read from r representing an unsigned integer in a given conversion base.
-// It returns z, the actual conversion base used, and an error, if any. In the
-// error case, the value of z is undefined. The syntax follows the syntax of
-// unsigned integer literals in Go.
-//
-// The base argument must be 0 or a value from 2 through MaxBase. If the base
-// is 0, the string prefix determines the actual conversion base. A prefix of
-// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
-// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
-//
-func (z nat) scan(r io.RuneScanner, base int) (nat, int, error) {
-       // reject illegal bases
-       if base < 0 || base == 1 || MaxBase < base {
-               return z, 0, errors.New("illegal number base")
-       }
-
-       // one char look-ahead
-       ch, _, err := r.ReadRune()
-       if err != nil {
-               return z, 0, err
-       }
-
-       // determine base if necessary
-       b := Word(base)
-       if base == 0 {
-               b = 10
-               if ch == '0' {
-                       switch ch, _, err = r.ReadRune(); err {
-                       case nil:
-                               b = 8
-                               switch ch {
-                               case 'x', 'X':
-                                       b = 16
-                               case 'b', 'B':
-                                       b = 2
-                               }
-                               if b == 2 || b == 16 {
-                                       if ch, _, err = r.ReadRune(); err != nil {
-                                               return z, 0, err
-                                       }
-                               }
-                       case io.EOF:
-                               return z.make(0), 10, nil
-                       default:
-                               return z, 10, err
-                       }
-               }
-       }
-
-       // convert string
-       // - group as many digits d as possible together into a "super-digit" dd with "super-base" bb
-       // - only when bb does not fit into a word anymore, do a full number mulAddWW using bb and dd
-       z = z.make(0)
-       bb := Word(1)
-       dd := Word(0)
-       for max := _M / b; ; {
-               d := hexValue(ch)
-               if d >= b {
-                       r.UnreadRune() // ch does not belong to number anymore
-                       break
-               }
-
-               if bb <= max {
-                       bb *= b
-                       dd = dd*b + d
-               } else {
-                       // bb * b would overflow
-                       z = z.mulAddWW(z, bb, dd)
-                       bb = b
-                       dd = d
-               }
-
-               if ch, _, err = r.ReadRune(); err != nil {
-                       if err != io.EOF {
-                               return z, int(b), err
-                       }
-                       break
-               }
-       }
-
-       switch {
-       case bb > 1:
-               // there was at least one mantissa digit
-               z = z.mulAddWW(z, bb, dd)
-       case base == 0 && b == 8:
-               // there was only the octal prefix 0 (possibly followed by digits > 7);
-               // return base 10, not 8
-               return z, 10, nil
-       case base != 0 || b != 8:
-               // there was neither a mantissa digit nor the octal prefix 0
-               return z, int(b), errors.New("syntax error scanning number")
-       }
-
-       return z.norm(), int(b), nil
-}
-
-// Character sets for string conversion.
-const (
-       lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
-       uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-)
-
-// decimalString returns a decimal representation of x.
-// It calls x.string with the charset "0123456789".
-func (x nat) decimalString() string {
-       return x.string(lowercaseDigits[0:10])
-}
-
-// string converts x to a string using digits from a charset; a digit with
-// value d is represented by charset[d]. The conversion base is determined
-// by len(charset), which must be >= 2 and <= 256.
-func (x nat) string(charset string) string {
-       b := Word(len(charset))
-
-       // special cases
-       switch {
-       case b < 2 || MaxBase > 256:
-               panic("illegal base")
-       case len(x) == 0:
-               return string(charset[0])
-       }
-
-       // allocate buffer for conversion
-       i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
-       s := make([]byte, i)
-
-       // convert power of two and non power of two bases separately
-       if b == b&-b {
-               // shift is base-b digit size in bits
-               shift := trailingZeroBits(b) // shift > 0 because b >= 2
-               mask := Word(1)<<shift - 1
-               w := x[0]
-               nbits := uint(_W) // number of unprocessed bits in w
-
-               // convert less-significant words
-               for k := 1; k < len(x); k++ {
-                       // convert full digits
-                       for nbits >= shift {
-                               i--
-                               s[i] = charset[w&mask]
-                               w >>= shift
-                               nbits -= shift
-                       }
-
-                       // convert any partial leading digit and advance to next word
-                       if nbits == 0 {
-                               // no partial digit remaining, just advance
-                               w = x[k]
-                               nbits = _W
-                       } else {
-                               // partial digit in current (k-1) and next (k) word
-                               w |= x[k] << nbits
-                               i--
-                               s[i] = charset[w&mask]
-
-                               // advance
-                               w = x[k] >> (shift - nbits)
-                               nbits = _W - (shift - nbits)
-                       }
-               }
-
-               // convert digits of most-significant word (omit leading zeros)
-               for nbits >= 0 && w != 0 {
-                       i--
-                       s[i] = charset[w&mask]
-                       w >>= shift
-                       nbits -= shift
-               }
-
-       } else {
-               // determine "big base"; i.e., the largest possible value bb
-               // that is a power of base b and still fits into a Word
-               // (as in 10^19 for 19 decimal digits in a 64bit Word)
-               bb := b      // big base is b**ndigits
-               ndigits := 1 // number of base b digits
-               for max := Word(_M / b); bb <= max; bb *= b {
-                       ndigits++ // maximize ndigits where bb = b**ndigits, bb <= _M
-               }
-
-               // construct table of successive squares of bb*leafSize to use in subdivisions
-               // result (table != nil) <=> (len(x) > leafSize > 0)
-               table := divisors(len(x), b, ndigits, bb)
-
-               // preserve x, create local copy for use by convertWords
-               q := nat(nil).set(x)
-
-               // convert q to string s in base b
-               q.convertWords(s, charset, b, ndigits, bb, table)
-
-               // strip leading zeros
-               // (x != 0; thus s must contain at least one non-zero digit
-               // and the loop will terminate)
-               i = 0
-               for zero := charset[0]; s[i] == zero; {
-                       i++
-               }
-       }
-
-       return string(s[i:])
-}
-
-// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
-// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
-// repeated nat/Word division.
-//
-// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
-// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
-// Recursive conversion divides q by its approximate square root, yielding two parts, each half
-// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
-// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
-// is made better by splitting the subblocks recursively. Best is to split blocks until one more
-// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
-// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
-// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
-// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
-// specific hardware.
-//
-func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
-       // split larger blocks recursively
-       if table != nil {
-               // len(q) > leafSize > 0
-               var r nat
-               index := len(table) - 1
-               for len(q) > leafSize {
-                       // find divisor close to sqrt(q) if possible, but in any case < q
-                       maxLength := q.bitLen()     // ~= log2 q, or at of least largest possible q of this bit length
-                       minLength := maxLength >> 1 // ~= log2 sqrt(q)
-                       for index > 0 && table[index-1].nbits > minLength {
-                               index-- // desired
-                       }
-                       if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
-                               index--
-                               if index < 0 {
-                                       panic("internal inconsistency")
-                               }
-                       }
-
-                       // split q into the two digit number (q'*bbb + r) to form independent subblocks
-                       q, r = q.div(r, q, table[index].bbb)
-
-                       // convert subblocks and collect results in s[:h] and s[h:]
-                       h := len(s) - table[index].ndigits
-                       r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index])
-                       s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1])
-               }
-       }
-
-       // having split any large blocks now process the remaining (small) block iteratively
-       i := len(s)
-       var r Word
-       if b == 10 {
-               // hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
-               for len(q) > 0 {
-                       // extract least significant, base bb "digit"
-                       q, r = q.divW(q, bb)
-                       for j := 0; j < ndigits && i > 0; j++ {
-                               i--
-                               // avoid % computation since r%10 == r - int(r/10)*10;
-                               // this appears to be faster for BenchmarkString10000Base10
-                               // and smaller strings (but a bit slower for larger ones)
-                               t := r / 10
-                               s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code
-                               r = t
-                       }
-               }
-       } else {
-               for len(q) > 0 {
-                       // extract least significant, base bb "digit"
-                       q, r = q.divW(q, bb)
-                       for j := 0; j < ndigits && i > 0; j++ {
-                               i--
-                               s[i] = charset[r%b]
-                               r /= b
-                       }
-               }
-       }
-
-       // prepend high-order zeroes
-       zero := charset[0]
-       for i > 0 { // while need more leading zeroes
-               i--
-               s[i] = zero
-       }
-}
-
-// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
-// Benchmark and configure leafSize using: go test -bench="Leaf"
-//   8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
-//   8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
-var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
-
-type divisor struct {
-       bbb     nat // divisor
-       nbits   int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
-       ndigits int // digit length of divisor in terms of output base digits
-}
-
-var cacheBase10 struct {
-       sync.Mutex
-       table [64]divisor // cached divisors for base 10
-}
-
-// expWW computes x**y
-func (z nat) expWW(x, y Word) nat {
-       return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
-}
-
-// construct table of powers of bb*leafSize to use in subdivisions
-func divisors(m int, b Word, ndigits int, bb Word) []divisor {
-       // only compute table when recursive conversion is enabled and x is large
-       if leafSize == 0 || m <= leafSize {
-               return nil
-       }
-
-       // determine k where (bb**leafSize)**(2**k) >= sqrt(x)
-       k := 1
-       for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 {
-               k++
-       }
-
-       // reuse and extend existing table of divisors or create new table as appropriate
-       var table []divisor // for b == 10, table overlaps with cacheBase10.table
-       if b == 10 {
-               cacheBase10.Lock()
-               table = cacheBase10.table[0:k] // reuse old table for this conversion
-       } else {
-               table = make([]divisor, k) // create new table for this conversion
-       }
-
-       // extend table
-       if table[k-1].ndigits == 0 {
-               // add new entries as needed
-               var larger nat
-               for i := 0; i < k; i++ {
-                       if table[i].ndigits == 0 {
-                               if i == 0 {
-                                       table[0].bbb = nat(nil).expWW(bb, Word(leafSize))
-                                       table[0].ndigits = ndigits * leafSize
-                               } else {
-                                       table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
-                                       table[i].ndigits = 2 * table[i-1].ndigits
-                               }
-
-                               // optimization: exploit aggregated extra bits in macro blocks
-                               larger = nat(nil).set(table[i].bbb)
-                               for mulAddVWW(larger, larger, b, 0) == 0 {
-                                       table[i].bbb = table[i].bbb.set(larger)
-                                       table[i].ndigits++
-                               }
-
-                               table[i].nbits = table[i].bbb.bitLen()
-                       }
-               }
-       }
-
-       if b == 10 {
-               cacheBase10.Unlock()
-       }
-
-       return table
-}
-
 const deBruijn32 = 0x077CB531
 
 var deBruijn32Lookup = []byte{
@@ -1041,7 +660,7 @@ func (x nat) trailingZeroBits() uint {
 func (z nat) shl(x nat, s uint) nat {
        m := len(x)
        if m == 0 {
-               return z.make(0)
+               return z[:0]
        }
        // m > 0
 
@@ -1058,7 +677,7 @@ func (z nat) shr(x nat, s uint) nat {
        m := len(x)
        n := m - int(s/_W)
        if n <= 0 {
-               return z.make(0)
+               return z[:0]
        }
        // n > 0
 
@@ -1097,12 +716,36 @@ func (z nat) setBit(x nat, i uint, b uint) nat {
        panic("set bit is not 0 or 1")
 }
 
-func (z nat) bit(i uint) uint {
-       j := int(i / _W)
-       if j >= len(z) {
+// bit returns the value of the i'th bit, with lsb == bit 0.
+func (x nat) bit(i uint) uint {
+       j := i / _W
+       if j >= uint(len(x)) {
                return 0
        }
-       return uint(z[j] >> (i % _W) & 1)
+       // 0 <= j < len(x)
+       return uint(x[j] >> (i % _W) & 1)
+}
+
+// sticky returns 1 if there's a 1 bit within the
+// i least significant bits, otherwise it returns 0.
+func (x nat) sticky(i uint) uint {
+       j := i / _W
+       if j >= uint(len(x)) {
+               if len(x) == 0 {
+                       return 0
+               }
+               return 1
+       }
+       // 0 <= j < len(x)
+       for _, x := range x[:j] {
+               if x != 0 {
+                       return 1
+               }
+       }
+       if x[j]<<(_W-i%_W) != 0 {
+               return 1
+       }
+       return 0
 }
 
 func (z nat) and(x, y nat) nat {
index 5d93df735deebd84c22ea9a61123a2ad431fa0f9..b25a89f731b0a2dd2a4658e1e649457c7e5006fe 100644 (file)
@@ -5,7 +5,6 @@
 package big
 
 import (
-       "io"
        "runtime"
        "strings"
        "testing"
@@ -88,7 +87,7 @@ var prodNN = []argNN{
 }
 
 func natFromString(s string) nat {
-       x, _, err := nat(nil).scan(strings.NewReader(s), 0)
+       x, _, _, err := nat(nil).scan(strings.NewReader(s), 0, false)
        if err != nil {
                panic(err)
        }
@@ -206,393 +205,6 @@ func BenchmarkMul(b *testing.B) {
        }
 }
 
-func toString(x nat, charset string) string {
-       base := len(charset)
-
-       // special cases
-       switch {
-       case base < 2:
-               panic("illegal base")
-       case len(x) == 0:
-               return string(charset[0])
-       }
-
-       // allocate buffer for conversion
-       i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
-       s := make([]byte, i)
-
-       // don't destroy x
-       q := nat(nil).set(x)
-
-       // convert
-       for len(q) > 0 {
-               i--
-               var r Word
-               q, r = q.divW(q, Word(base))
-               s[i] = charset[r]
-       }
-
-       return string(s[i:])
-}
-
-var strTests = []struct {
-       x nat    // nat value to be converted
-       c string // conversion charset
-       s string // expected result
-}{
-       {nil, "01", "0"},
-       {nat{1}, "01", "1"},
-       {nat{0xc5}, "01", "11000101"},
-       {nat{03271}, lowercaseDigits[0:8], "3271"},
-       {nat{10}, lowercaseDigits[0:10], "10"},
-       {nat{1234567890}, uppercaseDigits[0:10], "1234567890"},
-       {nat{0xdeadbeef}, lowercaseDigits[0:16], "deadbeef"},
-       {nat{0xdeadbeef}, uppercaseDigits[0:16], "DEADBEEF"},
-       {nat{0x229be7}, lowercaseDigits[0:17], "1a2b3c"},
-       {nat{0x309663e6}, uppercaseDigits[0:32], "O9COV6"},
-}
-
-func TestString(t *testing.T) {
-       for _, a := range strTests {
-               s := a.x.string(a.c)
-               if s != a.s {
-                       t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
-               }
-
-               x, b, err := nat(nil).scan(strings.NewReader(a.s), len(a.c))
-               if x.cmp(a.x) != 0 {
-                       t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
-               }
-               if b != len(a.c) {
-                       t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
-               }
-               if err != nil {
-                       t.Errorf("scan%+v\n\tgot error = %s", a, err)
-               }
-       }
-}
-
-var natScanTests = []struct {
-       s    string // string to be scanned
-       base int    // input base
-       x    nat    // expected nat
-       b    int    // expected base
-       ok   bool   // expected success
-       next rune   // next character (or 0, if at EOF)
-}{
-       // error: illegal base
-       {base: -1},
-       {base: 1},
-       {base: 37},
-
-       // error: no mantissa
-       {},
-       {s: "?"},
-       {base: 10},
-       {base: 36},
-       {s: "?", base: 10},
-       {s: "0x"},
-       {s: "345", base: 2},
-
-       // no errors
-       {"0", 0, nil, 10, true, 0},
-       {"0", 10, nil, 10, true, 0},
-       {"0", 36, nil, 36, true, 0},
-       {"1", 0, nat{1}, 10, true, 0},
-       {"1", 10, nat{1}, 10, true, 0},
-       {"0 ", 0, nil, 10, true, ' '},
-       {"08", 0, nil, 10, true, '8'},
-       {"018", 0, nat{1}, 8, true, '8'},
-       {"0b1", 0, nat{1}, 2, true, 0},
-       {"0b11000101", 0, nat{0xc5}, 2, true, 0},
-       {"03271", 0, nat{03271}, 8, true, 0},
-       {"10ab", 0, nat{10}, 10, true, 'a'},
-       {"1234567890", 0, nat{1234567890}, 10, true, 0},
-       {"xyz", 36, nat{(33*36+34)*36 + 35}, 36, true, 0},
-       {"xyz?", 36, nat{(33*36+34)*36 + 35}, 36, true, '?'},
-       {"0x", 16, nil, 16, true, 'x'},
-       {"0xdeadbeef", 0, nat{0xdeadbeef}, 16, true, 0},
-       {"0XDEADBEEF", 0, nat{0xdeadbeef}, 16, true, 0},
-}
-
-func TestScanBase(t *testing.T) {
-       for _, a := range natScanTests {
-               r := strings.NewReader(a.s)
-               x, b, err := nat(nil).scan(r, a.base)
-               if err == nil && !a.ok {
-                       t.Errorf("scan%+v\n\texpected error", a)
-               }
-               if err != nil {
-                       if a.ok {
-                               t.Errorf("scan%+v\n\tgot error = %s", a, err)
-                       }
-                       continue
-               }
-               if x.cmp(a.x) != 0 {
-                       t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
-               }
-               if b != a.b {
-                       t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
-               }
-               next, _, err := r.ReadRune()
-               if err == io.EOF {
-                       next = 0
-                       err = nil
-               }
-               if err == nil && next != a.next {
-                       t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
-               }
-       }
-}
-
-var pi = "3" +
-       "14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
-       "32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
-       "28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
-       "96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
-       "31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
-       "60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
-       "22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
-       "29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
-       "81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
-       "21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
-       "55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
-       "63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
-       "75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
-       "45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
-       "34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
-       "16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
-       "04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
-       "26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
-       "99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
-       "53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
-       "68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
-       "13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
-       "88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
-       "79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
-       "68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
-       "21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
-       "06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
-       "14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
-       "21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
-       "05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
-       "23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
-       "90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
-       "31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
-       "20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
-       "97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
-       "44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
-       "44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
-       "85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
-       "58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
-       "27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
-       "09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
-       "79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
-       "06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
-       "91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
-       "94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
-       "78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
-       "24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
-       "59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
-       "34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
-       "88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
-       "94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
-
-// Test case for BenchmarkScanPi.
-func TestScanPi(t *testing.T) {
-       var x nat
-       z, _, err := x.scan(strings.NewReader(pi), 10)
-       if err != nil {
-               t.Errorf("scanning pi: %s", err)
-       }
-       if s := z.decimalString(); s != pi {
-               t.Errorf("scanning pi: got %s", s)
-       }
-}
-
-func TestScanPiParallel(t *testing.T) {
-       const n = 2
-       c := make(chan int)
-       for i := 0; i < n; i++ {
-               go func() {
-                       TestScanPi(t)
-                       c <- 0
-               }()
-       }
-       for i := 0; i < n; i++ {
-               <-c
-       }
-}
-
-func BenchmarkScanPi(b *testing.B) {
-       for i := 0; i < b.N; i++ {
-               var x nat
-               x.scan(strings.NewReader(pi), 10)
-       }
-}
-
-func BenchmarkStringPiParallel(b *testing.B) {
-       var x nat
-       x, _, _ = x.scan(strings.NewReader(pi), 0)
-       if x.decimalString() != pi {
-               panic("benchmark incorrect: conversion failed")
-       }
-       b.RunParallel(func(pb *testing.PB) {
-               for pb.Next() {
-                       x.decimalString()
-               }
-       })
-}
-
-func BenchmarkScan10Base2(b *testing.B)     { ScanHelper(b, 2, 10, 10) }
-func BenchmarkScan100Base2(b *testing.B)    { ScanHelper(b, 2, 10, 100) }
-func BenchmarkScan1000Base2(b *testing.B)   { ScanHelper(b, 2, 10, 1000) }
-func BenchmarkScan10000Base2(b *testing.B)  { ScanHelper(b, 2, 10, 10000) }
-func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
-
-func BenchmarkScan10Base8(b *testing.B)     { ScanHelper(b, 8, 10, 10) }
-func BenchmarkScan100Base8(b *testing.B)    { ScanHelper(b, 8, 10, 100) }
-func BenchmarkScan1000Base8(b *testing.B)   { ScanHelper(b, 8, 10, 1000) }
-func BenchmarkScan10000Base8(b *testing.B)  { ScanHelper(b, 8, 10, 10000) }
-func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
-
-func BenchmarkScan10Base10(b *testing.B)     { ScanHelper(b, 10, 10, 10) }
-func BenchmarkScan100Base10(b *testing.B)    { ScanHelper(b, 10, 10, 100) }
-func BenchmarkScan1000Base10(b *testing.B)   { ScanHelper(b, 10, 10, 1000) }
-func BenchmarkScan10000Base10(b *testing.B)  { ScanHelper(b, 10, 10, 10000) }
-func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
-
-func BenchmarkScan10Base16(b *testing.B)     { ScanHelper(b, 16, 10, 10) }
-func BenchmarkScan100Base16(b *testing.B)    { ScanHelper(b, 16, 10, 100) }
-func BenchmarkScan1000Base16(b *testing.B)   { ScanHelper(b, 16, 10, 1000) }
-func BenchmarkScan10000Base16(b *testing.B)  { ScanHelper(b, 16, 10, 10000) }
-func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
-
-func ScanHelper(b *testing.B, base int, x, y Word) {
-       b.StopTimer()
-       var z nat
-       z = z.expWW(x, y)
-
-       var s string
-       s = z.string(lowercaseDigits[0:base])
-       if t := toString(z, lowercaseDigits[0:base]); t != s {
-               b.Fatalf("scanning: got %s; want %s", s, t)
-       }
-       b.StartTimer()
-
-       for i := 0; i < b.N; i++ {
-               z.scan(strings.NewReader(s), base)
-       }
-}
-
-func BenchmarkString10Base2(b *testing.B)     { StringHelper(b, 2, 10, 10) }
-func BenchmarkString100Base2(b *testing.B)    { StringHelper(b, 2, 10, 100) }
-func BenchmarkString1000Base2(b *testing.B)   { StringHelper(b, 2, 10, 1000) }
-func BenchmarkString10000Base2(b *testing.B)  { StringHelper(b, 2, 10, 10000) }
-func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
-
-func BenchmarkString10Base8(b *testing.B)     { StringHelper(b, 8, 10, 10) }
-func BenchmarkString100Base8(b *testing.B)    { StringHelper(b, 8, 10, 100) }
-func BenchmarkString1000Base8(b *testing.B)   { StringHelper(b, 8, 10, 1000) }
-func BenchmarkString10000Base8(b *testing.B)  { StringHelper(b, 8, 10, 10000) }
-func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
-
-func BenchmarkString10Base10(b *testing.B)     { StringHelper(b, 10, 10, 10) }
-func BenchmarkString100Base10(b *testing.B)    { StringHelper(b, 10, 10, 100) }
-func BenchmarkString1000Base10(b *testing.B)   { StringHelper(b, 10, 10, 1000) }
-func BenchmarkString10000Base10(b *testing.B)  { StringHelper(b, 10, 10, 10000) }
-func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
-
-func BenchmarkString10Base16(b *testing.B)     { StringHelper(b, 16, 10, 10) }
-func BenchmarkString100Base16(b *testing.B)    { StringHelper(b, 16, 10, 100) }
-func BenchmarkString1000Base16(b *testing.B)   { StringHelper(b, 16, 10, 1000) }
-func BenchmarkString10000Base16(b *testing.B)  { StringHelper(b, 16, 10, 10000) }
-func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
-
-func StringHelper(b *testing.B, base int, x, y Word) {
-       b.StopTimer()
-       var z nat
-       z = z.expWW(x, y)
-       z.string(lowercaseDigits[0:base]) // warm divisor cache
-       b.StartTimer()
-
-       for i := 0; i < b.N; i++ {
-               _ = z.string(lowercaseDigits[0:base])
-       }
-}
-
-func BenchmarkLeafSize0(b *testing.B)  { LeafSizeHelper(b, 10, 0) } // test without splitting
-func BenchmarkLeafSize1(b *testing.B)  { LeafSizeHelper(b, 10, 1) }
-func BenchmarkLeafSize2(b *testing.B)  { LeafSizeHelper(b, 10, 2) }
-func BenchmarkLeafSize3(b *testing.B)  { LeafSizeHelper(b, 10, 3) }
-func BenchmarkLeafSize4(b *testing.B)  { LeafSizeHelper(b, 10, 4) }
-func BenchmarkLeafSize5(b *testing.B)  { LeafSizeHelper(b, 10, 5) }
-func BenchmarkLeafSize6(b *testing.B)  { LeafSizeHelper(b, 10, 6) }
-func BenchmarkLeafSize7(b *testing.B)  { LeafSizeHelper(b, 10, 7) }
-func BenchmarkLeafSize8(b *testing.B)  { LeafSizeHelper(b, 10, 8) }
-func BenchmarkLeafSize9(b *testing.B)  { LeafSizeHelper(b, 10, 9) }
-func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
-func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
-func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
-func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
-func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
-func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
-func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
-func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
-func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
-
-func LeafSizeHelper(b *testing.B, base Word, size int) {
-       b.StopTimer()
-       originalLeafSize := leafSize
-       resetTable(cacheBase10.table[:])
-       leafSize = size
-       b.StartTimer()
-
-       for d := 1; d <= 10000; d *= 10 {
-               b.StopTimer()
-               var z nat
-               z = z.expWW(base, Word(d))            // build target number
-               _ = z.string(lowercaseDigits[0:base]) // warm divisor cache
-               b.StartTimer()
-
-               for i := 0; i < b.N; i++ {
-                       _ = z.string(lowercaseDigits[0:base])
-               }
-       }
-
-       b.StopTimer()
-       resetTable(cacheBase10.table[:])
-       leafSize = originalLeafSize
-       b.StartTimer()
-}
-
-func resetTable(table []divisor) {
-       if table != nil && table[0].bbb != nil {
-               for i := 0; i < len(table); i++ {
-                       table[i].bbb = nil
-                       table[i].nbits = 0
-                       table[i].ndigits = 0
-               }
-       }
-}
-
-func TestStringPowers(t *testing.T) {
-       var b, p Word
-       for b = 2; b <= 16; b++ {
-               for p = 0; p <= 512; p++ {
-                       x := nat(nil).expWW(b, p)
-                       xs := x.string(lowercaseDigits[0:b])
-                       xs2 := toString(x, lowercaseDigits[0:b])
-                       if xs != xs2 {
-                               t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
-                       }
-               }
-               if b >= 3 && testing.Short() {
-                       break
-               }
-       }
-}
-
 func TestLeadingZeros(t *testing.T) {
        var x Word = _B >> 1
        for i := 0; i <= _W; i++ {
@@ -691,20 +303,30 @@ func TestModW(t *testing.T) {
 }
 
 func TestTrailingZeroBits(t *testing.T) {
+       // test 0 case explicitly
+       if n := trailingZeroBits(0); n != 0 {
+               t.Errorf("got trailingZeroBits(0) = %d; want 0", n)
+       }
+
        x := Word(1)
-       for i := uint(0); i <= _W; i++ {
+       for i := uint(0); i < _W; i++ {
                n := trailingZeroBits(x)
-               if n != i%_W {
+               if n != i {
                        t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
                }
                x <<= 1
        }
 
+       // test 0 case explicitly
+       if n := nat(nil).trailingZeroBits(); n != 0 {
+               t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n)
+       }
+
        y := nat(nil).set(natOne)
        for i := uint(0); i <= 3*_W; i++ {
                n := y.trailingZeroBits()
                if n != i {
-                       t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.string(lowercaseDigits[0:16]), n, i)
+                       t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i)
                }
                y = y.shl(y, 1)
        }
@@ -735,14 +357,13 @@ var expNNTests = []struct {
 
 func TestExpNN(t *testing.T) {
        for i, test := range expNNTests {
-               x, _, _ := nat(nil).scan(strings.NewReader(test.x), 0)
-               y, _, _ := nat(nil).scan(strings.NewReader(test.y), 0)
-               out, _, _ := nat(nil).scan(strings.NewReader(test.out), 0)
+               x := natFromString(test.x)
+               y := natFromString(test.y)
+               out := natFromString(test.out)
 
                var m nat
-
                if len(test.m) > 0 {
-                       m, _, _ = nat(nil).scan(strings.NewReader(test.m), 0)
+                       m = natFromString(test.m)
                }
 
                z := nat(nil).expNN(x, y, m)
@@ -821,3 +442,77 @@ func BenchmarkFibo(b *testing.B) {
                fibo(1e5)
        }
 }
+
+var bitTests = []struct {
+       x    string
+       i    uint
+       want uint
+}{
+       {"0", 0, 0},
+       {"0", 1, 0},
+       {"0", 1000, 0},
+
+       {"0x1", 0, 1},
+       {"0x10", 0, 0},
+       {"0x10", 3, 0},
+       {"0x10", 4, 1},
+       {"0x10", 5, 0},
+
+       {"0x8000000000000000", 62, 0},
+       {"0x8000000000000000", 63, 1},
+       {"0x8000000000000000", 64, 0},
+
+       {"0x3" + strings.Repeat("0", 32), 127, 0},
+       {"0x3" + strings.Repeat("0", 32), 128, 1},
+       {"0x3" + strings.Repeat("0", 32), 129, 1},
+       {"0x3" + strings.Repeat("0", 32), 130, 0},
+}
+
+func TestBit(t *testing.T) {
+       for i, test := range bitTests {
+               x := natFromString(test.x)
+               if got := x.bit(test.i); got != test.want {
+                       t.Errorf("#%d: %s.bit(%d) = %v; want %v", i, test.x, test.i, got, test.want)
+               }
+       }
+}
+
+var stickyTests = []struct {
+       x    string
+       i    uint
+       want uint
+}{
+       {"0", 0, 0},
+       {"0", 1, 0},
+       {"0", 1000, 0},
+
+       {"0x1", 0, 0},
+       {"0x1", 1, 1},
+
+       {"0x1350", 0, 0},
+       {"0x1350", 4, 0},
+       {"0x1350", 5, 1},
+
+       {"0x8000000000000000", 63, 0},
+       {"0x8000000000000000", 64, 1},
+
+       {"0x1" + strings.Repeat("0", 100), 400, 0},
+       {"0x1" + strings.Repeat("0", 100), 401, 1},
+}
+
+func TestSticky(t *testing.T) {
+       for i, test := range stickyTests {
+               x := natFromString(test.x)
+               if got := x.sticky(test.i); got != test.want {
+                       t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i, got, test.want)
+               }
+               if test.want == 1 {
+                       // all subsequent i's should also return 1
+                       for d := uint(1); d <= 3; d++ {
+                               if got := x.sticky(test.i + d); got != 1 {
+                                       t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i+d, got, 1)
+                               }
+                       }
+               }
+       }
+}
diff --git a/src/math/big/natconv.go b/src/math/big/natconv.go
new file mode 100644 (file)
index 0000000..e094d22
--- /dev/null
@@ -0,0 +1,489 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements nat-to-string conversion functions.
+
+package big
+
+import (
+       "errors"
+       "io"
+       "math"
+       "sync"
+)
+
+// MaxBase is the largest number base accepted for string conversions.
+const MaxBase = 'z' - 'a' + 10 + 1
+
+// maxPow returns (b**n, n) such that b**n is the largest power b**n <= _M.
+// For instance maxPow(10) == (1e19, 19) for 19 decimal digits in a 64bit Word.
+// In other words, at most n digits in base b fit into a Word.
+// TODO(gri) replace this with a table, generated at build time.
+func maxPow(b Word) (p Word, n int) {
+       p, n = b, 1 // assuming b <= _M
+       for max := _M / b; p <= max; {
+               // p == b**n && p <= max
+               p *= b
+               n++
+       }
+       // p == b**n && p <= _M
+       return
+}
+
+// pow returns x**n for n > 0, and 1 otherwise.
+func pow(x Word, n int) (p Word) {
+       // n == sum of bi * 2**i, for 0 <= i < imax, and bi is 0 or 1
+       // thus x**n == product of x**(2**i) for all i where bi == 1
+       // (Russian Peasant Method for exponentiation)
+       p = 1
+       for n > 0 {
+               if n&1 != 0 {
+                       p *= x
+               }
+               x *= x
+               n >>= 1
+       }
+       return
+}
+
+// scan scans the number corresponding to the longest possible prefix
+// from r representing an unsigned number in a given conversion base.
+// It returns the corresponding natural number res, the actual base b,
+// a digit count, and an error err, if any.
+//
+//     number   = [ prefix ] mantissa .
+//     prefix   = "0" [ "x" | "X" | "b" | "B" ] .
+//      mantissa = digits | digits "." [ digits ] | "." digits .
+//     digits   = digit { digit } .
+//     digit    = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
+//
+// The base argument must be 0 or a value between 0 through MaxBase.
+//
+// For base 0, the number prefix determines the actual base: A prefix of
+// ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix
+// selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise
+// the selected base is 10 and no prefix is permitted.
+//
+// If fracOk is set, an octal prefix is ignored (a leading ``0'' simply
+// stands for a zero digit), and a period followed by a fractional part
+// is permitted. The result value is computed as if there were no period
+// present; and the count value is used to determine the fractional part.
+//
+// A result digit count > 0 corresponds to the number of (non-prefix) digits
+// parsed. A digit count <= 0 indicates the presence of a period (if fracOk
+// is set, only), and -count is the number of fractional digits found.
+// In this case, the value of the scanned number is res * 10**count.
+//
+func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) {
+       // reject illegal bases
+       if base != 0 && base < 2 || base > MaxBase {
+               err = errors.New("illegal number base")
+               return
+       }
+
+       // one char look-ahead
+       ch, err := r.ReadByte()
+       if err != nil {
+               return
+       }
+
+       // determine actual base
+       b = base
+       if base == 0 {
+               // actual base is 10 unless there's a base prefix
+               b = 10
+               if ch == '0' {
+                       count = 1
+                       switch ch, err = r.ReadByte(); err {
+                       case nil:
+                               // possibly one of 0x, 0X, 0b, 0B
+                               if !fracOk {
+                                       b = 8
+                               }
+                               switch ch {
+                               case 'x', 'X':
+                                       b = 16
+                               case 'b', 'B':
+                                       b = 2
+                               }
+                               switch b {
+                               case 16, 2:
+                                       count = 0 // prefix is not counted
+                                       if ch, err = r.ReadByte(); err != nil {
+                                               // io.EOF is also an error in this case
+                                               return
+                                       }
+                               case 8:
+                                       count = 0 // prefix is not counted
+                               }
+                       case io.EOF:
+                               // input is "0"
+                               res = z[:0]
+                               err = nil
+                               return
+                       default:
+                               // read error
+                               return
+                       }
+               }
+       }
+
+       // convert string
+       // Algorithm: Collect digits in groups of at most n digits in di
+       // and then use mulAddWW for every such group to add them to the
+       // result.
+       z = z[:0]
+       b1 := Word(b)
+       bn, n := maxPow(b1) // at most n digits in base b1 fit into Word
+       di := Word(0)       // 0 <= di < b1**i < bn
+       i := 0              // 0 <= i < n
+       dp := -1            // position of decimal point
+       for {
+               if fracOk && ch == '.' {
+                       fracOk = false
+                       dp = count
+                       // advance
+                       if ch, err = r.ReadByte(); err != nil {
+                               if err == io.EOF {
+                                       err = nil
+                                       break
+                               }
+                               return
+                       }
+               }
+
+               // convert rune into digit value d1
+               var d1 Word
+               switch {
+               case '0' <= ch && ch <= '9':
+                       d1 = Word(ch - '0')
+               case 'a' <= ch && ch <= 'z':
+                       d1 = Word(ch - 'a' + 10)
+               case 'A' <= ch && ch <= 'Z':
+                       d1 = Word(ch - 'A' + 10)
+               default:
+                       d1 = MaxBase + 1
+               }
+               if d1 >= b1 {
+                       r.UnreadByte() // ch does not belong to number anymore
+                       break
+               }
+               count++
+
+               // collect d1 in di
+               di = di*b1 + d1
+               i++
+
+               // if di is "full", add it to the result
+               if i == n {
+                       z = z.mulAddWW(z, bn, di)
+                       di = 0
+                       i = 0
+               }
+
+               // advance
+               if ch, err = r.ReadByte(); err != nil {
+                       if err == io.EOF {
+                               err = nil
+                               break
+                       }
+                       return
+               }
+       }
+
+       if count == 0 {
+               // no digits found
+               switch {
+               case base == 0 && b == 8:
+                       // there was only the octal prefix 0 (possibly followed by digits > 7);
+                       // count as one digit and return base 10, not 8
+                       count = 1
+                       b = 10
+               case base != 0 || b != 8:
+                       // there was neither a mantissa digit nor the octal prefix 0
+                       err = errors.New("syntax error scanning number")
+               }
+               return
+       }
+       // count > 0
+
+       // add remaining digits to result
+       if i > 0 {
+               z = z.mulAddWW(z, pow(b1, i), di)
+       }
+       res = z.norm()
+
+       // adjust for fraction, if any
+       if dp >= 0 {
+               // 0 <= dp <= count > 0
+               count = dp - count
+       }
+
+       return
+}
+
+// Character sets for string conversion.
+const (
+       lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
+       uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+)
+
+// decimalString returns a decimal representation of x.
+// It calls x.string with the charset "0123456789".
+func (x nat) decimalString() string {
+       return x.string(lowercaseDigits[:10])
+}
+
+// hexString returns a hexadecimal representation of x.
+// It calls x.string with the charset "0123456789abcdef".
+func (x nat) hexString() string {
+       return x.string(lowercaseDigits[:16])
+}
+
+// string converts x to a string using digits from a charset; a digit with
+// value d is represented by charset[d]. The conversion base is determined
+// by len(charset), which must be >= 2 and <= 256.
+func (x nat) string(charset string) string {
+       b := Word(len(charset))
+
+       // special cases
+       switch {
+       case b < 2 || b > 256:
+               panic("invalid character set length")
+       case len(x) == 0:
+               return string(charset[0])
+       }
+
+       // allocate buffer for conversion
+       i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
+       s := make([]byte, i)
+
+       // convert power of two and non power of two bases separately
+       if b == b&-b {
+               // shift is base-b digit size in bits
+               shift := trailingZeroBits(b) // shift > 0 because b >= 2
+               mask := Word(1)<<shift - 1
+               w := x[0]
+               nbits := uint(_W) // number of unprocessed bits in w
+
+               // convert less-significant words
+               for k := 1; k < len(x); k++ {
+                       // convert full digits
+                       for nbits >= shift {
+                               i--
+                               s[i] = charset[w&mask]
+                               w >>= shift
+                               nbits -= shift
+                       }
+
+                       // convert any partial leading digit and advance to next word
+                       if nbits == 0 {
+                               // no partial digit remaining, just advance
+                               w = x[k]
+                               nbits = _W
+                       } else {
+                               // partial digit in current (k-1) and next (k) word
+                               w |= x[k] << nbits
+                               i--
+                               s[i] = charset[w&mask]
+
+                               // advance
+                               w = x[k] >> (shift - nbits)
+                               nbits = _W - (shift - nbits)
+                       }
+               }
+
+               // convert digits of most-significant word (omit leading zeros)
+               for nbits >= 0 && w != 0 {
+                       i--
+                       s[i] = charset[w&mask]
+                       w >>= shift
+                       nbits -= shift
+               }
+
+       } else {
+               bb, ndigits := maxPow(Word(b))
+
+               // construct table of successive squares of bb*leafSize to use in subdivisions
+               // result (table != nil) <=> (len(x) > leafSize > 0)
+               table := divisors(len(x), b, ndigits, bb)
+
+               // preserve x, create local copy for use by convertWords
+               q := nat(nil).set(x)
+
+               // convert q to string s in base b
+               q.convertWords(s, charset, b, ndigits, bb, table)
+
+               // strip leading zeros
+               // (x != 0; thus s must contain at least one non-zero digit
+               // and the loop will terminate)
+               i = 0
+               for zero := charset[0]; s[i] == zero; {
+                       i++
+               }
+       }
+
+       return string(s[i:])
+}
+
+// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
+// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
+// repeated nat/Word division.
+//
+// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
+// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
+// Recursive conversion divides q by its approximate square root, yielding two parts, each half
+// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
+// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
+// is made better by splitting the subblocks recursively. Best is to split blocks until one more
+// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
+// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
+// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
+// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
+// specific hardware.
+//
+func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
+       // split larger blocks recursively
+       if table != nil {
+               // len(q) > leafSize > 0
+               var r nat
+               index := len(table) - 1
+               for len(q) > leafSize {
+                       // find divisor close to sqrt(q) if possible, but in any case < q
+                       maxLength := q.bitLen()     // ~= log2 q, or at of least largest possible q of this bit length
+                       minLength := maxLength >> 1 // ~= log2 sqrt(q)
+                       for index > 0 && table[index-1].nbits > minLength {
+                               index-- // desired
+                       }
+                       if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
+                               index--
+                               if index < 0 {
+                                       panic("internal inconsistency")
+                               }
+                       }
+
+                       // split q into the two digit number (q'*bbb + r) to form independent subblocks
+                       q, r = q.div(r, q, table[index].bbb)
+
+                       // convert subblocks and collect results in s[:h] and s[h:]
+                       h := len(s) - table[index].ndigits
+                       r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index])
+                       s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1])
+               }
+       }
+
+       // having split any large blocks now process the remaining (small) block iteratively
+       i := len(s)
+       var r Word
+       if b == 10 {
+               // hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
+               for len(q) > 0 {
+                       // extract least significant, base bb "digit"
+                       q, r = q.divW(q, bb)
+                       for j := 0; j < ndigits && i > 0; j++ {
+                               i--
+                               // avoid % computation since r%10 == r - int(r/10)*10;
+                               // this appears to be faster for BenchmarkString10000Base10
+                               // and smaller strings (but a bit slower for larger ones)
+                               t := r / 10
+                               s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code
+                               r = t
+                       }
+               }
+       } else {
+               for len(q) > 0 {
+                       // extract least significant, base bb "digit"
+                       q, r = q.divW(q, bb)
+                       for j := 0; j < ndigits && i > 0; j++ {
+                               i--
+                               s[i] = charset[r%b]
+                               r /= b
+                       }
+               }
+       }
+
+       // prepend high-order zeroes
+       zero := charset[0]
+       for i > 0 { // while need more leading zeroes
+               i--
+               s[i] = zero
+       }
+}
+
+// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
+// Benchmark and configure leafSize using: go test -bench="Leaf"
+//   8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
+//   8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
+var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
+
+type divisor struct {
+       bbb     nat // divisor
+       nbits   int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
+       ndigits int // digit length of divisor in terms of output base digits
+}
+
+var cacheBase10 struct {
+       sync.Mutex
+       table [64]divisor // cached divisors for base 10
+}
+
+// expWW computes x**y
+func (z nat) expWW(x, y Word) nat {
+       return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
+}
+
+// construct table of powers of bb*leafSize to use in subdivisions
+func divisors(m int, b Word, ndigits int, bb Word) []divisor {
+       // only compute table when recursive conversion is enabled and x is large
+       if leafSize == 0 || m <= leafSize {
+               return nil
+       }
+
+       // determine k where (bb**leafSize)**(2**k) >= sqrt(x)
+       k := 1
+       for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 {
+               k++
+       }
+
+       // reuse and extend existing table of divisors or create new table as appropriate
+       var table []divisor // for b == 10, table overlaps with cacheBase10.table
+       if b == 10 {
+               cacheBase10.Lock()
+               table = cacheBase10.table[0:k] // reuse old table for this conversion
+       } else {
+               table = make([]divisor, k) // create new table for this conversion
+       }
+
+       // extend table
+       if table[k-1].ndigits == 0 {
+               // add new entries as needed
+               var larger nat
+               for i := 0; i < k; i++ {
+                       if table[i].ndigits == 0 {
+                               if i == 0 {
+                                       table[0].bbb = nat(nil).expWW(bb, Word(leafSize))
+                                       table[0].ndigits = ndigits * leafSize
+                               } else {
+                                       table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
+                                       table[i].ndigits = 2 * table[i-1].ndigits
+                               }
+
+                               // optimization: exploit aggregated extra bits in macro blocks
+                               larger = nat(nil).set(table[i].bbb)
+                               for mulAddVWW(larger, larger, b, 0) == 0 {
+                                       table[i].bbb = table[i].bbb.set(larger)
+                                       table[i].ndigits++
+                               }
+
+                               table[i].nbits = table[i].bbb.bitLen()
+                       }
+               }
+       }
+
+       if b == 10 {
+               cacheBase10.Unlock()
+       }
+
+       return table
+}
diff --git a/src/math/big/natconv_test.go b/src/math/big/natconv_test.go
new file mode 100644 (file)
index 0000000..d4c3fb4
--- /dev/null
@@ -0,0 +1,429 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+       "io"
+       "strings"
+       "testing"
+)
+
+func toString(x nat, charset string) string {
+       base := len(charset)
+
+       // special cases
+       switch {
+       case base < 2:
+               panic("illegal base")
+       case len(x) == 0:
+               return string(charset[0])
+       }
+
+       // allocate buffer for conversion
+       i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+       s := make([]byte, i)
+
+       // don't destroy x
+       q := nat(nil).set(x)
+
+       // convert
+       for len(q) > 0 {
+               i--
+               var r Word
+               q, r = q.divW(q, Word(base))
+               s[i] = charset[r]
+       }
+
+       return string(s[i:])
+}
+
+var strTests = []struct {
+       x nat    // nat value to be converted
+       c string // conversion charset
+       s string // expected result
+}{
+       {nil, "01", "0"},
+       {nat{1}, "01", "1"},
+       {nat{0xc5}, "01", "11000101"},
+       {nat{03271}, lowercaseDigits[:8], "3271"},
+       {nat{10}, lowercaseDigits[:10], "10"},
+       {nat{1234567890}, uppercaseDigits[:10], "1234567890"},
+       {nat{0xdeadbeef}, lowercaseDigits[:16], "deadbeef"},
+       {nat{0xdeadbeef}, uppercaseDigits[:16], "DEADBEEF"},
+       {nat{0x229be7}, lowercaseDigits[:17], "1a2b3c"},
+       {nat{0x309663e6}, uppercaseDigits[:32], "O9COV6"},
+}
+
+func TestString(t *testing.T) {
+       // test invalid character set explicitly
+       var panicStr string
+       func() {
+               defer func() {
+                       panicStr = recover().(string)
+               }()
+               natOne.string("0")
+       }()
+       if panicStr != "invalid character set length" {
+               t.Errorf("expected panic for invalid character set")
+       }
+
+       for _, a := range strTests {
+               s := a.x.string(a.c)
+               if s != a.s {
+                       t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
+               }
+
+               x, b, _, err := nat(nil).scan(strings.NewReader(a.s), len(a.c), false)
+               if x.cmp(a.x) != 0 {
+                       t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+               }
+               if b != len(a.c) {
+                       t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
+               }
+               if err != nil {
+                       t.Errorf("scan%+v\n\tgot error = %s", a, err)
+               }
+       }
+}
+
+var natScanTests = []struct {
+       s     string // string to be scanned
+       base  int    // input base
+       frac  bool   // fraction ok
+       x     nat    // expected nat
+       b     int    // expected base
+       count int    // expected digit count
+       ok    bool   // expected success
+       next  rune   // next character (or 0, if at EOF)
+}{
+       // error: illegal base
+       {base: -1},
+       {base: 37},
+
+       // error: no mantissa
+       {},
+       {s: "?"},
+       {base: 10},
+       {base: 36},
+       {s: "?", base: 10},
+       {s: "0x"},
+       {s: "345", base: 2},
+
+       // error: incorrect use of decimal point
+       {s: ".0"},
+       {s: ".0", base: 10},
+       {s: ".", base: 1},
+       {s: "0x.0"},
+
+       // no errors
+       {"0", 0, false, nil, 10, 1, true, 0},
+       {"0", 10, false, nil, 10, 1, true, 0},
+       {"0", 36, false, nil, 36, 1, true, 0},
+       {"1", 0, false, nat{1}, 10, 1, true, 0},
+       {"1", 10, false, nat{1}, 10, 1, true, 0},
+       {"0 ", 0, false, nil, 10, 1, true, ' '},
+       {"08", 0, false, nil, 10, 1, true, '8'},
+       {"08", 10, false, nat{8}, 10, 2, true, 0},
+       {"018", 0, false, nat{1}, 8, 1, true, '8'},
+       {"0b1", 0, false, nat{1}, 2, 1, true, 0},
+       {"0b11000101", 0, false, nat{0xc5}, 2, 8, true, 0},
+       {"03271", 0, false, nat{03271}, 8, 4, true, 0},
+       {"10ab", 0, false, nat{10}, 10, 2, true, 'a'},
+       {"1234567890", 0, false, nat{1234567890}, 10, 10, true, 0},
+       {"xyz", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, 0},
+       {"xyz?", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, '?'},
+       {"0x", 16, false, nil, 16, 1, true, 'x'},
+       {"0xdeadbeef", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
+       {"0XDEADBEEF", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
+
+       // no errors, decimal point
+       {"0.", 0, false, nil, 10, 1, true, '.'},
+       {"0.", 10, true, nil, 10, 0, true, 0},
+       {"0.1.2", 10, true, nat{1}, 10, -1, true, '.'},
+       {".000", 10, true, nil, 10, -3, true, 0},
+       {"12.3", 10, true, nat{123}, 10, -1, true, 0},
+       {"012.345", 10, true, nat{12345}, 10, -3, true, 0},
+}
+
+func TestScanBase(t *testing.T) {
+       for _, a := range natScanTests {
+               r := strings.NewReader(a.s)
+               x, b, count, err := nat(nil).scan(r, a.base, a.frac)
+               if err == nil && !a.ok {
+                       t.Errorf("scan%+v\n\texpected error", a)
+               }
+               if err != nil {
+                       if a.ok {
+                               t.Errorf("scan%+v\n\tgot error = %s", a, err)
+                       }
+                       continue
+               }
+               if x.cmp(a.x) != 0 {
+                       t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+               }
+               if b != a.b {
+                       t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
+               }
+               if count != a.count {
+                       t.Errorf("scan%+v\n\tgot count = %d; want %d", a, count, a.count)
+               }
+               next, _, err := r.ReadRune()
+               if err == io.EOF {
+                       next = 0
+                       err = nil
+               }
+               if err == nil && next != a.next {
+                       t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
+               }
+       }
+}
+
+var pi = "3" +
+       "14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
+       "32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
+       "28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
+       "96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
+       "31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
+       "60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
+       "22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
+       "29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
+       "81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
+       "21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
+       "55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
+       "63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
+       "75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
+       "45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
+       "34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
+       "16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
+       "04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
+       "26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
+       "99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
+       "53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
+       "68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
+       "13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
+       "88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
+       "79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
+       "68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
+       "21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
+       "06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
+       "14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
+       "21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
+       "05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
+       "23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
+       "90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
+       "31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
+       "20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
+       "97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
+       "44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
+       "44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
+       "85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
+       "58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
+       "27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
+       "09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
+       "79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
+       "06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
+       "91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
+       "94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
+       "78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
+       "24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
+       "59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
+       "34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
+       "88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
+       "94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
+
+// Test case for BenchmarkScanPi.
+func TestScanPi(t *testing.T) {
+       var x nat
+       z, _, _, err := x.scan(strings.NewReader(pi), 10, false)
+       if err != nil {
+               t.Errorf("scanning pi: %s", err)
+       }
+       if s := z.decimalString(); s != pi {
+               t.Errorf("scanning pi: got %s", s)
+       }
+}
+
+func TestScanPiParallel(t *testing.T) {
+       const n = 2
+       c := make(chan int)
+       for i := 0; i < n; i++ {
+               go func() {
+                       TestScanPi(t)
+                       c <- 0
+               }()
+       }
+       for i := 0; i < n; i++ {
+               <-c
+       }
+}
+
+func BenchmarkScanPi(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               var x nat
+               x.scan(strings.NewReader(pi), 10, false)
+       }
+}
+
+func BenchmarkStringPiParallel(b *testing.B) {
+       var x nat
+       x, _, _, _ = x.scan(strings.NewReader(pi), 0, false)
+       if x.decimalString() != pi {
+               panic("benchmark incorrect: conversion failed")
+       }
+       b.RunParallel(func(pb *testing.PB) {
+               for pb.Next() {
+                       x.decimalString()
+               }
+       })
+}
+
+func BenchmarkScan10Base2(b *testing.B)     { ScanHelper(b, 2, 10, 10) }
+func BenchmarkScan100Base2(b *testing.B)    { ScanHelper(b, 2, 10, 100) }
+func BenchmarkScan1000Base2(b *testing.B)   { ScanHelper(b, 2, 10, 1000) }
+func BenchmarkScan10000Base2(b *testing.B)  { ScanHelper(b, 2, 10, 10000) }
+func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
+
+func BenchmarkScan10Base8(b *testing.B)     { ScanHelper(b, 8, 10, 10) }
+func BenchmarkScan100Base8(b *testing.B)    { ScanHelper(b, 8, 10, 100) }
+func BenchmarkScan1000Base8(b *testing.B)   { ScanHelper(b, 8, 10, 1000) }
+func BenchmarkScan10000Base8(b *testing.B)  { ScanHelper(b, 8, 10, 10000) }
+func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
+
+func BenchmarkScan10Base10(b *testing.B)     { ScanHelper(b, 10, 10, 10) }
+func BenchmarkScan100Base10(b *testing.B)    { ScanHelper(b, 10, 10, 100) }
+func BenchmarkScan1000Base10(b *testing.B)   { ScanHelper(b, 10, 10, 1000) }
+func BenchmarkScan10000Base10(b *testing.B)  { ScanHelper(b, 10, 10, 10000) }
+func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
+
+func BenchmarkScan10Base16(b *testing.B)     { ScanHelper(b, 16, 10, 10) }
+func BenchmarkScan100Base16(b *testing.B)    { ScanHelper(b, 16, 10, 100) }
+func BenchmarkScan1000Base16(b *testing.B)   { ScanHelper(b, 16, 10, 1000) }
+func BenchmarkScan10000Base16(b *testing.B)  { ScanHelper(b, 16, 10, 10000) }
+func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
+
+func ScanHelper(b *testing.B, base int, x, y Word) {
+       b.StopTimer()
+       var z nat
+       z = z.expWW(x, y)
+
+       var s string
+       s = z.string(lowercaseDigits[:base])
+       if t := toString(z, lowercaseDigits[:base]); t != s {
+               b.Fatalf("scanning: got %s; want %s", s, t)
+       }
+       b.StartTimer()
+
+       for i := 0; i < b.N; i++ {
+               z.scan(strings.NewReader(s), base, false)
+       }
+}
+
+func BenchmarkString10Base2(b *testing.B)     { StringHelper(b, 2, 10, 10) }
+func BenchmarkString100Base2(b *testing.B)    { StringHelper(b, 2, 10, 100) }
+func BenchmarkString1000Base2(b *testing.B)   { StringHelper(b, 2, 10, 1000) }
+func BenchmarkString10000Base2(b *testing.B)  { StringHelper(b, 2, 10, 10000) }
+func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
+
+func BenchmarkString10Base8(b *testing.B)     { StringHelper(b, 8, 10, 10) }
+func BenchmarkString100Base8(b *testing.B)    { StringHelper(b, 8, 10, 100) }
+func BenchmarkString1000Base8(b *testing.B)   { StringHelper(b, 8, 10, 1000) }
+func BenchmarkString10000Base8(b *testing.B)  { StringHelper(b, 8, 10, 10000) }
+func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
+
+func BenchmarkString10Base10(b *testing.B)     { StringHelper(b, 10, 10, 10) }
+func BenchmarkString100Base10(b *testing.B)    { StringHelper(b, 10, 10, 100) }
+func BenchmarkString1000Base10(b *testing.B)   { StringHelper(b, 10, 10, 1000) }
+func BenchmarkString10000Base10(b *testing.B)  { StringHelper(b, 10, 10, 10000) }
+func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
+
+func BenchmarkString10Base16(b *testing.B)     { StringHelper(b, 16, 10, 10) }
+func BenchmarkString100Base16(b *testing.B)    { StringHelper(b, 16, 10, 100) }
+func BenchmarkString1000Base16(b *testing.B)   { StringHelper(b, 16, 10, 1000) }
+func BenchmarkString10000Base16(b *testing.B)  { StringHelper(b, 16, 10, 10000) }
+func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
+
+func StringHelper(b *testing.B, base int, x, y Word) {
+       b.StopTimer()
+       var z nat
+       z = z.expWW(x, y)
+       z.string(lowercaseDigits[:base]) // warm divisor cache
+       b.StartTimer()
+
+       for i := 0; i < b.N; i++ {
+               _ = z.string(lowercaseDigits[:base])
+       }
+}
+
+func BenchmarkLeafSize0(b *testing.B)  { LeafSizeHelper(b, 10, 0) } // test without splitting
+func BenchmarkLeafSize1(b *testing.B)  { LeafSizeHelper(b, 10, 1) }
+func BenchmarkLeafSize2(b *testing.B)  { LeafSizeHelper(b, 10, 2) }
+func BenchmarkLeafSize3(b *testing.B)  { LeafSizeHelper(b, 10, 3) }
+func BenchmarkLeafSize4(b *testing.B)  { LeafSizeHelper(b, 10, 4) }
+func BenchmarkLeafSize5(b *testing.B)  { LeafSizeHelper(b, 10, 5) }
+func BenchmarkLeafSize6(b *testing.B)  { LeafSizeHelper(b, 10, 6) }
+func BenchmarkLeafSize7(b *testing.B)  { LeafSizeHelper(b, 10, 7) }
+func BenchmarkLeafSize8(b *testing.B)  { LeafSizeHelper(b, 10, 8) }
+func BenchmarkLeafSize9(b *testing.B)  { LeafSizeHelper(b, 10, 9) }
+func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
+func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
+func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
+func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
+func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
+func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
+func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
+func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
+func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
+
+func LeafSizeHelper(b *testing.B, base Word, size int) {
+       b.StopTimer()
+       originalLeafSize := leafSize
+       resetTable(cacheBase10.table[:])
+       leafSize = size
+       b.StartTimer()
+
+       for d := 1; d <= 10000; d *= 10 {
+               b.StopTimer()
+               var z nat
+               z = z.expWW(base, Word(d))           // build target number
+               _ = z.string(lowercaseDigits[:base]) // warm divisor cache
+               b.StartTimer()
+
+               for i := 0; i < b.N; i++ {
+                       _ = z.string(lowercaseDigits[:base])
+               }
+       }
+
+       b.StopTimer()
+       resetTable(cacheBase10.table[:])
+       leafSize = originalLeafSize
+       b.StartTimer()
+}
+
+func resetTable(table []divisor) {
+       if table != nil && table[0].bbb != nil {
+               for i := 0; i < len(table); i++ {
+                       table[i].bbb = nil
+                       table[i].nbits = 0
+                       table[i].ndigits = 0
+               }
+       }
+}
+
+func TestStringPowers(t *testing.T) {
+       var b, p Word
+       for b = 2; b <= 16; b++ {
+               for p = 0; p <= 512; p++ {
+                       x := nat(nil).expWW(b, p)
+                       xs := x.string(lowercaseDigits[:b])
+                       xs2 := toString(x, lowercaseDigits[:b])
+                       if xs != xs2 {
+                               t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
+                       }
+               }
+               if b >= 3 && testing.Short() {
+                       break
+               }
+       }
+}
index c5339fe443184583dadb2d6a224123955e2440d8..b73377ea3f8ababb2c7aa33b2564e4e988f023ce 100644 (file)
@@ -11,7 +11,6 @@ import (
        "errors"
        "fmt"
        "math"
-       "strings"
 )
 
 // A Rat represents a quotient a/b of arbitrary precision.
@@ -324,14 +323,14 @@ func (z *Rat) SetFrac64(a, b int64) *Rat {
 // SetInt sets z to x (by making a copy of x) and returns z.
 func (z *Rat) SetInt(x *Int) *Rat {
        z.a.Set(x)
-       z.b.abs = z.b.abs.make(0)
+       z.b.abs = z.b.abs[:0]
        return z
 }
 
 // SetInt64 sets z to x and returns z.
 func (z *Rat) SetInt64(x int64) *Rat {
        z.a.SetInt64(x)
-       z.b.abs = z.b.abs.make(0)
+       z.b.abs = z.b.abs[:0]
        return z
 }
 
@@ -370,7 +369,7 @@ func (z *Rat) Inv(x *Rat) *Rat {
        }
        b := z.a.abs
        if b.cmp(natOne) == 0 {
-               b = b.make(0) // normalize denominator
+               b = b[:0] // normalize denominator
        }
        z.a.abs, z.b.abs = a, b // sign doesn't change
        return z
@@ -415,12 +414,12 @@ func (z *Rat) norm() *Rat {
        case len(z.a.abs) == 0:
                // z == 0 - normalize sign and denominator
                z.a.neg = false
-               z.b.abs = z.b.abs.make(0)
+               z.b.abs = z.b.abs[:0]
        case len(z.b.abs) == 0:
                // z is normalized int - nothing to do
        case z.b.abs.cmp(natOne) == 0:
                // z is int - normalize denominator
-               z.b.abs = z.b.abs.make(0)
+               z.b.abs = z.b.abs[:0]
        default:
                neg := z.a.neg
                z.a.neg = false
@@ -430,7 +429,7 @@ func (z *Rat) norm() *Rat {
                        z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs)
                        if z.b.abs.cmp(natOne) == 0 {
                                // z is int - normalize denominator
-                               z.b.abs = z.b.abs.make(0)
+                               z.b.abs = z.b.abs[:0]
                        }
                }
                z.a.neg = neg
@@ -512,151 +511,6 @@ func (z *Rat) Quo(x, y *Rat) *Rat {
        return z.norm()
 }
 
-func ratTok(ch rune) bool {
-       return strings.IndexRune("+-/0123456789.eE", ch) >= 0
-}
-
-// Scan is a support routine for fmt.Scanner. It accepts the formats
-// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
-func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
-       tok, err := s.Token(true, ratTok)
-       if err != nil {
-               return err
-       }
-       if strings.IndexRune("efgEFGv", ch) < 0 {
-               return errors.New("Rat.Scan: invalid verb")
-       }
-       if _, ok := z.SetString(string(tok)); !ok {
-               return errors.New("Rat.Scan: invalid syntax")
-       }
-       return nil
-}
-
-// SetString sets z to the value of s and returns z and a boolean indicating
-// success. s can be given as a fraction "a/b" or as a floating-point number
-// optionally followed by an exponent. If the operation failed, the value of
-// z is undefined but the returned value is nil.
-func (z *Rat) SetString(s string) (*Rat, bool) {
-       if len(s) == 0 {
-               return nil, false
-       }
-
-       // check for a quotient
-       sep := strings.Index(s, "/")
-       if sep >= 0 {
-               if _, ok := z.a.SetString(s[0:sep], 10); !ok {
-                       return nil, false
-               }
-               s = s[sep+1:]
-               var err error
-               if z.b.abs, _, err = z.b.abs.scan(strings.NewReader(s), 10); err != nil {
-                       return nil, false
-               }
-               if len(z.b.abs) == 0 {
-                       return nil, false
-               }
-               return z.norm(), true
-       }
-
-       // check for a decimal point
-       sep = strings.Index(s, ".")
-       // check for an exponent
-       e := strings.IndexAny(s, "eE")
-       var exp Int
-       if e >= 0 {
-               if e < sep {
-                       // The E must come after the decimal point.
-                       return nil, false
-               }
-               if _, ok := exp.SetString(s[e+1:], 10); !ok {
-                       return nil, false
-               }
-               s = s[0:e]
-       }
-       if sep >= 0 {
-               s = s[0:sep] + s[sep+1:]
-               exp.Sub(&exp, NewInt(int64(len(s)-sep)))
-       }
-
-       if _, ok := z.a.SetString(s, 10); !ok {
-               return nil, false
-       }
-       powTen := nat(nil).expNN(natTen, exp.abs, nil)
-       if exp.neg {
-               z.b.abs = powTen
-               z.norm()
-       } else {
-               z.a.abs = z.a.abs.mul(z.a.abs, powTen)
-               z.b.abs = z.b.abs.make(0)
-       }
-
-       return z, true
-}
-
-// String returns a string representation of x in the form "a/b" (even if b == 1).
-func (x *Rat) String() string {
-       s := "/1"
-       if len(x.b.abs) != 0 {
-               s = "/" + x.b.abs.decimalString()
-       }
-       return x.a.String() + s
-}
-
-// RatString returns a string representation of x in the form "a/b" if b != 1,
-// and in the form "a" if b == 1.
-func (x *Rat) RatString() string {
-       if x.IsInt() {
-               return x.a.String()
-       }
-       return x.String()
-}
-
-// FloatString returns a string representation of x in decimal form with prec
-// digits of precision after the decimal point and the last digit rounded.
-func (x *Rat) FloatString(prec int) string {
-       if x.IsInt() {
-               s := x.a.String()
-               if prec > 0 {
-                       s += "." + strings.Repeat("0", prec)
-               }
-               return s
-       }
-       // x.b.abs != 0
-
-       q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
-
-       p := natOne
-       if prec > 0 {
-               p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
-       }
-
-       r = r.mul(r, p)
-       r, r2 := r.div(nat(nil), r, x.b.abs)
-
-       // see if we need to round up
-       r2 = r2.add(r2, r2)
-       if x.b.abs.cmp(r2) <= 0 {
-               r = r.add(r, natOne)
-               if r.cmp(p) >= 0 {
-                       q = nat(nil).add(q, natOne)
-                       r = nat(nil).sub(r, p)
-               }
-       }
-
-       s := q.decimalString()
-       if x.a.neg {
-               s = "-" + s
-       }
-
-       if prec > 0 {
-               rs := r.decimalString()
-               leadingZeros := prec - len(rs)
-               s += "." + strings.Repeat("0", leadingZeros) + rs
-       }
-
-       return s
-}
-
 // Gob codec version. Permits backward-compatible changes to the encoding.
 const ratGobVersion byte = 1
 
@@ -667,7 +521,7 @@ func (x *Rat) GobEncode() ([]byte, error) {
        }
        buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
        i := x.b.abs.bytes(buf)
-       j := x.a.abs.bytes(buf[0:i])
+       j := x.a.abs.bytes(buf[:i])
        n := i - j
        if int(uint32(n)) != n {
                // this should never happen
index 5dbbb3510f09cc3c308467e15d352c0a646530fd..012d0c47ec4fb857553e9bb6de246f102dfd8348 100644 (file)
@@ -9,10 +9,7 @@ import (
        "encoding/gob"
        "encoding/json"
        "encoding/xml"
-       "fmt"
        "math"
-       "strconv"
-       "strings"
        "testing"
 )
 
@@ -56,112 +53,6 @@ func TestZeroRat(t *testing.T) {
        z.Quo(&x, &y)
 }
 
-var setStringTests = []struct {
-       in, out string
-       ok      bool
-}{
-       {"0", "0", true},
-       {"-0", "0", true},
-       {"1", "1", true},
-       {"-1", "-1", true},
-       {"1.", "1", true},
-       {"1e0", "1", true},
-       {"1.e1", "10", true},
-       {in: "1e", ok: false},
-       {in: "1.e", ok: false},
-       {in: "1e+14e-5", ok: false},
-       {in: "1e4.5", ok: false},
-       {in: "r", ok: false},
-       {in: "a/b", ok: false},
-       {in: "a.b", ok: false},
-       {"-0.1", "-1/10", true},
-       {"-.1", "-1/10", true},
-       {"2/4", "1/2", true},
-       {".25", "1/4", true},
-       {"-1/5", "-1/5", true},
-       {"8129567.7690E14", "812956776900000000000", true},
-       {"78189e+4", "781890000", true},
-       {"553019.8935e+8", "55301989350000", true},
-       {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
-       {"9877861857500000E-7", "3951144743/4", true},
-       {"2169378.417e-3", "2169378417/1000000", true},
-       {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
-       {"53/70893980658822810696", "53/70893980658822810696", true},
-       {"106/141787961317645621392", "53/70893980658822810696", true},
-       {"204211327800791583.81095", "4084226556015831676219/20000", true},
-       {in: "1/0", ok: false},
-}
-
-func TestRatSetString(t *testing.T) {
-       for i, test := range setStringTests {
-               x, ok := new(Rat).SetString(test.in)
-
-               if ok {
-                       if !test.ok {
-                               t.Errorf("#%d SetString(%q) expected failure", i, test.in)
-                       } else if x.RatString() != test.out {
-                               t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
-                       }
-               } else if x != nil {
-                       t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
-               }
-       }
-}
-
-func TestRatScan(t *testing.T) {
-       var buf bytes.Buffer
-       for i, test := range setStringTests {
-               x := new(Rat)
-               buf.Reset()
-               buf.WriteString(test.in)
-
-               _, err := fmt.Fscanf(&buf, "%v", x)
-               if err == nil != test.ok {
-                       if test.ok {
-                               t.Errorf("#%d error: %s", i, err)
-                       } else {
-                               t.Errorf("#%d expected error", i)
-                       }
-                       continue
-               }
-               if err == nil && x.RatString() != test.out {
-                       t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
-               }
-       }
-}
-
-var floatStringTests = []struct {
-       in   string
-       prec int
-       out  string
-}{
-       {"0", 0, "0"},
-       {"0", 4, "0.0000"},
-       {"1", 0, "1"},
-       {"1", 2, "1.00"},
-       {"-1", 0, "-1"},
-       {".25", 2, "0.25"},
-       {".25", 1, "0.3"},
-       {".25", 3, "0.250"},
-       {"-1/3", 3, "-0.333"},
-       {"-2/3", 4, "-0.6667"},
-       {"0.96", 1, "1.0"},
-       {"0.999", 2, "1.00"},
-       {"0.9", 0, "1"},
-       {".25", -1, "0"},
-       {".55", -1, "1"},
-}
-
-func TestFloatString(t *testing.T) {
-       for i, test := range floatStringTests {
-               x, _ := new(Rat).SetString(test.in)
-
-               if x.FloatString(test.prec) != test.out {
-                       t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
-               }
-       }
-}
-
 func TestRatSign(t *testing.T) {
        zero := NewRat(0, 1)
        for _, a := range setStringTests {
@@ -592,321 +483,6 @@ func TestIssue3521(t *testing.T) {
        }
 }
 
-// Test inputs to Rat.SetString.  The prefix "long:" causes the test
-// to be skipped in --test.short mode.  (The threshold is about 500us.)
-var float64inputs = []string{
-       // Constants plundered from strconv/testfp.txt.
-
-       // Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
-       "5e+125",
-       "69e+267",
-       "999e-026",
-       "7861e-034",
-       "75569e-254",
-       "928609e-261",
-       "9210917e+080",
-       "84863171e+114",
-       "653777767e+273",
-       "5232604057e-298",
-       "27235667517e-109",
-       "653532977297e-123",
-       "3142213164987e-294",
-       "46202199371337e-072",
-       "231010996856685e-073",
-       "9324754620109615e+212",
-       "78459735791271921e+049",
-       "272104041512242479e+200",
-       "6802601037806061975e+198",
-       "20505426358836677347e-221",
-       "836168422905420598437e-234",
-       "4891559871276714924261e+222",
-
-       // Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
-       "9e-265",
-       "85e-037",
-       "623e+100",
-       "3571e+263",
-       "81661e+153",
-       "920657e-023",
-       "4603285e-024",
-       "87575437e-309",
-       "245540327e+122",
-       "6138508175e+120",
-       "83356057653e+193",
-       "619534293513e+124",
-       "2335141086879e+218",
-       "36167929443327e-159",
-       "609610927149051e-255",
-       "3743626360493413e-165",
-       "94080055902682397e-242",
-       "899810892172646163e+283",
-       "7120190517612959703e+120",
-       "25188282901709339043e-252",
-       "308984926168550152811e-052",
-       "6372891218502368041059e+064",
-
-       // Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
-       "5e-20",
-       "67e+14",
-       "985e+15",
-       "7693e-42",
-       "55895e-16",
-       "996622e-44",
-       "7038531e-32",
-       "60419369e-46",
-       "702990899e-20",
-       "6930161142e-48",
-       "25933168707e+13",
-       "596428896559e+20",
-
-       // Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
-       "3e-23",
-       "57e+18",
-       "789e-35",
-       "2539e-18",
-       "76173e+28",
-       "887745e-11",
-       "5382571e-37",
-       "82381273e-35",
-       "750486563e-38",
-       "3752432815e-39",
-       "75224575729e-45",
-       "459926601011e+15",
-
-       // Constants plundered from strconv/atof_test.go.
-
-       "0",
-       "1",
-       "+1",
-       "1e23",
-       "1E23",
-       "100000000000000000000000",
-       "1e-100",
-       "123456700",
-       "99999999999999974834176",
-       "100000000000000000000001",
-       "100000000000000008388608",
-       "100000000000000016777215",
-       "100000000000000016777216",
-       "-1",
-       "-0.1",
-       "-0", // NB: exception made for this input
-       "1e-20",
-       "625e-3",
-
-       // largest float64
-       "1.7976931348623157e308",
-       "-1.7976931348623157e308",
-       // next float64 - too large
-       "1.7976931348623159e308",
-       "-1.7976931348623159e308",
-       // the border is ...158079
-       // borderline - okay
-       "1.7976931348623158e308",
-       "-1.7976931348623158e308",
-       // borderline - too large
-       "1.797693134862315808e308",
-       "-1.797693134862315808e308",
-
-       // a little too large
-       "1e308",
-       "2e308",
-       "1e309",
-
-       // way too large
-       "1e310",
-       "-1e310",
-       "1e400",
-       "-1e400",
-       "long:1e400000",
-       "long:-1e400000",
-
-       // denormalized
-       "1e-305",
-       "1e-306",
-       "1e-307",
-       "1e-308",
-       "1e-309",
-       "1e-310",
-       "1e-322",
-       // smallest denormal
-       "5e-324",
-       "4e-324",
-       "3e-324",
-       // too small
-       "2e-324",
-       // way too small
-       "1e-350",
-       "long:1e-400000",
-       // way too small, negative
-       "-1e-350",
-       "long:-1e-400000",
-
-       // try to overflow exponent
-       // [Disabled: too slow and memory-hungry with rationals.]
-       // "1e-4294967296",
-       // "1e+4294967296",
-       // "1e-18446744073709551616",
-       // "1e+18446744073709551616",
-
-       // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
-       "2.2250738585072012e-308",
-       // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
-       "2.2250738585072011e-308",
-
-       // A very large number (initially wrongly parsed by the fast algorithm).
-       "4.630813248087435e+307",
-
-       // A different kind of very large number.
-       "22.222222222222222",
-       "long:2." + strings.Repeat("2", 4000) + "e+1",
-
-       // Exactly halfway between 1 and math.Nextafter(1, 2).
-       // Round to even (down).
-       "1.00000000000000011102230246251565404236316680908203125",
-       // Slightly lower; still round down.
-       "1.00000000000000011102230246251565404236316680908203124",
-       // Slightly higher; round up.
-       "1.00000000000000011102230246251565404236316680908203126",
-       // Slightly higher, but you have to read all the way to the end.
-       "long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1",
-
-       // Smallest denormal, 2^(-1022-52)
-       "4.940656458412465441765687928682213723651e-324",
-       // Half of smallest denormal, 2^(-1022-53)
-       "2.470328229206232720882843964341106861825e-324",
-       // A little more than the exact half of smallest denormal
-       // 2^-1075 + 2^-1100.  (Rounds to 1p-1074.)
-       "2.470328302827751011111470718709768633275e-324",
-       // The exact halfway between smallest normal and largest denormal:
-       // 2^-1022 - 2^-1075.  (Rounds to 2^-1022.)
-       "2.225073858507201136057409796709131975935e-308",
-
-       "1152921504606846975",  //   1<<60 - 1
-       "-1152921504606846975", // -(1<<60 - 1)
-       "1152921504606846977",  //   1<<60 + 1
-       "-1152921504606846977", // -(1<<60 + 1)
-
-       "1/3",
-}
-
-// isFinite reports whether f represents a finite rational value.
-// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
-func isFinite(f float64) bool {
-       return math.Abs(f) <= math.MaxFloat64
-}
-
-func TestFloat32SpecialCases(t *testing.T) {
-       for _, input := range float64inputs {
-               if strings.HasPrefix(input, "long:") {
-                       if testing.Short() {
-                               continue
-                       }
-                       input = input[len("long:"):]
-               }
-
-               r, ok := new(Rat).SetString(input)
-               if !ok {
-                       t.Errorf("Rat.SetString(%q) failed", input)
-                       continue
-               }
-               f, exact := r.Float32()
-
-               // 1. Check string -> Rat -> float32 conversions are
-               // consistent with strconv.ParseFloat.
-               // Skip this check if the input uses "a/b" rational syntax.
-               if !strings.Contains(input, "/") {
-                       e64, _ := strconv.ParseFloat(input, 32)
-                       e := float32(e64)
-
-                       // Careful: negative Rats too small for
-                       // float64 become -0, but Rat obviously cannot
-                       // preserve the sign from SetString("-0").
-                       switch {
-                       case math.Float32bits(e) == math.Float32bits(f):
-                               // Ok: bitwise equal.
-                       case f == 0 && r.Num().BitLen() == 0:
-                               // Ok: Rat(0) is equivalent to both +/- float64(0).
-                       default:
-                               t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
-                       }
-               }
-
-               if !isFinite(float64(f)) {
-                       continue
-               }
-
-               // 2. Check f is best approximation to r.
-               if !checkIsBestApprox32(t, f, r) {
-                       // Append context information.
-                       t.Errorf("(input was %q)", input)
-               }
-
-               // 3. Check f->R->f roundtrip is non-lossy.
-               checkNonLossyRoundtrip32(t, f)
-
-               // 4. Check exactness using slow algorithm.
-               if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact {
-                       t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact)
-               }
-       }
-}
-
-func TestFloat64SpecialCases(t *testing.T) {
-       for _, input := range float64inputs {
-               if strings.HasPrefix(input, "long:") {
-                       if testing.Short() {
-                               continue
-                       }
-                       input = input[len("long:"):]
-               }
-
-               r, ok := new(Rat).SetString(input)
-               if !ok {
-                       t.Errorf("Rat.SetString(%q) failed", input)
-                       continue
-               }
-               f, exact := r.Float64()
-
-               // 1. Check string -> Rat -> float64 conversions are
-               // consistent with strconv.ParseFloat.
-               // Skip this check if the input uses "a/b" rational syntax.
-               if !strings.Contains(input, "/") {
-                       e, _ := strconv.ParseFloat(input, 64)
-
-                       // Careful: negative Rats too small for
-                       // float64 become -0, but Rat obviously cannot
-                       // preserve the sign from SetString("-0").
-                       switch {
-                       case math.Float64bits(e) == math.Float64bits(f):
-                               // Ok: bitwise equal.
-                       case f == 0 && r.Num().BitLen() == 0:
-                               // Ok: Rat(0) is equivalent to both +/- float64(0).
-                       default:
-                               t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
-                       }
-               }
-
-               if !isFinite(f) {
-                       continue
-               }
-
-               // 2. Check f is best approximation to r.
-               if !checkIsBestApprox64(t, f, r) {
-                       // Append context information.
-                       t.Errorf("(input was %q)", input)
-               }
-
-               // 3. Check f->R->f roundtrip is non-lossy.
-               checkNonLossyRoundtrip64(t, f)
-
-               // 4. Check exactness using slow algorithm.
-               if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
-                       t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
-               }
-       }
-}
-
 func TestFloat32Distribution(t *testing.T) {
        // Generate a distribution of (sign, mantissa, exp) values
        // broader than the float32 range, and check Rat.Float32()
diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go
new file mode 100644 (file)
index 0000000..da4915e
--- /dev/null
@@ -0,0 +1,238 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements rat-to-string conversion functions.
+
+package big
+
+import (
+       "errors"
+       "fmt"
+       "io"
+       "strconv"
+       "strings"
+)
+
+func ratTok(ch rune) bool {
+       return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+}
+
+// Scan is a support routine for fmt.Scanner. It accepts the formats
+// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
+func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
+       tok, err := s.Token(true, ratTok)
+       if err != nil {
+               return err
+       }
+       if strings.IndexRune("efgEFGv", ch) < 0 {
+               return errors.New("Rat.Scan: invalid verb")
+       }
+       if _, ok := z.SetString(string(tok)); !ok {
+               return errors.New("Rat.Scan: invalid syntax")
+       }
+       return nil
+}
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s can be given as a fraction "a/b" or as a floating-point number
+// optionally followed by an exponent. If the operation failed, the value of
+// z is undefined but the returned value is nil.
+func (z *Rat) SetString(s string) (*Rat, bool) {
+       if len(s) == 0 {
+               return nil, false
+       }
+       // len(s) > 0
+
+       // parse fraction a/b, if any
+       if sep := strings.Index(s, "/"); sep >= 0 {
+               if _, ok := z.a.SetString(s[:sep], 0); !ok {
+                       return nil, false
+               }
+               s = s[sep+1:]
+               var err error
+               if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
+                       return nil, false
+               }
+               if len(z.b.abs) == 0 {
+                       return nil, false
+               }
+               return z.norm(), true
+       }
+
+       // parse floating-point number
+       r := strings.NewReader(s)
+
+       // sign
+       neg, err := scanSign(r)
+       if err != nil {
+               return nil, false
+       }
+
+       // mantissa
+       var ecorr int
+       z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
+       if err != nil {
+               return nil, false
+       }
+
+       // exponent
+       var exp int64
+       var ebase int
+       exp, ebase, err = scanExponent(r)
+       if ebase == 2 || err != nil {
+               return nil, false
+       }
+
+       // there should be no unread characters left
+       if _, err = r.ReadByte(); err != io.EOF {
+               return nil, false
+       }
+
+       // correct exponent
+       if ecorr < 0 {
+               exp += int64(ecorr)
+       }
+
+       // compute exponent power
+       expabs := exp
+       if expabs < 0 {
+               expabs = -expabs
+       }
+       powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
+
+       // complete fraction
+       if exp < 0 {
+               z.b.abs = powTen
+               z.norm()
+       } else {
+               z.a.abs = z.a.abs.mul(z.a.abs, powTen)
+               z.b.abs = z.b.abs[:0]
+       }
+
+       z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
+
+       return z, true
+}
+
+func scanExponent(r io.ByteScanner) (exp int64, base int, err error) {
+       base = 10
+
+       var ch byte
+       if ch, err = r.ReadByte(); err != nil {
+               if err == io.EOF {
+                       err = nil // no exponent; same as e0
+               }
+               return
+       }
+
+       switch ch {
+       case 'e', 'E':
+               // ok
+       case 'p':
+               base = 2
+       default:
+               r.UnreadByte()
+               return // no exponent; same as e0
+       }
+
+       var neg bool
+       if neg, err = scanSign(r); err != nil {
+               return
+       }
+
+       var digits []byte
+       if neg {
+               digits = append(digits, '-')
+       }
+
+       // no need to use nat.scan for exponent digits
+       // since we only care about int64 values - the
+       // from-scratch scan is easy enough and faster
+       for i := 0; ; i++ {
+               if ch, err = r.ReadByte(); err != nil {
+                       if err != io.EOF || i == 0 {
+                               return
+                       }
+                       err = nil
+                       break // i > 0
+               }
+               if ch < '0' || '9' < ch {
+                       if i == 0 {
+                               r.UnreadByte()
+                               err = fmt.Errorf("invalid exponent (missing digits)")
+                               return
+                       }
+                       break // i > 0
+               }
+               digits = append(digits, byte(ch))
+       }
+       // i > 0 => we have at least one digit
+
+       exp, err = strconv.ParseInt(string(digits), 10, 64)
+       return
+}
+
+// String returns a string representation of x in the form "a/b" (even if b == 1).
+func (x *Rat) String() string {
+       s := "/1"
+       if len(x.b.abs) != 0 {
+               s = "/" + x.b.abs.decimalString()
+       }
+       return x.a.String() + s
+}
+
+// RatString returns a string representation of x in the form "a/b" if b != 1,
+// and in the form "a" if b == 1.
+func (x *Rat) RatString() string {
+       if x.IsInt() {
+               return x.a.String()
+       }
+       return x.String()
+}
+
+// FloatString returns a string representation of x in decimal form with prec
+// digits of precision after the decimal point and the last digit rounded.
+func (x *Rat) FloatString(prec int) string {
+       if x.IsInt() {
+               s := x.a.String()
+               if prec > 0 {
+                       s += "." + strings.Repeat("0", prec)
+               }
+               return s
+       }
+       // x.b.abs != 0
+
+       q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
+
+       p := natOne
+       if prec > 0 {
+               p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
+       }
+
+       r = r.mul(r, p)
+       r, r2 := r.div(nat(nil), r, x.b.abs)
+
+       // see if we need to round up
+       r2 = r2.add(r2, r2)
+       if x.b.abs.cmp(r2) <= 0 {
+               r = r.add(r, natOne)
+               if r.cmp(p) >= 0 {
+                       q = nat(nil).add(q, natOne)
+                       r = nat(nil).sub(r, p)
+               }
+       }
+
+       s := q.decimalString()
+       if x.a.neg {
+               s = "-" + s
+       }
+
+       if prec > 0 {
+               rs := r.decimalString()
+               leadingZeros := prec - len(rs)
+               s += "." + strings.Repeat("0", leadingZeros) + rs
+       }
+
+       return s
+}
diff --git a/src/math/big/ratconv_test.go b/src/math/big/ratconv_test.go
new file mode 100644 (file)
index 0000000..16b3a19
--- /dev/null
@@ -0,0 +1,451 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+       "bytes"
+       "fmt"
+       "math"
+       "strconv"
+       "strings"
+       "testing"
+)
+
+type StringTest struct {
+       in, out string
+       ok      bool
+}
+
+var setStringTests = []StringTest{
+       {"0", "0", true},
+       {"-0", "0", true},
+       {"1", "1", true},
+       {"-1", "-1", true},
+       {"1.", "1", true},
+       {"1e0", "1", true},
+       {"1.e1", "10", true},
+       {in: "1e"},
+       {in: "1.e"},
+       {in: "1e+14e-5"},
+       {in: "1e4.5"},
+       {in: "r"},
+       {in: "a/b"},
+       {in: "a.b"},
+       {"-0.1", "-1/10", true},
+       {"-.1", "-1/10", true},
+       {"2/4", "1/2", true},
+       {".25", "1/4", true},
+       {"-1/5", "-1/5", true},
+       {"8129567.7690E14", "812956776900000000000", true},
+       {"78189e+4", "781890000", true},
+       {"553019.8935e+8", "55301989350000", true},
+       {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
+       {"9877861857500000E-7", "3951144743/4", true},
+       {"2169378.417e-3", "2169378417/1000000", true},
+       {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
+       {"53/70893980658822810696", "53/70893980658822810696", true},
+       {"106/141787961317645621392", "53/70893980658822810696", true},
+       {"204211327800791583.81095", "4084226556015831676219/20000", true},
+       {in: "1/0"},
+}
+
+// These are not supported by fmt.Fscanf.
+var setStringTests2 = []StringTest{
+       {"0x10", "16", true},
+       {"-010/1", "-8", true}, // TODO(gri) should we even permit octal here?
+       {"-010.", "-10", true},
+       {"0x10/0x20", "1/2", true},
+       {"0b1000/3", "8/3", true},
+       // TODO(gri) add more tests
+}
+
+func TestRatSetString(t *testing.T) {
+       var tests []StringTest
+       tests = append(tests, setStringTests...)
+       tests = append(tests, setStringTests2...)
+
+       for i, test := range tests {
+               x, ok := new(Rat).SetString(test.in)
+
+               if ok {
+                       if !test.ok {
+                               t.Errorf("#%d SetString(%q) expected failure", i, test.in)
+                       } else if x.RatString() != test.out {
+                               t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
+                       }
+               } else if x != nil {
+                       t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
+               }
+       }
+}
+
+func TestRatScan(t *testing.T) {
+       var buf bytes.Buffer
+       for i, test := range setStringTests {
+               x := new(Rat)
+               buf.Reset()
+               buf.WriteString(test.in)
+
+               _, err := fmt.Fscanf(&buf, "%v", x)
+               if err == nil != test.ok {
+                       if test.ok {
+                               t.Errorf("#%d (%s) error: %s", i, test.in, err)
+                       } else {
+                               t.Errorf("#%d (%s) expected error", i, test.in)
+                       }
+                       continue
+               }
+               if err == nil && x.RatString() != test.out {
+                       t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+               }
+       }
+}
+
+var floatStringTests = []struct {
+       in   string
+       prec int
+       out  string
+}{
+       {"0", 0, "0"},
+       {"0", 4, "0.0000"},
+       {"1", 0, "1"},
+       {"1", 2, "1.00"},
+       {"-1", 0, "-1"},
+       {".25", 2, "0.25"},
+       {".25", 1, "0.3"},
+       {".25", 3, "0.250"},
+       {"-1/3", 3, "-0.333"},
+       {"-2/3", 4, "-0.6667"},
+       {"0.96", 1, "1.0"},
+       {"0.999", 2, "1.00"},
+       {"0.9", 0, "1"},
+       {".25", -1, "0"},
+       {".55", -1, "1"},
+}
+
+func TestFloatString(t *testing.T) {
+       for i, test := range floatStringTests {
+               x, _ := new(Rat).SetString(test.in)
+
+               if x.FloatString(test.prec) != test.out {
+                       t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
+               }
+       }
+}
+
+// Test inputs to Rat.SetString.  The prefix "long:" causes the test
+// to be skipped in --test.short mode.  (The threshold is about 500us.)
+var float64inputs = []string{
+       // Constants plundered from strconv/testfp.txt.
+
+       // Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
+       "5e+125",
+       "69e+267",
+       "999e-026",
+       "7861e-034",
+       "75569e-254",
+       "928609e-261",
+       "9210917e+080",
+       "84863171e+114",
+       "653777767e+273",
+       "5232604057e-298",
+       "27235667517e-109",
+       "653532977297e-123",
+       "3142213164987e-294",
+       "46202199371337e-072",
+       "231010996856685e-073",
+       "9324754620109615e+212",
+       "78459735791271921e+049",
+       "272104041512242479e+200",
+       "6802601037806061975e+198",
+       "20505426358836677347e-221",
+       "836168422905420598437e-234",
+       "4891559871276714924261e+222",
+
+       // Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
+       "9e-265",
+       "85e-037",
+       "623e+100",
+       "3571e+263",
+       "81661e+153",
+       "920657e-023",
+       "4603285e-024",
+       "87575437e-309",
+       "245540327e+122",
+       "6138508175e+120",
+       "83356057653e+193",
+       "619534293513e+124",
+       "2335141086879e+218",
+       "36167929443327e-159",
+       "609610927149051e-255",
+       "3743626360493413e-165",
+       "94080055902682397e-242",
+       "899810892172646163e+283",
+       "7120190517612959703e+120",
+       "25188282901709339043e-252",
+       "308984926168550152811e-052",
+       "6372891218502368041059e+064",
+
+       // Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
+       "5e-20",
+       "67e+14",
+       "985e+15",
+       "7693e-42",
+       "55895e-16",
+       "996622e-44",
+       "7038531e-32",
+       "60419369e-46",
+       "702990899e-20",
+       "6930161142e-48",
+       "25933168707e+13",
+       "596428896559e+20",
+
+       // Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
+       "3e-23",
+       "57e+18",
+       "789e-35",
+       "2539e-18",
+       "76173e+28",
+       "887745e-11",
+       "5382571e-37",
+       "82381273e-35",
+       "750486563e-38",
+       "3752432815e-39",
+       "75224575729e-45",
+       "459926601011e+15",
+
+       // Constants plundered from strconv/atof_test.go.
+
+       "0",
+       "1",
+       "+1",
+       "1e23",
+       "1E23",
+       "100000000000000000000000",
+       "1e-100",
+       "123456700",
+       "99999999999999974834176",
+       "100000000000000000000001",
+       "100000000000000008388608",
+       "100000000000000016777215",
+       "100000000000000016777216",
+       "-1",
+       "-0.1",
+       "-0", // NB: exception made for this input
+       "1e-20",
+       "625e-3",
+
+       // largest float64
+       "1.7976931348623157e308",
+       "-1.7976931348623157e308",
+       // next float64 - too large
+       "1.7976931348623159e308",
+       "-1.7976931348623159e308",
+       // the border is ...158079
+       // borderline - okay
+       "1.7976931348623158e308",
+       "-1.7976931348623158e308",
+       // borderline - too large
+       "1.797693134862315808e308",
+       "-1.797693134862315808e308",
+
+       // a little too large
+       "1e308",
+       "2e308",
+       "1e309",
+
+       // way too large
+       "1e310",
+       "-1e310",
+       "1e400",
+       "-1e400",
+       "long:1e400000",
+       "long:-1e400000",
+
+       // denormalized
+       "1e-305",
+       "1e-306",
+       "1e-307",
+       "1e-308",
+       "1e-309",
+       "1e-310",
+       "1e-322",
+       // smallest denormal
+       "5e-324",
+       "4e-324",
+       "3e-324",
+       // too small
+       "2e-324",
+       // way too small
+       "1e-350",
+       "long:1e-400000",
+       // way too small, negative
+       "-1e-350",
+       "long:-1e-400000",
+
+       // try to overflow exponent
+       // [Disabled: too slow and memory-hungry with rationals.]
+       // "1e-4294967296",
+       // "1e+4294967296",
+       // "1e-18446744073709551616",
+       // "1e+18446744073709551616",
+
+       // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+       "2.2250738585072012e-308",
+       // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+       "2.2250738585072011e-308",
+
+       // A very large number (initially wrongly parsed by the fast algorithm).
+       "4.630813248087435e+307",
+
+       // A different kind of very large number.
+       "22.222222222222222",
+       "long:2." + strings.Repeat("2", 4000) + "e+1",
+
+       // Exactly halfway between 1 and math.Nextafter(1, 2).
+       // Round to even (down).
+       "1.00000000000000011102230246251565404236316680908203125",
+       // Slightly lower; still round down.
+       "1.00000000000000011102230246251565404236316680908203124",
+       // Slightly higher; round up.
+       "1.00000000000000011102230246251565404236316680908203126",
+       // Slightly higher, but you have to read all the way to the end.
+       "long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1",
+
+       // Smallest denormal, 2^(-1022-52)
+       "4.940656458412465441765687928682213723651e-324",
+       // Half of smallest denormal, 2^(-1022-53)
+       "2.470328229206232720882843964341106861825e-324",
+       // A little more than the exact half of smallest denormal
+       // 2^-1075 + 2^-1100.  (Rounds to 1p-1074.)
+       "2.470328302827751011111470718709768633275e-324",
+       // The exact halfway between smallest normal and largest denormal:
+       // 2^-1022 - 2^-1075.  (Rounds to 2^-1022.)
+       "2.225073858507201136057409796709131975935e-308",
+
+       "1152921504606846975",  //   1<<60 - 1
+       "-1152921504606846975", // -(1<<60 - 1)
+       "1152921504606846977",  //   1<<60 + 1
+       "-1152921504606846977", // -(1<<60 + 1)
+
+       "1/3",
+}
+
+// isFinite reports whether f represents a finite rational value.
+// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
+func isFinite(f float64) bool {
+       return math.Abs(f) <= math.MaxFloat64
+}
+
+func TestFloat32SpecialCases(t *testing.T) {
+       for _, input := range float64inputs {
+               if strings.HasPrefix(input, "long:") {
+                       if testing.Short() {
+                               continue
+                       }
+                       input = input[len("long:"):]
+               }
+
+               r, ok := new(Rat).SetString(input)
+               if !ok {
+                       t.Errorf("Rat.SetString(%q) failed", input)
+                       continue
+               }
+               f, exact := r.Float32()
+
+               // 1. Check string -> Rat -> float32 conversions are
+               // consistent with strconv.ParseFloat.
+               // Skip this check if the input uses "a/b" rational syntax.
+               if !strings.Contains(input, "/") {
+                       e64, _ := strconv.ParseFloat(input, 32)
+                       e := float32(e64)
+
+                       // Careful: negative Rats too small for
+                       // float64 become -0, but Rat obviously cannot
+                       // preserve the sign from SetString("-0").
+                       switch {
+                       case math.Float32bits(e) == math.Float32bits(f):
+                               // Ok: bitwise equal.
+                       case f == 0 && r.Num().BitLen() == 0:
+                               // Ok: Rat(0) is equivalent to both +/- float64(0).
+                       default:
+                               t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
+                       }
+               }
+
+               if !isFinite(float64(f)) {
+                       continue
+               }
+
+               // 2. Check f is best approximation to r.
+               if !checkIsBestApprox32(t, f, r) {
+                       // Append context information.
+                       t.Errorf("(input was %q)", input)
+               }
+
+               // 3. Check f->R->f roundtrip is non-lossy.
+               checkNonLossyRoundtrip32(t, f)
+
+               // 4. Check exactness using slow algorithm.
+               if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact {
+                       t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact)
+               }
+       }
+}
+
+func TestFloat64SpecialCases(t *testing.T) {
+       for _, input := range float64inputs {
+               if strings.HasPrefix(input, "long:") {
+                       if testing.Short() {
+                               continue
+                       }
+                       input = input[len("long:"):]
+               }
+
+               r, ok := new(Rat).SetString(input)
+               if !ok {
+                       t.Errorf("Rat.SetString(%q) failed", input)
+                       continue
+               }
+               f, exact := r.Float64()
+
+               // 1. Check string -> Rat -> float64 conversions are
+               // consistent with strconv.ParseFloat.
+               // Skip this check if the input uses "a/b" rational syntax.
+               if !strings.Contains(input, "/") {
+                       e, _ := strconv.ParseFloat(input, 64)
+
+                       // Careful: negative Rats too small for
+                       // float64 become -0, but Rat obviously cannot
+                       // preserve the sign from SetString("-0").
+                       switch {
+                       case math.Float64bits(e) == math.Float64bits(f):
+                               // Ok: bitwise equal.
+                       case f == 0 && r.Num().BitLen() == 0:
+                               // Ok: Rat(0) is equivalent to both +/- float64(0).
+                       default:
+                               t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
+                       }
+               }
+
+               if !isFinite(f) {
+                       continue
+               }
+
+               // 2. Check f is best approximation to r.
+               if !checkIsBestApprox64(t, f, r) {
+                       // Append context information.
+                       t.Errorf("(input was %q)", input)
+               }
+
+               // 3. Check f->R->f roundtrip is non-lossy.
+               checkNonLossyRoundtrip64(t, f)
+
+               // 4. Check exactness using slow algorithm.
+               if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
+                       t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
+               }
+       }
+}
index 3090d3019d336d3a8e5c7f90673af447984c06d3..388eab4fe1a0f7faec1dc6d9ffc017fa80a6c2bb 100644 (file)
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build !netgo
-// +build darwin dragonfly freebsd solaris
+// +build darwin dragonfly freebsd
 
 package net
 
index e8014e4ffc961685290004eadb3253f1866a4ab3..099ea45ebaf2c169cf074b656b9ae0251bf97791 100644 (file)
@@ -43,8 +43,8 @@ func reverseaddr(addr string) (arpa string, err error) {
                return "", &DNSError{Err: "unrecognized address", Name: addr}
        }
        if ip.To4() != nil {
-               return itoa(int(ip[15])) + "." + itoa(int(ip[14])) + "." + itoa(int(ip[13])) + "." +
-                       itoa(int(ip[12])) + ".in-addr.arpa.", nil
+               return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." +
+                       uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
        }
        // Must be IPv6
        buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
@@ -94,7 +94,7 @@ Cname:
                                continue
                        }
                        h := rr.Header()
-                       if h.Class == dnsClassINET && h.Name == name {
+                       if h.Class == dnsClassINET && equalASCIILabel(h.Name, name) {
                                switch h.Rrtype {
                                case qtype:
                                        addrs = append(addrs, rr)
@@ -114,6 +114,26 @@ Cname:
        return "", nil, &DNSError{Err: "too many redirects", Name: name, Server: server}
 }
 
+func equalASCIILabel(x, y string) bool {
+       if len(x) != len(y) {
+               return false
+       }
+       for i := 0; i < len(x); i++ {
+               a := x[i]
+               b := y[i]
+               if 'A' <= a && a <= 'Z' {
+                       a += 0x20
+               }
+               if 'A' <= b && b <= 'Z' {
+                       b += 0x20
+               }
+               if a != b {
+                       return false
+               }
+       }
+       return true
+}
+
 func isDomainName(s string) bool {
        // See RFC 1035, RFC 3696.
        if len(s) == 0 {
index c39dbdb049d63058f8e2df942de151a366304590..159a03e5252a6e301991148cafea7a4067ff35fc 100644 (file)
@@ -18,7 +18,7 @@ func TestDNSParseSRVReply(t *testing.T) {
        msg := new(dnsMsg)
        ok := msg.Unpack(data)
        if !ok {
-               t.Fatalf("unpacking packet failed")
+               t.Fatal("unpacking packet failed")
        }
        msg.String() // exercise this code path
        if g, e := len(msg.answer), 5; g != e {
@@ -32,13 +32,19 @@ func TestDNSParseSRVReply(t *testing.T) {
                        t.Errorf("answer[%d] = %T; want *dnsRR_SRV", idx, rr)
                }
        }
-       _, addrs, err := answer("_xmpp-server._tcp.google.com.", "foo:53", msg, uint16(dnsTypeSRV))
-       if err != nil {
-               t.Fatalf("answer: %v", err)
-       }
-       if g, e := len(addrs), 5; g != e {
-               t.Errorf("len(addrs) = %d; want %d", g, e)
-               t.Logf("addrs = %#v", addrs)
+       for _, name := range [...]string{
+               "_xmpp-server._tcp.google.com.",
+               "_XMPP-Server._TCP.Google.COM.",
+               "_XMPP-SERVER._TCP.GOOGLE.COM.",
+       } {
+               _, addrs, err := answer(name, "foo:53", msg, uint16(dnsTypeSRV))
+               if err != nil {
+                       t.Error(err)
+               }
+               if g, e := len(addrs), 5; g != e {
+                       t.Errorf("len(addrs) = %d; want %d", g, e)
+                       t.Logf("addrs = %#v", addrs)
+               }
        }
        // repack and unpack.
        data2, ok := msg.Pack()
@@ -46,9 +52,9 @@ func TestDNSParseSRVReply(t *testing.T) {
        msg2.Unpack(data2)
        switch {
        case !ok:
-               t.Errorf("failed to repack message")
+               t.Error("failed to repack message")
        case !reflect.DeepEqual(msg, msg2):
-               t.Errorf("repacked message differs from original")
+               t.Error("repacked message differs from original")
        }
 }
 
index 5fe8effc2954dc3ebd7ebe965dd253f36aaf9c85..ddadb6e5bc119a80781fe0874fa5f8a5f1459471 100644 (file)
@@ -226,7 +226,3 @@ func setReadBuffer(fd *netFD, bytes int) error {
 func setWriteBuffer(fd *netFD, bytes int) error {
        return syscall.EPLAN9
 }
-
-func skipRawSocketTests() (skip bool, skipmsg string, err error) {
-       return true, "skipping test on plan9", nil
-}
index a3701f8764833fcee124e49119ef13d8bdc14737..cdf14e32ce8010683acf8601253e5a845fc35c8a 100644 (file)
@@ -18,18 +18,11 @@ func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil }
 
 func (pd *pollDesc) Close() {}
 
-func (pd *pollDesc) Lock() {}
-
-func (pd *pollDesc) Unlock() {}
-
-func (pd *pollDesc) Wakeup() {}
-
-func (pd *pollDesc) Evict() bool {
+func (pd *pollDesc) Evict() {
        pd.closing = true
        if pd.fd != nil {
                syscall.StopIO(pd.fd.sysfd)
        }
-       return false
 }
 
 func (pd *pollDesc) Prepare(mode int) error {
index 2bddc836c75a7af4492cbb5a748c74fc6a3ad991..8522ccebfb364315c2d5f57213d67b1d697a0a5a 100644 (file)
@@ -48,23 +48,12 @@ func (pd *pollDesc) Close() {
        pd.runtimeCtx = 0
 }
 
-func (pd *pollDesc) Lock() {
-}
-
-func (pd *pollDesc) Unlock() {
-}
-
-func (pd *pollDesc) Wakeup() {
-}
-
 // Evict evicts fd from the pending list, unblocking any I/O running on fd.
-// Return value is whether the pollServer should be woken up.
-func (pd *pollDesc) Evict() bool {
+func (pd *pollDesc) Evict() {
        if pd.runtimeCtx == 0 {
-               return false
+               return
        }
        runtime_pollUnblock(pd.runtimeCtx)
-       return false
 }
 
 func (pd *pollDesc) Prepare(mode int) error {
index 4e3269b6bd0989939c592805bc6bf05ba7e755d8..24e6c59f370785d141c1be6a1b6529e826ad8c1c 100644 (file)
@@ -187,9 +187,7 @@ func (fd *netFD) writeUnlock() {
 }
 
 func (fd *netFD) Close() error {
-       fd.pd.Lock() // needed for both fd.incref(true) and pollDesc.Evict
        if !fd.fdmu.IncrefAndClose() {
-               fd.pd.Unlock()
                return errClosing
        }
        // Unblock any I/O.  Once it all unblocks and returns,
@@ -197,12 +195,8 @@ func (fd *netFD) Close() error {
        // the final decref will close fd.sysfd.  This should happen
        // fairly quickly, since all the I/O is non-blocking, and any
        // attempts to block in the pollDesc will return errClosing.
-       doWakeup := fd.pd.Evict()
-       fd.pd.Unlock()
+       fd.pd.Evict()
        fd.decref()
-       if doWakeup {
-               fd.pd.Wakeup()
-       }
        return nil
 }
 
@@ -502,10 +496,3 @@ func (fd *netFD) dup() (f *os.File, err error) {
 func closesocket(s int) error {
        return syscall.Close(s)
 }
-
-func skipRawSocketTests() (skip bool, skipmsg string, err error) {
-       if os.Getuid() != 0 {
-               return true, "skipping test; must be root", nil
-       }
-       return false, "", nil
-}
index a185975377219d82606d35bd8e819cf0d0eb1ddd..995bc4a7f50505fc26a24f9036691e4867c808f7 100644 (file)
@@ -617,25 +617,6 @@ func (fd *netFD) accept() (*netFD, error) {
        return netfd, nil
 }
 
-func skipRawSocketTests() (skip bool, skipmsg string, err error) {
-       // From http://msdn.microsoft.com/en-us/library/windows/desktop/ms740548.aspx:
-       // Note: To use a socket of type SOCK_RAW requires administrative privileges.
-       // Users running Winsock applications that use raw sockets must be a member of
-       // the Administrators group on the local computer, otherwise raw socket calls
-       // will fail with an error code of WSAEACCES. On Windows Vista and later, access
-       // for raw sockets is enforced at socket creation. In earlier versions of Windows,
-       // access for raw sockets is enforced during other socket operations.
-       s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, 0)
-       if err == syscall.WSAEACCES {
-               return true, "skipping test; no access to raw socket allowed", nil
-       }
-       if err != nil {
-               return true, "", err
-       }
-       defer syscall.Closesocket(s)
-       return false, "", nil
-}
-
 // Unimplemented functions.
 
 func (fd *netFD) dup() (*os.File, error) {
index b8c71fd19fd21285d4ebb3721f58f1062433834b..c7407df707cea6c7457ee1b9719f5b4030e04a65 100644 (file)
@@ -75,7 +75,7 @@ func goroutineLeaked() bool {
        return true
 }
 
-func afterTest(t *testing.T) {
+func afterTest(t testing.TB) {
        http.DefaultTransport.(*http.Transport).CloseIdleConnections()
        if testing.Short() {
                return
index a23f1bc4bc6026973a1faac1cd8bda9e82f70d5b..f5a352da41cf123ed9b29c5c82095fbf2c479a17 100644 (file)
 //
 //     go tool pprof http://localhost:6060/debug/pprof/block
 //
+// Or to collect a 5-second execution trace:
+//
+//     wget http://localhost:6060/debug/pprof/trace?seconds=5
+//
 // To view all available profiles, open http://localhost:6060/debug/pprof/
 // in your browser.
 //
@@ -64,6 +68,7 @@ func init() {
        http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
        http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
        http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
+       http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
 }
 
 // Cmdline responds with the running program's
@@ -98,6 +103,30 @@ func Profile(w http.ResponseWriter, r *http.Request) {
        pprof.StopCPUProfile()
 }
 
+// Trace responds with the execution trace in binary form.
+// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
+// The package initialization registers it as /debug/pprof/trace.
+func Trace(w http.ResponseWriter, r *http.Request) {
+       sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
+       if sec == 0 {
+               sec = 1
+       }
+
+       // Set Content Type assuming StartTrace will work,
+       // because if it does it starts writing.
+       w.Header().Set("Content-Type", "application/octet-stream")
+       if err := pprof.StartTrace(w); err != nil {
+               // StartTrace failed, so no writes yet.
+               // Can change header back to text content and send error code.
+               w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+               w.WriteHeader(http.StatusInternalServerError)
+               fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
+               return
+       }
+       time.Sleep(time.Duration(sec) * time.Second)
+       pprof.StopTrace()
+}
+
 // Symbol looks up the program counters listed in the request,
 // responding with a table mapping program counters to function names.
 // The package initialization registers it as /debug/pprof/symbol.
index 487eebcb841beff999f0998942f3ff7a13c4e9ad..63d7d44aa0fb803fce4932c15b312ad877a8b4d9 100644 (file)
@@ -536,10 +536,11 @@ func (r *Request) BasicAuth() (username, password string, ok bool) {
 // parseBasicAuth parses an HTTP Basic Authentication string.
 // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true).
 func parseBasicAuth(auth string) (username, password string, ok bool) {
-       if !strings.HasPrefix(auth, "Basic ") {
+       const prefix = "Basic "
+       if !strings.HasPrefix(auth, prefix) {
                return
        }
-       c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic "))
+       c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
        if err != nil {
                return
        }
index eb695e2549dd35f8b6c7fcb7d6de4171e5dc1c0e..85d5705137f0e29153d79a4848208d6091bde15e 100644 (file)
@@ -2891,7 +2891,7 @@ func BenchmarkServer(b *testing.B) {
        defer ts.Close()
        b.StartTimer()
 
-       cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer")
+       cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer$")
        cmd.Env = append([]string{
                fmt.Sprintf("TEST_BENCH_CLIENT_N=%d", b.N),
                fmt.Sprintf("TEST_BENCH_SERVER_URL=%s", ts.URL),
@@ -2902,6 +2902,95 @@ func BenchmarkServer(b *testing.B) {
        }
 }
 
+// getNoBody wraps Get but closes any Response.Body before returning the response.
+func getNoBody(urlStr string) (*Response, error) {
+       res, err := Get(urlStr)
+       if err != nil {
+               return nil, err
+       }
+       res.Body.Close()
+       return res, nil
+}
+
+// A benchmark for profiling the client without the HTTP server code.
+// The server code runs in a subprocess.
+func BenchmarkClient(b *testing.B) {
+       b.ReportAllocs()
+       b.StopTimer()
+       defer afterTest(b)
+
+       port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user
+       if port == "" {
+               port = "39207"
+       }
+       var data = []byte("Hello world.\n")
+       if server := os.Getenv("TEST_BENCH_SERVER"); server != "" {
+               // Server process mode.
+               HandleFunc("/", func(w ResponseWriter, r *Request) {
+                       r.ParseForm()
+                       if r.Form.Get("stop") != "" {
+                               os.Exit(0)
+                       }
+                       w.Header().Set("Content-Type", "text/html; charset=utf-8")
+                       w.Write(data)
+               })
+               log.Fatal(ListenAndServe("localhost:"+port, nil))
+       }
+
+       // Start server process.
+       cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkClient$")
+       cmd.Env = append(os.Environ(), "TEST_BENCH_SERVER=yes")
+       if err := cmd.Start(); err != nil {
+               b.Fatalf("subprocess failed to start: %v", err)
+       }
+       defer cmd.Process.Kill()
+       done := make(chan error)
+       go func() {
+               done <- cmd.Wait()
+       }()
+
+       // Wait for the server process to respond.
+       url := "http://localhost:" + port + "/"
+       for i := 0; i < 100; i++ {
+               time.Sleep(50 * time.Millisecond)
+               if _, err := getNoBody(url); err == nil {
+                       break
+               }
+               if i == 99 {
+                       b.Fatalf("subprocess does not respond")
+               }
+       }
+
+       // Do b.N requests to the server.
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               res, err := Get(url)
+               if err != nil {
+                       b.Fatalf("Get: %v", err)
+               }
+               body, err := ioutil.ReadAll(res.Body)
+               res.Body.Close()
+               if err != nil {
+                       b.Fatalf("ReadAll: %v", err)
+               }
+               if bytes.Compare(body, data) != 0 {
+                       b.Fatalf("Got body: %q", body)
+               }
+       }
+       b.StopTimer()
+
+       // Instruct server process to stop.
+       getNoBody(url + "?stop=yes")
+       select {
+       case err := <-done:
+               if err != nil {
+                       b.Fatalf("subprocess failed: %v", err)
+               }
+       case <-time.After(5 * time.Second):
+               b.Fatalf("subprocess did not stop")
+       }
+}
+
 func BenchmarkServerFakeConnNoKeepAlive(b *testing.B) {
        b.ReportAllocs()
        req := reqBytes(`GET / HTTP/1.0
index 8cdaf149899ec5cf1b1c756694f97a1af740df9e..c68aa2c9851771824600207664e7a997ab12229c 100644 (file)
@@ -191,20 +191,14 @@ func (c *conn) noteClientGone() {
        c.clientGone = true
 }
 
-// A switchReader can have its Reader changed at runtime.
-// It's not safe for concurrent Reads and switches.
-type switchReader struct {
-       io.Reader
-}
-
 // A switchWriter can have its Writer changed at runtime.
 // It's not safe for concurrent Writes and switches.
 type switchWriter struct {
        io.Writer
 }
 
-// A liveSwitchReader is a switchReader that's safe for concurrent
-// reads and switches, if its mutex is held.
+// A liveSwitchReader can have its Reader changed at runtime. It's
+// safe for concurrent reads and switches, if its mutex is held.
 type liveSwitchReader struct {
        sync.Mutex
        r io.Reader
index efabb5f3c25daafeed4082067bb83368cd181912..fbf15de4d37791f74541c8e0a7d100d71263b7d2 100644 (file)
@@ -6,6 +6,7 @@ package net
 
 import (
        "reflect"
+       "runtime"
        "testing"
 )
 
@@ -38,10 +39,6 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
        }
        for _, ifa := range ifat {
                switch ifa := ifa.(type) {
-               case *IPAddr:
-                       if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
-                               return ifa.IP.String()
-                       }
                case *IPNet:
                        if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
                                return ifa.IP.String()
@@ -52,104 +49,165 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
 }
 
 func TestInterfaces(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               t.Skip("temporarily disabled until golang.org/issue/5395 is fixed")
+       }
+
        ift, err := Interfaces()
        if err != nil {
-               t.Fatalf("Interfaces failed: %v", err)
+               t.Fatal(err)
        }
-       t.Logf("table: len/cap = %v/%v", len(ift), cap(ift))
-
+       var nifs, naf4, naf6, nmaf4, nmaf6 int
        for _, ifi := range ift {
                ifxi, err := InterfaceByIndex(ifi.Index)
                if err != nil {
-                       t.Fatalf("InterfaceByIndex(%v) failed: %v", ifi.Index, err)
+                       t.Fatal(err)
                }
                if !reflect.DeepEqual(ifxi, &ifi) {
-                       t.Fatalf("InterfaceByIndex(%v) = %v, want %v", ifi.Index, ifxi, ifi)
+                       t.Errorf("got %v; want %v", ifxi, ifi)
                }
                ifxn, err := InterfaceByName(ifi.Name)
                if err != nil {
-                       t.Fatalf("InterfaceByName(%q) failed: %v", ifi.Name, err)
+                       t.Fatal(err)
                }
                if !reflect.DeepEqual(ifxn, &ifi) {
-                       t.Fatalf("InterfaceByName(%q) = %v, want %v", ifi.Name, ifxn, ifi)
+                       t.Errorf("got %v; want %v", ifxn, ifi)
                }
                t.Logf("%q: flags %q, ifindex %v, mtu %v", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
-               t.Logf("\thardware address %q", ifi.HardwareAddr.String())
-               testInterfaceAddrs(t, &ifi)
-               testInterfaceMulticastAddrs(t, &ifi)
+               t.Logf("hardware address %q", ifi.HardwareAddr.String())
+               if ifi.Flags&FlagUp != 0 && ifi.Flags&FlagLoopback == 0 {
+                       nifs++ // active interfaces except loopback interfaces
+               }
+               n4, n6 := testInterfaceAddrs(t, &ifi)
+               naf4 += n4
+               naf6 += n6
+               n4, n6 = testInterfaceMulticastAddrs(t, &ifi)
+               nmaf4 += n4
+               nmaf6 += n6
+       }
+       switch runtime.GOOS {
+       case "nacl", "plan9", "solaris":
+       default:
+               if supportsIPv4 && nifs > 0 && naf4 == 0 {
+                       t.Errorf("got %v; want more than or equal to one", naf4)
+               }
+               if supportsIPv6 && nifs > 0 && naf6 == 0 {
+                       t.Errorf("got %v; want more than or equal to one", naf6)
+               }
+       }
+       switch runtime.GOOS {
+       case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris":
+       default:
+               // Unlike IPv6, IPv4 multicast capability is not a
+               // mandatory feature.
+               //if supportsIPv4 && nactvifs > 0 && nmaf4 == 0 {
+               //      t.Errorf("got %v; want more than or equal to one", nmaf4)
+               //}
+               if supportsIPv6 && nifs > 0 && nmaf6 == 0 {
+                       t.Errorf("got %v; want more than or equal to one", nmaf6)
+               }
        }
 }
 
 func TestInterfaceAddrs(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               t.Skip("temporarily disabled until golang.org/issue/5395 is fixed")
+       }
+
+       ift, err := Interfaces()
+       if err != nil {
+               t.Fatal(err)
+       }
+       var nifs int
+       for _, ifi := range ift {
+               if ifi.Flags&FlagUp != 0 && ifi.Flags&FlagLoopback == 0 {
+                       nifs++ // active interfaces except loopback interfaces
+               }
+       }
        ifat, err := InterfaceAddrs()
        if err != nil {
-               t.Fatalf("InterfaceAddrs failed: %v", err)
+               t.Fatal(err)
+       }
+       naf4, naf6 := testAddrs(t, ifat)
+       if supportsIPv4 && nifs > 0 && naf4 == 0 {
+               t.Errorf("got %v; want more than or equal to one", naf4)
+       }
+       if supportsIPv6 && nifs > 0 && naf6 == 0 {
+               t.Errorf("got %v; want more than or equal to one", naf6)
        }
-       t.Logf("table: len/cap = %v/%v", len(ifat), cap(ifat))
-       testAddrs(t, ifat)
 }
 
-func testInterfaceAddrs(t *testing.T, ifi *Interface) {
+func testInterfaceAddrs(t *testing.T, ifi *Interface) (naf4, naf6 int) {
        ifat, err := ifi.Addrs()
        if err != nil {
-               t.Fatalf("Interface.Addrs failed: %v", err)
+               t.Fatal(err)
        }
-       testAddrs(t, ifat)
+       return testAddrs(t, ifat)
 }
 
-func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) {
+func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) (nmaf4, nmaf6 int) {
        ifmat, err := ifi.MulticastAddrs()
        if err != nil {
-               t.Fatalf("Interface.MulticastAddrs failed: %v", err)
+               t.Fatal(err)
        }
-       testMulticastAddrs(t, ifmat)
+       return testMulticastAddrs(t, ifmat)
 }
 
-func testAddrs(t *testing.T, ifat []Addr) {
+func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) {
        for _, ifa := range ifat {
                switch ifa := ifa.(type) {
-               case *IPAddr:
-                       if ifa == nil || ifa.IP == nil {
-                               t.Errorf("\tunexpected value: %v, %v", ifa, ifa.IP)
-                       } else {
-                               t.Logf("\tinterface address %q", ifa.String())
-                       }
                case *IPNet:
-                       if ifa == nil || ifa.IP == nil || ifa.Mask == nil {
-                               t.Errorf("\tunexpected value: %v, %v, %v", ifa, ifa.IP, ifa.Mask)
-                       } else {
-                               _, prefixLen := ifa.Mask.Size()
-                               if ifa.IP.To4() != nil && prefixLen != 8*IPv4len || ifa.IP.To16() != nil && ifa.IP.To4() == nil && prefixLen != 8*IPv6len {
-                                       t.Errorf("\tunexpected value: %v, %v, %v, %v", ifa, ifa.IP, ifa.Mask, prefixLen)
-                               } else {
-                                       t.Logf("\tinterface address %q", ifa.String())
+                       if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || ifa.IP.IsMulticast() || ifa.Mask == nil {
+                               t.Errorf("unexpected value: %#v", ifa)
+                               continue
+                       }
+                       prefixLen, maxPrefixLen := ifa.Mask.Size()
+                       if ifa.IP.To4() != nil {
+                               if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len {
+                                       t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen)
+                                       continue
+                               }
+                               naf4++
+                       } else if ifa.IP.To16() != nil {
+                               if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len {
+                                       t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen)
+                                       continue
                                }
+                               naf6++
                        }
+                       t.Logf("interface address %q", ifa.String())
                default:
-                       t.Errorf("\tunexpected type: %T", ifa)
+                       t.Errorf("unexpected type: %T", ifa)
                }
        }
+       return
 }
 
-func testMulticastAddrs(t *testing.T, ifmat []Addr) {
+func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) {
        for _, ifma := range ifmat {
                switch ifma := ifma.(type) {
                case *IPAddr:
-                       if ifma == nil {
-                               t.Errorf("\tunexpected value: %v", ifma)
-                       } else {
-                               t.Logf("\tjoined group address %q", ifma.String())
+                       if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() {
+                               t.Errorf("unexpected value: %#v", ifma)
+                               continue
+                       }
+                       if ifma.IP.To4() != nil {
+                               nmaf4++
+                       } else if ifma.IP.To16() != nil {
+                               nmaf6++
                        }
+                       t.Logf("joined group address %q", ifma.String())
                default:
-                       t.Errorf("\tunexpected type: %T", ifma)
+                       t.Errorf("unexpected type: %T", ifma)
                }
        }
+       return
 }
 
 func BenchmarkInterfaces(b *testing.B) {
        for i := 0; i < b.N; i++ {
                if _, err := Interfaces(); err != nil {
-                       b.Fatalf("Interfaces failed: %v", err)
+                       b.Fatal(err)
                }
        }
 }
@@ -161,7 +219,7 @@ func BenchmarkInterfaceByIndex(b *testing.B) {
        }
        for i := 0; i < b.N; i++ {
                if _, err := InterfaceByIndex(ifi.Index); err != nil {
-                       b.Fatalf("InterfaceByIndex failed: %v", err)
+                       b.Fatal(err)
                }
        }
 }
@@ -173,7 +231,7 @@ func BenchmarkInterfaceByName(b *testing.B) {
        }
        for i := 0; i < b.N; i++ {
                if _, err := InterfaceByName(ifi.Name); err != nil {
-                       b.Fatalf("InterfaceByName failed: %v", err)
+                       b.Fatal(err)
                }
        }
 }
@@ -181,7 +239,7 @@ func BenchmarkInterfaceByName(b *testing.B) {
 func BenchmarkInterfaceAddrs(b *testing.B) {
        for i := 0; i < b.N; i++ {
                if _, err := InterfaceAddrs(); err != nil {
-                       b.Fatalf("InterfaceAddrs failed: %v", err)
+                       b.Fatal(err)
                }
        }
 }
@@ -193,7 +251,7 @@ func BenchmarkInterfacesAndAddrs(b *testing.B) {
        }
        for i := 0; i < b.N; i++ {
                if _, err := ifi.Addrs(); err != nil {
-                       b.Fatalf("Interface.Addrs failed: %v", err)
+                       b.Fatal(err)
                }
        }
 }
@@ -205,7 +263,7 @@ func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) {
        }
        for i := 0; i < b.N; i++ {
                if _, err := ifi.MulticastAddrs(); err != nil {
-                       b.Fatalf("Interface.MulticastAddrs failed: %v", err)
+                       b.Fatal(err)
                }
        }
 }
index 4a93e97b39d30217938d979d6506a651c3d09c4d..7bcc40e8f67f04363ae1de01f17db5e3ae4e0702 100644 (file)
@@ -267,10 +267,10 @@ func (ip IP) String() string {
 
        // If IPv4, use dotted notation.
        if p4 := p.To4(); len(p4) == IPv4len {
-               return itod(uint(p4[0])) + "." +
-                       itod(uint(p4[1])) + "." +
-                       itod(uint(p4[2])) + "." +
-                       itod(uint(p4[3]))
+               return uitoa(uint(p4[0])) + "." +
+                       uitoa(uint(p4[1])) + "." +
+                       uitoa(uint(p4[2])) + "." +
+                       uitoa(uint(p4[3]))
        }
        if len(p) != IPv6len {
                return "?"
@@ -491,7 +491,7 @@ func (n *IPNet) String() string {
        if l == -1 {
                return nn.String() + "/" + m.String()
        }
-       return nn.String() + "/" + itod(uint(l))
+       return nn.String() + "/" + uitoa(uint(l))
 }
 
 // Parse IPv4 address (d.d.d.d).
index 92dc8dc56942322c460833145ece5b2d7fa3a3c6..7bf95e12131f4d9aaadc0c0b5c3ffa690ff1488f 100644 (file)
@@ -5,15 +5,19 @@
 package net
 
 import (
-       "bytes"
        "fmt"
        "os"
        "reflect"
        "runtime"
        "testing"
-       "time"
 )
 
+// The full stack test cases for IPConn have been moved to the
+// following:
+//     golang.org/x/net/ipv4
+//     golang.org/x/net/ipv6
+//     golang.org/x/net/icmp
+
 type resolveIPAddrTest struct {
        net           string
        litAddrOrName string
@@ -59,14 +63,6 @@ func init() {
        }
 }
 
-func skipRawSocketTest(t *testing.T) (skip bool, skipmsg string) {
-       skip, skipmsg, err := skipRawSocketTests()
-       if err != nil {
-               t.Fatal(err)
-       }
-       return skip, skipmsg
-}
-
 func TestResolveIPAddr(t *testing.T) {
        switch runtime.GOOS {
        case "nacl":
@@ -83,164 +79,6 @@ func TestResolveIPAddr(t *testing.T) {
        }
 }
 
-var icmpEchoTests = []struct {
-       net   string
-       laddr string
-       raddr string
-}{
-       {"ip4:icmp", "0.0.0.0", "127.0.0.1"},
-       {"ip6:ipv6-icmp", "::", "::1"},
-}
-
-func TestConnICMPEcho(t *testing.T) {
-       if skip, skipmsg := skipRawSocketTest(t); skip {
-               t.Skip(skipmsg)
-       }
-
-       for i, tt := range icmpEchoTests {
-               net, _, err := parseNetwork(tt.net)
-               if err != nil {
-                       t.Fatalf("parseNetwork failed: %v", err)
-               }
-               if net == "ip6" && !supportsIPv6 {
-                       continue
-               }
-
-               c, err := Dial(tt.net, tt.raddr)
-               if err != nil {
-                       t.Fatalf("Dial failed: %v", err)
-               }
-               c.SetDeadline(time.Now().Add(100 * time.Millisecond))
-               defer c.Close()
-
-               typ := icmpv4EchoRequest
-               if net == "ip6" {
-                       typ = icmpv6EchoRequest
-               }
-               xid, xseq := os.Getpid()&0xffff, i+1
-               wb, err := (&icmpMessage{
-                       Type: typ, Code: 0,
-                       Body: &icmpEcho{
-                               ID: xid, Seq: xseq,
-                               Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3),
-                       },
-               }).Marshal()
-               if err != nil {
-                       t.Fatalf("icmpMessage.Marshal failed: %v", err)
-               }
-               if _, err := c.Write(wb); err != nil {
-                       t.Fatalf("Conn.Write failed: %v", err)
-               }
-               var m *icmpMessage
-               rb := make([]byte, 20+len(wb))
-               for {
-                       if _, err := c.Read(rb); err != nil {
-                               t.Fatalf("Conn.Read failed: %v", err)
-                       }
-                       if net == "ip4" {
-                               rb = ipv4Payload(rb)
-                       }
-                       if m, err = parseICMPMessage(rb); err != nil {
-                               t.Fatalf("parseICMPMessage failed: %v", err)
-                       }
-                       switch m.Type {
-                       case icmpv4EchoRequest, icmpv6EchoRequest:
-                               continue
-                       }
-                       break
-               }
-               switch p := m.Body.(type) {
-               case *icmpEcho:
-                       if p.ID != xid || p.Seq != xseq {
-                               t.Fatalf("got id=%v, seqnum=%v; expected id=%v, seqnum=%v", p.ID, p.Seq, xid, xseq)
-                       }
-               default:
-                       t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, typ, 0)
-               }
-       }
-}
-
-func TestPacketConnICMPEcho(t *testing.T) {
-       if skip, skipmsg := skipRawSocketTest(t); skip {
-               t.Skip(skipmsg)
-       }
-
-       for i, tt := range icmpEchoTests {
-               net, _, err := parseNetwork(tt.net)
-               if err != nil {
-                       t.Fatalf("parseNetwork failed: %v", err)
-               }
-               if net == "ip6" && !supportsIPv6 {
-                       continue
-               }
-
-               c, err := ListenPacket(tt.net, tt.laddr)
-               if err != nil {
-                       t.Fatalf("ListenPacket failed: %v", err)
-               }
-               c.SetDeadline(time.Now().Add(100 * time.Millisecond))
-               defer c.Close()
-
-               ra, err := ResolveIPAddr(tt.net, tt.raddr)
-               if err != nil {
-                       t.Fatalf("ResolveIPAddr failed: %v", err)
-               }
-               typ := icmpv4EchoRequest
-               if net == "ip6" {
-                       typ = icmpv6EchoRequest
-               }
-               xid, xseq := os.Getpid()&0xffff, i+1
-               wb, err := (&icmpMessage{
-                       Type: typ, Code: 0,
-                       Body: &icmpEcho{
-                               ID: xid, Seq: xseq,
-                               Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3),
-                       },
-               }).Marshal()
-               if err != nil {
-                       t.Fatalf("icmpMessage.Marshal failed: %v", err)
-               }
-               if _, err := c.WriteTo(wb, ra); err != nil {
-                       t.Fatalf("PacketConn.WriteTo failed: %v", err)
-               }
-               var m *icmpMessage
-               rb := make([]byte, 20+len(wb))
-               for {
-                       if _, _, err := c.ReadFrom(rb); err != nil {
-                               t.Fatalf("PacketConn.ReadFrom failed: %v", err)
-                       }
-                       // See BUG section.
-                       //if net == "ip4" {
-                       //      rb = ipv4Payload(rb)
-                       //}
-                       if m, err = parseICMPMessage(rb); err != nil {
-                               t.Fatalf("parseICMPMessage failed: %v", err)
-                       }
-                       switch m.Type {
-                       case icmpv4EchoRequest, icmpv6EchoRequest:
-                               continue
-                       }
-                       break
-               }
-               switch p := m.Body.(type) {
-               case *icmpEcho:
-                       if p.ID != xid || p.Seq != xseq {
-                               t.Fatalf("got id=%v, seqnum=%v; expected id=%v, seqnum=%v", p.ID, p.Seq, xid, xseq)
-                       }
-               default:
-                       t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, typ, 0)
-               }
-       }
-}
-
-func ipv4Payload(b []byte) []byte {
-       if len(b) < 20 {
-               return b
-       }
-       hdrlen := int(b[0]&0x0f) << 2
-       return b[hdrlen:]
-}
-
 var ipConnLocalNameTests = []struct {
        net   string
        laddr *IPAddr
index dda857803082fae372c1297f084f7849c2e7b0a9..858c6ef12c03b2733ceb39f38797485209c24853 100644 (file)
@@ -303,7 +303,7 @@ func zoneToString(zone int) string {
        if ifi, err := InterfaceByIndex(zone); err == nil {
                return ifi.Name
        }
-       return itod(uint(zone))
+       return uitoa(uint(zone))
 }
 
 func zoneToInt(zone string) int {
diff --git a/src/net/mockicmp_test.go b/src/net/mockicmp_test.go
deleted file mode 100644 (file)
index e742365..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-import "errors"
-
-const (
-       icmpv4EchoRequest = 8
-       icmpv4EchoReply   = 0
-       icmpv6EchoRequest = 128
-       icmpv6EchoReply   = 129
-)
-
-// icmpMessage represents an ICMP message.
-type icmpMessage struct {
-       Type     int             // type
-       Code     int             // code
-       Checksum int             // checksum
-       Body     icmpMessageBody // body
-}
-
-// icmpMessageBody represents an ICMP message body.
-type icmpMessageBody interface {
-       Len() int
-       Marshal() ([]byte, error)
-}
-
-// Marshal returns the binary enconding of the ICMP echo request or
-// reply message m.
-func (m *icmpMessage) Marshal() ([]byte, error) {
-       b := []byte{byte(m.Type), byte(m.Code), 0, 0}
-       if m.Body != nil && m.Body.Len() != 0 {
-               mb, err := m.Body.Marshal()
-               if err != nil {
-                       return nil, err
-               }
-               b = append(b, mb...)
-       }
-       switch m.Type {
-       case icmpv6EchoRequest, icmpv6EchoReply:
-               return b, nil
-       }
-       csumcv := len(b) - 1 // checksum coverage
-       s := uint32(0)
-       for i := 0; i < csumcv; i += 2 {
-               s += uint32(b[i+1])<<8 | uint32(b[i])
-       }
-       if csumcv&1 == 0 {
-               s += uint32(b[csumcv])
-       }
-       s = s>>16 + s&0xffff
-       s = s + s>>16
-       // Place checksum back in header; using ^= avoids the
-       // assumption the checksum bytes are zero.
-       b[2] ^= byte(^s)
-       b[3] ^= byte(^s >> 8)
-       return b, nil
-}
-
-// parseICMPMessage parses b as an ICMP message.
-func parseICMPMessage(b []byte) (*icmpMessage, error) {
-       msglen := len(b)
-       if msglen < 4 {
-               return nil, errors.New("message too short")
-       }
-       m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
-       if msglen > 4 {
-               var err error
-               switch m.Type {
-               case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply:
-                       m.Body, err = parseICMPEcho(b[4:])
-                       if err != nil {
-                               return nil, err
-                       }
-               }
-       }
-       return m, nil
-}
-
-// imcpEcho represenets an ICMP echo request or reply message body.
-type icmpEcho struct {
-       ID   int    // identifier
-       Seq  int    // sequence number
-       Data []byte // data
-}
-
-func (p *icmpEcho) Len() int {
-       if p == nil {
-               return 0
-       }
-       return 4 + len(p.Data)
-}
-
-// Marshal returns the binary enconding of the ICMP echo request or
-// reply message body p.
-func (p *icmpEcho) Marshal() ([]byte, error) {
-       b := make([]byte, 4+len(p.Data))
-       b[0], b[1] = byte(p.ID>>8), byte(p.ID)
-       b[2], b[3] = byte(p.Seq>>8), byte(p.Seq)
-       copy(b[4:], p.Data)
-       return b, nil
-}
-
-// parseICMPEcho parses b as an ICMP echo request or reply message
-// body.
-func parseICMPEcho(b []byte) (*icmpEcho, error) {
-       bodylen := len(b)
-       p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
-       if bodylen > 4 {
-               p.Data = make([]byte, bodylen-4)
-               copy(p.Data, b[4:])
-       }
-       return p, nil
-}
index cb31af5e347d109a5a065f053a45c4837a919c0f..c850d2b1fdb26159fe977536c79b9e7da1735933 100644 (file)
@@ -38,9 +38,6 @@ The Listen function creates servers:
 */
 package net
 
-// TODO(rsc):
-//     support for raw ethernet sockets
-
 import (
        "errors"
        "io"
index b6e4e76f93045a9d70847c1d551d53d89193491b..f00eacaf36a4c32b6b8fb0b7669ec0882e6a5075 100644 (file)
@@ -15,29 +15,16 @@ import (
        "time"
 )
 
+// The full stack test cases for IPConn have been moved to the
+// following:
+//     golang.org/x/net/ipv4
+//     golang.org/x/net/ipv6
+//     golang.org/x/net/icmp
+
 func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
        switch net {
        case "udp":
                return []byte("UDP PACKETCONN TEST"), nil
-       case "ip":
-               if skip, skipmsg := skipRawSocketTest(t); skip {
-                       return nil, func() {
-                               t.Logf(skipmsg)
-                       }
-               }
-               b, err := (&icmpMessage{
-                       Type: icmpv4EchoRequest, Code: 0,
-                       Body: &icmpEcho{
-                               ID: os.Getpid() & 0xffff, Seq: i + 1,
-                               Data: []byte("IP PACKETCONN TEST"),
-                       },
-               }).Marshal()
-               if err != nil {
-                       return nil, func() {
-                               t.Fatalf("icmpMessage.Marshal failed: %v", err)
-                       }
-               }
-               return b, nil
        case "unixgram":
                switch runtime.GOOS {
                case "nacl", "plan9", "windows":
@@ -60,7 +47,6 @@ var packetConnTests = []struct {
        addr2 string
 }{
        {"udp", "127.0.0.1:0", "127.0.0.1:0"},
-       {"ip:icmp", "127.0.0.1", "127.0.0.1"},
        {"unixgram", testUnixAddr(), testUnixAddr()},
 }
 
index e1d0130c9ac7ebb925a4c78d374da84edcb337c4..ad901fff27746056c3a8c7572c49abc6bae2f8ea 100644 (file)
@@ -171,43 +171,30 @@ func xtoi2(s string, e byte) (byte, bool) {
        return byte(n), ok && ei == 2
 }
 
-// Integer to decimal.
-func itoa(i int) string {
-       var buf [30]byte
-       n := len(buf)
-       neg := false
-       if i < 0 {
-               i = -i
-               neg = true
-       }
-       ui := uint(i)
-       for ui > 0 || n == len(buf) {
-               n--
-               buf[n] = byte('0' + ui%10)
-               ui /= 10
-       }
-       if neg {
-               n--
-               buf[n] = '-'
-       }
-       return string(buf[n:])
+// Convert integer to decimal string.
+func itoa(val int) string {
+       if val < 0 {
+               return "-" + uitoa(uint(-val))
+       }
+       return uitoa(uint(val))
 }
 
-// Convert i to decimal string.
-func itod(i uint) string {
-       if i == 0 {
+// Convert unsigned integer to decimal string.
+func uitoa(val uint) string {
+       if val == 0 { // avoid string allocation
                return "0"
        }
-
-       // Assemble decimal in reverse order.
-       var b [32]byte
-       bp := len(b)
-       for ; i > 0; i /= 10 {
-               bp--
-               b[bp] = byte(i%10) + '0'
-       }
-
-       return string(b[bp:])
+       var buf [20]byte // big enough for 64bit value base 10
+       i := len(buf) - 1
+       for val >= 10 {
+               q := val / 10
+               buf[i] = byte('0' + val - q*10)
+               i--
+               val = q
+       }
+       // val < 10
+       buf[i] = byte('0' + val)
+       return string(buf[i:])
 }
 
 // Convert i to a hexadecimal string. Leading zeros are not printed.
index 12856b6c311cf038a6988be5c5e8ea38787efd96..61c35dfc703b44c4eaf379065476d868ccd690dc 100644 (file)
@@ -15,6 +15,12 @@ import (
        "time"
 )
 
+// The full stack test cases for IPConn have been moved to the
+// following:
+//     golang.org/x/net/ipv4
+//     golang.org/x/net/ipv6
+//     golang.org/x/net/icmp
+
 // testUnixAddr uses ioutil.TempFile to get a name that is unique. It
 // also uses /tmp directory in case it is prohibited to create UNIX
 // sockets in TMPDIR.
@@ -173,8 +179,8 @@ func TestUDPConnSpecificMethods(t *testing.T) {
 }
 
 func TestIPConnSpecificMethods(t *testing.T) {
-       if skip, skipmsg := skipRawSocketTest(t); skip {
-               t.Skip(skipmsg)
+       if os.Getuid() != 0 {
+               t.Skip("must be root")
        }
 
        la, err := ResolveIPAddr("ip4", "127.0.0.1")
@@ -194,30 +200,6 @@ func TestIPConnSpecificMethods(t *testing.T) {
        c.SetReadBuffer(2048)
        c.SetWriteBuffer(2048)
 
-       wb, err := (&icmpMessage{
-               Type: icmpv4EchoRequest, Code: 0,
-               Body: &icmpEcho{
-                       ID: os.Getpid() & 0xffff, Seq: 1,
-                       Data: []byte("IPCONN TEST "),
-               },
-       }).Marshal()
-       if err != nil {
-               t.Fatalf("icmpMessage.Marshal failed: %v", err)
-       }
-       rb := make([]byte, 20+len(wb))
-       if _, err := c.WriteToIP(wb, c.LocalAddr().(*IPAddr)); err != nil {
-               t.Fatalf("IPConn.WriteToIP failed: %v", err)
-       }
-       if _, _, err := c.ReadFromIP(rb); err != nil {
-               t.Fatalf("IPConn.ReadFromIP failed: %v", err)
-       }
-       if _, _, err := c.WriteMsgIP(wb, nil, c.LocalAddr().(*IPAddr)); err != nil {
-               condFatalf(t, "IPConn.WriteMsgIP failed: %v", err)
-       }
-       if _, _, _, _, err := c.ReadMsgIP(rb, nil); err != nil {
-               condFatalf(t, "IPConn.ReadMsgIP failed: %v", err)
-       }
-
        if f, err := c.File(); err != nil {
                condFatalf(t, "IPConn.File failed: %v", err)
        } else {
@@ -230,6 +212,7 @@ func TestIPConnSpecificMethods(t *testing.T) {
                }
        }()
 
+       wb := []byte("IPCONN TEST")
        c.WriteToIP(wb, nil)
        c.WriteMsgIP(wb, nil, nil)
 }
index 6a2bb924329d37fd65653cb01bd7b9ef917e0502..bf7feab8f515aaab336267d6de31efcc23974b8a 100644 (file)
@@ -441,7 +441,7 @@ func runDatagramPacketConnClient(t *testing.T, net, laddr, taddr string, isEmpty
        }
        c, err := ListenPacket(net, laddr)
        if err != nil {
-               t.Fatalf("ListenPacket(%q, %q) faild: %v", net, laddr, err)
+               t.Fatalf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
        }
        defer c.Close()
        c.SetReadDeadline(time.Now().Add(1 * time.Second))
index 21d40ccaf848c9b8cfe50a61008a3b0c88afe910..afee189650c0cc3afb7532cecdf90179b9b43b48 100644 (file)
@@ -13,6 +13,10 @@ import (
        "testing"
 )
 
+func init() {
+       isReadonlyError = func(err error) bool { return err == syscall.EROFS }
+}
+
 func checkUidGid(t *testing.T, path string, uid, gid int) {
        dir, err := Stat(path)
        if err != nil {
index 6f24a43132a883e747e9119b300d41e0353bdfdb..66ed49b6fd33ac10425cf1a8074fe604d81af98e 100644 (file)
@@ -13,6 +13,8 @@ import (
        "testing"
 )
 
+var isReadonlyError = func(error) bool { return false }
+
 func TestMkdirAll(t *testing.T) {
        tmpDir := TempDir()
        path := tmpDir + "/_TestMkdirAll_/dir/./dir2"
@@ -207,12 +209,13 @@ func TestMkdirAllAtSlash(t *testing.T) {
                t.Skipf("skipping on %s", runtime.GOOS)
        }
        RemoveAll("/_go_os_test")
-       err := MkdirAll("/_go_os_test/dir", 0777)
+       const dir = "/go_os_test/dir"
+       err := MkdirAll(dir, 0777)
        if err != nil {
                pathErr, ok := err.(*PathError)
                // common for users not to be able to write to /
-               if ok && pathErr.Err == syscall.EACCES {
-                       return
+               if ok && (pathErr.Err == syscall.EACCES || isReadonlyError(pathErr.Err)) {
+                       t.Skipf("could not create %v: %v", dir, err)
                }
                t.Fatalf(`MkdirAll "/_go_os_test/dir": %v`, err)
        }
index 25c9a8c14b3ddc61352f18c28fe9afce6557bd20..57227876f1c6fe7777e81f73c7ac120d1421d12e 100644 (file)
@@ -9,6 +9,8 @@ import (
        "time"
 )
 
+const _BIT16SZ = 2
+
 func sameFile(fs1, fs2 *fileStat) bool {
        a := fs1.sys.(*syscall.Dir)
        b := fs2.sys.(*syscall.Dir)
@@ -41,16 +43,14 @@ func fileInfoFromStat(d *syscall.Dir) FileInfo {
 // arg is an open *File or a path string.
 func dirstat(arg interface{}) (*syscall.Dir, error) {
        var name string
+       var err error
 
-       // This is big enough for most stat messages
-       // and rounded to a multiple of 128 bytes.
-       size := (syscall.STATFIXLEN + 16*4 + 128) &^ 128
+       size := syscall.STATFIXLEN + 16*4
 
        for i := 0; i < 2; i++ {
-               buf := make([]byte, size)
+               buf := make([]byte, _BIT16SZ+size)
 
                var n int
-               var err error
                switch a := arg.(type) {
                case *File:
                        name = a.name
@@ -61,10 +61,8 @@ func dirstat(arg interface{}) (*syscall.Dir, error) {
                default:
                        panic("phase error in dirstat")
                }
-               if err != nil {
-                       return nil, &PathError{"stat", name, err}
-               }
-               if n < syscall.STATFIXLEN {
+
+               if n < _BIT16SZ {
                        return nil, &PathError{"stat", name, syscall.ErrShortStat}
                }
 
@@ -73,17 +71,21 @@ func dirstat(arg interface{}) (*syscall.Dir, error) {
 
                // If the stat message is larger than our buffer we will
                // go around the loop and allocate one that is big enough.
-               if size > n {
-                       continue
+               if size <= n {
+                       d, err := syscall.UnmarshalDir(buf[:n])
+                       if err != nil {
+                               return nil, &PathError{"stat", name, err}
+                       }
+                       return d, nil
                }
 
-               d, err := syscall.UnmarshalDir(buf[:n])
-               if err != nil {
-                       return nil, &PathError{"stat", name, err}
-               }
-               return d, nil
        }
-       return nil, &PathError{"stat", name, syscall.ErrBadStat}
+
+       if err == nil {
+               err = syscall.ErrBadStat
+       }
+
+       return nil, &PathError{"stat", name, err}
 }
 
 // Stat returns a FileInfo describing the named file.
index 3bde14b91e881b153d3495f8b574147937ba000e..ebdd9f596884c41a18ace70ca85675f53bee3d1d 100644 (file)
@@ -196,13 +196,10 @@ func Split(path string) (dir, file string) {
 // Join joins any number of path elements into a single path, adding
 // a Separator if necessary. The result is Cleaned, in particular
 // all empty strings are ignored.
+// On Windows, the result is a UNC path if and only if the first path
+// element is a UNC path.
 func Join(elem ...string) string {
-       for i, e := range elem {
-               if e != "" {
-                       return Clean(strings.Join(elem[i:], string(Separator)))
-               }
-       }
-       return ""
+       return join(elem)
 }
 
 // Ext returns the file name extension used by path.
index ee8912d58e1dbbcf9d19ccf278092d988ae2a1f0..da5f5fdac71d22f24c701752921cb83c50fbb3f9 100644 (file)
@@ -32,3 +32,13 @@ func splitList(path string) []string {
 func abs(path string) (string, error) {
        return unixAbs(path)
 }
+
+func join(elem []string) string {
+       // If there's a bug here, fix the logic in ./path_unix.go too.
+       for i, e := range elem {
+               if e != "" {
+                       return Clean(strings.Join(elem[i:], string(Separator)))
+               }
+       }
+       return ""
+}
index 399284b97da310e70247bc35e478d468b1b02d50..c4f74b97ffc2ab6fc7270060a57fb7c1a6ac5bef 100644 (file)
@@ -242,6 +242,7 @@ var jointests = []JoinTest{
 
        // one parameter
        {[]string{""}, ""},
+       {[]string{"/"}, "/"},
        {[]string{"a"}, "a"},
 
        // two parameters
@@ -249,10 +250,16 @@ var jointests = []JoinTest{
        {[]string{"a", ""}, "a"},
        {[]string{"", "b"}, "b"},
        {[]string{"/", "a"}, "/a"},
+       {[]string{"/", "a/b"}, "/a/b"},
        {[]string{"/", ""}, "/"},
+       {[]string{"//", "a"}, "/a"},
+       {[]string{"/a", "b"}, "/a/b"},
        {[]string{"a/", "b"}, "a/b"},
        {[]string{"a/", ""}, "a"},
        {[]string{"", ""}, ""},
+
+       // three parameters
+       {[]string{"/", "a", "b"}, "/a/b"},
 }
 
 var winjointests = []JoinTest{
@@ -262,13 +269,17 @@ var winjointests = []JoinTest{
        {[]string{`C:\`, `Windows`}, `C:\Windows`},
        {[]string{`C:`, `Windows`}, `C:\Windows`},
        {[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
+       {[]string{`\\host\share\foo`}, `\\host\share\foo`},
        {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
-}
-
-// join takes a []string and passes it to Join.
-func join(elem []string, args ...string) string {
-       args = elem
-       return filepath.Join(args...)
+       {[]string{`\`}, `\`},
+       {[]string{`\`, ``}, `\`},
+       {[]string{`\`, `a`}, `\a`},
+       {[]string{`\\`, `a`}, `\a`},
+       {[]string{`\`, `a`, `b`}, `\a\b`},
+       {[]string{`\\`, `a`, `b`}, `\a\b`},
+       {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`},
+       {[]string{`\\a`, `b`, `c`}, `\a\b\c`},
+       {[]string{`\\a\`, `b`, `c`}, `\a\b\c`},
 }
 
 func TestJoin(t *testing.T) {
@@ -276,8 +287,9 @@ func TestJoin(t *testing.T) {
                jointests = append(jointests, winjointests...)
        }
        for _, test := range jointests {
-               if p := join(test.elem); p != filepath.FromSlash(test.path) {
-                       t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
+               expected := filepath.FromSlash(test.path)
+               if p := filepath.Join(test.elem...); p != expected {
+                       t.Errorf("join(%q) = %q, want %q", test.elem, p, expected)
                }
        }
 }
index 4e7d0d1b42258e57f6125efc9219b89a1e63f6fc..008b76e19e245c5d5769800c6c025fb0a3bdb188 100644 (file)
@@ -34,3 +34,13 @@ func splitList(path string) []string {
 func abs(path string) (string, error) {
        return unixAbs(path)
 }
+
+func join(elem []string) string {
+       // If there's a bug here, fix the logic in ./path_plan9.go too.
+       for i, e := range elem {
+               if e != "" {
+                       return Clean(strings.Join(elem[i:], string(Separator)))
+               }
+       }
+       return ""
+}
index ec50f6b264f3b304f4edf281caca0a37b55fdb74..d6ed3d142da6e506d67ab29d04f22aeca3912814 100644 (file)
@@ -108,3 +108,40 @@ func splitList(path string) []string {
 func abs(path string) (string, error) {
        return syscall.FullPath(path)
 }
+
+func join(elem []string) string {
+       for i, e := range elem {
+               if e != "" {
+                       return joinNonEmpty(elem[i:])
+               }
+       }
+       return ""
+}
+
+// joinNonEmpty is like join, but it assumes that the first element is non-empty.
+func joinNonEmpty(elem []string) string {
+       // The following logic prevents Join from inadvertently creating a
+       // UNC path on Windows. Unless the first element is a UNC path, Join
+       // shouldn't create a UNC path. See golang.org/issue/9167.
+       p := Clean(strings.Join(elem, string(Separator)))
+       if !isUNC(p) {
+               return p
+       }
+       // p == UNC only allowed when the first element is a UNC path.
+       head := Clean(elem[0])
+       if isUNC(head) {
+               return p
+       }
+       // head + tail == UNC, but joining two non-UNC paths should not result
+       // in a UNC path. Undo creation of UNC path.
+       tail := Clean(strings.Join(elem[1:], string(Separator)))
+       if head[len(head)-1] == Separator {
+               return head + tail
+       }
+       return head + string(Separator) + tail
+}
+
+// isUNC returns true if path is a UNC path.
+func isUNC(path string) bool {
+       return volumeNameLen(path) > 2
+}
index 278848bc007811dcbdbdf90daca4228230691acb..7d40f9a8b67f668f990820ad743b40c2ed03acc2 100644 (file)
@@ -1506,6 +1506,17 @@ func TestCallWithStruct(t *testing.T) {
        }
 }
 
+func BenchmarkCall(b *testing.B) {
+       fv := ValueOf(func(a, b string) {})
+       b.ReportAllocs()
+       b.RunParallel(func(pb *testing.PB) {
+               args := []Value{ValueOf("a"), ValueOf("b")}
+               for pb.Next() {
+                       fv.Call(args)
+               }
+       })
+}
+
 func TestMakeFunc(t *testing.T) {
        f := dummy
        fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
index 82a8a10930a816363603252500c7312ffa826656..9f06324bf86e6f2cc6230d1a41d6e6c73844e907 100644 (file)
@@ -26,9 +26,9 @@ func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr,
        var ft *rtype
        var s *bitVector
        if rcvr != nil {
-               ft, argSize, retOffset, s = funcLayout(t.(*rtype), rcvr.(*rtype))
+               ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), rcvr.(*rtype))
        } else {
-               ft, argSize, retOffset, s = funcLayout(t.(*rtype), nil)
+               ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), nil)
        }
        frametype = ft
        for i := uint32(0); i < s.n; i += 2 {
index d89f7f6811daecb2b07ca9221e1fcc9b0a204d4a..447180524815a18cf0bb8de5e1bbdd39f163cf04 100644 (file)
@@ -56,7 +56,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
        code := **(**uintptr)(unsafe.Pointer(&dummy))
 
        // makeFuncImpl contains a stack map for use by the runtime
-       _, _, _, stack := funcLayout(t, nil)
+       _, _, _, stack, _ := funcLayout(t, nil)
 
        impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn}
 
@@ -104,7 +104,7 @@ func makeMethodValue(op string, v Value) Value {
        code := **(**uintptr)(unsafe.Pointer(&dummy))
 
        // methodValue contains a stack map for use by the runtime
-       _, _, _, stack := funcLayout(funcType, nil)
+       _, _, _, stack, _ := funcLayout(funcType, nil)
 
        fv := &methodValue{
                fn:     code,
index a71d8374c6319e7c6d507196b3c525e53e1681b0..ae7d165a68d2b2655b788b779261e130c7f14e14 100644 (file)
@@ -1469,9 +1469,8 @@ func MapOf(key, elem Type) Type {
 
        // Make a map type.
        var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
-       prototype := *(**mapType)(unsafe.Pointer(&imap))
        mt := new(mapType)
-       *mt = *prototype
+       *mt = **(**mapType)(unsafe.Pointer(&imap))
        mt.string = &s
        mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
        mt.key = ktyp
@@ -1575,7 +1574,7 @@ func (gc *gcProg) appendProg(t *rtype) {
                for i := 0; i < c; i++ {
                        gc.appendProg(t.Field(i).Type.common())
                }
-               if gc.size > oldsize + t.size {
+               if gc.size > oldsize+t.size {
                        panic("reflect: struct components are larger than the struct itself")
                }
                gc.size = oldsize + t.size
@@ -1650,6 +1649,12 @@ const (
 )
 
 func bucketOf(ktyp, etyp *rtype) *rtype {
+       // See comment on hmap.overflow in ../runtime/hashmap.go.
+       var kind uint8
+       if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 {
+               kind = kindNoPointers
+       }
+
        if ktyp.size > maxKeySize {
                ktyp = PtrTo(ktyp).(*rtype)
        }
@@ -1679,6 +1684,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
 
        b := new(rtype)
        b.size = gc.size
+       b.kind = kind
        b.gc[0], _ = gc.finalize()
        s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
        b.string = &s
@@ -1803,6 +1809,7 @@ type layoutType struct {
        argSize   uintptr // size of arguments
        retOffset uintptr // offset of return values.
        stack     *bitVector
+       framePool *sync.Pool
 }
 
 var layoutCache struct {
@@ -1816,7 +1823,7 @@ var layoutCache struct {
 // The returned type exists only for GC, so we only fill out GC relevant info.
 // Currently, that's just size and the GC program.  We also fill in
 // the name for possible debugging use.
-func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stack *bitVector) {
+func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stack *bitVector, framePool *sync.Pool) {
        if t.Kind() != Func {
                panic("reflect: funcLayout of non-func type")
        }
@@ -1827,13 +1834,13 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
        layoutCache.RLock()
        if x := layoutCache.m[k]; x.t != nil {
                layoutCache.RUnlock()
-               return x.t, x.argSize, x.retOffset, x.stack
+               return x.t, x.argSize, x.retOffset, x.stack, x.framePool
        }
        layoutCache.RUnlock()
        layoutCache.Lock()
        if x := layoutCache.m[k]; x.t != nil {
                layoutCache.Unlock()
-               return x.t, x.argSize, x.retOffset, x.stack
+               return x.t, x.argSize, x.retOffset, x.stack, x.framePool
        }
 
        tt := (*funcType)(unsafe.Pointer(t))
@@ -1897,14 +1904,18 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
        if layoutCache.m == nil {
                layoutCache.m = make(map[layoutKey]layoutType)
        }
+       framePool = &sync.Pool{New: func() interface{} {
+               return unsafe_New(x)
+       }}
        layoutCache.m[k] = layoutType{
                t:         x,
                argSize:   argSize,
                retOffset: retOffset,
                stack:     stack,
+               framePool: framePool,
        }
        layoutCache.Unlock()
-       return x, argSize, retOffset, stack
+       return x, argSize, retOffset, stack, framePool
 }
 
 // ifaceIndir reports whether t is stored indirectly in an interface value.
index 3255a697d5971ec663e64e92a6baf219afa45d11..4060206eacb21cc220c775210c38250cd74977bf 100644 (file)
@@ -393,9 +393,18 @@ func (v Value) call(op string, in []Value) []Value {
        }
        nout := t.NumOut()
 
-       // Compute frame type, allocate a chunk of memory for frame
-       frametype, _, retOffset, _ := funcLayout(t, rcvrtype)
-       args := unsafe_New(frametype)
+       // Compute frame type.
+       frametype, _, retOffset, _, framePool := funcLayout(t, rcvrtype)
+
+       // Allocate a chunk of memory for frame.
+       var args unsafe.Pointer
+       if nout == 0 {
+               args = framePool.Get().(unsafe.Pointer)
+       } else {
+               // Can't use pool if the function has return values.
+               // We will leak pointer to args in ret, so its lifetime is not scoped.
+               args = unsafe_New(frametype)
+       }
        off := uintptr(0)
 
        // Copy inputs into args.
@@ -427,16 +436,26 @@ func (v Value) call(op string, in []Value) []Value {
                runtime.GC()
        }
 
-       // Copy return values out of args.
-       ret := make([]Value, nout)
-       off = retOffset
-       for i := 0; i < nout; i++ {
-               tv := t.Out(i)
-               a := uintptr(tv.Align())
-               off = (off + a - 1) &^ (a - 1)
-               fl := flagIndir | flag(tv.Kind())
-               ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), fl}
-               off += tv.Size()
+       var ret []Value
+       if nout == 0 {
+               memclr(args, frametype.size)
+               framePool.Put(args)
+       } else {
+               // Zero the now unused input area of args,
+               // because the Values returned by this function contain pointers to the args object,
+               // and will thus keep the args object alive indefinitely.
+               memclr(args, retOffset)
+               // Copy return values out of args.
+               ret = make([]Value, nout)
+               off = retOffset
+               for i := 0; i < nout; i++ {
+                       tv := t.Out(i)
+                       a := uintptr(tv.Align())
+                       off = (off + a - 1) &^ (a - 1)
+                       fl := flagIndir | flag(tv.Kind())
+                       ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), fl}
+                       off += tv.Size()
+               }
        }
 
        return ret
@@ -596,10 +615,10 @@ func align(x, n uintptr) uintptr {
 func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
        rcvr := ctxt.rcvr
        rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method)
-       frametype, argSize, retOffset, _ := funcLayout(t, rcvrtype)
+       frametype, argSize, retOffset, _, framePool := funcLayout(t, rcvrtype)
 
        // Make a new frame that is one word bigger so we can store the receiver.
-       args := unsafe_New(frametype)
+       args := framePool.Get().(unsafe.Pointer)
 
        // Copy in receiver and rest of args.
        storeRcvr(rcvr, args)
@@ -622,6 +641,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
                unsafe.Pointer(uintptr(args)+retOffset),
                retOffset,
                frametype.size-retOffset)
+
+       memclr(args, frametype.size)
+       framePool.Put(args)
 }
 
 // funcName returns the name of f, for use in error messages.
@@ -2448,6 +2470,9 @@ func typedmemmovepartial(t *rtype, dst, src unsafe.Pointer, off, size uintptr)
 //go:noescape
 func typedslicecopy(elemType *rtype, dst, src sliceHeader) int
 
+//go:noescape
+func memclr(ptr unsafe.Pointer, n uintptr)
+
 // Dummy annotation marking that the value x escapes,
 // for use in cases where the reflect code is so clever that
 // the compiler cannot follow.
index 70d069c06110855e79eddfddb47df328373e60af..b1bf4053f5c1869f8e9c79c50ceea8d598a9a09a 100644 (file)
@@ -326,7 +326,7 @@ func same(x, y []int) bool {
 
 // TestFowler runs this package's regexp API against the
 // POSIX regular expression tests collected by Glenn Fowler
-// at http://www2.research.att.com/~gsf/testregex/.
+// at http://www2.research.att.com/~astopen/testregex/testregex.html.
 func TestFowler(t *testing.T) {
        files, err := filepath.Glob("testdata/*.dat")
        if err != nil {
@@ -361,7 +361,7 @@ Reading:
                        break Reading
                }
 
-               // http://www2.research.att.com/~gsf/man/man1/testregex.html
+               // http://www2.research.att.com/~astopen/man/man1/testregex.html
                //
                // INPUT FORMAT
                //   Input lines may be blank, a comment beginning with #, or a test
index 794b7f65c4899c0b716e91d110aee7bae140db41..199686db6f512a833391e706dc76cb41dbb7830a 100644 (file)
@@ -8,7 +8,7 @@ const (
        thechar           = '6'
        _BigEndian        = 0
        _CacheLineSize    = 64
-       _RuntimeGogoBytes = 64 + (goos_plan9|goos_solaris|goos_windows)*16
+       _RuntimeGogoBytes = 80 + (goos_solaris)*16
        _PhysPageSize     = 4096
        _PCQuantum        = 1
        _Int64Align       = 8
index 0a58faf19b23fe405c5661fb9e0f05c070849f74..49bba32ebe7ccede3a25af969113885f91f33393 100644 (file)
@@ -555,6 +555,9 @@ TEXT runtime·atomicstore(SB), NOSPLIT, $0-8
 // uint64 atomicload64(uint64 volatile* addr);
 TEXT runtime·atomicload64(SB), NOSPLIT, $0-12
        MOVL    ptr+0(FP), AX
+       TESTL   $7, AX
+       JZ      2(PC)
+       MOVL    0, AX // crash with nil ptr deref
        LEAL    ret_lo+4(FP), BX
        // MOVQ (%EAX), %MM0
        BYTE $0x0f; BYTE $0x6f; BYTE $0x00
@@ -567,6 +570,9 @@ TEXT runtime·atomicload64(SB), NOSPLIT, $0-12
 // void runtime·atomicstore64(uint64 volatile* addr, uint64 v);
 TEXT runtime·atomicstore64(SB), NOSPLIT, $0-12
        MOVL    ptr+0(FP), AX
+       TESTL   $7, AX
+       JZ      2(PC)
+       MOVL    0, AX // crash with nil ptr deref
        // MOVQ and EMMS were introduced on the Pentium MMX.
        // MOVQ 0x8(%ESP), %MM0
        BYTE $0x0f; BYTE $0x6f; BYTE $0x44; BYTE $0x24; BYTE $0x08
index 8547228ee37804e50ce02bf079661d5b2bce1e83..f09e5ae250e16d4843310385da3b6b3b59b5a1ab 100644 (file)
@@ -96,8 +96,8 @@ ok:
        CALL    runtime·schedinit(SB)
 
        // create a new goroutine to start program
-       MOVQ    $runtime·main·f(SB), BP               // entry
-       PUSHQ   BP
+       MOVQ    $runtime·main·f(SB), AX               // entry
+       PUSHQ   AX
        PUSHQ   $0                      // arg size
        CALL    runtime·newproc(SB)
        POPQ    AX
@@ -134,6 +134,7 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-8
        MOVQ    BX, gobuf_pc(AX)
        MOVQ    $0, gobuf_ret(AX)
        MOVQ    $0, gobuf_ctxt(AX)
+       MOVQ    BP, gobuf_bp(AX)
        get_tls(CX)
        MOVQ    g(CX), BX
        MOVQ    BX, gobuf_g(AX)
@@ -150,9 +151,11 @@ TEXT runtime·gogo(SB), NOSPLIT, $0-8
        MOVQ    gobuf_sp(BX), SP        // restore SP
        MOVQ    gobuf_ret(BX), AX
        MOVQ    gobuf_ctxt(BX), DX
+       MOVQ    gobuf_bp(BX), BP
        MOVQ    $0, gobuf_sp(BX)        // clear to help garbage collector
        MOVQ    $0, gobuf_ret(BX)
        MOVQ    $0, gobuf_ctxt(BX)
+       MOVQ    $0, gobuf_bp(BX)
        MOVQ    gobuf_pc(BX), BX
        JMP     BX
 
@@ -170,6 +173,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8
        LEAQ    fn+0(FP), BX    // caller's SP
        MOVQ    BX, (g_sched+gobuf_sp)(AX)
        MOVQ    AX, (g_sched+gobuf_g)(AX)
+       MOVQ    BP, (g_sched+gobuf_bp)(AX)
 
        // switch to m->g0 & its stack, call fn
        MOVQ    g(CX), BX
@@ -213,8 +217,8 @@ TEXT runtime·systemstack(SB), NOSPLIT, $0-8
        CMPQ    AX, DX
        JEQ     noswitch
 
-       MOVQ    m_curg(BX), BP
-       CMPQ    AX, BP
+       MOVQ    m_curg(BX), R8
+       CMPQ    AX, R8
        JEQ     switch
        
        // Bad: g is not gsignal, not g0, not curg. What is it?
@@ -224,10 +228,11 @@ TEXT runtime·systemstack(SB), NOSPLIT, $0-8
 switch:
        // save our state in g->sched.  Pretend to
        // be systemstack_switch if the G stack is scanned.
-       MOVQ    $runtime·systemstack_switch(SB), BP
-       MOVQ    BP, (g_sched+gobuf_pc)(AX)
+       MOVQ    $runtime·systemstack_switch(SB), SI
+       MOVQ    SI, (g_sched+gobuf_pc)(AX)
        MOVQ    SP, (g_sched+gobuf_sp)(AX)
        MOVQ    AX, (g_sched+gobuf_g)(AX)
+       MOVQ    BP, (g_sched+gobuf_bp)(AX)
 
        // switch to g0
        MOVQ    DX, g(CX)
@@ -303,11 +308,12 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
        LEAQ    8(SP), AX // f's SP
        MOVQ    AX, (g_sched+gobuf_sp)(SI)
        MOVQ    DX, (g_sched+gobuf_ctxt)(SI)
+       MOVQ    BP, (g_sched+gobuf_bp)(SI)
 
        // Call newstack on m->g0's stack.
-       MOVQ    m_g0(BX), BP
-       MOVQ    BP, g(CX)
-       MOVQ    (g_sched+gobuf_sp)(BP), SP
+       MOVQ    m_g0(BX), BX
+       MOVQ    BX, g(CX)
+       MOVQ    (g_sched+gobuf_sp)(BX), SP
        CALL    runtime·newstack(SB)
        MOVQ    $0, 0x1003      // crash if newstack returns
        RET
@@ -592,6 +598,7 @@ TEXT gosave<>(SB),NOSPLIT,$0
        MOVQ    R9, (g_sched+gobuf_sp)(R8)
        MOVQ    $0, (g_sched+gobuf_ret)(R8)
        MOVQ    $0, (g_sched+gobuf_ctxt)(R8)
+       MOVQ    BP, (g_sched+gobuf_bp)(R8)
        RET
 
 // asmcgocall(void(*fn)(void*), void *arg)
@@ -619,17 +626,17 @@ TEXT asmcgocall<>(SB),NOSPLIT,$0-0
        // We get called to create new OS threads too, and those
        // come in on the m->g0 stack already.
        get_tls(CX)
-       MOVQ    g(CX), BP
-       MOVQ    g_m(BP), BP
-       MOVQ    m_g0(BP), SI
+       MOVQ    g(CX), R8
+       MOVQ    g_m(R8), R8
+       MOVQ    m_g0(R8), SI
        MOVQ    g(CX), DI
        CMPQ    SI, DI
        JEQ     nosave
-       MOVQ    m_gsignal(BP), SI
+       MOVQ    m_gsignal(R8), SI
        CMPQ    SI, DI
        JEQ     nosave
        
-       MOVQ    m_g0(BP), SI
+       MOVQ    m_g0(R8), SI
        CALL    gosave<>(SB)
        MOVQ    SI, g(CX)
        MOVQ    (g_sched+gobuf_sp)(SI), SP
@@ -683,15 +690,15 @@ TEXT Â·cgocallback_gofunc(SB),NOSPLIT,$8-24
        // the linker analysis by using an indirect call through AX.
        get_tls(CX)
 #ifdef GOOS_windows
-       MOVL    $0, BP
+       MOVL    $0, BX
        CMPQ    CX, $0
        JEQ     2(PC)
 #endif
-       MOVQ    g(CX), BP
-       CMPQ    BP, $0
+       MOVQ    g(CX), BX
+       CMPQ    BX, $0
        JEQ     needm
-       MOVQ    g_m(BP), BP
-       MOVQ    BP, R8 // holds oldm until end of function
+       MOVQ    g_m(BX), BX
+       MOVQ    BX, R8 // holds oldm until end of function
        JMP     havem
 needm:
        MOVQ    $0, 0(SP)
@@ -699,8 +706,8 @@ needm:
        CALL    AX
        MOVQ    0(SP), R8
        get_tls(CX)
-       MOVQ    g(CX), BP
-       MOVQ    g_m(BP), BP
+       MOVQ    g(CX), BX
+       MOVQ    g_m(BX), BX
        
        // Set m->sched.sp = SP, so that if a panic happens
        // during the function we are about to execute, it will
@@ -713,7 +720,7 @@ needm:
        // and then systemstack will try to use it. If we don't set it here,
        // that restored SP will be uninitialized (typically 0) and
        // will not be usable.
-       MOVQ    m_g0(BP), SI
+       MOVQ    m_g0(BX), SI
        MOVQ    SP, (g_sched+gobuf_sp)(SI)
 
 havem:
@@ -722,7 +729,7 @@ havem:
        // Save current sp in m->g0->sched.sp in preparation for
        // switch back to m->curg stack.
        // NOTE: unwindm knows that the saved g->sched.sp is at 0(SP).
-       MOVQ    m_g0(BP), SI
+       MOVQ    m_g0(BX), SI
        MOVQ    (g_sched+gobuf_sp)(SI), AX
        MOVQ    AX, 0(SP)
        MOVQ    SP, (g_sched+gobuf_sp)(SI)
@@ -742,30 +749,43 @@ havem:
        // the earlier calls.
        //
        // In the new goroutine, 0(SP) holds the saved R8.
-       MOVQ    m_curg(BP), SI
+       MOVQ    m_curg(BX), SI
        MOVQ    SI, g(CX)
        MOVQ    (g_sched+gobuf_sp)(SI), DI  // prepare stack as DI
-       MOVQ    (g_sched+gobuf_pc)(SI), BP
-       MOVQ    BP, -8(DI)
-       LEAQ    -(8+8)(DI), SP
+       MOVQ    (g_sched+gobuf_pc)(SI), BX
+       MOVQ    BX, -8(DI)
+       // Compute the size of the frame, including return PC and, if
+       // GOEXPERIMENT=framepointer, the saved based pointer
+       LEAQ    x+0(FP), AX
+       SUBQ    SP, AX
+       SUBQ    AX, DI
+       MOVQ    DI, SP
+
        MOVQ    R8, 0(SP)
        CALL    runtime·cgocallbackg(SB)
        MOVQ    0(SP), R8
 
+       // Compute the size of the frame again.  FP and SP have
+       // completely different values here than they did above,
+       // but only their difference matters.
+       LEAQ    x+0(FP), AX
+       SUBQ    SP, AX
+
        // Restore g->sched (== m->curg->sched) from saved values.
        get_tls(CX)
        MOVQ    g(CX), SI
-       MOVQ    8(SP), BP
-       MOVQ    BP, (g_sched+gobuf_pc)(SI)
-       LEAQ    (8+8)(SP), DI
+       MOVQ    SP, DI
+       ADDQ    AX, DI
+       MOVQ    -8(DI), BX
+       MOVQ    BX, (g_sched+gobuf_pc)(SI)
        MOVQ    DI, (g_sched+gobuf_sp)(SI)
 
        // Switch back to m->g0's stack and restore m->g0->sched.sp.
        // (Unlike m->curg, the g0 goroutine never uses sched.pc,
        // so we do not have to restore it.)
-       MOVQ    g(CX), BP
-       MOVQ    g_m(BP), BP
-       MOVQ    m_g0(BP), SI
+       MOVQ    g(CX), BX
+       MOVQ    g_m(BX), BX
+       MOVQ    m_g0(BX), SI
        MOVQ    SI, g(CX)
        MOVQ    (g_sched+gobuf_sp)(SI), SP
        MOVQ    0(SP), AX
@@ -915,8 +935,8 @@ aes0to15:
        // a page boundary, so we can load it directly.
        MOVOU   -16(AX), X0
        ADDQ    CX, CX
-       MOVQ    $masks<>(SB), BP
-       PAND    (BP)(CX*8), X0
+       MOVQ    $masks<>(SB), AX
+       PAND    (AX)(CX*8), X0
 
        // scramble 3 times
        AESENC  X6, X0
@@ -931,8 +951,8 @@ endofpage:
        // Then shift bytes down using pshufb.
        MOVOU   -32(AX)(CX*1), X0
        ADDQ    CX, CX
-       MOVQ    $shifts<>(SB), BP
-       PSHUFB  (BP)(CX*8), X0
+       MOVQ    $shifts<>(SB), AX
+       PSHUFB  (AX)(CX*8), X0
        AESENC  X6, X0
        AESENC  X7, X0
        AESENC  X7, X0
@@ -1384,13 +1404,13 @@ TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
        CMPQ    SI, DI
        JEQ     allsame
        CMPQ    BX, DX
-       MOVQ    DX, BP
-       CMOVQLT BX, BP // BP = min(alen, blen) = # of bytes to compare
-       CMPQ    BP, $8
+       MOVQ    DX, R8
+       CMOVQLT BX, R8 // R8 = min(alen, blen) = # of bytes to compare
+       CMPQ    R8, $8
        JB      small
 
 loop:
-       CMPQ    BP, $16
+       CMPQ    R8, $16
        JBE     _0through16
        MOVOU   (SI), X0
        MOVOU   (DI), X1
@@ -1400,7 +1420,7 @@ loop:
        JNE     diff16  // branch if at least one byte is not equal
        ADDQ    $16, SI
        ADDQ    $16, DI
-       SUBQ    $16, BP
+       SUBQ    $16, R8
        JMP     loop
        
        // AX = bit mask of differences
@@ -1415,15 +1435,15 @@ diff16:
 
        // 0 through 16 bytes left, alen>=8, blen>=8
 _0through16:
-       CMPQ    BP, $8
+       CMPQ    R8, $8
        JBE     _0through8
        MOVQ    (SI), AX
        MOVQ    (DI), CX
        CMPQ    AX, CX
        JNE     diff8
 _0through8:
-       MOVQ    -8(SI)(BP*1), AX
-       MOVQ    -8(DI)(BP*1), CX
+       MOVQ    -8(SI)(R8*1), AX
+       MOVQ    -8(DI)(R8*1), CX
        CMPQ    AX, CX
        JEQ     allsame
 
@@ -1440,7 +1460,7 @@ diff8:
 
        // 0-7 bytes in common
 small:
-       LEAQ    (BP*8), CX      // bytes left -> bits left
+       LEAQ    (R8*8), CX      // bytes left -> bits left
        NEGQ    CX              //  - bits lift (== 64 - bits left mod 64)
        JEQ     allsame
 
@@ -1450,7 +1470,7 @@ small:
        MOVQ    (SI), SI
        JMP     si_finish
 si_high:
-       MOVQ    -8(SI)(BP*1), SI
+       MOVQ    -8(SI)(R8*1), SI
        SHRQ    CX, SI
 si_finish:
        SHLQ    CX, SI
@@ -1461,7 +1481,7 @@ si_finish:
        MOVQ    (DI), DI
        JMP     di_finish
 di_high:
-       MOVQ    -8(DI)(BP*1), DI
+       MOVQ    -8(DI)(R8*1), DI
        SHRQ    CX, DI
 di_finish:
        SHLQ    CX, DI
index 96873cc2da713b90f8b2846873f2ea21ca556b21..e7aeb7bee3e40d6f1679bd8def595b2aa3d38a7a 100644 (file)
@@ -225,6 +225,11 @@ func cgocallbackg1() {
                cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
        case "amd64":
                // On amd64, stack frame is one word, plus caller PC.
+               if framepointer_enabled {
+                       // In this case, there's also saved BP.
+                       cb = (*args)(unsafe.Pointer(sp + 3*ptrSize))
+                       break
+               }
                cb = (*args)(unsafe.Pointer(sp + 2*ptrSize))
        case "386":
                // On 386, stack frame is three words, plus caller PC.
index abe73e70a034d7389da651b9c530d4f8a1db1540..56560f94f0d343e49c4526cd9047d61066578e8a 100644 (file)
@@ -96,7 +96,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
                if !block {
                        return false
                }
-               gopark(nil, nil, "chan send (nil chan)")
+               gopark(nil, nil, "chan send (nil chan)", traceEvGoStop)
                throw("unreachable")
        }
 
@@ -178,7 +178,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
                mysg.selectdone = nil
                gp.param = nil
                c.sendq.enqueue(mysg)
-               goparkunlock(&c.lock, "chan send")
+               goparkunlock(&c.lock, "chan send", traceEvGoBlockSend)
 
                // someone woke us up.
                if mysg != gp.waiting {
@@ -217,7 +217,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
                mysg.elem = nil
                mysg.selectdone = nil
                c.sendq.enqueue(mysg)
-               goparkunlock(&c.lock, "chan send")
+               goparkunlock(&c.lock, "chan send", traceEvGoBlockSend)
 
                // someone woke us up - try again
                if mysg.releasetime > 0 {
@@ -340,7 +340,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
                if !block {
                        return
                }
-               gopark(nil, nil, "chan receive (nil chan)")
+               gopark(nil, nil, "chan receive (nil chan)", traceEvGoStop)
                throw("unreachable")
        }
 
@@ -414,7 +414,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
                mysg.selectdone = nil
                gp.param = nil
                c.recvq.enqueue(mysg)
-               goparkunlock(&c.lock, "chan receive")
+               goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv)
 
                // someone woke us up
                if mysg != gp.waiting {
@@ -471,7 +471,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
                mysg.selectdone = nil
 
                c.recvq.enqueue(mysg)
-               goparkunlock(&c.lock, "chan receive")
+               goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv)
 
                // someone woke us up - try again
                if mysg.releasetime > 0 {
index 105b79cfefebc3d3f4cad554a76139d9ca1e49b9..3ecaac10bc1a02794619fc5364bcfa338ad87a8a 100644 (file)
@@ -24,13 +24,13 @@ func GOMAXPROCS(n int) int {
 
        semacquire(&worldsema, false)
        gp := getg()
-       gp.m.gcing = 1
+       gp.m.preemptoff = "GOMAXPROCS"
        systemstack(stoptheworld)
 
        // newprocs will be processed by starttheworld
        newprocs = int32(n)
 
-       gp.m.gcing = 0
+       gp.m.preemptoff = ""
        semrelease(&worldsema)
        systemstack(starttheworld)
        return ret
index c3a6e2f01962cdde0ac9bcafa4846805ee416065..3940240898b0ca0ca44d8a01ec81deba99411d97 100644 (file)
@@ -65,7 +65,7 @@ const (
        _ITIMER_PROF    = 0x2
        _ITIMER_VIRTUAL = 0x1
        _O_RDONLY       = 0
-       _O_CLOEXEC      = 02000000
+       _O_CLOEXEC      = 0x80000
 
        _EPOLLIN       = 0x1
        _EPOLLOUT      = 0x4
@@ -77,6 +77,10 @@ const (
        _EPOLL_CTL_ADD = 0x1
        _EPOLL_CTL_DEL = 0x2
        _EPOLL_CTL_MOD = 0x3
+
+       _AF_UNIX    = 0x1
+       _F_SETFL    = 0x4
+       _SOCK_DGRAM = 0x2
 )
 
 type timespec struct {
@@ -166,3 +170,8 @@ type epollevent struct {
        _pad   uint32
        data   [8]byte // to match amd64
 }
+
+type sockaddr_un struct {
+       family uint16
+       path   [108]byte
+}
index 016938ed4ea76759f1ed58a38b9d6657b043779e..a5d923e860fc122c37367a8461463c99dde8c5d9 100644 (file)
@@ -36,14 +36,12 @@ func LFStackPop(head *uint64) *LFNode {
 }
 
 type ParFor struct {
-       body    *byte
-       done    uint32
-       Nthr    uint32
-       nthrmax uint32
-       thrseq  uint32
-       Cnt     uint32
-       Ctx     *byte
-       wait    bool
+       body   func(*ParFor, uint32)
+       done   uint32
+       Nthr   uint32
+       thrseq uint32
+       Cnt    uint32
+       wait   bool
 }
 
 func NewParFor(nthrmax uint32) *ParFor {
@@ -54,9 +52,9 @@ func NewParFor(nthrmax uint32) *ParFor {
        return desc
 }
 
-func ParForSetup(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32)) {
+func ParForSetup(desc *ParFor, nthr, n uint32, wait bool, body func(*ParFor, uint32)) {
        systemstack(func() {
-               parforsetup((*parfor)(unsafe.Pointer(desc)), nthr, n, unsafe.Pointer(ctx), wait,
+               parforsetup((*parfor)(unsafe.Pointer(desc)), nthr, n, wait,
                        *(*func(*parfor, uint32))(unsafe.Pointer(&body)))
        })
 }
@@ -69,7 +67,7 @@ func ParForDo(desc *ParFor) {
 
 func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
        desc1 := (*parfor)(unsafe.Pointer(desc))
-       pos := desc_thr_index(desc1, tid).pos
+       pos := desc1.thr[tid].pos
        return uint32(pos), uint32(pos >> 32)
 }
 
index 58acbb378808968df596fc71ffd6e9643cdfe790..cd90390b34a613ba7ffcae1a04c56fd8cdba2010 100644 (file)
@@ -45,6 +45,10 @@ a comma-separated list of name=val pairs. Supported names are:
        This should only be used as a temporary workaround to diagnose buggy code.
        The real fix is to not store integers in pointer-typed locations.
 
+       memprofilerate: setting memprofilerate=X will update the value of runtime.MemProfileRate.
+       When set to 0 memory profiling is disabled.  Refer to the description of
+       MemProfileRate for the default value.
+
        scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit
        detailed multiline info every X milliseconds, describing state of the scheduler,
        processors, threads and goroutines.
index f829e8fff1fbf7e260deb1b4c191f752272e5303..058d1c76c43c601f5f27a05b9c5734d5e82c6688 100644 (file)
@@ -106,13 +106,24 @@ type hmap struct {
        // Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
        // ../reflect/type.go.  Don't change this structure without also changing that code!
        count int // # live cells == size of map.  Must be first (used by len() builtin)
-       flags uint32
-       hash0 uint32 // hash seed
+       flags uint8
        B     uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
+       hash0 uint32 // hash seed
 
        buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
        oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
        nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
+
+       // If both key and value do not contain pointers, then we mark bucket
+       // type as containing no pointers. This avoids scanning such maps.
+       // However, bmap.overflow is a pointer. In order to keep overflow buckets
+       // alive, we store pointers to all overflow buckets in hmap.overflow.
+       // Overflow is used only if key and value do not contain pointers.
+       // overflow[0] contains overflow buckets for hmap.buckets.
+       // overflow[1] contains overflow buckets for hmap.oldbuckets.
+       // The first indirection allows us to reduce static size of hmap.
+       // The second indirection allows to store a pointer to the slice in hiter.
+       overflow *[2]*[]*bmap
 }
 
 // A bucket for a Go map.
@@ -135,6 +146,7 @@ type hiter struct {
        h           *hmap
        buckets     unsafe.Pointer // bucket ptr at hash_iter initialization time
        bptr        *bmap          // current bucket
+       overflow    [2]*[]*bmap    // keeps overflow buckets alive
        startBucket uintptr        // bucket iteration started at
        offset      uint8          // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1)
        wrapped     bool           // already wrapped around from end of bucket array to beginning
@@ -152,10 +164,24 @@ func evacuated(b *bmap) bool {
 func (b *bmap) overflow(t *maptype) *bmap {
        return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize))
 }
-func (b *bmap) setoverflow(t *maptype, ovf *bmap) {
+
+func (h *hmap) setoverflow(t *maptype, b, ovf *bmap) {
+       if t.bucket.kind&kindNoPointers != 0 {
+               h.createOverflow()
+               *h.overflow[0] = append(*h.overflow[0], ovf)
+       }
        *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize)) = ovf
 }
 
+func (h *hmap) createOverflow() {
+       if h.overflow == nil {
+               h.overflow = new([2]*[]*bmap)
+       }
+       if h.overflow[0] == nil {
+               h.overflow[0] = new([]*bmap)
+       }
+}
+
 func makemap(t *maptype, hint int64) *hmap {
        if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != uintptr(t.hmap.size) {
                throw("bad hmap size")
@@ -463,7 +489,7 @@ again:
                        memstats.next_gc = memstats.heap_alloc
                }
                newb := (*bmap)(newobject(t.bucket))
-               b.setoverflow(t, newb)
+               h.setoverflow(t, b, newb)
                inserti = &newb.tophash[0]
                insertk = add(unsafe.Pointer(newb), dataOffset)
                insertv = add(insertk, bucketCnt*uintptr(t.keysize))
@@ -548,6 +574,8 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
        it.h = nil
        it.buckets = nil
        it.bptr = nil
+       it.overflow[0] = nil
+       it.overflow[1] = nil
 
        if raceenabled && h != nil {
                callerpc := getcallerpc(unsafe.Pointer(&t))
@@ -560,7 +588,7 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
                return
        }
 
-       if unsafe.Sizeof(hiter{})/ptrSize != 10 {
+       if unsafe.Sizeof(hiter{})/ptrSize != 12 {
                throw("hash_iter size incorrect") // see ../../cmd/gc/reflect.c
        }
        it.t = t
@@ -569,6 +597,14 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
        // grab snapshot of bucket state
        it.B = h.B
        it.buckets = h.buckets
+       if t.bucket.kind&kindNoPointers != 0 {
+               // Allocate the current slice and remember pointers to both current and old.
+               // This preserves all relevant overflow buckets alive even if
+               // the table grows and/or overflow buckets are added to the table
+               // while we are iterating.
+               h.createOverflow()
+               it.overflow = *h.overflow
+       }
 
        // decide where to start
        r := uintptr(fastrand1())
@@ -585,14 +621,8 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
 
        // Remember we have an iterator.
        // Can run concurrently with another hash_iter_init().
-       for {
-               old := h.flags
-               if old == old|iterator|oldIterator {
-                       break
-               }
-               if cas(&h.flags, old, old|iterator|oldIterator) {
-                       break
-               }
+       if old := h.flags; old&(iterator|oldIterator) != iterator|oldIterator {
+               atomicor8(&h.flags, iterator|oldIterator)
        }
 
        mapiternext(it)
@@ -753,6 +783,15 @@ func hashGrow(t *maptype, h *hmap) {
        h.buckets = newbuckets
        h.nevacuate = 0
 
+       if h.overflow != nil {
+               // Promote current overflow buckets to the old generation.
+               if h.overflow[1] != nil {
+                       throw("overflow is not nil")
+               }
+               h.overflow[1] = h.overflow[0]
+               h.overflow[0] = nil
+       }
+
        // the actual copying of the hash table data is done incrementally
        // by growWork() and evacuate().
 }
@@ -836,7 +875,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
                                                        memstats.next_gc = memstats.heap_alloc
                                                }
                                                newx := (*bmap)(newobject(t.bucket))
-                                               x.setoverflow(t, newx)
+                                               h.setoverflow(t, x, newx)
                                                x = newx
                                                xi = 0
                                                xk = add(unsafe.Pointer(x), dataOffset)
@@ -863,7 +902,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
                                                        memstats.next_gc = memstats.heap_alloc
                                                }
                                                newy := (*bmap)(newobject(t.bucket))
-                                               y.setoverflow(t, newy)
+                                               h.setoverflow(t, y, newy)
                                                y = newy
                                                yi = 0
                                                yk = add(unsafe.Pointer(y), dataOffset)
@@ -899,6 +938,12 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
                if oldbucket+1 == newbit { // newbit == # of oldbuckets
                        // Growing is all done.  Free old main bucket array.
                        h.oldbuckets = nil
+                       // Can discard old overflow buckets as well.
+                       // If they are still referenced by an iterator,
+                       // then the iterator holds a pointers to the slice.
+                       if h.overflow != nil {
+                               h.overflow[1] = nil
+                       }
                }
        }
 }
index 6e1f1e9da453069b899489a2022d447fd6bcc8e4..1765a6ce66aacda079ec449e09e2c219790bf661 100644 (file)
@@ -180,7 +180,7 @@ func notetsleep_internal(n *note, ns int64) bool {
 
 func notetsleep(n *note, ns int64) bool {
        gp := getg()
-       if gp != gp.m.g0 && gp.m.gcing == 0 {
+       if gp != gp.m.g0 && gp.m.preemptoff != "" {
                throw("notetsleep not on g0")
        }
 
index c995e084419347f55bccfb9bde053471093aac2d..47cb88335b2ed2bb23b0f48dca0d7b42029becca 100644 (file)
@@ -240,7 +240,7 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
 
 func notetsleep(n *note, ns int64) bool {
        gp := getg()
-       if gp != gp.m.g0 && gp.m.gcing == 0 {
+       if gp != gp.m.g0 && gp.m.preemptoff != "" {
                throw("notetsleep not on g0")
        }
        if gp.m.waitsema == 0 {
index 223220a570ee97d5ef307488c5cdfb305de08b6f..b8b1f4ed36b528f4043f245c9aaa98214b8c8914 100644 (file)
@@ -31,10 +31,12 @@ type pageID uintptr
 // base address for all 0-byte allocations
 var zerobase uintptr
 
+// Trigger the concurrent GC when 1/triggerratio memory is available to allocate.
+// Adjust this ratio as part of a scheme to ensure that mutators have enough
+// memory to allocate in durring a concurrent GC cycle.
+var triggerratio = int64(8)
+
 // Determine whether to initiate a GC.
-// Currently the primitive heuristic we use will start a new
-// concurrent GC when approximately half the available space
-// made available by the last GC cycle has been used.
 // If the GC is already working no need to trigger another one.
 // This should establish a feedback loop where if the GC does not
 // have sufficient time to complete then more memory will be
@@ -44,7 +46,7 @@ var zerobase uintptr
 // A false negative simple does not start a GC, a false positive
 // will start a GC needlessly. Neither have correctness issues.
 func shouldtriggergc() bool {
-       return memstats.heap_alloc+memstats.heap_alloc*3/4 >= memstats.next_gc && atomicloaduint(&bggc.working) == 0
+       return triggerratio*(int64(memstats.next_gc)-int64(memstats.heap_alloc)) <= int64(memstats.next_gc) && atomicloaduint(&bggc.working) == 0
 }
 
 // Allocate an object of size bytes.
@@ -360,12 +362,18 @@ func gcwork(force int32) {
        // Ok, we're doing it!  Stop everybody else
 
        mp := acquirem()
-       mp.gcing = 1
+       mp.preemptoff = "gcing"
        releasem(mp)
        gctimer.count++
        if force == 0 {
                gctimer.cycle.sweepterm = nanotime()
        }
+
+       if trace.enabled {
+               traceGoSched()
+               traceGCStart()
+       }
+
        // Pick up the remaining unswept/not being swept spans before we STW
        for gosweepone() != ^uintptr(0) {
                sweep.nbgsweep++
@@ -387,6 +395,14 @@ func gcwork(force int32) {
                gctimer.cycle.markterm = nanotime()
                systemstack(stoptheworld)
                systemstack(gcinstalloffwb_m)
+       } else {
+               // For non-concurrent GC (force != 0) g stack have not been scanned so
+               // set gcscanvalid such that mark termination scans all stacks.
+               // No races here since we are in a STW phase.
+               for _, gp := range allgs {
+                       gp.gcworkdone = false  // set to true in gcphasework
+                       gp.gcscanvalid = false // stack has not been scanned
+               }
        }
 
        startTime := nanotime()
@@ -421,8 +437,13 @@ func gcwork(force int32) {
                gccheckmark_m(startTime, eagersweep)
        })
 
+       if trace.enabled {
+               traceGCDone()
+               traceGoStart()
+       }
+
        // all done
-       mp.gcing = 0
+       mp.preemptoff = ""
 
        if force == 0 {
                gctimer.cycle.sweep = nanotime()
index 7b5907b2565a9313a632d8c9c2bf8150e61507c3..4d0754ba9d04e97017bd2766089d4c23ca9ce347 100644 (file)
@@ -71,6 +71,9 @@ func purgecachedstats(c *mcache) {
        h := &mheap_
        memstats.heap_alloc += uint64(c.local_cachealloc)
        c.local_cachealloc = 0
+       if trace.enabled {
+               traceHeapAlloc()
+       }
        memstats.tinyallocs += uint64(c.local_tinyallocs)
        c.local_tinyallocs = 0
        memstats.nlookup += uint64(c.local_nlookup)
index 619fd22a929120ac310322f2f8b5078b145dde51..14ffbdbb8ed4a321bb6822c9a634f11000cf2dd4 100644 (file)
@@ -523,8 +523,3 @@ type stackmap struct {
        nbit     int32   // number of bits in each bitmap
        bytedata [1]byte // bitmaps, each starting on a 32-bit boundary
 }
-
-// Returns pointer map data for the given stackmap index
-// (the index is encoded in PCDATA_StackMapIndex).
-
-// defined in mgc0.go
index b7795aa1d66071049fdd88d7a89c7b67d04d462f..454b3c36fe816f6dcc47af0689e47ccfb3c98c5f 100644 (file)
@@ -46,6 +46,23 @@ func TestMemStats(t *testing.T) {
        }
 }
 
+func TestStringConcatenationAllocs(t *testing.T) {
+       n := testing.AllocsPerRun(1e3, func() {
+               b := make([]byte, 10)
+               for i := 0; i < 10; i++ {
+                       b[i] = byte(i) + '0'
+               }
+               s := "foo" + string(b)
+               if want := "foo0123456789"; s != want {
+                       t.Fatalf("want %v, got %v", want, s)
+               }
+       })
+       // Only string concatenation allocates.
+       if n != 1 {
+               t.Fatalf("want 1 allocation, got %v", n)
+       }
+}
+
 var mallocSink uintptr
 
 func BenchmarkMalloc8(b *testing.B) {
index 6c1ebd5c64016d22d9dbfe006951f8a2e001a8de..33d67c49761ffc857fba5b823c6df1a298cd0657 100644 (file)
@@ -105,33 +105,38 @@ func writebarrierptr(dst *uintptr, src uintptr) {
                return
        }
 
-       if src != 0 && (src < _PageSize || src == poisonStack) {
+       if src != 0 && (src < _PhysPageSize || src == poisonStack) {
                systemstack(func() { throw("bad pointer in write barrier") })
        }
 
        if mheap_.shadow_enabled {
-               systemstack(func() {
-                       addr := uintptr(unsafe.Pointer(dst))
-                       shadow := shadowptr(addr)
-                       if shadow == nil {
-                               return
-                       }
-                       // There is a race here but only if the program is using
-                       // racy writes instead of sync/atomic. In that case we
-                       // don't mind crashing.
-                       if *shadow != *dst && *shadow != noShadow && istrackedptr(*dst) {
-                               mheap_.shadow_enabled = false
-                               print("runtime: write barrier dst=", dst, " old=", hex(*dst), " shadow=", shadow, " old=", hex(*shadow), " new=", hex(src), "\n")
-                               throw("missed write barrier")
-                       }
-                       *shadow = src
-               })
+               writebarrierptr_shadow(dst, src)
        }
 
        *dst = src
        writebarrierptr_nostore1(dst, src)
 }
 
+//go:nosplit
+func writebarrierptr_shadow(dst *uintptr, src uintptr) {
+       systemstack(func() {
+               addr := uintptr(unsafe.Pointer(dst))
+               shadow := shadowptr(addr)
+               if shadow == nil {
+                       return
+               }
+               // There is a race here but only if the program is using
+               // racy writes instead of sync/atomic. In that case we
+               // don't mind crashing.
+               if *shadow != *dst && *shadow != noShadow && istrackedptr(*dst) {
+                       mheap_.shadow_enabled = false
+                       print("runtime: write barrier dst=", dst, " old=", hex(*dst), " shadow=", shadow, " old=", hex(*shadow), " new=", hex(src), "\n")
+                       throw("missed write barrier")
+               }
+               *shadow = src
+       })
+}
+
 // Like writebarrierptr, but the store has already been applied.
 // Do not reapply.
 //go:nosplit
@@ -140,7 +145,7 @@ func writebarrierptr_nostore(dst *uintptr, src uintptr) {
                return
        }
 
-       if src != 0 && (src < _PageSize || src == poisonStack) {
+       if src != 0 && (src < _PhysPageSize || src == poisonStack) {
                systemstack(func() { throw("bad pointer in write barrier") })
        }
 
@@ -422,8 +427,8 @@ func wbshadowinit() {
        if end < uintptr(unsafe.Pointer(&ebss)) {
                end = uintptr(unsafe.Pointer(&ebss))
        }
-       start &^= _PageSize - 1
-       end = round(end, _PageSize)
+       start &^= _PhysPageSize - 1
+       end = round(end, _PhysPageSize)
        mheap_.data_start = start
        mheap_.data_end = end
        reserved = false
index e74ad7163d2f913d91daf48d72dceac7b87bc35c..c145886eed7e9176fe4fe8e0ad32dd67f98c77d6 100644 (file)
@@ -81,14 +81,14 @@ func ReadMemStats(m *MemStats) {
        // a pending garbage collection already calling it.
        semacquire(&worldsema, false)
        gp := getg()
-       gp.m.gcing = 1
+       gp.m.preemptoff = "read mem stats"
        systemstack(stoptheworld)
 
        systemstack(func() {
                readmemstats_m(m)
        })
 
-       gp.m.gcing = 0
+       gp.m.preemptoff = ""
        gp.m.locks++
        semrelease(&worldsema)
        systemstack(starttheworld)
@@ -99,14 +99,14 @@ func ReadMemStats(m *MemStats) {
 func runtime_debug_WriteHeapDump(fd uintptr) {
        semacquire(&worldsema, false)
        gp := getg()
-       gp.m.gcing = 1
+       gp.m.preemptoff = "write heap dump"
        systemstack(stoptheworld)
 
        systemstack(func() {
                writeheapdump_m(fd)
        })
 
-       gp.m.gcing = 0
+       gp.m.preemptoff = ""
        gp.m.locks++
        semrelease(&worldsema)
        systemstack(starttheworld)
index a5d7c1a4cfe8b2da4b3e47d27bf12d3e93d17bff..477a52700e7c3f86bf5b104e6f6881e200e8ea3c 100644 (file)
@@ -9,21 +9,24 @@ import "unsafe"
 var bloc uintptr
 var memlock mutex
 
-const memRound = _PAGESIZE - 1
+func memRound(p uintptr) uintptr {
+       return (p + _PAGESIZE - 1) &^ (_PAGESIZE - 1)
+}
 
 func initBloc() {
-       bloc = uintptr(unsafe.Pointer(&end))
+       bloc = memRound(uintptr(unsafe.Pointer(&end)))
 }
 
 func sbrk(n uintptr) unsafe.Pointer {
        lock(&memlock)
        // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
-       bl := (bloc + memRound) &^ memRound
+       bl := bloc
+       n = memRound(n)
        if brk_(unsafe.Pointer(bl+n)) < 0 {
                unlock(&memlock)
                return nil
        }
-       bloc = bl + n
+       bloc += n
        unlock(&memlock)
        return unsafe.Pointer(bl)
 }
@@ -42,7 +45,7 @@ func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
        // from tiny/mem.c
        // Push pointer back if this is a free
        // of the most recent sysAlloc.
-       n += (n + memRound) &^ memRound
+       n = memRound(n)
        if bloc == uintptr(v)+n {
                bloc -= n
        }
index a9a459916681943e575e4941b12749f72f19a8ed..28afa0dfab1215f168dbf39342bd78c7ab0843f5 100644 (file)
@@ -127,7 +127,7 @@ func runfinq() {
                        fing = gp
                        fingwait = true
                        gp.issystem = true
-                       goparkunlock(&finlock, "finalizer wait")
+                       goparkunlock(&finlock, "finalizer wait", traceEvGoBlock)
                        gp.issystem = false
                        continue
                }
@@ -136,8 +136,8 @@ func runfinq() {
                        racefingo()
                }
                for fb != nil {
-                       for i := int32(0); i < fb.cnt; i++ {
-                               f := (*finalizer)(add(unsafe.Pointer(&fb.fin), uintptr(i)*unsafe.Sizeof(finalizer{})))
+                       for i := fb.cnt; i > 0; i-- {
+                               f := (*finalizer)(add(unsafe.Pointer(&fb.fin), uintptr(i-1)*unsafe.Sizeof(finalizer{})))
 
                                framesz := unsafe.Sizeof((interface{})(nil)) + uintptr(f.nret)
                                if framecap < framesz {
@@ -175,8 +175,8 @@ func runfinq() {
                                f.fn = nil
                                f.arg = nil
                                f.ot = nil
+                               fb.cnt = i - 1
                        }
-                       fb.cnt = 0
                        next := fb.next
                        lock(&finlock)
                        fb.next = finc
index 3972d0f2a3696f99a10ba16416ae3c514e37e4d1..75b1e5291616a0fc4b7bcf8ee049cb9335679bc9 100644 (file)
@@ -143,12 +143,12 @@ var gcpercent int32
 // The procedure is:
 //
 //     semacquire(&worldsema);
-//     m.gcing = 1;
+//     m.preemptoff = "reason";
 //     stoptheworld();
 //
 //     ... do stuff ...
 //
-//     m.gcing = 0;
+//     m.preemptoff = "";
 //     semrelease(&worldsema);
 //     starttheworld();
 //
@@ -276,11 +276,31 @@ func greyobject(obj, base, off uintptr, hbits heapBits, wbuf *workbuf) *workbuf
                        print("runtime:greyobject: checkmarks finds unexpected unmarked object obj=", hex(obj), "\n")
                        print("runtime: found obj at *(", hex(base), "+", hex(off), ")\n")
 
+                       // Dump the source (base) object
+
+                       kb := base >> _PageShift
+                       xb := kb
+                       xb -= mheap_.arena_start >> _PageShift
+                       sb := h_spans[xb]
+                       printlock()
+                       print("runtime:greyobject Span: base=", hex(base), " kb=", hex(kb))
+                       if sb == nil {
+                               print(" sb=nil\n")
+                       } else {
+                               print(" sb.start*_PageSize=", hex(sb.start*_PageSize), " sb.limit=", hex(sb.limit), " sb.sizeclass=", sb.sizeclass, " sb.elemsize=", sb.elemsize, "\n")
+                               // base is (a pointer to) the source object holding the reference to object. Create a pointer to each of the fields
+                               // fields in base and print them out as hex values.
+                               for i := 0; i < int(sb.elemsize/ptrSize); i++ {
+                                       print(" *(base+", i*ptrSize, ") = ", hex(*(*uintptr)(unsafe.Pointer(base + uintptr(i)*ptrSize))), "\n")
+                               }
+                       }
+
+                       // Dump the object
+
                        k := obj >> _PageShift
                        x := k
                        x -= mheap_.arena_start >> _PageShift
                        s := h_spans[x]
-                       printlock()
                        print("runtime:greyobject Span: obj=", hex(obj), " k=", hex(k))
                        if s == nil {
                                print(" s=nil\n")
@@ -482,13 +502,16 @@ func drainworkbuf(wbuf *workbuf, drainallwbufs bool) {
        }
 }
 
-// Scan at most count objects in the wbuf.
+// Scan count objects starting with those in wbuf.
 //go:nowritebarrier
 func drainobjects(wbuf *workbuf, count uintptr) {
        for i := uintptr(0); i < count; i++ {
                if wbuf.nobj == 0 {
                        putempty(wbuf)
-                       return
+                       wbuf = trygetfull()
+                       if wbuf == nil {
+                               return
+                       }
                }
 
                // This might be a good place to add prefetch code...
@@ -567,7 +590,10 @@ func markroot(desc *parfor, i uint32) {
                }
 
                // Shrink a stack if not much of it is being used but not in the scan phase.
-               if gcphase != _GCscan { // Do not shrink during GCscan phase.
+               if gcphase == _GCmarktermination {
+                       // Shrink during STW GCmarktermination phase thus avoiding
+                       // complications introduced by shrinking during
+                       // non-STW phases.
                        shrinkstack(gp)
                }
                if readgstatus(gp) == _Gdead {
@@ -833,6 +859,9 @@ func scanframe(frame *stkframe, unused unsafe.Pointer) bool {
 
 //go:nowritebarrier
 func scanstack(gp *g) {
+       if gp.gcscanvalid {
+               return
+       }
 
        if readgstatus(gp)&_Gscan == 0 {
                print("runtime:scanstack: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", hex(readgstatus(gp)), "\n")
@@ -862,6 +891,7 @@ func scanstack(gp *g) {
 
        gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0)
        tracebackdefers(gp, scanframe, nil)
+       gp.gcscanvalid = true
 }
 
 // Shade the object if it isn't already.
@@ -925,6 +955,7 @@ func gcphasework(gp *g) {
        case _GCscan:
                // scan the stack, mark the objects, put pointers in work buffers
                // hanging off the P where this is being run.
+               // Indicate that the scan is valid until the goroutine runs again
                scanstack(gp)
        case _GCmark:
                // No work.
@@ -983,6 +1014,11 @@ func mSpan_Sweep(s *mspan, preserve bool) bool {
                print("MSpan_Sweep: state=", s.state, " sweepgen=", s.sweepgen, " mheap.sweepgen=", sweepgen, "\n")
                throw("MSpan_Sweep: bad span state")
        }
+
+       if trace.enabled {
+               traceGCSweepStart()
+       }
+
        cl := s.sizeclass
        size := s.elemsize
        res := false
@@ -1071,7 +1107,12 @@ func mSpan_Sweep(s *mspan, preserve bool) bool {
                        }
                        c.local_nlargefree++
                        c.local_largefree += size
-                       xadd64(&memstats.next_gc, -int64(size)*int64(gcpercent+100)/100)
+                       reduction := int64(size) * int64(gcpercent+100) / 100
+                       if int64(memstats.next_gc)-reduction > int64(heapminimum) {
+                               xadd64(&memstats.next_gc, -reduction)
+                       } else {
+                               atomicstore64(&memstats.next_gc, heapminimum)
+                       }
                        res = true
                } else {
                        // Free small object.
@@ -1108,10 +1149,19 @@ func mSpan_Sweep(s *mspan, preserve bool) bool {
        if nfree > 0 {
                c.local_nsmallfree[cl] += uintptr(nfree)
                c.local_cachealloc -= intptr(uintptr(nfree) * size)
-               xadd64(&memstats.next_gc, -int64(nfree)*int64(size)*int64(gcpercent+100)/100)
+               reduction := int64(nfree) * int64(size) * int64(gcpercent+100) / 100
+               if int64(memstats.next_gc)-reduction > int64(heapminimum) {
+                       xadd64(&memstats.next_gc, -reduction)
+               } else {
+                       atomicstore64(&memstats.next_gc, heapminimum)
+               }
                res = mCentral_FreeSpan(&mheap_.central[cl].mcentral, s, int32(nfree), head, end, preserve)
                // MCentral_FreeSpan updates sweepgen
        }
+       if trace.enabled {
+               traceGCSweepDone()
+               traceNextGC()
+       }
        return res
 }
 
@@ -1192,12 +1242,20 @@ func gchelper() {
        _g_.m.traceback = 2
        gchelperstart()
 
+       if trace.enabled {
+               traceGCScanStart()
+       }
+
        // parallel mark for over GC roots
        parfordo(work.markfor)
        if gcphase != _GCscan {
                scanblock(0, 0, nil) // blocks in getfull
        }
 
+       if trace.enabled {
+               traceGCScanDone()
+       }
+
        nproc := work.nproc // work.nproc can change right after we increment work.ndone
        if xadd(&work.ndone, +1) == nproc-1 {
                notewakeup(&work.alldone)
@@ -1315,6 +1373,11 @@ func updatememstats(stats *gcstats) {
        memstats.heap_objects = memstats.nmalloc - memstats.nfree
 }
 
+// heapminimum is the minimum number of bytes in the heap.
+// This cleans up the corner case of where we have a very small live set but a lot
+// of allocations and collecting every GOGC * live set is expensive.
+var heapminimum = uint64(4 << 20)
+
 func gcinit() {
        if unsafe.Sizeof(workbuf{}) != _WorkbufSize {
                throw("runtime: size of Workbuf is suboptimal")
@@ -1324,9 +1387,10 @@ func gcinit() {
        gcpercent = readgogc()
        gcdatamask = unrollglobgcprog((*byte)(unsafe.Pointer(&gcdata)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)))
        gcbssmask = unrollglobgcprog((*byte)(unsafe.Pointer(&gcbss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)))
+       memstats.next_gc = heapminimum
 }
 
-// Called from malloc.go using onM, stopping and starting the world handled in caller.
+// Called from malloc.go using systemstack, stopping and starting the world handled in caller.
 //go:nowritebarrier
 func gc_m(start_time int64, eagersweep bool) {
        _g_ := getg()
@@ -1355,7 +1419,7 @@ func clearCheckmarks() {
        }
 }
 
-// Called from malloc.go using onM.
+// Called from malloc.go using systemstack.
 // The world is stopped. Rerun the scan and mark phases
 // using the bitMarkedCheck bit instead of the
 // bitMarked bit. If the marking encounters an
@@ -1417,7 +1481,8 @@ func gcscan_m() {
        local_allglen := allglen
        for i := uintptr(0); i < local_allglen; i++ {
                gp := allgs[i]
-               gp.gcworkdone = false // set to true in gcphasework
+               gp.gcworkdone = false  // set to true in gcphasework
+               gp.gcscanvalid = false // stack has not been scanned
        }
        unlock(&allglock)
 
@@ -1425,7 +1490,7 @@ func gcscan_m() {
        work.ndone = 0
        work.nproc = 1 // For now do not do this in parallel.
        //      ackgcphase is not needed since we are not scanning running goroutines.
-       parforsetup(work.markfor, work.nproc, uint32(_RootCount+local_allglen), nil, false, markroot)
+       parforsetup(work.markfor, work.nproc, uint32(_RootCount+local_allglen), false, markroot)
        parfordo(work.markfor)
 
        lock(&allglock)
@@ -1519,7 +1584,11 @@ func gc(start_time int64, eagersweep bool) {
                gp.gcworkdone = false // set to true in gcphasework
        }
 
-       parforsetup(work.markfor, work.nproc, uint32(_RootCount+allglen), nil, false, markroot)
+       if trace.enabled {
+               traceGCScanStart()
+       }
+
+       parforsetup(work.markfor, work.nproc, uint32(_RootCount+allglen), false, markroot)
        if work.nproc > 1 {
                noteclear(&work.alldone)
                helpgc(int32(work.nproc))
@@ -1551,6 +1620,10 @@ func gc(start_time int64, eagersweep bool) {
                notesleep(&work.alldone)
        }
 
+       if trace.enabled {
+               traceGCScanDone()
+       }
+
        shrinkfinish()
 
        cachestats()
@@ -1560,6 +1633,13 @@ func gc(start_time int64, eagersweep bool) {
        // conservatively set next_gc to high value assuming that everything is live
        // concurrent/lazy sweep will reduce this number while discovering new garbage
        memstats.next_gc = memstats.heap_alloc + memstats.heap_alloc*uint64(gcpercent)/100
+       if memstats.next_gc < heapminimum {
+               memstats.next_gc = heapminimum
+       }
+
+       if trace.enabled {
+               traceNextGC()
+       }
 
        t4 := nanotime()
        atomicstore64(&memstats.last_gc, uint64(unixnanotime())) // must be Unix time to make sense to user
index 5959396bed9a36926697d13a63b341af750ba1f2..bbd786d519949724f47175fa1c32b3be93392e6b 100644 (file)
@@ -67,7 +67,7 @@ func backgroundgc() {
                gcwork(0)
                lock(&bggc.lock)
                bggc.working = 0
-               goparkunlock(&bggc.lock, "Concurrent GC wait")
+               goparkunlock(&bggc.lock, "Concurrent GC wait", traceEvGoBlock)
        }
 }
 
@@ -88,6 +88,6 @@ func bgsweep() {
                        continue
                }
                sweep.parked = true
-               goparkunlock(&gclock, "GC sweep wait")
+               goparkunlock(&gclock, "GC sweep wait", traceEvGoBlock)
        }
 }
index 1ff661c9813184af8a36d33b2cea983b45e83cd4..11bc809ec1d036a12957c8494f98afb6855ad99e 100644 (file)
@@ -217,6 +217,9 @@ func mHeap_Alloc_m(h *mheap, npage uintptr, sizeclass int32, large bool) *mspan
                        }
                }
        }
+       if trace.enabled {
+               traceHeapAlloc()
+       }
        unlock(&h.lock)
        return s
 }
@@ -440,6 +443,9 @@ func mHeap_Free(h *mheap, s *mspan, acct int32) {
                        memstats.heap_objects--
                }
                mHeap_FreeSpanLocked(h, s, true, true)
+               if trace.enabled {
+                       traceHeapAlloc()
+               }
                unlock(&h.lock)
        })
 }
index 7f9b6671f7740170e7a6ae09af0adea4da607980..df7093a004ae2969df5ecfb5262179e3c47c1621 100644 (file)
@@ -522,7 +522,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
        if n <= len(p) {
                gp := getg()
                semacquire(&worldsema, false)
-               gp.m.gcing = 1
+               gp.m.preemptoff = "profile"
                systemstack(stoptheworld)
 
                n = NumGoroutine()
@@ -544,7 +544,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
                        }
                }
 
-               gp.m.gcing = 0
+               gp.m.preemptoff = ""
                semrelease(&worldsema)
                systemstack(starttheworld)
        }
@@ -567,7 +567,7 @@ func Stack(buf []byte, all bool) int {
        if all {
                semacquire(&worldsema, false)
                gp := getg()
-               gp.m.gcing = 1
+               gp.m.preemptoff = "stack trace"
                systemstack(stoptheworld)
        }
 
@@ -591,7 +591,7 @@ func Stack(buf []byte, all bool) int {
 
        if all {
                gp := getg()
-               gp.m.gcing = 0
+               gp.m.preemptoff = ""
                semrelease(&worldsema)
                systemstack(starttheworld)
        }
index 3ef45064914c5ccd4bc0e81efeac0c513e3d2103..8ea0878ca27b161b634286855b241ecb9583b712 100644 (file)
@@ -71,7 +71,7 @@ type pollCache struct {
 
 var (
        netpollInited uint32
-       pollcache pollCache
+       pollcache     pollCache
 )
 
 //go:linkname net_runtime_pollServerInit net.runtime_pollServerInit
@@ -333,7 +333,7 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
        // this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
        // do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
        if waitio || netpollcheckerr(pd, mode) == 0 {
-               gopark(netpollblockcommit, unsafe.Pointer(gpp), "IO wait")
+               gopark(netpollblockcommit, unsafe.Pointer(gpp), "IO wait", traceEvGoBlockNet)
        }
        // be careful to not lose concurrent READY notification
        old := xchguintptr(gpp, 0)
index 09278afbed6c5ecb00683f80598db145d166653f..e2a5c629dada2301c9e3ecdf8688585e45eb0a5d 100644 (file)
@@ -353,11 +353,14 @@ func gopanic(e interface{}) {
                print("\n")
                throw("panic during malloc")
        }
-       if gp.m.gcing != 0 {
+       if gp.m.preemptoff != "" {
                print("panic: ")
                printany(e)
                print("\n")
-               throw("panic during gc")
+               print("preempt off reason: ")
+               print(gp.m.preemptoff)
+               print("\n")
+               throw("panic during preemptoff")
        }
        if gp.m.locks != 0 {
                print("panic: ")
index 880c3bac9ba8a497251a7381b32f5571abd7366c..4c0eb405859d201867aabfc1df6f3bff94ec9a41 100644 (file)
@@ -135,7 +135,7 @@ func canpanic(gp *g) bool {
        if gp == nil || gp != _m_.curg {
                return false
        }
-       if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.gcing != 0 || _m_.dying != 0 {
+       if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
                return false
        }
        status := readgstatus(gp)
index 3a377474dca575d6c1df5e91dfe73d023faf3caa..c82beee3fd11b1af8c632dc96f49ed1e947388e5 100644 (file)
@@ -6,8 +6,27 @@
 
 package runtime
 
-import "unsafe"
+// A parfor holds state for the parallel for operation.
+type parfor struct {
+       body   func(*parfor, uint32) // executed for each element
+       done   uint32                // number of idle threads
+       nthr   uint32                // total number of threads
+       thrseq uint32                // thread id sequencer
+       cnt    uint32                // iteration space [0, cnt)
+       wait   bool                  // if true, wait while all threads finish processing,
+       // otherwise parfor may return while other threads are still working
+
+       thr []parforthread // thread descriptors
 
+       // stats
+       nsteal     uint64
+       nstealcnt  uint64
+       nprocyield uint64
+       nosyield   uint64
+       nsleep     uint64
+}
+
+// A parforthread holds state for a single thread in the parallel for.
 type parforthread struct {
        // the thread's iteration space [32lsb, 32msb)
        pos uint64
@@ -20,22 +39,33 @@ type parforthread struct {
        pad        [_CacheLineSize]byte
 }
 
-func desc_thr_index(desc *parfor, i uint32) *parforthread {
-       return (*parforthread)(add(unsafe.Pointer(desc.thr), uintptr(i)*unsafe.Sizeof(*desc.thr)))
+func parforalloc(nthrmax uint32) *parfor {
+       return &parfor{
+               thr: make([]parforthread, nthrmax),
+       }
 }
 
-func parforsetup(desc *parfor, nthr, n uint32, ctx unsafe.Pointer, wait bool, body func(*parfor, uint32)) {
-       if desc == nil || nthr == 0 || nthr > desc.nthrmax || body == nil {
+// Parforsetup initializes desc for a parallel for operation with nthr
+// threads executing n jobs.
+//
+// On return the nthr threads are each expected to call parfordo(desc)
+// to run the operation. During those calls, for each i in [0, n), one
+// thread will be used invoke body(desc, i).
+// If wait is true, no parfordo will return until all work has been completed.
+// If wait is false, parfordo may return when there is a small amount
+// of work left, under the assumption that another thread has that
+// work well in hand.
+func parforsetup(desc *parfor, nthr, n uint32, wait bool, body func(*parfor, uint32)) {
+       if desc == nil || nthr == 0 || nthr > uint32(len(desc.thr)) || body == nil {
                print("desc=", desc, " nthr=", nthr, " count=", n, " body=", body, "\n")
                throw("parfor: invalid args")
        }
 
-       desc.body = *(*unsafe.Pointer)(unsafe.Pointer(&body))
+       desc.body = body
        desc.done = 0
        desc.nthr = nthr
        desc.thrseq = 0
        desc.cnt = n
-       desc.ctx = ctx
        desc.wait = wait
        desc.nsteal = 0
        desc.nstealcnt = 0
@@ -43,14 +73,10 @@ func parforsetup(desc *parfor, nthr, n uint32, ctx unsafe.Pointer, wait bool, bo
        desc.nosyield = 0
        desc.nsleep = 0
 
-       for i := uint32(0); i < nthr; i++ {
+       for i := range desc.thr {
                begin := uint32(uint64(n) * uint64(i) / uint64(nthr))
                end := uint32(uint64(n) * uint64(i+1) / uint64(nthr))
-               pos := &desc_thr_index(desc, i).pos
-               if uintptr(unsafe.Pointer(pos))&7 != 0 {
-                       throw("parforsetup: pos is not aligned")
-               }
-               *pos = uint64(begin) | uint64(end)<<32
+               desc.thr[i].pos = uint64(begin) | uint64(end)<<32
        }
 }
 
@@ -63,7 +89,7 @@ func parfordo(desc *parfor) {
        }
 
        // If single-threaded, just execute the for serially.
-       body := *(*func(*parfor, uint32))(unsafe.Pointer(&desc.body))
+       body := desc.body
        if desc.nthr == 1 {
                for i := uint32(0); i < desc.cnt; i++ {
                        body(desc, i)
@@ -71,7 +97,7 @@ func parfordo(desc *parfor) {
                return
        }
 
-       me := desc_thr_index(desc, tid)
+       me := &desc.thr[tid]
        mypos := &me.pos
        for {
                for {
@@ -116,7 +142,7 @@ func parfordo(desc *parfor) {
                        if victim >= tid {
                                victim++
                        }
-                       victimpos := &desc_thr_index(desc, victim).pos
+                       victimpos := &desc.thr[victim].pos
                        for {
                                // See if it has any work.
                                pos := atomicload64(victimpos)
index de64285b8a8e532f461ddc540bef0653a7078da4..5d22aecc9bb24ac3b53e33936a2756ad1100b460 100644 (file)
@@ -10,11 +10,8 @@ package runtime_test
 import (
        . "runtime"
        "testing"
-       "unsafe"
 )
 
-var gdata []uint64
-
 // Simple serial sanity test for parallelfor.
 func TestParFor(t *testing.T) {
        const P = 1
@@ -24,12 +21,7 @@ func TestParFor(t *testing.T) {
                data[i] = i
        }
        desc := NewParFor(P)
-       // Avoid making func a closure: parfor cannot invoke them.
-       // Since it doesn't happen in the C code, it's not worth doing
-       // just for the test.
-       gdata = data
-       ParForSetup(desc, P, N, nil, true, func(desc *ParFor, i uint32) {
-               data := gdata
+       ParForSetup(desc, P, N, true, func(desc *ParFor, i uint32) {
                data[i] = data[i]*data[i] + 1
        })
        ParForDo(desc)
@@ -49,9 +41,8 @@ func TestParFor2(t *testing.T) {
                data[i] = i
        }
        desc := NewParFor(P)
-       ParForSetup(desc, P, N, (*byte)(unsafe.Pointer(&data)), false, func(desc *ParFor, i uint32) {
-               d := *(*[]uint64)(unsafe.Pointer(desc.Ctx))
-               d[i] = d[i]*d[i] + 1
+       ParForSetup(desc, P, N, false, func(desc *ParFor, i uint32) {
+               data[i] = data[i]*data[i] + 1
        })
        for p := 0; p < P; p++ {
                ParForDo(desc)
@@ -70,7 +61,7 @@ func TestParForSetup(t *testing.T) {
        desc := NewParFor(P)
        for n := uint32(0); n < N; n++ {
                for p := uint32(1); p <= P; p++ {
-                       ParForSetup(desc, p, n, nil, true, func(desc *ParFor, i uint32) {})
+                       ParForSetup(desc, p, n, true, func(desc *ParFor, i uint32) {})
                        sum := uint32(0)
                        size0 := uint32(0)
                        end0 := uint32(0)
@@ -113,9 +104,7 @@ func TestParForParallel(t *testing.T) {
        P := GOMAXPROCS(-1)
        c := make(chan bool, P)
        desc := NewParFor(uint32(P))
-       gdata = data
-       ParForSetup(desc, uint32(P), uint32(N), nil, false, func(desc *ParFor, i uint32) {
-               data := gdata
+       ParForSetup(desc, uint32(P), uint32(N), false, func(desc *ParFor, i uint32) {
                data[i] = data[i]*data[i] + 1
        })
        for p := 1; p < P; p++ {
index 236de54f384cabc24effed0da6c188ed1756a0e9..b3d0ae9b648b069d5ea9ed4df980b25bf60bf9c4 100644 (file)
@@ -615,6 +615,33 @@ func StopCPUProfile() {
        <-cpu.done
 }
 
+// TODO(rsc): Decide if StartTrace belongs in this package.
+// See golang.org/issue/9710.
+// StartTrace enables tracing for the current process.
+// While tracing, the trace will be buffered and written to w.
+// StartTrace returns an error if profiling is tracing enabled.
+func StartTrace(w io.Writer) error {
+       if err := runtime.StartTrace(); err != nil {
+               return err
+       }
+       go func() {
+               for {
+                       data := runtime.ReadTrace()
+                       if data == nil {
+                               break
+                       }
+                       w.Write(data)
+               }
+       }()
+       return nil
+}
+
+// StopTrace stops the current tracing, if any.
+// StopTrace only returns after all the writes for the trace have completed.
+func StopTrace() {
+       runtime.StopTrace()
+}
+
 type byCycles []runtime.BlockProfileRecord
 
 func (x byCycles) Len() int           { return len(x) }
index 101c0598937e3468b7a82a07f78c54a2e562ebe4..49dd78446f68947b65176f672f06538a3e2ec008 100644 (file)
@@ -10,6 +10,7 @@ import (
        "bytes"
        "fmt"
        "math/big"
+       "os"
        "os/exec"
        "regexp"
        "runtime"
@@ -186,6 +187,14 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
                        t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
                        return
                }
+               // Ignore the failure if the tests are running in a QEMU-based emulator,
+               // QEMU is not perfect at emulating everything.
+               // IN_QEMU environmental variable is set by some of the Go builders.
+               // IN_QEMU=1 indicates that the tests are running in QEMU. See issue 9605.
+               if os.Getenv("IN_QEMU") == "1" {
+                       t.Skip("ignore the failure in QEMU; see golang.org/issue/9605")
+                       return
+               }
                t.FailNow()
        }
 }
diff --git a/src/runtime/pprof/trace_parser_test.go b/src/runtime/pprof/trace_parser_test.go
new file mode 100644 (file)
index 0000000..c1c4324
--- /dev/null
@@ -0,0 +1,656 @@
+// Copyright 2014 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pprof_test
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+       "io"
+       "os/exec"
+       "sort"
+       "strconv"
+       "strings"
+)
+
+// Event describes one event in the trace.
+type Event struct {
+       off   int       // offset in input file (for debugging and error reporting)
+       typ   byte      // one of traceEv*
+       ts    int64     // timestamp in nanoseconds
+       p     int       // P on which the event happened (can be one of timerP, netpollP, syscallP)
+       g     uint64    // G on which the event happened
+       stkID uint64    // unique stack ID
+       stk   []*Frame  // stack trace (can be empty)
+       args  [2]uint64 // event-type-specific arguments
+       // linked event (can be nil), depends on event type:
+       // for GCStart: the GCStop
+       // for GCScanStart: the GCScanDone
+       // for GCSweepStart: the GCSweepDone
+       // for GoCreate: first GoStart of the created goroutine
+       // for GoStart: the associated GoEnd, GoBlock or other blocking event
+       // for GoSched/GoPreempt: the next GoStart
+       // for GoBlock and other blocking events: the unblock event
+       // for GoUnblock: the associated GoStart
+       // for blocking GoSysCall: the associated GoSysExit
+       // for GoSysExit: the next GoStart
+       link *Event
+}
+
+// Frame is a frame in stack traces.
+type Frame struct {
+       pc   uint64
+       fn   string
+       file string
+       line int
+}
+
+const (
+       // Special P identifiers:
+       timerP   = 1000000 + iota // depicts timer unblocks
+       netpollP                  // depicts network unblocks
+       syscallP                  // depicts returns from syscalls
+)
+
+// parseTrace parses, post-processes and verifies the trace.
+func parseTrace(r io.Reader) ([]*Event, error) {
+       rawEvents, err := readTrace(r)
+       if err != nil {
+               return nil, err
+       }
+       events, err := parseEvents(rawEvents)
+       if err != nil {
+               return nil, err
+       }
+       err = postProcessTrace(events)
+       if err != nil {
+               return nil, err
+       }
+       return events, nil
+}
+
+// RawEvent is a helper type used during parsing.
+type RawEvent struct {
+       off  int
+       typ  byte
+       args []uint64
+}
+
+// readTrace does wire-format parsing and verification.
+// It does not care about specific event types and argument meaning.
+func readTrace(r io.Reader) ([]RawEvent, error) {
+       // Read and validate trace header.
+       var buf [8]byte
+       off, err := r.Read(buf[:])
+       if off != 8 || err != nil {
+               return nil, fmt.Errorf("failed to read header: read %v, err %v", off, err)
+       }
+       if bytes.Compare(buf[:], []byte("gotrace\x00")) != 0 {
+               return nil, fmt.Errorf("not a trace file")
+       }
+
+       // Read events.
+       var events []RawEvent
+       for {
+               // Read event type and number of arguments (1 byte).
+               off0 := off
+               n, err := r.Read(buf[:1])
+               if err == io.EOF {
+                       break
+               }
+               if err != nil || n != 1 {
+                       return nil, fmt.Errorf("failed to read trace at offset 0x%x: n=%v err=%v", off0, n, err)
+               }
+               off += n
+               typ := buf[0] << 2 >> 2
+               narg := buf[0]>>6 + 1
+               ev := RawEvent{typ: typ, off: off0}
+               if narg <= 3 {
+                       for i := 0; i < int(narg); i++ {
+                               var v uint64
+                               v, off, err = readVal(r, off)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               ev.args = append(ev.args, v)
+                       }
+               } else {
+                       // If narg == 4, the first value is length of the event in bytes.
+                       var v uint64
+                       v, off, err = readVal(r, off)
+                       if err != nil {
+                               return nil, err
+                       }
+                       evLen := v
+                       off1 := off
+                       for evLen > uint64(off-off1) {
+                               v, off, err = readVal(r, off)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               ev.args = append(ev.args, v)
+                       }
+                       if evLen != uint64(off-off1) {
+                               return nil, fmt.Errorf("event has wrong length at offset 0x%x: want %v, got %v", off0, evLen, off-off1)
+                       }
+               }
+               events = append(events, ev)
+       }
+       return events, nil
+}
+
+// Parse events transforms raw events into events.
+// It does analyze and verify per-event-type arguments.
+func parseEvents(rawEvents []RawEvent) (events []*Event, err error) {
+       var ticksPerSec, lastTs int64
+       var lastG, timerGoid uint64
+       var lastP int
+       lastGs := make(map[int]uint64) // last goroutine running on P
+       stacks := make(map[uint64][]*Frame)
+       for _, raw := range rawEvents {
+               if raw.typ == traceEvNone || raw.typ >= traceEvCount {
+                       err = fmt.Errorf("unknown event type %v at offset 0x%x", raw.typ, raw.off)
+                       return
+               }
+               desc := evDescriptions[raw.typ]
+               if desc.name == "" {
+                       err = fmt.Errorf("missing description for event type %v", raw.typ)
+                       return
+               }
+               if raw.typ != traceEvStack {
+                       narg := len(desc.args)
+                       if desc.stack {
+                               narg++
+                       }
+                       if raw.typ != traceEvBatch && raw.typ != traceEvFrequency && raw.typ != traceEvTimerGoroutine {
+                               narg++ // timestamp
+                       }
+                       if len(raw.args) != narg {
+                               err = fmt.Errorf("%v has wrong number of arguments at offset 0x%x: want %v, got %v",
+                                       desc.name, raw.off, narg, len(raw.args))
+                               return
+                       }
+               }
+               switch raw.typ {
+               case traceEvBatch:
+                       lastGs[lastP] = lastG
+                       lastP = int(raw.args[0])
+                       lastG = lastGs[lastP]
+                       lastTs = int64(raw.args[1])
+               case traceEvFrequency:
+                       ticksPerSec = int64(raw.args[0])
+                       if ticksPerSec <= 0 {
+                               err = fmt.Errorf("traceEvFrequency contains invalid frequency %v at offset 0x%x",
+                                       ticksPerSec, raw.off)
+                               return
+                       }
+               case traceEvTimerGoroutine:
+                       timerGoid = raw.args[0]
+               case traceEvStack:
+                       if len(raw.args) < 2 {
+                               err = fmt.Errorf("traceEvStack has wrong number of arguments at offset 0x%x: want at least 2, got %v",
+                                       raw.off, len(raw.args))
+                               return
+                       }
+                       size := raw.args[1]
+                       if size > 1000 {
+                               err = fmt.Errorf("traceEvStack has bad number of frames at offset 0x%x: %v",
+                                       raw.off, size)
+                               return
+                       }
+                       id := raw.args[0]
+                       if id != 0 && size > 0 {
+                               stk := make([]*Frame, size)
+                               for i := 0; i < int(size); i++ {
+                                       stk[i] = &Frame{pc: raw.args[i+2]}
+                               }
+                               stacks[id] = stk
+                       }
+               default:
+                       e := &Event{off: raw.off, typ: raw.typ, p: lastP, g: lastG}
+                       e.ts = lastTs + int64(raw.args[0])
+                       lastTs = e.ts
+                       for i := range desc.args {
+                               e.args[i] = raw.args[i+1]
+                       }
+                       if desc.stack {
+                               e.stkID = raw.args[len(desc.args)+1]
+                       }
+                       switch raw.typ {
+                       case traceEvGoStart:
+                               lastG = e.args[0]
+                               e.g = lastG
+                       case traceEvGCStart, traceEvGCDone, traceEvGCScanStart, traceEvGCScanDone:
+                               e.g = 0
+                       case traceEvGoEnd, traceEvGoStop, traceEvGoSched, traceEvGoPreempt,
+                               traceEvGoSleep, traceEvGoBlock, traceEvGoBlockSend, traceEvGoBlockRecv,
+                               traceEvGoBlockSelect, traceEvGoBlockSync, traceEvGoBlockCond, traceEvGoBlockNet,
+                               traceEvGoSysBlock:
+                               lastG = 0
+                       }
+                       events = append(events, e)
+               }
+       }
+
+       // Attach stack traces.
+       for _, ev := range events {
+               if ev.stkID != 0 {
+                       ev.stk = stacks[ev.stkID]
+               }
+       }
+
+       // Sort by time and translate cpu ticks to real time.
+       sort.Sort(EventList(events))
+       if ticksPerSec == 0 {
+               err = fmt.Errorf("no traceEvFrequency event")
+               return
+       }
+       minTs := events[0].ts
+       for _, ev := range events {
+               ev.ts = (ev.ts - minTs) * 1e9 / ticksPerSec
+               // Move timers and syscalls to separate fake Ps.
+               if timerGoid != 0 && ev.g == timerGoid && ev.typ == traceEvGoUnblock {
+                       ev.p = timerP
+               }
+               if ev.typ == traceEvGoSysExit {
+                       ev.p = syscallP
+                       ev.g = ev.args[0]
+               }
+       }
+
+       return
+}
+
+// postProcessTrace does inter-event verification and information restoration.
+// The resulting trace is guaranteed to be consistent
+// (for example, a P does not run two Gs at the same time, or a G is indeed
+// blocked before an unblock event).
+func postProcessTrace(events []*Event) error {
+       const (
+               gDead = iota
+               gRunnable
+               gRunning
+               gWaiting
+       )
+       type gdesc struct {
+               state   int
+               ev      *Event
+               evStart *Event
+       }
+       type pdesc struct {
+               running bool
+               g       uint64
+               evGC    *Event
+               evScan  *Event
+               evSweep *Event
+       }
+
+       gs := make(map[uint64]gdesc)
+       ps := make(map[int]pdesc)
+       gs[0] = gdesc{state: gRunning}
+
+       checkRunning := func(p pdesc, g gdesc, ev *Event) error {
+               name := evDescriptions[ev.typ].name
+               if g.state != gRunning {
+                       return fmt.Errorf("g %v is not running while %v (offset %v, time %v)", ev.g, name, ev.off, ev.ts)
+               }
+               if p.g != ev.g {
+                       return fmt.Errorf("p %v is not running g %v while %v (offset %v, time %v)", ev.p, ev.g, name, ev.off, ev.ts)
+               }
+               return nil
+       }
+
+       for _, ev := range events {
+               g := gs[ev.g]
+               p := ps[ev.p]
+
+               switch ev.typ {
+               case traceEvProcStart:
+                       if p.running {
+                               return fmt.Errorf("p %v is running before start (offset %v, time %v)", ev.p, ev.off, ev.ts)
+                       }
+                       p.running = true
+               case traceEvProcStop:
+                       if !p.running {
+                               return fmt.Errorf("p %v is not running before stop (offset %v, time %v)", ev.p, ev.off, ev.ts)
+                       }
+                       if p.g != 0 {
+                               return fmt.Errorf("p %v is running a goroutine %v during stop (offset %v, time %v)", ev.p, p.g, ev.off, ev.ts)
+                       }
+                       p.running = false
+               case traceEvGCStart:
+                       if p.evGC != nil {
+                               return fmt.Errorf("previous GC is not ended before a new one (offset %v, time %v)", ev.off, ev.ts)
+                       }
+                       p.evGC = ev
+               case traceEvGCDone:
+                       if p.evGC == nil {
+                               return fmt.Errorf("bogus GC end (offset %v, time %v)", ev.off, ev.ts)
+                       }
+                       p.evGC.link = ev
+                       p.evGC = nil
+               case traceEvGCScanStart:
+                       if p.evScan != nil {
+                               return fmt.Errorf("previous scanning is not ended before a new one (offset %v, time %v)", ev.off, ev.ts)
+                       }
+                       p.evScan = ev
+               case traceEvGCScanDone:
+                       if p.evScan == nil {
+                               return fmt.Errorf("bogus scanning end (offset %v, time %v)", ev.off, ev.ts)
+                       }
+                       p.evScan.link = ev
+                       p.evScan = nil
+               case traceEvGCSweepStart:
+                       if p.evSweep != nil {
+                               return fmt.Errorf("previous sweeping is not ended before a new one (offset %v, time %v)", ev.off, ev.ts)
+                       }
+                       p.evSweep = ev
+               case traceEvGCSweepDone:
+                       if p.evSweep == nil {
+                               return fmt.Errorf("bogus sweeping end (offset %v, time %v)", ev.off, ev.ts)
+                       }
+                       p.evSweep.link = ev
+                       p.evSweep = nil
+               case traceEvGoWaiting:
+                       g1 := gs[ev.args[0]]
+                       if g1.state != gRunnable {
+                               return fmt.Errorf("g %v is not runnable before traceEvGoWaiting (offset %v, time %v)", ev.args[0], ev.off, ev.ts)
+                       }
+                       g1.state = gWaiting
+                       gs[ev.args[0]] = g1
+               case traceEvGoInSyscall:
+                       // this case is intentionally left blank
+               case traceEvGoCreate:
+                       if err := checkRunning(p, g, ev); err != nil {
+                               return err
+                       }
+                       if _, ok := gs[ev.args[0]]; ok {
+                               return fmt.Errorf("g %v already exists (offset %v, time %v)", ev.args[0], ev.off, ev.ts)
+                       }
+                       gs[ev.args[0]] = gdesc{state: gRunnable, ev: ev}
+               case traceEvGoStart:
+                       if g.state != gRunnable {
+                               return fmt.Errorf("g %v is not runnable before start (offset %v, time %v)", ev.g, ev.off, ev.ts)
+                       }
+                       if p.g != 0 {
+                               return fmt.Errorf("p %v is already running g %v while start g %v (offset %v, time %v)", ev.p, p.g, ev.g, ev.off, ev.ts)
+                       }
+                       g.state = gRunning
+                       g.evStart = ev
+                       p.g = ev.g
+                       if g.ev != nil {
+                               if g.ev.typ == traceEvGoCreate {
+                                       // +1 because symblizer expects return pc.
+                                       ev.stk = []*Frame{&Frame{pc: g.ev.args[1] + 1}}
+                               }
+                               g.ev.link = ev
+                               g.ev = nil
+                       }
+               case traceEvGoEnd, traceEvGoStop:
+                       if err := checkRunning(p, g, ev); err != nil {
+                               return err
+                       }
+                       g.evStart.link = ev
+                       g.evStart = nil
+                       g.state = gDead
+                       p.g = 0
+               case traceEvGoSched, traceEvGoPreempt:
+                       if err := checkRunning(p, g, ev); err != nil {
+                               return err
+                       }
+                       g.state = gRunnable
+                       g.evStart.link = ev
+                       g.evStart = nil
+                       p.g = 0
+                       g.ev = ev
+               case traceEvGoUnblock:
+                       if g.state != gRunning {
+                               return fmt.Errorf("g %v is not running while unpark (offset %v, time %v)", ev.g, ev.off, ev.ts)
+                       }
+                       if ev.p != timerP && p.g != ev.g {
+                               return fmt.Errorf("p %v is not running g %v while unpark (offset %v, time %v)", ev.p, ev.g, ev.off, ev.ts)
+                       }
+                       g1 := gs[ev.args[0]]
+                       if g1.state != gWaiting {
+                               return fmt.Errorf("g %v is not waiting before unpark (offset %v, time %v)", ev.args[0], ev.off, ev.ts)
+                       }
+                       if g1.ev != nil && g1.ev.typ == traceEvGoBlockNet && ev.p != timerP {
+                               ev.p = netpollP
+                       }
+                       if g1.ev != nil {
+                               g1.ev.link = ev
+                       }
+                       g1.state = gRunnable
+                       g1.ev = ev
+                       gs[ev.args[0]] = g1
+               case traceEvGoSysCall:
+                       if err := checkRunning(p, g, ev); err != nil {
+                               return err
+                       }
+                       g.ev = ev
+               case traceEvGoSysBlock:
+                       if err := checkRunning(p, g, ev); err != nil {
+                               return err
+                       }
+                       g.state = gRunnable
+                       g.evStart.link = ev
+                       g.evStart = nil
+                       p.g = 0
+               case traceEvGoSysExit:
+                       if g.state != gRunnable {
+                               return fmt.Errorf("g %v is not runnable during syscall exit (offset %v, time %v)", ev.g, ev.off, ev.ts)
+                       }
+                       if g.ev != nil && g.ev.typ == traceEvGoSysCall {
+                               g.ev.link = ev
+                       }
+                       g.ev = ev
+               case traceEvGoSleep, traceEvGoBlock, traceEvGoBlockSend, traceEvGoBlockRecv,
+                       traceEvGoBlockSelect, traceEvGoBlockSync, traceEvGoBlockCond, traceEvGoBlockNet:
+                       if err := checkRunning(p, g, ev); err != nil {
+                               return err
+                       }
+                       g.state = gWaiting
+                       g.ev = ev
+                       g.evStart.link = ev
+                       g.evStart = nil
+                       p.g = 0
+               }
+
+               gs[ev.g] = g
+               ps[ev.p] = p
+       }
+
+       return nil
+}
+
+// symbolizeTrace attaches func/file/line info to stack traces.
+func symbolizeTrace(events []*Event, bin string) error {
+       // First, collect and dedup all pcs.
+       pcs := make(map[uint64]*Frame)
+       for _, ev := range events {
+               for _, f := range ev.stk {
+                       pcs[f.pc] = nil
+               }
+       }
+
+       // Start addr2line.
+       cmd := exec.Command("go", "tool", "addr2line", bin)
+       in, err := cmd.StdinPipe()
+       if err != nil {
+               return fmt.Errorf("failed to pipe addr2line stdin: %v", err)
+       }
+       out, err := cmd.StdoutPipe()
+       if err != nil {
+               return fmt.Errorf("failed to pipe addr2line stdout: %v", err)
+       }
+       err = cmd.Start()
+       if err != nil {
+               return fmt.Errorf("failed to start addr2line: %v", err)
+       }
+       outb := bufio.NewReader(out)
+
+       // Write all pcs to addr2line.
+       // Need to copy pcs to an array, because map iteration order is non-deterministic.
+       var pcArray []uint64
+       for pc := range pcs {
+               pcArray = append(pcArray, pc)
+               _, err := fmt.Fprintf(in, "0x%x\n", pc-1)
+               if err != nil {
+                       return fmt.Errorf("failed to write to addr2line: %v", err)
+               }
+       }
+       in.Close()
+
+       // Read in answers.
+       for _, pc := range pcArray {
+               fn, err := outb.ReadString('\n')
+               if err != nil {
+                       return fmt.Errorf("failed to read from addr2line: %v", err)
+               }
+               file, err := outb.ReadString('\n')
+               if err != nil {
+                       return fmt.Errorf("failed to read from addr2line: %v", err)
+               }
+               f := &Frame{pc: pc}
+               f.fn = fn[:len(fn)-1]
+               f.file = file[:len(file)-1]
+               if colon := strings.LastIndex(f.file, ":"); colon != -1 {
+                       ln, err := strconv.Atoi(f.file[colon+1:])
+                       if err == nil {
+                               f.file = f.file[:colon]
+                               f.line = ln
+                       }
+               }
+               pcs[pc] = f
+       }
+       cmd.Wait()
+
+       // Replace frames in events array.
+       for _, ev := range events {
+               for i, f := range ev.stk {
+                       ev.stk[i] = pcs[f.pc]
+               }
+       }
+
+       return nil
+}
+
+// readVal reads unsigned base-128 value from r.
+func readVal(r io.Reader, off0 int) (v uint64, off int, err error) {
+       off = off0
+       for i := 0; i < 10; i++ {
+               var buf [1]byte
+               var n int
+               n, err = r.Read(buf[:])
+               if err != nil || n != 1 {
+                       return 0, 0, fmt.Errorf("failed to read trace at offset: read %v, error %v", off0, n, err)
+               }
+               off++
+               v |= uint64(buf[0]&0x7f) << (uint(i) * 7)
+               if buf[0]&0x80 == 0 {
+                       return
+               }
+       }
+       return 0, 0, fmt.Errorf("bad value at offset 0x%x", off0)
+}
+
+type EventList []*Event
+
+func (l EventList) Len() int {
+       return len(l)
+}
+
+func (l EventList) Less(i, j int) bool {
+       return l[i].ts < l[j].ts
+}
+
+func (l EventList) Swap(i, j int) {
+       l[i], l[j] = l[j], l[i]
+}
+
+// Event types in the trace.
+// Verbatim copy from src/runtime/trace.go.
+const (
+       traceEvNone           = 0  // unused
+       traceEvBatch          = 1  // start of per-P batch of events [pid, timestamp]
+       traceEvFrequency      = 2  // contains tracer timer frequency [frequency (ticks per second)]
+       traceEvStack          = 3  // stack [stack id, number of PCs, array of PCs]
+       traceEvGomaxprocs     = 4  // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id]
+       traceEvProcStart      = 5  // start of P [timestamp]
+       traceEvProcStop       = 6  // stop of P [timestamp]
+       traceEvGCStart        = 7  // GC start [timestamp, stack id]
+       traceEvGCDone         = 8  // GC done [timestamp]
+       traceEvGCScanStart    = 9  // GC scan start [timestamp]
+       traceEvGCScanDone     = 10 // GC scan done [timestamp]
+       traceEvGCSweepStart   = 11 // GC sweep start [timestamp, stack id]
+       traceEvGCSweepDone    = 12 // GC sweep done [timestamp]
+       traceEvGoCreate       = 13 // goroutine creation [timestamp, new goroutine id, start PC, stack id]
+       traceEvGoStart        = 14 // goroutine starts running [timestamp, goroutine id]
+       traceEvGoEnd          = 15 // goroutine ends [timestamp]
+       traceEvGoStop         = 16 // goroutine stops (like in select{}) [timestamp, stack]
+       traceEvGoSched        = 17 // goroutine calls Gosched [timestamp, stack]
+       traceEvGoPreempt      = 18 // goroutine is preempted [timestamp, stack]
+       traceEvGoSleep        = 19 // goroutine calls Sleep [timestamp, stack]
+       traceEvGoBlock        = 20 // goroutine blocks [timestamp, stack]
+       traceEvGoUnblock      = 21 // goroutine is unblocked [timestamp, goroutine id, stack]
+       traceEvGoBlockSend    = 22 // goroutine blocks on chan send [timestamp, stack]
+       traceEvGoBlockRecv    = 23 // goroutine blocks on chan recv [timestamp, stack]
+       traceEvGoBlockSelect  = 24 // goroutine blocks on select [timestamp, stack]
+       traceEvGoBlockSync    = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
+       traceEvGoBlockCond    = 26 // goroutine blocks on Cond [timestamp, stack]
+       traceEvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
+       traceEvGoSysCall      = 28 // syscall enter [timestamp, stack]
+       traceEvGoSysExit      = 29 // syscall exit [timestamp, goroutine id]
+       traceEvGoSysBlock     = 30 // syscall blocks [timestamp, stack]
+       traceEvGoWaiting      = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
+       traceEvGoInSyscall    = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
+       traceEvHeapAlloc      = 33 // memstats.heap_alloc change [timestamp, heap_alloc]
+       traceEvNextGC         = 34 // memstats.next_gc change [timestamp, next_gc]
+       traceEvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
+       traceEvCount          = 36
+)
+
+var evDescriptions = [traceEvCount]struct {
+       name  string
+       stack bool
+       args  []string
+}{
+       traceEvNone:           {"None", false, []string{}},
+       traceEvBatch:          {"Batch", false, []string{"p", "ticks"}},
+       traceEvFrequency:      {"Frequency", false, []string{"freq"}},
+       traceEvStack:          {"Stack", false, []string{"id", "siz"}},
+       traceEvGomaxprocs:     {"Gomaxprocs", true, []string{"procs"}},
+       traceEvProcStart:      {"ProcStart", false, []string{}},
+       traceEvProcStop:       {"ProcStop", false, []string{}},
+       traceEvGCStart:        {"GCStart", true, []string{}},
+       traceEvGCDone:         {"GCDone", false, []string{}},
+       traceEvGCScanStart:    {"GCScanStart", false, []string{}},
+       traceEvGCScanDone:     {"GCScanDone", false, []string{}},
+       traceEvGCSweepStart:   {"GCSweepStart", true, []string{}},
+       traceEvGCSweepDone:    {"GCSweepDone", false, []string{}},
+       traceEvGoCreate:       {"GoCreate", true, []string{"g", "pc"}},
+       traceEvGoStart:        {"GoStart", false, []string{"g"}},
+       traceEvGoEnd:          {"GoEnd", false, []string{}},
+       traceEvGoStop:         {"GoStop", true, []string{}},
+       traceEvGoSched:        {"GoSched", true, []string{}},
+       traceEvGoPreempt:      {"GoPreempt", true, []string{}},
+       traceEvGoSleep:        {"GoSleep", true, []string{}},
+       traceEvGoBlock:        {"GoBlock", true, []string{}},
+       traceEvGoUnblock:      {"GoUnblock", true, []string{"g"}},
+       traceEvGoBlockSend:    {"GoBlockSend", true, []string{}},
+       traceEvGoBlockRecv:    {"GoBlockRecv", true, []string{}},
+       traceEvGoBlockSelect:  {"GoBlockSelect", true, []string{}},
+       traceEvGoBlockSync:    {"GoBlockSync", true, []string{}},
+       traceEvGoBlockCond:    {"GoBlockCond", true, []string{}},
+       traceEvGoBlockNet:     {"GoBlockNet", true, []string{}},
+       traceEvGoSysCall:      {"GoSysCall", true, []string{}},
+       traceEvGoSysExit:      {"GoSysExit", false, []string{"g"}},
+       traceEvGoSysBlock:     {"GoSysBlock", true, []string{}},
+       traceEvGoWaiting:      {"GoWaiting", false, []string{"g"}},
+       traceEvGoInSyscall:    {"GoInSyscall", false, []string{"g"}},
+       traceEvHeapAlloc:      {"HeapAlloc", false, []string{"mem"}},
+       traceEvNextGC:         {"NextGC", false, []string{"mem"}},
+       traceEvTimerGoroutine: {"TimerGoroutine", false, []string{"g"}},
+}
diff --git a/src/runtime/pprof/trace_test.go b/src/runtime/pprof/trace_test.go
new file mode 100644 (file)
index 0000000..1b99830
--- /dev/null
@@ -0,0 +1,244 @@
+// Copyright 2014 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pprof_test
+
+import (
+       "bytes"
+       "net"
+       "os"
+       "runtime"
+       . "runtime/pprof"
+       "strings"
+       "sync"
+       "testing"
+       "time"
+)
+
+func skipTraceTestsIfNeeded(t *testing.T) {
+       switch runtime.GOOS {
+       case "solaris":
+               t.Skip("skipping: solaris timer can go backwards (http://golang.org/issue/8976)")
+       }
+
+       switch runtime.GOARCH {
+       case "arm":
+               t.Skip("skipping: arm tests fail with 'failed to parse trace' (http://golang.org/issue/9725)")
+       }
+}
+
+func TestTraceStartStop(t *testing.T) {
+       skipTraceTestsIfNeeded(t)
+       buf := new(bytes.Buffer)
+       if err := StartTrace(buf); err != nil {
+               t.Fatalf("failed to start tracing: %v", err)
+       }
+       StopTrace()
+       size := buf.Len()
+       if size == 0 {
+               t.Fatalf("trace is empty")
+       }
+       time.Sleep(100 * time.Millisecond)
+       if size != buf.Len() {
+               t.Fatalf("trace writes after stop: %v -> %v", size, buf.Len())
+       }
+}
+
+func TestTraceDoubleStart(t *testing.T) {
+       skipTraceTestsIfNeeded(t)
+       StopTrace()
+       buf := new(bytes.Buffer)
+       if err := StartTrace(buf); err != nil {
+               t.Fatalf("failed to start tracing: %v", err)
+       }
+       if err := StartTrace(buf); err == nil {
+               t.Fatalf("succeed to start tracing second time")
+       }
+       StopTrace()
+       StopTrace()
+}
+
+func TestTrace(t *testing.T) {
+       skipTraceTestsIfNeeded(t)
+       buf := new(bytes.Buffer)
+       if err := StartTrace(buf); err != nil {
+               t.Fatalf("failed to start tracing: %v", err)
+       }
+       StopTrace()
+       _, err := parseTrace(buf)
+       if err != nil {
+               t.Fatalf("failed to parse trace: %v", err)
+       }
+}
+
+func TestTraceStress(t *testing.T) {
+       skipTraceTestsIfNeeded(t)
+
+       var wg sync.WaitGroup
+       done := make(chan bool)
+
+       // Create a goroutine blocked before tracing.
+       wg.Add(1)
+       go func() {
+               <-done
+               wg.Done()
+       }()
+
+       // Create a goroutine blocked in syscall before tracing.
+       rp, wp, err := os.Pipe()
+       if err != nil {
+               t.Fatalf("failed to create pipe: %v", err)
+       }
+       defer func() {
+               rp.Close()
+               wp.Close()
+       }()
+       wg.Add(1)
+       go func() {
+               var tmp [1]byte
+               rp.Read(tmp[:])
+               <-done
+               wg.Done()
+       }()
+       time.Sleep(time.Millisecond)
+
+       buf := new(bytes.Buffer)
+       if err := StartTrace(buf); err != nil {
+               t.Fatalf("failed to start tracing: %v", err)
+       }
+
+       procs := runtime.GOMAXPROCS(10)
+
+       go func() {
+               runtime.LockOSThread()
+               for {
+                       select {
+                       case <-done:
+                               return
+                       default:
+                               runtime.Gosched()
+                       }
+               }
+       }()
+
+       runtime.GC()
+       // Trigger GC from malloc.
+       for i := 0; i < 1e3; i++ {
+               _ = make([]byte, 1<<20)
+       }
+
+       // Create a bunch of busy goroutines to load all Ps.
+       for p := 0; p < 10; p++ {
+               wg.Add(1)
+               go func() {
+                       // Do something useful.
+                       tmp := make([]byte, 1<<16)
+                       for i := range tmp {
+                               tmp[i]++
+                       }
+                       _ = tmp
+                       <-done
+                       wg.Done()
+               }()
+       }
+
+       // Block in syscall.
+       wg.Add(1)
+       go func() {
+               var tmp [1]byte
+               rp.Read(tmp[:])
+               <-done
+               wg.Done()
+       }()
+
+       // Test timers.
+       timerDone := make(chan bool)
+       go func() {
+               time.Sleep(time.Millisecond)
+               timerDone <- true
+       }()
+       <-timerDone
+
+       // A bit of network.
+       ln, err := net.Listen("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatalf("listen failed: %v", err)
+       }
+       defer ln.Close()
+       go func() {
+               c, err := ln.Accept()
+               if err != nil {
+                       return
+               }
+               time.Sleep(time.Millisecond)
+               var buf [1]byte
+               c.Write(buf[:])
+               c.Close()
+       }()
+       c, err := net.Dial("tcp", ln.Addr().String())
+       if err != nil {
+               t.Fatalf("dial failed: %v", err)
+       }
+       var tmp [1]byte
+       c.Read(tmp[:])
+       c.Close()
+
+       go func() {
+               runtime.Gosched()
+               select {}
+       }()
+
+       // Unblock helper goroutines and wait them to finish.
+       wp.Write(tmp[:])
+       wp.Write(tmp[:])
+       close(done)
+       wg.Wait()
+
+       runtime.GOMAXPROCS(procs)
+
+       StopTrace()
+       _, err = parseTrace(buf)
+       if err != nil {
+               t.Fatalf("failed to parse trace: %v", err)
+       }
+}
+
+func TestTraceSymbolize(t *testing.T) {
+       skipTraceTestsIfNeeded(t)
+       if runtime.GOOS == "nacl" {
+               t.Skip("skipping: nacl tests fail with 'failed to symbolize trace: failed to start addr2line'")
+       }
+       buf := new(bytes.Buffer)
+       if err := StartTrace(buf); err != nil {
+               t.Fatalf("failed to start tracing: %v", err)
+       }
+       runtime.GC()
+       StopTrace()
+       events, err := parseTrace(buf)
+       if err != nil {
+               t.Fatalf("failed to parse trace: %v", err)
+       }
+       err = symbolizeTrace(events, os.Args[0])
+       if err != nil {
+               t.Fatalf("failed to symbolize trace: %v", err)
+       }
+       found := false
+eventLoop:
+       for _, ev := range events {
+               if ev.typ != traceEvGCStart {
+                       continue
+               }
+               for _, f := range ev.stk {
+                       if strings.HasSuffix(f.file, "trace_test.go") &&
+                               strings.HasSuffix(f.fn, "pprof_test.TestTraceSymbolize") &&
+                               f.line == 216 {
+                               found = true
+                               break eventLoop
+                       }
+               }
+       }
+       if !found {
+               t.Fatalf("the trace does not contain GC event")
+       }
+}
index 31093de70f5778735b5d4312f3d48828654285ca..1f4f0996fe18abb2add2b0afb24ef216aa9a52c3 100644 (file)
@@ -9,29 +9,60 @@ import "unsafe"
 var (
        writeHeader = []byte{6 /* ANDROID_LOG_ERROR */, 'G', 'o', 0}
        writePath   = []byte("/dev/log/main\x00")
-       writeFD     uintptr
-       writeBuf    [1024]byte
-       writePos    int
+       writeLogd   = []byte("/dev/socket/logdw\x00")
+
+       // guarded by printlock/printunlock.
+       writeFD  uintptr
+       writeBuf [1024]byte
+       writePos int
+)
+
+// Prior to Android-L, logging was done through writes to /dev/log files implemented
+// in kernel ring buffers. In Android-L, those /dev/log files are no longer
+// accessible and logging is done through a centralized user-mode logger, logd.
+//
+// https://android.googlesource.com/platform/system/core/+/master/liblog/logd_write.c
+type loggerType int32
+
+const (
+       unknown loggerType = iota
+       legacy
+       logd
+       // TODO(hakim): logging for emulator?
 )
 
+var logger loggerType
+
 func writeErr(b []byte) {
-       // Log format: "<priority 1 byte><tag n bytes>\x00<message m bytes>\x00"
+       if logger == unknown {
+               // Use logd if /dev/socket/logdw is available.
+               if v := uintptr(access(&writeLogd[0], 0x02 /* W_OK */)); v == 0 {
+                       logger = logd
+                       initLogd()
+               } else {
+                       logger = legacy
+                       initLegacy()
+               }
+       }
+
+       // Log format: "<header>\x00<message m bytes>\x00"
+       //
+       // <header>
+       //   In legacy mode: "<priority 1 byte><tag n bytes>".
+       //   In logd mode: "<android_log_header_t 11 bytes><priority 1 byte><tag n bytes>"
+       //
        // The entire log needs to be delivered in a single syscall (the NDK
        // does this with writev). Each log is its own line, so we need to
        // buffer writes until we see a newline.
-       if writeFD == 0 {
-               writeFD = uintptr(open(&writePath[0], 0x1 /* O_WRONLY */, 0))
-               if writeFD == 0 {
-                       // It is hard to do anything here. Write to stderr just
-                       // in case user has root on device and has run
-                       //      adb shell setprop log.redirect-stdio true
-                       msg := []byte("runtime: cannot open /dev/log/main\x00")
-                       write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
-                       exit(2)
-               }
-               copy(writeBuf[:], writeHeader)
+       var hlen int
+       switch logger {
+       case logd:
+               hlen = writeLogdHeader()
+       case legacy:
+               hlen = len(writeHeader)
        }
-       dst := writeBuf[len(writeHeader):]
+
+       dst := writeBuf[hlen:]
        for _, v := range b {
                if v == 0 { // android logging won't print a zero byte
                        v = '0'
@@ -40,9 +71,87 @@ func writeErr(b []byte) {
                writePos++
                if v == '\n' || writePos == len(dst)-1 {
                        dst[writePos] = 0
-                       write(writeFD, unsafe.Pointer(&writeBuf[0]), int32(len(writeHeader)+writePos))
+                       write(writeFD, unsafe.Pointer(&writeBuf[0]), int32(hlen+writePos))
                        memclrBytes(dst)
                        writePos = 0
                }
        }
 }
+
+func initLegacy() {
+       // In legacy mode, logs are written to /dev/log/main
+       writeFD = uintptr(open(&writePath[0], 0x1 /* O_WRONLY */, 0))
+       if writeFD == 0 {
+               // It is hard to do anything here. Write to stderr just
+               // in case user has root on device and has run
+               //      adb shell setprop log.redirect-stdio true
+               msg := []byte("runtime: cannot open /dev/log/main\x00")
+               write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
+               exit(2)
+       }
+
+       // Prepopulate the invariant header part.
+       copy(writeBuf[:len(writeHeader)], writeHeader)
+}
+
+// used in initLogdWrite but defined here to avoid heap allocation.
+var logdAddr sockaddr_un
+
+func initLogd() {
+       // In logd mode, logs are sent to the logd via a unix domain socket.
+       logdAddr.family = _AF_UNIX
+       copy(logdAddr.path[:], writeLogd)
+
+       // We are not using non-blocking I/O because writes taking this path
+       // are most likely triggered by panic, we cannot think of the advantage of
+       // non-blocking I/O for panic but see disadvantage (dropping panic message),
+       // and blocking I/O simplifies the code a lot.
+       fd := socket(_AF_UNIX, _SOCK_DGRAM|_O_CLOEXEC, 0)
+       if fd < 0 {
+               msg := []byte("runtime: cannot create a socket for logging\x00")
+               write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
+               exit(2)
+       }
+
+       errno := connect(uintptr(fd), unsafe.Pointer(&logdAddr), int32(unsafe.Sizeof(logdAddr)))
+       if errno < 0 {
+               msg := []byte("runtime: cannot connect to /dev/socket/logdw\x00")
+               write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
+               // TODO(hakim): or should we just close fd and hope for better luck next time?
+               exit(2)
+       }
+       writeFD = uintptr(fd)
+
+       // Prepopulate invariant part of the header.
+       // The first 11 bytes will be populated later in writeLogdHeader.
+       copy(writeBuf[11:11+len(writeHeader)], writeHeader)
+}
+
+// writeLogdHeader populates the header and returns the length of the payload.
+func writeLogdHeader() int {
+       hdr := writeBuf[:11]
+
+       // The first 11 bytes of the header corresponds to android_log_header_t
+       // as defined in system/core/include/private/android_logger.h
+       //   hdr[0] log type id (unsigned char), defined in <log/log.h>
+       //   hdr[1:2] tid (uint16_t)
+       //   hdr[3:11] log_time defined in <log/log_read.h>
+       //      hdr[3:7] sec unsigned uint32, little endian.
+       //      hdr[7:11] nsec unsigned uint32, little endian.
+       hdr[0] = 0 // LOG_ID_MAIN
+       sec, nsec := time_now()
+       packUint32(hdr[3:7], uint32(sec))
+       packUint32(hdr[7:11], uint32(nsec))
+
+       // TODO(hakim):  hdr[1:2] = gettid?
+
+       return 11 + len(writeHeader)
+}
+
+func packUint32(b []byte, v uint32) {
+       // little-endian.
+       b[0] = byte(v)
+       b[1] = byte(v >> 8)
+       b[2] = byte(v >> 16)
+       b[3] = byte(v >> 24)
+}
index 03ba00fd97ee540963e34bab36b73acdeb50dba4..c8f6de1ac8ac6b62cc47b5920619a1de17e91117 100644 (file)
@@ -93,7 +93,7 @@ func main() {
        // let the other goroutine finish printing the panic trace.
        // Once it does, it will exit. See issue 3934.
        if panicking != 0 {
-               gopark(nil, nil, "panicwait")
+               gopark(nil, nil, "panicwait", traceEvGoStop)
        }
 
        exit(0)
@@ -117,7 +117,7 @@ func forcegchelper() {
                        throw("forcegc: phase error")
                }
                atomicstore(&forcegc.idle, 1)
-               goparkunlock(&forcegc.lock, "force gc (idle)")
+               goparkunlock(&forcegc.lock, "force gc (idle)", traceEvGoBlock)
                // this goroutine is explicitly resumed by sysmon
                if debug.gctrace > 0 {
                        println("GC forced")
@@ -136,7 +136,7 @@ func Gosched() {
 
 // Puts the current goroutine into a waiting state and calls unlockf.
 // If unlockf returns false, the goroutine is resumed.
-func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string) {
+func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string, traceEv byte) {
        mp := acquirem()
        gp := mp.curg
        status := readgstatus(gp)
@@ -146,6 +146,7 @@ func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason s
        mp.waitlock = lock
        mp.waitunlockf = *(*unsafe.Pointer)(unsafe.Pointer(&unlockf))
        gp.waitreason = reason
+       mp.waittraceev = traceEv
        releasem(mp)
        // can't do anything that might move the G between Ms here.
        mcall(park_m)
@@ -153,8 +154,8 @@ func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason s
 
 // Puts the current goroutine into a waiting state and unlocks the lock.
 // The goroutine can be made runnable again by calling goready(gp).
-func goparkunlock(lock *mutex, reason string) {
-       gopark(parkunlock_c, unsafe.Pointer(lock), reason)
+func goparkunlock(lock *mutex, reason string, traceEv byte) {
+       gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceEv)
 }
 
 func goready(gp *g) {
@@ -244,18 +245,6 @@ func lockedOSThread() bool {
        return gp.lockedm != nil && gp.m.lockedg != nil
 }
 
-func newP() *p {
-       return new(p)
-}
-
-func newM() *m {
-       return new(m)
-}
-
-func newG() *g {
-       return new(g)
-}
-
 var (
        allgs    []*g
        allglock mutex
index 6fa407f0ce2f29e01e150994955a611218a9a10f..70addbffad5cfdee783e443bb1303fca9ee3cad9 100644 (file)
@@ -29,72 +29,6 @@ const (
        _GoidCacheBatch = 16
 )
 
-/*
-SchedT sched;
-int32  gomaxprocs;
-uint32 needextram;
-bool   iscgo;
-M      m0;
-G      g0;     // idle goroutine for m0
-G*     lastg;
-M*     allm;
-M*     extram;
-P*     allp[MaxGomaxprocs+1];
-int8*  goos;
-int32  ncpu;
-int32  newprocs;
-
-Mutex allglock;        // the following vars are protected by this lock or by stoptheworld
-G**    allg;
-Slice  allgs;
-uintptr allglen;
-ForceGCState   forcegc;
-
-void mstart(void);
-static void runqput(P*, G*);
-static G* runqget(P*);
-static bool runqputslow(P*, G*, uint32, uint32);
-static G* runqsteal(P*, P*);
-static void mput(M*);
-static M* mget(void);
-static void mcommoninit(M*);
-static void schedule(void);
-static void procresize(int32);
-static void acquirep(P*);
-static P* releasep(void);
-static void newm(void(*)(void), P*);
-static void stopm(void);
-static void startm(P*, bool);
-static void handoffp(P*);
-static void wakep(void);
-static void stoplockedm(void);
-static void startlockedm(G*);
-static void sysmon(void);
-static uint32 retake(int64);
-static void incidlelocked(int32);
-static void checkdead(void);
-static void exitsyscall0(G*);
-void park_m(G*);
-static void goexit0(G*);
-static void gfput(P*, G*);
-static G* gfget(P*);
-static void gfpurge(P*);
-static void globrunqput(G*);
-static void globrunqputbatch(G*, G*, int32);
-static G* globrunqget(P*, int32);
-static P* pidleget(void);
-static void pidleput(P*);
-static void injectglist(G*);
-static bool preemptall(void);
-static bool preemptone(P*);
-static bool exitsyscallfast(void);
-static bool haveexperiment(int8*);
-void allgadd(G*);
-static void dropg(void);
-
-extern String buildVersion;
-*/
-
 // The bootstrap sequence is:
 //
 //     call osinit
@@ -113,6 +47,9 @@ func schedinit() {
 
        sched.maxmcount = 10000
 
+       // Cache the framepointer experiment.  This affects stack unwinding.
+       framepointer_enabled = haveexperiment("framepointer")
+
        tracebackinit()
        symtabinit()
        stackinit()
@@ -196,6 +133,10 @@ func mcommoninit(mp *m) {
 
 // Mark gp ready to run.
 func ready(gp *g) {
+       if trace.enabled {
+               traceGoUnpark(gp)
+       }
+
        status := readgstatus(gp)
 
        // Mark runnable.
@@ -263,6 +204,7 @@ func helpgc(nproc int32) {
                        throw("gcprocs inconsistency")
                }
                mp.helpgc = n
+               mp.p = allp[pos]
                mp.mcache = allp[pos].mcache
                pos++
                notewakeup(&mp.park)
@@ -340,6 +282,9 @@ func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
                dumpgstatus(gp)
                throw("casfrom_Gscanstatus: gp->status is not in scan state")
        }
+       if newval == _Grunning {
+               gp.gcscanvalid = false
+       }
 }
 
 // This will return false if the gp is not in the expected status and the cas fails.
@@ -353,6 +298,10 @@ func castogscanstatus(gp *g, oldval, newval uint32) bool {
                        return cas(&gp.atomicstatus, oldval, newval)
                }
        case _Grunning:
+               if gp.gcscanvalid {
+                       print("runtime: castogscanstatus _Grunning and gp.gcscanvalid is true, newval=", hex(newval), "\n")
+                       throw("castogscanstatus")
+               }
                if newval == _Gscanrunning || newval == _Gscanenqueue {
                        return cas(&gp.atomicstatus, oldval, newval)
                }
@@ -370,7 +319,7 @@ func castogscanstatus(gp *g, oldval, newval uint32) bool {
 func casgstatus(gp *g, oldval, newval uint32) {
        if (oldval&_Gscan != 0) || (newval&_Gscan != 0) || oldval == newval {
                systemstack(func() {
-                       print("casgstatus: oldval=", hex(oldval), " newval=", hex(newval), "\n")
+                       print("runtime: casgstatus: oldval=", hex(oldval), " newval=", hex(newval), "\n")
                        throw("casgstatus: bad incoming values")
                })
        }
@@ -391,6 +340,9 @@ func casgstatus(gp *g, oldval, newval uint32) {
                //      })
                // }
        }
+       if newval == _Grunning {
+               gp.gcscanvalid = false
+       }
 }
 
 // casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
@@ -604,6 +556,11 @@ func stoptheworld() {
                p := allp[i]
                s := p.status
                if s == _Psyscall && cas(&p.status, s, _Pgcstop) {
+                       if trace.enabled {
+                               traceGoSysBlock(p)
+                               traceProcStop(p)
+                       }
+                       p.syscalltick++
                        sched.stopwait--
                }
        }
@@ -790,7 +747,7 @@ func allocm(_p_ *p) *m {
        if _g_.m.p == nil {
                acquirep(_p_) // temporarily borrow p for mallocs in this function
        }
-       mp := newM()
+       mp := new(m)
        mcommoninit(mp)
 
        // In case of cgo or Solaris, pthread_create will make us a stack.
@@ -813,10 +770,6 @@ func allocm(_p_ *p) *m {
        return mp
 }
 
-func allocg() *g {
-       return newG()
-}
-
 // needm is called when a cgo callback happens on a
 // thread without an m (a thread not created by Go).
 // In this case, needm is expected to find an m to use
@@ -1052,6 +1005,7 @@ retry:
                gchelper()
                _g_.m.helpgc = 0
                _g_.m.mcache = nil
+               _g_.m.p = nil
                goto retry
        }
        acquirep(_g_.m.nextp)
@@ -1234,6 +1188,10 @@ func execute(gp *g) {
                resetcpuprofiler(hz)
        }
 
+       if trace.enabled {
+               traceGoStart()
+       }
+
        gogo(&gp.sched)
 }
 
@@ -1272,6 +1230,9 @@ top:
        if gp := netpoll(false); gp != nil { // non-blocking
                injectglist(gp.schedlink)
                casgstatus(gp, _Gwaiting, _Grunnable)
+               if trace.enabled {
+                       traceGoUnpark(gp)
+               }
                return gp
        }
 
@@ -1355,6 +1316,9 @@ stop:
                                acquirep(_p_)
                                injectglist(gp.schedlink)
                                casgstatus(gp, _Gwaiting, _Grunnable)
+                               if trace.enabled {
+                                       traceGoUnpark(gp)
+                               }
                                return gp
                        }
                        injectglist(gp)
@@ -1391,6 +1355,11 @@ func injectglist(glist *g) {
        if glist == nil {
                return
        }
+       if trace.enabled {
+               for gp := glist; gp != nil; gp = gp.schedlink {
+                       traceGoUnpark(gp)
+               }
+       }
        lock(&sched.lock)
        var n int
        for n = 0; glist != nil; n++ {
@@ -1426,20 +1395,27 @@ top:
        }
 
        var gp *g
-       // Check the global runnable queue once in a while to ensure fairness.
-       // Otherwise two goroutines can completely occupy the local runqueue
-       // by constantly respawning each other.
-       tick := _g_.m.p.schedtick
-       // This is a fancy way to say tick%61==0,
-       // it uses 2 MUL instructions instead of a single DIV and so is faster on modern processors.
-       if uint64(tick)-((uint64(tick)*0x4325c53f)>>36)*61 == 0 && sched.runqsize > 0 {
-               lock(&sched.lock)
-               gp = globrunqget(_g_.m.p, 1)
-               unlock(&sched.lock)
+       if trace.enabled || trace.shutdown {
+               gp = traceReader()
                if gp != nil {
+                       casgstatus(gp, _Gwaiting, _Grunnable)
+                       traceGoUnpark(gp)
                        resetspinning()
                }
        }
+       if gp == nil {
+               // Check the global runnable queue once in a while to ensure fairness.
+               // Otherwise two goroutines can completely occupy the local runqueue
+               // by constantly respawning each other.
+               if _g_.m.p.schedtick%61 == 0 && sched.runqsize > 0 {
+                       lock(&sched.lock)
+                       gp = globrunqget(_g_.m.p, 1)
+                       unlock(&sched.lock)
+                       if gp != nil {
+                               resetspinning()
+                       }
+               }
+       }
        if gp == nil {
                gp = runqget(_g_.m.p)
                if gp != nil && _g_.m.spinning {
@@ -1479,11 +1455,12 @@ func dropg() {
 
 // Puts the current goroutine into a waiting state and calls unlockf.
 // If unlockf returns false, the goroutine is resumed.
-func park(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string) {
+func park(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string, traceev byte) {
        _g_ := getg()
 
        _g_.m.waitlock = lock
        _g_.m.waitunlockf = *(*unsafe.Pointer)(unsafe.Pointer(&unlockf))
+       _g_.m.waittraceev = traceev
        _g_.waitreason = reason
        mcall(park_m)
 }
@@ -1495,14 +1472,18 @@ func parkunlock_c(gp *g, lock unsafe.Pointer) bool {
 
 // Puts the current goroutine into a waiting state and unlocks the lock.
 // The goroutine can be made runnable again by calling ready(gp).
-func parkunlock(lock *mutex, reason string) {
-       park(parkunlock_c, unsafe.Pointer(lock), reason)
+func parkunlock(lock *mutex, reason string, traceev byte) {
+       park(parkunlock_c, unsafe.Pointer(lock), reason, traceev)
 }
 
 // park continuation on g0.
 func park_m(gp *g) {
        _g_ := getg()
 
+       if trace.enabled {
+               traceGoPark(_g_.m.waittraceev, gp)
+       }
+
        casgstatus(gp, _Grunning, _Gwaiting)
        dropg()
 
@@ -1512,6 +1493,9 @@ func park_m(gp *g) {
                _g_.m.waitunlockf = nil
                _g_.m.waitlock = nil
                if !ok {
+                       if trace.enabled {
+                               traceGoUnpark(gp)
+                       }
                        casgstatus(gp, _Gwaiting, _Grunnable)
                        execute(gp) // Schedule it back, never returns.
                }
@@ -1519,8 +1503,7 @@ func park_m(gp *g) {
        schedule()
 }
 
-// Gosched continuation on g0.
-func gosched_m(gp *g) {
+func goschedImpl(gp *g) {
        status := readgstatus(gp)
        if status&^_Gscan != _Grunning {
                dumpgstatus(gp)
@@ -1535,6 +1518,21 @@ func gosched_m(gp *g) {
        schedule()
 }
 
+// Gosched continuation on g0.
+func gosched_m(gp *g) {
+       if trace.enabled {
+               traceGoSched()
+       }
+       goschedImpl(gp)
+}
+
+func gopreempt_m(gp *g) {
+       if trace.enabled {
+               traceGoPreempt()
+       }
+       goschedImpl(gp)
+}
+
 // Finishes execution of the current goroutine.
 // Must be NOSPLIT because it is called from Go. (TODO - probably not anymore)
 //go:nosplit
@@ -1542,6 +1540,9 @@ func goexit1() {
        if raceenabled {
                racegoend()
        }
+       if trace.enabled {
+               traceGoEnd()
+       }
        mcall(goexit0)
 }
 
@@ -1606,6 +1607,20 @@ func save(pc, sp uintptr) {
 // from a function further up in the call stack than the parent, as g->syscallsp
 // must always point to a valid stack frame. entersyscall below is the normal
 // entry point for syscalls, which obtains the SP and PC from the caller.
+//
+// Syscall tracing:
+// At the start of a syscall we emit traceGoSysCall to capture the stack trace.
+// If the syscall does not block, that is it, we do not emit any other events.
+// If the syscall blocks (that is, P is retaken), retaker emits traceGoSysBlock;
+// when syscall returns we emit traceGoSysExit and when the goroutine starts running
+// (potentially instantly, if exitsyscallfast returns true) we emit traceGoStart.
+// To ensure that traceGoSysExit is emitted strictly after traceGoSysBlock,
+// we remember current value of syscalltick in m (_g_.m.syscalltick = _g_.m.p.syscalltick),
+// whoever emits traceGoSysBlock increments p.syscalltick afterwards;
+// and we wait for the increment before emitting traceGoSysExit.
+// Note that the increment is done even if tracing is not enabled,
+// because tracing can be enabled in the middle of syscall. We don't want the wait to hang.
+//
 //go:nosplit
 func reentersyscall(pc, sp uintptr) {
        _g_ := getg()
@@ -1614,6 +1629,10 @@ func reentersyscall(pc, sp uintptr) {
        // but can have inconsistent g->sched, do not let GC observe it.
        _g_.m.locks++
 
+       if trace.enabled {
+               systemstack(traceGoSysCall)
+       }
+
        // Entersyscall must not call any function that might split/grow the stack.
        // (See details in comment above.)
        // Catch calls that might, by replacing the stack guard with something that
@@ -1638,6 +1657,7 @@ func reentersyscall(pc, sp uintptr) {
                save(pc, sp)
        }
 
+       _g_.m.syscalltick = _g_.m.p.syscalltick
        _g_.m.mcache = nil
        _g_.m.p.m = nil
        atomicstore(&_g_.m.p.status, _Psyscall)
@@ -1670,9 +1690,15 @@ func entersyscall_sysmon() {
 
 func entersyscall_gcwait() {
        _g_ := getg()
+       _p_ := _g_.m.p
 
        lock(&sched.lock)
-       if sched.stopwait > 0 && cas(&_g_.m.p.status, _Psyscall, _Pgcstop) {
+       if sched.stopwait > 0 && cas(&_p_.status, _Psyscall, _Pgcstop) {
+               if trace.enabled {
+                       traceGoSysBlock(_p_)
+                       traceProcStop(_p_)
+               }
+               _p_.syscalltick++
                if sched.stopwait--; sched.stopwait == 0 {
                        notewakeup(&sched.stopnote)
                }
@@ -1688,6 +1714,8 @@ func entersyscallblock(dummy int32) {
        _g_.m.locks++ // see comment in entersyscall
        _g_.throwsplit = true
        _g_.stackguard0 = stackPreempt // see comment in entersyscall
+       _g_.m.syscalltick = _g_.m.p.syscalltick
+       _g_.m.p.syscalltick++
 
        // Leave SP around for GC and traceback.
        pc := getcallerpc(unsafe.Pointer(&dummy))
@@ -1721,6 +1749,10 @@ func entersyscallblock(dummy int32) {
 }
 
 func entersyscallblock_handoff() {
+       if trace.enabled {
+               traceGoSysCall()
+               traceGoSysBlock(getg().m.p)
+       }
        handoffp(releasep())
 }
 
@@ -1738,10 +1770,16 @@ func exitsyscall(dummy int32) {
        }
 
        _g_.waitsince = 0
+       oldp := _g_.m.p
        if exitsyscallfast() {
                if _g_.m.mcache == nil {
                        throw("lost mcache")
                }
+               if trace.enabled {
+                       if oldp != _g_.m.p || _g_.m.syscalltick != _g_.m.p.syscalltick {
+                               systemstack(traceGoStart)
+                       }
+               }
                // There's a cpu for us, so we can run.
                _g_.m.p.syscalltick++
                // We need to cas the status and scan before resuming...
@@ -1762,6 +1800,15 @@ func exitsyscall(dummy int32) {
                return
        }
 
+       if trace.enabled {
+               // Wait till traceGoSysBlock event is emited.
+               // This ensures consistency of the trace (the goroutine is started after it is blocked).
+               for oldp != nil && oldp.syscalltick == _g_.m.syscalltick {
+                       osyield()
+               }
+               systemstack(traceGoSysExit)
+       }
+
        _g_.m.locks--
 
        // Call the scheduler.
@@ -1798,16 +1845,41 @@ func exitsyscallfast() bool {
                // There's a cpu for us, so we can run.
                _g_.m.mcache = _g_.m.p.mcache
                _g_.m.p.m = _g_.m
+               if _g_.m.syscalltick != _g_.m.p.syscalltick {
+                       if trace.enabled {
+                               // The p was retaken and then enter into syscall again (since _g_.m.syscalltick has changed).
+                               // traceGoSysBlock for this syscall was already emitted,
+                               // but here we effectively retake the p from the new syscall running on the same p.
+                               systemstack(func() {
+                                       // Denote blocking of the new syscall.
+                                       traceGoSysBlock(_g_.m.p)
+                                       // Denote completion of the current syscall.
+                                       traceGoSysExit()
+                               })
+                       }
+                       _g_.m.p.syscalltick++
+               }
                return true
        }
 
        // Try to get any other idle P.
+       oldp := _g_.m.p
        _g_.m.mcache = nil
        _g_.m.p = nil
        if sched.pidle != nil {
                var ok bool
                systemstack(func() {
                        ok = exitsyscallfast_pidle()
+                       if ok && trace.enabled {
+                               if oldp != nil {
+                                       // Wait till traceGoSysBlock event is emited.
+                                       // This ensures consistency of the trace (the goroutine is started after it is blocked).
+                                       for oldp.syscalltick == _g_.m.syscalltick {
+                                               osyield()
+                                       }
+                               }
+                               traceGoSysExit()
+                       }
                })
                if ok {
                        return true
@@ -1906,7 +1978,7 @@ func syscall_runtime_AfterFork() {
 
 // Allocate a new g, with a stack big enough for stacksize bytes.
 func malg(stacksize int32) *g {
-       newg := allocg()
+       newg := new(g)
        if stacksize >= 0 {
                stacksize = round2(_StackSystem + stacksize)
                systemstack(func() {
@@ -1987,6 +2059,7 @@ func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr
        newg.sched.g = guintptr(unsafe.Pointer(newg))
        gostartcallfn(&newg.sched, fn)
        newg.gopc = callerpc
+       newg.startpc = fn.fn
        casgstatus(newg, _Gdead, _Grunnable)
 
        if _p_.goidcache == _p_.goidcacheend {
@@ -2002,6 +2075,9 @@ func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr
        if raceenabled {
                newg.racectx = racegostart(callerpc)
        }
+       if trace.enabled {
+               traceGoCreate(newg, newg.startpc)
+       }
        runqput(_p_, newg)
 
        if atomicload(&sched.npidle) != 0 && atomicload(&sched.nmspinning) == 0 && unsafe.Pointer(fn.fn) != unsafe.Pointer(funcPC(main)) { // TODO: fast atomic
@@ -2319,7 +2395,7 @@ func sigprof(pc *uint8, sp *uint8, lr *uint8, gp *g, mp *m) {
                                pc = (*uint8)(unsafe.Pointer(uintptr(funcPC(_ExternalCode) + _PCQuantum)))
                        }
                        stk[0] = uintptr(unsafe.Pointer(pc))
-                       if mp.gcing != 0 || mp.helpgc != 0 {
+                       if mp.preemptoff != "" || mp.helpgc != 0 {
                                stk[1] = funcPC(_GC) + _PCQuantum
                        } else {
                                stk[1] = funcPC(_System) + _PCQuantum
@@ -2378,36 +2454,47 @@ func setcpuprofilerate_m(hz int32) {
 // gcworkbufs are not being modified by either the GC or
 // the write barrier code.
 // Returns list of Ps with local work, they need to be scheduled by the caller.
-func procresize(new int32) *p {
+func procresize(nprocs int32) *p {
        old := gomaxprocs
-       if old < 0 || old > _MaxGomaxprocs || new <= 0 || new > _MaxGomaxprocs {
+       if old < 0 || old > _MaxGomaxprocs || nprocs <= 0 || nprocs > _MaxGomaxprocs {
                throw("procresize: invalid arg")
        }
+       if trace.enabled {
+               traceGomaxprocs(nprocs)
+       }
 
        // initialize new P's
-       for i := int32(0); i < new; i++ {
-               p := allp[i]
-               if p == nil {
-                       p = newP()
-                       p.id = i
-                       p.status = _Pgcstop
-                       atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(p))
-               }
-               if p.mcache == nil {
+       for i := int32(0); i < nprocs; i++ {
+               pp := allp[i]
+               if pp == nil {
+                       pp = new(p)
+                       pp.id = i
+                       pp.status = _Pgcstop
+                       atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp))
+               }
+               if pp.mcache == nil {
                        if old == 0 && i == 0 {
                                if getg().m.mcache == nil {
                                        throw("missing mcache?")
                                }
-                               p.mcache = getg().m.mcache // bootstrap
+                               pp.mcache = getg().m.mcache // bootstrap
                        } else {
-                               p.mcache = allocmcache()
+                               pp.mcache = allocmcache()
                        }
                }
        }
 
        // free unused P's
-       for i := new; i < old; i++ {
+       for i := nprocs; i < old; i++ {
                p := allp[i]
+               if trace.enabled {
+                       if p == getg().m.p {
+                               // moving to p[0], pretend that we were descheduled
+                               // and then scheduled again to keep the trace sane.
+                               traceGoSched()
+                               traceProcStop(p)
+                       }
+               }
                // move all runable goroutines to the global queue
                for p.runqhead != p.runqtail {
                        // pop from tail of local queue
@@ -2424,12 +2511,13 @@ func procresize(new int32) *p {
                freemcache(p.mcache)
                p.mcache = nil
                gfpurge(p)
+               traceProcFree(p)
                p.status = _Pdead
                // can't free P itself because it can be referenced by an M in syscall
        }
 
        _g_ := getg()
-       if _g_.m.p != nil && _g_.m.p.id < new {
+       if _g_.m.p != nil && _g_.m.p.id < nprocs {
                // continue to use the current P
                _g_.m.p.status = _Prunning
        } else {
@@ -2443,9 +2531,12 @@ func procresize(new int32) *p {
                p.m = nil
                p.status = _Pidle
                acquirep(p)
+               if trace.enabled {
+                       traceGoStart()
+               }
        }
        var runnablePs *p
-       for i := new - 1; i >= 0; i-- {
+       for i := nprocs - 1; i >= 0; i-- {
                p := allp[i]
                if _g_.m.p == p {
                        continue
@@ -2460,7 +2551,7 @@ func procresize(new int32) *p {
                }
        }
        var int32p *int32 = &gomaxprocs // make compiler check that gomaxprocs is an int32
-       atomicstore((*uint32)(unsafe.Pointer(int32p)), uint32(new))
+       atomicstore((*uint32)(unsafe.Pointer(int32p)), uint32(nprocs))
        return runnablePs
 }
 
@@ -2483,6 +2574,10 @@ func acquirep(_p_ *p) {
        _g_.m.p = _p_
        _p_.m = _g_.m
        _p_.status = _Prunning
+
+       if trace.enabled {
+               traceProcStart()
+       }
 }
 
 // Disassociate p and the current m.
@@ -2497,6 +2592,9 @@ func releasep() *p {
                print("releasep: m=", _g_.m, " m->p=", _g_.m.p, " p->m=", _p_.m, " m->mcache=", _g_.m.mcache, " p->mcache=", _p_.mcache, " p->status=", _p_.status, "\n")
                throw("releasep: invalid p state")
        }
+       if trace.enabled {
+               traceProcStop(_g_.m.p)
+       }
        _g_.m.p = nil
        _g_.m.mcache = nil
        _p_.m = nil
@@ -2716,7 +2814,12 @@ func retake(now int64) uint32 {
                        // increment nmidle and report deadlock.
                        incidlelocked(-1)
                        if cas(&_p_.status, s, _Pidle) {
+                               if trace.enabled {
+                                       traceGoSysBlock(_p_)
+                                       traceProcStop(_p_)
+                               }
                                n++
+                               _p_.syscalltick++
                                handoffp(_p_)
                        }
                        incidlelocked(1)
@@ -2851,7 +2954,7 @@ func schedtrace(detailed bool) {
                if lockedg != nil {
                        id3 = lockedg.goid
                }
-               print("  M", mp.id, ": p=", id1, " curg=", id2, " mallocing=", mp.mallocing, " throwing=", mp.throwing, " gcing=", mp.gcing, ""+" locks=", mp.locks, " dying=", mp.dying, " helpgc=", mp.helpgc, " spinning=", mp.spinning, " blocked=", getg().m.blocked, " lockedg=", id3, "\n")
+               print("  M", mp.id, ": p=", id1, " curg=", id2, " mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, ""+" locks=", mp.locks, " dying=", mp.dying, " helpgc=", mp.helpgc, " spinning=", mp.spinning, " blocked=", getg().m.blocked, " lockedg=", id3, "\n")
        }
 
        lock(&allglock)
@@ -3163,8 +3266,6 @@ func setMaxThreads(in int) (out int) {
        return
 }
 
-var goexperiment string = "GOEXPERIMENT" // TODO: defined in zaexperiment.h
-
 func haveexperiment(name string) bool {
        x := goexperiment
        for x != "" {
index aa9bc81ac45d87e40788dc0a3a282b7563ccbe77..3b78b01ca31ed1fe2b36faca72ff04da871a60dc 100644 (file)
@@ -7,6 +7,7 @@ package runtime_test
 import (
        "math"
        "runtime"
+       "sync"
        "sync/atomic"
        "syscall"
        "testing"
@@ -415,6 +416,25 @@ func benchmarkCreateGoroutines(b *testing.B, procs int) {
        }
 }
 
+func BenchmarkCreateGoroutinesCapture(b *testing.B) {
+       b.ReportAllocs()
+       for i := 0; i < b.N; i++ {
+               const N = 4
+               var wg sync.WaitGroup
+               wg.Add(N)
+               for i := 0; i < N; i++ {
+                       i := i
+                       go func() {
+                               if i >= N {
+                                       b.Logf("bad") // just to capture b
+                               }
+                               wg.Done()
+                       }()
+               }
+               wg.Wait()
+       }
+}
+
 type Matrix [][]float64
 
 func BenchmarkMatmult(b *testing.B) {
index 2ce4618f3fd831e2ee166647fa09ffbbb17c22e3..0f660038fb4a2aea1d8c56d3aa36697b1366665d 100644 (file)
@@ -10,6 +10,7 @@ import _ "unsafe" // for go:linkname
 
 var ticks struct {
        lock mutex
+       pad  uint32 // ensure 8-byte alignment of val on 386
        val  uint64
 }
 
@@ -46,14 +47,6 @@ func makeStringSlice(n int) []string {
        return make([]string, n)
 }
 
-// TODO: Move to parfor.go when parfor.c becomes parfor.go.
-func parforalloc(nthrmax uint32) *parfor {
-       return &parfor{
-               thr:     &make([]parforthread, nthrmax)[0],
-               nthrmax: nthrmax,
-       }
-}
-
 var envs []string
 var argslice []string
 
index 6056a8dd7ee100529fbde8badbff5f9e9ef55eb5..c056bfcdbfc9b7d28228fe764505208f01f63236 100644 (file)
@@ -95,45 +95,47 @@ func environ() []string {
        return envs
 }
 
+// TODO: These should be locals in testAtomic64, but we don't 8-byte
+// align stack variables on 386.
+var test_z64, test_x64 uint64
+
 func testAtomic64() {
-       var z64, x64 uint64
-
-       z64 = 42
-       x64 = 0
-       prefetcht0(uintptr(unsafe.Pointer(&z64)))
-       prefetcht1(uintptr(unsafe.Pointer(&z64)))
-       prefetcht2(uintptr(unsafe.Pointer(&z64)))
-       prefetchnta(uintptr(unsafe.Pointer(&z64)))
-       if cas64(&z64, x64, 1) {
+       test_z64 = 42
+       test_x64 = 0
+       prefetcht0(uintptr(unsafe.Pointer(&test_z64)))
+       prefetcht1(uintptr(unsafe.Pointer(&test_z64)))
+       prefetcht2(uintptr(unsafe.Pointer(&test_z64)))
+       prefetchnta(uintptr(unsafe.Pointer(&test_z64)))
+       if cas64(&test_z64, test_x64, 1) {
                throw("cas64 failed")
        }
-       if x64 != 0 {
+       if test_x64 != 0 {
                throw("cas64 failed")
        }
-       x64 = 42
-       if !cas64(&z64, x64, 1) {
+       test_x64 = 42
+       if !cas64(&test_z64, test_x64, 1) {
                throw("cas64 failed")
        }
-       if x64 != 42 || z64 != 1 {
+       if test_x64 != 42 || test_z64 != 1 {
                throw("cas64 failed")
        }
-       if atomicload64(&z64) != 1 {
+       if atomicload64(&test_z64) != 1 {
                throw("load64 failed")
        }
-       atomicstore64(&z64, (1<<40)+1)
-       if atomicload64(&z64) != (1<<40)+1 {
+       atomicstore64(&test_z64, (1<<40)+1)
+       if atomicload64(&test_z64) != (1<<40)+1 {
                throw("store64 failed")
        }
-       if xadd64(&z64, (1<<40)+1) != (2<<40)+2 {
+       if xadd64(&test_z64, (1<<40)+1) != (2<<40)+2 {
                throw("xadd64 failed")
        }
-       if atomicload64(&z64) != (2<<40)+2 {
+       if atomicload64(&test_z64) != (2<<40)+2 {
                throw("xadd64 failed")
        }
-       if xchg64(&z64, (3<<40)+3) != (2<<40)+2 {
+       if xchg64(&test_z64, (3<<40)+3) != (2<<40)+2 {
                throw("xchg64 failed")
        }
-       if atomicload64(&z64) != (3<<40)+3 {
+       if atomicload64(&test_z64) != (3<<40)+3 {
                throw("xchg64 failed")
        }
 }
@@ -306,7 +308,10 @@ type dbgVar struct {
 
 // TODO(rsc): Make GC respect debug.invalidptr.
 
-// Holds variables parsed from GODEBUG env var.
+// Holds variables parsed from GODEBUG env var,
+// except for "memprofilerate" since there is an
+// existing int var for that value, which may
+// already have an initial value.
 var debug struct {
        allocfreetrace int32
        efence         int32
@@ -350,9 +355,17 @@ func parsedebugvars() {
                        continue
                }
                key, value := field[:i], field[i+1:]
-               for _, v := range dbgvars {
-                       if v.name == key {
-                               *v.value = int32(atoi(value))
+
+               // Update MemProfileRate directly here since it
+               // is int, not int32, and should only be updated
+               // if specified in GODEBUG.
+               if key == "memprofilerate" {
+                       MemProfileRate = atoi(value)
+               } else {
+                       for _, v := range dbgvars {
+                               if v.name == key {
+                                       *v.value = int32(atoi(value))
+                               }
                        }
                }
        }
index 697ff692348497a2f3d2b1449155fa1bcd8f4181..e38d11a59da08bc6ab46f91de2e2b81a6b64a5d3 100644 (file)
@@ -125,6 +125,7 @@ type gobuf struct {
        ctxt unsafe.Pointer // this has to be a pointer so that gc scans it
        ret  uintreg
        lr   uintptr
+       bp   uintptr // for GOEXPERIMENT=framepointer
 }
 
 // Known to compiler.
@@ -203,6 +204,7 @@ type g struct {
        paniconfault bool // panic (instead of crash) on unexpected fault address
        preemptscan  bool // preempted g does scan for gc
        gcworkdone   bool // debug: cleared at begining of gc work phase cycle, set by gcphasework, tested at end of cycle
+       gcscanvalid  bool // false at start of gc cycle, true if G has not run since last scan
        throwsplit   bool // must not split stack
        raceignore   int8 // ignore race detection events
        m            *m   // for debuggers, but offset not hard-coded
@@ -213,6 +215,7 @@ type g struct {
        sigcode1     uintptr
        sigpc        uintptr
        gopc         uintptr // pc of go statement that created this goroutine
+       startpc      uintptr // pc of goroutine function
        racectx      uintptr
        waiting      *sudog // sudog structures this g is waiting on (that have a valid elem ptr)
 }
@@ -242,7 +245,7 @@ type m struct {
        id            int32
        mallocing     int32
        throwing      int32
-       gcing         int32
+       preemptoff    string // if != "", keep curg running on this m
        locks         int32
        softfloat     int32
        dying         int32
@@ -276,6 +279,8 @@ type m struct {
        traceback     uint8
        waitunlockf   unsafe.Pointer // todo go func(*g, unsafe.pointer) bool
        waitlock      unsafe.Pointer
+       waittraceev   byte
+       syscalltick   uint32
        //#ifdef GOOS_windows
        thread uintptr // thread handle
        // these are here because they are too large to be on the stack
@@ -324,6 +329,8 @@ type p struct {
        gfree    *g
        gfreecnt int32
 
+       tracebuf *traceBuf
+
        pad [64]byte
 }
 
@@ -433,27 +440,6 @@ type lfnode struct {
        pushcnt uintptr
 }
 
-// Parallel for descriptor.
-type parfor struct {
-       body    unsafe.Pointer // go func(*parfor, uint32), executed for each element
-       done    uint32         // number of idle threads
-       nthr    uint32         // total number of threads
-       nthrmax uint32         // maximum number of threads
-       thrseq  uint32         // thread id sequencer
-       cnt     uint32         // iteration space [0, cnt)
-       ctx     unsafe.Pointer // arbitrary user context
-       wait    bool           // if true, wait while all threads finish processing,
-       // otherwise parfor may return while other threads are still working
-       thr *parforthread // array of thread descriptors
-       pad uint32        // to align parforthread.pos for 64-bit atomic operations
-       // stats
-       nsteal     uint64
-       nstealcnt  uint64
-       nprocyield uint64
-       nosyield   uint64
-       nsleep     uint64
-}
-
 // Track memory allocated by code not written in Go during a cgo call,
 // so that the garbage collector can see them.
 type cgomal struct {
@@ -623,15 +609,6 @@ var (
  * so they can be garbage collected if there are no other pointers to nodes.
  */
 
-/*
- * Parallel for over [0, n).
- * body() is executed for each iteration.
- * nthr - total number of worker threads.
- * ctx - arbitrary user context.
- * if wait=true, threads return from parfor() when all work is done;
- * otherwise, threads can return while other threads are still finishing processing.
- */
-
 // for mmap, we only pass the lower 32 bits of file offset to the
 // assembly routine; the higher bits (if required), should be provided
 // by the assembly routine as 0.
index 20dd2995b667b92a582eefd873b487bae362cfe9..34fda16ef890ddb9f475487df44f2003300978bb 100644 (file)
@@ -173,7 +173,7 @@ func selparkcommit(gp *g, sel unsafe.Pointer) bool {
 }
 
 func block() {
-       gopark(nil, nil, "select (no cases)") // forever
+       gopark(nil, nil, "select (no cases)", traceEvGoStop) // forever
 }
 
 // overwrites return pc on stack to signal which case of the select
@@ -363,7 +363,7 @@ loop:
 
        // wait for someone to wake us up
        gp.param = nil
-       gopark(selparkcommit, unsafe.Pointer(sel), "select")
+       gopark(selparkcommit, unsafe.Pointer(sel), "select", traceEvGoBlockSelect)
 
        // someone woke us up
        sellock(sel)
index 35a126476272eba69de6588bb72fa78f7f09c851..34852ea8354d2581c96aa57449c20e7641a72190 100644 (file)
@@ -97,7 +97,7 @@ func semacquire(addr *uint32, profile bool) {
                // Any semrelease after the cansemacquire knows we're waiting
                // (we set nwait above), so go to sleep.
                root.queue(addr, s)
-               goparkunlock(&root.lock, "semacquire")
+               goparkunlock(&root.lock, "semacquire", traceEvGoBlockSync)
                if cansemacquire(addr) {
                        break
                }
@@ -234,7 +234,7 @@ func syncsemacquire(s *syncSema) {
                        s.tail.next = w
                }
                s.tail = w
-               goparkunlock(&s.lock, "semacquire")
+               goparkunlock(&s.lock, "semacquire", traceEvGoBlockCond)
                if t0 != 0 {
                        blockevent(int64(w.releasetime)-t0, 2)
                }
@@ -273,7 +273,7 @@ func syncsemrelease(s *syncSema, n uint32) {
                        s.tail.next = w
                }
                s.tail = w
-               goparkunlock(&s.lock, "semarelease")
+               goparkunlock(&s.lock, "semarelease", traceEvGoBlockCond)
                releaseSudog(w)
        } else {
                unlock(&s.lock)
index 513f27d143345cf401b85ff37956abe33588d2f7..3f89bb173901522788c8642c48eabbca085a9f30 100644 (file)
@@ -46,6 +46,9 @@ var stackpoolmu mutex
 
 var stackfreequeue stack
 
+// Cached value of haveexperiment("framepointer")
+var framepointer_enabled bool
+
 func stackinit() {
        if _StackCacheSize&_PageMask != 0 {
                throw("cache size must be a multiple of page size")
@@ -208,7 +211,7 @@ func stackalloc(n uint32) stack {
                }
                var x gclinkptr
                c := thisg.m.mcache
-               if c == nil || thisg.m.gcing != 0 || thisg.m.helpgc != 0 {
+               if c == nil || thisg.m.preemptoff != "" || thisg.m.helpgc != 0 {
                        // c == nil can happen in the guts of exitsyscall or
                        // procresize. Just get a stack from the global pool.
                        // Also don't touch stackcache during gc
@@ -271,7 +274,7 @@ func stackfree(stk stack) {
                }
                x := gclinkptr(v)
                c := gp.m.mcache
-               if c == nil || gp.m.gcing != 0 || gp.m.helpgc != 0 {
+               if c == nil || gp.m.preemptoff != "" || gp.m.helpgc != 0 {
                        lock(&stackpoolmu)
                        stackpoolfree(x, order)
                        unlock(&stackpoolmu)
@@ -308,6 +311,8 @@ var mapnames = []string{
 // | args from caller |
 // +------------------+ <- frame->argp
 // |  return address  |
+// +------------------+
+// |  caller's BP (*) | (*) if framepointer_enabled && varp < sp
 // +------------------+ <- frame->varp
 // |     locals       |
 // +------------------+
@@ -460,6 +465,19 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
                adjustpointers(unsafe.Pointer(frame.varp-size), &bv, adjinfo, f)
        }
 
+       // Adjust saved base pointer if there is one.
+       if thechar == '6' && frame.argp-frame.varp == 2*regSize {
+               if !framepointer_enabled {
+                       print("runtime: found space for saved base pointer, but no framepointer experiment\n")
+                       print("argp=", hex(frame.argp), " varp=", hex(frame.varp), "\n")
+                       throw("bad frame layout")
+               }
+               if stackDebug >= 3 {
+                       print("      saved bp\n")
+               }
+               adjustpointer(adjinfo, unsafe.Pointer(frame.varp))
+       }
+
        // Adjust arguments.
        if frame.arglen > 0 {
                var bv bitvector
@@ -648,7 +666,8 @@ func newstack() {
 
        // Be conservative about where we preempt.
        // We are interested in preempting user Go code, not runtime code.
-       // If we're holding locks, mallocing, or GCing, don't preempt.
+       // If we're holding locks, mallocing, or preemption is disabled, don't
+       // preempt.
        // This check is very early in newstack so that even the status change
        // from Grunning to Gwaiting and back doesn't happen in this case.
        // That status change by itself can be viewed as a small preemption,
@@ -658,7 +677,7 @@ func newstack() {
        // it needs a lock held by the goroutine), that small preemption turns
        // into a real deadlock.
        if preempt {
-               if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.gcing != 0 || thisg.m.p.status != _Prunning {
+               if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.preemptoff != "" || thisg.m.p.status != _Prunning {
                        // Let the goroutine keep running for now.
                        // gp->preempt is set, so it will be preempted next time.
                        gp.stackguard0 = gp.stack.lo + _StackGuard
@@ -721,7 +740,7 @@ func newstack() {
 
                // Act like goroutine called runtime.Gosched.
                casgstatus(gp, _Gwaiting, _Grunning)
-               gosched_m(gp) // never return
+               gopreempt_m(gp) // never return
        }
 
        // Allocate a bigger segment and move the stack.
index 96f95796243acfd308b8df3bdb8da74f0b25c341..46c3502f7778c6a8b2e93433df89dd6ec439fb38 100644 (file)
@@ -8,7 +8,18 @@ import (
        "unsafe"
 )
 
-func concatstrings(a []string) string {
+// The constant is known to the compiler.
+// There is no fundamental theory behind this number.
+const tmpStringBufSize = 32
+
+type tmpBuf [tmpStringBufSize]byte
+
+// concatstrings implements a Go string concatenation x+y+z+...
+// The operands are passed in the slice a.
+// If buf != nil, the compiler has determined that the result does not
+// escape the calling function, so the string data can be stored in buf
+// if small enough.
+func concatstrings(buf *tmpBuf, a []string) string {
        idx := 0
        l := 0
        count := 0
@@ -27,10 +38,14 @@ func concatstrings(a []string) string {
        if count == 0 {
                return ""
        }
-       if count == 1 {
+
+       // If there is just one string and either it is not on the stack
+       // or our result does not escape the calling frame (buf != nil),
+       // then we can return that string directly.
+       if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
                return a[idx]
        }
-       s, b := rawstring(l)
+       s, b := rawstringtmp(buf, l)
        l = 0
        for _, x := range a {
                copy(b[l:], x)
@@ -39,42 +54,71 @@ func concatstrings(a []string) string {
        return s
 }
 
-func concatstring2(a [2]string) string {
-       return concatstrings(a[:])
+func concatstring2(buf *tmpBuf, a [2]string) string {
+       return concatstrings(buf, a[:])
 }
 
-func concatstring3(a [3]string) string {
-       return concatstrings(a[:])
+func concatstring3(buf *tmpBuf, a [3]string) string {
+       return concatstrings(buf, a[:])
 }
 
-func concatstring4(a [4]string) string {
-       return concatstrings(a[:])
+func concatstring4(buf *tmpBuf, a [4]string) string {
+       return concatstrings(buf, a[:])
 }
 
-func concatstring5(a [5]string) string {
-       return concatstrings(a[:])
+func concatstring5(buf *tmpBuf, a [5]string) string {
+       return concatstrings(buf, a[:])
 }
 
-func slicebytetostring(b []byte) string {
-       if raceenabled && len(b) > 0 {
+// Buf is a fixed-size buffer for the result,
+// it is not nil if the result does not escape.
+func slicebytetostring(buf *tmpBuf, b []byte) string {
+       l := len(b)
+       if l == 0 {
+               // Turns out to be a relatively common case.
+               // Consider that you want to parse out data between parens in "foo()bar",
+               // you find the indices and convert the subslice to string.
+               return ""
+       }
+       if raceenabled && l > 0 {
                racereadrangepc(unsafe.Pointer(&b[0]),
-                       uintptr(len(b)),
+                       uintptr(l),
                        getcallerpc(unsafe.Pointer(&b)),
                        funcPC(slicebytetostring))
        }
-       s, c := rawstring(len(b))
+       s, c := rawstringtmp(buf, l)
        copy(c, b)
        return s
 }
 
+// stringDataOnStack reports whether the string's data is
+// stored on the current goroutine's stack.
+func stringDataOnStack(s string) bool {
+       ptr := uintptr((*stringStruct)(unsafe.Pointer(&s)).str)
+       stk := getg().stack
+       return stk.lo <= ptr && ptr < stk.hi
+}
+
+func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
+       if buf != nil && l <= len(buf) {
+               b = buf[:l]
+               s = slicebytetostringtmp(b)
+       } else {
+               s, b = rawstring(l)
+       }
+       return
+}
+
 func slicebytetostringtmp(b []byte) string {
        // Return a "string" referring to the actual []byte bytes.
        // This is only for use by internal compiler optimizations
        // that know that the string form will be discarded before
        // the calling goroutine could possibly modify the original
        // slice or synchronize with another goroutine.
-       // Today, the only such case is a m[string(k)] lookup where
+       // First such case is a m[string(k)] lookup where
        // m is a string-keyed map and k is a []byte.
+       // Second such case is "<"+string(b)+">" concatenation where b is []byte.
+       // Third such case is string(b)=="foo" comparison where b is []byte.
 
        if raceenabled && len(b) > 0 {
                racereadrangepc(unsafe.Pointer(&b[0]),
@@ -91,6 +135,18 @@ func stringtoslicebyte(s string) []byte {
        return b
 }
 
+func stringtoslicebytetmp(s string) []byte {
+       // Return a slice referring to the actual string bytes.
+       // This is only for use by internal compiler optimizations
+       // that know that the slice won't be mutated.
+       // The only such case today is:
+       // for i, c := range []byte(str)
+
+       str := (*stringStruct)(unsafe.Pointer(&s))
+       ret := slice{array: (*byte)(str.str), len: uint(str.len), cap: uint(str.len)}
+       return *(*[]byte)(unsafe.Pointer(&ret))
+}
+
 func stringtoslicerune(s string) []rune {
        // two passes.
        // unlike slicerunetostring, no race because strings are immutable.
@@ -141,8 +197,15 @@ type stringStruct struct {
        len int
 }
 
-func intstring(v int64) string {
-       s, b := rawstring(4)
+func intstring(buf *[4]byte, v int64) string {
+       var s string
+       var b []byte
+       if buf != nil {
+               b = buf[:]
+               s = slicebytetostringtmp(b)
+       } else {
+               s, b = rawstring(4)
+       }
        n := runetochar(b, rune(v))
        return s[:n]
 }
index 1551ecc82b68a7a30be2b017fa480092a644c25b..dfda950bdd3ba5d41994a0d70266ec2a2e513957 100644 (file)
@@ -158,3 +158,80 @@ func TestGostringnocopy(t *testing.T) {
                t.Errorf("want %d, got %d", max+9, newmax)
        }
 }
+
+func TestCompareTempString(t *testing.T) {
+       s := "foo"
+       b := []byte(s)
+       n := testing.AllocsPerRun(1000, func() {
+               if string(b) != s {
+                       t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
+               }
+               if string(b) == s {
+               } else {
+                       t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
+               }
+       })
+       if n != 0 {
+               t.Fatalf("want 0 allocs, got %v", n)
+       }
+}
+
+func TestStringOnStack(t *testing.T) {
+       s := ""
+       for i := 0; i < 3; i++ {
+               s = "a" + s + "b" + s + "c"
+       }
+
+       if want := "aaabcbabccbaabcbabccc"; s != want {
+               t.Fatalf("want: '%v', got '%v'", want, s)
+       }
+}
+
+func TestIntString(t *testing.T) {
+       // Non-escaping result of intstring.
+       s := ""
+       for i := 0; i < 4; i++ {
+               s += string(i+'0') + string(i+'0'+1)
+       }
+       if want := "01122334"; s != want {
+               t.Fatalf("want '%v', got '%v'", want, s)
+       }
+
+       // Escaping result of intstring.
+       var a [4]string
+       for i := 0; i < 4; i++ {
+               a[i] = string(i + '0')
+       }
+       s = a[0] + a[1] + a[2] + a[3]
+       if want := "0123"; s != want {
+               t.Fatalf("want '%v', got '%v'", want, s)
+       }
+}
+
+func TestIntStringAllocs(t *testing.T) {
+       unknown := '0'
+       n := testing.AllocsPerRun(1000, func() {
+               s1 := string(unknown)
+               s2 := string(unknown + 1)
+               if s1 == s2 {
+                       t.Fatalf("bad")
+               }
+       })
+       if n != 0 {
+               t.Fatalf("want 0 allocs, got %v", n)
+       }
+}
+
+func TestRangeStringCast(t *testing.T) {
+       s := "abc"
+       n := testing.AllocsPerRun(1000, func() {
+               for i, c := range []byte(s) {
+                       if c != s[i] {
+                               t.Fatalf("want '%c' at pos %v, got '%c'", s[i], i, c)
+                       }
+               }
+       })
+       if n != 0 {
+               t.Fatalf("want 0 allocs, got %v", n)
+       }
+}
index d198f02e600edec80e12335cfa9d1e7ae933d879..9aa83ef5874a10ea9db02604970c058d8217b490 100644 (file)
@@ -61,6 +61,11 @@ func badsystemstack() {
 //go:noescape
 func memclr(ptr unsafe.Pointer, n uintptr)
 
+//go:linkname reflect_memclr reflect.memclr
+func reflect_memclr(ptr unsafe.Pointer, n uintptr) {
+       memclr(ptr, n)
+}
+
 // memmove copies n bytes from "from" to "to".
 // in memmove_*.s
 //go:noescape
diff --git a/src/runtime/stubs_android.go b/src/runtime/stubs_android.go
new file mode 100644 (file)
index 0000000..e372377
--- /dev/null
@@ -0,0 +1,10 @@
+package runtime
+
+import "unsafe"
+
+//go:noescape
+func access(name *byte, mode int32) int32
+
+func connect(fd uintptr, addr unsafe.Pointer, len int32) int32
+
+func socket(domain int32, typ int32, prot int32) int32
index db07ed70325d52aed48af49de49546ed902da073..2f2942ae190569225bfb39e42ce15367db52fdef 100644 (file)
@@ -186,9 +186,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
        MOVQ    R10, 40(SP)
        
        // g = m->signal
-       MOVQ    g_m(R10), BP
-       MOVQ    m_gsignal(BP), BP
-       MOVQ    BP, g(BX)
+       MOVQ    g_m(R10), AX
+       MOVQ    m_gsignal(AX), AX
+       MOVQ    AX, g(BX)
        
        MOVQ    DI, 0(SP)
        MOVQ    SI, 8(SP)
index 400c1845be68a185a96135f1f706d504ee766668..eac0319d0b13ca12fc063678ad57eb7e861602a1 100644 (file)
@@ -180,9 +180,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
        MOVQ    R10, 40(SP)
        
        // g = m->signal
-       MOVQ    g_m(R10), BP
-       MOVQ    m_gsignal(BP), BP
-       MOVQ    BP, g(BX)
+       MOVQ    g_m(R10), AX
+       MOVQ    m_gsignal(AX), AX
+       MOVQ    AX, g(BX)
        
        MOVQ    DI, 0(SP)
        MOVQ    SI, 8(SP)
index 1125edd7fd96271687916f0c0147d997c93875ed..aac741b7131f511665a651a5705087f0765b6860 100644 (file)
@@ -216,9 +216,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
        MOVQ    R10, 40(SP)
 
        // g = m->gsignal
-       MOVQ    g_m(R10), BP
-       MOVQ    m_gsignal(BP), BP
-       MOVQ    BP, g(BX)
+       MOVQ    g_m(R10), AX
+       MOVQ    m_gsignal(AX), AX
+       MOVQ    AX, g(BX)
 
        MOVQ    DI, 0(SP)
        MOVQ    SI, 8(SP)
index f7d08cae3c5d28d3873fc1ef745ab057b52a9793..bf0c810ad1fe5f3b2f618854a1d06eb0b0952d94 100644 (file)
@@ -45,6 +45,9 @@
 #define SYS_epoll_wait (SYS_BASE + 252)
 #define SYS_epoll_create1 (SYS_BASE + 357)
 #define SYS_fcntl (SYS_BASE + 55)
+#define SYS_access (SYS_BASE + 33)
+#define SYS_connect (SYS_BASE + 283)
+#define SYS_socket (SYS_BASE + 281)
 
 #define ARM_BASE (SYS_BASE + 0x0f0000)
 
@@ -471,3 +474,29 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
        MOVW    $0xffff0fe0, R0
        B       (R0)
+
+TEXT runtime·access(SB),NOSPLIT,$0
+       MOVW    0(FP), R0
+       MOVW    4(FP), R1
+       MOVW    $SYS_access, R7
+       SWI     $0
+       MOVW    R0, ret+8(FP)
+       RET
+
+TEXT runtime·connect(SB),NOSPLIT,$0
+       MOVW    0(FP), R0
+       MOVW    4(FP), R1
+       MOVW    8(FP), R2
+       MOVW    $SYS_connect, R7
+       SWI     $0
+       MOVW    R0, ret+12(FP)
+       RET
+
+TEXT runtime·socket(SB),NOSPLIT,$0
+       MOVW    0(FP), R0
+       MOVW    4(FP), R1
+       MOVW    8(FP), R2
+       MOVW    $SYS_socket, R7
+       SWI     $0
+       MOVW    R0, ret+12(FP)
+       RET
index e26d6066719beb3133c69480ab8de289a3ca8dd5..83de9111dd76f5fd9a3e005063515ef409386c4d 100644 (file)
@@ -236,9 +236,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
        MOVQ    R10, 40(SP)
 
        // g = m->signal
-       MOVQ    g_m(R10), BP
-       MOVQ    m_gsignal(BP), BP
-       MOVQ    BP, g(BX)
+       MOVQ    g_m(R10), AX
+       MOVQ    m_gsignal(AX), AX
+       MOVQ    AX, g(BX)
 
        MOVQ    DI, 0(SP)
        MOVQ    SI, 8(SP)
index 9dc0fb6857f15fa566dd0fd7dc5565907bfaa082..f1ee4a9ce1ada4dca224c5b8e37d662a01f8a690 100644 (file)
@@ -227,9 +227,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
        MOVQ    R10, 40(SP)
        
        // g = m->signal
-       MOVQ    g_m(R10), BP
-       MOVQ    m_gsignal(BP), BP
-       MOVQ    BP, g(BX)
+       MOVQ    g_m(R10), AX
+       MOVQ    m_gsignal(AX), AX
+       MOVQ    AX, g(BX)
        
        MOVQ    DI, 0(SP)
        MOVQ    SI, 8(SP)
index 5917d7ce04d95f7a920670186b0e6ed68de2d04d..50895ca8ec7d7d743020fafef45732b84319ace9 100644 (file)
@@ -56,7 +56,7 @@ func timeSleep(ns int64) {
        t.arg = getg()
        lock(&timers.lock)
        addtimerLocked(t)
-       goparkunlock(&timers.lock, "sleep")
+       goparkunlock(&timers.lock, "sleep", traceEvGoSleep)
 }
 
 // startTimer adds t to the timer heap.
@@ -200,7 +200,7 @@ func timerproc() {
                if delta < 0 || faketime > 0 {
                        // No timers left - put goroutine to sleep.
                        timers.rescheduling = true
-                       goparkunlock(&timers.lock, "timer goroutine (idle)")
+                       goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock)
                        continue
                }
                // At least one timer pending.  Sleep until then.
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
new file mode 100644 (file)
index 0000000..e7937b3
--- /dev/null
@@ -0,0 +1,807 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go execution tracer.
+// The tracer captures a wide range of execution events like goroutine
+// creation/blocking/unblocking, syscall enter/exit/block, GC-related events,
+// changes of heap size, processor start/stop, etc and writes them to a buffer
+// in a compact form. A precise nanosecond-precision timestamp and a stack
+// trace is captured for most events.
+// See http://golang.org/s/go15trace for more info.
+
+package runtime
+
+import "unsafe"
+
+// Event types in the trace, args are given in square brackets.
+const (
+       traceEvNone           = 0  // unused
+       traceEvBatch          = 1  // start of per-P batch of events [pid, timestamp]
+       traceEvFrequency      = 2  // contains tracer timer frequency [frequency (ticks per second)]
+       traceEvStack          = 3  // stack [stack id, number of PCs, array of PCs]
+       traceEvGomaxprocs     = 4  // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id]
+       traceEvProcStart      = 5  // start of P [timestamp]
+       traceEvProcStop       = 6  // stop of P [timestamp]
+       traceEvGCStart        = 7  // GC start [timestamp, stack id]
+       traceEvGCDone         = 8  // GC done [timestamp]
+       traceEvGCScanStart    = 9  // GC scan start [timestamp]
+       traceEvGCScanDone     = 10 // GC scan done [timestamp]
+       traceEvGCSweepStart   = 11 // GC sweep start [timestamp, stack id]
+       traceEvGCSweepDone    = 12 // GC sweep done [timestamp]
+       traceEvGoCreate       = 13 // goroutine creation [timestamp, new goroutine id, start PC, stack id]
+       traceEvGoStart        = 14 // goroutine starts running [timestamp, goroutine id]
+       traceEvGoEnd          = 15 // goroutine ends [timestamp]
+       traceEvGoStop         = 16 // goroutine stops (like in select{}) [timestamp, stack]
+       traceEvGoSched        = 17 // goroutine calls Gosched [timestamp, stack]
+       traceEvGoPreempt      = 18 // goroutine is preempted [timestamp, stack]
+       traceEvGoSleep        = 19 // goroutine calls Sleep [timestamp, stack]
+       traceEvGoBlock        = 20 // goroutine blocks [timestamp, stack]
+       traceEvGoUnblock      = 21 // goroutine is unblocked [timestamp, goroutine id, stack]
+       traceEvGoBlockSend    = 22 // goroutine blocks on chan send [timestamp, stack]
+       traceEvGoBlockRecv    = 23 // goroutine blocks on chan recv [timestamp, stack]
+       traceEvGoBlockSelect  = 24 // goroutine blocks on select [timestamp, stack]
+       traceEvGoBlockSync    = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
+       traceEvGoBlockCond    = 26 // goroutine blocks on Cond [timestamp, stack]
+       traceEvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
+       traceEvGoSysCall      = 28 // syscall enter [timestamp, stack]
+       traceEvGoSysExit      = 29 // syscall exit [timestamp, goroutine id]
+       traceEvGoSysBlock     = 30 // syscall blocks [timestamp, stack]
+       traceEvGoWaiting      = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
+       traceEvGoInSyscall    = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
+       traceEvHeapAlloc      = 33 // memstats.heap_alloc change [timestamp, heap_alloc]
+       traceEvNextGC         = 34 // memstats.next_gc change [timestamp, next_gc]
+       traceEvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
+       traceEvCount          = 36
+)
+
+const (
+       // Timestamps in trace are cputicks/traceTickDiv.
+       // This makes absolute values of timestamp diffs smaller,
+       // and so they are encoded in less number of bytes.
+       // 64 is somewhat arbitrary (one tick is ~20ns on a 3GHz machine).
+       traceTickDiv = 64
+       // Maximum number of PCs in a single stack trace.
+       // Since events contain only stack id rather than whole stack trace,
+       // we can allow quite large values here.
+       traceStackSize = 128
+       // Identifier of a fake P that is used when we trace without a real P.
+       traceGlobProc = -1
+       // Maximum number of bytes to encode uint64 in base-128.
+       traceBytesPerNumber = 10
+       // Shift of the number of arguments in the first event byte.
+       traceArgCountShift = 6
+)
+
+// trace is global tracing context.
+var trace struct {
+       lock          mutex     // protects the following members
+       lockOwner     *g        // to avoid deadlocks during recursive lock locks
+       enabled       bool      // when set runtime traces events
+       shutdown      bool      // set when we are waiting for trace reader to finish after setting enabled to false
+       headerWritten bool      // whether ReadTrace has emitted trace header
+       footerWritten bool      // whether ReadTrace has emitted trace footer
+       shutdownSema  uint32    // used to wait for ReadTrace completion
+       ticksStart    int64     // cputicks when tracing was started
+       ticksEnd      int64     // cputicks when tracing was stopped
+       timeStart     int64     // nanotime when tracing was started
+       timeEnd       int64     // nanotime when tracing was stopped
+       reading       *traceBuf // buffer currently handed off to user
+       empty         *traceBuf // stack of empty buffers
+       fullHead      *traceBuf // queue of full buffers
+       fullTail      *traceBuf
+       reader        *g              // goroutine that called ReadTrace, or nil
+       stackTab      traceStackTable // maps stack traces to unique ids
+
+       bufLock mutex     // protects buf
+       buf     *traceBuf // global trace buffer, used when running without a p
+}
+
+// traceBufHeader is per-P tracing buffer.
+type traceBufHeader struct {
+       link      *traceBuf               // in trace.empty/full
+       lastTicks uint64                  // when we wrote the last event
+       buf       []byte                  // trace data, always points to traceBuf.arr
+       stk       [traceStackSize]uintptr // scratch buffer for traceback
+}
+
+// traceBuf is per-P tracing buffer.
+type traceBuf struct {
+       traceBufHeader
+       arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf
+}
+
+// StartTrace enables tracing for the current process.
+// While tracing, the data will be buffered and available via ReadTrace.
+// StartTrace returns an error if tracing is already enabled.
+// Most clients should use the runtime/pprof package or the testing package's
+// -test.trace flag instead of calling StartTrace directly.
+func StartTrace() error {
+       // Stop the world, so that we can take a consistent snapshot
+       // of all goroutines at the beginning of the trace.
+       semacquire(&worldsema, false)
+       _g_ := getg()
+       _g_.m.preemptoff = "start tracing"
+       systemstack(stoptheworld)
+
+       // We are in stop-the-world, but syscalls can finish and write to trace concurrently.
+       // Exitsyscall could check trace.enabled long before and then suddenly wake up
+       // and decide to write to trace at a random point in time.
+       // However, such syscall will use the global trace.buf buffer, because we've
+       // acquired all p's by doing stop-the-world. So this protects us from such races.
+       lock(&trace.bufLock)
+
+       if trace.enabled || trace.shutdown {
+               unlock(&trace.bufLock)
+               _g_.m.preemptoff = ""
+               semrelease(&worldsema)
+               systemstack(starttheworld)
+               return errorString("tracing is already enabled")
+       }
+
+       trace.ticksStart = cputicks()
+       trace.timeStart = nanotime()
+       trace.enabled = true
+       trace.headerWritten = false
+       trace.footerWritten = false
+
+       for _, gp := range allgs {
+               status := readgstatus(gp)
+               if status != _Gdead {
+                       traceGoCreate(gp, gp.startpc)
+               }
+               if status == _Gwaiting {
+                       traceEvent(traceEvGoWaiting, false, uint64(gp.goid))
+               }
+               if status == _Gsyscall {
+                       traceEvent(traceEvGoInSyscall, false, uint64(gp.goid))
+               }
+       }
+       traceProcStart()
+       traceGoStart()
+
+       unlock(&trace.bufLock)
+
+       _g_.m.preemptoff = ""
+       semrelease(&worldsema)
+       systemstack(starttheworld)
+       return nil
+}
+
+// StopTrace stops tracing, if it was previously enabled.
+// StopTrace only returns after all the reads for the trace have completed.
+func StopTrace() {
+       // Stop the world so that we can collect the trace buffers from all p's below,
+       // and also to avoid races with traceEvent.
+       semacquire(&worldsema, false)
+       _g_ := getg()
+       _g_.m.preemptoff = "stop tracing"
+       systemstack(stoptheworld)
+
+       // See the comment in StartTrace.
+       lock(&trace.bufLock)
+
+       if !trace.enabled {
+               unlock(&trace.bufLock)
+               _g_.m.preemptoff = ""
+               semrelease(&worldsema)
+               systemstack(starttheworld)
+               return
+       }
+
+       traceGoSched()
+       traceGoStart()
+
+       for _, p := range &allp {
+               if p == nil {
+                       break
+               }
+               buf := p.tracebuf
+               if buf != nil {
+                       traceFullQueue(buf)
+                       p.tracebuf = nil
+               }
+       }
+       if trace.buf != nil && len(trace.buf.buf) != 0 {
+               buf := trace.buf
+               trace.buf = nil
+               traceFullQueue(buf)
+       }
+
+       for {
+               trace.ticksEnd = cputicks()
+               trace.timeEnd = nanotime()
+               // Windows time can tick only every 15ms, wait for at least one tick.
+               if trace.timeEnd != trace.timeStart {
+                       break
+               }
+               osyield()
+       }
+
+       trace.enabled = false
+       trace.shutdown = true
+       trace.stackTab.dump()
+
+       unlock(&trace.bufLock)
+
+       _g_.m.preemptoff = ""
+       semrelease(&worldsema)
+       systemstack(starttheworld)
+
+       // The world is started but we've set trace.shutdown, so new tracing can't start.
+       // Wait for the trace reader to flush pending buffers and stop.
+       semacquire(&trace.shutdownSema, false)
+       if raceenabled {
+               raceacquire(unsafe.Pointer(&trace.shutdownSema))
+       }
+
+       // The lock protects us from races with StartTrace/StopTrace because they do stop-the-world.
+       lock(&trace.lock)
+       for _, p := range &allp {
+               if p == nil {
+                       break
+               }
+               if p.tracebuf != nil {
+                       throw("trace: non-empty trace buffer in proc")
+               }
+       }
+       if trace.buf != nil {
+               throw("trace: non-empty global trace buffer")
+       }
+       if trace.fullHead != nil || trace.fullTail != nil {
+               throw("trace: non-empty full trace buffer")
+       }
+       if trace.reading != nil || trace.reader != nil {
+               throw("trace: reading after shutdown")
+       }
+       for trace.empty != nil {
+               buf := trace.empty
+               trace.empty = buf.link
+               sysFree(unsafe.Pointer(buf), unsafe.Sizeof(*buf), &memstats.other_sys)
+       }
+       trace.shutdown = false
+       unlock(&trace.lock)
+}
+
+// ReadTrace returns the next chunk of binary tracing data, blocking until data
+// is available. If tracing is turned off and all the data accumulated while it
+// was on has been returned, ReadTrace returns nil. The caller must copy the
+// returned data before calling ReadTrace again.
+// ReadTrace must be called from one goroutine at a time.
+func ReadTrace() []byte {
+       // This function may need to lock trace.lock recursively
+       // (goparkunlock -> traceGoPark -> traceEvent -> traceFlush).
+       // To allow this we use trace.lockOwner.
+       // Also this function must not allocate while holding trace.lock:
+       // allocation can call heap allocate, which will try to emit a trace
+       // event while holding heap lock.
+       lock(&trace.lock)
+       trace.lockOwner = getg()
+
+       if trace.reader != nil {
+               // More than one goroutine reads trace. This is bad.
+               // But we rather do not crash the program because of tracing,
+               // because tracing can be enabled at runtime on prod servers.
+               trace.lockOwner = nil
+               unlock(&trace.lock)
+               println("runtime: ReadTrace called from multiple goroutines simultaneously")
+               return nil
+       }
+       // Recycle the old buffer.
+       if buf := trace.reading; buf != nil {
+               buf.link = trace.empty
+               trace.empty = buf
+               trace.reading = nil
+       }
+       // Write trace header.
+       if !trace.headerWritten {
+               trace.headerWritten = true
+               trace.lockOwner = nil
+               unlock(&trace.lock)
+               return []byte("gotrace\x00")
+       }
+       // Wait for new data.
+       if trace.fullHead == nil && !trace.shutdown {
+               trace.reader = getg()
+               goparkunlock(&trace.lock, "trace reader (blocked)", traceEvGoBlock)
+               lock(&trace.lock)
+       }
+       // Write a buffer.
+       if trace.fullHead != nil {
+               buf := traceFullDequeue()
+               trace.reading = buf
+               trace.lockOwner = nil
+               unlock(&trace.lock)
+               return buf.buf
+       }
+       // Write footer with timer frequency.
+       if !trace.footerWritten {
+               trace.footerWritten = true
+               // Use float64 because (trace.ticksEnd - trace.ticksStart) * 1e9 can overflow int64.
+               freq := float64(trace.ticksEnd-trace.ticksStart) * 1e9 / float64(trace.timeEnd-trace.timeStart) / traceTickDiv
+               trace.lockOwner = nil
+               unlock(&trace.lock)
+               var data []byte
+               data = append(data, traceEvFrequency|0<<traceArgCountShift)
+               data = traceAppend(data, uint64(freq))
+               if timers.gp != nil {
+                       data = append(data, traceEvTimerGoroutine|0<<traceArgCountShift)
+                       data = traceAppend(data, uint64(timers.gp.goid))
+               }
+               return data
+       }
+       // Done.
+       if trace.shutdown {
+               trace.lockOwner = nil
+               unlock(&trace.lock)
+               if raceenabled {
+                       // Model synchronization on trace.shutdownSema, which race
+                       // detector does not see. This is required to avoid false
+                       // race reports on writer passed to pprof.StartTrace.
+                       racerelease(unsafe.Pointer(&trace.shutdownSema))
+               }
+               // trace.enabled is already reset, so can call traceable functions.
+               semrelease(&trace.shutdownSema)
+               return nil
+       }
+       // Also bad, but see the comment above.
+       trace.lockOwner = nil
+       unlock(&trace.lock)
+       println("runtime: spurious wakeup of trace reader")
+       return nil
+}
+
+// traceReader returns the trace reader that should be woken up, if any.
+func traceReader() *g {
+       if trace.reader == nil || (trace.fullHead == nil && !trace.shutdown) {
+               return nil
+       }
+       lock(&trace.lock)
+       if trace.reader == nil || (trace.fullHead == nil && !trace.shutdown) {
+               unlock(&trace.lock)
+               return nil
+       }
+       gp := trace.reader
+       trace.reader = nil
+       unlock(&trace.lock)
+       return gp
+}
+
+// traceProcFree frees trace buffer associated with pp.
+func traceProcFree(pp *p) {
+       buf := pp.tracebuf
+       pp.tracebuf = nil
+       if buf == nil {
+               return
+       }
+       lock(&trace.lock)
+       traceFullQueue(buf)
+       unlock(&trace.lock)
+}
+
+// traceFullQueue queues buf into queue of full buffers.
+func traceFullQueue(buf *traceBuf) {
+       buf.link = nil
+       if trace.fullHead == nil {
+               trace.fullHead = buf
+       } else {
+               trace.fullTail.link = buf
+       }
+       trace.fullTail = buf
+}
+
+// traceFullDequeue dequeues from queue of full buffers.
+func traceFullDequeue() *traceBuf {
+       buf := trace.fullHead
+       if buf == nil {
+               return nil
+       }
+       trace.fullHead = buf.link
+       if trace.fullHead == nil {
+               trace.fullTail = nil
+       }
+       buf.link = nil
+       return buf
+}
+
+// traceEvent writes a single event to trace buffer, flushing the buffer if necessary.
+// ev is event type.
+// If stack, write current stack id as the last argument.
+func traceEvent(ev byte, stack bool, args ...uint64) {
+       mp, pid, bufp := traceAcquireBuffer()
+       // Double-check trace.enabled now that we've done m.locks++ and acquired bufLock.
+       // This protects from races between traceEvent and StartTrace/StopTrace.
+
+       // The caller checked that trace.enabled == true, but trace.enabled might have been
+       // turned off between the check and now. Check again. traceLockBuffer did mp.locks++,
+       // StopTrace does stoptheworld, and stoptheworld waits for mp.locks to go back to zero,
+       // so if we see trace.enabled == true now, we know it's true for the rest of the function.
+       // Exitsyscall can run even during stoptheworld. The race with StartTrace/StopTrace
+       // during tracing in exitsyscall is resolved by locking trace.bufLock in traceLockBuffer.
+       if !trace.enabled {
+               traceReleaseBuffer(pid)
+               return
+       }
+       buf := *bufp
+       const maxSize = 2 + 4*traceBytesPerNumber // event type, length, timestamp, stack id and two add params
+       if buf == nil || cap(buf.buf)-len(buf.buf) < maxSize {
+               buf = traceFlush(buf)
+               *bufp = buf
+       }
+
+       ticks := uint64(cputicks()) / traceTickDiv
+       tickDiff := ticks - buf.lastTicks
+       if len(buf.buf) == 0 {
+               data := buf.buf
+               data = append(data, traceEvBatch|1<<traceArgCountShift)
+               data = traceAppend(data, uint64(pid))
+               data = traceAppend(data, ticks)
+               buf.buf = data
+               tickDiff = 0
+       }
+       buf.lastTicks = ticks
+       narg := byte(len(args))
+       if stack {
+               narg++
+       }
+       // We have only 2 bits for number of arguments.
+       // If number is >= 3, then the event type is followed by event length in bytes.
+       if narg > 3 {
+               narg = 3
+       }
+       data := buf.buf
+       data = append(data, ev|narg<<traceArgCountShift)
+       var lenp *byte
+       if narg == 3 {
+               // Reserve the byte for length assuming that length < 128.
+               data = append(data, 0)
+               lenp = &data[len(data)-1]
+       }
+       data = traceAppend(data, tickDiff)
+       for _, a := range args {
+               data = traceAppend(data, a)
+       }
+       if stack {
+               _g_ := getg()
+               gp := mp.curg
+               if gp == nil && ev == traceEvGoSysBlock {
+                       gp = _g_
+               }
+               var nstk int
+               if gp == _g_ {
+                       nstk = callers(1, &buf.stk[0], len(buf.stk))
+               } else if gp != nil {
+                       nstk = gcallers(mp.curg, 1, &buf.stk[0], len(buf.stk))
+               }
+               id := trace.stackTab.put(buf.stk[:nstk])
+               data = traceAppend(data, uint64(id))
+       }
+       evSize := len(data) - len(buf.buf)
+       if evSize > maxSize {
+               throw("invalid length of trace event")
+       }
+       if lenp != nil {
+               // Fill in actual length.
+               *lenp = byte(evSize - 2)
+       }
+       buf.buf = data
+       traceReleaseBuffer(pid)
+}
+
+// traceAcquireBuffer returns trace buffer to use and, if necessary, locks it.
+func traceAcquireBuffer() (mp *m, pid int32, bufp **traceBuf) {
+       mp = acquirem()
+       if p := mp.p; p != nil {
+               return mp, p.id, &p.tracebuf
+       }
+       lock(&trace.bufLock)
+       return mp, traceGlobProc, &trace.buf
+}
+
+// traceReleaseBuffer releases a buffer previously acquired with traceAcquireBuffer.
+func traceReleaseBuffer(pid int32) {
+       if pid == traceGlobProc {
+               unlock(&trace.bufLock)
+       }
+       releasem(getg().m)
+}
+
+// traceFlush puts buf onto stack of full buffers and returns an empty buffer.
+func traceFlush(buf *traceBuf) *traceBuf {
+       owner := trace.lockOwner
+       dolock := owner == nil || owner != getg().m.curg
+       if dolock {
+               lock(&trace.lock)
+       }
+       if buf != nil {
+               if &buf.buf[0] != &buf.arr[0] {
+                       throw("trace buffer overflow")
+               }
+               traceFullQueue(buf)
+       }
+       if trace.empty != nil {
+               buf = trace.empty
+               trace.empty = buf.link
+       } else {
+               buf = (*traceBuf)(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys))
+               if buf == nil {
+                       throw("trace: out of memory")
+               }
+       }
+       buf.link = nil
+       buf.buf = buf.arr[:0]
+       buf.lastTicks = 0
+       if dolock {
+               unlock(&trace.lock)
+       }
+       return buf
+}
+
+// traceAppend appends v to buf in little-endian-base-128 encoding.
+func traceAppend(buf []byte, v uint64) []byte {
+       for ; v >= 0x80; v >>= 7 {
+               buf = append(buf, 0x80|byte(v))
+       }
+       buf = append(buf, byte(v))
+       return buf
+}
+
+// traceStackTable maps stack traces (arrays of PC's) to unique uint32 ids.
+// It is lock-free for reading.
+type traceStackTable struct {
+       lock mutex
+       seq  uint32
+       mem  traceAlloc
+       tab  [1 << 13]*traceStack
+}
+
+// traceStack is a single stack in traceStackTable.
+type traceStack struct {
+       link *traceStack
+       hash uintptr
+       id   uint32
+       n    int
+       stk  [0]uintptr // real type [n]uintptr
+}
+
+// stack returns slice of PCs.
+func (ts *traceStack) stack() []uintptr {
+       return (*[traceStackSize]uintptr)(unsafe.Pointer(&ts.stk))[:ts.n]
+}
+
+// put returns a unique id for the stack trace pcs and caches it in the table,
+// if it sees the trace for the first time.
+func (tab *traceStackTable) put(pcs []uintptr) uint32 {
+       if len(pcs) == 0 {
+               return 0
+       }
+       hash := memhash(unsafe.Pointer(&pcs[0]), uintptr(len(pcs))*unsafe.Sizeof(pcs[0]), 0)
+       // First, search the hashtable w/o the mutex.
+       if id := tab.find(pcs, hash); id != 0 {
+               return id
+       }
+       // Now, double check under the mutex.
+       lock(&tab.lock)
+       if id := tab.find(pcs, hash); id != 0 {
+               unlock(&tab.lock)
+               return id
+       }
+       // Create new record.
+       tab.seq++
+       stk := tab.newStack(len(pcs))
+       stk.hash = hash
+       stk.id = tab.seq
+       stk.n = len(pcs)
+       stkpc := stk.stack()
+       for i, pc := range pcs {
+               stkpc[i] = pc
+       }
+       part := int(hash % uintptr(len(tab.tab)))
+       stk.link = tab.tab[part]
+       atomicstorep(unsafe.Pointer(&tab.tab[part]), unsafe.Pointer(stk))
+       unlock(&tab.lock)
+       return stk.id
+}
+
+// find checks if the stack trace pcs is already present in the table.
+func (tab *traceStackTable) find(pcs []uintptr, hash uintptr) uint32 {
+       part := int(hash % uintptr(len(tab.tab)))
+Search:
+       for stk := tab.tab[part]; stk != nil; stk = stk.link {
+               if stk.hash == hash && stk.n == len(pcs) {
+                       for i, stkpc := range stk.stack() {
+                               if stkpc != pcs[i] {
+                                       continue Search
+                               }
+                       }
+                       return stk.id
+               }
+       }
+       return 0
+}
+
+// newStack allocates a new stack of size n.
+func (tab *traceStackTable) newStack(n int) *traceStack {
+       return (*traceStack)(tab.mem.alloc(unsafe.Sizeof(traceStack{}) + uintptr(n)*ptrSize))
+}
+
+// dump writes all previously cached stacks to trace buffers,
+// releases all memory and resets state.
+func (tab *traceStackTable) dump() {
+       var tmp [(2 + traceStackSize) * traceBytesPerNumber]byte
+       buf := traceFlush(nil)
+       for _, stk := range tab.tab {
+               for ; stk != nil; stk = stk.link {
+                       maxSize := 1 + (3+stk.n)*traceBytesPerNumber
+                       if cap(buf.buf)-len(buf.buf) < maxSize {
+                               buf = traceFlush(buf)
+                       }
+                       // Form the event in the temp buffer, we need to know the actual length.
+                       tmpbuf := tmp[:0]
+                       tmpbuf = traceAppend(tmpbuf, uint64(stk.id))
+                       tmpbuf = traceAppend(tmpbuf, uint64(stk.n))
+                       for _, pc := range stk.stack() {
+                               tmpbuf = traceAppend(tmpbuf, uint64(pc))
+                       }
+                       // Now copy to the buffer.
+                       data := buf.buf
+                       data = append(data, traceEvStack|3<<traceArgCountShift)
+                       data = traceAppend(data, uint64(len(tmpbuf)))
+                       data = append(data, tmpbuf...)
+                       buf.buf = data
+               }
+       }
+
+       lock(&trace.lock)
+       traceFullQueue(buf)
+       unlock(&trace.lock)
+
+       tab.mem.drop()
+       *tab = traceStackTable{}
+}
+
+// traceAlloc is a non-thread-safe region allocator.
+// It holds a linked list of traceAllocBlock.
+type traceAlloc struct {
+       head *traceAllocBlock
+       off  uintptr
+}
+
+// traceAllocBlock is a block in traceAlloc.
+type traceAllocBlock struct {
+       next *traceAllocBlock
+       data [64<<10 - ptrSize]byte
+}
+
+// alloc allocates n-byte block.
+func (a *traceAlloc) alloc(n uintptr) unsafe.Pointer {
+       n = round(n, ptrSize)
+       if a.head == nil || a.off+n > uintptr(len(a.head.data)) {
+               if n > uintptr(len(a.head.data)) {
+                       throw("trace: alloc too large")
+               }
+               block := (*traceAllocBlock)(sysAlloc(unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys))
+               if block == nil {
+                       throw("trace: out of memory")
+               }
+               block.next = a.head
+               a.head = block
+               a.off = 0
+       }
+       p := &a.head.data[a.off]
+       a.off += n
+       return unsafe.Pointer(p)
+}
+
+// drop frees all previously allocated memory and resets the allocator.
+func (a *traceAlloc) drop() {
+       for a.head != nil {
+               block := a.head
+               a.head = block.next
+               sysFree(unsafe.Pointer(block), unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys)
+       }
+}
+
+// The following functions write specific events to trace.
+
+func traceGomaxprocs(procs int32) {
+       traceEvent(traceEvGomaxprocs, true, uint64(procs))
+}
+
+func traceProcStart() {
+       traceEvent(traceEvProcStart, false)
+}
+
+func traceProcStop(pp *p) {
+       // Sysmon and stoptheworld can stop Ps blocked in syscalls,
+       // to handle this we temporary employ the P.
+       mp := acquirem()
+       oldp := mp.p
+       mp.p = pp
+       traceEvent(traceEvProcStop, false)
+       mp.p = oldp
+       releasem(mp)
+}
+
+func traceGCStart() {
+       traceEvent(traceEvGCStart, true)
+}
+
+func traceGCDone() {
+       traceEvent(traceEvGCDone, false)
+}
+
+func traceGCScanStart() {
+       traceEvent(traceEvGCScanStart, false)
+}
+
+func traceGCScanDone() {
+       traceEvent(traceEvGCScanDone, false)
+}
+
+func traceGCSweepStart() {
+       traceEvent(traceEvGCSweepStart, true)
+}
+
+func traceGCSweepDone() {
+       traceEvent(traceEvGCSweepDone, false)
+}
+
+func traceGoCreate(newg *g, pc uintptr) {
+       traceEvent(traceEvGoCreate, true, uint64(newg.goid), uint64(pc))
+}
+
+func traceGoStart() {
+       traceEvent(traceEvGoStart, false, uint64(getg().m.curg.goid))
+}
+
+func traceGoEnd() {
+       traceEvent(traceEvGoEnd, false)
+}
+
+func traceGoSched() {
+       traceEvent(traceEvGoSched, true)
+}
+
+func traceGoPreempt() {
+       traceEvent(traceEvGoPreempt, true)
+}
+
+func traceGoStop() {
+       traceEvent(traceEvGoStop, true)
+}
+
+func traceGoPark(traceEv byte, gp *g) {
+       traceEvent(traceEv, true)
+}
+
+func traceGoUnpark(gp *g) {
+       traceEvent(traceEvGoUnblock, true, uint64(gp.goid))
+}
+
+func traceGoSysCall() {
+       traceEvent(traceEvGoSysCall, true)
+}
+
+func traceGoSysExit() {
+       traceEvent(traceEvGoSysExit, false, uint64(getg().m.curg.goid))
+}
+
+func traceGoSysBlock(pp *p) {
+       // Sysmon and stoptheworld can declare syscalls running on remote Ps as blocked,
+       // to handle this we temporary employ the P.
+       mp := acquirem()
+       oldp := mp.p
+       mp.p = pp
+       traceEvent(traceEvGoSysBlock, true)
+       mp.p = oldp
+       releasem(mp)
+}
+
+func traceHeapAlloc() {
+       traceEvent(traceEvHeapAlloc, false, memstats.heap_alloc)
+}
+
+func traceNextGC() {
+       traceEvent(traceEvNextGC, false, memstats.next_gc)
+}
index 499256f42dab10a4e81d03e37462f4c761898272..6c87d7e2e4581a4d26366afd1aeef2da8dfeb0a5 100644 (file)
@@ -232,6 +232,12 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
                        frame.varp -= regSize
                }
 
+               // If framepointer_enabled and there's a frame, then
+               // there's a saved bp here.
+               if framepointer_enabled && GOARCH == "amd64" && frame.varp > frame.sp {
+                       frame.varp -= regSize
+               }
+
                // Derive size of arguments.
                // Most functions have a fixed-size argument block,
                // so we can use metadata about the function f.
index 6e7c1f0847f9435049f372e68876d176cab8994f..64d7c300566d0101fc8c7b8ea21c3bcca568c1af 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Runtime _type representation.
+// Runtime type representation.
 
 package runtime
 
@@ -17,13 +17,13 @@ type _type struct {
        fieldalign uint8
        kind       uint8
        alg        *typeAlg
-       // gc stores _type info required for garbage collector.
+       // gc stores type info required for garbage collector.
        // If (kind&KindGCProg)==0, then gc[0] points at sparse GC bitmap
        // (no indirection), 4 bits per word.
        // If (kind&KindGCProg)!=0, then gc[1] points to a compiler-generated
        // read-only GC program; and gc[0] points to BSS space for sparse GC bitmap.
-       // For huge _types (>maxGCMask), runtime unrolls the program directly into
-       // GC bitmap and gc[0] is not used. For moderately-sized _types, runtime
+       // For huge types (>maxGCMask), runtime unrolls the program directly into
+       // GC bitmap and gc[0] is not used. For moderately-sized types, runtime
        // unrolls the program into gc[0] space on first use. The first byte of gc[0]
        // (gc[0][0]) contains 'unroll' flag saying whether the program is already
        // unrolled into gc[0] or not.
@@ -31,7 +31,7 @@ type _type struct {
        _string *string
        x       *uncommontype
        ptrto   *_type
-       zero    *byte // ptr to the zero value for this _type
+       zero    *byte // ptr to the zero value for this type
 }
 
 type method struct {
@@ -64,8 +64,8 @@ type maptype struct {
        typ           _type
        key           *_type
        elem          *_type
-       bucket        *_type // internal _type representing a hash bucket
-       hmap          *_type // internal _type representing a hmap
+       bucket        *_type // internal type representing a hash bucket
+       hmap          *_type // internal type representing a hmap
        keysize       uint8  // size of key slot
        indirectkey   bool   // store ptr to key instead of key itself
        valuesize     uint8  // size of value slot
index 27d384983efb3626f62a4fd9ad60beebb106ef83..f362f185a9b2ae64b0cc4414084e91902e22b103 100644 (file)
@@ -78,6 +78,7 @@ func hashStrRev(sep string) (uint32, uint32) {
 }
 
 // Count counts the number of non-overlapping instances of sep in s.
+// If sep is an empty string, Count returns 1 + the number of Unicode code points in s.
 func Count(s, sep string) int {
        n := 0
        // special cases
index fa1b3712067fb122905c73c881edb04d73400d02..ec7487b4b9a4f1075c59a04453822c1b44b72a76 100644 (file)
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
 #include "textflag.h"
 #include "funcdata.h"
 
 
 TEXT   Â·Syscall(SB),NOSPLIT,$0-28
        CALL    runtime·entersyscall(SB)
-       MOVL    4(SP), AX       // syscall entry
-       MOVL    8(SP), BX
-       MOVL    12(SP), CX
-       MOVL    16(SP), DX
+       MOVL    trap+0(FP), AX  // syscall entry
+       MOVL    a1+4(FP), BX
+       MOVL    a2+8(FP), CX
+       MOVL    a3+12(FP), DX
        MOVL    $0, SI
        MOVL    $0,  DI
        CALL    *runtime·_vdso(SB)
        CMPL    AX, $0xfffff001
        JLS     ok
-       MOVL    $-1, 20(SP)     // r1
-       MOVL    $0, 24(SP)      // r2
+       MOVL    $-1, r1+16(FP)
+       MOVL    $0, r2+20(FP)
        NEGL    AX
-       MOVL    AX, 28(SP)  // errno
+       MOVL    AX, err+24(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 ok:
-       MOVL    AX, 20(SP)      // r1
-       MOVL    DX, 24(SP)      // r2
-       MOVL    $0, 28(SP)      // errno
+       MOVL    AX, r1+16(FP)
+       MOVL    DX, r2+20(FP)
+       MOVL    $0, err+24(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 
 // func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
 TEXT   Â·Syscall6(SB),NOSPLIT,$0-40
        CALL    runtime·entersyscall(SB)
-       MOVL    4(SP), AX       // syscall entry
-       MOVL    8(SP), BX
-       MOVL    12(SP), CX
-       MOVL    16(SP), DX
-       MOVL    20(SP), SI
-       MOVL    24(SP), DI
-       MOVL    28(SP), BP
+       MOVL    trap+0(FP), AX  // syscall entry
+       MOVL    a1+4(FP), BX
+       MOVL    a2+8(FP), CX
+       MOVL    a3+12(FP), DX
+       MOVL    a4+16(FP), SI
+       MOVL    a5+20(FP), DI
+       MOVL    a6+24(FP), BP
        CALL    *runtime·_vdso(SB)
        CMPL    AX, $0xfffff001
        JLS     ok6
-       MOVL    $-1, 32(SP)     // r1
-       MOVL    $0, 36(SP)      // r2
+       MOVL    $-1, r1+28(FP)
+       MOVL    $0, r2+32(FP)
        NEGL    AX
-       MOVL    AX, 40(SP)  // errno
+       MOVL    AX, err+36(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 ok6:
-       MOVL    AX, 32(SP)      // r1
-       MOVL    DX, 36(SP)      // r2
-       MOVL    $0, 40(SP)      // errno
+       MOVL    AX, r1+28(FP)
+       MOVL    DX, r2+32(FP)
+       MOVL    $0, err+36(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 
 // func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
 TEXT Â·RawSyscall(SB),NOSPLIT,$0-28
-       MOVL    4(SP), AX       // syscall entry
-       MOVL    8(SP), BX
-       MOVL    12(SP), CX
-       MOVL    16(SP), DX
+       MOVL    trap+0(FP), AX  // syscall entry
+       MOVL    a1+4(FP), BX
+       MOVL    a2+8(FP), CX
+       MOVL    a3+12(FP), DX
        MOVL    $0, SI
        MOVL    $0,  DI
        CALL    *runtime·_vdso(SB)
        CMPL    AX, $0xfffff001
        JLS     ok1
-       MOVL    $-1, 20(SP)     // r1
-       MOVL    $0, 24(SP)      // r2
+       MOVL    $-1, r1+16(FP)
+       MOVL    $0, r2+20(FP)
        NEGL    AX
-       MOVL    AX, 28(SP)  // errno
+       MOVL    AX, err+24(FP)
        RET
 ok1:
-       MOVL    AX, 20(SP)      // r1
-       MOVL    DX, 24(SP)      // r2
-       MOVL    $0, 28(SP)      // errno
+       MOVL    AX, r1+16(FP)
+       MOVL    DX, r2+20(FP)
+       MOVL    $0, err+24(FP)
        RET
 
 // func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
 TEXT   Â·RawSyscall6(SB),NOSPLIT,$0-40
-       MOVL    4(SP), AX       // syscall entry
-       MOVL    8(SP), BX
-       MOVL    12(SP), CX
-       MOVL    16(SP), DX
-       MOVL    20(SP), SI
-       MOVL    24(SP), DI
-       MOVL    28(SP), BP
+       MOVL    trap+0(FP), AX  // syscall entry
+       MOVL    a1+4(FP), BX
+       MOVL    a2+8(FP), CX
+       MOVL    a3+12(FP), DX
+       MOVL    a4+16(FP), SI
+       MOVL    a5+20(FP), DI
+       MOVL    a6+24(FP), BP
        CALL    *runtime·_vdso(SB)
        CMPL    AX, $0xfffff001
        JLS     ok2
-       MOVL    $-1, 32(SP)     // r1
-       MOVL    $0, 36(SP)      // r2
+       MOVL    $-1, r1+28(FP)
+       MOVL    $0, r2+32(FP)
        NEGL    AX
-       MOVL    AX, 40(SP)  // errno
+       MOVL    AX, err+36(FP)
        RET
 ok2:
-       MOVL    AX, 32(SP)      // r1
-       MOVL    DX, 36(SP)      // r2
-       MOVL    $0, 40(SP)      // errno
+       MOVL    AX, r1+28(FP)
+       MOVL    DX, r2+32(FP)
+       MOVL    $0, err+36(FP)
        RET
 
 #define SYS_SOCKETCALL 102     /* from zsysnum_linux_386.go */
 
-// func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+// func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err int)
 // Kernel interface gets call sub-number and pointer to a0.
 TEXT Â·socketcall(SB),NOSPLIT,$0-36
        CALL    runtime·entersyscall(SB)
        MOVL    $SYS_SOCKETCALL, AX     // syscall entry
-       MOVL    4(SP), BX       // socket call number
-       LEAL            8(SP), CX       // pointer to call arguments
+       MOVL    call+0(FP), BX  // socket call number
+       LEAL            a0+4(FP), CX    // pointer to call arguments
        MOVL    $0, DX
        MOVL    $0, SI
        MOVL    $0,  DI
        CALL    *runtime·_vdso(SB)
        CMPL    AX, $0xfffff001
        JLS     oksock
-       MOVL    $-1, 32(SP)     // n
+       MOVL    $-1, n+28(FP)
        NEGL    AX
-       MOVL    AX, 36(SP)  // errno
+       MOVL    AX, err+32(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 oksock:
-       MOVL    AX, 32(SP)      // n
-       MOVL    $0, 36(SP)      // errno
+       MOVL    AX, n+28(FP)
+       MOVL    $0, err+32(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 
-// func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+// func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err int)
 // Kernel interface gets call sub-number and pointer to a0.
 TEXT Â·rawsocketcall(SB),NOSPLIT,$0-36
        MOVL    $SYS_SOCKETCALL, AX     // syscall entry
-       MOVL    4(SP), BX       // socket call number
-       LEAL            8(SP), CX       // pointer to call arguments
+       MOVL    call+0(FP), BX  // socket call number
+       LEAL            a0+4(FP), CX    // pointer to call arguments
        MOVL    $0, DX
        MOVL    $0, SI
        MOVL    $0,  DI
        CALL    *runtime·_vdso(SB)
        CMPL    AX, $0xfffff001
        JLS     oksock1
-       MOVL    $-1, 32(SP)     // n
+       MOVL    $-1, n+28(FP)
        NEGL    AX
-       MOVL    AX, 36(SP)  // errno
+       MOVL    AX, err+32(FP)
        RET
 oksock1:
-       MOVL    AX, 32(SP)      // n
-       MOVL    $0, 36(SP)      // errno
+       MOVL    AX, n+28(FP)
+       MOVL    $0, err+32(FP)
        RET
 
 #define SYS__LLSEEK 140        /* from zsysnum_linux_386.go */
-// func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
+// func Seek(fd int, offset int64, whence int) (newoffset int64, err int)
 // Implemented in assembly to avoid allocation when
 // taking the address of the return value newoffset.
 // Underlying system call is
@@ -166,22 +163,22 @@ oksock1:
 TEXT Â·seek(SB),NOSPLIT,$0-28
        CALL    runtime·entersyscall(SB)
        MOVL    $SYS__LLSEEK, AX        // syscall entry
-       MOVL    4(SP), BX       // fd
-       MOVL    12(SP), CX      // offset-high
-       MOVL    8(SP), DX       // offset-low
-       LEAL    20(SP), SI      // result pointer
-       MOVL    16(SP),  DI     // whence
+       MOVL    fd+0(FP), BX
+       MOVL    offset_hi+8(FP), CX
+       MOVL    offset_lo+4(FP), DX
+       LEAL    newoffset_lo+16(FP), SI // result pointer
+       MOVL    whence+12(FP),  DI
        CALL    *runtime·_vdso(SB)
        CMPL    AX, $0xfffff001
        JLS     okseek
-       MOVL    $-1, 20(SP)     // newoffset low
-       MOVL    $-1, 24(SP)     // newoffset high
+       MOVL    $-1, newoffset_lo+16(FP)
+       MOVL    $-1, newoffset_hi+20(FP)
        NEGL    AX
-       MOVL    AX, 28(SP)  // errno
+       MOVL    AX, err+24(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 okseek:
        // system call filled in newoffset already
-       MOVL    $0, 28(SP)      // errno
+       MOVL    $0, err+24(FP)
        CALL    runtime·exitsyscall(SB)
        RET
index b3ce2165d6fe187d6b65ca56db4a8980f9a8603d..6634875f6a1927fb48d6ec449dc3079eccc92794 100644 (file)
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
 #include "textflag.h"
 #include "funcdata.h"
 
 
 TEXT   Â·Syscall(SB),NOSPLIT,$0-56
        CALL    runtime·entersyscall(SB)
-       MOVQ    16(SP), DI
-       MOVQ    24(SP), SI
-       MOVQ    32(SP), DX
+       MOVQ    a1+8(FP), DI
+       MOVQ    a2+16(FP), SI
+       MOVQ    a3+24(FP), DX
        MOVQ    $0, R10
        MOVQ    $0, R8
        MOVQ    $0, R9
-       MOVQ    8(SP), AX       // syscall entry
+       MOVQ    trap+0(FP), AX  // syscall entry
        SYSCALL
        CMPQ    AX, $0xfffffffffffff001
        JLS     ok
-       MOVQ    $-1, 40(SP)     // r1
-       MOVQ    $0, 48(SP)      // r2
+       MOVQ    $-1, r1+32(FP)
+       MOVQ    $0, r2+40(FP)
        NEGQ    AX
-       MOVQ    AX, 56(SP)  // errno
+       MOVQ    AX, err+48(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 ok:
-       MOVQ    AX, 40(SP)      // r1
-       MOVQ    DX, 48(SP)      // r2
-       MOVQ    $0, 56(SP)      // errno
+       MOVQ    AX, r1+32(FP)
+       MOVQ    DX, r2+40(FP)
+       MOVQ    $0, err+48(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 
+// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
 TEXT Â·Syscall6(SB),NOSPLIT,$0-80
        CALL    runtime·entersyscall(SB)
-       MOVQ    16(SP), DI
-       MOVQ    24(SP), SI
-       MOVQ    32(SP), DX
-       MOVQ    40(SP), R10
-       MOVQ    48(SP), R8
-       MOVQ    56(SP), R9
-       MOVQ    8(SP), AX       // syscall entry
+       MOVQ    a1+8(FP), DI
+       MOVQ    a2+16(FP), SI
+       MOVQ    a3+24(FP), DX
+       MOVQ    a4+32(FP), R10
+       MOVQ    a5+40(FP), R8
+       MOVQ    a6+48(FP), R9
+       MOVQ    trap+0(FP), AX  // syscall entry
        SYSCALL
        CMPQ    AX, $0xfffffffffffff001
        JLS     ok6
-       MOVQ    $-1, 64(SP)     // r1
-       MOVQ    $0, 72(SP)      // r2
+       MOVQ    $-1, r1+56(FP)
+       MOVQ    $0, r2+64(FP)
        NEGQ    AX
-       MOVQ    AX, 80(SP)  // errno
+       MOVQ    AX, err+72(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 ok6:
-       MOVQ    AX, 64(SP)      // r1
-       MOVQ    DX, 72(SP)      // r2
-       MOVQ    $0, 80(SP)      // errno
+       MOVQ    AX, r1+56(FP)
+       MOVQ    DX, r2+64(FP)
+       MOVQ    $0, err+72(FP)
        CALL    runtime·exitsyscall(SB)
        RET
 
+// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
 TEXT Â·RawSyscall(SB),NOSPLIT,$0-56
-       MOVQ    16(SP), DI
-       MOVQ    24(SP), SI
-       MOVQ    32(SP), DX
+       MOVQ    a1+8(FP), DI
+       MOVQ    a2+16(FP), SI
+       MOVQ    a3+24(FP), DX
        MOVQ    $0, R10
        MOVQ    $0, R8
        MOVQ    $0, R9
-       MOVQ    8(SP), AX       // syscall entry
+       MOVQ    trap+0(FP), AX  // syscall entry
        SYSCALL
        CMPQ    AX, $0xfffffffffffff001
        JLS     ok1
-       MOVQ    $-1, 40(SP)     // r1
-       MOVQ    $0, 48(SP)      // r2
+       MOVQ    $-1, r1+32(FP)
+       MOVQ    $0, r2+40(FP)
        NEGQ    AX
-       MOVQ    AX, 56(SP)  // errno
+       MOVQ    AX, err+48(FP)
        RET
 ok1:
-       MOVQ    AX, 40(SP)      // r1
-       MOVQ    DX, 48(SP)      // r2
-       MOVQ    $0, 56(SP)      // errno
+       MOVQ    AX, r1+32(FP)
+       MOVQ    DX, r2+40(FP)
+       MOVQ    $0, err+48(FP)
        RET
 
+// func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
 TEXT Â·RawSyscall6(SB),NOSPLIT,$0-80
-       MOVQ    16(SP), DI
-       MOVQ    24(SP), SI
-       MOVQ    32(SP), DX
-       MOVQ    40(SP), R10
-       MOVQ    48(SP), R8
-       MOVQ    56(SP), R9
-       MOVQ    8(SP), AX       // syscall entry
+       MOVQ    a1+8(FP), DI
+       MOVQ    a2+16(FP), SI
+       MOVQ    a3+24(FP), DX
+       MOVQ    a4+32(FP), R10
+       MOVQ    a5+40(FP), R8
+       MOVQ    a6+48(FP), R9
+       MOVQ    trap+0(FP), AX  // syscall entry
        SYSCALL
        CMPQ    AX, $0xfffffffffffff001
        JLS     ok2
-       MOVQ    $-1, 64(SP)     // r1
-       MOVQ    $0, 72(SP)      // r2
+       MOVQ    $-1, r1+56(FP)
+       MOVQ    $0, r2+64(FP)
        NEGQ    AX
-       MOVQ    AX, 80(SP)  // errno
+       MOVQ    AX, err+72(FP)
        RET
 ok2:
-       MOVQ    AX, 64(SP)      // r1
-       MOVQ    DX, 72(SP)      // r2
-       MOVQ    $0, 80(SP)      // errno
+       MOVQ    AX, r1+56(FP)
+       MOVQ    DX, r2+64(FP)
+       MOVQ    $0, err+72(FP)
        RET
 
+// func gettimeofday(tv *Timeval) (err uintptr)
 TEXT Â·gettimeofday(SB),NOSPLIT,$0-16
-       MOVQ    8(SP), DI
+       MOVQ    tv+0(FP), DI
        MOVQ    $0, SI
        MOVQ    runtime·__vdso_gettimeofday_sym(SB), AX
        CALL    AX
@@ -120,8 +121,8 @@ TEXT Â·gettimeofday(SB),NOSPLIT,$0-16
        CMPQ    AX, $0xfffffffffffff001
        JLS     ok7
        NEGQ    AX
-       MOVQ    AX, 16(SP)  // errno
+       MOVQ    AX, err+8(FP)
        RET
 ok7:
-       MOVQ    $0, 16(SP)  // errno
+       MOVQ    $0, err+8(FP)
        RET
index 909c65f788b78f5b197b57bfc1b952f9abf4b09d..edcaaa091aba27f19513a2744f037f9dd2d74c03 100644 (file)
@@ -118,6 +118,14 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
                        }
                        v.Index(i).Set(elem)
                }
+       case reflect.Array:
+               for i := 0; i < v.Len(); i++ {
+                       elem, ok := Value(concrete.Elem(), rand)
+                       if !ok {
+                               return reflect.Value{}, false
+                       }
+                       v.Index(i).Set(elem)
+               }
        case reflect.String:
                numChars := rand.Intn(complexSize)
                codePoints := make([]rune, numChars)
index e925ba67507120d50301067b330fdc4c5fb4016b..ca340fe76d6d98dfad071450e6bc5e7af5e90d5b 100644 (file)
@@ -144,6 +144,12 @@ type TestIntptrAlias *int
 
 func fIntptrAlias(a TestIntptrAlias) TestIntptrAlias { return a }
 
+func fArray(a [4]byte) [4]byte { return a }
+
+type TestArrayAlias [4]byte
+
+func fArrayAlias(a TestArrayAlias) TestArrayAlias { return a }
+
 func reportError(property string, err error, t *testing.T) {
        if err != nil {
                t.Errorf("%s: %s", property, err)
@@ -195,6 +201,8 @@ func TestCheckEqual(t *testing.T) {
        reportError("fUintptrAlias", CheckEqual(fUintptrAlias, fUintptrAlias, nil), t)
        reportError("fIntptr", CheckEqual(fIntptr, fIntptr, nil), t)
        reportError("fIntptrAlias", CheckEqual(fIntptrAlias, fIntptrAlias, nil), t)
+       reportError("fArray", CheckEqual(fArray, fArray, nil), t)
+       reportError("fArrayAlais", CheckEqual(fArrayAlias, fArrayAlias, nil), t)
 }
 
 // This tests that ArbitraryValue is working by checking that all the arbitrary
index e54a3b8ce4dfca3a0e01dc2d35f95d269d035141..966b5466b711faaf7d186a45ff167394fd7b8ff2 100644 (file)
@@ -175,6 +175,7 @@ var (
        cpuProfile       = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
        blockProfile     = flag.String("test.blockprofile", "", "write a goroutine blocking profile to the named file after execution")
        blockProfileRate = flag.Int("test.blockprofilerate", 1, "if >= 0, calls runtime.SetBlockProfileRate()")
+       trace            = flag.String("test.trace", "", "write an execution trace to the named file after execution")
        timeout          = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
        cpuListStr       = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
        parallel         = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
@@ -600,6 +601,19 @@ func before() {
                }
                // Could save f so after can call f.Close; not worth the effort.
        }
+       if *trace != "" {
+               f, err := os.Create(toOutputDir(*trace))
+               if err != nil {
+                       fmt.Fprintf(os.Stderr, "testing: %s", err)
+                       return
+               }
+               if err := pprof.StartTrace(f); err != nil {
+                       fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s", err)
+                       f.Close()
+                       return
+               }
+               // Could save f so after can call f.Close; not worth the effort.
+       }
        if *blockProfile != "" && *blockProfileRate >= 0 {
                runtime.SetBlockProfileRate(*blockProfileRate)
        }
@@ -614,6 +628,9 @@ func after() {
        if *cpuProfile != "" {
                pprof.StopCPUProfile() // flushes profile to disk
        }
+       if *trace != "" {
+               pprof.StopTrace() // flushes trace to disk
+       }
        if *memProfile != "" {
                f, err := os.Create(toOutputDir(*memProfile))
                if err != nil {
index 79499b2955f633b50d6da71c1cc658168a71d5fd..752792f41bf5bc6dfcd05f10c3e8ac588ab939dc 100644 (file)
@@ -24,17 +24,19 @@ type ArbitraryType int
 // arbitrary memory. It should be used with extreme care.
 type Pointer *ArbitraryType
 
-// Sizeof returns the size in bytes occupied by the value v.  The size is that of the
-// "top level" of the value only.  For instance, if v is a slice, it returns the size of
-// the slice descriptor, not the size of the memory referenced by the slice.
-func Sizeof(v ArbitraryType) uintptr
+// Sizeof takes an expression x of any type and returns the size in bytes
+// of a hypothetical variable v as if v was declared via var v = x.
+// The size does not include any memory possibly referenced by x.
+// For instance, if x is a slice,  Sizeof returns the size of the slice
+// descriptor, not the size of the memory referenced by the slice.
+func Sizeof(x ArbitraryType) uintptr
 
-// Offsetof returns the offset within the struct of the field represented by v,
+// Offsetof returns the offset within the struct of the field represented by x,
 // which must be of the form structValue.field.  In other words, it returns the
 // number of bytes between the start of the struct and the start of the field.
-func Offsetof(v ArbitraryType) uintptr
+func Offsetof(x ArbitraryType) uintptr
 
-// Alignof returns the alignment of the value v.  It is the maximum value m such
-// that the address of a variable with the type of v will always be zero mod m.
-// If v is of the form structValue.field, it returns the alignment of field f within struct object obj.
-func Alignof(v ArbitraryType) uintptr
+// Alignof takes an expression x of any type and returns the alignment
+// of a hypothetical variable v as if v was declared via var v = x.
+// It is the largest value m such that the address of v is zero mod m.
+func Alignof(x ArbitraryType) uintptr
diff --git a/test/closure1.go b/test/closure1.go
new file mode 100644 (file)
index 0000000..5869982
--- /dev/null
@@ -0,0 +1,19 @@
+// run
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       x := 0
+       func() {
+               x = 1
+       }()
+       func() {
+               if x != 1 {
+                       panic("x != 1")
+               }
+       }()
+}
\ No newline at end of file
diff --git a/test/closure2.go b/test/closure2.go
new file mode 100644 (file)
index 0000000..4d61b45
--- /dev/null
@@ -0,0 +1,118 @@
+// run
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that these do not use "by value" capturing,
+// because changes are made to the value during the closure.
+
+package main
+
+func main() {
+       {
+               type X struct {
+                       v int
+               }
+               var x X
+               func() {
+                       x.v++
+               }()
+               if x.v != 1 {
+                       panic("x.v != 1")
+               }
+
+               type Y struct {
+                       X
+               }
+               var y Y
+               func() {
+                       y.v = 1
+               }()
+               if y.v != 1 {
+                       panic("y.v != 1")
+               }
+       }
+
+       {
+               type Z struct {
+                       a [3]byte
+               }
+               var z Z
+               func() {
+                       i := 0
+                       for z.a[1] = 1; i < 10; i++ {
+                       }
+               }()
+               if z.a[1] != 1 {
+                       panic("z.a[1] != 1")
+               }
+       }
+
+       {
+               w := 0
+               tmp := 0
+               f := func() {
+                       if w != 1 {
+                               panic("w != 1")
+                       }
+               }
+               func() {
+                       tmp = w // force capture of w, but do not write to it yet
+                       _ = tmp
+                       func() {
+                               func() {
+                                       w++ // write in a nested closure
+                               }()
+                       }()
+               }()
+               f()
+       }
+
+       {
+               var g func() int
+               for i := range [2]int{} {
+                       if i == 0 {
+                               g = func() int {
+                                       return i // test that we capture by ref here, i is mutated on every interation
+                               }
+                       }
+               }
+               if g() != 1 {
+                       panic("g() != 1")
+               }
+       }
+
+       {
+               var g func() int
+               q := 0
+               for range [2]int{} {
+                       q++
+                       g = func() int {
+                               return q // test that we capture by ref here
+                                        // q++ must on a different decldepth than q declaration
+                       }
+               }
+               if g() != 2 {
+                       panic("g() != 2")
+               }
+       }
+
+       {
+               var g func() int
+               var a [2]int
+               q := 0
+               for a[func() int {
+                       q++
+                       return 0
+               }()] = range [2]int{} {
+                       g = func() int {
+                               return q // test that we capture by ref here
+                                        // q++ must on a different decldepth than q declaration
+                       }
+               }
+               if g() != 2 {
+                       panic("g() != 2")
+               }
+       }
+}
index 6a46ce86abd4173cc549967658f1107cbb278c31..8c50277e9dc730d523569c237084e30e3f418866 100644 (file)
@@ -203,9 +203,17 @@ func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b"
 }
 
 func foo21() func() int {
+       x := 42
+       return func() int { // ERROR "func literal escapes to heap"
+               return x
+       }
+}
+
+func foo21a() func() int {
        x := 42             // ERROR "moved to heap: x"
        return func() int { // ERROR "func literal escapes to heap"
-               return x // ERROR "&x escapes to heap"
+               x++  // ERROR "&x escapes to heap"
+               return x
        }
 }
 
@@ -216,24 +224,31 @@ func foo22() int {
        }()
 }
 
-func foo23(x int) func() int { // ERROR "moved to heap: x"
+func foo23(x int) func() int {
        return func() int { // ERROR "func literal escapes to heap"
-               return x // ERROR "&x escapes to heap"
+               return x
        }
 }
 
-func foo23a(x int) func() int { // ERROR "moved to heap: x"
+func foo23a(x int) func() int {
        f := func() int { // ERROR "func literal escapes to heap"
-               return x // ERROR "&x escapes to heap"
+               return x
        }
        return f
 }
 
-func foo23b(x int) *(func() int) { // ERROR "moved to heap: x"
-       f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap" "&x escapes to heap"
+func foo23b(x int) *(func() int) {
+       f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap"
        return &f                    // ERROR "&f escapes to heap"
 }
 
+func foo23c(x int) func() int { // ERROR "moved to heap: x"
+       return func() int { // ERROR "func literal escapes to heap"
+               x++ // ERROR "&x escapes to heap"
+               return x
+       }
+}
+
 func foo24(x int) int {
        return func() int { // ERROR "func literal does not escape"
                return x
@@ -523,23 +538,48 @@ func foo72b() [10]*int {
 
 // issue 2145
 func foo73() {
+       s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+       for _, v := range s {
+               vv := v
+               // actually just escapes its scope
+               defer func() { // ERROR "func literal escapes to heap"
+                       println(vv)
+               }()
+       }
+}
+
+func foo731() {
        s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
        for _, v := range s {
                vv := v // ERROR "moved to heap: vv"
                // actually just escapes its scope
                defer func() { // ERROR "func literal escapes to heap"
-                       println(vv) // ERROR "&vv escapes to heap"
+                       vv = 42 // ERROR "&vv escapes to heap"
+                       println(vv)
                }()
        }
 }
 
 func foo74() {
+       s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+       for _, v := range s {
+               vv := v
+               // actually just escapes its scope
+               fn := func() { // ERROR "func literal escapes to heap"
+                       println(vv)
+               }
+               defer fn()
+       }
+}
+
+func foo74a() {
        s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
        for _, v := range s {
                vv := v // ERROR "moved to heap: vv"
                // actually just escapes its scope
                fn := func() { // ERROR "func literal escapes to heap"
-                       println(vv) // ERROR "&vv escapes to heap"
+                       vv += 1 // ERROR "&vv escapes to heap"
+                       println(vv)
                }
                defer fn()
        }
@@ -547,13 +587,25 @@ func foo74() {
 
 // issue 3975
 func foo74b() {
+       var array [3]func()
+       s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+       for i, v := range s {
+               vv := v
+               // actually just escapes its scope
+               array[i] = func() { // ERROR "func literal escapes to heap"
+                       println(vv)
+               }
+       }
+}
+
+func foo74c() {
        var array [3]func()
        s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
        for i, v := range s {
                vv := v // ERROR "moved to heap: vv"
                // actually just escapes its scope
                array[i] = func() { // ERROR "func literal escapes to heap"
-                       println(vv) // ERROR "&vv escapes to heap"
+                       println(&vv) // ERROR "&vv escapes to heap" "&vv does not escape"
                }
        }
 }
@@ -1213,9 +1265,9 @@ func foo134() {
 
 func foo135() {
        var i int   // ERROR "moved to heap: i"
-       p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
+       p := &i     // ERROR "&i escapes to heap"
        go func() { // ERROR "func literal escapes to heap"
-               q := p   // ERROR "&p escapes to heap"
+               q := p
                func() { // ERROR "func literal does not escape"
                        r := q
                        _ = r
@@ -1225,9 +1277,9 @@ func foo135() {
 
 func foo136() {
        var i int   // ERROR "moved to heap: i"
-       p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
+       p := &i     // ERROR "&i escapes to heap"
        go func() { // ERROR "func literal escapes to heap"
-               q := p   // ERROR "&p escapes to heap" "leaking closure reference p"
+               q := p   // ERROR "leaking closure reference p"
                func() { // ERROR "func literal does not escape"
                        r := q // ERROR "leaking closure reference q"
                        px = r
@@ -1239,9 +1291,9 @@ func foo137() {
        var i int // ERROR "moved to heap: i"
        p := &i   // ERROR "&i escapes to heap"
        func() {  // ERROR "func literal does not escape"
-               q := p      // ERROR "leaking closure reference p" "moved to heap: q"
+               q := p      // ERROR "leaking closure reference p"
                go func() { // ERROR "func literal escapes to heap"
-                       r := q // ERROR "&q escapes to heap"
+                       r := q
                        _ = r
                }()
        }()
@@ -1492,3 +1544,162 @@ func g() (x interface{}) { // ERROR "moved to heap: x"
        x = &x // ERROR "&x escapes to heap"
        return
 }
+
+var sink interface{}
+
+type Lit struct {
+       p *int
+}
+
+func ptrlitNoescape() {
+       // Both literal and element do not escape.
+       i := 0
+       x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i does not escape"
+       _ = x
+}
+
+func ptrlitNoEscape2() {
+       // Literal does not escape, but element does.
+       i := 0 // ERROR "moved to heap: i"
+       x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
+       sink = *x
+}
+
+func ptrlitEscape() {
+       // Both literal and element escape.
+       i := 0 // ERROR "moved to heap: i"
+       x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
+       sink = x
+}
+
+// self-assignments
+
+type Buffer struct {
+       arr  [64]byte
+       buf1 []byte
+       buf2 []byte
+       str1 string
+       str2 string
+}
+
+func (b *Buffer) foo() { // ERROR "b does not escape"
+       b.buf1 = b.buf1[1:2]   // ERROR "ignoring self-assignment to b.buf1"
+       b.buf1 = b.buf1[1:2:3] // ERROR "ignoring self-assignment to b.buf1"
+       b.buf1 = b.buf2[1:2]   // ERROR "ignoring self-assignment to b.buf1"
+       b.buf1 = b.buf2[1:2:3] // ERROR "ignoring self-assignment to b.buf1"
+}
+
+func (b *Buffer) bar() { // ERROR "leaking param: b"
+       b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap"
+}
+
+func (b *Buffer) baz() { // ERROR "b does not escape"
+       b.str1 = b.str1[1:2] // ERROR "ignoring self-assignment to b.str1"
+       b.str1 = b.str2[1:2] // ERROR "ignoring self-assignment to b.str1"
+}
+
+func (b *Buffer) bat() { // ERROR "leaking param: b"
+       o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap"
+       o.buf1 = b.buf1[1:2]
+       sink = o
+}
+
+func quux(sp *string, bp *[]byte) { // ERROR "sp does not escape" "bp does not escape"
+       *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp"
+       *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp"
+}
+
+type StructWithString struct {
+       p *int
+       s string
+}
+
+// This is escape analysis false negative.
+// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows
+// to just x, and thus &i looks escaping.
+func fieldFlowTracking() {
+       var x StructWithString
+       i := 0 // ERROR "moved to heap: i"
+       x.p = &i // ERROR "&i escapes to heap"
+       sink = x.s
+}
+
+// String operations.
+
+func slicebytetostring0() {
+       b := make([]byte, 20) // ERROR "does not escape"
+       s := string(b)        // ERROR "string\(b\) does not escape"
+       _ = s
+}
+
+func slicebytetostring1() {
+       b := make([]byte, 20) // ERROR "does not escape"
+       s := string(b)        // ERROR "string\(b\) does not escape"
+       s1 := s[0:1]
+       _ = s1
+}
+
+func slicebytetostring2() {
+       b := make([]byte, 20) // ERROR "does not escape"
+       s := string(b)        // ERROR "string\(b\) escapes to heap"
+       s1 := s[0:1]          // ERROR "moved to heap: s1"
+       sink = &s1            // ERROR "&s1 escapes to heap"
+}
+
+func slicebytetostring3() {
+       b := make([]byte, 20) // ERROR "does not escape"
+       s := string(b)        // ERROR "string\(b\) escapes to heap"
+       s1 := s[0:1]
+       sink = s1
+}
+
+func addstr0() {
+       s0 := "a"
+       s1 := "b"
+       s := s0 + s1 // ERROR "s0 \+ s1 does not escape"
+       _ = s
+}
+
+func addstr1() {
+       s0 := "a"
+       s1 := "b"
+       s := "c"
+       s += s0 + s1 // ERROR "s0 \+ s1 does not escape"
+       _ = s
+}
+
+func addstr2() {
+       b := make([]byte, 20) // ERROR "does not escape"
+       s0 := "a"
+       s := string(b) + s0 // ERROR "string\(b\) does not escape" "string\(b\) \+ s0 does not escape"
+       _ = s
+}
+
+func addstr3() {
+       s0 := "a"
+       s1 := "b"
+       s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap"
+       s2 := s[0:1]
+       sink = s2
+}
+
+func intstring0() bool {
+       // string does not escape
+       x := '0'
+       s := string(x) // ERROR "string\(x\) does not escape"
+       return s == "0"
+}
+
+func intstring1() string {
+       // string does not escape, but the buffer does
+       x := '0'
+       s := string(x) // ERROR "string\(x\) escapes to heap"
+       return s
+}
+
+func intstring2() {
+       // string escapes to heap
+       x := '0'
+       s := string(x) // ERROR "string\(x\) escapes to heap" "moved to heap: s"
+       sink = &s      // ERROR "&s escapes to heap"
+}
index 002a78ea50d14f49024e1a7e0e869d13dae13e83..31f4ed083c469147e834dec21522337cc7163c45 100644 (file)
@@ -203,9 +203,17 @@ func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b"
 }
 
 func foo21() func() int {
+       x := 42
+       return func() int { // ERROR "func literal escapes to heap"
+               return x
+       }
+}
+
+func foo21a() func() int {
        x := 42             // ERROR "moved to heap: x"
        return func() int { // ERROR "func literal escapes to heap"
-               return x // ERROR "&x escapes to heap"
+               x++  // ERROR "&x escapes to heap"
+               return x
        }
 }
 
@@ -216,24 +224,31 @@ func foo22() int {
        }()
 }
 
-func foo23(x int) func() int { // ERROR "moved to heap: x"
+func foo23(x int) func() int {
        return func() int { // ERROR "func literal escapes to heap"
-               return x // ERROR "&x escapes to heap"
+               return x
        }
 }
 
-func foo23a(x int) func() int { // ERROR "moved to heap: x"
+func foo23a(x int) func() int {
        f := func() int { // ERROR "func literal escapes to heap"
-               return x // ERROR "&x escapes to heap"
+               return x
        }
        return f
 }
 
-func foo23b(x int) *(func() int) { // ERROR "moved to heap: x"
-       f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap" "&x escapes to heap"
+func foo23b(x int) *(func() int) {
+       f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap"
        return &f                    // ERROR "&f escapes to heap"
 }
 
+func foo23c(x int) func() int { // ERROR "moved to heap: x"
+       return func() int { // ERROR "func literal escapes to heap"
+               x++ // ERROR "&x escapes to heap"
+               return x
+       }
+}
+
 func foo24(x int) int {
        return func() int { // ERROR "func literal does not escape"
                return x
@@ -523,23 +538,48 @@ func foo72b() [10]*int {
 
 // issue 2145
 func foo73() {
+       s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+       for _, v := range s {
+               vv := v
+               // actually just escapes its scope
+               defer func() { // ERROR "func literal escapes to heap"
+                       println(vv)
+               }()
+       }
+}
+
+func foo731() {
        s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
        for _, v := range s {
                vv := v // ERROR "moved to heap: vv"
                // actually just escapes its scope
                defer func() { // ERROR "func literal escapes to heap"
-                       println(vv) // ERROR "&vv escapes to heap"
+                       vv = 42 // ERROR "&vv escapes to heap"
+                       println(vv)
                }()
        }
 }
 
 func foo74() {
+       s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+       for _, v := range s {
+               vv := v
+               // actually just escapes its scope
+               fn := func() { // ERROR "func literal escapes to heap"
+                       println(vv)
+               }
+               defer fn()
+       }
+}
+
+func foo74a() {
        s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
        for _, v := range s {
                vv := v // ERROR "moved to heap: vv"
                // actually just escapes its scope
                fn := func() { // ERROR "func literal escapes to heap"
-                       println(vv) // ERROR "&vv escapes to heap"
+                       vv += 1 // ERROR "&vv escapes to heap"
+                       println(vv)
                }
                defer fn()
        }
@@ -547,13 +587,25 @@ func foo74() {
 
 // issue 3975
 func foo74b() {
+       var array [3]func()
+       s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+       for i, v := range s {
+               vv := v
+               // actually just escapes its scope
+               array[i] = func() { // ERROR "func literal escapes to heap"
+                       println(vv)
+               }
+       }
+}
+
+func foo74c() {
        var array [3]func()
        s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
        for i, v := range s {
                vv := v // ERROR "moved to heap: vv"
                // actually just escapes its scope
                array[i] = func() { // ERROR "func literal escapes to heap"
-                       println(vv) // ERROR "&vv escapes to heap"
+                       println(&vv) // ERROR "&vv escapes to heap" "&vv does not escape"
                }
        }
 }
@@ -1213,9 +1265,9 @@ func foo134() {
 
 func foo135() {
        var i int   // ERROR "moved to heap: i"
-       p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
+       p := &i     // ERROR "&i escapes to heap"
        go func() { // ERROR "func literal escapes to heap"
-               q := p   // ERROR "&p escapes to heap"
+               q := p
                func() { // ERROR "func literal does not escape"
                        r := q
                        _ = r
@@ -1225,9 +1277,9 @@ func foo135() {
 
 func foo136() {
        var i int   // ERROR "moved to heap: i"
-       p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
+       p := &i     // ERROR "&i escapes to heap"
        go func() { // ERROR "func literal escapes to heap"
-               q := p   // ERROR "&p escapes to heap" "leaking closure reference p"
+               q := p   // ERROR "leaking closure reference p"
                func() { // ERROR "func literal does not escape"
                        r := q // ERROR "leaking closure reference q"
                        px = r
@@ -1239,9 +1291,9 @@ func foo137() {
        var i int // ERROR "moved to heap: i"
        p := &i   // ERROR "&i escapes to heap"
        func() {  // ERROR "func literal does not escape"
-               q := p      // ERROR "leaking closure reference p" "moved to heap: q"
+               q := p      // ERROR "leaking closure reference p"
                go func() { // ERROR "func literal escapes to heap"
-                       r := q // ERROR "&q escapes to heap"
+                       r := q
                        _ = r
                }()
        }()
@@ -1492,3 +1544,162 @@ func g() (x interface{}) { // ERROR "moved to heap: x"
        x = &x // ERROR "&x escapes to heap"
        return
 }
+
+var sink interface{}
+
+type Lit struct {
+       p *int
+}
+
+func ptrlitNoescape() {
+       // Both literal and element do not escape.
+       i := 0
+       x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i does not escape"
+       _ = x
+}
+
+func ptrlitNoEscape2() {
+       // Literal does not escape, but element does.
+       i := 0 // ERROR "moved to heap: i"
+       x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
+       sink = *x
+}
+
+func ptrlitEscape() {
+       // Both literal and element escape.
+       i := 0 // ERROR "moved to heap: i"
+       x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
+       sink = x
+}
+
+// self-assignments
+
+type Buffer struct {
+       arr  [64]byte
+       buf1 []byte
+       buf2 []byte
+       str1 string
+       str2 string
+}
+
+func (b *Buffer) foo() { // ERROR "b does not escape"
+       b.buf1 = b.buf1[1:2]   // ERROR "ignoring self-assignment to b.buf1"
+       b.buf1 = b.buf1[1:2:3] // ERROR "ignoring self-assignment to b.buf1"
+       b.buf1 = b.buf2[1:2]   // ERROR "ignoring self-assignment to b.buf1"
+       b.buf1 = b.buf2[1:2:3] // ERROR "ignoring self-assignment to b.buf1"
+}
+
+func (b *Buffer) bar() { // ERROR "leaking param: b"
+       b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap"
+}
+
+func (b *Buffer) baz() { // ERROR "b does not escape"
+       b.str1 = b.str1[1:2] // ERROR "ignoring self-assignment to b.str1"
+       b.str1 = b.str2[1:2] // ERROR "ignoring self-assignment to b.str1"
+}
+
+func (b *Buffer) bat() { // ERROR "leaking param: b"
+       o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap"
+       o.buf1 = b.buf1[1:2]
+       sink = o
+}
+
+func quux(sp *string, bp *[]byte) { // ERROR "sp does not escape" "bp does not escape"
+       *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp"
+       *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp"
+}
+
+type StructWithString struct {
+       p *int
+       s string
+}
+
+// This is escape analysis false negative.
+// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows
+// to just x, and thus &i looks escaping.
+func fieldFlowTracking() {
+       var x StructWithString
+       i := 0 // ERROR "moved to heap: i"
+       x.p = &i // ERROR "&i escapes to heap"
+       sink = x.s
+}
+
+// String operations.
+
+func slicebytetostring0() {
+       b := make([]byte, 20) // ERROR "does not escape"
+       s := string(b)        // ERROR "string\(b\) does not escape"
+       _ = s
+}
+
+func slicebytetostring1() {
+       b := make([]byte, 20) // ERROR "does not escape"
+       s := string(b)        // ERROR "string\(b\) does not escape"
+       s1 := s[0:1]
+       _ = s1
+}
+
+func slicebytetostring2() {
+       b := make([]byte, 20) // ERROR "does not escape"
+       s := string(b)        // ERROR "string\(b\) escapes to heap"
+       s1 := s[0:1]          // ERROR "moved to heap: s1"
+       sink = &s1            // ERROR "&s1 escapes to heap"
+}
+
+func slicebytetostring3() {
+       b := make([]byte, 20) // ERROR "does not escape"
+       s := string(b)        // ERROR "string\(b\) escapes to heap"
+       s1 := s[0:1]
+       sink = s1
+}
+
+func addstr0() {
+       s0 := "a"
+       s1 := "b"
+       s := s0 + s1 // ERROR "s0 \+ s1 does not escape"
+       _ = s
+}
+
+func addstr1() {
+       s0 := "a"
+       s1 := "b"
+       s := "c"
+       s += s0 + s1 // ERROR "s0 \+ s1 does not escape"
+       _ = s
+}
+
+func addstr2() {
+       b := make([]byte, 20) // ERROR "does not escape"
+       s0 := "a"
+       s := string(b) + s0 // ERROR "string\(b\) does not escape" "string\(b\) \+ s0 does not escape"
+       _ = s
+}
+
+func addstr3() {
+       s0 := "a"
+       s1 := "b"
+       s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap"
+       s2 := s[0:1]
+       sink = s2
+}
+
+func intstring0() bool {
+       // string does not escape
+       x := '0'
+       s := string(x) // ERROR "string\(x\) does not escape"
+       return s == "0"
+}
+
+func intstring1() string {
+       // string does not escape, but the buffer does
+       x := '0'
+       s := string(x) // ERROR "string\(x\) escapes to heap"
+       return s
+}
+
+func intstring2() {
+       // string escapes to heap
+       x := '0'
+       s := string(x) // ERROR "string\(x\) escapes to heap" "moved to heap: s"
+       sink = &s      // ERROR "&s escapes to heap"
+}
diff --git a/test/fixedbugs/issue9537.dir/a.go b/test/fixedbugs/issue9537.dir/a.go
new file mode 100644 (file)
index 0000000..818c9eb
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type X struct {
+       T [32]byte
+}
+
+func (x *X) Get() []byte {
+       t := x.T
+       return t[:]
+}
+
+func (x *X) RetPtr(i int) *int {
+       i++
+       return &i
+}
+
+func (x *X) RetRPtr(i int) (r1 int, r2 *int) {
+       r1 = i + 1
+       r2 = &r1
+       return
+}
diff --git a/test/fixedbugs/issue9537.dir/b.go b/test/fixedbugs/issue9537.dir/b.go
new file mode 100644 (file)
index 0000000..52e64c8
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "bytes"
+
+       "./a"
+)
+
+type X struct {
+       *a.X
+}
+
+type Intf interface {
+       Get()        []byte
+       RetPtr(int)  *int
+       RetRPtr(int) (int, *int)
+}
+
+func main() {
+       x := &a.X{T: [32]byte{1, 2, 3, 4}}
+       var ix Intf = X{x}
+       t1 := ix.Get()
+       t2 := x.Get()
+       if !bytes.Equal(t1, t2) {
+               panic(t1)
+       }
+
+       p1 := ix.RetPtr(5)
+       p2 := x.RetPtr(7)
+       if *p1 != 6 || *p2 != 8 {
+               panic(*p1)
+       }
+
+       r1, r2 := ix.RetRPtr(10)
+       r3, r4 := x.RetRPtr(13)
+       if r1 != 11 || *r2 != 11 || r3 != 14 || *r4 != 14 {
+               panic("bad RetRPtr")
+       }
+}
diff --git a/test/fixedbugs/issue9537.go b/test/fixedbugs/issue9537.go
new file mode 100644 (file)
index 0000000..ac2d41b
--- /dev/null
@@ -0,0 +1,10 @@
+// rundir
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 9537: Compiler does not run escape analysis on an inlined
+// generated method wrapper.
+
+package ignored
diff --git a/test/fixedbugs/issue9634.go b/test/fixedbugs/issue9634.go
new file mode 100644 (file)
index 0000000..2d5aae4
--- /dev/null
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 9634: Structs are incorrectly unpacked when passed as an argument
+// to append.
+
+package main
+
+func main() {
+       s := struct{
+               t []int
+               u int
+       }{}
+       _ = append(s, 0) // ERROR "must be a slice|must be slice"
+}
diff --git a/test/fixedbugs/issue9691.go b/test/fixedbugs/issue9691.go
new file mode 100644 (file)
index 0000000..39c3dfa
--- /dev/null
@@ -0,0 +1,21 @@
+// run
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       s := "foo"
+       b := []byte(s)
+       m := make(map[string]int)
+       // Test that map index can be used in range
+       // and that slicebytetostringtmp is not used in this context.
+       for m[string(b)] = range s {
+       }
+       b[0] = 'b'
+       if m["foo"] != 2 {
+               panic("bad")
+       }
+}
diff --git a/test/fixedbugs/issue9731.go b/test/fixedbugs/issue9731.go
new file mode 100644 (file)
index 0000000..286cebd
--- /dev/null
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2014 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func f(x interface{}) {
+       switch x := x.(type) {
+       case int:
+               func() {
+                       _ = x
+               }()
+       case map[int]int:
+               func() {
+                       for range x {
+                       }
+               }()
+       }
+}
diff --git a/test/fixedbugs/issue9738.go b/test/fixedbugs/issue9738.go
new file mode 100644 (file)
index 0000000..85319d7
--- /dev/null
@@ -0,0 +1,20 @@
+// run
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func F() (x int) {
+       defer func() {
+               if x != 42 {
+                       println("BUG: x =", x)
+               }
+       }()
+       return 42
+}
+
+func main() {
+       F()
+}
index 93fb133ebb075988bba0f8ee2c896662bf47ffe1..a639150511c2fa1e8776d4fa687669880cb795c6 100644 (file)
@@ -185,6 +185,26 @@ func main() {
                goarch = runtime.GOARCH
        }
 
+       thechar := ""
+       if gochar, err := exec.Command("go", "env", "GOCHAR").Output(); err != nil {
+               bug()
+               fmt.Printf("running go env GOCHAR: %v\n", err)
+               return
+       } else {
+               thechar = strings.TrimSpace(string(gochar))
+       }
+
+       version, err := exec.Command("go", "tool", thechar+"g", "-V").Output()
+       if err != nil {
+               bug()
+               fmt.Printf("running go tool %sg -V: %v\n", thechar, err)
+               return
+       }
+       if strings.Contains(string(version), "framepointer") {
+               // Skip this test if GOEXPERIMENT=framepointer
+               return
+       }
+
        dir, err := ioutil.TempDir("", "go-test-nosplit")
        if err != nil {
                bug()