summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-12-05 11:43:41 -0500
committerRuss Cox <rsc@golang.org>2014-12-05 11:43:41 -0500
commit8670c52abcdb260f5366d6fa205a7c7f9b5b1067 (patch)
tree3781a05c976360f88b736c71316dadc789e02062
parent3ebebda3a7495402239db4369d59d73749c1bfa2 (diff)
parent6d3ba1914e289ed223f7bb69f34604c0e2ae5384 (diff)
downloadgo-8670c52abcdb260f5366d6fa205a7c7f9b5b1067.tar.gz
all: merge dev.cc (81884b89bd88) into default
With this change, default now contains Go 1.5 work. Any future bug fixes for Go 1.4 in the compilers or the runtime will have to be made directly to the release branch.
-rw-r--r--.hgignore6
-rw-r--r--dev.cc0
-rw-r--r--include/link.h41
-rw-r--r--lib/codereview/codereview.cfg1
-rw-r--r--lib/codereview/codereview.py12
-rw-r--r--src/cmd/5a/a.h3
-rw-r--r--src/cmd/5a/a.y26
-rw-r--r--src/cmd/5a/y.tab.c2049
-rw-r--r--src/cmd/5a/y.tab.h68
-rw-r--r--src/cmd/5c/cgen.c1213
-rw-r--r--src/cmd/5c/doc.go16
-rw-r--r--src/cmd/5c/gc.h333
-rw-r--r--src/cmd/5c/mul.c640
-rw-r--r--src/cmd/5c/peep.c1478
-rw-r--r--src/cmd/5c/reg.c1210
-rw-r--r--src/cmd/5c/sgen.c265
-rw-r--r--src/cmd/5c/swt.c461
-rw-r--r--src/cmd/5c/txt.c1361
-rw-r--r--src/cmd/5g/gobj.c2
-rw-r--r--src/cmd/5g/gsubr.c3
-rw-r--r--src/cmd/5g/opt.h44
-rw-r--r--src/cmd/5g/reg.c95
-rw-r--r--src/cmd/5l/5.out.h2
-rw-r--r--src/cmd/6a/a.h3
-rw-r--r--src/cmd/6a/a.y25
-rw-r--r--src/cmd/6a/y.tab.c1054
-rw-r--r--src/cmd/6c/Makefile5
-rw-r--r--src/cmd/6c/cgen.c2046
-rw-r--r--src/cmd/6c/div.c236
-rw-r--r--src/cmd/6c/doc.go16
-rw-r--r--src/cmd/6c/gc.h359
-rw-r--r--src/cmd/6c/list.c38
-rw-r--r--src/cmd/6c/machcap.c107
-rw-r--r--src/cmd/6c/mul.c458
-rw-r--r--src/cmd/6c/peep.c902
-rw-r--r--src/cmd/6c/reg.c1523
-rw-r--r--src/cmd/6c/sgen.c483
-rw-r--r--src/cmd/6c/swt.c353
-rw-r--r--src/cmd/6c/txt.c1674
-rw-r--r--src/cmd/6g/gobj.c2
-rw-r--r--src/cmd/6g/opt.h46
-rw-r--r--src/cmd/6g/reg.c140
-rw-r--r--src/cmd/6l/6.out.h2
-rw-r--r--src/cmd/8a/a.h3
-rw-r--r--src/cmd/8a/a.y25
-rw-r--r--src/cmd/8a/y.tab.c1050
-rw-r--r--src/cmd/8c/Makefile5
-rw-r--r--src/cmd/8c/cgen.c1939
-rw-r--r--src/cmd/8c/cgen64.c2657
-rw-r--r--src/cmd/8c/div.c236
-rw-r--r--src/cmd/8c/doc.go16
-rw-r--r--src/cmd/8c/gc.h364
-rw-r--r--src/cmd/8c/list.c38
-rw-r--r--src/cmd/8c/machcap.c116
-rw-r--r--src/cmd/8c/mul.c458
-rw-r--r--src/cmd/8c/peep.c807
-rw-r--r--src/cmd/8c/reg.c1438
-rw-r--r--src/cmd/8c/sgen.c483
-rw-r--r--src/cmd/8c/swt.c341
-rw-r--r--src/cmd/8c/txt.c1537
-rw-r--r--src/cmd/8g/gobj.c2
-rw-r--r--src/cmd/8g/opt.h46
-rw-r--r--src/cmd/8g/reg.c141
-rw-r--r--src/cmd/8l/8.out.h2
-rw-r--r--src/cmd/9a/Makefile (renamed from src/cmd/cc/Makefile)6
-rw-r--r--src/cmd/9a/a.h170
-rw-r--r--src/cmd/9a/a.y991
-rw-r--r--src/cmd/9a/doc.go21
-rw-r--r--src/cmd/9a/lex.c726
-rw-r--r--src/cmd/9a/y.tab.c3398
-rw-r--r--src/cmd/9a/y.tab.h188
-rw-r--r--src/cmd/9g/cgen.c1763
-rw-r--r--src/cmd/9g/doc.go16
-rw-r--r--src/cmd/9g/galign.c54
-rw-r--r--src/cmd/9g/gg.h117
-rw-r--r--src/cmd/9g/ggen.c1040
-rw-r--r--src/cmd/9g/gobj.c240
-rw-r--r--src/cmd/9g/gsubr.c1707
-rw-r--r--src/cmd/9g/opt.h244
-rw-r--r--src/cmd/9g/peep.c984
-rw-r--r--src/cmd/9g/prog.c307
-rw-r--r--src/cmd/9g/reg.c1346
-rw-r--r--src/cmd/9l/9.out.h516
-rw-r--r--src/cmd/9l/Makefile (renamed from src/cmd/5c/Makefile)0
-rw-r--r--src/cmd/9l/asm.c342
-rw-r--r--src/cmd/9l/doc.go (renamed from src/cmd/cc/doc.go)7
-rw-r--r--src/cmd/9l/l.h100
-rw-r--r--src/cmd/9l/list.c (renamed from src/cmd/5c/list.c)11
-rw-r--r--src/cmd/9l/obj.c108
-rw-r--r--src/cmd/cc/acid.c344
-rw-r--r--src/cmd/cc/bits.c120
-rw-r--r--src/cmd/cc/cc.h835
-rw-r--r--src/cmd/cc/cc.y1220
-rw-r--r--src/cmd/cc/com.c1384
-rw-r--r--src/cmd/cc/com64.c644
-rw-r--r--src/cmd/cc/dcl.c1707
-rw-r--r--src/cmd/cc/dpchk.c793
-rw-r--r--src/cmd/cc/funct.c431
-rw-r--r--src/cmd/cc/godefs.c367
-rw-r--r--src/cmd/cc/lex.c1593
-rw-r--r--src/cmd/cc/lexbody25
-rw-r--r--src/cmd/cc/mac.c34
-rw-r--r--src/cmd/cc/omachcap.c40
-rw-r--r--src/cmd/cc/pgen.c622
-rw-r--r--src/cmd/cc/pswt.c140
-rw-r--r--src/cmd/cc/scon.c640
-rw-r--r--src/cmd/cc/sub.c2068
-rw-r--r--src/cmd/cc/y.tab.c3822
-rw-r--r--src/cmd/cc/y.tab.h230
-rw-r--r--src/cmd/cgo/main.go21
-rw-r--r--src/cmd/cgo/out.go154
-rw-r--r--src/cmd/dist/build.c190
-rw-r--r--src/cmd/dist/buildgc.c89
-rw-r--r--src/cmd/dist/buildruntime.c359
-rw-r--r--src/cmd/dist/unix.c4
-rw-r--r--src/cmd/gc/bits.c34
-rw-r--r--src/cmd/gc/export.c41
-rw-r--r--src/cmd/gc/go.h19
-rw-r--r--src/cmd/gc/lex.c200
-rw-r--r--src/cmd/gc/obj.c12
-rw-r--r--src/cmd/gc/pgen.c4
-rw-r--r--src/cmd/gc/plive.c19
-rw-r--r--src/cmd/gc/reflect.c14
-rw-r--r--src/cmd/gc/subr.c46
-rw-r--r--src/cmd/gc/walk.c8
-rw-r--r--src/cmd/go/build.go54
-rw-r--r--src/cmd/ld/data.c4
-rw-r--r--src/cmd/ld/doc.go6
-rw-r--r--src/cmd/ld/dwarf.c4
-rw-r--r--src/cmd/ld/elf.c29
-rw-r--r--src/cmd/ld/ldelf.c6
-rw-r--r--src/cmd/ld/lib.c60
-rw-r--r--src/cmd/ld/macho.c1
-rw-r--r--src/cmd/ld/symtab.c1
-rw-r--r--src/cmd/objdump/objdump_test.go8
-rw-r--r--src/debug/elf/elf.go178
-rw-r--r--src/debug/elf/file.go50
-rw-r--r--src/debug/elf/file_test.go6
-rw-r--r--src/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.objbin0 -> 3016 bytes
-rw-r--r--src/go/build/build.go2
-rw-r--r--src/go/build/syslist.go2
-rw-r--r--src/hash/crc32/crc32_generic.go2
-rw-r--r--src/liblink/asm6.c5
-rw-r--r--src/liblink/asm9.c2783
-rw-r--r--src/liblink/list6.c38
-rw-r--r--src/liblink/list9.c451
-rw-r--r--src/liblink/obj9.c1083
-rw-r--r--src/liblink/objfile.c42
-rw-r--r--src/liblink/pass.c4
-rw-r--r--src/liblink/sched9.c835
-rw-r--r--src/math/abs_power64x.s14
-rw-r--r--src/math/big/arith_power64x.s46
-rw-r--r--src/math/stubs_power64x.s91
-rw-r--r--src/os/signal/sig.s8
-rw-r--r--src/reflect/all_test.go5
-rw-r--r--src/reflect/asm_power64x.s32
-rw-r--r--src/reflect/type.go13
-rwxr-xr-xsrc/run.bash4
-rw-r--r--src/run.bat8
-rw-r--r--src/runtime/alg.go3
-rw-r--r--src/runtime/arch1_386.go15
-rw-r--r--src/runtime/arch1_amd64.go15
-rw-r--r--src/runtime/arch1_amd64p32.go15
-rw-r--r--src/runtime/arch1_arm.go15
-rw-r--r--src/runtime/arch1_power64.go15
-rw-r--r--src/runtime/arch1_power64le.go15
-rw-r--r--src/runtime/arch_386.h17
-rw-r--r--src/runtime/arch_amd64.h25
-rw-r--r--src/runtime/arch_amd64p32.h17
-rw-r--r--src/runtime/arch_arm.h17
-rw-r--r--src/runtime/arch_power64.go8
-rw-r--r--src/runtime/arch_power64le.go8
-rw-r--r--src/runtime/asm.s5
-rw-r--r--src/runtime/asm_386.s129
-rw-r--r--src/runtime/asm_amd64.s147
-rw-r--r--src/runtime/asm_amd64p32.s118
-rw-r--r--src/runtime/asm_arm.s84
-rw-r--r--src/runtime/asm_power64x.s979
-rw-r--r--src/runtime/atomic_386.c46
-rw-r--r--src/runtime/atomic_386.go91
-rw-r--r--src/runtime/atomic_amd64x.c29
-rw-r--r--src/runtime/atomic_amd64x.go82
-rw-r--r--src/runtime/atomic_arm.go10
-rw-r--r--src/runtime/atomic_power64x.go (renamed from src/runtime/atomic.go)30
-rw-r--r--src/runtime/atomic_power64x.s40
-rw-r--r--src/runtime/cgo.go23
-rw-r--r--src/runtime/cgo/callbacks.c83
-rw-r--r--src/runtime/cgo/callbacks.go95
-rw-r--r--src/runtime/cgo/dragonfly.go (renamed from src/runtime/cgo/dragonfly.c)14
-rw-r--r--src/runtime/cgo/freebsd.go (renamed from src/runtime/cgo/freebsd.c)17
-rw-r--r--src/runtime/cgo/iscgo.go (renamed from src/runtime/cgo/iscgo.c)11
-rw-r--r--src/runtime/cgo/netbsd.go (renamed from src/runtime/cgo/netbsd.c)14
-rw-r--r--src/runtime/cgo/openbsd.go (renamed from src/runtime/cgo/openbsd.c)24
-rw-r--r--src/runtime/cgo/setenv.c13
-rw-r--r--src/runtime/cgo/setenv.go21
-rw-r--r--src/runtime/cgocall.go20
-rw-r--r--src/runtime/chan.go2
-rw-r--r--src/runtime/chan.h68
-rw-r--r--src/runtime/chan1.go61
-rw-r--r--src/runtime/complex.go39
-rw-r--r--src/runtime/cpuprof.go8
-rw-r--r--src/runtime/cputicks.go11
-rw-r--r--src/runtime/debug.go18
-rw-r--r--src/runtime/debug/stubs.s6
-rw-r--r--src/runtime/defs.c15
-rw-r--r--src/runtime/defs1_linux.go6
-rw-r--r--src/runtime/defs1_netbsd_386.go183
-rw-r--r--src/runtime/defs1_netbsd_amd64.go195
-rw-r--r--src/runtime/defs1_netbsd_arm.go170
-rw-r--r--src/runtime/defs1_solaris_amd64.go245
-rw-r--r--src/runtime/defs3_linux.go43
-rw-r--r--src/runtime/defs_android_arm.h3
-rw-r--r--src/runtime/defs_darwin_386.go382
-rw-r--r--src/runtime/defs_darwin_386.h392
-rw-r--r--src/runtime/defs_darwin_amd64.go385
-rw-r--r--src/runtime/defs_darwin_amd64.h395
-rw-r--r--src/runtime/defs_dragonfly_386.go198
-rw-r--r--src/runtime/defs_dragonfly_386.h198
-rw-r--r--src/runtime/defs_dragonfly_amd64.go208
-rw-r--r--src/runtime/defs_dragonfly_amd64.h208
-rw-r--r--src/runtime/defs_freebsd_386.go213
-rw-r--r--src/runtime/defs_freebsd_386.h213
-rw-r--r--src/runtime/defs_freebsd_amd64.go224
-rw-r--r--src/runtime/defs_freebsd_amd64.h224
-rw-r--r--src/runtime/defs_freebsd_arm.go186
-rw-r--r--src/runtime/defs_freebsd_arm.h186
-rw-r--r--src/runtime/defs_linux.go11
-rw-r--r--src/runtime/defs_linux_386.go218
-rw-r--r--src/runtime/defs_linux_386.h211
-rw-r--r--src/runtime/defs_linux_amd64.go253
-rw-r--r--src/runtime/defs_linux_amd64.h254
-rw-r--r--src/runtime/defs_linux_arm.go168
-rw-r--r--src/runtime/defs_linux_arm.h168
-rw-r--r--src/runtime/defs_linux_power64.go198
-rw-r--r--src/runtime/defs_linux_power64le.go198
-rw-r--r--src/runtime/defs_nacl_386.go42
-rw-r--r--src/runtime/defs_nacl_386.h63
-rw-r--r--src/runtime/defs_nacl_amd64p32.go63
-rw-r--r--src/runtime/defs_nacl_amd64p32.h90
-rw-r--r--src/runtime/defs_nacl_arm.go49
-rw-r--r--src/runtime/defs_nacl_arm.h70
-rw-r--r--src/runtime/defs_netbsd_386.h182
-rw-r--r--src/runtime/defs_netbsd_amd64.h194
-rw-r--r--src/runtime/defs_netbsd_arm.h184
-rw-r--r--src/runtime/defs_openbsd_386.go170
-rw-r--r--src/runtime/defs_openbsd_386.h168
-rw-r--r--src/runtime/defs_openbsd_amd64.go181
-rw-r--r--src/runtime/defs_openbsd_amd64.h179
-rw-r--r--src/runtime/defs_plan9_386.go25
-rw-r--r--src/runtime/defs_plan9_386.h26
-rw-r--r--src/runtime/defs_plan9_amd64.go34
-rw-r--r--src/runtime/defs_plan9_amd64.h34
-rw-r--r--src/runtime/defs_solaris_amd64.h254
-rw-r--r--src/runtime/defs_windows_386.go109
-rw-r--r--src/runtime/defs_windows_386.h116
-rw-r--r--src/runtime/defs_windows_amd64.go124
-rw-r--r--src/runtime/defs_windows_amd64.h131
-rw-r--r--src/runtime/env_plan9.go3
-rw-r--r--src/runtime/env_posix.go10
-rw-r--r--src/runtime/export_test.go80
-rw-r--r--src/runtime/extern.go3
-rw-r--r--src/runtime/float.c10
-rw-r--r--src/runtime/funcdata.h10
-rw-r--r--src/runtime/futex_test.go4
-rw-r--r--src/runtime/gcinfo_test.go11
-rw-r--r--src/runtime/gengoos.go84
-rw-r--r--src/runtime/go_tls.h22
-rw-r--r--src/runtime/heapdump.c864
-rw-r--r--src/runtime/heapdump.go729
-rw-r--r--src/runtime/lfstack.c87
-rw-r--r--src/runtime/lfstack.go44
-rw-r--r--src/runtime/lfstack_32bit.go21
-rw-r--r--src/runtime/lfstack_amd64.go24
-rw-r--r--src/runtime/lfstack_linux_power64x.go32
-rw-r--r--src/runtime/lock_futex.go7
-rw-r--r--src/runtime/lock_sema.go8
-rw-r--r--src/runtime/malloc.c396
-rw-r--r--src/runtime/malloc.go101
-rw-r--r--src/runtime/malloc.h621
-rw-r--r--src/runtime/malloc1.go318
-rw-r--r--src/runtime/malloc2.go475
-rw-r--r--src/runtime/mcache.c115
-rw-r--r--src/runtime/mcache.go86
-rw-r--r--src/runtime/mcentral.c214
-rw-r--r--src/runtime/mcentral.go199
-rw-r--r--src/runtime/mem.go24
-rw-r--r--src/runtime/mem_bsd.go88
-rw-r--r--src/runtime/mem_darwin.c82
-rw-r--r--src/runtime/mem_darwin.go58
-rw-r--r--src/runtime/mem_dragonfly.c105
-rw-r--r--src/runtime/mem_freebsd.c100
-rw-r--r--src/runtime/mem_linux.c162
-rw-r--r--src/runtime/mem_linux.go135
-rw-r--r--src/runtime/mem_nacl.c120
-rw-r--r--src/runtime/mem_netbsd.c100
-rw-r--r--src/runtime/mem_openbsd.c100
-rw-r--r--src/runtime/mem_plan9.c121
-rw-r--r--src/runtime/mem_plan9.go70
-rw-r--r--src/runtime/mem_solaris.c101
-rw-r--r--src/runtime/mem_windows.c132
-rw-r--r--src/runtime/mem_windows.go119
-rw-r--r--src/runtime/memclr_386.s46
-rw-r--r--src/runtime/memclr_amd64.s44
-rw-r--r--src/runtime/memclr_plan9_386.s24
-rw-r--r--src/runtime/memclr_power64x.s20
-rw-r--r--src/runtime/memmove_power64x.s40
-rw-r--r--src/runtime/mfixalloc.c64
-rw-r--r--src/runtime/mfixalloc.go59
-rw-r--r--src/runtime/mgc.go1798
-rw-r--r--src/runtime/mgc0.c2010
-rw-r--r--src/runtime/mgc0.go6
-rw-r--r--src/runtime/mgc0.h74
-rw-r--r--src/runtime/mgc1.go77
-rw-r--r--src/runtime/mheap.c889
-rw-r--r--src/runtime/mheap.go785
-rw-r--r--src/runtime/mprof.go33
-rw-r--r--src/runtime/msize.c184
-rw-r--r--src/runtime/msize.go174
-rw-r--r--src/runtime/netpoll.go53
-rw-r--r--src/runtime/netpoll_solaris.go (renamed from src/runtime/netpoll_solaris.c)259
-rw-r--r--src/runtime/netpoll_stub.go (renamed from src/runtime/netpoll_stub.c)9
-rw-r--r--src/runtime/netpoll_windows.c163
-rw-r--r--src/runtime/netpoll_windows.go156
-rw-r--r--src/runtime/noasm.go (renamed from src/runtime/noasm_arm.go)2
-rw-r--r--src/runtime/norace_test.go4
-rw-r--r--src/runtime/os1_darwin.go423
-rw-r--r--src/runtime/os1_dragonfly.go220
-rw-r--r--src/runtime/os1_freebsd.go221
-rw-r--r--src/runtime/os1_linux.go287
-rw-r--r--src/runtime/os1_nacl.go197
-rw-r--r--src/runtime/os1_netbsd.go265
-rw-r--r--src/runtime/os1_netbsd_386.go16
-rw-r--r--src/runtime/os1_netbsd_amd64.go16
-rw-r--r--src/runtime/os1_openbsd.go235
-rw-r--r--src/runtime/os1_plan9.go270
-rw-r--r--src/runtime/os1_windows.go564
-rw-r--r--src/runtime/os1_windows_386.go118
-rw-r--r--src/runtime/os1_windows_amd64.go137
-rw-r--r--src/runtime/os2_darwin.go14
-rw-r--r--src/runtime/os2_dragonfly.go12
-rw-r--r--src/runtime/os2_freebsd.go12
-rw-r--r--src/runtime/os2_linux.go23
-rw-r--r--src/runtime/os2_nacl.go154
-rw-r--r--src/runtime/os2_netbsd.go18
-rw-r--r--src/runtime/os2_openbsd.go14
-rw-r--r--src/runtime/os2_plan9.go72
-rw-r--r--src/runtime/os2_solaris.go13
-rw-r--r--src/runtime/os2_windows.go25
-rw-r--r--src/runtime/os3_solaris.go493
-rw-r--r--src/runtime/os_android.h1
-rw-r--r--src/runtime/os_android_arm.go (renamed from src/runtime/os_android.c)11
-rw-r--r--src/runtime/os_darwin.c567
-rw-r--r--src/runtime/os_darwin.go30
-rw-r--r--src/runtime/os_darwin.h43
-rw-r--r--src/runtime/os_dragonfly.c312
-rw-r--r--src/runtime/os_dragonfly.go34
-rw-r--r--src/runtime/os_dragonfly.h30
-rw-r--r--src/runtime/os_freebsd.c320
-rw-r--r--src/runtime/os_freebsd.go29
-rw-r--r--src/runtime/os_freebsd.h29
-rw-r--r--src/runtime/os_freebsd_arm.go (renamed from src/runtime/os_freebsd_arm.c)17
-rw-r--r--src/runtime/os_linux.c342
-rw-r--r--src/runtime/os_linux.go26
-rw-r--r--src/runtime/os_linux.h41
-rw-r--r--src/runtime/os_linux_386.c38
-rw-r--r--src/runtime/os_linux_386.go37
-rw-r--r--src/runtime/os_linux_arm.c80
-rw-r--r--src/runtime/os_linux_arm.go78
-rw-r--r--src/runtime/os_nacl.c312
-rw-r--r--src/runtime/os_nacl.go21
-rw-r--r--src/runtime/os_nacl.h162
-rw-r--r--src/runtime/os_nacl_arm.go (renamed from src/runtime/os_nacl_arm.c)19
-rw-r--r--src/runtime/os_netbsd.c368
-rw-r--r--src/runtime/os_netbsd.go32
-rw-r--r--src/runtime/os_netbsd.h31
-rw-r--r--src/runtime/os_netbsd_386.c17
-rw-r--r--src/runtime/os_netbsd_amd64.c18
-rw-r--r--src/runtime/os_openbsd.c309
-rw-r--r--src/runtime/os_openbsd.go30
-rw-r--r--src/runtime/os_openbsd.h26
-rw-r--r--src/runtime/os_plan9.c362
-rw-r--r--src/runtime/os_plan9.go27
-rw-r--r--src/runtime/os_plan9.h93
-rw-r--r--src/runtime/os_plan9_386.c150
-rw-r--r--src/runtime/os_plan9_386.go131
-rw-r--r--src/runtime/os_plan9_amd64.c158
-rw-r--r--src/runtime/os_plan9_amd64.go139
-rw-r--r--src/runtime/os_solaris.c557
-rw-r--r--src/runtime/os_solaris.go52
-rw-r--r--src/runtime/os_solaris.h55
-rw-r--r--src/runtime/os_windows.c636
-rw-r--r--src/runtime/os_windows.go20
-rw-r--r--src/runtime/os_windows.h42
-rw-r--r--src/runtime/os_windows_386.c128
-rw-r--r--src/runtime/os_windows_amd64.c150
-rw-r--r--src/runtime/panic.c200
-rw-r--r--src/runtime/panic.go56
-rw-r--r--src/runtime/panic1.go161
-rw-r--r--src/runtime/parfor.c226
-rw-r--r--src/runtime/parfor.go186
-rw-r--r--src/runtime/pprof/pprof_test.go2
-rw-r--r--src/runtime/proc.c3521
-rw-r--r--src/runtime/proc.go44
-rw-r--r--src/runtime/proc1.go3193
-rw-r--r--src/runtime/race.c347
-rw-r--r--src/runtime/race.go42
-rw-r--r--src/runtime/race.h34
-rw-r--r--src/runtime/race0.go2
-rw-r--r--src/runtime/race1.go335
-rw-r--r--src/runtime/race_amd64.s21
-rw-r--r--src/runtime/rdebug.go18
-rw-r--r--src/runtime/rt0_linux_power64.s17
-rw-r--r--src/runtime/rt0_linux_power64le.s14
-rw-r--r--src/runtime/rt0_windows_amd64.s3
-rw-r--r--src/runtime/runtime.c399
-rw-r--r--src/runtime/runtime.h1132
-rw-r--r--src/runtime/runtime1.go417
-rw-r--r--src/runtime/runtime2.go606
-rw-r--r--src/runtime/runtime2_windows.go8
-rw-r--r--src/runtime/select.go6
-rw-r--r--src/runtime/signal.c25
-rw-r--r--src/runtime/signal1_unix.go111
-rw-r--r--src/runtime/signal_386.c122
-rw-r--r--src/runtime/signal_386.go131
-rw-r--r--src/runtime/signal_amd64x.c156
-rw-r--r--src/runtime/signal_amd64x.go163
-rw-r--r--src/runtime/signal_android_386.h1
-rw-r--r--src/runtime/signal_android_arm.h1
-rw-r--r--src/runtime/signal_arm.c121
-rw-r--r--src/runtime/signal_arm.go126
-rw-r--r--src/runtime/signal_darwin.go45
-rw-r--r--src/runtime/signal_darwin_386.go34
-rw-r--r--src/runtime/signal_darwin_386.h23
-rw-r--r--src/runtime/signal_darwin_amd64.go42
-rw-r--r--src/runtime/signal_darwin_amd64.h31
-rw-r--r--src/runtime/signal_dragonfly.go46
-rw-r--r--src/runtime/signal_dragonfly_386.go34
-rw-r--r--src/runtime/signal_dragonfly_386.h23
-rw-r--r--src/runtime/signal_dragonfly_amd64.go44
-rw-r--r--src/runtime/signal_dragonfly_amd64.h31
-rw-r--r--src/runtime/signal_freebsd.go46
-rw-r--r--src/runtime/signal_freebsd_386.go34
-rw-r--r--src/runtime/signal_freebsd_386.h23
-rw-r--r--src/runtime/signal_freebsd_amd64.go44
-rw-r--r--src/runtime/signal_freebsd_amd64.h31
-rw-r--r--src/runtime/signal_freebsd_arm.go48
-rw-r--r--src/runtime/signal_freebsd_arm.h28
-rw-r--r--src/runtime/signal_linux.go78
-rw-r--r--src/runtime/signal_linux_386.go36
-rw-r--r--src/runtime/signal_linux_386.h24
-rw-r--r--src/runtime/signal_linux_amd64.go46
-rw-r--r--src/runtime/signal_linux_amd64.h32
-rw-r--r--src/runtime/signal_linux_arm.go48
-rw-r--r--src/runtime/signal_linux_arm.h28
-rw-r--r--src/runtime/signal_linux_power64x.go71
-rw-r--r--src/runtime/signal_nacl.go45
-rw-r--r--src/runtime/signal_nacl_386.go34
-rw-r--r--src/runtime/signal_nacl_386.h23
-rw-r--r--src/runtime/signal_nacl_amd64p32.go44
-rw-r--r--src/runtime/signal_nacl_amd64p32.h31
-rw-r--r--src/runtime/signal_nacl_arm.go47
-rw-r--r--src/runtime/signal_nacl_arm.h28
-rw-r--r--src/runtime/signal_netbsd.go46
-rw-r--r--src/runtime/signal_netbsd_386.go38
-rw-r--r--src/runtime/signal_netbsd_386.h23
-rw-r--r--src/runtime/signal_netbsd_amd64.go48
-rw-r--r--src/runtime/signal_netbsd_amd64.h31
-rw-r--r--src/runtime/signal_openbsd.go46
-rw-r--r--src/runtime/signal_openbsd_386.go41
-rw-r--r--src/runtime/signal_openbsd_386.h23
-rw-r--r--src/runtime/signal_openbsd_amd64.go49
-rw-r--r--src/runtime/signal_openbsd_amd64.h31
-rw-r--r--src/runtime/signal_plan9.go (renamed from src/runtime/signals_plan9.h)57
-rw-r--r--src/runtime/signal_power64x.go144
-rw-r--r--src/runtime/signal_solaris.go88
-rw-r--r--src/runtime/signal_solaris_amd64.go46
-rw-r--r--src/runtime/signal_solaris_amd64.h31
-rw-r--r--src/runtime/signal_unix.c119
-rw-r--r--src/runtime/signal_unix.go4
-rw-r--r--src/runtime/signals_android.h1
-rw-r--r--src/runtime/signals_darwin.h53
-rw-r--r--src/runtime/signals_dragonfly.h54
-rw-r--r--src/runtime/signals_freebsd.h54
-rw-r--r--src/runtime/signals_linux.h86
-rw-r--r--src/runtime/signals_nacl.h53
-rw-r--r--src/runtime/signals_netbsd.h54
-rw-r--r--src/runtime/signals_openbsd.h54
-rw-r--r--src/runtime/signals_solaris.h97
-rw-r--r--src/runtime/sigpanic_unix.go9
-rw-r--r--src/runtime/sigqueue.go21
-rw-r--r--src/runtime/slice.go8
-rw-r--r--src/runtime/softfloat64.go22
-rw-r--r--src/runtime/softfloat64_test.go2
-rw-r--r--src/runtime/softfloat_arm.c687
-rw-r--r--src/runtime/softfloat_arm.go645
-rw-r--r--src/runtime/sqrt.go9
-rw-r--r--src/runtime/stack.c892
-rw-r--r--src/runtime/stack.go13
-rw-r--r--src/runtime/stack.h97
-rw-r--r--src/runtime/stack1.go801
-rw-r--r--src/runtime/stack2.go106
-rw-r--r--src/runtime/string.c226
-rw-r--r--src/runtime/string.go18
-rw-r--r--src/runtime/string1.go108
-rw-r--r--src/runtime/stubs.go155
-rw-r--r--src/runtime/stubs2.go30
-rw-r--r--src/runtime/stubs3.go12
-rw-r--r--src/runtime/symtab.go22
-rw-r--r--src/runtime/sys_arm.c35
-rw-r--r--src/runtime/sys_arm.go35
-rw-r--r--src/runtime/sys_darwin_386.s7
-rw-r--r--src/runtime/sys_darwin_amd64.s7
-rw-r--r--src/runtime/sys_dragonfly_386.s7
-rw-r--r--src/runtime/sys_dragonfly_amd64.s3
-rw-r--r--src/runtime/sys_freebsd_386.s7
-rw-r--r--src/runtime/sys_freebsd_amd64.s3
-rw-r--r--src/runtime/sys_freebsd_arm.s5
-rw-r--r--src/runtime/sys_linux_386.s3
-rw-r--r--src/runtime/sys_linux_amd64.s11
-rw-r--r--src/runtime/sys_linux_arm.s13
-rw-r--r--src/runtime/sys_linux_power64x.s384
-rw-r--r--src/runtime/sys_nacl_386.s7
-rw-r--r--src/runtime/sys_nacl_amd64p32.s4
-rw-r--r--src/runtime/sys_nacl_arm.s6
-rw-r--r--src/runtime/sys_netbsd_386.s3
-rw-r--r--src/runtime/sys_netbsd_amd64.s3
-rw-r--r--src/runtime/sys_netbsd_arm.s5
-rw-r--r--src/runtime/sys_openbsd_386.s7
-rw-r--r--src/runtime/sys_openbsd_amd64.s3
-rw-r--r--src/runtime/sys_plan9_386.s3
-rw-r--r--src/runtime/sys_plan9_amd64.s3
-rw-r--r--src/runtime/sys_power64x.go37
-rw-r--r--src/runtime/sys_solaris_amd64.s27
-rw-r--r--src/runtime/sys_windows_386.s31
-rw-r--r--src/runtime/sys_windows_amd64.s29
-rw-r--r--src/runtime/sys_x86.go (renamed from src/runtime/sys_x86.c)57
-rw-r--r--src/runtime/syscall2_solaris.go47
-rw-r--r--src/runtime/syscall_solaris.c23
-rw-r--r--src/runtime/syscall_solaris.go79
-rw-r--r--src/runtime/syscall_windows.go18
-rw-r--r--src/runtime/thunk.s22
-rw-r--r--src/runtime/thunk_solaris_amd64.s88
-rw-r--r--src/runtime/thunk_windows.s3
-rw-r--r--src/runtime/tls_arm.s3
-rw-r--r--src/runtime/traceback.go28
-rw-r--r--src/runtime/type.go99
-rw-r--r--src/runtime/type.h113
-rw-r--r--src/runtime/typekind.h12
-rw-r--r--src/runtime/typekind1.go39
-rw-r--r--src/runtime/vdso_linux_amd64.c371
-rw-r--r--src/runtime/vdso_linux_amd64.go328
-rw-r--r--src/runtime/vdso_none.go10
-rw-r--r--src/runtime/vlop_arm.s5
-rw-r--r--src/runtime/vlrt.c914
-rw-r--r--src/runtime/zgoarch_386.go12
-rw-r--r--src/runtime/zgoarch_amd64.go12
-rw-r--r--src/runtime/zgoarch_amd64p32.go12
-rw-r--r--src/runtime/zgoarch_arm.go12
-rw-r--r--src/runtime/zgoarch_power64.go12
-rw-r--r--src/runtime/zgoarch_power64le.go12
-rw-r--r--src/runtime/zgoos_android.go17
-rw-r--r--src/runtime/zgoos_darwin.go17
-rw-r--r--src/runtime/zgoos_dragonfly.go17
-rw-r--r--src/runtime/zgoos_freebsd.go17
-rw-r--r--src/runtime/zgoos_linux.go19
-rw-r--r--src/runtime/zgoos_nacl.go17
-rw-r--r--src/runtime/zgoos_netbsd.go17
-rw-r--r--src/runtime/zgoos_openbsd.go17
-rw-r--r--src/runtime/zgoos_plan9.go17
-rw-r--r--src/runtime/zgoos_solaris.go17
-rw-r--r--src/runtime/zgoos_windows.go17
-rw-r--r--src/sync/atomic/asm_power64x.s184
-rw-r--r--src/syscall/asm.s7
-rw-r--r--src/syscall/asm_linux_power64x.s104
-rwxr-xr-xsrc/syscall/mkall.sh17
-rwxr-xr-xsrc/syscall/mkerrors.sh1
-rw-r--r--src/syscall/syscall_linux_power64x.go97
-rw-r--r--src/syscall/types_linux.go110
-rw-r--r--src/syscall/zerrors_linux_power64.go1878
-rw-r--r--src/syscall/zerrors_linux_power64le.go1902
-rw-r--r--src/syscall/zsyscall_linux_power64.go1931
-rw-r--r--src/syscall/zsyscall_linux_power64le.go1931
-rw-r--r--src/syscall/zsysnum_linux_power64.go351
-rw-r--r--src/syscall/zsysnum_linux_power64le.go351
-rw-r--r--src/syscall/ztypes_linux_power64.go602
-rw-r--r--src/syscall/ztypes_linux_power64le.go602
-rw-r--r--test/clearfat.go68
-rw-r--r--test/live.go2
-rw-r--r--test/nilptr3.go2
-rw-r--r--test/nosplit.go21
590 files changed, 60113 insertions, 74993 deletions
diff --git a/.hgignore b/.hgignore
index 007116113..a833065f2 100644
--- a/.hgignore
+++ b/.hgignore
@@ -2,13 +2,13 @@ syntax:glob
.DS_Store
.git
.gitignore
-*.[568ao]
-*.a[568o]
+*.[5689ao]
+*.a[5689o]
*.so
*.pyc
._*
.nfs.*
-[568a].out
+[5689a].out
*~
*.orig
*.rej
diff --git a/dev.cc b/dev.cc
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/dev.cc
diff --git a/include/link.h b/include/link.h
index 05e117c87..2b1d02102 100644
--- a/include/link.h
+++ b/include/link.h
@@ -54,7 +54,7 @@ struct Addr
{
char sval[8];
float64 dval;
- Prog* branch; // for 5g, 6g, 8g
+ Prog* branch; // for 5g, 6g, 8g, 9g
} u;
LSym* sym;
@@ -62,9 +62,9 @@ struct Addr
short type;
uint8 index;
int8 scale;
- int8 reg; // for 5l
- int8 name; // for 5l
- int8 class; // for 5l
+ 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
@@ -89,9 +89,14 @@ struct Prog
int32 lineno;
Prog* link;
short as;
- uchar reg; // arm only
- uchar scond; // arm only
+ uchar scond; // arm only; condition codes
+
+ // operands
Addr from;
+ uchar reg; // arm, power64 only (e.g., ADD from, reg, to);
+ // starts at 0 for both GPRs and FPRs;
+ // also used for ADATA width on arm, power64
+ Addr from3; // power64 only (e.g., RLWM/FMADD from, reg, from3, to)
Addr to;
// for 5g, 6g, 8g internal use
@@ -103,11 +108,11 @@ struct Prog
Prog* comefrom; // 6l, 8l
Prog* pcrel; // 5l
int32 spadj;
- uchar mark;
+ uint16 mark;
+ uint16 optab; // 5l, 9l
uchar back; // 6l, 8l
uchar ft; /* 6l, 8l oclass cache */
uchar tt; // 6l, 8l
- uint16 optab; // 5l
uchar isize; // 6l, 8l
char width; /* fake for DATA */
@@ -233,10 +238,12 @@ enum
enum
{
R_ADDR = 1,
+ R_ADDRPOWER, // relocation for loading 31-bit address using addis and addi/ld/st for Power
R_SIZE,
R_CALL, // relocation for direct PC-relative call
R_CALLARM, // relocation for ARM direct call
R_CALLIND, // marker for indirect call (no actual relocating necessary)
+ R_CALLPOWER, // relocation for Power direct call
R_CONST,
R_PCREL,
R_TLS,
@@ -529,6 +536,9 @@ void span6(Link *ctxt, LSym *s);
// asm8.c
void span8(Link *ctxt, LSym *s);
+// asm9.c
+void span9(Link *ctxt, LSym *s);
+
// data.c
vlong addaddr(Link *ctxt, LSym *s, LSym *t);
vlong addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add);
@@ -576,10 +586,11 @@ Prog* copyp(Link*, Prog*);
Prog* appendp(Link*, Prog*);
vlong atolwhex(char*);
-// list[568].c
+// list[5689].c
void listinit5(void);
void listinit6(void);
void listinit8(void);
+void listinit9(void);
// obj.c
int linklinefmt(Link *ctxt, Fmt *fp);
@@ -611,20 +622,30 @@ char* headstr(int);
extern char* anames5[];
extern char* anames6[];
extern char* anames8[];
+extern char* anames9[];
extern char* cnames5[];
+extern char* cnames9[];
+
+extern char* dnames5[];
+extern char* dnames6[];
+extern char* dnames8[];
+extern char* dnames9[];
extern LinkArch link386;
extern LinkArch linkamd64;
extern LinkArch linkamd64p32;
extern LinkArch linkarm;
+extern LinkArch linkpower64;
+extern LinkArch linkpower64le;
#pragma varargck type "A" int
+#pragma varargck type "E" uint
#pragma varargck type "D" Addr*
#pragma varargck type "lD" Addr*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
-#pragma varargck type "^" int
+#pragma varargck type "^" int // for 5l/9l, C_* classes (liblink internal)
// TODO(ality): remove this workaround.
// It's here because Pconv in liblink/list?.c references %L.
diff --git a/lib/codereview/codereview.cfg b/lib/codereview/codereview.cfg
index 2801ebf8d..43dbf3ce3 100644
--- a/lib/codereview/codereview.cfg
+++ b/lib/codereview/codereview.cfg
@@ -1 +1,2 @@
defaultcc: golang-codereviews@googlegroups.com
+contributors: http://go.googlecode.com/hg/CONTRIBUTORS
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
index 416702c63..9181f1df3 100644
--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -3604,11 +3604,17 @@ class MercurialVCS(VersionControlSystem):
if use_hg_shell:
base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath], silent_ok=True)
else:
- base_content = str(self.repo[base_rev][oldrelpath].data())
+ try:
+ base_content = str(self.repo[base_rev][oldrelpath].data())
+ except Exception:
+ pass
is_binary = "\0" in base_content # Mercurial's heuristic
if status != "R":
- new_content = open(relpath, "rb").read()
- is_binary = is_binary or "\0" in new_content
+ try:
+ new_content = open(relpath, "rb").read()
+ is_binary = is_binary or "\0" in new_content
+ except Exception:
+ pass
if is_binary and base_content and use_hg_shell:
# Fetch again without converting newlines
base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
index bb60fe7de..df9838ad3 100644
--- a/src/cmd/5a/a.h
+++ b/src/cmd/5a/a.h
@@ -67,6 +67,7 @@ struct Sym
int32 value;
ushort type;
char *name;
+ char* labelname;
char sym;
};
#define S ((Sym*)0)
@@ -136,6 +137,8 @@ void newio(void);
void newfile(char*, int);
Sym* slookup(char*);
Sym* lookup(void);
+Sym* labellookup(Sym*);
+void settext(LSym*);
void syminit(Sym*);
int32 yylex(void);
int getc(void);
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
index ad647606e..d365c7534 100644
--- a/src/cmd/5a/a.y
+++ b/src/cmd/5a/a.y
@@ -73,15 +73,11 @@ prog:
line
line:
- LLAB ':'
- {
- if($1->value != pc)
- yyerror("redeclaration of %s", $1->name);
- $1->value = pc;
- }
- line
-| LNAME ':'
+ LNAME ':'
{
+ $1 = labellookup($1);
+ if($1->type == LLAB && $1->value != pc)
+ yyerror("redeclaration of %s", $1->labelname);
$1->type = LLAB;
$1->value = pc;
}
@@ -218,18 +214,21 @@ inst:
*/
| LTYPEB name ',' imm
{
+ settext($2.sym);
$4.type = D_CONST2;
$4.offset2 = ArgsSizeUnknown;
outcode($1, Always, &$2, 0, &$4);
}
| LTYPEB name ',' con ',' imm
{
+ settext($2.sym);
$6.type = D_CONST2;
$6.offset2 = ArgsSizeUnknown;
outcode($1, Always, &$2, $4, &$6);
}
| LTYPEB name ',' con ',' imm '-' con
{
+ settext($2.sym);
$6.type = D_CONST2;
$6.offset2 = $8;
outcode($1, Always, &$2, $4, &$6);
@@ -373,15 +372,10 @@ rel:
}
| LNAME offset
{
+ $1 = labellookup($1);
$$ = nullgen;
- if(pass == 2)
- yyerror("undefined label: %s", $1->name);
- $$.type = D_BRANCH;
- $$.offset = $2;
- }
-| LLAB offset
- {
- $$ = nullgen;
+ if(pass == 2 && $1->type != LLAB)
+ yyerror("undefined label: %s", $1->labelname);
$$.type = D_BRANCH;
$$.offset = $1->value + $2;
}
diff --git a/src/cmd/5a/y.tab.c b/src/cmd/5a/y.tab.c
index a6251b835..ace80c7e0 100644
--- a/src/cmd/5a/y.tab.c
+++ b/src/cmd/5a/y.tab.c
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.7.12-4996. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison implementation for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,7 +29,7 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
@@ -44,7 +47,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.7.12-4996"
+#define YYBISON_VERSION "2.3"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -52,55 +55,10 @@
/* Pure parsers. */
#define YYPURE 0
-/* Push parsers. */
-#define YYPUSH 0
-
-/* Pull parsers. */
-#define YYPULL 1
-
-
-
-
-/* Copy the first part of user declarations. */
-/* Line 371 of yacc.c */
-#line 31 "a.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
+/* Using locations. */
+#define YYLSP_NEEDED 0
-/* Line 371 of yacc.c */
-#line 76 "y.tab.c"
-# ifndef YY_NULL
-# if defined __cplusplus && 201103L <= __cplusplus
-# define YY_NULL nullptr
-# else
-# define YY_NULL 0
-# endif
-# endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* In a future release of Bison, this section will be replaced
- by #include "y.tab.h". */
-#ifndef YY_YY_Y_TAB_H_INCLUDED
-# define YY_YY_Y_TAB_H_INCLUDED
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int yydebug;
-#endif
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -210,49 +168,60 @@ extern int yydebug;
+
+/* Copy the first part of user declarations. */
+#line 31 "a.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+#include "../../runtime/funcdata.h"
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-/* Line 387 of yacc.c */
#line 39 "a.y"
-
+{
Sym *sym;
int32 lval;
double dval;
char sval[8];
Addr addr;
-
-
-/* Line 387 of yacc.c */
-#line 228 "y.tab.c"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+}
+/* Line 193 of yacc.c. */
+#line 212 "y.tab.c"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
-extern YYSTYPE yylval;
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-#endif /* !YY_YY_Y_TAB_H_INCLUDED */
/* Copy the second part of user declarations. */
-/* Line 390 of yacc.c */
-#line 256 "y.tab.c"
+
+/* Line 216 of yacc.c. */
+#line 225 "y.tab.c"
#ifdef short
# undef short
@@ -305,45 +274,36 @@ typedef short int yytype_int16;
# if defined YYENABLE_NLS && YYENABLE_NLS
# if ENABLE_NLS
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
# endif
# endif
# ifndef YY_
-# define YY_(Msgid) Msgid
-# endif
-#endif
-
-#ifndef __attribute__
-/* This feature is available in gcc versions 2.5 and later. */
-# if (! defined __GNUC__ || __GNUC__ < 2 \
- || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
-# define __attribute__(Spec) /* empty */
+# define YY_(msgid) msgid
# endif
#endif
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
-# define YYUSE(E) ((void) (E))
+# define YYUSE(e) ((void) (e))
#else
-# define YYUSE(E) /* empty */
+# define YYUSE(e) /* empty */
#endif
-
/* Identity function, used to suppress warnings about constant conditions. */
#ifndef lint
-# define YYID(N) (N)
+# define YYID(n) (n)
#else
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static int
-YYID (int yyi)
+YYID (int i)
#else
static int
-YYID (yyi)
- int yyi;
+YYID (i)
+ int i;
#endif
{
- return yyi;
+ return i;
}
#endif
@@ -364,12 +324,11 @@ YYID (yyi)
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
- /* Use EXIT_SUCCESS as a witness for stdlib.h. */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# endif
@@ -392,24 +351,24 @@ YYID (yyi)
# ifndef YYSTACK_ALLOC_MAXIMUM
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
# endif
-# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+# if (defined __cplusplus && ! defined _STDLIB_H \
&& ! ((defined YYMALLOC || defined malloc) \
&& (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
-# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# ifndef YYFREE
# define YYFREE free
-# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
@@ -425,9 +384,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
/* A type that is properly aligned for any stack member. */
union yyalloc
{
- yytype_int16 yyss_alloc;
- YYSTYPE yyvs_alloc;
-};
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
@@ -438,19 +397,35 @@ union yyalloc
((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
-# define YYCOPY_NEEDED 1
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
/* Relocate STACK from its old location to the new one. The
local variables YYSIZE and YYSTACKSIZE give the old and new number of
elements in the stack, and YYPTR gives the new location of the
stack. Advance YYPTR to a properly aligned location for the next
stack. */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+# define YYSTACK_RELOCATE(Stack) \
do \
{ \
YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
yyptr += yynewbytes / sizeof (*yyptr); \
} \
@@ -458,39 +433,19 @@ union yyalloc
#endif
-#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from SRC to DST. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(Dst, Src, Count) \
- __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
-# else
-# define YYCOPY(Dst, Src, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (Dst)[yyi] = (Src)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-#endif /* !YYCOPY_NEEDED */
-
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 2
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 609
+#define YYLAST 640
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 71
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 35
+#define YYNNTS 34
/* YYNRULES -- Number of rules. */
-#define YYNRULES 133
+#define YYNRULES 130
/* YYNRULES -- Number of states. */
-#define YYNSTATES 339
+#define YYNSTATES 333
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
@@ -540,101 +495,100 @@ static const yytype_uint8 yytranslate[] =
YYRHS. */
static const yytype_uint16 yyprhs[] =
{
- 0, 0, 3, 4, 5, 9, 10, 15, 16, 21,
- 26, 31, 33, 36, 39, 47, 54, 60, 66, 72,
- 77, 82, 86, 90, 95, 102, 110, 118, 126, 133,
- 140, 144, 149, 156, 165, 172, 177, 181, 187, 193,
- 201, 208, 221, 229, 239, 242, 247, 252, 255, 256,
- 259, 262, 263, 266, 271, 274, 277, 280, 283, 288,
- 291, 293, 296, 300, 302, 306, 310, 312, 314, 316,
- 321, 323, 325, 327, 329, 331, 333, 335, 339, 341,
- 346, 348, 353, 355, 357, 359, 361, 364, 366, 372,
- 377, 382, 387, 392, 394, 396, 398, 400, 405, 407,
- 409, 411, 416, 418, 420, 422, 427, 432, 438, 446,
- 447, 450, 453, 455, 457, 459, 461, 463, 466, 469,
- 472, 476, 477, 480, 482, 486, 490, 494, 498, 502,
- 507, 512, 516, 520
+ 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
};
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
static const yytype_int8 yyrhs[] =
{
72, 0, -1, -1, -1, 72, 73, 74, -1, -1,
- 59, 61, 75, 74, -1, -1, 58, 61, 76, 74,
- -1, 58, 62, 105, 63, -1, 60, 62, 105, 63,
- -1, 63, -1, 77, 63, -1, 1, 63, -1, 13,
- 78, 89, 64, 96, 64, 91, -1, 13, 78, 89,
- 64, 96, 64, -1, 13, 78, 89, 64, 91, -1,
- 14, 78, 89, 64, 91, -1, 15, 78, 84, 64,
- 84, -1, 16, 78, 79, 80, -1, 16, 78, 79,
- 85, -1, 35, 79, 86, -1, 17, 79, 80, -1,
- 18, 78, 79, 84, -1, 19, 78, 89, 64, 96,
- 79, -1, 20, 78, 87, 64, 65, 83, 66, -1,
- 20, 78, 65, 83, 66, 64, 87, -1, 21, 78,
- 91, 64, 86, 64, 91, -1, 21, 78, 91, 64,
- 86, 79, -1, 21, 78, 79, 86, 64, 91, -1,
- 22, 78, 79, -1, 23, 100, 64, 90, -1, 23,
- 100, 64, 103, 64, 90, -1, 23, 100, 64, 103,
- 64, 90, 9, 103, -1, 24, 100, 11, 103, 64,
- 81, -1, 25, 78, 91, 79, -1, 28, 79, 81,
- -1, 29, 78, 99, 64, 99, -1, 31, 78, 98,
- 64, 99, -1, 31, 78, 98, 64, 48, 64, 99,
- -1, 32, 78, 99, 64, 99, 79, -1, 30, 78,
- 103, 64, 105, 64, 96, 64, 97, 64, 97, 104,
- -1, 33, 78, 91, 64, 91, 64, 92, -1, 34,
- 78, 91, 64, 91, 64, 91, 64, 96, -1, 36,
- 88, -1, 43, 84, 64, 84, -1, 44, 84, 64,
- 84, -1, 26, 79, -1, -1, 78, 53, -1, 78,
- 54, -1, -1, 64, 79, -1, 103, 67, 41, 68,
- -1, 58, 101, -1, 59, 101, -1, 69, 103, -1,
- 69, 88, -1, 69, 10, 69, 88, -1, 69, 57,
- -1, 82, -1, 69, 56, -1, 69, 9, 56, -1,
- 96, -1, 96, 9, 96, -1, 96, 79, 83, -1,
- 91, -1, 81, -1, 93, -1, 93, 67, 96, 68,
- -1, 51, -1, 52, -1, 103, -1, 88, -1, 99,
- -1, 86, -1, 100, -1, 67, 96, 68, -1, 86,
- -1, 103, 67, 95, 68, -1, 100, -1, 100, 67,
- 95, 68, -1, 87, -1, 91, -1, 90, -1, 93,
- -1, 69, 103, -1, 96, -1, 67, 96, 64, 96,
- 68, -1, 96, 6, 6, 94, -1, 96, 7, 7,
- 94, -1, 96, 9, 7, 94, -1, 96, 55, 7,
- 94, -1, 96, -1, 103, -1, 46, -1, 41, -1,
- 45, 67, 105, 68, -1, 95, -1, 38, -1, 50,
- -1, 49, 67, 105, 68, -1, 99, -1, 82, -1,
- 48, -1, 47, 67, 103, 68, -1, 103, 67, 102,
- 68, -1, 58, 101, 67, 102, 68, -1, 58, 6,
- 7, 101, 67, 39, 68, -1, -1, 8, 103, -1,
- 9, 103, -1, 39, -1, 38, -1, 40, -1, 37,
- -1, 60, -1, 9, 103, -1, 8, 103, -1, 70,
- 103, -1, 67, 105, 68, -1, -1, 64, 105, -1,
- 103, -1, 105, 8, 105, -1, 105, 9, 105, -1,
- 105, 10, 105, -1, 105, 11, 105, -1, 105, 12,
- 105, -1, 105, 6, 6, 105, -1, 105, 7, 7,
- 105, -1, 105, 5, 105, -1, 105, 4, 105, -1,
- 105, 3, 105, -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
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 68, 68, 70, 69, 77, 76, 84, 83, 89,
- 94, 100, 101, 102, 108, 112, 116, 123, 130, 137,
- 141, 148, 155, 162, 169, 176, 185, 197, 201, 205,
- 212, 219, 225, 231, 240, 247, 254, 261, 265, 269,
- 273, 280, 302, 310, 319, 326, 335, 346, 352, 355,
- 359, 364, 365, 368, 374, 382, 389, 395, 400, 405,
- 411, 414, 420, 428, 432, 441, 447, 448, 449, 450,
- 455, 461, 467, 473, 474, 477, 478, 486, 495, 496,
- 505, 506, 512, 515, 516, 517, 519, 527, 535, 544,
- 550, 556, 562, 570, 576, 584, 585, 589, 597, 598,
- 604, 605, 613, 614, 617, 623, 631, 639, 647, 657,
- 660, 664, 670, 671, 672, 675, 676, 680, 684, 688,
- 692, 698, 701, 707, 708, 712, 716, 720, 724, 728,
- 732, 736, 740, 744
+ 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
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE || 0
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
@@ -647,11 +601,11 @@ static const char *const yytname[] =
"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", "$@3", "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", YY_NULL
+ "','", "'['", "']'", "'('", "')'", "'$'", "'~'", "$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
};
#endif
@@ -674,279 +628,282 @@ static const yytype_uint16 yytoknum[] =
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] =
{
- 0, 71, 72, 73, 72, 75, 74, 76, 74, 74,
- 74, 74, 74, 74, 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, 80, 81, 81, 81, 81,
- 81, 82, 82, 83, 83, 83, 84, 84, 84, 84,
- 84, 84, 84, 84, 84, 85, 85, 86, 87, 87,
- 88, 88, 88, 89, 89, 89, 90, 91, 92, 93,
- 93, 93, 93, 94, 94, 95, 95, 95, 96, 96,
- 97, 97, 98, 98, 99, 99, 100, 100, 100, 101,
- 101, 101, 102, 102, 102, 103, 103, 103, 103, 103,
- 103, 104, 104, 105, 105, 105, 105, 105, 105, 105,
- 105, 105, 105, 105
+ 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
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
static const yytype_uint8 yyr2[] =
{
- 0, 2, 0, 0, 3, 0, 4, 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, 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
+ 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
};
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
- Performed when YYTABLE doesn't specify something else to do. Zero
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 2, 3, 1, 0, 0, 48, 48, 48, 48, 51,
- 48, 48, 48, 48, 48, 0, 0, 48, 51, 51,
- 48, 48, 48, 48, 48, 48, 51, 0, 0, 0,
- 0, 0, 0, 11, 4, 0, 13, 0, 0, 0,
- 51, 51, 0, 51, 0, 0, 51, 51, 0, 0,
- 115, 109, 116, 0, 0, 0, 0, 0, 0, 47,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 78,
- 82, 44, 80, 0, 99, 96, 0, 95, 0, 104,
- 70, 71, 0, 67, 60, 0, 73, 66, 68, 98,
- 87, 74, 72, 0, 7, 0, 5, 0, 12, 49,
- 50, 0, 0, 84, 83, 85, 0, 0, 0, 52,
- 109, 109, 22, 0, 0, 0, 0, 0, 0, 0,
- 0, 87, 30, 118, 117, 0, 0, 0, 0, 123,
- 0, 119, 0, 0, 0, 51, 36, 0, 0, 0,
- 103, 0, 102, 0, 0, 0, 0, 21, 0, 0,
- 0, 0, 0, 0, 0, 61, 59, 57, 56, 0,
+ 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,
- 86, 0, 0, 0, 109, 19, 20, 75, 76, 0,
- 54, 55, 0, 23, 0, 0, 51, 0, 0, 0,
- 0, 109, 110, 111, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 120, 31, 0, 113, 112,
- 114, 0, 0, 35, 0, 0, 0, 0, 0, 0,
- 0, 77, 0, 0, 0, 0, 62, 0, 45, 0,
- 0, 0, 0, 0, 46, 8, 9, 6, 10, 16,
- 87, 17, 18, 54, 0, 0, 51, 0, 0, 0,
- 0, 0, 51, 0, 0, 133, 132, 131, 0, 0,
- 124, 125, 126, 127, 128, 0, 106, 0, 37, 0,
- 104, 38, 51, 0, 0, 81, 79, 97, 105, 58,
- 69, 89, 93, 94, 90, 91, 92, 15, 53, 24,
- 0, 64, 65, 0, 29, 51, 28, 0, 107, 129,
- 130, 32, 34, 0, 0, 40, 0, 0, 14, 26,
- 25, 27, 0, 0, 0, 39, 0, 42, 0, 108,
- 33, 0, 0, 0, 0, 100, 0, 0, 43, 0,
- 0, 0, 0, 121, 88, 101, 0, 41, 122
+ 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
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
- -1, 1, 3, 34, 168, 166, 35, 37, 109, 112,
- 83, 84, 185, 85, 176, 69, 70, 86, 102, 103,
- 87, 317, 88, 281, 89, 121, 326, 141, 91, 72,
- 128, 211, 129, 337, 130
+ -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
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -128
+#define YYPACT_NINF -125
static const yytype_int16 yypact[] =
{
- -128, 4, -128, 315, -35, -128, -128, -128, -128, -10,
- -128, -128, -128, -128, -128, 44, 44, -128, -10, -10,
- -128, -128, -128, -128, -128, -128, -10, 416, 371, 371,
- -49, 9, 32, -128, -128, 38, -128, 487, 487, 344,
- 69, -10, 391, 69, 487, 209, 489, 69, 317, 317,
- -128, 49, -128, 317, 317, 42, 48, 106, 67, -128,
- 61, 191, 25, 93, 191, 67, 67, 68, 170, -128,
- -128, -128, 72, 84, -128, -128, 86, -128, 109, -128,
- -128, -128, 233, -128, -128, 80, -128, -128, 115, -128,
- 426, -128, 84, 120, -128, 317, -128, 317, -128, -128,
- -128, 317, 137, -128, -128, -128, 148, 155, 397, -128,
- 74, 74, -128, 164, 371, 204, 240, 207, 206, 68,
- 223, -128, -128, -128, -128, 270, 317, 317, 227, -128,
- 183, -128, 90, 160, 317, -10, -128, 234, 237, 16,
- -128, 254, -128, 255, 256, 257, 240, -128, 212, 168,
- 548, 317, 317, 428, 258, -128, -128, -128, 84, 371,
- 240, 318, 316, 335, 348, 371, 315, 502, 315, 512,
- -128, 240, 240, 371, 49, -128, -128, -128, -128, 289,
- -128, -128, 330, -128, 240, 291, 11, 307, 168, 312,
- 68, 74, -128, -128, 160, 317, 317, 317, 377, 379,
- 317, 317, 317, 317, 317, -128, -128, 324, -128, -128,
- -128, 325, 337, -128, 77, 317, 338, 126, 77, 240,
- 240, -128, 339, 342, 249, 347, -128, 416, -128, 352,
- 170, 170, 170, 170, -128, -128, -128, -128, -128, -128,
- 362, -128, -128, 227, -2, 359, -10, 366, 240, 240,
- 240, 240, 375, 336, 384, 562, 590, 597, 317, 317,
- 213, 213, -128, -128, -128, 385, -128, 61, -128, 357,
- 395, -128, -10, 396, 398, -128, -128, -128, -128, -128,
- -128, -128, -128, -128, -128, -128, -128, 240, -128, -128,
- 434, -128, -128, 400, -128, 432, -128, 424, -128, 436,
- 436, 459, -128, 240, 77, -128, 402, 240, -128, -128,
- -128, -128, 404, 317, 411, -128, 240, -128, 415, -128,
- -128, 216, 418, 240, 413, -128, 421, 240, -128, 317,
- 216, 419, 302, 425, -128, -128, 317, -128, 573
+ -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
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] =
{
- -128, -128, -128, -77, -128, -128, -128, 538, 50, 382,
- -57, 429, 33, -7, -128, -48, -43, -21, 36, -127,
- -23, -128, 29, 17, -101, -28, 161, -128, -37, -8,
- -65, 299, 2, -128, -32
+ -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
};
/* 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 YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -64
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -61
static const yytype_int16 yytable[] =
{
- 90, 90, 117, 136, 2, 206, 71, 55, 57, 90,
- 90, 90, 94, 95, 104, 104, 90, 56, 56, 147,
- 248, 104, 93, 120, 137, 216, 142, 143, 36, 73,
- 92, 92, 107, 48, 49, 135, 208, 209, 210, 245,
- 148, 92, 144, 145, 113, 180, 181, 118, 222, 223,
- 123, 124, 48, 49, 41, 125, 131, 126, 127, 42,
- 177, 157, 50, 167, 138, 169, 105, 105, 59, 60,
- 96, 189, 155, 105, 106, 41, 67, -63, 99, 100,
- 115, 50, 126, 127, 158, 52, 90, 223, 186, 235,
- 108, 237, 53, 114, 97, 54, 119, 122, 48, 49,
- 178, 98, 51, 170, 52, 74, 132, 183, 75, 243,
- 179, 53, 76, 77, 54, 133, 92, 134, 148, 224,
- 99, 100, 99, 100, 78, 79, 253, 50, 192, 193,
- 82, 90, 229, 41, 207, 146, 212, 90, 301, 149,
- 78, 79, 252, 240, 159, 90, 99, 100, 239, 241,
- 52, 150, 228, 151, 225, 124, 246, 53, 234, 101,
- 54, 92, 139, 255, 256, 257, 242, 92, 260, 261,
- 262, 263, 264, 78, 270, 92, 152, 268, 48, 49,
- 271, 272, 160, 269, 165, 213, 195, 196, 197, 198,
- 199, 200, 201, 202, 203, 204, 273, 274, 208, 209,
- 210, 171, 282, 282, 282, 282, 279, 50, 74, 75,
- 302, 75, 172, 76, 77, 76, 77, 48, 49, 173,
- 291, 186, 186, 202, 203, 204, 299, 300, 294, 73,
- 52, 182, 283, 283, 283, 283, 249, 53, 78, 79,
- 54, 48, 153, 154, 99, 100, 50, 309, 284, 285,
- 286, 205, 195, 196, 197, 198, 199, 200, 201, 202,
- 203, 204, 99, 100, 308, 324, 325, 315, 184, 52,
- 50, 187, 311, 188, 116, 314, 68, 191, 74, 54,
- 221, 75, 292, 293, 318, 76, 77, 190, 322, 155,
- 156, 51, 118, 52, 194, 328, 289, 332, 214, 331,
- 68, 215, 296, 54, 338, 195, 196, 197, 198, 199,
- 200, 201, 202, 203, 204, 320, 4, 277, 217, 218,
- 219, 220, 305, 231, 230, 48, 49, 227, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 18, 232, 19, 20, 21, 22, 23, 24, 25,
- 26, 27, 48, 49, 50, 233, 244, 247, 28, 29,
- 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
- 335, 245, 250, 30, 31, 32, 251, 52, 33, 48,
- 49, 50, 74, 258, 53, 75, 259, 54, 265, 76,
- 77, 78, 79, 266, 226, 80, 81, 99, 100, 48,
- 49, 267, 51, 297, 52, 48, 49, 275, 50, 74,
- 276, 68, 75, 82, 54, 278, 76, 77, 78, 79,
- 280, 303, 80, 81, 48, 49, 287, 288, 50, 51,
- 290, 52, 161, 162, 50, 163, 48, 49, 68, 295,
- 82, 54, 48, 49, 200, 201, 202, 203, 204, 110,
- 111, 52, 298, 50, 101, 174, 111, 52, 53, 304,
- 306, 54, 307, 312, 68, 50, 310, 54, 313, 316,
- 74, 50, 319, 75, 51, 321, 52, 76, 77, 323,
- 329, 164, 327, 68, 226, 330, 54, 334, 52, 336,
- 175, 333, 140, 254, 52, 53, 41, 0, 54, 0,
- 0, 68, 0, 0, 54, 195, 196, 197, 198, 199,
- 200, 201, 202, 203, 204, 195, 196, 197, 198, 199,
- 200, 201, 202, 203, 204, 74, 0, 74, 75, 0,
- 75, 0, 76, 77, 76, 77, 0, 0, 0, 0,
- 99, 100, 99, 100, 38, 39, 40, 0, 43, 44,
- 45, 46, 47, 41, 0, 58, 101, 0, 61, 62,
- 63, 64, 65, 66, 0, 236, 196, 197, 198, 199,
- 200, 201, 202, 203, 204, 238, 195, 196, 197, 198,
- 199, 200, 201, 202, 203, 204, 208, 209, 210, 75,
- 0, 0, 0, 76, 77, 197, 198, 199, 200, 201,
- 202, 203, 204, 198, 199, 200, 201, 202, 203, 204
+ 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
};
-#define yypact_value_is_default(Yystate) \
- (!!((Yystate) == (-128)))
-
-#define yytable_value_is_error(Yytable_value) \
- YYID (0)
-
static const yytype_int16 yycheck[] =
{
- 28, 29, 45, 60, 0, 132, 27, 15, 16, 37,
- 38, 39, 61, 62, 37, 38, 44, 15, 16, 67,
- 9, 44, 29, 46, 61, 9, 63, 64, 63, 27,
- 28, 29, 39, 8, 9, 58, 38, 39, 40, 41,
- 68, 39, 65, 66, 42, 110, 111, 45, 149, 150,
- 48, 49, 8, 9, 64, 6, 54, 8, 9, 9,
- 108, 82, 37, 95, 62, 97, 37, 38, 18, 19,
- 61, 119, 56, 44, 38, 64, 26, 66, 53, 54,
- 44, 37, 8, 9, 82, 60, 114, 188, 116, 166,
- 40, 168, 67, 43, 62, 70, 46, 47, 8, 9,
- 108, 63, 58, 101, 60, 38, 64, 114, 41, 174,
- 108, 67, 45, 46, 70, 67, 114, 11, 146, 151,
- 53, 54, 53, 54, 47, 48, 191, 37, 126, 127,
- 69, 159, 160, 64, 132, 67, 134, 165, 265, 67,
- 47, 48, 190, 171, 64, 173, 53, 54, 171, 172,
- 60, 67, 159, 67, 152, 153, 184, 67, 165, 69,
- 70, 159, 69, 195, 196, 197, 173, 165, 200, 201,
- 202, 203, 204, 47, 48, 173, 67, 214, 8, 9,
- 217, 218, 67, 215, 64, 135, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 219, 220, 38, 39,
- 40, 64, 230, 231, 232, 233, 227, 37, 38, 41,
- 267, 41, 64, 45, 46, 45, 46, 8, 9, 64,
- 248, 249, 250, 10, 11, 12, 258, 259, 251, 227,
- 60, 67, 230, 231, 232, 233, 186, 67, 47, 48,
- 70, 8, 9, 10, 53, 54, 37, 290, 231, 232,
- 233, 68, 3, 4, 5, 6, 7, 8, 9, 10,
- 11, 12, 53, 54, 287, 49, 50, 304, 64, 60,
- 37, 64, 295, 67, 65, 303, 67, 7, 38, 70,
- 68, 41, 249, 250, 307, 45, 46, 64, 316, 56,
- 57, 58, 290, 60, 67, 323, 246, 329, 64, 327,
- 67, 64, 252, 70, 336, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 313, 1, 68, 64, 64,
- 64, 64, 272, 7, 6, 8, 9, 69, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 7, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 8, 9, 37, 7, 67, 66, 43, 44,
+ 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,
- 68, 41, 65, 58, 59, 60, 64, 60, 63, 8,
- 9, 37, 38, 6, 67, 41, 7, 70, 64, 45,
- 46, 47, 48, 68, 56, 51, 52, 53, 54, 8,
- 9, 64, 58, 67, 60, 8, 9, 68, 37, 38,
- 68, 67, 41, 69, 70, 68, 45, 46, 47, 48,
- 68, 64, 51, 52, 8, 9, 64, 68, 37, 58,
- 64, 60, 6, 7, 37, 9, 8, 9, 67, 64,
- 69, 70, 8, 9, 8, 9, 10, 11, 12, 58,
- 59, 60, 68, 37, 69, 58, 59, 60, 67, 64,
- 64, 70, 64, 39, 67, 37, 66, 70, 9, 67,
- 38, 37, 68, 41, 58, 64, 60, 45, 46, 64,
- 67, 55, 64, 67, 56, 64, 70, 68, 60, 64,
- 108, 330, 63, 194, 60, 67, 64, -1, 70, -1,
+ 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, 38, -1, 38, 41, -1,
- 41, -1, 45, 46, 45, 46, -1, -1, -1, -1,
- 53, 54, 53, 54, 6, 7, 8, -1, 10, 11,
- 12, 13, 14, 64, -1, 17, 69, -1, 20, 21,
+ 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, 38, 39, 40, 41,
- -1, -1, -1, 45, 46, 5, 6, 7, 8, 9,
- 10, 11, 12, 6, 7, 8, 9, 10, 11, 12
+ 7, 8, 9, 10, 11, 12, 5, 6, 7, 8,
+ 9, 10, 11, 12, 6, 7, 8, 9, 10, 11,
+ 12
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -956,37 +913,37 @@ 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, 59, 60, 63, 74, 77, 63, 78, 78, 78,
- 78, 64, 79, 78, 78, 78, 78, 78, 8, 9,
- 37, 58, 60, 67, 70, 100, 103, 100, 78, 79,
- 79, 78, 78, 78, 78, 78, 78, 79, 67, 86,
- 87, 88, 100, 103, 38, 41, 45, 46, 47, 48,
- 51, 52, 69, 81, 82, 84, 88, 91, 93, 95,
- 96, 99, 103, 84, 61, 62, 61, 62, 63, 53,
- 54, 69, 89, 90, 91, 93, 89, 84, 79, 79,
- 58, 59, 80, 103, 79, 89, 65, 87, 103, 79,
- 91, 96, 79, 103, 103, 6, 8, 9, 101, 103,
- 105, 103, 64, 67, 11, 91, 81, 99, 103, 69,
- 82, 98, 99, 99, 91, 91, 67, 86, 96, 67,
- 67, 67, 67, 9, 10, 56, 57, 88, 103, 64,
- 67, 6, 7, 9, 55, 64, 76, 105, 75, 105,
- 103, 64, 64, 64, 58, 80, 85, 86, 100, 103,
- 101, 101, 67, 84, 64, 83, 96, 64, 67, 86,
- 64, 7, 103, 103, 67, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 68, 90, 103, 38, 39,
- 40, 102, 103, 79, 64, 64, 9, 64, 64, 64,
- 64, 68, 95, 95, 105, 103, 56, 69, 84, 96,
- 6, 7, 7, 7, 84, 74, 63, 74, 63, 91,
- 96, 91, 84, 101, 67, 41, 96, 66, 9, 79,
- 65, 64, 86, 101, 102, 105, 105, 105, 6, 7,
- 105, 105, 105, 105, 105, 64, 68, 64, 99, 105,
- 48, 99, 99, 91, 91, 68, 68, 68, 68, 88,
- 68, 94, 96, 103, 94, 94, 94, 64, 68, 79,
- 64, 96, 83, 83, 91, 64, 79, 67, 68, 105,
- 105, 90, 81, 64, 64, 79, 64, 64, 91, 87,
- 66, 91, 39, 9, 96, 99, 67, 92, 91, 68,
- 103, 64, 96, 64, 49, 50, 97, 64, 96, 67,
- 64, 96, 105, 97, 68, 68, 64, 104, 105
+ 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
};
#define yyerrok (yyerrstatus = 0)
@@ -1001,50 +958,78 @@ static const yytype_uint8 yystos[] =
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. However,
- YYFAIL appears to be in use. Nevertheless, it is formally deprecated
- in Bison 2.4.2's NEWS entry, where a plan to phase it out is
- discussed. */
+ Once GCC version 2 has supplanted version 1, this can go. */
#define YYFAIL goto yyerrlab
-#if defined YYFAIL
- /* This is here to suppress warnings from the GCC cpp's
- -Wunused-macros. Normally we don't worry about that warning, but
- some users do, and we want to make it easy for users to remove
- YYFAIL uses, which will produce warnings from Bison 2.5. */
-#endif
#define YYRECOVERING() (!!yyerrstatus)
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- YYPOPSTACK (yylen); \
- yystate = *yyssp; \
- goto yybackup; \
- } \
- else \
- { \
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
yyerror (YY_("syntax error: cannot back up")); \
YYERROR; \
} \
while (YYID (0))
-/* Error token number */
+
#define YYTERROR 1
#define YYERRCODE 256
-/* This macro is provided for backward compatibility. */
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
#endif
/* YYLEX -- calling `yylex' with the right arguments. */
+
#ifdef YYLEX_PARAM
# define YYLEX yylex (YYLEX_PARAM)
#else
@@ -1094,8 +1079,6 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
YYSTYPE const * const yyvaluep;
#endif
{
- FILE *yyo = yyoutput;
- YYUSE (yyo);
if (!yyvaluep)
return;
# ifdef YYPRINT
@@ -1104,7 +1087,11 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
# else
YYUSE (yyoutput);
# endif
- YYUSE (yytype);
+ switch (yytype)
+ {
+ default:
+ break;
+ }
}
@@ -1141,20 +1128,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep)
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
#else
static void
-yy_stack_print (yybottom, yytop)
- yytype_int16 *yybottom;
- yytype_int16 *yytop;
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
#endif
{
YYFPRINTF (stderr, "Stack now");
- for (; yybottom <= yytop; yybottom++)
- {
- int yybot = *yybottom;
- YYFPRINTF (stderr, " %d", yybot);
- }
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
YYFPRINTF (stderr, "\n");
}
@@ -1188,11 +1172,11 @@ yy_reduce_print (yyvsp, yyrule)
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
- YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ fprintf (stderr, " $%d = ", yyi + 1);
yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
&(yyvsp[(yyi + 1) - (yynrhs)])
);
- YYFPRINTF (stderr, "\n");
+ fprintf (stderr, "\n");
}
}
@@ -1229,6 +1213,7 @@ int yydebug;
# define YYMAXDEPTH 10000
#endif
+
#if YYERROR_VERBOSE
@@ -1331,145 +1316,115 @@ yytnamerr (char *yyres, const char *yystr)
}
# endif
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
- about the unexpected token YYTOKEN for the state stack whose top is
- YYSSP.
-
- Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
- not large enough to hold the message. In that case, also set
- *YYMSG_ALLOC to the required number of bytes. Return 2 if the
- required number of bytes is too large to store. */
-static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
- yytype_int16 *yyssp, int yytoken)
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
{
- YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
- YYSIZE_T yysize = yysize0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- /* Internationalized format string. */
- const char *yyformat = YY_NULL;
- /* Arguments of yyformat. */
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- /* Number of reported tokens (one for the "unexpected", one per
- "expected"). */
- int yycount = 0;
-
- /* There are many possibilities here to consider:
- - Assume YYFAIL is not used. It's too flawed to consider. See
- <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
- for details. YYERROR is fine as it does not invoke this
- function.
- - If this state is a consistent state with a default action, then
- the only way this function was invoked is if the default action
- is an error action. In that case, don't check for expected
- tokens because there are none.
- - The only way there can be no lookahead present (in yychar) is if
- this state is a consistent state with a default action. Thus,
- detecting the absence of a lookahead is sufficient to determine
- that there is no unexpected or expected token to report. In that
- case, just report a simple "syntax error".
- - Don't assume there isn't a lookahead just because this state is a
- consistent state with a default action. There might have been a
- previous inconsistent state, consistent state with a non-default
- action, or user semantic action that manipulated yychar.
- - Of course, the expected token list depends on states to have
- correct lookahead information, and it depends on the parser not
- to perform extra reductions after fetching a lookahead from the
- scanner and before detecting a syntax error. Thus, state merging
- (from LALR or IELR) and default reductions corrupt the expected
- token list. However, the list is correct for canonical LR with
- one exception: it will still contain any token that will not be
- accepted due to an error action in a later state.
- */
- if (yytoken != YYEMPTY)
- {
- int yyn = yypact[*yyssp];
- yyarg[yycount++] = yytname[yytoken];
- if (!yypact_value_is_default (yyn))
- {
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. In other words, skip the first -YYN actions for
- this state because they are default actions. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yyx;
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
- && !yytable_value_is_error (yytable[yyx + yyn]))
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- {
- YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
- }
- }
- }
- }
+ int yyn = yypact[yystate];
- switch (yycount)
- {
-# define YYCASE_(N, S) \
- case N: \
- yyformat = S; \
- break
- YYCASE_(0, YY_("syntax error"));
- YYCASE_(1, YY_("syntax error, unexpected %s"));
- YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
- YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
- YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
- YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
- }
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
- {
- YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
- }
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
- if (*yymsg_alloc < yysize)
- {
- *yymsg_alloc = 2 * yysize;
- if (! (yysize <= *yymsg_alloc
- && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
- *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
- return 1;
- }
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- {
- char *yyp = *yymsg;
- int yyi = 0;
- while ((*yyp = *yyformat) != '\0')
- if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyformat += 2;
- }
- else
- {
- yyp++;
- yyformat++;
- }
- }
- return 0;
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
}
#endif /* YYERROR_VERBOSE */
+
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
@@ -1494,31 +1449,44 @@ yydestruct (yymsg, yytype, yyvaluep)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
- YYUSE (yytype);
-}
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+/* Prevent warnings from -Wmissing-prototypes. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
-/* The lookahead symbol. */
-int yychar;
-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
-#endif
-#ifndef YY_INITIAL_VALUE
-# define YY_INITIAL_VALUE(Value) /* Nothing. */
-#endif
+/* The look-ahead symbol. */
+int yychar;
-/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
/* Number of syntax errors so far. */
int yynerrs;
+
/*----------.
| yyparse. |
`----------*/
@@ -1545,37 +1513,14 @@ yyparse ()
#endif
#endif
{
- int yystate;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
-
- /* The stacks and their tools:
- `yyss': related to states.
- `yyvs': related to semantic values.
-
- Refer to the stacks through separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs;
- YYSTYPE *yyvsp;
-
- YYSIZE_T yystacksize;
-
+
+ int yystate;
int yyn;
int yyresult;
- /* Lookahead token as an internal (translated) token number. */
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
int yytoken = 0;
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
#if YYERROR_VERBOSE
/* Buffer for error messages, and its allocated size. */
char yymsgbuf[128];
@@ -1583,22 +1528,54 @@ yyparse ()
YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
#endif
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
/* The number of symbols on the RHS of the reduced rule.
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yyssp = yyss = yyssa;
- yyvsp = yyvs = yyvsa;
- yystacksize = YYINITDEPTH;
-
YYDPRINTF ((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
goto yysetstate;
/*------------------------------------------------------------.
@@ -1625,6 +1602,7 @@ yyparse ()
YYSTYPE *yyvs1 = yyvs;
yytype_int16 *yyss1 = yyss;
+
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
@@ -1632,6 +1610,7 @@ yyparse ()
yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
+
&yystacksize);
yyss = yyss1;
@@ -1654,8 +1633,9 @@ yyparse ()
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
@@ -1666,6 +1646,7 @@ yyparse ()
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
+
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
(unsigned long int) yystacksize));
@@ -1675,9 +1656,6 @@ yyparse ()
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
- if (yystate == YYFINAL)
- YYACCEPT;
-
goto yybackup;
/*-----------.
@@ -1686,16 +1664,16 @@ yyparse ()
yybackup:
/* Do appropriate processing given the current state. Read a
- lookahead token if we need one and don't already have one. */
+ look-ahead token if we need one and don't already have one. */
- /* First try to decide what to do without reference to lookahead token. */
+ /* First try to decide what to do without reference to look-ahead token. */
yyn = yypact[yystate];
- if (yypact_value_is_default (yyn))
+ if (yyn == YYPACT_NINF)
goto yydefault;
- /* Not known => get a lookahead token if don't already have one. */
+ /* Not known => get a look-ahead token if don't already have one. */
- /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
if (yychar == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token: "));
@@ -1721,27 +1699,29 @@ yybackup:
yyn = yytable[yyn];
if (yyn <= 0)
{
- if (yytable_value_is_error (yyn))
- goto yyerrlab;
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
- /* Shift the lookahead token. */
+ /* Shift the look-ahead token. */
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
- /* Discard the shifted token. */
- yychar = YYEMPTY;
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
yystate = yyn;
- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
- YY_IGNORE_MAYBE_UNINITIALIZED_END
goto yynewstate;
@@ -1778,7 +1758,6 @@ yyreduce:
switch (yyn)
{
case 3:
-/* Line 1787 of yacc.c */
#line 70 "a.y"
{
stmtline = lineno;
@@ -1786,36 +1765,26 @@ yyreduce:
break;
case 5:
-/* Line 1787 of yacc.c */
#line 77 "a.y"
{
- if((yyvsp[(1) - (2)].sym)->value != pc)
- yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
- (yyvsp[(1) - (2)].sym)->value = pc;
- }
- break;
-
- case 7:
-/* Line 1787 of yacc.c */
-#line 84 "a.y"
- {
+ (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
+ if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc)
+ yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->labelname);
(yyvsp[(1) - (2)].sym)->type = LLAB;
(yyvsp[(1) - (2)].sym)->value = pc;
}
break;
- case 9:
-/* Line 1787 of yacc.c */
-#line 90 "a.y"
+ case 7:
+#line 86 "a.y"
{
(yyvsp[(1) - (4)].sym)->type = LVAR;
(yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
}
break;
- case 10:
-/* Line 1787 of yacc.c */
-#line 95 "a.y"
+ case 8:
+#line 91 "a.y"
{
if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval))
yyerror("redeclaration of %s", (yyvsp[(1) - (4)].sym)->name);
@@ -1823,97 +1792,85 @@ yyreduce:
}
break;
- case 14:
-/* Line 1787 of yacc.c */
-#line 109 "a.y"
+ case 12:
+#line 105 "a.y"
{
outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr));
}
break;
- case 15:
-/* Line 1787 of yacc.c */
-#line 113 "a.y"
+ case 13:
+#line 109 "a.y"
{
outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen);
}
break;
- case 16:
-/* Line 1787 of yacc.c */
-#line 117 "a.y"
+ case 14:
+#line 113 "a.y"
{
outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
}
break;
- case 17:
-/* Line 1787 of yacc.c */
-#line 124 "a.y"
+ case 15:
+#line 120 "a.y"
{
outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
}
break;
- case 18:
-/* Line 1787 of yacc.c */
-#line 131 "a.y"
+ case 16:
+#line 127 "a.y"
{
outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
}
break;
- case 19:
-/* Line 1787 of yacc.c */
-#line 138 "a.y"
+ case 17:
+#line 134 "a.y"
{
outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
}
break;
- case 20:
-/* Line 1787 of yacc.c */
-#line 142 "a.y"
+ case 18:
+#line 138 "a.y"
{
outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
}
break;
- case 21:
-/* Line 1787 of yacc.c */
-#line 149 "a.y"
+ case 19:
+#line 145 "a.y"
{
outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
}
break;
- case 22:
-/* Line 1787 of yacc.c */
-#line 156 "a.y"
+ case 20:
+#line 152 "a.y"
{
outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
}
break;
- case 23:
-/* Line 1787 of yacc.c */
-#line 163 "a.y"
+ case 21:
+#line 159 "a.y"
{
outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
}
break;
- case 24:
-/* Line 1787 of yacc.c */
-#line 170 "a.y"
+ case 22:
+#line 166 "a.y"
{
outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen);
}
break;
- case 25:
-/* Line 1787 of yacc.c */
-#line 177 "a.y"
+ case 23:
+#line 173 "a.y"
{
Addr g;
@@ -1924,9 +1881,8 @@ yyreduce:
}
break;
- case 26:
-/* Line 1787 of yacc.c */
-#line 186 "a.y"
+ case 24:
+#line 182 "a.y"
{
Addr g;
@@ -1937,127 +1893,115 @@ yyreduce:
}
break;
- case 27:
-/* Line 1787 of yacc.c */
-#line 198 "a.y"
+ case 25:
+#line 194 "a.y"
{
outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(5) - (7)].addr), (yyvsp[(3) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr));
}
break;
- case 28:
-/* Line 1787 of yacc.c */
-#line 202 "a.y"
+ case 26:
+#line 198 "a.y"
{
outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr), (yyvsp[(3) - (6)].addr).reg, &(yyvsp[(3) - (6)].addr));
}
break;
- case 29:
-/* Line 1787 of yacc.c */
-#line 206 "a.y"
+ case 27:
+#line 202 "a.y"
{
outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(4) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr));
}
break;
- case 30:
-/* Line 1787 of yacc.c */
-#line 213 "a.y"
+ case 28:
+#line 209 "a.y"
{
outcode((yyvsp[(1) - (3)].lval), (yyvsp[(2) - (3)].lval), &nullgen, NREG, &nullgen);
}
break;
- case 31:
-/* Line 1787 of yacc.c */
-#line 220 "a.y"
+ 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));
}
break;
- case 32:
-/* Line 1787 of yacc.c */
-#line 226 "a.y"
+ case 30:
+#line 223 "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));
}
break;
- case 33:
-/* Line 1787 of yacc.c */
-#line 232 "a.y"
+ case 31:
+#line 230 "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));
}
break;
- case 34:
-/* Line 1787 of yacc.c */
-#line 241 "a.y"
+ case 32:
+#line 240 "a.y"
{
outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
}
break;
- case 35:
-/* Line 1787 of yacc.c */
-#line 248 "a.y"
+ case 33:
+#line 247 "a.y"
{
outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].addr), NREG, &nullgen);
}
break;
- case 36:
-/* Line 1787 of yacc.c */
-#line 255 "a.y"
+ case 34:
+#line 254 "a.y"
{
outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
}
break;
- case 37:
-/* Line 1787 of yacc.c */
-#line 262 "a.y"
+ case 35:
+#line 261 "a.y"
{
outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
}
break;
- case 38:
-/* Line 1787 of yacc.c */
-#line 266 "a.y"
+ case 36:
+#line 265 "a.y"
{
outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
}
break;
- case 39:
-/* Line 1787 of yacc.c */
-#line 270 "a.y"
+ case 37:
+#line 269 "a.y"
{
outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr));
}
break;
- case 40:
-/* Line 1787 of yacc.c */
-#line 274 "a.y"
+ case 38:
+#line 273 "a.y"
{
outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr).reg, &nullgen);
}
break;
- case 41:
-/* Line 1787 of yacc.c */
-#line 281 "a.y"
+ case 39:
+#line 280 "a.y"
{
Addr g;
@@ -2078,17 +2022,15 @@ yyreduce:
}
break;
- case 42:
-/* Line 1787 of yacc.c */
-#line 303 "a.y"
+ case 40:
+#line 302 "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 43:
-/* Line 1787 of yacc.c */
-#line 311 "a.y"
+ case 41:
+#line 310 "a.y"
{
(yyvsp[(7) - (9)].addr).type = D_REGREG2;
(yyvsp[(7) - (9)].addr).offset = (yyvsp[(9) - (9)].lval);
@@ -2096,17 +2038,15 @@ yyreduce:
}
break;
- case 44:
-/* Line 1787 of yacc.c */
-#line 320 "a.y"
+ case 42:
+#line 319 "a.y"
{
outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
}
break;
- case 45:
-/* Line 1787 of yacc.c */
-#line 327 "a.y"
+ case 43:
+#line 326 "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");
@@ -2114,9 +2054,8 @@ yyreduce:
}
break;
- case 46:
-/* Line 1787 of yacc.c */
-#line 336 "a.y"
+ case 44:
+#line 335 "a.y"
{
if((yyvsp[(2) - (4)].addr).type != D_CONST)
yyerror("index for FUNCDATA must be integer constant");
@@ -2126,41 +2065,36 @@ yyreduce:
}
break;
- case 47:
-/* Line 1787 of yacc.c */
-#line 347 "a.y"
+ case 45:
+#line 346 "a.y"
{
outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, NREG, &nullgen);
}
break;
- case 48:
-/* Line 1787 of yacc.c */
-#line 352 "a.y"
+ case 46:
+#line 351 "a.y"
{
(yyval.lval) = Always;
}
break;
- case 49:
-/* Line 1787 of yacc.c */
-#line 356 "a.y"
+ case 47:
+#line 355 "a.y"
{
(yyval.lval) = ((yyvsp[(1) - (2)].lval) & ~C_SCOND) | (yyvsp[(2) - (2)].lval);
}
break;
- case 50:
-/* Line 1787 of yacc.c */
-#line 360 "a.y"
+ case 48:
+#line 359 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (2)].lval) | (yyvsp[(2) - (2)].lval);
}
break;
- case 53:
-/* Line 1787 of yacc.c */
-#line 369 "a.y"
+ case 51:
+#line 368 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_BRANCH;
@@ -2168,31 +2102,20 @@ yyreduce:
}
break;
- case 54:
-/* Line 1787 of yacc.c */
-#line 375 "a.y"
- {
- (yyval.addr) = nullgen;
- if(pass == 2)
- yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
- (yyval.addr).type = D_BRANCH;
- (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 55:
-/* Line 1787 of yacc.c */
-#line 383 "a.y"
+ case 52:
+#line 374 "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).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
}
break;
- case 56:
-/* Line 1787 of yacc.c */
-#line 390 "a.y"
+ case 53:
+#line 384 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_CONST;
@@ -2200,27 +2123,24 @@ yyreduce:
}
break;
- case 57:
-/* Line 1787 of yacc.c */
-#line 396 "a.y"
+ case 54:
+#line 390 "a.y"
{
(yyval.addr) = (yyvsp[(2) - (2)].addr);
(yyval.addr).type = D_CONST;
}
break;
- case 58:
-/* Line 1787 of yacc.c */
-#line 401 "a.y"
+ case 55:
+#line 395 "a.y"
{
(yyval.addr) = (yyvsp[(4) - (4)].addr);
(yyval.addr).type = D_OCONST;
}
break;
- case 59:
-/* Line 1787 of yacc.c */
-#line 406 "a.y"
+ case 56:
+#line 400 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_SCONST;
@@ -2228,9 +2148,8 @@ yyreduce:
}
break;
- case 61:
-/* Line 1787 of yacc.c */
-#line 415 "a.y"
+ case 58:
+#line 409 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FCONST;
@@ -2238,9 +2157,8 @@ yyreduce:
}
break;
- case 62:
-/* Line 1787 of yacc.c */
-#line 421 "a.y"
+ case 59:
+#line 415 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FCONST;
@@ -2248,17 +2166,15 @@ yyreduce:
}
break;
- case 63:
-/* Line 1787 of yacc.c */
-#line 429 "a.y"
+ case 60:
+#line 423 "a.y"
{
(yyval.lval) = 1 << (yyvsp[(1) - (1)].lval);
}
break;
- case 64:
-/* Line 1787 of yacc.c */
-#line 433 "a.y"
+ case 61:
+#line 427 "a.y"
{
int i;
(yyval.lval)=0;
@@ -2269,26 +2185,23 @@ yyreduce:
}
break;
- case 65:
-/* Line 1787 of yacc.c */
-#line 442 "a.y"
+ case 62:
+#line 436 "a.y"
{
(yyval.lval) = (1<<(yyvsp[(1) - (3)].lval)) | (yyvsp[(3) - (3)].lval);
}
break;
- case 69:
-/* Line 1787 of yacc.c */
-#line 451 "a.y"
+ case 66:
+#line 445 "a.y"
{
(yyval.addr) = (yyvsp[(1) - (4)].addr);
(yyval.addr).reg = (yyvsp[(3) - (4)].lval);
}
break;
- case 70:
-/* Line 1787 of yacc.c */
-#line 456 "a.y"
+ case 67:
+#line 450 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_PSR;
@@ -2296,9 +2209,8 @@ yyreduce:
}
break;
- case 71:
-/* Line 1787 of yacc.c */
-#line 462 "a.y"
+ case 68:
+#line 456 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FPCR;
@@ -2306,9 +2218,8 @@ yyreduce:
}
break;
- case 72:
-/* Line 1787 of yacc.c */
-#line 468 "a.y"
+ case 69:
+#line 462 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_OREG;
@@ -2316,9 +2227,8 @@ yyreduce:
}
break;
- case 76:
-/* Line 1787 of yacc.c */
-#line 479 "a.y"
+ case 73:
+#line 473 "a.y"
{
(yyval.addr) = (yyvsp[(1) - (1)].addr);
if((yyvsp[(1) - (1)].addr).name != D_EXTERN && (yyvsp[(1) - (1)].addr).name != D_STATIC) {
@@ -2326,9 +2236,8 @@ yyreduce:
}
break;
- case 77:
-/* Line 1787 of yacc.c */
-#line 487 "a.y"
+ case 74:
+#line 481 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_OREG;
@@ -2337,9 +2246,8 @@ yyreduce:
}
break;
- case 79:
-/* Line 1787 of yacc.c */
-#line 497 "a.y"
+ case 76:
+#line 491 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_OREG;
@@ -2348,9 +2256,8 @@ yyreduce:
}
break;
- case 81:
-/* Line 1787 of yacc.c */
-#line 507 "a.y"
+ case 78:
+#line 501 "a.y"
{
(yyval.addr) = (yyvsp[(1) - (4)].addr);
(yyval.addr).type = D_OREG;
@@ -2358,9 +2265,8 @@ yyreduce:
}
break;
- case 86:
-/* Line 1787 of yacc.c */
-#line 520 "a.y"
+ case 83:
+#line 514 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_CONST;
@@ -2368,9 +2274,8 @@ yyreduce:
}
break;
- case 87:
-/* Line 1787 of yacc.c */
-#line 528 "a.y"
+ case 84:
+#line 522 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_REG;
@@ -2378,9 +2283,8 @@ yyreduce:
}
break;
- case 88:
-/* Line 1787 of yacc.c */
-#line 536 "a.y"
+ case 85:
+#line 530 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_REGREG;
@@ -2389,9 +2293,8 @@ yyreduce:
}
break;
- case 89:
-/* Line 1787 of yacc.c */
-#line 545 "a.y"
+ case 86:
+#line 539 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_SHIFT;
@@ -2399,9 +2302,8 @@ yyreduce:
}
break;
- case 90:
-/* Line 1787 of yacc.c */
-#line 551 "a.y"
+ case 87:
+#line 545 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_SHIFT;
@@ -2409,9 +2311,8 @@ yyreduce:
}
break;
- case 91:
-/* Line 1787 of yacc.c */
-#line 557 "a.y"
+ case 88:
+#line 551 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_SHIFT;
@@ -2419,9 +2320,8 @@ yyreduce:
}
break;
- case 92:
-/* Line 1787 of yacc.c */
-#line 563 "a.y"
+ case 89:
+#line 557 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_SHIFT;
@@ -2429,9 +2329,8 @@ yyreduce:
}
break;
- case 93:
-/* Line 1787 of yacc.c */
-#line 571 "a.y"
+ case 90:
+#line 565 "a.y"
{
if((yyval.lval) < 0 || (yyval.lval) >= 16)
print("register value out of range\n");
@@ -2439,9 +2338,8 @@ yyreduce:
}
break;
- case 94:
-/* Line 1787 of yacc.c */
-#line 577 "a.y"
+ case 91:
+#line 571 "a.y"
{
if((yyval.lval) < 0 || (yyval.lval) >= 32)
print("shift value out of range\n");
@@ -2449,17 +2347,15 @@ yyreduce:
}
break;
- case 96:
-/* Line 1787 of yacc.c */
-#line 586 "a.y"
+ case 93:
+#line 580 "a.y"
{
(yyval.lval) = REGPC;
}
break;
- case 97:
-/* Line 1787 of yacc.c */
-#line 590 "a.y"
+ case 94:
+#line 584 "a.y"
{
if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
print("register value out of range\n");
@@ -2467,17 +2363,15 @@ yyreduce:
}
break;
- case 99:
-/* Line 1787 of yacc.c */
-#line 599 "a.y"
+ case 96:
+#line 593 "a.y"
{
(yyval.lval) = REGSP;
}
break;
- case 101:
-/* Line 1787 of yacc.c */
-#line 606 "a.y"
+ case 98:
+#line 600 "a.y"
{
if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
print("register value out of range\n");
@@ -2485,9 +2379,8 @@ yyreduce:
}
break;
- case 104:
-/* Line 1787 of yacc.c */
-#line 618 "a.y"
+ case 101:
+#line 612 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FREG;
@@ -2495,9 +2388,8 @@ yyreduce:
}
break;
- case 105:
-/* Line 1787 of yacc.c */
-#line 624 "a.y"
+ case 102:
+#line 618 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FREG;
@@ -2505,9 +2397,8 @@ yyreduce:
}
break;
- case 106:
-/* Line 1787 of yacc.c */
-#line 632 "a.y"
+ case 103:
+#line 626 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_OREG;
@@ -2517,9 +2408,8 @@ yyreduce:
}
break;
- case 107:
-/* Line 1787 of yacc.c */
-#line 640 "a.y"
+ case 104:
+#line 634 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_OREG;
@@ -2529,9 +2419,8 @@ yyreduce:
}
break;
- case 108:
-/* Line 1787 of yacc.c */
-#line 648 "a.y"
+ case 105:
+#line 642 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_OREG;
@@ -2541,182 +2430,151 @@ yyreduce:
}
break;
- case 109:
-/* Line 1787 of yacc.c */
-#line 657 "a.y"
+ case 106:
+#line 651 "a.y"
{
(yyval.lval) = 0;
}
break;
- case 110:
-/* Line 1787 of yacc.c */
-#line 661 "a.y"
+ case 107:
+#line 655 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
- case 111:
-/* Line 1787 of yacc.c */
-#line 665 "a.y"
+ case 108:
+#line 659 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
- case 116:
-/* Line 1787 of yacc.c */
-#line 677 "a.y"
+ case 113:
+#line 671 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
}
break;
- case 117:
-/* Line 1787 of yacc.c */
-#line 681 "a.y"
+ case 114:
+#line 675 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
- case 118:
-/* Line 1787 of yacc.c */
-#line 685 "a.y"
+ case 115:
+#line 679 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
- case 119:
-/* Line 1787 of yacc.c */
-#line 689 "a.y"
+ case 116:
+#line 683 "a.y"
{
(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
}
break;
- case 120:
-/* Line 1787 of yacc.c */
-#line 693 "a.y"
+ case 117:
+#line 687 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (3)].lval);
}
break;
- case 121:
-/* Line 1787 of yacc.c */
-#line 698 "a.y"
+ case 118:
+#line 692 "a.y"
{
(yyval.lval) = 0;
}
break;
- case 122:
-/* Line 1787 of yacc.c */
-#line 702 "a.y"
+ case 119:
+#line 696 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
- case 124:
-/* Line 1787 of yacc.c */
-#line 709 "a.y"
+ case 121:
+#line 703 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
}
break;
- case 125:
-/* Line 1787 of yacc.c */
-#line 713 "a.y"
+ case 122:
+#line 707 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
}
break;
- case 126:
-/* Line 1787 of yacc.c */
-#line 717 "a.y"
+ case 123:
+#line 711 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
}
break;
- case 127:
-/* Line 1787 of yacc.c */
-#line 721 "a.y"
+ case 124:
+#line 715 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
}
break;
- case 128:
-/* Line 1787 of yacc.c */
-#line 725 "a.y"
+ case 125:
+#line 719 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
}
break;
- case 129:
-/* Line 1787 of yacc.c */
-#line 729 "a.y"
+ case 126:
+#line 723 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
}
break;
- case 130:
-/* Line 1787 of yacc.c */
-#line 733 "a.y"
+ case 127:
+#line 727 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
}
break;
- case 131:
-/* Line 1787 of yacc.c */
-#line 737 "a.y"
+ case 128:
+#line 731 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
}
break;
- case 132:
-/* Line 1787 of yacc.c */
-#line 741 "a.y"
+ case 129:
+#line 735 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
}
break;
- case 133:
-/* Line 1787 of yacc.c */
-#line 745 "a.y"
+ case 130:
+#line 739 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
}
break;
-/* Line 1787 of yacc.c */
-#line 2707 "y.tab.c"
+/* Line 1267 of yacc.c. */
+#line 2576 "y.tab.c"
default: break;
}
- /* User semantic actions sometimes alter yychar, and that requires
- that yytoken be updated with the new translation. We take the
- approach of translating immediately before every use of yytoken.
- One alternative is translating here after every semantic action,
- but that translation would be missed if the semantic action invokes
- YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
- if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
- incorrect destructor might then be invoked immediately. In the
- case of YYERROR or YYBACKUP, subsequent parser actions might lead
- to an incorrect destructor call or verbose syntax error message
- before the lookahead is translated. */
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
YYPOPSTACK (yylen);
@@ -2725,6 +2583,7 @@ yyreduce:
*++yyvsp = yyval;
+
/* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
@@ -2744,10 +2603,6 @@ yyreduce:
| yyerrlab -- here on detecting error |
`------------------------------------*/
yyerrlab:
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
- yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
/* If not already recovering from an error, report this error. */
if (!yyerrstatus)
{
@@ -2755,36 +2610,37 @@ yyerrlab:
#if ! YYERROR_VERBOSE
yyerror (YY_("syntax error"));
#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
- yyssp, yytoken)
{
- char const *yymsgp = YY_("syntax error");
- int yysyntax_error_status;
- yysyntax_error_status = YYSYNTAX_ERROR;
- if (yysyntax_error_status == 0)
- yymsgp = yymsg;
- else if (yysyntax_error_status == 1)
- {
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
- if (!yymsg)
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- yysyntax_error_status = 2;
- }
- else
- {
- yysyntax_error_status = YYSYNTAX_ERROR;
- yymsgp = yymsg;
- }
- }
- yyerror (yymsgp);
- if (yysyntax_error_status == 2)
- goto yyexhaustedlab;
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
}
-# undef YYSYNTAX_ERROR
#endif
}
@@ -2792,7 +2648,7 @@ yyerrlab:
if (yyerrstatus == 3)
{
- /* If just tried and failed to reuse lookahead token after an
+ /* If just tried and failed to reuse look-ahead token after an
error, discard it. */
if (yychar <= YYEOF)
@@ -2809,7 +2665,7 @@ yyerrlab:
}
}
- /* Else will try to reuse lookahead token after shifting the error
+ /* Else will try to reuse look-ahead token after shifting the error
token. */
goto yyerrlab1;
@@ -2843,7 +2699,7 @@ yyerrlab1:
for (;;)
{
yyn = yypact[yystate];
- if (!yypact_value_is_default (yyn))
+ if (yyn != YYPACT_NINF)
{
yyn += YYTERROR;
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -2866,9 +2722,10 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
*++yyvsp = yylval;
- YY_IGNORE_MAYBE_UNINITIALIZED_END
/* Shift the error token. */
@@ -2892,7 +2749,7 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#if !defined yyoverflow || YYERROR_VERBOSE
+#ifndef yyoverflow
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
@@ -2903,14 +2760,9 @@ yyexhaustedlab:
#endif
yyreturn:
- if (yychar != YYEMPTY)
- {
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
- yytoken = YYTRANSLATE (yychar);
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- }
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
/* Do not reclaim the symbols of the rule which action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
@@ -2934,3 +2786,4 @@ yyreturn:
}
+
diff --git a/src/cmd/5a/y.tab.h b/src/cmd/5a/y.tab.h
index f11fb85c6..f75cb22a7 100644
--- a/src/cmd/5a/y.tab.h
+++ b/src/cmd/5a/y.tab.h
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.7.12-4996. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison interface for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,20 +29,10 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
-#ifndef YY_YY_Y_TAB_H_INCLUDED
-# define YY_YY_Y_TAB_H_INCLUDED
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int yydebug;
-#endif
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -148,41 +141,24 @@ extern int yydebug;
+
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-/* Line 2053 of yacc.c */
#line 39 "a.y"
-
+{
Sym *sym;
int32 lval;
double dval;
char sval[8];
Addr addr;
-
-
-/* Line 2053 of yacc.c */
-#line 166 "y.tab.h"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+}
+/* Line 1529 of yacc.c. */
+#line 157 "y.tab.h"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE yylval;
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-#endif /* !YY_YY_Y_TAB_H_INCLUDED */
diff --git a/src/cmd/5c/cgen.c b/src/cmd/5c/cgen.c
deleted file mode 100644
index 5a049ae62..000000000
--- a/src/cmd/5c/cgen.c
+++ /dev/null
@@ -1,1213 +0,0 @@
-// Inferno utils/5c/cgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/cgen.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-void
-_cgen(Node *n, Node *nn, int inrel)
-{
- Node *l, *r;
- Prog *p1;
- Node nod, nod1, nod2, nod3, nod4;
- int o, t;
- int32 v, curs;
-
- if(debug['g']) {
- prtree(nn, "cgen lhs");
- prtree(n, "cgen");
- }
- if(n == Z || n->type == T)
- return;
- if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) {
- sugen(n, nn, n->type->width);
- return;
- }
- l = n->left;
- r = n->right;
- o = n->op;
- if(n->addable >= INDEXED) {
- if(nn == Z) {
- switch(o) {
- default:
- nullwarn(Z, Z);
- break;
- case OINDEX:
- nullwarn(l, r);
- break;
- }
- return;
- }
- gmove(n, nn);
- return;
- }
- curs = cursafe;
-
- if(n->complex >= FNX)
- if(l->complex >= FNX)
- if(r != Z && r->complex >= FNX)
- switch(o) {
- default:
- regret(&nod, r, 0, 0);
- cgen(r, &nod);
-
- regsalloc(&nod1, r);
- gopcode(OAS, &nod, Z, &nod1);
-
- regfree(&nod);
- nod = *n;
- nod.right = &nod1;
- cgen(&nod, nn);
- return;
-
- case OFUNC:
- case OCOMMA:
- case OANDAND:
- case OOROR:
- case OCOND:
- case ODOT:
- break;
- }
-
- switch(o) {
- default:
- diag(n, "unknown op in cgen: %O", o);
- break;
-
- case OAS:
- if(l->op == OBIT)
- goto bitas;
- if(l->addable >= INDEXED && l->complex < FNX) {
- if(nn != Z || r->addable < INDEXED) {
- if(r->complex >= FNX && nn == Z)
- regret(&nod, r, 0, 0);
- else
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- gmove(&nod, l);
- if(nn != Z)
- gmove(&nod, nn);
- regfree(&nod);
- } else
- gmove(r, l);
- break;
- }
- if(l->complex >= r->complex) {
- reglcgen(&nod1, l, Z);
- if(r->addable >= INDEXED) {
- gmove(r, &nod1);
- if(nn != Z)
- gmove(r, nn);
- regfree(&nod1);
- break;
- }
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- } else {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- reglcgen(&nod1, l, Z);
- }
- gmove(&nod, &nod1);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- bitas:
- n = l->left;
- regalloc(&nod, r, nn);
- if(l->complex >= r->complex) {
- reglcgen(&nod1, n, Z);
- cgen(r, &nod);
- } else {
- cgen(r, &nod);
- reglcgen(&nod1, n, Z);
- }
- regalloc(&nod2, n, Z);
- gopcode(OAS, &nod1, Z, &nod2);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
-
- case OBIT:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- bitload(n, &nod, Z, Z, nn);
- gopcode(OAS, &nod, Z, nn);
- regfree(&nod);
- break;
-
- case ODIV:
- case OMOD:
- if(nn != Z)
- if((t = vlog(r)) >= 0) {
- /* signed div/mod by constant power of 2 */
- cgen(l, nn);
- gopcode(OGE, nodconst(0), nn, Z);
- p1 = p;
- if(o == ODIV) {
- gopcode(OADD, nodconst((1<<t)-1), Z, nn);
- patch(p1, pc);
- gopcode(OASHR, nodconst(t), Z, nn);
- } else {
- gopcode(OSUB, nn, nodconst(0), nn);
- gopcode(OAND, nodconst((1<<t)-1), Z, nn);
- gopcode(OSUB, nn, nodconst(0), nn);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- gopcode(OAND, nodconst((1<<t)-1), Z, nn);
- patch(p1, pc);
- }
- break;
- }
- goto muldiv;
-
- case OSUB:
- if(nn != Z)
- if(l->op == OCONST)
- if(!typefd[n->type->etype]) {
- cgen(r, nn);
- gopcode(o, Z, l, nn);
- break;
- }
- case OADD:
- case OAND:
- case OOR:
- case OXOR:
- case OLSHR:
- case OASHL:
- case OASHR:
- /*
- * immediate operands
- */
- if(nn != Z)
- if(r->op == OCONST)
- if(!typefd[n->type->etype]) {
- cgen(l, nn);
- if(r->vconst == 0)
- if(o != OAND)
- break;
- if(nn != Z)
- gopcode(o, r, Z, nn);
- break;
- }
-
- case OLMUL:
- case OLDIV:
- case OLMOD:
- case OMUL:
- muldiv:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- if(o == OMUL || o == OLMUL) {
- if(mulcon(n, nn))
- break;
- }
- if(l->complex >= r->complex) {
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- gopcode(o, &nod1, Z, &nod);
- } else {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- regalloc(&nod1, l, Z);
- cgen(l, &nod1);
- gopcode(o, &nod, &nod1, &nod);
- }
- gopcode(OAS, &nod, Z, nn);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- case OASLSHR:
- case OASASHL:
- case OASASHR:
- case OASAND:
- case OASADD:
- case OASSUB:
- case OASXOR:
- case OASOR:
- if(l->op == OBIT)
- goto asbitop;
- if(r->op == OCONST)
- if(!typefd[r->type->etype])
- if(!typefd[n->type->etype]) {
- if(l->addable < INDEXED)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- regalloc(&nod, r, nn);
- gopcode(OAS, &nod2, Z, &nod);
- gopcode(o, r, Z, &nod);
- gopcode(OAS, &nod, Z, &nod2);
-
- regfree(&nod);
- if(l->addable < INDEXED)
- regfree(&nod2);
- break;
- }
-
- case OASLMUL:
- case OASLDIV:
- case OASLMOD:
- case OASMUL:
- case OASDIV:
- case OASMOD:
- if(l->op == OBIT)
- goto asbitop;
- if(l->complex >= r->complex) {
- if(l->addable < INDEXED)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- } else {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- if(l->addable < INDEXED)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- }
-
- regalloc(&nod, n, nn);
- gmove(&nod2, &nod);
- gopcode(o, &nod1, Z, &nod);
- gmove(&nod, &nod2);
- if(nn != Z)
- gopcode(OAS, &nod, Z, nn);
- regfree(&nod);
- regfree(&nod1);
- if(l->addable < INDEXED)
- regfree(&nod2);
- break;
-
- asbitop:
- regalloc(&nod4, n, nn);
- if(l->complex >= r->complex) {
- bitload(l, &nod, &nod1, &nod2, &nod4);
- regalloc(&nod3, r, Z);
- cgen(r, &nod3);
- } else {
- regalloc(&nod3, r, Z);
- cgen(r, &nod3);
- bitload(l, &nod, &nod1, &nod2, &nod4);
- }
- gmove(&nod, &nod4);
- gopcode(o, &nod3, Z, &nod4);
- regfree(&nod3);
- gmove(&nod4, &nod);
- regfree(&nod4);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
-
- case OADDR:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- lcgen(l, nn);
- break;
-
- case OFUNC:
- if(l->complex >= FNX) {
- if(l->op != OIND)
- diag(n, "bad function call");
-
- regret(&nod, l->left, 0, 0);
- cgen(l->left, &nod);
- regsalloc(&nod1, l->left);
- gopcode(OAS, &nod, Z, &nod1);
- regfree(&nod);
-
- nod = *n;
- nod.left = &nod2;
- nod2 = *l;
- nod2.left = &nod1;
- nod2.complex = 1;
- cgen(&nod, nn);
-
- return;
- }
- if(REGARG >= 0)
- o = reg[REGARG];
- gargs(r, &nod, &nod1);
- if(l->addable < INDEXED) {
- reglcgen(&nod, l, Z);
- gopcode(OFUNC, Z, Z, &nod);
- regfree(&nod);
- } else
- gopcode(OFUNC, Z, Z, l);
- if(REGARG >= 0)
- if(o != reg[REGARG])
- reg[REGARG]--;
- regret(&nod, n, l->type, 1);
- if(nn != Z)
- gmove(&nod, nn);
- if(nod.op == OREGISTER)
- regfree(&nod);
- break;
-
- case OIND:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- regialloc(&nod, n, nn);
- r = l;
- while(r->op == OADD)
- r = r->right;
- if(sconst(r) && (v = r->vconst+nod.xoffset) > -4096 && v < 4096) {
- v = r->vconst;
- r->vconst = 0;
- cgen(l, &nod);
- nod.xoffset += v;
- r->vconst = v;
- } else
- cgen(l, &nod);
- regind(&nod, n);
- gopcode(OAS, &nod, Z, nn);
- regfree(&nod);
- break;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OLO:
- case OLS:
- case OHI:
- case OHS:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- boolgen(n, 1, nn);
- break;
-
- case OANDAND:
- case OOROR:
- boolgen(n, 1, nn);
- if(nn == Z)
- patch(p, pc);
- break;
-
- case ONOT:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- boolgen(n, 1, nn);
- break;
-
- case OCOMMA:
- cgen(l, Z);
- cgen(r, nn);
- break;
-
- case OCAST:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- /*
- * convert from types l->n->nn
- */
- if(nocast(l->type, n->type)) {
- if(nocast(n->type, nn->type)) {
- cgen(l, nn);
- break;
- }
- }
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- regalloc(&nod1, n, &nod);
- if(inrel)
- gmover(&nod, &nod1);
- else
- gopcode(OAS, &nod, Z, &nod1);
- gopcode(OAS, &nod1, Z, nn);
- regfree(&nod1);
- regfree(&nod);
- break;
-
- case ODOT:
- sugen(l, nodrat, l->type->width);
- if(nn != Z) {
- warn(n, "non-interruptable temporary");
- nod = *nodrat;
- if(!r || r->op != OCONST) {
- diag(n, "DOT and no offset");
- break;
- }
- nod.xoffset += (int32)r->vconst;
- nod.type = n->type;
- cgen(&nod, nn);
- }
- break;
-
- case OCOND:
- bcgen(l, 1);
- p1 = p;
- cgen(r->left, nn);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- cgen(r->right, nn);
- patch(p1, pc);
- break;
-
- case OPOSTINC:
- case OPOSTDEC:
- v = 1;
- if(l->type->etype == TIND)
- v = l->type->link->width;
- if(o == OPOSTDEC)
- v = -v;
- if(l->op == OBIT)
- goto bitinc;
- if(nn == Z)
- goto pre;
-
- if(l->addable < INDEXED)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
-
- regalloc(&nod, l, nn);
- gopcode(OAS, &nod2, Z, &nod);
- regalloc(&nod1, l, Z);
- if(typefd[l->type->etype]) {
- regalloc(&nod3, l, Z);
- if(v < 0) {
- gopcode(OAS, nodfconst(-v), Z, &nod3);
- gopcode(OSUB, &nod3, &nod, &nod1);
- } else {
- gopcode(OAS, nodfconst(v), Z, &nod3);
- gopcode(OADD, &nod3, &nod, &nod1);
- }
- regfree(&nod3);
- } else
- gopcode(OADD, nodconst(v), &nod, &nod1);
- gopcode(OAS, &nod1, Z, &nod2);
-
- regfree(&nod);
- regfree(&nod1);
- if(l->addable < INDEXED)
- regfree(&nod2);
- break;
-
- case OPREINC:
- case OPREDEC:
- v = 1;
- if(l->type->etype == TIND)
- v = l->type->link->width;
- if(o == OPREDEC)
- v = -v;
- if(l->op == OBIT)
- goto bitinc;
-
- pre:
- if(l->addable < INDEXED)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
-
- regalloc(&nod, l, nn);
- gopcode(OAS, &nod2, Z, &nod);
- if(typefd[l->type->etype]) {
- regalloc(&nod3, l, Z);
- if(v < 0) {
- gopcode(OAS, nodfconst(-v), Z, &nod3);
- gopcode(OSUB, &nod3, Z, &nod);
- } else {
- gopcode(OAS, nodfconst(v), Z, &nod3);
- gopcode(OADD, &nod3, Z, &nod);
- }
- regfree(&nod3);
- } else
- gopcode(OADD, nodconst(v), Z, &nod);
- gopcode(OAS, &nod, Z, &nod2);
-
- regfree(&nod);
- if(l->addable < INDEXED)
- regfree(&nod2);
- break;
-
- bitinc:
- if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
- bitload(l, &nod, &nod1, &nod2, Z);
- gopcode(OAS, &nod, Z, nn);
- gopcode(OADD, nodconst(v), Z, &nod);
- bitstore(l, &nod, &nod1, &nod2, Z);
- break;
- }
- bitload(l, &nod, &nod1, &nod2, nn);
- gopcode(OADD, nodconst(v), Z, &nod);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
- }
- cursafe = curs;
- return;
-}
-
-void
-cgen(Node *n, Node *nn)
-{
- _cgen(n, nn, 0);
-}
-
-void
-cgenrel(Node *n, Node *nn)
-{
- _cgen(n, nn, 1);
-}
-
-void
-reglcgen(Node *t, Node *n, Node *nn)
-{
- Node *r;
- int32 v;
-
- regialloc(t, n, nn);
- if(n->op == OIND) {
- r = n->left;
- while(r->op == OADD)
- r = r->right;
- if(sconst(r) && (v = r->vconst+t->xoffset) > -4096 && v < 4096) {
- v = r->vconst;
- r->vconst = 0;
- lcgen(n, t);
- t->xoffset += v;
- r->vconst = v;
- regind(t, n);
- return;
- }
- } else if(n->op == OINDREG) {
- if((v = n->xoffset) > -4096 && v < 4096) {
- n->op = OREGISTER;
- cgen(n, t);
- t->xoffset += v;
- n->op = OINDREG;
- regind(t, n);
- return;
- }
- }
- lcgen(n, t);
- regind(t, n);
-}
-
-void
-reglpcgen(Node *n, Node *nn, int f)
-{
- Type *t;
-
- t = nn->type;
- nn->type = types[TLONG];
- if(f)
- reglcgen(n, nn, Z);
- else {
- regialloc(n, nn, Z);
- lcgen(nn, n);
- regind(n, nn);
- }
- nn->type = t;
-}
-
-void
-lcgen(Node *n, Node *nn)
-{
- Prog *p1;
- Node nod;
-
- if(debug['g']) {
- prtree(nn, "lcgen lhs");
- prtree(n, "lcgen");
- }
- if(n == Z || n->type == T)
- return;
- if(nn == Z) {
- nn = &nod;
- regalloc(&nod, n, Z);
- }
- switch(n->op) {
- default:
- if(n->addable < INDEXED) {
- diag(n, "unknown op in lcgen: %O", n->op);
- break;
- }
- nod = *n;
- nod.op = OADDR;
- nod.left = n;
- nod.right = Z;
- nod.type = types[TIND];
- gopcode(OAS, &nod, Z, nn);
- break;
-
- case OCOMMA:
- cgen(n->left, n->left);
- lcgen(n->right, nn);
- break;
-
- case OIND:
- cgen(n->left, nn);
- break;
-
- case OCOND:
- bcgen(n->left, 1);
- p1 = p;
- lcgen(n->right->left, nn);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- lcgen(n->right->right, nn);
- patch(p1, pc);
- break;
- }
-}
-
-void
-bcgen(Node *n, int true)
-{
-
- if(n->type == T)
- gbranch(OGOTO);
- else
- boolgen(n, true, Z);
-}
-
-void
-boolgen(Node *n, int true, Node *nn)
-{
- int o;
- Prog *p1, *p2;
- Node *l, *r, nod, nod1;
- int32 curs;
-
- if(debug['g']) {
- prtree(nn, "boolgen lhs");
- prtree(n, "boolgen");
- }
- curs = cursafe;
- l = n->left;
- r = n->right;
- switch(n->op) {
-
- default:
- regalloc(&nod, n, nn);
- cgen(n, &nod);
- o = ONE;
- if(true)
- o = comrel[relindex(o)];
- if(typefd[n->type->etype]) {
- gopcode(o, nodfconst(0), &nod, Z);
- } else
- gopcode(o, nodconst(0), &nod, Z);
- regfree(&nod);
- goto com;
-
- case OCONST:
- o = vconst(n);
- if(!true)
- o = !o;
- gbranch(OGOTO);
- if(o) {
- p1 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- }
- goto com;
-
- case OCOMMA:
- cgen(l, Z);
- boolgen(r, true, nn);
- break;
-
- case ONOT:
- boolgen(l, !true, nn);
- break;
-
- case OCOND:
- bcgen(l, 1);
- p1 = p;
- bcgen(r->left, true);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- bcgen(r->right, !true);
- patch(p2, pc);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- patch(p2, pc);
- goto com;
-
- case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- bcgen(l, true);
- p1 = p;
- bcgen(r, !true);
- p2 = p;
- patch(p1, pc);
- gbranch(OGOTO);
- patch(p2, pc);
- goto com;
-
- case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bcgen(l, !true);
- p1 = p;
- bcgen(r, !true);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- patch(p2, pc);
- goto com;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- o = n->op;
- if(true)
- o = comrel[relindex(o)];
- if(l->complex >= FNX && r->complex >= FNX) {
- regret(&nod, r, 0, 0);
- cgenrel(r, &nod);
- regsalloc(&nod1, r);
- gopcode(OAS, &nod, Z, &nod1);
- regfree(&nod);
- nod = *n;
- nod.right = &nod1;
- boolgen(&nod, true, nn);
- break;
- }
- if(sconst(l)) {
- regalloc(&nod, r, nn);
- cgenrel(r, &nod);
- o = invrel[relindex(o)];
- gopcode(o, l, &nod, Z);
- regfree(&nod);
- goto com;
- }
- if(sconst(r)) {
- regalloc(&nod, l, nn);
- cgenrel(l, &nod);
- gopcode(o, r, &nod, Z);
- regfree(&nod);
- goto com;
- }
- if(l->complex >= r->complex) {
- regalloc(&nod1, l, nn);
- cgenrel(l, &nod1);
- regalloc(&nod, r, Z);
- cgenrel(r, &nod);
- } else {
- regalloc(&nod, r, nn);
- cgenrel(r, &nod);
- regalloc(&nod1, l, Z);
- cgenrel(l, &nod1);
- }
- gopcode(o, &nod, &nod1, Z);
- regfree(&nod);
- regfree(&nod1);
-
- com:
- if(nn != Z) {
- p1 = p;
- gopcode(OAS, nodconst(1), Z, nn);
- gbranch(OGOTO);
- p2 = p;
- patch(p1, pc);
- gopcode(OAS, nodconst(0), Z, nn);
- patch(p2, pc);
- }
- break;
- }
- cursafe = curs;
-}
-
-void
-sugen(Node *n, Node *nn, int32 w)
-{
- Prog *p1;
- Node nod0, nod1, nod2, nod3, nod4, *l, *r;
- Type *t;
- int32 pc1;
- int i, m, c;
-
- if(n == Z || n->type == T)
- return;
- if(debug['g']) {
- prtree(nn, "sugen lhs");
- prtree(n, "sugen");
- }
- if(nn == nodrat)
- if(w > nrathole)
- nrathole = w;
- switch(n->op) {
- case OIND:
- if(nn == Z) {
- nullwarn(n->left, Z);
- break;
- }
-
- default:
- goto copy;
-
- case OCONST:
- if(n->type && typev[n->type->etype]) {
- if(nn == Z) {
- nullwarn(n->left, Z);
- break;
- }
-
- t = nn->type;
- nn->type = types[TLONG];
- reglcgen(&nod1, nn, Z);
- nn->type = t;
-
- if(isbigendian)
- gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
- else
- gopcode(OAS, nod32const(n->vconst), Z, &nod1);
- nod1.xoffset += SZ_LONG;
- if(isbigendian)
- gopcode(OAS, nod32const(n->vconst), Z, &nod1);
- else
- gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
-
- regfree(&nod1);
- break;
- }
- goto copy;
-
- case ODOT:
- l = n->left;
- sugen(l, nodrat, l->type->width);
- if(nn != Z) {
- warn(n, "non-interruptable temporary");
- nod1 = *nodrat;
- r = n->right;
- if(!r || r->op != OCONST) {
- diag(n, "DOT and no offset");
- break;
- }
- nod1.xoffset += (int32)r->vconst;
- nod1.type = n->type;
- sugen(&nod1, nn, w);
- }
- break;
-
- case OSTRUCT:
- /*
- * rewrite so lhs has no side effect.
- */
- if(nn != Z && side(nn)) {
- nod1 = *n;
- nod1.type = typ(TIND, n->type);
- regret(&nod2, &nod1, 0, 0);
- lcgen(nn, &nod2);
- regsalloc(&nod0, &nod1);
- gopcode(OAS, &nod2, Z, &nod0);
- regfree(&nod2);
-
- nod1 = *n;
- nod1.op = OIND;
- nod1.left = &nod0;
- nod1.right = Z;
- nod1.complex = 1;
-
- sugen(n, &nod1, w);
- return;
- }
-
- r = n->left;
- for(t = n->type->link; t != T; t = t->down) {
- l = r;
- if(r->op == OLIST) {
- l = r->left;
- r = r->right;
- }
- if(nn == Z) {
- cgen(l, nn);
- continue;
- }
- /*
- * hand craft *(&nn + o) = l
- */
- nod0 = znode;
- nod0.op = OAS;
- nod0.type = t;
- nod0.left = &nod1;
- nod0.right = l;
-
- nod1 = znode;
- nod1.op = OIND;
- nod1.type = t;
- nod1.left = &nod2;
-
- nod2 = znode;
- nod2.op = OADD;
- nod2.type = typ(TIND, t);
- nod2.left = &nod3;
- nod2.right = &nod4;
-
- nod3 = znode;
- nod3.op = OADDR;
- nod3.type = nod2.type;
- nod3.left = nn;
-
- nod4 = znode;
- nod4.op = OCONST;
- nod4.type = nod2.type;
- nod4.vconst = t->offset;
-
- ccom(&nod0);
- acom(&nod0);
- xcom(&nod0);
- nod0.addable = 0;
-
- cgen(&nod0, Z);
- }
- break;
-
- case OAS:
- if(nn == Z) {
- if(n->addable < INDEXED)
- sugen(n->right, n->left, w);
- break;
- }
- sugen(n->right, nodrat, w);
- warn(n, "non-interruptable temporary");
- sugen(nodrat, n->left, w);
- sugen(nodrat, nn, w);
- break;
-
- case OFUNC:
- if(!hasdotdotdot(n->left->type)) {
- cgen(n, Z);
- if(nn != Z) {
- curarg -= n->type->width;
- regret(&nod1, n, n->left->type, 1);
- if(nn->complex >= FNX) {
- regsalloc(&nod2, n);
- cgen(&nod1, &nod2);
- nod1 = nod2;
- }
- cgen(&nod1, nn);
- }
- break;
- }
- if(nn == Z) {
- sugen(n, nodrat, w);
- break;
- }
- if(nn->op != OIND) {
- nn = new1(OADDR, nn, Z);
- nn->type = types[TIND];
- nn->addable = 0;
- } else
- nn = nn->left;
- n = new(OFUNC, n->left, new(OLIST, nn, n->right));
- n->type = types[TVOID];
- n->left->type = types[TVOID];
- cgen(n, Z);
- break;
-
- case OCOND:
- bcgen(n->left, 1);
- p1 = p;
- sugen(n->right->left, nn, w);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- sugen(n->right->right, nn, w);
- patch(p1, pc);
- break;
-
- case OCOMMA:
- cgen(n->left, Z);
- sugen(n->right, nn, w);
- break;
- }
- return;
-
-copy:
- if(nn == Z)
- return;
- if(n->complex >= FNX && nn->complex >= FNX) {
- t = nn->type;
- nn->type = types[TLONG];
- regialloc(&nod1, nn, Z);
- lcgen(nn, &nod1);
- regsalloc(&nod2, nn);
- nn->type = t;
-
- gopcode(OAS, &nod1, Z, &nod2);
- regfree(&nod1);
-
- nod2.type = typ(TIND, t);
-
- nod1 = nod2;
- nod1.op = OIND;
- nod1.left = &nod2;
- nod1.right = Z;
- nod1.complex = 1;
- nod1.type = t;
-
- sugen(n, &nod1, w);
- return;
- }
-
- w /= SZ_LONG;
- if(w <= 2) {
- if(n->complex > nn->complex) {
- reglpcgen(&nod1, n, 1);
- reglpcgen(&nod2, nn, 1);
- } else {
- reglpcgen(&nod2, nn, 1);
- reglpcgen(&nod1, n, 1);
- }
- regalloc(&nod3, &regnode, Z);
- regalloc(&nod4, &regnode, Z);
- nod0 = *nodconst((1<<nod3.reg)|(1<<nod4.reg));
- if(w == 2 && nod1.xoffset == 0)
- gmovm(&nod1, &nod0, 0);
- else {
- gmove(&nod1, &nod3);
- if(w == 2) {
- nod1.xoffset += SZ_LONG;
- gmove(&nod1, &nod4);
- }
- }
- if(w == 2 && nod2.xoffset == 0)
- gmovm(&nod0, &nod2, 0);
- else {
- gmove(&nod3, &nod2);
- if(w == 2) {
- nod2.xoffset += SZ_LONG;
- gmove(&nod4, &nod2);
- }
- }
- regfree(&nod1);
- regfree(&nod2);
- regfree(&nod3);
- regfree(&nod4);
- return;
- }
-
- if(n->complex > nn->complex) {
- reglpcgen(&nod1, n, 0);
- reglpcgen(&nod2, nn, 0);
- } else {
- reglpcgen(&nod2, nn, 0);
- reglpcgen(&nod1, n, 0);
- }
-
- m = 0;
- for(c = 0; c < w && c < 4; c++) {
- i = tmpreg();
- if (i == 0)
- break;
- reg[i]++;
- m |= 1<<i;
- }
- nod4 = *(nodconst(m));
- if(w < 3*c) {
- for (; w>c; w-=c) {
- gmovm(&nod1, &nod4, 1);
- gmovm(&nod4, &nod2, 1);
- }
- goto out;
- }
-
- regalloc(&nod3, &regnode, Z);
- gopcode(OAS, nodconst(w/c), Z, &nod3);
- w %= c;
-
- pc1 = pc;
- gmovm(&nod1, &nod4, 1);
- gmovm(&nod4, &nod2, 1);
-
- gopcode(OSUB, nodconst(1), Z, &nod3);
- gopcode(OEQ, nodconst(0), &nod3, Z);
- p->as = ABGT;
- patch(p, pc1);
- regfree(&nod3);
-
-out:
- if (w) {
- i = 0;
- while (c>w) {
- while ((m&(1<<i)) == 0)
- i++;
- m &= ~(1<<i);
- reg[i] = 0;
- c--;
- i++;
- }
- nod4.vconst = m;
- gmovm(&nod1, &nod4, 0);
- gmovm(&nod4, &nod2, 0);
- }
- i = 0;
- do {
- while ((m&(1<<i)) == 0)
- i++;
- reg[i] = 0;
- c--;
- i++;
- } while (c>0);
- regfree(&nod1);
- regfree(&nod2);
-}
diff --git a/src/cmd/5c/doc.go b/src/cmd/5c/doc.go
deleted file mode 100644
index 7291d45f4..000000000
--- a/src/cmd/5c/doc.go
+++ /dev/null
@@ -1,16 +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.
-
-// +build ignore
-
-/*
-
-5c is a version of the Plan 9 C compiler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/8c
-
-Its target architecture is the ARM, referred to by these tools as arm.
-
-*/
-package main
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h
deleted file mode 100644
index 7417b7dbe..000000000
--- a/src/cmd/5c/gc.h
+++ /dev/null
@@ -1,333 +0,0 @@
-// Inferno utils/5c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/gc.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "../cc/cc.h"
-#include "../5l/5.out.h"
-
-/*
- * 5c/arm
- * Arm 7500
- */
-#define SZ_CHAR 1
-#define SZ_SHORT 2
-#define SZ_INT 4
-#define SZ_LONG 4
-#define SZ_IND 4
-#define SZ_FLOAT 4
-#define SZ_VLONG 8
-#define SZ_DOUBLE 8
-#define FNX 100
-
-typedef struct Case Case;
-typedef struct C1 C1;
-typedef struct Multab Multab;
-typedef struct Hintab Hintab;
-typedef struct Reg Reg;
-typedef struct Rgn Rgn;
-
-
-#define R0ISZERO 0
-
-#define A ((Addr*)0)
-
-#define INDEXED 9
-#define P ((Prog*)0)
-
-struct Case
-{
- Case* link;
- int32 val;
- int32 label;
- char def;
- char isv;
-};
-#define C ((Case*)0)
-
-struct C1
-{
- int32 val;
- int32 label;
-};
-
-struct Multab
-{
- int32 val;
- char code[20];
-};
-
-struct Hintab
-{
- ushort val;
- char hint[10];
-};
-
-struct Reg
-{
- int32 pc;
- int32 rpo; /* reverse post ordering */
-
- Bits set;
- Bits use1;
- Bits use2;
-
- Bits refbehind;
- Bits refahead;
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- int32 regu;
- int32 loop; /* could be shorter */
-
-
- Reg* log5;
- int32 active;
-
- Reg* p1;
- Reg* p2;
- Reg* p2link;
- Reg* s1;
- Reg* s2;
- Reg* link;
- Prog* prog;
-};
-#define R ((Reg*)0)
-
-#define NRGN 600
-struct Rgn
-{
- Reg* enter;
- short cost;
- short varno;
- short regno;
-};
-
-EXTERN int32 breakpc;
-EXTERN int32 nbreak;
-EXTERN Case* cases;
-EXTERN Node constnode;
-EXTERN Node fconstnode;
-EXTERN int32 continpc;
-EXTERN int32 curarg;
-EXTERN int32 cursafe;
-EXTERN int32 isbigendian;
-EXTERN Prog* lastp;
-EXTERN int32 maxargsafe;
-EXTERN int mnstring;
-EXTERN Multab multab[20];
-extern int hintabsize;
-EXTERN Node* nodrat;
-EXTERN Node* nodret;
-EXTERN Node* nodsafe;
-EXTERN int32 nrathole;
-EXTERN int32 nstring;
-EXTERN Prog* p;
-EXTERN int32 pc;
-EXTERN Node regnode;
-EXTERN char string[NSNAME];
-EXTERN Sym* symrathole;
-EXTERN Node znode;
-EXTERN Prog zprog;
-EXTERN char reg[NREG+NFREG];
-EXTERN int32 exregoffset;
-EXTERN int32 exfregoffset;
-EXTERN int suppress;
-
-#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
-#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
-#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
-#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
-
-#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
-
-#define CLOAD 4
-#define CREF 5
-#define CINF 1000
-#define LOOP 3
-
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-
-EXTERN int32 regbits;
-EXTERN int32 exregbits;
-
-EXTERN int change;
-
-EXTERN Reg* firstr;
-EXTERN Reg* lastr;
-EXTERN Reg zreg;
-EXTERN Reg* freer;
-EXTERN int32* idom;
-EXTERN Reg** rpo2r;
-EXTERN int32 maxnr;
-
-extern char* anames[];
-extern Hintab hintab[];
-
-/*
- * sgen.c
- */
-void codgen(Node*, Node*);
-void gen(Node*);
-void noretval(int);
-void usedset(Node*, int);
-void xcom(Node*);
-int bcomplex(Node*, Node*);
-Prog* gtext(Sym*, int32);
-vlong argsize(int);
-
-/*
- * cgen.c
- */
-void cgen(Node*, Node*);
-void reglcgen(Node*, Node*, Node*);
-void lcgen(Node*, Node*);
-void bcgen(Node*, int);
-void boolgen(Node*, int, Node*);
-void sugen(Node*, Node*, int32);
-void layout(Node*, Node*, int, int, Node*);
-void cgenrel(Node*, Node*);
-
-/*
- * txt.c
- */
-void ginit(void);
-void gclean(void);
-void nextpc(void);
-void gargs(Node*, Node*, Node*);
-void garg1(Node*, Node*, Node*, int, Node**);
-Node* nodconst(int32);
-Node* nod32const(vlong);
-Node* nodfconst(double);
-void nodreg(Node*, Node*, int);
-void regret(Node*, Node*, Type*, int);
-int tmpreg(void);
-void regalloc(Node*, Node*, Node*);
-void regfree(Node*);
-void regialloc(Node*, Node*, Node*);
-void regsalloc(Node*, Node*);
-void regaalloc1(Node*, Node*);
-void regaalloc(Node*, Node*);
-void regind(Node*, Node*);
-void gprep(Node*, Node*);
-void raddr(Node*, Prog*);
-void naddr(Node*, Addr*);
-void gmovm(Node*, Node*, int);
-void gmove(Node*, Node*);
-void gmover(Node*, Node*);
-void gins(int a, Node*, Node*);
-void gopcode(int, Node*, Node*, Node*);
-int samaddr(Node*, Node*);
-void gbranch(int);
-void patch(Prog*, int32);
-int sconst(Node*);
-int sval(int32);
-void gpseudo(int, Sym*, Node*);
-void gprefetch(Node*);
-void gpcdata(int, int);
-
-/*
- * swt.c
- */
-int swcmp(const void*, const void*);
-void doswit(Node*);
-void swit1(C1*, int, int32, Node*);
-void swit2(C1*, int, int32, Node*);
-void newcase(void);
-void bitload(Node*, Node*, Node*, Node*, Node*);
-void bitstore(Node*, Node*, Node*, Node*, Node*);
-int mulcon(Node*, Node*);
-Multab* mulcon0(int32);
-void nullwarn(Node*, Node*);
-void outcode(void);
-
-/*
- * list
- */
-void listinit(void);
-
-/*
- * reg.c
- */
-Reg* rega(void);
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Addr*, int);
-void prop(Reg*, Bits, Bits);
-void loopit(Reg*, int32);
-void synch(Reg*, Bits);
-uint32 allreg(uint32, Rgn*);
-void paint1(Reg*, int);
-uint32 paint2(Reg*, int);
-void paint3(Reg*, int, int32, int);
-void addreg(Addr*, int);
-
-/*
- * peep.c
- */
-void peep(void);
-void excise(Reg*);
-Reg* uniqp(Reg*);
-Reg* uniqs(Reg*);
-int regtyp(Addr*);
-int regzer(Addr*);
-int anyvar(Addr*);
-int subprop(Reg*);
-int copyprop(Reg*);
-int shiftprop(Reg*);
-void constprop(Addr*, Addr*, Reg*);
-int copy1(Addr*, Addr*, Reg*, int);
-int copyu(Prog*, Addr*, Addr*);
-
-int copyas(Addr*, Addr*);
-int copyau(Addr*, Addr*);
-int copyau1(Prog*, Addr*);
-int copysub(Addr*, Addr*, Addr*, int);
-int copysub1(Prog*, Addr*, Addr*, int);
-
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
-
-void predicate(void);
-int isbranch(Prog *);
-int predicable(Prog *p);
-int modifiescpsr(Prog *p);
diff --git a/src/cmd/5c/mul.c b/src/cmd/5c/mul.c
deleted file mode 100644
index ff50c4845..000000000
--- a/src/cmd/5c/mul.c
+++ /dev/null
@@ -1,640 +0,0 @@
-// Inferno utils/5c/mul.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/mul.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-#include "gc.h"
-
-/*
- * code sequences for multiply by constant.
- * [a-l][0-3]
- * lsl $(A-'a'),r0,r1
- * [+][0-7]
- * add r0,r1,r2
- * [-][0-7]
- * sub r0,r1,r2
- */
-
-static int maxmulops = 3; /* max # of ops to replace mul with */
-static int multabp;
-static int32 mulval;
-static char* mulcp;
-static int32 valmax;
-static int shmax;
-
-static int docode(char *hp, char *cp, int r0, int r1);
-static int gen1(int len);
-static int gen2(int len, int32 r1);
-static int gen3(int len, int32 r0, int32 r1, int flag);
-enum
-{
- SR1 = 1<<0, /* r1 has been shifted */
- SR0 = 1<<1, /* r0 has been shifted */
- UR1 = 1<<2, /* r1 has not been used */
- UR0 = 1<<3, /* r0 has not been used */
-};
-
-Multab*
-mulcon0(int32 v)
-{
- int a1, a2, g;
- Multab *m, *m1;
- char hint[10];
-
- if(v < 0)
- v = -v;
-
- /*
- * look in cache
- */
- m = multab;
- for(g=0; g<nelem(multab); g++) {
- if(m->val == v) {
- if(m->code[0] == 0)
- return 0;
- return m;
- }
- m++;
- }
-
- /*
- * select a spot in cache to overwrite
- */
- multabp++;
- if(multabp < 0 || multabp >= nelem(multab))
- multabp = 0;
- m = multab+multabp;
- m->val = v;
- mulval = v;
-
- /*
- * look in execption hint table
- */
- a1 = 0;
- a2 = hintabsize;
- for(;;) {
- if(a1 >= a2)
- goto no;
- g = (a2 + a1)/2;
- if(v < hintab[g].val) {
- a2 = g;
- continue;
- }
- if(v > hintab[g].val) {
- a1 = g+1;
- continue;
- }
- break;
- }
-
- if(docode(hintab[g].hint, m->code, 1, 0))
- return m;
- print("multiply table failure %d\n", v);
- m->code[0] = 0;
- return 0;
-
-no:
- /*
- * try to search
- */
- hint[0] = 0;
- for(g=1; g<=maxmulops; g++) {
- if(g >= maxmulops && v >= 65535)
- break;
- mulcp = hint+g;
- *mulcp = 0;
- if(gen1(g)) {
- if(docode(hint, m->code, 1, 0))
- return m;
- print("multiply table failure %d\n", v);
- break;
- }
- }
-
- /*
- * try a recur followed by a shift
- */
- g = 0;
- while(!(v & 1)) {
- g++;
- v >>= 1;
- }
- if(g) {
- m1 = mulcon0(v);
- if(m1) {
- strcpy(m->code, m1->code);
- sprint(strchr(m->code, 0), "%c0", g+'a');
- return m;
- }
- }
- m->code[0] = 0;
- return 0;
-}
-
-static int
-docode(char *hp, char *cp, int r0, int r1)
-{
- int c, i;
-
- c = *hp++;
- *cp = c;
- cp += 2;
- switch(c) {
- default:
- c -= 'a';
- if(c < 1 || c >= 30)
- break;
- for(i=0; i<4; i++) {
- switch(i) {
- case 0:
- if(docode(hp, cp, r0<<c, r1))
- goto out;
- break;
- case 1:
- if(docode(hp, cp, r1<<c, r1))
- goto out;
- break;
- case 2:
- if(docode(hp, cp, r0, r0<<c))
- goto out;
- break;
- case 3:
- if(docode(hp, cp, r0, r1<<c))
- goto out;
- break;
- }
- }
- break;
-
- case '+':
- for(i=0; i<8; i++) {
- cp[-1] = i+'0';
- switch(i) {
- case 1:
- if(docode(hp, cp, r0+r1, r1))
- goto out;
- break;
- case 5:
- if(docode(hp, cp, r0, r0+r1))
- goto out;
- break;
- }
- }
- break;
-
- case '-':
- for(i=0; i<8; i++) {
- cp[-1] = i+'0';
- switch(i) {
- case 1:
- if(docode(hp, cp, r0-r1, r1))
- goto out;
- break;
- case 2:
- if(docode(hp, cp, r1-r0, r1))
- goto out;
- break;
- case 5:
- if(docode(hp, cp, r0, r0-r1))
- goto out;
- break;
- case 6:
- if(docode(hp, cp, r0, r1-r0))
- goto out;
- break;
- }
- }
- break;
-
- case 0:
- if(r0 == mulval)
- return 1;
- }
- return 0;
-
-out:
- cp[-1] = i+'0';
- return 1;
-}
-
-static int
-gen1(int len)
-{
- int i;
-
- for(shmax=1; shmax<30; shmax++) {
- valmax = 1<<shmax;
- if(valmax >= mulval)
- break;
- }
- if(mulval == 1)
- return 1;
-
- len--;
- for(i=1; i<=shmax; i++)
- if(gen2(len, 1<<i)) {
- *--mulcp = 'a'+i;
- return 1;
- }
- return 0;
-}
-
-static int
-gen2(int len, int32 r1)
-{
- int i;
-
- if(len <= 0) {
- if(r1 == mulval)
- return 1;
- return 0;
- }
-
- len--;
- if(len == 0)
- goto calcr0;
-
- if(gen3(len, r1, r1+1, UR1)) {
- i = '+';
- goto out;
- }
- if(gen3(len, r1-1, r1, UR0)) {
- i = '-';
- goto out;
- }
- if(gen3(len, 1, r1+1, UR1)) {
- i = '+';
- goto out;
- }
- if(gen3(len, 1, r1-1, UR1)) {
- i = '-';
- goto out;
- }
-
- return 0;
-
-calcr0:
- if(mulval == r1+1) {
- i = '+';
- goto out;
- }
- if(mulval == r1-1) {
- i = '-';
- goto out;
- }
- return 0;
-
-out:
- *--mulcp = i;
- return 1;
-}
-
-static int
-gen3(int len, int32 r0, int32 r1, int flag)
-{
- int i, f1, f2;
- int32 x;
-
- if(r0 <= 0 ||
- r0 >= r1 ||
- r1 > valmax)
- return 0;
-
- len--;
- if(len == 0)
- goto calcr0;
-
- if(!(flag & UR1)) {
- f1 = UR1|SR1;
- for(i=1; i<=shmax; i++) {
- x = r0<<i;
- if(x > valmax)
- break;
- if(gen3(len, r0, x, f1)) {
- i += 'a';
- goto out;
- }
- }
- }
-
- if(!(flag & UR0)) {
- f1 = UR1|SR1;
- for(i=1; i<=shmax; i++) {
- x = r1<<i;
- if(x > valmax)
- break;
- if(gen3(len, r1, x, f1)) {
- i += 'a';
- goto out;
- }
- }
- }
-
- if(!(flag & SR1)) {
- f1 = UR1|SR1|(flag&UR0);
- for(i=1; i<=shmax; i++) {
- x = r1<<i;
- if(x > valmax)
- break;
- if(gen3(len, r0, x, f1)) {
- i += 'a';
- goto out;
- }
- }
- }
-
- if(!(flag & SR0)) {
- f1 = UR0|SR0|(flag&(SR1|UR1));
-
- f2 = UR1|SR1;
- if(flag & UR1)
- f2 |= UR0;
- if(flag & SR1)
- f2 |= SR0;
-
- for(i=1; i<=shmax; i++) {
- x = r0<<i;
- if(x > valmax)
- break;
- if(x > r1) {
- if(gen3(len, r1, x, f2)) {
- i += 'a';
- goto out;
- }
- } else
- if(gen3(len, x, r1, f1)) {
- i += 'a';
- goto out;
- }
- }
- }
-
- x = r1+r0;
- if(gen3(len, r0, x, UR1)) {
- i = '+';
- goto out;
- }
-
- if(gen3(len, r1, x, UR1)) {
- i = '+';
- goto out;
- }
-
- x = r1-r0;
- if(gen3(len, x, r1, UR0)) {
- i = '-';
- goto out;
- }
-
- if(x > r0) {
- if(gen3(len, r0, x, UR1)) {
- i = '-';
- goto out;
- }
- } else
- if(gen3(len, x, r0, UR0)) {
- i = '-';
- goto out;
- }
-
- return 0;
-
-calcr0:
- f1 = flag & (UR0|UR1);
- if(f1 == UR1) {
- for(i=1; i<=shmax; i++) {
- x = r1<<i;
- if(x >= mulval) {
- if(x == mulval) {
- i += 'a';
- goto out;
- }
- break;
- }
- }
- }
-
- if(mulval == r1+r0) {
- i = '+';
- goto out;
- }
- if(mulval == r1-r0) {
- i = '-';
- goto out;
- }
-
- return 0;
-
-out:
- *--mulcp = i;
- return 1;
-}
-
-/*
- * hint table has numbers that
- * the search algorithm fails on.
- * <1000:
- * all numbers
- * <5000:
- * ÷ by 5
- * <10000:
- * ÷ by 50
- * <65536:
- * ÷ by 250
- */
-Hintab hintab[] =
-{
- 683, "b++d+e+",
- 687, "b+e++e-",
- 691, "b++d+e+",
- 731, "b++d+e+",
- 811, "b++d+i+",
- 821, "b++e+e+",
- 843, "b+d++e+",
- 851, "b+f-+e-",
- 853, "b++e+e+",
- 877, "c++++g-",
- 933, "b+c++g-",
- 981, "c-+e-d+",
- 1375, "b+c+b+h-",
- 1675, "d+b++h+",
- 2425, "c++f-e+",
- 2675, "c+d++f-",
- 2750, "b+d-b+h-",
- 2775, "c-+g-e-",
- 3125, "b++e+g+",
- 3275, "b+c+g+e+",
- 3350, "c++++i+",
- 3475, "c-+e-f-",
- 3525, "c-+d+g-",
- 3625, "c-+e-j+",
- 3675, "b+d+d+e+",
- 3725, "b+d-+h+",
- 3925, "b+d+f-d-",
- 4275, "b+g++e+",
- 4325, "b+h-+d+",
- 4425, "b+b+g-j-",
- 4525, "b+d-d+f+",
- 4675, "c++d-g+",
- 4775, "b+d+b+g-",
- 4825, "c+c-+i-",
- 4850, "c++++i-",
- 4925, "b++e-g-",
- 4975, "c+f++e-",
- 5500, "b+g-c+d+",
- 6700, "d+b++i+",
- 9700, "d++++j-",
- 11000, "b+f-c-h-",
- 11750, "b+d+g+j-",
- 12500, "b+c+e-k+",
- 13250, "b+d+e-f+",
- 13750, "b+h-c-d+",
- 14250, "b+g-c+e-",
- 14500, "c+f+j-d-",
- 14750, "d-g--f+",
- 16750, "b+e-d-n+",
- 17750, "c+h-b+e+",
- 18250, "d+b+h-d+",
- 18750, "b+g-++f+",
- 19250, "b+e+b+h+",
- 19750, "b++h--f-",
- 20250, "b+e-l-c+",
- 20750, "c++bi+e-",
- 21250, "b+i+l+c+",
- 22000, "b+e+d-g-",
- 22250, "b+d-h+k-",
- 22750, "b+d-e-g+",
- 23250, "b+c+h+e-",
- 23500, "b+g-c-g-",
- 23750, "b+g-b+h-",
- 24250, "c++g+m-",
- 24750, "b+e+e+j-",
- 25000, "b++dh+g+",
- 25250, "b+e+d-g-",
- 25750, "b+e+b+j+",
- 26250, "b+h+c+e+",
- 26500, "b+h+c+g+",
- 26750, "b+d+e+g-",
- 27250, "b+e+e+f+",
- 27500, "c-i-c-d+",
- 27750, "b+bd++j+",
- 28250, "d-d-++i-",
- 28500, "c+c-h-e-",
- 29000, "b+g-d-f+",
- 29500, "c+h+++e-",
- 29750, "b+g+f-c+",
- 30250, "b+f-g-c+",
- 33500, "c-f-d-n+",
- 33750, "b+d-b+j-",
- 34250, "c+e+++i+",
- 35250, "e+b+d+k+",
- 35500, "c+e+d-g-",
- 35750, "c+i-++e+",
- 36250, "b+bh-d+e+",
- 36500, "c+c-h-e-",
- 36750, "d+e--i+",
- 37250, "b+g+g+b+",
- 37500, "b+h-b+f+",
- 37750, "c+be++j-",
- 38500, "b+e+b+i+",
- 38750, "d+i-b+d+",
- 39250, "b+g-l-+d+",
- 39500, "b+g-c+g-",
- 39750, "b+bh-c+f-",
- 40250, "b+bf+d+g-",
- 40500, "b+g-c+g+",
- 40750, "c+b+i-e+",
- 41250, "d++bf+h+",
- 41500, "b+j+c+d-",
- 41750, "c+f+b+h-",
- 42500, "c+h++g+",
- 42750, "b+g+d-f-",
- 43250, "b+l-e+d-",
- 43750, "c+bd+h+f-",
- 44000, "b+f+g-d-",
- 44250, "b+d-g--f+",
- 44500, "c+e+c+h+",
- 44750, "b+e+d-h-",
- 45250, "b++g+j-g+",
- 45500, "c+d+e-g+",
- 45750, "b+d-h-e-",
- 46250, "c+bd++j+",
- 46500, "b+d-c-j-",
- 46750, "e-e-b+g-",
- 47000, "b+c+d-j-",
- 47250, "b+e+e-g-",
- 47500, "b+g-c-h-",
- 47750, "b+f-c+h-",
- 48250, "d--h+n-",
- 48500, "b+c-g+m-",
- 48750, "b+e+e-g+",
- 49500, "c-f+e+j-",
- 49750, "c+c+g++f-",
- 50000, "b+e+e+k+",
- 50250, "b++i++g+",
- 50500, "c+g+f-i+",
- 50750, "b+e+d+k-",
- 51500, "b+i+c-f+",
- 51750, "b+bd+g-e-",
- 52250, "b+d+g-j+",
- 52500, "c+c+f+g+",
- 52750, "b+c+e+i+",
- 53000, "b+i+c+g+",
- 53500, "c+g+g-n+",
- 53750, "b+j+d-c+",
- 54250, "b+d-g-j-",
- 54500, "c-f+e+f+",
- 54750, "b+f-+c+g+",
- 55000, "b+g-d-g-",
- 55250, "b+e+e+g+",
- 55500, "b+cd++j+",
- 55750, "b+bh-d-f-",
- 56250, "c+d-b+j-",
- 56500, "c+d+c+i+",
- 56750, "b+e+d++h-",
- 57000, "b+d+g-f+",
- 57250, "b+f-m+d-",
- 57750, "b+i+c+e-",
- 58000, "b+e+d+h+",
- 58250, "c+b+g+g+",
- 58750, "d-e-j--e+",
- 59000, "d-i-+e+",
- 59250, "e--h-m+",
- 59500, "c+c-h+f-",
- 59750, "b+bh-e+i-",
- 60250, "b+bh-e-e-",
- 60500, "c+c-g-g-",
- 60750, "b+e-l-e-",
- 61250, "b+g-g-c+",
- 61750, "b+g-c+g+",
- 62250, "f--+c-i-",
- 62750, "e+f--+g+",
- 64750, "b+f+d+p-",
-};
-int hintabsize = nelem(hintab);
diff --git a/src/cmd/5c/peep.c b/src/cmd/5c/peep.c
deleted file mode 100644
index 1de56b594..000000000
--- a/src/cmd/5c/peep.c
+++ /dev/null
@@ -1,1478 +0,0 @@
-// Inferno utils/5c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-#include "gc.h"
-
-int xtramodes(Reg*, Addr*);
-
-void
-peep(void)
-{
- Reg *r, *r1, *r2;
- Prog *p, *p1;
- int t;
-/*
- * complete R structure
- */
- t = 0;
- for(r=firstr; r!=R; r=r1) {
- r1 = r->link;
- if(r1 == R)
- break;
- p = r->prog->link;
- while(p != r1->prog)
- switch(p->as) {
- default:
- r2 = rega();
- r->link = r2;
- r2->link = r1;
-
- r2->prog = p;
- r2->p1 = r;
- r->s1 = r2;
- r2->s1 = r1;
- r1->p1 = r2;
-
- r = r2;
- t++;
-
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- p = p->link;
- }
- }
-
-loop1:
- t = 0;
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- if(p->as == ASLL || p->as == ASRL || p->as == ASRA) {
- /*
- * elide shift into D_SHIFT operand of subsequent instruction
- */
- if(shiftprop(r)) {
- excise(r);
- t++;
- }
- }
- if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
- if(regtyp(&p->to)) {
- if(p->from.type == D_CONST)
- constprop(&p->from, &p->to, r->s1);
- else if(regtyp(&p->from))
- if(p->from.type == p->to.type) {
- if(copyprop(r)) {
- excise(r);
- t++;
- } else
- if(subprop(r) && copyprop(r)) {
- excise(r);
- t++;
- }
- }
- }
- }
- if(t)
- goto loop1;
- /*
- * look for MOVB x,R; MOVB R,R
- */
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- default:
- continue;
- case AEOR:
- /*
- * EOR -1,x,y => MVN x,y
- */
- if(p->from.type == D_CONST && p->from.offset == -1) {
- p->as = AMVN;
- p->from.type = D_REG;
- if(p->reg != NREG)
- p->from.reg = p->reg;
- else
- p->from.reg = p->to.reg;
- p->reg = NREG;
- }
- continue;
- case AMOVH:
- case AMOVHS:
- case AMOVHU:
- case AMOVB:
- case AMOVBS:
- case AMOVBU:
- if(p->to.type != D_REG)
- continue;
- break;
- }
- r1 = r->link;
- if(r1 == R)
- continue;
- p1 = r1->prog;
- if(p1->as != p->as)
- continue;
- if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
- continue;
- if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
- continue;
- excise(r1);
- }
-
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AMOVW:
- case AMOVB:
- case AMOVBS:
- case AMOVBU:
- if(p->from.type == D_OREG && p->from.offset == 0)
- xtramodes(r, &p->from);
- else if(p->to.type == D_OREG && p->to.offset == 0)
- xtramodes(r, &p->to);
- else
- continue;
- break;
- case ACMP:
- /*
- * elide CMP $0,x if calculation of x can set condition codes
- */
- if(p->from.type != D_CONST || p->from.offset != 0)
- continue;
- r2 = r->s1;
- if(r2 == R)
- continue;
- t = r2->prog->as;
- switch(t) {
- default:
- continue;
- case ABEQ:
- case ABNE:
- case ABMI:
- case ABPL:
- break;
- case ABGE:
- t = ABPL;
- break;
- case ABLT:
- t = ABMI;
- break;
- case ABHI:
- t = ABNE;
- break;
- case ABLS:
- t = ABEQ;
- break;
- }
- r1 = r;
- do
- r1 = uniqp(r1);
- while (r1 != R && r1->prog->as == ANOP);
- if(r1 == R)
- continue;
- p1 = r1->prog;
- if(p1->to.type != D_REG)
- continue;
- if(p1->to.reg != p->reg)
- if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
- continue;
- switch(p1->as) {
- default:
- continue;
- case AMOVW:
- if(p1->from.type != D_REG)
- continue;
- case AAND:
- case AEOR:
- case AORR:
- case ABIC:
- case AMVN:
- case ASUB:
- case ARSB:
- case AADD:
- case AADC:
- case ASBC:
- case ARSC:
- break;
- }
- p1->scond |= C_SBIT;
- r2->prog->as = t;
- excise(r);
- continue;
- }
- }
-
- predicate();
-}
-
-void
-excise(Reg *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; /**/
-}
-
-Reg*
-uniqp(Reg *r)
-{
- Reg *r1;
-
- r1 = r->p1;
- if(r1 == R) {
- r1 = r->p2;
- if(r1 == R || r1->p2link != R)
- return R;
- } else
- if(r->p2 != R)
- return R;
- return r1;
-}
-
-Reg*
-uniqs(Reg *r)
-{
- Reg *r1;
-
- r1 = r->s1;
- if(r1 == R) {
- r1 = r->s2;
- if(r1 == R)
- return R;
- } else
- if(r->s2 != R)
- return R;
- return r1;
-}
-
-int
-regtyp(Addr *a)
-{
-
- if(a->type == D_REG)
- return 1;
- if(a->type == D_FREG)
- return 1;
- return 0;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-int
-subprop(Reg *r0)
-{
- Prog *p;
- Addr *v1, *v2;
- Reg *r;
- int t;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case ABL:
- return 0;
-
- case ACMP:
- case ACMN:
- case AADD:
- case ASUB:
- case ARSB:
- case ASLL:
- case ASRL:
- case ASRA:
- case AORR:
- case AAND:
- case AEOR:
- case AMUL:
- case ADIV:
- case ADIVU:
-
- case ACMPF:
- case ACMPD:
- case AADDD:
- case AADDF:
- case ASUBD:
- case ASUBF:
- case AMULD:
- case AMULF:
- case ADIVD:
- case ADIVF:
- if(p->to.type == v1->type)
- if(p->to.reg == v1->reg) {
- if(p->reg == NREG)
- p->reg = p->to.reg;
- goto gotit;
- }
- break;
-
- case AMOVF:
- case AMOVD:
- case AMOVW:
- if(p->to.type == v1->type)
- if(p->to.reg == v1->reg)
- goto gotit;
- break;
-
- case AMOVM:
- t = 1<<v2->reg;
- if((p->from.type == D_CONST && (p->from.offset&t)) ||
- (p->to.type == D_CONST && (p->to.offset&t)))
- return 0;
- break;
- }
- if(copyau(&p->from, v2) ||
- copyau1(p, v2) ||
- copyau(&p->to, v2))
- break;
- if(copysub(&p->from, v1, v2, 0) ||
- copysub1(p, v1, v2, 0) ||
- copysub(&p->to, v1, v2, 0))
- break;
- }
- return 0;
-
-gotit:
- copysub(&p->to, v1, v2, 1);
- if(debug['P']) {
- print("gotit: %D->%D\n%P", v1, v2, r->prog);
- if(p->from.type == v2->type)
- print(" excise");
- print("\n");
- }
- for(r=uniqs(r); r!=r0; r=uniqs(r)) {
- p = r->prog;
- copysub(&p->from, v1, v2, 1);
- copysub1(p, v1, v2, 1);
- copysub(&p->to, v1, v2, 1);
- if(debug['P'])
- print("%P\n", r->prog);
- }
- t = v1->reg;
- v1->reg = v2->reg;
- v2->reg = t;
- if(debug['P'])
- print("%P last\n", r->prog);
- return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
-int
-copyprop(Reg *r0)
-{
- Prog *p;
- Addr *v1, *v2;
- Reg *r;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Addr *v1, Addr *v2, Reg *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, A);
- switch(t) {
- case 2: /* rar, can't split */
- if(debug['P'])
- print("; %Drar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %Dset; return 1\n", v2);
- return 1;
-
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %Dused+set and f=%d; return 0\n", v2, f);
- else
- print("; %Dused and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub%D/%D", v2, v1);
- if(t == 4) {
- if(debug['P'])
- print("; %Dused+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, A);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %Dset and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
-}
-
-/*
- * The idea is to remove redundant constants.
- * $c1->v1
- * ($c1->v2 s/$c1/v1)*
- * set v1 return
- * The v1->v2 should be eliminated by copy propagation.
- */
-void
-constprop(Addr *c1, Addr *v1, Reg *r)
-{
- Prog *p;
-
- if(debug['C'])
- print("constprop %D->%D\n", c1, v1);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['C'])
- print("%P", p);
- if(uniqp(r) == R) {
- if(debug['C'])
- print("; merge; return\n");
- return;
- }
- if(p->as == AMOVW && copyas(&p->from, c1)) {
- if(debug['C'])
- print("; sub%D/%D", &p->from, v1);
- p->from = *v1;
- } else if(copyu(p, v1, A) > 1) {
- if(debug['C'])
- print("; %Dset; return\n", v1);
- return;
- }
- if(debug['C'])
- print("\n");
- if(r->s2)
- constprop(c1, v1, r->s2);
- }
-}
-
-/*
- * ASLL x,y,w
- * .. (not use w, not set x y w)
- * AXXX w,a,b (a != w)
- * .. (not use w)
- * (set w)
- * ----------- changed to
- * ..
- * AXXX (x<<y),a,b
- * ..
- */
-#define FAIL(msg) { if(debug['H']) print("\t%s; FAILURE\n", msg); return 0; }
-int
-shiftprop(Reg *r)
-{
- Reg *r1;
- Prog *p, *p1, *p2;
- int n, o;
- Addr a;
-
- p = r->prog;
- if(p->to.type != D_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;
- a.reg = p->reg;
- }
- if(debug['H'])
- print("shiftprop\n%P", p);
- r1 = r;
- for(;;) {
- /* find first use of shift result; abort if shift operands or result are changed */
- r1 = uniqs(r1);
- if(r1 == R)
- FAIL("branch");
- if(uniqp(r1) == R)
- FAIL("merge");
- p1 = r1->prog;
- if(debug['H'])
- print("\n%P", p1);
- switch(copyu(p1, &p->to, A)) {
- case 0: /* not used or set */
- if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) ||
- (a.type == D_REG && copyu(p1, &a, A) > 1))
- FAIL("args modified");
- continue;
- case 3: /* set, not used */
- FAIL("BOTCH: noref");
- }
- break;
- }
- /* check whether substitution can be done */
- switch(p1->as) {
- default:
- FAIL("non-dpi");
- case AAND:
- case AEOR:
- case AADD:
- case AADC:
- case AORR:
- case ASUB:
- case ARSB:
- case ASBC:
- case ARSC:
- if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
- if(p1->from.type != D_REG)
- FAIL("can't swap");
- p1->reg = p1->from.reg;
- p1->from.reg = n;
- switch(p1->as) {
- case ASUB:
- p1->as = ARSB;
- break;
- case ARSB:
- p1->as = ASUB;
- break;
- case ASBC:
- p1->as = ARSC;
- break;
- case ARSC:
- p1->as = ASBC;
- break;
- }
- if(debug['H'])
- print("\t=>%P", p1);
- }
- case ABIC:
- case ACMP:
- case ACMN:
- if(p1->reg == n)
- FAIL("can't swap");
- if(p1->reg == NREG && p1->to.reg == n)
- FAIL("shift result used twice");
- case AMVN:
- if(p1->from.type == D_SHIFT)
- FAIL("shift result used in shift");
- if(p1->from.type != D_REG || p1->from.reg != n)
- FAIL("BOTCH: where is it used?");
- break;
- }
- /* check whether shift result is used subsequently */
- p2 = p1;
- if(p1->to.reg != n)
- for (;;) {
- r1 = uniqs(r1);
- if(r1 == R)
- FAIL("inconclusive");
- p1 = r1->prog;
- if(debug['H'])
- print("\n%P", p1);
- switch(copyu(p1, &p->to, A)) {
- case 0: /* not used or set */
- continue;
- case 3: /* set, not used */
- break;
- default:/* used */
- FAIL("reused");
- }
- break;
- }
- /* make the substitution */
- p2->from.type = D_SHIFT;
- p2->from.reg = NREG;
- o = p->reg;
- if(o == NREG)
- o = p->to.reg;
- switch(p->from.type){
- case D_CONST:
- o |= (p->from.offset&0x1f)<<7;
- break;
- case D_REG:
- o |= (1<<4) | (p->from.reg<<8);
- break;
- }
- switch(p->as){
- case ASLL:
- o |= 0<<5;
- break;
- case ASRL:
- o |= 1<<5;
- break;
- case ASRA:
- o |= 2<<5;
- break;
- }
- p2->from.offset = o;
- if(debug['H'])
- print("\t=>%P\tSUCCEED\n", p2);
- return 1;
-}
-
-Reg*
-findpre(Reg *r, Addr *v)
-{
- Reg *r1;
-
- for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) {
- if(uniqs(r1) != r)
- return R;
- switch(copyu(r1->prog, v, A)) {
- case 1: /* used */
- case 2: /* read-alter-rewrite */
- return R;
- case 3: /* set */
- case 4: /* set and used */
- return r1;
- }
- }
- return R;
-}
-
-Reg*
-findinc(Reg *r, Reg *r2, Addr *v)
-{
- Reg *r1;
- Prog *p;
-
-
- for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) {
- if(uniqp(r1) != r)
- return R;
- switch(copyu(r1->prog, v, A)) {
- case 0: /* not touched */
- continue;
- case 4: /* set and used */
- p = r1->prog;
- if(p->as == AADD)
- if(p->from.type == D_CONST)
- if(p->from.offset > -4096 && p->from.offset < 4096)
- return r1;
- default:
- return R;
- }
- }
- return R;
-}
-
-int
-nochange(Reg *r, Reg *r2, Prog *p)
-{
- Addr a[3];
- int i, n;
-
- if(r == r2)
- return 1;
- n = 0;
- if(p->reg != NREG && p->reg != p->to.reg) {
- a[n].type = D_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;
- a[n++].reg = p->from.reg;
- }
- if(n == 0)
- return 1;
- for(; r!=R && r!=r2; r=uniqs(r)) {
- p = r->prog;
- for(i=0; i<n; i++)
- if(copyu(p, &a[i], A) > 1)
- return 0;
- }
- return 1;
-}
-
-int
-findu1(Reg *r, Addr *v)
-{
- for(; r != R; r = r->s1) {
- if(r->active)
- return 0;
- r->active = 1;
- switch(copyu(r->prog, v, A)) {
- case 1: /* used */
- case 2: /* read-alter-rewrite */
- case 4: /* set and used */
- return 1;
- case 3: /* set */
- return 0;
- }
- if(r->s2)
- if (findu1(r->s2, v))
- return 1;
- }
- return 0;
-}
-
-int
-finduse(Reg *r, Addr *v)
-{
- Reg *r1;
-
- for(r1=firstr; r1!=R; r1=r1->link)
- r1->active = 0;
- return findu1(r, v);
-}
-
-int
-xtramodes(Reg *r, Addr *a)
-{
- Reg *r1, *r2, *r3;
- Prog *p, *p1;
- Addr v;
-
- p = r->prog;
- if((p->as == AMOVB || p->as == AMOVBS) && p->from.type == D_OREG) /* byte load */
- return 0;
- v = *a;
- v.type = D_REG;
- r1 = findpre(r, &v);
- if(r1 != R) {
- p1 = r1->prog;
- if(p1->to.type == D_REG && p1->to.reg == v.reg)
- switch(p1->as) {
- case AADD:
- if(p1->from.type == D_REG ||
- (p1->from.type == D_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.offset > -4096 && p1->from.offset < 4096))
- if(nochange(uniqs(r1), r, p1)) {
- if(a != &p->from || v.reg != p->to.reg)
- if (finduse(r->s1, &v)) {
- if(p1->reg == NREG || p1->reg == v.reg)
- /* pre-indexing */
- p->scond |= C_WBIT;
- else return 0;
- }
- switch (p1->from.type) {
- case D_REG:
- /* register offset */
- if(nacl)
- return 0;
- a->type = D_SHIFT;
- a->offset = p1->from.reg;
- break;
- case D_SHIFT:
- /* scaled register offset */
- if(nacl)
- return 0;
- a->type = D_SHIFT;
- case D_CONST:
- /* immediate offset */
- a->offset = p1->from.offset;
- break;
- }
- if(p1->reg != NREG)
- a->reg = p1->reg;
- excise(r1);
- return 1;
- }
- break;
- case AMOVW:
- if(p1->from.type == D_REG)
- if((r2 = findinc(r1, r, &p1->from)) != R) {
- for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
- ;
- if(r3 == r) {
- /* post-indexing */
- p1 = r2->prog;
- a->reg = p1->to.reg;
- a->offset = p1->from.offset;
- p->scond |= C_PBIT;
- if(!finduse(r, &r1->prog->to))
- excise(r1);
- excise(r2);
- return 1;
- }
- }
- break;
- }
- }
- if(a != &p->from || a->reg != p->to.reg)
- if((r1 = findinc(r, R, &v)) != R) {
- /* post-indexing */
- p1 = r1->prog;
- a->offset = p1->from.offset;
- p->scond |= C_PBIT;
- excise(r1);
- return 1;
- }
- return 0;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-int
-copyu(Prog *p, Addr *v, Addr *s)
-{
-
- switch(p->as) {
-
- default:
- if(debug['P'])
- print(" (?)");
- return 2;
-
- case AMOVM:
- if(v->type != D_REG)
- return 0;
- if(p->from.type == D_CONST) { /* read reglist, read/rar */
- if(s != A) {
- if(p->from.offset&(1<<v->reg))
- return 1;
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v)) {
- if(p->scond&C_WBIT)
- return 2;
- return 1;
- }
- if(p->from.offset&(1<<v->reg))
- return 1;
- } else { /* read/rar, write reglist */
- if(s != A) {
- if(p->to.offset&(1<<v->reg))
- return 1;
- if(copysub(&p->from, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->from, v)) {
- if(p->scond&C_WBIT)
- return 2;
- if(p->to.offset&(1<<v->reg))
- return 4;
- return 1;
- }
- if(p->to.offset&(1<<v->reg))
- return 3;
- }
- return 0;
-
- case ANOP: /* read, write */
- case AMOVW:
- case AMOVF:
- case AMOVD:
- case AMOVH:
- case AMOVHS:
- case AMOVHU:
- case AMOVB:
- case AMOVBS:
- case AMOVBU:
- case AMOVDW:
- case AMOVWD:
- 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(p->from.reg == v->reg)
- return 2;
- } else {
- if(p->to.reg == v->reg)
- return 2;
- }
- }
- if(s != A) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- if(copyau(&p->from, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
-
- case AADD: /* read, read, write */
- case ASUB:
- case ARSB:
- case ASLL:
- case ASRL:
- case ASRA:
- case AORR:
- case AAND:
- case AEOR:
- case AMUL:
- case ADIV:
- case ADIVU:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
-
- case ACMPF:
- case ACMPD:
- case ACMP:
- case ACMN:
- case ACASE:
- if(s != A) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- if(copysub1(p, v, s, 1))
- return 1;
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- if(p->reg == NREG)
- p->reg = p->to.reg;
- if(copyau(&p->from, v))
- return 4;
- if(copyau1(p, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau1(p, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ABEQ: /* read, read */
- case ABNE:
- case ABCS:
- case ABHS:
- case ABCC:
- case ABLO:
- case ABMI:
- case ABPL:
- case ABVS:
- case ABVC:
- case ABHI:
- case ABLS:
- case ABGE:
- case ABLT:
- case ABGT:
- case ABLE:
- case APLD:
- if(s != A) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return copysub1(p, v, s, 1);
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau1(p, v))
- return 1;
- return 0;
-
- case AB: /* funny */
- if(s != A) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ARET: /* funny */
- if(v->type == D_REG)
- if(v->reg == REGRET)
- return 2;
- if(v->type == D_FREG)
- if(v->reg == FREGRET)
- return 2;
-
- case ABL: /* funny */
- if(v->type == D_REG) {
- if(v->reg <= REGEXT && v->reg > exregoffset)
- return 2;
- if(v->reg == REGARG)
- return 2;
- }
- if(v->type == D_FREG)
- if(v->reg <= FREGEXT && v->reg > exfregoffset)
- return 2;
-
- if(s != A) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 4;
- return 3;
-
- case ATEXT: /* funny */
- if(v->type == D_REG)
- if(v->reg == REGARG)
- return 3;
- return 0;
- }
-}
-
-int
-a2type(Prog *p)
-{
-
- switch(p->as) {
-
- case ACMP:
- case ACMN:
-
- case AADD:
- case ASUB:
- case ARSB:
- case ASLL:
- case ASRL:
- case ASRA:
- case AORR:
- case AAND:
- case AEOR:
- case AMUL:
- case ADIV:
- case ADIVU:
- return D_REG;
-
- case ACMPF:
- case ACMPD:
-
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- return D_FREG;
- }
- return D_NONE;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-int
-copyas(Addr *a, Addr *v)
-{
-
- if(regtyp(v)) {
- if(a->type == v->type)
- if(a->reg == v->reg)
- return 1;
- } else if(v->type == D_CONST) { /* for constprop */
- if(a->type == v->type)
- if(a->name == v->name)
- if(a->sym == v->sym)
- if(a->reg == v->reg)
- if(a->offset == v->offset)
- return 1;
- }
- return 0;
-}
-
-/*
- * either direct or indirect
- */
-int
-copyau(Addr *a, Addr *v)
-{
-
- if(copyas(a, v))
- return 1;
- if(v->type == D_REG) {
- if(a->type == D_OREG) {
- if(v->reg == a->reg)
- return 1;
- } else if(a->type == D_SHIFT) {
- if((a->offset&0xf) == v->reg)
- return 1;
- if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
- return 1;
- }
- }
- return 0;
-}
-
-int
-copyau1(Prog *p, Addr *v)
-{
-
- if(regtyp(v)) {
- if(a2type(p) == v->type)
- if(p->reg == v->reg) {
- if(a2type(p) != v->type)
- print("botch a2type %P\n", p);
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-int
-copysub(Addr *a, Addr *v, Addr *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);
- } else
- a->reg = s->reg;
- }
- return 0;
-}
-
-int
-copysub1(Prog *p1, Addr *v, Addr *s, int f)
-{
-
- if(f)
- if(copyau1(p1, v))
- p1->reg = s->reg;
- return 0;
-}
-
-struct {
- int opcode;
- int notopcode;
- int scond;
- int notscond;
-} predinfo[] = {
- { ABEQ, ABNE, 0x0, 0x1, },
- { ABNE, ABEQ, 0x1, 0x0, },
- { ABCS, ABCC, 0x2, 0x3, },
- { ABHS, ABLO, 0x2, 0x3, },
- { ABCC, ABCS, 0x3, 0x2, },
- { ABLO, ABHS, 0x3, 0x2, },
- { ABMI, ABPL, 0x4, 0x5, },
- { ABPL, ABMI, 0x5, 0x4, },
- { ABVS, ABVC, 0x6, 0x7, },
- { ABVC, ABVS, 0x7, 0x6, },
- { ABHI, ABLS, 0x8, 0x9, },
- { ABLS, ABHI, 0x9, 0x8, },
- { ABGE, ABLT, 0xA, 0xB, },
- { ABLT, ABGE, 0xB, 0xA, },
- { ABGT, ABLE, 0xC, 0xD, },
- { ABLE, ABGT, 0xD, 0xC, },
-};
-
-typedef struct {
- Reg *start;
- Reg *last;
- Reg *end;
- int len;
-} Joininfo;
-
-enum {
- Join,
- Split,
- End,
- Branch,
- Setcond,
- Toolong
-};
-
-enum {
- Falsecond,
- Truecond,
- Delbranch,
- Keepbranch
-};
-
-int
-isbranch(Prog *p)
-{
- return (ABEQ <= p->as) && (p->as <= ABLE);
-}
-
-int
-predicable(Prog *p)
-{
- if (isbranch(p)
- || p->as == ANOP
- || p->as == AXXX
- || p->as == ADATA
- || p->as == AGLOBL
- || p->as == AGOK
- || p->as == AHISTORY
- || p->as == ANAME
- || p->as == ASIGNAME
- || p->as == ATEXT
- || p->as == AWORD
- || p->as == ABCASE
- || p->as == ACASE)
- return 0;
- return 1;
-}
-
-/*
- * Depends on an analysis of the encodings performed by 5l.
- * These seem to be all of the opcodes that lead to the "S" bit
- * being set in the instruction encodings.
- *
- * C_SBIT may also have been set explicitly in p->scond.
- */
-int
-modifiescpsr(Prog *p)
-{
- return (p->scond&C_SBIT)
- || p->as == ATST
- || p->as == ATEQ
- || p->as == ACMN
- || p->as == ACMP
- || p->as == AMULU
- || p->as == ADIVU
- || p->as == AMUL
- || p->as == ADIV
- || p->as == AMOD
- || p->as == AMODU
- || p->as == ABL;
-}
-
-/*
- * Find the maximal chain of instructions starting with r which could
- * be executed conditionally
- */
-int
-joinsplit(Reg *r, Joininfo *j)
-{
- j->start = r;
- j->last = r;
- j->len = 0;
- do {
- if (r->p2 && (r->p1 || r->p2->p2link)) {
- j->end = r;
- return Join;
- }
- if (r->s1 && r->s2) {
- j->end = r;
- return Split;
- }
- j->last = r;
- if (r->prog->as != ANOP)
- j->len++;
- if (!r->s1 && !r->s2) {
- j->end = r->link;
- return End;
- }
- if (r->s2) {
- j->end = r->s2;
- return Branch;
- }
- if (modifiescpsr(r->prog)) {
- j->end = r->s1;
- return Setcond;
- }
- r = r->s1;
- } while (j->len < 4);
- j->end = r;
- return Toolong;
-}
-
-Reg *
-successor(Reg *r)
-{
- if (r->s1)
- return r->s1;
- else
- return r->s2;
-}
-
-void
-applypred(Reg *rstart, Joininfo *j, int cond, int branch)
-{
- int pred;
- Reg *r;
-
- if(j->len == 0)
- return;
- if (cond == Truecond)
- pred = predinfo[rstart->prog->as - ABEQ].scond;
- else
- pred = predinfo[rstart->prog->as - ABEQ].notscond;
-
- for (r = j->start; ; r = successor(r)) {
- if (r->prog->as == AB) {
- if (r != j->last || branch == Delbranch)
- excise(r);
- else {
- if (cond == Truecond)
- r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
- else
- r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
- }
- }
- else if (predicable(r->prog))
- r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
- if (r->s1 != r->link) {
- r->s1 = r->link;
- r->link->p1 = r;
- }
- if (r == j->last)
- break;
- }
-}
-
-void
-predicate(void)
-{
- Reg *r;
- int t1, t2;
- Joininfo j1, j2;
-
- for(r=firstr; r!=R; r=r->link) {
- if (isbranch(r->prog)) {
- t1 = joinsplit(r->s1, &j1);
- t2 = joinsplit(r->s2, &j2);
- if(j1.last->link != j2.start)
- continue;
- if(j1.end == j2.end)
- if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
- (t2 == Join && (t1 == Join || t1 == Setcond))) {
- applypred(r, &j1, Falsecond, Delbranch);
- applypred(r, &j2, Truecond, Delbranch);
- excise(r);
- continue;
- }
- if(t1 == End || t1 == Branch) {
- applypred(r, &j1, Falsecond, Keepbranch);
- excise(r);
- continue;
- }
- }
- }
-}
diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c
deleted file mode 100644
index 9024d5f49..000000000
--- a/src/cmd/5c/reg.c
+++ /dev/null
@@ -1,1210 +0,0 @@
-// Inferno utils/5c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-#include "gc.h"
-
-void addsplits(void);
-
-Reg*
-rega(void)
-{
- Reg *r;
-
- r = freer;
- if(r == R) {
- r = alloc(sizeof(*r));
- } else
- freer = r->link;
-
- *r = zreg;
- return r;
-}
-
-int
-rcmp(const void *a1, const void *a2)
-{
- Rgn *p1, *p2;
- int c1, c2;
-
- p1 = (Rgn*)a1;
- p2 = (Rgn*)a2;
- c1 = p2->cost;
- c2 = p1->cost;
- if(c1 -= c2)
- return c1;
- return p2->varno - p1->varno;
-}
-
-void
-regopt(Prog *p)
-{
- Reg *r, *r1, *r2;
- Prog *p1;
- int i, z;
- int32 initpc, val, npc;
- uint32 vreg;
- Bits bit;
- struct
- {
- int32 m;
- int32 c;
- Reg* p;
- } log5[6], *lp;
-
- firstr = R;
- lastr = R;
- nvar = 0;
- regbits = 0;
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- }
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- val = 5L * 5L * 5L * 5L * 5L;
- lp = log5;
- for(i=0; i<5; i++) {
- lp->m = val;
- lp->c = 0;
- lp->p = R;
- val /= 5L;
- lp++;
- }
- val = 0;
- for(; p != P; p = p->link) {
- switch(p->as) {
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- case AFUNCDATA:
- continue;
- }
- r = rega();
- if(firstr == R) {
- firstr = r;
- lastr = r;
- } else {
- lastr->link = r;
- r->p1 = lastr;
- lastr->s1 = r;
- lastr = r;
- }
- r->prog = p;
- r->pc = val;
- val++;
-
- lp = log5;
- for(i=0; i<5; i++) {
- lp->c--;
- if(lp->c <= 0) {
- lp->c = lp->m;
- if(lp->p != R)
- lp->p->log5 = r;
- lp->p = r;
- (lp+1)->c = 0;
- break;
- }
- lp++;
- }
-
- r1 = r->p1;
- if(r1 != R)
- switch(r1->prog->as) {
- case ARET:
- case AB:
- case ARFE:
- r->p1 = R;
- r1->s1 = R;
- }
-
- /*
- * left side always read
- */
- bit = mkvar(&p->from, p->as==AMOVW);
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
-
- /*
- * right side depends on opcode
- */
- bit = mkvar(&p->to, 0);
- if(bany(&bit))
- switch(p->as) {
- default:
- diag(Z, "reg: unknown asop: %A", p->as);
- break;
-
- /*
- * right side write
- */
- case ANOP:
- case AMOVB:
- case AMOVBS:
- case AMOVBU:
- case AMOVH:
- case AMOVHS:
- case AMOVHU:
- case AMOVW:
- case AMOVF:
- case AMOVD:
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- break;
-
- /*
- * right side read
- */
- case APLD:
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- break;
-
- /*
- * funny
- */
- case ABL:
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- break;
- }
-
- /* the mod/div runtime routines smash R12 */
- switch(p->as) {
- case AMOD:
- case AMODU:
- case ADIV:
- case ADIVU:
- regbits |= RtoB(12);
- break;
- }
-
- if(p->as == AMOVM) {
- if(p->from.type == D_CONST)
- z = p->from.offset;
- else
- z = p->to.offset;
- for(i=0; z; i++) {
- if(z&1)
- regbits |= RtoB(i);
- z >>= 1;
- }
- }
- }
- if(firstr == R)
- return;
- initpc = pc - val;
- npc = val;
-
- /*
- * pass 2
- * turn branch references to pointers
- * build back pointers
- */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH) {
- val = p->to.offset - initpc;
- r1 = firstr;
- while(r1 != R) {
- r2 = r1->log5;
- if(r2 != R && val >= r2->pc) {
- r1 = r2;
- continue;
- }
- if(r1->pc == val)
- break;
- r1 = r1->link;
- }
- if(r1 == R) {
- nearln = p->lineno;
- diag(Z, "ref not found\n%P", p);
- continue;
- }
- if(r1 == r) {
- nearln = p->lineno;
- diag(Z, "ref to self\n%P", p);
- continue;
- }
- r->s2 = r1;
- r->p2link = r1->p2;
- r1->p2 = r;
- }
- }
- if(debug['R']) {
- p = firstr->prog;
- print("\n%L %D\n", p->lineno, &p->from);
- }
-
- /*
- * pass 2.5
- * find looping structure
- */
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- change = 0;
- loopit(firstr, npc);
-
- /*
- * pass 3
- * iterate propagating usage
- * back until flow graph is complete
- */
-loop1:
- change = 0;
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- for(r = firstr; r != R; r = r->link)
- if(r->prog->as == ARET)
- prop(r, zbits, zbits);
-loop11:
- /* pick up unreachable code */
- i = 0;
- for(r = firstr; r != R; r = r1) {
- r1 = r->link;
- if(r1 && r1->active && !r->active) {
- prop(r, zbits, zbits);
- i = 1;
- }
- }
- if(i)
- goto loop11;
- if(change)
- goto loop1;
-
-
- /*
- * pass 4
- * iterate propagating register/variable synchrony
- * forward until graph is complete
- */
-loop2:
- change = 0;
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- synch(firstr, zbits);
- if(change)
- goto loop2;
-
- addsplits();
-
- if(debug['R'] && debug['v']) {
- print("\nprop structure:\n");
- for(r = firstr; r != R; r = r->link) {
- print("%d:%P", r->loop, r->prog);
- for(z=0; z<BITS; z++)
- bit.b[z] = r->set.b[z] |
- r->refahead.b[z] | r->calahead.b[z] |
- r->refbehind.b[z] | r->calbehind.b[z] |
- r->use1.b[z] | r->use2.b[z];
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->use1))
- print(" u1=%B", r->use1);
- if(bany(&r->use2))
- print(" u2=%B", r->use2);
- if(bany(&r->set))
- print(" st=%B", r->set);
- if(bany(&r->refahead))
- print(" ra=%B", r->refahead);
- if(bany(&r->calahead))
- print(" ca=%B", r->calahead);
- if(bany(&r->refbehind))
- print(" rb=%B", r->refbehind);
- if(bany(&r->calbehind))
- print(" cb=%B", r->calbehind);
- }
- print("\n");
- }
- }
-
- /*
- * pass 5
- * isolate regions
- * calculate costs (paint1)
- */
- r = firstr;
- if(r) {
- for(z=0; z<BITS; z++)
- bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
- ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
- if(bany(&bit)) {
- nearln = r->prog->lineno;
- warn(Z, "used and not set: %B", bit);
- if(debug['R'] && !debug['w'])
- print("used and not set: %B\n", bit);
- }
- }
-
- for(r = firstr; r != R; r = r->link)
- r->act = zbits;
- rgp = region;
- nregion = 0;
- for(r = firstr; r != R; r = r->link) {
- for(z=0; z<BITS; z++)
- bit.b[z] = r->set.b[z] &
- ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
- if(bany(&bit)) {
- nearln = r->prog->lineno;
- warn(Z, "set and not used: %B", bit);
- if(debug['R'])
- print("set and not used: %B\n", bit);
- excise(r);
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- rgp->enter = r;
- rgp->varno = i;
- change = 0;
- if(debug['R'] && debug['v'])
- print("\n");
- paint1(r, i);
- bit.b[i/32] &= ~(1L<<(i%32));
- if(change <= 0) {
- if(debug['R'])
- print("%L $%d: %B\n",
- r->prog->lineno, change, blsh(i));
- continue;
- }
- rgp->cost = change;
- nregion++;
- if(nregion >= NRGN) {
- fatal(Z, "too many regions");
- goto brk;
- }
- rgp++;
- }
- }
-brk:
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- for(i=0; i<nregion; i++) {
- bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
- vreg = allreg(vreg, rgp);
- if(debug['R']) {
- if(rgp->regno >= NREG)
- print("%L $%d F%d: %B\n",
- rgp->enter->prog->lineno,
- rgp->cost,
- rgp->regno-NREG,
- bit);
- else
- print("%L $%d R%d: %B\n",
- rgp->enter->prog->lineno,
- rgp->cost,
- rgp->regno,
- bit);
- }
- if(rgp->regno != 0)
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- rgp++;
- }
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P'])
- peep();
-
- /*
- * pass 8
- * recalculate pc
- */
- val = initpc;
- for(r = firstr; r != R; r = r1) {
- r->pc = val;
- p = r->prog;
- p1 = P;
- r1 = r->link;
- if(r1 != R)
- p1 = r1->prog;
- for(; p != p1; p = p->link) {
- switch(p->as) {
- default:
- val++;
- break;
-
- case ANOP:
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- case AFUNCDATA:
- break;
- }
- }
- }
- pc = val;
-
- /*
- * fix up branches
- */
- if(debug['R'])
- if(bany(&addrs))
- print("addrs: %B\n", addrs);
-
- r1 = 0; /* set */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH) {
- p->to.offset = r->s2->pc;
- p->to.u.branch = r->s2->prog;
- }
- r1 = r;
- }
-
- /*
- * last pass
- * eliminate nops
- * free aux structures
- */
- for(p = firstr->prog; p != P; p = p->link){
- while(p->link && p->link->as == ANOP)
- p->link = p->link->link;
- }
- if(r1 != R) {
- r1->link = freer;
- freer = firstr;
- }
-}
-
-void
-addsplits(void)
-{
- Reg *r, *r1;
- int z, i;
- Bits bit;
-
- for(r = firstr; r != R; r = r->link) {
- if(r->loop > 1)
- continue;
- if(r->prog->as == ABL)
- continue;
- for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
- if(r1->loop <= 1)
- continue;
- for(z=0; z<BITS; z++)
- bit.b[z] = r1->calbehind.b[z] &
- (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
- ~(r->calahead.b[z] & addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- bit.b[i/32] &= ~(1L << (i%32));
- }
- }
- }
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Addr *a;
- Var *v;
-
- p1 = alloc(sizeof(*p1));
- *p1 = zprog;
- p = r->prog;
-
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->sym = v->sym;
- a->name = v->name;
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = D_OREG;
- if(a->etype == TARRAY || a->sym == nil)
- a->type = D_CONST;
-
- p1->as = AMOVW;
- if(v->etype == TCHAR || v->etype == TUCHAR)
- p1->as = AMOVBS;
- if(v->etype == TSHORT || v->etype == TUSHORT)
- p1->as = AMOVHS;
- if(v->etype == TFLOAT)
- p1->as = AMOVF;
- if(v->etype == TDOUBLE)
- p1->as = AMOVD;
-
- p1->from.type = D_REG;
- p1->from.reg = rn;
- if(rn >= NREG) {
- p1->from.type = D_FREG;
- p1->from.reg = rn-NREG;
- }
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = D_REG;
- a->reg = rn;
- if(rn >= NREG) {
- a->type = D_FREG;
- a->reg = rn-NREG;
- }
- if(v->etype == TUCHAR)
- p1->as = AMOVBU;
- if(v->etype == TUSHORT)
- p1->as = AMOVHU;
- }
- if(debug['R'])
- print("%P\t.a%P\n", p, p1);
-}
-
-Bits
-mkvar(Addr *a, int docon)
-{
- Var *v;
- int i, t, n, et, z;
- int32 o;
- Bits bit;
- LSym *s;
-
- t = a->type;
- if(t == D_REG && a->reg != NREG)
- regbits |= RtoB(a->reg);
- if(t == D_FREG && a->reg != NREG)
- regbits |= FtoB(a->reg);
- s = a->sym;
- o = a->offset;
- et = a->etype;
- if(s == nil) {
- if(t != D_CONST || !docon || a->reg != NREG)
- goto none;
- et = TLONG;
- }
- if(t == D_CONST) {
- if(s == nil && sval(o))
- goto none;
- }
-
- n = a->name;
- v = var;
- for(i=0; i<nvar; i++) {
- if(s == v->sym)
- if(n == v->name)
- if(o == v->offset)
- goto out;
- v++;
- }
- if(s)
- if(s->name[0] == '.')
- goto none;
- if(nvar >= NVAR)
- fatal(Z, "variable not optimized: %s", s->name);
- i = nvar;
- nvar++;
- v = &var[i];
- v->sym = s;
- v->offset = o;
- v->etype = et;
- v->name = n;
- if(debug['R'])
- print("bit=%2d et=%2d %D\n", i, et, a);
-out:
- bit = blsh(i);
- if(n == D_EXTERN || n == D_STATIC)
- for(z=0; z<BITS; z++)
- externs.b[z] |= bit.b[z];
- if(n == D_PARAM)
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
- if(v->etype != et || !typechlpfd[et]) /* funny punning */
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- if(t == D_CONST) {
- if(s == nil) {
- for(z=0; z<BITS; z++)
- consts.b[z] |= bit.b[z];
- return bit;
- }
- if(et != TARRAY)
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
- return bit;
- }
- if(t == D_OREG)
- return bit;
-
-none:
- return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
- Reg *r1, *r2;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->p1) {
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(r1->prog->as) {
- case ABL:
- for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z];
- ref.b[z] = 0;
- }
- break;
-
- case ATEXT:
- for(z=0; z<BITS; z++) {
- cal.b[z] = 0;
- ref.b[z] = 0;
- }
- break;
-
- case ARET:
- for(z=0; z<BITS; z++) {
- cal.b[z] = externs.b[z];
- ref.b[z] = 0;
- }
- }
- for(z=0; z<BITS; z++) {
- ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
- r1->use1.b[z] | r1->use2.b[z];
- cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
- r1->refbehind.b[z] = ref.b[z];
- r1->calbehind.b[z] = cal.b[z];
- }
- if(r1->active)
- break;
- r1->active = 1;
- }
- for(; r != r1; r = r->p1)
- for(r2 = r->p2; r2 != R; r2 = r2->p2link)
- prop(r2, r->refbehind, r->calbehind);
-}
-
-/*
- * find looping structure
- *
- * 1) find reverse postordering
- * 2) find approximate dominators,
- * the actual dominators if the flow graph is reducible
- * otherwise, dominators plus some other non-dominators.
- * See Matthew S. Hecht and Jeffrey D. Ullman,
- * "Analysis of a Simple Algorithm for Global Data Flow Problems",
- * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
- * Oct. 1-3, 1973, pp. 207-217.
- * 3) find all nodes with a predecessor dominated by the current node.
- * such a node is a loop head.
- * recursively, all preds with a greater rpo number are in the loop
- */
-int32
-postorder(Reg *r, Reg **rpo2r, int32 n)
-{
- Reg *r1;
-
- r->rpo = 1;
- r1 = r->s1;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- r1 = r->s2;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- rpo2r[n] = r;
- n++;
- return n;
-}
-
-int32
-rpolca(int32 *idom, int32 rpo1, int32 rpo2)
-{
- int32 t;
-
- if(rpo1 == -1)
- return rpo2;
- while(rpo1 != rpo2){
- if(rpo1 > rpo2){
- t = rpo2;
- rpo2 = rpo1;
- rpo1 = t;
- }
- while(rpo1 < rpo2){
- t = idom[rpo2];
- if(t >= rpo2)
- fatal(Z, "bad idom");
- rpo2 = t;
- }
- }
- return rpo1;
-}
-
-int
-doms(int32 *idom, int32 r, int32 s)
-{
- while(s > r)
- s = idom[s];
- return s == r;
-}
-
-int
-loophead(int32 *idom, Reg *r)
-{
- int32 src;
-
- src = r->rpo;
- if(r->p1 != R && doms(idom, src, r->p1->rpo))
- return 1;
- for(r = r->p2; r != R; r = r->p2link)
- if(doms(idom, src, r->rpo))
- return 1;
- return 0;
-}
-
-void
-loopmark(Reg **rpo2r, int32 head, Reg *r)
-{
- if(r->rpo < head || r->active == head)
- return;
- r->active = head;
- r->loop += LOOP;
- if(r->p1 != R)
- loopmark(rpo2r, head, r->p1);
- for(r = r->p2; r != R; r = r->p2link)
- loopmark(rpo2r, head, r);
-}
-
-void
-loopit(Reg *r, int32 nr)
-{
- Reg *r1;
- int32 i, d, me;
-
- if(nr > maxnr) {
- rpo2r = alloc(nr * sizeof(Reg*));
- idom = alloc(nr * sizeof(int32));
- maxnr = nr;
- }
- d = postorder(r, rpo2r, 0);
- if(d > nr)
- fatal(Z, "too many reg nodes");
- nr = d;
- for(i = 0; i < nr / 2; i++){
- r1 = rpo2r[i];
- rpo2r[i] = rpo2r[nr - 1 - i];
- rpo2r[nr - 1 - i] = r1;
- }
- for(i = 0; i < nr; i++)
- rpo2r[i]->rpo = i;
-
- idom[0] = 0;
- for(i = 0; i < nr; i++){
- r1 = rpo2r[i];
- me = r1->rpo;
- d = -1;
- if(r1->p1 != R && r1->p1->rpo < me)
- d = r1->p1->rpo;
- for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
- if(r1->rpo < me)
- d = rpolca(idom, d, r1->rpo);
- idom[i] = d;
- }
-
- for(i = 0; i < nr; i++){
- r1 = rpo2r[i];
- r1->loop++;
- if(r1->p2 != R && loophead(idom, r1))
- loopmark(rpo2r, i, r1);
- }
-}
-
-void
-synch(Reg *r, Bits dif)
-{
- Reg *r1;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->s1) {
- for(z=0; z<BITS; z++) {
- dif.b[z] = (dif.b[z] &
- ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
- r1->set.b[z] | r1->regdiff.b[z];
- if(dif.b[z] != r1->regdiff.b[z]) {
- r1->regdiff.b[z] = dif.b[z];
- change++;
- }
- }
- if(r1->active)
- break;
- r1->active = 1;
- for(z=0; z<BITS; z++)
- dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if(r1->s2 != R)
- synch(r1->s2, dif);
- }
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
- Var *v;
- int i;
-
- v = var + r->varno;
- r->regno = 0;
- switch(v->etype) {
-
- default:
- diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
- break;
-
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- case TARRAY:
- i = BtoR(~b);
- if(i && r->cost >= 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TVLONG:
- case TDOUBLE:
- case TFLOAT:
- i = BtoF(~b);
- if(i && r->cost >= 0) {
- r->regno = i+NREG;
- return FtoB(i);
- }
- break;
- }
- return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint32 bb;
-
- z = bn/32;
- bb = 1L<<(bn%32);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
- change -= CLOAD * r->loop;
- if(debug['R'] && debug['v'])
- print("%d%P\td %B $%d\n", r->loop,
- r->prog, blsh(bn), change);
- }
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- change += CREF * r->loop;
- if(debug['R'] && debug['v'])
- print("%d%P\tu1 %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->loop;
- if(debug['R'] && debug['v'])
- print("%d%P\tu2 %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->loop;
- if(debug['R'] && debug['v'])
- print("%d%P\tst %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint1(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint1(r1, bn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
- Reg *r1;
- int z;
- uint32 bb, vreg;
-
- z = bn/32;
- bb = 1L << (bn%32);
- vreg = regbits;
- if(!(r->act.b[z] & bb))
- return vreg;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(!(r1->act.b[z] & bb))
- break;
- r = r1;
- }
- for(;;) {
- r->act.b[z] &= ~bb;
-
- vreg |= r->regu;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
- r = r->s1;
- if(r == R)
- break;
- if(!(r->act.b[z] & bb))
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
- return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint32 bb;
-
- z = bn/32;
- bb = 1L << (bn%32);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
- addmove(r, bn, rn, 0);
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->from, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->to, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(r, bn, rn, 1);
- r->regu |= rb;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Addr *a, int rn)
-{
-
- a->sym = 0;
- a->name = D_NONE;
- a->type = D_REG;
- a->reg = rn;
- if(rn >= NREG) {
- a->type = D_FREG;
- a->reg = rn-NREG;
- }
-}
-
-/*
- * bit reg
- * 0 R0
- * 1 R1
- * ... ...
- * 10 R10
- * 12 R12
- */
-int32
-RtoB(int r)
-{
-
- if(r < 2 || (r >= REGTMP-2 && r != 12)) // excluded R9 and R10 for m and g, but not R12
- return 0;
- return 1L << r;
-}
-
-int
-BtoR(int32 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
- */
-int32
-FtoB(int f)
-{
-
- if(f < 2 || f > NFREG-1)
- return 0;
- return 1L << (f + 16);
-}
-
-int
-BtoF(int32 b)
-{
-
- b &= 0xfffc0000L;
- if(b == 0)
- return 0;
- return bitno(b) - 16;
-}
diff --git a/src/cmd/5c/sgen.c b/src/cmd/5c/sgen.c
deleted file mode 100644
index a36612caa..000000000
--- a/src/cmd/5c/sgen.c
+++ /dev/null
@@ -1,265 +0,0 @@
-// Inferno utils/5c/sgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/sgen.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-#include "gc.h"
-
-Prog*
-gtext(Sym *s, int32 stkoff)
-{
- int32 a;
-
- a = argsize(1);
- if((textflag & NOSPLIT) != 0 && stkoff >= 128)
- yyerror("stack frame too large for NOSPLIT function");
-
- gpseudo(ATEXT, s, nodconst(stkoff));
- p->to.type = D_CONST2;
- p->to.offset2 = a;
- return p;
-}
-
-void
-noretval(int n)
-{
-
- if(n & 1) {
- gins(ANOP, Z, Z);
- p->to.type = D_REG;
- p->to.reg = REGRET;
- }
- if(n & 2) {
- gins(ANOP, Z, Z);
- p->to.type = D_FREG;
- p->to.reg = FREGRET;
- }
-}
-
-/*
- * calculate addressability as follows
- * CONST ==> 20 $value
- * NAME ==> 10 name
- * REGISTER ==> 11 register
- * INDREG ==> 12 *[(reg)+offset]
- * &10 ==> 2 $name
- * ADD(2, 20) ==> 2 $name+offset
- * ADD(3, 20) ==> 3 $(reg)+offset
- * &12 ==> 3 $(reg)+offset
- * *11 ==> 11 ??
- * *2 ==> 10 name
- * *3 ==> 12 *(reg)+offset
- * calculate complexity (number of registers)
- */
-void
-xcom(Node *n)
-{
- Node *l, *r;
- int t;
-
- if(n == Z)
- return;
- l = n->left;
- r = n->right;
- n->addable = 0;
- n->complex = 0;
- switch(n->op) {
- case OCONST:
- n->addable = 20;
- return;
-
- case OREGISTER:
- n->addable = 11;
- return;
-
- case OINDREG:
- n->addable = 12;
- return;
-
- case ONAME:
- n->addable = 10;
- return;
-
- case OADDR:
- xcom(l);
- if(l->addable == 10)
- n->addable = 2;
- if(l->addable == 12)
- n->addable = 3;
- break;
-
- case OIND:
- xcom(l);
- if(l->addable == 11)
- n->addable = 12;
- if(l->addable == 3)
- n->addable = 12;
- if(l->addable == 2)
- n->addable = 10;
- break;
-
- case OADD:
- xcom(l);
- xcom(r);
- if(l->addable == 20) {
- if(r->addable == 2)
- n->addable = 2;
- if(r->addable == 3)
- n->addable = 3;
- }
- if(r->addable == 20) {
- if(l->addable == 2)
- n->addable = 2;
- if(l->addable == 3)
- n->addable = 3;
- }
- break;
-
- case OASLMUL:
- case OASMUL:
- xcom(l);
- xcom(r);
- t = vlog(r);
- if(t >= 0) {
- n->op = OASASHL;
- r->vconst = t;
- r->type = types[TINT];
- }
- break;
-
- case OMUL:
- case OLMUL:
- xcom(l);
- xcom(r);
- t = vlog(r);
- if(t >= 0) {
- n->op = OASHL;
- r->vconst = t;
- r->type = types[TINT];
- }
- t = vlog(l);
- if(t >= 0) {
- n->op = OASHL;
- n->left = r;
- n->right = l;
- r = l;
- l = n->left;
- r->vconst = t;
- r->type = types[TINT];
- }
- break;
-
- case OASLDIV:
- xcom(l);
- xcom(r);
- t = vlog(r);
- if(t >= 0) {
- n->op = OASLSHR;
- r->vconst = t;
- r->type = types[TINT];
- }
- break;
-
- case OLDIV:
- xcom(l);
- xcom(r);
- t = vlog(r);
- if(t >= 0) {
- n->op = OLSHR;
- r->vconst = t;
- r->type = types[TINT];
- }
- break;
-
- case OASLMOD:
- xcom(l);
- xcom(r);
- t = vlog(r);
- if(t >= 0) {
- n->op = OASAND;
- r->vconst--;
- }
- break;
-
- case OLMOD:
- xcom(l);
- xcom(r);
- t = vlog(r);
- if(t >= 0) {
- n->op = OAND;
- r->vconst--;
- }
- break;
-
- default:
- if(l != Z)
- xcom(l);
- if(r != Z)
- xcom(r);
- break;
- }
- if(n->addable >= 10)
- return;
-
- if(l != Z)
- n->complex = l->complex;
- if(r != Z) {
- if(r->complex == n->complex)
- n->complex = r->complex+1;
- else
- if(r->complex > n->complex)
- n->complex = r->complex;
- }
- if(n->complex == 0)
- n->complex++;
-
- if(com64(n))
- return;
-
- switch(n->op) {
- case OFUNC:
- n->complex = FNX;
- break;
-
- case OADD:
- case OXOR:
- case OAND:
- case OOR:
- case OEQ:
- case ONE:
- /*
- * immediate operators, make const on right
- */
- if(l->op == OCONST) {
- n->left = r;
- n->right = l;
- }
- break;
- }
-}
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
deleted file mode 100644
index f39963b8f..000000000
--- a/src/cmd/5c/swt.c
+++ /dev/null
@@ -1,461 +0,0 @@
-// Inferno utils/5c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-void
-swit1(C1 *q, int nc, int32 def, Node *n)
-{
- Node nreg;
-
- if(typev[n->type->etype]) {
- regsalloc(&nreg, n);
- nreg.type = types[TVLONG];
- cgen(n, &nreg);
- swit2(q, nc, def, &nreg);
- return;
- }
-
- regalloc(&nreg, n, Z);
- nreg.type = types[TLONG];
- cgen(n, &nreg);
- swit2(q, nc, def, &nreg);
- regfree(&nreg);
-}
-
-void
-swit2(C1 *q, int nc, int32 def, Node *n)
-{
- C1 *r;
- int i;
- int32 v;
- Prog *sp;
-
- if(nc >= 3) {
- i = (q+nc-1)->val - (q+0)->val;
- if(!nacl && i > 0 && i < nc*2)
- goto direct;
- }
- if(nc < 5) {
- for(i=0; i<nc; i++) {
- if(debug['W'])
- print("case = %.8ux\n", q->val);
- gopcode(OEQ, nodconst(q->val), n, Z);
- patch(p, q->label);
- q++;
- }
- gbranch(OGOTO);
- patch(p, def);
- return;
- }
-
- i = nc / 2;
- r = q+i;
- if(debug['W'])
- print("case > %.8ux\n", r->val);
- gopcode(OGT, nodconst(r->val), n, Z);
- sp = p;
- gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */
- patch(p, r->label);
- swit2(q, i, def, n);
-
- if(debug['W'])
- print("case < %.8ux\n", r->val);
- patch(sp, pc);
- swit2(r+1, nc-i-1, def, n);
- return;
-
-direct:
- v = q->val;
- if(v != 0)
- gopcode(OSUB, nodconst(v), Z, n);
- gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z);
- patch(p, def);
- for(i=0; i<nc; i++) {
- if(debug['W'])
- print("case = %.8ux\n", q->val);
- while(q->val != v) {
- nextpc();
- p->as = ABCASE;
- patch(p, def);
- v++;
- }
- nextpc();
- p->as = ABCASE;
- patch(p, q->label);
- q++;
- v++;
- }
- gbranch(OGOTO); /* so that regopt() won't be confused */
- patch(p, def);
-}
-
-void
-bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
- int sh;
- int32 v;
- Node *l;
-
- /*
- * n1 gets adjusted/masked value
- * n2 gets address of cell
- * n3 gets contents of cell
- */
- l = b->left;
- if(n2 != Z) {
- regalloc(n1, l, nn);
- reglcgen(n2, l, Z);
- regalloc(n3, l, Z);
- gopcode(OAS, n2, Z, n3);
- gopcode(OAS, n3, Z, n1);
- } else {
- regalloc(n1, l, nn);
- cgen(l, n1);
- }
- if(b->type->shift == 0 && typeu[b->type->etype]) {
- v = ~0 + (1L << b->type->nbits);
- gopcode(OAND, nodconst(v), Z, n1);
- } else {
- sh = 32 - b->type->shift - b->type->nbits;
- if(sh > 0)
- gopcode(OASHL, nodconst(sh), Z, n1);
- sh += b->type->shift;
- if(sh > 0)
- if(typeu[b->type->etype])
- gopcode(OLSHR, nodconst(sh), Z, n1);
- else
- gopcode(OASHR, nodconst(sh), Z, n1);
- }
-}
-
-void
-bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
- int32 v;
- Node nod, *l;
- int sh;
-
- /*
- * n1 has adjusted/masked value
- * n2 has address of cell
- * n3 has contents of cell
- */
- l = b->left;
- regalloc(&nod, l, Z);
- v = ~0 + (1L << b->type->nbits);
- gopcode(OAND, nodconst(v), Z, n1);
- gopcode(OAS, n1, Z, &nod);
- if(nn != Z)
- gopcode(OAS, n1, Z, nn);
- sh = b->type->shift;
- if(sh > 0)
- gopcode(OASHL, nodconst(sh), Z, &nod);
- v <<= sh;
- gopcode(OAND, nodconst(~v), Z, n3);
- gopcode(OOR, n3, Z, &nod);
- gopcode(OAS, &nod, Z, n2);
-
- regfree(&nod);
- regfree(n1);
- regfree(n2);
- regfree(n3);
-}
-
-int32
-outstring(char *s, int32 n)
-{
- int32 r;
-
- if(suppress)
- return nstring;
- r = nstring;
- while(n) {
- string[mnstring] = *s++;
- mnstring++;
- nstring++;
- if(mnstring >= NSNAME) {
- gpseudo(ADATA, symstring, nodconst(0L));
- p->from.offset += nstring - NSNAME;
- p->reg = NSNAME;
- p->to.type = D_SCONST;
- memmove(p->to.u.sval, string, NSNAME);
- mnstring = 0;
- }
- n--;
- }
- return r;
-}
-
-int
-mulcon(Node *n, Node *nn)
-{
- Node *l, *r, nod1, nod2;
- Multab *m;
- int32 v, vs;
- int o;
- char code[sizeof(m->code)+2], *p;
-
- if(typefd[n->type->etype])
- return 0;
- l = n->left;
- r = n->right;
- if(l->op == OCONST) {
- l = r;
- r = n->left;
- }
- if(r->op != OCONST)
- return 0;
- v = convvtox(r->vconst, n->type->etype);
- if(v != r->vconst) {
- if(debug['M'])
- print("%L multiply conv: %lld\n", n->lineno, r->vconst);
- return 0;
- }
- m = mulcon0(v);
- if(!m) {
- if(debug['M'])
- print("%L multiply table: %lld\n", n->lineno, r->vconst);
- return 0;
- }
- if(debug['M'] && debug['v'])
- print("%L multiply: %d\n", n->lineno, v);
-
- memmove(code, m->code, sizeof(m->code));
- code[sizeof(m->code)] = 0;
-
- p = code;
- if(p[1] == 'i')
- p += 2;
- regalloc(&nod1, n, nn);
- cgen(l, &nod1);
- vs = v;
- regalloc(&nod2, n, Z);
-
-loop:
- switch(*p) {
- case 0:
- regfree(&nod2);
- if(vs < 0) {
- gopcode(OAS, &nod1, Z, &nod1);
- gopcode(OSUB, &nod1, nodconst(0), nn);
- } else
- gopcode(OAS, &nod1, Z, nn);
- regfree(&nod1);
- return 1;
- case '+':
- o = OADD;
- goto addsub;
- case '-':
- o = OSUB;
- addsub: /* number is r,n,l */
- v = p[1] - '0';
- r = &nod1;
- if(v&4)
- r = &nod2;
- n = &nod1;
- if(v&2)
- n = &nod2;
- l = &nod1;
- if(v&1)
- l = &nod2;
- gopcode(o, l, n, r);
- break;
- default: /* op is shiftcount, number is r,l */
- v = p[1] - '0';
- r = &nod1;
- if(v&2)
- r = &nod2;
- l = &nod1;
- if(v&1)
- l = &nod2;
- v = *p - 'a';
- if(v < 0 || v >= 32) {
- diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
- break;
- }
- gopcode(OASHL, nodconst(v), l, r);
- break;
- }
- p += 2;
- goto loop;
-}
-
-void
-sextern(Sym *s, Node *a, int32 o, int32 w)
-{
- int32 e, lw;
-
- for(e=0; e<w; e+=NSNAME) {
- lw = NSNAME;
- if(w-e < lw)
- lw = w-e;
- gpseudo(ADATA, s, nodconst(0));
- p->from.offset += o+e;
- p->reg = lw;
- p->to.type = D_SCONST;
- memmove(p->to.u.sval, a->cstring+e, lw);
- }
-}
-
-void
-gextern(Sym *s, Node *a, int32 o, int32 w)
-{
-
- if(a->op == OCONST && typev[a->type->etype]) {
- if(isbigendian)
- gpseudo(ADATA, s, nod32const(a->vconst>>32));
- else
- gpseudo(ADATA, s, nod32const(a->vconst));
- p->from.offset += o;
- p->reg = 4;
- if(isbigendian)
- gpseudo(ADATA, s, nod32const(a->vconst));
- else
- gpseudo(ADATA, s, nod32const(a->vconst>>32));
- p->from.offset += o + 4;
- p->reg = 4;
- return;
- }
- gpseudo(ADATA, s, a);
- p->from.offset += o;
- p->reg = w;
- if(p->to.type == D_OREG)
- p->to.type = D_CONST;
-}
-
-void
-outcode(void)
-{
- Bprint(&outbuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
- if(pragcgobuf.to > pragcgobuf.start) {
- Bprint(&outbuf, "\n");
- Bprint(&outbuf, "$$ // exports\n\n");
- Bprint(&outbuf, "$$ // local types\n\n");
- Bprint(&outbuf, "$$ // cgo\n");
- Bprint(&outbuf, "%s", fmtstrflush(&pragcgobuf));
- Bprint(&outbuf, "\n$$\n\n");
- }
- Bprint(&outbuf, "!\n");
-
- writeobj(ctxt, &outbuf);
- lastp = P;
-}
-
-int32
-align(int32 i, Type *t, int op, int32 *maxalign)
-{
- int32 o;
- Type *v;
- int w, packw;
-
- o = i;
- w = 1;
- packw = 0;
- switch(op) {
- default:
- diag(Z, "unknown align opcode %d", op);
- break;
-
- case Asu2: /* padding at end of a struct */
- w = *maxalign;
- if(w < 1)
- w = 1;
- if(packflg)
- packw = packflg;
- break;
-
- case Ael1: /* initial align of struct element */
- for(v=t; v->etype==TARRAY; v=v->link)
- ;
- if(v->etype == TSTRUCT || v->etype == TUNION)
- w = v->align;
- else {
- w = ewidth[v->etype];
- if(w == 8)
- w = 4;
- }
- if(w < 1 || w > SZ_LONG)
- fatal(Z, "align");
- if(packflg)
- packw = packflg;
- break;
-
- case Ael2: /* width of a struct element */
- o += t->width;
- break;
-
- case Aarg0: /* initial passbyptr argument in arg list */
- if(typesuv[t->etype]) {
- o = align(o, types[TIND], Aarg1, nil);
- o = align(o, types[TIND], Aarg2, nil);
- }
- break;
-
- case Aarg1: /* initial align of parameter */
- w = ewidth[t->etype];
- if(w <= 0 || w >= SZ_LONG) {
- w = SZ_LONG;
- break;
- }
- w = 1; /* little endian no adjustment */
- break;
-
- case Aarg2: /* width of a parameter */
- o += t->width;
- w = t->width;
- if(w > SZ_LONG)
- w = SZ_LONG;
- break;
-
- case Aaut3: /* total align of automatic */
- o = align(o, t, Ael2, nil);
- o = align(o, t, Ael1, nil);
- w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */
- break;
- }
- if(packw != 0 && xround(o, w) != xround(o, packw))
- diag(Z, "#pragma pack changes offset of %T", t);
- o = xround(o, w);
- if(maxalign != nil && *maxalign < w)
- *maxalign = w;
- if(debug['A'])
- print("align %s %d %T = %d\n", bnames[op], i, t, o);
- return o;
-}
-
-int32
-maxround(int32 max, int32 v)
-{
- v = xround(v, SZ_LONG);
- if(v > max)
- return v;
- return max;
-}
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
deleted file mode 100644
index af40220cc..000000000
--- a/src/cmd/5c/txt.c
+++ /dev/null
@@ -1,1361 +0,0 @@
-// Inferno utils/5c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-#include "gc.h"
-
-
-int thechar = '5';
-char *thestring = "arm";
-
-LinkArch *thelinkarch = &linkarm;
-
-void
-linkarchinit(void)
-{
-}
-
-void
-ginit(void)
-{
- Type *t;
-
- exregoffset = REGEXT;
- exfregoffset = FREGEXT;
- listinit();
- nstring = 0;
- mnstring = 0;
- nrathole = 0;
- pc = 0;
- breakpc = -1;
- continpc = -1;
- cases = C;
- lastp = P;
- tfield = types[TLONG];
-
- zprog.link = P;
- zprog.as = AGOK;
- zprog.reg = NREG;
- zprog.from.type = D_NONE;
- zprog.from.name = D_NONE;
- zprog.from.reg = NREG;
- zprog.to = zprog.from;
- zprog.scond = 0xE;
-
- regnode.op = OREGISTER;
- regnode.class = CEXREG;
- regnode.reg = REGTMP;
- regnode.complex = 0;
- regnode.addable = 11;
- regnode.type = types[TLONG];
-
- constnode.op = OCONST;
- constnode.class = CXXX;
- constnode.complex = 0;
- constnode.addable = 20;
- constnode.type = types[TLONG];
-
- fconstnode.op = OCONST;
- fconstnode.class = CXXX;
- fconstnode.complex = 0;
- fconstnode.addable = 20;
- fconstnode.type = types[TDOUBLE];
-
- nodsafe = new(ONAME, Z, Z);
- nodsafe->sym = slookup(".safe");
- nodsafe->type = types[TINT];
- nodsafe->etype = types[TINT]->etype;
- nodsafe->class = CAUTO;
- complex(nodsafe);
-
- t = typ(TARRAY, types[TCHAR]);
- symrathole = slookup(".rathole");
- symrathole->class = CGLOBL;
- symrathole->type = t;
-
- nodrat = new(ONAME, Z, Z);
- nodrat->sym = symrathole;
- nodrat->type = types[TIND];
- nodrat->etype = TVOID;
- nodrat->class = CGLOBL;
- complex(nodrat);
- nodrat->type = t;
-
- nodret = new(ONAME, Z, Z);
- nodret->sym = slookup(".ret");
- nodret->type = types[TIND];
- nodret->etype = TIND;
- nodret->class = CPARAM;
- nodret = new(OIND, nodret, Z);
- complex(nodret);
-
- com64init();
-
- memset(reg, 0, sizeof(reg));
-}
-
-void
-gclean(void)
-{
- int i;
- Sym *s;
-
- for(i=0; i<NREG; i++)
- if(reg[i])
- diag(Z, "reg %d left allocated", i);
- for(i=NREG; i<NREG+NFREG; i++)
- if(reg[i])
- diag(Z, "freg %d left allocated", i-NREG);
- while(mnstring)
- outstring("", 1L);
- symstring->type->width = nstring;
- symrathole->type->width = nrathole;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type == T)
- continue;
- if(s->type->width == 0)
- continue;
- if(s->class != CGLOBL && s->class != CSTATIC)
- continue;
- if(s->type == types[TENUM])
- continue;
- gpseudo(AGLOBL, s, nodconst(s->type->width));
- }
- nextpc();
- p->as = AEND;
- outcode();
-}
-
-void
-nextpc(void)
-{
- Plist *pl;
-
- p = alloc(sizeof(*p));
- *p = zprog;
- p->lineno = nearln;
- pc++;
- if(lastp == nil) {
- pl = linknewplist(ctxt);
- pl->firstpc = p;
- } else
- lastp->link = p;
- lastp = p;
-}
-
-void
-gargs(Node *n, Node *tn1, Node *tn2)
-{
- int32 regs;
- Node fnxargs[20], *fnxp;
-
- regs = cursafe;
-
- fnxp = fnxargs;
- garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
-
- curarg = 0;
- fnxp = fnxargs;
- garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
-
- cursafe = regs;
-}
-
-void
-garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
-{
- Node nod;
-
- if(n == Z)
- return;
- if(n->op == OLIST) {
- garg1(n->left, tn1, tn2, f, fnxp);
- garg1(n->right, tn1, tn2, f, fnxp);
- return;
- }
- if(f == 0) {
- if(n->complex >= FNX) {
- regsalloc(*fnxp, n);
- nod = znode;
- nod.op = OAS;
- nod.left = *fnxp;
- nod.right = n;
- nod.type = n->type;
- cgen(&nod, Z);
- (*fnxp)++;
- }
- return;
- }
- if(typesuv[n->type->etype]) {
- regaalloc(tn2, n);
- if(n->complex >= FNX) {
- sugen(*fnxp, tn2, n->type->width);
- (*fnxp)++;
- } else
- sugen(n, tn2, n->type->width);
- return;
- }
- if(REGARG >= 0 && curarg == 0 && typechlp[n->type->etype]) {
- regaalloc1(tn1, n);
- if(n->complex >= FNX) {
- cgen(*fnxp, tn1);
- (*fnxp)++;
- } else
- cgen(n, tn1);
- return;
- }
- regalloc(tn1, n, Z);
- if(n->complex >= FNX) {
- cgen(*fnxp, tn1);
- (*fnxp)++;
- } else
- cgen(n, tn1);
- regaalloc(tn2, n);
- gopcode(OAS, tn1, Z, tn2);
- regfree(tn1);
-}
-
-Node*
-nodconst(int32 v)
-{
- constnode.vconst = v;
- return &constnode;
-}
-
-Node*
-nod32const(vlong v)
-{
- constnode.vconst = v & MASK(32);
- return &constnode;
-}
-
-Node*
-nodfconst(double d)
-{
- fconstnode.fconst = d;
- return &fconstnode;
-}
-
-void
-nodreg(Node *n, Node *nn, int reg)
-{
- *n = regnode;
- n->reg = reg;
- n->type = nn->type;
- n->lineno = nn->lineno;
-}
-
-void
-regret(Node *n, Node *nn, Type *t, int mode)
-{
- int r;
-
- if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET+NREG;
- nodreg(n, nn, r);
- reg[r]++;
- return;
- }
-
- if(mode == 1) {
- // fetch returned value after call.
- // already called gargs, so curarg is set.
- curarg = (curarg+3) & ~3;
- regaalloc(n, nn);
- return;
- }
-
- if(mode == 2) {
- // store value to be returned.
- // must compute arg offset.
- if(t->etype != TFUNC)
- fatal(Z, "bad regret func %T", t);
- *n = *nn;
- n->op = ONAME;
- n->class = CPARAM;
- n->sym = slookup(".ret");
- n->complex = nodret->complex;
- n->xoffset = argsize(0);
- n->addable = 20;
- return;
- }
-
- fatal(Z, "bad regret");
-}
-
-int
-tmpreg(void)
-{
- int i;
-
- for(i=REGRET+1; i<NREG; i++)
- if(reg[i] == 0)
- return i;
- diag(Z, "out of fixed registers");
- return 0;
-}
-
-void
-regalloc(Node *n, Node *tn, Node *o)
-{
- int i;
-
- switch(tn->type->etype) {
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- if(o != Z && o->op == OREGISTER) {
- i = o->reg;
- if(i >= 0 && i < NREG)
- goto out;
- }
- for(i=REGRET+1; i<=REGEXT-2; i++)
- if(reg[i] == 0)
- goto out;
- diag(tn, "out of fixed registers");
- goto err;
-
- case TFLOAT:
- case TDOUBLE:
- case TVLONG:
- if(o != Z && o->op == OREGISTER) {
- i = o->reg;
- if(i >= NREG && i < NREG+NFREG)
- goto out;
- }
- for(i=NREG; i<NREG+NFREG; i++)
- if(reg[i] == 0)
- goto out;
- diag(tn, "out of float registers");
- goto err;
- }
- diag(tn, "unknown type in regalloc: %T", tn->type);
-err:
- nodreg(n, tn, 0);
- return;
-out:
- reg[i]++;
- nodreg(n, tn, i);
-}
-
-void
-regialloc(Node *n, Node *tn, Node *o)
-{
- Node nod;
-
- nod = *tn;
- nod.type = types[TIND];
- regalloc(n, &nod, o);
-}
-
-void
-regfree(Node *n)
-{
- int i;
-
- i = 0;
- if(n->op != OREGISTER && n->op != OINDREG)
- goto err;
- i = n->reg;
- if(i < 0 || i >= nelem(reg))
- goto err;
- if(reg[i] <= 0)
- goto err;
- reg[i]--;
- return;
-err:
- diag(n, "error in regfree: %d", i);
-}
-
-void
-regsalloc(Node *n, Node *nn)
-{
- cursafe = align(cursafe, nn->type, Aaut3, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
- *n = *nodsafe;
- n->xoffset = -(stkoff + cursafe);
- n->type = nn->type;
- n->etype = nn->type->etype;
- n->lineno = nn->lineno;
-}
-
-void
-regaalloc1(Node *n, Node *nn)
-{
- if(REGARG < 0) {
- fatal(n, "regaalloc1 and REGARG<0");
- return;
- }
- nodreg(n, nn, REGARG);
- reg[REGARG]++;
- curarg = align(curarg, nn->type, Aarg1, nil);
- curarg = align(curarg, nn->type, Aarg2, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regaalloc(Node *n, Node *nn)
-{
- curarg = align(curarg, nn->type, Aarg1, nil);
- *n = *nn;
- n->op = OINDREG;
- n->reg = REGSP;
- n->xoffset = curarg + SZ_LONG;
- n->complex = 0;
- n->addable = 20;
- curarg = align(curarg, nn->type, Aarg2, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regind(Node *n, Node *nn)
-{
-
- if(n->op != OREGISTER) {
- diag(n, "regind not OREGISTER");
- return;
- }
- n->op = OINDREG;
- n->type = nn->type;
-}
-
-void
-raddr(Node *n, Prog *p)
-{
- Addr a;
-
- naddr(n, &a);
- if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
- a.type = D_REG;
- a.reg = 0;
- }
- if(a.type != D_REG && a.type != D_FREG) {
- if(n)
- diag(n, "bad in raddr: %O", n->op);
- else
- diag(n, "bad in raddr: <null>");
- p->reg = NREG;
- } else
- p->reg = a.reg;
-}
-
-void
-naddr(Node *n, Addr *a)
-{
- int32 v;
-
- a->type = D_NONE;
- if(n == Z)
- return;
- switch(n->op) {
- default:
- bad:
- diag(n, "bad in naddr: %O", n->op);
- break;
-
- case OREGISTER:
- a->type = D_REG;
- a->sym = nil;
- a->reg = n->reg;
- if(a->reg >= NREG) {
- a->type = D_FREG;
- a->reg -= NREG;
- }
- break;
-
- case OIND:
- naddr(n->left, a);
- if(a->type == D_REG) {
- a->type = D_OREG;
- break;
- }
- if(a->type == D_CONST) {
- a->type = D_OREG;
- break;
- }
- goto bad;
-
- case OINDREG:
- a->type = D_OREG;
- a->sym = nil;
- a->offset = n->xoffset;
- a->reg = n->reg;
- break;
-
- case ONAME:
- a->etype = n->etype;
- a->type = D_OREG;
- a->name = D_STATIC;
- a->sym = linksym(n->sym);
- a->offset = n->xoffset;
- if(n->class == CSTATIC)
- break;
- if(n->class == CEXTERN || n->class == CGLOBL) {
- a->name = D_EXTERN;
- break;
- }
- if(n->class == CAUTO) {
- a->name = D_AUTO;
- break;
- }
- if(n->class == CPARAM) {
- a->name = D_PARAM;
- break;
- }
- goto bad;
-
- case OCONST:
- a->sym = nil;
- a->reg = NREG;
- if(typefd[n->type->etype]) {
- a->type = D_FCONST;
- a->u.dval = n->fconst;
- } else {
- a->type = D_CONST;
- a->offset = n->vconst;
- }
- break;
-
- case OADDR:
- naddr(n->left, a);
- if(a->type == D_OREG) {
- a->type = D_CONST;
- break;
- }
- goto bad;
-
- case OADD:
- if(n->left->op == OCONST) {
- naddr(n->left, a);
- v = a->offset;
- naddr(n->right, a);
- } else {
- naddr(n->right, a);
- v = a->offset;
- naddr(n->left, a);
- }
- a->offset += v;
- break;
-
- }
-}
-
-void
-fop(int as, int f1, int f2, Node *t)
-{
- Node nod1, nod2, nod3;
-
- nodreg(&nod1, t, NREG+f1);
- nodreg(&nod2, t, NREG+f2);
- regalloc(&nod3, t, t);
- gopcode(as, &nod1, &nod2, &nod3);
- gmove(&nod3, t);
- regfree(&nod3);
-}
-
-void
-gmovm(Node *f, Node *t, int w)
-{
- gins(AMOVM, f, t);
- p->scond |= C_UBIT;
- if(w)
- p->scond |= C_WBIT;
-}
-
-void
-gmove(Node *f, Node *t)
-{
- int ft, tt, a;
- Node nod, nod1;
- Prog *p1;
-
- ft = f->type->etype;
- tt = t->type->etype;
-
- if(ft == TDOUBLE && f->op == OCONST) {
- }
- if(ft == TFLOAT && f->op == OCONST) {
- }
-
- /*
- * a load --
- * put it into a register then
- * worry what to do with it.
- */
- if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
- switch(ft) {
- default:
- a = AMOVW;
- break;
- case TFLOAT:
- a = AMOVF;
- break;
- case TDOUBLE:
- a = AMOVD;
- break;
- case TCHAR:
- a = AMOVBS;
- break;
- case TUCHAR:
- a = AMOVBU;
- break;
- case TSHORT:
- a = AMOVHS;
- break;
- case TUSHORT:
- a = AMOVHU;
- break;
- }
- if(typechlp[ft] && typeilp[tt])
- regalloc(&nod, t, t);
- else
- regalloc(&nod, f, t);
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
- }
-
- /*
- * a store --
- * put it into a register then
- * store it.
- */
- if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
- switch(tt) {
- default:
- a = AMOVW;
- break;
- case TUCHAR:
- a = AMOVBU;
- break;
- case TCHAR:
- a = AMOVBS;
- break;
- case TUSHORT:
- a = AMOVHU;
- break;
- case TSHORT:
- a = AMOVHS;
- break;
- case TFLOAT:
- a = AMOVF;
- break;
- case TVLONG:
- case TDOUBLE:
- a = AMOVD;
- break;
- }
- if(ft == tt)
- regalloc(&nod, t, f);
- else
- regalloc(&nod, t, Z);
- gmove(f, &nod);
- gins(a, &nod, t);
- regfree(&nod);
- return;
- }
-
- /*
- * type x type cross table
- */
- a = AGOK;
- switch(ft) {
- case TDOUBLE:
- case TVLONG:
- case TFLOAT:
- switch(tt) {
- case TDOUBLE:
- case TVLONG:
- a = AMOVD;
- if(ft == TFLOAT)
- a = AMOVFD;
- break;
- case TFLOAT:
- a = AMOVDF;
- if(ft == TFLOAT)
- a = AMOVF;
- break;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- a = AMOVDW;
- if(ft == TFLOAT)
- a = AMOVFW;
- break;
- case TSHORT:
- case TUSHORT:
- case TCHAR:
- case TUCHAR:
- a = AMOVDW;
- if(ft == TFLOAT)
- a = AMOVFW;
- break;
- }
- break;
- case TUINT:
- case TULONG:
- if(tt == TFLOAT || tt == TDOUBLE) {
- // ugly and probably longer than necessary,
- // but vfp has a single instruction for this,
- // so hopefully it won't last long.
- //
- // tmp = f
- // tmp1 = tmp & 0x80000000
- // tmp ^= tmp1
- // t = float(int32(tmp))
- // if(tmp1)
- // t += 2147483648.
- //
- regalloc(&nod, f, Z);
- regalloc(&nod1, f, Z);
- gins(AMOVW, f, &nod);
- gins(AMOVW, &nod, &nod1);
- gins(AAND, nodconst(0x80000000), &nod1);
- gins(AEOR, &nod1, &nod);
- if(tt == TFLOAT)
- gins(AMOVWF, &nod, t);
- else
- gins(AMOVWD, &nod, t);
- gins(ACMP, nodconst(0), Z);
- raddr(&nod1, p);
- gins(ABEQ, Z, Z);
- regfree(&nod);
- regfree(&nod1);
- p1 = p;
- regalloc(&nod, t, Z);
- gins(AMOVF, nodfconst(2147483648.), &nod);
- gins(AADDF, &nod, t);
- regfree(&nod);
- patch(p1, pc);
- return;
- }
- // fall through
-
- case TINT:
- case TLONG:
- case TIND:
- switch(tt) {
- case TDOUBLE:
- gins(AMOVWD, f, t);
- return;
- case TFLOAT:
- gins(AMOVWF, f, t);
- return;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- case TSHORT:
- case TUSHORT:
- case TCHAR:
- case TUCHAR:
- a = AMOVW;
- break;
- }
- break;
- case TSHORT:
- switch(tt) {
- case TDOUBLE:
- regalloc(&nod, f, Z);
- gins(AMOVHS, f, &nod);
- gins(AMOVWD, &nod, t);
- regfree(&nod);
- return;
- case TFLOAT:
- regalloc(&nod, f, Z);
- gins(AMOVHS, f, &nod);
- gins(AMOVWF, &nod, t);
- regfree(&nod);
- return;
- case TUINT:
- case TINT:
- case TULONG:
- case TLONG:
- case TIND:
- a = AMOVHS;
- break;
- case TSHORT:
- case TUSHORT:
- case TCHAR:
- case TUCHAR:
- a = AMOVW;
- break;
- }
- break;
- case TUSHORT:
- switch(tt) {
- case TDOUBLE:
- regalloc(&nod, f, Z);
- gins(AMOVHU, f, &nod);
- gins(AMOVWD, &nod, t);
- regfree(&nod);
- return;
- case TFLOAT:
- regalloc(&nod, f, Z);
- gins(AMOVHU, f, &nod);
- gins(AMOVWF, &nod, t);
- regfree(&nod);
- return;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- a = AMOVHU;
- break;
- case TSHORT:
- case TUSHORT:
- case TCHAR:
- case TUCHAR:
- a = AMOVW;
- break;
- }
- break;
- case TCHAR:
- switch(tt) {
- case TDOUBLE:
- regalloc(&nod, f, Z);
- gins(AMOVBS, f, &nod);
- gins(AMOVWD, &nod, t);
- regfree(&nod);
- return;
- case TFLOAT:
- regalloc(&nod, f, Z);
- gins(AMOVBS, f, &nod);
- gins(AMOVWF, &nod, t);
- regfree(&nod);
- return;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- case TSHORT:
- case TUSHORT:
- a = AMOVBS;
- break;
- case TCHAR:
- case TUCHAR:
- a = AMOVW;
- break;
- }
- break;
- case TUCHAR:
- switch(tt) {
- case TDOUBLE:
- regalloc(&nod, f, Z);
- gins(AMOVBU, f, &nod);
- gins(AMOVWD, &nod, t);
- regfree(&nod);
- return;
- case TFLOAT:
- regalloc(&nod, f, Z);
- gins(AMOVBU, f, &nod);
- gins(AMOVWF, &nod, t);
- regfree(&nod);
- return;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- case TSHORT:
- case TUSHORT:
- a = AMOVBU;
- break;
- case TCHAR:
- case TUCHAR:
- a = AMOVW;
- break;
- }
- break;
- }
- if(a == AGOK)
- diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
- if(a == AMOVW || a == AMOVF || a == AMOVD)
- if(samaddr(f, t))
- return;
- gins(a, f, t);
-}
-
-void
-gmover(Node *f, Node *t)
-{
- int ft, tt, a;
-
- ft = f->type->etype;
- tt = t->type->etype;
- a = AGOK;
- if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){
- switch(tt){
- case TSHORT:
- a = AMOVHS;
- break;
- case TUSHORT:
- a = AMOVHU;
- break;
- case TCHAR:
- a = AMOVBS;
- break;
- case TUCHAR:
- a = AMOVBU;
- break;
- }
- }
- if(a == AGOK)
- gmove(f, t);
- else
- gins(a, f, t);
-}
-
-void
-gins(int a, Node *f, Node *t)
-{
-
- nextpc();
- p->as = a;
- if(f != Z)
- naddr(f, &p->from);
- if(t != Z)
- naddr(t, &p->to);
- if(debug['g'])
- print("%P\n", p);
-}
-
-void
-gopcode(int o, Node *f1, Node *f2, Node *t)
-{
- int a, et;
- Addr ta;
-
- et = TLONG;
- if(f1 != Z && f1->type != T)
- et = f1->type->etype;
- a = AGOK;
- switch(o) {
- case OAS:
- gmove(f1, t);
- return;
-
- case OASADD:
- case OADD:
- a = AADD;
- if(et == TFLOAT)
- a = AADDF;
- else
- if(et == TDOUBLE || et == TVLONG)
- a = AADDD;
- break;
-
- case OASSUB:
- case OSUB:
- if(f2 && f2->op == OCONST) {
- Node *t = f1;
- f1 = f2;
- f2 = t;
- a = ARSB;
- } else
- a = ASUB;
- if(et == TFLOAT)
- a = ASUBF;
- else
- if(et == TDOUBLE || et == TVLONG)
- a = ASUBD;
- break;
-
- case OASOR:
- case OOR:
- a = AORR;
- break;
-
- case OASAND:
- case OAND:
- a = AAND;
- break;
-
- case OASXOR:
- case OXOR:
- a = AEOR;
- break;
-
- case OASLSHR:
- case OLSHR:
- a = ASRL;
- break;
-
- case OASASHR:
- case OASHR:
- a = ASRA;
- break;
-
- case OASASHL:
- case OASHL:
- a = ASLL;
- break;
-
- case OFUNC:
- a = ABL;
- break;
-
- case OASMUL:
- case OMUL:
- a = AMUL;
- if(et == TFLOAT)
- a = AMULF;
- else
- if(et == TDOUBLE || et == TVLONG)
- a = AMULD;
- break;
-
- case OASDIV:
- case ODIV:
- a = ADIV;
- if(et == TFLOAT)
- a = ADIVF;
- else
- if(et == TDOUBLE || et == TVLONG)
- a = ADIVD;
- break;
-
- case OASMOD:
- case OMOD:
- a = AMOD;
- break;
-
- case OASLMUL:
- case OLMUL:
- a = AMULU;
- break;
-
- case OASLMOD:
- case OLMOD:
- a = AMODU;
- break;
-
- case OASLDIV:
- case OLDIV:
- a = ADIVU;
- break;
-
- case OCASE:
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case OLO:
- case OLS:
- case OHS:
- case OHI:
- a = ACMP;
- if(et == TFLOAT)
- a = ACMPF;
- else
- if(et == TDOUBLE || et == TVLONG)
- a = ACMPD;
- nextpc();
- p->as = a;
- naddr(f1, &p->from);
- if(a == ACMP && f1->op == OCONST && p->from.offset < 0) {
- p->as = ACMN;
- p->from.offset = -p->from.offset;
- }
- raddr(f2, p);
- switch(o) {
- case OEQ:
- a = ABEQ;
- break;
- case ONE:
- a = ABNE;
- break;
- case OLT:
- a = ABLT;
- break;
- case OLE:
- a = ABLE;
- break;
- case OGE:
- a = ABGE;
- break;
- case OGT:
- a = ABGT;
- break;
- case OLO:
- a = ABLO;
- break;
- case OLS:
- a = ABLS;
- break;
- case OHS:
- a = ABHS;
- break;
- case OHI:
- a = ABHI;
- break;
- case OCASE:
- nextpc();
- p->as = ACASE;
- p->scond = 0x9;
- naddr(f2, &p->from);
- a = ABHI;
- break;
- }
- f1 = Z;
- f2 = Z;
- break;
- }
- if(a == AGOK)
- diag(Z, "bad in gopcode %O", o);
- nextpc();
- p->as = a;
- if(f1 != Z)
- naddr(f1, &p->from);
- if(f2 != Z) {
- naddr(f2, &ta);
- p->reg = ta.reg;
- }
- if(t != Z)
- naddr(t, &p->to);
- if(debug['g'])
- print("%P\n", p);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
- if(f->op != t->op)
- return 0;
- switch(f->op) {
-
- case OREGISTER:
- if(f->reg != t->reg)
- break;
- return 1;
- }
- return 0;
-}
-
-void
-gbranch(int o)
-{
- int a;
-
- a = AGOK;
- switch(o) {
- case ORETURN:
- a = ARET;
- break;
- case OGOTO:
- a = AB;
- break;
- }
- nextpc();
- if(a == AGOK) {
- diag(Z, "bad in gbranch %O", o);
- nextpc();
- }
- p->as = a;
-}
-
-void
-patch(Prog *op, int32 pc)
-{
-
- op->to.offset = pc;
- op->to.type = D_BRANCH;
-}
-
-void
-gpseudo(int a, Sym *s, Node *n)
-{
- nextpc();
- p->as = a;
- p->from.type = D_OREG;
- p->from.sym = linksym(s);
- p->from.name = D_EXTERN;
-
- switch(a) {
- case ATEXT:
- p->reg = textflag;
- textflag = 0;
- break;
- case AGLOBL:
- p->reg = s->dataflag;
- break;
- }
-
- if(s->class == CSTATIC)
- p->from.name = D_STATIC;
- naddr(n, &p->to);
- if(a == ADATA || a == AGLOBL)
- pc--;
-}
-
-void
-gpcdata(int index, int value)
-{
- Node n1;
-
- n1 = *nodconst(index);
- gins(APCDATA, &n1, nodconst(value));
-}
-
-void
-gprefetch(Node *n)
-{
- Node n1;
-
- regalloc(&n1, n, Z);
- gmove(n, &n1);
- n1.op = OINDREG;
- gins(APLD, &n1, Z);
- regfree(&n1);
-}
-
-int
-sconst(Node *n)
-{
- vlong vv;
-
- if(n->op == OCONST) {
- if(!typefd[n->type->etype]) {
- vv = n->vconst;
- if(vv >= (vlong)(-32766) && vv < (vlong)32766)
- return 1;
- /*
- * should be specialised for constant values which will
- * fit in different instructionsl; for now, let 5l
- * sort it out
- */
- return 1;
- }
- }
- return 0;
-}
-
-int
-sval(int32 v)
-{
- int i;
-
- for(i=0; i<16; i++) {
- if((v & ~0xff) == 0)
- return 1;
- if((~v & ~0xff) == 0)
- return 1;
- v = (v<<2) | ((uint32)v>>30);
- }
- return 0;
-}
-
-int32
-exreg(Type *t)
-{
- int32 o;
-
- if(typechlp[t->etype]) {
- if(exregoffset <= REGEXT-4)
- return 0;
- o = exregoffset;
- exregoffset--;
- return o;
- }
- if(typefd[t->etype]) {
- if(exfregoffset <= NFREG-1)
- return 0;
- o = exfregoffset + NREG;
- exfregoffset--;
- return o;
- }
- return 0;
-}
-
-schar ewidth[NTYPE] =
-{
- -1, /* [TXXX] */
- SZ_CHAR, /* [TCHAR] */
- SZ_CHAR, /* [TUCHAR] */
- SZ_SHORT, /* [TSHORT] */
- SZ_SHORT, /* [TUSHORT] */
- SZ_INT, /* [TINT] */
- SZ_INT, /* [TUINT] */
- SZ_LONG, /* [TLONG] */
- SZ_LONG, /* [TULONG] */
- SZ_VLONG, /* [TVLONG] */
- SZ_VLONG, /* [TUVLONG] */
- SZ_FLOAT, /* [TFLOAT] */
- SZ_DOUBLE, /* [TDOUBLE] */
- SZ_IND, /* [TIND] */
- 0, /* [TFUNC] */
- -1, /* [TARRAY] */
- 0, /* [TVOID] */
- -1, /* [TSTRUCT] */
- -1, /* [TUNION] */
- SZ_INT, /* [TENUM] */
-};
-
-int32 ncast[NTYPE] =
-{
- 0, /* [TXXX] */
- BCHAR|BUCHAR, /* [TCHAR] */
- BCHAR|BUCHAR, /* [TUCHAR] */
- BSHORT|BUSHORT, /* [TSHORT] */
- BSHORT|BUSHORT, /* [TUSHORT] */
- BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
- BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
- BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
- BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
- BVLONG|BUVLONG, /* [TVLONG] */
- BVLONG|BUVLONG, /* [TUVLONG] */
- BFLOAT, /* [TFLOAT] */
- BDOUBLE, /* [TDOUBLE] */
- BLONG|BULONG|BIND, /* [TIND] */
- 0, /* [TFUNC] */
- 0, /* [TARRAY] */
- 0, /* [TVOID] */
- BSTRUCT, /* [TSTRUCT] */
- BUNION, /* [TUNION] */
- 0, /* [TENUM] */
-};
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
index 5e988878f..65f731685 100644
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -86,7 +86,7 @@ datagostring(Strlit *sval, Addr *a)
sym = stringsym(sval->s, sval->len);
a->type = D_OREG;
a->name = D_EXTERN;
- a->etype = TINT32;
+ a->etype = TSTRING;
a->offset = 0; // header
a->reg = NREG;
a->sym = linksym(sym);
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 06e274e14..f09197963 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -1353,9 +1353,10 @@ naddr(Node *n, Addr *a, int canemitcode)
case OITAB:
// itable of interface value
naddr(n->left, a, canemitcode);
- a->etype = TINT32;
+ a->etype = simtype[tptr];
if(a->type == D_CONST && a->offset == 0)
break; // len(nil)
+ a->width = widthptr;
break;
case OSPTR:
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
index 1946c1d33..a606f1d31 100644
--- a/src/cmd/5g/opt.h
+++ b/src/cmd/5g/opt.h
@@ -63,8 +63,8 @@ enum
uint32 BLOAD(Reg*);
uint32 BSTORE(Reg*);
-uint32 LOAD(Reg*);
-uint32 STORE(Reg*);
+uint64 LOAD(Reg*);
+uint64 STORE(Reg*);
*/
// A Reg is a wrapper around a single Prog (one instruction) that holds
@@ -75,12 +75,18 @@ struct Reg
{
Flow f;
- Bits set; // variables written by this instruction.
- Bits use1; // variables read by prog->from.
- Bits use2; // variables read by prog->to.
+ Bits set; // regopt variables written by this instruction.
+ Bits use1; // regopt variables read by prog->from.
+ Bits use2; // regopt variables read by prog->to.
+ // refahead/refbehind are the regopt variables whose current
+ // value may be used in the following/preceding instructions
+ // up to a CALL (or the value is clobbered).
Bits refbehind;
Bits refahead;
+ // calahead/calbehind are similar, but for variables in
+ // instructions that are reachable after hitting at least one
+ // CALL.
Bits calbehind;
Bits calahead;
Bits regdiff;
@@ -93,6 +99,16 @@ struct Reg
#define NRGN 600
/*c2go enum { NRGN = 600 }; */
+
+// A Rgn represents a single regopt variable over a region of code
+// where a register could potentially be dedicated to that variable.
+// The code encompassed by a Rgn is defined by the flow graph,
+// starting at enter, flood-filling forward while varno is refahead
+// and backward while varno is refbehind, and following branches. A
+// single variable may be represented by multiple disjoint Rgns and
+// each Rgn may choose a different register for that variable.
+// Registers are allocated to regions greedily in order of descending
+// cost.
struct Rgn
{
Reg* enter;
@@ -144,8 +160,8 @@ void prop(Reg*, Bits, Bits);
void synch(Reg*, Bits);
uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
-uint32 paint2(Reg*, int);
-void paint3(Reg*, int, int32, int);
+uint32 paint2(Reg*, int, int);
+void paint3(Reg*, int, uint32, int);
void addreg(Adr*, int);
void dumpit(char *str, Flow *r0, int);
@@ -156,10 +172,10 @@ void peep(Prog*);
void excise(Flow*);
int copyu(Prog*, Adr*, Adr*);
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
+uint32 RtoB(int);
+uint32 FtoB(int);
+int BtoR(uint32);
+int BtoF(uint32);
/*
* prog.c
@@ -187,16 +203,16 @@ enum
SizeF = 1<<7, // float aka float32
SizeD = 1<<8, // double aka float64
- // Left side: address taken, read, write.
+ // Left side (Prog.from): address taken, read, write.
LeftAddr = 1<<9,
LeftRead = 1<<10,
LeftWrite = 1<<11,
- // Register in middle; never written.
+ // Register in middle (Prog.reg); only ever read.
RegRead = 1<<12,
CanRegRead = 1<<13,
- // Right side: address taken, read, write.
+ // Right side (Prog.to): address taken, read, write.
RightAddr = 1<<14,
RightRead = 1<<15,
RightWrite = 1<<16,
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index b78c268df..30fb81601 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -35,7 +35,7 @@
#include "opt.h"
#define NREGVAR 32
-#define REGBITS ((uint32)0xffffffff)
+#define REGBITS ((uint64)0xffffffffull)
/*c2go enum {
NREGVAR = 32,
REGBITS = 0xffffffff,
@@ -86,7 +86,7 @@ setaddrs(Bits bit)
i = bnum(bit);
node = var[i].node;
n = var[i].name;
- bit.b[i/32] &= ~(1L<<(i%32));
+ biclr(&bit, i);
// disable all pieces of that variable
for(i=0; i<nvar; i++) {
@@ -393,7 +393,7 @@ loop2:
for(z=0; z<BITS; z++)
bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
- if(bany(&bit) & !r->f.refset) {
+ if(bany(&bit) && !r->f.refset) {
// should never happen - all variables are preset
if(debug['w'])
print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
@@ -425,7 +425,7 @@ loop2:
if(debug['R'] > 1)
print("\n");
paint1(r, i);
- bit.b[i/32] &= ~(1L<<(i%32));
+ biclr(&bit, i);
if(change <= 0) {
if(debug['R'])
print("%L $%d: %Q\n",
@@ -454,9 +454,13 @@ brk:
* replace code (paint3)
*/
rgp = region;
+ if(debug['R'] && debug['v'])
+ print("\nregisterizing\n");
for(i=0; i<nregion; i++) {
+ if(debug['R'] && debug['v'])
+ print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(vreg, rgp);
if(debug['R']) {
if(rgp->regno >= NREG)
@@ -477,9 +481,6 @@ brk:
rgp++;
}
- if(debug['R'] && debug['v'])
- dumpit("pass6", &firstr->f, 1);
-
/*
* free aux structures. peep allocates new ones.
*/
@@ -488,6 +489,15 @@ brk:
flowend(g);
firstr = R;
+ if(debug['R'] && debug['v']) {
+ // Rebuild flow graph, since we inserted instructions
+ g = flowstart(firstp, sizeof(Reg));
+ firstr = (Reg*)g->start;
+ dumpit("pass6", &firstr->f, 1);
+ flowend(g);
+ firstr = R;
+ }
+
/*
* pass 7
* peep-hole on basic block
@@ -570,7 +580,7 @@ walkvardef(Node *n, Reg *r, int active)
break;
for(v=n->opt; v!=nil; v=v->nextinnode) {
bn = v - var;
- r1->act.b[bn/32] |= 1L << (bn%32);
+ biset(&r1->act, bn);
}
if(r1->f.prog->as == ABL)
break;
@@ -606,7 +616,7 @@ addsplits(void)
~(r->calahead.b[z] & addrs.b[z]);
while(bany(&bit)) {
i = bnum(bit);
- bit.b[i/32] &= ~(1L << (i%32));
+ biclr(&bit, i);
}
}
}
@@ -972,10 +982,10 @@ prop(Reg *r, Bits ref, Bits cal)
for(z=0; z<BITS; z++) {
if(cal.b[z] == 0)
continue;
- for(i=0; i<32; i++) {
- if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
+ for(i=0; i<64; i++) {
+ if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
continue;
- v = var+z*32+i;
+ v = var+z*64+i;
if(v->node->opt == nil) // v represents fixed register, not Go variable
continue;
@@ -991,10 +1001,10 @@ prop(Reg *r, Bits ref, Bits cal)
// This will set the bits at most twice, keeping the overall loop linear.
v1 = v->node->opt;
j = v1 - var;
- if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
+ if(v == v1 || !btest(&cal, j)) {
for(; v1 != nil; v1 = v1->nextinnode) {
j = v1 - var;
- cal.b[j/32] |= 1<<(j&31);
+ biset(&cal, j);
}
}
}
@@ -1115,10 +1125,10 @@ paint1(Reg *r, int bn)
Reg *r1;
Prog *p;
int z;
- uint32 bb;
+ uint64 bb;
- z = bn/32;
- bb = 1L<<(bn%32);
+ z = bn/64;
+ bb = 1LL<<(bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@@ -1189,14 +1199,14 @@ paint1(Reg *r, int bn)
}
uint32
-paint2(Reg *r, int bn)
+paint2(Reg *r, int bn, int depth)
{
Reg *r1;
int z;
- uint32 bb, vreg;
+ uint64 bb, vreg;
- z = bn/32;
- bb = 1L << (bn%32);
+ z = bn/64;
+ bb = 1LL << (bn%64);
vreg = regbits;
if(!(r->act.b[z] & bb))
return vreg;
@@ -1213,6 +1223,9 @@ paint2(Reg *r, int bn)
r = r1;
}
for(;;) {
+ if(debug['R'] && debug['v'])
+ print(" paint2 %d %P\n", depth, r->f.prog);
+
r->act.b[z] &= ~bb;
vreg |= r->regu;
@@ -1220,14 +1233,14 @@ paint2(Reg *r, int bn)
if(r->refbehind.b[z] & bb)
for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
if(!(r->refahead.b[z] & bb))
break;
r1 = (Reg*)r->f.s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
r = (Reg*)r->f.s1;
if(r == R)
break;
@@ -1240,15 +1253,15 @@ paint2(Reg *r, int bn)
}
void
-paint3(Reg *r, int bn, int32 rb, int rn)
+paint3(Reg *r, int bn, uint32 rb, int rn)
{
Reg *r1;
Prog *p;
int z;
- uint32 bb;
+ uint64 bb;
- z = bn/32;
- bb = 1L << (bn%32);
+ z = bn/64;
+ bb = 1LL << (bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@@ -1333,7 +1346,7 @@ addreg(Adr *a, int rn)
* 10 R10
* 12 R12
*/
-int32
+uint32
RtoB(int r)
{
if(r >= REGTMP-2 && r != 12) // excluded R9 and R10 for m and g, but not R12
@@ -1342,8 +1355,10 @@ RtoB(int r)
}
int
-BtoR(int32 b)
+BtoR(uint32 b)
{
+ // TODO Allow R0 and R1, but be careful with a 0 return
+ // TODO Allow R9. Only R10 is reserved now (just g, not m).
b &= 0x11fcL; // excluded R9 and R10 for m and g, but not R12
if(b == 0)
return 0;
@@ -1357,7 +1372,7 @@ BtoR(int32 b)
* ... ...
* 31 F15
*/
-int32
+uint32
FtoB(int f)
{
@@ -1367,7 +1382,7 @@ FtoB(int f)
}
int
-BtoF(int32 b)
+BtoF(uint32 b)
{
b &= 0xfffc0000L;
@@ -1442,12 +1457,14 @@ dumpit(char *str, Flow *r0, int isreg)
print(" (only)");
print("\n");
}
-// r1 = r->s1;
-// if(r1 != nil) {
-// print(" succ:");
-// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", (int)r1->prog->pc);
-// print("\n");
-// }
+ // Print successors if it's not just the next one
+ if(r->s1 != r->link || r->s2 != nil) {
+ print(" succ:");
+ if(r->s1 != nil)
+ print(" %.4ud", (int)r->s1->prog->pc);
+ if(r->s2 != nil)
+ print(" %.4ud", (int)r->s2->prog->pc);
+ print("\n");
+ }
}
}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index 7b16ac446..38a33db64 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -338,6 +338,8 @@ enum
D_STATIC = (D_NONE+4),
D_AUTO = (D_NONE+5),
D_PARAM = (D_NONE+6),
+
+ D_LAST = (D_NONE+26),
};
/*
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
index b3fb0bb19..e1927b6d4 100644
--- a/src/cmd/6a/a.h
+++ b/src/cmd/6a/a.h
@@ -70,6 +70,7 @@ struct Sym
vlong value;
ushort type;
char *name;
+ char* labelname;
char sym;
};
#define S ((Sym*)0)
@@ -148,6 +149,8 @@ void newio(void);
void newfile(char*, int);
Sym* slookup(char*);
Sym* lookup(void);
+Sym* labellookup(Sym*);
+void settext(LSym*);
void syminit(Sym*);
int32 yylex(void);
int getc(void);
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
index 1089d4061..29011c7ff 100644
--- a/src/cmd/6a/a.y
+++ b/src/cmd/6a/a.y
@@ -71,15 +71,11 @@ prog:
line
line:
- LLAB ':'
- {
- if($1->value != pc)
- yyerror("redeclaration of %s", $1->name);
- $1->value = pc;
- }
- line
-| LNAME ':'
+ LNAME ':'
{
+ $1 = labellookup($1);
+ if($1->type == LLAB && $1->value != pc)
+ yyerror("redeclaration of %s (%s)", $1->labelname, $1->name);
$1->type = LLAB;
$1->value = pc;
}
@@ -197,11 +193,13 @@ spec1: /* DATA */
spec2: /* TEXT */
mem ',' imm2
{
+ settext($1.sym);
$$.from = $1;
$$.to = $3;
}
| mem ',' con ',' imm2
{
+ settext($1.sym);
$$.from = $1;
$$.from.scale = $3;
$$.to = $5;
@@ -363,15 +361,10 @@ rel:
}
| LNAME offset
{
+ $1 = labellookup($1);
$$ = nullgen;
- if(pass == 2)
- yyerror("undefined label: %s", $1->name);
- $$.type = D_BRANCH;
- $$.offset = $2;
- }
-| LLAB offset
- {
- $$ = nullgen;
+ if(pass == 2 && $1->type != LLAB)
+ yyerror("undefined label: %s", $1->labelname);
$$.type = D_BRANCH;
$$.offset = $1->value + $2;
}
diff --git a/src/cmd/6a/y.tab.c b/src/cmd/6a/y.tab.c
index b69fd95b5..a698079d2 100644
--- a/src/cmd/6a/y.tab.c
+++ b/src/cmd/6a/y.tab.c
@@ -411,16 +411,16 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 2
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 560
+#define YYLAST 549
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 56
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 42
+#define YYNNTS 41
/* YYNRULES -- Number of rules. */
-#define YYNRULES 137
+#define YYNRULES 134
/* YYNRULES -- Number of states. */
-#define YYNSTATES 277
+#define YYNSTATES 271
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
@@ -469,91 +469,91 @@ static const yytype_uint8 yytranslate[] =
YYRHS. */
static const yytype_uint16 yyprhs[] =
{
- 0, 0, 3, 4, 5, 9, 10, 15, 16, 21,
- 23, 26, 29, 33, 37, 40, 43, 46, 49, 52,
+ 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, 91, 94, 95, 97, 101, 105, 108, 110,
- 113, 115, 118, 120, 124, 130, 134, 140, 143, 145,
- 147, 149, 153, 159, 163, 169, 172, 174, 178, 184,
- 190, 191, 193, 197, 203, 207, 211, 213, 215, 217,
- 219, 222, 225, 227, 229, 231, 233, 238, 241, 244,
- 246, 248, 250, 252, 254, 256, 258, 261, 264, 267,
- 270, 273, 278, 284, 288, 290, 292, 294, 299, 304,
- 309, 316, 326, 336, 340, 344, 350, 359, 361, 368,
- 374, 382, 383, 386, 389, 391, 393, 395, 397, 399,
- 402, 405, 408, 412, 414, 417, 421, 426, 428, 432,
- 436, 440, 444, 448, 453, 458, 462, 466
+ 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
};
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
static const yytype_int8 yyrhs[] =
{
57, 0, -1, -1, -1, 57, 58, 59, -1, -1,
- 46, 48, 60, 59, -1, -1, 45, 48, 61, 59,
- -1, 49, -1, 62, 49, -1, 1, 49, -1, 45,
- 50, 97, -1, 47, 50, 97, -1, 13, 63, -1,
- 14, 67, -1, 15, 66, -1, 16, 64, -1, 17,
- 65, -1, 21, 68, -1, 19, 69, -1, 22, 70,
- -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, 23, 79, -1, 24, 80,
- -1, 31, 81, -1, -1, 51, -1, 84, 51, 82,
- -1, 82, 51, 84, -1, 84, 51, -1, 84, -1,
- 51, 82, -1, 82, -1, 51, 85, -1, 85, -1,
- 88, 51, 85, -1, 92, 11, 95, 51, 88, -1,
- 89, 51, 87, -1, 89, 51, 95, 51, 87, -1,
- 51, 83, -1, 83, -1, 63, -1, 67, -1, 84,
- 51, 82, -1, 84, 51, 82, 48, 37, -1, 84,
- 51, 82, -1, 84, 51, 82, 48, 38, -1, 84,
- 51, -1, 84, -1, 84, 51, 82, -1, 86, 51,
- 82, 51, 95, -1, 88, 51, 82, 51, 86, -1,
- -1, 88, -1, 89, 51, 88, -1, 89, 51, 95,
- 51, 88, -1, 84, 51, 84, -1, 84, 51, 84,
- -1, 86, -1, 89, -1, 85, -1, 91, -1, 10,
- 86, -1, 10, 90, -1, 86, -1, 90, -1, 82,
- -1, 88, -1, 95, 52, 34, 53, -1, 45, 93,
- -1, 46, 93, -1, 36, -1, 39, -1, 37, -1,
- 40, -1, 44, -1, 38, -1, 41, -1, 54, 96,
- -1, 54, 95, -1, 54, 92, -1, 54, 43, -1,
- 54, 42, -1, 54, 52, 42, 53, -1, 54, 52,
- 9, 42, 53, -1, 54, 9, 42, -1, 90, -1,
- 91, -1, 95, -1, 95, 52, 37, 53, -1, 95,
- 52, 44, 53, -1, 95, 52, 38, 53, -1, 95,
- 52, 37, 10, 95, 53, -1, 95, 52, 37, 53,
- 52, 37, 10, 95, 53, -1, 95, 52, 37, 53,
- 52, 38, 10, 95, 53, -1, 52, 37, 53, -1,
- 52, 44, 53, -1, 52, 37, 10, 95, 53, -1,
- 52, 37, 53, 52, 37, 10, 95, 53, -1, 92,
- -1, 92, 52, 37, 10, 95, 53, -1, 45, 93,
- 52, 94, 53, -1, 45, 6, 7, 93, 52, 35,
- 53, -1, -1, 8, 95, -1, 9, 95, -1, 35,
- -1, 44, -1, 33, -1, 32, -1, 47, -1, 9,
- 95, -1, 8, 95, -1, 55, 95, -1, 52, 97,
- 53, -1, 32, -1, 9, 32, -1, 32, 9, 32,
- -1, 9, 32, 9, 32, -1, 95, -1, 97, 8,
- 97, -1, 97, 9, 97, -1, 97, 10, 97, -1,
- 97, 11, 97, -1, 97, 12, 97, -1, 97, 6,
- 6, 97, -1, 97, 7, 7, 97, -1, 97, 5,
- 97, -1, 97, 4, 97, -1, 97, 3, 97, -1
+ 45, 48, 60, 59, -1, 49, -1, 61, 49, -1,
+ 1, 49, -1, 45, 50, 96, -1, 47, 50, 96,
+ -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
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 66, 66, 68, 67, 75, 74, 82, 81, 87,
- 88, 89, 92, 97, 103, 104, 105, 106, 107, 108,
- 109, 110, 111, 112, 113, 114, 115, 116, 117, 118,
- 119, 120, 121, 124, 128, 135, 142, 149, 154, 161,
- 166, 173, 178, 183, 190, 198, 203, 211, 216, 223,
- 224, 227, 232, 242, 247, 257, 262, 267, 274, 282,
- 292, 296, 303, 308, 316, 325, 336, 337, 340, 341,
- 342, 346, 350, 351, 354, 355, 358, 364, 372, 380,
- 385, 390, 395, 400, 405, 410, 416, 424, 430, 441,
- 447, 453, 459, 465, 473, 474, 477, 483, 489, 495,
- 501, 510, 519, 528, 533, 538, 546, 556, 560, 569,
- 576, 585, 588, 592, 598, 599, 603, 606, 607, 611,
- 615, 619, 623, 629, 634, 639, 644, 651, 652, 656,
- 660, 664, 668, 672, 676, 680, 684, 688
+ 0, 66, 66, 68, 67, 75, 74, 83, 84, 85,
+ 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
};
#endif
@@ -569,7 +569,7 @@ static const char *const yytname[] =
"LTYPEF", "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG",
"LFREG", "LMREG", "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB",
"LVAR", "':'", "';'", "'='", "','", "'('", "')'", "'$'", "'~'",
- "$accept", "prog", "@1", "line", "@2", "@3", "inst", "nonnon", "rimrem",
+ "$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",
@@ -594,39 +594,39 @@ static const yytype_uint16 yytoknum[] =
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] =
{
- 0, 56, 57, 58, 57, 60, 59, 61, 59, 59,
- 59, 59, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 63, 63, 64, 65, 66, 66, 67,
- 67, 68, 68, 68, 69, 70, 70, 71, 71, 72,
- 72, 73, 73, 74, 74, 75, 75, 75, 76, 77,
- 78, 78, 79, 79, 80, 81, 82, 82, 83, 83,
- 83, 83, 83, 83, 84, 84, 85, 85, 85, 86,
- 86, 86, 86, 86, 86, 86, 87, 88, 88, 88,
- 88, 88, 88, 88, 89, 89, 90, 90, 90, 90,
- 90, 90, 90, 90, 90, 90, 90, 91, 91, 92,
- 92, 93, 93, 93, 94, 94, 94, 95, 95, 95,
- 95, 95, 95, 96, 96, 96, 96, 97, 97, 97,
- 97, 97, 97, 97, 97, 97, 97, 97
+ 0, 56, 57, 58, 57, 60, 59, 59, 59, 59,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+ 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,
+ 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
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
static const yytype_uint8 yyr2[] =
{
- 0, 2, 0, 0, 3, 0, 4, 0, 4, 1,
- 2, 2, 3, 3, 2, 2, 2, 2, 2, 2,
+ 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,
- 2, 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, 1, 1, 1, 4, 2, 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
+ 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, 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
};
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -634,89 +634,89 @@ static const yytype_uint8 yyr2[] =
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 2, 3, 1, 0, 0, 33, 0, 0, 0, 0,
- 0, 0, 33, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 60, 0, 0, 0, 0, 9, 4, 0,
- 11, 34, 14, 0, 0, 117, 79, 81, 84, 80,
- 82, 85, 83, 111, 118, 0, 0, 0, 15, 40,
- 66, 67, 94, 95, 107, 96, 0, 16, 74, 38,
- 75, 17, 0, 18, 0, 0, 111, 111, 0, 22,
- 48, 68, 72, 73, 69, 96, 20, 0, 34, 49,
- 50, 23, 111, 0, 0, 19, 42, 0, 0, 21,
- 0, 30, 0, 31, 0, 24, 0, 25, 0, 26,
- 56, 27, 0, 28, 0, 29, 61, 32, 0, 7,
- 0, 5, 0, 10, 120, 119, 0, 0, 0, 0,
- 39, 0, 0, 127, 0, 121, 0, 0, 0, 90,
- 89, 0, 88, 87, 37, 0, 0, 70, 71, 77,
- 78, 47, 0, 0, 77, 41, 0, 0, 0, 0,
- 0, 0, 0, 55, 0, 0, 0, 0, 12, 0,
- 13, 111, 112, 113, 0, 0, 103, 104, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 122, 0,
- 0, 0, 0, 93, 0, 0, 35, 36, 0, 0,
- 43, 0, 45, 0, 62, 0, 64, 51, 53, 57,
- 0, 0, 65, 8, 6, 0, 116, 114, 115, 0,
- 0, 0, 137, 136, 135, 0, 0, 128, 129, 130,
- 131, 132, 0, 0, 97, 99, 98, 0, 91, 76,
- 0, 0, 123, 86, 0, 0, 0, 0, 0, 0,
- 0, 109, 105, 0, 133, 134, 0, 0, 0, 92,
- 44, 124, 0, 46, 63, 52, 54, 58, 59, 0,
- 0, 108, 100, 0, 0, 0, 125, 110, 0, 0,
- 0, 126, 106, 0, 0, 101, 102
+ 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
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
- -1, 1, 3, 28, 159, 157, 29, 32, 61, 63,
- 57, 48, 85, 76, 89, 69, 81, 95, 97, 99,
- 101, 103, 105, 91, 93, 107, 58, 70, 59, 71,
- 50, 192, 60, 51, 52, 53, 54, 119, 209, 55,
- 233, 124
+ -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
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -94
+#define YYPACT_NINF -89
static const yytype_int16 yypact[] =
{
- -94, 15, -94, 218, -28, -25, 264, 285, 285, 340,
- 163, 2, 319, 97, 415, 415, 285, 285, 285, 285,
- 306, -24, -24, 285, -17, -14, 4, -94, -94, 48,
- -94, -94, -94, 481, 481, -94, -94, -94, -94, -94,
- -94, -94, -94, 19, -94, 340, 399, 481, -94, -94,
- -94, -94, -94, -94, 46, 47, 385, -94, -94, 52,
- -94, -94, 59, -94, 60, 374, 19, 56, 243, -94,
- -94, -94, -94, -94, -94, 63, -94, 106, 340, -94,
- -94, -94, 56, 138, 481, -94, -94, 69, 72, -94,
- 74, -94, 76, -94, 77, -94, 79, -94, 80, -94,
- 81, -94, 83, -94, 89, -94, -94, -94, 94, -94,
- 481, -94, 481, -94, -94, -94, 119, 481, 481, 98,
- -94, -1, 100, -94, 84, -94, 117, 23, 426, -94,
- -94, 433, -94, -94, -94, 340, 285, -94, -94, 98,
- -94, -94, 75, 481, -94, -94, 138, 122, 440, 444,
- 285, 340, 340, 340, 340, 340, 285, 218, 393, 218,
- 393, 56, -94, -94, -15, 481, 105, -94, 481, 481,
- 481, 156, 162, 481, 481, 481, 481, 481, -94, 165,
- 0, 123, 133, -94, 474, 134, -94, -94, 136, 140,
- -94, 7, -94, 141, -94, 143, -94, 148, 149, -94,
- 147, 160, -94, -94, -94, 164, -94, -94, -94, 167,
- 168, 180, 533, 541, 548, 481, 481, 58, 58, -94,
- -94, -94, 481, 481, 171, -94, -94, 172, -94, -94,
- -24, 192, 217, -94, 175, -24, 219, 216, 481, 306,
- 220, -94, -94, 247, 33, 33, 205, 208, 41, -94,
- -94, 253, 234, -94, -94, -94, -94, -94, -94, 215,
- 481, -94, -94, 259, 260, 239, -94, -94, 221, 481,
- 481, -94, -94, 223, 224, -94, -94
+ -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
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] =
{
- -94, -94, -94, -43, -94, -94, -94, 266, -94, -94,
- -94, 273, -94, -94, -94, -94, -94, -94, -94, -94,
- -94, -94, -94, -94, -94, -94, 26, 229, 32, -11,
- -9, 57, -8, 71, -2, -6, 1, -60, -94, -10,
- -94, -93
+ -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
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
@@ -726,124 +726,120 @@ static const yytype_int16 yypgoto[] =
#define YYTABLE_NINF -1
static const yytype_uint16 yytable[] =
{
- 75, 72, 86, 88, 74, 87, 139, 140, 73, 165,
- 223, 102, 77, 104, 106, 2, 231, 158, 206, 160,
- 207, 30, 144, 114, 115, 116, 31, 117, 118, 208,
- 56, 109, 49, 110, 111, 64, 123, 125, 49, 232,
- 62, 173, 174, 175, 176, 177, 133, 43, 94, 96,
- 98, 100, 166, 224, 112, 108, 137, 132, 75, 72,
- 180, 181, 74, 138, 117, 118, 73, 182, 175, 176,
- 177, 120, 145, 88, 123, 212, 213, 214, 263, 264,
- 217, 218, 219, 220, 221, 90, 92, 168, 169, 170,
- 171, 172, 173, 174, 175, 176, 177, 113, 126, 127,
- 123, 205, 123, 134, 120, 33, 34, 162, 163, 188,
- 135, 136, 180, 181, 203, 142, 204, 143, 115, 182,
- 146, 123, 244, 245, 147, 148, 161, 149, 150, 35,
- 151, 152, 153, 189, 154, 190, 88, 178, 193, 195,
- 155, 194, 82, 67, 44, 156, 33, 34, 83, 84,
- 164, 56, 47, 167, 179, 210, 188, 211, 123, 123,
- 123, 186, 215, 123, 123, 123, 123, 123, 187, 216,
- 35, 33, 34, 65, 115, 222, 225, 197, 198, 199,
- 200, 201, 196, 82, 67, 44, 226, 228, 202, 229,
- 84, 230, 234, 47, 235, 35, 236, 237, 238, 36,
- 37, 38, 39, 40, 41, 123, 123, 42, 66, 67,
- 44, 239, 246, 247, 68, 46, 240, 243, 47, 4,
- 241, 242, 250, 248, 251, 249, 252, 254, 257, 191,
- 258, 5, 6, 7, 8, 9, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
- 268, 33, 34, 65, 256, 259, 255, 260, 261, 273,
- 274, 262, 265, 24, 25, 26, 266, 27, 267, 269,
- 270, 271, 33, 34, 272, 35, 275, 276, 79, 36,
- 37, 38, 39, 40, 41, 80, 0, 42, 66, 67,
- 44, 253, 0, 33, 34, 46, 35, 141, 47, 0,
- 36, 37, 38, 39, 40, 41, 0, 0, 42, 43,
- 0, 44, 0, 0, 0, 45, 46, 35, 0, 47,
- 0, 36, 37, 38, 39, 40, 41, 33, 34, 42,
- 43, 0, 44, 0, 0, 0, 0, 46, 0, 56,
- 47, 0, 36, 37, 38, 39, 40, 41, 33, 34,
- 42, 35, 0, 0, 0, 36, 37, 38, 39, 40,
- 41, 0, 0, 42, 43, 0, 44, 0, 0, 0,
- 78, 46, 35, 0, 47, 0, 36, 37, 38, 39,
- 40, 41, 33, 34, 42, 43, 0, 44, 0, 0,
- 0, 0, 46, 33, 128, 47, 168, 169, 170, 171,
- 172, 173, 174, 175, 176, 177, 35, 33, 34, 0,
- 36, 37, 38, 39, 40, 41, 0, 35, 42, 0,
- 0, 44, 0, 33, 34, 0, 46, 129, 130, 47,
- 43, 35, 44, 0, 33, 34, 121, 131, 0, 0,
- 47, 33, 184, 122, 0, 0, 44, 35, 33, 34,
- 0, 84, 33, 34, 47, 0, 0, 0, 35, 0,
- 43, 0, 44, 0, 0, 35, 0, 46, 183, 0,
- 47, 0, 35, 44, 0, 185, 35, 0, 84, 0,
- 44, 47, 33, 34, 0, 84, 0, 44, 47, 33,
- 34, 44, 84, 0, 191, 47, 84, 0, 56, 47,
- 0, 0, 0, 0, 0, 0, 35, 0, 0, 0,
- 0, 0, 0, 35, 0, 0, 227, 0, 0, 0,
- 0, 44, 0, 0, 0, 0, 84, 0, 44, 47,
- 0, 0, 0, 84, 0, 0, 47, 169, 170, 171,
- 172, 173, 174, 175, 176, 177, 170, 171, 172, 173,
- 174, 175, 176, 177, 171, 172, 173, 174, 175, 176,
- 177
+ 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
};
static const yytype_int16 yycheck[] =
{
- 10, 10, 13, 13, 10, 13, 66, 67, 10, 10,
- 10, 20, 11, 21, 22, 0, 9, 110, 33, 112,
- 35, 49, 82, 33, 34, 6, 51, 8, 9, 44,
- 54, 48, 6, 50, 48, 9, 46, 47, 12, 32,
- 8, 8, 9, 10, 11, 12, 56, 45, 16, 17,
- 18, 19, 53, 53, 50, 23, 65, 56, 68, 68,
- 37, 38, 68, 65, 8, 9, 68, 44, 10, 11,
- 12, 45, 83, 83, 84, 168, 169, 170, 37, 38,
- 173, 174, 175, 176, 177, 14, 15, 3, 4, 5,
- 6, 7, 8, 9, 10, 11, 12, 49, 52, 52,
- 110, 161, 112, 51, 78, 8, 9, 117, 118, 34,
- 51, 51, 37, 38, 157, 52, 159, 11, 128, 44,
- 51, 131, 215, 216, 52, 51, 7, 51, 51, 32,
- 51, 51, 51, 143, 51, 146, 146, 53, 148, 149,
- 51, 149, 45, 46, 47, 51, 8, 9, 51, 52,
- 52, 54, 55, 53, 37, 165, 34, 52, 168, 169,
- 170, 135, 6, 173, 174, 175, 176, 177, 136, 7,
- 32, 8, 9, 10, 184, 10, 53, 151, 152, 153,
- 154, 155, 150, 45, 46, 47, 53, 53, 156, 53,
- 52, 51, 51, 55, 51, 32, 48, 48, 51, 36,
- 37, 38, 39, 40, 41, 215, 216, 44, 45, 46,
- 47, 51, 222, 223, 51, 52, 52, 37, 55, 1,
- 53, 53, 230, 52, 32, 53, 9, 235, 238, 54,
- 239, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 260, 8, 9, 10, 38, 35, 37, 10, 53, 269,
- 270, 53, 9, 45, 46, 47, 32, 49, 53, 10,
- 10, 32, 8, 9, 53, 32, 53, 53, 12, 36,
- 37, 38, 39, 40, 41, 12, -1, 44, 45, 46,
- 47, 234, -1, 8, 9, 52, 32, 68, 55, -1,
+ 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,
+ 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, -1, -1, -1, 51, 52, 32, -1, 55,
+ -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, -1, 54,
+ 45, -1, 47, -1, -1, -1, -1, 52, 32, -1,
55, -1, 36, 37, 38, 39, 40, 41, 8, 9,
- 44, 32, -1, -1, -1, 36, 37, 38, 39, 40,
- 41, -1, -1, 44, 45, -1, 47, -1, -1, -1,
- 51, 52, 32, -1, 55, -1, 36, 37, 38, 39,
- 40, 41, 8, 9, 44, 45, -1, 47, -1, -1,
- -1, -1, 52, 8, 9, 55, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 32, 8, 9, -1,
- 36, 37, 38, 39, 40, 41, -1, 32, 44, -1,
- -1, 47, -1, 8, 9, -1, 52, 42, 43, 55,
- 45, 32, 47, -1, 8, 9, 37, 52, -1, -1,
- 55, 8, 9, 44, -1, -1, 47, 32, 8, 9,
- -1, 52, 8, 9, 55, -1, -1, -1, 32, -1,
- 45, -1, 47, -1, -1, 32, -1, 52, 42, -1,
- 55, -1, 32, 47, -1, 42, 32, -1, 52, -1,
- 47, 55, 8, 9, -1, 52, -1, 47, 55, 8,
- 9, 47, 52, -1, 54, 55, 52, -1, 54, 55,
- -1, -1, -1, -1, -1, -1, 32, -1, -1, -1,
- -1, -1, -1, 32, -1, -1, 42, -1, -1, -1,
- -1, 47, -1, -1, -1, -1, 52, -1, 47, 55,
- -1, -1, -1, 52, -1, -1, 55, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 5, 6, 7, 8,
- 9, 10, 11, 12, 6, 7, 8, 9, 10, 11,
- 12
+ 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
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -852,32 +848,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, 46, 47, 49, 59, 62,
- 49, 51, 63, 8, 9, 32, 36, 37, 38, 39,
- 40, 41, 44, 45, 47, 51, 52, 55, 67, 82,
- 86, 89, 90, 91, 92, 95, 54, 66, 82, 84,
- 88, 64, 84, 65, 82, 10, 45, 46, 51, 71,
- 83, 85, 86, 90, 91, 95, 69, 92, 51, 63,
- 67, 72, 45, 51, 52, 68, 85, 88, 95, 70,
- 89, 79, 89, 80, 84, 73, 84, 74, 84, 75,
- 84, 76, 86, 77, 88, 78, 88, 81, 84, 48,
- 50, 48, 50, 49, 95, 95, 6, 8, 9, 93,
- 82, 37, 44, 95, 97, 95, 52, 52, 9, 42,
- 43, 52, 92, 95, 51, 51, 51, 86, 90, 93,
- 93, 83, 52, 11, 93, 85, 51, 52, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 61, 97, 60,
- 97, 7, 95, 95, 52, 10, 53, 53, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 53, 37,
- 37, 38, 44, 42, 9, 42, 82, 84, 34, 95,
- 85, 54, 87, 95, 88, 95, 84, 82, 82, 82,
- 82, 82, 84, 59, 59, 93, 33, 35, 44, 94,
- 95, 52, 97, 97, 97, 6, 7, 97, 97, 97,
- 97, 97, 10, 10, 53, 53, 53, 42, 53, 53,
- 51, 9, 32, 96, 51, 51, 48, 48, 51, 51,
- 52, 53, 53, 37, 97, 97, 95, 95, 52, 53,
- 88, 32, 9, 87, 88, 37, 38, 95, 86, 35,
- 10, 53, 53, 37, 38, 9, 32, 53, 95, 10,
- 10, 32, 53, 95, 95, 53, 53
+ 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
};
#define yyerrok (yyerrstatus = 0)
@@ -1701,30 +1697,24 @@ yyreduce:
case 5:
#line 75 "a.y"
{
- if((yyvsp[(1) - (2)].sym)->value != pc)
- yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
- (yyvsp[(1) - (2)].sym)->value = pc;
- }
- break;
-
- case 7:
-#line 82 "a.y"
- {
+ (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
+ if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc)
+ yyerror("redeclaration of %s (%s)", (yyvsp[(1) - (2)].sym)->labelname, (yyvsp[(1) - (2)].sym)->name);
(yyvsp[(1) - (2)].sym)->type = LLAB;
(yyvsp[(1) - (2)].sym)->value = pc;
}
break;
- case 12:
-#line 93 "a.y"
+ case 10:
+#line 89 "a.y"
{
(yyvsp[(1) - (3)].sym)->type = LVAR;
(yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
}
break;
- case 13:
-#line 98 "a.y"
+ case 11:
+#line 94 "a.y"
{
if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
@@ -1732,191 +1722,191 @@ yyreduce:
}
break;
+ case 12:
+#line 99 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+ break;
+
+ case 13:
+#line 100 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+ break;
+
case 14:
-#line 103 "a.y"
+#line 101 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 15:
-#line 104 "a.y"
+#line 102 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 16:
-#line 105 "a.y"
+#line 103 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 17:
-#line 106 "a.y"
+#line 104 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 18:
-#line 107 "a.y"
+#line 105 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 19:
-#line 108 "a.y"
+#line 106 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 20:
-#line 109 "a.y"
+#line 107 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 21:
-#line 110 "a.y"
+#line 108 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 22:
-#line 111 "a.y"
+#line 109 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 23:
-#line 112 "a.y"
+#line 110 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 24:
-#line 113 "a.y"
+#line 111 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 25:
-#line 114 "a.y"
+#line 112 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 26:
-#line 115 "a.y"
+#line 113 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 27:
-#line 116 "a.y"
+#line 114 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 28:
-#line 117 "a.y"
+#line 115 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 29:
-#line 118 "a.y"
+#line 116 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 30:
-#line 119 "a.y"
+#line 117 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 31:
#line 120 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 32:
-#line 121 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 33:
-#line 124 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = nullgen;
}
break;
- case 34:
-#line 129 "a.y"
+ case 32:
+#line 125 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = nullgen;
}
break;
- case 35:
-#line 136 "a.y"
+ case 33:
+#line 132 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 36:
-#line 143 "a.y"
+ case 34:
+#line 139 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 37:
-#line 150 "a.y"
+ case 35:
+#line 146 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
(yyval.addr2).to = nullgen;
}
break;
- case 38:
-#line 155 "a.y"
+ case 36:
+#line 151 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
(yyval.addr2).to = nullgen;
}
break;
- case 39:
-#line 162 "a.y"
+ case 37:
+#line 158 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
- case 40:
-#line 167 "a.y"
+ case 38:
+#line 163 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
- case 41:
-#line 174 "a.y"
+ case 39:
+#line 170 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
- case 42:
-#line 179 "a.y"
+ case 40:
+#line 175 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
- case 43:
-#line 184 "a.y"
+ case 41:
+#line 180 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 44:
-#line 191 "a.y"
+ case 42:
+#line 187 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
(yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
@@ -1924,49 +1914,51 @@ yyreduce:
}
break;
- case 45:
-#line 199 "a.y"
+ case 43:
+#line 195 "a.y"
{
+ settext((yyvsp[(1) - (3)].addr).sym);
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 46:
-#line 204 "a.y"
+ 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);
}
break;
- case 47:
-#line 212 "a.y"
+ case 45:
+#line 210 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
- case 48:
-#line 217 "a.y"
+ case 46:
+#line 215 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
- case 51:
-#line 228 "a.y"
+ case 49:
+#line 226 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 52:
-#line 233 "a.y"
+ case 50:
+#line 231 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
@@ -1976,16 +1968,16 @@ yyreduce:
}
break;
- case 53:
-#line 243 "a.y"
+ case 51:
+#line 241 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 54:
-#line 248 "a.y"
+ case 52:
+#line 246 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
@@ -1995,32 +1987,32 @@ yyreduce:
}
break;
- case 55:
-#line 258 "a.y"
+ case 53:
+#line 256 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
(yyval.addr2).to = nullgen;
}
break;
- case 56:
-#line 263 "a.y"
+ case 54:
+#line 261 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
(yyval.addr2).to = nullgen;
}
break;
- case 57:
-#line 268 "a.y"
+ case 55:
+#line 266 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 58:
-#line 275 "a.y"
+ case 56:
+#line 273 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
@@ -2028,8 +2020,8 @@ yyreduce:
}
break;
- case 59:
-#line 283 "a.y"
+ case 57:
+#line 281 "a.y"
{
(yyval.addr2).from = (yyvsp[(3) - (5)].addr);
(yyval.addr2).to = (yyvsp[(5) - (5)].addr);
@@ -2039,32 +2031,32 @@ yyreduce:
}
break;
- case 60:
-#line 292 "a.y"
+ case 58:
+#line 290 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = nullgen;
}
break;
- case 61:
-#line 297 "a.y"
+ case 59:
+#line 295 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
(yyval.addr2).to = nullgen;
}
break;
- case 62:
-#line 304 "a.y"
+ case 60:
+#line 302 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 63:
-#line 309 "a.y"
+ case 61:
+#line 307 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
(yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
@@ -2072,8 +2064,8 @@ yyreduce:
}
break;
- case 64:
-#line 317 "a.y"
+ case 62:
+#line 315 "a.y"
{
if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST)
yyerror("arguments to PCDATA must be integer constants");
@@ -2082,8 +2074,8 @@ yyreduce:
}
break;
- case 65:
-#line 326 "a.y"
+ case 63:
+#line 324 "a.y"
{
if((yyvsp[(1) - (3)].addr).type != D_CONST)
yyerror("index for FUNCDATA must be integer constant");
@@ -2094,22 +2086,22 @@ yyreduce:
}
break;
- case 70:
-#line 343 "a.y"
+ case 68:
+#line 341 "a.y"
{
(yyval.addr) = (yyvsp[(2) - (2)].addr);
}
break;
- case 71:
-#line 347 "a.y"
+ case 69:
+#line 345 "a.y"
{
(yyval.addr) = (yyvsp[(2) - (2)].addr);
}
break;
- case 76:
-#line 359 "a.y"
+ case 74:
+#line 357 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_BRANCH;
@@ -2117,84 +2109,76 @@ yyreduce:
}
break;
- case 77:
-#line 365 "a.y"
- {
- (yyval.addr) = nullgen;
- if(pass == 2)
- yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
- (yyval.addr).type = D_BRANCH;
- (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 78:
-#line 373 "a.y"
+ case 75:
+#line 363 "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).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
}
break;
- case 79:
-#line 381 "a.y"
+ case 76:
+#line 374 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 80:
-#line 386 "a.y"
+ case 77:
+#line 379 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 81:
-#line 391 "a.y"
+ case 78:
+#line 384 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 82:
-#line 396 "a.y"
+ case 79:
+#line 389 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 83:
-#line 401 "a.y"
+ case 80:
+#line 394 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_SP;
}
break;
- case 84:
-#line 406 "a.y"
+ case 81:
+#line 399 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 85:
-#line 411 "a.y"
+ case 82:
+#line 404 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 86:
-#line 417 "a.y"
+ case 83:
+#line 410 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_CONST;
@@ -2202,8 +2186,8 @@ yyreduce:
}
break;
- case 87:
-#line 425 "a.y"
+ case 84:
+#line 418 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_CONST;
@@ -2211,8 +2195,8 @@ yyreduce:
}
break;
- case 88:
-#line 431 "a.y"
+ case 85:
+#line 424 "a.y"
{
(yyval.addr) = (yyvsp[(2) - (2)].addr);
(yyval.addr).index = (yyvsp[(2) - (2)].addr).type;
@@ -2225,8 +2209,8 @@ yyreduce:
}
break;
- case 89:
-#line 442 "a.y"
+ case 86:
+#line 435 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_SCONST;
@@ -2234,8 +2218,8 @@ yyreduce:
}
break;
- case 90:
-#line 448 "a.y"
+ case 87:
+#line 441 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FCONST;
@@ -2243,8 +2227,8 @@ yyreduce:
}
break;
- case 91:
-#line 454 "a.y"
+ case 88:
+#line 447 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FCONST;
@@ -2252,8 +2236,8 @@ yyreduce:
}
break;
- case 92:
-#line 460 "a.y"
+ case 89:
+#line 453 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FCONST;
@@ -2261,8 +2245,8 @@ yyreduce:
}
break;
- case 93:
-#line 466 "a.y"
+ case 90:
+#line 459 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FCONST;
@@ -2270,8 +2254,8 @@ yyreduce:
}
break;
- case 96:
-#line 478 "a.y"
+ case 93:
+#line 471 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+D_NONE;
@@ -2279,8 +2263,8 @@ yyreduce:
}
break;
- case 97:
-#line 484 "a.y"
+ case 94:
+#line 477 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
@@ -2288,8 +2272,8 @@ yyreduce:
}
break;
- case 98:
-#line 490 "a.y"
+ case 95:
+#line 483 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+D_SP;
@@ -2297,8 +2281,8 @@ yyreduce:
}
break;
- case 99:
-#line 496 "a.y"
+ case 96:
+#line 489 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
@@ -2306,8 +2290,8 @@ yyreduce:
}
break;
- case 100:
-#line 502 "a.y"
+ case 97:
+#line 495 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+D_NONE;
@@ -2318,8 +2302,8 @@ yyreduce:
}
break;
- case 101:
-#line 511 "a.y"
+ case 98:
+#line 504 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
@@ -2330,8 +2314,8 @@ yyreduce:
}
break;
- case 102:
-#line 520 "a.y"
+ case 99:
+#line 513 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
@@ -2342,24 +2326,24 @@ yyreduce:
}
break;
- case 103:
-#line 529 "a.y"
+ case 100:
+#line 522 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval);
}
break;
- case 104:
-#line 534 "a.y"
+ case 101:
+#line 527 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+D_SP;
}
break;
- case 105:
-#line 539 "a.y"
+ case 102:
+#line 532 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+D_NONE;
@@ -2369,8 +2353,8 @@ yyreduce:
}
break;
- case 106:
-#line 547 "a.y"
+ case 103:
+#line 540 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(2) - (8)].lval);
@@ -2380,15 +2364,15 @@ yyreduce:
}
break;
- case 107:
-#line 557 "a.y"
+ case 104:
+#line 550 "a.y"
{
(yyval.addr) = (yyvsp[(1) - (1)].addr);
}
break;
- case 108:
-#line 561 "a.y"
+ case 105:
+#line 554 "a.y"
{
(yyval.addr) = (yyvsp[(1) - (6)].addr);
(yyval.addr).index = (yyvsp[(3) - (6)].lval);
@@ -2397,8 +2381,8 @@ yyreduce:
}
break;
- case 109:
-#line 570 "a.y"
+ case 106:
+#line 563 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(4) - (5)].lval);
@@ -2407,8 +2391,8 @@ yyreduce:
}
break;
- case 110:
-#line 577 "a.y"
+ case 107:
+#line 570 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_STATIC;
@@ -2417,166 +2401,166 @@ yyreduce:
}
break;
- case 111:
-#line 585 "a.y"
+ case 108:
+#line 578 "a.y"
{
(yyval.lval) = 0;
}
break;
- case 112:
-#line 589 "a.y"
+ case 109:
+#line 582 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
- case 113:
-#line 593 "a.y"
+ case 110:
+#line 586 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
- case 115:
-#line 600 "a.y"
+ case 112:
+#line 593 "a.y"
{
(yyval.lval) = D_AUTO;
}
break;
- case 118:
-#line 608 "a.y"
+ case 115:
+#line 601 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
}
break;
- case 119:
-#line 612 "a.y"
+ case 116:
+#line 605 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
- case 120:
-#line 616 "a.y"
+ case 117:
+#line 609 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
- case 121:
-#line 620 "a.y"
+ case 118:
+#line 613 "a.y"
{
(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
}
break;
- case 122:
-#line 624 "a.y"
+ case 119:
+#line 617 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (3)].lval);
}
break;
- case 123:
-#line 630 "a.y"
+ case 120:
+#line 623 "a.y"
{
(yyval.lval) = ((yyvsp[(1) - (1)].lval) & 0xffffffffLL) +
((vlong)ArgsSizeUnknown << 32);
}
break;
- case 124:
-#line 635 "a.y"
+ case 121:
+#line 628 "a.y"
{
(yyval.lval) = (-(yyvsp[(2) - (2)].lval) & 0xffffffffLL) +
((vlong)ArgsSizeUnknown << 32);
}
break;
- case 125:
-#line 640 "a.y"
+ case 122:
+#line 633 "a.y"
{
(yyval.lval) = ((yyvsp[(1) - (3)].lval) & 0xffffffffLL) +
(((yyvsp[(3) - (3)].lval) & 0xffffLL) << 32);
}
break;
- case 126:
-#line 645 "a.y"
+ case 123:
+#line 638 "a.y"
{
(yyval.lval) = (-(yyvsp[(2) - (4)].lval) & 0xffffffffLL) +
(((yyvsp[(4) - (4)].lval) & 0xffffLL) << 32);
}
break;
- case 128:
-#line 653 "a.y"
+ case 125:
+#line 646 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
}
break;
- case 129:
-#line 657 "a.y"
+ case 126:
+#line 650 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
}
break;
- case 130:
-#line 661 "a.y"
+ case 127:
+#line 654 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
}
break;
- case 131:
-#line 665 "a.y"
+ case 128:
+#line 658 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
}
break;
- case 132:
-#line 669 "a.y"
+ case 129:
+#line 662 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
}
break;
- case 133:
-#line 673 "a.y"
+ case 130:
+#line 666 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
}
break;
- case 134:
-#line 677 "a.y"
+ case 131:
+#line 670 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
}
break;
- case 135:
-#line 681 "a.y"
+ case 132:
+#line 674 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
}
break;
- case 136:
-#line 685 "a.y"
+ case 133:
+#line 678 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
}
break;
- case 137:
-#line 689 "a.y"
+ case 134:
+#line 682 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
}
@@ -2584,7 +2568,7 @@ yyreduce:
/* Line 1267 of yacc.c. */
-#line 2588 "y.tab.c"
+#line 2572 "y.tab.c"
default: break;
}
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
diff --git a/src/cmd/6c/Makefile b/src/cmd/6c/Makefile
deleted file mode 100644
index 3f528d751..000000000
--- a/src/cmd/6c/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2012 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.
-
-include ../../Make.dist
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
deleted file mode 100644
index 68dd7bb5f..000000000
--- a/src/cmd/6c/cgen.c
+++ /dev/null
@@ -1,2046 +0,0 @@
-// Inferno utils/6c/cgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/cgen.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-/* ,x/^(print|prtree)\(/i/\/\/ */
-int castup(Type*, Type*);
-int vaddr(Node *n, int a);
-
-void
-cgen(Node *n, Node *nn)
-{
- Node *l, *r, *t;
- Prog *p1;
- Node nod, nod1, nod2, nod3, nod4;
- int o, hardleft;
- int32 v, curs;
- vlong c;
-
- if(debug['g']) {
- prtree(nn, "cgen lhs");
- prtree(n, "cgen");
- }
- if(n == Z || n->type == T)
- return;
- if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) {
- sugen(n, nn, n->type->width);
- return;
- }
- l = n->left;
- r = n->right;
- o = n->op;
-
- if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) {
- gmove(n, nn);
- return;
- }
-
- if(n->addable >= INDEXED) {
- if(nn == Z) {
- switch(o) {
- default:
- nullwarn(Z, Z);
- break;
- case OINDEX:
- nullwarn(l, r);
- break;
- }
- return;
- }
- gmove(n, nn);
- return;
- }
- curs = cursafe;
-
- if(l->complex >= FNX)
- if(r != Z && r->complex >= FNX)
- switch(o) {
- default:
- if(cond(o) && typesu[l->type->etype])
- break;
-
- regret(&nod, r, 0, 0);
- cgen(r, &nod);
-
- regsalloc(&nod1, r);
- gmove(&nod, &nod1);
-
- regfree(&nod);
- nod = *n;
- nod.right = &nod1;
-
- cgen(&nod, nn);
- return;
-
- case OFUNC:
- case OCOMMA:
- case OANDAND:
- case OOROR:
- case OCOND:
- case ODOT:
- break;
- }
-
- hardleft = l->addable < INDEXED || l->complex >= FNX;
- switch(o) {
- default:
- diag(n, "unknown op in cgen: %O", o);
- break;
-
- case ONEG:
- case OCOM:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- gopcode(o, n->type, Z, &nod);
- gmove(&nod, nn);
- regfree(&nod);
- break;
-
- case OAS:
- if(l->op == OBIT)
- goto bitas;
- if(!hardleft) {
- if(nn != Z || r->addable < INDEXED || hardconst(r)) {
- if(r->complex >= FNX && nn == Z)
- regret(&nod, r, 0, 0);
- else
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- gmove(&nod, l);
- if(nn != Z)
- gmove(&nod, nn);
- regfree(&nod);
- } else
- gmove(r, l);
- break;
- }
- if(l->complex >= r->complex) {
- if(l->op == OINDEX && immconst(r)) {
- gmove(r, l);
- break;
- }
- reglcgen(&nod1, l, Z);
- if(r->addable >= INDEXED && !hardconst(r)) {
- gmove(r, &nod1);
- if(nn != Z)
- gmove(r, nn);
- regfree(&nod1);
- break;
- }
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- } else {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- reglcgen(&nod1, l, Z);
- }
- gmove(&nod, &nod1);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- bitas:
- n = l->left;
- regalloc(&nod, r, nn);
- if(l->complex >= r->complex) {
- reglcgen(&nod1, n, Z);
- cgen(r, &nod);
- } else {
- cgen(r, &nod);
- reglcgen(&nod1, n, Z);
- }
- regalloc(&nod2, n, Z);
- gmove(&nod1, &nod2);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
-
- case OBIT:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- bitload(n, &nod, Z, Z, nn);
- gmove(&nod, nn);
- regfree(&nod);
- break;
-
- case OLSHR:
- case OASHL:
- case OASHR:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- if(r->op == OCONST) {
- if(r->vconst == 0) {
- cgen(l, nn);
- break;
- }
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- if(o == OASHL && r->vconst == 1)
- gopcode(OADD, n->type, &nod, &nod);
- else
- gopcode(o, n->type, r, &nod);
- gmove(&nod, nn);
- regfree(&nod);
- break;
- }
-
- /*
- * get nod to be D_CX
- */
- if(nodreg(&nod, nn, D_CX)) {
- regsalloc(&nod1, n);
- gmove(&nod, &nod1);
- cgen(n, &nod); /* probably a bug */
- gmove(&nod, nn);
- gmove(&nod1, &nod);
- break;
- }
- reg[D_CX]++;
- if(nn->op == OREGISTER && nn->reg == D_CX)
- regalloc(&nod1, l, Z);
- else
- regalloc(&nod1, l, nn);
- if(r->complex >= l->complex) {
- cgen(r, &nod);
- cgen(l, &nod1);
- } else {
- cgen(l, &nod1);
- cgen(r, &nod);
- }
- gopcode(o, n->type, &nod, &nod1);
- gmove(&nod1, nn);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- case OADD:
- case OSUB:
- case OOR:
- case OXOR:
- case OAND:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- if(typefd[n->type->etype])
- goto fop;
- if(r->op == OCONST) {
- if(r->vconst == 0 && o != OAND) {
- cgen(l, nn);
- break;
- }
- }
- if(n->op == OOR && l->op == OASHL && r->op == OLSHR
- && l->right->op == OCONST && r->right->op == OCONST
- && l->left->op == ONAME && r->left->op == ONAME
- && l->left->sym == r->left->sym
- && l->right->vconst + r->right->vconst == 8 * l->left->type->width) {
- regalloc(&nod, l->left, nn);
- cgen(l->left, &nod);
- gopcode(OROTL, n->type, l->right, &nod);
- gmove(&nod, nn);
- regfree(&nod);
- break;
- }
- if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
- && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
- c = l->right->vconst;
- if(c > 0 && c <= 3) {
- if(l->left->complex >= r->complex) {
- regalloc(&nod, l->left, nn);
- cgen(l->left, &nod);
- if(r->addable < INDEXED) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- genmuladd(&nod, &nod, 1 << c, &nod1);
- regfree(&nod1);
- }
- else
- genmuladd(&nod, &nod, 1 << c, r);
- }
- else {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- regalloc(&nod1, l->left, Z);
- cgen(l->left, &nod1);
- genmuladd(&nod, &nod1, 1 << c, &nod);
- regfree(&nod1);
- }
- gmove(&nod, nn);
- regfree(&nod);
- break;
- }
- }
- if(r->addable >= INDEXED && !hardconst(r)) {
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- gopcode(o, n->type, r, &nod);
- gmove(&nod, nn);
- regfree(&nod);
- break;
- }
- if(l->complex >= r->complex) {
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- gopcode(o, n->type, &nod1, &nod);
- } else {
- regalloc(&nod1, r, nn);
- cgen(r, &nod1);
- regalloc(&nod, l, Z);
- cgen(l, &nod);
- gopcode(o, n->type, &nod1, &nod);
- }
- gmove(&nod, nn);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- case OLMOD:
- case OMOD:
- case OLMUL:
- case OLDIV:
- case OMUL:
- case ODIV:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- if(typefd[n->type->etype])
- goto fop;
- if(r->op == OCONST && typechl[n->type->etype]) { /* TO DO */
- SET(v);
- switch(o) {
- case ODIV:
- case OMOD:
- c = r->vconst;
- if(c < 0)
- c = -c;
- v = xlog2(c);
- if(v < 0)
- break;
- /* fall thru */
- case OMUL:
- case OLMUL:
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- switch(o) {
- case OMUL:
- case OLMUL:
- mulgen(n->type, r, &nod);
- break;
- case ODIV:
- sdiv2(r->vconst, v, l, &nod);
- break;
- case OMOD:
- smod2(r->vconst, v, l, &nod);
- break;
- }
- gmove(&nod, nn);
- regfree(&nod);
- goto done;
- case OLDIV:
- c = r->vconst;
- if((c & 0x80000000) == 0)
- break;
- regalloc(&nod1, l, Z);
- cgen(l, &nod1);
- regalloc(&nod, l, nn);
- zeroregm(&nod);
- gins(ACMPL, &nod1, nodconst(c));
- gins(ASBBL, nodconst(-1), &nod);
- regfree(&nod1);
- gmove(&nod, nn);
- regfree(&nod);
- goto done;
- }
- }
-
- if(o == OMUL || o == OLMUL) {
- if(l->addable >= INDEXED) {
- t = l;
- l = r;
- r = t;
- }
- reg[D_DX]++; // for gopcode case OMUL
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- if(r->addable < INDEXED || hardconst(r)) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- gopcode(OMUL, n->type, &nod1, &nod);
- regfree(&nod1);
- }else
- gopcode(OMUL, n->type, r, &nod); /* addressible */
- gmove(&nod, nn);
- regfree(&nod);
- reg[D_DX]--;
- break;
- }
-
- /*
- * get nod to be D_AX
- * get nod1 to be D_DX
- */
- if(nodreg(&nod, nn, D_AX)) {
- regsalloc(&nod2, n);
- gmove(&nod, &nod2);
- v = reg[D_AX];
- reg[D_AX] = 0;
-
- if(isreg(l, D_AX)) {
- nod3 = *n;
- nod3.left = &nod2;
- cgen(&nod3, nn);
- } else
- if(isreg(r, D_AX)) {
- nod3 = *n;
- nod3.right = &nod2;
- cgen(&nod3, nn);
- } else
- cgen(n, nn);
-
- gmove(&nod2, &nod);
- reg[D_AX] = v;
- break;
- }
- if(nodreg(&nod1, nn, D_DX)) {
- regsalloc(&nod2, n);
- gmove(&nod1, &nod2);
- v = reg[D_DX];
- reg[D_DX] = 0;
-
- if(isreg(l, D_DX)) {
- nod3 = *n;
- nod3.left = &nod2;
- cgen(&nod3, nn);
- } else
- if(isreg(r, D_DX)) {
- nod3 = *n;
- nod3.right = &nod2;
- cgen(&nod3, nn);
- } else
- cgen(n, nn);
-
- gmove(&nod2, &nod1);
- reg[D_DX] = v;
- break;
- }
- reg[D_AX]++;
-
- if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) {
- reg[D_DX]++;
- if(l->addable < INDEXED) {
- regalloc(&nod2, l, Z);
- cgen(l, &nod2);
- l = &nod2;
- }
- if(o == ODIV)
- sdivgen(l, r, &nod, &nod1);
- else
- udivgen(l, r, &nod, &nod1);
- gmove(&nod1, nn);
- if(l == &nod2)
- regfree(l);
- goto freeaxdx;
- }
-
- if(l->complex >= r->complex) {
- cgen(l, &nod);
- reg[D_DX]++;
- if(o == ODIV || o == OMOD)
- gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
- if(o == OLDIV || o == OLMOD)
- zeroregm(&nod1);
- if(r->addable < INDEXED || r->op == OCONST) {
- regsalloc(&nod3, r);
- cgen(r, &nod3);
- gopcode(o, n->type, &nod3, Z);
- } else
- gopcode(o, n->type, r, Z);
- } else {
- regsalloc(&nod3, r);
- cgen(r, &nod3);
- cgen(l, &nod);
- reg[D_DX]++;
- if(o == ODIV || o == OMOD)
- gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
- if(o == OLDIV || o == OLMOD)
- zeroregm(&nod1);
- gopcode(o, n->type, &nod3, Z);
- }
- if(o == OMOD || o == OLMOD)
- gmove(&nod1, nn);
- else
- gmove(&nod, nn);
- freeaxdx:
- regfree(&nod);
- regfree(&nod1);
- break;
-
- case OASLSHR:
- case OASASHL:
- case OASASHR:
- if(r->op == OCONST)
- goto asand;
- if(l->op == OBIT)
- goto asbitop;
- if(typefd[n->type->etype])
- goto asand; /* can this happen? */
-
- /*
- * get nod to be D_CX
- */
- if(nodreg(&nod, nn, D_CX)) {
- regsalloc(&nod1, n);
- gmove(&nod, &nod1);
- cgen(n, &nod);
- if(nn != Z)
- gmove(&nod, nn);
- gmove(&nod1, &nod);
- break;
- }
- reg[D_CX]++;
-
- if(r->complex >= l->complex) {
- cgen(r, &nod);
- if(hardleft)
- reglcgen(&nod1, l, Z);
- else
- nod1 = *l;
- } else {
- if(hardleft)
- reglcgen(&nod1, l, Z);
- else
- nod1 = *l;
- cgen(r, &nod);
- }
-
- gopcode(o, l->type, &nod, &nod1);
- regfree(&nod);
- if(nn != Z)
- gmove(&nod1, nn);
- if(hardleft)
- regfree(&nod1);
- break;
-
- case OASAND:
- case OASADD:
- case OASSUB:
- case OASXOR:
- case OASOR:
- asand:
- if(l->op == OBIT)
- goto asbitop;
- if(typefd[l->type->etype] || typefd[r->type->etype])
- goto asfop;
- if(l->complex >= r->complex) {
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
- if(!immconst(r)) {
- regalloc(&nod1, r, nn);
- cgen(r, &nod1);
- gopcode(o, l->type, &nod1, &nod);
- regfree(&nod1);
- } else
- gopcode(o, l->type, r, &nod);
- } else {
- regalloc(&nod1, r, nn);
- cgen(r, &nod1);
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
- gopcode(o, l->type, &nod1, &nod);
- regfree(&nod1);
- }
- if(nn != Z)
- gmove(&nod, nn);
- if(hardleft)
- regfree(&nod);
- break;
-
- asfop:
- if(l->complex >= r->complex) {
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
- if(r->addable < INDEXED){
- regalloc(&nod1, r, nn);
- cgen(r, &nod1);
- }else
- nod1 = *r;
- regalloc(&nod2, r, Z);
- gmove(&nod, &nod2);
- gopcode(o, r->type, &nod1, &nod2);
- gmove(&nod2, &nod);
- regfree(&nod2);
- if(r->addable < INDEXED)
- regfree(&nod1);
- } else {
- regalloc(&nod1, r, nn);
- cgen(r, &nod1);
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
- if(o != OASMUL && o != OASADD) {
- regalloc(&nod2, r, Z);
- gmove(&nod, &nod2);
- gopcode(o, r->type, &nod1, &nod2);
- regfree(&nod1);
- gmove(&nod2, &nod);
- regfree(&nod2);
- } else {
- gopcode(o, r->type, &nod, &nod1);
- gmove(&nod1, &nod);
- regfree(&nod1);
- }
- }
- if(nn != Z)
- gmove(&nod, nn);
- if(hardleft)
- regfree(&nod);
- break;
-
- case OASLMUL:
- case OASLDIV:
- case OASLMOD:
- case OASMUL:
- case OASDIV:
- case OASMOD:
- if(l->op == OBIT)
- goto asbitop;
- if(typefd[n->type->etype] || typefd[r->type->etype])
- goto asfop;
- if(r->op == OCONST && typechl[n->type->etype]) {
- SET(v);
- switch(o) {
- case OASDIV:
- case OASMOD:
- c = r->vconst;
- if(c < 0)
- c = -c;
- v = xlog2(c);
- if(v < 0)
- break;
- /* fall thru */
- case OASMUL:
- case OASLMUL:
- if(hardleft)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- regalloc(&nod, l, nn);
- cgen(&nod2, &nod);
- switch(o) {
- case OASMUL:
- case OASLMUL:
- mulgen(n->type, r, &nod);
- break;
- case OASDIV:
- sdiv2(r->vconst, v, l, &nod);
- break;
- case OASMOD:
- smod2(r->vconst, v, l, &nod);
- break;
- }
- havev:
- gmove(&nod, &nod2);
- if(nn != Z)
- gmove(&nod, nn);
- if(hardleft)
- regfree(&nod2);
- regfree(&nod);
- goto done;
- case OASLDIV:
- c = r->vconst;
- if((c & 0x80000000) == 0)
- break;
- if(hardleft)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- regalloc(&nod1, l, nn);
- cgen(&nod2, &nod1);
- regalloc(&nod, l, nn);
- zeroregm(&nod);
- gins(ACMPL, &nod1, nodconst(c));
- gins(ASBBL, nodconst(-1), &nod);
- regfree(&nod1);
- goto havev;
- }
- }
-
- if(o == OASMUL) {
- /* should favour AX */
- regalloc(&nod, l, nn);
- if(r->complex >= FNX) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- r = &nod1;
- }
- if(hardleft)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- cgen(&nod2, &nod);
- if(r->addable < INDEXED || hardconst(r)) {
- if(r->complex < FNX) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- }
- gopcode(OASMUL, n->type, &nod1, &nod);
- regfree(&nod1);
- }
- else
- gopcode(OASMUL, n->type, r, &nod);
- if(r == &nod1)
- regfree(r);
- gmove(&nod, &nod2);
- if(nn != Z)
- gmove(&nod, nn);
- regfree(&nod);
- if(hardleft)
- regfree(&nod2);
- break;
- }
-
- /*
- * get nod to be D_AX
- * get nod1 to be D_DX
- */
- if(nodreg(&nod, nn, D_AX)) {
- regsalloc(&nod2, n);
- gmove(&nod, &nod2);
- v = reg[D_AX];
- reg[D_AX] = 0;
-
- if(isreg(l, D_AX)) {
- nod3 = *n;
- nod3.left = &nod2;
- cgen(&nod3, nn);
- } else
- if(isreg(r, D_AX)) {
- nod3 = *n;
- nod3.right = &nod2;
- cgen(&nod3, nn);
- } else
- cgen(n, nn);
-
- gmove(&nod2, &nod);
- reg[D_AX] = v;
- break;
- }
- if(nodreg(&nod1, nn, D_DX)) {
- regsalloc(&nod2, n);
- gmove(&nod1, &nod2);
- v = reg[D_DX];
- reg[D_DX] = 0;
-
- if(isreg(l, D_DX)) {
- nod3 = *n;
- nod3.left = &nod2;
- cgen(&nod3, nn);
- } else
- if(isreg(r, D_DX)) {
- nod3 = *n;
- nod3.right = &nod2;
- cgen(&nod3, nn);
- } else
- cgen(n, nn);
-
- gmove(&nod2, &nod1);
- reg[D_DX] = v;
- break;
- }
- reg[D_AX]++;
- reg[D_DX]++;
-
- if(l->complex >= r->complex) {
- if(hardleft)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- cgen(&nod2, &nod);
- if(r->op == OCONST && typechl[r->type->etype]) {
- switch(o) {
- case OASDIV:
- sdivgen(&nod2, r, &nod, &nod1);
- goto divdone;
- case OASLDIV:
- udivgen(&nod2, r, &nod, &nod1);
- divdone:
- gmove(&nod1, &nod2);
- if(nn != Z)
- gmove(&nod1, nn);
- goto freelxaxdx;
- }
- }
- if(o == OASDIV || o == OASMOD)
- gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
- if(o == OASLDIV || o == OASLMOD)
- zeroregm(&nod1);
- if(r->addable < INDEXED || r->op == OCONST ||
- !typeil[r->type->etype]) {
- regalloc(&nod3, r, Z);
- cgen(r, &nod3);
- gopcode(o, l->type, &nod3, Z);
- regfree(&nod3);
- } else
- gopcode(o, n->type, r, Z);
- } else {
- regalloc(&nod3, r, Z);
- cgen(r, &nod3);
- if(hardleft)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- cgen(&nod2, &nod);
- if(o == OASDIV || o == OASMOD)
- gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
- if(o == OASLDIV || o == OASLMOD)
- zeroregm(&nod1);
- gopcode(o, l->type, &nod3, Z);
- regfree(&nod3);
- }
- if(o == OASMOD || o == OASLMOD) {
- gmove(&nod1, &nod2);
- if(nn != Z)
- gmove(&nod1, nn);
- } else {
- gmove(&nod, &nod2);
- if(nn != Z)
- gmove(&nod, nn);
- }
- freelxaxdx:
- if(hardleft)
- regfree(&nod2);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- fop:
- if(l->complex >= r->complex) {
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- if(r->addable < INDEXED) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- gopcode(o, n->type, &nod1, &nod);
- regfree(&nod1);
- } else
- gopcode(o, n->type, r, &nod);
- } else {
- /* TO DO: could do better with r->addable >= INDEXED */
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- gopcode(o, n->type, &nod1, &nod);
- regfree(&nod1);
- }
- gmove(&nod, nn);
- regfree(&nod);
- break;
-
- asbitop:
- regalloc(&nod4, n, nn);
- if(l->complex >= r->complex) {
- bitload(l, &nod, &nod1, &nod2, &nod4);
- regalloc(&nod3, r, Z);
- cgen(r, &nod3);
- } else {
- regalloc(&nod3, r, Z);
- cgen(r, &nod3);
- bitload(l, &nod, &nod1, &nod2, &nod4);
- }
- gmove(&nod, &nod4);
-
- { /* TO DO: check floating point source */
- Node onod;
-
- /* incredible grot ... */
- onod = nod3;
- onod.op = o;
- onod.complex = 2;
- onod.addable = 0;
- onod.type = tfield;
- onod.left = &nod4;
- onod.right = &nod3;
- cgen(&onod, Z);
- }
- regfree(&nod3);
- gmove(&nod4, &nod);
- regfree(&nod4);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
-
- case OADDR:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- lcgen(l, nn);
- break;
-
- case OFUNC:
- if(l->complex >= FNX) {
- if(l->op != OIND)
- diag(n, "bad function call");
-
- regret(&nod, l->left, 0, 0);
- cgen(l->left, &nod);
- regsalloc(&nod1, l->left);
- gmove(&nod, &nod1);
- regfree(&nod);
-
- nod = *n;
- nod.left = &nod2;
- nod2 = *l;
- nod2.left = &nod1;
- nod2.complex = 1;
- cgen(&nod, nn);
-
- return;
- }
- gargs(r, &nod, &nod1);
- if(l->addable < INDEXED) {
- reglcgen(&nod, l, nn);
- nod.op = OREGISTER;
- gopcode(OFUNC, n->type, Z, &nod);
- regfree(&nod);
- } else
- gopcode(OFUNC, n->type, Z, l);
- if(REGARG >= 0 && reg[REGARG])
- reg[REGARG]--;
- regret(&nod, n, l->type, 1); // update maxarg if nothing else
- if(nn != Z)
- gmove(&nod, nn);
- if(nod.op == OREGISTER)
- regfree(&nod);
- break;
-
- case OIND:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- regialloc(&nod, n, nn);
- r = l;
- while(r->op == OADD)
- r = r->right;
- if(sconst(r)) {
- v = r->vconst;
- r->vconst = 0;
- cgen(l, &nod);
- nod.xoffset += v;
- r->vconst = v;
- } else
- cgen(l, &nod);
- regind(&nod, n);
- gmove(&nod, nn);
- regfree(&nod);
- break;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OLO:
- case OLS:
- case OHI:
- case OHS:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- boolgen(n, 1, nn);
- break;
-
- case OANDAND:
- case OOROR:
- boolgen(n, 1, nn);
- if(nn == Z)
- patch(p, pc);
- break;
-
- case ONOT:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- boolgen(n, 1, nn);
- break;
-
- case OCOMMA:
- cgen(l, Z);
- cgen(r, nn);
- break;
-
- case OCAST:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- /*
- * convert from types l->n->nn
- */
- if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
- /* both null, gen l->nn */
- cgen(l, nn);
- break;
- }
- if(ewidth[n->type->etype] < ewidth[l->type->etype]){
- if(l->type->etype == TIND && typechlp[n->type->etype])
- warn(n, "conversion of pointer to shorter integer");
- }else if(0){
- if(nocast(n->type, nn->type) || castup(n->type, nn->type)){
- if(typefd[l->type->etype] != typefd[nn->type->etype])
- regalloc(&nod, l, nn);
- else
- regalloc(&nod, nn, nn);
- cgen(l, &nod);
- gmove(&nod, nn);
- regfree(&nod);
- break;
- }
- }
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- regalloc(&nod1, n, &nod);
- gmove(&nod, &nod1);
- gmove(&nod1, nn);
- regfree(&nod1);
- regfree(&nod);
- break;
-
- case ODOT:
- sugen(l, nodrat, l->type->width);
- if(nn == Z)
- break;
- warn(n, "non-interruptable temporary");
- nod = *nodrat;
- if(!r || r->op != OCONST) {
- diag(n, "DOT and no offset");
- break;
- }
- nod.xoffset += (int32)r->vconst;
- nod.type = n->type;
- cgen(&nod, nn);
- break;
-
- case OCOND:
- bcgen(l, 1);
- p1 = p;
- cgen(r->left, nn);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- cgen(r->right, nn);
- patch(p1, pc);
- break;
-
- case OPOSTINC:
- case OPOSTDEC:
- v = 1;
- if(l->type->etype == TIND)
- v = l->type->link->width;
- if(o == OPOSTDEC)
- v = -v;
- if(l->op == OBIT)
- goto bitinc;
- if(nn == Z)
- goto pre;
-
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
-
- gmove(&nod, nn);
- if(typefd[n->type->etype]) {
- regalloc(&nod1, l, Z);
- gmove(&nod, &nod1);
- if(v < 0)
- gopcode(OSUB, n->type, nodfconst(-v), &nod1);
- else
- gopcode(OADD, n->type, nodfconst(v), &nod1);
- gmove(&nod1, &nod);
- regfree(&nod1);
- } else
- gopcode(OADD, n->type, nodconst(v), &nod);
- if(hardleft)
- regfree(&nod);
- break;
-
- case OPREINC:
- case OPREDEC:
- v = 1;
- if(l->type->etype == TIND)
- v = l->type->link->width;
- if(o == OPREDEC)
- v = -v;
- if(l->op == OBIT)
- goto bitinc;
-
- pre:
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
- if(typefd[n->type->etype]) {
- regalloc(&nod1, l, Z);
- gmove(&nod, &nod1);
- if(v < 0)
- gopcode(OSUB, n->type, nodfconst(-v), &nod1);
- else
- gopcode(OADD, n->type, nodfconst(v), &nod1);
- gmove(&nod1, &nod);
- regfree(&nod1);
- } else
- gopcode(OADD, n->type, nodconst(v), &nod);
- if(nn != Z)
- gmove(&nod, nn);
- if(hardleft)
- regfree(&nod);
- break;
-
- bitinc:
- if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
- bitload(l, &nod, &nod1, &nod2, Z);
- gmove(&nod, nn);
- gopcode(OADD, tfield, nodconst(v), &nod);
- bitstore(l, &nod, &nod1, &nod2, Z);
- break;
- }
- bitload(l, &nod, &nod1, &nod2, nn);
- gopcode(OADD, tfield, nodconst(v), &nod);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
- }
-done:
- cursafe = curs;
-}
-
-void
-reglcgen(Node *t, Node *n, Node *nn)
-{
- Node *r;
- int32 v;
-
- regialloc(t, n, nn);
- if(n->op == OIND) {
- r = n->left;
- while(r->op == OADD)
- r = r->right;
- if(sconst(r)) {
- v = r->vconst;
- r->vconst = 0;
- lcgen(n, t);
- t->xoffset += v;
- r->vconst = v;
- regind(t, n);
- return;
- }
- }
- lcgen(n, t);
- regind(t, n);
-}
-
-void
-lcgen(Node *n, Node *nn)
-{
- Prog *p1;
- Node nod;
-
- if(debug['g']) {
- prtree(nn, "lcgen lhs");
- prtree(n, "lcgen");
- }
- if(n == Z || n->type == T)
- return;
- if(nn == Z) {
- nn = &nod;
- regalloc(&nod, n, Z);
- }
- switch(n->op) {
- default:
- if(n->addable < INDEXED) {
- diag(n, "unknown op in lcgen: %O", n->op);
- break;
- }
- gopcode(OADDR, n->type, n, nn);
- break;
-
- case OCOMMA:
- cgen(n->left, n->left);
- lcgen(n->right, nn);
- break;
-
- case OIND:
- cgen(n->left, nn);
- break;
-
- case OCOND:
- bcgen(n->left, 1);
- p1 = p;
- lcgen(n->right->left, nn);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- lcgen(n->right->right, nn);
- patch(p1, pc);
- break;
- }
-}
-
-void
-bcgen(Node *n, int true)
-{
-
- if(n->type == T)
- gbranch(OGOTO);
- else
- boolgen(n, true, Z);
-}
-
-void
-boolgen(Node *n, int true, Node *nn)
-{
- int o;
- Prog *p1, *p2, *p3;
- Node *l, *r, nod, nod1;
- int32 curs;
-
- if(debug['g']) {
- print("boolgen %d\n", true);
- prtree(nn, "boolgen lhs");
- prtree(n, "boolgen");
- }
- curs = cursafe;
- l = n->left;
- r = n->right;
- switch(n->op) {
-
- default:
- o = ONE;
- if(true)
- o = OEQ;
- /* bad, 13 is address of external that becomes constant */
- if(n->addable >= INDEXED && n->addable != 13) {
- if(typefd[n->type->etype]) {
- regalloc(&nod1, n, Z);
- gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */
- gopcode(o, n->type, n, &nod1);
- regfree(&nod1);
- } else
- gopcode(o, n->type, n, nodconst(0));
- goto com;
- }
- regalloc(&nod, n, nn);
- cgen(n, &nod);
- if(typefd[n->type->etype]) {
- regalloc(&nod1, n, Z);
- gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */
- gopcode(o, n->type, &nod, &nod1);
- regfree(&nod1);
- } else
- gopcode(o, n->type, &nod, nodconst(0));
- regfree(&nod);
- goto com;
-
- case OCONST:
- o = vconst(n);
- if(!true)
- o = !o;
- gbranch(OGOTO);
- if(o) {
- p1 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- }
- goto com;
-
- case OCOMMA:
- cgen(l, Z);
- boolgen(r, true, nn);
- break;
-
- case ONOT:
- boolgen(l, !true, nn);
- break;
-
- case OCOND:
- bcgen(l, 1);
- p1 = p;
- bcgen(r->left, true);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- bcgen(r->right, !true);
- patch(p2, pc);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- patch(p2, pc);
- goto com;
-
- case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- bcgen(l, true);
- p1 = p;
- bcgen(r, !true);
- p2 = p;
- patch(p1, pc);
- gbranch(OGOTO);
- patch(p2, pc);
- goto com;
-
- case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bcgen(l, !true);
- p1 = p;
- bcgen(r, !true);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- patch(p2, pc);
- goto com;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- o = n->op;
- if(true && typefd[l->type->etype] && (o == OEQ || o == ONE)) {
- // Cannot rewrite !(l == r) into l != r with float64; it breaks NaNs.
- // Jump around instead.
- boolgen(n, 0, Z);
- p1 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- goto com;
- }
- if(true)
- o = comrel[relindex(o)];
- if(l->complex >= FNX && r->complex >= FNX) {
- regret(&nod, r, 0, 0);
- cgen(r, &nod);
- regsalloc(&nod1, r);
- gmove(&nod, &nod1);
- regfree(&nod);
- nod = *n;
- nod.right = &nod1;
- boolgen(&nod, true, nn);
- break;
- }
- if(immconst(l)) {
- // NOTE: Reversing the comparison here is wrong
- // for floating point ordering comparisons involving NaN,
- // but we don't have any of those yet so we don't
- // bother worrying about it.
- o = invrel[relindex(o)];
- /* bad, 13 is address of external that becomes constant */
- if(r->addable < INDEXED || r->addable == 13) {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- gopcode(o, l->type, &nod, l);
- regfree(&nod);
- } else
- gopcode(o, l->type, r, l);
- goto com;
- }
- if(typefd[l->type->etype])
- o = invrel[relindex(logrel[relindex(o)])];
- if(l->complex >= r->complex) {
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- gopcode(o, l->type, &nod, &nod1);
- regfree(&nod1);
- } else {
- gopcode(o, l->type, &nod, r);
- }
- regfree(&nod);
- goto fixfloat;
- }
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) {
- regalloc(&nod1, l, Z);
- cgen(l, &nod1);
- if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT])
- gopcode(o, types[TINT], &nod1, &nod);
- else
- gopcode(o, l->type, &nod1, &nod);
- regfree(&nod1);
- } else
- gopcode(o, l->type, l, &nod);
- regfree(&nod);
- fixfloat:
- if(typefd[l->type->etype]) {
- switch(o) {
- case OEQ:
- // Already emitted AJEQ; want AJEQ and AJPC.
- p1 = p;
- gbranch(OGOTO);
- p2 = p;
- patch(p1, pc);
- gins(AJPC, Z, Z);
- patch(p2, pc);
- break;
-
- case ONE:
- // Already emitted AJNE; want AJNE or AJPS.
- p1 = p;
- gins(AJPS, Z, Z);
- p2 = p;
- gbranch(OGOTO);
- p3 = p;
- patch(p1, pc);
- patch(p2, pc);
- gbranch(OGOTO);
- patch(p3, pc);
- break;
- }
- }
-
- com:
- if(nn != Z) {
- p1 = p;
- gmove(nodconst(1L), nn);
- gbranch(OGOTO);
- p2 = p;
- patch(p1, pc);
- gmove(nodconst(0L), nn);
- patch(p2, pc);
- }
- break;
- }
- cursafe = curs;
-}
-
-void
-sugen(Node *n, Node *nn, int32 w)
-{
- Prog *p1;
- Node nod0, nod1, nod2, nod3, nod4, *l, *r;
- Type *t;
- int c, mt, mo;
- vlong o0, o1;
-
- if(n == Z || n->type == T)
- return;
- if(debug['g']) {
- prtree(nn, "sugen lhs");
- prtree(n, "sugen");
- }
- if(nn == nodrat)
- if(w > nrathole)
- nrathole = w;
- switch(n->op) {
- case OIND:
- if(nn == Z) {
- nullwarn(n->left, Z);
- break;
- }
-
- default:
- goto copy;
-
- case OCONST:
- goto copy;
-
- case ODOT:
- l = n->left;
- sugen(l, nodrat, l->type->width);
- if(nn == Z)
- break;
- warn(n, "non-interruptable temporary");
- nod1 = *nodrat;
- r = n->right;
- if(!r || r->op != OCONST) {
- diag(n, "DOT and no offset");
- break;
- }
- nod1.xoffset += (int32)r->vconst;
- nod1.type = n->type;
- sugen(&nod1, nn, w);
- break;
-
- case OSTRUCT:
- /*
- * rewrite so lhs has no fn call
- */
- if(nn != Z && side(nn)) {
- nod1 = *n;
- nod1.type = typ(TIND, n->type);
- regret(&nod2, &nod1, 0, 0);
- lcgen(nn, &nod2);
- regsalloc(&nod0, &nod1);
- cgen(&nod2, &nod0);
- regfree(&nod2);
-
- nod1 = *n;
- nod1.op = OIND;
- nod1.left = &nod0;
- nod1.right = Z;
- nod1.complex = 1;
-
- sugen(n, &nod1, w);
- return;
- }
-
- r = n->left;
- for(t = n->type->link; t != T; t = t->down) {
- l = r;
- if(r->op == OLIST) {
- l = r->left;
- r = r->right;
- }
- if(nn == Z) {
- cgen(l, nn);
- continue;
- }
- /*
- * hand craft *(&nn + o) = l
- */
- nod0 = znode;
- nod0.op = OAS;
- nod0.type = t;
- nod0.left = &nod1;
- nod0.right = nil;
-
- nod1 = znode;
- nod1.op = OIND;
- nod1.type = t;
- nod1.left = &nod2;
-
- nod2 = znode;
- nod2.op = OADD;
- nod2.type = typ(TIND, t);
- nod2.left = &nod3;
- nod2.right = &nod4;
-
- nod3 = znode;
- nod3.op = OADDR;
- nod3.type = nod2.type;
- nod3.left = nn;
-
- nod4 = znode;
- nod4.op = OCONST;
- nod4.type = nod2.type;
- nod4.vconst = t->offset;
-
- ccom(&nod0);
- acom(&nod0);
- xcom(&nod0);
- nod0.addable = 0;
- nod0.right = l;
-
- // prtree(&nod0, "hand craft");
- cgen(&nod0, Z);
- }
- break;
-
- case OAS:
- if(nn == Z) {
- if(n->addable < INDEXED)
- sugen(n->right, n->left, w);
- break;
- }
-
- sugen(n->right, nodrat, w);
- warn(n, "non-interruptable temporary");
- sugen(nodrat, n->left, w);
- sugen(nodrat, nn, w);
- break;
-
- case OFUNC:
- if(!hasdotdotdot(n->left->type)) {
- cgen(n, Z);
- if(nn != Z) {
- curarg -= n->type->width;
- regret(&nod1, n, n->left->type, 1);
- if(nn->complex >= FNX) {
- regsalloc(&nod2, n);
- cgen(&nod1, &nod2);
- nod1 = nod2;
- }
- cgen(&nod1, nn);
- }
- break;
- }
- if(nn == Z) {
- sugen(n, nodrat, w);
- break;
- }
- if(nn->op != OIND) {
- nn = new1(OADDR, nn, Z);
- nn->type = types[TIND];
- nn->addable = 0;
- } else
- nn = nn->left;
- n = new(OFUNC, n->left, new(OLIST, nn, n->right));
- n->type = types[TVOID];
- n->left->type = types[TVOID];
- cgen(n, Z);
- break;
-
- case OCOND:
- bcgen(n->left, 1);
- p1 = p;
- sugen(n->right->left, nn, w);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- sugen(n->right->right, nn, w);
- patch(p1, pc);
- break;
-
- case OCOMMA:
- cgen(n->left, Z);
- sugen(n->right, nn, w);
- break;
- }
- return;
-
-copy:
- if(nn == Z) {
- switch(n->op) {
- case OASADD:
- case OASSUB:
- case OASAND:
- case OASOR:
- case OASXOR:
-
- case OASMUL:
- case OASLMUL:
-
-
- case OASASHL:
- case OASASHR:
- case OASLSHR:
- break;
-
- case OPOSTINC:
- case OPOSTDEC:
- case OPREINC:
- case OPREDEC:
- break;
-
- default:
- return;
- }
- }
-
- if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
- t = nn->type;
- nn->type = types[TIND];
- regialloc(&nod1, nn, Z);
- lcgen(nn, &nod1);
- regsalloc(&nod2, nn);
- nn->type = t;
-
- gins(AMOVQ, &nod1, &nod2);
- regfree(&nod1);
-
- nod2.type = typ(TIND, t);
-
- nod1 = nod2;
- nod1.op = OIND;
- nod1.left = &nod2;
- nod1.right = Z;
- nod1.complex = 1;
- nod1.type = t;
-
- sugen(n, &nod1, w);
- return;
- }
-
- if(w <= 32) {
- c = cursafe;
- if(n->left != Z && n->left->complex >= FNX
- && n->right != Z && n->right->complex >= FNX) {
- regsalloc(&nod1, n->right);
- cgen(n->right, &nod1);
- nod2 = *n;
- nod2.right = &nod1;
- cgen(&nod2, nn);
- cursafe = c;
- return;
- }
- if(w & 7) {
- mt = TLONG;
- mo = AMOVL;
- } else {
- mt = TVLONG;
- mo = AMOVQ;
- }
- if(n->complex > nn->complex) {
- t = n->type;
- n->type = types[mt];
- regalloc(&nod0, n, Z);
- if(!vaddr(n, 0)) {
- reglcgen(&nod1, n, Z);
- n->type = t;
- n = &nod1;
- }
- else
- n->type = t;
-
- t = nn->type;
- nn->type = types[mt];
- if(!vaddr(nn, 0)) {
- reglcgen(&nod2, nn, Z);
- nn->type = t;
- nn = &nod2;
- }
- else
- nn->type = t;
- } else {
- t = nn->type;
- nn->type = types[mt];
- regalloc(&nod0, nn, Z);
- if(!vaddr(nn, 0)) {
- reglcgen(&nod2, nn, Z);
- nn->type = t;
- nn = &nod2;
- }
- else
- nn->type = t;
-
- t = n->type;
- n->type = types[mt];
- if(!vaddr(n, 0)) {
- reglcgen(&nod1, n, Z);
- n->type = t;
- n = &nod1;
- }
- else
- n->type = t;
- }
- o0 = n->xoffset;
- o1 = nn->xoffset;
- w /= ewidth[mt];
- while(--w >= 0) {
- gins(mo, n, &nod0);
- gins(mo, &nod0, nn);
- n->xoffset += ewidth[mt];
- nn->xoffset += ewidth[mt];
- }
- n->xoffset = o0;
- nn->xoffset = o1;
- if(nn == &nod2)
- regfree(&nod2);
- if(n == &nod1)
- regfree(&nod1);
- regfree(&nod0);
- return;
- }
-
- /* botch, need to save in .safe */
- c = 0;
- if(n->complex > nn->complex) {
- t = n->type;
- n->type = types[TIND];
- nodreg(&nod1, n, D_SI);
- if(reg[D_SI]) {
- gins(APUSHQ, &nod1, Z);
- c |= 1;
- reg[D_SI]++;
- }
- lcgen(n, &nod1);
- n->type = t;
-
- t = nn->type;
- nn->type = types[TIND];
- nodreg(&nod2, nn, D_DI);
- if(reg[D_DI]) {
-warn(Z, "DI botch");
- gins(APUSHQ, &nod2, Z);
- c |= 2;
- reg[D_DI]++;
- }
- lcgen(nn, &nod2);
- nn->type = t;
- } else {
- t = nn->type;
- nn->type = types[TIND];
- nodreg(&nod2, nn, D_DI);
- if(reg[D_DI]) {
-warn(Z, "DI botch");
- gins(APUSHQ, &nod2, Z);
- c |= 2;
- reg[D_DI]++;
- }
- lcgen(nn, &nod2);
- nn->type = t;
-
- t = n->type;
- n->type = types[TIND];
- nodreg(&nod1, n, D_SI);
- if(reg[D_SI]) {
- gins(APUSHQ, &nod1, Z);
- c |= 1;
- reg[D_SI]++;
- }
- lcgen(n, &nod1);
- n->type = t;
- }
- nodreg(&nod3, n, D_CX);
- if(reg[D_CX]) {
- gins(APUSHQ, &nod3, Z);
- c |= 4;
- reg[D_CX]++;
- }
- gins(AMOVL, nodconst(w/SZ_INT), &nod3);
- gins(ACLD, Z, Z);
- gins(AREP, Z, Z);
- gins(AMOVSL, Z, Z);
- if(c & 4) {
- gins(APOPQ, Z, &nod3);
- reg[D_CX]--;
- }
- if(c & 2) {
- gins(APOPQ, Z, &nod2);
- reg[nod2.reg]--;
- }
- if(c & 1) {
- gins(APOPQ, Z, &nod1);
- reg[nod1.reg]--;
- }
-}
-
-/*
- * TO DO
- */
-void
-layout(Node *f, Node *t, int c, int cv, Node *cn)
-{
- Node t1, t2;
-
- while(c > 3) {
- layout(f, t, 2, 0, Z);
- c -= 2;
- }
-
- regalloc(&t1, &lregnode, Z);
- regalloc(&t2, &lregnode, Z);
- if(c > 0) {
- gmove(f, &t1);
- f->xoffset += SZ_INT;
- }
- if(cn != Z)
- gmove(nodconst(cv), cn);
- if(c > 1) {
- gmove(f, &t2);
- f->xoffset += SZ_INT;
- }
- if(c > 0) {
- gmove(&t1, t);
- t->xoffset += SZ_INT;
- }
- if(c > 2) {
- gmove(f, &t1);
- f->xoffset += SZ_INT;
- }
- if(c > 1) {
- gmove(&t2, t);
- t->xoffset += SZ_INT;
- }
- if(c > 2) {
- gmove(&t1, t);
- t->xoffset += SZ_INT;
- }
- regfree(&t1);
- regfree(&t2);
-}
-
-/*
- * constant is not vlong or fits as 32-bit signed immediate
- */
-int
-immconst(Node *n)
-{
- int32 v;
-
- if(n->op != OCONST || !typechlpv[n->type->etype])
- return 0;
- if(typechl[n->type->etype])
- return 1;
- v = n->vconst;
- return n->vconst == (vlong)v;
-}
-
-/*
- * if a constant and vlong, doesn't fit as 32-bit signed immediate
- */
-int
-hardconst(Node *n)
-{
- return n->op == OCONST && !immconst(n);
-}
-
-/*
- * casting up to t2 covers an intermediate cast to t1
- */
-int
-castup(Type *t1, Type *t2)
-{
- int ft;
-
- if(!nilcast(t1, t2))
- return 0;
- /* known to be small to large */
- ft = t1->etype;
- switch(t2->etype){
- case TINT:
- case TLONG:
- return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR;
- case TUINT:
- case TULONG:
- return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR;
- case TVLONG:
- return ft == TLONG || ft == TINT || ft == TSHORT;
- case TUVLONG:
- return ft == TULONG || ft == TUINT || ft == TUSHORT;
- }
- return 0;
-}
-
-void
-zeroregm(Node *n)
-{
- gins(AMOVL, nodconst(0), n);
-}
-
-/* do we need to load the address of a vlong? */
-int
-vaddr(Node *n, int a)
-{
- switch(n->op) {
- case ONAME:
- if(a)
- return 1;
- return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
-
- case OCONST:
- case OREGISTER:
- case OINDREG:
- return 1;
- }
- return 0;
-}
-
-int32
-hi64v(Node *n)
-{
- if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
- return (int32)(n->vconst) & ~0L;
- else
- return (int32)((uvlong)n->vconst>>32) & ~0L;
-}
-
-int32
-lo64v(Node *n)
-{
- if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
- return (int32)((uvlong)n->vconst>>32) & ~0L;
- else
- return (int32)(n->vconst) & ~0L;
-}
-
-Node *
-hi64(Node *n)
-{
- return nodconst(hi64v(n));
-}
-
-Node *
-lo64(Node *n)
-{
- return nodconst(lo64v(n));
-}
-
-int
-cond(int op)
-{
- switch(op) {
- case OANDAND:
- case OOROR:
- case ONOT:
- return 1;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- return 1;
- }
- return 0;
-}
diff --git a/src/cmd/6c/div.c b/src/cmd/6c/div.c
deleted file mode 100644
index bad6c5e27..000000000
--- a/src/cmd/6c/div.c
+++ /dev/null
@@ -1,236 +0,0 @@
-// Inferno utils/6c/div.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/div.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-/*
- * Based on: Granlund, T.; Montgomery, P.L.
- * "Division by Invariant Integers using Multiplication".
- * SIGPLAN Notices, Vol. 29, June 1994, page 61.
- */
-
-#define TN(n) ((uvlong)1 << (n))
-#define T31 TN(31)
-#define T32 TN(32)
-
-int
-multiplier(uint32 d, int p, uvlong *mp)
-{
- int l;
- uvlong mlo, mhi, tlo, thi;
-
- l = topbit(d - 1) + 1;
- mlo = (((TN(l) - d) << 32) / d) + T32;
- if(l + p == 64)
- mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
- else
- mhi = (TN(32 + l) + TN(32 + l - p)) / d;
- /*assert(mlo < mhi);*/
- while(l > 0) {
- tlo = mlo >> 1;
- thi = mhi >> 1;
- if(tlo == thi)
- break;
- mlo = tlo;
- mhi = thi;
- l--;
- }
- *mp = mhi;
- return l;
-}
-
-int
-sdiv(uint32 d, uint32 *mp, int *sp)
-{
- int s;
- uvlong m;
-
- s = multiplier(d, 32 - 1, &m);
- *mp = m;
- *sp = s;
- if(m >= T31)
- return 1;
- else
- return 0;
-}
-
-int
-udiv(uint32 d, uint32 *mp, int *sp, int *pp)
-{
- int p, s;
- uvlong m;
-
- s = multiplier(d, 32, &m);
- p = 0;
- if(m >= T32) {
- while((d & 1) == 0) {
- d >>= 1;
- p++;
- }
- s = multiplier(d, 32 - p, &m);
- }
- *mp = m;
- *pp = p;
- if(m >= T32) {
- /*assert(p == 0);*/
- *sp = s - 1;
- return 1;
- }
- else {
- *sp = s;
- return 0;
- }
-}
-
-void
-sdivgen(Node *l, Node *r, Node *ax, Node *dx)
-{
- int a, s;
- uint32 m;
- vlong c;
-
- c = r->vconst;
- if(c < 0)
- c = -c;
- a = sdiv(c, &m, &s);
-//print("a=%d i=%d s=%d m=%ux\n", a, (long)r->vconst, s, m);
- gins(AMOVL, nodconst(m), ax);
- gins(AIMULL, l, Z);
- gins(AMOVL, l, ax);
- if(a)
- gins(AADDL, ax, dx);
- gins(ASHRL, nodconst(31), ax);
- gins(ASARL, nodconst(s), dx);
- gins(AADDL, ax, dx);
- if(r->vconst < 0)
- gins(ANEGL, Z, dx);
-}
-
-void
-udivgen(Node *l, Node *r, Node *ax, Node *dx)
-{
- int a, s, t;
- uint32 m;
- Node nod;
-
- a = udiv(r->vconst, &m, &s, &t);
-//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (long)r->vconst, t, s, m);
- if(t != 0) {
- gins(AMOVL, l, ax);
- gins(ASHRL, nodconst(t), ax);
- gins(AMOVL, nodconst(m), dx);
- gins(AMULL, dx, Z);
- }
- else if(a) {
- if(l->op != OREGISTER) {
- regalloc(&nod, l, Z);
- gins(AMOVL, l, &nod);
- l = &nod;
- }
- gins(AMOVL, nodconst(m), ax);
- gins(AMULL, l, Z);
- gins(AADDL, l, dx);
- gins(ARCRL, nodconst(1), dx);
- if(l == &nod)
- regfree(l);
- }
- else {
- gins(AMOVL, nodconst(m), ax);
- gins(AMULL, l, Z);
- }
- if(s != 0)
- gins(ASHRL, nodconst(s), dx);
-}
-
-void
-sext(Node *d, Node *s, Node *l)
-{
- if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
- reg[D_DX]++;
- gins(ACDQ, Z, Z);
- }
- else {
- regalloc(d, l, Z);
- gins(AMOVL, s, d);
- gins(ASARL, nodconst(31), d);
- }
-}
-
-void
-sdiv2(int32 c, int v, Node *l, Node *n)
-{
- Node nod;
-
- if(v > 0) {
- if(v > 1) {
- sext(&nod, n, l);
- gins(AANDL, nodconst((1 << v) - 1), &nod);
- gins(AADDL, &nod, n);
- regfree(&nod);
- }
- else {
- gins(ACMPL, n, nodconst(0x80000000));
- gins(ASBBL, nodconst(-1), n);
- }
- gins(ASARL, nodconst(v), n);
- }
- if(c < 0)
- gins(ANEGL, Z, n);
-}
-
-void
-smod2(int32 c, int v, Node *l, Node *n)
-{
- Node nod;
-
- if(c == 1) {
- zeroregm(n);
- return;
- }
-
- sext(&nod, n, l);
- if(v == 0) {
- zeroregm(n);
- gins(AXORL, &nod, n);
- gins(ASUBL, &nod, n);
- }
- else if(v > 1) {
- gins(AANDL, nodconst((1 << v) - 1), &nod);
- gins(AADDL, &nod, n);
- gins(AANDL, nodconst((1 << v) - 1), n);
- gins(ASUBL, &nod, n);
- }
- else {
- gins(AANDL, nodconst(1), n);
- gins(AXORL, &nod, n);
- gins(ASUBL, &nod, n);
- }
- regfree(&nod);
-}
diff --git a/src/cmd/6c/doc.go b/src/cmd/6c/doc.go
deleted file mode 100644
index e0a22e78b..000000000
--- a/src/cmd/6c/doc.go
+++ /dev/null
@@ -1,16 +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.
-
-// +build ignore
-
-/*
-
-6c is a version of the Plan 9 C compiler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/8c
-
-Its target architecture is the x86-64, referred to by these tools as amd64.
-
-*/
-package main
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
deleted file mode 100644
index aa9d95d21..000000000
--- a/src/cmd/6c/gc.h
+++ /dev/null
@@ -1,359 +0,0 @@
-// Inferno utils/6c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "../cc/cc.h"
-#include "../6l/6.out.h"
-
-/*
- * 6c/amd64
- * Intel 386 with AMD64 extensions
- */
-#define SZ_CHAR 1
-#define SZ_SHORT 2
-#define SZ_INT 4
-#define SZ_LONG 4
-#define SZ_IND 8
-#define SZ_FLOAT 4
-#define SZ_VLONG 8
-#define SZ_DOUBLE 8
-#define FNX 100
-
-typedef struct Case Case;
-typedef struct C1 C1;
-typedef struct Reg Reg;
-typedef struct Rgn Rgn;
-typedef struct Renv Renv;
-
-EXTERN struct
-{
- Node* regtree;
- Node* basetree;
- short scale;
- short reg;
- short ptr;
-} idx;
-
-#define INDEXED 9
-
-#define A ((Addr*)0)
-#define P ((Prog*)0)
-
-struct Case
-{
- Case* link;
- vlong val;
- int32 label;
- char def;
- char isv;
-};
-#define C ((Case*)0)
-
-struct C1
-{
- vlong val;
- int32 label;
-};
-
-struct Reg
-{
- int32 pc;
- int32 rpo; /* reverse post ordering */
-
- Bits set;
- Bits use1;
- Bits use2;
-
- Bits refbehind;
- Bits refahead;
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- int32 regu;
- int32 loop; /* could be shorter */
-
- Reg* log5;
- int32 active;
-
- Reg* p1;
- Reg* p2;
- Reg* p2link;
- Reg* s1;
- Reg* s2;
- Reg* link;
- Prog* prog;
-};
-#define R ((Reg*)0)
-
-struct Renv
-{
- int safe;
- Node base;
- Node* saved;
- Node* scope;
-};
-
-#define NRGN 600
-struct Rgn
-{
- Reg* enter;
- short cost;
- short varno;
- short regno;
-};
-
-EXTERN int32 breakpc;
-EXTERN int32 nbreak;
-EXTERN Case* cases;
-EXTERN Node constnode;
-EXTERN Node fconstnode;
-EXTERN Node vconstnode;
-EXTERN int32 continpc;
-EXTERN int32 curarg;
-EXTERN int32 cursafe;
-EXTERN Prog* lastp;
-EXTERN int32 maxargsafe;
-EXTERN int mnstring;
-EXTERN Node* nodrat;
-EXTERN Node* nodret;
-EXTERN Node* nodsafe;
-EXTERN int32 nrathole;
-EXTERN int32 nstring;
-EXTERN Prog* p;
-EXTERN int32 pc;
-EXTERN Node lregnode;
-EXTERN Node qregnode;
-EXTERN char string[NSNAME];
-EXTERN Sym* symrathole;
-EXTERN Node znode;
-EXTERN Prog zprog;
-EXTERN int reg[D_NONE];
-EXTERN int32 exregoffset;
-EXTERN int32 exfregoffset;
-EXTERN uchar typechlpv[NTYPE];
-
-#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
-#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
-#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
-#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
-
-#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
-
-#define CLOAD 5
-#define CREF 5
-#define CINF 1000
-#define LOOP 3
-
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-
-EXTERN int32 regbits;
-EXTERN int32 exregbits;
-
-EXTERN int change;
-EXTERN int suppress;
-
-EXTERN Reg* firstr;
-EXTERN Reg* lastr;
-EXTERN Reg zreg;
-EXTERN Reg* freer;
-EXTERN int32* idom;
-EXTERN Reg** rpo2r;
-EXTERN int32 maxnr;
-
-extern char* anames[];
-
-/*
- * sgen.c
- */
-void codgen(Node*, Node*);
-void gen(Node*);
-void noretval(int);
-void usedset(Node*, int);
-void xcom(Node*);
-void indx(Node*);
-int bcomplex(Node*, Node*);
-Prog* gtext(Sym*, int32);
-vlong argsize(int);
-
-/*
- * cgen.c
- */
-void zeroregm(Node*);
-void cgen(Node*, Node*);
-void reglcgen(Node*, Node*, Node*);
-void lcgen(Node*, Node*);
-void bcgen(Node*, int);
-void boolgen(Node*, int, Node*);
-void sugen(Node*, Node*, int32);
-int needreg(Node*, int);
-int hardconst(Node*);
-int immconst(Node*);
-
-/*
- * txt.c
- */
-void ginit(void);
-void gclean(void);
-void nextpc(void);
-void gargs(Node*, Node*, Node*);
-void garg1(Node*, Node*, Node*, int, Node**);
-Node* nodconst(int32);
-Node* nodfconst(double);
-Node* nodgconst(vlong, Type*);
-int nodreg(Node*, Node*, int);
-int isreg(Node*, int);
-void regret(Node*, Node*, Type*, int);
-void regalloc(Node*, Node*, Node*);
-void regfree(Node*);
-void regialloc(Node*, Node*, Node*);
-void regsalloc(Node*, Node*);
-void regaalloc1(Node*, Node*);
-void regaalloc(Node*, Node*);
-void regind(Node*, Node*);
-void gprep(Node*, Node*);
-void naddr(Node*, Addr*);
-void gcmp(int, Node*, vlong);
-void gmove(Node*, Node*);
-void gins(int a, Node*, Node*);
-void gopcode(int, Type*, Node*, Node*);
-int samaddr(Node*, Node*);
-void gbranch(int);
-void patch(Prog*, int32);
-int sconst(Node*);
-void gpseudo(int, Sym*, Node*);
-void gprefetch(Node*);
-void gpcdata(int, int);
-
-/*
- * swt.c
- */
-int swcmp(const void*, const void*);
-void doswit(Node*);
-void swit1(C1*, int, int32, Node*);
-void swit2(C1*, int, int32, Node*);
-void newcase(void);
-void bitload(Node*, Node*, Node*, Node*, Node*);
-void bitstore(Node*, Node*, Node*, Node*, Node*);
-int32 outstring(char*, int32);
-void nullwarn(Node*, Node*);
-void sextern(Sym*, Node*, int32, int32);
-void gextern(Sym*, Node*, int32, int32);
-void outcode(void);
-
-/*
- * list
- */
-void listinit(void);
-
-/*
- * reg.c
- */
-Reg* rega(void);
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Addr*);
-void prop(Reg*, Bits, Bits);
-void loopit(Reg*, int32);
-void synch(Reg*, Bits);
-uint32 allreg(uint32, Rgn*);
-void paint1(Reg*, int);
-uint32 paint2(Reg*, int);
-void paint3(Reg*, int, int32, int);
-void addreg(Addr*, int);
-
-/*
- * peep.c
- */
-void peep(void);
-void excise(Reg*);
-Reg* uniqp(Reg*);
-Reg* uniqs(Reg*);
-int regtyp(Addr*);
-int anyvar(Addr*);
-int subprop(Reg*);
-int copyprop(Reg*);
-int copy1(Addr*, Addr*, Reg*, int);
-int copyu(Prog*, Addr*, Addr*);
-
-int copyas(Addr*, Addr*);
-int copyau(Addr*, Addr*);
-int copysub(Addr*, Addr*, Addr*, int);
-int copysub1(Prog*, Addr*, Addr*, int);
-
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
-
-#define D_HI D_NONE
-#define D_LO D_NONE
-
-/*
- * bound
- */
-void comtarg(void);
-
-/*
- * com64
- */
-int cond(int);
-int com64(Node*);
-void com64init(void);
-void bool64(Node*);
-int32 lo64v(Node*);
-int32 hi64v(Node*);
-Node* lo64(Node*);
-Node* hi64(Node*);
-
-/*
- * div/mul
- */
-void sdivgen(Node*, Node*, Node*, Node*);
-void udivgen(Node*, Node*, Node*, Node*);
-void sdiv2(int32, int, Node*, Node*);
-void smod2(int32, int, Node*, Node*);
-void mulgen(Type*, Node*, Node*);
-void genmuladd(Node*, Node*, int, Node*);
-void shiftit(Type*, Node*, Node*);
-
-#define D_X7 (D_X0+7)
-
-void fgopcode(int, Node*, Node*, int, int);
diff --git a/src/cmd/6c/list.c b/src/cmd/6c/list.c
deleted file mode 100644
index 28f5b8df7..000000000
--- a/src/cmd/6c/list.c
+++ /dev/null
@@ -1,38 +0,0 @@
-// Inferno utils/6c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#define EXTERN
-#include "gc.h"
-
-void
-listinit(void)
-{
- listinit6();
-}
diff --git a/src/cmd/6c/machcap.c b/src/cmd/6c/machcap.c
deleted file mode 100644
index 820d9a0aa..000000000
--- a/src/cmd/6c/machcap.c
+++ /dev/null
@@ -1,107 +0,0 @@
-// Inferno utils/6c/machcap.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/machcap.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-int
-machcap(Node *n)
-{
-
- if(n == Z)
- return 1; /* test */
-
- switch(n->op) {
- case OMUL:
- case OLMUL:
- case OASMUL:
- case OASLMUL:
- if(typechl[n->type->etype])
- return 1;
- if(typev[n->type->etype])
- return 1;
- break;
-
- case OCOM:
- case ONEG:
- case OADD:
- case OAND:
- case OOR:
- case OSUB:
- case OXOR:
- case OASHL:
- case OLSHR:
- case OASHR:
- if(typechlv[n->left->type->etype])
- return 1;
- break;
-
- case OCAST:
- return 1;
-
- case OCOND:
- case OCOMMA:
- case OLIST:
- case OANDAND:
- case OOROR:
- case ONOT:
- return 1;
-
- case OASADD:
- case OASSUB:
- case OASAND:
- case OASOR:
- case OASXOR:
- return 1;
-
- case OASASHL:
- case OASASHR:
- case OASLSHR:
- return 1;
-
- case OPOSTINC:
- case OPOSTDEC:
- case OPREINC:
- case OPREDEC:
- return 1;
-
- case OEQ:
- case ONE:
- case OLE:
- case OGT:
- case OLT:
- case OGE:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- return 1;
- }
- return 0;
-}
diff --git a/src/cmd/6c/mul.c b/src/cmd/6c/mul.c
deleted file mode 100644
index 510edc05c..000000000
--- a/src/cmd/6c/mul.c
+++ /dev/null
@@ -1,458 +0,0 @@
-// Inferno utils/6c/mul.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/mul.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-typedef struct Malg Malg;
-typedef struct Mparam Mparam;
-
-struct Malg
-{
- schar vals[10];
-};
-
-struct Mparam
-{
- uint32 value;
- schar alg;
- char neg;
- char shift;
- char arg;
- schar off;
-};
-
-static Mparam multab[32];
-static int mulptr;
-
-static Malg malgs[] =
-{
- {0, 100},
- {-1, 1, 100},
- {-9, -5, -3, 3, 5, 9, 100},
- {6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
- {-8, -4, -2, 2, 4, 8, 100},
-};
-
-/*
- * return position of lowest 1
- */
-int
-lowbit(uint32 v)
-{
- int s, i;
- uint32 m;
-
- s = 0;
- m = 0xFFFFFFFFUL;
- for(i = 16; i > 0; i >>= 1) {
- m >>= i;
- if((v & m) == 0) {
- v >>= i;
- s += i;
- }
- }
- return s;
-}
-
-void
-genmuladd(Node *d, Node *s, int m, Node *a)
-{
- Node nod;
-
- nod.op = OINDEX;
- nod.left = a;
- nod.right = s;
- nod.scale = m;
- nod.type = types[TIND];
- nod.xoffset = 0;
- xcom(&nod);
- gopcode(OADDR, d->type, &nod, d);
-}
-
-void
-mulparam(uint32 m, Mparam *mp)
-{
- int c, i, j, n, o, q, s;
- int bc, bi, bn, bo, bq, bs, bt;
- schar *p;
- int32 u;
- uint32 t;
-
- bc = bq = 10;
- bi = bn = bo = bs = bt = 0;
- for(i = 0; i < nelem(malgs); i++) {
- for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
- for(s = 0; s < 2; s++) {
- c = 10;
- q = 10;
- u = m - o;
- if(u == 0)
- continue;
- if(s) {
- o = -o;
- if(o > 0)
- continue;
- u = -u;
- }
- n = lowbit(u);
- t = (uint32)u >> n;
- switch(i) {
- case 0:
- if(t == 1) {
- c = s + 1;
- q = 0;
- break;
- }
- switch(t) {
- case 3:
- case 5:
- case 9:
- c = s + 1;
- if(n)
- c++;
- q = 0;
- break;
- }
- if(s)
- break;
- switch(t) {
- case 15:
- case 25:
- case 27:
- case 45:
- case 81:
- c = 2;
- if(n)
- c++;
- q = 1;
- break;
- }
- break;
- case 1:
- if(t == 1) {
- c = 3;
- q = 3;
- break;
- }
- switch(t) {
- case 3:
- case 5:
- case 9:
- c = 3;
- q = 2;
- break;
- }
- break;
- case 2:
- if(t == 1) {
- c = 3;
- q = 2;
- break;
- }
- break;
- case 3:
- if(s)
- break;
- if(t == 1) {
- c = 3;
- q = 1;
- break;
- }
- break;
- case 4:
- if(t == 1) {
- c = 3;
- q = 0;
- break;
- }
- break;
- }
- if(c < bc || (c == bc && q > bq)) {
- bc = c;
- bi = i;
- bn = n;
- bo = o;
- bq = q;
- bs = s;
- bt = t;
- }
- }
- }
- mp->value = m;
- if(bc <= 3) {
- mp->alg = bi;
- mp->shift = bn;
- mp->off = bo;
- mp->neg = bs;
- mp->arg = bt;
- }
- else
- mp->alg = -1;
-}
-
-int
-m0(int a)
-{
- switch(a) {
- case -2:
- case 2:
- return 2;
- case -3:
- case 3:
- return 2;
- case -4:
- case 4:
- return 4;
- case -5:
- case 5:
- return 4;
- case 6:
- return 2;
- case -8:
- case 8:
- return 8;
- case -9:
- case 9:
- return 8;
- case 10:
- return 4;
- case 12:
- return 2;
- case 15:
- return 2;
- case 18:
- return 8;
- case 20:
- return 4;
- case 24:
- return 2;
- case 25:
- return 4;
- case 27:
- return 2;
- case 36:
- return 8;
- case 40:
- return 4;
- case 45:
- return 4;
- case 72:
- return 8;
- case 81:
- return 8;
- }
- diag(Z, "bad m0");
- return 0;
-}
-
-int
-m1(int a)
-{
- switch(a) {
- case 15:
- return 4;
- case 25:
- return 4;
- case 27:
- return 8;
- case 45:
- return 8;
- case 81:
- return 8;
- }
- diag(Z, "bad m1");
- return 0;
-}
-
-int
-m2(int a)
-{
- switch(a) {
- case 6:
- return 2;
- case 10:
- return 2;
- case 12:
- return 4;
- case 18:
- return 2;
- case 20:
- return 4;
- case 24:
- return 8;
- case 36:
- return 4;
- case 40:
- return 8;
- case 72:
- return 8;
- }
- diag(Z, "bad m2");
- return 0;
-}
-
-void
-shiftit(Type *t, Node *s, Node *d)
-{
- int32 c;
-
- c = (int32)s->vconst & 31;
- switch(c) {
- case 0:
- break;
- case 1:
- gopcode(OADD, t, d, d);
- break;
- default:
- gopcode(OASHL, t, s, d);
- }
-}
-
-static int
-mulgen1(uint32 v, Node *n)
-{
- int i, o;
- Mparam *p;
- Node nod, nods;
-
- for(i = 0; i < nelem(multab); i++) {
- p = &multab[i];
- if(p->value == v)
- goto found;
- }
-
- p = &multab[mulptr];
- if(++mulptr == nelem(multab))
- mulptr = 0;
-
- mulparam(v, p);
-
-found:
-// print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
- if(p->alg < 0)
- return 0;
-
- nods = *nodconst(p->shift);
-
- o = OADD;
- if(p->alg > 0) {
- regalloc(&nod, n, Z);
- if(p->off < 0)
- o = OSUB;
- }
-
- switch(p->alg) {
- case 0:
- switch(p->arg) {
- case 1:
- shiftit(n->type, &nods, n);
- break;
- case 15:
- case 25:
- case 27:
- case 45:
- case 81:
- genmuladd(n, n, m1(p->arg), n);
- /* fall thru */
- case 3:
- case 5:
- case 9:
- genmuladd(n, n, m0(p->arg), n);
- shiftit(n->type, &nods, n);
- break;
- default:
- goto bad;
- }
- if(p->neg == 1)
- gins(ANEGL, Z, n);
- break;
- case 1:
- switch(p->arg) {
- case 1:
- gmove(n, &nod);
- shiftit(n->type, &nods, &nod);
- break;
- case 3:
- case 5:
- case 9:
- genmuladd(&nod, n, m0(p->arg), n);
- shiftit(n->type, &nods, &nod);
- break;
- default:
- goto bad;
- }
- if(p->neg)
- gopcode(o, n->type, &nod, n);
- else {
- gopcode(o, n->type, n, &nod);
- gmove(&nod, n);
- }
- break;
- case 2:
- genmuladd(&nod, n, m0(p->off), n);
- shiftit(n->type, &nods, n);
- goto comop;
- case 3:
- genmuladd(&nod, n, m0(p->off), n);
- shiftit(n->type, &nods, n);
- genmuladd(n, &nod, m2(p->off), n);
- break;
- case 4:
- genmuladd(&nod, n, m0(p->off), nodconst(0));
- shiftit(n->type, &nods, n);
- goto comop;
- default:
- diag(Z, "bad mul alg");
- break;
- comop:
- if(p->neg) {
- gopcode(o, n->type, n, &nod);
- gmove(&nod, n);
- }
- else
- gopcode(o, n->type, &nod, n);
- }
-
- if(p->alg > 0)
- regfree(&nod);
-
- return 1;
-
-bad:
- diag(Z, "mulgen botch");
- return 1;
-}
-
-void
-mulgen(Type *t, Node *r, Node *n)
-{
- if(!mulgen1(r->vconst, n))
- gopcode(OMUL, t, r, n);
-}
diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c
deleted file mode 100644
index a11067c84..000000000
--- a/src/cmd/6c/peep.c
+++ /dev/null
@@ -1,902 +0,0 @@
-// Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-static int
-needc(Prog *p)
-{
- while(p != P) {
- switch(p->as) {
- case AADCL:
- case AADCQ:
- case ASBBL:
- case ASBBQ:
- case ARCRL:
- case ARCRQ:
- return 1;
- case AADDL:
- case AADDQ:
- case ASUBL:
- case ASUBQ:
- case AJMP:
- case ARET:
- case ACALL:
- return 0;
- default:
- if(p->to.type == D_BRANCH)
- return 0;
- }
- p = p->link;
- }
- return 0;
-}
-
-static Reg*
-rnops(Reg *r)
-{
- Prog *p;
- Reg *r1;
-
- if(r != R)
- for(;;){
- p = r->prog;
- if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
- break;
- r1 = uniqs(r);
- if(r1 == R)
- break;
- r = r1;
- }
- return r;
-}
-
-void
-peep(void)
-{
- Reg *r, *r1, *r2;
- Prog *p, *p1;
- int t;
-
- /*
- * complete R structure
- */
- t = 0;
- for(r=firstr; r!=R; r=r1) {
- r1 = r->link;
- if(r1 == R)
- break;
- p = r->prog->link;
- while(p != r1->prog)
- switch(p->as) {
- default:
- r2 = rega();
- r->link = r2;
- r2->link = r1;
-
- r2->prog = p;
- r2->p1 = r;
- r->s1 = r2;
- r2->s1 = r1;
- r1->p1 = r2;
-
- r = r2;
- t++;
-
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- p = p->link;
- }
- }
-
- pc = 0; /* speculating it won't kill */
-
-loop1:
-
- t = 0;
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AMOVL:
- case AMOVQ:
- case AMOVSS:
- case AMOVSD:
- if(regtyp(&p->to))
- if(regtyp(&p->from)) {
- if(copyprop(r)) {
- excise(r);
- t++;
- } else
- if(subprop(r) && copyprop(r)) {
- excise(r);
- t++;
- }
- }
- break;
-
- case AMOVBLZX:
- case AMOVWLZX:
- case AMOVBLSX:
- case AMOVWLSX:
- if(regtyp(&p->to)) {
- r1 = rnops(uniqs(r));
- if(r1 != R) {
- p1 = r1->prog;
- if(p->as == p1->as && p->to.type == p1->from.type){
- p1->as = AMOVL;
- t++;
- }
- }
- }
- break;
-
- case AMOVBQSX:
- case AMOVBQZX:
- case AMOVWQSX:
- case AMOVWQZX:
- case AMOVLQSX:
- case AMOVLQZX:
- if(regtyp(&p->to)) {
- r1 = rnops(uniqs(r));
- if(r1 != R) {
- p1 = r1->prog;
- if(p->as == p1->as && p->to.type == p1->from.type){
- p1->as = AMOVQ;
- t++;
- }
- }
- }
- break;
-
- case AADDL:
- case AADDQ:
- case AADDW:
- if(p->from.type != D_CONST || needc(p->link))
- break;
- if(p->from.offset == -1){
- if(p->as == AADDQ)
- p->as = ADECQ;
- else if(p->as == AADDL)
- p->as = ADECL;
- else
- p->as = ADECW;
- p->from = zprog.from;
- }
- else if(p->from.offset == 1){
- if(p->as == AADDQ)
- p->as = AINCQ;
- else if(p->as == AADDL)
- p->as = AINCL;
- else
- p->as = AINCW;
- p->from = zprog.from;
- }
- break;
-
- case ASUBL:
- case ASUBQ:
- case ASUBW:
- if(p->from.type != D_CONST || needc(p->link))
- break;
- if(p->from.offset == -1) {
- if(p->as == ASUBQ)
- p->as = AINCQ;
- else if(p->as == ASUBL)
- p->as = AINCL;
- else
- p->as = AINCW;
- p->from = zprog.from;
- }
- else if(p->from.offset == 1){
- if(p->as == ASUBQ)
- p->as = ADECQ;
- else if(p->as == ASUBL)
- p->as = ADECL;
- else
- p->as = ADECW;
- p->from = zprog.from;
- }
- break;
- }
- }
- if(t)
- goto loop1;
-}
-
-void
-excise(Reg *r)
-{
- Prog *p;
-
- p = r->prog;
- p->as = ANOP;
- p->from = zprog.from;
- p->to = zprog.to;
-}
-
-Reg*
-uniqp(Reg *r)
-{
- Reg *r1;
-
- r1 = r->p1;
- if(r1 == R) {
- r1 = r->p2;
- if(r1 == R || r1->p2link != R)
- return R;
- } else
- if(r->p2 != R)
- return R;
- return r1;
-}
-
-Reg*
-uniqs(Reg *r)
-{
- Reg *r1;
-
- r1 = r->s1;
- if(r1 == R) {
- r1 = r->s2;
- if(r1 == R)
- return R;
- } else
- if(r->s2 != R)
- return R;
- return r1;
-}
-
-int
-regtyp(Addr *a)
-{
- int t;
-
- t = a->type;
- if(t >= D_AX && t <= D_R15)
- return 1;
- if(t >= D_X0 && t <= D_X0+15)
- return 1;
- return 0;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-int
-subprop(Reg *r0)
-{
- Prog *p;
- Addr *v1, *v2;
- Reg *r;
- int t;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case ACALL:
- return 0;
-
- case AIMULL:
- case AIMULQ:
- case AIMULW:
- if(p->to.type != D_NONE)
- break;
- goto giveup;
-
- case AROLB:
- case AROLL:
- case AROLQ:
- case AROLW:
- case ARORB:
- case ARORL:
- case ARORQ:
- case ARORW:
- case ASALB:
- case ASALL:
- case ASALQ:
- case ASALW:
- case ASARB:
- case ASARL:
- case ASARQ:
- case ASARW:
- case ASHLB:
- case ASHLL:
- case ASHLQ:
- case ASHLW:
- case ASHRB:
- case ASHRL:
- case ASHRQ:
- case ASHRW:
- if(p->from.type == D_CONST)
- break;
- goto giveup;
-
- case ADIVB:
- case ADIVL:
- case ADIVQ:
- case ADIVW:
- case AIDIVB:
- case AIDIVL:
- case AIDIVQ:
- case AIDIVW:
- case AIMULB:
- case AMULB:
- case AMULL:
- case AMULQ:
- case AMULW:
-
- case AREP:
- case AREPN:
-
- case ACWD:
- case ACDQ:
- case ACQO:
-
- case ASTOSB:
- case ASTOSL:
- case ASTOSQ:
- case AMOVSB:
- case AMOVSL:
- case AMOVSQ:
- case AMOVQL:
- giveup:
- return 0;
-
- case AMOVL:
- case AMOVQ:
- if(p->to.type == v1->type)
- goto gotit;
- break;
- }
- if(copyau(&p->from, v2) ||
- copyau(&p->to, v2))
- break;
- if(copysub(&p->from, v1, v2, 0) ||
- copysub(&p->to, v1, v2, 0))
- break;
- }
- return 0;
-
-gotit:
- copysub(&p->to, v1, v2, 1);
- if(debug['P']) {
- print("gotit: %D->%D\n%P", v1, v2, r->prog);
- if(p->from.type == v2->type)
- print(" excise");
- print("\n");
- }
- for(r=uniqs(r); r!=r0; r=uniqs(r)) {
- p = r->prog;
- copysub(&p->from, v1, v2, 1);
- copysub(&p->to, v1, v2, 1);
- if(debug['P'])
- print("%P\n", r->prog);
- }
- t = v1->type;
- v1->type = v2->type;
- v2->type = t;
- if(debug['P'])
- print("%P last\n", r->prog);
- return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
-int
-copyprop(Reg *r0)
-{
- Prog *p;
- Addr *v1, *v2;
- Reg *r;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Addr *v1, Addr *v2, Reg *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, A);
- switch(t) {
- case 2: /* rar, can't split */
- if(debug['P'])
- print("; %D rar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %D set; return 1\n", v2);
- return 1;
-
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %D used+set and f=%d; return 0\n", v2, f);
- else
- print("; %D used and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub %D/%D", v2, v1);
- if(t == 4) {
- if(debug['P'])
- print("; %D used+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, A);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %D set and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-int
-copyu(Prog *p, Addr *v, Addr *s)
-{
-
- switch(p->as) {
-
- default:
- if(debug['P'])
- print("unknown op %A\n", p->as);
- /* SBBL; ADCL; FLD1; SAHF */
- return 2;
-
-
- case ANEGB:
- case ANEGW:
- case ANEGL:
- case ANEGQ:
- case ANOTB:
- case ANOTW:
- case ANOTL:
- case ANOTQ:
- if(copyas(&p->to, v))
- return 2;
- break;
-
- case ALEAL: /* lhs addr, rhs store */
- case ALEAQ:
- if(copyas(&p->from, v))
- return 2;
-
-
- case ANOP: /* rhs store */
- case AMOVL:
- case AMOVQ:
- case AMOVBLSX:
- case AMOVBLZX:
- case AMOVBQSX:
- case AMOVBQZX:
- case AMOVLQSX:
- case AMOVLQZX:
- case AMOVWLSX:
- case AMOVWLZX:
- case AMOVWQSX:
- case AMOVWQZX:
- case AMOVQL:
-
- case AMOVSS:
- case AMOVSD:
- case ACVTSD2SL:
- case ACVTSD2SQ:
- case ACVTSD2SS:
- case ACVTSL2SD:
- case ACVTSL2SS:
- case ACVTSQ2SD:
- case ACVTSQ2SS:
- case ACVTSS2SD:
- case ACVTSS2SL:
- case ACVTSS2SQ:
- case ACVTTSD2SL:
- case ACVTTSD2SQ:
- case ACVTTSS2SL:
- case ACVTTSS2SQ:
- if(copyas(&p->to, v)) {
- if(s != A)
- return copysub(&p->from, v, s, 1);
- if(copyau(&p->from, v))
- return 4;
- return 3;
- }
- goto caseread;
-
- case AROLB:
- case AROLL:
- case AROLQ:
- case AROLW:
- case ARORB:
- case ARORL:
- case ARORQ:
- case ARORW:
- case ASALB:
- case ASALL:
- case ASALQ:
- case ASALW:
- case ASARB:
- case ASARL:
- case ASARQ:
- case ASARW:
- case ASHLB:
- case ASHLL:
- case ASHLQ:
- case ASHLW:
- case ASHRB:
- case ASHRL:
- case ASHRQ:
- case ASHRW:
- if(copyas(&p->to, v))
- return 2;
- if(copyas(&p->from, v))
- if(p->from.type == D_CX)
- return 2;
- goto caseread;
-
- case AADDB: /* rhs rar */
- case AADDL:
- case AADDQ:
- case AADDW:
- case AANDB:
- case AANDL:
- case AANDQ:
- case AANDW:
- case ADECL:
- case ADECQ:
- case ADECW:
- case AINCL:
- case AINCQ:
- case AINCW:
- case ASUBB:
- case ASUBL:
- case ASUBQ:
- case ASUBW:
- case AORB:
- case AORL:
- case AORQ:
- case AORW:
- case AXORB:
- case AXORL:
- case AXORQ:
- case AXORW:
- case AMOVB:
- case AMOVW:
-
- case AADDSD:
- case AADDSS:
- case ACMPSD:
- case ACMPSS:
- case ADIVSD:
- case ADIVSS:
- case AMAXSD:
- case AMAXSS:
- case AMINSD:
- case AMINSS:
- case AMULSD:
- case AMULSS:
- case ARCPSS:
- case ARSQRTSS:
- case ASQRTSD:
- case ASQRTSS:
- case ASUBSD:
- case ASUBSS:
- case AXORPD:
- if(copyas(&p->to, v))
- return 2;
- goto caseread;
-
- case ACMPL: /* read only */
- case ACMPW:
- case ACMPB:
- case ACMPQ:
-
- case APREFETCHT0:
- case APREFETCHT1:
- case APREFETCHT2:
- case APREFETCHNTA:
-
- case ACOMISD:
- case ACOMISS:
- case AUCOMISD:
- case AUCOMISS:
- caseread:
- if(s != A) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return copysub(&p->to, v, s, 1);
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- break;
-
- case AJGE: /* no reference */
- case AJNE:
- case AJLE:
- case AJEQ:
- case AJHI:
- case AJLS:
- case AJMI:
- case AJPL:
- case AJGT:
- case AJLT:
- case AJCC:
- case AJCS:
-
- case AADJSP:
- case AWAIT:
- case ACLD:
- break;
-
- case AIMULL:
- case AIMULQ:
- case AIMULW:
- if(p->to.type != D_NONE) {
- if(copyas(&p->to, v))
- return 2;
- goto caseread;
- }
-
- case ADIVB:
- case ADIVL:
- case ADIVQ:
- case ADIVW:
- case AIDIVB:
- case AIDIVL:
- case AIDIVQ:
- case AIDIVW:
- case AIMULB:
- case AMULB:
- case AMULL:
- case AMULQ:
- case AMULW:
-
- case ACWD:
- case ACDQ:
- case ACQO:
- if(v->type == D_AX || v->type == D_DX)
- return 2;
- goto caseread;
-
- case AREP:
- case AREPN:
- if(v->type == D_CX)
- return 2;
- goto caseread;
-
- case AMOVSB:
- case AMOVSL:
- case AMOVSQ:
- if(v->type == D_DI || v->type == D_SI)
- return 2;
- goto caseread;
-
- case ASTOSB:
- case ASTOSL:
- case ASTOSQ:
- if(v->type == D_AX || v->type == D_DI)
- return 2;
- goto caseread;
-
- case AJMP: /* funny */
- if(s != A) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ARET: /* funny */
- if(v->type == REGRET || v->type == FREGRET)
- return 2;
- if(s != A)
- return 1;
- return 3;
-
- case ACALL: /* funny */
- if(REGARG >= 0 && v->type == (uchar)REGARG)
- return 2;
-
- if(s != A) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 4;
- return 3;
-
- case ATEXT: /* funny */
- if(REGARG >= 0 && v->type == (uchar)REGARG)
- return 3;
- return 0;
- }
- return 0;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-int
-copyas(Addr *a, Addr *v)
-{
- if(a->type != v->type)
- return 0;
- if(regtyp(v))
- return 1;
- if(v->type == D_AUTO || v->type == D_PARAM)
- if(v->offset == a->offset)
- return 1;
- return 0;
-}
-
-/*
- * either direct or indirect
- */
-int
-copyau(Addr *a, Addr *v)
-{
-
- if(copyas(a, v))
- return 1;
- if(regtyp(v)) {
- if(a->type-D_INDIR == v->type)
- return 1;
- if(a->index == v->type)
- return 1;
- }
- return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-int
-copysub(Addr *a, Addr *v, Addr *s, int f)
-{
- int t;
-
- if(copyas(a, v)) {
- t = s->type;
- if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
- if(f)
- a->type = t;
- }
- 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)
- return 1; /* can't use BP-base with index */
- if(f)
- a->type = s->type+D_INDIR;
-// return 0;
- }
- if(a->index == t) {
- if(f)
- a->index = s->type;
- return 0;
- }
- return 0;
- }
- return 0;
-}
diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c
deleted file mode 100644
index 6f8d3ce14..000000000
--- a/src/cmd/6c/reg.c
+++ /dev/null
@@ -1,1523 +0,0 @@
-// Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-static void fixjmp(Reg*);
-
-Reg*
-rega(void)
-{
- Reg *r;
-
- r = freer;
- if(r == R) {
- r = alloc(sizeof(*r));
- } else
- freer = r->link;
-
- *r = zreg;
- return r;
-}
-
-int
-rcmp(const void *a1, const void *a2)
-{
- Rgn *p1, *p2;
- int c1, c2;
-
- p1 = (Rgn*)a1;
- p2 = (Rgn*)a2;
- c1 = p2->cost;
- c2 = p1->cost;
- if(c1 -= c2)
- return c1;
- return p2->varno - p1->varno;
-}
-
-void
-regopt(Prog *p)
-{
- Reg *r, *r1, *r2;
- Prog *p1;
- int i, z;
- int32 initpc, val, npc;
- uint32 vreg;
- Bits bit;
- struct
- {
- int32 m;
- int32 c;
- Reg* p;
- } log5[6], *lp;
-
- firstr = R;
- lastr = R;
- nvar = 0;
- regbits = RtoB(D_SP) | RtoB(D_AX) | RtoB(D_X0);
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- }
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- val = 5L * 5L * 5L * 5L * 5L;
- lp = log5;
- for(i=0; i<5; i++) {
- lp->m = val;
- lp->c = 0;
- lp->p = R;
- val /= 5L;
- lp++;
- }
- val = 0;
- for(; p != P; p = p->link) {
- switch(p->as) {
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- case AFUNCDATA:
- continue;
- }
- r = rega();
- if(firstr == R) {
- firstr = r;
- lastr = r;
- } else {
- lastr->link = r;
- r->p1 = lastr;
- lastr->s1 = r;
- lastr = r;
- }
- r->prog = p;
- r->pc = val;
- val++;
-
- lp = log5;
- for(i=0; i<5; i++) {
- lp->c--;
- if(lp->c <= 0) {
- lp->c = lp->m;
- if(lp->p != R)
- lp->p->log5 = r;
- lp->p = r;
- (lp+1)->c = 0;
- break;
- }
- lp++;
- }
-
- r1 = r->p1;
- if(r1 != R)
- switch(r1->prog->as) {
- case ARET:
- case AJMP:
- case AIRETL:
- case AIRETQ:
- r->p1 = R;
- r1->s1 = R;
- }
-
- bit = mkvar(r, &p->from);
- if(bany(&bit))
- switch(p->as) {
- /*
- * funny
- */
- case ALEAL:
- case ALEAQ:
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- break;
-
- /*
- * left side read
- */
- default:
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
- break;
- }
-
- bit = mkvar(r, &p->to);
- if(bany(&bit))
- switch(p->as) {
- default:
- diag(Z, "reg: unknown op: %A", p->as);
- break;
-
- /*
- * right side read
- */
- case ACMPB:
- case ACMPL:
- case ACMPQ:
- case ACMPW:
- case APREFETCHT0:
- case APREFETCHT1:
- case APREFETCHT2:
- case APREFETCHNTA:
- case ACOMISS:
- case ACOMISD:
- case AUCOMISS:
- case AUCOMISD:
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- break;
-
- /*
- * right side write
- */
- case ANOP:
- case AMOVL:
- case AMOVQ:
- case AMOVB:
- case AMOVW:
- case AMOVBLSX:
- case AMOVBLZX:
- case AMOVBQSX:
- case AMOVBQZX:
- case AMOVLQSX:
- case AMOVLQZX:
- case AMOVWLSX:
- case AMOVWLZX:
- case AMOVWQSX:
- case AMOVWQZX:
- case AMOVQL:
-
- case AMOVSS:
- case AMOVSD:
- case ACVTSD2SL:
- case ACVTSD2SQ:
- case ACVTSD2SS:
- case ACVTSL2SD:
- case ACVTSL2SS:
- case ACVTSQ2SD:
- case ACVTSQ2SS:
- case ACVTSS2SD:
- case ACVTSS2SL:
- case ACVTSS2SQ:
- case ACVTTSD2SL:
- case ACVTTSD2SQ:
- case ACVTTSS2SL:
- case ACVTTSS2SQ:
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- break;
-
- /*
- * right side read+write
- */
- case AADDB:
- case AADDL:
- case AADDQ:
- case AADDW:
- case AANDB:
- case AANDL:
- case AANDQ:
- case AANDW:
- case ASUBB:
- case ASUBL:
- case ASUBQ:
- case ASUBW:
- case AORB:
- case AORL:
- case AORQ:
- case AORW:
- case AXORB:
- case AXORL:
- case AXORQ:
- case AXORW:
- case ASALB:
- case ASALL:
- case ASALQ:
- case ASALW:
- case ASARB:
- case ASARL:
- case ASARQ:
- case ASARW:
- case AROLB:
- case AROLL:
- case AROLQ:
- case AROLW:
- case ARORB:
- case ARORL:
- case ARORQ:
- case ARORW:
- case ASHLB:
- case ASHLL:
- case ASHLQ:
- case ASHLW:
- case ASHRB:
- case ASHRL:
- case ASHRQ:
- case ASHRW:
- case AIMULL:
- case AIMULQ:
- case AIMULW:
- case ANEGL:
- case ANEGQ:
- case ANOTL:
- case ANOTQ:
- case AADCL:
- case AADCQ:
- case ASBBL:
- case ASBBQ:
-
- case AADDSD:
- case AADDSS:
- case ACMPSD:
- case ACMPSS:
- case ADIVSD:
- case ADIVSS:
- case AMAXSD:
- case AMAXSS:
- case AMINSD:
- case AMINSS:
- case AMULSD:
- case AMULSS:
- case ARCPSS:
- case ARSQRTSS:
- case ASQRTSD:
- case ASQRTSS:
- case ASUBSD:
- case ASUBSS:
- case AXORPD:
- for(z=0; z<BITS; z++) {
- r->set.b[z] |= bit.b[z];
- r->use2.b[z] |= bit.b[z];
- }
- break;
-
- /*
- * funny
- */
- case ACALL:
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- break;
- }
-
- switch(p->as) {
- case AIMULL:
- case AIMULQ:
- case AIMULW:
- if(p->to.type != D_NONE)
- break;
-
- case AIDIVB:
- case AIDIVL:
- case AIDIVQ:
- case AIDIVW:
- case AIMULB:
- case ADIVB:
- case ADIVL:
- case ADIVQ:
- case ADIVW:
- case AMULB:
- case AMULL:
- case AMULQ:
- case AMULW:
-
- case ACWD:
- case ACDQ:
- case ACQO:
- r->regu |= RtoB(D_AX) | RtoB(D_DX);
- break;
-
- case AREP:
- case AREPN:
- case ALOOP:
- case ALOOPEQ:
- case ALOOPNE:
- r->regu |= RtoB(D_CX);
- break;
-
- case AMOVSB:
- case AMOVSL:
- case AMOVSQ:
- case AMOVSW:
- case ACMPSB:
- case ACMPSL:
- case ACMPSQ:
- case ACMPSW:
- r->regu |= RtoB(D_SI) | RtoB(D_DI);
- break;
-
- case ASTOSB:
- case ASTOSL:
- case ASTOSQ:
- case ASTOSW:
- case ASCASB:
- case ASCASL:
- case ASCASQ:
- case ASCASW:
- r->regu |= RtoB(D_AX) | RtoB(D_DI);
- break;
-
- case AINSB:
- case AINSL:
- case AINSW:
- case AOUTSB:
- case AOUTSL:
- case AOUTSW:
- r->regu |= RtoB(D_DI) | RtoB(D_DX);
- break;
- }
- }
- if(firstr == R)
- return;
- initpc = pc - val;
- npc = val;
-
- /*
- * pass 2
- * turn branch references to pointers
- * build back pointers
- */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH) {
- val = p->to.offset - initpc;
- r1 = firstr;
- while(r1 != R) {
- r2 = r1->log5;
- if(r2 != R && val >= r2->pc) {
- r1 = r2;
- continue;
- }
- if(r1->pc == val)
- break;
- r1 = r1->link;
- }
- if(r1 == R) {
- nearln = p->lineno;
- diag(Z, "ref not found\n%P", p);
- continue;
- }
- if(r1 == r) {
- nearln = p->lineno;
- diag(Z, "ref to self\n%P", p);
- continue;
- }
- r->s2 = r1;
- r->p2link = r1->p2;
- r1->p2 = r;
- }
- }
- if(debug['R']) {
- p = firstr->prog;
- print("\n%L %D\n", p->lineno, &p->from);
- }
-
- /*
- * pass 2.1
- * fix jumps
- */
- fixjmp(firstr);
-
- /*
- * pass 2.5
- * find looping structure
- */
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- change = 0;
- loopit(firstr, npc);
- if(debug['R'] && debug['v']) {
- print("\nlooping structure:\n");
- for(r = firstr; r != R; r = r->link) {
- print("%d:%P", r->loop, r->prog);
- for(z=0; z<BITS; z++)
- bit.b[z] = r->use1.b[z] |
- r->use2.b[z] |
- r->set.b[z];
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->use1))
- print(" u1=%B", r->use1);
- if(bany(&r->use2))
- print(" u2=%B", r->use2);
- if(bany(&r->set))
- print(" st=%B", r->set);
- }
- print("\n");
- }
- }
-
- /*
- * pass 3
- * iterate propagating usage
- * back until flow graph is complete
- */
-loop1:
- change = 0;
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- for(r = firstr; r != R; r = r->link)
- if(r->prog->as == ARET)
- prop(r, zbits, zbits);
-loop11:
- /* pick up unreachable code */
- i = 0;
- for(r = firstr; r != R; r = r1) {
- r1 = r->link;
- if(r1 && r1->active && !r->active) {
- prop(r, zbits, zbits);
- i = 1;
- }
- }
- if(i)
- goto loop11;
- if(change)
- goto loop1;
-
-
- /*
- * pass 4
- * iterate propagating register/variable synchrony
- * forward until graph is complete
- */
-loop2:
- change = 0;
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- synch(firstr, zbits);
- if(change)
- goto loop2;
-
-
- /*
- * pass 5
- * isolate regions
- * calculate costs (paint1)
- */
- r = firstr;
- if(r) {
- for(z=0; z<BITS; z++)
- bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
- ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
- if(bany(&bit)) {
- nearln = r->prog->lineno;
- warn(Z, "used and not set: %B", bit);
- if(debug['R'] && !debug['w'])
- print("used and not set: %B\n", bit);
- }
- }
- if(debug['R'] && debug['v'])
- print("\nprop structure:\n");
- for(r = firstr; r != R; r = r->link)
- r->act = zbits;
- rgp = region;
- nregion = 0;
- for(r = firstr; r != R; r = r->link) {
- if(debug['R'] && debug['v']) {
- print("%P\t", r->prog);
- if(bany(&r->set))
- print("s:%B ", r->set);
- if(bany(&r->refahead))
- print("ra:%B ", r->refahead);
- if(bany(&r->calahead))
- print("ca:%B ", r->calahead);
- print("\n");
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = r->set.b[z] &
- ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
- if(bany(&bit)) {
- nearln = r->prog->lineno;
- warn(Z, "set and not used: %B", bit);
- if(debug['R'])
- print("set and not used: %B\n", bit);
- excise(r);
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- rgp->enter = r;
- rgp->varno = i;
- change = 0;
- if(debug['R'] && debug['v'])
- print("\n");
- paint1(r, i);
- bit.b[i/32] &= ~(1L<<(i%32));
- if(change <= 0) {
- if(debug['R'])
- print("%L$%d: %B\n",
- r->prog->lineno, change, blsh(i));
- continue;
- }
- rgp->cost = change;
- nregion++;
- if(nregion >= NRGN)
- fatal(Z, "too many regions");
- rgp++;
- }
- }
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- for(i=0; i<nregion; i++) {
- bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
- vreg = allreg(vreg, rgp);
- if(debug['R']) {
- print("%L$%d %R: %B\n",
- rgp->enter->prog->lineno,
- rgp->cost,
- rgp->regno,
- bit);
- }
- if(rgp->regno != 0)
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- rgp++;
- }
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P'])
- peep();
-
- /*
- * pass 8
- * recalculate pc
- */
- val = initpc;
- for(r = firstr; r != R; r = r1) {
- r->pc = val;
- p = r->prog;
- p1 = P;
- r1 = r->link;
- if(r1 != R)
- p1 = r1->prog;
- for(; p != p1; p = p->link) {
- switch(p->as) {
- default:
- val++;
- break;
-
- case ANOP:
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- case AFUNCDATA:
- break;
- }
- }
- }
- pc = val;
-
- /*
- * fix up branches
- */
- if(debug['R'])
- if(bany(&addrs))
- print("addrs: %B\n", addrs);
-
- r1 = 0; /* set */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH) {
- p->to.offset = r->s2->pc;
- p->to.u.branch = r->s2->prog;
- }
- r1 = r;
- }
-
- /*
- * last pass
- * eliminate nops
- * free aux structures
- */
- for(p = firstr->prog; p != P; p = p->link){
- while(p->link && p->link->as == ANOP)
- p->link = p->link->link;
- }
- if(r1 != R) {
- r1->link = freer;
- freer = firstr;
- }
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Addr *a;
- Var *v;
-
- p1 = alloc(sizeof(*p1));
- *p1 = zprog;
- p = r->prog;
-
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->sym = v->sym;
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = v->name;
-
- p1->as = AMOVL;
- if(v->etype == TCHAR || v->etype == TUCHAR)
- p1->as = AMOVB;
- if(v->etype == TSHORT || v->etype == TUSHORT)
- p1->as = AMOVW;
- if(v->etype == TVLONG || v->etype == TUVLONG || (v->etype == TIND && ewidth[TIND] == 8))
- p1->as = AMOVQ;
- if(v->etype == TFLOAT)
- p1->as = AMOVSS;
- if(v->etype == TDOUBLE)
- p1->as = AMOVSD;
-
- p1->from.type = rn;
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = rn;
- if(v->etype == TUCHAR)
- p1->as = AMOVB;
- if(v->etype == TUSHORT)
- p1->as = AMOVW;
- }
- if(debug['R'])
- print("%P\t.a%P\n", p, p1);
-}
-
-uint32
-doregbits(int r)
-{
- uint32 b;
-
- b = 0;
- if(r >= D_INDIR)
- r -= D_INDIR;
- if(r >= D_AX && r <= D_R15)
- b |= RtoB(r);
- else
- if(r >= D_AL && r <= D_R15B)
- b |= RtoB(r-D_AL+D_AX);
- else
- if(r >= D_AH && r <= D_BH)
- b |= RtoB(r-D_AH+D_AX);
- else
- if(r >= D_X0 && r <= D_X0+15)
- b |= FtoB(r);
- return b;
-}
-
-Bits
-mkvar(Reg *r, Addr *a)
-{
- Var *v;
- int i, t, n, et, z;
- int32 o;
- Bits bit;
- LSym *s;
-
- /*
- * mark registers used
- */
- t = a->type;
- r->regu |= doregbits(t);
- r->regu |= doregbits(a->index);
-
- switch(t) {
- default:
- goto none;
- case D_ADDR:
- a->type = a->index;
- bit = mkvar(r, a);
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- a->type = t;
- goto none;
- case D_EXTERN:
- case D_STATIC:
- case D_PARAM:
- case D_AUTO:
- n = t;
- break;
- }
- s = a->sym;
- if(s == nil)
- goto none;
- if(s->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- v = var;
- for(i=0; i<nvar; i++) {
- if(s == v->sym)
- if(n == v->name)
- if(o == v->offset)
- goto out;
- v++;
- }
- if(nvar >= NVAR)
- fatal(Z, "variable not optimized: %s", s->name);
- i = nvar;
- nvar++;
- v = &var[i];
- v->sym = s;
- v->offset = o;
- v->name = n;
- v->etype = et;
- if(debug['R'])
- print("bit=%2d et=%2d %D\n", i, et, a);
-
-out:
- bit = blsh(i);
- if(n == D_EXTERN || n == D_STATIC)
- for(z=0; z<BITS; z++)
- externs.b[z] |= bit.b[z];
- if(n == D_PARAM)
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
- if(v->etype != et || !(typechlpfd[et] || typev[et])) /* funny punning */
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- return bit;
-
-none:
- return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
- Reg *r1, *r2;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->p1) {
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(r1->prog->as) {
- case ACALL:
- for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z];
- ref.b[z] = 0;
- }
- break;
-
- case ATEXT:
- for(z=0; z<BITS; z++) {
- cal.b[z] = 0;
- ref.b[z] = 0;
- }
- break;
-
- case ARET:
- for(z=0; z<BITS; z++) {
- cal.b[z] = externs.b[z];
- ref.b[z] = 0;
- }
- }
- for(z=0; z<BITS; z++) {
- ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
- r1->use1.b[z] | r1->use2.b[z];
- cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
- r1->refbehind.b[z] = ref.b[z];
- r1->calbehind.b[z] = cal.b[z];
- }
- if(r1->active)
- break;
- r1->active = 1;
- }
- for(; r != r1; r = r->p1)
- for(r2 = r->p2; r2 != R; r2 = r2->p2link)
- prop(r2, r->refbehind, r->calbehind);
-}
-
-/*
- * find looping structure
- *
- * 1) find reverse postordering
- * 2) find approximate dominators,
- * the actual dominators if the flow graph is reducible
- * otherwise, dominators plus some other non-dominators.
- * See Matthew S. Hecht and Jeffrey D. Ullman,
- * "Analysis of a Simple Algorithm for Global Data Flow Problems",
- * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
- * Oct. 1-3, 1973, pp. 207-217.
- * 3) find all nodes with a predecessor dominated by the current node.
- * such a node is a loop head.
- * recursively, all preds with a greater rpo number are in the loop
- */
-int32
-postorder(Reg *r, Reg **rpo2r, int32 n)
-{
- Reg *r1;
-
- r->rpo = 1;
- r1 = r->s1;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- r1 = r->s2;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- rpo2r[n] = r;
- n++;
- return n;
-}
-
-int32
-rpolca(int32 *idom, int32 rpo1, int32 rpo2)
-{
- int32 t;
-
- if(rpo1 == -1)
- return rpo2;
- while(rpo1 != rpo2){
- if(rpo1 > rpo2){
- t = rpo2;
- rpo2 = rpo1;
- rpo1 = t;
- }
- while(rpo1 < rpo2){
- t = idom[rpo2];
- if(t >= rpo2)
- fatal(Z, "bad idom");
- rpo2 = t;
- }
- }
- return rpo1;
-}
-
-int
-doms(int32 *idom, int32 r, int32 s)
-{
- while(s > r)
- s = idom[s];
- return s == r;
-}
-
-int
-loophead(int32 *idom, Reg *r)
-{
- int32 src;
-
- src = r->rpo;
- if(r->p1 != R && doms(idom, src, r->p1->rpo))
- return 1;
- for(r = r->p2; r != R; r = r->p2link)
- if(doms(idom, src, r->rpo))
- return 1;
- return 0;
-}
-
-void
-loopmark(Reg **rpo2r, int32 head, Reg *r)
-{
- if(r->rpo < head || r->active == head)
- return;
- r->active = head;
- r->loop += LOOP;
- if(r->p1 != R)
- loopmark(rpo2r, head, r->p1);
- for(r = r->p2; r != R; r = r->p2link)
- loopmark(rpo2r, head, r);
-}
-
-void
-loopit(Reg *r, int32 nr)
-{
- Reg *r1;
- int32 i, d, me;
-
- if(nr > maxnr) {
- rpo2r = alloc(nr * sizeof(Reg*));
- idom = alloc(nr * sizeof(int32));
- maxnr = nr;
- }
-
- d = postorder(r, rpo2r, 0);
- if(d > nr)
- fatal(Z, "too many reg nodes");
- nr = d;
- for(i = 0; i < nr / 2; i++){
- r1 = rpo2r[i];
- rpo2r[i] = rpo2r[nr - 1 - i];
- rpo2r[nr - 1 - i] = r1;
- }
- for(i = 0; i < nr; i++)
- rpo2r[i]->rpo = i;
-
- idom[0] = 0;
- for(i = 0; i < nr; i++){
- r1 = rpo2r[i];
- me = r1->rpo;
- d = -1;
- if(r1->p1 != R && r1->p1->rpo < me)
- d = r1->p1->rpo;
- for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
- if(r1->rpo < me)
- d = rpolca(idom, d, r1->rpo);
- idom[i] = d;
- }
-
- for(i = 0; i < nr; i++){
- r1 = rpo2r[i];
- r1->loop++;
- if(r1->p2 != R && loophead(idom, r1))
- loopmark(rpo2r, i, r1);
- }
-}
-
-void
-synch(Reg *r, Bits dif)
-{
- Reg *r1;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->s1) {
- for(z=0; z<BITS; z++) {
- dif.b[z] = (dif.b[z] &
- ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
- r1->set.b[z] | r1->regdiff.b[z];
- if(dif.b[z] != r1->regdiff.b[z]) {
- r1->regdiff.b[z] = dif.b[z];
- change++;
- }
- }
- if(r1->active)
- break;
- r1->active = 1;
- for(z=0; z<BITS; z++)
- dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if(r1->s2 != R)
- synch(r1->s2, dif);
- }
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
- Var *v;
- int i;
-
- v = var + r->varno;
- r->regno = 0;
- switch(v->etype) {
-
- default:
- diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
- break;
-
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TIND:
- case TARRAY:
- i = BtoR(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TDOUBLE:
- case TFLOAT:
- i = BtoF(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return FtoB(i);
- }
- break;
- }
- return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint32 bb;
-
- z = bn/32;
- bb = 1L<<(bn%32);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
- change -= CLOAD * r->loop;
- if(debug['R'] && debug['v'])
- print("%d%P\td %B $%d\n", r->loop,
- r->prog, blsh(bn), change);
- }
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- change += CREF * r->loop;
- if(debug['R'] && debug['v'])
- print("%d%P\tu1 %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->loop;
- if(debug['R'] && debug['v'])
- print("%d%P\tu2 %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->loop;
- if(debug['R'] && debug['v'])
- print("%d%P\tst %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint1(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint1(r1, bn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-uint32
-regset(Reg *r, uint32 bb)
-{
- uint32 b, set;
- Addr v;
- int c;
-
- set = 0;
- v = zprog.from;
- while(b = bb & ~(bb-1)) {
- v.type = b & 0xFFFF? BtoR(b): BtoF(b);
- if(v.type == 0)
- diag(Z, "zero v.type for %#ux", b);
- c = copyu(r->prog, &v, A);
- if(c == 3)
- set |= b;
- bb &= ~b;
- }
- return set;
-}
-
-uint32
-reguse(Reg *r, uint32 bb)
-{
- uint32 b, set;
- Addr v;
- int c;
-
- set = 0;
- v = zprog.from;
- while(b = bb & ~(bb-1)) {
- v.type = b & 0xFFFF? BtoR(b): BtoF(b);
- c = copyu(r->prog, &v, A);
- if(c == 1 || c == 2 || c == 4)
- set |= b;
- bb &= ~b;
- }
- return set;
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
- Reg *r1;
- int z;
- uint32 bb, vreg, x;
-
- z = bn/32;
- bb = 1L << (bn%32);
- vreg = regbits;
- if(!(r->act.b[z] & bb))
- return vreg;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(!(r1->act.b[z] & bb))
- break;
- r = r1;
- }
- for(;;) {
- r->act.b[z] &= ~bb;
-
- vreg |= r->regu;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
- r = r->s1;
- if(r == R)
- break;
- if(!(r->act.b[z] & bb))
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-
- bb = vreg;
- for(; r; r=r->s1) {
- x = r->regu & ~bb;
- if(x) {
- vreg |= reguse(r, x);
- bb |= regset(r, x);
- }
- }
- return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint32 bb;
-
- z = bn/32;
- bb = 1L << (bn%32);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
- addmove(r, bn, rn, 0);
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->from, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->to, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(r, bn, rn, 1);
- r->regu |= rb;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Addr *a, int rn)
-{
-
- a->sym = 0;
- a->offset = 0;
- a->type = rn;
-}
-
-int32
-RtoB(int r)
-{
-
- if(r < D_AX || r > D_R15)
- return 0;
- return 1L << (r-D_AX);
-}
-
-int
-BtoR(int32 b)
-{
-
- b &= 0xffffL;
- if(nacl)
- b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX)));
- if(b == 0)
- return 0;
- return bitno(b) + D_AX;
-}
-
-/*
- * bit reg
- * 16 X5
- * 17 X6
- * 18 X7
- */
-int32
-FtoB(int f)
-{
- if(f < FREGMIN || f > FREGEXT)
- return 0;
- return 1L << (f - FREGMIN + 16);
-}
-
-int
-BtoF(int32 b)
-{
-
- b &= 0x70000L;
- if(b == 0)
- return 0;
- return bitno(b) - 16 + FREGMIN;
-}
-
-/* what instruction does a JMP to p eventually land on? */
-static Reg*
-chasejmp(Reg *r, int *jmploop)
-{
- int n;
-
- n = 0;
- for(; r; r=r->s2) {
- if(r->prog->as != AJMP || r->prog->to.type != D_BRANCH)
- break;
- if(++n > 10) {
- *jmploop = 1;
- break;
- }
- }
- return r;
-}
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Reg *firstr)
-{
- Reg *r;
- Prog *p;
-
- for(r=firstr; r; r=r->link) {
- if(r->active)
- break;
- r->active = 1;
- p = r->prog;
- if(p->as != ACALL && p->to.type == D_BRANCH)
- mark(r->s2);
- if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
- break;
- }
-}
-
-/*
- * the code generator depends on being able to write out JMP
- * instructions that it can jump to now but fill in later.
- * the linker will resolve them nicely, but they make the code
- * longer and more difficult to follow during debugging.
- * remove them.
- */
-static void
-fixjmp(Reg *firstr)
-{
- int jmploop;
- Reg *r;
- Prog *p;
-
- if(debug['R'] && debug['v'])
- print("\nfixjmp\n");
-
- // pass 1: resolve jump to AJMP, mark all code as dead.
- jmploop = 0;
- for(r=firstr; r; r=r->link) {
- p = r->prog;
- if(debug['R'] && debug['v'])
- print("%04d %P\n", (int)r->pc, p);
- if(p->as != ACALL && p->to.type == D_BRANCH && r->s2 && r->s2->prog->as == AJMP) {
- r->s2 = chasejmp(r->s2, &jmploop);
- p->to.offset = r->s2->pc;
- p->to.u.branch = r->s2->prog;
- if(debug['R'] && debug['v'])
- print("->%P\n", p);
- }
- r->active = 0;
- }
- if(debug['R'] && debug['v'])
- print("\n");
-
- // pass 2: mark all reachable code alive
- mark(firstr);
-
- // pass 3: delete dead code (mostly JMPs).
- for(r=firstr; r; r=r->link) {
- if(!r->active) {
- p = r->prog;
- if(p->link == P && p->as == ARET && r->p1 && r->p1->prog->as != ARET) {
- // This is the final ARET, and the code so far doesn't have one.
- // Let it stay.
- } else {
- if(debug['R'] && debug['v'])
- print("del %04d %P\n", (int)r->pc, p);
- p->as = ANOP;
- }
- }
- }
-
- // pass 4: elide JMP to next instruction.
- // only safe if there are no jumps to JMPs anymore.
- if(!jmploop) {
- for(r=firstr; r; r=r->link) {
- p = r->prog;
- if(p->as == AJMP && p->to.type == D_BRANCH && r->s2 == r->link) {
- if(debug['R'] && debug['v'])
- print("del %04d %P\n", (int)r->pc, p);
- p->as = ANOP;
- }
- }
- }
-
- // fix back pointers.
- for(r=firstr; r; r=r->link) {
- r->p2 = R;
- r->p2link = R;
- }
- for(r=firstr; r; r=r->link) {
- if(r->s2) {
- r->p2link = r->s2->p2;
- r->s2->p2 = r;
- }
- }
-
- if(debug['R'] && debug['v']) {
- print("\n");
- for(r=firstr; r; r=r->link)
- print("%04d %P\n", (int)r->pc, r->prog);
- print("\n");
- }
-}
-
diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c
deleted file mode 100644
index fceb332b2..000000000
--- a/src/cmd/6c/sgen.c
+++ /dev/null
@@ -1,483 +0,0 @@
-// Inferno utils/6c/sgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-Prog*
-gtext(Sym *s, int32 stkoff)
-{
- vlong v;
-
- v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff);
- if((textflag & NOSPLIT) && stkoff >= 128)
- yyerror("stack frame too large for NOSPLIT function");
-
- gpseudo(ATEXT, s, nodgconst(v, types[TVLONG]));
- return p;
-}
-
-void
-noretval(int n)
-{
-
- if(n & 1) {
- gins(ANOP, Z, Z);
- p->to.type = REGRET;
- }
- if(n & 2) {
- gins(ANOP, Z, Z);
- p->to.type = FREGRET;
- }
-}
-
-/* welcome to commute */
-static void
-commute(Node *n)
-{
- Node *l, *r;
-
- l = n->left;
- r = n->right;
- if(r->complex > l->complex) {
- n->left = r;
- n->right = l;
- }
-}
-
-void
-indexshift(Node *n)
-{
- int g;
-
- if(!typechlpv[n->type->etype])
- return;
- simplifyshift(n);
- if(n->op == OASHL && n->right->op == OCONST){
- g = vconst(n->right);
- if(g >= 0 && g <= 3)
- n->addable = 7;
- }
-}
-
-/*
- * calculate addressability as follows
- * NAME ==> 10/11 name+value(SB/SP)
- * REGISTER ==> 12 register
- * CONST ==> 20 $value
- * *(20) ==> 21 value
- * &(10) ==> 13 $name+value(SB)
- * &(11) ==> 1 $name+value(SP)
- * (13) + (20) ==> 13 fold constants
- * (1) + (20) ==> 1 fold constants
- * *(13) ==> 10 back to name
- * *(1) ==> 11 back to name
- *
- * (20) * (X) ==> 7 multiplier in indexing
- * (X,7) + (13,1) ==> 8 adder in indexing (addresses)
- * (8) ==> &9(OINDEX) index, almost addressable
- *
- * calculate complexity (number of registers)
- */
-void
-xcom(Node *n)
-{
- Node *l, *r;
- int g;
-
- if(n == Z)
- return;
- l = n->left;
- r = n->right;
- n->complex = 0;
- n->addable = 0;
- switch(n->op) {
- case OCONST:
- n->addable = 20;
- break;
-
- case ONAME:
- n->addable = 9;
- if(n->class == CPARAM || n->class == CAUTO)
- n->addable = 11;
- break;
-
- case OEXREG:
- n->addable = 0;
- break;
-
- case OREGISTER:
- n->addable = 12;
- break;
-
- case OINDREG:
- n->addable = 12;
- break;
-
- case OADDR:
- xcom(l);
- if(l->addable == 10)
- n->addable = 13;
- else
- if(l->addable == 11)
- n->addable = 1;
- break;
-
- case OADD:
- xcom(l);
- xcom(r);
- if(n->type->etype != TIND)
- break;
-
- switch(r->addable) {
- case 20:
- switch(l->addable) {
- case 1:
- case 13:
- commadd:
- l->type = n->type;
- *n = *l;
- l = new(0, Z, Z);
- *l = *(n->left);
- l->xoffset += r->vconst;
- n->left = l;
- r = n->right;
- goto brk;
- }
- break;
-
- case 1:
- case 13:
- case 10:
- case 11:
- /* l is the base, r is the index */
- if(l->addable != 20)
- n->addable = 8;
- break;
- }
- switch(l->addable) {
- case 20:
- switch(r->addable) {
- case 13:
- case 1:
- r = n->left;
- l = n->right;
- n->left = l;
- n->right = r;
- goto commadd;
- }
- break;
-
- case 13:
- case 1:
- case 10:
- case 11:
- /* r is the base, l is the index */
- if(r->addable != 20)
- n->addable = 8;
- break;
- }
- if(n->addable == 8 && !side(n) && !nacl) {
- indx(n);
- l = new1(OINDEX, idx.basetree, idx.regtree);
- l->scale = idx.scale;
- l->addable = 9;
- l->complex = l->right->complex;
- l->type = l->left->type;
- n->op = OADDR;
- n->left = l;
- n->right = Z;
- n->addable = 8;
- break;
- }
- break;
-
- case OINDEX:
- xcom(l);
- xcom(r);
- n->addable = 9;
- break;
-
- case OIND:
- xcom(l);
- if(l->op == OADDR) {
- l = l->left;
- l->type = n->type;
- *n = *l;
- return;
- }
- switch(l->addable) {
- case 20:
- n->addable = 21;
- break;
- case 1:
- n->addable = 11;
- break;
- case 13:
- n->addable = 10;
- break;
- }
- break;
-
- case OASHL:
- xcom(l);
- xcom(r);
- indexshift(n);
- break;
-
- case OMUL:
- case OLMUL:
- xcom(l);
- xcom(r);
- g = vlog(l);
- if(g >= 0) {
- n->left = r;
- n->right = l;
- l = r;
- r = n->right;
- }
- g = vlog(r);
- if(g >= 0) {
- n->op = OASHL;
- r->vconst = g;
- r->type = types[TINT];
- indexshift(n);
- break;
- }
- commute(n);
- break;
-
- case OASLDIV:
- xcom(l);
- xcom(r);
- g = vlog(r);
- if(g >= 0) {
- n->op = OASLSHR;
- r->vconst = g;
- r->type = types[TINT];
- }
- break;
-
- case OLDIV:
- xcom(l);
- xcom(r);
- g = vlog(r);
- if(g >= 0) {
- n->op = OLSHR;
- r->vconst = g;
- r->type = types[TINT];
- indexshift(n);
- break;
- }
- break;
-
- case OASLMOD:
- xcom(l);
- xcom(r);
- g = vlog(r);
- if(g >= 0) {
- n->op = OASAND;
- r->vconst--;
- }
- break;
-
- case OLMOD:
- xcom(l);
- xcom(r);
- g = vlog(r);
- if(g >= 0) {
- n->op = OAND;
- r->vconst--;
- }
- break;
-
- case OASMUL:
- case OASLMUL:
- xcom(l);
- xcom(r);
- g = vlog(r);
- if(g >= 0) {
- n->op = OASASHL;
- r->vconst = g;
- }
- break;
-
- case OLSHR:
- case OASHR:
- xcom(l);
- xcom(r);
- indexshift(n);
- break;
-
- default:
- if(l != Z)
- xcom(l);
- if(r != Z)
- xcom(r);
- break;
- }
-brk:
- if(n->addable >= 10)
- return;
- if(l != Z)
- n->complex = l->complex;
- if(r != Z) {
- if(r->complex == n->complex)
- n->complex = r->complex+1;
- else
- if(r->complex > n->complex)
- n->complex = r->complex;
- }
- if(n->complex == 0)
- n->complex++;
-
- switch(n->op) {
-
- case OFUNC:
- n->complex = FNX;
- break;
-
- case OCAST:
- if(l->type->etype == TUVLONG && typefd[n->type->etype])
- n->complex += 2;
- break;
-
- case OLMOD:
- case OMOD:
- case OLMUL:
- case OLDIV:
- case OMUL:
- case ODIV:
- case OASLMUL:
- case OASLDIV:
- case OASLMOD:
- case OASMUL:
- case OASDIV:
- case OASMOD:
- if(r->complex >= l->complex) {
- n->complex = l->complex + 3;
- if(r->complex > n->complex)
- n->complex = r->complex;
- } else {
- n->complex = r->complex + 3;
- if(l->complex > n->complex)
- n->complex = l->complex;
- }
- break;
-
- case OLSHR:
- case OASHL:
- case OASHR:
- case OASLSHR:
- case OASASHL:
- case OASASHR:
- if(r->complex >= l->complex) {
- n->complex = l->complex + 2;
- if(r->complex > n->complex)
- n->complex = r->complex;
- } else {
- n->complex = r->complex + 2;
- if(l->complex > n->complex)
- n->complex = l->complex;
- }
- break;
-
- case OADD:
- case OXOR:
- case OAND:
- case OOR:
- /*
- * immediate operators, make const on right
- */
- if(l->op == OCONST) {
- n->left = r;
- n->right = l;
- }
- break;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- /*
- * compare operators, make const on left
- */
- if(r->op == OCONST) {
- n->left = r;
- n->right = l;
- n->op = invrel[relindex(n->op)];
- }
- break;
- }
-}
-
-void
-indx(Node *n)
-{
- Node *l, *r;
-
- if(debug['x'])
- prtree(n, "indx");
-
- l = n->left;
- r = n->right;
- if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
- n->right = l;
- n->left = r;
- l = r;
- r = n->right;
- }
- if(l->addable != 7) {
- idx.regtree = l;
- idx.scale = 1;
- } else
- if(l->right->addable == 20) {
- idx.regtree = l->left;
- idx.scale = 1 << l->right->vconst;
- } else
- if(l->left->addable == 20) {
- idx.regtree = l->right;
- idx.scale = 1 << l->left->vconst;
- } else
- diag(n, "bad index");
-
- idx.basetree = r;
- if(debug['x']) {
- print("scale = %d\n", idx.scale);
- prtree(idx.regtree, "index");
- prtree(idx.basetree, "base");
- }
-}
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
deleted file mode 100644
index 6e918eb10..000000000
--- a/src/cmd/6c/swt.c
+++ /dev/null
@@ -1,353 +0,0 @@
-// Inferno utils/6c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-void
-swit1(C1 *q, int nc, int32 def, Node *n)
-{
- Node nreg;
-
- regalloc(&nreg, n, Z);
- if(typev[n->type->etype])
- nreg.type = types[TVLONG];
- else
- nreg.type = types[TLONG];
- cgen(n, &nreg);
- swit2(q, nc, def, &nreg);
- regfree(&nreg);
-}
-
-void
-swit2(C1 *q, int nc, int32 def, Node *n)
-{
- C1 *r;
- int i;
- Prog *sp;
-
- if(nc < 5) {
- for(i=0; i<nc; i++) {
- if(debug['W'])
- print("case = %.8llux\n", q->val);
- gcmp(OEQ, n, q->val);
- patch(p, q->label);
- q++;
- }
- gbranch(OGOTO);
- patch(p, def);
- return;
- }
- i = nc / 2;
- r = q+i;
- if(debug['W'])
- print("case > %.8llux\n", r->val);
- gcmp(OGT, n, r->val);
- sp = p;
- gbranch(OGOTO);
- p->as = AJEQ;
- patch(p, r->label);
- swit2(q, i, def, n);
-
- if(debug['W'])
- print("case < %.8llux\n", r->val);
- patch(sp, pc);
- swit2(r+1, nc-i-1, def, n);
-}
-
-void
-bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
- int sh;
- int32 v;
- Node *l;
-
- /*
- * n1 gets adjusted/masked value
- * n2 gets address of cell
- * n3 gets contents of cell
- */
- l = b->left;
- if(n2 != Z) {
- regalloc(n1, l, nn);
- reglcgen(n2, l, Z);
- regalloc(n3, l, Z);
- gmove(n2, n3);
- gmove(n3, n1);
- } else {
- regalloc(n1, l, nn);
- cgen(l, n1);
- }
- if(b->type->shift == 0 && typeu[b->type->etype]) {
- v = ~0 + (1L << b->type->nbits);
- gopcode(OAND, tfield, nodconst(v), n1);
- } else {
- sh = 32 - b->type->shift - b->type->nbits;
- if(sh > 0)
- gopcode(OASHL, tfield, nodconst(sh), n1);
- sh += b->type->shift;
- if(sh > 0)
- if(typeu[b->type->etype])
- gopcode(OLSHR, tfield, nodconst(sh), n1);
- else
- gopcode(OASHR, tfield, nodconst(sh), n1);
- }
-}
-
-void
-bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
- int32 v;
- Node nod;
- int sh;
-
- regalloc(&nod, b->left, Z);
- v = ~0 + (1L << b->type->nbits);
- gopcode(OAND, types[TLONG], nodconst(v), n1);
- gmove(n1, &nod);
- if(nn != Z)
- gmove(n1, nn);
- sh = b->type->shift;
- if(sh > 0)
- gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
- v <<= sh;
- gopcode(OAND, types[TLONG], nodconst(~v), n3);
- gopcode(OOR, types[TLONG], n3, &nod);
- gmove(&nod, n2);
-
- regfree(&nod);
- regfree(n1);
- regfree(n2);
- regfree(n3);
-}
-
-int32
-outstring(char *s, int32 n)
-{
- int32 r;
-
- if(suppress)
- return nstring;
- r = nstring;
- while(n) {
- string[mnstring] = *s++;
- mnstring++;
- nstring++;
- if(mnstring >= NSNAME) {
- gpseudo(ADATA, symstring, nodconst(0L));
- p->from.offset += nstring - NSNAME;
- p->from.scale = NSNAME;
- p->to.type = D_SCONST;
- memmove(p->to.u.sval, string, NSNAME);
- mnstring = 0;
- }
- n--;
- }
- return r;
-}
-
-void
-sextern(Sym *s, Node *a, int32 o, int32 w)
-{
- int32 e, lw;
-
- for(e=0; e<w; e+=NSNAME) {
- lw = NSNAME;
- if(w-e < lw)
- lw = w-e;
- gpseudo(ADATA, s, nodconst(0L));
- p->from.offset += o+e;
- p->from.scale = lw;
- p->to.type = D_SCONST;
- memmove(p->to.u.sval, a->cstring+e, lw);
- }
-}
-
-void
-gextern(Sym *s, Node *a, int32 o, int32 w)
-{
- if(0 && a->op == OCONST && typev[a->type->etype]) {
- gpseudo(ADATA, s, lo64(a));
- p->from.offset += o;
- p->from.scale = 4;
- gpseudo(ADATA, s, hi64(a));
- p->from.offset += o + 4;
- p->from.scale = 4;
- return;
- }
- gpseudo(ADATA, s, a);
- p->from.offset += o;
- p->from.scale = w;
- switch(p->to.type) {
- default:
- p->to.index = p->to.type;
- p->to.type = D_ADDR;
- case D_CONST:
- case D_FCONST:
- case D_ADDR:
- break;
- }
-}
-
-void
-outcode(void)
-{
- int f;
- Biobuf b;
-
- f = open(outfile, OWRITE);
- if(f < 0) {
- diag(Z, "cannot open %s", outfile);
- return;
- }
- Binit(&b, f, OWRITE);
-
- Bprint(&b, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
- if(pragcgobuf.to > pragcgobuf.start) {
- Bprint(&b, "\n");
- Bprint(&b, "$$ // exports\n\n");
- Bprint(&b, "$$ // local types\n\n");
- Bprint(&b, "$$ // cgo\n");
- Bprint(&b, "%s", fmtstrflush(&pragcgobuf));
- Bprint(&b, "\n$$\n\n");
- }
- Bprint(&b, "!\n");
-
- writeobj(ctxt, &b);
- Bterm(&b);
- close(f);
- lastp = P;
-}
-
-int32
-align(int32 i, Type *t, int op, int32 *maxalign)
-{
- int32 o;
- Type *v;
- int w, packw;
-
- o = i;
- w = 1;
- packw = 0;
- switch(op) {
- default:
- diag(Z, "unknown align opcode %d", op);
- break;
-
- case Asu2: /* padding at end of a struct */
- w = *maxalign;
- if(w < 1)
- w = 1;
- if(packflg)
- packw = packflg;
- break;
-
- case Ael1: /* initial align of struct element */
- for(v=t; v->etype==TARRAY; v=v->link)
- ;
- if(v->etype == TSTRUCT || v->etype == TUNION)
- w = v->align;
- else
- w = ewidth[v->etype];
- if(w < 1 || w > SZ_VLONG)
- fatal(Z, "align");
- if(packflg)
- packw = packflg;
- break;
-
- case Ael2: /* width of a struct element */
- o += t->width;
- break;
-
- case Aarg0: /* initial passbyptr argument in arg list */
- if(typesu[t->etype]) {
- o = align(o, types[TIND], Aarg1, nil);
- o = align(o, types[TIND], Aarg2, nil);
- }
- break;
-
- case Aarg1: /* initial align of parameter */
- if(ewidth[TIND] == 4) {
- if(typesu[t->etype]) {
- for(v = t->link; v != T; v = v->down)
- o = align(o, v, Aarg1, maxalign);
- goto out;
- }
- w = ewidth[t->etype];
- if(typev[t->etype] || t->etype == TDOUBLE)
- w = 8;
- else if(w <= 0 || w >= 4)
- w = 4;
- else
- w = 1;
- break;
- }
- w = ewidth[t->etype];
- if(w <= 0 || w >= SZ_VLONG) {
- w = SZ_VLONG;
- break;
- }
- w = 1; /* little endian no adjustment */
- break;
-
- case Aarg2: /* width of a parameter */
- o += t->width;
- if(ewidth[TIND] == 4) {
- o = align(o, t, Aarg1, maxalign);
- goto out;
- }
- w = t->width;
- if(w > SZ_VLONG)
- w = SZ_VLONG;
- break;
-
- case Aaut3: /* total align of automatic */
- o = align(o, t, Ael1, nil);
- o = align(o, t, Ael2, nil);
- break;
- }
- if(packw != 0 && xround(o, w) != xround(o, packw))
- diag(Z, "#pragma pack changes offset of %T", t);
- o = xround(o, w);
- if(maxalign && *maxalign < w)
- *maxalign = w;
-out:
- if(debug['A'])
- print("align %s %d %T = %d\n", bnames[op], i, t, o);
- return o;
-}
-
-int32
-maxround(int32 max, int32 v)
-{
- v = xround(v, SZ_VLONG);
- if(v > max)
- return v;
- return max;
-}
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
deleted file mode 100644
index 3bdbf410e..000000000
--- a/src/cmd/6c/txt.c
+++ /dev/null
@@ -1,1674 +0,0 @@
-// Inferno utils/6c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-int thechar = '6';
-char *thestring = "amd64";
-
-LinkArch *thelinkarch = &linkamd64;
-
-void
-linkarchinit(void)
-{
- if(strcmp(getgoarch(), "amd64p32") == 0)
- thelinkarch = &linkamd64p32;
-}
-
-void
-ginit(void)
-{
- int i;
- Type *t;
-
- dodefine("_64BITREG");
- if(ewidth[TIND] == 8)
- dodefine("_64BIT");
- listinit();
- nstring = 0;
- mnstring = 0;
- nrathole = 0;
- pc = 0;
- breakpc = -1;
- continpc = -1;
- cases = C;
- lastp = P;
- tfield = types[TINT];
-
- typeword = typechlvp;
- typecmplx = typesu;
-
- /* TO DO */
- memmove(typechlpv, typechlp, sizeof(typechlpv));
- typechlpv[TVLONG] = 1;
- typechlpv[TUVLONG] = 1;
-
- zprog.link = P;
- zprog.as = AGOK;
- zprog.from.type = D_NONE;
- zprog.from.index = D_NONE;
- zprog.from.scale = 0;
- zprog.to = zprog.from;
-
- lregnode.op = OREGISTER;
- lregnode.class = CEXREG;
- lregnode.reg = REGTMP;
- lregnode.complex = 0;
- lregnode.addable = 11;
- lregnode.type = types[TLONG];
-
- qregnode = lregnode;
- qregnode.type = types[TVLONG];
-
- constnode.op = OCONST;
- constnode.class = CXXX;
- constnode.complex = 0;
- constnode.addable = 20;
- constnode.type = types[TLONG];
-
- vconstnode = constnode;
- vconstnode.type = types[TVLONG];
-
- fconstnode.op = OCONST;
- fconstnode.class = CXXX;
- fconstnode.complex = 0;
- fconstnode.addable = 20;
- fconstnode.type = types[TDOUBLE];
-
- nodsafe = new(ONAME, Z, Z);
- nodsafe->sym = slookup(".safe");
- nodsafe->type = types[TINT];
- nodsafe->etype = types[TINT]->etype;
- nodsafe->class = CAUTO;
- complex(nodsafe);
-
- t = typ(TARRAY, types[TCHAR]);
- symrathole = slookup(".rathole");
- symrathole->class = CGLOBL;
- symrathole->type = t;
-
- nodrat = new(ONAME, Z, Z);
- nodrat->sym = symrathole;
- nodrat->type = types[TIND];
- nodrat->etype = TVOID;
- nodrat->class = CGLOBL;
- complex(nodrat);
- nodrat->type = t;
-
- nodret = new(ONAME, Z, Z);
- nodret->sym = slookup(".ret");
- nodret->type = types[TIND];
- nodret->etype = TIND;
- nodret->class = CPARAM;
- nodret = new(OIND, nodret, Z);
- complex(nodret);
-
- if(0)
- com64init();
-
- for(i=0; i<nelem(reg); i++) {
- reg[i] = 1;
- if(i >= D_AX && i <= D_R15 && i != D_SP)
- reg[i] = 0;
- if(i >= D_X0 && i <= D_X7)
- reg[i] = 0;
- }
- if(nacl) {
- reg[D_BP] = 1;
- reg[D_R15] = 1;
- }
-}
-
-void
-gclean(void)
-{
- int i;
- Sym *s;
-
- reg[D_SP]--;
- if(nacl) {
- reg[D_BP]--;
- reg[D_R15]--;
- }
- for(i=D_AX; i<=D_R15; i++)
- if(reg[i])
- diag(Z, "reg %R left allocated", i);
- for(i=D_X0; i<=D_X7; i++)
- if(reg[i])
- diag(Z, "reg %R left allocated", i);
- while(mnstring)
- outstring("", 1L);
- symstring->type->width = nstring;
- symrathole->type->width = nrathole;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type == T)
- continue;
- if(s->type->width == 0)
- continue;
- if(s->class != CGLOBL && s->class != CSTATIC)
- continue;
- if(s->type == types[TENUM])
- continue;
- gpseudo(AGLOBL, s, nodconst(s->type->width));
- }
- nextpc();
- p->as = AEND;
- outcode();
-}
-
-void
-nextpc(void)
-{
- Plist *pl;
-
- p = alloc(sizeof(*p));
- *p = zprog;
- p->lineno = nearln;
- p->pc = pc;
- pc++;
- if(lastp == nil) {
- pl = linknewplist(ctxt);
- pl->firstpc = p;
- } else
- lastp->link = p;
- lastp = p;
-}
-
-void
-gargs(Node *n, Node *tn1, Node *tn2)
-{
- int32 regs;
- Node fnxargs[20], *fnxp;
-
- regs = cursafe;
-
- fnxp = fnxargs;
- garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
-
- curarg = 0;
- fnxp = fnxargs;
- garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
-
- cursafe = regs;
-}
-
-int
-nareg(void)
-{
- int i, n;
-
- n = 0;
- for(i=D_AX; i<=D_R15; i++)
- if(reg[i] == 0)
- n++;
- return n;
-}
-
-void
-garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
-{
- Node nod;
-
- if(n == Z)
- return;
- if(n->op == OLIST) {
- garg1(n->left, tn1, tn2, f, fnxp);
- garg1(n->right, tn1, tn2, f, fnxp);
- return;
- }
- if(f == 0) {
- if(n->complex >= FNX) {
- regsalloc(*fnxp, n);
- nod = znode;
- nod.op = OAS;
- nod.left = *fnxp;
- nod.right = n;
- nod.type = n->type;
- cgen(&nod, Z);
- (*fnxp)++;
- }
- return;
- }
- if(typesu[n->type->etype]) {
- regaalloc(tn2, n);
- if(n->complex >= FNX) {
- sugen(*fnxp, tn2, n->type->width);
- (*fnxp)++;
- } else
- sugen(n, tn2, n->type->width);
- return;
- }
- if(REGARG >= 0 && curarg == 0 && typechlpv[n->type->etype]) {
- regaalloc1(tn1, n);
- if(n->complex >= FNX) {
- cgen(*fnxp, tn1);
- (*fnxp)++;
- } else
- cgen(n, tn1);
- return;
- }
- if(vconst(n) == 0) {
- regaalloc(tn2, n);
- gmove(n, tn2);
- return;
- }
- regalloc(tn1, n, Z);
- if(n->complex >= FNX) {
- cgen(*fnxp, tn1);
- (*fnxp)++;
- } else
- cgen(n, tn1);
- regaalloc(tn2, n);
- gmove(tn1, tn2);
- regfree(tn1);
-}
-
-Node*
-nodgconst(vlong v, Type *t)
-{
- if(!typev[t->etype])
- return nodconst((int32)v);
- vconstnode.vconst = v;
- return &vconstnode;
-}
-
-Node*
-nodconst(int32 v)
-{
- constnode.vconst = v;
- return &constnode;
-}
-
-Node*
-nodfconst(double d)
-{
- fconstnode.fconst = d;
- return &fconstnode;
-}
-
-int
-isreg(Node *n, int r)
-{
-
- if(n->op == OREGISTER)
- if(n->reg == r)
- return 1;
- return 0;
-}
-
-int
-nodreg(Node *n, Node *nn, int r)
-{
- int et;
-
- *n = qregnode;
- n->reg = r;
- if(nn != Z){
- et = nn->type->etype;
- if(!typefd[et] && nn->type->width <= SZ_LONG && 0)
- n->type = typeu[et]? types[TUINT]: types[TINT];
- else
- n->type = nn->type;
-//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]);
- n->lineno = nn->lineno;
- }
- if(reg[r] == 0)
- return 0;
- if(nn != Z) {
- if(nn->op == OREGISTER)
- if(nn->reg == r)
- return 0;
- }
- return 1;
-}
-
-void
-regret(Node *n, Node *nn, Type *t, int mode)
-{
- int r;
-
- if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET;
- nodreg(n, nn, r);
- reg[r]++;
- return;
- }
-
- if(mode == 1) {
- // fetch returned value after call.
- // already called gargs, so curarg is set.
- curarg = (curarg+7) & ~7;
- regaalloc(n, nn);
- return;
- }
-
- if(mode == 2) {
- // store value to be returned.
- // must compute arg offset.
- if(t->etype != TFUNC)
- fatal(Z, "bad regret func %T", t);
- *n = *nn;
- n->op = ONAME;
- n->class = CPARAM;
- n->sym = slookup(".ret");
- n->complex = nodret->complex;
- n->addable = 20;
- n->xoffset = argsize(0);
- return;
- }
-
- fatal(Z, "bad regret");
-}
-
-void
-regalloc(Node *n, Node *tn, Node *o)
-{
- int i;
-
- switch(tn->type->etype) {
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TIND:
- if(o != Z && o->op == OREGISTER) {
- i = o->reg;
- if(i >= D_AX && i <= D_R15)
- goto out;
- }
- for(i=D_AX; i<=D_R15; i++)
- if(reg[i] == 0)
- goto out;
- diag(tn, "out of fixed registers");
- goto err;
-
- case TFLOAT:
- case TDOUBLE:
- if(o != Z && o->op == OREGISTER) {
- i = o->reg;
- if(i >= D_X0 && i <= D_X7)
- goto out;
- }
- for(i=D_X0; i<=D_X7; i++)
- if(reg[i] == 0)
- goto out;
- diag(tn, "out of float registers");
- goto out;
- }
- diag(tn, "unknown type in regalloc: %T", tn->type);
-err:
- i = 0;
-out:
- if(i)
- reg[i]++;
- nodreg(n, tn, i);
-}
-
-void
-regialloc(Node *n, Node *tn, Node *o)
-{
- Node nod;
-
- nod = *tn;
- nod.type = types[TIND];
- regalloc(n, &nod, o);
-}
-
-void
-regfree(Node *n)
-{
- int i;
-
- i = 0;
- if(n->op != OREGISTER && n->op != OINDREG)
- goto err;
- i = n->reg;
- if(i < 0 || i >= nelem(reg))
- goto err;
- if(reg[i] <= 0)
- goto err;
- reg[i]--;
- return;
-err:
- diag(n, "error in regfree: %R", i);
-}
-
-void
-regsalloc(Node *n, Node *nn)
-{
- cursafe = align(cursafe, nn->type, Aaut3, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
- *n = *nodsafe;
- n->xoffset = -(stkoff + cursafe);
- n->type = nn->type;
- n->etype = nn->type->etype;
- n->lineno = nn->lineno;
-}
-
-void
-regaalloc1(Node *n, Node *nn)
-{
- if(REGARG < 0) {
- fatal(n, "regaalloc1 and REGARG<0");
- return;
- }
- nodreg(n, nn, REGARG);
- reg[(uchar)REGARG]++;
- curarg = align(curarg, nn->type, Aarg1, nil);
- curarg = align(curarg, nn->type, Aarg2, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regaalloc(Node *n, Node *nn)
-{
- curarg = align(curarg, nn->type, Aarg1, nil);
- *n = *nn;
- n->op = OINDREG;
- n->reg = REGSP;
- n->xoffset = curarg;
- n->complex = 0;
- n->addable = 20;
- curarg = align(curarg, nn->type, Aarg2, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regind(Node *n, Node *nn)
-{
-
- if(n->op != OREGISTER) {
- diag(n, "regind not OREGISTER");
- return;
- }
- n->op = OINDREG;
- n->type = nn->type;
-}
-
-void
-naddr(Node *n, Addr *a)
-{
- int32 v;
-
- a->type = D_NONE;
- if(n == Z)
- return;
- switch(n->op) {
- default:
- bad:
- diag(n, "bad in naddr: %O %D", n->op, a);
- break;
-
- case OREGISTER:
- a->type = n->reg;
- a->sym = nil;
- break;
-
- case OEXREG:
- a->type = D_INDIR + D_TLS;
- a->offset = n->reg - 1;
- break;
-
- case OIND:
- naddr(n->left, a);
- if(a->type >= D_AX && a->type <= D_R15)
- 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;
- break;
-
- case OINDEX:
- a->type = idx.ptr;
- if(n->left->op == OADDR || n->left->op == OCONST)
- naddr(n->left, a);
- if(a->type >= D_AX && a->type <= D_R15)
- 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;
- a->index = idx.reg;
- a->scale = n->scale;
- a->offset += n->xoffset;
- break;
-
- case OINDREG:
- a->type = n->reg+D_INDIR;
- a->sym = nil;
- a->offset = n->xoffset;
- break;
-
- case ONAME:
- a->etype = n->etype;
- a->type = D_STATIC;
- a->sym = linksym(n->sym);
- a->offset = n->xoffset;
- if(n->class == CSTATIC)
- break;
- if(n->class == CEXTERN || n->class == CGLOBL) {
- a->type = D_EXTERN;
- break;
- }
- if(n->class == CAUTO) {
- a->type = D_AUTO;
- break;
- }
- if(n->class == CPARAM) {
- a->type = D_PARAM;
- break;
- }
- goto bad;
-
- case OCONST:
- if(typefd[n->type->etype]) {
- a->type = D_FCONST;
- a->u.dval = n->fconst;
- break;
- }
- a->sym = nil;
- a->type = D_CONST;
- if(typev[n->type->etype] || (n->type->etype == TIND && ewidth[TIND] == 8))
- a->offset = n->vconst;
- else
- a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG);
- break;
-
- case OADDR:
- naddr(n->left, a);
- 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;
- }
- goto bad;
-
- case OADD:
- if(n->right->op == OCONST) {
- v = n->right->vconst;
- naddr(n->left, a);
- } else
- if(n->left->op == OCONST) {
- v = n->left->vconst;
- naddr(n->right, a);
- } else
- goto bad;
- a->offset += v;
- break;
-
- }
-}
-
-void
-gcmp(int op, Node *n, vlong val)
-{
- Node *cn, nod;
-
- cn = nodgconst(val, n->type);
- if(!immconst(cn)){
- regalloc(&nod, n, Z);
- gmove(cn, &nod);
- gopcode(op, n->type, n, &nod);
- regfree(&nod);
- }else
- gopcode(op, n->type, n, cn);
-}
-
-#define CASE(a,b) ((a<<8)|(b<<0))
-
-void
-gmove(Node *f, Node *t)
-{
- int ft, tt, t64, a;
- Node nod, nod1, nod2, nod3;
- Prog *p1, *p2;
-
- ft = f->type->etype;
- tt = t->type->etype;
- if(ewidth[TIND] == 4) {
- if(ft == TIND)
- ft = TUINT;
- if(tt == TIND)
- tt = TUINT;
- }
- t64 = tt == TVLONG || tt == TUVLONG || tt == TIND;
- if(debug['M'])
- print("gop: %O %O[%s],%O[%s]\n", OAS,
- f->op, tnames[ft], t->op, tnames[tt]);
- if(typefd[ft] && f->op == OCONST) {
- /* TO DO: pick up special constants, possibly preloaded */
- if(f->fconst == 0.0){
- regalloc(&nod, t, t);
- gins(AXORPD, &nod, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
- }
- }
-/*
- * load
- */
- if(ft == TVLONG || ft == TUVLONG)
- if(f->op == OCONST)
- if(f->vconst > 0x7fffffffLL || f->vconst < -0x7fffffffLL)
- if(t->op != OREGISTER) {
- regalloc(&nod, f, Z);
- gmove(f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
- }
-
- if(f->op == ONAME || f->op == OINDREG ||
- f->op == OIND || f->op == OINDEX)
- switch(ft) {
- case TCHAR:
- a = AMOVBLSX;
- if(t64)
- a = AMOVBQSX;
- goto ld;
- case TUCHAR:
- a = AMOVBLZX;
- if(t64)
- a = AMOVBQZX;
- goto ld;
- case TSHORT:
- a = AMOVWLSX;
- if(t64)
- a = AMOVWQSX;
- goto ld;
- case TUSHORT:
- a = AMOVWLZX;
- if(t64)
- a = AMOVWQZX;
- goto ld;
- case TINT:
- case TLONG:
- if(typefd[tt]) {
- regalloc(&nod, t, t);
- if(tt == TDOUBLE)
- a = ACVTSL2SD;
- else
- a = ACVTSL2SS;
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
- }
- a = AMOVL;
- if(t64)
- a = AMOVLQSX;
- goto ld;
- case TUINT:
- case TULONG:
- a = AMOVL;
- if(t64)
- a = AMOVLQZX; /* could probably use plain MOVL */
- goto ld;
- case TVLONG:
- if(typefd[tt]) {
- regalloc(&nod, t, t);
- if(tt == TDOUBLE)
- a = ACVTSQ2SD;
- else
- a = ACVTSQ2SS;
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
- }
- case TUVLONG:
- a = AMOVQ;
- goto ld;
- case TIND:
- a = AMOVQ;
- if(ewidth[TIND] == 4)
- a = AMOVL;
-
- ld:
- regalloc(&nod, f, t);
- nod.type = t64? types[TVLONG]: types[TINT];
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
-
- case TFLOAT:
- a = AMOVSS;
- goto fld;
- case TDOUBLE:
- a = AMOVSD;
- fld:
- regalloc(&nod, f, t);
- if(tt != TDOUBLE && tt != TFLOAT){ /* TO DO: why is this here */
- prtree(f, "odd tree");
- nod.type = t64? types[TVLONG]: types[TINT];
- }
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
- }
-
-/*
- * store
- */
- if(t->op == ONAME || t->op == OINDREG ||
- t->op == OIND || t->op == OINDEX)
- switch(tt) {
- case TCHAR:
- case TUCHAR:
- a = AMOVB; goto st;
- case TSHORT:
- case TUSHORT:
- a = AMOVW; goto st;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- a = AMOVL; goto st;
- case TVLONG:
- case TUVLONG:
- case TIND:
- a = AMOVQ; goto st;
-
- st:
- if(f->op == OCONST) {
- gins(a, f, t);
- return;
- }
- fst:
- regalloc(&nod, t, f);
- gmove(f, &nod);
- gins(a, &nod, t);
- regfree(&nod);
- return;
-
- case TFLOAT:
- a = AMOVSS;
- goto fst;
- case TDOUBLE:
- a = AMOVSD;
- goto fst;
- }
-
-/*
- * convert
- */
- switch(CASE(ft,tt)) {
- default:
-/*
- * integer to integer
- ********
- a = AGOK; break;
-
- case CASE( TCHAR, TCHAR):
- case CASE( TUCHAR, TCHAR):
- case CASE( TSHORT, TCHAR):
- case CASE( TUSHORT,TCHAR):
- case CASE( TINT, TCHAR):
- case CASE( TUINT, TCHAR):
- case CASE( TLONG, TCHAR):
- case CASE( TULONG, TCHAR):
-
- case CASE( TCHAR, TUCHAR):
- case CASE( TUCHAR, TUCHAR):
- case CASE( TSHORT, TUCHAR):
- case CASE( TUSHORT,TUCHAR):
- case CASE( TINT, TUCHAR):
- case CASE( TUINT, TUCHAR):
- case CASE( TLONG, TUCHAR):
- case CASE( TULONG, TUCHAR):
-
- case CASE( TSHORT, TSHORT):
- case CASE( TUSHORT,TSHORT):
- case CASE( TINT, TSHORT):
- case CASE( TUINT, TSHORT):
- case CASE( TLONG, TSHORT):
- case CASE( TULONG, TSHORT):
-
- case CASE( TSHORT, TUSHORT):
- case CASE( TUSHORT,TUSHORT):
- case CASE( TINT, TUSHORT):
- case CASE( TUINT, TUSHORT):
- case CASE( TLONG, TUSHORT):
- case CASE( TULONG, TUSHORT):
-
- case CASE( TINT, TINT):
- case CASE( TUINT, TINT):
- case CASE( TLONG, TINT):
- case CASE( TULONG, TINT):
-
- case CASE( TINT, TUINT):
- case CASE( TUINT, TUINT):
- case CASE( TLONG, TUINT):
- case CASE( TULONG, TUINT):
- *****/
- a = AMOVL;
- break;
-
- case CASE( TINT, TIND):
- case CASE( TINT, TVLONG):
- case CASE( TINT, TUVLONG):
- case CASE( TLONG, TIND):
- case CASE( TLONG, TVLONG):
- case CASE( TLONG, TUVLONG):
- a = AMOVLQSX;
- if(f->op == OCONST) {
- f->vconst &= (uvlong)0xffffffffU;
- if(f->vconst & 0x80000000)
- f->vconst |= (vlong)0xffffffff << 32;
- a = AMOVQ;
- }
- break;
-
- case CASE( TUINT, TIND):
- case CASE( TUINT, TVLONG):
- case CASE( TUINT, TUVLONG):
- case CASE( TULONG, TVLONG):
- case CASE( TULONG, TUVLONG):
- case CASE( TULONG, TIND):
- a = AMOVLQZX;
- if(f->op == OCONST) {
- f->vconst &= (uvlong)0xffffffffU;
- a = AMOVQ;
- }
- break;
-
- case CASE( TIND, TCHAR):
- case CASE( TIND, TUCHAR):
- case CASE( TIND, TSHORT):
- case CASE( TIND, TUSHORT):
- case CASE( TIND, TINT):
- case CASE( TIND, TUINT):
- case CASE( TIND, TLONG):
- case CASE( TIND, TULONG):
- case CASE( TVLONG, TCHAR):
- case CASE( TVLONG, TUCHAR):
- case CASE( TVLONG, TSHORT):
- case CASE( TVLONG, TUSHORT):
- case CASE( TVLONG, TINT):
- case CASE( TVLONG, TUINT):
- case CASE( TVLONG, TLONG):
- case CASE( TVLONG, TULONG):
- case CASE( TUVLONG, TCHAR):
- case CASE( TUVLONG, TUCHAR):
- case CASE( TUVLONG, TSHORT):
- case CASE( TUVLONG, TUSHORT):
- case CASE( TUVLONG, TINT):
- case CASE( TUVLONG, TUINT):
- case CASE( TUVLONG, TLONG):
- case CASE( TUVLONG, TULONG):
- a = AMOVQL;
- if(f->op == OCONST) {
- f->vconst &= (int)0xffffffffU;
- a = AMOVL;
- }
- break;
-
- case CASE( TIND, TIND):
- case CASE( TIND, TVLONG):
- case CASE( TIND, TUVLONG):
- case CASE( TVLONG, TIND):
- case CASE( TVLONG, TVLONG):
- case CASE( TVLONG, TUVLONG):
- case CASE( TUVLONG, TIND):
- case CASE( TUVLONG, TVLONG):
- case CASE( TUVLONG, TUVLONG):
- a = AMOVQ;
- break;
-
- case CASE( TSHORT, TINT):
- case CASE( TSHORT, TUINT):
- case CASE( TSHORT, TLONG):
- case CASE( TSHORT, TULONG):
- a = AMOVWLSX;
- if(f->op == OCONST) {
- f->vconst &= 0xffff;
- if(f->vconst & 0x8000)
- f->vconst |= 0xffff0000;
- a = AMOVL;
- }
- break;
-
- case CASE( TSHORT, TVLONG):
- case CASE( TSHORT, TUVLONG):
- case CASE( TSHORT, TIND):
- a = AMOVWQSX;
- if(f->op == OCONST) {
- f->vconst &= 0xffff;
- if(f->vconst & 0x8000){
- f->vconst |= 0xffff0000;
- f->vconst |= (vlong)~0 << 32;
- }
- a = AMOVL;
- }
- break;
-
- case CASE( TUSHORT,TINT):
- case CASE( TUSHORT,TUINT):
- case CASE( TUSHORT,TLONG):
- case CASE( TUSHORT,TULONG):
- a = AMOVWLZX;
- if(f->op == OCONST) {
- f->vconst &= 0xffff;
- a = AMOVL;
- }
- break;
-
- case CASE( TUSHORT,TVLONG):
- case CASE( TUSHORT,TUVLONG):
- case CASE( TUSHORT,TIND):
- a = AMOVWQZX;
- if(f->op == OCONST) {
- f->vconst &= 0xffff;
- a = AMOVL; /* MOVL also zero-extends to 64 bits */
- }
- break;
-
- case CASE( TCHAR, TSHORT):
- case CASE( TCHAR, TUSHORT):
- case CASE( TCHAR, TINT):
- case CASE( TCHAR, TUINT):
- case CASE( TCHAR, TLONG):
- case CASE( TCHAR, TULONG):
- a = AMOVBLSX;
- if(f->op == OCONST) {
- f->vconst &= 0xff;
- if(f->vconst & 0x80)
- f->vconst |= 0xffffff00;
- a = AMOVL;
- }
- break;
-
- case CASE( TCHAR, TVLONG):
- case CASE( TCHAR, TUVLONG):
- case CASE( TCHAR, TIND):
- a = AMOVBQSX;
- if(f->op == OCONST) {
- f->vconst &= 0xff;
- if(f->vconst & 0x80){
- f->vconst |= 0xffffff00;
- f->vconst |= (vlong)~0 << 32;
- }
- a = AMOVQ;
- }
- break;
-
- case CASE( TUCHAR, TSHORT):
- case CASE( TUCHAR, TUSHORT):
- case CASE( TUCHAR, TINT):
- case CASE( TUCHAR, TUINT):
- case CASE( TUCHAR, TLONG):
- case CASE( TUCHAR, TULONG):
- a = AMOVBLZX;
- if(f->op == OCONST) {
- f->vconst &= 0xff;
- a = AMOVL;
- }
- break;
-
- case CASE( TUCHAR, TVLONG):
- case CASE( TUCHAR, TUVLONG):
- case CASE( TUCHAR, TIND):
- a = AMOVBQZX;
- if(f->op == OCONST) {
- f->vconst &= 0xff;
- a = AMOVL; /* zero-extends to 64-bits */
- }
- break;
-
-/*
- * float to fix
- */
- case CASE( TFLOAT, TCHAR):
- case CASE( TFLOAT, TUCHAR):
- case CASE( TFLOAT, TSHORT):
- case CASE( TFLOAT, TUSHORT):
- case CASE( TFLOAT, TINT):
- case CASE( TFLOAT, TUINT):
- case CASE( TFLOAT, TLONG):
- case CASE( TFLOAT, TULONG):
- case CASE( TFLOAT, TVLONG):
- case CASE( TFLOAT, TUVLONG):
- case CASE( TFLOAT, TIND):
-
- case CASE( TDOUBLE,TCHAR):
- case CASE( TDOUBLE,TUCHAR):
- case CASE( TDOUBLE,TSHORT):
- case CASE( TDOUBLE,TUSHORT):
- case CASE( TDOUBLE,TINT):
- case CASE( TDOUBLE,TUINT):
- case CASE( TDOUBLE,TLONG):
- case CASE( TDOUBLE,TULONG):
- case CASE( TDOUBLE,TVLONG):
- case CASE( TDOUBLE,TUVLONG):
- case CASE( TDOUBLE,TIND):
- regalloc(&nod, t, Z);
- if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){
- if(ft == TFLOAT)
- a = ACVTTSS2SQ;
- else
- a = ACVTTSD2SQ;
- }else{
- if(ft == TFLOAT)
- a = ACVTTSS2SL;
- else
- a = ACVTTSD2SL;
- }
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
-
-/*
- * uvlong to float
- */
- case CASE( TUVLONG, TDOUBLE):
- case CASE( TUVLONG, TFLOAT):
- a = ACVTSQ2SS;
- if(tt == TDOUBLE)
- a = ACVTSQ2SD;
- regalloc(&nod, f, f);
- gmove(f, &nod);
- regalloc(&nod1, t, t);
- gins(ACMPQ, &nod, nodconst(0));
- gins(AJLT, Z, Z);
- p1 = p;
- gins(a, &nod, &nod1);
- gins(AJMP, Z, Z);
- p2 = p;
- patch(p1, pc);
- regalloc(&nod2, f, Z);
- regalloc(&nod3, f, Z);
- gmove(&nod, &nod2);
- gins(ASHRQ, nodconst(1), &nod2);
- gmove(&nod, &nod3);
- gins(AANDL, nodconst(1), &nod3);
- gins(AORQ, &nod3, &nod2);
- gins(a, &nod2, &nod1);
- gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1);
- regfree(&nod2);
- regfree(&nod3);
- patch(p2, pc);
- regfree(&nod);
- regfree(&nod1);
- return;
-
- case CASE( TULONG, TDOUBLE):
- case CASE( TUINT, TDOUBLE):
- case CASE( TULONG, TFLOAT):
- case CASE( TUINT, TFLOAT):
- a = ACVTSQ2SS;
- if(tt == TDOUBLE)
- a = ACVTSQ2SD;
- regalloc(&nod, f, f);
- gins(AMOVLQZX, f, &nod);
- regalloc(&nod1, t, t);
- gins(a, &nod, &nod1);
- gmove(&nod1, t);
- regfree(&nod);
- regfree(&nod1);
- return;
-
-/*
- * fix to float
- */
- case CASE( TCHAR, TFLOAT):
- case CASE( TUCHAR, TFLOAT):
- case CASE( TSHORT, TFLOAT):
- case CASE( TUSHORT,TFLOAT):
- case CASE( TINT, TFLOAT):
- case CASE( TLONG, TFLOAT):
- case CASE( TVLONG, TFLOAT):
- case CASE( TIND, TFLOAT):
-
- case CASE( TCHAR, TDOUBLE):
- case CASE( TUCHAR, TDOUBLE):
- case CASE( TSHORT, TDOUBLE):
- case CASE( TUSHORT,TDOUBLE):
- case CASE( TINT, TDOUBLE):
- case CASE( TLONG, TDOUBLE):
- case CASE( TVLONG, TDOUBLE):
- case CASE( TIND, TDOUBLE):
- regalloc(&nod, t, t);
- if(ewidth[ft] == SZ_VLONG){
- if(tt == TFLOAT)
- a = ACVTSQ2SS;
- else
- a = ACVTSQ2SD;
- }else{
- if(tt == TFLOAT)
- a = ACVTSL2SS;
- else
- a = ACVTSL2SD;
- }
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
-
-/*
- * float to float
- */
- case CASE( TFLOAT, TFLOAT):
- a = AMOVSS;
- break;
- case CASE( TDOUBLE,TFLOAT):
- a = ACVTSD2SS;
- break;
- case CASE( TFLOAT, TDOUBLE):
- a = ACVTSS2SD;
- break;
- case CASE( TDOUBLE,TDOUBLE):
- a = AMOVSD;
- break;
- }
- if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */
- if(samaddr(f, t))
- return;
- gins(a, f, t);
-}
-
-void
-doindex(Node *n)
-{
- Node nod, nod1;
- int32 v;
-
-if(debug['Y'])
-prtree(n, "index");
-
-if(n->left->complex >= FNX)
-print("botch in doindex\n");
-
- regalloc(&nod, &qregnode, Z);
- v = constnode.vconst;
- cgen(n->right, &nod);
- idx.ptr = D_NONE;
- if(n->left->op == OCONST)
- idx.ptr = D_CONST;
- else if(n->left->op == OREGISTER)
- idx.ptr = n->left->reg;
- else if(n->left->op != OADDR) {
- reg[D_BP]++; // can't be used as a base
- regalloc(&nod1, &qregnode, Z);
- cgen(n->left, &nod1);
- idx.ptr = nod1.reg;
- regfree(&nod1);
- reg[D_BP]--;
- }
- idx.reg = nod.reg;
- regfree(&nod);
- constnode.vconst = v;
-}
-
-void
-gins(int a, Node *f, Node *t)
-{
-
- if(f != Z && f->op == OINDEX)
- doindex(f);
- if(t != Z && t->op == OINDEX)
- doindex(t);
- nextpc();
- p->as = a;
- if(f != Z)
- naddr(f, &p->from);
- if(t != Z)
- naddr(t, &p->to);
- if(debug['g'])
- print("%P\n", p);
-}
-
-void
-gopcode(int o, Type *ty, Node *f, Node *t)
-{
- int a, et;
-
- et = TLONG;
- if(ty != T)
- et = ty->etype;
- if(et == TIND && ewidth[TIND] == 4)
- et = TUINT;
- if(debug['M']) {
- if(f != Z && f->type != T)
- print("gop: %O %O[%s],", o, f->op, tnames[et]);
- else
- print("gop: %O Z,", o);
- if(t != Z && t->type != T)
- print("%O[%s]\n", t->op, tnames[t->type->etype]);
- else
- print("Z\n");
- }
- a = AGOK;
- switch(o) {
- case OCOM:
- a = ANOTL;
- if(et == TCHAR || et == TUCHAR)
- a = ANOTB;
- if(et == TSHORT || et == TUSHORT)
- a = ANOTW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = ANOTQ;
- break;
-
- case ONEG:
- a = ANEGL;
- if(et == TCHAR || et == TUCHAR)
- a = ANEGB;
- if(et == TSHORT || et == TUSHORT)
- a = ANEGW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = ANEGQ;
- break;
-
- case OADDR:
- a = ALEAQ;
- break;
-
- case OASADD:
- case OADD:
- a = AADDL;
- if(et == TCHAR || et == TUCHAR)
- a = AADDB;
- if(et == TSHORT || et == TUSHORT)
- a = AADDW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = AADDQ;
- if(et == TFLOAT)
- a = AADDSS;
- if(et == TDOUBLE)
- a = AADDSD;
- break;
-
- case OASSUB:
- case OSUB:
- a = ASUBL;
- if(et == TCHAR || et == TUCHAR)
- a = ASUBB;
- if(et == TSHORT || et == TUSHORT)
- a = ASUBW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = ASUBQ;
- if(et == TFLOAT)
- a = ASUBSS;
- if(et == TDOUBLE)
- a = ASUBSD;
- break;
-
- case OASOR:
- case OOR:
- a = AORL;
- if(et == TCHAR || et == TUCHAR)
- a = AORB;
- if(et == TSHORT || et == TUSHORT)
- a = AORW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = AORQ;
- break;
-
- case OASAND:
- case OAND:
- a = AANDL;
- if(et == TCHAR || et == TUCHAR)
- a = AANDB;
- if(et == TSHORT || et == TUSHORT)
- a = AANDW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = AANDQ;
- break;
-
- case OASXOR:
- case OXOR:
- a = AXORL;
- if(et == TCHAR || et == TUCHAR)
- a = AXORB;
- if(et == TSHORT || et == TUSHORT)
- a = AXORW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = AXORQ;
- break;
-
- case OASLSHR:
- case OLSHR:
- a = ASHRL;
- if(et == TCHAR || et == TUCHAR)
- a = ASHRB;
- if(et == TSHORT || et == TUSHORT)
- a = ASHRW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = ASHRQ;
- break;
-
- case OASASHR:
- case OASHR:
- a = ASARL;
- if(et == TCHAR || et == TUCHAR)
- a = ASARB;
- if(et == TSHORT || et == TUSHORT)
- a = ASARW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = ASARQ;
- break;
-
- case OASASHL:
- case OASHL:
- a = ASALL;
- if(et == TCHAR || et == TUCHAR)
- a = ASALB;
- if(et == TSHORT || et == TUSHORT)
- a = ASALW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = ASALQ;
- break;
-
- case OROTL:
- a = AROLL;
- if(et == TCHAR || et == TUCHAR)
- a = AROLB;
- if(et == TSHORT || et == TUSHORT)
- a = AROLW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = AROLQ;
- break;
-
- case OFUNC:
- a = ACALL;
- break;
-
- case OASMUL:
- case OMUL:
- if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
- t = Z;
- a = AIMULL;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = AIMULQ;
- if(et == TFLOAT)
- a = AMULSS;
- if(et == TDOUBLE)
- a = AMULSD;
- break;
-
- case OASMOD:
- case OMOD:
- case OASDIV:
- case ODIV:
- a = AIDIVL;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = AIDIVQ;
- if(et == TFLOAT)
- a = ADIVSS;
- if(et == TDOUBLE)
- a = ADIVSD;
- break;
-
- case OASLMUL:
- case OLMUL:
- a = AMULL;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = AMULQ;
- break;
-
- case OASLMOD:
- case OLMOD:
- case OASLDIV:
- case OLDIV:
- a = ADIVL;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = ADIVQ;
- break;
-
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case OLO:
- case OLS:
- case OHS:
- case OHI:
- a = ACMPL;
- if(et == TCHAR || et == TUCHAR)
- a = ACMPB;
- if(et == TSHORT || et == TUSHORT)
- a = ACMPW;
- if(et == TVLONG || et == TUVLONG || et == TIND)
- a = ACMPQ;
- if(et == TFLOAT)
- a = AUCOMISS;
- if(et == TDOUBLE)
- a = AUCOMISD;
- gins(a, f, t);
- switch(o) {
- case OEQ: a = AJEQ; break;
- case ONE: a = AJNE; break;
- case OLT: a = AJLT; break;
- case OLE: a = AJLE; break;
- case OGE: a = AJGE; break;
- case OGT: a = AJGT; break;
- case OLO: a = AJCS; break;
- case OLS: a = AJLS; break;
- case OHS: a = AJCC; break;
- case OHI: a = AJHI; break;
- }
- gins(a, Z, Z);
- return;
- }
- if(a == AGOK)
- diag(Z, "bad in gopcode %O", o);
- gins(a, f, t);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
- return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
-}
-
-void
-gbranch(int o)
-{
- int a;
-
- a = AGOK;
- switch(o) {
- case ORETURN:
- a = ARET;
- break;
- case OGOTO:
- a = AJMP;
- break;
- }
- nextpc();
- if(a == AGOK) {
- diag(Z, "bad in gbranch %O", o);
- nextpc();
- }
- p->as = a;
-}
-
-void
-patch(Prog *op, int32 pc)
-{
- op->to.offset = pc;
- op->to.type = D_BRANCH;
- op->to.u.branch = nil;
- op->pcond = nil;
-}
-
-void
-gpseudo(int a, Sym *s, Node *n)
-{
-
- nextpc();
- p->as = a;
- p->from.type = D_EXTERN;
- p->from.sym = linksym(s);
-
- switch(a) {
- case ATEXT:
- p->from.scale = textflag;
- textflag = 0;
- break;
- case AGLOBL:
- p->from.scale = s->dataflag;
- break;
- }
-
- if(s->class == CSTATIC)
- p->from.type = D_STATIC;
- naddr(n, &p->to);
- if(a == ADATA || a == AGLOBL)
- pc--;
-}
-
-void
-gpcdata(int index, int value)
-{
- Node n1;
-
- n1 = *nodconst(index);
- gins(APCDATA, &n1, nodconst(value));
-}
-
-void
-gprefetch(Node *n)
-{
- Node n1;
-
- regalloc(&n1, n, Z);
- gmove(n, &n1);
- n1.op = OINDREG;
- gins(APREFETCHNTA, &n1, Z);
- regfree(&n1);
-}
-
-int
-sconst(Node *n)
-{
- int32 v;
-
- if(n->op == OCONST && !typefd[n->type->etype]) {
- v = n->vconst;
- if(v >= -32766L && v < 32766L)
- return 1;
- }
- return 0;
-}
-
-int32
-exreg(Type *t)
-{
- int32 o;
-
- if(typechlpv[t->etype]) {
- if(exregoffset >= 64)
- return 0;
- o = exregoffset;
- exregoffset += ewidth[TIND];
- return o+1; // +1 to avoid 0 == failure; naddr's case OEXREG will subtract 1.
- }
- return 0;
-}
-
-schar ewidth[NTYPE] =
-{
- -1, /*[TXXX]*/
- SZ_CHAR, /*[TCHAR]*/
- SZ_CHAR, /*[TUCHAR]*/
- SZ_SHORT, /*[TSHORT]*/
- SZ_SHORT, /*[TUSHORT]*/
- SZ_INT, /*[TINT]*/
- SZ_INT, /*[TUINT]*/
- SZ_LONG, /*[TLONG]*/
- SZ_LONG, /*[TULONG]*/
- SZ_VLONG, /*[TVLONG]*/
- SZ_VLONG, /*[TUVLONG]*/
- SZ_FLOAT, /*[TFLOAT]*/
- SZ_DOUBLE, /*[TDOUBLE]*/
- SZ_IND, /*[TIND]*/
- 0, /*[TFUNC]*/
- -1, /*[TARRAY]*/
- 0, /*[TVOID]*/
- -1, /*[TSTRUCT]*/
- -1, /*[TUNION]*/
- SZ_INT, /*[TENUM]*/
-};
-int32 ncast[NTYPE] =
-{
- 0, /*[TXXX]*/
- BCHAR|BUCHAR, /*[TCHAR]*/
- BCHAR|BUCHAR, /*[TUCHAR]*/
- BSHORT|BUSHORT, /*[TSHORT]*/
- BSHORT|BUSHORT, /*[TUSHORT]*/
- BINT|BUINT|BLONG|BULONG, /*[TINT]*/
- BINT|BUINT|BLONG|BULONG, /*[TUINT]*/
- BINT|BUINT|BLONG|BULONG, /*[TLONG]*/
- BINT|BUINT|BLONG|BULONG, /*[TULONG]*/
- BVLONG|BUVLONG|BIND, /*[TVLONG]*/
- BVLONG|BUVLONG|BIND, /*[TUVLONG]*/
- BFLOAT, /*[TFLOAT]*/
- BDOUBLE, /*[TDOUBLE]*/
- BVLONG|BUVLONG|BIND, /*[TIND]*/
- 0, /*[TFUNC]*/
- 0, /*[TARRAY]*/
- 0, /*[TVOID]*/
- BSTRUCT, /*[TSTRUCT]*/
- BUNION, /*[TUNION]*/
- 0, /*[TENUM]*/
-};
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
index 04e837b13..dbb4ff62c 100644
--- a/src/cmd/6g/gobj.c
+++ b/src/cmd/6g/gobj.c
@@ -81,7 +81,7 @@ datagostring(Strlit *sval, Addr *a)
a->sym = linksym(sym);
a->node = sym->def;
a->offset = 0; // header
- a->etype = TINT32;
+ a->etype = TSTRING;
}
void
diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h
index dbd039d89..493171ef8 100644
--- a/src/cmd/6g/opt.h
+++ b/src/cmd/6g/opt.h
@@ -63,8 +63,8 @@ enum
uint32 BLOAD(Reg*);
uint32 BSTORE(Reg*);
-uint32 LOAD(Reg*);
-uint32 STORE(Reg*);
+uint64 LOAD(Reg*);
+uint64 STORE(Reg*);
*/
// A Reg is a wrapper around a single Prog (one instruction) that holds
@@ -75,12 +75,18 @@ struct Reg
{
Flow f;
- Bits set; // variables written by this instruction.
- Bits use1; // variables read by prog->from.
- Bits use2; // variables read by prog->to.
+ Bits set; // regopt variables written by this instruction.
+ Bits use1; // regopt variables read by prog->from.
+ Bits use2; // regopt variables read by prog->to.
+ // refahead/refbehind are the regopt variables whose current
+ // value may be used in the following/preceding instructions
+ // up to a CALL (or the value is clobbered).
Bits refbehind;
Bits refahead;
+ // calahead/calbehind are similar, but for variables in
+ // instructions that are reachable after hitting at least one
+ // CALL.
Bits calbehind;
Bits calahead;
Bits regdiff;
@@ -93,6 +99,16 @@ struct Reg
#define NRGN 600
/*c2go enum { NRGN = 600 }; */
+
+// A Rgn represents a single regopt variable over a region of code
+// where a register could potentially be dedicated to that variable.
+// The code encompassed by a Rgn is defined by the flow graph,
+// starting at enter, flood-filling forward while varno is refahead
+// and backward while varno is refbehind, and following branches. A
+// single variable may be represented by multiple disjoint Rgns and
+// each Rgn may choose a different register for that variable.
+// Registers are allocated to regions greedily in order of descending
+// cost.
struct Rgn
{
Reg* enter;
@@ -140,8 +156,8 @@ void prop(Reg*, Bits, Bits);
void synch(Reg*, Bits);
uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
-uint32 paint2(Reg*, int);
-void paint3(Reg*, int, int32, int);
+uint32 paint2(Reg*, int, int);
+void paint3(Reg*, int, uint32, int);
void addreg(Adr*, int);
void dumpone(Flow*, int);
void dumpit(char*, Flow*, int);
@@ -153,10 +169,10 @@ void peep(Prog*);
void excise(Flow*);
int copyu(Prog*, Adr*, Adr*);
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
+uint32 RtoB(int);
+uint32 FtoB(int);
+int BtoR(uint32);
+int BtoF(uint32);
/*
* prog.c
@@ -165,8 +181,8 @@ typedef struct ProgInfo ProgInfo;
struct ProgInfo
{
uint32 flags; // the bits below
- uint32 reguse; // required registers used by this instruction
- uint32 regset; // required registers set by this instruction
+ uint32 reguse; // registers implicitly used by this instruction
+ uint32 regset; // registers implicitly set by this instruction
uint32 regindex; // registers used by addressing mode
};
@@ -187,12 +203,12 @@ enum
SizeF = 1<<7, // float aka float32
SizeD = 1<<8, // double aka float64
- // Left side: address taken, read, write.
+ // Left side (Prog.from): address taken, read, write.
LeftAddr = 1<<9,
LeftRead = 1<<10,
LeftWrite = 1<<11,
- // Right side: address taken, read, write.
+ // Right side (Prog.to): address taken, read, write.
RightAddr = 1<<12,
RightRead = 1<<13,
RightWrite = 1<<14,
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index 1f757e197..f3dc59b14 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -34,7 +34,7 @@
#include "opt.h"
#define NREGVAR 32 /* 16 general + 16 floating */
-#define REGBITS ((uint32)0xffffffff)
+#define REGBITS ((uint64)0xffffffffull)
/*c2go enum {
NREGVAR = 32,
REGBITS = 0xffffffff,
@@ -71,7 +71,7 @@ setaddrs(Bits bit)
i = bnum(bit);
node = var[i].node;
n = var[i].name;
- bit.b[i/32] &= ~(1L<<(i%32));
+ biclr(&bit, i);
// disable all pieces of that variable
for(i=0; i<nvar; i++) {
@@ -364,7 +364,7 @@ loop2:
rgp->varno = i;
change = 0;
paint1(r, i);
- bit.b[i/32] &= ~(1L<<(i%32));
+ biclr(&bit, i);
if(change <= 0)
continue;
rgp->cost = change;
@@ -389,9 +389,13 @@ brk:
* replace code (paint3)
*/
rgp = region;
+ if(debug['R'] && debug['v'])
+ print("\nregisterizing\n");
for(i=0; i<nregion; i++) {
+ if(debug['R'] && debug['v'])
+ print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(vreg, rgp);
if(rgp->regno != 0) {
if(debug['R'] && debug['v']) {
@@ -406,9 +410,6 @@ brk:
rgp++;
}
- if(debug['R'] && debug['v'])
- dumpit("pass6", &firstr->f, 1);
-
/*
* free aux structures. peep allocates new ones.
*/
@@ -417,6 +418,15 @@ brk:
flowend(g);
firstr = R;
+ if(debug['R'] && debug['v']) {
+ // Rebuild flow graph, since we inserted instructions
+ g = flowstart(firstp, sizeof(Reg));
+ firstr = (Reg*)g->start;
+ dumpit("pass6", &firstr->f, 1);
+ flowend(g);
+ firstr = R;
+ }
+
/*
* pass 7
* peep-hole on basic block
@@ -477,7 +487,7 @@ walkvardef(Node *n, Reg *r, int active)
break;
for(v=n->opt; v!=nil; v=v->nextinnode) {
bn = v - var;
- r1->act.b[bn/32] |= 1L << (bn%32);
+ biset(&r1->act, bn);
}
if(r1->f.prog->as == ACALL)
break;
@@ -621,6 +631,9 @@ mkvar(Reg *r, Adr *a)
if(r != R)
r->use1.b[0] |= doregbits(a->index);
+ if(t >= D_INDIR && t < 2*D_INDIR)
+ goto none;
+
switch(t) {
default:
regu = doregbits(t);
@@ -822,10 +835,10 @@ prop(Reg *r, Bits ref, Bits cal)
for(z=0; z<BITS; z++) {
if(cal.b[z] == 0)
continue;
- for(i=0; i<32; i++) {
- if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
+ for(i=0; i<64; i++) {
+ if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
continue;
- v = var+z*32+i;
+ v = var+z*64+i;
if(v->node->opt == nil) // v represents fixed register, not Go variable
continue;
@@ -841,10 +854,10 @@ prop(Reg *r, Bits ref, Bits cal)
// This will set the bits at most twice, keeping the overall loop linear.
v1 = v->node->opt;
j = v1 - var;
- if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
+ if(v == v1 || !btest(&cal, j)) {
for(; v1 != nil; v1 = v1->nextinnode) {
j = v1 - var;
- cal.b[j/32] |= 1UL<<(j&31);
+ biset(&cal, j);
}
}
}
@@ -959,10 +972,10 @@ paint1(Reg *r, int bn)
{
Reg *r1;
int z;
- uint32 bb;
+ uint64 bb;
- z = bn/32;
- bb = 1L<<(bn%32);
+ z = bn/64;
+ bb = 1LL<<(bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@@ -1017,54 +1030,14 @@ paint1(Reg *r, int bn)
}
uint32
-regset(Reg *r, uint32 bb)
-{
- uint32 b, set;
- Adr v;
- int c;
-
- set = 0;
- v = zprog.from;
- while(b = bb & ~(bb-1)) {
- v.type = b & 0xFFFF? BtoR(b): BtoF(b);
- if(v.type == 0)
- fatal("zero v.type for %#ux", b);
- c = copyu(r->f.prog, &v, nil);
- if(c == 3)
- set |= b;
- bb &= ~b;
- }
- return set;
-}
-
-uint32
-reguse(Reg *r, uint32 bb)
-{
- uint32 b, set;
- Adr v;
- int c;
-
- set = 0;
- v = zprog.from;
- while(b = bb & ~(bb-1)) {
- v.type = b & 0xFFFF? BtoR(b): BtoF(b);
- c = copyu(r->f.prog, &v, nil);
- if(c == 1 || c == 2 || c == 4)
- set |= b;
- bb &= ~b;
- }
- return set;
-}
-
-uint32
-paint2(Reg *r, int bn)
+paint2(Reg *r, int bn, int depth)
{
Reg *r1;
int z;
- uint32 bb, vreg, x;
+ uint64 bb, vreg;
- z = bn/32;
- bb = 1L << (bn%32);
+ z = bn/64;
+ bb = 1LL << (bn%64);
vreg = regbits;
if(!(r->act.b[z] & bb))
return vreg;
@@ -1081,6 +1054,9 @@ paint2(Reg *r, int bn)
r = r1;
}
for(;;) {
+ if(debug['R'] && debug['v'])
+ print(" paint2 %d %P\n", depth, r->f.prog);
+
r->act.b[z] &= ~bb;
vreg |= r->regu;
@@ -1088,14 +1064,14 @@ paint2(Reg *r, int bn)
if(r->refbehind.b[z] & bb)
for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
if(!(r->refahead.b[z] & bb))
break;
r1 = (Reg*)r->f.s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
r = (Reg*)r->f.s1;
if(r == R)
break;
@@ -1105,27 +1081,19 @@ paint2(Reg *r, int bn)
break;
}
- bb = vreg;
- for(; r; r=(Reg*)r->f.s1) {
- x = r->regu & ~bb;
- if(x) {
- vreg |= reguse(r, x);
- bb |= regset(r, x);
- }
- }
return vreg;
}
void
-paint3(Reg *r, int bn, int32 rb, int rn)
+paint3(Reg *r, int bn, uint32 rb, int rn)
{
Reg *r1;
Prog *p;
int z;
- uint32 bb;
+ uint64 bb;
- z = bn/32;
- bb = 1L << (bn%32);
+ z = bn/64;
+ bb = 1LL << (bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@@ -1198,7 +1166,7 @@ addreg(Adr *a, int rn)
ostats.ncvtreg++;
}
-int32
+uint32
RtoB(int r)
{
@@ -1208,7 +1176,7 @@ RtoB(int r)
}
int
-BtoR(int32 b)
+BtoR(uint32 b)
{
b &= 0xffffL;
if(nacl)
@@ -1224,7 +1192,7 @@ BtoR(int32 b)
* ...
* 31 X15
*/
-int32
+uint32
FtoB(int f)
{
if(f < D_X0 || f > D_X15)
@@ -1233,7 +1201,7 @@ FtoB(int f)
}
int
-BtoF(int32 b)
+BtoF(uint32 b)
{
b &= 0xFFFF0000L;
@@ -1304,12 +1272,14 @@ dumpit(char *str, Flow *r0, int isreg)
print(" %.4ud", (int)r1->prog->pc);
print("\n");
}
-// r1 = r->s1;
-// if(r1 != R) {
-// print(" succ:");
-// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", (int)r1->prog->pc);
-// print("\n");
-// }
+ // Print successors if it's not just the next one
+ if(r->s1 != r->link || r->s2 != nil) {
+ print(" succ:");
+ if(r->s1 != nil)
+ print(" %.4ud", (int)r->s1->prog->pc);
+ if(r->s2 != nil)
+ print(" %.4ud", (int)r->s2->prog->pc);
+ print("\n");
+ }
}
}
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index af72784e8..c09ac2824 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -865,6 +865,8 @@ enum
D_INDIR, /* additive */
+ D_LAST,
+
T_TYPE = 1<<0,
T_INDEX = 1<<1,
T_OFFSET = 1<<2,
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
index adc388ca9..a1aca07ae 100644
--- a/src/cmd/8a/a.h
+++ b/src/cmd/8a/a.h
@@ -70,6 +70,7 @@ struct Sym
int32 value;
ushort type;
char *name;
+ char* labelname;
char sym;
};
#define S ((Sym*)0)
@@ -148,6 +149,8 @@ void newio(void);
void newfile(char*, int);
Sym* slookup(char*);
Sym* lookup(void);
+Sym* labellookup(Sym*);
+void settext(LSym*);
void syminit(Sym*);
int32 yylex(void);
int getc(void);
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
index 6bcf1313b..c810d3857 100644
--- a/src/cmd/8a/a.y
+++ b/src/cmd/8a/a.y
@@ -74,15 +74,11 @@ prog:
line
line:
- LLAB ':'
- {
- if($1->value != pc)
- yyerror("redeclaration of %s", $1->name);
- $1->value = pc;
- }
- line
-| LNAME ':'
+ LNAME ':'
{
+ $1 = labellookup($1);
+ if($1->type == LLAB && $1->value != pc)
+ yyerror("redeclaration of %s", $1->labelname);
$1->type = LLAB;
$1->value = pc;
}
@@ -199,11 +195,13 @@ spec1: /* DATA */
spec2: /* TEXT */
mem ',' imm2
{
+ settext($1.sym);
$$.from = $1;
$$.to = $3;
}
| mem ',' con ',' imm2
{
+ settext($1.sym);
$$.from = $1;
$$.from.scale = $3;
$$.to = $5;
@@ -362,15 +360,10 @@ rel:
}
| LNAME offset
{
+ $1 = labellookup($1);
$$ = nullgen;
- if(pass == 2)
- yyerror("undefined label: %s", $1->name);
- $$.type = D_BRANCH;
- $$.offset = $2;
- }
-| LLAB offset
- {
- $$ = nullgen;
+ if(pass == 2 && $1->type != LLAB)
+ yyerror("undefined label: %s", $1->labelname);
$$.type = D_BRANCH;
$$.offset = $1->value + $2;
}
diff --git a/src/cmd/8a/y.tab.c b/src/cmd/8a/y.tab.c
index 85279c21f..f284d8ea2 100644
--- a/src/cmd/8a/y.tab.c
+++ b/src/cmd/8a/y.tab.c
@@ -411,16 +411,16 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 2
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 546
+#define YYLAST 561
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 54
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 41
+#define YYNNTS 40
/* YYNRULES -- Number of rules. */
-#define YYNRULES 135
+#define YYNRULES 132
/* YYNRULES -- Number of states. */
-#define YYNSTATES 276
+#define YYNSTATES 270
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
@@ -469,91 +469,90 @@ static const yytype_uint8 yytranslate[] =
YYRHS. */
static const yytype_uint16 yyprhs[] =
{
- 0, 0, 3, 4, 5, 9, 10, 15, 16, 21,
- 23, 26, 29, 33, 37, 40, 43, 46, 49, 52,
+ 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, 91, 92, 94, 98, 102, 105, 107, 110,
- 112, 115, 117, 121, 127, 131, 137, 140, 142, 145,
- 147, 149, 153, 159, 163, 169, 172, 174, 178, 182,
- 188, 194, 200, 204, 208, 210, 212, 214, 216, 219,
- 222, 224, 226, 228, 230, 232, 237, 240, 243, 245,
- 247, 249, 251, 253, 255, 258, 261, 264, 267, 272,
- 278, 282, 285, 287, 290, 294, 299, 301, 303, 305,
- 310, 315, 322, 332, 342, 346, 350, 355, 361, 370,
- 372, 379, 385, 393, 394, 397, 400, 402, 404, 406,
- 408, 410, 413, 416, 419, 423, 425, 429, 433, 437,
- 441, 445, 450, 455, 459, 463
+ 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
};
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
static const yytype_int8 yyrhs[] =
{
55, 0, -1, -1, -1, 55, 56, 57, -1, -1,
- 44, 46, 58, 57, -1, -1, 43, 46, 59, 57,
- -1, 47, -1, 60, 47, -1, 1, 47, -1, 43,
- 48, 94, -1, 45, 48, 94, -1, 13, 61, -1,
- 14, 65, -1, 15, 64, -1, 16, 62, -1, 17,
- 63, -1, 21, 66, -1, 19, 67, -1, 22, 68,
- -1, 18, 69, -1, 20, 70, -1, 23, 71, -1,
- 24, 72, -1, 25, 73, -1, 26, 74, -1, 27,
- 75, -1, 28, 76, -1, 29, 77, -1, 30, 78,
- -1, -1, 49, -1, 81, 49, 79, -1, 79, 49,
- 81, -1, 81, 49, -1, 81, -1, 49, 79, -1,
- 79, -1, 49, 82, -1, 82, -1, 84, 49, 82,
- -1, 90, 11, 93, 49, 84, -1, 87, 49, 85,
- -1, 87, 49, 93, 49, 85, -1, 49, 80, -1,
- 80, -1, 10, 90, -1, 61, -1, 65, -1, 81,
- 49, 79, -1, 81, 49, 79, 46, 36, -1, 81,
- 49, 79, -1, 81, 49, 79, 46, 37, -1, 81,
- 49, -1, 81, -1, 81, 49, 79, -1, 87, 49,
- 84, -1, 87, 49, 93, 49, 84, -1, 83, 49,
- 79, 49, 93, -1, 84, 49, 79, 49, 83, -1,
- 81, 49, 81, -1, 81, 49, 81, -1, 83, -1,
- 87, -1, 82, -1, 89, -1, 10, 83, -1, 10,
- 88, -1, 83, -1, 88, -1, 84, -1, 79, -1,
- 84, -1, 93, 50, 33, 51, -1, 43, 91, -1,
- 44, 91, -1, 35, -1, 38, -1, 36, -1, 39,
- -1, 42, -1, 37, -1, 52, 93, -1, 52, 90,
- -1, 52, 41, -1, 52, 40, -1, 52, 50, 40,
- 51, -1, 52, 50, 9, 40, 51, -1, 52, 9,
- 40, -1, 52, 86, -1, 31, -1, 9, 31, -1,
- 31, 9, 31, -1, 9, 31, 9, 31, -1, 88,
- -1, 89, -1, 93, -1, 93, 50, 36, 51, -1,
- 93, 50, 42, 51, -1, 93, 50, 36, 10, 93,
- 51, -1, 93, 50, 36, 51, 50, 36, 10, 93,
- 51, -1, 93, 50, 36, 51, 50, 37, 10, 93,
- 51, -1, 50, 36, 51, -1, 50, 42, 51, -1,
- 93, 50, 37, 51, -1, 50, 36, 10, 93, 51,
- -1, 50, 36, 51, 50, 36, 10, 93, 51, -1,
- 90, -1, 90, 50, 36, 10, 93, 51, -1, 43,
- 91, 50, 92, 51, -1, 43, 6, 7, 91, 50,
- 34, 51, -1, -1, 8, 93, -1, 9, 93, -1,
- 34, -1, 42, -1, 32, -1, 31, -1, 45, -1,
- 9, 93, -1, 8, 93, -1, 53, 93, -1, 50,
- 94, 51, -1, 93, -1, 94, 8, 94, -1, 94,
- 9, 94, -1, 94, 10, 94, -1, 94, 11, 94,
- -1, 94, 12, 94, -1, 94, 6, 6, 94, -1,
- 94, 7, 7, 94, -1, 94, 5, 94, -1, 94,
- 4, 94, -1, 94, 3, 94, -1
+ 43, 46, 58, 57, -1, 47, -1, 59, 47, -1,
+ 1, 47, -1, 43, 48, 93, -1, 45, 48, 93,
+ -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
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 69, 69, 71, 70, 78, 77, 85, 84, 90,
- 91, 92, 95, 100, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
- 122, 123, 126, 130, 137, 144, 151, 156, 163, 168,
- 175, 180, 185, 192, 200, 205, 213, 218, 223, 232,
- 233, 236, 241, 251, 256, 266, 271, 276, 283, 288,
- 296, 304, 314, 323, 334, 335, 338, 339, 340, 344,
- 348, 349, 350, 353, 354, 357, 363, 371, 379, 384,
- 389, 394, 399, 404, 411, 417, 428, 434, 440, 446,
- 452, 460, 469, 474, 479, 484, 491, 492, 495, 501,
- 507, 513, 522, 531, 540, 545, 550, 556, 564, 574,
- 578, 587, 594, 603, 606, 610, 616, 617, 621, 624,
- 625, 629, 633, 637, 641, 647, 648, 652, 656, 660,
- 664, 668, 672, 676, 680, 684
+ 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
};
#endif
@@ -569,10 +568,10 @@ static const char *const yytname[] =
"LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG", "LFREG",
"LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB", "LVAR", "':'",
"';'", "'='", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog", "@1",
- "line", "@2", "@3", "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",
+ "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
};
#endif
@@ -594,39 +593,39 @@ static const yytype_uint16 yytoknum[] =
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] =
{
- 0, 54, 55, 56, 55, 58, 57, 59, 57, 57,
- 57, 57, 60, 60, 60, 60, 60, 60, 60, 60,
- 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
- 60, 60, 61, 61, 62, 63, 64, 64, 65, 65,
- 66, 66, 66, 67, 68, 68, 69, 69, 69, 70,
- 70, 71, 71, 72, 72, 73, 73, 73, 74, 74,
- 75, 76, 77, 78, 79, 79, 80, 80, 80, 80,
- 80, 80, 80, 81, 81, 82, 82, 82, 83, 83,
- 83, 83, 83, 83, 84, 84, 84, 84, 84, 84,
- 84, 85, 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, 94,
- 94, 94, 94, 94, 94, 94
+ 0, 54, 55, 56, 55, 58, 57, 57, 57, 57,
+ 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,
+ 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
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
static const yytype_uint8 yyr2[] =
{
- 0, 2, 0, 0, 3, 0, 4, 0, 4, 1,
- 2, 2, 3, 3, 2, 2, 2, 2, 2, 2,
+ 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,
- 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, 3, 1, 1, 1, 1, 2, 2,
- 1, 1, 1, 1, 1, 4, 2, 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
+ 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, 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
};
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -634,89 +633,85 @@ static const yytype_uint8 yyr2[] =
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 2, 3, 1, 0, 0, 32, 0, 0, 0, 0,
- 0, 0, 32, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 9, 4, 0, 11,
- 33, 14, 0, 0, 119, 78, 80, 83, 79, 81,
- 82, 113, 120, 0, 0, 0, 15, 39, 64, 65,
- 96, 97, 109, 98, 0, 16, 73, 37, 74, 17,
- 0, 18, 0, 0, 113, 113, 0, 22, 47, 66,
- 70, 72, 71, 67, 98, 20, 0, 33, 49, 50,
- 23, 113, 0, 0, 19, 41, 0, 0, 21, 0,
- 24, 0, 25, 0, 26, 56, 27, 0, 28, 0,
- 29, 0, 30, 0, 31, 0, 7, 0, 5, 0,
- 10, 122, 121, 0, 0, 0, 0, 38, 0, 0,
- 125, 0, 123, 0, 0, 0, 87, 86, 0, 85,
- 84, 36, 0, 0, 68, 69, 48, 76, 77, 0,
- 46, 0, 0, 76, 40, 0, 0, 0, 0, 0,
- 55, 0, 0, 0, 0, 0, 0, 12, 0, 13,
- 113, 114, 115, 0, 0, 104, 105, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 124, 0, 0,
- 0, 0, 90, 0, 0, 34, 35, 0, 0, 42,
- 0, 44, 0, 51, 53, 57, 58, 0, 0, 0,
- 62, 63, 8, 6, 0, 118, 116, 117, 0, 0,
- 0, 135, 134, 133, 0, 0, 126, 127, 128, 129,
- 130, 0, 0, 99, 106, 100, 0, 88, 75, 0,
- 0, 92, 91, 0, 0, 0, 0, 0, 0, 0,
- 111, 107, 0, 131, 132, 0, 0, 0, 89, 43,
- 93, 0, 45, 52, 54, 59, 60, 61, 0, 0,
- 110, 101, 0, 0, 0, 94, 112, 0, 0, 0,
- 95, 108, 0, 0, 102, 103
+ 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, 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
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
- -1, 1, 3, 27, 158, 156, 28, 31, 59, 61,
- 55, 46, 84, 75, 88, 67, 80, 90, 92, 94,
- 96, 98, 100, 102, 104, 56, 68, 57, 69, 48,
- 58, 191, 232, 49, 50, 51, 52, 116, 208, 53,
- 121
+ -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
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -104
+#define YYPACT_NINF -89
static const yytype_int16 yypact[] =
{
- -104, 4, -104, 173, -26, -25, 277, 297, 297, 349,
- 225, -14, 329, 396, 18, 297, 297, 297, 18, 171,
- -20, 297, 297, 2, -4, 26, -104, -104, 43, -104,
- -104, -104, 478, 478, -104, -104, -104, -104, -104, -104,
- -104, 111, -104, 349, 402, 478, -104, -104, -104, -104,
- -104, -104, -12, -5, 83, -104, -104, 44, -104, -104,
- 46, -104, 49, 349, 111, 113, 245, -104, -104, -104,
- -104, -104, -104, -104, 50, -104, 100, 349, -104, -104,
- -104, 113, 420, 478, -104, -104, 64, 66, -104, 78,
- -104, 80, -104, 85, -104, 89, -104, 93, -104, 98,
- -104, 101, -104, 112, -104, 121, -104, 478, -104, 478,
- -104, -104, -104, 153, 478, 478, 135, -104, 8, 163,
- -104, 74, -104, 179, 52, 427, -104, -104, 445, -104,
- -104, -104, 349, 297, -104, -104, -104, 135, -104, 381,
- -104, 33, 478, -104, -104, 420, 186, 451, 349, 349,
- 349, 460, 349, 349, 297, 297, 173, 172, 173, 172,
- 113, -104, -104, 5, 478, 180, -104, 478, 478, 478,
- 226, 224, 478, 478, 478, 478, 478, -104, 235, 36,
- 195, 196, -104, 466, 197, -104, -104, 199, 202, -104,
- 21, -104, 203, 211, 219, -104, -104, 217, 222, 223,
- -104, -104, -104, -104, 229, -104, -104, -104, 240, 241,
- 237, 232, 527, 534, 478, 478, 134, 134, -104, -104,
- -104, 478, 478, 243, -104, -104, 248, -104, -104, -20,
- 263, 287, -104, 249, 264, 265, -20, 478, 171, 269,
- -104, -104, 294, 214, 214, 256, 258, 119, -104, -104,
- 301, 280, -104, -104, -104, -104, -104, -104, 266, 478,
- -104, -104, 308, 311, 292, -104, -104, 273, 478, 478,
- -104, -104, 274, 278, -104, -104
+ -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
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] =
{
- -104, -104, -104, -103, -104, -104, -104, 319, -104, -104,
- -104, 331, -104, -104, -104, -104, -104, -104, -104, -104,
- -104, -104, -104, -104, -104, 19, 275, -2, -6, -9,
- -8, 115, -104, 22, 1, -1, -3, -48, -104, -10,
- -66
+ -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
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
@@ -726,120 +721,124 @@ static const yytype_int16 yypgoto[] =
#define YYTABLE_NINF -1
static const yytype_uint16 yytable[] =
{
- 74, 70, 71, 87, 2, 86, 60, 85, 76, 73,
- 99, 72, 101, 91, 93, 95, 137, 138, 164, 103,
- 105, 29, 111, 112, 30, 47, 32, 33, 62, 41,
- 230, 47, 54, 143, 120, 122, 89, 205, 123, 206,
- 97, 157, 108, 159, 130, 124, 222, 207, 106, 34,
- 107, 129, 231, 202, 134, 203, 74, 70, 71, 165,
- 136, 41, 117, 42, 135, 73, 187, 72, 44, 179,
- 180, 45, 87, 120, 109, 181, 144, 167, 168, 169,
- 170, 171, 172, 173, 174, 175, 176, 223, 179, 180,
- 110, 32, 125, 131, 181, 132, 117, 120, 133, 120,
- 141, 211, 212, 213, 161, 162, 216, 217, 218, 219,
- 220, 142, 204, 145, 34, 112, 146, 113, 120, 114,
- 115, 114, 115, 126, 127, 177, 41, 147, 42, 148,
- 134, 186, 188, 128, 149, 87, 45, 192, 150, 189,
- 135, 197, 151, 196, 174, 175, 176, 152, 243, 244,
- 153, 185, 200, 201, 209, 262, 263, 120, 120, 120,
- 160, 154, 120, 120, 120, 120, 120, 193, 194, 195,
- 155, 198, 199, 112, 4, 167, 168, 169, 170, 171,
- 172, 173, 174, 175, 176, 163, 5, 6, 7, 8,
- 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 120, 120, 35, 36, 37, 38,
- 39, 245, 246, 40, 166, 178, 23, 24, 25, 187,
- 26, 249, 172, 173, 174, 175, 176, 256, 255, 257,
- 210, 215, 214, 32, 33, 63, 168, 169, 170, 171,
- 172, 173, 174, 175, 176, 221, 224, 225, 227, 267,
- 228, 229, 233, 32, 33, 139, 34, 234, 272, 273,
- 35, 36, 37, 38, 39, 235, 236, 40, 64, 65,
- 42, 237, 238, 242, 66, 44, 34, 54, 45, 239,
- 35, 36, 37, 38, 39, 32, 33, 40, 64, 65,
- 42, 240, 241, 247, 250, 44, 251, 54, 45, 248,
- 253, 190, 254, 258, 259, 32, 33, 260, 34, 261,
- 264, 265, 35, 36, 37, 38, 39, 266, 268, 40,
- 41, 269, 42, 270, 271, 274, 43, 44, 34, 275,
- 45, 78, 35, 36, 37, 38, 39, 32, 33, 40,
- 41, 140, 42, 79, 0, 0, 0, 44, 252, 54,
- 45, 0, 0, 0, 0, 0, 0, 32, 33, 0,
- 34, 0, 0, 0, 35, 36, 37, 38, 39, 0,
- 0, 40, 41, 0, 42, 0, 0, 0, 77, 44,
- 34, 0, 45, 0, 35, 36, 37, 38, 39, 32,
- 33, 40, 41, 0, 42, 0, 0, 0, 0, 44,
- 0, 0, 45, 0, 32, 33, 0, 0, 0, 0,
- 32, 33, 34, 0, 0, 0, 35, 36, 37, 38,
- 39, 0, 0, 40, 0, 0, 42, 34, 32, 33,
- 0, 44, 0, 34, 45, 32, 33, 0, 118, 81,
- 65, 42, 0, 0, 119, 82, 83, 42, 54, 45,
- 0, 34, 83, 32, 183, 45, 0, 0, 34, 32,
- 33, 0, 0, 81, 65, 42, 0, 182, 32, 33,
- 83, 0, 42, 45, 32, 33, 34, 83, 0, 0,
- 45, 0, 34, 0, 0, 184, 32, 33, 0, 0,
- 42, 34, 0, 0, 0, 83, 42, 34, 45, 0,
- 0, 83, 0, 190, 45, 42, 226, 0, 0, 34,
- 83, 42, 54, 45, 0, 0, 83, 0, 0, 45,
- 0, 0, 0, 42, 0, 0, 0, 0, 83, 0,
- 0, 45, 169, 170, 171, 172, 173, 174, 175, 176,
- 170, 171, 172, 173, 174, 175, 176
+ 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
};
static const yytype_int16 yycheck[] =
{
- 10, 10, 10, 13, 0, 13, 8, 13, 11, 10,
- 19, 10, 20, 15, 16, 17, 64, 65, 10, 21,
- 22, 47, 32, 33, 49, 6, 8, 9, 9, 43,
- 9, 12, 52, 81, 44, 45, 14, 32, 50, 34,
- 18, 107, 46, 109, 54, 50, 10, 42, 46, 31,
- 48, 54, 31, 156, 63, 158, 66, 66, 66, 51,
- 63, 43, 43, 45, 63, 66, 33, 66, 50, 36,
- 37, 53, 82, 83, 48, 42, 82, 3, 4, 5,
- 6, 7, 8, 9, 10, 11, 12, 51, 36, 37,
- 47, 8, 9, 49, 42, 49, 77, 107, 49, 109,
- 50, 167, 168, 169, 114, 115, 172, 173, 174, 175,
- 176, 11, 160, 49, 31, 125, 50, 6, 128, 8,
- 9, 8, 9, 40, 41, 51, 43, 49, 45, 49,
- 139, 133, 142, 50, 49, 145, 53, 147, 49, 145,
- 139, 151, 49, 151, 10, 11, 12, 49, 214, 215,
- 49, 132, 154, 155, 164, 36, 37, 167, 168, 169,
- 7, 49, 172, 173, 174, 175, 176, 148, 149, 150,
- 49, 152, 153, 183, 1, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 50, 13, 14, 15, 16,
- 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
- 27, 28, 29, 30, 214, 215, 35, 36, 37, 38,
- 39, 221, 222, 42, 51, 36, 43, 44, 45, 33,
- 47, 229, 8, 9, 10, 11, 12, 237, 236, 238,
- 50, 7, 6, 8, 9, 10, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 10, 51, 51, 51, 259,
- 51, 49, 49, 8, 9, 10, 31, 46, 268, 269,
- 35, 36, 37, 38, 39, 46, 49, 42, 43, 44,
- 45, 49, 49, 36, 49, 50, 31, 52, 53, 50,
- 35, 36, 37, 38, 39, 8, 9, 42, 43, 44,
- 45, 51, 51, 50, 31, 50, 9, 52, 53, 51,
- 36, 52, 37, 34, 10, 8, 9, 51, 31, 51,
- 9, 31, 35, 36, 37, 38, 39, 51, 10, 42,
- 43, 10, 45, 31, 51, 51, 49, 50, 31, 51,
- 53, 12, 35, 36, 37, 38, 39, 8, 9, 42,
- 43, 66, 45, 12, -1, -1, -1, 50, 233, 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, 8, 9, -1, 36, 43,
- 44, 45, -1, -1, 42, 49, 50, 45, 52, 53,
- -1, 31, 50, 8, 9, 53, -1, -1, 31, 8,
- 9, -1, -1, 43, 44, 45, -1, 40, 8, 9,
- 50, -1, 45, 53, 8, 9, 31, 50, -1, -1,
- 53, -1, 31, -1, -1, 40, 8, 9, -1, -1,
- 45, 31, -1, -1, -1, 50, 45, 31, 53, -1,
- -1, 50, -1, 52, 53, 45, 40, -1, -1, 31,
- 50, 45, 52, 53, -1, -1, 50, -1, -1, 53,
- -1, -1, -1, 45, -1, -1, -1, -1, 50, -1,
- -1, 53, 5, 6, 7, 8, 9, 10, 11, 12,
- 6, 7, 8, 9, 10, 11, 12
+ 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
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -848,32 +847,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, 44, 45, 47, 57, 60, 47,
- 49, 61, 8, 9, 31, 35, 36, 37, 38, 39,
- 42, 43, 45, 49, 50, 53, 65, 79, 83, 87,
- 88, 89, 90, 93, 52, 64, 79, 81, 84, 62,
- 81, 63, 79, 10, 43, 44, 49, 69, 80, 82,
- 83, 84, 88, 89, 93, 67, 90, 49, 61, 65,
- 70, 43, 49, 50, 66, 82, 84, 93, 68, 87,
- 71, 81, 72, 81, 73, 81, 74, 87, 75, 83,
- 76, 84, 77, 81, 78, 81, 46, 48, 46, 48,
- 47, 93, 93, 6, 8, 9, 91, 79, 36, 42,
- 93, 94, 93, 50, 50, 9, 40, 41, 50, 90,
- 93, 49, 49, 49, 83, 88, 90, 91, 91, 10,
- 80, 50, 11, 91, 82, 49, 50, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 59, 94, 58, 94,
- 7, 93, 93, 50, 10, 51, 51, 3, 4, 5,
- 6, 7, 8, 9, 10, 11, 12, 51, 36, 36,
- 37, 42, 40, 9, 40, 79, 81, 33, 93, 82,
- 52, 85, 93, 79, 79, 79, 84, 93, 79, 79,
- 81, 81, 57, 57, 91, 32, 34, 42, 92, 93,
- 50, 94, 94, 94, 6, 7, 94, 94, 94, 94,
- 94, 10, 10, 51, 51, 51, 40, 51, 51, 49,
- 9, 31, 86, 49, 46, 46, 49, 49, 49, 50,
- 51, 51, 36, 94, 94, 93, 93, 50, 51, 84,
- 31, 9, 85, 36, 37, 84, 93, 83, 34, 10,
- 51, 51, 36, 37, 9, 31, 51, 93, 10, 10,
- 31, 51, 93, 93, 51, 51
+ 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
};
#define yyerrok (yyerrstatus = 0)
@@ -1697,30 +1695,24 @@ yyreduce:
case 5:
#line 78 "a.y"
{
- if((yyvsp[(1) - (2)].sym)->value != pc)
- yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
- (yyvsp[(1) - (2)].sym)->value = pc;
- }
- break;
-
- case 7:
-#line 85 "a.y"
- {
+ (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
+ if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc)
+ yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->labelname);
(yyvsp[(1) - (2)].sym)->type = LLAB;
(yyvsp[(1) - (2)].sym)->value = pc;
}
break;
- case 12:
-#line 96 "a.y"
+ case 10:
+#line 92 "a.y"
{
(yyvsp[(1) - (3)].sym)->type = LVAR;
(yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
}
break;
- case 13:
-#line 101 "a.y"
+ case 11:
+#line 97 "a.y"
{
if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
@@ -1728,186 +1720,186 @@ yyreduce:
}
break;
+ case 12:
+#line 102 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+ break;
+
+ case 13:
+#line 103 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+ break;
+
case 14:
-#line 106 "a.y"
+#line 104 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 15:
-#line 107 "a.y"
+#line 105 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 16:
-#line 108 "a.y"
+#line 106 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 17:
-#line 109 "a.y"
+#line 107 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 18:
-#line 110 "a.y"
+#line 108 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 19:
-#line 111 "a.y"
+#line 109 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 20:
-#line 112 "a.y"
+#line 110 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 21:
-#line 113 "a.y"
+#line 111 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 22:
-#line 114 "a.y"
+#line 112 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 23:
-#line 115 "a.y"
+#line 113 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 24:
-#line 116 "a.y"
+#line 114 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 25:
-#line 117 "a.y"
+#line 115 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 26:
-#line 118 "a.y"
+#line 116 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 27:
-#line 119 "a.y"
+#line 117 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 28:
-#line 120 "a.y"
+#line 118 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 29:
-#line 121 "a.y"
+#line 119 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 30:
#line 122 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 31:
-#line 123 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 32:
-#line 126 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = nullgen;
}
break;
- case 33:
-#line 131 "a.y"
+ case 31:
+#line 127 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = nullgen;
}
break;
- case 34:
-#line 138 "a.y"
+ case 32:
+#line 134 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 35:
-#line 145 "a.y"
+ case 33:
+#line 141 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 36:
-#line 152 "a.y"
+ case 34:
+#line 148 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
(yyval.addr2).to = nullgen;
}
break;
- case 37:
-#line 157 "a.y"
+ case 35:
+#line 153 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
(yyval.addr2).to = nullgen;
}
break;
- case 38:
-#line 164 "a.y"
+ case 36:
+#line 160 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
- case 39:
-#line 169 "a.y"
+ case 37:
+#line 165 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
- case 40:
-#line 176 "a.y"
+ case 38:
+#line 172 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
- case 41:
-#line 181 "a.y"
+ case 39:
+#line 177 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
- case 42:
-#line 186 "a.y"
+ case 40:
+#line 182 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 43:
-#line 193 "a.y"
+ case 41:
+#line 189 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
(yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
@@ -1915,41 +1907,43 @@ yyreduce:
}
break;
- case 44:
-#line 201 "a.y"
+ 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);
}
break;
- case 45:
-#line 206 "a.y"
+ 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);
}
break;
- case 46:
-#line 214 "a.y"
+ case 44:
+#line 212 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
- case 47:
-#line 219 "a.y"
+ case 45:
+#line 217 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
- case 48:
-#line 224 "a.y"
+ case 46:
+#line 222 "a.y"
{
(yyval.addr2).from = nullgen;
(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
@@ -1958,16 +1952,16 @@ yyreduce:
}
break;
- case 51:
-#line 237 "a.y"
+ case 49:
+#line 235 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 52:
-#line 242 "a.y"
+ case 50:
+#line 240 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
@@ -1977,16 +1971,16 @@ yyreduce:
}
break;
- case 53:
-#line 252 "a.y"
+ case 51:
+#line 250 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 54:
-#line 257 "a.y"
+ case 52:
+#line 255 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
@@ -1996,40 +1990,40 @@ yyreduce:
}
break;
- case 55:
-#line 267 "a.y"
+ case 53:
+#line 265 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
(yyval.addr2).to = nullgen;
}
break;
- case 56:
-#line 272 "a.y"
+ case 54:
+#line 270 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
(yyval.addr2).to = nullgen;
}
break;
- case 57:
-#line 277 "a.y"
+ case 55:
+#line 275 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 58:
-#line 284 "a.y"
+ case 56:
+#line 282 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
- case 59:
-#line 289 "a.y"
+ case 57:
+#line 287 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
(yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
@@ -2037,8 +2031,8 @@ yyreduce:
}
break;
- case 60:
-#line 297 "a.y"
+ case 58:
+#line 295 "a.y"
{
(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
@@ -2046,8 +2040,8 @@ yyreduce:
}
break;
- case 61:
-#line 305 "a.y"
+ case 59:
+#line 303 "a.y"
{
(yyval.addr2).from = (yyvsp[(3) - (5)].addr);
(yyval.addr2).to = (yyvsp[(5) - (5)].addr);
@@ -2057,8 +2051,8 @@ yyreduce:
}
break;
- case 62:
-#line 315 "a.y"
+ case 60:
+#line 313 "a.y"
{
if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST)
yyerror("arguments to PCDATA must be integer constants");
@@ -2067,8 +2061,8 @@ yyreduce:
}
break;
- case 63:
-#line 324 "a.y"
+ case 61:
+#line 322 "a.y"
{
if((yyvsp[(1) - (3)].addr).type != D_CONST)
yyerror("index for FUNCDATA must be integer constant");
@@ -2079,22 +2073,22 @@ yyreduce:
}
break;
- case 68:
-#line 341 "a.y"
+ case 66:
+#line 339 "a.y"
{
(yyval.addr) = (yyvsp[(2) - (2)].addr);
}
break;
- case 69:
-#line 345 "a.y"
+ case 67:
+#line 343 "a.y"
{
(yyval.addr) = (yyvsp[(2) - (2)].addr);
}
break;
- case 75:
-#line 358 "a.y"
+ case 73:
+#line 356 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_BRANCH;
@@ -2102,76 +2096,68 @@ yyreduce:
}
break;
- case 76:
-#line 364 "a.y"
- {
- (yyval.addr) = nullgen;
- if(pass == 2)
- yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
- (yyval.addr).type = D_BRANCH;
- (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 77:
-#line 372 "a.y"
+ case 74:
+#line 362 "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).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
}
break;
- case 78:
-#line 380 "a.y"
+ case 75:
+#line 373 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 79:
-#line 385 "a.y"
+ case 76:
+#line 378 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 80:
-#line 390 "a.y"
+ case 77:
+#line 383 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 81:
-#line 395 "a.y"
+ case 78:
+#line 388 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 82:
-#line 400 "a.y"
+ case 79:
+#line 393 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_SP;
}
break;
- case 83:
-#line 405 "a.y"
+ case 80:
+#line 398 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 84:
-#line 412 "a.y"
+ case 81:
+#line 405 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_CONST;
@@ -2179,8 +2165,8 @@ yyreduce:
}
break;
- case 85:
-#line 418 "a.y"
+ case 82:
+#line 411 "a.y"
{
(yyval.addr) = (yyvsp[(2) - (2)].addr);
(yyval.addr).index = (yyvsp[(2) - (2)].addr).type;
@@ -2193,8 +2179,8 @@ yyreduce:
}
break;
- case 86:
-#line 429 "a.y"
+ case 83:
+#line 422 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_SCONST;
@@ -2202,8 +2188,8 @@ yyreduce:
}
break;
- case 87:
-#line 435 "a.y"
+ case 84:
+#line 428 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FCONST;
@@ -2211,8 +2197,8 @@ yyreduce:
}
break;
- case 88:
-#line 441 "a.y"
+ case 85:
+#line 434 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FCONST;
@@ -2220,8 +2206,8 @@ yyreduce:
}
break;
- case 89:
-#line 447 "a.y"
+ case 86:
+#line 440 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FCONST;
@@ -2229,8 +2215,8 @@ yyreduce:
}
break;
- case 90:
-#line 453 "a.y"
+ case 87:
+#line 446 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_FCONST;
@@ -2238,8 +2224,8 @@ yyreduce:
}
break;
- case 91:
-#line 461 "a.y"
+ case 88:
+#line 454 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_CONST2;
@@ -2248,40 +2234,40 @@ yyreduce:
}
break;
- case 92:
-#line 470 "a.y"
+ case 89:
+#line 463 "a.y"
{
(yyval.con2).v1 = (yyvsp[(1) - (1)].lval);
(yyval.con2).v2 = ArgsSizeUnknown;
}
break;
- case 93:
-#line 475 "a.y"
+ case 90:
+#line 468 "a.y"
{
(yyval.con2).v1 = -(yyvsp[(2) - (2)].lval);
(yyval.con2).v2 = ArgsSizeUnknown;
}
break;
- case 94:
-#line 480 "a.y"
+ case 91:
+#line 473 "a.y"
{
(yyval.con2).v1 = (yyvsp[(1) - (3)].lval);
(yyval.con2).v2 = (yyvsp[(3) - (3)].lval);
}
break;
- case 95:
-#line 485 "a.y"
+ case 92:
+#line 478 "a.y"
{
(yyval.con2).v1 = -(yyvsp[(2) - (4)].lval);
(yyval.con2).v2 = (yyvsp[(4) - (4)].lval);
}
break;
- case 98:
-#line 496 "a.y"
+ case 95:
+#line 489 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+D_NONE;
@@ -2289,8 +2275,8 @@ yyreduce:
}
break;
- case 99:
-#line 502 "a.y"
+ case 96:
+#line 495 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
@@ -2298,8 +2284,8 @@ yyreduce:
}
break;
- case 100:
-#line 508 "a.y"
+ case 97:
+#line 501 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+D_SP;
@@ -2307,8 +2293,8 @@ yyreduce:
}
break;
- case 101:
-#line 514 "a.y"
+ case 98:
+#line 507 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+D_NONE;
@@ -2319,8 +2305,8 @@ yyreduce:
}
break;
- case 102:
-#line 523 "a.y"
+ case 99:
+#line 516 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
@@ -2331,8 +2317,8 @@ yyreduce:
}
break;
- case 103:
-#line 532 "a.y"
+ case 100:
+#line 525 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
@@ -2343,24 +2329,24 @@ yyreduce:
}
break;
- case 104:
-#line 541 "a.y"
+ case 101:
+#line 534 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval);
}
break;
- case 105:
-#line 546 "a.y"
+ case 102:
+#line 539 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+D_SP;
}
break;
- case 106:
-#line 551 "a.y"
+ case 103:
+#line 544 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
@@ -2368,8 +2354,8 @@ yyreduce:
}
break;
- case 107:
-#line 557 "a.y"
+ case 104:
+#line 550 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+D_NONE;
@@ -2379,8 +2365,8 @@ yyreduce:
}
break;
- case 108:
-#line 565 "a.y"
+ case 105:
+#line 558 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_INDIR+(yyvsp[(2) - (8)].lval);
@@ -2390,15 +2376,15 @@ yyreduce:
}
break;
- case 109:
-#line 575 "a.y"
+ case 106:
+#line 568 "a.y"
{
(yyval.addr) = (yyvsp[(1) - (1)].addr);
}
break;
- case 110:
-#line 579 "a.y"
+ case 107:
+#line 572 "a.y"
{
(yyval.addr) = (yyvsp[(1) - (6)].addr);
(yyval.addr).index = (yyvsp[(3) - (6)].lval);
@@ -2407,8 +2393,8 @@ yyreduce:
}
break;
- case 111:
-#line 588 "a.y"
+ case 108:
+#line 581 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = (yyvsp[(4) - (5)].lval);
@@ -2417,8 +2403,8 @@ yyreduce:
}
break;
- case 112:
-#line 595 "a.y"
+ case 109:
+#line 588 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = D_STATIC;
@@ -2427,134 +2413,134 @@ yyreduce:
}
break;
- case 113:
-#line 603 "a.y"
+ case 110:
+#line 596 "a.y"
{
(yyval.lval) = 0;
}
break;
- case 114:
-#line 607 "a.y"
+ case 111:
+#line 600 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
- case 115:
-#line 611 "a.y"
+ case 112:
+#line 604 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
- case 117:
-#line 618 "a.y"
+ case 114:
+#line 611 "a.y"
{
(yyval.lval) = D_AUTO;
}
break;
- case 120:
-#line 626 "a.y"
+ case 117:
+#line 619 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
}
break;
- case 121:
-#line 630 "a.y"
+ case 118:
+#line 623 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
- case 122:
-#line 634 "a.y"
+ case 119:
+#line 627 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
- case 123:
-#line 638 "a.y"
+ case 120:
+#line 631 "a.y"
{
(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
}
break;
- case 124:
-#line 642 "a.y"
+ case 121:
+#line 635 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (3)].lval);
}
break;
- case 126:
-#line 649 "a.y"
+ case 123:
+#line 642 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
}
break;
- case 127:
-#line 653 "a.y"
+ case 124:
+#line 646 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
}
break;
- case 128:
-#line 657 "a.y"
+ case 125:
+#line 650 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
}
break;
- case 129:
-#line 661 "a.y"
+ case 126:
+#line 654 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
}
break;
- case 130:
-#line 665 "a.y"
+ case 127:
+#line 658 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
}
break;
- case 131:
-#line 669 "a.y"
+ case 128:
+#line 662 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
}
break;
- case 132:
-#line 673 "a.y"
+ case 129:
+#line 666 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
}
break;
- case 133:
-#line 677 "a.y"
+ case 130:
+#line 670 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
}
break;
- case 134:
-#line 681 "a.y"
+ case 131:
+#line 674 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
}
break;
- case 135:
-#line 685 "a.y"
+ case 132:
+#line 678 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
}
@@ -2562,7 +2548,7 @@ yyreduce:
/* Line 1267 of yacc.c. */
-#line 2566 "y.tab.c"
+#line 2552 "y.tab.c"
default: break;
}
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
diff --git a/src/cmd/8c/Makefile b/src/cmd/8c/Makefile
deleted file mode 100644
index 3f528d751..000000000
--- a/src/cmd/8c/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2012 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.
-
-include ../../Make.dist
diff --git a/src/cmd/8c/cgen.c b/src/cmd/8c/cgen.c
deleted file mode 100644
index 87e8fdad8..000000000
--- a/src/cmd/8c/cgen.c
+++ /dev/null
@@ -1,1939 +0,0 @@
-// Inferno utils/8c/cgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-/* ,x/^(print|prtree)\(/i/\/\/ */
-
-void
-cgen(Node *n, Node *nn)
-{
- Node *l, *r, *t;
- Prog *p1;
- Node nod, nod1, nod2, nod3, nod4;
- int o, hardleft;
- int32 v, curs;
- vlong c;
-
- if(debug['g']) {
- prtree(nn, "cgen lhs");
- prtree(n, "cgen");
- }
- if(n == Z || n->type == T)
- return;
- if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) {
- sugen(n, nn, n->type->width);
- return;
- }
- l = n->left;
- r = n->right;
- o = n->op;
-
- if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) {
- gmove(n, nn);
- return;
- }
-
- if(n->addable >= INDEXED) {
- if(nn == Z) {
- switch(o) {
- default:
- nullwarn(Z, Z);
- break;
- case OINDEX:
- nullwarn(l, r);
- break;
- }
- return;
- }
- gmove(n, nn);
- return;
- }
- curs = cursafe;
-
- if(l->complex >= FNX)
- if(r != Z && r->complex >= FNX)
- switch(o) {
- default:
- if(cond(o) && typesuv[l->type->etype])
- break;
-
- regret(&nod, r, 0, 0);
- cgen(r, &nod);
-
- regsalloc(&nod1, r);
- gmove(&nod, &nod1);
-
- regfree(&nod);
- nod = *n;
- nod.right = &nod1;
-
- cgen(&nod, nn);
- return;
-
- case OFUNC:
- case OCOMMA:
- case OANDAND:
- case OOROR:
- case OCOND:
- case ODOT:
- break;
- }
-
- hardleft = l->addable < INDEXED || l->complex >= FNX;
- switch(o) {
- default:
- diag(n, "unknown op in cgen: %O", o);
- break;
-
- case ONEG:
- case OCOM:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- gopcode(o, n->type, Z, &nod);
- gmove(&nod, nn);
- regfree(&nod);
- break;
-
- case OAS:
- if(typefd[n->type->etype]) {
- cgen(r, &fregnode0);
- if(nn != Z)
- gins(AFMOVD, &fregnode0, &fregnode0);
- if(l->addable < INDEXED) {
- reglcgen(&nod, l, Z);
- gmove(&fregnode0, &nod);
- regfree(&nod);
- } else
- gmove(&fregnode0, l);
- if(nn != Z)
- gmove(&fregnode0, nn);
- return;
- }
- if(l->op == OBIT)
- goto bitas;
- if(!hardleft) {
- if(nn != Z || r->addable < INDEXED) {
- if(r->complex >= FNX && nn == Z)
- regret(&nod, r, 0, 0);
- else
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- gmove(&nod, l);
- if(nn != Z)
- gmove(&nod, nn);
- regfree(&nod);
- } else
- gmove(r, l);
- break;
- }
- if(l->complex >= r->complex) {
- if(l->op == OINDEX && r->op == OCONST) {
- gmove(r, l);
- break;
- }
- reglcgen(&nod1, l, Z);
- if(r->addable >= INDEXED) {
- gmove(r, &nod1);
- if(nn != Z)
- gmove(r, nn);
- regfree(&nod1);
- break;
- }
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- } else {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- reglcgen(&nod1, l, Z);
- }
- gmove(&nod, &nod1);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- bitas:
- n = l->left;
- regalloc(&nod, r, nn);
- if(l->complex >= r->complex) {
- reglcgen(&nod1, n, Z);
- cgen(r, &nod);
- } else {
- cgen(r, &nod);
- reglcgen(&nod1, n, Z);
- }
- regalloc(&nod2, n, Z);
- gmove(&nod1, &nod2);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
-
- case OBIT:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- bitload(n, &nod, Z, Z, nn);
- gmove(&nod, nn);
- regfree(&nod);
- break;
-
- case OLSHR:
- case OASHL:
- case OASHR:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- if(r->op == OCONST) {
- if(r->vconst == 0) {
- cgen(l, nn);
- break;
- }
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- if(o == OASHL && r->vconst == 1)
- gopcode(OADD, n->type, &nod, &nod);
- else
- gopcode(o, n->type, r, &nod);
- gmove(&nod, nn);
- regfree(&nod);
- break;
- }
-
- /*
- * get nod to be D_CX
- */
- if(nodreg(&nod, nn, D_CX)) {
- regsalloc(&nod1, n);
- gmove(&nod, &nod1);
- cgen(n, &nod); /* probably a bug */
- gmove(&nod, nn);
- gmove(&nod1, &nod);
- break;
- }
- reg[D_CX]++;
- if(nn->op == OREGISTER && nn->reg == D_CX)
- regalloc(&nod1, l, Z);
- else
- regalloc(&nod1, l, nn);
- if(r->complex >= l->complex) {
- cgen(r, &nod);
- cgen(l, &nod1);
- } else {
- cgen(l, &nod1);
- cgen(r, &nod);
- }
- gopcode(o, n->type, &nod, &nod1);
- gmove(&nod1, nn);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- case OADD:
- case OSUB:
- case OOR:
- case OXOR:
- case OAND:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- if(typefd[n->type->etype])
- goto fop;
- if(r->op == OCONST) {
- if(r->vconst == 0 && o != OAND) {
- cgen(l, nn);
- break;
- }
- }
- if(n->op == OOR && l->op == OASHL && r->op == OLSHR
- && l->right->op == OCONST && r->right->op == OCONST
- && l->left->op == ONAME && r->left->op == ONAME
- && l->left->sym == r->left->sym
- && l->right->vconst + r->right->vconst == 8 * l->left->type->width) {
- regalloc(&nod, l->left, nn);
- cgen(l->left, &nod);
- gopcode(OROTL, n->type, l->right, &nod);
- gmove(&nod, nn);
- regfree(&nod);
- break;
- }
- if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
- && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
- c = l->right->vconst;
- if(c > 0 && c <= 3) {
- if(l->left->complex >= r->complex) {
- regalloc(&nod, l->left, nn);
- cgen(l->left, &nod);
- if(r->addable < INDEXED) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- genmuladd(&nod, &nod, 1 << c, &nod1);
- regfree(&nod1);
- }
- else
- genmuladd(&nod, &nod, 1 << c, r);
- }
- else {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- regalloc(&nod1, l->left, Z);
- cgen(l->left, &nod1);
- genmuladd(&nod, &nod1, 1 << c, &nod);
- regfree(&nod1);
- }
- gmove(&nod, nn);
- regfree(&nod);
- break;
- }
- }
- if(r->addable >= INDEXED) {
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- gopcode(o, n->type, r, &nod);
- gmove(&nod, nn);
- regfree(&nod);
- break;
- }
- if(l->complex >= r->complex) {
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- gopcode(o, n->type, &nod1, &nod);
- } else {
- regalloc(&nod1, r, nn);
- cgen(r, &nod1);
- regalloc(&nod, l, Z);
- cgen(l, &nod);
- gopcode(o, n->type, &nod1, &nod);
- }
- gmove(&nod, nn);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- case OLMOD:
- case OMOD:
- case OLMUL:
- case OLDIV:
- case OMUL:
- case ODIV:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- if(typefd[n->type->etype])
- goto fop;
- if(r->op == OCONST) {
- SET(v);
- switch(o) {
- case ODIV:
- case OMOD:
- c = r->vconst;
- if(c < 0)
- c = -c;
- v = xlog2(c);
- if(v < 0)
- break;
- /* fall thru */
- case OMUL:
- case OLMUL:
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- switch(o) {
- case OMUL:
- case OLMUL:
- mulgen(n->type, r, &nod);
- break;
- case ODIV:
- sdiv2(r->vconst, v, l, &nod);
- break;
- case OMOD:
- smod2(r->vconst, v, l, &nod);
- break;
- }
- gmove(&nod, nn);
- regfree(&nod);
- goto done;
- case OLDIV:
- c = r->vconst;
- if((c & 0x80000000) == 0)
- break;
- regalloc(&nod1, l, Z);
- cgen(l, &nod1);
- regalloc(&nod, l, nn);
- zeroregm(&nod);
- gins(ACMPL, &nod1, nodconst(c));
- gins(ASBBL, nodconst(-1), &nod);
- regfree(&nod1);
- gmove(&nod, nn);
- regfree(&nod);
- goto done;
- }
- }
-
- if(o == OMUL || o == OLMUL) {
- if(l->addable >= INDEXED) {
- t = l;
- l = r;
- r = t;
- }
- reg[D_DX]++; // for gopcode case OMUL
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- if(r->addable < INDEXED) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- gopcode(OMUL, n->type, &nod1, &nod);
- regfree(&nod1);
- }else
- gopcode(OMUL, n->type, r, &nod); /* addressible */
- gmove(&nod, nn);
- regfree(&nod);
- reg[D_DX]--;
- break;
- }
-
- /*
- * get nod to be D_AX
- * get nod1 to be D_DX
- */
- if(nodreg(&nod, nn, D_AX)) {
- regsalloc(&nod2, n);
- gmove(&nod, &nod2);
- v = reg[D_AX];
- reg[D_AX] = 0;
-
- if(isreg(l, D_AX)) {
- nod3 = *n;
- nod3.left = &nod2;
- cgen(&nod3, nn);
- } else
- if(isreg(r, D_AX)) {
- nod3 = *n;
- nod3.right = &nod2;
- cgen(&nod3, nn);
- } else
- cgen(n, nn);
-
- gmove(&nod2, &nod);
- reg[D_AX] = v;
- break;
- }
- if(nodreg(&nod1, nn, D_DX)) {
- regsalloc(&nod2, n);
- gmove(&nod1, &nod2);
- v = reg[D_DX];
- reg[D_DX] = 0;
-
- if(isreg(l, D_DX)) {
- nod3 = *n;
- nod3.left = &nod2;
- cgen(&nod3, nn);
- } else
- if(isreg(r, D_DX)) {
- nod3 = *n;
- nod3.right = &nod2;
- cgen(&nod3, nn);
- } else
- cgen(n, nn);
-
- gmove(&nod2, &nod1);
- reg[D_DX] = v;
- break;
- }
- reg[D_AX]++;
-
- if(r->op == OCONST && (o == ODIV || o == OLDIV)) {
- reg[D_DX]++;
- if(l->addable < INDEXED) {
- regalloc(&nod2, l, Z);
- cgen(l, &nod2);
- l = &nod2;
- }
- if(o == ODIV)
- sdivgen(l, r, &nod, &nod1);
- else
- udivgen(l, r, &nod, &nod1);
- gmove(&nod1, nn);
- if(l == &nod2)
- regfree(l);
- goto freeaxdx;
- }
-
- if(l->complex >= r->complex) {
- cgen(l, &nod);
- reg[D_DX]++;
- if(o == ODIV || o == OMOD)
- gins(ACDQ, Z, Z);
- if(o == OLDIV || o == OLMOD)
- zeroregm(&nod1);
- if(r->addable < INDEXED || r->op == OCONST) {
- regsalloc(&nod3, r);
- cgen(r, &nod3);
- gopcode(o, n->type, &nod3, Z);
- } else
- gopcode(o, n->type, r, Z);
- } else {
- regsalloc(&nod3, r);
- cgen(r, &nod3);
- cgen(l, &nod);
- reg[D_DX]++;
- if(o == ODIV || o == OMOD)
- gins(ACDQ, Z, Z);
- if(o == OLDIV || o == OLMOD)
- zeroregm(&nod1);
- gopcode(o, n->type, &nod3, Z);
- }
- if(o == OMOD || o == OLMOD)
- gmove(&nod1, nn);
- else
- gmove(&nod, nn);
- freeaxdx:
- regfree(&nod);
- regfree(&nod1);
- break;
-
- case OASLSHR:
- case OASASHL:
- case OASASHR:
- if(r->op == OCONST)
- goto asand;
- if(l->op == OBIT)
- goto asbitop;
- if(typefd[n->type->etype])
- goto asfop;
-
- /*
- * get nod to be D_CX
- */
- if(nodreg(&nod, nn, D_CX)) {
- regsalloc(&nod1, n);
- gmove(&nod, &nod1);
- cgen(n, &nod);
- if(nn != Z)
- gmove(&nod, nn);
- gmove(&nod1, &nod);
- break;
- }
- reg[D_CX]++;
-
- if(r->complex >= l->complex) {
- cgen(r, &nod);
- if(hardleft)
- reglcgen(&nod1, l, Z);
- else
- nod1 = *l;
- } else {
- if(hardleft)
- reglcgen(&nod1, l, Z);
- else
- nod1 = *l;
- cgen(r, &nod);
- }
-
- gopcode(o, l->type, &nod, &nod1);
- regfree(&nod);
- if(nn != Z)
- gmove(&nod1, nn);
- if(hardleft)
- regfree(&nod1);
- break;
-
- case OASAND:
- case OASADD:
- case OASSUB:
- case OASXOR:
- case OASOR:
- asand:
- if(l->op == OBIT)
- goto asbitop;
- if(typefd[n->type->etype]||typefd[r->type->etype])
- goto asfop;
- if(l->complex >= r->complex) {
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
- if(r->op != OCONST) {
- regalloc(&nod1, r, nn);
- cgen(r, &nod1);
- gopcode(o, l->type, &nod1, &nod);
- regfree(&nod1);
- } else
- gopcode(o, l->type, r, &nod);
- } else {
- regalloc(&nod1, r, nn);
- cgen(r, &nod1);
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
- gopcode(o, l->type, &nod1, &nod);
- regfree(&nod1);
- }
- if(nn != Z)
- gmove(&nod, nn);
- if(hardleft)
- regfree(&nod);
- break;
-
- case OASLMUL:
- case OASLDIV:
- case OASLMOD:
- case OASMUL:
- case OASDIV:
- case OASMOD:
- if(l->op == OBIT)
- goto asbitop;
- if(typefd[n->type->etype]||typefd[r->type->etype])
- goto asfop;
- if(r->op == OCONST) {
- SET(v);
- switch(o) {
- case OASDIV:
- case OASMOD:
- c = r->vconst;
- if(c < 0)
- c = -c;
- v = xlog2(c);
- if(v < 0)
- break;
- /* fall thru */
- case OASMUL:
- case OASLMUL:
- if(hardleft)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- regalloc(&nod, l, nn);
- cgen(&nod2, &nod);
- switch(o) {
- case OASMUL:
- case OASLMUL:
- mulgen(n->type, r, &nod);
- break;
- case OASDIV:
- sdiv2(r->vconst, v, l, &nod);
- break;
- case OASMOD:
- smod2(r->vconst, v, l, &nod);
- break;
- }
- havev:
- gmove(&nod, &nod2);
- if(nn != Z)
- gmove(&nod, nn);
- if(hardleft)
- regfree(&nod2);
- regfree(&nod);
- goto done;
- case OASLDIV:
- c = r->vconst;
- if((c & 0x80000000) == 0)
- break;
- if(hardleft)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- regalloc(&nod1, l, nn);
- cgen(&nod2, &nod1);
- regalloc(&nod, l, nn);
- zeroregm(&nod);
- gins(ACMPL, &nod1, nodconst(c));
- gins(ASBBL, nodconst(-1), &nod);
- regfree(&nod1);
- goto havev;
- }
- }
-
- if(o == OASMUL) {
- /* should favour AX */
- regalloc(&nod, l, nn);
- if(r->complex >= FNX) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- r = &nod1;
- }
- if(hardleft)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- cgen(&nod2, &nod);
- if(r->addable < INDEXED) {
- if(r->complex < FNX) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- }
- gopcode(OASMUL, n->type, &nod1, &nod);
- regfree(&nod1);
- }
- else
- gopcode(OASMUL, n->type, r, &nod);
- if(r == &nod1)
- regfree(r);
- gmove(&nod, &nod2);
- if(nn != Z)
- gmove(&nod, nn);
- regfree(&nod);
- if(hardleft)
- regfree(&nod2);
- break;
- }
-
- /*
- * get nod to be D_AX
- * get nod1 to be D_DX
- */
- if(nodreg(&nod, nn, D_AX)) {
- regsalloc(&nod2, n);
- gmove(&nod, &nod2);
- v = reg[D_AX];
- reg[D_AX] = 0;
-
- if(isreg(l, D_AX)) {
- nod3 = *n;
- nod3.left = &nod2;
- cgen(&nod3, nn);
- } else
- if(isreg(r, D_AX)) {
- nod3 = *n;
- nod3.right = &nod2;
- cgen(&nod3, nn);
- } else
- cgen(n, nn);
-
- gmove(&nod2, &nod);
- reg[D_AX] = v;
- break;
- }
- if(nodreg(&nod1, nn, D_DX)) {
- regsalloc(&nod2, n);
- gmove(&nod1, &nod2);
- v = reg[D_DX];
- reg[D_DX] = 0;
-
- if(isreg(l, D_DX)) {
- nod3 = *n;
- nod3.left = &nod2;
- cgen(&nod3, nn);
- } else
- if(isreg(r, D_DX)) {
- nod3 = *n;
- nod3.right = &nod2;
- cgen(&nod3, nn);
- } else
- cgen(n, nn);
-
- gmove(&nod2, &nod1);
- reg[D_DX] = v;
- break;
- }
- reg[D_AX]++;
- reg[D_DX]++;
-
- if(l->complex >= r->complex) {
- if(hardleft)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- cgen(&nod2, &nod);
- if(r->op == OCONST) {
- switch(o) {
- case OASDIV:
- sdivgen(&nod2, r, &nod, &nod1);
- goto divdone;
- case OASLDIV:
- udivgen(&nod2, r, &nod, &nod1);
- divdone:
- gmove(&nod1, &nod2);
- if(nn != Z)
- gmove(&nod1, nn);
- goto freelxaxdx;
- }
- }
- if(o == OASDIV || o == OASMOD)
- gins(ACDQ, Z, Z);
- if(o == OASLDIV || o == OASLMOD)
- zeroregm(&nod1);
- if(r->addable < INDEXED || r->op == OCONST ||
- !typeil[r->type->etype]) {
- regalloc(&nod3, r, Z);
- cgen(r, &nod3);
- gopcode(o, l->type, &nod3, Z);
- regfree(&nod3);
- } else
- gopcode(o, n->type, r, Z);
- } else {
- regalloc(&nod3, r, Z);
- cgen(r, &nod3);
- if(hardleft)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- cgen(&nod2, &nod);
- if(o == OASDIV || o == OASMOD)
- gins(ACDQ, Z, Z);
- if(o == OASLDIV || o == OASLMOD)
- zeroregm(&nod1);
- gopcode(o, l->type, &nod3, Z);
- regfree(&nod3);
- }
- if(o == OASMOD || o == OASLMOD) {
- gmove(&nod1, &nod2);
- if(nn != Z)
- gmove(&nod1, nn);
- } else {
- gmove(&nod, &nod2);
- if(nn != Z)
- gmove(&nod, nn);
- }
- freelxaxdx:
- if(hardleft)
- regfree(&nod2);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- fop:
- if(l->complex >= r->complex) {
- cgen(l, &fregnode0);
- if(r->addable < INDEXED) {
- cgen(r, &fregnode0);
- fgopcode(o, &fregnode0, &fregnode1, 1, 0);
- } else
- fgopcode(o, r, &fregnode0, 0, 0);
- } else {
- cgen(r, &fregnode0);
- if(l->addable < INDEXED) {
- cgen(l, &fregnode0);
- fgopcode(o, &fregnode0, &fregnode1, 1, 1);
- } else
- fgopcode(o, l, &fregnode0, 0, 1);
- }
- gmove(&fregnode0, nn);
- break;
-
- asfop:
- if(l->complex >= r->complex) {
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
- cgen(r, &fregnode0);
- } else {
- cgen(r, &fregnode0);
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
- }
- if(!typefd[l->type->etype]) {
- gmove(&nod, &fregnode0);
- fgopcode(o, &fregnode0, &fregnode1, 1, 1);
- } else
- fgopcode(o, &nod, &fregnode0, 0, 1);
- if(nn != Z)
- gins(AFMOVD, &fregnode0, &fregnode0);
- gmove(&fregnode0, &nod);
- if(nn != Z)
- gmove(&fregnode0, nn);
- if(hardleft)
- regfree(&nod);
- break;
-
- asbitop:
- regalloc(&nod4, n, nn);
- if(l->complex >= r->complex) {
- bitload(l, &nod, &nod1, &nod2, &nod4);
- regalloc(&nod3, r, Z);
- cgen(r, &nod3);
- } else {
- regalloc(&nod3, r, Z);
- cgen(r, &nod3);
- bitload(l, &nod, &nod1, &nod2, &nod4);
- }
- gmove(&nod, &nod4);
-
- if(typefd[nod3.type->etype])
- fgopcode(o, &fregnode0, &fregnode1, 1, 1);
- else {
- Node onod;
-
- /* incredible grot ... */
- onod = nod3;
- onod.op = o;
- onod.complex = 2;
- onod.addable = 0;
- onod.type = tfield;
- onod.left = &nod4;
- onod.right = &nod3;
- cgen(&onod, Z);
- }
- regfree(&nod3);
- gmove(&nod4, &nod);
- regfree(&nod4);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
-
- case OADDR:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- lcgen(l, nn);
- break;
-
- case OFUNC:
- if(l->complex >= FNX) {
- if(l->op != OIND)
- diag(n, "bad function call");
-
- regret(&nod, l->left, 0, 0);
- cgen(l->left, &nod);
- regsalloc(&nod1, l->left);
- gmove(&nod, &nod1);
- regfree(&nod);
-
- nod = *n;
- nod.left = &nod2;
- nod2 = *l;
- nod2.left = &nod1;
- nod2.complex = 1;
- cgen(&nod, nn);
-
- return;
- }
- gargs(r, &nod, &nod1);
- if(l->addable < INDEXED) {
- reglcgen(&nod, l, nn);
- nod.op = OREGISTER;
- gopcode(OFUNC, n->type, Z, &nod);
- regfree(&nod);
- } else
- gopcode(OFUNC, n->type, Z, l);
- if(REGARG >= 0 && reg[REGARG])
- reg[REGARG]--;
- regret(&nod, n, l->type, 1); // update maxarg if nothing else
- if(nn != Z)
- gmove(&nod, nn);
- if(nod.op == OREGISTER)
- regfree(&nod);
- if(nn == Z && hasdotdotdot(l->type) && typefd[n->type->etype])
- gins(AFMOVDP, &fregnode0, &fregnode0);
- break;
-
- case OIND:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- regialloc(&nod, n, nn);
- r = l;
- while(r->op == OADD)
- r = r->right;
- if(sconst(r)) {
- v = r->vconst;
- r->vconst = 0;
- cgen(l, &nod);
- nod.xoffset += v;
- r->vconst = v;
- } else
- cgen(l, &nod);
- regind(&nod, n);
- gmove(&nod, nn);
- regfree(&nod);
- break;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OLO:
- case OLS:
- case OHI:
- case OHS:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- boolgen(n, 1, nn);
- break;
-
- case OANDAND:
- case OOROR:
- boolgen(n, 1, nn);
- if(nn == Z)
- patch(p, pc);
- break;
-
- case ONOT:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- boolgen(n, 1, nn);
- break;
-
- case OCOMMA:
- cgen(l, Z);
- cgen(r, nn);
- break;
-
- case OCAST:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- /*
- * convert from types l->n->nn
- */
- if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
- /* both null, gen l->nn */
- cgen(l, nn);
- break;
- }
- if(typev[l->type->etype]) {
- cgen64(n, nn);
- break;
- }
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- regalloc(&nod1, n, &nod);
- gmove(&nod, &nod1);
- gmove(&nod1, nn);
- regfree(&nod1);
- regfree(&nod);
- break;
-
- case ODOT:
- sugen(l, nodrat, l->type->width);
- if(nn == Z)
- break;
- warn(n, "non-interruptable temporary");
- nod = *nodrat;
- if(!r || r->op != OCONST) {
- diag(n, "DOT and no offset");
- break;
- }
- nod.xoffset += (int32)r->vconst;
- nod.type = n->type;
- cgen(&nod, nn);
- break;
-
- case OCOND:
- bcgen(l, 1);
- p1 = p;
- cgen(r->left, nn);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- cgen(r->right, nn);
- patch(p1, pc);
- break;
-
- case OPOSTINC:
- case OPOSTDEC:
- v = 1;
- if(l->type->etype == TIND)
- v = l->type->link->width;
- if(o == OPOSTDEC)
- v = -v;
- if(l->op == OBIT)
- goto bitinc;
- if(nn == Z)
- goto pre;
-
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
-
- if(typefd[n->type->etype])
- goto fltinc;
- gmove(&nod, nn);
- gopcode(OADD, n->type, nodconst(v), &nod);
- if(hardleft)
- regfree(&nod);
- break;
-
- case OPREINC:
- case OPREDEC:
- v = 1;
- if(l->type->etype == TIND)
- v = l->type->link->width;
- if(o == OPREDEC)
- v = -v;
- if(l->op == OBIT)
- goto bitinc;
-
- pre:
- if(hardleft)
- reglcgen(&nod, l, Z);
- else
- nod = *l;
- if(typefd[n->type->etype])
- goto fltinc;
- gopcode(OADD, n->type, nodconst(v), &nod);
- if(nn != Z)
- gmove(&nod, nn);
- if(hardleft)
- regfree(&nod);
- break;
-
- fltinc:
- gmove(&nod, &fregnode0);
- if(nn != Z && (o == OPOSTINC || o == OPOSTDEC))
- gins(AFMOVD, &fregnode0, &fregnode0);
- gins(AFLD1, Z, Z);
- if(v < 0)
- fgopcode(OSUB, &fregnode0, &fregnode1, 1, 0);
- else
- fgopcode(OADD, &fregnode0, &fregnode1, 1, 0);
- if(nn != Z && (o == OPREINC || o == OPREDEC))
- gins(AFMOVD, &fregnode0, &fregnode0);
- gmove(&fregnode0, &nod);
- if(hardleft)
- regfree(&nod);
- break;
-
- bitinc:
- if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
- bitload(l, &nod, &nod1, &nod2, Z);
- gmove(&nod, nn);
- gopcode(OADD, tfield, nodconst(v), &nod);
- bitstore(l, &nod, &nod1, &nod2, Z);
- break;
- }
- bitload(l, &nod, &nod1, &nod2, nn);
- gopcode(OADD, tfield, nodconst(v), &nod);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
- }
-done:
- cursafe = curs;
-}
-
-void
-reglcgen(Node *t, Node *n, Node *nn)
-{
- Node *r;
- int32 v;
-
- regialloc(t, n, nn);
- if(n->op == OIND) {
- r = n->left;
- while(r->op == OADD)
- r = r->right;
- if(sconst(r)) {
- v = r->vconst;
- r->vconst = 0;
- lcgen(n, t);
- t->xoffset += v;
- r->vconst = v;
- regind(t, n);
- return;
- }
- }
- lcgen(n, t);
- regind(t, n);
-}
-
-void
-lcgen(Node *n, Node *nn)
-{
- Prog *p1;
- Node nod;
-
- if(debug['g']) {
- prtree(nn, "lcgen lhs");
- prtree(n, "lcgen");
- }
- if(n == Z || n->type == T)
- return;
- if(nn == Z) {
- nn = &nod;
- regalloc(&nod, n, Z);
- }
- switch(n->op) {
- default:
- if(n->addable < INDEXED) {
- diag(n, "unknown op in lcgen: %O", n->op);
- break;
- }
- gopcode(OADDR, n->type, n, nn);
- break;
-
- case OCOMMA:
- cgen(n->left, n->left);
- lcgen(n->right, nn);
- break;
-
- case OIND:
- cgen(n->left, nn);
- break;
-
- case OCOND:
- bcgen(n->left, 1);
- p1 = p;
- lcgen(n->right->left, nn);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- lcgen(n->right->right, nn);
- patch(p1, pc);
- break;
- }
-}
-
-void
-bcgen(Node *n, int true)
-{
-
- if(n->type == T)
- gbranch(OGOTO);
- else
- boolgen(n, true, Z);
-}
-
-void
-boolgen(Node *n, int true, Node *nn)
-{
- int o;
- Prog *p1, *p2, *p3;
- Node *l, *r, nod, nod1;
- int32 curs;
-
- if(debug['g']) {
- prtree(nn, "boolgen lhs");
- prtree(n, "boolgen");
- }
- curs = cursafe;
- l = n->left;
- r = n->right;
- switch(n->op) {
-
- default:
- if(typev[n->type->etype]) {
- testv(n, true);
- goto com;
- }
- o = ONE;
- if(true)
- o = OEQ;
- if(typefd[n->type->etype]) {
- if(n->addable < INDEXED) {
- cgen(n, &fregnode0);
- gins(AFLDZ, Z, Z);
- fgopcode(o, &fregnode0, &fregnode1, 1, 1);
- } else {
- gins(AFLDZ, Z, Z);
- fgopcode(o, n, &fregnode0, 0, 1);
- }
- goto com;
- }
- /* bad, 13 is address of external that becomes constant */
- if(n->addable >= INDEXED && n->addable != 13) {
- gopcode(o, n->type, n, nodconst(0));
- goto com;
- }
- regalloc(&nod, n, nn);
- cgen(n, &nod);
- gopcode(o, n->type, &nod, nodconst(0));
- regfree(&nod);
- goto com;
-
- case OCONST:
- o = vconst(n);
- if(!true)
- o = !o;
- gbranch(OGOTO);
- if(o) {
- p1 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- }
- goto com;
-
- case OCOMMA:
- cgen(l, Z);
- boolgen(r, true, nn);
- break;
-
- case ONOT:
- boolgen(l, !true, nn);
- break;
-
- case OCOND:
- bcgen(l, 1);
- p1 = p;
- bcgen(r->left, true);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- bcgen(r->right, !true);
- patch(p2, pc);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- patch(p2, pc);
- goto com;
-
- case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- bcgen(l, true);
- p1 = p;
- bcgen(r, !true);
- p2 = p;
- patch(p1, pc);
- gbranch(OGOTO);
- patch(p2, pc);
- goto com;
-
- case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bcgen(l, !true);
- p1 = p;
- bcgen(r, !true);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- patch(p2, pc);
- goto com;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- o = n->op;
- if(typev[l->type->etype]) {
- if(!true)
- n->op = comrel[relindex(o)];
- cgen64(n, Z);
- goto com;
- }
- if(true && typefd[l->type->etype] && (o == OEQ || o == ONE)) {
- // Cannot rewrite !(l == r) into l != r with float64; it breaks NaNs.
- // Jump around instead.
- boolgen(n, 0, Z);
- p1 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- goto com;
- }
- if(true)
- o = comrel[relindex(o)];
- if(l->complex >= FNX && r->complex >= FNX) {
- regret(&nod, r, 0, 0);
- cgen(r, &nod);
- regsalloc(&nod1, r);
- gmove(&nod, &nod1);
- regfree(&nod);
- nod = *n;
- nod.right = &nod1;
- boolgen(&nod, true, nn);
- break;
- }
- if(typefd[l->type->etype]) {
- if(l->complex >= r->complex) {
- cgen(l, &fregnode0);
- if(r->addable < INDEXED) {
- cgen(r, &fregnode0);
- o = invrel[relindex(o)];
- fgopcode(o, &fregnode0, &fregnode1, 1, 1);
- } else
- fgopcode(o, r, &fregnode0, 0, 1);
- } else {
- o = invrel[relindex(o)];
- cgen(r, &fregnode0);
- if(l->addable < INDEXED) {
- cgen(l, &fregnode0);
- o = invrel[relindex(o)];
- fgopcode(o, &fregnode0, &fregnode1, 1, 1);
- } else
- fgopcode(o, l, &fregnode0, 0, 1);
- }
- switch(o) {
- case OEQ:
- // Already emitted AJEQ; want AJEQ and AJPC.
- p1 = p;
- gbranch(OGOTO);
- p2 = p;
- patch(p1, pc);
- gins(AJPC, Z, Z);
- patch(p2, pc);
- break;
-
- case ONE:
- // Already emitted AJNE; want AJNE or AJPS.
- p1 = p;
- gins(AJPS, Z, Z);
- p2 = p;
- gbranch(OGOTO);
- p3 = p;
- patch(p1, pc);
- patch(p2, pc);
- gbranch(OGOTO);
- patch(p3, pc);
- break;
- }
- goto com;
- }
- if(l->op == OCONST) {
- o = invrel[relindex(o)];
- /* bad, 13 is address of external that becomes constant */
- if(r->addable < INDEXED || r->addable == 13) {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- gopcode(o, l->type, &nod, l);
- regfree(&nod);
- } else
- gopcode(o, l->type, r, l);
- goto com;
- }
- if(l->complex >= r->complex) {
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- if(r->addable < INDEXED) {
- regalloc(&nod1, r, Z);
- cgen(r, &nod1);
- gopcode(o, l->type, &nod, &nod1);
- regfree(&nod1);
- } else
- gopcode(o, l->type, &nod, r);
- regfree(&nod);
- goto com;
- }
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- if(l->addable < INDEXED || l->addable == 13) {
- regalloc(&nod1, l, Z);
- cgen(l, &nod1);
- if(typechlp[l->type->etype])
- gopcode(o, types[TINT], &nod1, &nod);
- else
- gopcode(o, l->type, &nod1, &nod);
- regfree(&nod1);
- } else
- gopcode(o, l->type, l, &nod);
- regfree(&nod);
-
- com:
- if(nn != Z) {
- p1 = p;
- gmove(nodconst(1L), nn);
- gbranch(OGOTO);
- p2 = p;
- patch(p1, pc);
- gmove(nodconst(0L), nn);
- patch(p2, pc);
- }
- break;
- }
- cursafe = curs;
-}
-
-void
-sugen(Node *n, Node *nn, int32 w)
-{
- Prog *p1;
- Node nod0, nod1, nod2, nod3, nod4, *h, *l, *r;
- Type *t;
- int c, v, x;
-
- if(n == Z || n->type == T)
- return;
- if(debug['g']) {
- prtree(nn, "sugen lhs");
- prtree(n, "sugen");
- }
- if(nn == nodrat)
- if(w > nrathole)
- nrathole = w;
- switch(n->op) {
- case OIND:
- if(nn == Z) {
- nullwarn(n->left, Z);
- break;
- }
-
- default:
- goto copy;
-
- case OCONST:
- if(n->type && typev[n->type->etype]) {
- if(nn == Z) {
- nullwarn(n->left, Z);
- break;
- }
-
- if(nn->op == OREGPAIR) {
- loadpair(n, nn);
- break;
- }
- else if(!vaddr(nn, 0)) {
- t = nn->type;
- nn->type = types[TLONG];
- reglcgen(&nod1, nn, Z);
- nn->type = t;
-
- gmove(lo64(n), &nod1);
- nod1.xoffset += SZ_LONG;
- gmove(hi64(n), &nod1);
- regfree(&nod1);
- }
- else {
- gins(AMOVL, lo64(n), nn);
- nn->xoffset += SZ_LONG;
- gins(AMOVL, hi64(n), nn);
- nn->xoffset -= SZ_LONG;
- break;
- }
- break;
- }
- goto copy;
-
- case ODOT:
- l = n->left;
- sugen(l, nodrat, l->type->width);
- if(nn == Z)
- break;
- warn(n, "non-interruptable temporary");
- nod1 = *nodrat;
- r = n->right;
- if(!r || r->op != OCONST) {
- diag(n, "DOT and no offset");
- break;
- }
- nod1.xoffset += (int32)r->vconst;
- nod1.type = n->type;
- sugen(&nod1, nn, w);
- break;
-
- case OSTRUCT:
- /*
- * rewrite so lhs has no fn call
- */
- if(nn != Z && side(nn)) {
- nod1 = *n;
- nod1.type = typ(TIND, n->type);
- regret(&nod2, &nod1, 0, 0);
- lcgen(nn, &nod2);
- regsalloc(&nod0, &nod1);
- cgen(&nod2, &nod0);
- regfree(&nod2);
-
- nod1 = *n;
- nod1.op = OIND;
- nod1.left = &nod0;
- nod1.right = Z;
- nod1.complex = 1;
-
- sugen(n, &nod1, w);
- return;
- }
-
- r = n->left;
- for(t = n->type->link; t != T; t = t->down) {
- l = r;
- if(r->op == OLIST) {
- l = r->left;
- r = r->right;
- }
- if(nn == Z) {
- cgen(l, nn);
- continue;
- }
- /*
- * hand craft *(&nn + o) = l
- */
- nod0 = znode;
- nod0.op = OAS;
- nod0.type = t;
- nod0.left = &nod1;
- nod0.right = nil;
-
- nod1 = znode;
- nod1.op = OIND;
- nod1.type = t;
- nod1.left = &nod2;
-
- nod2 = znode;
- nod2.op = OADD;
- nod2.type = typ(TIND, t);
- nod2.left = &nod3;
- nod2.right = &nod4;
-
- nod3 = znode;
- nod3.op = OADDR;
- nod3.type = nod2.type;
- nod3.left = nn;
-
- nod4 = znode;
- nod4.op = OCONST;
- nod4.type = nod2.type;
- nod4.vconst = t->offset;
-
- ccom(&nod0);
- acom(&nod0);
- xcom(&nod0);
- nod0.addable = 0;
- nod0.right = l;
-
- // prtree(&nod0, "hand craft");
- cgen(&nod0, Z);
- }
- break;
-
- case OAS:
- if(nn == Z) {
- if(n->addable < INDEXED)
- sugen(n->right, n->left, w);
- break;
- }
-
- sugen(n->right, nodrat, w);
- warn(n, "non-interruptable temporary");
- sugen(nodrat, n->left, w);
- sugen(nodrat, nn, w);
- break;
-
- case OFUNC:
- if(!hasdotdotdot(n->left->type)) {
- cgen(n, Z);
- if(nn != Z) {
- curarg -= n->type->width;
- regret(&nod1, n, n->left->type, 1);
- if(nn->complex >= FNX) {
- regsalloc(&nod2, n);
- cgen(&nod1, &nod2);
- nod1 = nod2;
- }
- cgen(&nod1, nn);
- }
- break;
- }
- if(nn == Z) {
- sugen(n, nodrat, w);
- break;
- }
- h = nn;
- if(nn->op == OREGPAIR) {
- regsalloc(&nod1, nn);
- nn = &nod1;
- }
- if(nn->op != OIND) {
- nn = new1(OADDR, nn, Z);
- nn->type = types[TIND];
- nn->addable = 0;
- } else
- nn = nn->left;
- n = new(OFUNC, n->left, new(OLIST, nn, n->right));
- n->type = types[TVOID];
- n->left->type = types[TVOID];
- cgen(n, Z);
- if(h->op == OREGPAIR)
- loadpair(nn->left, h);
- break;
-
- case OCOND:
- bcgen(n->left, 1);
- p1 = p;
- sugen(n->right->left, nn, w);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- sugen(n->right->right, nn, w);
- patch(p1, pc);
- break;
-
- case OCOMMA:
- cgen(n->left, Z);
- sugen(n->right, nn, w);
- break;
- }
- return;
-
-copy:
- if(nn == Z) {
- switch(n->op) {
- case OASADD:
- case OASSUB:
- case OASAND:
- case OASOR:
- case OASXOR:
-
- case OASMUL:
- case OASLMUL:
-
-
- case OASASHL:
- case OASASHR:
- case OASLSHR:
- break;
-
- case OPOSTINC:
- case OPOSTDEC:
- case OPREINC:
- case OPREDEC:
- break;
-
- default:
- return;
- }
- }
-
- v = w == 8;
- if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
- t = nn->type;
- nn->type = types[TLONG];
- regialloc(&nod1, nn, Z);
- lcgen(nn, &nod1);
- regsalloc(&nod2, nn);
- nn->type = t;
-
- gins(AMOVL, &nod1, &nod2);
- regfree(&nod1);
-
- nod2.type = typ(TIND, t);
-
- nod1 = nod2;
- nod1.op = OIND;
- nod1.left = &nod2;
- nod1.right = Z;
- nod1.complex = 1;
- nod1.type = t;
-
- sugen(n, &nod1, w);
- return;
- }
-
- x = 0;
- if(v) {
- if(nn != nil && nn->complex >= FNX) {
- t = nn->type;
- nn->type = types[TLONG];
- regialloc(&nod2, nn, Z);
- lcgen(nn, &nod2);
- nn->type = t;
-
- nod2.type = typ(TIND, t);
-
- nod1 = nod2;
- nod1.op = OIND;
- nod1.left = &nod2;
- nod1.right = Z;
- nod1.complex = 1;
- nod1.type = t;
-
- sugen(n, &nod1, w);
- regfree(&nod2);
- return;
- }
-
- c = cursafe;
- if(n->left != Z && n->left->complex >= FNX
- && n->right != Z && n->right->complex >= FNX) {
-// warn(n, "toughie");
- regsalloc(&nod1, n->right);
- cgen(n->right, &nod1);
- nod2 = *n;
- nod2.right = &nod1;
- cgen(&nod2, nn);
- cursafe = c;
- return;
- }
- if(cgen64(n, nn)) {
- cursafe = c;
- return;
- }
- if(n->op == OCOM) {
- n = n->left;
- x = 1;
- }
- }
-
- /* botch, need to save in .safe */
- c = 0;
- if(n->complex > nn->complex) {
- t = n->type;
- n->type = types[TLONG];
- if(v) {
- regalloc(&nod0, n, Z);
- if(!vaddr(n, 0)) {
- reglcgen(&nod1, n, Z);
- n->type = t;
- n = &nod1;
- }
- else
- n->type = t;
- }
- else {
- nodreg(&nod1, n, D_SI);
- if(reg[D_SI]) {
- gins(APUSHL, &nod1, Z);
- c |= 1;
- reg[D_SI]++;
- }
- lcgen(n, &nod1);
- n->type = t;
- }
-
- t = nn->type;
- nn->type = types[TLONG];
- if(v) {
- if(!vaddr(nn, 0)) {
- reglcgen(&nod2, nn, Z);
- nn->type = t;
- nn = &nod2;
- }
- else
- nn->type = t;
- }
- else {
- nodreg(&nod2, nn, D_DI);
- if(reg[D_DI]) {
- gins(APUSHL, &nod2, Z);
- c |= 2;
- reg[D_DI]++;
- }
- lcgen(nn, &nod2);
- nn->type = t;
- }
- } else {
- t = nn->type;
- nn->type = types[TLONG];
- if(v) {
- regalloc(&nod0, nn, Z);
- if(!vaddr(nn, 0)) {
- reglcgen(&nod2, nn, Z);
- nn->type = t;
- nn = &nod2;
- }
- else
- nn->type = t;
- }
- else {
- nodreg(&nod2, nn, D_DI);
- if(reg[D_DI]) {
- gins(APUSHL, &nod2, Z);
- c |= 2;
- reg[D_DI]++;
- }
- lcgen(nn, &nod2);
- nn->type = t;
- }
-
- t = n->type;
- n->type = types[TLONG];
- if(v) {
- if(!vaddr(n, 0)) {
- reglcgen(&nod1, n, Z);
- n->type = t;
- n = &nod1;
- }
- else
- n->type = t;
- }
- else {
- nodreg(&nod1, n, D_SI);
- if(reg[D_SI]) {
- gins(APUSHL, &nod1, Z);
- c |= 1;
- reg[D_SI]++;
- }
- lcgen(n, &nod1);
- n->type = t;
- }
- }
- if(v) {
- gins(AMOVL, n, &nod0);
- if(x)
- gins(ANOTL, Z, &nod0);
- gins(AMOVL, &nod0, nn);
- n->xoffset += SZ_LONG;
- nn->xoffset += SZ_LONG;
- gins(AMOVL, n, &nod0);
- if(x)
- gins(ANOTL, Z, &nod0);
- gins(AMOVL, &nod0, nn);
- n->xoffset -= SZ_LONG;
- nn->xoffset -= SZ_LONG;
- if(nn == &nod2)
- regfree(&nod2);
- if(n == &nod1)
- regfree(&nod1);
- regfree(&nod0);
- return;
- }
- nodreg(&nod3, n, D_CX);
- if(reg[D_CX]) {
- gins(APUSHL, &nod3, Z);
- c |= 4;
- reg[D_CX]++;
- }
- gins(AMOVL, nodconst(w/SZ_LONG), &nod3);
- gins(ACLD, Z, Z);
- gins(AREP, Z, Z);
- gins(AMOVSL, Z, Z);
- if(c & 4) {
- gins(APOPL, Z, &nod3);
- reg[D_CX]--;
- }
- if(c & 2) {
- gins(APOPL, Z, &nod2);
- reg[nod2.reg]--;
- }
- if(c & 1) {
- gins(APOPL, Z, &nod1);
- reg[nod1.reg]--;
- }
-}
diff --git a/src/cmd/8c/cgen64.c b/src/cmd/8c/cgen64.c
deleted file mode 100644
index 3424f762c..000000000
--- a/src/cmd/8c/cgen64.c
+++ /dev/null
@@ -1,2657 +0,0 @@
-// Inferno utils/8c/cgen64.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen64.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-void
-zeroregm(Node *n)
-{
- gins(AMOVL, nodconst(0), n);
-}
-
-/* do we need to load the address of a vlong? */
-int
-vaddr(Node *n, int a)
-{
- switch(n->op) {
- case ONAME:
- if(a)
- return 1;
- return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
-
- case OCONST:
- case OREGISTER:
- case OINDREG:
- return 1;
- }
- return 0;
-}
-
-int32
-hi64v(Node *n)
-{
- if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
- return (int32)(n->vconst) & ~0L;
- else
- return (int32)((uvlong)n->vconst>>32) & ~0L;
-}
-
-int32
-lo64v(Node *n)
-{
- if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
- return (int32)((uvlong)n->vconst>>32) & ~0L;
- else
- return (int32)(n->vconst) & ~0L;
-}
-
-Node *
-hi64(Node *n)
-{
- return nodconst(hi64v(n));
-}
-
-Node *
-lo64(Node *n)
-{
- return nodconst(lo64v(n));
-}
-
-static Node *
-anonreg(void)
-{
- Node *n;
-
- n = new(OREGISTER, Z, Z);
- n->reg = D_NONE;
- n->type = types[TLONG];
- return n;
-}
-
-static Node *
-regpair(Node *n, Node *t)
-{
- Node *r;
-
- if(n != Z && n->op == OREGPAIR)
- return n;
- r = new(OREGPAIR, anonreg(), anonreg());
- if(n != Z)
- r->type = n->type;
- else
- r->type = t->type;
- return r;
-}
-
-static void
-evacaxdx(Node *r)
-{
- Node nod1, nod2;
-
- if(r->reg == D_AX || r->reg == D_DX) {
- reg[D_AX]++;
- reg[D_DX]++;
- /*
- * this is just an optim that should
- * check for spill
- */
- r->type = types[TULONG];
- regalloc(&nod1, r, Z);
- nodreg(&nod2, Z, r->reg);
- gins(AMOVL, &nod2, &nod1);
- regfree(r);
- r->reg = nod1.reg;
- reg[D_AX]--;
- reg[D_DX]--;
- }
-}
-
-/* lazy instantiation of register pair */
-static int
-instpair(Node *n, Node *l)
-{
- int r;
-
- r = 0;
- if(n->left->reg == D_NONE) {
- if(l != Z) {
- n->left->reg = l->reg;
- r = 1;
- }
- else
- regalloc(n->left, n->left, Z);
- }
- if(n->right->reg == D_NONE)
- regalloc(n->right, n->right, Z);
- return r;
-}
-
-static void
-zapreg(Node *n)
-{
- if(n->reg != D_NONE) {
- regfree(n);
- n->reg = D_NONE;
- }
-}
-
-static void
-freepair(Node *n)
-{
- regfree(n->left);
- regfree(n->right);
-}
-
-/* n is not OREGPAIR, nn is */
-void
-loadpair(Node *n, Node *nn)
-{
- Node nod;
-
- instpair(nn, Z);
- if(n->op == OCONST) {
- gins(AMOVL, lo64(n), nn->left);
- n->xoffset += SZ_LONG;
- gins(AMOVL, hi64(n), nn->right);
- n->xoffset -= SZ_LONG;
- return;
- }
- if(!vaddr(n, 0)) {
- /* steal the right register for the laddr */
- nod = regnode;
- nod.reg = nn->right->reg;
- lcgen(n, &nod);
- n = &nod;
- regind(n, n);
- n->xoffset = 0;
- }
- gins(AMOVL, n, nn->left);
- n->xoffset += SZ_LONG;
- gins(AMOVL, n, nn->right);
- n->xoffset -= SZ_LONG;
-}
-
-/* n is OREGPAIR, nn is not */
-static void
-storepair(Node *n, Node *nn, int f)
-{
- Node nod;
-
- if(!vaddr(nn, 0)) {
- reglcgen(&nod, nn, Z);
- nn = &nod;
- }
- gins(AMOVL, n->left, nn);
- nn->xoffset += SZ_LONG;
- gins(AMOVL, n->right, nn);
- nn->xoffset -= SZ_LONG;
- if(nn == &nod)
- regfree(&nod);
- if(f)
- freepair(n);
-}
-
-enum
-{
-/* 4 only, see WW */
- WNONE = 0,
- WCONST,
- WADDR,
- WHARD,
-};
-
-static int
-whatof(Node *n, int a)
-{
- if(n->op == OCONST)
- return WCONST;
- return !vaddr(n, a) ? WHARD : WADDR;
-}
-
-/* can upgrade an extern to addr for AND */
-static int
-reduxv(Node *n)
-{
- return lo64v(n) == 0 || hi64v(n) == 0;
-}
-
-int
-cond(int op)
-{
- switch(op) {
- case OANDAND:
- case OOROR:
- case ONOT:
- return 1;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- return 1;
- }
- return 0;
-}
-
-/*
- * for a func operand call it and then return
- * the safe node
- */
-static Node *
-vfunc(Node *n, Node *nn)
-{
- Node *t;
-
- if(n->op != OFUNC)
- return n;
- t = new(0, Z, Z);
- if(nn == Z || nn == nodret)
- nn = n;
- regsalloc(t, nn);
- sugen(n, t, 8);
- return t;
-}
-
-/* try to steal a reg */
-static int
-getreg(Node **np, Node *t, int r)
-{
- Node *n, *p;
-
- n = *np;
- if(n->reg == r) {
- p = new(0, Z, Z);
- regalloc(p, n, Z);
- gins(AMOVL, n, p);
- *t = *n;
- *np = p;
- return 1;
- }
- return 0;
-}
-
-static Node *
-snarfreg(Node *n, Node *t, int r, Node *d, Node *c)
-{
- if(n == Z || n->op != OREGPAIR || (!getreg(&n->left, t, r) && !getreg(&n->right, t, r))) {
- if(nodreg(t, Z, r)) {
- regalloc(c, d, Z);
- gins(AMOVL, t, c);
- reg[r]++;
- return c;
- }
- reg[r]++;
- }
- return Z;
-}
-
-enum
-{
- Vstart = OEND,
-
- Vgo,
- Vamv,
- Vmv,
- Vzero,
- Vop,
- Vopx,
- Vins,
- Vins0,
- Vinsl,
- Vinsr,
- Vinsla,
- Vinsra,
- Vinsx,
- Vmul,
- Vshll,
- VT,
- VF,
- V_l_lo_f,
- V_l_hi_f,
- V_l_lo_t,
- V_l_hi_t,
- V_l_lo_u,
- V_l_hi_u,
- V_r_lo_f,
- V_r_hi_f,
- V_r_lo_t,
- V_r_hi_t,
- V_r_lo_u,
- V_r_hi_u,
- Vspazz,
- Vend,
-
- V_T0,
- V_T1,
- V_F0,
- V_F1,
-
- V_a0,
- V_a1,
- V_f0,
- V_f1,
-
- V_p0,
- V_p1,
- V_p2,
- V_p3,
- V_p4,
-
- V_s0,
- V_s1,
- V_s2,
- V_s3,
- V_s4,
-
- C00,
- C01,
- C31,
- C32,
-
- O_l_lo,
- O_l_hi,
- O_r_lo,
- O_r_hi,
- O_t_lo,
- O_t_hi,
- O_l,
- O_r,
- O_l_rp,
- O_r_rp,
- O_t_rp,
- O_r0,
- O_r1,
- O_Zop,
-
- O_a0,
- O_a1,
-
- V_C0,
- V_C1,
-
- V_S0,
- V_S1,
-
- VOPS = 5,
- VLEN = 5,
- VARGS = 2,
-
- S00 = 0,
- Sc0,
- Sc1,
- Sc2,
- Sac3,
- Sac4,
- S10,
-
- SAgen = 0,
- SAclo,
- SAc32,
- SAchi,
- SAdgen,
- SAdclo,
- SAdc32,
- SAdchi,
-
- B0c = 0,
- Bca,
- Bac,
-
- T0i = 0,
- Tii,
-
- Bop0 = 0,
- Bop1,
-};
-
-/*
- * _testv:
- * CMPL lo,$0
- * JNE true
- * CMPL hi,$0
- * JNE true
- * GOTO false
- * false:
- * GOTO code
- * true:
- * GOTO patchme
- * code:
- */
-
-static uchar testi[][VLEN] =
-{
- {Vop, ONE, O_l_lo, C00},
- {V_s0, Vop, ONE, O_l_hi, C00},
- {V_s1, Vgo, V_s2, Vgo, V_s3},
- {VF, V_p0, V_p1, VT, V_p2},
- {Vgo, V_p3},
- {VT, V_p0, V_p1, VF, V_p2},
- {Vend},
-};
-
-/* shift left general case */
-static uchar shll00[][VLEN] =
-{
- {Vop, OGE, O_r, C32},
- {V_s0, Vinsl, ASHLL, O_r, O_l_rp},
- {Vins, ASHLL, O_r, O_l_lo, Vgo},
- {V_p0, V_s0},
- {Vins, ASHLL, O_r, O_l_lo},
- {Vins, AMOVL, O_l_lo, O_l_hi},
- {Vzero, O_l_lo, V_p0, Vend},
-};
-
-/* shift left rp, const < 32 */
-static uchar shllc0[][VLEN] =
-{
- {Vinsl, ASHLL, O_r, O_l_rp},
- {Vshll, O_r, O_l_lo, Vend},
-};
-
-/* shift left rp, const == 32 */
-static uchar shllc1[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_l_hi},
- {Vzero, O_l_lo, Vend},
-};
-
-/* shift left rp, const > 32 */
-static uchar shllc2[][VLEN] =
-{
- {Vshll, O_r, O_l_lo},
- {Vins, AMOVL, O_l_lo, O_l_hi},
- {Vzero, O_l_lo, Vend},
-};
-
-/* shift left addr, const == 32 */
-static uchar shllac3[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_hi},
- {Vzero, O_t_lo, Vend},
-};
-
-/* shift left addr, const > 32 */
-static uchar shllac4[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_hi},
- {Vshll, O_r, O_t_hi},
- {Vzero, O_t_lo, Vend},
-};
-
-/* shift left of constant */
-static uchar shll10[][VLEN] =
-{
- {Vop, OGE, O_r, C32},
- {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsl, ASHLL, O_r, O_t_rp},
- {Vins, ASHLL, O_r, O_t_lo, Vgo},
- {V_p0, V_s0},
- {Vins, AMOVL, O_l_lo, O_t_hi},
- {V_l_lo_t, Vins, ASHLL, O_r, O_t_hi},
- {Vzero, O_t_lo, V_p0, Vend},
-};
-
-static uchar (*shlltab[])[VLEN] =
-{
- shll00,
- shllc0,
- shllc1,
- shllc2,
- shllac3,
- shllac4,
- shll10,
-};
-
-/* shift right general case */
-static uchar shrl00[][VLEN] =
-{
- {Vop, OGE, O_r, C32},
- {V_s0, Vinsr, ASHRL, O_r, O_l_rp},
- {Vins, O_a0, O_r, O_l_hi, Vgo},
- {V_p0, V_s0},
- {Vins, O_a0, O_r, O_l_hi},
- {Vins, AMOVL, O_l_hi, O_l_lo},
- {V_T1, Vzero, O_l_hi},
- {V_F1, Vins, ASARL, C31, O_l_hi},
- {V_p0, Vend},
-};
-
-/* shift right rp, const < 32 */
-static uchar shrlc0[][VLEN] =
-{
- {Vinsr, ASHRL, O_r, O_l_rp},
- {Vins, O_a0, O_r, O_l_hi, Vend},
-};
-
-/* shift right rp, const == 32 */
-static uchar shrlc1[][VLEN] =
-{
- {Vins, AMOVL, O_l_hi, O_l_lo},
- {V_T1, Vzero, O_l_hi},
- {V_F1, Vins, ASARL, C31, O_l_hi},
- {Vend},
-};
-
-/* shift right rp, const > 32 */
-static uchar shrlc2[][VLEN] =
-{
- {Vins, O_a0, O_r, O_l_hi},
- {Vins, AMOVL, O_l_hi, O_l_lo},
- {V_T1, Vzero, O_l_hi},
- {V_F1, Vins, ASARL, C31, O_l_hi},
- {Vend},
-};
-
-/* shift right addr, const == 32 */
-static uchar shrlac3[][VLEN] =
-{
- {Vins, AMOVL, O_l_hi, O_t_lo},
- {V_T1, Vzero, O_t_hi},
- {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
- {V_F1, Vins, ASARL, C31, O_t_hi},
- {Vend},
-};
-
-/* shift right addr, const > 32 */
-static uchar shrlac4[][VLEN] =
-{
- {Vins, AMOVL, O_l_hi, O_t_lo},
- {Vins, O_a0, O_r, O_t_lo},
- {V_T1, Vzero, O_t_hi},
- {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
- {V_F1, Vins, ASARL, C31, O_t_hi},
- {Vend},
-};
-
-/* shift right of constant */
-static uchar shrl10[][VLEN] =
-{
- {Vop, OGE, O_r, C32},
- {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsr, ASHRL, O_r, O_t_rp},
- {Vins, O_a0, O_r, O_t_hi, Vgo},
- {V_p0, V_s0},
- {Vins, AMOVL, O_l_hi, O_t_lo},
- {V_l_hi_t, Vins, O_a0, O_r, O_t_lo},
- {V_l_hi_u, V_S1},
- {V_T1, Vzero, O_t_hi, V_p0},
- {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
- {V_F1, Vins, ASARL, C31, O_t_hi},
- {Vend},
-};
-
-static uchar (*shrltab[])[VLEN] =
-{
- shrl00,
- shrlc0,
- shrlc1,
- shrlc2,
- shrlac3,
- shrlac4,
- shrl10,
-};
-
-/* shift asop left general case */
-static uchar asshllgen[][VLEN] =
-{
- {V_a0, V_a1},
- {Vop, OGE, O_r, C32},
- {V_s0, Vins, AMOVL, O_l_lo, O_r0},
- {Vins, AMOVL, O_l_hi, O_r1},
- {Vinsla, ASHLL, O_r, O_r0},
- {Vins, ASHLL, O_r, O_r0},
- {Vins, AMOVL, O_r1, O_l_hi},
- {Vins, AMOVL, O_r0, O_l_lo, Vgo},
- {V_p0, V_s0},
- {Vins, AMOVL, O_l_lo, O_r0},
- {Vzero, O_l_lo},
- {Vins, ASHLL, O_r, O_r0},
- {Vins, AMOVL, O_r0, O_l_hi, V_p0},
- {V_f0, V_f1, Vend},
-};
-
-/* shift asop left, const < 32 */
-static uchar asshllclo[][VLEN] =
-{
- {V_a0, V_a1},
- {Vins, AMOVL, O_l_lo, O_r0},
- {Vins, AMOVL, O_l_hi, O_r1},
- {Vinsla, ASHLL, O_r, O_r0},
- {Vshll, O_r, O_r0},
- {Vins, AMOVL, O_r1, O_l_hi},
- {Vins, AMOVL, O_r0, O_l_lo},
- {V_f0, V_f1, Vend},
-};
-
-/* shift asop left, const == 32 */
-static uchar asshllc32[][VLEN] =
-{
- {V_a0},
- {Vins, AMOVL, O_l_lo, O_r0},
- {Vzero, O_l_lo},
- {Vins, AMOVL, O_r0, O_l_hi},
- {V_f0, Vend},
-};
-
-/* shift asop left, const > 32 */
-static uchar asshllchi[][VLEN] =
-{
- {V_a0},
- {Vins, AMOVL, O_l_lo, O_r0},
- {Vzero, O_l_lo},
- {Vshll, O_r, O_r0},
- {Vins, AMOVL, O_r0, O_l_hi},
- {V_f0, Vend},
-};
-
-/* shift asop dest left general case */
-static uchar asdshllgen[][VLEN] =
-{
- {Vop, OGE, O_r, C32},
- {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsl, ASHLL, O_r, O_t_rp},
- {Vins, ASHLL, O_r, O_t_lo},
- {Vins, AMOVL, O_t_hi, O_l_hi},
- {Vins, AMOVL, O_t_lo, O_l_lo, Vgo},
- {V_p0, V_s0},
- {Vins, AMOVL, O_l_lo, O_t_hi},
- {Vzero, O_l_lo},
- {Vins, ASHLL, O_r, O_t_hi},
- {Vzero, O_t_lo},
- {Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
- {Vend},
-};
-
-/* shift asop dest left, const < 32 */
-static uchar asdshllclo[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsl, ASHLL, O_r, O_t_rp},
- {Vshll, O_r, O_t_lo},
- {Vins, AMOVL, O_t_hi, O_l_hi},
- {Vins, AMOVL, O_t_lo, O_l_lo},
- {Vend},
-};
-
-/* shift asop dest left, const == 32 */
-static uchar asdshllc32[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_hi},
- {Vzero, O_t_lo},
- {Vins, AMOVL, O_t_hi, O_l_hi},
- {Vins, AMOVL, O_t_lo, O_l_lo},
- {Vend},
-};
-
-/* shift asop dest, const > 32 */
-static uchar asdshllchi[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_hi},
- {Vzero, O_t_lo},
- {Vshll, O_r, O_t_hi},
- {Vins, AMOVL, O_t_lo, O_l_lo},
- {Vins, AMOVL, O_t_hi, O_l_hi},
- {Vend},
-};
-
-static uchar (*asshlltab[])[VLEN] =
-{
- asshllgen,
- asshllclo,
- asshllc32,
- asshllchi,
- asdshllgen,
- asdshllclo,
- asdshllc32,
- asdshllchi,
-};
-
-/* shift asop right general case */
-static uchar asshrlgen[][VLEN] =
-{
- {V_a0, V_a1},
- {Vop, OGE, O_r, C32},
- {V_s0, Vins, AMOVL, O_l_lo, O_r0},
- {Vins, AMOVL, O_l_hi, O_r1},
- {Vinsra, ASHRL, O_r, O_r0},
- {Vinsx, Bop0, O_r, O_r1},
- {Vins, AMOVL, O_r0, O_l_lo},
- {Vins, AMOVL, O_r1, O_l_hi, Vgo},
- {V_p0, V_s0},
- {Vins, AMOVL, O_l_hi, O_r0},
- {Vinsx, Bop0, O_r, O_r0},
- {V_T1, Vzero, O_l_hi},
- {Vins, AMOVL, O_r0, O_l_lo},
- {V_F1, Vins, ASARL, C31, O_r0},
- {V_F1, Vins, AMOVL, O_r0, O_l_hi},
- {V_p0, V_f0, V_f1, Vend},
-};
-
-/* shift asop right, const < 32 */
-static uchar asshrlclo[][VLEN] =
-{
- {V_a0, V_a1},
- {Vins, AMOVL, O_l_lo, O_r0},
- {Vins, AMOVL, O_l_hi, O_r1},
- {Vinsra, ASHRL, O_r, O_r0},
- {Vinsx, Bop0, O_r, O_r1},
- {Vins, AMOVL, O_r0, O_l_lo},
- {Vins, AMOVL, O_r1, O_l_hi},
- {V_f0, V_f1, Vend},
-};
-
-/* shift asop right, const == 32 */
-static uchar asshrlc32[][VLEN] =
-{
- {V_a0},
- {Vins, AMOVL, O_l_hi, O_r0},
- {V_T1, Vzero, O_l_hi},
- {Vins, AMOVL, O_r0, O_l_lo},
- {V_F1, Vins, ASARL, C31, O_r0},
- {V_F1, Vins, AMOVL, O_r0, O_l_hi},
- {V_f0, Vend},
-};
-
-/* shift asop right, const > 32 */
-static uchar asshrlchi[][VLEN] =
-{
- {V_a0},
- {Vins, AMOVL, O_l_hi, O_r0},
- {V_T1, Vzero, O_l_hi},
- {Vinsx, Bop0, O_r, O_r0},
- {Vins, AMOVL, O_r0, O_l_lo},
- {V_F1, Vins, ASARL, C31, O_r0},
- {V_F1, Vins, AMOVL, O_r0, O_l_hi},
- {V_f0, Vend},
-};
-
-/* shift asop dest right general case */
-static uchar asdshrlgen[][VLEN] =
-{
- {Vop, OGE, O_r, C32},
- {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsr, ASHRL, O_r, O_t_rp},
- {Vinsx, Bop0, O_r, O_t_hi},
- {Vins, AMOVL, O_t_lo, O_l_lo},
- {Vins, AMOVL, O_t_hi, O_l_hi, Vgo},
- {V_p0, V_s0},
- {Vins, AMOVL, O_l_hi, O_t_lo},
- {V_T1, Vzero, O_t_hi},
- {Vinsx, Bop0, O_r, O_t_lo},
- {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
- {V_F1, Vins, ASARL, C31, O_t_hi},
- {Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
- {Vend},
-};
-
-/* shift asop dest right, const < 32 */
-static uchar asdshrlclo[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsr, ASHRL, O_r, O_t_rp},
- {Vinsx, Bop0, O_r, O_t_hi},
- {Vins, AMOVL, O_t_lo, O_l_lo},
- {Vins, AMOVL, O_t_hi, O_l_hi},
- {Vend},
-};
-
-/* shift asop dest right, const == 32 */
-static uchar asdshrlc32[][VLEN] =
-{
- {Vins, AMOVL, O_l_hi, O_t_lo},
- {V_T1, Vzero, O_t_hi},
- {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
- {V_F1, Vins, ASARL, C31, O_t_hi},
- {Vins, AMOVL, O_t_lo, O_l_lo},
- {Vins, AMOVL, O_t_hi, O_l_hi},
- {Vend},
-};
-
-/* shift asop dest, const > 32 */
-static uchar asdshrlchi[][VLEN] =
-{
- {Vins, AMOVL, O_l_hi, O_t_lo},
- {V_T1, Vzero, O_t_hi},
- {Vinsx, Bop0, O_r, O_t_lo},
- {V_T1, Vins, AMOVL, O_t_hi, O_l_hi},
- {V_T1, Vins, AMOVL, O_t_lo, O_l_lo},
- {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
- {V_F1, Vins, ASARL, C31, O_t_hi},
- {V_F1, Vins, AMOVL, O_t_lo, O_l_lo},
- {V_F1, Vins, AMOVL, O_t_hi, O_l_hi},
- {Vend},
-};
-
-static uchar (*asshrltab[])[VLEN] =
-{
- asshrlgen,
- asshrlclo,
- asshrlc32,
- asshrlchi,
- asdshrlgen,
- asdshrlclo,
- asdshrlc32,
- asdshrlchi,
-};
-
-static uchar shrlargs[] = { ASHRL, 1 };
-static uchar sarlargs[] = { ASARL, 0 };
-
-/* ++ -- */
-static uchar incdec[][VLEN] =
-{
- {Vinsx, Bop0, C01, O_l_lo},
- {Vinsx, Bop1, C00, O_l_hi, Vend},
-};
-
-/* ++ -- *p */
-static uchar incdecpre[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsx, Bop0, C01, O_t_lo},
- {Vinsx, Bop1, C00, O_t_hi},
- {Vins, AMOVL, O_t_lo, O_l_lo},
- {Vins, AMOVL, O_t_hi, O_l_hi, Vend},
-};
-
-/* *p ++ -- */
-static uchar incdecpost[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsx, Bop0, C01, O_l_lo},
- {Vinsx, Bop1, C00, O_l_hi, Vend},
-};
-
-/* binop rp, rp */
-static uchar binop00[][VLEN] =
-{
- {Vinsx, Bop0, O_r_lo, O_l_lo},
- {Vinsx, Bop1, O_r_hi, O_l_hi, Vend},
- {Vend},
-};
-
-/* binop rp, addr */
-static uchar binoptmp[][VLEN] =
-{
- {V_a0, Vins, AMOVL, O_r_lo, O_r0},
- {Vinsx, Bop0, O_r0, O_l_lo},
- {Vins, AMOVL, O_r_hi, O_r0},
- {Vinsx, Bop1, O_r0, O_l_hi},
- {V_f0, Vend},
-};
-
-/* binop t = *a op *b */
-static uchar binop11[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_lo},
- {Vinsx, Bop0, O_r_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsx, Bop1, O_r_hi, O_t_hi, Vend},
-};
-
-/* binop t = rp +- c */
-static uchar add0c[][VLEN] =
-{
- {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
- {V_r_lo_f, Vamv, Bop0, Bop1},
- {Vinsx, Bop1, O_r_hi, O_l_hi},
- {Vend},
-};
-
-/* binop t = rp & c */
-static uchar and0c[][VLEN] =
-{
- {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
- {V_r_lo_f, Vins, AMOVL, C00, O_l_lo},
- {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
- {V_r_hi_f, Vins, AMOVL, C00, O_l_hi},
- {Vend},
-};
-
-/* binop t = rp | c */
-static uchar or0c[][VLEN] =
-{
- {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
- {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
- {Vend},
-};
-
-/* binop t = c - rp */
-static uchar sub10[][VLEN] =
-{
- {V_a0, Vins, AMOVL, O_l_lo, O_r0},
- {Vinsx, Bop0, O_r_lo, O_r0},
- {Vins, AMOVL, O_l_hi, O_r_lo},
- {Vinsx, Bop1, O_r_hi, O_r_lo},
- {Vspazz, V_f0, Vend},
-};
-
-/* binop t = c + *b */
-static uchar addca[][VLEN] =
-{
- {Vins, AMOVL, O_r_lo, O_t_lo},
- {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
- {V_l_lo_f, Vamv, Bop0, Bop1},
- {Vins, AMOVL, O_r_hi, O_t_hi},
- {Vinsx, Bop1, O_l_hi, O_t_hi},
- {Vend},
-};
-
-/* binop t = c & *b */
-static uchar andca[][VLEN] =
-{
- {V_l_lo_t, Vins, AMOVL, O_r_lo, O_t_lo},
- {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
- {V_l_lo_f, Vzero, O_t_lo},
- {V_l_hi_t, Vins, AMOVL, O_r_hi, O_t_hi},
- {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
- {V_l_hi_f, Vzero, O_t_hi},
- {Vend},
-};
-
-/* binop t = c | *b */
-static uchar orca[][VLEN] =
-{
- {Vins, AMOVL, O_r_lo, O_t_lo},
- {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
- {Vins, AMOVL, O_r_hi, O_t_hi},
- {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
- {Vend},
-};
-
-/* binop t = c - *b */
-static uchar subca[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsx, Bop0, O_r_lo, O_t_lo},
- {Vinsx, Bop1, O_r_hi, O_t_hi},
- {Vend},
-};
-
-/* binop t = *a +- c */
-static uchar addac[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_lo},
- {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
- {V_r_lo_f, Vamv, Bop0, Bop1},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {Vinsx, Bop1, O_r_hi, O_t_hi},
- {Vend},
-};
-
-/* binop t = *a | c */
-static uchar orac[][VLEN] =
-{
- {Vins, AMOVL, O_l_lo, O_t_lo},
- {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
- {Vins, AMOVL, O_l_hi, O_t_hi},
- {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_t_hi},
- {Vend},
-};
-
-/* binop t = *a & c */
-static uchar andac[][VLEN] =
-{
- {V_r_lo_t, Vins, AMOVL, O_l_lo, O_t_lo},
- {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
- {V_r_lo_f, Vzero, O_t_lo},
- {V_r_hi_t, Vins, AMOVL, O_l_hi, O_t_hi},
- {V_r_hi_t, Vinsx, Bop0, O_r_hi, O_t_hi},
- {V_r_hi_f, Vzero, O_t_hi},
- {Vend},
-};
-
-static uchar ADDargs[] = { AADDL, AADCL };
-static uchar ANDargs[] = { AANDL, AANDL };
-static uchar ORargs[] = { AORL, AORL };
-static uchar SUBargs[] = { ASUBL, ASBBL };
-static uchar XORargs[] = { AXORL, AXORL };
-
-static uchar (*ADDtab[])[VLEN] =
-{
- add0c, addca, addac,
-};
-
-static uchar (*ANDtab[])[VLEN] =
-{
- and0c, andca, andac,
-};
-
-static uchar (*ORtab[])[VLEN] =
-{
- or0c, orca, orac,
-};
-
-static uchar (*SUBtab[])[VLEN] =
-{
- add0c, subca, addac,
-};
-
-/* mul of const32 */
-static uchar mulc32[][VLEN] =
-{
- {V_a0, Vop, ONE, O_l_hi, C00},
- {V_s0, Vins, AMOVL, O_r_lo, O_r0},
- {Vins, AMULL, O_r0, O_Zop},
- {Vgo, V_p0, V_s0},
- {Vins, AMOVL, O_l_hi, O_r0},
- {Vmul, O_r_lo, O_r0},
- {Vins, AMOVL, O_r_lo, O_l_hi},
- {Vins, AMULL, O_l_hi, O_Zop},
- {Vins, AADDL, O_r0, O_l_hi},
- {V_f0, V_p0, Vend},
-};
-
-/* mul of const64 */
-static uchar mulc64[][VLEN] =
-{
- {V_a0, Vins, AMOVL, O_r_hi, O_r0},
- {Vop, OOR, O_l_hi, O_r0},
- {Vop, ONE, O_r0, C00},
- {V_s0, Vins, AMOVL, O_r_lo, O_r0},
- {Vins, AMULL, O_r0, O_Zop},
- {Vgo, V_p0, V_s0},
- {Vmul, O_r_lo, O_l_hi},
- {Vins, AMOVL, O_l_lo, O_r0},
- {Vmul, O_r_hi, O_r0},
- {Vins, AADDL, O_l_hi, O_r0},
- {Vins, AMOVL, O_r_lo, O_l_hi},
- {Vins, AMULL, O_l_hi, O_Zop},
- {Vins, AADDL, O_r0, O_l_hi},
- {V_f0, V_p0, Vend},
-};
-
-/* mul general */
-static uchar mull[][VLEN] =
-{
- {V_a0, Vins, AMOVL, O_r_hi, O_r0},
- {Vop, OOR, O_l_hi, O_r0},
- {Vop, ONE, O_r0, C00},
- {V_s0, Vins, AMOVL, O_r_lo, O_r0},
- {Vins, AMULL, O_r0, O_Zop},
- {Vgo, V_p0, V_s0},
- {Vins, AIMULL, O_r_lo, O_l_hi},
- {Vins, AMOVL, O_l_lo, O_r0},
- {Vins, AIMULL, O_r_hi, O_r0},
- {Vins, AADDL, O_l_hi, O_r0},
- {Vins, AMOVL, O_r_lo, O_l_hi},
- {Vins, AMULL, O_l_hi, O_Zop},
- {Vins, AADDL, O_r0, O_l_hi},
- {V_f0, V_p0, Vend},
-};
-
-/* cast rp l to rp t */
-static uchar castrp[][VLEN] =
-{
- {Vmv, O_l, O_t_lo},
- {VT, Vins, AMOVL, O_t_lo, O_t_hi},
- {VT, Vins, ASARL, C31, O_t_hi},
- {VF, Vzero, O_t_hi},
- {Vend},
-};
-
-/* cast rp l to addr t */
-static uchar castrpa[][VLEN] =
-{
- {VT, V_a0, Vmv, O_l, O_r0},
- {VT, Vins, AMOVL, O_r0, O_t_lo},
- {VT, Vins, ASARL, C31, O_r0},
- {VT, Vins, AMOVL, O_r0, O_t_hi},
- {VT, V_f0},
- {VF, Vmv, O_l, O_t_lo},
- {VF, Vzero, O_t_hi},
- {Vend},
-};
-
-static uchar netab0i[][VLEN] =
-{
- {Vop, ONE, O_l_lo, O_r_lo},
- {V_s0, Vop, ONE, O_l_hi, O_r_hi},
- {V_s1, Vgo, V_s2, Vgo, V_s3},
- {VF, V_p0, V_p1, VT, V_p2},
- {Vgo, V_p3},
- {VT, V_p0, V_p1, VF, V_p2},
- {Vend},
-};
-
-static uchar netabii[][VLEN] =
-{
- {V_a0, Vins, AMOVL, O_l_lo, O_r0},
- {Vop, ONE, O_r0, O_r_lo},
- {V_s0, Vins, AMOVL, O_l_hi, O_r0},
- {Vop, ONE, O_r0, O_r_hi},
- {V_s1, Vgo, V_s2, Vgo, V_s3},
- {VF, V_p0, V_p1, VT, V_p2},
- {Vgo, V_p3},
- {VT, V_p0, V_p1, VF, V_p2},
- {V_f0, Vend},
-};
-
-static uchar cmptab0i[][VLEN] =
-{
- {Vopx, Bop0, O_l_hi, O_r_hi},
- {V_s0, Vins0, AJNE},
- {V_s1, Vopx, Bop1, O_l_lo, O_r_lo},
- {V_s2, Vgo, V_s3, Vgo, V_s4},
- {VT, V_p1, V_p3},
- {VF, V_p0, V_p2},
- {Vgo, V_p4},
- {VT, V_p0, V_p2},
- {VF, V_p1, V_p3},
- {Vend},
-};
-
-static uchar cmptabii[][VLEN] =
-{
- {V_a0, Vins, AMOVL, O_l_hi, O_r0},
- {Vopx, Bop0, O_r0, O_r_hi},
- {V_s0, Vins0, AJNE},
- {V_s1, Vins, AMOVL, O_l_lo, O_r0},
- {Vopx, Bop1, O_r0, O_r_lo},
- {V_s2, Vgo, V_s3, Vgo, V_s4},
- {VT, V_p1, V_p3},
- {VF, V_p0, V_p2},
- {Vgo, V_p4},
- {VT, V_p0, V_p2},
- {VF, V_p1, V_p3},
- {V_f0, Vend},
-};
-
-static uchar (*NEtab[])[VLEN] =
-{
- netab0i, netabii,
-};
-
-static uchar (*cmptab[])[VLEN] =
-{
- cmptab0i, cmptabii,
-};
-
-static uchar GEargs[] = { OGT, OHS };
-static uchar GTargs[] = { OGT, OHI };
-static uchar HIargs[] = { OHI, OHI };
-static uchar HSargs[] = { OHI, OHS };
-
-/* Big Generator */
-static void
-biggen(Node *l, Node *r, Node *t, int true, uchar code[][VLEN], uchar *a)
-{
- int i, j, g, oc, op, lo, ro, to, xo, *xp;
- Type *lt;
- Prog *pr[VOPS];
- Node *ot, *tl, *tr, tmps[2];
- uchar *c, (*cp)[VLEN], args[VARGS];
-
- if(a != nil)
- memmove(args, a, VARGS);
-//print("biggen %d %d %d\n", args[0], args[1], args[2]);
-//if(l) prtree(l, "l");
-//if(r) prtree(r, "r");
-//if(t) prtree(t, "t");
- lo = ro = to = 0;
- cp = code;
-
- for (;;) {
- c = *cp++;
- g = 1;
- i = 0;
-//print("code %d %d %d %d %d\n", c[0], c[1], c[2], c[3], c[4]);
- for(;;) {
- switch(op = c[i]) {
- case Vgo:
- if(g)
- gbranch(OGOTO);
- i++;
- break;
-
- case Vamv:
- i += 3;
- if(i > VLEN) {
- diag(l, "bad Vop");
- return;
- }
- if(g)
- args[c[i - 1]] = args[c[i - 2]];
- break;
-
- case Vzero:
- i += 2;
- if(i > VLEN) {
- diag(l, "bad Vop");
- return;
- }
- j = i - 1;
- goto op;
-
- case Vspazz: // nasty hack to save a reg in SUB
-//print("spazz\n");
- if(g) {
-//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
- ot = r->right;
- r->right = r->left;
- tl = new(0, Z, Z);
- *tl = tmps[0];
- r->left = tl;
- tmps[0] = *ot;
-//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
- }
- i++;
- break;
-
- case Vmv:
- case Vmul:
- case Vshll:
- i += 3;
- if(i > VLEN) {
- diag(l, "bad Vop");
- return;
- }
- j = i - 2;
- goto op;
-
- case Vins0:
- i += 2;
- if(i > VLEN) {
- diag(l, "bad Vop");
- return;
- }
- gins(c[i - 1], Z, Z);
- break;
-
- case Vop:
- case Vopx:
- case Vins:
- case Vinsl:
- case Vinsr:
- case Vinsla:
- case Vinsra:
- case Vinsx:
- i += 4;
- if(i > VLEN) {
- diag(l, "bad Vop");
- return;
- }
- j = i - 2;
- goto op;
-
- op:
- if(!g)
- break;
- tl = Z;
- tr = Z;
- for(; j < i; j++) {
- switch(c[j]) {
- case C00:
- ot = nodconst(0);
- break;
- case C01:
- ot = nodconst(1);
- break;
- case C31:
- ot = nodconst(31);
- break;
- case C32:
- ot = nodconst(32);
- break;
-
- case O_l:
- case O_l_lo:
- ot = l; xp = &lo; xo = 0;
- goto op0;
- case O_l_hi:
- ot = l; xp = &lo; xo = SZ_LONG;
- goto op0;
- case O_r:
- case O_r_lo:
- ot = r; xp = &ro; xo = 0;
- goto op0;
- case O_r_hi:
- ot = r; xp = &ro; xo = SZ_LONG;
- goto op0;
- case O_t_lo:
- ot = t; xp = &to; xo = 0;
- goto op0;
- case O_t_hi:
- ot = t; xp = &to; xo = SZ_LONG;
- goto op0;
- case O_l_rp:
- ot = l;
- break;
- case O_r_rp:
- ot = r;
- break;
- case O_t_rp:
- ot = t;
- break;
- case O_r0:
- case O_r1:
- ot = &tmps[c[j] - O_r0];
- break;
- case O_Zop:
- ot = Z;
- break;
-
- op0:
- switch(ot->op) {
- case OCONST:
- if(xo)
- ot = hi64(ot);
- else
- ot = lo64(ot);
- break;
- case OREGPAIR:
- if(xo)
- ot = ot->right;
- else
- ot = ot->left;
- break;
- case OREGISTER:
- break;
- default:
- if(xo != *xp) {
- ot->xoffset += xo - *xp;
- *xp = xo;
- }
- }
- break;
-
- default:
- diag(l, "bad V_lop");
- return;
- }
- if(tl == nil)
- tl = ot;
- else
- tr = ot;
- }
- if(op == Vzero) {
- zeroregm(tl);
- break;
- }
- oc = c[i - 3];
- if(op == Vinsx || op == Vopx) {
-//print("%d -> %d\n", oc, args[oc]);
- oc = args[oc];
- }
- else {
- switch(oc) {
- case O_a0:
- case O_a1:
- oc = args[oc - O_a0];
- break;
- }
- }
- switch(op) {
- case Vmul:
- mulgen(tr->type, tl, tr);
- break;
- case Vmv:
- gmove(tl, tr);
- break;
- case Vshll:
- shiftit(tr->type, tl, tr);
- break;
- case Vop:
- case Vopx:
- gopcode(oc, types[TULONG], tl, tr);
- break;
- case Vins:
- case Vinsx:
- gins(oc, tl, tr);
- break;
- case Vinsl:
- gins(oc, tl, tr->right);
- p->from.index = tr->left->reg;
- break;
- case Vinsr:
- gins(oc, tl, tr->left);
- p->from.index = tr->right->reg;
- break;
- case Vinsla:
- gins(oc, tl, tr + 1);
- p->from.index = tr->reg;
- break;
- case Vinsra:
- gins(oc, tl, tr);
- p->from.index = (tr + 1)->reg;
- break;
- }
- break;
-
- case VT:
- g = true;
- i++;
- break;
- case VF:
- g = !true;
- i++;
- break;
-
- case V_T0: case V_T1:
- g = args[op - V_T0];
- i++;
- break;
-
- case V_F0: case V_F1:
- g = !args[op - V_F0];
- i++;
- break;
-
- case V_C0: case V_C1:
- if(g)
- args[op - V_C0] = 0;
- i++;
- break;
-
- case V_S0: case V_S1:
- if(g)
- args[op - V_S0] = 1;
- i++;
- break;
-
- case V_l_lo_f:
- g = lo64v(l) == 0;
- i++;
- break;
- case V_l_hi_f:
- g = hi64v(l) == 0;
- i++;
- break;
- case V_l_lo_t:
- g = lo64v(l) != 0;
- i++;
- break;
- case V_l_hi_t:
- g = hi64v(l) != 0;
- i++;
- break;
- case V_l_lo_u:
- g = lo64v(l) >= 0;
- i++;
- break;
- case V_l_hi_u:
- g = hi64v(l) >= 0;
- i++;
- break;
- case V_r_lo_f:
- g = lo64v(r) == 0;
- i++;
- break;
- case V_r_hi_f:
- g = hi64v(r) == 0;
- i++;
- break;
- case V_r_lo_t:
- g = lo64v(r) != 0;
- i++;
- break;
- case V_r_hi_t:
- g = hi64v(r) != 0;
- i++;
- break;
- case V_r_lo_u:
- g = lo64v(r) >= 0;
- i++;
- break;
- case V_r_hi_u:
- g = hi64v(r) >= 0;
- i++;
- break;
-
- case Vend:
- goto out;
-
- case V_a0: case V_a1:
- if(g) {
- lt = l->type;
- l->type = types[TULONG];
- regalloc(&tmps[op - V_a0], l, Z);
- l->type = lt;
- }
- i++;
- break;
-
- case V_f0: case V_f1:
- if(g)
- regfree(&tmps[op - V_f0]);
- i++;
- break;
-
- case V_p0: case V_p1: case V_p2: case V_p3: case V_p4:
- if(g)
- patch(pr[op - V_p0], pc);
- i++;
- break;
-
- case V_s0: case V_s1: case V_s2: case V_s3: case V_s4:
- if(g)
- pr[op - V_s0] = p;
- i++;
- break;
-
- default:
- diag(l, "bad biggen: %d", op);
- return;
- }
- if(i == VLEN || c[i] == 0)
- break;
- }
- }
-out:
- if(lo)
- l->xoffset -= lo;
- if(ro)
- r->xoffset -= ro;
- if(to)
- t->xoffset -= to;
-}
-
-int
-cgen64(Node *n, Node *nn)
-{
- Type *dt;
- uchar *args, (*cp)[VLEN], (**optab)[VLEN];
- int li, ri, lri, dr, si, m, op, sh, cmp, true;
- Node *c, *d, *l, *r, *t, *s, nod1, nod2, nod3, nod4, nod5;
-
- if(debug['g']) {
- prtree(nn, "cgen64 lhs");
- prtree(n, "cgen64");
- print("AX = %d\n", reg[D_AX]);
- }
- cmp = 0;
- sh = 0;
-
- switch(n->op) {
- case ONEG:
- d = regpair(nn, n);
- sugen(n->left, d, 8);
- gins(ANOTL, Z, d->right);
- gins(ANEGL, Z, d->left);
- gins(ASBBL, nodconst(-1), d->right);
- break;
-
- case OCOM:
- if(!vaddr(n->left, 0) || !vaddr(nn, 0))
- d = regpair(nn, n);
- else
- return 0;
- sugen(n->left, d, 8);
- gins(ANOTL, Z, d->left);
- gins(ANOTL, Z, d->right);
- break;
-
- case OADD:
- optab = ADDtab;
- args = ADDargs;
- goto twoop;
- case OAND:
- optab = ANDtab;
- args = ANDargs;
- goto twoop;
- case OOR:
- optab = ORtab;
- args = ORargs;
- goto twoop;
- case OSUB:
- optab = SUBtab;
- args = SUBargs;
- goto twoop;
- case OXOR:
- optab = ORtab;
- args = XORargs;
- goto twoop;
- case OASHL:
- sh = 1;
- args = nil;
- optab = shlltab;
- goto twoop;
- case OLSHR:
- sh = 1;
- args = shrlargs;
- optab = shrltab;
- goto twoop;
- case OASHR:
- sh = 1;
- args = sarlargs;
- optab = shrltab;
- goto twoop;
- case OEQ:
- cmp = 1;
- args = nil;
- optab = nil;
- goto twoop;
- case ONE:
- cmp = 1;
- args = nil;
- optab = nil;
- goto twoop;
- case OLE:
- cmp = 1;
- args = nil;
- optab = nil;
- goto twoop;
- case OLT:
- cmp = 1;
- args = nil;
- optab = nil;
- goto twoop;
- case OGE:
- cmp = 1;
- args = nil;
- optab = nil;
- goto twoop;
- case OGT:
- cmp = 1;
- args = nil;
- optab = nil;
- goto twoop;
- case OHI:
- cmp = 1;
- args = nil;
- optab = nil;
- goto twoop;
- case OHS:
- cmp = 1;
- args = nil;
- optab = nil;
- goto twoop;
- case OLO:
- cmp = 1;
- args = nil;
- optab = nil;
- goto twoop;
- case OLS:
- cmp = 1;
- args = nil;
- optab = nil;
- goto twoop;
-
-twoop:
- dr = nn != Z && nn->op == OREGPAIR;
- l = vfunc(n->left, nn);
- if(sh)
- r = n->right;
- else
- r = vfunc(n->right, nn);
-
- li = l->op == ONAME || l->op == OINDREG || l->op == OCONST;
- ri = r->op == ONAME || r->op == OINDREG || r->op == OCONST;
-
-#define IMM(l, r) ((l) | ((r) << 1))
-
- lri = IMM(li, ri);
-
- /* find out what is so easy about some operands */
- if(li)
- li = whatof(l, sh | cmp);
- if(ri)
- ri = whatof(r, cmp);
-
- if(sh)
- goto shift;
-
- if(cmp)
- goto cmp;
-
- /* evaluate hard subexps, stealing nn if possible. */
- switch(lri) {
- case IMM(0, 0):
- bin00:
- if(l->complex > r->complex) {
- if(dr)
- t = nn;
- else
- t = regpair(Z, n);
- sugen(l, t, 8);
- l = t;
- t = regpair(Z, n);
- sugen(r, t, 8);
- r = t;
- }
- else {
- t = regpair(Z, n);
- sugen(r, t, 8);
- r = t;
- if(dr)
- t = nn;
- else
- t = regpair(Z, n);
- sugen(l, t, 8);
- l = t;
- }
- break;
- case IMM(0, 1):
- if(dr)
- t = nn;
- else
- t = regpair(Z, n);
- sugen(l, t, 8);
- l = t;
- break;
- case IMM(1, 0):
- if(n->op == OSUB && l->op == OCONST && hi64v(l) == 0) {
- lri = IMM(0, 0);
- goto bin00;
- }
- if(dr)
- t = nn;
- else
- t = regpair(Z, n);
- sugen(r, t, 8);
- r = t;
- break;
- case IMM(1, 1):
- break;
- }
-
-#define WW(l, r) ((l) | ((r) << 2))
- d = Z;
- dt = nn->type;
- nn->type = types[TLONG];
-
- switch(lri) {
- case IMM(0, 0):
- biggen(l, r, Z, 0, binop00, args);
- break;
- case IMM(0, 1):
- switch(ri) {
- case WNONE:
- diag(r, "bad whatof\n");
- break;
- case WCONST:
- biggen(l, r, Z, 0, optab[B0c], args);
- break;
- case WHARD:
- reglcgen(&nod2, r, Z);
- r = &nod2;
- /* fall thru */
- case WADDR:
- biggen(l, r, Z, 0, binoptmp, args);
- if(ri == WHARD)
- regfree(r);
- break;
- }
- break;
- case IMM(1, 0):
- if(n->op == OSUB) {
- switch(li) {
- case WNONE:
- diag(l, "bad whatof\n");
- break;
- case WHARD:
- reglcgen(&nod2, l, Z);
- l = &nod2;
- /* fall thru */
- case WADDR:
- case WCONST:
- biggen(l, r, Z, 0, sub10, args);
- break;
- }
- if(li == WHARD)
- regfree(l);
- }
- else {
- switch(li) {
- case WNONE:
- diag(l, "bad whatof\n");
- break;
- case WCONST:
- biggen(r, l, Z, 0, optab[B0c], args);
- break;
- case WHARD:
- reglcgen(&nod2, l, Z);
- l = &nod2;
- /* fall thru */
- case WADDR:
- biggen(r, l, Z, 0, binoptmp, args);
- if(li == WHARD)
- regfree(l);
- break;
- }
- }
- break;
- case IMM(1, 1):
- switch(WW(li, ri)) {
- case WW(WCONST, WHARD):
- if(r->op == ONAME && n->op == OAND && reduxv(l))
- ri = WADDR;
- break;
- case WW(WHARD, WCONST):
- if(l->op == ONAME && n->op == OAND && reduxv(r))
- li = WADDR;
- break;
- }
- if(li == WHARD) {
- reglcgen(&nod3, l, Z);
- l = &nod3;
- }
- if(ri == WHARD) {
- reglcgen(&nod2, r, Z);
- r = &nod2;
- }
- d = regpair(nn, n);
- instpair(d, Z);
- switch(WW(li, ri)) {
- case WW(WCONST, WADDR):
- case WW(WCONST, WHARD):
- biggen(l, r, d, 0, optab[Bca], args);
- break;
-
- case WW(WADDR, WCONST):
- case WW(WHARD, WCONST):
- biggen(l, r, d, 0, optab[Bac], args);
- break;
-
- case WW(WADDR, WADDR):
- case WW(WADDR, WHARD):
- case WW(WHARD, WADDR):
- case WW(WHARD, WHARD):
- biggen(l, r, d, 0, binop11, args);
- break;
-
- default:
- diag(r, "bad whatof pair %d %d\n", li, ri);
- break;
- }
- if(li == WHARD)
- regfree(l);
- if(ri == WHARD)
- regfree(r);
- break;
- }
-
- nn->type = dt;
-
- if(d != Z)
- goto finished;
-
- switch(lri) {
- case IMM(0, 0):
- freepair(r);
- /* fall thru */;
- case IMM(0, 1):
- if(!dr)
- storepair(l, nn, 1);
- break;
- case IMM(1, 0):
- if(!dr)
- storepair(r, nn, 1);
- break;
- case IMM(1, 1):
- break;
- }
- return 1;
-
- shift:
- c = Z;
-
- /* evaluate hard subexps, stealing nn if possible. */
- /* must also secure CX. not as many optims as binop. */
- switch(lri) {
- case IMM(0, 0):
- imm00:
- if(l->complex + 1 > r->complex) {
- if(dr)
- t = nn;
- else
- t = regpair(Z, l);
- sugen(l, t, 8);
- l = t;
- t = &nod1;
- c = snarfreg(l, t, D_CX, r, &nod2);
- cgen(r, t);
- r = t;
- }
- else {
- t = &nod1;
- c = snarfreg(nn, t, D_CX, r, &nod2);
- cgen(r, t);
- r = t;
- if(dr)
- t = nn;
- else
- t = regpair(Z, l);
- sugen(l, t, 8);
- l = t;
- }
- break;
- case IMM(0, 1):
- imm01:
- if(ri != WCONST) {
- lri = IMM(0, 0);
- goto imm00;
- }
- if(dr)
- t = nn;
- else
- t = regpair(Z, n);
- sugen(l, t, 8);
- l = t;
- break;
- case IMM(1, 0):
- imm10:
- if(li != WCONST) {
- lri = IMM(0, 0);
- goto imm00;
- }
- t = &nod1;
- c = snarfreg(nn, t, D_CX, r, &nod2);
- cgen(r, t);
- r = t;
- break;
- case IMM(1, 1):
- if(ri != WCONST) {
- lri = IMM(1, 0);
- goto imm10;
- }
- if(li == WHARD) {
- lri = IMM(0, 1);
- goto imm01;
- }
- break;
- }
-
- d = Z;
-
- switch(lri) {
- case IMM(0, 0):
- biggen(l, r, Z, 0, optab[S00], args);
- break;
- case IMM(0, 1):
- switch(ri) {
- case WNONE:
- case WADDR:
- case WHARD:
- diag(r, "bad whatof\n");
- break;
- case WCONST:
- m = r->vconst & 63;
- s = nodconst(m);
- if(m < 32)
- cp = optab[Sc0];
- else if(m == 32)
- cp = optab[Sc1];
- else
- cp = optab[Sc2];
- biggen(l, s, Z, 0, cp, args);
- break;
- }
- break;
- case IMM(1, 0):
- /* left is const */
- d = regpair(nn, n);
- instpair(d, Z);
- biggen(l, r, d, 0, optab[S10], args);
- regfree(r);
- break;
- case IMM(1, 1):
- d = regpair(nn, n);
- instpair(d, Z);
- switch(WW(li, ri)) {
- case WW(WADDR, WCONST):
- m = r->vconst & 63;
- s = nodconst(m);
- if(m < 32) {
- loadpair(l, d);
- l = d;
- cp = optab[Sc0];
- }
- else if(m == 32)
- cp = optab[Sac3];
- else
- cp = optab[Sac4];
- biggen(l, s, d, 0, cp, args);
- break;
-
- default:
- diag(r, "bad whatof pair %d %d\n", li, ri);
- break;
- }
- break;
- }
-
- if(c != Z) {
- gins(AMOVL, c, r);
- regfree(c);
- }
-
- if(d != Z)
- goto finished;
-
- switch(lri) {
- case IMM(0, 0):
- regfree(r);
- /* fall thru */
- case IMM(0, 1):
- if(!dr)
- storepair(l, nn, 1);
- break;
- case IMM(1, 0):
- regfree(r);
- break;
- case IMM(1, 1):
- break;
- }
- return 1;
-
- cmp:
- op = n->op;
- /* evaluate hard subexps */
- switch(lri) {
- case IMM(0, 0):
- if(l->complex > r->complex) {
- t = regpair(Z, l);
- sugen(l, t, 8);
- l = t;
- t = regpair(Z, r);
- sugen(r, t, 8);
- r = t;
- }
- else {
- t = regpair(Z, r);
- sugen(r, t, 8);
- r = t;
- t = regpair(Z, l);
- sugen(l, t, 8);
- l = t;
- }
- break;
- case IMM(1, 0):
- t = r;
- r = l;
- l = t;
- ri = li;
- op = invrel[relindex(op)];
- /* fall thru */
- case IMM(0, 1):
- t = regpair(Z, l);
- sugen(l, t, 8);
- l = t;
- break;
- case IMM(1, 1):
- break;
- }
-
- true = 1;
- optab = cmptab;
- switch(op) {
- case OEQ:
- optab = NEtab;
- true = 0;
- break;
- case ONE:
- optab = NEtab;
- break;
- case OLE:
- args = GTargs;
- true = 0;
- break;
- case OGT:
- args = GTargs;
- break;
- case OLS:
- args = HIargs;
- true = 0;
- break;
- case OHI:
- args = HIargs;
- break;
- case OLT:
- args = GEargs;
- true = 0;
- break;
- case OGE:
- args = GEargs;
- break;
- case OLO:
- args = HSargs;
- true = 0;
- break;
- case OHS:
- args = HSargs;
- break;
- default:
- diag(n, "bad cmp\n");
- SET(optab);
- }
-
- switch(lri) {
- case IMM(0, 0):
- biggen(l, r, Z, true, optab[T0i], args);
- break;
- case IMM(0, 1):
- case IMM(1, 0):
- switch(ri) {
- case WNONE:
- diag(l, "bad whatof\n");
- break;
- case WCONST:
- biggen(l, r, Z, true, optab[T0i], args);
- break;
- case WHARD:
- reglcgen(&nod2, r, Z);
- r = &nod2;
- /* fall thru */
- case WADDR:
- biggen(l, r, Z, true, optab[T0i], args);
- if(ri == WHARD)
- regfree(r);
- break;
- }
- break;
- case IMM(1, 1):
- if(li == WHARD) {
- reglcgen(&nod3, l, Z);
- l = &nod3;
- }
- if(ri == WHARD) {
- reglcgen(&nod2, r, Z);
- r = &nod2;
- }
- biggen(l, r, Z, true, optab[Tii], args);
- if(li == WHARD)
- regfree(l);
- if(ri == WHARD)
- regfree(r);
- break;
- }
-
- switch(lri) {
- case IMM(0, 0):
- freepair(r);
- /* fall thru */;
- case IMM(0, 1):
- case IMM(1, 0):
- freepair(l);
- break;
- case IMM(1, 1):
- break;
- }
- return 1;
-
- case OASMUL:
- case OASLMUL:
- m = 0;
- goto mulop;
-
- case OMUL:
- case OLMUL:
- m = 1;
- goto mulop;
-
- mulop:
- dr = nn != Z && nn->op == OREGPAIR;
- l = vfunc(n->left, nn);
- r = vfunc(n->right, nn);
- if(r->op != OCONST) {
- if(l->complex > r->complex) {
- if(m) {
- t = l;
- l = r;
- r = t;
- }
- else if(!vaddr(l, 1)) {
- reglcgen(&nod5, l, Z);
- l = &nod5;
- evacaxdx(l);
- }
- }
- t = regpair(Z, n);
- sugen(r, t, 8);
- r = t;
- evacaxdx(r->left);
- evacaxdx(r->right);
- if(l->complex <= r->complex && !m && !vaddr(l, 1)) {
- reglcgen(&nod5, l, Z);
- l = &nod5;
- evacaxdx(l);
- }
- }
- if(dr)
- t = nn;
- else
- t = regpair(Z, n);
- c = Z;
- d = Z;
- if(!nodreg(&nod1, t->left, D_AX)) {
- if(t->left->reg != D_AX){
- t->left->reg = D_AX;
- reg[D_AX]++;
- }else if(reg[D_AX] == 0)
- fatal(Z, "vlong mul AX botch");
- }
- if(!nodreg(&nod2, t->right, D_DX)) {
- if(t->right->reg != D_DX){
- t->right->reg = D_DX;
- reg[D_DX]++;
- }else if(reg[D_DX] == 0)
- fatal(Z, "vlong mul DX botch");
- }
- if(m)
- sugen(l, t, 8);
- else
- loadpair(l, t);
- if(t->left->reg != D_AX) {
- c = &nod3;
- regsalloc(c, t->left);
- gmove(&nod1, c);
- gmove(t->left, &nod1);
- zapreg(t->left);
- }
- if(t->right->reg != D_DX) {
- d = &nod4;
- regsalloc(d, t->right);
- gmove(&nod2, d);
- gmove(t->right, &nod2);
- zapreg(t->right);
- }
- if(c != Z || d != Z) {
- s = regpair(Z, n);
- s->left = &nod1;
- s->right = &nod2;
- }
- else
- s = t;
- if(r->op == OCONST) {
- if(hi64v(r) == 0)
- biggen(s, r, Z, 0, mulc32, nil);
- else
- biggen(s, r, Z, 0, mulc64, nil);
- }
- else
- biggen(s, r, Z, 0, mull, nil);
- instpair(t, Z);
- if(c != Z) {
- gmove(&nod1, t->left);
- gmove(&nod3, &nod1);
- }
- if(d != Z) {
- gmove(&nod2, t->right);
- gmove(&nod4, &nod2);
- }
- if(r->op == OREGPAIR)
- freepair(r);
- if(!m)
- storepair(t, l, 0);
- if(l == &nod5)
- regfree(l);
- if(!dr) {
- if(nn != Z)
- storepair(t, nn, 1);
- else
- freepair(t);
- }
- return 1;
-
- case OASADD:
- args = ADDargs;
- goto vasop;
- case OASAND:
- args = ANDargs;
- goto vasop;
- case OASOR:
- args = ORargs;
- goto vasop;
- case OASSUB:
- args = SUBargs;
- goto vasop;
- case OASXOR:
- args = XORargs;
- goto vasop;
-
- vasop:
- l = n->left;
- r = n->right;
- dr = nn != Z && nn->op == OREGPAIR;
- m = 0;
- if(l->complex > r->complex) {
- if(!vaddr(l, 1)) {
- reglcgen(&nod1, l, Z);
- l = &nod1;
- }
- if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
- if(dr)
- t = nn;
- else
- t = regpair(Z, r);
- sugen(r, t, 8);
- r = t;
- m = 1;
- }
- }
- else {
- if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
- if(dr)
- t = nn;
- else
- t = regpair(Z, r);
- sugen(r, t, 8);
- r = t;
- m = 1;
- }
- if(!vaddr(l, 1)) {
- reglcgen(&nod1, l, Z);
- l = &nod1;
- }
- }
- if(nn != Z) {
- if(n->op == OASSUB)
- biggen(l, r, Z, 0, sub10, args);
- else
- biggen(r, l, Z, 0, binoptmp, args);
- storepair(r, l, 0);
- }
- else {
- if(m)
- biggen(l, r, Z, 0, binop00, args);
- else
- biggen(l, r, Z, 0, binoptmp, args);
- }
- if(l == &nod1)
- regfree(&nod1);
- if(m) {
- if(nn == Z)
- freepair(r);
- else if(!dr)
- storepair(r, nn, 1);
- }
- return 1;
-
- case OASASHL:
- args = nil;
- optab = asshlltab;
- goto assh;
- case OASLSHR:
- args = shrlargs;
- optab = asshrltab;
- goto assh;
- case OASASHR:
- args = sarlargs;
- optab = asshrltab;
- goto assh;
-
- assh:
- c = Z;
- l = n->left;
- r = n->right;
- if(r->op == OCONST) {
- m = r->vconst & 63;
- if(m < 32)
- m = SAclo;
- else if(m == 32)
- m = SAc32;
- else
- m = SAchi;
- }
- else
- m = SAgen;
- if(l->complex > r->complex) {
- if(!vaddr(l, 0)) {
- reglcgen(&nod1, l, Z);
- l = &nod1;
- }
- if(m == SAgen) {
- t = &nod2;
- if(l->reg == D_CX) {
- regalloc(t, r, Z);
- gmove(l, t);
- l->reg = t->reg;
- t->reg = D_CX;
- }
- else
- c = snarfreg(nn, t, D_CX, r, &nod3);
- cgen(r, t);
- r = t;
- }
- }
- else {
- if(m == SAgen) {
- t = &nod2;
- c = snarfreg(nn, t, D_CX, r, &nod3);
- cgen(r, t);
- r = t;
- }
- if(!vaddr(l, 0)) {
- reglcgen(&nod1, l, Z);
- l = &nod1;
- }
- }
-
- if(nn != Z) {
- m += SAdgen - SAgen;
- d = regpair(nn, n);
- instpair(d, Z);
- biggen(l, r, d, 0, optab[m], args);
- if(l == &nod1) {
- regfree(&nod1);
- l = Z;
- }
- if(r == &nod2 && c == Z) {
- regfree(&nod2);
- r = Z;
- }
- if(d != nn)
- storepair(d, nn, 1);
- }
- else
- biggen(l, r, Z, 0, optab[m], args);
-
- if(c != Z) {
- gins(AMOVL, c, r);
- regfree(c);
- }
- if(l == &nod1)
- regfree(&nod1);
- if(r == &nod2)
- regfree(&nod2);
- return 1;
-
- case OPOSTINC:
- args = ADDargs;
- cp = incdecpost;
- goto vinc;
- case OPOSTDEC:
- args = SUBargs;
- cp = incdecpost;
- goto vinc;
- case OPREINC:
- args = ADDargs;
- cp = incdecpre;
- goto vinc;
- case OPREDEC:
- args = SUBargs;
- cp = incdecpre;
- goto vinc;
-
- vinc:
- l = n->left;
- if(!vaddr(l, 1)) {
- reglcgen(&nod1, l, Z);
- l = &nod1;
- }
-
- if(nn != Z) {
- d = regpair(nn, n);
- instpair(d, Z);
- biggen(l, Z, d, 0, cp, args);
- if(l == &nod1) {
- regfree(&nod1);
- l = Z;
- }
- if(d != nn)
- storepair(d, nn, 1);
- }
- else
- biggen(l, Z, Z, 0, incdec, args);
-
- if(l == &nod1)
- regfree(&nod1);
- return 1;
-
- case OCAST:
- l = n->left;
- if(typev[l->type->etype]) {
- if(!vaddr(l, 1)) {
- if(l->complex + 1 > nn->complex) {
- d = regpair(Z, l);
- sugen(l, d, 8);
- if(!vaddr(nn, 1)) {
- reglcgen(&nod1, nn, Z);
- r = &nod1;
- }
- else
- r = nn;
- }
- else {
- if(!vaddr(nn, 1)) {
- reglcgen(&nod1, nn, Z);
- r = &nod1;
- }
- else
- r = nn;
- d = regpair(Z, l);
- sugen(l, d, 8);
- }
-// d->left->type = r->type;
- d->left->type = types[TLONG];
- gmove(d->left, r);
- freepair(d);
- }
- else {
- if(nn->op != OREGISTER && !vaddr(nn, 1)) {
- reglcgen(&nod1, nn, Z);
- r = &nod1;
- }
- else
- r = nn;
-// l->type = r->type;
- l->type = types[TLONG];
- gmove(l, r);
- }
- if(r != nn)
- regfree(r);
- }
- else {
- if(typeu[l->type->etype] || cond(l->op))
- si = TUNSIGNED;
- else
- si = TSIGNED;
- regalloc(&nod1, l, Z);
- cgen(l, &nod1);
- if(nn->op == OREGPAIR) {
- m = instpair(nn, &nod1);
- biggen(&nod1, Z, nn, si == TSIGNED, castrp, nil);
- }
- else {
- m = 0;
- if(!vaddr(nn, si != TSIGNED)) {
- dt = nn->type;
- nn->type = types[TLONG];
- reglcgen(&nod2, nn, Z);
- nn->type = dt;
- nn = &nod2;
- }
- dt = nn->type;
- nn->type = types[TLONG];
- biggen(&nod1, Z, nn, si == TSIGNED, castrpa, nil);
- nn->type = dt;
- if(nn == &nod2)
- regfree(&nod2);
- }
- if(!m)
- regfree(&nod1);
- }
- return 1;
-
- default:
- if(n->op == OREGPAIR) {
- storepair(n, nn, 1);
- return 1;
- }
- if(nn->op == OREGPAIR) {
- loadpair(n, nn);
- return 1;
- }
- return 0;
- }
-finished:
- if(d != nn)
- storepair(d, nn, 1);
- return 1;
-}
-
-void
-testv(Node *n, int true)
-{
- Type *t;
- Node *nn, nod;
-
- switch(n->op) {
- case OINDREG:
- case ONAME:
- biggen(n, Z, Z, true, testi, nil);
- break;
-
- default:
- n = vfunc(n, n);
- if(n->addable >= INDEXED) {
- t = n->type;
- n->type = types[TLONG];
- reglcgen(&nod, n, Z);
- n->type = t;
- n = &nod;
- biggen(n, Z, Z, true, testi, nil);
- if(n == &nod)
- regfree(n);
- }
- else {
- nn = regpair(Z, n);
- sugen(n, nn, 8);
- biggen(nn, Z, Z, true, testi, nil);
- freepair(nn);
- }
- }
-}
diff --git a/src/cmd/8c/div.c b/src/cmd/8c/div.c
deleted file mode 100644
index 14945052e..000000000
--- a/src/cmd/8c/div.c
+++ /dev/null
@@ -1,236 +0,0 @@
-// Inferno utils/8c/div.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/div.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-/*
- * Based on: Granlund, T.; Montgomery, P.L.
- * "Division by Invariant Integers using Multiplication".
- * SIGPLAN Notices, Vol. 29, June 1994, page 61.
- */
-
-#define TN(n) ((uvlong)1 << (n))
-#define T31 TN(31)
-#define T32 TN(32)
-
-int
-multiplier(uint32 d, int p, uvlong *mp)
-{
- int l;
- uvlong mlo, mhi, tlo, thi;
-
- l = topbit(d - 1) + 1;
- mlo = (((TN(l) - d) << 32) / d) + T32;
- if(l + p == 64)
- mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
- else
- mhi = (TN(32 + l) + TN(32 + l - p)) / d;
- /*assert(mlo < mhi);*/
- while(l > 0) {
- tlo = mlo >> 1;
- thi = mhi >> 1;
- if(tlo == thi)
- break;
- mlo = tlo;
- mhi = thi;
- l--;
- }
- *mp = mhi;
- return l;
-}
-
-int
-sdiv(uint32 d, uint32 *mp, int *sp)
-{
- int s;
- uvlong m;
-
- s = multiplier(d, 32 - 1, &m);
- *mp = m;
- *sp = s;
- if(m >= T31)
- return 1;
- else
- return 0;
-}
-
-int
-udiv(uint32 d, uint32 *mp, int *sp, int *pp)
-{
- int p, s;
- uvlong m;
-
- s = multiplier(d, 32, &m);
- p = 0;
- if(m >= T32) {
- while((d & 1) == 0) {
- d >>= 1;
- p++;
- }
- s = multiplier(d, 32 - p, &m);
- }
- *mp = m;
- *pp = p;
- if(m >= T32) {
- /*assert(p == 0);*/
- *sp = s - 1;
- return 1;
- }
- else {
- *sp = s;
- return 0;
- }
-}
-
-void
-sdivgen(Node *l, Node *r, Node *ax, Node *dx)
-{
- int a, s;
- uint32 m;
- vlong c;
-
- c = r->vconst;
- if(c < 0)
- c = -c;
- a = sdiv(c, &m, &s);
-//print("a=%d i=%d s=%d m=%ux\n", a, (int32)r->vconst, s, m);
- gins(AMOVL, nodconst(m), ax);
- gins(AIMULL, l, Z);
- gins(AMOVL, l, ax);
- if(a)
- gins(AADDL, ax, dx);
- gins(ASHRL, nodconst(31), ax);
- gins(ASARL, nodconst(s), dx);
- gins(AADDL, ax, dx);
- if(r->vconst < 0)
- gins(ANEGL, Z, dx);
-}
-
-void
-udivgen(Node *l, Node *r, Node *ax, Node *dx)
-{
- int a, s, t;
- uint32 m;
- Node nod;
-
- a = udiv(r->vconst, &m, &s, &t);
-//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (int32)r->vconst, t, s, m);
- if(t != 0) {
- gins(AMOVL, l, ax);
- gins(ASHRL, nodconst(t), ax);
- gins(AMOVL, nodconst(m), dx);
- gins(AMULL, dx, Z);
- }
- else if(a) {
- if(l->op != OREGISTER) {
- regalloc(&nod, l, Z);
- gins(AMOVL, l, &nod);
- l = &nod;
- }
- gins(AMOVL, nodconst(m), ax);
- gins(AMULL, l, Z);
- gins(AADDL, l, dx);
- gins(ARCRL, nodconst(1), dx);
- if(l == &nod)
- regfree(l);
- }
- else {
- gins(AMOVL, nodconst(m), ax);
- gins(AMULL, l, Z);
- }
- if(s != 0)
- gins(ASHRL, nodconst(s), dx);
-}
-
-void
-sext(Node *d, Node *s, Node *l)
-{
- if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
- reg[D_DX]++;
- gins(ACDQ, Z, Z);
- }
- else {
- regalloc(d, l, Z);
- gins(AMOVL, s, d);
- gins(ASARL, nodconst(31), d);
- }
-}
-
-void
-sdiv2(int32 c, int v, Node *l, Node *n)
-{
- Node nod;
-
- if(v > 0) {
- if(v > 1) {
- sext(&nod, n, l);
- gins(AANDL, nodconst((1 << v) - 1), &nod);
- gins(AADDL, &nod, n);
- regfree(&nod);
- }
- else {
- gins(ACMPL, n, nodconst(0x80000000));
- gins(ASBBL, nodconst(-1), n);
- }
- gins(ASARL, nodconst(v), n);
- }
- if(c < 0)
- gins(ANEGL, Z, n);
-}
-
-void
-smod2(int32 c, int v, Node *l, Node *n)
-{
- Node nod;
-
- if(c == 1) {
- zeroregm(n);
- return;
- }
-
- sext(&nod, n, l);
- if(v == 0) {
- zeroregm(n);
- gins(AXORL, &nod, n);
- gins(ASUBL, &nod, n);
- }
- else if(v > 1) {
- gins(AANDL, nodconst((1 << v) - 1), &nod);
- gins(AADDL, &nod, n);
- gins(AANDL, nodconst((1 << v) - 1), n);
- gins(ASUBL, &nod, n);
- }
- else {
- gins(AANDL, nodconst(1), n);
- gins(AXORL, &nod, n);
- gins(ASUBL, &nod, n);
- }
- regfree(&nod);
-}
diff --git a/src/cmd/8c/doc.go b/src/cmd/8c/doc.go
deleted file mode 100644
index 0d07db14d..000000000
--- a/src/cmd/8c/doc.go
+++ /dev/null
@@ -1,16 +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.
-
-// +build ignore
-
-/*
-
-8c is a version of the Plan 9 C compiler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/8c
-
-Its target architecture is the x86, referred to by these tools for historical reasons as 386.
-
-*/
-package main
diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h
deleted file mode 100644
index aa3888d73..000000000
--- a/src/cmd/8c/gc.h
+++ /dev/null
@@ -1,364 +0,0 @@
-// Inferno utils/8c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/gc.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "../cc/cc.h"
-#include "../8l/8.out.h"
-
-/*
- * 8c/386
- * Intel 386
- */
-#define SZ_CHAR 1
-#define SZ_SHORT 2
-#define SZ_INT 4
-#define SZ_LONG 4
-#define SZ_IND 4
-#define SZ_FLOAT 4
-#define SZ_VLONG 8
-#define SZ_DOUBLE 8
-#define FNX 100
-
-typedef struct Case Case;
-typedef struct C1 C1;
-typedef struct Reg Reg;
-typedef struct Rgn Rgn;
-typedef struct Renv Renv;
-
-EXTERN struct
-{
- Node* regtree;
- Node* basetree;
- short scale;
- short reg;
- short ptr;
-} idx;
-
-#define A ((Addr*)0)
-
-#define INDEXED 9
-
-#define P ((Prog*)0)
-
-struct Case
-{
- Case* link;
- int32 val;
- int32 label;
- char def;
- char isv;
-};
-#define C ((Case*)0)
-
-struct C1
-{
- int32 val;
- int32 label;
-};
-
-struct Reg
-{
- int32 pc;
- int32 rpo; /* reverse post ordering */
-
- Bits set;
- Bits use1;
- Bits use2;
-
- Bits refbehind;
- Bits refahead;
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- int32 regu;
- int32 loop; /* could be shorter */
-
- Reg* log5;
- int32 active;
-
- Reg* p1;
- Reg* p2;
- Reg* p2link;
- Reg* s1;
- Reg* s2;
- Reg* link;
- Prog* prog;
-};
-#define R ((Reg*)0)
-
-struct Renv
-{
- int safe;
- Node base;
- Node* saved;
- Node* scope;
-};
-
-#define NRGN 600
-struct Rgn
-{
- Reg* enter;
- short cost;
- short varno;
- short regno;
-};
-
-EXTERN int32 breakpc;
-EXTERN int32 nbreak;
-EXTERN Case* cases;
-EXTERN Node constnode;
-EXTERN Node fconstnode;
-EXTERN int32 continpc;
-EXTERN int32 curarg;
-EXTERN int32 cursafe;
-EXTERN Prog* lastp;
-EXTERN int32 maxargsafe;
-EXTERN int mnstring;
-EXTERN Node* nodrat;
-EXTERN Node* nodret;
-EXTERN Node* nodsafe;
-EXTERN int32 nrathole;
-EXTERN int32 nstring;
-EXTERN Prog* p;
-EXTERN int32 pc;
-EXTERN Node regnode;
-EXTERN Node fregnode0;
-EXTERN Node fregnode1;
-EXTERN char string[NSNAME];
-EXTERN Sym* symrathole;
-EXTERN Node znode;
-EXTERN Prog zprog;
-EXTERN int reg[D_NONE];
-EXTERN int32 exregoffset;
-EXTERN int32 exfregoffset;
-
-#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
-#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
-#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
-#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
-
-#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
-
-#define CLOAD 5
-#define CREF 5
-#define CINF 1000
-#define LOOP 3
-
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-
-EXTERN int32 regbits;
-EXTERN int32 exregbits;
-
-EXTERN int change;
-EXTERN int suppress;
-
-EXTERN Reg* firstr;
-EXTERN Reg* lastr;
-EXTERN Reg zreg;
-EXTERN Reg* freer;
-EXTERN int32* idom;
-EXTERN Reg** rpo2r;
-EXTERN int32 maxnr;
-
-extern char* anames[];
-
-/*
- * sgen.c
- */
-void codgen(Node*, Node*);
-void gen(Node*);
-void noretval(int);
-void usedset(Node*, int);
-void xcom(Node*);
-void indx(Node*);
-int bcomplex(Node*, Node*);
-Prog* gtext(Sym*, int32);
-vlong argsize(int);
-
-/*
- * cgen.c
- */
-void zeroregm(Node*);
-void cgen(Node*, Node*);
-void reglcgen(Node*, Node*, Node*);
-void lcgen(Node*, Node*);
-void bcgen(Node*, int);
-void boolgen(Node*, int, Node*);
-void sugen(Node*, Node*, int32);
-int needreg(Node*, int);
-
-/*
- * cgen64.c
- */
-int vaddr(Node*, int);
-void loadpair(Node*, Node*);
-int cgen64(Node*, Node*);
-void testv(Node*, int);
-
-/*
- * txt.c
- */
-void ginit(void);
-void gclean(void);
-void nextpc(void);
-void gargs(Node*, Node*, Node*);
-void garg1(Node*, Node*, Node*, int, Node**);
-Node* nodconst(int32);
-Node* nodfconst(double);
-int nodreg(Node*, Node*, int);
-int isreg(Node*, int);
-void regret(Node*, Node*, Type*, int);
-void regalloc(Node*, Node*, Node*);
-void regfree(Node*);
-void regialloc(Node*, Node*, Node*);
-void regsalloc(Node*, Node*);
-void regaalloc1(Node*, Node*);
-void regaalloc(Node*, Node*);
-void regind(Node*, Node*);
-void gprep(Node*, Node*);
-void naddr(Node*, Addr*);
-void gmove(Node*, Node*);
-void gins(int a, Node*, Node*);
-void fgopcode(int, Node*, Node*, int, int);
-void gopcode(int, Type*, Node*, Node*);
-int samaddr(Node*, Node*);
-void gbranch(int);
-void patch(Prog*, int32);
-int sconst(Node*);
-void gpseudo(int, Sym*, Node*);
-void gprefetch(Node*);
-void gpcdata(int, int);
-
-/*
- * swt.c
- */
-int swcmp(const void*, const void*);
-void doswit(Node*);
-void swit1(C1*, int, int32, Node*);
-void swit2(C1*, int, int32, Node*);
-void newcase(void);
-void bitload(Node*, Node*, Node*, Node*, Node*);
-void bitstore(Node*, Node*, Node*, Node*, Node*);
-int32 outstring(char*, int32);
-void nullwarn(Node*, Node*);
-void sextern(Sym*, Node*, int32, int32);
-void gextern(Sym*, Node*, int32, int32);
-void outcode(void);
-
-/*
- * list
- */
-void listinit(void);
-
-/*
- * reg.c
- */
-Reg* rega(void);
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Addr*);
-void prop(Reg*, Bits, Bits);
-void loopit(Reg*, int32);
-void synch(Reg*, Bits);
-uint32 allreg(uint32, Rgn*);
-void paint1(Reg*, int);
-uint32 paint2(Reg*, int);
-void paint3(Reg*, int, int32, int);
-void addreg(Addr*, int);
-
-/*
- * peep.c
- */
-void peep(void);
-void excise(Reg*);
-Reg* uniqp(Reg*);
-Reg* uniqs(Reg*);
-int regtyp(Addr*);
-int anyvar(Addr*);
-int subprop(Reg*);
-int copyprop(Reg*);
-int copy1(Addr*, Addr*, Reg*, int);
-int copyu(Prog*, Addr*, Addr*);
-
-int copyas(Addr*, Addr*);
-int copyau(Addr*, Addr*);
-int copysub(Addr*, Addr*, Addr*, int);
-int copysub1(Prog*, Addr*, Addr*, int);
-
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
-
-#define D_HI D_NONE
-#define D_LO D_NONE
-
-/*
- * bound
- */
-void comtarg(void);
-
-/*
- * com64
- */
-int cond(int);
-int com64(Node*);
-void com64init(void);
-void bool64(Node*);
-int32 lo64v(Node*);
-int32 hi64v(Node*);
-Node* lo64(Node*);
-Node* hi64(Node*);
-
-/*
- * div/mul
- */
-void sdivgen(Node*, Node*, Node*, Node*);
-void udivgen(Node*, Node*, Node*, Node*);
-void sdiv2(int32, int, Node*, Node*);
-void smod2(int32, int, Node*, Node*);
-void mulgen(Type*, Node*, Node*);
-void genmuladd(Node*, Node*, int, Node*);
-void shiftit(Type*, Node*, Node*);
-
-/* wrecklessly steal a field */
-
-#define rplink label
diff --git a/src/cmd/8c/list.c b/src/cmd/8c/list.c
deleted file mode 100644
index 1730eccd0..000000000
--- a/src/cmd/8c/list.c
+++ /dev/null
@@ -1,38 +0,0 @@
-// Inferno utils/8c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/list.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#define EXTERN
-#include "gc.h"
-
-void
-listinit(void)
-{
- listinit8();
-}
diff --git a/src/cmd/8c/machcap.c b/src/cmd/8c/machcap.c
deleted file mode 100644
index 61e5aad16..000000000
--- a/src/cmd/8c/machcap.c
+++ /dev/null
@@ -1,116 +0,0 @@
-// Inferno utils/8c/machcap.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/machcap.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-int
-machcap(Node *n)
-{
-
- if(n == Z)
- return 1; /* test */
-
- switch(n->op) {
- case OMUL:
- case OLMUL:
- case OASMUL:
- case OASLMUL:
- if(typechl[n->type->etype])
- return 1;
- if(typev[n->type->etype]) {
- return 1;
- }
- break;
-
- case OCOM:
- case ONEG:
- case OADD:
- case OAND:
- case OOR:
- case OSUB:
- case OXOR:
- case OASHL:
- case OLSHR:
- case OASHR:
- if(typechlv[n->left->type->etype])
- return 1;
- break;
-
- case OCAST:
- if(typev[n->type->etype]) {
- if(typechlp[n->left->type->etype])
- return 1;
- }
- else if(!typefd[n->type->etype]) {
- if(typev[n->left->type->etype])
- return 1;
- }
- break;
-
- case OCOND:
- case OCOMMA:
- case OLIST:
- case OANDAND:
- case OOROR:
- case ONOT:
- return 1;
-
- case OASADD:
- case OASSUB:
- case OASAND:
- case OASOR:
- case OASXOR:
- return 1;
-
- case OASASHL:
- case OASASHR:
- case OASLSHR:
- return 1;
-
- case OPOSTINC:
- case OPOSTDEC:
- case OPREINC:
- case OPREDEC:
- return 1;
-
- case OEQ:
- case ONE:
- case OLE:
- case OGT:
- case OLT:
- case OGE:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- return 1;
- }
- return 0;
-}
diff --git a/src/cmd/8c/mul.c b/src/cmd/8c/mul.c
deleted file mode 100644
index 9955e762f..000000000
--- a/src/cmd/8c/mul.c
+++ /dev/null
@@ -1,458 +0,0 @@
-// Inferno utils/8c/mul.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/mul.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-typedef struct Malg Malg;
-typedef struct Mparam Mparam;
-
-struct Malg
-{
- schar vals[10];
-};
-
-struct Mparam
-{
- uint32 value;
- schar alg;
- char neg;
- char shift;
- char arg;
- schar off;
-};
-
-static Mparam multab[32];
-static int mulptr;
-
-static Malg malgs[] =
-{
- {0, 100},
- {-1, 1, 100},
- {-9, -5, -3, 3, 5, 9, 100},
- {6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
- {-8, -4, -2, 2, 4, 8, 100},
-};
-
-/*
- * return position of lowest 1
- */
-int
-lowbit(uint32 v)
-{
- int s, i;
- uint32 m;
-
- s = 0;
- m = 0xFFFFFFFFUL;
- for(i = 16; i > 0; i >>= 1) {
- m >>= i;
- if((v & m) == 0) {
- v >>= i;
- s += i;
- }
- }
- return s;
-}
-
-void
-genmuladd(Node *d, Node *s, int m, Node *a)
-{
- Node nod;
-
- nod.op = OINDEX;
- nod.left = a;
- nod.right = s;
- nod.scale = m;
- nod.type = types[TIND];
- nod.xoffset = 0;
- xcom(&nod);
- gopcode(OADDR, d->type, &nod, d);
-}
-
-void
-mulparam(uint32 m, Mparam *mp)
-{
- int c, i, j, n, o, q, s;
- int bc, bi, bn, bo, bq, bs, bt;
- schar *p;
- int32 u;
- uint32 t;
-
- bc = bq = 10;
- bi = bn = bo = bs = bt = 0;
- for(i = 0; i < nelem(malgs); i++) {
- for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
- for(s = 0; s < 2; s++) {
- c = 10;
- q = 10;
- u = m - o;
- if(u == 0)
- continue;
- if(s) {
- o = -o;
- if(o > 0)
- continue;
- u = -u;
- }
- n = lowbit(u);
- t = (uint32)u >> n;
- switch(i) {
- case 0:
- if(t == 1) {
- c = s + 1;
- q = 0;
- break;
- }
- switch(t) {
- case 3:
- case 5:
- case 9:
- c = s + 1;
- if(n)
- c++;
- q = 0;
- break;
- }
- if(s)
- break;
- switch(t) {
- case 15:
- case 25:
- case 27:
- case 45:
- case 81:
- c = 2;
- if(n)
- c++;
- q = 1;
- break;
- }
- break;
- case 1:
- if(t == 1) {
- c = 3;
- q = 3;
- break;
- }
- switch(t) {
- case 3:
- case 5:
- case 9:
- c = 3;
- q = 2;
- break;
- }
- break;
- case 2:
- if(t == 1) {
- c = 3;
- q = 2;
- break;
- }
- break;
- case 3:
- if(s)
- break;
- if(t == 1) {
- c = 3;
- q = 1;
- break;
- }
- break;
- case 4:
- if(t == 1) {
- c = 3;
- q = 0;
- break;
- }
- break;
- }
- if(c < bc || (c == bc && q > bq)) {
- bc = c;
- bi = i;
- bn = n;
- bo = o;
- bq = q;
- bs = s;
- bt = t;
- }
- }
- }
- mp->value = m;
- if(bc <= 3) {
- mp->alg = bi;
- mp->shift = bn;
- mp->off = bo;
- mp->neg = bs;
- mp->arg = bt;
- }
- else
- mp->alg = -1;
-}
-
-int
-m0(int a)
-{
- switch(a) {
- case -2:
- case 2:
- return 2;
- case -3:
- case 3:
- return 2;
- case -4:
- case 4:
- return 4;
- case -5:
- case 5:
- return 4;
- case 6:
- return 2;
- case -8:
- case 8:
- return 8;
- case -9:
- case 9:
- return 8;
- case 10:
- return 4;
- case 12:
- return 2;
- case 15:
- return 2;
- case 18:
- return 8;
- case 20:
- return 4;
- case 24:
- return 2;
- case 25:
- return 4;
- case 27:
- return 2;
- case 36:
- return 8;
- case 40:
- return 4;
- case 45:
- return 4;
- case 72:
- return 8;
- case 81:
- return 8;
- }
- diag(Z, "bad m0");
- return 0;
-}
-
-int
-m1(int a)
-{
- switch(a) {
- case 15:
- return 4;
- case 25:
- return 4;
- case 27:
- return 8;
- case 45:
- return 8;
- case 81:
- return 8;
- }
- diag(Z, "bad m1");
- return 0;
-}
-
-int
-m2(int a)
-{
- switch(a) {
- case 6:
- return 2;
- case 10:
- return 2;
- case 12:
- return 4;
- case 18:
- return 2;
- case 20:
- return 4;
- case 24:
- return 8;
- case 36:
- return 4;
- case 40:
- return 8;
- case 72:
- return 8;
- }
- diag(Z, "bad m2");
- return 0;
-}
-
-void
-shiftit(Type *t, Node *s, Node *d)
-{
- int32 c;
-
- c = (int32)s->vconst & 31;
- switch(c) {
- case 0:
- break;
- case 1:
- gopcode(OADD, t, d, d);
- break;
- default:
- gopcode(OASHL, t, s, d);
- }
-}
-
-static int
-mulgen1(uint32 v, Node *n)
-{
- int i, o;
- Mparam *p;
- Node nod, nods;
-
- for(i = 0; i < nelem(multab); i++) {
- p = &multab[i];
- if(p->value == v)
- goto found;
- }
-
- p = &multab[mulptr];
- if(++mulptr == nelem(multab))
- mulptr = 0;
-
- mulparam(v, p);
-
-found:
-// print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
- if(p->alg < 0)
- return 0;
-
- nods = *nodconst(p->shift);
-
- o = OADD;
- if(p->alg > 0) {
- regalloc(&nod, n, Z);
- if(p->off < 0)
- o = OSUB;
- }
-
- switch(p->alg) {
- case 0:
- switch(p->arg) {
- case 1:
- shiftit(n->type, &nods, n);
- break;
- case 15:
- case 25:
- case 27:
- case 45:
- case 81:
- genmuladd(n, n, m1(p->arg), n);
- /* fall thru */
- case 3:
- case 5:
- case 9:
- genmuladd(n, n, m0(p->arg), n);
- shiftit(n->type, &nods, n);
- break;
- default:
- goto bad;
- }
- if(p->neg == 1)
- gins(ANEGL, Z, n);
- break;
- case 1:
- switch(p->arg) {
- case 1:
- gmove(n, &nod);
- shiftit(n->type, &nods, &nod);
- break;
- case 3:
- case 5:
- case 9:
- genmuladd(&nod, n, m0(p->arg), n);
- shiftit(n->type, &nods, &nod);
- break;
- default:
- goto bad;
- }
- if(p->neg)
- gopcode(o, n->type, &nod, n);
- else {
- gopcode(o, n->type, n, &nod);
- gmove(&nod, n);
- }
- break;
- case 2:
- genmuladd(&nod, n, m0(p->off), n);
- shiftit(n->type, &nods, n);
- goto comop;
- case 3:
- genmuladd(&nod, n, m0(p->off), n);
- shiftit(n->type, &nods, n);
- genmuladd(n, &nod, m2(p->off), n);
- break;
- case 4:
- genmuladd(&nod, n, m0(p->off), nodconst(0));
- shiftit(n->type, &nods, n);
- goto comop;
- default:
- diag(Z, "bad mul alg");
- break;
- comop:
- if(p->neg) {
- gopcode(o, n->type, n, &nod);
- gmove(&nod, n);
- }
- else
- gopcode(o, n->type, &nod, n);
- }
-
- if(p->alg > 0)
- regfree(&nod);
-
- return 1;
-
-bad:
- diag(Z, "mulgen botch");
- return 1;
-}
-
-void
-mulgen(Type *t, Node *r, Node *n)
-{
- if(!mulgen1(r->vconst, n))
- gopcode(OMUL, t, r, n);
-}
diff --git a/src/cmd/8c/peep.c b/src/cmd/8c/peep.c
deleted file mode 100644
index 4f58fc05c..000000000
--- a/src/cmd/8c/peep.c
+++ /dev/null
@@ -1,807 +0,0 @@
-// Inferno utils/8c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/peep.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-static int
-needc(Prog *p)
-{
- while(p != P) {
- switch(p->as) {
- case AADCL:
- case ASBBL:
- case ARCRL:
- return 1;
- case AADDL:
- case ASUBL:
- case AJMP:
- case ARET:
- case ACALL:
- return 0;
- default:
- if(p->to.type == D_BRANCH)
- return 0;
- }
- p = p->link;
- }
- return 0;
-}
-
-void
-peep(void)
-{
- Reg *r, *r1, *r2;
- Prog *p, *p1;
- int t;
-
- /*
- * complete R structure
- */
- t = 0;
- for(r=firstr; r!=R; r=r1) {
- r1 = r->link;
- if(r1 == R)
- break;
- p = r->prog->link;
- while(p != r1->prog)
- switch(p->as) {
- default:
- r2 = rega();
- r->link = r2;
- r2->link = r1;
-
- r2->prog = p;
- r2->p1 = r;
- r->s1 = r2;
- r2->s1 = r1;
- r1->p1 = r2;
-
- r = r2;
- t++;
-
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- p = p->link;
- }
- }
-
- pc = 0; /* speculating it won't kill */
-
-loop1:
-
- t = 0;
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AMOVL:
- if(regtyp(&p->to))
- if(regtyp(&p->from)) {
- if(copyprop(r)) {
- excise(r);
- t++;
- }
- if(subprop(r) && copyprop(r)) {
- excise(r);
- t++;
- }
- }
- break;
-
- case AMOVBLSX:
- case AMOVBLZX:
- case AMOVWLSX:
- case AMOVWLZX:
- if(regtyp(&p->to)) {
- r1 = uniqs(r);
- if(r1 != R) {
- p1 = r1->prog;
- if(p->as == p1->as && p->to.type == p1->from.type)
- p1->as = AMOVL;
- }
- }
- break;
- case AADDL:
- case AADDW:
- if(p->from.type != D_CONST || needc(p->link))
- break;
- if(p->from.offset == -1){
- if(p->as == AADDL)
- p->as = ADECL;
- else
- p->as = ADECW;
- p->from = zprog.from;
- }
- else if(p->from.offset == 1){
- if(p->as == AADDL)
- p->as = AINCL;
- else
- p->as = AINCW;
- p->from = zprog.from;
- }
- break;
- case ASUBL:
- case ASUBW:
- if(p->from.type != D_CONST || needc(p->link))
- break;
- if(p->from.offset == -1) {
- if(p->as == ASUBL)
- p->as = AINCL;
- else
- p->as = AINCW;
- p->from = zprog.from;
- }
- else if(p->from.offset == 1){
- if(p->as == ASUBL)
- p->as = ADECL;
- else
- p->as = ADECW;
- p->from = zprog.from;
- }
- break;
- }
- }
- if(t)
- goto loop1;
-}
-
-void
-excise(Reg *r)
-{
- Prog *p;
-
- p = r->prog;
- p->as = ANOP;
- p->from = zprog.from;
- p->to = zprog.to;
-}
-
-Reg*
-uniqp(Reg *r)
-{
- Reg *r1;
-
- r1 = r->p1;
- if(r1 == R) {
- r1 = r->p2;
- if(r1 == R || r1->p2link != R)
- return R;
- } else
- if(r->p2 != R)
- return R;
- return r1;
-}
-
-Reg*
-uniqs(Reg *r)
-{
- Reg *r1;
-
- r1 = r->s1;
- if(r1 == R) {
- r1 = r->s2;
- if(r1 == R)
- return R;
- } else
- if(r->s2 != R)
- return R;
- return r1;
-}
-
-int
-regtyp(Addr *a)
-{
- int t;
-
- t = a->type;
- if(t >= D_AX && t <= D_DI)
- return 1;
- return 0;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-int
-subprop(Reg *r0)
-{
- Prog *p;
- Addr *v1, *v2;
- Reg *r;
- int t;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case ACALL:
- return 0;
-
- case AIMULL:
- case AIMULW:
- if(p->to.type != D_NONE)
- break;
-
- case ADIVB:
- case ADIVL:
- case ADIVW:
- case AIDIVB:
- case AIDIVL:
- case AIDIVW:
- case AIMULB:
- case AMULB:
- case AMULL:
- case AMULW:
-
- case AROLB:
- case AROLL:
- case AROLW:
- case ARORB:
- case ARORL:
- case ARORW:
- case ASALB:
- case ASALL:
- case ASALW:
- case ASARB:
- case ASARL:
- case ASARW:
- case ASHLB:
- case ASHLL:
- case ASHLW:
- case ASHRB:
- case ASHRL:
- case ASHRW:
-
- case AREP:
- case AREPN:
-
- case ACWD:
- case ACDQ:
-
- case ASTOSB:
- case ASTOSL:
- case AMOVSB:
- case AMOVSL:
- case AFSTSW:
- return 0;
-
- case AMOVL:
- if(p->to.type == v1->type)
- goto gotit;
- break;
- }
- if(copyau(&p->from, v2) ||
- copyau(&p->to, v2))
- break;
- if(copysub(&p->from, v1, v2, 0) ||
- copysub(&p->to, v1, v2, 0))
- break;
- }
- return 0;
-
-gotit:
- copysub(&p->to, v1, v2, 1);
- if(debug['P']) {
- print("gotit: %D->%D\n%P", v1, v2, r->prog);
- if(p->from.type == v2->type)
- print(" excise");
- print("\n");
- }
- for(r=uniqs(r); r!=r0; r=uniqs(r)) {
- p = r->prog;
- copysub(&p->from, v1, v2, 1);
- copysub(&p->to, v1, v2, 1);
- if(debug['P'])
- print("%P\n", r->prog);
- }
- t = v1->type;
- v1->type = v2->type;
- v2->type = t;
- if(debug['P'])
- print("%P last\n", r->prog);
- return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
-int
-copyprop(Reg *r0)
-{
- Prog *p;
- Addr *v1, *v2;
- Reg *r;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Addr *v1, Addr *v2, Reg *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, A);
- switch(t) {
- case 2: /* rar, can't split */
- if(debug['P'])
- print("; %D rar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %D set; return 1\n", v2);
- return 1;
-
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %D used+set and f=%d; return 0\n", v2, f);
- else
- print("; %D used and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub %D/%D", v2, v1);
- if(t == 4) {
- if(debug['P'])
- print("; %D used+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, A);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %D set and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-int
-copyu(Prog *p, Addr *v, Addr *s)
-{
-
- switch(p->as) {
-
- default:
- if(debug['P'])
- print("unknown op %A\n", p->as);
- return 2;
-
- case ANEGB:
- case ANEGW:
- case ANEGL:
- case ANOTB:
- case ANOTW:
- case ANOTL:
- if(copyas(&p->to, v))
- return 2;
- break;
-
- case ALEAL: /* lhs addr, rhs store */
- if(copyas(&p->from, v))
- return 2;
-
-
- case ANOP: /* rhs store */
- case AMOVL:
- case AMOVBLSX:
- case AMOVBLZX:
- case AMOVWLSX:
- case AMOVWLZX:
- if(copyas(&p->to, v)) {
- if(s != A)
- return copysub(&p->from, v, s, 1);
- if(copyau(&p->from, v))
- return 4;
- return 3;
- }
- goto caseread;
-
- case AROLB:
- case AROLL:
- case AROLW:
- case ARORB:
- case ARORL:
- case ARORW:
- case ASALB:
- case ASALL:
- case ASALW:
- case ASARB:
- case ASARL:
- case ASARW:
- case ASHLB:
- case ASHLL:
- case ASHLW:
- case ASHRB:
- case ASHRL:
- case ASHRW:
- if(copyas(&p->to, v))
- return 2;
- if(copyas(&p->from, v))
- if(p->from.type == D_CX)
- return 2;
- goto caseread;
-
- case AADDB: /* rhs rar */
- case AADDL:
- case AADDW:
- case AANDB:
- case AANDL:
- case AANDW:
- case ADECL:
- case ADECW:
- case AINCL:
- case AINCW:
- case ASUBB:
- case ASUBL:
- case ASUBW:
- case AORB:
- case AORL:
- case AORW:
- case AXORB:
- case AXORL:
- case AXORW:
- case AMOVB:
- case AMOVW:
-
- case AFMOVB:
- case AFMOVBP:
- case AFMOVD:
- case AFMOVDP:
- case AFMOVF:
- case AFMOVFP:
- case AFMOVL:
- case AFMOVLP:
- case AFMOVV:
- case AFMOVVP:
- case AFMOVW:
- case AFMOVWP:
- case AFMOVX:
- case AFMOVXP:
- case AFADDDP:
- case AFADDW:
- case AFADDL:
- case AFADDF:
- case AFADDD:
- case AFMULDP:
- case AFMULW:
- case AFMULL:
- case AFMULF:
- case AFMULD:
- case AFSUBDP:
- case AFSUBW:
- case AFSUBL:
- case AFSUBF:
- case AFSUBD:
- case AFSUBRDP:
- case AFSUBRW:
- case AFSUBRL:
- case AFSUBRF:
- case AFSUBRD:
- case AFDIVDP:
- case AFDIVW:
- case AFDIVL:
- case AFDIVF:
- case AFDIVD:
- case AFDIVRDP:
- case AFDIVRW:
- case AFDIVRL:
- case AFDIVRF:
- case AFDIVRD:
- if(copyas(&p->to, v))
- return 2;
- goto caseread;
-
- case ACMPL: /* read only */
- case ACMPW:
- case ACMPB:
-
- case APREFETCHT0:
- case APREFETCHT1:
- case APREFETCHT2:
- case APREFETCHNTA:
-
-
- case AFCOMB:
- case AFCOMBP:
- case AFCOMD:
- case AFCOMDP:
- case AFCOMDPP:
- case AFCOMF:
- case AFCOMFP:
- case AFCOML:
- case AFCOMLP:
- case AFCOMW:
- case AFCOMWP:
- case AFUCOM:
- case AFUCOMP:
- case AFUCOMPP:
- caseread:
- if(s != A) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return copysub(&p->to, v, s, 1);
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- break;
-
- case AJGE: /* no reference */
- case AJNE:
- case AJLE:
- case AJEQ:
- case AJHI:
- case AJLS:
- case AJMI:
- case AJPL:
- case AJGT:
- case AJLT:
- case AJCC:
- case AJCS:
-
- case AADJSP:
- case AFLDZ:
- case AWAIT:
- break;
-
- case AIMULL:
- case AIMULW:
- if(p->to.type != D_NONE) {
- if(copyas(&p->to, v))
- return 2;
- goto caseread;
- }
-
- case ADIVB:
- case ADIVL:
- case ADIVW:
- case AIDIVB:
- case AIDIVL:
- case AIDIVW:
- case AIMULB:
- case AMULB:
- case AMULL:
- case AMULW:
-
- case ACWD:
- case ACDQ:
- if(v->type == D_AX || v->type == D_DX)
- return 2;
- goto caseread;
-
- case AREP:
- case AREPN:
- if(v->type == D_CX)
- return 2;
- goto caseread;
-
- case AMOVSB:
- case AMOVSL:
- if(v->type == D_DI || v->type == D_SI)
- return 2;
- goto caseread;
-
- case ASTOSB:
- case ASTOSL:
- if(v->type == D_AX || v->type == D_DI)
- return 2;
- goto caseread;
-
- case AFSTSW:
- if(v->type == D_AX)
- return 2;
- goto caseread;
-
- case AJMP: /* funny */
- if(s != A) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ARET: /* funny */
- if(v->type == REGRET)
- return 2;
- if(s != A)
- return 1;
- return 3;
-
- case ACALL: /* funny */
- if(REGARG >= 0 && v->type == (uchar)REGARG)
- return 2;
-
- if(s != A) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 4;
- return 3;
- }
- return 0;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-int
-copyas(Addr *a, Addr *v)
-{
- if(a->type != v->type)
- return 0;
- if(regtyp(v))
- return 1;
- if(v->type == D_AUTO || v->type == D_PARAM)
- if(v->offset == a->offset)
- return 1;
- return 0;
-}
-
-/*
- * either direct or indirect
- */
-int
-copyau(Addr *a, Addr *v)
-{
-
- if(copyas(a, v))
- return 1;
- if(regtyp(v)) {
- if(a->type-D_INDIR == v->type)
- return 1;
- if(a->index == v->type)
- return 1;
- }
- return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-int
-copysub(Addr *a, Addr *v, Addr *s, int f)
-{
- int t;
-
- if(copyas(a, v)) {
- t = s->type;
- if(t >= D_AX && t <= D_DI) {
- if(f)
- a->type = t;
- }
- return 0;
- }
- if(regtyp(v)) {
- t = v->type;
- if(a->type == t+D_INDIR) {
- if(s->type == D_BP && a->index != D_NONE)
- return 1; /* can't use BP-base with index */
- if(f)
- a->type = s->type+D_INDIR;
-// return 0;
- }
- if(a->index == t) {
- if(f)
- a->index = s->type;
- return 0;
- }
- return 0;
- }
- return 0;
-}
diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c
deleted file mode 100644
index ea862f388..000000000
--- a/src/cmd/8c/reg.c
+++ /dev/null
@@ -1,1438 +0,0 @@
-// Inferno utils/8c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-static void fixjmp(Reg*);
-
-Reg*
-rega(void)
-{
- Reg *r;
-
- r = freer;
- if(r == R) {
- r = alloc(sizeof(*r));
- } else
- freer = r->link;
-
- *r = zreg;
- return r;
-}
-
-int
-rcmp(const void *a1, const void *a2)
-{
- Rgn *p1, *p2;
- int c1, c2;
-
- p1 = (Rgn*)a1;
- p2 = (Rgn*)a2;
- c1 = p2->cost;
- c2 = p1->cost;
- if(c1 -= c2)
- return c1;
- return p2->varno - p1->varno;
-}
-
-void
-regopt(Prog *p)
-{
- Reg *r, *r1, *r2;
- Prog *p1;
- int i, z;
- int32 initpc, val, npc;
- uint32 vreg;
- Bits bit;
- struct
- {
- int32 m;
- int32 c;
- Reg* p;
- } log5[6], *lp;
-
- firstr = R;
- lastr = R;
- nvar = 0;
- regbits = RtoB(D_SP) | RtoB(D_AX);
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- }
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- val = 5L * 5L * 5L * 5L * 5L;
- lp = log5;
- for(i=0; i<5; i++) {
- lp->m = val;
- lp->c = 0;
- lp->p = R;
- val /= 5L;
- lp++;
- }
- val = 0;
- for(; p != P; p = p->link) {
- switch(p->as) {
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- case AFUNCDATA:
- continue;
- }
- r = rega();
- if(firstr == R) {
- firstr = r;
- lastr = r;
- } else {
- lastr->link = r;
- r->p1 = lastr;
- lastr->s1 = r;
- lastr = r;
- }
- r->prog = p;
- r->pc = val;
- val++;
-
- lp = log5;
- for(i=0; i<5; i++) {
- lp->c--;
- if(lp->c <= 0) {
- lp->c = lp->m;
- if(lp->p != R)
- lp->p->log5 = r;
- lp->p = r;
- (lp+1)->c = 0;
- break;
- }
- lp++;
- }
-
- r1 = r->p1;
- if(r1 != R)
- switch(r1->prog->as) {
- case ARET:
- case AJMP:
- case AIRETL:
- r->p1 = R;
- r1->s1 = R;
- }
- bit = mkvar(r, &p->from);
- if(bany(&bit))
- switch(p->as) {
- /*
- * funny
- */
- case ALEAL:
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- break;
-
- /*
- * left side read
- */
- default:
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
- break;
- }
-
- bit = mkvar(r, &p->to);
- if(bany(&bit))
- switch(p->as) {
- default:
- diag(Z, "reg: unknown op: %A", p->as);
- break;
-
- /*
- * right side read
- */
- case ACMPB:
- case ACMPL:
- case ACMPW:
- case APREFETCHT0:
- case APREFETCHT1:
- case APREFETCHT2:
- case APREFETCHNTA:
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- break;
-
- /*
- * right side write
- */
- case ANOP:
- case AMOVL:
- case AMOVB:
- case AMOVW:
- case AMOVBLSX:
- case AMOVBLZX:
- case AMOVWLSX:
- case AMOVWLZX:
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- break;
-
- /*
- * right side read+write
- */
- case AADDB:
- case AADDL:
- case AADDW:
- case AANDB:
- case AANDL:
- case AANDW:
- case ASUBB:
- case ASUBL:
- case ASUBW:
- case AORB:
- case AORL:
- case AORW:
- case AXORB:
- case AXORL:
- case AXORW:
- case ASALB:
- case ASALL:
- case ASALW:
- case ASARB:
- case ASARL:
- case ASARW:
- case AROLB:
- case AROLL:
- case AROLW:
- case ARORB:
- case ARORL:
- case ARORW:
- case ASHLB:
- case ASHLL:
- case ASHLW:
- case ASHRB:
- case ASHRL:
- case ASHRW:
- case AIMULL:
- case AIMULW:
- case ANEGL:
- case ANOTL:
- case AADCL:
- case ASBBL:
- for(z=0; z<BITS; z++) {
- r->set.b[z] |= bit.b[z];
- r->use2.b[z] |= bit.b[z];
- }
- break;
-
- /*
- * funny
- */
- case AFMOVDP:
- case AFMOVFP:
- case AFMOVLP:
- case AFMOVVP:
- case AFMOVWP:
- case ACALL:
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- break;
- }
-
- switch(p->as) {
- case AIMULL:
- case AIMULW:
- if(p->to.type != D_NONE)
- break;
-
- case AIDIVB:
- case AIDIVL:
- case AIDIVW:
- case AIMULB:
- case ADIVB:
- case ADIVL:
- case ADIVW:
- case AMULB:
- case AMULL:
- case AMULW:
-
- case ACWD:
- case ACDQ:
- r->regu |= RtoB(D_AX) | RtoB(D_DX);
- break;
-
- case AREP:
- case AREPN:
- case ALOOP:
- case ALOOPEQ:
- case ALOOPNE:
- r->regu |= RtoB(D_CX);
- break;
-
- case AMOVSB:
- case AMOVSL:
- case AMOVSW:
- case ACMPSB:
- case ACMPSL:
- case ACMPSW:
- r->regu |= RtoB(D_SI) | RtoB(D_DI);
- break;
-
- case ASTOSB:
- case ASTOSL:
- case ASTOSW:
- case ASCASB:
- case ASCASL:
- case ASCASW:
- r->regu |= RtoB(D_AX) | RtoB(D_DI);
- break;
-
- case AINSB:
- case AINSL:
- case AINSW:
- case AOUTSB:
- case AOUTSL:
- case AOUTSW:
- r->regu |= RtoB(D_DI) | RtoB(D_DX);
- break;
-
- case AFSTSW:
- case ASAHF:
- r->regu |= RtoB(D_AX);
- break;
- }
- }
- if(firstr == R)
- return;
- initpc = pc - val;
- npc = val;
-
- /*
- * pass 2
- * turn branch references to pointers
- * build back pointers
- */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH) {
- val = p->to.offset - initpc;
- r1 = firstr;
- while(r1 != R) {
- r2 = r1->log5;
- if(r2 != R && val >= r2->pc) {
- r1 = r2;
- continue;
- }
- if(r1->pc == val)
- break;
- r1 = r1->link;
- }
- if(r1 == R) {
- nearln = p->lineno;
- diag(Z, "ref not found\n%P", p);
- continue;
- }
- if(r1 == r) {
- nearln = p->lineno;
- diag(Z, "ref to self\n%P", p);
- continue;
- }
- r->s2 = r1;
- r->p2link = r1->p2;
- r1->p2 = r;
- }
- }
- if(debug['R']) {
- p = firstr->prog;
- print("\n%L %D\n", p->lineno, &p->from);
- }
-
- /*
- * pass 2.1
- * fix jumps
- */
- fixjmp(firstr);
-
- /*
- * pass 2.5
- * find looping structure
- */
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- change = 0;
- loopit(firstr, npc);
- if(debug['R'] && debug['v']) {
- print("\nlooping structure:\n");
- for(r = firstr; r != R; r = r->link) {
- print("%d:%P", r->loop, r->prog);
- for(z=0; z<BITS; z++)
- bit.b[z] = r->use1.b[z] |
- r->use2.b[z] |
- r->set.b[z];
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->use1))
- print(" u1=%B", r->use1);
- if(bany(&r->use2))
- print(" u2=%B", r->use2);
- if(bany(&r->set))
- print(" st=%B", r->set);
- }
- print("\n");
- }
- }
-
- /*
- * pass 3
- * iterate propagating usage
- * back until flow graph is complete
- */
-loop1:
- change = 0;
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- for(r = firstr; r != R; r = r->link)
- if(r->prog->as == ARET)
- prop(r, zbits, zbits);
-loop11:
- /* pick up unreachable code */
- i = 0;
- for(r = firstr; r != R; r = r1) {
- r1 = r->link;
- if(r1 && r1->active && !r->active) {
- prop(r, zbits, zbits);
- i = 1;
- }
- }
- if(i)
- goto loop11;
- if(change)
- goto loop1;
-
-
- /*
- * pass 4
- * iterate propagating register/variable synchrony
- * forward until graph is complete
- */
-loop2:
- change = 0;
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- synch(firstr, zbits);
- if(change)
- goto loop2;
-
-
- /*
- * pass 5
- * isolate regions
- * calculate costs (paint1)
- */
- r = firstr;
- if(r) {
- for(z=0; z<BITS; z++)
- bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
- ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
- if(bany(&bit)) {
- nearln = r->prog->lineno;
- warn(Z, "used and not set: %B", bit);
- if(debug['R'] && !debug['w'])
- print("used and not set: %B\n", bit);
- }
- }
- if(debug['R'] && debug['v'])
- print("\nprop structure:\n");
- for(r = firstr; r != R; r = r->link)
- r->act = zbits;
- rgp = region;
- nregion = 0;
- for(r = firstr; r != R; r = r->link) {
- if(debug['R'] && debug['v']) {
- print("%P\t", r->prog);
- if(bany(&r->set))
- print("s:%B ", r->set);
- if(bany(&r->refahead))
- print("ra:%B ", r->refahead);
- if(bany(&r->calahead))
- print("ca:%B ", r->calahead);
- print("\n");
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = r->set.b[z] &
- ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
- if(bany(&bit)) {
- nearln = r->prog->lineno;
- warn(Z, "set and not used: %B", bit);
- if(debug['R'])
- print("set and not used: %B\n", bit);
- excise(r);
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- rgp->enter = r;
- rgp->varno = i;
- change = 0;
- if(debug['R'] && debug['v'])
- print("\n");
- paint1(r, i);
- bit.b[i/32] &= ~(1L<<(i%32));
- if(change <= 0) {
- if(debug['R'])
- print("%L$%d: %B\n",
- r->prog->lineno, change, blsh(i));
- continue;
- }
- rgp->cost = change;
- nregion++;
- if(nregion >= NRGN) {
- fatal(Z, "too many regions");
- goto brk;
- }
- rgp++;
- }
- }
-brk:
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- for(i=0; i<nregion; i++) {
- bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
- vreg = allreg(vreg, rgp);
- if(debug['R']) {
- print("%L$%d %R: %B\n",
- rgp->enter->prog->lineno,
- rgp->cost,
- rgp->regno,
- bit);
- }
- if(rgp->regno != 0)
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- rgp++;
- }
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P'])
- peep();
-
- if(debug['R'] && debug['v']) {
- print("after pass 7 (peep)\n");
- for(r=firstr; r; r=r->link)
- print("%04d %P\n", (int)r->pc, r->prog);
- print("\n");
- }
-
- /*
- * pass 8
- * recalculate pc
- */
- val = initpc;
- for(r = firstr; r != R; r = r1) {
- r->pc = val;
- p = r->prog;
- p1 = P;
- r1 = r->link;
- if(r1 != R)
- p1 = r1->prog;
- for(; p != p1; p = p->link) {
- switch(p->as) {
- default:
- val++;
- break;
-
- case ANOP:
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- case AFUNCDATA:
- break;
- }
- }
- }
- pc = val;
-
- /*
- * fix up branches
- */
- if(debug['R'])
- if(bany(&addrs))
- print("addrs: %B\n", addrs);
-
- r1 = 0; /* set */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH) {
- p->to.offset = r->s2->pc;
- p->to.u.branch = r->s2->prog;
- }
- r1 = r;
- }
-
- /*
- * last pass
- * eliminate nops
- * free aux structures
- */
- for(p = firstr->prog; p != P; p = p->link){
- while(p->link && p->link->as == ANOP)
- p->link = p->link->link;
- }
-
- if(debug['R'] && debug['v']) {
- print("after pass 8 (fixup pc)\n");
- for(p1=firstr->prog; p1!=P; p1=p1->link)
- print("%P\n", p1);
- print("\n");
- }
-
- if(r1 != R) {
- r1->link = freer;
- freer = firstr;
- }
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Addr *a;
- Var *v;
-
- p1 = alloc(sizeof(*p1));
- *p1 = zprog;
- p = r->prog;
-
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->sym = v->sym;
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = v->name;
-
- p1->as = AMOVL;
- if(v->etype == TCHAR || v->etype == TUCHAR)
- p1->as = AMOVB;
- if(v->etype == TSHORT || v->etype == TUSHORT)
- p1->as = AMOVW;
-
- p1->from.type = rn;
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = rn;
- if(v->etype == TUCHAR)
- p1->as = AMOVB;
- if(v->etype == TUSHORT)
- p1->as = AMOVW;
- }
- if(debug['R'])
- print("%P\t.a%P\n", p, p1);
-}
-
-uint32
-doregbits(int r)
-{
- uint32 b;
-
- b = 0;
- if(r >= D_INDIR)
- r -= D_INDIR;
- if(r >= D_AX && r <= D_DI)
- b |= RtoB(r);
- else
- if(r >= D_AL && r <= D_BL)
- b |= RtoB(r-D_AL+D_AX);
- else
- if(r >= D_AH && r <= D_BH)
- b |= RtoB(r-D_AH+D_AX);
- return b;
-}
-
-Bits
-mkvar(Reg *r, Addr *a)
-{
- Var *v;
- int i, t, n, et, z;
- int32 o;
- Bits bit;
- LSym *s;
-
- /*
- * mark registers used
- */
- t = a->type;
- r->regu |= doregbits(t);
- r->regu |= doregbits(a->index);
-
- switch(t) {
- default:
- goto none;
- case D_ADDR:
- a->type = a->index;
- bit = mkvar(r, a);
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- a->type = t;
- goto none;
- case D_EXTERN:
- case D_STATIC:
- case D_PARAM:
- case D_AUTO:
- n = t;
- break;
- }
- s = a->sym;
- if(s == nil)
- goto none;
- if(s->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- v = var;
- for(i=0; i<nvar; i++) {
- if(s == v->sym)
- if(n == v->name)
- if(o == v->offset)
- goto out;
- v++;
- }
- if(nvar >= NVAR)
- fatal(Z, "variable not optimized: %s", s->name);
- i = nvar;
- nvar++;
- v = &var[i];
- v->sym = s;
- v->offset = o;
- v->name = n;
- v->etype = et;
- if(debug['R'])
- print("bit=%2d et=%2d %D\n", i, et, a);
-
-out:
- bit = blsh(i);
- if(n == D_EXTERN || n == D_STATIC)
- for(z=0; z<BITS; z++)
- externs.b[z] |= bit.b[z];
- if(n == D_PARAM)
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
- if(v->etype != et || !typechlpfd[et]) /* funny punning */
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- return bit;
-
-none:
- return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
- Reg *r1, *r2;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->p1) {
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(r1->prog->as) {
- case ACALL:
- for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z];
- ref.b[z] = 0;
- }
- break;
-
- case ATEXT:
- for(z=0; z<BITS; z++) {
- cal.b[z] = 0;
- ref.b[z] = 0;
- }
- break;
-
- case ARET:
- for(z=0; z<BITS; z++) {
- cal.b[z] = externs.b[z];
- ref.b[z] = 0;
- }
- }
- for(z=0; z<BITS; z++) {
- ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
- r1->use1.b[z] | r1->use2.b[z];
- cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
- r1->refbehind.b[z] = ref.b[z];
- r1->calbehind.b[z] = cal.b[z];
- }
- if(r1->active)
- break;
- r1->active = 1;
- }
- for(; r != r1; r = r->p1)
- for(r2 = r->p2; r2 != R; r2 = r2->p2link)
- prop(r2, r->refbehind, r->calbehind);
-}
-
-/*
- * find looping structure
- *
- * 1) find reverse postordering
- * 2) find approximate dominators,
- * the actual dominators if the flow graph is reducible
- * otherwise, dominators plus some other non-dominators.
- * See Matthew S. Hecht and Jeffrey D. Ullman,
- * "Analysis of a Simple Algorithm for Global Data Flow Problems",
- * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
- * Oct. 1-3, 1973, pp. 207-217.
- * 3) find all nodes with a predecessor dominated by the current node.
- * such a node is a loop head.
- * recursively, all preds with a greater rpo number are in the loop
- */
-int32
-postorder(Reg *r, Reg **rpo2r, int32 n)
-{
- Reg *r1;
-
- r->rpo = 1;
- r1 = r->s1;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- r1 = r->s2;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- rpo2r[n] = r;
- n++;
- return n;
-}
-
-int32
-rpolca(int32 *idom, int32 rpo1, int32 rpo2)
-{
- int32 t;
-
- if(rpo1 == -1)
- return rpo2;
- while(rpo1 != rpo2){
- if(rpo1 > rpo2){
- t = rpo2;
- rpo2 = rpo1;
- rpo1 = t;
- }
- while(rpo1 < rpo2){
- t = idom[rpo2];
- if(t >= rpo2)
- fatal(Z, "bad idom");
- rpo2 = t;
- }
- }
- return rpo1;
-}
-
-int
-doms(int32 *idom, int32 r, int32 s)
-{
- while(s > r)
- s = idom[s];
- return s == r;
-}
-
-int
-loophead(int32 *idom, Reg *r)
-{
- int32 src;
-
- src = r->rpo;
- if(r->p1 != R && doms(idom, src, r->p1->rpo))
- return 1;
- for(r = r->p2; r != R; r = r->p2link)
- if(doms(idom, src, r->rpo))
- return 1;
- return 0;
-}
-
-void
-loopmark(Reg **rpo2r, int32 head, Reg *r)
-{
- if(r->rpo < head || r->active == head)
- return;
- r->active = head;
- r->loop += LOOP;
- if(r->p1 != R)
- loopmark(rpo2r, head, r->p1);
- for(r = r->p2; r != R; r = r->p2link)
- loopmark(rpo2r, head, r);
-}
-
-void
-loopit(Reg *r, int32 nr)
-{
- Reg *r1;
- int32 i, d, me;
-
- if(nr > maxnr) {
- rpo2r = alloc(nr * sizeof(Reg*));
- idom = alloc(nr * sizeof(int32));
- maxnr = nr;
- }
-
- d = postorder(r, rpo2r, 0);
- if(d > nr)
- fatal(Z, "too many reg nodes");
- nr = d;
- for(i = 0; i < nr / 2; i++){
- r1 = rpo2r[i];
- rpo2r[i] = rpo2r[nr - 1 - i];
- rpo2r[nr - 1 - i] = r1;
- }
- for(i = 0; i < nr; i++)
- rpo2r[i]->rpo = i;
-
- idom[0] = 0;
- for(i = 0; i < nr; i++){
- r1 = rpo2r[i];
- me = r1->rpo;
- d = -1;
- if(r1->p1 != R && r1->p1->rpo < me)
- d = r1->p1->rpo;
- for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
- if(r1->rpo < me)
- d = rpolca(idom, d, r1->rpo);
- idom[i] = d;
- }
-
- for(i = 0; i < nr; i++){
- r1 = rpo2r[i];
- r1->loop++;
- if(r1->p2 != R && loophead(idom, r1))
- loopmark(rpo2r, i, r1);
- }
-}
-
-void
-synch(Reg *r, Bits dif)
-{
- Reg *r1;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->s1) {
- for(z=0; z<BITS; z++) {
- dif.b[z] = (dif.b[z] &
- ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
- r1->set.b[z] | r1->regdiff.b[z];
- if(dif.b[z] != r1->regdiff.b[z]) {
- r1->regdiff.b[z] = dif.b[z];
- change++;
- }
- }
- if(r1->active)
- break;
- r1->active = 1;
- for(z=0; z<BITS; z++)
- dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if(r1->s2 != R)
- synch(r1->s2, dif);
- }
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
- Var *v;
- int i;
-
- v = var + r->varno;
- r->regno = 0;
- switch(v->etype) {
-
- default:
- diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
- break;
-
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- case TARRAY:
- i = BtoR(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TDOUBLE:
- case TFLOAT:
- break;
- }
- return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint32 bb;
-
- z = bn/32;
- bb = 1L<<(bn%32);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
- change -= CLOAD * r->loop;
- if(debug['R'] && debug['v'])
- print("%d%P\td %B $%d\n", r->loop,
- r->prog, blsh(bn), change);
- }
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- change += CREF * r->loop;
- if(p->as == AFMOVL)
- if(BtoR(bb) != D_F0)
- change = -CINF;
- if(debug['R'] && debug['v'])
- print("%d%P\tu1 %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->loop;
- if(p->as == AFMOVL)
- if(BtoR(bb) != D_F0)
- change = -CINF;
- if(debug['R'] && debug['v'])
- print("%d%P\tu2 %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->loop;
- if(p->as == AFMOVL)
- if(BtoR(bb) != D_F0)
- change = -CINF;
- if(debug['R'] && debug['v'])
- print("%d%P\tst %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint1(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint1(r1, bn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-uint32
-regset(Reg *r, uint32 bb)
-{
- uint32 b, set;
- Addr v;
- int c;
-
- set = 0;
- v = zprog.from;
- while(b = bb & ~(bb-1)) {
- v.type = BtoR(b);
- c = copyu(r->prog, &v, A);
- if(c == 3)
- set |= b;
- bb &= ~b;
- }
- return set;
-}
-
-uint32
-reguse(Reg *r, uint32 bb)
-{
- uint32 b, set;
- Addr v;
- int c;
-
- set = 0;
- v = zprog.from;
- while(b = bb & ~(bb-1)) {
- v.type = BtoR(b);
- c = copyu(r->prog, &v, A);
- if(c == 1 || c == 2 || c == 4)
- set |= b;
- bb &= ~b;
- }
- return set;
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
- Reg *r1;
- int z;
- uint32 bb, vreg, x;
-
- z = bn/32;
- bb = 1L << (bn%32);
- vreg = regbits;
- if(!(r->act.b[z] & bb))
- return vreg;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(!(r1->act.b[z] & bb))
- break;
- r = r1;
- }
- for(;;) {
- r->act.b[z] &= ~bb;
-
- vreg |= r->regu;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
- r = r->s1;
- if(r == R)
- break;
- if(!(r->act.b[z] & bb))
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-
- bb = vreg;
- for(; r; r=r->s1) {
- x = r->regu & ~bb;
- if(x) {
- vreg |= reguse(r, x);
- bb |= regset(r, x);
- }
- }
- return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint32 bb;
-
- z = bn/32;
- bb = 1L << (bn%32);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
- addmove(r, bn, rn, 0);
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->from, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->to, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(r, bn, rn, 1);
- r->regu |= rb;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Addr *a, int rn)
-{
-
- a->sym = 0;
- a->offset = 0;
- a->type = rn;
-}
-
-int32
-RtoB(int r)
-{
-
- if(r < D_AX || r > D_DI)
- return 0;
- return 1L << (r-D_AX);
-}
-
-int
-BtoR(int32 b)
-{
-
- b &= 0xffL;
- if(b == 0)
- return 0;
- return bitno(b) + D_AX;
-}
-
-/* what instruction does a JMP to p eventually land on? */
-static Reg*
-chasejmp(Reg *r, int *jmploop)
-{
- int n;
-
- n = 0;
- for(; r; r=r->s2) {
- if(r->prog->as != AJMP || r->prog->to.type != D_BRANCH)
- break;
- if(++n > 10) {
- *jmploop = 1;
- break;
- }
- }
- return r;
-}
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Reg *firstr)
-{
- Reg *r;
- Prog *p;
-
- for(r=firstr; r; r=r->link) {
- if(r->active)
- break;
- r->active = 1;
- p = r->prog;
- if(p->as != ACALL && p->to.type == D_BRANCH)
- mark(r->s2);
- if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
- break;
- }
-}
-
-/*
- * the code generator depends on being able to write out JMP
- * instructions that it can jump to now but fill in later.
- * the linker will resolve them nicely, but they make the code
- * longer and more difficult to follow during debugging.
- * remove them.
- */
-static void
-fixjmp(Reg *firstr)
-{
- int jmploop;
- Reg *r;
- Prog *p;
-
- if(debug['R'] && debug['v'])
- print("\nfixjmp\n");
-
- // pass 1: resolve jump to AJMP, mark all code as dead.
- jmploop = 0;
- for(r=firstr; r; r=r->link) {
- p = r->prog;
- if(debug['R'] && debug['v'])
- print("%04d %P\n", (int)r->pc, p);
- if(p->as != ACALL && p->to.type == D_BRANCH && r->s2 && r->s2->prog->as == AJMP) {
- r->s2 = chasejmp(r->s2, &jmploop);
- p->to.offset = r->s2->pc;
- p->to.u.branch = r->s2->prog;
- if(debug['R'] && debug['v'])
- print("->%P\n", p);
- }
- r->active = 0;
- }
- if(debug['R'] && debug['v'])
- print("\n");
-
- // pass 2: mark all reachable code alive
- mark(firstr);
-
- // pass 3: delete dead code (mostly JMPs).
- for(r=firstr; r; r=r->link) {
- if(!r->active) {
- p = r->prog;
- if(p->link == P && p->as == ARET && r->p1 && r->p1->prog->as != ARET) {
- // This is the final ARET, and the code so far doesn't have one.
- // Let it stay.
- } else {
- if(debug['R'] && debug['v'])
- print("del %04d %P\n", (int)r->pc, p);
- p->as = ANOP;
- }
- }
- }
-
- // pass 4: elide JMP to next instruction.
- // only safe if there are no jumps to JMPs anymore.
- if(!jmploop) {
- for(r=firstr; r; r=r->link) {
- p = r->prog;
- if(p->as == AJMP && p->to.type == D_BRANCH && r->s2 == r->link) {
- if(debug['R'] && debug['v'])
- print("del %04d %P\n", (int)r->pc, p);
- p->as = ANOP;
- }
- }
- }
-
- // fix back pointers.
- for(r=firstr; r; r=r->link) {
- r->p2 = R;
- r->p2link = R;
- }
- for(r=firstr; r; r=r->link) {
- if(r->s2) {
- r->p2link = r->s2->p2;
- r->s2->p2 = r;
- }
- }
-
- if(debug['R'] && debug['v']) {
- print("\n");
- for(r=firstr; r; r=r->link)
- print("%04d %P\n", (int)r->pc, r->prog);
- print("\n");
- }
-}
-
diff --git a/src/cmd/8c/sgen.c b/src/cmd/8c/sgen.c
deleted file mode 100644
index d647010ef..000000000
--- a/src/cmd/8c/sgen.c
+++ /dev/null
@@ -1,483 +0,0 @@
-// Inferno utils/8c/sgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/sgen.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-Prog*
-gtext(Sym *s, int32 stkoff)
-{
- int32 a;
-
- a = argsize(1);
- if((textflag & NOSPLIT) != 0 && stkoff >= 128)
- yyerror("stack frame too large for NOSPLIT function");
-
- gpseudo(ATEXT, s, nodconst(stkoff));
- p->to.type = D_CONST2;
- p->to.offset2 = a;
- return p;
-}
-
-void
-noretval(int n)
-{
-
- if(n & 1) {
- gins(ANOP, Z, Z);
- p->to.type = REGRET;
- }
- if(n & 2) {
- gins(ANOP, Z, Z);
- p->to.type = FREGRET;
- }
-}
-
-/* welcome to commute */
-static void
-commute(Node *n)
-{
- Node *l, *r;
-
- l = n->left;
- r = n->right;
- if(r->complex > l->complex) {
- n->left = r;
- n->right = l;
- }
-}
-
-void
-indexshift(Node *n)
-{
- int g;
-
- if(!typechlp[n->type->etype])
- return;
- simplifyshift(n);
- if(n->op == OASHL && n->right->op == OCONST){
- g = vconst(n->right);
- if(g >= 0 && g < 4)
- n->addable = 7;
- }
-}
-
-/*
- * calculate addressability as follows
- * NAME ==> 10/11 name+value(SB/SP)
- * REGISTER ==> 12 register
- * CONST ==> 20 $value
- * *(20) ==> 21 value
- * &(10) ==> 13 $name+value(SB)
- * &(11) ==> 1 $name+value(SP)
- * (13) + (20) ==> 13 fold constants
- * (1) + (20) ==> 1 fold constants
- * *(13) ==> 10 back to name
- * *(1) ==> 11 back to name
- *
- * (20) * (X) ==> 7 multiplier in indexing
- * (X,7) + (13,1) ==> 8 adder in indexing (addresses)
- * (8) ==> &9(OINDEX) index, almost addressable
- * 100 extern register
- *
- * calculate complexity (number of registers)
- */
-void
-xcom(Node *n)
-{
- Node *l, *r;
- int g;
-
- if(n == Z)
- return;
- l = n->left;
- r = n->right;
- n->complex = 0;
- n->addable = 0;
- switch(n->op) {
- case OCONST:
- n->addable = 20;
- break;
-
- case ONAME:
- n->addable = 10;
- if(n->class == CPARAM || n->class == CAUTO)
- n->addable = 11;
- break;
-
- case OEXREG:
- n->addable = 0;
- break;
-
- case OREGISTER:
- n->addable = 12;
- break;
-
- case OINDREG:
- n->addable = 12;
- break;
-
- case OADDR:
- xcom(l);
- if(l->addable == 10)
- n->addable = 13;
- else
- if(l->addable == 11)
- n->addable = 1;
- break;
-
- case OADD:
- xcom(l);
- xcom(r);
- if(n->type->etype != TIND)
- break;
-
- switch(r->addable) {
- case 20:
- switch(l->addable) {
- case 1:
- case 13:
- commadd:
- l->type = n->type;
- *n = *l;
- l = new(0, Z, Z);
- *l = *(n->left);
- l->xoffset += r->vconst;
- n->left = l;
- r = n->right;
- goto brk;
- }
- break;
-
- case 1:
- case 13:
- case 10:
- case 11:
- /* l is the base, r is the index */
- if(l->addable != 20)
- n->addable = 8;
- break;
- }
- switch(l->addable) {
- case 20:
- switch(r->addable) {
- case 13:
- case 1:
- r = n->left;
- l = n->right;
- n->left = l;
- n->right = r;
- goto commadd;
- }
- break;
-
- case 13:
- case 1:
- case 10:
- case 11:
- /* r is the base, l is the index */
- if(r->addable != 20)
- n->addable = 8;
- break;
- }
- if(n->addable == 8 && !side(n)) {
- indx(n);
- l = new1(OINDEX, idx.basetree, idx.regtree);
- l->scale = idx.scale;
- l->addable = 9;
- l->complex = l->right->complex;
- l->type = l->left->type;
- n->op = OADDR;
- n->left = l;
- n->right = Z;
- n->addable = 8;
- break;
- }
- break;
-
- case OINDEX:
- xcom(l);
- xcom(r);
- n->addable = 9;
- break;
-
- case OIND:
- xcom(l);
- if(l->op == OADDR) {
- l = l->left;
- l->type = n->type;
- *n = *l;
- return;
- }
- switch(l->addable) {
- case 20:
- n->addable = 21;
- break;
- case 1:
- n->addable = 11;
- break;
- case 13:
- n->addable = 10;
- break;
- }
- break;
-
- case OASHL:
- xcom(l);
- xcom(r);
- indexshift(n);
- break;
-
- case OMUL:
- case OLMUL:
- xcom(l);
- xcom(r);
- g = vlog(l);
- if(g >= 0) {
- n->left = r;
- n->right = l;
- l = r;
- r = n->right;
- }
- g = vlog(r);
- if(g >= 0) {
- n->op = OASHL;
- r->vconst = g;
- r->type = types[TINT];
- indexshift(n);
- break;
- }
-commute(n);
- break;
-
- case OASLDIV:
- xcom(l);
- xcom(r);
- g = vlog(r);
- if(g >= 0) {
- n->op = OASLSHR;
- r->vconst = g;
- r->type = types[TINT];
- }
- break;
-
- case OLDIV:
- xcom(l);
- xcom(r);
- g = vlog(r);
- if(g >= 0) {
- n->op = OLSHR;
- r->vconst = g;
- r->type = types[TINT];
- indexshift(n);
- break;
- }
- break;
-
- case OASLMOD:
- xcom(l);
- xcom(r);
- g = vlog(r);
- if(g >= 0) {
- n->op = OASAND;
- r->vconst--;
- }
- break;
-
- case OLMOD:
- xcom(l);
- xcom(r);
- g = vlog(r);
- if(g >= 0) {
- n->op = OAND;
- r->vconst--;
- }
- break;
-
- case OASMUL:
- case OASLMUL:
- xcom(l);
- xcom(r);
- g = vlog(r);
- if(g >= 0) {
- n->op = OASASHL;
- r->vconst = g;
- }
- break;
-
- case OLSHR:
- case OASHR:
- xcom(l);
- xcom(r);
- indexshift(n);
- break;
-
- default:
- if(l != Z)
- xcom(l);
- if(r != Z)
- xcom(r);
- break;
- }
-brk:
- if(n->addable >= 10)
- return;
- if(l != Z)
- n->complex = l->complex;
- if(r != Z) {
- if(r->complex == n->complex)
- n->complex = r->complex+1;
- else
- if(r->complex > n->complex)
- n->complex = r->complex;
- }
- if(n->complex == 0)
- n->complex++;
-
- if(com64(n))
- return;
-
- switch(n->op) {
-
- case OFUNC:
- n->complex = FNX;
- break;
-
- case OLMOD:
- case OMOD:
- case OLMUL:
- case OLDIV:
- case OMUL:
- case ODIV:
- case OASLMUL:
- case OASLDIV:
- case OASLMOD:
- case OASMUL:
- case OASDIV:
- case OASMOD:
- if(r->complex >= l->complex) {
- n->complex = l->complex + 3;
- if(r->complex > n->complex)
- n->complex = r->complex;
- } else {
- n->complex = r->complex + 3;
- if(l->complex > n->complex)
- n->complex = l->complex;
- }
- break;
-
- case OLSHR:
- case OASHL:
- case OASHR:
- case OASLSHR:
- case OASASHL:
- case OASASHR:
- if(r->complex >= l->complex) {
- n->complex = l->complex + 2;
- if(r->complex > n->complex)
- n->complex = r->complex;
- } else {
- n->complex = r->complex + 2;
- if(l->complex > n->complex)
- n->complex = l->complex;
- }
- break;
-
- case OADD:
- case OXOR:
- case OAND:
- case OOR:
- /*
- * immediate operators, make const on right
- */
- if(l->op == OCONST) {
- n->left = r;
- n->right = l;
- }
- break;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- /*
- * compare operators, make const on left
- */
- if(r->op == OCONST) {
- n->left = r;
- n->right = l;
- n->op = invrel[relindex(n->op)];
- }
- break;
- }
-}
-
-void
-indx(Node *n)
-{
- Node *l, *r;
-
- if(debug['x'])
- prtree(n, "indx");
-
- l = n->left;
- r = n->right;
- if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
- n->right = l;
- n->left = r;
- l = r;
- r = n->right;
- }
- if(l->addable != 7) {
- idx.regtree = l;
- idx.scale = 1;
- } else
- if(l->right->addable == 20) {
- idx.regtree = l->left;
- idx.scale = 1 << l->right->vconst;
- } else
- if(l->left->addable == 20) {
- idx.regtree = l->right;
- idx.scale = 1 << l->left->vconst;
- } else
- diag(n, "bad index");
-
- idx.basetree = r;
- if(debug['x']) {
- print("scale = %d\n", idx.scale);
- prtree(idx.regtree, "index");
- prtree(idx.basetree, "base");
- }
-}
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
deleted file mode 100644
index d960519e3..000000000
--- a/src/cmd/8c/swt.c
+++ /dev/null
@@ -1,341 +0,0 @@
-// Inferno utils/8c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-void
-swit1(C1 *q, int nc, int32 def, Node *n)
-{
- Node nreg;
-
- if(typev[n->type->etype]) {
- regsalloc(&nreg, n);
- nreg.type = types[TVLONG];
- cgen(n, &nreg);
- swit2(q, nc, def, &nreg);
- return;
- }
-
- regalloc(&nreg, n, Z);
- nreg.type = types[TLONG];
- cgen(n, &nreg);
- swit2(q, nc, def, &nreg);
- regfree(&nreg);
-}
-
-void
-swit2(C1 *q, int nc, int32 def, Node *n)
-{
- C1 *r;
- int i;
- Prog *sp;
-
- if(nc < 5) {
- for(i=0; i<nc; i++) {
- if(debug['W'])
- print("case = %.8ux\n", q->val);
- gopcode(OEQ, n->type, n, nodconst(q->val));
- patch(p, q->label);
- q++;
- }
- gbranch(OGOTO);
- patch(p, def);
- return;
- }
- i = nc / 2;
- r = q+i;
- if(debug['W'])
- print("case > %.8ux\n", r->val);
- gopcode(OGT, n->type, n, nodconst(r->val));
- sp = p;
- gbranch(OGOTO);
- p->as = AJEQ;
- patch(p, r->label);
- swit2(q, i, def, n);
-
- if(debug['W'])
- print("case < %.8ux\n", r->val);
- patch(sp, pc);
- swit2(r+1, nc-i-1, def, n);
-}
-
-void
-bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
- int sh;
- int32 v;
- Node *l;
-
- /*
- * n1 gets adjusted/masked value
- * n2 gets address of cell
- * n3 gets contents of cell
- */
- l = b->left;
- if(n2 != Z) {
- regalloc(n1, l, nn);
- reglcgen(n2, l, Z);
- regalloc(n3, l, Z);
- gmove(n2, n3);
- gmove(n3, n1);
- } else {
- regalloc(n1, l, nn);
- cgen(l, n1);
- }
- if(b->type->shift == 0 && typeu[b->type->etype]) {
- v = ~0 + (1L << b->type->nbits);
- gopcode(OAND, types[TLONG], nodconst(v), n1);
- } else {
- sh = 32 - b->type->shift - b->type->nbits;
- if(sh > 0)
- gopcode(OASHL, types[TLONG], nodconst(sh), n1);
- sh += b->type->shift;
- if(sh > 0)
- if(typeu[b->type->etype])
- gopcode(OLSHR, types[TLONG], nodconst(sh), n1);
- else
- gopcode(OASHR, types[TLONG], nodconst(sh), n1);
- }
-}
-
-void
-bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
- int32 v;
- Node nod;
- int sh;
-
- regalloc(&nod, b->left, Z);
- v = ~0 + (1L << b->type->nbits);
- gopcode(OAND, types[TLONG], nodconst(v), n1);
- gmove(n1, &nod);
- if(nn != Z)
- gmove(n1, nn);
- sh = b->type->shift;
- if(sh > 0)
- gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
- v <<= sh;
- gopcode(OAND, types[TLONG], nodconst(~v), n3);
- gopcode(OOR, types[TLONG], n3, &nod);
- gmove(&nod, n2);
-
- regfree(&nod);
- regfree(n1);
- regfree(n2);
- regfree(n3);
-}
-
-int32
-outstring(char *s, int32 n)
-{
- int32 r;
-
- if(suppress)
- return nstring;
- r = nstring;
- while(n) {
- string[mnstring] = *s++;
- mnstring++;
- nstring++;
- if(mnstring >= NSNAME) {
- gpseudo(ADATA, symstring, nodconst(0L));
- p->from.offset += nstring - NSNAME;
- p->from.scale = NSNAME;
- p->to.type = D_SCONST;
- memmove(p->to.u.sval, string, NSNAME);
- mnstring = 0;
- }
- n--;
- }
- return r;
-}
-
-void
-sextern(Sym *s, Node *a, int32 o, int32 w)
-{
- int32 e, lw;
-
- for(e=0; e<w; e+=NSNAME) {
- lw = NSNAME;
- if(w-e < lw)
- lw = w-e;
- gpseudo(ADATA, s, nodconst(0L));
- p->from.offset += o+e;
- p->from.scale = lw;
- p->to.type = D_SCONST;
- memmove(p->to.u.sval, a->cstring+e, lw);
- }
-}
-
-void
-gextern(Sym *s, Node *a, int32 o, int32 w)
-{
- if(a->op == OCONST && typev[a->type->etype]) {
- gpseudo(ADATA, s, lo64(a));
- p->from.offset += o;
- p->from.scale = 4;
- gpseudo(ADATA, s, hi64(a));
- p->from.offset += o + 4;
- p->from.scale = 4;
- return;
- }
- gpseudo(ADATA, s, a);
- p->from.offset += o;
- p->from.scale = w;
- switch(p->to.type) {
- default:
- p->to.index = p->to.type;
- p->to.type = D_ADDR;
- case D_CONST:
- case D_FCONST:
- case D_ADDR:
- break;
- }
-}
-
-void
-outcode(void)
-{
- int f;
- Biobuf b;
-
- f = open(outfile, OWRITE);
- if(f < 0) {
- diag(Z, "cannot open %s", outfile);
- return;
- }
- Binit(&b, f, OWRITE);
-
- Bprint(&b, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
- if(pragcgobuf.to > pragcgobuf.start) {
- Bprint(&b, "\n");
- Bprint(&b, "$$ // exports\n\n");
- Bprint(&b, "$$ // local types\n\n");
- Bprint(&b, "$$ // cgo\n");
- Bprint(&b, "%s", fmtstrflush(&pragcgobuf));
- Bprint(&b, "\n$$\n\n");
- }
- Bprint(&b, "!\n");
-
- writeobj(ctxt, &b);
- Bterm(&b);
- close(f);
- lastp = P;
-}
-
-int32
-align(int32 i, Type *t, int op, int32 *maxalign)
-{
- int32 o;
- Type *v;
- int w, packw;
-
- o = i;
- w = 1;
- packw = 0;
- switch(op) {
- default:
- diag(Z, "unknown align opcode %d", op);
- break;
-
- case Asu2: /* padding at end of a struct */
- w = *maxalign;
- if(w < 1)
- w = 1;
- if(packflg)
- packw = packflg;
- break;
-
- case Ael1: /* initial align of struct element */
- for(v=t; v->etype==TARRAY; v=v->link)
- ;
- if(v->etype == TSTRUCT || v->etype == TUNION)
- w = v->align;
- else {
- w = ewidth[v->etype];
- if(w == 8)
- w = 4;
- }
- if(w < 1 || w > SZ_LONG)
- fatal(Z, "align");
- if(packflg)
- packw = packflg;
- break;
-
- case Ael2: /* width of a struct element */
- o += t->width;
- break;
-
- case Aarg0: /* initial passbyptr argument in arg list */
- if(typesuv[t->etype]) {
- o = align(o, types[TIND], Aarg1, nil);
- o = align(o, types[TIND], Aarg2, nil);
- }
- break;
-
- case Aarg1: /* initial align of parameter */
- w = ewidth[t->etype];
- if(w <= 0 || w >= SZ_LONG) {
- w = SZ_LONG;
- break;
- }
- w = 1; /* little endian no adjustment */
- break;
-
- case Aarg2: /* width of a parameter */
- o += t->width;
- w = t->width;
- if(w > SZ_LONG)
- w = SZ_LONG;
- break;
-
- case Aaut3: /* total align of automatic */
- o = align(o, t, Ael1, nil);
- o = align(o, t, Ael2, nil);
- break;
- }
- if(packw != 0 && xround(o, w) != xround(o, packw))
- diag(Z, "#pragma pack changes offset of %T", t);
- o = xround(o, w);
- if(maxalign && *maxalign < w)
- *maxalign = w;
- if(debug['A'])
- print("align %s %d %T = %d\n", bnames[op], i, t, o);
- return o;
-}
-
-int32
-maxround(int32 max, int32 v)
-{
- v = xround(v, SZ_LONG);
- if(v > max)
- return v;
- return max;
-}
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
deleted file mode 100644
index 7f87a0a0d..000000000
--- a/src/cmd/8c/txt.c
+++ /dev/null
@@ -1,1537 +0,0 @@
-// Inferno utils/8c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-
-int thechar = '8';
-char *thestring = "386";
-
-LinkArch *thelinkarch = &link386;
-
-void
-linkarchinit(void)
-{
-}
-
-void
-ginit(void)
-{
- int i;
- Type *t;
-
- exregoffset = 0;
- exfregoffset = 0;
- listinit();
- nstring = 0;
- mnstring = 0;
- nrathole = 0;
- pc = 0;
- breakpc = -1;
- continpc = -1;
- cases = C;
- lastp = P;
- tfield = types[TLONG];
-
- zprog.link = P;
- zprog.as = AGOK;
- zprog.from.type = D_NONE;
- zprog.from.index = D_NONE;
- zprog.from.scale = 0;
- zprog.to = zprog.from;
-
- regnode.op = OREGISTER;
- regnode.class = CEXREG;
- regnode.reg = REGTMP;
- regnode.complex = 0;
- regnode.addable = 11;
- regnode.type = types[TLONG];
-
- fregnode0 = regnode;
- fregnode0.reg = D_F0;
- fregnode0.type = types[TDOUBLE];
-
- fregnode1 = fregnode0;
- fregnode1.reg = D_F0+1;
-
- constnode.op = OCONST;
- constnode.class = CXXX;
- constnode.complex = 0;
- constnode.addable = 20;
- constnode.type = types[TLONG];
-
- fconstnode.op = OCONST;
- fconstnode.class = CXXX;
- fconstnode.complex = 0;
- fconstnode.addable = 20;
- fconstnode.type = types[TDOUBLE];
-
- nodsafe = new(ONAME, Z, Z);
- nodsafe->sym = slookup(".safe");
- nodsafe->type = types[TINT];
- nodsafe->etype = types[TINT]->etype;
- nodsafe->class = CAUTO;
- complex(nodsafe);
-
- t = typ(TARRAY, types[TCHAR]);
- symrathole = slookup(".rathole");
- symrathole->class = CGLOBL;
- symrathole->type = t;
-
- nodrat = new(ONAME, Z, Z);
- nodrat->sym = symrathole;
- nodrat->type = types[TIND];
- nodrat->etype = TVOID;
- nodrat->class = CGLOBL;
- complex(nodrat);
- nodrat->type = t;
-
- nodret = new(ONAME, Z, Z);
- nodret->sym = slookup(".ret");
- nodret->type = types[TIND];
- nodret->etype = TIND;
- nodret->class = CPARAM;
- nodret = new(OIND, nodret, Z);
- complex(nodret);
-
- com64init();
-
- for(i=0; i<nelem(reg); i++) {
- reg[i] = 1;
- if(i >= D_AX && i <= D_DI && i != D_SP)
- reg[i] = 0;
- }
-}
-
-void
-gclean(void)
-{
- int i;
- Sym *s;
-
- reg[D_SP]--;
- for(i=D_AX; i<=D_DI; i++)
- if(reg[i])
- diag(Z, "reg %R left allocated", i);
- while(mnstring)
- outstring("", 1L);
- symstring->type->width = nstring;
- symrathole->type->width = nrathole;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type == T)
- continue;
- if(s->type->width == 0)
- continue;
- if(s->class != CGLOBL && s->class != CSTATIC)
- continue;
- if(s->type == types[TENUM])
- continue;
- gpseudo(AGLOBL, s, nodconst(s->type->width));
- }
- nextpc();
- p->as = AEND;
- outcode();
-}
-
-void
-nextpc(void)
-{
- Plist *pl;
-
- p = alloc(sizeof(*p));
- *p = zprog;
- p->lineno = nearln;
- p->pc = pc;
- pc++;
- if(lastp == nil) {
- pl = linknewplist(ctxt);
- pl->firstpc = p;
- } else
- lastp->link = p;
- lastp = p;
-}
-
-void
-gargs(Node *n, Node *tn1, Node *tn2)
-{
- int32 regs;
- Node fnxargs[20], *fnxp;
-
- regs = cursafe;
-
- fnxp = fnxargs;
- garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
-
- curarg = 0;
- fnxp = fnxargs;
- garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
-
- cursafe = regs;
-}
-
-int
-nareg(void)
-{
- int i, n;
-
- n = 0;
- for(i=D_AX; i<=D_DI; i++)
- if(reg[i] == 0)
- n++;
- return n;
-}
-
-void
-garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
-{
- Node nod;
-
- if(n == Z)
- return;
- if(n->op == OLIST) {
- garg1(n->left, tn1, tn2, f, fnxp);
- garg1(n->right, tn1, tn2, f, fnxp);
- return;
- }
- if(f == 0) {
- if(n->complex >= FNX) {
- regsalloc(*fnxp, n);
- nod = znode;
- nod.op = OAS;
- nod.left = *fnxp;
- nod.right = n;
- nod.type = n->type;
- cgen(&nod, Z);
- (*fnxp)++;
- }
- return;
- }
- if(typesu[n->type->etype] || typev[n->type->etype]) {
- regaalloc(tn2, n);
- if(n->complex >= FNX) {
- sugen(*fnxp, tn2, n->type->width);
- (*fnxp)++;
- } else
- sugen(n, tn2, n->type->width);
- return;
- }
- if(REGARG >= 0 && curarg == 0 && typeilp[n->type->etype]) {
- regaalloc1(tn1, n);
- if(n->complex >= FNX) {
- cgen(*fnxp, tn1);
- (*fnxp)++;
- } else
- cgen(n, tn1);
- return;
- }
- if(vconst(n) == 0) {
- regaalloc(tn2, n);
- gmove(n, tn2);
- return;
- }
- regalloc(tn1, n, Z);
- if(n->complex >= FNX) {
- cgen(*fnxp, tn1);
- (*fnxp)++;
- } else
- cgen(n, tn1);
- regaalloc(tn2, n);
- gmove(tn1, tn2);
- regfree(tn1);
-}
-
-Node*
-nodconst(int32 v)
-{
- constnode.vconst = v;
- return &constnode;
-}
-
-Node*
-nodfconst(double d)
-{
- fconstnode.fconst = d;
- return &fconstnode;
-}
-
-int
-isreg(Node *n, int r)
-{
-
- if(n->op == OREGISTER)
- if(n->reg == r)
- return 1;
- return 0;
-}
-
-int
-nodreg(Node *n, Node *nn, int r)
-{
-
- *n = regnode;
- n->reg = r;
- if(reg[r] == 0)
- return 0;
- if(nn != Z) {
- n->type = nn->type;
- n->lineno = nn->lineno;
- if(nn->op == OREGISTER)
- if(nn->reg == r)
- return 0;
- }
- return 1;
-}
-
-void
-regret(Node *n, Node *nn, Type *t, int mode)
-{
- int r;
-
- if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET;
- nodreg(n, nn, r);
- reg[r]++;
- return;
- }
-
- if(mode == 1) {
- // fetch returned value after call.
- // already called gargs, so curarg is set.
- curarg = (curarg+3) & ~3;
- regaalloc(n, nn);
- return;
- }
-
- if(mode == 2) {
- // store value to be returned.
- // must compute arg offset.
- if(t->etype != TFUNC)
- fatal(Z, "bad regret func %T", t);
- *n = *nn;
- n->op = ONAME;
- n->class = CPARAM;
- n->sym = slookup(".retx");
- n->complex = 0;
- n->addable = 20;
- n->xoffset = argsize(0);
- return;
- }
-
- fatal(Z, "bad regret");
-}
-
-void
-regalloc(Node *n, Node *tn, Node *o)
-{
- int i;
-
- switch(tn->type->etype) {
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- if(o != Z && o->op == OREGISTER) {
- i = o->reg;
- if(i >= D_AX && i <= D_DI)
- goto out;
- }
- for(i=D_AX; i<=D_DI; i++)
- if(reg[i] == 0)
- goto out;
- diag(tn, "out of fixed registers");
- goto err;
-
- case TFLOAT:
- case TDOUBLE:
- case TVLONG:
- i = D_F0;
- goto out;
- }
- diag(tn, "unknown type in regalloc: %T", tn->type);
-err:
- i = 0;
-out:
- if(i)
- reg[i]++;
- nodreg(n, tn, i);
-}
-
-void
-regialloc(Node *n, Node *tn, Node *o)
-{
- Node nod;
-
- nod = *tn;
- nod.type = types[TIND];
- regalloc(n, &nod, o);
-}
-
-void
-regfree(Node *n)
-{
- int i;
-
- i = 0;
- if(n->op != OREGISTER && n->op != OINDREG)
- goto err;
- i = n->reg;
- if(i < 0 || i >= nelem(reg))
- goto err;
- if(reg[i] <= 0)
- goto err;
- reg[i]--;
- return;
-err:
- diag(n, "error in regfree: %R", i);
-}
-
-void
-regsalloc(Node *n, Node *nn)
-{
- cursafe = align(cursafe, nn->type, Aaut3, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
- *n = *nodsafe;
- n->xoffset = -(stkoff + cursafe);
- n->type = nn->type;
- n->etype = nn->type->etype;
- n->lineno = nn->lineno;
-}
-
-void
-regaalloc1(Node *n, Node *nn)
-{
- if(REGARG < 0) {
- fatal(n, "regaalloc1 and REGARG<0");
- return;
- }
- nodreg(n, nn, REGARG);
- reg[REGARG]++;
- curarg = align(curarg, nn->type, Aarg1, nil);
- curarg = align(curarg, nn->type, Aarg2, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regaalloc(Node *n, Node *nn)
-{
- curarg = align(curarg, nn->type, Aarg1, nil);
- *n = *nn;
- n->op = OINDREG;
- n->reg = REGSP;
- n->xoffset = curarg;
- n->complex = 0;
- n->addable = 20;
- curarg = align(curarg, nn->type, Aarg2, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regind(Node *n, Node *nn)
-{
-
- if(n->op != OREGISTER) {
- diag(n, "regind not OREGISTER");
- return;
- }
- n->op = OINDREG;
- n->type = nn->type;
-}
-
-void
-naddr(Node *n, Addr *a)
-{
- int32 v;
-
- a->type = D_NONE;
- if(n == Z)
- return;
- switch(n->op) {
- default:
- bad:
- diag(n, "bad in naddr: %O %D", n->op, a);
- break;
-
- case OREGISTER:
- a->type = n->reg;
- a->sym = nil;
- break;
-
- case OEXREG:
- a->type = D_INDIR + D_TLS;
- a->offset = n->reg - 1;
- break;
-
- 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;
- break;
-
- case OINDEX:
- a->type = idx.ptr;
- if(n->left->op == OADDR || n->left->op == OCONST)
- 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;
- a->index = idx.reg;
- a->scale = n->scale;
- a->offset += n->xoffset;
- break;
-
- case OINDREG:
- a->type = n->reg+D_INDIR;
- a->sym = nil;
- a->offset = n->xoffset;
- break;
-
- case ONAME:
- a->etype = n->etype;
- a->type = D_STATIC;
- a->sym = linksym(n->sym);
- a->offset = n->xoffset;
- if(n->class == CSTATIC)
- break;
- if(n->class == CEXTERN || n->class == CGLOBL) {
- a->type = D_EXTERN;
- break;
- }
- if(n->class == CAUTO) {
- a->type = D_AUTO;
- break;
- }
- if(n->class == CPARAM) {
- a->type = D_PARAM;
- break;
- }
- goto bad;
-
- case OCONST:
- if(typefd[n->type->etype]) {
- a->type = D_FCONST;
- a->u.dval = n->fconst;
- break;
- }
- a->sym = nil;
- a->type = D_CONST;
- a->offset = n->vconst;
- break;
-
- case OADDR:
- naddr(n->left, a);
- 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;
- }
- goto bad;
-
- case OADD:
- if(n->right->op == OCONST) {
- v = n->right->vconst;
- naddr(n->left, a);
- } else
- if(n->left->op == OCONST) {
- v = n->left->vconst;
- naddr(n->right, a);
- } else
- goto bad;
- a->offset += v;
- break;
-
- }
-}
-
-#define CASE(a,b) ((a<<8)|(b<<0))
-
-void
-gmove(Node *f, Node *t)
-{
- int ft, tt, a;
- Node nod, nod1;
- Prog *p1;
-
- ft = f->type->etype;
- tt = t->type->etype;
- if(debug['M'])
- print("gop: %O %O[%s],%O[%s]\n", OAS,
- f->op, tnames[ft], t->op, tnames[tt]);
- if(typefd[ft] && f->op == OCONST) {
- if(f->fconst == 0)
- gins(AFLDZ, Z, Z);
- else
- if(f->fconst == 1)
- gins(AFLD1, Z, Z);
- else
- gins(AFMOVD, f, &fregnode0);
- gmove(&fregnode0, t);
- return;
- }
-/*
- * load
- */
- if(f->op == ONAME || f->op == OINDREG ||
- f->op == OIND || f->op == OINDEX)
- switch(ft) {
- case TCHAR:
- a = AMOVBLSX;
- goto ld;
- case TUCHAR:
- a = AMOVBLZX;
- goto ld;
- case TSHORT:
- if(typefd[tt]) {
- gins(AFMOVW, f, &fregnode0);
- gmove(&fregnode0, t);
- return;
- }
- a = AMOVWLSX;
- goto ld;
- case TUSHORT:
- a = AMOVWLZX;
- goto ld;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- if(typefd[tt]) {
- gins(AFMOVL, f, &fregnode0);
- gmove(&fregnode0, t);
- return;
- }
- a = AMOVL;
-
- ld:
- regalloc(&nod, f, t);
- nod.type = types[TLONG];
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
-
- case TFLOAT:
- gins(AFMOVF, f, t);
- return;
- case TDOUBLE:
- gins(AFMOVD, f, t);
- return;
- case TVLONG:
- gins(AFMOVV, f, t);
- return;
- }
-
-/*
- * store
- */
- if(t->op == ONAME || t->op == OINDREG ||
- t->op == OIND || t->op == OINDEX)
- switch(tt) {
- case TCHAR:
- case TUCHAR:
- a = AMOVB; goto st;
- case TSHORT:
- case TUSHORT:
- a = AMOVW; goto st;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- a = AMOVL; goto st;
-
- st:
- if(f->op == OCONST) {
- gins(a, f, t);
- return;
- }
- regalloc(&nod, t, f);
- gmove(f, &nod);
- gins(a, &nod, t);
- regfree(&nod);
- return;
-
- case TFLOAT:
- gins(AFMOVFP, f, t);
- return;
- case TDOUBLE:
- gins(AFMOVDP, f, t);
- return;
- case TVLONG:
- gins(AFMOVVP, f, t);
- return;
- }
-
-/*
- * convert
- */
- switch(CASE(ft,tt)) {
- default:
-/*
- * integer to integer
- ********
- a = AGOK; break;
-
- case CASE( TCHAR, TCHAR):
- case CASE( TUCHAR, TCHAR):
- case CASE( TSHORT, TCHAR):
- case CASE( TUSHORT,TCHAR):
- case CASE( TINT, TCHAR):
- case CASE( TUINT, TCHAR):
- case CASE( TLONG, TCHAR):
- case CASE( TULONG, TCHAR):
- case CASE( TIND, TCHAR):
-
- case CASE( TCHAR, TUCHAR):
- case CASE( TUCHAR, TUCHAR):
- case CASE( TSHORT, TUCHAR):
- case CASE( TUSHORT,TUCHAR):
- case CASE( TINT, TUCHAR):
- case CASE( TUINT, TUCHAR):
- case CASE( TLONG, TUCHAR):
- case CASE( TULONG, TUCHAR):
- case CASE( TIND, TUCHAR):
-
- case CASE( TSHORT, TSHORT):
- case CASE( TUSHORT,TSHORT):
- case CASE( TINT, TSHORT):
- case CASE( TUINT, TSHORT):
- case CASE( TLONG, TSHORT):
- case CASE( TULONG, TSHORT):
- case CASE( TIND, TSHORT):
-
- case CASE( TSHORT, TUSHORT):
- case CASE( TUSHORT,TUSHORT):
- case CASE( TINT, TUSHORT):
- case CASE( TUINT, TUSHORT):
- case CASE( TLONG, TUSHORT):
- case CASE( TULONG, TUSHORT):
- case CASE( TIND, TUSHORT):
-
- case CASE( TINT, TINT):
- case CASE( TUINT, TINT):
- case CASE( TLONG, TINT):
- case CASE( TULONG, TINT):
- case CASE( TIND, TINT):
-
- case CASE( TINT, TUINT):
- case CASE( TUINT, TUINT):
- case CASE( TLONG, TUINT):
- case CASE( TULONG, TUINT):
- case CASE( TIND, TUINT):
-
- case CASE( TINT, TLONG):
- case CASE( TUINT, TLONG):
- case CASE( TLONG, TLONG):
- case CASE( TULONG, TLONG):
- case CASE( TIND, TLONG):
-
- case CASE( TINT, TULONG):
- case CASE( TUINT, TULONG):
- case CASE( TLONG, TULONG):
- case CASE( TULONG, TULONG):
- case CASE( TIND, TULONG):
-
- case CASE( TINT, TIND):
- case CASE( TUINT, TIND):
- case CASE( TLONG, TIND):
- case CASE( TULONG, TIND):
- case CASE( TIND, TIND):
- *****/
- a = AMOVL;
- break;
-
- case CASE( TSHORT, TINT):
- case CASE( TSHORT, TUINT):
- case CASE( TSHORT, TLONG):
- case CASE( TSHORT, TULONG):
- case CASE( TSHORT, TIND):
- a = AMOVWLSX;
- if(f->op == OCONST) {
- f->vconst &= 0xffff;
- if(f->vconst & 0x8000)
- f->vconst |= 0xffff0000;
- a = AMOVL;
- }
- break;
-
- case CASE( TUSHORT,TINT):
- case CASE( TUSHORT,TUINT):
- case CASE( TUSHORT,TLONG):
- case CASE( TUSHORT,TULONG):
- case CASE( TUSHORT,TIND):
- a = AMOVWLZX;
- if(f->op == OCONST) {
- f->vconst &= 0xffff;
- a = AMOVL;
- }
- break;
-
- case CASE( TCHAR, TSHORT):
- case CASE( TCHAR, TUSHORT):
- case CASE( TCHAR, TINT):
- case CASE( TCHAR, TUINT):
- case CASE( TCHAR, TLONG):
- case CASE( TCHAR, TULONG):
- case CASE( TCHAR, TIND):
- a = AMOVBLSX;
- if(f->op == OCONST) {
- f->vconst &= 0xff;
- if(f->vconst & 0x80)
- f->vconst |= 0xffffff00;
- a = AMOVL;
- }
- break;
-
- case CASE( TUCHAR, TSHORT):
- case CASE( TUCHAR, TUSHORT):
- case CASE( TUCHAR, TINT):
- case CASE( TUCHAR, TUINT):
- case CASE( TUCHAR, TLONG):
- case CASE( TUCHAR, TULONG):
- case CASE( TUCHAR, TIND):
- a = AMOVBLZX;
- if(f->op == OCONST) {
- f->vconst &= 0xff;
- a = AMOVL;
- }
- break;
-
-/*
- * float to fix
- */
- case CASE( TFLOAT, TCHAR):
- case CASE( TFLOAT, TUCHAR):
- case CASE( TFLOAT, TSHORT):
- case CASE( TFLOAT, TUSHORT):
- case CASE( TFLOAT, TINT):
- case CASE( TFLOAT, TUINT):
- case CASE( TFLOAT, TLONG):
- case CASE( TFLOAT, TULONG):
- case CASE( TFLOAT, TIND):
-
- case CASE( TDOUBLE,TCHAR):
- case CASE( TDOUBLE,TUCHAR):
- case CASE( TDOUBLE,TSHORT):
- case CASE( TDOUBLE,TUSHORT):
- case CASE( TDOUBLE,TINT):
- case CASE( TDOUBLE,TUINT):
- case CASE( TDOUBLE,TLONG):
- case CASE( TDOUBLE,TULONG):
- case CASE( TDOUBLE,TIND):
-
- case CASE( TVLONG, TCHAR):
- case CASE( TVLONG, TUCHAR):
- case CASE( TVLONG, TSHORT):
- case CASE( TVLONG, TUSHORT):
- case CASE( TVLONG, TINT):
- case CASE( TVLONG, TUINT):
- case CASE( TVLONG, TLONG):
- case CASE( TVLONG, TULONG):
- case CASE( TVLONG, TIND):
- if(fproundflg) {
- regsalloc(&nod, &regnode);
- gins(AFMOVLP, f, &nod);
- gmove(&nod, t);
- return;
- }
- regsalloc(&nod, &regnode);
- regsalloc(&nod1, &regnode);
- gins(AFSTCW, Z, &nod1);
- nod1.xoffset += 2;
- gins(AMOVW, nodconst(0xf7f), &nod1);
- gins(AFLDCW, &nod1, Z);
- gins(AFMOVLP, f, &nod);
- nod1.xoffset -= 2;
- gins(AFLDCW, &nod1, Z);
- gmove(&nod, t);
- return;
-
-/*
- * ulong to float
- */
- case CASE( TULONG, TDOUBLE):
- case CASE( TULONG, TVLONG):
- case CASE( TULONG, TFLOAT):
- case CASE( TUINT, TDOUBLE):
- case CASE( TUINT, TVLONG):
- case CASE( TUINT, TFLOAT):
- regalloc(&nod, f, f);
- gmove(f, &nod);
- regsalloc(&nod1, &regnode);
- gmove(&nod, &nod1);
- gins(AFMOVL, &nod1, &fregnode0);
- gins(ACMPL, &nod, nodconst(0));
- gins(AJGE, Z, Z);
- p1 = p;
- gins(AFADDD, nodfconst(4294967296.), &fregnode0);
- patch(p1, pc);
- regfree(&nod);
- return;
-
-/*
- * fix to float
- */
- case CASE( TCHAR, TFLOAT):
- case CASE( TUCHAR, TFLOAT):
- case CASE( TSHORT, TFLOAT):
- case CASE( TUSHORT,TFLOAT):
- case CASE( TINT, TFLOAT):
- case CASE( TLONG, TFLOAT):
- case CASE( TIND, TFLOAT):
-
- case CASE( TCHAR, TDOUBLE):
- case CASE( TUCHAR, TDOUBLE):
- case CASE( TSHORT, TDOUBLE):
- case CASE( TUSHORT,TDOUBLE):
- case CASE( TINT, TDOUBLE):
- case CASE( TLONG, TDOUBLE):
- case CASE( TIND, TDOUBLE):
-
- case CASE( TCHAR, TVLONG):
- case CASE( TUCHAR, TVLONG):
- case CASE( TSHORT, TVLONG):
- case CASE( TUSHORT,TVLONG):
- case CASE( TINT, TVLONG):
- case CASE( TLONG, TVLONG):
- case CASE( TIND, TVLONG):
- regsalloc(&nod, &regnode);
- gmove(f, &nod);
- gins(AFMOVL, &nod, &fregnode0);
- return;
-
-/*
- * float to float
- */
- case CASE( TFLOAT, TFLOAT):
- case CASE( TDOUBLE,TFLOAT):
- case CASE( TVLONG, TFLOAT):
-
- case CASE( TFLOAT, TDOUBLE):
- case CASE( TDOUBLE,TDOUBLE):
- case CASE( TVLONG, TDOUBLE):
-
- case CASE( TFLOAT, TVLONG):
- case CASE( TDOUBLE,TVLONG):
- case CASE( TVLONG, TVLONG):
- a = AFMOVD; break;
- }
- if(a == AMOVL || a == AFMOVD)
- if(samaddr(f, t))
- return;
- gins(a, f, t);
-}
-
-void
-doindex(Node *n)
-{
- Node nod, nod1;
- int32 v;
-
-if(debug['Y'])
-prtree(n, "index");
-
-if(n->left->complex >= FNX)
-print("botch in doindex\n");
-
- regalloc(&nod, &regnode, Z);
- v = constnode.vconst;
- cgen(n->right, &nod);
- idx.ptr = D_NONE;
- if(n->left->op == OCONST)
- idx.ptr = D_CONST;
- else if(n->left->op == OREGISTER)
- idx.ptr = n->left->reg;
- else if(n->left->op != OADDR) {
- reg[D_BP]++; // can't be used as a base
- regalloc(&nod1, &regnode, Z);
- cgen(n->left, &nod1);
- idx.ptr = nod1.reg;
- regfree(&nod1);
- reg[D_BP]--;
- }
- idx.reg = nod.reg;
- regfree(&nod);
- constnode.vconst = v;
-}
-
-void
-gins(int a, Node *f, Node *t)
-{
-
- if(f != Z && f->op == OINDEX)
- doindex(f);
- if(t != Z && t->op == OINDEX)
- doindex(t);
- nextpc();
- p->as = a;
- if(f != Z)
- naddr(f, &p->from);
- if(t != Z)
- naddr(t, &p->to);
- if(debug['g'])
- print("%P\n", p);
-}
-
-void
-fgopcode(int o, Node *f, Node *t, int pop, int rev)
-{
- int a, et;
- Node nod;
-
- et = TLONG;
- if(f != Z && f->type != T)
- et = f->type->etype;
- if(!typefd[et]) {
- diag(f, "fop: integer %O", o);
- return;
- }
- if(debug['M']) {
- if(t != Z && t->type != T)
- print("gop: %O %O-%s Z\n", o, f->op, tnames[et]);
- else
- print("gop: %O %O-%s %O-%s\n", o,
- f->op, tnames[et], t->op, tnames[t->type->etype]);
- }
- a = AGOK;
- switch(o) {
-
- case OASADD:
- case OADD:
- if(et == TFLOAT)
- a = AFADDF;
- else
- if(et == TDOUBLE || et == TVLONG) {
- a = AFADDD;
- if(pop)
- a = AFADDDP;
- }
- break;
-
- case OASSUB:
- case OSUB:
- if(et == TFLOAT) {
- a = AFSUBF;
- if(rev)
- a = AFSUBRF;
- } else
- if(et == TDOUBLE || et == TVLONG) {
- a = AFSUBD;
- if(pop)
- a = AFSUBDP;
- if(rev) {
- a = AFSUBRD;
- if(pop)
- a = AFSUBRDP;
- }
- }
- break;
-
- case OASMUL:
- case OMUL:
- if(et == TFLOAT)
- a = AFMULF;
- else
- if(et == TDOUBLE || et == TVLONG) {
- a = AFMULD;
- if(pop)
- a = AFMULDP;
- }
- break;
-
- case OASMOD:
- case OMOD:
- case OASDIV:
- case ODIV:
- if(et == TFLOAT) {
- a = AFDIVF;
- if(rev)
- a = AFDIVRF;
- } else
- if(et == TDOUBLE || et == TVLONG) {
- a = AFDIVD;
- if(pop)
- a = AFDIVDP;
- if(rev) {
- a = AFDIVRD;
- if(pop)
- a = AFDIVRDP;
- }
- }
- break;
-
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- pop += rev;
- if(et == TFLOAT) {
- a = AFCOMF;
- if(pop) {
- a = AFCOMFP;
- if(pop > 1)
- a = AGOK;
- }
- } else
- if(et == TDOUBLE || et == TVLONG) {
- a = AFCOMF;
- if(pop) {
- a = AFCOMDP;
- if(pop > 1)
- a = AFCOMDPP;
- }
- }
- gins(a, f, t);
- regalloc(&nod, &regnode, Z);
- if(nod.reg != D_AX) {
- regfree(&nod);
- nod.reg = D_AX;
- gins(APUSHL, &nod, Z);
- gins(AWAIT, Z, Z);
- gins(AFSTSW, Z, &nod);
- gins(ASAHF, Z, Z);
- gins(APOPL, Z, &nod);
- } else {
- gins(AWAIT, Z, Z);
- gins(AFSTSW, Z, &nod);
- gins(ASAHF, Z, Z);
- regfree(&nod);
- }
- switch(o) {
- case OEQ: a = AJEQ; break;
- case ONE: a = AJNE; break;
- case OLT: a = AJCS; break;
- case OLE: a = AJLS; break;
- case OGE: a = AJCC; break;
- case OGT: a = AJHI; break;
- }
- gins(a, Z, Z);
- return;
- }
- if(a == AGOK)
- diag(Z, "bad in gopcode %O", o);
- gins(a, f, t);
-}
-
-void
-gopcode(int o, Type *ty, Node *f, Node *t)
-{
- int a, et;
-
- et = TLONG;
- if(ty != T)
- et = ty->etype;
- if(typefd[et] && o != OADDR && o != OFUNC) {
- diag(f, "gop: float %O", o);
- return;
- }
- if(debug['M']) {
- if(f != Z && f->type != T)
- print("gop: %O %O[%s],", o, f->op, tnames[et]);
- else
- print("gop: %O Z,", o);
- if(t != Z && t->type != T)
- print("%O[%s]\n", t->op, tnames[t->type->etype]);
- else
- print("Z\n");
- }
- a = AGOK;
- switch(o) {
- case OCOM:
- a = ANOTL;
- if(et == TCHAR || et == TUCHAR)
- a = ANOTB;
- if(et == TSHORT || et == TUSHORT)
- a = ANOTW;
- break;
-
- case ONEG:
- a = ANEGL;
- if(et == TCHAR || et == TUCHAR)
- a = ANEGB;
- if(et == TSHORT || et == TUSHORT)
- a = ANEGW;
- break;
-
- case OADDR:
- a = ALEAL;
- break;
-
- case OASADD:
- case OADD:
- a = AADDL;
- if(et == TCHAR || et == TUCHAR)
- a = AADDB;
- if(et == TSHORT || et == TUSHORT)
- a = AADDW;
- break;
-
- case OASSUB:
- case OSUB:
- a = ASUBL;
- if(et == TCHAR || et == TUCHAR)
- a = ASUBB;
- if(et == TSHORT || et == TUSHORT)
- a = ASUBW;
- break;
-
- case OASOR:
- case OOR:
- a = AORL;
- if(et == TCHAR || et == TUCHAR)
- a = AORB;
- if(et == TSHORT || et == TUSHORT)
- a = AORW;
- break;
-
- case OASAND:
- case OAND:
- a = AANDL;
- if(et == TCHAR || et == TUCHAR)
- a = AANDB;
- if(et == TSHORT || et == TUSHORT)
- a = AANDW;
- break;
-
- case OASXOR:
- case OXOR:
- a = AXORL;
- if(et == TCHAR || et == TUCHAR)
- a = AXORB;
- if(et == TSHORT || et == TUSHORT)
- a = AXORW;
- break;
-
- case OASLSHR:
- case OLSHR:
- a = ASHRL;
- if(et == TCHAR || et == TUCHAR)
- a = ASHRB;
- if(et == TSHORT || et == TUSHORT)
- a = ASHRW;
- break;
-
- case OASASHR:
- case OASHR:
- a = ASARL;
- if(et == TCHAR || et == TUCHAR)
- a = ASARB;
- if(et == TSHORT || et == TUSHORT)
- a = ASARW;
- break;
-
- case OASASHL:
- case OASHL:
- a = ASALL;
- if(et == TCHAR || et == TUCHAR)
- a = ASALB;
- if(et == TSHORT || et == TUSHORT)
- a = ASALW;
- break;
-
- case OROTL:
- a = AROLL;
- if(et == TCHAR || et == TUCHAR)
- a = AROLB;
- if(et == TSHORT || et == TUSHORT)
- a = AROLW;
- break;
-
- case OFUNC:
- a = ACALL;
- break;
-
- case OASMUL:
- case OMUL:
- if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
- t = Z;
- a = AIMULL;
- break;
-
- case OASMOD:
- case OMOD:
- case OASDIV:
- case ODIV:
- a = AIDIVL;
- break;
-
- case OASLMUL:
- case OLMUL:
- a = AMULL;
- break;
-
- case OASLMOD:
- case OLMOD:
- case OASLDIV:
- case OLDIV:
- a = ADIVL;
- break;
-
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case OLO:
- case OLS:
- case OHS:
- case OHI:
- a = ACMPL;
- if(et == TCHAR || et == TUCHAR)
- a = ACMPB;
- if(et == TSHORT || et == TUSHORT)
- a = ACMPW;
- gins(a, f, t);
- switch(o) {
- case OEQ: a = AJEQ; break;
- case ONE: a = AJNE; break;
- case OLT: a = AJLT; break;
- case OLE: a = AJLE; break;
- case OGE: a = AJGE; break;
- case OGT: a = AJGT; break;
- case OLO: a = AJCS; break;
- case OLS: a = AJLS; break;
- case OHS: a = AJCC; break;
- case OHI: a = AJHI; break;
- }
- gins(a, Z, Z);
- return;
- }
- if(a == AGOK)
- diag(Z, "bad in gopcode %O", o);
- gins(a, f, t);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
- if(f->op != t->op)
- return 0;
- switch(f->op) {
-
- case OREGISTER:
- if(f->reg != t->reg)
- break;
- return 1;
- }
- return 0;
-}
-
-void
-gbranch(int o)
-{
- int a;
-
- a = AGOK;
- switch(o) {
- case ORETURN:
- a = ARET;
- break;
- case OGOTO:
- a = AJMP;
- break;
- }
- nextpc();
- if(a == AGOK) {
- diag(Z, "bad in gbranch %O", o);
- nextpc();
- }
- p->as = a;
-}
-
-void
-patch(Prog *op, int32 pc)
-{
- op->to.offset = pc;
- op->to.type = D_BRANCH;
- op->to.u.branch = nil;
- op->pcond = nil;
-}
-
-void
-gpseudo(int a, Sym *s, Node *n)
-{
-
- nextpc();
- p->as = a;
- p->from.type = D_EXTERN;
- p->from.sym = linksym(s);
-
- switch(a) {
- case ATEXT:
- p->from.scale = textflag;
- textflag = 0;
- break;
- case AGLOBL:
- p->from.scale = s->dataflag;
- break;
- }
-
- if(s->class == CSTATIC)
- p->from.type = D_STATIC;
- naddr(n, &p->to);
- if(a == ADATA || a == AGLOBL)
- pc--;
-}
-
-void
-gpcdata(int index, int value)
-{
- Node n1;
-
- n1 = *nodconst(index);
- gins(APCDATA, &n1, nodconst(value));
-}
-
-void
-gprefetch(Node *n)
-{
- Node n1;
-
- if(strcmp(getgo386(), "sse2") != 0) // assume no prefetch on old machines
- return;
-
- regalloc(&n1, n, Z);
- gmove(n, &n1);
- n1.op = OINDREG;
- gins(APREFETCHNTA, &n1, Z);
- regfree(&n1);
-}
-
-int
-sconst(Node *n)
-{
- int32 v;
-
- if(n->op == OCONST && !typefd[n->type->etype]) {
- v = n->vconst;
- if(v >= -32766L && v < 32766L)
- return 1;
- }
- return 0;
-}
-
-int32
-exreg(Type *t)
-{
- int32 o;
-
- if(typechlp[t->etype]){
- if(exregoffset >= 32)
- return 0;
- o = exregoffset;
- exregoffset += 4;
- return o+1; // +1 to avoid 0 == failure; naddr case OEXREG will -1.
- }
-
- return 0;
-}
-
-schar ewidth[NTYPE] =
-{
- -1, /*[TXXX]*/
- SZ_CHAR, /*[TCHAR]*/
- SZ_CHAR, /*[TUCHAR]*/
- SZ_SHORT, /*[TSHORT]*/
- SZ_SHORT, /*[TUSHORT]*/
- SZ_INT, /*[TINT]*/
- SZ_INT, /*[TUINT]*/
- SZ_LONG, /*[TLONG]*/
- SZ_LONG, /*[TULONG]*/
- SZ_VLONG, /*[TVLONG]*/
- SZ_VLONG, /*[TUVLONG]*/
- SZ_FLOAT, /*[TFLOAT]*/
- SZ_DOUBLE, /*[TDOUBLE]*/
- SZ_IND, /*[TIND]*/
- 0, /*[TFUNC]*/
- -1, /*[TARRAY]*/
- 0, /*[TVOID]*/
- -1, /*[TSTRUCT]*/
- -1, /*[TUNION]*/
- SZ_INT, /*[TENUM]*/
-};
-int32 ncast[NTYPE] =
-{
- 0, /*[TXXX]*/
- BCHAR|BUCHAR, /*[TCHAR]*/
- BCHAR|BUCHAR, /*[TUCHAR]*/
- BSHORT|BUSHORT, /*[TSHORT]*/
- BSHORT|BUSHORT, /*[TUSHORT]*/
- BINT|BUINT|BLONG|BULONG|BIND, /*[TINT]*/
- BINT|BUINT|BLONG|BULONG|BIND, /*[TUINT]*/
- BINT|BUINT|BLONG|BULONG|BIND, /*[TLONG]*/
- BINT|BUINT|BLONG|BULONG|BIND, /*[TULONG]*/
- BVLONG|BUVLONG, /*[TVLONG]*/
- BVLONG|BUVLONG, /*[TUVLONG]*/
- BFLOAT, /*[TFLOAT]*/
- BDOUBLE, /*[TDOUBLE]*/
- BLONG|BULONG|BIND, /*[TIND]*/
- 0, /*[TFUNC]*/
- 0, /*[TARRAY]*/
- 0, /*[TVOID]*/
- BSTRUCT, /*[TSTRUCT]*/
- BUNION, /*[TUNION]*/
- 0, /*[TENUM]*/
-};
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
index fa0605e6c..af287f702 100644
--- a/src/cmd/8g/gobj.c
+++ b/src/cmd/8g/gobj.c
@@ -81,7 +81,7 @@ datagostring(Strlit *sval, Addr *a)
a->sym = linksym(sym);
a->node = sym->def;
a->offset = 0; // header
- a->etype = TINT32;
+ a->etype = TSTRING;
}
void
diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h
index 09f58c40a..5445f9127 100644
--- a/src/cmd/8g/opt.h
+++ b/src/cmd/8g/opt.h
@@ -63,8 +63,8 @@ enum
uint32 BLOAD(Reg*);
uint32 BSTORE(Reg*);
-uint32 LOAD(Reg*);
-uint32 STORE(Reg*);
+uint64 LOAD(Reg*);
+uint64 STORE(Reg*);
*/
// A Reg is a wrapper around a single Prog (one instruction) that holds
@@ -75,12 +75,18 @@ struct Reg
{
Flow f;
- Bits set; // variables written by this instruction.
- Bits use1; // variables read by prog->from.
- Bits use2; // variables read by prog->to.
+ Bits set; // regopt variables written by this instruction.
+ Bits use1; // regopt variables read by prog->from.
+ Bits use2; // regopt variables read by prog->to.
+ // refahead/refbehind are the regopt variables whose current
+ // value may be used in the following/preceding instructions
+ // up to a CALL (or the value is clobbered).
Bits refbehind;
Bits refahead;
+ // calahead/calbehind are similar, but for variables in
+ // instructions that are reachable after hitting at least one
+ // CALL.
Bits calbehind;
Bits calahead;
Bits regdiff;
@@ -106,6 +112,16 @@ struct Reg
#define NRGN 600
/*c2go enum { NRGN = 600 }; */
+
+// A Rgn represents a single regopt variable over a region of code
+// where a register could potentially be dedicated to that variable.
+// The code encompassed by a Rgn is defined by the flow graph,
+// starting at enter, flood-filling forward while varno is refahead
+// and backward while varno is refbehind, and following branches. A
+// single variable may be represented by multiple disjoint Rgns and
+// each Rgn may choose a different register for that variable.
+// Registers are allocated to regions greedily in order of descending
+// cost.
struct Rgn
{
Reg* enter;
@@ -158,8 +174,8 @@ void loopit(Reg*, int32);
void synch(Reg*, Bits);
uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
-uint32 paint2(Reg*, int);
-void paint3(Reg*, int, int32, int);
+uint32 paint2(Reg*, int, int);
+void paint3(Reg*, int, uint32, int);
void addreg(Adr*, int);
void dumpone(Flow*, int);
void dumpit(char*, Flow*, int);
@@ -171,10 +187,10 @@ void peep(Prog*);
void excise(Flow*);
int copyu(Prog*, Adr*, Adr*);
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
+uint32 RtoB(int);
+uint32 FtoB(int);
+int BtoR(uint32);
+int BtoF(uint32);
/*
* prog.c
@@ -183,8 +199,8 @@ typedef struct ProgInfo ProgInfo;
struct ProgInfo
{
uint32 flags; // the bits below
- uint32 reguse; // required registers used by this instruction
- uint32 regset; // required registers set by this instruction
+ uint32 reguse; // registers implicitly used by this instruction
+ uint32 regset; // registers implicitly set by this instruction
uint32 regindex; // registers used by addressing mode
};
@@ -205,12 +221,12 @@ enum
SizeF = 1<<7, // float aka float32
SizeD = 1<<8, // double aka float64
- // Left side: address taken, read, write.
+ // Left side (Prog.from): address taken, read, write.
LeftAddr = 1<<9,
LeftRead = 1<<10,
LeftWrite = 1<<11,
- // Right side: address taken, read, write.
+ // Right side (Prog.to): address taken, read, write.
RightAddr = 1<<12,
RightRead = 1<<13,
RightWrite = 1<<14,
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index 302b273a1..d7394a16d 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -34,7 +34,7 @@
#include "opt.h"
#define NREGVAR 16 /* 8 integer + 8 floating */
-#define REGBITS ((uint32)0xffff)
+#define REGBITS ((uint64)0xffffull)
/*c2go enum {
NREGVAR = 16,
REGBITS = (1<<NREGVAR) - 1,
@@ -71,7 +71,7 @@ setaddrs(Bits bit)
i = bnum(bit);
node = var[i].node;
n = var[i].name;
- bit.b[i/32] &= ~(1L<<(i%32));
+ biclr(&bit, i);
// disable all pieces of that variable
for(i=0; i<nvar; i++) {
@@ -336,7 +336,7 @@ loop2:
rgp->varno = i;
change = 0;
paint1(r, i);
- bit.b[i/32] &= ~(1L<<(i%32));
+ biclr(&bit, i);
if(change <= 0)
continue;
rgp->cost = change;
@@ -358,18 +358,19 @@ brk:
* replace code (paint3)
*/
rgp = region;
+ if(debug['R'] && debug['v'])
+ print("\nregisterizing\n");
for(i=0; i<nregion; i++) {
+ if(debug['R'] && debug['v'])
+ print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(vreg, rgp);
if(rgp->regno != 0)
paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
rgp++;
}
- if(debug['R'] && debug['v'])
- dumpit("pass6", &firstr->f, 1);
-
/*
* free aux structures. peep allocates new ones.
*/
@@ -378,6 +379,15 @@ brk:
flowend(g);
firstr = R;
+ if(debug['R'] && debug['v']) {
+ // Rebuild flow graph, since we inserted instructions
+ g = flowstart(firstp, sizeof(Reg));
+ firstr = (Reg*)g->start;
+ dumpit("pass6", &firstr->f, 1);
+ flowend(g);
+ firstr = R;
+ }
+
/*
* pass 7
* peep-hole on basic block
@@ -446,7 +456,7 @@ walkvardef(Node *n, Reg *r, int active)
break;
for(v=n->opt; v!=nil; v=v->nextinnode) {
bn = v - var;
- r1->act.b[bn/32] |= 1L << (bn%32);
+ biset(&r1->act, bn);
}
if(r1->f.prog->as == ACALL)
break;
@@ -788,10 +798,10 @@ prop(Reg *r, Bits ref, Bits cal)
for(z=0; z<BITS; z++) {
if(cal.b[z] == 0)
continue;
- for(i=0; i<32; i++) {
- if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
+ for(i=0; i<64; i++) {
+ if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
continue;
- v = var+z*32+i;
+ v = var+z*64+i;
if(v->node->opt == nil) // v represents fixed register, not Go variable
continue;
@@ -807,10 +817,10 @@ prop(Reg *r, Bits ref, Bits cal)
// This will set the bits at most twice, keeping the overall loop linear.
v1 = v->node->opt;
j = v1 - var;
- if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
+ if(v == v1 || !btest(&cal, j)) {
for(; v1 != nil; v1 = v1->nextinnode) {
j = v1 - var;
- cal.b[j/32] |= 1<<(j&31);
+ biset(&cal, j);
}
}
}
@@ -926,10 +936,10 @@ paint1(Reg *r, int bn)
Reg *r1;
Prog *p;
int z;
- uint32 bb;
+ uint64 bb, rbz;
- z = bn/32;
- bb = 1L<<(bn%32);
+ z = bn/64;
+ bb = 1LL<<(bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@@ -945,7 +955,8 @@ paint1(Reg *r, int bn)
r = r1;
}
- if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ rbz = ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z]));
+ if(LOAD(r) & rbz & bb) {
change -= CLOAD * r->f.loop;
}
for(;;) {
@@ -996,52 +1007,14 @@ paint1(Reg *r, int bn)
}
uint32
-regset(Reg *r, uint32 bb)
-{
- uint32 b, set;
- Adr v;
- int c;
-
- set = 0;
- v = zprog.from;
- while(b = bb & ~(bb-1)) {
- v.type = b & 0xFF ? BtoR(b): BtoF(b);
- c = copyu(r->f.prog, &v, nil);
- if(c == 3)
- set |= b;
- bb &= ~b;
- }
- return set;
-}
-
-uint32
-reguse(Reg *r, uint32 bb)
-{
- uint32 b, set;
- Adr v;
- int c;
-
- set = 0;
- v = zprog.from;
- while(b = bb & ~(bb-1)) {
- v.type = b & 0xFF ? BtoR(b): BtoF(b);
- c = copyu(r->f.prog, &v, nil);
- if(c == 1 || c == 2 || c == 4)
- set |= b;
- bb &= ~b;
- }
- return set;
-}
-
-uint32
-paint2(Reg *r, int bn)
+paint2(Reg *r, int bn, int depth)
{
Reg *r1;
int z;
- uint32 bb, vreg, x;
+ uint64 bb, vreg;
- z = bn/32;
- bb = 1L << (bn%32);
+ z = bn/64;
+ bb = 1LL << (bn%64);
vreg = regbits;
if(!(r->act.b[z] & bb))
return vreg;
@@ -1058,6 +1031,9 @@ paint2(Reg *r, int bn)
r = r1;
}
for(;;) {
+ if(debug['R'] && debug['v'])
+ print(" paint2 %d %P\n", depth, r->f.prog);
+
r->act.b[z] &= ~bb;
vreg |= r->regu;
@@ -1065,14 +1041,14 @@ paint2(Reg *r, int bn)
if(r->refbehind.b[z] & bb)
for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
if(!(r->refahead.b[z] & bb))
break;
r1 = (Reg*)r->f.s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
r = (Reg*)r->f.s1;
if(r == R)
break;
@@ -1082,27 +1058,19 @@ paint2(Reg *r, int bn)
break;
}
- bb = vreg;
- for(; r; r=(Reg*)r->f.s1) {
- x = r->regu & ~bb;
- if(x) {
- vreg |= reguse(r, x);
- bb |= regset(r, x);
- }
- }
return vreg;
}
void
-paint3(Reg *r, int bn, int32 rb, int rn)
+paint3(Reg *r, int bn, uint32 rb, int rn)
{
Reg *r1;
Prog *p;
int z;
- uint32 bb;
+ uint64 bb, rbz;
- z = bn/32;
- bb = 1L << (bn%32);
+ z = bn/64;
+ bb = 1LL << (bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@@ -1118,7 +1086,8 @@ paint3(Reg *r, int bn, int32 rb, int rn)
r = r1;
}
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ rbz = ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z]));
+ if(LOAD(r) & rbz & bb)
addmove(r, bn, rn, 0);
for(;;) {
r->act.b[z] |= bb;
@@ -1175,7 +1144,7 @@ addreg(Adr *a, int rn)
ostats.ncvtreg++;
}
-int32
+uint32
RtoB(int r)
{
@@ -1185,7 +1154,7 @@ RtoB(int r)
}
int
-BtoR(int32 b)
+BtoR(uint32 b)
{
b &= 0xffL;
@@ -1194,7 +1163,7 @@ BtoR(int32 b)
return bitno(b) + D_AX;
}
-int32
+uint32
FtoB(int f)
{
if(f < D_X0 || f > D_X7)
@@ -1203,7 +1172,7 @@ FtoB(int f)
}
int
-BtoF(int32 b)
+BtoF(uint32 b)
{
b &= 0xFF00L;
if(b == 0)
@@ -1273,12 +1242,14 @@ dumpit(char *str, Flow *r0, int isreg)
print(" %.4ud", (int)r1->prog->pc);
print("\n");
}
-// r1 = r->s1;
-// if(r1 != nil) {
-// print(" succ:");
-// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", (int)r1->prog->pc);
-// print("\n");
-// }
+ // Print successors if it's not just the next one
+ if(r->s1 != r->link || r->s2 != nil) {
+ print(" succ:");
+ if(r->s1 != nil)
+ print(" %.4ud", (int)r->s1->prog->pc);
+ if(r->s2 != nil)
+ print(" %.4ud", (int)r->s2->prog->pc);
+ print("\n");
+ }
}
}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index ed54f6744..596c5f61a 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -654,6 +654,8 @@ enum
D_CONST2 = D_INDIR+D_INDIR,
+ D_LAST,
+
T_TYPE = 1<<0,
T_INDEX = 1<<1,
T_OFFSET = 1<<2,
diff --git a/src/cmd/cc/Makefile b/src/cmd/9a/Makefile
index 34df31d6f..27290ddd7 100644
--- a/src/cmd/cc/Makefile
+++ b/src/cmd/9a/Makefile
@@ -1,4 +1,4 @@
-# Copyright 2012 The Go Authors. All rights reserved.
+# Copyright 2012 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.
@@ -6,5 +6,5 @@ include ../../Make.dist
install: y.tab.h
-y.tab.h: cc.y
- LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y cc.y
+y.tab.h: a.y
+ LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/9a/a.h b/src/cmd/9a/a.h
new file mode 100644
index 000000000..7a01fc947
--- /dev/null
+++ b/src/cmd/9a/a.h
@@ -0,0 +1,170 @@
+// cmd/9a/a.h from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <bio.h>
+#include <link.h>
+#include "../9l/9.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#undef getc
+#undef ungetc
+#undef BUFSIZ
+
+#define getc ccgetc
+#define ungetc ccungetc
+
+typedef struct Sym Sym;
+typedef struct Io Io;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 8192
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#ifndef EOF
+#define EOF (-1)
+#endif
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ char* macro;
+ vlong value;
+ ushort type;
+ char *name;
+ char* labelname;
+ char sym;
+};
+#define S ((Sym*)0)
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+};
+
+EXTERN int debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char** Dlist;
+EXTERN int nDlist;
+EXTERN int newflag;
+EXTERN char* hunk;
+EXTERN char** include;
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN int32 lineno;
+EXTERN int nerrors;
+EXTERN int32 nhunk;
+EXTERN int nosched;
+EXTERN int ninclude;
+EXTERN int32 nsymb;
+EXTERN Addr nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN int32 pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char* symb;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN int32 thunk;
+EXTERN Biobuf obuf;
+EXTERN Link* ctxt;
+EXTERN Biobuf bstdout;
+
+void* alloc(int32);
+void* allocn(void*, int32, int32);
+void ensuresymb(int32);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+Sym* labellookup(Sym*);
+void settext(LSym*);
+void syminit(Sym*);
+int32 yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+void outcode(int, Addr*, int, Addr*);
+void outgcode(int, Addr*, int, Addr*, Addr*);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void macprag(void);
+void maclin(void);
+void macif(int);
+void macend(void);
+void dodefine(char*);
+void prfile(int32);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
diff --git a/src/cmd/9a/a.y b/src/cmd/9a/a.y
new file mode 100644
index 000000000..b36614615
--- /dev/null
+++ b/src/cmd/9a/a.y
@@ -0,0 +1,991 @@
+// cmd/9a/a.y from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+%{
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+#include "../../runtime/funcdata.h"
+%}
+%union
+{
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Addr addr;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%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> LCONST LSP LSB LFP LPC LCREG LFLUSH
+%token <lval> LREG LFREG LR LCR LF LFPSCR
+%token <lval> LLR LCTR LSPR LSPREG LSEG LMSR
+%token <lval> LPCDAT LFUNCDAT LSCHED LXLD LXST LXOP LXMV
+%token <lval> LRLWM LMOVMW LMOVEM LMOVFL LMTFSB LMA
+%token <dval> LFCONST
+%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
+%%
+prog:
+| prog line
+
+line:
+ LNAME ':'
+ {
+ $1 = labellookup($1);
+ if($1->type == LLAB && $1->value != pc)
+ yyerror("redeclaration of %s", $1->labelname);
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| LNAME '=' expr ';'
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr ';'
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LSCHED ';'
+ {
+ nosched = $1;
+ }
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+/*
+ * load ints and bytes
+ */
+ LMOVW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * load floats
+ */
+| LFMOV addr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV regaddr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV fimm ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * store ints and bytes
+ */
+| LMOVW rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * store floats
+ */
+| LMOVW freg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW freg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * floating point status
+ */
+| LMOVW fpscr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW freg ',' fpscr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW freg ',' imm ',' fpscr
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LMOVW fpscr ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW imm ',' fpscrf
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMTFSB imm ',' con
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+/*
+ * field moves (mtcrf)
+ */
+| LMOVW rreg ',' imm ',' lcr
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LMOVW rreg ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' lcr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * integer operations
+ * logical instructions
+ * shift instructions
+ * unary instructions
+ */
+| LADDW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LADDW imm ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LADDW rreg ',' imm ',' rreg
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LADDW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LADDW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LLOGW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LLOGW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LSHW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LSHW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LSHW imm ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LSHW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LABS rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LABS rreg
+ {
+ outcode($1, &$2, NREG, &$2);
+ }
+/*
+ * multiply-accumulate
+ */
+| LMA rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * move immediate: macro for cau+or, addi, addis, and other combinations
+ */
+| LMOVW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW ximm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * condition register operations
+ */
+| LCROP cbit ',' cbit
+ {
+ outcode($1, &$2, $4.reg, &$4);
+ }
+| LCROP cbit ',' con ',' cbit
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * condition register moves
+ * move from machine state register
+ */
+| LMOVW creg ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW psr ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW lcr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW psr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW xlreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' xlreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW creg ',' psr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' psr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * branch, branch conditional
+ * branch conditional register
+ * branch conditional to count register
+ */
+| LBRA rel
+ {
+ outcode($1, &nullgen, NREG, &$2);
+ }
+| LBRA addr
+ {
+ outcode($1, &nullgen, NREG, &$2);
+ }
+| LBRA '(' xlreg ')'
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LBRA ',' rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LBRA ',' addr
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LBRA ',' '(' xlreg ')'
+ {
+ outcode($1, &nullgen, NREG, &$4);
+ }
+| LBRA creg ',' rel
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LBRA creg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LBRA creg ',' '(' xlreg ')'
+ {
+ outcode($1, &$2, NREG, &$5);
+ }
+| LBRA con ',' rel
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+| LBRA con ',' addr
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+| LBRA con ',' '(' xlreg ')'
+ {
+ outcode($1, &nullgen, $2, &$5);
+ }
+| LBRA con ',' con ',' rel
+ {
+ Addr g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $2;
+ outcode($1, &g, $4, &$6);
+ }
+| LBRA con ',' con ',' addr
+ {
+ Addr g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $2;
+ outcode($1, &g, $4, &$6);
+ }
+| LBRA con ',' con ',' '(' xlreg ')'
+ {
+ Addr g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $2;
+ outcode($1, &g, $4, &$7);
+ }
+/*
+ * conditional trap
+ */
+| LTRAP rreg ',' sreg
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTRAP imm ',' sreg
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTRAP rreg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LTRAP comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * floating point operate
+ */
+| LFCONV freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFADD freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFADD freg ',' freg ',' freg
+ {
+ outcode($1, &$2, $4.reg, &$6);
+ }
+| LFMA freg ',' freg ',' freg ',' freg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LFCMP freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFCMP freg ',' freg ',' creg
+ {
+ outcode($1, &$2, $6.reg, &$4);
+ }
+/*
+ * CMP
+ */
+| LCMP rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LCMP rreg ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LCMP rreg ',' rreg ',' creg
+ {
+ outcode($1, &$2, $6.reg, &$4);
+ }
+| LCMP rreg ',' imm ',' creg
+ {
+ outcode($1, &$2, $6.reg, &$4);
+ }
+/*
+ * rotate and mask
+ */
+| LRLWM imm ',' rreg ',' imm ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LRLWM imm ',' rreg ',' mask ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LRLWM rreg ',' rreg ',' imm ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LRLWM rreg ',' rreg ',' mask ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+/*
+ * load/store multiple
+ */
+| LMOVMW addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVMW rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * various indexed load/store
+ * indexed unary (eg, cache clear)
+ */
+| LXLD regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXLD regaddr ',' imm ',' rreg
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LXST rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXST rreg ',' imm ',' regaddr
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LXMV regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXMV rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXOP regaddr
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * NOP
+ */
+| LNOP comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LNOP rreg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LNOP freg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LNOP ',' rreg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LNOP ',' freg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LNOP imm /* SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards. */
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * word
+ */
+| LWORD imm comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LWORD ximm comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * PCDATA
+ */
+| LPCDAT imm ',' imm
+ {
+ if($2.type != D_CONST || $4.type != D_CONST)
+ yyerror("arguments to PCDATA must be integer constants");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * FUNCDATA
+ */
+| LFUNCDAT imm ',' addr
+ {
+ if($2.type != D_CONST)
+ yyerror("index for FUNCDATA must be integer constant");
+ if($4.type != D_EXTERN && $4.type != D_STATIC && $4.type != D_OREG)
+ yyerror("value for FUNCDATA must be symbol reference");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * END
+ */
+| LEND comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * TEXT/GLOBL
+ */
+| LTEXT name ',' imm
+ {
+ settext($2.sym);
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTEXT name ',' con ',' imm
+ {
+ settext($2.sym);
+ $6.offset &= 0xffffffffull;
+ $6.offset |= (vlong)ArgsSizeUnknown << 32;
+ outcode($1, &$2, $4, &$6);
+ }
+| LTEXT name ',' con ',' imm '-' con
+ {
+ settext($2.sym);
+ $6.offset &= 0xffffffffull;
+ $6.offset |= ($8 & 0xffffffffull) << 32;
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * DATA
+ */
+| LDATA name '/' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LDATA name '/' con ',' ximm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LDATA name '/' con ',' fimm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * RETURN
+ */
+| LRETRN comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $1 = labellookup($1);
+ $$ = nullgen;
+ if(pass == 2 && $1->type != LLAB)
+ yyerror("undefined label: %s", $1->labelname);
+ $$.type = D_BRANCH;
+ $$.offset = $1->value + $2;
+ }
+
+rreg:
+ sreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+xlreg:
+ lr
+| ctr
+
+lr:
+ LLR
+ {
+ $$ = nullgen;
+ $$.type = D_SPR;
+ $$.offset = $1;
+ }
+
+lcr:
+ LCR
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = NREG; /* whole register */
+ }
+
+ctr:
+ LCTR
+ {
+ $$ = nullgen;
+ $$.type = D_SPR;
+ $$.offset = $1;
+ }
+
+msr:
+ LMSR
+ {
+ $$ = nullgen;
+ $$.type = D_MSR;
+ }
+
+psr:
+ LSPREG
+ {
+ $$ = nullgen;
+ $$.type = D_SPR;
+ $$.offset = $1;
+ }
+| LSPR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ $$.offset = $3;
+ }
+| msr
+
+fpscr:
+ LFPSCR
+ {
+ $$ = nullgen;
+ $$.type = D_FPSCR;
+ $$.reg = NREG;
+ }
+
+fpscrf:
+ LFPSCR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FPSCR;
+ $$.reg = $3;
+ }
+
+freg:
+ LFREG
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+| LF '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $3;
+ }
+
+creg:
+ LCREG
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = $1;
+ }
+| LCR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = $3;
+ }
+
+
+cbit: con
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+mask:
+ con ',' con
+ {
+ int mb, me;
+ uint32 v;
+
+ $$ = nullgen;
+ $$.type = D_CONST;
+ mb = $1;
+ me = $3;
+ if(mb < 0 || mb > 31 || me < 0 || me > 31){
+ yyerror("illegal mask start/end value(s)");
+ mb = me = 0;
+ }
+ if(mb <= me)
+ v = ((uint32)~0L>>mb) & (~0L<<(31-me));
+ else
+ v = ~(((uint32)~0L>>(me+1)) & (~0L<<(31-(mb-1))));
+ $$.offset = v;
+ }
+
+ximm:
+ '$' addr
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.u.sval, $2, sizeof($$.u.sval));
+ }
+
+fimm:
+ '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.u.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.u.dval = -$3;
+ }
+
+imm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+sreg:
+ LREG
+| LR '(' con ')'
+ {
+ if($$ < 0 || $$ >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+regaddr:
+ '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+| '(' sreg '+' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.scale = $4;
+ $$.offset = 0;
+ }
+
+addr:
+ name
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+name:
+ con '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $3;
+ $$.sym = nil;
+ $$.offset = $1;
+ }
+| LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $4;
+ $$.sym = linklookup(ctxt, $1->name, 0);
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = D_STATIC;
+ $$.sym = linklookup(ctxt, $1->name, 0);
+ $$.offset = $4;
+ }
+
+comma:
+| ','
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/src/cmd/9a/doc.go b/src/cmd/9a/doc.go
new file mode 100644
index 000000000..44bf89dc0
--- /dev/null
+++ b/src/cmd/9a/doc.go
@@ -0,0 +1,21 @@
+// 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.
+
+// +build ignore
+
+/*
+
+9a is a version of the Plan 9 assembler. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/8a
+
+Go-specific considerations are documented at
+
+ http://golang.org/doc/asm
+
+Its target architecture is the Power64, referred to by these tools as
+power64 (big endian) or power64le (little endian).
+
+*/
+package main
diff --git a/src/cmd/9a/lex.c b/src/cmd/9a/lex.c
new file mode 100644
index 000000000..e2945ef89
--- /dev/null
+++ b/src/cmd/9a/lex.c
@@ -0,0 +1,726 @@
+// cmd/9a/lex.c from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define EXTERN
+#include <u.h>
+#include <libc.h>
+#include "a.h"
+#include "y.tab.h"
+
+enum
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+
+int
+systemtype(int sys)
+{
+#ifdef _WIN32
+ return sys&Windows;
+#else
+ return sys&Plan9;
+#endif
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+int
+Lconv(Fmt *fp)
+{
+ return linklinefmt(ctxt, fp);
+}
+
+void
+dodef(char *p)
+{
+ if(nDlist%8 == 0)
+ Dlist = allocn(Dlist, nDlist*sizeof(char *),
+ 8*sizeof(char *));
+ Dlist[nDlist++] = p;
+}
+
+LinkArch* thelinkarch = &linkpower64;
+
+void
+usage(void)
+{
+ print("usage: %ca [options] file.c...\n", thechar);
+ flagprint(1);
+ errorexit();
+}
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+
+ thechar = '9';
+ thestring = "power64";
+
+ // Allow GOARCH=thestring or GOARCH=thestringsuffix,
+ // but not other values.
+ p = getgoarch();
+ if(strncmp(p, thestring, strlen(thestring)) != 0)
+ sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
+ if(strcmp(p, "power64le") == 0)
+ thelinkarch = &linkpower64le;
+
+ ctxt = linknew(thelinkarch);
+ ctxt->diag = yyerror;
+ ctxt->bso = &bstdout;
+ ctxt->enforce_data_order = 1;
+ Binit(&bstdout, 1, OWRITE);
+ listinit9();
+ fmtinstall('L', Lconv);
+
+ ensuresymb(NSYMB);
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ setinclude(".");
+
+ flagfn1("D", "name[=value]: add #define", dodef);
+ flagfn1("I", "dir: add dir to include path", setinclude);
+ flagcount("S", "print assembly and machine code", &debug['S']);
+ flagcount("m", "debug preprocessor macros", &debug['m']);
+ flagstr("o", "file: set output file", &outfile);
+ flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
+
+ flagparse(&argc, &argv, usage);
+ ctxt->debugasm = debug['S'];
+
+ if(argc < 1)
+ usage();
+ if(argc > 1){
+ print("can't assemble multiple files\n");
+ errorexit();
+ }
+
+ if(assemble(argv[0]))
+ errorexit();
+ Bflush(&bstdout);
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char *ofile, *p;
+ int i, of;
+
+ ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+
+ of = create(outfile, OWRITE, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+ Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
+ Bprint(&obuf, "!\n");
+
+ for(pass = 1; pass <= 2; pass++) {
+ nosched = 0;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ if(nerrors)
+ return nerrors;
+ }
+
+ writeobj(ctxt, &obuf);
+ Bflush(&obuf);
+ return 0;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ 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,
+
+ "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,
+
+ "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,
+
+ "CREQV", LCROP, ACREQV,
+ "CRXOR", LCROP, ACRXOR,
+ "CRAND", LCROP, ACRAND,
+ "CROR", LCROP, ACROR,
+ "CRANDN", LCROP, ACRANDN,
+ "CRORN", LCROP, ACRORN,
+ "CRNAND", LCROP, ACRNAND,
+ "CRNOR", LCROP, ACRNOR,
+
+ "ADD", LADDW, AADD,
+ "ADDV", LADDW, AADDV,
+ "ADDCC", LADDW, AADDCC,
+ "ADDVCC", LADDW, AADDVCC,
+ "ADDC", LADDW, AADDC,
+ "ADDCV", LADDW, AADDCV,
+ "ADDCCC", LADDW, AADDCCC,
+ "ADDCVCC", LADDW, AADDCVCC,
+ "ADDE", LLOGW, AADDE,
+ "ADDEV", LLOGW, AADDEV,
+ "ADDECC", LLOGW, AADDECC,
+ "ADDEVCC", LLOGW, AADDEVCC,
+
+ "ADDME", LABS, AADDME,
+ "ADDMEV", LABS, AADDMEV,
+ "ADDMECC", LABS, AADDMECC,
+ "ADDMEVCC", LABS, AADDMEVCC,
+ "ADDZE", LABS, AADDZE,
+ "ADDZEV", LABS, AADDZEV,
+ "ADDZECC", LABS, AADDZECC,
+ "ADDZEVCC", LABS, AADDZEVCC,
+
+ "SUB", LADDW, ASUB,
+ "SUBV", LADDW, ASUBV,
+ "SUBCC", LADDW, ASUBCC,
+ "SUBVCC", LADDW, ASUBVCC,
+ "SUBE", LLOGW, ASUBE,
+ "SUBECC", LLOGW, ASUBECC,
+ "SUBEV", LLOGW, ASUBEV,
+ "SUBEVCC", LLOGW, ASUBEVCC,
+ "SUBC", LADDW, ASUBC,
+ "SUBCCC", LADDW, ASUBCCC,
+ "SUBCV", LADDW, ASUBCV,
+ "SUBCVCC", LADDW, ASUBCVCC,
+
+ "SUBME", LABS, ASUBME,
+ "SUBMEV", LABS, ASUBMEV,
+ "SUBMECC", LABS, ASUBMECC,
+ "SUBMEVCC", LABS, ASUBMEVCC,
+ "SUBZE", LABS, ASUBZE,
+ "SUBZEV", LABS, ASUBZEV,
+ "SUBZECC", LABS, ASUBZECC,
+ "SUBZEVCC", LABS, ASUBZEVCC,
+
+ "AND", LADDW, AAND,
+ "ANDCC", LADDW, AANDCC, /* includes andil & andiu */
+ "ANDN", LLOGW, AANDN,
+ "ANDNCC", LLOGW, AANDNCC,
+ "EQV", LLOGW, AEQV,
+ "EQVCC", LLOGW, AEQVCC,
+ "NAND", LLOGW, ANAND,
+ "NANDCC", LLOGW, ANANDCC,
+ "NOR", LLOGW, ANOR,
+ "NORCC", LLOGW, ANORCC,
+ "OR", LADDW, AOR, /* includes oril & oriu */
+ "ORCC", LADDW, AORCC,
+ "ORN", LLOGW, AORN,
+ "ORNCC", LLOGW, AORNCC,
+ "XOR", LADDW, AXOR, /* includes xoril & xoriu */
+ "XORCC", LLOGW, AXORCC,
+
+ "EXTSB", LABS, AEXTSB,
+ "EXTSBCC", LABS, AEXTSBCC,
+ "EXTSH", LABS, AEXTSH,
+ "EXTSHCC", LABS, AEXTSHCC,
+
+ "CNTLZW", LABS, ACNTLZW,
+ "CNTLZWCC", LABS, ACNTLZWCC,
+
+ "RLWMI", LRLWM, ARLWMI,
+ "RLWMICC", LRLWM, ARLWMICC,
+ "RLWNM", LRLWM, ARLWNM,
+ "RLWNMCC", LRLWM, ARLWNMCC,
+
+ "SLW", LSHW, ASLW,
+ "SLWCC", LSHW, ASLWCC,
+ "SRW", LSHW, ASRW,
+ "SRWCC", LSHW, ASRWCC,
+ "SRAW", LSHW, ASRAW,
+ "SRAWCC", LSHW, ASRAWCC,
+
+ "BR", LBRA, ABR,
+ "BC", LBRA, ABC,
+ "BCL", LBRA, ABC,
+ "BL", LBRA, ABL,
+ "BEQ", LBRA, ABEQ,
+ "BNE", LBRA, ABNE,
+ "BGT", LBRA, ABGT,
+ "BGE", LBRA, ABGE,
+ "BLT", LBRA, ABLT,
+ "BLE", LBRA, ABLE,
+ "BVC", LBRA, ABVC,
+ "BVS", LBRA, ABVS,
+
+ "CMP", LCMP, ACMP,
+ "CMPU", LCMP, ACMPU,
+ "CMPW", LCMP, ACMPW,
+ "CMPWU", LCMP, ACMPWU,
+
+ "DIVW", LLOGW, ADIVW,
+ "DIVWV", LLOGW, ADIVWV,
+ "DIVWCC", LLOGW, ADIVWCC,
+ "DIVWVCC", LLOGW, ADIVWVCC,
+ "DIVWU", LLOGW, ADIVWU,
+ "DIVWUV", LLOGW, ADIVWUV,
+ "DIVWUCC", LLOGW, ADIVWUCC,
+ "DIVWUVCC", LLOGW, ADIVWUVCC,
+
+ "FABS", LFCONV, AFABS,
+ "FABSCC", LFCONV, AFABSCC,
+ "FNEG", LFCONV, AFNEG,
+ "FNEGCC", LFCONV, AFNEGCC,
+ "FNABS", LFCONV, AFNABS,
+ "FNABSCC", LFCONV, AFNABSCC,
+
+ "FADD", LFADD, AFADD,
+ "FADDCC", LFADD, AFADDCC,
+ "FSUB", LFADD, AFSUB,
+ "FSUBCC", LFADD, AFSUBCC,
+ "FMUL", LFADD, AFMUL,
+ "FMULCC", LFADD, AFMULCC,
+ "FDIV", LFADD, AFDIV,
+ "FDIVCC", LFADD, AFDIVCC,
+ "FRSP", LFCONV, AFRSP,
+ "FRSPCC", LFCONV, AFRSPCC,
+ "FCTIW", LFCONV, AFCTIW,
+ "FCTIWCC", LFCONV, AFCTIWCC,
+ "FCTIWZ", LFCONV, AFCTIWZ,
+ "FCTIWZCC", LFCONV, AFCTIWZCC,
+
+ "FMADD", LFMA, AFMADD,
+ "FMADDCC", LFMA, AFMADDCC,
+ "FMSUB", LFMA, AFMSUB,
+ "FMSUBCC", LFMA, AFMSUBCC,
+ "FNMADD", LFMA, AFNMADD,
+ "FNMADDCC", LFMA, AFNMADDCC,
+ "FNMSUB", LFMA, AFNMSUB,
+ "FNMSUBCC", LFMA, AFNMSUBCC,
+ "FMADDS", LFMA, AFMADDS,
+ "FMADDSCC", LFMA, AFMADDSCC,
+ "FMSUBS", LFMA, AFMSUBS,
+ "FMSUBSCC", LFMA, AFMSUBSCC,
+ "FNMADDS", LFMA, AFNMADDS,
+ "FNMADDSCC", LFMA, AFNMADDSCC,
+ "FNMSUBS", LFMA, AFNMSUBS,
+ "FNMSUBSCC", LFMA, AFNMSUBSCC,
+
+ "FCMPU", LFCMP, AFCMPU,
+ "FCMPO", LFCMP, AFCMPO,
+ "MTFSB0", LMTFSB, AMTFSB0,
+ "MTFSB1", LMTFSB, AMTFSB1,
+
+ "FMOVD", LFMOV, AFMOVD,
+ "FMOVS", LFMOV, AFMOVS,
+ "FMOVDCC", LFCONV, AFMOVDCC, /* fmr. */
+
+ "GLOBL", LTEXT, AGLOBL,
+
+ "MOVB", LMOVB, AMOVB,
+ "MOVBZ", LMOVB, AMOVBZ,
+ "MOVBU", LMOVB, AMOVBU,
+ "MOVBZU", LMOVB, AMOVBZU,
+ "MOVH", LMOVB, AMOVH,
+ "MOVHZ", LMOVB, AMOVHZ,
+ "MOVHU", LMOVB, AMOVHU,
+ "MOVHZU", LMOVB, AMOVHZU,
+ "MOVHBR", LXMV, AMOVHBR,
+ "MOVWBR", LXMV, AMOVWBR,
+ "MOVW", LMOVW, AMOVW,
+ "MOVWU", LMOVW, AMOVWU,
+ "MOVMW", LMOVMW, AMOVMW,
+ "MOVFL", LMOVW, AMOVFL,
+
+ "MULLW", LADDW, AMULLW, /* includes multiply immediate 10-139 */
+ "MULLWV", LLOGW, AMULLWV,
+ "MULLWCC", LLOGW, AMULLWCC,
+ "MULLWVCC", LLOGW, AMULLWVCC,
+
+ "MULHW", LLOGW, AMULHW,
+ "MULHWCC", LLOGW, AMULHWCC,
+ "MULHWU", LLOGW, AMULHWU,
+ "MULHWUCC", LLOGW, AMULHWUCC,
+
+ "NEG", LABS, ANEG,
+ "NEGV", LABS, ANEGV,
+ "NEGCC", LABS, ANEGCC,
+ "NEGVCC", LABS, ANEGVCC,
+
+ "NOP", LNOP, ANOP, /* ori 0,0,0 */
+ "SYSCALL", LNOP, ASYSCALL,
+ "UNDEF", LNOP, AUNDEF,
+
+ "RET", LRETRN, ARETURN,
+ "RETURN", LRETRN, ARETURN,
+ "RFI", LRETRN, ARFI,
+ "RFCI", LRETRN, ARFCI,
+
+ "DATA", LDATA, ADATA,
+ "END", LEND, AEND,
+ "TEXT", LTEXT, ATEXT,
+
+ /* 64-bit instructions */
+ "CNTLZD", LABS, ACNTLZD,
+ "CNTLZDCC", LABS, ACNTLZDCC,
+ "DIVD", LLOGW, ADIVD,
+ "DIVDCC", LLOGW, ADIVDCC,
+ "DIVDVCC", LLOGW, ADIVDVCC,
+ "DIVDV", LLOGW, ADIVDV,
+ "DIVDU", LLOGW, ADIVDU,
+ "DIVDUCC", LLOGW, ADIVDUCC,
+ "DIVDUVCC", LLOGW, ADIVDUVCC,
+ "DIVDUV", LLOGW, ADIVDUV,
+ "EXTSW", LABS, AEXTSW,
+ "EXTSWCC", LABS, AEXTSWCC,
+ "FCTID", LFCONV, AFCTID,
+ "FCTIDCC", LFCONV, AFCTIDCC,
+ "FCTIDZ", LFCONV, AFCTIDZ,
+ "FCTIDZCC", LFCONV, AFCTIDZCC,
+ "FCFID", LFCONV, AFCFID,
+ "FCFIDCC", LFCONV, AFCFIDCC,
+ "LDAR", LXLD, ALDAR,
+ "MOVD", LMOVW, AMOVD,
+ "MOVDU", LMOVW, AMOVDU,
+ "MOVWZ", LMOVW, AMOVWZ,
+ "MOVWZU", LMOVW, AMOVWZU,
+ "MULHD", LLOGW, AMULHD,
+ "MULHDCC", LLOGW, AMULHDCC,
+ "MULHDU", LLOGW, AMULHDU,
+ "MULHDUCC", LLOGW, AMULHDUCC,
+ "MULLD", LADDW, AMULLD, /* includes multiply immediate? */
+ "MULLDCC", LLOGW, AMULLDCC,
+ "MULLDVCC", LLOGW, AMULLDVCC,
+ "MULLDV", LLOGW, AMULLDV,
+ "RFID", LRETRN, ARFID,
+ "HRFID", LRETRN, AHRFID,
+ "RLDMI", LRLWM, ARLDMI,
+ "RLDMICC", LRLWM, ARLDMICC,
+ "RLDC", LRLWM, ARLDC,
+ "RLDCCC", LRLWM, ARLDCCC,
+ "RLDCR", LRLWM, ARLDCR,
+ "RLDCRCC", LRLWM, ARLDCRCC,
+ "RLDCL", LRLWM, ARLDCL,
+ "RLDCLCC", LRLWM, ARLDCLCC,
+ "SLBIA", LNOP, ASLBIA,
+ "SLBIE", LNOP, ASLBIE,
+ "SLBMFEE", LABS, ASLBMFEE,
+ "SLBMFEV", LABS, ASLBMFEV,
+ "SLBMTE", LABS, ASLBMTE,
+ "SLD", LSHW, ASLD,
+ "SLDCC", LSHW, ASLDCC,
+ "SRD", LSHW, ASRD,
+ "SRAD", LSHW, ASRAD,
+ "SRADCC", LSHW, ASRADCC,
+ "SRDCC", LSHW, ASRDCC,
+ "STDCCC", LXST, ASTDCCC,
+ "TD", LADDW, ATD,
+
+ /* pseudo instructions */
+ "REM", LLOGW, AREM,
+ "REMCC", LLOGW, AREMCC,
+ "REMV", LLOGW, AREMV,
+ "REMVCC", LLOGW, AREMVCC,
+ "REMU", LLOGW, AREMU,
+ "REMUCC", LLOGW, AREMUCC,
+ "REMUV", LLOGW, AREMUV,
+ "REMUVCC", LLOGW, AREMUVCC,
+ "REMD", LLOGW, AREMD,
+ "REMDCC", LLOGW, AREMDCC,
+ "REMDV", LLOGW, AREMDV,
+ "REMDVCC", LLOGW, AREMDVCC,
+ "REMDU", LLOGW, AREMDU,
+ "REMDUCC", LLOGW, AREMDUCC,
+ "REMDUV", LLOGW, AREMDUV,
+ "REMDUVCC", LLOGW, AREMDUVCC,
+
+/* special instructions */
+ "DCBF", LXOP, ADCBF,
+ "DCBI", LXOP, ADCBI,
+ "DCBST", LXOP, ADCBST,
+ "DCBT", LXOP, ADCBT,
+ "DCBTST", LXOP, ADCBTST,
+ "DCBZ", LXOP, ADCBZ,
+ "ICBI", LXOP, AICBI,
+
+ "ECIWX", LXLD, AECIWX,
+ "ECOWX", LXST, AECOWX,
+ "LWAR", LXLD, ALWAR,
+ "LWAR", LXLD, ALWAR,
+ "STWCCC", LXST, ASTWCCC,
+ "EIEIO", LRETRN, AEIEIO,
+ "TLBIE", LNOP, ATLBIE,
+ "TLBIEL", LNOP, ATLBIEL,
+ "LSW", LXLD, ALSW,
+ "STSW", LXST, ASTSW,
+
+ "ISYNC", LRETRN, AISYNC,
+ "SYNC", LRETRN, ASYNC,
+ "TLBSYNC", LRETRN, ATLBSYNC,
+ "PTESYNC", LRETRN, APTESYNC,
+/* "TW", LADDW, ATW,*/
+
+ "WORD", LWORD, AWORD,
+ "DWORD", LWORD, ADWORD,
+ "SCHED", LSCHED, 0,
+ "NOSCHED", LSCHED, 0x80,
+
+ "PCDATA", LPCDAT, APCDATA,
+ "FUNCDATA", LFUNCDAT, AFUNCDATA,
+
+ 0
+};
+
+void
+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
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+void
+cclean(void)
+{
+
+ outcode(AEND, &nullgen, NREG, &nullgen);
+}
+
+static Prog *lastpc;
+
+void
+outcode(int a, Addr *g1, int reg, Addr *g2)
+{
+ Prog *p;
+ Plist *pl;
+
+ if(pass == 1)
+ goto out;
+
+ if(g1->scale != NREG) {
+ if(reg != NREG || g2->scale != NREG)
+ yyerror("bad addressing modes");
+ reg = g1->scale;
+ } else
+ if(g2->scale != NREG) {
+ if(reg != NREG)
+ yyerror("bad addressing modes");
+ reg = g2->scale;
+ }
+
+ p = ctxt->arch->prg();
+ p->as = a;
+ p->lineno = lineno;
+ if(nosched)
+ p->mark |= NOSCHED;
+ p->from = *g1;
+ p->reg = reg;
+ p->to = *g2;
+ p->pc = pc;
+
+ if(lastpc == nil) {
+ pl = linknewplist(ctxt);
+ pl->firstpc = p;
+ } else
+ lastpc->link = p;
+ lastpc = p;
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outgcode(int a, Addr *g1, int reg, Addr *g2, Addr *g3)
+{
+ Prog *p;
+ Plist *pl;
+
+ if(pass == 1)
+ goto out;
+
+ p = ctxt->arch->prg();
+ p->as = a;
+ p->lineno = lineno;
+ if(nosched)
+ p->mark |= NOSCHED;
+ p->from = *g1;
+ p->reg = reg;
+ p->from3 = *g2;
+ p->to = *g3;
+ p->pc = pc;
+
+ if(lastpc == nil) {
+ pl = linknewplist(ctxt);
+ pl->firstpc = p;
+ } else
+ lastpc->link = p;
+ lastpc = p;
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/src/cmd/9a/y.tab.c b/src/cmd/9a/y.tab.c
new file mode 100644
index 000000000..6025a2402
--- /dev/null
+++ b/src/cmd/9a/y.tab.c
@@ -0,0 +1,3398 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LMOVW = 258,
+ LMOVB = 259,
+ LABS = 260,
+ LLOGW = 261,
+ LSHW = 262,
+ LADDW = 263,
+ LCMP = 264,
+ LCROP = 265,
+ LBRA = 266,
+ LFMOV = 267,
+ LFCONV = 268,
+ LFCMP = 269,
+ LFADD = 270,
+ LFMA = 271,
+ LTRAP = 272,
+ LXORW = 273,
+ LNOP = 274,
+ LEND = 275,
+ 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
+ };
+#endif
+/* Tokens. */
+#define LMOVW 258
+#define LMOVB 259
+#define LABS 260
+#define LLOGW 261
+#define LSHW 262
+#define LADDW 263
+#define LCMP 264
+#define LCROP 265
+#define LBRA 266
+#define LFMOV 267
+#define LFCONV 268
+#define LFCMP 269
+#define LFADD 270
+#define LFMA 271
+#define LTRAP 272
+#define LXORW 273
+#define LNOP 274
+#define LEND 275
+#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
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 30 "a.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+#include "../../runtime/funcdata.h"
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 38 "a.y"
+{
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Addr addr;
+}
+/* Line 193 of yacc.c. */
+#line 236 "y.tab.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 249 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 862
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 81
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 31
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 183
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 453
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 317
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+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, 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, 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, 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, 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, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 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, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+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
+};
+
+/* 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
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+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,
+ 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
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
+ "'-'", "'*'", "'/'", "'%'", "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
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 124, 94, 38, 60, 62, 43, 45,
+ 42, 47, 37, 258, 259, 260, 261, 262, 263, 264,
+ 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, 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
+};
+# 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
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+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
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+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, 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, 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
+};
+
+/* 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
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -176
+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
+};
+
+/* 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
+};
+
+/* 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 -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,
+ 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
+};
+
+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,
+ 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
+};
+
+/* 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,
+ 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
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 71 "a.y"
+ {
+ (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
+ if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc)
+ yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->labelname);
+ (yyvsp[(1) - (2)].sym)->type = LLAB;
+ (yyvsp[(1) - (2)].sym)->value = pc;
+ }
+ break;
+
+ case 6:
+#line 80 "a.y"
+ {
+ (yyvsp[(1) - (4)].sym)->type = LVAR;
+ (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 7:
+#line 85 "a.y"
+ {
+ if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval))
+ yyerror("redeclaration of %s", (yyvsp[(1) - (4)].sym)->name);
+ (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 8:
+#line 91 "a.y"
+ {
+ nosched = (yyvsp[(1) - (2)].lval);
+ }
+ break;
+
+ case 12:
+#line 103 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 14:
+#line 111 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 16:
+#line 119 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 18:
+#line 130 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 20:
+#line 138 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 22:
+#line 146 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 24:
+#line 157 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 26:
+#line 165 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 28:
+#line 176 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 30:
+#line 187 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ 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));
+ }
+ break;
+
+ case 33:
+#line 199 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 35:
+#line 207 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
+ }
+ 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));
+ }
+ break;
+
+ case 37:
+#line 218 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 38:
+#line 222 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 39:
+#line 232 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 40:
+#line 236 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(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));
+ }
+ break;
+
+ case 42:
+#line 244 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 44:
+#line 252 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 45:
+#line 256 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].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));
+ }
+ break;
+
+ case 47:
+#line 264 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].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));
+ }
+ break;
+
+ case 49:
+#line 272 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 51:
+#line 280 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), NREG, &(yyvsp[(2) - (2)].addr));
+ }
+ break;
+
+ case 52:
+#line 287 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 53:
+#line 294 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 54:
+#line 298 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 56:
+#line 309 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 57:
+#line 317 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 59:
+#line 325 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 61:
+#line 333 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 63:
+#line 341 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 64:
+#line 345 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 65:
+#line 354 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &(yyvsp[(2) - (2)].addr));
+ }
+ break;
+
+ case 66:
+#line 358 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &(yyvsp[(2) - (2)].addr));
+ }
+ break;
+
+ case 67:
+#line 362 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &nullgen, NREG, &(yyvsp[(3) - (4)].addr));
+ }
+ break;
+
+ case 68:
+#line 366 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+ }
+ break;
+
+ case 69:
+#line 370 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+ }
+ break;
+
+ case 70:
+#line 374 "a.y"
+ {
+ outcode((yyvsp[(1) - (5)].lval), &nullgen, NREG, &(yyvsp[(4) - (5)].addr));
+ }
+ break;
+
+ case 71:
+#line 378 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 73:
+#line 386 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(5) - (6)].addr));
+ }
+ break;
+
+ case 74:
+#line 390 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &nullgen, (yyvsp[(2) - (4)].lval), &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 75:
+#line 394 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &nullgen, (yyvsp[(2) - (4)].lval), &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 76:
+#line 398 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &nullgen, (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr));
+ }
+ break;
+
+ case 77:
+#line 402 "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));
+ }
+ break;
+
+ case 78:
+#line 410 "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));
+ }
+ break;
+
+ case 79:
+#line 418 "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));
+ }
+ break;
+
+ case 80:
+#line 429 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
+ }
+ break;
+
+ case 81:
+#line 433 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
+ }
+ break;
+
+ case 82:
+#line 437 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 83:
+#line 441 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+ }
+ break;
+
+ case 84:
+#line 448 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ 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));
+ }
+ 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));
+ }
+ break;
+
+ case 88:
+#line 464 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 89:
+#line 468 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
+ }
+ break;
+
+ case 90:
+#line 475 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 92:
+#line 483 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
+ }
+ break;
+
+ case 93:
+#line 487 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
+ }
+ break;
+
+ case 94:
+#line 494 "a.y"
+ {
+ outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
+ }
+ break;
+
+ case 95:
+#line 498 "a.y"
+ {
+ outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
+ }
+ break;
+
+ case 96:
+#line 502 "a.y"
+ {
+ outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
+ }
+ break;
+
+ case 97:
+#line 506 "a.y"
+ {
+ outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
+ }
+ break;
+
+ case 98:
+#line 513 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 99:
+#line 517 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ 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));
+ }
+ break;
+
+ case 102:
+#line 533 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].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));
+ }
+ break;
+
+ case 104:
+#line 541 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(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));
+ }
+ break;
+
+ case 106:
+#line 549 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 107:
+#line 556 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+ }
+ break;
+
+ case 108:
+#line 560 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 109:
+#line 564 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 110:
+#line 568 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+ }
+ break;
+
+ case 111:
+#line 572 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+ }
+ break;
+
+ case 112:
+#line 576 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 113:
+#line 583 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 114:
+#line 587 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 115:
+#line 594 "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));
+ }
+ break;
+
+ case 116:
+#line 603 "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));
+ }
+ break;
+
+ case 117:
+#line 614 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+ }
+ break;
+
+ case 118:
+#line 621 "a.y"
+ {
+ settext((yyvsp[(2) - (4)].addr).sym);
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 119:
+#line 626 "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));
+ }
+ break;
+
+ case 120:
+#line 633 "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));
+ }
+ break;
+
+ case 121:
+#line 643 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 122:
+#line 647 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 123:
+#line 651 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 124:
+#line 658 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+ }
+ break;
+
+ case 125:
+#line 664 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
+ }
+ break;
+
+ case 126:
+#line 670 "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).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 127:
+#line 681 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_REG;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 130:
+#line 693 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SPR;
+ (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 131:
+#line 701 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CREG;
+ (yyval.addr).reg = NREG; /* whole register */
+ }
+ break;
+
+ case 132:
+#line 709 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SPR;
+ (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 133:
+#line 717 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_MSR;
+ }
+ break;
+
+ case 134:
+#line 724 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SPR;
+ (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 135:
+#line 730 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (4)].lval);
+ (yyval.addr).offset = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 137:
+#line 739 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FPSCR;
+ (yyval.addr).reg = NREG;
+ }
+ break;
+
+ case 138:
+#line 747 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FPSCR;
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 139:
+#line 755 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FREG;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 140:
+#line 761 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FREG;
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 141:
+#line 769 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CREG;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].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"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_REG;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 144:
+#line 791 "a.y"
+ {
+ int mb, me;
+ uint32 v;
+
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CONST;
+ mb = (yyvsp[(1) - (3)].lval);
+ me = (yyvsp[(3) - (3)].lval);
+ if(mb < 0 || mb > 31 || me < 0 || me > 31){
+ yyerror("illegal mask start/end value(s)");
+ mb = me = 0;
+ }
+ if(mb <= me)
+ v = ((uint32)~0L>>mb) & (~0L<<(31-me));
+ else
+ v = ~(((uint32)~0L>>(me+1)) & (~0L<<(31-(mb-1))));
+ (yyval.addr).offset = v;
+ }
+ break;
+
+ case 145:
+#line 812 "a.y"
+ {
+ (yyval.addr) = (yyvsp[(2) - (2)].addr);
+ (yyval.addr).type = D_CONST;
+ }
+ break;
+
+ case 146:
+#line 817 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SCONST;
+ memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
+ }
+ break;
+
+ case 147:
+#line 825 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
+ }
+ break;
+
+ case 148:
+#line 831 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
+ }
+ break;
+
+ case 149:
+#line 838 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CONST;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 151:
+#line 847 "a.y"
+ {
+ if((yyval.lval) < 0 || (yyval.lval) >= NREG)
+ print("register value out of range\n");
+ (yyval.lval) = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 152:
+#line 855 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
+ (yyval.addr).offset = 0;
+ }
+ break;
+
+ case 153:
+#line 862 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (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"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 156:
+#line 882 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (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"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (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"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).name = D_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"
+ {
+ (yyval.lval) = 0;
+ }
+ break;
+
+ case 162:
+#line 914 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 163:
+#line 918 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 168:
+#line 930 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
+ }
+ break;
+
+ case 169:
+#line 934 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 170:
+#line 938 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 171:
+#line 942 "a.y"
+ {
+ (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 172:
+#line 946 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (3)].lval);
+ }
+ break;
+
+ case 174:
+#line 953 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 175:
+#line 957 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 176:
+#line 961 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 177:
+#line 965 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 178:
+#line 969 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 179:
+#line 973 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 180:
+#line 977 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 181:
+#line 981 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 182:
+#line 985 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 183:
+#line 989 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 3185 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
diff --git a/src/cmd/9a/y.tab.h b/src/cmd/9a/y.tab.h
new file mode 100644
index 000000000..e6b93a2ec
--- /dev/null
+++ b/src/cmd/9a/y.tab.h
@@ -0,0 +1,188 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LMOVW = 258,
+ LMOVB = 259,
+ LABS = 260,
+ LLOGW = 261,
+ LSHW = 262,
+ LADDW = 263,
+ LCMP = 264,
+ LCROP = 265,
+ LBRA = 266,
+ LFMOV = 267,
+ LFCONV = 268,
+ LFCMP = 269,
+ LFADD = 270,
+ LFMA = 271,
+ LTRAP = 272,
+ LXORW = 273,
+ LNOP = 274,
+ LEND = 275,
+ 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
+ };
+#endif
+/* Tokens. */
+#define LMOVW 258
+#define LMOVB 259
+#define LABS 260
+#define LLOGW 261
+#define LSHW 262
+#define LADDW 263
+#define LCMP 264
+#define LCROP 265
+#define LBRA 266
+#define LFMOV 267
+#define LFCONV 268
+#define LFCMP 269
+#define LFADD 270
+#define LFMA 271
+#define LTRAP 272
+#define LXORW 273
+#define LNOP 274
+#define LEND 275
+#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
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 38 "a.y"
+{
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Addr addr;
+}
+/* Line 1529 of yacc.c. */
+#line 181 "y.tab.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
diff --git a/src/cmd/9g/cgen.c b/src/cmd/9g/cgen.c
new file mode 100644
index 000000000..e38936001
--- /dev/null
+++ b/src/cmd/9g/cgen.c
@@ -0,0 +1,1763 @@
+// 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.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+
+/*
+ * generate:
+ * res = n;
+ * simplifies and calls gmove.
+ */
+void
+cgen(Node *n, Node *res)
+{
+ Node *nl, *nr, *r;
+ Node n1, n2;
+ int a, f;
+ Prog *p1, *p2, *p3;
+ Addr addr;
+
+//print("cgen %N(%d) -> %N(%d)\n", n, n->addable, res, res->addable);
+ if(debug['g']) {
+ dump("\ncgen-n", n);
+ dump("cgen-res", res);
+ }
+ if(n == N || n->type == T)
+ goto ret;
+
+ if(res == N || res->type == T)
+ fatal("cgen: res nil");
+
+ while(n->op == OCONVNOP)
+ n = n->left;
+
+ switch(n->op) {
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICESTR:
+ case OSLICE3:
+ case OSLICE3ARR:
+ if (res->op != ONAME || !res->addable) {
+ tempname(&n1, n->type);
+ cgen_slice(n, &n1);
+ cgen(&n1, res);
+ } else
+ cgen_slice(n, res);
+ goto ret;
+ case OEFACE:
+ if (res->op != ONAME || !res->addable) {
+ tempname(&n1, n->type);
+ cgen_eface(n, &n1);
+ cgen(&n1, res);
+ } else
+ cgen_eface(n, res);
+ goto ret;
+ }
+
+ if(n->ullman >= UINF) {
+ if(n->op == OINDREG)
+ fatal("cgen: this is going to misscompile");
+ if(res->ullman >= UINF) {
+ tempname(&n1, n->type);
+ cgen(n, &n1);
+ cgen(&n1, res);
+ goto ret;
+ }
+ }
+
+ if(isfat(n->type)) {
+ if(n->type->width < 0)
+ fatal("forgot to compute width for %T", n->type);
+ sgen(n, res, n->type->width);
+ goto ret;
+ }
+
+ if(!res->addable) {
+ if(n->ullman > res->ullman) {
+ regalloc(&n1, n->type, res);
+ cgen(n, &n1);
+ if(n1.ullman > res->ullman) {
+ dump("n1", &n1);
+ dump("res", res);
+ fatal("loop in cgen");
+ }
+ cgen(&n1, res);
+ regfree(&n1);
+ goto ret;
+ }
+
+ if(res->ullman >= UINF)
+ goto gen;
+
+ if(complexop(n, res)) {
+ complexgen(n, res);
+ goto ret;
+ }
+
+ f = 1; // gen thru register
+ switch(n->op) {
+ case OLITERAL:
+ if(smallintconst(n))
+ f = 0;
+ break;
+ case OREGISTER:
+ f = 0;
+ break;
+ }
+
+ if(!iscomplex[n->type->etype]) {
+ a = optoas(OAS, res->type);
+ if(sudoaddable(a, res, &addr)) {
+ if(f) {
+ regalloc(&n2, res->type, N);
+ cgen(n, &n2);
+ p1 = gins(a, &n2, N);
+ regfree(&n2);
+ } else
+ p1 = gins(a, n, N);
+ p1->to = addr;
+ if(debug['g'])
+ print("%P [ignore previous line]\n", p1);
+ sudoclean();
+ goto ret;
+ }
+ }
+
+ gen:
+ igen(res, &n1, N);
+ cgen(n, &n1);
+ regfree(&n1);
+ goto ret;
+ }
+
+ // update addressability for string, slice
+ // can't do in walk because n->left->addable
+ // changes if n->left is an escaping local variable.
+ switch(n->op) {
+ case OSPTR:
+ case OLEN:
+ if(isslice(n->left->type) || istype(n->left->type, TSTRING))
+ n->addable = n->left->addable;
+ break;
+ case OCAP:
+ if(isslice(n->left->type))
+ n->addable = n->left->addable;
+ break;
+ case OITAB:
+ n->addable = n->left->addable;
+ break;
+ }
+
+ if(complexop(n, res)) {
+ complexgen(n, res);
+ goto ret;
+ }
+
+ // if both are addressable, move
+ if(n->addable) {
+ if(n->op == OREGISTER || res->op == OREGISTER) {
+ gmove(n, res);
+ } else {
+ regalloc(&n1, n->type, N);
+ gmove(n, &n1);
+ cgen(&n1, res);
+ regfree(&n1);
+ }
+ goto ret;
+ }
+
+ nl = n->left;
+ nr = n->right;
+
+ if(nl != N && nl->ullman >= UINF)
+ if(nr != N && nr->ullman >= UINF) {
+ tempname(&n1, nl->type);
+ cgen(nl, &n1);
+ n2 = *n;
+ n2.left = &n1;
+ cgen(&n2, res);
+ goto ret;
+ }
+
+ if(!iscomplex[n->type->etype]) {
+ a = optoas(OAS, n->type);
+ if(sudoaddable(a, n, &addr)) {
+ if(res->op == OREGISTER) {
+ p1 = gins(a, N, res);
+ p1->from = addr;
+ } else {
+ regalloc(&n2, n->type, N);
+ p1 = gins(a, N, &n2);
+ p1->from = addr;
+ gins(a, &n2, res);
+ regfree(&n2);
+ }
+ sudoclean();
+ goto ret;
+ }
+ }
+
+ // TODO(minux): we shouldn't reverse FP comparisons, but then we need to synthesize
+ // OGE, OLE, and ONE ourselves.
+ // if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) goto flt;
+
+ switch(n->op) {
+ default:
+ dump("cgen", n);
+ fatal("cgen: unknown op %+hN", n);
+ break;
+
+ // these call bgen to get a bool value
+ case OOROR:
+ case OANDAND:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case ONOT:
+ p1 = gbranch(ABR, T, 0);
+ p2 = pc;
+ gmove(nodbool(1), res);
+ p3 = gbranch(ABR, T, 0);
+ patch(p1, pc);
+ bgen(n, 1, 0, p2);
+ gmove(nodbool(0), res);
+ patch(p3, pc);
+ goto ret;
+
+ case OPLUS:
+ cgen(nl, res);
+ goto ret;
+
+ // unary
+ case OCOM:
+ a = optoas(OXOR, nl->type);
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+ nodconst(&n2, nl->type, -1);
+ gins(a, &n2, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+
+ case OMINUS:
+ if(isfloat[nl->type->etype]) {
+ nr = nodintconst(-1);
+ convlit(&nr, n->type);
+ a = optoas(OMUL, nl->type);
+ goto sbop;
+ }
+ a = optoas(n->op, nl->type);
+ goto uop;
+
+ // symmetric binary
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OADD:
+ case OMUL:
+ a = optoas(n->op, nl->type);
+ goto sbop;
+
+ // asymmetric binary
+ case OSUB:
+ a = optoas(n->op, nl->type);
+ goto abop;
+
+ case OHMUL:
+ cgen_hmul(nl, nr, res);
+ break;
+
+ case OCONV:
+ if(n->type->width > nl->type->width) {
+ // If loading from memory, do conversion during load,
+ // so as to avoid use of 8-bit register in, say, int(*byteptr).
+ switch(nl->op) {
+ case ODOT:
+ case ODOTPTR:
+ case OINDEX:
+ case OIND:
+ case ONAME:
+ igen(nl, &n1, res);
+ regalloc(&n2, n->type, res);
+ gmove(&n1, &n2);
+ gmove(&n2, res);
+ regfree(&n2);
+ regfree(&n1);
+ goto ret;
+ }
+ }
+
+ regalloc(&n1, nl->type, res);
+ regalloc(&n2, n->type, &n1);
+ cgen(nl, &n1);
+
+ // if we do the conversion n1 -> n2 here
+ // reusing the register, then gmove won't
+ // have to allocate its own register.
+ gmove(&n1, &n2);
+ gmove(&n2, res);
+ regfree(&n2);
+ regfree(&n1);
+ break;
+
+ case ODOT:
+ case ODOTPTR:
+ case OINDEX:
+ case OIND:
+ case ONAME: // PHEAP or PPARAMREF var
+ igen(n, &n1, res);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
+ case OITAB:
+ // interface table is first word of interface value
+ igen(nl, &n1, res);
+ n1.type = n->type;
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
+ case OSPTR:
+ // pointer is the first word of string or slice.
+ if(isconst(nl, CTSTR)) {
+ regalloc(&n1, types[tptr], res);
+ p1 = gins(AMOVD, N, &n1);
+ datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ igen(nl, &n1, res);
+ n1.type = n->type;
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
+ case OLEN:
+ if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
+ // map and chan have len in the first int-sized word.
+ // a zero pointer means zero length
+ regalloc(&n1, types[tptr], res);
+ cgen(nl, &n1);
+
+ nodconst(&n2, types[tptr], 0);
+ gins(optoas(OCMP, types[tptr]), &n1, &n2);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
+
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.type = types[simtype[TINT]];
+ gmove(&n2, &n1);
+
+ patch(p1, pc);
+
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ if(istype(nl->type, TSTRING) || isslice(nl->type)) {
+ // both slice and string have len one pointer into the struct.
+ // a zero pointer means zero length
+ igen(nl, &n1, res);
+ n1.type = types[simtype[TUINT]];
+ n1.xoffset += Array_nel;
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ fatal("cgen: OLEN: unknown type %lT", nl->type);
+ break;
+
+ case OCAP:
+ if(istype(nl->type, TCHAN)) {
+ // chan has cap in the second int-sized word.
+ // a zero pointer means zero length
+ regalloc(&n1, types[tptr], res);
+ cgen(nl, &n1);
+
+ nodconst(&n2, types[tptr], 0);
+ gins(optoas(OCMP, types[tptr]), &n1, &n2);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
+
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = widthint;
+ n2.type = types[simtype[TINT]];
+ gmove(&n2, &n1);
+
+ patch(p1, pc);
+
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ if(isslice(nl->type)) {
+ igen(nl, &n1, res);
+ n1.type = types[simtype[TUINT]];
+ n1.xoffset += Array_cap;
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ fatal("cgen: OCAP: unknown type %lT", nl->type);
+ break;
+
+ case OADDR:
+ if(n->bounded) // let race detector avoid nil checks
+ disable_checknil++;
+ agen(nl, res);
+ if(n->bounded)
+ disable_checknil--;
+ break;
+
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, res, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OMOD:
+ case ODIV:
+ if(isfloat[n->type->etype]) {
+ a = optoas(n->op, nl->type);
+ goto abop;
+ }
+
+ if(nl->ullman >= nr->ullman) {
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ cgen_div(n->op, &n1, nr, res);
+ regfree(&n1);
+ } else {
+ if(!smallintconst(nr)) {
+ regalloc(&n2, nr->type, res);
+ cgen(nr, &n2);
+ } else {
+ n2 = *nr;
+ }
+ cgen_div(n->op, nl, &n2, res);
+ if(n2.op != OLITERAL)
+ regfree(&n2);
+ }
+ break;
+
+ case OLSH:
+ case ORSH:
+ case OLROT:
+ cgen_shift(n->op, n->bounded, nl, nr, res);
+ break;
+ }
+ goto ret;
+
+sbop: // symmetric binary
+ /*
+ * put simplest on right - we'll generate into left
+ * and then adjust it using the computation of right.
+ * constants and variables have the same ullman
+ * count, so look for constants specially.
+ *
+ * an integer constant we can use as an immediate
+ * is simpler than a variable - we can use the immediate
+ * in the adjustment instruction directly - so it goes
+ * on the right.
+ *
+ * other constants, like big integers or floating point
+ * constants, require a mov into a register, so those
+ * might as well go on the left, so we can reuse that
+ * register for the computation.
+ */
+ if(nl->ullman < nr->ullman ||
+ (nl->ullman == nr->ullman &&
+ (smallintconst(nl) || (nr->op == OLITERAL && !smallintconst(nr))))) {
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+abop: // asymmetric binary
+ if(nl->ullman >= nr->ullman) {
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ /*
+ * This generates smaller code - it avoids a MOV - but it's
+ * easily 10% slower due to not being able to
+ * optimize/manipulate the move.
+ * To see, run: go test -bench . crypto/md5
+ * with and without.
+ *
+ if(sudoaddable(a, nr, &addr)) {
+ p1 = gins(a, N, &n1);
+ p1->from = addr;
+ gmove(&n1, res);
+ sudoclean();
+ regfree(&n1);
+ goto ret;
+ }
+ *
+ */
+ // TODO(minux): enable using constants directly in certain instructions.
+ //if(smallintconst(nr))
+ // n2 = *nr;
+ //else {
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ //}
+ } else {
+ //if(smallintconst(nr))
+ // n2 = *nr;
+ //else {
+ regalloc(&n2, nr->type, res);
+ cgen(nr, &n2);
+ //}
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+ }
+ gins(a, &n2, &n1);
+ // Normalize result for types smaller than word.
+ if(n->type->width < widthreg) {
+ switch(n->op) {
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OLSH:
+ gins(optoas(OAS, n->type), &n1, &n1);
+ break;
+ }
+ }
+ gmove(&n1, res);
+ regfree(&n1);
+ if(n2.op != OLITERAL)
+ regfree(&n2);
+ goto ret;
+
+uop: // unary
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ gins(a, N, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+
+ret:
+ ;
+}
+
+/*
+ * allocate a register (reusing res if possible) and generate
+ * a = n
+ * The caller must call regfree(a).
+ */
+void
+cgenr(Node *n, Node *a, Node *res)
+{
+ Node n1;
+
+ if(debug['g'])
+ dump("cgenr-n", n);
+
+ if(isfat(n->type))
+ fatal("cgenr on fat node");
+
+ if(n->addable) {
+ regalloc(a, n->type, res);
+ gmove(n, a);
+ return;
+ }
+
+ switch(n->op) {
+ case ONAME:
+ case ODOT:
+ case ODOTPTR:
+ case OINDEX:
+ case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ igen(n, &n1, res);
+ regalloc(a, types[tptr], &n1);
+ gmove(&n1, a);
+ regfree(&n1);
+ break;
+ default:
+ regalloc(a, n->type, res);
+ cgen(n, a);
+ break;
+ }
+}
+
+/*
+ * allocate a register (reusing res if possible) and generate
+ * a = &n
+ * The caller must call regfree(a).
+ * The generated code checks that the result is not nil.
+ */
+void
+agenr(Node *n, Node *a, Node *res)
+{
+ Node *nl, *nr;
+ Node n1, n2, n3, n4, tmp;
+ Prog *p1, *p2;
+ uint32 w;
+ uint64 v;
+
+ if(debug['g'])
+ dump("agenr-n", n);
+
+ nl = n->left;
+ nr = n->right;
+
+ switch(n->op) {
+ case ODOT:
+ case ODOTPTR:
+ case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ igen(n, &n1, res);
+ regalloc(a, types[tptr], &n1);
+ agen(&n1, a);
+ regfree(&n1);
+ break;
+
+ case OIND:
+ cgenr(n->left, a, res);
+ cgen_checknil(a);
+ break;
+
+ case OINDEX:
+ p2 = nil; // to be patched to panicindex.
+ w = n->type->width;
+ //bounded = debug['B'] || n->bounded;
+ if(nr->addable) {
+ if(!isconst(nr, CTINT))
+ tempname(&tmp, types[TINT64]);
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
+ if(!isconst(nr, CTINT)) {
+ cgen(nr, &tmp);
+ regalloc(&n1, tmp.type, N);
+ gmove(&tmp, &n1);
+ }
+ } else if(nl->addable) {
+ if(!isconst(nr, CTINT)) {
+ tempname(&tmp, types[TINT64]);
+ cgen(nr, &tmp);
+ regalloc(&n1, tmp.type, N);
+ gmove(&tmp, &n1);
+ }
+ if(!isconst(nl, CTSTR)) {
+ agenr(nl, &n3, res);
+ }
+ } else {
+ tempname(&tmp, types[TINT64]);
+ cgen(nr, &tmp);
+ nr = &tmp;
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
+ regalloc(&n1, tmp.type, N);
+ gins(optoas(OAS, tmp.type), &tmp, &n1);
+ }
+
+ // &a is in &n3 (allocated in res)
+ // i is in &n1 (if not constant)
+ // w is width
+
+ // constant index
+ if(isconst(nr, CTINT)) {
+ if(isconst(nl, CTSTR))
+ fatal("constant string constant index");
+ v = mpgetfix(nr->val.u.xval);
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
+ if(!debug['B'] && !n->bounded) {
+ n1 = n3;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_nel;
+ regalloc(&n4, n1.type, N);
+ gmove(&n1, &n4);
+ ginscon2(optoas(OCMP, types[TUINT64]), &n4, v);
+ regfree(&n4);
+ p1 = gbranch(optoas(OGT, types[TUINT64]), T, +1);
+ ginscall(panicindex, 0);
+ patch(p1, pc);
+ }
+
+ n1 = n3;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_array;
+ gmove(&n1, &n3);
+ }
+
+ if (v*w != 0) {
+ ginscon(optoas(OADD, types[tptr]), v*w, &n3);
+ }
+ *a = n3;
+ break;
+ }
+
+ regalloc(&n2, types[TINT64], &n1); // i
+ gmove(&n1, &n2);
+ regfree(&n1);
+
+ if(!debug['B'] && !n->bounded) {
+ // check bounds
+ if(isconst(nl, CTSTR)) {
+ nodconst(&n4, types[TUINT64], nl->val.u.sval->len);
+ } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
+ n1 = n3;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_nel;
+ regalloc(&n4, types[TUINT64], N);
+ gmove(&n1, &n4);
+ } else {
+ if(nl->type->bound < (1<<15)-1)
+ nodconst(&n4, types[TUINT64], nl->type->bound);
+ else {
+ regalloc(&n4, types[TUINT64], N);
+ p1 = gins(AMOVD, N, &n4);
+ p1->from.type = D_CONST;
+ p1->from.offset = nl->type->bound;
+ }
+ }
+ gins(optoas(OCMP, types[TUINT64]), &n2, &n4);
+ if(n4.op == OREGISTER)
+ regfree(&n4);
+ p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1);
+ if(p2)
+ patch(p2, pc);
+ ginscall(panicindex, 0);
+ patch(p1, pc);
+ }
+
+ if(isconst(nl, CTSTR)) {
+ 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;
+ } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
+ n1 = n3;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_array;
+ gmove(&n1, &n3);
+ }
+
+ if(w == 0) {
+ // nothing to do
+ } else if(w == 1) {
+ /* w already scaled */
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ } /* else if(w == 2 || w == 4 || w == 8) {
+ // TODO(minux): scale using shift
+ } */ else {
+ regalloc(&n4, types[TUINT64], N);
+ nodconst(&n1, types[TUINT64], w);
+ gmove(&n1, &n4);
+ gins(optoas(OMUL, types[TUINT64]), &n4, &n2);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ regfree(&n4);
+ }
+
+ *a = n3;
+ regfree(&n2);
+ break;
+
+ default:
+ regalloc(a, types[tptr], res);
+ agen(n, a);
+ break;
+ }
+}
+
+static void
+ginsadd(int as, vlong off, Node *dst)
+{
+ Node n1;
+
+ regalloc(&n1, types[tptr], dst);
+ gmove(dst, &n1);
+ ginscon(as, off, &n1);
+ gmove(&n1, dst);
+ regfree(&n1);
+}
+
+/*
+ * generate:
+ * res = &n;
+ * The generated code checks that the result is not nil.
+ */
+void
+agen(Node *n, Node *res)
+{
+ Node *nl, *nr;
+ Node n1, n2, n3;
+
+ if(debug['g']) {
+ dump("\nagen-res", res);
+ dump("agen-r", n);
+ }
+ if(n == N || n->type == T)
+ return;
+
+ while(n->op == OCONVNOP)
+ n = n->left;
+
+ if(isconst(n, CTNIL) && n->type->width > widthptr) {
+ // Use of a nil interface or nil slice.
+ // Create a temporary we can take the address of and read.
+ // The generated code is just going to panic, so it need not
+ // be terribly efficient. See issue 3670.
+ tempname(&n1, n->type);
+ gvardef(&n1);
+ clearfat(&n1);
+ regalloc(&n2, types[tptr], res);
+ memset(&n3, 0, sizeof n3);
+ n3.op = OADDR;
+ n3.left = &n1;
+ gins(AMOVD, &n3, &n2);
+ gmove(&n2, res);
+ regfree(&n2);
+ goto ret;
+ }
+
+ if(n->addable) {
+ memset(&n1, 0, sizeof n1);
+ n1.op = OADDR;
+ n1.left = n;
+ regalloc(&n2, types[tptr], res);
+ gins(AMOVD, &n1, &n2);
+ gmove(&n2, res);
+ regfree(&n2);
+ goto ret;
+ }
+
+ nl = n->left;
+ nr = n->right;
+ USED(nr);
+
+ switch(n->op) {
+ default:
+ fatal("agen: unknown op %+hN", n);
+ break;
+
+ case OCALLMETH:
+ // TODO(minux): 5g has this: Release res so that it is available for cgen_call.
+ // Pick it up again after the call for OCALLMETH and OCALLFUNC.
+ cgen_callmeth(n, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, res, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICESTR:
+ case OSLICE3:
+ case OSLICE3ARR:
+ tempname(&n1, n->type);
+ cgen_slice(n, &n1);
+ agen(&n1, res);
+ break;
+
+ case OEFACE:
+ tempname(&n1, n->type);
+ cgen_eface(n, &n1);
+ agen(&n1, res);
+ break;
+
+ case OINDEX:
+ agenr(n, &n1, res);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
+ case ONAME:
+ // should only get here with names in this func.
+ if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
+ dump("bad agen", n);
+ fatal("agen: bad ONAME funcdepth %d != %d",
+ n->funcdepth, funcdepth);
+ }
+
+ // should only get here for heap vars or paramref
+ if(!(n->class & PHEAP) && n->class != PPARAMREF) {
+ dump("bad agen", n);
+ fatal("agen: bad ONAME class %#x", n->class);
+ }
+ cgen(n->heapaddr, res);
+ if(n->xoffset != 0) {
+ ginsadd(optoas(OADD, types[tptr]), n->xoffset, res);
+ }
+ break;
+
+ case OIND:
+ cgen(nl, res);
+ cgen_checknil(res);
+ break;
+
+ case ODOT:
+ agen(nl, res);
+ if(n->xoffset != 0) {
+ ginsadd(optoas(OADD, types[tptr]), n->xoffset, res);
+ }
+ break;
+
+ case ODOTPTR:
+ cgen(nl, res);
+ cgen_checknil(res);
+ if(n->xoffset != 0) {
+ ginsadd(optoas(OADD, types[tptr]), n->xoffset, res);
+ }
+ break;
+ }
+
+ret:
+ ;
+}
+
+/*
+ * generate:
+ * newreg = &n;
+ * res = newreg
+ *
+ * on exit, a has been changed to be *newreg.
+ * caller must regfree(a).
+ * The generated code checks that the result is not *nil.
+ */
+void
+igen(Node *n, Node *a, Node *res)
+{
+ Type *fp;
+ Iter flist;
+ Node n1;
+
+ if(debug['g']) {
+ dump("\nigen-n", n);
+ }
+ switch(n->op) {
+ case ONAME:
+ if((n->class&PHEAP) || n->class == PPARAMREF)
+ break;
+ *a = *n;
+ return;
+
+ 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)
+ reg[n->val.u.reg]++;
+ *a = *n;
+ return;
+
+ case ODOT:
+ igen(n->left, a, res);
+ a->xoffset += n->xoffset;
+ a->type = n->type;
+ fixlargeoffset(a);
+ return;
+
+ case ODOTPTR:
+ cgenr(n->left, a, res);
+ cgen_checknil(a);
+ a->op = OINDREG;
+ a->xoffset += n->xoffset;
+ a->type = n->type;
+ fixlargeoffset(a);
+ return;
+
+ case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ switch(n->op) {
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ break;
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ break;
+ case OCALLINTER:
+ cgen_callinter(n, N, 0);
+ break;
+ }
+ fp = structfirst(&flist, getoutarg(n->left->type));
+ memset(a, 0, sizeof *a);
+ a->op = OINDREG;
+ a->val.u.reg = D_R0+REGSP;
+ a->addable = 1;
+ a->xoffset = fp->width + widthptr; // +widthptr: saved lr at 0(SP)
+ a->type = n->type;
+ return;
+
+ case OINDEX:
+ // Index of fixed-size array by constant can
+ // put the offset in the addressing.
+ // Could do the same for slice except that we need
+ // to use the real index for the bounds checking.
+ if(isfixedarray(n->left->type) ||
+ (isptr[n->left->type->etype] && isfixedarray(n->left->left->type)))
+ if(isconst(n->right, CTINT)) {
+ // Compute &a.
+ if(!isptr[n->left->type->etype])
+ igen(n->left, a, res);
+ else {
+ igen(n->left, &n1, res);
+ cgen_checknil(&n1);
+ regalloc(a, types[tptr], res);
+ gmove(&n1, a);
+ regfree(&n1);
+ a->op = OINDREG;
+ }
+
+ // Compute &a[i] as &a + i*width.
+ a->type = n->type;
+ a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width;
+ fixlargeoffset(a);
+ return;
+ }
+ break;
+ }
+
+ agenr(n, a, res);
+ a->op = OINDREG;
+ a->type = n->type;
+}
+
+/*
+ * generate:
+ * if(n == true) goto to;
+ */
+void
+bgen(Node *n, int true, int likely, Prog *to)
+{
+ int et, a;
+ Node *nl, *nr, *l, *r;
+ Node n1, n2, tmp;
+ NodeList *ll;
+ Prog *p1, *p2;
+
+ if(debug['g']) {
+ dump("\nbgen", n);
+ }
+
+ if(n == N)
+ n = nodbool(1);
+
+ if(n->ninit != nil)
+ genlist(n->ninit);
+
+ if(n->type == T) {
+ convlit(&n, types[TBOOL]);
+ if(n->type == T)
+ goto ret;
+ }
+
+ et = n->type->etype;
+ if(et != TBOOL) {
+ yyerror("cgen: bad type %T for %O", n->type, n->op);
+ patch(gins(AEND, N, N), to);
+ goto ret;
+ }
+ nr = N;
+
+ while(n->op == OCONVNOP) {
+ n = n->left;
+ if(n->ninit != nil)
+ genlist(n->ninit);
+ }
+
+ switch(n->op) {
+ default:
+ regalloc(&n1, n->type, N);
+ cgen(n, &n1);
+ nodconst(&n2, n->type, 0);
+ gins(optoas(OCMP, n->type), &n1, &n2);
+ a = ABNE;
+ if(!true)
+ a = ABEQ;
+ patch(gbranch(a, n->type, likely), to);
+ regfree(&n1);
+ goto ret;
+
+ case OLITERAL:
+ // need to ask if it is bool?
+ if(!true == !n->val.u.bval)
+ patch(gbranch(ABR, T, likely), to);
+ goto ret;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ p1 = gbranch(ABR, T, 0);
+ p2 = gbranch(ABR, T, 0);
+ patch(p1, pc);
+ bgen(n->left, !true, -likely, p2);
+ bgen(n->right, !true, -likely, p2);
+ p1 = gbranch(ABR, T, 0);
+ patch(p1, to);
+ patch(p2, pc);
+ goto ret;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bgen(n->left, true, likely, to);
+ bgen(n->right, true, likely, to);
+ goto ret;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ nr = n->right;
+ if(nr == N || nr->type == T)
+ goto ret;
+
+ case ONOT: // unary
+ nl = n->left;
+ if(nl == N || nl->type == T)
+ goto ret;
+ break;
+ }
+
+ switch(n->op) {
+
+ case ONOT:
+ bgen(nl, !true, likely, to);
+ goto ret;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ a = n->op;
+ if(!true) {
+ if(isfloat[nr->type->etype]) {
+ // brcom is not valid on floats when NaN is involved.
+ p1 = gbranch(ABR, T, 0);
+ p2 = gbranch(ABR, T, 0);
+ patch(p1, pc);
+ ll = n->ninit; // avoid re-genning ninit
+ n->ninit = nil;
+ bgen(n, 1, -likely, p2);
+ n->ninit = ll;
+ patch(gbranch(ABR, T, 0), to);
+ patch(p2, pc);
+ goto ret;
+ }
+ a = brcom(a);
+ true = !true;
+ }
+
+ // make simplest on right
+ if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) {
+ a = brrev(a);
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+ if(isslice(nl->type)) {
+ // front end should only leave cmp to literal nil
+ if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+ yyerror("illegal slice comparison");
+ break;
+ }
+ a = optoas(a, types[tptr]);
+ igen(nl, &n1, N);
+ n1.xoffset += Array_array;
+ n1.type = types[tptr];
+ nodconst(&tmp, types[tptr], 0);
+ regalloc(&n2, types[tptr], &n1);
+ gmove(&n1, &n2);
+ gins(optoas(OCMP, types[tptr]), &n2, &tmp);
+ regfree(&n2);
+ patch(gbranch(a, types[tptr], likely), to);
+ regfree(&n1);
+ break;
+ }
+
+ if(isinter(nl->type)) {
+ // front end should only leave cmp to literal nil
+ if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+ yyerror("illegal interface comparison");
+ break;
+ }
+ a = optoas(a, types[tptr]);
+ igen(nl, &n1, N);
+ n1.type = types[tptr];
+ nodconst(&tmp, types[tptr], 0);
+ regalloc(&n2, types[tptr], &n1);
+ gmove(&n1, &n2);
+ gins(optoas(OCMP, types[tptr]), &n2, &tmp);
+ regfree(&n2);
+ patch(gbranch(a, types[tptr], likely), to);
+ regfree(&n1);
+ break;
+ }
+ if(iscomplex[nl->type->etype]) {
+ complexbool(a, nl, nr, true, likely, to);
+ break;
+ }
+
+ if(nr->ullman >= UINF) {
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+
+ tempname(&tmp, nl->type);
+ gmove(&n1, &tmp);
+ regfree(&n1);
+
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+
+ regalloc(&n1, nl->type, N);
+ cgen(&tmp, &n1);
+
+ goto cmp;
+ }
+
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+
+ // TODO(minux): cmpi does accept 16-bit signed immediate as p->to.
+ // and cmpli accepts 16-bit unsigned immediate.
+ //if(smallintconst(nr)) {
+ // gins(optoas(OCMP, nr->type), &n1, nr);
+ // patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
+ // regfree(&n1);
+ // break;
+ //}
+
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ cmp:
+ l = &n1;
+ r = &n2;
+ gins(optoas(OCMP, nr->type), l, r);
+ if(isfloat[nr->type->etype] && (a == OLE || a == OGE)) {
+ // To get NaN right, must rewrite x <= y into separate x < y or x = y.
+ switch(a) {
+ case OLE:
+ a = OLT;
+ break;
+ case OGE:
+ a = OGT;
+ break;
+ }
+ patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
+ patch(gbranch(optoas(OEQ, nr->type), nr->type, likely), to);
+ } else {
+ patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
+ }
+ regfree(&n1);
+ regfree(&n2);
+ break;
+ }
+ goto ret;
+
+ret:
+ ;
+}
+
+/*
+ * n is on stack, either local variable
+ * or return value from function call.
+ * return n's offset from SP.
+ */
+int64
+stkof(Node *n)
+{
+ Type *t;
+ Iter flist;
+ int64 off;
+
+ switch(n->op) {
+ case OINDREG:
+ return n->xoffset;
+
+ case ODOT:
+ t = n->left->type;
+ if(isptr[t->etype])
+ break;
+ off = stkof(n->left);
+ if(off == -1000 || off == 1000)
+ return off;
+ return off + n->xoffset;
+
+ case OINDEX:
+ t = n->left->type;
+ if(!isfixedarray(t))
+ break;
+ off = stkof(n->left);
+ if(off == -1000 || off == 1000)
+ return off;
+ if(isconst(n->right, CTINT))
+ return off + t->type->width * mpgetfix(n->right->val.u.xval);
+ return 1000;
+
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
+ t = n->left->type;
+ if(isptr[t->etype])
+ t = t->type;
+
+ t = structfirst(&flist, getoutarg(t));
+ if(t != T)
+ return t->width + widthptr; // +widthptr: correct for saved LR
+ break;
+ }
+
+ // botch - probably failing to recognize address
+ // arithmetic on the above. eg INDEX and DOT
+ return -1000;
+}
+
+/*
+ * block copy:
+ * memmove(&ns, &n, w);
+ */
+void
+sgen(Node *n, Node *ns, int64 w)
+{
+ Node dst, src, tmp, nend;
+ int32 c, odst, osrc;
+ int dir, align, op;
+ Prog *p, *ploop;
+ NodeList *l;
+ Node *res = ns;
+
+ if(debug['g']) {
+ print("\nsgen w=%lld\n", w);
+ dump("r", n);
+ dump("res", ns);
+ }
+
+ if(n->ullman >= UINF && ns->ullman >= UINF)
+ fatal("sgen UINF");
+
+ if(w < 0)
+ fatal("sgen copy %lld", w);
+
+ // If copying .args, that's all the results, so record definition sites
+ // for them for the liveness analysis.
+ if(ns->op == ONAME && strcmp(ns->sym->name, ".args") == 0)
+ for(l = curfn->dcl; l != nil; l = l->next)
+ if(l->n->class == PPARAMOUT)
+ gvardef(l->n);
+
+ // Avoid taking the address for simple enough types.
+ //if(componentgen(n, ns))
+ // return;
+
+ if(w == 0) {
+ // evaluate side effects only.
+ regalloc(&dst, types[tptr], N);
+ agen(res, &dst);
+ agen(n, &dst);
+ regfree(&dst);
+ return;
+ }
+
+ // determine alignment.
+ // want to avoid unaligned access, so have to use
+ // smaller operations for less aligned types.
+ // for example moving [4]byte must use 4 MOVB not 1 MOVW.
+ align = n->type->align;
+ switch(align) {
+ default:
+ fatal("sgen: invalid alignment %d for %T", align, n->type);
+ case 1:
+ op = AMOVBU;
+ break;
+ case 2:
+ op = AMOVHU;
+ break;
+ case 4:
+ op = AMOVWZU; // there is no lwau, only lwaux
+ break;
+ case 8:
+ op = AMOVDU;
+ break;
+ }
+ if(w%align)
+ fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type);
+ c = w / align;
+
+ // offset on the stack
+ osrc = stkof(n);
+ odst = stkof(res);
+ if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
+ // osrc and odst both on stack, and at least one is in
+ // an unknown position. Could generate code to test
+ // for forward/backward copy, but instead just copy
+ // to a temporary location first.
+ tempname(&tmp, n->type);
+ sgen(n, &tmp, w);
+ sgen(&tmp, res, w);
+ return;
+ }
+ if(osrc%align != 0 || odst%align != 0)
+ fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align);
+
+ // if we are copying forward on the stack and
+ // the src and dst overlap, then reverse direction
+ dir = align;
+ if(osrc < odst && odst < osrc+w)
+ dir = -dir;
+
+ if(n->ullman >= res->ullman) {
+ agenr(n, &dst, res); // temporarily use dst
+ regalloc(&src, types[tptr], N);
+ gins(AMOVD, &dst, &src);
+ if(res->op == ONAME)
+ gvardef(res);
+ agen(res, &dst);
+ } else {
+ if(res->op == ONAME)
+ gvardef(res);
+ agenr(res, &dst, res);
+ agenr(n, &src, N);
+ }
+
+ regalloc(&tmp, types[tptr], N);
+
+ // set up end marker
+ memset(&nend, 0, sizeof nend);
+
+ // move src and dest to the end of block if necessary
+ if(dir < 0) {
+ if(c >= 4) {
+ regalloc(&nend, types[tptr], N);
+ p = gins(AMOVD, &src, &nend);
+ }
+
+ p = gins(AADD, N, &src);
+ p->from.type = D_CONST;
+ p->from.offset = w;
+
+ p = gins(AADD, N, &dst);
+ p->from.type = D_CONST;
+ p->from.offset = w;
+ } else {
+ p = gins(AADD, N, &src);
+ p->from.type = D_CONST;
+ p->from.offset = -dir;
+
+ p = gins(AADD, N, &dst);
+ p->from.type = D_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.offset = w;
+ }
+ }
+
+
+ // move
+ // TODO: enable duffcopy for larger copies.
+ if(c >= 4) {
+ p = gins(op, &src, &tmp);
+ p->from.type = D_OREG;
+ p->from.offset = dir;
+ ploop = p;
+
+ p = gins(op, &tmp, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = dir;
+
+ p = gins(ACMP, &src, &nend);
+
+ patch(gbranch(ABNE, T, 0), ploop);
+ regfree(&nend);
+ } else {
+ while(c-- > 0) {
+ p = gins(op, &src, &tmp);
+ p->from.type = D_OREG;
+ p->from.offset = dir;
+
+ p = gins(op, &tmp, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = dir;
+ }
+ }
+
+ regfree(&dst);
+ regfree(&src);
+ regfree(&tmp);
+}
+
+static int
+cadable(Node *n)
+{
+ if(!n->addable) {
+ // dont know how it happens,
+ // but it does
+ return 0;
+ }
+
+ switch(n->op) {
+ case ONAME:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * copy a composite value by moving its individual components.
+ * Slices, strings and interfaces are supported.
+ * Small structs or arrays with elements of basic type are
+ * also supported.
+ * nr is N when assigning a zero value.
+ * return 1 if can do, 0 if can't.
+ */
+int
+componentgen(Node *nr, Node *nl)
+{
+ Node nodl, nodr;
+ Type *t;
+ int freel, freer;
+ vlong fldcount;
+ vlong loffset, roffset;
+
+ freel = 0;
+ freer = 0;
+
+ switch(nl->type->etype) {
+ default:
+ goto no;
+
+ case TARRAY:
+ t = nl->type;
+
+ // Slices are ok.
+ if(isslice(t))
+ break;
+ // Small arrays are ok.
+ if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
+ break;
+
+ goto no;
+
+ case TSTRUCT:
+ // Small structs with non-fat types are ok.
+ // Zero-sized structs are treated separately elsewhere.
+ fldcount = 0;
+ for(t=nl->type->type; t; t=t->down) {
+ if(isfat(t->type))
+ goto no;
+ if(t->etype != TFIELD)
+ fatal("componentgen: not a TFIELD: %lT", t);
+ fldcount++;
+ }
+ if(fldcount == 0 || fldcount > 4)
+ goto no;
+
+ break;
+
+ case TSTRING:
+ case TINTER:
+ break;
+ }
+
+ nodl = *nl;
+ if(!cadable(nl)) {
+ if(nr == N || !cadable(nr))
+ goto no;
+ igen(nl, &nodl, N);
+ freel = 1;
+ }
+
+ if(nr != N) {
+ nodr = *nr;
+ if(!cadable(nr)) {
+ igen(nr, &nodr, N);
+ freer = 1;
+ }
+ }
+
+ // nl and nr are 'cadable' which basically means they are names (variables) now.
+ // If they are the same variable, don't generate any code, because the
+ // VARDEF we generate will mark the old value as dead incorrectly.
+ // (And also the assignments are useless.)
+ if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
+ goto yes;
+
+ switch(nl->type->etype) {
+ case TARRAY:
+ // componentgen for arrays.
+ if(nl->op == ONAME)
+ gvardef(nl);
+ t = nl->type;
+ if(!isslice(t)) {
+ nodl.type = t->type;
+ nodr.type = nodl.type;
+ for(fldcount=0; fldcount < t->bound; fldcount++) {
+ if(nr == N)
+ clearslim(&nodl);
+ else
+ gmove(&nodr, &nodl);
+ nodl.xoffset += t->type->width;
+ nodr.xoffset += t->type->width;
+ }
+ goto yes;
+ }
+
+ // componentgen for slices.
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(nl->type->type);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = types[simtype[TUINT]];
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_cap-Array_nel;
+ nodl.type = types[simtype[TUINT]];
+
+ if(nr != N) {
+ nodr.xoffset += Array_cap-Array_nel;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TSTRING:
+ if(nl->op == ONAME)
+ gvardef(nl);
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = types[simtype[TUINT]];
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TINTER:
+ if(nl->op == ONAME)
+ gvardef(nl);
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TSTRUCT:
+ if(nl->op == ONAME)
+ gvardef(nl);
+ loffset = nodl.xoffset;
+ roffset = nodr.xoffset;
+ // funarg structs may not begin at offset zero.
+ if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
+ loffset -= nl->type->type->width;
+ if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
+ roffset -= nr->type->type->width;
+
+ for(t=nl->type->type; t; t=t->down) {
+ nodl.xoffset = loffset + t->width;
+ nodl.type = t->type;
+
+ if(nr == N)
+ clearslim(&nodl);
+ else {
+ nodr.xoffset = roffset + t->width;
+ nodr.type = nodl.type;
+ gmove(&nodr, &nodl);
+ }
+ }
+ goto yes;
+ }
+
+no:
+ if(freer)
+ regfree(&nodr);
+ if(freel)
+ regfree(&nodl);
+ return 0;
+
+yes:
+ if(freer)
+ regfree(&nodr);
+ if(freel)
+ regfree(&nodl);
+ return 1;
+}
diff --git a/src/cmd/9g/doc.go b/src/cmd/9g/doc.go
new file mode 100644
index 000000000..200be2eda
--- /dev/null
+++ b/src/cmd/9g/doc.go
@@ -0,0 +1,16 @@
+// 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.
+
+// +build ignore
+
+/*
+
+9g is the version of the gc compiler for the Power64.
+The $GOARCH for these tools is power64 (big endian) or
+power64le (little endian).
+
+It reads .go files and outputs .9 files. The flags are documented in ../gc/doc.go.
+
+*/
+package main
diff --git a/src/cmd/9g/galign.c b/src/cmd/9g/galign.c
new file mode 100644
index 000000000..97a5a5d06
--- /dev/null
+++ b/src/cmd/9g/galign.c
@@ -0,0 +1,54 @@
+// 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.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+
+int thechar = '9';
+char* thestring = "power64";
+LinkArch* thelinkarch;
+
+void
+linkarchinit(void)
+{
+ thestring = getgoarch();
+ if(strcmp(thestring, "power64le") == 0)
+ thelinkarch = &linkpower64le;
+ else
+ thelinkarch = &linkpower64;
+}
+
+vlong MAXWIDTH = 1LL<<50;
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, float, and uintptr
+ */
+Typedef typedefs[] =
+{
+ {"int", TINT, TINT64},
+ {"uint", TUINT, TUINT64},
+ {"uintptr", TUINTPTR, TUINT64},
+ {0}
+};
+
+void
+betypeinit(void)
+{
+ widthptr = 8;
+ 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();
+}
diff --git a/src/cmd/9g/gg.h b/src/cmd/9g/gg.h
new file mode 100644
index 000000000..703fbd0a8
--- /dev/null
+++ b/src/cmd/9g/gg.h
@@ -0,0 +1,117 @@
+// 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.
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#include "../gc/go.h"
+#include "../9l/9.out.h"
+
+// 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;
+
+/*
+ * ggen.c
+ */
+void compile(Node*);
+void gen(Node*);
+Node* lookdot(Node*, Node*, int);
+void cgen_as(Node*, Node*);
+void cgen_callmeth(Node*, int);
+void cgen_callinter(Node*, Node*, int);
+void cgen_proc(Node*, int);
+void cgen_callret(Node*, Node*);
+void cgen_div(int, Node*, Node*, Node*);
+void cgen_hmul(Node*, Node*, Node*);
+void cgen_shift(int, int, Node*, Node*, Node*);
+void cgen_dcl(Node*);
+int needconvert(Type*, Type*);
+void genconv(Type*, Type*);
+void allocparams(void);
+void checklabels(void);
+void ginscall(Node*, int);
+int gen_as_init(Node*);
+
+/*
+ * cgen.c
+ */
+void agen(Node*, Node*);
+void agenr(Node*, Node*, Node*);
+void cgenr(Node*, Node*, Node*);
+void igen(Node*, Node*, Node*);
+vlong fieldoffset(Type*, Node*);
+void sgen(Node*, Node*, int64);
+void gmove(Node*, Node*);
+Prog* gins(int, Node*, Node*);
+void naddr(Node*, Addr*, int);
+void cgen_aret(Node*, Node*);
+int componentgen(Node*, Node*);
+
+/*
+ * gsubr.c
+ */
+void clearp(Prog*);
+Prog* gbranch(int, Type*, int);
+Prog* prog(int);
+void gconv(int, int);
+int conv2pt(Type*);
+vlong convvtox(vlong, int);
+void fnparam(Type*, int, int);
+Prog* gop(int, Node*, Node*, Node*);
+int optoas(int, Type*);
+void ginit(void);
+void gclean(void);
+void regalloc(Node*, Type*, Node*);
+void regfree(Node*);
+Node* nodarg(Type*, int);
+void nodreg(Node*, Type*, int);
+void nodindreg(Node*, Type*, int);
+void ginscon(int, vlong, Node*);
+void ginscon2(int, Node*, vlong);
+void buildtxt(void);
+Plist* newplist(void);
+int isfat(Type*);
+void sudoclean(void);
+int sudoaddable(int, Node*, Addr*);
+void afunclit(Addr*, Node*);
+void nodfconst(Node*, Type*, Mpflt*);
+void gtrack(Sym*);
+void fixlargeoffset(Node *n);
+
+/*
+ * cplx.c
+ */
+int complexop(Node*, Node*);
+void complexmove(Node*, Node*);
+void complexgen(Node*, Node*);
+
+/*
+ * gobj.c
+ */
+void datastring(char*, int, Addr*);
+void datagostring(Strlit*, Addr*);
+
+/*
+ * list.c
+ */
+void listinit(void);
+
+void zaddr(Biobuf*, Addr*, int, int);
diff --git a/src/cmd/9g/ggen.c b/src/cmd/9g/ggen.c
new file mode 100644
index 000000000..7d9cf5050
--- /dev/null
+++ b/src/cmd/9g/ggen.c
@@ -0,0 +1,1040 @@
+// 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.
+
+#undef EXTERN
+#define EXTERN
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+static Prog *appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset);
+static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi);
+
+void
+defframe(Prog *ptxt)
+{
+ uint32 frame;
+ Prog *p;
+ vlong hi, lo;
+ 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;
+ frame = rnd(stksize+maxarg, widthreg);
+ ptxt->to.offset |= frame;
+
+ // insert code to zero ambiguously live variables
+ // so that the garbage collector only sees initialized values
+ // when it looks for pointers.
+ p = ptxt;
+ lo = hi = 0;
+ // iterate through declarations - they are sorted in decreasing xoffset order.
+ for(l=curfn->dcl; l != nil; l = l->next) {
+ n = l->n;
+ if(!n->needzero)
+ continue;
+ if(n->class != PAUTO)
+ fatal("needzero class %d", n->class);
+ if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
+ fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
+
+ if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthreg) {
+ // merge with range we already have
+ lo = n->xoffset;
+ continue;
+ }
+ // zero old range
+ p = zerorange(p, frame, lo, hi);
+
+ // set new range
+ hi = n->xoffset + n->type->width;
+ lo = n->xoffset;
+ }
+ // zero final range
+ zerorange(p, frame, lo, hi);
+}
+
+static Prog*
+zerorange(Prog *p, vlong frame, vlong lo, vlong hi)
+{
+ vlong cnt, i;
+ Prog *p1;
+ Node *f;
+
+ cnt = hi - lo;
+ if(cnt == 0)
+ 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);
+ } else if(cnt <= 128*widthptr) {
+ p = appendpp(p, AADD, D_CONST, NREG, 8+frame+lo-8, D_REG, REGRT1, 0);
+ p->reg = REGSP;
+ p = appendpp(p, ADUFFZERO, D_NONE, NREG, 0, D_OREG, NREG, 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->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->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);
+ patch(p, p1);
+ }
+ return p;
+}
+
+static Prog*
+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.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;
+ return q;
+}
+
+// Sweep the prog list to mark any used nodes.
+void
+markautoused(Prog *p)
+{
+ for (; p; p = p->link) {
+ if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
+ continue;
+
+ if (p->from.node)
+ p->from.node->used = 1;
+
+ if (p->to.node)
+ p->to.node->used = 1;
+ }
+}
+
+// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
+void
+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) {
+ *lp = p->link;
+ continue;
+ }
+ if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.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;
+ continue;
+ }
+ if (p->from.name == D_AUTO && p->from.node)
+ p->from.offset += p->from.node->stkdelta;
+
+ if (p->to.name == D_AUTO && p->to.node)
+ p->to.offset += p->to.node->stkdelta;
+
+ lp = &p->link;
+ }
+}
+
+/*
+ * generate: BL reg, f
+ * where both reg and f are registers.
+ * On power, f must be moved to CTR first.
+ */
+static void
+ginsBL(Node *reg, Node *f)
+{
+ Prog *p;
+ p = gins(AMOVD, f, N);
+ p->to.type = D_SPR;
+ p->to.offset = D_CTR;
+ p = gins(ABL, reg, N);
+ p->to.type = D_SPR;
+ p->to.offset = D_CTR;
+}
+
+/*
+ * generate:
+ * call f
+ * proc=-1 normal call but no return
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
+ * proc=3 normal call to C pointer (not Go func value)
+ */
+void
+ginscall(Node *f, int proc)
+{
+ Prog *p;
+ Node reg, con, reg2;
+ Node r1;
+
+ if(f->type != T)
+ setmaxarg(f->type);
+
+ switch(proc) {
+ default:
+ fatal("ginscall: bad proc %d", proc);
+ break;
+
+ case 0: // normal call
+ case -1: // normal call but no return
+ if(f->op == ONAME && f->class == PFUNC) {
+ if(f == deferreturn) {
+ // Deferred calls will appear to be returning to
+ // the CALL deferreturn(SB) that we are about to emit.
+ // However, the stack trace code will show the line
+ // of the instruction byte before the return PC.
+ // To avoid that being an unrelated instruction,
+ // insert a Power64 NOP that we will have the right line number.
+ // Power64 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);
+ gins(AOR, &reg, &reg);
+ }
+ p = gins(ABL, N, f);
+ afunclit(&p->to, f);
+ if(proc == -1 || noreturn(p))
+ gins(AUNDEF, N, N);
+ break;
+ }
+ nodreg(&reg, types[tptr], D_R0+REGENV);
+ nodreg(&r1, types[tptr], D_R0+3);
+ gmove(f, &reg);
+ reg.op = OINDREG;
+ gmove(&reg, &r1);
+ reg.op = OREGISTER;
+ ginsBL(&reg, &r1);
+ break;
+
+ case 3: // normal call of c function pointer
+ ginsBL(N, f);
+ break;
+
+ 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);
+ gmove(f, &reg);
+
+ p = gins(ASUB, N, N);
+ p->from.type = D_CONST;
+ p->from.offset = 3 * 8;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ gmove(&con, &reg2);
+ p = gins(AMOVW, &reg2, N);
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 8;
+
+ p = gins(AMOVD, &reg, N);
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 16;
+
+ if(proc == 1)
+ ginscall(newproc, 0);
+ else {
+ if(!hasdefer)
+ fatal("hasdefer=0 but has defer");
+ ginscall(deferproc, 0);
+ }
+
+ p = gins(AADD, N, N);
+ p->from.type = D_CONST;
+ p->from.offset = 3 * 8;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ if(proc == 2) {
+ nodreg(&reg, types[TINT64], D_R0+3);
+ p = gins(ACMP, &reg, N);
+ p->to.type = D_REG;
+ p->to.reg = D_R0;
+ p = gbranch(ABEQ, T, +1);
+ cgen_ret(N);
+ patch(p, pc);
+ }
+ break;
+ }
+}
+
+/*
+ * n is call to interface method.
+ * generate res = n.
+ */
+void
+cgen_callinter(Node *n, Node *res, int proc)
+{
+ Node *i, *f;
+ Node tmpi, nodi, nodo, nodr, nodsp;
+ Prog *p;
+
+ i = n->left;
+ if(i->op != ODOTINTER)
+ fatal("cgen_callinter: not ODOTINTER %O", i->op);
+
+ f = i->right; // field
+ if(f->op != ONAME)
+ fatal("cgen_callinter: not ONAME %O", f->op);
+
+ i = i->left; // interface
+
+ if(!i->addable) {
+ tempname(&tmpi, i->type);
+ cgen(i, &tmpi);
+ i = &tmpi;
+ }
+
+ genlist(n->list); // assign the args
+
+ // i is now addable, prepare an indirected
+ // register to hold its address.
+ igen(i, &nodi, res); // REG = &inter
+
+ nodindreg(&nodsp, types[tptr], D_R0+REGSP);
+ nodsp.xoffset = widthptr;
+ nodi.type = types[tptr];
+ nodi.xoffset += widthptr;
+ cgen(&nodi, &nodsp); // 0(SP) = 8(REG) -- i.data
+
+ regalloc(&nodo, types[tptr], res);
+ nodi.type = types[tptr];
+ nodi.xoffset -= widthptr;
+ cgen(&nodi, &nodo); // REG = 0(REG) -- i.tab
+ regfree(&nodi);
+
+ regalloc(&nodr, types[tptr], &nodo);
+ if(n->left->xoffset == BADWIDTH)
+ fatal("cgen_callinter: badwidth");
+ cgen_checknil(&nodo); // in case offset is huge
+ nodo.op = OINDREG;
+ nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
+ if(proc == 0) {
+ // plain call: use direct c function pointer - more efficient
+ cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f]
+ proc = 3;
+ } 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;
+ }
+
+ nodr.type = n->left->type;
+ ginscall(&nodr, proc);
+
+ regfree(&nodr);
+ regfree(&nodo);
+}
+
+/*
+ * generate function call;
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
+ */
+void
+cgen_call(Node *n, int proc)
+{
+ Type *t;
+ Node nod, afun;
+
+ if(n == N)
+ return;
+
+ if(n->left->ullman >= UINF) {
+ // if name involves a fn call
+ // precompute the address of the fn
+ tempname(&afun, types[tptr]);
+ cgen(n->left, &afun);
+ }
+
+ genlist(n->list); // assign the args
+ t = n->left->type;
+
+ // call tempname pointer
+ if(n->left->ullman >= UINF) {
+ regalloc(&nod, types[tptr], N);
+ cgen_as(&nod, &afun);
+ nod.type = t;
+ ginscall(&nod, proc);
+ regfree(&nod);
+ return;
+ }
+
+ // call pointer
+ if(n->left->op != ONAME || n->left->class != PFUNC) {
+ regalloc(&nod, types[tptr], N);
+ cgen_as(&nod, n->left);
+ nod.type = t;
+ ginscall(&nod, proc);
+ regfree(&nod);
+ return;
+ }
+
+ // call direct
+ n->left->method = 1;
+ ginscall(n->left, proc);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ * res = return value from call.
+ */
+void
+cgen_callret(Node *n, Node *res)
+{
+ Node nod;
+ Type *fp, *t;
+ Iter flist;
+
+ t = n->left->type;
+ if(t->etype == TPTR32 || t->etype == TPTR64)
+ t = t->type;
+
+ fp = structfirst(&flist, getoutarg(t));
+ if(fp == T)
+ fatal("cgen_callret: nil");
+
+ memset(&nod, 0, sizeof(nod));
+ nod.op = OINDREG;
+ nod.val.u.reg = D_R0+REGSP;
+ nod.addable = 1;
+
+ nod.xoffset = fp->width + widthptr; // +widthptr: saved LR at 0(R1)
+ nod.type = fp->type;
+ cgen_as(res, &nod);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ * res = &return value from call.
+ */
+void
+cgen_aret(Node *n, Node *res)
+{
+ Node nod1, nod2;
+ Type *fp, *t;
+ Iter flist;
+
+ t = n->left->type;
+ if(isptr[t->etype])
+ t = t->type;
+
+ fp = structfirst(&flist, getoutarg(t));
+ if(fp == T)
+ fatal("cgen_aret: nil");
+
+ memset(&nod1, 0, sizeof(nod1));
+ nod1.op = OINDREG;
+ nod1.val.u.reg = D_R0 + REGSP;
+ nod1.addable = 1;
+
+ nod1.xoffset = fp->width + widthptr; // +widthptr: saved lr at 0(SP)
+ nod1.type = fp->type;
+
+ if(res->op != OREGISTER) {
+ regalloc(&nod2, types[tptr], res);
+ agen(&nod1, &nod2);
+ gins(AMOVD, &nod2, res);
+ regfree(&nod2);
+ } else
+ agen(&nod1, res);
+}
+
+/*
+ * generate return.
+ * n->left is assignments to return values.
+ */
+void
+cgen_ret(Node *n)
+{
+ Prog *p;
+
+ if(n != N)
+ genlist(n->list); // copy out args
+ if(hasdefer)
+ ginscall(deferreturn, 0);
+ 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.sym = linksym(n->left->sym);
+ }
+}
+
+void
+cgen_asop(Node *n)
+{
+ USED(n);
+ fatal("cgen_asop"); // no longer used
+}
+
+int
+samereg(Node *a, Node *b)
+{
+ if(a == N || b == N)
+ return 0;
+ if(a->op != OREGISTER)
+ return 0;
+ if(b->op != OREGISTER)
+ return 0;
+ if(a->val.u.reg != b->val.u.reg)
+ return 0;
+ return 1;
+}
+
+/*
+ * generate division.
+ * generates one of:
+ * res = nl / nr
+ * res = nl % nr
+ * according to op.
+ */
+void
+dodiv(int op, Node *nl, Node *nr, Node *res)
+{
+ int a, check;
+ Type *t, *t0;
+ Node tl, tr, tl2, tr2, nm1, nz, tm;
+ Prog *p1, *p2;
+
+ // Have to be careful about handling
+ // most negative int divided by -1 correctly.
+ // The hardware will generate undefined result.
+ // Also need to explicitly trap on division on zero,
+ // the hardware will silently generate undefined result.
+ // DIVW will leave unpredicable result in higher 32-bit,
+ // so always use DIVD/DIVDU.
+ t = nl->type;
+ t0 = t;
+ check = 0;
+ if(issigned[t->etype]) {
+ check = 1;
+ if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -(1ULL<<(t->width*8-1)))
+ check = 0;
+ else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
+ check = 0;
+ }
+ if(t->width < 8) {
+ if(issigned[t->etype])
+ t = types[TINT64];
+ else
+ t = types[TUINT64];
+ check = 0;
+ }
+
+ a = optoas(ODIV, t);
+
+ regalloc(&tl, t0, N);
+ regalloc(&tr, t0, N);
+ if(nl->ullman >= nr->ullman) {
+ cgen(nl, &tl);
+ cgen(nr, &tr);
+ } else {
+ cgen(nr, &tr);
+ cgen(nl, &tl);
+ }
+ if(t != t0) {
+ // Convert
+ tl2 = tl;
+ tr2 = tr;
+ tl.type = t;
+ tr.type = t;
+ gmove(&tl2, &tl);
+ gmove(&tr2, &tr);
+ }
+
+ // Handle divide-by-zero panic.
+ p1 = gins(optoas(OCMP, t), &tr, N);
+ p1->to.type = D_REG;
+ p1->to.reg = REGZERO;
+ p1 = gbranch(optoas(ONE, t), T, +1);
+ if(panicdiv == N)
+ panicdiv = sysfunc("panicdivide");
+ ginscall(panicdiv, -1);
+ patch(p1, pc);
+
+ if(check) {
+ nodconst(&nm1, t, -1);
+ gins(optoas(OCMP, t), &tr, &nm1);
+ p1 = gbranch(optoas(ONE, t), T, +1);
+ if(op == ODIV) {
+ // a / (-1) is -a.
+ gins(optoas(OMINUS, t), N, &tl);
+ gmove(&tl, res);
+ } else {
+ // a % (-1) is 0.
+ nodconst(&nz, t, 0);
+ gmove(&nz, res);
+ }
+ p2 = gbranch(AJMP, T, 0);
+ patch(p1, pc);
+ }
+ p1 = gins(a, &tr, &tl);
+ if(op == ODIV) {
+ regfree(&tr);
+ gmove(&tl, res);
+ } else {
+ // A%B = A-(A/B*B)
+ regalloc(&tm, t, N);
+ // patch div to use the 3 register form
+ // TODO(minux): add gins3?
+ p1->reg = p1->to.reg;
+ p1->to.reg = tm.val.u.reg;
+ gins(optoas(OMUL, t), &tr, &tm);
+ regfree(&tr);
+ gins(optoas(OSUB, t), &tm, &tl);
+ regfree(&tm);
+ gmove(&tl, res);
+ }
+ regfree(&tl);
+ if(check)
+ patch(p2, pc);
+}
+
+/*
+ * generate division according to op, one of:
+ * res = nl / nr
+ * res = nl % nr
+ */
+void
+cgen_div(int op, Node *nl, Node *nr, Node *res)
+{
+ Node n1, n2, n3;
+ int w, a;
+ Magic m;
+
+ // TODO(minux): enable division by magic multiply (also need to fix longmod below)
+ //if(nr->op != OLITERAL)
+ goto longdiv;
+ w = nl->type->width*8;
+
+ // Front end handled 32-bit division. We only need to handle 64-bit.
+ // try to do division by multiply by (2^w)/d
+ // see hacker's delight chapter 10
+ switch(simtype[nl->type->etype]) {
+ default:
+ goto longdiv;
+
+ case TUINT64:
+ m.w = w;
+ m.ud = mpgetfix(nr->val.u.xval);
+ umagic(&m);
+ if(m.bad)
+ break;
+ if(op == OMOD)
+ goto longmod;
+
+ cgenr(nl, &n1, N);
+ nodconst(&n2, nl->type, m.um);
+ regalloc(&n3, nl->type, res);
+ cgen_hmul(&n1, &n2, &n3);
+
+ if(m.ua) {
+ // need to add numerator accounting for overflow
+ gins(optoas(OADD, nl->type), &n1, &n3);
+ nodconst(&n2, nl->type, 1);
+ gins(optoas(ORROTC, nl->type), &n2, &n3);
+ nodconst(&n2, nl->type, m.s-1);
+ gins(optoas(ORSH, nl->type), &n2, &n3);
+ } else {
+ nodconst(&n2, nl->type, m.s);
+ gins(optoas(ORSH, nl->type), &n2, &n3); // shift dx
+ }
+
+ gmove(&n3, res);
+ regfree(&n1);
+ regfree(&n3);
+ return;
+
+ case TINT64:
+ m.w = w;
+ m.sd = mpgetfix(nr->val.u.xval);
+ smagic(&m);
+ if(m.bad)
+ break;
+ if(op == OMOD)
+ goto longmod;
+
+ cgenr(nl, &n1, res);
+ nodconst(&n2, nl->type, m.sm);
+ regalloc(&n3, nl->type, N);
+ cgen_hmul(&n1, &n2, &n3);
+
+ if(m.sm < 0) {
+ // need to add numerator
+ gins(optoas(OADD, nl->type), &n1, &n3);
+ }
+
+ nodconst(&n2, nl->type, m.s);
+ gins(optoas(ORSH, nl->type), &n2, &n3); // shift n3
+
+ nodconst(&n2, nl->type, w-1);
+ gins(optoas(ORSH, nl->type), &n2, &n1); // -1 iff num is neg
+ gins(optoas(OSUB, nl->type), &n1, &n3); // added
+
+ if(m.sd < 0) {
+ // this could probably be removed
+ // by factoring it into the multiplier
+ gins(optoas(OMINUS, nl->type), N, &n3);
+ }
+
+ gmove(&n3, res);
+ regfree(&n1);
+ regfree(&n3);
+ return;
+ }
+ goto longdiv;
+
+longdiv:
+ // division and mod using (slow) hardware instruction
+ dodiv(op, nl, nr, res);
+ return;
+
+longmod:
+ // mod using formula A%B = A-(A/B*B) but
+ // we know that there is a fast algorithm for A/B
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ regalloc(&n2, nl->type, N);
+ cgen_div(ODIV, &n1, nr, &n2);
+ a = optoas(OMUL, nl->type);
+ if(w == 8) {
+ // use 2-operand 16-bit multiply
+ // because there is no 2-operand 8-bit multiply
+ //a = AIMULW;
+ }
+ if(!smallintconst(nr)) {
+ regalloc(&n3, nl->type, N);
+ cgen(nr, &n3);
+ gins(a, &n3, &n2);
+ regfree(&n3);
+ } else
+ gins(a, nr, &n2);
+ gins(optoas(OSUB, nl->type), &n2, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ regfree(&n2);
+}
+
+/*
+ * generate high multiply:
+ * res = (nl*nr) >> width
+ */
+void
+cgen_hmul(Node *nl, Node *nr, Node *res)
+{
+ int w;
+ Node n1, n2, *tmp;
+ Type *t;
+ Prog *p;
+
+ // largest ullman on left.
+ if(nl->ullman < nr->ullman) {
+ tmp = nl;
+ nl = nr;
+ nr = tmp;
+ }
+ t = nl->type;
+ w = t->width * 8;
+ cgenr(nl, &n1, res);
+ cgenr(nr, &n2, N);
+ switch(simtype[t->etype]) {
+ case TINT8:
+ case TINT16:
+ case TINT32:
+ gins(optoas(OMUL, t), &n2, &n1);
+ p = gins(ASRAD, N, &n1);
+ p->from.type = D_CONST;
+ p->from.offset = w;
+ break;
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ gins(optoas(OMUL, t), &n2, &n1);
+ p = gins(ASRD, N, &n1);
+ p->from.type = D_CONST;
+ p->from.offset = w;
+ break;
+ case TINT64:
+ case TUINT64:
+ if(issigned[t->etype])
+ p = gins(AMULHD, &n2, &n1);
+ else
+ p = gins(AMULHDU, &n2, &n1);
+ break;
+ default:
+ fatal("cgen_hmul %T", t);
+ break;
+ }
+ cgen(&n1, res);
+ regfree(&n1);
+ regfree(&n2);
+}
+
+/*
+ * generate shift according to op, one of:
+ * res = nl << nr
+ * res = nl >> nr
+ */
+void
+cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
+{
+ Node n1, n2, n3, n4, n5;
+ int a;
+ Prog *p1;
+ uvlong sc;
+ Type *tcount;
+
+ a = optoas(op, nl->type);
+
+ if(nr->op == OLITERAL) {
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ sc = mpgetfix(nr->val.u.xval);
+ if(sc >= nl->type->width*8) {
+ // large shift gets 2 shifts by width-1
+ nodconst(&n3, types[TUINT32], nl->type->width*8-1);
+ gins(a, &n3, &n1);
+ gins(a, &n3, &n1);
+ } else
+ gins(a, nr, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+ }
+
+ if(nl->ullman >= UINF) {
+ tempname(&n4, nl->type);
+ cgen(nl, &n4);
+ nl = &n4;
+ }
+ if(nr->ullman >= UINF) {
+ tempname(&n5, nr->type);
+ cgen(nr, &n5);
+ nr = &n5;
+ }
+
+ // Allow either uint32 or uint64 as shift type,
+ // to avoid unnecessary conversion from uint32 to uint64
+ // just to do the comparison.
+ tcount = types[simtype[nr->type->etype]];
+ if(tcount->etype < TUINT32)
+ tcount = types[TUINT32];
+
+ regalloc(&n1, nr->type, N); // to hold the shift type in CX
+ regalloc(&n3, tcount, &n1); // to clear high bits of CX
+
+ regalloc(&n2, nl->type, res);
+ if(nl->ullman >= nr->ullman) {
+ cgen(nl, &n2);
+ cgen(nr, &n1);
+ gmove(&n1, &n3);
+ } else {
+ cgen(nr, &n1);
+ gmove(&n1, &n3);
+ cgen(nl, &n2);
+ }
+ regfree(&n3);
+
+ // test and fix up large shifts
+ if(!bounded) {
+ nodconst(&n3, tcount, nl->type->width*8);
+ gins(optoas(OCMP, tcount), &n1, &n3);
+ p1 = gbranch(optoas(OLT, tcount), T, +1);
+ if(op == ORSH && issigned[nl->type->etype]) {
+ nodconst(&n3, types[TUINT32], nl->type->width*8-1);
+ gins(a, &n3, &n2);
+ } else {
+ nodconst(&n3, nl->type, 0);
+ gmove(&n3, &n2);
+ }
+ patch(p1, pc);
+ }
+
+ gins(a, &n1, &n2);
+
+ gmove(&n2, res);
+
+ regfree(&n1);
+ regfree(&n2);
+
+ret:
+ ;
+}
+
+void
+clearfat(Node *nl)
+{
+ uint64 w, c, q, t, boff;
+ Node dst, end, r0, *f;
+ Prog *p, *pl;
+
+ /* clear a fat object */
+ if(debug['g']) {
+ print("clearfat %N (%T, size: %lld)\n", nl, nl->type, nl->type->width);
+ }
+
+ w = nl->type->width;
+ // Avoid taking the address for simple enough types.
+ //if(componentgen(N, nl))
+ // return;
+
+ c = w % 8; // bytes
+ q = w / 8; // dwords
+
+ 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);
+ reg[REGRT1]++;
+ agen(nl, &dst);
+
+ if(q > 128) {
+ p = gins(ASUB, N, &dst);
+ p->from.type = D_CONST;
+ p->from.offset = 8;
+
+ regalloc(&end, types[tptr], N);
+ p = gins(AMOVD, &dst, &end);
+ p->from.type = D_CONST;
+ p->from.offset = q*8;
+
+ p = gins(AMOVDU, &r0, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = 8;
+ pl = p;
+
+ p = gins(ACMP, &dst, &end);
+ patch(gbranch(ABNE, T, 0), pl);
+
+ regfree(&end);
+ // The loop leaves R3 on the last zeroed dword
+ boff = 8;
+ } else if(q >= 4) {
+ p = gins(ASUB, N, &dst);
+ p->from.type = D_CONST;
+ p->from.offset = 8;
+ f = sysfunc("duffzero");
+ p = gins(ADUFFZERO, N, f);
+ afunclit(&p->to, f);
+ // 4 and 128 = magic constants: see ../../runtime/asm_power64x.s
+ p->to.offset = 4*(128-q);
+ // duffzero leaves R3 on the last zeroed dword
+ boff = 8;
+ } else {
+ for(t = 0; t < q; t++) {
+ p = gins(AMOVD, &r0, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = 8*t;
+ }
+ boff = 8*q;
+ }
+
+ for(t = 0; t < c; t++) {
+ p = gins(AMOVB, &r0, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = t+boff;
+ }
+ reg[REGRT1]--;
+}
+
+// Called after regopt and peep have run.
+// Expand CHECKNIL pseudo-op into actual nil pointer check.
+void
+expandchecks(Prog *firstp)
+{
+ Prog *p, *p1, *p2;
+
+ for(p = firstp; p != P; p = p->link) {
+ if(debug_checknil && ctxt->debugvlog)
+ print("expandchecks: %P\n", p);
+ if(p->as != ACHECKNIL)
+ 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)
+ fatal("invalid nil check %P\n", p);
+ /*
+ // check is
+ // TD $4, R0, arg (R0 is always zero)
+ // eqv. to:
+ // tdeq r0, arg
+ // NOTE: this needs special runtime support to make SIGTRAP recoverable.
+ reg = p->from.reg;
+ p->as = ATD;
+ p->from = p->to = p->from3 = zprog.from;
+ p->from.type = D_CONST;
+ p->from.offset = 4;
+ p->from.reg = NREG;
+ p->reg = 0;
+ p->to.type = D_REG;
+ p->to.reg = reg;
+ */
+ // check is
+ // CMP arg, R0
+ // BNE 2(PC) [likely]
+ // MOVD R0, 0(R0)
+ p1 = mal(sizeof *p1);
+ p2 = mal(sizeof *p2);
+ clearp(p1);
+ clearp(p2);
+ p1->link = p2;
+ p2->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+ p2->lineno = p->lineno;
+ p1->pc = 9999;
+ p2->pc = 9999;
+ p->as = ACMP;
+ p->to.type = D_REG;
+ p->to.reg = REGZERO;
+ p1->as = ABNE;
+ //p1->from.type = D_CONST;
+ //p1->from.offset = 1; // likely
+ p1->to.type = D_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->to.offset = 0;
+ }
+}
diff --git a/src/cmd/9g/gobj.c b/src/cmd/9g/gobj.c
new file mode 100644
index 000000000..3da55878a
--- /dev/null
+++ b/src/cmd/9g/gobj.c
@@ -0,0 +1,240 @@
+// Derived from Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+
+int
+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.offset = off;
+ p->from.reg = NREG;
+ p->from.sym = linksym(s);
+
+ p->reg = n;
+
+ p->to.type = D_SCONST;
+ p->to.name = D_NONE;
+ p->to.reg = NREG;
+ p->to.offset = 0;
+ memmove(p->to.u.sval, t, n);
+ return off + n;
+}
+
+/*
+ * make a refer to the data s, s+len
+ * emitting DATA if needed.
+ */
+void
+datastring(char *s, int len, Addr *a)
+{
+ Sym *sym;
+
+ sym = stringsym(s, len);
+ a->type = D_OREG;
+ a->name = D_EXTERN;
+ a->etype = simtype[TINT];
+ a->offset = widthptr+widthint; // skip header
+ a->reg = NREG;
+ a->sym = linksym(sym);
+ a->node = sym->def;
+}
+
+/*
+ * make a refer to the string sval,
+ * emitting DATA if needed.
+ */
+void
+datagostring(Strlit *sval, Addr *a)
+{
+ Sym *sym;
+
+ sym = stringsym(sval->s, sval->len);
+ a->type = D_OREG;
+ a->name = D_EXTERN;
+ a->sym = linksym(sym);
+ a->reg = NREG;
+ a->node = sym->def;
+ a->offset = 0; // header
+ a->etype = TSTRING;
+}
+
+void
+gdata(Node *nam, Node *nr, int wid)
+{
+ Prog *p;
+
+ if(nr->op == OLITERAL) {
+ switch(nr->val.ctype) {
+ case CTCPLX:
+ gdatacomplex(nam, nr->val.u.cval);
+ return;
+ case CTSTR:
+ gdatastring(nam, nr->val.u.sval);
+ return;
+ }
+ }
+ p = gins(ADATA, nam, nr);
+ p->reg = wid;
+}
+
+void
+gdatacomplex(Node *nam, Mpcplx *cval)
+{
+ Prog *p;
+ int w;
+
+ w = cplxsubtype(nam->type->etype);
+ w = types[w]->width;
+
+ p = gins(ADATA, nam, N);
+ p->reg = w;
+ p->to.type = D_FCONST;
+ p->to.u.dval = mpgetflt(&cval->real);
+
+ p = gins(ADATA, nam, N);
+ p->reg = w;
+ p->from.offset += w;
+ p->to.type = D_FCONST;
+ p->to.u.dval = mpgetflt(&cval->imag);
+}
+
+void
+gdatastring(Node *nam, Strlit *sval)
+{
+ Prog *p;
+ Node nod1;
+
+ p = gins(ADATA, nam, N);
+ datastring(sval->s, sval->len, &p->to);
+ p->reg = types[tptr]->width;
+ p->to.type = D_CONST;
+ p->to.etype = simtype[tptr];
+
+ nodconst(&nod1, types[TINT], sval->len);
+ p = gins(ADATA, nam, &nod1);
+ p->reg = widthint;
+ p->from.offset += widthptr;
+}
+
+int
+dstringptr(Sym *s, int off, char *str)
+{
+ Prog *p;
+
+ off = rnd(off, widthptr);
+ p = gins(ADATA, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = linksym(s);
+ p->from.offset = off;
+ p->reg = widthptr;
+
+ datastring(str, strlen(str)+1, &p->to);
+ p->to.type = D_CONST;
+ p->to.etype = simtype[TINT];
+ off += widthptr;
+
+ return off;
+}
+
+int
+dgostrlitptr(Sym *s, int off, Strlit *lit)
+{
+ Prog *p;
+
+ if(lit == nil)
+ return duintptr(s, off, 0);
+
+ off = rnd(off, widthptr);
+ p = gins(ADATA, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = linksym(s);
+ p->from.offset = off;
+ p->reg = widthptr;
+ datagostring(lit, &p->to);
+ p->to.type = D_CONST;
+ p->to.etype = simtype[TINT];
+ off += widthptr;
+
+ return off;
+}
+
+int
+dgostringptr(Sym *s, int off, char *str)
+{
+ int n;
+ Strlit *lit;
+
+ if(str == nil)
+ return duintptr(s, off, 0);
+
+ n = strlen(str);
+ lit = mal(sizeof *lit + n);
+ strcpy(lit->s, str);
+ lit->len = n;
+ return dgostrlitptr(s, off, lit);
+}
+
+int
+dsymptr(Sym *s, int off, Sym *x, int xoff)
+{
+ Prog *p;
+
+ off = rnd(off, widthptr);
+
+ p = gins(ADATA, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = linksym(s);
+ p->from.offset = off;
+ p->reg = widthptr;
+ p->to.type = D_CONST;
+ p->to.name = D_EXTERN;
+ p->to.sym = linksym(x);
+ p->to.offset = xoff;
+ off += widthptr;
+
+ return off;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+}
+
diff --git a/src/cmd/9g/gsubr.c b/src/cmd/9g/gsubr.c
new file mode 100644
index 000000000..e5cd5ed4b
--- /dev/null
+++ b/src/cmd/9g/gsubr.c
@@ -0,0 +1,1707 @@
+// Derived from Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "../../runtime/funcdata.h"
+
+// TODO(rsc): Can make this bigger if we move
+// the text segment up higher in 6l for all GOOS.
+// At the same time, can raise StackBig in ../../runtime/stack.h.
+vlong unmappedzero = 4096;
+
+void
+clearp(Prog *p)
+{
+ *p = zprog;
+ p->as = AEND;
+ p->pc = pcloc;
+ pcloc++;
+}
+
+static int ddumped;
+static Prog *dfirst;
+static Prog *dpc;
+
+/*
+ * generate and return proc with p->as = as,
+ * linked into program. pc is next instruction.
+ */
+Prog*
+prog(int as)
+{
+ Prog *p;
+
+ if(as == ADATA || as == AGLOBL) {
+ if(ddumped)
+ fatal("already dumped data");
+ if(dpc == nil) {
+ dpc = mal(sizeof(*dpc));
+ dfirst = dpc;
+ }
+ p = dpc;
+ dpc = mal(sizeof(*dpc));
+ p->link = dpc;
+ p->reg = 0; // used for flags
+ } else {
+ p = pc;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p->link = pc;
+ }
+
+ if(lineno == 0) {
+ if(debug['K'])
+ warn("prog: line 0");
+ }
+
+ p->as = as;
+ p->lineno = lineno;
+ return p;
+}
+
+void
+dumpdata(void)
+{
+ ddumped = 1;
+ if(dfirst == nil)
+ return;
+ newplist();
+ *pc = *dfirst;
+ pc = dpc;
+ clearp(pc);
+}
+
+/*
+ * generate a branch.
+ * t is ignored.
+ * likely values are for branch prediction:
+ * -1 unlikely
+ * 0 no opinion
+ * +1 likely
+ */
+Prog*
+gbranch(int as, Type *t, int likely)
+{
+ Prog *p;
+
+ USED(t);
+
+ p = prog(as);
+ p->to.type = D_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.offset = likely > 0;
+ }
+ return p;
+}
+
+/*
+ * patch previous branch to jump to to.
+ */
+void
+patch(Prog *p, Prog *to)
+{
+ if(p->to.type != D_BRANCH)
+ fatal("patch: not a branch");
+ p->to.u.branch = to;
+ p->to.offset = to->pc;
+}
+
+Prog*
+unpatch(Prog *p)
+{
+ Prog *q;
+
+ if(p->to.type != D_BRANCH)
+ fatal("unpatch: not a branch");
+ q = p->to.u.branch;
+ p->to.u.branch = P;
+ p->to.offset = 0;
+ return q;
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+newplist(void)
+{
+ Plist *pl;
+
+ pl = linknewplist(ctxt);
+
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ pl->firstpc = pc;
+
+ return pl;
+}
+
+void
+gused(Node *n)
+{
+ gins(ANOP, n, N); // used
+}
+
+Prog*
+gjmp(Prog *to)
+{
+ Prog *p;
+
+ p = gbranch(ABR, T, 0);
+ if(to != P)
+ patch(p, to);
+ return p;
+}
+
+void
+ggloblnod(Node *nam)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, nam, N);
+ p->lineno = nam->lineno;
+ p->from.sym->gotype = linksym(ngotype(nam));
+ p->to.sym = nil;
+ p->to.type = D_CONST;
+ p->to.offset = nam->type->width;
+ if(nam->readonly)
+ p->reg = RODATA;
+ if(nam->type != T && !haspointers(nam->type))
+ p->reg |= NOPTR;
+}
+
+void
+gtrack(Sym *s)
+{
+ Prog *p;
+
+ p = gins(AUSEFIELD, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = linksym(s);
+}
+
+void
+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.sym = linksym(s);
+ p->to.type = D_CONST;
+ p->to.name = D_NONE;
+ p->to.offset = width;
+ p->reg = flags;
+}
+
+int
+isfat(Type *t)
+{
+ if(t != T)
+ switch(t->etype) {
+ case TSTRUCT:
+ case TARRAY:
+ case TSTRING:
+ case TINTER: // maybe remove later
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ */
+void
+afunclit(Addr *a, Node *n)
+{
+ if(a->type == D_CONST && a->name == D_EXTERN) {
+ a->type = D_OREG;
+ a->sym = linksym(n->sym);
+ }
+}
+
+static int resvd[] =
+{
+ REGZERO,
+ REGSP, // reserved for SP, XXX: not reserved in 9c.
+ 30, // for g
+ REGTMP, // REGTMP
+ FREGCVI+NREG,
+ FREGZERO+NREG,
+ FREGHALF+NREG,
+ FREGONE+NREG,
+ FREGTWO+NREG,
+};
+
+void
+ginit(void)
+{
+ int i;
+
+ 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++)
+ reg[i] = 0;
+
+ for(i=0; i<nelem(resvd); i++)
+ reg[resvd[i]]++;
+}
+
+static uintptr regpc[nelem(reg)];
+
+void
+gclean(void)
+{
+ int i;
+
+ for(i=0; i<nelem(resvd); i++)
+ reg[resvd[i]]--;
+
+ for(i=0; i<nelem(reg); i++)
+ if(reg[i])
+ yyerror("reg %R left allocated, %p\n", i, regpc[i]);
+}
+
+int32
+anyregalloc(void)
+{
+ int i, j;
+
+ for(i=0; i<nelem(reg); i++) {
+ if(reg[i] == 0)
+ goto ok;
+ for(j=0; j<nelem(resvd); j++)
+ if(resvd[j] == i)
+ goto ok;
+ return 1;
+ ok:;
+ }
+ return 0;
+}
+
+/*
+ * allocate register of type t, leave in n.
+ * if o != N, o is desired fixed register.
+ * caller must regfree(n).
+ */
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+ int i, et;
+ int fixfree, fltfree;
+
+ if(t == T)
+ fatal("regalloc: t nil");
+ et = simtype[t->etype];
+
+ if(debug['r']) {
+ fixfree = 0;
+ fltfree = 0;
+ for(i = D_R0; i < D_F0+NREG; i++)
+ if(reg[i] == 0) {
+ if(i < D_F0)
+ fixfree++;
+ else
+ fltfree++;
+ }
+ print("regalloc fix %d flt %d free\n", fixfree, fltfree);
+ }
+
+ switch(et) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TPTR32:
+ case TPTR64:
+ case TBOOL:
+ if(o != N && o->op == OREGISTER) {
+ i = o->val.u.reg;
+ if(i >= D_R0+REGMIN && i <= D_R0+REGMAX)
+ goto out;
+ }
+ for(i=D_R0+REGMIN; i<=D_R0+REGMAX; i++)
+ if(reg[i] == 0) {
+ regpc[i] = (uintptr)getcallerpc(&n);
+ goto out;
+ }
+ flusherrors();
+ for(i=D_R0; i<D_R0+NREG; i++)
+ print("R%d %p\n", i, regpc[i]);
+ 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)
+ goto out;
+ }
+ for(i=D_F0+FREGMIN; i<=D_F0+FREGMAX; i++)
+ if(reg[i] == 0) {
+ regpc[i] = (uintptr)getcallerpc(&n);
+ goto out;
+ }
+ flusherrors();
+ for(i=D_F0; i<D_F0+NREG; i++)
+ print("F%d %p\n", i, regpc[i]);
+ fatal("out of floating registers");
+
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ tempname(n, t);
+ return;
+ }
+ fatal("regalloc: unknown type %T", t);
+ return;
+
+out:
+ reg[i]++;
+ nodreg(n, t, i);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ if(n->op == ONAME)
+ return;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ fatal("regfree: not a register");
+ i = n->val.u.reg;
+ if(i == D_R0 + REGSP)
+ 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)
+ regpc[i] = 0;
+}
+
+/*
+ * initialize n to be register r of type t.
+ */
+void
+nodreg(Node *n, Type *t, int r)
+{
+ if(t == T)
+ fatal("nodreg: t nil");
+
+ memset(n, 0, sizeof(*n));
+ n->op = OREGISTER;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.u.reg = r;
+ n->type = t;
+}
+
+/*
+ * initialize n to be indirect of register r; n is type t.
+ */
+void
+nodindreg(Node *n, Type *t, int r)
+{
+ nodreg(n, t, r);
+ n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+ Node *n;
+ NodeList *l;
+ Type *first;
+ Iter savet;
+
+ // entire argument struct, not just one arg
+ if(t->etype == TSTRUCT && t->funarg) {
+ n = nod(ONAME, N, N);
+ n->sym = lookup(".args");
+ n->type = t;
+ first = structfirst(&savet, &t);
+ if(first == nil)
+ fatal("nodarg: bad struct");
+ if(first->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = first->width;
+ n->addable = 1;
+ goto fp;
+ }
+
+ if(t->etype != TFIELD)
+ fatal("nodarg: not field %T", t);
+
+ if(fp == 1) {
+ for(l=curfn->dcl; l; l=l->next) {
+ n = l->n;
+ if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
+ return n;
+ }
+ }
+
+ n = nod(ONAME, N, N);
+ n->type = t->type;
+ n->sym = t->sym;
+
+ if(t->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = t->width;
+ n->addable = 1;
+ n->orig = t->nname;
+
+fp:
+ // Rewrite argument named _ to __,
+ // or else the assignment to _ will be
+ // discarded during code generation.
+ if(isblank(n))
+ n->sym = lookup("__");
+
+ switch(fp) {
+ default:
+ fatal("nodarg %T %d", t, fp);
+
+ case 0: // output arg for calling another function
+ n->op = OINDREG;
+ n->val.u.reg = D_R0+REGSP;
+ n->xoffset += 8;
+ break;
+
+ case 1: // input arg to current function
+ n->class = PPARAM;
+ break;
+
+ case 2: // offset output arg
+fatal("shouldn't be used");
+ n->op = OINDREG;
+ n->val.u.reg = D_R0 + REGSP;
+ n->xoffset += types[tptr]->width;
+ break;
+ }
+ n->typecheck = 1;
+ return n;
+}
+
+/*
+ * generate
+ * as $c, n
+ */
+void
+ginscon(int as, vlong c, Node *n2)
+{
+ Node n1, ntmp;
+
+ nodconst(&n1, types[TINT64], c);
+
+ if(as != AMOVD && (c < -BIG || c > BIG)) {
+ // cannot have more than 16-bit of immediate in ADD, etc.
+ // instead, MOV into register first.
+ regalloc(&ntmp, types[TINT64], N);
+ gins(AMOVD, &n1, &ntmp);
+ gins(as, &ntmp, n2);
+ regfree(&ntmp);
+ return;
+ }
+ gins(as, &n1, n2);
+}
+
+/*
+ * generate
+ * as n, $c (CMP/CMPU)
+ */
+void
+ginscon2(int as, Node *n2, vlong c)
+{
+ Node n1, ntmp;
+
+ nodconst(&n1, types[TINT64], c);
+
+ switch(as) {
+ default:
+ fatal("ginscon2");
+ case ACMP:
+ if(-BIG <= c && c <= BIG) {
+ gins(as, n2, &n1);
+ return;
+ }
+ break;
+ case ACMPU:
+ if(0 <= c && c <= 2*BIG) {
+ gins(as, n2, &n1);
+ return;
+ }
+ break;
+ }
+ // MOV n1 into register first
+ regalloc(&ntmp, types[TINT64], N);
+ gins(AMOVD, &n1, &ntmp);
+ gins(as, n2, &ntmp);
+ regfree(&ntmp);
+}
+
+#define CASE(a,b) (((a)<<16)|((b)<<0))
+/*c2go int CASE(int, int); */
+
+/*
+ * Is this node a memory operand?
+ */
+int
+ismem(Node *n)
+{
+ switch(n->op) {
+ case OITAB:
+ case OSPTR:
+ case OLEN:
+ case OCAP:
+ case OINDREG:
+ case ONAME:
+ case OPARAM:
+ case OCLOSUREVAR:
+ case OADDR:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * set up nodes representing 2^63
+ */
+Node bigi;
+Node bigf;
+
+void
+bignodes(void)
+{
+ static int did;
+
+ if(did)
+ return;
+ did = 1;
+
+ nodconst(&bigi, types[TUINT64], 1);
+ mpshiftfix(bigi.val.u.xval, 63);
+
+ bigf = bigi;
+ bigf.type = types[TFLOAT64];
+ bigf.val.ctype = CTFLT;
+ bigf.val.u.fval = mal(sizeof *bigf.val.u.fval);
+ mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval);
+}
+
+/*
+ * generate move:
+ * t = f
+ * hard part is conversions.
+ */
+void
+gmove(Node *f, Node *t)
+{
+ int a, ft, tt;
+ Type *cvt;
+ Node r1, r2, r3, con;
+ Prog *p1, *p2;
+
+ if(debug['M'])
+ print("gmove %lN -> %lN\n", f, t);
+
+ ft = simsimtype(f->type);
+ tt = simsimtype(t->type);
+ cvt = t->type;
+
+ if(iscomplex[ft] || iscomplex[tt]) {
+ complexmove(f, t);
+ return;
+ }
+
+ // cannot have two memory operands
+ if(ismem(f) && ismem(t))
+ goto hard;
+
+ // convert constant to desired type
+ if(f->op == OLITERAL) {
+ switch(tt) {
+ default:
+ convconst(&con, t->type, &f->val);
+ break;
+
+ case TINT32:
+ case TINT16:
+ case TINT8:
+ convconst(&con, types[TINT64], &f->val);
+ regalloc(&r1, con.type, t);
+ gins(AMOVD, &con, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+ case TUINT32:
+ case TUINT16:
+ case TUINT8:
+ convconst(&con, types[TUINT64], &f->val);
+ regalloc(&r1, con.type, t);
+ gins(AMOVD, &con, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+ }
+
+ f = &con;
+ ft = tt; // so big switch will choose a simple mov
+
+ // constants can't move directly to memory.
+ if(ismem(t)) {
+ goto hard;
+ // float constants come from memory.
+ //if(isfloat[tt])
+ // goto hard;
+
+ // 64-bit immediates are also from memory.
+ //if(isint[tt])
+ // goto hard;
+ //// 64-bit immediates are really 32-bit sign-extended
+ //// unless moving into a register.
+ //if(isint[tt]) {
+ // if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0)
+ // goto hard;
+ // if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0)
+ // goto hard;
+ //}
+ }
+ }
+
+ // value -> value copy, only one memory operand.
+ // figure out the instruction to use.
+ // break out of switch for one-instruction gins.
+ // goto rdst for "destination must be register".
+ // goto hard for "convert to cvt type first".
+ // otherwise handle and return.
+
+ switch(CASE(ft, tt)) {
+ default:
+ fatal("gmove %lT -> %lT", f->type, t->type);
+
+ /*
+ * integer copy and truncate
+ */
+ case CASE(TINT8, TINT8): // same size
+ case CASE(TUINT8, TINT8):
+ case CASE(TINT16, TINT8): // truncate
+ case CASE(TUINT16, TINT8):
+ case CASE(TINT32, TINT8):
+ case CASE(TUINT32, TINT8):
+ case CASE(TINT64, TINT8):
+ case CASE(TUINT64, TINT8):
+ a = AMOVB;
+ break;
+
+ case CASE(TINT8, TUINT8): // same size
+ case CASE(TUINT8, TUINT8):
+ case CASE(TINT16, TUINT8): // truncate
+ case CASE(TUINT16, TUINT8):
+ case CASE(TINT32, TUINT8):
+ case CASE(TUINT32, TUINT8):
+ case CASE(TINT64, TUINT8):
+ case CASE(TUINT64, TUINT8):
+ a = AMOVBZ;
+ break;
+
+ case CASE(TINT16, TINT16): // same size
+ case CASE(TUINT16, TINT16):
+ case CASE(TINT32, TINT16): // truncate
+ case CASE(TUINT32, TINT16):
+ case CASE(TINT64, TINT16):
+ case CASE(TUINT64, TINT16):
+ a = AMOVH;
+ break;
+
+ case CASE(TINT16, TUINT16): // same size
+ case CASE(TUINT16, TUINT16):
+ case CASE(TINT32, TUINT16): // truncate
+ case CASE(TUINT32, TUINT16):
+ case CASE(TINT64, TUINT16):
+ case CASE(TUINT64, TUINT16):
+ a = AMOVHZ;
+ break;
+
+ case CASE(TINT32, TINT32): // same size
+ case CASE(TUINT32, TINT32):
+ case CASE(TINT64, TINT32): // truncate
+ case CASE(TUINT64, TINT32):
+ a = AMOVW;
+ break;
+
+ case CASE(TINT32, TUINT32): // same size
+ case CASE(TUINT32, TUINT32):
+ case CASE(TINT64, TUINT32):
+ case CASE(TUINT64, TUINT32):
+ a = AMOVWZ;
+ break;
+
+ case CASE(TINT64, TINT64): // same size
+ case CASE(TINT64, TUINT64):
+ case CASE(TUINT64, TINT64):
+ case CASE(TUINT64, TUINT64):
+ a = AMOVD;
+ break;
+
+ /*
+ * integer up-conversions
+ */
+ case CASE(TINT8, TINT16): // sign extend int8
+ case CASE(TINT8, TUINT16):
+ case CASE(TINT8, TINT32):
+ case CASE(TINT8, TUINT32):
+ case CASE(TINT8, TINT64):
+ case CASE(TINT8, TUINT64):
+ a = AMOVB;
+ goto rdst;
+
+ case CASE(TUINT8, TINT16): // zero extend uint8
+ case CASE(TUINT8, TUINT16):
+ case CASE(TUINT8, TINT32):
+ case CASE(TUINT8, TUINT32):
+ case CASE(TUINT8, TINT64):
+ case CASE(TUINT8, TUINT64):
+ a = AMOVBZ;
+ goto rdst;
+
+ case CASE(TINT16, TINT32): // sign extend int16
+ case CASE(TINT16, TUINT32):
+ case CASE(TINT16, TINT64):
+ case CASE(TINT16, TUINT64):
+ a = AMOVH;
+ goto rdst;
+
+ case CASE(TUINT16, TINT32): // zero extend uint16
+ case CASE(TUINT16, TUINT32):
+ case CASE(TUINT16, TINT64):
+ case CASE(TUINT16, TUINT64):
+ a = AMOVHZ;
+ goto rdst;
+
+ case CASE(TINT32, TINT64): // sign extend int32
+ case CASE(TINT32, TUINT64):
+ a = AMOVW;
+ goto rdst;
+
+ case CASE(TUINT32, TINT64): // zero extend uint32
+ case CASE(TUINT32, TUINT64):
+ a = AMOVWZ;
+ goto rdst;
+
+ /*
+ * float to integer
+ */
+ case CASE(TFLOAT32, TINT32):
+ case CASE(TFLOAT64, TINT32):
+ case CASE(TFLOAT32, TINT64):
+ case CASE(TFLOAT64, TINT64):
+ case CASE(TFLOAT32, TINT16):
+ case CASE(TFLOAT32, TINT8):
+ case CASE(TFLOAT32, TUINT16):
+ case CASE(TFLOAT32, TUINT8):
+ case CASE(TFLOAT64, TINT16):
+ case CASE(TFLOAT64, TINT8):
+ case CASE(TFLOAT64, TUINT16):
+ case CASE(TFLOAT64, TUINT8):
+ case CASE(TFLOAT32, TUINT32):
+ case CASE(TFLOAT64, TUINT32):
+ case CASE(TFLOAT32, TUINT64):
+ case CASE(TFLOAT64, TUINT64):
+ //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t);
+ //return;
+ // algorithm is:
+ // if small enough, use native float64 -> int64 conversion.
+ // otherwise, subtract 2^63, convert, and add it back.
+ bignodes();
+ regalloc(&r1, types[ft], f);
+ gmove(f, &r1);
+ if(tt == TUINT64) {
+ regalloc(&r2, types[TFLOAT64], N);
+ gmove(&bigf, &r2);
+ gins(AFCMPU, &r1, &r2);
+ p1 = gbranch(optoas(OLT, types[TFLOAT64]), T, +1);
+ gins(AFSUB, &r2, &r1);
+ patch(p1, pc);
+ regfree(&r2);
+ }
+ regalloc(&r2, types[TFLOAT64], N);
+ regalloc(&r3, types[TINT64], t);
+ gins(AFCTIDZ, &r1, &r2);
+ p1 = gins(AFMOVD, &r2, N);
+ p1->to.type = D_OREG;
+ p1->to.reg = REGSP;
+ p1->to.offset = -8;
+ p1 = gins(AMOVD, N, &r3);
+ p1->from.type = D_OREG;
+ 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);
+ gins(AMOVD, &bigi, &r1);
+ gins(AADD, &r1, &r3);
+ patch(p1, pc);
+ }
+ gmove(&r3, t);
+ regfree(&r3);
+ return;
+
+ /*
+ * integer to float
+ */
+ case CASE(TINT32, TFLOAT32):
+ case CASE(TINT32, TFLOAT64):
+ case CASE(TINT64, TFLOAT32):
+ case CASE(TINT64, TFLOAT64):
+ case CASE(TINT16, TFLOAT32):
+ case CASE(TINT16, TFLOAT64):
+ case CASE(TINT8, TFLOAT32):
+ case CASE(TINT8, TFLOAT64):
+ case CASE(TUINT16, TFLOAT32):
+ case CASE(TUINT16, TFLOAT64):
+ case CASE(TUINT8, TFLOAT32):
+ case CASE(TUINT8, TFLOAT64):
+ case CASE(TUINT32, TFLOAT32):
+ case CASE(TUINT32, TFLOAT64):
+ case CASE(TUINT64, TFLOAT32):
+ case CASE(TUINT64, TFLOAT64):
+ //warn("gmove: convert int to float not implemented: %N -> %N\n", f, t);
+ //return;
+ // algorithm is:
+ // if small enough, use native int64 -> uint64 conversion.
+ // otherwise, halve (rounding to odd?), convert, and double.
+ bignodes();
+ regalloc(&r1, types[TINT64], N);
+ gmove(f, &r1);
+ if(ft == TUINT64) {
+ nodreg(&r2, types[TUINT64], D_R0+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.offset = 1;
+ patch(p1, pc);
+ }
+ regalloc(&r2, types[TFLOAT64], t);
+ p1 = gins(AMOVD, &r1, N);
+ p1->to.type = D_OREG;
+ p1->to.reg = REGSP;
+ p1->to.offset = -8;
+ p1 = gins(AFMOVD, N, &r2);
+ p1->from.type = D_OREG;
+ 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);
+ gins(AFMUL, &r1, &r2);
+ patch(p1, pc);
+ }
+ gmove(&r2, t);
+ regfree(&r2);
+ return;
+
+ /*
+ * float to float
+ */
+ case CASE(TFLOAT32, TFLOAT32):
+ a = AFMOVS;
+ break;
+
+ case CASE(TFLOAT64, TFLOAT64):
+ a = AFMOVD;
+ break;
+
+ case CASE(TFLOAT32, TFLOAT64):
+ a = AFMOVS;
+ goto rdst;
+
+ case CASE(TFLOAT64, TFLOAT32):
+ a = AFRSP;
+ goto rdst;
+ }
+
+ gins(a, f, t);
+ return;
+
+rdst:
+ // requires register destination
+ regalloc(&r1, t->type, t);
+ gins(a, f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+hard:
+ // requires register intermediate
+ regalloc(&r1, cvt, t);
+ gmove(f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+}
+
+/*
+ * generate one instruction:
+ * as f, t
+ */
+Prog*
+gins(int as, Node *f, Node *t)
+{
+ int32 w;
+ Prog *p;
+ Addr af, at;
+
+ // TODO(austin): Add self-move test like in 6g (but be careful
+ // of truncation moves)
+
+ memset(&af, 0, sizeof af);
+ memset(&at, 0, sizeof at);
+ if(f != N)
+ naddr(f, &af, 1);
+ if(t != N)
+ naddr(t, &at, 1);
+ p = prog(as);
+ if(f != N)
+ p->from = af;
+ if(t != N)
+ p->to = at;
+ if(as == ATEXT)
+ p->reg = 0;
+ if(debug['g'])
+ print("%P\n", p);
+
+ w = 0;
+ switch(as) {
+ case AMOVB:
+ case AMOVBU:
+ case AMOVBZ:
+ case AMOVBZU:
+ w = 1;
+ break;
+ case AMOVH:
+ case AMOVHU:
+ case AMOVHZ:
+ case AMOVHZU:
+ w = 2;
+ break;
+ case AMOVW:
+ case AMOVWU:
+ case AMOVWZ:
+ case AMOVWZU:
+ w = 4;
+ break;
+ case AMOVD:
+ case AMOVDU:
+ if(af.type == D_CONST)
+ break;
+ w = 8;
+ break;
+ }
+ if(w != 0 && ((f != N && af.width < w) || (t != N && at.type != D_REG && at.width > w))) {
+ dump("f", f);
+ dump("t", t);
+ fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
+ }
+
+ return p;
+}
+
+void
+fixlargeoffset(Node *n)
+{
+ Node a;
+
+ if(n == N)
+ return;
+ if(n->op != OINDREG)
+ return;
+ if(n->val.u.reg == D_R0+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.
+ // this is used only in test/fixedbugs/issue6036.go.
+ print("offset too large: %N\n", n);
+ noimpl;
+ a = *n;
+ a.op = OREGISTER;
+ a.type = types[tptr];
+ a.xoffset = 0;
+ cgen_checknil(&a);
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, &a);
+ n->xoffset = 0;
+ }
+}
+
+/*
+ * generate code to compute n;
+ * make a refer to result.
+ */
+void
+naddr(Node *n, Addr *a, int canemitcode)
+{
+ Sym *s;
+
+ a->type = D_NONE;
+ a->name = D_NONE;
+ a->reg = NREG;
+ a->gotype = nil;
+ a->node = N;
+ a->etype = 0;
+ a->width = 0;
+ if(n == N)
+ return;
+
+ if(n->type != T && n->type->etype != TIDEAL) {
+ dowidth(n->type);
+ a->width = n->type->width;
+ }
+
+ switch(n->op) {
+ default:
+ fatal("naddr: bad %O %D", n->op, a);
+ break;
+
+ case ONAME:
+ a->etype = 0;
+ a->reg = NREG;
+ if(n->type != T)
+ a->etype = simtype[n->type->etype];
+ a->offset = n->xoffset;
+ s = n->sym;
+ a->node = n->orig;
+ //if(a->node >= (Node*)&n)
+ // fatal("stack node");
+ if(s == S)
+ s = lookup(".noname");
+ if(n->method) {
+ if(n->type != T)
+ if(n->type->sym != S)
+ if(n->type->sym->pkg != nil)
+ s = pkglookup(s->name, n->type->sym->pkg);
+ }
+
+ a->type = D_OREG;
+ switch(n->class) {
+ default:
+ fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+ case PEXTERN:
+ a->name = D_EXTERN;
+ break;
+ case PAUTO:
+ a->name = D_AUTO;
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ a->name = D_PARAM;
+ break;
+ case PFUNC:
+ a->name = D_EXTERN;
+ a->type = D_CONST;
+ a->width = widthptr;
+ s = funcsym(s);
+ break;
+ }
+ a->sym = linksym(s);
+ break;
+
+ case OLITERAL:
+ switch(n->val.ctype) {
+ default:
+ fatal("naddr: const %lT", n->type);
+ break;
+ case CTFLT:
+ a->type = D_FCONST;
+ a->u.dval = mpgetflt(n->val.u.fval);
+ break;
+ case CTINT:
+ case CTRUNE:
+ a->sym = nil;
+ a->type = D_CONST;
+ a->offset = mpgetfix(n->val.u.xval);
+ break;
+ case CTSTR:
+ datagostring(n->val.u.sval, a);
+ break;
+ case CTBOOL:
+ a->sym = nil;
+ a->type = D_CONST;
+ a->offset = n->val.u.bval;
+ break;
+ case CTNIL:
+ a->sym = nil;
+ a->type = D_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->sym = nil;
+ break;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->reg = n->val.u.reg;
+ a->sym = linksym(n->sym);
+ a->offset = n->xoffset;
+ if(a->offset != (int32)a->offset)
+ yyerror("offset %lld too large for OINDREG", a->offset);
+ break;
+
+ case OPARAM:
+ // n->left is PHEAP ONAME for stack parameter.
+ // compute address of actual parameter on stack.
+ a->etype = simtype[n->left->type->etype];
+ 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->node = n->left->orig;
+ break;
+
+ case OCLOSUREVAR:
+ if(!curfn->needctxt)
+ fatal("closurevar without needctxt");
+ a->type = D_OREG;
+ a->reg = REGENV;
+ a->offset = n->xoffset;
+ a->sym = nil;
+ break;
+
+ case OCFUNC:
+ naddr(n->left, a, canemitcode);
+ a->sym = linksym(n->left->sym);
+ break;
+
+ case OITAB:
+ // itable of interface value
+ naddr(n->left, a, canemitcode);
+ a->etype = simtype[tptr];
+ if(a->type == D_CONST && a->offset == 0)
+ break; // itab(nil)
+ a->width = widthptr;
+ break;
+
+ case OSPTR:
+ // pointer in a string or slice
+ naddr(n->left, a, canemitcode);
+ a->etype = simtype[tptr];
+ if(a->type == D_CONST && a->offset == 0)
+ break; // ptr(nil)
+ a->offset += Array_array;
+ a->width = widthptr;
+ break;
+
+ case OLEN:
+ // len of string or slice
+ naddr(n->left, a, canemitcode);
+ a->etype = simtype[TINT];
+ if(a->type == D_CONST && a->offset == 0)
+ break; // len(nil)
+ a->offset += Array_nel;
+ a->width = widthint;
+ break;
+
+ case OCAP:
+ // cap of string or slice
+ naddr(n->left, a, canemitcode);
+ a->etype = simtype[TINT];
+ if(a->type == D_CONST && a->offset == 0)
+ break; // cap(nil)
+ a->offset += Array_cap;
+ a->width = widthint;
+ break;
+
+ case OADDR:
+ naddr(n->left, a, canemitcode);
+ a->etype = tptr;
+ switch(a->type) {
+ case D_OREG:
+ a->type = D_CONST;
+ break;
+
+ case D_REG:
+ case D_CONST:
+ break;
+
+ default:
+ fatal("naddr: OADDR %d\n", a->type);
+ }
+ break;
+ }
+}
+
+/*
+ * return Axxx for Oxxx on type t.
+ */
+int
+optoas(int op, Type *t)
+{
+ int a;
+
+ if(t == T)
+ fatal("optoas: t is nil");
+
+ a = AGOK;
+ switch(CASE(op, simtype[t->etype])) {
+ default:
+ fatal("optoas: no entry for op=%O type=%T", op, t);
+ break;
+
+ case CASE(OEQ, TBOOL):
+ case CASE(OEQ, TINT8):
+ case CASE(OEQ, TUINT8):
+ case CASE(OEQ, TINT16):
+ case CASE(OEQ, TUINT16):
+ case CASE(OEQ, TINT32):
+ case CASE(OEQ, TUINT32):
+ case CASE(OEQ, TINT64):
+ case CASE(OEQ, TUINT64):
+ case CASE(OEQ, TPTR32):
+ case CASE(OEQ, TPTR64):
+ case CASE(OEQ, TFLOAT32):
+ case CASE(OEQ, TFLOAT64):
+ a = ABEQ;
+ break;
+
+ case CASE(ONE, TBOOL):
+ case CASE(ONE, TINT8):
+ case CASE(ONE, TUINT8):
+ case CASE(ONE, TINT16):
+ case CASE(ONE, TUINT16):
+ case CASE(ONE, TINT32):
+ case CASE(ONE, TUINT32):
+ case CASE(ONE, TINT64):
+ case CASE(ONE, TUINT64):
+ case CASE(ONE, TPTR32):
+ case CASE(ONE, TPTR64):
+ case CASE(ONE, TFLOAT32):
+ case CASE(ONE, TFLOAT64):
+ a = ABNE;
+ break;
+
+ case CASE(OLT, TINT8): // ACMP
+ case CASE(OLT, TINT16):
+ case CASE(OLT, TINT32):
+ case CASE(OLT, TINT64):
+ case CASE(OLT, TUINT8): // ACMPU
+ case CASE(OLT, TUINT16):
+ case CASE(OLT, TUINT32):
+ case CASE(OLT, TUINT64):
+ case CASE(OLT, TFLOAT32): // AFCMPU
+ case CASE(OLT, TFLOAT64):
+ a = ABLT;
+ break;
+
+ case CASE(OLE, TINT8): // ACMP
+ case CASE(OLE, TINT16):
+ case CASE(OLE, TINT32):
+ case CASE(OLE, TINT64):
+ case CASE(OLE, TUINT8): // ACMPU
+ case CASE(OLE, TUINT16):
+ case CASE(OLE, TUINT32):
+ case CASE(OLE, TUINT64):
+ case CASE(OLE, TFLOAT32): // AFCMPU
+ case CASE(OLE, TFLOAT64):
+ a = ABLE;
+ break;
+
+ case CASE(OGT, TINT8):
+ case CASE(OGT, TINT16):
+ case CASE(OGT, TINT32):
+ case CASE(OGT, TINT64):
+ case CASE(OGT, TUINT8):
+ case CASE(OGT, TUINT16):
+ case CASE(OGT, TUINT32):
+ case CASE(OGT, TUINT64):
+ case CASE(OGT, TFLOAT32):
+ case CASE(OGT, TFLOAT64):
+ a = ABGT;
+ break;
+
+ case CASE(OGE, TINT8):
+ case CASE(OGE, TINT16):
+ case CASE(OGE, TINT32):
+ case CASE(OGE, TINT64):
+ case CASE(OGE, TUINT8):
+ case CASE(OGE, TUINT16):
+ case CASE(OGE, TUINT32):
+ case CASE(OGE, TUINT64):
+ case CASE(OGE, TFLOAT32):
+ case CASE(OGE, TFLOAT64):
+ a = ABGE;
+ break;
+
+ case CASE(OCMP, TBOOL):
+ case CASE(OCMP, TINT8):
+ case CASE(OCMP, TINT16):
+ case CASE(OCMP, TINT32):
+ case CASE(OCMP, TPTR32):
+ case CASE(OCMP, TINT64):
+ a = ACMP;
+ break;
+
+ case CASE(OCMP, TUINT8):
+ case CASE(OCMP, TUINT16):
+ case CASE(OCMP, TUINT32):
+ case CASE(OCMP, TUINT64):
+ case CASE(OCMP, TPTR64):
+ a = ACMPU;
+ break;
+
+ case CASE(OCMP, TFLOAT32):
+ case CASE(OCMP, TFLOAT64):
+ a = AFCMPU;
+ break;
+
+ case CASE(OAS, TBOOL):
+ case CASE(OAS, TINT8):
+ a = AMOVB;
+ break;
+
+ case CASE(OAS, TUINT8):
+ a = AMOVBZ;
+ break;
+
+ case CASE(OAS, TINT16):
+ a = AMOVH;
+ break;
+
+ case CASE(OAS, TUINT16):
+ a = AMOVHZ;
+ break;
+
+ case CASE(OAS, TINT32):
+ a = AMOVW;
+ break;
+
+ case CASE(OAS, TUINT32):
+ case CASE(OAS, TPTR32):
+ a = AMOVWZ;
+ break;
+
+ case CASE(OAS, TINT64):
+ case CASE(OAS, TUINT64):
+ case CASE(OAS, TPTR64):
+ a = AMOVD;
+ break;
+
+ case CASE(OAS, TFLOAT32):
+ a = AFMOVS;
+ break;
+
+ case CASE(OAS, TFLOAT64):
+ a = AFMOVD;
+ break;
+
+ case CASE(OADD, TINT8):
+ case CASE(OADD, TUINT8):
+ case CASE(OADD, TINT16):
+ case CASE(OADD, TUINT16):
+ case CASE(OADD, TINT32):
+ case CASE(OADD, TUINT32):
+ case CASE(OADD, TPTR32):
+ case CASE(OADD, TINT64):
+ case CASE(OADD, TUINT64):
+ case CASE(OADD, TPTR64):
+ a = AADD;
+ break;
+
+ case CASE(OADD, TFLOAT32):
+ a = AFADDS;
+ break;
+
+ case CASE(OADD, TFLOAT64):
+ a = AFADD;
+ break;
+
+ case CASE(OSUB, TINT8):
+ case CASE(OSUB, TUINT8):
+ case CASE(OSUB, TINT16):
+ case CASE(OSUB, TUINT16):
+ case CASE(OSUB, TINT32):
+ case CASE(OSUB, TUINT32):
+ case CASE(OSUB, TPTR32):
+ case CASE(OSUB, TINT64):
+ case CASE(OSUB, TUINT64):
+ case CASE(OSUB, TPTR64):
+ a = ASUB;
+ break;
+
+ case CASE(OSUB, TFLOAT32):
+ a = AFSUBS;
+ break;
+
+ case CASE(OSUB, TFLOAT64):
+ a = AFSUB;
+ break;
+
+ case CASE(OMINUS, TINT8):
+ case CASE(OMINUS, TUINT8):
+ case CASE(OMINUS, TINT16):
+ case CASE(OMINUS, TUINT16):
+ case CASE(OMINUS, TINT32):
+ case CASE(OMINUS, TUINT32):
+ case CASE(OMINUS, TPTR32):
+ case CASE(OMINUS, TINT64):
+ case CASE(OMINUS, TUINT64):
+ case CASE(OMINUS, TPTR64):
+ a = ANEG;
+ break;
+
+ case CASE(OAND, TINT8):
+ case CASE(OAND, TUINT8):
+ case CASE(OAND, TINT16):
+ case CASE(OAND, TUINT16):
+ case CASE(OAND, TINT32):
+ case CASE(OAND, TUINT32):
+ case CASE(OAND, TPTR32):
+ case CASE(OAND, TINT64):
+ case CASE(OAND, TUINT64):
+ case CASE(OAND, TPTR64):
+ a = AAND;
+ break;
+
+ case CASE(OOR, TINT8):
+ case CASE(OOR, TUINT8):
+ case CASE(OOR, TINT16):
+ case CASE(OOR, TUINT16):
+ case CASE(OOR, TINT32):
+ case CASE(OOR, TUINT32):
+ case CASE(OOR, TPTR32):
+ case CASE(OOR, TINT64):
+ case CASE(OOR, TUINT64):
+ case CASE(OOR, TPTR64):
+ a = AOR;
+ break;
+
+ case CASE(OXOR, TINT8):
+ case CASE(OXOR, TUINT8):
+ case CASE(OXOR, TINT16):
+ case CASE(OXOR, TUINT16):
+ case CASE(OXOR, TINT32):
+ case CASE(OXOR, TUINT32):
+ case CASE(OXOR, TPTR32):
+ case CASE(OXOR, TINT64):
+ case CASE(OXOR, TUINT64):
+ case CASE(OXOR, TPTR64):
+ a = AXOR;
+ break;
+
+ // TODO(minux): handle rotates
+ //case CASE(OLROT, TINT8):
+ //case CASE(OLROT, TUINT8):
+ //case CASE(OLROT, TINT16):
+ //case CASE(OLROT, TUINT16):
+ //case CASE(OLROT, TINT32):
+ //case CASE(OLROT, TUINT32):
+ //case CASE(OLROT, TPTR32):
+ //case CASE(OLROT, TINT64):
+ //case CASE(OLROT, TUINT64):
+ //case CASE(OLROT, TPTR64):
+ // a = 0//???; RLDC?
+ // break;
+
+ case CASE(OLSH, TINT8):
+ case CASE(OLSH, TUINT8):
+ case CASE(OLSH, TINT16):
+ case CASE(OLSH, TUINT16):
+ case CASE(OLSH, TINT32):
+ case CASE(OLSH, TUINT32):
+ case CASE(OLSH, TPTR32):
+ case CASE(OLSH, TINT64):
+ case CASE(OLSH, TUINT64):
+ case CASE(OLSH, TPTR64):
+ a = ASLD;
+ break;
+
+ case CASE(ORSH, TUINT8):
+ case CASE(ORSH, TUINT16):
+ case CASE(ORSH, TUINT32):
+ case CASE(ORSH, TPTR32):
+ case CASE(ORSH, TUINT64):
+ case CASE(ORSH, TPTR64):
+ a = ASRD;
+ break;
+
+ case CASE(ORSH, TINT8):
+ case CASE(ORSH, TINT16):
+ case CASE(ORSH, TINT32):
+ case CASE(ORSH, TINT64):
+ a = ASRAD;
+ break;
+
+ // TODO(minux): handle rotates
+ //case CASE(ORROTC, TINT8):
+ //case CASE(ORROTC, TUINT8):
+ //case CASE(ORROTC, TINT16):
+ //case CASE(ORROTC, TUINT16):
+ //case CASE(ORROTC, TINT32):
+ //case CASE(ORROTC, TUINT32):
+ //case CASE(ORROTC, TINT64):
+ //case CASE(ORROTC, TUINT64):
+ // a = 0//??? RLDC??
+ // break;
+
+ case CASE(OHMUL, TINT64):
+ a = AMULHD;
+ break;
+ case CASE(OHMUL, TUINT64):
+ case CASE(OHMUL, TPTR64):
+ a = AMULHDU;
+ break;
+
+ case CASE(OMUL, TINT8):
+ case CASE(OMUL, TINT16):
+ case CASE(OMUL, TINT32):
+ case CASE(OMUL, TINT64):
+ a = AMULLD;
+ break;
+
+ case CASE(OMUL, TUINT8):
+ case CASE(OMUL, TUINT16):
+ case CASE(OMUL, TUINT32):
+ case CASE(OMUL, TPTR32):
+ // don't use word multiply, the high 32-bit are undefined.
+ // fallthrough
+ case CASE(OMUL, TUINT64):
+ case CASE(OMUL, TPTR64):
+ a = AMULLD; // for 64-bit multiplies, signedness doesn't matter.
+ break;
+
+ case CASE(OMUL, TFLOAT32):
+ a = AFMULS;
+ break;
+
+ case CASE(OMUL, TFLOAT64):
+ a = AFMUL;
+ break;
+
+ case CASE(ODIV, TINT8):
+ case CASE(ODIV, TINT16):
+ case CASE(ODIV, TINT32):
+ case CASE(ODIV, TINT64):
+ a = ADIVD;
+ break;
+
+ case CASE(ODIV, TUINT8):
+ case CASE(ODIV, TUINT16):
+ case CASE(ODIV, TUINT32):
+ case CASE(ODIV, TPTR32):
+ case CASE(ODIV, TUINT64):
+ case CASE(ODIV, TPTR64):
+ a = ADIVDU;
+ break;
+
+ case CASE(ODIV, TFLOAT32):
+ a = AFDIVS;
+ break;
+
+ case CASE(ODIV, TFLOAT64):
+ a = AFDIV;
+ break;
+
+ }
+ return a;
+}
+
+enum
+{
+ ODynam = 1<<0,
+ OAddable = 1<<1,
+};
+
+int
+xgen(Node *n, Node *a, int o)
+{
+ // TODO(minux)
+ USED(n); USED(a); USED(o);
+ return -1;
+}
+
+void
+sudoclean(void)
+{
+ return;
+}
+
+/*
+ * generate code to compute address of n,
+ * a reference to a (perhaps nested) field inside
+ * an array or struct.
+ * return 0 on failure, 1 on success.
+ * on success, leaves usable address in a.
+ *
+ * caller is responsible for calling sudoclean
+ * after successful sudoaddable,
+ * to release the register used for a.
+ */
+int
+sudoaddable(int as, Node *n, Addr *a)
+{
+ // TODO(minux)
+ USED(as); USED(n); USED(a);
+ return 0;
+}
diff --git a/src/cmd/9g/opt.h b/src/cmd/9g/opt.h
new file mode 100644
index 000000000..6a07b268f
--- /dev/null
+++ b/src/cmd/9g/opt.h
@@ -0,0 +1,244 @@
+// Derived from Inferno utils/6c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// 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 BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define CLOAD 5
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+/*c2go
+extern Node *Z;
+enum
+{
+ CLOAD = 5,
+ CREF = 5,
+ CINF = 1000,
+ LOOP = 3,
+};
+
+uint32 BLOAD(Reg*);
+uint32 BSTORE(Reg*);
+uint32 LOAD(Reg*);
+uint32 STORE(Reg*);
+*/
+
+// A Reg is a wrapper around a single Prog (one instruction) that holds
+// register optimization information while the optimizer runs.
+// r->prog is the instruction.
+// r->prog->opt points back to r.
+struct Reg
+{
+ Flow f;
+
+ Bits set; // regopt variables written by this instruction.
+ Bits use1; // regopt variables read by prog->from.
+ Bits use2; // regopt variables read by prog->to.
+
+ // refahead/refbehind are the regopt variables whose current
+ // value may be used in the following/preceding instructions
+ // up to a CALL (or the value is clobbered).
+ Bits refbehind;
+ Bits refahead;
+ // calahead/calbehind are similar, but for variables in
+ // instructions that are reachable after hitting at least one
+ // CALL.
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ uint64 regu; // register used bitmap
+};
+#define R ((Reg*)0)
+/*c2go extern Reg *R; */
+
+#define NRGN 600
+/*c2go enum { NRGN = 600 }; */
+
+// A Rgn represents a single regopt variable over a region of code
+// where a register could potentially be dedicated to that variable.
+// The code encompassed by a Rgn is defined by the flow graph,
+// starting at enter, flood-filling forward while varno is refahead
+// and backward while varno is refbehind, and following branches. A
+// single variable may be represented by multiple disjoint Rgns and
+// each Rgn may choose a different register for that variable.
+// Registers are allocated to regions greedily in order of descending
+// cost.
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN int32 exregoffset; // not set
+EXTERN int32 exfregoffset; // not set
+EXTERN Reg zreg;
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+EXTERN int32 regbits;
+EXTERN int32 exregbits; // TODO(austin) not used; remove
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+EXTERN Bits ivar;
+EXTERN Bits ovar;
+EXTERN int change;
+EXTERN int32 maxnr;
+
+EXTERN struct
+{
+ int32 ncvtreg;
+ int32 nspill;
+ int32 ndelmov;
+ int32 nvar;
+} ostats;
+
+/*
+ * reg.c
+ */
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Reg*, Adr*);
+void prop(Reg*, Bits, Bits);
+void synch(Reg*, Bits);
+uint64 allreg(uint64, Rgn*);
+void paint1(Reg*, int);
+uint64 paint2(Reg*, int, int);
+void paint3(Reg*, int, uint64, int);
+void addreg(Adr*, int);
+void dumpone(Flow*, int);
+void dumpit(char*, Flow*, int);
+
+/*
+ * peep.c
+ */
+void peep(Prog*);
+void excise(Flow*);
+int copyu(Prog*, Adr*, Adr*);
+
+uint64 RtoB(int);
+uint64 FtoB(int);
+int BtoR(uint64);
+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
+// standard variants. These bits let us map between variants.
+enum {
+ V_CC = 1<<0, // xCC (affect CR field 0 flags)
+ V_V = 1<<1, // xV (affect SO and OV flags)
+};
+
+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,
+};
diff --git a/src/cmd/9g/peep.c b/src/cmd/9g/peep.c
new file mode 100644
index 000000000..1f430220e
--- /dev/null
+++ b/src/cmd/9g/peep.c
@@ -0,0 +1,984 @@
+// Derived from Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+static int regzer(Addr *a);
+static int subprop(Flow*);
+static int copyprop(Flow*);
+static int copy1(Addr*, Addr*, Flow*, int);
+static int copyas(Addr*, Addr*);
+static int copyau(Addr*, Addr*);
+static int copysub(Addr*, Addr*, Addr*, int);
+static int copysub1(Prog*, Addr*, Addr*, int);
+static int copyau1(Prog *p, Addr *v);
+
+static uint32 gactive;
+
+void
+peep(Prog *firstp)
+{
+ Graph *g;
+ Flow *r, *r1;
+ Prog *p, *p1;
+ int t;
+
+ g = flowstart(firstp, sizeof(Flow));
+ if(g == nil)
+ return;
+ gactive = 0;
+
+loop1:
+ if(debug['P'] && debug['v'])
+ dumpit("loop1", g->start, 0);
+
+ t = 0;
+ for(r=g->start; r!=nil; r=r->link) {
+ p = r->prog;
+ // TODO(austin) Handle smaller moves. arm and amd64
+ // distinguish between moves that moves that *must*
+ // sign/zero extend and moves that don't care so they
+ // can eliminate moves that don't care without
+ // breaking moves that do care. This might let us
+ // simplify or remove the next peep loop, too.
+ if(p->as == AMOVD || p->as == AFMOVD)
+ if(regtyp(&p->to)) {
+ // Try to eliminate reg->reg moves
+ if(regtyp(&p->from))
+ if(p->from.type == p->to.type) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ // 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;
+ p->from.reg = REGZERO;
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+
+ /*
+ * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
+ */
+ for(r=g->start; r!=nil; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ default:
+ continue;
+ case AMOVH:
+ case AMOVHZ:
+ case AMOVB:
+ case AMOVBZ:
+ case AMOVW:
+ case AMOVWZ:
+ if(p->to.type != D_REG)
+ continue;
+ break;
+ }
+ r1 = r->link;
+ if(r1 == nil)
+ continue;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ continue;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ continue;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ continue;
+ excise(r1);
+ }
+
+ if(debug['D'] > 1)
+ goto ret; /* allow following code improvement to be suppressed */
+
+ /*
+ * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R
+ * when OP can set condition codes correctly
+ */
+ for(r=g->start; r!=nil; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case ACMP:
+ case ACMPW: /* always safe? */
+ if(!regzer(&p->to))
+ continue;
+ r1 = r->s1;
+ if(r1 == nil)
+ continue;
+ switch(r1->prog->as) {
+ default:
+ continue;
+ case ABCL:
+ case ABC:
+ /* the conditions can be complex and these are currently little used */
+ continue;
+ case ABEQ:
+ case ABGE:
+ case ABGT:
+ case ABLE:
+ case ABLT:
+ case ABNE:
+ case ABVC:
+ case ABVS:
+ break;
+ }
+ r1 = r;
+ do
+ r1 = uniqp(r1);
+ while (r1 != nil && r1->prog->as == ANOP);
+ if(r1 == nil)
+ continue;
+ p1 = r1->prog;
+ if(p1->to.type != D_REG || p1->to.reg != p->from.reg)
+ continue;
+ switch(p1->as) {
+ case ASUB:
+ case AADD:
+ case AXOR:
+ case AOR:
+ /* irregular instructions */
+ if(p1->from.type == D_CONST)
+ continue;
+ break;
+ }
+ switch(p1->as) {
+ default:
+ continue;
+ case AMOVW:
+ case AMOVD:
+ if(p1->from.type != D_REG)
+ continue;
+ continue;
+ case AANDCC:
+ case AANDNCC:
+ case AORCC:
+ case AORNCC:
+ case AXORCC:
+ case ASUBCC:
+ case ASUBECC:
+ case ASUBMECC:
+ case ASUBZECC:
+ case AADDCC:
+ case AADDCCC:
+ case AADDECC:
+ case AADDMECC:
+ case AADDZECC:
+ case ARLWMICC:
+ case ARLWNMCC:
+ /* don't deal with floating point instructions for now */
+/*
+ case AFABS:
+ case AFADD:
+ case AFADDS:
+ case AFCTIW:
+ case AFCTIWZ:
+ case AFDIV:
+ case AFDIVS:
+ case AFMADD:
+ case AFMADDS:
+ case AFMOVD:
+ case AFMSUB:
+ case AFMSUBS:
+ case AFMUL:
+ case AFMULS:
+ case AFNABS:
+ case AFNEG:
+ case AFNMADD:
+ case AFNMADDS:
+ case AFNMSUB:
+ case AFNMSUBS:
+ case AFRSP:
+ case AFSUB:
+ case AFSUBS:
+ case ACNTLZW:
+ case AMTFSB0:
+ case AMTFSB1:
+*/
+ case AADD:
+ case AADDV:
+ case AADDC:
+ case AADDCV:
+ case AADDME:
+ case AADDMEV:
+ case AADDE:
+ case AADDEV:
+ case AADDZE:
+ case AADDZEV:
+ case AAND:
+ case AANDN:
+ case ADIVW:
+ case ADIVWV:
+ case ADIVWU:
+ case ADIVWUV:
+ case ADIVD:
+ case ADIVDV:
+ case ADIVDU:
+ case ADIVDUV:
+ case AEQV:
+ case AEXTSB:
+ case AEXTSH:
+ case AEXTSW:
+ case AMULHW:
+ case AMULHWU:
+ case AMULLW:
+ case AMULLWV:
+ case AMULHD:
+ case AMULHDU:
+ case AMULLD:
+ case AMULLDV:
+ case ANAND:
+ case ANEG:
+ case ANEGV:
+ case ANOR:
+ case AOR:
+ case AORN:
+ case AREM:
+ case AREMV:
+ case AREMU:
+ case AREMUV:
+ case AREMD:
+ case AREMDV:
+ case AREMDU:
+ case AREMDUV:
+ case ARLWMI:
+ case ARLWNM:
+ case ASLW:
+ case ASRAW:
+ case ASRW:
+ case ASLD:
+ case ASRAD:
+ case ASRD:
+ case ASUB:
+ case ASUBV:
+ case ASUBC:
+ case ASUBCV:
+ case ASUBME:
+ case ASUBMEV:
+ case ASUBE:
+ case ASUBEV:
+ case ASUBZE:
+ case ASUBZEV:
+ case AXOR:
+ t = variant2as(p1->as, as2variant(p1->as) | V_CC);
+ break;
+ }
+ if(debug['D'])
+ print("cmp %P; %P -> ", p1, p);
+ p1->as = t;
+ if(debug['D'])
+ print("%P\n", p1);
+ excise(r);
+ continue;
+ }
+ }
+
+ret:
+ flowend(g);
+}
+
+void
+excise(Flow *r)
+{
+ Prog *p, *l;
+
+ p = r->prog;
+ if(debug['P'] && debug['v'])
+ print("%P ===delete===\n", p);
+ l = p->link;
+ *p = zprog;
+ p->as = ANOP;
+ p->link = l;
+ ostats.ndelmov++;
+}
+
+/*
+ * regzer returns 1 if a's value is 0 (a is R0 or $0)
+ */
+static int
+regzer(Addr *a)
+{
+ if(a->type == D_CONST)
+ if(a->sym == nil && a->reg == NREG)
+ if(a->offset == 0)
+ return 1;
+ if(a->type == D_REG)
+ if(a->reg == REGZERO)
+ return 1;
+ return 0;
+}
+
+int
+regtyp(Adr *a)
+{
+ switch(a->type) {
+ default:
+ return 0;
+ case D_REG:
+ if(a->reg == REGZERO)
+ return 0;
+ case D_FREG:
+ return 1;
+ }
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R1
+ * ADD b, R1 / no use of R2
+ * MOV R1, R2
+ * would be converted to
+ * MOV a, R2
+ * ADD b, R2
+ * MOV R2, R1
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ *
+ * r0 (the argument, not the register) is the MOV at the end of the
+ * above sequences. This returns 1 if it modified any instructions.
+ */
+static int
+subprop(Flow *r0)
+{
+ Prog *p;
+ Addr *v1, *v2;
+ Flow *r;
+ int t;
+ ProgInfo info;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
+ if(uniqs(r) == nil)
+ break;
+ p = r->prog;
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ continue;
+ proginfo(&info, p);
+ if(info.flags & Call)
+ return 0;
+
+ if((info.flags & (RightRead|RightWrite)) == RightWrite) {
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg)
+ goto gotit;
+ }
+
+ if(copyau(&p->from, v2) ||
+ copyau1(p, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub1(p, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub1(p, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->reg;
+ v1->reg = v2->reg;
+ v2->reg = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail (v1->v2 move must remain)
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success (caller can remove v1->v2 move)
+ */
+static int
+copyprop(Flow *r0)
+{
+ Prog *p;
+ Addr *v1, *v2;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2)) {
+ if(debug['P'])
+ print("eliminating self-move\n", r0->prog);
+ return 1;
+ }
+ gactive++;
+ if(debug['P'])
+ print("trying to eliminate %D->%D move from:\n%P\n", v1, v2, r0->prog);
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+// copy1 replaces uses of v2 with v1 starting at r and returns 1 if
+// all uses were rewritten.
+static int
+copy1(Addr *v1, Addr *v2, Flow *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active == gactive) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = gactive;
+ if(debug['P'])
+ print("copy1 replace %D with %D f=%d\n", v2, v1, f);
+ for(; r != nil; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == nil) {
+ // Multiple predecessors; conservatively
+ // assume v1 was set on other path
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, nil);
+ switch(t) {
+ case 2: /* rar, can't split */
+ if(debug['P'])
+ print("; %D rar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %D set; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %D used+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %D used and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub %D->%D\n => %P", v2, v1, p);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %D used+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, nil);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %D set and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+// If s==nil, copyu returns the set/use of v in p; otherwise, it
+// modifies p to replace reads of v with reads of s and returns 0 for
+// success or non-zero for failure.
+//
+// If s==nil, copy returns one of the following values:
+// 1 if v only used
+// 2 if v is set and used in one address (read-alter-rewrite;
+// can't substitute)
+// 3 if v is only set
+// 4 if v is set in one address and used in another (so addresses
+// can be rewritten independently)
+// 0 otherwise (not touched)
+int
+copyu(Prog *p, Addr *v, Addr *s)
+{
+ if(p->from3.type != D_NONE)
+ // 9g never generates a from3
+ print("copyu: from3 (%D) not implemented\n", p->from3);
+
+ switch(p->as) {
+
+ default:
+ print("copyu: can't find %A\n", p->as);
+ return 2;
+
+ case ANOP: /* read p->from, write p->to */
+ case AMOVH:
+ case AMOVHZ:
+ case AMOVB:
+ case AMOVBZ:
+ case AMOVW:
+ case AMOVWZ:
+ case AMOVD:
+
+ case ANEG:
+ case ANEGCC:
+ case AADDME:
+ case AADDMECC:
+ case AADDZE:
+ case AADDZECC:
+ case ASUBME:
+ case ASUBMECC:
+ case ASUBZE:
+ case ASUBZECC:
+
+ case AFCTIW:
+ case AFCTIWZ:
+ case AFCTID:
+ case AFCTIDZ:
+ case AFCFID:
+ case AFCFIDCC:
+ case AFMOVS:
+ case AFMOVD:
+ case AFRSP:
+ case AFNEG:
+ case AFNEGCC:
+ if(s != nil) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ // Update only indirect uses of v in p->to
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ // Fix up implicit from
+ if(p->from.type == D_NONE)
+ p->from = p->to;
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ // p->to only indirectly uses v
+ return 1;
+ return 0;
+
+ case AMOVBU: /* rar p->from, write p->to or read p->from, rar p->to */
+ case AMOVBZU:
+ case AMOVHU:
+ case AMOVHZU:
+ case AMOVWZU:
+ case AMOVDU:
+ if(p->from.type == D_OREG) {
+ if(copyas(&p->from, v))
+ // No s!=nil check; need to fail
+ // anyway in that case
+ return 2;
+ if(s != nil) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v))
+ return 3;
+ } else if (p->to.type == D_OREG) {
+ if(copyas(&p->to, v))
+ return 2;
+ if(s != nil) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ } else {
+ print("copyu: bad %P\n", p);
+ }
+ return 0;
+
+ case ARLWMI: /* read p->from, read p->reg, rar p->to */
+ case ARLWMICC:
+ if(copyas(&p->to, v))
+ return 2;
+ /* fall through */
+
+ case AADD: /* read p->from, read p->reg, write p->to */
+ case AADDC:
+ case AADDE:
+ case ASUB:
+ case ASLW:
+ case ASRW:
+ case ASRAW:
+ case ASLD:
+ case ASRD:
+ case ASRAD:
+ case AOR:
+ case AORCC:
+ case AORN:
+ case AORNCC:
+ case AAND:
+ case AANDCC:
+ case AANDN:
+ case AANDNCC:
+ case ANAND:
+ case ANANDCC:
+ case ANOR:
+ case ANORCC:
+ case AXOR:
+ case AMULHW:
+ case AMULHWU:
+ case AMULLW:
+ case AMULLD:
+ case ADIVW:
+ case ADIVD:
+ case ADIVWU:
+ case ADIVDU:
+ case AREM:
+ case AREMU:
+ case AREMD:
+ case AREMDU:
+ case ARLWNM:
+ case ARLWNMCC:
+
+ case AFADDS:
+ case AFADD:
+ case AFSUBS:
+ case AFSUB:
+ case AFMULS:
+ case AFMUL:
+ case AFDIVS:
+ case AFDIV:
+ if(s != nil) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(copysub1(p, v, s, 1))
+ return 1;
+ // Update only indirect uses of v in p->to
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(p->reg == NREG)
+ // Fix up implicit reg (e.g., ADD
+ // R3,R4 -> ADD R3,R4,R4) so we can
+ // update reg and to separately.
+ p->reg = p->to.reg;
+ if(copyau(&p->from, v))
+ return 4;
+ if(copyau1(p, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABEQ:
+ case ABGT:
+ case ABGE:
+ case ABLT:
+ case ABLE:
+ case ABNE:
+ case ABVC:
+ case ABVS:
+ return 0;
+
+ case ACHECKNIL: /* read p->from */
+ case ACMP: /* read p->from, read p->to */
+ case ACMPU:
+ case ACMPW:
+ case ACMPWU:
+ case AFCMPO:
+ case AFCMPU:
+ if(s != nil) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub(&p->to, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABR: /* read p->to */
+ // 9g never generates a branch to a GPR (this isn't
+ // even a normal instruction; liblink turns it in to a
+ // mov and a branch).
+ if(s != nil) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARETURN: /* funny */
+ if(s != nil)
+ return 0;
+ // All registers die at this point, so claim
+ // everything is set (and not used).
+ return 3;
+
+ case ABL: /* funny */
+ if(v->type == D_REG) {
+ if(v->reg <= REGEXT && v->reg > exregoffset)
+ return 2;
+ if(v->reg == REGARG)
+ return 2;
+ }
+ if(v->type == D_FREG) {
+ if(v->reg <= FREGEXT && v->reg > exfregoffset)
+ return 2;
+ }
+ if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg)
+ return 2;
+
+ if(s != nil) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ 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->reg == 0)
+ return 1;
+ if(v->reg == 3)
+ return 2;
+ }
+ return 0;
+
+ 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->reg == 3 || v->reg == 4)
+ return 2;
+ if(v->reg == 5)
+ return 3;
+ }
+ return 0;
+
+ case ATEXT: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGARG)
+ return 3;
+ return 0;
+
+ case APCDATA:
+ case AFUNCDATA:
+ case AVARDEF:
+ case AVARKILL:
+ return 0;
+ }
+}
+
+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
+// register in v. If a is the to operand, this means this operation
+// writes the register in v.
+static int
+copyas(Addr *a, Addr *v)
+{
+ if(regtyp(v))
+ if(a->type == v->type)
+ if(a->reg == v->reg)
+ return 1;
+ return 0;
+}
+
+// copyau returns 1 if a either directly or indirectly addresses the
+// same register as v.
+//
+// If a is the from operand, this means this operation reads the
+// register in v. If a is the to operand, this means the operation
+// either reads or writes the register in v (if !copyas(a, v), then
+// the operation reads the register in v).
+static int
+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->reg == a->reg)
+ return 1;
+ return 0;
+}
+
+// copyau1 returns 1 if p->reg references the same register as v and v
+// is a direct reference.
+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);
+ return 1;
+ }
+ return 0;
+}
+
+// copysub replaces v with s in a if f!=0 or indicates it if could if f==0.
+// Returns 1 on failure to substitute (it always succeeds on power64).
+static int
+copysub(Addr *a, Addr *v, Addr *s, int f)
+{
+ if(f)
+ if(copyau(a, v))
+ a->reg = s->reg;
+ return 0;
+}
+
+// copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0.
+// Returns 1 on failure to substitute (it always succeeds on power64).
+static int
+copysub1(Prog *p1, Addr *v, Addr *s, int f)
+{
+ if(f)
+ if(copyau1(p1, v))
+ p1->reg = s->reg;
+ return 0;
+}
+
+int
+sameaddr(Addr *a, Addr *v)
+{
+ if(a->type != v->type)
+ 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;
+ return 0;
+}
+
+int
+smallindir(Addr *a, Addr *reg)
+{
+ return reg->type == D_REG && a->type == D_OREG &&
+ a->reg == reg->reg &&
+ 0 <= a->offset && a->offset < 4096;
+}
+
+int
+stackaddr(Addr *a)
+{
+ return a->type == D_REG && a->reg == REGSP;
+}
diff --git a/src/cmd/9g/prog.c b/src/cmd/9g/prog.c
new file mode 100644
index 000000000..7c0f0c795
--- /dev/null
+++ b/src/cmd/9g/prog.c
@@ -0,0 +1,307 @@
+// 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.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+enum {
+ LeftRdwr = LeftRead | LeftWrite,
+ RightRdwr = RightRead | RightWrite,
+};
+
+// This table gives the basic information about instruction
+// generated by the compiler and processed in the optimizer.
+// See opt.h for bit definitions.
+//
+// Instructions not generated need not be listed.
+// As an exception to that rule, we typically write down all the
+// size variants of an operation even if we just use a subset.
+//
+// The table is formatted for 8-space tabs.
+static ProgInfo progtable[ALAST] = {
+ [ATYPE]= {Pseudo | Skip},
+ [ATEXT]= {Pseudo},
+ [AFUNCDATA]= {Pseudo},
+ [APCDATA]= {Pseudo},
+ [AUNDEF]= {Break},
+ [AUSEFIELD]= {OK},
+ [ACHECKNIL]= {LeftRead},
+ [AVARDEF]= {Pseudo | RightWrite},
+ [AVARKILL]= {Pseudo | RightWrite},
+
+ // NOP is an internal no-op that also stands
+ // for USED and SET annotations, not the Power opcode.
+ [ANOP]= {LeftRead | RightWrite},
+
+ // Integer
+ [AADD]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [ASUB]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [ANEG]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [AAND]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [AOR]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [AXOR]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [AMULLD]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [AMULLW]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AMULHD]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AMULHDU]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ADIVD]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [ADIVDU]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [ASLD]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [ASRD]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [ASRAD]= {SizeQ | LeftRead | RegRead | RightWrite},
+ [ACMP]= {SizeQ | LeftRead | RightRead},
+ [ACMPU]= {SizeQ | LeftRead | RightRead},
+ [ATD]= {SizeQ | RightRead},
+
+ // Floating point.
+ [AFADD]= {SizeD | LeftRead | RegRead | RightWrite},
+ [AFADDS]= {SizeF | LeftRead | RegRead | RightWrite},
+ [AFSUB]= {SizeD | LeftRead | RegRead | RightWrite},
+ [AFSUBS]= {SizeF | LeftRead | RegRead | RightWrite},
+ [AFMUL]= {SizeD | LeftRead | RegRead | RightWrite},
+ [AFMULS]= {SizeF | LeftRead | RegRead | RightWrite},
+ [AFDIV]= {SizeD | LeftRead | RegRead | RightWrite},
+ [AFDIVS]= {SizeF | LeftRead | RegRead | RightWrite},
+ [AFCTIDZ]= {SizeF | LeftRead | RegRead | RightWrite},
+ [AFCFID]= {SizeF | LeftRead | RegRead | RightWrite},
+ [AFCMPU]= {SizeD | LeftRead | RightRead},
+ [AFRSP]= {SizeD | LeftRead | RightWrite | Conv},
+
+ // Moves
+ [AMOVB]= {SizeB | LeftRead | RightWrite | Move | Conv},
+ [AMOVBU]= {SizeB | LeftRead | RightWrite | Move | Conv | PostInc},
+ [AMOVBZ]= {SizeB | LeftRead | RightWrite | Move | Conv},
+ [AMOVH]= {SizeW | LeftRead | RightWrite | Move | Conv},
+ [AMOVHU]= {SizeW | LeftRead | RightWrite | Move | Conv | PostInc},
+ [AMOVHZ]= {SizeW | LeftRead | RightWrite | Move | Conv},
+ [AMOVW]= {SizeL | LeftRead | RightWrite | Move | Conv},
+ // there is no AMOVWU.
+ [AMOVWZU]= {SizeL | LeftRead | RightWrite | Move | Conv | PostInc},
+ [AMOVWZ]= {SizeL | LeftRead | RightWrite | Move | Conv},
+ [AMOVD]= {SizeQ | LeftRead | RightWrite | Move},
+ [AMOVDU]= {SizeQ | LeftRead | RightWrite | Move | PostInc},
+ [AFMOVS]= {SizeF | LeftRead | RightWrite | Move | Conv},
+ [AFMOVD]= {SizeD | LeftRead | RightWrite | Move},
+
+ // Jumps
+ [ABR]= {Jump | Break},
+ [ABL]= {Call},
+ [ABEQ]= {Cjmp},
+ [ABNE]= {Cjmp},
+ [ABGE]= {Cjmp},
+ [ABLT]= {Cjmp},
+ [ABGT]= {Cjmp},
+ [ABLE]= {Cjmp},
+ [ARETURN]= {Break},
+
+ [ADUFFZERO]= {Call},
+ [ADUFFCOPY]= {Call},
+};
+
+static void
+initproginfo(void)
+{
+ static int initialized;
+ int addvariant[] = {V_CC, V_V, V_CC|V_V};
+ int as, as2, i, variant;
+
+ if(initialized)
+ return;
+ initialized = 1;
+
+ // Perform one-time expansion of instructions in progtable to
+ // their CC, V, and VCC variants
+ for(as=0; as<nelem(progtable); as++) {
+ if(progtable[as].flags == 0)
+ continue;
+ variant = as2variant(as);
+ for(i=0; i<nelem(addvariant); i++) {
+ as2 = variant2as(as, variant | addvariant[i]);
+ if(as2 != 0 && progtable[as2].flags == 0)
+ progtable[as2] = progtable[as];
+ }
+ }
+}
+
+void
+proginfo(ProgInfo *info, Prog *p)
+{
+ initproginfo();
+
+ *info = progtable[p->as];
+ if(info->flags == 0) {
+ *info = progtable[AADD];
+ fatal("proginfo: unknown instruction %P", p);
+ }
+
+ if((info->flags & RegRead) && p->reg == NREG) {
+ info->flags &= ~RegRead;
+ info->flags |= /*CanRegRead |*/ RightRead;
+ }
+
+ if((p->from.type == D_OREG || p->from.type == D_CONST) && p->from.reg != NREG) {
+ 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) {
+ 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)) {
+ info->flags &= ~LeftRead;
+ info->flags |= LeftAddr;
+ }
+
+ if(p->as == ADUFFZERO) {
+ info->reguse |= (1<<D_R0) | RtoB(3);
+ info->regset |= RtoB(3);
+ }
+ 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);
+ }
+}
+
+// Instruction variants table. Initially this contains entries only
+// for the "base" form of each instruction. On the first call to
+// as2variant or variant2as, we'll add the variants to the table.
+static int varianttable[ALAST][4] = {
+ [AADD]= {AADD, AADDCC, AADDV, AADDVCC},
+ [AADDC]= {AADDC, AADDCCC, AADDCV, AADDCVCC},
+ [AADDE]= {AADDE, AADDECC, AADDEV, AADDEVCC},
+ [AADDME]= {AADDME, AADDMECC, AADDMEV, AADDMEVCC},
+ [AADDZE]= {AADDZE, AADDZECC, AADDZEV, AADDZEVCC},
+ [AAND]= {AAND, AANDCC, 0, 0},
+ [AANDN]= {AANDN, AANDNCC, 0, 0},
+ [ACNTLZD]= {ACNTLZD, ACNTLZDCC, 0, 0},
+ [ACNTLZW]= {ACNTLZW, ACNTLZWCC, 0, 0},
+ [ADIVD]= {ADIVD, ADIVDCC, ADIVDV, ADIVDVCC},
+ [ADIVDU]= {ADIVDU, ADIVDUCC, ADIVDUV, ADIVDUVCC},
+ [ADIVW]= {ADIVW, ADIVWCC, ADIVWV, ADIVWVCC},
+ [ADIVWU]= {ADIVWU, ADIVWUCC, ADIVWUV, ADIVWUVCC},
+ [AEQV]= {AEQV, AEQVCC, 0, 0},
+ [AEXTSB]= {AEXTSB, AEXTSBCC, 0, 0},
+ [AEXTSH]= {AEXTSH, AEXTSHCC, 0, 0},
+ [AEXTSW]= {AEXTSW, AEXTSWCC, 0, 0},
+ [AFABS]= {AFABS, AFABSCC, 0, 0},
+ [AFADD]= {AFADD, AFADDCC, 0, 0},
+ [AFADDS]= {AFADDS, AFADDSCC, 0, 0},
+ [AFCFID]= {AFCFID, AFCFIDCC, 0, 0},
+ [AFCTID]= {AFCTID, AFCTIDCC, 0, 0},
+ [AFCTIDZ]= {AFCTIDZ, AFCTIDZCC, 0, 0},
+ [AFCTIW]= {AFCTIW, AFCTIWCC, 0, 0},
+ [AFCTIWZ]= {AFCTIWZ, AFCTIWZCC, 0, 0},
+ [AFDIV]= {AFDIV, AFDIVCC, 0, 0},
+ [AFDIVS]= {AFDIVS, AFDIVSCC, 0, 0},
+ [AFMADD]= {AFMADD, AFMADDCC, 0, 0},
+ [AFMADDS]= {AFMADDS, AFMADDSCC, 0, 0},
+ [AFMOVD]= {AFMOVD, AFMOVDCC, 0, 0},
+ [AFMSUB]= {AFMSUB, AFMSUBCC, 0, 0},
+ [AFMSUBS]= {AFMSUBS, AFMSUBSCC, 0, 0},
+ [AFMUL]= {AFMUL, AFMULCC, 0, 0},
+ [AFMULS]= {AFMULS, AFMULSCC, 0, 0},
+ [AFNABS]= {AFNABS, AFNABSCC, 0, 0},
+ [AFNEG]= {AFNEG, AFNEGCC, 0, 0},
+ [AFNMADD]= {AFNMADD, AFNMADDCC, 0, 0},
+ [AFNMADDS]= {AFNMADDS, AFNMADDSCC, 0, 0},
+ [AFNMSUB]= {AFNMSUB, AFNMSUBCC, 0, 0},
+ [AFNMSUBS]= {AFNMSUBS, AFNMSUBSCC, 0, 0},
+ [AFRES]= {AFRES, AFRESCC, 0, 0},
+ [AFRSP]= {AFRSP, AFRSPCC, 0, 0},
+ [AFRSQRTE]= {AFRSQRTE, AFRSQRTECC, 0, 0},
+ [AFSEL]= {AFSEL, AFSELCC, 0, 0},
+ [AFSQRT]= {AFSQRT, AFSQRTCC, 0, 0},
+ [AFSQRTS]= {AFSQRTS, AFSQRTSCC, 0, 0},
+ [AFSUB]= {AFSUB, AFSUBCC, 0, 0},
+ [AFSUBS]= {AFSUBS, AFSUBSCC, 0, 0},
+ [AMTFSB0]= {AMTFSB0, AMTFSB0CC, 0, 0},
+ [AMTFSB1]= {AMTFSB1, AMTFSB1CC, 0, 0},
+ [AMULHD]= {AMULHD, AMULHDCC, 0, 0},
+ [AMULHDU]= {AMULHDU, AMULHDUCC, 0, 0},
+ [AMULHW]= {AMULHW, AMULHWCC, 0, 0},
+ [AMULHWU]= {AMULHWU, AMULHWUCC, 0, 0},
+ [AMULLD]= {AMULLD, AMULLDCC, AMULLDV, AMULLDVCC},
+ [AMULLW]= {AMULLW, AMULLWCC, AMULLWV, AMULLWVCC},
+ [ANAND]= {ANAND, ANANDCC, 0, 0},
+ [ANEG]= {ANEG, ANEGCC, ANEGV, ANEGVCC},
+ [ANOR]= {ANOR, ANORCC, 0, 0},
+ [AOR]= {AOR, AORCC, 0, 0},
+ [AORN]= {AORN, AORNCC, 0, 0},
+ [AREM]= {AREM, AREMCC, AREMV, AREMVCC},
+ [AREMD]= {AREMD, AREMDCC, AREMDV, AREMDVCC},
+ [AREMDU]= {AREMDU, AREMDUCC, AREMDUV, AREMDUVCC},
+ [AREMU]= {AREMU, AREMUCC, AREMUV, AREMUVCC},
+ [ARLDC]= {ARLDC, ARLDCCC, 0, 0},
+ [ARLDCL]= {ARLDCL, ARLDCLCC, 0, 0},
+ [ARLDCR]= {ARLDCR, ARLDCRCC, 0, 0},
+ [ARLDMI]= {ARLDMI, ARLDMICC, 0, 0},
+ [ARLWMI]= {ARLWMI, ARLWMICC, 0, 0},
+ [ARLWNM]= {ARLWNM, ARLWNMCC, 0, 0},
+ [ASLD]= {ASLD, ASLDCC, 0, 0},
+ [ASLW]= {ASLW, ASLWCC, 0, 0},
+ [ASRAD]= {ASRAD, ASRADCC, 0, 0},
+ [ASRAW]= {ASRAW, ASRAWCC, 0, 0},
+ [ASRD]= {ASRD, ASRDCC, 0, 0},
+ [ASRW]= {ASRW, ASRWCC, 0, 0},
+ [ASUB]= {ASUB, ASUBCC, ASUBV, ASUBVCC},
+ [ASUBC]= {ASUBC, ASUBCCC, ASUBCV, ASUBCVCC},
+ [ASUBE]= {ASUBE, ASUBECC, ASUBEV, ASUBEVCC},
+ [ASUBME]= {ASUBME, ASUBMECC, ASUBMEV, ASUBMEVCC},
+ [ASUBZE]= {ASUBZE, ASUBZECC, ASUBZEV, ASUBZEVCC},
+ [AXOR]= {AXOR, AXORCC, 0, 0},
+};
+
+static void
+initvariants(void)
+{
+ static int initialized;
+ int i, j;
+
+ if(initialized)
+ return;
+ initialized = 1;
+
+ for(i=0; i<nelem(varianttable); i++) {
+ if(varianttable[i][0] == 0) {
+ // Instruction has no variants
+ varianttable[i][0] = i;
+ continue;
+ }
+ // Copy base form to other variants
+ if(varianttable[i][0] == i) {
+ for(j=0; j<nelem(varianttable[i]); j++)
+ memmove(&varianttable[varianttable[i][j]], &varianttable[i], sizeof(varianttable[i]));
+ }
+ }
+}
+
+// as2variant returns the variant (V_*) flags of instruction as.
+int
+as2variant(int as)
+{
+ int i;
+ initvariants();
+ for(i=0; i<nelem(varianttable[as]); i++)
+ if(varianttable[as][i] == as)
+ return i;
+ fatal("as2variant: instruction %A is not a variant of itself", as);
+ return 0;
+}
+
+// variant2as returns the instruction as with the given variant (V_*) flags.
+// If no such variant exists, this returns 0.
+int
+variant2as(int as, int flags)
+{
+ initvariants();
+ return varianttable[as][flags];
+}
diff --git a/src/cmd/9g/reg.c b/src/cmd/9g/reg.c
new file mode 100644
index 000000000..2d8dbc4f1
--- /dev/null
+++ b/src/cmd/9g/reg.c
@@ -0,0 +1,1346 @@
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+#define NREGVAR 64 /* 32 general + 32 floating */
+#define REGBITS ((uint64)0xffffffffffffffffull)
+/*c2go enum {
+ NREGVAR = 64,
+ REGBITS = 0xffffffffffffffff,
+};
+*/
+
+static Reg* firstr;
+static int first = 1;
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+static void
+setaddrs(Bits bit)
+{
+ int i, n;
+ Var *v;
+ Node *node;
+
+ while(bany(&bit)) {
+ // convert each bit to a variable
+ i = bnum(bit);
+ node = var[i].node;
+ n = var[i].name;
+ biclr(&bit, i);
+
+ // disable all pieces of that variable
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->node == node && v->name == n)
+ v->addr = 2;
+ }
+ }
+}
+
+static char* regname[] = {
+ ".R0",
+ ".R1",
+ ".R2",
+ ".R3",
+ ".R4",
+ ".R5",
+ ".R6",
+ ".R7",
+ ".R8",
+ ".R9",
+ ".R10",
+ ".R11",
+ ".R12",
+ ".R13",
+ ".R14",
+ ".R15",
+ ".R16",
+ ".R17",
+ ".R18",
+ ".R19",
+ ".R20",
+ ".R21",
+ ".R22",
+ ".R23",
+ ".R24",
+ ".R25",
+ ".R26",
+ ".R27",
+ ".R28",
+ ".R29",
+ ".R30",
+ ".R31",
+ ".F0",
+ ".F1",
+ ".F2",
+ ".F3",
+ ".F4",
+ ".F5",
+ ".F6",
+ ".F7",
+ ".F8",
+ ".F9",
+ ".F10",
+ ".F11",
+ ".F12",
+ ".F13",
+ ".F14",
+ ".F15",
+ ".F16",
+ ".F17",
+ ".F18",
+ ".F19",
+ ".F20",
+ ".F21",
+ ".F22",
+ ".F23",
+ ".F24",
+ ".F25",
+ ".F26",
+ ".F27",
+ ".F28",
+ ".F29",
+ ".F30",
+ ".F31",
+};
+
+static Node* regnodes[NREGVAR];
+
+static void walkvardef(Node *n, Reg *r, int active);
+
+void
+regopt(Prog *firstp)
+{
+ Reg *r, *r1;
+ Prog *p;
+ Graph *g;
+ ProgInfo info;
+ int i, z, active;
+ uint64 vreg, usedreg;
+ Bits bit;
+
+ if(first) {
+ fmtinstall('Q', Qconv);
+ first = 0;
+ }
+
+ mergetemp(firstp);
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ nvar = NREGVAR;
+ memset(var, 0, NREGVAR*sizeof var[0]);
+ for(i=0; i<NREGVAR; i++) {
+ if(regnodes[i] == N)
+ regnodes[i] = newname(lookup(regname[i]));
+ var[i].node = regnodes[i];
+ }
+
+ // Exclude registers with fixed functions
+ regbits = (1<<D_R0)|RtoB(REGSP)|RtoB(REGG);
+ // 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);
+ externs = zbits;
+ params = zbits;
+ consts = zbits;
+ addrs = zbits;
+ ivar = zbits;
+ ovar = zbits;
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ g = flowstart(firstp, sizeof(Reg));
+ if(g == nil) {
+ for(i=0; i<nvar; i++)
+ var[i].node->opt = nil;
+ return;
+ }
+
+ firstr = (Reg*)g->start;
+
+ for(r = firstr; r != R; r = (Reg*)r->f.link) {
+ p = r->f.prog;
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ continue;
+ proginfo(&info, p);
+
+ // Avoid making variables for direct-called functions.
+ if(p->as == ABL && p->to.name == D_EXTERN)
+ continue;
+
+ // from vs to doesn't matter for registers
+ r->use1.b[0] |= info.reguse | info.regindex;
+ r->set.b[0] |= info.regset;
+
+ // Compute used register for from
+ bit = mkvar(r, &p->from);
+ if(info.flags & LeftAddr)
+ setaddrs(bit);
+ if(info.flags & LeftRead)
+ for(z=0; z<BITS; z++)
+ 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);
+ }
+
+ // Currently we never generate three register forms.
+ // If we do, this will need to change.
+ if(p->from3.type != D_NONE)
+ fatal("regopt not implemented for from3");
+
+ // Compute used register for to
+ bit = mkvar(r, &p->to);
+ if(info.flags & RightAddr)
+ setaddrs(bit);
+ if(info.flags & RightRead)
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ if(info.flags & RightWrite)
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ }
+
+ for(i=0; i<nvar; i++) {
+ Var *v = var+i;
+ if(v->addr) {
+ bit = blsh(i);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ }
+
+ if(debug['R'] && debug['v'])
+ print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
+ i, v->addr, v->etype, v->width, v->node, v->offset);
+ }
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass1", &firstr->f, 1);
+
+ /*
+ * pass 2
+ * find looping structure
+ */
+ flowrpo(g);
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass2", &firstr->f, 1);
+
+ /*
+ * pass 2.5
+ * iterate propagating fat vardef covering forward
+ * r->act records vars with a VARDEF since the last CALL.
+ * (r->act will be reused in pass 5 for something else,
+ * but we'll be done with it by then.)
+ */
+ active = 0;
+ for(r = firstr; r != R; r = (Reg*)r->f.link) {
+ r->f.active = 0;
+ r->act = zbits;
+ }
+ 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) {
+ active++;
+ walkvardef(p->to.node, r, active);
+ }
+ }
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = (Reg*)r->f.link)
+ r->f.active = 0;
+ for(r = firstr; r != R; r = (Reg*)r->f.link)
+ if(r->f.prog->as == ARET)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = (Reg*)r->f.link;
+ if(r1 && r1->f.active && !r->f.active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass3", &firstr->f, 1);
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = (Reg*)r->f.link)
+ r->f.active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass4", &firstr->f, 1);
+
+ /*
+ * pass 4.5
+ * move register pseudo-variables into regu.
+ */
+ for(r = firstr; r != R; r = (Reg*)r->f.link) {
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+ r->set.b[0] &= ~REGBITS;
+ r->use1.b[0] &= ~REGBITS;
+ r->use2.b[0] &= ~REGBITS;
+ r->refbehind.b[0] &= ~REGBITS;
+ r->refahead.b[0] &= ~REGBITS;
+ r->calbehind.b[0] &= ~REGBITS;
+ r->calahead.b[0] &= ~REGBITS;
+ r->regdiff.b[0] &= ~REGBITS;
+ r->act.b[0] &= ~REGBITS;
+ }
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass4.5", &firstr->f, 1);
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit) && !r->f.refset) {
+ // should never happen - all variables are preset
+ if(debug['w'])
+ print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
+ r->f.refset = 1;
+ }
+ }
+ for(r = firstr; r != R; r = (Reg*)r->f.link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = (Reg*)r->f.link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit) && !r->f.refset) {
+ if(debug['w'])
+ print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
+ r->f.refset = 1;
+ excise(&r->f);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ paint1(r, i);
+ biclr(&bit, i);
+ if(change <= 0)
+ continue;
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ if(debug['R'] && debug['v'])
+ print("too many regions\n");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass5", &firstr->f, 1);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ if(debug['R'] && debug['v'])
+ print("\nregisterizing\n");
+ for(i=0; i<nregion; i++) {
+ if(debug['R'] && debug['v'])
+ print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
+ bit = blsh(rgp->varno);
+ usedreg = paint2(rgp->enter, rgp->varno, 0);
+ vreg = allreg(usedreg, rgp);
+ if(rgp->regno != 0) {
+ if(debug['R'] && debug['v']) {
+ Var *v;
+
+ v = var + rgp->varno;
+ print("registerize %N+%lld (bit=%2d et=%2E) in %R usedreg=%llx vreg=%llx\n",
+ v->node, v->offset, rgp->varno, v->etype, rgp->regno, usedreg, vreg);
+ }
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ }
+ rgp++;
+ }
+
+ /*
+ * free aux structures. peep allocates new ones.
+ */
+ for(i=0; i<nvar; i++)
+ var[i].node->opt = nil;
+ flowend(g);
+ firstr = R;
+
+ if(debug['R'] && debug['v']) {
+ // Rebuild flow graph, since we inserted instructions
+ g = flowstart(firstp, sizeof(Reg));
+ firstr = (Reg*)g->start;
+ dumpit("pass6", &firstr->f, 1);
+ flowend(g);
+ firstr = R;
+ }
+
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep(firstp);
+
+ /*
+ * eliminate nops
+ */
+ 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)
+ while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
+ p->to.u.branch = p->to.u.branch->link;
+ }
+
+ if(debug['R']) {
+ if(ostats.ncvtreg ||
+ ostats.nspill ||
+ ostats.ndelmov ||
+ ostats.nvar ||
+ 0)
+ print("\nstats\n");
+
+ if(ostats.ncvtreg)
+ print(" %4d cvtreg\n", ostats.ncvtreg);
+ if(ostats.nspill)
+ print(" %4d spill\n", ostats.nspill);
+ if(ostats.ndelmov)
+ print(" %4d delmov\n", ostats.ndelmov);
+ if(ostats.nvar)
+ print(" %4d var\n", ostats.nvar);
+
+ memset(&ostats, 0, sizeof(ostats));
+ }
+
+ return;
+}
+
+static void
+walkvardef(Node *n, Reg *r, int active)
+{
+ Reg *r1, *r2;
+ int bn;
+ Var *v;
+
+ for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
+ if(r1->f.active == active)
+ break;
+ r1->f.active = active;
+ if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
+ break;
+ for(v=n->opt; v!=nil; v=v->nextinnode) {
+ bn = v - var;
+ biset(&r1->act, bn);
+ }
+ if(r1->f.prog->as == ABL)
+ break;
+ }
+
+ for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
+ if(r2->f.s2 != nil)
+ walkvardef(n, (Reg*)r2->f.s2, active);
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1, *p2;
+ Adr *a;
+ Var *v;
+
+ p1 = mal(sizeof(*p1));
+ *p1 = zprog;
+ p = r->f.prog;
+
+ // 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)
+ p = p2;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->name = v->name;
+ a->node = v->node;
+ 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;
+
+ if(v->addr)
+ fatal("addmove: shouldn't be doing this %A\n", a);
+
+ switch(v->etype) {
+ default:
+ print("What is this %E\n", v->etype);
+
+ case TINT8:
+ p1->as = AMOVB;
+ break;
+ case TBOOL:
+ case TUINT8:
+//print("movbu %E %d %S\n", v->etype, bn, v->sym);
+ p1->as = AMOVBZ;
+ break;
+ case TINT16:
+ p1->as = AMOVH;
+ break;
+ case TUINT16:
+ p1->as = AMOVHZ;
+ break;
+ case TINT32:
+ p1->as = AMOVW;
+ break;
+ case TUINT32:
+ case TPTR32:
+ p1->as = AMOVWZ;
+ break;
+ case TINT64:
+ case TUINT64:
+ case TPTR64:
+ p1->as = AMOVD;
+ break;
+ case TFLOAT32:
+ p1->as = AFMOVS;
+ break;
+ case TFLOAT64:
+ p1->as = AFMOVD;
+ break;
+ }
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUINT8 || v->etype == TBOOL)
+ p1->as = AMOVBZ;
+ if(v->etype == TUINT16)
+ p1->as = AMOVHZ;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+ ostats.nspill++;
+}
+
+static int
+overlap(int64 o1, int w1, int64 o2, int w2)
+{
+ int64 t1, t2;
+
+ t1 = o1+w1;
+ t2 = o2+w2;
+
+ if(!(t1 > o2 && t2 > o1))
+ return 0;
+
+ return 1;
+}
+
+Bits
+mkvar(Reg *r, Adr *a)
+{
+ USED(r);
+ Var *v;
+ int i, t, n, et, z, flag;
+ int64 w;
+ int64 o;
+ Bits bit;
+ Node *node;
+
+ // mark registers used
+ t = a->type;
+ switch(t) {
+ default:
+ print("type %d %d %D\n", t, a->name, a);
+ goto none;
+
+ case D_NONE:
+ goto none;
+
+ case D_BRANCH:
+ case D_CONST:
+ case D_FCONST:
+ case D_SCONST:
+ case D_SPR:
+ case D_OREG:
+ break;
+
+ case D_REG:
+ if(a->reg != NREG) {
+ 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:
+ n = a->name;
+ break;
+ }
+
+ node = a->node;
+ if(node == N || node->op != ONAME || node->orig == N)
+ goto none;
+ node = node->orig;
+ if(node->orig != node)
+ fatal("%D: bad node", a);
+ if(node->sym == S || node->sym->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ w = a->width;
+ if(w < 0)
+ fatal("bad width %lld for %D", w, a);
+
+ flag = 0;
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->node == node && v->name == n) {
+ if(v->offset == o)
+ if(v->etype == et)
+ if(v->width == w)
+ return blsh(i);
+
+ // if they overlap, disable both
+ if(overlap(v->offset, v->width, o, w)) {
+ v->addr = 1;
+ flag = 1;
+ }
+ }
+ }
+
+ switch(et) {
+ case 0:
+ case TFUNC:
+ goto none;
+ }
+
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && node != N)
+ fatal("variable not optimized: %#N", node);
+
+ // If we're not tracking a word in a variable, mark the rest as
+ // having its address taken, so that we keep the whole thing
+ // live at all calls. otherwise we might optimize away part of
+ // a variable but not all of it.
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->node == node)
+ v->addr = 1;
+ }
+ goto none;
+ }
+
+ i = nvar;
+ nvar++;
+ v = var+i;
+ v->offset = o;
+ v->name = n;
+ v->etype = et;
+ v->width = w;
+ v->addr = flag; // funny punning
+ v->node = node;
+
+ // node->opt is the head of a linked list
+ // of Vars within the given Node, so that
+ // we can start at a Var and find all the other
+ // Vars in the same Go variable.
+ v->nextinnode = node->opt;
+ node->opt = v;
+
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+
+ if(node->class == PPARAM)
+ for(z=0; z<BITS; z++)
+ ivar.b[z] |= bit.b[z];
+ if(node->class == PPARAMOUT)
+ for(z=0; z<BITS; z++)
+ ovar.b[z] |= bit.b[z];
+
+ // Treat values with their address taken as live at calls,
+ // because the garbage collector's liveness analysis in ../gc/plive.c does.
+ // These must be consistent or else we will elide stores and the garbage
+ // collector will see uninitialized data.
+ // The typical case where our own analysis is out of sync is when the
+ // node appears to have its address taken but that code doesn't actually
+ // get generated and therefore doesn't show up as an address being
+ // taken when we analyze the instruction stream.
+ // One instance of this case is when a closure uses the same name as
+ // an outer variable for one of its own variables declared with :=.
+ // The parser flags the outer variable as possibly shared, and therefore
+ // sets addrtaken, even though it ends up not being actually shared.
+ // If we were better about _ elision, _ = &x would suffice too.
+ // The broader := in a closure problem is mentioned in a comment in
+ // closure.c:/^typecheckclosure and dcl.c:/^oldname.
+ if(node->addrtaken)
+ v->addr = 1;
+
+ // Disable registerization for globals, because:
+ // (1) we might panic at any time and we want the recovery code
+ // to see the latest values (issue 1304).
+ // (2) we don't know what pointers might point at them and we want
+ // loads via those pointers to see updated values and vice versa (issue 7995).
+ //
+ // Disable registerization for results if using defer, because the deferred func
+ // might recover and return, causing the current values to be used.
+ if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
+ v->addr = 1;
+
+ if(debug['R'])
+ print("bit=%2d et=%2E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
+ ostats.nvar++;
+
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z, i, j;
+ Var *v, *v1;
+
+ for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->f.prog->as) {
+ case ABL:
+ if(noreturn(r1->f.prog))
+ break;
+
+ // Mark all input variables (ivar) as used, because that's what the
+ // liveness bitmaps say. The liveness bitmaps say that so that a
+ // panic will not show stale values in the parameter dump.
+ // Mark variables with a recent VARDEF (r1->act) as used,
+ // so that the optimizer flushes initializations to memory,
+ // so that if a garbage collection happens during this CALL,
+ // the collector will see initialized memory. Again this is to
+ // match what the liveness bitmaps say.
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
+ ref.b[z] = 0;
+ }
+
+ // cal.b is the current approximation of what's live across the call.
+ // Every bit in cal.b is a single stack word. For each such word,
+ // find all the other tracked stack words in the same Go variable
+ // (struct/slice/string/interface) and mark them live too.
+ // This is necessary because the liveness analysis for the garbage
+ // collector works at variable granularity, not at word granularity.
+ // It is fundamental for slice/string/interface: the garbage collector
+ // needs the whole value, not just some of the words, in order to
+ // interpret the other bits correctly. Specifically, slice needs a consistent
+ // ptr and cap, string needs a consistent ptr and len, and interface
+ // needs a consistent type word and data word.
+ for(z=0; z<BITS; z++) {
+ if(cal.b[z] == 0)
+ continue;
+ for(i=0; i<64; i++) {
+ if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
+ continue;
+ v = var+z*64+i;
+ if(v->node->opt == nil) // v represents fixed register, not Go variable
+ continue;
+
+ // v->node->opt is the head of a linked list of Vars
+ // corresponding to tracked words from the Go variable v->node.
+ // Walk the list and set all the bits.
+ // For a large struct this could end up being quadratic:
+ // after the first setting, the outer loop (for z, i) would see a 1 bit
+ // for all of the remaining words in the struct, and for each such
+ // word would go through and turn on all the bits again.
+ // To avoid the quadratic behavior, we only turn on the bits if
+ // v is the head of the list or if the head's bit is not yet turned on.
+ // This will set the bits at most twice, keeping the overall loop linear.
+ v1 = v->node->opt;
+ j = v1 - var;
+ if(v == v1 || !btest(&cal, j)) {
+ for(; v1 != nil; v1 = v1->nextinnode) {
+ j = v1 - var;
+ biset(&cal, j);
+ }
+ }
+ }
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z] | ovar.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->f.active)
+ break;
+ r1->f.active = 1;
+ }
+ for(; r != r1; r = (Reg*)r->f.p1)
+ for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->f.active)
+ break;
+ r1->f.active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->f.s2 != nil)
+ synch((Reg*)r1->f.s2, dif);
+ }
+}
+
+uint64
+allreg(uint64 b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ fatal("unknown etype %d/%E", bitno(b), v->etype);
+ break;
+
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TBOOL:
+ case TPTR32:
+ case TPTR64:
+ i = BtoR(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ i = BtoF(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ uint64 bb;
+
+ z = bn/64;
+ bb = 1LL<<(bn%64);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = (Reg*)r->f.p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->f.loop;
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+
+ if(r->f.prog->as != ANOP) { // don't give credit for NOPs
+ if(r->use1.b[z] & bb)
+ change += CREF * r->f.loop;
+ if((r->use2.b[z]|r->set.b[z]) & bb)
+ change += CREF * r->f.loop;
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->f.loop;
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = (Reg*)r->f.s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = (Reg*)r->f.s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+uint64
+paint2(Reg *r, int bn, int depth)
+{
+ Reg *r1;
+ int z;
+ uint64 bb, vreg;
+
+ z = bn/64;
+ bb = 1LL << (bn%64);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = (Reg*)r->f.p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ if(debug['R'] && debug['v'])
+ print(" paint2 %d %P\n", depth, r->f.prog);
+
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn, depth+1);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = (Reg*)r->f.s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn, depth+1);
+ r = (Reg*)r->f.s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, uint64 rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ uint64 bb;
+
+ z = bn/64;
+ bb = 1LL << (bn%64);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = (Reg*)r->f.p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->f.prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'] && debug['v'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'] && debug['v'])
+ print(" ===change== %P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'] && debug['v'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'] && debug['v'])
+ print(" ===change== %P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = (Reg*)r->f.s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = (Reg*)r->f.s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+ a->sym = nil;
+ a->node = nil;
+ a->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+
+ ostats.ncvtreg++;
+}
+
+/*
+ * track register variables including external registers:
+ * bit reg
+ * 0 R0
+ * 1 R1
+ * ... ...
+ * 31 R31
+ * 32+0 F0
+ * 32+1 F1
+ * ... ...
+ * 32+31 F31
+ */
+uint64
+RtoB(int r)
+{
+ if(r > D_R0 && r <= D_R0+31)
+ return 1ULL << (r - D_R0);
+ return 0;
+}
+
+int
+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;
+}
+
+int
+BtoF(uint64 b)
+{
+ b >>= 32;
+ if(b == 0)
+ return 0;
+ return bitno(b) + D_F0;
+}
+
+void
+dumpone(Flow *f, int isreg)
+{
+ int z;
+ Bits bit;
+ Reg *r;
+
+ print("%d:%P", f->loop, f->prog);
+ if(isreg) {
+ r = (Reg*)f;
+ for(z=0; z<BITS; z++)
+ bit.b[z] =
+ r->set.b[z] |
+ r->use1.b[z] |
+ r->use2.b[z] |
+ r->refbehind.b[z] |
+ r->refahead.b[z] |
+ r->calbehind.b[z] |
+ r->calahead.b[z] |
+ r->regdiff.b[z] |
+ r->act.b[z] |
+ 0;
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->set))
+ print(" s:%Q", r->set);
+ if(bany(&r->use1))
+ print(" u1:%Q", r->use1);
+ if(bany(&r->use2))
+ print(" u2:%Q", r->use2);
+ if(bany(&r->refbehind))
+ print(" rb:%Q ", r->refbehind);
+ if(bany(&r->refahead))
+ print(" ra:%Q ", r->refahead);
+ if(bany(&r->calbehind))
+ print(" cb:%Q ", r->calbehind);
+ if(bany(&r->calahead))
+ print(" ca:%Q ", r->calahead);
+ if(bany(&r->regdiff))
+ print(" d:%Q ", r->regdiff);
+ if(bany(&r->act))
+ print(" a:%Q ", r->act);
+ }
+ }
+ print("\n");
+}
+
+
+void
+dumpit(char *str, Flow *r0, int isreg)
+{
+ Flow *r, *r1;
+
+ print("\n%s\n", str);
+ for(r = r0; r != nil; r = r->link) {
+ dumpone(r, isreg);
+ r1 = r->p2;
+ if(r1 != nil) {
+ print(" pred:");
+ for(; r1 != nil; r1 = r1->p2link)
+ print(" %.4ud", (int)r1->prog->pc);
+ print("\n");
+ }
+ // Print successors if it's not just the next one
+ if(r->s1 != r->link || r->s2 != nil) {
+ print(" succ:");
+ if(r->s1 != nil)
+ print(" %.4ud", (int)r->s1->prog->pc);
+ if(r->s2 != nil)
+ print(" %.4ud", (int)r->s2->prog->pc);
+ print("\n");
+ }
+ }
+}
diff --git a/src/cmd/9l/9.out.h b/src/cmd/9l/9.out.h
new file mode 100644
index 000000000..87917f88a
--- /dev/null
+++ b/src/cmd/9l/9.out.h
@@ -0,0 +1,516 @@
+// cmd/9c/9.out.h from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * powerpc 64
+ */
+#define NSNAME 8
+#define NSYM 50
+#define NREG 32 /* number of general registers */
+#define NFREG 32 /* number of floating point registers */
+
+#include "../ld/textflag.h"
+
+enum
+{
+ REGZERO = 0, /* set to zero */
+ REGSP = 1,
+ REGSB = 2,
+ REGRET = 3,
+ 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 */
+ REGMAX = 27,
+ REGEXT = 30, /* external registers allocated from here down */
+ REGG = 30, /* G */
+ REGTMP = 31, /* 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 */
+/*
+ * GENERAL:
+ *
+ * compiler allocates R3 up as temps
+ * compiler allocates register variables R7-R27
+ * compiler allocates external registers R30 down
+ *
+ * compiler allocates register variables F17-F26
+ * compiler allocates external registers F26 down
+ */
+};
+
+enum {
+ BIG = 32768-8,
+};
+
+enum {
+/* mark flags */
+ LABEL = 1<<0,
+ LEAF = 1<<1,
+ FLOAT = 1<<2,
+ BRANCH = 1<<3,
+ LOAD = 1<<4,
+ FCMP = 1<<5,
+ SYNC = 1<<6,
+ LIST = 1<<7,
+ FOLL = 1<<8,
+ NOSCHED = 1<<9,
+};
+
+enum
+{
+ C_NONE,
+ C_REG,
+ C_FREG,
+ C_CREG,
+ C_SPR, /* special processor register */
+ C_ZCON,
+ C_SCON, /* 16 bit signed */
+ C_UCON, /* low 16 bits 0 */
+ C_ADDCON, /* -0x8000 <= v < 0 */
+ C_ANDCON, /* 0 < v <= 0xFFFF */
+ C_LCON, /* other 32 */
+ C_DCON, /* other 64 (could subdivide further) */
+ C_SACON,
+ C_SECON,
+ C_LACON,
+ C_LECON,
+ C_SBRA,
+ C_LBRA,
+ C_SAUTO,
+ C_LAUTO,
+ C_SEXT,
+ C_LEXT,
+ C_ZOREG,
+ C_SOREG,
+ C_LOREG,
+ C_FPSCR,
+ C_MSR,
+ C_XER,
+ C_LR,
+ C_CTR,
+ C_ANY,
+ C_GOK,
+ C_ADDR,
+
+ C_NCLASS, /* must be the last */
+};
+
+enum
+{
+ AXXX,
+ AADD,
+ AADDCC,
+ AADDV,
+ AADDVCC,
+ AADDC,
+ AADDCCC,
+ AADDCV,
+ AADDCVCC,
+ AADDME,
+ AADDMECC,
+ AADDMEVCC,
+ AADDMEV,
+ AADDE,
+ AADDECC,
+ AADDEVCC,
+ AADDEV,
+ AADDZE,
+ AADDZECC,
+ AADDZEVCC,
+ AADDZEV,
+ AAND,
+ AANDCC,
+ AANDN,
+ AANDNCC,
+ ABC,
+ ABCL,
+ ABEQ,
+ ABGE,
+ ABGT,
+ ABL,
+ ABLE,
+ ABLT,
+ ABNE,
+ ABR,
+ ABVC,
+ ABVS,
+ ACMP,
+ ACMPU,
+ ACNTLZW,
+ ACNTLZWCC,
+ ACRAND,
+ ACRANDN,
+ ACREQV,
+ ACRNAND,
+ ACRNOR,
+ ACROR,
+ ACRORN,
+ ACRXOR,
+ ADIVW,
+ ADIVWCC,
+ ADIVWVCC,
+ ADIVWV,
+ ADIVWU,
+ ADIVWUCC,
+ ADIVWUVCC,
+ ADIVWUV,
+ AEQV,
+ AEQVCC,
+ AEXTSB,
+ AEXTSBCC,
+ AEXTSH,
+ AEXTSHCC,
+ AFABS,
+ AFABSCC,
+ AFADD,
+ AFADDCC,
+ AFADDS,
+ AFADDSCC,
+ AFCMPO,
+ AFCMPU,
+ AFCTIW,
+ AFCTIWCC,
+ AFCTIWZ,
+ AFCTIWZCC,
+ AFDIV,
+ AFDIVCC,
+ AFDIVS,
+ AFDIVSCC,
+ AFMADD,
+ AFMADDCC,
+ AFMADDS,
+ AFMADDSCC,
+ AFMOVD,
+ AFMOVDCC,
+ AFMOVDU,
+ AFMOVS,
+ AFMOVSU,
+ AFMSUB,
+ AFMSUBCC,
+ AFMSUBS,
+ AFMSUBSCC,
+ AFMUL,
+ AFMULCC,
+ AFMULS,
+ AFMULSCC,
+ AFNABS,
+ AFNABSCC,
+ AFNEG,
+ AFNEGCC,
+ AFNMADD,
+ AFNMADDCC,
+ AFNMADDS,
+ AFNMADDSCC,
+ AFNMSUB,
+ AFNMSUBCC,
+ AFNMSUBS,
+ AFNMSUBSCC,
+ AFRSP,
+ AFRSPCC,
+ AFSUB,
+ AFSUBCC,
+ AFSUBS,
+ AFSUBSCC,
+ AMOVMW,
+ ALSW,
+ ALWAR,
+ AMOVWBR,
+ AMOVB,
+ AMOVBU,
+ AMOVBZ,
+ AMOVBZU,
+ AMOVH,
+ AMOVHBR,
+ AMOVHU,
+ AMOVHZ,
+ AMOVHZU,
+ AMOVW,
+ AMOVWU,
+ AMOVFL,
+ AMOVCRFS,
+ AMTFSB0,
+ AMTFSB0CC,
+ AMTFSB1,
+ AMTFSB1CC,
+ AMULHW,
+ AMULHWCC,
+ AMULHWU,
+ AMULHWUCC,
+ AMULLW,
+ AMULLWCC,
+ AMULLWVCC,
+ AMULLWV,
+ ANAND,
+ ANANDCC,
+ ANEG,
+ ANEGCC,
+ ANEGVCC,
+ ANEGV,
+ ANOR,
+ ANORCC,
+ AOR,
+ AORCC,
+ AORN,
+ AORNCC,
+ AREM,
+ AREMCC,
+ AREMV,
+ AREMVCC,
+ AREMU,
+ AREMUCC,
+ AREMUV,
+ AREMUVCC,
+ ARFI,
+ ARLWMI,
+ ARLWMICC,
+ ARLWNM,
+ ARLWNMCC,
+ ASLW,
+ ASLWCC,
+ ASRW,
+ ASRAW,
+ ASRAWCC,
+ ASRWCC,
+ ASTSW,
+ ASTWCCC,
+ ASUB,
+ ASUBCC,
+ ASUBVCC,
+ ASUBC,
+ ASUBCCC,
+ ASUBCV,
+ ASUBCVCC,
+ ASUBME,
+ ASUBMECC,
+ ASUBMEVCC,
+ ASUBMEV,
+ ASUBV,
+ ASUBE,
+ ASUBECC,
+ ASUBEV,
+ ASUBEVCC,
+ ASUBZE,
+ ASUBZECC,
+ ASUBZEVCC,
+ ASUBZEV,
+ ASYNC,
+ AXOR,
+ AXORCC,
+
+ ADCBF,
+ ADCBI,
+ ADCBST,
+ ADCBT,
+ ADCBTST,
+ ADCBZ,
+ AECIWX,
+ AECOWX,
+ AEIEIO,
+ AICBI,
+ AISYNC,
+ APTESYNC,
+ ATLBIE,
+ ATLBIEL,
+ ATLBSYNC,
+ ATW,
+
+ ASYSCALL,
+ ADATA,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ ANAME,
+ ANOP,
+ ARETURN,
+ ATEXT,
+ AWORD,
+ AEND,
+ ADYNT,
+ AINIT,
+ ASIGNAME,
+
+ ARFCI,
+
+ /* optional on 32-bit */
+ AFRES,
+ AFRESCC,
+ AFRSQRTE,
+ AFRSQRTECC,
+ AFSEL,
+ AFSELCC,
+ AFSQRT,
+ AFSQRTCC,
+ AFSQRTS,
+ AFSQRTSCC,
+
+ /* 64-bit */
+
+ ACNTLZD,
+ ACNTLZDCC,
+ ACMPW, /* CMP with L=0 */
+ ACMPWU,
+ ADIVD,
+ ADIVDCC,
+ ADIVDVCC,
+ ADIVDV,
+ ADIVDU,
+ ADIVDUCC,
+ ADIVDUVCC,
+ ADIVDUV,
+ AEXTSW,
+ AEXTSWCC,
+ /* AFCFIW; AFCFIWCC */
+ AFCFID,
+ AFCFIDCC,
+ AFCTID,
+ AFCTIDCC,
+ AFCTIDZ,
+ AFCTIDZCC,
+ ALDAR,
+ AMOVD,
+ AMOVDU,
+ AMOVWZ,
+ AMOVWZU,
+ AMULHD,
+ AMULHDCC,
+ AMULHDU,
+ AMULHDUCC,
+ AMULLD,
+ AMULLDCC,
+ AMULLDVCC,
+ AMULLDV,
+ ARFID,
+ ARLDMI,
+ ARLDMICC,
+ ARLDC,
+ ARLDCCC,
+ ARLDCR,
+ ARLDCRCC,
+ ARLDCL,
+ ARLDCLCC,
+ ASLBIA,
+ ASLBIE,
+ ASLBMFEE,
+ ASLBMFEV,
+ ASLBMTE,
+ ASLD,
+ ASLDCC,
+ ASRD,
+ ASRAD,
+ ASRADCC,
+ ASRDCC,
+ ASTDCCC,
+ ATD,
+
+ /* 64-bit pseudo operation */
+ ADWORD,
+ AREMD,
+ AREMDCC,
+ AREMDV,
+ AREMDVCC,
+ AREMDU,
+ AREMDUCC,
+ AREMDUV,
+ AREMDUVCC,
+
+ /* 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 */
+};
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.GOSYMDEF"
diff --git a/src/cmd/5c/Makefile b/src/cmd/9l/Makefile
index 3f528d751..3f528d751 100644
--- a/src/cmd/5c/Makefile
+++ b/src/cmd/9l/Makefile
diff --git a/src/cmd/9l/asm.c b/src/cmd/9l/asm.c
new file mode 100644
index 000000000..65a36285d
--- /dev/null
+++ b/src/cmd/9l/asm.c
@@ -0,0 +1,342 @@
+// Inferno utils/5l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Writing object files.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/elf.h"
+#include "../ld/dwarf.h"
+
+
+char linuxdynld[] = "/lib64/ld64.so.1";
+char freebsddynld[] = "XXX";
+char openbsddynld[] = "XXX";
+char netbsddynld[] = "XXX";
+char dragonflydynld[] = "XXX";
+char solarisdynld[] = "XXX";
+
+static int
+needlib(char *name)
+{
+ char *p;
+ LSym *s;
+
+ if(*name == '\0')
+ return 0;
+
+ /* reuse hash code in symbol table */
+ p = smprint(".dynlib.%s", name);
+ s = linklookup(ctxt, p, 0);
+ free(p);
+ if(s->type == 0) {
+ s->type = 100; // avoid SDATA, etc.
+ return 1;
+ }
+ return 0;
+}
+
+int nelfsym = 1;
+
+void
+adddynrela(LSym *rel, LSym *s, Reloc *r)
+{
+ // TODO(minux)
+ USED(rel); USED(s); USED(r);
+}
+
+void
+adddynrel(LSym *s, Reloc *r)
+{
+ LSym *targ;
+
+ // TODO(minux)
+
+ targ = r->sym;
+ ctxt->cursym = s;
+ diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+int
+elfreloc1(Reloc *r, vlong sectoff)
+{
+ USED(r); USED(sectoff);
+ // TODO(minux)
+ return -1;
+}
+
+void
+elfsetupplt(void)
+{
+ // TODO(minux)
+ return;
+}
+
+int
+machoreloc1(Reloc *r, vlong sectoff)
+{
+ USED(r);
+ USED(sectoff);
+
+ return -1;
+}
+
+
+int
+archreloc(Reloc *r, LSym *s, vlong *val)
+{
+ uint32 o1, o2;
+ int32 t;
+
+ if(linkmode == LinkExternal) {
+ // TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations.
+ // R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO.
+ // R_CALLPOWER corresponds to R_PPC_REL24.
+ return -1;
+ }
+ switch(r->type) {
+ case R_CONST:
+ *val = r->add;
+ return 0;
+ case R_GOTOFF:
+ *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
+ return 0;
+ case R_ADDRPOWER:
+ // r->add is two power64 instructions holding an immediate 32-bit constant.
+ // We want to add r->sym's address to that constant.
+ // The encoding of the immediate x<<16 + y,
+ // where x is the low 16 bits of the first instruction and y is the low 16
+ // bits of the second. Both x and y are signed (int16, not uint16).
+ o1 = r->add >> 32;
+ o2 = r->add;
+ t = symaddr(r->sym);
+ if(t < 0) {
+ ctxt->diag("relocation for %s is too big (>=2G): %lld", s->name, symaddr(r->sym));
+ }
+ t += ((o1 & 0xffff) << 16) + ((int32)o2 << 16 >> 16);
+ if(t & 0x8000)
+ t += 0x10000;
+ o1 = (o1 & 0xffff0000) | ((t >> 16) & 0xffff);
+ o2 = (o2 & 0xffff0000) | (t & 0xffff);
+ // when laid out, the instruction order must always be o1, o2.
+ if(ctxt->arch->endian == BigEndian)
+ *val = ((vlong)o1 << 32) | o2;
+ else
+ *val = ((vlong)o2 << 32) | o1;
+ return 0;
+ case R_CALLPOWER:
+ // Bits 6 through 29 = (S + A - P) >> 2
+ if(ctxt->arch->endian == BigEndian)
+ o1 = be32(s->p + r->off);
+ else
+ o1 = le32(s->p + r->off);
+
+ t = symaddr(r->sym) + r->add - (s->value + r->off);
+ if(t & 3)
+ ctxt->diag("relocation for %s is not aligned: %lld", s->name, t);
+ if(t << 6 >> 6 != t)
+ ctxt->diag("relocation for %s is too big: %lld", s->name, t);
+
+ *val = (o1 & 0xfc000003U) | (t & ~0xfc000003U);
+ return 0;
+ }
+ return -1;
+}
+
+void
+adddynsym(Link *ctxt, LSym *s)
+{
+ USED(ctxt); USED(s);
+ // TODO(minux)
+ return;
+}
+
+void
+adddynlib(char *lib)
+{
+ LSym *s;
+
+ if(!needlib(lib))
+ return;
+
+ if(iself) {
+ s = linklookup(ctxt, ".dynstr", 0);
+ if(s->size == 0)
+ addstring(s, "");
+ elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ } else {
+ diag("adddynlib: unsupported binary format");
+ }
+}
+
+void
+asmb(void)
+{
+ uint32 symo;
+ Section *sect;
+ LSym *sym;
+ int i;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asmb\n", cputime());
+ Bflush(&bso);
+
+ if(iself)
+ asmbelfsetup();
+
+ sect = segtext.sect;
+ cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+ codeblk(sect->vaddr, sect->len);
+ for(sect = sect->next; sect != nil; sect = sect->next) {
+ cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+ datblk(sect->vaddr, sect->len);
+ }
+
+ if(segrodata.filelen > 0) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f rodatblk\n", cputime());
+ Bflush(&bso);
+
+ cseek(segrodata.fileoff);
+ datblk(segrodata.vaddr, segrodata.filelen);
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+
+ cseek(segdata.fileoff);
+ datblk(segdata.vaddr, segdata.filelen);
+
+ /* output symbol table */
+ symsize = 0;
+ lcsize = 0;
+ symo = 0;
+ if(!debug['s']) {
+ // TODO: rationalize
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ default:
+ if(iself)
+ goto ElfSym;
+ case Hplan9:
+ symo = segdata.fileoff+segdata.filelen;
+ break;
+ ElfSym:
+ symo = segdata.fileoff+segdata.filelen;
+ symo = rnd(symo, INITRND);
+ break;
+ }
+ cseek(symo);
+ switch(HEADTYPE) {
+ default:
+ if(iself) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f elfsym\n", cputime());
+ asmelfsym();
+ cflush();
+ cwrite(elfstrdat, elfstrsize);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+ dwarfemitdebugsections();
+
+ if(linkmode == LinkExternal)
+ elfemitreloc();
+ }
+ break;
+ case Hplan9:
+ asmplan9sym();
+ cflush();
+
+ sym = linklookup(ctxt, "pclntab", 0);
+ if(sym != nil) {
+ lcsize = sym->np;
+ for(i=0; i < lcsize; i++)
+ cput(sym->p[i]);
+
+ cflush();
+ }
+ break;
+ }
+ }
+
+ ctxt->cursym = nil;
+ if(debug['v'])
+ Bprint(&bso, "%5.2f header\n", cputime());
+ Bflush(&bso);
+ cseek(0L);
+ switch(HEADTYPE) {
+ default:
+ case Hplan9: /* plan 9 */
+ LPUT(0x647); /* magic */
+ LPUT(segtext.filelen); /* sizes */
+ LPUT(segdata.filelen);
+ LPUT(segdata.len - segdata.filelen);
+ LPUT(symsize); /* nsyms */
+ LPUT(entryvalue()); /* va of entry */
+ LPUT(0L);
+ LPUT(lcsize);
+ break;
+ case Hlinux:
+ case Hfreebsd:
+ case Hnetbsd:
+ case Hopenbsd:
+ case Hnacl:
+ asmbelf(symo);
+ break;
+ }
+ cflush();
+ if(debug['c']){
+ print("textsize=%ulld\n", segtext.filelen);
+ print("datsize=%ulld\n", segdata.filelen);
+ print("bsssize=%ulld\n", segdata.len - segdata.filelen);
+ print("symsize=%d\n", symsize);
+ print("lcsize=%d\n", lcsize);
+ print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize);
+ }
+}
+
+vlong
+rnd(vlong v, int32 r)
+{
+ vlong c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
diff --git a/src/cmd/cc/doc.go b/src/cmd/9l/doc.go
index 10901b441..9df5dc614 100644
--- a/src/cmd/cc/doc.go
+++ b/src/cmd/9l/doc.go
@@ -6,8 +6,11 @@
/*
-This directory contains the portable section of the Plan 9 C compilers.
-See ../6c, ../8c, and ../5c for more information.
+9l is the linker for the Power64.
+The $GOARCH for these tools is power64 (big endian) or
+power64le (little endian).
+
+The flags are documented in ../ld/doc.go.
*/
package main
diff --git a/src/cmd/9l/l.h b/src/cmd/9l/l.h
new file mode 100644
index 000000000..dda741c56
--- /dev/null
+++ b/src/cmd/9l/l.h
@@ -0,0 +1,100 @@
+// cmd/9l/l.h from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "9.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+enum
+{
+ thechar = '9',
+ PtrSize = 8,
+ IntSize = 8,
+ RegSize = 8,
+ MaxAlign = 32, // max data alignment
+ FuncAlign = 8
+};
+
+#define P ((Prog*)0)
+#define S ((LSym*)0)
+
+enum
+{
+ FPCHIP = 1,
+ STRINGSZ = 200,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+ DATBLK = 1024,
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 64,
+ NENT = 100,
+ NSCHED = 20,
+ MINLC = 4,
+
+ Roffset = 22, /* no. bits for offset in relocation address */
+ Rindex = 10 /* no. bits for index in relocation address */
+};
+
+EXTERN int32 autosize;
+EXTERN LSym* datap;
+EXTERN int debug[128];
+EXTERN int32 lcsize;
+EXTERN char literal[32];
+EXTERN int nerrors;
+EXTERN vlong instoffset;
+EXTERN char* rpath;
+EXTERN vlong pc;
+EXTERN int32 symsize;
+EXTERN int32 staticgen;
+EXTERN Prog* lastp;
+EXTERN vlong textsize;
+
+void asmb(void);
+void adddynlib(char *lib);
+void adddynrel(LSym *s, Reloc *r);
+void adddynsym(Link *ctxt, LSym *s);
+int archreloc(Reloc *r, LSym *s, vlong *val);
+void listinit(void);
+vlong rnd(vlong, int32);
+
+#define LPUT(a) (ctxt->arch->endian == BigEndian ? lputb(a):lputl(a))
+#define WPUT(a) (ctxt->arch->endian == BigEndian ? wputb(a):wputl(a))
+#define VPUT(a) (ctxt->arch->endian == BigEndian ? vputb(a):vputl(a))
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+ DWARFREGSP = 1
+};
diff --git a/src/cmd/5c/list.c b/src/cmd/9l/list.c
index 98da424de..af8dc1588 100644
--- a/src/cmd/5c/list.c
+++ b/src/cmd/9l/list.c
@@ -1,5 +1,5 @@
-// Inferno utils/5c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.c
+// Inferno utils/5l/list.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -28,12 +28,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Printing.
-#define EXTERN
-#include "gc.h"
+#include "l.h"
+#include "../ld/lib.h"
void
listinit(void)
{
- listinit5();
+ listinit9();
}
diff --git a/src/cmd/9l/obj.c b/src/cmd/9l/obj.c
new file mode 100644
index 000000000..badb72a1a
--- /dev/null
+++ b/src/cmd/9l/obj.c
@@ -0,0 +1,108 @@
+// Inferno utils/5l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Reading object files.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/elf.h"
+#include "../ld/dwarf.h"
+#include <ar.h>
+
+char *thestring = "power64";
+LinkArch *thelinkarch;
+
+void
+linkarchinit(void)
+{
+ thestring = getgoarch();
+ if(strcmp(thestring, "power64le") == 0)
+ thelinkarch = &linkpower64le;
+ else
+ thelinkarch = &linkpower64;
+}
+
+void
+archinit(void)
+{
+ // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+ // Go was built; see ../../make.bash.
+ if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
+ linkmode = LinkInternal;
+
+ switch(HEADTYPE) {
+ default:
+ if(linkmode == LinkAuto)
+ linkmode = LinkInternal;
+ if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
+ sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
+ break;
+ }
+
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+ case Hplan9: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4128;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case Hlinux: /* power64 elf */
+ debug['d'] = 1; // TODO(minux): dynamic linking is not supported yet.
+ elfinit();
+ HEADR = ELFRESERVE;
+ if(INITTEXT == -1)
+ INITTEXT = 0x10000 + HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 0x10000;
+ break;
+ case Hnacl:
+ elfinit();
+ HEADR = 0x10000;
+ funcalign = 16;
+ if(INITTEXT == -1)
+ INITTEXT = 0x20000;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 0x10000;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%ux is ignored because of -R0x%ux\n",
+ INITDAT, INITRND);
+}
diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c
deleted file mode 100644
index 23147e519..000000000
--- a/src/cmd/cc/acid.c
+++ /dev/null
@@ -1,344 +0,0 @@
-// Inferno utils/cc/acid.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/acid.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-
-static char *kwd[] =
-{
- "$adt", "$aggr", "$append", "$complex", "$defn",
- "$delete", "$do", "$else", "$eval", "$head", "$if",
- "$local", "$loop", "$return", "$tail", "$then",
- "$union", "$whatis", "$while",
-};
-
-char*
-amap(char *s)
-{
- int i, bot, top, new;
-
- bot = 0;
- top = bot + nelem(kwd) - 1;
- while(bot <= top){
- new = bot + (top - bot)/2;
- i = strcmp(kwd[new]+1, s);
- if(i == 0)
- return kwd[new];
-
- if(i < 0)
- bot = new + 1;
- else
- top = new - 1;
- }
- return s;
-}
-
-Sym*
-acidsue(Type *t)
-{
- int h;
- Sym *s;
-
- if(t != T)
- for(h=0; h<nelem(hash); h++)
- for(s = hash[h]; s != S; s = s->link)
- if(s->suetag && s->suetag->link == t)
- return s;
- return 0;
-}
-
-Sym*
-acidfun(Type *t)
-{
- int h;
- Sym *s;
-
- for(h=0; h<nelem(hash); h++)
- for(s = hash[h]; s != S; s = s->link)
- if(s->type == t)
- return s;
- return 0;
-}
-
-char acidchar[NTYPE];
-Init acidcinit[] =
-{
- TCHAR, 'C', 0,
- TUCHAR, 'b', 0,
- TSHORT, 'd', 0,
- TUSHORT, 'u', 0,
- TLONG, 'D', 0,
- TULONG, 'U', 0,
- TVLONG, 'V', 0,
- TUVLONG, 'W', 0,
- TFLOAT, 'f', 0,
- TDOUBLE, 'F', 0,
- TARRAY, 'a', 0,
- TIND, 'X', 0,
- -1, 0, 0,
-};
-
-static void
-acidinit(void)
-{
- Init *p;
-
- for(p=acidcinit; p->code >= 0; p++)
- acidchar[p->code] = p->value;
-
- acidchar[TINT] = acidchar[TLONG];
- acidchar[TUINT] = acidchar[TULONG];
- if(types[TINT]->width != types[TLONG]->width) {
- acidchar[TINT] = acidchar[TSHORT];
- acidchar[TUINT] = acidchar[TUSHORT];
- if(types[TINT]->width != types[TSHORT]->width)
- warn(Z, "acidmember int not long or short");
- }
- if(types[TIND]->width == types[TUVLONG]->width)
- acidchar[TIND] = 'Y';
-
-}
-
-void
-acidmember(Type *t, int32 off, int flag)
-{
- Sym *s, *s1;
- Type *l;
- static int acidcharinit = 0;
-
- if(acidcharinit == 0) {
- acidinit();
- acidcharinit = 1;
- }
- s = t->sym;
- switch(t->etype) {
- default:
- Bprint(&outbuf, " T%d\n", t->etype);
- break;
-
- case TIND:
- if(s == S)
- break;
- l = t->link;
- if(flag) {
- if(typesu[l->etype]) {
- s1 = acidsue(l->link);
- if(s1 != S) {
- Bprint(&outbuf, " 'A' %s %d %s;\n",
- amap(s1->name),
- t->offset+off, amap(s->name));
- break;
- }
- }
- } else {
- l = t->link;
- s1 = S;
- if(typesu[l->etype])
- s1 = acidsue(l->link);
- if(s1 != S) {
- Bprint(&outbuf,
- "\tprint(indent, \"%s\t(%s)\", addr.%s\\X, \"\\n\");\n",
- amap(s->name), amap(s1->name), amap(s->name));
- } else {
- Bprint(&outbuf,
- "\tprint(indent, \"%s\t\", addr.%s\\X, \"\\n\");\n",
- amap(s->name), amap(s->name));
- }
- break;
- }
-
- case TINT:
- case TUINT:
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TFLOAT:
- case TDOUBLE:
- case TARRAY:
- if(s == S)
- break;
- if(flag) {
- Bprint(&outbuf, " '%c' %d %s;\n",
- acidchar[t->etype], t->offset+off, amap(s->name));
- } else {
- Bprint(&outbuf, "\tprint(indent, \"%s\t\", addr.%s, \"\\n\");\n",
- amap(s->name), amap(s->name));
- }
- break;
-
- case TSTRUCT:
- case TUNION:
- s1 = acidsue(t->link);
- if(s1 == S)
- break;
- if(flag) {
- if(s == S) {
- Bprint(&outbuf, " {\n");
- for(l = t->link; l != T; l = l->down)
- acidmember(l, t->offset+off, flag);
- Bprint(&outbuf, " };\n");
- } else {
- Bprint(&outbuf, " %s %d %s;\n",
- amap(s1->name),
- t->offset+off, amap(s->name));
- }
- } else {
- if(s != S) {
- Bprint(&outbuf, "\tprint(indent, \"%s %s {\\n\");\n",
- amap(s1->name), amap(s->name));
- Bprint(&outbuf, "\tindent_%s(addr.%s, indent+\"\\t\");\n",
- amap(s1->name), amap(s->name));
- Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n");
- } else {
- Bprint(&outbuf, "\tprint(indent, \"%s {\\n\");\n",
- amap(s1->name));
- Bprint(&outbuf, "\tindent_%s(addr+%d, indent+\"\\t\");\n",
- amap(s1->name), t->offset+off);
- Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n");
- }
- }
- break;
- }
-}
-
-void
-acidtype(Type *t)
-{
- Sym *s;
- Type *l;
- Io *i;
- int n;
- char *an;
-
- if(!debug['a'])
- return;
- if(debug['a'] > 1) {
- n = 0;
- for(i=iostack; i; i=i->link)
- n++;
- if(n > 1)
- return;
- }
- s = acidsue(t->link);
- if(s == S)
- return;
- switch(t->etype) {
- default:
- Bprint(&outbuf, "T%d\n", t->etype);
- return;
-
- case TUNION:
- case TSTRUCT:
- if(debug['s'])
- goto asmstr;
- an = amap(s->name);
- Bprint(&outbuf, "sizeof%s = %d;\n", an, t->width);
- Bprint(&outbuf, "aggr %s\n{\n", an);
- for(l = t->link; l != T; l = l->down)
- acidmember(l, 0, 1);
- Bprint(&outbuf, "};\n\n");
-
- Bprint(&outbuf, "defn\n%s(addr) {\n\tindent_%s(addr, \"\\t\");\n}\n", an, an);
- Bprint(&outbuf, "defn\nindent_%s(addr, indent) {\n\tcomplex %s addr;\n", an, an);
- for(l = t->link; l != T; l = l->down)
- acidmember(l, 0, 0);
- Bprint(&outbuf, "};\n\n");
- break;
- asmstr:
- if(s == S)
- break;
- for(l = t->link; l != T; l = l->down)
- if(l->sym != S)
- Bprint(&outbuf, "#define\t%s.%s\t%d\n",
- s->name,
- l->sym->name,
- l->offset);
- break;
- }
-}
-
-void
-acidvar(Sym *s)
-{
- int n;
- Io *i;
- Type *t;
- Sym *s1, *s2;
-
- if(!debug['a'] || debug['s'])
- return;
- if(debug['a'] > 1) {
- n = 0;
- for(i=iostack; i; i=i->link)
- n++;
- if(n > 1)
- return;
- }
- t = s->type;
- while(t && t->etype == TIND)
- t = t->link;
- if(t == T)
- return;
- if(t->etype == TENUM) {
- Bprint(&outbuf, "%s = ", amap(s->name));
- if(!typefd[t->etype])
- Bprint(&outbuf, "%lld;\n", s->vconst);
- else
- Bprint(&outbuf, "%f\n;", s->fconst);
- return;
- }
- if(!typesu[t->etype])
- return;
- s1 = acidsue(t->link);
- if(s1 == S)
- return;
- switch(s->class) {
- case CAUTO:
- case CPARAM:
- s2 = acidfun(thisfn);
- if(s2)
- Bprint(&outbuf, "complex %s %s:%s;\n",
- amap(s1->name), amap(s2->name), amap(s->name));
- break;
-
- case CSTATIC:
- case CEXTERN:
- case CGLOBL:
- case CLOCAL:
- Bprint(&outbuf, "complex %s %s;\n",
- amap(s1->name), amap(s->name));
- break;
- }
-}
diff --git a/src/cmd/cc/bits.c b/src/cmd/cc/bits.c
deleted file mode 100644
index 4496d65e7..000000000
--- a/src/cmd/cc/bits.c
+++ /dev/null
@@ -1,120 +0,0 @@
-// Inferno utils/cc/bits.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-
-Bits
-bor(Bits a, Bits b)
-{
- Bits c;
- int i;
-
- for(i=0; i<BITS; i++)
- c.b[i] = a.b[i] | b.b[i];
- return c;
-}
-
-Bits
-band(Bits a, Bits b)
-{
- Bits c;
- int i;
-
- for(i=0; i<BITS; i++)
- c.b[i] = a.b[i] & b.b[i];
- return c;
-}
-
-/*
-Bits
-bnot(Bits a)
-{
- Bits c;
- int i;
-
- for(i=0; i<BITS; i++)
- c.b[i] = ~a.b[i];
- return c;
-}
-*/
-
-int
-bany(Bits *a)
-{
- int i;
-
- for(i=0; i<BITS; i++)
- if(a->b[i])
- return 1;
- return 0;
-}
-
-int
-beq(Bits a, Bits b)
-{
- int i;
-
- for(i=0; i<BITS; i++)
- if(a.b[i] != b.b[i])
- return 0;
- return 1;
-}
-
-int
-bnum(Bits a)
-{
- int i;
- int32 b;
-
- for(i=0; i<BITS; i++)
- if(b = a.b[i])
- return 32*i + bitno(b);
- diag(Z, "bad in bnum");
- return 0;
-}
-
-Bits
-blsh(uint n)
-{
- Bits c;
-
- c = zbits;
- c.b[n/32] = 1L << (n%32);
- return c;
-}
-
-int
-bset(Bits a, uint n)
-{
- if(a.b[n/32] & (1L << (n%32)))
- return 1;
- return 0;
-}
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
deleted file mode 100644
index 9530f5cf6..000000000
--- a/src/cmd/cc/cc.h
+++ /dev/null
@@ -1,835 +0,0 @@
-// Inferno utils/cc/cc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#undef getc
-#undef ungetc
-#undef BUFSIZ
-
-#define getc ccgetc
-#define ungetc ccungetc
-
-typedef struct Node Node;
-typedef struct Sym Sym;
-typedef struct Type Type;
-typedef struct Funct Funct;
-typedef struct Decl Decl;
-typedef struct Io Io;
-typedef struct Term Term;
-typedef struct Init Init;
-typedef struct Bits Bits;
-typedef struct Bvec Bvec;
-typedef struct Dynimp Dynimp;
-typedef struct Dynexp Dynexp;
-typedef struct Var Var;
-
-typedef Rune TRune; /* target system type */
-
-#define BUFSIZ 8192
-#define NSYMB 500
-#define NHASH 1024
-#define STRINGSZ 200
-#define HISTSZ 20
-#define YYMAXDEPTH 500
-#define NTERM 10
-#define MAXALIGN 7
-
-#define SIGN(n) ((uvlong)1<<(n-1))
-#define MASK(n) (SIGN(n)|(SIGN(n)-1))
-
-#define BITS 5
-#define NVAR (BITS*sizeof(uint32)*8)
-struct Bits
-{
- uint32 b[BITS];
-};
-
-struct Bvec
-{
- int32 n; // number of bits
- uint32 b[];
-};
-
-struct Var
-{
- vlong offset;
- LSym* sym;
- char name;
- char etype;
-};
-
-struct Node
-{
- Node* left;
- Node* right;
- void* label;
- int32 pc;
- int reg;
- int32 xoffset;
- double fconst; /* fp constant */
- vlong vconst; /* non fp const */
- char* cstring; /* character string */
- TRune* rstring; /* rune string */
-
- Sym* sym;
- Type* type;
- int32 lineno;
- uchar op;
- uchar oldop;
- uchar xcast;
- uchar class;
- uchar etype;
- uchar complex;
- uchar addable;
- uchar scale;
- uchar garb;
-};
-#define Z ((Node*)0)
-
-struct Sym
-{
- Sym* link;
- LSym* lsym;
- Type* type;
- Type* suetag;
- Type* tenum;
- char* macro;
- int32 varlineno;
- int32 offset;
- vlong vconst;
- double fconst;
- Node* label;
- ushort lexical;
- char *name;
- ushort block;
- ushort sueblock;
- uchar class;
- uchar sym;
- uchar aused;
- uchar sig;
- uchar dataflag;
-};
-#define S ((Sym*)0)
-
-enum{
- SIGNONE = 0,
- SIGDONE = 1,
- SIGINTERN = 2,
-
- SIGNINTERN = 1729*325*1729,
-};
-
-struct Decl
-{
- Decl* link;
- Sym* sym;
- Type* type;
- int32 varlineno;
- int32 offset;
- short val;
- ushort block;
- uchar class;
- uchar aused;
-};
-#define D ((Decl*)0)
-
-struct Type
-{
- Sym* sym;
- Sym* tag;
- Funct* funct;
- Type* link;
- Type* down;
- int32 width;
- int32 offset;
- int32 lineno;
- uchar shift;
- uchar nbits;
- uchar etype;
- uchar garb;
- uchar align;
-};
-
-#define T ((Type*)0)
-#define NODECL ((void(*)(int, Type*, Sym*))0)
-
-struct Init /* general purpose initialization */
-{
- int code;
- uint32 value;
- char* s;
-};
-
-EXTERN struct
-{
- char* p;
- int c;
-} fi;
-
-struct Io
-{
- Io* link;
- char* p;
- char b[BUFSIZ];
- short c;
- short f;
-};
-#define I ((Io*)0)
-
-struct Term
-{
- vlong mult;
- Node *node;
-};
-
-enum
-{
- Axxx,
- Ael1,
- Ael2,
- Asu2,
- Aarg0,
- Aarg1,
- Aarg2,
- Aaut3,
- NALIGN,
-};
-
-enum
-{
- DMARK,
- DAUTO,
- DSUE,
- DLABEL,
-};
-enum
-{
- OXXX,
- OADD,
- OADDR,
- OAND,
- OANDAND,
- OARRAY,
- OAS,
- OASI,
- OASADD,
- OASAND,
- OASASHL,
- OASASHR,
- OASDIV,
- OASHL,
- OASHR,
- OASLDIV,
- OASLMOD,
- OASLMUL,
- OASLSHR,
- OASMOD,
- OASMUL,
- OASOR,
- OASSUB,
- OASXOR,
- OBIT,
- OBREAK,
- OCASE,
- OCAST,
- OCOMMA,
- OCOND,
- OCONST,
- OCONTINUE,
- ODIV,
- ODOT,
- ODOTDOT,
- ODWHILE,
- OENUM,
- OEQ,
- OEXREG,
- OFOR,
- OFUNC,
- OGE,
- OGOTO,
- OGT,
- OHI,
- OHS,
- OIF,
- OIND,
- OINDREG,
- OINIT,
- OLABEL,
- OLDIV,
- OLE,
- OLIST,
- OLMOD,
- OLMUL,
- OLO,
- OLS,
- OLSHR,
- OLT,
- OMOD,
- OMUL,
- ONAME,
- ONE,
- ONOT,
- OOR,
- OOROR,
- OPOSTDEC,
- OPOSTINC,
- OPREDEC,
- OPREINC,
- OPREFETCH,
- OPROTO,
- OREGISTER,
- ORETURN,
- OSET,
- OSIGN,
- OSIZE,
- OSTRING,
- OLSTRING,
- OSTRUCT,
- OSUB,
- OSWITCH,
- OUNION,
- OUSED,
- OWHILE,
- OXOR,
- ONEG,
- OCOM,
- OPOS,
- OELEM,
-
- OTST, /* used in some compilers */
- OINDEX,
- OFAS,
- OREGPAIR,
- OROTL,
-
- OEND
-};
-enum
-{
- TXXX,
- TCHAR,
- TUCHAR,
- TSHORT,
- TUSHORT,
- TINT,
- TUINT,
- TLONG,
- TULONG,
- TVLONG,
- TUVLONG,
- TFLOAT,
- TDOUBLE,
- TIND,
- TFUNC,
- TARRAY,
- TVOID,
- TSTRUCT,
- TUNION,
- TENUM,
- NTYPE,
-
- TAUTO = NTYPE,
- TEXTERN,
- TSTATIC,
- TTYPEDEF,
- TTYPESTR,
- TREGISTER,
- TCONSTNT,
- TVOLATILE,
- TUNSIGNED,
- TSIGNED,
- TDOT,
- TFILE,
- TOLD,
- NALLTYPES,
-
- /* adapt size of Rune to target system's size */
- TRUNE = sizeof(TRune)==4? TUINT: TUSHORT,
-};
-enum
-{
- CXXX,
- CAUTO,
- CEXTERN,
- CGLOBL,
- CSTATIC,
- CLOCAL,
- CTYPEDEF,
- CTYPESTR,
- CPARAM,
- CSELEM,
- CLABEL,
- CEXREG,
- NCTYPES,
-};
-enum
-{
- GXXX = 0,
- GCONSTNT = 1<<0,
- GVOLATILE = 1<<1,
- NGTYPES = 1<<2,
-
- GINCOMPLETE = 1<<2,
-};
-enum
-{
- BCHAR = 1L<<TCHAR,
- BUCHAR = 1L<<TUCHAR,
- BSHORT = 1L<<TSHORT,
- BUSHORT = 1L<<TUSHORT,
- BINT = 1L<<TINT,
- BUINT = 1L<<TUINT,
- BLONG = 1L<<TLONG,
- BULONG = 1L<<TULONG,
- BVLONG = 1L<<TVLONG,
- BUVLONG = 1L<<TUVLONG,
- BFLOAT = 1L<<TFLOAT,
- BDOUBLE = 1L<<TDOUBLE,
- BIND = 1L<<TIND,
- BFUNC = 1L<<TFUNC,
- BARRAY = 1L<<TARRAY,
- BVOID = 1L<<TVOID,
- BSTRUCT = 1L<<TSTRUCT,
- BUNION = 1L<<TUNION,
- BENUM = 1L<<TENUM,
- BFILE = 1L<<TFILE,
- BDOT = 1L<<TDOT,
- BCONSTNT = 1L<<TCONSTNT,
- BVOLATILE = 1L<<TVOLATILE,
- BUNSIGNED = 1L<<TUNSIGNED,
- BSIGNED = 1L<<TSIGNED,
- BAUTO = 1L<<TAUTO,
- BEXTERN = 1L<<TEXTERN,
- BSTATIC = 1L<<TSTATIC,
- BTYPEDEF = 1L<<TTYPEDEF,
- BTYPESTR = 1L<<TTYPESTR,
- BREGISTER = 1L<<TREGISTER,
-
- BINTEGER = BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT|
- BLONG|BULONG|BVLONG|BUVLONG,
- BNUMBER = BINTEGER|BFLOAT|BDOUBLE,
-
-/* these can be overloaded with complex types */
-
- BCLASS = BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BTYPESTR|BREGISTER,
- BGARB = BCONSTNT|BVOLATILE,
-};
-
-struct Funct
-{
- Sym* sym[OEND];
- Sym* castto[NTYPE];
- Sym* castfr[NTYPE];
-};
-
-EXTERN struct
-{
- Type* tenum; /* type of entire enum */
- Type* cenum; /* type of current enum run */
- vlong lastenum; /* value of current enum */
- double floatenum; /* value of current enum */
-} en;
-
-EXTERN int autobn;
-EXTERN int32 autoffset;
-EXTERN int blockno;
-EXTERN Decl* dclstack;
-EXTERN int debug[256];
-EXTERN int32 firstbit;
-EXTERN Sym* firstarg;
-EXTERN Type* firstargtype;
-EXTERN Decl* firstdcl;
-EXTERN int fperror;
-EXTERN Sym* hash[NHASH];
-EXTERN char* hunk;
-EXTERN char** include;
-EXTERN Io* iofree;
-EXTERN Io* ionext;
-EXTERN Io* iostack;
-EXTERN int32 lastbit;
-EXTERN char lastclass;
-EXTERN Type* lastdcl;
-EXTERN int32 lastfield;
-EXTERN Type* lasttype;
-EXTERN int32 lineno;
-EXTERN int32 nearln;
-EXTERN int nerrors;
-EXTERN int newflag;
-EXTERN int32 nhunk;
-EXTERN int ninclude;
-EXTERN Node* nodproto;
-EXTERN Node* nodcast;
-EXTERN int32 nsymb;
-EXTERN Biobuf outbuf;
-EXTERN Biobuf diagbuf;
-EXTERN char* outfile;
-EXTERN int peekc;
-EXTERN int32 stkoff;
-EXTERN Type* strf;
-EXTERN Type* strl;
-EXTERN char* symb;
-EXTERN Sym* symstring;
-EXTERN int taggen;
-EXTERN Type* tfield;
-EXTERN Type* tufield;
-extern int thechar;
-extern char* thestring;
-extern LinkArch* thelinkarch;
-EXTERN Type* thisfn;
-EXTERN int32 thunk;
-EXTERN Type* types[NALLTYPES];
-EXTERN Type* fntypes[NALLTYPES];
-EXTERN Node* initlist;
-EXTERN Term term[NTERM];
-EXTERN int nterm;
-EXTERN int packflg;
-EXTERN int fproundflg;
-EXTERN int textflag;
-EXTERN int dataflag;
-EXTERN int flag_largemodel;
-EXTERN int ncontin;
-EXTERN int canreach;
-EXTERN int warnreach;
-EXTERN int nacl;
-EXTERN Bits zbits;
-EXTERN Fmt pragcgobuf;
-EXTERN Biobuf bstdout;
-EXTERN Var var[NVAR];
-
-extern char *onames[], *tnames[], *gnames[];
-extern char *cnames[], *qnames[], *bnames[];
-extern uchar tab[NTYPE][NTYPE];
-extern uchar comrel[], invrel[], logrel[];
-extern int32 ncast[], tadd[], tand[];
-extern int32 targ[], tasadd[], tasign[], tcast[];
-extern int32 tdot[], tfunct[], tindir[], tmul[];
-extern int32 tnot[], trel[], tsub[];
-
-extern uchar typeaf[];
-extern uchar typefd[];
-extern uchar typei[];
-extern uchar typesu[];
-extern uchar typesuv[];
-extern uchar typeu[];
-extern uchar typev[];
-extern uchar typec[];
-extern uchar typeh[];
-extern uchar typeil[];
-extern uchar typeilp[];
-extern uchar typechl[];
-extern uchar typechlv[];
-extern uchar typechlvp[];
-extern uchar typechlp[];
-extern uchar typechlpfd[];
-
-EXTERN uchar* typeword;
-EXTERN uchar* typecmplx;
-EXTERN Link* ctxt;
-
-extern uint32 thash1;
-extern uint32 thash2;
-extern uint32 thash3;
-extern uint32 thash[];
-
-/*
- * compat.c/unix.c/windows.c
- */
-int systemtype(int);
-int pathchar(void);
-
-/*
- * parser
- */
-int yyparse(void);
-int mpatov(char*, vlong*);
-
-/*
- * lex.c
- */
-void* allocn(void*, int32, int32);
-void* alloc(int32);
-void ensuresymb(int32);
-void cinit(void);
-int compile(char*, char**, int);
-void errorexit(void);
-int filbuf(void);
-int getc(void);
-int32 getr(void);
-int getnsc(void);
-Sym* lookup(void);
-void main(int, char*[]);
-void newfile(char*, int);
-void newio(void);
-void pushio(void);
-int32 escchar(int32, int, int);
-Sym* slookup(char*);
-void syminit(Sym*);
-void unget(int);
-int32 yylex(void);
-int Lconv(Fmt*);
-int Tconv(Fmt*);
-int FNconv(Fmt*);
-int Oconv(Fmt*);
-int Qconv(Fmt*);
-int VBconv(Fmt*);
-int Bconv(Fmt*);
-void setinclude(char*);
-
-/*
- * mac.c
- */
-void dodefine(char*);
-void domacro(void);
-Sym* getsym(void);
-int32 getnsn(void);
-void macdef(void);
-void macprag(void);
-void macend(void);
-void macexpand(Sym*, char*);
-void macif(int);
-void macinc(void);
-void maclin(void);
-void macund(void);
-
-/*
- * dcl.c
- */
-Node* doinit(Sym*, Type*, int32, Node*);
-Type* tcopy(Type*);
-Node* init1(Sym*, Type*, int32, int);
-Node* newlist(Node*, Node*);
-void adecl(int, Type*, Sym*);
-int anyproto(Node*);
-void argmark(Node*, int);
-void dbgdecl(Sym*);
-Node* dcllabel(Sym*, int);
-Node* dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*);
-Sym* mkstatic(Sym*);
-void doenum(Sym*, Node*);
-void snap(Type*);
-Type* dotag(Sym*, int, int);
-void edecl(int, Type*, Sym*);
-Type* fnproto(Node*);
-Type* fnproto1(Node*);
-void markdcl(void);
-Type* paramconv(Type*, int);
-void pdecl(int, Type*, Sym*);
-Decl* push(void);
-Decl* push1(Sym*);
-Node* revertdcl(void);
-int32 xround(int32, int);
-int rsametype(Type*, Type*, int, int);
-int sametype(Type*, Type*);
-uint32 sign(Sym*);
-uint32 signature(Type*);
-void sualign(Type*);
-void tmerge(Type*, Sym*);
-void walkparam(Node*, int);
-void xdecl(int, Type*, Sym*);
-Node* contig(Sym*, Node*, int32);
-
-/*
- * com.c
- */
-void ccom(Node*);
-void complex(Node*);
-int tcom(Node*);
-int tcoma(Node*, Node*, Type*, int);
-int tcomd(Node*);
-int tcomo(Node*, int);
-int tcomx(Node*);
-int tlvalue(Node*);
-void constas(Node*, Type*, Type*);
-
-/*
- * con.c
- */
-void acom(Node*);
-void acom1(vlong, Node*);
-void acom2(Node*, Type*);
-int acomcmp1(const void*, const void*);
-int acomcmp2(const void*, const void*);
-int addo(Node*);
-void evconst(Node*);
-
-/*
- * funct.c
- */
-int isfunct(Node*);
-void dclfunct(Type*, Sym*);
-
-/*
- * sub.c
- */
-void arith(Node*, int);
-int deadheads(Node*);
-Type* dotsearch(Sym*, Type*, Node*, int32*);
-int32 dotoffset(Type*, Type*, Node*);
-void gethunk(void);
-Node* invert(Node*);
-int bitno(int32);
-void makedot(Node*, Type*, int32);
-int mixedasop(Type*, Type*);
-Node* new(int, Node*, Node*);
-Node* new1(int, Node*, Node*);
-int nilcast(Type*, Type*);
-int nocast(Type*, Type*);
-void prtree(Node*, char*);
-void prtree1(Node*, int, int);
-void relcon(Node*, Node*);
-int relindex(int);
-int simpleg(int32);
-Type* garbt(Type*, int32);
-int simplec(int32);
-Type* simplet(int32);
-int stcompat(Node*, Type*, Type*, int32[]);
-int tcompat(Node*, Type*, Type*, int32[]);
-void tinit(void);
-Type* typ(int, Type*);
-Type* copytyp(Type*);
-void typeext(Type*, Node*);
-void typeext1(Type*, Node*);
-int side(Node*);
-int vconst(Node*);
-int xlog2(uvlong);
-int vlog(Node*);
-int topbit(uint32);
-void simplifyshift(Node*);
-int32 typebitor(int32, int32);
-void diag(Node*, char*, ...);
-void warn(Node*, char*, ...);
-void yyerror(char*, ...);
-void fatal(Node*, char*, ...);
-LSym* linksym(Sym*);
-
-/*
- * acid.c
- */
-void acidtype(Type*);
-void acidvar(Sym*);
-
-/*
- * godefs.c
- */
-int Uconv(Fmt*);
-void godeftype(Type*);
-void godefvar(Sym*);
-
-/*
- * bits.c
- */
-Bits bor(Bits, Bits);
-Bits band(Bits, Bits);
-Bits bnot(Bits);
-int bany(Bits*);
-int bnum(Bits);
-Bits blsh(uint);
-int beq(Bits, Bits);
-int bset(Bits, uint);
-
-/*
- * dpchk.c
- */
-void dpcheck(Node*);
-void arginit(void);
-void pragvararg(void);
-void pragpack(void);
-void pragfpround(void);
-void pragdataflag(void);
-void pragtextflag(void);
-void pragincomplete(void);
-void pragcgo(char*);
-
-/*
- * calls to machine depend part
- */
-void codgen(Node*, Node*);
-void gclean(void);
-void gextern(Sym*, Node*, int32, int32);
-void ginit(void);
-int32 outstring(char*, int32);
-int32 outlstring(TRune*, int32);
-void sextern(Sym*, Node*, int32, int32);
-void xcom(Node*);
-int32 exreg(Type*);
-int32 align(int32, Type*, int, int32*);
-int32 maxround(int32, int32);
-int hasdotdotdot(Type*);
-void linkarchinit(void);
-
-extern schar ewidth[];
-
-/*
- * com64
- */
-int com64(Node*);
-void com64init(void);
-void bool64(Node*);
-double convvtof(vlong);
-vlong convftov(double);
-double convftox(double, int);
-vlong convvtox(vlong, int);
-
-/*
- * machcap
- */
-int machcap(Node*);
-
-#pragma varargck argpos warn 2
-#pragma varargck argpos diag 2
-#pragma varargck argpos yyerror 1
-
-#pragma varargck type "B" Bits
-#pragma varargck type "F" Node*
-#pragma varargck type "L" int32
-#pragma varargck type "Q" int32
-#pragma varargck type "O" int
-#pragma varargck type "O" uint
-#pragma varargck type "T" Type*
-#pragma varargck type "U" char*
-#pragma varargck type "|" int
-
-enum
-{
- Plan9 = 1<<0,
- Unix = 1<<1,
- Windows = 1<<2,
-};
-int pathchar(void);
-int systemtype(int);
-void* alloc(int32 n);
-void* allocn(void*, int32, int32);
diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y
deleted file mode 100644
index 8d7cb1472..000000000
--- a/src/cmd/cc/cc.y
+++ /dev/null
@@ -1,1220 +0,0 @@
-// Inferno utils/cc/cc.y
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.y
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-%{
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and cc.h re-#defines getc */
-#include "cc.h"
-%}
-%union {
- Node* node;
- Sym* sym;
- Type* type;
- struct
- {
- Type* t;
- uchar c;
- } tycl;
- struct
- {
- Type* t1;
- Type* t2;
- Type* t3;
- uchar c;
- } tyty;
- struct
- {
- char* s;
- int32 l;
- } sval;
- int32 lval;
- double dval;
- vlong vval;
-}
-%type <sym> ltag
-%type <lval> gctname gcname cname gname tname
-%type <lval> gctnlist gcnlist zgnlist
-%type <type> tlist sbody complex
-%type <tycl> types
-%type <node> zarglist arglist zcexpr
-%type <node> name block stmnt cexpr expr xuexpr pexpr
-%type <node> zelist elist adecl slist uexpr string lstring
-%type <node> xdecor xdecor2 labels label ulstmnt
-%type <node> adlist edecor tag qual qlist
-%type <node> abdecor abdecor1 abdecor2 abdecor3
-%type <node> zexpr lexpr init ilist forexpr
-
-%left ';'
-%left ','
-%right '=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE
-%right '?' ':'
-%left LOROR
-%left LANDAND
-%left '|'
-%left '^'
-%left '&'
-%left LEQ LNE
-%left '<' '>' LLE LGE
-%left LLSH LRSH
-%left '+' '-'
-%left '*' '/' '%'
-%right LMM LPP LMG '.' '[' '('
-
-%token <sym> LNAME LTYPE
-%token <dval> LFCONST LDCONST
-%token <vval> LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST
-%token <sval> LSTRING LLSTRING
-%token LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO
-%token LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO
-%token LIF LINT LLONG LPREFETCH LREGISTER LRETURN LSHORT LSIZEOF LUSED
-%token LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED
-%token LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF
-%token LRESTRICT LINLINE
-%%
-prog:
-| prog xdecl
-
-/*
- * external declarator
- */
-xdecl:
- zctlist ';'
- {
- dodecl(xdecl, lastclass, lasttype, Z);
- }
-| zctlist xdlist ';'
-| zctlist xdecor
- {
- lastdcl = T;
- firstarg = S;
- dodecl(xdecl, lastclass, lasttype, $2);
- if(lastdcl == T || lastdcl->etype != TFUNC) {
- diag($2, "not a function");
- lastdcl = types[TFUNC];
- }
- thisfn = lastdcl;
- markdcl();
- firstdcl = dclstack;
- argmark($2, 0);
- }
- pdecl
- {
- argmark($2, 1);
- }
- block
- {
- Node *n;
-
- n = revertdcl();
- if(n)
- $6 = new(OLIST, n, $6);
- if(!debug['a'] && !debug['Z'])
- codgen($6, $2);
- }
-
-xdlist:
- xdecor
- {
- dodecl(xdecl, lastclass, lasttype, $1);
- }
-| xdecor
- {
- $1 = dodecl(xdecl, lastclass, lasttype, $1);
- }
- '=' init
- {
- doinit($1->sym, $1->type, 0L, $4);
- }
-| xdlist ',' xdlist
-
-xdecor:
- xdecor2
-| '*' zgnlist xdecor
- {
- $$ = new(OIND, $3, Z);
- $$->garb = simpleg($2);
- }
-
-xdecor2:
- tag
-| '(' xdecor ')'
- {
- $$ = $2;
- }
-| xdecor2 '(' zarglist ')'
- {
- $$ = new(OFUNC, $1, $3);
- }
-| xdecor2 '[' zexpr ']'
- {
- $$ = new(OARRAY, $1, $3);
- }
-
-/*
- * automatic declarator
- */
-adecl:
- ctlist ';'
- {
- $$ = dodecl(adecl, lastclass, lasttype, Z);
- }
-| ctlist adlist ';'
- {
- $$ = $2;
- }
-
-adlist:
- xdecor
- {
- dodecl(adecl, lastclass, lasttype, $1);
- $$ = Z;
- }
-| xdecor
- {
- $1 = dodecl(adecl, lastclass, lasttype, $1);
- }
- '=' init
- {
- int32 w;
-
- w = $1->sym->type->width;
- $$ = doinit($1->sym, $1->type, 0L, $4);
- $$ = contig($1->sym, $$, w);
- }
-| adlist ',' adlist
- {
- $$ = $1;
- if($3 != Z) {
- $$ = $3;
- if($1 != Z)
- $$ = new(OLIST, $1, $3);
- }
- }
-
-/*
- * parameter declarator
- */
-pdecl:
-| pdecl ctlist pdlist ';'
-
-pdlist:
- xdecor
- {
- dodecl(pdecl, lastclass, lasttype, $1);
- }
-| pdlist ',' pdlist
-
-/*
- * structure element declarator
- */
-edecl:
- tlist
- {
- lasttype = $1;
- }
- zedlist ';'
-| edecl tlist
- {
- lasttype = $2;
- }
- zedlist ';'
-
-zedlist: /* extension */
- {
- lastfield = 0;
- edecl(CXXX, lasttype, S);
- }
-| edlist
-
-edlist:
- edecor
- {
- dodecl(edecl, CXXX, lasttype, $1);
- }
-| edlist ',' edlist
-
-edecor:
- xdecor
- {
- lastbit = 0;
- firstbit = 1;
- }
-| tag ':' lexpr
- {
- $$ = new(OBIT, $1, $3);
- }
-| ':' lexpr
- {
- $$ = new(OBIT, Z, $2);
- }
-
-/*
- * abstract declarator
- */
-abdecor:
- {
- $$ = (Z);
- }
-| abdecor1
-
-abdecor1:
- '*' zgnlist
- {
- $$ = new(OIND, (Z), Z);
- $$->garb = simpleg($2);
- }
-| '*' zgnlist abdecor1
- {
- $$ = new(OIND, $3, Z);
- $$->garb = simpleg($2);
- }
-| abdecor2
-
-abdecor2:
- abdecor3
-| abdecor2 '(' zarglist ')'
- {
- $$ = new(OFUNC, $1, $3);
- }
-| abdecor2 '[' zexpr ']'
- {
- $$ = new(OARRAY, $1, $3);
- }
-
-abdecor3:
- '(' ')'
- {
- $$ = new(OFUNC, (Z), Z);
- }
-| '[' zexpr ']'
- {
- $$ = new(OARRAY, (Z), $2);
- }
-| '(' abdecor1 ')'
- {
- $$ = $2;
- }
-
-init:
- expr
-| '{' ilist '}'
- {
- $$ = new(OINIT, invert($2), Z);
- }
-
-qual:
- '[' lexpr ']'
- {
- $$ = new(OARRAY, $2, Z);
- }
-| '.' ltag
- {
- $$ = new(OELEM, Z, Z);
- $$->sym = $2;
- }
-| qual '='
-
-qlist:
- init ','
-| qlist init ','
- {
- $$ = new(OLIST, $1, $2);
- }
-| qual
-| qlist qual
- {
- $$ = new(OLIST, $1, $2);
- }
-
-ilist:
- qlist
-| init
-| qlist init
- {
- $$ = new(OLIST, $1, $2);
- }
-
-zarglist:
- {
- $$ = Z;
- }
-| arglist
- {
- $$ = invert($1);
- }
-
-
-arglist:
- name
-| tlist abdecor
- {
- $$ = new(OPROTO, $2, Z);
- $$->type = $1;
- }
-| tlist xdecor
- {
- $$ = new(OPROTO, $2, Z);
- $$->type = $1;
- }
-| '.' '.' '.'
- {
- $$ = new(ODOTDOT, Z, Z);
- }
-| arglist ',' arglist
- {
- $$ = new(OLIST, $1, $3);
- }
-
-block:
- '{' slist '}'
- {
- $$ = invert($2);
- // if($2 != Z)
- // $$ = new(OLIST, $2, $$);
- if($$ == Z)
- $$ = new(OLIST, Z, Z);
- }
-
-slist:
- {
- $$ = Z;
- }
-| slist adecl
- {
- $$ = new(OLIST, $1, $2);
- }
-| slist stmnt
- {
- $$ = new(OLIST, $1, $2);
- }
-
-labels:
- label
-| labels label
- {
- $$ = new(OLIST, $1, $2);
- }
-
-label:
- LCASE expr ':'
- {
- $$ = new(OCASE, $2, Z);
- }
-| LDEFAULT ':'
- {
- $$ = new(OCASE, Z, Z);
- }
-| LNAME ':'
- {
- $$ = new(OLABEL, dcllabel($1, 1), Z);
- }
-
-stmnt:
- error ';'
- {
- $$ = Z;
- }
-| ulstmnt
-| labels ulstmnt
- {
- $$ = new(OLIST, $1, $2);
- }
-
-forexpr:
- zcexpr
-| ctlist adlist
- {
- $$ = $2;
- }
-
-ulstmnt:
- zcexpr ';'
-| {
- markdcl();
- }
- block
- {
- $$ = revertdcl();
- if($$)
- $$ = new(OLIST, $$, $2);
- else
- $$ = $2;
- }
-| LIF '(' cexpr ')' stmnt
- {
- $$ = new(OIF, $3, new(OLIST, $5, Z));
- if($5 == Z)
- warn($3, "empty if body");
- }
-| LIF '(' cexpr ')' stmnt LELSE stmnt
- {
- $$ = new(OIF, $3, new(OLIST, $5, $7));
- if($5 == Z)
- warn($3, "empty if body");
- if($7 == Z)
- warn($3, "empty else body");
- }
-| { markdcl(); } LFOR '(' forexpr ';' zcexpr ';' zcexpr ')' stmnt
- {
- $$ = revertdcl();
- if($$){
- if($4)
- $4 = new(OLIST, $$, $4);
- else
- $4 = $$;
- }
- $$ = new(OFOR, new(OLIST, $6, new(OLIST, $4, $8)), $10);
- }
-| LWHILE '(' cexpr ')' stmnt
- {
- $$ = new(OWHILE, $3, $5);
- }
-| LDO stmnt LWHILE '(' cexpr ')' ';'
- {
- $$ = new(ODWHILE, $5, $2);
- }
-| LRETURN zcexpr ';'
- {
- $$ = new(ORETURN, $2, Z);
- $$->type = thisfn->link;
- }
-| LSWITCH '(' cexpr ')' stmnt
- {
- $$ = new(OCONST, Z, Z);
- $$->vconst = 0;
- $$->type = types[TINT];
- $3 = new(OSUB, $$, $3);
-
- $$ = new(OCONST, Z, Z);
- $$->vconst = 0;
- $$->type = types[TINT];
- $3 = new(OSUB, $$, $3);
-
- $$ = new(OSWITCH, $3, $5);
- }
-| LBREAK ';'
- {
- $$ = new(OBREAK, Z, Z);
- }
-| LCONTINUE ';'
- {
- $$ = new(OCONTINUE, Z, Z);
- }
-| LGOTO ltag ';'
- {
- $$ = new(OGOTO, dcllabel($2, 0), Z);
- }
-| LUSED '(' zelist ')' ';'
- {
- $$ = new(OUSED, $3, Z);
- }
-| LPREFETCH '(' zelist ')' ';'
- {
- $$ = new(OPREFETCH, $3, Z);
- }
-| LSET '(' zelist ')' ';'
- {
- $$ = new(OSET, $3, Z);
- }
-
-zcexpr:
- {
- $$ = Z;
- }
-| cexpr
-
-zexpr:
- {
- $$ = Z;
- }
-| lexpr
-
-lexpr:
- expr
- {
- $$ = new(OCAST, $1, Z);
- $$->type = types[TLONG];
- }
-
-cexpr:
- expr
-| cexpr ',' cexpr
- {
- $$ = new(OCOMMA, $1, $3);
- }
-
-expr:
- xuexpr
-| expr '*' expr
- {
- $$ = new(OMUL, $1, $3);
- }
-| expr '/' expr
- {
- $$ = new(ODIV, $1, $3);
- }
-| expr '%' expr
- {
- $$ = new(OMOD, $1, $3);
- }
-| expr '+' expr
- {
- $$ = new(OADD, $1, $3);
- }
-| expr '-' expr
- {
- $$ = new(OSUB, $1, $3);
- }
-| expr LRSH expr
- {
- $$ = new(OASHR, $1, $3);
- }
-| expr LLSH expr
- {
- $$ = new(OASHL, $1, $3);
- }
-| expr '<' expr
- {
- $$ = new(OLT, $1, $3);
- }
-| expr '>' expr
- {
- $$ = new(OGT, $1, $3);
- }
-| expr LLE expr
- {
- $$ = new(OLE, $1, $3);
- }
-| expr LGE expr
- {
- $$ = new(OGE, $1, $3);
- }
-| expr LEQ expr
- {
- $$ = new(OEQ, $1, $3);
- }
-| expr LNE expr
- {
- $$ = new(ONE, $1, $3);
- }
-| expr '&' expr
- {
- $$ = new(OAND, $1, $3);
- }
-| expr '^' expr
- {
- $$ = new(OXOR, $1, $3);
- }
-| expr '|' expr
- {
- $$ = new(OOR, $1, $3);
- }
-| expr LANDAND expr
- {
- $$ = new(OANDAND, $1, $3);
- }
-| expr LOROR expr
- {
- $$ = new(OOROR, $1, $3);
- }
-| expr '?' cexpr ':' expr
- {
- $$ = new(OCOND, $1, new(OLIST, $3, $5));
- }
-| expr '=' expr
- {
- $$ = new(OAS, $1, $3);
- }
-| expr LPE expr
- {
- $$ = new(OASADD, $1, $3);
- }
-| expr LME expr
- {
- $$ = new(OASSUB, $1, $3);
- }
-| expr LMLE expr
- {
- $$ = new(OASMUL, $1, $3);
- }
-| expr LDVE expr
- {
- $$ = new(OASDIV, $1, $3);
- }
-| expr LMDE expr
- {
- $$ = new(OASMOD, $1, $3);
- }
-| expr LLSHE expr
- {
- $$ = new(OASASHL, $1, $3);
- }
-| expr LRSHE expr
- {
- $$ = new(OASASHR, $1, $3);
- }
-| expr LANDE expr
- {
- $$ = new(OASAND, $1, $3);
- }
-| expr LXORE expr
- {
- $$ = new(OASXOR, $1, $3);
- }
-| expr LORE expr
- {
- $$ = new(OASOR, $1, $3);
- }
-
-xuexpr:
- uexpr
-| '(' tlist abdecor ')' xuexpr
- {
- $$ = new(OCAST, $5, Z);
- dodecl(NODECL, CXXX, $2, $3);
- $$->type = lastdcl;
- $$->xcast = 1;
- }
-| '(' tlist abdecor ')' '{' ilist '}' /* extension */
- {
- $$ = new(OSTRUCT, $6, Z);
- dodecl(NODECL, CXXX, $2, $3);
- $$->type = lastdcl;
- }
-
-uexpr:
- pexpr
-| '*' xuexpr
- {
- $$ = new(OIND, $2, Z);
- }
-| '&' xuexpr
- {
- $$ = new(OADDR, $2, Z);
- }
-| '+' xuexpr
- {
- $$ = new(OPOS, $2, Z);
- }
-| '-' xuexpr
- {
- $$ = new(ONEG, $2, Z);
- }
-| '!' xuexpr
- {
- $$ = new(ONOT, $2, Z);
- }
-| '~' xuexpr
- {
- $$ = new(OCOM, $2, Z);
- }
-| LPP xuexpr
- {
- $$ = new(OPREINC, $2, Z);
- }
-| LMM xuexpr
- {
- $$ = new(OPREDEC, $2, Z);
- }
-| LSIZEOF uexpr
- {
- $$ = new(OSIZE, $2, Z);
- }
-| LSIGNOF uexpr
- {
- $$ = new(OSIGN, $2, Z);
- }
-
-pexpr:
- '(' cexpr ')'
- {
- $$ = $2;
- }
-| LSIZEOF '(' tlist abdecor ')'
- {
- $$ = new(OSIZE, Z, Z);
- dodecl(NODECL, CXXX, $3, $4);
- $$->type = lastdcl;
- }
-| LSIGNOF '(' tlist abdecor ')'
- {
- $$ = new(OSIGN, Z, Z);
- dodecl(NODECL, CXXX, $3, $4);
- $$->type = lastdcl;
- }
-| pexpr '(' zelist ')'
- {
- $$ = new(OFUNC, $1, Z);
- if($1->op == ONAME)
- if($1->type == T)
- dodecl(xdecl, CXXX, types[TINT], $$);
- $$->right = invert($3);
- }
-| pexpr '[' cexpr ']'
- {
- $$ = new(OIND, new(OADD, $1, $3), Z);
- }
-| pexpr LMG ltag
- {
- $$ = new(ODOT, new(OIND, $1, Z), Z);
- $$->sym = $3;
- }
-| pexpr '.' ltag
- {
- $$ = new(ODOT, $1, Z);
- $$->sym = $3;
- }
-| pexpr LPP
- {
- $$ = new(OPOSTINC, $1, Z);
- }
-| pexpr LMM
- {
- $$ = new(OPOSTDEC, $1, Z);
- }
-| name
-| LCONST
- {
- $$ = new(OCONST, Z, Z);
- $$->type = types[TINT];
- $$->vconst = $1;
- $$->cstring = strdup(symb);
- }
-| LLCONST
- {
- $$ = new(OCONST, Z, Z);
- $$->type = types[TLONG];
- $$->vconst = $1;
- $$->cstring = strdup(symb);
- }
-| LUCONST
- {
- $$ = new(OCONST, Z, Z);
- $$->type = types[TUINT];
- $$->vconst = $1;
- $$->cstring = strdup(symb);
- }
-| LULCONST
- {
- $$ = new(OCONST, Z, Z);
- $$->type = types[TULONG];
- $$->vconst = $1;
- $$->cstring = strdup(symb);
- }
-| LDCONST
- {
- $$ = new(OCONST, Z, Z);
- $$->type = types[TDOUBLE];
- $$->fconst = $1;
- $$->cstring = strdup(symb);
- }
-| LFCONST
- {
- $$ = new(OCONST, Z, Z);
- $$->type = types[TFLOAT];
- $$->fconst = $1;
- $$->cstring = strdup(symb);
- }
-| LVLCONST
- {
- $$ = new(OCONST, Z, Z);
- $$->type = types[TVLONG];
- $$->vconst = $1;
- $$->cstring = strdup(symb);
- }
-| LUVLCONST
- {
- $$ = new(OCONST, Z, Z);
- $$->type = types[TUVLONG];
- $$->vconst = $1;
- $$->cstring = strdup(symb);
- }
-| string
-| lstring
-
-string:
- LSTRING
- {
- $$ = new(OSTRING, Z, Z);
- $$->type = typ(TARRAY, types[TCHAR]);
- $$->type->width = $1.l + 1;
- $$->cstring = $1.s;
- $$->sym = symstring;
- $$->etype = TARRAY;
- $$->class = CSTATIC;
- }
-| string LSTRING
- {
- char *s;
- int n;
-
- n = $1->type->width - 1;
- s = alloc(n+$2.l+MAXALIGN);
-
- memcpy(s, $1->cstring, n);
- memcpy(s+n, $2.s, $2.l);
- s[n+$2.l] = 0;
-
- $$ = $1;
- $$->type->width += $2.l;
- $$->cstring = s;
- }
-
-lstring:
- LLSTRING
- {
- $$ = new(OLSTRING, Z, Z);
- $$->type = typ(TARRAY, types[TRUNE]);
- $$->type->width = $1.l + sizeof(TRune);
- $$->rstring = (TRune*)$1.s;
- $$->sym = symstring;
- $$->etype = TARRAY;
- $$->class = CSTATIC;
- }
-| lstring LLSTRING
- {
- char *s;
- int n;
-
- n = $1->type->width - sizeof(TRune);
- s = alloc(n+$2.l+MAXALIGN);
-
- memcpy(s, $1->rstring, n);
- memcpy(s+n, $2.s, $2.l);
- *(TRune*)(s+n+$2.l) = 0;
-
- $$ = $1;
- $$->type->width += $2.l;
- $$->rstring = (TRune*)s;
- }
-
-zelist:
- {
- $$ = Z;
- }
-| elist
-
-elist:
- expr
-| elist ',' elist
- {
- $$ = new(OLIST, $1, $3);
- }
-
-sbody:
- '{'
- {
- $<tyty>$.t1 = strf;
- $<tyty>$.t2 = strl;
- $<tyty>$.t3 = lasttype;
- $<tyty>$.c = lastclass;
- strf = T;
- strl = T;
- lastbit = 0;
- firstbit = 1;
- lastclass = CXXX;
- lasttype = T;
- }
- edecl '}'
- {
- $$ = strf;
- strf = $<tyty>2.t1;
- strl = $<tyty>2.t2;
- lasttype = $<tyty>2.t3;
- lastclass = $<tyty>2.c;
- }
-
-zctlist:
- {
- lastclass = CXXX;
- lasttype = types[TINT];
- }
-| ctlist
-
-types:
- complex
- {
- $$.t = $1;
- $$.c = CXXX;
- }
-| tname
- {
- $$.t = simplet($1);
- $$.c = CXXX;
- }
-| gcnlist
- {
- $$.t = simplet($1);
- $$.c = simplec($1);
- $$.t = garbt($$.t, $1);
- }
-| complex gctnlist
- {
- $$.t = $1;
- $$.c = simplec($2);
- $$.t = garbt($$.t, $2);
- if($2 & ~BCLASS & ~BGARB)
- diag(Z, "duplicate types given: %T and %Q", $1, $2);
- }
-| tname gctnlist
- {
- $$.t = simplet(typebitor($1, $2));
- $$.c = simplec($2);
- $$.t = garbt($$.t, $2);
- }
-| gcnlist complex zgnlist
- {
- $$.t = $2;
- $$.c = simplec($1);
- $$.t = garbt($$.t, $1|$3);
- }
-| gcnlist tname
- {
- $$.t = simplet($2);
- $$.c = simplec($1);
- $$.t = garbt($$.t, $1);
- }
-| gcnlist tname gctnlist
- {
- $$.t = simplet(typebitor($2, $3));
- $$.c = simplec($1|$3);
- $$.t = garbt($$.t, $1|$3);
- }
-
-tlist:
- types
- {
- $$ = $1.t;
- if($1.c != CXXX)
- diag(Z, "illegal combination of class 4: %s", cnames[$1.c]);
- }
-
-ctlist:
- types
- {
- lasttype = $1.t;
- lastclass = $1.c;
- }
-
-complex:
- LSTRUCT ltag
- {
- dotag($2, TSTRUCT, 0);
- $$ = $2->suetag;
- }
-| LSTRUCT ltag
- {
- dotag($2, TSTRUCT, autobn);
- }
- sbody
- {
- $$ = $2->suetag;
- if($$->link != T)
- diag(Z, "redeclare tag: %s", $2->name);
- $$->link = $4;
- sualign($$);
- }
-| LSTRUCT sbody
- {
- diag(Z, "struct must have tag");
- taggen++;
- sprint(symb, "_%d_", taggen);
- $$ = dotag(lookup(), TSTRUCT, autobn);
- $$->link = $2;
- sualign($$);
- }
-| LUNION ltag
- {
- dotag($2, TUNION, 0);
- $$ = $2->suetag;
- }
-| LUNION ltag
- {
- dotag($2, TUNION, autobn);
- }
- sbody
- {
- $$ = $2->suetag;
- if($$->link != T)
- diag(Z, "redeclare tag: %s", $2->name);
- $$->link = $4;
- sualign($$);
- }
-| LUNION sbody
- {
- taggen++;
- sprint(symb, "_%d_", taggen);
- $$ = dotag(lookup(), TUNION, autobn);
- $$->link = $2;
- sualign($$);
- }
-| LENUM ltag
- {
- dotag($2, TENUM, 0);
- $$ = $2->suetag;
- if($$->link == T)
- $$->link = types[TINT];
- $$ = $$->link;
- }
-| LENUM ltag
- {
- dotag($2, TENUM, autobn);
- }
- '{'
- {
- en.tenum = T;
- en.cenum = T;
- }
- enum '}'
- {
- $$ = $2->suetag;
- if($$->link != T)
- diag(Z, "redeclare tag: %s", $2->name);
- if(en.tenum == T) {
- diag(Z, "enum type ambiguous: %s", $2->name);
- en.tenum = types[TINT];
- }
- $$->link = en.tenum;
- $$ = en.tenum;
- }
-| LENUM '{'
- {
- en.tenum = T;
- en.cenum = T;
- }
- enum '}'
- {
- $$ = en.tenum;
- }
-| LTYPE
- {
- $$ = tcopy($1->type);
- }
-
-gctnlist:
- gctname
-| gctnlist gctname
- {
- $$ = typebitor($1, $2);
- }
-
-zgnlist:
- {
- $$ = 0;
- }
-| zgnlist gname
- {
- $$ = typebitor($1, $2);
- }
-
-gctname:
- tname
-| gname
-| cname
-
-gcnlist:
- gcname
-| gcnlist gcname
- {
- $$ = typebitor($1, $2);
- }
-
-gcname:
- gname
-| cname
-
-enum:
- LNAME
- {
- doenum($1, Z);
- }
-| LNAME '=' expr
- {
- doenum($1, $3);
- }
-| enum ','
-| enum ',' enum
-
-tname: /* type words */
- LCHAR { $$ = BCHAR; }
-| LSHORT { $$ = BSHORT; }
-| LINT { $$ = BINT; }
-| LLONG { $$ = BLONG; }
-| LSIGNED { $$ = BSIGNED; }
-| LUNSIGNED { $$ = BUNSIGNED; }
-| LFLOAT { $$ = BFLOAT; }
-| LDOUBLE { $$ = BDOUBLE; }
-| LVOID { $$ = BVOID; }
-
-cname: /* class words */
- LAUTO { $$ = BAUTO; }
-| LSTATIC { $$ = BSTATIC; }
-| LEXTERN { $$ = BEXTERN; }
-| LTYPEDEF { $$ = BTYPEDEF; }
-| LTYPESTR { $$ = BTYPESTR; }
-| LREGISTER { $$ = BREGISTER; }
-| LINLINE { $$ = 0; }
-
-gname: /* garbage words */
- LCONSTNT { $$ = BCONSTNT; }
-| LVOLATILE { $$ = BVOLATILE; }
-| LRESTRICT { $$ = 0; }
-
-name:
- LNAME
- {
- $$ = new(ONAME, Z, Z);
- if($1->class == CLOCAL)
- $1 = mkstatic($1);
- $$->sym = $1;
- $$->type = $1->type;
- $$->etype = TVOID;
- if($$->type != T)
- $$->etype = $$->type->etype;
- $$->xoffset = $1->offset;
- $$->class = $1->class;
- $1->aused = 1;
- }
-tag:
- ltag
- {
- $$ = new(ONAME, Z, Z);
- $$->sym = $1;
- $$->type = $1->type;
- $$->etype = TVOID;
- if($$->type != T)
- $$->etype = $$->type->etype;
- $$->xoffset = $1->offset;
- $$->class = $1->class;
- }
-ltag:
- LNAME
-| LTYPE
-%%
diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c
deleted file mode 100644
index 4886b73eb..000000000
--- a/src/cmd/cc/com.c
+++ /dev/null
@@ -1,1384 +0,0 @@
-// Inferno utils/cc/com.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/com.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-
-int compar(Node*, int);
-
-void
-complex(Node *n)
-{
-
- if(n == Z)
- return;
-
- nearln = n->lineno;
- if(debug['t'])
- if(n->op != OCONST)
- prtree(n, "pre complex");
- if(tcom(n))
- return;
- if(debug['t'])
- if(n->op != OCONST)
- prtree(n, "t complex");
- ccom(n);
- if(debug['t'])
- if(n->op != OCONST)
- prtree(n, "c complex");
- acom(n);
- if(debug['t'])
- if(n->op != OCONST)
- prtree(n, "a complex");
- xcom(n);
- if(debug['t'])
- if(n->op != OCONST)
- prtree(n, "x complex");
-}
-
-/*
- * evaluate types
- * evaluate lvalues (addable == 1)
- */
-enum
-{
- ADDROF = 1<<0,
- CASTOF = 1<<1,
- ADDROP = 1<<2,
-};
-
-int
-tcom(Node *n)
-{
-
- return tcomo(n, ADDROF);
-}
-
-int
-tcomo(Node *n, int f)
-{
- Node *l, *r;
- Type *t;
- int o;
- static TRune zer;
-
- if(n == Z) {
- diag(Z, "Z in tcom");
- errorexit();
- }
- n->addable = 0;
- l = n->left;
- r = n->right;
-
- switch(n->op) {
- default:
- diag(n, "unknown op in type complex: %O", n->op);
- goto bad;
-
- case ODOTDOT:
- /*
- * tcom has already been called on this subtree
- */
- *n = *n->left;
- if(n->type == T)
- goto bad;
- break;
-
- case OCAST:
- if(n->type == T)
- break;
- if(n->type->width == types[TLONG]->width) {
- if(tcomo(l, ADDROF|CASTOF))
- goto bad;
- } else
- if(tcom(l))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, l->type, n->type, tcast))
- goto bad;
- break;
-
- case ORETURN:
- if(l == Z) {
- if(n->type->etype != TVOID)
- diag(n, "null return of a typed function");
- break;
- }
- if(tcom(l))
- goto bad;
- typeext(n->type, l);
- if(tcompat(n, n->type, l->type, tasign))
- break;
- constas(n, n->type, l->type);
- if(!sametype(n->type, l->type)) {
- l = new1(OCAST, l, Z);
- l->type = n->type;
- n->left = l;
- }
- break;
-
- case OASI: /* same as as, but no test for const */
- n->op = OAS;
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
-
- typeext(l->type, r);
- if(tlvalue(l) || tcompat(n, l->type, r->type, tasign))
- goto bad;
- if(!sametype(l->type, r->type)) {
- r = new1(OCAST, r, Z);
- r->type = l->type;
- n->right = r;
- }
- n->type = l->type;
- break;
-
- case OAS:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(tlvalue(l))
- goto bad;
- if(isfunct(n))
- break;
- typeext(l->type, r);
- if(tcompat(n, l->type, r->type, tasign))
- goto bad;
- constas(n, l->type, r->type);
- if(!sametype(l->type, r->type)) {
- r = new1(OCAST, r, Z);
- r->type = l->type;
- n->right = r;
- }
- n->type = l->type;
- break;
-
- case OASADD:
- case OASSUB:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(tlvalue(l))
- goto bad;
- if(isfunct(n))
- break;
- typeext1(l->type, r);
- if(tcompat(n, l->type, r->type, tasadd))
- goto bad;
- constas(n, l->type, r->type);
- t = l->type;
- arith(n, 0);
- while(n->left->op == OCAST)
- n->left = n->left->left;
- if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
- r = new1(OCAST, n->right, Z);
- r->type = t;
- n->right = r;
- n->type = t;
- }
- break;
-
- case OASMUL:
- case OASLMUL:
- case OASDIV:
- case OASLDIV:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(tlvalue(l))
- goto bad;
- if(isfunct(n))
- break;
- typeext1(l->type, r);
- if(tcompat(n, l->type, r->type, tmul))
- goto bad;
- constas(n, l->type, r->type);
- t = l->type;
- arith(n, 0);
- while(n->left->op == OCAST)
- n->left = n->left->left;
- if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
- r = new1(OCAST, n->right, Z);
- r->type = t;
- n->right = r;
- n->type = t;
- }
- if(typeu[n->type->etype]) {
- if(n->op == OASDIV)
- n->op = OASLDIV;
- if(n->op == OASMUL)
- n->op = OASLMUL;
- }
- break;
-
- case OASLSHR:
- case OASASHR:
- case OASASHL:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(tlvalue(l))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, l->type, r->type, tand))
- goto bad;
- n->type = l->type;
- if(typeu[n->type->etype]) {
- if(n->op == OASASHR)
- n->op = OASLSHR;
- }
- break;
-
- case OASMOD:
- case OASLMOD:
- case OASOR:
- case OASAND:
- case OASXOR:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(tlvalue(l))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, l->type, r->type, tand))
- goto bad;
- t = l->type;
- arith(n, 0);
- while(n->left->op == OCAST)
- n->left = n->left->left;
- if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
- r = new1(OCAST, n->right, Z);
- r->type = t;
- n->right = r;
- n->type = t;
- }
- if(typeu[n->type->etype]) {
- if(n->op == OASMOD)
- n->op = OASLMOD;
- }
- break;
-
- case OPREINC:
- case OPREDEC:
- case OPOSTINC:
- case OPOSTDEC:
- if(tcom(l))
- goto bad;
- if(tlvalue(l))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, l->type, types[TINT], tadd))
- goto bad;
- n->type = l->type;
- if(n->type->etype == TIND)
- if(n->type->link->width < 1)
- diag(n, "inc/dec of a void pointer");
- break;
-
- case OEQ:
- case ONE:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(isfunct(n))
- break;
- typeext(l->type, r);
- typeext(r->type, l);
- if(tcompat(n, l->type, r->type, trel))
- goto bad;
- arith(n, 0);
- n->type = types[TINT];
- break;
-
- case OLT:
- case OGE:
- case OGT:
- case OLE:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(isfunct(n))
- break;
- typeext1(l->type, r);
- typeext1(r->type, l);
- if(tcompat(n, l->type, r->type, trel))
- goto bad;
- arith(n, 0);
- if(typeu[n->type->etype])
- n->op = logrel[relindex(n->op)];
- n->type = types[TINT];
- break;
-
- case OCOND:
- o = tcom(l);
- o |= tcom(r->left);
- if(o | tcom(r->right))
- goto bad;
- if(r->right->type->etype == TIND && vconst(r->left) == 0) {
- r->left->type = r->right->type;
- r->left->vconst = 0;
- }
- if(r->left->type->etype == TIND && vconst(r->right) == 0) {
- r->right->type = r->left->type;
- r->right->vconst = 0;
- }
- if(sametype(r->right->type, r->left->type)) {
- r->type = r->right->type;
- n->type = r->type;
- break;
- }
- if(tcompat(r, r->left->type, r->right->type, trel))
- goto bad;
- arith(r, 0);
- n->type = r->type;
- break;
-
- case OADD:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, l->type, r->type, tadd))
- goto bad;
- arith(n, 1);
- break;
-
- case OSUB:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, l->type, r->type, tsub))
- goto bad;
- arith(n, 1);
- break;
-
- case OMUL:
- case OLMUL:
- case ODIV:
- case OLDIV:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, l->type, r->type, tmul))
- goto bad;
- arith(n, 1);
- if(typeu[n->type->etype]) {
- if(n->op == ODIV)
- n->op = OLDIV;
- if(n->op == OMUL)
- n->op = OLMUL;
- }
- break;
-
- case OLSHR:
- case OASHL:
- case OASHR:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, l->type, r->type, tand))
- goto bad;
- n->right = Z;
- arith(n, 1);
- n->right = new1(OCAST, r, Z);
- n->right->type = types[TINT];
- if(typeu[n->type->etype])
- if(n->op == OASHR)
- n->op = OLSHR;
- break;
-
- case OAND:
- case OOR:
- case OXOR:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, l->type, r->type, tand))
- goto bad;
- arith(n, 1);
- break;
-
- case OMOD:
- case OLMOD:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, l->type, r->type, tand))
- goto bad;
- arith(n, 1);
- if(typeu[n->type->etype])
- n->op = OLMOD;
- break;
-
- case OPOS:
- if(tcom(l))
- goto bad;
- if(isfunct(n))
- break;
-
- r = l;
- l = new(OCONST, Z, Z);
- l->vconst = 0;
- l->type = types[TINT];
- n->op = OADD;
- n->right = r;
- n->left = l;
-
- if(tcom(l))
- goto bad;
- if(tcompat(n, l->type, r->type, tsub))
- goto bad;
- arith(n, 1);
- break;
-
- case ONEG:
- if(tcom(l))
- goto bad;
- if(isfunct(n))
- break;
-
- if(!machcap(n)) {
- r = l;
- l = new(OCONST, Z, Z);
- l->vconst = 0;
- l->type = types[TINT];
- n->op = OSUB;
- n->right = r;
- n->left = l;
-
- if(tcom(l))
- goto bad;
- if(tcompat(n, l->type, r->type, tsub))
- goto bad;
- }
- arith(n, 1);
- break;
-
- case OCOM:
- if(tcom(l))
- goto bad;
- if(isfunct(n))
- break;
-
- if(!machcap(n)) {
- r = l;
- l = new(OCONST, Z, Z);
- l->vconst = -1;
- l->type = types[TINT];
- n->op = OXOR;
- n->right = r;
- n->left = l;
-
- if(tcom(l))
- goto bad;
- if(tcompat(n, l->type, r->type, tand))
- goto bad;
- }
- arith(n, 1);
- break;
-
- case ONOT:
- if(tcom(l))
- goto bad;
- if(isfunct(n))
- break;
- if(tcompat(n, T, l->type, tnot))
- goto bad;
- n->type = types[TINT];
- break;
-
- case OANDAND:
- case OOROR:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- if(tcompat(n, T, l->type, tnot) |
- tcompat(n, T, r->type, tnot))
- goto bad;
- n->type = types[TINT];
- break;
-
- case OCOMMA:
- o = tcom(l);
- if(o | tcom(r))
- goto bad;
- n->type = r->type;
- break;
-
-
- case OSIGN: /* extension signof(type) returns a hash */
- if(l != Z) {
- if(l->op != OSTRING && l->op != OLSTRING)
- if(tcomo(l, 0))
- goto bad;
- if(l->op == OBIT) {
- diag(n, "signof bitfield");
- goto bad;
- }
- n->type = l->type;
- }
- if(n->type == T)
- goto bad;
- if(n->type->width < 0) {
- diag(n, "signof undefined type");
- goto bad;
- }
- n->op = OCONST;
- n->left = Z;
- n->right = Z;
- n->vconst = convvtox(signature(n->type), TULONG);
- n->type = types[TULONG];
- break;
-
- case OSIZE:
- if(l != Z) {
- if(l->op != OSTRING && l->op != OLSTRING)
- if(tcomo(l, 0))
- goto bad;
- if(l->op == OBIT) {
- diag(n, "sizeof bitfield");
- goto bad;
- }
- n->type = l->type;
- }
- if(n->type == T)
- goto bad;
- if(n->type->width <= 0) {
- diag(n, "sizeof undefined type");
- goto bad;
- }
- if(n->type->etype == TFUNC) {
- diag(n, "sizeof function");
- goto bad;
- }
- n->op = OCONST;
- n->left = Z;
- n->right = Z;
- n->vconst = convvtox(n->type->width, TINT);
- n->type = types[TINT];
- break;
-
- case OFUNC:
- o = tcomo(l, 0);
- if(o)
- goto bad;
- if(l->type->etype == TIND && l->type->link->etype == TFUNC) {
- l = new1(OIND, l, Z);
- l->type = l->left->type->link;
- n->left = l;
- }
- if(tcompat(n, T, l->type, tfunct))
- goto bad;
- if(o | tcoma(l, r, l->type->down, 1))
- goto bad;
- n->type = l->type->link;
- if(!debug['B'])
- if(l->type->down == T || l->type->down->etype == TOLD) {
- nerrors--;
- diag(n, "function args not checked: %F", l);
- }
- dpcheck(n);
- break;
-
- case ONAME:
- if(n->type == T) {
- diag(n, "name not declared: %F", n);
- goto bad;
- }
- if(n->type->etype == TENUM) {
- n->op = OCONST;
- n->type = n->sym->tenum;
- if(!typefd[n->type->etype])
- n->vconst = n->sym->vconst;
- else
- n->fconst = n->sym->fconst;
- break;
- }
- n->addable = 1;
- if(n->class == CEXREG) {
- n->op = OREGISTER;
- // on 386 or amd64, "extern register" generates
- // memory references relative to the
- // gs or fs segment.
- if(thechar == '8' || thechar == '6') // [sic]
- n->op = OEXREG;
- n->reg = n->sym->offset;
- n->xoffset = 0;
- break;
- }
- break;
-
- case OLSTRING:
- if(n->type->link != types[TRUNE]) {
- o = outstring(0, 0);
- while(o & 3) {
- outlstring(&zer, sizeof(TRune));
- o = outlstring(0, 0);
- }
- }
- n->op = ONAME;
- n->xoffset = outlstring(n->rstring, n->type->width);
- n->addable = 1;
- break;
-
- case OSTRING:
- if(n->type->link != types[TCHAR]) {
- o = outstring(0, 0);
- while(o & 3) {
- outstring("", 1);
- o = outstring(0, 0);
- }
- }
- n->op = ONAME;
- n->xoffset = outstring(n->cstring, n->type->width);
- n->addable = 1;
- break;
-
- case OCONST:
- break;
-
- case ODOT:
- if(tcom(l))
- goto bad;
- if(tcompat(n, T, l->type, tdot))
- goto bad;
- if(tcomd(n))
- goto bad;
- break;
-
- case OADDR:
- if(tcomo(l, ADDROP))
- goto bad;
- if(tlvalue(l))
- goto bad;
- if(l->type->nbits) {
- diag(n, "address of a bit field");
- goto bad;
- }
- if(l->op == OREGISTER) {
- diag(n, "address of a register");
- goto bad;
- }
- n->type = typ(TIND, l->type);
- n->type->width = types[TIND]->width;
- break;
-
- case OIND:
- if(tcom(l))
- goto bad;
- if(tcompat(n, T, l->type, tindir))
- goto bad;
- n->type = l->type->link;
- n->addable = 1;
- break;
-
- case OSTRUCT:
- if(tcomx(n))
- goto bad;
- break;
- }
- t = n->type;
- if(t == T)
- goto bad;
- if(t->width < 0) {
- snap(t);
- if(t->width < 0) {
- if(typesu[t->etype] && t->tag)
- diag(n, "structure not fully declared %s", t->tag->name);
- else
- diag(n, "structure not fully declared");
- goto bad;
- }
- }
- if(typeaf[t->etype]) {
- if(f & ADDROF)
- goto addaddr;
- if(f & ADDROP)
- warn(n, "address of array/func ignored");
- }
- return 0;
-
-addaddr:
- if(tlvalue(n))
- goto bad;
- l = new1(OXXX, Z, Z);
- *l = *n;
- n->op = OADDR;
- if(l->type->etype == TARRAY)
- l->type = l->type->link;
- n->left = l;
- n->right = Z;
- n->addable = 0;
- n->type = typ(TIND, l->type);
- n->type->width = types[TIND]->width;
- return 0;
-
-bad:
- n->type = T;
- return 1;
-}
-
-int
-tcoma(Node *l, Node *n, Type *t, int f)
-{
- Node *n1;
- int o;
-
- if(t != T)
- if(t->etype == TOLD || t->etype == TDOT) /* .../old in prototype */
- t = T;
- if(n == Z) {
- if(t != T && !sametype(t, types[TVOID])) {
- diag(n, "not enough function arguments: %F", l);
- return 1;
- }
- return 0;
- }
- if(n->op == OLIST) {
- o = tcoma(l, n->left, t, 0);
- if(t != T) {
- t = t->down;
- if(t == T)
- t = types[TVOID];
- }
- return o | tcoma(l, n->right, t, 1);
- }
- if(f && t != T)
- tcoma(l, Z, t->down, 0);
- if(tcom(n) || tcompat(n, T, n->type, targ))
- return 1;
- if(sametype(t, types[TVOID])) {
- diag(n, "too many function arguments: %F", l);
- return 1;
- }
- if(t != T) {
- typeext(t, n);
- if(stcompat(nodproto, t, n->type, tasign)) {
- diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F",
- n->type, t, l);
- return 1;
- }
-// switch(t->etype) {
-// case TCHAR:
-// case TSHORT:
-// t = types[TINT];
-// break;
-//
-// case TUCHAR:
-// case TUSHORT:
-// t = types[TUINT];
-// break;
-// }
- } else {
- switch(n->type->etype) {
- case TCHAR:
- case TSHORT:
- t = types[TINT];
- break;
-
- case TUCHAR:
- case TUSHORT:
- t = types[TUINT];
- break;
-
- case TFLOAT:
- t = types[TDOUBLE];
- }
- }
-
- if(t != T && !sametype(t, n->type)) {
- n1 = new1(OXXX, Z, Z);
- *n1 = *n;
- n->op = OCAST;
- n->left = n1;
- n->right = Z;
- n->type = t;
- n->addable = 0;
- }
- return 0;
-}
-
-int
-tcomd(Node *n)
-{
- Type *t;
- int32 o;
-
- o = 0;
- t = dotsearch(n->sym, n->left->type->link, n, &o);
- if(t == T) {
- diag(n, "not a member of struct/union: %F", n);
- return 1;
- }
- makedot(n, t, o);
- return 0;
-}
-
-int
-tcomx(Node *n)
-{
- Type *t;
- Node *l, *r, **ar, **al;
- int e;
-
- e = 0;
- if(n->type->etype != TSTRUCT) {
- diag(n, "constructor must be a structure");
- return 1;
- }
- l = invert(n->left);
- n->left = l;
- al = &n->left;
- for(t = n->type->link; t != T; t = t->down) {
- if(l == Z) {
- diag(n, "constructor list too short");
- return 1;
- }
- if(l->op == OLIST) {
- r = l->left;
- ar = &l->left;
- al = &l->right;
- l = l->right;
- } else {
- r = l;
- ar = al;
- l = Z;
- }
- if(tcom(r))
- e++;
- typeext(t, r);
- if(tcompat(n, t, r->type, tasign))
- e++;
- constas(n, t, r->type);
- if(!e && !sametype(t, r->type)) {
- r = new1(OCAST, r, Z);
- r->type = t;
- *ar = r;
- }
- }
- if(l != Z) {
- diag(n, "constructor list too long");
- return 1;
- }
- return e;
-}
-
-int
-tlvalue(Node *n)
-{
-
- if(!n->addable) {
- diag(n, "not an l-value");
- return 1;
- }
- return 0;
-}
-
-/*
- * general rewrite
- * (IND(ADDR x)) ==> x
- * (ADDR(IND x)) ==> x
- * remove some zero operands
- * remove no op casts
- * evaluate constants
- */
-void
-ccom(Node *n)
-{
- Node *l, *r;
- int t;
-
-loop:
- if(n == Z)
- return;
- l = n->left;
- r = n->right;
- switch(n->op) {
-
- case OAS:
- case OASXOR:
- case OASAND:
- case OASOR:
- case OASMOD:
- case OASLMOD:
- case OASLSHR:
- case OASASHR:
- case OASASHL:
- case OASDIV:
- case OASLDIV:
- case OASMUL:
- case OASLMUL:
- case OASSUB:
- case OASADD:
- ccom(l);
- ccom(r);
- if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL)
- if(r->op == OCONST) {
- t = n->type->width * 8; /* bits per byte */
- if(r->vconst >= t || r->vconst < 0)
- warn(n, "stupid shift: %lld", r->vconst);
- }
- break;
-
- case OCAST:
- ccom(l);
- if(l->op == OCONST) {
- evconst(n);
- if(n->op == OCONST)
- break;
- }
- if(nocast(l->type, n->type)) {
- l->type = n->type;
- *n = *l;
- }
- break;
-
- case OCOND:
- ccom(l);
- ccom(r);
- if(l->op == OCONST)
- if(vconst(l) == 0)
- *n = *r->right;
- else
- *n = *r->left;
- break;
-
- case OREGISTER:
- case OINDREG:
- case OCONST:
- case ONAME:
- break;
-
- case OADDR:
- ccom(l);
- l->etype = TVOID;
- if(l->op == OIND) {
- l->left->type = n->type;
- *n = *l->left;
- break;
- }
- goto common;
-
- case OIND:
- ccom(l);
- if(l->op == OADDR) {
- l->left->type = n->type;
- *n = *l->left;
- break;
- }
- goto common;
-
- case OEQ:
- case ONE:
-
- case OLE:
- case OGE:
- case OLT:
- case OGT:
-
- case OLS:
- case OHS:
- case OLO:
- case OHI:
- ccom(l);
- ccom(r);
- if(compar(n, 0) || compar(n, 1))
- break;
- relcon(l, r);
- relcon(r, l);
- goto common;
-
- case OASHR:
- case OASHL:
- case OLSHR:
- ccom(l);
- if(vconst(l) == 0 && !side(r)) {
- *n = *l;
- break;
- }
- ccom(r);
- if(vconst(r) == 0) {
- *n = *l;
- break;
- }
- if(r->op == OCONST) {
- t = n->type->width * 8; /* bits per byte */
- if(r->vconst >= t || r->vconst <= -t)
- warn(n, "stupid shift: %lld", r->vconst);
- }
- goto common;
-
- case OMUL:
- case OLMUL:
- ccom(l);
- t = vconst(l);
- if(t == 0 && !side(r)) {
- *n = *l;
- break;
- }
- if(t == 1) {
- *n = *r;
- goto loop;
- }
- ccom(r);
- t = vconst(r);
- if(t == 0 && !side(l)) {
- *n = *r;
- break;
- }
- if(t == 1) {
- *n = *l;
- break;
- }
- goto common;
-
- case ODIV:
- case OLDIV:
- ccom(l);
- if(vconst(l) == 0 && !side(r)) {
- *n = *l;
- break;
- }
- ccom(r);
- t = vconst(r);
- if(t == 0) {
- diag(n, "divide check");
- *n = *r;
- break;
- }
- if(t == 1) {
- *n = *l;
- break;
- }
- goto common;
-
- case OSUB:
- ccom(r);
- if(r->op == OCONST) {
- if(typefd[r->type->etype]) {
- n->op = OADD;
- r->fconst = -r->fconst;
- goto loop;
- } else {
- n->op = OADD;
- r->vconst = -r->vconst;
- goto loop;
- }
- }
- ccom(l);
- goto common;
-
- case OXOR:
- case OOR:
- case OADD:
- ccom(l);
- if(vconst(l) == 0) {
- *n = *r;
- goto loop;
- }
- ccom(r);
- if(vconst(r) == 0) {
- *n = *l;
- break;
- }
- goto commute;
-
- case OAND:
- ccom(l);
- ccom(r);
- if(vconst(l) == 0 && !side(r)) {
- *n = *l;
- break;
- }
- if(vconst(r) == 0 && !side(l)) {
- *n = *r;
- break;
- }
-
- commute:
- /* look for commutative constant */
- if(r->op == OCONST) {
- if(l->op == n->op) {
- if(l->left->op == OCONST) {
- n->right = l->right;
- l->right = r;
- goto loop;
- }
- if(l->right->op == OCONST) {
- n->right = l->left;
- l->left = r;
- goto loop;
- }
- }
- }
- if(l->op == OCONST) {
- if(r->op == n->op) {
- if(r->left->op == OCONST) {
- n->left = r->right;
- r->right = l;
- goto loop;
- }
- if(r->right->op == OCONST) {
- n->left = r->left;
- r->left = l;
- goto loop;
- }
- }
- }
- goto common;
-
- case OANDAND:
- ccom(l);
- if(vconst(l) == 0) {
- *n = *l;
- break;
- }
- ccom(r);
- goto common;
-
- case OOROR:
- ccom(l);
- if(l->op == OCONST && l->vconst != 0) {
- *n = *l;
- n->vconst = 1;
- break;
- }
- ccom(r);
- goto common;
-
- default:
- if(l != Z)
- ccom(l);
- if(r != Z)
- ccom(r);
- common:
- if(l != Z)
- if(l->op != OCONST)
- break;
- if(r != Z)
- if(r->op != OCONST)
- break;
- evconst(n);
- }
-}
-
-/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
-static char *cmps[12] =
-{
- "==", "!=", "<=", "<=", "<", "<", ">=", ">=", ">", ">",
-};
-
-/* 128-bit numbers */
-typedef struct Big Big;
-struct Big
-{
- vlong a;
- uvlong b;
-};
-static int
-cmp(Big x, Big y)
-{
- if(x.a != y.a){
- if(x.a < y.a)
- return -1;
- return 1;
- }
- if(x.b != y.b){
- if(x.b < y.b)
- return -1;
- return 1;
- }
- return 0;
-}
-static Big
-add(Big x, int y)
-{
- uvlong ob;
-
- ob = x.b;
- x.b += y;
- if(y > 0 && x.b < ob)
- x.a++;
- if(y < 0 && x.b > ob)
- x.a--;
- return x;
-}
-
-Big
-big(vlong a, uvlong b)
-{
- Big x;
-
- x.a = a;
- x.b = b;
- return x;
-}
-
-int
-compar(Node *n, int reverse)
-{
- Big lo, hi, x;
- int op;
- char xbuf[40], cmpbuf[50];
- Node *l, *r;
- Type *lt, *rt;
-
- /*
- * The point of this function is to diagnose comparisons
- * that can never be true or that look misleading because
- * of the `usual arithmetic conversions'. As an example
- * of the latter, if x is a ulong, then if(x <= -1) really means
- * if(x <= 0xFFFFFFFF), while if(x <= -1LL) really means
- * what it says (but 8c compiles it wrong anyway).
- */
-
- if(reverse){
- r = n->left;
- l = n->right;
- op = comrel[relindex(n->op)];
- }else{
- l = n->left;
- r = n->right;
- op = n->op;
- }
-
- /*
- * Skip over left casts to find out the original expression range.
- */
- while(l->op == OCAST)
- l = l->left;
- if(l->op == OCONST)
- return 0;
- lt = l->type;
- if(l->op == ONAME && l->sym->type){
- lt = l->sym->type;
- if(lt->etype == TARRAY)
- lt = lt->link;
- }
- if(lt == T)
- return 0;
- if(lt->etype == TXXX || lt->etype > TUVLONG)
- return 0;
-
- /*
- * Skip over the right casts to find the on-screen value.
- */
- if(r->op != OCONST)
- return 0;
- while(r->oldop == OCAST && !r->xcast)
- r = r->left;
- rt = r->type;
- if(rt == T)
- return 0;
-
- x.b = r->vconst;
- x.a = 0;
- if((rt->etype&1) && r->vconst < 0) /* signed negative */
- x.a = ~0ULL;
-
- if((lt->etype&1)==0){
- /* unsigned */
- lo = big(0, 0);
- if(lt->width == 8)
- hi = big(0, ~0ULL);
- else
- hi = big(0, (1ULL<<(l->type->width*8))-1);
- }else{
- lo = big(~0ULL, -(1ULL<<(l->type->width*8-1)));
- hi = big(0, (1ULL<<(l->type->width*8-1))-1);
- }
-
- switch(op){
- case OLT:
- case OLO:
- case OGE:
- case OHS:
- if(cmp(x, lo) <= 0)
- goto useless;
- if(cmp(x, add(hi, 1)) >= 0)
- goto useless;
- break;
- case OLE:
- case OLS:
- case OGT:
- case OHI:
- if(cmp(x, add(lo, -1)) <= 0)
- goto useless;
- if(cmp(x, hi) >= 0)
- goto useless;
- break;
- case OEQ:
- case ONE:
- /*
- * Don't warn about comparisons if the expression
- * is as wide as the value: the compiler-supplied casts
- * will make both outcomes possible.
- */
- if(lt->width >= rt->width && debug['w'] < 2)
- return 0;
- if(cmp(x, lo) < 0 || cmp(x, hi) > 0)
- goto useless;
- break;
- }
- return 0;
-
-useless:
- if((x.a==0 && x.b<=9) || (x.a==~0LL && x.b >= -9ULL))
- snprint(xbuf, sizeof xbuf, "%lld", x.b);
- else if(x.a == 0)
- snprint(xbuf, sizeof xbuf, "%#llux", x.b);
- else
- snprint(xbuf, sizeof xbuf, "%#llx", x.b);
- if(reverse)
- snprint(cmpbuf, sizeof cmpbuf, "%s %s %T",
- xbuf, cmps[relindex(n->op)], lt);
- else
- snprint(cmpbuf, sizeof cmpbuf, "%T %s %s",
- lt, cmps[relindex(n->op)], xbuf);
- warn(n, "useless or misleading comparison: %s", cmpbuf);
- return 0;
-}
-
diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c
deleted file mode 100644
index f46fedc16..000000000
--- a/src/cmd/cc/com64.c
+++ /dev/null
@@ -1,644 +0,0 @@
-// Inferno utils/cc/com64.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-
-/*
- * this is machine depend, but it is totally
- * common on all of the 64-bit symulating machines.
- */
-
-#define FNX 100 /* botch -- redefinition */
-
-Node* nodaddv;
-Node* nodsubv;
-Node* nodmulv;
-Node* noddivv;
-Node* noddivvu;
-Node* nodmodv;
-Node* nodmodvu;
-Node* nodlshv;
-Node* nodrshav;
-Node* nodrshlv;
-Node* nodandv;
-Node* nodorv;
-Node* nodxorv;
-Node* nodnegv;
-Node* nodcomv;
-
-Node* nodtestv;
-Node* nodeqv;
-Node* nodnev;
-Node* nodlev;
-Node* nodltv;
-Node* nodgev;
-Node* nodgtv;
-Node* nodhiv;
-Node* nodhsv;
-Node* nodlov;
-Node* nodlsv;
-
-Node* nodf2v;
-Node* nodd2v;
-Node* nodp2v;
-Node* nodsi2v;
-Node* nodui2v;
-Node* nodsl2v;
-Node* nodul2v;
-Node* nodsh2v;
-Node* noduh2v;
-Node* nodsc2v;
-Node* noduc2v;
-
-Node* nodv2f;
-Node* nodv2d;
-Node* nodv2ui;
-Node* nodv2si;
-Node* nodv2ul;
-Node* nodv2sl;
-Node* nodv2uh;
-Node* nodv2sh;
-Node* nodv2uc;
-Node* nodv2sc;
-
-Node* nodvpp;
-Node* nodppv;
-Node* nodvmm;
-Node* nodmmv;
-
-Node* nodvasop;
-
-char etconv[NALLTYPES]; /* for _vasop */
-Init initetconv[] =
-{
- TCHAR, 1, 0,
- TUCHAR, 2, 0,
- TSHORT, 3, 0,
- TUSHORT, 4, 0,
- TLONG, 5, 0,
- TULONG, 6, 0,
- TVLONG, 7, 0,
- TUVLONG, 8, 0,
- TINT, 9, 0,
- TUINT, 10, 0,
- -1, 0, 0,
-};
-
-Node*
-fvn(char *name, int type)
-{
- Node *n;
-
- n = new(ONAME, Z, Z);
- n->sym = slookup(name);
- n->sym->sig = SIGINTERN;
- if(fntypes[type] == 0)
- fntypes[type] = typ(TFUNC, types[type]);
- n->type = fntypes[type];
- n->etype = type;
- n->class = CGLOBL;
- n->addable = 10;
- n->complex = 0;
- return n;
-}
-
-void
-com64init(void)
-{
- Init *p;
-
- nodaddv = fvn("_addv", TVLONG);
- nodsubv = fvn("_subv", TVLONG);
- nodmulv = fvn("_mulv", TVLONG);
- noddivv = fvn("_divv", TVLONG);
- noddivvu = fvn("_divvu", TVLONG);
- nodmodv = fvn("_modv", TVLONG);
- nodmodvu = fvn("_modvu", TVLONG);
- nodlshv = fvn("_lshv", TVLONG);
- nodrshav = fvn("_rshav", TVLONG);
- nodrshlv = fvn("_rshlv", TVLONG);
- nodandv = fvn("_andv", TVLONG);
- nodorv = fvn("_orv", TVLONG);
- nodxorv = fvn("_xorv", TVLONG);
- nodnegv = fvn("_negv", TVLONG);
- nodcomv = fvn("_comv", TVLONG);
-
- nodtestv = fvn("_testv", TLONG);
- nodeqv = fvn("_eqv", TLONG);
- nodnev = fvn("_nev", TLONG);
- nodlev = fvn("_lev", TLONG);
- nodltv = fvn("_ltv", TLONG);
- nodgev = fvn("_gev", TLONG);
- nodgtv = fvn("_gtv", TLONG);
- nodhiv = fvn("_hiv", TLONG);
- nodhsv = fvn("_hsv", TLONG);
- nodlov = fvn("_lov", TLONG);
- nodlsv = fvn("_lsv", TLONG);
-
- nodf2v = fvn("_f2v", TVLONG);
- nodd2v = fvn("_d2v", TVLONG);
- nodp2v = fvn("_p2v", TVLONG);
- nodsi2v = fvn("_si2v", TVLONG);
- nodui2v = fvn("_ui2v", TVLONG);
- nodsl2v = fvn("_sl2v", TVLONG);
- nodul2v = fvn("_ul2v", TVLONG);
- nodsh2v = fvn("_sh2v", TVLONG);
- noduh2v = fvn("_uh2v", TVLONG);
- nodsc2v = fvn("_sc2v", TVLONG);
- noduc2v = fvn("_uc2v", TVLONG);
-
- nodv2f = fvn("_v2f", TFLOAT);
- nodv2d = fvn("_v2d", TDOUBLE);
- nodv2sl = fvn("_v2sl", TLONG);
- nodv2ul = fvn("_v2ul", TULONG);
- nodv2si = fvn("_v2si", TINT);
- nodv2ui = fvn("_v2ui", TUINT);
- nodv2sh = fvn("_v2sh", TSHORT);
- nodv2uh = fvn("_v2ul", TUSHORT);
- nodv2sc = fvn("_v2sc", TCHAR);
- nodv2uc = fvn("_v2uc", TUCHAR);
-
- nodvpp = fvn("_vpp", TVLONG);
- nodppv = fvn("_ppv", TVLONG);
- nodvmm = fvn("_vmm", TVLONG);
- nodmmv = fvn("_mmv", TVLONG);
-
- nodvasop = fvn("_vasop", TVLONG);
-
- for(p = initetconv; p->code >= 0; p++)
- etconv[p->code] = p->value;
-}
-
-int
-com64(Node *n)
-{
- Node *l, *r, *a, *t;
- int lv, rv;
-
- if(n->type == 0)
- return 0;
-
- l = n->left;
- r = n->right;
-
- lv = 0;
- if(l && l->type && typev[l->type->etype])
- lv = 1;
- rv = 0;
- if(r && r->type && typev[r->type->etype])
- rv = 1;
-
- if(lv) {
- switch(n->op) {
- case OEQ:
- a = nodeqv;
- goto setbool;
- case ONE:
- a = nodnev;
- goto setbool;
- case OLE:
- a = nodlev;
- goto setbool;
- case OLT:
- a = nodltv;
- goto setbool;
- case OGE:
- a = nodgev;
- goto setbool;
- case OGT:
- a = nodgtv;
- goto setbool;
- case OHI:
- a = nodhiv;
- goto setbool;
- case OHS:
- a = nodhsv;
- goto setbool;
- case OLO:
- a = nodlov;
- goto setbool;
- case OLS:
- a = nodlsv;
- goto setbool;
-
- case OANDAND:
- case OOROR:
- if(machcap(n))
- return 1;
-
- if(rv) {
- r = new(OFUNC, nodtestv, r);
- n->right = r;
- r->complex = FNX;
- r->op = OFUNC;
- r->type = types[TLONG];
- }
-
- case OCOND:
- case ONOT:
- if(machcap(n))
- return 1;
-
- l = new(OFUNC, nodtestv, l);
- n->left = l;
- l->complex = FNX;
- l->op = OFUNC;
- l->type = types[TLONG];
- n->complex = FNX;
- return 1;
- }
- }
-
- if(rv) {
- if(machcap(n))
- return 1;
- switch(n->op) {
- case OANDAND:
- case OOROR:
- r = new(OFUNC, nodtestv, r);
- n->right = r;
- r->complex = FNX;
- r->op = OFUNC;
- r->type = types[TLONG];
- return 1;
- }
- }
-
- if(typev[n->type->etype]) {
- if(machcap(n))
- return 1;
- switch(n->op) {
- default:
- diag(n, "unknown vlong %O", n->op);
- case OFUNC:
- n->complex = FNX;
- case ORETURN:
- case OAS:
- case OIND:
- return 1;
- case OADD:
- a = nodaddv;
- goto setbop;
- case OSUB:
- a = nodsubv;
- goto setbop;
- case OMUL:
- case OLMUL:
- a = nodmulv;
- goto setbop;
- case ODIV:
- a = noddivv;
- goto setbop;
- case OLDIV:
- a = noddivvu;
- goto setbop;
- case OMOD:
- a = nodmodv;
- goto setbop;
- case OLMOD:
- a = nodmodvu;
- goto setbop;
- case OASHL:
- a = nodlshv;
- goto setbop;
- case OASHR:
- a = nodrshav;
- goto setbop;
- case OLSHR:
- a = nodrshlv;
- goto setbop;
- case OAND:
- a = nodandv;
- goto setbop;
- case OOR:
- a = nodorv;
- goto setbop;
- case OXOR:
- a = nodxorv;
- goto setbop;
- case OPOSTINC:
- a = nodvpp;
- goto setvinc;
- case OPOSTDEC:
- a = nodvmm;
- goto setvinc;
- case OPREINC:
- a = nodppv;
- goto setvinc;
- case OPREDEC:
- a = nodmmv;
- goto setvinc;
- case ONEG:
- a = nodnegv;
- goto setfnx;
- case OCOM:
- a = nodcomv;
- goto setfnx;
- case OCAST:
- switch(l->type->etype) {
- case TCHAR:
- a = nodsc2v;
- goto setfnxl;
- case TUCHAR:
- a = noduc2v;
- goto setfnxl;
- case TSHORT:
- a = nodsh2v;
- goto setfnxl;
- case TUSHORT:
- a = noduh2v;
- goto setfnxl;
- case TINT:
- a = nodsi2v;
- goto setfnx;
- case TUINT:
- a = nodui2v;
- goto setfnx;
- case TLONG:
- a = nodsl2v;
- goto setfnx;
- case TULONG:
- a = nodul2v;
- goto setfnx;
- case TFLOAT:
- a = nodf2v;
- goto setfnx;
- case TDOUBLE:
- a = nodd2v;
- goto setfnx;
- case TIND:
- a = nodp2v;
- goto setfnx;
- }
- diag(n, "unknown %T->vlong cast", l->type);
- return 1;
- case OASADD:
- a = nodaddv;
- goto setasop;
- case OASSUB:
- a = nodsubv;
- goto setasop;
- case OASMUL:
- case OASLMUL:
- a = nodmulv;
- goto setasop;
- case OASDIV:
- a = noddivv;
- goto setasop;
- case OASLDIV:
- a = noddivvu;
- goto setasop;
- case OASMOD:
- a = nodmodv;
- goto setasop;
- case OASLMOD:
- a = nodmodvu;
- goto setasop;
- case OASASHL:
- a = nodlshv;
- goto setasop;
- case OASASHR:
- a = nodrshav;
- goto setasop;
- case OASLSHR:
- a = nodrshlv;
- goto setasop;
- case OASAND:
- a = nodandv;
- goto setasop;
- case OASOR:
- a = nodorv;
- goto setasop;
- case OASXOR:
- a = nodxorv;
- goto setasop;
- }
- }
-
- if(typefd[n->type->etype] && l && l->op == OFUNC) {
- switch(n->op) {
- case OASADD:
- case OASSUB:
- case OASMUL:
- case OASLMUL:
- case OASDIV:
- case OASLDIV:
- case OASMOD:
- case OASLMOD:
- case OASASHL:
- case OASASHR:
- case OASLSHR:
- case OASAND:
- case OASOR:
- case OASXOR:
- if(l->right && typev[l->right->etype]) {
- diag(n, "sorry float <asop> vlong not implemented\n");
- }
- }
- }
-
- if(n->op == OCAST) {
- if(l->type && typev[l->type->etype]) {
- if(machcap(n))
- return 1;
- switch(n->type->etype) {
- case TDOUBLE:
- a = nodv2d;
- goto setfnx;
- case TFLOAT:
- a = nodv2f;
- goto setfnx;
- case TLONG:
- a = nodv2sl;
- goto setfnx;
- case TULONG:
- a = nodv2ul;
- goto setfnx;
- case TINT:
- a = nodv2si;
- goto setfnx;
- case TUINT:
- a = nodv2ui;
- goto setfnx;
- case TSHORT:
- a = nodv2sh;
- goto setfnx;
- case TUSHORT:
- a = nodv2uh;
- goto setfnx;
- case TCHAR:
- a = nodv2sc;
- goto setfnx;
- case TUCHAR:
- a = nodv2uc;
- goto setfnx;
- case TIND: // small pun here
- a = nodv2ul;
- goto setfnx;
- }
- diag(n, "unknown vlong->%T cast", n->type);
- return 1;
- }
- }
-
- return 0;
-
-setbop:
- n->left = a;
- n->right = new(OLIST, l, r);
- n->complex = FNX;
- n->op = OFUNC;
- return 1;
-
-setfnxl:
- l = new(OCAST, l, 0);
- l->type = types[TLONG];
- l->complex = l->left->complex;
-
-setfnx:
- n->left = a;
- n->right = l;
- n->complex = FNX;
- n->op = OFUNC;
- return 1;
-
-setvinc:
- n->left = a;
- l = new(OADDR, l, Z);
- l->type = typ(TIND, l->left->type);
- n->right = new(OLIST, l, r);
- n->complex = FNX;
- n->op = OFUNC;
- return 1;
-
-setbool:
- if(machcap(n))
- return 1;
- n->left = a;
- n->right = new(OLIST, l, r);
- n->complex = FNX;
- n->op = OFUNC;
- n->type = types[TLONG];
- return 1;
-
-setasop:
- if(l->op == OFUNC) {
- l = l->right;
- goto setasop;
- }
-
- t = new(OCONST, 0, 0);
- t->vconst = etconv[l->type->etype];
- t->type = types[TLONG];
- t->addable = 20;
- r = new(OLIST, t, r);
-
- t = new(OADDR, a, 0);
- t->type = typ(TIND, a->type);
- r = new(OLIST, t, r);
-
- t = new(OADDR, l, 0);
- t->type = typ(TIND, l->type);
- r = new(OLIST, t, r);
-
- n->left = nodvasop;
- n->right = r;
- n->complex = FNX;
- n->op = OFUNC;
-
- return 1;
-}
-
-void
-bool64(Node *n)
-{
- Node *n1;
-
- if(machcap(Z))
- return;
- if(typev[n->type->etype]) {
- n1 = new(OXXX, 0, 0);
- *n1 = *n;
-
- n->right = n1;
- n->left = nodtestv;
- n->complex = FNX;
- n->addable = 0;
- n->op = OFUNC;
- n->type = types[TLONG];
- }
-}
-
-/*
- * more machine depend stuff.
- * this is common for 8,16,32,64 bit machines.
- * this is common for ieee machines.
- */
-double
-convvtof(vlong v)
-{
- double d;
-
- d = v; /* BOTCH */
- return d;
-}
-
-vlong
-convftov(double d)
-{
- vlong v;
-
-
- v = d; /* BOTCH */
- return v;
-}
-
-double
-convftox(double d, int et)
-{
-
- if(!typefd[et])
- diag(Z, "bad type in castftox %s", tnames[et]);
- return d;
-}
-
-vlong
-convvtox(vlong c, int et)
-{
- int n;
-
- n = 8 * ewidth[et];
- c &= MASK(n);
- if(!typeu[et])
- if(c & SIGN(n))
- c |= ~MASK(n);
- return c;
-}
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
deleted file mode 100644
index 117508fd6..000000000
--- a/src/cmd/cc/dcl.c
+++ /dev/null
@@ -1,1707 +0,0 @@
-// Inferno utils/cc/dcl.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/dcl.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-#include "../ld/textflag.h"
-
-static int haspointers(Type*);
-
-Node*
-dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n)
-{
- Sym *s;
- Node *n1;
- int32 v;
-
- nearln = lineno;
- lastfield = 0;
-
-loop:
- if(n != Z)
- switch(n->op) {
- default:
- diag(n, "unknown declarator: %O", n->op);
- break;
-
- case OARRAY:
- t = typ(TARRAY, t);
- t->width = 0;
- n1 = n->right;
- n = n->left;
- if(n1 != Z) {
- complex(n1);
- v = -1;
- if(n1->op == OCONST)
- v = n1->vconst;
- if(v <= 0) {
- diag(n, "array size must be a positive constant");
- v = 1;
- }
- t->width = v * t->link->width;
- }
- goto loop;
-
- case OIND:
- t = typ(TIND, t);
- t->garb = n->garb;
- n = n->left;
- goto loop;
-
- case OFUNC:
- t = typ(TFUNC, t);
- t->down = fnproto(n);
- n = n->left;
- goto loop;
-
- case OBIT:
- n1 = n->right;
- complex(n1);
- lastfield = -1;
- if(n1->op == OCONST)
- lastfield = n1->vconst;
- if(lastfield < 0) {
- diag(n, "field width must be non-negative constant");
- lastfield = 1;
- }
- if(lastfield == 0) {
- lastbit = 0;
- firstbit = 1;
- if(n->left != Z) {
- diag(n, "zero width named field");
- lastfield = 1;
- }
- }
- if(!typei[t->etype]) {
- diag(n, "field type must be int-like");
- t = types[TINT];
- lastfield = 1;
- }
- if(lastfield > tfield->width*8) {
- diag(n, "field width larger than field unit");
- lastfield = 1;
- }
- lastbit += lastfield;
- if(lastbit > tfield->width*8) {
- lastbit = lastfield;
- firstbit = 1;
- }
- n = n->left;
- goto loop;
-
- case ONAME:
- if(f == NODECL)
- break;
- s = n->sym;
- (*f)(c, t, s);
- if(s->class == CLOCAL)
- s = mkstatic(s);
- if(dataflag) {
- s->dataflag = dataflag;
- dataflag = 0;
- } else if(s->type != T && !haspointers(s->type))
- s->dataflag = NOPTR;
- firstbit = 0;
- n->sym = s;
- n->type = s->type;
- n->xoffset = s->offset;
- n->class = s->class;
- n->etype = TVOID;
- if(n->type != T)
- n->etype = n->type->etype;
- if(debug['d'])
- dbgdecl(s);
- acidvar(s);
- godefvar(s);
- s->varlineno = lineno;
- break;
- }
- lastdcl = t;
- return n;
-}
-
-Sym*
-mkstatic(Sym *s)
-{
- Sym *s1;
-
- if(s->class != CLOCAL)
- return s;
- snprint(symb, NSYMB, "%s$%d", s->name, s->block);
- s1 = lookup();
- if(s1->class != CSTATIC) {
- s1->type = s->type;
- s1->offset = s->offset;
- s1->block = s->block;
- s1->class = CSTATIC;
- }
- return s1;
-}
-
-/*
- * make a copy of a typedef
- * the problem is to split out incomplete
- * arrays so that it is in the variable
- * rather than the typedef.
- */
-Type*
-tcopy(Type *t)
-{
- Type *tl, *tx;
- int et;
-
- if(t == T)
- return t;
- et = t->etype;
- if(typesu[et])
- return t;
- tl = tcopy(t->link);
- if(tl != t->link ||
- (et == TARRAY && t->width == 0)) {
- tx = copytyp(t);
- tx->link = tl;
- return tx;
- }
- return t;
-}
-
-Node*
-doinit(Sym *s, Type *t, int32 o, Node *a)
-{
- Node *n;
-
- if(t == T)
- return Z;
- if(s->class == CEXTERN) {
- s->class = CGLOBL;
- if(debug['d'])
- dbgdecl(s);
- }
- if(debug['i']) {
- print("t = %T; o = %d; n = %s\n", t, o, s->name);
- prtree(a, "doinit value");
- }
-
-
- n = initlist;
- if(a->op == OINIT)
- a = a->left;
- initlist = a;
-
- a = init1(s, t, o, 0);
- if(initlist != Z)
- diag(initlist, "more initializers than structure: %s",
- s->name);
- initlist = n;
-
- return a;
-}
-
-/*
- * get next major operator,
- * dont advance initlist.
- */
-Node*
-peekinit(void)
-{
- Node *a;
-
- a = initlist;
-
-loop:
- if(a == Z)
- return a;
- if(a->op == OLIST) {
- a = a->left;
- goto loop;
- }
- return a;
-}
-
-/*
- * consume and return next element on
- * initlist. expand strings.
- */
-Node*
-nextinit(void)
-{
- Node *a, *b, *n;
-
- a = initlist;
- n = Z;
-
- if(a == Z)
- return a;
- if(a->op == OLIST) {
- n = a->right;
- a = a->left;
- }
- if(a->op == OUSED) {
- a = a->left;
- b = new(OCONST, Z, Z);
- b->type = a->type->link;
- if(a->op == OSTRING) {
- b->vconst = convvtox(*a->cstring, TCHAR);
- a->cstring++;
- }
- if(a->op == OLSTRING) {
- b->vconst = convvtox(*a->rstring, TRUNE);
- a->rstring++;
- }
- a->type->width -= b->type->width;
- if(a->type->width <= 0)
- initlist = n;
- return b;
- }
- initlist = n;
- return a;
-}
-
-int
-isstruct(Node *a, Type *t)
-{
- Node *n;
-
- switch(a->op) {
- case ODOTDOT:
- n = a->left;
- if(n && n->type && sametype(n->type, t))
- return 1;
- case OSTRING:
- case OLSTRING:
- case OCONST:
- case OINIT:
- case OELEM:
- return 0;
- }
-
- n = new(ODOTDOT, Z, Z);
- *n = *a;
-
- /*
- * ODOTDOT is a flag for tcom
- * a second tcom will not be performed
- */
- a->op = ODOTDOT;
- a->left = n;
- a->right = Z;
-
- if(tcom(n))
- return 0;
-
- if(sametype(n->type, t))
- return 1;
- return 0;
-}
-
-Node*
-init1(Sym *s, Type *t, int32 o, int exflag)
-{
- Node *a, *l, *r, nod;
- Type *t1;
- int32 e, w, so, mw;
-
- a = peekinit();
- if(a == Z)
- return Z;
-
- if(debug['i']) {
- print("t = %T; o = %d; n = %s\n", t, o, s->name);
- prtree(a, "init1 value");
- }
-
- if(exflag && a->op == OINIT)
- return doinit(s, t, o, nextinit());
-
- switch(t->etype) {
- default:
- diag(Z, "unknown type in initialization: %T to: %s", t, s->name);
- return Z;
-
- case TCHAR:
- case TUCHAR:
- case TINT:
- case TUINT:
- case TSHORT:
- case TUSHORT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TFLOAT:
- case TDOUBLE:
- case TIND:
- single:
- if(a->op == OARRAY || a->op == OELEM)
- return Z;
-
- a = nextinit();
- if(a == Z)
- return Z;
-
- if(t->nbits)
- diag(Z, "cannot initialize bitfields");
- if(s->class == CAUTO) {
- l = new(ONAME, Z, Z);
- l->sym = s;
- l->type = t;
- l->etype = TVOID;
- if(s->type)
- l->etype = s->type->etype;
- l->xoffset = s->offset + o;
- l->class = s->class;
-
- l = new(OASI, l, a);
- return l;
- }
-
- complex(a);
- if(a->type == T)
- return Z;
-
- if(a->op == OCONST) {
- if(vconst(a) && t->etype == TIND && a->type && a->type->etype != TIND){
- diag(a, "initialize pointer to an integer: %s", s->name);
- return Z;
- }
- if(!sametype(a->type, t)) {
- /* hoop jumping to save malloc */
- if(nodcast == Z)
- nodcast = new(OCAST, Z, Z);
- nod = *nodcast;
- nod.left = a;
- nod.type = t;
- nod.lineno = a->lineno;
- complex(&nod);
- if(nod.type)
- *a = nod;
- }
- if(a->op != OCONST) {
- diag(a, "initializer is not a constant: %s",
- s->name);
- return Z;
- }
- if(vconst(a) == 0)
- return Z;
- goto gext;
- }
- if(t->etype == TIND) {
- while(a->op == OCAST) {
- warn(a, "CAST in initialization ignored");
- a = a->left;
- }
- if(!sametype(t, a->type)) {
- diag(a, "initialization of incompatible pointers: %s\n%T and %T",
- s->name, t, a->type);
- }
- if(a->op == OADDR)
- a = a->left;
- goto gext;
- }
-
- while(a->op == OCAST)
- a = a->left;
- if(a->op == OADDR) {
- warn(a, "initialize pointer to an integer: %s", s->name);
- a = a->left;
- goto gext;
- }
- diag(a, "initializer is not a constant: %s", s->name);
- return Z;
-
- gext:
- gextern(s, a, o, t->width);
-
- return Z;
-
- case TARRAY:
- w = t->link->width;
- if(a->op == OSTRING || a->op == OLSTRING)
- if(typei[t->link->etype]) {
- /*
- * get rid of null if sizes match exactly
- */
- a = nextinit();
- mw = t->width/w;
- so = a->type->width/a->type->link->width;
- if(mw && so > mw) {
- if(so != mw+1)
- diag(a, "string initialization larger than array");
- a->type->width -= a->type->link->width;
- }
-
- /*
- * arrange strings to be expanded
- * inside OINIT braces.
- */
- a = new(OUSED, a, Z);
- return doinit(s, t, o, a);
- }
-
- mw = -w;
- l = Z;
- for(e=0;;) {
- /*
- * peek ahead for element initializer
- */
- a = peekinit();
- if(a == Z)
- break;
- if(a->op == OELEM && t->link->etype != TSTRUCT)
- break;
- if(a->op == OARRAY) {
- if(e && exflag)
- break;
- a = nextinit();
- r = a->left;
- complex(r);
- if(r->op != OCONST) {
- diag(r, "initializer subscript must be constant");
- return Z;
- }
- e = r->vconst;
- if(t->width != 0)
- if(e < 0 || e*w >= t->width) {
- diag(a, "initialization index out of range: %d", e);
- continue;
- }
- }
-
- so = e*w;
- if(so > mw)
- mw = so;
- if(t->width != 0)
- if(mw >= t->width)
- break;
- r = init1(s, t->link, o+so, 1);
- l = newlist(l, r);
- e++;
- }
- if(t->width == 0)
- t->width = mw+w;
- return l;
-
- case TUNION:
- case TSTRUCT:
- /*
- * peek ahead to find type of rhs.
- * if its a structure, then treat
- * this element as a variable
- * rather than an aggregate.
- */
- if(isstruct(a, t))
- goto single;
-
- if(t->width <= 0) {
- diag(Z, "incomplete structure: %s", s->name);
- return Z;
- }
- l = Z;
-
- again:
- for(t1 = t->link; t1 != T; t1 = t1->down) {
- if(a->op == OARRAY && t1->etype != TARRAY)
- break;
- if(a->op == OELEM) {
- if(t1->sym != a->sym)
- continue;
- nextinit();
- }
- r = init1(s, t1, o+t1->offset, 1);
- l = newlist(l, r);
- a = peekinit();
- if(a == Z)
- break;
- if(a->op == OELEM)
- goto again;
- }
- if(a && a->op == OELEM)
- diag(a, "structure element not found %F", a);
- return l;
- }
-}
-
-Node*
-newlist(Node *l, Node *r)
-{
- if(r == Z)
- return l;
- if(l == Z)
- return r;
- return new(OLIST, l, r);
-}
-
-static int
-haspointers(Type *t)
-{
- Type *fld;
-
- switch(t->etype) {
- case TSTRUCT:
- for(fld = t->link; fld != T; fld = fld->down) {
- if(haspointers(fld))
- return 1;
- }
- return 0;
- case TARRAY:
- return haspointers(t->link);
- case TIND:
- return t->link->etype != TFUNC;
- default:
- return 0;
- }
-}
-
-void
-sualign(Type *t)
-{
- Type *l;
- int32 o, w, maxal;
-
- o = 0;
- maxal = 0;
- switch(t->etype) {
-
- case TSTRUCT:
- t->offset = 0;
- w = 0;
- for(l = t->link; l != T; l = l->down) {
- if(l->nbits) {
- if(l->shift <= 0) {
- l->shift = -l->shift;
- w = xround(w, tfield->width);
- o = w;
- w += tfield->width;
- }
- l->offset = o;
- } else {
- if(l->width <= 0)
- if(l->down != T)
- if(l->sym)
- diag(Z, "incomplete structure element: %s",
- l->sym->name);
- else
- diag(Z, "incomplete structure element");
- w = align(w, l, Ael1, &maxal);
- l->offset = w;
- w = align(w, l, Ael2, &maxal);
- }
- }
- w = align(w, t, Asu2, &maxal);
- t->width = w;
- t->align = maxal;
- acidtype(t);
- godeftype(t);
- return;
-
- case TUNION:
- t->offset = 0;
- w = 0;
- for(l = t->link; l != T; l = l->down) {
- if(l->width <= 0)
- if(l->sym)
- diag(Z, "incomplete union element: %s",
- l->sym->name);
- else
- diag(Z, "incomplete union element");
- l->offset = 0;
- l->shift = 0;
- if((debug['q'] || debug['Q']) && haspointers(l))
- diag(Z, "precise garbage collector cannot handle unions with pointers");
-
- o = align(align(0, l, Ael1, &maxal), l, Ael2, &maxal);
- if(o > w)
- w = o;
- }
- w = align(w, t, Asu2, &maxal);
- t->width = w;
- t->align = maxal;
- acidtype(t);
- godeftype(t);
- return;
-
- default:
- diag(Z, "unknown type in sualign: %T", t);
- break;
- }
-}
-
-int32
-xround(int32 v, int w)
-{
- int r;
-
- if(w <= 0 || w > 8) {
- diag(Z, "rounding by %d", w);
- w = 1;
- }
- r = v%w;
- if(r)
- v += w-r;
- return v;
-}
-
-Type*
-ofnproto(Node *n)
-{
- Type *tl, *tr, *t;
-
- if(n == Z)
- return T;
- switch(n->op) {
- case OLIST:
- tl = ofnproto(n->left);
- tr = ofnproto(n->right);
- if(tl == T)
- return tr;
- tl->down = tr;
- return tl;
-
- case ONAME:
- t = copytyp(n->sym->type);
- t->down = T;
- return t;
- }
- return T;
-}
-
-#define ANSIPROTO 1
-#define OLDPROTO 2
-
-void
-argmark(Node *n, int pass)
-{
- Type *t;
-
- if(hasdotdotdot(thisfn->link))
- autoffset = align(0, thisfn->link, Aarg0, nil);
- stkoff = 0;
- for(; n->left != Z; n = n->left) {
- if(n->op != OFUNC || n->left->op != ONAME)
- continue;
- walkparam(n->right, pass);
- if(pass != 0 && anyproto(n->right) == OLDPROTO) {
- t = typ(TFUNC, n->left->sym->type->link);
- t->down = typ(TOLD, T);
- t->down->down = ofnproto(n->right);
- tmerge(t, n->left->sym);
- n->left->sym->type = t;
- }
- break;
- }
- autoffset = 0;
- stkoff = 0;
-}
-
-void
-walkparam(Node *n, int pass)
-{
- Sym *s;
- Node *n1;
-
- if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID])
- return;
-
-loop:
- if(n == Z)
- return;
- switch(n->op) {
- default:
- diag(n, "argument not a name/prototype: %O", n->op);
- break;
-
- case OLIST:
- walkparam(n->left, pass);
- n = n->right;
- goto loop;
-
- case OPROTO:
- for(n1 = n; n1 != Z; n1=n1->left)
- if(n1->op == ONAME) {
- if(pass == 0) {
- s = n1->sym;
- push1(s);
- s->offset = -1;
- break;
- }
- dodecl(pdecl, CPARAM, n->type, n->left);
- break;
- }
- if(n1)
- break;
- if(pass == 0) {
- /*
- * extension:
- * allow no name in argument declaration
- diag(Z, "no name in argument declaration");
- */
- break;
- }
- dodecl(NODECL, CPARAM, n->type, n->left);
- pdecl(CPARAM, lastdcl, S);
- break;
-
- case ODOTDOT:
- break;
-
- case ONAME:
- s = n->sym;
- if(pass == 0) {
- push1(s);
- s->offset = -1;
- break;
- }
- if(s->offset != -1) {
- if(autoffset == 0) {
- firstarg = s;
- firstargtype = s->type;
- }
- autoffset = align(autoffset, s->type, Aarg1, nil);
- s->offset = autoffset;
- autoffset = align(autoffset, s->type, Aarg2, nil);
- } else
- dodecl(pdecl, CXXX, types[TINT], n);
- break;
- }
-}
-
-void
-markdcl(void)
-{
- Decl *d;
-
- blockno++;
- d = push();
- d->val = DMARK;
- d->offset = autoffset;
- d->block = autobn;
- autobn = blockno;
-}
-
-Node*
-revertdcl(void)
-{
- Decl *d;
- Sym *s;
- Node *n, *n1;
-
- n = Z;
- for(;;) {
- d = dclstack;
- if(d == D) {
- diag(Z, "pop off dcl stack");
- break;
- }
- dclstack = d->link;
- s = d->sym;
- switch(d->val) {
- case DMARK:
- autoffset = d->offset;
- autobn = d->block;
- return n;
-
- case DAUTO:
- if(debug['d'])
- print("revert1 \"%s\"\n", s->name);
- if(s->aused == 0) {
- nearln = s->varlineno;
- if(s->class == CAUTO)
- warn(Z, "auto declared and not used: %s", s->name);
- if(s->class == CPARAM)
- warn(Z, "param declared and not used: %s", s->name);
- }
- if(s->type && (s->type->garb & GVOLATILE)) {
- n1 = new(ONAME, Z, Z);
- n1->sym = s;
- n1->type = s->type;
- n1->etype = TVOID;
- if(n1->type != T)
- n1->etype = n1->type->etype;
- n1->xoffset = s->offset;
- n1->class = s->class;
-
- n1 = new(OADDR, n1, Z);
- n1 = new(OUSED, n1, Z);
- if(n == Z)
- n = n1;
- else
- n = new(OLIST, n1, n);
- }
- s->type = d->type;
- s->class = d->class;
- s->offset = d->offset;
- s->block = d->block;
- s->varlineno = d->varlineno;
- s->aused = d->aused;
- break;
-
- case DSUE:
- if(debug['d'])
- print("revert2 \"%s\"\n", s->name);
- s->suetag = d->type;
- s->sueblock = d->block;
- break;
-
- case DLABEL:
- if(debug['d'])
- print("revert3 \"%s\"\n", s->name);
- if(s->label && s->label->addable == 0)
- warn(s->label, "label declared and not used \"%s\"", s->name);
- s->label = Z;
- break;
- }
- }
- return n;
-}
-
-Type*
-fnproto(Node *n)
-{
- int r;
-
- r = anyproto(n->right);
- if(r == 0 || (r & OLDPROTO)) {
- if(r & ANSIPROTO)
- diag(n, "mixed ansi/old function declaration: %F", n->left);
- return T;
- }
- return fnproto1(n->right);
-}
-
-int
-anyproto(Node *n)
-{
- int r;
-
- r = 0;
-
-loop:
- if(n == Z)
- return r;
- switch(n->op) {
- case OLIST:
- r |= anyproto(n->left);
- n = n->right;
- goto loop;
-
- case ODOTDOT:
- case OPROTO:
- return r | ANSIPROTO;
- }
- return r | OLDPROTO;
-}
-
-Type*
-fnproto1(Node *n)
-{
- Type *t;
-
- if(n == Z)
- return T;
- switch(n->op) {
- case OLIST:
- t = fnproto1(n->left);
- if(t != T)
- t->down = fnproto1(n->right);
- return t;
-
- case OPROTO:
- lastdcl = T;
- dodecl(NODECL, CXXX, n->type, n->left);
- t = typ(TXXX, T);
- if(lastdcl != T)
- *t = *paramconv(lastdcl, 1);
- return t;
-
- case ONAME:
- diag(n, "incomplete argument prototype");
- return typ(TINT, T);
-
- case ODOTDOT:
- return typ(TDOT, T);
- }
- diag(n, "unknown op in fnproto");
- return T;
-}
-
-void
-dbgdecl(Sym *s)
-{
- print("decl \"%s\": C=%s [B=%d:O=%d] T=%T\n",
- s->name, cnames[s->class], s->block, s->offset, s->type);
-}
-
-Decl*
-push(void)
-{
- Decl *d;
-
- d = alloc(sizeof(*d));
- d->link = dclstack;
- dclstack = d;
- return d;
-}
-
-Decl*
-push1(Sym *s)
-{
- Decl *d;
-
- d = push();
- d->sym = s;
- d->val = DAUTO;
- d->type = s->type;
- d->class = s->class;
- d->offset = s->offset;
- d->block = s->block;
- d->varlineno = s->varlineno;
- d->aused = s->aused;
- return d;
-}
-
-int
-sametype(Type *t1, Type *t2)
-{
-
- if(t1 == t2)
- return 1;
- return rsametype(t1, t2, 5, 1);
-}
-
-int
-rsametype(Type *t1, Type *t2, int n, int f)
-{
- int et;
-
- n--;
- for(;;) {
- if(t1 == t2)
- return 1;
- if(t1 == T || t2 == T)
- return 0;
- if(n <= 0)
- return 1;
- et = t1->etype;
- if(et != t2->etype)
- return 0;
- if(et == TFUNC) {
- if(!rsametype(t1->link, t2->link, n, 0))
- return 0;
- t1 = t1->down;
- t2 = t2->down;
- while(t1 != T && t2 != T) {
- if(t1->etype == TOLD) {
- t1 = t1->down;
- continue;
- }
- if(t2->etype == TOLD) {
- t2 = t2->down;
- continue;
- }
- while(t1 != T || t2 != T) {
- if(!rsametype(t1, t2, n, 0))
- return 0;
- t1 = t1->down;
- t2 = t2->down;
- }
- break;
- }
- return 1;
- }
- if(et == TARRAY)
- if(t1->width != t2->width && t1->width != 0 && t2->width != 0)
- return 0;
- if(typesu[et]) {
- if(t1->link == T)
- snap(t1);
- if(t2->link == T)
- snap(t2);
- t1 = t1->link;
- t2 = t2->link;
- for(;;) {
- if(t1 == t2)
- return 1;
- if(!rsametype(t1, t2, n, 0))
- return 0;
- t1 = t1->down;
- t2 = t2->down;
- }
- }
- t1 = t1->link;
- t2 = t2->link;
- if((f || !debug['V']) && et == TIND) {
- if(t1 != T && t1->etype == TVOID)
- return 1;
- if(t2 != T && t2->etype == TVOID)
- return 1;
- }
- }
-}
-
-typedef struct Typetab Typetab;
-
-struct Typetab{
- int n;
- Type **a;
-};
-
-static int
-sigind(Type *t, Typetab *tt)
-{
- int n;
- Type **a, **na, **p, **e;
-
- n = tt->n;
- a = tt->a;
- e = a+n;
- /* linear search seems ok */
- for(p = a ; p < e; p++)
- if(sametype(*p, t))
- return p-a;
- if((n&15) == 0){
- na = malloc((n+16)*sizeof(Type*));
- if(na == nil) {
- print("%s: out of memory", argv0);
- errorexit();
- }
- memmove(na, a, n*sizeof(Type*));
- free(a);
- a = tt->a = na;
- }
- a[tt->n++] = t;
- return -1;
-}
-
-static uint32
-signat(Type *t, Typetab *tt)
-{
- int i;
- Type *t1;
- int32 s;
-
- s = 0;
- for(; t; t=t->link) {
- s = s*thash1 + thash[t->etype];
- if(t->garb&GINCOMPLETE)
- return s;
- switch(t->etype) {
- default:
- return s;
- case TARRAY:
- s = s*thash2 + 0; /* was t->width */
- break;
- case TFUNC:
- for(t1=t->down; t1; t1=t1->down)
- s = s*thash3 + signat(t1, tt);
- break;
- case TSTRUCT:
- case TUNION:
- if((i = sigind(t, tt)) >= 0){
- s = s*thash2 + i;
- return s;
- }
- for(t1=t->link; t1; t1=t1->down)
- s = s*thash3 + signat(t1, tt);
- return s;
- case TIND:
- break;
- }
- }
- return s;
-}
-
-uint32
-signature(Type *t)
-{
- uint32 s;
- Typetab tt;
-
- tt.n = 0;
- tt.a = nil;
- s = signat(t, &tt);
- free(tt.a);
- return s;
-}
-
-uint32
-sign(Sym *s)
-{
- uint32 v;
- Type *t;
-
- if(s->sig == SIGINTERN)
- return SIGNINTERN;
- if((t = s->type) == T)
- return 0;
- v = signature(t);
- if(v == 0)
- v = SIGNINTERN;
- return v;
-}
-
-void
-snap(Type *t)
-{
- if(typesu[t->etype])
- if(t->link == T && t->tag && t->tag->suetag) {
- t->link = t->tag->suetag->link;
- t->width = t->tag->suetag->width;
- }
-}
-
-Type*
-dotag(Sym *s, int et, int bn)
-{
- Decl *d;
-
- if(bn != 0 && bn != s->sueblock) {
- d = push();
- d->sym = s;
- d->val = DSUE;
- d->type = s->suetag;
- d->block = s->sueblock;
- s->suetag = T;
- }
- if(s->suetag == T) {
- s->suetag = typ(et, T);
- s->sueblock = autobn;
- }
- if(s->suetag->etype != et)
- diag(Z, "tag used for more than one type: %s",
- s->name);
- if(s->suetag->tag == S)
- s->suetag->tag = s;
- return s->suetag;
-}
-
-Node*
-dcllabel(Sym *s, int f)
-{
- Decl *d, d1;
- Node *n;
-
- n = s->label;
- if(n != Z) {
- if(f) {
- if(n->complex)
- diag(Z, "label reused: %s", s->name);
- n->complex = 1; // declared
- } else
- n->addable = 1; // used
- return n;
- }
-
- d = push();
- d->sym = s;
- d->val = DLABEL;
- dclstack = d->link;
-
- d1 = *firstdcl;
- *firstdcl = *d;
- *d = d1;
-
- firstdcl->link = d;
- firstdcl = d;
-
- n = new(OXXX, Z, Z);
- n->sym = s;
- n->complex = f;
- n->addable = !f;
- s->label = n;
-
- if(debug['d'])
- dbgdecl(s);
- return n;
-}
-
-Type*
-paramconv(Type *t, int f)
-{
-
- switch(t->etype) {
- case TUNION:
- case TSTRUCT:
- if(t->width <= 0)
- diag(Z, "incomplete structure: %s", t->tag->name);
- break;
-
- case TARRAY:
- t = typ(TIND, t->link);
- t->width = types[TIND]->width;
- break;
-
- case TFUNC:
- t = typ(TIND, t);
- t->width = types[TIND]->width;
- break;
-
- case TFLOAT:
- if(!f)
- t = types[TDOUBLE];
- break;
-
- case TCHAR:
- case TSHORT:
- if(!f)
- t = types[TINT];
- break;
-
- case TUCHAR:
- case TUSHORT:
- if(!f)
- t = types[TUINT];
- break;
- }
- return t;
-}
-
-void
-adecl(int c, Type *t, Sym *s)
-{
-
- if(c == CSTATIC)
- c = CLOCAL;
- if(t->etype == TFUNC) {
- if(c == CXXX)
- c = CEXTERN;
- if(c == CLOCAL)
- c = CSTATIC;
- if(c == CAUTO || c == CEXREG)
- diag(Z, "function cannot be %s %s", cnames[c], s->name);
- }
- if(c == CXXX)
- c = CAUTO;
- if(s) {
- if(s->class == CSTATIC)
- if(c == CEXTERN || c == CGLOBL) {
- warn(Z, "just say static: %s", s->name);
- c = CSTATIC;
- }
- if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL)
- if(s->block == autobn)
- diag(Z, "auto redeclaration of: %s", s->name);
- if(c != CPARAM)
- push1(s);
- s->block = autobn;
- s->offset = 0;
- s->type = t;
- s->class = c;
- s->aused = 0;
- }
- switch(c) {
- case CAUTO:
- autoffset = align(autoffset, t, Aaut3, nil);
- stkoff = maxround(stkoff, autoffset);
- s->offset = -autoffset;
- break;
-
- case CPARAM:
- if(autoffset == 0) {
- firstarg = s;
- firstargtype = t;
- }
- autoffset = align(autoffset, t, Aarg1, nil);
- if(s)
- s->offset = autoffset;
- autoffset = align(autoffset, t, Aarg2, nil);
- break;
- }
-}
-
-void
-pdecl(int c, Type *t, Sym *s)
-{
- if(s && s->offset != -1) {
- diag(Z, "not a parameter: %s", s->name);
- return;
- }
- t = paramconv(t, c==CPARAM);
- if(c == CXXX)
- c = CPARAM;
- if(c != CPARAM) {
- diag(Z, "parameter cannot have class: %s", s->name);
- c = CPARAM;
- }
- adecl(c, t, s);
-}
-
-void
-xdecl(int c, Type *t, Sym *s)
-{
- int32 o;
-
- o = 0;
- switch(c) {
- case CEXREG:
- o = exreg(t);
- if(o == 0)
- c = CEXTERN;
- if(s->class == CGLOBL)
- c = CGLOBL;
- break;
-
- case CEXTERN:
- if(s->class == CGLOBL)
- c = CGLOBL;
- break;
-
- case CXXX:
- c = CGLOBL;
- if(s->class == CEXTERN)
- s->class = CGLOBL;
- break;
-
- case CAUTO:
- diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
- c = CEXTERN;
- break;
-
- case CTYPESTR:
- if(!typesuv[t->etype]) {
- diag(Z, "typestr must be struct/union: %s", s->name);
- break;
- }
- dclfunct(t, s);
- break;
- }
-
- if(s->class == CSTATIC)
- if(c == CEXTERN || c == CGLOBL) {
- warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
- c = CSTATIC;
- }
- if(s->type != T)
- if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) {
- diag(Z, "external redeclaration of: %s", s->name);
- Bprint(&diagbuf, " %s %T %L\n", cnames[c], t, nearln);
- Bprint(&diagbuf, " %s %T %L\n", cnames[s->class], s->type, s->varlineno);
- }
- tmerge(t, s);
- s->type = t;
- if(c == CTYPEDEF && (typechlv[t->etype] || typefd[t->etype])) {
- s->type = copytyp(t);
- s->type->tag = s;
- }
- s->class = c;
- s->block = 0;
- s->offset = o;
-}
-
-void
-tmerge(Type *t1, Sym *s)
-{
- Type *ta, *tb, *t2;
-
- t2 = s->type;
- for(;;) {
- if(t1 == T || t2 == T || t1 == t2)
- break;
- if(t1->etype != t2->etype)
- break;
- switch(t1->etype) {
- case TFUNC:
- ta = t1->down;
- tb = t2->down;
- if(ta == T) {
- t1->down = tb;
- break;
- }
- if(tb == T)
- break;
- while(ta != T && tb != T) {
- if(ta == tb)
- break;
- /* ignore old-style flag */
- if(ta->etype == TOLD) {
- ta = ta->down;
- continue;
- }
- if(tb->etype == TOLD) {
- tb = tb->down;
- continue;
- }
- /* checking terminated by ... */
- if(ta->etype == TDOT && tb->etype == TDOT) {
- ta = T;
- tb = T;
- break;
- }
- if(!sametype(ta, tb))
- break;
- ta = ta->down;
- tb = tb->down;
- }
- if(ta != tb)
- diag(Z, "function inconsistently declared: %s", s->name);
-
- /* take new-style over old-style */
- ta = t1->down;
- tb = t2->down;
- if(ta != T && ta->etype == TOLD)
- if(tb != T && tb->etype != TOLD)
- t1->down = tb;
- break;
-
- case TARRAY:
- /* should we check array size change? */
- if(t2->width > t1->width)
- t1->width = t2->width;
- break;
-
- case TUNION:
- case TSTRUCT:
- return;
- }
- t1 = t1->link;
- t2 = t2->link;
- }
-}
-
-void
-edecl(int c, Type *t, Sym *s)
-{
- Type *t1;
-
- if(s == S)
- diag(Z, "unnamed structure elements not supported");
- else
- if(c != CXXX)
- diag(Z, "structure element cannot have class: %s", s->name);
- t1 = t;
- t = copytyp(t1);
- t->sym = s;
- t->down = T;
- if(lastfield) {
- t->shift = lastbit - lastfield;
- t->nbits = lastfield;
- if(firstbit)
- t->shift = -t->shift;
- if(typeu[t->etype])
- t->etype = tufield->etype;
- else
- t->etype = tfield->etype;
- }
- if(strf == T)
- strf = t;
- else
- strl->down = t;
- strl = t;
-}
-
-/*
- * this routine is very suspect.
- * ansi requires the enum type to
- * be represented as an 'int'
- * this means that 0x81234567
- * would be illegal. this routine
- * makes signed and unsigned go
- * to unsigned.
- */
-Type*
-maxtype(Type *t1, Type *t2)
-{
-
- if(t1 == T)
- return t2;
- if(t2 == T)
- return t1;
- if(t1->etype > t2->etype)
- return t1;
- return t2;
-}
-
-void
-doenum(Sym *s, Node *n)
-{
-
- if(n) {
- complex(n);
- if(n->op != OCONST) {
- diag(n, "enum not a constant: %s", s->name);
- return;
- }
- en.cenum = n->type;
- en.tenum = maxtype(en.cenum, en.tenum);
-
- if(!typefd[en.cenum->etype])
- en.lastenum = n->vconst;
- else
- en.floatenum = n->fconst;
- }
- if(dclstack)
- push1(s);
- xdecl(CXXX, types[TENUM], s);
-
- if(en.cenum == T) {
- en.tenum = types[TINT];
- en.cenum = types[TINT];
- en.lastenum = 0;
- }
- s->tenum = en.cenum;
-
- if(!typefd[s->tenum->etype]) {
- s->vconst = convvtox(en.lastenum, s->tenum->etype);
- en.lastenum++;
- } else {
- s->fconst = en.floatenum;
- en.floatenum++;
- }
-
- if(debug['d'])
- dbgdecl(s);
- acidvar(s);
- godefvar(s);
-}
-
-void
-symadjust(Sym *s, Node *n, int32 del)
-{
-
- switch(n->op) {
- default:
- if(n->left)
- symadjust(s, n->left, del);
- if(n->right)
- symadjust(s, n->right, del);
- return;
-
- case ONAME:
- if(n->sym == s)
- n->xoffset -= del;
- return;
-
- case OCONST:
- case OSTRING:
- case OLSTRING:
- case OINDREG:
- case OREGISTER:
- return;
- }
-}
-
-Node*
-contig(Sym *s, Node *n, int32 v)
-{
- Node *p, *r, *q, *m;
- int32 w;
- Type *zt;
-
- if(debug['i']) {
- print("contig v = %d; s = %s\n", v, s->name);
- prtree(n, "doinit value");
- }
-
- if(n == Z)
- goto no;
- w = s->type->width;
-
- /*
- * nightmare: an automatic array whose size
- * increases when it is initialized
- */
- if(v != w) {
- if(v != 0)
- diag(n, "automatic adjustable array: %s", s->name);
- v = s->offset;
- autoffset = align(autoffset, s->type, Aaut3, nil);
- s->offset = -autoffset;
- stkoff = maxround(stkoff, autoffset);
- symadjust(s, n, v - s->offset);
- }
- if(w <= ewidth[TIND])
- goto no;
- if(n->op == OAS)
- diag(Z, "oops in contig");
-/*ZZZ this appears incorrect
-need to check if the list completely covers the data.
-if not, bail
- */
- if(n->op == OLIST)
- goto no;
- if(n->op == OASI)
- if(n->left->type)
- if(n->left->type->width == w)
- goto no;
- while(w & (ewidth[TIND]-1))
- w++;
-/*
- * insert the following code, where long becomes vlong if pointers are fat
- *
- *(long**)&X = (long*)((char*)X + sizeof(X));
- do {
- *(long**)&X -= 1;
- **(long**)&X = 0;
- } while(*(long**)&X);
- */
-
- for(q=n; q->op != ONAME; q=q->left)
- ;
-
- zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG];
-
- p = new(ONAME, Z, Z);
- *p = *q;
- p->type = typ(TIND, zt);
- p->xoffset = s->offset;
-
- r = new(ONAME, Z, Z);
- *r = *p;
- r = new(OPOSTDEC, r, Z);
-
- q = new(ONAME, Z, Z);
- *q = *p;
- q = new(OIND, q, Z);
-
- m = new(OCONST, Z, Z);
- m->vconst = 0;
- m->type = zt;
-
- q = new(OAS, q, m);
-
- r = new(OLIST, r, q);
-
- q = new(ONAME, Z, Z);
- *q = *p;
- r = new(ODWHILE, q, r);
-
- q = new(ONAME, Z, Z);
- *q = *p;
- q->type = q->type->link;
- q->xoffset += w;
- q = new(OADDR, q, 0);
-
- q = new(OASI, p, q);
- r = new(OLIST, q, r);
-
- n = new(OLIST, r, n);
-
-no:
- return n;
-}
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
deleted file mode 100644
index 606bf40dd..000000000
--- a/src/cmd/cc/dpchk.c
+++ /dev/null
@@ -1,793 +0,0 @@
-// Inferno utils/cc/dpchk.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-#include "y.tab.h"
-
-enum
-{
- Fnone = 0,
- Fl,
- Fvl,
- Fignor,
- Fstar,
- Fadj,
-
- Fverb = 10,
-};
-
-typedef struct Tprot Tprot;
-struct Tprot
-{
- Type* type;
- Bits flag;
- Tprot* link;
-};
-
-typedef struct Tname Tname;
-struct Tname
-{
- char* name;
- int param;
- int count;
- Tname* link;
- Tprot* prot;
-};
-
-static Type* indchar;
-static uchar flagbits[512];
-static char* lastfmt;
-static int lastadj;
-static int lastverb;
-static int nstar;
-static Tprot* tprot;
-static Tname* tname;
-
-void
-argflag(int c, int v)
-{
-
- switch(v) {
- case Fignor:
- case Fstar:
- case Fl:
- case Fvl:
- flagbits[c] = v;
- break;
- case Fverb:
- flagbits[c] = lastverb;
-/*print("flag-v %c %d\n", c, lastadj);*/
- lastverb++;
- break;
- case Fadj:
- flagbits[c] = lastadj;
-/*print("flag-l %c %d\n", c, lastadj);*/
- lastadj++;
- break;
- }
-}
-
-Bits
-getflag(char *s)
-{
- Bits flag;
- int f;
- Fmt fmt;
- Rune c;
-
- flag = zbits;
- nstar = 0;
- fmtstrinit(&fmt);
- for(;;) {
- s += chartorune(&c, s);
- if(c == 0 || c >= nelem(flagbits))
- break;
- fmtrune(&fmt, c);
- f = flagbits[c];
- switch(f) {
- case Fnone:
- argflag(c, Fverb);
- f = flagbits[c];
- break;
- case Fstar:
- nstar++;
- case Fignor:
- continue;
- case Fl:
- if(bset(flag, Fl))
- flag = bor(flag, blsh(Fvl));
- }
- flag = bor(flag, blsh(f));
- if(f >= Fverb)
- break;
- }
- free(lastfmt);
- lastfmt = fmtstrflush(&fmt);
- return flag;
-}
-
-static void
-newprot(Sym *m, Type *t, char *s, Tprot **prot)
-{
- Bits flag;
- Tprot *l;
-
- if(t == T) {
- warn(Z, "%s: newprot: type not defined", m->name);
- return;
- }
- flag = getflag(s);
- for(l=*prot; l; l=l->link)
- if(beq(flag, l->flag) && sametype(t, l->type))
- return;
- l = alloc(sizeof(*l));
- l->type = t;
- l->flag = flag;
- l->link = *prot;
- *prot = l;
-}
-
-static Tname*
-newname(char *s, int p, int count)
-{
- Tname *l;
-
- for(l=tname; l; l=l->link)
- if(strcmp(l->name, s) == 0) {
- if(p >= 0 && l->param != p)
- yyerror("vargck %s already defined\n", s);
- return l;
- }
- if(p < 0)
- return nil;
-
- l = alloc(sizeof(*l));
- l->name = s;
- l->param = p;
- l->link = tname;
- l->count = count;
- tname = l;
- return l;
-}
-
-void
-arginit(void)
-{
- int i;
-
-/* debug['F'] = 1;*/
-/* debug['w'] = 1;*/
-
- lastadj = Fadj;
- lastverb = Fverb;
- indchar = typ(TIND, types[TCHAR]);
-
- memset(flagbits, Fnone, sizeof(flagbits));
-
- for(i='0'; i<='9'; i++)
- argflag(i, Fignor);
- argflag('.', Fignor);
- argflag('#', Fignor);
- argflag('u', Fignor);
- argflag('h', Fignor);
- argflag('+', Fignor);
- argflag('-', Fignor);
-
- argflag('*', Fstar);
- argflag('l', Fl);
-
- argflag('o', Fverb);
- flagbits['x'] = flagbits['o'];
- flagbits['X'] = flagbits['o'];
-}
-
-static char*
-getquoted(void)
-{
- int c;
- Rune r;
- Fmt fmt;
-
- c = getnsc();
- if(c != '"')
- return nil;
- fmtstrinit(&fmt);
- for(;;) {
- r = getr();
- if(r == '\n') {
- free(fmtstrflush(&fmt));
- return nil;
- }
- if(r == '"')
- break;
- fmtrune(&fmt, r);
- }
- free(lastfmt);
- lastfmt = fmtstrflush(&fmt);
- return strdup(lastfmt);
-}
-
-void
-pragvararg(void)
-{
- Sym *s;
- int n, c;
- char *t;
- Type *ty;
- Tname *l;
-
- if(!debug['F'])
- goto out;
- s = getsym();
- if(s && strcmp(s->name, "argpos") == 0)
- goto ckpos;
- if(s && strcmp(s->name, "type") == 0)
- goto cktype;
- if(s && strcmp(s->name, "flag") == 0)
- goto ckflag;
- if(s && strcmp(s->name, "countpos") == 0)
- goto ckcount;
- yyerror("syntax in #pragma varargck");
- goto out;
-
-ckpos:
-/*#pragma varargck argpos warn 2*/
- s = getsym();
- if(s == S)
- goto bad;
- n = getnsn();
- if(n < 0)
- goto bad;
- newname(s->name, n, 0);
- goto out;
-
-ckcount:
-/*#pragma varargck countpos name 2*/
- s = getsym();
- if(s == S)
- goto bad;
- n = getnsn();
- if(n < 0)
- goto bad;
- newname(s->name, 0, n);
- goto out;
-
-ckflag:
-/*#pragma varargck flag 'c'*/
- c = getnsc();
- if(c != '\'')
- goto bad;
- c = getr();
- if(c == '\\')
- c = getr();
- else if(c == '\'')
- goto bad;
- if(c == '\n')
- goto bad;
- if(getc() != '\'')
- goto bad;
- argflag(c, Fignor);
- goto out;
-
-cktype:
- c = getnsc();
- unget(c);
- if(c != '"') {
-/*#pragma varargck type name int*/
- s = getsym();
- if(s == S)
- goto bad;
- l = newname(s->name, -1, -1);
- s = getsym();
- if(s == S)
- goto bad;
- ty = s->type;
- while((c = getnsc()) == '*')
- ty = typ(TIND, ty);
- unget(c);
- newprot(s, ty, "a", &l->prot);
- goto out;
- }
-
-/*#pragma varargck type O int*/
- t = getquoted();
- if(t == nil)
- goto bad;
- s = getsym();
- if(s == S)
- goto bad;
- ty = s->type;
- while((c = getnsc()) == '*')
- ty = typ(TIND, ty);
- unget(c);
- newprot(s, ty, t, &tprot);
- goto out;
-
-bad:
- yyerror("syntax in #pragma varargck");
-
-out:
- while(getnsc() != '\n')
- ;
-}
-
-Node*
-nextarg(Node *n, Node **a)
-{
- if(n == Z) {
- *a = Z;
- return Z;
- }
- if(n->op == OLIST) {
- *a = n->left;
- return n->right;
- }
- *a = n;
- return Z;
-}
-
-void
-checkargs(Node *nn, char *s, int pos)
-{
- Node *a, *n;
- Bits flag;
- Tprot *l;
-
- if(!debug['F'])
- return;
- n = nn;
- for(;;) {
- s = strchr(s, '%');
- if(s == 0) {
- nextarg(n, &a);
- if(a != Z)
- warn(nn, "more arguments than format %T",
- a->type);
- return;
- }
- s++;
- flag = getflag(s);
- while(nstar > 0) {
- n = nextarg(n, &a);
- pos++;
- nstar--;
- if(a == Z) {
- warn(nn, "more format than arguments %s",
- lastfmt);
- return;
- }
- if(a->type == T)
- continue;
- if(!sametype(types[TINT], a->type) &&
- !sametype(types[TUINT], a->type))
- warn(nn, "format mismatch '*' in %s %T, arg %d",
- lastfmt, a->type, pos);
- }
- for(l=tprot; l; l=l->link)
- if(sametype(types[TVOID], l->type)) {
- if(beq(flag, l->flag)) {
- s++;
- goto loop;
- }
- }
-
- n = nextarg(n, &a);
- pos++;
- if(a == Z) {
- warn(nn, "more format than arguments %s",
- lastfmt);
- return;
- }
- if(a->type == 0)
- continue;
- for(l=tprot; l; l=l->link)
- if(sametype(a->type, l->type)) {
-/*print("checking %T/%ux %T/%ux\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
- if(beq(flag, l->flag))
- goto loop;
- }
- warn(nn, "format mismatch %s %T, arg %d", lastfmt, a->type, pos);
- loop:;
- }
-}
-
-void
-dpcheck(Node *n)
-{
- char *s;
- Node *a, *b;
- Tname *l;
- Tprot *tl;
- int i, j;
-
- if(n == Z)
- return;
- b = n->left;
- if(b == Z || b->op != ONAME)
- return;
- s = b->sym->name;
- for(l=tname; l; l=l->link)
- if(strcmp(s, l->name) == 0)
- break;
- if(l == 0)
- return;
-
- if(l->count > 0) {
- // fetch count, then check remaining length
- i = l->count;
- a = nil;
- b = n->right;
- while(i > 0) {
- b = nextarg(b, &a);
- i--;
- }
- if(a == Z) {
- diag(n, "can't find count arg");
- return;
- }
- if(a->op != OCONST || !typechl[a->type->etype]) {
- diag(n, "count is invalid constant");
- return;
- }
- j = a->vconst;
- i = 0;
- while(b != Z) {
- b = nextarg(b, &a);
- i++;
- }
- if(i != j)
- diag(n, "found %d argument%s after count %d", i, i == 1 ? "" : "s", j);
- }
-
- if(l->prot != nil) {
- // check that all arguments after param or count
- // are listed in type list.
- i = l->count;
- if(i == 0)
- i = l->param;
- if(i == 0)
- return;
- a = nil;
- b = n->right;
- while(i > 0) {
- b = nextarg(b, &a);
- i--;
- }
- if(a == Z) {
- diag(n, "can't find count/param arg");
- return;
- }
- while(b != Z) {
- b = nextarg(b, &a);
- for(tl=l->prot; tl; tl=tl->link)
- if(sametype(a->type, tl->type))
- break;
- if(tl == nil)
- diag(a, "invalid type %T in call to %s", a->type, s);
- }
- }
-
- if(l->param <= 0)
- return;
- i = l->param;
- a = nil;
- b = n->right;
- while(i > 0) {
- b = nextarg(b, &a);
- i--;
- }
- if(a == Z) {
- diag(n, "can't find format arg");
- return;
- }
- if(!sametype(indchar, a->type)) {
- diag(n, "format arg type %T", a->type);
- return;
- }
- if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
-/* warn(n, "format arg not constant string");*/
- return;
- }
- s = a->left->cstring;
- checkargs(b, s, l->param);
-}
-
-void
-pragpack(void)
-{
- Sym *s;
-
- packflg = 0;
- s = getsym();
- if(s) {
- packflg = atoi(s->name+1);
- if(strcmp(s->name, "on") == 0 ||
- strcmp(s->name, "yes") == 0)
- packflg = 1;
- }
- while(getnsc() != '\n')
- ;
- if(debug['f'])
- if(packflg)
- print("%4d: pack %d\n", lineno, packflg);
- else
- print("%4d: pack off\n", lineno);
-}
-
-void
-pragfpround(void)
-{
- Sym *s;
-
- fproundflg = 0;
- s = getsym();
- if(s) {
- fproundflg = atoi(s->name+1);
- if(strcmp(s->name, "on") == 0 ||
- strcmp(s->name, "yes") == 0)
- fproundflg = 1;
- }
- while(getnsc() != '\n')
- ;
- if(debug['f'])
- if(fproundflg)
- print("%4d: fproundflg %d\n", lineno, fproundflg);
- else
- print("%4d: fproundflg off\n", lineno);
-}
-
-void
-pragtextflag(void)
-{
- Sym *s;
-
- s = getsym();
- if(s == S) {
- textflag = getnsn();
- } else {
- if(s->macro) {
- macexpand(s, symb);
- }
- if(symb[0] < '0' || symb[0] > '9')
- yyerror("pragma textflag not an integer");
- textflag = atoi(symb);
- }
- while(getnsc() != '\n')
- ;
- if(debug['f'])
- print("%4d: textflag %d\n", lineno, textflag);
-}
-
-void
-pragdataflag(void)
-{
- Sym *s;
-
- s = getsym();
- if(s == S) {
- dataflag = getnsn();
- } else {
- if(s->macro) {
- macexpand(s, symb);
- }
- if(symb[0] < '0' || symb[0] > '9')
- yyerror("pragma dataflag not an integer");
- dataflag = atoi(symb);
- }
- while(getnsc() != '\n')
- ;
- if(debug['f'])
- print("%4d: dataflag %d\n", lineno, dataflag);
-}
-
-void
-pragincomplete(void)
-{
- Sym *s;
- Type *t;
- int istag, w, et;
-
- istag = 0;
- s = getsym();
- if(s == nil)
- goto out;
- et = 0;
- w = s->lexical;
- if(w == LSTRUCT)
- et = TSTRUCT;
- else if(w == LUNION)
- et = TUNION;
- if(et != 0){
- s = getsym();
- if(s == nil){
- yyerror("missing struct/union tag in pragma incomplete");
- goto out;
- }
- if(s->lexical != LNAME && s->lexical != LTYPE){
- yyerror("invalid struct/union tag: %s", s->name);
- goto out;
- }
- dotag(s, et, 0);
- istag = 1;
- }else if(strcmp(s->name, "_off_") == 0){
- debug['T'] = 0;
- goto out;
- }else if(strcmp(s->name, "_on_") == 0){
- debug['T'] = 1;
- goto out;
- }
- t = s->type;
- if(istag)
- t = s->suetag;
- if(t == T)
- yyerror("unknown type %s in pragma incomplete", s->name);
- else if(!typesu[t->etype])
- yyerror("not struct/union type in pragma incomplete: %s", s->name);
- else
- t->garb |= GINCOMPLETE;
-out:
- while(getnsc() != '\n')
- ;
- if(debug['f'])
- print("%s incomplete\n", s->name);
-}
-
-Sym*
-getimpsym(void)
-{
- int c;
- char *cp;
-
- c = getnsc();
- if(isspace(c) || c == '"') {
- unget(c);
- return S;
- }
- for(cp = symb;;) {
- if(cp <= symb+NSYMB-4)
- *cp++ = c;
- c = getc();
- if(c > 0 && !isspace(c) && c != '"')
- continue;
- unget(c);
- break;
- }
- *cp = 0;
- if(cp > symb+NSYMB-4)
- yyerror("symbol too large: %s", symb);
- return lookup();
-}
-
-static int
-more(void)
-{
- int c;
-
- do
- c = getnsc();
- while(c == ' ' || c == '\t');
- unget(c);
- return c != '\n';
-}
-
-void
-pragcgo(char *verb)
-{
- Sym *local, *remote;
- char *p;
-
- if(strcmp(verb, "cgo_dynamic_linker") == 0 || strcmp(verb, "dynlinker") == 0) {
- p = getquoted();
- if(p == nil)
- goto err1;
- fmtprint(&pragcgobuf, "cgo_dynamic_linker %q\n", p);
- goto out;
-
- err1:
- yyerror("usage: #pragma cgo_dynamic_linker \"path\"");
- goto out;
- }
-
- if(strcmp(verb, "dynexport") == 0)
- verb = "cgo_export_dynamic";
- if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) {
- local = getimpsym();
- if(local == nil)
- goto err2;
- if(!more()) {
- fmtprint(&pragcgobuf, "%s %q\n", verb, local->name);
- goto out;
- }
- remote = getimpsym();
- if(remote == nil)
- goto err2;
- fmtprint(&pragcgobuf, "%s %q %q\n", verb, local->name, remote->name);
- goto out;
-
- err2:
- yyerror("usage: #pragma %s local [remote]", verb);
- goto out;
- }
-
- if(strcmp(verb, "cgo_import_dynamic") == 0 || strcmp(verb, "dynimport") == 0) {
- local = getimpsym();
- if(local == nil)
- goto err3;
- if(!more()) {
- fmtprint(&pragcgobuf, "cgo_import_dynamic %q\n", local->name);
- goto out;
- }
- remote = getimpsym();
- if(remote == nil)
- goto err3;
- if(!more()) {
- fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q\n", local->name, remote->name);
- goto out;
- }
- p = getquoted();
- if(p == nil)
- goto err3;
- fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q %q\n", local->name, remote->name, p);
- goto out;
-
- err3:
- yyerror("usage: #pragma cgo_import_dynamic local [remote [\"library\"]]");
- goto out;
- }
-
- if(strcmp(verb, "cgo_import_static") == 0) {
- local = getimpsym();
- if(local == nil)
- goto err4;
- fmtprint(&pragcgobuf, "cgo_import_static %q\n", local->name);
- goto out;
-
- err4:
- yyerror("usage: #pragma cgo_import_static local [remote]");
- goto out;
- }
-
- if(strcmp(verb, "cgo_ldflag") == 0) {
- p = getquoted();
- if(p == nil)
- goto err5;
- fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p);
- goto out;
-
- err5:
- yyerror("usage: #pragma cgo_ldflag \"arg\"");
- goto out;
- }
-
-out:
- while(getnsc() != '\n')
- ;
-}
diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c
deleted file mode 100644
index 92c067db8..000000000
--- a/src/cmd/cc/funct.c
+++ /dev/null
@@ -1,431 +0,0 @@
-// Inferno utils/cc/funct.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-
-typedef struct Ftab Ftab;
-struct Ftab
-{
- char op;
- char* name;
- char typ;
-};
-typedef struct Gtab Gtab;
-struct Gtab
-{
- char etype;
- char* name;
-};
-
-Ftab ftabinit[OEND];
-Gtab gtabinit[NALLTYPES];
-
-int
-isfunct(Node *n)
-{
- Type *t, *t1;
- Funct *f;
- Node *l;
- Sym *s;
- int o;
-
- o = n->op;
- if(n->left == Z)
- goto no;
- t = n->left->type;
- if(t == T)
- goto no;
- f = t->funct;
-
- switch(o) {
- case OAS: // put cast on rhs
- case OASI:
- case OASADD:
- case OASAND:
- case OASASHL:
- case OASASHR:
- case OASDIV:
- case OASLDIV:
- case OASLMOD:
- case OASLMUL:
- case OASLSHR:
- case OASMOD:
- case OASMUL:
- case OASOR:
- case OASSUB:
- case OASXOR:
- if(n->right == Z)
- goto no;
- t1 = n->right->type;
- if(t1 == T)
- goto no;
- if(t1->funct == f)
- break;
-
- l = new(OXXX, Z, Z);
- *l = *n->right;
-
- n->right->left = l;
- n->right->right = Z;
- n->right->type = t;
- n->right->op = OCAST;
-
- if(!isfunct(n->right))
- prtree(n, "isfunc !");
- break;
-
- case OCAST: // t f(T) or T f(t)
- t1 = n->type;
- if(t1 == T)
- goto no;
- if(f != nil) {
- s = f->castfr[t1->etype];
- if(s == S)
- goto no;
- n->right = n->left;
- goto build;
- }
- f = t1->funct;
- if(f != nil) {
- s = f->castto[t->etype];
- if(s == S)
- goto no;
- n->right = n->left;
- goto build;
- }
- goto no;
- }
-
- if(f == nil)
- goto no;
- s = f->sym[o];
- if(s == S)
- goto no;
-
- /*
- * the answer is yes,
- * now we rewrite the node
- * and give diagnostics
- */
- switch(o) {
- default:
- diag(n, "isfunct op missing %O\n", o);
- goto bad;
-
- case OADD: // T f(T, T)
- case OAND:
- case OASHL:
- case OASHR:
- case ODIV:
- case OLDIV:
- case OLMOD:
- case OLMUL:
- case OLSHR:
- case OMOD:
- case OMUL:
- case OOR:
- case OSUB:
- case OXOR:
-
- case OEQ: // int f(T, T)
- case OGE:
- case OGT:
- case OHI:
- case OHS:
- case OLE:
- case OLO:
- case OLS:
- case OLT:
- case ONE:
- if(n->right == Z)
- goto bad;
- t1 = n->right->type;
- if(t1 == T)
- goto bad;
- if(t1->funct != f)
- goto bad;
- n->right = new(OLIST, n->left, n->right);
- break;
-
- case OAS: // structure copies done by the compiler
- case OASI:
- goto no;
-
- case OASADD: // T f(T*, T)
- case OASAND:
- case OASASHL:
- case OASASHR:
- case OASDIV:
- case OASLDIV:
- case OASLMOD:
- case OASLMUL:
- case OASLSHR:
- case OASMOD:
- case OASMUL:
- case OASOR:
- case OASSUB:
- case OASXOR:
- if(n->right == Z)
- goto bad;
- t1 = n->right->type;
- if(t1 == T)
- goto bad;
- if(t1->funct != f)
- goto bad;
- n->right = new(OLIST, new(OADDR, n->left, Z), n->right);
- break;
-
- case OPOS: // T f(T)
- case ONEG:
- case ONOT:
- case OCOM:
- n->right = n->left;
- break;
-
-
- }
-
-build:
- l = new(ONAME, Z, Z);
- l->sym = s;
- l->type = s->type;
- l->etype = s->type->etype;
- l->xoffset = s->offset;
- l->class = s->class;
- tcomo(l, 0);
-
- n->op = OFUNC;
- n->left = l;
- n->type = l->type->link;
- if(tcompat(n, T, l->type, tfunct))
- goto bad;
- if(tcoma(n->left, n->right, l->type->down, 1))
- goto bad;
- return 1;
-
-no:
- return 0;
-
-bad:
- diag(n, "can't rewrite typestr for op %O\n", o);
- prtree(n, "isfunct");
- n->type = T;
- return 1;
-}
-
-void
-dclfunct(Type *t, Sym *s)
-{
- Funct *f;
- Node *n;
- Type *f1, *f2, *f3, *f4;
- int o, i, c;
- char str[100];
-
- if(t->funct)
- return;
-
- // recognize generated tag of dorm _%d_
- if(t->tag == S)
- goto bad;
- for(i=0; c = t->tag->name[i]; i++) {
- if(c == '_') {
- if(i == 0 || t->tag->name[i+1] == 0)
- continue;
- break;
- }
- if(c < '0' || c > '9')
- break;
- }
- if(c == 0)
- goto bad;
-
- f = alloc(sizeof(*f));
- for(o=0; o<nelem(f->sym); o++)
- f->sym[o] = S;
-
- t->funct = f;
-
- f1 = typ(TFUNC, t);
- f1->down = copytyp(t);
- f1->down->down = t;
-
- f2 = typ(TFUNC, types[TINT]);
- f2->down = copytyp(t);
- f2->down->down = t;
-
- f3 = typ(TFUNC, t);
- f3->down = typ(TIND, t);
- f3->down->down = t;
-
- f4 = typ(TFUNC, t);
- f4->down = t;
-
- for(i=0;; i++) {
- o = ftabinit[i].op;
- if(o == OXXX)
- break;
- sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name);
- n = new(ONAME, Z, Z);
- n->sym = slookup(str);
- f->sym[o] = n->sym;
- switch(ftabinit[i].typ) {
- default:
- diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ);
- break;
-
- case 1: // T f(T,T) +
- dodecl(xdecl, CEXTERN, f1, n);
- break;
-
- case 2: // int f(T,T) ==
- dodecl(xdecl, CEXTERN, f2, n);
- break;
-
- case 3: // void f(T*,T) +=
- dodecl(xdecl, CEXTERN, f3, n);
- break;
-
- case 4: // T f(T) ~
- dodecl(xdecl, CEXTERN, f4, n);
- break;
- }
- }
- for(i=0;; i++) {
- o = gtabinit[i].etype;
- if(o == TXXX)
- break;
-
- /*
- * OCAST types T1 _T2_T1_(T2)
- */
- sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name);
- n = new(ONAME, Z, Z);
- n->sym = slookup(str);
- f->castto[o] = n->sym;
-
- f1 = typ(TFUNC, t);
- f1->down = types[o];
- dodecl(xdecl, CEXTERN, f1, n);
-
- sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name);
- n = new(ONAME, Z, Z);
- n->sym = slookup(str);
- f->castfr[o] = n->sym;
-
- f1 = typ(TFUNC, types[o]);
- f1->down = t;
- dodecl(xdecl, CEXTERN, f1, n);
- }
- return;
-bad:
- diag(Z, "dclfunct bad %T %s\n", t, s->name);
-}
-
-Gtab gtabinit[NALLTYPES] =
-{
- TCHAR, "c",
- TUCHAR, "uc",
- TSHORT, "h",
- TUSHORT, "uh",
- TINT, "i",
- TUINT, "ui",
- TLONG, "l",
- TULONG, "ul",
- TVLONG, "v",
- TUVLONG, "uv",
- TFLOAT, "f",
- TDOUBLE, "d",
- TXXX
-};
-
-Ftab ftabinit[OEND] =
-{
- OADD, "add", 1,
- OAND, "and", 1,
- OASHL, "ashl", 1,
- OASHR, "ashr", 1,
- ODIV, "div", 1,
- OLDIV, "ldiv", 1,
- OLMOD, "lmod", 1,
- OLMUL, "lmul", 1,
- OLSHR, "lshr", 1,
- OMOD, "mod", 1,
- OMUL, "mul", 1,
- OOR, "or", 1,
- OSUB, "sub", 1,
- OXOR, "xor", 1,
-
- OEQ, "eq", 2,
- OGE, "ge", 2,
- OGT, "gt", 2,
- OHI, "hi", 2,
- OHS, "hs", 2,
- OLE, "le", 2,
- OLO, "lo", 2,
- OLS, "ls", 2,
- OLT, "lt", 2,
- ONE, "ne", 2,
-
- OASADD, "asadd", 3,
- OASAND, "asand", 3,
- OASASHL, "asashl", 3,
- OASASHR, "asashr", 3,
- OASDIV, "asdiv", 3,
- OASLDIV, "asldiv", 3,
- OASLMOD, "aslmod", 3,
- OASLMUL, "aslmul", 3,
- OASLSHR, "aslshr", 3,
- OASMOD, "asmod", 3,
- OASMUL, "asmul", 3,
- OASOR, "asor", 3,
- OASSUB, "assub", 3,
- OASXOR, "asxor", 3,
-
- OPOS, "pos", 4,
- ONEG, "neg", 4,
- OCOM, "com", 4,
- ONOT, "not", 4,
-
-// OPOSTDEC,
-// OPOSTINC,
-// OPREDEC,
-// OPREINC,
-
- OXXX,
-};
-
-// Node* nodtestv;
-
-// Node* nodvpp;
-// Node* nodppv;
-// Node* nodvmm;
-// Node* nodmmv;
diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c
deleted file mode 100644
index d9f67f0ae..000000000
--- a/src/cmd/cc/godefs.c
+++ /dev/null
@@ -1,367 +0,0 @@
-// cmd/cc/godefs.cc
-//
-// derived from pickle.cc which itself was derived from acid.cc.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009-2011 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-
-static int upper;
-
-static char *kwd[] =
-{
- "_bool",
- "_break",
- "_byte",
- "_case",
- "_chan",
- "_complex128",
- "_complex64",
- "_const",
- "_continue",
- "_default",
- "_defer",
- "_else",
- "_fallthrough",
- "_false",
- "_float32",
- "_float64",
- "_for",
- "_func",
- "_go",
- "_goto",
- "_if",
- "_import",
- "_int",
- "_int16",
- "_int32",
- "_int64",
- "_int8",
- "_interface",
- "_intptr",
- "_map",
- "_package",
- "_panic",
- "_range",
- "_return",
- "_select",
- "_string",
- "_struct",
- "_switch",
- "_true",
- "_type",
- "_uint",
- "_uint16",
- "_uint32",
- "_uint64",
- "_uint8",
- "_uintptr",
- "_var",
-};
-
-static char*
-pmap(char *s)
-{
- int i, bot, top, mid;
-
- bot = -1;
- top = nelem(kwd);
- while(top - bot > 1){
- mid = (bot + top) / 2;
- i = strcmp(kwd[mid]+1, s);
- if(i == 0)
- return kwd[mid];
- if(i < 0)
- bot = mid;
- else
- top = mid;
- }
-
- return s;
-}
-
-
-int
-Uconv(Fmt *fp)
-{
- char str[STRINGSZ+1];
- char *s, *n;
- int i;
-
- str[0] = 0;
- s = va_arg(fp->args, char*);
-
- // strip package name
- n = strrchr(s, '.');
- if(n != nil)
- s = n + 1;
-
- if(s && *s) {
- if(upper)
- str[0] = toupper((uchar)*s);
- else
- str[0] = tolower((uchar)*s);
- for(i = 1; i < STRINGSZ && s[i] != 0; i++)
- str[i] = tolower((uchar)s[i]);
- str[i] = 0;
- }
-
- return fmtstrcpy(fp, pmap(str));
-}
-
-
-static Sym*
-findsue(Type *t)
-{
- int h;
- Sym *s;
-
- if(t != T)
- for(h=0; h<nelem(hash); h++)
- for(s = hash[h]; s != S; s = s->link)
- if(s->suetag && s->suetag->link == t)
- return s;
- return 0;
-}
-
-static void
-printtypename(Type *t)
-{
- Sym *s;
- int w;
- char *n;
-
- for( ; t != nil; t = t->link) {
- switch(t->etype) {
- case TIND:
- // Special handling of *void.
- if(t->link != nil && t->link->etype==TVOID) {
- Bprint(&outbuf, "unsafe.Pointer");
- return;
- }
- // *func == func
- if(t->link != nil && t->link->etype==TFUNC)
- continue;
- Bprint(&outbuf, "*");
- continue;
- case TARRAY:
- w = t->width;
- if(t->link && t->link->width)
- w /= t->link->width;
- Bprint(&outbuf, "[%d]", w);
- continue;
- }
- break;
- }
-
- if(t == nil) {
- Bprint(&outbuf, "bad // should not happen");
- return;
- }
-
- switch(t->etype) {
- case TINT:
- case TUINT:
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TFLOAT:
- case TDOUBLE:
- // All names used in the runtime code should be typedefs.
- if(t->tag != nil) {
- if(strcmp(t->tag->name, "intgo") == 0)
- Bprint(&outbuf, "int");
- else if(strcmp(t->tag->name, "uintgo") == 0)
- Bprint(&outbuf, "uint");
- else
- Bprint(&outbuf, "%s", t->tag->name);
- } else
- Bprint(&outbuf, "C.%T", t);
- break;
- case TUNION:
- case TSTRUCT:
- s = findsue(t->link);
- n = "bad";
- if(s != S)
- n = s->name;
- else if(t->tag)
- n = t->tag->name;
- if(strcmp(n, "String") == 0)
- Bprint(&outbuf, "string");
- else if(strcmp(n, "Slice") == 0)
- Bprint(&outbuf, "[]byte");
- else if(strcmp(n, "Eface") == 0)
- Bprint(&outbuf, "interface{}");
- else
- Bprint(&outbuf, "%U", n);
- break;
- case TFUNC:
- // There's no equivalent to a C function in the Go world.
- Bprint(&outbuf, "unsafe.Pointer");
- break;
- case TDOT:
- Bprint(&outbuf, "...interface{}");
- break;
- default:
- Bprint(&outbuf, " weird<%T>", t);
- }
-}
-
-static int
-dontrun(void)
-{
- Io *i;
- int n;
-
- if(!debug['q'] && !debug['Q'])
- return 1;
- if(debug['q'] + debug['Q'] > 1) {
- n = 0;
- for(i=iostack; i; i=i->link)
- n++;
- if(n > 1)
- return 1;
- }
-
- upper = debug['Q'];
- return 0;
-}
-
-void
-godeftype(Type *t)
-{
- Sym *s;
- Type *l;
- int gotone;
-
- if(dontrun())
- return;
-
- switch(t->etype) {
- case TUNION:
- case TSTRUCT:
- s = findsue(t->link);
- if(s == S) {
- Bprint(&outbuf, "/* can't find %T */\n\n", t);
- return;
- }
-
- gotone = 0; // for unions, take first member of size equal to union
- Bprint(&outbuf, "type %U struct {\n", s->name);
- for(l = t->link; l != T; l = l->down) {
- Bprint(&outbuf, "\t");
- if(t->etype == TUNION) {
- if(!gotone && l->width == t->width)
- gotone = 1;
- else
- Bprint(&outbuf, "// (union)\t");
- }
- if(l->sym != nil) // not anonymous field
- Bprint(&outbuf, "%U\t", l->sym->name);
- printtypename(l);
- Bprint(&outbuf, "\n");
- }
- Bprint(&outbuf, "}\n\n");
- break;
-
- default:
- Bprint(&outbuf, "/* %T */\n\n", t);
- break;
- }
-}
-
-void
-godefvar(Sym *s)
-{
- Type *t, *t1;
- char n;
-
- if(dontrun())
- return;
-
- t = s->type;
- if(t == nil)
- return;
-
- switch(t->etype) {
- case TENUM:
- if(!typefd[t->etype])
- Bprint(&outbuf, "const %s = %lld\n", s->name, s->vconst);
- else
- Bprint(&outbuf, "const %s = %f\n;", s->name, s->fconst);
- break;
-
- case TFUNC:
- Bprint(&outbuf, "func %U(", s->name);
- n = 'a';
- for(t1 = t->down; t1 != T; t1 = t1->down) {
- if(t1->etype == TVOID)
- break;
- if(t1 != t->down)
- Bprint(&outbuf, ", ");
- Bprint(&outbuf, "%c ", n++);
- printtypename(t1);
- }
- Bprint(&outbuf, ")");
- if(t->link && t->link->etype != TVOID) {
- Bprint(&outbuf, " ");
- printtypename(t->link);
- }
- Bprint(&outbuf, "\n");
- break;
-
- default:
- switch(s->class) {
- case CTYPEDEF:
- if(!typesu[t->etype]) {
- Bprint(&outbuf, "// type %U\t", s->name);
- printtypename(t);
- Bprint(&outbuf, "\n");
- }
- break;
- case CSTATIC:
- case CEXTERN:
- case CGLOBL:
- if(strchr(s->name, '$') != nil)
- break;
- if(strncmp(s->name, "go.weak.", 8) == 0)
- break;
- Bprint(&outbuf, "var %U\t", s->name);
- printtypename(t);
- Bprint(&outbuf, "\n");
- break;
- }
- break;
- }
-}
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
deleted file mode 100644
index 7c9f718c0..000000000
--- a/src/cmd/cc/lex.c
+++ /dev/null
@@ -1,1593 +0,0 @@
-// Inferno utils/cc/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/lex.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-#include "y.tab.h"
-#include "../ld/textflag.h"
-
-#ifndef CPP
-#define CPP "cpp"
-#endif
-
-int
-systemtype(int sys)
-{
-#ifdef _WIN32
- return sys&Windows;
-#else
- return sys&Plan9;
-#endif
-}
-
-int
-pathchar(void)
-{
- return '/';
-}
-
-/*
- * known debug flags
- * -a acid declaration output
- * -A !B
- * -B non ANSI
- * -d print declarations
- * -D name define
- * -F format specification check
- * -G print pgen stuff
- * -g print cgen trees
- * -i print initialization
- * -I path include
- * -l generate little-endian code
- * -L print every NAME symbol
- * -M constant multiplication
- * -m print add/sub/mul trees
- * -n print acid or godefs to file (%.c=%.acid) (with -a or -aa)
- * -o file output file
- * -p use standard cpp ANSI preprocessor (not on windows)
- * -p something with peepholes
- * -q print equivalent Go code for variables and types (lower-case identifiers)
- * -Q print equivalent Go code for variables and types (upper-case identifiers)
- * -r print registerization
- * -s print structure offsets (with -a or -aa)
- * -S print assembly
- * -t print type trees
- * -V enable void* conversion warnings
- * -v verbose printing
- * -w print warnings
- * -X abort on error
- * -. Inhibit search for includes in source directory
- */
-
-void
-usage(void)
-{
- print("usage: %cc [options] file.c...\n", thechar);
- flagprint(1);
- errorexit();
-}
-
-void
-dospim(void)
-{
- thechar = '0';
- thestring = "spim";
-}
-
-char **defs;
-int ndef;
-
-void
-dodef(char *p)
-{
- if(ndef%8 == 0)
- defs = allocn(defs, ndef*sizeof(char *),
- 8*sizeof(char *));
- defs[ndef++] = p;
- dodefine(p);
-}
-
-void
-main(int argc, char *argv[])
-{
- int c;
- char *p;
-
- // Allow GOARCH=thestring or GOARCH=thestringsuffix,
- // but not other values.
- p = getgoarch();
- if(strncmp(p, thestring, strlen(thestring)) != 0)
- sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
- if(strcmp(p, "amd64p32") == 0) // must be before cinit
- ewidth[TIND] = 4;
-
- nacl = strcmp(getgoos(), "nacl") == 0;
- if(nacl)
- flag_largemodel = 1;
-
- quotefmtinstall(); // before cinit, which overrides %Q
-
- linkarchinit();
- ctxt = linknew(thelinkarch);
- ctxt->diag = yyerror;
- ctxt->bso = &bstdout;
- Binit(&bstdout, 1, OWRITE);
-
- ensuresymb(NSYMB);
- memset(debug, 0, sizeof(debug));
- tinit();
- cinit();
- ginit();
- arginit();
-
- fmtstrinit(&pragcgobuf);
-
- tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
- ndef = 0;
- defs = nil;
- outfile = 0;
- setinclude(".");
-
- flagcount("+", "pass -+ to preprocessor", &debug['+']);
- flagcount(".", "pass -. to preprocessor", &debug['.']);
- flagcount("<", "debug shift", &debug['<']);
- flagcount("A", "debug alignment", &debug['A']);
- flagcount("B", "allow pre-ANSI code", &debug['B']);
- if(thechar == '5')
- flagcount("C", "debug constant propagation", &debug['C']);
- flagfn1("D", "name[=value]: add #define", dodef);
- flagcount("F", "enable print format checks", &debug['F']);
- if(thechar == '5')
- flagcount("H", "debug shift propagation", &debug['H']);
- flagfn1("I", "dir: add dir to include path", setinclude);
- flagcount("L", "debug lexer", &debug['L']);
- flagcount("M", "debug move generation", &debug['M']);
- flagcount("N", "disable optimizations", &debug['N']);
- flagcount("P", "debug peephole optimizer", &debug['P']);
- flagcount("Q", "print exported Go definitions", &debug['Q']);
- flagcount("R", "debug register optimizer", &debug['R']);
- flagcount("S", "print assembly", &debug['S']);
- flagcount("T", "enable type signatures", &debug['T']);
- flagcount("V", "enable pointer type checks", &debug['V']);
- flagcount("W", "debug switch generation", &debug['W']);
- flagcount("X", "abort on error", &debug['X']);
- flagcount("Y", "debug index generation", &debug['Y']);
- flagcount("Z", "skip code generation", &debug['Z']);
- flagcount("a", "print acid definitions", &debug['a']);
- flagcount("c", "debug constant evaluation", &debug['c']);
- flagcount("d", "debug declarations", &debug['d']);
- flagcount("e", "debug macro expansion", &debug['e']);
- flagcount("f", "debug pragmas", &debug['f']);
- flagcount("g", "debug code generation", &debug['g']);
- flagcount("i", "debug initialization", &debug['i']);
- if(thechar == 'v')
- flagfn0("l", "little-endian mips mode", dospim);
- flagcount("m", "debug multiplication", &debug['m']);
- flagcount("n", "print acid/Go to file, not stdout", &debug['n']);
- flagstr("o", "file: set output file", &outfile);
- flagcount("p", "invoke C preprocessor", &debug['p']);
- flagcount("q", "print Go definitions", &debug['q']);
- flagcount("s", "print #define assembly offsets", &debug['s']);
- flagcount("t", "debug code generation", &debug['t']);
- flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
- flagcount("w", "enable warnings", &debug['w']);
- flagcount("v", "increase debug verbosity", &debug['v']);
- if(thechar == '6')
- flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
-
- flagparse(&argc, &argv, usage);
- ctxt->debugasm = debug['S'];
- ctxt->debugvlog = debug['v'];
-
- if(argc < 1 && outfile == 0)
- usage();
-
- if(argc > 1){
- print("can't compile multiple files\n");
- errorexit();
- }
-
- if(argc == 0)
- c = compile("stdin", defs, ndef);
- else
- c = compile(argv[0], defs, ndef);
-
- Bflush(&bstdout);
- if(c)
- errorexit();
- exits(0);
-}
-
-int
-compile(char *file, char **defs, int ndef)
-{
- char *ofile;
- char *p, **av, opt[256];
- int i, c, fd[2];
- static int first = 1;
-
- ofile = alloc(strlen(file)+10);
- strcpy(ofile, file);
- p = utfrrune(ofile, pathchar());
- if(p) {
- *p++ = 0;
- if(!debug['.'])
- include[0] = strdup(ofile);
- } else
- p = ofile;
-
- if(outfile == 0) {
- outfile = p;
- if(outfile) {
- if(p = utfrrune(outfile, '.'))
- if(p[1] == 'c' && p[2] == 0)
- p[0] = 0;
- p = utfrune(outfile, 0);
- if(debug['a'] && debug['n'])
- strcat(p, ".acid");
- else if((debug['q'] || debug['Q']) && debug['n'])
- strcat(p, ".go");
- else {
- p[0] = '.';
- p[1] = thechar;
- p[2] = 0;
- }
- } else
- outfile = "/dev/null";
- }
-
- if (first)
- Binit(&diagbuf, 1, OWRITE);
- /*
- * if we're writing acid to standard output, don't keep scratching
- * outbuf.
- */
- if((debug['a'] || debug['q'] || debug['Q']) && !debug['n']) {
- if (first) {
- outfile = 0;
- Binit(&outbuf, dup(1, -1), OWRITE);
- dup(2, 1);
- }
- } else {
- c = create(outfile, OWRITE, 0664);
- if(c < 0) {
- diag(Z, "cannot open %s - %r", outfile);
- outfile = 0;
- errorexit();
- }
- Binit(&outbuf, c, OWRITE);
- outfile = strdup(outfile);
- }
- newio();
- first = 0;
-
- /* Use an ANSI preprocessor */
- if(debug['p']) {
- if(systemtype(Windows)) {
- diag(Z, "-p option not supported on windows");
- errorexit();
- }
- if(access(file, AREAD) < 0) {
- diag(Z, "%s does not exist", file);
- errorexit();
- }
- if(pipe(fd) < 0) {
- diag(Z, "pipe failed");
- errorexit();
- }
- switch(fork()) {
- case -1:
- diag(Z, "fork failed");
- errorexit();
- case 0:
- close(fd[0]);
- dup(fd[1], 1);
- close(fd[1]);
- av = alloc((ndef+ninclude+5)*sizeof(char *));
- av[0] = CPP;
- i = 1;
- if(debug['.']){
- sprint(opt, "-.");
- av[i++] = strdup(opt);
- }
- if(debug['+']) {
- sprint(opt, "-+");
- av[i++] = strdup(opt);
- }
- for(c = 0; c < ndef; c++)
- av[i++] = smprint("-D%s", defs[c]);
- for(c = 0; c < ninclude; c++)
- av[i++] = smprint("-I%s", include[c]);
- if(strcmp(file, "stdin") != 0)
- av[i++] = file;
- av[i] = 0;
- if(debug['p'] > 1) {
- for(c = 0; c < i; c++)
- fprint(2, "%s ", av[c]);
- fprint(2, "\n");
- }
- exec(av[0], av);
- fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
- errorexit();
- default:
- close(fd[1]);
- newfile(file, fd[0]);
- break;
- }
- } else {
- if(strcmp(file, "stdin") == 0)
- newfile(file, 0);
- else
- newfile(file, -1);
- }
- yyparse();
- if(!debug['a'] && !debug['q'] && !debug['Q'])
- gclean();
- return nerrors;
-}
-
-void
-errorexit(void)
-{
- Bflush(&bstdout);
- if(outfile)
- remove(outfile);
- exits("error");
-}
-
-void
-pushio(void)
-{
- Io *i;
-
- i = iostack;
- if(i == I) {
- yyerror("botch in pushio");
- errorexit();
- }
- i->p = fi.p;
- i->c = fi.c;
-}
-
-void
-newio(void)
-{
- Io *i;
- static int pushdepth = 0;
-
- i = iofree;
- if(i == I) {
- pushdepth++;
- if(pushdepth > 1000) {
- yyerror("macro/io expansion too deep");
- errorexit();
- }
- i = alloc(sizeof(*i));
- } else
- iofree = i->link;
- i->c = 0;
- i->f = -1;
- ionext = i;
-}
-
-void
-newfile(char *s, int f)
-{
- Io *i;
-
- if(debug['e'])
- print("%L: %s\n", lineno, s);
-
- i = ionext;
- i->link = iostack;
- iostack = i;
- i->f = f;
- if(f < 0)
- i->f = open(s, 0);
- if(i->f < 0) {
- yyerror("%cc: %r: %s", thechar, s);
- errorexit();
- }
- fi.c = 0;
- linklinehist(ctxt, lineno, s, 0);
-}
-
-Sym*
-slookup(char *s)
-{
- ensuresymb(strlen(s));
- strcpy(symb, s);
- return lookup();
-}
-
-Sym*
-lookup(void)
-{
- Sym *s;
- uint32 h;
- char *p;
- int c, n;
- char *r, *w;
-
- if((uchar)symb[0] == 0xc2 && (uchar)symb[1] == 0xb7) {
- // turn leading · into ""·
- h = strlen(symb);
- ensuresymb(h+2);
- memmove(symb+2, symb, h+1);
- symb[0] = '"';
- symb[1] = '"';
- }
-
- for(r=w=symb; *r; r++) {
- // turn · (U+00B7) into .
- // turn ∕ (U+2215) into /
- if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) {
- *w++ = '.';
- r++;
- }else if((uchar)*r == 0xe2 && (uchar)*(r+1) == 0x88 && (uchar)*(r+2) == 0x95) {
- *w++ = '/';
- r++;
- r++;
- }else
- *w++ = *r;
- }
- *w = '\0';
-
- h = 0;
- for(p=symb; *p;) {
- h = h * 3;
- h += *p++;
- }
- n = (p - symb) + 1;
- h &= 0xffffff;
- h %= NHASH;
- c = symb[0];
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != c)
- continue;
- if(strcmp(s->name, symb) == 0)
- return s;
- }
- s = alloc(sizeof(*s));
- s->name = alloc(n);
- memmove(s->name, symb, n);
- s->link = hash[h];
- hash[h] = s;
- syminit(s);
-
- return s;
-}
-
-void
-syminit(Sym *s)
-{
- s->lexical = LNAME;
- s->block = 0;
- s->offset = 0;
- s->type = T;
- s->suetag = T;
- s->class = CXXX;
- s->aused = 0;
- s->sig = SIGNONE;
-}
-
-#define EOF (-1)
-#define IGN (-2)
-#define ESC (1<<20)
-#define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
-
-enum
-{
- Numdec = 1<<0,
- Numlong = 1<<1,
- Numuns = 1<<2,
- Numvlong = 1<<3,
- Numflt = 1<<4,
-};
-
-int32
-yylex(void)
-{
- vlong vv;
- int32 c, c1, t;
- char *cp;
- Rune rune;
- Sym *s;
-
- if(peekc != IGN) {
- c = peekc;
- peekc = IGN;
- goto l1;
- }
-l0:
- c = GETC();
-
-l1:
- if(c >= Runeself) {
- /*
- * extension --
- * all multibyte runes are alpha
- */
- cp = symb;
- goto talph;
- }
- if(isspace(c)) {
- if(c == '\n')
- lineno++;
- goto l0;
- }
- if(isalpha(c)) {
- cp = symb;
- if(c != 'L')
- goto talph;
- *cp++ = c;
- c = GETC();
- if(c == '\'') {
- /* L'x' */
- c = escchar('\'', 1, 0);
- if(c == EOF)
- c = '\'';
- c1 = escchar('\'', 1, 0);
- if(c1 != EOF) {
- yyerror("missing '");
- peekc = c1;
- }
- yylval.vval = convvtox(c, TRUNE);
- return LUCONST;
- }
- if(c == '"') {
- goto caselq;
- }
- goto talph;
- }
- if(isdigit(c))
- goto tnum;
- switch(c)
- {
-
- case EOF:
- peekc = EOF;
- return -1;
-
- case '_':
- cp = symb;
- goto talph;
-
- case '#':
- domacro();
- goto l0;
-
- case '.':
- c1 = GETC();
- if(isdigit(c1)) {
- cp = symb;
- *cp++ = c;
- c = c1;
- c1 = 0;
- goto casedot;
- }
- break;
-
- case '"':
- strcpy(symb, "\"<string>\"");
- cp = alloc(0);
- c1 = 0;
-
- /* "..." */
- for(;;) {
- c = escchar('"', 0, 1);
- if(c == EOF)
- break;
- if(c & ESC) {
- cp = allocn(cp, c1, 1);
- cp[c1++] = c;
- } else {
- rune = c;
- c = runelen(rune);
- cp = allocn(cp, c1, c);
- runetochar(cp+c1, &rune);
- c1 += c;
- }
- }
- yylval.sval.l = c1;
- do {
- cp = allocn(cp, c1, 1);
- cp[c1++] = 0;
- } while(c1 & MAXALIGN);
- yylval.sval.s = cp;
- return LSTRING;
-
- caselq:
- /* L"..." */
- strcpy(symb, "\"L<string>\"");
- cp = alloc(0);
- c1 = 0;
- for(;;) {
- c = escchar('"', 1, 0);
- if(c == EOF)
- break;
- cp = allocn(cp, c1, sizeof(TRune));
- *(TRune*)(cp + c1) = c;
- c1 += sizeof(TRune);
- }
- yylval.sval.l = c1;
- do {
- cp = allocn(cp, c1, sizeof(TRune));
- *(TRune*)(cp + c1) = 0;
- c1 += sizeof(TRune);
- } while(c1 & MAXALIGN);
- yylval.sval.s = cp;
- return LLSTRING;
-
- case '\'':
- /* '.' */
- c = escchar('\'', 0, 0);
- if(c == EOF)
- c = '\'';
- c1 = escchar('\'', 0, 0);
- if(c1 != EOF) {
- yyerror("missing '");
- peekc = c1;
- }
- vv = c;
- yylval.vval = convvtox(vv, TUCHAR);
- if(yylval.vval != vv)
- yyerror("overflow in character constant: 0x%x", c);
- else
- if(c & 0x80){
- nearln = lineno;
- warn(Z, "sign-extended character constant");
- }
- yylval.vval = convvtox(vv, TCHAR);
- return LCONST;
-
- case '/':
- c1 = GETC();
- if(c1 == '*') {
- for(;;) {
- c = getr();
- while(c == '*') {
- c = getr();
- if(c == '/')
- goto l0;
- }
- if(c == EOF) {
- yyerror("eof in comment");
- errorexit();
- }
- }
- }
- if(c1 == '/') {
- for(;;) {
- c = getr();
- if(c == '\n')
- goto l0;
- if(c == EOF) {
- yyerror("eof in comment");
- errorexit();
- }
- }
- }
- if(c1 == '=')
- return LDVE;
- break;
-
- case '*':
- c1 = GETC();
- if(c1 == '=')
- return LMLE;
- break;
-
- case '%':
- c1 = GETC();
- if(c1 == '=')
- return LMDE;
- break;
-
- case '+':
- c1 = GETC();
- if(c1 == '+')
- return LPP;
- if(c1 == '=')
- return LPE;
- break;
-
- case '-':
- c1 = GETC();
- if(c1 == '-')
- return LMM;
- if(c1 == '=')
- return LME;
- if(c1 == '>')
- return LMG;
- break;
-
- case '>':
- c1 = GETC();
- if(c1 == '>') {
- c = LRSH;
- c1 = GETC();
- if(c1 == '=')
- return LRSHE;
- break;
- }
- if(c1 == '=')
- return LGE;
- break;
-
- case '<':
- c1 = GETC();
- if(c1 == '<') {
- c = LLSH;
- c1 = GETC();
- if(c1 == '=')
- return LLSHE;
- break;
- }
- if(c1 == '=')
- return LLE;
- break;
-
- case '=':
- c1 = GETC();
- if(c1 == '=')
- return LEQ;
- break;
-
- case '!':
- c1 = GETC();
- if(c1 == '=')
- return LNE;
- break;
-
- case '&':
- c1 = GETC();
- if(c1 == '&')
- return LANDAND;
- if(c1 == '=')
- return LANDE;
- break;
-
- case '|':
- c1 = GETC();
- if(c1 == '|')
- return LOROR;
- if(c1 == '=')
- return LORE;
- break;
-
- case '^':
- c1 = GETC();
- if(c1 == '=')
- return LXORE;
- break;
-
- default:
- return c;
- }
- peekc = c1;
- return c;
-
-talph:
- /*
- * cp is set to symb and some
- * prefix has been stored
- */
- for(;;) {
- if(c >= Runeself) {
- for(c1=0;;) {
- cp[c1++] = c;
- if(fullrune(cp, c1))
- break;
- c = GETC();
- }
- cp += c1;
- c = GETC();
- continue;
- }
- if(!isalnum(c) && c != '_')
- break;
- *cp++ = c;
- c = GETC();
- }
- *cp = 0;
- if(debug['L'])
- print("%L: %s\n", lineno, symb);
- peekc = c;
- s = lookup();
- if(s->macro) {
- newio();
- cp = ionext->b;
- macexpand(s, cp);
- pushio();
- ionext->link = iostack;
- iostack = ionext;
- fi.p = cp;
- fi.c = strlen(cp);
- if(peekc != IGN) {
- cp[fi.c++] = peekc;
- cp[fi.c] = 0;
- peekc = IGN;
- }
- goto l0;
- }
- yylval.sym = s;
- if(s->class == CTYPEDEF || s->class == CTYPESTR)
- return LTYPE;
- return s->lexical;
-
-tnum:
- c1 = 0;
- cp = symb;
- if(c != '0') {
- c1 |= Numdec;
- for(;;) {
- *cp++ = c;
- c = GETC();
- if(isdigit(c))
- continue;
- goto dc;
- }
- }
- *cp++ = c;
- c = GETC();
- if(c == 'x' || c == 'X')
- for(;;) {
- *cp++ = c;
- c = GETC();
- if(isdigit(c))
- continue;
- if(c >= 'a' && c <= 'f')
- continue;
- if(c >= 'A' && c <= 'F')
- continue;
- if(cp == symb+2)
- yyerror("malformed hex constant");
- goto ncu;
- }
- if(c < '0' || c > '7')
- goto dc;
- for(;;) {
- if(c >= '0' && c <= '7') {
- *cp++ = c;
- c = GETC();
- continue;
- }
- goto ncu;
- }
-
-dc:
- if(c == '.')
- goto casedot;
- if(c == 'e' || c == 'E')
- goto casee;
-
-ncu:
- if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
- c = GETC();
- c1 |= Numuns;
- goto ncu;
- }
- if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
- c = GETC();
- if(c1 & Numlong)
- c1 |= Numvlong;
- c1 |= Numlong;
- goto ncu;
- }
- *cp = 0;
- peekc = c;
- if(mpatov(symb, &yylval.vval))
- yyerror("overflow in constant");
-
- vv = yylval.vval;
- if(c1 & Numvlong) {
- if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
- c = LUVLCONST;
- t = TUVLONG;
- goto nret;
- }
- c = LVLCONST;
- t = TVLONG;
- goto nret;
- }
- if(c1 & Numlong) {
- if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
- c = LULCONST;
- t = TULONG;
- goto nret;
- }
- c = LLCONST;
- t = TLONG;
- goto nret;
- }
- if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
- c = LUCONST;
- t = TUINT;
- goto nret;
- }
- c = LCONST;
- t = TINT;
- goto nret;
-
-nret:
- yylval.vval = convvtox(vv, t);
- if(yylval.vval != vv){
- nearln = lineno;
- warn(Z, "truncated constant: %T %s", types[t], symb);
- }
- return c;
-
-casedot:
- for(;;) {
- *cp++ = c;
- c = GETC();
- if(!isdigit(c))
- break;
- }
- if(c != 'e' && c != 'E')
- goto caseout;
-
-casee:
- *cp++ = 'e';
- c = GETC();
- if(c == '+' || c == '-') {
- *cp++ = c;
- c = GETC();
- }
- if(!isdigit(c))
- yyerror("malformed fp constant exponent");
- while(isdigit(c)) {
- *cp++ = c;
- c = GETC();
- }
-
-caseout:
- if(c == 'L' || c == 'l') {
- c = GETC();
- c1 |= Numlong;
- } else
- if(c == 'F' || c == 'f') {
- c = GETC();
- c1 |= Numflt;
- }
- *cp = 0;
- peekc = c;
- yylval.dval = strtod(symb, nil);
- if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
- yyerror("overflow in float constant");
- yylval.dval = 0;
- }
- if(c1 & Numflt)
- return LFCONST;
- return LDCONST;
-}
-
-/*
- * convert a string, s, to vlong in *v
- * return conversion overflow.
- * required syntax is [0[x]]d*
- */
-int
-mpatov(char *s, vlong *v)
-{
- vlong n, nn;
- int c;
-
- n = 0;
- c = *s;
- if(c == '0')
- goto oct;
- while(c = *s++) {
- if(c >= '0' && c <= '9')
- nn = n*10 + c-'0';
- else
- goto bad;
- if(n < 0 && nn >= 0)
- goto bad;
- n = nn;
- }
- goto out;
-
-oct:
- s++;
- c = *s;
- if(c == 'x' || c == 'X')
- goto hex;
- while(c = *s++) {
- if(c >= '0' || c <= '7')
- nn = n*8 + c-'0';
- else
- goto bad;
- if(n < 0 && nn >= 0)
- goto bad;
- n = nn;
- }
- goto out;
-
-hex:
- s++;
- while(c = *s++) {
- if(c >= '0' && c <= '9')
- c += 0-'0';
- else
- if(c >= 'a' && c <= 'f')
- c += 10-'a';
- else
- if(c >= 'A' && c <= 'F')
- c += 10-'A';
- else
- goto bad;
- nn = (uvlong)n*16 + c;
- if(n < 0 && nn >= 0)
- goto bad;
- n = nn;
- }
-out:
- *v = n;
- return 0;
-
-bad:
- *v = ~0;
- return 1;
-}
-
-int
-getc(void)
-{
- int c;
-
- if(peekc != IGN) {
- c = peekc;
- peekc = IGN;
- } else
- c = GETC();
- if(c == '\n')
- lineno++;
- if(c == EOF) {
- yyerror("End of file");
- errorexit();
- }
- return c;
-}
-
-int32
-getr(void)
-{
- int c, i;
- char str[UTFmax+1];
- Rune rune;
-
-
- c = getc();
- if(c < Runeself)
- return c;
- i = 0;
- str[i++] = c;
-
-loop:
- c = getc();
- str[i++] = c;
- if(!fullrune(str, i))
- goto loop;
- c = chartorune(&rune, str);
- if(rune == Runeerror && c == 1) {
- nearln = lineno;
- diag(Z, "illegal rune in string");
- for(c=0; c<i; c++)
- print(" %.2x", *(uchar*)(str+c));
- print("\n");
- }
- return rune;
-}
-
-int
-getnsc(void)
-{
- int c;
-
- if(peekc != IGN) {
- c = peekc;
- peekc = IGN;
- } else
- c = GETC();
- for(;;) {
- if(c >= Runeself || !isspace(c))
- return c;
- if(c == '\n') {
- lineno++;
- return c;
- }
- c = GETC();
- }
-}
-
-void
-unget(int c)
-{
-
- peekc = c;
- if(c == '\n')
- lineno--;
-}
-
-int32
-escchar(int32 e, int longflg, int escflg)
-{
- int32 c, l;
- int i;
-
-loop:
- c = getr();
- if(c == '\n') {
- yyerror("newline in string");
- return EOF;
- }
- if(c != '\\') {
- if(c == e)
- c = EOF;
- return c;
- }
- c = getr();
- if(c == 'x') {
- /*
- * note this is not ansi,
- * supposed to only accept 2 hex
- */
- i = 2;
- if(longflg)
- i = 6;
- l = 0;
- for(; i>0; i--) {
- c = getc();
- if(c >= '0' && c <= '9') {
- l = l*16 + c-'0';
- continue;
- }
- if(c >= 'a' && c <= 'f') {
- l = l*16 + c-'a' + 10;
- continue;
- }
- if(c >= 'A' && c <= 'F') {
- l = l*16 + c-'A' + 10;
- continue;
- }
- unget(c);
- break;
- }
- if(escflg)
- l |= ESC;
- return l;
- }
- if(c >= '0' && c <= '7') {
- /*
- * note this is not ansi,
- * supposed to only accept 3 oct
- */
- i = 2;
- if(longflg)
- i = 8;
- l = c - '0';
- for(; i>0; i--) {
- c = getc();
- if(c >= '0' && c <= '7') {
- l = l*8 + c-'0';
- continue;
- }
- unget(c);
- }
- if(escflg)
- l |= ESC;
- return l;
- }
- switch(c)
- {
- case '\n': goto loop;
- case 'n': return '\n';
- case 't': return '\t';
- case 'b': return '\b';
- case 'r': return '\r';
- case 'f': return '\f';
- case 'a': return '\a';
- case 'v': return '\v';
- }
- return c;
-}
-
-struct
-{
- char *name;
- ushort lexical;
- ushort type;
-} itab[] =
-{
- "auto", LAUTO, 0,
- "break", LBREAK, 0,
- "case", LCASE, 0,
- "char", LCHAR, TCHAR,
- "const", LCONSTNT, 0,
- "continue", LCONTINUE, 0,
- "default", LDEFAULT, 0,
- "do", LDO, 0,
- "double", LDOUBLE, TDOUBLE,
- "else", LELSE, 0,
- "enum", LENUM, 0,
- "extern", LEXTERN, 0,
- "float", LFLOAT, TFLOAT,
- "for", LFOR, 0,
- "goto", LGOTO, 0,
- "if", LIF, 0,
- "inline", LINLINE, 0,
- "int", LINT, TINT,
- "long", LLONG, TLONG,
- "PREFETCH", LPREFETCH, 0,
- "register", LREGISTER, 0,
- "restrict", LRESTRICT, 0,
- "return", LRETURN, 0,
- "SET", LSET, 0,
- "short", LSHORT, TSHORT,
- "signed", LSIGNED, 0,
- "signof", LSIGNOF, 0,
- "sizeof", LSIZEOF, 0,
- "static", LSTATIC, 0,
- "struct", LSTRUCT, 0,
- "switch", LSWITCH, 0,
- "typedef", LTYPEDEF, 0,
- "typestr", LTYPESTR, 0,
- "union", LUNION, 0,
- "unsigned", LUNSIGNED, 0,
- "USED", LUSED, 0,
- "void", LVOID, TVOID,
- "volatile", LVOLATILE, 0,
- "while", LWHILE, 0,
- 0
-};
-
-void
-cinit(void)
-{
- Sym *s;
- int i;
- Type *t;
-
- nerrors = 0;
- lineno = 1;
- iostack = I;
- iofree = I;
- peekc = IGN;
- nhunk = 0;
-
- types[TXXX] = T;
- types[TCHAR] = typ(TCHAR, T);
- types[TUCHAR] = typ(TUCHAR, T);
- types[TSHORT] = typ(TSHORT, T);
- types[TUSHORT] = typ(TUSHORT, T);
- types[TINT] = typ(TINT, T);
- types[TUINT] = typ(TUINT, T);
- types[TLONG] = typ(TLONG, T);
- types[TULONG] = typ(TULONG, T);
- types[TVLONG] = typ(TVLONG, T);
- types[TUVLONG] = typ(TUVLONG, T);
- types[TFLOAT] = typ(TFLOAT, T);
- types[TDOUBLE] = typ(TDOUBLE, T);
- types[TVOID] = typ(TVOID, T);
- types[TENUM] = typ(TENUM, T);
- types[TFUNC] = typ(TFUNC, types[TINT]);
- types[TIND] = typ(TIND, types[TVOID]);
-
- for(i=0; i<NHASH; i++)
- hash[i] = S;
- for(i=0; itab[i].name; i++) {
- s = slookup(itab[i].name);
- s->lexical = itab[i].lexical;
- if(itab[i].type != 0)
- s->type = types[itab[i].type];
- }
- blockno = 0;
- autobn = 0;
- autoffset = 0;
-
- t = typ(TARRAY, types[TCHAR]);
- t->width = 0;
- symstring = slookup(".string");
- symstring->class = CSTATIC;
- symstring->dataflag = NOPTR;
- symstring->type = t;
-
- t = typ(TARRAY, types[TCHAR]);
- t->width = 0;
-
- nodproto = new(OPROTO, Z, Z);
- dclstack = D;
-
- fmtinstall('O', Oconv);
- fmtinstall('T', Tconv);
- fmtinstall('F', FNconv);
- fmtinstall('L', Lconv);
- fmtinstall('Q', Qconv);
- fmtinstall('|', VBconv);
- fmtinstall('U', Uconv);
- fmtinstall('B', Bconv);
-}
-
-int
-filbuf(void)
-{
- Io *i;
-
-loop:
- i = iostack;
- if(i == I)
- return EOF;
- if(i->f < 0)
- goto pop;
- fi.c = read(i->f, i->b, BUFSIZ) - 1;
- if(fi.c < 0) {
- close(i->f);
- linklinehist(ctxt, lineno, nil, 0);
- goto pop;
- }
- fi.p = i->b + 1;
- return i->b[0] & 0xff;
-
-pop:
- iostack = i->link;
- i->link = iofree;
- iofree = i;
- i = iostack;
- if(i == I)
- return EOF;
- fi.p = i->p;
- fi.c = i->c;
- if(--fi.c < 0)
- goto loop;
- return *fi.p++ & 0xff;
-}
-
-int
-Oconv(Fmt *fp)
-{
- int a;
-
- a = va_arg(fp->args, int);
- if(a < OXXX || a > OEND)
- return fmtprint(fp, "***badO %d***", a);
-
- return fmtstrcpy(fp, onames[a]);
-}
-
-int
-Lconv(Fmt *fp)
-{
- return linklinefmt(ctxt, fp);
-}
-
-int
-Tconv(Fmt *fp)
-{
- char str[STRINGSZ+20], s[STRINGSZ+20];
- Type *t, *t1;
- int et;
- int32 n;
-
- str[0] = 0;
- for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
- et = t->etype;
- if(str[0])
- strcat(str, " ");
- if(t->garb&~GINCOMPLETE) {
- sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
- if(strlen(str) + strlen(s) < STRINGSZ)
- strcat(str, s);
- }
- sprint(s, "%s", tnames[et]);
- if(strlen(str) + strlen(s) < STRINGSZ)
- strcat(str, s);
- if(et == TFUNC && (t1 = t->down)) {
- sprint(s, "(%T", t1);
- if(strlen(str) + strlen(s) < STRINGSZ)
- strcat(str, s);
- while(t1 = t1->down) {
- sprint(s, ", %T", t1);
- if(strlen(str) + strlen(s) < STRINGSZ)
- strcat(str, s);
- }
- if(strlen(str) + strlen(s) < STRINGSZ)
- strcat(str, ")");
- }
- if(et == TARRAY) {
- n = t->width;
- if(t->link && t->link->width)
- n /= t->link->width;
- sprint(s, "[%d]", n);
- if(strlen(str) + strlen(s) < STRINGSZ)
- strcat(str, s);
- }
- if(t->nbits) {
- sprint(s, " %d:%d", t->shift, t->nbits);
- if(strlen(str) + strlen(s) < STRINGSZ)
- strcat(str, s);
- }
- if(typesu[et]) {
- if(t->tag) {
- strcat(str, " ");
- if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
- strcat(str, t->tag->name);
- } else
- strcat(str, " {}");
- break;
- }
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-FNconv(Fmt *fp)
-{
- char *str;
- Node *n;
-
- n = va_arg(fp->args, Node*);
- str = "<indirect>";
- if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
- str = n->sym->name;
- return fmtstrcpy(fp, str);
-}
-
-int
-Qconv(Fmt *fp)
-{
- char str[STRINGSZ+20], *s;
- int32 b;
- int i;
-
- str[0] = 0;
- for(b = va_arg(fp->args, int32); b;) {
- i = bitno(b);
- if(str[0])
- strcat(str, " ");
- s = qnames[i];
- if(strlen(str) + strlen(s) >= STRINGSZ)
- break;
- strcat(str, s);
- b &= ~(1L << i);
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-VBconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int i, n, t, pc;
-
- n = va_arg(fp->args, int);
- pc = 0; /* BUG: was printcol */
- i = 0;
- while(pc < n) {
- t = (pc+4) & ~3;
- if(t <= n) {
- str[i++] = '\t';
- pc = t;
- continue;
- }
- str[i++] = ' ';
- pc++;
- }
- str[i] = 0;
-
- return fmtstrcpy(fp, str);
-}
-
-int
-Bconv(Fmt *fp)
-{
- char str[STRINGSZ], ss[STRINGSZ], *s;
- Bits bits;
- int i;
-
- str[0] = 0;
- bits = va_arg(fp->args, Bits);
- while(bany(&bits)) {
- i = bnum(bits);
- if(str[0])
- strcat(str, " ");
- if(var[i].sym == nil) {
- sprint(ss, "$%lld", var[i].offset);
- s = ss;
- } else
- s = var[i].sym->name;
- if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
- break;
- strcat(str, s);
- bits.b[i/32] &= ~(1L << (i%32));
- }
- return fmtstrcpy(fp, str);
-}
-
-void
-setinclude(char *p)
-{
- int i;
-
- if(*p != 0) {
- for(i=1; i < ninclude; i++)
- if(strcmp(p, include[i]) == 0)
- return;
-
- if(ninclude%8 == 0)
- include = allocn(include, ninclude*sizeof(char *),
- 8*sizeof(char *));
- include[ninclude++] = p;
- }
-}
-
-void*
-alloc(int32 n)
-{
- void *p;
-
- p = malloc(n);
- if(p == nil) {
- print("alloc out of mem\n");
- exits("alloc: out of mem");
- }
- memset(p, 0, n);
- return p;
-}
-
-void*
-allocn(void *p, int32 n, int32 d)
-{
- if(p == nil)
- return alloc(n+d);
- p = realloc(p, n+d);
- if(p == nil) {
- print("allocn out of mem\n");
- exits("allocn: out of mem");
- }
- if(d > 0)
- memset((char*)p+n, 0, d);
- return p;
-}
-
-void
-ensuresymb(int32 n)
-{
- if(symb == nil) {
- symb = alloc(NSYMB+1);
- nsymb = NSYMB;
- }
-
- if(n > nsymb) {
- symb = allocn(symb, nsymb, n+1-nsymb);
- nsymb = n;
- }
-}
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
index e24db1bc0..f586aaa20 100644
--- a/src/cmd/cc/lexbody
+++ b/src/cmd/cc/lexbody
@@ -220,6 +220,31 @@ slookup(char *s)
return lookup();
}
+LSym *thetext;
+
+void
+settext(LSym *s)
+{
+ thetext = s;
+}
+
+Sym*
+labellookup(Sym *s)
+{
+ char *p;
+ Sym *lab;
+
+ if(thetext == nil) {
+ s->labelname = s->name;
+ return s;
+ }
+ p = smprint("%s.%s", thetext->name, s->name);
+ lab = slookup(p);
+ free(p);
+ lab->labelname = s->name;
+ return lab;
+}
+
Sym*
lookup(void)
{
diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c
deleted file mode 100644
index b969662ae..000000000
--- a/src/cmd/cc/mac.c
+++ /dev/null
@@ -1,34 +0,0 @@
-// Inferno utils/cc/mac.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/mac.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-
-#include "macbody"
diff --git a/src/cmd/cc/omachcap.c b/src/cmd/cc/omachcap.c
deleted file mode 100644
index f8fc1d88b..000000000
--- a/src/cmd/cc/omachcap.c
+++ /dev/null
@@ -1,40 +0,0 @@
-// Inferno utils/cc/machcap.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/machcap.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-
-/* default, like old cc */
-int
-machcap(Node *n)
-{
- USED(n);
- return 0;
-}
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
deleted file mode 100644
index db9aae916..000000000
--- a/src/cmd/cc/pgen.c
+++ /dev/null
@@ -1,622 +0,0 @@
-// Inferno utils/6c/sgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-int
-hasdotdotdot(Type *t)
-{
- for(t=t->down; t!=T; t=t->down)
- if(t->etype == TDOT)
- return 1;
- return 0;
-}
-
-vlong
-argsize(int doret)
-{
- Type *t;
- int32 s;
-
-//print("t=%T\n", thisfn);
- s = 0;
- if(hasdotdotdot(thisfn))
- s = align(s, thisfn->link, Aarg0, nil);
- for(t=thisfn->down; t!=T; t=t->down) {
- switch(t->etype) {
- case TVOID:
- break;
- case TDOT:
- if((textflag & NOSPLIT) == 0)
- yyerror("function takes ... without textflag NOSPLIT");
- return ArgsSizeUnknown;
- default:
- s = align(s, t, Aarg1, nil);
- s = align(s, t, Aarg2, nil);
- break;
- }
-//print(" %d %T\n", s, t);
- }
- if(thechar == '6')
- s = (s+7) & ~7;
- else
- s = (s+3) & ~3;
- if(doret && thisfn->link->etype != TVOID) {
- s = align(s, thisfn->link, Aarg1, nil);
- s = align(s, thisfn->link, Aarg2, nil);
- if(thechar == '6')
- s = (s+7) & ~7;
- else
- s = (s+3) & ~3;
- }
- return s;
-}
-
-void
-codgen(Node *n, Node *nn)
-{
- Prog *sp;
- Node *n1, nod, nod1;
-
- cursafe = 0;
- curarg = 0;
- maxargsafe = 0;
-
- /*
- * isolate name
- */
- for(n1 = nn;; n1 = n1->left) {
- if(n1 == Z) {
- diag(nn, "can't find function name");
- return;
- }
- if(n1->op == ONAME)
- break;
- }
- nearln = nn->lineno;
-
- p = gtext(n1->sym, stkoff);
- p->from.sym->cfunc = 1;
- sp = p;
-
- /*
- * isolate first argument
- */
- if(REGARG >= 0) {
- if(typesuv[thisfn->link->etype]) {
- nod1 = *nodret->left;
- nodreg(&nod, &nod1, REGARG);
- gmove(&nod, &nod1);
- } else
- if(firstarg && typechlp[firstargtype->etype]) {
- nod1 = *nodret->left;
- nod1.sym = firstarg;
- nod1.type = firstargtype;
- nod1.xoffset = align(0, firstargtype, Aarg1, nil);
- nod1.etype = firstargtype->etype;
- nodreg(&nod, &nod1, REGARG);
- gmove(&nod, &nod1);
- }
- }
-
- canreach = 1;
- warnreach = 1;
- gen(n);
- if(canreach && thisfn->link->etype != TVOID)
- diag(Z, "no return at end of function: %s", n1->sym->name);
- noretval(3);
- gbranch(ORETURN);
-
- if(!debug['N'] || debug['R'] || debug['P'])
- regopt(sp);
-
- if(thechar=='6' || thechar=='7') /* [sic] */
- maxargsafe = xround(maxargsafe, 8);
- sp->to.offset += maxargsafe;
-}
-
-void
-supgen(Node *n)
-{
- int owarn;
- long spc;
- Prog *sp;
-
- if(n == Z)
- return;
- suppress++;
- owarn = warnreach;
- warnreach = 0;
- spc = pc;
- sp = lastp;
- gen(n);
- lastp = sp;
- pc = spc;
- sp->link = nil;
- suppress--;
- warnreach = owarn;
-}
-
-void
-gen(Node *n)
-{
- Node *l, nod, nod1;
- Prog *sp, *spc, *spb;
- Case *cn;
- long sbc, scc;
- int snbreak, sncontin;
- int f, o, oldreach;
-
-loop:
- if(n == Z)
- return;
- nearln = n->lineno;
- o = n->op;
- if(debug['G'])
- if(o != OLIST)
- print("%L %O\n", nearln, o);
-
- if(!canreach) {
- switch(o) {
- case OLABEL:
- case OCASE:
- case OLIST:
- case OBREAK:
- case OFOR:
- case OWHILE:
- case ODWHILE:
- /* all handled specially - see switch body below */
- break;
- default:
- if(warnreach) {
- warn(n, "unreachable code %O", o);
- warnreach = 0;
- }
- }
- }
-
- switch(o) {
-
- default:
- complex(n);
- cgen(n, Z);
- break;
-
- case OLIST:
- gen(n->left);
-
- rloop:
- n = n->right;
- goto loop;
-
- case ORETURN:
- canreach = 0;
- warnreach = !suppress;
- complex(n);
- if(n->type == T)
- break;
- l = n->left;
- if(l == Z) {
- noretval(3);
- gbranch(ORETURN);
- break;
- }
- if(typecmplx[n->type->etype] && !hasdotdotdot(thisfn)) {
- regret(&nod, n, thisfn, 2);
- sugen(l, &nod, n->type->width);
- noretval(3);
- gbranch(ORETURN);
- break;
- }
- if(typecmplx[n->type->etype]) {
- sugen(l, nodret, n->type->width);
- noretval(3);
- gbranch(ORETURN);
- break;
- }
- regret(&nod1, n, thisfn, 2);
- nod = nod1;
- if(nod.op != OREGISTER)
- regalloc(&nod, n, Z);
- cgen(l, &nod);
- if(nod1.op != OREGISTER)
- gmove(&nod, &nod1);
- regfree(&nod);
- if(typefd[n->type->etype])
- noretval(1);
- else
- noretval(2);
- gbranch(ORETURN);
- break;
-
- case OLABEL:
- canreach = 1;
- l = n->left;
- if(l) {
- l->pc = pc;
- if(l->label)
- patch(l->label, pc);
- }
- gbranch(OGOTO); /* prevent self reference in reg */
- patch(p, pc);
- goto rloop;
-
- case OGOTO:
- canreach = 0;
- warnreach = !suppress;
- n = n->left;
- if(n == Z)
- return;
- if(n->complex == 0) {
- diag(Z, "label undefined: %s", n->sym->name);
- return;
- }
- if(suppress)
- return;
- gbranch(OGOTO);
- if(n->pc) {
- patch(p, n->pc);
- return;
- }
- if(n->label)
- patch(n->label, pc-1);
- n->label = p;
- return;
-
- case OCASE:
- canreach = 1;
- l = n->left;
- if(cases == C)
- diag(n, "case/default outside a switch");
- if(l == Z) {
- newcase();
- cases->val = 0;
- cases->def = 1;
- cases->label = pc;
- cases->isv = 0;
- goto rloop;
- }
- complex(l);
- if(l->type == T)
- goto rloop;
- if(l->op == OCONST)
- if(typeword[l->type->etype] && l->type->etype != TIND) {
- newcase();
- cases->val = l->vconst;
- cases->def = 0;
- cases->label = pc;
- cases->isv = typev[l->type->etype];
- goto rloop;
- }
- diag(n, "case expression must be integer constant");
- goto rloop;
-
- case OSWITCH:
- l = n->left;
- complex(l);
- if(l->type == T)
- break;
- if(!typechlvp[l->type->etype] || l->type->etype == TIND) {
- diag(n, "switch expression must be integer");
- break;
- }
-
- gbranch(OGOTO); /* entry */
- sp = p;
-
- cn = cases;
- cases = C;
- newcase();
-
- sbc = breakpc;
- breakpc = pc;
- snbreak = nbreak;
- nbreak = 0;
- gbranch(OGOTO);
- spb = p;
-
- gen(n->right); /* body */
- if(canreach){
- gbranch(OGOTO);
- patch(p, breakpc);
- nbreak++;
- }
-
- patch(sp, pc);
- doswit(l);
- patch(spb, pc);
-
- cases = cn;
- breakpc = sbc;
- canreach = nbreak!=0;
- if(canreach == 0)
- warnreach = !suppress;
- nbreak = snbreak;
- break;
-
- case OWHILE:
- case ODWHILE:
- l = n->left;
- gbranch(OGOTO); /* entry */
- sp = p;
-
- scc = continpc;
- continpc = pc;
- gbranch(OGOTO);
- spc = p;
-
- sbc = breakpc;
- breakpc = pc;
- snbreak = nbreak;
- nbreak = 0;
- gbranch(OGOTO);
- spb = p;
-
- patch(spc, pc);
- if(n->op == OWHILE)
- patch(sp, pc);
- bcomplex(l, Z); /* test */
- patch(p, breakpc);
- if(l->op != OCONST || vconst(l) == 0)
- nbreak++;
-
- if(n->op == ODWHILE)
- patch(sp, pc);
- gen(n->right); /* body */
- gbranch(OGOTO);
- patch(p, continpc);
-
- patch(spb, pc);
- continpc = scc;
- breakpc = sbc;
- canreach = nbreak!=0;
- if(canreach == 0)
- warnreach = !suppress;
- nbreak = snbreak;
- break;
-
- case OFOR:
- l = n->left;
- if(!canreach && l->right->left && warnreach) {
- warn(n, "unreachable code FOR");
- warnreach = 0;
- }
- gen(l->right->left); /* init */
- gbranch(OGOTO); /* entry */
- sp = p;
-
- /*
- * if there are no incoming labels in the
- * body and the top's not reachable, warn
- */
- if(!canreach && warnreach && deadheads(n)) {
- warn(n, "unreachable code %O", o);
- warnreach = 0;
- }
-
- scc = continpc;
- continpc = pc;
- gbranch(OGOTO);
- spc = p;
-
- sbc = breakpc;
- breakpc = pc;
- snbreak = nbreak;
- nbreak = 0;
- sncontin = ncontin;
- ncontin = 0;
- gbranch(OGOTO);
- spb = p;
-
- patch(spc, pc);
- gen(l->right->right); /* inc */
- patch(sp, pc);
- if(l->left != Z) { /* test */
- bcomplex(l->left, Z);
- patch(p, breakpc);
- if(l->left->op != OCONST || vconst(l->left) == 0)
- nbreak++;
- }
- canreach = 1;
- gen(n->right); /* body */
- if(canreach){
- gbranch(OGOTO);
- patch(p, continpc);
- ncontin++;
- }
- if(!ncontin && l->right->right && warnreach) {
- warn(l->right->right, "unreachable FOR inc");
- warnreach = 0;
- }
-
- patch(spb, pc);
- continpc = scc;
- breakpc = sbc;
- canreach = nbreak!=0;
- if(canreach == 0)
- warnreach = !suppress;
- nbreak = snbreak;
- ncontin = sncontin;
- break;
-
- case OCONTINUE:
- if(continpc < 0) {
- diag(n, "continue not in a loop");
- break;
- }
- gbranch(OGOTO);
- patch(p, continpc);
- ncontin++;
- canreach = 0;
- warnreach = !suppress;
- break;
-
- case OBREAK:
- if(breakpc < 0) {
- diag(n, "break not in a loop");
- break;
- }
- /*
- * Don't complain about unreachable break statements.
- * There are breaks hidden in yacc's output and some people
- * write return; break; in their switch statements out of habit.
- * However, don't confuse the analysis by inserting an
- * unreachable reference to breakpc either.
- */
- if(!canreach)
- break;
- gbranch(OGOTO);
- patch(p, breakpc);
- nbreak++;
- canreach = 0;
- warnreach = !suppress;
- break;
-
- case OIF:
- l = n->left;
- if(bcomplex(l, n->right)) {
- if(typefd[l->type->etype])
- f = !l->fconst;
- else
- f = !l->vconst;
- if(debug['c'])
- print("%L const if %s\n", nearln, f ? "false" : "true");
- if(f) {
- canreach = 1;
- supgen(n->right->left);
- oldreach = canreach;
- canreach = 1;
- gen(n->right->right);
- /*
- * treat constant ifs as regular ifs for
- * reachability warnings.
- */
- if(!canreach && oldreach && debug['w'] < 2)
- warnreach = 0;
- }
- else {
- canreach = 1;
- gen(n->right->left);
- oldreach = canreach;
- canreach = 1;
- supgen(n->right->right);
- /*
- * treat constant ifs as regular ifs for
- * reachability warnings.
- */
- if(!oldreach && canreach && debug['w'] < 2)
- warnreach = 0;
- canreach = oldreach;
- }
- }
- else {
- sp = p;
- canreach = 1;
- if(n->right->left != Z)
- gen(n->right->left);
- oldreach = canreach;
- canreach = 1;
- if(n->right->right != Z) {
- gbranch(OGOTO);
- patch(sp, pc);
- sp = p;
- gen(n->right->right);
- }
- patch(sp, pc);
- canreach = canreach || oldreach;
- if(canreach == 0)
- warnreach = !suppress;
- }
- break;
-
- case OSET:
- case OUSED:
- case OPREFETCH:
- usedset(n->left, o);
- break;
- }
-}
-
-void
-usedset(Node *n, int o)
-{
- if(n->op == OLIST) {
- usedset(n->left, o);
- usedset(n->right, o);
- return;
- }
- complex(n);
- if(o == OPREFETCH) {
- gprefetch(n);
- return;
- }
- switch(n->op) {
- case OADDR: /* volatile */
- gins(ANOP, n, Z);
- break;
- case ONAME:
- if(o == OSET)
- gins(ANOP, Z, n);
- else
- gins(ANOP, n, Z);
- break;
- }
-}
-
-int
-bcomplex(Node *n, Node *c)
-{
- Node *b, nod;
-
- complex(n);
- if(n->type != T)
- if(tcompat(n, T, n->type, tnot))
- n->type = T;
- if(n->type == T) {
- gbranch(OGOTO);
- return 0;
- }
- if(c != Z && n->op == OCONST && deadheads(c))
- return 1;
- if(typev[n->type->etype] && machcap(Z)) {
- b = &nod;
- b->op = ONE;
- b->left = n;
- b->right = new(0, Z, Z);
- *b->right = *nodconst(0);
- b->right->type = n->type;
- b->type = types[TLONG];
- n = b;
- }
- bool64(n);
- boolgen(n, 1, Z);
- return 0;
-}
diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c
deleted file mode 100644
index bae57c64d..000000000
--- a/src/cmd/cc/pswt.c
+++ /dev/null
@@ -1,140 +0,0 @@
-// Inferno utils/6c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-int
-swcmp(const void *a1, const void *a2)
-{
- C1 *p1, *p2;
-
- p1 = (C1*)a1;
- p2 = (C1*)a2;
- if(p1->val < p2->val)
- return -1;
- return p1->val > p2->val;
-}
-
-void
-doswit(Node *n)
-{
- Case *c;
- C1 *q, *iq;
- int32 def, nc, i, isv;
-
- def = 0;
- nc = 0;
- isv = 0;
- for(c = cases; c->link != C; c = c->link) {
- if(c->def) {
- if(def)
- diag(n, "more than one default in switch");
- def = c->label;
- continue;
- }
- isv |= c->isv;
- nc++;
- }
- if(isv && !typev[n->type->etype])
- warn(n, "32-bit switch expression with 64-bit case constant");
-
- iq = alloc(nc*sizeof(C1));
- q = iq;
- for(c = cases; c->link != C; c = c->link) {
- if(c->def)
- continue;
- q->label = c->label;
- if(isv)
- q->val = c->val;
- else
- q->val = (int32)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */
- q++;
- }
- qsort(iq, nc, sizeof(C1), swcmp);
- if(debug['W'])
- for(i=0; i<nc; i++)
- print("case %2d: = %.8llux\n", i, (vlong)iq[i].val);
- for(i=0; i<nc-1; i++)
- if(iq[i].val == iq[i+1].val)
- diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
- if(def == 0) {
- def = breakpc;
- nbreak++;
- }
- swit1(iq, nc, def, n);
-}
-
-void
-newcase(void)
-{
- Case *c;
-
- c = alloc(sizeof(*c));
- c->link = cases;
- cases = c;
-}
-
-int32
-outlstring(TRune *s, int32 n)
-{
- char buf[sizeof(TRune)];
- uint c;
- int i;
- int32 r;
-
- if(suppress)
- return nstring;
- while(nstring & (sizeof(TRune)-1))
- outstring("", 1);
- r = nstring;
- while(n > 0) {
- c = *s++;
- if(align(0, types[TCHAR], Aarg1, nil)) {
- for(i = 0; i < sizeof(TRune); i++)
- buf[i] = c>>(8*(sizeof(TRune) - i - 1));
- } else {
- for(i = 0; i < sizeof(TRune); i++)
- buf[i] = c>>(8*i);
- }
- outstring(buf, sizeof(TRune));
- n -= sizeof(TRune);
- }
- return r;
-}
-
-void
-nullwarn(Node *l, Node *r)
-{
- warn(Z, "result of operation not used");
- if(l != Z)
- cgen(l, Z);
- if(r != Z)
- cgen(r, Z);
-}
diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c
deleted file mode 100644
index b0b909759..000000000
--- a/src/cmd/cc/scon.c
+++ /dev/null
@@ -1,640 +0,0 @@
-// Inferno utils/cc/scon.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-
-static Node*
-acast(Type *t, Node *n)
-{
- if(n->type->etype != t->etype || n->op == OBIT) {
- n = new1(OCAST, n, Z);
- if(nocast(n->left->type, t))
- *n = *n->left;
- n->type = t;
- }
- return n;
-}
-
-
-void
-evconst(Node *n)
-{
- Node *l, *r;
- int et, isf;
- vlong v;
- double d;
-
- if(n == Z || n->type == T)
- return;
-
- et = n->type->etype;
- isf = typefd[et];
-
- l = n->left;
- r = n->right;
-
- d = 0;
- v = 0;
-
- switch(n->op) {
- default:
- return;
-
- case ONEG:
- if(isf)
- d = -l->fconst;
- else
- v = -l->vconst;
- break;
-
- case OCOM:
- v = ~l->vconst;
- break;
-
- case OCAST:
- if(et == TVOID)
- return;
- et = l->type->etype;
- if(isf) {
- if(typefd[et])
- d = l->fconst;
- else
- d = l->vconst;
- } else {
- if(typefd[et])
- v = l->fconst;
- else
- v = convvtox(l->vconst, n->type->etype);
- }
- break;
-
- case OCONST:
- break;
-
- case OADD:
- if(isf)
- d = l->fconst + r->fconst;
- else {
- v = l->vconst + r->vconst;
- }
- break;
-
- case OSUB:
- if(isf)
- d = l->fconst - r->fconst;
- else
- v = l->vconst - r->vconst;
- break;
-
- case OMUL:
- if(isf)
- d = l->fconst * r->fconst;
- else {
- v = l->vconst * r->vconst;
- }
- break;
-
- case OLMUL:
- v = (uvlong)l->vconst * (uvlong)r->vconst;
- break;
-
-
- case ODIV:
- if(vconst(r) == 0) {
- warn(n, "divide by zero");
- return;
- }
- if(isf)
- d = l->fconst / r->fconst;
- else
- v = l->vconst / r->vconst;
- break;
-
- case OLDIV:
- if(vconst(r) == 0) {
- warn(n, "divide by zero");
- return;
- }
- v = (uvlong)l->vconst / (uvlong)r->vconst;
- break;
-
- case OMOD:
- if(vconst(r) == 0) {
- warn(n, "modulo by zero");
- return;
- }
- v = l->vconst % r->vconst;
- break;
-
- case OLMOD:
- if(vconst(r) == 0) {
- warn(n, "modulo by zero");
- return;
- }
- v = (uvlong)l->vconst % (uvlong)r->vconst;
- break;
-
- case OAND:
- v = l->vconst & r->vconst;
- break;
-
- case OOR:
- v = l->vconst | r->vconst;
- break;
-
- case OXOR:
- v = l->vconst ^ r->vconst;
- break;
-
- case OLSHR:
- if(l->type->width != sizeof(uvlong))
- v = ((uvlong)l->vconst & 0xffffffffULL) >> r->vconst;
- else
- v = (uvlong)l->vconst >> r->vconst;
- break;
-
- case OASHR:
- v = l->vconst >> r->vconst;
- break;
-
- case OASHL:
- v = (uvlong)l->vconst << r->vconst;
- break;
-
- case OLO:
- v = (uvlong)l->vconst < (uvlong)r->vconst;
- break;
-
- case OLT:
- if(typefd[l->type->etype])
- v = l->fconst < r->fconst;
- else
- v = l->vconst < r->vconst;
- break;
-
- case OHI:
- v = (uvlong)l->vconst > (uvlong)r->vconst;
- break;
-
- case OGT:
- if(typefd[l->type->etype])
- v = l->fconst > r->fconst;
- else
- v = l->vconst > r->vconst;
- break;
-
- case OLS:
- v = (uvlong)l->vconst <= (uvlong)r->vconst;
- break;
-
- case OLE:
- if(typefd[l->type->etype])
- v = l->fconst <= r->fconst;
- else
- v = l->vconst <= r->vconst;
- break;
-
- case OHS:
- v = (uvlong)l->vconst >= (uvlong)r->vconst;
- break;
-
- case OGE:
- if(typefd[l->type->etype])
- v = l->fconst >= r->fconst;
- else
- v = l->vconst >= r->vconst;
- break;
-
- case OEQ:
- if(typefd[l->type->etype])
- v = l->fconst == r->fconst;
- else
- v = l->vconst == r->vconst;
- break;
-
- case ONE:
- if(typefd[l->type->etype])
- v = l->fconst != r->fconst;
- else
- v = l->vconst != r->vconst;
- break;
-
- case ONOT:
- if(typefd[l->type->etype])
- v = !l->fconst;
- else
- v = !l->vconst;
- break;
-
- case OANDAND:
- if(typefd[l->type->etype])
- v = l->fconst && r->fconst;
- else
- v = l->vconst && r->vconst;
- break;
-
- case OOROR:
- if(typefd[l->type->etype])
- v = l->fconst || r->fconst;
- else
- v = l->vconst || r->vconst;
- break;
- }
- if(isf) {
- n->fconst = d;
- } else {
- n->vconst = convvtox(v, n->type->etype);
- }
- n->oldop = n->op;
- n->op = OCONST;
-}
-
-void
-acom(Node *n)
-{
- Type *t;
- Node *l, *r;
- int i;
-
- switch(n->op)
- {
-
- case ONAME:
- case OCONST:
- case OSTRING:
- case OINDREG:
- case OREGISTER:
- return;
-
- case ONEG:
- l = n->left;
- if(addo(n) && addo(l))
- break;
- acom(l);
- return;
-
- case OADD:
- case OSUB:
- case OMUL:
- l = n->left;
- r = n->right;
- if(addo(n)) {
- if(addo(r))
- break;
- if(addo(l))
- break;
- }
- acom(l);
- acom(r);
- return;
-
- default:
- l = n->left;
- r = n->right;
- if(l != Z)
- acom(l);
- if(r != Z)
- acom(r);
- return;
- }
-
- /* bust terms out */
- t = n->type;
- term[0].mult = 0;
- term[0].node = Z;
- nterm = 1;
- acom1(1, n);
- if(debug['m'])
- for(i=0; i<nterm; i++) {
- print("%d %3lld ", i, term[i].mult);
- prtree1(term[i].node, 1, 0);
- }
- if(nterm < NTERM)
- acom2(n, t);
- n->type = t;
-}
-
-int
-acomcmp1(const void *a1, const void *a2)
-{
- vlong c1, c2;
- Term *t1, *t2;
-
- t1 = (Term*)a1;
- t2 = (Term*)a2;
- c1 = t1->mult;
- if(c1 < 0)
- c1 = -c1;
- c2 = t2->mult;
- if(c2 < 0)
- c2 = -c2;
- if(c1 > c2)
- return 1;
- if(c1 < c2)
- return -1;
- c1 = 1;
- if(t1->mult < 0)
- c1 = 0;
- c2 = 1;
- if(t2->mult < 0)
- c2 = 0;
- if(c2 -= c1)
- return c2;
- if(t2 > t1)
- return 1;
- return -1;
-}
-
-int
-acomcmp2(const void *a1, const void *a2)
-{
- vlong c1, c2;
- Term *t1, *t2;
-
- t1 = (Term*)a1;
- t2 = (Term*)a2;
- c1 = t1->mult;
- c2 = t2->mult;
- if(c1 > c2)
- return 1;
- if(c1 < c2)
- return -1;
- if(t2 > t1)
- return 1;
- return -1;
-}
-
-void
-acom2(Node *n, Type *t)
-{
- Node *l, *r;
- Term trm[NTERM];
- int et, nt, i, j;
- vlong c1, c2;
-
- /*
- * copy into automatic
- */
- c2 = 0;
- nt = nterm;
- for(i=0; i<nt; i++)
- trm[i] = term[i];
- /*
- * recur on subtrees
- */
- j = 0;
- for(i=1; i<nt; i++) {
- c1 = trm[i].mult;
- if(c1 == 0)
- continue;
- l = trm[i].node;
- if(l != Z) {
- j = 1;
- acom(l);
- }
- }
- c1 = trm[0].mult;
- if(j == 0) {
- n->oldop = n->op;
- n->op = OCONST;
- n->vconst = c1;
- return;
- }
- et = t->etype;
-
- /*
- * prepare constant term,
- * combine it with an addressing term
- */
- if(c1 != 0) {
- l = new1(OCONST, Z, Z);
- l->type = t;
- l->vconst = c1;
- trm[0].mult = 1;
- for(i=1; i<nt; i++) {
- if(trm[i].mult != 1)
- continue;
- r = trm[i].node;
- if(r->op != OADDR)
- continue;
- r->type = t;
- l = new1(OADD, r, l);
- l->type = t;
- trm[i].mult = 0;
- break;
- }
- trm[0].node = l;
- }
- /*
- * look for factorable terms
- * c1*i + c1*c2*j -> c1*(i + c2*j)
- */
- qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1);
- for(i=nt-1; i>=0; i--) {
- c1 = trm[i].mult;
- if(c1 < 0)
- c1 = -c1;
- if(c1 <= 1)
- continue;
- for(j=i+1; j<nt; j++) {
- c2 = trm[j].mult;
- if(c2 < 0)
- c2 = -c2;
- if(c2 <= 1)
- continue;
- if(c2 % c1)
- continue;
- r = trm[j].node;
- if(r->type->etype != et)
- r = acast(t, r);
- c2 = trm[j].mult/trm[i].mult;
- if(c2 != 1 && c2 != -1) {
- r = new1(OMUL, r, new(OCONST, Z, Z));
- r->type = t;
- r->right->type = t;
- r->right->vconst = c2;
- }
- l = trm[i].node;
- if(l->type->etype != et)
- l = acast(t, l);
- r = new1(OADD, l, r);
- r->type = t;
- if(c2 == -1)
- r->op = OSUB;
- trm[i].node = r;
- trm[j].mult = 0;
- }
- }
- if(debug['m']) {
- print("\n");
- for(i=0; i<nt; i++) {
- print("%d %3lld ", i, trm[i].mult);
- prtree1(trm[i].node, 1, 0);
- }
- }
-
- /*
- * put it all back together
- */
- qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2);
- l = Z;
- for(i=nt-1; i>=0; i--) {
- c1 = trm[i].mult;
- if(c1 == 0)
- continue;
- r = trm[i].node;
- if(r->type->etype != et || r->op == OBIT)
- r = acast(t, r);
- if(c1 != 1 && c1 != -1) {
- r = new1(OMUL, r, new(OCONST, Z, Z));
- r->type = t;
- r->right->type = t;
- if(c1 < 0) {
- r->right->vconst = -c1;
- c1 = -1;
- } else {
- r->right->vconst = c1;
- c1 = 1;
- }
- }
- if(l == Z) {
- l = r;
- c2 = c1;
- continue;
- }
- if(c1 < 0)
- if(c2 < 0)
- l = new1(OADD, l, r);
- else
- l = new1(OSUB, l, r);
- else
- if(c2 < 0) {
- l = new1(OSUB, r, l);
- c2 = 1;
- } else
- l = new1(OADD, l, r);
- l->type = t;
- }
- if(c2 < 0) {
- r = new1(OCONST, 0, 0);
- r->vconst = 0;
- r->type = t;
- l = new1(OSUB, r, l);
- l->type = t;
- }
- *n = *l;
-}
-
-void
-acom1(vlong v, Node *n)
-{
- Node *l, *r;
-
- if(v == 0 || nterm >= NTERM)
- return;
- if(!addo(n)) {
- if(n->op == OCONST)
- if(!typefd[n->type->etype]) {
- term[0].mult += v*n->vconst;
- return;
- }
- term[nterm].mult = v;
- term[nterm].node = n;
- nterm++;
- return;
- }
- switch(n->op) {
-
- case OCAST:
- acom1(v, n->left);
- break;
-
- case ONEG:
- acom1(-v, n->left);
- break;
-
- case OADD:
- acom1(v, n->left);
- acom1(v, n->right);
- break;
-
- case OSUB:
- acom1(v, n->left);
- acom1(-v, n->right);
- break;
-
- case OMUL:
- l = n->left;
- r = n->right;
- if(l->op == OCONST)
- if(!typefd[n->type->etype]) {
- acom1(v*l->vconst, r);
- break;
- }
- if(r->op == OCONST)
- if(!typefd[n->type->etype]) {
- acom1(v*r->vconst, l);
- break;
- }
- break;
-
- default:
- diag(n, "not addo");
- }
-}
-
-int
-addo(Node *n)
-{
-
- if(n != Z)
- if(!typefd[n->type->etype])
- if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND])
- switch(n->op) {
-
- case OCAST:
- if(nilcast(n->left->type, n->type))
- return 1;
- break;
-
- case ONEG:
- case OADD:
- case OSUB:
- return 1;
-
- case OMUL:
- if(n->left->op == OCONST)
- return 1;
- if(n->right->op == OCONST)
- return 1;
- }
- return 0;
-}
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
deleted file mode 100644
index 94c11d021..000000000
--- a/src/cmd/cc/sub.c
+++ /dev/null
@@ -1,2068 +0,0 @@
-// Inferno utils/cc/sub.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/sub.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "cc.h"
-
-Node*
-new(int t, Node *l, Node *r)
-{
- Node *n;
-
- n = alloc(sizeof(*n));
- n->op = t;
- n->left = l;
- n->right = r;
- if(l && t != OGOTO)
- n->lineno = l->lineno;
- else if(r)
- n->lineno = r->lineno;
- else
- n->lineno = lineno;
- newflag = 1;
- return n;
-}
-
-Node*
-new1(int o, Node *l, Node *r)
-{
- Node *n;
-
- n = new(o, l, r);
- n->lineno = nearln;
- return n;
-}
-
-void
-prtree(Node *n, char *s)
-{
-
- print(" == %s ==\n", s);
- prtree1(n, 0, 0);
- print("\n");
-}
-
-void
-prtree1(Node *n, int d, int f)
-{
- int i;
-
- if(f)
- for(i=0; i<d; i++)
- print(" ");
- if(n == Z) {
- print("Z\n");
- return;
- }
- if(n->op == OLIST) {
- prtree1(n->left, d, 0);
- prtree1(n->right, d, 1);
- return;
- }
- d++;
- print("%O", n->op);
- i = 3;
- switch(n->op)
- {
- case ONAME:
- print(" \"%F\"", n);
- print(" %d", n->xoffset);
- i = 0;
- break;
-
- case OINDREG:
- print(" %d(R%d)", n->xoffset, n->reg);
- i = 0;
- break;
-
- case OREGISTER:
- if(n->xoffset)
- print(" %d+R%d", n->xoffset, n->reg);
- else
- print(" R%d", n->reg);
- i = 0;
- break;
-
- case OSTRING:
- print(" \"%s\"", n->cstring);
- i = 0;
- break;
-
- case OLSTRING:
- if(sizeof(TRune) == sizeof(Rune))
- print(" \"%S\"", (Rune*)n->rstring);
- else
- print(" \"...\"");
- i = 0;
- break;
-
- case ODOT:
- case OELEM:
- print(" \"%F\"", n);
- break;
-
- case OCONST:
- if(typefd[n->type->etype])
- print(" \"%.8e\"", n->fconst);
- else
- print(" \"%lld\"", n->vconst);
- i = 0;
- break;
- }
- if(n->addable != 0)
- print(" <%d>", n->addable);
- if(n->type != T)
- print(" %T", n->type);
- if(n->complex != 0)
- print(" (%d)", n->complex);
- print(" %L\n", n->lineno);
- if(i & 2)
- prtree1(n->left, d, 1);
- if(i & 1)
- prtree1(n->right, d, 1);
-}
-
-Type*
-typ(int et, Type *d)
-{
- Type *t;
-
- t = alloc(sizeof(*t));
- t->etype = et;
- t->link = d;
- t->down = T;
- t->sym = S;
- if(et < NTYPE)
- t->width = ewidth[et];
- else
- t->width = -1; // for TDOT or TOLD in prototype
- t->offset = 0;
- t->shift = 0;
- t->nbits = 0;
- t->garb = 0;
- return t;
-}
-
-Type*
-copytyp(Type *t)
-{
- Type *nt;
-
- nt = typ(TXXX, T);
- *nt = *t;
- return nt;
-}
-
-Type*
-garbt(Type *t, int32 b)
-{
- Type *t1;
-
- if(b & BGARB) {
- t1 = copytyp(t);
- t1->garb = simpleg(b);
- return t1;
- }
- return t;
-}
-
-int
-simpleg(int32 b)
-{
-
- b &= BGARB;
- switch(b) {
- case BCONSTNT:
- return GCONSTNT;
- case BVOLATILE:
- return GVOLATILE;
- case BVOLATILE|BCONSTNT:
- return GCONSTNT|GVOLATILE;
- }
- return GXXX;
-}
-
-int
-simplec(int32 b)
-{
-
- b &= BCLASS;
- switch(b) {
- case 0:
- case BREGISTER:
- return CXXX;
- case BAUTO:
- case BAUTO|BREGISTER:
- return CAUTO;
- case BEXTERN:
- return CEXTERN;
- case BEXTERN|BREGISTER:
- return CEXREG;
- case BSTATIC:
- return CSTATIC;
- case BTYPEDEF:
- return CTYPEDEF;
- case BTYPESTR:
- return CTYPESTR;
- }
- diag(Z, "illegal combination of classes %Q", b);
- return CXXX;
-}
-
-Type*
-simplet(int32 b)
-{
-
- b &= ~BCLASS & ~BGARB;
- switch(b) {
- case BCHAR:
- case BCHAR|BSIGNED:
- return types[TCHAR];
-
- case BCHAR|BUNSIGNED:
- return types[TUCHAR];
-
- case BSHORT:
- case BSHORT|BINT:
- case BSHORT|BSIGNED:
- case BSHORT|BINT|BSIGNED:
- return types[TSHORT];
-
- case BUNSIGNED|BSHORT:
- case BUNSIGNED|BSHORT|BINT:
- return types[TUSHORT];
-
- case 0:
- case BINT:
- case BINT|BSIGNED:
- case BSIGNED:
- return types[TINT];
-
- case BUNSIGNED:
- case BUNSIGNED|BINT:
- return types[TUINT];
-
- case BLONG:
- case BLONG|BINT:
- case BLONG|BSIGNED:
- case BLONG|BINT|BSIGNED:
- return types[TLONG];
-
- case BUNSIGNED|BLONG:
- case BUNSIGNED|BLONG|BINT:
- return types[TULONG];
-
- case BVLONG|BLONG:
- case BVLONG|BLONG|BINT:
- case BVLONG|BLONG|BSIGNED:
- case BVLONG|BLONG|BINT|BSIGNED:
- return types[TVLONG];
-
- case BVLONG|BLONG|BUNSIGNED:
- case BVLONG|BLONG|BINT|BUNSIGNED:
- return types[TUVLONG];
-
- case BFLOAT:
- return types[TFLOAT];
-
- case BDOUBLE:
- case BDOUBLE|BLONG:
- case BFLOAT|BLONG:
- return types[TDOUBLE];
-
- case BVOID:
- return types[TVOID];
- }
-
- diag(Z, "illegal combination of types %Q", b);
- return types[TINT];
-}
-
-int
-stcompat(Node *n, Type *t1, Type *t2, int32 ttab[])
-{
- int i;
- uint32 b;
-
- i = 0;
- if(t2 != T)
- i = t2->etype;
- b = 1L << i;
- i = 0;
- if(t1 != T)
- i = t1->etype;
- if(b & ttab[i]) {
- if(ttab == tasign)
- if(b == BSTRUCT || b == BUNION)
- if(!sametype(t1, t2))
- return 1;
- if(n->op != OCAST)
- if(b == BIND && i == TIND)
- if(!sametype(t1, t2))
- return 1;
- return 0;
- }
- return 1;
-}
-
-int
-tcompat(Node *n, Type *t1, Type *t2, int32 ttab[])
-{
-
- if(stcompat(n, t1, t2, ttab)) {
- if(t1 == T)
- diag(n, "incompatible type: \"%T\" for op \"%O\"",
- t2, n->op);
- else
- diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"",
- t1, t2, n->op);
- return 1;
- }
- return 0;
-}
-
-void
-makedot(Node *n, Type *t, int32 o)
-{
- Node *n1, *n2;
-
- if(t->nbits) {
- n1 = new(OXXX, Z, Z);
- *n1 = *n;
- n->op = OBIT;
- n->left = n1;
- n->right = Z;
- n->type = t;
- n->addable = n1->left->addable;
- n = n1;
- }
- n->addable = n->left->addable;
- if(n->addable == 0) {
- n1 = new1(OCONST, Z, Z);
- n1->vconst = o;
- n1->type = types[TLONG];
- n->right = n1;
- n->type = t;
- return;
- }
- n->left->type = t;
- if(o == 0) {
- *n = *n->left;
- return;
- }
- n->type = t;
- n1 = new1(OCONST, Z, Z);
- n1->vconst = o;
- t = typ(TIND, t);
- t->width = types[TIND]->width;
- n1->type = t;
-
- n2 = new1(OADDR, n->left, Z);
- n2->type = t;
-
- n1 = new1(OADD, n1, n2);
- n1->type = t;
-
- n->op = OIND;
- n->left = n1;
- n->right = Z;
-}
-
-Type*
-dotsearch(Sym *s, Type *t, Node *n, int32 *off)
-{
- Type *t1, *xt, *rt;
-
- xt = T;
-
- /*
- * look it up by name
- */
- for(t1 = t; t1 != T; t1 = t1->down)
- if(t1->sym == s) {
- if(xt != T)
- goto ambig;
- xt = t1;
- }
-
- /*
- * look it up by type
- */
- if(s->class == CTYPEDEF || s->class == CTYPESTR)
- for(t1 = t; t1 != T; t1 = t1->down)
- if(t1->sym == S && typesu[t1->etype])
- if(sametype(s->type, t1)) {
- if(xt != T)
- goto ambig;
- xt = t1;
- }
- if(xt != T) {
- *off = xt->offset;
- return xt;
- }
-
- /*
- * look it up in unnamed substructures
- */
- for(t1 = t; t1 != T; t1 = t1->down)
- if(t1->sym == S && typesu[t1->etype]){
- rt = dotsearch(s, t1->link, n, off);
- if(rt != T) {
- if(xt != T)
- goto ambig;
- xt = rt;
- *off += t1->offset;
- }
- }
- return xt;
-
-ambig:
- diag(n, "ambiguous structure element: %s", s->name);
- return xt;
-}
-
-int32
-dotoffset(Type *st, Type *lt, Node *n)
-{
- Type *t;
- Sym *g;
- int32 o, o1;
-
- o = -1;
- /*
- * first try matching at the top level
- * for matching tag names
- */
- g = st->tag;
- if(g != S)
- for(t=lt->link; t!=T; t=t->down)
- if(t->sym == S)
- if(g == t->tag) {
- if(o >= 0)
- goto ambig;
- o = t->offset;
- }
- if(o >= 0)
- return o;
-
- /*
- * second try matching at the top level
- * for similar types
- */
- for(t=lt->link; t!=T; t=t->down)
- if(t->sym == S)
- if(sametype(st, t)) {
- if(o >= 0)
- goto ambig;
- o = t->offset;
- }
- if(o >= 0)
- return o;
-
- /*
- * last try matching sub-levels
- */
- for(t=lt->link; t!=T; t=t->down)
- if(t->sym == S)
- if(typesu[t->etype]) {
- o1 = dotoffset(st, t, n);
- if(o1 >= 0) {
- if(o >= 0)
- goto ambig;
- o = o1 + t->offset;
- }
- }
- return o;
-
-ambig:
- diag(n, "ambiguous unnamed structure element");
- return o;
-}
-
-/*
- * look into tree for floating point constant expressions
- */
-int
-allfloat(Node *n, int flag)
-{
-
- if(n != Z) {
- if(n->type->etype != TDOUBLE)
- return 1;
- switch(n->op) {
- case OCONST:
- if(flag)
- n->type = types[TFLOAT];
- return 1;
- case OADD: /* no need to get more exotic than this */
- case OSUB:
- case OMUL:
- case ODIV:
- if(!allfloat(n->right, flag))
- break;
- case OCAST:
- if(!allfloat(n->left, flag))
- break;
- if(flag)
- n->type = types[TFLOAT];
- return 1;
- }
- }
- return 0;
-}
-
-void
-constas(Node *n, Type *il, Type *ir)
-{
- Type *l, *r;
-
- l = il;
- r = ir;
-
- if(l == T)
- return;
- if(l->garb & GCONSTNT) {
- warn(n, "assignment to a constant type (%T)", il);
- return;
- }
- if(r == T)
- return;
- for(;;) {
- if(l->etype != TIND || r->etype != TIND)
- break;
- l = l->link;
- r = r->link;
- if(l == T || r == T)
- break;
- if(r->garb & GCONSTNT)
- if(!(l->garb & GCONSTNT)) {
- warn(n, "assignment of a constant pointer type (%T)", ir);
- break;
- }
- }
-}
-
-void
-typeext1(Type *st, Node *l)
-{
- if(st->etype == TFLOAT && allfloat(l, 0))
- allfloat(l, 1);
-}
-
-void
-typeext(Type *st, Node *l)
-{
- Type *lt;
- Node *n1, *n2;
- int32 o;
-
- lt = l->type;
- if(lt == T)
- return;
- if(st->etype == TIND && vconst(l) == 0) {
- l->type = st;
- l->vconst = 0;
- return;
- }
- typeext1(st, l);
-
- /*
- * extension of C
- * if assign of struct containing unnamed sub-struct
- * to type of sub-struct, insert the DOT.
- * if assign of *struct containing unnamed substruct
- * to type of *sub-struct, insert the add-offset
- */
- if(typesu[st->etype] && typesu[lt->etype]) {
- o = dotoffset(st, lt, l);
- if(o >= 0) {
- n1 = new1(OXXX, Z, Z);
- *n1 = *l;
- l->op = ODOT;
- l->left = n1;
- l->right = Z;
- makedot(l, st, o);
- }
- return;
- }
- if(st->etype == TIND && typesu[st->link->etype])
- if(lt->etype == TIND && typesu[lt->link->etype]) {
- o = dotoffset(st->link, lt->link, l);
- if(o >= 0) {
- l->type = st;
- if(o == 0)
- return;
- n1 = new1(OXXX, Z, Z);
- *n1 = *l;
- n2 = new1(OCONST, Z, Z);
- n2->vconst = o;
- n2->type = st;
- l->op = OADD;
- l->left = n1;
- l->right = n2;
- }
- return;
- }
-}
-
-/*
- * a cast that generates no code
- * (same size move)
- */
-int
-nocast(Type *t1, Type *t2)
-{
- int i, b;
-
- if(t1->nbits)
- return 0;
- i = 0;
- if(t2 != T)
- i = t2->etype;
- b = 1<<i;
- i = 0;
- if(t1 != T)
- i = t1->etype;
- if(b & ncast[i])
- return 1;
- return 0;
-}
-
-/*
- * a cast that has a noop semantic
- * (small to large, convert)
- */
-int
-nilcast(Type *t1, Type *t2)
-{
- int et1, et2;
-
- if(t1 == T)
- return 0;
- if(t1->nbits)
- return 0;
- if(t2 == T)
- return 0;
- et1 = t1->etype;
- et2 = t2->etype;
- if(et1 == et2)
- return 1;
- if(typefd[et1] && typefd[et2]) {
- if(ewidth[et1] < ewidth[et2])
- return 1;
- return 0;
- }
- if(typechlp[et1] && typechlp[et2]) {
- if(ewidth[et1] < ewidth[et2])
- return 1;
- return 0;
- }
- return 0;
-}
-
-/*
- * "the usual arithmetic conversions are performed"
- */
-void
-arith(Node *n, int f)
-{
- Type *t1, *t2;
- int i, j, k;
- Node *n1;
- int32 w;
-
- t1 = n->left->type;
- if(n->right == Z)
- t2 = t1;
- else
- t2 = n->right->type;
- i = TXXX;
- if(t1 != T)
- i = t1->etype;
- j = TXXX;
- if(t2 != T)
- j = t2->etype;
- k = tab[i][j];
- if(k == TIND) {
- if(i == TIND)
- n->type = t1;
- else
- if(j == TIND)
- n->type = t2;
- } else {
- /* convert up to at least int */
- if(f == 1)
- while(k < TINT)
- k += 2;
- n->type = types[k];
- }
- if(n->op == OSUB)
- if(i == TIND && j == TIND) {
- w = n->right->type->link->width;
- if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1)
- goto bad;
- n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG];
- if(0 && ewidth[TIND] > ewidth[TLONG]){
- n1 = new1(OXXX, Z, Z);
- *n1 = *n;
- n->op = OCAST;
- n->left = n1;
- n->right = Z;
- n->type = types[TLONG];
- }
- if(w > 1) {
- n1 = new1(OXXX, Z, Z);
- *n1 = *n;
- n->op = ODIV;
- n->left = n1;
- n1 = new1(OCONST, Z, Z);
- n1->vconst = w;
- n1->type = n->type;
- n->right = n1;
- w = vlog(n1);
- if(w >= 0) {
- n->op = OASHR;
- n1->vconst = w;
- }
- }
- return;
- }
- if(!sametype(n->type, n->left->type)) {
- n->left = new1(OCAST, n->left, Z);
- n->left->type = n->type;
- if(n->type->etype == TIND) {
- w = n->type->link->width;
- if(w < 1) {
- snap(n->type->link);
- w = n->type->link->width;
- if(w < 1)
- goto bad;
- }
- if(w > 1) {
- n1 = new1(OCONST, Z, Z);
- n1->vconst = w;
- n1->type = n->type;
- n->left = new1(OMUL, n->left, n1);
- n->left->type = n->type;
- }
- }
- }
- if(n->right != Z)
- if(!sametype(n->type, n->right->type)) {
- n->right = new1(OCAST, n->right, Z);
- n->right->type = n->type;
- if(n->type->etype == TIND) {
- w = n->type->link->width;
- if(w < 1) {
- snap(n->type->link);
- w = n->type->link->width;
- if(w < 1)
- goto bad;
- }
- if(w != 1) {
- n1 = new1(OCONST, Z, Z);
- n1->vconst = w;
- n1->type = n->type;
- n->right = new1(OMUL, n->right, n1);
- n->right->type = n->type;
- }
- }
- }
- return;
-bad:
- diag(n, "pointer addition not fully declared: %T", n->type->link);
-}
-
-/*
- * try to rewrite shift & mask
- */
-void
-simplifyshift(Node *n)
-{
- uint32 c3;
- int o, s1, s2, c1, c2;
-
- if(!typechlp[n->type->etype])
- return;
- switch(n->op) {
- default:
- return;
- case OASHL:
- s1 = 0;
- break;
- case OLSHR:
- s1 = 1;
- break;
- case OASHR:
- s1 = 2;
- break;
- }
- if(n->right->op != OCONST)
- return;
- if(n->left->op != OAND)
- return;
- if(n->left->right->op != OCONST)
- return;
- switch(n->left->left->op) {
- default:
- return;
- case OASHL:
- s2 = 0;
- break;
- case OLSHR:
- s2 = 1;
- break;
- case OASHR:
- s2 = 2;
- break;
- }
- if(n->left->left->right->op != OCONST)
- return;
-
- c1 = n->right->vconst;
- c2 = n->left->left->right->vconst;
- c3 = n->left->right->vconst;
-
- o = n->op;
- switch((s1<<3)|s2) {
- case 000: /* (((e <<u c2) & c3) <<u c1) */
- c3 >>= c2;
- c1 += c2;
- if(c1 >= 32)
- break;
- goto rewrite1;
-
- case 002: /* (((e >>s c2) & c3) <<u c1) */
- if(topbit(c3) >= (32-c2))
- break;
- case 001: /* (((e >>u c2) & c3) <<u c1) */
- if(c1 > c2) {
- c3 <<= c2;
- c1 -= c2;
- o = OASHL;
- goto rewrite1;
- }
- c3 <<= c1;
- if(c1 == c2)
- goto rewrite0;
- c1 = c2-c1;
- o = OLSHR;
- goto rewrite2;
-
- case 022: /* (((e >>s c2) & c3) >>s c1) */
- if(c2 <= 0)
- break;
- case 012: /* (((e >>s c2) & c3) >>u c1) */
- if(topbit(c3) >= (32-c2))
- break;
- goto s11;
- case 021: /* (((e >>u c2) & c3) >>s c1) */
- if(topbit(c3) >= 31 && c2 <= 0)
- break;
- goto s11;
- case 011: /* (((e >>u c2) & c3) >>u c1) */
- s11:
- c3 <<= c2;
- c1 += c2;
- if(c1 >= 32)
- break;
- o = OLSHR;
- goto rewrite1;
-
- case 020: /* (((e <<u c2) & c3) >>s c1) */
- if(topbit(c3) >= 31)
- break;
- case 010: /* (((e <<u c2) & c3) >>u c1) */
- c3 >>= c1;
- if(c1 == c2)
- goto rewrite0;
- if(c1 > c2) {
- c1 -= c2;
- goto rewrite2;
- }
- c1 = c2 - c1;
- o = OASHL;
- goto rewrite2;
- }
- return;
-
-rewrite0: /* get rid of both shifts */
-if(debug['<'])prtree(n, "rewrite0");
- *n = *n->left;
- n->left = n->left->left;
- n->right->vconst = c3;
- return;
-rewrite1: /* get rid of lower shift */
-if(debug['<'])prtree(n, "rewrite1");
- n->left->left = n->left->left->left;
- n->left->right->vconst = c3;
- n->right->vconst = c1;
- n->op = o;
- return;
-rewrite2: /* get rid of upper shift */
-if(debug['<'])prtree(n, "rewrite2");
- *n = *n->left;
- n->right->vconst = c3;
- n->left->right->vconst = c1;
- n->left->op = o;
-}
-
-int
-side(Node *n)
-{
-
-loop:
- if(n != Z)
- switch(n->op) {
- case OCAST:
- case ONOT:
- case OADDR:
- case OIND:
- n = n->left;
- goto loop;
-
- case OCOND:
- if(side(n->left))
- break;
- n = n->right;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGE:
- case OGT:
- case OLE:
- case OADD:
- case OSUB:
- case OMUL:
- case OLMUL:
- case ODIV:
- case OLDIV:
- case OLSHR:
- case OASHL:
- case OASHR:
- case OAND:
- case OOR:
- case OXOR:
- case OMOD:
- case OLMOD:
- case OANDAND:
- case OOROR:
- case OCOMMA:
- case ODOT:
- if(side(n->left))
- break;
- n = n->right;
- goto loop;
-
- case OSIGN:
- case OSIZE:
- case OCONST:
- case OSTRING:
- case OLSTRING:
- case ONAME:
- return 0;
- }
- return 1;
-}
-
-int
-vconst(Node *n)
-{
- int i;
-
- if(n == Z)
- goto no;
- if(n->op != OCONST)
- goto no;
- if(n->type == T)
- goto no;
- switch(n->type->etype)
- {
- case TFLOAT:
- case TDOUBLE:
- i = 100;
- if(n->fconst > i || n->fconst < -i)
- goto no;
- i = n->fconst;
- if(i != n->fconst)
- goto no;
- return i;
-
- case TVLONG:
- case TUVLONG:
- i = n->vconst;
- if(i != n->vconst)
- goto no;
- return i;
-
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- i = n->vconst;
- if(i != n->vconst)
- goto no;
- return i;
- }
-no:
- return -159; /* first uninteresting constant */
-}
-
-/*
- * return log(n) if n is a power of 2 constant
- */
-int
-xlog2(uvlong v)
-{
- int s, i;
- uvlong m;
-
- s = 0;
- m = MASK(8*sizeof(uvlong));
- for(i=32; i; i>>=1) {
- m >>= i;
- if(!(v & m)) {
- v >>= i;
- s += i;
- }
- }
- if(v == 1)
- return s;
- return -1;
-}
-
-int
-vlog(Node *n)
-{
- if(n->op != OCONST)
- goto bad;
- if(typefd[n->type->etype])
- goto bad;
-
- return xlog2(n->vconst);
-
-bad:
- return -1;
-}
-
-int
-topbit(uint32 v)
-{
- int i;
-
- for(i = -1; v; i++)
- v >>= 1;
- return i;
-}
-
-/*
- * try to cast a constant down
- * rather than cast a variable up
- * example:
- * if(c == 'a')
- */
-void
-relcon(Node *l, Node *r)
-{
- vlong v;
-
- if(l->op != OCONST)
- return;
- if(r->op != OCAST)
- return;
- if(!nilcast(r->left->type, r->type))
- return;
- switch(r->type->etype) {
- default:
- return;
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- v = convvtox(l->vconst, r->type->etype);
- if(v != l->vconst)
- return;
- break;
- }
- l->type = r->left->type;
- *r = *r->left;
-}
-
-int
-relindex(int o)
-{
-
- switch(o) {
- default:
- diag(Z, "bad in relindex: %O", o);
- case OEQ: return 0;
- case ONE: return 1;
- case OLE: return 2;
- case OLS: return 3;
- case OLT: return 4;
- case OLO: return 5;
- case OGE: return 6;
- case OHS: return 7;
- case OGT: return 8;
- case OHI: return 9;
- }
-}
-
-Node*
-invert(Node *n)
-{
- Node *i;
-
- if(n == Z || n->op != OLIST)
- return n;
- i = n;
- for(n = n->left; n != Z; n = n->left) {
- if(n->op != OLIST)
- break;
- i->left = n->right;
- n->right = i;
- i = n;
- }
- i->left = n;
- return i;
-}
-
-int
-bitno(int32 b)
-{
- int i;
-
- for(i=0; i<32; i++)
- if(b & (1L<<i))
- return i;
- diag(Z, "bad in bitno");
- return 0;
-}
-
-int32
-typebitor(int32 a, int32 b)
-{
- int32 c;
-
- c = a | b;
- if(a & b)
- if((a & b) == BLONG)
- c |= BVLONG; /* long long => vlong */
- else
- warn(Z, "once is enough: %Q", a & b);
- return c;
-}
-
-void
-diag(Node *n, char *fmt, ...)
-{
- char buf[STRINGSZ];
- va_list arg;
-
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
-
- if(debug['X']){
- Bflush(&diagbuf);
- abort();
- }
- if(n != Z)
- if(debug['v'])
- prtree(n, "diagnostic");
-
- nerrors++;
- if(nerrors > 10) {
- Bprint(&diagbuf, "too many errors\n");
- errorexit();
- }
-}
-
-void
-warn(Node *n, char *fmt, ...)
-{
- char buf[STRINGSZ];
- va_list arg;
-
- if(debug['w']) {
- Bprint(&diagbuf, "warning: ");
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
-
- if(n != Z)
- if(debug['v'])
- prtree(n, "warning");
- }
-}
-
-void
-yyerror(char *fmt, ...)
-{
- char buf[STRINGSZ];
- va_list arg;
-
- /*
- * hack to intercept message from yaccpar
- */
- if(strcmp(fmt, "syntax error") == 0) {
- yyerror("syntax error, last name: %s", symb);
- return;
- }
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- Bprint(&diagbuf, "%L %s\n", lineno, buf);
- nerrors++;
- if(nerrors > 10) {
- Bprint(&diagbuf, "too many errors\n");
- errorexit();
- }
-}
-
-void
-fatal(Node *n, char *fmt, ...)
-{
- char buf[STRINGSZ];
- va_list arg;
-
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
-
- if(debug['X']){
- Bflush(&diagbuf);
- abort();
- }
- if(n != Z)
- if(debug['v'])
- prtree(n, "diagnostic");
-
- nerrors++;
- errorexit();
-}
-
-uint32 thash1 = 0x2edab8c9;
-uint32 thash2 = 0x1dc74fb8;
-uint32 thash3 = 0x1f241331;
-uint32 thash[NALLTYPES];
-Init thashinit[] =
-{
- TXXX, 0x17527bbd, 0,
- TCHAR, 0x5cedd32b, 0,
- TUCHAR, 0x552c4454, 0,
- TSHORT, 0x63040b4b, 0,
- TUSHORT, 0x32a45878, 0,
- TINT, 0x4151d5bd, 0,
- TUINT, 0x5ae707d6, 0,
- TLONG, 0x5ef20f47, 0,
- TULONG, 0x36d8eb8f, 0,
- TVLONG, 0x6e5e9590, 0,
- TUVLONG, 0x75910105, 0,
- TFLOAT, 0x25fd7af1, 0,
- TDOUBLE, 0x7c40a1b2, 0,
- TIND, 0x1b832357, 0,
- TFUNC, 0x6babc9cb, 0,
- TARRAY, 0x7c50986d, 0,
- TVOID, 0x44112eff, 0,
- TSTRUCT, 0x7c2da3bf, 0,
- TUNION, 0x3eb25e98, 0,
- TENUM, 0x44b54f61, 0,
- TFILE, 0x19242ac3, 0,
- TOLD, 0x22b15988, 0,
- TDOT, 0x0204f6b3, 0,
- -1, 0, 0,
-};
-
-char* bnames[NALIGN];
-Init bnamesinit[] =
-{
- Axxx, 0, "Axxx",
- Ael1, 0, "el1",
- Ael2, 0, "el2",
- Asu2, 0, "su2",
- Aarg0, 0, "arg0",
- Aarg1, 0, "arg1",
- Aarg2, 0, "arg2",
- Aaut3, 0, "aut3",
- -1, 0, 0,
-};
-
-char* tnames[NALLTYPES];
-Init tnamesinit[] =
-{
- TXXX, 0, "TXXX",
- TCHAR, 0, "CHAR",
- TUCHAR, 0, "UCHAR",
- TSHORT, 0, "SHORT",
- TUSHORT, 0, "USHORT",
- TINT, 0, "INT",
- TUINT, 0, "UINT",
- TLONG, 0, "LONG",
- TULONG, 0, "ULONG",
- TVLONG, 0, "VLONG",
- TUVLONG, 0, "UVLONG",
- TFLOAT, 0, "FLOAT",
- TDOUBLE, 0, "DOUBLE",
- TIND, 0, "IND",
- TFUNC, 0, "FUNC",
- TARRAY, 0, "ARRAY",
- TVOID, 0, "VOID",
- TSTRUCT, 0, "STRUCT",
- TUNION, 0, "UNION",
- TENUM, 0, "ENUM",
- TFILE, 0, "FILE",
- TOLD, 0, "OLD",
- TDOT, 0, "DOT",
- -1, 0, 0,
-};
-
-char* gnames[NGTYPES];
-Init gnamesinit[] =
-{
- GXXX, 0, "GXXX",
- GCONSTNT, 0, "CONST",
- GVOLATILE, 0, "VOLATILE",
- GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE",
- -1, 0, 0,
-};
-
-char* qnames[NALLTYPES];
-Init qnamesinit[] =
-{
- TXXX, 0, "TXXX",
- TCHAR, 0, "CHAR",
- TUCHAR, 0, "UCHAR",
- TSHORT, 0, "SHORT",
- TUSHORT, 0, "USHORT",
- TINT, 0, "INT",
- TUINT, 0, "UINT",
- TLONG, 0, "LONG",
- TULONG, 0, "ULONG",
- TVLONG, 0, "VLONG",
- TUVLONG, 0, "UVLONG",
- TFLOAT, 0, "FLOAT",
- TDOUBLE, 0, "DOUBLE",
- TIND, 0, "IND",
- TFUNC, 0, "FUNC",
- TARRAY, 0, "ARRAY",
- TVOID, 0, "VOID",
- TSTRUCT, 0, "STRUCT",
- TUNION, 0, "UNION",
- TENUM, 0, "ENUM",
-
- TAUTO, 0, "AUTO",
- TEXTERN, 0, "EXTERN",
- TSTATIC, 0, "STATIC",
- TTYPEDEF, 0, "TYPEDEF",
- TTYPESTR, 0, "TYPESTR",
- TREGISTER, 0, "REGISTER",
- TCONSTNT, 0, "CONSTNT",
- TVOLATILE, 0, "VOLATILE",
- TUNSIGNED, 0, "UNSIGNED",
- TSIGNED, 0, "SIGNED",
- TDOT, 0, "DOT",
- TFILE, 0, "FILE",
- TOLD, 0, "OLD",
- -1, 0, 0,
-};
-char* cnames[NCTYPES];
-Init cnamesinit[] =
-{
- CXXX, 0, "CXXX",
- CAUTO, 0, "AUTO",
- CEXTERN, 0, "EXTERN",
- CGLOBL, 0, "GLOBL",
- CSTATIC, 0, "STATIC",
- CLOCAL, 0, "LOCAL",
- CTYPEDEF, 0, "TYPEDEF",
- CTYPESTR, 0, "TYPESTR",
- CPARAM, 0, "PARAM",
- CSELEM, 0, "SELEM",
- CLABEL, 0, "LABEL",
- CEXREG, 0, "EXREG",
- -1, 0, 0,
-};
-
-char* onames[OEND+1];
-Init onamesinit[] =
-{
- OXXX, 0, "OXXX",
- OADD, 0, "ADD",
- OADDR, 0, "ADDR",
- OAND, 0, "AND",
- OANDAND, 0, "ANDAND",
- OARRAY, 0, "ARRAY",
- OAS, 0, "AS",
- OASI, 0, "ASI",
- OASADD, 0, "ASADD",
- OASAND, 0, "ASAND",
- OASASHL, 0, "ASASHL",
- OASASHR, 0, "ASASHR",
- OASDIV, 0, "ASDIV",
- OASHL, 0, "ASHL",
- OASHR, 0, "ASHR",
- OASLDIV, 0, "ASLDIV",
- OASLMOD, 0, "ASLMOD",
- OASLMUL, 0, "ASLMUL",
- OASLSHR, 0, "ASLSHR",
- OASMOD, 0, "ASMOD",
- OASMUL, 0, "ASMUL",
- OASOR, 0, "ASOR",
- OASSUB, 0, "ASSUB",
- OASXOR, 0, "ASXOR",
- OBIT, 0, "BIT",
- OBREAK, 0, "BREAK",
- OCASE, 0, "CASE",
- OCAST, 0, "CAST",
- OCOMMA, 0, "COMMA",
- OCOND, 0, "COND",
- OCONST, 0, "CONST",
- OCONTINUE, 0, "CONTINUE",
- ODIV, 0, "DIV",
- ODOT, 0, "DOT",
- ODOTDOT, 0, "DOTDOT",
- ODWHILE, 0, "DWHILE",
- OENUM, 0, "ENUM",
- OEQ, 0, "EQ",
- OEXREG, 0, "EXREG",
- OFOR, 0, "FOR",
- OFUNC, 0, "FUNC",
- OGE, 0, "GE",
- OGOTO, 0, "GOTO",
- OGT, 0, "GT",
- OHI, 0, "HI",
- OHS, 0, "HS",
- OIF, 0, "IF",
- OIND, 0, "IND",
- OINDREG, 0, "INDREG",
- OINIT, 0, "INIT",
- OLABEL, 0, "LABEL",
- OLDIV, 0, "LDIV",
- OLE, 0, "LE",
- OLIST, 0, "LIST",
- OLMOD, 0, "LMOD",
- OLMUL, 0, "LMUL",
- OLO, 0, "LO",
- OLS, 0, "LS",
- OLSHR, 0, "LSHR",
- OLT, 0, "LT",
- OMOD, 0, "MOD",
- OMUL, 0, "MUL",
- ONAME, 0, "NAME",
- ONE, 0, "NE",
- ONOT, 0, "NOT",
- OOR, 0, "OR",
- OOROR, 0, "OROR",
- OPOSTDEC, 0, "POSTDEC",
- OPOSTINC, 0, "POSTINC",
- OPREDEC, 0, "PREDEC",
- OPREINC, 0, "PREINC",
- OPREFETCH, 0, "PREFETCH",
- OPROTO, 0, "PROTO",
- OREGISTER, 0, "REGISTER",
- ORETURN, 0, "RETURN",
- OSET, 0, "SET",
- OSIGN, 0, "SIGN",
- OSIZE, 0, "SIZE",
- OSTRING, 0, "STRING",
- OLSTRING, 0, "LSTRING",
- OSTRUCT, 0, "STRUCT",
- OSUB, 0, "SUB",
- OSWITCH, 0, "SWITCH",
- OUNION, 0, "UNION",
- OUSED, 0, "USED",
- OWHILE, 0, "WHILE",
- OXOR, 0, "XOR",
- OPOS, 0, "POS",
- ONEG, 0, "NEG",
- OCOM, 0, "COM",
- OELEM, 0, "ELEM",
- OTST, 0, "TST",
- OINDEX, 0, "INDEX",
- OFAS, 0, "FAS",
- OREGPAIR, 0, "REGPAIR",
- OROTL, 0, "ROTL",
- OEND, 0, "END",
- -1, 0, 0,
-};
-
-/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
-uchar comrel[12] =
-{
- ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
-};
-uchar invrel[12] =
-{
- OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
-};
-uchar logrel[12] =
-{
- OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
-};
-
-uchar typei[NALLTYPES];
-int typeiinit[] =
-{
- TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
-};
-uchar typeu[NALLTYPES];
-int typeuinit[] =
-{
- TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
-};
-
-uchar typesuv[NALLTYPES];
-int typesuvinit[] =
-{
- TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
-};
-
-uchar typeilp[NALLTYPES];
-int typeilpinit[] =
-{
- TINT, TUINT, TLONG, TULONG, TIND, -1
-};
-
-uchar typechl[NALLTYPES];
-uchar typechlv[NALLTYPES];
-uchar typechlvp[NALLTYPES];
-int typechlinit[] =
-{
- TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
-};
-
-uchar typechlp[NALLTYPES];
-int typechlpinit[] =
-{
- TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
-};
-
-uchar typechlpfd[NALLTYPES];
-int typechlpfdinit[] =
-{
- TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
-};
-
-uchar typec[NALLTYPES];
-int typecinit[] =
-{
- TCHAR, TUCHAR, -1
-};
-
-uchar typeh[NALLTYPES];
-int typehinit[] =
-{
- TSHORT, TUSHORT, -1,
-};
-
-uchar typeil[NALLTYPES];
-int typeilinit[] =
-{
- TINT, TUINT, TLONG, TULONG, -1,
-};
-
-uchar typev[NALLTYPES];
-int typevinit[] =
-{
- TVLONG, TUVLONG, -1,
-};
-
-uchar typefd[NALLTYPES];
-int typefdinit[] =
-{
- TFLOAT, TDOUBLE, -1,
-};
-
-uchar typeaf[NALLTYPES];
-int typeafinit[] =
-{
- TFUNC, TARRAY, -1,
-};
-
-uchar typesu[NALLTYPES];
-int typesuinit[] =
-{
- TSTRUCT, TUNION, -1,
-};
-
-int32 tasign[NALLTYPES];
-Init tasigninit[] =
-{
- TCHAR, BNUMBER, 0,
- TUCHAR, BNUMBER, 0,
- TSHORT, BNUMBER, 0,
- TUSHORT, BNUMBER, 0,
- TINT, BNUMBER, 0,
- TUINT, BNUMBER, 0,
- TLONG, BNUMBER, 0,
- TULONG, BNUMBER, 0,
- TVLONG, BNUMBER, 0,
- TUVLONG, BNUMBER, 0,
- TFLOAT, BNUMBER, 0,
- TDOUBLE, BNUMBER, 0,
- TIND, BIND, 0,
- TSTRUCT, BSTRUCT, 0,
- TUNION, BUNION, 0,
- -1, 0, 0,
-};
-
-int32 tasadd[NALLTYPES];
-Init tasaddinit[] =
-{
- TCHAR, BNUMBER, 0,
- TUCHAR, BNUMBER, 0,
- TSHORT, BNUMBER, 0,
- TUSHORT, BNUMBER, 0,
- TINT, BNUMBER, 0,
- TUINT, BNUMBER, 0,
- TLONG, BNUMBER, 0,
- TULONG, BNUMBER, 0,
- TVLONG, BNUMBER, 0,
- TUVLONG, BNUMBER, 0,
- TFLOAT, BNUMBER, 0,
- TDOUBLE, BNUMBER, 0,
- TIND, BINTEGER, 0,
- -1, 0, 0,
-};
-
-int32 tcast[NALLTYPES];
-Init tcastinit[] =
-{
- TCHAR, BNUMBER|BIND|BVOID, 0,
- TUCHAR, BNUMBER|BIND|BVOID, 0,
- TSHORT, BNUMBER|BIND|BVOID, 0,
- TUSHORT, BNUMBER|BIND|BVOID, 0,
- TINT, BNUMBER|BIND|BVOID, 0,
- TUINT, BNUMBER|BIND|BVOID, 0,
- TLONG, BNUMBER|BIND|BVOID, 0,
- TULONG, BNUMBER|BIND|BVOID, 0,
- TVLONG, BNUMBER|BIND|BVOID, 0,
- TUVLONG, BNUMBER|BIND|BVOID, 0,
- TFLOAT, BNUMBER|BVOID, 0,
- TDOUBLE, BNUMBER|BVOID, 0,
- TIND, BINTEGER|BIND|BVOID, 0,
- TVOID, BVOID, 0,
- TSTRUCT, BSTRUCT|BVOID, 0,
- TUNION, BUNION|BVOID, 0,
- -1, 0, 0,
-};
-
-int32 tadd[NALLTYPES];
-Init taddinit[] =
-{
- TCHAR, BNUMBER|BIND, 0,
- TUCHAR, BNUMBER|BIND, 0,
- TSHORT, BNUMBER|BIND, 0,
- TUSHORT, BNUMBER|BIND, 0,
- TINT, BNUMBER|BIND, 0,
- TUINT, BNUMBER|BIND, 0,
- TLONG, BNUMBER|BIND, 0,
- TULONG, BNUMBER|BIND, 0,
- TVLONG, BNUMBER|BIND, 0,
- TUVLONG, BNUMBER|BIND, 0,
- TFLOAT, BNUMBER, 0,
- TDOUBLE, BNUMBER, 0,
- TIND, BINTEGER, 0,
- -1, 0, 0,
-};
-
-int32 tsub[NALLTYPES];
-Init tsubinit[] =
-{
- TCHAR, BNUMBER, 0,
- TUCHAR, BNUMBER, 0,
- TSHORT, BNUMBER, 0,
- TUSHORT, BNUMBER, 0,
- TINT, BNUMBER, 0,
- TUINT, BNUMBER, 0,
- TLONG, BNUMBER, 0,
- TULONG, BNUMBER, 0,
- TVLONG, BNUMBER, 0,
- TUVLONG, BNUMBER, 0,
- TFLOAT, BNUMBER, 0,
- TDOUBLE, BNUMBER, 0,
- TIND, BINTEGER|BIND, 0,
- -1, 0, 0,
-};
-
-int32 tmul[NALLTYPES];
-Init tmulinit[] =
-{
- TCHAR, BNUMBER, 0,
- TUCHAR, BNUMBER, 0,
- TSHORT, BNUMBER, 0,
- TUSHORT, BNUMBER, 0,
- TINT, BNUMBER, 0,
- TUINT, BNUMBER, 0,
- TLONG, BNUMBER, 0,
- TULONG, BNUMBER, 0,
- TVLONG, BNUMBER, 0,
- TUVLONG, BNUMBER, 0,
- TFLOAT, BNUMBER, 0,
- TDOUBLE, BNUMBER, 0,
- -1, 0, 0,
-};
-
-int32 tand[NALLTYPES];
-Init tandinit[] =
-{
- TCHAR, BINTEGER, 0,
- TUCHAR, BINTEGER, 0,
- TSHORT, BINTEGER, 0,
- TUSHORT, BINTEGER, 0,
- TINT, BNUMBER, 0,
- TUINT, BNUMBER, 0,
- TLONG, BINTEGER, 0,
- TULONG, BINTEGER, 0,
- TVLONG, BINTEGER, 0,
- TUVLONG, BINTEGER, 0,
- -1, 0, 0,
-};
-
-int32 trel[NALLTYPES];
-Init trelinit[] =
-{
- TCHAR, BNUMBER, 0,
- TUCHAR, BNUMBER, 0,
- TSHORT, BNUMBER, 0,
- TUSHORT, BNUMBER, 0,
- TINT, BNUMBER, 0,
- TUINT, BNUMBER, 0,
- TLONG, BNUMBER, 0,
- TULONG, BNUMBER, 0,
- TVLONG, BNUMBER, 0,
- TUVLONG, BNUMBER, 0,
- TFLOAT, BNUMBER, 0,
- TDOUBLE, BNUMBER, 0,
- TIND, BIND, 0,
- -1, 0, 0,
-};
-
-int32 tfunct[1] =
-{
- BFUNC,
-};
-
-int32 tindir[1] =
-{
- BIND,
-};
-
-int32 tdot[1] =
-{
- BSTRUCT|BUNION,
-};
-
-int32 tnot[1] =
-{
- BNUMBER|BIND,
-};
-
-int32 targ[1] =
-{
- BNUMBER|BIND|BSTRUCT|BUNION,
-};
-
-uchar tab[NTYPE][NTYPE] =
-{
-/*TXXX*/ { 0,
- },
-
-/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG,
- TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
- },
-/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
- TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
- },
-/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG,
- TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
- },
-/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
- TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
- },
-/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG,
- TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
- },
-/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG,
- TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
- },
-/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG,
- TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
- },
-/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG,
- TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
- },
-/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG,
- TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
- },
-/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG,
- TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
- },
-/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT,
- TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND,
- },
-/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE,
- TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND,
- },
-/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND,
- TIND, TIND, TIND, TIND, TIND, TIND,
- },
-};
-
-void
-urk(char *name, int max, int i)
-{
- if(i >= max) {
- fprint(2, "bad tinit: %s %d>=%d\n", name, i, max);
- exits("init");
- }
-}
-
-void
-tinit(void)
-{
- int *ip;
- Init *p;
-
- for(p=thashinit; p->code >= 0; p++) {
- urk("thash", nelem(thash), p->code);
- thash[p->code] = p->value;
- }
- for(p=bnamesinit; p->code >= 0; p++) {
- urk("bnames", nelem(bnames), p->code);
- bnames[p->code] = p->s;
- }
- for(p=tnamesinit; p->code >= 0; p++) {
- urk("tnames", nelem(tnames), p->code);
- tnames[p->code] = p->s;
- }
- for(p=gnamesinit; p->code >= 0; p++) {
- urk("gnames", nelem(gnames), p->code);
- gnames[p->code] = p->s;
- }
- for(p=qnamesinit; p->code >= 0; p++) {
- urk("qnames", nelem(qnames), p->code);
- qnames[p->code] = p->s;
- }
- for(p=cnamesinit; p->code >= 0; p++) {
- urk("cnames", nelem(cnames), p->code);
- cnames[p->code] = p->s;
- }
- for(p=onamesinit; p->code >= 0; p++) {
- urk("onames", nelem(onames), p->code);
- onames[p->code] = p->s;
- }
- for(ip=typeiinit; *ip>=0; ip++) {
- urk("typei", nelem(typei), *ip);
- typei[*ip] = 1;
- }
- for(ip=typeuinit; *ip>=0; ip++) {
- urk("typeu", nelem(typeu), *ip);
- typeu[*ip] = 1;
- }
- for(ip=typesuvinit; *ip>=0; ip++) {
- urk("typesuv", nelem(typesuv), *ip);
- typesuv[*ip] = 1;
- }
- for(ip=typeilpinit; *ip>=0; ip++) {
- urk("typeilp", nelem(typeilp), *ip);
- typeilp[*ip] = 1;
- }
- for(ip=typechlinit; *ip>=0; ip++) {
- urk("typechl", nelem(typechl), *ip);
- typechl[*ip] = 1;
- typechlv[*ip] = 1;
- typechlvp[*ip] = 1;
- }
- for(ip=typechlpinit; *ip>=0; ip++) {
- urk("typechlp", nelem(typechlp), *ip);
- typechlp[*ip] = 1;
- typechlvp[*ip] = 1;
- }
- for(ip=typechlpfdinit; *ip>=0; ip++) {
- urk("typechlpfd", nelem(typechlpfd), *ip);
- typechlpfd[*ip] = 1;
- }
- for(ip=typecinit; *ip>=0; ip++) {
- urk("typec", nelem(typec), *ip);
- typec[*ip] = 1;
- }
- for(ip=typehinit; *ip>=0; ip++) {
- urk("typeh", nelem(typeh), *ip);
- typeh[*ip] = 1;
- }
- for(ip=typeilinit; *ip>=0; ip++) {
- urk("typeil", nelem(typeil), *ip);
- typeil[*ip] = 1;
- }
- for(ip=typevinit; *ip>=0; ip++) {
- urk("typev", nelem(typev), *ip);
- typev[*ip] = 1;
- typechlv[*ip] = 1;
- typechlvp[*ip] = 1;
- }
- for(ip=typefdinit; *ip>=0; ip++) {
- urk("typefd", nelem(typefd), *ip);
- typefd[*ip] = 1;
- }
- for(ip=typeafinit; *ip>=0; ip++) {
- urk("typeaf", nelem(typeaf), *ip);
- typeaf[*ip] = 1;
- }
- for(ip=typesuinit; *ip >= 0; ip++) {
- urk("typesu", nelem(typesu), *ip);
- typesu[*ip] = 1;
- }
- for(p=tasigninit; p->code >= 0; p++) {
- urk("tasign", nelem(tasign), p->code);
- tasign[p->code] = p->value;
- }
- for(p=tasaddinit; p->code >= 0; p++) {
- urk("tasadd", nelem(tasadd), p->code);
- tasadd[p->code] = p->value;
- }
- for(p=tcastinit; p->code >= 0; p++) {
- urk("tcast", nelem(tcast), p->code);
- tcast[p->code] = p->value;
- }
- for(p=taddinit; p->code >= 0; p++) {
- urk("tadd", nelem(tadd), p->code);
- tadd[p->code] = p->value;
- }
- for(p=tsubinit; p->code >= 0; p++) {
- urk("tsub", nelem(tsub), p->code);
- tsub[p->code] = p->value;
- }
- for(p=tmulinit; p->code >= 0; p++) {
- urk("tmul", nelem(tmul), p->code);
- tmul[p->code] = p->value;
- }
- for(p=tandinit; p->code >= 0; p++) {
- urk("tand", nelem(tand), p->code);
- tand[p->code] = p->value;
- }
- for(p=trelinit; p->code >= 0; p++) {
- urk("trel", nelem(trel), p->code);
- trel[p->code] = p->value;
- }
-
- /* 32-bit defaults */
- typeword = typechlp;
- typecmplx = typesuv;
-}
-
-/*
- * return 1 if it is impossible to jump into the middle of n.
- */
-static int
-deadhead(Node *n, int caseok)
-{
-loop:
- if(n == Z)
- return 1;
- switch(n->op) {
- case OLIST:
- if(!deadhead(n->left, caseok))
- return 0;
- rloop:
- n = n->right;
- goto loop;
-
- case ORETURN:
- break;
-
- case OLABEL:
- return 0;
-
- case OGOTO:
- break;
-
- case OCASE:
- if(!caseok)
- return 0;
- goto rloop;
-
- case OSWITCH:
- return deadhead(n->right, 1);
-
- case OWHILE:
- case ODWHILE:
- goto rloop;
-
- case OFOR:
- goto rloop;
-
- case OCONTINUE:
- break;
-
- case OBREAK:
- break;
-
- case OIF:
- return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok);
-
- case OSET:
- case OUSED:
- break;
- }
- return 1;
-}
-
-int
-deadheads(Node *c)
-{
- return deadhead(c->left, 0) && deadhead(c->right, 0);
-}
-
-int
-mixedasop(Type *l, Type *r)
-{
- return !typefd[l->etype] && typefd[r->etype];
-}
-
-LSym*
-linksym(Sym *s)
-{
- if(s == nil)
- return nil;
- if(s->lsym != nil)
- return s->lsym;
- return linklookup(ctxt, s->name, s->class == CSTATIC);
-}
diff --git a/src/cmd/cc/y.tab.c b/src/cmd/cc/y.tab.c
deleted file mode 100644
index 94932efe5..000000000
--- a/src/cmd/cc/y.tab.c
+++ /dev/null
@@ -1,3822 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-/* Identify Bison output. */
-#define YYBISON 1
-
-/* Bison version. */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name. */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers. */
-#define YYPURE 0
-
-/* Using locations. */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LORE = 258,
- LXORE = 259,
- LANDE = 260,
- LLSHE = 261,
- LRSHE = 262,
- LMDE = 263,
- LDVE = 264,
- LMLE = 265,
- LME = 266,
- LPE = 267,
- LOROR = 268,
- LANDAND = 269,
- LNE = 270,
- LEQ = 271,
- LGE = 272,
- LLE = 273,
- LRSH = 274,
- LLSH = 275,
- LMG = 276,
- LPP = 277,
- LMM = 278,
- LNAME = 279,
- LTYPE = 280,
- LFCONST = 281,
- LDCONST = 282,
- LCONST = 283,
- LLCONST = 284,
- LUCONST = 285,
- LULCONST = 286,
- LVLCONST = 287,
- LUVLCONST = 288,
- LSTRING = 289,
- LLSTRING = 290,
- LAUTO = 291,
- LBREAK = 292,
- LCASE = 293,
- LCHAR = 294,
- LCONTINUE = 295,
- LDEFAULT = 296,
- LDO = 297,
- LDOUBLE = 298,
- LELSE = 299,
- LEXTERN = 300,
- LFLOAT = 301,
- LFOR = 302,
- LGOTO = 303,
- LIF = 304,
- LINT = 305,
- LLONG = 306,
- LPREFETCH = 307,
- LREGISTER = 308,
- LRETURN = 309,
- LSHORT = 310,
- LSIZEOF = 311,
- LUSED = 312,
- LSTATIC = 313,
- LSTRUCT = 314,
- LSWITCH = 315,
- LTYPEDEF = 316,
- LTYPESTR = 317,
- LUNION = 318,
- LUNSIGNED = 319,
- LWHILE = 320,
- LVOID = 321,
- LENUM = 322,
- LSIGNED = 323,
- LCONSTNT = 324,
- LVOLATILE = 325,
- LSET = 326,
- LSIGNOF = 327,
- LRESTRICT = 328,
- LINLINE = 329
- };
-#endif
-/* Tokens. */
-#define LORE 258
-#define LXORE 259
-#define LANDE 260
-#define LLSHE 261
-#define LRSHE 262
-#define LMDE 263
-#define LDVE 264
-#define LMLE 265
-#define LME 266
-#define LPE 267
-#define LOROR 268
-#define LANDAND 269
-#define LNE 270
-#define LEQ 271
-#define LGE 272
-#define LLE 273
-#define LRSH 274
-#define LLSH 275
-#define LMG 276
-#define LPP 277
-#define LMM 278
-#define LNAME 279
-#define LTYPE 280
-#define LFCONST 281
-#define LDCONST 282
-#define LCONST 283
-#define LLCONST 284
-#define LUCONST 285
-#define LULCONST 286
-#define LVLCONST 287
-#define LUVLCONST 288
-#define LSTRING 289
-#define LLSTRING 290
-#define LAUTO 291
-#define LBREAK 292
-#define LCASE 293
-#define LCHAR 294
-#define LCONTINUE 295
-#define LDEFAULT 296
-#define LDO 297
-#define LDOUBLE 298
-#define LELSE 299
-#define LEXTERN 300
-#define LFLOAT 301
-#define LFOR 302
-#define LGOTO 303
-#define LIF 304
-#define LINT 305
-#define LLONG 306
-#define LPREFETCH 307
-#define LREGISTER 308
-#define LRETURN 309
-#define LSHORT 310
-#define LSIZEOF 311
-#define LUSED 312
-#define LSTATIC 313
-#define LSTRUCT 314
-#define LSWITCH 315
-#define LTYPEDEF 316
-#define LTYPESTR 317
-#define LUNION 318
-#define LUNSIGNED 319
-#define LWHILE 320
-#define LVOID 321
-#define LENUM 322
-#define LSIGNED 323
-#define LCONSTNT 324
-#define LVOLATILE 325
-#define LSET 326
-#define LSIGNOF 327
-#define LRESTRICT 328
-#define LINLINE 329
-
-
-
-
-/* Copy the first part of user declarations. */
-#line 31 "cc.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and cc.h re-#defines getc */
-#include "cc.h"
-
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 36 "cc.y"
-{
- Node* node;
- Sym* sym;
- Type* type;
- struct
- {
- Type* t;
- uchar c;
- } tycl;
- struct
- {
- Type* t1;
- Type* t2;
- Type* t3;
- uchar c;
- } tyty;
- struct
- {
- char* s;
- int32 l;
- } sval;
- int32 lval;
- double dval;
- vlong vval;
-}
-/* Line 193 of yacc.c. */
-#line 276 "y.tab.c"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations. */
-
-
-/* Line 216 of yacc.c. */
-#line 289 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
- int i;
-#endif
-{
- return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# ifdef YYSTACK_USE_ALLOCA
-# if YYSTACK_USE_ALLOCA
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
-# else
-# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
-# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- yytype_int16 yyss;
- YYSTYPE yyvs;
- };
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
- + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 2
-/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 1188
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 99
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 75
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 247
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 417
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
-#define YYUNDEFTOK 2
-#define YYMAXUTOK 329
-
-#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-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, 97, 2, 2, 2, 35, 22, 2,
- 38, 93, 33, 31, 4, 32, 36, 34, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 17, 3,
- 25, 5, 26, 16, 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, 37, 2, 94, 21, 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, 95, 20, 96, 98, 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, 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, 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, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15, 18, 19,
- 23, 24, 27, 28, 29, 30, 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,
- 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
- 83, 84, 85, 86, 87, 88, 89, 90, 91, 92
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 4, 7, 10, 14, 15, 16, 23,
- 25, 26, 31, 35, 37, 41, 43, 47, 52, 57,
- 60, 64, 66, 67, 72, 76, 77, 82, 84, 88,
- 89, 94, 95, 101, 102, 104, 106, 110, 112, 116,
- 119, 120, 122, 125, 129, 131, 133, 138, 143, 146,
- 150, 154, 156, 160, 164, 167, 170, 173, 177, 179,
- 182, 184, 186, 189, 190, 192, 194, 197, 200, 204,
- 208, 212, 213, 216, 219, 221, 224, 228, 231, 234,
- 237, 239, 242, 244, 247, 250, 251, 254, 260, 268,
- 269, 280, 286, 294, 298, 304, 307, 310, 314, 320,
- 326, 332, 333, 335, 336, 338, 340, 342, 346, 348,
- 352, 356, 360, 364, 368, 372, 376, 380, 384, 388,
- 392, 396, 400, 404, 408, 412, 416, 420, 426, 430,
- 434, 438, 442, 446, 450, 454, 458, 462, 466, 470,
- 472, 478, 486, 488, 491, 494, 497, 500, 503, 506,
- 509, 512, 515, 518, 522, 528, 534, 539, 544, 548,
- 552, 555, 558, 560, 562, 564, 566, 568, 570, 572,
- 574, 576, 578, 580, 582, 585, 587, 590, 591, 593,
- 595, 599, 600, 605, 606, 608, 610, 612, 614, 617,
- 620, 624, 627, 631, 633, 635, 638, 639, 644, 647,
- 650, 651, 656, 659, 662, 663, 664, 672, 673, 679,
- 681, 683, 686, 687, 690, 692, 694, 696, 698, 701,
- 703, 705, 707, 711, 714, 718, 720, 722, 724, 726,
- 728, 730, 732, 734, 736, 738, 740, 742, 744, 746,
- 748, 750, 752, 754, 756, 758, 760, 762
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int16 yyrhs[] =
-{
- 100, 0, -1, -1, 100, 101, -1, 152, 3, -1,
- 152, 104, 3, -1, -1, -1, 152, 106, 102, 111,
- 103, 129, -1, 106, -1, -1, 106, 105, 5, 123,
- -1, 104, 4, 104, -1, 107, -1, 33, 163, 106,
- -1, 172, -1, 38, 106, 93, -1, 107, 38, 127,
- 93, -1, 107, 37, 139, 94, -1, 155, 3, -1,
- 155, 109, 3, -1, 106, -1, -1, 106, 110, 5,
- 123, -1, 109, 4, 109, -1, -1, 111, 155, 112,
- 3, -1, 106, -1, 112, 4, 112, -1, -1, 154,
- 114, 116, 3, -1, -1, 113, 154, 115, 116, 3,
- -1, -1, 117, -1, 118, -1, 117, 4, 117, -1,
- 106, -1, 172, 17, 140, -1, 17, 140, -1, -1,
- 120, -1, 33, 163, -1, 33, 163, 120, -1, 121,
- -1, 122, -1, 121, 38, 127, 93, -1, 121, 37,
- 139, 94, -1, 38, 93, -1, 37, 139, 94, -1,
- 38, 120, 93, -1, 142, -1, 95, 126, 96, -1,
- 37, 140, 94, -1, 36, 173, -1, 124, 5, -1,
- 123, 4, -1, 125, 123, 4, -1, 124, -1, 125,
- 124, -1, 125, -1, 123, -1, 125, 123, -1, -1,
- 128, -1, 171, -1, 154, 119, -1, 154, 106, -1,
- 36, 36, 36, -1, 128, 4, 128, -1, 95, 130,
- 96, -1, -1, 130, 108, -1, 130, 133, -1, 132,
- -1, 131, 132, -1, 56, 142, 17, -1, 59, 17,
- -1, 42, 17, -1, 1, 3, -1, 135, -1, 131,
- 135, -1, 138, -1, 155, 109, -1, 138, 3, -1,
- -1, 136, 129, -1, 67, 38, 141, 93, 133, -1,
- 67, 38, 141, 93, 133, 62, 133, -1, -1, 137,
- 65, 38, 134, 3, 138, 3, 138, 93, 133, -1,
- 83, 38, 141, 93, 133, -1, 60, 133, 83, 38,
- 141, 93, 3, -1, 72, 138, 3, -1, 78, 38,
- 141, 93, 133, -1, 55, 3, -1, 58, 3, -1,
- 66, 173, 3, -1, 75, 38, 148, 93, 3, -1,
- 70, 38, 148, 93, 3, -1, 89, 38, 148, 93,
- 3, -1, -1, 141, -1, -1, 140, -1, 142, -1,
- 142, -1, 141, 4, 141, -1, 143, -1, 142, 33,
- 142, -1, 142, 34, 142, -1, 142, 35, 142, -1,
- 142, 31, 142, -1, 142, 32, 142, -1, 142, 29,
- 142, -1, 142, 30, 142, -1, 142, 25, 142, -1,
- 142, 26, 142, -1, 142, 28, 142, -1, 142, 27,
- 142, -1, 142, 24, 142, -1, 142, 23, 142, -1,
- 142, 22, 142, -1, 142, 21, 142, -1, 142, 20,
- 142, -1, 142, 19, 142, -1, 142, 18, 142, -1,
- 142, 16, 141, 17, 142, -1, 142, 5, 142, -1,
- 142, 15, 142, -1, 142, 14, 142, -1, 142, 13,
- 142, -1, 142, 12, 142, -1, 142, 11, 142, -1,
- 142, 9, 142, -1, 142, 10, 142, -1, 142, 8,
- 142, -1, 142, 7, 142, -1, 142, 6, 142, -1,
- 144, -1, 38, 154, 119, 93, 143, -1, 38, 154,
- 119, 93, 95, 126, 96, -1, 145, -1, 33, 143,
- -1, 22, 143, -1, 31, 143, -1, 32, 143, -1,
- 97, 143, -1, 98, 143, -1, 40, 143, -1, 41,
- 143, -1, 74, 144, -1, 90, 144, -1, 38, 141,
- 93, -1, 74, 38, 154, 119, 93, -1, 90, 38,
- 154, 119, 93, -1, 145, 38, 148, 93, -1, 145,
- 37, 141, 94, -1, 145, 39, 173, -1, 145, 36,
- 173, -1, 145, 40, -1, 145, 41, -1, 171, -1,
- 46, -1, 47, -1, 48, -1, 49, -1, 45, -1,
- 44, -1, 50, -1, 51, -1, 146, -1, 147, -1,
- 52, -1, 146, 52, -1, 53, -1, 147, 53, -1,
- -1, 149, -1, 142, -1, 149, 4, 149, -1, -1,
- 95, 151, 113, 96, -1, -1, 155, -1, 156, -1,
- 168, -1, 165, -1, 156, 162, -1, 168, 162, -1,
- 165, 156, 163, -1, 165, 168, -1, 165, 168, 162,
- -1, 153, -1, 153, -1, 77, 173, -1, -1, 77,
- 173, 157, 150, -1, 77, 150, -1, 81, 173, -1,
- -1, 81, 173, 158, 150, -1, 81, 150, -1, 85,
- 173, -1, -1, -1, 85, 173, 159, 95, 160, 167,
- 96, -1, -1, 85, 95, 161, 167, 96, -1, 43,
- -1, 164, -1, 162, 164, -1, -1, 163, 170, -1,
- 168, -1, 170, -1, 169, -1, 166, -1, 165, 166,
- -1, 170, -1, 169, -1, 42, -1, 42, 5, 142,
- -1, 167, 4, -1, 167, 4, 167, -1, 57, -1,
- 73, -1, 68, -1, 69, -1, 86, -1, 82, -1,
- 64, -1, 61, -1, 84, -1, 54, -1, 76, -1,
- 63, -1, 79, -1, 80, -1, 71, -1, 92, -1,
- 87, -1, 88, -1, 91, -1, 42, -1, 173, -1,
- 42, -1, 43, -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
-{
- 0, 101, 101, 102, 108, 112, 114, 128, 113, 143,
- 148, 147, 155, 158, 159, 166, 167, 171, 175, 184,
- 188, 194, 200, 199, 211, 224, 225, 228, 232, 239,
- 238, 244, 243, 250, 254, 257, 261, 264, 269, 273,
- 282, 285, 288, 293, 298, 301, 302, 306, 312, 316,
- 320, 326, 327, 333, 337, 342, 345, 346, 350, 351,
- 357, 358, 359, 365, 368, 375, 376, 381, 386, 390,
- 396, 406, 409, 413, 419, 420, 426, 430, 434, 440,
- 444, 445, 451, 452, 458, 459, 459, 470, 476, 484,
- 484, 495, 499, 503, 508, 522, 526, 530, 534, 538,
- 542, 548, 551, 554, 557, 560, 567, 568, 574, 575,
- 579, 583, 587, 591, 595, 599, 603, 607, 611, 615,
- 619, 623, 627, 631, 635, 639, 643, 647, 651, 655,
- 659, 663, 667, 671, 675, 679, 683, 687, 691, 697,
- 698, 705, 713, 714, 718, 722, 726, 730, 734, 738,
- 742, 746, 750, 756, 760, 766, 772, 780, 784, 789,
- 794, 798, 802, 803, 810, 817, 824, 831, 838, 845,
- 852, 859, 860, 863, 873, 891, 901, 919, 922, 925,
- 926, 933, 932, 955, 959, 962, 967, 972, 978, 986,
- 992, 998, 1004, 1012, 1020, 1027, 1033, 1032, 1044, 1053,
- 1059, 1058, 1070, 1078, 1087, 1091, 1086, 1108, 1107, 1116,
- 1122, 1123, 1129, 1132, 1138, 1139, 1140, 1143, 1144, 1150,
- 1151, 1154, 1158, 1162, 1163, 1166, 1167, 1168, 1169, 1170,
- 1171, 1172, 1173, 1174, 1177, 1178, 1179, 1180, 1181, 1182,
- 1183, 1186, 1187, 1188, 1191, 1206, 1218, 1219
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-static const char *const yytname[] =
-{
- "$end", "error", "$undefined", "';'", "','", "'='", "LORE", "LXORE",
- "LANDE", "LLSHE", "LRSHE", "LMDE", "LDVE", "LMLE", "LME", "LPE", "'?'",
- "':'", "LOROR", "LANDAND", "'|'", "'^'", "'&'", "LNE", "LEQ", "'<'",
- "'>'", "LGE", "LLE", "LRSH", "LLSH", "'+'", "'-'", "'*'", "'/'", "'%'",
- "'.'", "'['", "'('", "LMG", "LPP", "LMM", "LNAME", "LTYPE", "LFCONST",
- "LDCONST", "LCONST", "LLCONST", "LUCONST", "LULCONST", "LVLCONST",
- "LUVLCONST", "LSTRING", "LLSTRING", "LAUTO", "LBREAK", "LCASE", "LCHAR",
- "LCONTINUE", "LDEFAULT", "LDO", "LDOUBLE", "LELSE", "LEXTERN", "LFLOAT",
- "LFOR", "LGOTO", "LIF", "LINT", "LLONG", "LPREFETCH", "LREGISTER",
- "LRETURN", "LSHORT", "LSIZEOF", "LUSED", "LSTATIC", "LSTRUCT", "LSWITCH",
- "LTYPEDEF", "LTYPESTR", "LUNION", "LUNSIGNED", "LWHILE", "LVOID",
- "LENUM", "LSIGNED", "LCONSTNT", "LVOLATILE", "LSET", "LSIGNOF",
- "LRESTRICT", "LINLINE", "')'", "']'", "'{'", "'}'", "'!'", "'~'",
- "$accept", "prog", "xdecl", "@1", "@2", "xdlist", "@3", "xdecor",
- "xdecor2", "adecl", "adlist", "@4", "pdecl", "pdlist", "edecl", "@5",
- "@6", "zedlist", "edlist", "edecor", "abdecor", "abdecor1", "abdecor2",
- "abdecor3", "init", "qual", "qlist", "ilist", "zarglist", "arglist",
- "block", "slist", "labels", "label", "stmnt", "forexpr", "ulstmnt", "@7",
- "@8", "zcexpr", "zexpr", "lexpr", "cexpr", "expr", "xuexpr", "uexpr",
- "pexpr", "string", "lstring", "zelist", "elist", "sbody", "@9",
- "zctlist", "types", "tlist", "ctlist", "complex", "@10", "@11", "@12",
- "@13", "@14", "gctnlist", "zgnlist", "gctname", "gcnlist", "gcname",
- "enum", "tname", "cname", "gname", "name", "tag", "ltag", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
-{
- 0, 256, 257, 59, 44, 61, 258, 259, 260, 261,
- 262, 263, 264, 265, 266, 267, 63, 58, 268, 269,
- 124, 94, 38, 270, 271, 60, 62, 272, 273, 274,
- 275, 43, 45, 42, 47, 37, 46, 91, 40, 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, 306,
- 307, 308, 309, 310, 311, 312, 313, 314, 315, 316,
- 317, 318, 319, 320, 321, 322, 323, 324, 325, 326,
- 327, 328, 329, 41, 93, 123, 125, 33, 126
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
-{
- 0, 99, 100, 100, 101, 101, 102, 103, 101, 104,
- 105, 104, 104, 106, 106, 107, 107, 107, 107, 108,
- 108, 109, 110, 109, 109, 111, 111, 112, 112, 114,
- 113, 115, 113, 116, 116, 117, 117, 118, 118, 118,
- 119, 119, 120, 120, 120, 121, 121, 121, 122, 122,
- 122, 123, 123, 124, 124, 124, 125, 125, 125, 125,
- 126, 126, 126, 127, 127, 128, 128, 128, 128, 128,
- 129, 130, 130, 130, 131, 131, 132, 132, 132, 133,
- 133, 133, 134, 134, 135, 136, 135, 135, 135, 137,
- 135, 135, 135, 135, 135, 135, 135, 135, 135, 135,
- 135, 138, 138, 139, 139, 140, 141, 141, 142, 142,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 143,
- 143, 143, 144, 144, 144, 144, 144, 144, 144, 144,
- 144, 144, 144, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 146, 146, 147, 147, 148, 148, 149,
- 149, 151, 150, 152, 152, 153, 153, 153, 153, 153,
- 153, 153, 153, 154, 155, 156, 157, 156, 156, 156,
- 158, 156, 156, 156, 159, 160, 156, 161, 156, 156,
- 162, 162, 163, 163, 164, 164, 164, 165, 165, 166,
- 166, 167, 167, 167, 167, 168, 168, 168, 168, 168,
- 168, 168, 168, 168, 169, 169, 169, 169, 169, 169,
- 169, 170, 170, 170, 171, 172, 173, 173
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 0, 2, 2, 3, 0, 0, 6, 1,
- 0, 4, 3, 1, 3, 1, 3, 4, 4, 2,
- 3, 1, 0, 4, 3, 0, 4, 1, 3, 0,
- 4, 0, 5, 0, 1, 1, 3, 1, 3, 2,
- 0, 1, 2, 3, 1, 1, 4, 4, 2, 3,
- 3, 1, 3, 3, 2, 2, 2, 3, 1, 2,
- 1, 1, 2, 0, 1, 1, 2, 2, 3, 3,
- 3, 0, 2, 2, 1, 2, 3, 2, 2, 2,
- 1, 2, 1, 2, 2, 0, 2, 5, 7, 0,
- 10, 5, 7, 3, 5, 2, 2, 3, 5, 5,
- 5, 0, 1, 0, 1, 1, 1, 3, 1, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 5, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
- 5, 7, 1, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 3, 5, 5, 4, 4, 3, 3,
- 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 2, 1, 2, 0, 1, 1,
- 3, 0, 4, 0, 1, 1, 1, 1, 2, 2,
- 3, 2, 3, 1, 1, 2, 0, 4, 2, 2,
- 0, 4, 2, 2, 0, 0, 7, 0, 5, 1,
- 1, 2, 0, 2, 1, 1, 1, 1, 2, 1,
- 1, 1, 3, 2, 3, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint8 yydefact[] =
-{
- 2, 183, 1, 209, 234, 225, 232, 236, 231, 227,
- 228, 239, 226, 235, 0, 237, 238, 0, 230, 233,
- 0, 229, 241, 242, 243, 240, 3, 0, 194, 184,
- 185, 187, 217, 186, 220, 219, 246, 247, 181, 198,
- 195, 202, 199, 207, 203, 4, 212, 0, 0, 6,
- 13, 15, 245, 188, 210, 214, 216, 215, 212, 218,
- 191, 189, 0, 0, 0, 0, 0, 0, 0, 5,
- 0, 25, 0, 103, 63, 211, 190, 192, 0, 193,
- 29, 197, 201, 221, 0, 205, 14, 213, 16, 12,
- 9, 7, 0, 0, 0, 0, 0, 0, 0, 0,
- 244, 168, 167, 163, 164, 165, 166, 169, 170, 173,
- 175, 0, 0, 0, 0, 0, 104, 105, 108, 139,
- 142, 171, 172, 162, 0, 0, 64, 40, 65, 182,
- 31, 33, 0, 223, 208, 0, 0, 0, 0, 11,
- 51, 144, 145, 146, 143, 0, 106, 40, 149, 150,
- 0, 151, 0, 152, 147, 148, 18, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 177,
- 0, 160, 161, 174, 176, 0, 17, 0, 212, 103,
- 0, 67, 66, 41, 44, 45, 33, 0, 37, 0,
- 34, 35, 15, 222, 224, 0, 71, 8, 27, 0,
- 0, 0, 61, 58, 60, 0, 0, 153, 212, 0,
- 0, 40, 40, 128, 138, 137, 136, 134, 135, 133,
- 132, 131, 130, 129, 0, 126, 125, 124, 123, 122,
- 121, 120, 116, 117, 119, 118, 114, 115, 112, 113,
- 109, 110, 111, 159, 0, 179, 0, 178, 158, 68,
- 69, 42, 0, 48, 0, 103, 63, 0, 39, 30,
- 0, 0, 206, 0, 26, 0, 54, 0, 56, 55,
- 62, 59, 52, 107, 42, 0, 0, 0, 0, 157,
- 156, 0, 43, 49, 50, 0, 0, 32, 36, 38,
- 0, 244, 0, 0, 0, 0, 0, 0, 0, 0,
- 101, 0, 0, 0, 0, 70, 72, 85, 74, 73,
- 80, 0, 0, 0, 102, 0, 28, 53, 57, 0,
- 140, 154, 155, 127, 180, 47, 46, 79, 78, 95,
- 0, 96, 77, 0, 0, 0, 177, 0, 177, 0,
- 0, 177, 75, 81, 86, 0, 84, 19, 21, 0,
- 0, 76, 0, 97, 0, 0, 93, 0, 0, 0,
- 0, 101, 0, 20, 0, 141, 0, 0, 0, 0,
- 0, 0, 0, 0, 82, 0, 0, 24, 0, 87,
- 99, 98, 94, 91, 100, 101, 83, 23, 0, 0,
- 0, 92, 88, 101, 0, 0, 90
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int16 yydefgoto[] =
-{
- -1, 1, 26, 71, 136, 48, 72, 208, 50, 326,
- 369, 382, 91, 219, 78, 131, 206, 209, 210, 211,
- 202, 203, 204, 205, 222, 223, 224, 225, 125, 126,
- 217, 283, 327, 328, 329, 393, 330, 331, 332, 333,
- 115, 116, 334, 146, 118, 119, 120, 121, 122, 266,
- 267, 39, 62, 27, 79, 127, 29, 30, 63, 64,
- 66, 135, 65, 53, 67, 54, 31, 32, 84, 33,
- 34, 35, 123, 51, 52
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -331
-static const yytype_int16 yypact[] =
-{
- -331, 548, -331, -331, -331, -331, -331, -331, -331, -331,
- -331, -331, -331, -331, -3, -331, -331, -3, -331, -331,
- 149, -331, -331, -331, -331, -331, -331, 264, -331, -331,
- 965, 929, -331, 965, -331, -331, -331, -331, -331, -331,
- -75, -331, -72, -331, -60, -331, -331, 307, 60, 270,
- 156, -331, -331, 965, -331, -331, -331, -331, -331, -331,
- 965, 965, 929, -44, -44, 29, -15, 199, -10, -331,
- 307, -331, 83, 756, 849, -331, 140, 965, 889, -331,
- -331, -331, -331, 86, 12, -331, -331, -331, -331, -331,
- 90, 929, 686, 756, 756, 756, 756, 615, 756, 756,
- -331, -331, -331, -331, -331, -331, -331, -331, -331, -331,
- -331, 791, 826, 756, 756, 9, -331, 1084, -331, -331,
- 708, 54, 57, -331, 110, 56, 152, 310, -331, -331,
- -331, 279, 756, 29, -331, 29, 63, 307, 165, -331,
- 1084, -331, -331, -331, -331, 30, 1084, 44, -331, -331,
- 615, -331, 615, -331, -331, -331, -331, 756, 756, 756,
- 756, 756, 756, 756, 756, 756, 756, 756, 756, 756,
- 756, 756, 756, 756, 756, 756, 756, 756, 756, 756,
- 756, 756, 756, 756, 756, 756, 756, 157, 756, 756,
- 157, -331, -331, -331, -331, 115, -331, 849, -331, 756,
- 128, -331, -331, -331, 182, -331, 279, 756, -331, 164,
- 200, -331, 208, 1084, -331, 13, -331, -331, -331, 262,
- 157, 756, 225, 228, 165, 73, 756, -331, -331, -7,
- 150, 44, 44, 1084, 1084, 1084, 1084, 1084, 1084, 1084,
- 1084, 1084, 1084, 1084, 28, 304, 1100, 1115, 1129, 1142,
- 1153, 1153, 433, 433, 433, 433, 333, 333, 265, 265,
- -331, -331, -331, -331, 8, 1084, 153, 236, -331, -331,
- -331, 147, 158, -331, 161, 756, 849, 247, -331, -331,
- 279, 756, -331, 341, -331, 307, -331, 175, -331, -331,
- 254, 228, -331, -331, 135, 721, 188, 190, 756, -331,
- -331, 756, -331, -331, -331, 191, 211, -331, -331, -331,
- 298, 301, 338, 756, 343, 339, 439, 157, 319, 321,
- 756, 322, 323, 324, 332, -331, -331, 509, -331, -331,
- -331, 63, 306, 372, 373, 277, -331, -331, -331, 165,
- -331, -331, -331, 425, -331, -331, -331, -331, -331, -331,
- 1053, -331, -331, 293, 375, 756, 756, 400, 756, 756,
- 756, 756, -331, -331, -331, 396, -331, -331, 430, 285,
- 377, -331, 431, -331, 55, 381, -331, 382, 62, 64,
- 383, 615, 473, -331, 307, -331, 756, 439, 479, 490,
- 439, 439, 493, 497, -331, 307, 686, -331, 66, 440,
- -331, -331, -331, -331, -331, 756, 499, -331, 498, 439,
- 504, -331, -331, 756, 415, 439, -331
-};
-
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int16 yypgoto[] =
-{
- -331, -331, -331, -331, -331, 445, -331, -26, -331, -331,
- -330, -331, -331, 233, -331, -331, -331, 313, 230, -331,
- -132, -187, -331, -331, -82, 292, -331, 181, 245, 326,
- 193, -331, -331, 198, -227, -331, 203, -331, -331, -309,
- -181, -183, -83, -45, -38, 243, -331, -331, -331, -175,
- 226, 10, -331, -331, -1, 0, -88, 495, -331, -331,
- -331, -331, -331, -14, -51, -28, -331, 501, -85, 218,
- 231, -24, -52, -127, -12
-};
-
-/* 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 -205
-static const yytype_int16 yytable[] =
-{
- 28, 49, 40, 137, 212, 42, 57, 76, 44, 57,
- 139, 357, 226, 274, 145, 230, 133, 133, 272, 61,
- -196, 68, 128, -200, 278, 75, 228, 41, 117, 57,
- 199, 229, 226, 75, 226, -204, 57, 57, 287, 36,
- 37, 86, 274, 87, 90, 298, 77, 140, 214, 75,
- 215, 38, 87, 57, 397, 141, 142, 143, 144, 226,
- 148, 149, 80, 69, 70, 406, 226, 145, 226, 145,
- 226, 83, 394, 81, 82, 154, 155, 228, 130, 212,
- 85, 199, 229, 88, 302, 244, 273, 213, 92, 353,
- 28, 132, 38, 140, 305, -10, 410, 147, 309, 296,
- 297, 201, 299, 156, 414, 264, 193, 302, 134, 282,
- 194, 218, 233, 234, 235, 236, 237, 238, 239, 240,
- 241, 242, 243, 227, 245, 246, 247, 248, 249, 250,
- 251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
- 261, 262, 290, 293, 265, 128, 195, 271, 387, 196,
- 231, 269, 232, 212, 117, 390, 197, 391, 216, 408,
- 399, 198, 117, 402, 403, 199, 200, 279, 228, 292,
- 36, 37, 199, 229, 68, 263, 117, 294, 268, 140,
- 198, 375, 412, 377, 199, 200, 380, 93, 416, 36,
- 37, 36, 37, 73, 74, 335, 94, 95, 96, 36,
- 37, 220, 221, 97, 280, 98, 99, 100, 286, 101,
- 102, 103, 104, 105, 106, 107, 108, 109, 110, 275,
- 276, 273, 22, 23, 128, 281, 24, 22, 23, 288,
- 117, 24, 46, 289, 22, 23, 117, 47, 24, 111,
- 301, 36, 37, 295, 43, 86, 300, 87, 55, 60,
- 307, 55, 303, 343, 304, 112, 265, 340, 338, 218,
- 138, 56, 113, 114, 56, 284, 285, 45, 350, 337,
- 87, 55, 374, -9, -9, -10, 378, 379, 55, 55,
- 367, 341, 28, 342, 56, 345, 22, 23, 383, 384,
- 24, 56, 56, 395, 140, 55, 207, 46, 184, 185,
- 186, 347, 47, 398, 346, 354, 36, 37, 56, 368,
- 46, 265, 46, 265, 407, 47, 265, 47, 348, 36,
- 37, 36, 37, 170, 171, 172, 173, 174, 175, 176,
- 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
- 46, 349, 310, 198, -101, 47, 351, 199, 200, 36,
- 37, 140, 36, 37, 151, 153, 352, 355, 368, 356,
- 358, 359, 360, 93, 182, 183, 184, 185, 186, 368,
- 361, 365, 94, 95, 96, 366, 372, 226, 373, 97,
- 28, 98, 99, 311, 3, 101, 102, 103, 104, 105,
- 106, 107, 108, 109, 110, 4, 312, 313, 5, 314,
- 315, 316, 6, 376, 7, 8, -89, 317, 318, 9,
- 10, 319, 11, 320, 12, 111, 321, 13, 14, 322,
- 15, 16, 17, 18, 323, 19, 20, 21, 22, 23,
- 324, 112, 24, 25, 381, -22, -85, 325, 113, 114,
- 310, 168, -101, 169, 170, 171, 172, 173, 174, 175,
- 176, 177, 178, 179, 180, 181, 182, 183, 184, 185,
- 186, 93, 180, 181, 182, 183, 184, 185, 186, 386,
- 94, 95, 96, 385, 388, 389, 392, 97, 396, 98,
- 99, 311, 400, 101, 102, 103, 104, 105, 106, 107,
- 108, 109, 110, 401, 312, 313, 404, 314, 315, 316,
- 405, 411, 409, 384, -89, 317, 318, 413, 415, 319,
- 308, 320, -101, 111, 321, 89, 291, 322, 336, 277,
- 370, 306, 323, 270, 364, 362, 58, 344, 324, 112,
- 363, 93, 59, 0, -85, 0, 113, 114, 0, 0,
- 94, 95, 96, 0, 0, 0, 0, 97, 2, 98,
- 99, 311, 0, 101, 102, 103, 104, 105, 106, 107,
- 108, 109, 110, 0, 312, 313, 0, 314, 315, 316,
- 0, 0, 0, 0, -89, 317, 318, 0, 0, 319,
- 0, 320, 0, 111, 321, 0, 0, 322, 0, 0,
- 0, 3, 323, 0, 0, 0, 0, 0, 324, 112,
- 0, 0, 4, 0, 0, 5, 113, 114, 0, 6,
- 0, 7, 8, 0, 0, 0, 9, 10, 0, 11,
- 0, 12, 0, 0, 13, 14, 0, 15, 16, 17,
- 18, 0, 19, 20, 21, 22, 23, 93, 0, 24,
- 25, 0, 0, 0, 0, 0, 94, 95, 96, 0,
- 0, 0, 0, 97, 0, 98, 99, 100, 3, 101,
- 102, 103, 104, 105, 106, 107, 108, 109, 110, 4,
- 0, 0, 5, 0, 0, 0, 6, 0, 7, 8,
- 0, 0, 0, 9, 10, 0, 11, 0, 12, 111,
- 0, 13, 14, 0, 15, 16, 17, 18, 0, 19,
- 20, 21, 22, 23, 0, 112, 24, 25, 93, 0,
- 0, 0, 113, 114, 0, 0, 0, 94, 95, 96,
- 0, 0, 0, 0, 97, 0, 98, 99, 100, 0,
- 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- 0, 0, 0, 93, 187, 188, 189, 190, 191, 192,
- 0, 0, 94, 95, 96, 0, 0, 0, 0, 97,
- 111, 98, 99, 100, 0, 101, 102, 103, 104, 105,
- 106, 107, 108, 109, 110, 0, 112, 0, 93, 0,
- 0, 138, 0, 113, 114, 0, 0, 94, 95, 96,
- 0, 0, 0, 0, 97, 111, 98, 99, 100, 0,
- 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- 0, 112, 0, 93, 0, 0, 339, 0, 113, 114,
- 0, 0, 94, 95, 96, 0, 0, 0, 0, 150,
- 111, 98, 99, 100, 0, 101, 102, 103, 104, 105,
- 106, 107, 108, 109, 110, 0, 112, 0, 93, 0,
- 0, 0, 0, 113, 114, 0, 0, 94, 95, 96,
- 0, 0, 0, 0, 152, 111, 98, 99, 100, 0,
- 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- 0, 112, 0, 0, 0, 124, 0, 0, 113, 114,
- 0, 100, 3, 0, 0, 0, 0, 0, 0, 0,
- 111, 0, 0, 4, 0, 0, 5, 0, 0, 0,
- 6, 0, 7, 8, 0, 0, 112, 9, 10, 0,
- 11, 0, 12, 113, 114, 13, 14, 0, 15, 16,
- 17, 18, 3, 19, 20, 21, 22, 23, 0, 0,
- 24, 25, 0, 4, 0, 0, 5, 0, 0, 0,
- 6, 0, 7, 8, 0, 0, 0, 9, 10, 0,
- 11, 0, 12, 0, 0, 13, 14, 0, 15, 16,
- 17, 18, 3, 19, 20, 21, 22, 23, 0, 0,
- 24, 25, 0, 4, 0, 129, 5, 0, 0, 0,
- 6, 0, 7, 8, 0, 0, 0, 9, 10, 0,
- 11, 0, 12, 0, 0, 13, 14, 0, 15, 16,
- 17, 18, 0, 19, 20, 21, 22, 23, 0, 4,
- 24, 25, 5, 0, 0, 0, 6, 0, 7, 8,
- 0, 0, 0, 9, 10, 0, 11, 0, 12, 0,
- 0, 13, 0, 0, 15, 16, 0, 18, 0, 19,
- 0, 21, 22, 23, 0, 0, 24, 25, 157, 158,
- 159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
- 371, 169, 170, 171, 172, 173, 174, 175, 176, 177,
- 178, 179, 180, 181, 182, 183, 184, 185, 186, 157,
- 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
- 168, 0, 169, 170, 171, 172, 173, 174, 175, 176,
- 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
- 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
- 181, 182, 183, 184, 185, 186, 172, 173, 174, 175,
- 176, 177, 178, 179, 180, 181, 182, 183, 184, 185,
- 186, 173, 174, 175, 176, 177, 178, 179, 180, 181,
- 182, 183, 184, 185, 186, 174, 175, 176, 177, 178,
- 179, 180, 181, 182, 183, 184, 185, 186, 176, 177,
- 178, 179, 180, 181, 182, 183, 184, 185, 186
-};
-
-static const yytype_int16 yycheck[] =
-{
- 1, 27, 14, 91, 131, 17, 30, 58, 20, 33,
- 92, 320, 4, 200, 97, 147, 4, 4, 199, 33,
- 95, 47, 74, 95, 207, 53, 33, 17, 73, 53,
- 37, 38, 4, 61, 4, 95, 60, 61, 221, 42,
- 43, 67, 229, 67, 70, 17, 60, 92, 133, 77,
- 135, 95, 76, 77, 384, 93, 94, 95, 96, 4,
- 98, 99, 62, 3, 4, 395, 4, 150, 4, 152,
- 4, 42, 381, 63, 64, 113, 114, 33, 78, 206,
- 95, 37, 38, 93, 271, 168, 93, 132, 5, 316,
- 91, 5, 95, 138, 275, 5, 405, 97, 281, 231,
- 232, 127, 94, 94, 413, 188, 52, 294, 96, 96,
- 53, 137, 157, 158, 159, 160, 161, 162, 163, 164,
- 165, 166, 167, 93, 169, 170, 171, 172, 173, 174,
- 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
- 185, 186, 224, 226, 189, 197, 36, 198, 93, 93,
- 150, 36, 152, 280, 199, 93, 4, 93, 95, 93,
- 387, 33, 207, 390, 391, 37, 38, 3, 33, 96,
- 42, 43, 37, 38, 200, 187, 221, 228, 190, 224,
- 33, 356, 409, 358, 37, 38, 361, 22, 415, 42,
- 43, 42, 43, 37, 38, 283, 31, 32, 33, 42,
- 43, 36, 37, 38, 4, 40, 41, 42, 220, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 37,
- 38, 93, 87, 88, 276, 17, 91, 87, 88, 4,
- 275, 91, 33, 5, 87, 88, 281, 38, 91, 74,
- 4, 42, 43, 93, 95, 271, 93, 271, 30, 31,
- 3, 33, 94, 298, 93, 90, 301, 295, 4, 285,
- 95, 30, 97, 98, 33, 3, 4, 3, 313, 94,
- 294, 53, 355, 3, 4, 5, 359, 360, 60, 61,
- 3, 93, 283, 93, 53, 94, 87, 88, 3, 4,
- 91, 60, 61, 381, 339, 77, 17, 33, 33, 34,
- 35, 3, 38, 386, 93, 317, 42, 43, 77, 335,
- 33, 356, 33, 358, 396, 38, 361, 38, 17, 42,
- 43, 42, 43, 19, 20, 21, 22, 23, 24, 25,
- 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
- 33, 3, 1, 33, 3, 38, 3, 37, 38, 42,
- 43, 396, 42, 43, 111, 112, 17, 38, 384, 38,
- 38, 38, 38, 22, 31, 32, 33, 34, 35, 395,
- 38, 65, 31, 32, 33, 3, 83, 4, 3, 38,
- 381, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 3, 63, 64, 65, 66, 67, 68,
- 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
- 89, 90, 91, 92, 38, 5, 95, 96, 97, 98,
- 1, 16, 3, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 22, 29, 30, 31, 32, 33, 34, 35, 38,
- 31, 32, 33, 96, 93, 93, 93, 38, 5, 40,
- 41, 42, 3, 44, 45, 46, 47, 48, 49, 50,
- 51, 52, 53, 3, 55, 56, 3, 58, 59, 60,
- 3, 3, 62, 4, 65, 66, 67, 3, 93, 70,
- 280, 72, 3, 74, 75, 70, 224, 78, 285, 206,
- 339, 276, 83, 197, 331, 327, 31, 301, 89, 90,
- 327, 22, 31, -1, 95, -1, 97, 98, -1, -1,
- 31, 32, 33, -1, -1, -1, -1, 38, 0, 40,
- 41, 42, -1, 44, 45, 46, 47, 48, 49, 50,
- 51, 52, 53, -1, 55, 56, -1, 58, 59, 60,
- -1, -1, -1, -1, 65, 66, 67, -1, -1, 70,
- -1, 72, -1, 74, 75, -1, -1, 78, -1, -1,
- -1, 43, 83, -1, -1, -1, -1, -1, 89, 90,
- -1, -1, 54, -1, -1, 57, 97, 98, -1, 61,
- -1, 63, 64, -1, -1, -1, 68, 69, -1, 71,
- -1, 73, -1, -1, 76, 77, -1, 79, 80, 81,
- 82, -1, 84, 85, 86, 87, 88, 22, -1, 91,
- 92, -1, -1, -1, -1, -1, 31, 32, 33, -1,
- -1, -1, -1, 38, -1, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- -1, -1, 57, -1, -1, -1, 61, -1, 63, 64,
- -1, -1, -1, 68, 69, -1, 71, -1, 73, 74,
- -1, 76, 77, -1, 79, 80, 81, 82, -1, 84,
- 85, 86, 87, 88, -1, 90, 91, 92, 22, -1,
- -1, -1, 97, 98, -1, -1, -1, 31, 32, 33,
- -1, -1, -1, -1, 38, -1, 40, 41, 42, -1,
- 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- -1, -1, -1, 22, 36, 37, 38, 39, 40, 41,
- -1, -1, 31, 32, 33, -1, -1, -1, -1, 38,
- 74, 40, 41, 42, -1, 44, 45, 46, 47, 48,
- 49, 50, 51, 52, 53, -1, 90, -1, 22, -1,
- -1, 95, -1, 97, 98, -1, -1, 31, 32, 33,
- -1, -1, -1, -1, 38, 74, 40, 41, 42, -1,
- 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- -1, 90, -1, 22, -1, -1, 95, -1, 97, 98,
- -1, -1, 31, 32, 33, -1, -1, -1, -1, 38,
- 74, 40, 41, 42, -1, 44, 45, 46, 47, 48,
- 49, 50, 51, 52, 53, -1, 90, -1, 22, -1,
- -1, -1, -1, 97, 98, -1, -1, 31, 32, 33,
- -1, -1, -1, -1, 38, 74, 40, 41, 42, -1,
- 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- -1, 90, -1, -1, -1, 36, -1, -1, 97, 98,
- -1, 42, 43, -1, -1, -1, -1, -1, -1, -1,
- 74, -1, -1, 54, -1, -1, 57, -1, -1, -1,
- 61, -1, 63, 64, -1, -1, 90, 68, 69, -1,
- 71, -1, 73, 97, 98, 76, 77, -1, 79, 80,
- 81, 82, 43, 84, 85, 86, 87, 88, -1, -1,
- 91, 92, -1, 54, -1, -1, 57, -1, -1, -1,
- 61, -1, 63, 64, -1, -1, -1, 68, 69, -1,
- 71, -1, 73, -1, -1, 76, 77, -1, 79, 80,
- 81, 82, 43, 84, 85, 86, 87, 88, -1, -1,
- 91, 92, -1, 54, -1, 96, 57, -1, -1, -1,
- 61, -1, 63, 64, -1, -1, -1, 68, 69, -1,
- 71, -1, 73, -1, -1, 76, 77, -1, 79, 80,
- 81, 82, -1, 84, 85, 86, 87, 88, -1, 54,
- 91, 92, 57, -1, -1, -1, 61, -1, 63, 64,
- -1, -1, -1, 68, 69, -1, 71, -1, 73, -1,
- -1, 76, -1, -1, 79, 80, -1, 82, -1, 84,
- -1, 86, 87, 88, -1, -1, 91, 92, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
- 27, 28, 29, 30, 31, 32, 33, 34, 35, 5,
- 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, -1, 18, 19, 20, 21, 22, 23, 24, 25,
- 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
- 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, 32, 33, 34, 35, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 22, 23, 24, 25, 26, 27, 28, 29, 30,
- 31, 32, 33, 34, 35, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35, 25, 26,
- 27, 28, 29, 30, 31, 32, 33, 34, 35
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
-{
- 0, 100, 0, 43, 54, 57, 61, 63, 64, 68,
- 69, 71, 73, 76, 77, 79, 80, 81, 82, 84,
- 85, 86, 87, 88, 91, 92, 101, 152, 153, 155,
- 156, 165, 166, 168, 169, 170, 42, 43, 95, 150,
- 173, 150, 173, 95, 173, 3, 33, 38, 104, 106,
- 107, 172, 173, 162, 164, 168, 169, 170, 156, 166,
- 168, 162, 151, 157, 158, 161, 159, 163, 106, 3,
- 4, 102, 105, 37, 38, 164, 163, 162, 113, 153,
- 154, 150, 150, 42, 167, 95, 106, 170, 93, 104,
- 106, 111, 5, 22, 31, 32, 33, 38, 40, 41,
- 42, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- 53, 74, 90, 97, 98, 139, 140, 142, 143, 144,
- 145, 146, 147, 171, 36, 127, 128, 154, 171, 96,
- 154, 114, 5, 4, 96, 160, 103, 155, 95, 123,
- 142, 143, 143, 143, 143, 141, 142, 154, 143, 143,
- 38, 144, 38, 144, 143, 143, 94, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15, 16, 18,
- 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
- 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- 39, 40, 41, 52, 53, 36, 93, 4, 33, 37,
- 38, 106, 119, 120, 121, 122, 115, 17, 106, 116,
- 117, 118, 172, 142, 167, 167, 95, 129, 106, 112,
- 36, 37, 123, 124, 125, 126, 4, 93, 33, 38,
- 119, 154, 154, 142, 142, 142, 142, 142, 142, 142,
- 142, 142, 142, 142, 141, 142, 142, 142, 142, 142,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 142, 142, 142, 173, 141, 142, 148, 149, 173, 36,
- 128, 163, 139, 93, 120, 37, 38, 116, 140, 3,
- 4, 17, 96, 130, 3, 4, 173, 140, 4, 5,
- 123, 124, 96, 141, 163, 93, 119, 119, 17, 94,
- 93, 4, 120, 94, 93, 139, 127, 3, 117, 140,
- 1, 42, 55, 56, 58, 59, 60, 66, 67, 70,
- 72, 75, 78, 83, 89, 96, 108, 131, 132, 133,
- 135, 136, 137, 138, 141, 155, 112, 94, 4, 95,
- 143, 93, 93, 142, 149, 94, 93, 3, 17, 3,
- 142, 3, 17, 133, 173, 38, 38, 138, 38, 38,
- 38, 38, 132, 135, 129, 65, 3, 3, 106, 109,
- 126, 17, 83, 3, 141, 148, 3, 148, 141, 141,
- 148, 38, 110, 3, 4, 96, 38, 93, 93, 93,
- 93, 93, 93, 134, 138, 155, 5, 109, 141, 133,
- 3, 3, 133, 133, 3, 3, 109, 123, 93, 62,
- 138, 3, 133, 3, 138, 93, 133
-};
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-
-#define YYFAIL goto yyerrlab
-
-#define YYRECOVERING() (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
- yyerror (YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (!yyvaluep)
- return;
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- yy_symbol_value_print (yyoutput, yytype, yyvaluep);
- YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included). |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
- yytype_int16 *bottom;
- yytype_int16 *top;
-#endif
-{
- YYFPRINTF (stderr, "Stack now");
- for (; bottom <= top; ++bottom)
- YYFPRINTF (stderr, " %d", *bottom);
- YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced. |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
- YYSTYPE *yyvsp;
- int yyrule;
-#endif
-{
- int yynrhs = yyr2[yyrule];
- int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- fprintf (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
- fprintf (stderr, "\n");
- }
-}
-
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
-{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
- continue;
- return yylen;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
-{
- char *yyd = yydest;
- const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
-
- if (! yyres)
- return yystrlen (yystr);
-
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
-
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
- }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol. |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
-{
- YYUSE (yyvaluep);
-
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
- switch (yytype)
- {
-
- default:
- break;
- }
-}
-
-
-/* Prevent warnings from -Wmissing-prototypes. */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol. */
-int yychar;
-
-/* The semantic value of the look-ahead symbol. */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far. */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse. |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-
- int yystate;
- int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Look-ahead token as an internal (translated) token number. */
- int yytoken = 0;
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss = yyssa;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
-
- YYSIZE_T yystacksize = YYINITDEPTH;
-
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
-
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
-
- yyssp = yyss;
- yyvsp = yyvs;
-
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyss + yystacksize - 1 <= yyssp)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
-
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
-
- &yystacksize);
-
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
-# else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
-
- {
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
-
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- goto yybackup;
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
- /* Do appropriate processing given the current state. Read a
- look-ahead token if we need one and don't already have one. */
-
- /* First try to decide what to do without reference to look-ahead token. */
- yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
- goto yydefault;
-
- /* Not known => get a look-ahead token if don't already have one. */
-
- /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
- {
- yychar = yytoken = YYEOF;
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yytoken = YYTRANSLATE (yychar);
- YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
- }
-
- /* If the proper action on seeing token YYTOKEN is to reduce or to
- detect an error, take that action. */
- yyn += yytoken;
- if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
- goto yydefault;
- yyn = yytable[yyn];
- if (yyn <= 0)
- {
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- /* Shift the look-ahead token. */
- YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
- /* Discard the shifted token unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- yystate = yyn;
- *++yyvsp = yylval;
-
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
-
- YY_REDUCE_PRINT (yyn);
- switch (yyn)
- {
- case 4:
-#line 109 "cc.y"
- {
- dodecl(xdecl, lastclass, lasttype, Z);
- }
- break;
-
- case 6:
-#line 114 "cc.y"
- {
- lastdcl = T;
- firstarg = S;
- dodecl(xdecl, lastclass, lasttype, (yyvsp[(2) - (2)].node));
- if(lastdcl == T || lastdcl->etype != TFUNC) {
- diag((yyvsp[(2) - (2)].node), "not a function");
- lastdcl = types[TFUNC];
- }
- thisfn = lastdcl;
- markdcl();
- firstdcl = dclstack;
- argmark((yyvsp[(2) - (2)].node), 0);
- }
- break;
-
- case 7:
-#line 128 "cc.y"
- {
- argmark((yyvsp[(2) - (4)].node), 1);
- }
- break;
-
- case 8:
-#line 132 "cc.y"
- {
- Node *n;
-
- n = revertdcl();
- if(n)
- (yyvsp[(6) - (6)].node) = new(OLIST, n, (yyvsp[(6) - (6)].node));
- if(!debug['a'] && !debug['Z'])
- codgen((yyvsp[(6) - (6)].node), (yyvsp[(2) - (6)].node));
- }
- break;
-
- case 9:
-#line 144 "cc.y"
- {
- dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
- }
- break;
-
- case 10:
-#line 148 "cc.y"
- {
- (yyvsp[(1) - (1)].node) = dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
- }
- break;
-
- case 11:
-#line 152 "cc.y"
- {
- doinit((yyvsp[(1) - (4)].node)->sym, (yyvsp[(1) - (4)].node)->type, 0L, (yyvsp[(4) - (4)].node));
- }
- break;
-
- case 14:
-#line 160 "cc.y"
- {
- (yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z);
- (yyval.node)->garb = simpleg((yyvsp[(2) - (3)].lval));
- }
- break;
-
- case 16:
-#line 168 "cc.y"
- {
- (yyval.node) = (yyvsp[(2) - (3)].node);
- }
- break;
-
- case 17:
-#line 172 "cc.y"
- {
- (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
- }
- break;
-
- case 18:
-#line 176 "cc.y"
- {
- (yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
- }
- break;
-
- case 19:
-#line 185 "cc.y"
- {
- (yyval.node) = dodecl(adecl, lastclass, lasttype, Z);
- }
- break;
-
- case 20:
-#line 189 "cc.y"
- {
- (yyval.node) = (yyvsp[(2) - (3)].node);
- }
- break;
-
- case 21:
-#line 195 "cc.y"
- {
- dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
- (yyval.node) = Z;
- }
- break;
-
- case 22:
-#line 200 "cc.y"
- {
- (yyvsp[(1) - (1)].node) = dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
- }
- break;
-
- case 23:
-#line 204 "cc.y"
- {
- int32 w;
-
- w = (yyvsp[(1) - (4)].node)->sym->type->width;
- (yyval.node) = doinit((yyvsp[(1) - (4)].node)->sym, (yyvsp[(1) - (4)].node)->type, 0L, (yyvsp[(4) - (4)].node));
- (yyval.node) = contig((yyvsp[(1) - (4)].node)->sym, (yyval.node), w);
- }
- break;
-
- case 24:
-#line 212 "cc.y"
- {
- (yyval.node) = (yyvsp[(1) - (3)].node);
- if((yyvsp[(3) - (3)].node) != Z) {
- (yyval.node) = (yyvsp[(3) - (3)].node);
- if((yyvsp[(1) - (3)].node) != Z)
- (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- }
- break;
-
- case 27:
-#line 229 "cc.y"
- {
- dodecl(pdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
- }
- break;
-
- case 29:
-#line 239 "cc.y"
- {
- lasttype = (yyvsp[(1) - (1)].type);
- }
- break;
-
- case 31:
-#line 244 "cc.y"
- {
- lasttype = (yyvsp[(2) - (2)].type);
- }
- break;
-
- case 33:
-#line 250 "cc.y"
- {
- lastfield = 0;
- edecl(CXXX, lasttype, S);
- }
- break;
-
- case 35:
-#line 258 "cc.y"
- {
- dodecl(edecl, CXXX, lasttype, (yyvsp[(1) - (1)].node));
- }
- break;
-
- case 37:
-#line 265 "cc.y"
- {
- lastbit = 0;
- firstbit = 1;
- }
- break;
-
- case 38:
-#line 270 "cc.y"
- {
- (yyval.node) = new(OBIT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 39:
-#line 274 "cc.y"
- {
- (yyval.node) = new(OBIT, Z, (yyvsp[(2) - (2)].node));
- }
- break;
-
- case 40:
-#line 282 "cc.y"
- {
- (yyval.node) = (Z);
- }
- break;
-
- case 42:
-#line 289 "cc.y"
- {
- (yyval.node) = new(OIND, (Z), Z);
- (yyval.node)->garb = simpleg((yyvsp[(2) - (2)].lval));
- }
- break;
-
- case 43:
-#line 294 "cc.y"
- {
- (yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z);
- (yyval.node)->garb = simpleg((yyvsp[(2) - (3)].lval));
- }
- break;
-
- case 46:
-#line 303 "cc.y"
- {
- (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
- }
- break;
-
- case 47:
-#line 307 "cc.y"
- {
- (yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
- }
- break;
-
- case 48:
-#line 313 "cc.y"
- {
- (yyval.node) = new(OFUNC, (Z), Z);
- }
- break;
-
- case 49:
-#line 317 "cc.y"
- {
- (yyval.node) = new(OARRAY, (Z), (yyvsp[(2) - (3)].node));
- }
- break;
-
- case 50:
-#line 321 "cc.y"
- {
- (yyval.node) = (yyvsp[(2) - (3)].node);
- }
- break;
-
- case 52:
-#line 328 "cc.y"
- {
- (yyval.node) = new(OINIT, invert((yyvsp[(2) - (3)].node)), Z);
- }
- break;
-
- case 53:
-#line 334 "cc.y"
- {
- (yyval.node) = new(OARRAY, (yyvsp[(2) - (3)].node), Z);
- }
- break;
-
- case 54:
-#line 338 "cc.y"
- {
- (yyval.node) = new(OELEM, Z, Z);
- (yyval.node)->sym = (yyvsp[(2) - (2)].sym);
- }
- break;
-
- case 57:
-#line 347 "cc.y"
- {
- (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].node));
- }
- break;
-
- case 59:
-#line 352 "cc.y"
- {
- (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
- }
- break;
-
- case 62:
-#line 360 "cc.y"
- {
- (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
- }
- break;
-
- case 63:
-#line 365 "cc.y"
- {
- (yyval.node) = Z;
- }
- break;
-
- case 64:
-#line 369 "cc.y"
- {
- (yyval.node) = invert((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 66:
-#line 377 "cc.y"
- {
- (yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z);
- (yyval.node)->type = (yyvsp[(1) - (2)].type);
- }
- break;
-
- case 67:
-#line 382 "cc.y"
- {
- (yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z);
- (yyval.node)->type = (yyvsp[(1) - (2)].type);
- }
- break;
-
- case 68:
-#line 387 "cc.y"
- {
- (yyval.node) = new(ODOTDOT, Z, Z);
- }
- break;
-
- case 69:
-#line 391 "cc.y"
- {
- (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 70:
-#line 397 "cc.y"
- {
- (yyval.node) = invert((yyvsp[(2) - (3)].node));
- // if($2 != Z)
- // $$ = new(OLIST, $2, $$);
- if((yyval.node) == Z)
- (yyval.node) = new(OLIST, Z, Z);
- }
- break;
-
- case 71:
-#line 406 "cc.y"
- {
- (yyval.node) = Z;
- }
- break;
-
- case 72:
-#line 410 "cc.y"
- {
- (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
- }
- break;
-
- case 73:
-#line 414 "cc.y"
- {
- (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
- }
- break;
-
- case 75:
-#line 421 "cc.y"
- {
- (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
- }
- break;
-
- case 76:
-#line 427 "cc.y"
- {
- (yyval.node) = new(OCASE, (yyvsp[(2) - (3)].node), Z);
- }
- break;
-
- case 77:
-#line 431 "cc.y"
- {
- (yyval.node) = new(OCASE, Z, Z);
- }
- break;
-
- case 78:
-#line 435 "cc.y"
- {
- (yyval.node) = new(OLABEL, dcllabel((yyvsp[(1) - (2)].sym), 1), Z);
- }
- break;
-
- case 79:
-#line 441 "cc.y"
- {
- (yyval.node) = Z;
- }
- break;
-
- case 81:
-#line 446 "cc.y"
- {
- (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
- }
- break;
-
- case 83:
-#line 453 "cc.y"
- {
- (yyval.node) = (yyvsp[(2) - (2)].node);
- }
- break;
-
- case 85:
-#line 459 "cc.y"
- {
- markdcl();
- }
- break;
-
- case 86:
-#line 463 "cc.y"
- {
- (yyval.node) = revertdcl();
- if((yyval.node))
- (yyval.node) = new(OLIST, (yyval.node), (yyvsp[(2) - (2)].node));
- else
- (yyval.node) = (yyvsp[(2) - (2)].node);
- }
- break;
-
- case 87:
-#line 471 "cc.y"
- {
- (yyval.node) = new(OIF, (yyvsp[(3) - (5)].node), new(OLIST, (yyvsp[(5) - (5)].node), Z));
- if((yyvsp[(5) - (5)].node) == Z)
- warn((yyvsp[(3) - (5)].node), "empty if body");
- }
- break;
-
- case 88:
-#line 477 "cc.y"
- {
- (yyval.node) = new(OIF, (yyvsp[(3) - (7)].node), new(OLIST, (yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)));
- if((yyvsp[(5) - (7)].node) == Z)
- warn((yyvsp[(3) - (7)].node), "empty if body");
- if((yyvsp[(7) - (7)].node) == Z)
- warn((yyvsp[(3) - (7)].node), "empty else body");
- }
- break;
-
- case 89:
-#line 484 "cc.y"
- { markdcl(); }
- break;
-
- case 90:
-#line 485 "cc.y"
- {
- (yyval.node) = revertdcl();
- if((yyval.node)){
- if((yyvsp[(4) - (10)].node))
- (yyvsp[(4) - (10)].node) = new(OLIST, (yyval.node), (yyvsp[(4) - (10)].node));
- else
- (yyvsp[(4) - (10)].node) = (yyval.node);
- }
- (yyval.node) = new(OFOR, new(OLIST, (yyvsp[(6) - (10)].node), new(OLIST, (yyvsp[(4) - (10)].node), (yyvsp[(8) - (10)].node))), (yyvsp[(10) - (10)].node));
- }
- break;
-
- case 91:
-#line 496 "cc.y"
- {
- (yyval.node) = new(OWHILE, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
- }
- break;
-
- case 92:
-#line 500 "cc.y"
- {
- (yyval.node) = new(ODWHILE, (yyvsp[(5) - (7)].node), (yyvsp[(2) - (7)].node));
- }
- break;
-
- case 93:
-#line 504 "cc.y"
- {
- (yyval.node) = new(ORETURN, (yyvsp[(2) - (3)].node), Z);
- (yyval.node)->type = thisfn->link;
- }
- break;
-
- case 94:
-#line 509 "cc.y"
- {
- (yyval.node) = new(OCONST, Z, Z);
- (yyval.node)->vconst = 0;
- (yyval.node)->type = types[TINT];
- (yyvsp[(3) - (5)].node) = new(OSUB, (yyval.node), (yyvsp[(3) - (5)].node));
-
- (yyval.node) = new(OCONST, Z, Z);
- (yyval.node)->vconst = 0;
- (yyval.node)->type = types[TINT];
- (yyvsp[(3) - (5)].node) = new(OSUB, (yyval.node), (yyvsp[(3) - (5)].node));
-
- (yyval.node) = new(OSWITCH, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
- }
- break;
-
- case 95:
-#line 523 "cc.y"
- {
- (yyval.node) = new(OBREAK, Z, Z);
- }
- break;
-
- case 96:
-#line 527 "cc.y"
- {
- (yyval.node) = new(OCONTINUE, Z, Z);
- }
- break;
-
- case 97:
-#line 531 "cc.y"
- {
- (yyval.node) = new(OGOTO, dcllabel((yyvsp[(2) - (3)].sym), 0), Z);
- }
- break;
-
- case 98:
-#line 535 "cc.y"
- {
- (yyval.node) = new(OUSED, (yyvsp[(3) - (5)].node), Z);
- }
- break;
-
- case 99:
-#line 539 "cc.y"
- {
- (yyval.node) = new(OPREFETCH, (yyvsp[(3) - (5)].node), Z);
- }
- break;
-
- case 100:
-#line 543 "cc.y"
- {
- (yyval.node) = new(OSET, (yyvsp[(3) - (5)].node), Z);
- }
- break;
-
- case 101:
-#line 548 "cc.y"
- {
- (yyval.node) = Z;
- }
- break;
-
- case 103:
-#line 554 "cc.y"
- {
- (yyval.node) = Z;
- }
- break;
-
- case 105:
-#line 561 "cc.y"
- {
- (yyval.node) = new(OCAST, (yyvsp[(1) - (1)].node), Z);
- (yyval.node)->type = types[TLONG];
- }
- break;
-
- case 107:
-#line 569 "cc.y"
- {
- (yyval.node) = new(OCOMMA, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 109:
-#line 576 "cc.y"
- {
- (yyval.node) = new(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 110:
-#line 580 "cc.y"
- {
- (yyval.node) = new(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 111:
-#line 584 "cc.y"
- {
- (yyval.node) = new(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 112:
-#line 588 "cc.y"
- {
- (yyval.node) = new(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 113:
-#line 592 "cc.y"
- {
- (yyval.node) = new(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 114:
-#line 596 "cc.y"
- {
- (yyval.node) = new(OASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 115:
-#line 600 "cc.y"
- {
- (yyval.node) = new(OASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 116:
-#line 604 "cc.y"
- {
- (yyval.node) = new(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 117:
-#line 608 "cc.y"
- {
- (yyval.node) = new(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 118:
-#line 612 "cc.y"
- {
- (yyval.node) = new(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 119:
-#line 616 "cc.y"
- {
- (yyval.node) = new(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 120:
-#line 620 "cc.y"
- {
- (yyval.node) = new(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 121:
-#line 624 "cc.y"
- {
- (yyval.node) = new(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 122:
-#line 628 "cc.y"
- {
- (yyval.node) = new(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 123:
-#line 632 "cc.y"
- {
- (yyval.node) = new(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 124:
-#line 636 "cc.y"
- {
- (yyval.node) = new(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 125:
-#line 640 "cc.y"
- {
- (yyval.node) = new(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 126:
-#line 644 "cc.y"
- {
- (yyval.node) = new(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 127:
-#line 648 "cc.y"
- {
- (yyval.node) = new(OCOND, (yyvsp[(1) - (5)].node), new(OLIST, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)));
- }
- break;
-
- case 128:
-#line 652 "cc.y"
- {
- (yyval.node) = new(OAS, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 129:
-#line 656 "cc.y"
- {
- (yyval.node) = new(OASADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 130:
-#line 660 "cc.y"
- {
- (yyval.node) = new(OASSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 131:
-#line 664 "cc.y"
- {
- (yyval.node) = new(OASMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 132:
-#line 668 "cc.y"
- {
- (yyval.node) = new(OASDIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 133:
-#line 672 "cc.y"
- {
- (yyval.node) = new(OASMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 134:
-#line 676 "cc.y"
- {
- (yyval.node) = new(OASASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 135:
-#line 680 "cc.y"
- {
- (yyval.node) = new(OASASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 136:
-#line 684 "cc.y"
- {
- (yyval.node) = new(OASAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 137:
-#line 688 "cc.y"
- {
- (yyval.node) = new(OASXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 138:
-#line 692 "cc.y"
- {
- (yyval.node) = new(OASOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 140:
-#line 699 "cc.y"
- {
- (yyval.node) = new(OCAST, (yyvsp[(5) - (5)].node), Z);
- dodecl(NODECL, CXXX, (yyvsp[(2) - (5)].type), (yyvsp[(3) - (5)].node));
- (yyval.node)->type = lastdcl;
- (yyval.node)->xcast = 1;
- }
- break;
-
- case 141:
-#line 706 "cc.y"
- {
- (yyval.node) = new(OSTRUCT, (yyvsp[(6) - (7)].node), Z);
- dodecl(NODECL, CXXX, (yyvsp[(2) - (7)].type), (yyvsp[(3) - (7)].node));
- (yyval.node)->type = lastdcl;
- }
- break;
-
- case 143:
-#line 715 "cc.y"
- {
- (yyval.node) = new(OIND, (yyvsp[(2) - (2)].node), Z);
- }
- break;
-
- case 144:
-#line 719 "cc.y"
- {
- (yyval.node) = new(OADDR, (yyvsp[(2) - (2)].node), Z);
- }
- break;
-
- case 145:
-#line 723 "cc.y"
- {
- (yyval.node) = new(OPOS, (yyvsp[(2) - (2)].node), Z);
- }
- break;
-
- case 146:
-#line 727 "cc.y"
- {
- (yyval.node) = new(ONEG, (yyvsp[(2) - (2)].node), Z);
- }
- break;
-
- case 147:
-#line 731 "cc.y"
- {
- (yyval.node) = new(ONOT, (yyvsp[(2) - (2)].node), Z);
- }
- break;
-
- case 148:
-#line 735 "cc.y"
- {
- (yyval.node) = new(OCOM, (yyvsp[(2) - (2)].node), Z);
- }
- break;
-
- case 149:
-#line 739 "cc.y"
- {
- (yyval.node) = new(OPREINC, (yyvsp[(2) - (2)].node), Z);
- }
- break;
-
- case 150:
-#line 743 "cc.y"
- {
- (yyval.node) = new(OPREDEC, (yyvsp[(2) - (2)].node), Z);
- }
- break;
-
- case 151:
-#line 747 "cc.y"
- {
- (yyval.node) = new(OSIZE, (yyvsp[(2) - (2)].node), Z);
- }
- break;
-
- case 152:
-#line 751 "cc.y"
- {
- (yyval.node) = new(OSIGN, (yyvsp[(2) - (2)].node), Z);
- }
- break;
-
- case 153:
-#line 757 "cc.y"
- {
- (yyval.node) = (yyvsp[(2) - (3)].node);
- }
- break;
-
- case 154:
-#line 761 "cc.y"
- {
- (yyval.node) = new(OSIZE, Z, Z);
- dodecl(NODECL, CXXX, (yyvsp[(3) - (5)].type), (yyvsp[(4) - (5)].node));
- (yyval.node)->type = lastdcl;
- }
- break;
-
- case 155:
-#line 767 "cc.y"
- {
- (yyval.node) = new(OSIGN, Z, Z);
- dodecl(NODECL, CXXX, (yyvsp[(3) - (5)].type), (yyvsp[(4) - (5)].node));
- (yyval.node)->type = lastdcl;
- }
- break;
-
- case 156:
-#line 773 "cc.y"
- {
- (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), Z);
- if((yyvsp[(1) - (4)].node)->op == ONAME)
- if((yyvsp[(1) - (4)].node)->type == T)
- dodecl(xdecl, CXXX, types[TINT], (yyval.node));
- (yyval.node)->right = invert((yyvsp[(3) - (4)].node));
- }
- break;
-
- case 157:
-#line 781 "cc.y"
- {
- (yyval.node) = new(OIND, new(OADD, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)), Z);
- }
- break;
-
- case 158:
-#line 785 "cc.y"
- {
- (yyval.node) = new(ODOT, new(OIND, (yyvsp[(1) - (3)].node), Z), Z);
- (yyval.node)->sym = (yyvsp[(3) - (3)].sym);
- }
- break;
-
- case 159:
-#line 790 "cc.y"
- {
- (yyval.node) = new(ODOT, (yyvsp[(1) - (3)].node), Z);
- (yyval.node)->sym = (yyvsp[(3) - (3)].sym);
- }
- break;
-
- case 160:
-#line 795 "cc.y"
- {
- (yyval.node) = new(OPOSTINC, (yyvsp[(1) - (2)].node), Z);
- }
- break;
-
- case 161:
-#line 799 "cc.y"
- {
- (yyval.node) = new(OPOSTDEC, (yyvsp[(1) - (2)].node), Z);
- }
- break;
-
- case 163:
-#line 804 "cc.y"
- {
- (yyval.node) = new(OCONST, Z, Z);
- (yyval.node)->type = types[TINT];
- (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
- (yyval.node)->cstring = strdup(symb);
- }
- break;
-
- case 164:
-#line 811 "cc.y"
- {
- (yyval.node) = new(OCONST, Z, Z);
- (yyval.node)->type = types[TLONG];
- (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
- (yyval.node)->cstring = strdup(symb);
- }
- break;
-
- case 165:
-#line 818 "cc.y"
- {
- (yyval.node) = new(OCONST, Z, Z);
- (yyval.node)->type = types[TUINT];
- (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
- (yyval.node)->cstring = strdup(symb);
- }
- break;
-
- case 166:
-#line 825 "cc.y"
- {
- (yyval.node) = new(OCONST, Z, Z);
- (yyval.node)->type = types[TULONG];
- (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
- (yyval.node)->cstring = strdup(symb);
- }
- break;
-
- case 167:
-#line 832 "cc.y"
- {
- (yyval.node) = new(OCONST, Z, Z);
- (yyval.node)->type = types[TDOUBLE];
- (yyval.node)->fconst = (yyvsp[(1) - (1)].dval);
- (yyval.node)->cstring = strdup(symb);
- }
- break;
-
- case 168:
-#line 839 "cc.y"
- {
- (yyval.node) = new(OCONST, Z, Z);
- (yyval.node)->type = types[TFLOAT];
- (yyval.node)->fconst = (yyvsp[(1) - (1)].dval);
- (yyval.node)->cstring = strdup(symb);
- }
- break;
-
- case 169:
-#line 846 "cc.y"
- {
- (yyval.node) = new(OCONST, Z, Z);
- (yyval.node)->type = types[TVLONG];
- (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
- (yyval.node)->cstring = strdup(symb);
- }
- break;
-
- case 170:
-#line 853 "cc.y"
- {
- (yyval.node) = new(OCONST, Z, Z);
- (yyval.node)->type = types[TUVLONG];
- (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
- (yyval.node)->cstring = strdup(symb);
- }
- break;
-
- case 173:
-#line 864 "cc.y"
- {
- (yyval.node) = new(OSTRING, Z, Z);
- (yyval.node)->type = typ(TARRAY, types[TCHAR]);
- (yyval.node)->type->width = (yyvsp[(1) - (1)].sval).l + 1;
- (yyval.node)->cstring = (yyvsp[(1) - (1)].sval).s;
- (yyval.node)->sym = symstring;
- (yyval.node)->etype = TARRAY;
- (yyval.node)->class = CSTATIC;
- }
- break;
-
- case 174:
-#line 874 "cc.y"
- {
- char *s;
- int n;
-
- n = (yyvsp[(1) - (2)].node)->type->width - 1;
- s = alloc(n+(yyvsp[(2) - (2)].sval).l+MAXALIGN);
-
- memcpy(s, (yyvsp[(1) - (2)].node)->cstring, n);
- memcpy(s+n, (yyvsp[(2) - (2)].sval).s, (yyvsp[(2) - (2)].sval).l);
- s[n+(yyvsp[(2) - (2)].sval).l] = 0;
-
- (yyval.node) = (yyvsp[(1) - (2)].node);
- (yyval.node)->type->width += (yyvsp[(2) - (2)].sval).l;
- (yyval.node)->cstring = s;
- }
- break;
-
- case 175:
-#line 892 "cc.y"
- {
- (yyval.node) = new(OLSTRING, Z, Z);
- (yyval.node)->type = typ(TARRAY, types[TRUNE]);
- (yyval.node)->type->width = (yyvsp[(1) - (1)].sval).l + sizeof(TRune);
- (yyval.node)->rstring = (TRune*)(yyvsp[(1) - (1)].sval).s;
- (yyval.node)->sym = symstring;
- (yyval.node)->etype = TARRAY;
- (yyval.node)->class = CSTATIC;
- }
- break;
-
- case 176:
-#line 902 "cc.y"
- {
- char *s;
- int n;
-
- n = (yyvsp[(1) - (2)].node)->type->width - sizeof(TRune);
- s = alloc(n+(yyvsp[(2) - (2)].sval).l+MAXALIGN);
-
- memcpy(s, (yyvsp[(1) - (2)].node)->rstring, n);
- memcpy(s+n, (yyvsp[(2) - (2)].sval).s, (yyvsp[(2) - (2)].sval).l);
- *(TRune*)(s+n+(yyvsp[(2) - (2)].sval).l) = 0;
-
- (yyval.node) = (yyvsp[(1) - (2)].node);
- (yyval.node)->type->width += (yyvsp[(2) - (2)].sval).l;
- (yyval.node)->rstring = (TRune*)s;
- }
- break;
-
- case 177:
-#line 919 "cc.y"
- {
- (yyval.node) = Z;
- }
- break;
-
- case 180:
-#line 927 "cc.y"
- {
- (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 181:
-#line 933 "cc.y"
- {
- (yyval.tyty).t1 = strf;
- (yyval.tyty).t2 = strl;
- (yyval.tyty).t3 = lasttype;
- (yyval.tyty).c = lastclass;
- strf = T;
- strl = T;
- lastbit = 0;
- firstbit = 1;
- lastclass = CXXX;
- lasttype = T;
- }
- break;
-
- case 182:
-#line 946 "cc.y"
- {
- (yyval.type) = strf;
- strf = (yyvsp[(2) - (4)].tyty).t1;
- strl = (yyvsp[(2) - (4)].tyty).t2;
- lasttype = (yyvsp[(2) - (4)].tyty).t3;
- lastclass = (yyvsp[(2) - (4)].tyty).c;
- }
- break;
-
- case 183:
-#line 955 "cc.y"
- {
- lastclass = CXXX;
- lasttype = types[TINT];
- }
- break;
-
- case 185:
-#line 963 "cc.y"
- {
- (yyval.tycl).t = (yyvsp[(1) - (1)].type);
- (yyval.tycl).c = CXXX;
- }
- break;
-
- case 186:
-#line 968 "cc.y"
- {
- (yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval));
- (yyval.tycl).c = CXXX;
- }
- break;
-
- case 187:
-#line 973 "cc.y"
- {
- (yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval));
- (yyval.tycl).c = simplec((yyvsp[(1) - (1)].lval));
- (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (1)].lval));
- }
- break;
-
- case 188:
-#line 979 "cc.y"
- {
- (yyval.tycl).t = (yyvsp[(1) - (2)].type);
- (yyval.tycl).c = simplec((yyvsp[(2) - (2)].lval));
- (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(2) - (2)].lval));
- if((yyvsp[(2) - (2)].lval) & ~BCLASS & ~BGARB)
- diag(Z, "duplicate types given: %T and %Q", (yyvsp[(1) - (2)].type), (yyvsp[(2) - (2)].lval));
- }
- break;
-
- case 189:
-#line 987 "cc.y"
- {
- (yyval.tycl).t = simplet(typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval)));
- (yyval.tycl).c = simplec((yyvsp[(2) - (2)].lval));
- (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(2) - (2)].lval));
- }
- break;
-
- case 190:
-#line 993 "cc.y"
- {
- (yyval.tycl).t = (yyvsp[(2) - (3)].type);
- (yyval.tycl).c = simplec((yyvsp[(1) - (3)].lval));
- (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
- }
- break;
-
- case 191:
-#line 999 "cc.y"
- {
- (yyval.tycl).t = simplet((yyvsp[(2) - (2)].lval));
- (yyval.tycl).c = simplec((yyvsp[(1) - (2)].lval));
- (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (2)].lval));
- }
- break;
-
- case 192:
-#line 1005 "cc.y"
- {
- (yyval.tycl).t = simplet(typebitor((yyvsp[(2) - (3)].lval), (yyvsp[(3) - (3)].lval)));
- (yyval.tycl).c = simplec((yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
- (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
- }
- break;
-
- case 193:
-#line 1013 "cc.y"
- {
- (yyval.type) = (yyvsp[(1) - (1)].tycl).t;
- if((yyvsp[(1) - (1)].tycl).c != CXXX)
- diag(Z, "illegal combination of class 4: %s", cnames[(yyvsp[(1) - (1)].tycl).c]);
- }
- break;
-
- case 194:
-#line 1021 "cc.y"
- {
- lasttype = (yyvsp[(1) - (1)].tycl).t;
- lastclass = (yyvsp[(1) - (1)].tycl).c;
- }
- break;
-
- case 195:
-#line 1028 "cc.y"
- {
- dotag((yyvsp[(2) - (2)].sym), TSTRUCT, 0);
- (yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
- }
- break;
-
- case 196:
-#line 1033 "cc.y"
- {
- dotag((yyvsp[(2) - (2)].sym), TSTRUCT, autobn);
- }
- break;
-
- case 197:
-#line 1037 "cc.y"
- {
- (yyval.type) = (yyvsp[(2) - (4)].sym)->suetag;
- if((yyval.type)->link != T)
- diag(Z, "redeclare tag: %s", (yyvsp[(2) - (4)].sym)->name);
- (yyval.type)->link = (yyvsp[(4) - (4)].type);
- sualign((yyval.type));
- }
- break;
-
- case 198:
-#line 1045 "cc.y"
- {
- diag(Z, "struct must have tag");
- taggen++;
- sprint(symb, "_%d_", taggen);
- (yyval.type) = dotag(lookup(), TSTRUCT, autobn);
- (yyval.type)->link = (yyvsp[(2) - (2)].type);
- sualign((yyval.type));
- }
- break;
-
- case 199:
-#line 1054 "cc.y"
- {
- dotag((yyvsp[(2) - (2)].sym), TUNION, 0);
- (yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
- }
- break;
-
- case 200:
-#line 1059 "cc.y"
- {
- dotag((yyvsp[(2) - (2)].sym), TUNION, autobn);
- }
- break;
-
- case 201:
-#line 1063 "cc.y"
- {
- (yyval.type) = (yyvsp[(2) - (4)].sym)->suetag;
- if((yyval.type)->link != T)
- diag(Z, "redeclare tag: %s", (yyvsp[(2) - (4)].sym)->name);
- (yyval.type)->link = (yyvsp[(4) - (4)].type);
- sualign((yyval.type));
- }
- break;
-
- case 202:
-#line 1071 "cc.y"
- {
- taggen++;
- sprint(symb, "_%d_", taggen);
- (yyval.type) = dotag(lookup(), TUNION, autobn);
- (yyval.type)->link = (yyvsp[(2) - (2)].type);
- sualign((yyval.type));
- }
- break;
-
- case 203:
-#line 1079 "cc.y"
- {
- dotag((yyvsp[(2) - (2)].sym), TENUM, 0);
- (yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
- if((yyval.type)->link == T)
- (yyval.type)->link = types[TINT];
- (yyval.type) = (yyval.type)->link;
- }
- break;
-
- case 204:
-#line 1087 "cc.y"
- {
- dotag((yyvsp[(2) - (2)].sym), TENUM, autobn);
- }
- break;
-
- case 205:
-#line 1091 "cc.y"
- {
- en.tenum = T;
- en.cenum = T;
- }
- break;
-
- case 206:
-#line 1096 "cc.y"
- {
- (yyval.type) = (yyvsp[(2) - (7)].sym)->suetag;
- if((yyval.type)->link != T)
- diag(Z, "redeclare tag: %s", (yyvsp[(2) - (7)].sym)->name);
- if(en.tenum == T) {
- diag(Z, "enum type ambiguous: %s", (yyvsp[(2) - (7)].sym)->name);
- en.tenum = types[TINT];
- }
- (yyval.type)->link = en.tenum;
- (yyval.type) = en.tenum;
- }
- break;
-
- case 207:
-#line 1108 "cc.y"
- {
- en.tenum = T;
- en.cenum = T;
- }
- break;
-
- case 208:
-#line 1113 "cc.y"
- {
- (yyval.type) = en.tenum;
- }
- break;
-
- case 209:
-#line 1117 "cc.y"
- {
- (yyval.type) = tcopy((yyvsp[(1) - (1)].sym)->type);
- }
- break;
-
- case 211:
-#line 1124 "cc.y"
- {
- (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
- }
- break;
-
- case 212:
-#line 1129 "cc.y"
- {
- (yyval.lval) = 0;
- }
- break;
-
- case 213:
-#line 1133 "cc.y"
- {
- (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
- }
- break;
-
- case 218:
-#line 1145 "cc.y"
- {
- (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
- }
- break;
-
- case 221:
-#line 1155 "cc.y"
- {
- doenum((yyvsp[(1) - (1)].sym), Z);
- }
- break;
-
- case 222:
-#line 1159 "cc.y"
- {
- doenum((yyvsp[(1) - (3)].sym), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 225:
-#line 1166 "cc.y"
- { (yyval.lval) = BCHAR; }
- break;
-
- case 226:
-#line 1167 "cc.y"
- { (yyval.lval) = BSHORT; }
- break;
-
- case 227:
-#line 1168 "cc.y"
- { (yyval.lval) = BINT; }
- break;
-
- case 228:
-#line 1169 "cc.y"
- { (yyval.lval) = BLONG; }
- break;
-
- case 229:
-#line 1170 "cc.y"
- { (yyval.lval) = BSIGNED; }
- break;
-
- case 230:
-#line 1171 "cc.y"
- { (yyval.lval) = BUNSIGNED; }
- break;
-
- case 231:
-#line 1172 "cc.y"
- { (yyval.lval) = BFLOAT; }
- break;
-
- case 232:
-#line 1173 "cc.y"
- { (yyval.lval) = BDOUBLE; }
- break;
-
- case 233:
-#line 1174 "cc.y"
- { (yyval.lval) = BVOID; }
- break;
-
- case 234:
-#line 1177 "cc.y"
- { (yyval.lval) = BAUTO; }
- break;
-
- case 235:
-#line 1178 "cc.y"
- { (yyval.lval) = BSTATIC; }
- break;
-
- case 236:
-#line 1179 "cc.y"
- { (yyval.lval) = BEXTERN; }
- break;
-
- case 237:
-#line 1180 "cc.y"
- { (yyval.lval) = BTYPEDEF; }
- break;
-
- case 238:
-#line 1181 "cc.y"
- { (yyval.lval) = BTYPESTR; }
- break;
-
- case 239:
-#line 1182 "cc.y"
- { (yyval.lval) = BREGISTER; }
- break;
-
- case 240:
-#line 1183 "cc.y"
- { (yyval.lval) = 0; }
- break;
-
- case 241:
-#line 1186 "cc.y"
- { (yyval.lval) = BCONSTNT; }
- break;
-
- case 242:
-#line 1187 "cc.y"
- { (yyval.lval) = BVOLATILE; }
- break;
-
- case 243:
-#line 1188 "cc.y"
- { (yyval.lval) = 0; }
- break;
-
- case 244:
-#line 1192 "cc.y"
- {
- (yyval.node) = new(ONAME, Z, Z);
- if((yyvsp[(1) - (1)].sym)->class == CLOCAL)
- (yyvsp[(1) - (1)].sym) = mkstatic((yyvsp[(1) - (1)].sym));
- (yyval.node)->sym = (yyvsp[(1) - (1)].sym);
- (yyval.node)->type = (yyvsp[(1) - (1)].sym)->type;
- (yyval.node)->etype = TVOID;
- if((yyval.node)->type != T)
- (yyval.node)->etype = (yyval.node)->type->etype;
- (yyval.node)->xoffset = (yyvsp[(1) - (1)].sym)->offset;
- (yyval.node)->class = (yyvsp[(1) - (1)].sym)->class;
- (yyvsp[(1) - (1)].sym)->aused = 1;
- }
- break;
-
- case 245:
-#line 1207 "cc.y"
- {
- (yyval.node) = new(ONAME, Z, Z);
- (yyval.node)->sym = (yyvsp[(1) - (1)].sym);
- (yyval.node)->type = (yyvsp[(1) - (1)].sym)->type;
- (yyval.node)->etype = TVOID;
- if((yyval.node)->type != T)
- (yyval.node)->etype = (yyval.node)->type->etype;
- (yyval.node)->xoffset = (yyvsp[(1) - (1)].sym)->offset;
- (yyval.node)->class = (yyvsp[(1) - (1)].sym)->class;
- }
- break;
-
-
-/* Line 1267 of yacc.c. */
-#line 3607 "y.tab.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
-
- *++yyvsp = yyval;
-
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
- if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTOKENS];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (yymsg);
- }
- else
- {
- yyerror (YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
- }
-
-
-
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse look-ahead token after an
- error, discard it. */
-
- if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
- else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval);
- yychar = YYEMPTY;
- }
- }
-
- /* Else will try to reuse look-ahead token after shifting the error
- token. */
- goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR. |
-`---------------------------------------------------*/
-yyerrorlab:
-
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
- goto yyerrorlab;
-
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
- yystate = *yyssp;
- goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR. |
-`-------------------------------------------------------------*/
-yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
- YYABORT;
-
-
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- *++yyvsp = yylval;
-
-
- /* Shift the error token. */
- YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (YY_("memory exhausted"));
- yyresult = 2;
- /* Fall through. */
-#endif
-
-yyreturn:
- if (yychar != YYEOF && yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
- YYPOPSTACK (1);
- }
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
-}
-
-
-#line 1220 "cc.y"
-
-
diff --git a/src/cmd/cc/y.tab.h b/src/cmd/cc/y.tab.h
deleted file mode 100644
index 32daca9b6..000000000
--- a/src/cmd/cc/y.tab.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LORE = 258,
- LXORE = 259,
- LANDE = 260,
- LLSHE = 261,
- LRSHE = 262,
- LMDE = 263,
- LDVE = 264,
- LMLE = 265,
- LME = 266,
- LPE = 267,
- LOROR = 268,
- LANDAND = 269,
- LNE = 270,
- LEQ = 271,
- LGE = 272,
- LLE = 273,
- LRSH = 274,
- LLSH = 275,
- LMG = 276,
- LPP = 277,
- LMM = 278,
- LNAME = 279,
- LTYPE = 280,
- LFCONST = 281,
- LDCONST = 282,
- LCONST = 283,
- LLCONST = 284,
- LUCONST = 285,
- LULCONST = 286,
- LVLCONST = 287,
- LUVLCONST = 288,
- LSTRING = 289,
- LLSTRING = 290,
- LAUTO = 291,
- LBREAK = 292,
- LCASE = 293,
- LCHAR = 294,
- LCONTINUE = 295,
- LDEFAULT = 296,
- LDO = 297,
- LDOUBLE = 298,
- LELSE = 299,
- LEXTERN = 300,
- LFLOAT = 301,
- LFOR = 302,
- LGOTO = 303,
- LIF = 304,
- LINT = 305,
- LLONG = 306,
- LPREFETCH = 307,
- LREGISTER = 308,
- LRETURN = 309,
- LSHORT = 310,
- LSIZEOF = 311,
- LUSED = 312,
- LSTATIC = 313,
- LSTRUCT = 314,
- LSWITCH = 315,
- LTYPEDEF = 316,
- LTYPESTR = 317,
- LUNION = 318,
- LUNSIGNED = 319,
- LWHILE = 320,
- LVOID = 321,
- LENUM = 322,
- LSIGNED = 323,
- LCONSTNT = 324,
- LVOLATILE = 325,
- LSET = 326,
- LSIGNOF = 327,
- LRESTRICT = 328,
- LINLINE = 329
- };
-#endif
-/* Tokens. */
-#define LORE 258
-#define LXORE 259
-#define LANDE 260
-#define LLSHE 261
-#define LRSHE 262
-#define LMDE 263
-#define LDVE 264
-#define LMLE 265
-#define LME 266
-#define LPE 267
-#define LOROR 268
-#define LANDAND 269
-#define LNE 270
-#define LEQ 271
-#define LGE 272
-#define LLE 273
-#define LRSH 274
-#define LLSH 275
-#define LMG 276
-#define LPP 277
-#define LMM 278
-#define LNAME 279
-#define LTYPE 280
-#define LFCONST 281
-#define LDCONST 282
-#define LCONST 283
-#define LLCONST 284
-#define LUCONST 285
-#define LULCONST 286
-#define LVLCONST 287
-#define LUVLCONST 288
-#define LSTRING 289
-#define LLSTRING 290
-#define LAUTO 291
-#define LBREAK 292
-#define LCASE 293
-#define LCHAR 294
-#define LCONTINUE 295
-#define LDEFAULT 296
-#define LDO 297
-#define LDOUBLE 298
-#define LELSE 299
-#define LEXTERN 300
-#define LFLOAT 301
-#define LFOR 302
-#define LGOTO 303
-#define LIF 304
-#define LINT 305
-#define LLONG 306
-#define LPREFETCH 307
-#define LREGISTER 308
-#define LRETURN 309
-#define LSHORT 310
-#define LSIZEOF 311
-#define LUSED 312
-#define LSTATIC 313
-#define LSTRUCT 314
-#define LSWITCH 315
-#define LTYPEDEF 316
-#define LTYPESTR 317
-#define LUNION 318
-#define LUNSIGNED 319
-#define LWHILE 320
-#define LVOID 321
-#define LENUM 322
-#define LSIGNED 323
-#define LCONSTNT 324
-#define LVOLATILE 325
-#define LSET 326
-#define LSIGNOF 327
-#define LRESTRICT 328
-#define LINLINE 329
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 36 "cc.y"
-{
- Node* node;
- Sym* sym;
- Type* type;
- struct
- {
- Type* t;
- uchar c;
- } tycl;
- struct
- {
- Type* t1;
- Type* t2;
- Type* t3;
- uchar c;
- } tyty;
- struct
- {
- char* s;
- int32 l;
- } sval;
- int32 lval;
- double dval;
- vlong vval;
-}
-/* Line 1529 of yacc.c. */
-#line 223 "y.tab.h"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 17b0cdd16..28ded816d 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -130,15 +130,23 @@ func usage() {
}
var ptrSizeMap = map[string]int64{
- "386": 4,
- "amd64": 8,
- "arm": 4,
+ "386": 4,
+ "amd64": 8,
+ "arm": 4,
+ "ppc64": 8,
+ "ppc64le": 8,
+ "power64": 8,
+ "power64le": 8,
}
var intSizeMap = map[string]int64{
- "386": 4,
- "amd64": 8,
- "arm": 4,
+ "386": 4,
+ "amd64": 8,
+ "arm": 4,
+ "ppc64": 8,
+ "ppc64le": 8,
+ "power64": 8,
+ "power64le": 8,
}
var cPrefix string
@@ -147,6 +155,7 @@ var fset = token.NewFileSet()
var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
var dynout = flag.String("dynout", "", "write -dynobj output to this file")
+var dynpackage = flag.String("dynpackage", "main", "set Go package for dynobj output")
var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in dynimport mode")
// These flags are for bootstrapping a new Go implementation,
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index d92bed9bf..78ecfd397 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -13,6 +13,7 @@ import (
"go/ast"
"go/printer"
"go/token"
+ "io"
"os"
"sort"
"strings"
@@ -23,8 +24,15 @@ var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Package) writeDefs() {
- fgo2 := creat(*objDir + "_cgo_gotypes.go")
- fc := creat(*objDir + "_cgo_defun.c")
+ var fgo2, fc io.Writer
+ f := creat(*objDir + "_cgo_gotypes.go")
+ defer f.Close()
+ fgo2 = f
+ if *gccgo {
+ f := creat(*objDir + "_cgo_defun.c")
+ defer f.Close()
+ fc = f
+ }
fm := creat(*objDir + "_cgo_main.c")
var gccgoInit bytes.Buffer
@@ -34,7 +42,7 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " "))
if k == "LDFLAGS" && !*gccgo {
for _, arg := range v {
- fmt.Fprintf(fc, "#pragma cgo_ldflag %q\n", arg)
+ fmt.Fprintf(fgo2, "//go:cgo_ldflag %q\n", arg)
}
}
}
@@ -88,7 +96,6 @@ func (p *Package) writeDefs() {
if *gccgo {
fmt.Fprint(fc, p.cPrologGccgo())
} else {
- fmt.Fprint(fc, cProlog)
fmt.Fprint(fgo2, goProlog)
}
@@ -104,42 +111,42 @@ func (p *Package) writeDefs() {
if !cVars[n.C] {
fmt.Fprintf(fm, "extern char %s[];\n", n.C)
fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
-
- if !*gccgo {
- fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C)
+ if *gccgo {
+ fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
+ } else {
+ fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C)
+ fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C)
+ fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C)
}
-
- fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
-
cVars[n.C] = true
}
- var amp string
+
var node ast.Node
if n.Kind == "var" {
- amp = "&"
node = &ast.StarExpr{X: n.Type.Go}
} else if n.Kind == "fpvar" {
node = n.Type.Go
- if *gccgo {
- amp = "&"
- }
} else {
panic(fmt.Errorf("invalid var kind %q", n.Kind))
}
if *gccgo {
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
- fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C)
- } else {
- fmt.Fprintf(fc, "#pragma dataflag NOPTR /* C pointer, not heap pointer */ \n")
- fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C)
+ fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
+ fmt.Fprintf(fc, "\n")
}
- fmt.Fprintf(fc, "\n")
fmt.Fprintf(fgo2, "var %s ", n.Mangle)
conf.Fprint(fgo2, fset, node)
+ if !*gccgo {
+ fmt.Fprintf(fgo2, " = (")
+ conf.Fprint(fgo2, fset, node)
+ fmt.Fprintf(fgo2, ")(unsafe.Pointer(&__cgo_%s))", n.C)
+ }
fmt.Fprintf(fgo2, "\n")
}
- fmt.Fprintf(fc, "\n")
+ if *gccgo {
+ fmt.Fprintf(fc, "\n")
+ }
for _, key := range nameKeys(p.Name) {
n := p.Name[key]
@@ -169,9 +176,6 @@ func (p *Package) writeDefs() {
fmt.Fprint(fc, init)
fmt.Fprintln(fc, "}")
}
-
- fgo2.Close()
- fc.Close()
}
func dynimport(obj string) {
@@ -184,13 +188,15 @@ func dynimport(obj string) {
stdout = f
}
+ fmt.Fprintf(stdout, "package %s\n", *dynpackage)
+
if f, err := elf.Open(obj); err == nil {
if *dynlinker {
// Emit the cgo_dynamic_linker line.
if sec := f.Section(".interp"); sec != nil {
if data, err := sec.Data(); err == nil && len(data) > 1 {
// skip trailing \0 in data
- fmt.Fprintf(stdout, "#pragma cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
+ fmt.Fprintf(stdout, "//go:cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
}
}
}
@@ -203,14 +209,14 @@ func dynimport(obj string) {
if s.Version != "" {
targ += "#" + s.Version
}
- fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
}
lib, err := f.ImportedLibraries()
if err != nil {
fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
}
for _, l := range lib {
- fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
}
return
}
@@ -224,14 +230,14 @@ func dynimport(obj string) {
if len(s) > 0 && s[0] == '_' {
s = s[1:]
}
- fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s, s, "")
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
}
lib, err := f.ImportedLibraries()
if err != nil {
fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
}
for _, l := range lib {
- fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
}
return
}
@@ -244,7 +250,7 @@ func dynimport(obj string) {
for _, s := range sym {
ss := strings.Split(s, ":")
name := strings.Split(ss[0], "@")[0]
- fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
}
return
}
@@ -304,7 +310,7 @@ func (p *Package) structType(n *Name) (string, int64) {
return buf.String(), off
}
-func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
+func (p *Package) writeDefsFunc(fc, fgo2 io.Writer, n *Name) {
name := n.Go
gtype := n.FuncType.Go
void := gtype.Results == nil || len(gtype.Results.List) == 0
@@ -397,10 +403,10 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
}
// C wrapper calls into gcc, passing a pointer to the argument frame.
- fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname)
- fmt.Fprintf(fc, "void %s(void*);\n", cname)
- fmt.Fprintf(fc, "#pragma dataflag NOPTR\n")
- fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
+ fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", cname)
+ fmt.Fprintf(fgo2, "//go:linkname __cgofn_%s %s\n", cname, cname)
+ fmt.Fprintf(fgo2, "var __cgofn_%s byte\n", cname)
+ fmt.Fprintf(fgo2, "var %s = unsafe.Pointer(&__cgofn_%s)\n", cname, cname)
nret := 0
if !void {
@@ -412,7 +418,6 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
}
fmt.Fprint(fgo2, "\n")
- fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname)
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, " {\n")
@@ -626,7 +631,7 @@ func (p *Package) packedAttribute() string {
// Write out the various stubs we need to support functions exported
// from Go so that they are callable from C.
-func (p *Package) writeExports(fgo2, fc, fm *os.File) {
+func (p *Package) writeExports(fgo2, fc, fm io.Writer) {
fgcc := creat(*objDir + "_cgo_export.c")
fgcch := creat(*objDir + "_cgo_export.h")
@@ -763,15 +768,15 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
if fn.Recv != nil {
goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
}
- fmt.Fprintf(fc, "#pragma cgo_export_dynamic %s\n", goname)
- fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
- fmt.Fprintf(fc, "#pragma cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
- fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g
- fmt.Fprintf(fc, "void\n")
- fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
- fmt.Fprintf(fc, "{\n")
- fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
- fmt.Fprintf(fc, "}\n")
+ fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", goname)
+ fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
+ fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
+ fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
+ fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {", cPrefix, exp.ExpName)
+ fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
+ // The indirect here is converting from a Go function pointer to a C function pointer.
+ fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n));\n")
+ fmt.Fprintf(fgo2, "}\n")
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
@@ -817,7 +822,7 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
}
// Write out the C header allowing C code to call exported gccgo functions.
-func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
+func (p *Package) writeGccgoExports(fgo2, fc, fm io.Writer) {
fgcc := creat(*objDir + "_cgo_export.c")
fgcch := creat(*objDir + "_cgo_export.h")
@@ -1164,60 +1169,39 @@ char *CString(_GoString_);
void *_CMalloc(size_t);
`
-const cProlog = `
-#include "runtime.h"
-#include "cgocall.h"
-#include "textflag.h"
-
-#pragma dataflag NOPTR
-static void *cgocall_errno = runtime·cgocall_errno;
-#pragma dataflag NOPTR
-void *·_cgo_runtime_cgocall_errno = &cgocall_errno;
-
-#pragma dataflag NOPTR
-static void *runtime_gostring = runtime·gostring;
-#pragma dataflag NOPTR
-void *·_cgo_runtime_gostring = &runtime_gostring;
-
-#pragma dataflag NOPTR
-static void *runtime_gostringn = runtime·gostringn;
-#pragma dataflag NOPTR
-void *·_cgo_runtime_gostringn = &runtime_gostringn;
-
-#pragma dataflag NOPTR
-static void *runtime_gobytes = runtime·gobytes;
-#pragma dataflag NOPTR
-void *·_cgo_runtime_gobytes = &runtime_gobytes;
-
-#pragma dataflag NOPTR
-static void *runtime_cmalloc = runtime·cmalloc;
-#pragma dataflag NOPTR
-void *·_cgo_runtime_cmalloc = &runtime_cmalloc;
-
-void ·_Cerrno(void*, int32);
-`
-
const goProlog = `
-var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32
-var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer
+//go:linkname _cgo_runtime_cgocall_errno runtime.cgocall_errno
+func _cgo_runtime_cgocall_errno(unsafe.Pointer, uintptr) int32
+
+//go:linkname _cgo_runtime_cmalloc runtime.cmalloc
+func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer
+
+//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
+func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
`
const goStringDef = `
-var _cgo_runtime_gostring func(*_Ctype_char) string
+//go:linkname _cgo_runtime_gostring runtime.gostring
+func _cgo_runtime_gostring(*_Ctype_char) string
+
func _Cfunc_GoString(p *_Ctype_char) string {
return _cgo_runtime_gostring(p)
}
`
const goStringNDef = `
-var _cgo_runtime_gostringn func(*_Ctype_char, int) string
+//go:linkname _cgo_runtime_gostringn runtime.gostringn
+func _cgo_runtime_gostringn(*_Ctype_char, int) string
+
func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
return _cgo_runtime_gostringn(p, int(l))
}
`
const goBytesDef = `
-var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte
+//go:linkname _cgo_runtime_gobytes runtime.gobytes
+func _cgo_runtime_gobytes(unsafe.Pointer, int) []byte
+
func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
return _cgo_runtime_gobytes(p, int(l))
}
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
index d638ae4eb..bfb3d15b8 100644
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -39,7 +39,7 @@ static void dopack(char*, char*, char**, int);
static char *findgoversion(void);
// The known architecture letters.
-static char *gochars = "5668";
+static char *gochars = "566899";
// The known architectures.
static char *okgoarch[] = {
@@ -48,6 +48,8 @@ static char *okgoarch[] = {
"amd64",
"amd64p32",
"386",
+ "power64",
+ "power64le",
};
// The known operating systems.
@@ -344,6 +346,7 @@ static char *oldtool[] = {
"5a", "5c", "5g", "5l",
"6a", "6c", "6g", "6l",
"8a", "8c", "8g", "8l",
+ "9a", "9c", "9g", "9l",
"6cov",
"6nm",
"6prof",
@@ -521,10 +524,7 @@ static struct {
"anames5.c",
"anames6.c",
"anames8.c",
- }},
- {"cmd/cc", {
- "-pgen.c",
- "-pswt.c",
+ "anames9.c",
}},
{"cmd/gc", {
"-cplx.c",
@@ -534,21 +534,6 @@ static struct {
"-y1.tab.c", // makefile dreg
"opnames.h",
}},
- {"cmd/5c", {
- "../cc/pgen.c",
- "../cc/pswt.c",
- "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
- }},
- {"cmd/6c", {
- "../cc/pgen.c",
- "../cc/pswt.c",
- "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
- }},
- {"cmd/8c", {
- "../cc/pgen.c",
- "../cc/pswt.c",
- "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
- }},
{"cmd/5g", {
"../gc/cplx.c",
"../gc/pgen.c",
@@ -573,6 +558,14 @@ static struct {
"../gc/popt.h",
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
}},
+ {"cmd/9g", {
+ "../gc/cplx.c",
+ "../gc/pgen.c",
+ "../gc/plive.c",
+ "../gc/popt.c",
+ "../gc/popt.h",
+ "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
+ }},
{"cmd/5l", {
"../ld/*",
}},
@@ -582,6 +575,9 @@ static struct {
{"cmd/8l", {
"../ld/*",
}},
+ {"cmd/9l", {
+ "../ld/*",
+ }},
{"cmd/go", {
"zdefaultcc.go",
}},
@@ -591,12 +587,10 @@ static struct {
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/lib9.a",
}},
{"runtime", {
- "zaexperiment.h", // must sort above zasm
- "zasm_$GOOS_$GOARCH.h",
+ "zaexperiment.h",
"zsys_$GOOS_$GOARCH.s",
"zgoarch_$GOARCH.go",
"zgoos_$GOOS.go",
- "zruntime_defs_$GOOS_$GOARCH.go",
"zversion.go",
}},
};
@@ -618,12 +612,9 @@ static struct {
{"anames5.c", mkanames},
{"anames6.c", mkanames},
{"anames8.c", mkanames},
- {"zasm_", mkzasm},
+ {"anames9.c", mkanames},
{"zdefaultcc.go", mkzdefaultcc},
{"zsys_", mkzsys},
- {"zgoarch_", mkzgoarch},
- {"zgoos_", mkzgoos},
- {"zruntime_defs_", mkzruntimedefs},
{"zversion.go", mkzversion},
{"zaexperiment.h", mkzexperiment},
@@ -638,7 +629,7 @@ install(char *dir)
{
char *name, *p, *elem, *prefix, *exe;
bool islib, ispkg, isgo, stale, ispackcmd;
- Buf b, b1, path, final_path, final_name;
+ Buf b, b1, path, final_path, final_name, archive;
Vec compile, files, link, go, missing, clean, lib, extra;
Time ttarg, t;
int i, j, k, n, doclean, targ;
@@ -655,6 +646,7 @@ install(char *dir)
binit(&path);
binit(&final_path);
binit(&final_name);
+ binit(&archive);
vinit(&compile);
vinit(&files);
vinit(&link);
@@ -698,7 +690,7 @@ install(char *dir)
splitfields(&ldargs, bstr(&b));
}
- islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");
+ islib = hasprefix(dir, "lib") || streq(dir, "cmd/gc");
ispkg = !islib && !hasprefix(dir, "cmd/");
isgo = ispkg || streq(dir, "cmd/go") || streq(dir, "cmd/cgo");
@@ -877,17 +869,6 @@ install(char *dir)
// For package runtime, copy some files into the work space.
if(streq(dir, "runtime")) {
- copyfile(bpathf(&b, "%s/arch_GOARCH.h", workdir),
- bpathf(&b1, "%s/arch_%s.h", bstr(&path), goarch), 0);
- copyfile(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
- bpathf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch), 0);
- p = bpathf(&b1, "%s/signal_%s_%s.h", bstr(&path), goos, goarch);
- if(isfile(p))
- copyfile(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0);
- copyfile(bpathf(&b, "%s/os_GOOS.h", workdir),
- bpathf(&b1, "%s/os_%s.h", bstr(&path), goos), 0);
- copyfile(bpathf(&b, "%s/signals_GOOS.h", workdir),
- bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0);
copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
copyfile(bpathf(&b, "%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch),
@@ -921,14 +902,6 @@ install(char *dir)
built:;
}
- // One more copy for package runtime.
- // The last batch was required for the generators.
- // This one is generated.
- if(streq(dir, "runtime")) {
- copyfile(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir),
- bpathf(&b1, "%s/zasm_%s_%s.h", bstr(&path), goos, goarch), 0);
- }
-
if((!streq(goos, gohostos) || !streq(goarch, gohostarch)) && isgo) {
// We've generated the right files; the go command can do the build.
if(vflag > 1)
@@ -936,6 +909,42 @@ install(char *dir)
goto nobuild;
}
+ if(isgo) {
+ // The next loop will compile individual non-Go files.
+ // Hand the Go files to the compiler en masse.
+ // For package runtime, this writes go_asm.h, which
+ // the assembly files will need.
+ vreset(&compile);
+ vadd(&compile, bpathf(&b, "%s/%sg", tooldir, gochar));
+
+ bpathf(&b, "%s/_go_.a", workdir);
+ vadd(&compile, "-pack");
+ vadd(&compile, "-o");
+ vadd(&compile, bstr(&b));
+ vadd(&clean, bstr(&b));
+ if(!ispackcmd)
+ vadd(&link, bstr(&b));
+ else
+ bwriteb(&archive, &b);
+
+ vadd(&compile, "-p");
+ if(hasprefix(dir, "cmd/"))
+ vadd(&compile, "main");
+ else
+ vadd(&compile, dir);
+
+ if(streq(dir, "runtime")) {
+ vadd(&compile, "-+");
+ vadd(&compile, "-asmhdr");
+ bpathf(&b1, "%s/go_asm.h", workdir);
+ vadd(&compile, bstr(&b1));
+ }
+
+ vcopy(&compile, go.p, go.len);
+
+ runv(nil, bstr(&path), CheckExit, &compile);
+ }
+
// Compile the files.
for(i=0; i<files.len; i++) {
if(!hassuffix(files.p[i], ".c") && !hassuffix(files.p[i], ".s"))
@@ -1049,38 +1058,10 @@ install(char *dir)
}
bgwait();
- if(isgo) {
- // The last loop was compiling individual files.
- // Hand the Go files to the compiler en masse.
- vreset(&compile);
- vadd(&compile, bpathf(&b, "%s/%sg", tooldir, gochar));
-
- bpathf(&b, "%s/_go_.a", workdir);
- vadd(&compile, "-pack");
- vadd(&compile, "-o");
- vadd(&compile, bstr(&b));
- vadd(&clean, bstr(&b));
- if(!ispackcmd)
- vadd(&link, bstr(&b));
-
- vadd(&compile, "-p");
- if(hasprefix(dir, "pkg/"))
- vadd(&compile, dir+4);
- else
- vadd(&compile, "main");
-
- if(streq(dir, "runtime"))
- vadd(&compile, "-+");
-
- vcopy(&compile, go.p, go.len);
-
- runv(nil, bstr(&path), CheckExit, &compile);
-
- if(ispackcmd) {
- xremove(link.p[targ]);
- dopack(link.p[targ], bstr(&b), &link.p[targ+1], link.len - (targ+1));
- goto nobuild;
- }
+ if(isgo && ispackcmd) {
+ xremove(link.p[targ]);
+ dopack(link.p[targ], bstr(&archive), &link.p[targ+1], link.len - (targ+1));
+ goto nobuild;
}
if(!islib && !isgo) {
@@ -1094,17 +1075,7 @@ install(char *dir)
xremove(link.p[targ]);
runv(nil, nil, CheckExit, &link);
-
nobuild:
- // In package runtime, we install runtime.h and cgocall.h too,
- // for use by cgo compilation.
- if(streq(dir, "runtime")) {
- copyfile(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch),
- bpathf(&b1, "%s/src/runtime/cgocall.h", goroot), 0);
- copyfile(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch),
- bpathf(&b1, "%s/src/runtime/runtime.h", goroot), 0);
- }
-
out:
for(i=0; i<clean.len; i++)
@@ -1113,6 +1084,7 @@ out:
bfree(&b);
bfree(&b1);
bfree(&path);
+ bfree(&archive);
vfree(&compile);
vfree(&files);
vfree(&link);
@@ -1156,12 +1128,26 @@ shouldbuild(char *file, char *dir)
// Check file name for GOOS or GOARCH.
name = lastelem(file);
- for(i=0; i<nelem(okgoos); i++)
- if(contains(name, okgoos[i]) && !streq(okgoos[i], goos))
+ for(i=0; i<nelem(okgoos); i++) {
+ if(streq(okgoos[i], goos))
+ continue;
+ p = xstrstr(name, okgoos[i]);
+ if(p == nil)
+ continue;
+ p += xstrlen(okgoos[i]);
+ if(*p == '.' || *p == '_' || *p == '\0')
return 0;
- for(i=0; i<nelem(okgoarch); i++)
- if(contains(name, okgoarch[i]) && !streq(okgoarch[i], goarch))
+ }
+ for(i=0; i<nelem(okgoarch); i++) {
+ if(streq(okgoarch[i], goarch))
+ continue;
+ p = xstrstr(name, okgoarch[i]);
+ if(p == nil)
+ continue;
+ p += xstrlen(okgoarch[i]);
+ if(*p == '.' || *p == '_' || *p == '\0')
return 0;
+ }
// Omit test files.
if(contains(name, "_test"))
@@ -1286,11 +1272,9 @@ static char *buildorder[] = {
"libbio",
"liblink",
- "cmd/cc", // must be before c
"cmd/gc", // must be before g
- "cmd/%sl", // must be before a, c, g
+ "cmd/%sl", // must be before a, g
"cmd/%sa",
- "cmd/%sc",
"cmd/%sg",
// The dependency order here was copied from a buildscript
@@ -1347,18 +1331,17 @@ static char *buildorder[] = {
static char *cleantab[] = {
// Commands and C libraries.
"cmd/5a",
- "cmd/5c",
"cmd/5g",
"cmd/5l",
"cmd/6a",
- "cmd/6c",
"cmd/6g",
"cmd/6l",
"cmd/8a",
- "cmd/8c",
"cmd/8g",
"cmd/8l",
- "cmd/cc",
+ "cmd/9a",
+ "cmd/9g",
+ "cmd/9l",
"cmd/gc",
"cmd/go",
"lib9",
@@ -1434,12 +1417,13 @@ clean(void)
xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4));
}
- // remove src/runtime/z* unconditionally
+ // remove src/runtime/z* unconditionally,
+ // except leave zgoos and zgoarch, now maintained with go generate.
vreset(&dir);
bpathf(&path, "%s/src/runtime", goroot);
xreaddir(&dir, bstr(&path));
for(j=0; j<dir.len; j++) {
- if(hasprefix(dir.p[j], "z"))
+ if(hasprefix(dir.p[j], "z") && !hasprefix(dir.p[j], "zg"))
xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j]));
}
diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c
index 66adf6857..64434d51e 100644
--- a/src/cmd/dist/buildgc.c
+++ b/src/cmd/dist/buildgc.c
@@ -63,22 +63,36 @@ gcopnames(char *dir, char *file)
vfree(&fields);
}
-// mkanames reads [568].out.h and writes anames[568].c
+static int
+xatoi(char *s, char **end)
+{
+ int val = 0;
+ for(; *s && *s >= '0' && *s <= '9'; ++s)
+ val = val * 10 + (*s - '0');
+ *end = s;
+ return val;
+}
+
+// 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.
+// It also writes out cnames array for C_* constants and the dnames
+// array for D_* constants.
void
mkanames(char *dir, char *file)
{
- int i, j, ch;
+ int i, j, ch, n, unknown;
Buf in, b, out, out2;
Vec lines;
- char *p;
+ char *p, *p2;
+ Vec dnames[128];
binit(&b);
binit(&in);
binit(&out);
binit(&out2);
vinit(&lines);
+ for(i=0; i<nelem(dnames); i++)
+ vinit(&dnames[i]);
ch = file[xstrlen(file)-3];
bprintf(&b, "%s/../cmd/%cl/%c.out.h", dir, ch, ch);
@@ -87,10 +101,12 @@ mkanames(char *dir, char *file)
// Include link.h so that the extern declaration there is
// checked against the non-extern declaration we are generating.
+ bwritestr(&out, bprintf(&b, "// auto generated by go tool dist\n"));
bwritestr(&out, bprintf(&b, "#include <u.h>\n"));
bwritestr(&out, bprintf(&b, "#include <libc.h>\n"));
bwritestr(&out, bprintf(&b, "#include <bio.h>\n"));
bwritestr(&out, bprintf(&b, "#include <link.h>\n"));
+ bwritestr(&out, bprintf(&b, "#include \"../cmd/%cl/%c.out.h\"\n", ch, ch));
bwritestr(&out, bprintf(&b, "\n"));
bwritestr(&out, bprintf(&b, "char* anames%c[] = {\n", ch));
@@ -127,6 +143,69 @@ mkanames(char *dir, char *file)
if(j>0)
bwriteb(&out, &out2);
+ j=unknown=0;
+ n=-1;
+ for(i=0; i<lines.len; i++) {
+ if(hasprefix(lines.p[i], "\tD_")) {
+ p = xstrstr(lines.p[i], ",");
+ if(p)
+ *p = '\0';
+ p = xstrstr(lines.p[i], "\n");
+ if(p)
+ *p = '\0';
+
+ // Parse explicit value, if any
+ p = xstrstr(lines.p[i], "=");
+ if(p) {
+ // Skip space after '='
+ p2 = p + 1;
+ while(*p2 == ' ' || *p2 == '\t')
+ p2++;
+ n = xatoi(p2, &p2);
+ // We can't do anything about
+ // non-numeric values or anything that
+ // follows
+ while(*p2 == ' ' || *p2 == '\t')
+ p2++;
+ if(*p2 != 0) {
+ unknown = 1;
+ continue;
+ }
+ // Truncate space before '='
+ while(*(p-1) == ' ' || *(p-1) == '\t')
+ p--;
+ *p = '\0';
+ unknown = 0;
+ } else {
+ n++;
+ }
+
+ if(unknown || n >= nelem(dnames))
+ continue;
+
+ p = lines.p[i] + 3;
+ if(xstrcmp(p, "LAST") == 0)
+ continue;
+ vadd(&dnames[n], p);
+ j++;
+ }
+ }
+ if(j>0){
+ bwritestr(&out, bprintf(&b, "char* dnames%c[D_LAST] = {\n", ch));
+ for(i=0; i<nelem(dnames); i++) {
+ if(dnames[i].len == 0)
+ continue;
+ bwritestr(&out, bprintf(&b, "\t[D_%s] = \"", dnames[i].p[0]));
+ for(j=0; j<dnames[i].len; j++) {
+ if(j != 0)
+ bwritestr(&out, "/");
+ bwritestr(&out, dnames[i].p[j]);
+ }
+ bwritestr(&out, "\",\n");
+ }
+ bwritestr(&out, "};\n");
+ }
+
writefile(&out, file, 0);
bfree(&b);
@@ -134,4 +213,6 @@ mkanames(char *dir, char *file)
bfree(&out);
bfree(&out2);
vfree(&lines);
+ for(i=0; i<nelem(dnames); i++)
+ vfree(&dnames[i]);
}
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
index bb774e05f..38e99e116 100644
--- a/src/cmd/dist/buildruntime.c
+++ b/src/cmd/dist/buildruntime.c
@@ -67,227 +67,8 @@ mkzexperiment(char *dir, char *file)
bfree(&exp);
}
-// mkzgoarch writes zgoarch_$GOARCH.go:
-//
-// package runtime
-// const theGoarch = <goarch>
-//
-void
-mkzgoarch(char *dir, char *file)
-{
- Buf b, out;
-
- USED(dir);
-
- binit(&b);
- binit(&out);
-
- bwritestr(&out, bprintf(&b,
- "// auto generated by go tool dist\n"
- "\n"
- "package runtime\n"
- "\n"
- "const theGoarch = `%s`\n", goarch));
-
- writefile(&out, file, 0);
-
- bfree(&b);
- bfree(&out);
-}
-
-// mkzgoos writes zgoos_$GOOS.go:
-//
-// package runtime
-// const theGoos = <goos>
-//
-void
-mkzgoos(char *dir, char *file)
-{
- Buf b, out;
-
- USED(dir);
-
- binit(&b);
- binit(&out);
-
- bwritestr(&out, "// auto generated by go tool dist\n\n");
-
- if(streq(goos, "linux")) {
- bwritestr(&out, "// +build !android\n\n");
- }
-
- bwritestr(&out, bprintf(&b,
- "package runtime\n"
- "\n"
- "const theGoos = `%s`\n", goos));
-
- writefile(&out, file, 0);
-
- bfree(&b);
- bfree(&out);
-}
-
-static struct {
- char *goarch;
- char *goos;
- char *hdr;
-} zasmhdr[] = {
- {"386", "",
- "#define get_tls(r) MOVL TLS, r\n"
- "#define g(r) 0(r)(TLS*1)\n"
- },
- {"amd64p32", "",
- "#define get_tls(r) MOVL TLS, r\n"
- "#define g(r) 0(r)(TLS*1)\n"
- },
- {"amd64", "",
- "#define get_tls(r) MOVQ TLS, r\n"
- "#define g(r) 0(r)(TLS*1)\n"
- },
-
- {"arm", "",
- "#define LR R14\n"
- },
-};
-
#define MAXWINCB 2000 /* maximum number of windows callbacks allowed */
-// mkzasm writes zasm_$GOOS_$GOARCH.h,
-// which contains struct offsets for use by
-// assembly files. It also writes a copy to the work space
-// under the name zasm_GOOS_GOARCH.h (no expansion).
-//
-void
-mkzasm(char *dir, char *file)
-{
- int i, n;
- char *aggr, *p;
- Buf in, b, b1, out, exp;
- Vec argv, lines, fields;
-
- binit(&in);
- binit(&b);
- binit(&b1);
- binit(&out);
- binit(&exp);
- vinit(&argv);
- vinit(&lines);
- vinit(&fields);
-
- bwritestr(&out, "// auto generated by go tool dist\n\n");
- if(streq(goos, "linux")) {
- bwritestr(&out, "// +build !android\n\n");
- }
-
- for(i=0; i<nelem(zasmhdr); i++) {
- if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) {
- bwritestr(&out, zasmhdr[i].hdr);
- goto ok;
- }
- }
- fatal("unknown $GOOS/$GOARCH in mkzasm");
-ok:
-
- copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
- bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
-
- // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c
- // to get acid [sic] output. Run once without the -a -o workdir/proc.acid in order to
- // report compilation failures (the -o redirects all messages, unfortunately).
- vreset(&argv);
- vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
- vadd(&argv, "-D");
- vadd(&argv, bprintf(&b, "GOOS_%s", goos));
- vadd(&argv, "-D");
- vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
- vadd(&argv, "-I");
- vadd(&argv, bprintf(&b, "%s", workdir));
- vadd(&argv, "-I");
- vadd(&argv, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
- vadd(&argv, "-n");
- vadd(&argv, "-a");
- vadd(&argv, "-o");
- vadd(&argv, bpathf(&b, "%s/proc.acid", workdir));
- vadd(&argv, "proc.c");
- runv(nil, dir, CheckExit, &argv);
- readfile(&in, bpathf(&b, "%s/proc.acid", workdir));
-
- // Convert input like
- // aggr G
- // {
- // Gobuf 24 sched;
- // 'Y' 48 stack0;
- // }
- // StackMin = 128;
- // into output like
- // #define g_sched 24
- // #define g_stack0 48
- // #define const_StackMin 128
- aggr = nil;
- splitlines(&lines, bstr(&in));
- for(i=0; i<lines.len; i++) {
- splitfields(&fields, lines.p[i]);
- if(fields.len == 2 && streq(fields.p[0], "aggr")) {
- if(streq(fields.p[1], "G"))
- aggr = "g";
- else if(streq(fields.p[1], "M"))
- aggr = "m";
- else if(streq(fields.p[1], "P"))
- aggr = "p";
- else if(streq(fields.p[1], "Gobuf"))
- aggr = "gobuf";
- else if(streq(fields.p[1], "LibCall"))
- aggr = "libcall";
- else if(streq(fields.p[1], "WinCallbackContext"))
- aggr = "cbctxt";
- else if(streq(fields.p[1], "SEH"))
- aggr = "seh";
- else if(streq(fields.p[1], "Alg"))
- aggr = "alg";
- else if(streq(fields.p[1], "Panic"))
- aggr = "panic";
- else if(streq(fields.p[1], "Stack"))
- aggr = "stack";
- }
- if(hasprefix(lines.p[i], "}"))
- aggr = nil;
- if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) {
- n = fields.len;
- p = fields.p[n-1];
- if(p[xstrlen(p)-1] == ';')
- p[xstrlen(p)-1] = '\0';
- bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2]));
- }
- if(fields.len == 3 && streq(fields.p[1], "=")) { // generated from enumerated constants
- p = fields.p[2];
- if(p[xstrlen(p)-1] == ';')
- p[xstrlen(p)-1] = '\0';
- bwritestr(&out, bprintf(&b, "#define const_%s %s\n", fields.p[0], p));
- }
- }
-
- // Some #defines that are used for .c files.
- if(streq(goos, "windows")) {
- bwritestr(&out, bprintf(&b, "#define cb_max %d\n", MAXWINCB));
- }
-
- xgetenv(&exp, "GOEXPERIMENT");
- bwritestr(&out, bprintf(&b, "#define GOEXPERIMENT \"%s\"\n", bstr(&exp)));
-
- // Write both to file and to workdir/zasm_GOOS_GOARCH.h.
- writefile(&out, file, 0);
- writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0);
-
- bfree(&in);
- bfree(&b);
- bfree(&b1);
- bfree(&out);
- bfree(&exp);
- vfree(&argv);
- vfree(&lines);
- vfree(&fields);
-}
-
// mkzsys writes zsys_$GOOS_$GOARCH.s,
// which contains arch or os specific asm code.
//
@@ -326,143 +107,3 @@ mkzsys(char *dir, char *file)
bfree(&out);
}
-
-static char *runtimedefs[] = {
- "defs.c",
- "malloc.c",
- "mcache.c",
- "mgc0.c",
- "proc.c",
- "parfor.c",
- "stack.c",
-};
-
-// mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h,
-// which contains Go struct definitions equivalent to the C ones.
-// Mostly we just write the output of 6c -q to the file.
-// However, we run it on multiple files, so we have to delete
-// the duplicated definitions, and we don't care about the funcs,
-// so we delete those too.
-//
-void
-mkzruntimedefs(char *dir, char *file)
-{
- int i, skip;
- char *p;
- Buf in, b, b1, out;
- Vec argv, lines, fields, seen;
-
- binit(&in);
- binit(&b);
- binit(&b1);
- binit(&out);
- vinit(&argv);
- vinit(&lines);
- vinit(&fields);
- vinit(&seen);
-
- bwritestr(&out, "// auto generated by go tool dist\n"
- "\n");
-
- if(streq(goos, "linux")) {
- bwritestr(&out, "// +build !android\n\n");
- }
-
- bwritestr(&out,
- "package runtime\n"
- "import \"unsafe\"\n"
- "var _ unsafe.Pointer\n"
- "\n"
- );
-
- // Do not emit definitions for these.
- vadd(&seen, "true");
- vadd(&seen, "false");
- vadd(&seen, "raceenabled");
- vadd(&seen, "allgs");
-
- // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -q -n -o workdir/runtimedefs
- // on each of the runtimedefs C files.
- vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
- vadd(&argv, "-D");
- vadd(&argv, bprintf(&b, "GOOS_%s", goos));
- vadd(&argv, "-D");
- vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
- vadd(&argv, "-I");
- vadd(&argv, bprintf(&b, "%s", workdir));
- vadd(&argv, "-I");
- vadd(&argv, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
- vadd(&argv, "-q");
- vadd(&argv, "-n");
- vadd(&argv, "-o");
- vadd(&argv, bpathf(&b, "%s/runtimedefs", workdir));
- vadd(&argv, "");
- p = argv.p[argv.len-1];
- for(i=0; i<nelem(runtimedefs); i++) {
- argv.p[argv.len-1] = runtimedefs[i];
- runv(nil, dir, CheckExit, &argv);
- readfile(&b, bpathf(&b1, "%s/runtimedefs", workdir));
- bwriteb(&in, &b);
- }
- argv.p[argv.len-1] = p;
-
- // Process the aggregate output.
- skip = 0;
- splitlines(&lines, bstr(&in));
- for(i=0; i<lines.len; i++) {
- p = lines.p[i];
- // Drop comment and func lines.
- if(hasprefix(p, "//") || hasprefix(p, "func"))
- continue;
-
- // Note beginning of type or var decl, which can be multiline.
- // Remove duplicates. The linear check of seen here makes the
- // whole processing quadratic in aggregate, but there are only
- // about 100 declarations, so this is okay (and simple).
- if(hasprefix(p, "type ") || hasprefix(p, "var ") || hasprefix(p, "const ")) {
- splitfields(&fields, p);
- if(fields.len < 2)
- continue;
- if(find(fields.p[1], seen.p, seen.len) >= 0) {
- if(streq(fields.p[fields.len-1], "{"))
- skip = 1; // skip until }
- continue;
- }
- vadd(&seen, fields.p[1]);
- }
-
- // Const lines are printed in original case (usually upper). Add a leading _ as needed.
- if(hasprefix(p, "const ")) {
- if('A' <= p[6] && p[6] <= 'Z')
- bwritestr(&out, "const _");
- else
- bwritestr(&out, "const ");
- bwritestr(&out, p+6);
- continue;
- }
-
- if(skip) {
- if(hasprefix(p, "}"))
- skip = 0;
- continue;
- }
-
- bwritestr(&out, p);
- }
-
- // Some windows specific const.
- if(streq(goos, "windows")) {
- bwritestr(&out, bprintf(&b, "const cb_max = %d\n", MAXWINCB));
- }
-
- writefile(&out, file, 0);
-
- bfree(&in);
- bfree(&b);
- bfree(&b1);
- bfree(&out);
- vfree(&argv);
- vfree(&lines);
- vfree(&fields);
- vfree(&seen);
-}
diff --git a/src/cmd/dist/unix.c b/src/cmd/dist/unix.c
index 4a78684b4..893ed5cdd 100644
--- a/src/cmd/dist/unix.c
+++ b/src/cmd/dist/unix.c
@@ -708,6 +708,10 @@ main(int argc, char **argv)
gohostarch = "386";
else if(contains(u.machine, "arm"))
gohostarch = "arm";
+ else if(contains(u.machine, "ppc64le"))
+ gohostarch = "power64le";
+ else if(contains(u.machine, "ppc64"))
+ gohostarch = "power64";
else
fatal("unknown architecture: %s", u.machine);
}
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
index 2e79f6f1d..fe9a168dc 100644
--- a/src/cmd/gc/bits.c
+++ b/src/cmd/gc/bits.c
@@ -95,11 +95,11 @@ int
bnum(Bits a)
{
int i;
- int32 b;
+ uint64 b;
for(i=0; i<BITS; i++)
if(b = a.b[i])
- return 32*i + bitno(b);
+ return 64*i + bitno(b);
fatal("bad in bnum");
return 0;
}
@@ -110,27 +110,35 @@ blsh(uint n)
Bits c;
c = zbits;
- c.b[n/32] = 1L << (n%32);
+ c.b[n/64] = 1LL << (n%64);
return c;
}
-/*
int
-bset(Bits a, uint n)
+btest(Bits *a, uint n)
{
- if(a.b[n/32] & (1L << (n%32)))
- return 1;
- return 0;
+ return (a->b[n/64] & (1LL << (n%64))) != 0;
+}
+
+void
+biset(Bits *a, uint n)
+{
+ a->b[n/64] |= 1LL << (n%64);
+}
+
+void
+biclr(Bits *a, uint n)
+{
+ a->b[n/64] &= ~(1LL << (n%64));
}
-*/
int
-bitno(int32 b)
+bitno(uint64 b)
{
int i;
- for(i=0; i<32; i++)
- if(b & (1L<<i))
+ for(i=0; i<64; i++)
+ if(b & (1LL<<i))
return i;
fatal("bad in bitno");
return 0;
@@ -157,7 +165,7 @@ Qconv(Fmt *fp)
if(var[i].offset != 0)
fmtprint(fp, "%+lld", (vlong)var[i].offset);
}
- bits.b[i/32] &= ~(1L << (i%32));
+ biclr(&bits, i);
}
return 0;
}
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
index da5984ceb..aeee55236 100644
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -7,6 +7,8 @@
#include "go.h"
#include "y.tab.h"
+static NodeList *asmlist;
+
static void dumpexporttype(Type *t);
// Mark n's symbol as exported
@@ -68,6 +70,11 @@ autoexport(Node *n, int ctxt)
// -A is for cmd/gc/mkbuiltin script, so export everything
if(debug['A'] || exportname(n->sym->name) || initname(n->sym->name))
exportsym(n);
+ if(asmhdr && n->sym->pkg == localpkg && !(n->sym->flags & SymAsm)) {
+ n->sym->flags |= SymAsm;
+ asmlist = list(asmlist, n);
+ }
+
}
static void
@@ -519,3 +526,37 @@ importtype(Type *pt, Type *t)
if(debug['E'])
print("import type %T %lT\n", pt, t);
}
+
+void
+dumpasmhdr(void)
+{
+ Biobuf *b;
+ NodeList *l;
+ Node *n;
+ Type *t;
+
+ 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);
+ for(l=asmlist; l; l=l->next) {
+ n = l->n;
+ if(isblanksym(n->sym))
+ continue;
+ switch(n->op) {
+ case OLITERAL:
+ Bprint(b, "#define const_%s %#V\n", n->sym->name, &n->val);
+ break;
+ case OTYPE:
+ t = n->type;
+ if(t->etype != TSTRUCT || t->map != T || t->funarg)
+ break;
+ for(t=t->type; t != T; t=t->down)
+ if(!isblanksym(t->sym))
+ Bprint(b, "#define %s_%s %d\n", n->sym->name, t->sym->name, (int)t->width);
+ break;
+ }
+ }
+
+ Bterm(b);
+}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 965a0550d..6e326961d 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -382,6 +382,7 @@ enum
SymExported = 1<<2, // already written out by export
SymUniq = 1<<3,
SymSiggen = 1<<4,
+ SymAsm = 1<<5,
};
struct Sym
@@ -393,6 +394,7 @@ struct Sym
int32 npkg; // number of imported packages with this name
uint32 uniqgen;
Pkg* importdef; // where imported definition was found
+ char* linkname; // link name
// saved and restored by dcopy
Pkg* pkg;
@@ -704,13 +706,13 @@ enum
Ecomplit = 1<<11, // type in composite literal
};
-#define BITS 5
-#define NVAR (BITS*sizeof(uint32)*8)
+#define BITS 3
+#define NVAR (BITS*sizeof(uint64)*8)
typedef struct Bits Bits;
struct Bits
{
- uint32 b[BITS];
+ uint64 b[BITS];
};
EXTERN Bits zbits;
@@ -860,6 +862,8 @@ EXTERN int32 lexlineno;
EXTERN int32 lineno;
EXTERN int32 prevlineno;
+EXTERN Fmt pragcgobuf;
+
EXTERN char* infile;
EXTERN char* outfile;
EXTERN Biobuf* bout;
@@ -890,6 +894,7 @@ EXTERN Pkg* typelinkpkg; // fake package for runtime type info (data)
EXTERN Pkg* weaktypepkg; // weak references to runtime type info
EXTERN Pkg* unsafepkg; // package unsafe
EXTERN Pkg* trackpkg; // fake package for field tracking
+EXTERN Pkg* rawpkg; // fake package for raw symbol names
EXTERN Pkg* phash[128];
EXTERN int tptr; // either TPTR32 or TPTR64
extern char* runtimeimport;
@@ -897,6 +902,7 @@ extern char* unsafeimport;
EXTERN char* myimportpath;
EXTERN Idir* idirs;
EXTERN char* localimport;
+EXTERN char* asmhdr;
EXTERN Type* types[NTYPE];
EXTERN Type* idealstring;
@@ -1027,12 +1033,14 @@ int Qconv(Fmt *fp);
Bits band(Bits a, Bits b);
int bany(Bits *a);
int beq(Bits a, Bits b);
-int bitno(int32 b);
+int bitno(uint64 b);
Bits blsh(uint n);
Bits bnot(Bits a);
int bnum(Bits a);
Bits bor(Bits a, Bits b);
-int bset(Bits a, uint n);
+int btest(Bits *a, uint n);
+void biset(Bits *a, uint n);
+void biclr(Bits *a, uint n);
/*
* bv.c
@@ -1145,6 +1153,7 @@ void escapes(NodeList*);
*/
void autoexport(Node *n, int ctxt);
void dumpexport(void);
+void dumpasmhdr(void);
int exportname(char *s);
void exportsym(Node *n);
void importconst(Sym *s, Type *t, Node *n);
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 523ba37aa..2bd7adfb6 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -17,6 +17,8 @@ extern int yychar;
int yyprev;
int yylast;
+static int imported_unsafe;
+
static void lexinit(void);
static void lexinit1(void);
static void lexfini(void);
@@ -271,6 +273,9 @@ main(int argc, char *argv[])
flag_largemodel = 1;
setexp();
+
+ fmtstrinit(&pragcgobuf);
+ quotefmtinstall();
outfile = nil;
flagcount("+", "compiling runtime", &compiling_runtime);
@@ -289,6 +294,7 @@ main(int argc, char *argv[])
flagcount("S", "print assembly listing", &debug['S']);
flagfn0("V", "print compiler version", doversion);
flagcount("W", "debug parse tree after type checking", &debug['W']);
+ flagstr("asmhdr", "file: write assembly header to named file", &asmhdr);
flagcount("complete", "compiling complete package (no C or assembly)", &pure_go);
flagstr("d", "list: print debug information about items in list", &debugstr);
flagcount("e", "no limit on number of errors reported", &debug['e']);
@@ -403,6 +409,8 @@ main(int argc, char *argv[])
block = 1;
iota = -1000000;
+
+ imported_unsafe = 0;
yyparse();
if(nsyntaxerrors != 0)
@@ -509,6 +517,9 @@ main(int argc, char *argv[])
errorexit();
dumpobj();
+
+ if(asmhdr)
+ dumpasmhdr();
if(nerrors+nsavederrors)
errorexit();
@@ -724,6 +735,7 @@ importfile(Val *f, int line)
}
importpkg = mkpkg(f->u.sval);
cannedimports("unsafe.6", unsafeimport);
+ imported_unsafe = 1;
return;
}
@@ -1501,6 +1513,20 @@ caseout:
return LLITERAL;
}
+static void pragcgo(char*);
+
+static int
+more(char **pp)
+{
+ char *p;
+
+ p = *pp;
+ while(yy_isspace(*p))
+ p++;
+ *pp = p;
+ return *p != '\0';
+}
+
/*
* read and interpret syntax that looks like
* //line parse.y:15
@@ -1583,9 +1609,39 @@ go:
*cp++ = c;
}
*cp = 0;
+
+ if(strncmp(lexbuf, "go:cgo_", 7) == 0)
+ pragcgo(lexbuf);
+
ep = strchr(lexbuf, ' ');
if(ep != nil)
*ep = 0;
+
+ if(strcmp(lexbuf, "go:linkname") == 0) {
+ if(!imported_unsafe)
+ yyerror("//go:linkname only allowed in Go files that import \"unsafe\"");
+ if(ep == nil) {
+ yyerror("usage: //go:linkname localname linkname");
+ goto out;
+ }
+ cp = ep+1;
+ while(yy_isspace(*cp))
+ cp++;
+ ep = strchr(cp, ' ');
+ if(ep == nil) {
+ yyerror("usage: //go:linkname localname linkname");
+ goto out;
+ }
+ *ep++ = 0;
+ while(yy_isspace(*ep))
+ ep++;
+ if(*ep == 0) {
+ yyerror("usage: //go:linkname localname linkname");
+ goto out;
+ }
+ lookup(cp)->linkname = strdup(ep);
+ goto out;
+ }
if(strcmp(lexbuf, "go:nointerface") == 0 && fieldtrack_enabled) {
nointerface = 1;
@@ -1604,6 +1660,150 @@ out:
return c;
}
+static char*
+getimpsym(char **pp)
+{
+ char *p, *start;
+
+ more(pp); // skip spaces
+
+ p = *pp;
+ if(*p == '\0' || *p == '"')
+ return nil;
+
+ start = p;
+ while(*p != '\0' && !yy_isspace(*p) && *p != '"')
+ p++;
+ if(*p != '\0')
+ *p++ = '\0';
+
+ *pp = p;
+ return start;
+}
+
+static char*
+getquoted(char **pp)
+{
+ char *p, *start;
+
+ more(pp); // skip spaces
+
+ p = *pp;
+ if(*p != '"')
+ return nil;
+ p++;
+
+ start = p;
+ while(*p != '"') {
+ if(*p == '\0')
+ return nil;
+ p++;
+ }
+ *p++ = '\0';
+ *pp = p;
+ return start;
+}
+
+// Copied nearly verbatim from the C compiler's #pragma parser.
+// TODO: Rewrite more cleanly once the compiler is written in Go.
+static void
+pragcgo(char *text)
+{
+ char *local, *remote, *p, *q, *verb;
+
+ for(q=text; *q != '\0' && *q != ' '; q++)
+ ;
+ if(*q == ' ')
+ *q++ = '\0';
+
+ verb = text+3; // skip "go:"
+
+ if(strcmp(verb, "cgo_dynamic_linker") == 0 || strcmp(verb, "dynlinker") == 0) {
+ p = getquoted(&q);
+ if(p == nil)
+ goto err1;
+ fmtprint(&pragcgobuf, "cgo_dynamic_linker %q\n", p);
+ goto out;
+
+ err1:
+ yyerror("usage: //go:cgo_dynamic_linker \"path\"");
+ goto out;
+ }
+
+ if(strcmp(verb, "dynexport") == 0)
+ verb = "cgo_export_dynamic";
+ if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) {
+ local = getimpsym(&q);
+ if(local == nil)
+ goto err2;
+ if(!more(&q)) {
+ fmtprint(&pragcgobuf, "%s %q\n", verb, local);
+ goto out;
+ }
+ remote = getimpsym(&q);
+ if(remote == nil)
+ goto err2;
+ fmtprint(&pragcgobuf, "%s %q %q\n", verb, local, remote);
+ goto out;
+
+ err2:
+ yyerror("usage: //go:%s local [remote]", verb);
+ goto out;
+ }
+
+ if(strcmp(verb, "cgo_import_dynamic") == 0 || strcmp(verb, "dynimport") == 0) {
+ local = getimpsym(&q);
+ if(local == nil)
+ goto err3;
+ if(!more(&q)) {
+ fmtprint(&pragcgobuf, "cgo_import_dynamic %q\n", local);
+ goto out;
+ }
+ remote = getimpsym(&q);
+ if(remote == nil)
+ goto err3;
+ if(!more(&q)) {
+ fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q\n", local, remote);
+ goto out;
+ }
+ p = getquoted(&q);
+ if(p == nil)
+ goto err3;
+ fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q %q\n", local, remote, p);
+ goto out;
+
+ err3:
+ yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]");
+ goto out;
+ }
+
+ if(strcmp(verb, "cgo_import_static") == 0) {
+ local = getimpsym(&q);
+ if(local == nil || more(&q))
+ goto err4;
+ fmtprint(&pragcgobuf, "cgo_import_static %q\n", local);
+ goto out;
+
+ err4:
+ yyerror("usage: //go:cgo_import_static local");
+ goto out;
+ }
+
+ if(strcmp(verb, "cgo_ldflag") == 0) {
+ p = getquoted(&q);
+ if(p == nil)
+ goto err5;
+ fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p);
+ goto out;
+
+ err5:
+ yyerror("usage: //go:cgo_ldflag \"arg\"");
+ goto out;
+ }
+
+out:;
+}
+
int32
yylex(void)
{
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index b752a13ce..7e4e97854 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -67,6 +67,16 @@ dumpobj(void)
startobj = Boffset(bout);
Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
}
+
+ if(pragcgobuf.to > pragcgobuf.start) {
+ if(writearchive) {
+ // write empty export section; must be before cgo section
+ Bprint(bout, "\n$$\n\n$$\n\n");
+ }
+ Bprint(bout, "\n$$ // cgo\n");
+ Bprint(bout, "%s\n$$\n\n", fmtstrflush(&pragcgobuf));
+ }
+
Bprint(bout, "\n!\n");
@@ -153,6 +163,8 @@ linksym(Sym *s)
return s->lsym;
if(isblanksym(s))
s->lsym = linklookup(ctxt, "_", 0);
+ else if(s->linkname != nil)
+ s->lsym = linklookup(ctxt, s->linkname, 0);
else {
p = smprint("%s.%s", s->pkg->prefix, s->name);
s->lsym = linklookup(ctxt, p, 0);
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index 39028e3f8..259cec85a 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -471,7 +471,7 @@ allocauto(Prog* ptxt)
stksize = rnd(stksize, n->type->align);
if(haspointers(n->type))
stkptrsize = stksize;
- if(thechar == '5')
+ if(thechar == '5' || thechar == '9')
stksize = rnd(stksize, widthptr);
if(stksize >= (1ULL<<31)) {
setlineno(curfn);
@@ -528,7 +528,7 @@ cgen_checknil(Node *n)
dump("checknil", n);
fatal("bad checknil");
}
- if((thechar == '5' && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
+ 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);
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
index 0feb2c710..3bfa69b1f 100644
--- a/src/cmd/gc/plive.c
+++ b/src/cmd/gc/plive.c
@@ -1092,7 +1092,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
case TCOMPLEX64:
case TCOMPLEX128:
for(i = 0; i < t->width; i++) {
- bvset(bv, ((*xoffset + i) / widthptr) * BitsPerPointer); // 1 = live scalar
+ bvset(bv, ((*xoffset + i) / widthptr) * BitsPerPointer); // 1 = live scalar (BitsScalar)
}
*xoffset += t->width;
break;
@@ -1105,7 +1105,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
case TMAP:
if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr (BitsPointer)
*xoffset += t->width;
break;
@@ -1113,7 +1113,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
// struct { byte *str; intgo len; }
if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer)
*xoffset += t->width;
break;
@@ -1123,15 +1123,8 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
// struct { Type *type; union { void *ptr, uintptr val } data; }
if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid alignment, %T", t);
- bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 0);
- bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1); // 3 = multiword
- // next word contains 2 = Iface, 3 = Eface
- if(isnilinter(t)) {
- bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 2);
- bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3);
- } else {
- bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3);
- }
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer)
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 3); // 2 = live ptr in second slot (BitsPointer)
*xoffset += t->width;
break;
@@ -1144,7 +1137,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
// struct { byte *array; uintgo len; uintgo cap; }
if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid TARRAY alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer)
*xoffset += t->width;
} else
for(i = 0; i < t->bound; i++)
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index b2ff2fbc5..4155953be 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -1318,7 +1318,7 @@ gengcmask(Type *t, uint8 gcmask[16])
{
Bvec *vec;
vlong xoffset, nptr, i, j;
- int half, mw;
+ int half;
uint8 bits, *pos;
memset(gcmask, 0, 16);
@@ -1335,7 +1335,6 @@ gengcmask(Type *t, uint8 gcmask[16])
pos = (uint8*)gcmask;
nptr = (t->width+widthptr-1)/widthptr;
half = 0;
- mw = 0;
// If number of words is odd, repeat the mask.
// This makes simpler handling of arrays in runtime.
for(j=0; j<=(nptr%2); j++) {
@@ -1344,9 +1343,8 @@ gengcmask(Type *t, uint8 gcmask[16])
// Some fake types (e.g. Hmap) has missing fileds.
// twobitwalktype1 generates BitsDead for that holes,
// replace BitsDead with BitsScalar.
- if(!mw && bits == BitsDead)
+ if(bits == BitsDead)
bits = BitsScalar;
- mw = !mw && bits == BitsMultiWord;
bits <<= 2;
if(half)
bits <<= 4;
@@ -1525,11 +1523,9 @@ gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
*xoffset += t->width;
break;
case TINTER:
- proggendata(g, BitsMultiWord);
- if(isnilinter(t))
- proggendata(g, BitsEface);
- else
- proggendata(g, BitsIface);
+ // Assuming IfacePointerOnly=1.
+ proggendata(g, BitsPointer);
+ proggendata(g, BitsPointer);
*xoffset += t->width;
break;
case TARRAY:
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index c3bc5af3b..5e369b695 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -3802,39 +3802,25 @@ checknil(Node *x, NodeList **init)
/*
* Can this type be stored directly in an interface word?
+ * Yes, if the representation is a single pointer.
*/
int
isdirectiface(Type *t)
{
- // Setting IfacePointerOnly = 1 changes the
- // interface representation so that the data word
- // in an interface value must always be a pointer.
- // Setting it to 0 uses the original representation,
- // where the data word can hold a pointer or any
- // non-pointer value no bigger than a pointer.
- enum {
- IfacePointerOnly = 1,
- };
-
- if(IfacePointerOnly) {
- switch(t->etype) {
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TMAP:
- case TFUNC:
- case TUNSAFEPTR:
- return 1;
- case TARRAY:
- // Array of 1 direct iface type can be direct.
- return t->bound == 1 && isdirectiface(t->type);
- case TSTRUCT:
- // Struct with 1 field of direct iface type can be direct.
- return t->type != T && t->type->down == T && isdirectiface(t->type->type);
- }
- return 0;
+ switch(t->etype) {
+ case TPTR32:
+ case TPTR64:
+ case TCHAN:
+ case TMAP:
+ case TFUNC:
+ case TUNSAFEPTR:
+ return 1;
+ case TARRAY:
+ // Array of 1 direct iface type can be direct.
+ return t->bound == 1 && isdirectiface(t->type);
+ case TSTRUCT:
+ // Struct with 1 field of direct iface type can be direct.
+ return t->type != T && t->type->down == T && isdirectiface(t->type->type);
}
-
- dowidth(t);
- return t->width <= widthptr;
+ return 0;
}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index ff9b36208..77f9c80f9 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -1766,7 +1766,6 @@ walkprint(Node *nn, NodeList **init)
int notfirst, et, op;
NodeList *calls;
- on = nil;
op = nn->op;
all = nn->list;
calls = nil;
@@ -3301,6 +3300,9 @@ walkrotate(Node **np)
int w, sl, sr, s;
Node *l, *r;
Node *n;
+
+ if(thechar == '9')
+ return;
n = *np;
@@ -3426,6 +3428,10 @@ walkdiv(Node **np, NodeList **init)
Type *twide;
Magic m;
+ // TODO(minux)
+ if(thechar == '9')
+ return;
+
n = *np;
if(n->right->op != OLITERAL)
return;
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 1dd4314da..5dcaa04a1 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -813,7 +813,7 @@ func (b *builder) build(a *action) (err error) {
}
if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" &&
- !hasString(a.p.HFiles, "zasm_"+buildContext.GOOS+"_"+buildContext.GOARCH+".h") {
+ !hasString(a.p.SFiles, "zsys_"+buildContext.GOOS+"_"+buildContext.GOARCH+".s") {
return fmt.Errorf("%s/%s must be bootstrapped using make%v", buildContext.GOOS, buildContext.GOARCH, defaultSuffix())
}
@@ -941,7 +941,7 @@ func (b *builder) build(a *action) (err error) {
inc := b.includeArgs("-I", a.deps)
// Compile Go.
- ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles)
+ ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, len(sfiles) > 0, inc, gofiles)
if len(out) > 0 {
b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
if err != nil {
@@ -1550,7 +1550,7 @@ type toolchain interface {
// gc runs the compiler in a specific directory on a set of files
// and returns the name of the generated output file.
// The compiler runs in the directory dir.
- gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
+ gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
// cc runs the toolchain's C compiler in a directory on a C file
// to produce an output file.
cc(b *builder, p *Package, objdir, ofile, cfile string) error
@@ -1587,7 +1587,7 @@ func (noToolchain) linker() string {
return ""
}
-func (noToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
+func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
return "", nil, noCompiler()
}
@@ -1623,7 +1623,7 @@ func (gcToolchain) linker() string {
return tool(archChar + "l")
}
-func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
if archive != "" {
ofile = archive
} else {
@@ -1660,6 +1660,9 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []
if ofile == archive {
args = append(args, "-pack")
}
+ if asmhdr {
+ args = append(args, "-asmhdr", obj+"go_asm.h")
+ }
for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f))
}
@@ -1824,18 +1827,7 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
}
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
- inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
- cfile = mkAbs(p.Dir, cfile)
- warn := []string{"-w"}
- if p.usesSwig() {
- // When using SWIG, this compiler is only used to
- // compile the C files generated by SWIG.
- // We don't want warnings.
- // See issue 9065 for details.
- warn = nil
- }
- args := stringList(tool(archChar+"c"), "-F", "-V", warn, "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
- return b.run(p.Dir, p.ImportPath, nil, args)
+ return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile))
}
// The Gccgo toolchain.
@@ -1859,7 +1851,7 @@ func (gccgoToolchain) linker() string {
return gccgoBin
}
-func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
out := "_go_.o"
ofile = obj + out
gcargs := []string{"-g"}
@@ -2225,11 +2217,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
outGo = append(outGo, gofiles...)
// cc _cgo_defun.c
- defunObj := obj + "_cgo_defun." + objExt
- if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
- return nil, nil, err
+ _, gccgo := buildToolchain.(gccgoToolchain)
+ if gccgo {
+ defunObj := obj + "_cgo_defun." + objExt
+ if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
+ return nil, nil, err
+ }
+ outObj = append(outObj, defunObj)
}
- outObj = append(outObj, defunObj)
// gcc
var linkobj []string
@@ -2343,20 +2338,15 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
}
// cgo -dynimport
- importC := obj + "_cgo_import.c"
+ importGo := obj + "_cgo_import.go"
cgoflags = []string{}
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, "-dynimport", dynobj, "-dynout", importC, cgoflags); err != nil {
- return nil, nil, err
- }
-
- // cc _cgo_import.ARCH
- importObj := obj + "_cgo_import." + objExt
- if err := buildToolchain.cc(b, p, obj, importObj, importC); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, nil, cgoExe, "-objdir", obj, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags); err != nil {
return nil, nil, err
}
+ outGo = append(outGo, importGo)
ofile := obj + "_all.o"
var gccObjs, nonGccObjs []string
@@ -2390,7 +2380,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
// NOTE(rsc): The importObj is a 5c/6c/8c object and on Windows
// must be processed before the gcc-generated objects.
// Put it first. http://golang.org/issue/2601
- outObj = stringList(importObj, nonGccObjs, ofile)
+ outObj = stringList(nonGccObjs, ofile)
return outGo, outObj, nil
}
@@ -2526,7 +2516,7 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
p := goFilesPackage(srcs)
- if _, _, e := buildToolchain.gc(b, p, "", obj, nil, srcs); e != nil {
+ if _, _, e := buildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil {
return "32", nil
}
return "64", nil
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 61847546a..92c6fb57c 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -445,11 +445,11 @@ blk(LSym *start, int64 addr, int64 size)
continue;
if(sym->value >= eaddr)
break;
+ ctxt->cursym = sym;
if(sym->value < addr) {
diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type);
errorexit();
}
- ctxt->cursym = sym;
for(; addr < sym->value; addr++)
cput(0);
p = sym->p;
@@ -463,6 +463,8 @@ blk(LSym *start, int64 addr, int64 size)
diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size);
errorexit();
}
+ if(sym->value+sym->size >= eaddr)
+ break;
}
for(; addr < eaddr; addr++)
diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go
index 5b5833db5..ad35df740 100644
--- a/src/cmd/ld/doc.go
+++ b/src/cmd/ld/doc.go
@@ -10,8 +10,8 @@ Ld is the portable code for a modified version of the Plan 9 linker. The origin
http://plan9.bell-labs.com/magic/man2html/1/8l
-It reads object files (.5, .6, or .8 files) and writes a binary named for the
-architecture (5.out, 6.out, 8.out) by default (if $GOOS is windows, a .exe suffix
+It reads object files (.5, .6, .8, .9 files) and writes a binary named for the
+architecture (5.out, 6.out, 8.out, 9.out) by default (if $GOOS is windows, a .exe suffix
will be appended).
Major changes include:
@@ -22,7 +22,7 @@ Original options are listed on the manual page linked above.
Usage:
go tool 6l [flags] mainObj
-Substitute 6l with 8l or 5l as appropriate.
+Substitute 6l with 5l, 8l or 9l as appropriate.
Options new in this version:
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index a3ba52325..fbb5699bd 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -2189,7 +2189,7 @@ dwarfaddshstrings(LSym *shstrtab)
elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str");
elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts");
if(linkmode == LinkExternal) {
- if(thechar == '6') {
+ if(thechar == '6' || thechar == '9') {
elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rela.debug_info");
elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rela.debug_aranges");
elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rela.debug_line");
@@ -2244,7 +2244,7 @@ dwarfaddelfrelocheader(int elfstr, ElfShdr *shdata, vlong off, vlong size)
ElfShdr *sh;
sh = newElfShdr(elfstrdbg[elfstr]);
- if(thechar == '6') {
+ if(thechar == '6' || thechar == '9') {
sh->type = SHT_RELA;
} else {
sh->type = SHT_REL;
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index 3196961f3..6ac6b6ee8 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -45,6 +45,7 @@ elfinit(void)
switch(thechar) {
// 64-bit architectures
case '6':
+ case '9':
elf64 = 1;
hdr.phoff = ELF64HDRSIZE; /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
hdr.shoff = ELF64HDRSIZE; /* Will move as we add PHeaders */
@@ -678,7 +679,7 @@ elfdynhash(void)
elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0));
}
- if(thechar == '6') {
+ if(thechar == '6' || thechar == '9') {
sy = linklookup(ctxt, ".rela.plt", 0);
if(sy->size > 0) {
elfwritedynent(s, DT_PLTREL, DT_RELA);
@@ -804,7 +805,7 @@ elfshreloc(Section *sect)
if(strcmp(sect->name, ".shstrtab") == 0 || strcmp(sect->name, ".tbss") == 0)
return nil;
- if(thechar == '6') {
+ if(thechar == '6' || thechar == '9') {
prefix = ".rela";
typ = SHT_RELA;
} else {
@@ -931,7 +932,7 @@ doelf(void)
debug['s'] = 0;
debug['d'] = 1;
- if(thechar == '6') {
+ if(thechar == '6' || thechar == '9') {
addstring(shstrtab, ".rela.text");
addstring(shstrtab, ".rela.rodata");
addstring(shstrtab, ".rela.typelink");
@@ -954,7 +955,7 @@ doelf(void)
if(flag_shared) {
addstring(shstrtab, ".init_array");
- if(thechar == '6')
+ if(thechar == '6' || thechar == '9')
addstring(shstrtab, ".rela.init_array");
else
addstring(shstrtab, ".rel.init_array");
@@ -975,7 +976,7 @@ doelf(void)
addstring(shstrtab, ".dynamic");
addstring(shstrtab, ".dynsym");
addstring(shstrtab, ".dynstr");
- if(thechar == '6') {
+ if(thechar == '6' || thechar == '9') {
addstring(shstrtab, ".rela");
addstring(shstrtab, ".rela.plt");
} else {
@@ -990,7 +991,7 @@ doelf(void)
s = linklookup(ctxt, ".dynsym", 0);
s->type = SELFROSECT;
s->reachable = 1;
- if(thechar == '6')
+ if(thechar == '6' || thechar == '9')
s->size += ELF64SYMSIZE;
else
s->size += ELF32SYMSIZE;
@@ -1004,7 +1005,7 @@ doelf(void)
dynstr = s;
/* relocation table */
- if(thechar == '6')
+ if(thechar == '6' || thechar == '9')
s = linklookup(ctxt, ".rela", 0);
else
s = linklookup(ctxt, ".rel", 0);
@@ -1031,7 +1032,7 @@ doelf(void)
elfsetupplt();
- if(thechar == '6')
+ if(thechar == '6' || thechar == '9')
s = linklookup(ctxt, ".rela.plt", 0);
else
s = linklookup(ctxt, ".rel.plt", 0);
@@ -1056,13 +1057,13 @@ doelf(void)
*/
elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0));
- if(thechar == '6')
+ if(thechar == '6' || thechar == '9')
elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
else
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0));
elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0));
- if(thechar == '6') {
+ if(thechar == '6' || thechar == '9') {
elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0));
elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0));
elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
@@ -1148,6 +1149,9 @@ asmbelf(vlong symo)
case '8':
eh->machine = EM_386;
break;
+ case '9':
+ eh->machine = EM_PPC64;
+ break;
}
startva = INITTEXT - HEADR;
@@ -1488,7 +1492,10 @@ elfobj:
eh->ident[EI_CLASS] = ELFCLASS64;
else
eh->ident[EI_CLASS] = ELFCLASS32;
- eh->ident[EI_DATA] = ELFDATA2LSB;
+ if(ctxt->arch->endian == BigEndian)
+ eh->ident[EI_DATA] = ELFDATA2MSB;
+ else
+ eh->ident[EI_DATA] = ELFDATA2LSB;
eh->ident[EI_VERSION] = EV_CURRENT;
if(linkmode == LinkExternal)
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index b5d081949..ec8e7c4ea 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -436,6 +436,12 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
return;
}
break;
+ case '9':
+ if(obj->machine != ElfMachPower64 || hdr->ident[4] != ElfClass64) {
+ diag("%s: elf object but not power64", pn);
+ return;
+ }
+ break;
}
// load section list into memory.
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index f889aba8a..925274bfd 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -202,7 +202,18 @@ loadlib(void)
iscgo |= strcmp(ctxt->library[i].pkg, "runtime/cgo") == 0;
objfile(ctxt->library[i].file, ctxt->library[i].pkg);
}
-
+
+ if(linkmode == LinkAuto) {
+ if(iscgo && externalobj)
+ linkmode = LinkExternal;
+ else
+ linkmode = LinkInternal;
+
+ // Force external linking for android.
+ if(strcmp(goos, "android") == 0)
+ linkmode = LinkExternal;
+ }
+
if(linkmode == LinkExternal && !iscgo) {
// This indicates a user requested -linkmode=external.
// The startup code uses an import of runtime/cgo to decide
@@ -229,17 +240,6 @@ loadlib(void)
}
}
- if(linkmode == LinkAuto) {
- if(iscgo && externalobj)
- linkmode = LinkExternal;
- else
- linkmode = LinkInternal;
-
- // Force external linking for android.
- if(strcmp(goos, "android") == 0)
- linkmode = LinkExternal;
- }
-
if(linkmode == LinkInternal) {
// Drop all the cgo_import_static declarations.
// Turns out we won't be needing them.
@@ -594,6 +594,7 @@ hostlink(void)
argv[argc++] = "-m32";
break;
case '6':
+ case '9':
argv[argc++] = "-m64";
break;
case '5':
@@ -1033,7 +1034,7 @@ static LSym *newstack;
enum
{
- HasLinkRegister = (thechar == '5'),
+ HasLinkRegister = (thechar == '5' || thechar == '9'),
};
// TODO: Record enough information in new object files to
@@ -1042,7 +1043,7 @@ enum
static int
callsize(void)
{
- if(thechar == '5')
+ if(HasLinkRegister)
return 0;
return RegSize;
}
@@ -1052,7 +1053,7 @@ dostkcheck(void)
{
Chain ch;
LSym *s;
-
+
morestack = linklookup(ctxt, "runtime.morestack", 0);
newstack = linklookup(ctxt, "runtime.newstack", 0);
@@ -1076,19 +1077,19 @@ dostkcheck(void)
continue;
if(s->nosplit) {
- ctxt->cursym = s;
- ch.sym = s;
- stkcheck(&ch, 0);
- }
+ ctxt->cursym = s;
+ ch.sym = s;
+ stkcheck(&ch, 0);
+ }
}
for(s = ctxt->textp; s != nil; s = s->next) {
if(!s->nosplit) {
- ctxt->cursym = s;
- ch.sym = s;
- stkcheck(&ch, 0);
+ ctxt->cursym = s;
+ ch.sym = s;
+ stkcheck(&ch, 0);
+ }
}
}
-}
static int
stkcheck(Chain *up, int depth)
@@ -1106,7 +1107,7 @@ stkcheck(Chain *up, int depth)
// function at top of safe zone once.
if(limit == StackLimit-callsize()) {
if(s->stkcheck)
- return 0;
+ return 0;
s->stkcheck = 1;
}
@@ -1154,6 +1155,7 @@ stkcheck(Chain *up, int depth)
switch(r->type) {
case R_CALL:
case R_CALLARM:
+ case R_CALLPOWER:
// Direct call.
ch.limit = limit - pcsp.value - callsize();
ch.sym = r->sym;
@@ -1164,8 +1166,8 @@ stkcheck(Chain *up, int depth)
// to StackLimit beyond the frame size.
if(strncmp(r->sym->name, "runtime.morestack", 17) == 0) {
limit = StackLimit + s->locals;
- if(thechar == '5')
- limit += 4; // saved LR
+ if(HasLinkRegister)
+ limit += RegSize;
}
break;
@@ -1184,7 +1186,7 @@ stkcheck(Chain *up, int depth)
break;
}
}
- }
+ }
return 0;
}
@@ -1213,7 +1215,7 @@ stkprint(Chain *ch, int limit)
else
print("\t%d\tguaranteed after split check in %s\n", ch->limit, name);
} else {
- stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize);
+ stkprint(ch->up, ch->limit + (!HasLinkRegister)*RegSize);
if(!HasLinkRegister)
print("\t%d\ton entry to %s\n", ch->limit, name);
}
@@ -1533,7 +1535,7 @@ callgraph(void)
r = &s->r[i];
if(r->sym == nil)
continue;
- if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT)
+ if((r->type == R_CALL || r->type == R_CALLARM || r->type == R_CALLPOWER) && r->sym->type == STEXT)
Bprint(&bso, "%s calls %s\n", s->name, r->sym->name);
}
}
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index fe7e10e46..ffb20b3a5 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -44,6 +44,7 @@ machoinit(void)
switch(thechar) {
// 64-bit architectures
case '6':
+ case '9':
macho64 = 1;
break;
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index 156270c8f..c3a72c3cf 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -78,6 +78,7 @@ putelfsyment(int off, vlong addr, vlong size, int info, int shndx, int other)
{
switch(thechar) {
case '6':
+ case '9':
LPUT(off);
cput(info);
cput(other);
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 2bb74663c..bd09ae9f9 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -101,6 +101,10 @@ func testDisasm(t *testing.T, flags ...string) {
}
func TestDisasm(t *testing.T) {
+ switch runtime.GOARCH {
+ case "power64", "power64le":
+ t.Skipf("skipping on %s, issue 9039", runtime.GOARCH)
+ }
testDisasm(t)
}
@@ -109,5 +113,9 @@ func TestDisasmExtld(t *testing.T) {
case "plan9", "windows":
t.Skipf("skipping on %s", runtime.GOOS)
}
+ switch runtime.GOARCH {
+ case "power64", "power64le":
+ t.Skipf("skipping on %s, no support for external linking, issue 9038", runtime.GOARCH)
+ }
testDisasm(t, "-ldflags=-linkmode=external")
}
diff --git a/src/debug/elf/elf.go b/src/debug/elf/elf.go
index cde296c79..46e9d5735 100644
--- a/src/debug/elf/elf.go
+++ b/src/debug/elf/elf.go
@@ -1414,6 +1414,184 @@ var rppcStrings = []intName{
func (i R_PPC) String() string { return stringName(uint32(i), rppcStrings, false) }
func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) }
+// Relocation types for PowerPC 64.
+type R_PPC64 int
+
+const (
+ R_PPC64_NONE R_PPC64 = 0
+ R_PPC64_ADDR32 R_PPC64 = 1
+ R_PPC64_ADDR24 R_PPC64 = 2
+ R_PPC64_ADDR16 R_PPC64 = 3
+ R_PPC64_ADDR16_LO R_PPC64 = 4
+ R_PPC64_ADDR16_HI R_PPC64 = 5
+ R_PPC64_ADDR16_HA R_PPC64 = 6
+ R_PPC64_ADDR14 R_PPC64 = 7
+ R_PPC64_ADDR14_BRTAKEN R_PPC64 = 8
+ R_PPC64_ADDR14_BRNTAKEN R_PPC64 = 9
+ R_PPC64_REL24 R_PPC64 = 10
+ R_PPC64_REL14 R_PPC64 = 11
+ R_PPC64_REL14_BRTAKEN R_PPC64 = 12
+ R_PPC64_REL14_BRNTAKEN R_PPC64 = 13
+ R_PPC64_GOT16 R_PPC64 = 14
+ R_PPC64_GOT16_LO R_PPC64 = 15
+ R_PPC64_GOT16_HI R_PPC64 = 16
+ R_PPC64_GOT16_HA R_PPC64 = 17
+ R_PPC64_JMP_SLOT R_PPC64 = 21
+ R_PPC64_REL32 R_PPC64 = 26
+ R_PPC64_ADDR64 R_PPC64 = 38
+ R_PPC64_ADDR16_HIGHER R_PPC64 = 39
+ R_PPC64_ADDR16_HIGHERA R_PPC64 = 40
+ R_PPC64_ADDR16_HIGHEST R_PPC64 = 41
+ R_PPC64_ADDR16_HIGHESTA R_PPC64 = 42
+ R_PPC64_REL64 R_PPC64 = 44
+ R_PPC64_TOC16 R_PPC64 = 47
+ R_PPC64_TOC16_LO R_PPC64 = 48
+ R_PPC64_TOC16_HI R_PPC64 = 49
+ R_PPC64_TOC16_HA R_PPC64 = 50
+ R_PPC64_TOC R_PPC64 = 51
+ R_PPC64_ADDR16_DS R_PPC64 = 56
+ R_PPC64_ADDR16_LO_DS R_PPC64 = 57
+ R_PPC64_GOT16_DS R_PPC64 = 58
+ R_PPC64_GOT16_LO_DS R_PPC64 = 59
+ R_PPC64_TOC16_DS R_PPC64 = 63
+ R_PPC64_TOC16_LO_DS R_PPC64 = 64
+ R_PPC64_TLS R_PPC64 = 67
+ R_PPC64_DTPMOD64 R_PPC64 = 68
+ R_PPC64_TPREL16 R_PPC64 = 69
+ R_PPC64_TPREL16_LO R_PPC64 = 70
+ R_PPC64_TPREL16_HI R_PPC64 = 71
+ R_PPC64_TPREL16_HA R_PPC64 = 72
+ R_PPC64_TPREL64 R_PPC64 = 73
+ R_PPC64_DTPREL16 R_PPC64 = 74
+ R_PPC64_DTPREL16_LO R_PPC64 = 75
+ R_PPC64_DTPREL16_HI R_PPC64 = 76
+ R_PPC64_DTPREL16_HA R_PPC64 = 77
+ R_PPC64_DTPREL64 R_PPC64 = 78
+ R_PPC64_GOT_TLSGD16 R_PPC64 = 79
+ R_PPC64_GOT_TLSGD16_LO R_PPC64 = 80
+ R_PPC64_GOT_TLSGD16_HI R_PPC64 = 81
+ R_PPC64_GOT_TLSGD16_HA R_PPC64 = 82
+ R_PPC64_GOT_TLSLD16 R_PPC64 = 83
+ R_PPC64_GOT_TLSLD16_LO R_PPC64 = 84
+ R_PPC64_GOT_TLSLD16_HI R_PPC64 = 85
+ R_PPC64_GOT_TLSLD16_HA R_PPC64 = 86
+ R_PPC64_GOT_TPREL16_DS R_PPC64 = 87
+ R_PPC64_GOT_TPREL16_LO_DS R_PPC64 = 88
+ R_PPC64_GOT_TPREL16_HI R_PPC64 = 89
+ R_PPC64_GOT_TPREL16_HA R_PPC64 = 90
+ R_PPC64_GOT_DTPREL16_DS R_PPC64 = 91
+ R_PPC64_GOT_DTPREL16_LO_DS R_PPC64 = 92
+ R_PPC64_GOT_DTPREL16_HI R_PPC64 = 93
+ R_PPC64_GOT_DTPREL16_HA R_PPC64 = 94
+ R_PPC64_TPREL16_DS R_PPC64 = 95
+ R_PPC64_TPREL16_LO_DS R_PPC64 = 96
+ R_PPC64_TPREL16_HIGHER R_PPC64 = 97
+ R_PPC64_TPREL16_HIGHERA R_PPC64 = 98
+ R_PPC64_TPREL16_HIGHEST R_PPC64 = 99
+ R_PPC64_TPREL16_HIGHESTA R_PPC64 = 100
+ R_PPC64_DTPREL16_DS R_PPC64 = 101
+ R_PPC64_DTPREL16_LO_DS R_PPC64 = 102
+ R_PPC64_DTPREL16_HIGHER R_PPC64 = 103
+ R_PPC64_DTPREL16_HIGHERA R_PPC64 = 104
+ R_PPC64_DTPREL16_HIGHEST R_PPC64 = 105
+ R_PPC64_DTPREL16_HIGHESTA R_PPC64 = 106
+ R_PPC64_TLSGD R_PPC64 = 107
+ R_PPC64_TLSLD R_PPC64 = 108
+ R_PPC64_REL16 R_PPC64 = 249
+ R_PPC64_REL16_LO R_PPC64 = 250
+ R_PPC64_REL16_HI R_PPC64 = 251
+ R_PPC64_REL16_HA R_PPC64 = 252
+)
+
+var rppc64Strings = []intName{
+ {0, "R_PPC64_NONE"},
+ {1, "R_PPC64_ADDR32"},
+ {2, "R_PPC64_ADDR24"},
+ {3, "R_PPC64_ADDR16"},
+ {4, "R_PPC64_ADDR16_LO"},
+ {5, "R_PPC64_ADDR16_HI"},
+ {6, "R_PPC64_ADDR16_HA"},
+ {7, "R_PPC64_ADDR14"},
+ {8, "R_PPC64_ADDR14_BRTAKEN"},
+ {9, "R_PPC64_ADDR14_BRNTAKEN"},
+ {10, "R_PPC64_REL24"},
+ {11, "R_PPC64_REL14"},
+ {12, "R_PPC64_REL14_BRTAKEN"},
+ {13, "R_PPC64_REL14_BRNTAKEN"},
+ {14, "R_PPC64_GOT16"},
+ {15, "R_PPC64_GOT16_LO"},
+ {16, "R_PPC64_GOT16_HI"},
+ {17, "R_PPC64_GOT16_HA"},
+ {21, "R_PPC64_JMP_SLOT"},
+ {26, "R_PPC64_REL32"},
+ {38, "R_PPC64_ADDR64"},
+ {39, "R_PPC64_ADDR16_HIGHER"},
+ {40, "R_PPC64_ADDR16_HIGHERA"},
+ {41, "R_PPC64_ADDR16_HIGHEST"},
+ {42, "R_PPC64_ADDR16_HIGHESTA"},
+ {44, "R_PPC64_REL64"},
+ {47, "R_PPC64_TOC16"},
+ {48, "R_PPC64_TOC16_LO"},
+ {49, "R_PPC64_TOC16_HI"},
+ {50, "R_PPC64_TOC16_HA"},
+ {51, "R_PPC64_TOC"},
+ {56, "R_PPC64_ADDR16_DS"},
+ {57, "R_PPC64_ADDR16_LO_DS"},
+ {58, "R_PPC64_GOT16_DS"},
+ {59, "R_PPC64_GOT16_LO_DS"},
+ {63, "R_PPC64_TOC16_DS"},
+ {64, "R_PPC64_TOC16_LO_DS"},
+ {67, "R_PPC64_TLS"},
+ {68, "R_PPC64_DTPMOD64"},
+ {69, "R_PPC64_TPREL16"},
+ {70, "R_PPC64_TPREL16_LO"},
+ {71, "R_PPC64_TPREL16_HI"},
+ {72, "R_PPC64_TPREL16_HA"},
+ {73, "R_PPC64_TPREL64"},
+ {74, "R_PPC64_DTPREL16"},
+ {75, "R_PPC64_DTPREL16_LO"},
+ {76, "R_PPC64_DTPREL16_HI"},
+ {77, "R_PPC64_DTPREL16_HA"},
+ {78, "R_PPC64_DTPREL64"},
+ {79, "R_PPC64_GOT_TLSGD16"},
+ {80, "R_PPC64_GOT_TLSGD16_LO"},
+ {81, "R_PPC64_GOT_TLSGD16_HI"},
+ {82, "R_PPC64_GOT_TLSGD16_HA"},
+ {83, "R_PPC64_GOT_TLSLD16"},
+ {84, "R_PPC64_GOT_TLSLD16_LO"},
+ {85, "R_PPC64_GOT_TLSLD16_HI"},
+ {86, "R_PPC64_GOT_TLSLD16_HA"},
+ {87, "R_PPC64_GOT_TPREL16_DS"},
+ {88, "R_PPC64_GOT_TPREL16_LO_DS"},
+ {89, "R_PPC64_GOT_TPREL16_HI"},
+ {90, "R_PPC64_GOT_TPREL16_HA"},
+ {91, "R_PPC64_GOT_DTPREL16_DS"},
+ {92, "R_PPC64_GOT_DTPREL16_LO_DS"},
+ {93, "R_PPC64_GOT_DTPREL16_HI"},
+ {94, "R_PPC64_GOT_DTPREL16_HA"},
+ {95, "R_PPC64_TPREL16_DS"},
+ {96, "R_PPC64_TPREL16_LO_DS"},
+ {97, "R_PPC64_TPREL16_HIGHER"},
+ {98, "R_PPC64_TPREL16_HIGHERA"},
+ {99, "R_PPC64_TPREL16_HIGHEST"},
+ {100, "R_PPC64_TPREL16_HIGHESTA"},
+ {101, "R_PPC64_DTPREL16_DS"},
+ {102, "R_PPC64_DTPREL16_LO_DS"},
+ {103, "R_PPC64_DTPREL16_HIGHER"},
+ {104, "R_PPC64_DTPREL16_HIGHERA"},
+ {105, "R_PPC64_DTPREL16_HIGHEST"},
+ {106, "R_PPC64_DTPREL16_HIGHESTA"},
+ {107, "R_PPC64_TLSGD"},
+ {108, "R_PPC64_TLSLD"},
+ {249, "R_PPC64_REL16"},
+ {250, "R_PPC64_REL16_LO"},
+ {251, "R_PPC64_REL16_HI"},
+ {252, "R_PPC64_REL16_HA"},
+}
+
+func (i R_PPC64) String() string { return stringName(uint32(i), rppc64Strings, false) }
+func (i R_PPC64) GoString() string { return stringName(uint32(i), rppc64Strings, true) }
+
// Relocation types for SPARC.
type R_SPARC int
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index de8a3a24f..74d1db306 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -532,6 +532,9 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
if f.Class == ELFCLASS64 && f.Machine == EM_AARCH64 {
return f.applyRelocationsARM64(dst, rels)
}
+ if f.Class == ELFCLASS64 && f.Machine == EM_PPC64 {
+ return f.applyRelocationsPPC64(dst, rels)
+ }
return errors.New("not implemented")
}
@@ -671,6 +674,51 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
return nil
}
+func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
+ // 24 is the size of Rela64.
+ if len(rels)%24 != 0 {
+ return errors.New("length of relocation section is not a multiple of 24")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewReader(rels)
+ var rela Rela64
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rela)
+ symNo := rela.Info >> 32
+ t := R_PPC64(rela.Info & 0xffff)
+
+ if symNo == 0 || symNo > uint64(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+ if SymType(sym.Info&0xf) != STT_SECTION {
+ // We don't handle non-section relocations for now.
+ continue
+ }
+
+ switch t {
+ case R_PPC64_ADDR64:
+ if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
+ case R_PPC64_ADDR32:
+ if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+ }
+ }
+
+ return nil
+}
+
func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package
@@ -693,7 +741,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
// If there's a relocation table for .debug_info, we have to process it
// now otherwise the data in .debug_info is invalid for x86-64 objects.
rela := f.Section(".rela.debug_info")
- if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_AARCH64) {
+ if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_AARCH64 || f.Machine == EM_PPC64) {
data, err := rela.Data()
if err != nil {
return nil, err
diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go
index 5e5ba52f3..d57aaab0e 100644
--- a/src/debug/elf/file_test.go
+++ b/src/debug/elf/file_test.go
@@ -267,6 +267,12 @@ var relocationTests = []relocationTest{
},
},
{
+ "testdata/go-relocation-test-gcc482-ppc64le.obj",
+ []relocationTestEntry{
+ {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x24)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+ },
+ },
+ {
"testdata/go-relocation-test-clang-x86.obj",
[]relocationTestEntry{
{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)"}, {Attr: dwarf.AttrLanguage, Val: int64(12)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"}, {Attr: dwarf.AttrStmtList, Val: int64(0)}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}}}},
diff --git a/src/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj b/src/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj
new file mode 100644
index 000000000..dad744548
--- /dev/null
+++ b/src/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj
Binary files differ
diff --git a/src/go/build/build.go b/src/go/build/build.go
index 311ecb01f..ab2976756 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -1386,6 +1386,8 @@ func ArchChar(goarch string) (string, error) {
return "6", nil
case "arm":
return "5", nil
+ case "power64", "power64le":
+ return "9", nil
}
return "", errors.New("unsupported GOARCH " + goarch)
}
diff --git a/src/go/build/syslist.go b/src/go/build/syslist.go
index 965f873df..2ab53bb9c 100644
--- a/src/go/build/syslist.go
+++ b/src/go/build/syslist.go
@@ -5,4 +5,4 @@
package build
const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
-const goarchList = "386 amd64 amd64p32 arm "
+const goarchList = "386 amd64 amd64p32 arm power64 power64le "
diff --git a/src/hash/crc32/crc32_generic.go b/src/hash/crc32/crc32_generic.go
index c3fdcd685..1c7f806c6 100644
--- a/src/hash/crc32/crc32_generic.go
+++ b/src/hash/crc32/crc32_generic.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build 386 arm
+// +build 386 arm power64 power64le
package crc32
diff --git a/src/liblink/asm6.c b/src/liblink/asm6.c
index 428eb9442..7971022b5 100644
--- a/src/liblink/asm6.c
+++ b/src/liblink/asm6.c
@@ -1543,9 +1543,8 @@ static vlong vaddr(Link*, Addr*, Reloc*);
static int
isextern(LSym *s)
{
- // All the Solaris dynamic imports from libc.so begin with "libc·", which
- // the compiler rewrites to "libc." by the time liblink gets it.
- return strncmp(s->name, "libc.", 5) == 0;
+ // All the Solaris dynamic imports from libc.so begin with "libc_".
+ return strncmp(s->name, "libc_", 5) == 0;
}
// single-instruction no-ops of various lengths.
diff --git a/src/liblink/asm9.c b/src/liblink/asm9.c
new file mode 100644
index 000000000..5a379270d
--- /dev/null
+++ b/src/liblink/asm9.c
@@ -0,0 +1,2783 @@
+// cmd/9l/optab.c, cmd/9l/asmout.c from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Instruction layout.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/9l/9.out.h"
+#include "../runtime/stack.h"
+
+enum {
+ FuncAlign = 8,
+};
+
+enum {
+ r0iszero = 1,
+};
+
+typedef struct Optab Optab;
+
+struct Optab
+{
+ short as;
+ uchar a1;
+ uchar a2;
+ uchar a3;
+ uchar a4;
+ char type;
+ char size;
+ char param;
+};
+
+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 },
+
+ /* move register */
+ { AMOVD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0 },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0 },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0 },
+
+ { AADD, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { AADD, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AADD, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AADD, C_UCON, C_REG, C_NONE, C_REG, 20, 4, 0 },
+ { AADD, C_UCON, C_NONE, C_NONE, C_REG, 20, 4, 0 },
+ { AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0 },
+ { AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0 },
+
+ { AADDC, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AADDC, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { AADDC, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AADDC, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AADDC, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0 },
+ { AADDC, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0 },
+
+ { AAND, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, /* logical, no literal */
+ { AAND, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { AANDCC, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { AANDCC, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+
+ { AANDCC, C_ANDCON,C_NONE, C_NONE, C_REG, 58, 4, 0 },
+ { AANDCC, C_ANDCON,C_REG, C_NONE, C_REG, 58, 4, 0 },
+ { AANDCC, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0 },
+ { AANDCC, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0 },
+ { AANDCC, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0 },
+ { AANDCC, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0 },
+
+ { AMULLW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AMULLW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { AMULLW, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_ANDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_ANDCON, C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0},
+ { AMULLW, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0},
+
+ { ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0 },
+ { ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0 },
+ { ASUBC, C_REG, C_NONE, C_ADDCON, C_REG, 27, 4, 0 },
+ { ASUBC, C_REG, C_NONE, C_LCON, C_REG, 28, 12, 0},
+
+ { AOR, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, /* logical, literal not cc (or/xor) */
+ { AOR, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { AOR, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0 },
+ { AOR, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0 },
+ { AOR, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0 },
+ { AOR, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0 },
+ { AOR, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0 },
+ { AOR, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0 },
+
+ { ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 }, /* op r1[,r2],r3 */
+ { ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0 }, /* op r2[,r1],r3 */
+ { ASUB, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0 },
+
+ { ASLW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { ASLW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { ASLD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { ASLD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { ASLD, C_SCON, C_REG, C_NONE, C_REG, 25, 4, 0 },
+ { ASLD, C_SCON, C_NONE, C_NONE, C_REG, 25, 4, 0 },
+ { ASLW, C_SCON, C_REG, C_NONE, C_REG, 57, 4, 0 },
+ { ASLW, C_SCON, C_NONE, C_NONE, C_REG, 57, 4, 0 },
+
+ { ASRAW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { ASRAW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { ASRAW, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0 },
+ { ASRAW, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0 },
+ { ASRAD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { ASRAD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { ASRAD, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0 },
+ { ASRAD, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0 },
+
+ { ARLWMI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0 },
+ { ARLWMI, C_REG, C_REG, C_LCON, C_REG, 63, 4, 0 },
+ { ARLDMI, C_SCON, C_REG, C_LCON, C_REG, 30, 4, 0 },
+
+ { ARLDC, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0 },
+ { ARLDCL, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0 },
+ { ARLDCL, C_REG, C_REG, C_LCON, C_REG, 14, 4, 0 },
+ { ARLDCL, C_REG, C_NONE, C_LCON, C_REG, 14, 4, 0 },
+
+ { AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 2, 4, 0 },
+ { AFADD, C_FREG, C_REG, C_NONE, C_FREG, 2, 4, 0 },
+ { AFABS, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
+ { AFABS, C_NONE, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
+
+ { AFMADD, C_FREG, C_REG, C_FREG, C_FREG, 34, 4, 0 },
+ { AFMUL, C_FREG, C_NONE, C_NONE, C_FREG, 32, 4, 0 },
+ { AFMUL, C_FREG, C_REG, C_NONE, C_FREG, 32, 4, 0 },
+
+ /* store, short offset */
+ { AMOVD, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVW, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVWZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVBZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVBZU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVB, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVBU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBZU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+
+ /* load, short offset */
+ { AMOVD, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVW, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVWZ, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZ, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZU, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVB, C_ZOREG,C_REG, C_NONE, C_REG, 9, 8, REGZERO },
+ { AMOVBU, C_ZOREG,C_REG, C_NONE, C_REG, 9, 8, REGZERO },
+ { AMOVD, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVW, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVWZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVBZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVB, C_SEXT, C_NONE, C_NONE, C_REG, 9, 8, REGSB },
+ { AMOVD, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVW, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVWZ, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVBZ, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVB, C_SAUTO,C_NONE, C_NONE, C_REG, 9, 8, REGSP },
+ { AMOVD, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVW, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVWZ, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZ, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZU, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVB, C_SOREG,C_NONE, C_NONE, C_REG, 9, 8, REGZERO },
+ { AMOVBU, C_SOREG,C_NONE, C_NONE, C_REG, 9, 8, REGZERO },
+
+ /* store, long offset */
+ { AMOVD, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+
+ /* load, long offset */
+ { AMOVD, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
+ { AMOVW, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
+ { AMOVWZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
+ { AMOVBZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
+ { AMOVB, C_LEXT, C_NONE, C_NONE, C_REG, 37, 12, REGSB },
+ { AMOVD, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
+ { AMOVW, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
+ { AMOVWZ, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
+ { AMOVBZ, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
+ { AMOVB, C_LAUTO,C_NONE, C_NONE, C_REG, 37, 12, REGSP },
+ { AMOVD, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
+ { AMOVW, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
+ { AMOVWZ, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
+ { AMOVBZ, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
+ { AMOVB, C_LOREG,C_NONE, C_NONE, C_REG, 37, 12, REGZERO },
+ { AMOVD, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
+ { AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
+ { AMOVWZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
+ { AMOVBZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
+ { AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 76, 12, 0 },
+
+ /* load constant */
+ { AMOVD, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB },
+ { AMOVD, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVD, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB },
+ { AMOVD, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP },
+ { AMOVD, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVW, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB }, /* TO DO: check */
+ { AMOVW, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVW, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB },
+ { AMOVW, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP },
+ { AMOVW, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVWZ, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB }, /* TO DO: check */
+ { AMOVWZ, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVWZ, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB },
+ { AMOVWZ, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP },
+ { AMOVWZ, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+
+ /* load unsigned/long constants (TO DO: check) */
+ { AMOVD, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVD, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 },
+ { AMOVW, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 },
+ { AMOVWZ, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVWZ, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 },
+
+ { AMOVHBR, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0 },
+ { AMOVHBR, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
+ { AMOVHBR, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0 },
+ { AMOVHBR, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
+
+ { ASYSCALL, C_NONE, C_NONE, C_NONE, C_NONE, 5, 4, 0 },
+ { ASYSCALL, C_REG, C_NONE, C_NONE, C_NONE, 77, 12, 0 },
+ { ASYSCALL, C_SCON, C_NONE, C_NONE, C_NONE, 77, 12, 0 },
+
+ { ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 16, 4, 0 },
+ { ABEQ, C_CREG, C_NONE, C_NONE, C_SBRA, 16, 4, 0 },
+
+ { ABR, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 },
+
+ { ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0 },
+ { ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0 },
+
+ { ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0 },
+ { ABR, C_NONE, C_NONE, C_NONE, C_CTR, 18, 4, 0 },
+ { ABR, C_REG, C_NONE, C_NONE, C_CTR, 18, 4, 0 },
+ { ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0 },
+
+ { ABC, C_NONE, C_REG, C_NONE, C_LR, 18, 4, 0 },
+ { ABC, C_NONE, C_REG, C_NONE, C_CTR, 18, 4, 0 },
+ { ABC, C_SCON, C_REG, C_NONE, C_LR, 18, 4, 0 },
+ { ABC, C_SCON, C_REG, C_NONE, C_CTR, 18, 4, 0 },
+ { ABC, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0 },
+
+ { AFMOVD, C_SEXT, C_NONE, C_NONE, C_FREG, 8, 4, REGSB },
+ { AFMOVD, C_SAUTO,C_NONE, C_NONE, C_FREG, 8, 4, REGSP },
+ { AFMOVD, C_SOREG,C_NONE, C_NONE, C_FREG, 8, 4, REGZERO },
+
+ { AFMOVD, C_LEXT, C_NONE, C_NONE, C_FREG, 36, 8, REGSB },
+ { AFMOVD, C_LAUTO,C_NONE, C_NONE, C_FREG, 36, 8, REGSP },
+ { AFMOVD, C_LOREG,C_NONE, C_NONE, C_FREG, 36, 8, REGZERO },
+ { AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 75, 8, 0 },
+
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+
+ { ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0 },
+ { AWORD, C_LCON, C_NONE, C_NONE, C_NONE, 40, 4, 0 },
+ { ADWORD, C_LCON, C_NONE, C_NONE, C_NONE, 31, 8, 0 },
+ { ADWORD, C_DCON, C_NONE, C_NONE, C_NONE, 31, 8, 0 },
+
+ { AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0 },
+
+ { AEXTSB, C_REG, C_NONE, C_NONE, C_REG, 48, 4, 0 },
+ { AEXTSB, C_NONE, C_NONE, C_NONE, C_REG, 48, 4, 0 },
+
+ { ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0 },
+ { ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 4, 0 },
+
+ { AREM, C_REG, C_NONE, C_NONE, C_REG, 50, 12, 0 },
+ { AREM, C_REG, C_REG, C_NONE, C_REG, 50, 12, 0 },
+ { AREMU, C_REG, C_NONE, C_NONE, C_REG, 50, 16, 0 },
+ { AREMU, C_REG, C_REG, C_NONE, C_REG, 50, 16, 0 },
+ { AREMD, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0 },
+ { AREMD, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0 },
+ { AREMDU, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0 },
+ { AREMDU, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0 },
+
+ { AMTFSB0, C_SCON, C_NONE, C_NONE, C_NONE, 52, 4, 0 },
+ { AMOVFL, C_FPSCR, C_NONE, C_NONE, C_FREG, 53, 4, 0 },
+ { AMOVFL, C_FREG, C_NONE, C_NONE, C_FPSCR, 64, 4, 0 },
+ { AMOVFL, C_FREG, C_NONE, C_LCON, C_FPSCR, 64, 4, 0 },
+ { AMOVFL, C_LCON, C_NONE, C_NONE, C_FPSCR, 65, 4, 0 },
+
+ { AMOVD, C_MSR, C_NONE, C_NONE, C_REG, 54, 4, 0 }, /* mfmsr */
+ { AMOVD, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0 }, /* mtmsrd */
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0 }, /* mtmsr */
+
+ /* 64-bit special registers */
+ { AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_LR, 66, 4, 0 },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 },
+ { AMOVD, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVD, C_LR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVD, C_CTR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVD, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+
+ /* 32-bit special registers (gloss over sign-extension or not?) */
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 },
+ { AMOVW, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVW, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 },
+ { AMOVWZ, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVWZ, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+
+ { AMOVFL, C_FPSCR, C_NONE, C_NONE, C_CREG, 73, 4, 0 },
+ { AMOVFL, C_CREG, C_NONE, C_NONE, C_CREG, 67, 4, 0 },
+ { AMOVW, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0 },
+ { AMOVWZ, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0 },
+ { AMOVFL, C_REG, C_NONE, C_LCON, C_CREG, 69, 4, 0 },
+ { AMOVFL, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
+
+ { ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0 },
+ { ACMP, C_REG, C_NONE, C_NONE, C_ADDCON, 71, 4, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, C_ADDCON, 71, 4, 0 },
+
+ { ACMPU, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0 },
+ { ACMPU, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0 },
+ { ACMPU, C_REG, C_NONE, C_NONE, C_ANDCON, 71, 4, 0 },
+ { ACMPU, C_REG, C_REG, C_NONE, C_ANDCON, 71, 4, 0 },
+
+ { AFCMPO, C_FREG, C_NONE, C_NONE, C_FREG, 70, 4, 0 },
+ { AFCMPO, C_FREG, C_REG, C_NONE, C_FREG, 70, 4, 0 },
+
+ { ATW, C_LCON, C_REG, C_NONE, C_REG, 60, 4, 0 },
+ { ATW, C_LCON, C_REG, C_NONE, C_ADDCON, 61, 4, 0 },
+
+ { ADCBF, C_ZOREG, C_NONE, C_NONE, C_NONE, 43, 4, 0 },
+ { ADCBF, C_ZOREG, C_REG, C_NONE, C_NONE, 43, 4, 0 },
+
+ { AECOWX, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0 },
+ { AECIWX, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0 },
+ { AECOWX, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
+ { AECIWX, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
+
+ { AEIEIO, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0 },
+ { ATLBIE, C_REG, C_NONE, C_NONE, C_NONE, 49, 4, 0 },
+ { ATLBIE, C_SCON, C_NONE, C_NONE, C_REG, 49, 4, 0 },
+ { ASLBMFEE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0 },
+ { ASLBMTE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0 },
+
+ { ASTSW, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
+ { ASTSW, C_REG, C_NONE, C_LCON, C_ZOREG, 41, 4, 0 },
+ { ALSW, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
+ { ALSW, C_ZOREG, C_NONE, C_LCON, C_REG, 42, 4, 0 },
+
+ { AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 78, 4, 0 },
+ { AUSEFIELD, C_ADDR, C_NONE, C_NONE, C_NONE, 0, 0, 0 },
+ { APCDATA, C_LCON, C_NONE, C_NONE, C_LCON, 0, 0, 0 },
+ { AFUNCDATA, C_SCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0 },
+ { ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0 },
+
+ { ADUFFZERO, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, // same as ABR/ABL
+ { ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, // same as ABR/ABL
+
+ { AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
+};
+
+static int ocmp(const void *, const void *);
+static int cmp(int, int);
+static void buildop(Link*);
+static void prasm(Prog *);
+static int isint32(vlong);
+static int isuint32(uvlong);
+static int aclass(Link*, Addr*);
+static Optab* oplook(Link*, Prog*);
+static void asmout(Link*, Prog*, Optab*, int32*);
+static vlong vregoff(Link*, Addr*);
+static int32 regoff(Link*, Addr*);
+static int32 oprrr(Link*, int);
+static int32 opirr(Link*, int);
+static int32 opload(Link*, int);
+static int32 opstore(Link*, int);
+static int32 oploadx(Link*, int);
+static int32 opstorex(Link*, int);
+static int getmask(uchar*, uint32);
+static void maskgen(Link*, Prog*, uchar*, uint32);
+static int getmask64(uchar*, uvlong);
+static void maskgen64(Link*, Prog*, uchar*, uvlong);
+static uint32 loadu32(int, vlong);
+static void addaddrreloc(Link*, LSym*, int*, int*);
+
+static struct
+{
+ Optab* start;
+ Optab* stop;
+} oprange[ALAST];
+
+static uchar xcmp[C_NCLASS][C_NCLASS];
+
+
+void
+span9(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *q;
+ Optab *o;
+ int m, bflag;
+ vlong c, otxt;
+ int32 out[6], i, j;
+ uchar *bp, *cast;
+
+ p = cursym->text;
+ 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;
+
+ if(oprange[AANDN].start == nil)
+ buildop(ctxt);
+
+ c = 0;
+ p->pc = c;
+
+ for(p = p->link; p != nil; p = p->link) {
+ ctxt->curp = p;
+ p->pc = c;
+ o = oplook(ctxt, p);
+ m = o->size;
+ if(m == 0) {
+ if(p->as != ANOP && p->as != AFUNCDATA && p->as != APCDATA)
+ ctxt->diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ cursym->size = c;
+
+ /*
+ * if any procedure is large enough to
+ * generate a large SBRA branch, then
+ * generate extra passes putting branches
+ * around jmps to fix. this is rare.
+ */
+ bflag = 1;
+ while(bflag) {
+ if(ctxt->debugvlog)
+ Bprint(ctxt->bso, "%5.2f span1\n", cputime());
+ bflag = 0;
+ c = 0;
+ for(p = cursym->text->link; p != nil; p = p->link) {
+ p->pc = c;
+ o = oplook(ctxt, p);
+
+ // very large conditional branches
+ 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->link = p->link;
+ p->link = q;
+ q->as = ABR;
+ q->to.type = D_BRANCH;
+ q->pcond = p->pcond;
+ p->pcond = q;
+ q = ctxt->arch->prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = ABR;
+ q->to.type = D_BRANCH;
+ q->pcond = q->link->link;
+ //addnop(p->link);
+ //addnop(p);
+ bflag = 1;
+ }
+ }
+
+ m = o->size;
+ if(m == 0) {
+ if(p->as != ANOP && p->as != AFUNCDATA && p->as != APCDATA)
+ ctxt->diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ cursym->size = c;
+ }
+
+ c += -c&(FuncAlign-1);
+ cursym->size = c;
+
+ /*
+ * lay out the code, emitting code and data relocations.
+ */
+ if(ctxt->tlsg == nil)
+ ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
+
+ symgrow(ctxt, cursym, cursym->size);
+
+ bp = cursym->p;
+ for(p = cursym->text->link; p != nil; p = p->link) {
+ ctxt->pc = p->pc;
+ ctxt->curp = p;
+ o = oplook(ctxt, p);
+ if(o->size > 4*nelem(out))
+ sysfatal("out array in span9 is too small, need at least %d for %P", o->size/4, p);
+ asmout(ctxt, p, o, out);
+ for(i=0; i<o->size/4; i++) {
+ cast = (uchar*)&out[i];
+ for(j=0; j<4; j++)
+ *bp++ = cast[inuxi4[j]];
+ }
+ }
+}
+
+static int
+isint32(vlong v)
+{
+ return (int32)v == v;
+}
+
+static int
+isuint32(uvlong v)
+{
+ return (uint32)v == v;
+}
+
+static int
+aclass(Link *ctxt, Addr *a)
+{
+ LSym *s;
+
+ switch(a->type) {
+ case D_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 D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_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:
+ ctxt->instoffset = ctxt->autosize + a->offset;
+ if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+ case D_PARAM:
+ ctxt->instoffset = ctxt->autosize + a->offset + 8L;
+ if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+ case D_NONE:
+ ctxt->instoffset = a->offset;
+ if(ctxt->instoffset == 0)
+ return C_ZOREG;
+ if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
+ return C_SOREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_OPT:
+ ctxt->instoffset = a->offset & 31L;
+ if(a->name == D_NONE)
+ return C_SCON;
+ return C_GOK;
+
+ case D_CONST:
+ switch(a->name) {
+ case D_NONE:
+ ctxt->instoffset = a->offset;
+ if(a->reg != NREG) {
+ if(-BIG <= ctxt->instoffset && ctxt->instoffset <= BIG)
+ return C_SACON;
+ return C_LACON;
+ }
+ consize:
+ if(ctxt->instoffset >= 0) {
+ if(ctxt->instoffset == 0)
+ return C_ZCON;
+ if(ctxt->instoffset <= 0x7fff)
+ return C_SCON;
+ if(ctxt->instoffset <= 0xffff)
+ return C_ANDCON;
+ if((ctxt->instoffset & 0xffff) == 0 && isuint32(ctxt->instoffset)) /* && (instoffset & (1<<31)) == 0) */
+ return C_UCON;
+ if(isint32(ctxt->instoffset) || isuint32(ctxt->instoffset))
+ return C_LCON;
+ return C_DCON;
+ }
+ if(ctxt->instoffset >= -0x8000)
+ return C_ADDCON;
+ if((ctxt->instoffset & 0xffff) == 0 && isint32(ctxt->instoffset))
+ return C_UCON;
+ if(isint32(ctxt->instoffset))
+ return C_LCON;
+ return C_DCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == nil)
+ break;
+ if(s->type == SCONST) {
+ ctxt->instoffset = s->value + a->offset;
+ goto consize;
+ }
+ ctxt->instoffset = s->value + a->offset;
+ /* not sure why this barfs */
+ return C_LCON;
+
+ case D_AUTO:
+ ctxt->instoffset = ctxt->autosize + a->offset;
+ if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+
+ case D_PARAM:
+ ctxt->instoffset = ctxt->autosize + a->offset + 8L;
+ if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+static void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+static Optab*
+oplook(Link *ctxt, Prog *p)
+{
+ int a1, a2, a3, a4, r;
+ uchar *c1, *c3, *c4;
+ Optab *o, *e;
+
+ a1 = p->optab;
+ if(a1)
+ return optab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ a1 = aclass(ctxt, &p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->from3.class;
+ if(a3 == 0) {
+ a3 = aclass(ctxt, &p->from3) + 1;
+ p->from3.class = a3;
+ }
+ a3--;
+ a4 = p->to.class;
+ if(a4 == 0) {
+ a4 = aclass(ctxt, &p->to) + 1;
+ p->to.class = a4;
+ }
+ a4--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+//print("oplook %P %d %d %d %d\n", p, a1, a2, a3, a4);
+ r = p->as;
+ o = oprange[r].start;
+ if(o == 0)
+ o = oprange[r].stop; /* just generate an error */
+ e = oprange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ c4 = xcmp[a4];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3])
+ if(c4[o->a4]) {
+ p->optab = (o-optab)+1;
+ return o;
+ }
+ ctxt->diag("illegal combination %A %^ %^ %^ %^",
+ p->as, a1, a2, a3, a4);
+ prasm(p);
+ if(o == 0)
+ o = optab;
+ return o;
+}
+
+static int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON)
+ return 1;
+ break;
+ case C_ADDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_ANDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_SPR:
+ if(b == C_LR || b == C_XER || b == C_CTR)
+ return 1;
+ break;
+ case C_UCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_SCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_SACON)
+ return 1;
+ break;
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+ case C_LEXT:
+ if(b == C_SEXT)
+ return 1;
+ break;
+ case C_LAUTO:
+ if(b == C_SAUTO)
+ return 1;
+ break;
+ case C_REG:
+ if(b == C_ZCON)
+ return r0iszero;
+ break;
+ case C_LOREG:
+ if(b == C_ZOREG || b == C_SOREG)
+ return 1;
+ break;
+ case C_SOREG:
+ if(b == C_ZOREG)
+ return 1;
+ break;
+
+ case C_ANY:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ocmp(const void *a1, const void *a2)
+{
+ const Optab *p1, *p2;
+ int n;
+
+ p1 = a1;
+ p2 = a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ n = p1->a4 - p2->a4;
+ if(n)
+ return n;
+ return 0;
+}
+
+static void
+buildop(Link *ctxt)
+{
+ int i, n, r;
+
+ for(i=0; i<C_NCLASS; i++)
+ for(n=0; n<C_NCLASS; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++)
+ ;
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ ctxt->diag("unknown op in build: %A", r);
+ sysfatal("bad code");
+ case ADCBF: /* unary indexed: op (b+a); op (b) */
+ oprange[ADCBI] = oprange[r];
+ oprange[ADCBST] = oprange[r];
+ oprange[ADCBT] = oprange[r];
+ oprange[ADCBTST] = oprange[r];
+ oprange[ADCBZ] = oprange[r];
+ oprange[AICBI] = oprange[r];
+ break;
+ case AECOWX: /* indexed store: op s,(b+a); op s,(b) */
+ oprange[ASTWCCC] = oprange[r];
+ oprange[ASTDCCC] = oprange[r];
+ break;
+ case AREM: /* macro */
+ oprange[AREMCC] = oprange[r];
+ oprange[AREMV] = oprange[r];
+ oprange[AREMVCC] = oprange[r];
+ break;
+ case AREMU:
+ oprange[AREMU] = oprange[r];
+ oprange[AREMUCC] = oprange[r];
+ oprange[AREMUV] = oprange[r];
+ oprange[AREMUVCC] = oprange[r];
+ break;
+ case AREMD:
+ oprange[AREMDCC] = oprange[r];
+ oprange[AREMDV] = oprange[r];
+ oprange[AREMDVCC] = oprange[r];
+ break;
+ case AREMDU:
+ oprange[AREMDU] = oprange[r];
+ oprange[AREMDUCC] = oprange[r];
+ oprange[AREMDUV] = oprange[r];
+ oprange[AREMDUVCC] = oprange[r];
+ break;
+ case ADIVW: /* op Rb[,Ra],Rd */
+ oprange[AMULHW] = oprange[r];
+ oprange[AMULHWCC] = oprange[r];
+ oprange[AMULHWU] = oprange[r];
+ oprange[AMULHWUCC] = oprange[r];
+ oprange[AMULLWCC] = oprange[r];
+ oprange[AMULLWVCC] = oprange[r];
+ oprange[AMULLWV] = oprange[r];
+ oprange[ADIVWCC] = oprange[r];
+ oprange[ADIVWV] = oprange[r];
+ oprange[ADIVWVCC] = oprange[r];
+ oprange[ADIVWU] = oprange[r];
+ oprange[ADIVWUCC] = oprange[r];
+ oprange[ADIVWUV] = oprange[r];
+ oprange[ADIVWUVCC] = oprange[r];
+ oprange[AADDCC] = oprange[r];
+ oprange[AADDCV] = oprange[r];
+ oprange[AADDCVCC] = oprange[r];
+ oprange[AADDV] = oprange[r];
+ oprange[AADDVCC] = oprange[r];
+ oprange[AADDE] = oprange[r];
+ oprange[AADDECC] = oprange[r];
+ oprange[AADDEV] = oprange[r];
+ oprange[AADDEVCC] = oprange[r];
+ oprange[ACRAND] = oprange[r];
+ oprange[ACRANDN] = oprange[r];
+ oprange[ACREQV] = oprange[r];
+ oprange[ACRNAND] = oprange[r];
+ oprange[ACRNOR] = oprange[r];
+ oprange[ACROR] = oprange[r];
+ oprange[ACRORN] = oprange[r];
+ oprange[ACRXOR] = oprange[r];
+ oprange[AMULHD] = oprange[r];
+ oprange[AMULHDCC] = oprange[r];
+ oprange[AMULHDU] = oprange[r];
+ oprange[AMULHDUCC] = oprange[r];
+ oprange[AMULLD] = oprange[r];
+ oprange[AMULLDCC] = oprange[r];
+ oprange[AMULLDVCC] = oprange[r];
+ oprange[AMULLDV] = oprange[r];
+ oprange[ADIVD] = oprange[r];
+ oprange[ADIVDCC] = oprange[r];
+ oprange[ADIVDVCC] = oprange[r];
+ oprange[ADIVDV] = oprange[r];
+ oprange[ADIVDU] = oprange[r];
+ oprange[ADIVDUCC] = oprange[r];
+ oprange[ADIVDUVCC] = oprange[r];
+ oprange[ADIVDUCC] = oprange[r];
+ break;
+ case AMOVBZ: /* lbz, stz, rlwm(r/r), lhz, lha, stz, and x variants */
+ oprange[AMOVH] = oprange[r];
+ oprange[AMOVHZ] = oprange[r];
+ break;
+ case AMOVBZU: /* lbz[x]u, stb[x]u, lhz[x]u, lha[x]u, sth[u]x, ld[x]u, std[u]x */
+ oprange[AMOVHU] = oprange[r];
+ oprange[AMOVHZU] = oprange[r];
+ oprange[AMOVWU] = oprange[r];
+ oprange[AMOVWZU] = oprange[r];
+ oprange[AMOVDU] = oprange[r];
+ oprange[AMOVMW] = oprange[r];
+ break;
+ case AAND: /* logical op Rb,Rs,Ra; no literal */
+ oprange[AANDN] = oprange[r];
+ oprange[AANDNCC] = oprange[r];
+ oprange[AEQV] = oprange[r];
+ oprange[AEQVCC] = oprange[r];
+ oprange[ANAND] = oprange[r];
+ oprange[ANANDCC] = oprange[r];
+ oprange[ANOR] = oprange[r];
+ oprange[ANORCC] = oprange[r];
+ oprange[AORCC] = oprange[r];
+ oprange[AORN] = oprange[r];
+ oprange[AORNCC] = oprange[r];
+ oprange[AXORCC] = oprange[r];
+ break;
+ case AADDME: /* op Ra, Rd */
+ oprange[AADDMECC] = oprange[r];
+ oprange[AADDMEV] = oprange[r];
+ oprange[AADDMEVCC] = oprange[r];
+ oprange[AADDZE] = oprange[r];
+ oprange[AADDZECC] = oprange[r];
+ oprange[AADDZEV] = oprange[r];
+ oprange[AADDZEVCC] = oprange[r];
+ oprange[ASUBME] = oprange[r];
+ oprange[ASUBMECC] = oprange[r];
+ oprange[ASUBMEV] = oprange[r];
+ oprange[ASUBMEVCC] = oprange[r];
+ oprange[ASUBZE] = oprange[r];
+ oprange[ASUBZECC] = oprange[r];
+ oprange[ASUBZEV] = oprange[r];
+ oprange[ASUBZEVCC] = oprange[r];
+ break;
+ case AADDC:
+ oprange[AADDCCC] = oprange[r];
+ break;
+ case ABEQ:
+ oprange[ABGE] = oprange[r];
+ oprange[ABGT] = oprange[r];
+ oprange[ABLE] = oprange[r];
+ oprange[ABLT] = oprange[r];
+ oprange[ABNE] = oprange[r];
+ oprange[ABVC] = oprange[r];
+ oprange[ABVS] = oprange[r];
+ break;
+ case ABR:
+ oprange[ABL] = oprange[r];
+ break;
+ case ABC:
+ oprange[ABCL] = oprange[r];
+ break;
+ case AEXTSB: /* op Rs, Ra */
+ oprange[AEXTSBCC] = oprange[r];
+ oprange[AEXTSH] = oprange[r];
+ oprange[AEXTSHCC] = oprange[r];
+ oprange[ACNTLZW] = oprange[r];
+ oprange[ACNTLZWCC] = oprange[r];
+ oprange[ACNTLZD] = oprange[r];
+ oprange[AEXTSW] = oprange[r];
+ oprange[AEXTSWCC] = oprange[r];
+ oprange[ACNTLZDCC] = oprange[r];
+ break;
+ case AFABS: /* fop [s,]d */
+ oprange[AFABSCC] = oprange[r];
+ oprange[AFNABS] = oprange[r];
+ oprange[AFNABSCC] = oprange[r];
+ oprange[AFNEG] = oprange[r];
+ oprange[AFNEGCC] = oprange[r];
+ oprange[AFRSP] = oprange[r];
+ oprange[AFRSPCC] = oprange[r];
+ oprange[AFCTIW] = oprange[r];
+ oprange[AFCTIWCC] = oprange[r];
+ oprange[AFCTIWZ] = oprange[r];
+ oprange[AFCTIWZCC] = oprange[r];
+ oprange[AFCTID] = oprange[r];
+ oprange[AFCTIDCC] = oprange[r];
+ oprange[AFCTIDZ] = oprange[r];
+ oprange[AFCTIDZCC] = oprange[r];
+ oprange[AFCFID] = oprange[r];
+ oprange[AFCFIDCC] = oprange[r];
+ oprange[AFRES] = oprange[r];
+ oprange[AFRESCC] = oprange[r];
+ oprange[AFRSQRTE] = oprange[r];
+ oprange[AFRSQRTECC] = oprange[r];
+ oprange[AFSQRT] = oprange[r];
+ oprange[AFSQRTCC] = oprange[r];
+ oprange[AFSQRTS] = oprange[r];
+ oprange[AFSQRTSCC] = oprange[r];
+ break;
+ case AFADD:
+ oprange[AFADDS] = oprange[r];
+ oprange[AFADDCC] = oprange[r];
+ oprange[AFADDSCC] = oprange[r];
+ oprange[AFDIV] = oprange[r];
+ oprange[AFDIVS] = oprange[r];
+ oprange[AFDIVCC] = oprange[r];
+ oprange[AFDIVSCC] = oprange[r];
+ oprange[AFSUB] = oprange[r];
+ oprange[AFSUBS] = oprange[r];
+ oprange[AFSUBCC] = oprange[r];
+ oprange[AFSUBSCC] = oprange[r];
+ break;
+ case AFMADD:
+ oprange[AFMADDCC] = oprange[r];
+ oprange[AFMADDS] = oprange[r];
+ oprange[AFMADDSCC] = oprange[r];
+ oprange[AFMSUB] = oprange[r];
+ oprange[AFMSUBCC] = oprange[r];
+ oprange[AFMSUBS] = oprange[r];
+ oprange[AFMSUBSCC] = oprange[r];
+ oprange[AFNMADD] = oprange[r];
+ oprange[AFNMADDCC] = oprange[r];
+ oprange[AFNMADDS] = oprange[r];
+ oprange[AFNMADDSCC] = oprange[r];
+ oprange[AFNMSUB] = oprange[r];
+ oprange[AFNMSUBCC] = oprange[r];
+ oprange[AFNMSUBS] = oprange[r];
+ oprange[AFNMSUBSCC] = oprange[r];
+ oprange[AFSEL] = oprange[r];
+ oprange[AFSELCC] = oprange[r];
+ break;
+ case AFMUL:
+ oprange[AFMULS] = oprange[r];
+ oprange[AFMULCC] = oprange[r];
+ oprange[AFMULSCC] = oprange[r];
+ break;
+ case AFCMPO:
+ oprange[AFCMPU] = oprange[r];
+ break;
+ case AMTFSB0:
+ oprange[AMTFSB0CC] = oprange[r];
+ oprange[AMTFSB1] = oprange[r];
+ oprange[AMTFSB1CC] = oprange[r];
+ break;
+ case ANEG: /* op [Ra,] Rd */
+ oprange[ANEGCC] = oprange[r];
+ oprange[ANEGV] = oprange[r];
+ oprange[ANEGVCC] = oprange[r];
+ break;
+ case AOR: /* or/xor Rb,Rs,Ra; ori/xori $uimm,Rs,Ra; oris/xoris $uimm,Rs,Ra */
+ oprange[AXOR] = oprange[r];
+ break;
+ case ASLW:
+ oprange[ASLWCC] = oprange[r];
+ oprange[ASRW] = oprange[r];
+ oprange[ASRWCC] = oprange[r];
+ break;
+ case ASLD:
+ oprange[ASLDCC] = oprange[r];
+ oprange[ASRD] = oprange[r];
+ oprange[ASRDCC] = oprange[r];
+ break;
+ case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
+ oprange[ASRAWCC] = oprange[r];
+ break;
+ case ASRAD: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
+ oprange[ASRADCC] = oprange[r];
+ break;
+ case ASUB: /* SUB Ra,Rb,Rd => subf Rd,ra,rb */
+ oprange[ASUB] = oprange[r];
+ oprange[ASUBCC] = oprange[r];
+ oprange[ASUBV] = oprange[r];
+ oprange[ASUBVCC] = oprange[r];
+ oprange[ASUBCCC] = oprange[r];
+ oprange[ASUBCV] = oprange[r];
+ oprange[ASUBCVCC] = oprange[r];
+ oprange[ASUBE] = oprange[r];
+ oprange[ASUBECC] = oprange[r];
+ oprange[ASUBEV] = oprange[r];
+ oprange[ASUBEVCC] = oprange[r];
+ break;
+ case ASYNC:
+ oprange[AISYNC] = oprange[r];
+ oprange[APTESYNC] = oprange[r];
+ oprange[ATLBSYNC] = oprange[r];
+ break;
+ case ARLWMI:
+ oprange[ARLWMICC] = oprange[r];
+ oprange[ARLWNM] = oprange[r];
+ oprange[ARLWNMCC] = oprange[r];
+ break;
+ case ARLDMI:
+ oprange[ARLDMICC] = oprange[r];
+ break;
+ case ARLDC:
+ oprange[ARLDCCC] = oprange[r];
+ break;
+ case ARLDCL:
+ oprange[ARLDCR] = oprange[r];
+ oprange[ARLDCLCC] = oprange[r];
+ oprange[ARLDCRCC] = oprange[r];
+ break;
+ case AFMOVD:
+ oprange[AFMOVDCC] = oprange[r];
+ oprange[AFMOVDU] = oprange[r];
+ oprange[AFMOVS] = oprange[r];
+ oprange[AFMOVSU] = oprange[r];
+ break;
+ case AECIWX:
+ oprange[ALWAR] = oprange[r];
+ oprange[ALDAR] = oprange[r];
+ break;
+ case ASYSCALL: /* just the op; flow of control */
+ oprange[ARFI] = oprange[r];
+ oprange[ARFCI] = oprange[r];
+ oprange[ARFID] = oprange[r];
+ oprange[AHRFID] = oprange[r];
+ break;
+ case AMOVHBR:
+ oprange[AMOVWBR] = oprange[r];
+ break;
+ case ASLBMFEE:
+ oprange[ASLBMFEV] = oprange[r];
+ break;
+ case ATW:
+ oprange[ATD] = oprange[r];
+ break;
+ case ATLBIE:
+ oprange[ASLBIE] = oprange[r];
+ oprange[ATLBIEL] = oprange[r];
+ break;
+ case AEIEIO:
+ oprange[ASLBIA] = oprange[r];
+ break;
+ case ACMP:
+ oprange[ACMPW] = oprange[r];
+ break;
+ case ACMPU:
+ oprange[ACMPWU] = oprange[r];
+ break;
+ case AADD:
+ case AANDCC: /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra; andis. $uimm,Rs,Ra */
+ case ALSW:
+ case AMOVW: /* load/store/move word with sign extension; special 32-bit move; move 32-bit literals */
+ case AMOVWZ: /* load/store/move word with zero extension; move 32-bit literals */
+ case AMOVD: /* load/store/move 64-bit values, including 32-bit literals with/without sign-extension */
+ case AMOVB: /* macro: move byte with sign extension */
+ case AMOVBU: /* macro: move byte with sign extension & update */
+ case AMOVFL:
+ case AMULLW: /* op $s[,r2],r3; op r1[,r2],r3; no cc/v */
+ case ASUBC: /* op r1,$s,r3; op r1[,r2],r3 */
+ case ASTSW:
+ case ASLBMTE:
+ case AWORD:
+ case ADWORD:
+ case ANOP:
+ case ATEXT:
+ case AUNDEF:
+ case AUSEFIELD:
+ case AFUNCDATA:
+ case APCDATA:
+ case ADUFFZERO:
+ case ADUFFCOPY:
+ break;
+ }
+ }
+}
+
+#define OPVCC(o,xo,oe,rc) (((o)<<26)|((xo)<<1)|((oe)<<10)|((rc)&1))
+#define OPCC(o,xo,rc) OPVCC((o),(xo),0,(rc))
+#define OP(o,xo) OPVCC((o),(xo),0,0)
+
+/* the order is dest, a/s, b/imm for both arithmetic and logical operations */
+#define AOP_RRR(op,d,a,b) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))
+#define AOP_IRR(op,d,a,simm) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|((simm)&0xFFFF))
+#define LOP_RRR(op,a,s,b) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))
+#define LOP_IRR(op,a,s,uimm) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|((uimm)&0xFFFF))
+#define OP_BR(op,li,aa) ((op)|((li)&0x03FFFFFC)|((aa)<<1))
+#define OP_BC(op,bo,bi,bd,aa) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16)|((bd)&0xFFFC)|((aa)<<1))
+#define OP_BCR(op,bo,bi) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16))
+#define OP_RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\
+ (((mb)&31L)<<6)|(((me)&31L)<<1))
+
+#define OP_ADD OPVCC(31,266,0,0)
+#define OP_ADDI OPVCC(14,0,0,0)
+#define OP_ADDIS OPVCC(15,0,0,0)
+#define OP_ANDI OPVCC(28,0,0,0)
+#define OP_EXTSB OPVCC(31,954,0,0)
+#define OP_EXTSH OPVCC(31,922,0,0)
+#define OP_EXTSW OPVCC(31,986,0,0)
+#define OP_MCRF OPVCC(19,0,0,0)
+#define OP_MCRFS OPVCC(63,64,0,0)
+#define OP_MCRXR OPVCC(31,512,0,0)
+#define OP_MFCR OPVCC(31,19,0,0)
+#define OP_MFFS OPVCC(63,583,0,0)
+#define OP_MFMSR OPVCC(31,83,0,0)
+#define OP_MFSPR OPVCC(31,339,0,0)
+#define OP_MFSR OPVCC(31,595,0,0)
+#define OP_MFSRIN OPVCC(31,659,0,0)
+#define OP_MTCRF OPVCC(31,144,0,0)
+#define OP_MTFSF OPVCC(63,711,0,0)
+#define OP_MTFSFI OPVCC(63,134,0,0)
+#define OP_MTMSR OPVCC(31,146,0,0)
+#define OP_MTMSRD OPVCC(31,178,0,0)
+#define OP_MTSPR OPVCC(31,467,0,0)
+#define OP_MTSR OPVCC(31,210,0,0)
+#define OP_MTSRIN OPVCC(31,242,0,0)
+#define OP_MULLW OPVCC(31,235,0,0)
+#define OP_MULLD OPVCC(31,233,0,0)
+#define OP_OR OPVCC(31,444,0,0)
+#define OP_ORI OPVCC(24,0,0,0)
+#define OP_ORIS OPVCC(25,0,0,0)
+#define OP_RLWINM OPVCC(21,0,0,0)
+#define OP_SUBF OPVCC(31,40,0,0)
+#define OP_RLDIC OPVCC(30,4,0,0)
+#define OP_RLDICR OPVCC(30,2,0,0)
+#define OP_RLDICL OPVCC(30,0,0,0)
+
+#define oclass(v) ((v).class-1)
+
+// add R_ADDRPOWER relocation to symbol s for the two instructions o1 and o2.
+static void
+addaddrreloc(Link *ctxt, LSym *s, int *o1, int *o2)
+{
+ Reloc *rel;
+
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 8;
+ rel->sym = s;
+ rel->add = ((uvlong)*o1<<32) | (uint32)*o2;
+ rel->type = R_ADDRPOWER;
+}
+
+/*
+ * 32-bit masks
+ */
+static int
+getmask(uchar *m, uint32 v)
+{
+ int i;
+
+ m[0] = m[1] = 0;
+ if(v != ~0U && v & (1<<31) && v & 1){ /* MB > ME */
+ if(getmask(m, ~v)){
+ i = m[0]; m[0] = m[1]+1; m[1] = i-1;
+ return 1;
+ }
+ return 0;
+ }
+ for(i=0; i<32; i++)
+ if(v & (1<<(31-i))){
+ m[0] = i;
+ do {
+ m[1] = i;
+ } while(++i<32 && (v & (1<<(31-i))) != 0);
+ for(; i<32; i++)
+ if(v & (1<<(31-i)))
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void
+maskgen(Link *ctxt, Prog *p, uchar *m, uint32 v)
+{
+ if(!getmask(m, v))
+ ctxt->diag("cannot generate mask #%lux\n%P", v, p);
+}
+
+/*
+ * 64-bit masks (rldic etc)
+ */
+static int
+getmask64(uchar *m, uvlong v)
+{
+ int i;
+
+ m[0] = m[1] = 0;
+ for(i=0; i<64; i++)
+ if(v & ((uvlong)1<<(63-i))){
+ m[0] = i;
+ do {
+ m[1] = i;
+ } while(++i<64 && (v & ((uvlong)1<<(63-i))) != 0);
+ for(; i<64; i++)
+ if(v & ((uvlong)1<<(63-i)))
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void
+maskgen64(Link *ctxt, Prog *p, uchar *m, uvlong v)
+{
+ if(!getmask64(m, v))
+ ctxt->diag("cannot generate mask #%llux\n%P", v, p);
+}
+
+static uint32
+loadu32(int r, vlong d)
+{
+ int32 v;
+
+ v = d>>16;
+ if(isuint32(d))
+ return LOP_IRR(OP_ORIS, r, REGZERO, v);
+ return AOP_IRR(OP_ADDIS, r, REGZERO, v);
+}
+
+static uint16
+high16adjusted(int32 d)
+{
+ if(d & 0x8000)
+ return (d>>16) + 1;
+ return d>>16;
+}
+
+static void
+asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
+{
+ int32 o1, o2, o3, o4, o5, v, t;
+ vlong d;
+ int r, a;
+ uchar mask[2];
+ Reloc *rel;
+
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+
+//print("%P => case %d\n", p, o->type);
+ switch(o->type) {
+ default:
+ ctxt->diag("unknown type %d", o->type);
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+ break;
+
+ case 1: /* mov r1,r2 ==> OR Rs,Rs,Ra */
+ if(p->to.reg == REGZERO && p->from.type == D_CONST) {
+ v = regoff(ctxt, &p->from);
+ if(r0iszero && v != 0) {
+ //nerrors--;
+ ctxt->diag("literal operation on R0\n%P", p);
+ }
+ o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v);
+ break;
+ }
+ o1 = LOP_RRR(OP_OR, p->to.reg, p->from.reg, p->from.reg);
+ break;
+
+ case 2: /* int/cr/fp op Rb,[Ra],Rd */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, p->from.reg);
+ break;
+
+ case 3: /* mov $soreg/addcon/ucon, r ==> addis/addi $i,reg',r */
+ d = vregoff(ctxt, &p->from);
+ v = d;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ if(r0iszero && p->to.reg == 0 && (r != 0 || v != 0))
+ ctxt->diag("literal operation on R0\n%P", p);
+ a = OP_ADDI;
+ if(o->a1 == C_UCON) {
+ if((d&0xffff) != 0)
+ sysfatal("invalid handling of %P", p);
+ v >>= 16;
+ if(r == REGZERO && isuint32(d)){
+ o1 = LOP_IRR(OP_ORIS, p->to.reg, REGZERO, v);
+ break;
+ }
+ a = OP_ADDIS;
+ } else {
+ if((int16)d != d)
+ sysfatal("invalid handling of %P", p);
+ }
+ o1 = AOP_IRR(a, p->to.reg, r, v);
+ break;
+
+ case 4: /* add/mul $scon,[r1],r2 */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ if(r0iszero && p->to.reg == 0)
+ ctxt->diag("literal operation on R0\n%P", p);
+ if((int16)v != v)
+ sysfatal("mishandled instruction %P", p);
+ o1 = AOP_IRR(opirr(ctxt, p->as), p->to.reg, r, v);
+ break;
+
+ case 5: /* syscall */
+ o1 = oprrr(ctxt, p->as);
+ break;
+
+ case 6: /* logical op Rb,[Rs,]Ra; no literal */
+ r = p->reg;
+ if(r == NREG)
+ 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)
+ r = o->param;
+ v = regoff(ctxt, &p->to);
+ if(p->to.type == D_OREG && p->reg != NREG) {
+ if(v)
+ ctxt->diag("illegal indexed instruction\n%P", p);
+ o1 = AOP_RRR(opstorex(ctxt, p->as), p->from.reg, p->reg, r);
+ } else {
+ if((int16)v != v)
+ sysfatal("mishandled instruction %P", p);
+ o1 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, r, v);
+ }
+ break;
+
+ case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(ctxt, &p->from);
+ if(p->from.type == D_OREG && p->reg != NREG) {
+ if(v)
+ ctxt->diag("illegal indexed instruction\n%P", p);
+ o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, p->reg, r);
+ } else {
+ if((int16)v != v)
+ sysfatal("mishandled instruction %P", p);
+ o1 = AOP_IRR(opload(ctxt, p->as), p->to.reg, r, v);
+ }
+ break;
+
+ case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(ctxt, &p->from);
+ if(p->from.type == D_OREG && p->reg != NREG) {
+ if(v)
+ ctxt->diag("illegal indexed instruction\n%P", p);
+ o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, p->reg, r);
+ } else
+ o1 = AOP_IRR(opload(ctxt, p->as), p->to.reg, r, v);
+ o2 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
+ break;
+
+ case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, p->from.reg, r);
+ break;
+
+ case 11: /* br/bl lbra */
+ v = 0;
+ if(p->pcond) {
+ v = p->pcond->pc - p->pc;
+ if(v & 03) {
+ ctxt->diag("odd branch target address\n%P", p);
+ v &= ~03;
+ }
+ if(v < -(1L<<25) || v >= (1L<<24))
+ ctxt->diag("branch too far\n%P", p);
+ }
+ o1 = OP_BR(opirr(ctxt, p->as), v, 0);
+ if(p->to.sym != nil) {
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 4;
+ rel->sym = p->to.sym;
+ v += p->to.offset;
+ if(v & 03) {
+ ctxt->diag("odd branch target address\n%P", p);
+ v &= ~03;
+ }
+ rel->add = v;
+ rel->type = R_CALLPOWER;
+ }
+ break;
+
+ case 12: /* movb r,r (extsb); movw r,r (extsw) */
+ if(p->to.reg == REGZERO && p->from.type == D_CONST) {
+ v = regoff(ctxt, &p->from);
+ if(r0iszero && v != 0) {
+ ctxt->diag("literal operation on R0\n%P", p);
+ }
+ o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v);
+ break;
+ }
+ if(p->as == AMOVW)
+ o1 = LOP_RRR(OP_EXTSW, p->to.reg, p->from.reg, 0);
+ else
+ o1 = LOP_RRR(OP_EXTSB, p->to.reg, p->from.reg, 0);
+ break;
+
+ case 13: /* mov[bhw]z r,r; uses rlwinm not andi. to avoid changing CC */
+ if(p->as == AMOVBZ)
+ o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 24, 31);
+ else if(p->as == AMOVH)
+ o1 = LOP_RRR(OP_EXTSH, p->to.reg, p->from.reg, 0);
+ else if(p->as == AMOVHZ)
+ o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 16, 31);
+ else if(p->as == AMOVWZ)
+ o1 = OP_RLW(OP_RLDIC, p->to.reg, p->from.reg, 0, 0, 0) | (1<<5); /* MB=32 */
+ else
+ ctxt->diag("internal: bad mov[bhw]z\n%P", p);
+ break;
+
+ case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ d = vregoff(ctxt, &p->from3);
+ maskgen64(ctxt, p, mask, d);
+ switch(p->as){
+ case ARLDCL: case ARLDCLCC:
+ a = mask[0]; /* MB */
+ if(mask[1] != 63)
+ ctxt->diag("invalid mask for rotate: %llux (end != bit 63)\n%P", d, p);
+ break;
+ case ARLDCR: case ARLDCRCC:
+ a = mask[1]; /* ME */
+ if(mask[0] != 0)
+ ctxt->diag("invalid mask for rotate: %llux (start != 0)\n%P", d, p);
+ break;
+ default:
+ ctxt->diag("unexpected op in rldc case\n%P", p);
+ a = 0;
+ }
+ o1 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, p->from.reg);
+ o1 |= (a&31L)<<6;
+ if(a & 0x20)
+ o1 |= 1<<5; /* mb[5] is top bit */
+ break;
+
+ case 17: /* bc bo,bi,lbra (same for now) */
+ case 16: /* bc bo,bi,sbra */
+ a = 0;
+ if(p->from.type == D_CONST)
+ a = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ v = 0;
+ if(p->pcond)
+ v = p->pcond->pc - p->pc;
+ if(v & 03) {
+ ctxt->diag("odd branch target address\n%P", p);
+ v &= ~03;
+ }
+ if(v < -(1L<<16) || v >= (1L<<15))
+ ctxt->diag("branch too far\n%P", p);
+ o1 = OP_BC(opirr(ctxt, p->as), a, r, v, 0);
+ break;
+
+ case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */
+ if(p->as == ABC || p->as == ABCL)
+ v = regoff(ctxt, &p->to)&31L;
+ else
+ v = 20; /* unconditional */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ o1 = AOP_RRR(OP_MTSPR, p->to.reg, 0, 0) | ((D_LR&0x1f)<<16) | (((D_LR>>5)&0x1f)<<11);
+ o2 = OPVCC(19, 16, 0, 0);
+ if(p->as == ABL || p->as == ABCL)
+ o2 |= 1;
+ o2 = OP_BCR(o2, v, r);
+ break;
+
+ case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */
+ if(p->as == ABC || p->as == ABCL)
+ v = regoff(ctxt, &p->from)&31L;
+ else
+ v = 20; /* unconditional */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ switch(oclass(p->to)) {
+ case C_CTR:
+ o1 = OPVCC(19, 528, 0, 0);
+ break;
+ case C_LR:
+ o1 = OPVCC(19, 16, 0, 0);
+ break;
+ default:
+ ctxt->diag("bad optab entry (18): %d\n%P", p->to.class, p);
+ v = 0;
+ }
+ if(p->as == ABL || p->as == ABCL)
+ o1 |= 1;
+ o1 = OP_BCR(o1, v, r);
+ break;
+
+ case 19: /* mov $lcon,r ==> cau+or */
+ d = vregoff(ctxt, &p->from);
+ if(p->from.sym == nil) {
+ o1 = loadu32(p->to.reg, d);
+ o2 = LOP_IRR(OP_ORI, p->to.reg, p->to.reg, (int32)d);
+ } else {
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(d));
+ o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, d);
+ addaddrreloc(ctxt, p->from.sym, &o1, &o2);
+ }
+ //if(dlm) reloc(&p->from, p->pc, 0);
+ break;
+
+ case 20: /* add $ucon,,r */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ 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);
+ break;
+
+ case 22: /* add $lcon,r1,r2 ==> cau+or+add */ /* could do add/sub more efficiently */
+ if(p->to.reg == REGTMP || p->reg == REGTMP)
+ ctxt->diag("cant synthesize large constant\n%P", p);
+ d = vregoff(ctxt, &p->from);
+ o1 = loadu32(REGTMP, d);
+ o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (int32)d);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o3 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, REGTMP, r);
+ if(p->from.sym != nil)
+ ctxt->diag("%P is not supported", p);
+ //if(dlm) reloc(&p->from, p->pc, 0);
+ break;
+
+ case 23: /* and $lcon,r1,r2 ==> cau+or+and */ /* masks could be done using rlnm etc. */
+ if(p->to.reg == REGTMP || p->reg == REGTMP)
+ ctxt->diag("cant synthesize large constant\n%P", p);
+ d = vregoff(ctxt, &p->from);
+ o1 = loadu32(REGTMP, d);
+ o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (int32)d);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o3 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, REGTMP, r);
+ if(p->from.sym != nil)
+ ctxt->diag("%P is not supported", p);
+ //if(dlm) reloc(&p->from, p->pc, 0);
+ break;
+/*24*/
+
+ case 25: /* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */
+ v = regoff(ctxt, &p->from);
+ if(v < 0)
+ v = 0;
+ else if(v > 63)
+ v = 63;
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ switch(p->as){
+ case ASLD: case ASLDCC:
+ a = 63-v;
+ o1 = OP_RLDICR;
+ break;
+ case ASRD: case ASRDCC:
+ a = v;
+ v = 64-v;
+ o1 = OP_RLDICL;
+ break;
+ default:
+ ctxt->diag("unexpected op in sldi case\n%P", p);
+ a = 0;
+ o1 = 0;
+ }
+ o1 = AOP_RRR(o1, r, p->to.reg, (v&0x1F));
+ o1 |= (a&31L)<<6;
+ if(v & 0x20)
+ o1 |= 1<<1;
+ if(a & 0x20)
+ o1 |= 1<<5; /* mb[5] is top bit */
+ if(p->as == ASLDCC || p->as == ASRDCC)
+ o1 |= 1; /* Rc */
+ break;
+
+ case 26: /* mov $lsext/auto/oreg,,r2 ==> addis+addi */
+ if(p->to.reg == REGTMP)
+ ctxt->diag("can't synthesize large constant\n%P", p);
+ v = regoff(ctxt, &p->from);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, v);
+ break;
+
+ case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
+ v = regoff(ctxt, &p->from3);
+ r = p->from.reg;
+ o1 = AOP_IRR(opirr(ctxt, p->as), p->to.reg, r, v);
+ break;
+
+ case 28: /* subc r1,$lcon,r2 ==> cau+or+subfc */
+ if(p->to.reg == REGTMP || p->from.reg == REGTMP)
+ ctxt->diag("can't synthesize large constant\n%P", p);
+ v = regoff(ctxt, &p->from3);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16);
+ o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v);
+ o3 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, p->from.reg, REGTMP);
+ if(p->from.sym != nil)
+ ctxt->diag("%P is not supported", p);
+ //if(dlm) reloc(&p->from3, p->pc, 0);
+ break;
+
+ case 29: /* rldic[lr]? $sh,s,$mask,a -- left, right, plain give different masks */
+ v = regoff(ctxt, &p->from);
+ d = vregoff(ctxt, &p->from3);
+ maskgen64(ctxt, p, mask, d);
+ switch(p->as){
+ case ARLDC: case ARLDCCC:
+ a = mask[0]; /* MB */
+ if(mask[1] != (63-v))
+ ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
+ break;
+ case ARLDCL: case ARLDCLCC:
+ a = mask[0]; /* MB */
+ if(mask[1] != 63)
+ ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
+ break;
+ case ARLDCR: case ARLDCRCC:
+ a = mask[1]; /* ME */
+ if(mask[0] != 0)
+ ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
+ break;
+ default:
+ ctxt->diag("unexpected op in rldic case\n%P", p);
+ a = 0;
+ }
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, (v&0x1F));
+ o1 |= (a&31L)<<6;
+ if(v & 0x20)
+ o1 |= 1<<1;
+ if(a & 0x20)
+ o1 |= 1<<5; /* mb[5] is top bit */
+ break;
+
+ case 30: /* rldimi $sh,s,$mask,a */
+ v = regoff(ctxt, &p->from);
+ d = vregoff(ctxt, &p->from3);
+ maskgen64(ctxt, p, mask, d);
+ if(mask[1] != (63-v))
+ ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, (v&0x1F));
+ o1 |= (mask[0]&31L)<<6;
+ if(v & 0x20)
+ o1 |= 1<<1;
+ if(mask[0] & 0x20)
+ o1 |= 1<<5; /* mb[5] is top bit */
+ break;
+
+ case 31: /* dword */
+ d = vregoff(ctxt, &p->from);
+ if(ctxt->arch->endian == BigEndian) {
+ o1 = d>>32;
+ o2 = d;
+ } else {
+ o1 = d;
+ o2 = d>>32;
+ }
+ if(p->from.sym != nil) {
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 8;
+ rel->sym = p->from.sym;
+ rel->add = p->from.offset;
+ rel->type = R_ADDR;
+ o1 = o2 = 0;
+ }
+ break;
+
+ case 32: /* fmul frc,fra,frd */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, 0)|((p->from.reg&31L)<<6);
+ break;
+
+ case 33: /* fabs [frb,]frd; fmr. frb,frd */
+ r = p->from.reg;
+ if(oclass(p->from) == C_NONE)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, 0, r);
+ break;
+
+ case 34: /* FMADDx fra,frb,frc,frd (d=a*b+c); FSELx a<0? (d=b): (d=c) */
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, p->from.reg, p->reg)|((p->from3.reg&31L)<<6);
+ break;
+
+ case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
+ v = regoff(ctxt, &p->to);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, REGTMP, v);
+ break;
+
+ case 36: /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */
+ v = regoff(ctxt, &p->from);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
+ break;
+
+ case 37: /* movb lext/lauto/lreg,r ==> lbz o(reg),r; extsb r */
+ v = regoff(ctxt, &p->from);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
+ o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
+ break;
+
+ case 40: /* word */
+ o1 = regoff(ctxt, &p->from);
+ break;
+
+ case 41: /* stswi */
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->from.reg, p->to.reg, 0) | ((regoff(ctxt, &p->from3)&0x7F)<<11);
+ break;
+
+ case 42: /* lswi */
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->to.reg, p->from.reg, 0) | ((regoff(ctxt, &p->from3)&0x7F)<<11);
+ break;
+
+ case 43: /* unary indexed source: dcbf (b); dcbf (a+b) */
+ r = p->reg;
+ if(r == NREG)
+ 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)
+ 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)
+ r = 0;
+ o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, r, p->from.reg);
+ break;
+
+ case 46: /* plain op */
+ o1 = oprrr(ctxt, p->as);
+ break;
+
+ case 47: /* op Ra, Rd; also op [Ra,] Rd */
+ r = p->from.reg;
+ if(r == NREG)
+ 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)
+ 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 */
+ v = regoff(ctxt, &p->from) & 1;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), 0, 0, p->to.reg) | (v<<21);
+ }else
+ o1 = AOP_RRR(oprrr(ctxt, p->as), 0, 0, p->from.reg);
+ break;
+
+ case 50: /* rem[u] r1[,r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ v = oprrr(ctxt, p->as);
+ t = v & ((1<<10)|1); /* OE|Rc */
+ o1 = AOP_RRR(v&~t, REGTMP, r, p->from.reg);
+ o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, p->from.reg);
+ o3 = AOP_RRR(OP_SUBF|t, p->to.reg, REGTMP, r);
+ if(p->as == AREMU) {
+ o4 = o3;
+ /* Clear top 32 bits */
+ o3 = OP_RLW(OP_RLDIC, REGTMP, REGTMP, 0, 0, 0) | (1<<5);
+ }
+ break;
+
+ case 51: /* remd[u] r1[,r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ v = oprrr(ctxt, p->as);
+ t = v & ((1<<10)|1); /* OE|Rc */
+ o1 = AOP_RRR(v&~t, REGTMP, r, p->from.reg);
+ o2 = AOP_RRR(OP_MULLD, REGTMP, REGTMP, p->from.reg);
+ o3 = AOP_RRR(OP_SUBF|t, p->to.reg, REGTMP, r);
+ break;
+
+ case 52: /* mtfsbNx cr(n) */
+ v = regoff(ctxt, &p->from)&31L;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), v, 0, 0);
+ break;
+
+ case 53: /* mffsX ,fr1 */
+ o1 = AOP_RRR(OP_MFFS, p->to.reg, 0, 0);
+ break;
+
+ case 54: /* mov msr,r1; mov r1, msr*/
+ if(oclass(p->from) == C_REG){
+ if(p->as == AMOVD)
+ o1 = AOP_RRR(OP_MTMSRD, p->from.reg, 0, 0);
+ else
+ o1 = AOP_RRR(OP_MTMSR, p->from.reg, 0, 0);
+ }else
+ o1 = AOP_RRR(OP_MFMSR, p->to.reg, 0, 0);
+ break;
+
+ case 55: /* op Rb, Rd */
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, 0, p->from.reg);
+ break;
+
+ case 56: /* sra $sh,[s,]a; srd $sh,[s,]a */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(opirr(ctxt, p->as), r, p->to.reg, v&31L);
+ if(p->as == ASRAD && (v&0x20))
+ o1 |= 1<<1; /* mb[5] */
+ break;
+
+ case 57: /* slw $sh,[s,]a -> rlwinm ... */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ /*
+ * Let user (gs) shoot himself in the foot.
+ * qc has already complained.
+ *
+ if(v < 0 || v > 31)
+ ctxt->diag("illegal shift %ld\n%P", v, p);
+ */
+ if(v < 0)
+ v = 0;
+ else if(v > 32)
+ v = 32;
+ if(p->as == ASRW || p->as == ASRWCC) { /* shift right */
+ mask[0] = v;
+ mask[1] = 31;
+ v = 32-v;
+ } else {
+ mask[0] = 0;
+ mask[1] = 31-v;
+ }
+ o1 = OP_RLW(OP_RLWINM, p->to.reg, r, v, mask[0], mask[1]);
+ if(p->as == ASLWCC || p->as == ASRWCC)
+ o1 |= 1; /* Rc */
+ break;
+
+ case 58: /* logical $andcon,[s],a */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = LOP_IRR(opirr(ctxt, p->as), p->to.reg, r, v);
+ break;
+
+ case 59: /* or/and $ucon,,r */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = LOP_IRR(opirr(ctxt, p->as+AEND), p->to.reg, r, v>>16); /* oris, xoris, andis */
+ break;
+
+ case 60: /* tw to,a,b */
+ r = regoff(ctxt, &p->from)&31L;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), r, p->reg, p->to.reg);
+ break;
+
+ case 61: /* tw to,a,$simm */
+ r = regoff(ctxt, &p->from)&31L;
+ v = regoff(ctxt, &p->to);
+ o1 = AOP_IRR(opirr(ctxt, p->as), r, p->reg, v);
+ break;
+
+ case 62: /* rlwmi $sh,s,$mask,a */
+ v = regoff(ctxt, &p->from);
+ maskgen(ctxt, p, mask, regoff(ctxt, &p->from3));
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, v);
+ o1 |= ((mask[0]&31L)<<6)|((mask[1]&31L)<<1);
+ break;
+
+ case 63: /* rlwmi b,s,$mask,a */
+ maskgen(ctxt, p, mask, regoff(ctxt, &p->from3));
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, p->from.reg);
+ o1 |= ((mask[0]&31L)<<6)|((mask[1]&31L)<<1);
+ break;
+
+ case 64: /* mtfsf fr[, $m] {,fpcsr} */
+ if(p->from3.type != D_NONE)
+ v = regoff(ctxt, &p->from3)&255L;
+ else
+ v = 255;
+ o1 = OP_MTFSF | (v<<17) | (p->from.reg<<11);
+ break;
+
+ case 65: /* MOVFL $imm,FPSCR(n) => mtfsfi crfd,imm */
+ if(p->to.reg == NREG)
+ 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) {
+ r = p->from.reg;
+ v = p->to.offset;
+ if(p->to.type == D_DCR)
+ 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)
+ o1 = OPVCC(31,323,0,0); /* mfdcr */
+ else
+ o1 = OPVCC(31,339,0,0); /* mfspr */
+ }
+ o1 = AOP_RRR(o1, r, 0, 0) | ((v&0x1f)<<16) | (((v>>5)&0x1f)<<11);
+ 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)
+ 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){
+ 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
+ o1 = AOP_RRR(OP_MFCR, p->to.reg, 0, 0); /* old form, whole register */
+ break;
+
+ case 69: /* mtcrf CRM,rS */
+ if(p->from3.type != D_NONE) {
+ if(p->to.reg != NREG)
+ 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)
+ v = 0xff; /* CR */
+ else
+ v = 1<<(7-(p->to.reg&7)); /* CR(n) */
+ }
+ o1 = AOP_RRR(OP_MTCRF, p->from.reg, 0, 0) | (v<<12);
+ break;
+
+ case 70: /* [f]cmp r,r,cr*/
+ if(p->reg == NREG)
+ r = 0;
+ else
+ r = (p->reg&7)<<2;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), r, p->from.reg, p->to.reg);
+ break;
+
+ case 71: /* cmp[l] r,i,cr*/
+ if(p->reg == NREG)
+ r = 0;
+ else
+ r = (p->reg&7)<<2;
+ o1 = AOP_RRR(opirr(ctxt, p->as), r, p->from.reg, 0) | (regoff(ctxt, &p->to)&0xffff);
+ break;
+
+ case 72: /* slbmte (Rb+Rs -> slb[Rb]) -> Rs, Rb */
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->from.reg, 0, p->to.reg);
+ 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)
+ 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);
+ break;
+
+ case 77: /* syscall $scon, syscall Rx */
+ if(p->from.type == D_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) {
+ o1 = LOP_RRR(OP_OR, REGZERO, p->from.reg, p->from.reg);
+ } else {
+ ctxt->diag("illegal syscall: %P", p);
+ o1 = 0x7fe00008; // trap always
+ }
+ o2 = oprrr(ctxt, p->as);
+ o3 = AOP_RRR(oprrr(ctxt, AXOR), REGZERO, REGZERO, REGZERO); // XOR R0, R0
+ break;
+
+ case 78: /* undef */
+ o1 = 0; /* "An instruction consisting entirely of binary 0s is guaranteed
+ always to be an illegal instruction." */
+ break;
+
+ /* relocation operations */
+
+ case 74:
+ v = regoff(ctxt, &p->to);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(v));
+ o2 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, REGTMP, v);
+ addaddrreloc(ctxt, p->to.sym, &o1, &o2);
+ //if(dlm) reloc(&p->to, p->pc, 1);
+ break;
+
+ case 75:
+ v = regoff(ctxt, &p->from);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(v));
+ o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
+ addaddrreloc(ctxt, p->from.sym, &o1, &o2);
+ //if(dlm) reloc(&p->from, p->pc, 1);
+ break;
+
+ case 76:
+ v = regoff(ctxt, &p->from);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(v));
+ o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
+ addaddrreloc(ctxt, p->from.sym, &o1, &o2);
+ o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
+ //if(dlm) reloc(&p->from, p->pc, 1);
+ break;
+
+ }
+
+ out[0] = o1;
+ out[1] = o2;
+ out[2] = o3;
+ out[3] = o4;
+ out[4] = o5;
+ return;
+}
+
+static vlong
+vregoff(Link *ctxt, Addr *a)
+{
+
+ ctxt->instoffset = 0;
+ aclass(ctxt, a);
+ return ctxt->instoffset;
+}
+
+static int32
+regoff(Link *ctxt, Addr *a)
+{
+ return vregoff(ctxt, a);
+}
+
+static int32
+oprrr(Link *ctxt, int a)
+{
+ switch(a) {
+ case AADD: return OPVCC(31,266,0,0);
+ case AADDCC: return OPVCC(31,266,0,1);
+ case AADDV: return OPVCC(31,266,1,0);
+ case AADDVCC: return OPVCC(31,266,1,1);
+ case AADDC: return OPVCC(31,10,0,0);
+ case AADDCCC: return OPVCC(31,10,0,1);
+ case AADDCV: return OPVCC(31,10,1,0);
+ case AADDCVCC: return OPVCC(31,10,1,1);
+ case AADDE: return OPVCC(31,138,0,0);
+ case AADDECC: return OPVCC(31,138,0,1);
+ case AADDEV: return OPVCC(31,138,1,0);
+ case AADDEVCC: return OPVCC(31,138,1,1);
+ case AADDME: return OPVCC(31,234,0,0);
+ case AADDMECC: return OPVCC(31,234,0,1);
+ case AADDMEV: return OPVCC(31,234,1,0);
+ case AADDMEVCC: return OPVCC(31,234,1,1);
+ case AADDZE: return OPVCC(31,202,0,0);
+ case AADDZECC: return OPVCC(31,202,0,1);
+ case AADDZEV: return OPVCC(31,202,1,0);
+ case AADDZEVCC: return OPVCC(31,202,1,1);
+
+ case AAND: return OPVCC(31,28,0,0);
+ case AANDCC: return OPVCC(31,28,0,1);
+ case AANDN: return OPVCC(31,60,0,0);
+ case AANDNCC: return OPVCC(31,60,0,1);
+
+ case ACMP: return OPVCC(31,0,0,0)|(1<<21); /* L=1 */
+ case ACMPU: return OPVCC(31,32,0,0)|(1<<21);
+ case ACMPW: return OPVCC(31,0,0,0); /* L=0 */
+ case ACMPWU: return OPVCC(31,32,0,0);
+
+ case ACNTLZW: return OPVCC(31,26,0,0);
+ case ACNTLZWCC: return OPVCC(31,26,0,1);
+ case ACNTLZD: return OPVCC(31,58,0,0);
+ case ACNTLZDCC: return OPVCC(31,58,0,1);
+
+ case ACRAND: return OPVCC(19,257,0,0);
+ case ACRANDN: return OPVCC(19,129,0,0);
+ case ACREQV: return OPVCC(19,289,0,0);
+ case ACRNAND: return OPVCC(19,225,0,0);
+ case ACRNOR: return OPVCC(19,33,0,0);
+ case ACROR: return OPVCC(19,449,0,0);
+ case ACRORN: return OPVCC(19,417,0,0);
+ case ACRXOR: return OPVCC(19,193,0,0);
+
+ case ADCBF: return OPVCC(31,86,0,0);
+ case ADCBI: return OPVCC(31,470,0,0);
+ case ADCBST: return OPVCC(31,54,0,0);
+ case ADCBT: return OPVCC(31,278,0,0);
+ case ADCBTST: return OPVCC(31,246,0,0);
+ case ADCBZ: return OPVCC(31,1014,0,0);
+
+ case AREM:
+ case ADIVW: return OPVCC(31,491,0,0);
+ case AREMCC:
+ case ADIVWCC: return OPVCC(31,491,0,1);
+ case AREMV:
+ case ADIVWV: return OPVCC(31,491,1,0);
+ case AREMVCC:
+ case ADIVWVCC: return OPVCC(31,491,1,1);
+ case AREMU:
+ case ADIVWU: return OPVCC(31,459,0,0);
+ case AREMUCC:
+ case ADIVWUCC: return OPVCC(31,459,0,1);
+ case AREMUV:
+ case ADIVWUV: return OPVCC(31,459,1,0);
+ case AREMUVCC:
+ case ADIVWUVCC: return OPVCC(31,459,1,1);
+
+ case AREMD:
+ case ADIVD: return OPVCC(31,489,0,0);
+ case AREMDCC:
+ case ADIVDCC: return OPVCC(31,489,0,1);
+ case AREMDV:
+ case ADIVDV: return OPVCC(31,489,1,0);
+ case AREMDVCC:
+ case ADIVDVCC: return OPVCC(31,489,1,1);
+ case AREMDU:
+ case ADIVDU: return OPVCC(31,457,0,0);
+ case AREMDUCC:
+ case ADIVDUCC: return OPVCC(31,457,0,1);
+ case AREMDUV:
+ case ADIVDUV: return OPVCC(31,457,1,0);
+ case AREMDUVCC:
+ case ADIVDUVCC: return OPVCC(31,457,1,1);
+
+ case AEIEIO: return OPVCC(31,854,0,0);
+
+ case AEQV: return OPVCC(31,284,0,0);
+ case AEQVCC: return OPVCC(31,284,0,1);
+
+ case AEXTSB: return OPVCC(31,954,0,0);
+ case AEXTSBCC: return OPVCC(31,954,0,1);
+ case AEXTSH: return OPVCC(31,922,0,0);
+ case AEXTSHCC: return OPVCC(31,922,0,1);
+ case AEXTSW: return OPVCC(31,986,0,0);
+ case AEXTSWCC: return OPVCC(31,986,0,1);
+
+ case AFABS: return OPVCC(63,264,0,0);
+ case AFABSCC: return OPVCC(63,264,0,1);
+ case AFADD: return OPVCC(63,21,0,0);
+ case AFADDCC: return OPVCC(63,21,0,1);
+ case AFADDS: return OPVCC(59,21,0,0);
+ case AFADDSCC: return OPVCC(59,21,0,1);
+ case AFCMPO: return OPVCC(63,32,0,0);
+ case AFCMPU: return OPVCC(63,0,0,0);
+ case AFCFID: return OPVCC(63,846,0,0);
+ case AFCFIDCC: return OPVCC(63,846,0,1);
+ case AFCTIW: return OPVCC(63,14,0,0);
+ case AFCTIWCC: return OPVCC(63,14,0,1);
+ case AFCTIWZ: return OPVCC(63,15,0,0);
+ case AFCTIWZCC: return OPVCC(63,15,0,1);
+ case AFCTID: return OPVCC(63,814,0,0);
+ case AFCTIDCC: return OPVCC(63,814,0,1);
+ case AFCTIDZ: return OPVCC(63,815,0,0);
+ case AFCTIDZCC: return OPVCC(63,815,0,1);
+ case AFDIV: return OPVCC(63,18,0,0);
+ case AFDIVCC: return OPVCC(63,18,0,1);
+ case AFDIVS: return OPVCC(59,18,0,0);
+ case AFDIVSCC: return OPVCC(59,18,0,1);
+ case AFMADD: return OPVCC(63,29,0,0);
+ case AFMADDCC: return OPVCC(63,29,0,1);
+ case AFMADDS: return OPVCC(59,29,0,0);
+ case AFMADDSCC: return OPVCC(59,29,0,1);
+ case AFMOVS:
+ case AFMOVD: return OPVCC(63,72,0,0); /* load */
+ case AFMOVDCC: return OPVCC(63,72,0,1);
+ case AFMSUB: return OPVCC(63,28,0,0);
+ case AFMSUBCC: return OPVCC(63,28,0,1);
+ case AFMSUBS: return OPVCC(59,28,0,0);
+ case AFMSUBSCC: return OPVCC(59,28,0,1);
+ case AFMUL: return OPVCC(63,25,0,0);
+ case AFMULCC: return OPVCC(63,25,0,1);
+ case AFMULS: return OPVCC(59,25,0,0);
+ case AFMULSCC: return OPVCC(59,25,0,1);
+ case AFNABS: return OPVCC(63,136,0,0);
+ case AFNABSCC: return OPVCC(63,136,0,1);
+ case AFNEG: return OPVCC(63,40,0,0);
+ case AFNEGCC: return OPVCC(63,40,0,1);
+ case AFNMADD: return OPVCC(63,31,0,0);
+ case AFNMADDCC: return OPVCC(63,31,0,1);
+ case AFNMADDS: return OPVCC(59,31,0,0);
+ case AFNMADDSCC: return OPVCC(59,31,0,1);
+ case AFNMSUB: return OPVCC(63,30,0,0);
+ case AFNMSUBCC: return OPVCC(63,30,0,1);
+ case AFNMSUBS: return OPVCC(59,30,0,0);
+ case AFNMSUBSCC: return OPVCC(59,30,0,1);
+ case AFRES: return OPVCC(59,24,0,0);
+ case AFRESCC: return OPVCC(59,24,0,1);
+ case AFRSP: return OPVCC(63,12,0,0);
+ case AFRSPCC: return OPVCC(63,12,0,1);
+ case AFRSQRTE: return OPVCC(63,26,0,0);
+ case AFRSQRTECC: return OPVCC(63,26,0,1);
+ case AFSEL: return OPVCC(63,23,0,0);
+ case AFSELCC: return OPVCC(63,23,0,1);
+ case AFSQRT: return OPVCC(63,22,0,0);
+ case AFSQRTCC: return OPVCC(63,22,0,1);
+ case AFSQRTS: return OPVCC(59,22,0,0);
+ case AFSQRTSCC: return OPVCC(59,22,0,1);
+ case AFSUB: return OPVCC(63,20,0,0);
+ case AFSUBCC: return OPVCC(63,20,0,1);
+ case AFSUBS: return OPVCC(59,20,0,0);
+ case AFSUBSCC: return OPVCC(59,20,0,1);
+
+ case AICBI: return OPVCC(31,982,0,0);
+ case AISYNC: return OPVCC(19,150,0,0);
+
+ case AMTFSB0: return OPVCC(63,70,0,0);
+ case AMTFSB0CC: return OPVCC(63,70,0,1);
+ case AMTFSB1: return OPVCC(63,38,0,0);
+ case AMTFSB1CC: return OPVCC(63,38,0,1);
+
+ case AMULHW: return OPVCC(31,75,0,0);
+ case AMULHWCC: return OPVCC(31,75,0,1);
+ case AMULHWU: return OPVCC(31,11,0,0);
+ case AMULHWUCC: return OPVCC(31,11,0,1);
+ case AMULLW: return OPVCC(31,235,0,0);
+ case AMULLWCC: return OPVCC(31,235,0,1);
+ case AMULLWV: return OPVCC(31,235,1,0);
+ case AMULLWVCC: return OPVCC(31,235,1,1);
+
+ case AMULHD: return OPVCC(31,73,0,0);
+ case AMULHDCC: return OPVCC(31,73,0,1);
+ case AMULHDU: return OPVCC(31,9,0,0);
+ case AMULHDUCC: return OPVCC(31,9,0,1);
+ case AMULLD: return OPVCC(31,233,0,0);
+ case AMULLDCC: return OPVCC(31,233,0,1);
+ case AMULLDV: return OPVCC(31,233,1,0);
+ case AMULLDVCC: return OPVCC(31,233,1,1);
+
+ case ANAND: return OPVCC(31,476,0,0);
+ case ANANDCC: return OPVCC(31,476,0,1);
+ case ANEG: return OPVCC(31,104,0,0);
+ case ANEGCC: return OPVCC(31,104,0,1);
+ case ANEGV: return OPVCC(31,104,1,0);
+ case ANEGVCC: return OPVCC(31,104,1,1);
+ case ANOR: return OPVCC(31,124,0,0);
+ case ANORCC: return OPVCC(31,124,0,1);
+ case AOR: return OPVCC(31,444,0,0);
+ case AORCC: return OPVCC(31,444,0,1);
+ case AORN: return OPVCC(31,412,0,0);
+ case AORNCC: return OPVCC(31,412,0,1);
+
+ case ARFI: return OPVCC(19,50,0,0);
+ case ARFCI: return OPVCC(19,51,0,0);
+ case ARFID: return OPVCC(19,18,0,0);
+ case AHRFID: return OPVCC(19,274,0,0);
+
+ case ARLWMI: return OPVCC(20,0,0,0);
+ case ARLWMICC: return OPVCC(20,0,0,1);
+ case ARLWNM: return OPVCC(23,0,0,0);
+ case ARLWNMCC: return OPVCC(23,0,0,1);
+
+ case ARLDCL: return OPVCC(30,8,0,0);
+ case ARLDCR: return OPVCC(30,9,0,0);
+
+ case ASYSCALL: return OPVCC(17,1,0,0);
+
+ case ASLW: return OPVCC(31,24,0,0);
+ case ASLWCC: return OPVCC(31,24,0,1);
+ case ASLD: return OPVCC(31,27,0,0);
+ case ASLDCC: return OPVCC(31,27,0,1);
+
+ case ASRAW: return OPVCC(31,792,0,0);
+ case ASRAWCC: return OPVCC(31,792,0,1);
+ case ASRAD: return OPVCC(31,794,0,0);
+ case ASRADCC: return OPVCC(31,794,0,1);
+
+ case ASRW: return OPVCC(31,536,0,0);
+ case ASRWCC: return OPVCC(31,536,0,1);
+ case ASRD: return OPVCC(31,539,0,0);
+ case ASRDCC: return OPVCC(31,539,0,1);
+
+ case ASUB: return OPVCC(31,40,0,0);
+ case ASUBCC: return OPVCC(31,40,0,1);
+ case ASUBV: return OPVCC(31,40,1,0);
+ case ASUBVCC: return OPVCC(31,40,1,1);
+ case ASUBC: return OPVCC(31,8,0,0);
+ case ASUBCCC: return OPVCC(31,8,0,1);
+ case ASUBCV: return OPVCC(31,8,1,0);
+ case ASUBCVCC: return OPVCC(31,8,1,1);
+ case ASUBE: return OPVCC(31,136,0,0);
+ case ASUBECC: return OPVCC(31,136,0,1);
+ case ASUBEV: return OPVCC(31,136,1,0);
+ case ASUBEVCC: return OPVCC(31,136,1,1);
+ case ASUBME: return OPVCC(31,232,0,0);
+ case ASUBMECC: return OPVCC(31,232,0,1);
+ case ASUBMEV: return OPVCC(31,232,1,0);
+ case ASUBMEVCC: return OPVCC(31,232,1,1);
+ case ASUBZE: return OPVCC(31,200,0,0);
+ case ASUBZECC: return OPVCC(31,200,0,1);
+ case ASUBZEV: return OPVCC(31,200,1,0);
+ case ASUBZEVCC: return OPVCC(31,200,1,1);
+
+ case ASYNC: return OPVCC(31,598,0,0);
+ case APTESYNC: return OPVCC(31,598,0,0) | (2<<21);
+
+ case ATLBIE: return OPVCC(31,306,0,0);
+ case ATLBIEL: return OPVCC(31,274,0,0);
+ case ATLBSYNC: return OPVCC(31,566,0,0);
+ case ASLBIA: return OPVCC(31,498,0,0);
+ case ASLBIE: return OPVCC(31,434,0,0);
+ case ASLBMFEE: return OPVCC(31,915,0,0);
+ case ASLBMFEV: return OPVCC(31,851,0,0);
+ case ASLBMTE: return OPVCC(31,402,0,0);
+
+ case ATW: return OPVCC(31,4,0,0);
+ case ATD: return OPVCC(31,68,0,0);
+
+ case AXOR: return OPVCC(31,316,0,0);
+ case AXORCC: return OPVCC(31,316,0,1);
+ }
+ ctxt->diag("bad r/r opcode %A", a);
+ return 0;
+}
+
+static int32
+opirr(Link *ctxt, int a)
+{
+ switch(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 AANDCC: return OPVCC(28,0,0,0);
+ case AANDCC+AEND: 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;
+ case ADUFFZERO: return OPVCC(18,0,0,0) | 1;
+ case ADUFFCOPY: return OPVCC(18,0,0,0) | 1;
+ case ABC: return OPVCC(16,0,0,0);
+ case ABCL: return OPVCC(16,0,0,0) | 1;
+
+ case ABEQ: return AOP_RRR(16<<26,12,2,0);
+ case ABGE: return AOP_RRR(16<<26,4,0,0);
+ case ABGT: return AOP_RRR(16<<26,12,1,0);
+ case ABLE: return AOP_RRR(16<<26,4,1,0);
+ case ABLT: return AOP_RRR(16<<26,12,0,0);
+ case ABNE: return AOP_RRR(16<<26,4,2,0);
+ case ABVC: return AOP_RRR(16<<26,4,3,0);
+ case ABVS: return AOP_RRR(16<<26,12,3,0);
+
+ case ACMP: return OPVCC(11,0,0,0)|(1<<21); /* L=1 */
+ case ACMPU: return OPVCC(10,0,0,0)|(1<<21);
+ case ACMPW: return OPVCC(11,0,0,0); /* L=0 */
+ case ACMPWU: return OPVCC(10,0,0,0);
+ case ALSW: return OPVCC(31,597,0,0);
+
+ 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 ARLWMI: return OPVCC(20,0,0,0); /* rlwimi */
+ case ARLWMICC: return OPVCC(20,0,0,1);
+ case ARLDMI: return OPVCC(30,0,0,0) | (3<<2); /* rldimi */
+ case ARLDMICC: return OPVCC(30,0,0,1) | (3<<2);
+
+ case ARLWNM: return OPVCC(21,0,0,0); /* rlwinm */
+ case ARLWNMCC: return OPVCC(21,0,0,1);
+
+ case ARLDCL: return OPVCC(30,0,0,0); /* rldicl */
+ case ARLDCLCC: return OPVCC(30,0,0,1);
+ case ARLDCR: return OPVCC(30,1,0,0); /* rldicr */
+ case ARLDCRCC: return OPVCC(30,1,0,1);
+ case ARLDC: return OPVCC(30,0,0,0) | (2<<2);
+ case ARLDCCC: return OPVCC(30,0,0,1) | (2<<2);
+
+ case ASRAW: return OPVCC(31,824,0,0);
+ case ASRAWCC: return OPVCC(31,824,0,1);
+ case ASRAD: return OPVCC(31,(413<<1),0,0);
+ case ASRADCC: return OPVCC(31,(413<<1),0,1);
+
+ case ASTSW: return OPVCC(31,725,0,0);
+
+ case ASUBC: return OPVCC(8,0,0,0);
+
+ case ATW: return OPVCC(3,0,0,0);
+ 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 */
+ }
+ ctxt->diag("bad opcode i/r %A", a);
+ return 0;
+}
+
+/*
+ * load o(a),d
+ */
+static int32
+opload(Link *ctxt, int a)
+{
+ switch(a) {
+ case AMOVD: return OPVCC(58,0,0,0); /* ld */
+ case AMOVDU: return OPVCC(58,0,0,1); /* ldu */
+ case AMOVWZ: return OPVCC(32,0,0,0); /* lwz */
+ case AMOVWZU: return OPVCC(33,0,0,0); /* lwzu */
+ case AMOVW: return OPVCC(58,0,0,0)|(1<<1); /* lwa */
+ /* no AMOVWU */
+ case AMOVB:
+ case AMOVBZ: return OPVCC(34,0,0,0); /* load */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(35,0,0,0);
+ case AFMOVD: return OPVCC(50,0,0,0);
+ case AFMOVDU: return OPVCC(51,0,0,0);
+ case AFMOVS: return OPVCC(48,0,0,0);
+ case AFMOVSU: return OPVCC(49,0,0,0);
+ case AMOVH: return OPVCC(42,0,0,0);
+ case AMOVHU: return OPVCC(43,0,0,0);
+ case AMOVHZ: return OPVCC(40,0,0,0);
+ case AMOVHZU: return OPVCC(41,0,0,0);
+ case AMOVMW: return OPVCC(46,0,0,0); /* lmw */
+ }
+ ctxt->diag("bad load opcode %A", a);
+ return 0;
+}
+
+/*
+ * indexed load a(b),d
+ */
+static int32
+oploadx(Link *ctxt, int a)
+{
+ switch(a) {
+ case AMOVWZ: return OPVCC(31,23,0,0); /* lwzx */
+ case AMOVWZU: return OPVCC(31,55,0,0); /* lwzux */
+ case AMOVW: return OPVCC(31,341,0,0); /* lwax */
+ case AMOVWU: return OPVCC(31,373,0,0); /* lwaux */
+ case AMOVB:
+ case AMOVBZ: return OPVCC(31,87,0,0); /* lbzx */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(31,119,0,0); /* lbzux */
+ case AFMOVD: return OPVCC(31,599,0,0); /* lfdx */
+ case AFMOVDU: return OPVCC(31,631,0,0); /* lfdux */
+ case AFMOVS: return OPVCC(31,535,0,0); /* lfsx */
+ case AFMOVSU: return OPVCC(31,567,0,0); /* lfsux */
+ case AMOVH: return OPVCC(31,343,0,0); /* lhax */
+ case AMOVHU: return OPVCC(31,375,0,0); /* lhaux */
+ case AMOVHBR: return OPVCC(31,790,0,0); /* lhbrx */
+ case AMOVWBR: return OPVCC(31,534,0,0); /* lwbrx */
+ case AMOVHZ: return OPVCC(31,279,0,0); /* lhzx */
+ case AMOVHZU: return OPVCC(31,311,0,0); /* lhzux */
+ case AECIWX: return OPVCC(31,310,0,0); /* eciwx */
+ case ALWAR: return OPVCC(31,20,0,0); /* lwarx */
+ case ALDAR: return OPVCC(31,84,0,0);
+ case ALSW: return OPVCC(31,533,0,0); /* lswx */
+ case AMOVD: return OPVCC(31,21,0,0); /* ldx */
+ case AMOVDU: return OPVCC(31,53,0,0); /* ldux */
+ }
+ ctxt->diag("bad loadx opcode %A", a);
+ return 0;
+}
+
+/*
+ * store s,o(d)
+ */
+static int32
+opstore(Link *ctxt, int a)
+{
+ switch(a) {
+ case AMOVB:
+ case AMOVBZ: return OPVCC(38,0,0,0); /* stb */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(39,0,0,0); /* stbu */
+ case AFMOVD: return OPVCC(54,0,0,0); /* stfd */
+ case AFMOVDU: return OPVCC(55,0,0,0); /* stfdu */
+ case AFMOVS: return OPVCC(52,0,0,0); /* stfs */
+ case AFMOVSU: return OPVCC(53,0,0,0); /* stfsu */
+ case AMOVHZ:
+ case AMOVH: return OPVCC(44,0,0,0); /* sth */
+ case AMOVHZU:
+ case AMOVHU: return OPVCC(45,0,0,0); /* sthu */
+ case AMOVMW: return OPVCC(47,0,0,0); /* stmw */
+ case ASTSW: return OPVCC(31,725,0,0); /* stswi */
+ case AMOVWZ:
+ case AMOVW: return OPVCC(36,0,0,0); /* stw */
+ case AMOVWZU:
+ case AMOVWU: return OPVCC(37,0,0,0); /* stwu */
+ case AMOVD: return OPVCC(62,0,0,0); /* std */
+ case AMOVDU: return OPVCC(62,0,0,1); /* stdu */
+ }
+ ctxt->diag("unknown store opcode %A", a);
+ return 0;
+}
+
+/*
+ * indexed store s,a(b)
+ */
+static int32
+opstorex(Link *ctxt, int a)
+{
+ switch(a) {
+ case AMOVB:
+ case AMOVBZ: return OPVCC(31,215,0,0); /* stbx */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(31,247,0,0); /* stbux */
+ case AFMOVD: return OPVCC(31,727,0,0); /* stfdx */
+ case AFMOVDU: return OPVCC(31,759,0,0); /* stfdux */
+ case AFMOVS: return OPVCC(31,663,0,0); /* stfsx */
+ case AFMOVSU: return OPVCC(31,695,0,0); /* stfsux */
+ case AMOVHZ:
+ case AMOVH: return OPVCC(31,407,0,0); /* sthx */
+ case AMOVHBR: return OPVCC(31,918,0,0); /* sthbrx */
+ case AMOVHZU:
+ case AMOVHU: return OPVCC(31,439,0,0); /* sthux */
+ case AMOVWZ:
+ case AMOVW: return OPVCC(31,151,0,0); /* stwx */
+ case AMOVWZU:
+ case AMOVWU: return OPVCC(31,183,0,0); /* stwux */
+ case ASTSW: return OPVCC(31,661,0,0); /* stswx */
+ case AMOVWBR: return OPVCC(31,662,0,0); /* stwbrx */
+ case ASTWCCC: return OPVCC(31,150,0,1); /* stwcx. */
+ case ASTDCCC: return OPVCC(31,214,0,1); /* stwdx. */
+ case AECOWX: return OPVCC(31,438,0,0); /* ecowx */
+ case AMOVD: return OPVCC(31,149,0,0); /* stdx */
+ case AMOVDU: return OPVCC(31,181,0,0); /* stdux */
+ }
+ ctxt->diag("unknown storex opcode %A", a);
+ return 0;
+}
+
diff --git a/src/liblink/list6.c b/src/liblink/list6.c
index 0635fdf1f..ff22273c4 100644
--- a/src/liblink/list6.c
+++ b/src/liblink/list6.c
@@ -82,6 +82,19 @@ Pconv(Fmt *fp)
p = va_arg(fp->args, Prog*);
bigP = p;
+
+ if(fp->flags & FmtSharp) {
+ char *s = str;
+ s += sprint(s, "%.5lld (%L) %A", p->pc, p->lineno, p->as);
+ if(p->from.type != D_NONE)
+ s += sprint(s, " from={%#D}", &p->from);
+ if(p->reg)
+ s += sprint(s, " reg=%d", p->reg);
+ if(p->to.type != D_NONE)
+ sprint(s, " to={%#D}", &p->to);
+ return fmtstrcpy(fp, str);
+ }
+
switch(p->as) {
case ADATA:
sprint(str, "%.5lld (%L) %A %D/%d,%D",
@@ -126,6 +139,31 @@ Dconv(Fmt *fp)
a = va_arg(fp->args, Addr*);
i = a->type;
+ if(fp->flags & FmtSharp) {
+ char *s = str;
+ s += sprint(s, "type=");
+ if(i == D_NONE) {
+ sprint(s, "NONE");
+ goto brk;
+ }
+ if(i >= D_INDIR) {
+ i -= D_INDIR;
+ s += sprint(s, "INDIR+");
+ }
+ if(i >= 0 && i < D_LAST && dnames6[i] != nil)
+ s += sprint(s, "%s ", dnames6[i]);
+ else
+ s += sprint(s, "%d ", i);
+ s += sprint(s, "offset=%lld etype=%E width=%lld", a->offset, a->etype, a->width);
+ if(a->class != 0)
+ s += sprint(s, " class=%s", cnames9[(int)a->class]);
+ if(a->sym != nil)
+ s += sprint(s, " sym=%s", a->sym->name);
+ if(a->type == D_BRANCH && a->u.branch != nil)
+ sprint(s, " branch=%.5lld", a->u.branch->pc);
+ goto brk;
+ }
+
if(fp->flags & FmtLong) {
if(i == D_CONST)
sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32);
diff --git a/src/liblink/list9.c b/src/liblink/list9.c
new file mode 100644
index 000000000..32fcf8f87
--- /dev/null
+++ b/src/liblink/list9.c
@@ -0,0 +1,451 @@
+// cmd/9l/list.c from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/9l/9.out.h"
+
+enum
+{
+ STRINGSZ = 1000,
+};
+
+static int Aconv(Fmt*);
+static int Dconv(Fmt*);
+static int Pconv(Fmt*);
+static int Rconv(Fmt*);
+static int DSconv(Fmt*);
+static int Mconv(Fmt*);
+static int DRconv(Fmt*);
+
+//
+// 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
+//
+// %R int Registers
+//
+// %$ char* String constant addresses (for internal use only)
+// %^ int C_* classes (for liblink internal use)
+
+#pragma varargck type "$" char*
+#pragma varargck type "M" Addr*
+
+void
+listinit9(void)
+{
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('R', Rconv);
+
+ // for liblink internal use
+ fmtinstall('^', DRconv);
+
+ // for internal use
+ fmtinstall('$', DSconv);
+ fmtinstall('M', Mconv);
+}
+
+static Prog* bigP;
+
+static int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], *s;
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+ a = p->as;
+
+ if(fp->flags & FmtSharp) {
+ s = str;
+ s += sprint(s, "%.5lld (%L) %A", p->pc, p->lineno, a);
+ if(p->from.type != D_NONE)
+ s += sprint(s, " from={%#D}", &p->from);
+ if(p->reg)
+ s += sprint(s, " reg=%d", p->reg);
+ if(p->from3.type != D_NONE)
+ s += sprint(s, " from3={%#D}", &p->from3);
+ if(p->to.type != D_NONE)
+ sprint(s, " to={%#D}", &p->to);
+ return fmtstrcpy(fp, str);
+ }
+
+ 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);
+ else
+ sprint(str, "%.5lld (%L) %A %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
+ } else {
+ s = str;
+ if(p->mark & NOSCHED)
+ s += sprint(s, "*");
+ if(p->reg == NREG && p->from3.type == D_NONE)
+ sprint(s, "%.5lld (%L) %A %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
+ else
+ if(a != ATEXT && p->from.type == D_OREG) {
+ sprint(s, "%.5lld (%L) %A %lld(R%d+R%d),%D", p->pc, p->lineno, a,
+ p->from.offset, p->from.reg, p->reg, &p->to);
+ } else
+ if(p->to.type == D_OREG) {
+ sprint(s, "%.5lld (%L) %A %D,%lld(R%d+R%d)", p->pc, p->lineno, a,
+ &p->from, p->to.offset, p->to.reg, p->reg);
+ } else {
+ s += sprint(s, "%.5lld (%L) %A %D", p->pc, p->lineno, a, &p->from);
+ if(p->reg != NREG)
+ s += sprint(s, ",%c%d", p->from.type==D_FREG?'F':'R', p->reg);
+ if(p->from3.type != D_NONE)
+ s += sprint(s, ",%D", &p->from3);
+ sprint(s, ",%D", &p->to);
+ }
+ if(p->spadj != 0)
+ return fmtprint(fp, "%s # spadj=%d", str, p->spadj);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+static int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames9[a];
+ return fmtstrcpy(fp, s);
+}
+
+static int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Addr *a;
+ int32 v;
+
+ a = va_arg(fp->args, Addr*);
+
+ if(fp->flags & FmtSharp) {
+ char *s = str;
+ if(a->type == D_NONE) {
+ sprint(s, "type=NONE");
+ goto ret;
+ }
+ if(a->type >= 0 && a->type < D_LAST && dnames9[a->type] != nil)
+ s += sprint(s, "type=%s ", dnames9[a->type]);
+ else
+ s += sprint(s, "type=%d ", a->type);
+ if(a->name >= 0 && a->name < D_LAST && dnames9[(int)a->name] != nil)
+ s += sprint(s, "name=%s ", dnames9[(int)a->name]);
+ else
+ s += sprint(s, "name=%d ", a->name);
+ s += sprint(s, "offset=%lld etype=%E width=%lld", a->offset, a->etype, a->width);
+ if(a->class != 0)
+ s += sprint(s, " class=%s", cnames9[(int)a->class]);
+ if(a->reg != NREG)
+ s += sprint(s, " reg=%d", a->reg);
+ if(a->sym != nil)
+ s += sprint(s, " sym=%s", a->sym->name);
+ if(a->type == D_BRANCH && a->u.branch != nil)
+ sprint(s, " branch=%.5lld", a->u.branch->pc);
+ goto ret;
+ }
+
+ 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:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != nil)
+ sprint(str, "%M(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ case D_DCONST:
+ if(a->reg != NREG)
+ sprint(str, "$%M(R%d)", 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");
+ else
+ sprint(str, "CR%d", a->reg);
+ if(a->name != D_NONE || a->sym != nil)
+ sprint(str, "%M(C%d)(REG)", a, a->reg);
+ 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");
+ else
+ sprint(str, "FPSCR(%d)", a->reg);
+ break;
+
+ case D_MSR:
+ sprint(str, "MSR");
+ break;
+
+ case D_BRANCH:
+ if(bigP->pcond != nil) {
+ v = bigP->pcond->pc;
+ //if(v >= INITTEXT)
+ // v -= INITTEXT-HEADR;
+ if(a->sym != nil)
+ sprint(str, "%s+%.5ux(BRANCH)", a->sym->name, v);
+ else
+ sprint(str, "%.5ux(BRANCH)", v);
+ } else if(a->u.branch != nil)
+ sprint(str, "%lld", a->u.branch->pc);
+ else if(a->sym != nil)
+ sprint(str, "%s+%lld(APC)", a->sym->name, a->offset);
+ else
+ sprint(str, "%lld(APC)", a->offset);
+ break;
+
+ case D_FCONST:
+ //sprint(str, "$%lux-%lux", a->ieee.h, a->ieee.l);
+ sprint(str, "$%.17g", a->u.dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%$\"", a->u.sval);
+ break;
+ }
+
+ret:
+ return fmtstrcpy(fp, str);
+}
+
+static int
+Mconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Addr *a;
+ LSym *s;
+ int32 l;
+
+ a = va_arg(fp->args, Addr*);
+ s = a->sym;
+ //if(s == nil) {
+ // l = a->offset;
+ // if((vlong)l != a->offset)
+ // sprint(str, "0x%llux", a->offset);
+ // else
+ // sprint(str, "%lld", a->offset);
+ // goto out;
+ //}
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ l = a->offset;
+ if((vlong)l != a->offset)
+ sprint(str, "0x%llux", a->offset);
+ else
+ sprint(str, "%lld", a->offset);
+ break;
+
+ case D_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:
+ sprint(str, "%s<>+%lld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ if(s == nil)
+ sprint(str, "%lld(SP)", -a->offset);
+ else
+ sprint(str, "%s-%lld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ if(s == nil)
+ sprint(str, "%lld(FP)", a->offset);
+ else
+ sprint(str, "%s+%lld(FP)", s->name, a->offset);
+ break;
+ }
+//out:
+ return fmtstrcpy(fp, str);
+}
+
+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);
+}
+
+static int
+DRconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "C_??";
+ if(a >= C_NONE && a <= C_NCLASS)
+ s = cnames9[a];
+ return fmtstrcpy(fp, s);
+}
+
+static int
+DSconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(int32); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/src/liblink/obj9.c b/src/liblink/obj9.c
new file mode 100644
index 000000000..10a1f1635
--- /dev/null
+++ b/src/liblink/obj9.c
@@ -0,0 +1,1083 @@
+// cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/9l/9.out.h"
+#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)
+{
+ char literal[64];
+ LSym *s;
+
+ USED(ctxt);
+
+ p->from.class = 0;
+ p->to.class = 0;
+
+ // Rewrite BR/BL to symbol as D_BRANCH.
+ switch(p->as) {
+ case ABR:
+ case ABL:
+ case ARETURN:
+ case ADUFFZERO:
+ case ADUFFCOPY:
+ if(p->to.sym != nil)
+ p->to.type = D_BRANCH;
+ break;
+ }
+
+ // Rewrite float constants to values stored in memory.
+ switch(p->as) {
+ case AFMOVS:
+ if(p->from.type == D_FCONST) {
+ int32 i32;
+ float32 f32;
+ f32 = p->from.u.dval;
+ memmove(&i32, &f32, 4);
+ sprint(literal, "$f32.%08ux", (uint32)i32);
+ s = linklookup(ctxt, literal, 0);
+ s->size = 4;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ break;
+ case AFMOVD:
+ if(p->from.type == D_FCONST) {
+ int64 i64;
+ memmove(&i64, &p->from.u.dval, 8);
+ sprint(literal, "$f64.%016llux", (uvlong)i64);
+ s = linklookup(ctxt, literal, 0);
+ s->size = 8;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ break;
+ case AMOVD:
+ if(p->from.type == D_CONST && p->from.name == D_NONE && (int64)(uint32)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.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ }
+
+ // Rewrite SUB constants into ADD.
+ switch(p->as) {
+ case ASUBC:
+ if(p->from.type == D_CONST) {
+ p->from.offset = -p->from.offset;
+ p->as = AADDC;
+ }
+ break;
+
+ case ASUBCCC:
+ if(p->from.type == D_CONST) {
+ p->from.offset = -p->from.offset;
+ p->as = AADDCCC;
+ }
+ break;
+
+ case ASUB:
+ if(p->from.type == D_CONST) {
+ p->from.offset = -p->from.offset;
+ p->as = AADD;
+ }
+ break;
+ }
+}
+
+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)
+{
+ Prog *p, *q, *p1, *p2, *q1;
+ int o, mov, aoffset;
+ vlong textstksiz, textarg;
+ int32 autosize;
+
+ if(ctxt->symmorestack[0] == nil) {
+ ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
+ ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
+ // TODO(minux): add morestack short-cuts with small fixed frame-size.
+ }
+
+ ctxt->cursym = cursym;
+
+ if(cursym->text == nil || cursym->text->link == nil)
+ return;
+
+ p = cursym->text;
+ parsetextconst(p->to.offset, &textstksiz, &textarg);
+
+ cursym->args = p->to.offset>>32;
+ cursym->locals = textstksiz;
+
+ /*
+ * find leaf subroutines
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ */
+
+ if(ctxt->debugvlog)
+ Bprint(ctxt->bso, "%5.2f noops\n", cputime());
+ Bflush(ctxt->bso);
+
+ q = nil;
+ for(p = cursym->text; p != nil; p = p->link) {
+ switch(p->as) {
+ /* too hard, just leave alone */
+ case ATEXT:
+ q = p;
+ p->mark |= LABEL|LEAF|SYNC;
+ if(p->link)
+ p->link->mark |= LABEL;
+ break;
+
+ case ANOR:
+ q = p;
+ if(p->to.type == D_REG)
+ if(p->to.reg == REGZERO)
+ p->mark |= LABEL|SYNC;
+ break;
+
+ case ALWAR:
+ case ASTWCCC:
+ case AECIWX:
+ case AECOWX:
+ case AEIEIO:
+ case AICBI:
+ case AISYNC:
+ case ATLBIE:
+ case ATLBIEL:
+ case ASLBIA:
+ case ASLBIE:
+ case ASLBMFEE:
+ case ASLBMFEV:
+ case ASLBMTE:
+ case ADCBF:
+ case ADCBI:
+ case ADCBST:
+ case ADCBT:
+ case ADCBTST:
+ case ADCBZ:
+ case ASYNC:
+ case ATLBSYNC:
+ case APTESYNC:
+ case ATW:
+ case AWORD:
+ case ARFI:
+ case ARFCI:
+ case ARFID:
+ case AHRFID:
+ q = p;
+ p->mark |= LABEL|SYNC;
+ continue;
+
+ case AMOVW:
+ 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:
+ p->mark |= LABEL|SYNC;
+ }
+ continue;
+
+ case AFABS:
+ case AFABSCC:
+ case AFADD:
+ case AFADDCC:
+ case AFCTIW:
+ case AFCTIWCC:
+ case AFCTIWZ:
+ case AFCTIWZCC:
+ case AFDIV:
+ case AFDIVCC:
+ case AFMADD:
+ case AFMADDCC:
+ case AFMOVD:
+ case AFMOVDU:
+ /* case AFMOVDS: */
+ case AFMOVS:
+ case AFMOVSU:
+ /* case AFMOVSD: */
+ case AFMSUB:
+ case AFMSUBCC:
+ case AFMUL:
+ case AFMULCC:
+ case AFNABS:
+ case AFNABSCC:
+ case AFNEG:
+ case AFNEGCC:
+ case AFNMADD:
+ case AFNMADDCC:
+ case AFNMSUB:
+ case AFNMSUBCC:
+ case AFRSP:
+ case AFRSPCC:
+ case AFSUB:
+ case AFSUBCC:
+ q = p;
+ p->mark |= FLOAT;
+ continue;
+
+ case ABL:
+ case ABCL:
+ case ADUFFZERO:
+ case ADUFFCOPY:
+ cursym->text->mark &= ~LEAF;
+
+ case ABC:
+ case ABEQ:
+ case ABGE:
+ case ABGT:
+ case ABLE:
+ case ABLT:
+ case ABNE:
+ case ABR:
+ case ABVC:
+ case ABVS:
+ p->mark |= BRANCH;
+ q = p;
+ q1 = p->pcond;
+ if(q1 != nil) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->pcond = q1;
+ }
+ if(!(q1->mark & LEAF))
+ q1->mark |= LABEL;
+ } else
+ p->mark |= LABEL;
+ q1 = p->link;
+ if(q1 != nil)
+ q1->mark |= LABEL;
+ continue;
+
+ case AFCMPO:
+ case AFCMPU:
+ q = p;
+ p->mark |= FCMP|FLOAT;
+ continue;
+
+ case ARETURN:
+ q = p;
+ if(p->link != nil)
+ p->link->mark |= LABEL;
+ continue;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ q1->mark |= p->mark;
+ continue;
+
+ default:
+ q = p;
+ continue;
+ }
+ }
+
+ autosize = 0;
+ for(p = cursym->text; p != nil; p = p->link) {
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ mov = AMOVD;
+ aoffset = 0;
+ autosize = textstksiz + 8;
+ if((p->mark & LEAF) && autosize <= 8)
+ autosize = 0;
+ else
+ if(autosize & 4)
+ autosize += 4;
+ p->to.offset = (p->to.offset & (0xffffffffull<<32)) | (uint32)(autosize-8);
+
+ if(!(p->reg & NOSPLIT))
+ p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
+
+ q = p;
+ if(autosize) {
+ /* use MOVDU to adjust R1 when saving R31, if autosize is small */
+ if(!(cursym->text->mark & LEAF) && autosize >= -BIG && autosize <= BIG) {
+ mov = AMOVDU;
+ aoffset = -autosize;
+ } else {
+ q = appendp(ctxt, p);
+ q->as = AADD;
+ q->lineno = p->lineno;
+ q->from.type = D_CONST;
+ q->from.offset = -autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->spadj = +autosize;
+ }
+ } else
+ if(!(cursym->text->mark & LEAF)) {
+ if(ctxt->debugvlog) {
+ Bprint(ctxt->bso, "save suppressed in: %s\n",
+ cursym->name);
+ Bflush(ctxt->bso);
+ }
+ cursym->text->mark |= LEAF;
+ }
+
+ if(cursym->text->mark & LEAF) {
+ cursym->leaf = 1;
+ break;
+ }
+
+ 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->to.reg = REGTMP;
+
+ q = appendp(ctxt, q);
+ q->as = mov;
+ q->lineno = p->lineno;
+ q->from.type = D_REG;
+ q->from.reg = REGTMP;
+ q->to.type = D_OREG;
+ q->to.offset = aoffset;
+ q->to.reg = REGSP;
+ if(q->as == AMOVDU)
+ q->spadj = -aoffset;
+
+ if(cursym->text->reg & WRAPPER) {
+ // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+ //
+ // MOVD g_panic(g), R3
+ // CMP R0, R3
+ // BEQ end
+ // MOVD panic_argp(R3), R4
+ // ADD $(autosize+8), R1, R5
+ // CMP R4, R5
+ // BNE end
+ // ADD $8, R1, R6
+ // MOVD R6, panic_argp(R3)
+ // end:
+ // NOP
+ //
+ // The NOP is needed to give the jumps somewhere to land.
+ // It is a liblink NOP, not a Power64 NOP: it encodes to 0 instruction bytes.
+
+
+ q = appendp(ctxt, q);
+ q->as = AMOVD;
+ q->from.type = D_OREG;
+ q->from.reg = REGG;
+ q->from.offset = 4*ctxt->arch->ptrsize; // G.panic
+ q->to.type = D_REG;
+ q->to.reg = 3;
+
+ 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 = appendp(ctxt, q);
+ q->as = ABEQ;
+ q->to.type = D_BRANCH;
+ p1 = q;
+
+ q = appendp(ctxt, q);
+ q->as = AMOVD;
+ q->from.type = D_OREG;
+ q->from.reg = 3;
+ q->from.offset = 0; // Panic.argp
+ q->to.type = D_REG;
+ q->to.reg = 4;
+
+ q = appendp(ctxt, q);
+ q->as = AADD;
+ q->from.type = D_CONST;
+ q->from.offset = autosize+8;
+ q->reg = REGSP;
+ q->to.type = D_REG;
+ q->to.reg = 5;
+
+ 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 = appendp(ctxt, q);
+ q->as = ABNE;
+ q->to.type = D_BRANCH;
+ p2 = q;
+
+ q = appendp(ctxt, q);
+ q->as = AADD;
+ q->from.type = D_CONST;
+ q->from.offset = 8;
+ q->reg = REGSP;
+ q->to.type = D_REG;
+ q->to.reg = 6;
+
+ 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->to.offset = 0; // Panic.argp
+
+ q = appendp(ctxt, q);
+ q->as = ANOP;
+ p1->pcond = q;
+ p2->pcond = q;
+ }
+
+ break;
+
+ case ARETURN:
+ if(p->from.type == D_CONST) {
+ ctxt->diag("using BECOME (%P) is not supported!", p);
+ break;
+ }
+ if(p->to.sym) { // retjmp
+ p->as = ABR;
+ p->to.type = D_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->mark |= BRANCH;
+ break;
+ }
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+ p->spadj = -autosize;
+
+ q = ctxt->arch->prg();
+ q->as = ABR;
+ q->lineno = p->lineno;
+ q->to.type = D_SPR;
+ q->to.offset = D_LR;
+ q->mark |= BRANCH;
+ q->spadj = +autosize;
+
+ q->link = p->link;
+ p->link = q;
+ break;
+ }
+
+ p->as = AMOVD;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = ctxt->arch->prg();
+ q->as = AMOVD;
+ q->lineno = p->lineno;
+ q->from.type = D_REG;
+ q->from.reg = REGTMP;
+ q->to.type = D_SPR;
+ q->to.offset = D_LR;
+
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ if(autosize) {
+ q = ctxt->arch->prg();
+ q->as = AADD;
+ q->lineno = p->lineno;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->spadj = -autosize;
+
+ q->link = p->link;
+ p->link = q;
+ }
+
+ q1 = ctxt->arch->prg();
+ q1->as = ABR;
+ q1->lineno = p->lineno;
+ q1->to.type = D_SPR;
+ q1->to.offset = D_LR;
+ q1->mark |= BRANCH;
+ q1->spadj = +autosize;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ case AADD:
+ if(p->to.type == D_REG && p->to.reg == REGSP && p->from.type == D_CONST)
+ p->spadj = -p->from.offset;
+ break;
+ }
+ }
+
+#if 0 // instruction scheduling
+ if(debug['Q'] == 0)
+ return;
+
+ curtext = nil;
+ q = nil; /* p - 1 */
+ q1 = firstp; /* top of block */
+ o = 0; /* count of instructions */
+ for(p = firstp; p != nil; p = p1) {
+ p1 = p->link;
+ o++;
+ if(p->mark & NOSCHED){
+ if(q1 != p){
+ sched(q1, q);
+ }
+ for(; p != nil; p = p->link){
+ if(!(p->mark & NOSCHED))
+ break;
+ q = p;
+ }
+ p1 = p;
+ q1 = p;
+ o = 0;
+ continue;
+ }
+ if(p->mark & (LABEL|SYNC)) {
+ if(q1 != p)
+ sched(q1, q);
+ q1 = p;
+ o = 1;
+ }
+ if(p->mark & (BRANCH|SYNC)) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ if(o >= NSCHED) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ q = p;
+ }
+#endif
+}
+
+static Prog*
+stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
+{
+ Prog *q, *q1;
+
+ // MOVD g_stackguard(g), R3
+ p = appendp(ctxt, p);
+ p->as = AMOVD;
+ p->from.type = D_OREG;
+ 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;
+
+ q = nil;
+ if(framesize <= StackSmall) {
+ // small stack: SP < stackguard
+ // 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->to.reg = REGSP;
+ } else if(framesize <= StackBig) {
+ // large stack: SP-framesize < stackguard-StackSmall
+ // ADD $-framesize, SP, R4
+ // CMP stackguard, R4
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = -framesize;
+ p->reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = 4;
+
+ 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;
+ } else {
+ // Such a large stack we need to protect against wraparound.
+ // If SP is close to zero:
+ // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
+ // The +StackGuard on both sides is required to keep the left side positive:
+ // SP is allowed to be slightly below stackguard. See stack.h.
+ //
+ // Preemption sets stackguard to StackPreempt, a very large value.
+ // That breaks the math above, so we have to check for that explicitly.
+ // // stackguard is R3
+ // CMP R3, $StackPreempt
+ // BEQ label-of-call-to-morestack
+ // ADD $StackGuard, SP, R4
+ // SUB R3, R4
+ // MOVD $(framesize+(StackGuard-StackSmall)), R31
+ // 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->to.offset = StackPreempt;
+
+ q = p = appendp(ctxt, p);
+ p->as = ABEQ;
+ p->to.type = D_BRANCH;
+
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = StackGuard;
+ p->reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = 4;
+
+ 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 = appendp(ctxt, p);
+ p->as = AMOVD;
+ p->from.type = D_CONST;
+ p->from.offset = framesize + StackGuard - StackSmall;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPU;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->to.type = D_REG;
+ p->to.reg = 4;
+ }
+
+ // q1: BLT done
+ q1 = p = appendp(ctxt, p);
+ p->as = ABLT;
+ p->to.type = D_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;
+ if(q)
+ q->pcond = p;
+
+ // BL runtime.morestack(SB)
+ p = appendp(ctxt, p);
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ if(ctxt->cursym->cfunc)
+ p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
+ else
+ p->to.sym = ctxt->symmorestack[noctxt];
+
+ // BR start
+ p = appendp(ctxt, p);
+ p->as = ABR;
+ p->to.type = D_BRANCH;
+ p->pcond = ctxt->cursym->text->link;
+
+ // placeholder for q1's jump target
+ p = appendp(ctxt, p);
+ p->as = ANOP; // zero-width place holder
+ q1->pcond = p;
+
+ return p;
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+ Prog *firstp, *lastp;
+
+ ctxt->cursym = s;
+
+ firstp = ctxt->arch->prg();
+ lastp = firstp;
+ xfol(ctxt, s->text, &lastp);
+ lastp->link = nil;
+ s->text = firstp->link;
+}
+
+static int
+relinv(int a)
+{
+
+ switch(a) {
+ case ABEQ: return ABNE;
+ case ABNE: return ABEQ;
+
+ case ABGE: return ABLT;
+ case ABLT: return ABGE;
+
+ case ABGT: return ABLE;
+ case ABLE: return ABGT;
+
+ case ABVC: return ABVS;
+ case ABVS: return ABVC;
+ }
+ return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+ Prog *q, *r;
+ int a, b, i;
+
+loop:
+ if(p == nil)
+ return;
+ a = p->as;
+ if(a == ABR) {
+ q = p->pcond;
+ if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){
+ p->mark |= FOLL;
+ (*last)->link = p;
+ *last = p;
+ p = p->link;
+ xfol(ctxt, p, last);
+ p = q;
+ if(p && !(p->mark & FOLL))
+ goto loop;
+ return;
+ }
+ if(q != nil) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == *last || (q->mark&NOSCHED))
+ break;
+ b = 0; /* set */
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID)
+ goto copy;
+ if(!q->pcond || (q->pcond->mark&FOLL))
+ continue;
+ b = relinv(a);
+ if(!b)
+ continue;
+ copy:
+ for(;;) {
+ r = ctxt->arch->prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("cant happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ (*last)->link = r;
+ *last = r;
+ continue;
+ }
+ (*last)->link = r;
+ *last = r;
+ if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID)
+ return;
+ r->as = b;
+ r->pcond = p->link;
+ r->link = p->pcond;
+ if(!(r->link->mark&FOLL))
+ xfol(ctxt, r->link, last);
+ if(!(r->pcond->mark&FOLL))
+ print("cant happen 2\n");
+ return;
+ }
+ }
+
+ a = ABR;
+ q = ctxt->arch->prg();
+ q->as = a;
+ q->lineno = p->lineno;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ (*last)->link = p;
+ *last = p;
+ if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID){
+ if(p->mark & NOSCHED){
+ p = p->link;
+ goto loop;
+ }
+ return;
+ }
+ if(p->pcond != nil)
+ if(a != ABL && p->link != nil) {
+ xfol(ctxt, p->link, last);
+ p = p->pcond;
+ if(p == nil || (p->mark&FOLL))
+ return;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+static Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = emallocz(sizeof(*p));
+ *p = zprg;
+ return p;
+}
+
+LinkArch linkpower64 = {
+ .name = "power64",
+ .thechar = '9',
+ .endian = BigEndian,
+
+ .addstacksplit = addstacksplit,
+ .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 linkpower64le = {
+ .name = "power64le",
+ .thechar = '9',
+ .endian = LittleEndian,
+
+ .addstacksplit = addstacksplit,
+ .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,
+};
diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c
index b2478ec17..aa701f459 100644
--- a/src/liblink/objfile.c
+++ b/src/liblink/objfile.c
@@ -142,6 +142,8 @@ writeobj(Link *ctxt, Biobuf *b)
edata = nil;
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);
plink = p->link;
p->link = nil;
@@ -365,7 +367,10 @@ writesym(Link *ctxt, Biobuf *b, LSym *s)
name = "";
if(r->sym != nil)
name = r->sym->name;
- Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
+ if(ctxt->arch->thechar == '5' || ctxt->arch->thechar == '9')
+ Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%llux\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
+ else
+ Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
}
}
@@ -546,9 +551,10 @@ ldobjfile(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
static void
readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
{
- int i, j, c, t, v, n, size, dupok;
+ int i, j, c, t, v, n, ndata, nreloc, size, dupok;
static int ndup;
char *name;
+ uchar *data;
Reloc *r;
LSym *s, *dup, *typ;
Pcln *pc;
@@ -564,12 +570,24 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
dupok = rdint(f);
dupok &= 1;
size = rdint(f);
+ typ = rdsym(ctxt, f, pkg);
+ rddata(f, &data, &ndata);
+ nreloc = rdint(f);
if(v != 0)
v = ctxt->version;
s = linklookup(ctxt, name, v);
dup = nil;
if(s->type != 0 && s->type != SXREF) {
+ if((t == SDATA || t == SBSS || t == SNOPTRBSS) && ndata == 0 && nreloc == 0) {
+ if(s->size < size)
+ s->size = size;
+ if(typ != nil && s->gotype == nil)
+ s->gotype = typ;
+ return;
+ }
+ if((s->type == SDATA || s->type == SBSS || s->type == SNOPTRBSS) && s->np == 0 && s->nr == 0)
+ goto overwrite;
if(s->type != SBSS && s->type != SNOPTRBSS && !dupok && !s->dupok)
sysfatal("duplicate symbol %s (types %d and %d) in %s and %s", s->name, s->type, t, s->file, pn);
if(s->np > 0) {
@@ -577,28 +595,30 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
s = linknewsym(ctxt, ".dup", ndup++); // scratch
}
}
+overwrite:
s->file = pkg;
s->dupok = dupok;
if(t == SXREF)
sysfatal("bad sxref");
if(t == 0)
sysfatal("missing type for %s in %s", name, pn);
+ if(t == SBSS && (s->type == SRODATA || s->type == SNOPTRBSS))
+ t = s->type;
s->type = t;
if(s->size < size)
s->size = size;
- typ = rdsym(ctxt, f, pkg);
if(typ != nil) // if bss sym defined multiple times, take type from any one def
s->gotype = typ;
if(dup != nil && typ != nil)
dup->gotype = typ;
- rddata(f, &s->p, &s->np);
+ s->p = data;
+ s->np = ndata;
s->maxp = s->np;
- n = rdint(f);
- if(n > 0) {
- s->r = emallocz(n * sizeof s->r[0]);
- s->nr = n;
- s->maxr = n;
- for(i=0; i<n; i++) {
+ if(nreloc > 0) {
+ s->r = emallocz(nreloc * sizeof s->r[0]);
+ s->nr = nreloc;
+ s->maxr = nreloc;
+ for(i=0; i<nreloc; i++) {
r = &s->r[i];
r->off = rdint(f);
r->siz = rdint(f);
@@ -777,7 +797,7 @@ rdsym(Link *ctxt, Biobuf *f, char *pkg)
s->type = SRODATA;
adduint32(ctxt, s, i32);
s->reachable = 0;
- } else if(strncmp(s->name, "$f64.", 5) == 0) {
+ } else if(strncmp(s->name, "$f64.", 5) == 0 || strncmp(s->name, "$i64.", 5) == 0) {
int64 i64;
i64 = strtoull(s->name+5, nil, 16);
s->type = SRODATA;
diff --git a/src/liblink/pass.c b/src/liblink/pass.c
index bc8eb4367..8721a6a79 100644
--- a/src/liblink/pass.c
+++ b/src/liblink/pass.c
@@ -41,7 +41,7 @@ brchain(Link *ctxt, Prog *p)
int i;
for(i=0; i<20; i++) {
- if(p == nil || p->as != ctxt->arch->AJMP)
+ if(p == nil || p->as != ctxt->arch->AJMP || p->pcond == nil)
return p;
p = p->pcond;
}
@@ -56,7 +56,7 @@ brloop(Link *ctxt, Prog *p)
c = 0;
for(q = p; q != nil; q = q->pcond) {
- if(q->as != ctxt->arch->AJMP)
+ if(q->as != ctxt->arch->AJMP || q->pcond == nil)
break;
c++;
if(c >= 5000)
diff --git a/src/liblink/sched9.c b/src/liblink/sched9.c
new file mode 100644
index 000000000..a9083df9b
--- /dev/null
+++ b/src/liblink/sched9.c
@@ -0,0 +1,835 @@
+// cmd/9l/sched.c from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// +build ignore
+
+#include "l.h"
+
+enum
+{
+ E_ICC = 1<<0,
+ E_FCC = 1<<1,
+ E_MEM = 1<<2,
+ E_MEMSP = 1<<3, /* uses offset and size */
+ E_MEMSB = 1<<4, /* uses offset and size */
+ E_LR = 1<<5,
+ E_CR = 1<<6,
+ E_CTR = 1<<7,
+ E_XER = 1<<8,
+
+ E_CR0 = 0xF<<0,
+ E_CR1 = 0xF<<4,
+
+ ANYMEM = E_MEM|E_MEMSP|E_MEMSB,
+ ALL = ~0,
+};
+
+typedef struct Sch Sch;
+typedef struct Dep Dep;
+
+struct Dep
+{
+ ulong ireg;
+ ulong freg;
+ ulong cc;
+ ulong cr;
+};
+struct Sch
+{
+ Prog p;
+ Dep set;
+ Dep used;
+ long soffset;
+ char size;
+ char comp;
+};
+
+void regused(Sch*, Prog*);
+int depend(Sch*, Sch*);
+int conflict(Sch*, Sch*);
+int offoverlap(Sch*, Sch*);
+void dumpbits(Sch*, Dep*);
+
+void
+sched(Prog *p0, Prog *pe)
+{
+ Prog *p, *q;
+ Sch sch[NSCHED], *s, *t, *u, *se, stmp;
+
+ if(!debug['Q'])
+ return;
+ /*
+ * build side structure
+ */
+ s = sch;
+ for(p=p0;; p=p->link) {
+ memset(s, 0, sizeof(*s));
+ s->p = *p;
+ regused(s, p);
+ if(debug['X']) {
+ Bprint(&bso, "%P\tset", &s->p);
+ dumpbits(s, &s->set);
+ Bprint(&bso, "; used");
+ dumpbits(s, &s->used);
+ if(s->comp)
+ Bprint(&bso, "; compound");
+ if(s->p.mark & LOAD)
+ Bprint(&bso, "; load");
+ if(s->p.mark & BRANCH)
+ Bprint(&bso, "; branch");
+ if(s->p.mark & FCMP)
+ Bprint(&bso, "; fcmp");
+ Bprint(&bso, "\n");
+ }
+ s++;
+ if(p == pe)
+ break;
+ }
+ se = s;
+
+ for(s=se-1; s>=sch; s--) {
+
+ /*
+ * load delay. interlocked.
+ */
+ if(s->p.mark & LOAD) {
+ if(s >= se-1)
+ continue;
+ if(!conflict(s, (s+1)))
+ continue;
+ /*
+ * s is load, s+1 is immediate use of result
+ * t is the trial instruction to insert between s and s+1
+ */
+ for(t=s-1; t>=sch; t--) {
+ if(t->p.mark & BRANCH)
+ goto no2;
+ if(t->p.mark & FCMP)
+ if((s+1)->p.mark & BRANCH)
+ goto no2;
+ if(t->p.mark & LOAD)
+ if(conflict(t, (s+1)))
+ goto no2;
+ for(u=t+1; u<=s; u++)
+ if(depend(u, t))
+ goto no2;
+ goto out2;
+ no2:;
+ }
+ if(debug['X'])
+ Bprint(&bso, "?l%P\n", &s->p);
+ continue;
+ out2:
+ if(debug['X']) {
+ Bprint(&bso, "!l%P\n", &t->p);
+ Bprint(&bso, "%P\n", &s->p);
+ }
+ stmp = *t;
+ memmove(t, t+1, (uchar*)s - (uchar*)t);
+ *s = stmp;
+ s--;
+ continue;
+ }
+
+ /*
+ * fop2 delay.
+ */
+ if(s->p.mark & FCMP) {
+ if(s >= se-1)
+ continue;
+ if(!((s+1)->p.mark & BRANCH))
+ continue;
+ /* t is the trial instruction to use */
+ for(t=s-1; t>=sch; t--) {
+ for(u=t+1; u<=s; u++)
+ if(depend(u, t))
+ goto no3;
+ goto out3;
+ no3:;
+ }
+ if(debug['X'])
+ Bprint(&bso, "?f%P\n", &s->p);
+ continue;
+ out3:
+ if(debug['X']) {
+ Bprint(&bso, "!f%P\n", &t->p);
+ Bprint(&bso, "%P\n", &s->p);
+ }
+ stmp = *t;
+ memmove(t, t+1, (uchar*)s - (uchar*)t);
+ *s = stmp;
+ s--;
+ continue;
+ }
+ }
+
+ /*
+ * put it all back
+ */
+ for(s=sch, p=p0; s<se; s++, p=q) {
+ q = p->link;
+ if(q != s->p.link) {
+ *p = s->p;
+ p->link = q;
+ }
+ }
+ if(debug['X'])
+ Bprint(&bso, "\n");
+}
+
+void
+regused(Sch *s, Prog *realp)
+{
+ int c, ar, ad, ld, sz, nr, upd;
+ ulong m;
+ Prog *p;
+
+ p = &s->p;
+ s->comp = compound(p);
+ if(s->comp) {
+ s->set.ireg |= 1<<REGTMP;
+ s->used.ireg |= 1<<REGTMP;
+ }
+ ar = 0; /* dest is really reference */
+ ad = 0; /* source/dest is really address */
+ ld = 0; /* opcode is load instruction */
+ sz = 32*4; /* size of load/store for overlap computation */
+ nr = 0; /* source/dest is not really reg */
+ upd = 0; /* move with update; changes reg */
+
+/*
+ * flags based on opcode
+ */
+ switch(p->as) {
+ case ATEXT:
+ curtext = realp;
+ autosize = p->to.offset + 8;
+ ad = 1;
+ break;
+ case ABL:
+ s->set.cc |= E_LR;
+ ar = 1;
+ ad = 1;
+ break;
+ case ABR:
+ ar = 1;
+ ad = 1;
+ break;
+ case ACMP:
+ case ACMPU:
+ case ACMPW:
+ case ACMPWU:
+ s->set.cc |= E_ICC;
+ if(p->reg == 0)
+ s->set.cr |= E_CR0;
+ else
+ s->set.cr |= (0xF<<((p->reg&7)*4));
+ ar = 1;
+ break;
+ case AFCMPO:
+ case AFCMPU:
+ s->set.cc |= E_FCC;
+ if(p->reg == 0)
+ s->set.cr |= E_CR0;
+ else
+ s->set.cr |= (0xF<<((p->reg&7)*4));
+ ar = 1;
+ break;
+ case ACRAND:
+ case ACRANDN:
+ case ACREQV:
+ case ACRNAND:
+ case ACRNOR:
+ case ACROR:
+ case ACRORN:
+ case ACRXOR:
+ s->used.cr |= 1<<p->from.reg;
+ s->set.cr |= 1<<p->to.reg;
+ nr = 1;
+ break;
+ case ABCL: /* tricky */
+ s->used.cc |= E_FCC|E_ICC;
+ s->used.cr = ALL;
+ s->set.cc |= E_LR;
+ ar = 1;
+ break;
+ case ABC: /* tricky */
+ s->used.cc |= E_FCC|E_ICC;
+ s->used.cr = ALL;
+ ar = 1;
+ break;
+ case ABEQ:
+ case ABGE:
+ case ABGT:
+ case ABLE:
+ case ABLT:
+ case ABNE:
+ case ABVC:
+ case ABVS:
+ s->used.cc |= E_ICC;
+ s->used.cr |= E_CR0;
+ ar = 1;
+ break;
+ case ALSW:
+ case AMOVMW:
+ /* could do better */
+ sz = 32*4;
+ ld = 1;
+ break;
+ case AMOVBU:
+ case AMOVBZU:
+ upd = 1;
+ sz = 1;
+ ld = 1;
+ break;
+ case AMOVB:
+ case AMOVBZ:
+ sz = 1;
+ ld = 1;
+ break;
+ case AMOVHU:
+ case AMOVHZU:
+ upd = 1;
+ sz = 2;
+ ld = 1;
+ break;
+ case AMOVH:
+ case AMOVHBR:
+ case AMOVHZ:
+ sz = 2;
+ ld = 1;
+ break;
+ case AFMOVSU:
+ case AMOVWU:
+ case AMOVWZU:
+ upd = 1;
+ sz = 4;
+ ld = 1;
+ break;
+ case AFMOVS:
+ case AMOVW:
+ case AMOVWZ:
+ case AMOVWBR:
+ case ALWAR:
+ sz = 4;
+ ld = 1;
+ break;
+ case AFMOVDU:
+ upd = 1;
+ sz = 8;
+ ld = 1;
+ break;
+ case AFMOVD:
+ sz = 8;
+ ld = 1;
+ break;
+ case AFMOVDCC:
+ sz = 8;
+ ld = 1;
+ s->set.cc |= E_FCC;
+ s->set.cr |= E_CR1;
+ break;
+ case AMOVFL:
+ case AMOVCRFS:
+ case AMTFSB0:
+ case AMTFSB0CC:
+ case AMTFSB1:
+ case AMTFSB1CC:
+ s->set.ireg = ALL;
+ s->set.freg = ALL;
+ s->set.cc = ALL;
+ s->set.cr = ALL;
+ break;
+ case AADDCC:
+ case AADDVCC:
+ case AADDCCC:
+ case AADDCVCC:
+ case AADDMECC:
+ case AADDMEVCC:
+ case AADDECC:
+ case AADDEVCC:
+ case AADDZECC:
+ case AADDZEVCC:
+ case AANDCC:
+ case AANDNCC:
+ case ACNTLZWCC:
+ case ADIVWCC:
+ case ADIVWVCC:
+ case ADIVWUCC:
+ case ADIVWUVCC:
+ case AEQVCC:
+ case AEXTSBCC:
+ case AEXTSHCC:
+ case AMULHWCC:
+ case AMULHWUCC:
+ case AMULLWCC:
+ case AMULLWVCC:
+ case ANANDCC:
+ case ANEGCC:
+ case ANEGVCC:
+ case ANORCC:
+ case AORCC:
+ case AORNCC:
+ case AREMCC:
+ case AREMVCC:
+ case AREMUCC:
+ case AREMUVCC:
+ case ARLWMICC:
+ case ARLWNMCC:
+ case ASLWCC:
+ case ASRAWCC:
+ case ASRWCC:
+ case ASTWCCC:
+ case ASUBCC:
+ case ASUBVCC:
+ case ASUBCCC:
+ case ASUBCVCC:
+ case ASUBMECC:
+ case ASUBMEVCC:
+ case ASUBECC:
+ case ASUBEVCC:
+ case ASUBZECC:
+ case ASUBZEVCC:
+ case AXORCC:
+ s->set.cc |= E_ICC;
+ s->set.cr |= E_CR0;
+ break;
+ case AFABSCC:
+ case AFADDCC:
+ case AFADDSCC:
+ case AFCTIWCC:
+ case AFCTIWZCC:
+ case AFDIVCC:
+ case AFDIVSCC:
+ case AFMADDCC:
+ case AFMADDSCC:
+ case AFMSUBCC:
+ case AFMSUBSCC:
+ case AFMULCC:
+ case AFMULSCC:
+ case AFNABSCC:
+ case AFNEGCC:
+ case AFNMADDCC:
+ case AFNMADDSCC:
+ case AFNMSUBCC:
+ case AFNMSUBSCC:
+ case AFRSPCC:
+ case AFSUBCC:
+ case AFSUBSCC:
+ s->set.cc |= E_FCC;
+ s->set.cr |= E_CR1;
+ break;
+ }
+
+/*
+ * flags based on 'to' field
+ */
+ c = p->to.class;
+ if(c == 0) {
+ c = aclass(&p->to) + 1;
+ p->to.class = c;
+ }
+ c--;
+ switch(c) {
+ default:
+ print("unknown class %d %D\n", c, &p->to);
+
+ case C_NONE:
+ case C_ZCON:
+ case C_SCON:
+ case C_UCON:
+ case C_LCON:
+ case C_ADDCON:
+ case C_ANDCON:
+ case C_SBRA:
+ case C_LBRA:
+ break;
+ case C_CREG:
+ c = p->to.reg;
+ if(c == NREG)
+ s->set.cr = ALL;
+ else
+ s->set.cr |= (0xF << ((p->from.reg&7)*4));
+ s->set.cc = ALL;
+ break;
+ case C_SPR:
+ case C_FPSCR:
+ case C_MSR:
+ case C_XER:
+ s->set.ireg = ALL;
+ s->set.freg = ALL;
+ s->set.cc = ALL;
+ s->set.cr = ALL;
+ break;
+ case C_LR:
+ s->set.cc |= E_LR;
+ break;
+ case C_CTR:
+ s->set.cc |= E_CTR;
+ break;
+ case C_ZOREG:
+ case C_SOREG:
+ case C_LOREG:
+ c = p->to.reg;
+ s->used.ireg |= 1<<c;
+ if(upd)
+ s->set.ireg |= 1<<c;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ m = ANYMEM;
+ if(c == REGSB)
+ m = E_MEMSB;
+ if(c == REGSP)
+ m = E_MEMSP;
+
+ if(ar)
+ s->used.cc |= m;
+ else
+ s->set.cc |= m;
+ break;
+ case C_SACON:
+ case C_LACON:
+ s->used.ireg |= 1<<REGSP;
+ if(upd)
+ s->set.ireg |= 1<<c;
+ break;
+ case C_SECON:
+ case C_LECON:
+ s->used.ireg |= 1<<REGSB;
+ if(upd)
+ s->set.ireg |= 1<<c;
+ break;
+ case C_REG:
+ if(nr)
+ break;
+ if(ar)
+ s->used.ireg |= 1<<p->to.reg;
+ else
+ s->set.ireg |= 1<<p->to.reg;
+ break;
+ case C_FREG:
+ if(ar)
+ s->used.freg |= 1<<p->to.reg;
+ else
+ s->set.freg |= 1<<p->to.reg;
+ break;
+ case C_SAUTO:
+ case C_LAUTO:
+ s->used.ireg |= 1<<REGSP;
+ if(upd)
+ s->set.ireg |= 1<<c;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ if(ar)
+ s->used.cc |= E_MEMSP;
+ else
+ s->set.cc |= E_MEMSP;
+ break;
+ case C_SEXT:
+ case C_LEXT:
+ s->used.ireg |= 1<<REGSB;
+ if(upd)
+ s->set.ireg |= 1<<c;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ if(ar)
+ s->used.cc |= E_MEMSB;
+ else
+ s->set.cc |= E_MEMSB;
+ break;
+ }
+
+/*
+ * flags based on 'from' field
+ */
+ c = p->from.class;
+ if(c == 0) {
+ c = aclass(&p->from) + 1;
+ p->from.class = c;
+ }
+ c--;
+ switch(c) {
+ default:
+ print("unknown class %d %D\n", c, &p->from);
+
+ case C_NONE:
+ case C_ZCON:
+ case C_SCON:
+ case C_UCON:
+ case C_LCON:
+ case C_ADDCON:
+ case C_ANDCON:
+ case C_SBRA:
+ case C_LBRA:
+ c = p->from.reg;
+ if(c != NREG)
+ s->used.ireg |= 1<<c;
+ break;
+ case C_CREG:
+ c = p->from.reg;
+ if(c == NREG)
+ s->used.cr = ALL;
+ else
+ s->used.cr |= (0xF << ((p->from.reg&7)*4));
+ s->used.cc = ALL;
+ break;
+ case C_SPR:
+ case C_FPSCR:
+ case C_MSR:
+ case C_XER:
+ s->set.ireg = ALL;
+ s->set.freg = ALL;
+ s->set.cc = ALL;
+ s->set.cr = ALL;
+ break;
+ case C_LR:
+ s->used.cc |= E_LR;
+ break;
+ case C_CTR:
+ s->used.cc |= E_CTR;
+ break;
+ case C_ZOREG:
+ case C_SOREG:
+ case C_LOREG:
+ c = p->from.reg;
+ s->used.ireg |= 1<<c;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ m = ANYMEM;
+ if(c == REGSB)
+ m = E_MEMSB;
+ if(c == REGSP)
+ m = E_MEMSP;
+
+ s->used.cc |= m;
+ break;
+ case C_SACON:
+ case C_LACON:
+ s->used.ireg |= 1<<REGSP;
+ break;
+ case C_SECON:
+ case C_LECON:
+ s->used.ireg |= 1<<REGSB;
+ break;
+ case C_REG:
+ if(nr)
+ break;
+ s->used.ireg |= 1<<p->from.reg;
+ break;
+ case C_FREG:
+ s->used.freg |= 1<<p->from.reg;
+ break;
+ case C_SAUTO:
+ case C_LAUTO:
+ s->used.ireg |= 1<<REGSP;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ s->used.cc |= E_MEMSP;
+ break;
+ case C_SEXT:
+ case C_LEXT:
+ s->used.ireg |= 1<<REGSB;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ s->used.cc |= E_MEMSB;
+ break;
+ }
+
+ c = p->reg;
+ if(c != NREG) {
+ if(p->from.type == D_FREG || p->to.type == D_FREG)
+ s->used.freg |= 1<<c;
+ else
+ s->used.ireg |= 1<<c;
+ }
+}
+
+/*
+ * test to see if 2 instrictions can be
+ * interchanged without changing semantics
+ */
+int
+depend(Sch *sa, Sch *sb)
+{
+ ulong x;
+
+ if(sa->set.ireg & (sb->set.ireg|sb->used.ireg))
+ return 1;
+ if(sb->set.ireg & sa->used.ireg)
+ return 1;
+
+ if(sa->set.freg & (sb->set.freg|sb->used.freg))
+ return 1;
+ if(sb->set.freg & sa->used.freg)
+ return 1;
+
+ if(sa->set.cr & (sb->set.cr|sb->used.cr))
+ return 1;
+ if(sb->set.cr & sa->used.cr)
+ return 1;
+
+
+ x = (sa->set.cc & (sb->set.cc|sb->used.cc)) |
+ (sb->set.cc & sa->used.cc);
+ if(x) {
+ /*
+ * allow SB and SP to pass each other.
+ * allow SB to pass SB iff doffsets are ok
+ * anything else conflicts
+ */
+ if(x != E_MEMSP && x != E_MEMSB)
+ return 1;
+ x = sa->set.cc | sb->set.cc |
+ sa->used.cc | sb->used.cc;
+ if(x & E_MEM)
+ return 1;
+ if(offoverlap(sa, sb))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+offoverlap(Sch *sa, Sch *sb)
+{
+
+ if(sa->soffset < sb->soffset) {
+ if(sa->soffset+sa->size > sb->soffset)
+ return 1;
+ return 0;
+ }
+ if(sb->soffset+sb->size > sa->soffset)
+ return 1;
+ return 0;
+}
+
+/*
+ * test 2 adjacent instructions
+ * and find out if inserted instructions
+ * are desired to prevent stalls.
+ * first instruction is a load instruction.
+ */
+int
+conflict(Sch *sa, Sch *sb)
+{
+
+ if(sa->set.ireg & sb->used.ireg)
+ return 1;
+ if(sa->set.freg & sb->used.freg)
+ return 1;
+ if(sa->set.cr & sb->used.cr)
+ return 1;
+ return 0;
+}
+
+int
+compound(Prog *p)
+{
+ Optab *o;
+
+ o = oplook(p);
+ if(o->size != 4)
+ return 1;
+ if(p->to.type == D_REG && p->to.reg == REGSB)
+ return 1;
+ return 0;
+}
+
+void
+dumpbits(Sch *s, Dep *d)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(d->ireg & (1<<i))
+ Bprint(&bso, " R%d", i);
+ for(i=0; i<32; i++)
+ if(d->freg & (1<<i))
+ Bprint(&bso, " F%d", i);
+ for(i=0; i<32; i++)
+ if(d->cr & (1<<i))
+ Bprint(&bso, " C%d", i);
+ for(i=0; i<32; i++)
+ switch(d->cc & (1<<i)) {
+ default:
+ break;
+ case E_ICC:
+ Bprint(&bso, " ICC");
+ break;
+ case E_FCC:
+ Bprint(&bso, " FCC");
+ break;
+ case E_LR:
+ Bprint(&bso, " LR");
+ break;
+ case E_CR:
+ Bprint(&bso, " CR");
+ break;
+ case E_CTR:
+ Bprint(&bso, " CTR");
+ break;
+ case E_XER:
+ Bprint(&bso, " XER");
+ break;
+ case E_MEM:
+ Bprint(&bso, " MEM%d", s->size);
+ break;
+ case E_MEMSB:
+ Bprint(&bso, " SB%d", s->size);
+ break;
+ case E_MEMSP:
+ Bprint(&bso, " SP%d", s->size);
+ break;
+ }
+}
diff --git a/src/math/abs_power64x.s b/src/math/abs_power64x.s
new file mode 100644
index 000000000..3ba8201b3
--- /dev/null
+++ b/src/math/abs_power64x.s
@@ -0,0 +1,14 @@
+// Copyright 2011 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.
+
+// +build power64 power64le
+
+#include "textflag.h"
+
+TEXT ·Abs(SB),NOSPLIT,$0-16
+ MOVD x+0(FP), R3
+ MOVD $((1<<63)-1), R4
+ AND R4, R3
+ MOVD R3, ret+8(FP)
+ RETURN
diff --git a/src/math/big/arith_power64x.s b/src/math/big/arith_power64x.s
new file mode 100644
index 000000000..c33a9209f
--- /dev/null
+++ b/src/math/big/arith_power64x.s
@@ -0,0 +1,46 @@
+// 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.
+
+// +build power64 power64le
+
+#include "textflag.h"
+
+// This file provides fast assembly versions for the elementary
+// arithmetic operations on vectors implemented in arith.go.
+
+TEXT ·mulWW(SB),NOSPLIT,$0
+ BR ·mulWW_g(SB)
+
+TEXT ·divWW(SB),NOSPLIT,$0
+ BR ·divWW_g(SB)
+
+TEXT ·addVV(SB),NOSPLIT,$0
+ BR ·addVV_g(SB)
+
+TEXT ·subVV(SB),NOSPLIT,$0
+ BR ·subVV_g(SB)
+
+TEXT ·addVW(SB),NOSPLIT,$0
+ BR ·addVW_g(SB)
+
+TEXT ·subVW(SB),NOSPLIT,$0
+ BR ·subVW_g(SB)
+
+TEXT ·shlVU(SB),NOSPLIT,$0
+ BR ·shlVU_g(SB)
+
+TEXT ·shrVU(SB),NOSPLIT,$0
+ BR ·shrVU_g(SB)
+
+TEXT ·mulAddVWW(SB),NOSPLIT,$0
+ BR ·mulAddVWW_g(SB)
+
+TEXT ·addMulVVW(SB),NOSPLIT,$0
+ BR ·addMulVVW_g(SB)
+
+TEXT ·divWVW(SB),NOSPLIT,$0
+ BR ·divWVW_g(SB)
+
+TEXT ·bitLen(SB),NOSPLIT,$0
+ BR ·bitLen_g(SB)
diff --git a/src/math/stubs_power64x.s b/src/math/stubs_power64x.s
new file mode 100644
index 000000000..36b762554
--- /dev/null
+++ b/src/math/stubs_power64x.s
@@ -0,0 +1,91 @@
+// 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.
+
+// +build power64 power64le
+
+#include "textflag.h"
+
+TEXT ·Asin(SB),NOSPLIT,$0
+ BR ·asin(SB)
+
+TEXT ·Acos(SB),NOSPLIT,$0
+ BR ·acos(SB)
+
+TEXT ·Atan2(SB),NOSPLIT,$0
+ BR ·atan2(SB)
+
+TEXT ·Atan(SB),NOSPLIT,$0
+ BR ·atan(SB)
+
+TEXT ·Dim(SB),NOSPLIT,$0
+ BR ·dim(SB)
+
+TEXT ·Min(SB),NOSPLIT,$0
+ BR ·min(SB)
+
+TEXT ·Max(SB),NOSPLIT,$0
+ BR ·max(SB)
+
+TEXT ·Exp2(SB),NOSPLIT,$0
+ BR ·exp2(SB)
+
+TEXT ·Expm1(SB),NOSPLIT,$0
+ BR ·expm1(SB)
+
+TEXT ·Exp(SB),NOSPLIT,$0
+ BR ·exp(SB)
+
+TEXT ·Floor(SB),NOSPLIT,$0
+ BR ·floor(SB)
+
+TEXT ·Ceil(SB),NOSPLIT,$0
+ BR ·ceil(SB)
+
+TEXT ·Trunc(SB),NOSPLIT,$0
+ BR ·trunc(SB)
+
+TEXT ·Frexp(SB),NOSPLIT,$0
+ BR ·frexp(SB)
+
+TEXT ·Hypot(SB),NOSPLIT,$0
+ BR ·hypot(SB)
+
+TEXT ·Ldexp(SB),NOSPLIT,$0
+ BR ·ldexp(SB)
+
+TEXT ·Log10(SB),NOSPLIT,$0
+ BR ·log10(SB)
+
+TEXT ·Log2(SB),NOSPLIT,$0
+ BR ·log2(SB)
+
+TEXT ·Log1p(SB),NOSPLIT,$0
+ BR ·log1p(SB)
+
+TEXT ·Log(SB),NOSPLIT,$0
+ BR ·log(SB)
+
+TEXT ·Modf(SB),NOSPLIT,$0
+ BR ·modf(SB)
+
+TEXT ·Mod(SB),NOSPLIT,$0
+ BR ·mod(SB)
+
+TEXT ·Remainder(SB),NOSPLIT,$0
+ BR ·remainder(SB)
+
+TEXT ·Sincos(SB),NOSPLIT,$0
+ BR ·sincos(SB)
+
+TEXT ·Sin(SB),NOSPLIT,$0
+ BR ·sin(SB)
+
+TEXT ·Cos(SB),NOSPLIT,$0
+ BR ·cos(SB)
+
+TEXT ·Sqrt(SB),NOSPLIT,$0
+ BR ·sqrt(SB)
+
+TEXT ·Tan(SB),NOSPLIT,$0
+ BR ·tan(SB)
diff --git a/src/os/signal/sig.s b/src/os/signal/sig.s
index d54c284b5..1826c37fb 100644
--- a/src/os/signal/sig.s
+++ b/src/os/signal/sig.s
@@ -4,13 +4,19 @@
// Assembly to get into package runtime without using exported symbols.
-// +build amd64 amd64p32 arm 386
+// +build amd64 amd64p32 arm 386 power64 power64le
#include "textflag.h"
#ifdef GOARCH_arm
#define JMP B
#endif
+#ifdef GOARCH_power64
+#define JMP BR
+#endif
+#ifdef GOARCH_power64le
+#define JMP BR
+#endif
TEXT ·signal_disable(SB),NOSPLIT,$0
JMP runtime·signal_disable(SB)
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 7a01c95d8..9d092d9ac 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -1052,6 +1052,11 @@ func TestChan(t *testing.T) {
ok = cv.TrySend(ValueOf(6))
if !ok {
t.Errorf("TrySend on empty chan failed")
+ select {
+ case x := <-c:
+ t.Errorf("TrySend failed but it did send %d", x)
+ default:
+ }
} else {
if i = <-c; i != 6 {
t.Errorf("TrySend 6, recv %d", i)
diff --git a/src/reflect/asm_power64x.s b/src/reflect/asm_power64x.s
new file mode 100644
index 000000000..472063824
--- /dev/null
+++ b/src/reflect/asm_power64x.s
@@ -0,0 +1,32 @@
+// Copyright 2012 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.
+
+// +build power64 power64le
+
+#include "textflag.h"
+#include "funcdata.h"
+
+// makeFuncStub is the code half of the function returned by MakeFunc.
+// See the comment on the declaration of makeFuncStub in makefunc.go
+// for more details.
+// No arg size here, runtime pulls arg map out of the func value.
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
+ NO_LOCAL_POINTERS
+ MOVD R11, 8(R1)
+ MOVD $argframe+0(FP), R3
+ MOVD R3, 16(R1)
+ BL ·callReflect(SB)
+ RETURN
+
+// methodValueCall is the code half of the function returned by makeMethodValue.
+// See the comment on the declaration of methodValueCall in makefunc.go
+// for more details.
+// No arg size here; runtime pulls arg map out of the func value.
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
+ NO_LOCAL_POINTERS
+ MOVD R11, 8(R1)
+ MOVD $argframe+0(FP), R3
+ MOVD R3, 16(R1)
+ BL ·callMethod(SB)
+ RETURN
diff --git a/src/reflect/type.go b/src/reflect/type.go
index c0ddfcad0..441459b3f 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -1533,12 +1533,8 @@ func (gc *gcProg) appendProg(t *rtype) {
gc.appendProg(e)
}
case Interface:
- gc.appendWord(bitsMultiWord)
- if t.NumMethod() == 0 {
- gc.appendWord(bitsEface)
- } else {
- gc.appendWord(bitsIface)
- }
+ gc.appendWord(bitsPointer)
+ gc.appendWord(bitsPointer)
case Struct:
c := t.NumField()
for i := 0; i < c; i++ {
@@ -1592,9 +1588,8 @@ func (gc *gcProg) align(a uintptr) {
// These constants must stay in sync with ../runtime/mgc0.h.
const (
- bitsScalar = 1
- bitsPointer = 2
- bitsMultiWord = 3
+ bitsScalar = 1
+ bitsPointer = 2
bitsIface = 2
bitsEface = 3
diff --git a/src/run.bash b/src/run.bash
index 5f20451a2..6b9ecc33c 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -255,8 +255,8 @@ rm -f runtest
[ "$GOOS" == nacl ] ||
(
echo
-echo '# Checking API compatibility.'
-time go run $GOROOT/src/cmd/api/run.go || exit 1
+echo '# SKIPPING API CHECK UNTIL ALL SYSTEMS BUILD.'
+# time go run $GOROOT/src/cmd/api/run.go || exit 1
) || exit $?
echo
diff --git a/src/run.bat b/src/run.bat
index 14c1b45fd..efa97662f 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -134,9 +134,11 @@ if %FAIL%==1 goto fail
set GOMAXPROCS=%OLDGOMAXPROCS%
set OLDGOMAXPROCS=
-echo # Checking API compatibility.
-go run "%GOROOT%\src\cmd\api\run.go"
-if errorlevel 1 goto fail
+:: echo # Checking API compatibility.
+:: go run "%GOROOT%\src\cmd\api\run.go"
+:: if errorlevel 1 goto fail
+:: echo.
+echo # SKIPPING API COMPATIBILITY UNTIL ALL SYSTEMS BUILD.
echo.
echo ALL TESTS PASSED
diff --git a/src/runtime/alg.go b/src/runtime/alg.go
index e9ed59503..e367bc5b2 100644
--- a/src/runtime/alg.go
+++ b/src/runtime/alg.go
@@ -314,9 +314,6 @@ const hashRandomBytes = 32
var aeskeysched [hashRandomBytes]byte
-//go:noescape
-func get_random_data(rnd *unsafe.Pointer, n *int32)
-
func init() {
if theGoos == "nacl" {
return
diff --git a/src/runtime/arch1_386.go b/src/runtime/arch1_386.go
new file mode 100644
index 000000000..a73e207ed
--- /dev/null
+++ b/src/runtime/arch1_386.go
@@ -0,0 +1,15 @@
+// Copyright 2011 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 runtime
+
+const (
+ thechar = '8'
+ _BigEndian = 0
+ _CacheLineSize = 64
+ _RuntimeGogoBytes = 64
+ _PhysPageSize = goos_nacl*65536 + (1-goos_nacl)*4096 // 4k normally; 64k on NaCl
+ _PCQuantum = 1
+ _Int64Align = 4
+)
diff --git a/src/runtime/arch1_amd64.go b/src/runtime/arch1_amd64.go
new file mode 100644
index 000000000..794b7f65c
--- /dev/null
+++ b/src/runtime/arch1_amd64.go
@@ -0,0 +1,15 @@
+// Copyright 2011 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 runtime
+
+const (
+ thechar = '6'
+ _BigEndian = 0
+ _CacheLineSize = 64
+ _RuntimeGogoBytes = 64 + (goos_plan9|goos_solaris|goos_windows)*16
+ _PhysPageSize = 4096
+ _PCQuantum = 1
+ _Int64Align = 8
+)
diff --git a/src/runtime/arch1_amd64p32.go b/src/runtime/arch1_amd64p32.go
new file mode 100644
index 000000000..2cee21f0c
--- /dev/null
+++ b/src/runtime/arch1_amd64p32.go
@@ -0,0 +1,15 @@
+// Copyright 2011 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 runtime
+
+const (
+ thechar = '6'
+ _BigEndian = 0
+ _CacheLineSize = 64
+ _RuntimeGogoBytes = 64
+ _PhysPageSize = 65536*goos_nacl + 4096*(1-goos_nacl)
+ _PCQuantum = 1
+ _Int64Align = 8
+)
diff --git a/src/runtime/arch1_arm.go b/src/runtime/arch1_arm.go
new file mode 100644
index 000000000..6662eaeac
--- /dev/null
+++ b/src/runtime/arch1_arm.go
@@ -0,0 +1,15 @@
+// Copyright 2011 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 runtime
+
+const (
+ thechar = '5'
+ _BigEndian = 0
+ _CacheLineSize = 32
+ _RuntimeGogoBytes = 60
+ _PhysPageSize = 65536*goos_nacl + 4096*(1-goos_nacl)
+ _PCQuantum = 4
+ _Int64Align = 4
+)
diff --git a/src/runtime/arch1_power64.go b/src/runtime/arch1_power64.go
new file mode 100644
index 000000000..01e2b70f9
--- /dev/null
+++ b/src/runtime/arch1_power64.go
@@ -0,0 +1,15 @@
+// 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 runtime
+
+const (
+ thechar = '9'
+ _BigEndian = 1
+ _CacheLineSize = 64
+ _RuntimeGogoBytes = 64
+ _PhysPageSize = 65536
+ _PCQuantum = 4
+ _Int64Align = 8
+)
diff --git a/src/runtime/arch1_power64le.go b/src/runtime/arch1_power64le.go
new file mode 100644
index 000000000..6580732a3
--- /dev/null
+++ b/src/runtime/arch1_power64le.go
@@ -0,0 +1,15 @@
+// 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 runtime
+
+const (
+ thechar = '9'
+ _BigEndian = 0
+ _CacheLineSize = 64
+ _RuntimeGogoBytes = 64
+ _PhysPageSize = 65536
+ _PCQuantum = 4
+ _Int64Align = 8
+)
diff --git a/src/runtime/arch_386.h b/src/runtime/arch_386.h
deleted file mode 100644
index 75a5ba77f..000000000
--- a/src/runtime/arch_386.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2011 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.
-
-enum {
- thechar = '8',
- BigEndian = 0,
- CacheLineSize = 64,
- RuntimeGogoBytes = 64,
-#ifdef GOOS_nacl
- PhysPageSize = 65536,
-#else
- PhysPageSize = 4096,
-#endif
- PCQuantum = 1,
- Int64Align = 4
-};
diff --git a/src/runtime/arch_amd64.h b/src/runtime/arch_amd64.h
deleted file mode 100644
index d7b81ee90..000000000
--- a/src/runtime/arch_amd64.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2011 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.
-
-enum {
- thechar = '6',
- BigEndian = 0,
- CacheLineSize = 64,
-#ifdef GOOS_solaris
- RuntimeGogoBytes = 80,
-#else
-#ifdef GOOS_windows
- RuntimeGogoBytes = 80,
-#else
-#ifdef GOOS_plan9
- RuntimeGogoBytes = 80,
-#else
- RuntimeGogoBytes = 64,
-#endif // Plan 9
-#endif // Windows
-#endif // Solaris
- PhysPageSize = 4096,
- PCQuantum = 1,
- Int64Align = 8
-};
diff --git a/src/runtime/arch_amd64p32.h b/src/runtime/arch_amd64p32.h
deleted file mode 100644
index d3e864987..000000000
--- a/src/runtime/arch_amd64p32.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2011 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.
-
-enum {
- thechar = '6',
- BigEndian = 0,
- CacheLineSize = 64,
- RuntimeGogoBytes = 64,
-#ifdef GOOS_nacl
- PhysPageSize = 65536,
-#else
- PhysPageSize = 4096,
-#endif
- PCQuantum = 1,
- Int64Align = 8
-};
diff --git a/src/runtime/arch_arm.h b/src/runtime/arch_arm.h
deleted file mode 100644
index 637a334a0..000000000
--- a/src/runtime/arch_arm.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2011 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.
-
-enum {
- thechar = '5',
- BigEndian = 0,
- CacheLineSize = 32,
- RuntimeGogoBytes = 60,
-#ifdef GOOS_nacl
- PhysPageSize = 65536,
-#else
- PhysPageSize = 4096,
-#endif
- PCQuantum = 4,
- Int64Align = 4
-};
diff --git a/src/runtime/arch_power64.go b/src/runtime/arch_power64.go
new file mode 100644
index 000000000..270cd7b95
--- /dev/null
+++ b/src/runtime/arch_power64.go
@@ -0,0 +1,8 @@
+// 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 runtime
+
+type uintreg uint64
+type intptr int64 // TODO(rsc): remove
diff --git a/src/runtime/arch_power64le.go b/src/runtime/arch_power64le.go
new file mode 100644
index 000000000..270cd7b95
--- /dev/null
+++ b/src/runtime/arch_power64le.go
@@ -0,0 +1,8 @@
+// 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 runtime
+
+type uintreg uint64
+type intptr int64 // TODO(rsc): remove
diff --git a/src/runtime/asm.s b/src/runtime/asm.s
index e6d782f37..f1c812b90 100644
--- a/src/runtime/asm.s
+++ b/src/runtime/asm.s
@@ -12,3 +12,8 @@ DATA runtime·no_pointers_stackmap+0x00(SB)/4, $2
DATA runtime·no_pointers_stackmap+0x04(SB)/4, $0
GLOBL runtime·no_pointers_stackmap(SB),RODATA, $8
+TEXT runtime·nop(SB),NOSPLIT,$0-0
+ RET
+
+GLOBL runtime·mheap_(SB), NOPTR, $0
+GLOBL runtime·memstats(SB), NOPTR, $0
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index b4b81d739..a02bb5556 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "funcdata.h"
#include "textflag.h"
@@ -49,7 +50,7 @@ nocpuinfo:
// update stackguard after _cgo_init
MOVL $runtime·g0(SB), CX
MOVL (g_stack+stack_lo)(CX), AX
- ADDL $const_StackGuard, AX
+ ADDL $const__StackGuard, AX
MOVL AX, g_stackguard0(CX)
MOVL AX, g_stackguard1(CX)
@@ -199,62 +200,49 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4
JMP AX
RET
-// switchtoM is a dummy routine that onM leaves at the bottom
+// systemstack_switch is a dummy routine that systemstack leaves at the bottom
// of the G stack. We need to distinguish the routine that
// lives at the bottom of the G stack from the one that lives
-// at the top of the M stack because the one at the top of
-// the M stack terminates the stack walk (see topofstack()).
-TEXT runtime·switchtoM(SB), NOSPLIT, $0-0
+// at the top of the system stack because the one at the top of
+// the system stack terminates the stack walk (see topofstack()).
+TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
RET
-// func onM_signalok(fn func())
-TEXT runtime·onM_signalok(SB), NOSPLIT, $0-4
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB), NOSPLIT, $0-4
+ MOVL fn+0(FP), DI // DI = fn
get_tls(CX)
MOVL g(CX), AX // AX = g
MOVL g_m(AX), BX // BX = m
+
MOVL m_gsignal(BX), DX // DX = gsignal
CMPL AX, DX
- JEQ ongsignal
- JMP runtime·onM(SB)
-
-ongsignal:
- MOVL fn+0(FP), DI // DI = fn
- MOVL DI, DX
- MOVL 0(DI), DI
- CALL DI
- RET
-
-// func onM(fn func())
-TEXT runtime·onM(SB), NOSPLIT, $0-4
- MOVL fn+0(FP), DI // DI = fn
- get_tls(CX)
- MOVL g(CX), AX // AX = g
- MOVL g_m(AX), BX // BX = m
+ JEQ noswitch
MOVL m_g0(BX), DX // DX = g0
CMPL AX, DX
- JEQ onm
+ JEQ noswitch
MOVL m_curg(BX), BP
CMPL AX, BP
- JEQ oncurg
+ JEQ switch
- // Not g0, not curg. Must be gsignal, but that's not allowed.
+ // Bad: g is not gsignal, not g0, not curg. What is it?
// Hide call from linker nosplit analysis.
- MOVL $runtime·badonm(SB), AX
+ MOVL $runtime·badsystemstack(SB), AX
CALL AX
-oncurg:
+switch:
// save our state in g->sched. Pretend to
- // be switchtoM if the G stack is scanned.
- MOVL $runtime·switchtoM(SB), (g_sched+gobuf_pc)(AX)
+ // be systemstack_switch if the G stack is scanned.
+ MOVL $runtime·systemstack_switch(SB), (g_sched+gobuf_pc)(AX)
MOVL SP, (g_sched+gobuf_sp)(AX)
MOVL AX, (g_sched+gobuf_g)(AX)
// switch to g0
MOVL DX, g(CX)
MOVL (g_sched+gobuf_sp)(DX), BX
- // make it look like mstart called onM on g0, to stop traceback
+ // make it look like mstart called systemstack on g0, to stop traceback
SUBL $4, BX
MOVL $runtime·mstart(SB), DX
MOVL DX, 0(BX)
@@ -275,8 +263,8 @@ oncurg:
MOVL $0, (g_sched+gobuf_sp)(AX)
RET
-onm:
- // already on m stack, just call directly
+noswitch:
+ // already on system stack, just call directly
MOVL DI, DX
MOVL 0(DI), DI
CALL DI
@@ -486,11 +474,11 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-21
MOVL new_hi+16(FP), CX
LOCK
CMPXCHG8B 0(BP)
- JNZ cas64_fail
+ JNZ fail
MOVL $1, AX
MOVB AX, ret+20(FP)
RET
-cas64_fail:
+fail:
MOVL $0, AX
MOVB AX, ret+20(FP)
RET
@@ -502,7 +490,7 @@ cas64_fail:
// return 1;
// }else
// return 0;
-TEXT runtime·casp(SB), NOSPLIT, $0-13
+TEXT runtime·casp1(SB), NOSPLIT, $0-13
MOVL ptr+0(FP), BX
MOVL old+4(FP), AX
MOVL new+8(FP), CX
@@ -537,7 +525,7 @@ TEXT runtime·xchg(SB), NOSPLIT, $0-12
MOVL AX, ret+8(FP)
RET
-TEXT runtime·xchgp(SB), NOSPLIT, $0-12
+TEXT runtime·xchgp1(SB), NOSPLIT, $0-12
MOVL ptr+0(FP), BX
MOVL new+4(FP), AX
XCHGL AX, 0(BX)
@@ -555,7 +543,7 @@ again:
JNZ again
RET
-TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
+TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-8
MOVL ptr+0(FP), BX
MOVL val+4(FP), AX
XCHGL AX, 0(BX)
@@ -740,7 +728,7 @@ needm:
// the same SP back to m->sched.sp. That seems redundant,
// but if an unrecovered panic happens, unwindm will
// restore the g->sched.sp from the stack location
- // and then onM will try to use it. If we don't set it here,
+ // 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.
MOVL m_g0(BP), SI
@@ -1356,29 +1344,29 @@ TEXT strings·IndexByte(SB),NOSPLIT,$0
// AX = 1/0/-1
TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
CMPL SI, DI
- JEQ cmp_allsame
+ JEQ allsame
CMPL BX, DX
MOVL DX, BP
CMOVLLT BX, BP // BP = min(alen, blen)
CMPL BP, $4
- JB cmp_small
+ JB small
TESTL $0x4000000, runtime·cpuid_edx(SB) // check for sse2
- JE cmp_mediumloop
-cmp_largeloop:
+ JE mediumloop
+largeloop:
CMPL BP, $16
- JB cmp_mediumloop
+ JB mediumloop
MOVOU (SI), X0
MOVOU (DI), X1
PCMPEQB X0, X1
PMOVMSKB X1, AX
XORL $0xffff, AX // convert EQ to NE
- JNE cmp_diff16 // branch if at least one byte is not equal
+ JNE diff16 // branch if at least one byte is not equal
ADDL $16, SI
ADDL $16, DI
SUBL $16, BP
- JMP cmp_largeloop
+ JMP largeloop
-cmp_diff16:
+diff16:
BSFL AX, BX // index of first byte that differs
XORL AX, AX
MOVB (SI)(BX*1), CX
@@ -1387,25 +1375,25 @@ cmp_diff16:
LEAL -1(AX*2), AX // convert 1/0 to +1/-1
RET
-cmp_mediumloop:
+mediumloop:
CMPL BP, $4
- JBE cmp_0through4
+ JBE _0through4
MOVL (SI), AX
MOVL (DI), CX
CMPL AX, CX
- JNE cmp_diff4
+ JNE diff4
ADDL $4, SI
ADDL $4, DI
SUBL $4, BP
- JMP cmp_mediumloop
+ JMP mediumloop
-cmp_0through4:
+_0through4:
MOVL -4(SI)(BP*1), AX
MOVL -4(DI)(BP*1), CX
CMPL AX, CX
- JEQ cmp_allsame
+ JEQ allsame
-cmp_diff4:
+diff4:
BSWAPL AX // reverse order of bytes
BSWAPL CX
XORL AX, CX // find bit differences
@@ -1416,37 +1404,37 @@ cmp_diff4:
RET
// 0-3 bytes in common
-cmp_small:
+small:
LEAL (BP*8), CX
NEGL CX
- JEQ cmp_allsame
+ JEQ allsame
// load si
CMPB SI, $0xfc
- JA cmp_si_high
+ JA si_high
MOVL (SI), SI
- JMP cmp_si_finish
-cmp_si_high:
+ JMP si_finish
+si_high:
MOVL -4(SI)(BP*1), SI
SHRL CX, SI
-cmp_si_finish:
+si_finish:
SHLL CX, SI
// same for di
CMPB DI, $0xfc
- JA cmp_di_high
+ JA di_high
MOVL (DI), DI
- JMP cmp_di_finish
-cmp_di_high:
+ JMP di_finish
+di_high:
MOVL -4(DI)(BP*1), DI
SHRL CX, DI
-cmp_di_finish:
+di_finish:
SHLL CX, DI
BSWAPL SI // reverse order of bytes
BSWAPL DI
XORL SI, DI // find bit differences
- JEQ cmp_allsame
+ JEQ allsame
BSRL DI, CX // index of highest bit difference
SHRL CX, SI // move a's bit to bottom
ANDL $1, SI // mask bit
@@ -1455,7 +1443,7 @@ cmp_di_finish:
// all the bytes in common are the same, so we just need
// to compare the lengths.
-cmp_allsame:
+allsame:
XORL AX, AX
XORL CX, CX
CMPL BX, DX
@@ -2290,3 +2278,10 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
TEXT runtime·goexit(SB),NOSPLIT,$0-0
BYTE $0x90 // NOP
CALL runtime·goexit1(SB) // does not return
+
+TEXT runtime·getg(SB),NOSPLIT,$0-4
+ get_tls(CX)
+ MOVL g(CX), AX
+ MOVL AX, ret+0(FP)
+ RET
+
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 39d7c78f2..6e3f5ff6c 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "funcdata.h"
#include "textflag.h"
@@ -47,7 +48,7 @@ nocpuinfo:
// update stackguard after _cgo_init
MOVQ $runtime·g0(SB), CX
MOVQ (g_stack+stack_lo)(CX), AX
- ADDQ $const_StackGuard, AX
+ ADDQ $const__StackGuard, AX
MOVQ AX, g_stackguard0(CX)
MOVQ AX, g_stackguard1(CX)
@@ -189,55 +190,41 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8
JMP AX
RET
-// switchtoM is a dummy routine that onM leaves at the bottom
+// systemstack_switch is a dummy routine that systemstack leaves at the bottom
// of the G stack. We need to distinguish the routine that
// lives at the bottom of the G stack from the one that lives
-// at the top of the M stack because the one at the top of
-// the M stack terminates the stack walk (see topofstack()).
-TEXT runtime·switchtoM(SB), NOSPLIT, $0-0
+// at the top of the system stack because the one at the top of
+// the system stack terminates the stack walk (see topofstack()).
+TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
RET
-// func onM_signalok(fn func())
-TEXT runtime·onM_signalok(SB), NOSPLIT, $0-8
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB), NOSPLIT, $0-8
+ MOVQ fn+0(FP), DI // DI = fn
get_tls(CX)
MOVQ g(CX), AX // AX = g
MOVQ g_m(AX), BX // BX = m
+
MOVQ m_gsignal(BX), DX // DX = gsignal
CMPQ AX, DX
- JEQ ongsignal
- JMP runtime·onM(SB)
-
-ongsignal:
- MOVQ fn+0(FP), DI // DI = fn
- MOVQ DI, DX
- MOVQ 0(DI), DI
- CALL DI
- RET
-
-// func onM(fn func())
-TEXT runtime·onM(SB), NOSPLIT, $0-8
- MOVQ fn+0(FP), DI // DI = fn
- get_tls(CX)
- MOVQ g(CX), AX // AX = g
- MOVQ g_m(AX), BX // BX = m
+ JEQ noswitch
MOVQ m_g0(BX), DX // DX = g0
CMPQ AX, DX
- JEQ onm
+ JEQ noswitch
MOVQ m_curg(BX), BP
CMPQ AX, BP
- JEQ oncurg
+ JEQ switch
- // Not g0, not curg. Must be gsignal, but that's not allowed.
- // Hide call from linker nosplit analysis.
- MOVQ $runtime·badonm(SB), AX
+ // Bad: g is not gsignal, not g0, not curg. What is it?
+ MOVQ $runtime·badsystemstack(SB), AX
CALL AX
-oncurg:
+switch:
// save our state in g->sched. Pretend to
- // be switchtoM if the G stack is scanned.
- MOVQ $runtime·switchtoM(SB), BP
+ // be systemstack_switch if the G stack is scanned.
+ MOVQ $runtime·systemstack_switch(SB), BP
MOVQ BP, (g_sched+gobuf_pc)(AX)
MOVQ SP, (g_sched+gobuf_sp)(AX)
MOVQ AX, (g_sched+gobuf_g)(AX)
@@ -245,7 +232,7 @@ oncurg:
// switch to g0
MOVQ DX, g(CX)
MOVQ (g_sched+gobuf_sp)(DX), BX
- // make it look like mstart called onM on g0, to stop traceback
+ // make it look like mstart called systemstack on g0, to stop traceback
SUBQ $8, BX
MOVQ $runtime·mstart(SB), DX
MOVQ DX, 0(BX)
@@ -266,7 +253,7 @@ oncurg:
MOVQ $0, (g_sched+gobuf_sp)(AX)
RET
-onm:
+noswitch:
// already on m stack, just call directly
MOVQ DI, DX
MOVQ 0(DI), DI
@@ -461,11 +448,11 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-25
MOVQ new+16(FP), CX
LOCK
CMPXCHGQ CX, 0(BX)
- JNZ cas64_fail
+ JNZ fail
MOVL $1, AX
MOVB AX, ret+24(FP)
RET
-cas64_fail:
+fail:
MOVL $0, AX
MOVB AX, ret+24(FP)
RET
@@ -489,7 +476,7 @@ TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
// return 1;
// } else
// return 0;
-TEXT runtime·casp(SB), NOSPLIT, $0-25
+TEXT runtime·casp1(SB), NOSPLIT, $0-25
MOVQ ptr+0(FP), BX
MOVQ old+8(FP), AX
MOVQ new+16(FP), CX
@@ -541,7 +528,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24
MOVQ AX, ret+16(FP)
RET
-TEXT runtime·xchgp(SB), NOSPLIT, $0-24
+TEXT runtime·xchgp1(SB), NOSPLIT, $0-24
MOVQ ptr+0(FP), BX
MOVQ new+8(FP), AX
XCHGQ AX, 0(BX)
@@ -559,7 +546,7 @@ again:
JNZ again
RET
-TEXT runtime·atomicstorep(SB), NOSPLIT, $0-16
+TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16
MOVQ ptr+0(FP), BX
MOVQ val+8(FP), AX
XCHGQ AX, 0(BX)
@@ -726,7 +713,7 @@ needm:
// the same SP back to m->sched.sp. That seems redundant,
// but if an unrecovered panic happens, unwindm will
// restore the g->sched.sp from the stack location
- // and then onM will try to use it. If we don't set it here,
+ // 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
@@ -890,24 +877,24 @@ TEXT runtime·aeshashbody(SB),NOSPLIT,$0-32
MOVO runtime·aeskeysched+0(SB), X2
MOVO runtime·aeskeysched+16(SB), X3
CMPQ CX, $16
- JB aessmall
-aesloop:
+ JB small
+loop:
CMPQ CX, $16
- JBE aesloopend
+ JBE loopend
MOVOU (AX), X1
AESENC X2, X0
AESENC X1, X0
SUBQ $16, CX
ADDQ $16, AX
- JMP aesloop
+ JMP loop
// 1-16 bytes remaining
-aesloopend:
+loopend:
// This load may overlap with the previous load above.
// We'll hash some bytes twice, but that's ok.
MOVOU -16(AX)(CX*1), X1
JMP partial
// 0-15 bytes
-aessmall:
+small:
TESTQ CX, CX
JE finalize // 0 bytes
@@ -1050,18 +1037,18 @@ TEXT runtime·eqstring(SB),NOSPLIT,$0-33
MOVQ s1len+8(FP), AX
MOVQ s2len+24(FP), BX
CMPQ AX, BX
- JNE different
+ JNE noteq
MOVQ s1str+0(FP), SI
MOVQ s2str+16(FP), DI
CMPQ SI, DI
- JEQ same
+ JEQ eq
CALL runtime·memeqbody(SB)
MOVB AX, v+32(FP)
RET
-same:
+eq:
MOVB $1, v+32(FP)
RET
-different:
+noteq:
MOVB $0, v+32(FP)
RET
@@ -1184,29 +1171,29 @@ TEXT runtime·cmpbytes(SB),NOSPLIT,$0-56
// AX = 1/0/-1
TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
CMPQ SI, DI
- JEQ cmp_allsame
+ JEQ allsame
CMPQ BX, DX
MOVQ DX, BP
CMOVQLT BX, BP // BP = min(alen, blen) = # of bytes to compare
CMPQ BP, $8
- JB cmp_small
+ JB small
-cmp_loop:
+loop:
CMPQ BP, $16
- JBE cmp_0through16
+ JBE _0through16
MOVOU (SI), X0
MOVOU (DI), X1
PCMPEQB X0, X1
PMOVMSKB X1, AX
XORQ $0xffff, AX // convert EQ to NE
- JNE cmp_diff16 // branch if at least one byte is not equal
+ JNE diff16 // branch if at least one byte is not equal
ADDQ $16, SI
ADDQ $16, DI
SUBQ $16, BP
- JMP cmp_loop
+ JMP loop
// AX = bit mask of differences
-cmp_diff16:
+diff16:
BSFQ AX, BX // index of first byte that differs
XORQ AX, AX
MOVB (SI)(BX*1), CX
@@ -1216,21 +1203,21 @@ cmp_diff16:
RET
// 0 through 16 bytes left, alen>=8, blen>=8
-cmp_0through16:
+_0through16:
CMPQ BP, $8
- JBE cmp_0through8
+ JBE _0through8
MOVQ (SI), AX
MOVQ (DI), CX
CMPQ AX, CX
- JNE cmp_diff8
-cmp_0through8:
+ JNE diff8
+_0through8:
MOVQ -8(SI)(BP*1), AX
MOVQ -8(DI)(BP*1), CX
CMPQ AX, CX
- JEQ cmp_allsame
+ JEQ allsame
// AX and CX contain parts of a and b that differ.
-cmp_diff8:
+diff8:
BSWAPQ AX // reverse order of bytes
BSWAPQ CX
XORQ AX, CX
@@ -1241,44 +1228,44 @@ cmp_diff8:
RET
// 0-7 bytes in common
-cmp_small:
+small:
LEAQ (BP*8), CX // bytes left -> bits left
NEGQ CX // - bits lift (== 64 - bits left mod 64)
- JEQ cmp_allsame
+ JEQ allsame
// load bytes of a into high bytes of AX
CMPB SI, $0xf8
- JA cmp_si_high
+ JA si_high
MOVQ (SI), SI
- JMP cmp_si_finish
-cmp_si_high:
+ JMP si_finish
+si_high:
MOVQ -8(SI)(BP*1), SI
SHRQ CX, SI
-cmp_si_finish:
+si_finish:
SHLQ CX, SI
// load bytes of b in to high bytes of BX
CMPB DI, $0xf8
- JA cmp_di_high
+ JA di_high
MOVQ (DI), DI
- JMP cmp_di_finish
-cmp_di_high:
+ JMP di_finish
+di_high:
MOVQ -8(DI)(BP*1), DI
SHRQ CX, DI
-cmp_di_finish:
+di_finish:
SHLQ CX, DI
BSWAPQ SI // reverse order of bytes
BSWAPQ DI
XORQ SI, DI // find bit differences
- JEQ cmp_allsame
+ JEQ allsame
BSRQ DI, CX // index of highest bit difference
SHRQ CX, SI // move a's bit to bottom
ANDQ $1, SI // mask bit
LEAQ -1(SI*2), AX // 1/0 => +1/-1
RET
-cmp_allsame:
+allsame:
XORQ AX, AX
XORQ CX, CX
CMPQ BX, DX
@@ -1313,7 +1300,7 @@ TEXT runtime·indexbytebody(SB),NOSPLIT,$0
MOVQ SI, DI
CMPQ BX, $16
- JLT indexbyte_small
+ JLT small
// round up to first 16-byte boundary
TESTQ $15, SI
@@ -1371,7 +1358,7 @@ failure:
RET
// handle for lengths < 16
-indexbyte_small:
+small:
MOVQ BX, CX
REPN; SCASB
JZ success
@@ -2235,3 +2222,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
TEXT runtime·goexit(SB),NOSPLIT,$0-0
BYTE $0x90 // NOP
CALL runtime·goexit1(SB) // does not return
+
+TEXT runtime·getg(SB),NOSPLIT,$0-8
+ get_tls(CX)
+ MOVQ g(CX), AX
+ MOVQ AX, ret+0(FP)
+ RET
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index a1116b5d4..b8370efd3 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "funcdata.h"
#include "textflag.h"
@@ -164,55 +165,42 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4
JMP AX
RET
-// switchtoM is a dummy routine that onM leaves at the bottom
+// systemstack_switch is a dummy routine that systemstack leaves at the bottom
// of the G stack. We need to distinguish the routine that
// lives at the bottom of the G stack from the one that lives
-// at the top of the M stack because the one at the top of
-// the M stack terminates the stack walk (see topofstack()).
-TEXT runtime·switchtoM(SB), NOSPLIT, $0-0
+// at the top of the system stack because the one at the top of
+// the system stack terminates the stack walk (see topofstack()).
+TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
RET
-// func onM_signalok(fn func())
-TEXT runtime·onM_signalok(SB), NOSPLIT, $0-4
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB), NOSPLIT, $0-4
+ MOVL fn+0(FP), DI // DI = fn
get_tls(CX)
MOVL g(CX), AX // AX = g
MOVL g_m(AX), BX // BX = m
+
MOVL m_gsignal(BX), DX // DX = gsignal
CMPL AX, DX
- JEQ ongsignal
- JMP runtime·onM(SB)
-
-ongsignal:
- MOVL fn+0(FP), DI // DI = fn
- MOVL DI, DX
- MOVL 0(DI), DI
- CALL DI
- RET
-
-// func onM(fn func())
-TEXT runtime·onM(SB), NOSPLIT, $0-4
- MOVL fn+0(FP), DI // DI = fn
- get_tls(CX)
- MOVL g(CX), AX // AX = g
- MOVL g_m(AX), BX // BX = m
+ JEQ noswitch
MOVL m_g0(BX), DX // DX = g0
CMPL AX, DX
- JEQ onm
+ JEQ noswitch
MOVL m_curg(BX), R8
CMPL AX, R8
- JEQ oncurg
+ JEQ switch
// Not g0, not curg. Must be gsignal, but that's not allowed.
// Hide call from linker nosplit analysis.
- MOVL $runtime·badonm(SB), AX
+ MOVL $runtime·badsystemstack(SB), AX
CALL AX
-oncurg:
+switch:
// save our state in g->sched. Pretend to
- // be switchtoM if the G stack is scanned.
- MOVL $runtime·switchtoM(SB), SI
+ // be systemstack_switch if the G stack is scanned.
+ MOVL $runtime·systemstack_switch(SB), SI
MOVL SI, (g_sched+gobuf_pc)(AX)
MOVL SP, (g_sched+gobuf_sp)(AX)
MOVL AX, (g_sched+gobuf_g)(AX)
@@ -236,7 +224,7 @@ oncurg:
MOVL $0, (g_sched+gobuf_sp)(AX)
RET
-onm:
+noswitch:
// already on m stack, just call directly
MOVL DI, DX
MOVL 0(DI), DI
@@ -444,11 +432,11 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-25
MOVQ new+16(FP), CX
LOCK
CMPXCHGQ CX, 0(BX)
- JNZ cas64_fail
+ JNZ fail
MOVL $1, AX
MOVB AX, ret+24(FP)
RET
-cas64_fail:
+fail:
MOVL $0, AX
MOVB AX, ret+24(FP)
RET
@@ -460,7 +448,7 @@ cas64_fail:
// return 1;
// } else
// return 0;
-TEXT runtime·casp(SB), NOSPLIT, $0-17
+TEXT runtime·casp1(SB), NOSPLIT, $0-17
MOVL ptr+0(FP), BX
MOVL old+4(FP), AX
MOVL new+8(FP), CX
@@ -512,7 +500,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24
MOVQ AX, ret+16(FP)
RET
-TEXT runtime·xchgp(SB), NOSPLIT, $0-12
+TEXT runtime·xchgp1(SB), NOSPLIT, $0-12
MOVL ptr+0(FP), BX
MOVL new+4(FP), AX
XCHGL AX, 0(BX)
@@ -530,7 +518,7 @@ again:
JNZ again
RET
-TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
+TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-8
MOVL ptr+0(FP), BX
MOVL val+4(FP), AX
XCHGL AX, 0(BX)
@@ -834,29 +822,29 @@ TEXT runtime·cmpbytes(SB),NOSPLIT,$0-28
// AX = 1/0/-1
TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
CMPQ SI, DI
- JEQ cmp_allsame
+ JEQ allsame
CMPQ BX, DX
MOVQ DX, R8
CMOVQLT BX, R8 // R8 = min(alen, blen) = # of bytes to compare
CMPQ R8, $8
- JB cmp_small
+ JB small
-cmp_loop:
+loop:
CMPQ R8, $16
- JBE cmp_0through16
+ JBE _0through16
MOVOU (SI), X0
MOVOU (DI), X1
PCMPEQB X0, X1
PMOVMSKB X1, AX
XORQ $0xffff, AX // convert EQ to NE
- JNE cmp_diff16 // branch if at least one byte is not equal
+ JNE diff16 // branch if at least one byte is not equal
ADDQ $16, SI
ADDQ $16, DI
SUBQ $16, R8
- JMP cmp_loop
+ JMP loop
// AX = bit mask of differences
-cmp_diff16:
+diff16:
BSFQ AX, BX // index of first byte that differs
XORQ AX, AX
ADDQ BX, SI
@@ -868,23 +856,23 @@ cmp_diff16:
RET
// 0 through 16 bytes left, alen>=8, blen>=8
-cmp_0through16:
+_0through16:
CMPQ R8, $8
- JBE cmp_0through8
+ JBE _0through8
MOVQ (SI), AX
MOVQ (DI), CX
CMPQ AX, CX
- JNE cmp_diff8
-cmp_0through8:
+ JNE diff8
+_0through8:
ADDQ R8, SI
ADDQ R8, DI
MOVQ -8(SI), AX
MOVQ -8(DI), CX
CMPQ AX, CX
- JEQ cmp_allsame
+ JEQ allsame
// AX and CX contain parts of a and b that differ.
-cmp_diff8:
+diff8:
BSWAPQ AX // reverse order of bytes
BSWAPQ CX
XORQ AX, CX
@@ -895,46 +883,46 @@ cmp_diff8:
RET
// 0-7 bytes in common
-cmp_small:
+small:
LEAQ (R8*8), CX // bytes left -> bits left
NEGQ CX // - bits lift (== 64 - bits left mod 64)
- JEQ cmp_allsame
+ JEQ allsame
// load bytes of a into high bytes of AX
CMPB SI, $0xf8
- JA cmp_si_high
+ JA si_high
MOVQ (SI), SI
- JMP cmp_si_finish
-cmp_si_high:
+ JMP si_finish
+si_high:
ADDQ R8, SI
MOVQ -8(SI), SI
SHRQ CX, SI
-cmp_si_finish:
+si_finish:
SHLQ CX, SI
// load bytes of b in to high bytes of BX
CMPB DI, $0xf8
- JA cmp_di_high
+ JA di_high
MOVQ (DI), DI
- JMP cmp_di_finish
-cmp_di_high:
+ JMP di_finish
+di_high:
ADDQ R8, DI
MOVQ -8(DI), DI
SHRQ CX, DI
-cmp_di_finish:
+di_finish:
SHLQ CX, DI
BSWAPQ SI // reverse order of bytes
BSWAPQ DI
XORQ SI, DI // find bit differences
- JEQ cmp_allsame
+ JEQ allsame
BSRQ DI, CX // index of highest bit difference
SHRQ CX, SI // move a's bit to bottom
ANDQ $1, SI // mask bit
LEAQ -1(SI*2), AX // 1/0 => +1/-1
RET
-cmp_allsame:
+allsame:
XORQ AX, AX
XORQ CX, CX
CMPQ BX, DX
@@ -969,7 +957,7 @@ TEXT runtime·indexbytebody(SB),NOSPLIT,$0
MOVL SI, DI
CMPL BX, $16
- JLT indexbyte_small
+ JLT small
// round up to first 16-byte boundary
TESTL $15, SI
@@ -1027,7 +1015,7 @@ failure:
RET
// handle for lengths < 16
-indexbyte_small:
+small:
MOVL BX, CX
REPN; SCASB
JZ success
@@ -1085,3 +1073,9 @@ TEXT runtime·return0(SB), NOSPLIT, $0
TEXT runtime·goexit(SB),NOSPLIT,$0-0
BYTE $0x90 // NOP
CALL runtime·goexit1(SB) // does not return
+
+TEXT runtime·getg(SB),NOSPLIT,$0-4
+ get_tls(CX)
+ MOVL g(CX), AX
+ MOVL AX, ret+0(FP)
+ RET
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index 0f3b5eeb8..583c7ba50 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "funcdata.h"
#include "textflag.h"
@@ -54,7 +55,7 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$-4
nocgo:
// update stackguard after _cgo_init
MOVW (g_stack+stack_lo)(g), R0
- ADD $const_StackGuard, R0
+ ADD $const__StackGuard, R0
MOVW R0, g_stackguard0(g)
MOVW R0, g_stackguard1(g)
@@ -190,53 +191,42 @@ TEXT runtime·mcall(SB),NOSPLIT,$-4-4
B runtime·badmcall2(SB)
RET
-// switchtoM is a dummy routine that onM leaves at the bottom
+// systemstack_switch is a dummy routine that systemstack leaves at the bottom
// of the G stack. We need to distinguish the routine that
// lives at the bottom of the G stack from the one that lives
-// at the top of the M stack because the one at the top of
-// the M stack terminates the stack walk (see topofstack()).
-TEXT runtime·switchtoM(SB),NOSPLIT,$0-0
+// at the top of the system stack because the one at the top of
+// the system stack terminates the stack walk (see topofstack()).
+TEXT runtime·systemstack_switch(SB),NOSPLIT,$0-0
MOVW $0, R0
BL (R0) // clobber lr to ensure push {lr} is kept
RET
-// func onM_signalok(fn func())
-TEXT runtime·onM_signalok(SB), NOSPLIT, $-4-4
- MOVW g_m(g), R1
- MOVW m_gsignal(R1), R2
- CMP g, R2
- B.EQ ongsignal
- B runtime·onM(SB)
-
-ongsignal:
- MOVW fn+0(FP), R0
- MOVW R0, R7
- MOVW 0(R0), R0
- BL (R0)
- RET
-
-// func onM(fn func())
-TEXT runtime·onM(SB),NOSPLIT,$0-4
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB),NOSPLIT,$0-4
MOVW fn+0(FP), R0 // R0 = fn
MOVW g_m(g), R1 // R1 = m
+ MOVW m_gsignal(R1), R2 // R2 = gsignal
+ CMP g, R2
+ B.EQ noswitch
+
MOVW m_g0(R1), R2 // R2 = g0
CMP g, R2
- B.EQ onm
+ B.EQ noswitch
MOVW m_curg(R1), R3
CMP g, R3
- B.EQ oncurg
+ B.EQ switch
- // Not g0, not curg. Must be gsignal, but that's not allowed.
+ // Bad: g is not gsignal, not g0, not curg. What is it?
// Hide call from linker nosplit analysis.
- MOVW $runtime·badonm(SB), R0
+ MOVW $runtime·badsystemstack(SB), R0
BL (R0)
-oncurg:
+switch:
// save our state in g->sched. Pretend to
- // be switchtoM if the G stack is scanned.
- MOVW $runtime·switchtoM(SB), R3
+ // be systemstack_switch if the G stack is scanned.
+ MOVW $runtime·systemstack_switch(SB), R3
ADD $4, R3, R3 // get past push {lr}
MOVW R3, (g_sched+gobuf_pc)(g)
MOVW SP, (g_sched+gobuf_sp)(g)
@@ -249,7 +239,7 @@ oncurg:
BL setg<>(SB)
MOVW R5, R0
MOVW (g_sched+gobuf_sp)(R2), R3
- // make it look like mstart called onM on g0, to stop traceback
+ // make it look like mstart called systemstack on g0, to stop traceback
SUB $4, R3, R3
MOVW $runtime·mstart(SB), R4
MOVW R4, 0(R3)
@@ -269,7 +259,7 @@ oncurg:
MOVW R3, (g_sched+gobuf_sp)(g)
RET
-onm:
+noswitch:
MOVW R0, R7
MOVW 0(R0), R0
BL (R0)
@@ -492,7 +482,7 @@ TEXT asmcgocall<>(SB),NOSPLIT,$0-0
MOVW g_m(g), R8
MOVW m_g0(R8), R3
CMP R3, g
- BEQ asmcgocall_g0
+ BEQ g0
BL gosave<>(SB)
MOVW R0, R5
MOVW R3, R0
@@ -501,7 +491,7 @@ TEXT asmcgocall<>(SB),NOSPLIT,$0-0
MOVW (g_sched+gobuf_sp)(g), R13
// Now on a scheduling stack (a pthread-created stack).
-asmcgocall_g0:
+g0:
SUB $24, R13
BIC $0x7, R13 // alignment for gcc ABI
MOVW R4, 20(R13) // save old g
@@ -564,7 +554,7 @@ TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-12
// the same SP back to m->sched.sp. That seems redundant,
// but if an unrecovered panic happens, unwindm will
// restore the g->sched.sp from the stack location
- // and then onM will try to use it. If we don't set it here,
+ // 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.
MOVW g_m(g), R8
@@ -751,13 +741,13 @@ TEXT runtime·memeq(SB),NOSPLIT,$-4-13
ADD R1, R3, R6
MOVW $1, R0
MOVB R0, ret+12(FP)
-_next2:
+loop:
CMP R1, R6
RET.EQ
MOVBU.P 1(R1), R4
MOVBU.P 1(R2), R5
CMP R4, R5
- BEQ _next2
+ BEQ loop
MOVW $0, R0
MOVB R0, ret+12(FP)
@@ -780,13 +770,13 @@ TEXT runtime·eqstring(SB),NOSPLIT,$-4-17
CMP R2, R3
RET.EQ
ADD R2, R0, R6
-_eqnext:
+loop:
CMP R2, R6
RET.EQ
MOVBU.P 1(R2), R4
MOVBU.P 1(R3), R5
CMP R4, R5
- BEQ _eqnext
+ BEQ loop
MOVB R7, v+16(FP)
RET
@@ -801,26 +791,26 @@ TEXT bytes·Equal(SB),NOSPLIT,$0
MOVW b_len+16(FP), R3
CMP R1, R3 // unequal lengths are not equal
- B.NE _notequal
+ B.NE notequal
MOVW a+0(FP), R0
MOVW b+12(FP), R2
ADD R0, R1 // end
-_byteseq_next:
+loop:
CMP R0, R1
- B.EQ _equal // reached the end
+ B.EQ equal // reached the end
MOVBU.P 1(R0), R4
MOVBU.P 1(R2), R5
CMP R4, R5
- B.EQ _byteseq_next
+ B.EQ loop
-_notequal:
+notequal:
MOVW $0, R0
MOVBU R0, ret+24(FP)
RET
-_equal:
+equal:
MOVW $1, R0
MOVBU R0, ret+24(FP)
RET
@@ -1326,3 +1316,7 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$8
TEXT runtime·goexit(SB),NOSPLIT,$-4-0
MOVW R0, R0 // NOP
BL runtime·goexit1(SB) // does not return
+
+TEXT runtime·getg(SB),NOSPLIT,$-4-4
+ MOVW g, ret+0(FP)
+ RET
diff --git a/src/runtime/asm_power64x.s b/src/runtime/asm_power64x.s
new file mode 100644
index 000000000..3f2ab6d0e
--- /dev/null
+++ b/src/runtime/asm_power64x.s
@@ -0,0 +1,979 @@
+// 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.
+
+// +build power64 power64le
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
+ // initialize essential registers
+ BL runtime·reginit(SB)
+
+ SUB $24, R1
+ MOVW R3, 8(R1) // argc
+ MOVD R4, 16(R1) // argv
+
+ // create istack out of the given (operating system) stack.
+ // _cgo_init may update stackguard.
+ MOVD $runtime·g0(SB), g
+ MOVD $(-64*1024), R31
+ ADD R31, R1, R3
+ MOVD R3, g_stackguard0(g)
+ MOVD R3, g_stackguard1(g)
+ MOVD R3, (g_stack+stack_lo)(g)
+ MOVD R1, (g_stack+stack_hi)(g)
+
+ // TODO: if there is a _cgo_init, call it.
+ // TODO: add TLS
+
+ // set the per-goroutine and per-mach "registers"
+ MOVD $runtime·m0(SB), R3
+
+ // save m->g0 = g0
+ MOVD g, m_g0(R3)
+ // save m0 to g0->m
+ MOVD R3, g_m(g)
+
+ BL runtime·check(SB)
+
+ // args are already prepared
+ BL runtime·args(SB)
+ BL runtime·osinit(SB)
+ BL runtime·schedinit(SB)
+
+ // create a new goroutine to start program
+ MOVD $runtime·main·f(SB), R3 // entry
+ MOVDU R3, -8(R1)
+ MOVDU R0, -8(R1)
+ MOVDU R0, -8(R1)
+ BL runtime·newproc(SB)
+ ADD $24, R1
+
+ // start this M
+ BL runtime·mstart(SB)
+
+ MOVD R0, 1(R0)
+ RETURN
+
+DATA runtime·main·f+0(SB)/8,$runtime·main(SB)
+GLOBL runtime·main·f(SB),RODATA,$8
+
+TEXT runtime·breakpoint(SB),NOSPLIT,$-8-0
+ MOVD R0, 2(R0) // TODO: TD
+ RETURN
+
+TEXT runtime·asminit(SB),NOSPLIT,$-8-0
+ RETURN
+
+TEXT runtime·reginit(SB),NOSPLIT,$-8-0
+ // set R0 to zero, it's expected by the toolchain
+ XOR R0, R0
+ // initialize essential FP registers
+ FMOVD $4503601774854144.0, F27
+ FMOVD $0.5, F29
+ FSUB F29, F29, F28
+ FADD F29, F29, F30
+ FADD F30, F30, F31
+ RETURN
+
+/*
+ * go-routine
+ */
+
+// void gosave(Gobuf*)
+// save state in Gobuf; setjmp
+TEXT runtime·gosave(SB), NOSPLIT, $-8-8
+ MOVD buf+0(FP), R3
+ MOVD R1, gobuf_sp(R3)
+ MOVD LR, R31
+ MOVD R31, gobuf_pc(R3)
+ MOVD g, gobuf_g(R3)
+ MOVD R0, gobuf_lr(R3)
+ MOVD R0, gobuf_ret(R3)
+ MOVD R0, gobuf_ctxt(R3)
+ RETURN
+
+// void gogo(Gobuf*)
+// restore state from Gobuf; longjmp
+TEXT runtime·gogo(SB), NOSPLIT, $-8-8
+ MOVD buf+0(FP), R5
+ MOVD gobuf_g(R5), g // make sure g is not nil
+ MOVD 0(g), R4
+ MOVD gobuf_sp(R5), R1
+ MOVD gobuf_lr(R5), R31
+ MOVD R31, LR
+ MOVD gobuf_ret(R5), R3
+ MOVD gobuf_ctxt(R5), R11
+ MOVD R0, gobuf_sp(R5)
+ MOVD R0, gobuf_ret(R5)
+ MOVD R0, gobuf_lr(R5)
+ MOVD R0, gobuf_ctxt(R5)
+ CMP R0, R0 // set condition codes for == test, needed by stack split
+ MOVD gobuf_pc(R5), R31
+ MOVD R31, CTR
+ BR (CTR)
+
+// void mcall(fn func(*g))
+// Switch to m->g0's stack, call fn(g).
+// Fn must never return. It should gogo(&g->sched)
+// to keep running g.
+TEXT runtime·mcall(SB), NOSPLIT, $-8-8
+ // Save caller state in g->sched
+ MOVD R1, (g_sched+gobuf_sp)(g)
+ MOVD LR, R31
+ MOVD R31, (g_sched+gobuf_pc)(g)
+ MOVD R0, (g_sched+gobuf_lr)(g)
+ MOVD g, (g_sched+gobuf_g)(g)
+
+ // Switch to m->g0 & its stack, call fn.
+ MOVD g, R3
+ MOVD g_m(g), R8
+ MOVD m_g0(R8), g
+ CMP g, R3
+ BNE 2(PC)
+ BR runtime·badmcall(SB)
+ MOVD fn+0(FP), R11 // context
+ MOVD 0(R11), R4 // code pointer
+ MOVD R4, CTR
+ MOVD (g_sched+gobuf_sp)(g), R1 // sp = m->g0->sched.sp
+ MOVDU R3, -8(R1)
+ MOVDU R0, -8(R1)
+ BL (CTR)
+ BR runtime·badmcall2(SB)
+
+// systemstack_switch is a dummy routine that systemstack leaves at the bottom
+// of the G stack. We need to distinguish the routine that
+// lives at the bottom of the G stack from the one that lives
+// at the top of the system stack because the one at the top of
+// the system stack terminates the stack walk (see topofstack()).
+TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
+ UNDEF
+ BL (LR) // make sure this function is not leaf
+ RETURN
+
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB), NOSPLIT, $0-8
+ MOVD fn+0(FP), R3 // R3 = fn
+ MOVD R3, R11 // context
+ MOVD g_m(g), R4 // R4 = m
+
+ MOVD m_gsignal(R4), R5 // R5 = gsignal
+ CMP g, R5
+ BEQ noswitch
+
+ MOVD m_g0(R4), R5 // R5 = g0
+ CMP g, R5
+ BEQ noswitch
+
+ MOVD m_curg(R4), R6
+ CMP g, R6
+ BEQ switch
+
+ // Bad: g is not gsignal, not g0, not curg. What is it?
+ // Hide call from linker nosplit analysis.
+ MOVD $runtime·badsystemstack(SB), R3
+ MOVD R3, CTR
+ BL (CTR)
+
+switch:
+ // save our state in g->sched. Pretend to
+ // be systemstack_switch if the G stack is scanned.
+ MOVD $runtime·systemstack_switch(SB), R6
+ ADD $8, R6 // get past prologue
+ MOVD R6, (g_sched+gobuf_pc)(g)
+ MOVD R1, (g_sched+gobuf_sp)(g)
+ MOVD R0, (g_sched+gobuf_lr)(g)
+ MOVD g, (g_sched+gobuf_g)(g)
+
+ // switch to g0
+ MOVD R5, g
+ MOVD (g_sched+gobuf_sp)(g), R3
+ // make it look like mstart called systemstack on g0, to stop traceback
+ SUB $8, R3
+ MOVD $runtime·mstart(SB), R4
+ MOVD R4, 0(R3)
+ MOVD R3, R1
+
+ // call target function
+ MOVD 0(R11), R3 // code pointer
+ MOVD R3, CTR
+ BL (CTR)
+
+ // switch back to g
+ MOVD g_m(g), R3
+ MOVD m_curg(R3), g
+ MOVD (g_sched+gobuf_sp)(g), R1
+ MOVD R0, (g_sched+gobuf_sp)(g)
+ RETURN
+
+noswitch:
+ // already on m stack, just call directly
+ MOVD 0(R11), R3 // code pointer
+ MOVD R3, CTR
+ BL (CTR)
+ RETURN
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+// Caller has already loaded:
+// R3: framesize, R4: argsize, R5: LR
+//
+// The traceback routines see morestack on a g0 as being
+// the top of a stack (for example, morestack calling newstack
+// calling the scheduler calling newm calling gc), so we must
+// record an argument size. For that purpose, it has no arguments.
+TEXT runtime·morestack(SB),NOSPLIT,$-8-0
+ // Cannot grow scheduler stack (m->g0).
+ MOVD g_m(g), R7
+ MOVD m_g0(R7), R8
+ CMP g, R8
+ BNE 2(PC)
+ BL runtime·abort(SB)
+
+ // Cannot grow signal stack (m->gsignal).
+ MOVD m_gsignal(R7), R8
+ CMP g, R8
+ BNE 2(PC)
+ BL runtime·abort(SB)
+
+ // Called from f.
+ // Set g->sched to context in f.
+ MOVD R11, (g_sched+gobuf_ctxt)(g)
+ MOVD R1, (g_sched+gobuf_sp)(g)
+ MOVD LR, R8
+ MOVD R8, (g_sched+gobuf_pc)(g)
+ MOVD R5, (g_sched+gobuf_lr)(g)
+
+ // Called from f.
+ // Set m->morebuf to f's caller.
+ MOVD R5, (m_morebuf+gobuf_pc)(R7) // f's caller's PC
+ MOVD R1, (m_morebuf+gobuf_sp)(R7) // f's caller's SP
+ MOVD g, (m_morebuf+gobuf_g)(R7)
+
+ // Call newstack on m->g0's stack.
+ MOVD m_g0(R7), g
+ MOVD (g_sched+gobuf_sp)(g), R1
+ BL runtime·newstack(SB)
+
+ // Not reached, but make sure the return PC from the call to newstack
+ // is still in this function, and not the beginning of the next.
+ UNDEF
+
+TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-8-0
+ MOVD R0, R11
+ BR runtime·morestack(SB)
+
+// reflectcall: call a function with the given argument list
+// func call(f *FuncVal, arg *byte, argsize, retoffset uint32).
+// we don't have variable-sized frames, so we use a small number
+// of constant-sized-frame functions to encode a few bits of size in the pc.
+// Caution: ugly multiline assembly macros in your future!
+
+#define DISPATCH(NAME,MAXSIZE) \
+ MOVD $MAXSIZE, R31; \
+ CMP R3, R31; \
+ BGT 4(PC); \
+ MOVD $NAME(SB), R31; \
+ MOVD R31, CTR; \
+ BR (CTR)
+// Note: can't just "BR NAME(SB)" - bad inlining results.
+
+TEXT ·reflectcall(SB), NOSPLIT, $-8-24
+ MOVWZ n+16(FP), R3
+ DISPATCH(runtime·call16, 16)
+ DISPATCH(runtime·call32, 32)
+ DISPATCH(runtime·call64, 64)
+ DISPATCH(runtime·call128, 128)
+ DISPATCH(runtime·call256, 256)
+ DISPATCH(runtime·call512, 512)
+ DISPATCH(runtime·call1024, 1024)
+ DISPATCH(runtime·call2048, 2048)
+ DISPATCH(runtime·call4096, 4096)
+ DISPATCH(runtime·call8192, 8192)
+ DISPATCH(runtime·call16384, 16384)
+ DISPATCH(runtime·call32768, 32768)
+ DISPATCH(runtime·call65536, 65536)
+ DISPATCH(runtime·call131072, 131072)
+ DISPATCH(runtime·call262144, 262144)
+ DISPATCH(runtime·call524288, 524288)
+ DISPATCH(runtime·call1048576, 1048576)
+ DISPATCH(runtime·call2097152, 2097152)
+ DISPATCH(runtime·call4194304, 4194304)
+ DISPATCH(runtime·call8388608, 8388608)
+ DISPATCH(runtime·call16777216, 16777216)
+ DISPATCH(runtime·call33554432, 33554432)
+ DISPATCH(runtime·call67108864, 67108864)
+ DISPATCH(runtime·call134217728, 134217728)
+ DISPATCH(runtime·call268435456, 268435456)
+ DISPATCH(runtime·call536870912, 536870912)
+ DISPATCH(runtime·call1073741824, 1073741824)
+ MOVD $runtime·badreflectcall(SB), R31
+ MOVD R31, CTR
+ BR (CTR)
+
+#define CALLFN(NAME,MAXSIZE) \
+TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \
+ NO_LOCAL_POINTERS; \
+ /* copy arguments to stack */ \
+ MOVD arg+8(FP), R3; \
+ MOVWZ n+16(FP), R4; \
+ MOVD R1, R5; \
+ ADD $(8-1), R5; \
+ SUB $1, R3; \
+ ADD R5, R4; \
+ CMP R5, R4; \
+ BEQ 4(PC); \
+ MOVBZU 1(R3), R6; \
+ MOVBZU R6, 1(R5); \
+ BR -4(PC); \
+ /* call function */ \
+ MOVD f+0(FP), R11; \
+ MOVD (R11), R31; \
+ MOVD R31, CTR; \
+ PCDATA $PCDATA_StackMapIndex, $0; \
+ BL (CTR); \
+ /* copy return values back */ \
+ MOVD arg+8(FP), R3; \
+ MOVWZ n+16(FP), R4; \
+ MOVWZ retoffset+20(FP), R6; \
+ MOVD R1, R5; \
+ ADD R6, R5; \
+ ADD R6, R3; \
+ SUB R6, R4; \
+ ADD $(8-1), R5; \
+ SUB $1, R3; \
+ ADD R5, R4; \
+ CMP R5, R4; \
+ BEQ 4(PC); \
+ MOVBZU 1(R5), R6; \
+ MOVBZU R6, 1(R3); \
+ BR -4(PC); \
+ RETURN
+
+CALLFN(·call16, 16)
+CALLFN(·call32, 32)
+CALLFN(·call64, 64)
+CALLFN(·call128, 128)
+CALLFN(·call256, 256)
+CALLFN(·call512, 512)
+CALLFN(·call1024, 1024)
+CALLFN(·call2048, 2048)
+CALLFN(·call4096, 4096)
+CALLFN(·call8192, 8192)
+CALLFN(·call16384, 16384)
+CALLFN(·call32768, 32768)
+CALLFN(·call65536, 65536)
+CALLFN(·call131072, 131072)
+CALLFN(·call262144, 262144)
+CALLFN(·call524288, 524288)
+CALLFN(·call1048576, 1048576)
+CALLFN(·call2097152, 2097152)
+CALLFN(·call4194304, 4194304)
+CALLFN(·call8388608, 8388608)
+CALLFN(·call16777216, 16777216)
+CALLFN(·call33554432, 33554432)
+CALLFN(·call67108864, 67108864)
+CALLFN(·call134217728, 134217728)
+CALLFN(·call268435456, 268435456)
+CALLFN(·call536870912, 536870912)
+CALLFN(·call1073741824, 1073741824)
+
+// bool cas(uint32 *ptr, uint32 old, uint32 new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// } else
+// return 0;
+TEXT runtime·cas(SB), NOSPLIT, $0-17
+ MOVD ptr+0(FP), R3
+ MOVWZ old+8(FP), R4
+ MOVWZ new+12(FP), R5
+cas_again:
+ SYNC
+ LWAR (R3), R6
+ CMPW R6, R4
+ BNE cas_fail
+ STWCCC R5, (R3)
+ BNE cas_again
+ MOVD $1, R3
+ SYNC
+ ISYNC
+ MOVB R3, ret+16(FP)
+ RETURN
+cas_fail:
+ MOVD $0, R3
+ BR -5(PC)
+
+// bool runtime·cas64(uint64 *ptr, uint64 old, uint64 new)
+// Atomically:
+// if(*val == *old){
+// *val = new;
+// return 1;
+// } else {
+// return 0;
+// }
+TEXT runtime·cas64(SB), NOSPLIT, $0-25
+ MOVD ptr+0(FP), R3
+ MOVD old+8(FP), R4
+ MOVD new+16(FP), R5
+cas64_again:
+ SYNC
+ LDAR (R3), R6
+ CMP R6, R4
+ BNE cas64_fail
+ STDCCC R5, (R3)
+ BNE cas64_again
+ MOVD $1, R3
+ SYNC
+ ISYNC
+ MOVB R3, ret+24(FP)
+ RETURN
+cas64_fail:
+ MOVD $0, R3
+ BR -5(PC)
+
+TEXT runtime·casuintptr(SB), NOSPLIT, $0-25
+ BR runtime·cas64(SB)
+
+TEXT runtime·atomicloaduintptr(SB), NOSPLIT, $-8-16
+ BR runtime·atomicload64(SB)
+
+TEXT runtime·atomicloaduint(SB), NOSPLIT, $-8-16
+ BR runtime·atomicload64(SB)
+
+TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
+ BR runtime·atomicstore64(SB)
+
+// bool casp(void **val, void *old, void *new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// } else
+// return 0;
+TEXT runtime·casp1(SB), NOSPLIT, $0-25
+ BR runtime·cas64(SB)
+
+// uint32 xadd(uint32 volatile *ptr, int32 delta)
+// Atomically:
+// *val += delta;
+// return *val;
+TEXT runtime·xadd(SB), NOSPLIT, $0-20
+ MOVD ptr+0(FP), R4
+ MOVW delta+8(FP), R5
+ SYNC
+ LWAR (R4), R3
+ ADD R5, R3
+ STWCCC R3, (R4)
+ BNE -4(PC)
+ SYNC
+ ISYNC
+ MOVW R3, ret+16(FP)
+ RETURN
+
+TEXT runtime·xadd64(SB), NOSPLIT, $0-24
+ MOVD ptr+0(FP), R4
+ MOVD delta+8(FP), R5
+ SYNC
+ LDAR (R4), R3
+ ADD R5, R3
+ STDCCC R3, (R4)
+ BNE -4(PC)
+ SYNC
+ ISYNC
+ MOVD R3, ret+16(FP)
+ RETURN
+
+TEXT runtime·xchg(SB), NOSPLIT, $0-20
+ MOVD ptr+0(FP), R4
+ MOVW new+8(FP), R5
+ SYNC
+ LWAR (R4), R3
+ STWCCC R5, (R4)
+ BNE -3(PC)
+ SYNC
+ ISYNC
+ MOVW R3, ret+16(FP)
+ RETURN
+
+TEXT runtime·xchg64(SB), NOSPLIT, $0-24
+ MOVD ptr+0(FP), R4
+ MOVD new+8(FP), R5
+ SYNC
+ LDAR (R4), R3
+ STDCCC R5, (R4)
+ BNE -3(PC)
+ SYNC
+ ISYNC
+ MOVD R3, ret+16(FP)
+ RETURN
+
+TEXT runtime·xchgp1(SB), NOSPLIT, $0-24
+ BR runtime·xchg64(SB)
+
+TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24
+ BR runtime·xchg64(SB)
+
+TEXT runtime·procyield(SB),NOSPLIT,$0-0
+ RETURN
+
+TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16
+ BR runtime·atomicstore64(SB)
+
+TEXT runtime·atomicstore(SB), NOSPLIT, $0-12
+ MOVD ptr+0(FP), R3
+ MOVW val+8(FP), R4
+ SYNC
+ MOVW R4, 0(R3)
+ RETURN
+
+TEXT runtime·atomicstore64(SB), NOSPLIT, $0-16
+ MOVD ptr+0(FP), R3
+ MOVD val+8(FP), R4
+ SYNC
+ MOVD R4, 0(R3)
+ RETURN
+
+// void runtime·atomicor8(byte volatile*, byte);
+TEXT runtime·atomicor8(SB), NOSPLIT, $0-9
+ MOVD ptr+0(FP), R3
+ MOVBZ val+8(FP), R4
+ // Align ptr down to 4 bytes so we can use 32-bit load/store.
+ // R5 = (R3 << 0) & ~3
+ RLDCR $0, R3, $~3, R5
+ // Compute val shift.
+#ifdef GOARCH_power64
+ // Big endian. ptr = ptr ^ 3
+ XOR $3, R3
+#endif
+ // R6 = ((ptr & 3) * 8) = (ptr << 3) & (3*8)
+ RLDC $3, R3, $(3*8), R6
+ // Shift val for aligned ptr. R4 = val << R6
+ SLD R6, R4, R4
+
+atomicor8_again:
+ SYNC
+ LWAR (R5), R6
+ OR R4, R6
+ STWCCC R6, (R5)
+ BNE atomicor8_again
+ SYNC
+ ISYNC
+ RETURN
+
+// void jmpdefer(fv, sp);
+// called from deferreturn.
+// 1. grab stored LR for caller
+// 2. sub 4 bytes to get back to BL deferreturn
+// 3. BR to fn
+TEXT runtime·jmpdefer(SB), NOSPLIT, $-8-16
+ MOVD 0(R1), R31
+ SUB $4, R31
+ MOVD R31, LR
+
+ MOVD fv+0(FP), R11
+ MOVD argp+8(FP), R1
+ SUB $8, R1
+ MOVD 0(R11), R3
+ MOVD R3, CTR
+ BR (CTR)
+
+// Save state of caller into g->sched. Smashes R31.
+TEXT gosave<>(SB),NOSPLIT,$-8
+ MOVD LR, R31
+ MOVD R31, (g_sched+gobuf_pc)(g)
+ MOVD R1, (g_sched+gobuf_sp)(g)
+ MOVD R0, (g_sched+gobuf_lr)(g)
+ MOVD R0, (g_sched+gobuf_ret)(g)
+ MOVD R0, (g_sched+gobuf_ctxt)(g)
+ RETURN
+
+// asmcgocall(void(*fn)(void*), void *arg)
+// Call fn(arg) on the scheduler stack,
+// aligned appropriately for the gcc ABI.
+// See cgocall.c for more details.
+TEXT ·asmcgocall(SB),NOSPLIT,$0-16
+ MOVD R0, 21(R0)
+
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// Turn the fn into a Go func (by taking its address) and call
+// cgocallback_gofunc.
+TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
+ MOVD R0, 22(R0)
+
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// See cgocall.c for more details.
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-24
+ MOVD R0, 23(R0)
+
+// void setg(G*); set g. for use by needm.
+TEXT runtime·setg(SB), NOSPLIT, $0-8
+ MOVD R0, 24(R0)
+
+// void setg_gcc(G*); set g called from gcc.
+TEXT setg_gcc<>(SB),NOSPLIT,$0
+ MOVD R0, 25(R0)
+
+TEXT runtime·getcallerpc(SB),NOSPLIT,$-8-16
+ MOVD 0(R1), R3
+ MOVD R3, ret+8(FP)
+ RETURN
+
+TEXT runtime·gogetcallerpc(SB),NOSPLIT,$-8-16
+ MOVD 0(R1), R3
+ MOVD R3,ret+8(FP)
+ RETURN
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$-8-16
+ MOVD pc+8(FP), R3
+ MOVD R3, 0(R1) // set calling pc
+ RETURN
+
+TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
+ MOVD argp+0(FP), R3
+ SUB $8, R3
+ MOVD R3, ret+8(FP)
+ RETURN
+
+// func gogetcallersp(p unsafe.Pointer) uintptr
+TEXT runtime·gogetcallersp(SB),NOSPLIT,$0-16
+ MOVD sp+0(FP), R3
+ SUB $8, R3
+ MOVD R3,ret+8(FP)
+ RETURN
+
+TEXT runtime·abort(SB),NOSPLIT,$-8-0
+ MOVW (R0), R0
+ UNDEF
+
+#define TBRL 268
+#define TBRU 269 /* Time base Upper/Lower */
+
+// int64 runtime·cputicks(void)
+TEXT runtime·cputicks(SB),NOSPLIT,$0-8
+ MOVW SPR(TBRU), R4
+ MOVW SPR(TBRL), R3
+ MOVW SPR(TBRU), R5
+ CMPW R4, R5
+ BNE -4(PC)
+ SLD $32, R5
+ OR R5, R3
+ MOVD R3, ret+0(FP)
+ RETURN
+
+// AES hashing not implemented for Power
+TEXT runtime·aeshash(SB),NOSPLIT,$-8-0
+ MOVW (R0), R1
+TEXT runtime·aeshash32(SB),NOSPLIT,$-8-0
+ MOVW (R0), R1
+TEXT runtime·aeshash64(SB),NOSPLIT,$-8-0
+ MOVW (R0), R1
+TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0
+ MOVW (R0), R1
+
+TEXT runtime·memeq(SB),NOSPLIT,$-8-25
+ MOVD a+0(FP), R3
+ MOVD b+8(FP), R4
+ MOVD size+16(FP), R5
+ SUB $1, R3
+ SUB $1, R4
+ ADD R3, R5, R8
+loop:
+ CMP R3, R8
+ BNE test
+ MOVD $1, R3
+ MOVB R3, ret+24(FP)
+ RETURN
+test:
+ MOVBZU 1(R3), R6
+ MOVBZU 1(R4), R7
+ CMP R6, R7
+ BEQ loop
+
+ MOVB R0, ret+24(FP)
+ RETURN
+
+// eqstring tests whether two strings are equal.
+// See runtime_test.go:eqstring_generic for
+// equivalent Go code.
+TEXT runtime·eqstring(SB),NOSPLIT,$0-33
+ MOVD s1len+8(FP), R4
+ MOVD s2len+24(FP), R5
+ CMP R4, R5
+ BNE noteq
+
+ MOVD s1str+0(FP), R3
+ MOVD s2str+16(FP), R4
+ SUB $1, R3
+ SUB $1, R4
+ ADD R3, R5, R8
+loop:
+ CMP R3, R8
+ BNE 4(PC)
+ MOVD $1, R3
+ MOVB R3, ret+32(FP)
+ RETURN
+ MOVBZU 1(R3), R6
+ MOVBZU 1(R4), R7
+ CMP R6, R7
+ BEQ loop
+noteq:
+ MOVB R0, ret+32(FP)
+ RETURN
+
+// TODO: share code with memeq?
+TEXT bytes·Equal(SB),NOSPLIT,$0-49
+ MOVD a_len+8(FP), R3
+ MOVD b_len+32(FP), R4
+
+ CMP R3, R4 // unequal lengths are not equal
+ BNE noteq
+
+ MOVD a+0(FP), R5
+ MOVD b+24(FP), R6
+ SUB $1, R5
+ SUB $1, R6
+ ADD R5, R3 // end-1
+
+loop:
+ CMP R5, R3
+ BEQ equal // reached the end
+ MOVBZU 1(R5), R4
+ MOVBZU 1(R6), R7
+ CMP R4, R7
+ BEQ loop
+
+noteq:
+ MOVBZ R0, ret+48(FP)
+ RETURN
+
+equal:
+ MOVD $1, R3
+ MOVBZ R3, ret+48(FP)
+ RETURN
+
+TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
+ MOVD s+0(FP), R3
+ MOVD s_len+8(FP), R4
+ MOVBZ c+24(FP), R5 // byte to find
+ MOVD R3, R6 // store base for later
+ SUB $1, R3
+ ADD R3, R4 // end-1
+
+loop:
+ CMP R3, R4
+ BEQ notfound
+ MOVBZU 1(R3), R7
+ CMP R7, R5
+ BNE loop
+
+ SUB R6, R3 // remove base
+ MOVD R3, ret+32(FP)
+ RETURN
+
+notfound:
+ MOVD $-1, R3
+ MOVD R3, ret+32(FP)
+ RETURN
+
+TEXT strings·IndexByte(SB),NOSPLIT,$0
+ MOVD p+0(FP), R3
+ MOVD b_len+8(FP), R4
+ MOVBZ c+16(FP), R5 // byte to find
+ MOVD R3, R6 // store base for later
+ SUB $1, R3
+ ADD R3, R4 // end-1
+
+loop:
+ CMP R3, R4
+ BEQ notfound
+ MOVBZU 1(R3), R7
+ CMP R7, R5
+ BNE loop
+
+ SUB R6, R3 // remove base
+ MOVD R3, ret+24(FP)
+ RETURN
+
+notfound:
+ MOVD $-1, R3
+ MOVD R3, ret+24(FP)
+ RETURN
+
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory. Do not
+// change this code without also changing the code
+// in ../../cmd/9g/ggen.c:/^clearfat.
+// R0: always zero
+// R3 (aka REGRT1): ptr to memory to be zeroed - 8
+// On return, R3 points to the last zeroed dword.
+TEXT runtime·duffzero(SB), NOSPLIT, $-8-0
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ MOVDU R0, 8(R3)
+ RETURN
+
+TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
+ MOVD g_m(g), R4
+ MOVWZ m_fastrand(R4), R3
+ ADD R3, R3
+ CMPW R3, $0
+ BGE 2(PC)
+ XOR $0x88888eef, R3
+ MOVW R3, m_fastrand(R4)
+ MOVW R3, ret+0(FP)
+ RETURN
+
+TEXT runtime·return0(SB), NOSPLIT, $0
+ MOVW $0, R3
+ RETURN
+
+// Called from cgo wrappers, this function returns g->m->curg.stack.hi.
+// Must obey the gcc calling convention.
+TEXT _cgo_topofstack(SB),NOSPLIT,$0
+ MOVD R0, 26(R0)
+
+// The top-most function running on a goroutine
+// returns to goexit+PCQuantum.
+TEXT runtime·goexit(SB),NOSPLIT,$-8-0
+ MOVD R0, R0 // NOP
+ BL runtime·goexit1(SB) // does not return
+
+TEXT runtime·getg(SB),NOSPLIT,$-8-8
+ MOVD g, ret+0(FP)
+ RETURN
diff --git a/src/runtime/atomic_386.c b/src/runtime/atomic_386.c
deleted file mode 100644
index 82d36f2d9..000000000
--- a/src/runtime/atomic_386.c
+++ /dev/null
@@ -1,46 +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.
-
-#include "runtime.h"
-#include "textflag.h"
-
-#pragma textflag NOSPLIT
-uint32
-runtime·atomicload(uint32 volatile* addr)
-{
- return *addr;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·atomicloadp(void* volatile* addr)
-{
- return *addr;
-}
-
-#pragma textflag NOSPLIT
-uint64
-runtime·xadd64(uint64 volatile* addr, int64 v)
-{
- uint64 old;
-
- do
- old = *addr;
- while(!runtime·cas64(addr, old, old+v));
-
- return old+v;
-}
-
-#pragma textflag NOSPLIT
-uint64
-runtime·xchg64(uint64 volatile* addr, uint64 v)
-{
- uint64 old;
-
- do
- old = *addr;
- while(!runtime·cas64(addr, old, v));
-
- return old;
-}
diff --git a/src/runtime/atomic_386.go b/src/runtime/atomic_386.go
new file mode 100644
index 000000000..5563432ef
--- /dev/null
+++ b/src/runtime/atomic_386.go
@@ -0,0 +1,91 @@
+// 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 runtime
+
+import "unsafe"
+
+// The calls to nop are to keep these functions from being inlined.
+// If they are inlined we have no guarantee that later rewrites of the
+// code by optimizers will preserve the relative order of memory accesses.
+
+//go:nosplit
+func atomicload(ptr *uint32) uint32 {
+ nop()
+ return *ptr
+}
+
+//go:nosplit
+func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer {
+ nop()
+ return *(*unsafe.Pointer)(ptr)
+}
+
+//go:nosplit
+func xadd64(ptr *uint64, delta int64) uint64 {
+ for {
+ old := *ptr
+ if cas64(ptr, old, old+uint64(delta)) {
+ return old + uint64(delta)
+ }
+ }
+}
+
+//go:nosplit
+func xchg64(ptr *uint64, new uint64) uint64 {
+ for {
+ old := *ptr
+ if cas64(ptr, old, new) {
+ return old
+ }
+ }
+}
+
+//go:noescape
+func xadd(ptr *uint32, delta int32) uint32
+
+//go:noescape
+func xchg(ptr *uint32, new uint32) uint32
+
+// xchgp cannot have a go:noescape annotation, because
+// while ptr does not escape, new does. If new is marked as
+// not escaping, the compiler will make incorrect escape analysis
+// decisions about the value being xchg'ed.
+// Instead, make xchgp a wrapper around the actual atomic.
+// When calling the wrapper we mark ptr as noescape explicitly.
+
+//go:nosplit
+func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer {
+ return xchgp1(noescape(ptr), new)
+}
+
+func xchgp1(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer
+
+//go:noescape
+func xchguintptr(ptr *uintptr, new uintptr) uintptr
+
+//go:noescape
+func atomicload64(ptr *uint64) uint64
+
+//go:noescape
+func atomicor8(ptr *uint8, val uint8)
+
+//go:noescape
+func cas64(ptr *uint64, old, new uint64) bool
+
+//go:noescape
+func atomicstore(ptr *uint32, val uint32)
+
+//go:noescape
+func atomicstore64(ptr *uint64, val uint64)
+
+// atomicstorep cannot have a go:noescape annotation.
+// See comment above for xchgp.
+
+//go:nosplit
+func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
+ atomicstorep1(noescape(ptr), new)
+}
+
+func atomicstorep1(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/atomic_amd64x.c b/src/runtime/atomic_amd64x.c
deleted file mode 100644
index 7be57ac95..000000000
--- a/src/runtime/atomic_amd64x.c
+++ /dev/null
@@ -1,29 +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.
-
-// +build amd64 amd64p32
-
-#include "runtime.h"
-#include "textflag.h"
-
-#pragma textflag NOSPLIT
-uint32
-runtime·atomicload(uint32 volatile* addr)
-{
- return *addr;
-}
-
-#pragma textflag NOSPLIT
-uint64
-runtime·atomicload64(uint64 volatile* addr)
-{
- return *addr;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·atomicloadp(void* volatile* addr)
-{
- return *addr;
-}
diff --git a/src/runtime/atomic_amd64x.go b/src/runtime/atomic_amd64x.go
new file mode 100644
index 000000000..f2dd58411
--- /dev/null
+++ b/src/runtime/atomic_amd64x.go
@@ -0,0 +1,82 @@
+// 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.
+
+// +build amd64 amd64p32
+
+package runtime
+
+import "unsafe"
+
+// The calls to nop are to keep these functions from being inlined.
+// If they are inlined we have no guarantee that later rewrites of the
+// code by optimizers will preserve the relative order of memory accesses.
+
+//go:nosplit
+func atomicload(ptr *uint32) uint32 {
+ nop()
+ return *ptr
+}
+
+//go:nosplit
+func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer {
+ nop()
+ return *(*unsafe.Pointer)(ptr)
+}
+
+//go:nosplit
+func atomicload64(ptr *uint64) uint64 {
+ nop()
+ return *ptr
+}
+
+//go:noescape
+func xadd(ptr *uint32, delta int32) uint32
+
+//go:noescape
+func xadd64(ptr *uint64, delta int64) uint64
+
+//go:noescape
+func xchg(ptr *uint32, new uint32) uint32
+
+//go:noescape
+func xchg64(ptr *uint64, new uint64) uint64
+
+// xchgp cannot have a go:noescape annotation, because
+// while ptr does not escape, new does. If new is marked as
+// not escaping, the compiler will make incorrect escape analysis
+// decisions about the value being xchg'ed.
+// Instead, make xchgp a wrapper around the actual atomic.
+// When calling the wrapper we mark ptr as noescape explicitly.
+
+//go:nosplit
+func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer {
+ return xchgp1(noescape(ptr), new)
+}
+
+func xchgp1(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer
+
+//go:noescape
+func xchguintptr(ptr *uintptr, new uintptr) uintptr
+
+//go:noescape
+func atomicor8(ptr *uint8, val uint8)
+
+//go:noescape
+func cas64(ptr *uint64, old, new uint64) bool
+
+//go:noescape
+func atomicstore(ptr *uint32, val uint32)
+
+//go:noescape
+func atomicstore64(ptr *uint64, val uint64)
+
+// atomicstorep cannot have a go:noescape annotation.
+// See comment above for xchgp.
+
+//go:nosplit
+func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
+ atomicstorep1(noescape(ptr), new)
+}
+
+func atomicstorep1(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/atomic_arm.go b/src/runtime/atomic_arm.go
index b1632cdd1..fd55a0aca 100644
--- a/src/runtime/atomic_arm.go
+++ b/src/runtime/atomic_arm.go
@@ -85,7 +85,7 @@ func atomicstore(addr *uint32, v uint32) {
//go:nosplit
func cas64(addr *uint64, old, new uint64) bool {
var ok bool
- onM(func() {
+ systemstack(func() {
lock(addrLock(addr))
if *addr == old {
*addr = new
@@ -99,7 +99,7 @@ func cas64(addr *uint64, old, new uint64) bool {
//go:nosplit
func xadd64(addr *uint64, delta int64) uint64 {
var r uint64
- onM(func() {
+ systemstack(func() {
lock(addrLock(addr))
r = *addr + uint64(delta)
*addr = r
@@ -111,7 +111,7 @@ func xadd64(addr *uint64, delta int64) uint64 {
//go:nosplit
func xchg64(addr *uint64, v uint64) uint64 {
var r uint64
- onM(func() {
+ systemstack(func() {
lock(addrLock(addr))
r = *addr
*addr = v
@@ -123,7 +123,7 @@ func xchg64(addr *uint64, v uint64) uint64 {
//go:nosplit
func atomicload64(addr *uint64) uint64 {
var r uint64
- onM(func() {
+ systemstack(func() {
lock(addrLock(addr))
r = *addr
unlock(addrLock(addr))
@@ -133,7 +133,7 @@ func atomicload64(addr *uint64) uint64 {
//go:nosplit
func atomicstore64(addr *uint64, v uint64) {
- onM(func() {
+ systemstack(func() {
lock(addrLock(addr))
*addr = v
unlock(addrLock(addr))
diff --git a/src/runtime/atomic.go b/src/runtime/atomic_power64x.go
index 7e9d9b3aa..a0dcf514b 100644
--- a/src/runtime/atomic.go
+++ b/src/runtime/atomic_power64x.go
@@ -1,8 +1,8 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// 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.
-// +build !arm
+// +build power64 power64le
package runtime
@@ -20,8 +20,19 @@ func xchg(ptr *uint32, new uint32) uint32
//go:noescape
func xchg64(ptr *uint64, new uint64) uint64
-//go:noescape
-func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer
+// xchgp cannot have a go:noescape annotation, because
+// while ptr does not escape, new does. If new is marked as
+// not escaping, the compiler will make incorrect escape analysis
+// decisions about the value being xchg'ed.
+// Instead, make xchgp a wrapper around the actual atomic.
+// When calling the wrapper we mark ptr as noescape explicitly.
+
+//go:nosplit
+func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer {
+ return xchgp1(noescape(ptr), new)
+}
+
+func xchgp1(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer
//go:noescape
func xchguintptr(ptr *uintptr, new uintptr) uintptr
@@ -47,5 +58,12 @@ func atomicstore(ptr *uint32, val uint32)
//go:noescape
func atomicstore64(ptr *uint64, val uint64)
-//go:noescape
-func atomicstorep(ptr unsafe.Pointer, val unsafe.Pointer)
+// atomicstorep cannot have a go:noescape annotation.
+// See comment above for xchgp.
+
+//go:nosplit
+func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
+ atomicstorep1(noescape(ptr), new)
+}
+
+func atomicstorep1(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/atomic_power64x.s b/src/runtime/atomic_power64x.s
new file mode 100644
index 000000000..e72871761
--- /dev/null
+++ b/src/runtime/atomic_power64x.s
@@ -0,0 +1,40 @@
+// 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.
+
+// +build power64 power64le
+
+#include "textflag.h"
+
+// uint32 runtime·atomicload(uint32 volatile* addr)
+TEXT ·atomicload(SB),NOSPLIT,$-8-12
+ MOVD 0(FP), R3
+ SYNC
+ MOVWZ 0(R3), R3
+ CMPW R3, R3, CR7
+ BC 4, 30, 1(PC) // bne- cr7,0x4
+ ISYNC
+ MOVW R3, ret+8(FP)
+ RETURN
+
+// uint64 runtime·atomicload64(uint64 volatile* addr)
+TEXT ·atomicload64(SB),NOSPLIT,$-8-16
+ MOVD 0(FP), R3
+ SYNC
+ MOVD 0(R3), R3
+ CMP R3, R3, CR7
+ BC 4, 30, 1(PC) // bne- cr7,0x4
+ ISYNC
+ MOVD R3, ret+8(FP)
+ RETURN
+
+// void *runtime·atomicloadp(void *volatile *addr)
+TEXT ·atomicloadp(SB),NOSPLIT,$-8-16
+ MOVD 0(FP), R3
+ SYNC
+ MOVD 0(R3), R3
+ CMP R3, R3, CR7
+ BC 4, 30, 1(PC) // bne- cr7,0x4
+ ISYNC
+ MOVD R3, ret+8(FP)
+ RETURN
diff --git a/src/runtime/cgo.go b/src/runtime/cgo.go
new file mode 100644
index 000000000..7e6b253af
--- /dev/null
+++ b/src/runtime/cgo.go
@@ -0,0 +1,23 @@
+// 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 runtime
+
+import "unsafe"
+
+//go:cgo_export_static main
+
+// Filled in by runtime/cgo when linked into binary.
+
+//go:linkname _cgo_init _cgo_init
+//go:linkname _cgo_malloc _cgo_malloc
+//go:linkname _cgo_free _cgo_free
+//go:linkname _cgo_thread_start _cgo_thread_start
+
+var (
+ _cgo_init unsafe.Pointer
+ _cgo_malloc unsafe.Pointer
+ _cgo_free unsafe.Pointer
+ _cgo_thread_start unsafe.Pointer
+)
diff --git a/src/runtime/cgo/callbacks.c b/src/runtime/cgo/callbacks.c
deleted file mode 100644
index 282beeea8..000000000
--- a/src/runtime/cgo/callbacks.c
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2011 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.
-
-#include "../runtime.h"
-#include "../cgocall.h"
-#include "textflag.h"
-
-// These utility functions are available to be called from code
-// compiled with gcc via crosscall2.
-
-// The declaration of crosscall2 is:
-// void crosscall2(void (*fn)(void *, int), void *, int);
-//
-// We need to export the symbol crosscall2 in order to support
-// callbacks from shared libraries. This applies regardless of
-// linking mode.
-#pragma cgo_export_static crosscall2
-#pragma cgo_export_dynamic crosscall2
-
-// Allocate memory. This allocates the requested number of bytes in
-// memory controlled by the Go runtime. The allocated memory will be
-// zeroed. You are responsible for ensuring that the Go garbage
-// collector can see a pointer to the allocated memory for as long as
-// it is valid, e.g., by storing a pointer in a local variable in your
-// C function, or in memory allocated by the Go runtime. If the only
-// pointers are in a C global variable or in memory allocated via
-// malloc, then the Go garbage collector may collect the memory.
-
-// Call like this in code compiled with gcc:
-// struct { size_t len; void *ret; } a;
-// a.len = /* number of bytes to allocate */;
-// crosscall2(_cgo_allocate, &a, sizeof a);
-// /* Here a.ret is a pointer to the allocated memory. */
-
-void runtime·_cgo_allocate_internal(void);
-
-#pragma cgo_export_static _cgo_allocate
-#pragma cgo_export_dynamic _cgo_allocate
-#pragma textflag NOSPLIT
-void
-_cgo_allocate(void *a, int32 n)
-{
- runtime·cgocallback((void(*)(void))runtime·_cgo_allocate_internal, a, n);
-}
-
-// Panic. The argument is converted into a Go string.
-
-// Call like this in code compiled with gcc:
-// struct { const char *p; } a;
-// a.p = /* string to pass to panic */;
-// crosscall2(_cgo_panic, &a, sizeof a);
-// /* The function call will not return. */
-
-void runtime·_cgo_panic_internal(void);
-
-#pragma cgo_export_static _cgo_panic
-#pragma cgo_export_dynamic _cgo_panic
-#pragma textflag NOSPLIT
-void
-_cgo_panic(void *a, int32 n)
-{
- runtime·cgocallback((void(*)(void))runtime·_cgo_panic_internal, a, n);
-}
-
-#pragma cgo_import_static x_cgo_init
-extern void x_cgo_init(G*);
-void (*_cgo_init)(G*) = x_cgo_init;
-
-#pragma cgo_import_static x_cgo_malloc
-extern void x_cgo_malloc(void*);
-void (*_cgo_malloc)(void*) = x_cgo_malloc;
-
-#pragma cgo_import_static x_cgo_free
-extern void x_cgo_free(void*);
-void (*_cgo_free)(void*) = x_cgo_free;
-
-#pragma cgo_import_static x_cgo_thread_start
-extern void x_cgo_thread_start(void*);
-void (*_cgo_thread_start)(void*) = x_cgo_thread_start;
-
-#pragma cgo_export_static _cgo_topofstack
-#pragma cgo_export_dynamic _cgo_topofstack
diff --git a/src/runtime/cgo/callbacks.go b/src/runtime/cgo/callbacks.go
new file mode 100644
index 000000000..1e8b59054
--- /dev/null
+++ b/src/runtime/cgo/callbacks.go
@@ -0,0 +1,95 @@
+// Copyright 2011 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 cgo
+
+import "unsafe"
+
+// These utility functions are available to be called from code
+// compiled with gcc via crosscall2.
+
+// cgocallback is defined in runtime
+//go:linkname _runtime_cgocallback runtime.cgocallback
+func _runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
+
+// The declaration of crosscall2 is:
+// void crosscall2(void (*fn)(void *, int), void *, int);
+//
+// We need to export the symbol crosscall2 in order to support
+// callbacks from shared libraries. This applies regardless of
+// linking mode.
+//go:cgo_export_static crosscall2
+//go:cgo_export_dynamic crosscall2
+
+// Allocate memory. This allocates the requested number of bytes in
+// memory controlled by the Go runtime. The allocated memory will be
+// zeroed. You are responsible for ensuring that the Go garbage
+// collector can see a pointer to the allocated memory for as long as
+// it is valid, e.g., by storing a pointer in a local variable in your
+// C function, or in memory allocated by the Go runtime. If the only
+// pointers are in a C global variable or in memory allocated via
+// malloc, then the Go garbage collector may collect the memory.
+
+// Call like this in code compiled with gcc:
+// struct { size_t len; void *ret; } a;
+// a.len = /* number of bytes to allocate */;
+// crosscall2(_cgo_allocate, &a, sizeof a);
+// /* Here a.ret is a pointer to the allocated memory. */
+
+//go:linkname _runtime_cgo_allocate_internal runtime._cgo_allocate_internal
+var _runtime_cgo_allocate_internal byte
+
+//go:linkname _cgo_allocate _cgo_allocate
+//go:cgo_export_static _cgo_allocate
+//go:cgo_export_dynamic _cgo_allocate
+//go:nosplit
+func _cgo_allocate(a unsafe.Pointer, n int32) {
+ _runtime_cgocallback(unsafe.Pointer(&_runtime_cgo_allocate_internal), a, uintptr(n))
+}
+
+// Panic. The argument is converted into a Go string.
+
+// Call like this in code compiled with gcc:
+// struct { const char *p; } a;
+// a.p = /* string to pass to panic */;
+// crosscall2(_cgo_panic, &a, sizeof a);
+// /* The function call will not return. */
+
+//go:linkname _runtime_cgo_panic_internal runtime._cgo_panic_internal
+var _runtime_cgo_panic_internal byte
+
+//go:linkname _cgo_panic _cgo_panic
+//go:cgo_export_static _cgo_panic
+//go:cgo_export_dynamic _cgo_panic
+//go:nosplit
+func _cgo_panic(a unsafe.Pointer, n int32) {
+ _runtime_cgocallback(unsafe.Pointer(&_runtime_cgo_panic_internal), a, uintptr(n))
+}
+
+//go:cgo_import_static x_cgo_init
+//go:linkname x_cgo_init x_cgo_init
+//go:linkname _cgo_init _cgo_init
+var x_cgo_init byte
+var _cgo_init = &x_cgo_init
+
+//go:cgo_import_static x_cgo_malloc
+//go:linkname x_cgo_malloc x_cgo_malloc
+//go:linkname _cgo_malloc _cgo_malloc
+var x_cgo_malloc byte
+var _cgo_malloc = &x_cgo_malloc
+
+//go:cgo_import_static x_cgo_free
+//go:linkname x_cgo_free x_cgo_free
+//go:linkname _cgo_free _cgo_free
+var x_cgo_free byte
+var _cgo_free = &x_cgo_free
+
+//go:cgo_import_static x_cgo_thread_start
+//go:linkname x_cgo_thread_start x_cgo_thread_start
+//go:linkname _cgo_thread_start _cgo_thread_start
+var x_cgo_thread_start byte
+var _cgo_thread_start = &x_cgo_thread_start
+
+//go:cgo_export_static _cgo_topofstack
+//go:cgo_export_dynamic _cgo_topofstack
diff --git a/src/runtime/cgo/dragonfly.c b/src/runtime/cgo/dragonfly.go
index c233c8ba9..69d52b5b2 100644
--- a/src/runtime/cgo/dragonfly.c
+++ b/src/runtime/cgo/dragonfly.go
@@ -4,16 +4,16 @@
// +build dragonfly
-#include "textflag.h"
+package cgo
+
+import _ "unsafe" // for go:linkname
// Supply environ and __progname, because we don't
// link against the standard DragonFly crt0.o and the
// libc dynamic library needs them.
-#pragma dataflag NOPTR
-char *environ[1];
-#pragma dataflag NOPTR
-char *__progname;
+//go:linkname _environ environ
+//go:linkname _progname __progname
-#pragma dynexport environ environ
-#pragma dynexport __progname __progname
+var _environ uintptr
+var _progname uintptr
diff --git a/src/runtime/cgo/freebsd.c b/src/runtime/cgo/freebsd.go
index 4876b2abe..99cf3fbca 100644
--- a/src/runtime/cgo/freebsd.c
+++ b/src/runtime/cgo/freebsd.go
@@ -4,16 +4,19 @@
// +build freebsd
-#include "textflag.h"
+package cgo
+
+import _ "unsafe" // for go:linkname
// Supply environ and __progname, because we don't
// link against the standard FreeBSD crt0.o and the
// libc dynamic library needs them.
-#pragma dataflag NOPTR
-char *environ[1];
-#pragma dataflag NOPTR
-char *__progname;
+//go:linkname _environ environ
+//go:linkname _progname __progname
+
+//go:cgo_export_dynamic environ
+//go:cgo_export_dynamic __progname
-#pragma dynexport environ environ
-#pragma dynexport __progname __progname
+var _environ uintptr
+var _progname uintptr
diff --git a/src/runtime/cgo/iscgo.c b/src/runtime/cgo/iscgo.go
index 0907a1958..61cba73d2 100644
--- a/src/runtime/cgo/iscgo.c
+++ b/src/runtime/cgo/iscgo.go
@@ -9,7 +9,12 @@
// correctly, and sometimes they break. This variable is a
// backup: it depends only on old C style static linking rules.
-#include "../runtime.h"
+package cgo
-bool runtime·iscgo = 1;
-uint32 runtime·needextram = 1; // create an extra M on first cgo call
+import _ "unsafe" // for go:linkname
+
+//go:linkname _iscgo runtime.iscgo
+var _iscgo bool = true
+
+//go:linkname _needextram runtime.needextram
+var _needextram uint32 = 1 // create an extra M on first cgo call
diff --git a/src/runtime/cgo/netbsd.c b/src/runtime/cgo/netbsd.go
index 076cc87f1..ac6b18a93 100644
--- a/src/runtime/cgo/netbsd.c
+++ b/src/runtime/cgo/netbsd.go
@@ -4,16 +4,16 @@
// +build netbsd
-#include "textflag.h"
+package cgo
+
+import _ "unsafe" // for go:linkname
// Supply environ and __progname, because we don't
// link against the standard NetBSD crt0.o and the
// libc dynamic library needs them.
-#pragma dataflag NOPTR
-char *environ[1];
-#pragma dataflag NOPTR
-char *__progname;
+//go:linkname _environ environ
+//go:linkname _progname __progname
-#pragma dynexport environ environ
-#pragma dynexport __progname __progname
+var _environ uintptr
+var _progname uintptr
diff --git a/src/runtime/cgo/openbsd.c b/src/runtime/cgo/openbsd.go
index 476649544..61af3a8e7 100644
--- a/src/runtime/cgo/openbsd.c
+++ b/src/runtime/cgo/openbsd.go
@@ -4,24 +4,28 @@
// +build openbsd
-#include "textflag.h"
+package cgo
+
+import _ "unsafe" // for go:linkname
// Supply environ, __progname and __guard_local, because
// we don't link against the standard OpenBSD crt0.o and
// the libc dynamic library needs them.
-#pragma dataflag NOPTR
-char *environ[1];
-#pragma dataflag NOPTR
-char *__progname;
-long __guard_local;
+//go:linkname _environ environ
+//go:linkname _progname __progname
+//go:linkname _guard_local __guard_local
+
+var _environ uintptr
+var _progname uintptr
+var _guard_local uintptr
-#pragma dynexport environ environ
-#pragma dynexport __progname __progname
+//go:cgo_export_dynamic environ environ
+//go:cgo_export_dynamic __progname __progname
// This is normally marked as hidden and placed in the
// .openbsd.randomdata section.
-#pragma dynexport __guard_local __guard_local
+//go:cgo_export_dynamic __guard_local __guard_local
// We override pthread_create to support PT_TLS.
-#pragma dynexport pthread_create pthread_create
+//go:cgo_export_dynamic pthread_create pthread_create
diff --git a/src/runtime/cgo/setenv.c b/src/runtime/cgo/setenv.c
deleted file mode 100644
index 76d88cbf1..000000000
--- a/src/runtime/cgo/setenv.c
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2011 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.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd
-
-#pragma cgo_import_static x_cgo_setenv
-#pragma cgo_import_static x_cgo_unsetenv
-
-void x_cgo_setenv(char**);
-void (*runtime·_cgo_setenv)(char**) = x_cgo_setenv;
-void x_cgo_unsetenv(char**);
-void (*runtime·_cgo_unsetenv)(char**) = x_cgo_unsetenv;
diff --git a/src/runtime/cgo/setenv.go b/src/runtime/cgo/setenv.go
new file mode 100644
index 000000000..97c8c6ac9
--- /dev/null
+++ b/src/runtime/cgo/setenv.go
@@ -0,0 +1,21 @@
+// Copyright 2011 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+//go:cgo_import_static x_cgo_setenv
+//go:linkname x_cgo_setenv x_cgo_setenv
+//go:linkname _cgo_setenv runtime._cgo_setenv
+var x_cgo_setenv byte
+var _cgo_setenv = &x_cgo_setenv
+
+//go:cgo_import_static x_cgo_unsetenv
+//go:linkname x_cgo_unsetenv x_cgo_unsetenv
+//go:linkname _cgo_unsetenv runtime._cgo_unsetenv
+var x_cgo_unsetenv byte
+var _cgo_unsetenv = &x_cgo_unsetenv
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index 7fd91469e..258cabfc8 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -103,7 +103,7 @@ func cgocall_errno(fn, arg unsafe.Pointer) int32 {
// Create an extra M for callbacks on threads not created by Go on first cgo call.
if needextram == 1 && cas(&needextram, 1, 0) {
- onM(newextram)
+ systemstack(newextram)
}
/*
@@ -127,9 +127,9 @@ func cgocall_errno(fn, arg unsafe.Pointer) int32 {
* so it is safe to call while "in a system call", outside
* the $GOMAXPROCS accounting.
*/
- entersyscall()
+ entersyscall(0)
errno := asmcgocall_errno(fn, arg)
- exitsyscall()
+ exitsyscall(0)
return errno
}
@@ -153,17 +153,13 @@ func endcgo(mp *m) {
// Helper functions for cgo code.
-// Filled by schedinit from corresponding C variables,
-// which are in turn filled in by dynamic linker when Cgo is available.
-var cgoMalloc, cgoFree unsafe.Pointer
-
func cmalloc(n uintptr) unsafe.Pointer {
var args struct {
n uint64
ret unsafe.Pointer
}
args.n = uint64(n)
- cgocall(cgoMalloc, unsafe.Pointer(&args))
+ cgocall(_cgo_malloc, unsafe.Pointer(&args))
if args.ret == nil {
gothrow("C malloc failed")
}
@@ -171,7 +167,7 @@ func cmalloc(n uintptr) unsafe.Pointer {
}
func cfree(p unsafe.Pointer) {
- cgocall(cgoFree, p)
+ cgocall(_cgo_free, p)
}
// Call from C back to Go.
@@ -189,17 +185,17 @@ func cgocallbackg() {
// save syscall* and let reentersyscall restore them.
savedsp := unsafe.Pointer(gp.syscallsp)
savedpc := gp.syscallpc
- exitsyscall() // coming out of cgo call
+ exitsyscall(0) // coming out of cgo call
cgocallbackg1()
// going back to cgo call
- reentersyscall(savedpc, savedsp)
+ reentersyscall(savedpc, uintptr(savedsp))
}
func cgocallbackg1() {
gp := getg()
if gp.m.needextram {
gp.m.needextram = false
- onM(newextram)
+ systemstack(newextram)
}
// Add entry to defer stack in case of panic.
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index 0eb87df74..330422ad0 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -26,7 +26,7 @@ func makechan(t *chantype, size int64) *hchan {
if hchanSize%maxAlign != 0 || elem.align > maxAlign {
gothrow("makechan: bad alignment")
}
- if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (maxmem-hchanSize)/uintptr(elem.size)) {
+ if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/uintptr(elem.size)) {
panic("makechan: size out of range")
}
diff --git a/src/runtime/chan.h b/src/runtime/chan.h
deleted file mode 100644
index c34ff1533..000000000
--- a/src/runtime/chan.h
+++ /dev/null
@@ -1,68 +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.
-
-#define MAXALIGN 8
-
-typedef struct WaitQ WaitQ;
-typedef struct Select Select;
-typedef struct Scase Scase;
-
-struct WaitQ
-{
- SudoG* first;
- SudoG* last;
-};
-
-struct Hchan
-{
- uintgo qcount; // total data in the q
- uintgo dataqsiz; // size of the circular q
- byte* buf;
- uint16 elemsize;
- uint32 closed;
- Type* elemtype; // element type
- uintgo sendx; // send index
- uintgo recvx; // receive index
- WaitQ recvq; // list of recv waiters
- WaitQ sendq; // list of send waiters
- Mutex lock;
-};
-
-// Buffer follows Hchan immediately in memory.
-// chanbuf(c, i) is pointer to the i'th slot in the buffer.
-#define chanbuf(c, i) ((byte*)((c)->buf)+(uintptr)(c)->elemsize*(i))
-
-enum
-{
- debug = 0,
-
- // Scase.kind
- CaseRecv,
- CaseSend,
- CaseDefault,
-};
-
-// Known to compiler.
-// Changes here must also be made in src/cmd/gc/select.c's selecttype.
-struct Scase
-{
- void* elem; // data element
- Hchan* chan; // chan
- uintptr pc; // return pc
- uint16 kind;
- uint16 so; // vararg of selected bool
- bool* receivedp; // pointer to received bool (recv2)
- int64 releasetime;
-};
-
-// Known to compiler.
-// Changes here must also be made in src/cmd/gc/select.c's selecttype.
-struct Select
-{
- uint16 tcase; // total count of scase[]
- uint16 ncase; // currently filled scase[]
- uint16* pollorder; // case poll order
- Hchan** lockorder; // channel lock order
- Scase scase[1]; // one per case (in order of appearance)
-};
diff --git a/src/runtime/chan1.go b/src/runtime/chan1.go
new file mode 100644
index 000000000..000775b1e
--- /dev/null
+++ b/src/runtime/chan1.go
@@ -0,0 +1,61 @@
+// 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 runtime
+
+import "unsafe"
+
+//#define MAXALIGN 8
+
+type waitq struct {
+ first *sudog
+ last *sudog
+}
+
+type hchan struct {
+ qcount uint // total data in the q
+ dataqsiz uint // size of the circular q
+ buf *byte
+ elemsize uint16
+ closed uint32
+ elemtype *_type // element type
+ sendx uint // send index
+ recvx uint // receive index
+ recvq waitq // list of recv waiters
+ sendq waitq // list of send waiters
+ lock mutex
+}
+
+// Buffer follows Hchan immediately in memory.
+// chanbuf(c, i) is pointer to the i'th slot in the buffer.
+// #define chanbuf(c, i) ((byte*)((c)->buf)+(uintptr)(c)->elemsize*(i))
+
+const (
+ // scase.kind
+ _CaseRecv = iota
+ _CaseSend
+ _CaseDefault
+)
+
+// Known to compiler.
+// Changes here must also be made in src/cmd/gc/select.c's selecttype.
+type scase struct {
+ elem unsafe.Pointer // data element
+ _chan *hchan // chan
+ pc uintptr // return pc
+ kind uint16
+ so uint16 // vararg of selected bool
+ receivedp *bool // pointer to received bool (recv2)
+ releasetime int64
+}
+
+// Known to compiler.
+// Changes here must also be made in src/cmd/gc/select.c's selecttype.
+type _select struct {
+ tcase uint16 // total count of scase[]
+ ncase uint16 // currently filled scase[]
+ pollorder *uint16 // case poll order
+ lockorder **hchan // channel lock order
+ scase [1]scase // one per case (in order of appearance)
+}
diff --git a/src/runtime/complex.go b/src/runtime/complex.go
index ec50f8947..73f1161a5 100644
--- a/src/runtime/complex.go
+++ b/src/runtime/complex.go
@@ -4,28 +4,47 @@
package runtime
+func isposinf(f float64) bool { return f > maxFloat64 }
+func isneginf(f float64) bool { return f < -maxFloat64 }
+func isnan(f float64) bool { return f != f }
+
+func nan() float64 {
+ var f float64 = 0
+ return f / f
+}
+
+func posinf() float64 {
+ var f float64 = maxFloat64
+ return f * f
+}
+
+func neginf() float64 {
+ var f float64 = maxFloat64
+ return -f * f
+}
+
func complex128div(n complex128, d complex128) complex128 {
// Special cases as in C99.
- ninf := real(n) == posinf || real(n) == neginf ||
- imag(n) == posinf || imag(n) == neginf
- dinf := real(d) == posinf || real(d) == neginf ||
- imag(d) == posinf || imag(d) == neginf
+ ninf := isposinf(real(n)) || isneginf(real(n)) ||
+ isposinf(imag(n)) || isneginf(imag(n))
+ dinf := isposinf(real(d)) || isneginf(real(d)) ||
+ isposinf(imag(d)) || isneginf(imag(d))
- nnan := !ninf && (real(n) != real(n) || imag(n) != imag(n))
- dnan := !dinf && (real(d) != real(d) || imag(d) != imag(d))
+ nnan := !ninf && (isnan(real(n)) || isnan(imag(n)))
+ dnan := !dinf && (isnan(real(d)) || isnan(imag(d)))
switch {
case nnan || dnan:
- return complex(nan, nan)
+ return complex(nan(), nan())
case ninf && !dinf:
- return complex(posinf, posinf)
+ return complex(posinf(), posinf())
case !ninf && dinf:
return complex(0, 0)
case real(d) == 0 && imag(d) == 0:
if real(n) == 0 && imag(n) == 0 {
- return complex(nan, nan)
+ return complex(nan(), nan())
} else {
- return complex(posinf, posinf)
+ return complex(posinf(), posinf())
}
default:
// Standard complex arithmetic, factored to avoid unnecessary overflow.
diff --git a/src/runtime/cpuprof.go b/src/runtime/cpuprof.go
index 8b1c1c632..d56678e21 100644
--- a/src/runtime/cpuprof.go
+++ b/src/runtime/cpuprof.go
@@ -101,12 +101,10 @@ var (
eod = [3]uintptr{0, 1, 0}
)
-func setcpuprofilerate_m() // proc.c
-
func setcpuprofilerate(hz int32) {
- g := getg()
- g.m.scalararg[0] = uintptr(hz)
- onM(setcpuprofilerate_m)
+ systemstack(func() {
+ setcpuprofilerate_m(hz)
+ })
}
// lostProfileData is a no-op function used in profiles
diff --git a/src/runtime/cputicks.go b/src/runtime/cputicks.go
new file mode 100644
index 000000000..e0593d56e
--- /dev/null
+++ b/src/runtime/cputicks.go
@@ -0,0 +1,11 @@
+// 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.
+
+// +build !arm
+
+package runtime
+
+// careful: cputicks is not guaranteed to be monotonic! In particular, we have
+// noticed drift between cpus on certain os/arch combinations. See issue 8976.
+func cputicks() int64
diff --git a/src/runtime/debug.go b/src/runtime/debug.go
index 4414dd55d..105b79cfe 100644
--- a/src/runtime/debug.go
+++ b/src/runtime/debug.go
@@ -6,18 +6,6 @@ package runtime
import "unsafe"
-// Breakpoint executes a breakpoint trap.
-func Breakpoint()
-
-// LockOSThread wires the calling goroutine to its current operating system thread.
-// Until the calling goroutine exits or calls UnlockOSThread, it will always
-// execute in that thread, and no other goroutine can.
-func LockOSThread()
-
-// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
-// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
-func UnlockOSThread()
-
// GOMAXPROCS sets the maximum number of CPUs that can be executing
// simultaneously and returns the previous setting. If n < 1, it does not
// change the current setting.
@@ -37,14 +25,14 @@ func GOMAXPROCS(n int) int {
semacquire(&worldsema, false)
gp := getg()
gp.m.gcing = 1
- onM(stoptheworld)
+ systemstack(stoptheworld)
// newprocs will be processed by starttheworld
newprocs = int32(n)
gp.m.gcing = 0
semrelease(&worldsema)
- onM(starttheworld)
+ systemstack(starttheworld)
return ret
}
@@ -66,5 +54,3 @@ func NumCgoCall() int64 {
func NumGoroutine() int {
return int(gcount())
}
-
-func gcount() int32
diff --git a/src/runtime/debug/stubs.s b/src/runtime/debug/stubs.s
index d56274f2d..1e883b72c 100644
--- a/src/runtime/debug/stubs.s
+++ b/src/runtime/debug/stubs.s
@@ -7,6 +7,12 @@
#ifdef GOARCH_arm
#define JMP B
#endif
+#ifdef GOARCH_power64
+#define JMP BR
+#endif
+#ifdef GOARCH_power64le
+#define JMP BR
+#endif
TEXT ·setMaxStack(SB),NOSPLIT,$0-0
JMP runtime·setMaxStack(SB)
diff --git a/src/runtime/defs.c b/src/runtime/defs.c
deleted file mode 100644
index b0a9b20d7..000000000
--- a/src/runtime/defs.c
+++ /dev/null
@@ -1,15 +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.
-
-// This file is compiled by cmd/dist to obtain debug information
-// about the given header files.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "type.h"
-#include "race.h"
-#include "chan.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
diff --git a/src/runtime/defs1_linux.go b/src/runtime/defs1_linux.go
index 392cc4ab5..87c6e02a4 100644
--- a/src/runtime/defs1_linux.go
+++ b/src/runtime/defs1_linux.go
@@ -15,12 +15,14 @@ package runtime
/*
#include <ucontext.h>
#include <fcntl.h>
+#include <asm/signal.h>
*/
import "C"
const (
- O_RDONLY = C.O_RDONLY
- O_CLOEXEC = C.O_CLOEXEC
+ O_RDONLY = C.O_RDONLY
+ O_CLOEXEC = C.O_CLOEXEC
+ SA_RESTORER = C.SA_RESTORER
)
type Usigset C.__sigset_t
diff --git a/src/runtime/defs1_netbsd_386.go b/src/runtime/defs1_netbsd_386.go
new file mode 100644
index 000000000..f222bed99
--- /dev/null
+++ b/src/runtime/defs1_netbsd_386.go
@@ -0,0 +1,183 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_386.go
+
+package runtime
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x6
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_RECEIPT = 0
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = 0x0
+ _EVFILT_WRITE = 0x1
+)
+
+type sigaltstackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+}
+
+type sigset struct {
+ __bits [4]uint32
+}
+
+type siginfo struct {
+ _signo int32
+ _code int32
+ _errno int32
+ _reason [20]byte
+}
+
+type stackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int32
+}
+
+func (ts *timespec) set_sec(x int32) {
+ ts.tv_sec = int64(x)
+}
+
+func (ts *timespec) set_nsec(x int32) {
+ ts.tv_nsec = x
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int32
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type mcontextt struct {
+ __gregs [19]uint32
+ __fpregs [644]byte
+ _mc_tlsbase int32
+}
+
+type ucontextt struct {
+ uc_flags uint32
+ uc_link *ucontextt
+ uc_sigmask sigset
+ uc_stack stackt
+ uc_mcontext mcontextt
+ __uc_pad [4]int32
+}
+
+type keventt struct {
+ ident uint32
+ filter uint32
+ flags uint32
+ fflags uint32
+ data int64
+ udata *byte
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_386.go
+
+const (
+ _REG_GS = 0x0
+ _REG_FS = 0x1
+ _REG_ES = 0x2
+ _REG_DS = 0x3
+ _REG_EDI = 0x4
+ _REG_ESI = 0x5
+ _REG_EBP = 0x6
+ _REG_ESP = 0x7
+ _REG_EBX = 0x8
+ _REG_EDX = 0x9
+ _REG_ECX = 0xa
+ _REG_EAX = 0xb
+ _REG_TRAPNO = 0xc
+ _REG_ERR = 0xd
+ _REG_EIP = 0xe
+ _REG_CS = 0xf
+ _REG_EFL = 0x10
+ _REG_UESP = 0x11
+ _REG_SS = 0x12
+)
diff --git a/src/runtime/defs1_netbsd_amd64.go b/src/runtime/defs1_netbsd_amd64.go
new file mode 100644
index 000000000..c2bde4dab
--- /dev/null
+++ b/src/runtime/defs1_netbsd_amd64.go
@@ -0,0 +1,195 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go
+
+package runtime
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x6
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_RECEIPT = 0
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = 0x0
+ _EVFILT_WRITE = 0x1
+)
+
+type sigaltstackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type sigset struct {
+ __bits [4]uint32
+}
+
+type siginfo struct {
+ _signo int32
+ _code int32
+ _errno int32
+ _pad int32
+ _reason [24]byte
+}
+
+type stackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int32) {
+ ts.tv_sec = int64(x)
+}
+
+func (ts *timespec) set_nsec(x int32) {
+ ts.tv_nsec = int64(x)
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int32
+ pad_cgo_0 [4]byte
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type mcontextt struct {
+ __gregs [26]uint64
+ _mc_tlsbase uint64
+ __fpregs [512]int8
+}
+
+type ucontextt struct {
+ uc_flags uint32
+ pad_cgo_0 [4]byte
+ uc_link *ucontextt
+ uc_sigmask sigset
+ uc_stack stackt
+ uc_mcontext mcontextt
+}
+
+type keventt struct {
+ ident uint64
+ filter uint32
+ flags uint32
+ fflags uint32
+ pad_cgo_0 [4]byte
+ data int64
+ udata *byte
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go
+
+const (
+ _REG_RDI = 0x0
+ _REG_RSI = 0x1
+ _REG_RDX = 0x2
+ _REG_RCX = 0x3
+ _REG_R8 = 0x4
+ _REG_R9 = 0x5
+ _REG_R10 = 0x6
+ _REG_R11 = 0x7
+ _REG_R12 = 0x8
+ _REG_R13 = 0x9
+ _REG_R14 = 0xa
+ _REG_R15 = 0xb
+ _REG_RBP = 0xc
+ _REG_RBX = 0xd
+ _REG_RAX = 0xe
+ _REG_GS = 0xf
+ _REG_FS = 0x10
+ _REG_ES = 0x11
+ _REG_DS = 0x12
+ _REG_TRAPNO = 0x13
+ _REG_ERR = 0x14
+ _REG_RIP = 0x15
+ _REG_CS = 0x16
+ _REG_RFLAGS = 0x17
+ _REG_RSP = 0x18
+ _REG_SS = 0x19
+)
diff --git a/src/runtime/defs1_netbsd_arm.go b/src/runtime/defs1_netbsd_arm.go
new file mode 100644
index 000000000..54ddf3882
--- /dev/null
+++ b/src/runtime/defs1_netbsd_arm.go
@@ -0,0 +1,170 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
+
+package runtime
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x6
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_RECEIPT = 0
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = 0x0
+ _EVFILT_WRITE = 0x1
+)
+
+type sigaltstackt struct {
+ ss_sp *byte
+ ss_size uint32
+ ss_flags int32
+}
+
+type sigset struct {
+ __bits [4]uint32
+}
+
+type siginfo struct {
+ _signo int32
+ _code int32
+ _errno int32
+ _reason [20]byte
+}
+
+type stackt struct {
+ ss_sp *byte
+ ss_size uint32
+ ss_flags int32
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int32
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int32
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type mcontextt struct {
+ __gregs [17]uint32
+ __fpu [4 + 8*32 + 4]byte // EABI
+ // __fpu [4+4*33+4]byte // not EABI
+ _mc_tlsbase uint32
+}
+
+type ucontextt struct {
+ uc_flags uint32
+ uc_link *ucontextt
+ uc_sigmask sigset
+ uc_stack stackt
+ uc_mcontext mcontextt
+ __uc_pad [2]int32
+}
+
+type keventt struct {
+ ident uint32
+ filter uint32
+ flags uint32
+ fflags uint32
+ data int64
+ udata *byte
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
+
+const (
+ _REG_R0 = 0x0
+ _REG_R1 = 0x1
+ _REG_R2 = 0x2
+ _REG_R3 = 0x3
+ _REG_R4 = 0x4
+ _REG_R5 = 0x5
+ _REG_R6 = 0x6
+ _REG_R7 = 0x7
+ _REG_R8 = 0x8
+ _REG_R9 = 0x9
+ _REG_R10 = 0xa
+ _REG_R11 = 0xb
+ _REG_R12 = 0xc
+ _REG_R13 = 0xd
+ _REG_R14 = 0xe
+ _REG_R15 = 0xf
+ _REG_CPSR = 0x10
+)
diff --git a/src/runtime/defs1_solaris_amd64.go b/src/runtime/defs1_solaris_amd64.go
new file mode 100644
index 000000000..3bb6f69bf
--- /dev/null
+++ b/src/runtime/defs1_solaris_amd64.go
@@ -0,0 +1,245 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
+
+package runtime
+
+const (
+ _EINTR = 0x4
+ _EBADF = 0x9
+ _EFAULT = 0xe
+ _EAGAIN = 0xb
+ _ETIMEDOUT = 0x91
+ _EWOULDBLOCK = 0xb
+ _EINPROGRESS = 0x96
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x100
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x5
+
+ _SA_SIGINFO = 0x8
+ _SA_RESTART = 0x4
+ _SA_ONSTACK = 0x1
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x15
+ _SIGSTOP = 0x17
+ _SIGTSTP = 0x18
+ _SIGCONT = 0x19
+ _SIGCHLD = 0x12
+ _SIGTTIN = 0x1a
+ _SIGTTOU = 0x1b
+ _SIGIO = 0x16
+ _SIGXCPU = 0x1e
+ _SIGXFSZ = 0x1f
+ _SIGVTALRM = 0x1c
+ _SIGPROF = 0x1d
+ _SIGWINCH = 0x14
+ _SIGUSR1 = 0x10
+ _SIGUSR2 = 0x11
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ __SC_NPROCESSORS_ONLN = 0xf
+
+ _PTHREAD_CREATE_DETACHED = 0x40
+
+ _FORK_NOSIGCHLD = 0x1
+ _FORK_WAITPID = 0x2
+
+ _MAXHOSTNAMELEN = 0x100
+
+ _O_NONBLOCK = 0x80
+ _FD_CLOEXEC = 0x1
+ _F_GETFL = 0x3
+ _F_SETFL = 0x4
+ _F_SETFD = 0x2
+
+ _POLLIN = 0x1
+ _POLLOUT = 0x4
+ _POLLHUP = 0x10
+ _POLLERR = 0x8
+
+ _PORT_SOURCE_FD = 0x4
+)
+
+type semt struct {
+ sem_count uint32
+ sem_type uint16
+ sem_magic uint16
+ sem_pad1 [3]uint64
+ sem_pad2 [2]uint64
+}
+
+type sigaltstackt struct {
+ ss_sp *byte
+ ss_size uint64
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type sigset struct {
+ __sigbits [4]uint32
+}
+
+type stackt struct {
+ ss_sp *byte
+ ss_size uint64
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type siginfo struct {
+ si_signo int32
+ si_code int32
+ si_errno int32
+ si_pad int32
+ __data [240]byte
+}
+
+type sigactiont struct {
+ sa_flags int32
+ pad_cgo_0 [4]byte
+ _funcptr [8]byte
+ sa_mask sigset
+}
+
+type fpregset struct {
+ fp_reg_set [528]byte
+}
+
+type mcontext struct {
+ gregs [28]int64
+ fpregs fpregset
+}
+
+type ucontext struct {
+ uc_flags uint64
+ uc_link *ucontext
+ uc_sigmask sigset
+ uc_stack stackt
+ pad_cgo_0 [8]byte
+ uc_mcontext mcontext
+ uc_filler [5]int64
+ pad_cgo_1 [8]byte
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = int64(x)
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type portevent struct {
+ portev_events int32
+ portev_source uint16
+ portev_pad uint16
+ portev_object uint64
+ portev_user *byte
+}
+
+type pthread uint32
+type pthreadattr struct {
+ __pthread_attrp *byte
+}
+
+type stat struct {
+ st_dev uint64
+ st_ino uint64
+ st_mode uint32
+ st_nlink uint32
+ st_uid uint32
+ st_gid uint32
+ st_rdev uint64
+ st_size int64
+ st_atim timespec
+ st_mtim timespec
+ st_ctim timespec
+ st_blksize int32
+ pad_cgo_0 [4]byte
+ st_blocks int64
+ st_fstype [16]int8
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
+
+const (
+ _REG_RDI = 0x8
+ _REG_RSI = 0x9
+ _REG_RDX = 0xc
+ _REG_RCX = 0xd
+ _REG_R8 = 0x7
+ _REG_R9 = 0x6
+ _REG_R10 = 0x5
+ _REG_R11 = 0x4
+ _REG_R12 = 0x3
+ _REG_R13 = 0x2
+ _REG_R14 = 0x1
+ _REG_R15 = 0x0
+ _REG_RBP = 0xa
+ _REG_RBX = 0xb
+ _REG_RAX = 0xe
+ _REG_GS = 0x17
+ _REG_FS = 0x16
+ _REG_ES = 0x18
+ _REG_DS = 0x19
+ _REG_TRAPNO = 0xf
+ _REG_ERR = 0x10
+ _REG_RIP = 0x11
+ _REG_CS = 0x12
+ _REG_RFLAGS = 0x13
+ _REG_RSP = 0x14
+ _REG_SS = 0x15
+)
diff --git a/src/runtime/defs3_linux.go b/src/runtime/defs3_linux.go
new file mode 100644
index 000000000..3551a4fa9
--- /dev/null
+++ b/src/runtime/defs3_linux.go
@@ -0,0 +1,43 @@
+// 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.
+
+// +build ignore
+
+/*
+Input to cgo -cdefs
+
+GOARCH=power64 cgo -cdefs defs_linux.go defs3_linux.go > defs_linux_power64.h
+*/
+
+package runtime
+
+/*
+#define size_t __kernel_size_t
+#define sigset_t __sigset_t // rename the sigset_t here otherwise cgo will complain about "inconsistent definitions for C.sigset_t"
+#define _SYS_TYPES_H // avoid inclusion of sys/types.h
+#include <asm/ucontext.h>
+#include <asm-generic/fcntl.h>
+*/
+import "C"
+
+const (
+ O_RDONLY = C.O_RDONLY
+ O_CLOEXEC = C.O_CLOEXEC
+ SA_RESTORER = 0 // unused
+)
+
+type Usigset C.__sigset_t
+
+// types used in sigcontext
+type Ptregs C.struct_pt_regs
+type Gregset C.elf_gregset_t
+type FPregset C.elf_fpregset_t
+type Vreg C.elf_vrreg_t
+
+type SigaltstackT C.struct_sigaltstack
+
+// PPC64 uses sigcontext in place of mcontext in ucontext.
+// see http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/powerpc/include/uapi/asm/ucontext.h
+type Sigcontext C.struct_sigcontext
+type Ucontext C.struct_ucontext
diff --git a/src/runtime/defs_android_arm.h b/src/runtime/defs_android_arm.h
deleted file mode 100644
index 3611b3a10..000000000
--- a/src/runtime/defs_android_arm.h
+++ /dev/null
@@ -1,3 +0,0 @@
-// TODO: Generate using cgo like defs_linux_{386,amd64}.h
-
-#include "defs_linux_arm.h"
diff --git a/src/runtime/defs_darwin_386.go b/src/runtime/defs_darwin_386.go
new file mode 100644
index 000000000..cf4812f9f
--- /dev/null
+++ b/src/runtime/defs_darwin_386.go
@@ -0,0 +1,382 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_darwin.go
+
+package runtime
+
+import "unsafe"
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_DONTNEED = 0x4
+ _MADV_FREE = 0x5
+
+ _MACH_MSG_TYPE_MOVE_RECEIVE = 0x10
+ _MACH_MSG_TYPE_MOVE_SEND = 0x11
+ _MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
+ _MACH_MSG_TYPE_COPY_SEND = 0x13
+ _MACH_MSG_TYPE_MAKE_SEND = 0x14
+ _MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
+ _MACH_MSG_TYPE_COPY_RECEIVE = 0x16
+
+ _MACH_MSG_PORT_DESCRIPTOR = 0x0
+ _MACH_MSG_OOL_DESCRIPTOR = 0x1
+ _MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2
+ _MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
+
+ _MACH_MSGH_BITS_COMPLEX = 0x80000000
+
+ _MACH_SEND_MSG = 0x1
+ _MACH_RCV_MSG = 0x2
+ _MACH_RCV_LARGE = 0x4
+
+ _MACH_SEND_TIMEOUT = 0x10
+ _MACH_SEND_INTERRUPT = 0x40
+ _MACH_SEND_ALWAYS = 0x10000
+ _MACH_SEND_TRAILER = 0x20000
+ _MACH_RCV_TIMEOUT = 0x100
+ _MACH_RCV_NOTIFY = 0x200
+ _MACH_RCV_INTERRUPT = 0x400
+ _MACH_RCV_OVERWRITE = 0x1000
+
+ _NDR_PROTOCOL_2_0 = 0x0
+ _NDR_INT_BIG_ENDIAN = 0x0
+ _NDR_INT_LITTLE_ENDIAN = 0x1
+ _NDR_FLOAT_IEEE = 0x0
+ _NDR_CHAR_ASCII = 0x0
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+ _SA_USERTRAMP = 0x100
+ _SA_64REGSET = 0x200
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x7
+ _FPE_INTOVF = 0x8
+ _FPE_FLTDIV = 0x1
+ _FPE_FLTOVF = 0x2
+ _FPE_FLTUND = 0x3
+ _FPE_FLTRES = 0x4
+ _FPE_FLTINV = 0x5
+ _FPE_FLTSUB = 0x6
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_RECEIPT = 0x40
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type machbody struct {
+ msgh_descriptor_count uint32
+}
+
+type machheader struct {
+ msgh_bits uint32
+ msgh_size uint32
+ msgh_remote_port uint32
+ msgh_local_port uint32
+ msgh_reserved uint32
+ msgh_id int32
+}
+
+type machndr struct {
+ mig_vers uint8
+ if_vers uint8
+ reserved1 uint8
+ mig_encoding uint8
+ int_rep uint8
+ char_rep uint8
+ float_rep uint8
+ reserved2 uint8
+}
+
+type machport struct {
+ name uint32
+ pad1 uint32
+ pad2 uint16
+ disposition uint8
+ _type uint8
+}
+
+type stackt struct {
+ ss_sp *byte
+ ss_size uintptr
+ ss_flags int32
+}
+
+type sigactiont struct {
+ __sigaction_u [4]byte
+ sa_tramp unsafe.Pointer
+ sa_mask uint32
+ sa_flags int32
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ si_pid int32
+ si_uid uint32
+ si_status int32
+ si_addr *byte
+ si_value [4]byte
+ si_band int32
+ __pad [7]uint32
+}
+
+type timeval struct {
+ tv_sec int32
+ tv_usec int32
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type timespec struct {
+ tv_sec int32
+ tv_nsec int32
+}
+
+type fpcontrol struct {
+ pad_cgo_0 [2]byte
+}
+
+type fpstatus struct {
+ pad_cgo_0 [2]byte
+}
+
+type regmmst struct {
+ mmst_reg [10]int8
+ mmst_rsrv [6]int8
+}
+
+type regxmm struct {
+ xmm_reg [16]int8
+}
+
+type regs64 struct {
+ rax uint64
+ rbx uint64
+ rcx uint64
+ rdx uint64
+ rdi uint64
+ rsi uint64
+ rbp uint64
+ rsp uint64
+ r8 uint64
+ r9 uint64
+ r10 uint64
+ r11 uint64
+ r12 uint64
+ r13 uint64
+ r14 uint64
+ r15 uint64
+ rip uint64
+ rflags uint64
+ cs uint64
+ fs uint64
+ gs uint64
+}
+
+type floatstate64 struct {
+ fpu_reserved [2]int32
+ fpu_fcw fpcontrol
+ fpu_fsw fpstatus
+ fpu_ftw uint8
+ fpu_rsrv1 uint8
+ fpu_fop uint16
+ fpu_ip uint32
+ fpu_cs uint16
+ fpu_rsrv2 uint16
+ fpu_dp uint32
+ fpu_ds uint16
+ fpu_rsrv3 uint16
+ fpu_mxcsr uint32
+ fpu_mxcsrmask uint32
+ fpu_stmm0 regmmst
+ fpu_stmm1 regmmst
+ fpu_stmm2 regmmst
+ fpu_stmm3 regmmst
+ fpu_stmm4 regmmst
+ fpu_stmm5 regmmst
+ fpu_stmm6 regmmst
+ fpu_stmm7 regmmst
+ fpu_xmm0 regxmm
+ fpu_xmm1 regxmm
+ fpu_xmm2 regxmm
+ fpu_xmm3 regxmm
+ fpu_xmm4 regxmm
+ fpu_xmm5 regxmm
+ fpu_xmm6 regxmm
+ fpu_xmm7 regxmm
+ fpu_xmm8 regxmm
+ fpu_xmm9 regxmm
+ fpu_xmm10 regxmm
+ fpu_xmm11 regxmm
+ fpu_xmm12 regxmm
+ fpu_xmm13 regxmm
+ fpu_xmm14 regxmm
+ fpu_xmm15 regxmm
+ fpu_rsrv4 [96]int8
+ fpu_reserved1 int32
+}
+
+type exceptionstate64 struct {
+ trapno uint16
+ cpu uint16
+ err uint32
+ faultvaddr uint64
+}
+
+type mcontext64 struct {
+ es exceptionstate64
+ ss regs64
+ fs floatstate64
+}
+
+type regs32 struct {
+ eax uint32
+ ebx uint32
+ ecx uint32
+ edx uint32
+ edi uint32
+ esi uint32
+ ebp uint32
+ esp uint32
+ ss uint32
+ eflags uint32
+ eip uint32
+ cs uint32
+ ds uint32
+ es uint32
+ fs uint32
+ gs uint32
+}
+
+type floatstate32 struct {
+ fpu_reserved [2]int32
+ fpu_fcw fpcontrol
+ fpu_fsw fpstatus
+ fpu_ftw uint8
+ fpu_rsrv1 uint8
+ fpu_fop uint16
+ fpu_ip uint32
+ fpu_cs uint16
+ fpu_rsrv2 uint16
+ fpu_dp uint32
+ fpu_ds uint16
+ fpu_rsrv3 uint16
+ fpu_mxcsr uint32
+ fpu_mxcsrmask uint32
+ fpu_stmm0 regmmst
+ fpu_stmm1 regmmst
+ fpu_stmm2 regmmst
+ fpu_stmm3 regmmst
+ fpu_stmm4 regmmst
+ fpu_stmm5 regmmst
+ fpu_stmm6 regmmst
+ fpu_stmm7 regmmst
+ fpu_xmm0 regxmm
+ fpu_xmm1 regxmm
+ fpu_xmm2 regxmm
+ fpu_xmm3 regxmm
+ fpu_xmm4 regxmm
+ fpu_xmm5 regxmm
+ fpu_xmm6 regxmm
+ fpu_xmm7 regxmm
+ fpu_rsrv4 [224]int8
+ fpu_reserved1 int32
+}
+
+type exceptionstate32 struct {
+ trapno uint16
+ cpu uint16
+ err uint32
+ faultvaddr uint32
+}
+
+type mcontext32 struct {
+ es exceptionstate32
+ ss regs32
+ fs floatstate32
+}
+
+type ucontext struct {
+ uc_onstack int32
+ uc_sigmask uint32
+ uc_stack stackt
+ uc_link *ucontext
+ uc_mcsize uint32
+ uc_mcontext *mcontext32
+}
+
+type keventt struct {
+ ident uint32
+ filter int16
+ flags uint16
+ fflags uint32
+ data int32
+ udata *byte
+}
diff --git a/src/runtime/defs_darwin_386.h b/src/runtime/defs_darwin_386.h
deleted file mode 100644
index 0e0b4fbf7..000000000
--- a/src/runtime/defs_darwin_386.h
+++ /dev/null
@@ -1,392 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_darwin.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_DONTNEED = 0x4,
- MADV_FREE = 0x5,
-
- MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
- MACH_MSG_TYPE_MOVE_SEND = 0x11,
- MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
- MACH_MSG_TYPE_COPY_SEND = 0x13,
- MACH_MSG_TYPE_MAKE_SEND = 0x14,
- MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15,
- MACH_MSG_TYPE_COPY_RECEIVE = 0x16,
-
- MACH_MSG_PORT_DESCRIPTOR = 0x0,
- MACH_MSG_OOL_DESCRIPTOR = 0x1,
- MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2,
- MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3,
-
- MACH_MSGH_BITS_COMPLEX = 0x80000000,
-
- MACH_SEND_MSG = 0x1,
- MACH_RCV_MSG = 0x2,
- MACH_RCV_LARGE = 0x4,
-
- MACH_SEND_TIMEOUT = 0x10,
- MACH_SEND_INTERRUPT = 0x40,
- MACH_SEND_ALWAYS = 0x10000,
- MACH_SEND_TRAILER = 0x20000,
- MACH_RCV_TIMEOUT = 0x100,
- MACH_RCV_NOTIFY = 0x200,
- MACH_RCV_INTERRUPT = 0x400,
- MACH_RCV_OVERWRITE = 0x1000,
-
- NDR_PROTOCOL_2_0 = 0x0,
- NDR_INT_BIG_ENDIAN = 0x0,
- NDR_INT_LITTLE_ENDIAN = 0x1,
- NDR_FLOAT_IEEE = 0x0,
- NDR_CHAR_ASCII = 0x0,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
- SA_USERTRAMP = 0x100,
- SA_64REGSET = 0x200,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x7,
- FPE_INTOVF = 0x8,
- FPE_FLTDIV = 0x1,
- FPE_FLTOVF = 0x2,
- FPE_FLTUND = 0x3,
- FPE_FLTRES = 0x4,
- FPE_FLTINV = 0x5,
- FPE_FLTSUB = 0x6,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_RECEIPT = 0x40,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
-};
-
-typedef struct MachBody MachBody;
-typedef struct MachHeader MachHeader;
-typedef struct MachNDR MachNDR;
-typedef struct MachPort MachPort;
-typedef struct StackT StackT;
-typedef struct SigactionT SigactionT;
-typedef struct Siginfo Siginfo;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct Timespec Timespec;
-typedef struct FPControl FPControl;
-typedef struct FPStatus FPStatus;
-typedef struct RegMMST RegMMST;
-typedef struct RegXMM RegXMM;
-typedef struct Regs64 Regs64;
-typedef struct FloatState64 FloatState64;
-typedef struct ExceptionState64 ExceptionState64;
-typedef struct Mcontext64 Mcontext64;
-typedef struct Regs32 Regs32;
-typedef struct FloatState32 FloatState32;
-typedef struct ExceptionState32 ExceptionState32;
-typedef struct Mcontext32 Mcontext32;
-typedef struct Ucontext Ucontext;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct MachBody {
- uint32 msgh_descriptor_count;
-};
-struct MachHeader {
- uint32 msgh_bits;
- uint32 msgh_size;
- uint32 msgh_remote_port;
- uint32 msgh_local_port;
- uint32 msgh_reserved;
- int32 msgh_id;
-};
-struct MachNDR {
- uint8 mig_vers;
- uint8 if_vers;
- uint8 reserved1;
- uint8 mig_encoding;
- uint8 int_rep;
- uint8 char_rep;
- uint8 float_rep;
- uint8 reserved2;
-};
-struct MachPort {
- uint32 name;
- uint32 pad1;
- uint16 pad2;
- uint8 disposition;
- uint8 type;
-};
-
-struct StackT {
- byte *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-typedef byte Sighandler[4];
-
-struct SigactionT {
- byte __sigaction_u[4];
- void *sa_tramp;
- uint32 sa_mask;
- int32 sa_flags;
-};
-
-typedef byte Sigval[4];
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- int32 si_pid;
- uint32 si_uid;
- int32 si_status;
- byte *si_addr;
- byte si_value[4];
- int32 si_band;
- uint32 __pad[7];
-};
-struct Timeval {
- int32 tv_sec;
- int32 tv_usec;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-struct Timespec {
- int32 tv_sec;
- int32 tv_nsec;
-};
-
-struct FPControl {
- byte Pad_cgo_0[2];
-};
-struct FPStatus {
- byte Pad_cgo_0[2];
-};
-struct RegMMST {
- int8 mmst_reg[10];
- int8 mmst_rsrv[6];
-};
-struct RegXMM {
- int8 xmm_reg[16];
-};
-
-struct Regs64 {
- uint64 rax;
- uint64 rbx;
- uint64 rcx;
- uint64 rdx;
- uint64 rdi;
- uint64 rsi;
- uint64 rbp;
- uint64 rsp;
- uint64 r8;
- uint64 r9;
- uint64 r10;
- uint64 r11;
- uint64 r12;
- uint64 r13;
- uint64 r14;
- uint64 r15;
- uint64 rip;
- uint64 rflags;
- uint64 cs;
- uint64 fs;
- uint64 gs;
-};
-struct FloatState64 {
- int32 fpu_reserved[2];
- FPControl fpu_fcw;
- FPStatus fpu_fsw;
- uint8 fpu_ftw;
- uint8 fpu_rsrv1;
- uint16 fpu_fop;
- uint32 fpu_ip;
- uint16 fpu_cs;
- uint16 fpu_rsrv2;
- uint32 fpu_dp;
- uint16 fpu_ds;
- uint16 fpu_rsrv3;
- uint32 fpu_mxcsr;
- uint32 fpu_mxcsrmask;
- RegMMST fpu_stmm0;
- RegMMST fpu_stmm1;
- RegMMST fpu_stmm2;
- RegMMST fpu_stmm3;
- RegMMST fpu_stmm4;
- RegMMST fpu_stmm5;
- RegMMST fpu_stmm6;
- RegMMST fpu_stmm7;
- RegXMM fpu_xmm0;
- RegXMM fpu_xmm1;
- RegXMM fpu_xmm2;
- RegXMM fpu_xmm3;
- RegXMM fpu_xmm4;
- RegXMM fpu_xmm5;
- RegXMM fpu_xmm6;
- RegXMM fpu_xmm7;
- RegXMM fpu_xmm8;
- RegXMM fpu_xmm9;
- RegXMM fpu_xmm10;
- RegXMM fpu_xmm11;
- RegXMM fpu_xmm12;
- RegXMM fpu_xmm13;
- RegXMM fpu_xmm14;
- RegXMM fpu_xmm15;
- int8 fpu_rsrv4[96];
- int32 fpu_reserved1;
-};
-struct ExceptionState64 {
- uint16 trapno;
- uint16 cpu;
- uint32 err;
- uint64 faultvaddr;
-};
-struct Mcontext64 {
- ExceptionState64 es;
- Regs64 ss;
- FloatState64 fs;
-};
-
-struct Regs32 {
- uint32 eax;
- uint32 ebx;
- uint32 ecx;
- uint32 edx;
- uint32 edi;
- uint32 esi;
- uint32 ebp;
- uint32 esp;
- uint32 ss;
- uint32 eflags;
- uint32 eip;
- uint32 cs;
- uint32 ds;
- uint32 es;
- uint32 fs;
- uint32 gs;
-};
-struct FloatState32 {
- int32 fpu_reserved[2];
- FPControl fpu_fcw;
- FPStatus fpu_fsw;
- uint8 fpu_ftw;
- uint8 fpu_rsrv1;
- uint16 fpu_fop;
- uint32 fpu_ip;
- uint16 fpu_cs;
- uint16 fpu_rsrv2;
- uint32 fpu_dp;
- uint16 fpu_ds;
- uint16 fpu_rsrv3;
- uint32 fpu_mxcsr;
- uint32 fpu_mxcsrmask;
- RegMMST fpu_stmm0;
- RegMMST fpu_stmm1;
- RegMMST fpu_stmm2;
- RegMMST fpu_stmm3;
- RegMMST fpu_stmm4;
- RegMMST fpu_stmm5;
- RegMMST fpu_stmm6;
- RegMMST fpu_stmm7;
- RegXMM fpu_xmm0;
- RegXMM fpu_xmm1;
- RegXMM fpu_xmm2;
- RegXMM fpu_xmm3;
- RegXMM fpu_xmm4;
- RegXMM fpu_xmm5;
- RegXMM fpu_xmm6;
- RegXMM fpu_xmm7;
- int8 fpu_rsrv4[224];
- int32 fpu_reserved1;
-};
-struct ExceptionState32 {
- uint16 trapno;
- uint16 cpu;
- uint32 err;
- uint32 faultvaddr;
-};
-struct Mcontext32 {
- ExceptionState32 es;
- Regs32 ss;
- FloatState32 fs;
-};
-
-struct Ucontext {
- int32 uc_onstack;
- uint32 uc_sigmask;
- StackT uc_stack;
- Ucontext *uc_link;
- uint32 uc_mcsize;
- Mcontext32 *uc_mcontext;
-};
-
-struct KeventT {
- uint32 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int32 data;
- byte *udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_darwin_amd64.go b/src/runtime/defs_darwin_amd64.go
new file mode 100644
index 000000000..2cd4c0cd0
--- /dev/null
+++ b/src/runtime/defs_darwin_amd64.go
@@ -0,0 +1,385 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_darwin.go
+
+package runtime
+
+import "unsafe"
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_DONTNEED = 0x4
+ _MADV_FREE = 0x5
+
+ _MACH_MSG_TYPE_MOVE_RECEIVE = 0x10
+ _MACH_MSG_TYPE_MOVE_SEND = 0x11
+ _MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
+ _MACH_MSG_TYPE_COPY_SEND = 0x13
+ _MACH_MSG_TYPE_MAKE_SEND = 0x14
+ _MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
+ _MACH_MSG_TYPE_COPY_RECEIVE = 0x16
+
+ _MACH_MSG_PORT_DESCRIPTOR = 0x0
+ _MACH_MSG_OOL_DESCRIPTOR = 0x1
+ _MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2
+ _MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
+
+ _MACH_MSGH_BITS_COMPLEX = 0x80000000
+
+ _MACH_SEND_MSG = 0x1
+ _MACH_RCV_MSG = 0x2
+ _MACH_RCV_LARGE = 0x4
+
+ _MACH_SEND_TIMEOUT = 0x10
+ _MACH_SEND_INTERRUPT = 0x40
+ _MACH_SEND_ALWAYS = 0x10000
+ _MACH_SEND_TRAILER = 0x20000
+ _MACH_RCV_TIMEOUT = 0x100
+ _MACH_RCV_NOTIFY = 0x200
+ _MACH_RCV_INTERRUPT = 0x400
+ _MACH_RCV_OVERWRITE = 0x1000
+
+ _NDR_PROTOCOL_2_0 = 0x0
+ _NDR_INT_BIG_ENDIAN = 0x0
+ _NDR_INT_LITTLE_ENDIAN = 0x1
+ _NDR_FLOAT_IEEE = 0x0
+ _NDR_CHAR_ASCII = 0x0
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+ _SA_USERTRAMP = 0x100
+ _SA_64REGSET = 0x200
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x7
+ _FPE_INTOVF = 0x8
+ _FPE_FLTDIV = 0x1
+ _FPE_FLTOVF = 0x2
+ _FPE_FLTUND = 0x3
+ _FPE_FLTRES = 0x4
+ _FPE_FLTINV = 0x5
+ _FPE_FLTSUB = 0x6
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_RECEIPT = 0x40
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type machbody struct {
+ msgh_descriptor_count uint32
+}
+
+type machheader struct {
+ msgh_bits uint32
+ msgh_size uint32
+ msgh_remote_port uint32
+ msgh_local_port uint32
+ msgh_reserved uint32
+ msgh_id int32
+}
+
+type machndr struct {
+ mig_vers uint8
+ if_vers uint8
+ reserved1 uint8
+ mig_encoding uint8
+ int_rep uint8
+ char_rep uint8
+ float_rep uint8
+ reserved2 uint8
+}
+
+type machport struct {
+ name uint32
+ pad1 uint32
+ pad2 uint16
+ disposition uint8
+ _type uint8
+}
+
+type stackt struct {
+ ss_sp *byte
+ ss_size uintptr
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type sigactiont struct {
+ __sigaction_u [8]byte
+ sa_tramp unsafe.Pointer
+ sa_mask uint32
+ sa_flags int32
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ si_pid int32
+ si_uid uint32
+ si_status int32
+ si_addr *byte
+ si_value [8]byte
+ si_band int64
+ __pad [7]uint64
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int32
+ pad_cgo_0 [4]byte
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+type fpcontrol struct {
+ pad_cgo_0 [2]byte
+}
+
+type fpstatus struct {
+ pad_cgo_0 [2]byte
+}
+
+type regmmst struct {
+ mmst_reg [10]int8
+ mmst_rsrv [6]int8
+}
+
+type regxmm struct {
+ xmm_reg [16]int8
+}
+
+type regs64 struct {
+ rax uint64
+ rbx uint64
+ rcx uint64
+ rdx uint64
+ rdi uint64
+ rsi uint64
+ rbp uint64
+ rsp uint64
+ r8 uint64
+ r9 uint64
+ r10 uint64
+ r11 uint64
+ r12 uint64
+ r13 uint64
+ r14 uint64
+ r15 uint64
+ rip uint64
+ rflags uint64
+ cs uint64
+ fs uint64
+ gs uint64
+}
+
+type floatstate64 struct {
+ fpu_reserved [2]int32
+ fpu_fcw fpcontrol
+ fpu_fsw fpstatus
+ fpu_ftw uint8
+ fpu_rsrv1 uint8
+ fpu_fop uint16
+ fpu_ip uint32
+ fpu_cs uint16
+ fpu_rsrv2 uint16
+ fpu_dp uint32
+ fpu_ds uint16
+ fpu_rsrv3 uint16
+ fpu_mxcsr uint32
+ fpu_mxcsrmask uint32
+ fpu_stmm0 regmmst
+ fpu_stmm1 regmmst
+ fpu_stmm2 regmmst
+ fpu_stmm3 regmmst
+ fpu_stmm4 regmmst
+ fpu_stmm5 regmmst
+ fpu_stmm6 regmmst
+ fpu_stmm7 regmmst
+ fpu_xmm0 regxmm
+ fpu_xmm1 regxmm
+ fpu_xmm2 regxmm
+ fpu_xmm3 regxmm
+ fpu_xmm4 regxmm
+ fpu_xmm5 regxmm
+ fpu_xmm6 regxmm
+ fpu_xmm7 regxmm
+ fpu_xmm8 regxmm
+ fpu_xmm9 regxmm
+ fpu_xmm10 regxmm
+ fpu_xmm11 regxmm
+ fpu_xmm12 regxmm
+ fpu_xmm13 regxmm
+ fpu_xmm14 regxmm
+ fpu_xmm15 regxmm
+ fpu_rsrv4 [96]int8
+ fpu_reserved1 int32
+}
+
+type exceptionstate64 struct {
+ trapno uint16
+ cpu uint16
+ err uint32
+ faultvaddr uint64
+}
+
+type mcontext64 struct {
+ es exceptionstate64
+ ss regs64
+ fs floatstate64
+ pad_cgo_0 [4]byte
+}
+
+type regs32 struct {
+ eax uint32
+ ebx uint32
+ ecx uint32
+ edx uint32
+ edi uint32
+ esi uint32
+ ebp uint32
+ esp uint32
+ ss uint32
+ eflags uint32
+ eip uint32
+ cs uint32
+ ds uint32
+ es uint32
+ fs uint32
+ gs uint32
+}
+
+type floatstate32 struct {
+ fpu_reserved [2]int32
+ fpu_fcw fpcontrol
+ fpu_fsw fpstatus
+ fpu_ftw uint8
+ fpu_rsrv1 uint8
+ fpu_fop uint16
+ fpu_ip uint32
+ fpu_cs uint16
+ fpu_rsrv2 uint16
+ fpu_dp uint32
+ fpu_ds uint16
+ fpu_rsrv3 uint16
+ fpu_mxcsr uint32
+ fpu_mxcsrmask uint32
+ fpu_stmm0 regmmst
+ fpu_stmm1 regmmst
+ fpu_stmm2 regmmst
+ fpu_stmm3 regmmst
+ fpu_stmm4 regmmst
+ fpu_stmm5 regmmst
+ fpu_stmm6 regmmst
+ fpu_stmm7 regmmst
+ fpu_xmm0 regxmm
+ fpu_xmm1 regxmm
+ fpu_xmm2 regxmm
+ fpu_xmm3 regxmm
+ fpu_xmm4 regxmm
+ fpu_xmm5 regxmm
+ fpu_xmm6 regxmm
+ fpu_xmm7 regxmm
+ fpu_rsrv4 [224]int8
+ fpu_reserved1 int32
+}
+
+type exceptionstate32 struct {
+ trapno uint16
+ cpu uint16
+ err uint32
+ faultvaddr uint32
+}
+
+type mcontext32 struct {
+ es exceptionstate32
+ ss regs32
+ fs floatstate32
+}
+
+type ucontext struct {
+ uc_onstack int32
+ uc_sigmask uint32
+ uc_stack stackt
+ uc_link *ucontext
+ uc_mcsize uint64
+ uc_mcontext *mcontext64
+}
+
+type keventt struct {
+ ident uint64
+ filter int16
+ flags uint16
+ fflags uint32
+ data int64
+ udata *byte
+}
diff --git a/src/runtime/defs_darwin_amd64.h b/src/runtime/defs_darwin_amd64.h
deleted file mode 100644
index 4bf83c1cb..000000000
--- a/src/runtime/defs_darwin_amd64.h
+++ /dev/null
@@ -1,395 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_darwin.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_DONTNEED = 0x4,
- MADV_FREE = 0x5,
-
- MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
- MACH_MSG_TYPE_MOVE_SEND = 0x11,
- MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
- MACH_MSG_TYPE_COPY_SEND = 0x13,
- MACH_MSG_TYPE_MAKE_SEND = 0x14,
- MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15,
- MACH_MSG_TYPE_COPY_RECEIVE = 0x16,
-
- MACH_MSG_PORT_DESCRIPTOR = 0x0,
- MACH_MSG_OOL_DESCRIPTOR = 0x1,
- MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2,
- MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3,
-
- MACH_MSGH_BITS_COMPLEX = 0x80000000,
-
- MACH_SEND_MSG = 0x1,
- MACH_RCV_MSG = 0x2,
- MACH_RCV_LARGE = 0x4,
-
- MACH_SEND_TIMEOUT = 0x10,
- MACH_SEND_INTERRUPT = 0x40,
- MACH_SEND_ALWAYS = 0x10000,
- MACH_SEND_TRAILER = 0x20000,
- MACH_RCV_TIMEOUT = 0x100,
- MACH_RCV_NOTIFY = 0x200,
- MACH_RCV_INTERRUPT = 0x400,
- MACH_RCV_OVERWRITE = 0x1000,
-
- NDR_PROTOCOL_2_0 = 0x0,
- NDR_INT_BIG_ENDIAN = 0x0,
- NDR_INT_LITTLE_ENDIAN = 0x1,
- NDR_FLOAT_IEEE = 0x0,
- NDR_CHAR_ASCII = 0x0,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
- SA_USERTRAMP = 0x100,
- SA_64REGSET = 0x200,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x7,
- FPE_INTOVF = 0x8,
- FPE_FLTDIV = 0x1,
- FPE_FLTOVF = 0x2,
- FPE_FLTUND = 0x3,
- FPE_FLTRES = 0x4,
- FPE_FLTINV = 0x5,
- FPE_FLTSUB = 0x6,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_RECEIPT = 0x40,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
-};
-
-typedef struct MachBody MachBody;
-typedef struct MachHeader MachHeader;
-typedef struct MachNDR MachNDR;
-typedef struct MachPort MachPort;
-typedef struct StackT StackT;
-typedef struct SigactionT SigactionT;
-typedef struct Siginfo Siginfo;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct Timespec Timespec;
-typedef struct FPControl FPControl;
-typedef struct FPStatus FPStatus;
-typedef struct RegMMST RegMMST;
-typedef struct RegXMM RegXMM;
-typedef struct Regs64 Regs64;
-typedef struct FloatState64 FloatState64;
-typedef struct ExceptionState64 ExceptionState64;
-typedef struct Mcontext64 Mcontext64;
-typedef struct Regs32 Regs32;
-typedef struct FloatState32 FloatState32;
-typedef struct ExceptionState32 ExceptionState32;
-typedef struct Mcontext32 Mcontext32;
-typedef struct Ucontext Ucontext;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct MachBody {
- uint32 msgh_descriptor_count;
-};
-struct MachHeader {
- uint32 msgh_bits;
- uint32 msgh_size;
- uint32 msgh_remote_port;
- uint32 msgh_local_port;
- uint32 msgh_reserved;
- int32 msgh_id;
-};
-struct MachNDR {
- uint8 mig_vers;
- uint8 if_vers;
- uint8 reserved1;
- uint8 mig_encoding;
- uint8 int_rep;
- uint8 char_rep;
- uint8 float_rep;
- uint8 reserved2;
-};
-struct MachPort {
- uint32 name;
- uint32 pad1;
- uint16 pad2;
- uint8 disposition;
- uint8 type;
-};
-
-struct StackT {
- byte *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-typedef byte Sighandler[8];
-
-struct SigactionT {
- byte __sigaction_u[8];
- void *sa_tramp;
- uint32 sa_mask;
- int32 sa_flags;
-};
-
-typedef byte Sigval[8];
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- int32 si_pid;
- uint32 si_uid;
- int32 si_status;
- byte *si_addr;
- byte si_value[8];
- int64 si_band;
- uint64 __pad[7];
-};
-struct Timeval {
- int64 tv_sec;
- int32 tv_usec;
- byte Pad_cgo_0[4];
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-struct Timespec {
- int64 tv_sec;
- int64 tv_nsec;
-};
-
-struct FPControl {
- byte Pad_cgo_0[2];
-};
-struct FPStatus {
- byte Pad_cgo_0[2];
-};
-struct RegMMST {
- int8 mmst_reg[10];
- int8 mmst_rsrv[6];
-};
-struct RegXMM {
- int8 xmm_reg[16];
-};
-
-struct Regs64 {
- uint64 rax;
- uint64 rbx;
- uint64 rcx;
- uint64 rdx;
- uint64 rdi;
- uint64 rsi;
- uint64 rbp;
- uint64 rsp;
- uint64 r8;
- uint64 r9;
- uint64 r10;
- uint64 r11;
- uint64 r12;
- uint64 r13;
- uint64 r14;
- uint64 r15;
- uint64 rip;
- uint64 rflags;
- uint64 cs;
- uint64 fs;
- uint64 gs;
-};
-struct FloatState64 {
- int32 fpu_reserved[2];
- FPControl fpu_fcw;
- FPStatus fpu_fsw;
- uint8 fpu_ftw;
- uint8 fpu_rsrv1;
- uint16 fpu_fop;
- uint32 fpu_ip;
- uint16 fpu_cs;
- uint16 fpu_rsrv2;
- uint32 fpu_dp;
- uint16 fpu_ds;
- uint16 fpu_rsrv3;
- uint32 fpu_mxcsr;
- uint32 fpu_mxcsrmask;
- RegMMST fpu_stmm0;
- RegMMST fpu_stmm1;
- RegMMST fpu_stmm2;
- RegMMST fpu_stmm3;
- RegMMST fpu_stmm4;
- RegMMST fpu_stmm5;
- RegMMST fpu_stmm6;
- RegMMST fpu_stmm7;
- RegXMM fpu_xmm0;
- RegXMM fpu_xmm1;
- RegXMM fpu_xmm2;
- RegXMM fpu_xmm3;
- RegXMM fpu_xmm4;
- RegXMM fpu_xmm5;
- RegXMM fpu_xmm6;
- RegXMM fpu_xmm7;
- RegXMM fpu_xmm8;
- RegXMM fpu_xmm9;
- RegXMM fpu_xmm10;
- RegXMM fpu_xmm11;
- RegXMM fpu_xmm12;
- RegXMM fpu_xmm13;
- RegXMM fpu_xmm14;
- RegXMM fpu_xmm15;
- int8 fpu_rsrv4[96];
- int32 fpu_reserved1;
-};
-struct ExceptionState64 {
- uint16 trapno;
- uint16 cpu;
- uint32 err;
- uint64 faultvaddr;
-};
-struct Mcontext64 {
- ExceptionState64 es;
- Regs64 ss;
- FloatState64 fs;
- byte Pad_cgo_0[4];
-};
-
-struct Regs32 {
- uint32 eax;
- uint32 ebx;
- uint32 ecx;
- uint32 edx;
- uint32 edi;
- uint32 esi;
- uint32 ebp;
- uint32 esp;
- uint32 ss;
- uint32 eflags;
- uint32 eip;
- uint32 cs;
- uint32 ds;
- uint32 es;
- uint32 fs;
- uint32 gs;
-};
-struct FloatState32 {
- int32 fpu_reserved[2];
- FPControl fpu_fcw;
- FPStatus fpu_fsw;
- uint8 fpu_ftw;
- uint8 fpu_rsrv1;
- uint16 fpu_fop;
- uint32 fpu_ip;
- uint16 fpu_cs;
- uint16 fpu_rsrv2;
- uint32 fpu_dp;
- uint16 fpu_ds;
- uint16 fpu_rsrv3;
- uint32 fpu_mxcsr;
- uint32 fpu_mxcsrmask;
- RegMMST fpu_stmm0;
- RegMMST fpu_stmm1;
- RegMMST fpu_stmm2;
- RegMMST fpu_stmm3;
- RegMMST fpu_stmm4;
- RegMMST fpu_stmm5;
- RegMMST fpu_stmm6;
- RegMMST fpu_stmm7;
- RegXMM fpu_xmm0;
- RegXMM fpu_xmm1;
- RegXMM fpu_xmm2;
- RegXMM fpu_xmm3;
- RegXMM fpu_xmm4;
- RegXMM fpu_xmm5;
- RegXMM fpu_xmm6;
- RegXMM fpu_xmm7;
- int8 fpu_rsrv4[224];
- int32 fpu_reserved1;
-};
-struct ExceptionState32 {
- uint16 trapno;
- uint16 cpu;
- uint32 err;
- uint32 faultvaddr;
-};
-struct Mcontext32 {
- ExceptionState32 es;
- Regs32 ss;
- FloatState32 fs;
-};
-
-struct Ucontext {
- int32 uc_onstack;
- uint32 uc_sigmask;
- StackT uc_stack;
- Ucontext *uc_link;
- uint64 uc_mcsize;
- Mcontext64 *uc_mcontext;
-};
-
-struct KeventT {
- uint64 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int64 data;
- byte *udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_dragonfly_386.go b/src/runtime/defs_dragonfly_386.go
new file mode 100644
index 000000000..e9c635315
--- /dev/null
+++ b/src/runtime/defs_dragonfly_386.go
@@ -0,0 +1,198 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_dragonfly.go
+
+package runtime
+
+import "unsafe"
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _EBUSY = 0x10
+ _EAGAIN = 0x23
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x5
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x2
+ _FPE_INTOVF = 0x1
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type rtprio struct {
+ _type uint16
+ prio uint16
+}
+
+type lwpparams struct {
+ start_func uintptr
+ arg unsafe.Pointer
+ stack uintptr
+ tid1 unsafe.Pointer // *int32
+ tid2 unsafe.Pointer // *int32
+}
+
+type sigaltstackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+}
+
+type sigset struct {
+ __bits [4]uint32
+}
+
+type stackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ si_pid int32
+ si_uid uint32
+ si_status int32
+ si_addr uintptr
+ si_value [4]byte
+ si_band int32
+ __spare__ [7]int32
+}
+
+type mcontext struct {
+ mc_onstack uint32
+ mc_gs uint32
+ mc_fs uint32
+ mc_es uint32
+ mc_ds uint32
+ mc_edi uint32
+ mc_esi uint32
+ mc_ebp uint32
+ mc_isp uint32
+ mc_ebx uint32
+ mc_edx uint32
+ mc_ecx uint32
+ mc_eax uint32
+ mc_xflags uint32
+ mc_trapno uint32
+ mc_err uint32
+ mc_eip uint32
+ mc_cs uint32
+ mc_eflags uint32
+ mc_esp uint32
+ mc_ss uint32
+ mc_len uint32
+ mc_fpformat uint32
+ mc_ownedfp uint32
+ mc_fpregs [128]uint32
+ __spare__ [16]uint32
+}
+
+type ucontext struct {
+ uc_sigmask sigset
+ uc_mcontext mcontext
+ uc_link *ucontext
+ uc_stack stackt
+ __spare__ [8]int32
+}
+
+type timespec struct {
+ tv_sec int32
+ tv_nsec int32
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = int32(x)
+}
+
+type timeval struct {
+ tv_sec int32
+ tv_usec int32
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type keventt struct {
+ ident uint32
+ filter int16
+ flags uint16
+ fflags uint32
+ data int32
+ udata *byte
+}
diff --git a/src/runtime/defs_dragonfly_386.h b/src/runtime/defs_dragonfly_386.h
deleted file mode 100644
index f86b9c6b9..000000000
--- a/src/runtime/defs_dragonfly_386.h
+++ /dev/null
@@ -1,198 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_dragonfly.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
- EBUSY = 0x10,
- EAGAIN = 0x23,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x5,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x2,
- FPE_INTOVF = 0x1,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
-};
-
-typedef struct Rtprio Rtprio;
-typedef struct Lwpparams Lwpparams;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct Rtprio {
- uint16 type;
- uint16 prio;
-};
-struct Lwpparams {
- void *func;
- byte *arg;
- byte *stack;
- int32 *tid1;
- int32 *tid2;
-};
-struct SigaltstackT {
- int8 *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-struct Sigset {
- uint32 __bits[4];
-};
-struct StackT {
- int8 *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- int32 si_pid;
- uint32 si_uid;
- int32 si_status;
- byte *si_addr;
- byte si_value[4];
- int32 si_band;
- int32 __spare__[7];
-};
-
-struct Mcontext {
- int32 mc_onstack;
- int32 mc_gs;
- int32 mc_fs;
- int32 mc_es;
- int32 mc_ds;
- int32 mc_edi;
- int32 mc_esi;
- int32 mc_ebp;
- int32 mc_isp;
- int32 mc_ebx;
- int32 mc_edx;
- int32 mc_ecx;
- int32 mc_eax;
- int32 mc_xflags;
- int32 mc_trapno;
- int32 mc_err;
- int32 mc_eip;
- int32 mc_cs;
- int32 mc_eflags;
- int32 mc_esp;
- int32 mc_ss;
- int32 mc_len;
- int32 mc_fpformat;
- int32 mc_ownedfp;
- int32 mc_fpregs[128];
- int32 __spare__[16];
-};
-struct Ucontext {
- Sigset uc_sigmask;
- Mcontext uc_mcontext;
- Ucontext *uc_link;
- StackT uc_stack;
- int32 __spare__[8];
-};
-
-struct Timespec {
- int32 tv_sec;
- int32 tv_nsec;
-};
-struct Timeval {
- int32 tv_sec;
- int32 tv_usec;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct KeventT {
- uint32 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int32 data;
- byte *udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_dragonfly_amd64.go b/src/runtime/defs_dragonfly_amd64.go
new file mode 100644
index 000000000..3ac10b090
--- /dev/null
+++ b/src/runtime/defs_dragonfly_amd64.go
@@ -0,0 +1,208 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_dragonfly.go
+
+package runtime
+
+import "unsafe"
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _EBUSY = 0x10
+ _EAGAIN = 0x23
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x5
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x2
+ _FPE_INTOVF = 0x1
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type rtprio struct {
+ _type uint16
+ prio uint16
+}
+
+type lwpparams struct {
+ start_func uintptr
+ arg unsafe.Pointer
+ stack uintptr
+ tid1 unsafe.Pointer // *int32
+ tid2 unsafe.Pointer // *int32
+}
+
+type sigaltstackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type sigset struct {
+ __bits [4]uint32
+}
+
+type stackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ si_pid int32
+ si_uid uint32
+ si_status int32
+ si_addr uint64
+ si_value [8]byte
+ si_band int64
+ __spare__ [7]int32
+ pad_cgo_0 [4]byte
+}
+
+type mcontext struct {
+ mc_onstack uint64
+ mc_rdi uint64
+ mc_rsi uint64
+ mc_rdx uint64
+ mc_rcx uint64
+ mc_r8 uint64
+ mc_r9 uint64
+ mc_rax uint64
+ mc_rbx uint64
+ mc_rbp uint64
+ mc_r10 uint64
+ mc_r11 uint64
+ mc_r12 uint64
+ mc_r13 uint64
+ mc_r14 uint64
+ mc_r15 uint64
+ mc_xflags uint64
+ mc_trapno uint64
+ mc_addr uint64
+ mc_flags uint64
+ mc_err uint64
+ mc_rip uint64
+ mc_cs uint64
+ mc_rflags uint64
+ mc_rsp uint64
+ mc_ss uint64
+ mc_len uint32
+ mc_fpformat uint32
+ mc_ownedfp uint32
+ mc_reserved uint32
+ mc_unused [8]uint32
+ mc_fpregs [256]int32
+}
+
+type ucontext struct {
+ uc_sigmask sigset
+ pad_cgo_0 [48]byte
+ uc_mcontext mcontext
+ uc_link *ucontext
+ uc_stack stackt
+ __spare__ [8]int32
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = x
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = int64(x)
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type keventt struct {
+ ident uint64
+ filter int16
+ flags uint16
+ fflags uint32
+ data int64
+ udata *byte
+}
diff --git a/src/runtime/defs_dragonfly_amd64.h b/src/runtime/defs_dragonfly_amd64.h
deleted file mode 100644
index 671555241..000000000
--- a/src/runtime/defs_dragonfly_amd64.h
+++ /dev/null
@@ -1,208 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_dragonfly.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
- EBUSY = 0x10,
- EAGAIN = 0x23,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x5,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x2,
- FPE_INTOVF = 0x1,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
-};
-
-typedef struct Rtprio Rtprio;
-typedef struct Lwpparams Lwpparams;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct Rtprio {
- uint16 type;
- uint16 prio;
-};
-struct Lwpparams {
- void *func;
- byte *arg;
- byte *stack;
- int32 *tid1;
- int32 *tid2;
-};
-struct SigaltstackT {
- int8 *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-struct Sigset {
- uint32 __bits[4];
-};
-struct StackT {
- int8 *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- int32 si_pid;
- uint32 si_uid;
- int32 si_status;
- byte *si_addr;
- byte si_value[8];
- int64 si_band;
- int32 __spare__[7];
- byte Pad_cgo_0[4];
-};
-
-struct Mcontext {
- int64 mc_onstack;
- int64 mc_rdi;
- int64 mc_rsi;
- int64 mc_rdx;
- int64 mc_rcx;
- int64 mc_r8;
- int64 mc_r9;
- int64 mc_rax;
- int64 mc_rbx;
- int64 mc_rbp;
- int64 mc_r10;
- int64 mc_r11;
- int64 mc_r12;
- int64 mc_r13;
- int64 mc_r14;
- int64 mc_r15;
- int64 mc_xflags;
- int64 mc_trapno;
- int64 mc_addr;
- int64 mc_flags;
- int64 mc_err;
- int64 mc_rip;
- int64 mc_cs;
- int64 mc_rflags;
- int64 mc_rsp;
- int64 mc_ss;
- uint32 mc_len;
- uint32 mc_fpformat;
- uint32 mc_ownedfp;
- uint32 mc_reserved;
- uint32 mc_unused[8];
- int32 mc_fpregs[256];
-};
-struct Ucontext {
- Sigset uc_sigmask;
- byte Pad_cgo_0[48];
- Mcontext uc_mcontext;
- Ucontext *uc_link;
- StackT uc_stack;
- int32 __spare__[8];
-};
-
-struct Timespec {
- int64 tv_sec;
- int64 tv_nsec;
-};
-struct Timeval {
- int64 tv_sec;
- int64 tv_usec;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct KeventT {
- uint64 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int64 data;
- byte *udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_freebsd_386.go b/src/runtime/defs_freebsd_386.go
new file mode 100644
index 000000000..6938c1873
--- /dev/null
+++ b/src/runtime/defs_freebsd_386.go
@@ -0,0 +1,213 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_freebsd.go
+
+package runtime
+
+import "unsafe"
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x5
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _UMTX_OP_WAIT_UINT = 0xb
+ _UMTX_OP_WAIT_UINT_PRIVATE = 0xf
+ _UMTX_OP_WAKE = 0x3
+ _UMTX_OP_WAKE_PRIVATE = 0x10
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x2
+ _FPE_INTOVF = 0x1
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_RECEIPT = 0x40
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type rtprio struct {
+ _type uint16
+ prio uint16
+}
+
+type thrparam struct {
+ start_func uintptr
+ arg unsafe.Pointer
+ stack_base uintptr
+ stack_size uintptr
+ tls_base unsafe.Pointer
+ tls_size uintptr
+ child_tid unsafe.Pointer // *int32
+ parent_tid *int32
+ flags int32
+ rtp *rtprio
+ spare [3]uintptr
+}
+
+type sigaltstackt struct {
+ ss_sp *int8
+ ss_size uint32
+ ss_flags int32
+}
+
+type sigset struct {
+ __bits [4]uint32
+}
+
+type stackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ si_pid int32
+ si_uid uint32
+ si_status int32
+ si_addr uintptr
+ si_value [4]byte
+ _reason [32]byte
+}
+
+type mcontext struct {
+ mc_onstack uint32
+ mc_gs uint32
+ mc_fs uint32
+ mc_es uint32
+ mc_ds uint32
+ mc_edi uint32
+ mc_esi uint32
+ mc_ebp uint32
+ mc_isp uint32
+ mc_ebx uint32
+ mc_edx uint32
+ mc_ecx uint32
+ mc_eax uint32
+ mc_trapno uint32
+ mc_err uint32
+ mc_eip uint32
+ mc_cs uint32
+ mc_eflags uint32
+ mc_esp uint32
+ mc_ss uint32
+ mc_len uint32
+ mc_fpformat uint32
+ mc_ownedfp uint32
+ mc_flags uint32
+ mc_fpstate [128]uint32
+ mc_fsbase uint32
+ mc_gsbase uint32
+ mc_xfpustate uint32
+ mc_xfpustate_len uint32
+ mc_spare2 [4]uint32
+}
+
+type ucontext struct {
+ uc_sigmask sigset
+ uc_mcontext mcontext
+ uc_link *ucontext
+ uc_stack stackt
+ uc_flags int32
+ __spare__ [4]int32
+ pad_cgo_0 [12]byte
+}
+
+type timespec struct {
+ tv_sec int32
+ tv_nsec int32
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = int32(x)
+}
+
+type timeval struct {
+ tv_sec int32
+ tv_usec int32
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type keventt struct {
+ ident uint32
+ filter int16
+ flags uint16
+ fflags uint32
+ data int32
+ udata *byte
+}
diff --git a/src/runtime/defs_freebsd_386.h b/src/runtime/defs_freebsd_386.h
deleted file mode 100644
index 156dccba4..000000000
--- a/src/runtime/defs_freebsd_386.h
+++ /dev/null
@@ -1,213 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_freebsd.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x5,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
-
- UMTX_OP_WAIT_UINT = 0xb,
- UMTX_OP_WAIT_UINT_PRIVATE = 0xf,
- UMTX_OP_WAKE = 0x3,
- UMTX_OP_WAKE_PRIVATE = 0x10,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x2,
- FPE_INTOVF = 0x1,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_RECEIPT = 0x40,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
-};
-
-typedef struct Rtprio Rtprio;
-typedef struct ThrParam ThrParam;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct Rtprio {
- uint16 type;
- uint16 prio;
-};
-struct ThrParam {
- void *start_func;
- byte *arg;
- int8 *stack_base;
- uint32 stack_size;
- int8 *tls_base;
- uint32 tls_size;
- int32 *child_tid;
- int32 *parent_tid;
- int32 flags;
- Rtprio *rtp;
- void *spare[3];
-};
-struct SigaltstackT {
- int8 *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-struct Sigset {
- uint32 __bits[4];
-};
-struct StackT {
- int8 *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- int32 si_pid;
- uint32 si_uid;
- int32 si_status;
- byte *si_addr;
- byte si_value[4];
- byte _reason[32];
-};
-
-struct Mcontext {
- int32 mc_onstack;
- int32 mc_gs;
- int32 mc_fs;
- int32 mc_es;
- int32 mc_ds;
- int32 mc_edi;
- int32 mc_esi;
- int32 mc_ebp;
- int32 mc_isp;
- int32 mc_ebx;
- int32 mc_edx;
- int32 mc_ecx;
- int32 mc_eax;
- int32 mc_trapno;
- int32 mc_err;
- int32 mc_eip;
- int32 mc_cs;
- int32 mc_eflags;
- int32 mc_esp;
- int32 mc_ss;
- int32 mc_len;
- int32 mc_fpformat;
- int32 mc_ownedfp;
- int32 mc_flags;
- int32 mc_fpstate[128];
- int32 mc_fsbase;
- int32 mc_gsbase;
- int32 mc_xfpustate;
- int32 mc_xfpustate_len;
- int32 mc_spare2[4];
-};
-struct Ucontext {
- Sigset uc_sigmask;
- Mcontext uc_mcontext;
- Ucontext *uc_link;
- StackT uc_stack;
- int32 uc_flags;
- int32 __spare__[4];
- byte Pad_cgo_0[12];
-};
-
-struct Timespec {
- int32 tv_sec;
- int32 tv_nsec;
-};
-struct Timeval {
- int32 tv_sec;
- int32 tv_usec;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct KeventT {
- uint32 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int32 data;
- byte *udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_freebsd_amd64.go b/src/runtime/defs_freebsd_amd64.go
new file mode 100644
index 000000000..de98e7a3c
--- /dev/null
+++ b/src/runtime/defs_freebsd_amd64.go
@@ -0,0 +1,224 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_freebsd.go
+
+package runtime
+
+import "unsafe"
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x5
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _UMTX_OP_WAIT_UINT = 0xb
+ _UMTX_OP_WAIT_UINT_PRIVATE = 0xf
+ _UMTX_OP_WAKE = 0x3
+ _UMTX_OP_WAKE_PRIVATE = 0x10
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x2
+ _FPE_INTOVF = 0x1
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_RECEIPT = 0x40
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type rtprio struct {
+ _type uint16
+ prio uint16
+}
+
+type thrparam struct {
+ start_func uintptr
+ arg unsafe.Pointer
+ stack_base uintptr
+ stack_size uintptr
+ tls_base unsafe.Pointer
+ tls_size uintptr
+ child_tid unsafe.Pointer // *int64
+ parent_tid *int64
+ flags int32
+ pad_cgo_0 [4]byte
+ rtp *rtprio
+ spare [3]uintptr
+}
+
+type sigaltstackt struct {
+ ss_sp *int8
+ ss_size uint64
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type sigset struct {
+ __bits [4]uint32
+}
+
+type stackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ si_pid int32
+ si_uid uint32
+ si_status int32
+ si_addr uint64
+ si_value [8]byte
+ _reason [40]byte
+}
+
+type mcontext struct {
+ mc_onstack uint64
+ mc_rdi uint64
+ mc_rsi uint64
+ mc_rdx uint64
+ mc_rcx uint64
+ mc_r8 uint64
+ mc_r9 uint64
+ mc_rax uint64
+ mc_rbx uint64
+ mc_rbp uint64
+ mc_r10 uint64
+ mc_r11 uint64
+ mc_r12 uint64
+ mc_r13 uint64
+ mc_r14 uint64
+ mc_r15 uint64
+ mc_trapno uint32
+ mc_fs uint16
+ mc_gs uint16
+ mc_addr uint64
+ mc_flags uint32
+ mc_es uint16
+ mc_ds uint16
+ mc_err uint64
+ mc_rip uint64
+ mc_cs uint64
+ mc_rflags uint64
+ mc_rsp uint64
+ mc_ss uint64
+ mc_len uint64
+ mc_fpformat uint64
+ mc_ownedfp uint64
+ mc_fpstate [64]uint64
+ mc_fsbase uint64
+ mc_gsbase uint64
+ mc_xfpustate uint64
+ mc_xfpustate_len uint64
+ mc_spare [4]uint64
+}
+
+type ucontext struct {
+ uc_sigmask sigset
+ uc_mcontext mcontext
+ uc_link *ucontext
+ uc_stack stackt
+ uc_flags int32
+ __spare__ [4]int32
+ pad_cgo_0 [12]byte
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = x
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = int64(x)
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type keventt struct {
+ ident uint64
+ filter int16
+ flags uint16
+ fflags uint32
+ data int64
+ udata *byte
+}
diff --git a/src/runtime/defs_freebsd_amd64.h b/src/runtime/defs_freebsd_amd64.h
deleted file mode 100644
index 4ba8956a2..000000000
--- a/src/runtime/defs_freebsd_amd64.h
+++ /dev/null
@@ -1,224 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_freebsd.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x5,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
-
- UMTX_OP_WAIT_UINT = 0xb,
- UMTX_OP_WAIT_UINT_PRIVATE = 0xf,
- UMTX_OP_WAKE = 0x3,
- UMTX_OP_WAKE_PRIVATE = 0x10,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x2,
- FPE_INTOVF = 0x1,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_RECEIPT = 0x40,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
-};
-
-typedef struct Rtprio Rtprio;
-typedef struct ThrParam ThrParam;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct Rtprio {
- uint16 type;
- uint16 prio;
-};
-struct ThrParam {
- void *start_func;
- byte *arg;
- int8 *stack_base;
- uint64 stack_size;
- int8 *tls_base;
- uint64 tls_size;
- int64 *child_tid;
- int64 *parent_tid;
- int32 flags;
- byte Pad_cgo_0[4];
- Rtprio *rtp;
- void *spare[3];
-};
-struct SigaltstackT {
- int8 *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-struct Sigset {
- uint32 __bits[4];
-};
-struct StackT {
- int8 *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- int32 si_pid;
- uint32 si_uid;
- int32 si_status;
- byte *si_addr;
- byte si_value[8];
- byte _reason[40];
-};
-
-struct Mcontext {
- int64 mc_onstack;
- int64 mc_rdi;
- int64 mc_rsi;
- int64 mc_rdx;
- int64 mc_rcx;
- int64 mc_r8;
- int64 mc_r9;
- int64 mc_rax;
- int64 mc_rbx;
- int64 mc_rbp;
- int64 mc_r10;
- int64 mc_r11;
- int64 mc_r12;
- int64 mc_r13;
- int64 mc_r14;
- int64 mc_r15;
- uint32 mc_trapno;
- uint16 mc_fs;
- uint16 mc_gs;
- int64 mc_addr;
- uint32 mc_flags;
- uint16 mc_es;
- uint16 mc_ds;
- int64 mc_err;
- int64 mc_rip;
- int64 mc_cs;
- int64 mc_rflags;
- int64 mc_rsp;
- int64 mc_ss;
- int64 mc_len;
- int64 mc_fpformat;
- int64 mc_ownedfp;
- int64 mc_fpstate[64];
- int64 mc_fsbase;
- int64 mc_gsbase;
- int64 mc_xfpustate;
- int64 mc_xfpustate_len;
- int64 mc_spare[4];
-};
-struct Ucontext {
- Sigset uc_sigmask;
- Mcontext uc_mcontext;
- Ucontext *uc_link;
- StackT uc_stack;
- int32 uc_flags;
- int32 __spare__[4];
- byte Pad_cgo_0[12];
-};
-
-struct Timespec {
- int64 tv_sec;
- int64 tv_nsec;
-};
-struct Timeval {
- int64 tv_sec;
- int64 tv_usec;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct KeventT {
- uint64 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int64 data;
- byte *udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_freebsd_arm.go b/src/runtime/defs_freebsd_arm.go
new file mode 100644
index 000000000..744330f4b
--- /dev/null
+++ b/src/runtime/defs_freebsd_arm.go
@@ -0,0 +1,186 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_freebsd.go
+
+package runtime
+
+import "unsafe"
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x5
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _UMTX_OP_WAIT_UINT = 0xb
+ _UMTX_OP_WAIT_UINT_PRIVATE = 0xf
+ _UMTX_OP_WAKE = 0x3
+ _UMTX_OP_WAKE_PRIVATE = 0x10
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x2
+ _FPE_INTOVF = 0x1
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_RECEIPT = 0x40
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type rtprio struct {
+ _type uint16
+ prio uint16
+}
+
+type thrparam struct {
+ start_func uintptr
+ arg unsafe.Pointer
+ stack_base uintptr
+ stack_size uintptr
+ tls_base unsafe.Pointer
+ tls_size uintptr
+ child_tid unsafe.Pointer // *int32
+ parent_tid *int32
+ flags int32
+ rtp *rtprio
+ spare [3]uintptr
+}
+
+type sigaltstackt struct {
+ ss_sp *uint8
+ ss_size uint32
+ ss_flags int32
+}
+
+type sigset struct {
+ __bits [4]uint32
+}
+
+type stackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ si_pid int32
+ si_uid uint32
+ si_status int32
+ si_addr uintptr
+ si_value [4]byte
+ _reason [32]byte
+}
+
+type mcontext struct {
+ __gregs [17]uint32
+ __fpu [140]byte
+}
+
+type ucontext struct {
+ uc_sigmask sigset
+ uc_mcontext mcontext
+ uc_link *ucontext
+ uc_stack stackt
+ uc_flags int32
+ __spare__ [4]int32
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int32
+ pad_cgo_0 [4]byte
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = x
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int32
+ pad_cgo_0 [4]byte
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type keventt struct {
+ ident uint32
+ filter int16
+ flags uint16
+ fflags uint32
+ data int32
+ udata *byte
+}
diff --git a/src/runtime/defs_freebsd_arm.h b/src/runtime/defs_freebsd_arm.h
deleted file mode 100644
index 17deba68d..000000000
--- a/src/runtime/defs_freebsd_arm.h
+++ /dev/null
@@ -1,186 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_freebsd.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x5,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
-
- UMTX_OP_WAIT_UINT = 0xb,
- UMTX_OP_WAIT_UINT_PRIVATE = 0xf,
- UMTX_OP_WAKE = 0x3,
- UMTX_OP_WAKE_PRIVATE = 0x10,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x2,
- FPE_INTOVF = 0x1,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_RECEIPT = 0x40,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
-};
-
-typedef struct Rtprio Rtprio;
-typedef struct ThrParam ThrParam;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct Rtprio {
- uint16 type;
- uint16 prio;
-};
-struct ThrParam {
- void *start_func;
- byte *arg;
- uint8 *stack_base;
- uint32 stack_size;
- uint8 *tls_base;
- uint32 tls_size;
- int32 *child_tid;
- int32 *parent_tid;
- int32 flags;
- Rtprio *rtp;
- void *spare[3];
-};
-struct SigaltstackT {
- uint8 *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-struct Sigset {
- uint32 __bits[4];
-};
-struct StackT {
- uint8 *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- int32 si_pid;
- uint32 si_uid;
- int32 si_status;
- byte *si_addr;
- byte si_value[4];
- byte _reason[32];
-};
-
-struct Mcontext {
- uint32 __gregs[17];
- byte __fpu[140];
-};
-struct Ucontext {
- Sigset uc_sigmask;
- Mcontext uc_mcontext;
- Ucontext *uc_link;
- StackT uc_stack;
- int32 uc_flags;
- int32 __spare__[4];
-};
-
-struct Timespec {
- int64 tv_sec;
- int32 tv_nsec;
- byte Pad_cgo_0[4];
-};
-struct Timeval {
- int64 tv_sec;
- int32 tv_usec;
- byte Pad_cgo_0[4];
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct KeventT {
- uint32 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int32 data;
- byte *udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_linux.go b/src/runtime/defs_linux.go
index 8657dbb0e..553366a50 100644
--- a/src/runtime/defs_linux.go
+++ b/src/runtime/defs_linux.go
@@ -20,6 +20,7 @@ package runtime
// headers for things like ucontext_t, so that happens in
// a separate file, defs1.go.
+#define _SYS_TYPES_H // avoid inclusion of sys/types.h
#include <asm/posix_types.h>
#define size_t __kernel_size_t
#include <asm/signal.h>
@@ -28,7 +29,7 @@ package runtime
#include <asm-generic/errno.h>
#include <asm-generic/poll.h>
#include <linux/eventpoll.h>
-#undef size_t
+#include <linux/time.h>
*/
import "C"
@@ -48,10 +49,9 @@ const (
MADV_DONTNEED = C.MADV_DONTNEED
- SA_RESTART = C.SA_RESTART
- SA_ONSTACK = C.SA_ONSTACK
- SA_RESTORER = C.SA_RESTORER
- SA_SIGINFO = C.SA_SIGINFO
+ SA_RESTART = C.SA_RESTART
+ SA_ONSTACK = C.SA_ONSTACK
+ SA_SIGINFO = C.SA_SIGINFO
SIGHUP = C.SIGHUP
SIGINT = C.SIGINT
@@ -116,6 +116,7 @@ const (
EPOLL_CTL_MOD = C.EPOLL_CTL_MOD
)
+type Sigset C.sigset_t
type Timespec C.struct_timespec
type Timeval C.struct_timeval
type Sigaction C.struct_sigaction
diff --git a/src/runtime/defs_linux_386.go b/src/runtime/defs_linux_386.go
new file mode 100644
index 000000000..f55924b61
--- /dev/null
+++ b/src/runtime/defs_linux_386.go
@@ -0,0 +1,218 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs2_linux.go
+
+package runtime
+
+const (
+ _EINTR = 0x4
+ _EAGAIN = 0xb
+ _ENOMEM = 0xc
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x20
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_DONTNEED = 0x4
+
+ _SA_RESTART = 0x10000000
+ _SA_ONSTACK = 0x8000000
+ _SA_RESTORER = 0x4000000
+ _SA_SIGINFO = 0x4
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGBUS = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGUSR1 = 0xa
+ _SIGSEGV = 0xb
+ _SIGUSR2 = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGSTKFLT = 0x10
+ _SIGCHLD = 0x11
+ _SIGCONT = 0x12
+ _SIGSTOP = 0x13
+ _SIGTSTP = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGURG = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGIO = 0x1d
+ _SIGPWR = 0x1e
+ _SIGSYS = 0x1f
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _O_RDONLY = 0x0
+ _O_CLOEXEC = 0x80000
+
+ _EPOLLIN = 0x1
+ _EPOLLOUT = 0x4
+ _EPOLLERR = 0x8
+ _EPOLLHUP = 0x10
+ _EPOLLRDHUP = 0x2000
+ _EPOLLET = 0x80000000
+ _EPOLL_CLOEXEC = 0x80000
+ _EPOLL_CTL_ADD = 0x1
+ _EPOLL_CTL_DEL = 0x2
+ _EPOLL_CTL_MOD = 0x3
+)
+
+type fpreg struct {
+ significand [4]uint16
+ exponent uint16
+}
+
+type fpxreg struct {
+ significand [4]uint16
+ exponent uint16
+ padding [3]uint16
+}
+
+type xmmreg struct {
+ element [4]uint32
+}
+
+type fpstate struct {
+ cw uint32
+ sw uint32
+ tag uint32
+ ipoff uint32
+ cssel uint32
+ dataoff uint32
+ datasel uint32
+ _st [8]fpreg
+ status uint16
+ magic uint16
+ _fxsr_env [6]uint32
+ mxcsr uint32
+ reserved uint32
+ _fxsr_st [8]fpxreg
+ _xmm [8]xmmreg
+ padding1 [44]uint32
+ anon0 [48]byte
+}
+
+type timespec struct {
+ tv_sec int32
+ tv_nsec int32
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = int32(x)
+}
+
+func (ts *timespec) set_nsec(x int32) {
+ ts.tv_nsec = x
+}
+
+type timeval struct {
+ tv_sec int32
+ tv_usec int32
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type sigactiont struct {
+ sa_handler uintptr
+ sa_flags uint32
+ sa_restorer uintptr
+ sa_mask uint64
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ // below here is a union; si_addr is the only field we use
+ si_addr uint32
+}
+
+type sigaltstackt struct {
+ ss_sp *byte
+ ss_flags int32
+ ss_size uintptr
+}
+
+type sigcontext struct {
+ gs uint16
+ __gsh uint16
+ fs uint16
+ __fsh uint16
+ es uint16
+ __esh uint16
+ ds uint16
+ __dsh uint16
+ edi uint32
+ esi uint32
+ ebp uint32
+ esp uint32
+ ebx uint32
+ edx uint32
+ ecx uint32
+ eax uint32
+ trapno uint32
+ err uint32
+ eip uint32
+ cs uint16
+ __csh uint16
+ eflags uint32
+ esp_at_signal uint32
+ ss uint16
+ __ssh uint16
+ fpstate *fpstate
+ oldmask uint32
+ cr2 uint32
+}
+
+type ucontext struct {
+ uc_flags uint32
+ uc_link *ucontext
+ uc_stack sigaltstackt
+ uc_mcontext sigcontext
+ uc_sigmask uint32
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type epollevent struct {
+ events uint32
+ data [8]byte // to match amd64
+}
diff --git a/src/runtime/defs_linux_386.h b/src/runtime/defs_linux_386.h
deleted file mode 100644
index 24a05d862..000000000
--- a/src/runtime/defs_linux_386.h
+++ /dev/null
@@ -1,211 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs2_linux.go
-
-
-enum {
- EINTR = 0x4,
- EAGAIN = 0xb,
- ENOMEM = 0xc,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x20,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_DONTNEED = 0x4,
-
- SA_RESTART = 0x10000000,
- SA_ONSTACK = 0x8000000,
- SA_RESTORER = 0x4000000,
- SA_SIGINFO = 0x4,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGBUS = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGUSR1 = 0xa,
- SIGSEGV = 0xb,
- SIGUSR2 = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGSTKFLT = 0x10,
- SIGCHLD = 0x11,
- SIGCONT = 0x12,
- SIGSTOP = 0x13,
- SIGTSTP = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGURG = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGIO = 0x1d,
- SIGPWR = 0x1e,
- SIGSYS = 0x1f,
-
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- O_RDONLY = 0x0,
- O_CLOEXEC = 0x80000,
-
- EPOLLIN = 0x1,
- EPOLLOUT = 0x4,
- EPOLLERR = 0x8,
- EPOLLHUP = 0x10,
- EPOLLRDHUP = 0x2000,
- EPOLLET = -0x80000000,
- EPOLL_CLOEXEC = 0x80000,
- EPOLL_CTL_ADD = 0x1,
- EPOLL_CTL_DEL = 0x2,
- EPOLL_CTL_MOD = 0x3,
-};
-
-typedef struct Fpreg Fpreg;
-typedef struct Fpxreg Fpxreg;
-typedef struct Xmmreg Xmmreg;
-typedef struct Fpstate Fpstate;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct SigactionT SigactionT;
-typedef struct Siginfo Siginfo;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigcontext Sigcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Itimerval Itimerval;
-typedef struct EpollEvent EpollEvent;
-
-#pragma pack on
-
-struct Fpreg {
- uint16 significand[4];
- uint16 exponent;
-};
-struct Fpxreg {
- uint16 significand[4];
- uint16 exponent;
- uint16 padding[3];
-};
-struct Xmmreg {
- uint32 element[4];
-};
-struct Fpstate {
- uint32 cw;
- uint32 sw;
- uint32 tag;
- uint32 ipoff;
- uint32 cssel;
- uint32 dataoff;
- uint32 datasel;
- Fpreg _st[8];
- uint16 status;
- uint16 magic;
- uint32 _fxsr_env[6];
- uint32 mxcsr;
- uint32 reserved;
- Fpxreg _fxsr_st[8];
- Xmmreg _xmm[8];
- uint32 padding1[44];
- byte anon0[48];
-};
-struct Timespec {
- int32 tv_sec;
- int32 tv_nsec;
-};
-struct Timeval {
- int32 tv_sec;
- int32 tv_usec;
-};
-struct SigactionT {
- void *k_sa_handler;
- uint32 sa_flags;
- void *sa_restorer;
- uint64 sa_mask;
-};
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- byte _sifields[116];
-};
-struct SigaltstackT {
- byte *ss_sp;
- int32 ss_flags;
- uint32 ss_size;
-};
-struct Sigcontext {
- uint16 gs;
- uint16 __gsh;
- uint16 fs;
- uint16 __fsh;
- uint16 es;
- uint16 __esh;
- uint16 ds;
- uint16 __dsh;
- uint32 edi;
- uint32 esi;
- uint32 ebp;
- uint32 esp;
- uint32 ebx;
- uint32 edx;
- uint32 ecx;
- uint32 eax;
- uint32 trapno;
- uint32 err;
- uint32 eip;
- uint16 cs;
- uint16 __csh;
- uint32 eflags;
- uint32 esp_at_signal;
- uint16 ss;
- uint16 __ssh;
- Fpstate *fpstate;
- uint32 oldmask;
- uint32 cr2;
-};
-struct Ucontext {
- uint32 uc_flags;
- Ucontext *uc_link;
- SigaltstackT uc_stack;
- Sigcontext uc_mcontext;
- uint32 uc_sigmask;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-struct EpollEvent {
- uint32 events;
- byte data[8]; // to match amd64
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_linux_amd64.go b/src/runtime/defs_linux_amd64.go
new file mode 100644
index 000000000..a73f47514
--- /dev/null
+++ b/src/runtime/defs_linux_amd64.go
@@ -0,0 +1,253 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs1_linux.go
+
+package runtime
+
+const (
+ _EINTR = 0x4
+ _EAGAIN = 0xb
+ _ENOMEM = 0xc
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x20
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_DONTNEED = 0x4
+
+ _SA_RESTART = 0x10000000
+ _SA_ONSTACK = 0x8000000
+ _SA_RESTORER = 0x4000000
+ _SA_SIGINFO = 0x4
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGBUS = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGUSR1 = 0xa
+ _SIGSEGV = 0xb
+ _SIGUSR2 = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGSTKFLT = 0x10
+ _SIGCHLD = 0x11
+ _SIGCONT = 0x12
+ _SIGSTOP = 0x13
+ _SIGTSTP = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGURG = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGIO = 0x1d
+ _SIGPWR = 0x1e
+ _SIGSYS = 0x1f
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EPOLLIN = 0x1
+ _EPOLLOUT = 0x4
+ _EPOLLERR = 0x8
+ _EPOLLHUP = 0x10
+ _EPOLLRDHUP = 0x2000
+ _EPOLLET = 0x80000000
+ _EPOLL_CLOEXEC = 0x80000
+ _EPOLL_CTL_ADD = 0x1
+ _EPOLL_CTL_DEL = 0x2
+ _EPOLL_CTL_MOD = 0x3
+)
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = x
+}
+
+func (ts *timespec) set_nsec(x int32) {
+ ts.tv_nsec = int64(x)
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = int64(x)
+}
+
+type sigactiont struct {
+ sa_handler uintptr
+ sa_flags uint64
+ sa_restorer uintptr
+ sa_mask uint64
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ // below here is a union; si_addr is the only field we use
+ si_addr uint64
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type epollevent struct {
+ events uint32
+ data [8]byte // unaligned uintptr
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs1_linux.go
+
+const (
+ _O_RDONLY = 0x0
+ _O_CLOEXEC = 0x80000
+)
+
+type usigset struct {
+ __val [16]uint64
+}
+
+type fpxreg struct {
+ significand [4]uint16
+ exponent uint16
+ padding [3]uint16
+}
+
+type xmmreg struct {
+ element [4]uint32
+}
+
+type fpstate struct {
+ cwd uint16
+ swd uint16
+ ftw uint16
+ fop uint16
+ rip uint64
+ rdp uint64
+ mxcsr uint32
+ mxcr_mask uint32
+ _st [8]fpxreg
+ _xmm [16]xmmreg
+ padding [24]uint32
+}
+
+type fpxreg1 struct {
+ significand [4]uint16
+ exponent uint16
+ padding [3]uint16
+}
+
+type xmmreg1 struct {
+ element [4]uint32
+}
+
+type fpstate1 struct {
+ cwd uint16
+ swd uint16
+ ftw uint16
+ fop uint16
+ rip uint64
+ rdp uint64
+ mxcsr uint32
+ mxcr_mask uint32
+ _st [8]fpxreg1
+ _xmm [16]xmmreg1
+ padding [24]uint32
+}
+
+type fpreg1 struct {
+ significand [4]uint16
+ exponent uint16
+}
+
+type sigaltstackt struct {
+ ss_sp *byte
+ ss_flags int32
+ pad_cgo_0 [4]byte
+ ss_size uintptr
+}
+
+type mcontext struct {
+ gregs [23]uint64
+ fpregs *fpstate
+ __reserved1 [8]uint64
+}
+
+type ucontext struct {
+ uc_flags uint64
+ uc_link *ucontext
+ uc_stack sigaltstackt
+ uc_mcontext mcontext
+ uc_sigmask usigset
+ __fpregs_mem fpstate
+}
+
+type sigcontext struct {
+ r8 uint64
+ r9 uint64
+ r10 uint64
+ r11 uint64
+ r12 uint64
+ r13 uint64
+ r14 uint64
+ r15 uint64
+ rdi uint64
+ rsi uint64
+ rbp uint64
+ rbx uint64
+ rdx uint64
+ rax uint64
+ rcx uint64
+ rsp uint64
+ rip uint64
+ eflags uint64
+ cs uint16
+ gs uint16
+ fs uint16
+ __pad0 uint16
+ err uint64
+ trapno uint64
+ oldmask uint64
+ cr2 uint64
+ fpstate *fpstate1
+ __reserved1 [8]uint64
+}
diff --git a/src/runtime/defs_linux_amd64.h b/src/runtime/defs_linux_amd64.h
deleted file mode 100644
index 14616dffe..000000000
--- a/src/runtime/defs_linux_amd64.h
+++ /dev/null
@@ -1,254 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_linux.go defs1_linux.go
-
-
-enum {
- EINTR = 0x4,
- EAGAIN = 0xb,
- ENOMEM = 0xc,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x20,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_DONTNEED = 0x4,
-
- SA_RESTART = 0x10000000,
- SA_ONSTACK = 0x8000000,
- SA_RESTORER = 0x4000000,
- SA_SIGINFO = 0x4,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGBUS = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGUSR1 = 0xa,
- SIGSEGV = 0xb,
- SIGUSR2 = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGSTKFLT = 0x10,
- SIGCHLD = 0x11,
- SIGCONT = 0x12,
- SIGSTOP = 0x13,
- SIGTSTP = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGURG = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGIO = 0x1d,
- SIGPWR = 0x1e,
- SIGSYS = 0x1f,
-
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EPOLLIN = 0x1,
- EPOLLOUT = 0x4,
- EPOLLERR = 0x8,
- EPOLLHUP = 0x10,
- EPOLLRDHUP = 0x2000,
- EPOLLET = -0x80000000,
- EPOLL_CLOEXEC = 0x80000,
- EPOLL_CTL_ADD = 0x1,
- EPOLL_CTL_DEL = 0x2,
- EPOLL_CTL_MOD = 0x3,
-};
-
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct SigactionT SigactionT;
-typedef struct Siginfo Siginfo;
-typedef struct Itimerval Itimerval;
-typedef struct EpollEvent EpollEvent;
-
-#pragma pack on
-
-struct Timespec {
- int64 tv_sec;
- int64 tv_nsec;
-};
-struct Timeval {
- int64 tv_sec;
- int64 tv_usec;
-};
-struct SigactionT {
- void *sa_handler;
- uint64 sa_flags;
- void *sa_restorer;
- uint64 sa_mask;
-};
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- byte Pad_cgo_0[4];
- byte _sifields[112];
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-struct EpollEvent {
- uint32 events;
- byte data[8]; // unaligned uintptr
-};
-
-
-#pragma pack off
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_linux.go defs1_linux.go
-
-
-enum {
- O_RDONLY = 0x0,
- O_CLOEXEC = 0x80000,
-};
-
-typedef struct Usigset Usigset;
-typedef struct Fpxreg Fpxreg;
-typedef struct Xmmreg Xmmreg;
-typedef struct Fpstate Fpstate;
-typedef struct Fpxreg1 Fpxreg1;
-typedef struct Xmmreg1 Xmmreg1;
-typedef struct Fpstate1 Fpstate1;
-typedef struct Fpreg1 Fpreg1;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Sigcontext Sigcontext;
-
-#pragma pack on
-
-struct Usigset {
- uint64 __val[16];
-};
-struct Fpxreg {
- uint16 significand[4];
- uint16 exponent;
- uint16 padding[3];
-};
-struct Xmmreg {
- uint32 element[4];
-};
-struct Fpstate {
- uint16 cwd;
- uint16 swd;
- uint16 ftw;
- uint16 fop;
- uint64 rip;
- uint64 rdp;
- uint32 mxcsr;
- uint32 mxcr_mask;
- Fpxreg _st[8];
- Xmmreg _xmm[16];
- uint32 padding[24];
-};
-struct Fpxreg1 {
- uint16 significand[4];
- uint16 exponent;
- uint16 padding[3];
-};
-struct Xmmreg1 {
- uint32 element[4];
-};
-struct Fpstate1 {
- uint16 cwd;
- uint16 swd;
- uint16 ftw;
- uint16 fop;
- uint64 rip;
- uint64 rdp;
- uint32 mxcsr;
- uint32 mxcr_mask;
- Fpxreg1 _st[8];
- Xmmreg1 _xmm[16];
- uint32 padding[24];
-};
-struct Fpreg1 {
- uint16 significand[4];
- uint16 exponent;
-};
-struct SigaltstackT {
- byte *ss_sp;
- int32 ss_flags;
- byte Pad_cgo_0[4];
- uint64 ss_size;
-};
-struct Mcontext {
- int64 gregs[23];
- Fpstate *fpregs;
- uint64 __reserved1[8];
-};
-struct Ucontext {
- uint64 uc_flags;
- Ucontext *uc_link;
- SigaltstackT uc_stack;
- Mcontext uc_mcontext;
- Usigset uc_sigmask;
- Fpstate __fpregs_mem;
-};
-struct Sigcontext {
- uint64 r8;
- uint64 r9;
- uint64 r10;
- uint64 r11;
- uint64 r12;
- uint64 r13;
- uint64 r14;
- uint64 r15;
- uint64 rdi;
- uint64 rsi;
- uint64 rbp;
- uint64 rbx;
- uint64 rdx;
- uint64 rax;
- uint64 rcx;
- uint64 rsp;
- uint64 rip;
- uint64 eflags;
- uint16 cs;
- uint16 gs;
- uint16 fs;
- uint16 __pad0;
- uint64 err;
- uint64 trapno;
- uint64 oldmask;
- uint64 cr2;
- Fpstate1 *fpstate;
- uint64 __reserved1[8];
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_linux_arm.go b/src/runtime/defs_linux_arm.go
new file mode 100644
index 000000000..c3a6e2f01
--- /dev/null
+++ b/src/runtime/defs_linux_arm.go
@@ -0,0 +1,168 @@
+package runtime
+
+// Constants
+const (
+ _EINTR = 0x4
+ _ENOMEM = 0xc
+ _EAGAIN = 0xb
+
+ _PROT_NONE = 0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+ _MAP_ANON = 0x20
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+ _MADV_DONTNEED = 0x4
+ _SA_RESTART = 0x10000000
+ _SA_ONSTACK = 0x8000000
+ _SA_RESTORER = 0 // unused on ARM
+ _SA_SIGINFO = 0x4
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGBUS = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGUSR1 = 0xa
+ _SIGSEGV = 0xb
+ _SIGUSR2 = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGSTKFLT = 0x10
+ _SIGCHLD = 0x11
+ _SIGCONT = 0x12
+ _SIGSTOP = 0x13
+ _SIGTSTP = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGURG = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGIO = 0x1d
+ _SIGPWR = 0x1e
+ _SIGSYS = 0x1f
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+ _ITIMER_REAL = 0
+ _ITIMER_PROF = 0x2
+ _ITIMER_VIRTUAL = 0x1
+ _O_RDONLY = 0
+ _O_CLOEXEC = 02000000
+
+ _EPOLLIN = 0x1
+ _EPOLLOUT = 0x4
+ _EPOLLERR = 0x8
+ _EPOLLHUP = 0x10
+ _EPOLLRDHUP = 0x2000
+ _EPOLLET = 0x80000000
+ _EPOLL_CLOEXEC = 0x80000
+ _EPOLL_CTL_ADD = 0x1
+ _EPOLL_CTL_DEL = 0x2
+ _EPOLL_CTL_MOD = 0x3
+)
+
+type timespec struct {
+ tv_sec int32
+ tv_nsec int32
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = int32(x)
+}
+
+func (ts *timespec) set_nsec(x int32) {
+ ts.tv_nsec = x
+}
+
+type sigaltstackt struct {
+ ss_sp *byte
+ ss_flags int32
+ ss_size uintptr
+}
+
+type sigcontext struct {
+ trap_no uint32
+ error_code uint32
+ oldmask uint32
+ r0 uint32
+ r1 uint32
+ r2 uint32
+ r3 uint32
+ r4 uint32
+ r5 uint32
+ r6 uint32
+ r7 uint32
+ r8 uint32
+ r9 uint32
+ r10 uint32
+ fp uint32
+ ip uint32
+ sp uint32
+ lr uint32
+ pc uint32
+ cpsr uint32
+ fault_address uint32
+}
+
+type ucontext struct {
+ uc_flags uint32
+ uc_link *ucontext
+ uc_stack sigaltstackt
+ uc_mcontext sigcontext
+ uc_sigmask uint32
+ __unused [31]int32
+ uc_regspace [128]uint32
+}
+
+type timeval struct {
+ tv_sec int32
+ tv_usec int32
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ // below here is a union; si_addr is the only field we use
+ si_addr uint32
+}
+
+type sigactiont struct {
+ sa_handler uintptr
+ sa_flags uint32
+ sa_restorer uintptr
+ sa_mask uint64
+}
+
+type epollevent struct {
+ events uint32
+ _pad uint32
+ data [8]byte // to match amd64
+}
diff --git a/src/runtime/defs_linux_arm.h b/src/runtime/defs_linux_arm.h
deleted file mode 100644
index 50b3c919e..000000000
--- a/src/runtime/defs_linux_arm.h
+++ /dev/null
@@ -1,168 +0,0 @@
-// TODO: Generate using cgo like defs_linux_{386,amd64}.h
-
-// Constants
-enum {
- EINTR = 0x4,
- ENOMEM = 0xc,
- EAGAIN = 0xb,
-
- PROT_NONE = 0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
- MAP_ANON = 0x20,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
- MADV_DONTNEED = 0x4,
- SA_RESTART = 0x10000000,
- SA_ONSTACK = 0x8000000,
- SA_RESTORER = 0, // unused on ARM
- SA_SIGINFO = 0x4,
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGBUS = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGUSR1 = 0xa,
- SIGSEGV = 0xb,
- SIGUSR2 = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGSTKFLT = 0x10,
- SIGCHLD = 0x11,
- SIGCONT = 0x12,
- SIGSTOP = 0x13,
- SIGTSTP = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGURG = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGIO = 0x1d,
- SIGPWR = 0x1e,
- SIGSYS = 0x1f,
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
- ITIMER_REAL = 0,
- ITIMER_PROF = 0x2,
- ITIMER_VIRTUAL = 0x1,
- O_RDONLY = 0,
- O_CLOEXEC = 02000000,
-
- EPOLLIN = 0x1,
- EPOLLOUT = 0x4,
- EPOLLERR = 0x8,
- EPOLLHUP = 0x10,
- EPOLLRDHUP = 0x2000,
- EPOLLET = -0x80000000,
- EPOLL_CLOEXEC = 0x80000,
- EPOLL_CTL_ADD = 0x1,
- EPOLL_CTL_DEL = 0x2,
- EPOLL_CTL_MOD = 0x3,
-};
-
-// Types
-#pragma pack on
-
-typedef struct Timespec Timespec;
-struct Timespec {
- int32 tv_sec;
- int32 tv_nsec;
-};
-
-typedef struct SigaltstackT SigaltstackT;
-struct SigaltstackT {
- void *ss_sp;
- int32 ss_flags;
- uint32 ss_size;
-};
-
-typedef struct Sigcontext Sigcontext;
-struct Sigcontext {
- uint32 trap_no;
- uint32 error_code;
- uint32 oldmask;
- uint32 arm_r0;
- uint32 arm_r1;
- uint32 arm_r2;
- uint32 arm_r3;
- uint32 arm_r4;
- uint32 arm_r5;
- uint32 arm_r6;
- uint32 arm_r7;
- uint32 arm_r8;
- uint32 arm_r9;
- uint32 arm_r10;
- uint32 arm_fp;
- uint32 arm_ip;
- uint32 arm_sp;
- uint32 arm_lr;
- uint32 arm_pc;
- uint32 arm_cpsr;
- uint32 fault_address;
-};
-
-typedef struct Ucontext Ucontext;
-struct Ucontext {
- uint32 uc_flags;
- Ucontext *uc_link;
- SigaltstackT uc_stack;
- Sigcontext uc_mcontext;
- uint32 uc_sigmask;
- int32 __unused[31];
- uint32 uc_regspace[128];
-};
-
-typedef struct Timeval Timeval;
-struct Timeval {
- int32 tv_sec;
- int32 tv_usec;
-};
-
-typedef struct Itimerval Itimerval;
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-typedef struct Siginfo Siginfo;
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- uint8 _sifields[4];
-};
-
-typedef struct SigactionT SigactionT;
-struct SigactionT {
- void *sa_handler;
- uint32 sa_flags;
- void *sa_restorer;
- uint64 sa_mask;
-};
-
-typedef struct EpollEvent EpollEvent;
-struct EpollEvent {
- uint32 events;
- uint32 _pad;
- byte data[8]; // to match amd64
-};
-#pragma pack off
diff --git a/src/runtime/defs_linux_power64.go b/src/runtime/defs_linux_power64.go
new file mode 100644
index 000000000..f90b84874
--- /dev/null
+++ b/src/runtime/defs_linux_power64.go
@@ -0,0 +1,198 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs3_linux.go
+
+package runtime
+
+const (
+ _EINTR = 0x4
+ _EAGAIN = 0xb
+ _ENOMEM = 0xc
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x20
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_DONTNEED = 0x4
+
+ _SA_RESTART = 0x10000000
+ _SA_ONSTACK = 0x8000000
+ _SA_SIGINFO = 0x4
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGBUS = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGUSR1 = 0xa
+ _SIGSEGV = 0xb
+ _SIGUSR2 = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGSTKFLT = 0x10
+ _SIGCHLD = 0x11
+ _SIGCONT = 0x12
+ _SIGSTOP = 0x13
+ _SIGTSTP = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGURG = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGIO = 0x1d
+ _SIGPWR = 0x1e
+ _SIGSYS = 0x1f
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EPOLLIN = 0x1
+ _EPOLLOUT = 0x4
+ _EPOLLERR = 0x8
+ _EPOLLHUP = 0x10
+ _EPOLLRDHUP = 0x2000
+ _EPOLLET = 0x80000000
+ _EPOLL_CLOEXEC = 0x80000
+ _EPOLL_CTL_ADD = 0x1
+ _EPOLL_CTL_DEL = 0x2
+ _EPOLL_CTL_MOD = 0x3
+)
+
+//struct Sigset {
+// uint64 sig[1];
+//};
+//typedef uint64 Sigset;
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = x
+}
+
+func (ts *timespec) set_nsec(x int32) {
+ ts.tv_nsec = int64(x)
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = int64(x)
+}
+
+type sigactiont struct {
+ sa_handler uintptr
+ sa_flags uint64
+ sa_restorer uintptr
+ sa_mask uint64
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ // below here is a union; si_addr is the only field we use
+ si_addr uint64
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type epollevent struct {
+ events uint32
+ pad_cgo_0 [4]byte
+ data [8]byte // unaligned uintptr
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs3_linux.go
+
+const (
+ _O_RDONLY = 0x0
+ _O_CLOEXEC = 0x80000
+ _SA_RESTORER = 0
+)
+
+type ptregs struct {
+ gpr [32]uint64
+ nip uint64
+ msr uint64
+ orig_gpr3 uint64
+ ctr uint64
+ link uint64
+ xer uint64
+ ccr uint64
+ softe uint64
+ trap uint64
+ dar uint64
+ dsisr uint64
+ result uint64
+}
+
+type vreg struct {
+ u [4]uint32
+}
+
+type sigaltstackt struct {
+ ss_sp *byte
+ ss_flags int32
+ pad_cgo_0 [4]byte
+ ss_size uintptr
+}
+
+type sigcontext struct {
+ _unused [4]uint64
+ signal int32
+ _pad0 int32
+ handler uint64
+ oldmask uint64
+ regs *ptregs
+ gp_regs [48]uint64
+ fp_regs [33]float64
+ v_regs *vreg
+ vmx_reserve [101]int64
+}
+
+type ucontext struct {
+ uc_flags uint64
+ uc_link *ucontext
+ uc_stack sigaltstackt
+ uc_sigmask uint64
+ __unused [15]uint64
+ uc_mcontext sigcontext
+}
diff --git a/src/runtime/defs_linux_power64le.go b/src/runtime/defs_linux_power64le.go
new file mode 100644
index 000000000..f90b84874
--- /dev/null
+++ b/src/runtime/defs_linux_power64le.go
@@ -0,0 +1,198 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs3_linux.go
+
+package runtime
+
+const (
+ _EINTR = 0x4
+ _EAGAIN = 0xb
+ _ENOMEM = 0xc
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x20
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_DONTNEED = 0x4
+
+ _SA_RESTART = 0x10000000
+ _SA_ONSTACK = 0x8000000
+ _SA_SIGINFO = 0x4
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGBUS = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGUSR1 = 0xa
+ _SIGSEGV = 0xb
+ _SIGUSR2 = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGSTKFLT = 0x10
+ _SIGCHLD = 0x11
+ _SIGCONT = 0x12
+ _SIGSTOP = 0x13
+ _SIGTSTP = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGURG = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGIO = 0x1d
+ _SIGPWR = 0x1e
+ _SIGSYS = 0x1f
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EPOLLIN = 0x1
+ _EPOLLOUT = 0x4
+ _EPOLLERR = 0x8
+ _EPOLLHUP = 0x10
+ _EPOLLRDHUP = 0x2000
+ _EPOLLET = 0x80000000
+ _EPOLL_CLOEXEC = 0x80000
+ _EPOLL_CTL_ADD = 0x1
+ _EPOLL_CTL_DEL = 0x2
+ _EPOLL_CTL_MOD = 0x3
+)
+
+//struct Sigset {
+// uint64 sig[1];
+//};
+//typedef uint64 Sigset;
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = x
+}
+
+func (ts *timespec) set_nsec(x int32) {
+ ts.tv_nsec = int64(x)
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = int64(x)
+}
+
+type sigactiont struct {
+ sa_handler uintptr
+ sa_flags uint64
+ sa_restorer uintptr
+ sa_mask uint64
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ // below here is a union; si_addr is the only field we use
+ si_addr uint64
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type epollevent struct {
+ events uint32
+ pad_cgo_0 [4]byte
+ data [8]byte // unaligned uintptr
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs3_linux.go
+
+const (
+ _O_RDONLY = 0x0
+ _O_CLOEXEC = 0x80000
+ _SA_RESTORER = 0
+)
+
+type ptregs struct {
+ gpr [32]uint64
+ nip uint64
+ msr uint64
+ orig_gpr3 uint64
+ ctr uint64
+ link uint64
+ xer uint64
+ ccr uint64
+ softe uint64
+ trap uint64
+ dar uint64
+ dsisr uint64
+ result uint64
+}
+
+type vreg struct {
+ u [4]uint32
+}
+
+type sigaltstackt struct {
+ ss_sp *byte
+ ss_flags int32
+ pad_cgo_0 [4]byte
+ ss_size uintptr
+}
+
+type sigcontext struct {
+ _unused [4]uint64
+ signal int32
+ _pad0 int32
+ handler uint64
+ oldmask uint64
+ regs *ptregs
+ gp_regs [48]uint64
+ fp_regs [33]float64
+ v_regs *vreg
+ vmx_reserve [101]int64
+}
+
+type ucontext struct {
+ uc_flags uint64
+ uc_link *ucontext
+ uc_stack sigaltstackt
+ uc_sigmask uint64
+ __unused [15]uint64
+ uc_mcontext sigcontext
+}
diff --git a/src/runtime/defs_nacl_386.go b/src/runtime/defs_nacl_386.go
new file mode 100644
index 000000000..498882904
--- /dev/null
+++ b/src/runtime/defs_nacl_386.go
@@ -0,0 +1,42 @@
+package runtime
+
+const (
+ // These values are referred to in the source code
+ // but really don't matter. Even so, use the standard numbers.
+ _SIGSEGV = 11
+ _SIGPROF = 27
+)
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int32
+}
+
+type excregs386 struct {
+ eax uint32
+ ecx uint32
+ edx uint32
+ ebx uint32
+ esp uint32
+ ebp uint32
+ esi uint32
+ edi uint32
+ eip uint32
+ eflags uint32
+}
+
+type exccontext struct {
+ size uint32
+ portable_context_offset uint32
+ portable_context_size uint32
+ arch uint32
+ regs_size uint32
+ reserved [11]uint32
+ regs excregs386
+}
+
+type excportablecontext struct {
+ pc uint32
+ sp uint32
+ fp uint32
+}
diff --git a/src/runtime/defs_nacl_386.h b/src/runtime/defs_nacl_386.h
deleted file mode 100644
index e8fbb38e1..000000000
--- a/src/runtime/defs_nacl_386.h
+++ /dev/null
@@ -1,63 +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.
-
-// Created by hand, not machine generated.
-
-enum
-{
- // These values are referred to in the source code
- // but really don't matter. Even so, use the standard numbers.
- SIGSEGV = 11,
- SIGPROF = 27,
-};
-
-typedef struct Siginfo Siginfo;
-
-// native_client/src/trusted/service_runtime/include/machine/_types.h
-typedef struct Timespec Timespec;
-
-struct Timespec
-{
- int64 tv_sec;
- int32 tv_nsec;
-};
-
-// native_client/src/trusted/service_runtime/nacl_exception.h
-// native_client/src/include/nacl/nacl_exception.h
-
-typedef struct ExcContext ExcContext;
-typedef struct ExcPortable ExcPortable;
-typedef struct ExcRegs386 ExcRegs386;
-
-struct ExcRegs386
-{
- uint32 eax;
- uint32 ecx;
- uint32 edx;
- uint32 ebx;
- uint32 esp;
- uint32 ebp;
- uint32 esi;
- uint32 edi;
- uint32 eip;
- uint32 eflags;
-};
-
-struct ExcContext
-{
- uint32 size;
- uint32 portable_context_offset;
- uint32 portable_context_size;
- uint32 arch;
- uint32 regs_size;
- uint32 reserved[11];
- ExcRegs386 regs;
-};
-
-struct ExcPortableContext
-{
- uint32 pc;
- uint32 sp;
- uint32 fp;
-};
diff --git a/src/runtime/defs_nacl_amd64p32.go b/src/runtime/defs_nacl_amd64p32.go
new file mode 100644
index 000000000..add11fe06
--- /dev/null
+++ b/src/runtime/defs_nacl_amd64p32.go
@@ -0,0 +1,63 @@
+package runtime
+
+const (
+ // These values are referred to in the source code
+ // but really don't matter. Even so, use the standard numbers.
+ _SIGSEGV = 11
+ _SIGPROF = 27
+)
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int32
+}
+
+type excregs386 struct {
+ eax uint32
+ ecx uint32
+ edx uint32
+ ebx uint32
+ esp uint32
+ ebp uint32
+ esi uint32
+ edi uint32
+ eip uint32
+ eflags uint32
+}
+
+type excregsamd64 struct {
+ rax uint64
+ rcx uint64
+ rdx uint64
+ rbx uint64
+ rsp uint64
+ rbp uint64
+ rsi uint64
+ rdi uint64
+ r8 uint64
+ r9 uint64
+ r10 uint64
+ r11 uint64
+ r12 uint64
+ r13 uint64
+ r14 uint64
+ r15 uint64
+ rip uint64
+ rflags uint32
+}
+
+type exccontext struct {
+ size uint32
+ portable_context_offset uint32
+ portable_context_size uint32
+ arch uint32
+ regs_size uint32
+ reserved [11]uint32
+ regs excregsamd64
+}
+
+type excportablecontext struct {
+ pc uint32
+ sp uint32
+ fp uint32
+}
diff --git a/src/runtime/defs_nacl_amd64p32.h b/src/runtime/defs_nacl_amd64p32.h
deleted file mode 100644
index 45663d40a..000000000
--- a/src/runtime/defs_nacl_amd64p32.h
+++ /dev/null
@@ -1,90 +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.
-
-// Created by hand, not machine generated.
-
-enum
-{
- // These values are referred to in the source code
- // but really don't matter. Even so, use the standard numbers.
- SIGSEGV = 11,
- SIGPROF = 27,
-};
-
-typedef struct Siginfo Siginfo;
-
-
-// native_client/src/trusted/service_runtime/include/machine/_types.h
-typedef struct Timespec Timespec;
-
-struct Timespec
-{
- int64 tv_sec;
- int32 tv_nsec;
-};
-
-// native_client/src/trusted/service_runtime/nacl_exception.h
-// native_client/src/include/nacl/nacl_exception.h
-
-typedef struct ExcContext ExcContext;
-typedef struct ExcPortable ExcPortable;
-typedef struct ExcRegs386 ExcRegs386;
-typedef struct ExcRegsAmd64 ExcRegsAmd64;
-
-struct ExcRegs386
-{
- uint32 eax;
- uint32 ecx;
- uint32 edx;
- uint32 ebx;
- uint32 esp;
- uint32 ebp;
- uint32 esi;
- uint32 edi;
- uint32 eip;
- uint32 eflags;
-};
-
-struct ExcRegsAmd64
-{
- uint64 rax;
- uint64 rcx;
- uint64 rdx;
- uint64 rbx;
- uint64 rsp;
- uint64 rbp;
- uint64 rsi;
- uint64 rdi;
- uint64 r8;
- uint64 r9;
- uint64 r10;
- uint64 r11;
- uint64 r12;
- uint64 r13;
- uint64 r14;
- uint64 r15;
- uint64 rip;
- uint32 rflags;
-};
-
-struct ExcContext
-{
- uint32 size;
- uint32 portable_context_offset;
- uint32 portable_context_size;
- uint32 arch;
- uint32 regs_size;
- uint32 reserved[11];
- union {
- ExcRegs386 regs;
- ExcRegsAmd64 regs64;
- } regs;
-};
-
-struct ExcPortableContext
-{
- uint32 pc;
- uint32 sp;
- uint32 fp;
-};
diff --git a/src/runtime/defs_nacl_arm.go b/src/runtime/defs_nacl_arm.go
new file mode 100644
index 000000000..c983cffb9
--- /dev/null
+++ b/src/runtime/defs_nacl_arm.go
@@ -0,0 +1,49 @@
+package runtime
+
+const (
+ // These values are referred to in the source code
+ // but really don't matter. Even so, use the standard numbers.
+ _SIGSEGV = 11
+ _SIGPROF = 27
+)
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int32
+}
+
+type excregsarm struct {
+ r0 uint32
+ r1 uint32
+ r2 uint32
+ r3 uint32
+ r4 uint32
+ r5 uint32
+ r6 uint32
+ r7 uint32
+ r8 uint32
+ r9 uint32 // the value reported here is undefined.
+ r10 uint32
+ r11 uint32
+ r12 uint32
+ sp uint32 /* r13 */
+ lr uint32 /* r14 */
+ pc uint32 /* r15 */
+ cpsr uint32
+}
+
+type exccontext struct {
+ size uint32
+ portable_context_offset uint32
+ portable_context_size uint32
+ arch uint32
+ regs_size uint32
+ reserved [11]uint32
+ regs excregsarm
+}
+
+type excportablecontext struct {
+ pc uint32
+ sp uint32
+ fp uint32
+}
diff --git a/src/runtime/defs_nacl_arm.h b/src/runtime/defs_nacl_arm.h
deleted file mode 100644
index 9ce07ccb2..000000000
--- a/src/runtime/defs_nacl_arm.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.
-
-// Created by hand, not machine generated.
-
-enum
-{
- // These values are referred to in the source code
- // but really don't matter. Even so, use the standard numbers.
- SIGSEGV = 11,
- SIGPROF = 27,
-};
-
-typedef struct Siginfo Siginfo;
-
-// native_client/src/trusted/service_runtime/include/machine/_types.h
-typedef struct Timespec Timespec;
-
-struct Timespec
-{
- int64 tv_sec;
- int32 tv_nsec;
-};
-
-// native_client/src/trusted/service_runtime/nacl_exception.h
-// native_client/src/include/nacl/nacl_exception.h
-
-typedef struct ExcContext ExcContext;
-typedef struct ExcPortable ExcPortable;
-typedef struct ExcRegsARM ExcRegsARM;
-
-struct ExcRegsARM
-{
- uint32 r0;
- uint32 r1;
- uint32 r2;
- uint32 r3;
- uint32 r4;
- uint32 r5;
- uint32 r6;
- uint32 r7;
- uint32 r8;
- uint32 r9; // the value reported here is undefined.
- uint32 r10;
- uint32 r11;
- uint32 r12;
- uint32 sp; /* r13 */
- uint32 lr; /* r14 */
- uint32 pc; /* r15 */
- uint32 cpsr;
-};
-
-struct ExcContext
-{
- uint32 size;
- uint32 portable_context_offset;
- uint32 portable_context_size;
- uint32 arch;
- uint32 regs_size;
- uint32 reserved[11];
- ExcRegsARM regs;
-};
-
-struct ExcPortableContext
-{
- uint32 pc;
- uint32 sp;
- uint32 fp;
-};
diff --git a/src/runtime/defs_netbsd_386.h b/src/runtime/defs_netbsd_386.h
deleted file mode 100644
index fd87804f9..000000000
--- a/src/runtime/defs_netbsd_386.h
+++ /dev/null
@@ -1,182 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_386.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x6,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_RECEIPT = 0,
- EV_ERROR = 0x4000,
- EVFILT_READ = 0x0,
- EVFILT_WRITE = 0x1,
-};
-
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct Siginfo Siginfo;
-typedef struct StackT StackT;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct McontextT McontextT;
-typedef struct UcontextT UcontextT;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct SigaltstackT {
- byte *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-struct Sigset {
- uint32 __bits[4];
-};
-struct Siginfo {
- int32 _signo;
- int32 _code;
- int32 _errno;
- byte _reason[20];
-};
-
-struct StackT {
- byte *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-
-struct Timespec {
- int64 tv_sec;
- int32 tv_nsec;
-};
-struct Timeval {
- int64 tv_sec;
- int32 tv_usec;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct McontextT {
- int32 __gregs[19];
- byte __fpregs[644];
- int32 _mc_tlsbase;
-};
-struct UcontextT {
- uint32 uc_flags;
- UcontextT *uc_link;
- Sigset uc_sigmask;
- StackT uc_stack;
- McontextT uc_mcontext;
- int32 __uc_pad[4];
-};
-
-struct KeventT {
- uint32 ident;
- uint32 filter;
- uint32 flags;
- uint32 fflags;
- int64 data;
- byte *udata;
-};
-
-
-#pragma pack off
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_386.go
-
-
-enum {
- REG_GS = 0x0,
- REG_FS = 0x1,
- REG_ES = 0x2,
- REG_DS = 0x3,
- REG_EDI = 0x4,
- REG_ESI = 0x5,
- REG_EBP = 0x6,
- REG_ESP = 0x7,
- REG_EBX = 0x8,
- REG_EDX = 0x9,
- REG_ECX = 0xa,
- REG_EAX = 0xb,
- REG_TRAPNO = 0xc,
- REG_ERR = 0xd,
- REG_EIP = 0xe,
- REG_CS = 0xf,
- REG_EFL = 0x10,
- REG_UESP = 0x11,
- REG_SS = 0x12,
-};
-
diff --git a/src/runtime/defs_netbsd_amd64.h b/src/runtime/defs_netbsd_amd64.h
deleted file mode 100644
index dac94b113..000000000
--- a/src/runtime/defs_netbsd_amd64.h
+++ /dev/null
@@ -1,194 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x6,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_RECEIPT = 0,
- EV_ERROR = 0x4000,
- EVFILT_READ = 0x0,
- EVFILT_WRITE = 0x1,
-};
-
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct Siginfo Siginfo;
-typedef struct StackT StackT;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct McontextT McontextT;
-typedef struct UcontextT UcontextT;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct SigaltstackT {
- byte *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-struct Sigset {
- uint32 __bits[4];
-};
-struct Siginfo {
- int32 _signo;
- int32 _code;
- int32 _errno;
- int32 _pad;
- byte _reason[24];
-};
-
-struct StackT {
- byte *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-
-struct Timespec {
- int64 tv_sec;
- int64 tv_nsec;
-};
-struct Timeval {
- int64 tv_sec;
- int32 tv_usec;
- byte Pad_cgo_0[4];
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct McontextT {
- uint64 __gregs[26];
- uint64 _mc_tlsbase;
- int8 __fpregs[512];
-};
-struct UcontextT {
- uint32 uc_flags;
- byte Pad_cgo_0[4];
- UcontextT *uc_link;
- Sigset uc_sigmask;
- StackT uc_stack;
- McontextT uc_mcontext;
-};
-
-struct KeventT {
- uint64 ident;
- uint32 filter;
- uint32 flags;
- uint32 fflags;
- byte Pad_cgo_0[4];
- int64 data;
- byte *udata;
-};
-
-
-#pragma pack off
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go
-
-
-enum {
- REG_RDI = 0x0,
- REG_RSI = 0x1,
- REG_RDX = 0x2,
- REG_RCX = 0x3,
- REG_R8 = 0x4,
- REG_R9 = 0x5,
- REG_R10 = 0x6,
- REG_R11 = 0x7,
- REG_R12 = 0x8,
- REG_R13 = 0x9,
- REG_R14 = 0xa,
- REG_R15 = 0xb,
- REG_RBP = 0xc,
- REG_RBX = 0xd,
- REG_RAX = 0xe,
- REG_GS = 0xf,
- REG_FS = 0x10,
- REG_ES = 0x11,
- REG_DS = 0x12,
- REG_TRAPNO = 0x13,
- REG_ERR = 0x14,
- REG_RIP = 0x15,
- REG_CS = 0x16,
- REG_RFLAGS = 0x17,
- REG_RSP = 0x18,
- REG_SS = 0x19,
-};
-
diff --git a/src/runtime/defs_netbsd_arm.h b/src/runtime/defs_netbsd_arm.h
deleted file mode 100644
index 70f34af47..000000000
--- a/src/runtime/defs_netbsd_arm.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x6,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_RECEIPT = 0,
- EV_ERROR = 0x4000,
- EVFILT_READ = 0x0,
- EVFILT_WRITE = 0x1,
-};
-
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct Siginfo Siginfo;
-typedef struct StackT StackT;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct McontextT McontextT;
-typedef struct UcontextT UcontextT;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct SigaltstackT {
- byte *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-struct Sigset {
- uint32 __bits[4];
-};
-struct Siginfo {
- int32 _signo;
- int32 _code;
- int32 _errno;
- byte _reason[20];
-};
-
-struct StackT {
- byte *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-
-struct Timespec {
- int64 tv_sec;
- int32 tv_nsec;
-};
-struct Timeval {
- int64 tv_sec;
- int32 tv_usec;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct McontextT {
- uint32 __gregs[17];
-#ifdef __ARM_EABI__
- byte __fpu[4+8*32+4];
-#else
- byte __fpu[4+4*33+4];
-#endif
- uint32 _mc_tlsbase;
-};
-struct UcontextT {
- uint32 uc_flags;
- UcontextT *uc_link;
- Sigset uc_sigmask;
- StackT uc_stack;
- McontextT uc_mcontext;
- int32 __uc_pad[2];
-};
-
-struct KeventT {
- uint32 ident;
- uint32 filter;
- uint32 flags;
- uint32 fflags;
- int64 data;
- byte *udata;
-};
-
-
-#pragma pack off
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
-
-
-enum {
- REG_R0 = 0x0,
- REG_R1 = 0x1,
- REG_R2 = 0x2,
- REG_R3 = 0x3,
- REG_R4 = 0x4,
- REG_R5 = 0x5,
- REG_R6 = 0x6,
- REG_R7 = 0x7,
- REG_R8 = 0x8,
- REG_R9 = 0x9,
- REG_R10 = 0xa,
- REG_R11 = 0xb,
- REG_R12 = 0xc,
- REG_R13 = 0xd,
- REG_R14 = 0xe,
- REG_R15 = 0xf,
- REG_CPSR = 0x10,
-};
-
diff --git a/src/runtime/defs_openbsd_386.go b/src/runtime/defs_openbsd_386.go
new file mode 100644
index 000000000..4b6015811
--- /dev/null
+++ b/src/runtime/defs_openbsd_386.go
@@ -0,0 +1,170 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_openbsd.go
+
+package runtime
+
+import "unsafe"
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x6
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type tforkt struct {
+ tf_tcb unsafe.Pointer
+ tf_tid *int32
+ tf_stack uintptr
+}
+
+type sigaltstackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+}
+
+type sigcontext struct {
+ sc_gs uint32
+ sc_fs uint32
+ sc_es uint32
+ sc_ds uint32
+ sc_edi uint32
+ sc_esi uint32
+ sc_ebp uint32
+ sc_ebx uint32
+ sc_edx uint32
+ sc_ecx uint32
+ sc_eax uint32
+ sc_eip uint32
+ sc_cs uint32
+ sc_eflags uint32
+ sc_esp uint32
+ sc_ss uint32
+ __sc_unused uint32
+ sc_mask uint32
+ sc_trapno uint32
+ sc_err uint32
+ sc_fpstate unsafe.Pointer
+}
+
+type siginfo struct {
+ si_signo int32
+ si_code int32
+ si_errno int32
+ _data [116]byte
+}
+
+type stackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int32
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = x
+}
+
+func (ts *timespec) set_nsec(x int32) {
+ ts.tv_nsec = x
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int32
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type keventt struct {
+ ident uint32
+ filter int16
+ flags uint16
+ fflags uint32
+ data int64
+ udata *byte
+}
diff --git a/src/runtime/defs_openbsd_386.h b/src/runtime/defs_openbsd_386.h
deleted file mode 100644
index 6b77e0084..000000000
--- a/src/runtime/defs_openbsd_386.h
+++ /dev/null
@@ -1,168 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_openbsd.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x6,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
-};
-
-typedef struct TforkT TforkT;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigcontext Sigcontext;
-typedef struct Siginfo Siginfo;
-typedef struct StackT StackT;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct TforkT {
- byte *tf_tcb;
- int32 *tf_tid;
- byte *tf_stack;
-};
-
-struct SigaltstackT {
- byte *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-struct Sigcontext {
- int32 sc_gs;
- int32 sc_fs;
- int32 sc_es;
- int32 sc_ds;
- int32 sc_edi;
- int32 sc_esi;
- int32 sc_ebp;
- int32 sc_ebx;
- int32 sc_edx;
- int32 sc_ecx;
- int32 sc_eax;
- int32 sc_eip;
- int32 sc_cs;
- int32 sc_eflags;
- int32 sc_esp;
- int32 sc_ss;
- int32 __sc_unused;
- int32 sc_mask;
- int32 sc_trapno;
- int32 sc_err;
- void *sc_fpstate;
-};
-struct Siginfo {
- int32 si_signo;
- int32 si_code;
- int32 si_errno;
- byte _data[116];
-};
-typedef uint32 Sigset;
-typedef byte Sigval[4];
-
-struct StackT {
- byte *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-
-struct Timespec {
- int64 tv_sec;
- int32 tv_nsec;
-};
-struct Timeval {
- int64 tv_sec;
- int32 tv_usec;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct KeventT {
- uint32 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int64 data;
- byte *udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_openbsd_amd64.go b/src/runtime/defs_openbsd_amd64.go
new file mode 100644
index 000000000..3c27c9144
--- /dev/null
+++ b/src/runtime/defs_openbsd_amd64.go
@@ -0,0 +1,181 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_openbsd.go
+
+package runtime
+
+import "unsafe"
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x6
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type tforkt struct {
+ tf_tcb unsafe.Pointer
+ tf_tid *int32
+ tf_stack uintptr
+}
+
+type sigaltstackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type sigcontext struct {
+ sc_rdi uint64
+ sc_rsi uint64
+ sc_rdx uint64
+ sc_rcx uint64
+ sc_r8 uint64
+ sc_r9 uint64
+ sc_r10 uint64
+ sc_r11 uint64
+ sc_r12 uint64
+ sc_r13 uint64
+ sc_r14 uint64
+ sc_r15 uint64
+ sc_rbp uint64
+ sc_rbx uint64
+ sc_rax uint64
+ sc_gs uint64
+ sc_fs uint64
+ sc_es uint64
+ sc_ds uint64
+ sc_trapno uint64
+ sc_err uint64
+ sc_rip uint64
+ sc_cs uint64
+ sc_rflags uint64
+ sc_rsp uint64
+ sc_ss uint64
+ sc_fpstate unsafe.Pointer
+ __sc_unused int32
+ sc_mask int32
+}
+
+type siginfo struct {
+ si_signo int32
+ si_code int32
+ si_errno int32
+ pad_cgo_0 [4]byte
+ _data [120]byte
+}
+
+type stackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = x
+}
+
+func (ts *timespec) set_nsec(x int32) {
+ ts.tv_nsec = int64(x)
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = int64(x)
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type keventt struct {
+ ident uint64
+ filter int16
+ flags uint16
+ fflags uint32
+ data int64
+ udata *byte
+}
diff --git a/src/runtime/defs_openbsd_amd64.h b/src/runtime/defs_openbsd_amd64.h
deleted file mode 100644
index 761e8e47d..000000000
--- a/src/runtime/defs_openbsd_amd64.h
+++ /dev/null
@@ -1,179 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_openbsd.go
-
-
-enum {
- EINTR = 0x4,
- EFAULT = 0xe,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x6,
-
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
-
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
-};
-
-typedef struct TforkT TforkT;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigcontext Sigcontext;
-typedef struct Siginfo Siginfo;
-typedef struct StackT StackT;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct TforkT {
- byte *tf_tcb;
- int32 *tf_tid;
- byte *tf_stack;
-};
-
-struct SigaltstackT {
- byte *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-struct Sigcontext {
- int64 sc_rdi;
- int64 sc_rsi;
- int64 sc_rdx;
- int64 sc_rcx;
- int64 sc_r8;
- int64 sc_r9;
- int64 sc_r10;
- int64 sc_r11;
- int64 sc_r12;
- int64 sc_r13;
- int64 sc_r14;
- int64 sc_r15;
- int64 sc_rbp;
- int64 sc_rbx;
- int64 sc_rax;
- int64 sc_gs;
- int64 sc_fs;
- int64 sc_es;
- int64 sc_ds;
- int64 sc_trapno;
- int64 sc_err;
- int64 sc_rip;
- int64 sc_cs;
- int64 sc_rflags;
- int64 sc_rsp;
- int64 sc_ss;
- void *sc_fpstate;
- int32 __sc_unused;
- int32 sc_mask;
-};
-struct Siginfo {
- int32 si_signo;
- int32 si_code;
- int32 si_errno;
- byte Pad_cgo_0[4];
- byte _data[120];
-};
-typedef uint32 Sigset;
-typedef byte Sigval[8];
-
-struct StackT {
- byte *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-
-struct Timespec {
- int64 tv_sec;
- int64 tv_nsec;
-};
-struct Timeval {
- int64 tv_sec;
- int64 tv_usec;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct KeventT {
- uint64 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int64 data;
- byte *udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_plan9_386.go b/src/runtime/defs_plan9_386.go
new file mode 100644
index 000000000..212ecdf14
--- /dev/null
+++ b/src/runtime/defs_plan9_386.go
@@ -0,0 +1,25 @@
+package runtime
+
+const _PAGESIZE = 0x1000
+
+type ureg struct {
+ di uint32 /* general registers */
+ si uint32 /* ... */
+ bp uint32 /* ... */
+ nsp uint32
+ bx uint32 /* ... */
+ dx uint32 /* ... */
+ cx uint32 /* ... */
+ ax uint32 /* ... */
+ gs uint32 /* data segments */
+ fs uint32 /* ... */
+ es uint32 /* ... */
+ ds uint32 /* ... */
+ trap uint32 /* trap _type */
+ ecode uint32 /* error code (or zero) */
+ pc uint32 /* pc */
+ cs uint32 /* old context */
+ flags uint32 /* old flags */
+ sp uint32
+ ss uint32 /* old stack segment */
+}
diff --git a/src/runtime/defs_plan9_386.h b/src/runtime/defs_plan9_386.h
deleted file mode 100644
index a762b8589..000000000
--- a/src/runtime/defs_plan9_386.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#define PAGESIZE 0x1000
-
-typedef struct Ureg Ureg;
-
-struct Ureg
-{
- uint32 di; /* general registers */
- uint32 si; /* ... */
- uint32 bp; /* ... */
- uint32 nsp;
- uint32 bx; /* ... */
- uint32 dx; /* ... */
- uint32 cx; /* ... */
- uint32 ax; /* ... */
- uint32 gs; /* data segments */
- uint32 fs; /* ... */
- uint32 es; /* ... */
- uint32 ds; /* ... */
- uint32 trap; /* trap type */
- uint32 ecode; /* error code (or zero) */
- uint32 pc; /* pc */
- uint32 cs; /* old context */
- uint32 flags; /* old flags */
- uint32 sp;
- uint32 ss; /* old stack segment */
-};
diff --git a/src/runtime/defs_plan9_amd64.go b/src/runtime/defs_plan9_amd64.go
new file mode 100644
index 000000000..510da0e99
--- /dev/null
+++ b/src/runtime/defs_plan9_amd64.go
@@ -0,0 +1,34 @@
+package runtime
+
+const _PAGESIZE = 0x1000
+
+type ureg struct {
+ ax uint64
+ bx uint64
+ cx uint64
+ dx uint64
+ si uint64
+ di uint64
+ bp uint64
+ r8 uint64
+ r9 uint64
+ r10 uint64
+ r11 uint64
+ r12 uint64
+ r13 uint64
+ r14 uint64
+ r15 uint64
+
+ ds uint16
+ es uint16
+ fs uint16
+ gs uint16
+
+ _type uint64
+ error uint64 /* error code (or zero) */
+ ip uint64 /* pc */
+ cs uint64 /* old context */
+ flags uint64 /* old flags */
+ sp uint64 /* sp */
+ ss uint64 /* old stack segment */
+}
diff --git a/src/runtime/defs_plan9_amd64.h b/src/runtime/defs_plan9_amd64.h
deleted file mode 100644
index 20bca479c..000000000
--- a/src/runtime/defs_plan9_amd64.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#define PAGESIZE 0x1000
-
-typedef struct Ureg Ureg;
-
-struct Ureg {
- uint64 ax;
- uint64 bx;
- uint64 cx;
- uint64 dx;
- uint64 si;
- uint64 di;
- uint64 bp;
- uint64 r8;
- uint64 r9;
- uint64 r10;
- uint64 r11;
- uint64 r12;
- uint64 r13;
- uint64 r14;
- uint64 r15;
-
- uint16 ds;
- uint16 es;
- uint16 fs;
- uint16 gs;
-
- uint64 type;
- uint64 error; /* error code (or zero) */
- uint64 ip; /* pc */
- uint64 cs; /* old context */
- uint64 flags; /* old flags */
- uint64 sp; /* sp */
- uint64 ss; /* old stack segment */
-};
diff --git a/src/runtime/defs_solaris_amd64.h b/src/runtime/defs_solaris_amd64.h
deleted file mode 100644
index cb1cfeadc..000000000
--- a/src/runtime/defs_solaris_amd64.h
+++ /dev/null
@@ -1,254 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
-
-
-enum {
- EINTR = 0x4,
- EBADF = 0x9,
- EFAULT = 0xe,
- EAGAIN = 0xb,
- ETIMEDOUT = 0x91,
- EWOULDBLOCK = 0xb,
- EINPROGRESS = 0x96,
-
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_ANON = 0x100,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
-
- MADV_FREE = 0x5,
-
- SA_SIGINFO = 0x8,
- SA_RESTART = 0x4,
- SA_ONSTACK = 0x1,
-
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x15,
- SIGSTOP = 0x17,
- SIGTSTP = 0x18,
- SIGCONT = 0x19,
- SIGCHLD = 0x12,
- SIGTTIN = 0x1a,
- SIGTTOU = 0x1b,
- SIGIO = 0x16,
- SIGXCPU = 0x1e,
- SIGXFSZ = 0x1f,
- SIGVTALRM = 0x1c,
- SIGPROF = 0x1d,
- SIGWINCH = 0x14,
- SIGUSR1 = 0x10,
- SIGUSR2 = 0x11,
-
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
-
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
-
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
-
- ITIMER_REAL = 0x0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-
- _SC_NPROCESSORS_ONLN = 0xf,
-
- PTHREAD_CREATE_DETACHED = 0x40,
-
- FORK_NOSIGCHLD = 0x1,
- FORK_WAITPID = 0x2,
-
- MAXHOSTNAMELEN = 0x100,
-
- O_NONBLOCK = 0x80,
- FD_CLOEXEC = 0x1,
- F_GETFL = 0x3,
- F_SETFL = 0x4,
- F_SETFD = 0x2,
-
- POLLIN = 0x1,
- POLLOUT = 0x4,
- POLLHUP = 0x10,
- POLLERR = 0x8,
-
- PORT_SOURCE_FD = 0x4,
-};
-
-typedef struct SemT SemT;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct SigactionT SigactionT;
-typedef struct Fpregset Fpregset;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct PortEvent PortEvent;
-typedef struct PthreadAttr PthreadAttr;
-typedef struct Stat Stat;
-
-#pragma pack on
-
-struct SemT {
- uint32 sem_count;
- uint16 sem_type;
- uint16 sem_magic;
- uint64 sem_pad1[3];
- uint64 sem_pad2[2];
-};
-
-struct SigaltstackT {
- byte *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-struct Sigset {
- uint32 __sigbits[4];
-};
-struct StackT {
- byte *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte Pad_cgo_0[4];
-};
-
-struct Siginfo {
- int32 si_signo;
- int32 si_code;
- int32 si_errno;
- int32 si_pad;
- byte __data[240];
-};
-struct SigactionT {
- int32 sa_flags;
- byte Pad_cgo_0[4];
- byte _funcptr[8];
- Sigset sa_mask;
-};
-
-struct Fpregset {
- byte fp_reg_set[528];
-};
-struct Mcontext {
- int64 gregs[28];
- Fpregset fpregs;
-};
-struct Ucontext {
- uint64 uc_flags;
- Ucontext *uc_link;
- Sigset uc_sigmask;
- StackT uc_stack;
- byte Pad_cgo_0[8];
- Mcontext uc_mcontext;
- int64 uc_filler[5];
- byte Pad_cgo_1[8];
-};
-
-struct Timespec {
- int64 tv_sec;
- int64 tv_nsec;
-};
-struct Timeval {
- int64 tv_sec;
- int64 tv_usec;
-};
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-struct PortEvent {
- int32 portev_events;
- uint16 portev_source;
- uint16 portev_pad;
- uint64 portev_object;
- byte *portev_user;
-};
-typedef uint32 Pthread;
-struct PthreadAttr {
- byte *__pthread_attrp;
-};
-
-struct Stat {
- uint64 st_dev;
- uint64 st_ino;
- uint32 st_mode;
- uint32 st_nlink;
- uint32 st_uid;
- uint32 st_gid;
- uint64 st_rdev;
- int64 st_size;
- Timespec st_atim;
- Timespec st_mtim;
- Timespec st_ctim;
- int32 st_blksize;
- byte Pad_cgo_0[4];
- int64 st_blocks;
- int8 st_fstype[16];
-};
-
-
-#pragma pack off
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
-
-
-enum {
- REG_RDI = 0x8,
- REG_RSI = 0x9,
- REG_RDX = 0xc,
- REG_RCX = 0xd,
- REG_R8 = 0x7,
- REG_R9 = 0x6,
- REG_R10 = 0x5,
- REG_R11 = 0x4,
- REG_R12 = 0x3,
- REG_R13 = 0x2,
- REG_R14 = 0x1,
- REG_R15 = 0x0,
- REG_RBP = 0xa,
- REG_RBX = 0xb,
- REG_RAX = 0xe,
- REG_GS = 0x17,
- REG_FS = 0x16,
- REG_ES = 0x18,
- REG_DS = 0x19,
- REG_TRAPNO = 0xf,
- REG_ERR = 0x10,
- REG_RIP = 0x11,
- REG_CS = 0x12,
- REG_RFLAGS = 0x13,
- REG_RSP = 0x14,
- REG_SS = 0x15,
-};
-
diff --git a/src/runtime/defs_windows_386.go b/src/runtime/defs_windows_386.go
new file mode 100644
index 000000000..abec2d839
--- /dev/null
+++ b/src/runtime/defs_windows_386.go
@@ -0,0 +1,109 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_windows.go
+
+package runtime
+
+const (
+ _PROT_NONE = 0
+ _PROT_READ = 1
+ _PROT_WRITE = 2
+ _PROT_EXEC = 4
+
+ _MAP_ANON = 1
+ _MAP_PRIVATE = 2
+
+ _DUPLICATE_SAME_ACCESS = 0x2
+ _THREAD_PRIORITY_HIGHEST = 0x2
+
+ _SIGINT = 0x2
+ _CTRL_C_EVENT = 0x0
+ _CTRL_BREAK_EVENT = 0x1
+
+ _CONTEXT_CONTROL = 0x10001
+ _CONTEXT_FULL = 0x10007
+
+ _EXCEPTION_ACCESS_VIOLATION = 0xc0000005
+ _EXCEPTION_BREAKPOINT = 0x80000003
+ _EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d
+ _EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e
+ _EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f
+ _EXCEPTION_FLT_OVERFLOW = 0xc0000091
+ _EXCEPTION_FLT_UNDERFLOW = 0xc0000093
+ _EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094
+ _EXCEPTION_INT_OVERFLOW = 0xc0000095
+
+ _INFINITE = 0xffffffff
+ _WAIT_TIMEOUT = 0x102
+
+ _EXCEPTION_CONTINUE_EXECUTION = -0x1
+ _EXCEPTION_CONTINUE_SEARCH = 0x0
+)
+
+type systeminfo struct {
+ anon0 [4]byte
+ dwpagesize uint32
+ lpminimumapplicationaddress *byte
+ lpmaximumapplicationaddress *byte
+ dwactiveprocessormask uint32
+ dwnumberofprocessors uint32
+ dwprocessortype uint32
+ dwallocationgranularity uint32
+ wprocessorlevel uint16
+ wprocessorrevision uint16
+}
+
+type exceptionrecord struct {
+ exceptioncode uint32
+ exceptionflags uint32
+ exceptionrecord *exceptionrecord
+ exceptionaddress *byte
+ numberparameters uint32
+ exceptioninformation [15]uint32
+}
+
+type floatingsavearea struct {
+ controlword uint32
+ statusword uint32
+ tagword uint32
+ erroroffset uint32
+ errorselector uint32
+ dataoffset uint32
+ dataselector uint32
+ registerarea [80]uint8
+ cr0npxstate uint32
+}
+
+type context struct {
+ contextflags uint32
+ dr0 uint32
+ dr1 uint32
+ dr2 uint32
+ dr3 uint32
+ dr6 uint32
+ dr7 uint32
+ floatsave floatingsavearea
+ seggs uint32
+ segfs uint32
+ seges uint32
+ segds uint32
+ edi uint32
+ esi uint32
+ ebx uint32
+ edx uint32
+ ecx uint32
+ eax uint32
+ ebp uint32
+ eip uint32
+ segcs uint32
+ eflags uint32
+ esp uint32
+ segss uint32
+ extendedregisters [512]uint8
+}
+
+type overlapped struct {
+ internal uint32
+ internalhigh uint32
+ anon0 [8]byte
+ hevent *byte
+}
diff --git a/src/runtime/defs_windows_386.h b/src/runtime/defs_windows_386.h
deleted file mode 100644
index 2317c04f6..000000000
--- a/src/runtime/defs_windows_386.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_windows.go
-
-
-enum {
- PROT_NONE = 0,
- PROT_READ = 1,
- PROT_WRITE = 2,
- PROT_EXEC = 4,
-
- MAP_ANON = 1,
- MAP_PRIVATE = 2,
-
- DUPLICATE_SAME_ACCESS = 0x2,
- THREAD_PRIORITY_HIGHEST = 0x2,
-
- SIGINT = 0x2,
- CTRL_C_EVENT = 0x0,
- CTRL_BREAK_EVENT = 0x1,
-
- CONTEXT_CONTROL = 0x10001,
- CONTEXT_FULL = 0x10007,
-
- EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
- EXCEPTION_BREAKPOINT = 0x80000003,
- EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
- EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e,
- EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f,
- EXCEPTION_FLT_OVERFLOW = 0xc0000091,
- EXCEPTION_FLT_UNDERFLOW = 0xc0000093,
- EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094,
- EXCEPTION_INT_OVERFLOW = 0xc0000095,
-
- INFINITE = 0xffffffff,
- WAIT_TIMEOUT = 0x102,
-
- EXCEPTION_CONTINUE_EXECUTION = -0x1,
- EXCEPTION_CONTINUE_SEARCH = 0x0,
-};
-
-typedef struct SystemInfo SystemInfo;
-typedef struct ExceptionRecord ExceptionRecord;
-typedef struct FloatingSaveArea FloatingSaveArea;
-typedef struct M128a M128a;
-typedef struct Context Context;
-typedef struct Overlapped Overlapped;
-
-#pragma pack on
-
-struct SystemInfo {
- byte anon0[4];
- uint32 dwPageSize;
- byte *lpMinimumApplicationAddress;
- byte *lpMaximumApplicationAddress;
- uint32 dwActiveProcessorMask;
- uint32 dwNumberOfProcessors;
- uint32 dwProcessorType;
- uint32 dwAllocationGranularity;
- uint16 wProcessorLevel;
- uint16 wProcessorRevision;
-};
-struct ExceptionRecord {
- uint32 ExceptionCode;
- uint32 ExceptionFlags;
- ExceptionRecord *ExceptionRecord;
- byte *ExceptionAddress;
- uint32 NumberParameters;
- uint32 ExceptionInformation[15];
-};
-struct FloatingSaveArea {
- uint32 ControlWord;
- uint32 StatusWord;
- uint32 TagWord;
- uint32 ErrorOffset;
- uint32 ErrorSelector;
- uint32 DataOffset;
- uint32 DataSelector;
- uint8 RegisterArea[80];
- uint32 Cr0NpxState;
-};
-struct Context {
- uint32 ContextFlags;
- uint32 Dr0;
- uint32 Dr1;
- uint32 Dr2;
- uint32 Dr3;
- uint32 Dr6;
- uint32 Dr7;
- FloatingSaveArea FloatSave;
- uint32 SegGs;
- uint32 SegFs;
- uint32 SegEs;
- uint32 SegDs;
- uint32 Edi;
- uint32 Esi;
- uint32 Ebx;
- uint32 Edx;
- uint32 Ecx;
- uint32 Eax;
- uint32 Ebp;
- uint32 Eip;
- uint32 SegCs;
- uint32 EFlags;
- uint32 Esp;
- uint32 SegSs;
- uint8 ExtendedRegisters[512];
-};
-struct Overlapped {
- uint32 Internal;
- uint32 InternalHigh;
- byte anon0[8];
- byte *hEvent;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_windows_amd64.go b/src/runtime/defs_windows_amd64.go
new file mode 100644
index 000000000..81b13597b
--- /dev/null
+++ b/src/runtime/defs_windows_amd64.go
@@ -0,0 +1,124 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_windows.go
+
+package runtime
+
+const (
+ _PROT_NONE = 0
+ _PROT_READ = 1
+ _PROT_WRITE = 2
+ _PROT_EXEC = 4
+
+ _MAP_ANON = 1
+ _MAP_PRIVATE = 2
+
+ _DUPLICATE_SAME_ACCESS = 0x2
+ _THREAD_PRIORITY_HIGHEST = 0x2
+
+ _SIGINT = 0x2
+ _CTRL_C_EVENT = 0x0
+ _CTRL_BREAK_EVENT = 0x1
+
+ _CONTEXT_CONTROL = 0x100001
+ _CONTEXT_FULL = 0x10000b
+
+ _EXCEPTION_ACCESS_VIOLATION = 0xc0000005
+ _EXCEPTION_BREAKPOINT = 0x80000003
+ _EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d
+ _EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e
+ _EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f
+ _EXCEPTION_FLT_OVERFLOW = 0xc0000091
+ _EXCEPTION_FLT_UNDERFLOW = 0xc0000093
+ _EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094
+ _EXCEPTION_INT_OVERFLOW = 0xc0000095
+
+ _INFINITE = 0xffffffff
+ _WAIT_TIMEOUT = 0x102
+
+ _EXCEPTION_CONTINUE_EXECUTION = -0x1
+ _EXCEPTION_CONTINUE_SEARCH = 0x0
+)
+
+type systeminfo struct {
+ anon0 [4]byte
+ dwpagesize uint32
+ lpminimumapplicationaddress *byte
+ lpmaximumapplicationaddress *byte
+ dwactiveprocessormask uint64
+ dwnumberofprocessors uint32
+ dwprocessortype uint32
+ dwallocationgranularity uint32
+ wprocessorlevel uint16
+ wprocessorrevision uint16
+}
+
+type exceptionrecord struct {
+ exceptioncode uint32
+ exceptionflags uint32
+ exceptionrecord *exceptionrecord
+ exceptionaddress *byte
+ numberparameters uint32
+ pad_cgo_0 [4]byte
+ exceptioninformation [15]uint64
+}
+
+type m128a struct {
+ low uint64
+ high int64
+}
+
+type context struct {
+ p1home uint64
+ p2home uint64
+ p3home uint64
+ p4home uint64
+ p5home uint64
+ p6home uint64
+ contextflags uint32
+ mxcsr uint32
+ segcs uint16
+ segds uint16
+ seges uint16
+ segfs uint16
+ seggs uint16
+ segss uint16
+ eflags uint32
+ dr0 uint64
+ dr1 uint64
+ dr2 uint64
+ dr3 uint64
+ dr6 uint64
+ dr7 uint64
+ rax uint64
+ rcx uint64
+ rdx uint64
+ rbx uint64
+ rsp uint64
+ rbp uint64
+ rsi uint64
+ rdi uint64
+ r8 uint64
+ r9 uint64
+ r10 uint64
+ r11 uint64
+ r12 uint64
+ r13 uint64
+ r14 uint64
+ r15 uint64
+ rip uint64
+ anon0 [512]byte
+ vectorregister [26]m128a
+ vectorcontrol uint64
+ debugcontrol uint64
+ lastbranchtorip uint64
+ lastbranchfromrip uint64
+ lastexceptiontorip uint64
+ lastexceptionfromrip uint64
+}
+
+type overlapped struct {
+ internal uint64
+ internalhigh uint64
+ anon0 [8]byte
+ hevent *byte
+}
diff --git a/src/runtime/defs_windows_amd64.h b/src/runtime/defs_windows_amd64.h
deleted file mode 100644
index 7f37a7a8c..000000000
--- a/src/runtime/defs_windows_amd64.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_windows.go
-
-
-enum {
- PROT_NONE = 0,
- PROT_READ = 1,
- PROT_WRITE = 2,
- PROT_EXEC = 4,
-
- MAP_ANON = 1,
- MAP_PRIVATE = 2,
-
- DUPLICATE_SAME_ACCESS = 0x2,
- THREAD_PRIORITY_HIGHEST = 0x2,
-
- SIGINT = 0x2,
- CTRL_C_EVENT = 0x0,
- CTRL_BREAK_EVENT = 0x1,
-
- CONTEXT_CONTROL = 0x100001,
- CONTEXT_FULL = 0x10000b,
-
- EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
- EXCEPTION_BREAKPOINT = 0x80000003,
- EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
- EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e,
- EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f,
- EXCEPTION_FLT_OVERFLOW = 0xc0000091,
- EXCEPTION_FLT_UNDERFLOW = 0xc0000093,
- EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094,
- EXCEPTION_INT_OVERFLOW = 0xc0000095,
-
- INFINITE = 0xffffffff,
- WAIT_TIMEOUT = 0x102,
-
- EXCEPTION_CONTINUE_EXECUTION = -0x1,
- EXCEPTION_CONTINUE_SEARCH = 0x0,
-};
-
-typedef struct SystemInfo SystemInfo;
-typedef struct ExceptionRecord ExceptionRecord;
-typedef struct FloatingSaveArea FloatingSaveArea;
-typedef struct M128a M128a;
-typedef struct Context Context;
-typedef struct Overlapped Overlapped;
-
-#pragma pack on
-
-struct SystemInfo {
- byte anon0[4];
- uint32 dwPageSize;
- byte *lpMinimumApplicationAddress;
- byte *lpMaximumApplicationAddress;
- uint64 dwActiveProcessorMask;
- uint32 dwNumberOfProcessors;
- uint32 dwProcessorType;
- uint32 dwAllocationGranularity;
- uint16 wProcessorLevel;
- uint16 wProcessorRevision;
-};
-struct ExceptionRecord {
- uint32 ExceptionCode;
- uint32 ExceptionFlags;
- ExceptionRecord *ExceptionRecord;
- byte *ExceptionAddress;
- uint32 NumberParameters;
- byte Pad_cgo_0[4];
- uint64 ExceptionInformation[15];
-};
-struct M128a {
- uint64 Low;
- int64 High;
-};
-struct Context {
- uint64 P1Home;
- uint64 P2Home;
- uint64 P3Home;
- uint64 P4Home;
- uint64 P5Home;
- uint64 P6Home;
- uint32 ContextFlags;
- uint32 MxCsr;
- uint16 SegCs;
- uint16 SegDs;
- uint16 SegEs;
- uint16 SegFs;
- uint16 SegGs;
- uint16 SegSs;
- uint32 EFlags;
- uint64 Dr0;
- uint64 Dr1;
- uint64 Dr2;
- uint64 Dr3;
- uint64 Dr6;
- uint64 Dr7;
- uint64 Rax;
- uint64 Rcx;
- uint64 Rdx;
- uint64 Rbx;
- uint64 Rsp;
- uint64 Rbp;
- uint64 Rsi;
- uint64 Rdi;
- uint64 R8;
- uint64 R9;
- uint64 R10;
- uint64 R11;
- uint64 R12;
- uint64 R13;
- uint64 R14;
- uint64 R15;
- uint64 Rip;
- byte anon0[512];
- M128a VectorRegister[26];
- uint64 VectorControl;
- uint64 DebugControl;
- uint64 LastBranchToRip;
- uint64 LastBranchFromRip;
- uint64 LastExceptionToRip;
- uint64 LastExceptionFromRip;
-};
-struct Overlapped {
- uint64 Internal;
- uint64 InternalHigh;
- byte anon0[8];
- byte *hEvent;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go
index e442c3483..ec50cac48 100644
--- a/src/runtime/env_plan9.go
+++ b/src/runtime/env_plan9.go
@@ -54,3 +54,6 @@ func gogetenv(key string) string {
sp.len = int(r)
return s
}
+
+var _cgo_setenv unsafe.Pointer // pointer to C function
+var _cgo_unsetenv unsafe.Pointer // pointer to C function
diff --git a/src/runtime/env_posix.go b/src/runtime/env_posix.go
index dd57872d7..03c7a5a4a 100644
--- a/src/runtime/env_posix.go
+++ b/src/runtime/env_posix.go
@@ -8,8 +8,6 @@ package runtime
import "unsafe"
-func environ() []string
-
func getenv(s *byte) *byte {
val := gogetenv(gostringnocopy(s))
if val == "" {
@@ -32,13 +30,13 @@ func gogetenv(key string) string {
return ""
}
-var _cgo_setenv uintptr // pointer to C function
-var _cgo_unsetenv uintptr // pointer to C function
+var _cgo_setenv unsafe.Pointer // pointer to C function
+var _cgo_unsetenv unsafe.Pointer // pointer to C function
// Update the C environment if cgo is loaded.
// Called from syscall.Setenv.
func syscall_setenv_c(k string, v string) {
- if _cgo_setenv == 0 {
+ if _cgo_setenv == nil {
return
}
arg := [2]unsafe.Pointer{cstring(k), cstring(v)}
@@ -48,7 +46,7 @@ func syscall_setenv_c(k string, v string) {
// Update the C environment if cgo is loaded.
// Called from syscall.unsetenv.
func syscall_unsetenv_c(k string) {
- if _cgo_unsetenv == 0 {
+ if _cgo_unsetenv == nil {
return
}
arg := [1]unsafe.Pointer{cstring(k)}
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index be352557f..e871236e4 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -34,21 +34,11 @@ func lfstackpush_m()
func lfstackpop_m()
func LFStackPush(head *uint64, node *LFNode) {
- mp := acquirem()
- mp.ptrarg[0] = unsafe.Pointer(head)
- mp.ptrarg[1] = unsafe.Pointer(node)
- onM(lfstackpush_m)
- releasem(mp)
+ lfstackpush(head, (*lfnode)(unsafe.Pointer(node)))
}
func LFStackPop(head *uint64) *LFNode {
- mp := acquirem()
- mp.ptrarg[0] = unsafe.Pointer(head)
- onM(lfstackpop_m)
- node := (*LFNode)(unsafe.Pointer(mp.ptrarg[0]))
- mp.ptrarg[0] = nil
- releasem(mp)
- return node
+ return (*LFNode)(unsafe.Pointer(lfstackpop(head)))
}
type ParFor struct {
@@ -68,69 +58,49 @@ func parfordo_m()
func parforiters_m()
func NewParFor(nthrmax uint32) *ParFor {
- mp := acquirem()
- mp.scalararg[0] = uintptr(nthrmax)
- onM(newparfor_m)
- desc := (*ParFor)(mp.ptrarg[0])
- mp.ptrarg[0] = nil
- releasem(mp)
+ var desc *ParFor
+ systemstack(func() {
+ desc = (*ParFor)(unsafe.Pointer(parforalloc(nthrmax)))
+ })
return desc
}
func ParForSetup(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32)) {
- mp := acquirem()
- mp.ptrarg[0] = unsafe.Pointer(desc)
- mp.ptrarg[1] = unsafe.Pointer(ctx)
- mp.ptrarg[2] = unsafe.Pointer(funcPC(body)) // TODO(rsc): Should be a scalar.
- mp.scalararg[0] = uintptr(nthr)
- mp.scalararg[1] = uintptr(n)
- mp.scalararg[2] = 0
- if wait {
- mp.scalararg[2] = 1
- }
- onM(parforsetup_m)
- releasem(mp)
+ systemstack(func() {
+ parforsetup((*parfor)(unsafe.Pointer(desc)), nthr, n, unsafe.Pointer(ctx), wait,
+ *(*func(*parfor, uint32))(unsafe.Pointer(&body)))
+ })
}
func ParForDo(desc *ParFor) {
- mp := acquirem()
- mp.ptrarg[0] = unsafe.Pointer(desc)
- onM(parfordo_m)
- releasem(mp)
+ systemstack(func() {
+ parfordo((*parfor)(unsafe.Pointer(desc)))
+ })
}
func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
- mp := acquirem()
- mp.ptrarg[0] = unsafe.Pointer(desc)
- mp.scalararg[0] = uintptr(tid)
- onM(parforiters_m)
- begin := uint32(mp.scalararg[0])
- end := uint32(mp.scalararg[1])
- releasem(mp)
- return begin, end
+ desc1 := (*parfor)(unsafe.Pointer(desc))
+ pos := desc_thr_index(desc1, tid).pos
+ return uint32(pos), uint32(pos >> 32)
}
-// in mgc0.c
-//go:noescape
-func getgcmask(data unsafe.Pointer, typ *_type, array **byte, len *uint)
-
func GCMask(x interface{}) (ret []byte) {
e := (*eface)(unsafe.Pointer(&x))
s := (*slice)(unsafe.Pointer(&ret))
- onM(func() {
- getgcmask(e.data, e._type, &s.array, &s.len)
+ systemstack(func() {
+ var len uintptr
+ getgcmask(e.data, e._type, &s.array, &len)
+ s.len = uint(len)
s.cap = s.len
})
return
}
-func testSchedLocalQueue()
-func testSchedLocalQueueSteal()
func RunSchedLocalQueueTest() {
- onM(testSchedLocalQueue)
+ systemstack(testSchedLocalQueue)
}
func RunSchedLocalQueueStealTest() {
- onM(testSchedLocalQueueSteal)
+ systemstack(testSchedLocalQueueSteal)
}
var HaveGoodHash = haveGoodHash
@@ -149,13 +119,9 @@ func GogoBytes() int32 {
return _RuntimeGogoBytes
}
-// in string.c
-//go:noescape
-func gostringw(w *uint16) string
-
// entry point for testing
func GostringW(w []uint16) (s string) {
- onM(func() {
+ systemstack(func() {
s = gostringw(&w[0])
})
return
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index 6cc5df810..34fdeb2b4 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -112,7 +112,8 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
if xpc > f.entry && (g == nil || g.entry != funcPC(sigpanic)) {
xpc--
}
- line = int(funcline(f, xpc, &file))
+ file, line32 := funcline(f, xpc)
+ line = int(line32)
ok = true
return
}
diff --git a/src/runtime/float.c b/src/runtime/float.c
deleted file mode 100644
index 42082e434..000000000
--- a/src/runtime/float.c
+++ /dev/null
@@ -1,10 +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.
-
-#include "runtime.h"
-
-// used as float64 via runtime· names
-uint64 ·nan = 0x7FF8000000000001ULL;
-uint64 ·posinf = 0x7FF0000000000000ULL;
-uint64 ·neginf = 0xFFF0000000000000ULL;
diff --git a/src/runtime/funcdata.h b/src/runtime/funcdata.h
index d6c14fcb4..ce62dabe3 100644
--- a/src/runtime/funcdata.h
+++ b/src/runtime/funcdata.h
@@ -3,9 +3,10 @@
// license that can be found in the LICENSE file.
// This file defines the IDs for PCDATA and FUNCDATA instructions
-// in Go binaries. It is included by both C and assembly, so it must
-// be written using #defines. It is included by the runtime package
-// as well as the compilers.
+// in Go binaries. It is included by assembly sources, so it must
+// be written using #defines.
+//
+// The Go compiler also #includes this file, for now.
//
// symtab.go also contains a copy of these constants.
@@ -50,8 +51,7 @@
/*c2go
enum {
- PCDATA_ArgSize = 0,
- PCDATA_StackMapIndex = 1,
+ PCDATA_StackMapIndex = 0,
FUNCDATA_ArgsPointerMaps = 0,
FUNCDATA_LocalsPointerMaps = 1,
FUNCDATA_DeadValueMaps = 2,
diff --git a/src/runtime/futex_test.go b/src/runtime/futex_test.go
index f57fc52b8..b85249a54 100644
--- a/src/runtime/futex_test.go
+++ b/src/runtime/futex_test.go
@@ -44,9 +44,9 @@ func TestFutexsleep(t *testing.T) {
start := time.Now()
for _, tt := range futexsleepTests {
go func(tt futexsleepTest) {
- runtime.Entersyscall()
+ runtime.Entersyscall(0)
runtime.Futexsleep(&tt.mtx, tt.mtx, tt.ns)
- runtime.Exitsyscall()
+ runtime.Exitsyscall(0)
tt.ch <- tt
}(tt)
}
diff --git a/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go
index 88f6703f9..2b45c8184 100644
--- a/src/runtime/gcinfo_test.go
+++ b/src/runtime/gcinfo_test.go
@@ -62,12 +62,10 @@ func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) {
func nonStackInfo(mask []byte) []byte {
// BitsDead is replaced with BitsScalar everywhere except stacks.
mask1 := make([]byte, len(mask))
- mw := false
for i, v := range mask {
- if !mw && v == BitsDead {
+ if v == BitsDead {
v = BitsScalar
}
- mw = !mw && v == BitsMultiWord
mask1[i] = v
}
return mask1
@@ -84,7 +82,6 @@ const (
BitsDead = iota
BitsScalar
BitsPointer
- BitsMultiWord
)
const (
@@ -137,7 +134,7 @@ func infoBigStruct() []byte {
BitsScalar, BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64
BitsPointer, BitsDead, // i string
}
- case "amd64":
+ case "amd64", "power64", "power64le":
return []byte{
BitsPointer, // q *int
BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
@@ -188,6 +185,6 @@ var (
infoString = []byte{BitsPointer, BitsDead}
infoSlice = []byte{BitsPointer, BitsDead, BitsDead}
- infoEface = []byte{BitsMultiWord, BitsEface}
- infoIface = []byte{BitsMultiWord, BitsIface}
+ infoEface = []byte{BitsPointer, BitsPointer}
+ infoIface = []byte{BitsPointer, BitsPointer}
)
diff --git a/src/runtime/gengoos.go b/src/runtime/gengoos.go
new file mode 100644
index 000000000..06621c8db
--- /dev/null
+++ b/src/runtime/gengoos.go
@@ -0,0 +1,84 @@
+// 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.
+
+// +build ignore
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "strconv"
+ "strings"
+)
+
+var gooses, goarches []string
+
+func main() {
+ data, err := ioutil.ReadFile("../go/build/syslist.go")
+ if err != nil {
+ log.Fatal(err)
+ }
+ const (
+ goosPrefix = `const goosList = `
+ goarchPrefix = `const goarchList = `
+ )
+ for _, line := range strings.Split(string(data), "\n") {
+ if strings.HasPrefix(line, goosPrefix) {
+ text, err := strconv.Unquote(strings.TrimPrefix(line, goosPrefix))
+ if err != nil {
+ log.Fatalf("parsing goosList %#q: %v", strings.TrimPrefix(line, goosPrefix), err)
+ }
+ gooses = strings.Fields(text)
+ }
+ if strings.HasPrefix(line, goarchPrefix) {
+ text, err := strconv.Unquote(strings.TrimPrefix(line, goarchPrefix))
+ if err != nil {
+ log.Fatal("parsing goarchList: %v", err)
+ }
+ goarches = strings.Fields(text)
+ }
+ }
+
+ for _, target := range gooses {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n")
+ if target == "linux" {
+ fmt.Fprintf(&buf, "// +build !android\n\n") // must explicitly exclude android for linux
+ }
+ fmt.Fprintf(&buf, "package runtime\n\n")
+ fmt.Fprintf(&buf, "const theGoos = `%s`\n\n", target)
+ for _, goos := range gooses {
+ value := 0
+ if goos == target {
+ value = 1
+ }
+ fmt.Fprintf(&buf, "const goos_%s = %d\n", goos, value)
+ }
+ err := ioutil.WriteFile("zgoos_"+target+".go", buf.Bytes(), 0666)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ for _, target := range goarches {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n")
+ fmt.Fprintf(&buf, "package runtime\n\n")
+ fmt.Fprintf(&buf, "const theGoarch = `%s`\n\n", target)
+ for _, goarch := range goarches {
+ value := 0
+ if goarch == target {
+ value = 1
+ }
+ fmt.Fprintf(&buf, "const goarch_%s = %d\n", goarch, value)
+ }
+ err := ioutil.WriteFile("zgoarch_"+target+".go", buf.Bytes(), 0666)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+}
diff --git a/src/runtime/go_tls.h b/src/runtime/go_tls.h
new file mode 100644
index 000000000..6a707cf1e
--- /dev/null
+++ b/src/runtime/go_tls.h
@@ -0,0 +1,22 @@
+// 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.
+
+#ifdef GOARCH_arm
+#define LR R14
+#endif
+
+#ifdef GOARCH_amd64
+#define get_tls(r) MOVQ TLS, r
+#define g(r) 0(r)(TLS*1)
+#endif
+
+#ifdef GOARCH_amd64p32
+#define get_tls(r) MOVL TLS, r
+#define g(r) 0(r)(TLS*1)
+#endif
+
+#ifdef GOARCH_386
+#define get_tls(r) MOVL TLS, r
+#define g(r) 0(r)(TLS*1)
+#endif
diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c
deleted file mode 100644
index 7eba8c005..000000000
--- a/src/runtime/heapdump.c
+++ /dev/null
@@ -1,864 +0,0 @@
-// 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.
-
-// Implementation of runtime/debug.WriteHeapDump. Writes all
-// objects in the heap plus additional info (roots, threads,
-// finalizers, etc.) to a file.
-
-// The format of the dumped file is described at
-// http://golang.org/s/go14heapdump.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "mgc0.h"
-#include "type.h"
-#include "typekind.h"
-#include "funcdata.h"
-#include "zaexperiment.h"
-#include "textflag.h"
-
-extern byte runtime·data[];
-extern byte runtime·edata[];
-extern byte runtime·bss[];
-extern byte runtime·ebss[];
-
-enum {
- FieldKindEol = 0,
- FieldKindPtr = 1,
- FieldKindIface = 2,
- FieldKindEface = 3,
-
- TagEOF = 0,
- TagObject = 1,
- TagOtherRoot = 2,
- TagType = 3,
- TagGoRoutine = 4,
- TagStackFrame = 5,
- TagParams = 6,
- TagFinalizer = 7,
- TagItab = 8,
- TagOSThread = 9,
- TagMemStats = 10,
- TagQueuedFinalizer = 11,
- TagData = 12,
- TagBss = 13,
- TagDefer = 14,
- TagPanic = 15,
- TagMemProf = 16,
- TagAllocSample = 17,
-};
-
-static uintptr* playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg);
-static void dumpfields(BitVector bv);
-static void dumpbvtypes(BitVector *bv, byte *base);
-static BitVector makeheapobjbv(byte *p, uintptr size);
-
-// fd to write the dump to.
-static uintptr dumpfd;
-
-#pragma dataflag NOPTR /* tmpbuf not a heap pointer at least */
-static byte *tmpbuf;
-static uintptr tmpbufsize;
-
-// buffer of pending write data
-enum {
- BufSize = 4096,
-};
-#pragma dataflag NOPTR
-static byte buf[BufSize];
-static uintptr nbuf;
-
-static void
-write(byte *data, uintptr len)
-{
- if(len + nbuf <= BufSize) {
- runtime·memmove(buf + nbuf, data, len);
- nbuf += len;
- return;
- }
- runtime·write(dumpfd, buf, nbuf);
- if(len >= BufSize) {
- runtime·write(dumpfd, data, len);
- nbuf = 0;
- } else {
- runtime·memmove(buf, data, len);
- nbuf = len;
- }
-}
-
-static void
-flush(void)
-{
- runtime·write(dumpfd, buf, nbuf);
- nbuf = 0;
-}
-
-// Cache of types that have been serialized already.
-// We use a type's hash field to pick a bucket.
-// Inside a bucket, we keep a list of types that
-// have been serialized so far, most recently used first.
-// Note: when a bucket overflows we may end up
-// serializing a type more than once. That's ok.
-enum {
- TypeCacheBuckets = 256, // must be a power of 2
- TypeCacheAssoc = 4,
-};
-typedef struct TypeCacheBucket TypeCacheBucket;
-struct TypeCacheBucket {
- Type *t[TypeCacheAssoc];
-};
-#pragma dataflag NOPTR /* only initialized and used while world is stopped */
-static TypeCacheBucket typecache[TypeCacheBuckets];
-
-// dump a uint64 in a varint format parseable by encoding/binary
-static void
-dumpint(uint64 v)
-{
- byte buf[10];
- int32 n;
- n = 0;
- while(v >= 0x80) {
- buf[n++] = v | 0x80;
- v >>= 7;
- }
- buf[n++] = v;
- write(buf, n);
-}
-
-static void
-dumpbool(bool b)
-{
- dumpint(b ? 1 : 0);
-}
-
-// dump varint uint64 length followed by memory contents
-static void
-dumpmemrange(byte *data, uintptr len)
-{
- dumpint(len);
- write(data, len);
-}
-
-static void
-dumpstr(String s)
-{
- dumpmemrange(s.str, s.len);
-}
-
-static void
-dumpcstr(int8 *c)
-{
- dumpmemrange((byte*)c, runtime·findnull((byte*)c));
-}
-
-// dump information for a type
-static void
-dumptype(Type *t)
-{
- TypeCacheBucket *b;
- int32 i, j;
-
- if(t == nil) {
- return;
- }
-
- // If we've definitely serialized the type before,
- // no need to do it again.
- b = &typecache[t->hash & (TypeCacheBuckets-1)];
- if(t == b->t[0]) return;
- for(i = 1; i < TypeCacheAssoc; i++) {
- if(t == b->t[i]) {
- // Move-to-front
- for(j = i; j > 0; j--) {
- b->t[j] = b->t[j-1];
- }
- b->t[0] = t;
- return;
- }
- }
- // Might not have been dumped yet. Dump it and
- // remember we did so.
- for(j = TypeCacheAssoc-1; j > 0; j--) {
- b->t[j] = b->t[j-1];
- }
- b->t[0] = t;
-
- // dump the type
- dumpint(TagType);
- dumpint((uintptr)t);
- dumpint(t->size);
- if(t->x == nil || t->x->pkgPath == nil || t->x->name == nil) {
- dumpstr(*t->string);
- } else {
- dumpint(t->x->pkgPath->len + 1 + t->x->name->len);
- write(t->x->pkgPath->str, t->x->pkgPath->len);
- write((byte*)".", 1);
- write(t->x->name->str, t->x->name->len);
- }
- dumpbool((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0);
-}
-
-// dump an object
-static void
-dumpobj(byte *obj, uintptr size, BitVector bv)
-{
- dumpbvtypes(&bv, obj);
- dumpint(TagObject);
- dumpint((uintptr)obj);
- dumpmemrange(obj, size);
- dumpfields(bv);
-}
-
-static void
-dumpotherroot(int8 *description, byte *to)
-{
- dumpint(TagOtherRoot);
- dumpcstr(description);
- dumpint((uintptr)to);
-}
-
-static void
-dumpfinalizer(byte *obj, FuncVal *fn, Type* fint, PtrType *ot)
-{
- dumpint(TagFinalizer);
- dumpint((uintptr)obj);
- dumpint((uintptr)fn);
- dumpint((uintptr)fn->fn);
- dumpint((uintptr)fint);
- dumpint((uintptr)ot);
-}
-
-typedef struct ChildInfo ChildInfo;
-struct ChildInfo {
- // Information passed up from the callee frame about
- // the layout of the outargs region.
- uintptr argoff; // where the arguments start in the frame
- uintptr arglen; // size of args region
- BitVector args; // if args.n >= 0, pointer map of args region
-
- byte *sp; // callee sp
- uintptr depth; // depth in call stack (0 == most recent)
-};
-
-// dump kinds & offsets of interesting fields in bv
-static void
-dumpbv(BitVector *bv, uintptr offset)
-{
- uintptr i;
-
- for(i = 0; i < bv->n; i += BitsPerPointer) {
- switch(bv->bytedata[i/8] >> i%8 & 3) {
- case BitsDead:
- // BitsDead has already been processed in makeheapobjbv.
- // We should only see it in stack maps, in which case we should continue processing.
- break;
- case BitsScalar:
- break;
- case BitsPointer:
- dumpint(FieldKindPtr);
- dumpint(offset + i / BitsPerPointer * PtrSize);
- break;
- case BitsMultiWord:
- switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
- default:
- runtime·throw("unexpected garbage collection bits");
- case BitsIface:
- dumpint(FieldKindIface);
- dumpint(offset + i / BitsPerPointer * PtrSize);
- i += BitsPerPointer;
- break;
- case BitsEface:
- dumpint(FieldKindEface);
- dumpint(offset + i / BitsPerPointer * PtrSize);
- i += BitsPerPointer;
- break;
- }
- }
- }
-}
-
-static bool
-dumpframe(Stkframe *s, void *arg)
-{
- Func *f;
- ChildInfo *child;
- uintptr pc, off, size;
- int32 pcdata;
- StackMap *stackmap;
- int8 *name;
- BitVector bv;
-
- child = (ChildInfo*)arg;
- f = s->fn;
-
- // Figure out what we can about our stack map
- pc = s->pc;
- if(pc != f->entry)
- pc--;
- pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, pc);
- if(pcdata == -1) {
- // We do not have a valid pcdata value but there might be a
- // stackmap for this function. It is likely that we are looking
- // at the function prologue, assume so and hope for the best.
- pcdata = 0;
- }
- stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
-
- // Dump any types we will need to resolve Efaces.
- if(child->args.n >= 0)
- dumpbvtypes(&child->args, (byte*)s->sp + child->argoff);
- if(stackmap != nil && stackmap->n > 0) {
- bv = runtime·stackmapdata(stackmap, pcdata);
- dumpbvtypes(&bv, (byte*)(s->varp - bv.n / BitsPerPointer * PtrSize));
- } else {
- bv.n = -1;
- }
-
- // Dump main body of stack frame.
- dumpint(TagStackFrame);
- dumpint(s->sp); // lowest address in frame
- dumpint(child->depth); // # of frames deep on the stack
- dumpint((uintptr)child->sp); // sp of child, or 0 if bottom of stack
- dumpmemrange((byte*)s->sp, s->fp - s->sp); // frame contents
- dumpint(f->entry);
- dumpint(s->pc);
- dumpint(s->continpc);
- name = runtime·funcname(f);
- if(name == nil)
- name = "unknown function";
- dumpcstr(name);
-
- // Dump fields in the outargs section
- if(child->args.n >= 0) {
- dumpbv(&child->args, child->argoff);
- } else {
- // conservative - everything might be a pointer
- for(off = child->argoff; off < child->argoff + child->arglen; off += PtrSize) {
- dumpint(FieldKindPtr);
- dumpint(off);
- }
- }
-
- // Dump fields in the local vars section
- if(stackmap == nil) {
- // No locals information, dump everything.
- for(off = child->arglen; off < s->varp - s->sp; off += PtrSize) {
- dumpint(FieldKindPtr);
- dumpint(off);
- }
- } else if(stackmap->n < 0) {
- // Locals size information, dump just the locals.
- size = -stackmap->n;
- for(off = s->varp - size - s->sp; off < s->varp - s->sp; off += PtrSize) {
- dumpint(FieldKindPtr);
- dumpint(off);
- }
- } else if(stackmap->n > 0) {
- // Locals bitmap information, scan just the pointers in
- // locals.
- dumpbv(&bv, s->varp - bv.n / BitsPerPointer * PtrSize - s->sp);
- }
- dumpint(FieldKindEol);
-
- // Record arg info for parent.
- child->argoff = s->argp - s->fp;
- child->arglen = s->arglen;
- child->sp = (byte*)s->sp;
- child->depth++;
- stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
- if(stackmap != nil)
- child->args = runtime·stackmapdata(stackmap, pcdata);
- else
- child->args.n = -1;
- return true;
-}
-
-static void
-dumpgoroutine(G *gp)
-{
- uintptr sp, pc, lr;
- ChildInfo child;
- Defer *d;
- Panic *p;
- bool (*fn)(Stkframe*, void*);
-
- if(gp->syscallsp != (uintptr)nil) {
- sp = gp->syscallsp;
- pc = gp->syscallpc;
- lr = 0;
- } else {
- sp = gp->sched.sp;
- pc = gp->sched.pc;
- lr = gp->sched.lr;
- }
-
- dumpint(TagGoRoutine);
- dumpint((uintptr)gp);
- dumpint((uintptr)sp);
- dumpint(gp->goid);
- dumpint(gp->gopc);
- dumpint(runtime·readgstatus(gp));
- dumpbool(gp->issystem);
- dumpbool(false); // isbackground
- dumpint(gp->waitsince);
- dumpstr(gp->waitreason);
- dumpint((uintptr)gp->sched.ctxt);
- dumpint((uintptr)gp->m);
- dumpint((uintptr)gp->defer);
- dumpint((uintptr)gp->panic);
-
- // dump stack
- child.args.n = -1;
- child.arglen = 0;
- child.sp = nil;
- child.depth = 0;
- fn = dumpframe;
- runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, &fn, &child, 0);
-
- // dump defer & panic records
- for(d = gp->defer; d != nil; d = d->link) {
- dumpint(TagDefer);
- dumpint((uintptr)d);
- dumpint((uintptr)gp);
- dumpint((uintptr)d->argp);
- dumpint((uintptr)d->pc);
- dumpint((uintptr)d->fn);
- dumpint((uintptr)d->fn->fn);
- dumpint((uintptr)d->link);
- }
- for (p = gp->panic; p != nil; p = p->link) {
- dumpint(TagPanic);
- dumpint((uintptr)p);
- dumpint((uintptr)gp);
- dumpint((uintptr)p->arg.type);
- dumpint((uintptr)p->arg.data);
- dumpint(0); // was p->defer, no longer recorded
- dumpint((uintptr)p->link);
- }
-}
-
-static void
-dumpgs(void)
-{
- G *gp;
- uint32 i;
- uint32 status;
-
- // goroutines & stacks
- for(i = 0; i < runtime·allglen; i++) {
- gp = runtime·allg[i];
- status = runtime·readgstatus(gp); // The world is stopped so gp will not be in a scan state.
- switch(status){
- default:
- runtime·printf("runtime: unexpected G.status %d\n", status);
- runtime·throw("dumpgs in STW - bad status");
- case Gdead:
- break;
- case Grunnable:
- case Gsyscall:
- case Gwaiting:
- dumpgoroutine(gp);
- break;
- }
- }
-}
-
-static void
-finq_callback(FuncVal *fn, byte *obj, uintptr nret, Type *fint, PtrType *ot)
-{
- dumpint(TagQueuedFinalizer);
- dumpint((uintptr)obj);
- dumpint((uintptr)fn);
- dumpint((uintptr)fn->fn);
- dumpint((uintptr)fint);
- dumpint((uintptr)ot);
- USED(&nret);
-}
-
-
-static void
-dumproots(void)
-{
- MSpan *s, **allspans;
- uint32 spanidx;
- Special *sp;
- SpecialFinalizer *spf;
- byte *p;
-
- // data segment
- dumpbvtypes(&runtime·gcdatamask, runtime·data);
- dumpint(TagData);
- dumpint((uintptr)runtime·data);
- dumpmemrange(runtime·data, runtime·edata - runtime·data);
- dumpfields(runtime·gcdatamask);
-
- // bss segment
- dumpbvtypes(&runtime·gcbssmask, runtime·bss);
- dumpint(TagBss);
- dumpint((uintptr)runtime·bss);
- dumpmemrange(runtime·bss, runtime·ebss - runtime·bss);
- dumpfields(runtime·gcbssmask);
-
- // MSpan.types
- allspans = runtime·mheap.allspans;
- for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
- s = allspans[spanidx];
- if(s->state == MSpanInUse) {
- // Finalizers
- for(sp = s->specials; sp != nil; sp = sp->next) {
- if(sp->kind != KindSpecialFinalizer)
- continue;
- spf = (SpecialFinalizer*)sp;
- p = (byte*)((s->start << PageShift) + spf->special.offset);
- dumpfinalizer(p, spf->fn, spf->fint, spf->ot);
- }
- }
- }
-
- // Finalizer queue
- runtime·iterate_finq(finq_callback);
-}
-
-// Bit vector of free marks.
-// Needs to be as big as the largest number of objects per span.
-#pragma dataflag NOPTR
-static byte free[PageSize/8];
-
-static void
-dumpobjs(void)
-{
- uintptr i, j, size, n;
- MSpan *s;
- MLink *l;
- byte *p;
-
- for(i = 0; i < runtime·mheap.nspan; i++) {
- s = runtime·mheap.allspans[i];
- if(s->state != MSpanInUse)
- continue;
- p = (byte*)(s->start << PageShift);
- size = s->elemsize;
- n = (s->npages << PageShift) / size;
- if(n > nelem(free))
- runtime·throw("free array doesn't have enough entries");
- for(l = s->freelist; l != nil; l = l->next)
- free[((byte*)l - p) / size] = true;
- for(j = 0; j < n; j++, p += size) {
- if(free[j]) {
- free[j] = false;
- continue;
- }
- dumpobj(p, size, makeheapobjbv(p, size));
- }
- }
-}
-
-static void
-dumpparams(void)
-{
- byte *x;
-
- dumpint(TagParams);
- x = (byte*)1;
- if(*(byte*)&x == 1)
- dumpbool(false); // little-endian ptrs
- else
- dumpbool(true); // big-endian ptrs
- dumpint(PtrSize);
- dumpint((uintptr)runtime·mheap.arena_start);
- dumpint((uintptr)runtime·mheap.arena_used);
- dumpint(thechar);
- dumpcstr(GOEXPERIMENT);
- dumpint(runtime·ncpu);
-}
-
-static void
-itab_callback(Itab *tab)
-{
- Type *t;
-
- t = tab->type;
- // Dump a map from itab* to the type of its data field.
- // We want this map so we can deduce types of interface referents.
- if((t->kind & KindDirectIface) == 0) {
- // indirect - data slot is a pointer to t.
- dumptype(t->ptrto);
- dumpint(TagItab);
- dumpint((uintptr)tab);
- dumpint((uintptr)t->ptrto);
- } else if((t->kind & KindNoPointers) == 0) {
- // t is pointer-like - data slot is a t.
- dumptype(t);
- dumpint(TagItab);
- dumpint((uintptr)tab);
- dumpint((uintptr)t);
- } else {
- // Data slot is a scalar. Dump type just for fun.
- // With pointer-only interfaces, this shouldn't happen.
- dumptype(t);
- dumpint(TagItab);
- dumpint((uintptr)tab);
- dumpint((uintptr)t);
- }
-}
-
-static void
-dumpitabs(void)
-{
- void (*fn)(Itab*);
-
- fn = itab_callback;
- runtime·iterate_itabs(&fn);
-}
-
-static void
-dumpms(void)
-{
- M *mp;
-
- for(mp = runtime·allm; mp != nil; mp = mp->alllink) {
- dumpint(TagOSThread);
- dumpint((uintptr)mp);
- dumpint(mp->id);
- dumpint(mp->procid);
- }
-}
-
-static void
-dumpmemstats(void)
-{
- int32 i;
-
- dumpint(TagMemStats);
- dumpint(mstats.alloc);
- dumpint(mstats.total_alloc);
- dumpint(mstats.sys);
- dumpint(mstats.nlookup);
- dumpint(mstats.nmalloc);
- dumpint(mstats.nfree);
- dumpint(mstats.heap_alloc);
- dumpint(mstats.heap_sys);
- dumpint(mstats.heap_idle);
- dumpint(mstats.heap_inuse);
- dumpint(mstats.heap_released);
- dumpint(mstats.heap_objects);
- dumpint(mstats.stacks_inuse);
- dumpint(mstats.stacks_sys);
- dumpint(mstats.mspan_inuse);
- dumpint(mstats.mspan_sys);
- dumpint(mstats.mcache_inuse);
- dumpint(mstats.mcache_sys);
- dumpint(mstats.buckhash_sys);
- dumpint(mstats.gc_sys);
- dumpint(mstats.other_sys);
- dumpint(mstats.next_gc);
- dumpint(mstats.last_gc);
- dumpint(mstats.pause_total_ns);
- for(i = 0; i < 256; i++)
- dumpint(mstats.pause_ns[i]);
- dumpint(mstats.numgc);
-}
-
-static void
-dumpmemprof_callback(Bucket *b, uintptr nstk, uintptr *stk, uintptr size, uintptr allocs, uintptr frees)
-{
- uintptr i, pc;
- Func *f;
- byte buf[20];
- String file;
- int32 line;
-
- dumpint(TagMemProf);
- dumpint((uintptr)b);
- dumpint(size);
- dumpint(nstk);
- for(i = 0; i < nstk; i++) {
- pc = stk[i];
- f = runtime·findfunc(pc);
- if(f == nil) {
- runtime·snprintf(buf, sizeof(buf), "%X", (uint64)pc);
- dumpcstr((int8*)buf);
- dumpcstr("?");
- dumpint(0);
- } else {
- dumpcstr(runtime·funcname(f));
- // TODO: Why do we need to back up to a call instruction here?
- // Maybe profiler should do this.
- if(i > 0 && pc > f->entry) {
- if(thechar == '6' || thechar == '8')
- pc--;
- else
- pc -= 4; // arm, etc
- }
- line = runtime·funcline(f, pc, &file);
- dumpstr(file);
- dumpint(line);
- }
- }
- dumpint(allocs);
- dumpint(frees);
-}
-
-static void
-dumpmemprof(void)
-{
- MSpan *s, **allspans;
- uint32 spanidx;
- Special *sp;
- SpecialProfile *spp;
- byte *p;
- void (*fn)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr);
-
- fn = dumpmemprof_callback;
- runtime·iterate_memprof(&fn);
-
- allspans = runtime·mheap.allspans;
- for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
- s = allspans[spanidx];
- if(s->state != MSpanInUse)
- continue;
- for(sp = s->specials; sp != nil; sp = sp->next) {
- if(sp->kind != KindSpecialProfile)
- continue;
- spp = (SpecialProfile*)sp;
- p = (byte*)((s->start << PageShift) + spp->special.offset);
- dumpint(TagAllocSample);
- dumpint((uintptr)p);
- dumpint((uintptr)spp->b);
- }
- }
-}
-
-static void
-mdump(void)
-{
- byte *hdr;
- uintptr i;
- MSpan *s;
-
- // make sure we're done sweeping
- for(i = 0; i < runtime·mheap.nspan; i++) {
- s = runtime·mheap.allspans[i];
- if(s->state == MSpanInUse)
- runtime·MSpan_EnsureSwept(s);
- }
-
- runtime·memclr((byte*)&typecache[0], sizeof(typecache));
- hdr = (byte*)"go1.4 heap dump\n";
- write(hdr, runtime·findnull(hdr));
- dumpparams();
- dumpitabs();
- dumpobjs();
- dumpgs();
- dumpms();
- dumproots();
- dumpmemstats();
- dumpmemprof();
- dumpint(TagEOF);
- flush();
-}
-
-void
-runtime·writeheapdump_m(void)
-{
- uintptr fd;
-
- fd = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
-
- runtime·casgstatus(g->m->curg, Grunning, Gwaiting);
- g->waitreason = runtime·gostringnocopy((byte*)"dumping heap");
-
- // Update stats so we can dump them.
- // As a side effect, flushes all the MCaches so the MSpan.freelist
- // lists contain all the free objects.
- runtime·updatememstats(nil);
-
- // Set dump file.
- dumpfd = fd;
-
- // Call dump routine.
- mdump();
-
- // Reset dump file.
- dumpfd = 0;
- if(tmpbuf != nil) {
- runtime·SysFree(tmpbuf, tmpbufsize, &mstats.other_sys);
- tmpbuf = nil;
- tmpbufsize = 0;
- }
-
- runtime·casgstatus(g->m->curg, Gwaiting, Grunning);
-}
-
-// dumpint() the kind & offset of each field in an object.
-static void
-dumpfields(BitVector bv)
-{
- dumpbv(&bv, 0);
- dumpint(FieldKindEol);
-}
-
-// The heap dump reader needs to be able to disambiguate
-// Eface entries. So it needs to know every type that might
-// appear in such an entry. The following routine accomplishes that.
-
-// Dump all the types that appear in the type field of
-// any Eface described by this bit vector.
-static void
-dumpbvtypes(BitVector *bv, byte *base)
-{
- uintptr i;
-
- for(i = 0; i < bv->n; i += BitsPerPointer) {
- if((bv->bytedata[i/8] >> i%8 & 3) != BitsMultiWord)
- continue;
- switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
- default:
- runtime·throw("unexpected garbage collection bits");
- case BitsIface:
- i += BitsPerPointer;
- break;
- case BitsEface:
- dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize));
- i += BitsPerPointer;
- break;
- }
- }
-}
-
-static BitVector
-makeheapobjbv(byte *p, uintptr size)
-{
- uintptr off, nptr, i;
- byte shift, *bitp, bits;
- bool mw;
-
- // Extend the temp buffer if necessary.
- nptr = size/PtrSize;
- if(tmpbufsize < nptr*BitsPerPointer/8+1) {
- if(tmpbuf != nil)
- runtime·SysFree(tmpbuf, tmpbufsize, &mstats.other_sys);
- tmpbufsize = nptr*BitsPerPointer/8+1;
- tmpbuf = runtime·sysAlloc(tmpbufsize, &mstats.other_sys);
- if(tmpbuf == nil)
- runtime·throw("heapdump: out of memory");
- }
-
- // Copy and compact the bitmap.
- mw = false;
- for(i = 0; i < nptr; i++) {
- off = (uintptr*)(p + i*PtrSize) - (uintptr*)runtime·mheap.arena_start;
- bitp = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
- shift = (off % wordsPerBitmapByte) * gcBits;
- bits = (*bitp >> (shift + 2)) & BitsMask;
- if(!mw && bits == BitsDead)
- break; // end of heap object
- mw = !mw && bits == BitsMultiWord;
- tmpbuf[i*BitsPerPointer/8] &= ~(BitsMask<<((i*BitsPerPointer)%8));
- tmpbuf[i*BitsPerPointer/8] |= bits<<((i*BitsPerPointer)%8);
- }
- return (BitVector){i*BitsPerPointer, tmpbuf};
-}
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
new file mode 100644
index 000000000..0c1a60c8b
--- /dev/null
+++ b/src/runtime/heapdump.go
@@ -0,0 +1,729 @@
+// 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.
+
+// Implementation of runtime/debug.WriteHeapDump. Writes all
+// objects in the heap plus additional info (roots, threads,
+// finalizers, etc.) to a file.
+
+// The format of the dumped file is described at
+// http://golang.org/s/go14heapdump.
+
+package runtime
+
+import "unsafe"
+
+const (
+ fieldKindEol = 0
+ fieldKindPtr = 1
+ fieldKindIface = 2
+ fieldKindEface = 3
+ tagEOF = 0
+ tagObject = 1
+ tagOtherRoot = 2
+ tagType = 3
+ tagGoroutine = 4
+ tagStackFrame = 5
+ tagParams = 6
+ tagFinalizer = 7
+ tagItab = 8
+ tagOSThread = 9
+ tagMemStats = 10
+ tagQueuedFinalizer = 11
+ tagData = 12
+ tagBSS = 13
+ tagDefer = 14
+ tagPanic = 15
+ tagMemProf = 16
+ tagAllocSample = 17
+)
+
+var dumpfd uintptr // fd to write the dump to.
+var tmpbuf []byte
+
+// buffer of pending write data
+const (
+ bufSize = 4096
+)
+
+var buf [bufSize]byte
+var nbuf uintptr
+
+func dwrite(data unsafe.Pointer, len uintptr) {
+ if len == 0 {
+ return
+ }
+ if nbuf+len <= bufSize {
+ copy(buf[nbuf:], (*[bufSize]byte)(data)[:len])
+ nbuf += len
+ return
+ }
+
+ write(dumpfd, (unsafe.Pointer)(&buf), int32(nbuf))
+ if len >= bufSize {
+ write(dumpfd, data, int32(len))
+ nbuf = 0
+ } else {
+ copy(buf[:], (*[bufSize]byte)(data)[:len])
+ nbuf = len
+ }
+}
+
+func dwritebyte(b byte) {
+ dwrite(unsafe.Pointer(&b), 1)
+}
+
+func flush() {
+ write(dumpfd, (unsafe.Pointer)(&buf), int32(nbuf))
+ nbuf = 0
+}
+
+// Cache of types that have been serialized already.
+// We use a type's hash field to pick a bucket.
+// Inside a bucket, we keep a list of types that
+// have been serialized so far, most recently used first.
+// Note: when a bucket overflows we may end up
+// serializing a type more than once. That's ok.
+const (
+ typeCacheBuckets = 256
+ typeCacheAssoc = 4
+)
+
+type typeCacheBucket struct {
+ t [typeCacheAssoc]*_type
+}
+
+var typecache [typeCacheBuckets]typeCacheBucket
+
+// dump a uint64 in a varint format parseable by encoding/binary
+func dumpint(v uint64) {
+ var buf [10]byte
+ var n int
+ for v >= 0x80 {
+ buf[n] = byte(v | 0x80)
+ n++
+ v >>= 7
+ }
+ buf[n] = byte(v)
+ n++
+ dwrite(unsafe.Pointer(&buf), uintptr(n))
+}
+
+func dumpbool(b bool) {
+ if b {
+ dumpint(1)
+ } else {
+ dumpint(0)
+ }
+}
+
+// dump varint uint64 length followed by memory contents
+func dumpmemrange(data unsafe.Pointer, len uintptr) {
+ dumpint(uint64(len))
+ dwrite(data, len)
+}
+
+func dumpslice(b []byte) {
+ dumpint(uint64(len(b)))
+ if len(b) > 0 {
+ dwrite(unsafe.Pointer(&b[0]), uintptr(len(b)))
+ }
+}
+
+func dumpstr(s string) {
+ sp := (*stringStruct)(unsafe.Pointer(&s))
+ dumpmemrange(sp.str, uintptr(sp.len))
+}
+
+// dump information for a type
+func dumptype(t *_type) {
+ if t == nil {
+ return
+ }
+
+ // If we've definitely serialized the type before,
+ // no need to do it again.
+ b := &typecache[t.hash&(typeCacheBuckets-1)]
+ if t == b.t[0] {
+ return
+ }
+ for i := 1; i < typeCacheAssoc; i++ {
+ if t == b.t[i] {
+ // Move-to-front
+ for j := i; j > 0; j-- {
+ b.t[j] = b.t[j-1]
+ }
+ b.t[0] = t
+ return
+ }
+ }
+
+ // Might not have been dumped yet. Dump it and
+ // remember we did so.
+ for j := typeCacheAssoc - 1; j > 0; j-- {
+ b.t[j] = b.t[j-1]
+ }
+ b.t[0] = t
+
+ // dump the type
+ dumpint(tagType)
+ dumpint(uint64(uintptr(unsafe.Pointer(t))))
+ dumpint(uint64(t.size))
+ if t.x == nil || t.x.pkgpath == nil || t.x.name == nil {
+ dumpstr(*t._string)
+ } else {
+ pkgpath := (*stringStruct)(unsafe.Pointer(&t.x.pkgpath))
+ name := (*stringStruct)(unsafe.Pointer(&t.x.name))
+ dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
+ dwrite(pkgpath.str, uintptr(pkgpath.len))
+ dwritebyte('.')
+ dwrite(name.str, uintptr(name.len))
+ }
+ dumpbool(t.kind&kindDirectIface == 0 || t.kind&kindNoPointers == 0)
+}
+
+// dump an object
+func dumpobj(obj unsafe.Pointer, size uintptr, bv bitvector) {
+ dumpbvtypes(&bv, obj)
+ dumpint(tagObject)
+ dumpint(uint64(uintptr(obj)))
+ dumpmemrange(obj, size)
+ dumpfields(bv)
+}
+
+func dumpotherroot(description string, to unsafe.Pointer) {
+ dumpint(tagOtherRoot)
+ dumpstr(description)
+ dumpint(uint64(uintptr(to)))
+}
+
+func dumpfinalizer(obj unsafe.Pointer, fn *funcval, fint *_type, ot *ptrtype) {
+ dumpint(tagFinalizer)
+ dumpint(uint64(uintptr(obj)))
+ dumpint(uint64(uintptr(unsafe.Pointer(fn))))
+ dumpint(uint64(uintptr(unsafe.Pointer(fn.fn))))
+ dumpint(uint64(uintptr(unsafe.Pointer(fint))))
+ dumpint(uint64(uintptr(unsafe.Pointer(ot))))
+}
+
+type childInfo struct {
+ // Information passed up from the callee frame about
+ // the layout of the outargs region.
+ argoff uintptr // where the arguments start in the frame
+ arglen uintptr // size of args region
+ args bitvector // if args.n >= 0, pointer map of args region
+ sp *uint8 // callee sp
+ depth uintptr // depth in call stack (0 == most recent)
+}
+
+// dump kinds & offsets of interesting fields in bv
+func dumpbv(cbv *bitvector, offset uintptr) {
+ bv := gobv(*cbv)
+ for i := uintptr(0); i < uintptr(bv.n); i += bitsPerPointer {
+ switch bv.bytedata[i/8] >> (i % 8) & 3 {
+ default:
+ gothrow("unexpected pointer bits")
+ case _BitsDead:
+ // BitsDead has already been processed in makeheapobjbv.
+ // We should only see it in stack maps, in which case we should continue processing.
+ case _BitsScalar:
+ // ok
+ case _BitsPointer:
+ dumpint(fieldKindPtr)
+ dumpint(uint64(offset + i/_BitsPerPointer*ptrSize))
+ }
+ }
+}
+
+func dumpframe(s *stkframe, arg unsafe.Pointer) bool {
+ child := (*childInfo)(arg)
+ f := s.fn
+
+ // Figure out what we can about our stack map
+ pc := s.pc
+ if pc != f.entry {
+ pc--
+ }
+ pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, pc)
+ if pcdata == -1 {
+ // We do not have a valid pcdata value but there might be a
+ // stackmap for this function. It is likely that we are looking
+ // at the function prologue, assume so and hope for the best.
+ pcdata = 0
+ }
+ stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
+
+ // Dump any types we will need to resolve Efaces.
+ if child.args.n >= 0 {
+ dumpbvtypes(&child.args, unsafe.Pointer(s.sp+child.argoff))
+ }
+ var bv bitvector
+ if stkmap != nil && stkmap.n > 0 {
+ bv = stackmapdata(stkmap, pcdata)
+ dumpbvtypes(&bv, unsafe.Pointer(s.varp-uintptr(bv.n/_BitsPerPointer*ptrSize)))
+ } else {
+ bv.n = -1
+ }
+
+ // Dump main body of stack frame.
+ dumpint(tagStackFrame)
+ dumpint(uint64(s.sp)) // lowest address in frame
+ dumpint(uint64(child.depth)) // # of frames deep on the stack
+ dumpint(uint64(uintptr(unsafe.Pointer(child.sp)))) // sp of child, or 0 if bottom of stack
+ dumpmemrange(unsafe.Pointer(s.sp), s.fp-s.sp) // frame contents
+ dumpint(uint64(f.entry))
+ dumpint(uint64(s.pc))
+ dumpint(uint64(s.continpc))
+ name := gofuncname(f)
+ if name == "" {
+ name = "unknown function"
+ }
+ dumpstr(name)
+
+ // Dump fields in the outargs section
+ if child.args.n >= 0 {
+ dumpbv(&child.args, child.argoff)
+ } else {
+ // conservative - everything might be a pointer
+ for off := child.argoff; off < child.argoff+child.arglen; off += ptrSize {
+ dumpint(fieldKindPtr)
+ dumpint(uint64(off))
+ }
+ }
+
+ // Dump fields in the local vars section
+ if stkmap == nil {
+ // No locals information, dump everything.
+ for off := child.arglen; off < s.varp-s.sp; off += ptrSize {
+ dumpint(fieldKindPtr)
+ dumpint(uint64(off))
+ }
+ } else if stkmap.n < 0 {
+ // Locals size information, dump just the locals.
+ size := uintptr(-stkmap.n)
+ for off := s.varp - size - s.sp; off < s.varp-s.sp; off += ptrSize {
+ dumpint(fieldKindPtr)
+ dumpint(uint64(off))
+ }
+ } else if stkmap.n > 0 {
+ // Locals bitmap information, scan just the pointers in
+ // locals.
+ dumpbv(&bv, s.varp-uintptr(bv.n)/_BitsPerPointer*ptrSize-s.sp)
+ }
+ dumpint(fieldKindEol)
+
+ // Record arg info for parent.
+ child.argoff = s.argp - s.fp
+ child.arglen = s.arglen
+ child.sp = (*uint8)(unsafe.Pointer(s.sp))
+ child.depth++
+ stkmap = (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps))
+ if stkmap != nil {
+ child.args = stackmapdata(stkmap, pcdata)
+ } else {
+ child.args.n = -1
+ }
+ return true
+}
+
+func dumpgoroutine(gp *g) {
+ var sp, pc, lr uintptr
+ if gp.syscallsp != 0 {
+ sp = gp.syscallsp
+ pc = gp.syscallpc
+ lr = 0
+ } else {
+ sp = gp.sched.sp
+ pc = gp.sched.pc
+ lr = gp.sched.lr
+ }
+
+ dumpint(tagGoroutine)
+ dumpint(uint64(uintptr(unsafe.Pointer(gp))))
+ dumpint(uint64(sp))
+ dumpint(uint64(gp.goid))
+ dumpint(uint64(gp.gopc))
+ dumpint(uint64(readgstatus(gp)))
+ dumpbool(gp.issystem)
+ dumpbool(false) // isbackground
+ dumpint(uint64(gp.waitsince))
+ dumpstr(gp.waitreason)
+ dumpint(uint64(uintptr(gp.sched.ctxt)))
+ dumpint(uint64(uintptr(unsafe.Pointer(gp.m))))
+ dumpint(uint64(uintptr(unsafe.Pointer(gp._defer))))
+ dumpint(uint64(uintptr(unsafe.Pointer(gp._panic))))
+
+ // dump stack
+ var child childInfo
+ child.args.n = -1
+ child.arglen = 0
+ child.sp = nil
+ child.depth = 0
+ gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, dumpframe, noescape(unsafe.Pointer(&child)), 0)
+
+ // dump defer & panic records
+ for d := gp._defer; d != nil; d = d.link {
+ dumpint(tagDefer)
+ dumpint(uint64(uintptr(unsafe.Pointer(d))))
+ dumpint(uint64(uintptr(unsafe.Pointer(gp))))
+ dumpint(uint64(d.argp))
+ dumpint(uint64(d.pc))
+ dumpint(uint64(uintptr(unsafe.Pointer(d.fn))))
+ dumpint(uint64(uintptr(unsafe.Pointer(d.fn.fn))))
+ dumpint(uint64(uintptr(unsafe.Pointer(d.link))))
+ }
+ for p := gp._panic; p != nil; p = p.link {
+ dumpint(tagPanic)
+ dumpint(uint64(uintptr(unsafe.Pointer(p))))
+ dumpint(uint64(uintptr(unsafe.Pointer(gp))))
+ eface := (*eface)(unsafe.Pointer(&p.arg))
+ dumpint(uint64(uintptr(unsafe.Pointer(eface._type))))
+ dumpint(uint64(uintptr(unsafe.Pointer(eface.data))))
+ dumpint(0) // was p->defer, no longer recorded
+ dumpint(uint64(uintptr(unsafe.Pointer(p.link))))
+ }
+}
+
+func dumpgs() {
+ // goroutines & stacks
+ for i := 0; uintptr(i) < allglen; i++ {
+ gp := allgs[i]
+ status := readgstatus(gp) // The world is stopped so gp will not be in a scan state.
+ switch status {
+ default:
+ print("runtime: unexpected G.status ", hex(status), "\n")
+ gothrow("dumpgs in STW - bad status")
+ case _Gdead:
+ // ok
+ case _Grunnable,
+ _Gsyscall,
+ _Gwaiting:
+ dumpgoroutine(gp)
+ }
+ }
+}
+
+func finq_callback(fn *funcval, obj unsafe.Pointer, nret uintptr, fint *_type, ot *ptrtype) {
+ dumpint(tagQueuedFinalizer)
+ dumpint(uint64(uintptr(obj)))
+ dumpint(uint64(uintptr(unsafe.Pointer(fn))))
+ dumpint(uint64(uintptr(unsafe.Pointer(fn.fn))))
+ dumpint(uint64(uintptr(unsafe.Pointer(fint))))
+ dumpint(uint64(uintptr(unsafe.Pointer(ot))))
+}
+
+func dumproots() {
+ // data segment
+ dumpbvtypes(&gcdatamask, unsafe.Pointer(&data))
+ dumpint(tagData)
+ dumpint(uint64(uintptr(unsafe.Pointer(&data))))
+ dumpmemrange(unsafe.Pointer(&data), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)))
+ dumpfields(gcdatamask)
+
+ // bss segment
+ dumpbvtypes(&gcbssmask, unsafe.Pointer(&bss))
+ dumpint(tagBSS)
+ dumpint(uint64(uintptr(unsafe.Pointer(&bss))))
+ dumpmemrange(unsafe.Pointer(&bss), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)))
+ dumpfields(gcbssmask)
+
+ // MSpan.types
+ allspans := h_allspans
+ for spanidx := uint32(0); spanidx < mheap_.nspan; spanidx++ {
+ s := allspans[spanidx]
+ if s.state == _MSpanInUse {
+ // Finalizers
+ for sp := s.specials; sp != nil; sp = sp.next {
+ if sp.kind != _KindSpecialFinalizer {
+ continue
+ }
+ spf := (*specialfinalizer)(unsafe.Pointer(sp))
+ p := unsafe.Pointer((uintptr(s.start) << _PageShift) + uintptr(spf.special.offset))
+ dumpfinalizer(p, spf.fn, spf.fint, spf.ot)
+ }
+ }
+ }
+
+ // Finalizer queue
+ iterate_finq(finq_callback)
+}
+
+// Bit vector of free marks.
+// Needs to be as big as the largest number of objects per span.
+var freemark [_PageSize / 8]bool
+
+func dumpobjs() {
+ for i := uintptr(0); i < uintptr(mheap_.nspan); i++ {
+ s := h_allspans[i]
+ if s.state != _MSpanInUse {
+ continue
+ }
+ p := uintptr(s.start << _PageShift)
+ size := s.elemsize
+ n := (s.npages << _PageShift) / size
+ if n > uintptr(len(freemark)) {
+ gothrow("freemark array doesn't have enough entries")
+ }
+ for l := s.freelist; l != nil; l = l.next {
+ freemark[(uintptr(unsafe.Pointer(l))-p)/size] = true
+ }
+ for j := uintptr(0); j < n; j, p = j+1, p+size {
+ if freemark[j] {
+ freemark[j] = false
+ continue
+ }
+ dumpobj(unsafe.Pointer(p), size, makeheapobjbv(p, size))
+ }
+ }
+}
+
+func dumpparams() {
+ dumpint(tagParams)
+ x := uintptr(1)
+ if *(*byte)(unsafe.Pointer(&x)) == 1 {
+ dumpbool(false) // little-endian ptrs
+ } else {
+ dumpbool(true) // big-endian ptrs
+ }
+ dumpint(ptrSize)
+ dumpint(uint64(mheap_.arena_start))
+ dumpint(uint64(mheap_.arena_used))
+ dumpint(thechar)
+ dumpstr(goexperiment)
+ dumpint(uint64(ncpu))
+}
+
+func itab_callback(tab *itab) {
+ t := tab._type
+ // Dump a map from itab* to the type of its data field.
+ // We want this map so we can deduce types of interface referents.
+ if t.kind&kindDirectIface == 0 {
+ // indirect - data slot is a pointer to t.
+ dumptype(t.ptrto)
+ dumpint(tagItab)
+ dumpint(uint64(uintptr(unsafe.Pointer(tab))))
+ dumpint(uint64(uintptr(unsafe.Pointer(t.ptrto))))
+ } else if t.kind&kindNoPointers == 0 {
+ // t is pointer-like - data slot is a t.
+ dumptype(t)
+ dumpint(tagItab)
+ dumpint(uint64(uintptr(unsafe.Pointer(tab))))
+ dumpint(uint64(uintptr(unsafe.Pointer(t))))
+ } else {
+ // Data slot is a scalar. Dump type just for fun.
+ // With pointer-only interfaces, this shouldn't happen.
+ dumptype(t)
+ dumpint(tagItab)
+ dumpint(uint64(uintptr(unsafe.Pointer(tab))))
+ dumpint(uint64(uintptr(unsafe.Pointer(t))))
+ }
+}
+
+func dumpitabs() {
+ iterate_itabs(itab_callback)
+}
+
+func dumpms() {
+ for mp := allm; mp != nil; mp = mp.alllink {
+ dumpint(tagOSThread)
+ dumpint(uint64(uintptr(unsafe.Pointer(mp))))
+ dumpint(uint64(mp.id))
+ dumpint(mp.procid)
+ }
+}
+
+func dumpmemstats() {
+ dumpint(tagMemStats)
+ dumpint(memstats.alloc)
+ dumpint(memstats.total_alloc)
+ dumpint(memstats.sys)
+ dumpint(memstats.nlookup)
+ dumpint(memstats.nmalloc)
+ dumpint(memstats.nfree)
+ dumpint(memstats.heap_alloc)
+ dumpint(memstats.heap_sys)
+ dumpint(memstats.heap_idle)
+ dumpint(memstats.heap_inuse)
+ dumpint(memstats.heap_released)
+ dumpint(memstats.heap_objects)
+ dumpint(memstats.stacks_inuse)
+ dumpint(memstats.stacks_sys)
+ dumpint(memstats.mspan_inuse)
+ dumpint(memstats.mspan_sys)
+ dumpint(memstats.mcache_inuse)
+ dumpint(memstats.mcache_sys)
+ dumpint(memstats.buckhash_sys)
+ dumpint(memstats.gc_sys)
+ dumpint(memstats.other_sys)
+ dumpint(memstats.next_gc)
+ dumpint(memstats.last_gc)
+ dumpint(memstats.pause_total_ns)
+ for i := 0; i < 256; i++ {
+ dumpint(memstats.pause_ns[i])
+ }
+ dumpint(uint64(memstats.numgc))
+}
+
+func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs, frees uintptr) {
+ stk := (*[100000]uintptr)(unsafe.Pointer(pstk))
+ dumpint(tagMemProf)
+ dumpint(uint64(uintptr(unsafe.Pointer(b))))
+ dumpint(uint64(size))
+ dumpint(uint64(nstk))
+ for i := uintptr(0); i < nstk; i++ {
+ pc := stk[i]
+ f := findfunc(pc)
+ if f == nil {
+ var buf [64]byte
+ n := len(buf)
+ n--
+ buf[n] = ')'
+ if pc == 0 {
+ n--
+ buf[n] = '0'
+ } else {
+ for pc > 0 {
+ n--
+ buf[n] = "0123456789abcdef"[pc&15]
+ pc >>= 4
+ }
+ }
+ n--
+ buf[n] = 'x'
+ n--
+ buf[n] = '0'
+ n--
+ buf[n] = '('
+ dumpslice(buf[n:])
+ dumpstr("?")
+ dumpint(0)
+ } else {
+ dumpstr(gofuncname(f))
+ if i > 0 && pc > f.entry {
+ pc--
+ }
+ file, line := funcline(f, pc)
+ dumpstr(file)
+ dumpint(uint64(line))
+ }
+ }
+ dumpint(uint64(allocs))
+ dumpint(uint64(frees))
+}
+
+func dumpmemprof() {
+ iterate_memprof(dumpmemprof_callback)
+ allspans := h_allspans
+ for spanidx := uint32(0); spanidx < mheap_.nspan; spanidx++ {
+ s := allspans[spanidx]
+ if s.state != _MSpanInUse {
+ continue
+ }
+ for sp := s.specials; sp != nil; sp = sp.next {
+ if sp.kind != _KindSpecialProfile {
+ continue
+ }
+ spp := (*specialprofile)(unsafe.Pointer(sp))
+ p := uintptr(s.start<<_PageShift) + uintptr(spp.special.offset)
+ dumpint(tagAllocSample)
+ dumpint(uint64(p))
+ dumpint(uint64(uintptr(unsafe.Pointer(spp.b))))
+ }
+ }
+}
+
+var dumphdr = []byte("go1.4 heap dump\n")
+
+func mdump() {
+ // make sure we're done sweeping
+ for i := uintptr(0); i < uintptr(mheap_.nspan); i++ {
+ s := h_allspans[i]
+ if s.state == _MSpanInUse {
+ mSpan_EnsureSwept(s)
+ }
+ }
+ memclr(unsafe.Pointer(&typecache), unsafe.Sizeof(typecache))
+ dwrite(unsafe.Pointer(&dumphdr[0]), uintptr(len(dumphdr)))
+ dumpparams()
+ dumpitabs()
+ dumpobjs()
+ dumpgs()
+ dumpms()
+ dumproots()
+ dumpmemstats()
+ dumpmemprof()
+ dumpint(tagEOF)
+ flush()
+}
+
+func writeheapdump_m(fd uintptr) {
+ _g_ := getg()
+ casgstatus(_g_.m.curg, _Grunning, _Gwaiting)
+ _g_.waitreason = "dumping heap"
+
+ // Update stats so we can dump them.
+ // As a side effect, flushes all the MCaches so the MSpan.freelist
+ // lists contain all the free objects.
+ updatememstats(nil)
+
+ // Set dump file.
+ dumpfd = fd
+
+ // Call dump routine.
+ mdump()
+
+ // Reset dump file.
+ dumpfd = 0
+ if tmpbuf != nil {
+ sysFree(unsafe.Pointer(&tmpbuf[0]), uintptr(len(tmpbuf)), &memstats.other_sys)
+ tmpbuf = nil
+ }
+
+ casgstatus(_g_.m.curg, _Gwaiting, _Grunning)
+}
+
+// dumpint() the kind & offset of each field in an object.
+func dumpfields(bv bitvector) {
+ dumpbv(&bv, 0)
+ dumpint(fieldKindEol)
+}
+
+// The heap dump reader needs to be able to disambiguate
+// Eface entries. So it needs to know every type that might
+// appear in such an entry. The following routine accomplishes that.
+// TODO(rsc, khr): Delete - no longer possible.
+
+// Dump all the types that appear in the type field of
+// any Eface described by this bit vector.
+func dumpbvtypes(bv *bitvector, base unsafe.Pointer) {
+}
+
+func makeheapobjbv(p uintptr, size uintptr) bitvector {
+ // Extend the temp buffer if necessary.
+ nptr := size / ptrSize
+ if uintptr(len(tmpbuf)) < nptr*_BitsPerPointer/8+1 {
+ if tmpbuf != nil {
+ sysFree(unsafe.Pointer(&tmpbuf[0]), uintptr(len(tmpbuf)), &memstats.other_sys)
+ }
+ n := nptr*_BitsPerPointer/8 + 1
+ p := sysAlloc(n, &memstats.other_sys)
+ if p == nil {
+ gothrow("heapdump: out of memory")
+ }
+ tmpbuf = (*[1 << 30]byte)(p)[:n]
+ }
+ // Copy and compact the bitmap.
+ var i uintptr
+ for i = 0; i < nptr; i++ {
+ off := (p + i*ptrSize - mheap_.arena_start) / ptrSize
+ bitp := (*uint8)(unsafe.Pointer(mheap_.arena_start - off/wordsPerBitmapByte - 1))
+ shift := uint8((off % wordsPerBitmapByte) * gcBits)
+ bits := (*bitp >> (shift + 2)) & _BitsMask
+ if bits == _BitsDead {
+ break // end of heap object
+ }
+ tmpbuf[i*_BitsPerPointer/8] &^= (_BitsMask << ((i * _BitsPerPointer) % 8))
+ tmpbuf[i*_BitsPerPointer/8] |= bits << ((i * _BitsPerPointer) % 8)
+ }
+ return bitvector{int32(i * _BitsPerPointer), &tmpbuf[0]}
+}
diff --git a/src/runtime/lfstack.c b/src/runtime/lfstack.c
deleted file mode 100644
index 57e0af282..000000000
--- a/src/runtime/lfstack.c
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2012 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.
-
-// Lock-free stack.
-// The following code runs only on g0 stack.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-
-#ifdef _64BIT
-// Amd64 uses 48-bit virtual addresses, 47-th bit is used as kernel/user flag.
-// So we use 17msb of pointers as ABA counter.
-# define PTR_BITS 47
-#else
-# define PTR_BITS 32
-#endif
-#define PTR_MASK ((1ull<<PTR_BITS)-1)
-#define CNT_MASK (0ull-1)
-
-#ifdef _64BIT
-#ifdef GOOS_solaris
-// SPARC64 and Solaris on AMD64 uses all 64 bits of virtual addresses.
-// Use low-order three bits as ABA counter.
-// http://docs.oracle.com/cd/E19120-01/open.solaris/816-5138/6mba6ua5p/index.html
-#undef PTR_BITS
-#undef CNT_MASK
-#undef PTR_MASK
-#define PTR_BITS 0
-#define CNT_MASK 7
-#define PTR_MASK ((0ull-1)<<3)
-#endif
-#endif
-
-void
-runtime·lfstackpush(uint64 *head, LFNode *node)
-{
- uint64 old, new;
-
- if((uintptr)node != ((uintptr)node&PTR_MASK)) {
- runtime·printf("p=%p\n", node);
- runtime·throw("runtime·lfstackpush: invalid pointer");
- }
-
- node->pushcnt++;
- new = (uint64)(uintptr)node|(((uint64)node->pushcnt&CNT_MASK)<<PTR_BITS);
- for(;;) {
- old = runtime·atomicload64(head);
- node->next = (LFNode*)(uintptr)(old&PTR_MASK);
- if(runtime·cas64(head, old, new))
- break;
- }
-}
-
-LFNode*
-runtime·lfstackpop(uint64 *head)
-{
- LFNode *node, *node2;
- uint64 old, new;
-
- for(;;) {
- old = runtime·atomicload64(head);
- if(old == 0)
- return nil;
- node = (LFNode*)(uintptr)(old&PTR_MASK);
- node2 = runtime·atomicloadp(&node->next);
- new = 0;
- if(node2 != nil)
- new = (uint64)(uintptr)node2|(((uint64)node2->pushcnt&CNT_MASK)<<PTR_BITS);
- if(runtime·cas64(head, old, new))
- return node;
- }
-}
-
-void
-runtime·lfstackpush_m(void)
-{
- runtime·lfstackpush(g->m->ptrarg[0], g->m->ptrarg[1]);
- g->m->ptrarg[0] = nil;
- g->m->ptrarg[1] = nil;
-}
-
-void
-runtime·lfstackpop_m(void)
-{
- g->m->ptrarg[0] = runtime·lfstackpop(g->m->ptrarg[0]);
-}
diff --git a/src/runtime/lfstack.go b/src/runtime/lfstack.go
new file mode 100644
index 000000000..8a36a67b3
--- /dev/null
+++ b/src/runtime/lfstack.go
@@ -0,0 +1,44 @@
+// Copyright 2012 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.
+
+// Lock-free stack.
+// The following code runs only on g0 stack.
+
+package runtime
+
+import "unsafe"
+
+func lfstackpush(head *uint64, node *lfnode) {
+ node.pushcnt++
+ new := lfstackPack(node, node.pushcnt)
+ if node1, _ := lfstackUnpack(new); node1 != node {
+ println("runtime: lfstackpush invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n")
+ gothrow("lfstackpush")
+ }
+ for {
+ old := atomicload64(head)
+ node.next, _ = lfstackUnpack(old)
+ if cas64(head, old, new) {
+ break
+ }
+ }
+}
+
+func lfstackpop(head *uint64) unsafe.Pointer {
+ for {
+ old := atomicload64(head)
+ if old == 0 {
+ return nil
+ }
+ node, _ := lfstackUnpack(old)
+ node2 := (*lfnode)(atomicloadp(unsafe.Pointer(&node.next)))
+ new := uint64(0)
+ if node2 != nil {
+ new = lfstackPack(node2, node2.pushcnt)
+ }
+ if cas64(head, old, new) {
+ return unsafe.Pointer(node)
+ }
+ }
+}
diff --git a/src/runtime/lfstack_32bit.go b/src/runtime/lfstack_32bit.go
new file mode 100644
index 000000000..4b8bcbac6
--- /dev/null
+++ b/src/runtime/lfstack_32bit.go
@@ -0,0 +1,21 @@
+// 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.
+
+// +build 386 arm nacl
+
+package runtime
+
+import "unsafe"
+
+// On 32-bit systems, the stored uint64 has a 32-bit pointer and 32-bit count.
+
+func lfstackPack(node *lfnode, cnt uintptr) uint64 {
+ return uint64(uintptr(unsafe.Pointer(node)))<<32 | uint64(cnt)
+}
+
+func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) {
+ node = (*lfnode)(unsafe.Pointer(uintptr(val >> 32)))
+ cnt = uintptr(val)
+ return
+}
diff --git a/src/runtime/lfstack_amd64.go b/src/runtime/lfstack_amd64.go
new file mode 100644
index 000000000..84e28519f
--- /dev/null
+++ b/src/runtime/lfstack_amd64.go
@@ -0,0 +1,24 @@
+// 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 runtime
+
+import "unsafe"
+
+// On AMD64, virtual addresses are 48-bit numbers sign extended to 64.
+// We shift the address left 16 to eliminate the sign extended part and make
+// room in the bottom for the count.
+// In addition to the 16 bits taken from the top, we can take 3 from the
+// bottom, because node must be pointer-aligned, giving a total of 19 bits
+// of count.
+
+func lfstackPack(node *lfnode, cnt uintptr) uint64 {
+ return uint64(uintptr(unsafe.Pointer(node)))<<16 | uint64(cnt&(1<<19-1))
+}
+
+func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) {
+ node = (*lfnode)(unsafe.Pointer(uintptr(int64(val) >> 19 << 3)))
+ cnt = uintptr(val & (1<<19 - 1))
+ return
+}
diff --git a/src/runtime/lfstack_linux_power64x.go b/src/runtime/lfstack_linux_power64x.go
new file mode 100644
index 000000000..89e389fc7
--- /dev/null
+++ b/src/runtime/lfstack_linux_power64x.go
@@ -0,0 +1,32 @@
+// 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.
+
+// +build power64 power64le
+// +build linux
+
+package runtime
+
+import "unsafe"
+
+// On Power64, Linux limits the user address space to 46 bits (see
+// TASK_SIZE_USER64 in the Linux kernel). This has grown over time,
+// so here we allow 48 bit addresses.
+//
+// In addition to the 16 bits taken from the top, we can take 3 from the
+// bottom, because node must be pointer-aligned, giving a total of 19 bits
+// of count.
+const (
+ addrBits = 48
+ cntBits = 64 - addrBits + 3
+)
+
+func lfstackPack(node *lfnode, cnt uintptr) uint64 {
+ return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1))
+}
+
+func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) {
+ node = (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3)))
+ cnt = uintptr(val & (1<<cntBits - 1))
+ return
+}
diff --git a/src/runtime/lock_futex.go b/src/runtime/lock_futex.go
index 725962341..11c3a3f06 100644
--- a/src/runtime/lock_futex.go
+++ b/src/runtime/lock_futex.go
@@ -34,9 +34,6 @@ const (
// Note that there can be spinning threads during all states - they do not
// affect mutex's state.
-func futexsleep(addr *uint32, val uint32, ns int64)
-func futexwakeup(addr *uint32, cnt uint32)
-
// We use the uintptr mutex.key and note.key as a uint32.
func key32(p *uintptr) *uint32 {
return (*uint32)(unsafe.Pointer(p))
@@ -198,8 +195,8 @@ func notetsleepg(n *note, ns int64) bool {
gothrow("notetsleepg on g0")
}
- entersyscallblock()
+ entersyscallblock(0)
ok := notetsleep_internal(n, ns)
- exitsyscall()
+ exitsyscall(0)
return ok
}
diff --git a/src/runtime/lock_sema.go b/src/runtime/lock_sema.go
index d136b8280..a2a87bac4 100644
--- a/src/runtime/lock_sema.go
+++ b/src/runtime/lock_sema.go
@@ -31,10 +31,6 @@ const (
passive_spin = 1
)
-func semacreate() uintptr
-func semasleep(int64) int32
-func semawakeup(mp *m)
-
func lock(l *mutex) {
gp := getg()
if gp.m.locks < 0 {
@@ -263,8 +259,8 @@ func notetsleepg(n *note, ns int64) bool {
if gp.m.waitsema == 0 {
gp.m.waitsema = semacreate()
}
- entersyscallblock()
+ entersyscallblock(0)
ok := notetsleep_internal(n, ns, nil, 0)
- exitsyscall()
+ exitsyscall(0)
return ok
}
diff --git a/src/runtime/malloc.c b/src/runtime/malloc.c
deleted file mode 100644
index b79c30b72..000000000
--- a/src/runtime/malloc.c
+++ /dev/null
@@ -1,396 +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.
-
-// See malloc.h for overview.
-//
-// TODO(rsc): double-check stats.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "type.h"
-#include "typekind.h"
-#include "race.h"
-#include "stack.h"
-#include "textflag.h"
-
-// Mark mheap as 'no pointers', it does not contain interesting pointers but occupies ~45K.
-#pragma dataflag NOPTR
-MHeap runtime·mheap;
-#pragma dataflag NOPTR
-MStats runtime·memstats;
-
-int32
-runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
-{
- uintptr n, i;
- byte *p;
- MSpan *s;
-
- g->m->mcache->local_nlookup++;
- if (sizeof(void*) == 4 && g->m->mcache->local_nlookup >= (1<<30)) {
- // purge cache stats to prevent overflow
- runtime·lock(&runtime·mheap.lock);
- runtime·purgecachedstats(g->m->mcache);
- runtime·unlock(&runtime·mheap.lock);
- }
-
- s = runtime·MHeap_LookupMaybe(&runtime·mheap, v);
- if(sp)
- *sp = s;
- if(s == nil) {
- if(base)
- *base = nil;
- if(size)
- *size = 0;
- return 0;
- }
-
- p = (byte*)((uintptr)s->start<<PageShift);
- if(s->sizeclass == 0) {
- // Large object.
- if(base)
- *base = p;
- if(size)
- *size = s->npages<<PageShift;
- return 1;
- }
-
- n = s->elemsize;
- if(base) {
- i = ((byte*)v - p)/n;
- *base = p + i*n;
- }
- if(size)
- *size = n;
-
- return 1;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·purgecachedstats(MCache *c)
-{
- MHeap *h;
- int32 i;
-
- // Protected by either heap or GC lock.
- h = &runtime·mheap;
- mstats.heap_alloc += c->local_cachealloc;
- c->local_cachealloc = 0;
- mstats.tinyallocs += c->local_tinyallocs;
- c->local_tinyallocs = 0;
- mstats.nlookup += c->local_nlookup;
- c->local_nlookup = 0;
- h->largefree += c->local_largefree;
- c->local_largefree = 0;
- h->nlargefree += c->local_nlargefree;
- c->local_nlargefree = 0;
- for(i=0; i<nelem(c->local_nsmallfree); i++) {
- h->nsmallfree[i] += c->local_nsmallfree[i];
- c->local_nsmallfree[i] = 0;
- }
-}
-
-// Size of the trailing by_size array differs between Go and C,
-// and all data after by_size is local to C, not exported to Go.
-// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
-// sizeof_C_MStats is what C thinks about size of Go struct.
-uintptr runtime·sizeof_C_MStats = offsetof(MStats, by_size[61]);
-
-#define MaxArena32 (2U<<30)
-
-// For use by Go. If it were a C enum it would be made available automatically,
-// but the value of MaxMem is too large for enum.
-uintptr runtime·maxmem = MaxMem;
-
-void
-runtime·mallocinit(void)
-{
- byte *p, *p1;
- uintptr arena_size, bitmap_size, spans_size, p_size;
- extern byte runtime·end[];
- uintptr limit;
- uint64 i;
- bool reserved;
-
- p = nil;
- p_size = 0;
- arena_size = 0;
- bitmap_size = 0;
- spans_size = 0;
- reserved = false;
-
- // for 64-bit build
- USED(p);
- USED(p_size);
- USED(arena_size);
- USED(bitmap_size);
- USED(spans_size);
-
- runtime·InitSizes();
-
- if(runtime·class_to_size[TinySizeClass] != TinySize)
- runtime·throw("bad TinySizeClass");
-
- // limit = runtime·memlimit();
- // See https://code.google.com/p/go/issues/detail?id=5049
- // TODO(rsc): Fix after 1.1.
- limit = 0;
-
- // Set up the allocation arena, a contiguous area of memory where
- // allocated data will be found. The arena begins with a bitmap large
- // enough to hold 4 bits per allocated word.
- if(sizeof(void*) == 8 && (limit == 0 || limit > (1<<30))) {
- // On a 64-bit machine, allocate from a single contiguous reservation.
- // 128 GB (MaxMem) should be big enough for now.
- //
- // The code will work with the reservation at any address, but ask
- // SysReserve to use 0x0000XXc000000000 if possible (XX=00...7f).
- // Allocating a 128 GB region takes away 37 bits, and the amd64
- // doesn't let us choose the top 17 bits, so that leaves the 11 bits
- // in the middle of 0x00c0 for us to choose. Choosing 0x00c0 means
- // that the valid memory addresses will begin 0x00c0, 0x00c1, ..., 0x00df.
- // In little-endian, that's c0 00, c1 00, ..., df 00. None of those are valid
- // UTF-8 sequences, and they are otherwise as far away from
- // ff (likely a common byte) as possible. If that fails, we try other 0xXXc0
- // addresses. An earlier attempt to use 0x11f8 caused out of memory errors
- // on OS X during thread allocations. 0x00c0 causes conflicts with
- // AddressSanitizer which reserves all memory up to 0x0100.
- // These choices are both for debuggability and to reduce the
- // odds of the conservative garbage collector not collecting memory
- // because some non-pointer block of memory had a bit pattern
- // that matched a memory address.
- //
- // Actually we reserve 136 GB (because the bitmap ends up being 8 GB)
- // but it hardly matters: e0 00 is not valid UTF-8 either.
- //
- // If this fails we fall back to the 32 bit memory mechanism
- arena_size = MaxMem;
- bitmap_size = arena_size / (sizeof(void*)*8/4);
- spans_size = arena_size / PageSize * sizeof(runtime·mheap.spans[0]);
- spans_size = ROUND(spans_size, PageSize);
- for(i = 0; i <= 0x7f; i++) {
- p = (void*)(i<<40 | 0x00c0ULL<<32);
- p_size = bitmap_size + spans_size + arena_size + PageSize;
- p = runtime·SysReserve(p, p_size, &reserved);
- if(p != nil)
- break;
- }
- }
- if (p == nil) {
- // On a 32-bit machine, we can't typically get away
- // with a giant virtual address space reservation.
- // Instead we map the memory information bitmap
- // immediately after the data segment, large enough
- // to handle another 2GB of mappings (256 MB),
- // along with a reservation for another 512 MB of memory.
- // When that gets used up, we'll start asking the kernel
- // for any memory anywhere and hope it's in the 2GB
- // following the bitmap (presumably the executable begins
- // near the bottom of memory, so we'll have to use up
- // most of memory before the kernel resorts to giving out
- // memory before the beginning of the text segment).
- //
- // Alternatively we could reserve 512 MB bitmap, enough
- // for 4GB of mappings, and then accept any memory the
- // kernel threw at us, but normally that's a waste of 512 MB
- // of address space, which is probably too much in a 32-bit world.
- bitmap_size = MaxArena32 / (sizeof(void*)*8/4);
- arena_size = 512<<20;
- spans_size = MaxArena32 / PageSize * sizeof(runtime·mheap.spans[0]);
- if(limit > 0 && arena_size+bitmap_size+spans_size > limit) {
- bitmap_size = (limit / 9) & ~((1<<PageShift) - 1);
- arena_size = bitmap_size * 8;
- spans_size = arena_size / PageSize * sizeof(runtime·mheap.spans[0]);
- }
- spans_size = ROUND(spans_size, PageSize);
-
- // SysReserve treats the address we ask for, end, as a hint,
- // not as an absolute requirement. If we ask for the end
- // of the data segment but the operating system requires
- // a little more space before we can start allocating, it will
- // give out a slightly higher pointer. Except QEMU, which
- // is buggy, as usual: it won't adjust the pointer upward.
- // So adjust it upward a little bit ourselves: 1/4 MB to get
- // away from the running binary image and then round up
- // to a MB boundary.
- p = (byte*)ROUND((uintptr)runtime·end + (1<<18), 1<<20);
- p_size = bitmap_size + spans_size + arena_size + PageSize;
- p = runtime·SysReserve(p, p_size, &reserved);
- if(p == nil)
- runtime·throw("runtime: cannot reserve arena virtual address space");
- }
-
- // PageSize can be larger than OS definition of page size,
- // so SysReserve can give us a PageSize-unaligned pointer.
- // To overcome this we ask for PageSize more and round up the pointer.
- p1 = (byte*)ROUND((uintptr)p, PageSize);
-
- runtime·mheap.spans = (MSpan**)p1;
- runtime·mheap.bitmap = p1 + spans_size;
- runtime·mheap.arena_start = p1 + spans_size + bitmap_size;
- runtime·mheap.arena_used = runtime·mheap.arena_start;
- runtime·mheap.arena_end = p + p_size;
- runtime·mheap.arena_reserved = reserved;
-
- if(((uintptr)runtime·mheap.arena_start & (PageSize-1)) != 0)
- runtime·throw("misrounded allocation in mallocinit");
-
- // Initialize the rest of the allocator.
- runtime·MHeap_Init(&runtime·mheap);
- g->m->mcache = runtime·allocmcache();
-}
-
-void*
-runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
-{
- byte *p, *p_end;
- uintptr p_size;
- bool reserved;
-
- if(n > h->arena_end - h->arena_used) {
- // We are in 32-bit mode, maybe we didn't use all possible address space yet.
- // Reserve some more space.
- byte *new_end;
-
- p_size = ROUND(n + PageSize, 256<<20);
- new_end = h->arena_end + p_size;
- if(new_end <= h->arena_start + MaxArena32) {
- // TODO: It would be bad if part of the arena
- // is reserved and part is not.
- p = runtime·SysReserve(h->arena_end, p_size, &reserved);
- if(p == h->arena_end) {
- h->arena_end = new_end;
- h->arena_reserved = reserved;
- }
- else if(p+p_size <= h->arena_start + MaxArena32) {
- // Keep everything page-aligned.
- // Our pages are bigger than hardware pages.
- h->arena_end = p+p_size;
- h->arena_used = p + (-(uintptr)p&(PageSize-1));
- h->arena_reserved = reserved;
- } else {
- uint64 stat;
- stat = 0;
- runtime·SysFree(p, p_size, &stat);
- }
- }
- }
- if(n <= h->arena_end - h->arena_used) {
- // Keep taking from our reservation.
- p = h->arena_used;
- runtime·SysMap(p, n, h->arena_reserved, &mstats.heap_sys);
- h->arena_used += n;
- runtime·MHeap_MapBits(h);
- runtime·MHeap_MapSpans(h);
- if(raceenabled)
- runtime·racemapshadow(p, n);
-
- if(((uintptr)p & (PageSize-1)) != 0)
- runtime·throw("misrounded allocation in MHeap_SysAlloc");
- return p;
- }
-
- // If using 64-bit, our reservation is all we have.
- if(h->arena_end - h->arena_start >= MaxArena32)
- return nil;
-
- // On 32-bit, once the reservation is gone we can
- // try to get memory at a location chosen by the OS
- // and hope that it is in the range we allocated bitmap for.
- p_size = ROUND(n, PageSize) + PageSize;
- p = runtime·sysAlloc(p_size, &mstats.heap_sys);
- if(p == nil)
- return nil;
-
- if(p < h->arena_start || p+p_size - h->arena_start >= MaxArena32) {
- runtime·printf("runtime: memory allocated by OS (%p) not in usable range [%p,%p)\n",
- p, h->arena_start, h->arena_start+MaxArena32);
- runtime·SysFree(p, p_size, &mstats.heap_sys);
- return nil;
- }
-
- p_end = p + p_size;
- p += -(uintptr)p & (PageSize-1);
- if(p+n > h->arena_used) {
- h->arena_used = p+n;
- if(p_end > h->arena_end)
- h->arena_end = p_end;
- runtime·MHeap_MapBits(h);
- runtime·MHeap_MapSpans(h);
- if(raceenabled)
- runtime·racemapshadow(p, n);
- }
-
- if(((uintptr)p & (PageSize-1)) != 0)
- runtime·throw("misrounded allocation in MHeap_SysAlloc");
- return p;
-}
-
-void
-runtime·setFinalizer_m(void)
-{
- FuncVal *fn;
- void *arg;
- uintptr nret;
- Type *fint;
- PtrType *ot;
-
- fn = g->m->ptrarg[0];
- arg = g->m->ptrarg[1];
- nret = g->m->scalararg[0];
- fint = g->m->ptrarg[2];
- ot = g->m->ptrarg[3];
- g->m->ptrarg[0] = nil;
- g->m->ptrarg[1] = nil;
- g->m->ptrarg[2] = nil;
- g->m->ptrarg[3] = nil;
-
- g->m->scalararg[0] = runtime·addfinalizer(arg, fn, nret, fint, ot);
-}
-
-void
-runtime·removeFinalizer_m(void)
-{
- void *p;
-
- p = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- runtime·removefinalizer(p);
-}
-
-// mcallable cache refill
-void
-runtime·mcacheRefill_m(void)
-{
- runtime·MCache_Refill(g->m->mcache, (int32)g->m->scalararg[0]);
-}
-
-void
-runtime·largeAlloc_m(void)
-{
- uintptr npages, size;
- MSpan *s;
- void *v;
- int32 flag;
-
- //runtime·printf("largeAlloc size=%D\n", g->m->scalararg[0]);
- // Allocate directly from heap.
- size = g->m->scalararg[0];
- flag = (int32)g->m->scalararg[1];
- if(size + PageSize < size)
- runtime·throw("out of memory");
- npages = size >> PageShift;
- if((size & PageMask) != 0)
- npages++;
- s = runtime·MHeap_Alloc(&runtime·mheap, npages, 0, 1, !(flag & FlagNoZero));
- if(s == nil)
- runtime·throw("out of memory");
- s->limit = (byte*)(s->start<<PageShift) + size;
- v = (void*)(s->start << PageShift);
- // setup for mark sweep
- runtime·markspan(v, 0, 0, true);
- g->m->ptrarg[0] = s;
-}
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index 117044944..d73d1ba6a 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -4,9 +4,7 @@
package runtime
-import (
- "unsafe"
-)
+import "unsafe"
const (
debugMalloc = false
@@ -28,10 +26,11 @@ const (
maxGCMask = _MaxGCMask
bitsDead = _BitsDead
bitsPointer = _BitsPointer
+ bitsScalar = _BitsScalar
mSpanInUse = _MSpanInUse
- concurrentSweep = _ConcurrentSweep != 0
+ concurrentSweep = _ConcurrentSweep
)
// Page number (address>>pageShift)
@@ -56,7 +55,7 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
// This function must be atomic wrt GC, but for performance reasons
// we don't acquirem/releasem on fast path. The code below does not have
// split stack checks, so it can't be preempted by GC.
- // Functions like roundup/add are inlined. And onM/racemalloc are nosplit.
+ // Functions like roundup/add are inlined. And systemstack/racemalloc are nosplit.
// If debugMalloc = true, these assumptions are checked below.
if debugMalloc {
mp := acquirem()
@@ -142,10 +141,9 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
s = c.alloc[tinySizeClass]
v := s.freelist
if v == nil {
- mp := acquirem()
- mp.scalararg[0] = tinySizeClass
- onM(mcacheRefill_m)
- releasem(mp)
+ systemstack(func() {
+ mCache_Refill(c, tinySizeClass)
+ })
s = c.alloc[tinySizeClass]
v = s.freelist
}
@@ -173,10 +171,9 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
s = c.alloc[sizeclass]
v := s.freelist
if v == nil {
- mp := acquirem()
- mp.scalararg[0] = uintptr(sizeclass)
- onM(mcacheRefill_m)
- releasem(mp)
+ systemstack(func() {
+ mCache_Refill(c, int32(sizeclass))
+ })
s = c.alloc[sizeclass]
v = s.freelist
}
@@ -193,13 +190,10 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
}
c.local_cachealloc += intptr(size)
} else {
- mp := acquirem()
- mp.scalararg[0] = uintptr(size)
- mp.scalararg[1] = uintptr(flags)
- onM(largeAlloc_m)
- s = (*mspan)(mp.ptrarg[0])
- mp.ptrarg[0] = nil
- releasem(mp)
+ var s *mspan
+ systemstack(func() {
+ s = largeAlloc(size, uint32(flags))
+ })
x = unsafe.Pointer(uintptr(s.start << pageShift))
size = uintptr(s.elemsize)
}
@@ -251,22 +245,19 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
// into the GC bitmap. It's 7 times slower than copying
// from the pre-unrolled mask, but saves 1/16 of type size
// memory for the mask.
- mp := acquirem()
- mp.ptrarg[0] = x
- mp.ptrarg[1] = unsafe.Pointer(typ)
- mp.scalararg[0] = uintptr(size)
- mp.scalararg[1] = uintptr(size0)
- onM(unrollgcproginplace_m)
- releasem(mp)
+ systemstack(func() {
+ unrollgcproginplace_m(x, typ, size, size0)
+ })
goto marked
}
ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
- // Check whether the program is already unrolled.
- if uintptr(atomicloadp(unsafe.Pointer(ptrmask)))&0xff == 0 {
- mp := acquirem()
- mp.ptrarg[0] = unsafe.Pointer(typ)
- onM(unrollgcprog_m)
- releasem(mp)
+ // Check whether the program is already unrolled
+ // by checking if the unroll flag byte is set
+ maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask)))
+ if *(*uint8)(unsafe.Pointer(&maskword)) == 0 {
+ systemstack(func() {
+ unrollgcprog_m(typ)
+ })
}
ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
} else {
@@ -359,7 +350,7 @@ func newarray(typ *_type, n uintptr) unsafe.Pointer {
if typ.kind&kindNoPointers != 0 {
flags |= flagNoScan
}
- if int(n) < 0 || (typ.size > 0 && n > maxmem/uintptr(typ.size)) {
+ if int(n) < 0 || (typ.size > 0 && n > _MaxMem/uintptr(typ.size)) {
panic("runtime: allocation size out of range")
}
return mallocgc(uintptr(typ.size)*n, typ, flags)
@@ -438,7 +429,7 @@ func gogc(force int32) {
mp = acquirem()
mp.gcing = 1
releasem(mp)
- onM(stoptheworld)
+ systemstack(stoptheworld)
if mp != acquirem() {
gothrow("gogc: rescheduled")
}
@@ -459,20 +450,16 @@ func gogc(force int32) {
startTime = nanotime()
}
// switch to g0, call gc, then switch back
- mp.scalararg[0] = uintptr(uint32(startTime)) // low 32 bits
- mp.scalararg[1] = uintptr(startTime >> 32) // high 32 bits
- if force >= 2 {
- mp.scalararg[2] = 1 // eagersweep
- } else {
- mp.scalararg[2] = 0
- }
- onM(gc_m)
+ eagersweep := force >= 2
+ systemstack(func() {
+ gc_m(startTime, eagersweep)
+ })
}
// all done
mp.gcing = 0
semrelease(&worldsema)
- onM(starttheworld)
+ systemstack(starttheworld)
releasem(mp)
mp = nil
@@ -591,11 +578,10 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
f := (*eface)(unsafe.Pointer(&finalizer))
ftyp := f._type
if ftyp == nil {
- // switch to M stack and remove finalizer
- mp := acquirem()
- mp.ptrarg[0] = e.data
- onM(removeFinalizer_m)
- releasem(mp)
+ // switch to system stack and remove finalizer
+ systemstack(func() {
+ removefinalizer(e.data)
+ })
return
}
@@ -640,18 +626,11 @@ okarg:
// make sure we have a finalizer goroutine
createfing()
- // switch to M stack to add finalizer record
- mp := acquirem()
- mp.ptrarg[0] = f.data
- mp.ptrarg[1] = e.data
- mp.scalararg[0] = nret
- mp.ptrarg[2] = unsafe.Pointer(fint)
- mp.ptrarg[3] = unsafe.Pointer(ot)
- onM(setFinalizer_m)
- if mp.scalararg[0] != 1 {
- gothrow("runtime.SetFinalizer: finalizer already set")
- }
- releasem(mp)
+ systemstack(func() {
+ if !addfinalizer(e.data, (*funcval)(f.data), nret, fint, ot) {
+ gothrow("runtime.SetFinalizer: finalizer already set")
+ }
+ })
}
// round n up to a multiple of a. a must be a power of 2.
diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h
deleted file mode 100644
index adb8d3d67..000000000
--- a/src/runtime/malloc.h
+++ /dev/null
@@ -1,621 +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.
-
-// Memory allocator, based on tcmalloc.
-// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
-
-// The main allocator works in runs of pages.
-// Small allocation sizes (up to and including 32 kB) are
-// rounded to one of about 100 size classes, each of which
-// has its own free list of objects of exactly that size.
-// Any free page of memory can be split into a set of objects
-// of one size class, which are then managed using free list
-// allocators.
-//
-// The allocator's data structures are:
-//
-// FixAlloc: a free-list allocator for fixed-size objects,
-// used to manage storage used by the allocator.
-// MHeap: the malloc heap, managed at page (4096-byte) granularity.
-// MSpan: a run of pages managed by the MHeap.
-// MCentral: a shared free list for a given size class.
-// MCache: a per-thread (in Go, per-P) cache for small objects.
-// MStats: allocation statistics.
-//
-// Allocating a small object proceeds up a hierarchy of caches:
-//
-// 1. Round the size up to one of the small size classes
-// and look in the corresponding MCache free list.
-// If the list is not empty, allocate an object from it.
-// This can all be done without acquiring a lock.
-//
-// 2. If the MCache free list is empty, replenish it by
-// taking a bunch of objects from the MCentral free list.
-// Moving a bunch amortizes the cost of acquiring the MCentral lock.
-//
-// 3. If the MCentral free list is empty, replenish it by
-// allocating a run of pages from the MHeap and then
-// chopping that memory into a objects of the given size.
-// Allocating many objects amortizes the cost of locking
-// the heap.
-//
-// 4. If the MHeap is empty or has no page runs large enough,
-// allocate a new group of pages (at least 1MB) from the
-// operating system. Allocating a large run of pages
-// amortizes the cost of talking to the operating system.
-//
-// Freeing a small object proceeds up the same hierarchy:
-//
-// 1. Look up the size class for the object and add it to
-// the MCache free list.
-//
-// 2. If the MCache free list is too long or the MCache has
-// too much memory, return some to the MCentral free lists.
-//
-// 3. If all the objects in a given span have returned to
-// the MCentral list, return that span to the page heap.
-//
-// 4. If the heap has too much memory, return some to the
-// operating system.
-//
-// TODO(rsc): Step 4 is not implemented.
-//
-// Allocating and freeing a large object uses the page heap
-// directly, bypassing the MCache and MCentral free lists.
-//
-// The small objects on the MCache and MCentral free lists
-// may or may not be zeroed. They are zeroed if and only if
-// the second word of the object is zero. A span in the
-// page heap is zeroed unless s->needzero is set. When a span
-// is allocated to break into small objects, it is zeroed if needed
-// and s->needzero is set. There are two main benefits to delaying the
-// zeroing this way:
-//
-// 1. stack frames allocated from the small object lists
-// or the page heap can avoid zeroing altogether.
-// 2. the cost of zeroing when reusing a small object is
-// charged to the mutator, not the garbage collector.
-//
-// This C code was written with an eye toward translating to Go
-// in the future. Methods have the form Type_Method(Type *t, ...).
-
-typedef struct MCentral MCentral;
-typedef struct MHeap MHeap;
-typedef struct MSpan MSpan;
-typedef struct MStats MStats;
-typedef struct MLink MLink;
-typedef struct GCStats GCStats;
-
-enum
-{
- PageShift = 13,
- PageSize = 1<<PageShift,
- PageMask = PageSize - 1,
-};
-typedef uintptr pageID; // address >> PageShift
-
-enum
-{
- // Computed constant. The definition of MaxSmallSize and the
- // algorithm in msize.c produce some number of different allocation
- // size classes. NumSizeClasses is that number. It's needed here
- // because there are static arrays of this length; when msize runs its
- // size choosing algorithm it double-checks that NumSizeClasses agrees.
- NumSizeClasses = 67,
-
- // Tunable constants.
- MaxSmallSize = 32<<10,
-
- // Tiny allocator parameters, see "Tiny allocator" comment in malloc.goc.
- TinySize = 16,
- TinySizeClass = 2,
-
- FixAllocChunk = 16<<10, // Chunk size for FixAlloc
- MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap.
- HeapAllocChunk = 1<<20, // Chunk size for heap growth
-
- // Per-P, per order stack segment cache size.
- StackCacheSize = 32*1024,
- // Number of orders that get caching. Order 0 is FixedStack
- // and each successive order is twice as large.
- NumStackOrders = 3,
-
- // Number of bits in page to span calculations (4k pages).
- // On Windows 64-bit we limit the arena to 32GB or 35 bits (see below for reason).
- // On other 64-bit platforms, we limit the arena to 128GB, or 37 bits.
- // On 32-bit, we don't bother limiting anything, so we use the full 32-bit address.
-#ifdef _64BIT
-#ifdef GOOS_windows
- // Windows counts memory used by page table into committed memory
- // of the process, so we can't reserve too much memory.
- // See http://golang.org/issue/5402 and http://golang.org/issue/5236.
- MHeapMap_Bits = 35 - PageShift,
-#else
- MHeapMap_Bits = 37 - PageShift,
-#endif
-#else
- MHeapMap_Bits = 32 - PageShift,
-#endif
-
- // Max number of threads to run garbage collection.
- // 2, 3, and 4 are all plausible maximums depending
- // on the hardware details of the machine. The garbage
- // collector scales well to 32 cpus.
- MaxGcproc = 32,
-};
-
-// Maximum memory allocation size, a hint for callers.
-// This must be a #define instead of an enum because it
-// is so large.
-#ifdef _64BIT
-#define MaxMem (1ULL<<(MHeapMap_Bits+PageShift)) /* 128 GB or 32 GB */
-#else
-#define MaxMem ((uintptr)-1)
-#endif
-
-// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
-struct MLink
-{
- MLink *next;
-};
-
-// sysAlloc obtains a large chunk of zeroed memory from the
-// operating system, typically on the order of a hundred kilobytes
-// or a megabyte.
-// NOTE: sysAlloc returns OS-aligned memory, but the heap allocator
-// may use larger alignment, so the caller must be careful to realign the
-// memory obtained by sysAlloc.
-//
-// SysUnused notifies the operating system that the contents
-// of the memory region are no longer needed and can be reused
-// for other purposes.
-// SysUsed notifies the operating system that the contents
-// of the memory region are needed again.
-//
-// SysFree returns it unconditionally; this is only used if
-// an out-of-memory error has been detected midway through
-// an allocation. It is okay if SysFree is a no-op.
-//
-// SysReserve reserves address space without allocating memory.
-// If the pointer passed to it is non-nil, the caller wants the
-// reservation there, but SysReserve can still choose another
-// location if that one is unavailable. On some systems and in some
-// cases SysReserve will simply check that the address space is
-// available and not actually reserve it. If SysReserve returns
-// non-nil, it sets *reserved to true if the address space is
-// reserved, false if it has merely been checked.
-// NOTE: SysReserve returns OS-aligned memory, but the heap allocator
-// may use larger alignment, so the caller must be careful to realign the
-// memory obtained by sysAlloc.
-//
-// SysMap maps previously reserved address space for use.
-// The reserved argument is true if the address space was really
-// reserved, not merely checked.
-//
-// SysFault marks a (already sysAlloc'd) region to fault
-// if accessed. Used only for debugging the runtime.
-
-void* runtime·sysAlloc(uintptr nbytes, uint64 *stat);
-void runtime·SysFree(void *v, uintptr nbytes, uint64 *stat);
-void runtime·SysUnused(void *v, uintptr nbytes);
-void runtime·SysUsed(void *v, uintptr nbytes);
-void runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat);
-void* runtime·SysReserve(void *v, uintptr nbytes, bool *reserved);
-void runtime·SysFault(void *v, uintptr nbytes);
-
-// FixAlloc is a simple free-list allocator for fixed size objects.
-// Malloc uses a FixAlloc wrapped around sysAlloc to manages its
-// MCache and MSpan objects.
-//
-// Memory returned by FixAlloc_Alloc is not zeroed.
-// The caller is responsible for locking around FixAlloc calls.
-// Callers can keep state in the object but the first word is
-// smashed by freeing and reallocating.
-struct FixAlloc
-{
- uintptr size;
- void (*first)(void *arg, byte *p); // called first time p is returned
- void* arg;
- MLink* list;
- byte* chunk;
- uint32 nchunk;
- uintptr inuse; // in-use bytes now
- uint64* stat;
-};
-
-void runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void (*first)(void*, byte*), void *arg, uint64 *stat);
-void* runtime·FixAlloc_Alloc(FixAlloc *f);
-void runtime·FixAlloc_Free(FixAlloc *f, void *p);
-
-
-// Statistics.
-// Shared with Go: if you edit this structure, also edit type MemStats in mem.go.
-struct MStats
-{
- // General statistics.
- uint64 alloc; // bytes allocated and still in use
- uint64 total_alloc; // bytes allocated (even if freed)
- uint64 sys; // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
- uint64 nlookup; // number of pointer lookups
- uint64 nmalloc; // number of mallocs
- uint64 nfree; // number of frees
-
- // Statistics about malloc heap.
- // protected by mheap.lock
- uint64 heap_alloc; // bytes allocated and still in use
- uint64 heap_sys; // bytes obtained from system
- uint64 heap_idle; // bytes in idle spans
- uint64 heap_inuse; // bytes in non-idle spans
- uint64 heap_released; // bytes released to the OS
- uint64 heap_objects; // total number of allocated objects
-
- // Statistics about allocation of low-level fixed-size structures.
- // Protected by FixAlloc locks.
- uint64 stacks_inuse; // this number is included in heap_inuse above
- uint64 stacks_sys; // always 0 in mstats
- uint64 mspan_inuse; // MSpan structures
- uint64 mspan_sys;
- uint64 mcache_inuse; // MCache structures
- uint64 mcache_sys;
- uint64 buckhash_sys; // profiling bucket hash table
- uint64 gc_sys;
- uint64 other_sys;
-
- // Statistics about garbage collector.
- // Protected by mheap or stopping the world during GC.
- uint64 next_gc; // next GC (in heap_alloc time)
- uint64 last_gc; // last GC (in absolute time)
- uint64 pause_total_ns;
- uint64 pause_ns[256]; // circular buffer of recent GC pause lengths
- uint64 pause_end[256]; // circular buffer of recent GC end times (nanoseconds since 1970)
- uint32 numgc;
- bool enablegc;
- bool debuggc;
-
- // Statistics about allocation size classes.
-
- struct MStatsBySize {
- uint32 size;
- uint64 nmalloc;
- uint64 nfree;
- } by_size[NumSizeClasses];
-
- uint64 tinyallocs; // number of tiny allocations that didn't cause actual allocation; not exported to Go directly
-};
-
-
-#define mstats runtime·memstats
-extern MStats mstats;
-void runtime·updatememstats(GCStats *stats);
-void runtime·ReadMemStats(MStats *stats);
-
-// Size classes. Computed and initialized by InitSizes.
-//
-// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
-// 1 <= sizeclass < NumSizeClasses, for n.
-// Size class 0 is reserved to mean "not small".
-//
-// class_to_size[i] = largest size in class i
-// class_to_allocnpages[i] = number of pages to allocate when
-// making new objects in class i
-
-int32 runtime·SizeToClass(int32);
-uintptr runtime·roundupsize(uintptr);
-extern int32 runtime·class_to_size[NumSizeClasses];
-extern int32 runtime·class_to_allocnpages[NumSizeClasses];
-extern int8 runtime·size_to_class8[1024/8 + 1];
-extern int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
-extern void runtime·InitSizes(void);
-
-typedef struct MCacheList MCacheList;
-struct MCacheList
-{
- MLink *list;
- uint32 nlist;
-};
-
-typedef struct StackFreeList StackFreeList;
-struct StackFreeList
-{
- MLink *list; // linked list of free stacks
- uintptr size; // total size of stacks in list
-};
-
-typedef struct SudoG SudoG;
-
-// Per-thread (in Go, per-P) cache for small objects.
-// No locking needed because it is per-thread (per-P).
-struct MCache
-{
- // The following members are accessed on every malloc,
- // so they are grouped here for better caching.
- int32 next_sample; // trigger heap sample after allocating this many bytes
- intptr local_cachealloc; // bytes allocated (or freed) from cache since last lock of heap
- // Allocator cache for tiny objects w/o pointers.
- // See "Tiny allocator" comment in malloc.goc.
- byte* tiny;
- uintptr tinysize;
- uintptr local_tinyallocs; // number of tiny allocs not counted in other stats
- // The rest is not accessed on every malloc.
- MSpan* alloc[NumSizeClasses]; // spans to allocate from
-
- StackFreeList stackcache[NumStackOrders];
-
- SudoG* sudogcache;
-
- void* gcworkbuf;
-
- // Local allocator stats, flushed during GC.
- uintptr local_nlookup; // number of pointer lookups
- uintptr local_largefree; // bytes freed for large objects (>MaxSmallSize)
- uintptr local_nlargefree; // number of frees for large objects (>MaxSmallSize)
- uintptr local_nsmallfree[NumSizeClasses]; // number of frees for small objects (<=MaxSmallSize)
-};
-
-MSpan* runtime·MCache_Refill(MCache *c, int32 sizeclass);
-void runtime·MCache_ReleaseAll(MCache *c);
-void runtime·stackcache_clear(MCache *c);
-void runtime·gcworkbuffree(void *b);
-
-enum
-{
- KindSpecialFinalizer = 1,
- KindSpecialProfile = 2,
- // Note: The finalizer special must be first because if we're freeing
- // an object, a finalizer special will cause the freeing operation
- // to abort, and we want to keep the other special records around
- // if that happens.
-};
-
-typedef struct Special Special;
-struct Special
-{
- Special* next; // linked list in span
- uint16 offset; // span offset of object
- byte kind; // kind of Special
-};
-
-// The described object has a finalizer set for it.
-typedef struct SpecialFinalizer SpecialFinalizer;
-struct SpecialFinalizer
-{
- Special special;
- FuncVal* fn;
- uintptr nret;
- Type* fint;
- PtrType* ot;
-};
-
-// The described object is being heap profiled.
-typedef struct Bucket Bucket; // from mprof.h
-typedef struct SpecialProfile SpecialProfile;
-struct SpecialProfile
-{
- Special special;
- Bucket* b;
-};
-
-// An MSpan is a run of pages.
-enum
-{
- MSpanInUse = 0, // allocated for garbage collected heap
- MSpanStack, // allocated for use by stack allocator
- MSpanFree,
- MSpanListHead,
- MSpanDead,
-};
-struct MSpan
-{
- MSpan *next; // in a span linked list
- MSpan *prev; // in a span linked list
- pageID start; // starting page number
- uintptr npages; // number of pages in span
- MLink *freelist; // list of free objects
- // sweep generation:
- // if sweepgen == h->sweepgen - 2, the span needs sweeping
- // if sweepgen == h->sweepgen - 1, the span is currently being swept
- // if sweepgen == h->sweepgen, the span is swept and ready to use
- // h->sweepgen is incremented by 2 after every GC
- uint32 sweepgen;
- uint16 ref; // capacity - number of objects in freelist
- uint8 sizeclass; // size class
- bool incache; // being used by an MCache
- uint8 state; // MSpanInUse etc
- uint8 needzero; // needs to be zeroed before allocation
- uintptr elemsize; // computed from sizeclass or from npages
- int64 unusedsince; // First time spotted by GC in MSpanFree state
- uintptr npreleased; // number of pages released to the OS
- byte *limit; // end of data in span
- Mutex specialLock; // guards specials list
- Special *specials; // linked list of special records sorted by offset.
-};
-
-void runtime·MSpan_Init(MSpan *span, pageID start, uintptr npages);
-void runtime·MSpan_EnsureSwept(MSpan *span);
-bool runtime·MSpan_Sweep(MSpan *span, bool preserve);
-
-// Every MSpan is in one doubly-linked list,
-// either one of the MHeap's free lists or one of the
-// MCentral's span lists. We use empty MSpan structures as list heads.
-void runtime·MSpanList_Init(MSpan *list);
-bool runtime·MSpanList_IsEmpty(MSpan *list);
-void runtime·MSpanList_Insert(MSpan *list, MSpan *span);
-void runtime·MSpanList_InsertBack(MSpan *list, MSpan *span);
-void runtime·MSpanList_Remove(MSpan *span); // from whatever list it is in
-
-
-// Central list of free objects of a given size.
-struct MCentral
-{
- Mutex lock;
- int32 sizeclass;
- MSpan nonempty; // list of spans with a free object
- MSpan empty; // list of spans with no free objects (or cached in an MCache)
-};
-
-void runtime·MCentral_Init(MCentral *c, int32 sizeclass);
-MSpan* runtime·MCentral_CacheSpan(MCentral *c);
-void runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s);
-bool runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end, bool preserve);
-
-// Main malloc heap.
-// The heap itself is the "free[]" and "large" arrays,
-// but all the other global data is here too.
-struct MHeap
-{
- Mutex lock;
- MSpan free[MaxMHeapList]; // free lists of given length
- MSpan freelarge; // free lists length >= MaxMHeapList
- MSpan busy[MaxMHeapList]; // busy lists of large objects of given length
- MSpan busylarge; // busy lists of large objects length >= MaxMHeapList
- MSpan **allspans; // all spans out there
- MSpan **gcspans; // copy of allspans referenced by GC marker or sweeper
- uint32 nspan;
- uint32 nspancap;
- uint32 sweepgen; // sweep generation, see comment in MSpan
- uint32 sweepdone; // all spans are swept
-
- // span lookup
- MSpan** spans;
- uintptr spans_mapped;
-
- // range of addresses we might see in the heap
- byte *bitmap;
- uintptr bitmap_mapped;
- byte *arena_start;
- byte *arena_used;
- byte *arena_end;
- bool arena_reserved;
-
- // central free lists for small size classes.
- // the padding makes sure that the MCentrals are
- // spaced CacheLineSize bytes apart, so that each MCentral.lock
- // gets its own cache line.
- struct MHeapCentral {
- MCentral mcentral;
- byte pad[CacheLineSize];
- } central[NumSizeClasses];
-
- FixAlloc spanalloc; // allocator for Span*
- FixAlloc cachealloc; // allocator for MCache*
- FixAlloc specialfinalizeralloc; // allocator for SpecialFinalizer*
- FixAlloc specialprofilealloc; // allocator for SpecialProfile*
- Mutex speciallock; // lock for sepcial record allocators.
-
- // Malloc stats.
- uint64 largefree; // bytes freed for large objects (>MaxSmallSize)
- uint64 nlargefree; // number of frees for large objects (>MaxSmallSize)
- uint64 nsmallfree[NumSizeClasses]; // number of frees for small objects (<=MaxSmallSize)
-};
-#define runtime·mheap runtime·mheap_
-extern MHeap runtime·mheap;
-
-void runtime·MHeap_Init(MHeap *h);
-MSpan* runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero);
-MSpan* runtime·MHeap_AllocStack(MHeap *h, uintptr npage);
-void runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct);
-void runtime·MHeap_FreeStack(MHeap *h, MSpan *s);
-MSpan* runtime·MHeap_Lookup(MHeap *h, void *v);
-MSpan* runtime·MHeap_LookupMaybe(MHeap *h, void *v);
-void* runtime·MHeap_SysAlloc(MHeap *h, uintptr n);
-void runtime·MHeap_MapBits(MHeap *h);
-void runtime·MHeap_MapSpans(MHeap *h);
-void runtime·MHeap_Scavenge(int32 k, uint64 now, uint64 limit);
-
-void* runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat);
-int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s);
-uintptr runtime·sweepone(void);
-void runtime·markspan(void *v, uintptr size, uintptr n, bool leftover);
-void runtime·unmarkspan(void *v, uintptr size);
-void runtime·purgecachedstats(MCache*);
-void runtime·tracealloc(void*, uintptr, Type*);
-void runtime·tracefree(void*, uintptr);
-void runtime·tracegc(void);
-
-int32 runtime·gcpercent;
-int32 runtime·readgogc(void);
-void runtime·clearpools(void);
-
-enum
-{
- // flags to malloc
- FlagNoScan = 1<<0, // GC doesn't have to scan object
- FlagNoZero = 1<<1, // don't zero memory
-};
-
-void runtime·mProf_Malloc(void*, uintptr);
-void runtime·mProf_Free(Bucket*, uintptr, bool);
-void runtime·mProf_GC(void);
-void runtime·iterate_memprof(void (**callback)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr));
-int32 runtime·gcprocs(void);
-void runtime·helpgc(int32 nproc);
-void runtime·gchelper(void);
-void runtime·createfing(void);
-G* runtime·wakefing(void);
-void runtime·getgcmask(byte*, Type*, byte**, uintptr*);
-
-// NOTE: Layout known to queuefinalizer.
-typedef struct Finalizer Finalizer;
-struct Finalizer
-{
- FuncVal *fn; // function to call
- void *arg; // ptr to object
- uintptr nret; // bytes of return values from fn
- Type *fint; // type of first argument of fn
- PtrType *ot; // type of ptr to object
-};
-
-typedef struct FinBlock FinBlock;
-struct FinBlock
-{
- FinBlock *alllink;
- FinBlock *next;
- int32 cnt;
- int32 cap;
- Finalizer fin[1];
-};
-extern Mutex runtime·finlock; // protects the following variables
-extern G* runtime·fing;
-extern bool runtime·fingwait;
-extern bool runtime·fingwake;
-extern FinBlock *runtime·finq; // list of finalizers that are to be executed
-extern FinBlock *runtime·finc; // cache of free blocks
-
-void runtime·setprofilebucket_m(void);
-
-bool runtime·addfinalizer(void*, FuncVal *fn, uintptr, Type*, PtrType*);
-void runtime·removefinalizer(void*);
-void runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot);
-bool runtime·freespecial(Special *s, void *p, uintptr size, bool freed);
-
-// Information from the compiler about the layout of stack frames.
-struct BitVector
-{
- int32 n; // # of bits
- uint8 *bytedata;
-};
-typedef struct StackMap StackMap;
-struct StackMap
-{
- int32 n; // number of bitmaps
- int32 nbit; // number of bits in each bitmap
- uint8 bytedata[]; // bitmaps, each starting on a 32-bit boundary
-};
-// Returns pointer map data for the given stackmap index
-// (the index is encoded in PCDATA_StackMapIndex).
-BitVector runtime·stackmapdata(StackMap *stackmap, int32 n);
-
-extern BitVector runtime·gcdatamask;
-extern BitVector runtime·gcbssmask;
-
-// defined in mgc0.go
-void runtime·gc_m_ptr(Eface*);
-void runtime·gc_g_ptr(Eface*);
-void runtime·gc_itab_ptr(Eface*);
-
-void runtime·setgcpercent_m(void);
-
-// Value we use to mark dead pointers when GODEBUG=gcdead=1.
-#define PoisonGC ((uintptr)0xf969696969696969ULL)
-#define PoisonStack ((uintptr)0x6868686868686868ULL)
diff --git a/src/runtime/malloc1.go b/src/runtime/malloc1.go
new file mode 100644
index 000000000..db02d9cca
--- /dev/null
+++ b/src/runtime/malloc1.go
@@ -0,0 +1,318 @@
+// 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.
+
+// See malloc.h for overview.
+//
+// TODO(rsc): double-check stats.
+
+package runtime
+
+import "unsafe"
+
+const _MaxArena32 = 2 << 30
+
+// For use by Go. If it were a C enum it would be made available automatically,
+// but the value of MaxMem is too large for enum.
+// XXX - uintptr runtime·maxmem = MaxMem;
+
+func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 {
+ _g_ := getg()
+
+ _g_.m.mcache.local_nlookup++
+ if ptrSize == 4 && _g_.m.mcache.local_nlookup >= 1<<30 {
+ // purge cache stats to prevent overflow
+ lock(&mheap_.lock)
+ purgecachedstats(_g_.m.mcache)
+ unlock(&mheap_.lock)
+ }
+
+ s := mHeap_LookupMaybe(&mheap_, unsafe.Pointer(v))
+ if sp != nil {
+ *sp = s
+ }
+ if s == nil {
+ if base != nil {
+ *base = 0
+ }
+ if size != nil {
+ *size = 0
+ }
+ return 0
+ }
+
+ p := uintptr(s.start) << _PageShift
+ if s.sizeclass == 0 {
+ // Large object.
+ if base != nil {
+ *base = p
+ }
+ if size != nil {
+ *size = s.npages << _PageShift
+ }
+ return 1
+ }
+
+ n := s.elemsize
+ if base != nil {
+ i := (uintptr(v) - uintptr(p)) / n
+ *base = p + i*n
+ }
+ if size != nil {
+ *size = n
+ }
+
+ return 1
+}
+
+//go:nosplit
+func purgecachedstats(c *mcache) {
+ // Protected by either heap or GC lock.
+ h := &mheap_
+ memstats.heap_alloc += uint64(c.local_cachealloc)
+ c.local_cachealloc = 0
+ memstats.tinyallocs += uint64(c.local_tinyallocs)
+ c.local_tinyallocs = 0
+ memstats.nlookup += uint64(c.local_nlookup)
+ c.local_nlookup = 0
+ h.largefree += uint64(c.local_largefree)
+ c.local_largefree = 0
+ h.nlargefree += uint64(c.local_nlargefree)
+ c.local_nlargefree = 0
+ for i := 0; i < len(c.local_nsmallfree); i++ {
+ h.nsmallfree[i] += uint64(c.local_nsmallfree[i])
+ c.local_nsmallfree[i] = 0
+ }
+}
+
+func mallocinit() {
+ initSizes()
+
+ if class_to_size[_TinySizeClass] != _TinySize {
+ gothrow("bad TinySizeClass")
+ }
+
+ var p, arena_size, bitmap_size, spans_size, p_size, limit uintptr
+ var reserved bool
+
+ // limit = runtime.memlimit();
+ // See https://code.google.com/p/go/issues/detail?id=5049
+ // TODO(rsc): Fix after 1.1.
+ limit = 0
+
+ // Set up the allocation arena, a contiguous area of memory where
+ // allocated data will be found. The arena begins with a bitmap large
+ // enough to hold 4 bits per allocated word.
+ if ptrSize == 8 && (limit == 0 || limit > 1<<30) {
+ // On a 64-bit machine, allocate from a single contiguous reservation.
+ // 128 GB (MaxMem) should be big enough for now.
+ //
+ // The code will work with the reservation at any address, but ask
+ // SysReserve to use 0x0000XXc000000000 if possible (XX=00...7f).
+ // Allocating a 128 GB region takes away 37 bits, and the amd64
+ // doesn't let us choose the top 17 bits, so that leaves the 11 bits
+ // in the middle of 0x00c0 for us to choose. Choosing 0x00c0 means
+ // that the valid memory addresses will begin 0x00c0, 0x00c1, ..., 0x00df.
+ // In little-endian, that's c0 00, c1 00, ..., df 00. None of those are valid
+ // UTF-8 sequences, and they are otherwise as far away from
+ // ff (likely a common byte) as possible. If that fails, we try other 0xXXc0
+ // addresses. An earlier attempt to use 0x11f8 caused out of memory errors
+ // on OS X during thread allocations. 0x00c0 causes conflicts with
+ // AddressSanitizer which reserves all memory up to 0x0100.
+ // These choices are both for debuggability and to reduce the
+ // odds of the conservative garbage collector not collecting memory
+ // because some non-pointer block of memory had a bit pattern
+ // that matched a memory address.
+ //
+ // Actually we reserve 136 GB (because the bitmap ends up being 8 GB)
+ // but it hardly matters: e0 00 is not valid UTF-8 either.
+ //
+ // If this fails we fall back to the 32 bit memory mechanism
+ arena_size = round(_MaxMem, _PageSize)
+ bitmap_size = arena_size / (ptrSize * 8 / 4)
+ spans_size = arena_size / _PageSize * ptrSize
+ spans_size = round(spans_size, _PageSize)
+ for i := 0; i <= 0x7f; i++ {
+ p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
+ p_size = bitmap_size + spans_size + arena_size + _PageSize
+ p = uintptr(sysReserve(unsafe.Pointer(p), p_size, &reserved))
+ if p != 0 {
+ break
+ }
+ }
+ }
+
+ if p == 0 {
+ // On a 32-bit machine, we can't typically get away
+ // with a giant virtual address space reservation.
+ // Instead we map the memory information bitmap
+ // immediately after the data segment, large enough
+ // to handle another 2GB of mappings (256 MB),
+ // along with a reservation for another 512 MB of memory.
+ // When that gets used up, we'll start asking the kernel
+ // for any memory anywhere and hope it's in the 2GB
+ // following the bitmap (presumably the executable begins
+ // near the bottom of memory, so we'll have to use up
+ // most of memory before the kernel resorts to giving out
+ // memory before the beginning of the text segment).
+ //
+ // Alternatively we could reserve 512 MB bitmap, enough
+ // for 4GB of mappings, and then accept any memory the
+ // kernel threw at us, but normally that's a waste of 512 MB
+ // of address space, which is probably too much in a 32-bit world.
+ bitmap_size = _MaxArena32 / (ptrSize * 8 / 4)
+ arena_size = 512 << 20
+ spans_size = _MaxArena32 / _PageSize * ptrSize
+ if limit > 0 && arena_size+bitmap_size+spans_size > limit {
+ bitmap_size = (limit / 9) &^ ((1 << _PageShift) - 1)
+ arena_size = bitmap_size * 8
+ spans_size = arena_size / _PageSize * ptrSize
+ }
+ spans_size = round(spans_size, _PageSize)
+
+ // SysReserve treats the address we ask for, end, as a hint,
+ // not as an absolute requirement. If we ask for the end
+ // of the data segment but the operating system requires
+ // a little more space before we can start allocating, it will
+ // give out a slightly higher pointer. Except QEMU, which
+ // is buggy, as usual: it won't adjust the pointer upward.
+ // So adjust it upward a little bit ourselves: 1/4 MB to get
+ // away from the running binary image and then round up
+ // to a MB boundary.
+ p = round(uintptr(unsafe.Pointer(&end))+(1<<18), 1<<20)
+ p_size = bitmap_size + spans_size + arena_size + _PageSize
+ p = uintptr(sysReserve(unsafe.Pointer(p), p_size, &reserved))
+ if p == 0 {
+ gothrow("runtime: cannot reserve arena virtual address space")
+ }
+ }
+
+ // PageSize can be larger than OS definition of page size,
+ // so SysReserve can give us a PageSize-unaligned pointer.
+ // To overcome this we ask for PageSize more and round up the pointer.
+ p1 := round(p, _PageSize)
+
+ mheap_.spans = (**mspan)(unsafe.Pointer(p1))
+ mheap_.bitmap = p1 + spans_size
+ mheap_.arena_start = p1 + (spans_size + bitmap_size)
+ mheap_.arena_used = mheap_.arena_start
+ mheap_.arena_end = p + p_size
+ mheap_.arena_reserved = reserved
+
+ if mheap_.arena_start&(_PageSize-1) != 0 {
+ println("bad pagesize", hex(p), hex(p1), hex(spans_size), hex(bitmap_size), hex(_PageSize), "start", hex(mheap_.arena_start))
+ gothrow("misrounded allocation in mallocinit")
+ }
+
+ // Initialize the rest of the allocator.
+ mHeap_Init(&mheap_, spans_size)
+ _g_ := getg()
+ _g_.m.mcache = allocmcache()
+}
+
+func mHeap_SysAlloc(h *mheap, n uintptr) unsafe.Pointer {
+ if n > uintptr(h.arena_end)-uintptr(h.arena_used) {
+ // We are in 32-bit mode, maybe we didn't use all possible address space yet.
+ // Reserve some more space.
+ p_size := round(n+_PageSize, 256<<20)
+ new_end := h.arena_end + p_size
+ if new_end <= h.arena_start+_MaxArena32 {
+ // TODO: It would be bad if part of the arena
+ // is reserved and part is not.
+ var reserved bool
+ p := uintptr(sysReserve((unsafe.Pointer)(h.arena_end), p_size, &reserved))
+ if p == h.arena_end {
+ h.arena_end = new_end
+ h.arena_reserved = reserved
+ } else if p+p_size <= h.arena_start+_MaxArena32 {
+ // Keep everything page-aligned.
+ // Our pages are bigger than hardware pages.
+ h.arena_end = p + p_size
+ h.arena_used = p + (-uintptr(p) & (_PageSize - 1))
+ h.arena_reserved = reserved
+ } else {
+ var stat uint64
+ sysFree((unsafe.Pointer)(p), p_size, &stat)
+ }
+ }
+ }
+
+ if n <= uintptr(h.arena_end)-uintptr(h.arena_used) {
+ // Keep taking from our reservation.
+ p := h.arena_used
+ sysMap((unsafe.Pointer)(p), n, h.arena_reserved, &memstats.heap_sys)
+ h.arena_used += n
+ mHeap_MapBits(h)
+ mHeap_MapSpans(h)
+ if raceenabled {
+ racemapshadow((unsafe.Pointer)(p), n)
+ }
+
+ if uintptr(p)&(_PageSize-1) != 0 {
+ gothrow("misrounded allocation in MHeap_SysAlloc")
+ }
+ return (unsafe.Pointer)(p)
+ }
+
+ // If using 64-bit, our reservation is all we have.
+ if uintptr(h.arena_end)-uintptr(h.arena_start) >= _MaxArena32 {
+ return nil
+ }
+
+ // On 32-bit, once the reservation is gone we can
+ // try to get memory at a location chosen by the OS
+ // and hope that it is in the range we allocated bitmap for.
+ p_size := round(n, _PageSize) + _PageSize
+ p := uintptr(sysAlloc(p_size, &memstats.heap_sys))
+ if p == 0 {
+ return nil
+ }
+
+ if p < h.arena_start || uintptr(p)+p_size-uintptr(h.arena_start) >= _MaxArena32 {
+ print("runtime: memory allocated by OS (", p, ") not in usable range [", hex(h.arena_start), ",", hex(h.arena_start+_MaxArena32), ")\n")
+ sysFree((unsafe.Pointer)(p), p_size, &memstats.heap_sys)
+ return nil
+ }
+
+ p_end := p + p_size
+ p += -p & (_PageSize - 1)
+ if uintptr(p)+n > uintptr(h.arena_used) {
+ h.arena_used = p + n
+ if p_end > h.arena_end {
+ h.arena_end = p_end
+ }
+ mHeap_MapBits(h)
+ mHeap_MapSpans(h)
+ if raceenabled {
+ racemapshadow((unsafe.Pointer)(p), n)
+ }
+ }
+
+ if uintptr(p)&(_PageSize-1) != 0 {
+ gothrow("misrounded allocation in MHeap_SysAlloc")
+ }
+ return (unsafe.Pointer)(p)
+}
+
+var end struct{}
+
+func largeAlloc(size uintptr, flag uint32) *mspan {
+ // print("largeAlloc size=", size, "\n")
+
+ if size+_PageSize < size {
+ gothrow("out of memory")
+ }
+ npages := size >> _PageShift
+ if size&_PageMask != 0 {
+ npages++
+ }
+ s := mHeap_Alloc(&mheap_, npages, 0, true, flag&_FlagNoZero == 0)
+ if s == nil {
+ gothrow("out of memory")
+ }
+ s.limit = uintptr(s.start)<<_PageShift + size
+ v := unsafe.Pointer(uintptr(s.start) << _PageShift)
+ // setup for mark sweep
+ markspan(v, 0, 0, true)
+ return s
+}
diff --git a/src/runtime/malloc2.go b/src/runtime/malloc2.go
new file mode 100644
index 000000000..c175c2aec
--- /dev/null
+++ b/src/runtime/malloc2.go
@@ -0,0 +1,475 @@
+// 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 runtime
+
+import "unsafe"
+
+// Memory allocator, based on tcmalloc.
+// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
+
+// The main allocator works in runs of pages.
+// Small allocation sizes (up to and including 32 kB) are
+// rounded to one of about 100 size classes, each of which
+// has its own free list of objects of exactly that size.
+// Any free page of memory can be split into a set of objects
+// of one size class, which are then managed using free list
+// allocators.
+//
+// The allocator's data structures are:
+//
+// FixAlloc: a free-list allocator for fixed-size objects,
+// used to manage storage used by the allocator.
+// MHeap: the malloc heap, managed at page (4096-byte) granularity.
+// MSpan: a run of pages managed by the MHeap.
+// MCentral: a shared free list for a given size class.
+// MCache: a per-thread (in Go, per-P) cache for small objects.
+// MStats: allocation statistics.
+//
+// Allocating a small object proceeds up a hierarchy of caches:
+//
+// 1. Round the size up to one of the small size classes
+// and look in the corresponding MCache free list.
+// If the list is not empty, allocate an object from it.
+// This can all be done without acquiring a lock.
+//
+// 2. If the MCache free list is empty, replenish it by
+// taking a bunch of objects from the MCentral free list.
+// Moving a bunch amortizes the cost of acquiring the MCentral lock.
+//
+// 3. If the MCentral free list is empty, replenish it by
+// allocating a run of pages from the MHeap and then
+// chopping that memory into a objects of the given size.
+// Allocating many objects amortizes the cost of locking
+// the heap.
+//
+// 4. If the MHeap is empty or has no page runs large enough,
+// allocate a new group of pages (at least 1MB) from the
+// operating system. Allocating a large run of pages
+// amortizes the cost of talking to the operating system.
+//
+// Freeing a small object proceeds up the same hierarchy:
+//
+// 1. Look up the size class for the object and add it to
+// the MCache free list.
+//
+// 2. If the MCache free list is too long or the MCache has
+// too much memory, return some to the MCentral free lists.
+//
+// 3. If all the objects in a given span have returned to
+// the MCentral list, return that span to the page heap.
+//
+// 4. If the heap has too much memory, return some to the
+// operating system.
+//
+// TODO(rsc): Step 4 is not implemented.
+//
+// Allocating and freeing a large object uses the page heap
+// directly, bypassing the MCache and MCentral free lists.
+//
+// The small objects on the MCache and MCentral free lists
+// may or may not be zeroed. They are zeroed if and only if
+// the second word of the object is zero. A span in the
+// page heap is zeroed unless s->needzero is set. When a span
+// is allocated to break into small objects, it is zeroed if needed
+// and s->needzero is set. There are two main benefits to delaying the
+// zeroing this way:
+//
+// 1. stack frames allocated from the small object lists
+// or the page heap can avoid zeroing altogether.
+// 2. the cost of zeroing when reusing a small object is
+// charged to the mutator, not the garbage collector.
+//
+// This C code was written with an eye toward translating to Go
+// in the future. Methods have the form Type_Method(Type *t, ...).
+
+const (
+ _PageShift = 13
+ _PageSize = 1 << _PageShift
+ _PageMask = _PageSize - 1
+)
+
+const (
+ // _64bit = 1 on 64-bit systems, 0 on 32-bit systems
+ _64bit = 1 << (^uintptr(0) >> 63) / 2
+
+ // Computed constant. The definition of MaxSmallSize and the
+ // algorithm in msize.c produce some number of different allocation
+ // size classes. NumSizeClasses is that number. It's needed here
+ // because there are static arrays of this length; when msize runs its
+ // size choosing algorithm it double-checks that NumSizeClasses agrees.
+ _NumSizeClasses = 67
+
+ // Tunable constants.
+ _MaxSmallSize = 32 << 10
+
+ // Tiny allocator parameters, see "Tiny allocator" comment in malloc.goc.
+ _TinySize = 16
+ _TinySizeClass = 2
+
+ _FixAllocChunk = 16 << 10 // Chunk size for FixAlloc
+ _MaxMHeapList = 1 << (20 - _PageShift) // Maximum page length for fixed-size list in MHeap.
+ _HeapAllocChunk = 1 << 20 // Chunk size for heap growth
+
+ // Per-P, per order stack segment cache size.
+ _StackCacheSize = 32 * 1024
+
+ // Number of orders that get caching. Order 0 is FixedStack
+ // and each successive order is twice as large.
+ _NumStackOrders = 3
+
+ // Number of bits in page to span calculations (4k pages).
+ // On Windows 64-bit we limit the arena to 32GB or 35 bits.
+ // Windows counts memory used by page table into committed memory
+ // of the process, so we can't reserve too much memory.
+ // See http://golang.org/issue/5402 and http://golang.org/issue/5236.
+ // On other 64-bit platforms, we limit the arena to 128GB, or 37 bits.
+ // On 32-bit, we don't bother limiting anything, so we use the full 32-bit address.
+ _MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows))*37 + (1-_64bit)*32
+ _MHeapMap_Bits = _MHeapMap_TotalBits - _PageShift
+
+ _MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1)
+
+ // Max number of threads to run garbage collection.
+ // 2, 3, and 4 are all plausible maximums depending
+ // on the hardware details of the machine. The garbage
+ // collector scales well to 32 cpus.
+ _MaxGcproc = 32
+)
+
+// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
+type mlink struct {
+ next *mlink
+}
+
+// sysAlloc obtains a large chunk of zeroed memory from the
+// operating system, typically on the order of a hundred kilobytes
+// or a megabyte.
+// NOTE: sysAlloc returns OS-aligned memory, but the heap allocator
+// may use larger alignment, so the caller must be careful to realign the
+// memory obtained by sysAlloc.
+//
+// SysUnused notifies the operating system that the contents
+// of the memory region are no longer needed and can be reused
+// for other purposes.
+// SysUsed notifies the operating system that the contents
+// of the memory region are needed again.
+//
+// SysFree returns it unconditionally; this is only used if
+// an out-of-memory error has been detected midway through
+// an allocation. It is okay if SysFree is a no-op.
+//
+// SysReserve reserves address space without allocating memory.
+// If the pointer passed to it is non-nil, the caller wants the
+// reservation there, but SysReserve can still choose another
+// location if that one is unavailable. On some systems and in some
+// cases SysReserve will simply check that the address space is
+// available and not actually reserve it. If SysReserve returns
+// non-nil, it sets *reserved to true if the address space is
+// reserved, false if it has merely been checked.
+// NOTE: SysReserve returns OS-aligned memory, but the heap allocator
+// may use larger alignment, so the caller must be careful to realign the
+// memory obtained by sysAlloc.
+//
+// SysMap maps previously reserved address space for use.
+// The reserved argument is true if the address space was really
+// reserved, not merely checked.
+//
+// SysFault marks a (already sysAlloc'd) region to fault
+// if accessed. Used only for debugging the runtime.
+
+// FixAlloc is a simple free-list allocator for fixed size objects.
+// Malloc uses a FixAlloc wrapped around sysAlloc to manages its
+// MCache and MSpan objects.
+//
+// Memory returned by FixAlloc_Alloc is not zeroed.
+// The caller is responsible for locking around FixAlloc calls.
+// Callers can keep state in the object but the first word is
+// smashed by freeing and reallocating.
+type fixalloc struct {
+ size uintptr
+ first unsafe.Pointer // go func(unsafe.pointer, unsafe.pointer); f(arg, p) called first time p is returned
+ arg unsafe.Pointer
+ list *mlink
+ chunk *byte
+ nchunk uint32
+ inuse uintptr // in-use bytes now
+ stat *uint64
+}
+
+// Statistics.
+// Shared with Go: if you edit this structure, also edit type MemStats in mem.go.
+type mstats struct {
+ // General statistics.
+ alloc uint64 // bytes allocated and still in use
+ total_alloc uint64 // bytes allocated (even if freed)
+ sys uint64 // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
+ nlookup uint64 // number of pointer lookups
+ nmalloc uint64 // number of mallocs
+ nfree uint64 // number of frees
+
+ // Statistics about malloc heap.
+ // protected by mheap.lock
+ heap_alloc uint64 // bytes allocated and still in use
+ heap_sys uint64 // bytes obtained from system
+ heap_idle uint64 // bytes in idle spans
+ heap_inuse uint64 // bytes in non-idle spans
+ heap_released uint64 // bytes released to the os
+ heap_objects uint64 // total number of allocated objects
+
+ // Statistics about allocation of low-level fixed-size structures.
+ // Protected by FixAlloc locks.
+ stacks_inuse uint64 // this number is included in heap_inuse above
+ stacks_sys uint64 // always 0 in mstats
+ mspan_inuse uint64 // mspan structures
+ mspan_sys uint64
+ mcache_inuse uint64 // mcache structures
+ mcache_sys uint64
+ buckhash_sys uint64 // profiling bucket hash table
+ gc_sys uint64
+ other_sys uint64
+
+ // Statistics about garbage collector.
+ // Protected by mheap or stopping the world during GC.
+ next_gc uint64 // next gc (in heap_alloc time)
+ last_gc uint64 // last gc (in absolute time)
+ pause_total_ns uint64
+ pause_ns [256]uint64 // circular buffer of recent gc pause lengths
+ pause_end [256]uint64 // circular buffer of recent gc end times (nanoseconds since 1970)
+ numgc uint32
+ enablegc bool
+ debuggc bool
+
+ // Statistics about allocation size classes.
+
+ by_size [_NumSizeClasses]struct {
+ size uint32
+ nmalloc uint64
+ nfree uint64
+ }
+
+ tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly
+}
+
+var memstats mstats
+
+// Size classes. Computed and initialized by InitSizes.
+//
+// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
+// 1 <= sizeclass < NumSizeClasses, for n.
+// Size class 0 is reserved to mean "not small".
+//
+// class_to_size[i] = largest size in class i
+// class_to_allocnpages[i] = number of pages to allocate when
+// making new objects in class i
+
+var class_to_size [_NumSizeClasses]int32
+var class_to_allocnpages [_NumSizeClasses]int32
+var size_to_class8 [1024/8 + 1]int8
+var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8
+
+type mcachelist struct {
+ list *mlink
+ nlist uint32
+}
+
+type stackfreelist struct {
+ list *mlink // linked list of free stacks
+ size uintptr // total size of stacks in list
+}
+
+// Per-thread (in Go, per-P) cache for small objects.
+// No locking needed because it is per-thread (per-P).
+type mcache struct {
+ // The following members are accessed on every malloc,
+ // so they are grouped here for better caching.
+ next_sample int32 // trigger heap sample after allocating this many bytes
+ local_cachealloc intptr // bytes allocated (or freed) from cache since last lock of heap
+ // Allocator cache for tiny objects w/o pointers.
+ // See "Tiny allocator" comment in malloc.goc.
+ tiny *byte
+ tinysize uintptr
+ local_tinyallocs uintptr // number of tiny allocs not counted in other stats
+
+ // The rest is not accessed on every malloc.
+ alloc [_NumSizeClasses]*mspan // spans to allocate from
+
+ stackcache [_NumStackOrders]stackfreelist
+
+ sudogcache *sudog
+
+ gcworkbuf unsafe.Pointer
+
+ // Local allocator stats, flushed during GC.
+ local_nlookup uintptr // number of pointer lookups
+ local_largefree uintptr // bytes freed for large objects (>maxsmallsize)
+ local_nlargefree uintptr // number of frees for large objects (>maxsmallsize)
+ local_nsmallfree [_NumSizeClasses]uintptr // number of frees for small objects (<=maxsmallsize)
+}
+
+const (
+ _KindSpecialFinalizer = 1
+ _KindSpecialProfile = 2
+ // Note: The finalizer special must be first because if we're freeing
+ // an object, a finalizer special will cause the freeing operation
+ // to abort, and we want to keep the other special records around
+ // if that happens.
+)
+
+type special struct {
+ next *special // linked list in span
+ offset uint16 // span offset of object
+ kind byte // kind of special
+}
+
+// The described object has a finalizer set for it.
+type specialfinalizer struct {
+ special special
+ fn *funcval
+ nret uintptr
+ fint *_type
+ ot *ptrtype
+}
+
+// The described object is being heap profiled.
+type specialprofile struct {
+ special special
+ b *bucket
+}
+
+// An MSpan is a run of pages.
+const (
+ _MSpanInUse = iota // allocated for garbage collected heap
+ _MSpanStack // allocated for use by stack allocator
+ _MSpanFree
+ _MSpanListHead
+ _MSpanDead
+)
+
+type mspan struct {
+ next *mspan // in a span linked list
+ prev *mspan // in a span linked list
+ start pageID // starting page number
+ npages uintptr // number of pages in span
+ freelist *mlink // list of free objects
+ // sweep generation:
+ // if sweepgen == h->sweepgen - 2, the span needs sweeping
+ // if sweepgen == h->sweepgen - 1, the span is currently being swept
+ // if sweepgen == h->sweepgen, the span is swept and ready to use
+ // h->sweepgen is incremented by 2 after every GC
+ sweepgen uint32
+ ref uint16 // capacity - number of objects in freelist
+ sizeclass uint8 // size class
+ incache bool // being used by an mcache
+ state uint8 // mspaninuse etc
+ needzero uint8 // needs to be zeroed before allocation
+ elemsize uintptr // computed from sizeclass or from npages
+ unusedsince int64 // first time spotted by gc in mspanfree state
+ npreleased uintptr // number of pages released to the os
+ limit uintptr // end of data in span
+ speciallock mutex // guards specials list
+ specials *special // linked list of special records sorted by offset.
+}
+
+// Every MSpan is in one doubly-linked list,
+// either one of the MHeap's free lists or one of the
+// MCentral's span lists. We use empty MSpan structures as list heads.
+
+// Central list of free objects of a given size.
+type mcentral struct {
+ lock mutex
+ sizeclass int32
+ nonempty mspan // list of spans with a free object
+ empty mspan // list of spans with no free objects (or cached in an mcache)
+}
+
+// Main malloc heap.
+// The heap itself is the "free[]" and "large" arrays,
+// but all the other global data is here too.
+type mheap struct {
+ lock mutex
+ free [_MaxMHeapList]mspan // free lists of given length
+ freelarge mspan // free lists length >= _MaxMHeapList
+ busy [_MaxMHeapList]mspan // busy lists of large objects of given length
+ busylarge mspan // busy lists of large objects length >= _MaxMHeapList
+ allspans **mspan // all spans out there
+ gcspans **mspan // copy of allspans referenced by gc marker or sweeper
+ nspan uint32
+ sweepgen uint32 // sweep generation, see comment in mspan
+ sweepdone uint32 // all spans are swept
+
+ // span lookup
+ spans **mspan
+ spans_mapped uintptr
+
+ // range of addresses we might see in the heap
+ bitmap uintptr
+ bitmap_mapped uintptr
+ arena_start uintptr
+ arena_used uintptr
+ arena_end uintptr
+ arena_reserved bool
+
+ // central free lists for small size classes.
+ // the padding makes sure that the MCentrals are
+ // spaced CacheLineSize bytes apart, so that each MCentral.lock
+ // gets its own cache line.
+ central [_NumSizeClasses]struct {
+ mcentral mcentral
+ pad [_CacheLineSize]byte
+ }
+
+ spanalloc fixalloc // allocator for span*
+ cachealloc fixalloc // allocator for mcache*
+ specialfinalizeralloc fixalloc // allocator for specialfinalizer*
+ specialprofilealloc fixalloc // allocator for specialprofile*
+ speciallock mutex // lock for sepcial record allocators.
+
+ // Malloc stats.
+ largefree uint64 // bytes freed for large objects (>maxsmallsize)
+ nlargefree uint64 // number of frees for large objects (>maxsmallsize)
+ nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize)
+}
+
+var mheap_ mheap
+
+const (
+ // flags to malloc
+ _FlagNoScan = 1 << 0 // GC doesn't have to scan object
+ _FlagNoZero = 1 << 1 // don't zero memory
+)
+
+// NOTE: Layout known to queuefinalizer.
+type finalizer struct {
+ fn *funcval // function to call
+ arg unsafe.Pointer // ptr to object
+ nret uintptr // bytes of return values from fn
+ fint *_type // type of first argument of fn
+ ot *ptrtype // type of ptr to object
+}
+
+type finblock struct {
+ alllink *finblock
+ next *finblock
+ cnt int32
+ cap int32
+ fin [1]finalizer
+}
+
+// Information from the compiler about the layout of stack frames.
+type bitvector struct {
+ n int32 // # of bits
+ bytedata *uint8
+}
+
+type stackmap struct {
+ n int32 // number of bitmaps
+ nbit int32 // number of bits in each bitmap
+ bytedata [0]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
diff --git a/src/runtime/mcache.c b/src/runtime/mcache.c
deleted file mode 100644
index 5fdbe3266..000000000
--- a/src/runtime/mcache.c
+++ /dev/null
@@ -1,115 +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.
-
-// Per-P malloc cache for small objects.
-//
-// See malloc.h for an overview.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-extern volatile intgo runtime·MemProfileRate;
-
-// dummy MSpan that contains no free objects.
-MSpan runtime·emptymspan;
-
-MCache*
-runtime·allocmcache(void)
-{
- intgo rate;
- MCache *c;
- int32 i;
-
- runtime·lock(&runtime·mheap.lock);
- c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc);
- runtime·unlock(&runtime·mheap.lock);
- runtime·memclr((byte*)c, sizeof(*c));
- for(i = 0; i < NumSizeClasses; i++)
- c->alloc[i] = &runtime·emptymspan;
-
- // Set first allocation sample size.
- rate = runtime·MemProfileRate;
- if(rate > 0x3fffffff) // make 2*rate not overflow
- rate = 0x3fffffff;
- if(rate != 0)
- c->next_sample = runtime·fastrand1() % (2*rate);
-
- return c;
-}
-
-static void
-freemcache(MCache *c)
-{
- runtime·MCache_ReleaseAll(c);
- runtime·stackcache_clear(c);
- runtime·gcworkbuffree(c->gcworkbuf);
- runtime·lock(&runtime·mheap.lock);
- runtime·purgecachedstats(c);
- runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c);
- runtime·unlock(&runtime·mheap.lock);
-}
-
-static void
-freemcache_m(void)
-{
- MCache *c;
-
- c = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- freemcache(c);
-}
-
-void
-runtime·freemcache(MCache *c)
-{
- void (*fn)(void);
-
- g->m->ptrarg[0] = c;
- fn = freemcache_m;
- runtime·onM(&fn);
-}
-
-// Gets a span that has a free object in it and assigns it
-// to be the cached span for the given sizeclass. Returns this span.
-MSpan*
-runtime·MCache_Refill(MCache *c, int32 sizeclass)
-{
- MSpan *s;
-
- g->m->locks++;
- // Return the current cached span to the central lists.
- s = c->alloc[sizeclass];
- if(s->freelist != nil)
- runtime·throw("refill on a nonempty span");
- if(s != &runtime·emptymspan)
- s->incache = false;
-
- // Get a new cached span from the central lists.
- s = runtime·MCentral_CacheSpan(&runtime·mheap.central[sizeclass].mcentral);
- if(s == nil)
- runtime·throw("out of memory");
- if(s->freelist == nil) {
- runtime·printf("%d %d\n", s->ref, (int32)((s->npages << PageShift) / s->elemsize));
- runtime·throw("empty span");
- }
- c->alloc[sizeclass] = s;
- g->m->locks--;
- return s;
-}
-
-void
-runtime·MCache_ReleaseAll(MCache *c)
-{
- int32 i;
- MSpan *s;
-
- for(i=0; i<NumSizeClasses; i++) {
- s = c->alloc[i];
- if(s != &runtime·emptymspan) {
- runtime·MCentral_UncacheSpan(&runtime·mheap.central[i].mcentral, s);
- c->alloc[i] = &runtime·emptymspan;
- }
- }
-}
diff --git a/src/runtime/mcache.go b/src/runtime/mcache.go
new file mode 100644
index 000000000..d3afef6be
--- /dev/null
+++ b/src/runtime/mcache.go
@@ -0,0 +1,86 @@
+// 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.
+
+// Per-P malloc cache for small objects.
+//
+// See malloc.h for an overview.
+
+package runtime
+
+import "unsafe"
+
+// dummy MSpan that contains no free objects.
+var emptymspan mspan
+
+func allocmcache() *mcache {
+ lock(&mheap_.lock)
+ c := (*mcache)(fixAlloc_Alloc(&mheap_.cachealloc))
+ unlock(&mheap_.lock)
+ memclr(unsafe.Pointer(c), unsafe.Sizeof(*c))
+ for i := 0; i < _NumSizeClasses; i++ {
+ c.alloc[i] = &emptymspan
+ }
+
+ // Set first allocation sample size.
+ rate := MemProfileRate
+ if rate > 0x3fffffff { // make 2*rate not overflow
+ rate = 0x3fffffff
+ }
+ if rate != 0 {
+ c.next_sample = int32(int(fastrand1()) % (2 * rate))
+ }
+
+ return c
+}
+
+func freemcache(c *mcache) {
+ systemstack(func() {
+ mCache_ReleaseAll(c)
+ stackcache_clear(c)
+ gcworkbuffree(c.gcworkbuf)
+ lock(&mheap_.lock)
+ purgecachedstats(c)
+ fixAlloc_Free(&mheap_.cachealloc, unsafe.Pointer(c))
+ unlock(&mheap_.lock)
+ })
+}
+
+// Gets a span that has a free object in it and assigns it
+// to be the cached span for the given sizeclass. Returns this span.
+func mCache_Refill(c *mcache, sizeclass int32) *mspan {
+ _g_ := getg()
+
+ _g_.m.locks++
+ // Return the current cached span to the central lists.
+ s := c.alloc[sizeclass]
+ if s.freelist != nil {
+ gothrow("refill on a nonempty span")
+ }
+ if s != &emptymspan {
+ s.incache = false
+ }
+
+ // Get a new cached span from the central lists.
+ s = mCentral_CacheSpan(&mheap_.central[sizeclass].mcentral)
+ if s == nil {
+ gothrow("out of memory")
+ }
+ if s.freelist == nil {
+ println(s.ref, (s.npages<<_PageShift)/s.elemsize)
+ gothrow("empty span")
+ }
+ c.alloc[sizeclass] = s
+ _g_.m.locks--
+ return s
+}
+
+func mCache_ReleaseAll(c *mcache) {
+ for i := 0; i < _NumSizeClasses; i++ {
+ s := c.alloc[i]
+ if s != &emptymspan {
+ mCentral_UncacheSpan(&mheap_.central[i].mcentral, s)
+ c.alloc[i] = &emptymspan
+ }
+ }
+}
diff --git a/src/runtime/mcentral.c b/src/runtime/mcentral.c
deleted file mode 100644
index fe6bcfeb1..000000000
--- a/src/runtime/mcentral.c
+++ /dev/null
@@ -1,214 +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.
-
-// Central free lists.
-//
-// See malloc.h for an overview.
-//
-// The MCentral doesn't actually contain the list of free objects; the MSpan does.
-// Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
-// and those that are completely allocated (c->empty).
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-static MSpan* MCentral_Grow(MCentral *c);
-
-// Initialize a single central free list.
-void
-runtime·MCentral_Init(MCentral *c, int32 sizeclass)
-{
- c->sizeclass = sizeclass;
- runtime·MSpanList_Init(&c->nonempty);
- runtime·MSpanList_Init(&c->empty);
-}
-
-// Allocate a span to use in an MCache.
-MSpan*
-runtime·MCentral_CacheSpan(MCentral *c)
-{
- MSpan *s;
- int32 cap, n;
- uint32 sg;
-
- runtime·lock(&c->lock);
- sg = runtime·mheap.sweepgen;
-retry:
- for(s = c->nonempty.next; s != &c->nonempty; s = s->next) {
- if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
- runtime·MSpanList_Remove(s);
- runtime·MSpanList_InsertBack(&c->empty, s);
- runtime·unlock(&c->lock);
- runtime·MSpan_Sweep(s, true);
- goto havespan;
- }
- if(s->sweepgen == sg-1) {
- // the span is being swept by background sweeper, skip
- continue;
- }
- // we have a nonempty span that does not require sweeping, allocate from it
- runtime·MSpanList_Remove(s);
- runtime·MSpanList_InsertBack(&c->empty, s);
- runtime·unlock(&c->lock);
- goto havespan;
- }
-
- for(s = c->empty.next; s != &c->empty; s = s->next) {
- if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
- // we have an empty span that requires sweeping,
- // sweep it and see if we can free some space in it
- runtime·MSpanList_Remove(s);
- // swept spans are at the end of the list
- runtime·MSpanList_InsertBack(&c->empty, s);
- runtime·unlock(&c->lock);
- runtime·MSpan_Sweep(s, true);
- if(s->freelist != nil)
- goto havespan;
- runtime·lock(&c->lock);
- // the span is still empty after sweep
- // it is already in the empty list, so just retry
- goto retry;
- }
- if(s->sweepgen == sg-1) {
- // the span is being swept by background sweeper, skip
- continue;
- }
- // already swept empty span,
- // all subsequent ones must also be either swept or in process of sweeping
- break;
- }
- runtime·unlock(&c->lock);
-
- // Replenish central list if empty.
- s = MCentral_Grow(c);
- if(s == nil)
- return nil;
- runtime·lock(&c->lock);
- runtime·MSpanList_InsertBack(&c->empty, s);
- runtime·unlock(&c->lock);
-
-havespan:
- // At this point s is a non-empty span, queued at the end of the empty list,
- // c is unlocked.
- cap = (s->npages << PageShift) / s->elemsize;
- n = cap - s->ref;
- if(n == 0)
- runtime·throw("empty span");
- if(s->freelist == nil)
- runtime·throw("freelist empty");
- s->incache = true;
- return s;
-}
-
-// Return span from an MCache.
-void
-runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s)
-{
- int32 cap, n;
-
- runtime·lock(&c->lock);
-
- s->incache = false;
-
- if(s->ref == 0)
- runtime·throw("uncaching full span");
-
- cap = (s->npages << PageShift) / s->elemsize;
- n = cap - s->ref;
- if(n > 0) {
- runtime·MSpanList_Remove(s);
- runtime·MSpanList_Insert(&c->nonempty, s);
- }
- runtime·unlock(&c->lock);
-}
-
-// Free n objects from a span s back into the central free list c.
-// Called during sweep.
-// Returns true if the span was returned to heap. Sets sweepgen to
-// the latest generation.
-// If preserve=true, don't return the span to heap nor relink in MCentral lists;
-// caller takes care of it.
-bool
-runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end, bool preserve)
-{
- bool wasempty;
-
- if(s->incache)
- runtime·throw("freespan into cached span");
-
- // Add the objects back to s's free list.
- wasempty = s->freelist == nil;
- end->next = s->freelist;
- s->freelist = start;
- s->ref -= n;
-
- if(preserve) {
- // preserve is set only when called from MCentral_CacheSpan above,
- // the span must be in the empty list.
- if(s->next == nil)
- runtime·throw("can't preserve unlinked span");
- runtime·atomicstore(&s->sweepgen, runtime·mheap.sweepgen);
- return false;
- }
-
- runtime·lock(&c->lock);
-
- // Move to nonempty if necessary.
- if(wasempty) {
- runtime·MSpanList_Remove(s);
- runtime·MSpanList_Insert(&c->nonempty, s);
- }
-
- // delay updating sweepgen until here. This is the signal that
- // the span may be used in an MCache, so it must come after the
- // linked list operations above (actually, just after the
- // lock of c above.)
- runtime·atomicstore(&s->sweepgen, runtime·mheap.sweepgen);
-
- if(s->ref != 0) {
- runtime·unlock(&c->lock);
- return false;
- }
-
- // s is completely freed, return it to the heap.
- runtime·MSpanList_Remove(s);
- s->needzero = 1;
- s->freelist = nil;
- runtime·unlock(&c->lock);
- runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
- runtime·MHeap_Free(&runtime·mheap, s, 0);
- return true;
-}
-
-// Fetch a new span from the heap and carve into objects for the free list.
-static MSpan*
-MCentral_Grow(MCentral *c)
-{
- uintptr size, npages, i, n;
- MLink **tailp, *v;
- byte *p;
- MSpan *s;
-
- npages = runtime·class_to_allocnpages[c->sizeclass];
- size = runtime·class_to_size[c->sizeclass];
- n = (npages << PageShift) / size;
- s = runtime·MHeap_Alloc(&runtime·mheap, npages, c->sizeclass, 0, 1);
- if(s == nil)
- return nil;
-
- // Carve span into sequence of blocks.
- tailp = &s->freelist;
- p = (byte*)(s->start << PageShift);
- s->limit = p + size*n;
- for(i=0; i<n; i++) {
- v = (MLink*)p;
- *tailp = v;
- tailp = &v->next;
- p += size;
- }
- *tailp = nil;
- runtime·markspan((byte*)(s->start<<PageShift), size, n, size*n < (s->npages<<PageShift));
- return s;
-}
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go
new file mode 100644
index 000000000..0d172a08b
--- /dev/null
+++ b/src/runtime/mcentral.go
@@ -0,0 +1,199 @@
+// 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.
+
+// Central free lists.
+//
+// See malloc.h for an overview.
+//
+// The MCentral doesn't actually contain the list of free objects; the MSpan does.
+// Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
+// and those that are completely allocated (c->empty).
+
+package runtime
+
+import "unsafe"
+
+// Initialize a single central free list.
+func mCentral_Init(c *mcentral, sizeclass int32) {
+ c.sizeclass = sizeclass
+ mSpanList_Init(&c.nonempty)
+ mSpanList_Init(&c.empty)
+}
+
+// Allocate a span to use in an MCache.
+func mCentral_CacheSpan(c *mcentral) *mspan {
+ lock(&c.lock)
+ sg := mheap_.sweepgen
+retry:
+ var s *mspan
+ for s = c.nonempty.next; s != &c.nonempty; s = s.next {
+ if s.sweepgen == sg-2 && cas(&s.sweepgen, sg-2, sg-1) {
+ mSpanList_Remove(s)
+ mSpanList_InsertBack(&c.empty, s)
+ unlock(&c.lock)
+ mSpan_Sweep(s, true)
+ goto havespan
+ }
+ if s.sweepgen == sg-1 {
+ // the span is being swept by background sweeper, skip
+ continue
+ }
+ // we have a nonempty span that does not require sweeping, allocate from it
+ mSpanList_Remove(s)
+ mSpanList_InsertBack(&c.empty, s)
+ unlock(&c.lock)
+ goto havespan
+ }
+
+ for s = c.empty.next; s != &c.empty; s = s.next {
+ if s.sweepgen == sg-2 && cas(&s.sweepgen, sg-2, sg-1) {
+ // we have an empty span that requires sweeping,
+ // sweep it and see if we can free some space in it
+ mSpanList_Remove(s)
+ // swept spans are at the end of the list
+ mSpanList_InsertBack(&c.empty, s)
+ unlock(&c.lock)
+ mSpan_Sweep(s, true)
+ if s.freelist != nil {
+ goto havespan
+ }
+ lock(&c.lock)
+ // the span is still empty after sweep
+ // it is already in the empty list, so just retry
+ goto retry
+ }
+ if s.sweepgen == sg-1 {
+ // the span is being swept by background sweeper, skip
+ continue
+ }
+ // already swept empty span,
+ // all subsequent ones must also be either swept or in process of sweeping
+ break
+ }
+ unlock(&c.lock)
+
+ // Replenish central list if empty.
+ s = mCentral_Grow(c)
+ if s == nil {
+ return nil
+ }
+ lock(&c.lock)
+ mSpanList_InsertBack(&c.empty, s)
+ unlock(&c.lock)
+
+ // At this point s is a non-empty span, queued at the end of the empty list,
+ // c is unlocked.
+havespan:
+ cap := int32((s.npages << _PageShift) / s.elemsize)
+ n := cap - int32(s.ref)
+ if n == 0 {
+ gothrow("empty span")
+ }
+ if s.freelist == nil {
+ gothrow("freelist empty")
+ }
+ s.incache = true
+ return s
+}
+
+// Return span from an MCache.
+func mCentral_UncacheSpan(c *mcentral, s *mspan) {
+ lock(&c.lock)
+
+ s.incache = false
+
+ if s.ref == 0 {
+ gothrow("uncaching full span")
+ }
+
+ cap := int32((s.npages << _PageShift) / s.elemsize)
+ n := cap - int32(s.ref)
+ if n > 0 {
+ mSpanList_Remove(s)
+ mSpanList_Insert(&c.nonempty, s)
+ }
+ unlock(&c.lock)
+}
+
+// Free n objects from a span s back into the central free list c.
+// Called during sweep.
+// Returns true if the span was returned to heap. Sets sweepgen to
+// the latest generation.
+// If preserve=true, don't return the span to heap nor relink in MCentral lists;
+// caller takes care of it.
+func mCentral_FreeSpan(c *mcentral, s *mspan, n int32, start *mlink, end *mlink, preserve bool) bool {
+ if s.incache {
+ gothrow("freespan into cached span")
+ }
+
+ // Add the objects back to s's free list.
+ wasempty := s.freelist == nil
+ end.next = s.freelist
+ s.freelist = start
+ s.ref -= uint16(n)
+
+ if preserve {
+ // preserve is set only when called from MCentral_CacheSpan above,
+ // the span must be in the empty list.
+ if s.next == nil {
+ gothrow("can't preserve unlinked span")
+ }
+ atomicstore(&s.sweepgen, mheap_.sweepgen)
+ return false
+ }
+
+ lock(&c.lock)
+
+ // Move to nonempty if necessary.
+ if wasempty {
+ mSpanList_Remove(s)
+ mSpanList_Insert(&c.nonempty, s)
+ }
+
+ // delay updating sweepgen until here. This is the signal that
+ // the span may be used in an MCache, so it must come after the
+ // linked list operations above (actually, just after the
+ // lock of c above.)
+ atomicstore(&s.sweepgen, mheap_.sweepgen)
+
+ if s.ref != 0 {
+ unlock(&c.lock)
+ return false
+ }
+
+ // s is completely freed, return it to the heap.
+ mSpanList_Remove(s)
+ s.needzero = 1
+ s.freelist = nil
+ unlock(&c.lock)
+ unmarkspan(uintptr(s.start)<<_PageShift, s.npages<<_PageShift)
+ mHeap_Free(&mheap_, s, 0)
+ return true
+}
+
+// Fetch a new span from the heap and carve into objects for the free list.
+func mCentral_Grow(c *mcentral) *mspan {
+ npages := uintptr(class_to_allocnpages[c.sizeclass])
+ size := uintptr(class_to_size[c.sizeclass])
+ n := (npages << _PageShift) / size
+
+ s := mHeap_Alloc(&mheap_, npages, c.sizeclass, false, true)
+ if s == nil {
+ return nil
+ }
+
+ // Carve span into sequence of blocks.
+ tailp := &s.freelist
+ p := uintptr(s.start << _PageShift)
+ s.limit = p + size*n
+ for i := uintptr(0); i < n; i++ {
+ v := (*mlink)(unsafe.Pointer(p))
+ *tailp = v
+ tailp = &v.next
+ p += size
+ }
+ *tailp = nil
+ markspan(unsafe.Pointer(uintptr(s.start)<<_PageShift), size, n, size*n < s.npages<<_PageShift)
+ return s
+}
diff --git a/src/runtime/mem.go b/src/runtime/mem.go
index e6f1eb0e6..183567251 100644
--- a/src/runtime/mem.go
+++ b/src/runtime/mem.go
@@ -59,7 +59,11 @@ type MemStats struct {
}
}
-var sizeof_C_MStats uintptr // filled in by malloc.goc
+// Size of the trailing by_size array differs between Go and C,
+// and all data after by_size is local to runtime, not exported.
+// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+// sizeof_C_MStats is what C thinks about size of Go struct.
+var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0])
func init() {
var memStats MemStats
@@ -78,15 +82,16 @@ func ReadMemStats(m *MemStats) {
semacquire(&worldsema, false)
gp := getg()
gp.m.gcing = 1
- onM(stoptheworld)
+ systemstack(stoptheworld)
- gp.m.ptrarg[0] = noescape(unsafe.Pointer(m))
- onM(readmemstats_m)
+ systemstack(func() {
+ readmemstats_m(m)
+ })
gp.m.gcing = 0
gp.m.locks++
semrelease(&worldsema)
- onM(starttheworld)
+ systemstack(starttheworld)
gp.m.locks--
}
@@ -95,14 +100,15 @@ func writeHeapDump(fd uintptr) {
semacquire(&worldsema, false)
gp := getg()
gp.m.gcing = 1
- onM(stoptheworld)
+ systemstack(stoptheworld)
- gp.m.scalararg[0] = fd
- onM(writeheapdump_m)
+ systemstack(func() {
+ writeheapdump_m(fd)
+ })
gp.m.gcing = 0
gp.m.locks++
semrelease(&worldsema)
- onM(starttheworld)
+ systemstack(starttheworld)
gp.m.locks--
}
diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go
new file mode 100644
index 000000000..e9be5ec8c
--- /dev/null
+++ b/src/runtime/mem_bsd.go
@@ -0,0 +1,88 @@
+// Copyright 2010 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.
+
+// +build dragonfly freebsd nacl netbsd openbsd solaris
+
+package runtime
+
+import "unsafe"
+
+//go:nosplit
+func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
+ v := unsafe.Pointer(mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
+ if uintptr(v) < 4096 {
+ return nil
+ }
+ xadd64(stat, int64(n))
+ return v
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+ madvise(v, n, _MADV_FREE)
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+}
+
+func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
+ xadd64(stat, -int64(n))
+ munmap(v, n)
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+ mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE|_MAP_FIXED, -1, 0)
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
+ // On 64-bit, people with ulimit -v set complain if we reserve too
+ // much address space. Instead, assume that the reservation is okay
+ // and check the assumption in SysMap.
+ if ptrSize == 8 && uint64(n) > 1<<32 || goos_nacl != 0 {
+ *reserved = false
+ return v
+ }
+
+ p := unsafe.Pointer(mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
+ if uintptr(p) < 4096 {
+ return nil
+ }
+ *reserved = true
+ return p
+}
+
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
+ const _ENOMEM = 12
+
+ xadd64(stat, int64(n))
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if !reserved {
+ flags := int32(_MAP_ANON | _MAP_PRIVATE)
+ if GOOS == "dragonfly" {
+ // TODO(jsing): For some reason DragonFly seems to return
+ // memory at a different address than we requested, even when
+ // there should be no reason for it to do so. This can be
+ // avoided by using MAP_FIXED, but I'm not sure we should need
+ // to do this - we do not on other platforms.
+ flags |= _MAP_FIXED
+ }
+ p := mmap(v, n, _PROT_READ|_PROT_WRITE, flags, -1, 0)
+ if uintptr(p) == _ENOMEM {
+ gothrow("runtime: out of memory")
+ }
+ if p != v {
+ print("runtime: address space conflict: map(", v, ") = ", p, "\n")
+ gothrow("runtime: address space conflict")
+ }
+ return
+ }
+
+ p := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0)
+ if uintptr(p) == _ENOMEM {
+ gothrow("runtime: out of memory")
+ }
+ if p != v {
+ gothrow("runtime: cannot map pages in arena address space")
+ }
+}
diff --git a/src/runtime/mem_darwin.c b/src/runtime/mem_darwin.c
deleted file mode 100644
index bf3ede577..000000000
--- a/src/runtime/mem_darwin.c
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
- void *v;
-
- v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(v < (void*)4096)
- return nil;
- runtime·xadd64(stat, n);
- return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
- // Linux's MADV_DONTNEED is like BSD's MADV_FREE.
- runtime·madvise(v, n, MADV_FREE);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
- USED(v);
- USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
- runtime·xadd64(stat, -(uint64)n);
- runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
- runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
- void *p;
-
- *reserved = true;
- p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p < (void*)4096)
- return nil;
- return p;
-}
-
-enum
-{
- ENOMEM = 12,
-};
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
- void *p;
-
- USED(reserved);
-
- runtime·xadd64(stat, n);
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v)
- runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_darwin.go b/src/runtime/mem_darwin.go
new file mode 100644
index 000000000..1bee933d0
--- /dev/null
+++ b/src/runtime/mem_darwin.go
@@ -0,0 +1,58 @@
+// Copyright 2010 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 runtime
+
+import "unsafe"
+
+//go:nosplit
+func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
+ v := (unsafe.Pointer)(mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
+ if uintptr(v) < 4096 {
+ return nil
+ }
+ xadd64(stat, int64(n))
+ return v
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+ // Linux's MADV_DONTNEED is like BSD's MADV_FREE.
+ madvise(v, n, _MADV_FREE)
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+}
+
+func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
+ xadd64(stat, -int64(n))
+ munmap(v, n)
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+ mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE|_MAP_FIXED, -1, 0)
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
+ *reserved = true
+ p := (unsafe.Pointer)(mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
+ if uintptr(p) < 4096 {
+ return nil
+ }
+ return p
+}
+
+const (
+ _ENOMEM = 12
+)
+
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
+ xadd64(stat, int64(n))
+ p := (unsafe.Pointer)(mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0))
+ if uintptr(p) == _ENOMEM {
+ gothrow("runtime: out of memory")
+ }
+ if p != v {
+ gothrow("runtime: cannot map pages in arena address space")
+ }
+}
diff --git a/src/runtime/mem_dragonfly.c b/src/runtime/mem_dragonfly.c
deleted file mode 100644
index 11457b2c0..000000000
--- a/src/runtime/mem_dragonfly.c
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
- ENOMEM = 12,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
- void *v;
-
- v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(v < (void*)4096)
- return nil;
- runtime·xadd64(stat, n);
- return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
- runtime·madvise(v, n, MADV_FREE);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
- USED(v);
- USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
- runtime·xadd64(stat, -(uint64)n);
- runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
- runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
- void *p;
-
- // On 64-bit, people with ulimit -v set complain if we reserve too
- // much address space. Instead, assume that the reservation is okay
- // and check the assumption in SysMap.
- if(sizeof(void*) == 8 && n > 1LL<<32) {
- *reserved = false;
- return v;
- }
-
- *reserved = true;
- p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p < (void*)4096)
- return nil;
- return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
- void *p;
-
- runtime·xadd64(stat, n);
-
- // On 64-bit, we don't actually have v reserved, so tread carefully.
- if(!reserved) {
- // TODO(jsing): For some reason DragonFly seems to return
- // memory at a different address than we requested, even when
- // there should be no reason for it to do so. This can be
- // avoided by using MAP_FIXED, but I'm not sure we should need
- // to do this - we do not on other platforms.
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v) {
- runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
- runtime·throw("runtime: address space conflict");
- }
- return;
- }
-
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v)
- runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_freebsd.c b/src/runtime/mem_freebsd.c
deleted file mode 100644
index 18a9a2f5b..000000000
--- a/src/runtime/mem_freebsd.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
- ENOMEM = 12,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
- void *v;
-
- v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(v < (void*)4096)
- return nil;
- runtime·xadd64(stat, n);
- return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
- runtime·madvise(v, n, MADV_FREE);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
- USED(v);
- USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
- runtime·xadd64(stat, -(uint64)n);
- runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
- runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
- void *p;
-
- // On 64-bit, people with ulimit -v set complain if we reserve too
- // much address space. Instead, assume that the reservation is okay
- // and check the assumption in SysMap.
- if(sizeof(void*) == 8 && n > 1LL<<32) {
- *reserved = false;
- return v;
- }
-
- *reserved = true;
- p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p < (void*)4096)
- return nil;
- return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
- void *p;
-
- runtime·xadd64(stat, n);
-
- // On 64-bit, we don't actually have v reserved, so tread carefully.
- if(!reserved) {
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v) {
- runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
- runtime·throw("runtime: address space conflict");
- }
- return;
- }
-
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v)
- runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_linux.c b/src/runtime/mem_linux.c
deleted file mode 100644
index bfb405607..000000000
--- a/src/runtime/mem_linux.c
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
- _PAGE_SIZE = 4096,
- EACCES = 13,
-};
-
-static int32
-addrspace_free(void *v, uintptr n)
-{
- int32 errval;
- uintptr chunk;
- uintptr off;
-
- // NOTE: vec must be just 1 byte long here.
- // Mincore returns ENOMEM if any of the pages are unmapped,
- // but we want to know that all of the pages are unmapped.
- // To make these the same, we can only ask about one page
- // at a time. See golang.org/issue/7476.
- static byte vec[1];
-
- for(off = 0; off < n; off += chunk) {
- chunk = _PAGE_SIZE * sizeof vec;
- if(chunk > (n - off))
- chunk = n - off;
- errval = runtime·mincore((int8*)v + off, chunk, vec);
- // ENOMEM means unmapped, which is what we want.
- // Anything else we assume means the pages are mapped.
- if (errval != -ENOMEM)
- return 0;
- }
- return 1;
-}
-
-static void *
-mmap_fixed(byte *v, uintptr n, int32 prot, int32 flags, int32 fd, uint32 offset)
-{
- void *p;
-
- p = runtime·mmap(v, n, prot, flags, fd, offset);
- if(p != v && addrspace_free(v, n)) {
- // On some systems, mmap ignores v without
- // MAP_FIXED, so retry if the address space is free.
- if(p > (void*)4096)
- runtime·munmap(p, n);
- p = runtime·mmap(v, n, prot, flags|MAP_FIXED, fd, offset);
- }
- return p;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
- void *p;
-
- p = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p < (void*)4096) {
- if(p == (void*)EACCES) {
- runtime·printf("runtime: mmap: access denied\n");
- runtime·printf("if you're running SELinux, enable execmem for this process.\n");
- runtime·exit(2);
- }
- if(p == (void*)EAGAIN) {
- runtime·printf("runtime: mmap: too much locked memory (check 'ulimit -l').\n");
- runtime·exit(2);
- }
- return nil;
- }
- runtime·xadd64(stat, n);
- return p;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
- runtime·madvise(v, n, MADV_DONTNEED);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
- USED(v);
- USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
- runtime·xadd64(stat, -(uint64)n);
- runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
- runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
- void *p;
-
- // On 64-bit, people with ulimit -v set complain if we reserve too
- // much address space. Instead, assume that the reservation is okay
- // if we can reserve at least 64K and check the assumption in SysMap.
- // Only user-mode Linux (UML) rejects these requests.
- if(sizeof(void*) == 8 && n > 1LL<<32) {
- p = mmap_fixed(v, 64<<10, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if (p != v) {
- if(p >= (void*)4096)
- runtime·munmap(p, 64<<10);
- return nil;
- }
- runtime·munmap(p, 64<<10);
- *reserved = false;
- return v;
- }
-
- p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if((uintptr)p < 4096)
- return nil;
- *reserved = true;
- return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
- void *p;
-
- runtime·xadd64(stat, n);
-
- // On 64-bit, we don't actually have v reserved, so tread carefully.
- if(!reserved) {
- p = mmap_fixed(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v) {
- runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
- runtime·throw("runtime: address space conflict");
- }
- return;
- }
-
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v)
- runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_linux.go b/src/runtime/mem_linux.go
new file mode 100644
index 000000000..85b55ef49
--- /dev/null
+++ b/src/runtime/mem_linux.go
@@ -0,0 +1,135 @@
+// Copyright 2010 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 runtime
+
+import "unsafe"
+
+const (
+ _PAGE_SIZE = _PhysPageSize
+ _EACCES = 13
+)
+
+// NOTE: vec must be just 1 byte long here.
+// Mincore returns ENOMEM if any of the pages are unmapped,
+// but we want to know that all of the pages are unmapped.
+// To make these the same, we can only ask about one page
+// at a time. See golang.org/issue/7476.
+var addrspace_vec [1]byte
+
+func addrspace_free(v unsafe.Pointer, n uintptr) bool {
+ var chunk uintptr
+ for off := uintptr(0); off < n; off += chunk {
+ chunk = _PAGE_SIZE * uintptr(len(addrspace_vec))
+ if chunk > (n - off) {
+ chunk = n - off
+ }
+ errval := mincore(unsafe.Pointer(uintptr(v)+off), chunk, &addrspace_vec[0])
+ // ENOMEM means unmapped, which is what we want.
+ // Anything else we assume means the pages are mapped.
+ if errval != -_ENOMEM {
+ return false
+ }
+ }
+ return true
+}
+
+func mmap_fixed(v unsafe.Pointer, n uintptr, prot, flags, fd int32, offset uint32) unsafe.Pointer {
+ p := mmap(v, n, prot, flags, fd, offset)
+ // On some systems, mmap ignores v without
+ // MAP_FIXED, so retry if the address space is free.
+ if p != v && addrspace_free(v, n) {
+ if uintptr(p) > 4096 {
+ munmap(p, n)
+ }
+ p = mmap(v, n, prot, flags|_MAP_FIXED, fd, offset)
+ }
+ return p
+}
+
+//go:nosplit
+func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
+ p := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
+ if uintptr(p) < 4096 {
+ if uintptr(p) == _EACCES {
+ print("runtime: mmap: access denied\n")
+ print("if you're running SELinux, enable execmem for this process.\n")
+ exit(2)
+ }
+ if uintptr(p) == _EAGAIN {
+ print("runtime: mmap: too much locked memory (check 'ulimit -l').\n")
+ exit(2)
+ }
+ return nil
+ }
+ xadd64(stat, int64(n))
+ return p
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+ madvise(v, n, _MADV_DONTNEED)
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+}
+
+func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
+ xadd64(stat, -int64(n))
+ munmap(v, n)
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+ mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE|_MAP_FIXED, -1, 0)
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
+ // On 64-bit, people with ulimit -v set complain if we reserve too
+ // much address space. Instead, assume that the reservation is okay
+ // if we can reserve at least 64K and check the assumption in SysMap.
+ // Only user-mode Linux (UML) rejects these requests.
+ if ptrSize == 7 && uint64(n) > 1<<32 {
+ p := mmap_fixed(v, 64<<10, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
+ if p != v {
+ if uintptr(p) >= 4096 {
+ munmap(p, 64<<10)
+ }
+ return nil
+ }
+ munmap(p, 64<<10)
+ *reserved = false
+ return v
+ }
+
+ p := mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
+ if uintptr(p) < 4096 {
+ return nil
+ }
+ *reserved = true
+ return p
+}
+
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
+ xadd64(stat, int64(n))
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if !reserved {
+ p := mmap_fixed(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
+ if uintptr(p) == _ENOMEM {
+ gothrow("runtime: out of memory")
+ }
+ if p != v {
+ print("runtime: address space conflict: map(", v, ") = ", p, "\n")
+ gothrow("runtime: address space conflict")
+ }
+ return
+ }
+
+ p := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0)
+ if uintptr(p) == _ENOMEM {
+ gothrow("runtime: out of memory")
+ }
+ if p != v {
+ gothrow("runtime: cannot map pages in arena address space")
+ }
+}
diff --git a/src/runtime/mem_nacl.c b/src/runtime/mem_nacl.c
deleted file mode 100644
index 6c836f18a..000000000
--- a/src/runtime/mem_nacl.c
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
- Debug = 0,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
- void *v;
-
- v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(v < (void*)4096) {
- if(Debug)
- runtime·printf("sysAlloc(%p): %p\n", n, v);
- return nil;
- }
- runtime·xadd64(stat, n);
- if(Debug)
- runtime·printf("sysAlloc(%p) = %p\n", n, v);
- return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
- if(Debug)
- runtime·printf("SysUnused(%p, %p)\n", v, n);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
- USED(v);
- USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
- if(Debug)
- runtime·printf("SysFree(%p, %p)\n", v, n);
- runtime·xadd64(stat, -(uint64)n);
- runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
- runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
- void *p;
-
- // On 64-bit, people with ulimit -v set complain if we reserve too
- // much address space. Instead, assume that the reservation is okay
- // and check the assumption in SysMap.
- if(NaCl || sizeof(void*) == 8) {
- *reserved = false;
- return v;
- }
-
- p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p < (void*)4096)
- return nil;
- *reserved = true;
- return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
- void *p;
-
- runtime·xadd64(stat, n);
-
- // On 64-bit, we don't actually have v reserved, so tread carefully.
- if(!reserved) {
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM) {
- runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
- runtime·throw("runtime: out of memory");
- }
- if(p != v) {
- runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
- runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
- runtime·throw("runtime: address space conflict");
- }
- if(Debug)
- runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
- return;
- }
-
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM) {
- runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
- runtime·throw("runtime: out of memory");
- }
- if(p != v) {
- runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
- runtime·printf("mmap MAP_FIXED %p returned %p\n", v, p);
- runtime·throw("runtime: cannot map pages in arena address space");
- }
- if(Debug)
- runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
-}
diff --git a/src/runtime/mem_netbsd.c b/src/runtime/mem_netbsd.c
deleted file mode 100644
index 31820e517..000000000
--- a/src/runtime/mem_netbsd.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
- ENOMEM = 12,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
- void *v;
-
- v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(v < (void*)4096)
- return nil;
- runtime·xadd64(stat, n);
- return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
- runtime·madvise(v, n, MADV_FREE);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
- USED(v);
- USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
- runtime·xadd64(stat, -(uint64)n);
- runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
- runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
- void *p;
-
- // On 64-bit, people with ulimit -v set complain if we reserve too
- // much address space. Instead, assume that the reservation is okay
- // and check the assumption in SysMap.
- if(sizeof(void*) == 8 && n > 1LL<<32) {
- *reserved = false;
- return v;
- }
-
- p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p < (void*)4096)
- return nil;
- *reserved = true;
- return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
- void *p;
-
- runtime·xadd64(stat, n);
-
- // On 64-bit, we don't actually have v reserved, so tread carefully.
- if(!reserved) {
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v) {
- runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
- runtime·throw("runtime: address space conflict");
- }
- return;
- }
-
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v)
- runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_openbsd.c b/src/runtime/mem_openbsd.c
deleted file mode 100644
index 31820e517..000000000
--- a/src/runtime/mem_openbsd.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
- ENOMEM = 12,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
- void *v;
-
- v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(v < (void*)4096)
- return nil;
- runtime·xadd64(stat, n);
- return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
- runtime·madvise(v, n, MADV_FREE);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
- USED(v);
- USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
- runtime·xadd64(stat, -(uint64)n);
- runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
- runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
- void *p;
-
- // On 64-bit, people with ulimit -v set complain if we reserve too
- // much address space. Instead, assume that the reservation is okay
- // and check the assumption in SysMap.
- if(sizeof(void*) == 8 && n > 1LL<<32) {
- *reserved = false;
- return v;
- }
-
- p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p < (void*)4096)
- return nil;
- *reserved = true;
- return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
- void *p;
-
- runtime·xadd64(stat, n);
-
- // On 64-bit, we don't actually have v reserved, so tread carefully.
- if(!reserved) {
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v) {
- runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
- runtime·throw("runtime: address space conflict");
- }
- return;
- }
-
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v)
- runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_plan9.c b/src/runtime/mem_plan9.c
deleted file mode 100644
index d673d6f83..000000000
--- a/src/runtime/mem_plan9.c
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "os_GOOS.h"
-#include "textflag.h"
-
-extern byte runtime·end[];
-#pragma dataflag NOPTR
-static byte *bloc = { runtime·end };
-static Mutex memlock;
-
-enum
-{
- Round = PAGESIZE-1
-};
-
-static void*
-brk(uintptr nbytes)
-{
- uintptr bl;
-
- runtime·lock(&memlock);
- // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
- bl = ((uintptr)bloc + Round) & ~Round;
- if(runtime·brk_((void*)(bl + nbytes)) < 0) {
- runtime·unlock(&memlock);
- return nil;
- }
- bloc = (byte*)bl + nbytes;
- runtime·unlock(&memlock);
- return (void*)bl;
-}
-
-static void
-sysalloc(void)
-{
- uintptr nbytes;
- uint64 *stat;
- void *p;
-
- nbytes = g->m->scalararg[0];
- stat = g->m->ptrarg[0];
- g->m->scalararg[0] = 0;
- g->m->ptrarg[0] = nil;
-
- p = brk(nbytes);
- if(p != nil)
- runtime·xadd64(stat, nbytes);
-
- g->m->ptrarg[0] = p;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr nbytes, uint64 *stat)
-{
- void (*fn)(void);
- void *p;
-
- g->m->scalararg[0] = nbytes;
- g->m->ptrarg[0] = stat;
- fn = sysalloc;
- runtime·onM(&fn);
- p = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- return p;
-}
-
-void
-runtime·SysFree(void *v, uintptr nbytes, uint64 *stat)
-{
- runtime·xadd64(stat, -(uint64)nbytes);
- runtime·lock(&memlock);
- // from tiny/mem.c
- // Push pointer back if this is a free
- // of the most recent sysAlloc.
- nbytes += (nbytes + Round) & ~Round;
- if(bloc == (byte*)v+nbytes)
- bloc -= nbytes;
- runtime·unlock(&memlock);
-}
-
-void
-runtime·SysUnused(void *v, uintptr nbytes)
-{
- USED(v, nbytes);
-}
-
-void
-runtime·SysUsed(void *v, uintptr nbytes)
-{
- USED(v, nbytes);
-}
-
-void
-runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat)
-{
- // SysReserve has already allocated all heap memory,
- // but has not adjusted stats.
- USED(v, reserved);
- runtime·xadd64(stat, nbytes);
-}
-
-void
-runtime·SysFault(void *v, uintptr nbytes)
-{
- USED(v, nbytes);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr nbytes, bool *reserved)
-{
- USED(v);
- *reserved = true;
- return brk(nbytes);
-}
diff --git a/src/runtime/mem_plan9.go b/src/runtime/mem_plan9.go
new file mode 100644
index 000000000..a5d7c1a4c
--- /dev/null
+++ b/src/runtime/mem_plan9.go
@@ -0,0 +1,70 @@
+// Copyright 2010 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 runtime
+
+import "unsafe"
+
+var bloc uintptr
+var memlock mutex
+
+const memRound = _PAGESIZE - 1
+
+func initBloc() {
+ bloc = 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
+ if brk_(unsafe.Pointer(bl+n)) < 0 {
+ unlock(&memlock)
+ return nil
+ }
+ bloc = bl + n
+ unlock(&memlock)
+ return unsafe.Pointer(bl)
+}
+
+func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
+ p := sbrk(n)
+ if p != nil {
+ xadd64(stat, int64(n))
+ }
+ return p
+}
+
+func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
+ xadd64(stat, -int64(n))
+ lock(&memlock)
+ // from tiny/mem.c
+ // Push pointer back if this is a free
+ // of the most recent sysAlloc.
+ n += (n + memRound) &^ memRound
+ if bloc == uintptr(v)+n {
+ bloc -= n
+ }
+ unlock(&memlock)
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+}
+
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
+ // sysReserve has already allocated all heap memory,
+ // but has not adjusted stats.
+ xadd64(stat, int64(n))
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
+ *reserved = true
+ return sbrk(n)
+}
diff --git a/src/runtime/mem_solaris.c b/src/runtime/mem_solaris.c
deleted file mode 100644
index 8e90ba1d9..000000000
--- a/src/runtime/mem_solaris.c
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
- ENOMEM = 12,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
- void *v;
-
- v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(v < (void*)4096)
- return nil;
- runtime·xadd64(stat, n);
- return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
- USED(v);
- USED(n);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
- USED(v);
- USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
- runtime·xadd64(stat, -(uint64)n);
- runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
- runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
- void *p;
-
- // On 64-bit, people with ulimit -v set complain if we reserve too
- // much address space. Instead, assume that the reservation is okay
- // and check the assumption in SysMap.
- if(sizeof(void*) == 8 && n > 1LL<<32) {
- *reserved = false;
- return v;
- }
-
- p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p < (void*)4096)
- return nil;
- *reserved = true;
- return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
- void *p;
-
- runtime·xadd64(stat, n);
-
- // On 64-bit, we don't actually have v reserved, so tread carefully.
- if(!reserved) {
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v) {
- runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
- runtime·throw("runtime: address space conflict");
- }
- return;
- }
-
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
- runtime·throw("runtime: out of memory");
- if(p != v)
- runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_windows.c b/src/runtime/mem_windows.c
deleted file mode 100644
index 6ea992020..000000000
--- a/src/runtime/mem_windows.c
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "os_GOOS.h"
-#include "defs_GOOS_GOARCH.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum {
- MEM_COMMIT = 0x1000,
- MEM_RESERVE = 0x2000,
- MEM_DECOMMIT = 0x4000,
- MEM_RELEASE = 0x8000,
-
- PAGE_READWRITE = 0x0004,
- PAGE_NOACCESS = 0x0001,
-};
-
-#pragma dynimport runtime·VirtualAlloc VirtualAlloc "kernel32.dll"
-#pragma dynimport runtime·VirtualFree VirtualFree "kernel32.dll"
-#pragma dynimport runtime·VirtualProtect VirtualProtect "kernel32.dll"
-extern void *runtime·VirtualAlloc;
-extern void *runtime·VirtualFree;
-extern void *runtime·VirtualProtect;
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
- runtime·xadd64(stat, n);
- return runtime·stdcall4(runtime·VirtualAlloc, 0, n, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
- void *r;
- uintptr small;
-
- r = runtime·stdcall3(runtime·VirtualFree, (uintptr)v, n, MEM_DECOMMIT);
- if(r != nil)
- return;
-
- // Decommit failed. Usual reason is that we've merged memory from two different
- // VirtualAlloc calls, and Windows will only let each VirtualFree handle pages from
- // a single VirtualAlloc. It is okay to specify a subset of the pages from a single alloc,
- // just not pages from multiple allocs. This is a rare case, arising only when we're
- // trying to give memory back to the operating system, which happens on a time
- // scale of minutes. It doesn't have to be terribly fast. Instead of extra bookkeeping
- // on all our VirtualAlloc calls, try freeing successively smaller pieces until
- // we manage to free something, and then repeat. This ends up being O(n log n)
- // in the worst case, but that's fast enough.
- while(n > 0) {
- small = n;
- while(small >= 4096 && runtime·stdcall3(runtime·VirtualFree, (uintptr)v, small, MEM_DECOMMIT) == nil)
- small = (small / 2) & ~(4096-1);
- if(small < 4096)
- runtime·throw("runtime: failed to decommit pages");
- v = (byte*)v + small;
- n -= small;
- }
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
- void *r;
- uintptr small;
-
- r = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_COMMIT, PAGE_READWRITE);
- if(r != v)
- runtime·throw("runtime: failed to commit pages");
-
- // Commit failed. See SysUnused.
- while(n > 0) {
- small = n;
- while(small >= 4096 && runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, small, MEM_COMMIT, PAGE_READWRITE) == nil)
- small = (small / 2) & ~(4096-1);
- if(small < 4096)
- runtime·throw("runtime: failed to decommit pages");
- v = (byte*)v + small;
- n -= small;
- }
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
- uintptr r;
-
- runtime·xadd64(stat, -(uint64)n);
- r = (uintptr)runtime·stdcall3(runtime·VirtualFree, (uintptr)v, 0, MEM_RELEASE);
- if(r == 0)
- runtime·throw("runtime: failed to release pages");
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
- // SysUnused makes the memory inaccessible and prevents its reuse
- runtime·SysUnused(v, n);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
- *reserved = true;
- // v is just a hint.
- // First try at v.
- v = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_RESERVE, PAGE_READWRITE);
- if(v != nil)
- return v;
-
- // Next let the kernel choose the address.
- return runtime·stdcall4(runtime·VirtualAlloc, 0, n, MEM_RESERVE, PAGE_READWRITE);
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
- void *p;
-
- USED(reserved);
-
- runtime·xadd64(stat, n);
- p = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_COMMIT, PAGE_READWRITE);
- if(p != v)
- runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_windows.go b/src/runtime/mem_windows.go
new file mode 100644
index 000000000..a1dcad013
--- /dev/null
+++ b/src/runtime/mem_windows.go
@@ -0,0 +1,119 @@
+// Copyright 2010 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 runtime
+
+import (
+ "unsafe"
+)
+
+const (
+ _MEM_COMMIT = 0x1000
+ _MEM_RESERVE = 0x2000
+ _MEM_DECOMMIT = 0x4000
+ _MEM_RELEASE = 0x8000
+
+ _PAGE_READWRITE = 0x0004
+ _PAGE_NOACCESS = 0x0001
+)
+
+//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc "kernel32.dll"
+//go:cgo_import_dynamic runtime._VirtualFree VirtualFree "kernel32.dll"
+//go:cgo_import_dynamic runtime._VirtualProtect VirtualProtect "kernel32.dll"
+
+var (
+ _VirtualAlloc,
+ _VirtualFree,
+ _VirtualProtect stdFunction
+)
+
+//go:nosplit
+func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
+ xadd64(stat, int64(n))
+ return unsafe.Pointer(stdcall4(_VirtualAlloc, 0, n, _MEM_COMMIT|_MEM_RESERVE, _PAGE_READWRITE))
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+ r := stdcall3(_VirtualFree, uintptr(v), n, _MEM_DECOMMIT)
+ if r != 0 {
+ return
+ }
+
+ // Decommit failed. Usual reason is that we've merged memory from two different
+ // VirtualAlloc calls, and Windows will only let each VirtualFree handle pages from
+ // a single VirtualAlloc. It is okay to specify a subset of the pages from a single alloc,
+ // just not pages from multiple allocs. This is a rare case, arising only when we're
+ // trying to give memory back to the operating system, which happens on a time
+ // scale of minutes. It doesn't have to be terribly fast. Instead of extra bookkeeping
+ // on all our VirtualAlloc calls, try freeing successively smaller pieces until
+ // we manage to free something, and then repeat. This ends up being O(n log n)
+ // in the worst case, but that's fast enough.
+ for n > 0 {
+ small := n
+ for small >= 4096 && stdcall3(_VirtualFree, uintptr(v), small, _MEM_DECOMMIT) == 0 {
+ small /= 2
+ small &^= 4096 - 1
+ }
+ if small < 4096 {
+ gothrow("runtime: failed to decommit pages")
+ }
+ v = add(v, small)
+ n -= small
+ }
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+ r := stdcall4(_VirtualAlloc, uintptr(v), n, _MEM_COMMIT, _PAGE_READWRITE)
+ if r != uintptr(v) {
+ gothrow("runtime: failed to commit pages")
+ }
+
+ // Commit failed. See SysUnused.
+ for n > 0 {
+ small := n
+ for small >= 4096 && stdcall4(_VirtualAlloc, uintptr(v), small, _MEM_COMMIT, _PAGE_READWRITE) == 0 {
+ small /= 2
+ small &^= 4096 - 1
+ }
+ if small < 4096 {
+ gothrow("runtime: failed to decommit pages")
+ }
+ v = add(v, small)
+ n -= small
+ }
+}
+
+func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
+ xadd64(stat, -int64(n))
+ r := stdcall3(_VirtualFree, uintptr(v), 0, _MEM_RELEASE)
+ if r == 0 {
+ gothrow("runtime: failed to release pages")
+ }
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+ // SysUnused makes the memory inaccessible and prevents its reuse
+ sysUnused(v, n)
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
+ *reserved = true
+ // v is just a hint.
+ // First try at v.
+ v = unsafe.Pointer(stdcall4(_VirtualAlloc, uintptr(v), n, _MEM_RESERVE, _PAGE_READWRITE))
+ if v != nil {
+ return v
+ }
+
+ // Next let the kernel choose the address.
+ return unsafe.Pointer(stdcall4(_VirtualAlloc, 0, n, _MEM_RESERVE, _PAGE_READWRITE))
+}
+
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
+ xadd64(stat, int64(n))
+ p := stdcall4(_VirtualAlloc, uintptr(v), n, _MEM_COMMIT, _PAGE_READWRITE)
+ if p != uintptr(v) {
+ gothrow("runtime: cannot map pages in arena address space")
+ }
+}
diff --git a/src/runtime/memclr_386.s b/src/runtime/memclr_386.s
index 1520aea2e..3f20b69c8 100644
--- a/src/runtime/memclr_386.s
+++ b/src/runtime/memclr_386.s
@@ -15,31 +15,31 @@ TEXT runtime·memclr(SB), NOSPLIT, $0-8
XORL AX, AX
// MOVOU seems always faster than REP STOSL.
-clr_tail:
+tail:
TESTL BX, BX
- JEQ clr_0
+ JEQ _0
CMPL BX, $2
- JBE clr_1or2
+ JBE _1or2
CMPL BX, $4
- JBE clr_3or4
+ JBE _3or4
CMPL BX, $8
- JBE clr_5through8
+ JBE _5through8
CMPL BX, $16
- JBE clr_9through16
+ JBE _9through16
TESTL $0x4000000, runtime·cpuid_edx(SB) // check for sse2
JEQ nosse2
PXOR X0, X0
CMPL BX, $32
- JBE clr_17through32
+ JBE _17through32
CMPL BX, $64
- JBE clr_33through64
+ JBE _33through64
CMPL BX, $128
- JBE clr_65through128
+ JBE _65through128
CMPL BX, $256
- JBE clr_129through256
+ JBE _129through256
// TODO: use branch table and BSR to make this just a single dispatch
-clr_loop:
+loop:
MOVOU X0, 0(DI)
MOVOU X0, 16(DI)
MOVOU X0, 32(DI)
@@ -59,40 +59,40 @@ clr_loop:
SUBL $256, BX
ADDL $256, DI
CMPL BX, $256
- JAE clr_loop
- JMP clr_tail
+ JAE loop
+ JMP tail
-clr_1or2:
+_1or2:
MOVB AX, (DI)
MOVB AX, -1(DI)(BX*1)
RET
-clr_0:
+_0:
RET
-clr_3or4:
+_3or4:
MOVW AX, (DI)
MOVW AX, -2(DI)(BX*1)
RET
-clr_5through8:
+_5through8:
MOVL AX, (DI)
MOVL AX, -4(DI)(BX*1)
RET
-clr_9through16:
+_9through16:
MOVL AX, (DI)
MOVL AX, 4(DI)
MOVL AX, -8(DI)(BX*1)
MOVL AX, -4(DI)(BX*1)
RET
-clr_17through32:
+_17through32:
MOVOU X0, (DI)
MOVOU X0, -16(DI)(BX*1)
RET
-clr_33through64:
+_33through64:
MOVOU X0, (DI)
MOVOU X0, 16(DI)
MOVOU X0, -32(DI)(BX*1)
MOVOU X0, -16(DI)(BX*1)
RET
-clr_65through128:
+_65through128:
MOVOU X0, (DI)
MOVOU X0, 16(DI)
MOVOU X0, 32(DI)
@@ -102,7 +102,7 @@ clr_65through128:
MOVOU X0, -32(DI)(BX*1)
MOVOU X0, -16(DI)(BX*1)
RET
-clr_129through256:
+_129through256:
MOVOU X0, (DI)
MOVOU X0, 16(DI)
MOVOU X0, 32(DI)
@@ -126,5 +126,5 @@ nosse2:
REP
STOSL
ANDL $3, BX
- JNE clr_tail
+ JNE tail
RET
diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s
index 94a2c7f23..ec24f1db2 100644
--- a/src/runtime/memclr_amd64.s
+++ b/src/runtime/memclr_amd64.s
@@ -15,30 +15,30 @@ TEXT runtime·memclr(SB), NOSPLIT, $0-16
XORQ AX, AX
// MOVOU seems always faster than REP STOSQ.
-clr_tail:
+tail:
TESTQ BX, BX
- JEQ clr_0
+ JEQ _0
CMPQ BX, $2
- JBE clr_1or2
+ JBE _1or2
CMPQ BX, $4
- JBE clr_3or4
+ JBE _3or4
CMPQ BX, $8
- JBE clr_5through8
+ JBE _5through8
CMPQ BX, $16
- JBE clr_9through16
+ JBE _9through16
PXOR X0, X0
CMPQ BX, $32
- JBE clr_17through32
+ JBE _17through32
CMPQ BX, $64
- JBE clr_33through64
+ JBE _33through64
CMPQ BX, $128
- JBE clr_65through128
+ JBE _65through128
CMPQ BX, $256
- JBE clr_129through256
+ JBE _129through256
// TODO: use branch table and BSR to make this just a single dispatch
// TODO: for really big clears, use MOVNTDQ.
-clr_loop:
+loop:
MOVOU X0, 0(DI)
MOVOU X0, 16(DI)
MOVOU X0, 32(DI)
@@ -58,38 +58,38 @@ clr_loop:
SUBQ $256, BX
ADDQ $256, DI
CMPQ BX, $256
- JAE clr_loop
- JMP clr_tail
+ JAE loop
+ JMP tail
-clr_1or2:
+_1or2:
MOVB AX, (DI)
MOVB AX, -1(DI)(BX*1)
RET
-clr_0:
+_0:
RET
-clr_3or4:
+_3or4:
MOVW AX, (DI)
MOVW AX, -2(DI)(BX*1)
RET
-clr_5through8:
+_5through8:
MOVL AX, (DI)
MOVL AX, -4(DI)(BX*1)
RET
-clr_9through16:
+_9through16:
MOVQ AX, (DI)
MOVQ AX, -8(DI)(BX*1)
RET
-clr_17through32:
+_17through32:
MOVOU X0, (DI)
MOVOU X0, -16(DI)(BX*1)
RET
-clr_33through64:
+_33through64:
MOVOU X0, (DI)
MOVOU X0, 16(DI)
MOVOU X0, -32(DI)(BX*1)
MOVOU X0, -16(DI)(BX*1)
RET
-clr_65through128:
+_65through128:
MOVOU X0, (DI)
MOVOU X0, 16(DI)
MOVOU X0, 32(DI)
@@ -99,7 +99,7 @@ clr_65through128:
MOVOU X0, -32(DI)(BX*1)
MOVOU X0, -16(DI)(BX*1)
RET
-clr_129through256:
+_129through256:
MOVOU X0, (DI)
MOVOU X0, 16(DI)
MOVOU X0, 32(DI)
diff --git a/src/runtime/memclr_plan9_386.s b/src/runtime/memclr_plan9_386.s
index b4b671f77..50f327b4e 100644
--- a/src/runtime/memclr_plan9_386.s
+++ b/src/runtime/memclr_plan9_386.s
@@ -10,40 +10,40 @@ TEXT runtime·memclr(SB), NOSPLIT, $0-8
MOVL n+4(FP), BX
XORL AX, AX
-clr_tail:
+tail:
TESTL BX, BX
- JEQ clr_0
+ JEQ _0
CMPL BX, $2
- JBE clr_1or2
+ JBE _1or2
CMPL BX, $4
- JBE clr_3or4
+ JBE _3or4
CMPL BX, $8
- JBE clr_5through8
+ JBE _5through8
CMPL BX, $16
- JBE clr_9through16
+ JBE _9through16
MOVL BX, CX
SHRL $2, CX
REP
STOSL
ANDL $3, BX
- JNE clr_tail
+ JNE tail
RET
-clr_1or2:
+_1or2:
MOVB AX, (DI)
MOVB AX, -1(DI)(BX*1)
RET
-clr_0:
+_0:
RET
-clr_3or4:
+_3or4:
MOVW AX, (DI)
MOVW AX, -2(DI)(BX*1)
RET
-clr_5through8:
+_5through8:
MOVL AX, (DI)
MOVL AX, -4(DI)(BX*1)
RET
-clr_9through16:
+_9through16:
MOVL AX, (DI)
MOVL AX, 4(DI)
MOVL AX, -8(DI)(BX*1)
diff --git a/src/runtime/memclr_power64x.s b/src/runtime/memclr_power64x.s
new file mode 100644
index 000000000..dfad64b6f
--- /dev/null
+++ b/src/runtime/memclr_power64x.s
@@ -0,0 +1,20 @@
+// 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.
+
+// +build power64 power64le
+
+#include "textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB),NOSPLIT,$0-16
+ MOVD ptr+0(FP), R3
+ MOVD n+8(FP), R4
+ CMP R4, $0
+ BEQ done
+ SUB $1, R3
+ MOVD R4, CTR
+ MOVBU R0, 1(R3)
+ BC 25, 0, -1(PC) // bdnz+ $-4
+done:
+ RETURN
diff --git a/src/runtime/memmove_power64x.s b/src/runtime/memmove_power64x.s
new file mode 100644
index 000000000..2b04d8319
--- /dev/null
+++ b/src/runtime/memmove_power64x.s
@@ -0,0 +1,40 @@
+// 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.
+
+// +build power64 power64le
+
+#include "textflag.h"
+
+// void runtime·memmove(void*, void*, uintptr)
+TEXT runtime·memmove(SB), NOSPLIT, $-8-24
+ MOVD to+0(FP), R3
+ MOVD from+8(FP), R4
+ MOVD n+16(FP), R5
+ CMP R5, $0
+ BNE check
+ RETURN
+
+check:
+ CMP R3, R4
+ BGT backward
+
+ SUB $1, R3
+ ADD R3, R5
+ SUB $1, R4
+loop:
+ MOVBU 1(R4), R6
+ MOVBU R6, 1(R3)
+ CMP R3, R5
+ BNE loop
+ RETURN
+
+backward:
+ ADD R5, R4
+ ADD R3, R5
+loop1:
+ MOVBU -1(R4), R6
+ MOVBU R6, -1(R5)
+ CMP R3, R5
+ BNE loop1
+ RETURN
diff --git a/src/runtime/mfixalloc.c b/src/runtime/mfixalloc.c
deleted file mode 100644
index d670629da..000000000
--- a/src/runtime/mfixalloc.c
+++ /dev/null
@@ -1,64 +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.
-
-// Fixed-size object allocator. Returned memory is not zeroed.
-//
-// See malloc.h for overview.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-// Initialize f to allocate objects of the given size,
-// using the allocator to obtain chunks of memory.
-void
-runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void (*first)(void*, byte*), void *arg, uint64 *stat)
-{
- f->size = size;
- f->first = first;
- f->arg = arg;
- f->list = nil;
- f->chunk = nil;
- f->nchunk = 0;
- f->inuse = 0;
- f->stat = stat;
-}
-
-void*
-runtime·FixAlloc_Alloc(FixAlloc *f)
-{
- void *v;
-
- if(f->size == 0) {
- runtime·printf("runtime: use of FixAlloc_Alloc before FixAlloc_Init\n");
- runtime·throw("runtime: internal error");
- }
-
- if(f->list) {
- v = f->list;
- f->list = *(void**)f->list;
- f->inuse += f->size;
- return v;
- }
- if(f->nchunk < f->size) {
- f->chunk = runtime·persistentalloc(FixAllocChunk, 0, f->stat);
- f->nchunk = FixAllocChunk;
- }
- v = f->chunk;
- if(f->first)
- f->first(f->arg, v);
- f->chunk += f->size;
- f->nchunk -= f->size;
- f->inuse += f->size;
- return v;
-}
-
-void
-runtime·FixAlloc_Free(FixAlloc *f, void *p)
-{
- f->inuse -= f->size;
- *(void**)p = f->list;
- f->list = p;
-}
-
diff --git a/src/runtime/mfixalloc.go b/src/runtime/mfixalloc.go
new file mode 100644
index 000000000..b66a17e41
--- /dev/null
+++ b/src/runtime/mfixalloc.go
@@ -0,0 +1,59 @@
+// 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.
+
+// Fixed-size object allocator. Returned memory is not zeroed.
+//
+// See malloc.h for overview.
+
+package runtime
+
+import "unsafe"
+
+// Initialize f to allocate objects of the given size,
+// using the allocator to obtain chunks of memory.
+func fixAlloc_Init(f *fixalloc, size uintptr, first func(unsafe.Pointer, unsafe.Pointer), arg unsafe.Pointer, stat *uint64) {
+ f.size = size
+ f.first = *(*unsafe.Pointer)(unsafe.Pointer(&first))
+ f.arg = arg
+ f.list = nil
+ f.chunk = nil
+ f.nchunk = 0
+ f.inuse = 0
+ f.stat = stat
+}
+
+func fixAlloc_Alloc(f *fixalloc) unsafe.Pointer {
+ if f.size == 0 {
+ print("runtime: use of FixAlloc_Alloc before FixAlloc_Init\n")
+ gothrow("runtime: internal error")
+ }
+
+ if f.list != nil {
+ v := unsafe.Pointer(f.list)
+ f.list = f.list.next
+ f.inuse += f.size
+ return v
+ }
+ if uintptr(f.nchunk) < f.size {
+ f.chunk = (*uint8)(persistentalloc(_FixAllocChunk, 0, f.stat))
+ f.nchunk = _FixAllocChunk
+ }
+
+ v := (unsafe.Pointer)(f.chunk)
+ if f.first != nil {
+ fn := *(*func(unsafe.Pointer, unsafe.Pointer))(unsafe.Pointer(&f.first))
+ fn(f.arg, v)
+ }
+ f.chunk = (*byte)(add(unsafe.Pointer(f.chunk), f.size))
+ f.nchunk -= uint32(f.size)
+ f.inuse += f.size
+ return v
+}
+
+func fixAlloc_Free(f *fixalloc, p unsafe.Pointer) {
+ f.inuse -= f.size
+ v := (*mlink)(p)
+ v.next = f.list
+ f.list = v
+}
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
new file mode 100644
index 000000000..f44d7ddbc
--- /dev/null
+++ b/src/runtime/mgc.go
@@ -0,0 +1,1798 @@
+// 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.
+
+// TODO(rsc): The code having to do with the heap bitmap needs very serious cleanup.
+// It has gotten completely out of control.
+
+// Garbage collector (GC).
+//
+// GC is:
+// - mark&sweep
+// - mostly precise (with the exception of some C-allocated objects, assembly frames/arguments, etc)
+// - parallel (up to MaxGcproc threads)
+// - partially concurrent (mark is stop-the-world, while sweep is concurrent)
+// - non-moving/non-compacting
+// - full (non-partial)
+//
+// GC rate.
+// Next GC is after we've allocated an extra amount of memory proportional to
+// the amount already in use. The proportion is controlled by GOGC environment variable
+// (100 by default). If GOGC=100 and we're using 4M, we'll GC again when we get to 8M
+// (this mark is tracked in next_gc variable). This keeps the GC cost in linear
+// proportion to the allocation cost. Adjusting GOGC just changes the linear constant
+// (and also the amount of extra memory used).
+//
+// Concurrent sweep.
+// The sweep phase proceeds concurrently with normal program execution.
+// The heap is swept span-by-span both lazily (when a goroutine needs another span)
+// and concurrently in a background goroutine (this helps programs that are not CPU bound).
+// However, at the end of the stop-the-world GC phase we don't know the size of the live heap,
+// and so next_gc calculation is tricky and happens as follows.
+// At the end of the stop-the-world phase next_gc is conservatively set based on total
+// heap size; all spans are marked as "needs sweeping".
+// Whenever a span is swept, next_gc is decremented by GOGC*newly_freed_memory.
+// The background sweeper goroutine simply sweeps spans one-by-one bringing next_gc
+// closer to the target value. However, this is not enough to avoid over-allocating memory.
+// Consider that a goroutine wants to allocate a new span for a large object and
+// there are no free swept spans, but there are small-object unswept spans.
+// If the goroutine naively allocates a new span, it can surpass the yet-unknown
+// target next_gc value. In order to prevent such cases (1) when a goroutine needs
+// to allocate a new small-object span, it sweeps small-object spans for the same
+// object size until it frees at least one object; (2) when a goroutine needs to
+// allocate large-object span from heap, it sweeps spans until it frees at least
+// that many pages into heap. Together these two measures ensure that we don't surpass
+// target next_gc value by a large margin. There is an exception: if a goroutine sweeps
+// and frees two nonadjacent one-page spans to the heap, it will allocate a new two-page span,
+// but there can still be other one-page unswept spans which could be combined into a two-page span.
+// It's critical to ensure that no operations proceed on unswept spans (that would corrupt
+// mark bits in GC bitmap). During GC all mcaches are flushed into the central cache,
+// so they are empty. When a goroutine grabs a new span into mcache, it sweeps it.
+// When a goroutine explicitly frees an object or sets a finalizer, it ensures that
+// the span is swept (either by sweeping it, or by waiting for the concurrent sweep to finish).
+// The finalizer goroutine is kicked off only when all spans are swept.
+// When the next GC starts, it sweeps all not-yet-swept spans (if any).
+
+package runtime
+
+import "unsafe"
+
+const (
+ _DebugGC = 0
+ _DebugGCPtrs = false // if true, print trace of every pointer load during GC
+ _ConcurrentSweep = true
+
+ _WorkbufSize = 4 * 1024
+ _FinBlockSize = 4 * 1024
+ _RootData = 0
+ _RootBss = 1
+ _RootFinalizers = 2
+ _RootSpans = 3
+ _RootFlushCaches = 4
+ _RootCount = 5
+)
+
+// ptrmask for an allocation containing a single pointer.
+var oneptr = [...]uint8{bitsPointer}
+
+// Initialized from $GOGC. GOGC=off means no gc.
+var gcpercent int32
+
+// Holding worldsema grants an M the right to try to stop the world.
+// The procedure is:
+//
+// semacquire(&worldsema);
+// m.gcing = 1;
+// stoptheworld();
+//
+// ... do stuff ...
+//
+// m.gcing = 0;
+// semrelease(&worldsema);
+// starttheworld();
+//
+var worldsema uint32 = 1
+
+type workbuf struct {
+ node lfnode // must be first
+ nobj uintptr
+ obj [(_WorkbufSize - unsafe.Sizeof(lfnode{}) - ptrSize) / ptrSize]uintptr
+}
+
+var data, edata, bss, ebss, gcdata, gcbss struct{}
+
+var finlock mutex // protects the following variables
+var fing *g // goroutine that runs finalizers
+var finq *finblock // list of finalizers that are to be executed
+var finc *finblock // cache of free blocks
+var finptrmask [_FinBlockSize / ptrSize / pointersPerByte]byte
+var fingwait bool
+var fingwake bool
+var allfin *finblock // list of all blocks
+
+var gcdatamask bitvector
+var gcbssmask bitvector
+
+var gclock mutex
+
+var badblock [1024]uintptr
+var nbadblock int32
+
+type workdata struct {
+ full uint64 // lock-free list of full blocks
+ empty uint64 // lock-free list of empty blocks
+ pad0 [_CacheLineSize]uint8 // prevents false-sharing between full/empty and nproc/nwait
+ nproc uint32
+ tstart int64
+ nwait uint32
+ ndone uint32
+ alldone note
+ markfor *parfor
+
+ // Copy of mheap.allspans for marker or sweeper.
+ spans []*mspan
+}
+
+var work workdata
+
+//go:linkname weak_cgo_allocate go.weak.runtime._cgo_allocate_internal
+var weak_cgo_allocate byte
+
+// Is _cgo_allocate linked into the binary?
+func have_cgo_allocate() bool {
+ return &weak_cgo_allocate != nil
+}
+
+// scanblock scans a block of n bytes starting at pointer b for references
+// to other objects, scanning any it finds recursively until there are no
+// unscanned objects left. Instead of using an explicit recursion, it keeps
+// a work list in the Workbuf* structures and loops in the main function
+// body. Keeping an explicit work list is easier on the stack allocator and
+// more efficient.
+func scanblock(b, n uintptr, ptrmask *uint8) {
+ // Cache memory arena parameters in local vars.
+ arena_start := mheap_.arena_start
+ arena_used := mheap_.arena_used
+
+ wbuf := getempty(nil)
+ nobj := wbuf.nobj
+ wp := &wbuf.obj[nobj]
+ keepworking := b == 0
+
+ var ptrbitp unsafe.Pointer
+
+ // ptrmask can have 2 possible values:
+ // 1. nil - obtain pointer mask from GC bitmap.
+ // 2. pointer to a compact mask (for stacks and data).
+ goto_scanobj := b != 0
+
+ for {
+ if goto_scanobj {
+ goto_scanobj = false
+ } else {
+ if nobj == 0 {
+ // Out of work in workbuf.
+ if !keepworking {
+ putempty(wbuf)
+ return
+ }
+
+ // Refill workbuf from global queue.
+ wbuf = getfull(wbuf)
+ if wbuf == nil {
+ return
+ }
+ nobj = wbuf.nobj
+ if nobj < uintptr(len(wbuf.obj)) {
+ wp = &wbuf.obj[nobj]
+ } else {
+ wp = nil
+ }
+ }
+
+ // If another proc wants a pointer, give it some.
+ if work.nwait > 0 && nobj > 4 && work.full == 0 {
+ wbuf.nobj = nobj
+ wbuf = handoff(wbuf)
+ nobj = wbuf.nobj
+ if nobj < uintptr(len(wbuf.obj)) {
+ wp = &wbuf.obj[nobj]
+ } else {
+ wp = nil
+ }
+ }
+
+ nobj--
+ wp = &wbuf.obj[nobj]
+ b = *wp
+ n = arena_used - uintptr(b)
+ ptrmask = nil // use GC bitmap for pointer info
+ }
+
+ if _DebugGCPtrs {
+ print("scanblock ", b, " +", hex(n), " ", ptrmask, "\n")
+ }
+
+ // Find bits of the beginning of the object.
+ if ptrmask == nil {
+ off := (uintptr(b) - arena_start) / ptrSize
+ ptrbitp = unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1)
+ }
+
+ var i uintptr
+ for i = 0; i < n; i += ptrSize {
+ // Find bits for this word.
+ var bits uintptr
+ if ptrmask == nil {
+ // Check if we have reached end of span.
+ if (uintptr(b)+i)%_PageSize == 0 &&
+ h_spans[(uintptr(b)-arena_start)>>_PageShift] != h_spans[(uintptr(b)+i-arena_start)>>_PageShift] {
+ break
+ }
+
+ // Consult GC bitmap.
+ bits = uintptr(*(*byte)(ptrbitp))
+
+ if wordsPerBitmapByte != 2 {
+ gothrow("alg doesn't work for wordsPerBitmapByte != 2")
+ }
+ j := (uintptr(b) + i) / ptrSize & 1
+ ptrbitp = add(ptrbitp, -j)
+ bits >>= gcBits * j
+
+ if bits&bitBoundary != 0 && i != 0 {
+ break // reached beginning of the next object
+ }
+ bits = (bits >> 2) & bitsMask
+ if bits == bitsDead {
+ break // reached no-scan part of the object
+ }
+ } else {
+ // dense mask (stack or data)
+ bits = (uintptr(*(*byte)(add(unsafe.Pointer(ptrmask), (i/ptrSize)/4))) >> (((i / ptrSize) % 4) * bitsPerPointer)) & bitsMask
+ }
+
+ if bits <= _BitsScalar { // BitsScalar || BitsDead
+ continue
+ }
+
+ if bits != _BitsPointer {
+ gothrow("unexpected garbage collection bits")
+ }
+
+ obj := *(*uintptr)(unsafe.Pointer(b + i))
+ obj0 := obj
+
+ markobj:
+ var s *mspan
+ var off, bitp, shift, xbits uintptr
+
+ // At this point we have extracted the next potential pointer.
+ // Check if it points into heap.
+ if obj == 0 {
+ continue
+ }
+ if obj < arena_start || arena_used <= obj {
+ if uintptr(obj) < _PhysPageSize && invalidptr != 0 {
+ s = nil
+ goto badobj
+ }
+ continue
+ }
+
+ // Mark the object.
+ obj &^= ptrSize - 1
+ off = (obj - arena_start) / ptrSize
+ bitp = arena_start - off/wordsPerBitmapByte - 1
+ shift = (off % wordsPerBitmapByte) * gcBits
+ xbits = uintptr(*(*byte)(unsafe.Pointer(bitp)))
+ bits = (xbits >> shift) & bitMask
+ if (bits & bitBoundary) == 0 {
+ // Not a beginning of a block, consult span table to find the block beginning.
+ k := pageID(obj >> _PageShift)
+ x := k
+ x -= pageID(arena_start >> _PageShift)
+ s = h_spans[x]
+ if s == nil || k < s.start || s.limit <= obj || s.state != mSpanInUse {
+ // Stack pointers lie within the arena bounds but are not part of the GC heap.
+ // Ignore them.
+ if s != nil && s.state == _MSpanStack {
+ continue
+ }
+ goto badobj
+ }
+ p := uintptr(s.start) << _PageShift
+ if s.sizeclass != 0 {
+ size := s.elemsize
+ idx := (obj - p) / size
+ p = p + idx*size
+ }
+ if p == obj {
+ print("runtime: failed to find block beginning for ", hex(p), " s=", hex(s.start*_PageSize), " s.limit=", hex(s.limit), "\n")
+ gothrow("failed to find block beginning")
+ }
+ obj = p
+ goto markobj
+ }
+
+ if _DebugGCPtrs {
+ print("scan *", hex(b+i), " = ", hex(obj0), " => base ", hex(obj), "\n")
+ }
+
+ if nbadblock > 0 && obj == badblock[nbadblock-1] {
+ // Running garbage collection again because
+ // we want to find the path from a root to a bad pointer.
+ // Found possible next step; extend or finish path.
+ for j := int32(0); j < nbadblock; j++ {
+ if badblock[j] == b {
+ goto AlreadyBad
+ }
+ }
+ print("runtime: found *(", hex(b), "+", hex(i), ") = ", hex(obj0), "+", hex(obj-obj0), "\n")
+ if ptrmask != nil {
+ gothrow("bad pointer")
+ }
+ if nbadblock >= int32(len(badblock)) {
+ gothrow("badblock trace too long")
+ }
+ badblock[nbadblock] = uintptr(b)
+ nbadblock++
+ AlreadyBad:
+ }
+
+ // Now we have bits, bitp, and shift correct for
+ // obj pointing at the base of the object.
+ // Only care about not marked objects.
+ if bits&bitMarked != 0 {
+ continue
+ }
+
+ // If obj size is greater than 8, then each byte of GC bitmap
+ // contains info for at most one object. In such case we use
+ // non-atomic byte store to mark the object. This can lead
+ // to double enqueue of the object for scanning, but scanning
+ // is an idempotent operation, so it is OK. This cannot lead
+ // to bitmap corruption because the single marked bit is the
+ // only thing that can change in the byte.
+ // For 8-byte objects we use non-atomic store, if the other
+ // quadruple is already marked. Otherwise we resort to CAS
+ // loop for marking.
+ if xbits&(bitMask|bitMask<<gcBits) != bitBoundary|bitBoundary<<gcBits || work.nproc == 1 {
+ *(*byte)(unsafe.Pointer(bitp)) = uint8(xbits | bitMarked<<shift)
+ } else {
+ atomicor8((*byte)(unsafe.Pointer(bitp)), bitMarked<<shift)
+ }
+
+ if (xbits>>(shift+2))&bitsMask == bitsDead {
+ continue // noscan object
+ }
+
+ // Queue the obj for scanning.
+ // TODO: PREFETCH here.
+
+ // If workbuf is full, obtain an empty one.
+ if nobj >= uintptr(len(wbuf.obj)) {
+ wbuf.nobj = nobj
+ wbuf = getempty(wbuf)
+ nobj = wbuf.nobj
+ wp = &wbuf.obj[nobj]
+ }
+ *wp = obj
+ nobj++
+ if nobj < uintptr(len(wbuf.obj)) {
+ wp = &wbuf.obj[nobj]
+ } else {
+ wp = nil
+ }
+ continue
+
+ badobj:
+ // If cgo_allocate is linked into the binary, it can allocate
+ // memory as []unsafe.Pointer that may not contain actual
+ // pointers and must be scanned conservatively.
+ // In this case alone, allow the bad pointer.
+ if have_cgo_allocate() && ptrmask == nil {
+ continue
+ }
+
+ // Anything else indicates a bug somewhere.
+ // If we're in the middle of chasing down a different bad pointer,
+ // don't confuse the trace by printing about this one.
+ if nbadblock > 0 {
+ continue
+ }
+
+ print("runtime: garbage collector found invalid heap pointer *(", hex(b), "+", hex(i), ")=", hex(obj))
+ if s == nil {
+ print(" s=nil\n")
+ } else {
+ print(" span=", uintptr(s.start)<<_PageShift, "-", s.limit, "-", (uintptr(s.start)+s.npages)<<_PageShift, " state=", s.state, "\n")
+ }
+ if ptrmask != nil {
+ gothrow("invalid heap pointer")
+ }
+ // Add to badblock list, which will cause the garbage collection
+ // to keep repeating until it has traced the chain of pointers
+ // leading to obj all the way back to a root.
+ if nbadblock == 0 {
+ badblock[nbadblock] = uintptr(b)
+ nbadblock++
+ }
+ }
+ if _DebugGCPtrs {
+ print("end scanblock ", hex(b), " +", hex(n), " ", ptrmask, "\n")
+ }
+ if _DebugGC > 0 && ptrmask == nil {
+ // For heap objects ensure that we did not overscan.
+ var p, n uintptr
+ if mlookup(b, &p, &n, nil) == 0 || b != p || i > n {
+ print("runtime: scanned (", hex(b), "+", hex(i), "), heap object (", hex(p), "+", hex(n), ")\n")
+ gothrow("scanblock: scanned invalid object")
+ }
+ }
+ }
+}
+
+func markroot(desc *parfor, i uint32) {
+ // Note: if you add a case here, please also update heapdump.c:dumproots.
+ switch i {
+ case _RootData:
+ scanblock(uintptr(unsafe.Pointer(&data)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)), gcdatamask.bytedata)
+
+ case _RootBss:
+ scanblock(uintptr(unsafe.Pointer(&bss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)), gcbssmask.bytedata)
+
+ case _RootFinalizers:
+ for fb := allfin; fb != nil; fb = fb.alllink {
+ scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0])
+ }
+
+ case _RootSpans:
+ // mark MSpan.specials
+ sg := mheap_.sweepgen
+ for spanidx := uint32(0); spanidx < uint32(len(work.spans)); spanidx++ {
+ s := work.spans[spanidx]
+ if s.state != mSpanInUse {
+ continue
+ }
+ if s.sweepgen != sg {
+ print("sweep ", s.sweepgen, " ", sg, "\n")
+ gothrow("gc: unswept span")
+ }
+ for sp := s.specials; sp != nil; sp = sp.next {
+ if sp.kind != _KindSpecialFinalizer {
+ continue
+ }
+ // don't mark finalized object, but scan it so we
+ // retain everything it points to.
+ spf := (*specialfinalizer)(unsafe.Pointer(sp))
+ // A finalizer can be set for an inner byte of an object, find object beginning.
+ p := uintptr(s.start<<_PageShift) + uintptr(spf.special.offset)/s.elemsize*s.elemsize
+ scanblock(p, s.elemsize, nil)
+ scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptr[0])
+ }
+ }
+
+ case _RootFlushCaches:
+ flushallmcaches()
+
+ default:
+ // the rest is scanning goroutine stacks
+ if uintptr(i-_RootCount) >= allglen {
+ gothrow("markroot: bad index")
+ }
+ gp := allgs[i-_RootCount]
+ // remember when we've first observed the G blocked
+ // needed only to output in traceback
+ status := readgstatus(gp)
+ if (status == _Gwaiting || status == _Gsyscall) && gp.waitsince == 0 {
+ gp.waitsince = work.tstart
+ }
+ // Shrink a stack if not much of it is being used.
+ shrinkstack(gp)
+ if readgstatus(gp) == _Gdead {
+ gp.gcworkdone = true
+ } else {
+ gp.gcworkdone = false
+ }
+ restart := stopg(gp)
+ scanstack(gp)
+ if restart {
+ restartg(gp)
+ }
+ }
+}
+
+// Get an empty work buffer off the work.empty list,
+// allocating new buffers as needed.
+func getempty(b *workbuf) *workbuf {
+ _g_ := getg()
+ if b != nil {
+ lfstackpush(&work.full, &b.node)
+ }
+ b = nil
+ c := _g_.m.mcache
+ if c.gcworkbuf != nil {
+ b = (*workbuf)(c.gcworkbuf)
+ c.gcworkbuf = nil
+ }
+ if b == nil {
+ b = (*workbuf)(lfstackpop(&work.empty))
+ }
+ if b == nil {
+ b = (*workbuf)(persistentalloc(unsafe.Sizeof(*b), _CacheLineSize, &memstats.gc_sys))
+ }
+ b.nobj = 0
+ return b
+}
+
+func putempty(b *workbuf) {
+ _g_ := getg()
+ c := _g_.m.mcache
+ if c.gcworkbuf == nil {
+ c.gcworkbuf = (unsafe.Pointer)(b)
+ return
+ }
+ lfstackpush(&work.empty, &b.node)
+}
+
+func gcworkbuffree(b unsafe.Pointer) {
+ if b != nil {
+ putempty((*workbuf)(b))
+ }
+}
+
+// Get a full work buffer off the work.full list, or return nil.
+func getfull(b *workbuf) *workbuf {
+ if b != nil {
+ lfstackpush(&work.empty, &b.node)
+ }
+ b = (*workbuf)(lfstackpop(&work.full))
+ if b != nil || work.nproc == 1 {
+ return b
+ }
+
+ xadd(&work.nwait, +1)
+ for i := 0; ; i++ {
+ if work.full != 0 {
+ xadd(&work.nwait, -1)
+ b = (*workbuf)(lfstackpop(&work.full))
+ if b != nil {
+ return b
+ }
+ xadd(&work.nwait, +1)
+ }
+ if work.nwait == work.nproc {
+ return nil
+ }
+ _g_ := getg()
+ if i < 10 {
+ _g_.m.gcstats.nprocyield++
+ procyield(20)
+ } else if i < 20 {
+ _g_.m.gcstats.nosyield++
+ osyield()
+ } else {
+ _g_.m.gcstats.nsleep++
+ usleep(100)
+ }
+ }
+}
+
+func handoff(b *workbuf) *workbuf {
+ // Make new buffer with half of b's pointers.
+ b1 := getempty(nil)
+ n := b.nobj / 2
+ b.nobj -= n
+ b1.nobj = n
+ memmove(unsafe.Pointer(&b1.obj[0]), unsafe.Pointer(&b.obj[b.nobj]), n*unsafe.Sizeof(b1.obj[0]))
+ _g_ := getg()
+ _g_.m.gcstats.nhandoff++
+ _g_.m.gcstats.nhandoffcnt += uint64(n)
+
+ // Put b on full list - let first half of b get stolen.
+ lfstackpush(&work.full, &b.node)
+ return b1
+}
+
+func stackmapdata(stkmap *stackmap, n int32) bitvector {
+ if n < 0 || n >= stkmap.n {
+ gothrow("stackmapdata: index out of range")
+ }
+ return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))}
+}
+
+// Scan a stack frame: local variables and function arguments/results.
+func scanframe(frame *stkframe, unused unsafe.Pointer) bool {
+
+ f := frame.fn
+ targetpc := frame.continpc
+ if targetpc == 0 {
+ // Frame is dead.
+ return true
+ }
+ if _DebugGC > 1 {
+ print("scanframe ", gofuncname(f), "\n")
+ }
+ if targetpc != f.entry {
+ targetpc--
+ }
+ pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc)
+ if pcdata == -1 {
+ // We do not have a valid pcdata value but there might be a
+ // stackmap for this function. It is likely that we are looking
+ // at the function prologue, assume so and hope for the best.
+ pcdata = 0
+ }
+
+ // Scan local variables if stack frame has been allocated.
+ size := frame.varp - frame.sp
+ var minsize uintptr
+ if thechar != '6' && thechar != '8' {
+ minsize = ptrSize
+ } else {
+ minsize = 0
+ }
+ if size > minsize {
+ stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
+ if stkmap == nil || stkmap.n <= 0 {
+ print("runtime: frame ", gofuncname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n")
+ gothrow("missing stackmap")
+ }
+
+ // Locals bitmap information, scan just the pointers in locals.
+ if pcdata < 0 || pcdata >= stkmap.n {
+ // don't know where we are
+ print("runtime: pcdata is ", pcdata, " and ", stkmap.n, " locals stack map entries for ", gofuncname(f), " (targetpc=", targetpc, ")\n")
+ gothrow("scanframe: bad symbol table")
+ }
+ bv := stackmapdata(stkmap, pcdata)
+ size = (uintptr(bv.n) * ptrSize) / bitsPerPointer
+ scanblock(frame.varp-size, uintptr(bv.n)/bitsPerPointer*ptrSize, bv.bytedata)
+ }
+
+ // Scan arguments.
+ if frame.arglen > 0 {
+ var bv bitvector
+ if frame.argmap != nil {
+ bv = *frame.argmap
+ } else {
+ stkmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps))
+ if stkmap == nil || stkmap.n <= 0 {
+ print("runtime: frame ", gofuncname(f), " untyped args ", hex(frame.argp), "+", hex(frame.arglen), "\n")
+ gothrow("missing stackmap")
+ }
+ if pcdata < 0 || pcdata >= stkmap.n {
+ // don't know where we are
+ print("runtime: pcdata is ", pcdata, " and ", stkmap.n, " args stack map entries for ", gofuncname(f), " (targetpc=", targetpc, ")\n")
+ gothrow("scanframe: bad symbol table")
+ }
+ bv = stackmapdata(stkmap, pcdata)
+ }
+ scanblock(frame.argp, uintptr(bv.n)/bitsPerPointer*ptrSize, bv.bytedata)
+ }
+ return true
+}
+
+func scanstack(gp *g) {
+ // TODO(rsc): Due to a precedence error, this was never checked in the original C version.
+ // If you enable the check, the gothrow happens.
+ /*
+ if readgstatus(gp)&_Gscan == 0 {
+ print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
+ gothrow("mark - bad status")
+ }
+ */
+
+ switch readgstatus(gp) &^ _Gscan {
+ default:
+ print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
+ gothrow("mark - bad status")
+ case _Gdead:
+ return
+ case _Grunning:
+ print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
+ gothrow("mark - world not stopped")
+ case _Grunnable, _Gsyscall, _Gwaiting:
+ // ok
+ }
+
+ if gp == getg() {
+ gothrow("can't scan our own stack")
+ }
+ mp := gp.m
+ if mp != nil && mp.helpgc != 0 {
+ gothrow("can't scan gchelper stack")
+ }
+
+ gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0)
+ tracebackdefers(gp, scanframe, nil)
+}
+
+// The gp has been moved to a gc safepoint. If there is gcphase specific
+// work it is done here.
+func gcphasework(gp *g) {
+ switch gcphase {
+ default:
+ gothrow("gcphasework in bad gcphase")
+ case _GCoff, _GCquiesce, _GCstw, _GCsweep:
+ // No work for now.
+ case _GCmark:
+ // Disabled until concurrent GC is implemented
+ // but indicate the scan has been done.
+ // scanstack(gp);
+ }
+ gp.gcworkdone = true
+}
+
+var finalizer1 = [...]byte{
+ // Each Finalizer is 5 words, ptr ptr uintptr ptr ptr.
+ // Each byte describes 4 words.
+ // Need 4 Finalizers described by 5 bytes before pattern repeats:
+ // ptr ptr uintptr ptr ptr
+ // ptr ptr uintptr ptr ptr
+ // ptr ptr uintptr ptr ptr
+ // ptr ptr uintptr ptr ptr
+ // aka
+ // ptr ptr uintptr ptr
+ // ptr ptr ptr uintptr
+ // ptr ptr ptr ptr
+ // uintptr ptr ptr ptr
+ // ptr uintptr ptr ptr
+ // Assumptions about Finalizer layout checked below.
+ bitsPointer | bitsPointer<<2 | bitsScalar<<4 | bitsPointer<<6,
+ bitsPointer | bitsPointer<<2 | bitsPointer<<4 | bitsScalar<<6,
+ bitsPointer | bitsPointer<<2 | bitsPointer<<4 | bitsPointer<<6,
+ bitsScalar | bitsPointer<<2 | bitsPointer<<4 | bitsPointer<<6,
+ bitsPointer | bitsScalar<<2 | bitsPointer<<4 | bitsPointer<<6,
+}
+
+func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) {
+ lock(&finlock)
+ if finq == nil || finq.cnt == finq.cap {
+ if finc == nil {
+ finc = (*finblock)(persistentalloc(_FinBlockSize, 0, &memstats.gc_sys))
+ finc.cap = int32((_FinBlockSize-unsafe.Sizeof(finblock{}))/unsafe.Sizeof(finalizer{}) + 1)
+ finc.alllink = allfin
+ allfin = finc
+ if finptrmask[0] == 0 {
+ // Build pointer mask for Finalizer array in block.
+ // Check assumptions made in finalizer1 array above.
+ if (unsafe.Sizeof(finalizer{}) != 5*ptrSize ||
+ unsafe.Offsetof(finalizer{}.fn) != 0 ||
+ unsafe.Offsetof(finalizer{}.arg) != ptrSize ||
+ unsafe.Offsetof(finalizer{}.nret) != 2*ptrSize ||
+ unsafe.Offsetof(finalizer{}.fint) != 3*ptrSize ||
+ unsafe.Offsetof(finalizer{}.ot) != 4*ptrSize ||
+ bitsPerPointer != 2) {
+ gothrow("finalizer out of sync")
+ }
+ for i := range finptrmask {
+ finptrmask[i] = finalizer1[i%len(finalizer1)]
+ }
+ }
+ }
+ block := finc
+ finc = block.next
+ block.next = finq
+ finq = block
+ }
+ f := (*finalizer)(add(unsafe.Pointer(&finq.fin[0]), uintptr(finq.cnt)*unsafe.Sizeof(finq.fin[0])))
+ finq.cnt++
+ f.fn = fn
+ f.nret = nret
+ f.fint = fint
+ f.ot = ot
+ f.arg = p
+ fingwake = true
+ unlock(&finlock)
+}
+
+func iterate_finq(callback func(*funcval, unsafe.Pointer, uintptr, *_type, *ptrtype)) {
+ for fb := allfin; fb != nil; fb = fb.alllink {
+ for i := int32(0); i < fb.cnt; i++ {
+ f := &fb.fin[i]
+ callback(f.fn, f.arg, f.nret, f.fint, f.ot)
+ }
+ }
+}
+
+func mSpan_EnsureSwept(s *mspan) {
+ // Caller must disable preemption.
+ // Otherwise when this function returns the span can become unswept again
+ // (if GC is triggered on another goroutine).
+ _g_ := getg()
+ if _g_.m.locks == 0 && _g_.m.mallocing == 0 && _g_ != _g_.m.g0 {
+ gothrow("MSpan_EnsureSwept: m is not locked")
+ }
+
+ sg := mheap_.sweepgen
+ if atomicload(&s.sweepgen) == sg {
+ return
+ }
+ if cas(&s.sweepgen, sg-2, sg-1) {
+ mSpan_Sweep(s, false)
+ return
+ }
+ // unfortunate condition, and we don't have efficient means to wait
+ for atomicload(&s.sweepgen) != sg {
+ osyield()
+ }
+}
+
+// Sweep frees or collects finalizers for blocks not marked in the mark phase.
+// It clears the mark bits in preparation for the next GC round.
+// Returns true if the span was returned to heap.
+// If preserve=true, don't return it to heap nor relink in MCentral lists;
+// caller takes care of it.
+func mSpan_Sweep(s *mspan, preserve bool) bool {
+ // It's critical that we enter this function with preemption disabled,
+ // GC must not start while we are in the middle of this function.
+ _g_ := getg()
+ if _g_.m.locks == 0 && _g_.m.mallocing == 0 && _g_ != _g_.m.g0 {
+ gothrow("MSpan_Sweep: m is not locked")
+ }
+ sweepgen := mheap_.sweepgen
+ if s.state != mSpanInUse || s.sweepgen != sweepgen-1 {
+ print("MSpan_Sweep: state=", s.state, " sweepgen=", s.sweepgen, " mheap.sweepgen=", sweepgen, "\n")
+ gothrow("MSpan_Sweep: bad span state")
+ }
+ arena_start := mheap_.arena_start
+ cl := s.sizeclass
+ size := s.elemsize
+ var n int32
+ var npages int32
+ if cl == 0 {
+ n = 1
+ } else {
+ // Chunk full of small blocks.
+ npages = class_to_allocnpages[cl]
+ n = (npages << _PageShift) / int32(size)
+ }
+ res := false
+ nfree := 0
+ var head mlink
+ end := &head
+ c := _g_.m.mcache
+ sweepgenset := false
+
+ // Mark any free objects in this span so we don't collect them.
+ for link := s.freelist; link != nil; link = link.next {
+ off := (uintptr(unsafe.Pointer(link)) - arena_start) / ptrSize
+ bitp := arena_start - off/wordsPerBitmapByte - 1
+ shift := (off % wordsPerBitmapByte) * gcBits
+ *(*byte)(unsafe.Pointer(bitp)) |= bitMarked << shift
+ }
+
+ // Unlink & free special records for any objects we're about to free.
+ specialp := &s.specials
+ special := *specialp
+ for special != nil {
+ // A finalizer can be set for an inner byte of an object, find object beginning.
+ p := uintptr(s.start<<_PageShift) + uintptr(special.offset)/size*size
+ off := (p - arena_start) / ptrSize
+ bitp := arena_start - off/wordsPerBitmapByte - 1
+ shift := (off % wordsPerBitmapByte) * gcBits
+ bits := (*(*byte)(unsafe.Pointer(bitp)) >> shift) & bitMask
+ if bits&bitMarked == 0 {
+ // Find the exact byte for which the special was setup
+ // (as opposed to object beginning).
+ p := uintptr(s.start<<_PageShift) + uintptr(special.offset)
+ // about to free object: splice out special record
+ y := special
+ special = special.next
+ *specialp = special
+ if !freespecial(y, unsafe.Pointer(p), size, false) {
+ // stop freeing of object if it has a finalizer
+ *(*byte)(unsafe.Pointer(bitp)) |= bitMarked << shift
+ }
+ } else {
+ // object is still live: keep special record
+ specialp = &special.next
+ special = *specialp
+ }
+ }
+
+ // Sweep through n objects of given size starting at p.
+ // This thread owns the span now, so it can manipulate
+ // the block bitmap without atomic operations.
+ p := uintptr(s.start << _PageShift)
+ off := (p - arena_start) / ptrSize
+ bitp := arena_start - off/wordsPerBitmapByte - 1
+ shift := uint(0)
+ step := size / (ptrSize * wordsPerBitmapByte)
+ // Rewind to the previous quadruple as we move to the next
+ // in the beginning of the loop.
+ bitp += step
+ if step == 0 {
+ // 8-byte objects.
+ bitp++
+ shift = gcBits
+ }
+ for ; n > 0; n, p = n-1, p+size {
+ bitp -= step
+ if step == 0 {
+ if shift != 0 {
+ bitp--
+ }
+ shift = gcBits - shift
+ }
+
+ xbits := *(*byte)(unsafe.Pointer(bitp))
+ bits := (xbits >> shift) & bitMask
+
+ // Allocated and marked object, reset bits to allocated.
+ if bits&bitMarked != 0 {
+ *(*byte)(unsafe.Pointer(bitp)) &^= bitMarked << shift
+ continue
+ }
+
+ // At this point we know that we are looking at garbage object
+ // that needs to be collected.
+ if debug.allocfreetrace != 0 {
+ tracefree(unsafe.Pointer(p), size)
+ }
+
+ // Reset to allocated+noscan.
+ *(*byte)(unsafe.Pointer(bitp)) = uint8(uintptr(xbits&^((bitMarked|bitsMask<<2)<<shift)) | uintptr(bitsDead)<<(shift+2))
+ if cl == 0 {
+ // Free large span.
+ if preserve {
+ gothrow("can't preserve large span")
+ }
+ unmarkspan(p, s.npages<<_PageShift)
+ s.needzero = 1
+
+ // important to set sweepgen before returning it to heap
+ atomicstore(&s.sweepgen, sweepgen)
+ sweepgenset = true
+
+ // NOTE(rsc,dvyukov): The original implementation of efence
+ // in CL 22060046 used SysFree instead of SysFault, so that
+ // the operating system would eventually give the memory
+ // back to us again, so that an efence program could run
+ // longer without running out of memory. Unfortunately,
+ // calling SysFree here without any kind of adjustment of the
+ // heap data structures means that when the memory does
+ // come back to us, we have the wrong metadata for it, either in
+ // the MSpan structures or in the garbage collection bitmap.
+ // Using SysFault here means that the program will run out of
+ // memory fairly quickly in efence mode, but at least it won't
+ // have mysterious crashes due to confused memory reuse.
+ // It should be possible to switch back to SysFree if we also
+ // implement and then call some kind of MHeap_DeleteSpan.
+ if debug.efence > 0 {
+ s.limit = 0 // prevent mlookup from finding this span
+ sysFault(unsafe.Pointer(p), size)
+ } else {
+ mHeap_Free(&mheap_, s, 1)
+ }
+ c.local_nlargefree++
+ c.local_largefree += size
+ xadd64(&memstats.next_gc, -int64(size)*int64(gcpercent+100)/100)
+ res = true
+ } else {
+ // Free small object.
+ if size > 2*ptrSize {
+ *(*uintptr)(unsafe.Pointer(p + ptrSize)) = uintptrMask & 0xdeaddeaddeaddead // mark as "needs to be zeroed"
+ } else if size > ptrSize {
+ *(*uintptr)(unsafe.Pointer(p + ptrSize)) = 0
+ }
+ end.next = (*mlink)(unsafe.Pointer(p))
+ end = end.next
+ nfree++
+ }
+ }
+
+ // We need to set s.sweepgen = h.sweepgen only when all blocks are swept,
+ // because of the potential for a concurrent free/SetFinalizer.
+ // But we need to set it before we make the span available for allocation
+ // (return it to heap or mcentral), because allocation code assumes that a
+ // span is already swept if available for allocation.
+ if !sweepgenset && nfree == 0 {
+ // The span must be in our exclusive ownership until we update sweepgen,
+ // check for potential races.
+ if s.state != mSpanInUse || s.sweepgen != sweepgen-1 {
+ print("MSpan_Sweep: state=", s.state, " sweepgen=", s.sweepgen, " mheap.sweepgen=", sweepgen, "\n")
+ gothrow("MSpan_Sweep: bad span state after sweep")
+ }
+ atomicstore(&s.sweepgen, sweepgen)
+ }
+ 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)
+ res = mCentral_FreeSpan(&mheap_.central[cl].mcentral, s, int32(nfree), head.next, end, preserve)
+ // MCentral_FreeSpan updates sweepgen
+ }
+ return res
+}
+
+// State of background sweep.
+// Protected by gclock.
+type sweepdata struct {
+ g *g
+ parked bool
+ started bool
+
+ spanidx uint32 // background sweeper position
+
+ nbgsweep uint32
+ npausesweep uint32
+}
+
+var sweep sweepdata
+
+// sweeps one span
+// returns number of pages returned to heap, or ^uintptr(0) if there is nothing to sweep
+func sweepone() uintptr {
+ _g_ := getg()
+
+ // increment locks to ensure that the goroutine is not preempted
+ // in the middle of sweep thus leaving the span in an inconsistent state for next GC
+ _g_.m.locks++
+ sg := mheap_.sweepgen
+ for {
+ idx := xadd(&sweep.spanidx, 1) - 1
+ if idx >= uint32(len(work.spans)) {
+ mheap_.sweepdone = 1
+ _g_.m.locks--
+ return ^uintptr(0)
+ }
+ s := work.spans[idx]
+ if s.state != mSpanInUse {
+ s.sweepgen = sg
+ continue
+ }
+ if s.sweepgen != sg-2 || !cas(&s.sweepgen, sg-2, sg-1) {
+ continue
+ }
+ npages := s.npages
+ if !mSpan_Sweep(s, false) {
+ npages = 0
+ }
+ _g_.m.locks--
+ return npages
+ }
+}
+
+func gosweepone() uintptr {
+ var ret uintptr
+ systemstack(func() {
+ ret = sweepone()
+ })
+ return ret
+}
+
+func gosweepdone() bool {
+ return mheap_.sweepdone != 0
+}
+
+func gchelper() {
+ _g_ := getg()
+ _g_.m.traceback = 2
+ gchelperstart()
+
+ // parallel mark for over gc roots
+ parfordo(work.markfor)
+
+ // help other threads scan secondary blocks
+ scanblock(0, 0, nil)
+
+ nproc := work.nproc // work.nproc can change right after we increment work.ndone
+ if xadd(&work.ndone, +1) == nproc-1 {
+ notewakeup(&work.alldone)
+ }
+ _g_.m.traceback = 0
+}
+
+func cachestats() {
+ for i := 0; ; i++ {
+ p := allp[i]
+ if p == nil {
+ break
+ }
+ c := p.mcache
+ if c == nil {
+ continue
+ }
+ purgecachedstats(c)
+ }
+}
+
+func flushallmcaches() {
+ for i := 0; ; i++ {
+ p := allp[i]
+ if p == nil {
+ break
+ }
+ c := p.mcache
+ if c == nil {
+ continue
+ }
+ mCache_ReleaseAll(c)
+ stackcache_clear(c)
+ }
+}
+
+func updatememstats(stats *gcstats) {
+ if stats != nil {
+ *stats = gcstats{}
+ }
+ for mp := allm; mp != nil; mp = mp.alllink {
+ if stats != nil {
+ src := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(&mp.gcstats))
+ dst := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(stats))
+ for i, v := range src {
+ dst[i] += v
+ }
+ mp.gcstats = gcstats{}
+ }
+ }
+
+ memstats.mcache_inuse = uint64(mheap_.cachealloc.inuse)
+ memstats.mspan_inuse = uint64(mheap_.spanalloc.inuse)
+ memstats.sys = memstats.heap_sys + memstats.stacks_sys + memstats.mspan_sys +
+ memstats.mcache_sys + memstats.buckhash_sys + memstats.gc_sys + memstats.other_sys
+
+ // Calculate memory allocator stats.
+ // During program execution we only count number of frees and amount of freed memory.
+ // Current number of alive object in the heap and amount of alive heap memory
+ // are calculated by scanning all spans.
+ // Total number of mallocs is calculated as number of frees plus number of alive objects.
+ // Similarly, total amount of allocated memory is calculated as amount of freed memory
+ // plus amount of alive heap memory.
+ memstats.alloc = 0
+ memstats.total_alloc = 0
+ memstats.nmalloc = 0
+ memstats.nfree = 0
+ for i := 0; i < len(memstats.by_size); i++ {
+ memstats.by_size[i].nmalloc = 0
+ memstats.by_size[i].nfree = 0
+ }
+
+ // Flush MCache's to MCentral.
+ systemstack(flushallmcaches)
+
+ // Aggregate local stats.
+ cachestats()
+
+ // Scan all spans and count number of alive objects.
+ lock(&mheap_.lock)
+ for i := uint32(0); i < mheap_.nspan; i++ {
+ s := h_allspans[i]
+ if s.state != mSpanInUse {
+ continue
+ }
+ if s.sizeclass == 0 {
+ memstats.nmalloc++
+ memstats.alloc += uint64(s.elemsize)
+ } else {
+ memstats.nmalloc += uint64(s.ref)
+ memstats.by_size[s.sizeclass].nmalloc += uint64(s.ref)
+ memstats.alloc += uint64(s.ref) * uint64(s.elemsize)
+ }
+ }
+ unlock(&mheap_.lock)
+
+ // Aggregate by size class.
+ smallfree := uint64(0)
+ memstats.nfree = mheap_.nlargefree
+ for i := 0; i < len(memstats.by_size); i++ {
+ memstats.nfree += mheap_.nsmallfree[i]
+ memstats.by_size[i].nfree = mheap_.nsmallfree[i]
+ memstats.by_size[i].nmalloc += mheap_.nsmallfree[i]
+ smallfree += uint64(mheap_.nsmallfree[i]) * uint64(class_to_size[i])
+ }
+ memstats.nfree += memstats.tinyallocs
+ memstats.nmalloc += memstats.nfree
+
+ // Calculate derived stats.
+ memstats.total_alloc = uint64(memstats.alloc) + uint64(mheap_.largefree) + smallfree
+ memstats.heap_alloc = memstats.alloc
+ memstats.heap_objects = memstats.nmalloc - memstats.nfree
+}
+
+func gcinit() {
+ if unsafe.Sizeof(workbuf{}) != _WorkbufSize {
+ gothrow("runtime: size of Workbuf is suboptimal")
+ }
+
+ work.markfor = parforalloc(_MaxGcproc)
+ 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)))
+}
+
+func gc_m(start_time int64, eagersweep bool) {
+ _g_ := getg()
+ gp := _g_.m.curg
+ casgstatus(gp, _Grunning, _Gwaiting)
+ gp.waitreason = "garbage collection"
+
+ gc(start_time, eagersweep)
+
+ if nbadblock > 0 {
+ // Work out path from root to bad block.
+ for {
+ gc(start_time, eagersweep)
+ if nbadblock >= int32(len(badblock)) {
+ gothrow("cannot find path to bad pointer")
+ }
+ }
+ }
+
+ casgstatus(gp, _Gwaiting, _Grunning)
+}
+
+func gc(start_time int64, eagersweep bool) {
+ if _DebugGCPtrs {
+ print("GC start\n")
+ }
+
+ if debug.allocfreetrace > 0 {
+ tracegc()
+ }
+
+ _g_ := getg()
+ _g_.m.traceback = 2
+ t0 := start_time
+ work.tstart = start_time
+
+ var t1 int64
+ if debug.gctrace > 0 {
+ t1 = nanotime()
+ }
+
+ // Sweep what is not sweeped by bgsweep.
+ for sweepone() != ^uintptr(0) {
+ sweep.npausesweep++
+ }
+
+ // Cache runtime.mheap_.allspans in work.spans to avoid conflicts with
+ // resizing/freeing allspans.
+ // New spans can be created while GC progresses, but they are not garbage for
+ // this round:
+ // - new stack spans can be created even while the world is stopped.
+ // - new malloc spans can be created during the concurrent sweep
+
+ // Even if this is stop-the-world, a concurrent exitsyscall can allocate a stack from heap.
+ lock(&mheap_.lock)
+ // Free the old cached sweep array if necessary.
+ if work.spans != nil && &work.spans[0] != &h_allspans[0] {
+ sysFree(unsafe.Pointer(&work.spans[0]), uintptr(len(work.spans))*unsafe.Sizeof(work.spans[0]), &memstats.other_sys)
+ }
+ // Cache the current array for marking.
+ mheap_.gcspans = mheap_.allspans
+ work.spans = h_allspans
+ unlock(&mheap_.lock)
+
+ work.nwait = 0
+ work.ndone = 0
+ work.nproc = uint32(gcprocs())
+ parforsetup(work.markfor, work.nproc, uint32(_RootCount+allglen), nil, false, markroot)
+ if work.nproc > 1 {
+ noteclear(&work.alldone)
+ helpgc(int32(work.nproc))
+ }
+
+ var t2 int64
+ if debug.gctrace > 0 {
+ t2 = nanotime()
+ }
+
+ gchelperstart()
+ parfordo(work.markfor)
+ scanblock(0, 0, nil)
+
+ var t3 int64
+ if debug.gctrace > 0 {
+ t3 = nanotime()
+ }
+
+ if work.nproc > 1 {
+ notesleep(&work.alldone)
+ }
+
+ shrinkfinish()
+
+ cachestats()
+ // next_gc calculation is tricky with concurrent sweep since we don't know size of live heap
+ // estimate what was live heap size after previous GC (for printing only)
+ heap0 := memstats.next_gc * 100 / (uint64(gcpercent) + 100)
+ // 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
+
+ t4 := nanotime()
+ atomicstore64(&memstats.last_gc, uint64(unixnanotime())) // must be Unix time to make sense to user
+ memstats.pause_ns[memstats.numgc%uint32(len(memstats.pause_ns))] = uint64(t4 - t0)
+ memstats.pause_end[memstats.numgc%uint32(len(memstats.pause_end))] = uint64(t4)
+ memstats.pause_total_ns += uint64(t4 - t0)
+ memstats.numgc++
+ if memstats.debuggc {
+ print("pause ", t4-t0, "\n")
+ }
+
+ if debug.gctrace > 0 {
+ heap1 := memstats.heap_alloc
+ var stats gcstats
+ updatememstats(&stats)
+ if heap1 != memstats.heap_alloc {
+ print("runtime: mstats skew: heap=", heap1, "/", memstats.heap_alloc, "\n")
+ gothrow("mstats skew")
+ }
+ obj := memstats.nmalloc - memstats.nfree
+
+ stats.nprocyield += work.markfor.nprocyield
+ stats.nosyield += work.markfor.nosyield
+ stats.nsleep += work.markfor.nsleep
+
+ print("gc", memstats.numgc, "(", work.nproc, "): ",
+ (t1-t0)/1000, "+", (t2-t1)/1000, "+", (t3-t2)/1000, "+", (t4-t3)/1000, " us, ",
+ heap0>>20, " -> ", heap1>>20, " MB, ",
+ obj, " (", memstats.nmalloc, "-", memstats.nfree, ") objects, ",
+ gcount(), " goroutines, ",
+ len(work.spans), "/", sweep.nbgsweep, "/", sweep.npausesweep, " sweeps, ",
+ stats.nhandoff, "(", stats.nhandoffcnt, ") handoff, ",
+ work.markfor.nsteal, "(", work.markfor.nstealcnt, ") steal, ",
+ stats.nprocyield, "/", stats.nosyield, "/", stats.nsleep, " yields\n")
+ sweep.nbgsweep = 0
+ sweep.npausesweep = 0
+ }
+
+ // See the comment in the beginning of this function as to why we need the following.
+ // Even if this is still stop-the-world, a concurrent exitsyscall can allocate a stack from heap.
+ lock(&mheap_.lock)
+ // Free the old cached mark array if necessary.
+ if work.spans != nil && &work.spans[0] != &h_allspans[0] {
+ sysFree(unsafe.Pointer(&work.spans[0]), uintptr(len(work.spans))*unsafe.Sizeof(work.spans[0]), &memstats.other_sys)
+ }
+
+ // Cache the current array for sweeping.
+ mheap_.gcspans = mheap_.allspans
+ mheap_.sweepgen += 2
+ mheap_.sweepdone = 0
+ work.spans = h_allspans
+ sweep.spanidx = 0
+ unlock(&mheap_.lock)
+
+ if _ConcurrentSweep && !eagersweep {
+ lock(&gclock)
+ if !sweep.started {
+ go bgsweep()
+ sweep.started = true
+ } else if sweep.parked {
+ sweep.parked = false
+ ready(sweep.g)
+ }
+ unlock(&gclock)
+ } else {
+ // Sweep all spans eagerly.
+ for sweepone() != ^uintptr(0) {
+ sweep.npausesweep++
+ }
+ // Do an additional mProf_GC, because all 'free' events are now real as well.
+ mProf_GC()
+ }
+
+ mProf_GC()
+ _g_.m.traceback = 0
+
+ if _DebugGCPtrs {
+ print("GC end\n")
+ }
+}
+
+func readmemstats_m(stats *MemStats) {
+ updatememstats(nil)
+
+ // Size of the trailing by_size array differs between Go and C,
+ // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+ memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats)
+
+ // Stack numbers are part of the heap numbers, separate those out for user consumption
+ stats.StackSys = stats.StackInuse
+ stats.HeapInuse -= stats.StackInuse
+ stats.HeapSys -= stats.StackInuse
+}
+
+//go:linkname readGCStats runtime/debug.readGCStats
+func readGCStats(pauses *[]uint64) {
+ systemstack(func() {
+ readGCStats_m(pauses)
+ })
+}
+
+func readGCStats_m(pauses *[]uint64) {
+ p := *pauses
+ // Calling code in runtime/debug should make the slice large enough.
+ if cap(p) < len(memstats.pause_ns)+3 {
+ gothrow("runtime: short slice passed to readGCStats")
+ }
+
+ // Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns.
+ lock(&mheap_.lock)
+
+ n := memstats.numgc
+ if n > uint32(len(memstats.pause_ns)) {
+ n = uint32(len(memstats.pause_ns))
+ }
+
+ // The pause buffer is circular. The most recent pause is at
+ // pause_ns[(numgc-1)%len(pause_ns)], and then backward
+ // from there to go back farther in time. We deliver the times
+ // most recent first (in p[0]).
+ p = p[:cap(p)]
+ for i := uint32(0); i < n; i++ {
+ j := (memstats.numgc - 1 - i) % uint32(len(memstats.pause_ns))
+ p[i] = memstats.pause_ns[j]
+ p[n+i] = memstats.pause_end[j]
+ }
+
+ p[n+n] = memstats.last_gc
+ p[n+n+1] = uint64(memstats.numgc)
+ p[n+n+2] = memstats.pause_total_ns
+ unlock(&mheap_.lock)
+ *pauses = p[:n+n+3]
+}
+
+func setGCPercent(in int32) (out int32) {
+ lock(&mheap_.lock)
+ out = gcpercent
+ if in < 0 {
+ in = -1
+ }
+ gcpercent = in
+ unlock(&mheap_.lock)
+ return out
+}
+
+func gchelperstart() {
+ _g_ := getg()
+
+ if _g_.m.helpgc < 0 || _g_.m.helpgc >= _MaxGcproc {
+ gothrow("gchelperstart: bad m->helpgc")
+ }
+ if _g_ != _g_.m.g0 {
+ gothrow("gchelper not running on g0 stack")
+ }
+}
+
+func wakefing() *g {
+ var res *g
+ lock(&finlock)
+ if fingwait && fingwake {
+ fingwait = false
+ fingwake = false
+ res = fing
+ }
+ unlock(&finlock)
+ return res
+}
+
+func addb(p *byte, n uintptr) *byte {
+ return (*byte)(add(unsafe.Pointer(p), n))
+}
+
+// Recursively unrolls GC program in prog.
+// mask is where to store the result.
+// ppos is a pointer to position in mask, in bits.
+// sparse says to generate 4-bits per word mask for heap (2-bits for data/bss otherwise).
+func unrollgcprog1(maskp *byte, prog *byte, ppos *uintptr, inplace, sparse bool) *byte {
+ arena_start := mheap_.arena_start
+ pos := *ppos
+ mask := (*[1 << 30]byte)(unsafe.Pointer(maskp))
+ for {
+ switch *prog {
+ default:
+ gothrow("unrollgcprog: unknown instruction")
+
+ case insData:
+ prog = addb(prog, 1)
+ siz := int(*prog)
+ prog = addb(prog, 1)
+ p := (*[1 << 30]byte)(unsafe.Pointer(prog))
+ for i := 0; i < siz; i++ {
+ v := p[i/_PointersPerByte]
+ v >>= (uint(i) % _PointersPerByte) * _BitsPerPointer
+ v &= _BitsMask
+ if inplace {
+ // Store directly into GC bitmap.
+ off := (uintptr(unsafe.Pointer(&mask[pos])) - arena_start) / ptrSize
+ bitp := (*byte)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1))
+ shift := (off % wordsPerBitmapByte) * gcBits
+ if shift == 0 {
+ *bitp = 0
+ }
+ *bitp |= v << (shift + 2)
+ pos += ptrSize
+ } else if sparse {
+ // 4-bits per word
+ v <<= (pos % 8) + 2
+ mask[pos/8] |= v
+ pos += gcBits
+ } else {
+ // 2-bits per word
+ v <<= pos % 8
+ mask[pos/8] |= v
+ pos += _BitsPerPointer
+ }
+ }
+ prog = addb(prog, round(uintptr(siz)*_BitsPerPointer, 8)/8)
+
+ case insArray:
+ prog = (*byte)(add(unsafe.Pointer(prog), 1))
+ siz := uintptr(0)
+ for i := uintptr(0); i < ptrSize; i++ {
+ siz = (siz << 8) + uintptr(*(*byte)(add(unsafe.Pointer(prog), ptrSize-i-1)))
+ }
+ prog = (*byte)(add(unsafe.Pointer(prog), ptrSize))
+ var prog1 *byte
+ for i := uintptr(0); i < siz; i++ {
+ prog1 = unrollgcprog1(&mask[0], prog, &pos, inplace, sparse)
+ }
+ if *prog1 != insArrayEnd {
+ gothrow("unrollgcprog: array does not end with insArrayEnd")
+ }
+ prog = (*byte)(add(unsafe.Pointer(prog1), 1))
+
+ case insArrayEnd, insEnd:
+ *ppos = pos
+ return prog
+ }
+ }
+}
+
+// Unrolls GC program prog for data/bss, returns dense GC mask.
+func unrollglobgcprog(prog *byte, size uintptr) bitvector {
+ masksize := round(round(size, ptrSize)/ptrSize*bitsPerPointer, 8) / 8
+ mask := (*[1 << 30]byte)(persistentalloc(masksize+1, 0, &memstats.gc_sys))
+ mask[masksize] = 0xa1
+ pos := uintptr(0)
+ prog = unrollgcprog1(&mask[0], prog, &pos, false, false)
+ if pos != size/ptrSize*bitsPerPointer {
+ print("unrollglobgcprog: bad program size, got ", pos, ", expect ", size/ptrSize*bitsPerPointer, "\n")
+ gothrow("unrollglobgcprog: bad program size")
+ }
+ if *prog != insEnd {
+ gothrow("unrollglobgcprog: program does not end with insEnd")
+ }
+ if mask[masksize] != 0xa1 {
+ gothrow("unrollglobgcprog: overflow")
+ }
+ return bitvector{int32(masksize * 8), &mask[0]}
+}
+
+func unrollgcproginplace_m(v unsafe.Pointer, typ *_type, size, size0 uintptr) {
+ pos := uintptr(0)
+ prog := (*byte)(unsafe.Pointer(uintptr(typ.gc[1])))
+ for pos != size0 {
+ unrollgcprog1((*byte)(v), prog, &pos, true, true)
+ }
+
+ // Mark first word as bitAllocated.
+ arena_start := mheap_.arena_start
+ off := (uintptr(v) - arena_start) / ptrSize
+ bitp := (*byte)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1))
+ shift := (off % wordsPerBitmapByte) * gcBits
+ *bitp |= bitBoundary << shift
+
+ // Mark word after last as BitsDead.
+ if size0 < size {
+ off := (uintptr(v) + size0 - arena_start) / ptrSize
+ bitp := (*byte)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1))
+ shift := (off % wordsPerBitmapByte) * gcBits
+ *bitp &= uint8(^(bitPtrMask << shift) | uintptr(bitsDead)<<(shift+2))
+ }
+}
+
+var unroll mutex
+
+// Unrolls GC program in typ.gc[1] into typ.gc[0]
+func unrollgcprog_m(typ *_type) {
+ lock(&unroll)
+ mask := (*byte)(unsafe.Pointer(uintptr(typ.gc[0])))
+ if *mask == 0 {
+ pos := uintptr(8) // skip the unroll flag
+ prog := (*byte)(unsafe.Pointer(uintptr(typ.gc[1])))
+ prog = unrollgcprog1(mask, prog, &pos, false, true)
+ if *prog != insEnd {
+ gothrow("unrollgcprog: program does not end with insEnd")
+ }
+ if typ.size/ptrSize%2 != 0 {
+ // repeat the program
+ prog := (*byte)(unsafe.Pointer(uintptr(typ.gc[1])))
+ unrollgcprog1(mask, prog, &pos, false, true)
+ }
+
+ // atomic way to say mask[0] = 1
+ atomicor8(mask, 1)
+ }
+ unlock(&unroll)
+}
+
+// mark the span of memory at v as having n blocks of the given size.
+// if leftover is true, there is left over space at the end of the span.
+func markspan(v unsafe.Pointer, size uintptr, n uintptr, leftover bool) {
+ if uintptr(v)+size*n > mheap_.arena_used || uintptr(v) < mheap_.arena_start {
+ gothrow("markspan: bad pointer")
+ }
+
+ // Find bits of the beginning of the span.
+ off := (uintptr(v) - uintptr(mheap_.arena_start)) / ptrSize
+ if off%wordsPerBitmapByte != 0 {
+ gothrow("markspan: unaligned length")
+ }
+ b := mheap_.arena_start - off/wordsPerBitmapByte - 1
+
+ // Okay to use non-atomic ops here, because we control
+ // the entire span, and each bitmap byte has bits for only
+ // one span, so no other goroutines are changing these bitmap words.
+
+ if size == ptrSize {
+ // Possible only on 64-bits (minimal size class is 8 bytes).
+ // Set memory to 0x11.
+ if (bitBoundary|bitsDead)<<gcBits|bitBoundary|bitsDead != 0x11 {
+ gothrow("markspan: bad bits")
+ }
+ if n%(wordsPerBitmapByte*ptrSize) != 0 {
+ gothrow("markspan: unaligned length")
+ }
+ b = b - n/wordsPerBitmapByte + 1 // find first byte
+ if b%ptrSize != 0 {
+ gothrow("markspan: unaligned pointer")
+ }
+ for i := uintptr(0); i < n; i, b = i+wordsPerBitmapByte*ptrSize, b+ptrSize {
+ *(*uintptr)(unsafe.Pointer(b)) = uintptrMask & 0x1111111111111111 // bitBoundary | bitsDead, repeated
+ }
+ return
+ }
+
+ if leftover {
+ n++ // mark a boundary just past end of last block too
+ }
+ step := size / (ptrSize * wordsPerBitmapByte)
+ for i := uintptr(0); i < n; i, b = i+1, b-step {
+ *(*byte)(unsafe.Pointer(b)) = bitBoundary | bitsDead<<2
+ }
+}
+
+// unmark the span of memory at v of length n bytes.
+func unmarkspan(v, n uintptr) {
+ if v+n > mheap_.arena_used || v < mheap_.arena_start {
+ gothrow("markspan: bad pointer")
+ }
+
+ off := (v - mheap_.arena_start) / ptrSize // word offset
+ if off%(ptrSize*wordsPerBitmapByte) != 0 {
+ gothrow("markspan: unaligned pointer")
+ }
+
+ b := mheap_.arena_start - off/wordsPerBitmapByte - 1
+ n /= ptrSize
+ if n%(ptrSize*wordsPerBitmapByte) != 0 {
+ gothrow("unmarkspan: unaligned length")
+ }
+
+ // Okay to use non-atomic ops here, because we control
+ // the entire span, and each bitmap word has bits for only
+ // one span, so no other goroutines are changing these
+ // bitmap words.
+ n /= wordsPerBitmapByte
+ memclr(unsafe.Pointer(b-n+1), n)
+}
+
+func mHeap_MapBits(h *mheap) {
+ // Caller has added extra mappings to the arena.
+ // Add extra mappings of bitmap words as needed.
+ // We allocate extra bitmap pieces in chunks of bitmapChunk.
+ const bitmapChunk = 8192
+
+ n := (h.arena_used - h.arena_start) / (ptrSize * wordsPerBitmapByte)
+ n = round(n, bitmapChunk)
+ n = round(n, _PhysPageSize)
+ if h.bitmap_mapped >= n {
+ return
+ }
+
+ sysMap(unsafe.Pointer(h.arena_start-n), n-h.bitmap_mapped, h.arena_reserved, &memstats.gc_sys)
+ h.bitmap_mapped = n
+}
+
+func getgcmaskcb(frame *stkframe, ctxt unsafe.Pointer) bool {
+ target := (*stkframe)(ctxt)
+ if frame.sp <= target.sp && target.sp < frame.varp {
+ *target = *frame
+ return false
+ }
+ return true
+}
+
+// Returns GC type info for object p for testing.
+func getgcmask(p unsafe.Pointer, t *_type, mask **byte, len *uintptr) {
+ *mask = nil
+ *len = 0
+
+ // data
+ if uintptr(unsafe.Pointer(&data)) <= uintptr(p) && uintptr(p) < uintptr(unsafe.Pointer(&edata)) {
+ n := (*ptrtype)(unsafe.Pointer(t)).elem.size
+ *len = n / ptrSize
+ *mask = &make([]byte, *len)[0]
+ for i := uintptr(0); i < n; i += ptrSize {
+ off := (uintptr(p) + i - uintptr(unsafe.Pointer(&data))) / ptrSize
+ bits := (*(*byte)(add(unsafe.Pointer(gcdatamask.bytedata), off/pointersPerByte)) >> ((off % pointersPerByte) * bitsPerPointer)) & bitsMask
+ *(*byte)(add(unsafe.Pointer(*mask), i/ptrSize)) = bits
+ }
+ return
+ }
+
+ // bss
+ if uintptr(unsafe.Pointer(&bss)) <= uintptr(p) && uintptr(p) < uintptr(unsafe.Pointer(&ebss)) {
+ n := (*ptrtype)(unsafe.Pointer(t)).elem.size
+ *len = n / ptrSize
+ *mask = &make([]byte, *len)[0]
+ for i := uintptr(0); i < n; i += ptrSize {
+ off := (uintptr(p) + i - uintptr(unsafe.Pointer(&bss))) / ptrSize
+ bits := (*(*byte)(add(unsafe.Pointer(gcbssmask.bytedata), off/pointersPerByte)) >> ((off % pointersPerByte) * bitsPerPointer)) & bitsMask
+ *(*byte)(add(unsafe.Pointer(*mask), i/ptrSize)) = bits
+ }
+ return
+ }
+
+ // heap
+ var n uintptr
+ var base uintptr
+ if mlookup(uintptr(p), &base, &n, nil) != 0 {
+ *len = n / ptrSize
+ *mask = &make([]byte, *len)[0]
+ for i := uintptr(0); i < n; i += ptrSize {
+ off := (uintptr(base) + i - mheap_.arena_start) / ptrSize
+ b := mheap_.arena_start - off/wordsPerBitmapByte - 1
+ shift := (off % wordsPerBitmapByte) * gcBits
+ bits := (*(*byte)(unsafe.Pointer(b)) >> (shift + 2)) & bitsMask
+ *(*byte)(add(unsafe.Pointer(*mask), i/ptrSize)) = bits
+ }
+ return
+ }
+
+ // stack
+ var frame stkframe
+ frame.sp = uintptr(p)
+ _g_ := getg()
+ gentraceback(_g_.m.curg.sched.pc, _g_.m.curg.sched.sp, 0, _g_.m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&frame)), 0)
+ if frame.fn != nil {
+ f := frame.fn
+ targetpc := frame.continpc
+ if targetpc == 0 {
+ return
+ }
+ if targetpc != f.entry {
+ targetpc--
+ }
+ pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc)
+ if pcdata == -1 {
+ return
+ }
+ stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
+ if stkmap == nil || stkmap.n <= 0 {
+ return
+ }
+ bv := stackmapdata(stkmap, pcdata)
+ size := uintptr(bv.n) / bitsPerPointer * ptrSize
+ n := (*ptrtype)(unsafe.Pointer(t)).elem.size
+ *len = n / ptrSize
+ *mask = &make([]byte, *len)[0]
+ for i := uintptr(0); i < n; i += ptrSize {
+ off := (uintptr(p) + i - frame.varp + size) / ptrSize
+ bits := ((*(*byte)(add(unsafe.Pointer(bv.bytedata), off*bitsPerPointer/8))) >> ((off * bitsPerPointer) % 8)) & bitsMask
+ *(*byte)(add(unsafe.Pointer(*mask), i/ptrSize)) = bits
+ }
+ }
+}
+
+func unixnanotime() int64 {
+ var now int64
+ gc_unixnanotime(&now)
+ return now
+}
diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c
deleted file mode 100644
index 7754bad89..000000000
--- a/src/runtime/mgc0.c
+++ /dev/null
@@ -1,2010 +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.
-
-// Garbage collector (GC).
-//
-// GC is:
-// - mark&sweep
-// - mostly precise (with the exception of some C-allocated objects, assembly frames/arguments, etc)
-// - parallel (up to MaxGcproc threads)
-// - partially concurrent (mark is stop-the-world, while sweep is concurrent)
-// - non-moving/non-compacting
-// - full (non-partial)
-//
-// GC rate.
-// Next GC is after we've allocated an extra amount of memory proportional to
-// the amount already in use. The proportion is controlled by GOGC environment variable
-// (100 by default). If GOGC=100 and we're using 4M, we'll GC again when we get to 8M
-// (this mark is tracked in next_gc variable). This keeps the GC cost in linear
-// proportion to the allocation cost. Adjusting GOGC just changes the linear constant
-// (and also the amount of extra memory used).
-//
-// Concurrent sweep.
-// The sweep phase proceeds concurrently with normal program execution.
-// The heap is swept span-by-span both lazily (when a goroutine needs another span)
-// and concurrently in a background goroutine (this helps programs that are not CPU bound).
-// However, at the end of the stop-the-world GC phase we don't know the size of the live heap,
-// and so next_gc calculation is tricky and happens as follows.
-// At the end of the stop-the-world phase next_gc is conservatively set based on total
-// heap size; all spans are marked as "needs sweeping".
-// Whenever a span is swept, next_gc is decremented by GOGC*newly_freed_memory.
-// The background sweeper goroutine simply sweeps spans one-by-one bringing next_gc
-// closer to the target value. However, this is not enough to avoid over-allocating memory.
-// Consider that a goroutine wants to allocate a new span for a large object and
-// there are no free swept spans, but there are small-object unswept spans.
-// If the goroutine naively allocates a new span, it can surpass the yet-unknown
-// target next_gc value. In order to prevent such cases (1) when a goroutine needs
-// to allocate a new small-object span, it sweeps small-object spans for the same
-// object size until it frees at least one object; (2) when a goroutine needs to
-// allocate large-object span from heap, it sweeps spans until it frees at least
-// that many pages into heap. Together these two measures ensure that we don't surpass
-// target next_gc value by a large margin. There is an exception: if a goroutine sweeps
-// and frees two nonadjacent one-page spans to the heap, it will allocate a new two-page span,
-// but there can still be other one-page unswept spans which could be combined into a two-page span.
-// It's critical to ensure that no operations proceed on unswept spans (that would corrupt
-// mark bits in GC bitmap). During GC all mcaches are flushed into the central cache,
-// so they are empty. When a goroutine grabs a new span into mcache, it sweeps it.
-// When a goroutine explicitly frees an object or sets a finalizer, it ensures that
-// the span is swept (either by sweeping it, or by waiting for the concurrent sweep to finish).
-// The finalizer goroutine is kicked off only when all spans are swept.
-// When the next GC starts, it sweeps all not-yet-swept spans (if any).
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "stack.h"
-#include "mgc0.h"
-#include "chan.h"
-#include "race.h"
-#include "type.h"
-#include "typekind.h"
-#include "funcdata.h"
-#include "textflag.h"
-
-enum {
- Debug = 0,
- DebugPtrs = 0, // if 1, print trace of every pointer load during GC
- ConcurrentSweep = 1,
-
- WorkbufSize = 4*1024,
- FinBlockSize = 4*1024,
- RootData = 0,
- RootBss = 1,
- RootFinalizers = 2,
- RootSpans = 3,
- RootFlushCaches = 4,
- RootCount = 5,
-};
-
-// ptrmask for an allocation containing a single pointer.
-static byte oneptr[] = {BitsPointer};
-
-// Initialized from $GOGC. GOGC=off means no gc.
-extern int32 runtime·gcpercent;
-
-// Holding worldsema grants an M the right to try to stop the world.
-// The procedure is:
-//
-// runtime·semacquire(&runtime·worldsema);
-// m->gcing = 1;
-// runtime·stoptheworld();
-//
-// ... do stuff ...
-//
-// m->gcing = 0;
-// runtime·semrelease(&runtime·worldsema);
-// runtime·starttheworld();
-//
-uint32 runtime·worldsema = 1;
-
-typedef struct Workbuf Workbuf;
-struct Workbuf
-{
- LFNode node; // must be first
- uintptr nobj;
- byte* obj[(WorkbufSize-sizeof(LFNode)-sizeof(uintptr))/PtrSize];
-};
-
-extern byte runtime·data[];
-extern byte runtime·edata[];
-extern byte runtime·bss[];
-extern byte runtime·ebss[];
-
-extern byte runtime·gcdata[];
-extern byte runtime·gcbss[];
-
-Mutex runtime·finlock; // protects the following variables
-G* runtime·fing; // goroutine that runs finalizers
-FinBlock* runtime·finq; // list of finalizers that are to be executed
-FinBlock* runtime·finc; // cache of free blocks
-static byte finptrmask[FinBlockSize/PtrSize/PointersPerByte];
-bool runtime·fingwait;
-bool runtime·fingwake;
-FinBlock *runtime·allfin; // list of all blocks
-
-BitVector runtime·gcdatamask;
-BitVector runtime·gcbssmask;
-
-Mutex runtime·gclock;
-
-static uintptr badblock[1024];
-static int32 nbadblock;
-
-static Workbuf* getempty(Workbuf*);
-static Workbuf* getfull(Workbuf*);
-static void putempty(Workbuf*);
-static Workbuf* handoff(Workbuf*);
-static void gchelperstart(void);
-static void flushallmcaches(void);
-static bool scanframe(Stkframe *frame, void *unused);
-static void scanstack(G *gp);
-static BitVector unrollglobgcprog(byte *prog, uintptr size);
-
-void runtime·bgsweep(void);
-static FuncVal bgsweepv = {runtime·bgsweep};
-
-typedef struct WorkData WorkData;
-struct WorkData {
- uint64 full; // lock-free list of full blocks
- uint64 empty; // lock-free list of empty blocks
- byte pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait
- uint32 nproc;
- int64 tstart;
- volatile uint32 nwait;
- volatile uint32 ndone;
- Note alldone;
- ParFor* markfor;
-
- // Copy of mheap.allspans for marker or sweeper.
- MSpan** spans;
- uint32 nspan;
-};
-WorkData runtime·work;
-
-// Is _cgo_allocate linked into the binary?
-static bool
-have_cgo_allocate(void)
-{
- extern byte go·weak·runtime·_cgo_allocate_internal[1];
- return go·weak·runtime·_cgo_allocate_internal != nil;
-}
-
-// scanblock scans a block of n bytes starting at pointer b for references
-// to other objects, scanning any it finds recursively until there are no
-// unscanned objects left. Instead of using an explicit recursion, it keeps
-// a work list in the Workbuf* structures and loops in the main function
-// body. Keeping an explicit work list is easier on the stack allocator and
-// more efficient.
-static void
-scanblock(byte *b, uintptr n, byte *ptrmask)
-{
- byte *obj, *obj0, *p, *arena_start, *arena_used, **wp, *scanbuf[8], *ptrbitp, *bitp;
- uintptr i, j, nobj, size, idx, x, off, scanbufpos, bits, xbits, shift;
- Workbuf *wbuf;
- Iface *iface;
- Eface *eface;
- Type *typ;
- MSpan *s;
- pageID k;
- bool keepworking;
-
- // Cache memory arena parameters in local vars.
- arena_start = runtime·mheap.arena_start;
- arena_used = runtime·mheap.arena_used;
-
- wbuf = getempty(nil);
- nobj = wbuf->nobj;
- wp = &wbuf->obj[nobj];
- keepworking = b == nil;
- scanbufpos = 0;
- for(i = 0; i < nelem(scanbuf); i++)
- scanbuf[i] = nil;
-
- ptrbitp = nil;
-
- // ptrmask can have 2 possible values:
- // 1. nil - obtain pointer mask from GC bitmap.
- // 2. pointer to a compact mask (for stacks and data).
- if(b != nil)
- goto scanobj;
- for(;;) {
- if(nobj == 0) {
- // Out of work in workbuf.
- // First, see is there is any work in scanbuf.
- for(i = 0; i < nelem(scanbuf); i++) {
- b = scanbuf[scanbufpos];
- scanbuf[scanbufpos++] = nil;
- scanbufpos %= nelem(scanbuf);
- if(b != nil) {
- n = arena_used - b; // scan until bitBoundary or BitsDead
- ptrmask = nil; // use GC bitmap for pointer info
- goto scanobj;
- }
- }
- if(!keepworking) {
- putempty(wbuf);
- return;
- }
- // Refill workbuf from global queue.
- wbuf = getfull(wbuf);
- if(wbuf == nil)
- return;
- nobj = wbuf->nobj;
- wp = &wbuf->obj[nobj];
- }
-
- // If another proc wants a pointer, give it some.
- if(runtime·work.nwait > 0 && nobj > 4 && runtime·work.full == 0) {
- wbuf->nobj = nobj;
- wbuf = handoff(wbuf);
- nobj = wbuf->nobj;
- wp = &wbuf->obj[nobj];
- }
-
- wp--;
- nobj--;
- b = *wp;
- n = arena_used - b; // scan until next bitBoundary or BitsDead
- ptrmask = nil; // use GC bitmap for pointer info
-
- scanobj:
- if(DebugPtrs)
- runtime·printf("scanblock %p +%p %p\n", b, n, ptrmask);
- // Find bits of the beginning of the object.
- if(ptrmask == nil) {
- off = (uintptr*)b - (uintptr*)arena_start;
- ptrbitp = arena_start - off/wordsPerBitmapByte - 1;
- }
- for(i = 0; i < n; i += PtrSize) {
- obj = nil;
- // Find bits for this word.
- if(ptrmask == nil) {
- // Check is we have reached end of span.
- if((((uintptr)b+i)%PageSize) == 0 &&
- runtime·mheap.spans[(b-arena_start)>>PageShift] != runtime·mheap.spans[(b+i-arena_start)>>PageShift])
- break;
- // Consult GC bitmap.
- bits = *ptrbitp;
-
- if(wordsPerBitmapByte != 2)
- runtime·throw("alg doesn't work for wordsPerBitmapByte != 2");
- j = ((uintptr)b+i)/PtrSize & 1;
- ptrbitp -= j;
- bits >>= gcBits*j;
-
- if((bits&bitBoundary) != 0 && i != 0)
- break; // reached beginning of the next object
- bits = (bits>>2)&BitsMask;
- if(bits == BitsDead)
- break; // reached no-scan part of the object
- } else // dense mask (stack or data)
- bits = (ptrmask[(i/PtrSize)/4]>>(((i/PtrSize)%4)*BitsPerPointer))&BitsMask;
-
- if(bits <= BitsScalar) // BitsScalar || BitsDead
- continue;
- if(bits == BitsPointer) {
- obj = *(byte**)(b+i);
- obj0 = obj;
- goto markobj;
- }
-
- // With those three out of the way, must be multi-word.
- if(Debug && bits != BitsMultiWord)
- runtime·throw("unexpected garbage collection bits");
- // Find the next pair of bits.
- if(ptrmask == nil) {
- bits = *ptrbitp;
- j = ((uintptr)b+i+PtrSize)/PtrSize & 1;
- ptrbitp -= j;
- bits >>= gcBits*j;
- bits = (bits>>2)&BitsMask;
- } else
- bits = (ptrmask[((i+PtrSize)/PtrSize)/4]>>((((i+PtrSize)/PtrSize)%4)*BitsPerPointer))&BitsMask;
-
- if(Debug && bits != BitsIface && bits != BitsEface)
- runtime·throw("unexpected garbage collection bits");
-
- if(bits == BitsIface) {
- iface = (Iface*)(b+i);
- if(iface->tab != nil) {
- typ = iface->tab->type;
- if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers))
- obj = iface->data;
- }
- } else {
- eface = (Eface*)(b+i);
- typ = eface->type;
- if(typ != nil) {
- if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers))
- obj = eface->data;
- }
- }
-
- i += PtrSize;
-
- obj0 = obj;
- markobj:
- // At this point we have extracted the next potential pointer.
- // Check if it points into heap.
- if(obj == nil)
- continue;
- if(obj < arena_start || obj >= arena_used) {
- if((uintptr)obj < PhysPageSize && runtime·invalidptr) {
- s = nil;
- goto badobj;
- }
- continue;
- }
- // Mark the object.
- obj = (byte*)((uintptr)obj & ~(PtrSize-1));
- off = (uintptr*)obj - (uintptr*)arena_start;
- bitp = arena_start - off/wordsPerBitmapByte - 1;
- shift = (off % wordsPerBitmapByte) * gcBits;
- xbits = *bitp;
- bits = (xbits >> shift) & bitMask;
- if((bits&bitBoundary) == 0) {
- // Not a beginning of a block, consult span table to find the block beginning.
- k = (uintptr)obj>>PageShift;
- x = k;
- x -= (uintptr)arena_start>>PageShift;
- s = runtime·mheap.spans[x];
- if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse) {
- // Stack pointers lie within the arena bounds but are not part of the GC heap.
- // Ignore them.
- if(s != nil && s->state == MSpanStack)
- continue;
-
- badobj:
- // If cgo_allocate is linked into the binary, it can allocate
- // memory as []unsafe.Pointer that may not contain actual
- // pointers and must be scanned conservatively.
- // In this case alone, allow the bad pointer.
- if(have_cgo_allocate() && ptrmask == nil)
- continue;
-
- // Anything else indicates a bug somewhere.
- // If we're in the middle of chasing down a different bad pointer,
- // don't confuse the trace by printing about this one.
- if(nbadblock > 0)
- continue;
-
- runtime·printf("runtime: garbage collector found invalid heap pointer *(%p+%p)=%p", b, i, obj);
- if(s == nil)
- runtime·printf(" s=nil\n");
- else
- runtime·printf(" span=%p-%p-%p state=%d\n", (uintptr)s->start<<PageShift, s->limit, (uintptr)(s->start+s->npages)<<PageShift, s->state);
- if(ptrmask != nil)
- runtime·throw("invalid heap pointer");
- // Add to badblock list, which will cause the garbage collection
- // to keep repeating until it has traced the chain of pointers
- // leading to obj all the way back to a root.
- if(nbadblock == 0)
- badblock[nbadblock++] = (uintptr)b;
- continue;
- }
- p = (byte*)((uintptr)s->start<<PageShift);
- if(s->sizeclass != 0) {
- size = s->elemsize;
- idx = ((byte*)obj - p)/size;
- p = p+idx*size;
- }
- if(p == obj) {
- runtime·printf("runtime: failed to find block beginning for %p s=%p s->limit=%p\n",
- p, s->start*PageSize, s->limit);
- runtime·throw("failed to find block beginning");
- }
- obj = p;
- goto markobj;
- }
- if(DebugPtrs)
- runtime·printf("scan *%p = %p => base %p\n", b+i, obj0, obj);
-
- if(nbadblock > 0 && (uintptr)obj == badblock[nbadblock-1]) {
- // Running garbage collection again because
- // we want to find the path from a root to a bad pointer.
- // Found possible next step; extend or finish path.
- for(j=0; j<nbadblock; j++)
- if(badblock[j] == (uintptr)b)
- goto AlreadyBad;
- runtime·printf("runtime: found *(%p+%p) = %p+%p\n", b, i, obj0, (uintptr)(obj-obj0));
- if(ptrmask != nil)
- runtime·throw("bad pointer");
- if(nbadblock >= nelem(badblock))
- runtime·throw("badblock trace too long");
- badblock[nbadblock++] = (uintptr)b;
- AlreadyBad:;
- }
-
- // Now we have bits, bitp, and shift correct for
- // obj pointing at the base of the object.
- // Only care about not marked objects.
- if((bits&bitMarked) != 0)
- continue;
- // If obj size is greater than 8, then each byte of GC bitmap
- // contains info for at most one object. In such case we use
- // non-atomic byte store to mark the object. This can lead
- // to double enqueue of the object for scanning, but scanning
- // is an idempotent operation, so it is OK. This cannot lead
- // to bitmap corruption because the single marked bit is the
- // only thing that can change in the byte.
- // For 8-byte objects we use non-atomic store, if the other
- // quadruple is already marked. Otherwise we resort to CAS
- // loop for marking.
- if((xbits&(bitMask|(bitMask<<gcBits))) != (bitBoundary|(bitBoundary<<gcBits)) ||
- runtime·work.nproc == 1)
- *bitp = xbits | (bitMarked<<shift);
- else
- runtime·atomicor8(bitp, bitMarked<<shift);
-
- if(((xbits>>(shift+2))&BitsMask) == BitsDead)
- continue; // noscan object
-
- // Queue the obj for scanning.
- PREFETCH(obj);
- p = scanbuf[scanbufpos];
- scanbuf[scanbufpos++] = obj;
- scanbufpos %= nelem(scanbuf);
- if(p == nil)
- continue;
-
- // If workbuf is full, obtain an empty one.
- if(nobj >= nelem(wbuf->obj)) {
- wbuf->nobj = nobj;
- wbuf = getempty(wbuf);
- nobj = wbuf->nobj;
- wp = &wbuf->obj[nobj];
- }
- *wp = p;
- wp++;
- nobj++;
- }
- if(DebugPtrs)
- runtime·printf("end scanblock %p +%p %p\n", b, n, ptrmask);
-
- if(Debug && ptrmask == nil) {
- // For heap objects ensure that we did not overscan.
- n = 0;
- p = nil;
- if(!runtime·mlookup(b, &p, &n, nil) || b != p || i > n) {
- runtime·printf("runtime: scanned (%p,%p), heap object (%p,%p)\n", b, i, p, n);
- runtime·throw("scanblock: scanned invalid object");
- }
- }
- }
-}
-
-static void
-markroot(ParFor *desc, uint32 i)
-{
- FinBlock *fb;
- MSpan *s;
- uint32 spanidx, sg;
- G *gp;
- void *p;
- uint32 status;
- bool restart;
-
- USED(&desc);
- // Note: if you add a case here, please also update heapdump.c:dumproots.
- switch(i) {
- case RootData:
- scanblock(runtime·data, runtime·edata - runtime·data, runtime·gcdatamask.bytedata);
- break;
-
- case RootBss:
- scanblock(runtime·bss, runtime·ebss - runtime·bss, runtime·gcbssmask.bytedata);
- break;
-
- case RootFinalizers:
- for(fb=runtime·allfin; fb; fb=fb->alllink)
- scanblock((byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), finptrmask);
- break;
-
- case RootSpans:
- // mark MSpan.specials
- sg = runtime·mheap.sweepgen;
- for(spanidx=0; spanidx<runtime·work.nspan; spanidx++) {
- Special *sp;
- SpecialFinalizer *spf;
-
- s = runtime·work.spans[spanidx];
- if(s->state != MSpanInUse)
- continue;
- if(s->sweepgen != sg) {
- runtime·printf("sweep %d %d\n", s->sweepgen, sg);
- runtime·throw("gc: unswept span");
- }
- for(sp = s->specials; sp != nil; sp = sp->next) {
- if(sp->kind != KindSpecialFinalizer)
- continue;
- // don't mark finalized object, but scan it so we
- // retain everything it points to.
- spf = (SpecialFinalizer*)sp;
- // A finalizer can be set for an inner byte of an object, find object beginning.
- p = (void*)((s->start << PageShift) + spf->special.offset/s->elemsize*s->elemsize);
- scanblock(p, s->elemsize, nil);
- scanblock((void*)&spf->fn, PtrSize, oneptr);
- }
- }
- break;
-
- case RootFlushCaches:
- flushallmcaches();
- break;
-
- default:
- // the rest is scanning goroutine stacks
- if(i - RootCount >= runtime·allglen)
- runtime·throw("markroot: bad index");
- gp = runtime·allg[i - RootCount];
- // remember when we've first observed the G blocked
- // needed only to output in traceback
- status = runtime·readgstatus(gp);
- if((status == Gwaiting || status == Gsyscall) && gp->waitsince == 0)
- gp->waitsince = runtime·work.tstart;
- // Shrink a stack if not much of it is being used.
- runtime·shrinkstack(gp);
- if(runtime·readgstatus(gp) == Gdead)
- gp->gcworkdone = true;
- else
- gp->gcworkdone = false;
- restart = runtime·stopg(gp);
- scanstack(gp);
- if(restart)
- runtime·restartg(gp);
- break;
- }
-}
-
-// Get an empty work buffer off the work.empty list,
-// allocating new buffers as needed.
-static Workbuf*
-getempty(Workbuf *b)
-{
- MCache *c;
-
- if(b != nil)
- runtime·lfstackpush(&runtime·work.full, &b->node);
- b = nil;
- c = g->m->mcache;
- if(c->gcworkbuf != nil) {
- b = c->gcworkbuf;
- c->gcworkbuf = nil;
- }
- if(b == nil)
- b = (Workbuf*)runtime·lfstackpop(&runtime·work.empty);
- if(b == nil)
- b = runtime·persistentalloc(sizeof(*b), CacheLineSize, &mstats.gc_sys);
- b->nobj = 0;
- return b;
-}
-
-static void
-putempty(Workbuf *b)
-{
- MCache *c;
-
- c = g->m->mcache;
- if(c->gcworkbuf == nil) {
- c->gcworkbuf = b;
- return;
- }
- runtime·lfstackpush(&runtime·work.empty, &b->node);
-}
-
-void
-runtime·gcworkbuffree(void *b)
-{
- if(b != nil)
- putempty(b);
-}
-
-// Get a full work buffer off the work.full list, or return nil.
-static Workbuf*
-getfull(Workbuf *b)
-{
- int32 i;
-
- if(b != nil)
- runtime·lfstackpush(&runtime·work.empty, &b->node);
- b = (Workbuf*)runtime·lfstackpop(&runtime·work.full);
- if(b != nil || runtime·work.nproc == 1)
- return b;
-
- runtime·xadd(&runtime·work.nwait, +1);
- for(i=0;; i++) {
- if(runtime·work.full != 0) {
- runtime·xadd(&runtime·work.nwait, -1);
- b = (Workbuf*)runtime·lfstackpop(&runtime·work.full);
- if(b != nil)
- return b;
- runtime·xadd(&runtime·work.nwait, +1);
- }
- if(runtime·work.nwait == runtime·work.nproc)
- return nil;
- if(i < 10) {
- g->m->gcstats.nprocyield++;
- runtime·procyield(20);
- } else if(i < 20) {
- g->m->gcstats.nosyield++;
- runtime·osyield();
- } else {
- g->m->gcstats.nsleep++;
- runtime·usleep(100);
- }
- }
-}
-
-static Workbuf*
-handoff(Workbuf *b)
-{
- int32 n;
- Workbuf *b1;
-
- // Make new buffer with half of b's pointers.
- b1 = getempty(nil);
- n = b->nobj/2;
- b->nobj -= n;
- b1->nobj = n;
- runtime·memmove(b1->obj, b->obj+b->nobj, n*sizeof b1->obj[0]);
- g->m->gcstats.nhandoff++;
- g->m->gcstats.nhandoffcnt += n;
-
- // Put b on full list - let first half of b get stolen.
- runtime·lfstackpush(&runtime·work.full, &b->node);
- return b1;
-}
-
-BitVector
-runtime·stackmapdata(StackMap *stackmap, int32 n)
-{
- if(n < 0 || n >= stackmap->n)
- runtime·throw("stackmapdata: index out of range");
- return (BitVector){stackmap->nbit, stackmap->bytedata + n*((stackmap->nbit+31)/32*4)};
-}
-
-// Scan a stack frame: local variables and function arguments/results.
-static bool
-scanframe(Stkframe *frame, void *unused)
-{
- Func *f;
- StackMap *stackmap;
- BitVector bv;
- uintptr size, minsize;
- uintptr targetpc;
- int32 pcdata;
-
- USED(unused);
- f = frame->fn;
- targetpc = frame->continpc;
- if(targetpc == 0) {
- // Frame is dead.
- return true;
- }
- if(Debug > 1)
- runtime·printf("scanframe %s\n", runtime·funcname(f));
- if(targetpc != f->entry)
- targetpc--;
- pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
- if(pcdata == -1) {
- // We do not have a valid pcdata value but there might be a
- // stackmap for this function. It is likely that we are looking
- // at the function prologue, assume so and hope for the best.
- pcdata = 0;
- }
-
- // Scan local variables if stack frame has been allocated.
- size = frame->varp - frame->sp;
- if(thechar != '6' && thechar != '8')
- minsize = sizeof(uintptr);
- else
- minsize = 0;
- if(size > minsize) {
- stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
- if(stackmap == nil || stackmap->n <= 0) {
- runtime·printf("runtime: frame %s untyped locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size);
- runtime·throw("missing stackmap");
- }
-
- // Locals bitmap information, scan just the pointers in locals.
- if(pcdata < 0 || pcdata >= stackmap->n) {
- // don't know where we are
- runtime·printf("runtime: pcdata is %d and %d locals stack map entries for %s (targetpc=%p)\n",
- pcdata, stackmap->n, runtime·funcname(f), targetpc);
- runtime·throw("scanframe: bad symbol table");
- }
- bv = runtime·stackmapdata(stackmap, pcdata);
- size = (bv.n * PtrSize) / BitsPerPointer;
- scanblock((byte*)(frame->varp - size), bv.n/BitsPerPointer*PtrSize, bv.bytedata);
- }
-
- // Scan arguments.
- if(frame->arglen > 0) {
- if(frame->argmap != nil)
- bv = *frame->argmap;
- else {
- stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
- if(stackmap == nil || stackmap->n <= 0) {
- runtime·printf("runtime: frame %s untyped args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
- runtime·throw("missing stackmap");
- }
- if(pcdata < 0 || pcdata >= stackmap->n) {
- // don't know where we are
- runtime·printf("runtime: pcdata is %d and %d args stack map entries for %s (targetpc=%p)\n",
- pcdata, stackmap->n, runtime·funcname(f), targetpc);
- runtime·throw("scanframe: bad symbol table");
- }
- bv = runtime·stackmapdata(stackmap, pcdata);
- }
- scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, bv.bytedata);
- }
- return true;
-}
-
-static void
-scanstack(G *gp)
-{
- M *mp;
- bool (*fn)(Stkframe*, void*);
-
- if(runtime·readgstatus(gp)&Gscan == 0) {
- runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
- runtime·throw("mark - bad status");
- }
-
- switch(runtime·readgstatus(gp)&~Gscan) {
- default:
- runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
- runtime·throw("mark - bad status");
- case Gdead:
- return;
- case Grunning:
- runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
- runtime·throw("mark - world not stopped");
- case Grunnable:
- case Gsyscall:
- case Gwaiting:
- break;
- }
-
- if(gp == g)
- runtime·throw("can't scan our own stack");
- if((mp = gp->m) != nil && mp->helpgc)
- runtime·throw("can't scan gchelper stack");
-
- fn = scanframe;
- runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, 0);
- runtime·tracebackdefers(gp, &fn, nil);
-}
-
-// The gp has been moved to a gc safepoint. If there is gcphase specific
-// work it is done here.
-void
-runtime·gcphasework(G *gp)
-{
- switch(runtime·gcphase) {
- default:
- runtime·throw("gcphasework in bad gcphase");
- case GCoff:
- case GCquiesce:
- case GCstw:
- case GCsweep:
- // No work for now.
- break;
- case GCmark:
- // Disabled until concurrent GC is implemented
- // but indicate the scan has been done.
- // scanstack(gp);
- break;
- }
- gp->gcworkdone = true;
-}
-
-#pragma dataflag NOPTR
-static byte finalizer1[] = {
- // Each Finalizer is 5 words, ptr ptr uintptr ptr ptr.
- // Each byte describes 4 words.
- // Need 4 Finalizers described by 5 bytes before pattern repeats:
- // ptr ptr uintptr ptr ptr
- // ptr ptr uintptr ptr ptr
- // ptr ptr uintptr ptr ptr
- // ptr ptr uintptr ptr ptr
- // aka
- // ptr ptr uintptr ptr
- // ptr ptr ptr uintptr
- // ptr ptr ptr ptr
- // uintptr ptr ptr ptr
- // ptr uintptr ptr ptr
- // Assumptions about Finalizer layout checked below.
- BitsPointer | BitsPointer<<2 | BitsScalar<<4 | BitsPointer<<6,
- BitsPointer | BitsPointer<<2 | BitsPointer<<4 | BitsScalar<<6,
- BitsPointer | BitsPointer<<2 | BitsPointer<<4 | BitsPointer<<6,
- BitsScalar | BitsPointer<<2 | BitsPointer<<4 | BitsPointer<<6,
- BitsPointer | BitsScalar<<2 | BitsPointer<<4 | BitsPointer<<6,
-};
-
-void
-runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot)
-{
- FinBlock *block;
- Finalizer *f;
- int32 i;
-
- runtime·lock(&runtime·finlock);
- if(runtime·finq == nil || runtime·finq->cnt == runtime·finq->cap) {
- if(runtime·finc == nil) {
- runtime·finc = runtime·persistentalloc(FinBlockSize, 0, &mstats.gc_sys);
- runtime·finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
- runtime·finc->alllink = runtime·allfin;
- runtime·allfin = runtime·finc;
- if(finptrmask[0] == 0) {
- // Build pointer mask for Finalizer array in block.
- // Check assumptions made in finalizer1 array above.
- if(sizeof(Finalizer) != 5*PtrSize ||
- offsetof(Finalizer, fn) != 0 ||
- offsetof(Finalizer, arg) != PtrSize ||
- offsetof(Finalizer, nret) != 2*PtrSize ||
- offsetof(Finalizer, fint) != 3*PtrSize ||
- offsetof(Finalizer, ot) != 4*PtrSize ||
- BitsPerPointer != 2) {
- runtime·throw("finalizer out of sync");
- }
- for(i=0; i<nelem(finptrmask); i++)
- finptrmask[i] = finalizer1[i%nelem(finalizer1)];
- }
- }
- block = runtime·finc;
- runtime·finc = block->next;
- block->next = runtime·finq;
- runtime·finq = block;
- }
- f = &runtime·finq->fin[runtime·finq->cnt];
- runtime·finq->cnt++;
- f->fn = fn;
- f->nret = nret;
- f->fint = fint;
- f->ot = ot;
- f->arg = p;
- runtime·fingwake = true;
- runtime·unlock(&runtime·finlock);
-}
-
-void
-runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*))
-{
- FinBlock *fb;
- Finalizer *f;
- uintptr i;
-
- for(fb = runtime·allfin; fb; fb = fb->alllink) {
- for(i = 0; i < fb->cnt; i++) {
- f = &fb->fin[i];
- callback(f->fn, f->arg, f->nret, f->fint, f->ot);
- }
- }
-}
-
-void
-runtime·MSpan_EnsureSwept(MSpan *s)
-{
- uint32 sg;
-
- // Caller must disable preemption.
- // Otherwise when this function returns the span can become unswept again
- // (if GC is triggered on another goroutine).
- if(g->m->locks == 0 && g->m->mallocing == 0 && g != g->m->g0)
- runtime·throw("MSpan_EnsureSwept: m is not locked");
-
- sg = runtime·mheap.sweepgen;
- if(runtime·atomicload(&s->sweepgen) == sg)
- return;
- if(runtime·cas(&s->sweepgen, sg-2, sg-1)) {
- runtime·MSpan_Sweep(s, false);
- return;
- }
- // unfortunate condition, and we don't have efficient means to wait
- while(runtime·atomicload(&s->sweepgen) != sg)
- runtime·osyield();
-}
-
-// Sweep frees or collects finalizers for blocks not marked in the mark phase.
-// It clears the mark bits in preparation for the next GC round.
-// Returns true if the span was returned to heap.
-// If preserve=true, don't return it to heap nor relink in MCentral lists;
-// caller takes care of it.
-bool
-runtime·MSpan_Sweep(MSpan *s, bool preserve)
-{
- int32 cl, n, npages, nfree;
- uintptr size, off, step;
- uint32 sweepgen;
- byte *p, *bitp, shift, xbits, bits;
- MCache *c;
- byte *arena_start;
- MLink head, *end, *link;
- Special *special, **specialp, *y;
- bool res, sweepgenset;
-
- // It's critical that we enter this function with preemption disabled,
- // GC must not start while we are in the middle of this function.
- if(g->m->locks == 0 && g->m->mallocing == 0 && g != g->m->g0)
- runtime·throw("MSpan_Sweep: m is not locked");
- sweepgen = runtime·mheap.sweepgen;
- if(s->state != MSpanInUse || s->sweepgen != sweepgen-1) {
- runtime·printf("MSpan_Sweep: state=%d sweepgen=%d mheap.sweepgen=%d\n",
- s->state, s->sweepgen, sweepgen);
- runtime·throw("MSpan_Sweep: bad span state");
- }
- arena_start = runtime·mheap.arena_start;
- cl = s->sizeclass;
- size = s->elemsize;
- if(cl == 0) {
- n = 1;
- } else {
- // Chunk full of small blocks.
- npages = runtime·class_to_allocnpages[cl];
- n = (npages << PageShift) / size;
- }
- res = false;
- nfree = 0;
- end = &head;
- c = g->m->mcache;
- sweepgenset = false;
-
- // Mark any free objects in this span so we don't collect them.
- for(link = s->freelist; link != nil; link = link->next) {
- off = (uintptr*)link - (uintptr*)arena_start;
- bitp = arena_start - off/wordsPerBitmapByte - 1;
- shift = (off % wordsPerBitmapByte) * gcBits;
- *bitp |= bitMarked<<shift;
- }
-
- // Unlink & free special records for any objects we're about to free.
- specialp = &s->specials;
- special = *specialp;
- while(special != nil) {
- // A finalizer can be set for an inner byte of an object, find object beginning.
- p = (byte*)(s->start << PageShift) + special->offset/size*size;
- off = (uintptr*)p - (uintptr*)arena_start;
- bitp = arena_start - off/wordsPerBitmapByte - 1;
- shift = (off % wordsPerBitmapByte) * gcBits;
- bits = (*bitp>>shift) & bitMask;
- if((bits&bitMarked) == 0) {
- // Find the exact byte for which the special was setup
- // (as opposed to object beginning).
- p = (byte*)(s->start << PageShift) + special->offset;
- // about to free object: splice out special record
- y = special;
- special = special->next;
- *specialp = special;
- if(!runtime·freespecial(y, p, size, false)) {
- // stop freeing of object if it has a finalizer
- *bitp |= bitMarked << shift;
- }
- } else {
- // object is still live: keep special record
- specialp = &special->next;
- special = *specialp;
- }
- }
-
- // Sweep through n objects of given size starting at p.
- // This thread owns the span now, so it can manipulate
- // the block bitmap without atomic operations.
- p = (byte*)(s->start << PageShift);
- // Find bits for the beginning of the span.
- off = (uintptr*)p - (uintptr*)arena_start;
- bitp = arena_start - off/wordsPerBitmapByte - 1;
- shift = 0;
- step = size/(PtrSize*wordsPerBitmapByte);
- // Rewind to the previous quadruple as we move to the next
- // in the beginning of the loop.
- bitp += step;
- if(step == 0) {
- // 8-byte objects.
- bitp++;
- shift = gcBits;
- }
- for(; n > 0; n--, p += size) {
- bitp -= step;
- if(step == 0) {
- if(shift != 0)
- bitp--;
- shift = gcBits - shift;
- }
-
- xbits = *bitp;
- bits = (xbits>>shift) & bitMask;
-
- // Allocated and marked object, reset bits to allocated.
- if((bits&bitMarked) != 0) {
- *bitp &= ~(bitMarked<<shift);
- continue;
- }
- // At this point we know that we are looking at garbage object
- // that needs to be collected.
- if(runtime·debug.allocfreetrace)
- runtime·tracefree(p, size);
- // Reset to allocated+noscan.
- *bitp = (xbits & ~((bitMarked|(BitsMask<<2))<<shift)) | ((uintptr)BitsDead<<(shift+2));
- if(cl == 0) {
- // Free large span.
- if(preserve)
- runtime·throw("can't preserve large span");
- runtime·unmarkspan(p, s->npages<<PageShift);
- s->needzero = 1;
- // important to set sweepgen before returning it to heap
- runtime·atomicstore(&s->sweepgen, sweepgen);
- sweepgenset = true;
- // NOTE(rsc,dvyukov): The original implementation of efence
- // in CL 22060046 used SysFree instead of SysFault, so that
- // the operating system would eventually give the memory
- // back to us again, so that an efence program could run
- // longer without running out of memory. Unfortunately,
- // calling SysFree here without any kind of adjustment of the
- // heap data structures means that when the memory does
- // come back to us, we have the wrong metadata for it, either in
- // the MSpan structures or in the garbage collection bitmap.
- // Using SysFault here means that the program will run out of
- // memory fairly quickly in efence mode, but at least it won't
- // have mysterious crashes due to confused memory reuse.
- // It should be possible to switch back to SysFree if we also
- // implement and then call some kind of MHeap_DeleteSpan.
- if(runtime·debug.efence) {
- s->limit = nil; // prevent mlookup from finding this span
- runtime·SysFault(p, size);
- } else
- runtime·MHeap_Free(&runtime·mheap, s, 1);
- c->local_nlargefree++;
- c->local_largefree += size;
- runtime·xadd64(&mstats.next_gc, -(uint64)(size * (runtime·gcpercent + 100)/100));
- res = true;
- } else {
- // Free small object.
- if(size > 2*sizeof(uintptr))
- ((uintptr*)p)[1] = (uintptr)0xdeaddeaddeaddeadll; // mark as "needs to be zeroed"
- else if(size > sizeof(uintptr))
- ((uintptr*)p)[1] = 0;
-
- end->next = (MLink*)p;
- end = (MLink*)p;
- nfree++;
- }
- }
-
- // We need to set s->sweepgen = h->sweepgen only when all blocks are swept,
- // because of the potential for a concurrent free/SetFinalizer.
- // But we need to set it before we make the span available for allocation
- // (return it to heap or mcentral), because allocation code assumes that a
- // span is already swept if available for allocation.
-
- if(!sweepgenset && nfree == 0) {
- // The span must be in our exclusive ownership until we update sweepgen,
- // check for potential races.
- if(s->state != MSpanInUse || s->sweepgen != sweepgen-1) {
- runtime·printf("MSpan_Sweep: state=%d sweepgen=%d mheap.sweepgen=%d\n",
- s->state, s->sweepgen, sweepgen);
- runtime·throw("MSpan_Sweep: bad span state after sweep");
- }
- runtime·atomicstore(&s->sweepgen, sweepgen);
- }
- if(nfree > 0) {
- c->local_nsmallfree[cl] += nfree;
- c->local_cachealloc -= nfree * size;
- runtime·xadd64(&mstats.next_gc, -(uint64)(nfree * size * (runtime·gcpercent + 100)/100));
- res = runtime·MCentral_FreeSpan(&runtime·mheap.central[cl].mcentral, s, nfree, head.next, end, preserve);
- // MCentral_FreeSpan updates sweepgen
- }
- return res;
-}
-
-// State of background runtime·sweep.
-// Protected by runtime·gclock.
-typedef struct SweepData SweepData;
-struct SweepData
-{
- G* g;
- bool parked;
-
- uint32 spanidx; // background sweeper position
-
- uint32 nbgsweep;
- uint32 npausesweep;
-};
-SweepData runtime·sweep;
-
-// sweeps one span
-// returns number of pages returned to heap, or -1 if there is nothing to sweep
-uintptr
-runtime·sweepone(void)
-{
- MSpan *s;
- uint32 idx, sg;
- uintptr npages;
-
- // increment locks to ensure that the goroutine is not preempted
- // in the middle of sweep thus leaving the span in an inconsistent state for next GC
- g->m->locks++;
- sg = runtime·mheap.sweepgen;
- for(;;) {
- idx = runtime·xadd(&runtime·sweep.spanidx, 1) - 1;
- if(idx >= runtime·work.nspan) {
- runtime·mheap.sweepdone = true;
- g->m->locks--;
- return -1;
- }
- s = runtime·work.spans[idx];
- if(s->state != MSpanInUse) {
- s->sweepgen = sg;
- continue;
- }
- if(s->sweepgen != sg-2 || !runtime·cas(&s->sweepgen, sg-2, sg-1))
- continue;
- npages = s->npages;
- if(!runtime·MSpan_Sweep(s, false))
- npages = 0;
- g->m->locks--;
- return npages;
- }
-}
-
-static void
-sweepone_m(void)
-{
- g->m->scalararg[0] = runtime·sweepone();
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·gosweepone(void)
-{
- void (*fn)(void);
-
- fn = sweepone_m;
- runtime·onM(&fn);
- return g->m->scalararg[0];
-}
-
-#pragma textflag NOSPLIT
-bool
-runtime·gosweepdone(void)
-{
- return runtime·mheap.sweepdone;
-}
-
-void
-runtime·gchelper(void)
-{
- uint32 nproc;
-
- g->m->traceback = 2;
- gchelperstart();
-
- // parallel mark for over gc roots
- runtime·parfordo(runtime·work.markfor);
-
- // help other threads scan secondary blocks
- scanblock(nil, 0, nil);
-
- nproc = runtime·work.nproc; // runtime·work.nproc can change right after we increment runtime·work.ndone
- if(runtime·xadd(&runtime·work.ndone, +1) == nproc-1)
- runtime·notewakeup(&runtime·work.alldone);
- g->m->traceback = 0;
-}
-
-static void
-cachestats(void)
-{
- MCache *c;
- P *p, **pp;
-
- for(pp=runtime·allp; p=*pp; pp++) {
- c = p->mcache;
- if(c==nil)
- continue;
- runtime·purgecachedstats(c);
- }
-}
-
-static void
-flushallmcaches(void)
-{
- P *p, **pp;
- MCache *c;
-
- // Flush MCache's to MCentral.
- for(pp=runtime·allp; p=*pp; pp++) {
- c = p->mcache;
- if(c==nil)
- continue;
- runtime·MCache_ReleaseAll(c);
- runtime·stackcache_clear(c);
- }
-}
-
-static void
-flushallmcaches_m(G *gp)
-{
- flushallmcaches();
- runtime·gogo(&gp->sched);
-}
-
-void
-runtime·updatememstats(GCStats *stats)
-{
- M *mp;
- MSpan *s;
- int32 i;
- uint64 smallfree;
- uint64 *src, *dst;
- void (*fn)(G*);
-
- if(stats)
- runtime·memclr((byte*)stats, sizeof(*stats));
- for(mp=runtime·allm; mp; mp=mp->alllink) {
- if(stats) {
- src = (uint64*)&mp->gcstats;
- dst = (uint64*)stats;
- for(i=0; i<sizeof(*stats)/sizeof(uint64); i++)
- dst[i] += src[i];
- runtime·memclr((byte*)&mp->gcstats, sizeof(mp->gcstats));
- }
- }
- mstats.mcache_inuse = runtime·mheap.cachealloc.inuse;
- mstats.mspan_inuse = runtime·mheap.spanalloc.inuse;
- mstats.sys = mstats.heap_sys + mstats.stacks_sys + mstats.mspan_sys +
- mstats.mcache_sys + mstats.buckhash_sys + mstats.gc_sys + mstats.other_sys;
-
- // Calculate memory allocator stats.
- // During program execution we only count number of frees and amount of freed memory.
- // Current number of alive object in the heap and amount of alive heap memory
- // are calculated by scanning all spans.
- // Total number of mallocs is calculated as number of frees plus number of alive objects.
- // Similarly, total amount of allocated memory is calculated as amount of freed memory
- // plus amount of alive heap memory.
- mstats.alloc = 0;
- mstats.total_alloc = 0;
- mstats.nmalloc = 0;
- mstats.nfree = 0;
- for(i = 0; i < nelem(mstats.by_size); i++) {
- mstats.by_size[i].nmalloc = 0;
- mstats.by_size[i].nfree = 0;
- }
-
- // Flush MCache's to MCentral.
- if(g == g->m->g0)
- flushallmcaches();
- else {
- fn = flushallmcaches_m;
- runtime·mcall(&fn);
- }
-
- // Aggregate local stats.
- cachestats();
-
- // Scan all spans and count number of alive objects.
- runtime·lock(&runtime·mheap.lock);
- for(i = 0; i < runtime·mheap.nspan; i++) {
- s = runtime·mheap.allspans[i];
- if(s->state != MSpanInUse)
- continue;
- if(s->sizeclass == 0) {
- mstats.nmalloc++;
- mstats.alloc += s->elemsize;
- } else {
- mstats.nmalloc += s->ref;
- mstats.by_size[s->sizeclass].nmalloc += s->ref;
- mstats.alloc += s->ref*s->elemsize;
- }
- }
- runtime·unlock(&runtime·mheap.lock);
-
- // Aggregate by size class.
- smallfree = 0;
- mstats.nfree = runtime·mheap.nlargefree;
- for(i = 0; i < nelem(mstats.by_size); i++) {
- mstats.nfree += runtime·mheap.nsmallfree[i];
- mstats.by_size[i].nfree = runtime·mheap.nsmallfree[i];
- mstats.by_size[i].nmalloc += runtime·mheap.nsmallfree[i];
- smallfree += runtime·mheap.nsmallfree[i] * runtime·class_to_size[i];
- }
- mstats.nfree += mstats.tinyallocs;
- mstats.nmalloc += mstats.nfree;
-
- // Calculate derived stats.
- mstats.total_alloc = mstats.alloc + runtime·mheap.largefree + smallfree;
- mstats.heap_alloc = mstats.alloc;
- mstats.heap_objects = mstats.nmalloc - mstats.nfree;
-}
-
-// Structure of arguments passed to function gc().
-// This allows the arguments to be passed via runtime·mcall.
-struct gc_args
-{
- int64 start_time; // start time of GC in ns (just before stoptheworld)
- bool eagersweep;
-};
-
-static void gc(struct gc_args *args);
-
-int32
-runtime·readgogc(void)
-{
- byte *p;
-
- p = runtime·getenv("GOGC");
- if(p == nil || p[0] == '\0')
- return 100;
- if(runtime·strcmp(p, (byte*)"off") == 0)
- return -1;
- return runtime·atoi(p);
-}
-
-void
-runtime·gcinit(void)
-{
- if(sizeof(Workbuf) != WorkbufSize)
- runtime·throw("runtime: size of Workbuf is suboptimal");
-
- runtime·work.markfor = runtime·parforalloc(MaxGcproc);
- runtime·gcpercent = runtime·readgogc();
- runtime·gcdatamask = unrollglobgcprog(runtime·gcdata, runtime·edata - runtime·data);
- runtime·gcbssmask = unrollglobgcprog(runtime·gcbss, runtime·ebss - runtime·bss);
-}
-
-void
-runtime·gc_m(void)
-{
- struct gc_args a;
- G *gp;
-
- gp = g->m->curg;
- runtime·casgstatus(gp, Grunning, Gwaiting);
- gp->waitreason = runtime·gostringnocopy((byte*)"garbage collection");
-
- a.start_time = (uint64)(g->m->scalararg[0]) | ((uint64)(g->m->scalararg[1]) << 32);
- a.eagersweep = g->m->scalararg[2];
- gc(&a);
-
- if(nbadblock > 0) {
- // Work out path from root to bad block.
- for(;;) {
- gc(&a);
- if(nbadblock >= nelem(badblock))
- runtime·throw("cannot find path to bad pointer");
- }
- }
-
- runtime·casgstatus(gp, Gwaiting, Grunning);
-}
-
-static void
-gc(struct gc_args *args)
-{
- int64 t0, t1, t2, t3, t4;
- uint64 heap0, heap1, obj;
- GCStats stats;
-
- if(DebugPtrs)
- runtime·printf("GC start\n");
-
- if(runtime·debug.allocfreetrace)
- runtime·tracegc();
-
- g->m->traceback = 2;
- t0 = args->start_time;
- runtime·work.tstart = args->start_time;
-
- t1 = 0;
- if(runtime·debug.gctrace)
- t1 = runtime·nanotime();
-
- // Sweep what is not sweeped by bgsweep.
- while(runtime·sweepone() != -1)
- runtime·sweep.npausesweep++;
-
- // Cache runtime.mheap.allspans in work.spans to avoid conflicts with
- // resizing/freeing allspans.
- // New spans can be created while GC progresses, but they are not garbage for
- // this round:
- // - new stack spans can be created even while the world is stopped.
- // - new malloc spans can be created during the concurrent sweep
-
- // Even if this is stop-the-world, a concurrent exitsyscall can allocate a stack from heap.
- runtime·lock(&runtime·mheap.lock);
- // Free the old cached sweep array if necessary.
- if(runtime·work.spans != nil && runtime·work.spans != runtime·mheap.allspans)
- runtime·SysFree(runtime·work.spans, runtime·work.nspan*sizeof(runtime·work.spans[0]), &mstats.other_sys);
- // Cache the current array for marking.
- runtime·mheap.gcspans = runtime·mheap.allspans;
- runtime·work.spans = runtime·mheap.allspans;
- runtime·work.nspan = runtime·mheap.nspan;
- runtime·unlock(&runtime·mheap.lock);
-
- runtime·work.nwait = 0;
- runtime·work.ndone = 0;
- runtime·work.nproc = runtime·gcprocs();
- runtime·parforsetup(runtime·work.markfor, runtime·work.nproc, RootCount + runtime·allglen, nil, false, markroot);
- if(runtime·work.nproc > 1) {
- runtime·noteclear(&runtime·work.alldone);
- runtime·helpgc(runtime·work.nproc);
- }
-
- t2 = 0;
- if(runtime·debug.gctrace)
- t2 = runtime·nanotime();
-
- gchelperstart();
- runtime·parfordo(runtime·work.markfor);
- scanblock(nil, 0, nil);
-
- t3 = 0;
- if(runtime·debug.gctrace)
- t3 = runtime·nanotime();
-
- if(runtime·work.nproc > 1)
- runtime·notesleep(&runtime·work.alldone);
-
- runtime·shrinkfinish();
-
- cachestats();
- // next_gc calculation is tricky with concurrent sweep since we don't know size of live heap
- // estimate what was live heap size after previous GC (for tracing only)
- heap0 = mstats.next_gc*100/(runtime·gcpercent+100);
- // conservatively set next_gc to high value assuming that everything is live
- // concurrent/lazy sweep will reduce this number while discovering new garbage
- mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*runtime·gcpercent/100;
-
- t4 = runtime·nanotime();
- runtime·atomicstore64(&mstats.last_gc, runtime·unixnanotime()); // must be Unix time to make sense to user
- mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t4 - t0;
- mstats.pause_end[mstats.numgc%nelem(mstats.pause_end)] = t4;
- mstats.pause_total_ns += t4 - t0;
- mstats.numgc++;
- if(mstats.debuggc)
- runtime·printf("pause %D\n", t4-t0);
-
- if(runtime·debug.gctrace) {
- heap1 = mstats.heap_alloc;
- runtime·updatememstats(&stats);
- if(heap1 != mstats.heap_alloc) {
- runtime·printf("runtime: mstats skew: heap=%D/%D\n", heap1, mstats.heap_alloc);
- runtime·throw("mstats skew");
- }
- obj = mstats.nmalloc - mstats.nfree;
-
- stats.nprocyield += runtime·work.markfor->nprocyield;
- stats.nosyield += runtime·work.markfor->nosyield;
- stats.nsleep += runtime·work.markfor->nsleep;
-
- runtime·printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects,"
- " %d goroutines,"
- " %d/%d/%d sweeps,"
- " %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n",
- mstats.numgc, runtime·work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000,
- heap0>>20, heap1>>20, obj,
- mstats.nmalloc, mstats.nfree,
- runtime·gcount(),
- runtime·work.nspan, runtime·sweep.nbgsweep, runtime·sweep.npausesweep,
- stats.nhandoff, stats.nhandoffcnt,
- runtime·work.markfor->nsteal, runtime·work.markfor->nstealcnt,
- stats.nprocyield, stats.nosyield, stats.nsleep);
- runtime·sweep.nbgsweep = runtime·sweep.npausesweep = 0;
- }
-
- // See the comment in the beginning of this function as to why we need the following.
- // Even if this is still stop-the-world, a concurrent exitsyscall can allocate a stack from heap.
- runtime·lock(&runtime·mheap.lock);
- // Free the old cached mark array if necessary.
- if(runtime·work.spans != nil && runtime·work.spans != runtime·mheap.allspans)
- runtime·SysFree(runtime·work.spans, runtime·work.nspan*sizeof(runtime·work.spans[0]), &mstats.other_sys);
- // Cache the current array for sweeping.
- runtime·mheap.gcspans = runtime·mheap.allspans;
- runtime·mheap.sweepgen += 2;
- runtime·mheap.sweepdone = false;
- runtime·work.spans = runtime·mheap.allspans;
- runtime·work.nspan = runtime·mheap.nspan;
- runtime·sweep.spanidx = 0;
- runtime·unlock(&runtime·mheap.lock);
-
- if(ConcurrentSweep && !args->eagersweep) {
- runtime·lock(&runtime·gclock);
- if(runtime·sweep.g == nil)
- runtime·sweep.g = runtime·newproc1(&bgsweepv, nil, 0, 0, gc);
- else if(runtime·sweep.parked) {
- runtime·sweep.parked = false;
- runtime·ready(runtime·sweep.g);
- }
- runtime·unlock(&runtime·gclock);
- } else {
- // Sweep all spans eagerly.
- while(runtime·sweepone() != -1)
- runtime·sweep.npausesweep++;
- // Do an additional mProf_GC, because all 'free' events are now real as well.
- runtime·mProf_GC();
- }
-
- runtime·mProf_GC();
- g->m->traceback = 0;
-
- if(DebugPtrs)
- runtime·printf("GC end\n");
-}
-
-extern uintptr runtime·sizeof_C_MStats;
-
-static void readmemstats_m(void);
-
-void
-runtime·readmemstats_m(void)
-{
- MStats *stats;
-
- stats = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
-
- runtime·updatememstats(nil);
- // Size of the trailing by_size array differs between Go and C,
- // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
- runtime·memmove(stats, &mstats, runtime·sizeof_C_MStats);
-
- // Stack numbers are part of the heap numbers, separate those out for user consumption
- stats->stacks_sys = stats->stacks_inuse;
- stats->heap_inuse -= stats->stacks_inuse;
- stats->heap_sys -= stats->stacks_inuse;
-}
-
-static void readgcstats_m(void);
-
-#pragma textflag NOSPLIT
-void
-runtime∕debug·readGCStats(Slice *pauses)
-{
- void (*fn)(void);
-
- g->m->ptrarg[0] = pauses;
- fn = readgcstats_m;
- runtime·onM(&fn);
-}
-
-static void
-readgcstats_m(void)
-{
- Slice *pauses;
- uint64 *p;
- uint32 i, j, n;
-
- pauses = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
-
- // Calling code in runtime/debug should make the slice large enough.
- if(pauses->cap < nelem(mstats.pause_ns)+3)
- runtime·throw("runtime: short slice passed to readGCStats");
-
- // Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns.
- p = (uint64*)pauses->array;
- runtime·lock(&runtime·mheap.lock);
-
- n = mstats.numgc;
- if(n > nelem(mstats.pause_ns))
- n = nelem(mstats.pause_ns);
-
- // The pause buffer is circular. The most recent pause is at
- // pause_ns[(numgc-1)%nelem(pause_ns)], and then backward
- // from there to go back farther in time. We deliver the times
- // most recent first (in p[0]).
- for(i=0; i<n; i++) {
- j = (mstats.numgc-1-i)%nelem(mstats.pause_ns);
- p[i] = mstats.pause_ns[j];
- p[n+i] = mstats.pause_end[j];
- }
-
- p[n+n] = mstats.last_gc;
- p[n+n+1] = mstats.numgc;
- p[n+n+2] = mstats.pause_total_ns;
- runtime·unlock(&runtime·mheap.lock);
- pauses->len = n+n+3;
-}
-
-void
-runtime·setgcpercent_m(void)
-{
- int32 in;
- int32 out;
-
- in = (int32)(intptr)g->m->scalararg[0];
-
- runtime·lock(&runtime·mheap.lock);
- out = runtime·gcpercent;
- if(in < 0)
- in = -1;
- runtime·gcpercent = in;
- runtime·unlock(&runtime·mheap.lock);
-
- g->m->scalararg[0] = (uintptr)(intptr)out;
-}
-
-static void
-gchelperstart(void)
-{
- if(g->m->helpgc < 0 || g->m->helpgc >= MaxGcproc)
- runtime·throw("gchelperstart: bad m->helpgc");
- if(g != g->m->g0)
- runtime·throw("gchelper not running on g0 stack");
-}
-
-G*
-runtime·wakefing(void)
-{
- G *res;
-
- res = nil;
- runtime·lock(&runtime·finlock);
- if(runtime·fingwait && runtime·fingwake) {
- runtime·fingwait = false;
- runtime·fingwake = false;
- res = runtime·fing;
- }
- runtime·unlock(&runtime·finlock);
- return res;
-}
-
-// Recursively unrolls GC program in prog.
-// mask is where to store the result.
-// ppos is a pointer to position in mask, in bits.
-// sparse says to generate 4-bits per word mask for heap (2-bits for data/bss otherwise).
-static byte*
-unrollgcprog1(byte *mask, byte *prog, uintptr *ppos, bool inplace, bool sparse)
-{
- uintptr pos, siz, i, off;
- byte *arena_start, *prog1, v, *bitp, shift;
-
- arena_start = runtime·mheap.arena_start;
- pos = *ppos;
- for(;;) {
- switch(prog[0]) {
- case insData:
- prog++;
- siz = prog[0];
- prog++;
- for(i = 0; i < siz; i++) {
- v = prog[i/PointersPerByte];
- v >>= (i%PointersPerByte)*BitsPerPointer;
- v &= BitsMask;
- if(inplace) {
- // Store directly into GC bitmap.
- off = (uintptr*)(mask+pos) - (uintptr*)arena_start;
- bitp = arena_start - off/wordsPerBitmapByte - 1;
- shift = (off % wordsPerBitmapByte) * gcBits;
- if(shift==0)
- *bitp = 0;
- *bitp |= v<<(shift+2);
- pos += PtrSize;
- } else if(sparse) {
- // 4-bits per word
- v <<= (pos%8)+2;
- mask[pos/8] |= v;
- pos += gcBits;
- } else {
- // 2-bits per word
- v <<= pos%8;
- mask[pos/8] |= v;
- pos += BitsPerPointer;
- }
- }
- prog += ROUND(siz*BitsPerPointer, 8)/8;
- break;
- case insArray:
- prog++;
- siz = 0;
- for(i = 0; i < PtrSize; i++)
- siz = (siz<<8) + prog[PtrSize-i-1];
- prog += PtrSize;
- prog1 = nil;
- for(i = 0; i < siz; i++)
- prog1 = unrollgcprog1(mask, prog, &pos, inplace, sparse);
- if(prog1[0] != insArrayEnd)
- runtime·throw("unrollgcprog: array does not end with insArrayEnd");
- prog = prog1+1;
- break;
- case insArrayEnd:
- case insEnd:
- *ppos = pos;
- return prog;
- default:
- runtime·throw("unrollgcprog: unknown instruction");
- }
- }
-}
-
-// Unrolls GC program prog for data/bss, returns dense GC mask.
-static BitVector
-unrollglobgcprog(byte *prog, uintptr size)
-{
- byte *mask;
- uintptr pos, masksize;
-
- masksize = ROUND(ROUND(size, PtrSize)/PtrSize*BitsPerPointer, 8)/8;
- mask = runtime·persistentalloc(masksize+1, 0, &mstats.gc_sys);
- mask[masksize] = 0xa1;
- pos = 0;
- prog = unrollgcprog1(mask, prog, &pos, false, false);
- if(pos != size/PtrSize*BitsPerPointer) {
- runtime·printf("unrollglobgcprog: bad program size, got %D, expect %D\n",
- (uint64)pos, (uint64)size/PtrSize*BitsPerPointer);
- runtime·throw("unrollglobgcprog: bad program size");
- }
- if(prog[0] != insEnd)
- runtime·throw("unrollglobgcprog: program does not end with insEnd");
- if(mask[masksize] != 0xa1)
- runtime·throw("unrollglobgcprog: overflow");
- return (BitVector){masksize*8, mask};
-}
-
-void
-runtime·unrollgcproginplace_m(void)
-{
- uintptr size, size0, pos, off;
- byte *arena_start, *prog, *bitp, shift;
- Type *typ;
- void *v;
-
- v = g->m->ptrarg[0];
- typ = g->m->ptrarg[1];
- size = g->m->scalararg[0];
- size0 = g->m->scalararg[1];
- g->m->ptrarg[0] = nil;
- g->m->ptrarg[1] = nil;
-
- pos = 0;
- prog = (byte*)typ->gc[1];
- while(pos != size0)
- unrollgcprog1(v, prog, &pos, true, true);
- // Mark first word as bitAllocated.
- arena_start = runtime·mheap.arena_start;
- off = (uintptr*)v - (uintptr*)arena_start;
- bitp = arena_start - off/wordsPerBitmapByte - 1;
- shift = (off % wordsPerBitmapByte) * gcBits;
- *bitp |= bitBoundary<<shift;
- // Mark word after last as BitsDead.
- if(size0 < size) {
- off = (uintptr*)((byte*)v + size0) - (uintptr*)arena_start;
- bitp = arena_start - off/wordsPerBitmapByte - 1;
- shift = (off % wordsPerBitmapByte) * gcBits;
- *bitp &= ~(bitPtrMask<<shift) | ((uintptr)BitsDead<<(shift+2));
- }
-}
-
-// Unrolls GC program in typ->gc[1] into typ->gc[0]
-void
-runtime·unrollgcprog_m(void)
-{
- static Mutex lock;
- Type *typ;
- byte *mask, *prog;
- uintptr pos;
- uint32 x;
-
- typ = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
-
- runtime·lock(&lock);
- mask = (byte*)typ->gc[0];
- if(mask[0] == 0) {
- pos = 8; // skip the unroll flag
- prog = (byte*)typ->gc[1];
- prog = unrollgcprog1(mask, prog, &pos, false, true);
- if(prog[0] != insEnd)
- runtime·throw("unrollgcprog: program does not end with insEnd");
- if(((typ->size/PtrSize)%2) != 0) {
- // repeat the program twice
- prog = (byte*)typ->gc[1];
- unrollgcprog1(mask, prog, &pos, false, true);
- }
- // atomic way to say mask[0] = 1
- x = ((uint32*)mask)[0];
- runtime·atomicstore((uint32*)mask, x|1);
- }
- runtime·unlock(&lock);
-}
-
-// mark the span of memory at v as having n blocks of the given size.
-// if leftover is true, there is left over space at the end of the span.
-void
-runtime·markspan(void *v, uintptr size, uintptr n, bool leftover)
-{
- uintptr i, off, step;
- byte *b;
-
- if((byte*)v+size*n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
- runtime·throw("markspan: bad pointer");
-
- // Find bits of the beginning of the span.
- off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset
- b = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
- if((off%wordsPerBitmapByte) != 0)
- runtime·throw("markspan: unaligned length");
-
- // Okay to use non-atomic ops here, because we control
- // the entire span, and each bitmap byte has bits for only
- // one span, so no other goroutines are changing these bitmap words.
-
- if(size == PtrSize) {
- // Possible only on 64-bits (minimal size class is 8 bytes).
- // Poor man's memset(0x11).
- if(0x11 != ((bitBoundary+BitsDead)<<gcBits) + (bitBoundary+BitsDead))
- runtime·throw("markspan: bad bits");
- if((n%(wordsPerBitmapByte*PtrSize)) != 0)
- runtime·throw("markspan: unaligned length");
- b = b - n/wordsPerBitmapByte + 1; // find first byte
- if(((uintptr)b%PtrSize) != 0)
- runtime·throw("markspan: unaligned pointer");
- for(i = 0; i != n; i += wordsPerBitmapByte*PtrSize, b += PtrSize)
- *(uintptr*)b = (uintptr)0x1111111111111111ULL; // bitBoundary+BitsDead
- return;
- }
-
- if(leftover)
- n++; // mark a boundary just past end of last block too
- step = size/(PtrSize*wordsPerBitmapByte);
- for(i = 0; i != n; i++, b -= step)
- *b = bitBoundary|(BitsDead<<2);
-}
-
-// unmark the span of memory at v of length n bytes.
-void
-runtime·unmarkspan(void *v, uintptr n)
-{
- uintptr off;
- byte *b;
-
- if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
- runtime·throw("markspan: bad pointer");
-
- off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset
- if((off % (PtrSize*wordsPerBitmapByte)) != 0)
- runtime·throw("markspan: unaligned pointer");
- b = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
- n /= PtrSize;
- if(n%(PtrSize*wordsPerBitmapByte) != 0)
- runtime·throw("unmarkspan: unaligned length");
- // Okay to use non-atomic ops here, because we control
- // the entire span, and each bitmap word has bits for only
- // one span, so no other goroutines are changing these
- // bitmap words.
- n /= wordsPerBitmapByte;
- runtime·memclr(b - n + 1, n);
-}
-
-void
-runtime·MHeap_MapBits(MHeap *h)
-{
- // Caller has added extra mappings to the arena.
- // Add extra mappings of bitmap words as needed.
- // We allocate extra bitmap pieces in chunks of bitmapChunk.
- enum {
- bitmapChunk = 8192
- };
- uintptr n;
-
- n = (h->arena_used - h->arena_start) / (PtrSize*wordsPerBitmapByte);
- n = ROUND(n, bitmapChunk);
- n = ROUND(n, PhysPageSize);
- if(h->bitmap_mapped >= n)
- return;
-
- runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, h->arena_reserved, &mstats.gc_sys);
- h->bitmap_mapped = n;
-}
-
-static bool
-getgcmaskcb(Stkframe *frame, void *ctxt)
-{
- Stkframe *frame0;
-
- frame0 = ctxt;
- if(frame->sp <= frame0->sp && frame0->sp < frame->varp) {
- *frame0 = *frame;
- return false;
- }
- return true;
-}
-
-// Returns GC type info for object p for testing.
-void
-runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
-{
- Stkframe frame;
- uintptr i, n, off;
- byte *base, bits, shift, *b;
- bool (*cb)(Stkframe*, void*);
-
- *mask = nil;
- *len = 0;
-
- // data
- if(p >= runtime·data && p < runtime·edata) {
- n = ((PtrType*)t)->elem->size;
- *len = n/PtrSize;
- *mask = runtime·mallocgc(*len, nil, FlagNoScan);
- for(i = 0; i < n; i += PtrSize) {
- off = (p+i-runtime·data)/PtrSize;
- bits = (runtime·gcdatamask.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
- (*mask)[i/PtrSize] = bits;
- }
- return;
- }
- // bss
- if(p >= runtime·bss && p < runtime·ebss) {
- n = ((PtrType*)t)->elem->size;
- *len = n/PtrSize;
- *mask = runtime·mallocgc(*len, nil, FlagNoScan);
- for(i = 0; i < n; i += PtrSize) {
- off = (p+i-runtime·bss)/PtrSize;
- bits = (runtime·gcbssmask.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
- (*mask)[i/PtrSize] = bits;
- }
- return;
- }
- // heap
- if(runtime·mlookup(p, &base, &n, nil)) {
- *len = n/PtrSize;
- *mask = runtime·mallocgc(*len, nil, FlagNoScan);
- for(i = 0; i < n; i += PtrSize) {
- off = (uintptr*)(base+i) - (uintptr*)runtime·mheap.arena_start;
- b = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
- shift = (off % wordsPerBitmapByte) * gcBits;
- bits = (*b >> (shift+2))&BitsMask;
- (*mask)[i/PtrSize] = bits;
- }
- return;
- }
- // stack
- frame.fn = nil;
- frame.sp = (uintptr)p;
- cb = getgcmaskcb;
- runtime·gentraceback(g->m->curg->sched.pc, g->m->curg->sched.sp, 0, g->m->curg, 0, nil, 1000, &cb, &frame, 0);
- if(frame.fn != nil) {
- Func *f;
- StackMap *stackmap;
- BitVector bv;
- uintptr size;
- uintptr targetpc;
- int32 pcdata;
-
- f = frame.fn;
- targetpc = frame.continpc;
- if(targetpc == 0)
- return;
- if(targetpc != f->entry)
- targetpc--;
- pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
- if(pcdata == -1)
- return;
- stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
- if(stackmap == nil || stackmap->n <= 0)
- return;
- bv = runtime·stackmapdata(stackmap, pcdata);
- size = bv.n/BitsPerPointer*PtrSize;
- n = ((PtrType*)t)->elem->size;
- *len = n/PtrSize;
- *mask = runtime·mallocgc(*len, nil, FlagNoScan);
- for(i = 0; i < n; i += PtrSize) {
- off = (p+i-(byte*)frame.varp+size)/PtrSize;
- bits = (bv.bytedata[off*BitsPerPointer/8] >> ((off*BitsPerPointer)%8))&BitsMask;
- (*mask)[i/PtrSize] = bits;
- }
- }
-}
-
-void runtime·gc_unixnanotime(int64 *now);
-
-int64
-runtime·unixnanotime(void)
-{
- int64 now;
-
- runtime·gc_unixnanotime(&now);
- return now;
-}
diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go
index cbf5e9cfd..38406f33a 100644
--- a/src/runtime/mgc0.go
+++ b/src/runtime/mgc0.go
@@ -28,7 +28,7 @@ func gc_unixnanotime(now *int64) {
func freeOSMemory() {
gogc(2) // force GC and do eager sweep
- onM(scavenge_m)
+ systemstack(scavenge_m)
}
var poolcleanup func()
@@ -76,10 +76,8 @@ func clearpools() {
}
}
-func gosweepone() uintptr
-func gosweepdone() bool
-
func bgsweep() {
+ sweep.g = getg()
getg().issystem = true
for {
for gosweepone() != ^uintptr(0) {
diff --git a/src/runtime/mgc0.h b/src/runtime/mgc0.h
index 64f818914..62726b4f0 100644
--- a/src/runtime/mgc0.h
+++ b/src/runtime/mgc0.h
@@ -2,77 +2,19 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Garbage collector (GC)
+// Used by cmd/gc.
enum {
- // Four bits per word (see #defines below).
gcBits = 4,
- wordsPerBitmapByte = 8/gcBits,
-
- // GC type info programs.
- // The programs allow to store type info required for GC in a compact form.
- // Most importantly arrays take O(1) space instead of O(n).
- // The program grammar is:
- //
- // Program = {Block} "insEnd"
- // Block = Data | Array
- // Data = "insData" DataSize DataBlock
- // DataSize = int // size of the DataBlock in bit pairs, 1 byte
- // DataBlock = binary // dense GC mask (2 bits per word) of size ]DataSize/4[ bytes
- // Array = "insArray" ArrayLen Block "insArrayEnd"
- // ArrayLen = int // length of the array, 8 bytes (4 bytes for 32-bit arch)
- //
- // Each instruction (insData, insArray, etc) is 1 byte.
- // For example, for type struct { x []byte; y [20]struct{ z int; w *byte }; }
- // the program looks as:
- //
- // insData 3 (BitsMultiWord BitsSlice BitsScalar)
- // insArray 20 insData 2 (BitsScalar BitsPointer) insArrayEnd insEnd
- //
- // Total size of the program is 17 bytes (13 bytes on 32-bits).
- // The corresponding GC mask would take 43 bytes (it would be repeated
- // because the type has odd number of words).
+ BitsPerPointer = 2,
+ BitsDead = 0,
+ BitsScalar = 1,
+ BitsPointer = 2,
+ BitsMask = 3,
+ PointersPerByte = 8/BitsPerPointer,
+ MaxGCMask = 64,
insData = 1,
insArray,
insArrayEnd,
insEnd,
-
- // Pointer map
- BitsPerPointer = 2,
- BitsMask = (1<<BitsPerPointer)-1,
- PointersPerByte = 8/BitsPerPointer,
-
- // If you change these, also change scanblock.
- // scanblock does "if(bits == BitsScalar || bits == BitsDead)" as "if(bits <= BitsScalar)".
- BitsDead = 0,
- BitsScalar = 1,
- BitsPointer = 2,
- BitsMultiWord = 3,
- // BitsMultiWord will be set for the first word of a multi-word item.
- // When it is set, one of the following will be set for the second word.
- // NOT USED ANYMORE: BitsString = 0,
- // NOT USED ANYMORE: BitsSlice = 1,
- BitsIface = 2,
- BitsEface = 3,
-
- // 64 bytes cover objects of size 1024/512 on 64/32 bits, respectively.
- MaxGCMask = 64,
-};
-
-// Bits in per-word bitmap.
-// #defines because we shift the values beyond 32 bits.
-//
-// Each word in the bitmap describes wordsPerBitmapWord words
-// of heap memory. There are 4 bitmap bits dedicated to each heap word,
-// so on a 64-bit system there is one bitmap word per 16 heap words.
-//
-// The bitmap starts at mheap.arena_start and extends *backward* from
-// there. On a 64-bit system the off'th word in the arena is tracked by
-// the off/16+1'th word before mheap.arena_start. (On a 32-bit system,
-// the only difference is that the divisor is 8.)
-enum {
- bitBoundary = 1, // boundary of an object
- bitMarked = 2, // marked object
- bitMask = bitBoundary | bitMarked,
- bitPtrMask = BitsMask<<2,
};
diff --git a/src/runtime/mgc1.go b/src/runtime/mgc1.go
new file mode 100644
index 000000000..d1aab4554
--- /dev/null
+++ b/src/runtime/mgc1.go
@@ -0,0 +1,77 @@
+// Copyright 2012 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.
+
+// Garbage collector (GC)
+
+package runtime
+
+const (
+ // Four bits per word (see #defines below).
+ gcBits = 4
+ wordsPerBitmapByte = 8 / gcBits
+)
+
+const (
+ // GC type info programs.
+ // The programs allow to store type info required for GC in a compact form.
+ // Most importantly arrays take O(1) space instead of O(n).
+ // The program grammar is:
+ //
+ // Program = {Block} "insEnd"
+ // Block = Data | Array
+ // Data = "insData" DataSize DataBlock
+ // DataSize = int // size of the DataBlock in bit pairs, 1 byte
+ // DataBlock = binary // dense GC mask (2 bits per word) of size ]DataSize/4[ bytes
+ // Array = "insArray" ArrayLen Block "insArrayEnd"
+ // ArrayLen = int // length of the array, 8 bytes (4 bytes for 32-bit arch)
+ //
+ // Each instruction (insData, insArray, etc) is 1 byte.
+ // For example, for type struct { x []byte; y [20]struct{ z int; w *byte }; }
+ // the program looks as:
+ //
+ // insData 3 (BitsPointer BitsScalar BitsScalar)
+ // insArray 20 insData 2 (BitsScalar BitsPointer) insArrayEnd insEnd
+ //
+ // Total size of the program is 17 bytes (13 bytes on 32-bits).
+ // The corresponding GC mask would take 43 bytes (it would be repeated
+ // because the type has odd number of words).
+ insData = 1 + iota
+ insArray
+ insArrayEnd
+ insEnd
+)
+
+const (
+ // Pointer map
+ _BitsPerPointer = 2
+ _BitsMask = (1 << _BitsPerPointer) - 1
+ _PointersPerByte = 8 / _BitsPerPointer
+
+ // If you change these, also change scanblock.
+ // scanblock does "if(bits == BitsScalar || bits == BitsDead)" as "if(bits <= BitsScalar)".
+ _BitsDead = 0
+ _BitsScalar = 1
+ _BitsPointer = 2
+
+ // 64 bytes cover objects of size 1024/512 on 64/32 bits, respectively.
+ _MaxGCMask = 64
+)
+
+// Bits in per-word bitmap.
+// #defines because we shift the values beyond 32 bits.
+//
+// Each word in the bitmap describes wordsPerBitmapWord words
+// of heap memory. There are 4 bitmap bits dedicated to each heap word,
+// so on a 64-bit system there is one bitmap word per 16 heap words.
+//
+// The bitmap starts at mheap.arena_start and extends *backward* from
+// there. On a 64-bit system the off'th word in the arena is tracked by
+// the off/16+1'th word before mheap.arena_start. (On a 32-bit system,
+// the only difference is that the divisor is 8.)
+const (
+ bitBoundary = 1 // boundary of an object
+ bitMarked = 2 // marked object
+ bitMask = bitBoundary | bitMarked
+ bitPtrMask = _BitsMask << 2
+)
diff --git a/src/runtime/mheap.c b/src/runtime/mheap.c
deleted file mode 100644
index bb203d5ce..000000000
--- a/src/runtime/mheap.c
+++ /dev/null
@@ -1,889 +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.
-
-// Page heap.
-//
-// See malloc.h for overview.
-//
-// When a MSpan is in the heap free list, state == MSpanFree
-// and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
-//
-// When a MSpan is allocated, state == MSpanInUse or MSpanStack
-// and heapmap(i) == span for all s->start <= i < s->start+s->npages.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-static MSpan *MHeap_AllocSpanLocked(MHeap*, uintptr);
-static void MHeap_FreeSpanLocked(MHeap*, MSpan*, bool, bool);
-static bool MHeap_Grow(MHeap*, uintptr);
-static MSpan *MHeap_AllocLarge(MHeap*, uintptr);
-static MSpan *BestFit(MSpan*, uintptr, MSpan*);
-
-static void
-RecordSpan(void *vh, byte *p)
-{
- MHeap *h;
- MSpan *s;
- MSpan **all;
- uint32 cap;
-
- h = vh;
- s = (MSpan*)p;
- if(h->nspan >= h->nspancap) {
- cap = 64*1024/sizeof(all[0]);
- if(cap < h->nspancap*3/2)
- cap = h->nspancap*3/2;
- all = (MSpan**)runtime·sysAlloc(cap*sizeof(all[0]), &mstats.other_sys);
- if(all == nil)
- runtime·throw("runtime: cannot allocate memory");
- if(h->allspans) {
- runtime·memmove(all, h->allspans, h->nspancap*sizeof(all[0]));
- // Don't free the old array if it's referenced by sweep.
- // See the comment in mgc0.c.
- if(h->allspans != runtime·mheap.gcspans)
- runtime·SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
- }
- h->allspans = all;
- h->nspancap = cap;
- }
- h->allspans[h->nspan++] = s;
-}
-
-// Initialize the heap; fetch memory using alloc.
-void
-runtime·MHeap_Init(MHeap *h)
-{
- uint32 i;
-
- runtime·FixAlloc_Init(&h->spanalloc, sizeof(MSpan), RecordSpan, h, &mstats.mspan_sys);
- runtime·FixAlloc_Init(&h->cachealloc, sizeof(MCache), nil, nil, &mstats.mcache_sys);
- runtime·FixAlloc_Init(&h->specialfinalizeralloc, sizeof(SpecialFinalizer), nil, nil, &mstats.other_sys);
- runtime·FixAlloc_Init(&h->specialprofilealloc, sizeof(SpecialProfile), nil, nil, &mstats.other_sys);
- // h->mapcache needs no init
- for(i=0; i<nelem(h->free); i++) {
- runtime·MSpanList_Init(&h->free[i]);
- runtime·MSpanList_Init(&h->busy[i]);
- }
- runtime·MSpanList_Init(&h->freelarge);
- runtime·MSpanList_Init(&h->busylarge);
- for(i=0; i<nelem(h->central); i++)
- runtime·MCentral_Init(&h->central[i].mcentral, i);
-}
-
-void
-runtime·MHeap_MapSpans(MHeap *h)
-{
- uintptr n;
-
- // Map spans array, PageSize at a time.
- n = (uintptr)h->arena_used;
- n -= (uintptr)h->arena_start;
- n = n / PageSize * sizeof(h->spans[0]);
- n = ROUND(n, PhysPageSize);
- if(h->spans_mapped >= n)
- return;
- runtime·SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, h->arena_reserved, &mstats.other_sys);
- h->spans_mapped = n;
-}
-
-// Sweeps spans in list until reclaims at least npages into heap.
-// Returns the actual number of pages reclaimed.
-static uintptr
-MHeap_ReclaimList(MHeap *h, MSpan *list, uintptr npages)
-{
- MSpan *s;
- uintptr n;
- uint32 sg;
-
- n = 0;
- sg = runtime·mheap.sweepgen;
-retry:
- for(s = list->next; s != list; s = s->next) {
- if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
- runtime·MSpanList_Remove(s);
- // swept spans are at the end of the list
- runtime·MSpanList_InsertBack(list, s);
- runtime·unlock(&h->lock);
- n += runtime·MSpan_Sweep(s, false);
- runtime·lock(&h->lock);
- if(n >= npages)
- return n;
- // the span could have been moved elsewhere
- goto retry;
- }
- if(s->sweepgen == sg-1) {
- // the span is being sweept by background sweeper, skip
- continue;
- }
- // already swept empty span,
- // all subsequent ones must also be either swept or in process of sweeping
- break;
- }
- return n;
-}
-
-// Sweeps and reclaims at least npage pages into heap.
-// Called before allocating npage pages.
-static void
-MHeap_Reclaim(MHeap *h, uintptr npage)
-{
- uintptr reclaimed, n;
-
- // First try to sweep busy spans with large objects of size >= npage,
- // this has good chances of reclaiming the necessary space.
- for(n=npage; n < nelem(h->busy); n++) {
- if(MHeap_ReclaimList(h, &h->busy[n], npage))
- return; // Bingo!
- }
-
- // Then -- even larger objects.
- if(MHeap_ReclaimList(h, &h->busylarge, npage))
- return; // Bingo!
-
- // Now try smaller objects.
- // One such object is not enough, so we need to reclaim several of them.
- reclaimed = 0;
- for(n=0; n < npage && n < nelem(h->busy); n++) {
- reclaimed += MHeap_ReclaimList(h, &h->busy[n], npage-reclaimed);
- if(reclaimed >= npage)
- return;
- }
-
- // Now sweep everything that is not yet swept.
- runtime·unlock(&h->lock);
- for(;;) {
- n = runtime·sweepone();
- if(n == -1) // all spans are swept
- break;
- reclaimed += n;
- if(reclaimed >= npage)
- break;
- }
- runtime·lock(&h->lock);
-}
-
-// Allocate a new span of npage pages from the heap for GC'd memory
-// and record its size class in the HeapMap and HeapMapCache.
-static MSpan*
-mheap_alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large)
-{
- MSpan *s;
-
- if(g != g->m->g0)
- runtime·throw("mheap_alloc not on M stack");
- runtime·lock(&h->lock);
-
- // To prevent excessive heap growth, before allocating n pages
- // we need to sweep and reclaim at least n pages.
- if(!h->sweepdone)
- MHeap_Reclaim(h, npage);
-
- // transfer stats from cache to global
- mstats.heap_alloc += g->m->mcache->local_cachealloc;
- g->m->mcache->local_cachealloc = 0;
- mstats.tinyallocs += g->m->mcache->local_tinyallocs;
- g->m->mcache->local_tinyallocs = 0;
-
- s = MHeap_AllocSpanLocked(h, npage);
- if(s != nil) {
- // Record span info, because gc needs to be
- // able to map interior pointer to containing span.
- runtime·atomicstore(&s->sweepgen, h->sweepgen);
- s->state = MSpanInUse;
- s->freelist = nil;
- s->ref = 0;
- s->sizeclass = sizeclass;
- s->elemsize = (sizeclass==0 ? s->npages<<PageShift : runtime·class_to_size[sizeclass]);
-
- // update stats, sweep lists
- if(large) {
- mstats.heap_objects++;
- mstats.heap_alloc += npage<<PageShift;
- // Swept spans are at the end of lists.
- if(s->npages < nelem(h->free))
- runtime·MSpanList_InsertBack(&h->busy[s->npages], s);
- else
- runtime·MSpanList_InsertBack(&h->busylarge, s);
- }
- }
- runtime·unlock(&h->lock);
- return s;
-}
-
-static void
-mheap_alloc_m(G *gp)
-{
- MHeap *h;
- MSpan *s;
-
- h = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- s = mheap_alloc(h, g->m->scalararg[0], g->m->scalararg[1], g->m->scalararg[2]);
- g->m->ptrarg[0] = s;
-
- runtime·gogo(&gp->sched);
-}
-
-MSpan*
-runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero)
-{
- MSpan *s;
- void (*fn)(G*);
-
- // Don't do any operations that lock the heap on the G stack.
- // It might trigger stack growth, and the stack growth code needs
- // to be able to allocate heap.
- if(g == g->m->g0) {
- s = mheap_alloc(h, npage, sizeclass, large);
- } else {
- g->m->ptrarg[0] = h;
- g->m->scalararg[0] = npage;
- g->m->scalararg[1] = sizeclass;
- g->m->scalararg[2] = large;
- fn = mheap_alloc_m;
- runtime·mcall(&fn);
- s = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- }
- if(s != nil) {
- if(needzero && s->needzero)
- runtime·memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
- s->needzero = 0;
- }
- return s;
-}
-
-MSpan*
-runtime·MHeap_AllocStack(MHeap *h, uintptr npage)
-{
- MSpan *s;
-
- if(g != g->m->g0)
- runtime·throw("mheap_allocstack not on M stack");
- runtime·lock(&h->lock);
- s = MHeap_AllocSpanLocked(h, npage);
- if(s != nil) {
- s->state = MSpanStack;
- s->freelist = nil;
- s->ref = 0;
- mstats.stacks_inuse += s->npages<<PageShift;
- }
- runtime·unlock(&h->lock);
- return s;
-}
-
-// Allocates a span of the given size. h must be locked.
-// The returned span has been removed from the
-// free list, but its state is still MSpanFree.
-static MSpan*
-MHeap_AllocSpanLocked(MHeap *h, uintptr npage)
-{
- uintptr n;
- MSpan *s, *t;
- pageID p;
-
- // Try in fixed-size lists up to max.
- for(n=npage; n < nelem(h->free); n++) {
- if(!runtime·MSpanList_IsEmpty(&h->free[n])) {
- s = h->free[n].next;
- goto HaveSpan;
- }
- }
-
- // Best fit in list of large spans.
- if((s = MHeap_AllocLarge(h, npage)) == nil) {
- if(!MHeap_Grow(h, npage))
- return nil;
- if((s = MHeap_AllocLarge(h, npage)) == nil)
- return nil;
- }
-
-HaveSpan:
- // Mark span in use.
- if(s->state != MSpanFree)
- runtime·throw("MHeap_AllocLocked - MSpan not free");
- if(s->npages < npage)
- runtime·throw("MHeap_AllocLocked - bad npages");
- runtime·MSpanList_Remove(s);
- if(s->next != nil || s->prev != nil)
- runtime·throw("still in list");
- if(s->npreleased > 0) {
- runtime·SysUsed((void*)(s->start<<PageShift), s->npages<<PageShift);
- mstats.heap_released -= s->npreleased<<PageShift;
- s->npreleased = 0;
- }
-
- if(s->npages > npage) {
- // Trim extra and put it back in the heap.
- t = runtime·FixAlloc_Alloc(&h->spanalloc);
- runtime·MSpan_Init(t, s->start + npage, s->npages - npage);
- s->npages = npage;
- p = t->start;
- p -= ((uintptr)h->arena_start>>PageShift);
- if(p > 0)
- h->spans[p-1] = s;
- h->spans[p] = t;
- h->spans[p+t->npages-1] = t;
- t->needzero = s->needzero;
- s->state = MSpanStack; // prevent coalescing with s
- t->state = MSpanStack;
- MHeap_FreeSpanLocked(h, t, false, false);
- t->unusedsince = s->unusedsince; // preserve age (TODO: wrong: t is possibly merged and/or deallocated at this point)
- s->state = MSpanFree;
- }
- s->unusedsince = 0;
-
- p = s->start;
- p -= ((uintptr)h->arena_start>>PageShift);
- for(n=0; n<npage; n++)
- h->spans[p+n] = s;
-
- mstats.heap_inuse += npage<<PageShift;
- mstats.heap_idle -= npage<<PageShift;
-
- //runtime·printf("spanalloc %p\n", s->start << PageShift);
- if(s->next != nil || s->prev != nil)
- runtime·throw("still in list");
- return s;
-}
-
-// Allocate a span of exactly npage pages from the list of large spans.
-static MSpan*
-MHeap_AllocLarge(MHeap *h, uintptr npage)
-{
- return BestFit(&h->freelarge, npage, nil);
-}
-
-// Search list for smallest span with >= npage pages.
-// If there are multiple smallest spans, take the one
-// with the earliest starting address.
-static MSpan*
-BestFit(MSpan *list, uintptr npage, MSpan *best)
-{
- MSpan *s;
-
- for(s=list->next; s != list; s=s->next) {
- if(s->npages < npage)
- continue;
- if(best == nil
- || s->npages < best->npages
- || (s->npages == best->npages && s->start < best->start))
- best = s;
- }
- return best;
-}
-
-// Try to add at least npage pages of memory to the heap,
-// returning whether it worked.
-static bool
-MHeap_Grow(MHeap *h, uintptr npage)
-{
- uintptr ask;
- void *v;
- MSpan *s;
- pageID p;
-
- // Ask for a big chunk, to reduce the number of mappings
- // the operating system needs to track; also amortizes
- // the overhead of an operating system mapping.
- // Allocate a multiple of 64kB.
- npage = ROUND(npage, (64<<10)/PageSize);
- ask = npage<<PageShift;
- if(ask < HeapAllocChunk)
- ask = HeapAllocChunk;
-
- v = runtime·MHeap_SysAlloc(h, ask);
- if(v == nil) {
- if(ask > (npage<<PageShift)) {
- ask = npage<<PageShift;
- v = runtime·MHeap_SysAlloc(h, ask);
- }
- if(v == nil) {
- runtime·printf("runtime: out of memory: cannot allocate %D-byte block (%D in use)\n", (uint64)ask, mstats.heap_sys);
- return false;
- }
- }
-
- // Create a fake "in use" span and free it, so that the
- // right coalescing happens.
- s = runtime·FixAlloc_Alloc(&h->spanalloc);
- runtime·MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
- p = s->start;
- p -= ((uintptr)h->arena_start>>PageShift);
- h->spans[p] = s;
- h->spans[p + s->npages - 1] = s;
- runtime·atomicstore(&s->sweepgen, h->sweepgen);
- s->state = MSpanInUse;
- MHeap_FreeSpanLocked(h, s, false, true);
- return true;
-}
-
-// Look up the span at the given address.
-// Address is guaranteed to be in map
-// and is guaranteed to be start or end of span.
-MSpan*
-runtime·MHeap_Lookup(MHeap *h, void *v)
-{
- uintptr p;
-
- p = (uintptr)v;
- p -= (uintptr)h->arena_start;
- return h->spans[p >> PageShift];
-}
-
-// Look up the span at the given address.
-// Address is *not* guaranteed to be in map
-// and may be anywhere in the span.
-// Map entries for the middle of a span are only
-// valid for allocated spans. Free spans may have
-// other garbage in their middles, so we have to
-// check for that.
-MSpan*
-runtime·MHeap_LookupMaybe(MHeap *h, void *v)
-{
- MSpan *s;
- pageID p, q;
-
- if((byte*)v < h->arena_start || (byte*)v >= h->arena_used)
- return nil;
- p = (uintptr)v>>PageShift;
- q = p;
- q -= (uintptr)h->arena_start >> PageShift;
- s = h->spans[q];
- if(s == nil || p < s->start || v >= s->limit || s->state != MSpanInUse)
- return nil;
- return s;
-}
-
-// Free the span back into the heap.
-static void
-mheap_free(MHeap *h, MSpan *s, int32 acct)
-{
- if(g != g->m->g0)
- runtime·throw("mheap_free not on M stack");
- runtime·lock(&h->lock);
- mstats.heap_alloc += g->m->mcache->local_cachealloc;
- g->m->mcache->local_cachealloc = 0;
- mstats.tinyallocs += g->m->mcache->local_tinyallocs;
- g->m->mcache->local_tinyallocs = 0;
- if(acct) {
- mstats.heap_alloc -= s->npages<<PageShift;
- mstats.heap_objects--;
- }
- MHeap_FreeSpanLocked(h, s, true, true);
- runtime·unlock(&h->lock);
-}
-
-static void
-mheap_free_m(G *gp)
-{
- MHeap *h;
- MSpan *s;
-
- h = g->m->ptrarg[0];
- s = g->m->ptrarg[1];
- g->m->ptrarg[0] = nil;
- g->m->ptrarg[1] = nil;
- mheap_free(h, s, g->m->scalararg[0]);
- runtime·gogo(&gp->sched);
-}
-
-void
-runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct)
-{
- void (*fn)(G*);
-
- if(g == g->m->g0) {
- mheap_free(h, s, acct);
- } else {
- g->m->ptrarg[0] = h;
- g->m->ptrarg[1] = s;
- g->m->scalararg[0] = acct;
- fn = mheap_free_m;
- runtime·mcall(&fn);
- }
-}
-
-void
-runtime·MHeap_FreeStack(MHeap *h, MSpan *s)
-{
- if(g != g->m->g0)
- runtime·throw("mheap_freestack not on M stack");
- s->needzero = 1;
- runtime·lock(&h->lock);
- mstats.stacks_inuse -= s->npages<<PageShift;
- MHeap_FreeSpanLocked(h, s, true, true);
- runtime·unlock(&h->lock);
-}
-
-static void
-MHeap_FreeSpanLocked(MHeap *h, MSpan *s, bool acctinuse, bool acctidle)
-{
- MSpan *t;
- pageID p;
-
- switch(s->state) {
- case MSpanStack:
- if(s->ref != 0)
- runtime·throw("MHeap_FreeSpanLocked - invalid stack free");
- break;
- case MSpanInUse:
- if(s->ref != 0 || s->sweepgen != h->sweepgen) {
- runtime·printf("MHeap_FreeSpanLocked - span %p ptr %p ref %d sweepgen %d/%d\n",
- s, s->start<<PageShift, s->ref, s->sweepgen, h->sweepgen);
- runtime·throw("MHeap_FreeSpanLocked - invalid free");
- }
- break;
- default:
- runtime·throw("MHeap_FreeSpanLocked - invalid span state");
- break;
- }
- if(acctinuse)
- mstats.heap_inuse -= s->npages<<PageShift;
- if(acctidle)
- mstats.heap_idle += s->npages<<PageShift;
- s->state = MSpanFree;
- runtime·MSpanList_Remove(s);
- // Stamp newly unused spans. The scavenger will use that
- // info to potentially give back some pages to the OS.
- s->unusedsince = runtime·nanotime();
- s->npreleased = 0;
-
- // Coalesce with earlier, later spans.
- p = s->start;
- p -= (uintptr)h->arena_start >> PageShift;
- if(p > 0 && (t = h->spans[p-1]) != nil && t->state != MSpanInUse && t->state != MSpanStack) {
- s->start = t->start;
- s->npages += t->npages;
- s->npreleased = t->npreleased; // absorb released pages
- s->needzero |= t->needzero;
- p -= t->npages;
- h->spans[p] = s;
- runtime·MSpanList_Remove(t);
- t->state = MSpanDead;
- runtime·FixAlloc_Free(&h->spanalloc, t);
- }
- if((p+s->npages)*sizeof(h->spans[0]) < h->spans_mapped && (t = h->spans[p+s->npages]) != nil && t->state != MSpanInUse && t->state != MSpanStack) {
- s->npages += t->npages;
- s->npreleased += t->npreleased;
- s->needzero |= t->needzero;
- h->spans[p + s->npages - 1] = s;
- runtime·MSpanList_Remove(t);
- t->state = MSpanDead;
- runtime·FixAlloc_Free(&h->spanalloc, t);
- }
-
- // Insert s into appropriate list.
- if(s->npages < nelem(h->free))
- runtime·MSpanList_Insert(&h->free[s->npages], s);
- else
- runtime·MSpanList_Insert(&h->freelarge, s);
-}
-
-static uintptr
-scavengelist(MSpan *list, uint64 now, uint64 limit)
-{
- uintptr released, sumreleased;
- MSpan *s;
-
- if(runtime·MSpanList_IsEmpty(list))
- return 0;
-
- sumreleased = 0;
- for(s=list->next; s != list; s=s->next) {
- if((now - s->unusedsince) > limit && s->npreleased != s->npages) {
- released = (s->npages - s->npreleased) << PageShift;
- mstats.heap_released += released;
- sumreleased += released;
- s->npreleased = s->npages;
- runtime·SysUnused((void*)(s->start << PageShift), s->npages << PageShift);
- }
- }
- return sumreleased;
-}
-
-void
-runtime·MHeap_Scavenge(int32 k, uint64 now, uint64 limit)
-{
- uint32 i;
- uintptr sumreleased;
- MHeap *h;
-
- h = &runtime·mheap;
- runtime·lock(&h->lock);
- sumreleased = 0;
- for(i=0; i < nelem(h->free); i++)
- sumreleased += scavengelist(&h->free[i], now, limit);
- sumreleased += scavengelist(&h->freelarge, now, limit);
- runtime·unlock(&h->lock);
-
- if(runtime·debug.gctrace > 0) {
- if(sumreleased > 0)
- runtime·printf("scvg%d: %D MB released\n", k, (uint64)sumreleased>>20);
- // TODO(dvyukov): these stats are incorrect as we don't subtract stack usage from heap.
- // But we can't call ReadMemStats on g0 holding locks.
- runtime·printf("scvg%d: inuse: %D, idle: %D, sys: %D, released: %D, consumed: %D (MB)\n",
- k, mstats.heap_inuse>>20, mstats.heap_idle>>20, mstats.heap_sys>>20,
- mstats.heap_released>>20, (mstats.heap_sys - mstats.heap_released)>>20);
- }
-}
-
-void
-runtime·scavenge_m(void)
-{
- runtime·MHeap_Scavenge(-1, ~(uintptr)0, 0);
-}
-
-// Initialize a new span with the given start and npages.
-void
-runtime·MSpan_Init(MSpan *span, pageID start, uintptr npages)
-{
- span->next = nil;
- span->prev = nil;
- span->start = start;
- span->npages = npages;
- span->freelist = nil;
- span->ref = 0;
- span->sizeclass = 0;
- span->incache = false;
- span->elemsize = 0;
- span->state = MSpanDead;
- span->unusedsince = 0;
- span->npreleased = 0;
- span->specialLock.key = 0;
- span->specials = nil;
- span->needzero = 0;
-}
-
-// Initialize an empty doubly-linked list.
-void
-runtime·MSpanList_Init(MSpan *list)
-{
- list->state = MSpanListHead;
- list->next = list;
- list->prev = list;
-}
-
-void
-runtime·MSpanList_Remove(MSpan *span)
-{
- if(span->prev == nil && span->next == nil)
- return;
- span->prev->next = span->next;
- span->next->prev = span->prev;
- span->prev = nil;
- span->next = nil;
-}
-
-bool
-runtime·MSpanList_IsEmpty(MSpan *list)
-{
- return list->next == list;
-}
-
-void
-runtime·MSpanList_Insert(MSpan *list, MSpan *span)
-{
- if(span->next != nil || span->prev != nil) {
- runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
- runtime·throw("MSpanList_Insert");
- }
- span->next = list->next;
- span->prev = list;
- span->next->prev = span;
- span->prev->next = span;
-}
-
-void
-runtime·MSpanList_InsertBack(MSpan *list, MSpan *span)
-{
- if(span->next != nil || span->prev != nil) {
- runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
- runtime·throw("MSpanList_Insert");
- }
- span->next = list;
- span->prev = list->prev;
- span->next->prev = span;
- span->prev->next = span;
-}
-
-// Adds the special record s to the list of special records for
-// the object p. All fields of s should be filled in except for
-// offset & next, which this routine will fill in.
-// Returns true if the special was successfully added, false otherwise.
-// (The add will fail only if a record with the same p and s->kind
-// already exists.)
-static bool
-addspecial(void *p, Special *s)
-{
- MSpan *span;
- Special **t, *x;
- uintptr offset;
- byte kind;
-
- span = runtime·MHeap_LookupMaybe(&runtime·mheap, p);
- if(span == nil)
- runtime·throw("addspecial on invalid pointer");
-
- // Ensure that the span is swept.
- // GC accesses specials list w/o locks. And it's just much safer.
- g->m->locks++;
- runtime·MSpan_EnsureSwept(span);
-
- offset = (uintptr)p - (span->start << PageShift);
- kind = s->kind;
-
- runtime·lock(&span->specialLock);
-
- // Find splice point, check for existing record.
- t = &span->specials;
- while((x = *t) != nil) {
- if(offset == x->offset && kind == x->kind) {
- runtime·unlock(&span->specialLock);
- g->m->locks--;
- return false; // already exists
- }
- if(offset < x->offset || (offset == x->offset && kind < x->kind))
- break;
- t = &x->next;
- }
- // Splice in record, fill in offset.
- s->offset = offset;
- s->next = x;
- *t = s;
- runtime·unlock(&span->specialLock);
- g->m->locks--;
- return true;
-}
-
-// Removes the Special record of the given kind for the object p.
-// Returns the record if the record existed, nil otherwise.
-// The caller must FixAlloc_Free the result.
-static Special*
-removespecial(void *p, byte kind)
-{
- MSpan *span;
- Special *s, **t;
- uintptr offset;
-
- span = runtime·MHeap_LookupMaybe(&runtime·mheap, p);
- if(span == nil)
- runtime·throw("removespecial on invalid pointer");
-
- // Ensure that the span is swept.
- // GC accesses specials list w/o locks. And it's just much safer.
- g->m->locks++;
- runtime·MSpan_EnsureSwept(span);
-
- offset = (uintptr)p - (span->start << PageShift);
-
- runtime·lock(&span->specialLock);
- t = &span->specials;
- while((s = *t) != nil) {
- // This function is used for finalizers only, so we don't check for
- // "interior" specials (p must be exactly equal to s->offset).
- if(offset == s->offset && kind == s->kind) {
- *t = s->next;
- runtime·unlock(&span->specialLock);
- g->m->locks--;
- return s;
- }
- t = &s->next;
- }
- runtime·unlock(&span->specialLock);
- g->m->locks--;
- return nil;
-}
-
-// Adds a finalizer to the object p. Returns true if it succeeded.
-bool
-runtime·addfinalizer(void *p, FuncVal *f, uintptr nret, Type *fint, PtrType *ot)
-{
- SpecialFinalizer *s;
-
- runtime·lock(&runtime·mheap.speciallock);
- s = runtime·FixAlloc_Alloc(&runtime·mheap.specialfinalizeralloc);
- runtime·unlock(&runtime·mheap.speciallock);
- s->special.kind = KindSpecialFinalizer;
- s->fn = f;
- s->nret = nret;
- s->fint = fint;
- s->ot = ot;
- if(addspecial(p, &s->special))
- return true;
-
- // There was an old finalizer
- runtime·lock(&runtime·mheap.speciallock);
- runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, s);
- runtime·unlock(&runtime·mheap.speciallock);
- return false;
-}
-
-// Removes the finalizer (if any) from the object p.
-void
-runtime·removefinalizer(void *p)
-{
- SpecialFinalizer *s;
-
- s = (SpecialFinalizer*)removespecial(p, KindSpecialFinalizer);
- if(s == nil)
- return; // there wasn't a finalizer to remove
- runtime·lock(&runtime·mheap.speciallock);
- runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, s);
- runtime·unlock(&runtime·mheap.speciallock);
-}
-
-// Set the heap profile bucket associated with addr to b.
-void
-runtime·setprofilebucket_m(void)
-{
- void *p;
- Bucket *b;
- SpecialProfile *s;
-
- p = g->m->ptrarg[0];
- b = g->m->ptrarg[1];
- g->m->ptrarg[0] = nil;
- g->m->ptrarg[1] = nil;
-
- runtime·lock(&runtime·mheap.speciallock);
- s = runtime·FixAlloc_Alloc(&runtime·mheap.specialprofilealloc);
- runtime·unlock(&runtime·mheap.speciallock);
- s->special.kind = KindSpecialProfile;
- s->b = b;
- if(!addspecial(p, &s->special))
- runtime·throw("setprofilebucket: profile already set");
-}
-
-// Do whatever cleanup needs to be done to deallocate s. It has
-// already been unlinked from the MSpan specials list.
-// Returns true if we should keep working on deallocating p.
-bool
-runtime·freespecial(Special *s, void *p, uintptr size, bool freed)
-{
- SpecialFinalizer *sf;
- SpecialProfile *sp;
-
- switch(s->kind) {
- case KindSpecialFinalizer:
- sf = (SpecialFinalizer*)s;
- runtime·queuefinalizer(p, sf->fn, sf->nret, sf->fint, sf->ot);
- runtime·lock(&runtime·mheap.speciallock);
- runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, sf);
- runtime·unlock(&runtime·mheap.speciallock);
- return false; // don't free p until finalizer is done
- case KindSpecialProfile:
- sp = (SpecialProfile*)s;
- runtime·mProf_Free(sp->b, size, freed);
- runtime·lock(&runtime·mheap.speciallock);
- runtime·FixAlloc_Free(&runtime·mheap.specialprofilealloc, sp);
- runtime·unlock(&runtime·mheap.speciallock);
- return true;
- default:
- runtime·throw("bad special kind");
- return true;
- }
-}
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
new file mode 100644
index 000000000..fedcd69c5
--- /dev/null
+++ b/src/runtime/mheap.go
@@ -0,0 +1,785 @@
+// 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.
+
+// Page heap.
+//
+// See malloc.h for overview.
+//
+// When a MSpan is in the heap free list, state == MSpanFree
+// and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
+//
+// When a MSpan is allocated, state == MSpanInUse or MSpanStack
+// and heapmap(i) == span for all s->start <= i < s->start+s->npages.
+
+package runtime
+
+import "unsafe"
+
+var h_allspans []*mspan // TODO: make this h.allspans once mheap can be defined in Go
+var h_spans []*mspan // TODO: make this h.spans once mheap can be defined in Go
+
+func recordspan(vh unsafe.Pointer, p unsafe.Pointer) {
+ h := (*mheap)(vh)
+ s := (*mspan)(p)
+ if len(h_allspans) >= cap(h_allspans) {
+ n := 64 * 1024 / ptrSize
+ if n < cap(h_allspans)*3/2 {
+ n = cap(h_allspans) * 3 / 2
+ }
+ var new []*mspan
+ sp := (*slice)(unsafe.Pointer(&new))
+ sp.array = (*byte)(sysAlloc(uintptr(n)*ptrSize, &memstats.other_sys))
+ if sp.array == nil {
+ gothrow("runtime: cannot allocate memory")
+ }
+ sp.len = uint(len(h_allspans))
+ sp.cap = uint(n)
+ if len(h_allspans) > 0 {
+ copy(new, h_allspans)
+ // Don't free the old array if it's referenced by sweep.
+ // See the comment in mgc0.c.
+ if h.allspans != mheap_.gcspans {
+ sysFree(unsafe.Pointer(h.allspans), uintptr(cap(h_allspans))*ptrSize, &memstats.other_sys)
+ }
+ }
+ h_allspans = new
+ h.allspans = (**mspan)(unsafe.Pointer(sp.array))
+ }
+ h_allspans = append(h_allspans, s)
+ h.nspan = uint32(len(h_allspans))
+}
+
+// Initialize the heap.
+func mHeap_Init(h *mheap, spans_size uintptr) {
+ fixAlloc_Init(&h.spanalloc, unsafe.Sizeof(mspan{}), recordspan, unsafe.Pointer(h), &memstats.mspan_sys)
+ fixAlloc_Init(&h.cachealloc, unsafe.Sizeof(mcache{}), nil, nil, &memstats.mcache_sys)
+ fixAlloc_Init(&h.specialfinalizeralloc, unsafe.Sizeof(specialfinalizer{}), nil, nil, &memstats.other_sys)
+ fixAlloc_Init(&h.specialprofilealloc, unsafe.Sizeof(specialprofile{}), nil, nil, &memstats.other_sys)
+
+ // h->mapcache needs no init
+ for i := range h.free {
+ mSpanList_Init(&h.free[i])
+ mSpanList_Init(&h.busy[i])
+ }
+
+ mSpanList_Init(&h.freelarge)
+ mSpanList_Init(&h.busylarge)
+ for i := range h.central {
+ mCentral_Init(&h.central[i].mcentral, int32(i))
+ }
+
+ sp := (*slice)(unsafe.Pointer(&h_spans))
+ sp.array = (*byte)(unsafe.Pointer(h.spans))
+ sp.len = uint(spans_size / ptrSize)
+ sp.cap = uint(spans_size / ptrSize)
+}
+
+func mHeap_MapSpans(h *mheap) {
+ // Map spans array, PageSize at a time.
+ n := uintptr(unsafe.Pointer(h.arena_used))
+ n -= uintptr(unsafe.Pointer(h.arena_start))
+ n = n / _PageSize * ptrSize
+ n = round(n, _PhysPageSize)
+ if h.spans_mapped >= n {
+ return
+ }
+ sysMap(add(unsafe.Pointer(h.spans), h.spans_mapped), n-h.spans_mapped, h.arena_reserved, &memstats.other_sys)
+ h.spans_mapped = n
+}
+
+// Sweeps spans in list until reclaims at least npages into heap.
+// Returns the actual number of pages reclaimed.
+func mHeap_ReclaimList(h *mheap, list *mspan, npages uintptr) uintptr {
+ n := uintptr(0)
+ sg := mheap_.sweepgen
+retry:
+ for s := list.next; s != list; s = s.next {
+ if s.sweepgen == sg-2 && cas(&s.sweepgen, sg-2, sg-1) {
+ mSpanList_Remove(s)
+ // swept spans are at the end of the list
+ mSpanList_InsertBack(list, s)
+ unlock(&h.lock)
+ if mSpan_Sweep(s, false) {
+ // TODO(rsc,dvyukov): This is probably wrong.
+ // It is undercounting the number of pages reclaimed.
+ // See golang.org/issue/9048.
+ // Note that if we want to add the true count of s's pages,
+ // we must record that before calling mSpan_Sweep,
+ // because if mSpan_Sweep returns true the span has
+ // been
+ n++
+ }
+ lock(&h.lock)
+ if n >= npages {
+ return n
+ }
+ // the span could have been moved elsewhere
+ goto retry
+ }
+ if s.sweepgen == sg-1 {
+ // the span is being sweept by background sweeper, skip
+ continue
+ }
+ // already swept empty span,
+ // all subsequent ones must also be either swept or in process of sweeping
+ break
+ }
+ return n
+}
+
+// Sweeps and reclaims at least npage pages into heap.
+// Called before allocating npage pages.
+func mHeap_Reclaim(h *mheap, npage uintptr) {
+ // First try to sweep busy spans with large objects of size >= npage,
+ // this has good chances of reclaiming the necessary space.
+ for i := int(npage); i < len(h.busy); i++ {
+ if mHeap_ReclaimList(h, &h.busy[i], npage) != 0 {
+ return // Bingo!
+ }
+ }
+
+ // Then -- even larger objects.
+ if mHeap_ReclaimList(h, &h.busylarge, npage) != 0 {
+ return // Bingo!
+ }
+
+ // Now try smaller objects.
+ // One such object is not enough, so we need to reclaim several of them.
+ reclaimed := uintptr(0)
+ for i := 0; i < int(npage) && i < len(h.busy); i++ {
+ reclaimed += mHeap_ReclaimList(h, &h.busy[i], npage-reclaimed)
+ if reclaimed >= npage {
+ return
+ }
+ }
+
+ // Now sweep everything that is not yet swept.
+ unlock(&h.lock)
+ for {
+ n := sweepone()
+ if n == ^uintptr(0) { // all spans are swept
+ break
+ }
+ reclaimed += n
+ if reclaimed >= npage {
+ break
+ }
+ }
+ lock(&h.lock)
+}
+
+// Allocate a new span of npage pages from the heap for GC'd memory
+// and record its size class in the HeapMap and HeapMapCache.
+func mHeap_Alloc_m(h *mheap, npage uintptr, sizeclass int32, large bool) *mspan {
+ _g_ := getg()
+ if _g_ != _g_.m.g0 {
+ gothrow("_mheap_alloc not on g0 stack")
+ }
+ lock(&h.lock)
+
+ // To prevent excessive heap growth, before allocating n pages
+ // we need to sweep and reclaim at least n pages.
+ if h.sweepdone == 0 {
+ mHeap_Reclaim(h, npage)
+ }
+
+ // transfer stats from cache to global
+ memstats.heap_alloc += uint64(_g_.m.mcache.local_cachealloc)
+ _g_.m.mcache.local_cachealloc = 0
+ memstats.tinyallocs += uint64(_g_.m.mcache.local_tinyallocs)
+ _g_.m.mcache.local_tinyallocs = 0
+
+ s := mHeap_AllocSpanLocked(h, npage)
+ if s != nil {
+ // Record span info, because gc needs to be
+ // able to map interior pointer to containing span.
+ atomicstore(&s.sweepgen, h.sweepgen)
+ s.state = _MSpanInUse
+ s.freelist = nil
+ s.ref = 0
+ s.sizeclass = uint8(sizeclass)
+ if sizeclass == 0 {
+ s.elemsize = s.npages << _PageShift
+ } else {
+ s.elemsize = uintptr(class_to_size[sizeclass])
+ }
+
+ // update stats, sweep lists
+ if large {
+ memstats.heap_objects++
+ memstats.heap_alloc += uint64(npage << _PageShift)
+ // Swept spans are at the end of lists.
+ if s.npages < uintptr(len(h.free)) {
+ mSpanList_InsertBack(&h.busy[s.npages], s)
+ } else {
+ mSpanList_InsertBack(&h.busylarge, s)
+ }
+ }
+ }
+ unlock(&h.lock)
+ return s
+}
+
+func mHeap_Alloc(h *mheap, npage uintptr, sizeclass int32, large bool, needzero bool) *mspan {
+ // Don't do any operations that lock the heap on the G stack.
+ // It might trigger stack growth, and the stack growth code needs
+ // to be able to allocate heap.
+ var s *mspan
+ systemstack(func() {
+ s = mHeap_Alloc_m(h, npage, sizeclass, large)
+ })
+
+ if s != nil {
+ if needzero && s.needzero != 0 {
+ memclr(unsafe.Pointer(s.start<<_PageShift), s.npages<<_PageShift)
+ }
+ s.needzero = 0
+ }
+ return s
+}
+
+func mHeap_AllocStack(h *mheap, npage uintptr) *mspan {
+ _g_ := getg()
+ if _g_ != _g_.m.g0 {
+ gothrow("mheap_allocstack not on g0 stack")
+ }
+ lock(&h.lock)
+ s := mHeap_AllocSpanLocked(h, npage)
+ if s != nil {
+ s.state = _MSpanStack
+ s.freelist = nil
+ s.ref = 0
+ memstats.stacks_inuse += uint64(s.npages << _PageShift)
+ }
+ unlock(&h.lock)
+ return s
+}
+
+// Allocates a span of the given size. h must be locked.
+// The returned span has been removed from the
+// free list, but its state is still MSpanFree.
+func mHeap_AllocSpanLocked(h *mheap, npage uintptr) *mspan {
+ var s *mspan
+
+ // Try in fixed-size lists up to max.
+ for i := int(npage); i < len(h.free); i++ {
+ if !mSpanList_IsEmpty(&h.free[i]) {
+ s = h.free[i].next
+ goto HaveSpan
+ }
+ }
+
+ // Best fit in list of large spans.
+ s = mHeap_AllocLarge(h, npage)
+ if s == nil {
+ if !mHeap_Grow(h, npage) {
+ return nil
+ }
+ s = mHeap_AllocLarge(h, npage)
+ if s == nil {
+ return nil
+ }
+ }
+
+HaveSpan:
+ // Mark span in use.
+ if s.state != _MSpanFree {
+ gothrow("MHeap_AllocLocked - MSpan not free")
+ }
+ if s.npages < npage {
+ gothrow("MHeap_AllocLocked - bad npages")
+ }
+ mSpanList_Remove(s)
+ if s.next != nil || s.prev != nil {
+ gothrow("still in list")
+ }
+ if s.npreleased > 0 {
+ sysUsed((unsafe.Pointer)(s.start<<_PageShift), s.npages<<_PageShift)
+ memstats.heap_released -= uint64(s.npreleased << _PageShift)
+ s.npreleased = 0
+ }
+
+ if s.npages > npage {
+ // Trim extra and put it back in the heap.
+ t := (*mspan)(fixAlloc_Alloc(&h.spanalloc))
+ mSpan_Init(t, s.start+pageID(npage), s.npages-npage)
+ s.npages = npage
+ p := uintptr(t.start)
+ p -= (uintptr(unsafe.Pointer(h.arena_start)) >> _PageShift)
+ if p > 0 {
+ h_spans[p-1] = s
+ }
+ h_spans[p] = t
+ h_spans[p+t.npages-1] = t
+ t.needzero = s.needzero
+ s.state = _MSpanStack // prevent coalescing with s
+ t.state = _MSpanStack
+ mHeap_FreeSpanLocked(h, t, false, false)
+ t.unusedsince = s.unusedsince // preserve age (TODO: wrong: t is possibly merged and/or deallocated at this point)
+ s.state = _MSpanFree
+ }
+ s.unusedsince = 0
+
+ p := uintptr(s.start)
+ p -= (uintptr(unsafe.Pointer(h.arena_start)) >> _PageShift)
+ for n := uintptr(0); n < npage; n++ {
+ h_spans[p+n] = s
+ }
+
+ memstats.heap_inuse += uint64(npage << _PageShift)
+ memstats.heap_idle -= uint64(npage << _PageShift)
+
+ //println("spanalloc", hex(s.start<<_PageShift))
+ if s.next != nil || s.prev != nil {
+ gothrow("still in list")
+ }
+ return s
+}
+
+// Allocate a span of exactly npage pages from the list of large spans.
+func mHeap_AllocLarge(h *mheap, npage uintptr) *mspan {
+ return bestFit(&h.freelarge, npage, nil)
+}
+
+// Search list for smallest span with >= npage pages.
+// If there are multiple smallest spans, take the one
+// with the earliest starting address.
+func bestFit(list *mspan, npage uintptr, best *mspan) *mspan {
+ for s := list.next; s != list; s = s.next {
+ if s.npages < npage {
+ continue
+ }
+ if best == nil || s.npages < best.npages || (s.npages == best.npages && s.start < best.start) {
+ best = s
+ }
+ }
+ return best
+}
+
+// Try to add at least npage pages of memory to the heap,
+// returning whether it worked.
+func mHeap_Grow(h *mheap, npage uintptr) bool {
+ // Ask for a big chunk, to reduce the number of mappings
+ // the operating system needs to track; also amortizes
+ // the overhead of an operating system mapping.
+ // Allocate a multiple of 64kB.
+ npage = round(npage, (64<<10)/_PageSize)
+ ask := npage << _PageShift
+ if ask < _HeapAllocChunk {
+ ask = _HeapAllocChunk
+ }
+
+ v := mHeap_SysAlloc(h, ask)
+ if v == nil {
+ if ask > npage<<_PageShift {
+ ask = npage << _PageShift
+ v = mHeap_SysAlloc(h, ask)
+ }
+ if v == nil {
+ print("runtime: out of memory: cannot allocate ", ask, "-byte block (", memstats.heap_sys, " in use)\n")
+ return false
+ }
+ }
+
+ // Create a fake "in use" span and free it, so that the
+ // right coalescing happens.
+ s := (*mspan)(fixAlloc_Alloc(&h.spanalloc))
+ mSpan_Init(s, pageID(uintptr(v)>>_PageShift), ask>>_PageShift)
+ p := uintptr(s.start)
+ p -= (uintptr(unsafe.Pointer(h.arena_start)) >> _PageShift)
+ h_spans[p] = s
+ h_spans[p+s.npages-1] = s
+ atomicstore(&s.sweepgen, h.sweepgen)
+ s.state = _MSpanInUse
+ mHeap_FreeSpanLocked(h, s, false, true)
+ return true
+}
+
+// Look up the span at the given address.
+// Address is guaranteed to be in map
+// and is guaranteed to be start or end of span.
+func mHeap_Lookup(h *mheap, v unsafe.Pointer) *mspan {
+ p := uintptr(v)
+ p -= uintptr(unsafe.Pointer(h.arena_start))
+ return h_spans[p>>_PageShift]
+}
+
+// Look up the span at the given address.
+// Address is *not* guaranteed to be in map
+// and may be anywhere in the span.
+// Map entries for the middle of a span are only
+// valid for allocated spans. Free spans may have
+// other garbage in their middles, so we have to
+// check for that.
+func mHeap_LookupMaybe(h *mheap, v unsafe.Pointer) *mspan {
+ if uintptr(v) < uintptr(unsafe.Pointer(h.arena_start)) || uintptr(v) >= uintptr(unsafe.Pointer(h.arena_used)) {
+ return nil
+ }
+ p := uintptr(v) >> _PageShift
+ q := p
+ q -= uintptr(unsafe.Pointer(h.arena_start)) >> _PageShift
+ s := h_spans[q]
+ if s == nil || p < uintptr(s.start) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != _MSpanInUse {
+ return nil
+ }
+ return s
+}
+
+// Free the span back into the heap.
+func mHeap_Free(h *mheap, s *mspan, acct int32) {
+ systemstack(func() {
+ mp := getg().m
+ lock(&h.lock)
+ memstats.heap_alloc += uint64(mp.mcache.local_cachealloc)
+ mp.mcache.local_cachealloc = 0
+ memstats.tinyallocs += uint64(mp.mcache.local_tinyallocs)
+ mp.mcache.local_tinyallocs = 0
+ if acct != 0 {
+ memstats.heap_alloc -= uint64(s.npages << _PageShift)
+ memstats.heap_objects--
+ }
+ mHeap_FreeSpanLocked(h, s, true, true)
+ unlock(&h.lock)
+ })
+}
+
+func mHeap_FreeStack(h *mheap, s *mspan) {
+ _g_ := getg()
+ if _g_ != _g_.m.g0 {
+ gothrow("mheap_freestack not on g0 stack")
+ }
+ s.needzero = 1
+ lock(&h.lock)
+ memstats.stacks_inuse -= uint64(s.npages << _PageShift)
+ mHeap_FreeSpanLocked(h, s, true, true)
+ unlock(&h.lock)
+}
+
+func mHeap_FreeSpanLocked(h *mheap, s *mspan, acctinuse, acctidle bool) {
+ switch s.state {
+ case _MSpanStack:
+ if s.ref != 0 {
+ gothrow("MHeap_FreeSpanLocked - invalid stack free")
+ }
+ case _MSpanInUse:
+ if s.ref != 0 || s.sweepgen != h.sweepgen {
+ print("MHeap_FreeSpanLocked - span ", s, " ptr ", hex(s.start<<_PageShift), " ref ", s.ref, " sweepgen ", s.sweepgen, "/", h.sweepgen, "\n")
+ gothrow("MHeap_FreeSpanLocked - invalid free")
+ }
+ default:
+ gothrow("MHeap_FreeSpanLocked - invalid span state")
+ }
+
+ if acctinuse {
+ memstats.heap_inuse -= uint64(s.npages << _PageShift)
+ }
+ if acctidle {
+ memstats.heap_idle += uint64(s.npages << _PageShift)
+ }
+ s.state = _MSpanFree
+ mSpanList_Remove(s)
+
+ // Stamp newly unused spans. The scavenger will use that
+ // info to potentially give back some pages to the OS.
+ s.unusedsince = nanotime()
+ s.npreleased = 0
+
+ // Coalesce with earlier, later spans.
+ p := uintptr(s.start)
+ p -= uintptr(unsafe.Pointer(h.arena_start)) >> _PageShift
+ if p > 0 {
+ t := h_spans[p-1]
+ if t != nil && t.state != _MSpanInUse && t.state != _MSpanStack {
+ s.start = t.start
+ s.npages += t.npages
+ s.npreleased = t.npreleased // absorb released pages
+ s.needzero |= t.needzero
+ p -= t.npages
+ h_spans[p] = s
+ mSpanList_Remove(t)
+ t.state = _MSpanDead
+ fixAlloc_Free(&h.spanalloc, (unsafe.Pointer)(t))
+ }
+ }
+ if (p+s.npages)*ptrSize < h.spans_mapped {
+ t := h_spans[p+s.npages]
+ if t != nil && t.state != _MSpanInUse && t.state != _MSpanStack {
+ s.npages += t.npages
+ s.npreleased += t.npreleased
+ s.needzero |= t.needzero
+ h_spans[p+s.npages-1] = s
+ mSpanList_Remove(t)
+ t.state = _MSpanDead
+ fixAlloc_Free(&h.spanalloc, (unsafe.Pointer)(t))
+ }
+ }
+
+ // Insert s into appropriate list.
+ if s.npages < uintptr(len(h.free)) {
+ mSpanList_Insert(&h.free[s.npages], s)
+ } else {
+ mSpanList_Insert(&h.freelarge, s)
+ }
+}
+
+func scavengelist(list *mspan, now, limit uint64) uintptr {
+ if mSpanList_IsEmpty(list) {
+ return 0
+ }
+
+ var sumreleased uintptr
+ for s := list.next; s != list; s = s.next {
+ if (now-uint64(s.unusedsince)) > limit && s.npreleased != s.npages {
+ released := (s.npages - s.npreleased) << _PageShift
+ memstats.heap_released += uint64(released)
+ sumreleased += released
+ s.npreleased = s.npages
+ sysUnused((unsafe.Pointer)(s.start<<_PageShift), s.npages<<_PageShift)
+ }
+ }
+ return sumreleased
+}
+
+func mHeap_Scavenge(k int32, now, limit uint64) {
+ h := &mheap_
+ lock(&h.lock)
+ var sumreleased uintptr
+ for i := 0; i < len(h.free); i++ {
+ sumreleased += scavengelist(&h.free[i], now, limit)
+ }
+ sumreleased += scavengelist(&h.freelarge, now, limit)
+ unlock(&h.lock)
+
+ if debug.gctrace > 0 {
+ if sumreleased > 0 {
+ print("scvg", k, ": ", sumreleased>>20, " MB released\n")
+ }
+ // TODO(dvyukov): these stats are incorrect as we don't subtract stack usage from heap.
+ // But we can't call ReadMemStats on g0 holding locks.
+ print("scvg", k, ": inuse: ", memstats.heap_inuse>>20, ", idle: ", memstats.heap_idle>>20, ", sys: ", memstats.heap_sys>>20, ", released: ", memstats.heap_released>>20, ", consumed: ", (memstats.heap_sys-memstats.heap_released)>>20, " (MB)\n")
+ }
+}
+
+func scavenge_m() {
+ mHeap_Scavenge(-1, ^uint64(0), 0)
+}
+
+// Initialize a new span with the given start and npages.
+func mSpan_Init(span *mspan, start pageID, npages uintptr) {
+ span.next = nil
+ span.prev = nil
+ span.start = start
+ span.npages = npages
+ span.freelist = nil
+ span.ref = 0
+ span.sizeclass = 0
+ span.incache = false
+ span.elemsize = 0
+ span.state = _MSpanDead
+ span.unusedsince = 0
+ span.npreleased = 0
+ span.speciallock.key = 0
+ span.specials = nil
+ span.needzero = 0
+}
+
+// Initialize an empty doubly-linked list.
+func mSpanList_Init(list *mspan) {
+ list.state = _MSpanListHead
+ list.next = list
+ list.prev = list
+}
+
+func mSpanList_Remove(span *mspan) {
+ if span.prev == nil && span.next == nil {
+ return
+ }
+ span.prev.next = span.next
+ span.next.prev = span.prev
+ span.prev = nil
+ span.next = nil
+}
+
+func mSpanList_IsEmpty(list *mspan) bool {
+ return list.next == list
+}
+
+func mSpanList_Insert(list *mspan, span *mspan) {
+ if span.next != nil || span.prev != nil {
+ println("failed MSpanList_Insert", span, span.next, span.prev)
+ gothrow("MSpanList_Insert")
+ }
+ span.next = list.next
+ span.prev = list
+ span.next.prev = span
+ span.prev.next = span
+}
+
+func mSpanList_InsertBack(list *mspan, span *mspan) {
+ if span.next != nil || span.prev != nil {
+ println("failed MSpanList_InsertBack", span, span.next, span.prev)
+ gothrow("MSpanList_InsertBack")
+ }
+ span.next = list
+ span.prev = list.prev
+ span.next.prev = span
+ span.prev.next = span
+}
+
+// Adds the special record s to the list of special records for
+// the object p. All fields of s should be filled in except for
+// offset & next, which this routine will fill in.
+// Returns true if the special was successfully added, false otherwise.
+// (The add will fail only if a record with the same p and s->kind
+// already exists.)
+func addspecial(p unsafe.Pointer, s *special) bool {
+ span := mHeap_LookupMaybe(&mheap_, p)
+ if span == nil {
+ gothrow("addspecial on invalid pointer")
+ }
+
+ // Ensure that the span is swept.
+ // GC accesses specials list w/o locks. And it's just much safer.
+ mp := acquirem()
+ mSpan_EnsureSwept(span)
+
+ offset := uintptr(p) - uintptr(span.start<<_PageShift)
+ kind := s.kind
+
+ lock(&span.speciallock)
+
+ // Find splice point, check for existing record.
+ t := &span.specials
+ for {
+ x := *t
+ if x == nil {
+ break
+ }
+ if offset == uintptr(x.offset) && kind == x.kind {
+ unlock(&span.speciallock)
+ releasem(mp)
+ return false // already exists
+ }
+ if offset < uintptr(x.offset) || (offset == uintptr(x.offset) && kind < x.kind) {
+ break
+ }
+ t = &x.next
+ }
+
+ // Splice in record, fill in offset.
+ s.offset = uint16(offset)
+ s.next = *t
+ *t = s
+ unlock(&span.speciallock)
+ releasem(mp)
+
+ return true
+}
+
+// Removes the Special record of the given kind for the object p.
+// Returns the record if the record existed, nil otherwise.
+// The caller must FixAlloc_Free the result.
+func removespecial(p unsafe.Pointer, kind uint8) *special {
+ span := mHeap_LookupMaybe(&mheap_, p)
+ if span == nil {
+ gothrow("removespecial on invalid pointer")
+ }
+
+ // Ensure that the span is swept.
+ // GC accesses specials list w/o locks. And it's just much safer.
+ mp := acquirem()
+ mSpan_EnsureSwept(span)
+
+ offset := uintptr(p) - uintptr(span.start<<_PageShift)
+
+ lock(&span.speciallock)
+ t := &span.specials
+ for {
+ s := *t
+ if s == nil {
+ break
+ }
+ // This function is used for finalizers only, so we don't check for
+ // "interior" specials (p must be exactly equal to s->offset).
+ if offset == uintptr(s.offset) && kind == s.kind {
+ *t = s.next
+ unlock(&span.speciallock)
+ releasem(mp)
+ return s
+ }
+ t = &s.next
+ }
+ unlock(&span.speciallock)
+ releasem(mp)
+ return nil
+}
+
+// Adds a finalizer to the object p. Returns true if it succeeded.
+func addfinalizer(p unsafe.Pointer, f *funcval, nret uintptr, fint *_type, ot *ptrtype) bool {
+ lock(&mheap_.speciallock)
+ s := (*specialfinalizer)(fixAlloc_Alloc(&mheap_.specialfinalizeralloc))
+ unlock(&mheap_.speciallock)
+ s.special.kind = _KindSpecialFinalizer
+ s.fn = f
+ s.nret = nret
+ s.fint = fint
+ s.ot = ot
+ if addspecial(p, &s.special) {
+ return true
+ }
+
+ // There was an old finalizer
+ lock(&mheap_.speciallock)
+ fixAlloc_Free(&mheap_.specialfinalizeralloc, (unsafe.Pointer)(s))
+ unlock(&mheap_.speciallock)
+ return false
+}
+
+// Removes the finalizer (if any) from the object p.
+func removefinalizer(p unsafe.Pointer) {
+ s := (*specialfinalizer)(unsafe.Pointer(removespecial(p, _KindSpecialFinalizer)))
+ if s == nil {
+ return // there wasn't a finalizer to remove
+ }
+ lock(&mheap_.speciallock)
+ fixAlloc_Free(&mheap_.specialfinalizeralloc, (unsafe.Pointer)(s))
+ unlock(&mheap_.speciallock)
+}
+
+// Set the heap profile bucket associated with addr to b.
+func setprofilebucket(p unsafe.Pointer, b *bucket) {
+ lock(&mheap_.speciallock)
+ s := (*specialprofile)(fixAlloc_Alloc(&mheap_.specialprofilealloc))
+ unlock(&mheap_.speciallock)
+ s.special.kind = _KindSpecialProfile
+ s.b = b
+ if !addspecial(p, &s.special) {
+ gothrow("setprofilebucket: profile already set")
+ }
+}
+
+// Do whatever cleanup needs to be done to deallocate s. It has
+// already been unlinked from the MSpan specials list.
+// Returns true if we should keep working on deallocating p.
+func freespecial(s *special, p unsafe.Pointer, size uintptr, freed bool) bool {
+ switch s.kind {
+ case _KindSpecialFinalizer:
+ sf := (*specialfinalizer)(unsafe.Pointer(s))
+ queuefinalizer(p, sf.fn, sf.nret, sf.fint, sf.ot)
+ lock(&mheap_.speciallock)
+ fixAlloc_Free(&mheap_.specialfinalizeralloc, (unsafe.Pointer)(sf))
+ unlock(&mheap_.speciallock)
+ return false // don't free p until finalizer is done
+ case _KindSpecialProfile:
+ sp := (*specialprofile)(unsafe.Pointer(s))
+ mProf_Free(sp.b, size, freed)
+ lock(&mheap_.speciallock)
+ fixAlloc_Free(&mheap_.specialprofilealloc, (unsafe.Pointer)(sp))
+ unlock(&mheap_.speciallock)
+ return true
+ default:
+ gothrow("bad special kind")
+ panic("not reached")
+ }
+}
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go
index d409c6c30..ba989b1b8 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -190,8 +190,6 @@ func stkbucket(typ bucketType, size uintptr, stk []uintptr, alloc bool) *bucket
return b
}
-func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer
-
func eqslice(x, y []uintptr) bool {
if len(x) != len(y) {
return false
@@ -246,16 +244,9 @@ func mProf_Malloc(p unsafe.Pointer, size uintptr) {
// This reduces potential contention and chances of deadlocks.
// Since the object must be alive during call to mProf_Malloc,
// it's fine to do this non-atomically.
- setprofilebucket(p, b)
-}
-
-func setprofilebucket_m() // mheap.c
-
-func setprofilebucket(p unsafe.Pointer, b *bucket) {
- g := getg()
- g.m.ptrarg[0] = p
- g.m.ptrarg[1] = unsafe.Pointer(b)
- onM(setprofilebucket_m)
+ systemstack(func() {
+ setprofilebucket(p, b)
+ })
}
// Called when freeing a profiled block.
@@ -519,8 +510,6 @@ func ThreadCreateProfile(p []StackRecord) (n int, ok bool) {
return
}
-var allgs []*g // proc.c
-
// GoroutineProfile returns n, the number of records in the active goroutine stack profile.
// If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
// If len(p) < n, GoroutineProfile does not change p and returns n, false.
@@ -534,7 +523,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
gp := getg()
semacquire(&worldsema, false)
gp.m.gcing = 1
- onM(stoptheworld)
+ systemstack(stoptheworld)
n = NumGoroutine()
if n <= len(p) {
@@ -542,7 +531,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
r := p
sp := getcallersp(unsafe.Pointer(&p))
pc := getcallerpc(unsafe.Pointer(&p))
- onM(func() {
+ systemstack(func() {
saveg(pc, sp, gp, &r[0])
})
r = r[1:]
@@ -557,7 +546,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
gp.m.gcing = 0
semrelease(&worldsema)
- onM(starttheworld)
+ systemstack(starttheworld)
}
return n, ok
@@ -581,7 +570,7 @@ func Stack(buf []byte, all bool) int {
semacquire(&worldsema, false)
mp.gcing = 1
releasem(mp)
- onM(stoptheworld)
+ systemstack(stoptheworld)
if mp != acquirem() {
gothrow("Stack: rescheduled")
}
@@ -591,7 +580,7 @@ func Stack(buf []byte, all bool) int {
if len(buf) > 0 {
sp := getcallersp(unsafe.Pointer(&buf))
pc := getcallerpc(unsafe.Pointer(&buf))
- onM(func() {
+ systemstack(func() {
g0 := getg()
g0.writebuf = buf[0:0:len(buf)]
goroutineheader(gp)
@@ -607,7 +596,7 @@ func Stack(buf []byte, all bool) int {
if all {
mp.gcing = 0
semrelease(&worldsema)
- onM(starttheworld)
+ systemstack(starttheworld)
}
releasem(mp)
return n
@@ -630,7 +619,7 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
goroutineheader(gp)
pc := getcallerpc(unsafe.Pointer(&p))
sp := getcallersp(unsafe.Pointer(&p))
- onM(func() {
+ systemstack(func() {
traceback(pc, sp, 0, gp)
})
} else {
@@ -650,7 +639,7 @@ func tracefree(p unsafe.Pointer, size uintptr) {
goroutineheader(gp)
pc := getcallerpc(unsafe.Pointer(&p))
sp := getcallersp(unsafe.Pointer(&p))
- onM(func() {
+ systemstack(func() {
traceback(pc, sp, 0, gp)
})
print("\n")
diff --git a/src/runtime/msize.c b/src/runtime/msize.c
deleted file mode 100644
index 7cb65dad0..000000000
--- a/src/runtime/msize.c
+++ /dev/null
@@ -1,184 +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.
-
-// Malloc small size classes.
-//
-// See malloc.h for overview.
-//
-// The size classes are chosen so that rounding an allocation
-// request up to the next size class wastes at most 12.5% (1.125x).
-//
-// Each size class has its own page count that gets allocated
-// and chopped up when new objects of the size class are needed.
-// That page count is chosen so that chopping up the run of
-// pages into objects of the given size wastes at most 12.5% (1.125x)
-// of the memory. It is not necessary that the cutoff here be
-// the same as above.
-//
-// The two sources of waste multiply, so the worst possible case
-// for the above constraints would be that allocations of some
-// size might have a 26.6% (1.266x) overhead.
-// In practice, only one of the wastes comes into play for a
-// given size (sizes < 512 waste mainly on the round-up,
-// sizes > 512 waste mainly on the page chopping).
-//
-// TODO(rsc): Compute max waste for any given size.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "textflag.h"
-
-#pragma dataflag NOPTR
-int32 runtime·class_to_size[NumSizeClasses];
-#pragma dataflag NOPTR
-int32 runtime·class_to_allocnpages[NumSizeClasses];
-
-// The SizeToClass lookup is implemented using two arrays,
-// one mapping sizes <= 1024 to their class and one mapping
-// sizes >= 1024 and <= MaxSmallSize to their class.
-// All objects are 8-aligned, so the first array is indexed by
-// the size divided by 8 (rounded up). Objects >= 1024 bytes
-// are 128-aligned, so the second array is indexed by the
-// size divided by 128 (rounded up). The arrays are filled in
-// by InitSizes.
-
-#pragma dataflag NOPTR
-int8 runtime·size_to_class8[1024/8 + 1];
-#pragma dataflag NOPTR
-int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
-
-void runtime·testdefersizes(void);
-
-int32
-runtime·SizeToClass(int32 size)
-{
- if(size > MaxSmallSize)
- runtime·throw("SizeToClass - invalid size");
- if(size > 1024-8)
- return runtime·size_to_class128[(size-1024+127) >> 7];
- return runtime·size_to_class8[(size+7)>>3];
-}
-
-void
-runtime·InitSizes(void)
-{
- int32 align, sizeclass, size, nextsize, n;
- uint32 i;
- uintptr allocsize, npages;
-
- // Initialize the runtime·class_to_size table (and choose class sizes in the process).
- runtime·class_to_size[0] = 0;
- sizeclass = 1; // 0 means no class
- align = 8;
- for(size = align; size <= MaxSmallSize; size += align) {
- if((size&(size-1)) == 0) { // bump alignment once in a while
- if(size >= 2048)
- align = 256;
- else if(size >= 128)
- align = size / 8;
- else if(size >= 16)
- align = 16; // required for x86 SSE instructions, if we want to use them
- }
- if((align&(align-1)) != 0)
- runtime·throw("InitSizes - bug");
-
- // Make the allocnpages big enough that
- // the leftover is less than 1/8 of the total,
- // so wasted space is at most 12.5%.
- allocsize = PageSize;
- while(allocsize%size > allocsize/8)
- allocsize += PageSize;
- npages = allocsize >> PageShift;
-
- // If the previous sizeclass chose the same
- // allocation size and fit the same number of
- // objects into the page, we might as well
- // use just this size instead of having two
- // different sizes.
- if(sizeclass > 1 &&
- npages == runtime·class_to_allocnpages[sizeclass-1] &&
- allocsize/size == allocsize/runtime·class_to_size[sizeclass-1]) {
- runtime·class_to_size[sizeclass-1] = size;
- continue;
- }
-
- runtime·class_to_allocnpages[sizeclass] = npages;
- runtime·class_to_size[sizeclass] = size;
- sizeclass++;
- }
- if(sizeclass != NumSizeClasses) {
- runtime·printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
- runtime·throw("InitSizes - bad NumSizeClasses");
- }
-
- // Initialize the size_to_class tables.
- nextsize = 0;
- for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
- for(; nextsize < 1024 && nextsize <= runtime·class_to_size[sizeclass]; nextsize+=8)
- runtime·size_to_class8[nextsize/8] = sizeclass;
- if(nextsize >= 1024)
- for(; nextsize <= runtime·class_to_size[sizeclass]; nextsize += 128)
- runtime·size_to_class128[(nextsize-1024)/128] = sizeclass;
- }
-
- // Double-check SizeToClass.
- if(0) {
- for(n=0; n < MaxSmallSize; n++) {
- sizeclass = runtime·SizeToClass(n);
- if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime·class_to_size[sizeclass] < n) {
- runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
- runtime·printf("incorrect SizeToClass");
- goto dump;
- }
- if(sizeclass > 1 && runtime·class_to_size[sizeclass-1] >= n) {
- runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
- runtime·printf("SizeToClass too big");
- goto dump;
- }
- }
- }
-
- runtime·testdefersizes();
-
- // Copy out for statistics table.
- for(i=0; i<nelem(runtime·class_to_size); i++)
- mstats.by_size[i].size = runtime·class_to_size[i];
- return;
-
-dump:
- if(1){
- runtime·printf("NumSizeClasses=%d\n", NumSizeClasses);
- runtime·printf("runtime·class_to_size:");
- for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
- runtime·printf(" %d", runtime·class_to_size[sizeclass]);
- runtime·printf("\n\n");
- runtime·printf("size_to_class8:");
- for(i=0; i<nelem(runtime·size_to_class8); i++)
- runtime·printf(" %d=>%d(%d)\n", i*8, runtime·size_to_class8[i],
- runtime·class_to_size[runtime·size_to_class8[i]]);
- runtime·printf("\n");
- runtime·printf("size_to_class128:");
- for(i=0; i<nelem(runtime·size_to_class128); i++)
- runtime·printf(" %d=>%d(%d)\n", i*128, runtime·size_to_class128[i],
- runtime·class_to_size[runtime·size_to_class128[i]]);
- runtime·printf("\n");
- }
- runtime·throw("InitSizes failed");
-}
-
-// Returns size of the memory block that mallocgc will allocate if you ask for the size.
-uintptr
-runtime·roundupsize(uintptr size)
-{
- if(size < MaxSmallSize) {
- if(size <= 1024-8)
- return runtime·class_to_size[runtime·size_to_class8[(size+7)>>3]];
- else
- return runtime·class_to_size[runtime·size_to_class128[(size-1024+127) >> 7]];
- }
- if(size + PageSize < size)
- return size;
- return ROUND(size, PageSize);
-}
diff --git a/src/runtime/msize.go b/src/runtime/msize.go
new file mode 100644
index 000000000..aa2b43e90
--- /dev/null
+++ b/src/runtime/msize.go
@@ -0,0 +1,174 @@
+// 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.
+
+// Malloc small size classes.
+//
+// See malloc.h for overview.
+//
+// The size classes are chosen so that rounding an allocation
+// request up to the next size class wastes at most 12.5% (1.125x).
+//
+// Each size class has its own page count that gets allocated
+// and chopped up when new objects of the size class are needed.
+// That page count is chosen so that chopping up the run of
+// pages into objects of the given size wastes at most 12.5% (1.125x)
+// of the memory. It is not necessary that the cutoff here be
+// the same as above.
+//
+// The two sources of waste multiply, so the worst possible case
+// for the above constraints would be that allocations of some
+// size might have a 26.6% (1.266x) overhead.
+// In practice, only one of the wastes comes into play for a
+// given size (sizes < 512 waste mainly on the round-up,
+// sizes > 512 waste mainly on the page chopping).
+//
+// TODO(rsc): Compute max waste for any given size.
+
+package runtime
+
+//var class_to_size [_NumSizeClasses]int32
+//var class_to_allocnpages [_NumSizeClasses]int32
+
+// The SizeToClass lookup is implemented using two arrays,
+// one mapping sizes <= 1024 to their class and one mapping
+// sizes >= 1024 and <= MaxSmallSize to their class.
+// All objects are 8-aligned, so the first array is indexed by
+// the size divided by 8 (rounded up). Objects >= 1024 bytes
+// are 128-aligned, so the second array is indexed by the
+// size divided by 128 (rounded up). The arrays are filled in
+// by InitSizes.
+//var size_to_class8 [1024/8 + 1]int8
+//var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8
+
+func sizeToClass(size int32) int32 {
+ if size > _MaxSmallSize {
+ gothrow("SizeToClass - invalid size")
+ }
+ if size > 1024-8 {
+ return int32(size_to_class128[(size-1024+127)>>7])
+ }
+ return int32(size_to_class8[(size+7)>>3])
+}
+
+func initSizes() {
+ // Initialize the runtime·class_to_size table (and choose class sizes in the process).
+ class_to_size[0] = 0
+ sizeclass := 1 // 0 means no class
+ align := 8
+ for size := align; size <= _MaxSmallSize; size += align {
+ if size&(size-1) == 0 { // bump alignment once in a while
+ if size >= 2048 {
+ align = 256
+ } else if size >= 128 {
+ align = size / 8
+ } else if size >= 16 {
+ align = 16 // required for x86 SSE instructions, if we want to use them
+ }
+ }
+ if align&(align-1) != 0 {
+ gothrow("InitSizes - bug")
+ }
+
+ // Make the allocnpages big enough that
+ // the leftover is less than 1/8 of the total,
+ // so wasted space is at most 12.5%.
+ allocsize := _PageSize
+ for allocsize%size > allocsize/8 {
+ allocsize += _PageSize
+ }
+ npages := allocsize >> _PageShift
+
+ // If the previous sizeclass chose the same
+ // allocation size and fit the same number of
+ // objects into the page, we might as well
+ // use just this size instead of having two
+ // different sizes.
+ if sizeclass > 1 && npages == int(class_to_allocnpages[sizeclass-1]) && allocsize/size == allocsize/int(class_to_size[sizeclass-1]) {
+ class_to_size[sizeclass-1] = int32(size)
+ continue
+ }
+
+ class_to_allocnpages[sizeclass] = int32(npages)
+ class_to_size[sizeclass] = int32(size)
+ sizeclass++
+ }
+ if sizeclass != _NumSizeClasses {
+ print("sizeclass=", sizeclass, " NumSizeClasses=", _NumSizeClasses, "\n")
+ gothrow("InitSizes - bad NumSizeClasses")
+ }
+
+ // Initialize the size_to_class tables.
+ nextsize := 0
+ for sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++ {
+ for ; nextsize < 1024 && nextsize <= int(class_to_size[sizeclass]); nextsize += 8 {
+ size_to_class8[nextsize/8] = int8(sizeclass)
+ }
+ if nextsize >= 1024 {
+ for ; nextsize <= int(class_to_size[sizeclass]); nextsize += 128 {
+ size_to_class128[(nextsize-1024)/128] = int8(sizeclass)
+ }
+ }
+ }
+
+ // Double-check SizeToClass.
+ if false {
+ for n := int32(0); n < _MaxSmallSize; n++ {
+ sizeclass := sizeToClass(n)
+ if sizeclass < 1 || sizeclass >= _NumSizeClasses || class_to_size[sizeclass] < n {
+ print("size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
+ print("incorrect SizeToClass\n")
+ goto dump
+ }
+ if sizeclass > 1 && class_to_size[sizeclass-1] >= n {
+ print("size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
+ print("SizeToClass too big\n")
+ goto dump
+ }
+ }
+ }
+
+ testdefersizes()
+
+ // Copy out for statistics table.
+ for i := 0; i < len(class_to_size); i++ {
+ memstats.by_size[i].size = uint32(class_to_size[i])
+ }
+ return
+
+dump:
+ if true {
+ print("NumSizeClasses=", _NumSizeClasses, "\n")
+ print("runtime·class_to_size:")
+ for sizeclass = 0; sizeclass < _NumSizeClasses; sizeclass++ {
+ print(" ", class_to_size[sizeclass], "")
+ }
+ print("\n\n")
+ print("size_to_class8:")
+ for i := 0; i < len(size_to_class8); i++ {
+ print(" ", i*8, "=>", size_to_class8[i], "(", class_to_size[size_to_class8[i]], ")\n")
+ }
+ print("\n")
+ print("size_to_class128:")
+ for i := 0; i < len(size_to_class128); i++ {
+ print(" ", i*128, "=>", size_to_class128[i], "(", class_to_size[size_to_class128[i]], ")\n")
+ }
+ print("\n")
+ }
+ gothrow("InitSizes failed")
+}
+
+// Returns size of the memory block that mallocgc will allocate if you ask for the size.
+func roundupsize(size uintptr) uintptr {
+ if size < _MaxSmallSize {
+ if size <= 1024-8 {
+ return uintptr(class_to_size[size_to_class8[(size+7)>>3]])
+ } else {
+ return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]])
+ }
+ }
+ if size+_PageSize < size {
+ return size
+ }
+ return round(size, _PageSize)
+}
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index 3456e0208..7a99f18ad 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -49,14 +49,14 @@ type pollDesc struct {
lock mutex // protectes the following fields
fd uintptr
closing bool
- seq uintptr // protects from stale timers and ready notifications
- rg uintptr // pdReady, pdWait, G waiting for read or nil
- rt timer // read deadline timer (set if rt.f != nil)
- rd int64 // read deadline
- wg uintptr // pdReady, pdWait, G waiting for write or nil
- wt timer // write deadline timer
- wd int64 // write deadline
- user unsafe.Pointer // user settable cookie
+ seq uintptr // protects from stale timers and ready notifications
+ rg uintptr // pdReady, pdWait, G waiting for read or nil
+ rt timer // read deadline timer (set if rt.f != nil)
+ rd int64 // read deadline
+ wg uintptr // pdReady, pdWait, G waiting for write or nil
+ wt timer // write deadline timer
+ wd int64 // write deadline
+ user uint32 // user settable cookie
}
type pollCache struct {
@@ -72,7 +72,7 @@ type pollCache struct {
var pollcache pollCache
func netpollServerInit() {
- onM(netpollinit)
+ netpollinit()
}
func netpollOpen(fd uintptr) (*pollDesc, int) {
@@ -94,9 +94,7 @@ func netpollOpen(fd uintptr) (*pollDesc, int) {
unlock(&pd.lock)
var errno int32
- onM(func() {
- errno = netpollopen(fd, pd)
- })
+ errno = netpollopen(fd, pd)
return pd, int(errno)
}
@@ -110,9 +108,7 @@ func netpollClose(pd *pollDesc) {
if pd.rg != 0 && pd.rg != pdReady {
gothrow("netpollClose: blocked read on closing descriptor")
}
- onM(func() {
- netpollclose(uintptr(pd.fd))
- })
+ netpollclose(uintptr(pd.fd))
pollcache.free(pd)
}
@@ -143,9 +139,7 @@ func netpollWait(pd *pollDesc, mode int) int {
}
// As for now only Solaris uses level-triggered IO.
if GOOS == "solaris" {
- onM(func() {
- netpollarm(pd, mode)
- })
+ netpollarm(pd, mode)
}
for !netpollblock(pd, int32(mode), false) {
err = netpollcheckerr(pd, int32(mode))
@@ -263,26 +257,6 @@ func netpollUnblock(pd *pollDesc) {
}
}
-func netpollfd(pd *pollDesc) uintptr {
- return pd.fd
-}
-
-func netpolluser(pd *pollDesc) *unsafe.Pointer {
- return &pd.user
-}
-
-func netpollclosing(pd *pollDesc) bool {
- return pd.closing
-}
-
-func netpolllock(pd *pollDesc) {
- lock(&pd.lock)
-}
-
-func netpollunlock(pd *pollDesc) {
- unlock(&pd.lock)
-}
-
// make pd ready, newly runnable goroutines (if any) are returned in rg/wg
func netpollready(gpp **g, pd *pollDesc, mode int32) {
var rg, wg *g
@@ -343,8 +317,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 {
- f := netpollblockcommit
- gopark(**(**unsafe.Pointer)(unsafe.Pointer(&f)), unsafe.Pointer(gpp), "IO wait")
+ gopark(netpollblockcommit, unsafe.Pointer(gpp), "IO wait")
}
// be careful to not lose concurrent READY notification
old := xchguintptr(gpp, 0)
diff --git a/src/runtime/netpoll_solaris.c b/src/runtime/netpoll_solaris.go
index d422719cf..40e8a1a65 100644
--- a/src/runtime/netpoll_solaris.c
+++ b/src/runtime/netpoll_solaris.go
@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
+package runtime
+
+import "unsafe"
// Solaris runtime-integrated network poller.
-//
+//
// Solaris uses event ports for scalable network I/O. Event
// ports are level-triggered, unlike epoll and kqueue which
// can be configured in both level-triggered and edge-triggered
@@ -18,7 +17,7 @@
// events for that descriptor. When doing this we must keep track of
// what kind of events the goroutines are currently interested in,
// for example a fd may be open both for reading and writing.
-//
+//
// A description of the high level operation of this code
// follows. Networking code will get a file descriptor by some means
// and will register it with the netpolling mechanism by a code path
@@ -29,7 +28,7 @@
// readiness notification at some point in the future. If I/O becomes
// ready when nobody is listening, when we finally care about it,
// nobody will tell us anymore.
-//
+//
// Beside calling runtime·netpollopen, the networking code paths
// will call runtime·netpollarm each time goroutines are interested
// in doing network I/O. Because now we know what kind of I/O we
@@ -39,7 +38,7 @@
// when we now call port_associate, we will unblock the main poller
// loop (in runtime·netpoll) right away if the socket is actually
// ready for I/O.
-//
+//
// The main poller loop runs in its own thread waiting for events
// using port_getn. When an event happens, it will tell the scheduler
// about it using runtime·netpollready. Besides doing this, it must
@@ -47,7 +46,7 @@
// notification with the file descriptor. Failing to do this would
// mean each notification will prevent concurrent code using the
// same file descriptor in parallel.
-//
+//
// The logic dealing with re-associations is encapsulated in
// runtime·netpollupdate. This function takes care to associate the
// descriptor only with the subset of events that were previously
@@ -56,7 +55,7 @@
// are level triggered so it would cause a busy loop. Instead, that
// association is effected only by the runtime·netpollarm code path,
// when Go code actually asks for I/O.
-//
+//
// The open and arming mechanisms are serialized using the lock
// inside PollDesc. This is required because the netpoll loop runs
// asynchonously in respect to other Go code and by the time we get
@@ -68,179 +67,157 @@
// again we know for sure we are always talking about the same file
// descriptor and can safely access the data we want (the event set).
-#pragma dynimport libc·fcntl fcntl "libc.so"
-#pragma dynimport libc·port_create port_create "libc.so"
-#pragma dynimport libc·port_associate port_associate "libc.so"
-#pragma dynimport libc·port_dissociate port_dissociate "libc.so"
-#pragma dynimport libc·port_getn port_getn "libc.so"
-extern uintptr libc·fcntl;
-extern uintptr libc·port_create;
-extern uintptr libc·port_associate;
-extern uintptr libc·port_dissociate;
-extern uintptr libc·port_getn;
-
-#define errno (*g->m->perrno)
+//go:cgo_import_dynamic libc_port_create port_create "libc.so"
+//go:cgo_import_dynamic libc_port_associate port_associate "libc.so"
+//go:cgo_import_dynamic libc_port_dissociate port_dissociate "libc.so"
+//go:cgo_import_dynamic libc_port_getn port_getn "libc.so"
+
+//go:linkname libc_port_create libc_port_create
+//go:linkname libc_port_associate libc_port_associate
+//go:linkname libc_port_dissociate libc_port_dissociate
+//go:linkname libc_port_getn libc_port_getn
+
+var (
+ libc_port_create,
+ libc_port_associate,
+ libc_port_dissociate,
+ libc_port_getn libcFunc
+)
+
+func errno() int32 {
+ return *getg().m.perrno
+}
-int32
-runtime·fcntl(int32 fd, int32 cmd, uintptr arg)
-{
- return runtime·sysvicall3(libc·fcntl, (uintptr)fd, (uintptr)cmd, (uintptr)arg);
+func fcntl(fd, cmd int32, arg uintptr) int32 {
+ return int32(sysvicall3(libc_fcntl, uintptr(fd), uintptr(cmd), arg))
}
-int32
-runtime·port_create(void)
-{
- return runtime·sysvicall0(libc·port_create);
+func port_create() int32 {
+ return int32(sysvicall0(libc_port_create))
}
-int32
-runtime·port_associate(int32 port, int32 source, uintptr object, int32 events, uintptr user)
-{
- return runtime·sysvicall5(libc·port_associate, (uintptr)port, (uintptr)source, object, (uintptr)events, user);
+func port_associate(port, source int32, object uintptr, events uint32, user uintptr) int32 {
+ return int32(sysvicall5(libc_port_associate, uintptr(port), uintptr(source), object, uintptr(events), user))
}
-int32
-runtime·port_dissociate(int32 port, int32 source, uintptr object)
-{
- return runtime·sysvicall3(libc·port_dissociate, (uintptr)port, (uintptr)source, object);
+func port_dissociate(port, source int32, object uintptr) int32 {
+ return int32(sysvicall3(libc_port_dissociate, uintptr(port), uintptr(source), object))
}
-int32
-runtime·port_getn(int32 port, PortEvent *evs, uint32 max, uint32 *nget, Timespec *timeout)
-{
- return runtime·sysvicall5(libc·port_getn, (uintptr)port, (uintptr)evs, (uintptr)max, (uintptr)nget, (uintptr)timeout);
+func port_getn(port int32, evs *portevent, max uint32, nget *uint32, timeout *timespec) int32 {
+ return int32(sysvicall5(libc_port_getn, uintptr(port), uintptr(unsafe.Pointer(evs)), uintptr(max), uintptr(unsafe.Pointer(nget)), uintptr(unsafe.Pointer(timeout))))
}
-static int32 portfd = -1;
+var portfd int32 = -1
-void
-runtime·netpollinit(void)
-{
- if((portfd = runtime·port_create()) >= 0) {
- runtime·fcntl(portfd, F_SETFD, FD_CLOEXEC);
- return;
+func netpollinit() {
+ portfd = port_create()
+ if portfd >= 0 {
+ fcntl(portfd, _F_SETFD, _FD_CLOEXEC)
+ return
}
- runtime·printf("netpollinit: failed to create port (%d)\n", errno);
- runtime·throw("netpollinit: failed to create port");
+ print("netpollinit: failed to create port (", errno(), ")\n")
+ gothrow("netpollinit: failed to create port")
}
-int32
-runtime·netpollopen(uintptr fd, PollDesc *pd)
-{
- int32 r;
-
- runtime·netpolllock(pd);
+func netpollopen(fd uintptr, pd *pollDesc) int32 {
+ lock(&pd.lock)
// We don't register for any specific type of events yet, that's
// netpollarm's job. We merely ensure we call port_associate before
// asynchonous connect/accept completes, so when we actually want
// to do any I/O, the call to port_associate (from netpollarm,
// with the interested event set) will unblock port_getn right away
// because of the I/O readiness notification.
- *runtime·netpolluser(pd) = 0;
- r = runtime·port_associate(portfd, PORT_SOURCE_FD, fd, 0, (uintptr)pd);
- runtime·netpollunlock(pd);
- return r;
+ pd.user = 0
+ r := port_associate(portfd, _PORT_SOURCE_FD, fd, 0, uintptr(unsafe.Pointer(pd)))
+ unlock(&pd.lock)
+ return r
}
-int32
-runtime·netpollclose(uintptr fd)
-{
- return runtime·port_dissociate(portfd, PORT_SOURCE_FD, fd);
+func netpollclose(fd uintptr) int32 {
+ return port_dissociate(portfd, _PORT_SOURCE_FD, fd)
}
// Updates the association with a new set of interested events. After
// this call, port_getn will return one and only one event for that
// particular descriptor, so this function needs to be called again.
-void
-runtime·netpollupdate(PollDesc* pd, uint32 set, uint32 clear)
-{
- uint32 *ep, old, events;
- uintptr fd = runtime·netpollfd(pd);
- ep = (uint32*)runtime·netpolluser(pd);
-
- if(runtime·netpollclosing(pd))
- return;
+func netpollupdate(pd *pollDesc, set, clear uint32) {
+ if pd.closing {
+ return
+ }
- old = *ep;
- events = (old & ~clear) | set;
- if(old == events)
- return;
+ old := pd.user
+ events := (old & ^clear) | set
+ if old == events {
+ return
+ }
- if(events && runtime·port_associate(portfd, PORT_SOURCE_FD, fd, events, (uintptr)pd) != 0) {
- runtime·printf("netpollupdate: failed to associate (%d)\n", errno);
- runtime·throw("netpollupdate: failed to associate");
- }
- *ep = events;
+ if events != 0 && port_associate(portfd, _PORT_SOURCE_FD, pd.fd, events, uintptr(unsafe.Pointer(pd))) != 0 {
+ print("netpollupdate: failed to associate (", errno(), ")\n")
+ gothrow("netpollupdate: failed to associate")
+ }
+ pd.user = events
}
// subscribe the fd to the port such that port_getn will return one event.
-void
-runtime·netpollarm(PollDesc* pd, int32 mode)
-{
- runtime·netpolllock(pd);
- switch(mode) {
+func netpollarm(pd *pollDesc, mode int) {
+ lock(&pd.lock)
+ switch mode {
case 'r':
- runtime·netpollupdate(pd, POLLIN, 0);
- break;
+ netpollupdate(pd, _POLLIN, 0)
case 'w':
- runtime·netpollupdate(pd, POLLOUT, 0);
- break;
+ netpollupdate(pd, _POLLOUT, 0)
default:
- runtime·throw("netpollarm: bad mode");
+ gothrow("netpollarm: bad mode")
}
- runtime·netpollunlock(pd);
+ unlock(&pd.lock)
}
+// netpolllasterr holds the last error code returned by port_getn to prevent log spamming
+var netpolllasterr int32
+
// polls for ready network connections
// returns list of goroutines that become runnable
-G*
-runtime·netpoll(bool block)
-{
- static int32 lasterr;
- PortEvent events[128], *ev;
- PollDesc *pd;
- int32 i, mode, clear;
- uint32 n;
- Timespec *wait = nil, zero;
- G *gp;
-
- if(portfd == -1)
- return (nil);
+func netpoll(block bool) (gp *g) {
+ if portfd == -1 {
+ return
+ }
- if(!block) {
- zero.tv_sec = 0;
- zero.tv_nsec = 0;
- wait = &zero;
+ var wait *timespec
+ var zero timespec
+ if !block {
+ wait = &zero
}
+ var events [128]portevent
retry:
- n = 1;
- if(runtime·port_getn(portfd, events, nelem(events), &n, wait) < 0) {
- if(errno != EINTR && errno != lasterr) {
- lasterr = errno;
- runtime·printf("runtime: port_getn on fd %d failed with %d\n", portfd, errno);
+ var n uint32 = 1
+ if port_getn(portfd, &events[0], uint32(len(events)), &n, wait) < 0 {
+ if e := errno(); e != _EINTR && e != netpolllasterr {
+ netpolllasterr = e
+ print("runtime: port_getn on fd ", portfd, " failed with ", e, "\n")
}
- goto retry;
+ goto retry
}
- gp = nil;
- for(i = 0; i < n; i++) {
- ev = &events[i];
+ gp = nil
+ for i := 0; i < int(n); i++ {
+ ev := &events[i]
- if(ev->portev_events == 0)
- continue;
- pd = (PollDesc *)ev->portev_user;
+ if ev.portev_events == 0 {
+ continue
+ }
+ pd := (*pollDesc)(unsafe.Pointer(ev.portev_user))
- mode = 0;
- clear = 0;
- if(ev->portev_events & (POLLIN|POLLHUP|POLLERR)) {
- mode += 'r';
- clear |= POLLIN;
+ var mode, clear int32
+ if (ev.portev_events & (_POLLIN | _POLLHUP | _POLLERR)) != 0 {
+ mode += 'r'
+ clear |= _POLLIN
}
- if(ev->portev_events & (POLLOUT|POLLHUP|POLLERR)) {
- mode += 'w';
- clear |= POLLOUT;
+ if (ev.portev_events & (_POLLOUT | _POLLHUP | _POLLERR)) != 0 {
+ mode += 'w'
+ clear |= _POLLOUT
}
// To effect edge-triggered events, we need to be sure to
// update our association with whatever events were not
@@ -248,17 +225,19 @@ retry:
// for POLLIN|POLLOUT, and we get POLLIN, besides waking
// the goroutine interested in POLLIN we have to not forget
// about the one interested in POLLOUT.
- if(clear != 0) {
- runtime·netpolllock(pd);
- runtime·netpollupdate(pd, 0, clear);
- runtime·netpollunlock(pd);
+ if clear != 0 {
+ lock(&pd.lock)
+ netpollupdate(pd, 0, uint32(clear))
+ unlock(&pd.lock)
}
- if(mode)
- runtime·netpollready(&gp, pd, mode);
+ if mode != 0 {
+ netpollready((**g)(noescape(unsafe.Pointer(&gp))), pd, mode)
+ }
}
- if(block && gp == nil)
- goto retry;
- return gp;
+ if block && gp == nil {
+ goto retry
+ }
+ return gp
}
diff --git a/src/runtime/netpoll_stub.c b/src/runtime/netpoll_stub.go
index b7a8f2944..6c7e79ea3 100644
--- a/src/runtime/netpoll_stub.c
+++ b/src/runtime/netpoll_stub.go
@@ -4,15 +4,12 @@
// +build plan9
-#include "runtime.h"
+package runtime
// Polls for ready network connections.
// Returns list of goroutines that become runnable.
-G*
-runtime·netpoll(bool block)
-{
+func netpoll(block bool) (gp *g) {
// Implementation for platforms that do not support
// integrated network poller.
- USED(block);
- return nil;
+ return
}
diff --git a/src/runtime/netpoll_windows.c b/src/runtime/netpoll_windows.c
deleted file mode 100644
index 64da41ad9..000000000
--- a/src/runtime/netpoll_windows.c
+++ /dev/null
@@ -1,163 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-#define DWORD_MAX 0xffffffff
-
-#pragma dynimport runtime·CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll"
-#pragma dynimport runtime·GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll"
-#pragma dynimport runtime·WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll"
-
-extern void *runtime·CreateIoCompletionPort;
-extern void *runtime·GetQueuedCompletionStatus;
-extern void *runtime·WSAGetOverlappedResult;
-
-#define INVALID_HANDLE_VALUE ((uintptr)-1)
-
-// net_op must be the same as beginning of net.operation. Keep these in sync.
-typedef struct net_op net_op;
-struct net_op
-{
- // used by windows
- Overlapped o;
- // used by netpoll
- PollDesc* pd;
- int32 mode;
- int32 errno;
- uint32 qty;
-};
-
-typedef struct OverlappedEntry OverlappedEntry;
-struct OverlappedEntry
-{
- uintptr key;
- net_op* op; // In reality it's Overlapped*, but we cast it to net_op* anyway.
- uintptr internal;
- uint32 qty;
-};
-
-static void handlecompletion(G **gpp, net_op *o, int32 errno, uint32 qty);
-
-static uintptr iocphandle = INVALID_HANDLE_VALUE; // completion port io handle
-
-void
-runtime·netpollinit(void)
-{
- iocphandle = (uintptr)runtime·stdcall4(runtime·CreateIoCompletionPort, INVALID_HANDLE_VALUE, 0, 0, DWORD_MAX);
- if(iocphandle == 0) {
- runtime·printf("netpoll: failed to create iocp handle (errno=%d)\n", runtime·getlasterror());
- runtime·throw("netpoll: failed to create iocp handle");
- }
- return;
-}
-
-int32
-runtime·netpollopen(uintptr fd, PollDesc *pd)
-{
- USED(pd);
- if(runtime·stdcall4(runtime·CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0)
- return -runtime·getlasterror();
- return 0;
-}
-
-int32
-runtime·netpollclose(uintptr fd)
-{
- // nothing to do
- USED(fd);
- return 0;
-}
-
-void
-runtime·netpollarm(PollDesc* pd, int32 mode)
-{
- USED(pd, mode);
- runtime·throw("unused");
-}
-
-// Polls for completed network IO.
-// Returns list of goroutines that become runnable.
-G*
-runtime·netpoll(bool block)
-{
- OverlappedEntry entries[64];
- uint32 wait, qty, key, flags, n, i;
- int32 errno;
- net_op *op;
- G *gp;
-
- if(iocphandle == INVALID_HANDLE_VALUE)
- return nil;
- gp = nil;
- wait = 0;
- if(block)
- wait = INFINITE;
-retry:
- if(runtime·GetQueuedCompletionStatusEx != nil) {
- n = nelem(entries) / runtime·gomaxprocs;
- if(n < 8)
- n = 8;
- if(block)
- g->m->blocked = true;
- if(runtime·stdcall6(runtime·GetQueuedCompletionStatusEx, iocphandle, (uintptr)entries, n, (uintptr)&n, wait, 0) == 0) {
- g->m->blocked = false;
- errno = runtime·getlasterror();
- if(!block && errno == WAIT_TIMEOUT)
- return nil;
- runtime·printf("netpoll: GetQueuedCompletionStatusEx failed (errno=%d)\n", errno);
- runtime·throw("netpoll: GetQueuedCompletionStatusEx failed");
- }
- g->m->blocked = false;
- for(i = 0; i < n; i++) {
- op = entries[i].op;
- errno = 0;
- qty = 0;
- if(runtime·stdcall5(runtime·WSAGetOverlappedResult, runtime·netpollfd(op->pd), (uintptr)op, (uintptr)&qty, 0, (uintptr)&flags) == 0)
- errno = runtime·getlasterror();
- handlecompletion(&gp, op, errno, qty);
- }
- } else {
- op = nil;
- errno = 0;
- qty = 0;
- if(block)
- g->m->blocked = true;
- if(runtime·stdcall5(runtime·GetQueuedCompletionStatus, iocphandle, (uintptr)&qty, (uintptr)&key, (uintptr)&op, wait) == 0) {
- g->m->blocked = false;
- errno = runtime·getlasterror();
- if(!block && errno == WAIT_TIMEOUT)
- return nil;
- if(op == nil) {
- runtime·printf("netpoll: GetQueuedCompletionStatus failed (errno=%d)\n", errno);
- runtime·throw("netpoll: GetQueuedCompletionStatus failed");
- }
- // dequeued failed IO packet, so report that
- }
- g->m->blocked = false;
- handlecompletion(&gp, op, errno, qty);
- }
- if(block && gp == nil)
- goto retry;
- return gp;
-}
-
-static void
-handlecompletion(G **gpp, net_op *op, int32 errno, uint32 qty)
-{
- int32 mode;
-
- if(op == nil)
- runtime·throw("netpoll: GetQueuedCompletionStatus returned op == nil");
- mode = op->mode;
- if(mode != 'r' && mode != 'w') {
- runtime·printf("netpoll: GetQueuedCompletionStatus returned invalid mode=%d\n", mode);
- runtime·throw("netpoll: GetQueuedCompletionStatus returned invalid mode");
- }
- op->errno = errno;
- op->qty = qty;
- runtime·netpollready(gpp, op->pd, mode);
-}
diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go
new file mode 100644
index 000000000..23d5dc00f
--- /dev/null
+++ b/src/runtime/netpoll_windows.go
@@ -0,0 +1,156 @@
+// 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.
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+const _DWORD_MAX = 0xffffffff
+
+//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll"
+//go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll"
+
+var (
+ _CreateIoCompletionPort,
+ _GetQueuedCompletionStatus,
+ _WSAGetOverlappedResult stdFunction
+)
+
+const _INVALID_HANDLE_VALUE = ^uintptr(0)
+
+// net_op must be the same as beginning of net.operation. Keep these in sync.
+type net_op struct {
+ // used by windows
+ o overlapped
+ // used by netpoll
+ pd *pollDesc
+ mode int32
+ errno int32
+ qty uint32
+}
+
+type overlappedEntry struct {
+ key uintptr
+ op *net_op // In reality it's *overlapped, but we cast it to *net_op anyway.
+ internal uintptr
+ qty uint32
+}
+
+var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle
+
+func netpollinit() {
+ iocphandle = uintptr(stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX))
+ if iocphandle == 0 {
+ println("netpoll: failed to create iocp handle (errno=", getlasterror(), ")")
+ gothrow("netpoll: failed to create iocp handle")
+ }
+}
+
+func netpollopen(fd uintptr, pd *pollDesc) int32 {
+ if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 {
+ return -int32(getlasterror())
+ }
+ return 0
+}
+
+func netpollclose(fd uintptr) int32 {
+ // nothing to do
+ return 0
+}
+
+func netpollarm(pd *pollDesc, mode int) {
+ gothrow("unused")
+}
+
+// Polls for completed network IO.
+// Returns list of goroutines that become runnable.
+func netpoll(block bool) *g {
+ var entries [64]overlappedEntry
+ var wait, qty, key, flags, n, i uint32
+ var errno int32
+ var op *net_op
+ var gp *g
+
+ mp := getg().m
+
+ if iocphandle == _INVALID_HANDLE_VALUE {
+ return nil
+ }
+ gp = nil
+ wait = 0
+ if block {
+ wait = _INFINITE
+ }
+retry:
+ if _GetQueuedCompletionStatusEx != nil {
+ n = uint32(len(entries) / int(gomaxprocs))
+ if n < 8 {
+ n = 8
+ }
+ if block {
+ mp.blocked = true
+ }
+ if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 {
+ mp.blocked = false
+ errno = int32(getlasterror())
+ if !block && errno == _WAIT_TIMEOUT {
+ return nil
+ }
+ println("netpoll: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
+ gothrow("netpoll: GetQueuedCompletionStatusEx failed")
+ }
+ mp.blocked = false
+ for i = 0; i < n; i++ {
+ op = entries[i].op
+ errno = 0
+ qty = 0
+ if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 {
+ errno = int32(getlasterror())
+ }
+ handlecompletion(&gp, op, errno, qty)
+ }
+ } else {
+ op = nil
+ errno = 0
+ qty = 0
+ if block {
+ mp.blocked = true
+ }
+ if stdcall5(_GetQueuedCompletionStatus, iocphandle, uintptr(unsafe.Pointer(&qty)), uintptr(unsafe.Pointer(&key)), uintptr(unsafe.Pointer(&op)), uintptr(wait)) == 0 {
+ mp.blocked = false
+ errno = int32(getlasterror())
+ if !block && errno == _WAIT_TIMEOUT {
+ return nil
+ }
+ if op == nil {
+ println("netpoll: GetQueuedCompletionStatus failed (errno=", errno, ")")
+ gothrow("netpoll: GetQueuedCompletionStatus failed")
+ }
+ // dequeued failed IO packet, so report that
+ }
+ mp.blocked = false
+ handlecompletion(&gp, op, errno, qty)
+ }
+ if block && gp == nil {
+ goto retry
+ }
+ return gp
+}
+
+func handlecompletion(gpp **g, op *net_op, errno int32, qty uint32) {
+ if op == nil {
+ gothrow("netpoll: GetQueuedCompletionStatus returned op == nil")
+ }
+ mode := op.mode
+ if mode != 'r' && mode != 'w' {
+ println("netpoll: GetQueuedCompletionStatus returned invalid mode=", mode)
+ gothrow("netpoll: GetQueuedCompletionStatus returned invalid mode")
+ }
+ op.errno = errno
+ op.qty = qty
+ netpollready((**g)(noescape(unsafe.Pointer(gpp))), op.pd, mode)
+}
diff --git a/src/runtime/noasm_arm.go b/src/runtime/noasm.go
index dd3ef8267..43c16860b 100644
--- a/src/runtime/noasm_arm.go
+++ b/src/runtime/noasm.go
@@ -5,6 +5,8 @@
// Routines that are implemented in assembly in asm_{amd64,386}.s
// but are implemented in Go for arm.
+// +build arm power64 power64le
+
package runtime
func cmpstring(s1, s2 string) int {
diff --git a/src/runtime/norace_test.go b/src/runtime/norace_test.go
index 3b171877a..3681bf190 100644
--- a/src/runtime/norace_test.go
+++ b/src/runtime/norace_test.go
@@ -34,12 +34,12 @@ func benchmarkSyscall(b *testing.B, work, excess int) {
b.RunParallel(func(pb *testing.PB) {
foo := 42
for pb.Next() {
- runtime.Entersyscall()
+ runtime.Entersyscall(0)
for i := 0; i < work; i++ {
foo *= 2
foo /= 2
}
- runtime.Exitsyscall()
+ runtime.Exitsyscall(0)
}
_ = foo
})
diff --git a/src/runtime/os1_darwin.go b/src/runtime/os1_darwin.go
new file mode 100644
index 000000000..2fbf2cae0
--- /dev/null
+++ b/src/runtime/os1_darwin.go
@@ -0,0 +1,423 @@
+// 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 runtime
+
+import "unsafe"
+
+//extern SigTabTT runtime·sigtab[];
+
+var sigset_none = uint32(0)
+var sigset_all = ^uint32(0)
+
+func unimplemented(name string) {
+ println(name, "not implemented")
+ *(*int)(unsafe.Pointer(uintptr(1231))) = 1231
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ mach_semrelease(uint32(mp.waitsema))
+}
+
+//go:nosplit
+func semacreate() uintptr {
+ var x uintptr
+ systemstack(func() {
+ x = uintptr(mach_semcreate())
+ })
+ return x
+}
+
+// BSD interface for threading.
+func osinit() {
+ // bsdthread_register delayed until end of goenvs so that we
+ // can look at the environment first.
+
+ // Use sysctl to fetch hw.ncpu.
+ mib := [2]uint32{6, 3}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ ncpu = int32(out)
+ }
+}
+
+var urandom_data [_HashRandomBytes]byte
+var urandom_dev = []byte("/dev/random\x00")
+
+//go:nosplit
+func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
+ fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+ if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes {
+ *rnd = unsafe.Pointer(&urandom_data[0])
+ *rnd_len = _HashRandomBytes
+ } else {
+ *rnd = nil
+ *rnd_len = 0
+ }
+ close(fd)
+}
+
+func goenvs() {
+ goenvs_unix()
+
+ // Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
+ // but only if we're not using cgo. If we are using cgo we need
+ // to let the C pthread library install its own thread-creation callback.
+ if !iscgo {
+ if bsdthread_register() != 0 {
+ if gogetenv("DYLD_INSERT_LIBRARIES") != "" {
+ gothrow("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)")
+ }
+ gothrow("runtime: bsdthread_register error")
+ }
+ }
+}
+
+func newosproc(mp *m, stk unsafe.Pointer) {
+ mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+ if false {
+ print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int(mp.tls[0]), " ostk=", &mp, "\n")
+ }
+
+ var oset uint32
+ sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+ errno := bsdthread_create(stk, mp, mp.g0, funcPC(mstart))
+ sigprocmask(_SIG_SETMASK, &oset, nil)
+
+ if errno < 0 {
+ print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -errno, ")\n")
+ gothrow("runtime.newosproc")
+ }
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
+ mp.gsignal.m = mp
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ // Initialize signal handling.
+ _g_ := getg()
+ signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
+ sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+ signalstack(nil, 0)
+}
+
+// Mach IPC, to get at semaphores
+// Definitions are in /usr/include/mach on a Mac.
+
+func macherror(r int32, fn string) {
+ print("mach error ", fn, ": ", r, "\n")
+ gothrow("mach error")
+}
+
+const _DebugMach = false
+
+var zerondr machndr
+
+func mach_msgh_bits(a, b uint32) uint32 {
+ return a | b<<8
+}
+
+func mach_msg(h *machheader, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 {
+ // TODO: Loop on interrupt.
+ return mach_msg_trap(unsafe.Pointer(h), op, send_size, rcv_size, rcv_name, timeout, notify)
+}
+
+// Mach RPC (MIG)
+const (
+ _MinMachMsg = 48
+ _MachReply = 100
+)
+
+type codemsg struct {
+ h machheader
+ ndr machndr
+ code int32
+}
+
+func machcall(h *machheader, maxsize int32, rxsize int32) int32 {
+ _g_ := getg()
+ port := _g_.m.machport
+ if port == 0 {
+ port = mach_reply_port()
+ _g_.m.machport = port
+ }
+
+ h.msgh_bits |= mach_msgh_bits(_MACH_MSG_TYPE_COPY_SEND, _MACH_MSG_TYPE_MAKE_SEND_ONCE)
+ h.msgh_local_port = port
+ h.msgh_reserved = 0
+ id := h.msgh_id
+
+ if _DebugMach {
+ p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
+ print("send:\t")
+ var i uint32
+ for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
+ print(" ", p[i])
+ if i%8 == 7 {
+ print("\n\t")
+ }
+ }
+ if i%8 != 0 {
+ print("\n")
+ }
+ }
+ ret := mach_msg(h, _MACH_SEND_MSG|_MACH_RCV_MSG, h.msgh_size, uint32(maxsize), port, 0, 0)
+ if ret != 0 {
+ if _DebugMach {
+ print("mach_msg error ", ret, "\n")
+ }
+ return ret
+ }
+ if _DebugMach {
+ p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
+ var i uint32
+ for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
+ print(" ", p[i])
+ if i%8 == 7 {
+ print("\n\t")
+ }
+ }
+ if i%8 != 0 {
+ print("\n")
+ }
+ }
+ if h.msgh_id != id+_MachReply {
+ if _DebugMach {
+ print("mach_msg _MachReply id mismatch ", h.msgh_id, " != ", id+_MachReply, "\n")
+ }
+ return -303 // MIG_REPLY_MISMATCH
+ }
+ // Look for a response giving the return value.
+ // Any call can send this back with an error,
+ // and some calls only have return values so they
+ // send it back on success too. I don't quite see how
+ // you know it's one of these and not the full response
+ // format, so just look if the message is right.
+ c := (*codemsg)(unsafe.Pointer(h))
+ if uintptr(h.msgh_size) == unsafe.Sizeof(*c) && h.msgh_bits&_MACH_MSGH_BITS_COMPLEX == 0 {
+ if _DebugMach {
+ print("mig result ", c.code, "\n")
+ }
+ return c.code
+ }
+ if h.msgh_size != uint32(rxsize) {
+ if _DebugMach {
+ print("mach_msg _MachReply size mismatch ", h.msgh_size, " != ", rxsize, "\n")
+ }
+ return -307 // MIG_ARRAY_TOO_LARGE
+ }
+ return 0
+}
+
+// Semaphores!
+
+const (
+ tmach_semcreate = 3418
+ rmach_semcreate = tmach_semcreate + _MachReply
+
+ tmach_semdestroy = 3419
+ rmach_semdestroy = tmach_semdestroy + _MachReply
+
+ _KERN_ABORTED = 14
+ _KERN_OPERATION_TIMED_OUT = 49
+)
+
+type tmach_semcreatemsg struct {
+ h machheader
+ ndr machndr
+ policy int32
+ value int32
+}
+
+type rmach_semcreatemsg struct {
+ h machheader
+ body machbody
+ semaphore machport
+}
+
+type tmach_semdestroymsg struct {
+ h machheader
+ body machbody
+ semaphore machport
+}
+
+func mach_semcreate() uint32 {
+ var m [256]uint8
+ tx := (*tmach_semcreatemsg)(unsafe.Pointer(&m))
+ rx := (*rmach_semcreatemsg)(unsafe.Pointer(&m))
+
+ tx.h.msgh_bits = 0
+ tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
+ tx.h.msgh_remote_port = mach_task_self()
+ tx.h.msgh_id = tmach_semcreate
+ tx.ndr = zerondr
+
+ tx.policy = 0 // 0 = SYNC_POLICY_FIFO
+ tx.value = 0
+
+ for {
+ r := machcall(&tx.h, int32(unsafe.Sizeof(m)), int32(unsafe.Sizeof(*rx)))
+ if r == 0 {
+ break
+ }
+ if r == _KERN_ABORTED { // interrupted
+ continue
+ }
+ macherror(r, "semaphore_create")
+ }
+ if rx.body.msgh_descriptor_count != 1 {
+ unimplemented("mach_semcreate desc count")
+ }
+ return rx.semaphore.name
+}
+
+func mach_semdestroy(sem uint32) {
+ var m [256]uint8
+ tx := (*tmach_semdestroymsg)(unsafe.Pointer(&m))
+
+ tx.h.msgh_bits = _MACH_MSGH_BITS_COMPLEX
+ tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
+ tx.h.msgh_remote_port = mach_task_self()
+ tx.h.msgh_id = tmach_semdestroy
+ tx.body.msgh_descriptor_count = 1
+ tx.semaphore.name = sem
+ tx.semaphore.disposition = _MACH_MSG_TYPE_MOVE_SEND
+ tx.semaphore._type = 0
+
+ for {
+ r := machcall(&tx.h, int32(unsafe.Sizeof(m)), 0)
+ if r == 0 {
+ break
+ }
+ if r == _KERN_ABORTED { // interrupted
+ continue
+ }
+ macherror(r, "semaphore_destroy")
+ }
+}
+
+// The other calls have simple system call traps in sys_darwin_{amd64,386}.s
+
+func mach_semaphore_wait(sema uint32) int32
+func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
+func mach_semaphore_signal(sema uint32) int32
+func mach_semaphore_signal_all(sema uint32) int32
+
+func semasleep1(ns int64) int32 {
+ _g_ := getg()
+
+ if ns >= 0 {
+ var nsecs int32
+ secs := timediv(ns, 1000000000, &nsecs)
+ r := mach_semaphore_timedwait(uint32(_g_.m.waitsema), uint32(secs), uint32(nsecs))
+ if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT {
+ return -1
+ }
+ if r != 0 {
+ macherror(r, "semaphore_wait")
+ }
+ return 0
+ }
+
+ for {
+ r := mach_semaphore_wait(uint32(_g_.m.waitsema))
+ if r == 0 {
+ break
+ }
+ if r == _KERN_ABORTED { // interrupted
+ continue
+ }
+ macherror(r, "semaphore_wait")
+ }
+ return 0
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+ var r int32
+ systemstack(func() {
+ r = semasleep1(ns)
+ })
+ return r
+}
+
+//go:nosplit
+func mach_semrelease(sem uint32) {
+ for {
+ r := mach_semaphore_signal(sem)
+ if r == 0 {
+ break
+ }
+ if r == _KERN_ABORTED { // interrupted
+ continue
+ }
+
+ // mach_semrelease must be completely nosplit,
+ // because it is called from Go code.
+ // If we're going to die, start that process on the system stack
+ // to avoid a Go stack split.
+ systemstack(func() { macherror(r, "semaphore_signal") })
+ }
+}
+
+//go:nosplit
+func osyield() {
+ usleep(1)
+}
+
+func memlimit() uintptr {
+ // NOTE(rsc): Could use getrlimit here,
+ // like on FreeBSD or Linux, but Darwin doesn't enforce
+ // ulimit -v, so it's unclear why we'd try to stay within
+ // the limit.
+ return 0
+}
+
+func setsig(i int32, fn uintptr, restart bool) {
+ var sa sigactiont
+ memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+ if restart {
+ sa.sa_flags |= _SA_RESTART
+ }
+ sa.sa_mask = ^uint32(0)
+ sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtime·sigtramp's job is to call into real handler
+ *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
+ sigaction(uint32(i), &sa, nil)
+}
+
+func getsig(i int32) uintptr {
+ var sa sigactiont
+ memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
+ sigaction(uint32(i), nil, &sa)
+ return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
+}
+
+func signalstack(p *byte, n int32) {
+ var st stackt
+ st.ss_sp = p
+ st.ss_size = uintptr(n)
+ st.ss_flags = 0
+ if p == nil {
+ st.ss_flags = _SS_DISABLE
+ }
+ sigaltstack(&st, nil)
+}
+
+func unblocksignals() {
+ sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+}
diff --git a/src/runtime/os1_dragonfly.go b/src/runtime/os1_dragonfly.go
new file mode 100644
index 000000000..82bb45b9b
--- /dev/null
+++ b/src/runtime/os1_dragonfly.go
@@ -0,0 +1,220 @@
+// Copyright 2011 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 runtime
+
+import "unsafe"
+
+// From DragonFly's <sys/sysctl.h>
+const (
+ _CTL_HW = 6
+ _HW_NCPU = 3
+)
+
+var sigset_none = sigset{}
+var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
+
+func getncpu() int32 {
+ mib := [2]uint32{_CTL_HW, _HW_NCPU}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ return int32(out)
+ }
+ return 1
+}
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+ systemstack(func() {
+ futexsleep1(addr, val, ns)
+ })
+}
+
+func futexsleep1(addr *uint32, val uint32, ns int64) {
+ var timeout int32
+ if ns >= 0 {
+ // The timeout is specified in microseconds - ensure that we
+ // do not end up dividing to zero, which would put us to sleep
+ // indefinitely...
+ timeout = timediv(ns, 1000, nil)
+ if timeout == 0 {
+ timeout = 1
+ }
+ }
+
+ // sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
+ // expires or EBUSY if the mutex value does not match.
+ ret := sys_umtx_sleep(addr, int32(val), timeout)
+ if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY {
+ return
+ }
+
+ print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n")
+ *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+ ret := sys_umtx_wakeup(addr, int32(cnt))
+ if ret >= 0 {
+ return
+ }
+
+ systemstack(func() {
+ print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+ *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
+ })
+}
+
+func lwp_start(uintptr)
+
+func newosproc(mp *m, stk unsafe.Pointer) {
+ if false {
+ print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " lwp_start=", funcPC(lwp_start), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
+ }
+
+ var oset sigset
+ sigprocmask(&sigset_all, &oset)
+
+ params := lwpparams{
+ start_func: funcPC(lwp_start),
+ arg: unsafe.Pointer(mp),
+ stack: uintptr(stk),
+ tid1: unsafe.Pointer(&mp.procid),
+ tid2: nil,
+ }
+
+ mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+
+ lwp_create(&params)
+ sigprocmask(&oset, nil)
+}
+
+func osinit() {
+ ncpu = getncpu()
+}
+
+var urandom_data [_HashRandomBytes]byte
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
+ fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+ if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes {
+ *rnd = unsafe.Pointer(&urandom_data[0])
+ *rnd_len = _HashRandomBytes
+ } else {
+ *rnd = nil
+ *rnd_len = 0
+ }
+ close(fd)
+}
+
+func goenvs() {
+ goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ _g_ := getg()
+
+ // m.procid is a uint64, but lwp_start writes an int32. Fix it up.
+ _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
+
+ // Initialize signal handling
+ signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
+ sigprocmask(&sigset_none, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+ signalstack(nil, 0)
+}
+
+func memlimit() uintptr {
+ /*
+ TODO: Convert to Go when something actually uses the result.
+
+ Rlimit rl;
+ extern byte runtime·text[], runtime·end[];
+ uintptr used;
+
+ if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+ return 0;
+ if(rl.rlim_cur >= 0x7fffffff)
+ return 0;
+
+ // Estimate our VM footprint excluding the heap.
+ // Not an exact science: use size of binary plus
+ // some room for thread stacks.
+ used = runtime·end - runtime·text + (64<<20);
+ if(used >= rl.rlim_cur)
+ return 0;
+
+ // If there's not at least 16 MB left, we're probably
+ // not going to be able to do much. Treat as no limit.
+ rl.rlim_cur -= used;
+ if(rl.rlim_cur < (16<<20))
+ return 0;
+
+ return rl.rlim_cur - used;
+ */
+ return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+ sa_sigaction uintptr
+ sa_flags int32
+ sa_mask sigset
+}
+
+func setsig(i int32, fn uintptr, restart bool) {
+ var sa sigactiont
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+ if restart {
+ sa.sa_flags |= _SA_RESTART
+ }
+ sa.sa_mask = sigset_all
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
+ sa.sa_sigaction = fn
+ sigaction(i, &sa, nil)
+}
+
+func getsig(i int32) uintptr {
+ var sa sigactiont
+ sigaction(i, nil, &sa)
+ if sa.sa_sigaction == funcPC(sigtramp) {
+ return funcPC(sighandler)
+ }
+ return sa.sa_sigaction
+}
+
+func signalstack(p *byte, n int32) {
+ var st sigaltstackt
+ st.ss_sp = uintptr(unsafe.Pointer(p))
+ st.ss_size = uintptr(n)
+ st.ss_flags = 0
+ if p == nil {
+ st.ss_flags = _SS_DISABLE
+ }
+ sigaltstack(&st, nil)
+}
+
+func unblocksignals() {
+ sigprocmask(&sigset_none, nil)
+}
diff --git a/src/runtime/os1_freebsd.go b/src/runtime/os1_freebsd.go
new file mode 100644
index 000000000..2cacfbae6
--- /dev/null
+++ b/src/runtime/os1_freebsd.go
@@ -0,0 +1,221 @@
+// Copyright 2011 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 runtime
+
+import "unsafe"
+
+// From FreeBSD's <sys/sysctl.h>
+const (
+ _CTL_HW = 6
+ _HW_NCPU = 3
+)
+
+var sigset_none = sigset{}
+var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
+
+func getncpu() int32 {
+ mib := [2]uint32{_CTL_HW, _HW_NCPU}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ return int32(out)
+ }
+ return 1
+}
+
+// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
+// thus the code is largely similar. See Linux implementation
+// and lock_futex.c for comments.
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+ systemstack(func() {
+ futexsleep1(addr, val, ns)
+ })
+}
+
+func futexsleep1(addr *uint32, val uint32, ns int64) {
+ var tsp *timespec
+ if ns >= 0 {
+ var ts timespec
+ ts.tv_nsec = 0
+ ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
+ tsp = &ts
+ }
+ ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
+ if ret >= 0 || ret == -_EINTR {
+ return
+ }
+ print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
+ *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+ ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
+ if ret >= 0 {
+ return
+ }
+
+ systemstack(func() {
+ print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+ })
+}
+
+func thr_start()
+
+func newosproc(mp *m, stk unsafe.Pointer) {
+ if false {
+ print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
+ }
+
+ // NOTE(rsc): This code is confused. stackbase is the top of the stack
+ // and is equal to stk. However, it's working, so I'm not changing it.
+ param := thrparam{
+ start_func: funcPC(thr_start),
+ arg: unsafe.Pointer(mp),
+ stack_base: mp.g0.stack.hi,
+ stack_size: uintptr(stk) - mp.g0.stack.hi,
+ child_tid: unsafe.Pointer(&mp.procid),
+ parent_tid: nil,
+ tls_base: unsafe.Pointer(&mp.tls[0]),
+ tls_size: unsafe.Sizeof(mp.tls),
+ }
+ mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+
+ var oset sigset
+ sigprocmask(&sigset_all, &oset)
+ thr_new(&param, int32(unsafe.Sizeof(param)))
+ sigprocmask(&oset, nil)
+}
+
+func osinit() {
+ ncpu = getncpu()
+}
+
+var urandom_data [_HashRandomBytes]byte
+var urandom_dev = []byte("/dev/random\x00")
+
+//go:nosplit
+func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
+ fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+ if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes {
+ *rnd = unsafe.Pointer(&urandom_data[0])
+ *rnd_len = _HashRandomBytes
+ } else {
+ *rnd = nil
+ *rnd_len = 0
+ }
+ close(fd)
+}
+
+func goenvs() {
+ goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ _g_ := getg()
+
+ // m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
+ // Fix it up. (Only matters on big-endian, but be clean anyway.)
+ if ptrSize == 4 {
+ _g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
+ }
+
+ // Initialize signal handling.
+ signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
+ sigprocmask(&sigset_none, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+ signalstack(nil, 0)
+}
+
+func memlimit() uintptr {
+ /*
+ TODO: Convert to Go when something actually uses the result.
+ Rlimit rl;
+ extern byte runtime·text[], runtime·end[];
+ uintptr used;
+
+ if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+ return 0;
+ if(rl.rlim_cur >= 0x7fffffff)
+ return 0;
+
+ // Estimate our VM footprint excluding the heap.
+ // Not an exact science: use size of binary plus
+ // some room for thread stacks.
+ used = runtime·end - runtime·text + (64<<20);
+ if(used >= rl.rlim_cur)
+ return 0;
+
+ // If there's not at least 16 MB left, we're probably
+ // not going to be able to do much. Treat as no limit.
+ rl.rlim_cur -= used;
+ if(rl.rlim_cur < (16<<20))
+ return 0;
+
+ return rl.rlim_cur - used;
+ */
+
+ return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+ sa_handler uintptr
+ sa_flags int32
+ sa_mask sigset
+}
+
+func setsig(i int32, fn uintptr, restart bool) {
+ var sa sigactiont
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+ if restart {
+ sa.sa_flags |= _SA_RESTART
+ }
+ sa.sa_mask = sigset_all
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
+ sa.sa_handler = fn
+ sigaction(i, &sa, nil)
+}
+func getsig(i int32) uintptr {
+ var sa sigactiont
+ sigaction(i, nil, &sa)
+ if sa.sa_handler == funcPC(sigtramp) {
+ return funcPC(sighandler)
+ }
+ return sa.sa_handler
+}
+
+func signalstack(p *byte, n int32) {
+ var st stackt
+ st.ss_sp = uintptr(unsafe.Pointer(p))
+ st.ss_size = uintptr(n)
+ st.ss_flags = 0
+ if p == nil {
+ st.ss_flags = _SS_DISABLE
+ }
+ sigaltstack(&st, nil)
+}
+
+func unblocksignals() {
+ sigprocmask(&sigset_none, nil)
+}
diff --git a/src/runtime/os1_linux.go b/src/runtime/os1_linux.go
new file mode 100644
index 000000000..67fa6391e
--- /dev/null
+++ b/src/runtime/os1_linux.go
@@ -0,0 +1,287 @@
+// 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 runtime
+
+import "unsafe"
+
+var sigset_none sigset
+var sigset_all sigset = sigset{^uint32(0), ^uint32(0)}
+
+// Linux futex.
+//
+// futexsleep(uint32 *addr, uint32 val)
+// futexwakeup(uint32 *addr)
+//
+// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
+// Futexwakeup wakes up threads sleeping on addr.
+// Futexsleep is allowed to wake up spuriously.
+
+const (
+ _FUTEX_WAIT = 0
+ _FUTEX_WAKE = 1
+)
+
+// Atomically,
+// if(*addr == val) sleep
+// Might be woken up spuriously; that's allowed.
+// Don't sleep longer than ns; ns < 0 means forever.
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+ var ts timespec
+
+ // Some Linux kernels have a bug where futex of
+ // FUTEX_WAIT returns an internal error code
+ // as an errno. Libpthread ignores the return value
+ // here, and so can we: as it says a few lines up,
+ // spurious wakeups are allowed.
+ if ns < 0 {
+ futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, nil, nil, 0)
+ return
+ }
+
+ // It's difficult to live within the no-split stack limits here.
+ // On ARM and 386, a 64-bit divide invokes a general software routine
+ // that needs more stack than we can afford. So we use timediv instead.
+ // But on real 64-bit systems, where words are larger but the stack limit
+ // is not, even timediv is too heavy, and we really need to use just an
+ // ordinary machine instruction.
+ if ptrSize == 8 {
+ ts.set_sec(ns / 1000000000)
+ ts.set_nsec(int32(ns % 1000000000))
+ } else {
+ ts.tv_nsec = 0
+ ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
+ }
+ futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, unsafe.Pointer(&ts), nil, 0)
+}
+
+// If any procs are sleeping on addr, wake up at most cnt.
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+ ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE, cnt, nil, nil, 0)
+ if ret >= 0 {
+ return
+ }
+
+ // I don't know that futex wakeup can return
+ // EAGAIN or EINTR, but if it does, it would be
+ // safe to loop and call futex again.
+ systemstack(func() {
+ print("futexwakeup addr=", addr, " returned ", ret, "\n")
+ })
+
+ *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
+}
+
+func getproccount() int32 {
+ var buf [16]uintptr
+ r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0])
+ n := int32(0)
+ for _, v := range buf[:r/ptrSize] {
+ for i := 0; i < 64; i++ {
+ n += int32(v & 1)
+ v >>= 1
+ }
+ }
+ if n == 0 {
+ n = 1
+ }
+ return n
+}
+
+// Clone, the Linux rfork.
+const (
+ _CLONE_VM = 0x100
+ _CLONE_FS = 0x200
+ _CLONE_FILES = 0x400
+ _CLONE_SIGHAND = 0x800
+ _CLONE_PTRACE = 0x2000
+ _CLONE_VFORK = 0x4000
+ _CLONE_PARENT = 0x8000
+ _CLONE_THREAD = 0x10000
+ _CLONE_NEWNS = 0x20000
+ _CLONE_SYSVSEM = 0x40000
+ _CLONE_SETTLS = 0x80000
+ _CLONE_PARENT_SETTID = 0x100000
+ _CLONE_CHILD_CLEARTID = 0x200000
+ _CLONE_UNTRACED = 0x800000
+ _CLONE_CHILD_SETTID = 0x1000000
+ _CLONE_STOPPED = 0x2000000
+ _CLONE_NEWUTS = 0x4000000
+ _CLONE_NEWIPC = 0x8000000
+)
+
+func newosproc(mp *m, stk unsafe.Pointer) {
+ /*
+ * note: strace gets confused if we use CLONE_PTRACE here.
+ */
+ var flags int32 = _CLONE_VM | /* share memory */
+ _CLONE_FS | /* share cwd, etc */
+ _CLONE_FILES | /* share fd table */
+ _CLONE_SIGHAND | /* share sig handler table */
+ _CLONE_THREAD /* revisit - okay for now */
+
+ mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+ if false {
+ print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
+ }
+
+ // Disable signals during clone, so that the new thread starts
+ // with signals disabled. It will enable them in minit.
+ var oset sigset
+ rtsigprocmask(_SIG_SETMASK, &sigset_all, &oset, int32(unsafe.Sizeof(oset)))
+ ret := clone(flags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
+ rtsigprocmask(_SIG_SETMASK, &oset, nil, int32(unsafe.Sizeof(oset)))
+
+ if ret < 0 {
+ print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n")
+ gothrow("newosproc")
+ }
+}
+
+func osinit() {
+ ncpu = getproccount()
+}
+
+// Random bytes initialized at startup. These come
+// from the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.c).
+// byte* runtime·startup_random_data;
+// uint32 runtime·startup_random_data_len;
+
+var urandom_data [_HashRandomBytes]byte
+var urandom_dev = []byte("/dev/random\x00")
+
+//go:nosplit
+func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
+ if startup_random_data != nil {
+ *rnd = unsafe.Pointer(startup_random_data)
+ *rnd_len = int32(startup_random_data_len)
+ return
+ }
+ fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+ if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes {
+ *rnd = unsafe.Pointer(&urandom_data[0])
+ *rnd_len = _HashRandomBytes
+ } else {
+ *rnd = nil
+ *rnd_len = 0
+ }
+ close(fd)
+}
+
+func goenvs() {
+ goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024) // Linux wants >= 2K
+ mp.gsignal.m = mp
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ // Initialize signal handling.
+ _g_ := getg()
+ signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
+ rtsigprocmask(_SIG_SETMASK, &sigset_none, nil, int32(unsafe.Sizeof(sigset_none)))
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+ signalstack(nil, 0)
+}
+
+func memlimit() uintptr {
+ /*
+ TODO: Convert to Go when something actually uses the result.
+
+ Rlimit rl;
+ extern byte runtime·text[], runtime·end[];
+ uintptr used;
+
+ if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+ return 0;
+ if(rl.rlim_cur >= 0x7fffffff)
+ return 0;
+
+ // Estimate our VM footprint excluding the heap.
+ // Not an exact science: use size of binary plus
+ // some room for thread stacks.
+ used = runtime·end - runtime·text + (64<<20);
+ if(used >= rl.rlim_cur)
+ return 0;
+
+ // If there's not at least 16 MB left, we're probably
+ // not going to be able to do much. Treat as no limit.
+ rl.rlim_cur -= used;
+ if(rl.rlim_cur < (16<<20))
+ return 0;
+
+ return rl.rlim_cur - used;
+ */
+
+ return 0
+}
+
+//#ifdef GOARCH_386
+//#define sa_handler k_sa_handler
+//#endif
+
+func sigreturn()
+func sigtramp()
+
+func setsig(i int32, fn uintptr, restart bool) {
+ var sa sigactiont
+ memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTORER
+ if restart {
+ sa.sa_flags |= _SA_RESTART
+ }
+ sa.sa_mask = ^uint64(0)
+ // Although Linux manpage says "sa_restorer element is obsolete and
+ // should not be used". x86_64 kernel requires it. Only use it on
+ // x86.
+ if GOARCH == "386" || GOARCH == "amd64" {
+ sa.sa_restorer = funcPC(sigreturn)
+ }
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
+ sa.sa_handler = fn
+ if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 {
+ gothrow("rt_sigaction failure")
+ }
+}
+
+func getsig(i int32) uintptr {
+ var sa sigactiont
+
+ memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
+ if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
+ gothrow("rt_sigaction read failure")
+ }
+ if sa.sa_handler == funcPC(sigtramp) {
+ return funcPC(sighandler)
+ }
+ return sa.sa_handler
+}
+
+func signalstack(p *byte, n int32) {
+ var st sigaltstackt
+ st.ss_sp = p
+ st.ss_size = uintptr(n)
+ st.ss_flags = 0
+ if p == nil {
+ st.ss_flags = _SS_DISABLE
+ }
+ sigaltstack(&st, nil)
+}
+
+func unblocksignals() {
+ rtsigprocmask(_SIG_SETMASK, &sigset_none, nil, int32(unsafe.Sizeof(sigset_none)))
+}
diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go
new file mode 100644
index 000000000..7b4c99a3d
--- /dev/null
+++ b/src/runtime/os1_nacl.go
@@ -0,0 +1,197 @@
+// Copyright 2010 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 runtime
+
+import "unsafe"
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+}
+
+func sigtramp()
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ _g_ := getg()
+
+ // Initialize signal handling
+ ret := nacl_exception_stack(_g_.m.gsignal.stack.lo, 32*1024)
+ if ret < 0 {
+ print("runtime: nacl_exception_stack: error ", -ret, "\n")
+ }
+
+ ret = nacl_exception_handler(funcPC(sigtramp), nil)
+ if ret < 0 {
+ print("runtime: nacl_exception_handler: error ", -ret, "\n")
+ }
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+}
+
+func osinit() {
+ ncpu = 1
+ getg().m.procid = 2
+ //nacl_exception_handler(funcPC(sigtramp), nil);
+}
+
+func crash() {
+ *(*int32)(nil) = 0
+}
+
+//go:nosplit
+func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
+ *rnd = nil
+ *rnd_len = 0
+}
+
+func goenvs() {
+ goenvs_unix()
+}
+
+func initsig() {
+}
+
+//go:nosplit
+func usleep(us uint32) {
+ var ts timespec
+
+ ts.tv_sec = int64(us / 1e6)
+ ts.tv_nsec = int32(us%1e6) * 1e3
+ nacl_nanosleep(&ts, nil)
+}
+
+func mstart_nacl()
+
+func newosproc(mp *m, stk unsafe.Pointer) {
+ tls := (*[3]unsafe.Pointer)(unsafe.Pointer(&mp.tls))
+ tls[0] = unsafe.Pointer(mp.g0)
+ tls[1] = unsafe.Pointer(mp)
+ ret := nacl_thread_create(funcPC(mstart_nacl), stk, unsafe.Pointer(&tls[2]), nil)
+ if ret < 0 {
+ print("nacl_thread_create: error ", -ret, "\n")
+ gothrow("newosproc")
+ }
+}
+
+//go:nosplit
+func semacreate() uintptr {
+ var cond uintptr
+ systemstack(func() {
+ mu := nacl_mutex_create(0)
+ if mu < 0 {
+ print("nacl_mutex_create: error ", -mu, "\n")
+ gothrow("semacreate")
+ }
+ c := nacl_cond_create(0)
+ if c < 0 {
+ print("nacl_cond_create: error ", -cond, "\n")
+ gothrow("semacreate")
+ }
+ cond = uintptr(c)
+ _g_ := getg()
+ _g_.m.waitsemalock = uint32(mu)
+ })
+ return cond
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+ var ret int32
+
+ systemstack(func() {
+ _g_ := getg()
+ if nacl_mutex_lock(int32(_g_.m.waitsemalock)) < 0 {
+ gothrow("semasleep")
+ }
+
+ for _g_.m.waitsemacount == 0 {
+ if ns < 0 {
+ if nacl_cond_wait(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock)) < 0 {
+ gothrow("semasleep")
+ }
+ } else {
+ var ts timespec
+ end := ns + nanotime()
+ ts.tv_sec = end / 1e9
+ ts.tv_nsec = int32(end % 1e9)
+ r := nacl_cond_timed_wait_abs(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock), &ts)
+ if r == -_ETIMEDOUT {
+ nacl_mutex_unlock(int32(_g_.m.waitsemalock))
+ ret = -1
+ return
+ }
+ if r < 0 {
+ gothrow("semasleep")
+ }
+ }
+ }
+
+ _g_.m.waitsemacount = 0
+ nacl_mutex_unlock(int32(_g_.m.waitsemalock))
+ ret = 0
+ })
+ return ret
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ systemstack(func() {
+ if nacl_mutex_lock(int32(mp.waitsemalock)) < 0 {
+ gothrow("semawakeup")
+ }
+ if mp.waitsemacount != 0 {
+ gothrow("semawakeup")
+ }
+ mp.waitsemacount = 1
+ nacl_cond_signal(int32(mp.waitsema))
+ nacl_mutex_unlock(int32(mp.waitsemalock))
+ })
+}
+
+func memlimit() uintptr {
+ return 0
+}
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+func badsignal2() {
+ write(2, unsafe.Pointer(&badsignal1[0]), int32(len(badsignal1)))
+ exit(2)
+}
+
+var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n")
+
+func madvise(addr unsafe.Pointer, n uintptr, flags int32) {}
+func munmap(addr unsafe.Pointer, n uintptr) {}
+func resetcpuprofiler(hz int32) {}
+func sigdisable(uint32) {}
+func sigenable(uint32) {}
+func closeonexec(int32) {}
+
+var writelock uint32 // test-and-set spin lock for write
+
+/*
+An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
+
+void (*nacl_irt_query)(void);
+
+int8 nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
+void *nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
+int32 nacl_irt_basic_v0_1_size = sizeof(nacl_irt_basic_v0_1);
+
+int8 nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
+void *nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
+int32 nacl_irt_memory_v0_3_size = sizeof(nacl_irt_memory_v0_3);
+
+int8 nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
+void *nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
+int32 nacl_irt_thread_v0_1_size = sizeof(nacl_irt_thread_v0_1);
+*/
diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go
new file mode 100644
index 000000000..493be30fa
--- /dev/null
+++ b/src/runtime/os1_netbsd.go
@@ -0,0 +1,265 @@
+// Copyright 2011 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 runtime
+
+import "unsafe"
+
+const (
+ _ESRCH = 3
+ _ENOTSUP = 91
+
+ // From NetBSD's <sys/time.h>
+ _CLOCK_REALTIME = 0
+ _CLOCK_VIRTUAL = 1
+ _CLOCK_PROF = 2
+ _CLOCK_MONOTONIC = 3
+)
+
+var sigset_none = sigset{}
+var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
+
+// From NetBSD's <sys/sysctl.h>
+const (
+ _CTL_HW = 6
+ _HW_NCPU = 3
+)
+
+func getncpu() int32 {
+ mib := [2]uint32{_CTL_HW, _HW_NCPU}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ return int32(out)
+ }
+ return 1
+}
+
+//go:nosplit
+func semacreate() uintptr {
+ return 1
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+ _g_ := getg()
+
+ // spin-mutex lock
+ for {
+ if xchg(&_g_.m.waitsemalock, 1) == 0 {
+ break
+ }
+ osyield()
+ }
+
+ for {
+ // lock held
+ if _g_.m.waitsemacount == 0 {
+ // sleep until semaphore != 0 or timeout.
+ // thrsleep unlocks m.waitsemalock.
+ if ns < 0 {
+ // TODO(jsing) - potential deadlock!
+ //
+ // There is a potential deadlock here since we
+ // have to release the waitsemalock mutex
+ // before we call lwp_park() to suspend the
+ // thread. This allows another thread to
+ // release the lock and call lwp_unpark()
+ // before the thread is actually suspended.
+ // If this occurs the current thread will end
+ // up sleeping indefinitely. Unfortunately
+ // the NetBSD kernel does not appear to provide
+ // a mechanism for unlocking the userspace
+ // mutex once the thread is actually parked.
+ atomicstore(&_g_.m.waitsemalock, 0)
+ lwp_park(nil, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
+ } else {
+ var ts timespec
+ var nsec int32
+ ns += nanotime()
+ ts.set_sec(timediv(ns, 1000000000, &nsec))
+ ts.set_nsec(nsec)
+ // TODO(jsing) - potential deadlock!
+ // See above for details.
+ atomicstore(&_g_.m.waitsemalock, 0)
+ lwp_park(&ts, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
+ }
+ // reacquire lock
+ for {
+ if xchg(&_g_.m.waitsemalock, 1) == 0 {
+ break
+ }
+ osyield()
+ }
+ }
+
+ // lock held (again)
+ if _g_.m.waitsemacount != 0 {
+ // semaphore is available.
+ _g_.m.waitsemacount--
+ // spin-mutex unlock
+ atomicstore(&_g_.m.waitsemalock, 0)
+ return 0
+ }
+
+ // semaphore not available.
+ // if there is a timeout, stop now.
+ // otherwise keep trying.
+ if ns >= 0 {
+ break
+ }
+ }
+
+ // lock held but giving up
+ // spin-mutex unlock
+ atomicstore(&_g_.m.waitsemalock, 0)
+ return -1
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ // spin-mutex lock
+ for {
+ if xchg(&mp.waitsemalock, 1) == 0 {
+ break
+ }
+ osyield()
+ }
+
+ mp.waitsemacount++
+ // TODO(jsing) - potential deadlock, see semasleep() for details.
+ // Confirm that LWP is parked before unparking...
+ ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount))
+ if ret != 0 && ret != _ESRCH {
+ // semawakeup can be called on signal stack.
+ systemstack(func() {
+ print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
+ })
+ }
+
+ // spin-mutex unlock
+ atomicstore(&mp.waitsemalock, 0)
+}
+
+func newosproc(mp *m, stk unsafe.Pointer) {
+ if false {
+ print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
+ }
+
+ mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+
+ var uc ucontextt
+ getcontext(unsafe.Pointer(&uc))
+
+ uc.uc_flags = _UC_SIGMASK | _UC_CPU
+ uc.uc_link = nil
+ uc.uc_sigmask = sigset_all
+
+ lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(mstart))
+
+ ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid))
+ if ret < 0 {
+ print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
+ gothrow("runtime.newosproc")
+ }
+}
+
+func osinit() {
+ ncpu = getncpu()
+}
+
+var urandom_data [_HashRandomBytes]byte
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
+ fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+ if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes {
+ *rnd = unsafe.Pointer(&urandom_data[0])
+ *rnd_len = _HashRandomBytes
+ } else {
+ *rnd = nil
+ *rnd_len = 0
+ }
+ close(fd)
+}
+
+func goenvs() {
+ goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ _g_ := getg()
+ _g_.m.procid = uint64(lwp_self())
+
+ // Initialize signal handling
+ signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
+ sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+ signalstack(nil, 0)
+}
+
+func memlimit() uintptr {
+ return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+ sa_sigaction uintptr
+ sa_mask sigset
+ sa_flags int32
+}
+
+func setsig(i int32, fn uintptr, restart bool) {
+ var sa sigactiont
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+ if restart {
+ sa.sa_flags |= _SA_RESTART
+ }
+ sa.sa_mask = sigset_all
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
+ sa.sa_sigaction = fn
+ sigaction(i, &sa, nil)
+}
+
+func getsig(i int32) uintptr {
+ var sa sigactiont
+ sigaction(i, nil, &sa)
+ if sa.sa_sigaction == funcPC(sigtramp) {
+ return funcPC(sighandler)
+ }
+ return sa.sa_sigaction
+}
+
+func signalstack(p *byte, n int32) {
+ var st sigaltstackt
+
+ st.ss_sp = uintptr(unsafe.Pointer(p))
+ st.ss_size = uintptr(n)
+ st.ss_flags = 0
+ if p == nil {
+ st.ss_flags = _SS_DISABLE
+ }
+ sigaltstack(&st, nil)
+}
+
+func unblocksignals() {
+ sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+}
diff --git a/src/runtime/os1_netbsd_386.go b/src/runtime/os1_netbsd_386.go
new file mode 100644
index 000000000..037f7e36d
--- /dev/null
+++ b/src/runtime/os1_netbsd_386.go
@@ -0,0 +1,16 @@
+// 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 runtime
+
+import "unsafe"
+
+func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) {
+ // Machine dependent mcontext initialisation for LWP.
+ mc.__gregs[_REG_EIP] = uint32(funcPC(lwp_tramp))
+ mc.__gregs[_REG_UESP] = uint32(uintptr(stk))
+ mc.__gregs[_REG_EBX] = uint32(uintptr(unsafe.Pointer(mp)))
+ mc.__gregs[_REG_EDX] = uint32(uintptr(unsafe.Pointer(gp)))
+ mc.__gregs[_REG_ESI] = uint32(fn)
+}
diff --git a/src/runtime/os1_netbsd_amd64.go b/src/runtime/os1_netbsd_amd64.go
new file mode 100644
index 000000000..5118b0c4f
--- /dev/null
+++ b/src/runtime/os1_netbsd_amd64.go
@@ -0,0 +1,16 @@
+// 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 runtime
+
+import "unsafe"
+
+func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) {
+ // Machine dependent mcontext initialisation for LWP.
+ mc.__gregs[_REG_RIP] = uint64(funcPC(lwp_tramp))
+ mc.__gregs[_REG_RSP] = uint64(uintptr(stk))
+ mc.__gregs[_REG_R8] = uint64(uintptr(unsafe.Pointer(mp)))
+ mc.__gregs[_REG_R9] = uint64(uintptr(unsafe.Pointer(gp)))
+ mc.__gregs[_REG_R12] = uint64(fn)
+}
diff --git a/src/runtime/os1_openbsd.go b/src/runtime/os1_openbsd.go
new file mode 100644
index 000000000..d5ffe10a8
--- /dev/null
+++ b/src/runtime/os1_openbsd.go
@@ -0,0 +1,235 @@
+// Copyright 2011 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 runtime
+
+import "unsafe"
+
+const (
+ ESRCH = 3
+ EAGAIN = 35
+ EWOULDBLOCK = EAGAIN
+ ENOTSUP = 91
+
+ // From OpenBSD's sys/time.h
+ CLOCK_REALTIME = 0
+ CLOCK_VIRTUAL = 1
+ CLOCK_PROF = 2
+ CLOCK_MONOTONIC = 3
+)
+
+var sigset_none = uint32(0)
+var sigset_all = ^sigset_none
+
+// From OpenBSD's <sys/sysctl.h>
+const (
+ CTL_HW = 6
+ HW_NCPU = 3
+)
+
+func getncpu() int32 {
+ mib := [2]uint32{CTL_HW, HW_NCPU}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+
+ // Fetch hw.ncpu via sysctl.
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ return int32(out)
+ }
+ return 1
+}
+
+//go:nosplit
+func semacreate() uintptr {
+ return 1
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+ _g_ := getg()
+
+ // Compute sleep deadline.
+ var tsp *timespec
+ if ns >= 0 {
+ var ts timespec
+ var nsec int32
+ ns += nanotime()
+ ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
+ ts.set_nsec(nsec)
+ tsp = &ts
+ }
+
+ for {
+ // spin-mutex lock
+ for {
+ if xchg(&_g_.m.waitsemalock, 1) == 0 {
+ break
+ }
+ osyield()
+ }
+
+ if _g_.m.waitsemacount != 0 {
+ // semaphore is available.
+ _g_.m.waitsemacount--
+ // spin-mutex unlock
+ atomicstore(&_g_.m.waitsemalock, 0)
+ return 0 // semaphore acquired
+ }
+
+ // sleep until semaphore != 0 or timeout.
+ // thrsleep unlocks m.waitsemalock.
+ ret := thrsleep((uintptr)(unsafe.Pointer(&_g_.m.waitsemacount)), CLOCK_MONOTONIC, tsp, (uintptr)(unsafe.Pointer(&_g_.m.waitsemalock)), (*int32)(unsafe.Pointer(&_g_.m.waitsemacount)))
+ if ret == EWOULDBLOCK {
+ return -1
+ }
+ }
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ // spin-mutex lock
+ for {
+ if xchg(&mp.waitsemalock, 1) == 0 {
+ break
+ }
+ osyield()
+ }
+ mp.waitsemacount++
+ ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
+ if ret != 0 && ret != ESRCH {
+ // semawakeup can be called on signal stack.
+ systemstack(func() {
+ print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
+ })
+ }
+ // spin-mutex unlock
+ atomicstore(&mp.waitsemalock, 0)
+}
+
+func newosproc(mp *m, stk unsafe.Pointer) {
+ if false {
+ print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
+ }
+
+ mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+
+ param := tforkt{
+ tf_tcb: unsafe.Pointer(&mp.tls[0]),
+ tf_tid: (*int32)(unsafe.Pointer(&mp.procid)),
+ tf_stack: uintptr(stk),
+ }
+
+ oset := sigprocmask(_SIG_SETMASK, sigset_all)
+ ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
+ sigprocmask(_SIG_SETMASK, oset)
+
+ if ret < 0 {
+ print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
+ if ret == -ENOTSUP {
+ print("runtime: is kern.rthreads disabled?\n")
+ }
+ gothrow("runtime.newosproc")
+ }
+}
+
+func osinit() {
+ ncpu = getncpu()
+}
+
+var urandom_data [_HashRandomBytes]byte
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
+ fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+ if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes {
+ *rnd = unsafe.Pointer(&urandom_data[0])
+ *rnd_len = _HashRandomBytes
+ } else {
+ *rnd = nil
+ *rnd_len = 0
+ }
+ close(fd)
+}
+
+func goenvs() {
+ goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ _g_ := getg()
+
+ // m.procid is a uint64, but tfork writes an int32. Fix it up.
+ _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
+
+ // Initialize signal handling
+ signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
+ sigprocmask(_SIG_SETMASK, sigset_none)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+ signalstack(nil, 0)
+}
+
+func memlimit() uintptr {
+ return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+ sa_sigaction uintptr
+ sa_mask uint32
+ sa_flags int32
+}
+
+func setsig(i int32, fn uintptr, restart bool) {
+ var sa sigactiont
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+ if restart {
+ sa.sa_flags |= _SA_RESTART
+ }
+ sa.sa_mask = sigset_all
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
+ sa.sa_sigaction = fn
+ sigaction(i, &sa, nil)
+}
+
+func getsig(i int32) uintptr {
+ var sa sigactiont
+ sigaction(i, nil, &sa)
+ if sa.sa_sigaction == funcPC(sigtramp) {
+ return funcPC(sighandler)
+ }
+ return sa.sa_sigaction
+}
+
+func signalstack(p *byte, n int32) {
+ var st stackt
+
+ st.ss_sp = uintptr(unsafe.Pointer(p))
+ st.ss_size = uintptr(n)
+ st.ss_flags = 0
+ if p == nil {
+ st.ss_flags = _SS_DISABLE
+ }
+ sigaltstack(&st, nil)
+}
+
+func unblocksignals() {
+ sigprocmask(_SIG_SETMASK, sigset_none)
+}
diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go
new file mode 100644
index 000000000..0f8da03f2
--- /dev/null
+++ b/src/runtime/os1_plan9.go
@@ -0,0 +1,270 @@
+// Copyright 2010 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 runtime
+
+import "unsafe"
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ // Initialize stack and goroutine for note handling.
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+ mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, _FlagNoScan))
+ // Initialize stack for handling strings from the
+ // errstr system call, as used in package syscall.
+ mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, _FlagNoScan))
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ // Mask all SSE floating-point exceptions
+ // when running on the 64-bit kernel.
+ setfpmasks()
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+}
+
+var sysstat = []byte("/dev/sysstat\x00")
+
+func getproccount() int32 {
+ var buf [2048]byte
+ fd := open(&sysstat[0], _OREAD, 0)
+ if fd < 0 {
+ return 1
+ }
+ ncpu := int32(0)
+ for {
+ n := read(fd, unsafe.Pointer(&buf), int32(len(buf)))
+ if n <= 0 {
+ break
+ }
+ for i := int32(0); i < n; i++ {
+ if buf[i] == '\n' {
+ ncpu++
+ }
+ }
+ }
+ close(fd)
+ if ncpu == 0 {
+ ncpu = 1
+ }
+ return ncpu
+}
+
+var pid = []byte("#c/pid\x00")
+
+func getpid() uint64 {
+ var b [20]byte
+ fd := open(&pid[0], 0, 0)
+ if fd >= 0 {
+ read(fd, unsafe.Pointer(&b), int32(len(b)))
+ close(fd)
+ }
+ c := b[:]
+ for c[0] == ' ' || c[0] == '\t' {
+ c = c[1:]
+ }
+ return uint64(atoi(c))
+}
+
+func osinit() {
+ initBloc()
+ ncpu = getproccount()
+ getg().m.procid = getpid()
+ notify(unsafe.Pointer(funcPC(sigtramp)))
+}
+
+func crash() {
+ notify(nil)
+ *(*int)(nil) = 0
+}
+
+var random_data [_HashRandomBytes]byte
+var random_dev = []byte("/dev/random\x00")
+
+//go:nosplit
+func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
+ fd := open(&random_dev[0], 0 /* O_RDONLY */, 0)
+ if read(fd, unsafe.Pointer(&random_data), _HashRandomBytes) == _HashRandomBytes {
+ *rnd = unsafe.Pointer(&random_data[0])
+ *rnd_len = _HashRandomBytes
+ } else {
+ *rnd = nil
+ *rnd_len = 0
+ }
+ close(fd)
+}
+
+func goenvs() {
+}
+
+func initsig() {
+}
+
+//go:nosplit
+func osyield() {
+ sleep(0)
+}
+
+//go:nosplit
+func usleep(µs uint32) {
+ ms := int32(µs / 1000)
+ if ms == 0 {
+ ms = 1
+ }
+ sleep(ms)
+}
+
+//go:nosplit
+func nanotime() int64 {
+ var scratch int64
+ ns := nsec(&scratch)
+ // TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
+ if ns == 0 {
+ return scratch
+ }
+ return ns
+}
+
+//go:nosplit
+func itoa(buf []byte, val uint64) []byte {
+ i := len(buf) - 1
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ return buf[i:]
+}
+
+var goexits = []byte("go: exit ")
+
+func goexitsall(status *byte) {
+ var buf [_ERRMAX]byte
+ n := copy(buf[:], goexits)
+ n = copy(buf[n:], gostringnocopy(status))
+ pid := getpid()
+ for mp := (*m)(atomicloadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
+ if mp.procid != pid {
+ postnote(mp.procid, buf[:])
+ }
+ }
+}
+
+var procdir = []byte("/proc/")
+var notefile = []byte("/note\x00")
+
+func postnote(pid uint64, msg []byte) int {
+ var buf [128]byte
+ var tmp [32]byte
+ n := copy(buf[:], procdir)
+ n += copy(buf[n:], itoa(tmp[:], pid))
+ copy(buf[n:], notefile)
+ fd := open(&buf[0], _OWRITE, 0)
+ if fd < 0 {
+ return -1
+ }
+ len := findnull(&msg[0])
+ if write(uintptr(fd), (unsafe.Pointer)(&msg[0]), int32(len)) != int64(len) {
+ close(fd)
+ return -1
+ }
+ close(fd)
+ return 0
+}
+
+//go:nosplit
+func exit(e int) {
+ var status []byte
+ if e == 0 {
+ status = []byte("\x00")
+ } else {
+ // build error string
+ var tmp [32]byte
+ status = []byte(gostringnocopy(&itoa(tmp[:], uint64(e))[0]) + "\x00")
+ }
+ goexitsall(&status[0])
+ exits(&status[0])
+}
+
+func newosproc(mp *m, stk unsafe.Pointer) {
+ if false {
+ print("newosproc mp=", mp, " ostk=", &mp, "\n")
+ }
+ pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
+ if pid < 0 {
+ gothrow("newosproc: rfork failed")
+ }
+ if pid == 0 {
+ tstart_plan9(mp)
+ }
+}
+
+//go:nosplit
+func semacreate() uintptr {
+ return 1
+}
+
+//go:nosplit
+func semasleep(ns int64) int {
+ _g_ := getg()
+ if ns >= 0 {
+ ms := timediv(ns, 1000000, nil)
+ if ms == 0 {
+ ms = 1
+ }
+ ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
+ if ret == 1 {
+ return 0 // success
+ }
+ return -1 // timeout or interrupted
+ }
+ for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
+ // interrupted; try again (c.f. lock_sema.go)
+ }
+ return 0 // success
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ plan9_semrelease(&mp.waitsemacount, 1)
+}
+
+//go:nosplit
+func read(fd int32, buf unsafe.Pointer, n int32) int32 {
+ return pread(fd, buf, n, -1)
+}
+
+//go:nosplit
+func write(fd uintptr, buf unsafe.Pointer, n int32) int64 {
+ return int64(pwrite(int32(fd), buf, n, -1))
+}
+
+func memlimit() uint64 {
+ return 0
+}
+
+var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+func badsignal2() {
+ pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
+ exits(&_badsignal[0])
+}
+
+func atoi(b []byte) int {
+ n := 0
+ for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
+ n = n*10 + int(b[0]) - '0'
+ b = b[1:]
+ }
+ return n
+}
diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go
new file mode 100644
index 000000000..57ea050f2
--- /dev/null
+++ b/src/runtime/os1_windows.go
@@ -0,0 +1,564 @@
+// 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 runtime
+
+import (
+ "unsafe"
+)
+
+//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
+//go:cgo_import_dynamic runtime._CloseHandle CloseHandle "kernel32.dll"
+//go:cgo_import_dynamic runtime._CreateEventA CreateEventA "kernel32.dll"
+//go:cgo_import_dynamic runtime._CreateThread CreateThread "kernel32.dll"
+//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA "kernel32.dll"
+//go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
+//go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom "advapi32.dll"
+//go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext "advapi32.dll"
+//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle "kernel32.dll"
+//go:cgo_import_dynamic runtime._ExitProcess ExitProcess "kernel32.dll"
+//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext "kernel32.dll"
+//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW "kernel32.dll"
+//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA "kernel32.dll"
+//go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
+//go:cgo_import_dynamic runtime._ResumeThread ResumeThread "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetEvent SetEvent "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer "kernel32.dll"
+//go:cgo_import_dynamic runtime._Sleep Sleep "kernel32.dll"
+//go:cgo_import_dynamic runtime._SuspendThread SuspendThread "kernel32.dll"
+//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject "kernel32.dll"
+//go:cgo_import_dynamic runtime._WriteFile WriteFile "kernel32.dll"
+//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod "winmm.dll"
+
+var (
+ _AddVectoredExceptionHandler,
+ _CloseHandle,
+ _CreateEventA,
+ _CreateThread,
+ _CreateWaitableTimerA,
+ _CryptAcquireContextW,
+ _CryptGenRandom,
+ _CryptReleaseContext,
+ _DuplicateHandle,
+ _ExitProcess,
+ _FreeEnvironmentStringsW,
+ _GetEnvironmentStringsW,
+ _GetProcAddress,
+ _GetStdHandle,
+ _GetSystemInfo,
+ _GetThreadContext,
+ _LoadLibraryW,
+ _LoadLibraryA,
+ _NtWaitForSingleObject,
+ _ResumeThread,
+ _SetConsoleCtrlHandler,
+ _SetEvent,
+ _SetProcessPriorityBoost,
+ _SetThreadPriority,
+ _SetUnhandledExceptionFilter,
+ _SetWaitableTimer,
+ _Sleep,
+ _SuspendThread,
+ _WaitForSingleObject,
+ _WriteFile,
+ _timeBeginPeriod stdFunction
+)
+
+var _GetQueuedCompletionStatusEx stdFunction
+
+// in sys_windows_386.s and sys_windows_amd64.s
+func externalthreadhandler()
+func exceptiontramp()
+func firstcontinuetramp()
+func lastcontinuetramp()
+
+//go:nosplit
+func getLoadLibrary() uintptr {
+ return uintptr(unsafe.Pointer(_LoadLibraryW))
+}
+
+//go:nosplit
+func getGetProcAddress() uintptr {
+ return uintptr(unsafe.Pointer(_GetProcAddress))
+}
+
+func getproccount() int32 {
+ var info systeminfo
+ stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
+ return int32(info.dwnumberofprocessors)
+}
+
+const (
+ currentProcess = ^uintptr(0) // -1 = current process
+ currentThread = ^uintptr(1) // -2 = current thread
+)
+
+var (
+ kernel32Name = []byte("kernel32.dll\x00")
+ addVectoredContinueHandlerName = []byte("AddVectoredContinueHandler\x00")
+ getQueuedCompletionStatusExName = []byte("GetQueuedCompletionStatusEx\x00")
+)
+
+func osinit() {
+ setBadSignalMsg()
+
+ kernel32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32Name[0])))
+
+ externalthreadhandlerp = funcPC(externalthreadhandler)
+
+ stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
+ addVectoredContinueHandler := uintptr(0)
+ if kernel32 != 0 {
+ addVectoredContinueHandler = stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&addVectoredContinueHandlerName[0])))
+ }
+ if addVectoredContinueHandler == 0 || unsafe.Sizeof(&kernel32) == 4 {
+ // use SetUnhandledExceptionFilter for windows-386 or
+ // if VectoredContinueHandler is unavailable.
+ // note: SetUnhandledExceptionFilter handler won't be called, if debugging.
+ stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
+ } else {
+ stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 1, funcPC(firstcontinuetramp))
+ stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 0, funcPC(lastcontinuetramp))
+ }
+
+ stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
+
+ stdcall1(_timeBeginPeriod, 1)
+
+ ncpu = getproccount()
+
+ // Windows dynamic priority boosting assumes that a process has different types
+ // of dedicated threads -- GUI, IO, computational, etc. Go processes use
+ // equivalent threads that all do a mix of GUI, IO, computations, etc.
+ // In such context dynamic priority boosting does nothing but harm, so we turn it off.
+ stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
+
+ if kernel32 != 0 {
+ _GetQueuedCompletionStatusEx = stdFunction(unsafe.Pointer(stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&getQueuedCompletionStatusExName[0])))))
+ }
+}
+
+var random_data [_HashRandomBytes]byte
+
+//go:nosplit
+func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
+ const (
+ prov_rsa_full = 1
+ crypt_verifycontext = 0xF0000000
+ )
+ var handle uintptr
+ *rnd = nil
+ *rnd_len = 0
+ if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 {
+ if stdcall3(_CryptGenRandom, handle, _HashRandomBytes, uintptr(unsafe.Pointer(&random_data[0]))) != 0 {
+ *rnd = unsafe.Pointer(&random_data[0])
+ *rnd_len = _HashRandomBytes
+ }
+ stdcall2(_CryptReleaseContext, handle, 0)
+ }
+}
+
+func goenvs() {
+ var p *uint16
+
+ env := (*uint16)(unsafe.Pointer(stdcall0(_GetEnvironmentStringsW)))
+
+ n := 0
+ for p = env; *p != 0; n++ {
+ p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)*unsafe.Sizeof(*p)))
+ }
+
+ envs = makeStringSlice(int(n))
+
+ p = env
+ for i := 0; i < n; i++ {
+ envs[i] = gostringw(p)
+ p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)*unsafe.Sizeof(*p)))
+ }
+
+ stdcall1(_FreeEnvironmentStringsW, uintptr(unsafe.Pointer(env)))
+}
+
+//go:nosplit
+func exit(code int32) {
+ stdcall1(_ExitProcess, uintptr(code))
+}
+
+//go:nosplit
+func write(fd uintptr, buf unsafe.Pointer, n int32) int32 {
+ const (
+ _STD_OUTPUT_HANDLE = ^uintptr(10) // -11
+ _STD_ERROR_HANDLE = ^uintptr(11) // -12
+ )
+ var handle uintptr
+ switch fd {
+ case 1:
+ handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
+ case 2:
+ handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
+ default:
+ // assume fd is real windows handle.
+ handle = fd
+ }
+ var written uint32
+ stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
+ return int32(written)
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+ // store ms in ns to save stack space
+ if ns < 0 {
+ ns = _INFINITE
+ } else {
+ ns = int64(timediv(ns, 1000000, nil))
+ if ns == 0 {
+ ns = 1
+ }
+ }
+ if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 {
+ return -1 // timeout
+ }
+ return 0
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ stdcall1(_SetEvent, mp.waitsema)
+}
+
+//go:nosplit
+func semacreate() uintptr {
+ return stdcall4(_CreateEventA, 0, 0, 0, 0)
+}
+
+func newosproc(mp *m, stk unsafe.Pointer) {
+ const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
+ thandle := stdcall6(_CreateThread, 0, 0x20000,
+ funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
+ _STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
+ if thandle == 0 {
+ println("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")")
+ gothrow("runtime.newosproc")
+ }
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ var thandle uintptr
+ stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
+ atomicstoreuintptr(&getg().m.thread, thandle)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+ tp := &getg().m.thread
+ stdcall1(_CloseHandle, *tp)
+ *tp = 0
+}
+
+// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
+type _KSYSTEM_TIME struct {
+ LowPart uint32
+ High1Time int32
+ High2Time int32
+}
+
+const (
+ _INTERRUPT_TIME = 0x7ffe0008
+ _SYSTEM_TIME = 0x7ffe0014
+)
+
+//go:nosplit
+func systime(addr uintptr) int64 {
+ timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr))
+
+ var t _KSYSTEM_TIME
+ for i := 1; i < 10000; i++ {
+ // these fields must be read in that order (see URL above)
+ t.High1Time = timeaddr.High1Time
+ t.LowPart = timeaddr.LowPart
+ t.High2Time = timeaddr.High2Time
+ if t.High1Time == t.High2Time {
+ return int64(t.High1Time)<<32 | int64(t.LowPart)
+ }
+ if (i % 100) == 0 {
+ osyield()
+ }
+ }
+ systemstack(func() {
+ gothrow("interrupt/system time is changing too fast")
+ })
+ return 0
+}
+
+//go:nosplit
+func unixnano() int64 {
+ return (systime(_SYSTEM_TIME) - 116444736000000000) * 100
+}
+
+//go:nosplit
+func nanotime() int64 {
+ return systime(_INTERRUPT_TIME) * 100
+}
+
+// Calling stdcall on os stack.
+//go:nosplit
+func stdcall(fn stdFunction) uintptr {
+ gp := getg()
+ mp := gp.m
+ mp.libcall.fn = uintptr(unsafe.Pointer(fn))
+
+ if mp.profilehz != 0 {
+ // leave pc/sp for cpu profiler
+ mp.libcallg = gp
+ mp.libcallpc = getcallerpc(unsafe.Pointer(&fn))
+ // sp must be the last, because once async cpu profiler finds
+ // all three values to be non-zero, it will use them
+ mp.libcallsp = getcallersp(unsafe.Pointer(&fn))
+ }
+ asmcgocall(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&mp.libcall))
+ mp.libcallsp = 0
+ return mp.libcall.r1
+}
+
+//go:nosplit
+func stdcall0(fn stdFunction) uintptr {
+ mp := getg().m
+ mp.libcall.n = 0
+ mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
+ return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall1(fn stdFunction, a0 uintptr) uintptr {
+ mp := getg().m
+ mp.libcall.n = 1
+ mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+ return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
+ mp := getg().m
+ mp.libcall.n = 2
+ mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+ return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
+ mp := getg().m
+ mp.libcall.n = 3
+ mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+ return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
+ mp := getg().m
+ mp.libcall.n = 4
+ mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+ return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
+ mp := getg().m
+ mp.libcall.n = 5
+ mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+ return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
+ mp := getg().m
+ mp.libcall.n = 6
+ mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+ return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
+ mp := getg().m
+ mp.libcall.n = 7
+ mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+ return stdcall(fn)
+}
+
+// in sys_windows_386.s and sys_windows_amd64.s
+func usleep1(usec uint32)
+
+//go:nosplit
+func osyield() {
+ usleep1(1)
+}
+
+//go:nosplit
+func usleep(us uint32) {
+ // Have 1us units; want 100ns units.
+ usleep1(10 * us)
+}
+
+func issigpanic(code uint32) uint32 {
+ switch code {
+ default:
+ return 0
+ case _EXCEPTION_ACCESS_VIOLATION:
+ case _EXCEPTION_INT_DIVIDE_BY_ZERO:
+ case _EXCEPTION_INT_OVERFLOW:
+ case _EXCEPTION_FLT_DENORMAL_OPERAND:
+ case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case _EXCEPTION_FLT_INEXACT_RESULT:
+ case _EXCEPTION_FLT_OVERFLOW:
+ case _EXCEPTION_FLT_UNDERFLOW:
+ case _EXCEPTION_BREAKPOINT:
+ }
+ return 1
+}
+
+func initsig() {
+ /*
+ // TODO(brainman): I don't think we need that bit of code
+ // following line keeps these functions alive at link stage
+ // if there's a better way please write it here
+ void *e = runtime·exceptiontramp;
+ void *f = runtime·firstcontinuetramp;
+ void *l = runtime·lastcontinuetramp;
+ USED(e);
+ USED(f);
+ USED(l);
+ */
+}
+
+func ctrlhandler1(_type uint32) uint32 {
+ var s uint32
+
+ switch _type {
+ case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
+ s = _SIGINT
+ default:
+ return 0
+ }
+
+ if sigsend(s) {
+ return 1
+ }
+ exit(2) // SIGINT, SIGTERM, etc
+ return 0
+}
+
+// in sys_windows_386.s and sys_windows_amd64.s
+func profileloop()
+
+var profiletimer uintptr
+
+func profilem(mp *m) {
+ var r *context
+ rbuf := make([]byte, unsafe.Sizeof(*r)+15)
+
+ tls := &mp.tls[0]
+ if mp == &m0 {
+ tls = &tls0[0]
+ }
+ gp := *((**g)(unsafe.Pointer(tls)))
+
+ // align Context to 16 bytes
+ r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15))
+ r.contextflags = _CONTEXT_CONTROL
+ stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r)))
+ dosigprof(r, gp, mp)
+}
+
+func profileloop1() {
+ stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
+
+ for {
+ stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
+ first := (*m)(atomicloadp(unsafe.Pointer(&allm)))
+ for mp := first; mp != nil; mp = mp.alllink {
+ thread := atomicloaduintptr(&mp.thread)
+ // Do not profile threads blocked on Notes,
+ // this includes idle worker threads,
+ // idle timer thread, idle heap scavenger, etc.
+ if thread == 0 || mp.profilehz == 0 || mp.blocked {
+ continue
+ }
+ stdcall1(_SuspendThread, thread)
+ if mp.profilehz != 0 && !mp.blocked {
+ profilem(mp)
+ }
+ stdcall1(_ResumeThread, thread)
+ }
+ }
+}
+
+var cpuprofilerlock mutex
+
+func resetcpuprofiler(hz int32) {
+ lock(&cpuprofilerlock)
+ if profiletimer == 0 {
+ timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
+ atomicstoreuintptr(&profiletimer, timer)
+ thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0)
+ stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST)
+ stdcall1(_CloseHandle, thread)
+ }
+ unlock(&cpuprofilerlock)
+
+ ms := int32(0)
+ due := ^int64(^uint64(1 << 63))
+ if hz > 0 {
+ ms = 1000 / hz
+ if ms == 0 {
+ ms = 1
+ }
+ due = int64(ms) * -10000
+ }
+ stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
+ atomicstore((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
+}
+
+func memlimit() uintptr {
+ return 0
+}
+
+var (
+ badsignalmsg [100]byte
+ badsignallen int32
+)
+
+func setBadSignalMsg() {
+ const msg = "runtime: signal received on thread not created by Go.\n"
+ for i, c := range msg {
+ badsignalmsg[i] = byte(c)
+ badsignallen++
+ }
+}
+
+func crash() {
+ // TODO: This routine should do whatever is needed
+ // to make the Windows program abort/crash as it
+ // would if Go was not intercepting signals.
+ // On Unix the routine would remove the custom signal
+ // handler and then raise a signal (like SIGABRT).
+ // Something like that should happen here.
+ // It's okay to leave this empty for now: if crash returns
+ // the ordinary exit-after-panic happens.
+}
diff --git a/src/runtime/os1_windows_386.go b/src/runtime/os1_windows_386.go
new file mode 100644
index 000000000..0afef9156
--- /dev/null
+++ b/src/runtime/os1_windows_386.go
@@ -0,0 +1,118 @@
+// 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 runtime
+
+import (
+ "unsafe"
+)
+
+var text struct{}
+
+func dumpregs(r *context) {
+ print("eax ", hex(r.eax), "\n")
+ print("ebx ", hex(r.ebx), "\n")
+ print("ecx ", hex(r.ecx), "\n")
+ print("edx ", hex(r.edx), "\n")
+ print("edi ", hex(r.edi), "\n")
+ print("esi ", hex(r.esi), "\n")
+ print("ebp ", hex(r.ebp), "\n")
+ print("esp ", hex(r.esp), "\n")
+ print("eip ", hex(r.eip), "\n")
+ print("eflags ", hex(r.eflags), "\n")
+ print("cs ", hex(r.segcs), "\n")
+ print("fs ", hex(r.segfs), "\n")
+ print("gs ", hex(r.seggs), "\n")
+}
+
+func isgoexception(info *exceptionrecord, r *context) bool {
+ // Only handle exception if executing instructions in Go binary
+ // (not Windows library code).
+ if r.eip < uint32(uintptr(unsafe.Pointer(&text))) || uint32(uintptr(unsafe.Pointer(&etext))) < r.eip {
+ return false
+ }
+
+ if issigpanic(info.exceptioncode) == 0 {
+ return false
+ }
+
+ return true
+}
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
+// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
+func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
+ if !isgoexception(info, r) {
+ return _EXCEPTION_CONTINUE_SEARCH
+ }
+
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp.sig = info.exceptioncode
+ gp.sigcode0 = uintptr(info.exceptioninformation[0])
+ gp.sigcode1 = uintptr(info.exceptioninformation[1])
+ gp.sigpc = uintptr(r.eip)
+
+ // Only push runtime·sigpanic if r->eip != 0.
+ // If r->eip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if r.eip != 0 {
+ sp := unsafe.Pointer(uintptr(r.esp))
+ sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp--
+ *((*uintptr)(sp)) = uintptr(r.eip)
+ r.esp = uint32(uintptr(sp))
+ }
+ r.eip = uint32(funcPC(sigpanic))
+ return _EXCEPTION_CONTINUE_EXECUTION
+}
+
+// lastcontinuehandler is reached, because runtime cannot handle
+// current exception. lastcontinuehandler will print crash info and exit.
+func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 {
+ _g_ := getg()
+
+ if panicking != 0 { // traceback already printed
+ exit(2)
+ }
+ panicking = 1
+
+ print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.eip), "\n")
+
+ print("PC=", hex(r.eip), "\n")
+ if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+ print("signal arrived during cgo execution\n")
+ gp = _g_.m.lockedg
+ }
+ print("\n")
+
+ var docrash bool
+ if gotraceback(&docrash) > 0 {
+ tracebacktrap(uintptr(r.eip), uintptr(r.esp), 0, gp)
+ tracebackothers(gp)
+ dumpregs(r)
+ }
+
+ if docrash {
+ crash()
+ }
+
+ exit(2)
+ return 0 // not reached
+}
+
+func sigenable(sig uint32) {
+}
+
+func sigdisable(sig uint32) {
+}
+
+func dosigprof(r *context, gp *g, mp *m) {
+ sigprof((*byte)(unsafe.Pointer(uintptr(r.eip))), (*byte)(unsafe.Pointer(uintptr(r.esp))), nil, gp, mp)
+}
diff --git a/src/runtime/os1_windows_amd64.go b/src/runtime/os1_windows_amd64.go
new file mode 100644
index 000000000..0d21b3881
--- /dev/null
+++ b/src/runtime/os1_windows_amd64.go
@@ -0,0 +1,137 @@
+// Copyright 2011 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 runtime
+
+import (
+ "unsafe"
+)
+
+var text struct{}
+
+func dumpregs(r *context) {
+ print("rax ", hex(r.rax), "\n")
+ print("rbx ", hex(r.rbx), "\n")
+ print("rcx ", hex(r.rcx), "\n")
+ print("rdi ", hex(r.rdi), "\n")
+ print("rsi ", hex(r.rsi), "\n")
+ print("rbp ", hex(r.rbp), "\n")
+ print("rsp ", hex(r.rsp), "\n")
+ print("r8 ", hex(r.r8), "\n")
+ print("r9 ", hex(r.r9), "\n")
+ print("r10 ", hex(r.r10), "\n")
+ print("r11 ", hex(r.r11), "\n")
+ print("r12 ", hex(r.r12), "\n")
+ print("r13 ", hex(r.r13), "\n")
+ print("r14 ", hex(r.r14), "\n")
+ print("r15 ", hex(r.r15), "\n")
+ print("rip ", hex(r.rip), "\n")
+ print("rflags ", hex(r.eflags), "\n")
+ print("cs ", hex(r.segcs), "\n")
+ print("fs ", hex(r.segfs), "\n")
+ print("gs ", hex(r.seggs), "\n")
+}
+
+func isgoexception(info *exceptionrecord, r *context) bool {
+ // Only handle exception if executing instructions in Go binary
+ // (not Windows library code).
+ if r.rip < uint64(uintptr(unsafe.Pointer(&text))) || uint64(uintptr(unsafe.Pointer(&etext))) < r.rip {
+ return false
+ }
+
+ if issigpanic(info.exceptioncode) == 0 {
+ return false
+ }
+
+ return true
+}
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
+// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
+
+func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
+ if !isgoexception(info, r) {
+ return _EXCEPTION_CONTINUE_SEARCH
+ }
+
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp.sig = info.exceptioncode
+ gp.sigcode0 = uintptr(info.exceptioninformation[0])
+ gp.sigcode1 = uintptr(info.exceptioninformation[1])
+ gp.sigpc = uintptr(r.rip)
+
+ // Only push runtime·sigpanic if r->rip != 0.
+ // If r->rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if r.rip != 0 {
+ sp := unsafe.Pointer(uintptr(r.rsp))
+ sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp--
+ *((*uintptr)(sp)) = uintptr(r.rip)
+ r.rsp = uint64(uintptr(sp))
+ }
+ r.rip = uint64(funcPC(sigpanic))
+ return _EXCEPTION_CONTINUE_EXECUTION
+}
+
+// It seems Windows searches ContinueHandler's list even
+// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
+// firstcontinuehandler will stop that search,
+// if exceptionhandler did the same earlier.
+func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
+ if !isgoexception(info, r) {
+ return _EXCEPTION_CONTINUE_SEARCH
+ }
+ return _EXCEPTION_CONTINUE_EXECUTION
+}
+
+// lastcontinuehandler is reached, because runtime cannot handle
+// current exception. lastcontinuehandler will print crash info and exit.
+func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 {
+ _g_ := getg()
+
+ if panicking != 0 { // traceback already printed
+ exit(2)
+ }
+ panicking = 1
+
+ print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.rip), "\n")
+
+ print("PC=", hex(r.rip), "\n")
+ if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+ print("signal arrived during cgo execution\n")
+ gp = _g_.m.lockedg
+ }
+ print("\n")
+
+ var docrash bool
+ if gotraceback(&docrash) > 0 {
+ tracebacktrap(uintptr(r.rip), uintptr(r.rsp), 0, gp)
+ tracebackothers(gp)
+ dumpregs(r)
+ }
+
+ if docrash {
+ crash()
+ }
+
+ exit(2)
+ return 0 // not reached
+}
+
+func sigenable(sig uint32) {
+}
+
+func sigdisable(sig uint32) {
+}
+
+func dosigprof(r *context, gp *g, mp *m) {
+ sigprof((*byte)(unsafe.Pointer(uintptr(r.rip))), (*byte)(unsafe.Pointer(uintptr(r.rsp))), nil, gp, mp)
+}
diff --git a/src/runtime/os2_darwin.go b/src/runtime/os2_darwin.go
new file mode 100644
index 000000000..542bd7421
--- /dev/null
+++ b/src/runtime/os2_darwin.go
@@ -0,0 +1,14 @@
+// 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 runtime
+
+const (
+ _NSIG = 32
+ _SI_USER = 0 /* empirically true, but not what headers say */
+ _SIG_BLOCK = 1
+ _SIG_UNBLOCK = 2
+ _SIG_SETMASK = 3
+ _SS_DISABLE = 4
+)
diff --git a/src/runtime/os2_dragonfly.go b/src/runtime/os2_dragonfly.go
new file mode 100644
index 000000000..0a20ed43f
--- /dev/null
+++ b/src/runtime/os2_dragonfly.go
@@ -0,0 +1,12 @@
+// Copyright 2011 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 runtime
+
+const (
+ _NSIG = 33
+ _SI_USER = 0x10001
+ _SS_DISABLE = 4
+ _RLIMIT_AS = 10
+)
diff --git a/src/runtime/os2_freebsd.go b/src/runtime/os2_freebsd.go
new file mode 100644
index 000000000..f67211fdf
--- /dev/null
+++ b/src/runtime/os2_freebsd.go
@@ -0,0 +1,12 @@
+// Copyright 2011 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 runtime
+
+const (
+ _SS_DISABLE = 4
+ _NSIG = 33
+ _SI_USER = 0x10001
+ _RLIMIT_AS = 10
+)
diff --git a/src/runtime/os2_linux.go b/src/runtime/os2_linux.go
new file mode 100644
index 000000000..eaa9f0e83
--- /dev/null
+++ b/src/runtime/os2_linux.go
@@ -0,0 +1,23 @@
+// 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 runtime
+
+const (
+ _SS_DISABLE = 2
+ _NSIG = 65
+ _SI_USER = 0
+ _SIG_SETMASK = 2
+ _RLIMIT_AS = 9
+)
+
+// It's hard to tease out exactly how big a Sigset is, but
+// rt_sigprocmask crashes if we get it wrong, so if binaries
+// are running, this is right.
+type sigset [2]uint32
+
+type rlimit struct {
+ rlim_cur uintptr
+ rlim_max uintptr
+}
diff --git a/src/runtime/os2_nacl.go b/src/runtime/os2_nacl.go
new file mode 100644
index 000000000..0c91e0f73
--- /dev/null
+++ b/src/runtime/os2_nacl.go
@@ -0,0 +1,154 @@
+// 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 runtime
+
+const (
+ _NSIG = 32
+ _SI_USER = 1
+
+ // native_client/src/trusted/service_runtime/include/sys/errno.h
+ // The errors are mainly copied from Linux.
+ _EPERM = 1 /* Operation not permitted */
+ _ENOENT = 2 /* No such file or directory */
+ _ESRCH = 3 /* No such process */
+ _EINTR = 4 /* Interrupted system call */
+ _EIO = 5 /* I/O error */
+ _ENXIO = 6 /* No such device or address */
+ _E2BIG = 7 /* Argument list too long */
+ _ENOEXEC = 8 /* Exec format error */
+ _EBADF = 9 /* Bad file number */
+ _ECHILD = 10 /* No child processes */
+ _EAGAIN = 11 /* Try again */
+ _ENOMEM = 12 /* Out of memory */
+ _EACCES = 13 /* Permission denied */
+ _EFAULT = 14 /* Bad address */
+ _EBUSY = 16 /* Device or resource busy */
+ _EEXIST = 17 /* File exists */
+ _EXDEV = 18 /* Cross-device link */
+ _ENODEV = 19 /* No such device */
+ _ENOTDIR = 20 /* Not a directory */
+ _EISDIR = 21 /* Is a directory */
+ _EINVAL = 22 /* Invalid argument */
+ _ENFILE = 23 /* File table overflow */
+ _EMFILE = 24 /* Too many open files */
+ _ENOTTY = 25 /* Not a typewriter */
+ _EFBIG = 27 /* File too large */
+ _ENOSPC = 28 /* No space left on device */
+ _ESPIPE = 29 /* Illegal seek */
+ _EROFS = 30 /* Read-only file system */
+ _EMLINK = 31 /* Too many links */
+ _EPIPE = 32 /* Broken pipe */
+ _ENAMETOOLONG = 36 /* File name too long */
+ _ENOSYS = 38 /* Function not implemented */
+ _EDQUOT = 122 /* Quota exceeded */
+ _EDOM = 33 /* Math arg out of domain of func */
+ _ERANGE = 34 /* Math result not representable */
+ _EDEADLK = 35 /* Deadlock condition */
+ _ENOLCK = 37 /* No record locks available */
+ _ENOTEMPTY = 39 /* Directory not empty */
+ _ELOOP = 40 /* Too many symbolic links */
+ _ENOMSG = 42 /* No message of desired type */
+ _EIDRM = 43 /* Identifier removed */
+ _ECHRNG = 44 /* Channel number out of range */
+ _EL2NSYNC = 45 /* Level 2 not synchronized */
+ _EL3HLT = 46 /* Level 3 halted */
+ _EL3RST = 47 /* Level 3 reset */
+ _ELNRNG = 48 /* Link number out of range */
+ _EUNATCH = 49 /* Protocol driver not attached */
+ _ENOCSI = 50 /* No CSI structure available */
+ _EL2HLT = 51 /* Level 2 halted */
+ _EBADE = 52 /* Invalid exchange */
+ _EBADR = 53 /* Invalid request descriptor */
+ _EXFULL = 54 /* Exchange full */
+ _ENOANO = 55 /* No anode */
+ _EBADRQC = 56 /* Invalid request code */
+ _EBADSLT = 57 /* Invalid slot */
+ _EDEADLOCK = _EDEADLK /* File locking deadlock error */
+ _EBFONT = 59 /* Bad font file fmt */
+ _ENOSTR = 60 /* Device not a stream */
+ _ENODATA = 61 /* No data (for no delay io) */
+ _ETIME = 62 /* Timer expired */
+ _ENOSR = 63 /* Out of streams resources */
+ _ENONET = 64 /* Machine is not on the network */
+ _ENOPKG = 65 /* Package not installed */
+ _EREMOTE = 66 /* The object is remote */
+ _ENOLINK = 67 /* The link has been severed */
+ _EADV = 68 /* Advertise error */
+ _ESRMNT = 69 /* Srmount error */
+ _ECOMM = 70 /* Communication error on send */
+ _EPROTO = 71 /* Protocol error */
+ _EMULTIHOP = 72 /* Multihop attempted */
+ _EDOTDOT = 73 /* Cross mount point (not really error) */
+ _EBADMSG = 74 /* Trying to read unreadable message */
+ _EOVERFLOW = 75 /* Value too large for defined data type */
+ _ENOTUNIQ = 76 /* Given log. name not unique */
+ _EBADFD = 77 /* f.d. invalid for this operation */
+ _EREMCHG = 78 /* Remote address changed */
+ _ELIBACC = 79 /* Can't access a needed shared lib */
+ _ELIBBAD = 80 /* Accessing a corrupted shared lib */
+ _ELIBSCN = 81 /* .lib section in a.out corrupted */
+ _ELIBMAX = 82 /* Attempting to link in too many libs */
+ _ELIBEXEC = 83 /* Attempting to exec a shared library */
+ _EILSEQ = 84
+ _EUSERS = 87
+ _ENOTSOCK = 88 /* Socket operation on non-socket */
+ _EDESTADDRREQ = 89 /* Destination address required */
+ _EMSGSIZE = 90 /* Message too long */
+ _EPROTOTYPE = 91 /* Protocol wrong type for socket */
+ _ENOPROTOOPT = 92 /* Protocol not available */
+ _EPROTONOSUPPORT = 93 /* Unknown protocol */
+ _ESOCKTNOSUPPORT = 94 /* Socket type not supported */
+ _EOPNOTSUPP = 95 /* Operation not supported on transport endpoint */
+ _EPFNOSUPPORT = 96 /* Protocol family not supported */
+ _EAFNOSUPPORT = 97 /* Address family not supported by protocol family */
+ _EADDRINUSE = 98 /* Address already in use */
+ _EADDRNOTAVAIL = 99 /* Address not available */
+ _ENETDOWN = 100 /* Network interface is not configured */
+ _ENETUNREACH = 101 /* Network is unreachable */
+ _ENETRESET = 102
+ _ECONNABORTED = 103 /* Connection aborted */
+ _ECONNRESET = 104 /* Connection reset by peer */
+ _ENOBUFS = 105 /* No buffer space available */
+ _EISCONN = 106 /* Socket is already connected */
+ _ENOTCONN = 107 /* Socket is not connected */
+ _ESHUTDOWN = 108 /* Can't send after socket shutdown */
+ _ETOOMANYREFS = 109
+ _ETIMEDOUT = 110 /* Connection timed out */
+ _ECONNREFUSED = 111 /* Connection refused */
+ _EHOSTDOWN = 112 /* Host is down */
+ _EHOSTUNREACH = 113 /* Host is unreachable */
+ _EALREADY = 114 /* Socket already connected */
+ _EINPROGRESS = 115 /* Connection already in progress */
+ _ESTALE = 116
+ _ENOTSUP = _EOPNOTSUPP /* Not supported */
+ _ENOMEDIUM = 123 /* No medium (in tape drive) */
+ _ECANCELED = 125 /* Operation canceled. */
+ _ELBIN = 2048 /* Inode is remote (not really error) */
+ _EFTYPE = 2049 /* Inappropriate file type or format */
+ _ENMFILE = 2050 /* No more files */
+ _EPROCLIM = 2051
+ _ENOSHARE = 2052 /* No such host or network path */
+ _ECASECLASH = 2053 /* Filename exists with different case */
+ _EWOULDBLOCK = _EAGAIN /* Operation would block */
+
+ // native_client/src/trusted/service_runtime/include/bits/mman.h.
+ // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h.
+ // Those MAP_*values are different from these.
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_SHARED = 0x1
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+ _MAP_ANON = 0x20
+
+ _MADV_FREE = 0
+ _SIGFPE = 8
+ _FPE_INTDIV = 0
+)
+
+type siginfo struct{}
diff --git a/src/runtime/os2_netbsd.go b/src/runtime/os2_netbsd.go
new file mode 100644
index 000000000..46576b9bc
--- /dev/null
+++ b/src/runtime/os2_netbsd.go
@@ -0,0 +1,18 @@
+// Copyright 2010 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 runtime
+
+const (
+ _SS_DISABLE = 4
+ _SIG_BLOCK = 1
+ _SIG_UNBLOCK = 2
+ _SIG_SETMASK = 3
+ _NSIG = 33
+ _SI_USER = 0
+
+ // From NetBSD's <sys/ucontext.h>
+ _UC_SIGMASK = 0x01
+ _UC_CPU = 0x04
+)
diff --git a/src/runtime/os2_openbsd.go b/src/runtime/os2_openbsd.go
new file mode 100644
index 000000000..1e785ad51
--- /dev/null
+++ b/src/runtime/os2_openbsd.go
@@ -0,0 +1,14 @@
+// Copyright 2010 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 runtime
+
+const (
+ _SS_DISABLE = 4
+ _SIG_BLOCK = 1
+ _SIG_UNBLOCK = 2
+ _SIG_SETMASK = 3
+ _NSIG = 33
+ _SI_USER = 0
+)
diff --git a/src/runtime/os2_plan9.go b/src/runtime/os2_plan9.go
new file mode 100644
index 000000000..f64f4c8da
--- /dev/null
+++ b/src/runtime/os2_plan9.go
@@ -0,0 +1,72 @@
+// Copyright 2010 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.
+
+// Plan 9-specific system calls
+
+package runtime
+
+// open
+const (
+ _OREAD = 0
+ _OWRITE = 1
+ _ORDWR = 2
+ _OEXEC = 3
+ _OTRUNC = 16
+ _OCEXEC = 32
+ _ORCLOSE = 64
+ _OEXCL = 0x1000
+)
+
+// rfork
+const (
+ _RFNAMEG = 1 << 0
+ _RFENVG = 1 << 1
+ _RFFDG = 1 << 2
+ _RFNOTEG = 1 << 3
+ _RFPROC = 1 << 4
+ _RFMEM = 1 << 5
+ _RFNOWAIT = 1 << 6
+ _RFCNAMEG = 1 << 10
+ _RFCENVG = 1 << 11
+ _RFCFDG = 1 << 12
+ _RFREND = 1 << 13
+ _RFNOMNT = 1 << 14
+)
+
+// notify
+const (
+ _NCONT = 0
+ _NDFLT = 1
+)
+
+type uinptr _Plink
+
+type tos struct {
+ prof struct { // Per process profiling
+ pp *_Plink // known to be 0(ptr)
+ next *_Plink // known to be 4(ptr)
+ last *_Plink
+ first *_Plink
+ pid uint32
+ what uint32
+ }
+ cyclefreq uint64 // cycle clock frequency if there is one, 0 otherwise
+ kcycles int64 // cycles spent in kernel
+ pcycles int64 // cycles spent in process (kernel + user)
+ pid uint32 // might as well put the pid here
+ clock uint32
+ // top of stack is here
+}
+
+const (
+ _NSIG = 14 // number of signals in sigtable array
+ _ERRMAX = 128 // max length of note string
+
+ // Notes in runtime·sigtab that are handled by runtime·sigpanic.
+ _SIGRFAULT = 2
+ _SIGWFAULT = 3
+ _SIGINTDIV = 4
+ _SIGFLOAT = 5
+ _SIGTRAP = 6
+)
diff --git a/src/runtime/os2_solaris.go b/src/runtime/os2_solaris.go
new file mode 100644
index 000000000..26ca15f62
--- /dev/null
+++ b/src/runtime/os2_solaris.go
@@ -0,0 +1,13 @@
+// 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 runtime
+
+const (
+ _SS_DISABLE = 2
+ _SIG_SETMASK = 3
+ _NSIG = 73 /* number of signals in sigtable array */
+ _SI_USER = 0
+ _RLIMIT_AS = 10
+)
diff --git a/src/runtime/os2_windows.go b/src/runtime/os2_windows.go
new file mode 100644
index 000000000..d5b1f471f
--- /dev/null
+++ b/src/runtime/os2_windows.go
@@ -0,0 +1,25 @@
+// 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 runtime
+
+import "unsafe"
+
+// Call a Windows function with stdcall conventions,
+// and switch to os stack during the call.
+func asmstdcall(fn unsafe.Pointer)
+
+func getlasterror() uint32
+func setlasterror(err uint32)
+
+// Function to be called by windows CreateThread
+// to start new os thread.
+func tstart_stdcall(newm *m) uint32
+
+func ctrlhandler(_type uint32) uint32
+
+// TODO(brainman): should not need those
+const (
+ _NSIG = 65
+)
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
new file mode 100644
index 000000000..1df74faad
--- /dev/null
+++ b/src/runtime/os3_solaris.go
@@ -0,0 +1,493 @@
+// Copyright 2011 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 runtime
+
+import "unsafe"
+
+//go:cgo_export_dynamic runtime.end _end
+//go:cgo_export_dynamic runtime.etext _etext
+//go:cgo_export_dynamic runtime.edata _edata
+
+//go:cgo_import_dynamic libc____errno ___errno "libc.so"
+//go:cgo_import_dynamic libc_clock_gettime clock_gettime "libc.so"
+//go:cgo_import_dynamic libc_close close "libc.so"
+//go:cgo_import_dynamic libc_exit exit "libc.so"
+//go:cgo_import_dynamic libc_fstat fstat "libc.so"
+//go:cgo_import_dynamic libc_getcontext getcontext "libc.so"
+//go:cgo_import_dynamic libc_getrlimit getrlimit "libc.so"
+//go:cgo_import_dynamic libc_madvise madvise "libc.so"
+//go:cgo_import_dynamic libc_malloc malloc "libc.so"
+//go:cgo_import_dynamic libc_mmap mmap "libc.so"
+//go:cgo_import_dynamic libc_munmap munmap "libc.so"
+//go:cgo_import_dynamic libc_open open "libc.so"
+//go:cgo_import_dynamic libc_pthread_attr_destroy pthread_attr_destroy "libc.so"
+//go:cgo_import_dynamic libc_pthread_attr_getstack pthread_attr_getstack "libc.so"
+//go:cgo_import_dynamic libc_pthread_attr_init pthread_attr_init "libc.so"
+//go:cgo_import_dynamic libc_pthread_attr_setdetachstate pthread_attr_setdetachstate "libc.so"
+//go:cgo_import_dynamic libc_pthread_attr_setstack pthread_attr_setstack "libc.so"
+//go:cgo_import_dynamic libc_pthread_create pthread_create "libc.so"
+//go:cgo_import_dynamic libc_raise raise "libc.so"
+//go:cgo_import_dynamic libc_read read "libc.so"
+//go:cgo_import_dynamic libc_select select "libc.so"
+//go:cgo_import_dynamic libc_sched_yield sched_yield "libc.so"
+//go:cgo_import_dynamic libc_sem_init sem_init "libc.so"
+//go:cgo_import_dynamic libc_sem_post sem_post "libc.so"
+//go:cgo_import_dynamic libc_sem_reltimedwait_np sem_reltimedwait_np "libc.so"
+//go:cgo_import_dynamic libc_sem_wait sem_wait "libc.so"
+//go:cgo_import_dynamic libc_setitimer setitimer "libc.so"
+//go:cgo_import_dynamic libc_sigaction sigaction "libc.so"
+//go:cgo_import_dynamic libc_sigaltstack sigaltstack "libc.so"
+//go:cgo_import_dynamic libc_sigprocmask sigprocmask "libc.so"
+//go:cgo_import_dynamic libc_sysconf sysconf "libc.so"
+//go:cgo_import_dynamic libc_usleep usleep "libc.so"
+//go:cgo_import_dynamic libc_write write "libc.so"
+
+//go:linkname libc____errno libc____errno
+//go:linkname libc_clock_gettime libc_clock_gettime
+//go:linkname libc_close libc_close
+//go:linkname libc_exit libc_exit
+//go:linkname libc_fstat libc_fstat
+//go:linkname libc_getcontext libc_getcontext
+//go:linkname libc_getrlimit libc_getrlimit
+//go:linkname libc_madvise libc_madvise
+//go:linkname libc_malloc libc_malloc
+//go:linkname libc_mmap libc_mmap
+//go:linkname libc_munmap libc_munmap
+//go:linkname libc_open libc_open
+//go:linkname libc_pthread_attr_destroy libc_pthread_attr_destroy
+//go:linkname libc_pthread_attr_getstack libc_pthread_attr_getstack
+//go:linkname libc_pthread_attr_init libc_pthread_attr_init
+//go:linkname libc_pthread_attr_setdetachstate libc_pthread_attr_setdetachstate
+//go:linkname libc_pthread_attr_setstack libc_pthread_attr_setstack
+//go:linkname libc_pthread_create libc_pthread_create
+//go:linkname libc_raise libc_raise
+//go:linkname libc_read libc_read
+//go:linkname libc_select libc_select
+//go:linkname libc_sched_yield libc_sched_yield
+//go:linkname libc_sem_init libc_sem_init
+//go:linkname libc_sem_post libc_sem_post
+//go:linkname libc_sem_reltimedwait_np libc_sem_reltimedwait_np
+//go:linkname libc_sem_wait libc_sem_wait
+//go:linkname libc_setitimer libc_setitimer
+//go:linkname libc_sigaction libc_sigaction
+//go:linkname libc_sigaltstack libc_sigaltstack
+//go:linkname libc_sigprocmask libc_sigprocmask
+//go:linkname libc_sysconf libc_sysconf
+//go:linkname libc_usleep libc_usleep
+//go:linkname libc_write libc_write
+
+var (
+ libc____errno,
+ libc_clock_gettime,
+ libc_close,
+ libc_exit,
+ libc_fstat,
+ libc_getcontext,
+ libc_getrlimit,
+ libc_madvise,
+ libc_malloc,
+ libc_mmap,
+ libc_munmap,
+ libc_open,
+ libc_pthread_attr_destroy,
+ libc_pthread_attr_getstack,
+ libc_pthread_attr_init,
+ libc_pthread_attr_setdetachstate,
+ libc_pthread_attr_setstack,
+ libc_pthread_create,
+ libc_raise,
+ libc_read,
+ libc_sched_yield,
+ libc_select,
+ libc_sem_init,
+ libc_sem_post,
+ libc_sem_reltimedwait_np,
+ libc_sem_wait,
+ libc_setitimer,
+ libc_sigaction,
+ libc_sigaltstack,
+ libc_sigprocmask,
+ libc_sysconf,
+ libc_usleep,
+ libc_write libcFunc
+)
+
+var sigset_none = sigset{}
+var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
+
+func getncpu() int32 {
+ n := int32(sysconf(__SC_NPROCESSORS_ONLN))
+ if n < 1 {
+ return 1
+ }
+ return n
+}
+
+func osinit() {
+ ncpu = getncpu()
+}
+
+func tstart_sysvicall()
+
+func newosproc(mp *m, _ unsafe.Pointer) {
+ var (
+ attr pthreadattr
+ oset sigset
+ tid pthread
+ ret int32
+ size uint64
+ )
+
+ if pthread_attr_init(&attr) != 0 {
+ gothrow("pthread_attr_init")
+ }
+ if pthread_attr_setstack(&attr, 0, 0x200000) != 0 {
+ gothrow("pthread_attr_setstack")
+ }
+ if pthread_attr_getstack(&attr, unsafe.Pointer(&mp.g0.stack.hi), &size) != 0 {
+ gothrow("pthread_attr_getstack")
+ }
+ mp.g0.stack.lo = mp.g0.stack.hi - uintptr(size)
+ if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
+ gothrow("pthread_attr_setdetachstate")
+ }
+
+ // Disable signals during create, so that the new thread starts
+ // with signals disabled. It will enable them in minit.
+ sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+ ret = pthread_create(&tid, &attr, funcPC(tstart_sysvicall), unsafe.Pointer(mp))
+ sigprocmask(_SIG_SETMASK, &oset, nil)
+ if ret != 0 {
+ print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n")
+ gothrow("newosproc")
+ }
+}
+
+var urandom_data [_HashRandomBytes]byte
+var urandom_dev = []byte("/dev/random\x00")
+
+//go:nosplit
+func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
+ fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+ if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes {
+ *rnd = unsafe.Pointer(&urandom_data[0])
+ *rnd_len = _HashRandomBytes
+ } else {
+ *rnd = nil
+ *rnd_len = 0
+ }
+ close(fd)
+}
+
+func goenvs() {
+ goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+}
+
+func miniterrno()
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ _g_ := getg()
+ asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(libc____errno))
+ // Initialize signal handling
+ signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
+ sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+ signalstack(nil, 0)
+}
+
+func memlimit() uintptr {
+ /*
+ TODO: Convert to Go when something actually uses the result.
+ Rlimit rl;
+ extern byte runtime·text[], runtime·end[];
+ uintptr used;
+
+ if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+ return 0;
+ if(rl.rlim_cur >= 0x7fffffff)
+ return 0;
+
+ // Estimate our VM footprint excluding the heap.
+ // Not an exact science: use size of binary plus
+ // some room for thread stacks.
+ used = runtime·end - runtime·text + (64<<20);
+ if(used >= rl.rlim_cur)
+ return 0;
+
+ // If there's not at least 16 MB left, we're probably
+ // not going to be able to do much. Treat as no limit.
+ rl.rlim_cur -= used;
+ if(rl.rlim_cur < (16<<20))
+ return 0;
+
+ return rl.rlim_cur - used;
+ */
+
+ return 0
+}
+
+func sigtramp()
+
+func setsig(i int32, fn uintptr, restart bool) {
+ var sa sigactiont
+
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+ if restart {
+ sa.sa_flags |= _SA_RESTART
+ }
+ sa.sa_mask = sigset_all
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
+ *((*uintptr)(unsafe.Pointer(&sa._funcptr))) = fn
+ sigaction(i, &sa, nil)
+}
+
+func getsig(i int32) uintptr {
+ var sa sigactiont
+ sigaction(i, nil, &sa)
+ if *((*uintptr)(unsafe.Pointer(&sa._funcptr))) == funcPC(sigtramp) {
+ return funcPC(sighandler)
+ }
+ return *((*uintptr)(unsafe.Pointer(&sa._funcptr)))
+}
+
+func signalstack(p *byte, n int32) {
+ var st sigaltstackt
+ st.ss_sp = (*byte)(unsafe.Pointer(p))
+ st.ss_size = uint64(n)
+ st.ss_flags = 0
+ if p == nil {
+ st.ss_flags = _SS_DISABLE
+ }
+ sigaltstack(&st, nil)
+}
+
+func unblocksignals() {
+ sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+}
+
+//go:nosplit
+func semacreate() uintptr {
+ var sem *semt
+ _g_ := getg()
+
+ // Call libc's malloc rather than malloc. This will
+ // allocate space on the C heap. We can't call malloc
+ // here because it could cause a deadlock.
+ _g_.m.libcall.fn = uintptr(libc_malloc)
+ _g_.m.libcall.n = 1
+ memclr(unsafe.Pointer(&_g_.m.scratch), uintptr(len(_g_.m.scratch.v)))
+ _g_.m.scratch.v[0] = unsafe.Sizeof(*sem)
+ _g_.m.libcall.args = uintptr(unsafe.Pointer(&_g_.m.scratch))
+ asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_g_.m.libcall))
+ sem = (*semt)(unsafe.Pointer(_g_.m.libcall.r1))
+ if sem_init(sem, 0, 0) != 0 {
+ gothrow("sem_init")
+ }
+ return uintptr(unsafe.Pointer(sem))
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+ _m_ := getg().m
+ if ns >= 0 {
+ _m_.ts.tv_sec = ns / 1000000000
+ _m_.ts.tv_nsec = ns % 1000000000
+
+ _m_.libcall.fn = uintptr(unsafe.Pointer(libc_sem_reltimedwait_np))
+ _m_.libcall.n = 2
+ memclr(unsafe.Pointer(&_m_.scratch), uintptr(len(_m_.scratch.v)))
+ _m_.scratch.v[0] = _m_.waitsema
+ _m_.scratch.v[1] = uintptr(unsafe.Pointer(&_m_.ts))
+ _m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
+ asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_m_.libcall))
+ if *_m_.perrno != 0 {
+ if *_m_.perrno == _ETIMEDOUT || *_m_.perrno == _EAGAIN || *_m_.perrno == _EINTR {
+ return -1
+ }
+ gothrow("sem_reltimedwait_np")
+ }
+ return 0
+ }
+ for {
+ _m_.libcall.fn = uintptr(unsafe.Pointer(libc_sem_wait))
+ _m_.libcall.n = 1
+ memclr(unsafe.Pointer(&_m_.scratch), uintptr(len(_m_.scratch.v)))
+ _m_.scratch.v[0] = _m_.waitsema
+ _m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
+ asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_m_.libcall))
+ if _m_.libcall.r1 == 0 {
+ break
+ }
+ if *_m_.perrno == _EINTR {
+ continue
+ }
+ gothrow("sem_wait")
+ }
+ return 0
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ if sem_post((*semt)(unsafe.Pointer(mp.waitsema))) != 0 {
+ gothrow("sem_post")
+ }
+}
+
+//go:nosplit
+func close(fd int32) int32 {
+ return int32(sysvicall1(libc_close, uintptr(fd)))
+}
+
+//go:nosplit
+func exit(r int32) {
+ sysvicall1(libc_exit, uintptr(r))
+}
+
+//go:nosplit
+func getcontext(context *ucontext) /* int32 */ {
+ sysvicall1(libc_getcontext, uintptr(unsafe.Pointer(context)))
+}
+
+//go:nosplit
+func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
+ sysvicall3(libc_madvise, uintptr(addr), uintptr(n), uintptr(flags))
+}
+
+//go:nosplit
+func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer {
+ return unsafe.Pointer(sysvicall6(libc_mmap, uintptr(addr), uintptr(n), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off)))
+}
+
+//go:nosplit
+func munmap(addr unsafe.Pointer, n uintptr) {
+ sysvicall2(libc_munmap, uintptr(addr), uintptr(n))
+}
+
+func nanotime1()
+
+//go:nosplit
+func nanotime() int64 {
+ return int64(sysvicall0(libcFunc(funcPC(nanotime1))))
+}
+
+//go:nosplit
+func open(path *byte, mode, perm int32) int32 {
+ return int32(sysvicall3(libc_open, uintptr(unsafe.Pointer(path)), uintptr(mode), uintptr(perm)))
+}
+
+func pthread_attr_destroy(attr *pthreadattr) int32 {
+ return int32(sysvicall1(libc_pthread_attr_destroy, uintptr(unsafe.Pointer(attr))))
+}
+
+func pthread_attr_getstack(attr *pthreadattr, addr unsafe.Pointer, size *uint64) int32 {
+ return int32(sysvicall3(libc_pthread_attr_getstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(unsafe.Pointer(size))))
+}
+
+func pthread_attr_init(attr *pthreadattr) int32 {
+ return int32(sysvicall1(libc_pthread_attr_init, uintptr(unsafe.Pointer(attr))))
+}
+
+func pthread_attr_setdetachstate(attr *pthreadattr, state int32) int32 {
+ return int32(sysvicall2(libc_pthread_attr_setdetachstate, uintptr(unsafe.Pointer(attr)), uintptr(state)))
+}
+
+func pthread_attr_setstack(attr *pthreadattr, addr uintptr, size uint64) int32 {
+ return int32(sysvicall3(libc_pthread_attr_setstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(size)))
+}
+
+func pthread_create(thread *pthread, attr *pthreadattr, fn uintptr, arg unsafe.Pointer) int32 {
+ return int32(sysvicall4(libc_pthread_create, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(fn), uintptr(arg)))
+}
+
+func raise(sig int32) /* int32 */ {
+ sysvicall1(libc_raise, uintptr(sig))
+}
+
+//go:nosplit
+func read(fd int32, buf unsafe.Pointer, nbyte int32) int32 {
+ return int32(sysvicall3(libc_read, uintptr(fd), uintptr(buf), uintptr(nbyte)))
+}
+
+//go:nosplit
+func sem_init(sem *semt, pshared int32, value uint32) int32 {
+ return int32(sysvicall3(libc_sem_init, uintptr(unsafe.Pointer(sem)), uintptr(pshared), uintptr(value)))
+}
+
+//go:nosplit
+func sem_post(sem *semt) int32 {
+ return int32(sysvicall1(libc_sem_post, uintptr(unsafe.Pointer(sem))))
+}
+
+//go:nosplit
+func sem_reltimedwait_np(sem *semt, timeout *timespec) int32 {
+ return int32(sysvicall2(libc_sem_reltimedwait_np, uintptr(unsafe.Pointer(sem)), uintptr(unsafe.Pointer(timeout))))
+}
+
+//go:nosplit
+func sem_wait(sem *semt) int32 {
+ return int32(sysvicall1(libc_sem_wait, uintptr(unsafe.Pointer(sem))))
+}
+
+func setitimer(which int32, value *itimerval, ovalue *itimerval) /* int32 */ {
+ sysvicall3(libc_setitimer, uintptr(which), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(ovalue)))
+}
+
+func sigaction(sig int32, act *sigactiont, oact *sigactiont) /* int32 */ {
+ sysvicall3(libc_sigaction, uintptr(sig), uintptr(unsafe.Pointer(act)), uintptr(unsafe.Pointer(oact)))
+}
+
+func sigaltstack(ss *sigaltstackt, oss *sigaltstackt) /* int32 */ {
+ sysvicall2(libc_sigaltstack, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(oss)))
+}
+
+func sigprocmask(how int32, set *sigset, oset *sigset) /* int32 */ {
+ sysvicall3(libc_sigprocmask, uintptr(how), uintptr(unsafe.Pointer(set)), uintptr(unsafe.Pointer(oset)))
+}
+
+func sysconf(name int32) int64 {
+ return int64(sysvicall1(libc_sysconf, uintptr(name)))
+}
+
+func usleep1(uint32)
+
+//go:nosplit
+func usleep(µs uint32) {
+ usleep1(µs)
+}
+
+//go:nosplit
+func write(fd uintptr, buf unsafe.Pointer, nbyte int32) int32 {
+ return int32(sysvicall3(libc_write, uintptr(fd), uintptr(buf), uintptr(nbyte)))
+}
+
+func osyield1()
+
+//go:nosplit
+func osyield() {
+ _g_ := getg()
+
+ // Check the validity of m because we might be called in cgo callback
+ // path early enough where there isn't a m available yet.
+ if _g_ != nil && _g_.m != nil {
+ sysvicall0(libc_sched_yield)
+ return
+ }
+ osyield1()
+}
diff --git a/src/runtime/os_android.h b/src/runtime/os_android.h
deleted file mode 100644
index c7c1098e8..000000000
--- a/src/runtime/os_android.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "os_linux.h"
diff --git a/src/runtime/os_android.c b/src/runtime/os_android_arm.go
index 5805f6871..132832236 100644
--- a/src/runtime/os_android.c
+++ b/src/runtime/os_android_arm.go
@@ -2,15 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
+package runtime
+
+import _ "unsafe"
// Export the runtime entry point symbol.
//
// Used by the app package to start the Go runtime after loading
// a shared library via JNI. See golang.org/x/mobile/app.
-void _rt0_arm_linux1();
-#pragma cgo_export_static _rt0_arm_linux1
-#pragma cgo_export_dynamic _rt0_arm_linux1
+//go:cgo_export_static _rt0_arm_linux1
+//go:cgo_export_dynamic _rt0_arm_linux1
diff --git a/src/runtime/os_darwin.c b/src/runtime/os_darwin.c
deleted file mode 100644
index bbd29282b..000000000
--- a/src/runtime/os_darwin.c
+++ /dev/null
@@ -1,567 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-extern SigTab runtime·sigtab[];
-
-static Sigset sigset_none;
-static Sigset sigset_all = ~(Sigset)0;
-
-static void
-unimplemented(int8 *name)
-{
- runtime·prints(name);
- runtime·prints(" not implemented\n");
- *(int32*)1231 = 1231;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
- runtime·mach_semrelease(mp->waitsema);
-}
-
-static void
-semacreate(void)
-{
- g->m->scalararg[0] = runtime·mach_semcreate();
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
- uintptr x;
- void (*fn)(void);
-
- fn = semacreate;
- runtime·onM(&fn);
- x = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
- return x;
-}
-
-// BSD interface for threading.
-void
-runtime·osinit(void)
-{
- // bsdthread_register delayed until end of goenvs so that we
- // can look at the environment first.
-
- // Use sysctl to fetch hw.ncpu.
- uint32 mib[2];
- uint32 out;
- int32 ret;
- uintptr nout;
-
- mib[0] = 6;
- mib[1] = 3;
- nout = sizeof out;
- out = 0;
- ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
- if(ret >= 0)
- runtime·ncpu = out;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
- #pragma dataflag NOPTR
- static byte urandom_data[HashRandomBytes];
- int32 fd;
- fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
- if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
- *rnd = urandom_data;
- *rnd_len = HashRandomBytes;
- } else {
- *rnd = nil;
- *rnd_len = 0;
- }
- runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
- runtime·goenvs_unix();
-
- // Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
- // but only if we're not using cgo. If we are using cgo we need
- // to let the C pthread library install its own thread-creation callback.
- if(!runtime·iscgo) {
- if(runtime·bsdthread_register() != 0) {
- if(runtime·getenv("DYLD_INSERT_LIBRARIES"))
- runtime·throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)");
- runtime·throw("runtime: bsdthread_register error");
- }
- }
-
-}
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
- int32 errno;
- Sigset oset;
-
- mp->tls[0] = mp->id; // so 386 asm can find it
- if(0){
- runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
- stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
- }
-
- runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
- errno = runtime·bsdthread_create(stk, mp, mp->g0, runtime·mstart);
- runtime·sigprocmask(SIG_SETMASK, &oset, nil);
-
- if(errno < 0) {
- runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -errno);
- runtime·throw("runtime.newosproc");
- }
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
- mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
- mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
- // Initialize signal handling.
- runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
-
- runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
- runtime·signalstack(nil, 0);
-}
-
-// Mach IPC, to get at semaphores
-// Definitions are in /usr/include/mach on a Mac.
-
-static void
-macherror(int32 r, int8 *fn)
-{
- runtime·prints("mach error ");
- runtime·prints(fn);
- runtime·prints(": ");
- runtime·printint(r);
- runtime·prints("\n");
- runtime·throw("mach error");
-}
-
-enum
-{
- DebugMach = 0
-};
-
-static MachNDR zerondr;
-
-#define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8))
-
-static int32
-mach_msg(MachHeader *h,
- int32 op,
- uint32 send_size,
- uint32 rcv_size,
- uint32 rcv_name,
- uint32 timeout,
- uint32 notify)
-{
- // TODO: Loop on interrupt.
- return runtime·mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
-}
-
-// Mach RPC (MIG)
-
-enum
-{
- MinMachMsg = 48,
- Reply = 100,
-};
-
-#pragma pack on
-typedef struct CodeMsg CodeMsg;
-struct CodeMsg
-{
- MachHeader h;
- MachNDR NDR;
- int32 code;
-};
-#pragma pack off
-
-static int32
-machcall(MachHeader *h, int32 maxsize, int32 rxsize)
-{
- uint32 *p;
- int32 i, ret, id;
- uint32 port;
- CodeMsg *c;
-
- if((port = g->m->machport) == 0){
- port = runtime·mach_reply_port();
- g->m->machport = port;
- }
-
- h->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
- h->msgh_local_port = port;
- h->msgh_reserved = 0;
- id = h->msgh_id;
-
- if(DebugMach){
- p = (uint32*)h;
- runtime·prints("send:\t");
- for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
- runtime·prints(" ");
- runtime·printpointer((void*)p[i]);
- if(i%8 == 7)
- runtime·prints("\n\t");
- }
- if(i%8)
- runtime·prints("\n");
- }
-
- ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG,
- h->msgh_size, maxsize, port, 0, 0);
- if(ret != 0){
- if(DebugMach){
- runtime·prints("mach_msg error ");
- runtime·printint(ret);
- runtime·prints("\n");
- }
- return ret;
- }
-
- if(DebugMach){
- p = (uint32*)h;
- runtime·prints("recv:\t");
- for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
- runtime·prints(" ");
- runtime·printpointer((void*)p[i]);
- if(i%8 == 7)
- runtime·prints("\n\t");
- }
- if(i%8)
- runtime·prints("\n");
- }
-
- if(h->msgh_id != id+Reply){
- if(DebugMach){
- runtime·prints("mach_msg reply id mismatch ");
- runtime·printint(h->msgh_id);
- runtime·prints(" != ");
- runtime·printint(id+Reply);
- runtime·prints("\n");
- }
- return -303; // MIG_REPLY_MISMATCH
- }
-
- // Look for a response giving the return value.
- // Any call can send this back with an error,
- // and some calls only have return values so they
- // send it back on success too. I don't quite see how
- // you know it's one of these and not the full response
- // format, so just look if the message is right.
- c = (CodeMsg*)h;
- if(h->msgh_size == sizeof(CodeMsg)
- && !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){
- if(DebugMach){
- runtime·prints("mig result ");
- runtime·printint(c->code);
- runtime·prints("\n");
- }
- return c->code;
- }
-
- if(h->msgh_size != rxsize){
- if(DebugMach){
- runtime·prints("mach_msg reply size mismatch ");
- runtime·printint(h->msgh_size);
- runtime·prints(" != ");
- runtime·printint(rxsize);
- runtime·prints("\n");
- }
- return -307; // MIG_ARRAY_TOO_LARGE
- }
-
- return 0;
-}
-
-
-// Semaphores!
-
-enum
-{
- Tmach_semcreate = 3418,
- Rmach_semcreate = Tmach_semcreate + Reply,
-
- Tmach_semdestroy = 3419,
- Rmach_semdestroy = Tmach_semdestroy + Reply,
-
- // Mach calls that get interrupted by Unix signals
- // return this error code. We retry them.
- KERN_ABORTED = 14,
- KERN_OPERATION_TIMED_OUT = 49,
-};
-
-typedef struct Tmach_semcreateMsg Tmach_semcreateMsg;
-typedef struct Rmach_semcreateMsg Rmach_semcreateMsg;
-typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg;
-// Rmach_semdestroyMsg = CodeMsg
-
-#pragma pack on
-struct Tmach_semcreateMsg
-{
- MachHeader h;
- MachNDR ndr;
- int32 policy;
- int32 value;
-};
-
-struct Rmach_semcreateMsg
-{
- MachHeader h;
- MachBody body;
- MachPort semaphore;
-};
-
-struct Tmach_semdestroyMsg
-{
- MachHeader h;
- MachBody body;
- MachPort semaphore;
-};
-#pragma pack off
-
-uint32
-runtime·mach_semcreate(void)
-{
- union {
- Tmach_semcreateMsg tx;
- Rmach_semcreateMsg rx;
- uint8 pad[MinMachMsg];
- } m;
- int32 r;
-
- m.tx.h.msgh_bits = 0;
- m.tx.h.msgh_size = sizeof(m.tx);
- m.tx.h.msgh_remote_port = runtime·mach_task_self();
- m.tx.h.msgh_id = Tmach_semcreate;
- m.tx.ndr = zerondr;
-
- m.tx.policy = 0; // 0 = SYNC_POLICY_FIFO
- m.tx.value = 0;
-
- while((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0){
- if(r == KERN_ABORTED) // interrupted
- continue;
- macherror(r, "semaphore_create");
- }
- if(m.rx.body.msgh_descriptor_count != 1)
- unimplemented("mach_semcreate desc count");
- return m.rx.semaphore.name;
-}
-
-void
-runtime·mach_semdestroy(uint32 sem)
-{
- union {
- Tmach_semdestroyMsg tx;
- uint8 pad[MinMachMsg];
- } m;
- int32 r;
-
- m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX;
- m.tx.h.msgh_size = sizeof(m.tx);
- m.tx.h.msgh_remote_port = runtime·mach_task_self();
- m.tx.h.msgh_id = Tmach_semdestroy;
- m.tx.body.msgh_descriptor_count = 1;
- m.tx.semaphore.name = sem;
- m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND;
- m.tx.semaphore.type = 0;
-
- while((r = machcall(&m.tx.h, sizeof m, 0)) != 0){
- if(r == KERN_ABORTED) // interrupted
- continue;
- macherror(r, "semaphore_destroy");
- }
-}
-
-// The other calls have simple system call traps in sys_darwin_{amd64,386}.s
-int32 runtime·mach_semaphore_wait(uint32 sema);
-int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
-int32 runtime·mach_semaphore_signal(uint32 sema);
-int32 runtime·mach_semaphore_signal_all(uint32 sema);
-
-static void
-semasleep(void)
-{
- int32 r, secs, nsecs;
- int64 ns;
-
- ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
- g->m->scalararg[0] = 0;
- g->m->scalararg[1] = 0;
-
- if(ns >= 0) {
- secs = runtime·timediv(ns, 1000000000, &nsecs);
- r = runtime·mach_semaphore_timedwait(g->m->waitsema, secs, nsecs);
- if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT) {
- g->m->scalararg[0] = -1;
- return;
- }
- if(r != 0)
- macherror(r, "semaphore_wait");
- g->m->scalararg[0] = 0;
- return;
- }
- while((r = runtime·mach_semaphore_wait(g->m->waitsema)) != 0) {
- if(r == KERN_ABORTED) // interrupted
- continue;
- macherror(r, "semaphore_wait");
- }
- g->m->scalararg[0] = 0;
- return;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
- int32 r;
- void (*fn)(void);
-
- g->m->scalararg[0] = (uint32)ns;
- g->m->scalararg[1] = (uint32)(ns>>32);
- fn = semasleep;
- runtime·onM(&fn);
- r = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
- return r;
-}
-
-static int32 mach_semrelease_errno;
-
-static void
-mach_semrelease_fail(void)
-{
- macherror(mach_semrelease_errno, "semaphore_signal");
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·mach_semrelease(uint32 sem)
-{
- int32 r;
- void (*fn)(void);
-
- while((r = runtime·mach_semaphore_signal(sem)) != 0) {
- if(r == KERN_ABORTED) // interrupted
- continue;
-
- // mach_semrelease must be completely nosplit,
- // because it is called from Go code.
- // If we're going to die, start that process on the m stack
- // to avoid a Go stack split.
- // Only do that if we're actually running on the g stack.
- // We might be on the gsignal stack, and if so, onM will abort.
- // We use the global variable instead of scalararg because
- // we might be on the gsignal stack, having interrupted a
- // normal call to onM. It doesn't quite matter, since the
- // program is about to die, but better to be clean.
- mach_semrelease_errno = r;
- fn = mach_semrelease_fail;
- if(g == g->m->curg)
- runtime·onM(&fn);
- else
- fn();
- }
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·osyield(void)
-{
- runtime·usleep(1);
-}
-
-uintptr
-runtime·memlimit(void)
-{
- // NOTE(rsc): Could use getrlimit here,
- // like on FreeBSD or Linux, but Darwin doesn't enforce
- // ulimit -v, so it's unclear why we'd try to stay within
- // the limit.
- return 0;
-}
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask = ~(uintptr)0;
- sa.sa_tramp = (void*)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
- *(uintptr*)sa.__sigaction_u = (uintptr)fn;
- runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- return *(void**)sa.__sigaction_u;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- StackT st;
-
- st.ss_sp = (void*)p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
- runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
- return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index 4327ced91..d8296e056 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -6,19 +6,31 @@ package runtime
import "unsafe"
-func bsdthread_create(stk, mm, gg, fn unsafe.Pointer) int32
+func bsdthread_create(stk unsafe.Pointer, mm *m, gg *g, fn uintptr) int32
func bsdthread_register() int32
+
+//go:noescape
func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32
+
func mach_reply_port() uint32
func mach_task_self() uint32
func mach_thread_self() uint32
+
+//go:noescape
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-func sigprocmask(sig int32, new, old unsafe.Pointer)
-func sigaction(mode uint32, new, old unsafe.Pointer)
-func sigaltstack(new, old unsafe.Pointer)
+
+//go:noescape
+func sigprocmask(sig uint32, new, old *uint32)
+
+//go:noescape
+func sigaction(mode uint32, new, old *sigactiont)
+
+//go:noescape
+func sigaltstack(new, old *stackt)
+
func sigtramp()
-func setitimer(mode int32, new, old unsafe.Pointer)
-func mach_semaphore_wait(sema uint32) int32
-func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
-func mach_semaphore_signal(sema uint32) int32
-func mach_semaphore_signal_all(sema uint32) int32
+
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+func raise(int32)
diff --git a/src/runtime/os_darwin.h b/src/runtime/os_darwin.h
deleted file mode 100644
index e8bb45daf..000000000
--- a/src/runtime/os_darwin.h
+++ /dev/null
@@ -1,43 +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.
-
-typedef byte* kevent_udata;
-
-int32 runtime·bsdthread_create(void*, M*, G*, void(*)(void));
-int32 runtime·bsdthread_register(void);
-int32 runtime·mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32);
-uint32 runtime·mach_reply_port(void);
-int32 runtime·mach_semacquire(uint32, int64);
-uint32 runtime·mach_semcreate(void);
-void runtime·mach_semdestroy(uint32);
-void runtime·mach_semrelease(uint32);
-void runtime·mach_semreset(uint32);
-uint32 runtime·mach_task_self(void);
-uint32 runtime·mach_task_self(void);
-uint32 runtime·mach_thread_self(void);
-uint32 runtime·mach_thread_self(void);
-int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-
-typedef uint32 Sigset;
-void runtime·sigprocmask(int32, Sigset*, Sigset*);
-void runtime·unblocksignals(void);
-
-struct SigactionT;
-void runtime·sigaction(uintptr, struct SigactionT*, struct SigactionT*);
-
-struct StackT;
-void runtime·sigaltstack(struct StackT*, struct StackT*);
-void runtime·sigtramp(void);
-void runtime·sigpanic(void);
-void runtime·setitimer(int32, Itimerval*, Itimerval*);
-
-
-enum {
- NSIG = 32,
- SI_USER = 0, /* empirically true, but not what headers say */
- SIG_BLOCK = 1,
- SIG_UNBLOCK = 2,
- SIG_SETMASK = 3,
- SS_DISABLE = 4,
-};
diff --git a/src/runtime/os_dragonfly.c b/src/runtime/os_dragonfly.c
deleted file mode 100644
index e372205ec..000000000
--- a/src/runtime/os_dragonfly.c
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 2011 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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-extern SigTab runtime·sigtab[];
-extern int32 runtime·sys_umtx_sleep(uint32*, int32, int32);
-extern int32 runtime·sys_umtx_wakeup(uint32*, int32);
-
-// From DragonFly's <sys/sysctl.h>
-#define CTL_HW 6
-#define HW_NCPU 3
-
-static Sigset sigset_none;
-static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
-
-static int32
-getncpu(void)
-{
- uint32 mib[2];
- uint32 out;
- int32 ret;
- uintptr nout;
-
- // Fetch hw.ncpu via sysctl.
- mib[0] = CTL_HW;
- mib[1] = HW_NCPU;
- nout = sizeof out;
- out = 0;
- ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
- if(ret >= 0)
- return out;
- else
- return 1;
-}
-
-static void futexsleep(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
-{
- void (*fn)(void);
-
- g->m->ptrarg[0] = addr;
- g->m->scalararg[0] = val;
- g->m->ptrarg[1] = &ns;
-
- fn = futexsleep;
- runtime·onM(&fn);
-}
-
-static void
-futexsleep(void)
-{
- uint32 *addr;
- uint32 val;
- int64 ns;
- int32 timeout = 0;
- int32 ret;
-
- addr = g->m->ptrarg[0];
- val = g->m->scalararg[0];
- ns = *(int64*)g->m->ptrarg[1];
- g->m->ptrarg[0] = nil;
- g->m->scalararg[0] = 0;
- g->m->ptrarg[1] = nil;
-
- if(ns >= 0) {
- // The timeout is specified in microseconds - ensure that we
- // do not end up dividing to zero, which would put us to sleep
- // indefinitely...
- timeout = runtime·timediv(ns, 1000, nil);
- if(timeout == 0)
- timeout = 1;
- }
-
- // sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
- // expires or EBUSY if the mutex value does not match.
- ret = runtime·sys_umtx_sleep(addr, val, timeout);
- if(ret >= 0 || ret == -EINTR || ret == -EAGAIN || ret == -EBUSY)
- return;
-
- runtime·prints("umtx_wait addr=");
- runtime·printpointer(addr);
- runtime·prints(" val=");
- runtime·printint(val);
- runtime·prints(" ret=");
- runtime·printint(ret);
- runtime·prints("\n");
- *(int32*)0x1005 = 0x1005;
-}
-
-static void badfutexwakeup(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·futexwakeup(uint32 *addr, uint32 cnt)
-{
- int32 ret;
- void (*fn)(void);
-
- ret = runtime·sys_umtx_wakeup(addr, cnt);
- if(ret >= 0)
- return;
-
- g->m->ptrarg[0] = addr;
- g->m->scalararg[0] = ret;
- fn = badfutexwakeup;
- if(g == g->m->gsignal)
- fn();
- else
- runtime·onM(&fn);
- *(int32*)0x1006 = 0x1006;
-}
-
-static void
-badfutexwakeup(void)
-{
- void *addr;
- int32 ret;
-
- addr = g->m->ptrarg[0];
- ret = g->m->scalararg[0];
- runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
-}
-
-void runtime·lwp_start(void*);
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
- Lwpparams params;
- Sigset oset;
-
- if(0){
- runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
- stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
- }
-
- runtime·sigprocmask(&sigset_all, &oset);
- runtime·memclr((byte*)&params, sizeof params);
-
- params.func = runtime·lwp_start;
- params.arg = (byte*)mp;
- params.stack = (byte*)stk;
- params.tid1 = (int32*)&mp->procid;
- params.tid2 = nil;
-
- mp->tls[0] = mp->id; // so 386 asm can find it
-
- runtime·lwp_create(&params);
- runtime·sigprocmask(&oset, nil);
-}
-
-void
-runtime·osinit(void)
-{
- runtime·ncpu = getncpu();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
- #pragma dataflag NOPTR
- static byte urandom_data[HashRandomBytes];
- int32 fd;
- fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
- if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
- *rnd = urandom_data;
- *rnd_len = HashRandomBytes;
- } else {
- *rnd = nil;
- *rnd_len = 0;
- }
- runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
- runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
- mp->gsignal = runtime·malg(32*1024);
- mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
- // Initialize signal handling
- runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
- runtime·sigprocmask(&sigset_none, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
- runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
- Rlimit rl;
- extern byte runtime·text[], runtime·end[];
- uintptr used;
-
- if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
- return 0;
- if(rl.rlim_cur >= 0x7fffffff)
- return 0;
-
- // Estimate our VM footprint excluding the heap.
- // Not an exact science: use size of binary plus
- // some room for thread stacks.
- used = runtime·end - runtime·text + (64<<20);
- if(used >= rl.rlim_cur)
- return 0;
-
- // If there's not at least 16 MB left, we're probably
- // not going to be able to do much. Treat as no limit.
- rl.rlim_cur -= used;
- if(rl.rlim_cur < (16<<20))
- return 0;
-
- return rl.rlim_cur - used;
-}
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*__sa_handler)(int32);
- void (*__sa_sigaction)(int32, Siginfo*, void *);
- } __sigaction_u; /* signal handler */
- int32 sa_flags; /* see signal options below */
- Sigset sa_mask; /* signal mask to apply */
-} SigactionT;
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask.__bits[0] = ~(uint32)0;
- sa.sa_mask.__bits[1] = ~(uint32)0;
- sa.sa_mask.__bits[2] = ~(uint32)0;
- sa.sa_mask.__bits[3] = ~(uint32)0;
- if(fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.__sigaction_u.__sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
- return runtime·sighandler;
- return (void*)sa.__sigaction_u.__sa_sigaction;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- StackT st;
-
- st.ss_sp = (void*)p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
- runtime·sigprocmask(&sigset_none, nil);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
- return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go
index cdaa06986..0e00f874f 100644
--- a/src/runtime/os_dragonfly.go
+++ b/src/runtime/os_dragonfly.go
@@ -6,15 +6,35 @@ package runtime
import "unsafe"
-func lwp_create(param unsafe.Pointer) int32
-func sigaltstack(new, old unsafe.Pointer)
-func sigaction(sig int32, new, old unsafe.Pointer)
-func sigprocmask(new, old unsafe.Pointer)
-func setitimer(mode int32, new, old unsafe.Pointer)
+//go:noescape
+func lwp_create(param *lwpparams) int32
+
+//go:noescape
+func sigaltstack(new, old *sigaltstackt)
+
+//go:noescape
+func sigaction(sig int32, new, old *sigactiont)
+
+//go:noescape
+func sigprocmask(new, old *sigset)
+
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+//go:noescape
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
+
+//go:noescape
func getrlimit(kind int32, limit unsafe.Pointer) int32
+
func raise(sig int32)
-func sys_umtx_sleep(addr unsafe.Pointer, val, timeout int32) int32
-func sys_umtx_wakeup(addr unsafe.Pointer, val int32) int32
+
+//go:noescape
+func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
+
+//go:noescape
+func sys_umtx_wakeup(addr *uint32, val int32) int32
+
+func osyield()
const stackSystem = 0
diff --git a/src/runtime/os_dragonfly.h b/src/runtime/os_dragonfly.h
deleted file mode 100644
index 389736a32..000000000
--- a/src/runtime/os_dragonfly.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2011 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 byte* kevent_udata;
-
-int32 runtime·lwp_create(Lwpparams*);
-void runtime·sigpanic(void);
-void runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-struct sigaction;
-void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
-void runtime·sigprocmask(Sigset *, Sigset *);
-void runtime·unblocksignals(void);
-void runtime·setitimer(int32, Itimerval*, Itimerval*);
-int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-
-enum {
- NSIG = 33,
- SI_USER = 0x10001,
- SS_DISABLE = 4,
- RLIMIT_AS = 10,
-};
-
-typedef struct Rlimit Rlimit;
-struct Rlimit {
- int64 rlim_cur;
- int64 rlim_max;
-};
-int32 runtime·getrlimit(int32, Rlimit*);
diff --git a/src/runtime/os_freebsd.c b/src/runtime/os_freebsd.c
deleted file mode 100644
index a513cb604..000000000
--- a/src/runtime/os_freebsd.c
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright 2011 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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-extern SigTab runtime·sigtab[];
-extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*);
-
-// From FreeBSD's <sys/sysctl.h>
-#define CTL_HW 6
-#define HW_NCPU 3
-
-static Sigset sigset_none;
-static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
-
-static int32
-getncpu(void)
-{
- uint32 mib[2];
- uint32 out;
- int32 ret;
- uintptr nout;
-
- // Fetch hw.ncpu via sysctl.
- mib[0] = CTL_HW;
- mib[1] = HW_NCPU;
- nout = sizeof out;
- out = 0;
- ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
- if(ret >= 0)
- return out;
- else
- return 1;
-}
-
-// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
-// thus the code is largely similar. See linux/thread.c and lock_futex.c for comments.
-
-static void futexsleep(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
-{
- void (*fn)(void);
-
- g->m->ptrarg[0] = addr;
- g->m->scalararg[0] = val;
- g->m->ptrarg[1] = &ns;
-
- fn = futexsleep;
- runtime·onM(&fn);
-}
-
-static void
-futexsleep(void)
-{
- uint32 *addr;
- uint32 val;
- int64 ns;
- int32 ret;
- Timespec ts;
-
- addr = g->m->ptrarg[0];
- val = g->m->scalararg[0];
- ns = *(int64*)g->m->ptrarg[1];
- g->m->ptrarg[0] = nil;
- g->m->scalararg[0] = 0;
- g->m->ptrarg[1] = nil;
-
- if(ns < 0) {
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, nil);
- if(ret >= 0 || ret == -EINTR)
- return;
- goto fail;
- }
- // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
- ts.tv_nsec = 0;
- ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, &ts);
- if(ret >= 0 || ret == -EINTR)
- return;
-
-fail:
- runtime·prints("umtx_wait addr=");
- runtime·printpointer(addr);
- runtime·prints(" val=");
- runtime·printint(val);
- runtime·prints(" ret=");
- runtime·printint(ret);
- runtime·prints("\n");
- *(int32*)0x1005 = 0x1005;
-}
-
-static void badfutexwakeup(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·futexwakeup(uint32 *addr, uint32 cnt)
-{
- int32 ret;
- void (*fn)(void);
-
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE_PRIVATE, cnt, nil, nil);
- if(ret >= 0)
- return;
-
- g->m->ptrarg[0] = addr;
- g->m->scalararg[0] = ret;
- fn = badfutexwakeup;
- if(g == g->m->gsignal)
- fn();
- else
- runtime·onM(&fn);
- *(int32*)0x1006 = 0x1006;
-}
-
-static void
-badfutexwakeup(void)
-{
- void *addr;
- int32 ret;
-
- addr = g->m->ptrarg[0];
- ret = g->m->scalararg[0];
- runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
-}
-
-void runtime·thr_start(void*);
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
- ThrParam param;
- Sigset oset;
-
- if(0){
- runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
- stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
- }
-
- runtime·sigprocmask(&sigset_all, &oset);
- runtime·memclr((byte*)&param, sizeof param);
-
- param.start_func = runtime·thr_start;
- param.arg = (byte*)mp;
-
- // NOTE(rsc): This code is confused. stackbase is the top of the stack
- // and is equal to stk. However, it's working, so I'm not changing it.
- param.stack_base = (void*)mp->g0->stack.hi;
- param.stack_size = (byte*)stk - (byte*)mp->g0->stack.hi;
-
- param.child_tid = (void*)&mp->procid;
- param.parent_tid = nil;
- param.tls_base = (void*)&mp->tls[0];
- param.tls_size = sizeof mp->tls;
-
- mp->tls[0] = mp->id; // so 386 asm can find it
-
- runtime·thr_new(&param, sizeof param);
- runtime·sigprocmask(&oset, nil);
-}
-
-void
-runtime·osinit(void)
-{
- runtime·ncpu = getncpu();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
- #pragma dataflag NOPTR
- static byte urandom_data[HashRandomBytes];
- int32 fd;
- fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
- if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
- *rnd = urandom_data;
- *rnd_len = HashRandomBytes;
- } else {
- *rnd = nil;
- *rnd_len = 0;
- }
- runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
- runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
- mp->gsignal = runtime·malg(32*1024);
- mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
- // Initialize signal handling
- runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
- runtime·sigprocmask(&sigset_none, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
- runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
- Rlimit rl;
- extern byte runtime·text[], runtime·end[];
- uintptr used;
-
- if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
- return 0;
- if(rl.rlim_cur >= 0x7fffffff)
- return 0;
-
- // Estimate our VM footprint excluding the heap.
- // Not an exact science: use size of binary plus
- // some room for thread stacks.
- used = runtime·end - runtime·text + (64<<20);
- if(used >= rl.rlim_cur)
- return 0;
-
- // If there's not at least 16 MB left, we're probably
- // not going to be able to do much. Treat as no limit.
- rl.rlim_cur -= used;
- if(rl.rlim_cur < (16<<20))
- return 0;
-
- return rl.rlim_cur - used;
-}
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*__sa_handler)(int32);
- void (*__sa_sigaction)(int32, Siginfo*, void *);
- } __sigaction_u; /* signal handler */
- int32 sa_flags; /* see signal options below */
- Sigset sa_mask; /* signal mask to apply */
-} SigactionT;
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask.__bits[0] = ~(uint32)0;
- sa.sa_mask.__bits[1] = ~(uint32)0;
- sa.sa_mask.__bits[2] = ~(uint32)0;
- sa.sa_mask.__bits[3] = ~(uint32)0;
- if(fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.__sigaction_u.__sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
- return runtime·sighandler;
- return (void*)sa.__sigaction_u.__sa_sigaction;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- StackT st;
-
- st.ss_sp = (void*)p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
- runtime·sigprocmask(&sigset_none, nil);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
- return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go
index 59708049c..998fbca0f 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -6,12 +6,29 @@ package runtime
import "unsafe"
-func thr_new(param unsafe.Pointer, size int32)
-func sigaltstack(new, old unsafe.Pointer)
-func sigaction(sig int32, new, old unsafe.Pointer)
-func sigprocmask(new, old unsafe.Pointer)
-func setitimer(mode int32, new, old unsafe.Pointer)
+//go:noescape
+func thr_new(param *thrparam, size int32)
+
+//go:noescape
+func sigaltstack(new, old *stackt)
+
+//go:noescape
+func sigaction(sig int32, new, old *sigactiont)
+
+//go:noescape
+func sigprocmask(new, old *sigset)
+
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+//go:noescape
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
+
+//go:noescape
func getrlimit(kind int32, limit unsafe.Pointer) int32
func raise(sig int32)
-func sys_umtx_op(addr unsafe.Pointer, mode int32, val uint32, ptr2, ts unsafe.Pointer) int32
+
+//go:noescape
+func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32
+
+func osyield()
diff --git a/src/runtime/os_freebsd.h b/src/runtime/os_freebsd.h
deleted file mode 100644
index b86bb393c..000000000
--- a/src/runtime/os_freebsd.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2011 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 byte* kevent_udata;
-
-int32 runtime·thr_new(ThrParam*, int32);
-void runtime·sigpanic(void);
-void runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-struct sigaction;
-void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
-void runtime·sigprocmask(Sigset *, Sigset *);
-void runtime·unblocksignals(void);
-void runtime·setitimer(int32, Itimerval*, Itimerval*);
-int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-
-enum {
- SS_DISABLE = 4,
- NSIG = 33,
- SI_USER = 0x10001,
- RLIMIT_AS = 10,
-};
-
-typedef struct Rlimit Rlimit;
-struct Rlimit {
- int64 rlim_cur;
- int64 rlim_max;
-};
-int32 runtime·getrlimit(int32, Rlimit*);
diff --git a/src/runtime/os_freebsd_arm.c b/src/runtime/os_freebsd_arm.go
index 2f2d7767f..e049cbf9a 100644
--- a/src/runtime/os_freebsd_arm.c
+++ b/src/runtime/os_freebsd_arm.go
@@ -2,23 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "textflag.h"
+package runtime
-void
-runtime·checkgoarm(void)
-{
+func checkgoarm() {
// TODO(minux)
}
-#pragma textflag NOSPLIT
-int64
-runtime·cputicks(void)
-{
+//go:nosplit
+func cputicks() int64 {
// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
// TODO: need more entropy to better seed fastrand1.
- return runtime·nanotime();
+ return nanotime()
}
diff --git a/src/runtime/os_linux.c b/src/runtime/os_linux.c
deleted file mode 100644
index 0d8ffc995..000000000
--- a/src/runtime/os_linux.c
+++ /dev/null
@@ -1,342 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-extern SigTab runtime·sigtab[];
-
-static Sigset sigset_none;
-static Sigset sigset_all = { ~(uint32)0, ~(uint32)0 };
-
-// Linux futex.
-//
-// futexsleep(uint32 *addr, uint32 val)
-// futexwakeup(uint32 *addr)
-//
-// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
-// Futexwakeup wakes up threads sleeping on addr.
-// Futexsleep is allowed to wake up spuriously.
-
-enum
-{
- FUTEX_WAIT = 0,
- FUTEX_WAKE = 1,
-};
-
-// Atomically,
-// if(*addr == val) sleep
-// Might be woken up spuriously; that's allowed.
-// Don't sleep longer than ns; ns < 0 means forever.
-#pragma textflag NOSPLIT
-void
-runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
-{
- Timespec ts;
-
- // Some Linux kernels have a bug where futex of
- // FUTEX_WAIT returns an internal error code
- // as an errno. Libpthread ignores the return value
- // here, and so can we: as it says a few lines up,
- // spurious wakeups are allowed.
-
- if(ns < 0) {
- runtime·futex(addr, FUTEX_WAIT, val, nil, nil, 0);
- return;
- }
- // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
- ts.tv_nsec = 0;
- ts.tv_sec = runtime·timediv(ns, 1000000000LL, (int32*)&ts.tv_nsec);
- runtime·futex(addr, FUTEX_WAIT, val, &ts, nil, 0);
-}
-
-static void badfutexwakeup(void);
-
-// If any procs are sleeping on addr, wake up at most cnt.
-#pragma textflag NOSPLIT
-void
-runtime·futexwakeup(uint32 *addr, uint32 cnt)
-{
- int64 ret;
- void (*fn)(void);
-
- ret = runtime·futex(addr, FUTEX_WAKE, cnt, nil, nil, 0);
- if(ret >= 0)
- return;
-
- // I don't know that futex wakeup can return
- // EAGAIN or EINTR, but if it does, it would be
- // safe to loop and call futex again.
- g->m->ptrarg[0] = addr;
- g->m->scalararg[0] = (int32)ret; // truncated but fine
- fn = badfutexwakeup;
- if(g == g->m->gsignal)
- fn();
- else
- runtime·onM(&fn);
- *(int32*)0x1006 = 0x1006;
-}
-
-static void
-badfutexwakeup(void)
-{
- void *addr;
- int64 ret;
-
- addr = g->m->ptrarg[0];
- ret = (int32)g->m->scalararg[0];
- runtime·printf("futexwakeup addr=%p returned %D\n", addr, ret);
-}
-
-extern runtime·sched_getaffinity(uintptr pid, uintptr len, uintptr *buf);
-static int32
-getproccount(void)
-{
- uintptr buf[16], t;
- int32 r, cnt, i;
-
- cnt = 0;
- r = runtime·sched_getaffinity(0, sizeof(buf), buf);
- if(r > 0)
- for(i = 0; i < r/sizeof(buf[0]); i++) {
- t = buf[i];
- t = t - ((t >> 1) & 0x5555555555555555ULL);
- t = (t & 0x3333333333333333ULL) + ((t >> 2) & 0x3333333333333333ULL);
- cnt += (int32)((((t + (t >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56);
- }
-
- return cnt ? cnt : 1;
-}
-
-// Clone, the Linux rfork.
-enum
-{
- CLONE_VM = 0x100,
- CLONE_FS = 0x200,
- CLONE_FILES = 0x400,
- CLONE_SIGHAND = 0x800,
- CLONE_PTRACE = 0x2000,
- CLONE_VFORK = 0x4000,
- CLONE_PARENT = 0x8000,
- CLONE_THREAD = 0x10000,
- CLONE_NEWNS = 0x20000,
- CLONE_SYSVSEM = 0x40000,
- CLONE_SETTLS = 0x80000,
- CLONE_PARENT_SETTID = 0x100000,
- CLONE_CHILD_CLEARTID = 0x200000,
- CLONE_UNTRACED = 0x800000,
- CLONE_CHILD_SETTID = 0x1000000,
- CLONE_STOPPED = 0x2000000,
- CLONE_NEWUTS = 0x4000000,
- CLONE_NEWIPC = 0x8000000,
-};
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
- int32 ret;
- int32 flags;
- Sigset oset;
-
- /*
- * note: strace gets confused if we use CLONE_PTRACE here.
- */
- flags = CLONE_VM /* share memory */
- | CLONE_FS /* share cwd, etc */
- | CLONE_FILES /* share fd table */
- | CLONE_SIGHAND /* share sig handler table */
- | CLONE_THREAD /* revisit - okay for now */
- ;
-
- mp->tls[0] = mp->id; // so 386 asm can find it
- if(0){
- runtime·printf("newosproc stk=%p m=%p g=%p clone=%p id=%d/%d ostk=%p\n",
- stk, mp, mp->g0, runtime·clone, mp->id, (int32)mp->tls[0], &mp);
- }
-
- // Disable signals during clone, so that the new thread starts
- // with signals disabled. It will enable them in minit.
- runtime·rtsigprocmask(SIG_SETMASK, &sigset_all, &oset, sizeof oset);
- ret = runtime·clone(flags, stk, mp, mp->g0, runtime·mstart);
- runtime·rtsigprocmask(SIG_SETMASK, &oset, nil, sizeof oset);
-
- if(ret < 0) {
- runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -ret);
- runtime·throw("runtime.newosproc");
- }
-}
-
-void
-runtime·osinit(void)
-{
- runtime·ncpu = getproccount();
-}
-
-// Random bytes initialized at startup. These come
-// from the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.c).
-byte* runtime·startup_random_data;
-uint32 runtime·startup_random_data_len;
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
- if(runtime·startup_random_data != nil) {
- *rnd = runtime·startup_random_data;
- *rnd_len = runtime·startup_random_data_len;
- } else {
- #pragma dataflag NOPTR
- static byte urandom_data[HashRandomBytes];
- int32 fd;
- fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
- if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
- *rnd = urandom_data;
- *rnd_len = HashRandomBytes;
- } else {
- *rnd = nil;
- *rnd_len = 0;
- }
- runtime·close(fd);
- }
-}
-
-void
-runtime·goenvs(void)
-{
- runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
- mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
- mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
- // Initialize signal handling.
- runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
- runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof(Sigset));
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
- runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
- Rlimit rl;
- extern byte runtime·text[], runtime·end[];
- uintptr used;
-
- if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
- return 0;
- if(rl.rlim_cur >= 0x7fffffff)
- return 0;
-
- // Estimate our VM footprint excluding the heap.
- // Not an exact science: use size of binary plus
- // some room for thread stacks.
- used = runtime·end - runtime·text + (64<<20);
- if(used >= rl.rlim_cur)
- return 0;
-
- // If there's not at least 16 MB left, we're probably
- // not going to be able to do much. Treat as no limit.
- rl.rlim_cur -= used;
- if(rl.rlim_cur < (16<<20))
- return 0;
-
- return rl.rlim_cur - used;
-}
-
-#ifdef GOARCH_386
-#define sa_handler k_sa_handler
-#endif
-
-/*
- * This assembler routine takes the args from registers, puts them on the stack,
- * and calls sighandler().
- */
-extern void runtime·sigtramp(void);
-extern void runtime·sigreturn(void); // calls rt_sigreturn, only used with SA_RESTORER
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask = ~0ULL;
- // Although Linux manpage says "sa_restorer element is obsolete and
- // should not be used". x86_64 kernel requires it. Only use it on
- // x86.
-#ifdef GOARCH_386
- sa.sa_restorer = (void*)runtime·sigreturn;
-#endif
-#ifdef GOARCH_amd64
- sa.sa_restorer = (void*)runtime·sigreturn;
-#endif
- if(fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.sa_handler = fn;
- if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0)
- runtime·throw("rt_sigaction failure");
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0)
- runtime·throw("rt_sigaction read failure");
- if((void*)sa.sa_handler == runtime·sigtramp)
- return runtime·sighandler;
- return (void*)sa.sa_handler;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- SigaltstackT st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
- runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof sigset_none);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
- return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go
index 41123ad57..113219aab 100644
--- a/src/runtime/os_linux.go
+++ b/src/runtime/os_linux.go
@@ -6,12 +6,28 @@ package runtime
import "unsafe"
+//go:noescape
func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32
+
+//go:noescape
func clone(flags int32, stk, mm, gg, fn unsafe.Pointer) int32
-func rt_sigaction(sig uintptr, new, old unsafe.Pointer, size uintptr) int32
-func sigaltstack(new, old unsafe.Pointer)
-func setitimer(mode int32, new, old unsafe.Pointer)
-func rtsigprocmask(sig int32, new, old unsafe.Pointer, size int32)
+
+//go:noescape
+func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
+
+//go:noescape
+func sigaltstack(new, old *sigaltstackt)
+
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+//go:noescape
+func rtsigprocmask(sig uint32, new, old *sigset, size int32)
+
+//go:noescape
func getrlimit(kind int32, limit unsafe.Pointer) int32
-func raise(sig int32)
+func raise(sig uint32)
+
+//go:noescape
func sched_getaffinity(pid, len uintptr, buf *uintptr) int32
+func osyield()
diff --git a/src/runtime/os_linux.h b/src/runtime/os_linux.h
deleted file mode 100644
index 75606d615..000000000
--- a/src/runtime/os_linux.h
+++ /dev/null
@@ -1,41 +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.
-
-
-// Linux-specific system calls
-int32 runtime·futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
-int32 runtime·clone(int32, void*, M*, G*, void(*)(void));
-
-struct SigactionT;
-int32 runtime·rt_sigaction(uintptr, struct SigactionT*, void*, uintptr);
-
-void runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-void runtime·sigpanic(void);
-void runtime·setitimer(int32, Itimerval*, Itimerval*);
-
-enum {
- SS_DISABLE = 2,
- NSIG = 65,
- SI_USER = 0,
- SIG_SETMASK = 2,
- RLIMIT_AS = 9,
-};
-
-// It's hard to tease out exactly how big a Sigset is, but
-// rt_sigprocmask crashes if we get it wrong, so if binaries
-// are running, this is right.
-typedef struct Sigset Sigset;
-struct Sigset
-{
- uint32 mask[2];
-};
-void runtime·rtsigprocmask(int32, Sigset*, Sigset*, int32);
-void runtime·unblocksignals(void);
-
-typedef struct Rlimit Rlimit;
-struct Rlimit {
- uintptr rlim_cur;
- uintptr rlim_max;
-};
-int32 runtime·getrlimit(int32, Rlimit*);
diff --git a/src/runtime/os_linux_386.c b/src/runtime/os_linux_386.c
deleted file mode 100644
index dc89d04e2..000000000
--- a/src/runtime/os_linux_386.c
+++ /dev/null
@@ -1,38 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "textflag.h"
-
-#define AT_NULL 0
-#define AT_RANDOM 25
-#define AT_SYSINFO 32
-extern uint32 runtime·_vdso;
-
-#pragma textflag NOSPLIT
-void
-runtime·linux_setup_vdso(int32 argc, byte **argv)
-{
- byte **envp;
- uint32 *auxv;
-
- // skip envp to get to ELF auxiliary vector.
- for(envp = &argv[argc+1]; *envp != nil; envp++)
- ;
- envp++;
-
- for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
- if(auxv[0] == AT_SYSINFO) {
- runtime·_vdso = auxv[1];
- continue;
- }
- if(auxv[0] == AT_RANDOM) {
- runtime·startup_random_data = (byte*)auxv[1];
- runtime·startup_random_data_len = 16;
- continue;
- }
- }
-}
diff --git a/src/runtime/os_linux_386.go b/src/runtime/os_linux_386.go
new file mode 100644
index 000000000..c4f95804a
--- /dev/null
+++ b/src/runtime/os_linux_386.go
@@ -0,0 +1,37 @@
+// 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 runtime
+
+import "unsafe"
+
+const (
+ _AT_NULL = 0
+ _AT_RANDOM = 25
+ _AT_SYSINFO = 32
+)
+
+var _vdso uint32
+
+//go:nosplit
+func linux_setup_vdso(argc int32, argv **byte) {
+ // skip over argv, envv to get to auxv
+ n := argc + 1
+ for argv_index(argv, n) != nil {
+ n++
+ }
+ n++
+ auxv := (*[1 << 28]uint32)(add(unsafe.Pointer(argv), uintptr(n)*ptrSize))
+
+ for i := 0; auxv[i] != _AT_NULL; i += 2 {
+ switch auxv[i] {
+ case _AT_SYSINFO:
+ _vdso = auxv[i+1]
+
+ case _AT_RANDOM:
+ startup_random_data = (*byte)(unsafe.Pointer(uintptr(auxv[i+1])))
+ startup_random_data_len = 16
+ }
+ }
+}
diff --git a/src/runtime/os_linux_arm.c b/src/runtime/os_linux_arm.c
deleted file mode 100644
index e3eda7c2d..000000000
--- a/src/runtime/os_linux_arm.c
+++ /dev/null
@@ -1,80 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "textflag.h"
-
-#define AT_NULL 0
-#define AT_PLATFORM 15 // introduced in at least 2.6.11
-#define AT_HWCAP 16 // introduced in at least 2.6.11
-#define AT_RANDOM 25 // introduced in 2.6.29
-#define HWCAP_VFP (1 << 6) // introduced in at least 2.6.11
-#define HWCAP_VFPv3 (1 << 13) // introduced in 2.6.30
-static uint32 runtime·randomNumber;
-uint8 runtime·armArch = 6; // we default to ARMv6
-uint32 runtime·hwcap; // set by setup_auxv
-extern uint8 runtime·goarm; // set by 5l
-
-void
-runtime·checkgoarm(void)
-{
- if(runtime·goarm > 5 && !(runtime·hwcap & HWCAP_VFP)) {
- runtime·printf("runtime: this CPU has no floating point hardware, so it cannot run\n");
- runtime·printf("this GOARM=%d binary. Recompile using GOARM=5.\n", runtime·goarm);
- runtime·exit(1);
- }
- if(runtime·goarm > 6 && !(runtime·hwcap & HWCAP_VFPv3)) {
- runtime·printf("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n");
- runtime·printf("this GOARM=%d binary. Recompile using GOARM=6.\n", runtime·goarm);
- runtime·exit(1);
- }
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·setup_auxv(int32 argc, byte **argv)
-{
- byte **envp;
- byte *rnd;
- uint32 *auxv;
- uint32 t;
-
- // skip envp to get to ELF auxiliary vector.
- for(envp = &argv[argc+1]; *envp != nil; envp++)
- ;
- envp++;
-
- for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
- switch(auxv[0]) {
- case AT_RANDOM: // kernel provided 16-byte worth of random data
- if(auxv[1]) {
- rnd = (byte*)auxv[1];
- runtime·randomNumber = rnd[4] | rnd[5]<<8 | rnd[6]<<16 | rnd[7]<<24;
- }
- break;
- case AT_PLATFORM: // v5l, v6l, v7l
- if(auxv[1]) {
- t = *(uint8*)(auxv[1]+1);
- if(t >= '5' && t <= '7')
- runtime·armArch = t - '0';
- }
- break;
- case AT_HWCAP: // CPU capability bit flags
- runtime·hwcap = auxv[1];
- break;
- }
- }
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·cputicks(void)
-{
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
- // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // runtime·randomNumber provides better seeding of fastrand1.
- return runtime·nanotime() + runtime·randomNumber;
-}
diff --git a/src/runtime/os_linux_arm.go b/src/runtime/os_linux_arm.go
new file mode 100644
index 000000000..d5b37d6ab
--- /dev/null
+++ b/src/runtime/os_linux_arm.go
@@ -0,0 +1,78 @@
+// 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.
+
+// 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 runtime
+
+import "unsafe"
+
+const (
+ _AT_NULL = 0
+ _AT_PLATFORM = 15 // introduced in at least 2.6.11
+ _AT_HWCAP = 16 // introduced in at least 2.6.11
+ _AT_RANDOM = 25 // introduced in 2.6.29
+
+ _HWCAP_VFP = 1 << 6 // introduced in at least 2.6.11
+ _HWCAP_VFPv3 = 1 << 13 // introduced in 2.6.30
+)
+
+var randomNumber uint32
+var armArch uint8 = 6 // we default to ARMv6
+var hwcap uint32 // set by setup_auxv
+var goarm uint8 // set by 5l
+
+func checkgoarm() {
+ if goarm > 5 && hwcap&_HWCAP_VFP == 0 {
+ print("runtime: this CPU has no floating point hardware, so it cannot run\n")
+ print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n")
+ exit(1)
+ }
+ if goarm > 6 && hwcap&_HWCAP_VFPv3 == 0 {
+ print("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n")
+ print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n")
+ exit(1)
+ }
+}
+
+//go:nosplit
+func setup_auxv(argc int32, argv **byte) {
+ // skip over argv, envv to get to auxv
+ n := argc + 1
+ for argv_index(argv, n) != nil {
+ n++
+ }
+ n++
+ auxv := (*[1 << 28]uint32)(add(unsafe.Pointer(argv), uintptr(n)*ptrSize))
+
+ for i := 0; auxv[i] != _AT_NULL; i += 2 {
+ switch auxv[i] {
+ case _AT_RANDOM: // kernel provides a pointer to 16-bytes worth of random data
+ if auxv[i+1] != 0 {
+ // the pointer provided may not be word alined, so we must to treat it
+ // as a byte array.
+ rnd := (*[16]byte)(unsafe.Pointer(uintptr(auxv[i+1])))
+ randomNumber = uint32(rnd[0]) | uint32(rnd[1])<<8 | uint32(rnd[2])<<16 | uint32(rnd[3])<<24
+ }
+
+ case _AT_PLATFORM: // v5l, v6l, v7l
+ t := *(*uint8)(unsafe.Pointer(uintptr(auxv[i+1] + 1)))
+ if '5' <= t && t <= '7' {
+ armArch = t - '0'
+ }
+
+ case _AT_HWCAP: // CPU capability bit flags
+ hwcap = auxv[i+1]
+ }
+ }
+}
+
+func cputicks() int64 {
+ // Currently cputicks() is used in blocking profiler and to seed fastrand1().
+ // nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+ // randomNumber provides better seeding of fastrand1.
+ return nanotime() + int64(randomNumber)
+}
diff --git a/src/runtime/os_nacl.c b/src/runtime/os_nacl.c
deleted file mode 100644
index 14b558303..000000000
--- a/src/runtime/os_nacl.c
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "arch_GOARCH.h"
-#include "textflag.h"
-#include "stack.h"
-
-int8 *goos = "nacl";
-extern SigTab runtime·sigtab[];
-
-void runtime·sigtramp(void);
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
- mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
- mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
- int32 ret;
-
- // Initialize signal handling
- ret = runtime·nacl_exception_stack((byte*)g->m->gsignal->stack.lo, 32*1024);
- if(ret < 0)
- runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret);
-
- ret = runtime·nacl_exception_handler(runtime·sigtramp, nil);
- if(ret < 0)
- runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-}
-
-int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n";
-int8 runtime·sigtrampp[] = "runtime: sigtramp";
-
-extern byte runtime·tls0[];
-
-void
-runtime·osinit(void)
-{
- runtime·ncpu = 1;
- g->m->procid = 2;
-//runtime·nacl_exception_handler(runtime·sigtramp, nil);
-}
-
-void
-runtime·crash(void)
-{
- *(int32*)0 = 0;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
- *rnd = nil;
- *rnd_len = 0;
-}
-
-void
-runtime·goenvs(void)
-{
- runtime·goenvs_unix();
-}
-
-void
-runtime·initsig(void)
-{
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·usleep(uint32 us)
-{
- Timespec ts;
-
- ts.tv_sec = us/1000000;
- ts.tv_nsec = (us%1000000)*1000;
- runtime·nacl_nanosleep(&ts, nil);
-}
-
-void runtime·mstart_nacl(void);
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
- int32 ret;
- void **tls;
-
- tls = (void**)mp->tls;
- tls[0] = mp->g0;
- tls[1] = mp;
- ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0);
- if(ret < 0) {
- runtime·printf("nacl_thread_create: error %d\n", -ret);
- runtime·throw("newosproc");
- }
-}
-
-static void
-semacreate(void)
-{
- int32 mu, cond;
-
- mu = runtime·nacl_mutex_create(0);
- if(mu < 0) {
- runtime·printf("nacl_mutex_create: error %d\n", -mu);
- runtime·throw("semacreate");
- }
- cond = runtime·nacl_cond_create(0);
- if(cond < 0) {
- runtime·printf("nacl_cond_create: error %d\n", -cond);
- runtime·throw("semacreate");
- }
- g->m->waitsemalock = mu;
- g->m->scalararg[0] = cond; // assigned to m->waitsema
-}
-
-#pragma textflag NOSPLIT
-uint32
-runtime·semacreate(void)
-{
- void (*fn)(void);
- uint32 x;
-
- fn = semacreate;
- runtime·onM(&fn);
- x = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
- return x;
-}
-
-static void
-semasleep(void)
-{
- int32 ret;
- int64 ns;
-
- ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
- g->m->scalararg[0] = 0;
- g->m->scalararg[1] = 0;
-
- ret = runtime·nacl_mutex_lock(g->m->waitsemalock);
- if(ret < 0) {
- //runtime·printf("nacl_mutex_lock: error %d\n", -ret);
- runtime·throw("semasleep");
- }
- if(g->m->waitsemacount > 0) {
- g->m->waitsemacount = 0;
- runtime·nacl_mutex_unlock(g->m->waitsemalock);
- g->m->scalararg[0] = 0;
- return;
- }
-
- while(g->m->waitsemacount == 0) {
- if(ns < 0) {
- ret = runtime·nacl_cond_wait(g->m->waitsema, g->m->waitsemalock);
- if(ret < 0) {
- //runtime·printf("nacl_cond_wait: error %d\n", -ret);
- runtime·throw("semasleep");
- }
- } else {
- Timespec ts;
-
- ns += runtime·nanotime();
- ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
- ret = runtime·nacl_cond_timed_wait_abs(g->m->waitsema, g->m->waitsemalock, &ts);
- if(ret == -ETIMEDOUT) {
- runtime·nacl_mutex_unlock(g->m->waitsemalock);
- g->m->scalararg[0] = -1;
- return;
- }
- if(ret < 0) {
- //runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret);
- runtime·throw("semasleep");
- }
- }
- }
-
- g->m->waitsemacount = 0;
- runtime·nacl_mutex_unlock(g->m->waitsemalock);
- g->m->scalararg[0] = 0;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
- int32 r;
- void (*fn)(void);
-
- g->m->scalararg[0] = (uint32)ns;
- g->m->scalararg[1] = (uint32)(ns>>32);
- fn = semasleep;
- runtime·onM(&fn);
- r = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
- return r;
-}
-
-static void
-semawakeup(void)
-{
- int32 ret;
- M *mp;
-
- mp = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
-
- ret = runtime·nacl_mutex_lock(mp->waitsemalock);
- if(ret < 0) {
- //runtime·printf("nacl_mutex_lock: error %d\n", -ret);
- runtime·throw("semawakeup");
- }
- if(mp->waitsemacount != 0) {
- //runtime·printf("semawakeup: double wakeup\n");
- runtime·throw("semawakeup");
- }
- mp->waitsemacount = 1;
- runtime·nacl_cond_signal(mp->waitsema);
- runtime·nacl_mutex_unlock(mp->waitsemalock);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
- void (*fn)(void);
-
- g->m->ptrarg[0] = mp;
- fn = semawakeup;
- runtime·onM(&fn);
-}
-
-uintptr
-runtime·memlimit(void)
-{
- runtime·printf("memlimit\n");
- return 0;
-}
-
-#pragma dataflag NOPTR
-static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-#pragma textflag NOSPLIT
-void
-runtime·badsignal2(void)
-{
- runtime·write(2, badsignal, sizeof badsignal - 1);
- runtime·exit(2);
-}
-
-void runtime·madvise(byte*, uintptr, int32) { }
-void runtime·munmap(byte*, uintptr) {}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- USED(hz);
-}
-
-void
-runtime·sigdisable(uint32)
-{
-}
-
-void
-runtime·sigenable(uint32)
-{
-}
-
-void
-runtime·closeonexec(int32)
-{
-}
-
-uint32 runtime·writelock; // test-and-set spin lock for runtime.write
-
-/*
-An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
-
-void (*runtime·nacl_irt_query)(void);
-
-int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
-void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
-int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1);
-
-int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
-void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
-int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3);
-
-int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
-void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
-int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1);
-*/
diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go
index 8dd43ff06..eff9ec30e 100644
--- a/src/runtime/os_nacl.go
+++ b/src/runtime/os_nacl.go
@@ -6,8 +6,8 @@ package runtime
import "unsafe"
-func nacl_exception_stack(p unsafe.Pointer, size int32) int32
-func nacl_exception_handler(fn, arg unsafe.Pointer) int32
+func nacl_exception_stack(p uintptr, size int32) int32
+func nacl_exception_handler(fn uintptr, arg unsafe.Pointer) int32
func nacl_sem_create(flag int32) int32
func nacl_sem_wait(sem int32) int32
func nacl_sem_post(sem int32) int32
@@ -19,9 +19,20 @@ func nacl_cond_create(flag int32) int32
func nacl_cond_wait(cond, n int32) int32
func nacl_cond_signal(cond int32) int32
func nacl_cond_broadcast(cond int32) int32
-func nacl_cond_timed_wait_abs(cond, lock int32, ts unsafe.Pointer) int32
-func nacl_thread_create(fn, stk, tls, xx unsafe.Pointer) int32
-func nacl_nanosleep(ts, extra unsafe.Pointer) int32
+
+//go:noescape
+func nacl_cond_timed_wait_abs(cond, lock int32, ts *timespec) int32
+func nacl_thread_create(fn uintptr, stk, tls, xx unsafe.Pointer) int32
+
+//go:noescape
+func nacl_nanosleep(ts, extra *timespec) int32
+func nanotime() int64
+func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
+func exit(code int32)
+func osyield()
+
+//go:noescape
+func write(fd uintptr, p unsafe.Pointer, n int32) int32
func os_sigpipe() {
gothrow("too many writes on closed pipe")
diff --git a/src/runtime/os_nacl.h b/src/runtime/os_nacl.h
deleted file mode 100644
index 7c9d9c242..000000000
--- a/src/runtime/os_nacl.h
+++ /dev/null
@@ -1,162 +0,0 @@
-enum {
- NSIG = 32,
- SI_USER = 1,
-
- // native_client/src/trusted/service_runtime/include/sys/errno.h
- // The errors are mainly copied from Linux.
- EPERM = 1, /* Operation not permitted */
- ENOENT = 2, /* No such file or directory */
- ESRCH = 3, /* No such process */
- EINTR = 4, /* Interrupted system call */
- EIO = 5, /* I/O error */
- ENXIO = 6, /* No such device or address */
- E2BIG = 7, /* Argument list too long */
- ENOEXEC = 8, /* Exec format error */
- EBADF = 9, /* Bad file number */
- ECHILD = 10, /* No child processes */
- EAGAIN = 11, /* Try again */
- ENOMEM = 12, /* Out of memory */
- EACCES = 13, /* Permission denied */
- EFAULT = 14, /* Bad address */
- EBUSY = 16, /* Device or resource busy */
- EEXIST = 17, /* File exists */
- EXDEV = 18, /* Cross-device link */
- ENODEV = 19, /* No such device */
- ENOTDIR = 20, /* Not a directory */
- EISDIR = 21, /* Is a directory */
- EINVAL = 22, /* Invalid argument */
- ENFILE = 23, /* File table overflow */
- EMFILE = 24, /* Too many open files */
- ENOTTY = 25, /* Not a typewriter */
- EFBIG = 27, /* File too large */
- ENOSPC = 28, /* No space left on device */
- ESPIPE = 29, /* Illegal seek */
- EROFS = 30, /* Read-only file system */
- EMLINK = 31, /* Too many links */
- EPIPE = 32, /* Broken pipe */
- ENAMETOOLONG = 36, /* File name too long */
- ENOSYS = 38, /* Function not implemented */
- EDQUOT = 122, /* Quota exceeded */
- EDOM = 33, /* Math arg out of domain of func */
- ERANGE = 34, /* Math result not representable */
- EDEADLK = 35, /* Deadlock condition */
- ENOLCK = 37, /* No record locks available */
- ENOTEMPTY = 39, /* Directory not empty */
- ELOOP = 40, /* Too many symbolic links */
- ENOMSG = 42, /* No message of desired type */
- EIDRM = 43, /* Identifier removed */
- ECHRNG = 44, /* Channel number out of range */
- EL2NSYNC = 45, /* Level 2 not synchronized */
- EL3HLT = 46, /* Level 3 halted */
- EL3RST = 47, /* Level 3 reset */
- ELNRNG = 48, /* Link number out of range */
- EUNATCH = 49, /* Protocol driver not attached */
- ENOCSI = 50, /* No CSI structure available */
- EL2HLT = 51, /* Level 2 halted */
- EBADE = 52, /* Invalid exchange */
- EBADR = 53, /* Invalid request descriptor */
- EXFULL = 54, /* Exchange full */
- ENOANO = 55, /* No anode */
- EBADRQC = 56, /* Invalid request code */
- EBADSLT = 57, /* Invalid slot */
- EDEADLOCK = EDEADLK, /* File locking deadlock error */
- EBFONT = 59, /* Bad font file fmt */
- ENOSTR = 60, /* Device not a stream */
- ENODATA = 61, /* No data (for no delay io) */
- ETIME = 62, /* Timer expired */
- ENOSR = 63, /* Out of streams resources */
- ENONET = 64, /* Machine is not on the network */
- ENOPKG = 65, /* Package not installed */
- EREMOTE = 66, /* The object is remote */
- ENOLINK = 67, /* The link has been severed */
- EADV = 68, /* Advertise error */
- ESRMNT = 69, /* Srmount error */
- ECOMM = 70, /* Communication error on send */
- EPROTO = 71, /* Protocol error */
- EMULTIHOP = 72, /* Multihop attempted */
- EDOTDOT = 73, /* Cross mount point (not really error) */
- EBADMSG = 74, /* Trying to read unreadable message */
- EOVERFLOW = 75, /* Value too large for defined data type */
- ENOTUNIQ = 76, /* Given log. name not unique */
- EBADFD = 77, /* f.d. invalid for this operation */
- EREMCHG = 78, /* Remote address changed */
- ELIBACC = 79, /* Can't access a needed shared lib */
- ELIBBAD = 80, /* Accessing a corrupted shared lib */
- ELIBSCN = 81, /* .lib section in a.out corrupted */
- ELIBMAX = 82, /* Attempting to link in too many libs */
- ELIBEXEC = 83, /* Attempting to exec a shared library */
- EILSEQ = 84,
- EUSERS = 87,
- ENOTSOCK = 88, /* Socket operation on non-socket */
- EDESTADDRREQ = 89, /* Destination address required */
- EMSGSIZE = 90, /* Message too long */
- EPROTOTYPE = 91, /* Protocol wrong type for socket */
- ENOPROTOOPT = 92, /* Protocol not available */
- EPROTONOSUPPORT = 93, /* Unknown protocol */
- ESOCKTNOSUPPORT = 94, /* Socket type not supported */
- EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */
- EPFNOSUPPORT = 96, /* Protocol family not supported */
- EAFNOSUPPORT = 97, /* Address family not supported by protocol family */
- EADDRINUSE = 98, /* Address already in use */
- EADDRNOTAVAIL = 99, /* Address not available */
- ENETDOWN = 100, /* Network interface is not configured */
- ENETUNREACH = 101, /* Network is unreachable */
- ENETRESET = 102,
- ECONNABORTED = 103, /* Connection aborted */
- ECONNRESET = 104, /* Connection reset by peer */
- ENOBUFS = 105, /* No buffer space available */
- EISCONN = 106, /* Socket is already connected */
- ENOTCONN = 107, /* Socket is not connected */
- ESHUTDOWN = 108, /* Can't send after socket shutdown */
- ETOOMANYREFS = 109,
- ETIMEDOUT = 110, /* Connection timed out */
- ECONNREFUSED = 111, /* Connection refused */
- EHOSTDOWN = 112, /* Host is down */
- EHOSTUNREACH = 113, /* Host is unreachable */
- EALREADY = 114, /* Socket already connected */
- EINPROGRESS = 115, /* Connection already in progress */
- ESTALE = 116,
- ENOTSUP = EOPNOTSUPP, /* Not supported */
- ENOMEDIUM = 123, /* No medium (in tape drive) */
- ECANCELED = 125, /* Operation canceled. */
- ELBIN = 2048, /* Inode is remote (not really error) */
- EFTYPE = 2049, /* Inappropriate file type or format */
- ENMFILE = 2050, /* No more files */
- EPROCLIM = 2051,
- ENOSHARE = 2052, /* No such host or network path */
- ECASECLASH = 2053, /* Filename exists with different case */
- EWOULDBLOCK = EAGAIN, /* Operation would block */
-
- // native_client/src/trusted/service_runtime/include/bits/mman.h.
- // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h.
- // Those MAP_*values are different from these.
- PROT_NONE = 0x0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
-
- MAP_SHARED = 0x1,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
- MAP_ANON = 0x20,
-};
-typedef byte* kevent_udata;
-
-int32 runtime·nacl_exception_stack(byte*, int32);
-int32 runtime·nacl_exception_handler(void*, void*);
-int32 runtime·nacl_sem_create(int32);
-int32 runtime·nacl_sem_wait(int32);
-int32 runtime·nacl_sem_post(int32);
-int32 runtime·nacl_mutex_create(int32);
-int32 runtime·nacl_mutex_lock(int32);
-int32 runtime·nacl_mutex_trylock(int32);
-int32 runtime·nacl_mutex_unlock(int32);
-int32 runtime·nacl_cond_create(int32);
-int32 runtime·nacl_cond_wait(int32, int32);
-int32 runtime·nacl_cond_signal(int32);
-int32 runtime·nacl_cond_broadcast(int32);
-int32 runtime·nacl_cond_timed_wait_abs(int32, int32, Timespec*);
-int32 runtime·nacl_thread_create(void*, void*, void*, void*);
-int32 runtime·nacl_nanosleep(Timespec*, Timespec*);
-
-void runtime·sigpanic(void);
diff --git a/src/runtime/os_nacl_arm.c b/src/runtime/os_nacl_arm.go
index 1248ea644..a43e7c47b 100644
--- a/src/runtime/os_nacl_arm.c
+++ b/src/runtime/os_nacl_arm.go
@@ -2,23 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "textflag.h"
+package runtime
-void
-runtime·checkgoarm(void)
-{
- return; // NaCl/ARM only supports ARMv7
+func checkgoarm() {
+ return // NaCl/ARM only supports ARMv7
}
-#pragma textflag NOSPLIT
-int64
-runtime·cputicks(void)
-{
+//go:nosplit
+func cputicks() int64 {
// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
// TODO: need more entropy to better seed fastrand1.
- return runtime·nanotime();
+ return nanotime()
}
diff --git a/src/runtime/os_netbsd.c b/src/runtime/os_netbsd.c
deleted file mode 100644
index 58e5bedf2..000000000
--- a/src/runtime/os_netbsd.c
+++ /dev/null
@@ -1,368 +0,0 @@
-// Copyright 2011 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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-enum
-{
- ESRCH = 3,
- ENOTSUP = 91,
-
- // From NetBSD's <sys/time.h>
- CLOCK_REALTIME = 0,
- CLOCK_VIRTUAL = 1,
- CLOCK_PROF = 2,
- CLOCK_MONOTONIC = 3
-};
-
-extern SigTab runtime·sigtab[];
-
-static Sigset sigset_none;
-static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
-
-extern void runtime·getcontext(UcontextT *context);
-extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid);
-extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void));
-extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint);
-extern int32 runtime·lwp_unpark(int32 lwp, void *hint);
-extern int32 runtime·lwp_self(void);
-
-// From NetBSD's <sys/sysctl.h>
-#define CTL_HW 6
-#define HW_NCPU 3
-
-static int32
-getncpu(void)
-{
- uint32 mib[2];
- uint32 out;
- int32 ret;
- uintptr nout;
-
- // Fetch hw.ncpu via sysctl.
- mib[0] = CTL_HW;
- mib[1] = HW_NCPU;
- nout = sizeof out;
- out = 0;
- ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
- if(ret >= 0)
- return out;
- else
- return 1;
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
- return 1;
-}
-
-static void
-semasleep(void)
-{
- int64 ns;
- Timespec ts;
-
- ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
- g->m->scalararg[0] = 0;
- g->m->scalararg[1] = 0;
-
- // spin-mutex lock
- while(runtime·xchg(&g->m->waitsemalock, 1))
- runtime·osyield();
-
- for(;;) {
- // lock held
- if(g->m->waitsemacount == 0) {
- // sleep until semaphore != 0 or timeout.
- // thrsleep unlocks m->waitsemalock.
- if(ns < 0) {
- // TODO(jsing) - potential deadlock!
- //
- // There is a potential deadlock here since we
- // have to release the waitsemalock mutex
- // before we call lwp_park() to suspend the
- // thread. This allows another thread to
- // release the lock and call lwp_unpark()
- // before the thread is actually suspended.
- // If this occurs the current thread will end
- // up sleeping indefinitely. Unfortunately
- // the NetBSD kernel does not appear to provide
- // a mechanism for unlocking the userspace
- // mutex once the thread is actually parked.
- runtime·atomicstore(&g->m->waitsemalock, 0);
- runtime·lwp_park(nil, 0, &g->m->waitsemacount, nil);
- } else {
- ns = ns + runtime·nanotime();
- // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
- ts.tv_nsec = 0;
- ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
- // TODO(jsing) - potential deadlock!
- // See above for details.
- runtime·atomicstore(&g->m->waitsemalock, 0);
- runtime·lwp_park(&ts, 0, &g->m->waitsemacount, nil);
- }
- // reacquire lock
- while(runtime·xchg(&g->m->waitsemalock, 1))
- runtime·osyield();
- }
-
- // lock held (again)
- if(g->m->waitsemacount != 0) {
- // semaphore is available.
- g->m->waitsemacount--;
- // spin-mutex unlock
- runtime·atomicstore(&g->m->waitsemalock, 0);
- g->m->scalararg[0] = 0; // semaphore acquired
- return;
- }
-
- // semaphore not available.
- // if there is a timeout, stop now.
- // otherwise keep trying.
- if(ns >= 0)
- break;
- }
-
- // lock held but giving up
- // spin-mutex unlock
- runtime·atomicstore(&g->m->waitsemalock, 0);
- g->m->scalararg[0] = -1;
- return;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
- int32 r;
- void (*fn)(void);
-
- g->m->scalararg[0] = (uint32)ns;
- g->m->scalararg[1] = (uint32)(ns>>32);
- fn = semasleep;
- runtime·onM(&fn);
- r = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
- return r;
-}
-
-static void badsemawakeup(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
- uint32 ret;
- void (*fn)(void);
- void *oldptr;
- uintptr oldscalar;
-
- // spin-mutex lock
- while(runtime·xchg(&mp->waitsemalock, 1))
- runtime·osyield();
- mp->waitsemacount++;
- // TODO(jsing) - potential deadlock, see semasleep() for details.
- // Confirm that LWP is parked before unparking...
- ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount);
- if(ret != 0 && ret != ESRCH) {
- // semawakeup can be called on signal stack.
- // Save old ptrarg/scalararg so we can restore them.
- oldptr = g->m->ptrarg[0];
- oldscalar = g->m->scalararg[0];
- g->m->ptrarg[0] = mp;
- g->m->scalararg[0] = ret;
- fn = badsemawakeup;
- if(g == g->m->gsignal)
- fn();
- else
- runtime·onM(&fn);
- g->m->ptrarg[0] = oldptr;
- g->m->scalararg[0] = oldscalar;
- }
- // spin-mutex unlock
- runtime·atomicstore(&mp->waitsemalock, 0);
-}
-
-static void
-badsemawakeup(void)
-{
- M *mp;
- int32 ret;
-
- mp = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- ret = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
-
- runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
-}
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
- UcontextT uc;
- int32 ret;
-
- if(0) {
- runtime·printf(
- "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
- stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
- }
-
- mp->tls[0] = mp->id; // so 386 asm can find it
-
- runtime·getcontext(&uc);
-
- uc.uc_flags = _UC_SIGMASK | _UC_CPU;
- uc.uc_link = nil;
- uc.uc_sigmask = sigset_all;
-
- runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart);
-
- ret = runtime·lwp_create(&uc, 0, &mp->procid);
-
- if(ret < 0) {
- runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
- runtime·throw("runtime.newosproc");
- }
-}
-
-void
-runtime·osinit(void)
-{
- runtime·ncpu = getncpu();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
- #pragma dataflag NOPTR
- static byte urandom_data[HashRandomBytes];
- int32 fd;
- fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
- if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
- *rnd = urandom_data;
- *rnd_len = HashRandomBytes;
- } else {
- *rnd = nil;
- *rnd_len = 0;
- }
- runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
- runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
- mp->gsignal = runtime·malg(32*1024);
- mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
- g->m->procid = runtime·lwp_self();
-
- // Initialize signal handling
- runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
- runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
- runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
- return 0;
-}
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*_sa_handler)(int32);
- void (*_sa_sigaction)(int32, Siginfo*, void *);
- } _sa_u; /* signal handler */
- uint32 sa_mask[4]; /* signal mask to apply */
- int32 sa_flags; /* see signal options below */
-} SigactionT;
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask[0] = ~0U;
- sa.sa_mask[1] = ~0U;
- sa.sa_mask[2] = ~0U;
- sa.sa_mask[3] = ~0U;
- if (fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa._sa_u._sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp)
- return runtime·sighandler;
- return (void*)sa._sa_u._sa_sigaction;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- StackT st;
-
- st.ss_sp = (void*)p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
- runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
- return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index f000c5e9f..a153bf2eb 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -6,15 +6,37 @@ package runtime
import "unsafe"
-func setitimer(mode int32, new, old unsafe.Pointer)
-func sigaction(sig int32, new, old unsafe.Pointer)
-func sigaltstack(new, old unsafe.Pointer)
-func sigprocmask(mode int32, new, old unsafe.Pointer)
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+//go:noescape
+func sigaction(sig int32, new, old *sigactiont)
+
+//go:noescape
+func sigaltstack(new, old *sigaltstackt)
+
+//go:noescape
+func sigprocmask(mode int32, new, old *sigset)
+
+//go:noescape
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
+
func lwp_tramp()
+
func raise(sig int32)
+
+//go:noescape
func getcontext(ctxt unsafe.Pointer)
+
+//go:noescape
func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32
-func lwp_park(abstime unsafe.Pointer, unpark int32, hint, unparkhint unsafe.Pointer) int32
+
+//go:noescape
+func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32
+
+//go:noescape
func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
+
func lwp_self() int32
+
+func osyield()
diff --git a/src/runtime/os_netbsd.h b/src/runtime/os_netbsd.h
deleted file mode 100644
index f95db325f..000000000
--- a/src/runtime/os_netbsd.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2010 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 uintptr kevent_udata;
-
-struct sigaction;
-
-void runtime·sigpanic(void);
-
-void runtime·setitimer(int32, Itimerval*, Itimerval*);
-void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
-void runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-void runtime·sigprocmask(int32, Sigset*, Sigset*);
-void runtime·unblocksignals(void);
-int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-extern void runtime·lwp_tramp(void);
-
-enum {
- SS_DISABLE = 4,
- SIG_BLOCK = 1,
- SIG_UNBLOCK = 2,
- SIG_SETMASK = 3,
- NSIG = 33,
- SI_USER = 0,
-
- // From NetBSD's <sys/ucontext.h>
- _UC_SIGMASK = 0x01,
- _UC_CPU = 0x04,
-};
diff --git a/src/runtime/os_netbsd_386.c b/src/runtime/os_netbsd_386.c
deleted file mode 100644
index 23e9db3c1..000000000
--- a/src/runtime/os_netbsd_386.c
+++ /dev/null
@@ -1,17 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-void
-runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
-{
- mc->__gregs[REG_EIP] = (uint32)runtime·lwp_tramp;
- mc->__gregs[REG_UESP] = (uint32)stack;
- mc->__gregs[REG_EBX] = (uint32)mp;
- mc->__gregs[REG_EDX] = (uint32)gp;
- mc->__gregs[REG_ESI] = (uint32)fn;
-}
diff --git a/src/runtime/os_netbsd_amd64.c b/src/runtime/os_netbsd_amd64.c
deleted file mode 100644
index 226846cbb..000000000
--- a/src/runtime/os_netbsd_amd64.c
+++ /dev/null
@@ -1,18 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-void
-runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
-{
- // Machine dependent mcontext initialisation for LWP.
- mc->__gregs[REG_RIP] = (uint64)runtime·lwp_tramp;
- mc->__gregs[REG_RSP] = (uint64)stack;
- mc->__gregs[REG_R8] = (uint64)mp;
- mc->__gregs[REG_R9] = (uint64)gp;
- mc->__gregs[REG_R12] = (uint64)fn;
-}
diff --git a/src/runtime/os_openbsd.c b/src/runtime/os_openbsd.c
deleted file mode 100644
index eebaa13ee..000000000
--- a/src/runtime/os_openbsd.c
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright 2011 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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-enum
-{
- ESRCH = 3,
- EAGAIN = 35,
- EWOULDBLOCK = EAGAIN,
- ENOTSUP = 91,
-
- // From OpenBSD's sys/time.h
- CLOCK_REALTIME = 0,
- CLOCK_VIRTUAL = 1,
- CLOCK_PROF = 2,
- CLOCK_MONOTONIC = 3
-};
-
-extern SigTab runtime·sigtab[];
-
-static Sigset sigset_none;
-static Sigset sigset_all = ~(Sigset)0;
-
-extern int32 runtime·tfork(TforkT *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
-extern int32 runtime·thrsleep(void *ident, int32 clock_id, void *tsp, void *lock, const int32 *abort);
-extern int32 runtime·thrwakeup(void *ident, int32 n);
-
-// From OpenBSD's <sys/sysctl.h>
-#define CTL_HW 6
-#define HW_NCPU 3
-
-static int32
-getncpu(void)
-{
- uint32 mib[2];
- uint32 out;
- int32 ret;
- uintptr nout;
-
- // Fetch hw.ncpu via sysctl.
- mib[0] = CTL_HW;
- mib[1] = HW_NCPU;
- nout = sizeof out;
- out = 0;
- ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
- if(ret >= 0)
- return out;
- else
- return 1;
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
- return 1;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
- Timespec ts, *tsp = nil;
-
- // Compute sleep deadline.
- if(ns >= 0) {
- int32 nsec;
- ns += runtime·nanotime();
- ts.tv_sec = runtime·timediv(ns, 1000000000, &nsec);
- ts.tv_nsec = nsec; // tv_nsec is int64 on amd64
- tsp = &ts;
- }
-
- for(;;) {
- int32 ret;
-
- // spin-mutex lock
- while(runtime·xchg(&g->m->waitsemalock, 1))
- runtime·osyield();
-
- if(g->m->waitsemacount != 0) {
- // semaphore is available.
- g->m->waitsemacount--;
- // spin-mutex unlock
- runtime·atomicstore(&g->m->waitsemalock, 0);
- return 0; // semaphore acquired
- }
-
- // sleep until semaphore != 0 or timeout.
- // thrsleep unlocks m->waitsemalock.
- ret = runtime·thrsleep(&g->m->waitsemacount, CLOCK_MONOTONIC, tsp, &g->m->waitsemalock, (int32 *)&g->m->waitsemacount);
- if(ret == EWOULDBLOCK)
- return -1;
- }
-}
-
-static void badsemawakeup(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
- uint32 ret;
- void *oldptr;
- uint32 oldscalar;
- void (*fn)(void);
-
- // spin-mutex lock
- while(runtime·xchg(&mp->waitsemalock, 1))
- runtime·osyield();
- mp->waitsemacount++;
- ret = runtime·thrwakeup(&mp->waitsemacount, 1);
- if(ret != 0 && ret != ESRCH) {
- // semawakeup can be called on signal stack.
- // Save old ptrarg/scalararg so we can restore them.
- oldptr = g->m->ptrarg[0];
- oldscalar = g->m->scalararg[0];
- g->m->ptrarg[0] = mp;
- g->m->scalararg[0] = ret;
- fn = badsemawakeup;
- if(g == g->m->gsignal)
- fn();
- else
- runtime·onM(&fn);
- g->m->ptrarg[0] = oldptr;
- g->m->scalararg[0] = oldscalar;
- }
- // spin-mutex unlock
- runtime·atomicstore(&mp->waitsemalock, 0);
-}
-
-static void
-badsemawakeup(void)
-{
- M *mp;
- int32 ret;
-
- mp = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- ret = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
-
- runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
-}
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
- TforkT param;
- Sigset oset;
- int32 ret;
-
- if(0) {
- runtime·printf(
- "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
- stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
- }
-
- mp->tls[0] = mp->id; // so 386 asm can find it
-
- param.tf_tcb = (byte*)&mp->tls[0];
- param.tf_tid = (int32*)&mp->procid;
- param.tf_stack = stk;
-
- oset = runtime·sigprocmask(SIG_SETMASK, sigset_all);
- ret = runtime·tfork(&param, sizeof(param), mp, mp->g0, runtime·mstart);
- runtime·sigprocmask(SIG_SETMASK, oset);
-
- if(ret < 0) {
- runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
- if (ret == -ENOTSUP)
- runtime·printf("runtime: is kern.rthreads disabled?\n");
- runtime·throw("runtime.newosproc");
- }
-}
-
-void
-runtime·osinit(void)
-{
- runtime·ncpu = getncpu();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
- #pragma dataflag NOPTR
- static byte urandom_data[HashRandomBytes];
- int32 fd;
- fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
- if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
- *rnd = urandom_data;
- *rnd_len = HashRandomBytes;
- } else {
- *rnd = nil;
- *rnd_len = 0;
- }
- runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
- runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
- mp->gsignal = runtime·malg(32*1024);
- mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
- // Initialize signal handling
- runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
- runtime·sigprocmask(SIG_SETMASK, sigset_none);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
- runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
- return 0;
-}
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*__sa_handler)(int32);
- void (*__sa_sigaction)(int32, Siginfo*, void *);
- } __sigaction_u; /* signal handler */
- uint32 sa_mask; /* signal mask to apply */
- int32 sa_flags; /* see signal options below */
-} SigactionT;
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask = ~0U;
- if(fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.__sigaction_u.__sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
- return runtime·sighandler;
- return (void*)sa.__sigaction_u.__sa_sigaction;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- StackT st;
-
- st.ss_sp = (void*)p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
- runtime·sigprocmask(SIG_SETMASK, sigset_none);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
- return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go
index a000f963e..9e5adcd3d 100644
--- a/src/runtime/os_openbsd.go
+++ b/src/runtime/os_openbsd.go
@@ -4,14 +4,30 @@
package runtime
-import "unsafe"
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
-func setitimer(mode int32, new, old unsafe.Pointer)
-func sigaction(sig int32, new, old unsafe.Pointer)
-func sigaltstack(new, old unsafe.Pointer)
+//go:noescape
+func sigaction(sig int32, new, old *sigactiont)
+
+//go:noescape
+func sigaltstack(new, old *stackt)
+
+//go:noescape
func sigprocmask(mode int32, new uint32) uint32
+
+//go:noescape
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
+
func raise(sig int32)
-func tfork(param unsafe.Pointer, psize uintptr, mm, gg, fn unsafe.Pointer) int32
-func thrsleep(ident unsafe.Pointer, clock_id int32, tsp, lock, abort unsafe.Pointer) int32
-func thrwakeup(ident unsafe.Pointer, n int32) int32
+
+//go:noescape
+func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
+
+//go:noescape
+func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *int32) int32
+
+//go:noescape
+func thrwakeup(ident uintptr, n int32) int32
+
+func osyield()
diff --git a/src/runtime/os_openbsd.h b/src/runtime/os_openbsd.h
deleted file mode 100644
index 6ad98109e..000000000
--- a/src/runtime/os_openbsd.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2010 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 byte* kevent_udata;
-
-struct sigaction;
-
-void runtime·sigpanic(void);
-
-void runtime·setitimer(int32, Itimerval*, Itimerval*);
-void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
-void runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-Sigset runtime·sigprocmask(int32, Sigset);
-void runtime·unblocksignals(void);
-int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-
-enum {
- SS_DISABLE = 4,
- SIG_BLOCK = 1,
- SIG_UNBLOCK = 2,
- SIG_SETMASK = 3,
- NSIG = 33,
- SI_USER = 0,
-};
diff --git a/src/runtime/os_plan9.c b/src/runtime/os_plan9.c
deleted file mode 100644
index f8c543f6f..000000000
--- a/src/runtime/os_plan9.c
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "os_GOOS.h"
-#include "arch_GOARCH.h"
-#include "textflag.h"
-#include "malloc.h"
-
-int8 *goos = "plan9";
-extern SigTab runtime·sigtab[];
-
-int32 runtime·postnote(int32, int8*);
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
- // Initialize stack and goroutine for note handling.
- mp->gsignal = runtime·malg(32*1024);
- mp->gsignal->m = mp;
- mp->notesig = (int8*)runtime·mallocgc(ERRMAX*sizeof(int8), nil, FlagNoScan);
-
- // Initialize stack for handling strings from the
- // errstr system call, as used in package syscall.
- mp->errstr = (byte*)runtime·mallocgc(ERRMAX*sizeof(byte), nil, FlagNoScan);
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
- // Mask all SSE floating-point exceptions
- // when running on the 64-bit kernel.
- runtime·setfpmasks();
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-}
-
-
-static int32
-getproccount(void)
-{
- int32 fd, i, n, ncpu;
- byte buf[2048];
-
- fd = runtime·open("/dev/sysstat", OREAD, 0);
- if(fd < 0)
- return 1;
- ncpu = 0;
- for(;;) {
- n = runtime·read(fd, buf, sizeof buf);
- if(n <= 0)
- break;
- for(i = 0; i < n; i++) {
- if(buf[i] == '\n')
- ncpu++;
- }
- }
- runtime·close(fd);
- return ncpu > 0 ? ncpu : 1;
-}
-
-static int32
-getpid(void)
-{
- byte b[20], *c;
- int32 fd;
-
- runtime·memclr(b, sizeof(b));
- fd = runtime·open("#c/pid", 0, 0);
- if(fd >= 0) {
- runtime·read(fd, b, sizeof(b));
- runtime·close(fd);
- }
- c = b;
- while(*c == ' ' || *c == '\t')
- c++;
- return runtime·atoi(c);
-}
-
-void
-runtime·osinit(void)
-{
- runtime·ncpu = getproccount();
- g->m->procid = getpid();
- runtime·notify(runtime·sigtramp);
-}
-
-void
-runtime·crash(void)
-{
- runtime·notify(nil);
- *(int32*)0 = 0;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
- static byte random_data[HashRandomBytes];
- int32 fd;
-
- fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
- if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) {
- *rnd = random_data;
- *rnd_len = HashRandomBytes;
- } else {
- *rnd = nil;
- *rnd_len = 0;
- }
- runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
-}
-
-void
-runtime·initsig(void)
-{
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·osyield(void)
-{
- runtime·sleep(0);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·usleep(uint32 µs)
-{
- uint32 ms;
-
- ms = µs/1000;
- if(ms == 0)
- ms = 1;
- runtime·sleep(ms);
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·nanotime(void)
-{
- int64 ns, scratch;
-
- ns = runtime·nsec(&scratch);
- // TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
- if(ns == 0)
- return scratch;
- return ns;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·itoa(int32 n, byte *p, uint32 len)
-{
- byte *q, c;
- uint32 i;
-
- if(len <= 1)
- return;
-
- runtime·memclr(p, len);
- q = p;
-
- if(n==0) {
- *q++ = '0';
- USED(q);
- return;
- }
- if(n < 0) {
- *q++ = '-';
- p++;
- n = -n;
- }
- for(i=0; n > 0 && i < len; i++) {
- *q++ = '0' + (n%10);
- n = n/10;
- }
- for(q--; q >= p; ) {
- c = *p;
- *p++ = *q;
- *q-- = c;
- }
-}
-
-void
-runtime·goexitsall(int8 *status)
-{
- int8 buf[ERRMAX];
- M *mp;
- int32 pid;
-
- runtime·snprintf((byte*)buf, sizeof buf, "go: exit %s", status);
- pid = getpid();
- for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
- if(mp->procid != pid)
- runtime·postnote(mp->procid, buf);
-}
-
-int32
-runtime·postnote(int32 pid, int8* msg)
-{
- int32 fd;
- intgo len;
- uint8 buf[128];
- uint8 tmp[16];
- uint8 *p, *q;
-
- runtime·memclr(buf, sizeof buf);
-
- /* build path string /proc/pid/note */
- q = tmp;
- p = buf;
- runtime·itoa(pid, tmp, sizeof tmp);
- runtime·memmove((void*)p, (void*)"/proc/", 6);
- for(p += 6; *p++ = *q++; );
- p--;
- runtime·memmove((void*)p, (void*)"/note", 5);
-
- fd = runtime·open((int8*)buf, OWRITE, 0);
- if(fd < 0)
- return -1;
-
- len = runtime·findnull((byte*)msg);
- if(runtime·write(fd, msg, len) != len) {
- runtime·close(fd);
- return -1;
- }
- runtime·close(fd);
- return 0;
-}
-
-static void exit(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·exit(int32 e)
-{
- void (*fn)(void);
-
- g->m->scalararg[0] = e;
- fn = exit;
- runtime·onM(&fn);
-}
-
-static void
-exit(void)
-{
- int32 e;
- byte tmp[16];
- int8 *status;
-
- e = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
-
- if(e == 0)
- status = "";
- else {
- /* build error string */
- runtime·itoa(e, tmp, sizeof tmp);
- status = (int8*)tmp;
- }
-
- runtime·goexitsall(status);
- runtime·exits(status);
-}
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
- int32 pid;
-
- if(0)
- runtime·printf("newosproc mp=%p ostk=%p\n", mp, &mp);
-
- USED(stk);
- if((pid = runtime·rfork(RFPROC|RFMEM|RFNOWAIT)) < 0)
- runtime·throw("newosproc: rfork failed\n");
- if(pid == 0)
- runtime·tstart_plan9(mp);
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
- return 1;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
- int32 ret;
- int32 ms;
-
- if(ns >= 0) {
- ms = runtime·timediv(ns, 1000000, nil);
- if(ms == 0)
- ms = 1;
- ret = runtime·plan9_tsemacquire(&g->m->waitsemacount, ms);
- if(ret == 1)
- return 0; // success
- return -1; // timeout or interrupted
- }
-
- while(runtime·plan9_semacquire(&g->m->waitsemacount, 1) < 0) {
- /* interrupted; try again (c.f. lock_sema.c) */
- }
- return 0; // success
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
- runtime·plan9_semrelease(&mp->waitsemacount, 1);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·read(int32 fd, void *buf, int32 nbytes)
-{
- return runtime·pread(fd, buf, nbytes, -1LL);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·write(uintptr fd, void *buf, int32 nbytes)
-{
- return runtime·pwrite((int32)fd, buf, nbytes, -1LL);
-}
-
-uintptr
-runtime·memlimit(void)
-{
- return 0;
-}
-
-#pragma dataflag NOPTR
-static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-#pragma textflag NOSPLIT
-void
-runtime·badsignal2(void)
-{
- runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL);
- runtime·exits(badsignal);
-}
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index 20e47bf42..2dcdfc009 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -6,22 +6,49 @@ package runtime
import "unsafe"
+//go:noescape
func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
+
+//go:noescape
func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
+
func seek(fd int32, offset int64, whence int32) int64
+
+//go:noescape
func exits(msg *byte)
+
+//go:noescape
func brk_(addr unsafe.Pointer) uintptr
+
func sleep(ms int32) int32
+
func rfork(flags int32) int32
+
+//go:noescape
func plan9_semacquire(addr *uint32, block int32) int32
+
+//go:noescape
func plan9_tsemacquire(addr *uint32, ms int32) int32
+
+//go:noescape
func plan9_semrelease(addr *uint32, count int32) int32
+
+//go:noescape
func notify(fn unsafe.Pointer) int32
+
func noted(mode int32) int32
+
+//go:noescape
func nsec(*int64) int64
+
+//go:noescape
func sigtramp(ureg, msg unsafe.Pointer)
+
func setfpmasks()
+
+//go:noescape
func tstart_plan9(newm *m)
+
func errstr() string
type _Plink uintptr
diff --git a/src/runtime/os_plan9.h b/src/runtime/os_plan9.h
deleted file mode 100644
index 6d1802483..000000000
--- a/src/runtime/os_plan9.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2010 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.
-
-// Plan 9-specific system calls
-int32 runtime·pread(int32 fd, void *buf, int32 nbytes, int64 offset);
-int32 runtime·pwrite(int32 fd, void *buf, int32 nbytes, int64 offset);
-int64 runtime·seek(int32 fd, int64 offset, int32 whence);
-void runtime·exits(int8* msg);
-intptr runtime·brk_(void*);
-int32 runtime·sleep(int32 ms);
-int32 runtime·rfork(int32 flags);
-int32 runtime·plan9_semacquire(uint32 *addr, int32 block);
-int32 runtime·plan9_tsemacquire(uint32 *addr, int32 ms);
-int32 runtime·plan9_semrelease(uint32 *addr, int32 count);
-int32 runtime·notify(void (*fn)(void*, int8*));
-int32 runtime·noted(int32);
-int64 runtime·nsec(int64*);
-void runtime·sigtramp(void*, int8*);
-void runtime·sigpanic(void);
-void runtime·goexitsall(int8*);
-void runtime·setfpmasks(void);
-void runtime·tstart_plan9(M *newm);
-
-/* open */
-enum
-{
- OREAD = 0,
- OWRITE = 1,
- ORDWR = 2,
- OEXEC = 3,
- OTRUNC = 16,
- OCEXEC = 32,
- ORCLOSE = 64,
- OEXCL = 0x1000
-};
-
-/* rfork */
-enum
-{
- RFNAMEG = (1<<0),
- RFENVG = (1<<1),
- RFFDG = (1<<2),
- RFNOTEG = (1<<3),
- RFPROC = (1<<4),
- RFMEM = (1<<5),
- RFNOWAIT = (1<<6),
- RFCNAMEG = (1<<10),
- RFCENVG = (1<<11),
- RFCFDG = (1<<12),
- RFREND = (1<<13),
- RFNOMNT = (1<<14)
-};
-
-/* notify */
-enum
-{
- NCONT = 0,
- NDFLT = 1
-};
-
-typedef struct Tos Tos;
-typedef intptr _Plink;
-
-struct Tos {
- struct TosProf /* Per process profiling */
- {
- _Plink *pp; /* known to be 0(ptr) */
- _Plink *next; /* known to be 4(ptr) */
- _Plink *last;
- _Plink *first;
- uint32 pid;
- uint32 what;
- } prof;
- uint64 cyclefreq; /* cycle clock frequency if there is one, 0 otherwise */
- int64 kcycles; /* cycles spent in kernel */
- int64 pcycles; /* cycles spent in process (kernel + user) */
- uint32 pid; /* might as well put the pid here */
- uint32 clock;
- /* top of stack is here */
-};
-
-enum {
- NSIG = 14, /* number of signals in runtime·SigTab array */
- ERRMAX = 128, /* max length of note string */
-
- /* Notes in runtime·sigtab that are handled by runtime·sigpanic. */
- SIGRFAULT = 2,
- SIGWFAULT = 3,
- SIGINTDIV = 4,
- SIGFLOAT = 5,
- SIGTRAP = 6,
-};
diff --git a/src/runtime/os_plan9_386.c b/src/runtime/os_plan9_386.c
deleted file mode 100644
index 42c6d161c..000000000
--- a/src/runtime/os_plan9_386.c
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Ureg *u)
-{
- runtime·printf("ax %x\n", u->ax);
- runtime·printf("bx %x\n", u->bx);
- runtime·printf("cx %x\n", u->cx);
- runtime·printf("dx %x\n", u->dx);
- runtime·printf("di %x\n", u->di);
- runtime·printf("si %x\n", u->si);
- runtime·printf("bp %x\n", u->bp);
- runtime·printf("sp %x\n", u->sp);
- runtime·printf("pc %x\n", u->pc);
- runtime·printf("flags %x\n", u->flags);
- runtime·printf("cs %x\n", u->cs);
- runtime·printf("fs %x\n", u->fs);
- runtime·printf("gs %x\n", u->gs);
-}
-
-int32
-runtime·sighandler(void *v, int8 *note, G *gp)
-{
- uintptr *sp;
- SigTab *t;
- bool crash;
- Ureg *ureg;
- intgo len, n;
- int32 sig, flags;
-
- ureg = (Ureg*)v;
-
- // The kernel will never pass us a nil note or ureg so we probably
- // made a mistake somewhere in runtime·sigtramp.
- if(ureg == nil || note == nil) {
- runtime·printf("sighandler: ureg %p note %p\n", ureg, note);
- goto Throw;
- }
-
- // Check that the note is no more than ERRMAX bytes (including
- // the trailing NUL). We should never receive a longer note.
- len = runtime·findnull((byte*)note);
- if(len > ERRMAX-1) {
- runtime·printf("sighandler: note is longer than ERRMAX\n");
- goto Throw;
- }
-
- // See if the note matches one of the patterns in runtime·sigtab.
- // Notes that do not match any pattern can be handled at a higher
- // level by the program but will otherwise be ignored.
- flags = SigNotify;
- for(sig = 0; sig < nelem(runtime·sigtab); sig++) {
- t = &runtime·sigtab[sig];
- n = runtime·findnull((byte*)t->name);
- if(len < n)
- continue;
- if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) {
- flags = t->flags;
- break;
- }
- }
-
- if(flags & SigGoExit)
- runtime·exits(note+9); // Strip "go: exit " prefix.
-
- if(flags & SigPanic) {
- // Copy the error string from sigtramp's stack into m->notesig so
- // we can reliably access it from the panic routines.
- runtime·memmove(g->m->notesig, note, len+1);
-
- gp->sig = sig;
- gp->sigpc = ureg->pc;
-
- // Only push runtime·sigpanic if PC != 0.
- //
- // If PC == 0, probably panicked because of a call to a nil func.
- // Not pushing that onto SP will make the trace look like a call
- // to runtime·sigpanic instead. (Otherwise the trace will end at
- // runtime·sigpanic and we won't get to see who faulted).
- if(ureg->pc != 0) {
- sp = (uintptr*)ureg->sp;
- *--sp = ureg->pc;
- ureg->sp = (uint32)sp;
- }
- ureg->pc = (uintptr)runtime·sigpanic;
- return NCONT;
- }
-
- if(flags & SigNotify) {
- // TODO(ality): See if os/signal wants it.
- //if(runtime·sigsend(...))
- // return NCONT;
- }
- if(flags & SigKill)
- goto Exit;
- if(!(flags & SigThrow))
- return NCONT;
-
-Throw:
- g->m->throwing = 1;
- g->m->caughtsig = gp;
- runtime·startpanic();
-
- runtime·printf("%s\n", note);
- runtime·printf("PC=%x\n", ureg->pc);
- runtime·printf("\n");
-
- if(runtime·gotraceback(&crash)) {
- runtime·goroutineheader(gp);
- runtime·tracebacktrap(ureg->pc, ureg->sp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·printf("\n");
- runtime·dumpregs(ureg);
- }
-
- if(crash)
- runtime·crash();
-
-Exit:
- runtime·goexitsall(note);
- runtime·exits(note);
- return NDFLT; // not reached
-}
-
-void
-runtime·sigenable(uint32 sig)
-{
- USED(sig);
-}
-
-void
-runtime·sigdisable(uint32 sig)
-{
- USED(sig);
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- // TODO: Enable profiling interrupts.
-
- g->m->profilehz = hz;
-}
diff --git a/src/runtime/os_plan9_386.go b/src/runtime/os_plan9_386.go
new file mode 100644
index 000000000..7dda13931
--- /dev/null
+++ b/src/runtime/os_plan9_386.go
@@ -0,0 +1,131 @@
+// Copyright 2010 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 runtime
+
+import "unsafe"
+
+func dumpregs(u *ureg) {
+ print("ax ", hex(u.ax), "\n")
+ print("bx ", hex(u.bx), "\n")
+ print("cx ", hex(u.cx), "\n")
+ print("dx ", hex(u.dx), "\n")
+ print("di ", hex(u.di), "\n")
+ print("si ", hex(u.si), "\n")
+ print("bp ", hex(u.bp), "\n")
+ print("sp ", hex(u.sp), "\n")
+ print("pc ", hex(u.pc), "\n")
+ print("flags ", hex(u.flags), "\n")
+ print("cs ", hex(u.cs), "\n")
+ print("fs ", hex(u.fs), "\n")
+ print("gs ", hex(u.gs), "\n")
+}
+
+func sighandler(_ureg *ureg, note *byte, gp *g) int {
+ _g_ := getg()
+ var t sigTabT
+ var docrash bool
+ var length int
+ var sig int
+ var flags int
+
+ // The kernel will never pass us a nil note or ureg so we probably
+ // made a mistake somewhere in sigtramp.
+ if _ureg == nil || note == nil {
+ print("sighandler: ureg ", _ureg, " note ", note, "\n")
+ goto Throw
+ }
+ // Check that the note is no more than ERRMAX bytes (including
+ // the trailing NUL). We should never receive a longer note.
+ length = findnull(note)
+ if length > _ERRMAX-1 {
+ print("sighandler: note is longer than ERRMAX\n")
+ goto Throw
+ }
+ // See if the note matches one of the patterns in sigtab.
+ // Notes that do not match any pattern can be handled at a higher
+ // level by the program but will otherwise be ignored.
+ flags = _SigNotify
+ for sig, t = range sigtable {
+ n := len(t.name)
+ if length < n {
+ continue
+ }
+ if strncmp(note, &t.name[0], uintptr(n)) == 0 {
+ flags = t.flags
+ break
+ }
+ }
+ if flags&_SigGoExit != 0 {
+ exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix.
+ }
+ if flags&_SigPanic != 0 {
+ // Copy the error string from sigtramp's stack into m->notesig so
+ // we can reliably access it from the panic routines.
+ memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(length+1))
+ gp.sig = uint32(sig)
+ gp.sigpc = uintptr(_ureg.pc)
+ // Only push sigpanic if PC != 0.
+ //
+ // If PC == 0, probably panicked because of a call to a nil func.
+ // Not pushing that onto SP will make the trace look like a call
+ // to sigpanic instead. (Otherwise the trace will end at
+ // sigpanic and we won't get to see who faulted).
+ if _ureg.pc != 0 {
+ sp := _ureg.sp
+ if regSize > ptrSize {
+ sp -= ptrSize
+ *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0
+ }
+ sp -= ptrSize
+ *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(_ureg.pc)
+ _ureg.sp = sp
+ }
+ _ureg.pc = uint32(funcPC(sigpanic))
+ return _NCONT
+ }
+ if flags&_SigNotify != 0 {
+ // TODO(ality): See if os/signal wants it.
+ //if(sigsend(...))
+ // return _NCONT;
+ }
+ if flags&_SigKill != 0 {
+ goto Exit
+ }
+ if flags&_SigThrow == 0 {
+ return _NCONT
+ }
+Throw:
+ _g_.m.throwing = 1
+ _g_.m.caughtsig = gp
+ startpanic()
+ print(gostringnocopy(note), "\n")
+ print("PC=", hex(_ureg.pc), "\n")
+ print("\n")
+ if gotraceback(&docrash) > 0 {
+ goroutineheader(gp)
+ tracebacktrap(uintptr(_ureg.pc), uintptr(_ureg.sp), 0, gp)
+ tracebackothers(gp)
+ print("\n")
+ dumpregs(_ureg)
+ }
+ if docrash {
+ crash()
+ }
+Exit:
+ goexitsall(note)
+ exits(note)
+ return _NDFLT // not reached
+}
+
+func sigenable(sig uint32) {
+}
+
+func sigdisable(sig uint32) {
+}
+
+func resetcpuprofiler(hz int32) {
+ // TODO: Enable profiling interrupts.
+ getg().m.profilehz = hz
+}
diff --git a/src/runtime/os_plan9_amd64.c b/src/runtime/os_plan9_amd64.c
deleted file mode 100644
index a9dc0eb96..000000000
--- a/src/runtime/os_plan9_amd64.c
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2010 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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Ureg *u)
-{
- runtime·printf("ax %X\n", u->ax);
- runtime·printf("bx %X\n", u->bx);
- runtime·printf("cx %X\n", u->cx);
- runtime·printf("dx %X\n", u->dx);
- runtime·printf("di %X\n", u->di);
- runtime·printf("si %X\n", u->si);
- runtime·printf("bp %X\n", u->bp);
- runtime·printf("sp %X\n", u->sp);
- runtime·printf("r8 %X\n", u->r8);
- runtime·printf("r9 %X\n", u->r9);
- runtime·printf("r10 %X\n", u->r10);
- runtime·printf("r11 %X\n", u->r11);
- runtime·printf("r12 %X\n", u->r12);
- runtime·printf("r13 %X\n", u->r13);
- runtime·printf("r14 %X\n", u->r14);
- runtime·printf("r15 %X\n", u->r15);
- runtime·printf("ip %X\n", u->ip);
- runtime·printf("flags %X\n", u->flags);
- runtime·printf("cs %X\n", (uint64)u->cs);
- runtime·printf("fs %X\n", (uint64)u->fs);
- runtime·printf("gs %X\n", (uint64)u->gs);
-}
-
-int32
-runtime·sighandler(void *v, int8 *note, G *gp)
-{
- uintptr *sp;
- SigTab *t;
- bool crash;
- Ureg *ureg;
- intgo len, n;
- int32 sig, flags;
-
- ureg = (Ureg*)v;
-
- // The kernel will never pass us a nil note or ureg so we probably
- // made a mistake somewhere in runtime·sigtramp.
- if(ureg == nil || note == nil) {
- runtime·printf("sighandler: ureg %p note %p\n", ureg, note);
- goto Throw;
- }
-
- // Check that the note is no more than ERRMAX bytes (including
- // the trailing NUL). We should never receive a longer note.
- len = runtime·findnull((byte*)note);
- if(len > ERRMAX-1) {
- runtime·printf("sighandler: note is longer than ERRMAX\n");
- goto Throw;
- }
-
- // See if the note matches one of the patterns in runtime·sigtab.
- // Notes that do not match any pattern can be handled at a higher
- // level by the program but will otherwise be ignored.
- flags = SigNotify;
- for(sig = 0; sig < nelem(runtime·sigtab); sig++) {
- t = &runtime·sigtab[sig];
- n = runtime·findnull((byte*)t->name);
- if(len < n)
- continue;
- if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) {
- flags = t->flags;
- break;
- }
- }
-
- if(flags & SigGoExit)
- runtime·exits(note+9); // Strip "go: exit " prefix.
-
- if(flags & SigPanic) {
- // Copy the error string from sigtramp's stack into m->notesig so
- // we can reliably access it from the panic routines.
- runtime·memmove(g->m->notesig, note, len+1);
-
- gp->sig = sig;
- gp->sigpc = ureg->ip;
-
- // Only push runtime·sigpanic if PC != 0.
- //
- // If PC == 0, probably panicked because of a call to a nil func.
- // Not pushing that onto SP will make the trace look like a call
- // to runtime·sigpanic instead. (Otherwise the trace will end at
- // runtime·sigpanic and we won't get to see who faulted).
- if(ureg->ip != 0) {
- sp = (uintptr*)ureg->sp;
- *--sp = ureg->ip;
- ureg->sp = (uint64)sp;
- }
- ureg->ip = (uintptr)runtime·sigpanic;
- return NCONT;
- }
-
- if(flags & SigNotify) {
- // TODO(ality): See if os/signal wants it.
- //if(runtime·sigsend(...))
- // return NCONT;
- }
- if(flags & SigKill)
- goto Exit;
- if(!(flags & SigThrow))
- return NCONT;
-
-Throw:
- g->m->throwing = 1;
- g->m->caughtsig = gp;
- runtime·startpanic();
-
- runtime·printf("%s\n", note);
- runtime·printf("PC=%X\n", ureg->ip);
- runtime·printf("\n");
-
- if(runtime·gotraceback(&crash)) {
- runtime·goroutineheader(gp);
- runtime·tracebacktrap(ureg->ip, ureg->sp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·printf("\n");
- runtime·dumpregs(ureg);
- }
-
- if(crash)
- runtime·crash();
-
-Exit:
- runtime·goexitsall(note);
- runtime·exits(note);
- return NDFLT; // not reached
-}
-
-void
-runtime·sigenable(uint32 sig)
-{
- USED(sig);
-}
-
-void
-runtime·sigdisable(uint32 sig)
-{
- USED(sig);
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- // TODO: Enable profiling interrupts.
-
- g->m->profilehz = hz;
-}
diff --git a/src/runtime/os_plan9_amd64.go b/src/runtime/os_plan9_amd64.go
new file mode 100644
index 000000000..8727dcc20
--- /dev/null
+++ b/src/runtime/os_plan9_amd64.go
@@ -0,0 +1,139 @@
+// Copyright 2010 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 runtime
+
+import "unsafe"
+
+func dumpregs(u *ureg) {
+ print("ax ", hex(u.ax), "\n")
+ print("bx ", hex(u.bx), "\n")
+ print("cx ", hex(u.cx), "\n")
+ print("dx ", hex(u.dx), "\n")
+ print("di ", hex(u.di), "\n")
+ print("si ", hex(u.si), "\n")
+ print("bp ", hex(u.bp), "\n")
+ print("sp ", hex(u.sp), "\n")
+ print("r8 ", hex(u.r8), "\n")
+ print("r9 ", hex(u.r9), "\n")
+ print("r10 ", hex(u.r10), "\n")
+ print("r11 ", hex(u.r11), "\n")
+ print("r12 ", hex(u.r12), "\n")
+ print("r13 ", hex(u.r13), "\n")
+ print("r14 ", hex(u.r14), "\n")
+ print("r15 ", hex(u.r15), "\n")
+ print("ip ", hex(u.ip), "\n")
+ print("flags ", hex(u.flags), "\n")
+ print("cs ", hex(uint64(u.cs)), "\n")
+ print("fs ", hex(uint64(u.fs)), "\n")
+ print("gs ", hex(uint64(u.gs)), "\n")
+}
+
+func sighandler(_ureg *ureg, note *byte, gp *g) int {
+ _g_ := getg()
+ var t sigTabT
+ var docrash bool
+ var length int
+ var sig int
+ var flags int
+
+ // The kernel will never pass us a nil note or ureg so we probably
+ // made a mistake somewhere in sigtramp.
+ if _ureg == nil || note == nil {
+ print("sighandler: ureg ", _ureg, " note ", note, "\n")
+ goto Throw
+ }
+ // Check that the note is no more than ERRMAX bytes (including
+ // the trailing NUL). We should never receive a longer note.
+ length = findnull(note)
+ if length > _ERRMAX-1 {
+ print("sighandler: note is longer than ERRMAX\n")
+ goto Throw
+ }
+ // See if the note matches one of the patterns in sigtab.
+ // Notes that do not match any pattern can be handled at a higher
+ // level by the program but will otherwise be ignored.
+ flags = _SigNotify
+ for sig, t = range sigtable {
+ n := len(t.name)
+ if length < n {
+ continue
+ }
+ if strncmp(note, &t.name[0], uintptr(n)) == 0 {
+ flags = t.flags
+ break
+ }
+ }
+ if flags&_SigGoExit != 0 {
+ exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix.
+ }
+ if flags&_SigPanic != 0 {
+ // Copy the error string from sigtramp's stack into m->notesig so
+ // we can reliably access it from the panic routines.
+ memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(length+1))
+ gp.sig = uint32(sig)
+ gp.sigpc = uintptr(_ureg.ip)
+ // Only push sigpanic if PC != 0.
+ //
+ // If PC == 0, probably panicked because of a call to a nil func.
+ // Not pushing that onto SP will make the trace look like a call
+ // to sigpanic instead. (Otherwise the trace will end at
+ // sigpanic and we won't get to see who faulted).
+ if _ureg.ip != 0 {
+ sp := _ureg.sp
+ if regSize > ptrSize {
+ sp -= ptrSize
+ *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0
+ }
+ sp -= ptrSize
+ *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(_ureg.ip)
+ _ureg.sp = sp
+ }
+ _ureg.ip = uint64(funcPC(sigpanic))
+ return _NCONT
+ }
+ if flags&_SigNotify != 0 {
+ // TODO(ality): See if os/signal wants it.
+ //if(sigsend(...))
+ // return _NCONT;
+ }
+ if flags&_SigKill != 0 {
+ goto Exit
+ }
+ if flags&_SigThrow == 0 {
+ return _NCONT
+ }
+Throw:
+ _g_.m.throwing = 1
+ _g_.m.caughtsig = gp
+ startpanic()
+ print(gostringnocopy(note), "\n")
+ print("PC=", hex(_ureg.ip), "\n")
+ print("\n")
+ if gotraceback(&docrash) > 0 {
+ goroutineheader(gp)
+ tracebacktrap(uintptr(_ureg.ip), uintptr(_ureg.sp), 0, gp)
+ tracebackothers(gp)
+ print("\n")
+ dumpregs(_ureg)
+ }
+ if docrash {
+ crash()
+ }
+Exit:
+ goexitsall(note)
+ exits(note)
+ return _NDFLT // not reached
+}
+
+func sigenable(sig uint32) {
+}
+
+func sigdisable(sig uint32) {
+}
+
+func resetcpuprofiler(hz int32) {
+ // TODO: Enable profiling interrupts.
+ getg().m.profilehz = hz
+}
diff --git a/src/runtime/os_solaris.c b/src/runtime/os_solaris.c
deleted file mode 100644
index e16b8e637..000000000
--- a/src/runtime/os_solaris.c
+++ /dev/null
@@ -1,557 +0,0 @@
-// Copyright 2011 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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-#pragma dynexport runtime·end _end
-#pragma dynexport runtime·etext _etext
-#pragma dynexport runtime·edata _edata
-
-#pragma dynimport libc·___errno ___errno "libc.so"
-#pragma dynimport libc·clock_gettime clock_gettime "libc.so"
-#pragma dynimport libc·close close "libc.so"
-#pragma dynimport libc·exit exit "libc.so"
-#pragma dynimport libc·fstat fstat "libc.so"
-#pragma dynimport libc·getcontext getcontext "libc.so"
-#pragma dynimport libc·getrlimit getrlimit "libc.so"
-#pragma dynimport libc·malloc malloc "libc.so"
-#pragma dynimport libc·mmap mmap "libc.so"
-#pragma dynimport libc·munmap munmap "libc.so"
-#pragma dynimport libc·open open "libc.so"
-#pragma dynimport libc·pthread_attr_destroy pthread_attr_destroy "libc.so"
-#pragma dynimport libc·pthread_attr_getstack pthread_attr_getstack "libc.so"
-#pragma dynimport libc·pthread_attr_init pthread_attr_init "libc.so"
-#pragma dynimport libc·pthread_attr_setdetachstate pthread_attr_setdetachstate "libc.so"
-#pragma dynimport libc·pthread_attr_setstack pthread_attr_setstack "libc.so"
-#pragma dynimport libc·pthread_create pthread_create "libc.so"
-#pragma dynimport libc·raise raise "libc.so"
-#pragma dynimport libc·read read "libc.so"
-#pragma dynimport libc·select select "libc.so"
-#pragma dynimport libc·sched_yield sched_yield "libc.so"
-#pragma dynimport libc·sem_init sem_init "libc.so"
-#pragma dynimport libc·sem_post sem_post "libc.so"
-#pragma dynimport libc·sem_reltimedwait_np sem_reltimedwait_np "libc.so"
-#pragma dynimport libc·sem_wait sem_wait "libc.so"
-#pragma dynimport libc·setitimer setitimer "libc.so"
-#pragma dynimport libc·sigaction sigaction "libc.so"
-#pragma dynimport libc·sigaltstack sigaltstack "libc.so"
-#pragma dynimport libc·sigprocmask sigprocmask "libc.so"
-#pragma dynimport libc·sysconf sysconf "libc.so"
-#pragma dynimport libc·usleep usleep "libc.so"
-#pragma dynimport libc·write write "libc.so"
-
-extern uintptr libc·___errno;
-extern uintptr libc·clock_gettime;
-extern uintptr libc·close;
-extern uintptr libc·exit;
-extern uintptr libc·fstat;
-extern uintptr libc·getcontext;
-extern uintptr libc·getrlimit;
-extern uintptr libc·malloc;
-extern uintptr libc·mmap;
-extern uintptr libc·munmap;
-extern uintptr libc·open;
-extern uintptr libc·pthread_attr_destroy;
-extern uintptr libc·pthread_attr_getstack;
-extern uintptr libc·pthread_attr_init;
-extern uintptr libc·pthread_attr_setdetachstate;
-extern uintptr libc·pthread_attr_setstack;
-extern uintptr libc·pthread_create;
-extern uintptr libc·raise;
-extern uintptr libc·read;
-extern uintptr libc·sched_yield;
-extern uintptr libc·select;
-extern uintptr libc·sem_init;
-extern uintptr libc·sem_post;
-extern uintptr libc·sem_reltimedwait_np;
-extern uintptr libc·sem_wait;
-extern uintptr libc·setitimer;
-extern uintptr libc·sigaction;
-extern uintptr libc·sigaltstack;
-extern uintptr libc·sigprocmask;
-extern uintptr libc·sysconf;
-extern uintptr libc·usleep;
-extern uintptr libc·write;
-
-void runtime·getcontext(Ucontext *context);
-int32 runtime·pthread_attr_destroy(PthreadAttr* attr);
-int32 runtime·pthread_attr_init(PthreadAttr* attr);
-int32 runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size);
-int32 runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state);
-int32 runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size);
-int32 runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg);
-uint32 runtime·tstart_sysvicall(M *newm);
-int32 runtime·sem_init(SemT* sem, int32 pshared, uint32 value);
-int32 runtime·sem_post(SemT* sem);
-int32 runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout);
-int32 runtime·sem_wait(SemT* sem);
-int64 runtime·sysconf(int32 name);
-
-extern SigTab runtime·sigtab[];
-static Sigset sigset_none;
-static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
-
-static int32
-getncpu(void)
-{
- int32 n;
-
- n = (int32)runtime·sysconf(_SC_NPROCESSORS_ONLN);
- if(n < 1)
- return 1;
- return n;
-}
-
-void
-runtime·osinit(void)
-{
- runtime·ncpu = getncpu();
-}
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
- PthreadAttr attr;
- Sigset oset;
- Pthread tid;
- int32 ret;
- uint64 size;
-
- USED(stk);
- if(runtime·pthread_attr_init(&attr) != 0)
- runtime·throw("pthread_attr_init");
- if(runtime·pthread_attr_setstack(&attr, 0, 0x200000) != 0)
- runtime·throw("pthread_attr_setstack");
- size = 0;
- if(runtime·pthread_attr_getstack(&attr, (void**)&mp->g0->stack.hi, &size) != 0)
- runtime·throw("pthread_attr_getstack");
- mp->g0->stack.lo = mp->g0->stack.hi - size;
- if(runtime·pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
- runtime·throw("pthread_attr_setdetachstate");
-
- // Disable signals during create, so that the new thread starts
- // with signals disabled. It will enable them in minit.
- runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
- ret = runtime·pthread_create(&tid, &attr, (void (*)(void))runtime·tstart_sysvicall, mp);
- runtime·sigprocmask(SIG_SETMASK, &oset, nil);
- if(ret != 0) {
- runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), ret);
- runtime·throw("runtime.newosproc");
- }
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
- #pragma dataflag NOPTR
- static byte urandom_data[HashRandomBytes];
- int32 fd;
- fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
- if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
- *rnd = urandom_data;
- *rnd_len = HashRandomBytes;
- } else {
- *rnd = nil;
- *rnd_len = 0;
- }
- runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
- runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
- mp->gsignal = runtime·malg(32*1024);
- mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
- runtime·asmcgocall(runtime·miniterrno, (void *)libc·___errno);
- // Initialize signal handling
- runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
- runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
- runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
- Rlimit rl;
- extern byte runtime·text[], runtime·end[];
- uintptr used;
-
- if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
- return 0;
- if(rl.rlim_cur >= 0x7fffffff)
- return 0;
-
- // Estimate our VM footprint excluding the heap.
- // Not an exact science: use size of binary plus
- // some room for thread stacks.
- used = runtime·end - runtime·text + (64<<20);
- if(used >= rl.rlim_cur)
- return 0;
-
- // If there's not at least 16 MB left, we're probably
- // not going to be able to do much. Treat as no limit.
- rl.rlim_cur -= used;
- if(rl.rlim_cur < (16<<20))
- return 0;
-
- return rl.rlim_cur - used;
-}
-
-void
-runtime·setprof(bool on)
-{
- USED(on);
-}
-
-extern void runtime·sigtramp(void);
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask.__sigbits[0] = ~(uint32)0;
- sa.sa_mask.__sigbits[1] = ~(uint32)0;
- sa.sa_mask.__sigbits[2] = ~(uint32)0;
- sa.sa_mask.__sigbits[3] = ~(uint32)0;
- if(fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- *((void**)&sa._funcptr[0]) = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
- SigactionT sa;
-
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(*((void**)&sa._funcptr[0]) == runtime·sigtramp)
- return runtime·sighandler;
- return *((void**)&sa._funcptr[0]);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- StackT st;
-
- st.ss_sp = (void*)p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
- runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
- SemT* sem;
-
- // Call libc's malloc rather than runtime·malloc. This will
- // allocate space on the C heap. We can't call runtime·malloc
- // here because it could cause a deadlock.
- g->m->libcall.fn = (uintptr)(void*)libc·malloc;
- g->m->libcall.n = 1;
- runtime·memclr((byte*)&g->m->scratch, sizeof(g->m->scratch));
- g->m->scratch.v[0] = (uintptr)sizeof(*sem);
- g->m->libcall.args = (uintptr)(uintptr*)&g->m->scratch;
- runtime·asmcgocall(runtime·asmsysvicall6, &g->m->libcall);
- sem = (void*)g->m->libcall.r1;
- if(runtime·sem_init(sem, 0, 0) != 0)
- runtime·throw("sem_init");
- return (uintptr)sem;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
- M *m;
-
- m = g->m;
- if(ns >= 0) {
- m->ts.tv_sec = ns / 1000000000LL;
- m->ts.tv_nsec = ns % 1000000000LL;
-
- m->libcall.fn = (uintptr)(void*)libc·sem_reltimedwait_np;
- m->libcall.n = 2;
- runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
- m->scratch.v[0] = m->waitsema;
- m->scratch.v[1] = (uintptr)&m->ts;
- m->libcall.args = (uintptr)(uintptr*)&m->scratch;
- runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
- if(*m->perrno != 0) {
- if(*m->perrno == ETIMEDOUT || *m->perrno == EAGAIN || *m->perrno == EINTR)
- return -1;
- runtime·throw("sem_reltimedwait_np");
- }
- return 0;
- }
- for(;;) {
- m->libcall.fn = (uintptr)(void*)libc·sem_wait;
- m->libcall.n = 1;
- runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
- m->scratch.v[0] = m->waitsema;
- m->libcall.args = (uintptr)(uintptr*)&m->scratch;
- runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
- if(m->libcall.r1 == 0)
- break;
- if(*m->perrno == EINTR)
- continue;
- runtime·throw("sem_wait");
- }
- return 0;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
- SemT* sem = (SemT*)mp->waitsema;
- if(runtime·sem_post(sem) != 0)
- runtime·throw("sem_post");
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·close(int32 fd)
-{
- return runtime·sysvicall1(libc·close, (uintptr)fd);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·exit(int32 r)
-{
- runtime·sysvicall1(libc·exit, (uintptr)r);
-}
-
-#pragma textflag NOSPLIT
-/* int32 */ void
-runtime·getcontext(Ucontext* context)
-{
- runtime·sysvicall1(libc·getcontext, (uintptr)context);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·getrlimit(int32 res, Rlimit* rlp)
-{
- return runtime·sysvicall2(libc·getrlimit, (uintptr)res, (uintptr)rlp);
-}
-
-#pragma textflag NOSPLIT
-uint8*
-runtime·mmap(byte* addr, uintptr len, int32 prot, int32 flags, int32 fildes, uint32 off)
-{
- return (uint8*)runtime·sysvicall6(libc·mmap, (uintptr)addr, (uintptr)len, (uintptr)prot, (uintptr)flags, (uintptr)fildes, (uintptr)off);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·munmap(byte* addr, uintptr len)
-{
- runtime·sysvicall2(libc·munmap, (uintptr)addr, (uintptr)len);
-}
-
-extern int64 runtime·nanotime1(void);
-#pragma textflag NOSPLIT
-int64
-runtime·nanotime(void)
-{
- return runtime·sysvicall0((uintptr)runtime·nanotime1);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·open(int8* path, int32 oflag, int32 mode)
-{
- return runtime·sysvicall3(libc·open, (uintptr)path, (uintptr)oflag, (uintptr)mode);
-}
-
-int32
-runtime·pthread_attr_destroy(PthreadAttr* attr)
-{
- return runtime·sysvicall1(libc·pthread_attr_destroy, (uintptr)attr);
-}
-
-int32
-runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size)
-{
- return runtime·sysvicall3(libc·pthread_attr_getstack, (uintptr)attr, (uintptr)addr, (uintptr)size);
-}
-
-int32
-runtime·pthread_attr_init(PthreadAttr* attr)
-{
- return runtime·sysvicall1(libc·pthread_attr_init, (uintptr)attr);
-}
-
-int32
-runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state)
-{
- return runtime·sysvicall2(libc·pthread_attr_setdetachstate, (uintptr)attr, (uintptr)state);
-}
-
-int32
-runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size)
-{
- return runtime·sysvicall3(libc·pthread_attr_setstack, (uintptr)attr, (uintptr)addr, (uintptr)size);
-}
-
-int32
-runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg)
-{
- return runtime·sysvicall4(libc·pthread_create, (uintptr)thread, (uintptr)attr, (uintptr)fn, (uintptr)arg);
-}
-
-/* int32 */ void
-runtime·raise(int32 sig)
-{
- runtime·sysvicall1(libc·raise, (uintptr)sig);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·read(int32 fd, void* buf, int32 nbyte)
-{
- return runtime·sysvicall3(libc·read, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·sem_init(SemT* sem, int32 pshared, uint32 value)
-{
- return runtime·sysvicall3(libc·sem_init, (uintptr)sem, (uintptr)pshared, (uintptr)value);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·sem_post(SemT* sem)
-{
- return runtime·sysvicall1(libc·sem_post, (uintptr)sem);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout)
-{
- return runtime·sysvicall2(libc·sem_reltimedwait_np, (uintptr)sem, (uintptr)timeout);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·sem_wait(SemT* sem)
-{
- return runtime·sysvicall1(libc·sem_wait, (uintptr)sem);
-}
-
-/* int32 */ void
-runtime·setitimer(int32 which, Itimerval* value, Itimerval* ovalue)
-{
- runtime·sysvicall3(libc·setitimer, (uintptr)which, (uintptr)value, (uintptr)ovalue);
-}
-
-/* int32 */ void
-runtime·sigaction(int32 sig, struct SigactionT* act, struct SigactionT* oact)
-{
- runtime·sysvicall3(libc·sigaction, (uintptr)sig, (uintptr)act, (uintptr)oact);
-}
-
-/* int32 */ void
-runtime·sigaltstack(SigaltstackT* ss, SigaltstackT* oss)
-{
- runtime·sysvicall2(libc·sigaltstack, (uintptr)ss, (uintptr)oss);
-}
-
-/* int32 */ void
-runtime·sigprocmask(int32 how, Sigset* set, Sigset* oset)
-{
- runtime·sysvicall3(libc·sigprocmask, (uintptr)how, (uintptr)set, (uintptr)oset);
-}
-
-int64
-runtime·sysconf(int32 name)
-{
- return runtime·sysvicall1(libc·sysconf, (uintptr)name);
-}
-
-extern void runtime·usleep1(uint32);
-
-#pragma textflag NOSPLIT
-void
-runtime·usleep(uint32 µs)
-{
- runtime·usleep1(µs);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·write(uintptr fd, void* buf, int32 nbyte)
-{
- return runtime·sysvicall3(libc·write, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
-}
-
-extern void runtime·osyield1(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·osyield(void)
-{
- // Check the validity of m because we might be called in cgo callback
- // path early enough where there isn't a m available yet.
- if(g && g->m != nil) {
- runtime·sysvicall0(libc·sched_yield);
- return;
- }
- runtime·osyield1();
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
- return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_solaris.go b/src/runtime/os_solaris.go
index ca1315120..6864ef938 100644
--- a/src/runtime/os_solaris.go
+++ b/src/runtime/os_solaris.go
@@ -6,53 +6,35 @@ package runtime
import "unsafe"
-func setitimer(mode int32, new, old unsafe.Pointer)
-func sigaction(sig int32, new, old unsafe.Pointer)
-func sigaltstack(new, old unsafe.Pointer)
-func sigprocmask(mode int32, new, old unsafe.Pointer)
-func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-func getrlimit(kind int32, limit unsafe.Pointer)
-func miniterrno(fn unsafe.Pointer)
-func raise(sig int32)
-func getcontext(ctxt unsafe.Pointer)
-func tstart_sysvicall(mm unsafe.Pointer) uint32
-func nanotime1() int64
-func usleep1(usec uint32)
-func osyield1()
-func netpollinit()
-func netpollopen(fd uintptr, pd *pollDesc) int32
-func netpollclose(fd uintptr) int32
-func netpollarm(pd *pollDesc, mode int)
-
-type libcFunc byte
+type libcFunc uintptr
var asmsysvicall6 libcFunc
//go:nosplit
-func sysvicall0(fn *libcFunc) uintptr {
+func sysvicall0(fn libcFunc) uintptr {
libcall := &getg().m.libcall
- libcall.fn = uintptr(unsafe.Pointer(fn))
+ libcall.fn = uintptr(fn)
libcall.n = 0
- // TODO(rsc): Why is noescape necessary here and below?
- libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
+ libcall.args = uintptr(fn) // it's unused but must be non-nil, otherwise crashes
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
return libcall.r1
}
//go:nosplit
-func sysvicall1(fn *libcFunc, a1 uintptr) uintptr {
+func sysvicall1(fn libcFunc, a1 uintptr) uintptr {
libcall := &getg().m.libcall
- libcall.fn = uintptr(unsafe.Pointer(fn))
+ libcall.fn = uintptr(fn)
libcall.n = 1
+ // TODO(rsc): Why is noescape necessary here and below?
libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
return libcall.r1
}
//go:nosplit
-func sysvicall2(fn *libcFunc, a1, a2 uintptr) uintptr {
+func sysvicall2(fn libcFunc, a1, a2 uintptr) uintptr {
libcall := &getg().m.libcall
- libcall.fn = uintptr(unsafe.Pointer(fn))
+ libcall.fn = uintptr(fn)
libcall.n = 2
libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
@@ -60,9 +42,9 @@ func sysvicall2(fn *libcFunc, a1, a2 uintptr) uintptr {
}
//go:nosplit
-func sysvicall3(fn *libcFunc, a1, a2, a3 uintptr) uintptr {
+func sysvicall3(fn libcFunc, a1, a2, a3 uintptr) uintptr {
libcall := &getg().m.libcall
- libcall.fn = uintptr(unsafe.Pointer(fn))
+ libcall.fn = uintptr(fn)
libcall.n = 3
libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
@@ -70,9 +52,9 @@ func sysvicall3(fn *libcFunc, a1, a2, a3 uintptr) uintptr {
}
//go:nosplit
-func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr {
+func sysvicall4(fn libcFunc, a1, a2, a3, a4 uintptr) uintptr {
libcall := &getg().m.libcall
- libcall.fn = uintptr(unsafe.Pointer(fn))
+ libcall.fn = uintptr(fn)
libcall.n = 4
libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
@@ -80,9 +62,9 @@ func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr {
}
//go:nosplit
-func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr {
+func sysvicall5(fn libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr {
libcall := &getg().m.libcall
- libcall.fn = uintptr(unsafe.Pointer(fn))
+ libcall.fn = uintptr(fn)
libcall.n = 5
libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
@@ -90,9 +72,9 @@ func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr {
}
//go:nosplit
-func sysvicall6(fn *libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
+func sysvicall6(fn libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
libcall := &getg().m.libcall
- libcall.fn = uintptr(unsafe.Pointer(fn))
+ libcall.fn = uintptr(fn)
libcall.n = 6
libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
diff --git a/src/runtime/os_solaris.h b/src/runtime/os_solaris.h
deleted file mode 100644
index 3d9e1a240..000000000
--- a/src/runtime/os_solaris.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.
-
-
-typedef uintptr kevent_udata;
-
-struct sigaction;
-
-void runtime·sigpanic(void);
-
-void runtime·setitimer(int32, Itimerval*, Itimerval*);
-void runtime·sigaction(int32, struct SigactionT*, struct SigactionT*);
-void runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-void runtime·sigprocmask(int32, Sigset*, Sigset*);
-void runtime·unblocksignals(void);
-int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-
-
-void runtime·raisesigpipe(void);
-void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
-void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
-void runtime·sigpanic(void);
-
-enum {
- SS_DISABLE = 2,
- SIG_BLOCK = 1,
- SIG_UNBLOCK = 2,
- SIG_SETMASK = 3,
- NSIG = 73, /* number of signals in runtime·SigTab array */
- SI_USER = 0,
- _UC_SIGMASK = 0x01,
- _UC_CPU = 0x04,
- RLIMIT_AS = 10,
-};
-
-typedef struct Rlimit Rlimit;
-struct Rlimit {
- int64 rlim_cur;
- int64 rlim_max;
-};
-int32 runtime·getrlimit(int32, Rlimit*);
-
-// Call an external library function described by {fn, a0, ..., an}, with
-// SysV conventions, switching to os stack during the call, if necessary.
-uintptr runtime·sysvicall0(uintptr fn);
-uintptr runtime·sysvicall1(uintptr fn, uintptr a1);
-uintptr runtime·sysvicall2(uintptr fn, uintptr a1, uintptr a2);
-uintptr runtime·sysvicall3(uintptr fn, uintptr a1, uintptr a2, uintptr a3);
-uintptr runtime·sysvicall4(uintptr fn, uintptr a1, uintptr a2, uintptr a3, uintptr a4);
-uintptr runtime·sysvicall5(uintptr fn, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5);
-uintptr runtime·sysvicall6(uintptr fn, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6);
-void runtime·asmsysvicall6(void *c);
-
-void runtime·miniterrno(void *fn);
diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c
deleted file mode 100644
index b8b8eda5f..000000000
--- a/src/runtime/os_windows.c
+++ /dev/null
@@ -1,636 +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.
-
-#include "runtime.h"
-#include "type.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "textflag.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
-#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
-#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
-#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
-#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll"
-#pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
-#pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll"
-#pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll"
-#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll"
-#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
-#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
-#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
-#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
-#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
-#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll"
-#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll"
-#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll"
-#pragma dynimport runtime·LoadLibraryA LoadLibraryA "kernel32.dll"
-#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
-#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll"
-#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
-#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
-#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
-#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
-#pragma dynimport runtime·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll"
-#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
-#pragma dynimport runtime·Sleep Sleep "kernel32.dll"
-#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
-#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
-#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
-#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
-
-extern void *runtime·AddVectoredExceptionHandler;
-extern void *runtime·CloseHandle;
-extern void *runtime·CreateEvent;
-extern void *runtime·CreateThread;
-extern void *runtime·CreateWaitableTimer;
-extern void *runtime·CryptAcquireContextW;
-extern void *runtime·CryptGenRandom;
-extern void *runtime·CryptReleaseContext;
-extern void *runtime·DuplicateHandle;
-extern void *runtime·ExitProcess;
-extern void *runtime·FreeEnvironmentStringsW;
-extern void *runtime·GetEnvironmentStringsW;
-extern void *runtime·GetProcAddress;
-extern void *runtime·GetStdHandle;
-extern void *runtime·GetSystemInfo;
-extern void *runtime·GetThreadContext;
-extern void *runtime·LoadLibrary;
-extern void *runtime·LoadLibraryA;
-extern void *runtime·NtWaitForSingleObject;
-extern void *runtime·ResumeThread;
-extern void *runtime·SetConsoleCtrlHandler;
-extern void *runtime·SetEvent;
-extern void *runtime·SetProcessPriorityBoost;
-extern void *runtime·SetThreadPriority;
-extern void *runtime·SetUnhandledExceptionFilter;
-extern void *runtime·SetWaitableTimer;
-extern void *runtime·Sleep;
-extern void *runtime·SuspendThread;
-extern void *runtime·WaitForSingleObject;
-extern void *runtime·WriteFile;
-extern void *runtime·timeBeginPeriod;
-
-#pragma dataflag NOPTR
-void *runtime·GetQueuedCompletionStatusEx;
-
-extern uintptr runtime·externalthreadhandlerp;
-void runtime·externalthreadhandler(void);
-void runtime·exceptiontramp(void);
-void runtime·firstcontinuetramp(void);
-void runtime·lastcontinuetramp(void);
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·getLoadLibrary(void)
-{
- return (uintptr)runtime·LoadLibrary;
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·getGetProcAddress(void)
-{
- return (uintptr)runtime·GetProcAddress;
-}
-
-static int32
-getproccount(void)
-{
- SystemInfo info;
-
- runtime·stdcall1(runtime·GetSystemInfo, (uintptr)&info);
- return info.dwNumberOfProcessors;
-}
-
-void
-runtime·osinit(void)
-{
- void *kernel32;
- void *addVectoredContinueHandler;
-
- kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll");
-
- runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
-
- runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp);
- addVectoredContinueHandler = nil;
- if(kernel32 != nil)
- addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler");
- if(addVectoredContinueHandler == nil || sizeof(void*) == 4) {
- // use SetUnhandledExceptionFilter for windows-386 or
- // if VectoredContinueHandler is unavailable.
- // note: SetUnhandledExceptionFilter handler won't be called, if debugging.
- runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp);
- } else {
- runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp);
- runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp);
- }
-
- runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1);
-
- runtime·stdcall1(runtime·timeBeginPeriod, 1);
-
- runtime·ncpu = getproccount();
-
- // Windows dynamic priority boosting assumes that a process has different types
- // of dedicated threads -- GUI, IO, computational, etc. Go processes use
- // equivalent threads that all do a mix of GUI, IO, computations, etc.
- // In such context dynamic priority boosting does nothing but harm, so we turn it off.
- runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1);
-
- if(kernel32 != nil) {
- runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx");
- }
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
- uintptr handle;
- *rnd = nil;
- *rnd_len = 0;
- if(runtime·stdcall5(runtime·CryptAcquireContextW, (uintptr)&handle, (uintptr)nil, (uintptr)nil,
- 1 /* PROV_RSA_FULL */,
- 0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) {
- static byte random_data[HashRandomBytes];
- if(runtime·stdcall3(runtime·CryptGenRandom, handle, HashRandomBytes, (uintptr)&random_data[0])) {
- *rnd = random_data;
- *rnd_len = HashRandomBytes;
- }
- runtime·stdcall2(runtime·CryptReleaseContext, handle, 0);
- }
-}
-
-void
-runtime·goenvs(void)
-{
- extern Slice runtime·envs;
-
- uint16 *env;
- String *s;
- int32 i, n;
- uint16 *p;
-
- env = runtime·stdcall0(runtime·GetEnvironmentStringsW);
-
- n = 0;
- for(p=env; *p; n++)
- p += runtime·findnullw(p)+1;
-
- runtime·envs = runtime·makeStringSlice(n);
- s = (String*)runtime·envs.array;
-
- p = env;
- for(i=0; i<n; i++) {
- s[i] = runtime·gostringw(p);
- p += runtime·findnullw(p)+1;
- }
-
- runtime·stdcall1(runtime·FreeEnvironmentStringsW, (uintptr)env);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·exit(int32 code)
-{
- runtime·stdcall1(runtime·ExitProcess, code);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·write(uintptr fd, void *buf, int32 n)
-{
- void *handle;
- uint32 written;
-
- written = 0;
- switch(fd) {
- case 1:
- handle = runtime·stdcall1(runtime·GetStdHandle, -11);
- break;
- case 2:
- handle = runtime·stdcall1(runtime·GetStdHandle, -12);
- break;
- default:
- // assume fd is real windows handle.
- handle = (void*)fd;
- break;
- }
- runtime·stdcall5(runtime·WriteFile, (uintptr)handle, (uintptr)buf, n, (uintptr)&written, 0);
- return written;
-}
-
-#define INFINITE ((uintptr)0xFFFFFFFF)
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
- // store ms in ns to save stack space
- if(ns < 0)
- ns = INFINITE;
- else {
- ns = runtime·timediv(ns, 1000000, nil);
- if(ns == 0)
- ns = 1;
- }
- if(runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)g->m->waitsema, ns) != 0)
- return -1; // timeout
- return 0;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
- runtime·stdcall1(runtime·SetEvent, mp->waitsema);
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
- return (uintptr)runtime·stdcall4(runtime·CreateEvent, 0, 0, 0, 0);
-}
-
-#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
- void *thandle;
-
- USED(stk);
-
- thandle = runtime·stdcall6(runtime·CreateThread,
- (uintptr)nil, 0x20000, (uintptr)runtime·tstart_stdcall, (uintptr)mp,
- STACK_SIZE_PARAM_IS_A_RESERVATION, (uintptr)nil);
- if(thandle == nil) {
- runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
- runtime·throw("runtime.newosproc");
- }
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
- USED(mp);
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
- uintptr thandle;
-
- // -1 = current process, -2 = current thread
- runtime·stdcall7(runtime·DuplicateHandle, -1, -2, -1, (uintptr)&thandle, 0, 0, DUPLICATE_SAME_ACCESS);
- runtime·atomicstoreuintptr(&g->m->thread, thandle);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
- runtime·stdcall1(runtime·CloseHandle, g->m->thread);
- g->m->thread = 0;
-}
-
-// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
-typedef struct KSYSTEM_TIME {
- uint32 LowPart;
- int32 High1Time;
- int32 High2Time;
-} KSYSTEM_TIME;
-
-#pragma dataflag NOPTR
-const KSYSTEM_TIME* INTERRUPT_TIME = (KSYSTEM_TIME*)0x7ffe0008;
-#pragma dataflag NOPTR
-const KSYSTEM_TIME* SYSTEM_TIME = (KSYSTEM_TIME*)0x7ffe0014;
-
-static void badsystime(void);
-
-#pragma textflag NOSPLIT
-int64
-runtime·systime(KSYSTEM_TIME *timeaddr)
-{
- KSYSTEM_TIME t;
- int32 i;
- void (*fn)(void);
-
- for(i = 1; i < 10000; i++) {
- // these fields must be read in that order (see URL above)
- t.High1Time = timeaddr->High1Time;
- t.LowPart = timeaddr->LowPart;
- t.High2Time = timeaddr->High2Time;
- if(t.High1Time == t.High2Time)
- return (int64)t.High1Time<<32 | t.LowPart;
- if((i%100) == 0)
- runtime·osyield();
- }
- fn = badsystime;
- runtime·onM(&fn);
- return 0;
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·unixnano(void)
-{
- return (runtime·systime(SYSTEM_TIME) - 116444736000000000LL) * 100LL;
-}
-
-static void
-badsystime(void)
-{
- runtime·throw("interrupt/system time is changing too fast");
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·nanotime(void)
-{
- return runtime·systime(INTERRUPT_TIME) * 100LL;
-}
-
-// Calling stdcall on os stack.
-#pragma textflag NOSPLIT
-static void*
-stdcall(void *fn)
-{
- g->m->libcall.fn = (uintptr)fn;
- if(g->m->profilehz != 0) {
- // leave pc/sp for cpu profiler
- g->m->libcallg = g;
- g->m->libcallpc = (uintptr)runtime·getcallerpc(&fn);
- // sp must be the last, because once async cpu profiler finds
- // all three values to be non-zero, it will use them
- g->m->libcallsp = (uintptr)runtime·getcallersp(&fn);
- }
- runtime·asmcgocall(runtime·asmstdcall, &g->m->libcall);
- g->m->libcallsp = 0;
- return (void*)g->m->libcall.r1;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall0(void *fn)
-{
- g->m->libcall.n = 0;
- g->m->libcall.args = (uintptr)&fn; // it's unused but must be non-nil, otherwise crashes
- return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall1(void *fn, uintptr a0)
-{
- USED(a0);
- g->m->libcall.n = 1;
- g->m->libcall.args = (uintptr)&a0;
- return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall2(void *fn, uintptr a0, uintptr a1)
-{
- USED(a0, a1);
- g->m->libcall.n = 2;
- g->m->libcall.args = (uintptr)&a0;
- return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2)
-{
- USED(a0, a1, a2);
- g->m->libcall.n = 3;
- g->m->libcall.args = (uintptr)&a0;
- return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3)
-{
- USED(a0, a1, a2, a3);
- g->m->libcall.n = 4;
- g->m->libcall.args = (uintptr)&a0;
- return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4)
-{
- USED(a0, a1, a2, a3, a4);
- g->m->libcall.n = 5;
- g->m->libcall.args = (uintptr)&a0;
- return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5)
-{
- USED(a0, a1, a2, a3, a4, a5);
- g->m->libcall.n = 6;
- g->m->libcall.args = (uintptr)&a0;
- return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6)
-{
- USED(a0, a1, a2, a3, a4, a5, a6);
- g->m->libcall.n = 7;
- g->m->libcall.args = (uintptr)&a0;
- return stdcall(fn);
-}
-
-extern void runtime·usleep1(uint32);
-
-#pragma textflag NOSPLIT
-void
-runtime·osyield(void)
-{
- runtime·usleep1(1);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·usleep(uint32 us)
-{
- // Have 1us units; want 100ns units.
- runtime·usleep1(10*us);
-}
-
-uint32
-runtime·issigpanic(uint32 code)
-{
- switch(code) {
- case EXCEPTION_ACCESS_VIOLATION:
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- case EXCEPTION_INT_OVERFLOW:
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- case EXCEPTION_FLT_INEXACT_RESULT:
- case EXCEPTION_FLT_OVERFLOW:
- case EXCEPTION_FLT_UNDERFLOW:
- case EXCEPTION_BREAKPOINT:
- return 1;
- }
- return 0;
-}
-
-void
-runtime·initsig(void)
-{
- // following line keeps these functions alive at link stage
- // if there's a better way please write it here
- void *e = runtime·exceptiontramp;
- void *f = runtime·firstcontinuetramp;
- void *l = runtime·lastcontinuetramp;
- USED(e);
- USED(f);
- USED(l);
-}
-
-uint32
-runtime·ctrlhandler1(uint32 type)
-{
- int32 s;
-
- switch(type) {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
- s = SIGINT;
- break;
- default:
- return 0;
- }
-
- if(runtime·sigsend(s))
- return 1;
- runtime·exit(2); // SIGINT, SIGTERM, etc
- return 0;
-}
-
-extern void runtime·dosigprof(Context *r, G *gp, M *mp);
-extern void runtime·profileloop(void);
-#pragma dataflag NOPTR
-static void *profiletimer;
-
-static void
-profilem(M *mp)
-{
- extern M runtime·m0;
- extern uint32 runtime·tls0[];
- byte rbuf[sizeof(Context)+15];
- Context *r;
- void *tls;
- G *gp;
-
- tls = mp->tls;
- if(mp == &runtime·m0)
- tls = runtime·tls0;
- gp = *(G**)tls;
-
- // align Context to 16 bytes
- r = (Context*)((uintptr)(&rbuf[15]) & ~15);
- r->ContextFlags = CONTEXT_CONTROL;
- runtime·stdcall2(runtime·GetThreadContext, (uintptr)mp->thread, (uintptr)r);
- runtime·dosigprof(r, gp, mp);
-}
-
-void
-runtime·profileloop1(void)
-{
- M *mp, *allm;
- uintptr thread;
-
- runtime·stdcall2(runtime·SetThreadPriority, -2, THREAD_PRIORITY_HIGHEST);
-
- for(;;) {
- runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)profiletimer, -1);
- allm = runtime·atomicloadp(&runtime·allm);
- for(mp = allm; mp != nil; mp = mp->alllink) {
- thread = runtime·atomicloaduintptr(&mp->thread);
- // Do not profile threads blocked on Notes,
- // this includes idle worker threads,
- // idle timer thread, idle heap scavenger, etc.
- if(thread == 0 || mp->profilehz == 0 || mp->blocked)
- continue;
- runtime·stdcall1(runtime·SuspendThread, (uintptr)thread);
- if(mp->profilehz != 0 && !mp->blocked)
- profilem(mp);
- runtime·stdcall1(runtime·ResumeThread, (uintptr)thread);
- }
- }
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- static Mutex lock;
- void *timer, *thread;
- int32 ms;
- int64 due;
-
- runtime·lock(&lock);
- if(profiletimer == nil) {
- timer = runtime·stdcall3(runtime·CreateWaitableTimer, (uintptr)nil, (uintptr)nil, (uintptr)nil);
- runtime·atomicstorep(&profiletimer, timer);
- thread = runtime·stdcall6(runtime·CreateThread,
- (uintptr)nil, (uintptr)nil, (uintptr)runtime·profileloop, (uintptr)nil, (uintptr)nil, (uintptr)nil);
- runtime·stdcall2(runtime·SetThreadPriority, (uintptr)thread, THREAD_PRIORITY_HIGHEST);
- runtime·stdcall1(runtime·CloseHandle, (uintptr)thread);
- }
- runtime·unlock(&lock);
-
- ms = 0;
- due = 1LL<<63;
- if(hz > 0) {
- ms = 1000 / hz;
- if(ms == 0)
- ms = 1;
- due = ms * -10000;
- }
- runtime·stdcall6(runtime·SetWaitableTimer,
- (uintptr)profiletimer, (uintptr)&due, ms, (uintptr)nil, (uintptr)nil, (uintptr)nil);
- runtime·atomicstore((uint32*)&g->m->profilehz, hz);
-}
-
-uintptr
-runtime·memlimit(void)
-{
- return 0;
-}
-
-#pragma dataflag NOPTR
-int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n";
-int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1;
-
-void
-runtime·crash(void)
-{
- // TODO: This routine should do whatever is needed
- // to make the Windows program abort/crash as it
- // would if Go was not intercepting signals.
- // On Unix the routine would remove the custom signal
- // handler and then raise a signal (like SIGABRT).
- // Something like that should happen here.
- // It's okay to leave this empty for now: if crash returns
- // the ordinary exit-after-panic happens.
-}
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 1528d2fd1..097b5d629 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -4,28 +4,8 @@
package runtime
-import "unsafe"
-
type stdFunction *byte
-func stdcall0(fn stdFunction) uintptr
-func stdcall1(fn stdFunction, a0 uintptr) uintptr
-func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr
-func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr
-func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr
-func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr
-func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr
-func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr
-
-func asmstdcall(fn unsafe.Pointer)
-func getlasterror() uint32
-func setlasterror(err uint32)
-func usleep1(usec uint32)
-func netpollinit()
-func netpollopen(fd uintptr, pd *pollDesc) int32
-func netpollclose(fd uintptr) int32
-func netpollarm(pd *pollDesc, mode int)
-
func os_sigpipe() {
gothrow("too many writes on closed pipe")
}
diff --git a/src/runtime/os_windows.h b/src/runtime/os_windows.h
deleted file mode 100644
index d5d168d77..000000000
--- a/src/runtime/os_windows.h
+++ /dev/null
@@ -1,42 +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.
-
-extern void *runtime·LoadLibrary;
-extern void *runtime·GetProcAddress;
-extern void *runtime·GetQueuedCompletionStatusEx;
-
-// Call a Windows function with stdcall conventions,
-// and switch to os stack during the call.
-void runtime·asmstdcall(void *c);
-void *runtime·stdcall0(void *fn);
-void *runtime·stdcall1(void *fn, uintptr a0);
-void *runtime·stdcall2(void *fn, uintptr a0, uintptr a1);
-void *runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2);
-void *runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3);
-void *runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4);
-void *runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5);
-void *runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6);
-
-uint32 runtime·getlasterror(void);
-void runtime·setlasterror(uint32 err);
-
-// Function to be called by windows CreateThread
-// to start new os thread.
-uint32 runtime·tstart_stdcall(M *newm);
-
-uint32 runtime·issigpanic(uint32);
-void runtime·sigpanic(void);
-uint32 runtime·ctrlhandler(uint32 type);
-
-// Windows dll function to go callback entry.
-byte *runtime·compilecallback(Eface fn, bool cleanstack);
-void *runtime·callbackasm(void);
-
-void runtime·install_exception_handler(void);
-void runtime·remove_exception_handler(void);
-
-// TODO(brainman): should not need those
-enum {
- NSIG = 65,
-};
diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c
deleted file mode 100644
index 9962f0dc2..000000000
--- a/src/runtime/os_windows_386.c
+++ /dev/null
@@ -1,128 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-void
-runtime·dumpregs(Context *r)
-{
- runtime·printf("eax %x\n", r->Eax);
- runtime·printf("ebx %x\n", r->Ebx);
- runtime·printf("ecx %x\n", r->Ecx);
- runtime·printf("edx %x\n", r->Edx);
- runtime·printf("edi %x\n", r->Edi);
- runtime·printf("esi %x\n", r->Esi);
- runtime·printf("ebp %x\n", r->Ebp);
- runtime·printf("esp %x\n", r->Esp);
- runtime·printf("eip %x\n", r->Eip);
- runtime·printf("eflags %x\n", r->EFlags);
- runtime·printf("cs %x\n", r->SegCs);
- runtime·printf("fs %x\n", r->SegFs);
- runtime·printf("gs %x\n", r->SegGs);
-}
-
-bool
-runtime·isgoexception(ExceptionRecord *info, Context *r)
-{
- extern byte runtime·text[], runtime·etext[];
-
- // Only handle exception if executing instructions in Go binary
- // (not Windows library code).
- if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip)
- return false;
-
- if(!runtime·issigpanic(info->ExceptionCode))
- return false;
-
- return true;
-}
-
-// Called by sigtramp from Windows VEH handler.
-// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
-// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
-uint32
-runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
-{
- uintptr *sp;
-
- if(!runtime·isgoexception(info, r))
- return EXCEPTION_CONTINUE_SEARCH;
-
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp->sig = info->ExceptionCode;
- gp->sigcode0 = info->ExceptionInformation[0];
- gp->sigcode1 = info->ExceptionInformation[1];
- gp->sigpc = r->Eip;
-
- // Only push runtime·sigpanic if r->eip != 0.
- // If r->eip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->Eip != 0) {
- sp = (uintptr*)r->Esp;
- *--sp = r->Eip;
- r->Esp = (uintptr)sp;
- }
- r->Eip = (uintptr)runtime·sigpanic;
- return EXCEPTION_CONTINUE_EXECUTION;
-}
-
-// lastcontinuehandler is reached, because runtime cannot handle
-// current exception. lastcontinuehandler will print crash info and exit.
-uint32
-runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
-{
- bool crash;
-
- if(runtime·panicking) // traceback already printed
- runtime·exit(2);
- runtime·panicking = 1;
-
- runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
- (uintptr)info->ExceptionInformation[0], (uintptr)info->ExceptionInformation[1], (uintptr)r->Eip);
-
- runtime·printf("PC=%x\n", r->Eip);
- if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = g->m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback(&crash)){
- runtime·tracebacktrap(r->Eip, r->Esp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(r);
- }
-
- if(crash)
- runtime·crash();
-
- runtime·exit(2);
- return 0; // not reached
-}
-
-void
-runtime·sigenable(uint32 sig)
-{
- USED(sig);
-}
-
-void
-runtime·sigdisable(uint32 sig)
-{
- USED(sig);
-}
-
-void
-runtime·dosigprof(Context *r, G *gp, M *mp)
-{
- runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp);
-}
diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c
deleted file mode 100644
index e4617e4ce..000000000
--- a/src/runtime/os_windows_amd64.c
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2011 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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-void
-runtime·dumpregs(Context *r)
-{
- runtime·printf("rax %X\n", r->Rax);
- runtime·printf("rbx %X\n", r->Rbx);
- runtime·printf("rcx %X\n", r->Rcx);
- runtime·printf("rdx %X\n", r->Rdx);
- runtime·printf("rdi %X\n", r->Rdi);
- runtime·printf("rsi %X\n", r->Rsi);
- runtime·printf("rbp %X\n", r->Rbp);
- runtime·printf("rsp %X\n", r->Rsp);
- runtime·printf("r8 %X\n", r->R8 );
- runtime·printf("r9 %X\n", r->R9 );
- runtime·printf("r10 %X\n", r->R10);
- runtime·printf("r11 %X\n", r->R11);
- runtime·printf("r12 %X\n", r->R12);
- runtime·printf("r13 %X\n", r->R13);
- runtime·printf("r14 %X\n", r->R14);
- runtime·printf("r15 %X\n", r->R15);
- runtime·printf("rip %X\n", r->Rip);
- runtime·printf("rflags %X\n", r->EFlags);
- runtime·printf("cs %X\n", (uint64)r->SegCs);
- runtime·printf("fs %X\n", (uint64)r->SegFs);
- runtime·printf("gs %X\n", (uint64)r->SegGs);
-}
-
-bool
-runtime·isgoexception(ExceptionRecord *info, Context *r)
-{
- extern byte runtime·text[], runtime·etext[];
-
- // Only handle exception if executing instructions in Go binary
- // (not Windows library code).
- if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip)
- return false;
-
- if(!runtime·issigpanic(info->ExceptionCode))
- return false;
-
- return true;
-}
-
-// Called by sigtramp from Windows VEH handler.
-// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
-// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
-uint32
-runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
-{
- uintptr *sp;
-
- if(!runtime·isgoexception(info, r))
- return EXCEPTION_CONTINUE_SEARCH;
-
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp->sig = info->ExceptionCode;
- gp->sigcode0 = info->ExceptionInformation[0];
- gp->sigcode1 = info->ExceptionInformation[1];
- gp->sigpc = r->Rip;
-
- // Only push runtime·sigpanic if r->rip != 0.
- // If r->rip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->Rip != 0) {
- sp = (uintptr*)r->Rsp;
- *--sp = r->Rip;
- r->Rsp = (uintptr)sp;
- }
- r->Rip = (uintptr)runtime·sigpanic;
- return EXCEPTION_CONTINUE_EXECUTION;
-}
-
-// It seems Windows searches ContinueHandler's list even
-// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
-// firstcontinuehandler will stop that search,
-// if exceptionhandler did the same earlier.
-uint32
-runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
-{
- USED(gp);
- if(!runtime·isgoexception(info, r))
- return EXCEPTION_CONTINUE_SEARCH;
- return EXCEPTION_CONTINUE_EXECUTION;
-}
-
-// lastcontinuehandler is reached, because runtime cannot handle
-// current exception. lastcontinuehandler will print crash info and exit.
-uint32
-runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
-{
- bool crash;
-
- if(runtime·panicking) // traceback already printed
- runtime·exit(2);
- runtime·panicking = 1;
-
- runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
- info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip);
-
-
- runtime·printf("PC=%X\n", r->Rip);
- if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = g->m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback(&crash)){
- runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(r);
- }
-
- if(crash)
- runtime·crash();
-
- runtime·exit(2);
- return 0; // not reached
-}
-
-void
-runtime·sigenable(uint32 sig)
-{
- USED(sig);
-}
-
-void
-runtime·sigdisable(uint32 sig)
-{
- USED(sig);
-}
-
-void
-runtime·dosigprof(Context *r, G *gp, M *mp)
-{
- runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp);
-}
diff --git a/src/runtime/panic.c b/src/runtime/panic.c
deleted file mode 100644
index 24eb6dbfe..000000000
--- a/src/runtime/panic.c
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2012 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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "stack.h"
-#include "malloc.h"
-#include "textflag.h"
-
-// Code related to defer, panic and recover.
-
-// TODO: remove once code is moved to Go
-extern Defer* runtime·newdefer(int32 siz);
-extern runtime·freedefer(Defer *d);
-
-uint32 runtime·panicking;
-static Mutex paniclk;
-
-void
-runtime·deferproc_m(void)
-{
- int32 siz;
- FuncVal *fn;
- uintptr argp;
- uintptr callerpc;
- Defer *d;
-
- siz = g->m->scalararg[0];
- fn = g->m->ptrarg[0];
- argp = g->m->scalararg[1];
- callerpc = g->m->scalararg[2];
- g->m->ptrarg[0] = nil;
- g->m->scalararg[1] = 0;
-
- d = runtime·newdefer(siz);
- if(d->panic != nil)
- runtime·throw("deferproc: d->panic != nil after newdefer");
- d->fn = fn;
- d->pc = callerpc;
- d->argp = argp;
- runtime·memmove(d+1, (void*)argp, siz);
-}
-
-// Unwind the stack after a deferred function calls recover
-// after a panic. Then arrange to continue running as though
-// the caller of the deferred function returned normally.
-void
-runtime·recovery_m(G *gp)
-{
- void *argp;
- uintptr pc;
-
- // Info about defer passed in G struct.
- argp = (void*)gp->sigcode0;
- pc = (uintptr)gp->sigcode1;
-
- // d's arguments need to be in the stack.
- if(argp != nil && ((uintptr)argp < gp->stack.lo || gp->stack.hi < (uintptr)argp)) {
- runtime·printf("recover: %p not in [%p, %p]\n", argp, gp->stack.lo, gp->stack.hi);
- runtime·throw("bad recovery");
- }
-
- // Make the deferproc for this d return again,
- // this time returning 1. The calling function will
- // jump to the standard return epilogue.
- // The -2*sizeof(uintptr) makes up for the
- // two extra words that are on the stack at
- // each call to deferproc.
- // (The pc we're returning to does pop pop
- // before it tests the return value.)
- // On the arm there are 2 saved LRs mixed in too.
- if(thechar == '5')
- gp->sched.sp = (uintptr)argp - 4*sizeof(uintptr);
- else
- gp->sched.sp = (uintptr)argp - 2*sizeof(uintptr);
- gp->sched.pc = pc;
- gp->sched.lr = 0;
- gp->sched.ret = 1;
- runtime·gogo(&gp->sched);
-}
-
-void
-runtime·startpanic_m(void)
-{
- if(runtime·mheap.cachealloc.size == 0) { // very early
- runtime·printf("runtime: panic before malloc heap initialized\n");
- g->m->mallocing = 1; // tell rest of panic not to try to malloc
- } else if(g->m->mcache == nil) // can happen if called from signal handler or throw
- g->m->mcache = runtime·allocmcache();
- switch(g->m->dying) {
- case 0:
- g->m->dying = 1;
- if(g != nil) {
- g->writebuf.array = nil;
- g->writebuf.len = 0;
- g->writebuf.cap = 0;
- }
- runtime·xadd(&runtime·panicking, 1);
- runtime·lock(&paniclk);
- if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0)
- runtime·schedtrace(true);
- runtime·freezetheworld();
- return;
- case 1:
- // Something failed while panicing, probably the print of the
- // argument to panic(). Just print a stack trace and exit.
- g->m->dying = 2;
- runtime·printf("panic during panic\n");
- runtime·dopanic(0);
- runtime·exit(3);
- case 2:
- // This is a genuine bug in the runtime, we couldn't even
- // print the stack trace successfully.
- g->m->dying = 3;
- runtime·printf("stack trace unavailable\n");
- runtime·exit(4);
- default:
- // Can't even print! Just exit.
- runtime·exit(5);
- }
-}
-
-void
-runtime·dopanic_m(void)
-{
- G *gp;
- uintptr sp, pc;
- static bool didothers;
- bool crash;
- int32 t;
-
- gp = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- pc = g->m->scalararg[0];
- sp = g->m->scalararg[1];
- g->m->scalararg[1] = 0;
- if(gp->sig != 0)
- runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
- gp->sig, gp->sigcode0, gp->sigcode1, gp->sigpc);
-
- if((t = runtime·gotraceback(&crash)) > 0){
- if(gp != gp->m->g0) {
- runtime·printf("\n");
- runtime·goroutineheader(gp);
- runtime·traceback(pc, sp, 0, gp);
- } else if(t >= 2 || g->m->throwing > 0) {
- runtime·printf("\nruntime stack:\n");
- runtime·traceback(pc, sp, 0, gp);
- }
- if(!didothers) {
- didothers = true;
- runtime·tracebackothers(gp);
- }
- }
- runtime·unlock(&paniclk);
- if(runtime·xadd(&runtime·panicking, -1) != 0) {
- // Some other m is panicking too.
- // Let it print what it needs to print.
- // Wait forever without chewing up cpu.
- // It will exit when it's done.
- static Mutex deadlock;
- runtime·lock(&deadlock);
- runtime·lock(&deadlock);
- }
-
- if(crash)
- runtime·crash();
-
- runtime·exit(2);
-}
-
-#pragma textflag NOSPLIT
-bool
-runtime·canpanic(G *gp)
-{
- M *m;
- uint32 status;
-
- // Note that g is m->gsignal, different from gp.
- // Note also that g->m can change at preemption, so m can go stale
- // if this function ever makes a function call.
- m = g->m;
-
- // Is it okay for gp to panic instead of crashing the program?
- // Yes, as long as it is running Go code, not runtime code,
- // and not stuck in a system call.
- 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)
- return false;
- status = runtime·readgstatus(gp);
- if((status&~Gscan) != Grunning || gp->syscallsp != 0)
- return false;
-#ifdef GOOS_windows
- if(m->libcallsp != 0)
- return false;
-#endif
- return true;
-}
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 685ff5ca0..95e780b1d 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -54,6 +54,11 @@ func throwinit() {
// The compiler turns a defer statement into a call to this.
//go:nosplit
func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
+ if getg().m.curg != getg() {
+ // go code on the system stack can't defer
+ gothrow("defer on system stack")
+ }
+
// the arguments of fn are in a perilous state. The stack map
// for deferproc does not describe them. So we can't let garbage
// collection or stack copying trigger until we've copied them out
@@ -61,23 +66,21 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
// we can only call nosplit routines.
argp := uintptr(unsafe.Pointer(&fn))
argp += unsafe.Sizeof(fn)
- if GOARCH == "arm" {
+ if GOARCH == "arm" || GOARCH == "power64" || GOARCH == "power64le" {
argp += ptrSize // skip caller's saved link register
}
- mp := acquirem()
- mp.scalararg[0] = uintptr(siz)
- mp.ptrarg[0] = unsafe.Pointer(fn)
- mp.scalararg[1] = argp
- mp.scalararg[2] = getcallerpc(unsafe.Pointer(&siz))
-
- if mp.curg != getg() {
- // go code on the m stack can't defer
- gothrow("defer on m")
- }
+ callerpc := getcallerpc(unsafe.Pointer(&siz))
- onM(deferproc_m)
-
- releasem(mp)
+ systemstack(func() {
+ d := newdefer(siz)
+ if d._panic != nil {
+ gothrow("deferproc: d.panic != nil after newdefer")
+ }
+ d.fn = fn
+ d.pc = callerpc
+ d.argp = argp
+ memmove(add(unsafe.Pointer(d), unsafe.Sizeof(*d)), unsafe.Pointer(argp), uintptr(siz))
+ })
// deferproc returns 0 normally.
// a deferred func that stops a panic
@@ -159,7 +162,7 @@ func init() {
// Allocate a Defer, usually using per-P pool.
// Each defer must be released with freedefer.
-// Note: runs on M stack
+// Note: runs on g0 stack
func newdefer(siz int32) *_defer {
var d *_defer
sc := deferclass(uintptr(siz))
@@ -298,8 +301,6 @@ func Goexit() {
goexit()
}
-func canpanic(*g) bool
-
// Print all currently active panics. Used when crashing.
func printpanics(p *_panic) {
if p.link != nil {
@@ -318,7 +319,10 @@ func printpanics(p *_panic) {
func gopanic(e interface{}) {
gp := getg()
if gp.m.curg != gp {
- gothrow("panic on m stack")
+ print("panic: ")
+ printany(e)
+ print("\n")
+ gothrow("panic on system stack")
}
// m.softfloat is set during software floating point.
@@ -414,7 +418,7 @@ func gopanic(e interface{}) {
// Pass information about recovering frame to recovery.
gp.sigcode0 = uintptr(argp)
gp.sigcode1 = pc
- mcall(recovery_m)
+ mcall(recovery)
gothrow("recovery failed") // mcall should not return
}
}
@@ -466,17 +470,17 @@ func gorecover(argp uintptr) interface{} {
//go:nosplit
func startpanic() {
- onM_signalok(startpanic_m)
+ systemstack(startpanic_m)
}
//go:nosplit
func dopanic(unused int) {
+ pc := getcallerpc(unsafe.Pointer(&unused))
+ sp := getcallersp(unsafe.Pointer(&unused))
gp := getg()
- mp := acquirem()
- mp.ptrarg[0] = unsafe.Pointer(gp)
- mp.scalararg[0] = getcallerpc((unsafe.Pointer)(&unused))
- mp.scalararg[1] = getcallersp((unsafe.Pointer)(&unused))
- onM_signalok(dopanic_m) // should never return
+ systemstack(func() {
+ dopanic_m(gp, pc, sp) // should never return
+ })
*(*int)(nil) = 0
}
@@ -494,12 +498,12 @@ func throw(s *byte) {
//go:nosplit
func gothrow(s string) {
+ print("fatal error: ", s, "\n")
gp := getg()
if gp.m.throwing == 0 {
gp.m.throwing = 1
}
startpanic()
- print("fatal error: ", s, "\n")
dopanic(0)
*(*int)(nil) = 0 // not reached
}
diff --git a/src/runtime/panic1.go b/src/runtime/panic1.go
new file mode 100644
index 000000000..17379f963
--- /dev/null
+++ b/src/runtime/panic1.go
@@ -0,0 +1,161 @@
+// Copyright 2012 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 runtime
+
+import "unsafe"
+
+// Code related to defer, panic and recover.
+// TODO: Merge into panic.go.
+
+//uint32 runtime·panicking;
+var paniclk mutex
+
+const hasLinkRegister = GOARCH == "arm" || GOARCH == "power64" || GOARCH == "power64le"
+
+// Unwind the stack after a deferred function calls recover
+// after a panic. Then arrange to continue running as though
+// the caller of the deferred function returned normally.
+func recovery(gp *g) {
+ // Info about defer passed in G struct.
+ argp := (unsafe.Pointer)(gp.sigcode0)
+ pc := uintptr(gp.sigcode1)
+
+ // d's arguments need to be in the stack.
+ if argp != nil && (uintptr(argp) < gp.stack.lo || gp.stack.hi < uintptr(argp)) {
+ print("recover: ", argp, " not in [", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n")
+ gothrow("bad recovery")
+ }
+
+ // Make the deferproc for this d return again,
+ // this time returning 1. The calling function will
+ // jump to the standard return epilogue.
+ // The -2*sizeof(uintptr) makes up for the
+ // two extra words that are on the stack at
+ // each call to deferproc.
+ // (The pc we're returning to does pop pop
+ // before it tests the return value.)
+ // On the arm and power there are 2 saved LRs mixed in too.
+ if hasLinkRegister {
+ gp.sched.sp = uintptr(argp) - 4*ptrSize
+ } else {
+ gp.sched.sp = uintptr(argp) - 2*ptrSize
+ }
+ gp.sched.pc = pc
+ gp.sched.lr = 0
+ gp.sched.ret = 1
+ gogo(&gp.sched)
+}
+
+func startpanic_m() {
+ _g_ := getg()
+ if mheap_.cachealloc.size == 0 { // very early
+ print("runtime: panic before malloc heap initialized\n")
+ _g_.m.mallocing = 1 // tell rest of panic not to try to malloc
+ } else if _g_.m.mcache == nil { // can happen if called from signal handler or throw
+ _g_.m.mcache = allocmcache()
+ }
+
+ switch _g_.m.dying {
+ case 0:
+ _g_.m.dying = 1
+ if _g_ != nil {
+ _g_.writebuf = nil
+ }
+ xadd(&panicking, 1)
+ lock(&paniclk)
+ if debug.schedtrace > 0 || debug.scheddetail > 0 {
+ schedtrace(true)
+ }
+ freezetheworld()
+ return
+ case 1:
+ // Something failed while panicing, probably the print of the
+ // argument to panic(). Just print a stack trace and exit.
+ _g_.m.dying = 2
+ print("panic during panic\n")
+ dopanic(0)
+ exit(3)
+ fallthrough
+ case 2:
+ // This is a genuine bug in the runtime, we couldn't even
+ // print the stack trace successfully.
+ _g_.m.dying = 3
+ print("stack trace unavailable\n")
+ exit(4)
+ fallthrough
+ default:
+ // Can't even print! Just exit.
+ exit(5)
+ }
+}
+
+var didothers bool
+var deadlock mutex
+
+func dopanic_m(gp *g, pc, sp uintptr) {
+ if gp.sig != 0 {
+ print("[signal ", hex(gp.sig), " code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n")
+ }
+
+ var docrash bool
+ _g_ := getg()
+ if t := gotraceback(&docrash); t > 0 {
+ if gp != gp.m.g0 {
+ print("\n")
+ goroutineheader(gp)
+ traceback(pc, sp, 0, gp)
+ } else if t >= 2 || _g_.m.throwing > 0 {
+ print("\nruntime stack:\n")
+ traceback(pc, sp, 0, gp)
+ }
+ if !didothers {
+ didothers = true
+ tracebackothers(gp)
+ }
+ }
+ unlock(&paniclk)
+
+ if xadd(&panicking, -1) != 0 {
+ // Some other m is panicking too.
+ // Let it print what it needs to print.
+ // Wait forever without chewing up cpu.
+ // It will exit when it's done.
+ lock(&deadlock)
+ lock(&deadlock)
+ }
+
+ if docrash {
+ crash()
+ }
+
+ exit(2)
+}
+
+//go:nosplit
+func canpanic(gp *g) bool {
+ // Note that g is m->gsignal, different from gp.
+ // Note also that g->m can change at preemption, so m can go stale
+ // if this function ever makes a function call.
+ _g_ := getg()
+ _m_ := _g_.m
+
+ // Is it okay for gp to panic instead of crashing the program?
+ // Yes, as long as it is running Go code, not runtime code,
+ // and not stuck in a system call.
+ 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 {
+ return false
+ }
+ status := readgstatus(gp)
+ if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
+ return false
+ }
+ if GOOS == "windows" && _m_.libcallsp != 0 {
+ return false
+ }
+ return true
+}
diff --git a/src/runtime/parfor.c b/src/runtime/parfor.c
deleted file mode 100644
index e44956840..000000000
--- a/src/runtime/parfor.c
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2012 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.
-
-// Parallel for algorithm.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-struct ParForThread
-{
- // the thread's iteration space [32lsb, 32msb)
- uint64 pos;
- // stats
- uint64 nsteal;
- uint64 nstealcnt;
- uint64 nprocyield;
- uint64 nosyield;
- uint64 nsleep;
- byte pad[CacheLineSize];
-};
-
-void
-runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32))
-{
- uint32 i, begin, end;
- uint64 *pos;
-
- if(desc == nil || nthr == 0 || nthr > desc->nthrmax || body == nil) {
- runtime·printf("desc=%p nthr=%d count=%d body=%p\n", desc, nthr, n, body);
- runtime·throw("parfor: invalid args");
- }
-
- 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;
- desc->nprocyield = 0;
- desc->nosyield = 0;
- desc->nsleep = 0;
- for(i=0; i<nthr; i++) {
- begin = (uint64)n*i / nthr;
- end = (uint64)n*(i+1) / nthr;
- pos = &desc->thr[i].pos;
- if(((uintptr)pos & 7) != 0)
- runtime·throw("parforsetup: pos is not aligned");
- *pos = (uint64)begin | (((uint64)end)<<32);
- }
-}
-
-void
-runtime·parfordo(ParFor *desc)
-{
- ParForThread *me;
- uint32 tid, begin, end, begin2, try, victim, i;
- uint64 *mypos, *victimpos, pos, newpos;
- void (*body)(ParFor*, uint32);
- bool idle;
-
- // Obtain 0-based thread index.
- tid = runtime·xadd(&desc->thrseq, 1) - 1;
- if(tid >= desc->nthr) {
- runtime·printf("tid=%d nthr=%d\n", tid, desc->nthr);
- runtime·throw("parfor: invalid tid");
- }
-
- // If single-threaded, just execute the for serially.
- if(desc->nthr==1) {
- for(i=0; i<desc->cnt; i++)
- desc->body(desc, i);
- return;
- }
-
- body = desc->body;
- me = &desc->thr[tid];
- mypos = &me->pos;
- for(;;) {
- for(;;) {
- // While there is local work,
- // bump low index and execute the iteration.
- pos = runtime·xadd64(mypos, 1);
- begin = (uint32)pos-1;
- end = (uint32)(pos>>32);
- if(begin < end) {
- body(desc, begin);
- continue;
- }
- break;
- }
-
- // Out of work, need to steal something.
- idle = false;
- for(try=0;; try++) {
- // If we don't see any work for long enough,
- // increment the done counter...
- if(try > desc->nthr*4 && !idle) {
- idle = true;
- runtime·xadd(&desc->done, 1);
- }
- // ...if all threads have incremented the counter,
- // we are done.
- if(desc->done + !idle == desc->nthr) {
- if(!idle)
- runtime·xadd(&desc->done, 1);
- goto exit;
- }
- // Choose a random victim for stealing.
- victim = runtime·fastrand1() % (desc->nthr-1);
- if(victim >= tid)
- victim++;
- victimpos = &desc->thr[victim].pos;
- for(;;) {
- // See if it has any work.
- pos = runtime·atomicload64(victimpos);
- begin = (uint32)pos;
- end = (uint32)(pos>>32);
- if(begin+1 >= end) {
- begin = end = 0;
- break;
- }
- if(idle) {
- runtime·xadd(&desc->done, -1);
- idle = false;
- }
- begin2 = begin + (end-begin)/2;
- newpos = (uint64)begin | (uint64)begin2<<32;
- if(runtime·cas64(victimpos, pos, newpos)) {
- begin = begin2;
- break;
- }
- }
- if(begin < end) {
- // Has successfully stolen some work.
- if(idle)
- runtime·throw("parfor: should not be idle");
- runtime·atomicstore64(mypos, (uint64)begin | (uint64)end<<32);
- me->nsteal++;
- me->nstealcnt += end-begin;
- break;
- }
- // Backoff.
- if(try < desc->nthr) {
- // nothing
- } else if (try < 4*desc->nthr) {
- me->nprocyield++;
- runtime·procyield(20);
- // If a caller asked not to wait for the others, exit now
- // (assume that most work is already done at this point).
- } else if (!desc->wait) {
- if(!idle)
- runtime·xadd(&desc->done, 1);
- goto exit;
- } else if (try < 6*desc->nthr) {
- me->nosyield++;
- runtime·osyield();
- } else {
- me->nsleep++;
- runtime·usleep(1);
- }
- }
- }
-exit:
- runtime·xadd64(&desc->nsteal, me->nsteal);
- runtime·xadd64(&desc->nstealcnt, me->nstealcnt);
- runtime·xadd64(&desc->nprocyield, me->nprocyield);
- runtime·xadd64(&desc->nosyield, me->nosyield);
- runtime·xadd64(&desc->nsleep, me->nsleep);
- me->nsteal = 0;
- me->nstealcnt = 0;
- me->nprocyield = 0;
- me->nosyield = 0;
- me->nsleep = 0;
-}
-
-// For testing from Go.
-void
-runtime·newparfor_m(void)
-{
- g->m->ptrarg[0] = runtime·parforalloc(g->m->scalararg[0]);
-}
-
-void
-runtime·parforsetup_m(void)
-{
- ParFor *desc;
- void *ctx;
- void (*body)(ParFor*, uint32);
-
- desc = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- ctx = g->m->ptrarg[1];
- g->m->ptrarg[1] = nil;
- body = g->m->ptrarg[2];
- g->m->ptrarg[2] = nil;
-
- runtime·parforsetup(desc, g->m->scalararg[0], g->m->scalararg[1], ctx, g->m->scalararg[2], body);
-}
-
-void
-runtime·parfordo_m(void)
-{
- ParFor *desc;
-
- desc = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- runtime·parfordo(desc);
-}
-
-void
-runtime·parforiters_m(void)
-{
- ParFor *desc;
- uintptr tid;
-
- desc = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- tid = g->m->scalararg[0];
- g->m->scalararg[0] = desc->thr[tid].pos;
- g->m->scalararg[1] = desc->thr[tid].pos>>32;
-}
diff --git a/src/runtime/parfor.go b/src/runtime/parfor.go
new file mode 100644
index 000000000..14870c9fe
--- /dev/null
+++ b/src/runtime/parfor.go
@@ -0,0 +1,186 @@
+// Copyright 2012 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.
+
+// Parallel for algorithm.
+
+package runtime
+
+import "unsafe"
+
+type parforthread struct {
+ // the thread's iteration space [32lsb, 32msb)
+ pos uint64
+ // stats
+ nsteal uint64
+ nstealcnt uint64
+ nprocyield uint64
+ nosyield uint64
+ nsleep uint64
+ 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 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 {
+ print("desc=", desc, " nthr=", nthr, " count=", n, " body=", body, "\n")
+ gothrow("parfor: invalid args")
+ }
+
+ desc.body = *(*unsafe.Pointer)(unsafe.Pointer(&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
+ desc.nprocyield = 0
+ desc.nosyield = 0
+ desc.nsleep = 0
+
+ for i := uint32(0); i < nthr; i++ {
+ 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 {
+ gothrow("parforsetup: pos is not aligned")
+ }
+ *pos = uint64(begin) | uint64(end)<<32
+ }
+}
+
+func parfordo(desc *parfor) {
+ // Obtain 0-based thread index.
+ tid := xadd(&desc.thrseq, 1) - 1
+ if tid >= desc.nthr {
+ print("tid=", tid, " nthr=", desc.nthr, "\n")
+ gothrow("parfor: invalid tid")
+ }
+
+ // If single-threaded, just execute the for serially.
+ body := *(*func(*parfor, uint32))(unsafe.Pointer(&desc.body))
+ if desc.nthr == 1 {
+ for i := uint32(0); i < desc.cnt; i++ {
+ body(desc, i)
+ }
+ return
+ }
+
+ me := desc_thr_index(desc, tid)
+ mypos := &me.pos
+ for {
+ for {
+ // While there is local work,
+ // bump low index and execute the iteration.
+ pos := xadd64(mypos, 1)
+ begin := uint32(pos) - 1
+ end := uint32(pos >> 32)
+ if begin < end {
+ body(desc, begin)
+ continue
+ }
+ break
+ }
+
+ // Out of work, need to steal something.
+ idle := false
+ for try := uint32(0); ; try++ {
+ // If we don't see any work for long enough,
+ // increment the done counter...
+ if try > desc.nthr*4 && !idle {
+ idle = true
+ xadd(&desc.done, 1)
+ }
+
+ // ...if all threads have incremented the counter,
+ // we are done.
+ extra := uint32(0)
+ if !idle {
+ extra = 1
+ }
+ if desc.done+extra == desc.nthr {
+ if !idle {
+ xadd(&desc.done, 1)
+ }
+ goto exit
+ }
+
+ // Choose a random victim for stealing.
+ var begin, end uint32
+ victim := fastrand1() % (desc.nthr - 1)
+ if victim >= tid {
+ victim++
+ }
+ victimpos := &desc_thr_index(desc, victim).pos
+ for {
+ // See if it has any work.
+ pos := atomicload64(victimpos)
+ begin = uint32(pos)
+ end = uint32(pos >> 32)
+ if begin+1 >= end {
+ end = 0
+ begin = end
+ break
+ }
+ if idle {
+ xadd(&desc.done, -1)
+ idle = false
+ }
+ begin2 := begin + (end-begin)/2
+ newpos := uint64(begin) | uint64(begin2)<<32
+ if cas64(victimpos, pos, newpos) {
+ begin = begin2
+ break
+ }
+ }
+ if begin < end {
+ // Has successfully stolen some work.
+ if idle {
+ gothrow("parfor: should not be idle")
+ }
+ atomicstore64(mypos, uint64(begin)|uint64(end)<<32)
+ me.nsteal++
+ me.nstealcnt += uint64(end) - uint64(begin)
+ break
+ }
+
+ // Backoff.
+ if try < desc.nthr {
+ // nothing
+ } else if try < 4*desc.nthr {
+ me.nprocyield++
+ procyield(20)
+ } else if !desc.wait {
+ // If a caller asked not to wait for the others, exit now
+ // (assume that most work is already done at this point).
+ if !idle {
+ xadd(&desc.done, 1)
+ }
+ goto exit
+ } else if try < 6*desc.nthr {
+ me.nosyield++
+ osyield()
+ } else {
+ me.nsleep++
+ usleep(1)
+ }
+ }
+ }
+
+exit:
+ xadd64(&desc.nsteal, int64(me.nsteal))
+ xadd64(&desc.nstealcnt, int64(me.nstealcnt))
+ xadd64(&desc.nprocyield, int64(me.nprocyield))
+ xadd64(&desc.nosyield, int64(me.nosyield))
+ xadd64(&desc.nsleep, int64(me.nsleep))
+ me.nsteal = 0
+ me.nstealcnt = 0
+ me.nprocyield = 0
+ me.nosyield = 0
+ me.nsleep = 0
+}
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index 8677cb30c..101c05989 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -249,7 +249,7 @@ func TestGoroutineSwitch(t *testing.T) {
// exists to record a PC without a traceback. Those are okay.
if len(stk) == 2 {
f := runtime.FuncForPC(stk[1])
- if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode" || f.Name() == "GC") {
+ if f != nil && (f.Name() == "runtime._System" || f.Name() == "runtime._ExternalCode" || f.Name() == "runtime._GC") {
return
}
}
diff --git a/src/runtime/proc.c b/src/runtime/proc.c
deleted file mode 100644
index 8462c4b1d..000000000
--- a/src/runtime/proc.c
+++ /dev/null
@@ -1,3521 +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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "zaexperiment.h"
-#include "malloc.h"
-#include "stack.h"
-#include "race.h"
-#include "type.h"
-#include "mgc0.h"
-#include "textflag.h"
-
-// Goroutine scheduler
-// The scheduler's job is to distribute ready-to-run goroutines over worker threads.
-//
-// The main concepts are:
-// G - goroutine.
-// M - worker thread, or machine.
-// P - processor, a resource that is required to execute Go code.
-// M must have an associated P to execute Go code, however it can be
-// blocked or in a syscall w/o an associated P.
-//
-// Design doc at http://golang.org/s/go11sched.
-
-enum
-{
- // Number of goroutine ids to grab from runtime·sched.goidgen to local per-P cache at once.
- // 16 seems to provide enough amortization, but other than that it's mostly arbitrary number.
- GoidCacheBatch = 16,
-};
-
-SchedT runtime·sched;
-int32 runtime·gomaxprocs;
-uint32 runtime·needextram;
-bool runtime·iscgo;
-M runtime·m0;
-G runtime·g0; // idle goroutine for m0
-G* runtime·lastg;
-M* runtime·allm;
-M* runtime·extram;
-P* runtime·allp[MaxGomaxprocs+1];
-int8* runtime·goos;
-int32 runtime·ncpu;
-int32 runtime·newprocs;
-
-Mutex runtime·allglock; // the following vars are protected by this lock or by stoptheworld
-G** runtime·allg;
-Slice runtime·allgs;
-uintptr runtime·allglen;
-ForceGCState runtime·forcegc;
-
-void runtime·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 runtime·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 runtime·allgadd(G*);
-static void dropg(void);
-
-extern String runtime·buildVersion;
-
-// For cgo-using programs with external linking,
-// export "main" (defined in assembly) so that libc can handle basic
-// C runtime startup and call the Go program as if it were
-// the C main function.
-#pragma cgo_export_static main
-
-// Filled in by dynamic linker when Cgo is available.
-void (*_cgo_init)(void);
-void (*_cgo_malloc)(void);
-void (*_cgo_free)(void);
-
-// Copy for Go code.
-void* runtime·cgoMalloc;
-void* runtime·cgoFree;
-
-// The bootstrap sequence is:
-//
-// call osinit
-// call schedinit
-// make & queue new G
-// call runtime·mstart
-//
-// The new G calls runtime·main.
-void
-runtime·schedinit(void)
-{
- int32 n, procs;
- byte *p;
-
- // raceinit must be the first call to race detector.
- // In particular, it must be done before mallocinit below calls racemapshadow.
- if(raceenabled)
- g->racectx = runtime·raceinit();
-
- runtime·sched.maxmcount = 10000;
-
- runtime·tracebackinit();
- runtime·symtabinit();
- runtime·stackinit();
- runtime·mallocinit();
- mcommoninit(g->m);
-
- runtime·goargs();
- runtime·goenvs();
- runtime·parsedebugvars();
- runtime·gcinit();
-
- runtime·sched.lastpoll = runtime·nanotime();
- procs = 1;
- p = runtime·getenv("GOMAXPROCS");
- if(p != nil && (n = runtime·atoi(p)) > 0) {
- if(n > MaxGomaxprocs)
- n = MaxGomaxprocs;
- procs = n;
- }
- procresize(procs);
-
- if(runtime·buildVersion.str == nil) {
- // Condition should never trigger. This code just serves
- // to ensure runtime·buildVersion is kept in the resulting binary.
- runtime·buildVersion.str = (uint8*)"unknown";
- runtime·buildVersion.len = 7;
- }
-
- runtime·cgoMalloc = _cgo_malloc;
- runtime·cgoFree = _cgo_free;
-}
-
-void
-runtime·newsysmon(void)
-{
- newm(sysmon, nil);
-}
-
-static void
-dumpgstatus(G* gp)
-{
- runtime·printf("runtime: gp: gp=%p, goid=%D, gp->atomicstatus=%x\n", gp, gp->goid, runtime·readgstatus(gp));
- runtime·printf("runtime: g: g=%p, goid=%D, g->atomicstatus=%x\n", g, g->goid, runtime·readgstatus(g));
-}
-
-static void
-checkmcount(void)
-{
- // sched lock is held
- if(runtime·sched.mcount > runtime·sched.maxmcount){
- runtime·printf("runtime: program exceeds %d-thread limit\n", runtime·sched.maxmcount);
- runtime·throw("thread exhaustion");
- }
-}
-
-static void
-mcommoninit(M *mp)
-{
- // g0 stack won't make sense for user (and is not necessary unwindable).
- if(g != g->m->g0)
- runtime·callers(1, mp->createstack, nelem(mp->createstack));
-
- mp->fastrand = 0x49f6428aUL + mp->id + runtime·cputicks();
-
- runtime·lock(&runtime·sched.lock);
- mp->id = runtime·sched.mcount++;
- checkmcount();
- runtime·mpreinit(mp);
- if(mp->gsignal)
- mp->gsignal->stackguard1 = mp->gsignal->stack.lo + StackGuard;
-
- // Add to runtime·allm so garbage collector doesn't free g->m
- // when it is just in a register or thread-local storage.
- mp->alllink = runtime·allm;
- // runtime·NumCgoCall() iterates over allm w/o schedlock,
- // so we need to publish it safely.
- runtime·atomicstorep(&runtime·allm, mp);
- runtime·unlock(&runtime·sched.lock);
-}
-
-// Mark gp ready to run.
-void
-runtime·ready(G *gp)
-{
- uint32 status;
-
- status = runtime·readgstatus(gp);
- // Mark runnable.
- g->m->locks++; // disable preemption because it can be holding p in a local var
- if((status&~Gscan) != Gwaiting){
- dumpgstatus(gp);
- runtime·throw("bad g->status in ready");
- }
- // status is Gwaiting or Gscanwaiting, make Grunnable and put on runq
- runtime·casgstatus(gp, Gwaiting, Grunnable);
- runqput(g->m->p, gp);
- if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0) // TODO: fast atomic
- wakep();
- g->m->locks--;
- if(g->m->locks == 0 && g->preempt) // restore the preemption request in case we've cleared it in newstack
- g->stackguard0 = StackPreempt;
-}
-
-void
-runtime·ready_m(void)
-{
- G *gp;
-
- gp = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- runtime·ready(gp);
-}
-
-int32
-runtime·gcprocs(void)
-{
- int32 n;
-
- // Figure out how many CPUs to use during GC.
- // Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
- runtime·lock(&runtime·sched.lock);
- n = runtime·gomaxprocs;
- if(n > runtime·ncpu)
- n = runtime·ncpu;
- if(n > MaxGcproc)
- n = MaxGcproc;
- if(n > runtime·sched.nmidle+1) // one M is currently running
- n = runtime·sched.nmidle+1;
- runtime·unlock(&runtime·sched.lock);
- return n;
-}
-
-static bool
-needaddgcproc(void)
-{
- int32 n;
-
- runtime·lock(&runtime·sched.lock);
- n = runtime·gomaxprocs;
- if(n > runtime·ncpu)
- n = runtime·ncpu;
- if(n > MaxGcproc)
- n = MaxGcproc;
- n -= runtime·sched.nmidle+1; // one M is currently running
- runtime·unlock(&runtime·sched.lock);
- return n > 0;
-}
-
-void
-runtime·helpgc(int32 nproc)
-{
- M *mp;
- int32 n, pos;
-
- runtime·lock(&runtime·sched.lock);
- pos = 0;
- for(n = 1; n < nproc; n++) { // one M is currently running
- if(runtime·allp[pos]->mcache == g->m->mcache)
- pos++;
- mp = mget();
- if(mp == nil)
- runtime·throw("runtime·gcprocs inconsistency");
- mp->helpgc = n;
- mp->mcache = runtime·allp[pos]->mcache;
- pos++;
- runtime·notewakeup(&mp->park);
- }
- runtime·unlock(&runtime·sched.lock);
-}
-
-// Similar to stoptheworld but best-effort and can be called several times.
-// There is no reverse operation, used during crashing.
-// This function must not lock any mutexes.
-void
-runtime·freezetheworld(void)
-{
- int32 i;
-
- if(runtime·gomaxprocs == 1)
- return;
- // stopwait and preemption requests can be lost
- // due to races with concurrently executing threads,
- // so try several times
- for(i = 0; i < 5; i++) {
- // this should tell the scheduler to not start any new goroutines
- runtime·sched.stopwait = 0x7fffffff;
- runtime·atomicstore((uint32*)&runtime·sched.gcwaiting, 1);
- // this should stop running goroutines
- if(!preemptall())
- break; // no running goroutines
- runtime·usleep(1000);
- }
- // to be sure
- runtime·usleep(1000);
- preemptall();
- runtime·usleep(1000);
-}
-
-static bool
-isscanstatus(uint32 status)
-{
- if(status == Gscan)
- runtime·throw("isscanstatus: Bad status Gscan");
- return (status&Gscan) == Gscan;
-}
-
-// All reads and writes of g's status go through readgstatus, casgstatus
-// castogscanstatus, casfromgscanstatus.
-#pragma textflag NOSPLIT
-uint32
-runtime·readgstatus(G *gp)
-{
- return runtime·atomicload(&gp->atomicstatus);
-}
-
-// The Gscanstatuses are acting like locks and this releases them.
-// If it proves to be a performance hit we should be able to make these
-// simple atomic stores but for now we are going to throw if
-// we see an inconsistent state.
-void
-runtime·casfromgscanstatus(G *gp, uint32 oldval, uint32 newval)
-{
- bool success = false;
-
- // Check that transition is valid.
- switch(oldval) {
- case Gscanrunnable:
- case Gscanwaiting:
- case Gscanrunning:
- case Gscansyscall:
- if(newval == (oldval&~Gscan))
- success = runtime·cas(&gp->atomicstatus, oldval, newval);
- break;
- case Gscanenqueue:
- if(newval == Gwaiting)
- success = runtime·cas(&gp->atomicstatus, oldval, newval);
- break;
- }
- if(!success){
- runtime·printf("runtime: casfromgscanstatus failed gp=%p, oldval=%d, newval=%d\n",
- gp, oldval, newval);
- dumpgstatus(gp);
- runtime·throw("casfromgscanstatus: gp->status is not in scan state");
- }
-}
-
-// This will return false if the gp is not in the expected status and the cas fails.
-// This acts like a lock acquire while the casfromgstatus acts like a lock release.
-bool
-runtime·castogscanstatus(G *gp, uint32 oldval, uint32 newval)
-{
- switch(oldval) {
- case Grunnable:
- case Gwaiting:
- case Gsyscall:
- if(newval == (oldval|Gscan))
- return runtime·cas(&gp->atomicstatus, oldval, newval);
- break;
- case Grunning:
- if(newval == Gscanrunning || newval == Gscanenqueue)
- return runtime·cas(&gp->atomicstatus, oldval, newval);
- break;
- }
-
- runtime·printf("runtime: castogscanstatus oldval=%d newval=%d\n", oldval, newval);
- runtime·throw("castogscanstatus");
- return false; // not reached
-}
-
-static void badcasgstatus(void);
-static void helpcasgstatus(void);
-static void badgstatusrunnable(void);
-
-// If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus
-// and casfromgscanstatus instead.
-// casgstatus will loop if the g->atomicstatus is in a Gscan status until the routine that
-// put it in the Gscan state is finished.
-#pragma textflag NOSPLIT
-void
-runtime·casgstatus(G *gp, uint32 oldval, uint32 newval)
-{
- void (*fn)(void);
-
- if((oldval&Gscan) || (newval&Gscan) || oldval == newval) {
- g->m->scalararg[0] = oldval;
- g->m->scalararg[1] = newval;
- fn = badcasgstatus;
- runtime·onM(&fn);
- }
-
- // loop if gp->atomicstatus is in a scan state giving
- // GC time to finish and change the state to oldval.
- while(!runtime·cas(&gp->atomicstatus, oldval, newval)) {
- if(oldval == Gwaiting && gp->atomicstatus == Grunnable) {
- fn = badgstatusrunnable;
- runtime·onM(&fn);
- }
- // Help GC if needed.
- if(gp->preemptscan && !gp->gcworkdone && (oldval == Grunning || oldval == Gsyscall)) {
- gp->preemptscan = false;
- g->m->ptrarg[0] = gp;
- fn = helpcasgstatus;
- runtime·onM(&fn);
- }
- }
-}
-
-static void
-badgstatusrunnable(void)
-{
- runtime·throw("casgstatus: waiting for Gwaiting but is Grunnable");
-}
-
-// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
-// Returns old status. Cannot call casgstatus directly, because we are racing with an
-// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus,
-// it might have become Grunnable by the time we get to the cas. If we called casgstatus,
-// it would loop waiting for the status to go back to Gwaiting, which it never will.
-#pragma textflag NOSPLIT
-uint32
-runtime·casgcopystack(G *gp)
-{
- uint32 oldstatus;
-
- for(;;) {
- oldstatus = runtime·readgstatus(gp) & ~Gscan;
- if(oldstatus != Gwaiting && oldstatus != Grunnable)
- runtime·throw("copystack: bad status, not Gwaiting or Grunnable");
- if(runtime·cas(&gp->atomicstatus, oldstatus, Gcopystack))
- break;
- }
- return oldstatus;
-}
-
-static void
-badcasgstatus(void)
-{
- uint32 oldval, newval;
-
- oldval = g->m->scalararg[0];
- newval = g->m->scalararg[1];
- g->m->scalararg[0] = 0;
- g->m->scalararg[1] = 0;
-
- runtime·printf("casgstatus: oldval=%d, newval=%d\n", oldval, newval);
- runtime·throw("casgstatus: bad incoming values");
-}
-
-static void
-helpcasgstatus(void)
-{
- G *gp;
-
- gp = g->m->ptrarg[0];
- g->m->ptrarg[0] = 0;
- runtime·gcphasework(gp);
-}
-
-// stopg ensures that gp is stopped at a GC safe point where its stack can be scanned
-// or in the context of a moving collector the pointers can be flipped from pointing
-// to old object to pointing to new objects.
-// If stopg returns true, the caller knows gp is at a GC safe point and will remain there until
-// the caller calls restartg.
-// If stopg returns false, the caller is not responsible for calling restartg. This can happen
-// if another thread, either the gp itself or another GC thread is taking the responsibility
-// to do the GC work related to this thread.
-bool
-runtime·stopg(G *gp)
-{
- uint32 s;
-
- for(;;) {
- if(gp->gcworkdone)
- return false;
-
- s = runtime·readgstatus(gp);
- switch(s) {
- default:
- dumpgstatus(gp);
- runtime·throw("stopg: gp->atomicstatus is not valid");
-
- case Gdead:
- return false;
-
- case Gcopystack:
- // Loop until a new stack is in place.
- break;
-
- case Grunnable:
- case Gsyscall:
- case Gwaiting:
- // Claim goroutine by setting scan bit.
- if(!runtime·castogscanstatus(gp, s, s|Gscan))
- break;
- // In scan state, do work.
- runtime·gcphasework(gp);
- return true;
-
- case Gscanrunnable:
- case Gscanwaiting:
- case Gscansyscall:
- // Goroutine already claimed by another GC helper.
- return false;
-
- case Grunning:
- // Claim goroutine, so we aren't racing with a status
- // transition away from Grunning.
- if(!runtime·castogscanstatus(gp, Grunning, Gscanrunning))
- break;
-
- // Mark gp for preemption.
- if(!gp->gcworkdone) {
- gp->preemptscan = true;
- gp->preempt = true;
- gp->stackguard0 = StackPreempt;
- }
-
- // Unclaim.
- runtime·casfromgscanstatus(gp, Gscanrunning, Grunning);
- return false;
- }
- }
- // Should not be here....
-}
-
-// The GC requests that this routine be moved from a scanmumble state to a mumble state.
-void
-runtime·restartg (G *gp)
-{
- uint32 s;
-
- s = runtime·readgstatus(gp);
- switch(s) {
- default:
- dumpgstatus(gp);
- runtime·throw("restartg: unexpected status");
-
- case Gdead:
- break;
-
- case Gscanrunnable:
- case Gscanwaiting:
- case Gscansyscall:
- runtime·casfromgscanstatus(gp, s, s&~Gscan);
- break;
-
- case Gscanenqueue:
- // Scan is now completed.
- // Goroutine now needs to be made runnable.
- // We put it on the global run queue; ready blocks on the global scheduler lock.
- runtime·casfromgscanstatus(gp, Gscanenqueue, Gwaiting);
- if(gp != g->m->curg)
- runtime·throw("processing Gscanenqueue on wrong m");
- dropg();
- runtime·ready(gp);
- break;
- }
-}
-
-static void
-stopscanstart(G* gp)
-{
- if(g == gp)
- runtime·throw("GC not moved to G0");
- if(runtime·stopg(gp)) {
- if(!isscanstatus(runtime·readgstatus(gp))) {
- dumpgstatus(gp);
- runtime·throw("GC not in scan state");
- }
- runtime·restartg(gp);
- }
-}
-
-// Runs on g0 and does the actual work after putting the g back on the run queue.
-static void
-mquiesce(G *gpmaster)
-{
- G* gp;
- uint32 i;
- uint32 status;
- uint32 activeglen;
-
- activeglen = runtime·allglen;
- // enqueue the calling goroutine.
- runtime·restartg(gpmaster);
- for(i = 0; i < activeglen; i++) {
- gp = runtime·allg[i];
- if(runtime·readgstatus(gp) == Gdead)
- gp->gcworkdone = true; // noop scan.
- else
- gp->gcworkdone = false;
- stopscanstart(gp);
- }
-
- // Check that the G's gcwork (such as scanning) has been done. If not do it now.
- // You can end up doing work here if the page trap on a Grunning Goroutine has
- // not been sprung or in some race situations. For example a runnable goes dead
- // and is started up again with a gp->gcworkdone set to false.
- for(i = 0; i < activeglen; i++) {
- gp = runtime·allg[i];
- while (!gp->gcworkdone) {
- status = runtime·readgstatus(gp);
- if(status == Gdead) {
- gp->gcworkdone = true; // scan is a noop
- break;
- //do nothing, scan not needed.
- }
- if(status == Grunning && gp->stackguard0 == (uintptr)StackPreempt && runtime·notetsleep(&runtime·sched.stopnote, 100*1000)) // nanosecond arg
- runtime·noteclear(&runtime·sched.stopnote);
- else
- stopscanstart(gp);
- }
- }
-
- for(i = 0; i < activeglen; i++) {
- gp = runtime·allg[i];
- status = runtime·readgstatus(gp);
- if(isscanstatus(status)) {
- runtime·printf("mstopandscang:bottom: post scan bad status gp=%p has status %x\n", gp, status);
- dumpgstatus(gp);
- }
- if(!gp->gcworkdone && status != Gdead) {
- runtime·printf("mstopandscang:bottom: post scan gp=%p->gcworkdone still false\n", gp);
- dumpgstatus(gp);
- }
- }
-
- schedule(); // Never returns.
-}
-
-// quiesce moves all the goroutines to a GC safepoint which for now is a at preemption point.
-// If the global runtime·gcphase is GCmark quiesce will ensure that all of the goroutine's stacks
-// have been scanned before it returns.
-void
-runtime·quiesce(G* mastergp)
-{
- void (*fn)(G*);
-
- runtime·castogscanstatus(mastergp, Grunning, Gscanenqueue);
- // Now move this to the g0 (aka m) stack.
- // g0 will potentially scan this thread and put mastergp on the runqueue
- fn = mquiesce;
- runtime·mcall(&fn);
-}
-
-// This is used by the GC as well as the routines that do stack dumps. In the case
-// of GC all the routines can be reliably stopped. This is not always the case
-// when the system is in panic or being exited.
-void
-runtime·stoptheworld(void)
-{
- int32 i;
- uint32 s;
- P *p;
- bool wait;
-
- // If we hold a lock, then we won't be able to stop another M
- // that is blocked trying to acquire the lock.
- if(g->m->locks > 0)
- runtime·throw("stoptheworld: holding locks");
-
- runtime·lock(&runtime·sched.lock);
- runtime·sched.stopwait = runtime·gomaxprocs;
- runtime·atomicstore((uint32*)&runtime·sched.gcwaiting, 1);
- preemptall();
- // stop current P
- g->m->p->status = Pgcstop; // Pgcstop is only diagnostic.
- runtime·sched.stopwait--;
- // try to retake all P's in Psyscall status
- for(i = 0; i < runtime·gomaxprocs; i++) {
- p = runtime·allp[i];
- s = p->status;
- if(s == Psyscall && runtime·cas(&p->status, s, Pgcstop))
- runtime·sched.stopwait--;
- }
- // stop idle P's
- while(p = pidleget()) {
- p->status = Pgcstop;
- runtime·sched.stopwait--;
- }
- wait = runtime·sched.stopwait > 0;
- runtime·unlock(&runtime·sched.lock);
-
- // wait for remaining P's to stop voluntarily
- if(wait) {
- for(;;) {
- // wait for 100us, then try to re-preempt in case of any races
- if(runtime·notetsleep(&runtime·sched.stopnote, 100*1000)) {
- runtime·noteclear(&runtime·sched.stopnote);
- break;
- }
- preemptall();
- }
- }
- if(runtime·sched.stopwait)
- runtime·throw("stoptheworld: not stopped");
- for(i = 0; i < runtime·gomaxprocs; i++) {
- p = runtime·allp[i];
- if(p->status != Pgcstop)
- runtime·throw("stoptheworld: not stopped");
- }
-}
-
-static void
-mhelpgc(void)
-{
- g->m->helpgc = -1;
-}
-
-void
-runtime·starttheworld(void)
-{
- P *p, *p1;
- M *mp;
- G *gp;
- bool add;
-
- g->m->locks++; // disable preemption because it can be holding p in a local var
- gp = runtime·netpoll(false); // non-blocking
- injectglist(gp);
- add = needaddgcproc();
- runtime·lock(&runtime·sched.lock);
- if(runtime·newprocs) {
- procresize(runtime·newprocs);
- runtime·newprocs = 0;
- } else
- procresize(runtime·gomaxprocs);
- runtime·sched.gcwaiting = 0;
-
- p1 = nil;
- while(p = pidleget()) {
- // procresize() puts p's with work at the beginning of the list.
- // Once we reach a p without a run queue, the rest don't have one either.
- if(p->runqhead == p->runqtail) {
- pidleput(p);
- break;
- }
- p->m = mget();
- p->link = p1;
- p1 = p;
- }
- if(runtime·sched.sysmonwait) {
- runtime·sched.sysmonwait = false;
- runtime·notewakeup(&runtime·sched.sysmonnote);
- }
- runtime·unlock(&runtime·sched.lock);
-
- while(p1) {
- p = p1;
- p1 = p1->link;
- if(p->m) {
- mp = p->m;
- p->m = nil;
- if(mp->nextp)
- runtime·throw("starttheworld: inconsistent mp->nextp");
- mp->nextp = p;
- runtime·notewakeup(&mp->park);
- } else {
- // Start M to run P. Do not start another M below.
- newm(nil, p);
- add = false;
- }
- }
-
- if(add) {
- // If GC could have used another helper proc, start one now,
- // in the hope that it will be available next time.
- // It would have been even better to start it before the collection,
- // but doing so requires allocating memory, so it's tricky to
- // coordinate. This lazy approach works out in practice:
- // we don't mind if the first couple gc rounds don't have quite
- // the maximum number of procs.
- newm(mhelpgc, nil);
- }
- g->m->locks--;
- if(g->m->locks == 0 && g->preempt) // restore the preemption request in case we've cleared it in newstack
- g->stackguard0 = StackPreempt;
-}
-
-static void mstart(void);
-
-// Called to start an M.
-#pragma textflag NOSPLIT
-void
-runtime·mstart(void)
-{
- uintptr x, size;
-
- if(g->stack.lo == 0) {
- // Initialize stack bounds from system stack.
- // Cgo may have left stack size in stack.hi.
- size = g->stack.hi;
- if(size == 0)
- size = 8192;
- g->stack.hi = (uintptr)&x;
- g->stack.lo = g->stack.hi - size + 1024;
- }
-
- // Initialize stack guards so that we can start calling
- // both Go and C functions with stack growth prologues.
- g->stackguard0 = g->stack.lo + StackGuard;
- g->stackguard1 = g->stackguard0;
- mstart();
-}
-
-static void
-mstart(void)
-{
- if(g != g->m->g0)
- runtime·throw("bad runtime·mstart");
-
- // Record top of stack for use by mcall.
- // Once we call schedule we're never coming back,
- // so other calls can reuse this stack space.
- runtime·gosave(&g->m->g0->sched);
- g->m->g0->sched.pc = (uintptr)-1; // make sure it is never used
- runtime·asminit();
- runtime·minit();
-
- // Install signal handlers; after minit so that minit can
- // prepare the thread to be able to handle the signals.
- if(g->m == &runtime·m0)
- runtime·initsig();
-
- if(g->m->mstartfn)
- g->m->mstartfn();
-
- if(g->m->helpgc) {
- g->m->helpgc = 0;
- stopm();
- } else if(g->m != &runtime·m0) {
- acquirep(g->m->nextp);
- g->m->nextp = nil;
- }
- schedule();
-
- // TODO(brainman): This point is never reached, because scheduler
- // does not release os threads at the moment. But once this path
- // is enabled, we must remove our seh here.
-}
-
-// When running with cgo, we call _cgo_thread_start
-// to start threads for us so that we can play nicely with
-// foreign code.
-void (*_cgo_thread_start)(void*);
-
-typedef struct CgoThreadStart CgoThreadStart;
-struct CgoThreadStart
-{
- G *g;
- uintptr *tls;
- void (*fn)(void);
-};
-
-M *runtime·newM(void); // in proc.go
-
-// Allocate a new m unassociated with any thread.
-// Can use p for allocation context if needed.
-M*
-runtime·allocm(P *p)
-{
- M *mp;
-
- g->m->locks++; // disable GC because it can be called from sysmon
- if(g->m->p == nil)
- acquirep(p); // temporarily borrow p for mallocs in this function
- mp = runtime·newM();
- mcommoninit(mp);
-
- // In case of cgo or Solaris, pthread_create will make us a stack.
- // Windows and Plan 9 will layout sched stack on OS stack.
- if(runtime·iscgo || Solaris || Windows || Plan9)
- mp->g0 = runtime·malg(-1);
- else
- mp->g0 = runtime·malg(8192);
- mp->g0->m = mp;
-
- if(p == g->m->p)
- releasep();
- g->m->locks--;
- if(g->m->locks == 0 && g->preempt) // restore the preemption request in case we've cleared it in newstack
- g->stackguard0 = StackPreempt;
-
- return mp;
-}
-
-G *runtime·newG(void); // in proc.go
-
-static G*
-allocg(void)
-{
- return runtime·newG();
-}
-
-static M* lockextra(bool nilokay);
-static void unlockextra(M*);
-
-// 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
-// and return with m, g initialized correctly.
-// Since m and g are not set now (likely nil, but see below)
-// needm is limited in what routines it can call. In particular
-// it can only call nosplit functions (textflag 7) and cannot
-// do any scheduling that requires an m.
-//
-// In order to avoid needing heavy lifting here, we adopt
-// the following strategy: there is a stack of available m's
-// that can be stolen. Using compare-and-swap
-// to pop from the stack has ABA races, so we simulate
-// a lock by doing an exchange (via casp) to steal the stack
-// head and replace the top pointer with MLOCKED (1).
-// This serves as a simple spin lock that we can use even
-// without an m. The thread that locks the stack in this way
-// unlocks the stack by storing a valid stack head pointer.
-//
-// In order to make sure that there is always an m structure
-// available to be stolen, we maintain the invariant that there
-// is always one more than needed. At the beginning of the
-// program (if cgo is in use) the list is seeded with a single m.
-// If needm finds that it has taken the last m off the list, its job
-// is - once it has installed its own m so that it can do things like
-// allocate memory - to create a spare m and put it on the list.
-//
-// Each of these extra m's also has a g0 and a curg that are
-// pressed into service as the scheduling stack and current
-// goroutine for the duration of the cgo callback.
-//
-// When the callback is done with the m, it calls dropm to
-// put the m back on the list.
-#pragma textflag NOSPLIT
-void
-runtime·needm(byte x)
-{
- M *mp;
-
- if(runtime·needextram) {
- // Can happen if C/C++ code calls Go from a global ctor.
- // Can not throw, because scheduler is not initialized yet.
- runtime·write(2, "fatal error: cgo callback before cgo call\n",
- sizeof("fatal error: cgo callback before cgo call\n")-1);
- runtime·exit(1);
- }
-
- // Lock extra list, take head, unlock popped list.
- // nilokay=false is safe here because of the invariant above,
- // that the extra list always contains or will soon contain
- // at least one m.
- mp = lockextra(false);
-
- // Set needextram when we've just emptied the list,
- // so that the eventual call into cgocallbackg will
- // allocate a new m for the extra list. We delay the
- // allocation until then so that it can be done
- // after exitsyscall makes sure it is okay to be
- // running at all (that is, there's no garbage collection
- // running right now).
- mp->needextram = mp->schedlink == nil;
- unlockextra(mp->schedlink);
-
- // Install g (= m->g0) and set the stack bounds
- // to match the current stack. We don't actually know
- // how big the stack is, like we don't know how big any
- // scheduling stack is, but we assume there's at least 32 kB,
- // which is more than enough for us.
- runtime·setg(mp->g0);
- g->stack.hi = (uintptr)(&x + 1024);
- g->stack.lo = (uintptr)(&x - 32*1024);
- g->stackguard0 = g->stack.lo + StackGuard;
-
- // Initialize this thread to use the m.
- runtime·asminit();
- runtime·minit();
-}
-
-// newextram allocates an m and puts it on the extra list.
-// It is called with a working local m, so that it can do things
-// like call schedlock and allocate.
-void
-runtime·newextram(void)
-{
- M *mp, *mnext;
- G *gp;
-
- // Create extra goroutine locked to extra m.
- // The goroutine is the context in which the cgo callback will run.
- // The sched.pc will never be returned to, but setting it to
- // runtime.goexit makes clear to the traceback routines where
- // the goroutine stack ends.
- mp = runtime·allocm(nil);
- gp = runtime·malg(4096);
- gp->sched.pc = (uintptr)runtime·goexit + PCQuantum;
- gp->sched.sp = gp->stack.hi;
- gp->sched.sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
- gp->sched.lr = 0;
- gp->sched.g = gp;
- gp->syscallpc = gp->sched.pc;
- gp->syscallsp = gp->sched.sp;
- // malg returns status as Gidle, change to Gsyscall before adding to allg
- // where GC will see it.
- runtime·casgstatus(gp, Gidle, Gsyscall);
- gp->m = mp;
- mp->curg = gp;
- mp->locked = LockInternal;
- mp->lockedg = gp;
- gp->lockedm = mp;
- gp->goid = runtime·xadd64(&runtime·sched.goidgen, 1);
- if(raceenabled)
- gp->racectx = runtime·racegostart(runtime·newextram);
- // put on allg for garbage collector
- runtime·allgadd(gp);
-
- // Add m to the extra list.
- mnext = lockextra(true);
- mp->schedlink = mnext;
- unlockextra(mp);
-}
-
-// dropm is called when a cgo callback has called needm but is now
-// done with the callback and returning back into the non-Go thread.
-// It puts the current m back onto the extra list.
-//
-// The main expense here is the call to signalstack to release the
-// m's signal stack, and then the call to needm on the next callback
-// from this thread. It is tempting to try to save the m for next time,
-// which would eliminate both these costs, but there might not be
-// a next time: the current thread (which Go does not control) might exit.
-// If we saved the m for that thread, there would be an m leak each time
-// such a thread exited. Instead, we acquire and release an m on each
-// call. These should typically not be scheduling operations, just a few
-// atomics, so the cost should be small.
-//
-// TODO(rsc): An alternative would be to allocate a dummy pthread per-thread
-// variable using pthread_key_create. Unlike the pthread keys we already use
-// on OS X, this dummy key would never be read by Go code. It would exist
-// only so that we could register at thread-exit-time destructor.
-// That destructor would put the m back onto the extra list.
-// This is purely a performance optimization. The current version,
-// in which dropm happens on each cgo call, is still correct too.
-// We may have to keep the current version on systems with cgo
-// but without pthreads, like Windows.
-void
-runtime·dropm(void)
-{
- M *mp, *mnext;
-
- // Undo whatever initialization minit did during needm.
- runtime·unminit();
-
- // Clear m and g, and return m to the extra list.
- // After the call to setmg we can only call nosplit functions.
- mp = g->m;
- runtime·setg(nil);
-
- mnext = lockextra(true);
- mp->schedlink = mnext;
- unlockextra(mp);
-}
-
-#define MLOCKED ((M*)1)
-
-// lockextra locks the extra list and returns the list head.
-// The caller must unlock the list by storing a new list head
-// to runtime.extram. If nilokay is true, then lockextra will
-// return a nil list head if that's what it finds. If nilokay is false,
-// lockextra will keep waiting until the list head is no longer nil.
-#pragma textflag NOSPLIT
-static M*
-lockextra(bool nilokay)
-{
- M *mp;
- void (*yield)(void);
-
- for(;;) {
- mp = runtime·atomicloadp(&runtime·extram);
- if(mp == MLOCKED) {
- yield = runtime·osyield;
- yield();
- continue;
- }
- if(mp == nil && !nilokay) {
- runtime·usleep(1);
- continue;
- }
- if(!runtime·casp(&runtime·extram, mp, MLOCKED)) {
- yield = runtime·osyield;
- yield();
- continue;
- }
- break;
- }
- return mp;
-}
-
-#pragma textflag NOSPLIT
-static void
-unlockextra(M *mp)
-{
- runtime·atomicstorep(&runtime·extram, mp);
-}
-
-
-// Create a new m. It will start off with a call to fn, or else the scheduler.
-static void
-newm(void(*fn)(void), P *p)
-{
- M *mp;
-
- mp = runtime·allocm(p);
- mp->nextp = p;
- mp->mstartfn = fn;
-
- if(runtime·iscgo) {
- CgoThreadStart ts;
-
- if(_cgo_thread_start == nil)
- runtime·throw("_cgo_thread_start missing");
- ts.g = mp->g0;
- ts.tls = mp->tls;
- ts.fn = runtime·mstart;
- runtime·asmcgocall(_cgo_thread_start, &ts);
- return;
- }
- runtime·newosproc(mp, (byte*)mp->g0->stack.hi);
-}
-
-// Stops execution of the current m until new work is available.
-// Returns with acquired P.
-static void
-stopm(void)
-{
- if(g->m->locks)
- runtime·throw("stopm holding locks");
- if(g->m->p)
- runtime·throw("stopm holding p");
- if(g->m->spinning) {
- g->m->spinning = false;
- runtime·xadd(&runtime·sched.nmspinning, -1);
- }
-
-retry:
- runtime·lock(&runtime·sched.lock);
- mput(g->m);
- runtime·unlock(&runtime·sched.lock);
- runtime·notesleep(&g->m->park);
- runtime·noteclear(&g->m->park);
- if(g->m->helpgc) {
- runtime·gchelper();
- g->m->helpgc = 0;
- g->m->mcache = nil;
- goto retry;
- }
- acquirep(g->m->nextp);
- g->m->nextp = nil;
-}
-
-static void
-mspinning(void)
-{
- g->m->spinning = true;
-}
-
-// Schedules some M to run the p (creates an M if necessary).
-// If p==nil, tries to get an idle P, if no idle P's does nothing.
-static void
-startm(P *p, bool spinning)
-{
- M *mp;
- void (*fn)(void);
-
- runtime·lock(&runtime·sched.lock);
- if(p == nil) {
- p = pidleget();
- if(p == nil) {
- runtime·unlock(&runtime·sched.lock);
- if(spinning)
- runtime·xadd(&runtime·sched.nmspinning, -1);
- return;
- }
- }
- mp = mget();
- runtime·unlock(&runtime·sched.lock);
- if(mp == nil) {
- fn = nil;
- if(spinning)
- fn = mspinning;
- newm(fn, p);
- return;
- }
- if(mp->spinning)
- runtime·throw("startm: m is spinning");
- if(mp->nextp)
- runtime·throw("startm: m has p");
- mp->spinning = spinning;
- mp->nextp = p;
- runtime·notewakeup(&mp->park);
-}
-
-// Hands off P from syscall or locked M.
-static void
-handoffp(P *p)
-{
- // if it has local work, start it straight away
- if(p->runqhead != p->runqtail || runtime·sched.runqsize) {
- startm(p, false);
- return;
- }
- // no local work, check that there are no spinning/idle M's,
- // otherwise our help is not required
- if(runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) == 0 && // TODO: fast atomic
- runtime·cas(&runtime·sched.nmspinning, 0, 1)){
- startm(p, true);
- return;
- }
- runtime·lock(&runtime·sched.lock);
- if(runtime·sched.gcwaiting) {
- p->status = Pgcstop;
- if(--runtime·sched.stopwait == 0)
- runtime·notewakeup(&runtime·sched.stopnote);
- runtime·unlock(&runtime·sched.lock);
- return;
- }
- if(runtime·sched.runqsize) {
- runtime·unlock(&runtime·sched.lock);
- startm(p, false);
- return;
- }
- // If this is the last running P and nobody is polling network,
- // need to wakeup another M to poll network.
- if(runtime·sched.npidle == runtime·gomaxprocs-1 && runtime·atomicload64(&runtime·sched.lastpoll) != 0) {
- runtime·unlock(&runtime·sched.lock);
- startm(p, false);
- return;
- }
- pidleput(p);
- runtime·unlock(&runtime·sched.lock);
-}
-
-// Tries to add one more P to execute G's.
-// Called when a G is made runnable (newproc, ready).
-static void
-wakep(void)
-{
- // be conservative about spinning threads
- if(!runtime·cas(&runtime·sched.nmspinning, 0, 1))
- return;
- startm(nil, true);
-}
-
-// Stops execution of the current m that is locked to a g until the g is runnable again.
-// Returns with acquired P.
-static void
-stoplockedm(void)
-{
- P *p;
- uint32 status;
-
- if(g->m->lockedg == nil || g->m->lockedg->lockedm != g->m)
- runtime·throw("stoplockedm: inconsistent locking");
- if(g->m->p) {
- // Schedule another M to run this p.
- p = releasep();
- handoffp(p);
- }
- incidlelocked(1);
- // Wait until another thread schedules lockedg again.
- runtime·notesleep(&g->m->park);
- runtime·noteclear(&g->m->park);
- status = runtime·readgstatus(g->m->lockedg);
- if((status&~Gscan) != Grunnable){
- runtime·printf("runtime:stoplockedm: g is not Grunnable or Gscanrunnable");
- dumpgstatus(g);
- runtime·throw("stoplockedm: not runnable");
- }
- acquirep(g->m->nextp);
- g->m->nextp = nil;
-}
-
-// Schedules the locked m to run the locked gp.
-static void
-startlockedm(G *gp)
-{
- M *mp;
- P *p;
-
- mp = gp->lockedm;
- if(mp == g->m)
- runtime·throw("startlockedm: locked to me");
- if(mp->nextp)
- runtime·throw("startlockedm: m has p");
- // directly handoff current P to the locked m
- incidlelocked(-1);
- p = releasep();
- mp->nextp = p;
- runtime·notewakeup(&mp->park);
- stopm();
-}
-
-// Stops the current m for stoptheworld.
-// Returns when the world is restarted.
-static void
-gcstopm(void)
-{
- P *p;
-
- if(!runtime·sched.gcwaiting)
- runtime·throw("gcstopm: not waiting for gc");
- if(g->m->spinning) {
- g->m->spinning = false;
- runtime·xadd(&runtime·sched.nmspinning, -1);
- }
- p = releasep();
- runtime·lock(&runtime·sched.lock);
- p->status = Pgcstop;
- if(--runtime·sched.stopwait == 0)
- runtime·notewakeup(&runtime·sched.stopnote);
- runtime·unlock(&runtime·sched.lock);
- stopm();
-}
-
-// Schedules gp to run on the current M.
-// Never returns.
-static void
-execute(G *gp)
-{
- int32 hz;
-
- runtime·casgstatus(gp, Grunnable, Grunning);
- gp->waitsince = 0;
- gp->preempt = false;
- gp->stackguard0 = gp->stack.lo + StackGuard;
- g->m->p->schedtick++;
- g->m->curg = gp;
- gp->m = g->m;
-
- // Check whether the profiler needs to be turned on or off.
- hz = runtime·sched.profilehz;
- if(g->m->profilehz != hz)
- runtime·resetcpuprofiler(hz);
-
- runtime·gogo(&gp->sched);
-}
-
-// Finds a runnable goroutine to execute.
-// Tries to steal from other P's, get g from global queue, poll network.
-static G*
-findrunnable(void)
-{
- G *gp;
- P *p;
- int32 i;
-
-top:
- if(runtime·sched.gcwaiting) {
- gcstopm();
- goto top;
- }
- if(runtime·fingwait && runtime·fingwake && (gp = runtime·wakefing()) != nil)
- runtime·ready(gp);
- // local runq
- gp = runqget(g->m->p);
- if(gp)
- return gp;
- // global runq
- if(runtime·sched.runqsize) {
- runtime·lock(&runtime·sched.lock);
- gp = globrunqget(g->m->p, 0);
- runtime·unlock(&runtime·sched.lock);
- if(gp)
- return gp;
- }
- // poll network
- gp = runtime·netpoll(false); // non-blocking
- if(gp) {
- injectglist(gp->schedlink);
- runtime·casgstatus(gp, Gwaiting, Grunnable);
- return gp;
- }
- // If number of spinning M's >= number of busy P's, block.
- // This is necessary to prevent excessive CPU consumption
- // when GOMAXPROCS>>1 but the program parallelism is low.
- if(!g->m->spinning && 2 * runtime·atomicload(&runtime·sched.nmspinning) >= runtime·gomaxprocs - runtime·atomicload(&runtime·sched.npidle)) // TODO: fast atomic
- goto stop;
- if(!g->m->spinning) {
- g->m->spinning = true;
- runtime·xadd(&runtime·sched.nmspinning, 1);
- }
- // random steal from other P's
- for(i = 0; i < 2*runtime·gomaxprocs; i++) {
- if(runtime·sched.gcwaiting)
- goto top;
- p = runtime·allp[runtime·fastrand1()%runtime·gomaxprocs];
- if(p == g->m->p)
- gp = runqget(p);
- else
- gp = runqsteal(g->m->p, p);
- if(gp)
- return gp;
- }
-stop:
- // return P and block
- runtime·lock(&runtime·sched.lock);
- if(runtime·sched.gcwaiting) {
- runtime·unlock(&runtime·sched.lock);
- goto top;
- }
- if(runtime·sched.runqsize) {
- gp = globrunqget(g->m->p, 0);
- runtime·unlock(&runtime·sched.lock);
- return gp;
- }
- p = releasep();
- pidleput(p);
- runtime·unlock(&runtime·sched.lock);
- if(g->m->spinning) {
- g->m->spinning = false;
- runtime·xadd(&runtime·sched.nmspinning, -1);
- }
- // check all runqueues once again
- for(i = 0; i < runtime·gomaxprocs; i++) {
- p = runtime·allp[i];
- if(p && p->runqhead != p->runqtail) {
- runtime·lock(&runtime·sched.lock);
- p = pidleget();
- runtime·unlock(&runtime·sched.lock);
- if(p) {
- acquirep(p);
- goto top;
- }
- break;
- }
- }
- // poll network
- if(runtime·xchg64(&runtime·sched.lastpoll, 0) != 0) {
- if(g->m->p)
- runtime·throw("findrunnable: netpoll with p");
- if(g->m->spinning)
- runtime·throw("findrunnable: netpoll with spinning");
- gp = runtime·netpoll(true); // block until new work is available
- runtime·atomicstore64(&runtime·sched.lastpoll, runtime·nanotime());
- if(gp) {
- runtime·lock(&runtime·sched.lock);
- p = pidleget();
- runtime·unlock(&runtime·sched.lock);
- if(p) {
- acquirep(p);
- injectglist(gp->schedlink);
- runtime·casgstatus(gp, Gwaiting, Grunnable);
- return gp;
- }
- injectglist(gp);
- }
- }
- stopm();
- goto top;
-}
-
-static void
-resetspinning(void)
-{
- int32 nmspinning;
-
- if(g->m->spinning) {
- g->m->spinning = false;
- nmspinning = runtime·xadd(&runtime·sched.nmspinning, -1);
- if(nmspinning < 0)
- runtime·throw("findrunnable: negative nmspinning");
- } else
- nmspinning = runtime·atomicload(&runtime·sched.nmspinning);
-
- // M wakeup policy is deliberately somewhat conservative (see nmspinning handling),
- // so see if we need to wakeup another P here.
- if (nmspinning == 0 && runtime·atomicload(&runtime·sched.npidle) > 0)
- wakep();
-}
-
-// Injects the list of runnable G's into the scheduler.
-// Can run concurrently with GC.
-static void
-injectglist(G *glist)
-{
- int32 n;
- G *gp;
-
- if(glist == nil)
- return;
- runtime·lock(&runtime·sched.lock);
- for(n = 0; glist; n++) {
- gp = glist;
- glist = gp->schedlink;
- runtime·casgstatus(gp, Gwaiting, Grunnable);
- globrunqput(gp);
- }
- runtime·unlock(&runtime·sched.lock);
-
- for(; n && runtime·sched.npidle; n--)
- startm(nil, false);
-}
-
-// One round of scheduler: find a runnable goroutine and execute it.
-// Never returns.
-static void
-schedule(void)
-{
- G *gp;
- uint32 tick;
-
- if(g->m->locks)
- runtime·throw("schedule: holding locks");
-
- if(g->m->lockedg) {
- stoplockedm();
- execute(g->m->lockedg); // Never returns.
- }
-
-top:
- if(runtime·sched.gcwaiting) {
- gcstopm();
- goto top;
- }
-
- 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.
- 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(tick - (((uint64)tick*0x4325c53fu)>>36)*61 == 0 && runtime·sched.runqsize > 0) {
- runtime·lock(&runtime·sched.lock);
- gp = globrunqget(g->m->p, 1);
- runtime·unlock(&runtime·sched.lock);
- if(gp)
- resetspinning();
- }
- if(gp == nil) {
- gp = runqget(g->m->p);
- if(gp && g->m->spinning)
- runtime·throw("schedule: spinning with local work");
- }
- if(gp == nil) {
- gp = findrunnable(); // blocks until work is available
- resetspinning();
- }
-
- if(gp->lockedm) {
- // Hands off own p to the locked m,
- // then blocks waiting for a new p.
- startlockedm(gp);
- goto top;
- }
-
- execute(gp);
-}
-
-// dropg removes the association between m and the current goroutine m->curg (gp for short).
-// Typically a caller sets gp's status away from Grunning and then
-// immediately calls dropg to finish the job. The caller is also responsible
-// for arranging that gp will be restarted using runtime·ready at an
-// appropriate time. After calling dropg and arranging for gp to be
-// readied later, the caller can do other work but eventually should
-// call schedule to restart the scheduling of goroutines on this m.
-static void
-dropg(void)
-{
- if(g->m->lockedg == nil) {
- g->m->curg->m = nil;
- g->m->curg = nil;
- }
-}
-
-// Puts the current goroutine into a waiting state and calls unlockf.
-// If unlockf returns false, the goroutine is resumed.
-void
-runtime·park(bool(*unlockf)(G*, void*), void *lock, String reason)
-{
- void (*fn)(G*);
-
- g->m->waitlock = lock;
- g->m->waitunlockf = unlockf;
- g->waitreason = reason;
- fn = runtime·park_m;
- runtime·mcall(&fn);
-}
-
-bool
-runtime·parkunlock_c(G *gp, void *lock)
-{
- USED(gp);
- runtime·unlock(lock);
- return true;
-}
-
-// Puts the current goroutine into a waiting state and unlocks the lock.
-// The goroutine can be made runnable again by calling runtime·ready(gp).
-void
-runtime·parkunlock(Mutex *lock, String reason)
-{
- runtime·park(runtime·parkunlock_c, lock, reason);
-}
-
-// runtime·park continuation on g0.
-void
-runtime·park_m(G *gp)
-{
- bool ok;
-
- runtime·casgstatus(gp, Grunning, Gwaiting);
- dropg();
-
- if(g->m->waitunlockf) {
- ok = g->m->waitunlockf(gp, g->m->waitlock);
- g->m->waitunlockf = nil;
- g->m->waitlock = nil;
- if(!ok) {
- runtime·casgstatus(gp, Gwaiting, Grunnable);
- execute(gp); // Schedule it back, never returns.
- }
- }
-
- schedule();
-}
-
-// Gosched continuation on g0.
-void
-runtime·gosched_m(G *gp)
-{
- uint32 status;
-
- status = runtime·readgstatus(gp);
- if((status&~Gscan) != Grunning){
- dumpgstatus(gp);
- runtime·throw("bad g status");
- }
- runtime·casgstatus(gp, Grunning, Grunnable);
- dropg();
- runtime·lock(&runtime·sched.lock);
- globrunqput(gp);
- runtime·unlock(&runtime·sched.lock);
-
- schedule();
-}
-
-// Finishes execution of the current goroutine.
-// Must be NOSPLIT because it is called from Go.
-#pragma textflag NOSPLIT
-void
-runtime·goexit1(void)
-{
- void (*fn)(G*);
-
- if(raceenabled)
- runtime·racegoend();
- fn = goexit0;
- runtime·mcall(&fn);
-}
-
-// runtime·goexit continuation on g0.
-static void
-goexit0(G *gp)
-{
- runtime·casgstatus(gp, Grunning, Gdead);
- gp->m = nil;
- gp->lockedm = nil;
- g->m->lockedg = nil;
- gp->paniconfault = 0;
- gp->defer = nil; // should be true already but just in case.
- gp->panic = nil; // non-nil for Goexit during panic. points at stack-allocated data.
- gp->writebuf.array = nil;
- gp->writebuf.len = 0;
- gp->writebuf.cap = 0;
- gp->waitreason.str = nil;
- gp->waitreason.len = 0;
- gp->param = nil;
-
- dropg();
-
- if(g->m->locked & ~LockExternal) {
- runtime·printf("invalid m->locked = %d\n", g->m->locked);
- runtime·throw("internal lockOSThread error");
- }
- g->m->locked = 0;
- gfput(g->m->p, gp);
- schedule();
-}
-
-#pragma textflag NOSPLIT
-static void
-save(uintptr pc, uintptr sp)
-{
- g->sched.pc = pc;
- g->sched.sp = sp;
- g->sched.lr = 0;
- g->sched.ret = 0;
- g->sched.ctxt = 0;
- g->sched.g = g;
-}
-
-static void entersyscall_bad(void);
-static void entersyscall_sysmon(void);
-static void entersyscall_gcwait(void);
-
-// The goroutine g is about to enter a system call.
-// Record that it's not using the cpu anymore.
-// This is called only from the go syscall library and cgocall,
-// not from the low-level system calls used by the runtime.
-//
-// Entersyscall cannot split the stack: the runtime·gosave must
-// make g->sched refer to the caller's stack segment, because
-// entersyscall is going to return immediately after.
-//
-// Nothing entersyscall calls can split the stack either.
-// We cannot safely move the stack during an active call to syscall,
-// because we do not know which of the uintptr arguments are
-// really pointers (back into the stack).
-// In practice, this means that we make the fast path run through
-// entersyscall doing no-split things, and the slow path has to use onM
-// to run bigger things on the m stack.
-//
-// reentersyscall is the entry point used by cgo callbacks, where explicitly
-// saved SP and PC are restored. This is needed when exitsyscall will be called
-// 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.
-#pragma textflag NOSPLIT
-void
-runtime·reentersyscall(uintptr pc, uintptr sp)
-{
- void (*fn)(void);
-
- // Disable preemption because during this function g is in Gsyscall status,
- // but can have inconsistent g->sched, do not let GC observe it.
- g->m->locks++;
-
- // 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
- // will trip any stack check and leaving a flag to tell newstack to die.
- g->stackguard0 = StackPreempt;
- g->throwsplit = 1;
-
- // Leave SP around for GC and traceback.
- save(pc, sp);
- g->syscallsp = sp;
- g->syscallpc = pc;
- runtime·casgstatus(g, Grunning, Gsyscall);
- if(g->syscallsp < g->stack.lo || g->stack.hi < g->syscallsp) {
- fn = entersyscall_bad;
- runtime·onM(&fn);
- }
-
- if(runtime·atomicload(&runtime·sched.sysmonwait)) { // TODO: fast atomic
- fn = entersyscall_sysmon;
- runtime·onM(&fn);
- save(pc, sp);
- }
-
- g->m->mcache = nil;
- g->m->p->m = nil;
- runtime·atomicstore(&g->m->p->status, Psyscall);
- if(runtime·sched.gcwaiting) {
- fn = entersyscall_gcwait;
- runtime·onM(&fn);
- save(pc, sp);
- }
-
- // Goroutines must not split stacks in Gsyscall status (it would corrupt g->sched).
- // We set stackguard to StackPreempt so that first split stack check calls morestack.
- // Morestack detects this case and throws.
- g->stackguard0 = StackPreempt;
- g->m->locks--;
-}
-
-// Standard syscall entry used by the go syscall library and normal cgo calls.
-#pragma textflag NOSPLIT
-void
-·entersyscall(int32 dummy)
-{
- runtime·reentersyscall((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy));
-}
-
-static void
-entersyscall_bad(void)
-{
- G *gp;
-
- gp = g->m->curg;
- runtime·printf("entersyscall inconsistent %p [%p,%p]\n",
- gp->syscallsp, gp->stack.lo, gp->stack.hi);
- runtime·throw("entersyscall");
-}
-
-static void
-entersyscall_sysmon(void)
-{
- runtime·lock(&runtime·sched.lock);
- if(runtime·atomicload(&runtime·sched.sysmonwait)) {
- runtime·atomicstore(&runtime·sched.sysmonwait, 0);
- runtime·notewakeup(&runtime·sched.sysmonnote);
- }
- runtime·unlock(&runtime·sched.lock);
-}
-
-static void
-entersyscall_gcwait(void)
-{
- runtime·lock(&runtime·sched.lock);
- if (runtime·sched.stopwait > 0 && runtime·cas(&g->m->p->status, Psyscall, Pgcstop)) {
- if(--runtime·sched.stopwait == 0)
- runtime·notewakeup(&runtime·sched.stopnote);
- }
- runtime·unlock(&runtime·sched.lock);
-}
-
-static void entersyscallblock_handoff(void);
-
-// The same as runtime·entersyscall(), but with a hint that the syscall is blocking.
-#pragma textflag NOSPLIT
-void
-·entersyscallblock(int32 dummy)
-{
- void (*fn)(void);
-
- g->m->locks++; // see comment in entersyscall
- g->throwsplit = 1;
- g->stackguard0 = StackPreempt; // see comment in entersyscall
-
- // Leave SP around for GC and traceback.
- save((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy));
- g->syscallsp = g->sched.sp;
- g->syscallpc = g->sched.pc;
- runtime·casgstatus(g, Grunning, Gsyscall);
- if(g->syscallsp < g->stack.lo || g->stack.hi < g->syscallsp) {
- fn = entersyscall_bad;
- runtime·onM(&fn);
- }
-
- fn = entersyscallblock_handoff;
- runtime·onM(&fn);
-
- // Resave for traceback during blocked call.
- save((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy));
-
- g->m->locks--;
-}
-
-static void
-entersyscallblock_handoff(void)
-{
- handoffp(releasep());
-}
-
-// The goroutine g exited its system call.
-// Arrange for it to run on a cpu again.
-// This is called only from the go syscall library, not
-// from the low-level system calls used by the runtime.
-#pragma textflag NOSPLIT
-void
-·exitsyscall(int32 dummy)
-{
- void (*fn)(G*);
-
- g->m->locks++; // see comment in entersyscall
-
- if(runtime·getcallersp(&dummy) > g->syscallsp)
- runtime·throw("exitsyscall: syscall frame is no longer valid");
-
- g->waitsince = 0;
- if(exitsyscallfast()) {
- // There's a cpu for us, so we can run.
- g->m->p->syscalltick++;
- // We need to cas the status and scan before resuming...
- runtime·casgstatus(g, Gsyscall, Grunning);
-
- // Garbage collector isn't running (since we are),
- // so okay to clear syscallsp.
- g->syscallsp = (uintptr)nil;
- g->m->locks--;
- if(g->preempt) {
- // restore the preemption request in case we've cleared it in newstack
- g->stackguard0 = StackPreempt;
- } else {
- // otherwise restore the real stackguard, we've spoiled it in entersyscall/entersyscallblock
- g->stackguard0 = g->stack.lo + StackGuard;
- }
- g->throwsplit = 0;
- return;
- }
-
- g->m->locks--;
-
- // Call the scheduler.
- fn = exitsyscall0;
- runtime·mcall(&fn);
-
- // Scheduler returned, so we're allowed to run now.
- // Delete the syscallsp information that we left for
- // the garbage collector during the system call.
- // Must wait until now because until gosched returns
- // we don't know for sure that the garbage collector
- // is not running.
- g->syscallsp = (uintptr)nil;
- g->m->p->syscalltick++;
- g->throwsplit = 0;
-}
-
-static void exitsyscallfast_pidle(void);
-
-#pragma textflag NOSPLIT
-static bool
-exitsyscallfast(void)
-{
- void (*fn)(void);
-
- // Freezetheworld sets stopwait but does not retake P's.
- if(runtime·sched.stopwait) {
- g->m->p = nil;
- return false;
- }
-
- // Try to re-acquire the last P.
- if(g->m->p && g->m->p->status == Psyscall && runtime·cas(&g->m->p->status, Psyscall, Prunning)) {
- // There's a cpu for us, so we can run.
- g->m->mcache = g->m->p->mcache;
- g->m->p->m = g->m;
- return true;
- }
- // Try to get any other idle P.
- g->m->p = nil;
- if(runtime·sched.pidle) {
- fn = exitsyscallfast_pidle;
- runtime·onM(&fn);
- if(g->m->scalararg[0]) {
- g->m->scalararg[0] = 0;
- return true;
- }
- }
- return false;
-}
-
-static void
-exitsyscallfast_pidle(void)
-{
- P *p;
-
- runtime·lock(&runtime·sched.lock);
- p = pidleget();
- if(p && runtime·atomicload(&runtime·sched.sysmonwait)) {
- runtime·atomicstore(&runtime·sched.sysmonwait, 0);
- runtime·notewakeup(&runtime·sched.sysmonnote);
- }
- runtime·unlock(&runtime·sched.lock);
- if(p) {
- acquirep(p);
- g->m->scalararg[0] = 1;
- } else
- g->m->scalararg[0] = 0;
-}
-
-// runtime·exitsyscall slow path on g0.
-// Failed to acquire P, enqueue gp as runnable.
-static void
-exitsyscall0(G *gp)
-{
- P *p;
-
- runtime·casgstatus(gp, Gsyscall, Grunnable);
- dropg();
- runtime·lock(&runtime·sched.lock);
- p = pidleget();
- if(p == nil)
- globrunqput(gp);
- else if(runtime·atomicload(&runtime·sched.sysmonwait)) {
- runtime·atomicstore(&runtime·sched.sysmonwait, 0);
- runtime·notewakeup(&runtime·sched.sysmonnote);
- }
- runtime·unlock(&runtime·sched.lock);
- if(p) {
- acquirep(p);
- execute(gp); // Never returns.
- }
- if(g->m->lockedg) {
- // Wait until another thread schedules gp and so m again.
- stoplockedm();
- execute(gp); // Never returns.
- }
- stopm();
- schedule(); // Never returns.
-}
-
-static void
-beforefork(void)
-{
- G *gp;
-
- gp = g->m->curg;
- // Fork can hang if preempted with signals frequently enough (see issue 5517).
- // Ensure that we stay on the same M where we disable profiling.
- gp->m->locks++;
- if(gp->m->profilehz != 0)
- runtime·resetcpuprofiler(0);
-
- // This function is called before fork in syscall package.
- // Code between fork and exec must not allocate memory nor even try to grow stack.
- // Here we spoil g->stackguard to reliably detect any attempts to grow stack.
- // runtime_AfterFork will undo this in parent process, but not in child.
- gp->stackguard0 = StackFork;
-}
-
-// Called from syscall package before fork.
-#pragma textflag NOSPLIT
-void
-syscall·runtime_BeforeFork(void)
-{
- void (*fn)(void);
-
- fn = beforefork;
- runtime·onM(&fn);
-}
-
-static void
-afterfork(void)
-{
- int32 hz;
- G *gp;
-
- gp = g->m->curg;
- // See the comment in runtime_BeforeFork.
- gp->stackguard0 = gp->stack.lo + StackGuard;
-
- hz = runtime·sched.profilehz;
- if(hz != 0)
- runtime·resetcpuprofiler(hz);
- gp->m->locks--;
-}
-
-// Called from syscall package after fork in parent.
-#pragma textflag NOSPLIT
-void
-syscall·runtime_AfterFork(void)
-{
- void (*fn)(void);
-
- fn = afterfork;
- runtime·onM(&fn);
-}
-
-// Hook used by runtime·malg to call runtime·stackalloc on the
-// scheduler stack. This exists because runtime·stackalloc insists
-// on being called on the scheduler stack, to avoid trying to grow
-// the stack while allocating a new stack segment.
-static void
-mstackalloc(G *gp)
-{
- G *newg;
- uintptr size;
-
- newg = g->m->ptrarg[0];
- size = g->m->scalararg[0];
-
- newg->stack = runtime·stackalloc(size);
-
- runtime·gogo(&gp->sched);
-}
-
-// Allocate a new g, with a stack big enough for stacksize bytes.
-G*
-runtime·malg(int32 stacksize)
-{
- G *newg;
- void (*fn)(G*);
-
- newg = allocg();
- if(stacksize >= 0) {
- stacksize = runtime·round2(StackSystem + stacksize);
- if(g == g->m->g0) {
- // running on scheduler stack already.
- newg->stack = runtime·stackalloc(stacksize);
- } else {
- // have to call stackalloc on scheduler stack.
- g->m->scalararg[0] = stacksize;
- g->m->ptrarg[0] = newg;
- fn = mstackalloc;
- runtime·mcall(&fn);
- g->m->ptrarg[0] = nil;
- }
- newg->stackguard0 = newg->stack.lo + StackGuard;
- newg->stackguard1 = ~(uintptr)0;
- }
- return newg;
-}
-
-static void
-newproc_m(void)
-{
- byte *argp;
- void *callerpc;
- FuncVal *fn;
- int32 siz;
-
- siz = g->m->scalararg[0];
- callerpc = (void*)g->m->scalararg[1];
- argp = g->m->ptrarg[0];
- fn = (FuncVal*)g->m->ptrarg[1];
-
- runtime·newproc1(fn, argp, siz, 0, callerpc);
- g->m->ptrarg[0] = nil;
- g->m->ptrarg[1] = nil;
-}
-
-// Create a new g running fn with siz bytes of arguments.
-// Put it on the queue of g's waiting to run.
-// The compiler turns a go statement into a call to this.
-// Cannot split the stack because it assumes that the arguments
-// are available sequentially after &fn; they would not be
-// copied if a stack split occurred.
-#pragma textflag NOSPLIT
-void
-runtime·newproc(int32 siz, FuncVal* fn, ...)
-{
- byte *argp;
- void (*mfn)(void);
-
- if(thechar == '5')
- argp = (byte*)(&fn+2); // skip caller's saved LR
- else
- argp = (byte*)(&fn+1);
-
- g->m->locks++;
- g->m->scalararg[0] = siz;
- g->m->scalararg[1] = (uintptr)runtime·getcallerpc(&siz);
- g->m->ptrarg[0] = argp;
- g->m->ptrarg[1] = fn;
- mfn = newproc_m;
- runtime·onM(&mfn);
- g->m->locks--;
-}
-
-void runtime·main(void);
-
-// Create a new g running fn with narg bytes of arguments starting
-// at argp and returning nret bytes of results. callerpc is the
-// address of the go statement that created this. The new g is put
-// on the queue of g's waiting to run.
-G*
-runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
-{
- byte *sp;
- G *newg;
- P *p;
- int32 siz;
-
- if(fn == nil) {
- g->m->throwing = -1; // do not dump full stacks
- runtime·throw("go of nil func value");
- }
- g->m->locks++; // disable preemption because it can be holding p in a local var
- siz = narg + nret;
- siz = (siz+7) & ~7;
-
- // We could allocate a larger initial stack if necessary.
- // Not worth it: this is almost always an error.
- // 4*sizeof(uintreg): extra space added below
- // sizeof(uintreg): caller's LR (arm) or return address (x86, in gostartcall).
- if(siz >= StackMin - 4*sizeof(uintreg) - sizeof(uintreg))
- runtime·throw("runtime.newproc: function arguments too large for new goroutine");
-
- p = g->m->p;
- if((newg = gfget(p)) == nil) {
- newg = runtime·malg(StackMin);
- runtime·casgstatus(newg, Gidle, Gdead);
- runtime·allgadd(newg); // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack.
- }
- if(newg->stack.hi == 0)
- runtime·throw("newproc1: newg missing stack");
-
- if(runtime·readgstatus(newg) != Gdead)
- runtime·throw("newproc1: new g is not Gdead");
-
- sp = (byte*)newg->stack.hi;
- sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
- sp -= siz;
- runtime·memmove(sp, argp, narg);
- if(thechar == '5') {
- // caller's LR
- sp -= sizeof(void*);
- *(void**)sp = nil;
- }
-
- runtime·memclr((byte*)&newg->sched, sizeof newg->sched);
- newg->sched.sp = (uintptr)sp;
- newg->sched.pc = (uintptr)runtime·goexit + PCQuantum; // +PCQuantum so that previous instruction is in same function
- newg->sched.g = newg;
- runtime·gostartcallfn(&newg->sched, fn);
- newg->gopc = (uintptr)callerpc;
- runtime·casgstatus(newg, Gdead, Grunnable);
-
- if(p->goidcache == p->goidcacheend) {
- // Sched.goidgen is the last allocated id,
- // this batch must be [sched.goidgen+1, sched.goidgen+GoidCacheBatch].
- // At startup sched.goidgen=0, so main goroutine receives goid=1.
- p->goidcache = runtime·xadd64(&runtime·sched.goidgen, GoidCacheBatch);
- p->goidcache -= GoidCacheBatch - 1;
- p->goidcacheend = p->goidcache + GoidCacheBatch;
- }
- newg->goid = p->goidcache++;
- if(raceenabled)
- newg->racectx = runtime·racegostart((void*)callerpc);
- runqput(p, newg);
-
- if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0 && fn->fn != runtime·main) // TODO: fast atomic
- wakep();
- g->m->locks--;
- if(g->m->locks == 0 && g->preempt) // restore the preemption request in case we've cleared it in newstack
- g->stackguard0 = StackPreempt;
- return newg;
-}
-
-// Put on gfree list.
-// If local list is too long, transfer a batch to the global list.
-static void
-gfput(P *p, G *gp)
-{
- uintptr stksize;
-
- if(runtime·readgstatus(gp) != Gdead)
- runtime·throw("gfput: bad status (not Gdead)");
-
- stksize = gp->stack.hi - gp->stack.lo;
-
- if(stksize != FixedStack) {
- // non-standard stack size - free it.
- runtime·stackfree(gp->stack);
- gp->stack.lo = 0;
- gp->stack.hi = 0;
- gp->stackguard0 = 0;
- }
- gp->schedlink = p->gfree;
- p->gfree = gp;
- p->gfreecnt++;
- if(p->gfreecnt >= 64) {
- runtime·lock(&runtime·sched.gflock);
- while(p->gfreecnt >= 32) {
- p->gfreecnt--;
- gp = p->gfree;
- p->gfree = gp->schedlink;
- gp->schedlink = runtime·sched.gfree;
- runtime·sched.gfree = gp;
- runtime·sched.ngfree++;
- }
- runtime·unlock(&runtime·sched.gflock);
- }
-}
-
-// Get from gfree list.
-// If local list is empty, grab a batch from global list.
-static G*
-gfget(P *p)
-{
- G *gp;
- void (*fn)(G*);
-
-retry:
- gp = p->gfree;
- if(gp == nil && runtime·sched.gfree) {
- runtime·lock(&runtime·sched.gflock);
- while(p->gfreecnt < 32 && runtime·sched.gfree != nil) {
- p->gfreecnt++;
- gp = runtime·sched.gfree;
- runtime·sched.gfree = gp->schedlink;
- runtime·sched.ngfree--;
- gp->schedlink = p->gfree;
- p->gfree = gp;
- }
- runtime·unlock(&runtime·sched.gflock);
- goto retry;
- }
- if(gp) {
- p->gfree = gp->schedlink;
- p->gfreecnt--;
-
- if(gp->stack.lo == 0) {
- // Stack was deallocated in gfput. Allocate a new one.
- if(g == g->m->g0) {
- gp->stack = runtime·stackalloc(FixedStack);
- } else {
- g->m->scalararg[0] = FixedStack;
- g->m->ptrarg[0] = gp;
- fn = mstackalloc;
- runtime·mcall(&fn);
- g->m->ptrarg[0] = nil;
- }
- gp->stackguard0 = gp->stack.lo + StackGuard;
- } else {
- if(raceenabled)
- runtime·racemalloc((void*)gp->stack.lo, gp->stack.hi - gp->stack.lo);
- }
- }
- return gp;
-}
-
-// Purge all cached G's from gfree list to the global list.
-static void
-gfpurge(P *p)
-{
- G *gp;
-
- runtime·lock(&runtime·sched.gflock);
- while(p->gfreecnt != 0) {
- p->gfreecnt--;
- gp = p->gfree;
- p->gfree = gp->schedlink;
- gp->schedlink = runtime·sched.gfree;
- runtime·sched.gfree = gp;
- runtime·sched.ngfree++;
- }
- runtime·unlock(&runtime·sched.gflock);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·Breakpoint(void)
-{
- runtime·breakpoint();
-}
-
-// lockOSThread is called by runtime.LockOSThread and runtime.lockOSThread below
-// after they modify m->locked. Do not allow preemption during this call,
-// or else the m might be different in this function than in the caller.
-#pragma textflag NOSPLIT
-static void
-lockOSThread(void)
-{
- g->m->lockedg = g;
- g->lockedm = g->m;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·LockOSThread(void)
-{
- g->m->locked |= LockExternal;
- lockOSThread();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·lockOSThread(void)
-{
- g->m->locked += LockInternal;
- lockOSThread();
-}
-
-
-// unlockOSThread is called by runtime.UnlockOSThread and runtime.unlockOSThread below
-// after they update m->locked. Do not allow preemption during this call,
-// or else the m might be in different in this function than in the caller.
-#pragma textflag NOSPLIT
-static void
-unlockOSThread(void)
-{
- if(g->m->locked != 0)
- return;
- g->m->lockedg = nil;
- g->lockedm = nil;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·UnlockOSThread(void)
-{
- g->m->locked &= ~LockExternal;
- unlockOSThread();
-}
-
-static void badunlockOSThread(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·unlockOSThread(void)
-{
- void (*fn)(void);
-
- if(g->m->locked < LockInternal) {
- fn = badunlockOSThread;
- runtime·onM(&fn);
- }
- g->m->locked -= LockInternal;
- unlockOSThread();
-}
-
-static void
-badunlockOSThread(void)
-{
- runtime·throw("runtime: internal error: misuse of lockOSThread/unlockOSThread");
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·gcount(void)
-{
- P *p, **pp;
- int32 n;
-
- n = runtime·allglen - runtime·sched.ngfree;
- for(pp=runtime·allp; p=*pp; pp++)
- n -= p->gfreecnt;
- // All these variables can be changed concurrently, so the result can be inconsistent.
- // But at least the current goroutine is running.
- if(n < 1)
- n = 1;
- return n;
-}
-
-int32
-runtime·mcount(void)
-{
- return runtime·sched.mcount;
-}
-
-static struct ProfState {
- uint32 lock;
- int32 hz;
-} prof;
-
-static void System(void) { System(); }
-static void ExternalCode(void) { ExternalCode(); }
-static void GC(void) { GC(); }
-
-extern void runtime·cpuproftick(uintptr*, int32);
-extern byte runtime·etext[];
-
-// Called if we receive a SIGPROF signal.
-void
-runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
-{
- int32 n;
- bool traceback;
- // Do not use global m in this function, use mp instead.
- // On windows one m is sending reports about all the g's, so m means a wrong thing.
- byte m;
- uintptr stk[100];
-
- m = 0;
- USED(m);
-
- if(prof.hz == 0)
- return;
-
- // Profiling runs concurrently with GC, so it must not allocate.
- mp->mallocing++;
-
- // Define that a "user g" is a user-created goroutine, and a "system g"
- // is one that is m->g0 or m->gsignal. We've only made sure that we
- // can unwind user g's, so exclude the system g's.
- //
- // It is not quite as easy as testing gp == m->curg (the current user g)
- // because we might be interrupted for profiling halfway through a
- // goroutine switch. The switch involves updating three (or four) values:
- // g, PC, SP, and (on arm) LR. The PC must be the last to be updated,
- // because once it gets updated the new g is running.
- //
- // When switching from a user g to a system g, LR is not considered live,
- // so the update only affects g, SP, and PC. Since PC must be last, there
- // the possible partial transitions in ordinary execution are (1) g alone is updated,
- // (2) both g and SP are updated, and (3) SP alone is updated.
- // If g is updated, we'll see a system g and not look closer.
- // If SP alone is updated, we can detect the partial transition by checking
- // whether the SP is within g's stack bounds. (We could also require that SP
- // be changed only after g, but the stack bounds check is needed by other
- // cases, so there is no need to impose an additional requirement.)
- //
- // There is one exceptional transition to a system g, not in ordinary execution.
- // When a signal arrives, the operating system starts the signal handler running
- // with an updated PC and SP. The g is updated last, at the beginning of the
- // handler. There are two reasons this is okay. First, until g is updated the
- // g and SP do not match, so the stack bounds check detects the partial transition.
- // Second, signal handlers currently run with signals disabled, so a profiling
- // signal cannot arrive during the handler.
- //
- // When switching from a system g to a user g, there are three possibilities.
- //
- // First, it may be that the g switch has no PC update, because the SP
- // either corresponds to a user g throughout (as in runtime.asmcgocall)
- // or because it has been arranged to look like a user g frame
- // (as in runtime.cgocallback_gofunc). In this case, since the entire
- // transition is a g+SP update, a partial transition updating just one of
- // those will be detected by the stack bounds check.
- //
- // Second, when returning from a signal handler, the PC and SP updates
- // are performed by the operating system in an atomic update, so the g
- // update must be done before them. The stack bounds check detects
- // the partial transition here, and (again) signal handlers run with signals
- // disabled, so a profiling signal cannot arrive then anyway.
- //
- // Third, the common case: it may be that the switch updates g, SP, and PC
- // separately, as in runtime.gogo.
- //
- // Because runtime.gogo is the only instance, we check whether the PC lies
- // within that function, and if so, not ask for a traceback. This approach
- // requires knowing the size of the runtime.gogo function, which we
- // record in arch_*.h and check in runtime_test.go.
- //
- // There is another apparently viable approach, recorded here in case
- // the "PC within runtime.gogo" check turns out not to be usable.
- // It would be possible to delay the update of either g or SP until immediately
- // before the PC update instruction. Then, because of the stack bounds check,
- // the only problematic interrupt point is just before that PC update instruction,
- // and the sigprof handler can detect that instruction and simulate stepping past
- // it in order to reach a consistent state. On ARM, the update of g must be made
- // in two places (in R10 and also in a TLS slot), so the delayed update would
- // need to be the SP update. The sigprof handler must read the instruction at
- // the current PC and if it was the known instruction (for example, JMP BX or
- // MOV R2, PC), use that other register in place of the PC value.
- // The biggest drawback to this solution is that it requires that we can tell
- // whether it's safe to read from the memory pointed at by PC.
- // In a correct program, we can test PC == nil and otherwise read,
- // but if a profiling signal happens at the instant that a program executes
- // a bad jump (before the program manages to handle the resulting fault)
- // the profiling handler could fault trying to read nonexistent memory.
- //
- // To recap, there are no constraints on the assembly being used for the
- // transition. We simply require that g and SP match and that the PC is not
- // in runtime.gogo.
- traceback = true;
- if(gp == nil || gp != mp->curg ||
- (uintptr)sp < gp->stack.lo || gp->stack.hi < (uintptr)sp ||
- ((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGogoBytes))
- traceback = false;
-
- n = 0;
- if(traceback)
- n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, TraceTrap);
- if(!traceback || n <= 0) {
- // Normal traceback is impossible or has failed.
- // See if it falls into several common cases.
- n = 0;
- if(mp->ncgo > 0 && mp->curg != nil &&
- mp->curg->syscallpc != 0 && mp->curg->syscallsp != 0) {
- // Cgo, we can't unwind and symbolize arbitrary C code,
- // so instead collect Go stack that leads to the cgo call.
- // This is especially important on windows, since all syscalls are cgo calls.
- n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, stk, nelem(stk), nil, nil, 0);
- }
-#ifdef GOOS_windows
- if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) {
- // Libcall, i.e. runtime syscall on windows.
- // Collect Go stack that leads to the call.
- n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, stk, nelem(stk), nil, nil, 0);
- }
-#endif
- if(n == 0) {
- // If all of the above has failed, account it against abstract "System" or "GC".
- n = 2;
- // "ExternalCode" is better than "etext".
- if((uintptr)pc > (uintptr)runtime·etext)
- pc = (byte*)ExternalCode + PCQuantum;
- stk[0] = (uintptr)pc;
- if(mp->gcing || mp->helpgc)
- stk[1] = (uintptr)GC + PCQuantum;
- else
- stk[1] = (uintptr)System + PCQuantum;
- }
- }
-
- if(prof.hz != 0) {
- // Simple cas-lock to coordinate with setcpuprofilerate.
- while(!runtime·cas(&prof.lock, 0, 1))
- runtime·osyield();
- if(prof.hz != 0)
- runtime·cpuproftick(stk, n);
- runtime·atomicstore(&prof.lock, 0);
- }
- mp->mallocing--;
-}
-
-// Arrange to call fn with a traceback hz times a second.
-void
-runtime·setcpuprofilerate_m(void)
-{
- int32 hz;
-
- hz = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
-
- // Force sane arguments.
- if(hz < 0)
- hz = 0;
-
- // Disable preemption, otherwise we can be rescheduled to another thread
- // that has profiling enabled.
- g->m->locks++;
-
- // Stop profiler on this thread so that it is safe to lock prof.
- // if a profiling signal came in while we had prof locked,
- // it would deadlock.
- runtime·resetcpuprofiler(0);
-
- while(!runtime·cas(&prof.lock, 0, 1))
- runtime·osyield();
- prof.hz = hz;
- runtime·atomicstore(&prof.lock, 0);
-
- runtime·lock(&runtime·sched.lock);
- runtime·sched.profilehz = hz;
- runtime·unlock(&runtime·sched.lock);
-
- if(hz != 0)
- runtime·resetcpuprofiler(hz);
-
- g->m->locks--;
-}
-
-P *runtime·newP(void);
-
-// Change number of processors. The world is stopped, sched is locked.
-static void
-procresize(int32 new)
-{
- int32 i, old;
- bool empty;
- G *gp;
- P *p;
-
- old = runtime·gomaxprocs;
- if(old < 0 || old > MaxGomaxprocs || new <= 0 || new >MaxGomaxprocs)
- runtime·throw("procresize: invalid arg");
- // initialize new P's
- for(i = 0; i < new; i++) {
- p = runtime·allp[i];
- if(p == nil) {
- p = runtime·newP();
- p->id = i;
- p->status = Pgcstop;
- runtime·atomicstorep(&runtime·allp[i], p);
- }
- if(p->mcache == nil) {
- if(old==0 && i==0)
- p->mcache = g->m->mcache; // bootstrap
- else
- p->mcache = runtime·allocmcache();
- }
- }
-
- // redistribute runnable G's evenly
- // collect all runnable goroutines in global queue preserving FIFO order
- // FIFO order is required to ensure fairness even during frequent GCs
- // see http://golang.org/issue/7126
- empty = false;
- while(!empty) {
- empty = true;
- for(i = 0; i < old; i++) {
- p = runtime·allp[i];
- if(p->runqhead == p->runqtail)
- continue;
- empty = false;
- // pop from tail of local queue
- p->runqtail--;
- gp = p->runq[p->runqtail%nelem(p->runq)];
- // push onto head of global queue
- gp->schedlink = runtime·sched.runqhead;
- runtime·sched.runqhead = gp;
- if(runtime·sched.runqtail == nil)
- runtime·sched.runqtail = gp;
- runtime·sched.runqsize++;
- }
- }
- // fill local queues with at most nelem(p->runq)/2 goroutines
- // start at 1 because current M already executes some G and will acquire allp[0] below,
- // so if we have a spare G we want to put it into allp[1].
- for(i = 1; i < new * nelem(p->runq)/2 && runtime·sched.runqsize > 0; i++) {
- gp = runtime·sched.runqhead;
- runtime·sched.runqhead = gp->schedlink;
- if(runtime·sched.runqhead == nil)
- runtime·sched.runqtail = nil;
- runtime·sched.runqsize--;
- runqput(runtime·allp[i%new], gp);
- }
-
- // free unused P's
- for(i = new; i < old; i++) {
- p = runtime·allp[i];
- runtime·freemcache(p->mcache);
- p->mcache = nil;
- gfpurge(p);
- p->status = Pdead;
- // can't free P itself because it can be referenced by an M in syscall
- }
-
- if(g->m->p)
- g->m->p->m = nil;
- g->m->p = nil;
- g->m->mcache = nil;
- p = runtime·allp[0];
- p->m = nil;
- p->status = Pidle;
- acquirep(p);
- for(i = new-1; i > 0; i--) {
- p = runtime·allp[i];
- p->status = Pidle;
- pidleput(p);
- }
- runtime·atomicstore((uint32*)&runtime·gomaxprocs, new);
-}
-
-// Associate p and the current m.
-static void
-acquirep(P *p)
-{
- if(g->m->p || g->m->mcache)
- runtime·throw("acquirep: already in go");
- if(p->m || p->status != Pidle) {
- runtime·printf("acquirep: p->m=%p(%d) p->status=%d\n", p->m, p->m ? p->m->id : 0, p->status);
- runtime·throw("acquirep: invalid p state");
- }
- g->m->mcache = p->mcache;
- g->m->p = p;
- p->m = g->m;
- p->status = Prunning;
-}
-
-// Disassociate p and the current m.
-static P*
-releasep(void)
-{
- P *p;
-
- if(g->m->p == nil || g->m->mcache == nil)
- runtime·throw("releasep: invalid arg");
- p = g->m->p;
- if(p->m != g->m || p->mcache != g->m->mcache || p->status != Prunning) {
- runtime·printf("releasep: m=%p m->p=%p p->m=%p m->mcache=%p p->mcache=%p p->status=%d\n",
- g->m, g->m->p, p->m, g->m->mcache, p->mcache, p->status);
- runtime·throw("releasep: invalid p state");
- }
- g->m->p = nil;
- g->m->mcache = nil;
- p->m = nil;
- p->status = Pidle;
- return p;
-}
-
-static void
-incidlelocked(int32 v)
-{
- runtime·lock(&runtime·sched.lock);
- runtime·sched.nmidlelocked += v;
- if(v > 0)
- checkdead();
- runtime·unlock(&runtime·sched.lock);
-}
-
-// Check for deadlock situation.
-// The check is based on number of running M's, if 0 -> deadlock.
-static void
-checkdead(void)
-{
- G *gp;
- P *p;
- M *mp;
- int32 run, grunning, s;
- uintptr i;
-
- // -1 for sysmon
- run = runtime·sched.mcount - runtime·sched.nmidle - runtime·sched.nmidlelocked - 1;
- if(run > 0)
- return;
- // If we are dying because of a signal caught on an already idle thread,
- // freezetheworld will cause all running threads to block.
- // And runtime will essentially enter into deadlock state,
- // except that there is a thread that will call runtime·exit soon.
- if(runtime·panicking > 0)
- return;
- if(run < 0) {
- runtime·printf("runtime: checkdead: nmidle=%d nmidlelocked=%d mcount=%d\n",
- runtime·sched.nmidle, runtime·sched.nmidlelocked, runtime·sched.mcount);
- runtime·throw("checkdead: inconsistent counts");
- }
- grunning = 0;
- runtime·lock(&runtime·allglock);
- for(i = 0; i < runtime·allglen; i++) {
- gp = runtime·allg[i];
- if(gp->issystem)
- continue;
- s = runtime·readgstatus(gp);
- switch(s&~Gscan) {
- case Gwaiting:
- grunning++;
- break;
- case Grunnable:
- case Grunning:
- case Gsyscall:
- runtime·unlock(&runtime·allglock);
- runtime·printf("runtime: checkdead: find g %D in status %d\n", gp->goid, s);
- runtime·throw("checkdead: runnable g");
- break;
- }
- }
- runtime·unlock(&runtime·allglock);
- if(grunning == 0) // possible if main goroutine calls runtime·Goexit()
- runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!");
-
- // Maybe jump time forward for playground.
- if((gp = runtime·timejump()) != nil) {
- runtime·casgstatus(gp, Gwaiting, Grunnable);
- globrunqput(gp);
- p = pidleget();
- if(p == nil)
- runtime·throw("checkdead: no p for timer");
- mp = mget();
- if(mp == nil)
- newm(nil, p);
- else {
- mp->nextp = p;
- runtime·notewakeup(&mp->park);
- }
- return;
- }
-
- g->m->throwing = -1; // do not dump full stacks
- runtime·throw("all goroutines are asleep - deadlock!");
-}
-
-static void
-sysmon(void)
-{
- uint32 idle, delay, nscavenge;
- int64 now, unixnow, lastpoll, lasttrace, lastgc;
- int64 forcegcperiod, scavengelimit, lastscavenge, maxsleep;
- G *gp;
-
- // If we go two minutes without a garbage collection, force one to run.
- forcegcperiod = 2*60*1e9;
- // If a heap span goes unused for 5 minutes after a garbage collection,
- // we hand it back to the operating system.
- scavengelimit = 5*60*1e9;
- if(runtime·debug.scavenge > 0) {
- // Scavenge-a-lot for testing.
- forcegcperiod = 10*1e6;
- scavengelimit = 20*1e6;
- }
- lastscavenge = runtime·nanotime();
- nscavenge = 0;
- // Make wake-up period small enough for the sampling to be correct.
- maxsleep = forcegcperiod/2;
- if(scavengelimit < forcegcperiod)
- maxsleep = scavengelimit/2;
-
- lasttrace = 0;
- idle = 0; // how many cycles in succession we had not wokeup somebody
- delay = 0;
- for(;;) {
- if(idle == 0) // start with 20us sleep...
- delay = 20;
- else if(idle > 50) // start doubling the sleep after 1ms...
- delay *= 2;
- if(delay > 10*1000) // up to 10ms
- delay = 10*1000;
- runtime·usleep(delay);
- if(runtime·debug.schedtrace <= 0 &&
- (runtime·sched.gcwaiting || runtime·atomicload(&runtime·sched.npidle) == runtime·gomaxprocs)) { // TODO: fast atomic
- runtime·lock(&runtime·sched.lock);
- if(runtime·atomicload(&runtime·sched.gcwaiting) || runtime·atomicload(&runtime·sched.npidle) == runtime·gomaxprocs) {
- runtime·atomicstore(&runtime·sched.sysmonwait, 1);
- runtime·unlock(&runtime·sched.lock);
- runtime·notetsleep(&runtime·sched.sysmonnote, maxsleep);
- runtime·lock(&runtime·sched.lock);
- runtime·atomicstore(&runtime·sched.sysmonwait, 0);
- runtime·noteclear(&runtime·sched.sysmonnote);
- idle = 0;
- delay = 20;
- }
- runtime·unlock(&runtime·sched.lock);
- }
- // poll network if not polled for more than 10ms
- lastpoll = runtime·atomicload64(&runtime·sched.lastpoll);
- now = runtime·nanotime();
- unixnow = runtime·unixnanotime();
- if(lastpoll != 0 && lastpoll + 10*1000*1000 < now) {
- runtime·cas64(&runtime·sched.lastpoll, lastpoll, now);
- gp = runtime·netpoll(false); // non-blocking
- if(gp) {
- // Need to decrement number of idle locked M's
- // (pretending that one more is running) before injectglist.
- // Otherwise it can lead to the following situation:
- // injectglist grabs all P's but before it starts M's to run the P's,
- // another M returns from syscall, finishes running its G,
- // observes that there is no work to do and no other running M's
- // and reports deadlock.
- incidlelocked(-1);
- injectglist(gp);
- incidlelocked(1);
- }
- }
- // retake P's blocked in syscalls
- // and preempt long running G's
- if(retake(now))
- idle = 0;
- else
- idle++;
-
- // check if we need to force a GC
- lastgc = runtime·atomicload64(&mstats.last_gc);
- if(lastgc != 0 && unixnow - lastgc > forcegcperiod && runtime·atomicload(&runtime·forcegc.idle)) {
- runtime·lock(&runtime·forcegc.lock);
- runtime·forcegc.idle = 0;
- runtime·forcegc.g->schedlink = nil;
- injectglist(runtime·forcegc.g);
- runtime·unlock(&runtime·forcegc.lock);
- }
-
- // scavenge heap once in a while
- if(lastscavenge + scavengelimit/2 < now) {
- runtime·MHeap_Scavenge(nscavenge, now, scavengelimit);
- lastscavenge = now;
- nscavenge++;
- }
-
- if(runtime·debug.schedtrace > 0 && lasttrace + runtime·debug.schedtrace*1000000ll <= now) {
- lasttrace = now;
- runtime·schedtrace(runtime·debug.scheddetail);
- }
- }
-}
-
-typedef struct Pdesc Pdesc;
-struct Pdesc
-{
- uint32 schedtick;
- int64 schedwhen;
- uint32 syscalltick;
- int64 syscallwhen;
-};
-#pragma dataflag NOPTR
-static Pdesc pdesc[MaxGomaxprocs];
-
-static uint32
-retake(int64 now)
-{
- uint32 i, s, n;
- int64 t;
- P *p;
- Pdesc *pd;
-
- n = 0;
- for(i = 0; i < runtime·gomaxprocs; i++) {
- p = runtime·allp[i];
- if(p==nil)
- continue;
- pd = &pdesc[i];
- s = p->status;
- if(s == Psyscall) {
- // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
- t = p->syscalltick;
- if(pd->syscalltick != t) {
- pd->syscalltick = t;
- pd->syscallwhen = now;
- continue;
- }
- // On the one hand we don't want to retake Ps if there is no other work to do,
- // but on the other hand we want to retake them eventually
- // because they can prevent the sysmon thread from deep sleep.
- if(p->runqhead == p->runqtail &&
- runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) > 0 &&
- pd->syscallwhen + 10*1000*1000 > now)
- continue;
- // Need to decrement number of idle locked M's
- // (pretending that one more is running) before the CAS.
- // Otherwise the M from which we retake can exit the syscall,
- // increment nmidle and report deadlock.
- incidlelocked(-1);
- if(runtime·cas(&p->status, s, Pidle)) {
- n++;
- handoffp(p);
- }
- incidlelocked(1);
- } else if(s == Prunning) {
- // Preempt G if it's running for more than 10ms.
- t = p->schedtick;
- if(pd->schedtick != t) {
- pd->schedtick = t;
- pd->schedwhen = now;
- continue;
- }
- if(pd->schedwhen + 10*1000*1000 > now)
- continue;
- preemptone(p);
- }
- }
- return n;
-}
-
-// Tell all goroutines that they have been preempted and they should stop.
-// This function is purely best-effort. It can fail to inform a goroutine if a
-// processor just started running it.
-// No locks need to be held.
-// Returns true if preemption request was issued to at least one goroutine.
-static bool
-preemptall(void)
-{
- P *p;
- int32 i;
- bool res;
-
- res = false;
- for(i = 0; i < runtime·gomaxprocs; i++) {
- p = runtime·allp[i];
- if(p == nil || p->status != Prunning)
- continue;
- res |= preemptone(p);
- }
- return res;
-}
-
-// Tell the goroutine running on processor P to stop.
-// This function is purely best-effort. It can incorrectly fail to inform the
-// goroutine. It can send inform the wrong goroutine. Even if it informs the
-// correct goroutine, that goroutine might ignore the request if it is
-// simultaneously executing runtime·newstack.
-// No lock needs to be held.
-// Returns true if preemption request was issued.
-// The actual preemption will happen at some point in the future
-// and will be indicated by the gp->status no longer being
-// Grunning
-static bool
-preemptone(P *p)
-{
- M *mp;
- G *gp;
-
- mp = p->m;
- if(mp == nil || mp == g->m)
- return false;
- gp = mp->curg;
- if(gp == nil || gp == mp->g0)
- return false;
- gp->preempt = true;
- // Every call in a go routine checks for stack overflow by
- // comparing the current stack pointer to gp->stackguard0.
- // Setting gp->stackguard0 to StackPreempt folds
- // preemption into the normal stack overflow check.
- gp->stackguard0 = StackPreempt;
- return true;
-}
-
-void
-runtime·schedtrace(bool detailed)
-{
- static int64 starttime;
- int64 now;
- int64 id1, id2, id3;
- int32 i, t, h;
- uintptr gi;
- int8 *fmt;
- M *mp, *lockedm;
- G *gp, *lockedg;
- P *p;
-
- now = runtime·nanotime();
- if(starttime == 0)
- starttime = now;
-
- runtime·lock(&runtime·sched.lock);
- runtime·printf("SCHED %Dms: gomaxprocs=%d idleprocs=%d threads=%d spinningthreads=%d idlethreads=%d runqueue=%d",
- (now-starttime)/1000000, runtime·gomaxprocs, runtime·sched.npidle, runtime·sched.mcount,
- runtime·sched.nmspinning, runtime·sched.nmidle, runtime·sched.runqsize);
- if(detailed) {
- runtime·printf(" gcwaiting=%d nmidlelocked=%d stopwait=%d sysmonwait=%d\n",
- runtime·sched.gcwaiting, runtime·sched.nmidlelocked,
- runtime·sched.stopwait, runtime·sched.sysmonwait);
- }
- // We must be careful while reading data from P's, M's and G's.
- // Even if we hold schedlock, most data can be changed concurrently.
- // E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil.
- for(i = 0; i < runtime·gomaxprocs; i++) {
- p = runtime·allp[i];
- if(p == nil)
- continue;
- mp = p->m;
- h = runtime·atomicload(&p->runqhead);
- t = runtime·atomicload(&p->runqtail);
- if(detailed)
- runtime·printf(" P%d: status=%d schedtick=%d syscalltick=%d m=%d runqsize=%d gfreecnt=%d\n",
- i, p->status, p->schedtick, p->syscalltick, mp ? mp->id : -1, t-h, p->gfreecnt);
- else {
- // In non-detailed mode format lengths of per-P run queues as:
- // [len1 len2 len3 len4]
- fmt = " %d";
- if(runtime·gomaxprocs == 1)
- fmt = " [%d]\n";
- else if(i == 0)
- fmt = " [%d";
- else if(i == runtime·gomaxprocs-1)
- fmt = " %d]\n";
- runtime·printf(fmt, t-h);
- }
- }
- if(!detailed) {
- runtime·unlock(&runtime·sched.lock);
- return;
- }
- for(mp = runtime·allm; mp; mp = mp->alllink) {
- p = mp->p;
- gp = mp->curg;
- lockedg = mp->lockedg;
- id1 = -1;
- if(p)
- id1 = p->id;
- id2 = -1;
- if(gp)
- id2 = gp->goid;
- id3 = -1;
- if(lockedg)
- id3 = lockedg->goid;
- runtime·printf(" M%d: p=%D curg=%D mallocing=%d throwing=%d gcing=%d"
- " locks=%d dying=%d helpgc=%d spinning=%d blocked=%d lockedg=%D\n",
- mp->id, id1, id2,
- mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->dying, mp->helpgc,
- mp->spinning, g->m->blocked, id3);
- }
- runtime·lock(&runtime·allglock);
- for(gi = 0; gi < runtime·allglen; gi++) {
- gp = runtime·allg[gi];
- mp = gp->m;
- lockedm = gp->lockedm;
- runtime·printf(" G%D: status=%d(%S) m=%d lockedm=%d\n",
- gp->goid, runtime·readgstatus(gp), gp->waitreason, mp ? mp->id : -1,
- lockedm ? lockedm->id : -1);
- }
- runtime·unlock(&runtime·allglock);
- runtime·unlock(&runtime·sched.lock);
-}
-
-// Put mp on midle list.
-// Sched must be locked.
-static void
-mput(M *mp)
-{
- mp->schedlink = runtime·sched.midle;
- runtime·sched.midle = mp;
- runtime·sched.nmidle++;
- checkdead();
-}
-
-// Try to get an m from midle list.
-// Sched must be locked.
-static M*
-mget(void)
-{
- M *mp;
-
- if((mp = runtime·sched.midle) != nil){
- runtime·sched.midle = mp->schedlink;
- runtime·sched.nmidle--;
- }
- return mp;
-}
-
-// Put gp on the global runnable queue.
-// Sched must be locked.
-static void
-globrunqput(G *gp)
-{
- gp->schedlink = nil;
- if(runtime·sched.runqtail)
- runtime·sched.runqtail->schedlink = gp;
- else
- runtime·sched.runqhead = gp;
- runtime·sched.runqtail = gp;
- runtime·sched.runqsize++;
-}
-
-// Put a batch of runnable goroutines on the global runnable queue.
-// Sched must be locked.
-static void
-globrunqputbatch(G *ghead, G *gtail, int32 n)
-{
- gtail->schedlink = nil;
- if(runtime·sched.runqtail)
- runtime·sched.runqtail->schedlink = ghead;
- else
- runtime·sched.runqhead = ghead;
- runtime·sched.runqtail = gtail;
- runtime·sched.runqsize += n;
-}
-
-// Try get a batch of G's from the global runnable queue.
-// Sched must be locked.
-static G*
-globrunqget(P *p, int32 max)
-{
- G *gp, *gp1;
- int32 n;
-
- if(runtime·sched.runqsize == 0)
- return nil;
- n = runtime·sched.runqsize/runtime·gomaxprocs+1;
- if(n > runtime·sched.runqsize)
- n = runtime·sched.runqsize;
- if(max > 0 && n > max)
- n = max;
- if(n > nelem(p->runq)/2)
- n = nelem(p->runq)/2;
- runtime·sched.runqsize -= n;
- if(runtime·sched.runqsize == 0)
- runtime·sched.runqtail = nil;
- gp = runtime·sched.runqhead;
- runtime·sched.runqhead = gp->schedlink;
- n--;
- while(n--) {
- gp1 = runtime·sched.runqhead;
- runtime·sched.runqhead = gp1->schedlink;
- runqput(p, gp1);
- }
- return gp;
-}
-
-// Put p to on pidle list.
-// Sched must be locked.
-static void
-pidleput(P *p)
-{
- p->link = runtime·sched.pidle;
- runtime·sched.pidle = p;
- runtime·xadd(&runtime·sched.npidle, 1); // TODO: fast atomic
-}
-
-// Try get a p from pidle list.
-// Sched must be locked.
-static P*
-pidleget(void)
-{
- P *p;
-
- p = runtime·sched.pidle;
- if(p) {
- runtime·sched.pidle = p->link;
- runtime·xadd(&runtime·sched.npidle, -1); // TODO: fast atomic
- }
- return p;
-}
-
-// Try to put g on local runnable queue.
-// If it's full, put onto global queue.
-// Executed only by the owner P.
-static void
-runqput(P *p, G *gp)
-{
- uint32 h, t;
-
-retry:
- h = runtime·atomicload(&p->runqhead); // load-acquire, synchronize with consumers
- t = p->runqtail;
- if(t - h < nelem(p->runq)) {
- p->runq[t%nelem(p->runq)] = gp;
- runtime·atomicstore(&p->runqtail, t+1); // store-release, makes the item available for consumption
- return;
- }
- if(runqputslow(p, gp, h, t))
- return;
- // the queue is not full, now the put above must suceed
- goto retry;
-}
-
-// Put g and a batch of work from local runnable queue on global queue.
-// Executed only by the owner P.
-static bool
-runqputslow(P *p, G *gp, uint32 h, uint32 t)
-{
- G *batch[nelem(p->runq)/2+1];
- uint32 n, i;
-
- // First, grab a batch from local queue.
- n = t-h;
- n = n/2;
- if(n != nelem(p->runq)/2)
- runtime·throw("runqputslow: queue is not full");
- for(i=0; i<n; i++)
- batch[i] = p->runq[(h+i)%nelem(p->runq)];
- if(!runtime·cas(&p->runqhead, h, h+n)) // cas-release, commits consume
- return false;
- batch[n] = gp;
- // Link the goroutines.
- for(i=0; i<n; i++)
- batch[i]->schedlink = batch[i+1];
- // Now put the batch on global queue.
- runtime·lock(&runtime·sched.lock);
- globrunqputbatch(batch[0], batch[n], n+1);
- runtime·unlock(&runtime·sched.lock);
- return true;
-}
-
-// Get g from local runnable queue.
-// Executed only by the owner P.
-static G*
-runqget(P *p)
-{
- G *gp;
- uint32 t, h;
-
- for(;;) {
- h = runtime·atomicload(&p->runqhead); // load-acquire, synchronize with other consumers
- t = p->runqtail;
- if(t == h)
- return nil;
- gp = p->runq[h%nelem(p->runq)];
- if(runtime·cas(&p->runqhead, h, h+1)) // cas-release, commits consume
- return gp;
- }
-}
-
-// Grabs a batch of goroutines from local runnable queue.
-// batch array must be of size nelem(p->runq)/2. Returns number of grabbed goroutines.
-// Can be executed by any P.
-static uint32
-runqgrab(P *p, G **batch)
-{
- uint32 t, h, n, i;
-
- for(;;) {
- h = runtime·atomicload(&p->runqhead); // load-acquire, synchronize with other consumers
- t = runtime·atomicload(&p->runqtail); // load-acquire, synchronize with the producer
- n = t-h;
- n = n - n/2;
- if(n == 0)
- break;
- if(n > nelem(p->runq)/2) // read inconsistent h and t
- continue;
- for(i=0; i<n; i++)
- batch[i] = p->runq[(h+i)%nelem(p->runq)];
- if(runtime·cas(&p->runqhead, h, h+n)) // cas-release, commits consume
- break;
- }
- return n;
-}
-
-// Steal half of elements from local runnable queue of p2
-// and put onto local runnable queue of p.
-// Returns one of the stolen elements (or nil if failed).
-static G*
-runqsteal(P *p, P *p2)
-{
- G *gp;
- G *batch[nelem(p->runq)/2];
- uint32 t, h, n, i;
-
- n = runqgrab(p2, batch);
- if(n == 0)
- return nil;
- n--;
- gp = batch[n];
- if(n == 0)
- return gp;
- h = runtime·atomicload(&p->runqhead); // load-acquire, synchronize with consumers
- t = p->runqtail;
- if(t - h + n >= nelem(p->runq))
- runtime·throw("runqsteal: runq overflow");
- for(i=0; i<n; i++, t++)
- p->runq[t%nelem(p->runq)] = batch[i];
- runtime·atomicstore(&p->runqtail, t); // store-release, makes the item available for consumption
- return gp;
-}
-
-void
-runtime·testSchedLocalQueue(void)
-{
- P *p;
- G *gs;
- int32 i, j;
-
- p = (P*)runtime·mallocgc(sizeof(*p), nil, FlagNoScan);
- gs = (G*)runtime·mallocgc(nelem(p->runq)*sizeof(*gs), nil, FlagNoScan);
-
- for(i = 0; i < nelem(p->runq); i++) {
- if(runqget(p) != nil)
- runtime·throw("runq is not empty initially");
- for(j = 0; j < i; j++)
- runqput(p, &gs[i]);
- for(j = 0; j < i; j++) {
- if(runqget(p) != &gs[i]) {
- runtime·printf("bad element at iter %d/%d\n", i, j);
- runtime·throw("bad element");
- }
- }
- if(runqget(p) != nil)
- runtime·throw("runq is not empty afterwards");
- }
-}
-
-void
-runtime·testSchedLocalQueueSteal(void)
-{
- P *p1, *p2;
- G *gs, *gp;
- int32 i, j, s;
-
- p1 = (P*)runtime·mallocgc(sizeof(*p1), nil, FlagNoScan);
- p2 = (P*)runtime·mallocgc(sizeof(*p2), nil, FlagNoScan);
- gs = (G*)runtime·mallocgc(nelem(p1->runq)*sizeof(*gs), nil, FlagNoScan);
-
- for(i = 0; i < nelem(p1->runq); i++) {
- for(j = 0; j < i; j++) {
- gs[j].sig = 0;
- runqput(p1, &gs[j]);
- }
- gp = runqsteal(p2, p1);
- s = 0;
- if(gp) {
- s++;
- gp->sig++;
- }
- while(gp = runqget(p2)) {
- s++;
- gp->sig++;
- }
- while(gp = runqget(p1))
- gp->sig++;
- for(j = 0; j < i; j++) {
- if(gs[j].sig != 1) {
- runtime·printf("bad element %d(%d) at iter %d\n", j, gs[j].sig, i);
- runtime·throw("bad element");
- }
- }
- if(s != i/2 && s != i/2+1) {
- runtime·printf("bad steal %d, want %d or %d, iter %d\n",
- s, i/2, i/2+1, i);
- runtime·throw("bad steal");
- }
- }
-}
-
-void
-runtime·setmaxthreads_m(void)
-{
- int32 in;
- int32 out;
-
- in = g->m->scalararg[0];
-
- runtime·lock(&runtime·sched.lock);
- out = runtime·sched.maxmcount;
- runtime·sched.maxmcount = in;
- checkmcount();
- runtime·unlock(&runtime·sched.lock);
-
- g->m->scalararg[0] = out;
-}
-
-static int8 experiment[] = GOEXPERIMENT; // defined in zaexperiment.h
-
-static bool
-haveexperiment(int8 *name)
-{
- int32 i, j;
-
- for(i=0; i<sizeof(experiment); i++) {
- if((i == 0 || experiment[i-1] == ',') && experiment[i] == name[0]) {
- for(j=0; name[j]; j++)
- if(experiment[i+j] != name[j])
- goto nomatch;
- if(experiment[i+j] != '\0' && experiment[i+j] != ',')
- goto nomatch;
- return 1;
- }
- nomatch:;
- }
- return 0;
-}
-
-#pragma textflag NOSPLIT
-void
-sync·runtime_procPin(intptr p)
-{
- M *mp;
-
- mp = g->m;
- // Disable preemption.
- mp->locks++;
- p = mp->p->id;
- FLUSH(&p);
-}
-
-#pragma textflag NOSPLIT
-void
-sync·runtime_procUnpin()
-{
- g->m->locks--;
-}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 517ca03df..295190cb4 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -6,8 +6,6 @@ package runtime
import "unsafe"
-func newsysmon()
-
func runtime_init()
func main_init()
func main_main()
@@ -29,7 +27,7 @@ func main() {
maxstacksize = 250000000
}
- onM(newsysmon)
+ systemstack(newsysmon)
// Lock the main goroutine onto this, the main OS thread,
// during initialization. Most programs won't care, but a few
@@ -55,6 +53,26 @@ func main() {
memstats.enablegc = true // now that runtime is initialized, GC is okay
+ if iscgo {
+ if _cgo_thread_start == nil {
+ gothrow("_cgo_thread_start missing")
+ }
+ if _cgo_malloc == nil {
+ gothrow("_cgo_malloc missing")
+ }
+ if _cgo_free == nil {
+ gothrow("_cgo_free missing")
+ }
+ if GOOS != "windows" {
+ if _cgo_setenv == nil {
+ gothrow("_cgo_setenv missing")
+ }
+ if _cgo_unsetenv == nil {
+ gothrow("_cgo_unsetenv missing")
+ }
+ }
+ }
+
main_init()
needUnlock = false
@@ -80,8 +98,6 @@ func main() {
}
}
-var parkunlock_c byte
-
// start forcegc helper goroutine
func init() {
go forcegchelper()
@@ -115,7 +131,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 unsafe.Pointer, lock unsafe.Pointer, reason string) {
+func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string) {
mp := acquirem()
gp := mp.curg
status := readgstatus(gp)
@@ -123,7 +139,7 @@ func gopark(unlockf unsafe.Pointer, lock unsafe.Pointer, reason string) {
gothrow("gopark: bad g status")
}
mp.waitlock = lock
- mp.waitunlockf = unlockf
+ mp.waitunlockf = *(*unsafe.Pointer)(unsafe.Pointer(&unlockf))
gp.waitreason = reason
releasem(mp)
// can't do anything that might move the G between Ms here.
@@ -133,14 +149,13 @@ func gopark(unlockf unsafe.Pointer, lock unsafe.Pointer, reason string) {
// 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(unsafe.Pointer(&parkunlock_c), unsafe.Pointer(lock), reason)
+ gopark(parkunlock_c, unsafe.Pointer(lock), reason)
}
func goready(gp *g) {
- mp := acquirem()
- mp.ptrarg[0] = unsafe.Pointer(gp)
- onM(ready_m)
- releasem(mp)
+ systemstack(func() {
+ ready(gp)
+ })
}
//go:nosplit
@@ -233,6 +248,11 @@ func newG() *g {
return new(g)
}
+var (
+ allgs []*g
+ allglock mutex
+)
+
func allgadd(gp *g) {
if readgstatus(gp) == _Gidle {
gothrow("allgadd: bad status Gidle")
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
new file mode 100644
index 000000000..aeded0e77
--- /dev/null
+++ b/src/runtime/proc1.go
@@ -0,0 +1,3193 @@
+// 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 runtime
+
+import "unsafe"
+
+var (
+ m0 m
+ g0 g
+)
+
+// Goroutine scheduler
+// The scheduler's job is to distribute ready-to-run goroutines over worker threads.
+//
+// The main concepts are:
+// G - goroutine.
+// M - worker thread, or machine.
+// P - processor, a resource that is required to execute Go code.
+// M must have an associated P to execute Go code, however it can be
+// blocked or in a syscall w/o an associated P.
+//
+// Design doc at http://golang.org/s/go11sched.
+
+const (
+ // Number of goroutine ids to grab from sched.goidgen to local per-P cache at once.
+ // 16 seems to provide enough amortization, but other than that it's mostly arbitrary number.
+ _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
+// call schedinit
+// make & queue new G
+// call runtime·mstart
+//
+// The new G calls runtime·main.
+func schedinit() {
+ // raceinit must be the first call to race detector.
+ // In particular, it must be done before mallocinit below calls racemapshadow.
+ _g_ := getg()
+ if raceenabled {
+ _g_.racectx = raceinit()
+ }
+
+ sched.maxmcount = 10000
+
+ tracebackinit()
+ symtabinit()
+ stackinit()
+ mallocinit()
+ mcommoninit(_g_.m)
+
+ goargs()
+ goenvs()
+ parsedebugvars()
+ gcinit()
+
+ sched.lastpoll = uint64(nanotime())
+ procs := 1
+ if n := goatoi(gogetenv("GOMAXPROCS")); n > 0 {
+ if n > _MaxGomaxprocs {
+ n = _MaxGomaxprocs
+ }
+ procs = n
+ }
+ procresize(int32(procs))
+
+ if buildVersion == "" {
+ // Condition should never trigger. This code just serves
+ // to ensure runtime·buildVersion is kept in the resulting binary.
+ buildVersion = "unknown"
+ }
+}
+
+func newsysmon() {
+ _newm(sysmon, nil)
+}
+
+func dumpgstatus(gp *g) {
+ _g_ := getg()
+ print("runtime: gp: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
+ print("runtime: g: g=", _g_, ", goid=", _g_.goid, ", g->atomicstatus=", readgstatus(_g_), "\n")
+}
+
+func checkmcount() {
+ // sched lock is held
+ if sched.mcount > sched.maxmcount {
+ print("runtime: program exceeds ", sched.maxmcount, "-thread limit\n")
+ gothrow("thread exhaustion")
+ }
+}
+
+func mcommoninit(mp *m) {
+ _g_ := getg()
+
+ // g0 stack won't make sense for user (and is not necessary unwindable).
+ if _g_ != _g_.m.g0 {
+ callers(1, &mp.createstack[0], len(mp.createstack))
+ }
+
+ mp.fastrand = 0x49f6428a + uint32(mp.id) + uint32(cputicks())
+ if mp.fastrand == 0 {
+ mp.fastrand = 0x49f6428a
+ }
+
+ lock(&sched.lock)
+ mp.id = sched.mcount
+ sched.mcount++
+ checkmcount()
+ mpreinit(mp)
+ if mp.gsignal != nil {
+ mp.gsignal.stackguard1 = mp.gsignal.stack.lo + _StackGuard
+ }
+
+ // Add to allm so garbage collector doesn't free g->m
+ // when it is just in a register or thread-local storage.
+ mp.alllink = allm
+
+ // NumCgoCall() iterates over allm w/o schedlock,
+ // so we need to publish it safely.
+ atomicstorep(unsafe.Pointer(&allm), unsafe.Pointer(mp))
+ unlock(&sched.lock)
+}
+
+// Mark gp ready to run.
+func ready(gp *g) {
+ status := readgstatus(gp)
+
+ // Mark runnable.
+ _g_ := getg()
+ _g_.m.locks++ // disable preemption because it can be holding p in a local var
+ if status&^_Gscan != _Gwaiting {
+ dumpgstatus(gp)
+ gothrow("bad g->status in ready")
+ }
+
+ // status is Gwaiting or Gscanwaiting, make Grunnable and put on runq
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ runqput(_g_.m.p, gp)
+ if atomicload(&sched.npidle) != 0 && atomicload(&sched.nmspinning) == 0 { // TODO: fast atomic
+ wakep()
+ }
+ _g_.m.locks--
+ if _g_.m.locks == 0 && _g_.preempt { // restore the preemption request in case we've cleared it in newstack
+ _g_.stackguard0 = stackPreempt
+ }
+}
+
+func gcprocs() int32 {
+ // Figure out how many CPUs to use during GC.
+ // Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
+ lock(&sched.lock)
+ n := gomaxprocs
+ if n > ncpu {
+ n = ncpu
+ }
+ if n > _MaxGcproc {
+ n = _MaxGcproc
+ }
+ if n > sched.nmidle+1 { // one M is currently running
+ n = sched.nmidle + 1
+ }
+ unlock(&sched.lock)
+ return n
+}
+
+func needaddgcproc() bool {
+ lock(&sched.lock)
+ n := gomaxprocs
+ if n > ncpu {
+ n = ncpu
+ }
+ if n > _MaxGcproc {
+ n = _MaxGcproc
+ }
+ n -= sched.nmidle + 1 // one M is currently running
+ unlock(&sched.lock)
+ return n > 0
+}
+
+func helpgc(nproc int32) {
+ _g_ := getg()
+ lock(&sched.lock)
+ pos := 0
+ for n := int32(1); n < nproc; n++ { // one M is currently running
+ if allp[pos].mcache == _g_.m.mcache {
+ pos++
+ }
+ mp := mget()
+ if mp == nil {
+ gothrow("gcprocs inconsistency")
+ }
+ mp.helpgc = n
+ mp.mcache = allp[pos].mcache
+ pos++
+ notewakeup(&mp.park)
+ }
+ unlock(&sched.lock)
+}
+
+// Similar to stoptheworld but best-effort and can be called several times.
+// There is no reverse operation, used during crashing.
+// This function must not lock any mutexes.
+func freezetheworld() {
+ if gomaxprocs == 1 {
+ return
+ }
+ // stopwait and preemption requests can be lost
+ // due to races with concurrently executing threads,
+ // so try several times
+ for i := 0; i < 5; i++ {
+ // this should tell the scheduler to not start any new goroutines
+ sched.stopwait = 0x7fffffff
+ atomicstore(&sched.gcwaiting, 1)
+ // this should stop running goroutines
+ if !preemptall() {
+ break // no running goroutines
+ }
+ usleep(1000)
+ }
+ // to be sure
+ usleep(1000)
+ preemptall()
+ usleep(1000)
+}
+
+func isscanstatus(status uint32) bool {
+ if status == _Gscan {
+ gothrow("isscanstatus: Bad status Gscan")
+ }
+ return status&_Gscan == _Gscan
+}
+
+// All reads and writes of g's status go through readgstatus, casgstatus
+// castogscanstatus, casfrom_Gscanstatus.
+//go:nosplit
+func readgstatus(gp *g) uint32 {
+ return atomicload(&gp.atomicstatus)
+}
+
+// The Gscanstatuses are acting like locks and this releases them.
+// If it proves to be a performance hit we should be able to make these
+// simple atomic stores but for now we are going to throw if
+// we see an inconsistent state.
+func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
+ success := false
+
+ // Check that transition is valid.
+ switch oldval {
+ case _Gscanrunnable,
+ _Gscanwaiting,
+ _Gscanrunning,
+ _Gscansyscall:
+ if newval == oldval&^_Gscan {
+ success = cas(&gp.atomicstatus, oldval, newval)
+ }
+ case _Gscanenqueue:
+ if newval == _Gwaiting {
+ success = cas(&gp.atomicstatus, oldval, newval)
+ }
+ }
+ if !success {
+ print("runtime: casfrom_Gscanstatus failed gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")
+ dumpgstatus(gp)
+ gothrow("casfrom_Gscanstatus: gp->status is not in scan state")
+ }
+}
+
+// This will return false if the gp is not in the expected status and the cas fails.
+// This acts like a lock acquire while the casfromgstatus acts like a lock release.
+func castogscanstatus(gp *g, oldval, newval uint32) bool {
+ switch oldval {
+ case _Grunnable,
+ _Gwaiting,
+ _Gsyscall:
+ if newval == oldval|_Gscan {
+ return cas(&gp.atomicstatus, oldval, newval)
+ }
+ case _Grunning:
+ if newval == _Gscanrunning || newval == _Gscanenqueue {
+ return cas(&gp.atomicstatus, oldval, newval)
+ }
+ }
+ print("runtime: castogscanstatus oldval=", hex(oldval), " newval=", hex(newval), "\n")
+ gothrow("castogscanstatus")
+ panic("not reached")
+}
+
+// If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus
+// and casfrom_Gscanstatus instead.
+// casgstatus will loop if the g->atomicstatus is in a Gscan status until the routine that
+// put it in the Gscan state is finished.
+//go:nosplit
+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")
+ gothrow("casgstatus: bad incoming values")
+ })
+ }
+
+ // loop if gp->atomicstatus is in a scan state giving
+ // GC time to finish and change the state to oldval.
+ for !cas(&gp.atomicstatus, oldval, newval) {
+ if oldval == _Gwaiting && gp.atomicstatus == _Grunnable {
+ systemstack(func() {
+ gothrow("casgstatus: waiting for Gwaiting but is Grunnable")
+ })
+ }
+ // Help GC if needed.
+ if gp.preemptscan && !gp.gcworkdone && (oldval == _Grunning || oldval == _Gsyscall) {
+ gp.preemptscan = false
+ systemstack(func() {
+ gcphasework(gp)
+ })
+ }
+ }
+}
+
+// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
+// Returns old status. Cannot call casgstatus directly, because we are racing with an
+// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus,
+// it might have become Grunnable by the time we get to the cas. If we called casgstatus,
+// it would loop waiting for the status to go back to Gwaiting, which it never will.
+//go:nosplit
+func casgcopystack(gp *g) uint32 {
+ for {
+ oldstatus := readgstatus(gp) &^ _Gscan
+ if oldstatus != _Gwaiting && oldstatus != _Grunnable {
+ gothrow("copystack: bad status, not Gwaiting or Grunnable")
+ }
+ if cas(&gp.atomicstatus, oldstatus, _Gcopystack) {
+ return oldstatus
+ }
+ }
+}
+
+// stopg ensures that gp is stopped at a GC safe point where its stack can be scanned
+// or in the context of a moving collector the pointers can be flipped from pointing
+// to old object to pointing to new objects.
+// If stopg returns true, the caller knows gp is at a GC safe point and will remain there until
+// the caller calls restartg.
+// If stopg returns false, the caller is not responsible for calling restartg. This can happen
+// if another thread, either the gp itself or another GC thread is taking the responsibility
+// to do the GC work related to this thread.
+func stopg(gp *g) bool {
+ for {
+ if gp.gcworkdone {
+ return false
+ }
+
+ switch s := readgstatus(gp); s {
+ default:
+ dumpgstatus(gp)
+ gothrow("stopg: gp->atomicstatus is not valid")
+
+ case _Gdead:
+ return false
+
+ case _Gcopystack:
+ // Loop until a new stack is in place.
+
+ case _Grunnable,
+ _Gsyscall,
+ _Gwaiting:
+ // Claim goroutine by setting scan bit.
+ if !castogscanstatus(gp, s, s|_Gscan) {
+ break
+ }
+ // In scan state, do work.
+ gcphasework(gp)
+ return true
+
+ case _Gscanrunnable,
+ _Gscanwaiting,
+ _Gscansyscall:
+ // Goroutine already claimed by another GC helper.
+ return false
+
+ case _Grunning:
+ // Claim goroutine, so we aren't racing with a status
+ // transition away from Grunning.
+ if !castogscanstatus(gp, _Grunning, _Gscanrunning) {
+ break
+ }
+
+ // Mark gp for preemption.
+ if !gp.gcworkdone {
+ gp.preemptscan = true
+ gp.preempt = true
+ gp.stackguard0 = stackPreempt
+ }
+
+ // Unclaim.
+ casfrom_Gscanstatus(gp, _Gscanrunning, _Grunning)
+ return false
+ }
+ }
+}
+
+// The GC requests that this routine be moved from a scanmumble state to a mumble state.
+func restartg(gp *g) {
+ s := readgstatus(gp)
+ switch s {
+ default:
+ dumpgstatus(gp)
+ gothrow("restartg: unexpected status")
+
+ case _Gdead:
+ // ok
+
+ case _Gscanrunnable,
+ _Gscanwaiting,
+ _Gscansyscall:
+ casfrom_Gscanstatus(gp, s, s&^_Gscan)
+
+ // Scan is now completed.
+ // Goroutine now needs to be made runnable.
+ // We put it on the global run queue; ready blocks on the global scheduler lock.
+ case _Gscanenqueue:
+ casfrom_Gscanstatus(gp, _Gscanenqueue, _Gwaiting)
+ if gp != getg().m.curg {
+ gothrow("processing Gscanenqueue on wrong m")
+ }
+ dropg()
+ ready(gp)
+ }
+}
+
+func stopscanstart(gp *g) {
+ _g_ := getg()
+ if _g_ == gp {
+ gothrow("GC not moved to G0")
+ }
+ if stopg(gp) {
+ if !isscanstatus(readgstatus(gp)) {
+ dumpgstatus(gp)
+ gothrow("GC not in scan state")
+ }
+ restartg(gp)
+ }
+}
+
+// Runs on g0 and does the actual work after putting the g back on the run queue.
+func mquiesce(gpmaster *g) {
+ activeglen := len(allgs)
+ // enqueue the calling goroutine.
+ restartg(gpmaster)
+ for i := 0; i < activeglen; i++ {
+ gp := allgs[i]
+ if readgstatus(gp) == _Gdead {
+ gp.gcworkdone = true // noop scan.
+ } else {
+ gp.gcworkdone = false
+ }
+ stopscanstart(gp)
+ }
+
+ // Check that the G's gcwork (such as scanning) has been done. If not do it now.
+ // You can end up doing work here if the page trap on a Grunning Goroutine has
+ // not been sprung or in some race situations. For example a runnable goes dead
+ // and is started up again with a gp->gcworkdone set to false.
+ for i := 0; i < activeglen; i++ {
+ gp := allgs[i]
+ for !gp.gcworkdone {
+ status := readgstatus(gp)
+ if status == _Gdead {
+ //do nothing, scan not needed.
+ gp.gcworkdone = true // scan is a noop
+ break
+ }
+ if status == _Grunning && gp.stackguard0 == uintptr(stackPreempt) && notetsleep(&sched.stopnote, 100*1000) { // nanosecond arg
+ noteclear(&sched.stopnote)
+ } else {
+ stopscanstart(gp)
+ }
+ }
+ }
+
+ for i := 0; i < activeglen; i++ {
+ gp := allgs[i]
+ status := readgstatus(gp)
+ if isscanstatus(status) {
+ print("mstopandscang:bottom: post scan bad status gp=", gp, " has status ", hex(status), "\n")
+ dumpgstatus(gp)
+ }
+ if !gp.gcworkdone && status != _Gdead {
+ print("mstopandscang:bottom: post scan gp=", gp, "->gcworkdone still false\n")
+ dumpgstatus(gp)
+ }
+ }
+
+ schedule() // Never returns.
+}
+
+// quiesce moves all the goroutines to a GC safepoint which for now is a at preemption point.
+// If the global gcphase is GCmark quiesce will ensure that all of the goroutine's stacks
+// have been scanned before it returns.
+func quiesce(mastergp *g) {
+ castogscanstatus(mastergp, _Grunning, _Gscanenqueue)
+ // Now move this to the g0 (aka m) stack.
+ // g0 will potentially scan this thread and put mastergp on the runqueue
+ mcall(mquiesce)
+}
+
+// This is used by the GC as well as the routines that do stack dumps. In the case
+// of GC all the routines can be reliably stopped. This is not always the case
+// when the system is in panic or being exited.
+func stoptheworld() {
+ _g_ := getg()
+
+ // If we hold a lock, then we won't be able to stop another M
+ // that is blocked trying to acquire the lock.
+ if _g_.m.locks > 0 {
+ gothrow("stoptheworld: holding locks")
+ }
+
+ lock(&sched.lock)
+ sched.stopwait = gomaxprocs
+ atomicstore(&sched.gcwaiting, 1)
+ preemptall()
+ // stop current P
+ _g_.m.p.status = _Pgcstop // Pgcstop is only diagnostic.
+ sched.stopwait--
+ // try to retake all P's in Psyscall status
+ for i := 0; i < int(gomaxprocs); i++ {
+ p := allp[i]
+ s := p.status
+ if s == _Psyscall && cas(&p.status, s, _Pgcstop) {
+ sched.stopwait--
+ }
+ }
+ // stop idle P's
+ for {
+ p := pidleget()
+ if p == nil {
+ break
+ }
+ p.status = _Pgcstop
+ sched.stopwait--
+ }
+ wait := sched.stopwait > 0
+ unlock(&sched.lock)
+
+ // wait for remaining P's to stop voluntarily
+ if wait {
+ for {
+ // wait for 100us, then try to re-preempt in case of any races
+ if notetsleep(&sched.stopnote, 100*1000) {
+ noteclear(&sched.stopnote)
+ break
+ }
+ preemptall()
+ }
+ }
+ if sched.stopwait != 0 {
+ gothrow("stoptheworld: not stopped")
+ }
+ for i := 0; i < int(gomaxprocs); i++ {
+ p := allp[i]
+ if p.status != _Pgcstop {
+ gothrow("stoptheworld: not stopped")
+ }
+ }
+}
+
+func mhelpgc() {
+ _g_ := getg()
+ _g_.m.helpgc = -1
+}
+
+func starttheworld() {
+ _g_ := getg()
+
+ _g_.m.locks++ // disable preemption because it can be holding p in a local var
+ gp := netpoll(false) // non-blocking
+ injectglist(gp)
+ add := needaddgcproc()
+ lock(&sched.lock)
+ if newprocs != 0 {
+ procresize(newprocs)
+ newprocs = 0
+ } else {
+ procresize(gomaxprocs)
+ }
+ sched.gcwaiting = 0
+
+ var p1 *p
+ for {
+ p := pidleget()
+ if p == nil {
+ break
+ }
+ // procresize() puts p's with work at the beginning of the list.
+ // Once we reach a p without a run queue, the rest don't have one either.
+ if p.runqhead == p.runqtail {
+ pidleput(p)
+ break
+ }
+ p.m = mget()
+ p.link = p1
+ p1 = p
+ }
+ if sched.sysmonwait != 0 {
+ sched.sysmonwait = 0
+ notewakeup(&sched.sysmonnote)
+ }
+ unlock(&sched.lock)
+
+ for p1 != nil {
+ p := p1
+ p1 = p1.link
+ if p.m != nil {
+ mp := p.m
+ p.m = nil
+ if mp.nextp != nil {
+ gothrow("starttheworld: inconsistent mp->nextp")
+ }
+ mp.nextp = p
+ notewakeup(&mp.park)
+ } else {
+ // Start M to run P. Do not start another M below.
+ _newm(nil, p)
+ add = false
+ }
+ }
+
+ if add {
+ // If GC could have used another helper proc, start one now,
+ // in the hope that it will be available next time.
+ // It would have been even better to start it before the collection,
+ // but doing so requires allocating memory, so it's tricky to
+ // coordinate. This lazy approach works out in practice:
+ // we don't mind if the first couple gc rounds don't have quite
+ // the maximum number of procs.
+ _newm(mhelpgc, nil)
+ }
+ _g_.m.locks--
+ if _g_.m.locks == 0 && _g_.preempt { // restore the preemption request in case we've cleared it in newstack
+ _g_.stackguard0 = stackPreempt
+ }
+}
+
+// Called to start an M.
+//go:nosplit
+func mstart() {
+ _g_ := getg()
+
+ if _g_.stack.lo == 0 {
+ // Initialize stack bounds from system stack.
+ // Cgo may have left stack size in stack.hi.
+ size := _g_.stack.hi
+ if size == 0 {
+ size = 8192
+ }
+ _g_.stack.hi = uintptr(noescape(unsafe.Pointer(&size)))
+ _g_.stack.lo = _g_.stack.hi - size + 1024
+ }
+ // Initialize stack guards so that we can start calling
+ // both Go and C functions with stack growth prologues.
+ _g_.stackguard0 = _g_.stack.lo + _StackGuard
+ _g_.stackguard1 = _g_.stackguard0
+ mstart1()
+}
+
+func mstart1() {
+ _g_ := getg()
+
+ if _g_ != _g_.m.g0 {
+ gothrow("bad runtime·mstart")
+ }
+
+ // Record top of stack for use by mcall.
+ // Once we call schedule we're never coming back,
+ // so other calls can reuse this stack space.
+ gosave(&_g_.m.g0.sched)
+ _g_.m.g0.sched.pc = ^uintptr(0) // make sure it is never used
+ asminit()
+ minit()
+
+ // Install signal handlers; after minit so that minit can
+ // prepare the thread to be able to handle the signals.
+ if _g_.m == &m0 {
+ initsig()
+ }
+
+ if _g_.m.mstartfn != nil {
+ fn := *(*func())(unsafe.Pointer(&_g_.m.mstartfn))
+ fn()
+ }
+
+ if _g_.m.helpgc != 0 {
+ _g_.m.helpgc = 0
+ stopm()
+ } else if _g_.m != &m0 {
+ acquirep(_g_.m.nextp)
+ _g_.m.nextp = nil
+ }
+ schedule()
+
+ // TODO(brainman): This point is never reached, because scheduler
+ // does not release os threads at the moment. But once this path
+ // is enabled, we must remove our seh here.
+}
+
+// When running with cgo, we call _cgo_thread_start
+// to start threads for us so that we can play nicely with
+// foreign code.
+var cgoThreadStart unsafe.Pointer
+
+type cgothreadstart struct {
+ g *g
+ tls *uint64
+ fn unsafe.Pointer
+}
+
+// Allocate a new m unassociated with any thread.
+// Can use p for allocation context if needed.
+func allocm(_p_ *p) *m {
+ _g_ := getg()
+ _g_.m.locks++ // disable GC because it can be called from sysmon
+ if _g_.m.p == nil {
+ acquirep(_p_) // temporarily borrow p for mallocs in this function
+ }
+ mp := newM()
+ mcommoninit(mp)
+
+ // In case of cgo or Solaris, pthread_create will make us a stack.
+ // Windows and Plan 9 will layout sched stack on OS stack.
+ if iscgo || GOOS == "solaris" || GOOS == "windows" || GOOS == "plan9" {
+ mp.g0 = malg(-1)
+ } else {
+ mp.g0 = malg(8192)
+ }
+ mp.g0.m = mp
+
+ if _p_ == _g_.m.p {
+ releasep()
+ }
+ _g_.m.locks--
+ if _g_.m.locks == 0 && _g_.preempt { // restore the preemption request in case we've cleared it in newstack
+ _g_.stackguard0 = stackPreempt
+ }
+
+ 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
+// and return with m, g initialized correctly.
+// Since m and g are not set now (likely nil, but see below)
+// needm is limited in what routines it can call. In particular
+// it can only call nosplit functions (textflag 7) and cannot
+// do any scheduling that requires an m.
+//
+// In order to avoid needing heavy lifting here, we adopt
+// the following strategy: there is a stack of available m's
+// that can be stolen. Using compare-and-swap
+// to pop from the stack has ABA races, so we simulate
+// a lock by doing an exchange (via casp) to steal the stack
+// head and replace the top pointer with MLOCKED (1).
+// This serves as a simple spin lock that we can use even
+// without an m. The thread that locks the stack in this way
+// unlocks the stack by storing a valid stack head pointer.
+//
+// In order to make sure that there is always an m structure
+// available to be stolen, we maintain the invariant that there
+// is always one more than needed. At the beginning of the
+// program (if cgo is in use) the list is seeded with a single m.
+// If needm finds that it has taken the last m off the list, its job
+// is - once it has installed its own m so that it can do things like
+// allocate memory - to create a spare m and put it on the list.
+//
+// Each of these extra m's also has a g0 and a curg that are
+// pressed into service as the scheduling stack and current
+// goroutine for the duration of the cgo callback.
+//
+// When the callback is done with the m, it calls dropm to
+// put the m back on the list.
+//go:nosplit
+func needm(x byte) {
+ if needextram != 0 {
+ // Can happen if C/C++ code calls Go from a global ctor.
+ // Can not throw, because scheduler is not initialized yet.
+ // XXX
+ // write(2, unsafe.Pointer("fatal error: cgo callback before cgo call\n"), sizeof("fatal error: cgo callback before cgo call\n") - 1)
+ exit(1)
+ }
+
+ // Lock extra list, take head, unlock popped list.
+ // nilokay=false is safe here because of the invariant above,
+ // that the extra list always contains or will soon contain
+ // at least one m.
+ mp := lockextra(false)
+
+ // Set needextram when we've just emptied the list,
+ // so that the eventual call into cgocallbackg will
+ // allocate a new m for the extra list. We delay the
+ // allocation until then so that it can be done
+ // after exitsyscall makes sure it is okay to be
+ // running at all (that is, there's no garbage collection
+ // running right now).
+ mp.needextram = mp.schedlink == nil
+ unlockextra(mp.schedlink)
+
+ // Install g (= m->g0) and set the stack bounds
+ // to match the current stack. We don't actually know
+ // how big the stack is, like we don't know how big any
+ // scheduling stack is, but we assume there's at least 32 kB,
+ // which is more than enough for us.
+ setg(mp.g0)
+ _g_ := getg()
+ _g_.stack.hi = uintptr(noescape(unsafe.Pointer(&x))) + 1024
+ _g_.stack.lo = uintptr(noescape(unsafe.Pointer(&x))) - 32*1024
+ _g_.stackguard0 = _g_.stack.lo + _StackGuard
+
+ // Initialize this thread to use the m.
+ asminit()
+ minit()
+}
+
+// newextram allocates an m and puts it on the extra list.
+// It is called with a working local m, so that it can do things
+// like call schedlock and allocate.
+func newextram() {
+ // Create extra goroutine locked to extra m.
+ // The goroutine is the context in which the cgo callback will run.
+ // The sched.pc will never be returned to, but setting it to
+ // goexit makes clear to the traceback routines where
+ // the goroutine stack ends.
+ mp := allocm(nil)
+ gp := malg(4096)
+ gp.sched.pc = funcPC(goexit) + _PCQuantum
+ gp.sched.sp = gp.stack.hi
+ gp.sched.sp -= 4 * regSize // extra space in case of reads slightly beyond frame
+ gp.sched.lr = 0
+ gp.sched.g = gp
+ gp.syscallpc = gp.sched.pc
+ gp.syscallsp = gp.sched.sp
+ // malg returns status as Gidle, change to Gsyscall before adding to allg
+ // where GC will see it.
+ casgstatus(gp, _Gidle, _Gsyscall)
+ gp.m = mp
+ mp.curg = gp
+ mp.locked = _LockInternal
+ mp.lockedg = gp
+ gp.lockedm = mp
+ gp.goid = int64(xadd64(&sched.goidgen, 1))
+ if raceenabled {
+ gp.racectx = racegostart(funcPC(newextram))
+ }
+ // put on allg for garbage collector
+ allgadd(gp)
+
+ // Add m to the extra list.
+ mnext := lockextra(true)
+ mp.schedlink = mnext
+ unlockextra(mp)
+}
+
+// dropm is called when a cgo callback has called needm but is now
+// done with the callback and returning back into the non-Go thread.
+// It puts the current m back onto the extra list.
+//
+// The main expense here is the call to signalstack to release the
+// m's signal stack, and then the call to needm on the next callback
+// from this thread. It is tempting to try to save the m for next time,
+// which would eliminate both these costs, but there might not be
+// a next time: the current thread (which Go does not control) might exit.
+// If we saved the m for that thread, there would be an m leak each time
+// such a thread exited. Instead, we acquire and release an m on each
+// call. These should typically not be scheduling operations, just a few
+// atomics, so the cost should be small.
+//
+// TODO(rsc): An alternative would be to allocate a dummy pthread per-thread
+// variable using pthread_key_create. Unlike the pthread keys we already use
+// on OS X, this dummy key would never be read by Go code. It would exist
+// only so that we could register at thread-exit-time destructor.
+// That destructor would put the m back onto the extra list.
+// This is purely a performance optimization. The current version,
+// in which dropm happens on each cgo call, is still correct too.
+// We may have to keep the current version on systems with cgo
+// but without pthreads, like Windows.
+func dropm() {
+ // Undo whatever initialization minit did during needm.
+ unminit()
+
+ // Clear m and g, and return m to the extra list.
+ // After the call to setmg we can only call nosplit functions.
+ mp := getg().m
+ setg(nil)
+
+ mnext := lockextra(true)
+ mp.schedlink = mnext
+ unlockextra(mp)
+}
+
+var extram uintptr
+
+// lockextra locks the extra list and returns the list head.
+// The caller must unlock the list by storing a new list head
+// to extram. If nilokay is true, then lockextra will
+// return a nil list head if that's what it finds. If nilokay is false,
+// lockextra will keep waiting until the list head is no longer nil.
+//go:nosplit
+func lockextra(nilokay bool) *m {
+ const locked = 1
+
+ for {
+ old := atomicloaduintptr(&extram)
+ if old == locked {
+ yield := osyield
+ yield()
+ continue
+ }
+ if old == 0 && !nilokay {
+ usleep(1)
+ continue
+ }
+ if casuintptr(&extram, old, locked) {
+ return (*m)(unsafe.Pointer(old))
+ }
+ yield := osyield
+ yield()
+ continue
+ }
+}
+
+//go:nosplit
+func unlockextra(mp *m) {
+ atomicstoreuintptr(&extram, uintptr(unsafe.Pointer(mp)))
+}
+
+// Create a new m. It will start off with a call to fn, or else the scheduler.
+func _newm(fn func(), _p_ *p) {
+ mp := allocm(_p_)
+ mp.nextp = _p_
+ mp.mstartfn = *(*unsafe.Pointer)(unsafe.Pointer(&fn))
+
+ if iscgo {
+ var ts cgothreadstart
+ if _cgo_thread_start == nil {
+ gothrow("_cgo_thread_start missing")
+ }
+ ts.g = mp.g0
+ ts.tls = (*uint64)(unsafe.Pointer(&mp.tls[0]))
+ ts.fn = unsafe.Pointer(funcPC(mstart))
+ asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts))
+ return
+ }
+ newosproc(mp, unsafe.Pointer(mp.g0.stack.hi))
+}
+
+// Stops execution of the current m until new work is available.
+// Returns with acquired P.
+func stopm() {
+ _g_ := getg()
+
+ if _g_.m.locks != 0 {
+ gothrow("stopm holding locks")
+ }
+ if _g_.m.p != nil {
+ gothrow("stopm holding p")
+ }
+ if _g_.m.spinning {
+ _g_.m.spinning = false
+ xadd(&sched.nmspinning, -1)
+ }
+
+retry:
+ lock(&sched.lock)
+ mput(_g_.m)
+ unlock(&sched.lock)
+ notesleep(&_g_.m.park)
+ noteclear(&_g_.m.park)
+ if _g_.m.helpgc != 0 {
+ gchelper()
+ _g_.m.helpgc = 0
+ _g_.m.mcache = nil
+ goto retry
+ }
+ acquirep(_g_.m.nextp)
+ _g_.m.nextp = nil
+}
+
+func mspinning() {
+ getg().m.spinning = true
+}
+
+// Schedules some M to run the p (creates an M if necessary).
+// If p==nil, tries to get an idle P, if no idle P's does nothing.
+func startm(_p_ *p, spinning bool) {
+ lock(&sched.lock)
+ if _p_ == nil {
+ _p_ = pidleget()
+ if _p_ == nil {
+ unlock(&sched.lock)
+ if spinning {
+ xadd(&sched.nmspinning, -1)
+ }
+ return
+ }
+ }
+ mp := mget()
+ unlock(&sched.lock)
+ if mp == nil {
+ var fn func()
+ if spinning {
+ fn = mspinning
+ }
+ _newm(fn, _p_)
+ return
+ }
+ if mp.spinning {
+ gothrow("startm: m is spinning")
+ }
+ if mp.nextp != nil {
+ gothrow("startm: m has p")
+ }
+ mp.spinning = spinning
+ mp.nextp = _p_
+ notewakeup(&mp.park)
+}
+
+// Hands off P from syscall or locked M.
+func handoffp(_p_ *p) {
+ // if it has local work, start it straight away
+ if _p_.runqhead != _p_.runqtail || sched.runqsize != 0 {
+ startm(_p_, false)
+ return
+ }
+ // no local work, check that there are no spinning/idle M's,
+ // otherwise our help is not required
+ if atomicload(&sched.nmspinning)+atomicload(&sched.npidle) == 0 && cas(&sched.nmspinning, 0, 1) { // TODO: fast atomic
+ startm(_p_, true)
+ return
+ }
+ lock(&sched.lock)
+ if sched.gcwaiting != 0 {
+ _p_.status = _Pgcstop
+ sched.stopwait--
+ if sched.stopwait == 0 {
+ notewakeup(&sched.stopnote)
+ }
+ unlock(&sched.lock)
+ return
+ }
+ if sched.runqsize != 0 {
+ unlock(&sched.lock)
+ startm(_p_, false)
+ return
+ }
+ // If this is the last running P and nobody is polling network,
+ // need to wakeup another M to poll network.
+ if sched.npidle == uint32(gomaxprocs-1) && atomicload64(&sched.lastpoll) != 0 {
+ unlock(&sched.lock)
+ startm(_p_, false)
+ return
+ }
+ pidleput(_p_)
+ unlock(&sched.lock)
+}
+
+// Tries to add one more P to execute G's.
+// Called when a G is made runnable (newproc, ready).
+func wakep() {
+ // be conservative about spinning threads
+ if !cas(&sched.nmspinning, 0, 1) {
+ return
+ }
+ startm(nil, true)
+}
+
+// Stops execution of the current m that is locked to a g until the g is runnable again.
+// Returns with acquired P.
+func stoplockedm() {
+ _g_ := getg()
+
+ if _g_.m.lockedg == nil || _g_.m.lockedg.lockedm != _g_.m {
+ gothrow("stoplockedm: inconsistent locking")
+ }
+ if _g_.m.p != nil {
+ // Schedule another M to run this p.
+ _p_ := releasep()
+ handoffp(_p_)
+ }
+ incidlelocked(1)
+ // Wait until another thread schedules lockedg again.
+ notesleep(&_g_.m.park)
+ noteclear(&_g_.m.park)
+ status := readgstatus(_g_.m.lockedg)
+ if status&^_Gscan != _Grunnable {
+ print("runtime:stoplockedm: g is not Grunnable or Gscanrunnable\n")
+ dumpgstatus(_g_)
+ gothrow("stoplockedm: not runnable")
+ }
+ acquirep(_g_.m.nextp)
+ _g_.m.nextp = nil
+}
+
+// Schedules the locked m to run the locked gp.
+func startlockedm(gp *g) {
+ _g_ := getg()
+
+ mp := gp.lockedm
+ if mp == _g_.m {
+ gothrow("startlockedm: locked to me")
+ }
+ if mp.nextp != nil {
+ gothrow("startlockedm: m has p")
+ }
+ // directly handoff current P to the locked m
+ incidlelocked(-1)
+ _p_ := releasep()
+ mp.nextp = _p_
+ notewakeup(&mp.park)
+ stopm()
+}
+
+// Stops the current m for stoptheworld.
+// Returns when the world is restarted.
+func gcstopm() {
+ _g_ := getg()
+
+ if sched.gcwaiting == 0 {
+ gothrow("gcstopm: not waiting for gc")
+ }
+ if _g_.m.spinning {
+ _g_.m.spinning = false
+ xadd(&sched.nmspinning, -1)
+ }
+ _p_ := releasep()
+ lock(&sched.lock)
+ _p_.status = _Pgcstop
+ sched.stopwait--
+ if sched.stopwait == 0 {
+ notewakeup(&sched.stopnote)
+ }
+ unlock(&sched.lock)
+ stopm()
+}
+
+// Schedules gp to run on the current M.
+// Never returns.
+func execute(gp *g) {
+ _g_ := getg()
+
+ casgstatus(gp, _Grunnable, _Grunning)
+ gp.waitsince = 0
+ gp.preempt = false
+ gp.stackguard0 = gp.stack.lo + _StackGuard
+ _g_.m.p.schedtick++
+ _g_.m.curg = gp
+ gp.m = _g_.m
+
+ // Check whether the profiler needs to be turned on or off.
+ hz := sched.profilehz
+ if _g_.m.profilehz != hz {
+ resetcpuprofiler(hz)
+ }
+
+ gogo(&gp.sched)
+}
+
+// Finds a runnable goroutine to execute.
+// Tries to steal from other P's, get g from global queue, poll network.
+func findrunnable() *g {
+ _g_ := getg()
+
+top:
+ if sched.gcwaiting != 0 {
+ gcstopm()
+ goto top
+ }
+ if fingwait && fingwake {
+ if gp := wakefing(); gp != nil {
+ ready(gp)
+ }
+ }
+
+ // local runq
+ if gp := runqget(_g_.m.p); gp != nil {
+ return gp
+ }
+
+ // global runq
+ if sched.runqsize != 0 {
+ lock(&sched.lock)
+ gp := globrunqget(_g_.m.p, 0)
+ unlock(&sched.lock)
+ if gp != nil {
+ return gp
+ }
+ }
+
+ // poll network - returns list of goroutines
+ if gp := netpoll(false); gp != nil { // non-blocking
+ injectglist(gp.schedlink)
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ return gp
+ }
+
+ // If number of spinning M's >= number of busy P's, block.
+ // This is necessary to prevent excessive CPU consumption
+ // when GOMAXPROCS>>1 but the program parallelism is low.
+ if !_g_.m.spinning && 2*atomicload(&sched.nmspinning) >= uint32(gomaxprocs)-atomicload(&sched.npidle) { // TODO: fast atomic
+ goto stop
+ }
+ if !_g_.m.spinning {
+ _g_.m.spinning = true
+ xadd(&sched.nmspinning, 1)
+ }
+ // random steal from other P's
+ for i := 0; i < int(2*gomaxprocs); i++ {
+ if sched.gcwaiting != 0 {
+ goto top
+ }
+ _p_ := allp[fastrand1()%uint32(gomaxprocs)]
+ var gp *g
+ if _p_ == _g_.m.p {
+ gp = runqget(_p_)
+ } else {
+ gp = runqsteal(_g_.m.p, _p_)
+ }
+ if gp != nil {
+ return gp
+ }
+ }
+stop:
+
+ // return P and block
+ lock(&sched.lock)
+ if sched.gcwaiting != 0 {
+ unlock(&sched.lock)
+ goto top
+ }
+ if sched.runqsize != 0 {
+ gp := globrunqget(_g_.m.p, 0)
+ unlock(&sched.lock)
+ return gp
+ }
+ _p_ := releasep()
+ pidleput(_p_)
+ unlock(&sched.lock)
+ if _g_.m.spinning {
+ _g_.m.spinning = false
+ xadd(&sched.nmspinning, -1)
+ }
+
+ // check all runqueues once again
+ for i := 0; i < int(gomaxprocs); i++ {
+ _p_ := allp[i]
+ if _p_ != nil && _p_.runqhead != _p_.runqtail {
+ lock(&sched.lock)
+ _p_ = pidleget()
+ unlock(&sched.lock)
+ if _p_ != nil {
+ acquirep(_p_)
+ goto top
+ }
+ break
+ }
+ }
+
+ // poll network
+ if xchg64(&sched.lastpoll, 0) != 0 {
+ if _g_.m.p != nil {
+ gothrow("findrunnable: netpoll with p")
+ }
+ if _g_.m.spinning {
+ gothrow("findrunnable: netpoll with spinning")
+ }
+ gp := netpoll(true) // block until new work is available
+ atomicstore64(&sched.lastpoll, uint64(nanotime()))
+ if gp != nil {
+ lock(&sched.lock)
+ _p_ = pidleget()
+ unlock(&sched.lock)
+ if _p_ != nil {
+ acquirep(_p_)
+ injectglist(gp.schedlink)
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ return gp
+ }
+ injectglist(gp)
+ }
+ }
+ stopm()
+ goto top
+}
+
+func resetspinning() {
+ _g_ := getg()
+
+ var nmspinning uint32
+ if _g_.m.spinning {
+ _g_.m.spinning = false
+ nmspinning = xadd(&sched.nmspinning, -1)
+ if nmspinning < 0 {
+ gothrow("findrunnable: negative nmspinning")
+ }
+ } else {
+ nmspinning = atomicload(&sched.nmspinning)
+ }
+
+ // M wakeup policy is deliberately somewhat conservative (see nmspinning handling),
+ // so see if we need to wakeup another P here.
+ if nmspinning == 0 && atomicload(&sched.npidle) > 0 {
+ wakep()
+ }
+}
+
+// Injects the list of runnable G's into the scheduler.
+// Can run concurrently with GC.
+func injectglist(glist *g) {
+ if glist == nil {
+ return
+ }
+ lock(&sched.lock)
+ var n int
+ for n = 0; glist != nil; n++ {
+ gp := glist
+ glist = gp.schedlink
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ globrunqput(gp)
+ }
+ unlock(&sched.lock)
+ for ; n != 0 && sched.npidle != 0; n-- {
+ startm(nil, false)
+ }
+}
+
+// One round of scheduler: find a runnable goroutine and execute it.
+// Never returns.
+func schedule() {
+ _g_ := getg()
+
+ if _g_.m.locks != 0 {
+ gothrow("schedule: holding locks")
+ }
+
+ if _g_.m.lockedg != nil {
+ stoplockedm()
+ execute(_g_.m.lockedg) // Never returns.
+ }
+
+top:
+ if sched.gcwaiting != 0 {
+ gcstopm()
+ goto 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 gp != nil {
+ resetspinning()
+ }
+ }
+ if gp == nil {
+ gp = runqget(_g_.m.p)
+ if gp != nil && _g_.m.spinning {
+ gothrow("schedule: spinning with local work")
+ }
+ }
+ if gp == nil {
+ gp = findrunnable() // blocks until work is available
+ resetspinning()
+ }
+
+ if gp.lockedm != nil {
+ // Hands off own p to the locked m,
+ // then blocks waiting for a new p.
+ startlockedm(gp)
+ goto top
+ }
+
+ execute(gp)
+}
+
+// dropg removes the association between m and the current goroutine m->curg (gp for short).
+// Typically a caller sets gp's status away from Grunning and then
+// immediately calls dropg to finish the job. The caller is also responsible
+// for arranging that gp will be restarted using ready at an
+// appropriate time. After calling dropg and arranging for gp to be
+// readied later, the caller can do other work but eventually should
+// call schedule to restart the scheduling of goroutines on this m.
+func dropg() {
+ _g_ := getg()
+
+ if _g_.m.lockedg == nil {
+ _g_.m.curg.m = nil
+ _g_.m.curg = nil
+ }
+}
+
+// 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) {
+ _g_ := getg()
+
+ _g_.m.waitlock = lock
+ _g_.m.waitunlockf = *(*unsafe.Pointer)(unsafe.Pointer(&unlockf))
+ _g_.waitreason = reason
+ mcall(park_m)
+}
+
+func parkunlock_c(gp *g, lock unsafe.Pointer) bool {
+ unlock((*mutex)(lock))
+ return true
+}
+
+// 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)
+}
+
+// park continuation on g0.
+func park_m(gp *g) {
+ _g_ := getg()
+
+ casgstatus(gp, _Grunning, _Gwaiting)
+ dropg()
+
+ if _g_.m.waitunlockf != nil {
+ fn := *(*func(*g, unsafe.Pointer) bool)(unsafe.Pointer(&_g_.m.waitunlockf))
+ ok := fn(gp, _g_.m.waitlock)
+ _g_.m.waitunlockf = nil
+ _g_.m.waitlock = nil
+ if !ok {
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ execute(gp) // Schedule it back, never returns.
+ }
+ }
+ schedule()
+}
+
+// Gosched continuation on g0.
+func gosched_m(gp *g) {
+ status := readgstatus(gp)
+ if status&^_Gscan != _Grunning {
+ dumpgstatus(gp)
+ gothrow("bad g status")
+ }
+ casgstatus(gp, _Grunning, _Grunnable)
+ dropg()
+ lock(&sched.lock)
+ globrunqput(gp)
+ unlock(&sched.lock)
+
+ schedule()
+}
+
+// Finishes execution of the current goroutine.
+// Must be NOSPLIT because it is called from Go. (TODO - probably not anymore)
+//go:nosplit
+func goexit1() {
+ if raceenabled {
+ racegoend()
+ }
+ mcall(goexit0)
+}
+
+// goexit continuation on g0.
+func goexit0(gp *g) {
+ _g_ := getg()
+
+ casgstatus(gp, _Grunning, _Gdead)
+ gp.m = nil
+ gp.lockedm = nil
+ _g_.m.lockedg = nil
+ gp.paniconfault = false
+ gp._defer = nil // should be true already but just in case.
+ gp._panic = nil // non-nil for Goexit during panic. points at stack-allocated data.
+ gp.writebuf = nil
+ gp.waitreason = ""
+ gp.param = nil
+
+ dropg()
+
+ if _g_.m.locked&^_LockExternal != 0 {
+ print("invalid m->locked = ", _g_.m.locked, "\n")
+ gothrow("internal lockOSThread error")
+ }
+ _g_.m.locked = 0
+ gfput(_g_.m.p, gp)
+ schedule()
+}
+
+//go:nosplit
+func save(pc, sp uintptr) {
+ _g_ := getg()
+
+ _g_.sched.pc = pc
+ _g_.sched.sp = sp
+ _g_.sched.lr = 0
+ _g_.sched.ret = 0
+ _g_.sched.ctxt = nil
+ _g_.sched.g = _g_
+}
+
+// The goroutine g is about to enter a system call.
+// Record that it's not using the cpu anymore.
+// This is called only from the go syscall library and cgocall,
+// not from the low-level system calls used by the
+//
+// Entersyscall cannot split the stack: the gosave must
+// make g->sched refer to the caller's stack segment, because
+// entersyscall is going to return immediately after.
+//
+// Nothing entersyscall calls can split the stack either.
+// We cannot safely move the stack during an active call to syscall,
+// because we do not know which of the uintptr arguments are
+// really pointers (back into the stack).
+// In practice, this means that we make the fast path run through
+// entersyscall doing no-split things, and the slow path has to use systemstack
+// to run bigger things on the system stack.
+//
+// reentersyscall is the entry point used by cgo callbacks, where explicitly
+// saved SP and PC are restored. This is needed when exitsyscall will be called
+// 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.
+//go:nosplit
+func reentersyscall(pc, sp uintptr) {
+ _g_ := getg()
+
+ // Disable preemption because during this function g is in Gsyscall status,
+ // but can have inconsistent g->sched, do not let GC observe it.
+ _g_.m.locks++
+
+ // 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
+ // will trip any stack check and leaving a flag to tell newstack to die.
+ _g_.stackguard0 = stackPreempt
+ _g_.throwsplit = true
+
+ // Leave SP around for GC and traceback.
+ save(pc, sp)
+ _g_.syscallsp = sp
+ _g_.syscallpc = pc
+ casgstatus(_g_, _Grunning, _Gsyscall)
+ if _g_.syscallsp < _g_.stack.lo || _g_.stack.hi < _g_.syscallsp {
+ systemstack(entersyscall_bad)
+ }
+
+ if atomicload(&sched.sysmonwait) != 0 { // TODO: fast atomic
+ systemstack(entersyscall_sysmon)
+ save(pc, sp)
+ }
+
+ _g_.m.mcache = nil
+ _g_.m.p.m = nil
+ atomicstore(&_g_.m.p.status, _Psyscall)
+ if sched.gcwaiting != 0 {
+ systemstack(entersyscall_gcwait)
+ save(pc, sp)
+ }
+
+ // Goroutines must not split stacks in Gsyscall status (it would corrupt g->sched).
+ // We set _StackGuard to StackPreempt so that first split stack check calls morestack.
+ // Morestack detects this case and throws.
+ _g_.stackguard0 = stackPreempt
+ _g_.m.locks--
+}
+
+// Standard syscall entry used by the go syscall library and normal cgo calls.
+//go:nosplit
+func entersyscall(dummy int32) {
+ reentersyscall(getcallerpc(unsafe.Pointer(&dummy)), getcallersp(unsafe.Pointer(&dummy)))
+}
+
+func entersyscall_bad() {
+ var gp *g
+ gp = getg().m.curg
+ print("entersyscall inconsistent ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
+ gothrow("entersyscall")
+}
+
+func entersyscall_sysmon() {
+ lock(&sched.lock)
+ if atomicload(&sched.sysmonwait) != 0 {
+ atomicstore(&sched.sysmonwait, 0)
+ notewakeup(&sched.sysmonnote)
+ }
+ unlock(&sched.lock)
+}
+
+func entersyscall_gcwait() {
+ _g_ := getg()
+
+ lock(&sched.lock)
+ if sched.stopwait > 0 && cas(&_g_.m.p.status, _Psyscall, _Pgcstop) {
+ if sched.stopwait--; sched.stopwait == 0 {
+ notewakeup(&sched.stopnote)
+ }
+ }
+ unlock(&sched.lock)
+}
+
+// The same as entersyscall(), but with a hint that the syscall is blocking.
+//go:nosplit
+func entersyscallblock(dummy int32) {
+ _g_ := getg()
+
+ _g_.m.locks++ // see comment in entersyscall
+ _g_.throwsplit = true
+ _g_.stackguard0 = stackPreempt // see comment in entersyscall
+
+ // Leave SP around for GC and traceback.
+ save(getcallerpc(unsafe.Pointer(&dummy)), getcallersp(unsafe.Pointer(&dummy)))
+ _g_.syscallsp = _g_.sched.sp
+ _g_.syscallpc = _g_.sched.pc
+ casgstatus(_g_, _Grunning, _Gsyscall)
+ if _g_.syscallsp < _g_.stack.lo || _g_.stack.hi < _g_.syscallsp {
+ systemstack(entersyscall_bad)
+ }
+
+ systemstack(entersyscallblock_handoff)
+
+ // Resave for traceback during blocked call.
+ save(getcallerpc(unsafe.Pointer(&dummy)), getcallersp(unsafe.Pointer(&dummy)))
+
+ _g_.m.locks--
+}
+
+func entersyscallblock_handoff() {
+ handoffp(releasep())
+}
+
+// The goroutine g exited its system call.
+// Arrange for it to run on a cpu again.
+// This is called only from the go syscall library, not
+// from the low-level system calls used by the
+//go:nosplit
+func exitsyscall(dummy int32) {
+ _g_ := getg()
+
+ _g_.m.locks++ // see comment in entersyscall
+ if getcallersp(unsafe.Pointer(&dummy)) > _g_.syscallsp {
+ gothrow("exitsyscall: syscall frame is no longer valid")
+ }
+
+ _g_.waitsince = 0
+ if exitsyscallfast() {
+ if _g_.m.mcache == nil {
+ gothrow("lost mcache")
+ }
+ // There's a cpu for us, so we can run.
+ _g_.m.p.syscalltick++
+ // We need to cas the status and scan before resuming...
+ casgstatus(_g_, _Gsyscall, _Grunning)
+
+ // Garbage collector isn't running (since we are),
+ // so okay to clear syscallsp.
+ _g_.syscallsp = 0
+ _g_.m.locks--
+ if _g_.preempt {
+ // restore the preemption request in case we've cleared it in newstack
+ _g_.stackguard0 = stackPreempt
+ } else {
+ // otherwise restore the real _StackGuard, we've spoiled it in entersyscall/entersyscallblock
+ _g_.stackguard0 = _g_.stack.lo + _StackGuard
+ }
+ _g_.throwsplit = false
+ return
+ }
+
+ _g_.m.locks--
+
+ // Call the scheduler.
+ mcall(exitsyscall0)
+
+ if _g_.m.mcache == nil {
+ gothrow("lost mcache")
+ }
+
+ // Scheduler returned, so we're allowed to run now.
+ // Delete the syscallsp information that we left for
+ // the garbage collector during the system call.
+ // Must wait until now because until gosched returns
+ // we don't know for sure that the garbage collector
+ // is not running.
+ _g_.syscallsp = 0
+ _g_.m.p.syscalltick++
+ _g_.throwsplit = false
+}
+
+//go:nosplit
+func exitsyscallfast() bool {
+ _g_ := getg()
+
+ // Freezetheworld sets stopwait but does not retake P's.
+ if sched.stopwait != 0 {
+ _g_.m.p = nil
+ return false
+ }
+
+ // Try to re-acquire the last P.
+ if _g_.m.p != nil && _g_.m.p.status == _Psyscall && cas(&_g_.m.p.status, _Psyscall, _Prunning) {
+ // There's a cpu for us, so we can run.
+ _g_.m.mcache = _g_.m.p.mcache
+ _g_.m.p.m = _g_.m
+ return true
+ }
+
+ // Try to get any other idle P.
+ _g_.m.p = nil
+ if sched.pidle != nil {
+ var ok bool
+ systemstack(func() {
+ ok = exitsyscallfast_pidle()
+ })
+ if ok {
+ return true
+ }
+ }
+ return false
+}
+
+func exitsyscallfast_pidle() bool {
+ lock(&sched.lock)
+ _p_ := pidleget()
+ if _p_ != nil && atomicload(&sched.sysmonwait) != 0 {
+ atomicstore(&sched.sysmonwait, 0)
+ notewakeup(&sched.sysmonnote)
+ }
+ unlock(&sched.lock)
+ if _p_ != nil {
+ acquirep(_p_)
+ return true
+ }
+ return false
+}
+
+// exitsyscall slow path on g0.
+// Failed to acquire P, enqueue gp as runnable.
+func exitsyscall0(gp *g) {
+ _g_ := getg()
+
+ casgstatus(gp, _Gsyscall, _Grunnable)
+ dropg()
+ lock(&sched.lock)
+ _p_ := pidleget()
+ if _p_ == nil {
+ globrunqput(gp)
+ } else if atomicload(&sched.sysmonwait) != 0 {
+ atomicstore(&sched.sysmonwait, 0)
+ notewakeup(&sched.sysmonnote)
+ }
+ unlock(&sched.lock)
+ if _p_ != nil {
+ acquirep(_p_)
+ execute(gp) // Never returns.
+ }
+ if _g_.m.lockedg != nil {
+ // Wait until another thread schedules gp and so m again.
+ stoplockedm()
+ execute(gp) // Never returns.
+ }
+ stopm()
+ schedule() // Never returns.
+}
+
+func beforefork() {
+ gp := getg().m.curg
+
+ // Fork can hang if preempted with signals frequently enough (see issue 5517).
+ // Ensure that we stay on the same M where we disable profiling.
+ gp.m.locks++
+ if gp.m.profilehz != 0 {
+ resetcpuprofiler(0)
+ }
+
+ // This function is called before fork in syscall package.
+ // Code between fork and exec must not allocate memory nor even try to grow stack.
+ // Here we spoil g->_StackGuard to reliably detect any attempts to grow stack.
+ // runtime_AfterFork will undo this in parent process, but not in child.
+ gp.stackguard0 = stackFork
+}
+
+// Called from syscall package before fork.
+//go:nosplit
+func syscall_BeforeFork() {
+ systemstack(beforefork)
+}
+
+func afterfork() {
+ gp := getg().m.curg
+
+ // See the comment in beforefork.
+ gp.stackguard0 = gp.stack.lo + _StackGuard
+
+ hz := sched.profilehz
+ if hz != 0 {
+ resetcpuprofiler(hz)
+ }
+ gp.m.locks--
+}
+
+// Called from syscall package after fork in parent.
+//go:nosplit
+func syscall_AfterFork() {
+ systemstack(afterfork)
+}
+
+// Allocate a new g, with a stack big enough for stacksize bytes.
+func malg(stacksize int32) *g {
+ newg := allocg()
+ if stacksize >= 0 {
+ stacksize = round2(_StackSystem + stacksize)
+ systemstack(func() {
+ newg.stack = stackalloc(uint32(stacksize))
+ })
+ newg.stackguard0 = newg.stack.lo + _StackGuard
+ newg.stackguard1 = ^uintptr(0)
+ }
+ return newg
+}
+
+// Create a new g running fn with siz bytes of arguments.
+// Put it on the queue of g's waiting to run.
+// The compiler turns a go statement into a call to this.
+// Cannot split the stack because it assumes that the arguments
+// are available sequentially after &fn; they would not be
+// copied if a stack split occurred.
+//go:nosplit
+func newproc(siz int32, fn *funcval) {
+ argp := add(unsafe.Pointer(&fn), ptrSize)
+ if hasLinkRegister {
+ argp = add(argp, ptrSize) // skip caller's saved LR
+ }
+
+ pc := getcallerpc(unsafe.Pointer(&siz))
+ systemstack(func() {
+ newproc1(fn, (*uint8)(argp), siz, 0, pc)
+ })
+}
+
+// Create a new g running fn with narg bytes of arguments starting
+// at argp and returning nret bytes of results. callerpc is the
+// address of the go statement that created this. The new g is put
+// on the queue of g's waiting to run.
+func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr) *g {
+ _g_ := getg()
+
+ if fn == nil {
+ _g_.m.throwing = -1 // do not dump full stacks
+ gothrow("go of nil func value")
+ }
+ _g_.m.locks++ // disable preemption because it can be holding p in a local var
+ siz := narg + nret
+ siz = (siz + 7) &^ 7
+
+ // We could allocate a larger initial stack if necessary.
+ // Not worth it: this is almost always an error.
+ // 4*sizeof(uintreg): extra space added below
+ // sizeof(uintreg): caller's LR (arm) or return address (x86, in gostartcall).
+ if siz >= _StackMin-4*regSize-regSize {
+ gothrow("newproc: function arguments too large for new goroutine")
+ }
+
+ _p_ := _g_.m.p
+ newg := gfget(_p_)
+ if newg == nil {
+ newg = malg(_StackMin)
+ casgstatus(newg, _Gidle, _Gdead)
+ allgadd(newg) // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack.
+ }
+ if newg.stack.hi == 0 {
+ gothrow("newproc1: newg missing stack")
+ }
+
+ if readgstatus(newg) != _Gdead {
+ gothrow("newproc1: new g is not Gdead")
+ }
+
+ sp := newg.stack.hi
+ sp -= 4 * regSize // extra space in case of reads slightly beyond frame
+ sp -= uintptr(siz)
+ memmove(unsafe.Pointer(sp), unsafe.Pointer(argp), uintptr(narg))
+ if hasLinkRegister {
+ // caller's LR
+ sp -= ptrSize
+ *(*unsafe.Pointer)(unsafe.Pointer(sp)) = nil
+ }
+
+ memclr(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched))
+ newg.sched.sp = sp
+ newg.sched.pc = funcPC(goexit) + _PCQuantum // +PCQuantum so that previous instruction is in same function
+ newg.sched.g = newg
+ gostartcallfn(&newg.sched, fn)
+ newg.gopc = callerpc
+ casgstatus(newg, _Gdead, _Grunnable)
+
+ if _p_.goidcache == _p_.goidcacheend {
+ // Sched.goidgen is the last allocated id,
+ // this batch must be [sched.goidgen+1, sched.goidgen+GoidCacheBatch].
+ // At startup sched.goidgen=0, so main goroutine receives goid=1.
+ _p_.goidcache = xadd64(&sched.goidgen, _GoidCacheBatch)
+ _p_.goidcache -= _GoidCacheBatch - 1
+ _p_.goidcacheend = _p_.goidcache + _GoidCacheBatch
+ }
+ newg.goid = int64(_p_.goidcache)
+ _p_.goidcache++
+ if raceenabled {
+ newg.racectx = racegostart(callerpc)
+ }
+ runqput(_p_, newg)
+
+ if atomicload(&sched.npidle) != 0 && atomicload(&sched.nmspinning) == 0 && unsafe.Pointer(fn.fn) != unsafe.Pointer(funcPC(main)) { // TODO: fast atomic
+ wakep()
+ }
+ _g_.m.locks--
+ if _g_.m.locks == 0 && _g_.preempt { // restore the preemption request in case we've cleared it in newstack
+ _g_.stackguard0 = stackPreempt
+ }
+ return newg
+}
+
+// Put on gfree list.
+// If local list is too long, transfer a batch to the global list.
+func gfput(_p_ *p, gp *g) {
+ if readgstatus(gp) != _Gdead {
+ gothrow("gfput: bad status (not Gdead)")
+ }
+
+ stksize := gp.stack.hi - gp.stack.lo
+
+ if stksize != _FixedStack {
+ // non-standard stack size - free it.
+ stackfree(gp.stack)
+ gp.stack.lo = 0
+ gp.stack.hi = 0
+ gp.stackguard0 = 0
+ }
+
+ gp.schedlink = _p_.gfree
+ _p_.gfree = gp
+ _p_.gfreecnt++
+ if _p_.gfreecnt >= 64 {
+ lock(&sched.gflock)
+ for _p_.gfreecnt >= 32 {
+ _p_.gfreecnt--
+ gp = _p_.gfree
+ _p_.gfree = gp.schedlink
+ gp.schedlink = sched.gfree
+ sched.gfree = gp
+ sched.ngfree++
+ }
+ unlock(&sched.gflock)
+ }
+}
+
+// Get from gfree list.
+// If local list is empty, grab a batch from global list.
+func gfget(_p_ *p) *g {
+retry:
+ gp := _p_.gfree
+ if gp == nil && sched.gfree != nil {
+ lock(&sched.gflock)
+ for _p_.gfreecnt < 32 && sched.gfree != nil {
+ _p_.gfreecnt++
+ gp = sched.gfree
+ sched.gfree = gp.schedlink
+ sched.ngfree--
+ gp.schedlink = _p_.gfree
+ _p_.gfree = gp
+ }
+ unlock(&sched.gflock)
+ goto retry
+ }
+ if gp != nil {
+ _p_.gfree = gp.schedlink
+ _p_.gfreecnt--
+ if gp.stack.lo == 0 {
+ // Stack was deallocated in gfput. Allocate a new one.
+ systemstack(func() {
+ gp.stack = stackalloc(_FixedStack)
+ })
+ gp.stackguard0 = gp.stack.lo + _StackGuard
+ } else {
+ if raceenabled {
+ racemalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
+ }
+ }
+ }
+ return gp
+}
+
+// Purge all cached G's from gfree list to the global list.
+func gfpurge(_p_ *p) {
+ lock(&sched.gflock)
+ for _p_.gfreecnt != 0 {
+ _p_.gfreecnt--
+ gp := _p_.gfree
+ _p_.gfree = gp.schedlink
+ gp.schedlink = sched.gfree
+ sched.gfree = gp
+ sched.ngfree++
+ }
+ unlock(&sched.gflock)
+}
+
+// Breakpoint executes a breakpoint trap.
+func Breakpoint() {
+ breakpoint()
+}
+
+// dolockOSThread is called by LockOSThread and lockOSThread below
+// after they modify m.locked. Do not allow preemption during this call,
+// or else the m might be different in this function than in the caller.
+//go:nosplit
+func dolockOSThread() {
+ _g_ := getg()
+ _g_.m.lockedg = _g_
+ _g_.lockedm = _g_.m
+}
+
+//go:nosplit
+
+// LockOSThread wires the calling goroutine to its current operating system thread.
+// Until the calling goroutine exits or calls UnlockOSThread, it will always
+// execute in that thread, and no other goroutine can.
+func LockOSThread() {
+ getg().m.locked |= _LockExternal
+ dolockOSThread()
+}
+
+//go:nosplit
+func lockOSThread() {
+ getg().m.locked += _LockInternal
+ dolockOSThread()
+}
+
+// dounlockOSThread is called by UnlockOSThread and unlockOSThread below
+// after they update m->locked. Do not allow preemption during this call,
+// or else the m might be in different in this function than in the caller.
+//go:nosplit
+func dounlockOSThread() {
+ _g_ := getg()
+ if _g_.m.locked != 0 {
+ return
+ }
+ _g_.m.lockedg = nil
+ _g_.lockedm = nil
+}
+
+//go:nosplit
+
+// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
+// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
+func UnlockOSThread() {
+ getg().m.locked &^= _LockExternal
+ dounlockOSThread()
+}
+
+//go:nosplit
+func unlockOSThread() {
+ _g_ := getg()
+ if _g_.m.locked < _LockInternal {
+ systemstack(badunlockosthread)
+ }
+ _g_.m.locked -= _LockInternal
+ dounlockOSThread()
+}
+
+func badunlockosthread() {
+ gothrow("runtime: internal error: misuse of lockOSThread/unlockOSThread")
+}
+
+func gcount() int32 {
+ n := int32(allglen) - sched.ngfree
+ for i := 0; ; i++ {
+ _p_ := allp[i]
+ if _p_ == nil {
+ break
+ }
+ n -= _p_.gfreecnt
+ }
+
+ // All these variables can be changed concurrently, so the result can be inconsistent.
+ // But at least the current goroutine is running.
+ if n < 1 {
+ n = 1
+ }
+ return n
+}
+
+func mcount() int32 {
+ return sched.mcount
+}
+
+var prof struct {
+ lock uint32
+ hz int32
+}
+
+func _System() { _System() }
+func _ExternalCode() { _ExternalCode() }
+func _GC() { _GC() }
+
+var etext struct{}
+
+// Called if we receive a SIGPROF signal.
+func sigprof(pc *uint8, sp *uint8, lr *uint8, gp *g, mp *m) {
+ var n int32
+ var traceback bool
+ var stk [100]uintptr
+
+ if prof.hz == 0 {
+ return
+ }
+
+ // Profiling runs concurrently with GC, so it must not allocate.
+ mp.mallocing++
+
+ // Define that a "user g" is a user-created goroutine, and a "system g"
+ // is one that is m->g0 or m->gsignal. We've only made sure that we
+ // can unwind user g's, so exclude the system g's.
+ //
+ // It is not quite as easy as testing gp == m->curg (the current user g)
+ // because we might be interrupted for profiling halfway through a
+ // goroutine switch. The switch involves updating three (or four) values:
+ // g, PC, SP, and (on arm) LR. The PC must be the last to be updated,
+ // because once it gets updated the new g is running.
+ //
+ // When switching from a user g to a system g, LR is not considered live,
+ // so the update only affects g, SP, and PC. Since PC must be last, there
+ // the possible partial transitions in ordinary execution are (1) g alone is updated,
+ // (2) both g and SP are updated, and (3) SP alone is updated.
+ // If g is updated, we'll see a system g and not look closer.
+ // If SP alone is updated, we can detect the partial transition by checking
+ // whether the SP is within g's stack bounds. (We could also require that SP
+ // be changed only after g, but the stack bounds check is needed by other
+ // cases, so there is no need to impose an additional requirement.)
+ //
+ // There is one exceptional transition to a system g, not in ordinary execution.
+ // When a signal arrives, the operating system starts the signal handler running
+ // with an updated PC and SP. The g is updated last, at the beginning of the
+ // handler. There are two reasons this is okay. First, until g is updated the
+ // g and SP do not match, so the stack bounds check detects the partial transition.
+ // Second, signal handlers currently run with signals disabled, so a profiling
+ // signal cannot arrive during the handler.
+ //
+ // When switching from a system g to a user g, there are three possibilities.
+ //
+ // First, it may be that the g switch has no PC update, because the SP
+ // either corresponds to a user g throughout (as in asmcgocall)
+ // or because it has been arranged to look like a user g frame
+ // (as in cgocallback_gofunc). In this case, since the entire
+ // transition is a g+SP update, a partial transition updating just one of
+ // those will be detected by the stack bounds check.
+ //
+ // Second, when returning from a signal handler, the PC and SP updates
+ // are performed by the operating system in an atomic update, so the g
+ // update must be done before them. The stack bounds check detects
+ // the partial transition here, and (again) signal handlers run with signals
+ // disabled, so a profiling signal cannot arrive then anyway.
+ //
+ // Third, the common case: it may be that the switch updates g, SP, and PC
+ // separately, as in gogo.
+ //
+ // Because gogo is the only instance, we check whether the PC lies
+ // within that function, and if so, not ask for a traceback. This approach
+ // requires knowing the size of the gogo function, which we
+ // record in arch_*.h and check in runtime_test.go.
+ //
+ // There is another apparently viable approach, recorded here in case
+ // the "PC within gogo" check turns out not to be usable.
+ // It would be possible to delay the update of either g or SP until immediately
+ // before the PC update instruction. Then, because of the stack bounds check,
+ // the only problematic interrupt point is just before that PC update instruction,
+ // and the sigprof handler can detect that instruction and simulate stepping past
+ // it in order to reach a consistent state. On ARM, the update of g must be made
+ // in two places (in R10 and also in a TLS slot), so the delayed update would
+ // need to be the SP update. The sigprof handler must read the instruction at
+ // the current PC and if it was the known instruction (for example, JMP BX or
+ // MOV R2, PC), use that other register in place of the PC value.
+ // The biggest drawback to this solution is that it requires that we can tell
+ // whether it's safe to read from the memory pointed at by PC.
+ // In a correct program, we can test PC == nil and otherwise read,
+ // but if a profiling signal happens at the instant that a program executes
+ // a bad jump (before the program manages to handle the resulting fault)
+ // the profiling handler could fault trying to read nonexistent memory.
+ //
+ // To recap, there are no constraints on the assembly being used for the
+ // transition. We simply require that g and SP match and that the PC is not
+ // in gogo.
+ traceback = true
+ usp := uintptr(unsafe.Pointer(sp))
+ gogo := funcPC(gogo)
+ if gp == nil || gp != mp.curg ||
+ usp < gp.stack.lo || gp.stack.hi < usp ||
+ (gogo <= uintptr(unsafe.Pointer(pc)) && uintptr(unsafe.Pointer(pc)) < gogo+_RuntimeGogoBytes) {
+ traceback = false
+ }
+
+ n = 0
+ if traceback {
+ n = int32(gentraceback(uintptr(unsafe.Pointer(pc)), uintptr(unsafe.Pointer(sp)), uintptr(unsafe.Pointer(lr)), gp, 0, &stk[0], len(stk), nil, nil, _TraceTrap))
+ }
+ if !traceback || n <= 0 {
+ // Normal traceback is impossible or has failed.
+ // See if it falls into several common cases.
+ n = 0
+ if mp.ncgo > 0 && mp.curg != nil && mp.curg.syscallpc != 0 && mp.curg.syscallsp != 0 {
+ // Cgo, we can't unwind and symbolize arbitrary C code,
+ // so instead collect Go stack that leads to the cgo call.
+ // This is especially important on windows, since all syscalls are cgo calls.
+ n = int32(gentraceback(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, 0, &stk[0], len(stk), nil, nil, 0))
+ }
+ if GOOS == "windows" && n == 0 && mp.libcallg != nil && mp.libcallpc != 0 && mp.libcallsp != 0 {
+ // Libcall, i.e. runtime syscall on windows.
+ // Collect Go stack that leads to the call.
+ n = int32(gentraceback(mp.libcallpc, mp.libcallsp, 0, mp.libcallg, 0, &stk[0], len(stk), nil, nil, 0))
+ }
+ if n == 0 {
+ // If all of the above has failed, account it against abstract "System" or "GC".
+ n = 2
+ // "ExternalCode" is better than "etext".
+ if uintptr(unsafe.Pointer(pc)) > uintptr(unsafe.Pointer(&etext)) {
+ pc = (*uint8)(unsafe.Pointer(uintptr(funcPC(_ExternalCode) + _PCQuantum)))
+ }
+ stk[0] = uintptr(unsafe.Pointer(pc))
+ if mp.gcing != 0 || mp.helpgc != 0 {
+ stk[1] = funcPC(_GC) + _PCQuantum
+ } else {
+ stk[1] = funcPC(_System) + _PCQuantum
+ }
+ }
+ }
+
+ if prof.hz != 0 {
+ // Simple cas-lock to coordinate with setcpuprofilerate.
+ for !cas(&prof.lock, 0, 1) {
+ osyield()
+ }
+ if prof.hz != 0 {
+ cpuproftick(&stk[0], n)
+ }
+ atomicstore(&prof.lock, 0)
+ }
+ mp.mallocing--
+}
+
+// Arrange to call fn with a traceback hz times a second.
+func setcpuprofilerate_m(hz int32) {
+ // Force sane arguments.
+ if hz < 0 {
+ hz = 0
+ }
+
+ // Disable preemption, otherwise we can be rescheduled to another thread
+ // that has profiling enabled.
+ _g_ := getg()
+ _g_.m.locks++
+
+ // Stop profiler on this thread so that it is safe to lock prof.
+ // if a profiling signal came in while we had prof locked,
+ // it would deadlock.
+ resetcpuprofiler(0)
+
+ for !cas(&prof.lock, 0, 1) {
+ osyield()
+ }
+ prof.hz = hz
+ atomicstore(&prof.lock, 0)
+
+ lock(&sched.lock)
+ sched.profilehz = hz
+ unlock(&sched.lock)
+
+ if hz != 0 {
+ resetcpuprofiler(hz)
+ }
+
+ _g_.m.locks--
+}
+
+// Change number of processors. The world is stopped, sched is locked.
+func procresize(new int32) {
+ old := gomaxprocs
+ if old < 0 || old > _MaxGomaxprocs || new <= 0 || new > _MaxGomaxprocs {
+ gothrow("procresize: invalid arg")
+ }
+
+ // 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 {
+ if old == 0 && i == 0 {
+ if getg().m.mcache == nil {
+ gothrow("missing mcache?")
+ }
+ p.mcache = getg().m.mcache // bootstrap
+ } else {
+ p.mcache = allocmcache()
+ }
+ }
+ }
+
+ // redistribute runnable G's evenly
+ // collect all runnable goroutines in global queue preserving FIFO order
+ // FIFO order is required to ensure fairness even during frequent GCs
+ // see http://golang.org/issue/7126
+ empty := false
+ for !empty {
+ empty = true
+ for i := int32(0); i < old; i++ {
+ p := allp[i]
+ if p.runqhead == p.runqtail {
+ continue
+ }
+ empty = false
+ // pop from tail of local queue
+ p.runqtail--
+ gp := p.runq[p.runqtail%uint32(len(p.runq))]
+ // push onto head of global queue
+ gp.schedlink = sched.runqhead
+ sched.runqhead = gp
+ if sched.runqtail == nil {
+ sched.runqtail = gp
+ }
+ sched.runqsize++
+ }
+ }
+
+ // fill local queues with at most len(p.runq)/2 goroutines
+ // start at 1 because current M already executes some G and will acquire allp[0] below,
+ // so if we have a spare G we want to put it into allp[1].
+ var _p_ p
+ for i := int32(1); i < new*int32(len(_p_.runq))/2 && sched.runqsize > 0; i++ {
+ gp := sched.runqhead
+ sched.runqhead = gp.schedlink
+ if sched.runqhead == nil {
+ sched.runqtail = nil
+ }
+ sched.runqsize--
+ runqput(allp[i%new], gp)
+ }
+
+ // free unused P's
+ for i := new; i < old; i++ {
+ p := allp[i]
+ freemcache(p.mcache)
+ p.mcache = nil
+ gfpurge(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.m = nil
+ }
+ _g_.m.p = nil
+ _g_.m.mcache = nil
+ p := allp[0]
+ p.m = nil
+ p.status = _Pidle
+ acquirep(p)
+ for i := new - 1; i > 0; i-- {
+ p := allp[i]
+ p.status = _Pidle
+ pidleput(p)
+ }
+ var int32p *int32 = &gomaxprocs // make compiler check that gomaxprocs is an int32
+ atomicstore((*uint32)(unsafe.Pointer(int32p)), uint32(new))
+}
+
+// Associate p and the current m.
+func acquirep(_p_ *p) {
+ _g_ := getg()
+
+ if _g_.m.p != nil || _g_.m.mcache != nil {
+ gothrow("acquirep: already in go")
+ }
+ if _p_.m != nil || _p_.status != _Pidle {
+ id := int32(0)
+ if _p_.m != nil {
+ id = _p_.m.id
+ }
+ print("acquirep: p->m=", _p_.m, "(", id, ") p->status=", _p_.status, "\n")
+ gothrow("acquirep: invalid p state")
+ }
+ _g_.m.mcache = _p_.mcache
+ _g_.m.p = _p_
+ _p_.m = _g_.m
+ _p_.status = _Prunning
+}
+
+// Disassociate p and the current m.
+func releasep() *p {
+ _g_ := getg()
+
+ if _g_.m.p == nil || _g_.m.mcache == nil {
+ gothrow("releasep: invalid arg")
+ }
+ _p_ := _g_.m.p
+ if _p_.m != _g_.m || _p_.mcache != _g_.m.mcache || _p_.status != _Prunning {
+ 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")
+ gothrow("releasep: invalid p state")
+ }
+ _g_.m.p = nil
+ _g_.m.mcache = nil
+ _p_.m = nil
+ _p_.status = _Pidle
+ return _p_
+}
+
+func incidlelocked(v int32) {
+ lock(&sched.lock)
+ sched.nmidlelocked += v
+ if v > 0 {
+ checkdead()
+ }
+ unlock(&sched.lock)
+}
+
+// Check for deadlock situation.
+// The check is based on number of running M's, if 0 -> deadlock.
+func checkdead() {
+ // If we are dying because of a signal caught on an already idle thread,
+ // freezetheworld will cause all running threads to block.
+ // And runtime will essentially enter into deadlock state,
+ // except that there is a thread that will call exit soon.
+ if panicking > 0 {
+ return
+ }
+
+ // -1 for sysmon
+ run := sched.mcount - sched.nmidle - sched.nmidlelocked - 1
+ if run > 0 {
+ return
+ }
+ if run < 0 {
+ print("runtime: checkdead: nmidle=", sched.nmidle, " nmidlelocked=", sched.nmidlelocked, " mcount=", sched.mcount, "\n")
+ gothrow("checkdead: inconsistent counts")
+ }
+
+ grunning := 0
+ lock(&allglock)
+ for i := 0; i < len(allgs); i++ {
+ gp := allgs[i]
+ if gp.issystem {
+ continue
+ }
+ s := readgstatus(gp)
+ switch s &^ _Gscan {
+ case _Gwaiting:
+ grunning++
+ case _Grunnable,
+ _Grunning,
+ _Gsyscall:
+ unlock(&allglock)
+ print("runtime: checkdead: find g ", gp.goid, " in status ", s, "\n")
+ gothrow("checkdead: runnable g")
+ }
+ }
+ unlock(&allglock)
+ if grunning == 0 { // possible if main goroutine calls runtime·Goexit()
+ gothrow("no goroutines (main called runtime.Goexit) - deadlock!")
+ }
+
+ // Maybe jump time forward for playground.
+ gp := timejump()
+ if gp != nil {
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ globrunqput(gp)
+ _p_ := pidleget()
+ if _p_ == nil {
+ gothrow("checkdead: no p for timer")
+ }
+ mp := mget()
+ if mp == nil {
+ _newm(nil, _p_)
+ } else {
+ mp.nextp = _p_
+ notewakeup(&mp.park)
+ }
+ return
+ }
+
+ getg().m.throwing = -1 // do not dump full stacks
+ gothrow("all goroutines are asleep - deadlock!")
+}
+
+func sysmon() {
+ // If we go two minutes without a garbage collection, force one to run.
+ forcegcperiod := int64(2 * 60 * 1e9)
+
+ // If a heap span goes unused for 5 minutes after a garbage collection,
+ // we hand it back to the operating system.
+ scavengelimit := int64(5 * 60 * 1e9)
+
+ if debug.scavenge > 0 {
+ // Scavenge-a-lot for testing.
+ forcegcperiod = 10 * 1e6
+ scavengelimit = 20 * 1e6
+ }
+
+ lastscavenge := nanotime()
+ nscavenge := 0
+
+ // Make wake-up period small enough for the sampling to be correct.
+ maxsleep := forcegcperiod / 2
+ if scavengelimit < forcegcperiod {
+ maxsleep = scavengelimit / 2
+ }
+
+ lasttrace := int64(0)
+ idle := 0 // how many cycles in succession we had not wokeup somebody
+ delay := uint32(0)
+ for {
+ if idle == 0 { // start with 20us sleep...
+ delay = 20
+ } else if idle > 50 { // start doubling the sleep after 1ms...
+ delay *= 2
+ }
+ if delay > 10*1000 { // up to 10ms
+ delay = 10 * 1000
+ }
+ usleep(delay)
+ if debug.schedtrace <= 0 && (sched.gcwaiting != 0 || atomicload(&sched.npidle) == uint32(gomaxprocs)) { // TODO: fast atomic
+ lock(&sched.lock)
+ if atomicload(&sched.gcwaiting) != 0 || atomicload(&sched.npidle) == uint32(gomaxprocs) {
+ atomicstore(&sched.sysmonwait, 1)
+ unlock(&sched.lock)
+ notetsleep(&sched.sysmonnote, maxsleep)
+ lock(&sched.lock)
+ atomicstore(&sched.sysmonwait, 0)
+ noteclear(&sched.sysmonnote)
+ idle = 0
+ delay = 20
+ }
+ unlock(&sched.lock)
+ }
+ // poll network if not polled for more than 10ms
+ lastpoll := int64(atomicload64(&sched.lastpoll))
+ now := nanotime()
+ unixnow := unixnanotime()
+ if lastpoll != 0 && lastpoll+10*1000*1000 < now {
+ cas64(&sched.lastpoll, uint64(lastpoll), uint64(now))
+ gp := netpoll(false) // non-blocking - returns list of goroutines
+ if gp != nil {
+ // Need to decrement number of idle locked M's
+ // (pretending that one more is running) before injectglist.
+ // Otherwise it can lead to the following situation:
+ // injectglist grabs all P's but before it starts M's to run the P's,
+ // another M returns from syscall, finishes running its G,
+ // observes that there is no work to do and no other running M's
+ // and reports deadlock.
+ incidlelocked(-1)
+ injectglist(gp)
+ incidlelocked(1)
+ }
+ }
+ // retake P's blocked in syscalls
+ // and preempt long running G's
+ if retake(now) != 0 {
+ idle = 0
+ } else {
+ idle++
+ }
+ // check if we need to force a GC
+ lastgc := int64(atomicload64(&memstats.last_gc))
+ if lastgc != 0 && unixnow-lastgc > forcegcperiod && atomicload(&forcegc.idle) != 0 {
+ lock(&forcegc.lock)
+ forcegc.idle = 0
+ forcegc.g.schedlink = nil
+ injectglist(forcegc.g)
+ unlock(&forcegc.lock)
+ }
+ // scavenge heap once in a while
+ if lastscavenge+scavengelimit/2 < now {
+ mHeap_Scavenge(int32(nscavenge), uint64(now), uint64(scavengelimit))
+ lastscavenge = now
+ nscavenge++
+ }
+ if debug.schedtrace > 0 && lasttrace+int64(debug.schedtrace*1000000) <= now {
+ lasttrace = now
+ schedtrace(debug.scheddetail > 0)
+ }
+ }
+}
+
+var pdesc [_MaxGomaxprocs]struct {
+ schedtick uint32
+ schedwhen int64
+ syscalltick uint32
+ syscallwhen int64
+}
+
+func retake(now int64) uint32 {
+ n := 0
+ for i := int32(0); i < gomaxprocs; i++ {
+ _p_ := allp[i]
+ if _p_ == nil {
+ continue
+ }
+ pd := &pdesc[i]
+ s := _p_.status
+ if s == _Psyscall {
+ // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
+ t := int64(_p_.syscalltick)
+ if int64(pd.syscalltick) != t {
+ pd.syscalltick = uint32(t)
+ pd.syscallwhen = now
+ continue
+ }
+ // On the one hand we don't want to retake Ps if there is no other work to do,
+ // but on the other hand we want to retake them eventually
+ // because they can prevent the sysmon thread from deep sleep.
+ if _p_.runqhead == _p_.runqtail && atomicload(&sched.nmspinning)+atomicload(&sched.npidle) > 0 && pd.syscallwhen+10*1000*1000 > now {
+ continue
+ }
+ // Need to decrement number of idle locked M's
+ // (pretending that one more is running) before the CAS.
+ // Otherwise the M from which we retake can exit the syscall,
+ // increment nmidle and report deadlock.
+ incidlelocked(-1)
+ if cas(&_p_.status, s, _Pidle) {
+ n++
+ handoffp(_p_)
+ }
+ incidlelocked(1)
+ } else if s == _Prunning {
+ // Preempt G if it's running for more than 10ms.
+ t := int64(_p_.schedtick)
+ if int64(pd.schedtick) != t {
+ pd.schedtick = uint32(t)
+ pd.schedwhen = now
+ continue
+ }
+ if pd.schedwhen+10*1000*1000 > now {
+ continue
+ }
+ preemptone(_p_)
+ }
+ }
+ return uint32(n)
+}
+
+// Tell all goroutines that they have been preempted and they should stop.
+// This function is purely best-effort. It can fail to inform a goroutine if a
+// processor just started running it.
+// No locks need to be held.
+// Returns true if preemption request was issued to at least one goroutine.
+func preemptall() bool {
+ res := false
+ for i := int32(0); i < gomaxprocs; i++ {
+ _p_ := allp[i]
+ if _p_ == nil || _p_.status != _Prunning {
+ continue
+ }
+ if preemptone(_p_) {
+ res = true
+ }
+ }
+ return res
+}
+
+// Tell the goroutine running on processor P to stop.
+// This function is purely best-effort. It can incorrectly fail to inform the
+// goroutine. It can send inform the wrong goroutine. Even if it informs the
+// correct goroutine, that goroutine might ignore the request if it is
+// simultaneously executing newstack.
+// No lock needs to be held.
+// Returns true if preemption request was issued.
+// The actual preemption will happen at some point in the future
+// and will be indicated by the gp->status no longer being
+// Grunning
+func preemptone(_p_ *p) bool {
+ mp := _p_.m
+ if mp == nil || mp == getg().m {
+ return false
+ }
+ gp := mp.curg
+ if gp == nil || gp == mp.g0 {
+ return false
+ }
+
+ gp.preempt = true
+
+ // Every call in a go routine checks for stack overflow by
+ // comparing the current stack pointer to gp->stackguard0.
+ // Setting gp->stackguard0 to StackPreempt folds
+ // preemption into the normal stack overflow check.
+ gp.stackguard0 = stackPreempt
+ return true
+}
+
+var starttime int64
+
+func schedtrace(detailed bool) {
+ now := nanotime()
+ if starttime == 0 {
+ starttime = now
+ }
+
+ lock(&sched.lock)
+ print("SCHED ", (now-starttime)/1e6, "ms: gomaxprocs=", gomaxprocs, " idleprocs=", sched.npidle, " threads=", sched.mcount, " spinningthreads=", sched.nmspinning, " idlethreads=", sched.nmidle, " runqueue=", sched.runqsize)
+ if detailed {
+ print(" gcwaiting=", sched.gcwaiting, " nmidlelocked=", sched.nmidlelocked, " stopwait=", sched.stopwait, " sysmonwait=", sched.sysmonwait, "\n")
+ }
+ // We must be careful while reading data from P's, M's and G's.
+ // Even if we hold schedlock, most data can be changed concurrently.
+ // E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil.
+ for i := int32(0); i < gomaxprocs; i++ {
+ _p_ := allp[i]
+ if _p_ == nil {
+ continue
+ }
+ mp := _p_.m
+ h := atomicload(&_p_.runqhead)
+ t := atomicload(&_p_.runqtail)
+ if detailed {
+ id := int32(-1)
+ if mp != nil {
+ id = mp.id
+ }
+ print(" P", i, ": status=", _p_.status, " schedtick=", _p_.schedtick, " syscalltick=", _p_.syscalltick, " m=", id, " runqsize=", t-h, " gfreecnt=", _p_.gfreecnt, "\n")
+ } else {
+ // In non-detailed mode format lengths of per-P run queues as:
+ // [len1 len2 len3 len4]
+ print(" ")
+ if i == 0 {
+ print("[")
+ }
+ print(t - h)
+ if i == gomaxprocs-1 {
+ print("]\n")
+ }
+ }
+ }
+
+ if !detailed {
+ unlock(&sched.lock)
+ return
+ }
+
+ for mp := allm; mp != nil; mp = mp.alllink {
+ _p_ := mp.p
+ gp := mp.curg
+ lockedg := mp.lockedg
+ id1 := int32(-1)
+ if _p_ != nil {
+ id1 = _p_.id
+ }
+ id2 := int64(-1)
+ if gp != nil {
+ id2 = gp.goid
+ }
+ id3 := int64(-1)
+ 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")
+ }
+
+ lock(&allglock)
+ for gi := 0; gi < len(allgs); gi++ {
+ gp := allgs[gi]
+ mp := gp.m
+ lockedm := gp.lockedm
+ id1 := int32(-1)
+ if mp != nil {
+ id1 = mp.id
+ }
+ id2 := int32(-1)
+ if lockedm != nil {
+ id2 = lockedm.id
+ }
+ print(" G", gp.goid, ": status=", readgstatus(gp), "(", gp.waitreason, ") m=", id1, " lockedm=", id2, "\n")
+ }
+ unlock(&allglock)
+ unlock(&sched.lock)
+}
+
+// Put mp on midle list.
+// Sched must be locked.
+func mput(mp *m) {
+ mp.schedlink = sched.midle
+ sched.midle = mp
+ sched.nmidle++
+ checkdead()
+}
+
+// Try to get an m from midle list.
+// Sched must be locked.
+func mget() *m {
+ mp := sched.midle
+ if mp != nil {
+ sched.midle = mp.schedlink
+ sched.nmidle--
+ }
+ return mp
+}
+
+// Put gp on the global runnable queue.
+// Sched must be locked.
+func globrunqput(gp *g) {
+ gp.schedlink = nil
+ if sched.runqtail != nil {
+ sched.runqtail.schedlink = gp
+ } else {
+ sched.runqhead = gp
+ }
+ sched.runqtail = gp
+ sched.runqsize++
+}
+
+// Put a batch of runnable goroutines on the global runnable queue.
+// Sched must be locked.
+func globrunqputbatch(ghead *g, gtail *g, n int32) {
+ gtail.schedlink = nil
+ if sched.runqtail != nil {
+ sched.runqtail.schedlink = ghead
+ } else {
+ sched.runqhead = ghead
+ }
+ sched.runqtail = gtail
+ sched.runqsize += n
+}
+
+// Try get a batch of G's from the global runnable queue.
+// Sched must be locked.
+func globrunqget(_p_ *p, max int32) *g {
+ if sched.runqsize == 0 {
+ return nil
+ }
+
+ n := sched.runqsize/gomaxprocs + 1
+ if n > sched.runqsize {
+ n = sched.runqsize
+ }
+ if max > 0 && n > max {
+ n = max
+ }
+ if n > int32(len(_p_.runq))/2 {
+ n = int32(len(_p_.runq)) / 2
+ }
+
+ sched.runqsize -= n
+ if sched.runqsize == 0 {
+ sched.runqtail = nil
+ }
+
+ gp := sched.runqhead
+ sched.runqhead = gp.schedlink
+ n--
+ for ; n > 0; n-- {
+ gp1 := sched.runqhead
+ sched.runqhead = gp1.schedlink
+ runqput(_p_, gp1)
+ }
+ return gp
+}
+
+// Put p to on _Pidle list.
+// Sched must be locked.
+func pidleput(_p_ *p) {
+ _p_.link = sched.pidle
+ sched.pidle = _p_
+ xadd(&sched.npidle, 1) // TODO: fast atomic
+}
+
+// Try get a p from _Pidle list.
+// Sched must be locked.
+func pidleget() *p {
+ _p_ := sched.pidle
+ if _p_ != nil {
+ sched.pidle = _p_.link
+ xadd(&sched.npidle, -1) // TODO: fast atomic
+ }
+ return _p_
+}
+
+// Try to put g on local runnable queue.
+// If it's full, put onto global queue.
+// Executed only by the owner P.
+func runqput(_p_ *p, gp *g) {
+retry:
+ h := atomicload(&_p_.runqhead) // load-acquire, synchronize with consumers
+ t := _p_.runqtail
+ if t-h < uint32(len(_p_.runq)) {
+ _p_.runq[t%uint32(len(_p_.runq))] = gp
+ atomicstore(&_p_.runqtail, t+1) // store-release, makes the item available for consumption
+ return
+ }
+ if runqputslow(_p_, gp, h, t) {
+ return
+ }
+ // the queue is not full, now the put above must suceed
+ goto retry
+}
+
+// Put g and a batch of work from local runnable queue on global queue.
+// Executed only by the owner P.
+func runqputslow(_p_ *p, gp *g, h, t uint32) bool {
+ var batch [len(_p_.runq)/2 + 1]*g
+
+ // First, grab a batch from local queue.
+ n := t - h
+ n = n / 2
+ if n != uint32(len(_p_.runq)/2) {
+ gothrow("runqputslow: queue is not full")
+ }
+ for i := uint32(0); i < n; i++ {
+ batch[i] = _p_.runq[(h+i)%uint32(len(_p_.runq))]
+ }
+ if !cas(&_p_.runqhead, h, h+n) { // cas-release, commits consume
+ return false
+ }
+ batch[n] = gp
+
+ // Link the goroutines.
+ for i := uint32(0); i < n; i++ {
+ batch[i].schedlink = batch[i+1]
+ }
+
+ // Now put the batch on global queue.
+ lock(&sched.lock)
+ globrunqputbatch(batch[0], batch[n], int32(n+1))
+ unlock(&sched.lock)
+ return true
+}
+
+// Get g from local runnable queue.
+// Executed only by the owner P.
+func runqget(_p_ *p) *g {
+ for {
+ h := atomicload(&_p_.runqhead) // load-acquire, synchronize with other consumers
+ t := _p_.runqtail
+ if t == h {
+ return nil
+ }
+ gp := _p_.runq[h%uint32(len(_p_.runq))]
+ if cas(&_p_.runqhead, h, h+1) { // cas-release, commits consume
+ return gp
+ }
+ }
+}
+
+// Grabs a batch of goroutines from local runnable queue.
+// batch array must be of size len(p->runq)/2. Returns number of grabbed goroutines.
+// Can be executed by any P.
+func runqgrab(_p_ *p, batch []*g) uint32 {
+ for {
+ h := atomicload(&_p_.runqhead) // load-acquire, synchronize with other consumers
+ t := atomicload(&_p_.runqtail) // load-acquire, synchronize with the producer
+ n := t - h
+ n = n - n/2
+ if n == 0 {
+ return 0
+ }
+ if n > uint32(len(_p_.runq)/2) { // read inconsistent h and t
+ continue
+ }
+ for i := uint32(0); i < n; i++ {
+ batch[i] = _p_.runq[(h+i)%uint32(len(_p_.runq))]
+ }
+ if cas(&_p_.runqhead, h, h+n) { // cas-release, commits consume
+ return n
+ }
+ }
+}
+
+// Steal half of elements from local runnable queue of p2
+// and put onto local runnable queue of p.
+// Returns one of the stolen elements (or nil if failed).
+func runqsteal(_p_, p2 *p) *g {
+ var batch [len(_p_.runq) / 2]*g
+
+ n := runqgrab(p2, batch[:])
+ if n == 0 {
+ return nil
+ }
+ n--
+ gp := batch[n]
+ if n == 0 {
+ return gp
+ }
+ h := atomicload(&_p_.runqhead) // load-acquire, synchronize with consumers
+ t := _p_.runqtail
+ if t-h+n >= uint32(len(_p_.runq)) {
+ gothrow("runqsteal: runq overflow")
+ }
+ for i := uint32(0); i < n; i++ {
+ _p_.runq[(t+i)%uint32(len(_p_.runq))] = batch[i]
+ }
+ atomicstore(&_p_.runqtail, t+n) // store-release, makes the item available for consumption
+ return gp
+}
+
+func testSchedLocalQueue() {
+ _p_ := new(p)
+ gs := make([]g, len(_p_.runq))
+ for i := 0; i < len(_p_.runq); i++ {
+ if runqget(_p_) != nil {
+ gothrow("runq is not empty initially")
+ }
+ for j := 0; j < i; j++ {
+ runqput(_p_, &gs[i])
+ }
+ for j := 0; j < i; j++ {
+ if runqget(_p_) != &gs[i] {
+ print("bad element at iter ", i, "/", j, "\n")
+ gothrow("bad element")
+ }
+ }
+ if runqget(_p_) != nil {
+ gothrow("runq is not empty afterwards")
+ }
+ }
+}
+
+func testSchedLocalQueueSteal() {
+ p1 := new(p)
+ p2 := new(p)
+ gs := make([]g, len(p1.runq))
+ for i := 0; i < len(p1.runq); i++ {
+ for j := 0; j < i; j++ {
+ gs[j].sig = 0
+ runqput(p1, &gs[j])
+ }
+ gp := runqsteal(p2, p1)
+ s := 0
+ if gp != nil {
+ s++
+ gp.sig++
+ }
+ for {
+ gp = runqget(p2)
+ if gp == nil {
+ break
+ }
+ s++
+ gp.sig++
+ }
+ for {
+ gp = runqget(p1)
+ if gp == nil {
+ break
+ }
+ gp.sig++
+ }
+ for j := 0; j < i; j++ {
+ if gs[j].sig != 1 {
+ print("bad element ", j, "(", gs[j].sig, ") at iter ", i, "\n")
+ gothrow("bad element")
+ }
+ }
+ if s != i/2 && s != i/2+1 {
+ print("bad steal ", s, ", want ", i/2, " or ", i/2+1, ", iter ", i, "\n")
+ gothrow("bad steal")
+ }
+ }
+}
+
+func setMaxThreads(in int) (out int) {
+ lock(&sched.lock)
+ out = int(sched.maxmcount)
+ sched.maxmcount = int32(in)
+ checkmcount()
+ unlock(&sched.lock)
+ return
+}
+
+var goexperiment string = "GOEXPERIMENT" // TODO: defined in zaexperiment.h
+
+func haveexperiment(name string) bool {
+ x := goexperiment
+ for x != "" {
+ xname := ""
+ i := index(x, ",")
+ if i < 0 {
+ xname, x = x, ""
+ } else {
+ xname, x = x[:i], x[i+1:]
+ }
+ if xname == name {
+ return true
+ }
+ }
+ return false
+}
+
+//go:nosplit
+func sync_procPin() int {
+ _g_ := getg()
+ mp := _g_.m
+
+ mp.locks++
+ return int(mp.p.id)
+}
+
+//go:nosplit
+func sync_procUnpin() {
+ _g_ := getg()
+ _g_.m.locks--
+}
diff --git a/src/runtime/race.c b/src/runtime/race.c
deleted file mode 100644
index 5b0d11664..000000000
--- a/src/runtime/race.c
+++ /dev/null
@@ -1,347 +0,0 @@
-// Copyright 2011 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.
-
-// Implementation of the race detector API.
-// +build race
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "race.h"
-#include "type.h"
-#include "typekind.h"
-#include "textflag.h"
-
-// Race runtime functions called via runtime·racecall.
-void __tsan_init(void);
-void __tsan_fini(void);
-void __tsan_map_shadow(void);
-void __tsan_finalizer_goroutine(void);
-void __tsan_go_start(void);
-void __tsan_go_end(void);
-void __tsan_malloc(void);
-void __tsan_acquire(void);
-void __tsan_release(void);
-void __tsan_release_merge(void);
-void __tsan_go_ignore_sync_begin(void);
-void __tsan_go_ignore_sync_end(void);
-
-// Mimic what cmd/cgo would do.
-#pragma cgo_import_static __tsan_init
-#pragma cgo_import_static __tsan_fini
-#pragma cgo_import_static __tsan_map_shadow
-#pragma cgo_import_static __tsan_finalizer_goroutine
-#pragma cgo_import_static __tsan_go_start
-#pragma cgo_import_static __tsan_go_end
-#pragma cgo_import_static __tsan_malloc
-#pragma cgo_import_static __tsan_acquire
-#pragma cgo_import_static __tsan_release
-#pragma cgo_import_static __tsan_release_merge
-#pragma cgo_import_static __tsan_go_ignore_sync_begin
-#pragma cgo_import_static __tsan_go_ignore_sync_end
-
-// These are called from race_amd64.s.
-#pragma cgo_import_static __tsan_read
-#pragma cgo_import_static __tsan_read_pc
-#pragma cgo_import_static __tsan_read_range
-#pragma cgo_import_static __tsan_write
-#pragma cgo_import_static __tsan_write_pc
-#pragma cgo_import_static __tsan_write_range
-#pragma cgo_import_static __tsan_func_enter
-#pragma cgo_import_static __tsan_func_exit
-
-#pragma cgo_import_static __tsan_go_atomic32_load
-#pragma cgo_import_static __tsan_go_atomic64_load
-#pragma cgo_import_static __tsan_go_atomic32_store
-#pragma cgo_import_static __tsan_go_atomic64_store
-#pragma cgo_import_static __tsan_go_atomic32_exchange
-#pragma cgo_import_static __tsan_go_atomic64_exchange
-#pragma cgo_import_static __tsan_go_atomic32_fetch_add
-#pragma cgo_import_static __tsan_go_atomic64_fetch_add
-#pragma cgo_import_static __tsan_go_atomic32_compare_exchange
-#pragma cgo_import_static __tsan_go_atomic64_compare_exchange
-
-extern byte runtime·noptrdata[];
-extern byte runtime·enoptrdata[];
-extern byte runtime·data[];
-extern byte runtime·edata[];
-extern byte runtime·bss[];
-extern byte runtime·ebss[];
-extern byte runtime·noptrbss[];
-extern byte runtime·enoptrbss[];
-
-// start/end of global data (data+bss).
-uintptr runtime·racedatastart;
-uintptr runtime·racedataend;
-// start/end of heap for race_amd64.s
-uintptr runtime·racearenastart;
-uintptr runtime·racearenaend;
-
-void runtime·racefuncenter(void *callpc);
-void runtime·racefuncexit(void);
-void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc);
-void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc);
-void runtime·racesymbolizethunk(void*);
-
-// racecall allows calling an arbitrary function f from C race runtime
-// with up to 4 uintptr arguments.
-void runtime·racecall(void(*f)(void), ...);
-
-// checks if the address has shadow (i.e. heap or data/bss)
-#pragma textflag NOSPLIT
-static bool
-isvalidaddr(uintptr addr)
-{
- if(addr >= runtime·racearenastart && addr < runtime·racearenaend)
- return true;
- if(addr >= runtime·racedatastart && addr < runtime·racedataend)
- return true;
- return false;
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·raceinit(void)
-{
- uintptr racectx, start, end, size;
-
- // cgo is required to initialize libc, which is used by race runtime
- if(!runtime·iscgo)
- runtime·throw("raceinit: race build must use cgo");
- runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk);
- // Round data segment to page boundaries, because it's used in mmap().
- // The relevant sections are noptrdata, data, bss, noptrbss.
- // In external linking mode, there may be other non-Go data mixed in,
- // and the sections may even occur out of order.
- // Work out a conservative range of addresses.
- start = ~(uintptr)0;
- end = 0;
- if(start > (uintptr)runtime·noptrdata)
- start = (uintptr)runtime·noptrdata;
- if(start > (uintptr)runtime·data)
- start = (uintptr)runtime·data;
- if(start > (uintptr)runtime·noptrbss)
- start = (uintptr)runtime·noptrbss;
- if(start > (uintptr)runtime·bss)
- start = (uintptr)runtime·bss;
- if(end < (uintptr)runtime·enoptrdata)
- end = (uintptr)runtime·enoptrdata;
- if(end < (uintptr)runtime·edata)
- end = (uintptr)runtime·edata;
- if(end < (uintptr)runtime·enoptrbss)
- end = (uintptr)runtime·enoptrbss;
- if(end < (uintptr)runtime·ebss)
- end = (uintptr)runtime·ebss;
- start = start & ~(PageSize-1);
- size = ROUND(end - start, PageSize);
- runtime·racecall(__tsan_map_shadow, start, size);
- runtime·racedatastart = start;
- runtime·racedataend = start + size;
- return racectx;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racefini(void)
-{
- runtime·racecall(__tsan_fini);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racemapshadow(void *addr, uintptr size)
-{
- if(runtime·racearenastart == 0)
- runtime·racearenastart = (uintptr)addr;
- if(runtime·racearenaend < (uintptr)addr+size)
- runtime·racearenaend = (uintptr)addr+size;
- runtime·racecall(__tsan_map_shadow, addr, size);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racemalloc(void *p, uintptr sz)
-{
- runtime·racecall(__tsan_malloc, p, sz);
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·racegostart(void *pc)
-{
- uintptr racectx;
- G *spawng;
-
- if(g->m->curg != nil)
- spawng = g->m->curg;
- else
- spawng = g;
-
- runtime·racecall(__tsan_go_start, spawng->racectx, &racectx, pc);
- return racectx;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racegoend(void)
-{
- runtime·racecall(__tsan_go_end, g->racectx);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
-{
- if(g != g->m->curg) {
- // The call is coming from manual instrumentation of Go code running on g0/gsignal.
- // Not interesting.
- return;
- }
- if(callpc != nil)
- runtime·racefuncenter(callpc);
- runtime·racewriterangepc1(addr, sz, pc);
- if(callpc != nil)
- runtime·racefuncexit();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
-{
- if(g != g->m->curg) {
- // The call is coming from manual instrumentation of Go code running on g0/gsignal.
- // Not interesting.
- return;
- }
- if(callpc != nil)
- runtime·racefuncenter(callpc);
- runtime·racereadrangepc1(addr, sz, pc);
- if(callpc != nil)
- runtime·racefuncexit();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc)
-{
- uint8 kind;
-
- kind = t->kind & KindMask;
- if(kind == KindArray || kind == KindStruct)
- runtime·racewriterangepc(addr, t->size, callpc, pc);
- else
- runtime·racewritepc(addr, callpc, pc);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc)
-{
- uint8 kind;
-
- kind = t->kind & KindMask;
- if(kind == KindArray || kind == KindStruct)
- runtime·racereadrangepc(addr, t->size, callpc, pc);
- else
- runtime·racereadpc(addr, callpc, pc);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·raceacquire(void *addr)
-{
- runtime·raceacquireg(g, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·raceacquireg(G *gp, void *addr)
-{
- if(g->raceignore || !isvalidaddr((uintptr)addr))
- return;
- runtime·racecall(__tsan_acquire, gp->racectx, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racerelease(void *addr)
-{
- if(g->raceignore || !isvalidaddr((uintptr)addr))
- return;
- runtime·racereleaseg(g, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereleaseg(G *gp, void *addr)
-{
- if(g->raceignore || !isvalidaddr((uintptr)addr))
- return;
- runtime·racecall(__tsan_release, gp->racectx, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereleasemerge(void *addr)
-{
- runtime·racereleasemergeg(g, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereleasemergeg(G *gp, void *addr)
-{
- if(g->raceignore || !isvalidaddr((uintptr)addr))
- return;
- runtime·racecall(__tsan_release_merge, gp->racectx, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racefingo(void)
-{
- runtime·racecall(__tsan_finalizer_goroutine, g->racectx);
-}
-
-// func RaceAcquire(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceAcquire(void *addr)
-{
- runtime·raceacquire(addr);
-}
-
-// func RaceRelease(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceRelease(void *addr)
-{
- runtime·racerelease(addr);
-}
-
-// func RaceReleaseMerge(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceReleaseMerge(void *addr)
-{
- runtime·racereleasemerge(addr);
-}
-
-// func RaceDisable()
-#pragma textflag NOSPLIT
-void
-runtime·RaceDisable(void)
-{
- if(g->raceignore++ == 0)
- runtime·racecall(__tsan_go_ignore_sync_begin, g->racectx);
-}
-
-// func RaceEnable()
-#pragma textflag NOSPLIT
-void
-runtime·RaceEnable(void)
-{
- if(--g->raceignore == 0)
- runtime·racecall(__tsan_go_ignore_sync_end, g->racectx);
-}
diff --git a/src/runtime/race.go b/src/runtime/race.go
index bb0ee6df6..649cd7295 100644
--- a/src/runtime/race.go
+++ b/src/runtime/race.go
@@ -12,18 +12,6 @@ import (
"unsafe"
)
-func racefini()
-
-// RaceDisable disables handling of race events in the current goroutine.
-func RaceDisable()
-
-// RaceEnable re-enables handling of race events in the current goroutine.
-func RaceEnable()
-
-func RaceAcquire(addr unsafe.Pointer)
-func RaceRelease(addr unsafe.Pointer)
-func RaceReleaseMerge(addr unsafe.Pointer)
-
func RaceRead(addr unsafe.Pointer)
func RaceWrite(addr unsafe.Pointer)
func RaceReadRange(addr unsafe.Pointer, len int)
@@ -67,32 +55,6 @@ func racereadpc(addr unsafe.Pointer, callpc, pc uintptr)
//go:noescape
func racewritepc(addr unsafe.Pointer, callpc, pc uintptr)
-//go:noescape
-func racereadrangepc(addr unsafe.Pointer, len uintptr, callpc, pc uintptr)
-
-//go:noescape
-func racewriterangepc(addr unsafe.Pointer, len uintptr, callpc, pc uintptr)
-
-//go:noescape
-func raceacquire(addr unsafe.Pointer)
-
-//go:noescape
-func racerelease(addr unsafe.Pointer)
-
-//go:noescape
-func raceacquireg(gp *g, addr unsafe.Pointer)
-
-//go:noescape
-func racereleaseg(gp *g, addr unsafe.Pointer)
-
-func racefingo()
-
-//go:noescape
-func racemalloc(p unsafe.Pointer, size uintptr)
-
-//go:noescape
-func racereleasemerge(addr unsafe.Pointer)
-
type symbolizeContext struct {
pc uintptr
fn *byte
@@ -118,8 +80,8 @@ func racesymbolize(ctx *symbolizeContext) {
}
ctx.fn = funcname(f)
- var file string
- ctx.line = uintptr(funcline(f, ctx.pc, &file))
+ file, line := funcline(f, ctx.pc)
+ ctx.line = uintptr(line)
ctx.file = &bytes(file)[0] // assume NUL-terminated
ctx.off = ctx.pc - f.entry
ctx.res = 1
diff --git a/src/runtime/race.h b/src/runtime/race.h
deleted file mode 100644
index fee31e09f..000000000
--- a/src/runtime/race.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2012 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.
-
-// Definitions related to data race detection.
-
-#ifdef RACE
-enum { raceenabled = 1 };
-#else
-enum { raceenabled = 0 };
-#endif
-
-// Initialize race detection subsystem.
-uintptr runtime·raceinit(void);
-// Finalize race detection subsystem, does not return.
-void runtime·racefini(void);
-
-void runtime·racemapshadow(void *addr, uintptr size);
-void runtime·racemalloc(void *p, uintptr sz);
-uintptr runtime·racegostart(void *pc);
-void runtime·racegoend(void);
-void runtime·racewritepc(void *addr, void *callpc, void *pc);
-void runtime·racereadpc(void *addr, void *callpc, void *pc);
-void runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc);
-void runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc);
-void runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc);
-void runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc);
-void runtime·racefingo(void);
-void runtime·raceacquire(void *addr);
-void runtime·raceacquireg(G *gp, void *addr);
-void runtime·racerelease(void *addr);
-void runtime·racereleaseg(G *gp, void *addr);
-void runtime·racereleasemerge(void *addr);
-void runtime·racereleasemergeg(G *gp, void *addr);
diff --git a/src/runtime/race0.go b/src/runtime/race0.go
index 5d90cc859..dadb6083f 100644
--- a/src/runtime/race0.go
+++ b/src/runtime/race0.go
@@ -18,7 +18,7 @@ const raceenabled = false
func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { gothrow("race") }
func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { gothrow("race") }
-func raceinit() { gothrow("race") }
+func raceinit() uintptr { gothrow("race"); return 0 }
func racefini() { gothrow("race") }
func racemapshadow(addr unsafe.Pointer, size uintptr) { gothrow("race") }
func racewritepc(addr unsafe.Pointer, callerpc, pc uintptr) { gothrow("race") }
diff --git a/src/runtime/race1.go b/src/runtime/race1.go
new file mode 100644
index 000000000..2ec2bee65
--- /dev/null
+++ b/src/runtime/race1.go
@@ -0,0 +1,335 @@
+// Copyright 2011 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.
+
+// Implementation of the race detector API.
+// +build race
+
+package runtime
+
+import "unsafe"
+
+// Race runtime functions called via runtime·racecall.
+//go:linkname __tsan_init __tsan_init
+var __tsan_init byte
+
+//go:linkname __tsan_fini __tsan_fini
+var __tsan_fini byte
+
+//go:linkname __tsan_map_shadow __tsan_map_shadow
+var __tsan_map_shadow byte
+
+//go:linkname __tsan_finalizer_goroutine __tsan_finalizer_goroutine
+var __tsan_finalizer_goroutine byte
+
+//go:linkname __tsan_go_start __tsan_go_start
+var __tsan_go_start byte
+
+//go:linkname __tsan_go_end __tsan_go_end
+var __tsan_go_end byte
+
+//go:linkname __tsan_malloc __tsan_malloc
+var __tsan_malloc byte
+
+//go:linkname __tsan_acquire __tsan_acquire
+var __tsan_acquire byte
+
+//go:linkname __tsan_release __tsan_release
+var __tsan_release byte
+
+//go:linkname __tsan_release_merge __tsan_release_merge
+var __tsan_release_merge byte
+
+//go:linkname __tsan_go_ignore_sync_begin __tsan_go_ignore_sync_begin
+var __tsan_go_ignore_sync_begin byte
+
+//go:linkname __tsan_go_ignore_sync_end __tsan_go_ignore_sync_end
+var __tsan_go_ignore_sync_end byte
+
+// Mimic what cmd/cgo would do.
+//go:cgo_import_static __tsan_init
+//go:cgo_import_static __tsan_fini
+//go:cgo_import_static __tsan_map_shadow
+//go:cgo_import_static __tsan_finalizer_goroutine
+//go:cgo_import_static __tsan_go_start
+//go:cgo_import_static __tsan_go_end
+//go:cgo_import_static __tsan_malloc
+//go:cgo_import_static __tsan_acquire
+//go:cgo_import_static __tsan_release
+//go:cgo_import_static __tsan_release_merge
+//go:cgo_import_static __tsan_go_ignore_sync_begin
+//go:cgo_import_static __tsan_go_ignore_sync_end
+
+// These are called from race_amd64.s.
+//go:cgo_import_static __tsan_read
+//go:cgo_import_static __tsan_read_pc
+//go:cgo_import_static __tsan_read_range
+//go:cgo_import_static __tsan_write
+//go:cgo_import_static __tsan_write_pc
+//go:cgo_import_static __tsan_write_range
+//go:cgo_import_static __tsan_func_enter
+//go:cgo_import_static __tsan_func_exit
+
+//go:cgo_import_static __tsan_go_atomic32_load
+//go:cgo_import_static __tsan_go_atomic64_load
+//go:cgo_import_static __tsan_go_atomic32_store
+//go:cgo_import_static __tsan_go_atomic64_store
+//go:cgo_import_static __tsan_go_atomic32_exchange
+//go:cgo_import_static __tsan_go_atomic64_exchange
+//go:cgo_import_static __tsan_go_atomic32_fetch_add
+//go:cgo_import_static __tsan_go_atomic64_fetch_add
+//go:cgo_import_static __tsan_go_atomic32_compare_exchange
+//go:cgo_import_static __tsan_go_atomic64_compare_exchange
+
+// start/end of global data (data+bss).
+var racedatastart uintptr
+var racedataend uintptr
+
+// start/end of heap for race_amd64.s
+var racearenastart uintptr
+var racearenaend uintptr
+
+func racefuncenter(uintptr)
+func racefuncexit()
+func racereadrangepc1(uintptr, uintptr, uintptr)
+func racewriterangepc1(uintptr, uintptr, uintptr)
+func racesymbolizethunk(uintptr)
+
+// racecall allows calling an arbitrary function f from C race runtime
+// with up to 4 uintptr arguments.
+func racecall(*byte, uintptr, uintptr, uintptr, uintptr)
+
+// checks if the address has shadow (i.e. heap or data/bss)
+//go:nosplit
+func isvalidaddr(addr unsafe.Pointer) bool {
+ return racearenastart <= uintptr(addr) && uintptr(addr) < racearenaend ||
+ racedatastart <= uintptr(addr) && uintptr(addr) < racedataend
+}
+
+//go:nosplit
+func raceinit() uintptr {
+ // cgo is required to initialize libc, which is used by race runtime
+ if !iscgo {
+ gothrow("raceinit: race build must use cgo")
+ }
+
+ var racectx uintptr
+ racecall(&__tsan_init, uintptr(unsafe.Pointer(&racectx)), funcPC(racesymbolizethunk), 0, 0)
+
+ // Round data segment to page boundaries, because it's used in mmap().
+ start := ^uintptr(0)
+ end := uintptr(0)
+ if start > uintptr(unsafe.Pointer(&noptrdata)) {
+ start = uintptr(unsafe.Pointer(&noptrdata))
+ }
+ if start > uintptr(unsafe.Pointer(&data)) {
+ start = uintptr(unsafe.Pointer(&data))
+ }
+ if start > uintptr(unsafe.Pointer(&noptrbss)) {
+ start = uintptr(unsafe.Pointer(&noptrbss))
+ }
+ if start > uintptr(unsafe.Pointer(&bss)) {
+ start = uintptr(unsafe.Pointer(&bss))
+ }
+ if end < uintptr(unsafe.Pointer(&enoptrdata)) {
+ end = uintptr(unsafe.Pointer(&enoptrdata))
+ }
+ if end < uintptr(unsafe.Pointer(&edata)) {
+ end = uintptr(unsafe.Pointer(&edata))
+ }
+ if end < uintptr(unsafe.Pointer(&enoptrbss)) {
+ end = uintptr(unsafe.Pointer(&enoptrbss))
+ }
+ if end < uintptr(unsafe.Pointer(&ebss)) {
+ end = uintptr(unsafe.Pointer(&ebss))
+ }
+ size := round(end-start, _PageSize)
+ racecall(&__tsan_map_shadow, start, size, 0, 0)
+ racedatastart = start
+ racedataend = start + size
+
+ return racectx
+}
+
+//go:nosplit
+func racefini() {
+ racecall(&__tsan_fini, 0, 0, 0, 0)
+}
+
+//go:nosplit
+func racemapshadow(addr unsafe.Pointer, size uintptr) {
+ if racearenastart == 0 {
+ racearenastart = uintptr(addr)
+ }
+ if racearenaend < uintptr(addr)+size {
+ racearenaend = uintptr(addr) + size
+ }
+ racecall(&__tsan_map_shadow, uintptr(addr), size, 0, 0)
+}
+
+//go:nosplit
+func racemalloc(p unsafe.Pointer, sz uintptr) {
+ racecall(&__tsan_malloc, uintptr(p), sz, 0, 0)
+}
+
+//go:nosplit
+func racegostart(pc uintptr) uintptr {
+ _g_ := getg()
+ var spawng *g
+ if _g_.m.curg != nil {
+ spawng = _g_.m.curg
+ } else {
+ spawng = _g_
+ }
+
+ var racectx uintptr
+ racecall(&__tsan_go_start, spawng.racectx, uintptr(unsafe.Pointer(&racectx)), pc, 0)
+ return racectx
+}
+
+//go:nosplit
+func racegoend() {
+ racecall(&__tsan_go_end, getg().racectx, 0, 0, 0)
+}
+
+//go:nosplit
+func racewriterangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
+ _g_ := getg()
+ if _g_ != _g_.m.curg {
+ // The call is coming from manual instrumentation of Go code running on g0/gsignal.
+ // Not interesting.
+ return
+ }
+ if callpc != 0 {
+ racefuncenter(callpc)
+ }
+ racewriterangepc1(uintptr(addr), sz, pc)
+ if callpc != 0 {
+ racefuncexit()
+ }
+}
+
+//go:nosplit
+func racereadrangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
+ _g_ := getg()
+ if _g_ != _g_.m.curg {
+ // The call is coming from manual instrumentation of Go code running on g0/gsignal.
+ // Not interesting.
+ return
+ }
+ if callpc != 0 {
+ racefuncenter(callpc)
+ }
+ racereadrangepc1(uintptr(addr), sz, pc)
+ if callpc != 0 {
+ racefuncexit()
+ }
+}
+
+//go:nosplit
+func racewriteobjectpc(addr unsafe.Pointer, t *_type, callpc, pc uintptr) {
+ kind := t.kind & _KindMask
+ if kind == _KindArray || kind == _KindStruct {
+ racewriterangepc(addr, t.size, callpc, pc)
+ } else {
+ racewritepc(addr, callpc, pc)
+ }
+}
+
+//go:nosplit
+func racereadobjectpc(addr unsafe.Pointer, t *_type, callpc, pc uintptr) {
+ kind := t.kind & _KindMask
+ if kind == _KindArray || kind == _KindStruct {
+ racereadrangepc(addr, t.size, callpc, pc)
+ } else {
+ racereadpc(addr, callpc, pc)
+ }
+}
+
+//go:nosplit
+func raceacquire(addr unsafe.Pointer) {
+ raceacquireg(getg(), addr)
+}
+
+//go:nosplit
+func raceacquireg(gp *g, addr unsafe.Pointer) {
+ if getg().raceignore != 0 || !isvalidaddr(addr) {
+ return
+ }
+ racecall(&__tsan_acquire, gp.racectx, uintptr(addr), 0, 0)
+}
+
+//go:nosplit
+func racerelease(addr unsafe.Pointer) {
+ _g_ := getg()
+ if _g_.raceignore != 0 || !isvalidaddr(addr) {
+ return
+ }
+ racereleaseg(_g_, addr)
+}
+
+//go:nosplit
+func racereleaseg(gp *g, addr unsafe.Pointer) {
+ if getg().raceignore != 0 || !isvalidaddr(addr) {
+ return
+ }
+ racecall(&__tsan_release, gp.racectx, uintptr(addr), 0, 0)
+}
+
+//go:nosplit
+func racereleasemerge(addr unsafe.Pointer) {
+ racereleasemergeg(getg(), addr)
+}
+
+//go:nosplit
+func racereleasemergeg(gp *g, addr unsafe.Pointer) {
+ if getg().raceignore != 0 || !isvalidaddr(addr) {
+ return
+ }
+ racecall(&__tsan_release_merge, gp.racectx, uintptr(addr), 0, 0)
+}
+
+//go:nosplit
+func racefingo() {
+ racecall(&__tsan_finalizer_goroutine, getg().racectx, 0, 0, 0)
+}
+
+//go:nosplit
+
+func RaceAcquire(addr unsafe.Pointer) {
+ raceacquire(addr)
+}
+
+//go:nosplit
+
+func RaceRelease(addr unsafe.Pointer) {
+ racerelease(addr)
+}
+
+//go:nosplit
+
+func RaceReleaseMerge(addr unsafe.Pointer) {
+ racereleasemerge(addr)
+}
+
+//go:nosplit
+
+// RaceEnable re-enables handling of race events in the current goroutine.
+func RaceDisable() {
+ _g_ := getg()
+ if _g_.raceignore == 0 {
+ racecall(&__tsan_go_ignore_sync_begin, _g_.racectx, 0, 0, 0)
+ }
+ _g_.raceignore++
+}
+
+//go:nosplit
+
+// RaceDisable disables handling of race events in the current goroutine.
+func RaceEnable() {
+ _g_ := getg()
+ _g_.raceignore--
+ if _g_.raceignore == 0 {
+ racecall(&__tsan_go_ignore_sync_end, _g_.racectx, 0, 0, 0)
+ }
+}
diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s
index a96d9de12..d54d9798f 100644
--- a/src/runtime/race_amd64.s
+++ b/src/runtime/race_amd64.s
@@ -4,7 +4,8 @@
// +build race
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "funcdata.h"
#include "textflag.h"
@@ -140,18 +141,18 @@ TEXT racecalladdr<>(SB), NOSPLIT, $0-0
MOVQ g_racectx(R14), RARG0 // goroutine context
// Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend).
CMPQ RARG1, runtime·racearenastart(SB)
- JB racecalladdr_data
+ JB data
CMPQ RARG1, runtime·racearenaend(SB)
- JB racecalladdr_call
-racecalladdr_data:
+ JB call
+data:
CMPQ RARG1, runtime·racedatastart(SB)
- JB racecalladdr_ret
+ JB ret
CMPQ RARG1, runtime·racedataend(SB)
- JAE racecalladdr_ret
-racecalladdr_call:
+ JAE ret
+call:
MOVQ AX, AX // w/o this 6a miscompiles this function
JMP racecall<>(SB)
-racecalladdr_ret:
+ret:
RET
// func runtime·racefuncenter(pc uintptr)
@@ -366,9 +367,9 @@ TEXT racecall<>(SB), NOSPLIT, $0-0
MOVQ SP, R12 // callee-saved, preserved across the CALL
MOVQ m_g0(R13), R10
CMPQ R10, R14
- JE racecall_cont // already on g0
+ JE call // already on g0
MOVQ (g_sched+gobuf_sp)(R10), SP
-racecall_cont:
+call:
ANDQ $~15, SP // alignment for gcc ABI
CALL AX
MOVQ R12, SP
diff --git a/src/runtime/rdebug.go b/src/runtime/rdebug.go
index e5e691122..f2766d793 100644
--- a/src/runtime/rdebug.go
+++ b/src/runtime/rdebug.go
@@ -10,15 +10,6 @@ func setMaxStack(in int) (out int) {
return out
}
-func setGCPercent(in int32) (out int32) {
- mp := acquirem()
- mp.scalararg[0] = uintptr(int(in))
- onM(setgcpercent_m)
- out = int32(int(mp.scalararg[0]))
- releasem(mp)
- return out
-}
-
func setPanicOnFault(new bool) (old bool) {
mp := acquirem()
old = mp.curg.paniconfault
@@ -26,12 +17,3 @@ func setPanicOnFault(new bool) (old bool) {
releasem(mp)
return old
}
-
-func setMaxThreads(in int) (out int) {
- mp := acquirem()
- mp.scalararg[0] = uintptr(in)
- onM(setmaxthreads_m)
- out = int(mp.scalararg[0])
- releasem(mp)
- return out
-}
diff --git a/src/runtime/rt0_linux_power64.s b/src/runtime/rt0_linux_power64.s
new file mode 100644
index 000000000..970b6a673
--- /dev/null
+++ b/src/runtime/rt0_linux_power64.s
@@ -0,0 +1,17 @@
+#include "textflag.h"
+
+// actually a function descriptor for _main<>(SB)
+TEXT _rt0_power64_linux(SB),NOSPLIT,$0
+ DWORD $_main<>(SB)
+ DWORD $0
+ DWORD $0
+
+TEXT _main<>(SB),NOSPLIT,$-8
+ MOVD 0(R1), R3 // argc
+ ADD $8, R1, R4 // argv
+ BR main(SB)
+
+TEXT main(SB),NOSPLIT,$-8
+ MOVD $runtime·rt0_go(SB), R31
+ MOVD R31, CTR
+ BR (CTR)
diff --git a/src/runtime/rt0_linux_power64le.s b/src/runtime/rt0_linux_power64le.s
new file mode 100644
index 000000000..85ce84733
--- /dev/null
+++ b/src/runtime/rt0_linux_power64le.s
@@ -0,0 +1,14 @@
+#include "textflag.h"
+
+TEXT _rt0_power64le_linux(SB),NOSPLIT,$0
+ BR _main<>(SB)
+
+TEXT _main<>(SB),NOSPLIT,$-8
+ MOVD 0(R1), R3 // argc
+ ADD $8, R1, R4 // argv
+ BR main(SB)
+
+TEXT main(SB),NOSPLIT,$-8
+ MOVD $runtime·rt0_go(SB), R31
+ MOVD R31, CTR
+ BR (CTR)
diff --git a/src/runtime/rt0_windows_amd64.s b/src/runtime/rt0_windows_amd64.s
index 197f52e11..df956ba36 100644
--- a/src/runtime/rt0_windows_amd64.s
+++ b/src/runtime/rt0_windows_amd64.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
TEXT _rt0_amd64_windows(SB),NOSPLIT,$-8
diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c
deleted file mode 100644
index c823691ec..000000000
--- a/src/runtime/runtime.c
+++ /dev/null
@@ -1,399 +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.
-
-#include "runtime.h"
-#include "stack.h"
-#include "arch_GOARCH.h"
-#include "textflag.h"
-#include "malloc.h"
-
-// Keep a cached value to make gotraceback fast,
-// since we call it on every call to gentraceback.
-// The cached value is a uint32 in which the low bit
-// is the "crash" setting and the top 31 bits are the
-// gotraceback value.
-static uint32 traceback_cache = 2<<1;
-
-// The GOTRACEBACK environment variable controls the
-// behavior of a Go program that is crashing and exiting.
-// GOTRACEBACK=0 suppress all tracebacks
-// GOTRACEBACK=1 default behavior - show tracebacks but exclude runtime frames
-// GOTRACEBACK=2 show tracebacks including runtime frames
-// GOTRACEBACK=crash show tracebacks including runtime frames, then crash (core dump etc)
-#pragma textflag NOSPLIT
-int32
-runtime·gotraceback(bool *crash)
-{
- if(crash != nil)
- *crash = false;
- if(g->m->traceback != 0)
- return g->m->traceback;
- if(crash != nil)
- *crash = traceback_cache&1;
- return traceback_cache>>1;
-}
-
-int32
-runtime·mcmp(byte *s1, byte *s2, uintptr n)
-{
- uintptr i;
- byte c1, c2;
-
- for(i=0; i<n; i++) {
- c1 = s1[i];
- c2 = s2[i];
- if(c1 < c2)
- return -1;
- if(c1 > c2)
- return +1;
- }
- return 0;
-}
-
-
-byte*
-runtime·mchr(byte *p, byte c, byte *ep)
-{
- for(; p < ep; p++)
- if(*p == c)
- return p;
- return nil;
-}
-
-static int32 argc;
-
-#pragma dataflag NOPTR /* argv not a heap pointer */
-static uint8** argv;
-
-extern Slice runtime·argslice;
-extern Slice runtime·envs;
-
-void (*runtime·sysargs)(int32, uint8**);
-
-void
-runtime·args(int32 c, uint8 **v)
-{
- argc = c;
- argv = v;
- if(runtime·sysargs != nil)
- runtime·sysargs(c, v);
-}
-
-int32 runtime·isplan9;
-int32 runtime·issolaris;
-int32 runtime·iswindows;
-
-// Information about what cpu features are available.
-// Set on startup in asm_{x86/amd64}.s.
-uint32 runtime·cpuid_ecx;
-uint32 runtime·cpuid_edx;
-
-void
-runtime·goargs(void)
-{
- String *s;
- int32 i;
-
- // for windows implementation see "os" package
- if(Windows)
- return;
-
- runtime·argslice = runtime·makeStringSlice(argc);
- s = (String*)runtime·argslice.array;
- for(i=0; i<argc; i++)
- s[i] = runtime·gostringnocopy(argv[i]);
-}
-
-void
-runtime·goenvs_unix(void)
-{
- String *s;
- int32 i, n;
-
- for(n=0; argv[argc+1+n] != 0; n++)
- ;
-
- runtime·envs = runtime·makeStringSlice(n);
- s = (String*)runtime·envs.array;
- for(i=0; i<n; i++)
- s[i] = runtime·gostringnocopy(argv[argc+1+i]);
-}
-
-#pragma textflag NOSPLIT
-Slice
-runtime·environ()
-{
- return runtime·envs;
-}
-
-int32
-runtime·atoi(byte *p)
-{
- int32 n;
-
- n = 0;
- while('0' <= *p && *p <= '9')
- n = n*10 + *p++ - '0';
- return n;
-}
-
-static void
-TestAtomic64(void)
-{
- uint64 z64, x64;
-
- z64 = 42;
- x64 = 0;
- PREFETCH(&z64);
- if(runtime·cas64(&z64, x64, 1))
- runtime·throw("cas64 failed");
- if(x64 != 0)
- runtime·throw("cas64 failed");
- x64 = 42;
- if(!runtime·cas64(&z64, x64, 1))
- runtime·throw("cas64 failed");
- if(x64 != 42 || z64 != 1)
- runtime·throw("cas64 failed");
- if(runtime·atomicload64(&z64) != 1)
- runtime·throw("load64 failed");
- runtime·atomicstore64(&z64, (1ull<<40)+1);
- if(runtime·atomicload64(&z64) != (1ull<<40)+1)
- runtime·throw("store64 failed");
- if(runtime·xadd64(&z64, (1ull<<40)+1) != (2ull<<40)+2)
- runtime·throw("xadd64 failed");
- if(runtime·atomicload64(&z64) != (2ull<<40)+2)
- runtime·throw("xadd64 failed");
- if(runtime·xchg64(&z64, (3ull<<40)+3) != (2ull<<40)+2)
- runtime·throw("xchg64 failed");
- if(runtime·atomicload64(&z64) != (3ull<<40)+3)
- runtime·throw("xchg64 failed");
-}
-
-void
-runtime·check(void)
-{
- int8 a;
- uint8 b;
- int16 c;
- uint16 d;
- int32 e;
- uint32 f;
- int64 g;
- uint64 h;
- float32 i, i1;
- float64 j, j1;
- byte *k, *k1;
- uint16* l;
- struct x1 {
- byte x;
- };
- struct y1 {
- struct x1 x1;
- byte y;
- };
-
- if(sizeof(a) != 1) runtime·throw("bad a");
- if(sizeof(b) != 1) runtime·throw("bad b");
- if(sizeof(c) != 2) runtime·throw("bad c");
- if(sizeof(d) != 2) runtime·throw("bad d");
- if(sizeof(e) != 4) runtime·throw("bad e");
- if(sizeof(f) != 4) runtime·throw("bad f");
- if(sizeof(g) != 8) runtime·throw("bad g");
- if(sizeof(h) != 8) runtime·throw("bad h");
- if(sizeof(i) != 4) runtime·throw("bad i");
- if(sizeof(j) != 8) runtime·throw("bad j");
- if(sizeof(k) != sizeof(uintptr)) runtime·throw("bad k");
- if(sizeof(l) != sizeof(uintptr)) runtime·throw("bad l");
- if(sizeof(struct x1) != 1) runtime·throw("bad sizeof x1");
- if(offsetof(struct y1, y) != 1) runtime·throw("bad offsetof y1.y");
- if(sizeof(struct y1) != 2) runtime·throw("bad sizeof y1");
-
- if(runtime·timediv(12345LL*1000000000+54321, 1000000000, &e) != 12345 || e != 54321)
- runtime·throw("bad timediv");
-
- uint32 z;
- z = 1;
- if(!runtime·cas(&z, 1, 2))
- runtime·throw("cas1");
- if(z != 2)
- runtime·throw("cas2");
-
- z = 4;
- if(runtime·cas(&z, 5, 6))
- runtime·throw("cas3");
- if(z != 4)
- runtime·throw("cas4");
-
- k = (byte*)0xfedcb123;
- if(sizeof(void*) == 8)
- k = (byte*)((uintptr)k<<10);
- if(runtime·casp((void**)&k, nil, nil))
- runtime·throw("casp1");
- k1 = k+1;
- if(!runtime·casp((void**)&k, k, k1))
- runtime·throw("casp2");
- if(k != k1)
- runtime·throw("casp3");
-
- *(uint64*)&j = ~0ULL;
- if(j == j)
- runtime·throw("float64nan");
- if(!(j != j))
- runtime·throw("float64nan1");
-
- *(uint64*)&j1 = ~1ULL;
- if(j == j1)
- runtime·throw("float64nan2");
- if(!(j != j1))
- runtime·throw("float64nan3");
-
- *(uint32*)&i = ~0UL;
- if(i == i)
- runtime·throw("float32nan");
- if(!(i != i))
- runtime·throw("float32nan1");
-
- *(uint32*)&i1 = ~1UL;
- if(i == i1)
- runtime·throw("float32nan2");
- if(!(i != i1))
- runtime·throw("float32nan3");
-
- TestAtomic64();
-
- if(FixedStack != runtime·round2(FixedStack))
- runtime·throw("FixedStack is not power-of-2");
-}
-
-#pragma dataflag NOPTR
-DebugVars runtime·debug;
-
-typedef struct DbgVar DbgVar;
-struct DbgVar
-{
- int8* name;
- int32* value;
-};
-
-// Do we report invalid pointers found during stack or heap scans?
-int32 runtime·invalidptr = 1;
-
-#pragma dataflag NOPTR /* dbgvar has no heap pointers */
-static DbgVar dbgvar[] = {
- {"allocfreetrace", &runtime·debug.allocfreetrace},
- {"invalidptr", &runtime·invalidptr},
- {"efence", &runtime·debug.efence},
- {"gctrace", &runtime·debug.gctrace},
- {"gcdead", &runtime·debug.gcdead},
- {"scheddetail", &runtime·debug.scheddetail},
- {"schedtrace", &runtime·debug.schedtrace},
- {"scavenge", &runtime·debug.scavenge},
-};
-
-void
-runtime·parsedebugvars(void)
-{
- byte *p;
- intgo i, n;
-
- p = runtime·getenv("GODEBUG");
- if(p != nil){
- for(;;) {
- for(i=0; i<nelem(dbgvar); i++) {
- n = runtime·findnull((byte*)dbgvar[i].name);
- if(runtime·mcmp(p, (byte*)dbgvar[i].name, n) == 0 && p[n] == '=')
- *dbgvar[i].value = runtime·atoi(p+n+1);
- }
- p = runtime·strstr(p, (byte*)",");
- if(p == nil)
- break;
- p++;
- }
- }
-
- p = runtime·getenv("GOTRACEBACK");
- if(p == nil)
- p = (byte*)"";
- if(p[0] == '\0')
- traceback_cache = 1<<1;
- else if(runtime·strcmp(p, (byte*)"crash") == 0)
- traceback_cache = (2<<1) | 1;
- else
- traceback_cache = runtime·atoi(p)<<1;
-}
-
-// Poor mans 64-bit division.
-// This is a very special function, do not use it if you are not sure what you are doing.
-// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
-// Handles overflow in a time-specific manner.
-#pragma textflag NOSPLIT
-int32
-runtime·timediv(int64 v, int32 div, int32 *rem)
-{
- int32 res, bit;
-
- res = 0;
- for(bit = 30; bit >= 0; bit--) {
- if(v >= ((int64)div<<bit)) {
- v = v - ((int64)div<<bit);
- res += 1<<bit;
- }
- }
- if(v >= (int64)div) {
- if(rem != nil)
- *rem = 0;
- return 0x7fffffff;
- }
- if(rem != nil)
- *rem = v;
- return res;
-}
-
-// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.
-
-#pragma textflag NOSPLIT
-G*
-runtime·getg(void)
-{
- return g;
-}
-
-#pragma textflag NOSPLIT
-M*
-runtime·acquirem(void)
-{
- g->m->locks++;
- return g->m;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·releasem(M *mp)
-{
- mp->locks--;
- if(mp->locks == 0 && g->preempt) {
- // restore the preemption request in case we've cleared it in newstack
- g->stackguard0 = StackPreempt;
- }
-}
-
-#pragma textflag NOSPLIT
-MCache*
-runtime·gomcache(void)
-{
- return g->m->mcache;
-}
-
-#pragma textflag NOSPLIT
-Slice
-reflect·typelinks(void)
-{
- extern Type *runtime·typelink[], *runtime·etypelink[];
- Slice ret;
-
- ret.array = (byte*)runtime·typelink;
- ret.len = runtime·etypelink - runtime·typelink;
- ret.cap = ret.len;
- return ret;
-}
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
deleted file mode 100644
index 177a1287e..000000000
--- a/src/runtime/runtime.h
+++ /dev/null
@@ -1,1132 +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.
-
-/*
- * basic types
- */
-typedef signed char int8;
-typedef unsigned char uint8;
-typedef signed short int16;
-typedef unsigned short uint16;
-typedef signed int int32;
-typedef unsigned int uint32;
-typedef signed long long int int64;
-typedef unsigned long long int uint64;
-typedef float float32;
-typedef double float64;
-
-#ifdef _64BIT
-typedef uint64 uintptr;
-typedef int64 intptr;
-typedef int64 intgo; // Go's int
-typedef uint64 uintgo; // Go's uint
-#else
-typedef uint32 uintptr;
-typedef int32 intptr;
-typedef int32 intgo; // Go's int
-typedef uint32 uintgo; // Go's uint
-#endif
-
-#ifdef _64BITREG
-typedef uint64 uintreg;
-#else
-typedef uint32 uintreg;
-#endif
-
-/*
- * get rid of C types
- * the / / / forces a syntax error immediately,
- * which will show "last name: XXunsigned".
- */
-#define unsigned XXunsigned / / /
-#define signed XXsigned / / /
-#define char XXchar / / /
-#define short XXshort / / /
-#define int XXint / / /
-#define long XXlong / / /
-#define float XXfloat / / /
-#define double XXdouble / / /
-
-/*
- * defined types
- */
-typedef uint8 bool;
-typedef uint8 byte;
-typedef struct Func Func;
-typedef struct G G;
-typedef struct Gobuf Gobuf;
-typedef struct SudoG SudoG;
-typedef struct Mutex Mutex;
-typedef struct M M;
-typedef struct P P;
-typedef struct SchedT SchedT;
-typedef struct Note Note;
-typedef struct Slice Slice;
-typedef struct String String;
-typedef struct FuncVal FuncVal;
-typedef struct SigTab SigTab;
-typedef struct MCache MCache;
-typedef struct FixAlloc FixAlloc;
-typedef struct Iface Iface;
-typedef struct Itab Itab;
-typedef struct InterfaceType InterfaceType;
-typedef struct Eface Eface;
-typedef struct Type Type;
-typedef struct PtrType PtrType;
-typedef struct ChanType ChanType;
-typedef struct MapType MapType;
-typedef struct Defer Defer;
-typedef struct Panic Panic;
-typedef struct Hmap Hmap;
-typedef struct Hiter Hiter;
-typedef struct Hchan Hchan;
-typedef struct Complex64 Complex64;
-typedef struct Complex128 Complex128;
-typedef struct LibCall LibCall;
-typedef struct WinCallbackContext WinCallbackContext;
-typedef struct GCStats GCStats;
-typedef struct LFNode LFNode;
-typedef struct ParFor ParFor;
-typedef struct ParForThread ParForThread;
-typedef struct CgoMal CgoMal;
-typedef struct PollDesc PollDesc;
-typedef struct DebugVars DebugVars;
-typedef struct ForceGCState ForceGCState;
-typedef struct Stack Stack;
-
-/*
- * Per-CPU declaration.
- *
- * "extern register" is a special storage class implemented by 6c, 8c, etc.
- * On the ARM, it is an actual register; elsewhere it is a slot in thread-
- * local storage indexed by a pseudo-register TLS. See zasmhdr in
- * src/cmd/dist/buildruntime.c for details, and be aware that the linker may
- * make further OS-specific changes to the compiler's output. For example,
- * 6l/linux rewrites 0(TLS) as -8(FS).
- *
- * Every C file linked into a Go program must include runtime.h so that the
- * C compiler (6c, 8c, etc.) knows to avoid other uses of these dedicated
- * registers. The Go compiler (6g, 8g, etc.) knows to avoid them.
- */
-extern register G* g;
-
-/*
- * defined constants
- */
-enum
-{
- // G status
- //
- // If you add to this list, add to the list
- // of "okay during garbage collection" status
- // in mgc0.c too.
- Gidle, // 0
- Grunnable, // 1 runnable and on a run queue
- Grunning, // 2
- Gsyscall, // 3
- Gwaiting, // 4
- Gmoribund_unused, // 5 currently unused, but hardcoded in gdb scripts
- Gdead, // 6
- Genqueue, // 7 Only the Gscanenqueue is used.
- Gcopystack, // 8 in this state when newstack is moving the stack
- // the following encode that the GC is scanning the stack and what to do when it is done
- Gscan = 0x1000, // atomicstatus&~Gscan = the non-scan state,
- // Gscanidle = Gscan + Gidle, // Not used. Gidle only used with newly malloced gs
- Gscanrunnable = Gscan + Grunnable, // 0x1001 When scanning complets make Grunnable (it is already on run queue)
- Gscanrunning = Gscan + Grunning, // 0x1002 Used to tell preemption newstack routine to scan preempted stack.
- Gscansyscall = Gscan + Gsyscall, // 0x1003 When scanning completes make is Gsyscall
- Gscanwaiting = Gscan + Gwaiting, // 0x1004 When scanning completes make it Gwaiting
- // Gscanmoribund_unused, // not possible
- // Gscandead, // not possible
- Gscanenqueue = Gscan + Genqueue, // When scanning completes make it Grunnable and put on runqueue
-};
-enum
-{
- // P status
- Pidle,
- Prunning,
- Psyscall,
- Pgcstop,
- Pdead,
-};
-enum
-{
- true = 1,
- false = 0,
-};
-enum
-{
- PtrSize = sizeof(void*),
-};
-/*
- * structures
- */
-struct Mutex
-{
- // Futex-based impl treats it as uint32 key,
- // while sema-based impl as M* waitm.
- // Used to be a union, but unions break precise GC.
- uintptr key;
-};
-struct Note
-{
- // Futex-based impl treats it as uint32 key,
- // while sema-based impl as M* waitm.
- // Used to be a union, but unions break precise GC.
- uintptr key;
-};
-struct String
-{
- byte* str;
- intgo len;
-};
-struct FuncVal
-{
- void (*fn)(void);
- // variable-size, fn-specific data here
-};
-struct Iface
-{
- Itab* tab;
- void* data;
-};
-struct Eface
-{
- Type* type;
- void* data;
-};
-struct Complex64
-{
- float32 real;
- float32 imag;
-};
-struct Complex128
-{
- float64 real;
- float64 imag;
-};
-
-struct Slice
-{ // must not move anything
- byte* array; // actual data
- uintgo len; // number of elements
- uintgo cap; // allocated number of elements
-};
-struct Gobuf
-{
- // The offsets of sp, pc, and g are known to (hard-coded in) libmach.
- uintptr sp;
- uintptr pc;
- G* g;
- void* ctxt; // this has to be a pointer so that GC scans it
- uintreg ret;
- uintptr lr;
-};
-// Known to compiler.
-// Changes here must also be made in src/cmd/gc/select.c's selecttype.
-struct SudoG
-{
- G* g;
- uint32* selectdone;
- SudoG* next;
- SudoG* prev;
- void* elem; // data element
- int64 releasetime;
- int32 nrelease; // -1 for acquire
- SudoG* waitlink; // G.waiting list
-};
-struct GCStats
-{
- // the struct must consist of only uint64's,
- // because it is casted to uint64[].
- uint64 nhandoff;
- uint64 nhandoffcnt;
- uint64 nprocyield;
- uint64 nosyield;
- uint64 nsleep;
-};
-
-struct LibCall
-{
- uintptr fn;
- uintptr n; // number of parameters
- uintptr args; // parameters
- uintptr r1; // return values
- uintptr r2;
- uintptr err; // error number
-};
-
-// describes how to handle callback
-struct WinCallbackContext
-{
- void* gobody; // Go function to call
- uintptr argsize; // callback arguments size (in bytes)
- uintptr restorestack; // adjust stack on return by (in bytes) (386 only)
- bool cleanstack;
-};
-
-// Stack describes a Go execution stack.
-// The bounds of the stack are exactly [lo, hi),
-// with no implicit data structures on either side.
-struct Stack
-{
- uintptr lo;
- uintptr hi;
-};
-
-struct G
-{
- // Stack parameters.
- // stack describes the actual stack memory: [stack.lo, stack.hi).
- // stackguard0 is the stack pointer compared in the Go stack growth prologue.
- // It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption.
- // stackguard1 is the stack pointer compared in the C stack growth prologue.
- // It is stack.lo+StackGuard on g0 and gsignal stacks.
- // It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash).
- Stack stack; // offset known to runtime/cgo
- uintptr stackguard0; // offset known to liblink
- uintptr stackguard1; // offset known to liblink
-
- Panic* panic; // innermost panic - offset known to liblink
- Defer* defer; // innermost defer
- Gobuf sched;
- uintptr syscallsp; // if status==Gsyscall, syscallsp = sched.sp to use during gc
- uintptr syscallpc; // if status==Gsyscall, syscallpc = sched.pc to use during gc
- void* param; // passed parameter on wakeup
- uint32 atomicstatus;
- int64 goid;
- int64 waitsince; // approx time when the G become blocked
- String waitreason; // if status==Gwaiting
- G* schedlink;
- bool issystem; // do not output in stack dump, ignore in deadlock detector
- bool preempt; // preemption signal, duplicates stackguard0 = StackPreempt
- bool paniconfault; // panic (instead of crash) on unexpected fault address
- bool preemptscan; // preempted g does scan for GC
- bool gcworkdone; // debug: cleared at begining of gc work phase cycle, set by gcphasework, tested at end of cycle
- bool throwsplit; // must not split stack
- int8 raceignore; // ignore race detection events
- M* m; // for debuggers, but offset not hard-coded
- M* lockedm;
- int32 sig;
- Slice writebuf;
- uintptr sigcode0;
- uintptr sigcode1;
- uintptr sigpc;
- uintptr gopc; // pc of go statement that created this goroutine
- uintptr racectx;
- SudoG* waiting; // sudog structures this G is waiting on (that have a valid elem ptr)
- uintptr end[];
-};
-
-struct M
-{
- G* g0; // goroutine with scheduling stack
- Gobuf morebuf; // gobuf arg to morestack
-
- // Fields not known to debuggers.
- uint64 procid; // for debuggers, but offset not hard-coded
- G* gsignal; // signal-handling G
- uintptr tls[4]; // thread-local storage (for x86 extern register)
- void (*mstartfn)(void);
- G* curg; // current running goroutine
- G* caughtsig; // goroutine running during fatal signal
- P* p; // attached P for executing Go code (nil if not executing Go code)
- P* nextp;
- int32 id;
- int32 mallocing;
- int32 throwing;
- int32 gcing;
- int32 locks;
- int32 softfloat;
- int32 dying;
- int32 profilehz;
- int32 helpgc;
- bool spinning; // M is out of work and is actively looking for work
- bool blocked; // M is blocked on a Note
- uint32 fastrand;
- uint64 ncgocall; // number of cgo calls in total
- int32 ncgo; // number of cgo calls currently in progress
- CgoMal* cgomal;
- Note park;
- M* alllink; // on allm
- M* schedlink;
- uint32 machport; // Return address for Mach IPC (OS X)
- MCache* mcache;
- G* lockedg;
- uintptr createstack[32];// Stack that created this thread.
- uint32 freglo[16]; // D[i] lsb and F[i]
- uint32 freghi[16]; // D[i] msb and F[i+16]
- uint32 fflag; // floating point compare flags
- uint32 locked; // tracking for LockOSThread
- M* nextwaitm; // next M waiting for lock
- uintptr waitsema; // semaphore for parking on locks
- uint32 waitsemacount;
- uint32 waitsemalock;
- GCStats gcstats;
- bool needextram;
- uint8 traceback;
- bool (*waitunlockf)(G*, void*);
- void* waitlock;
- uintptr scalararg[4]; // scalar argument/return for mcall
- void* ptrarg[4]; // pointer argument/return for mcall
-#ifdef GOOS_windows
- uintptr thread; // thread handle
- // these are here because they are too large to be on the stack
- // of low-level NOSPLIT functions.
- LibCall libcall;
- uintptr libcallpc; // for cpu profiler
- uintptr libcallsp;
- G* libcallg;
-#endif
-#ifdef GOOS_solaris
- int32* perrno; // pointer to TLS errno
- // these are here because they are too large to be on the stack
- // of low-level NOSPLIT functions.
- LibCall libcall;
- struct MTs {
- int64 tv_sec;
- int64 tv_nsec;
- } ts;
- struct MScratch {
- uintptr v[6];
- } scratch;
-#endif
-#ifdef GOOS_plan9
- int8* notesig;
- byte* errstr;
-#endif
- uintptr end[];
-};
-
-struct P
-{
- Mutex lock;
-
- int32 id;
- uint32 status; // one of Pidle/Prunning/...
- P* link;
- uint32 schedtick; // incremented on every scheduler call
- uint32 syscalltick; // incremented on every system call
- M* m; // back-link to associated M (nil if idle)
- MCache* mcache;
- Defer* deferpool[5]; // pool of available Defer structs of different sizes (see panic.c)
-
- // Cache of goroutine ids, amortizes accesses to runtime·sched.goidgen.
- uint64 goidcache;
- uint64 goidcacheend;
-
- // Queue of runnable goroutines.
- uint32 runqhead;
- uint32 runqtail;
- G* runq[256];
-
- // Available G's (status == Gdead)
- G* gfree;
- int32 gfreecnt;
-
- byte pad[64];
-};
-
-enum {
- // The max value of GOMAXPROCS.
- // There are no fundamental restrictions on the value.
- MaxGomaxprocs = 1<<8,
-};
-
-struct SchedT
-{
- Mutex lock;
-
- uint64 goidgen;
-
- M* midle; // idle m's waiting for work
- int32 nmidle; // number of idle m's waiting for work
- int32 nmidlelocked; // number of locked m's waiting for work
- int32 mcount; // number of m's that have been created
- int32 maxmcount; // maximum number of m's allowed (or die)
-
- P* pidle; // idle P's
- uint32 npidle;
- uint32 nmspinning;
-
- // Global runnable queue.
- G* runqhead;
- G* runqtail;
- int32 runqsize;
-
- // Global cache of dead G's.
- Mutex gflock;
- G* gfree;
- int32 ngfree;
-
- uint32 gcwaiting; // gc is waiting to run
- int32 stopwait;
- Note stopnote;
- uint32 sysmonwait;
- Note sysmonnote;
- uint64 lastpoll;
-
- int32 profilehz; // cpu profiling rate
-};
-
-// The m->locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread.
-// The low bit (LockExternal) is a boolean reporting whether any LockOSThread call is active.
-// External locks are not recursive; a second lock is silently ignored.
-// The upper bits of m->lockedcount record the nesting depth of calls to lockOSThread
-// (counting up by LockInternal), popped by unlockOSThread (counting down by LockInternal).
-// Internal locks can be recursive. For instance, a lock for cgo can occur while the main
-// goroutine is holding the lock during the initialization phase.
-enum
-{
- LockExternal = 1,
- LockInternal = 2,
-};
-
-struct SigTab
-{
- int32 flags;
- int8 *name;
-};
-enum
-{
- SigNotify = 1<<0, // let signal.Notify have signal, even if from kernel
- SigKill = 1<<1, // if signal.Notify doesn't take it, exit quietly
- SigThrow = 1<<2, // if signal.Notify doesn't take it, exit loudly
- SigPanic = 1<<3, // if the signal is from the kernel, panic
- SigDefault = 1<<4, // if the signal isn't explicitly requested, don't monitor it
- SigHandling = 1<<5, // our signal handler is registered
- SigIgnored = 1<<6, // the signal was ignored before we registered for it
- SigGoExit = 1<<7, // cause all runtime procs to exit (only used on Plan 9).
-};
-
-// Layout of in-memory per-function information prepared by linker
-// See http://golang.org/s/go12symtab.
-// Keep in sync with linker and with ../../libmach/sym.c
-// and with package debug/gosym and with symtab.go in package runtime.
-struct Func
-{
- uintptr entry; // start pc
- int32 nameoff;// function name
-
- int32 args; // in/out args size
- int32 frame; // legacy frame size; use pcsp if possible
-
- int32 pcsp;
- int32 pcfile;
- int32 pcln;
- int32 npcdata;
- int32 nfuncdata;
-};
-
-// layout of Itab known to compilers
-// allocated in non-garbage-collected memory
-struct Itab
-{
- InterfaceType* inter;
- Type* type;
- Itab* link;
- int32 bad;
- int32 unused;
- void (*fun[])(void);
-};
-
-#ifdef GOOS_nacl
-enum {
- NaCl = 1,
-};
-#else
-enum {
- NaCl = 0,
-};
-#endif
-
-#ifdef GOOS_windows
-enum {
- Windows = 1
-};
-#else
-enum {
- Windows = 0
-};
-#endif
-#ifdef GOOS_solaris
-enum {
- Solaris = 1
-};
-#else
-enum {
- Solaris = 0
-};
-#endif
-#ifdef GOOS_plan9
-enum {
- Plan9 = 1
-};
-#else
-enum {
- Plan9 = 0
-};
-#endif
-
-// Lock-free stack node.
-struct LFNode
-{
- LFNode *next;
- uintptr pushcnt;
-};
-
-// Parallel for descriptor.
-struct ParFor
-{
- void (*body)(ParFor*, uint32); // executed for each element
- uint32 done; // number of idle threads
- uint32 nthr; // total number of threads
- uint32 nthrmax; // maximum number of threads
- uint32 thrseq; // thread id sequencer
- uint32 cnt; // iteration space [0, cnt)
- void *ctx; // arbitrary user context
- bool wait; // if true, wait while all threads finish processing,
- // otherwise parfor may return while other threads are still working
- ParForThread *thr; // array of thread descriptors
- uint32 pad; // to align ParForThread.pos for 64-bit atomic operations
- // stats
- uint64 nsteal;
- uint64 nstealcnt;
- uint64 nprocyield;
- uint64 nosyield;
- uint64 nsleep;
-};
-
-// Track memory allocated by code not written in Go during a cgo call,
-// so that the garbage collector can see them.
-struct CgoMal
-{
- CgoMal *next;
- void *alloc;
-};
-
-// Holds variables parsed from GODEBUG env var.
-struct DebugVars
-{
- int32 allocfreetrace;
- int32 efence;
- int32 gctrace;
- int32 gcdead;
- int32 scheddetail;
- int32 schedtrace;
- int32 scavenge;
-};
-
-// Indicates to write barrier and sychronization task to preform.
-enum
-{ // Synchronization Write barrier
- GCoff, // stop and start nop
- GCquiesce, // stop and start nop
- GCstw, // stop the ps nop
- GCmark, // scan the stacks and start no white to black
- GCsweep, // stop and start nop
-};
-
-struct ForceGCState
-{
- Mutex lock;
- G* g;
- uint32 idle;
-};
-
-extern uint32 runtime·gcphase;
-
-/*
- * defined macros
- * you need super-gopher-guru privilege
- * to add this list.
- */
-#define nelem(x) (sizeof(x)/sizeof((x)[0]))
-#define nil ((void*)0)
-#define offsetof(s,m) (uint32)(&(((s*)0)->m))
-#define ROUND(x, n) (((x)+(n)-1)&~(uintptr)((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
-
-/*
- * known to compiler
- */
-enum {
- Structrnd = sizeof(uintreg),
-};
-
-byte* runtime·startup_random_data;
-uint32 runtime·startup_random_data_len;
-
-int32 runtime·invalidptr;
-
-enum {
- // hashinit wants this many random bytes
- HashRandomBytes = 32
-};
-
-uint32 runtime·readgstatus(G*);
-void runtime·casgstatus(G*, uint32, uint32);
-void runtime·casgstatus(G*, uint32, uint32);
-uint32 runtime·casgcopystack(G*);
-void runtime·quiesce(G*);
-bool runtime·stopg(G*);
-void runtime·restartg(G*);
-void runtime·gcphasework(G*);
-
-/*
- * deferred subroutine calls
- */
-struct Defer
-{
- int32 siz;
- bool started;
- uintptr argp; // where args were copied from
- uintptr pc;
- FuncVal* fn;
- Panic* panic; // panic that is running defer
- Defer* link;
-};
-
-// argp used in Defer structs when there is no argp.
-#define NoArgs ((uintptr)-1)
-
-/*
- * panics
- */
-struct Panic
-{
- void* argp; // pointer to arguments of deferred call run during panic; cannot move - known to liblink
- Eface arg; // argument to panic
- Panic* link; // link to earlier panic
- bool recovered; // whether this panic is over
- bool aborted; // the panic was aborted
-};
-
-/*
- * stack traces
- */
-typedef struct Stkframe Stkframe;
-typedef struct BitVector BitVector;
-struct Stkframe
-{
- Func* fn; // function being run
- uintptr pc; // program counter within fn
- uintptr continpc; // program counter where execution can continue, or 0 if not
- uintptr lr; // program counter at caller aka link register
- uintptr sp; // stack pointer at pc
- uintptr fp; // stack pointer at caller aka frame pointer
- uintptr varp; // top of local variables
- uintptr argp; // pointer to function arguments
- uintptr arglen; // number of bytes at argp
- BitVector* argmap; // force use of this argmap
-};
-
-enum
-{
- TraceRuntimeFrames = 1<<0, // include frames for internal runtime functions.
- TraceTrap = 1<<1, // the initial PC, SP are from a trap, not a return PC from a call
-};
-intgo runtime·gentraceback(uintptr, uintptr, uintptr, G*, intgo, uintptr*, intgo, bool(**)(Stkframe*, void*), void*, uintgo);
-void runtime·tracebackdefers(G*, bool(**)(Stkframe*, void*), void*);
-void runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
-void runtime·tracebacktrap(uintptr pc, uintptr sp, uintptr lr, G* gp);
-void runtime·tracebackothers(G*);
-bool runtime·haszeroargs(uintptr pc);
-bool runtime·topofstack(Func*);
-enum
-{
- // The maximum number of frames we print for a traceback
- TracebackMaxFrames = 100,
-};
-
-/*
- * external data
- */
-extern String runtime·emptystring;
-extern G** runtime·allg;
-extern Slice runtime·allgs; // []*G
-extern uintptr runtime·allglen;
-extern G* runtime·lastg;
-extern M* runtime·allm;
-extern P* runtime·allp[MaxGomaxprocs+1];
-extern int32 runtime·gomaxprocs;
-extern uint32 runtime·needextram;
-extern uint32 runtime·panicking;
-extern int8* runtime·goos;
-extern int32 runtime·ncpu;
-extern bool runtime·iscgo;
-extern void (*runtime·sysargs)(int32, uint8**);
-extern uintptr runtime·maxstring;
-extern uint32 runtime·cpuid_ecx;
-extern uint32 runtime·cpuid_edx;
-extern DebugVars runtime·debug;
-extern uintptr runtime·maxstacksize;
-extern Note runtime·signote;
-extern ForceGCState runtime·forcegc;
-extern SchedT runtime·sched;
-extern int32 runtime·newprocs;
-
-/*
- * common functions and data
- */
-int32 runtime·strcmp(byte*, byte*);
-int32 runtime·strncmp(byte*, byte*, uintptr);
-byte* runtime·strstr(byte*, byte*);
-intgo runtime·findnull(byte*);
-intgo runtime·findnullw(uint16*);
-void runtime·dump(byte*, int32);
-int32 runtime·runetochar(byte*, int32);
-int32 runtime·charntorune(int32*, uint8*, int32);
-
-
-/*
- * This macro is used when writing C functions
- * called as if they were Go functions.
- * Passed the address of a result before a return statement,
- * it makes sure the result has been flushed to memory
- * before the return.
- *
- * It is difficult to write such functions portably, because
- * of the varying requirements on the alignment of the
- * first output value. Almost all code should write such
- * functions in .goc files, where goc2c (part of cmd/dist)
- * can arrange the correct alignment for the target system.
- * Goc2c also takes care of conveying to the garbage collector
- * which parts of the argument list are inputs vs outputs.
- *
- * Therefore, do NOT use this macro if at all possible.
- */
-#define FLUSH(x) USED(x)
-
-/*
- * GoOutput is a type with the same alignment requirements as the
- * initial output argument from a Go function. Only for use in cases
- * where using goc2c is not possible. See comment on FLUSH above.
- */
-typedef uint64 GoOutput;
-
-void runtime·gogo(Gobuf*);
-void runtime·gostartcall(Gobuf*, void(*)(void), void*);
-void runtime·gostartcallfn(Gobuf*, FuncVal*);
-void runtime·gosave(Gobuf*);
-void runtime·goargs(void);
-void runtime·goenvs(void);
-void runtime·goenvs_unix(void);
-void* runtime·getu(void);
-void runtime·throw(int8*);
-bool runtime·canpanic(G*);
-void runtime·prints(int8*);
-void runtime·printf(int8*, ...);
-void runtime·snprintf(byte*, int32, int8*, ...);
-byte* runtime·mchr(byte*, byte, byte*);
-int32 runtime·mcmp(byte*, byte*, uintptr);
-void runtime·memmove(void*, void*, uintptr);
-String runtime·catstring(String, String);
-String runtime·gostring(byte*);
-Slice runtime·makeStringSlice(intgo);
-String runtime·gostringn(byte*, intgo);
-Slice runtime·gobytes(byte*, intgo);
-String runtime·gostringnocopy(byte*);
-String runtime·gostringw(uint16*);
-void runtime·initsig(void);
-void runtime·sigenable(uint32 sig);
-void runtime·sigdisable(uint32 sig);
-int32 runtime·gotraceback(bool *crash);
-void runtime·goroutineheader(G*);
-int32 runtime·open(int8*, int32, int32);
-int32 runtime·read(int32, void*, int32);
-int32 runtime·write(uintptr, void*, int32); // use uintptr to accommodate windows.
-int32 runtime·close(int32);
-int32 runtime·mincore(void*, uintptr, byte*);
-void runtime·jmpdefer(FuncVal*, uintptr);
-void runtime·exit1(int32);
-void runtime·ready(G*);
-byte* runtime·getenv(int8*);
-int32 runtime·atoi(byte*);
-void runtime·newosproc(M *mp, void *stk);
-void runtime·mstart(void);
-G* runtime·malg(int32);
-void runtime·asminit(void);
-void runtime·mpreinit(M*);
-void runtime·minit(void);
-void runtime·unminit(void);
-void runtime·signalstack(byte*, int32);
-void runtime·tracebackinit(void);
-void runtime·symtabinit(void);
-Func* runtime·findfunc(uintptr);
-int32 runtime·funcline(Func*, uintptr, String*);
-int32 runtime·funcspdelta(Func*, uintptr);
-int8* runtime·funcname(Func*);
-int32 runtime·pcdatavalue(Func*, int32, uintptr);
-void runtime·stackinit(void);
-Stack runtime·stackalloc(uint32);
-void runtime·stackfree(Stack);
-void runtime·shrinkstack(G*);
-void runtime·shrinkfinish(void);
-MCache* runtime·allocmcache(void);
-void runtime·freemcache(MCache*);
-void runtime·mallocinit(void);
-void runtime·gcinit(void);
-void* runtime·mallocgc(uintptr size, Type* typ, uint32 flag);
-void runtime·runpanic(Panic*);
-uintptr runtime·getcallersp(void*);
-int32 runtime·mcount(void);
-int32 runtime·gcount(void);
-void runtime·mcall(void(**)(G*));
-void runtime·onM(void(**)(void));
-void runtime·onMsignal(void(**)(void));
-uint32 runtime·fastrand1(void);
-void runtime·rewindmorestack(Gobuf*);
-int32 runtime·timediv(int64, int32, int32*);
-int32 runtime·round2(int32 x); // round x up to a power of 2.
-
-// atomic operations
-bool runtime·cas(uint32*, uint32, uint32);
-bool runtime·cas64(uint64*, uint64, uint64);
-bool runtime·casp(void**, void*, void*);
-// Don't confuse with XADD x86 instruction,
-// this one is actually 'addx', that is, add-and-fetch.
-uint32 runtime·xadd(uint32 volatile*, int32);
-uint64 runtime·xadd64(uint64 volatile*, int64);
-uint32 runtime·xchg(uint32 volatile*, uint32);
-uint64 runtime·xchg64(uint64 volatile*, uint64);
-void* runtime·xchgp(void* volatile*, void*);
-uint32 runtime·atomicload(uint32 volatile*);
-void runtime·atomicstore(uint32 volatile*, uint32);
-void runtime·atomicstore64(uint64 volatile*, uint64);
-uint64 runtime·atomicload64(uint64 volatile*);
-void* runtime·atomicloadp(void* volatile*);
-uintptr runtime·atomicloaduintptr(uintptr volatile*);
-void runtime·atomicstorep(void* volatile*, void*);
-void runtime·atomicstoreuintptr(uintptr volatile*, uintptr);
-void runtime·atomicor8(byte volatile*, byte);
-
-void runtime·setg(G*);
-void runtime·newextram(void);
-void runtime·exit(int32);
-void runtime·breakpoint(void);
-void runtime·gosched_m(G*);
-void runtime·schedtrace(bool);
-void runtime·park(bool(*)(G*, void*), void*, String);
-void runtime·parkunlock(Mutex*, String);
-void runtime·tsleep(int64, String);
-M* runtime·newm(void);
-void runtime·goexit(void);
-void runtime·asmcgocall(void (*fn)(void*), void*);
-int32 runtime·asmcgocall_errno(void (*fn)(void*), void*);
-void runtime·entersyscall(void);
-void runtime·reentersyscall(uintptr, uintptr);
-void runtime·entersyscallblock(void);
-void runtime·exitsyscall(void);
-G* runtime·newproc1(FuncVal*, byte*, int32, int32, void*);
-bool runtime·sigsend(int32 sig);
-intgo runtime·callers(intgo, uintptr*, intgo);
-intgo runtime·gcallers(G*, intgo, uintptr*, intgo);
-int64 runtime·nanotime(void); // monotonic time
-int64 runtime·unixnanotime(void); // real time, can skip
-void runtime·dopanic(int32);
-void runtime·startpanic(void);
-void runtime·freezetheworld(void);
-void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp);
-void runtime·resetcpuprofiler(int32);
-void runtime·setcpuprofilerate(int32);
-void runtime·usleep(uint32);
-int64 runtime·cputicks(void);
-int64 runtime·tickspersecond(void);
-void runtime·blockevent(int64, intgo);
-G* runtime·netpoll(bool);
-void runtime·netpollready(G**, PollDesc*, int32);
-uintptr runtime·netpollfd(PollDesc*);
-void** runtime·netpolluser(PollDesc*);
-bool runtime·netpollclosing(PollDesc*);
-void runtime·netpolllock(PollDesc*);
-void runtime·netpollunlock(PollDesc*);
-void runtime·crash(void);
-void runtime·parsedebugvars(void);
-void* runtime·funcdata(Func*, int32);
-void runtime·setmaxthreads_m(void);
-G* runtime·timejump(void);
-void runtime·iterate_itabs(void (**callback)(Itab*));
-void runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*));
-
-#pragma varargck argpos runtime·printf 1
-#pragma varargck type "c" int32
-#pragma varargck type "d" int32
-#pragma varargck type "d" uint32
-#pragma varargck type "D" int64
-#pragma varargck type "D" uint64
-#pragma varargck type "x" int32
-#pragma varargck type "x" uint32
-#pragma varargck type "X" int64
-#pragma varargck type "X" uint64
-#pragma varargck type "p" void*
-#pragma varargck type "p" uintptr
-#pragma varargck type "s" int8*
-#pragma varargck type "s" uint8*
-#pragma varargck type "S" String
-
-void runtime·stoptheworld(void);
-void runtime·starttheworld(void);
-extern uint32 runtime·worldsema;
-
-/*
- * mutual exclusion locks. in the uncontended case,
- * as fast as spin locks (just a few user-level instructions),
- * but on the contention path they sleep in the kernel.
- * a zeroed Mutex is unlocked (no need to initialize each lock).
- */
-void runtime·lock(Mutex*);
-void runtime·unlock(Mutex*);
-
-/*
- * sleep and wakeup on one-time events.
- * before any calls to notesleep or notewakeup,
- * must call noteclear to initialize the Note.
- * then, exactly one thread can call notesleep
- * and exactly one thread can call notewakeup (once).
- * once notewakeup has been called, the notesleep
- * will return. future notesleep will return immediately.
- * subsequent noteclear must be called only after
- * previous notesleep has returned, e.g. it's disallowed
- * to call noteclear straight after notewakeup.
- *
- * notetsleep is like notesleep but wakes up after
- * a given number of nanoseconds even if the event
- * has not yet happened. if a goroutine uses notetsleep to
- * wake up early, it must wait to call noteclear until it
- * can be sure that no other goroutine is calling
- * notewakeup.
- *
- * notesleep/notetsleep are generally called on g0,
- * notetsleepg is similar to notetsleep but is called on user g.
- */
-void runtime·noteclear(Note*);
-void runtime·notesleep(Note*);
-void runtime·notewakeup(Note*);
-bool runtime·notetsleep(Note*, int64); // false - timeout
-bool runtime·notetsleepg(Note*, int64); // false - timeout
-
-/*
- * low-level synchronization for implementing the above
- */
-uintptr runtime·semacreate(void);
-int32 runtime·semasleep(int64);
-void runtime·semawakeup(M*);
-// or
-void runtime·futexsleep(uint32*, uint32, int64);
-void runtime·futexwakeup(uint32*, uint32);
-
-/*
- * Mutex-free stack.
- * Initialize uint64 head to 0, compare with 0 to test for emptiness.
- * The stack does not keep pointers to nodes,
- * so they can be garbage collected if there are no other pointers to nodes.
- */
-void runtime·lfstackpush(uint64 *head, LFNode *node);
-LFNode* runtime·lfstackpop(uint64 *head);
-
-/*
- * 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.
- */
-ParFor* runtime·parforalloc(uint32 nthrmax);
-void runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32));
-void runtime·parfordo(ParFor *desc);
-void runtime·parforiters(ParFor*, uintptr, uintptr*, uintptr*);
-
-/*
- * low level C-called
- */
-// 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.
-uint8* runtime·mmap(byte*, uintptr, int32, int32, int32, uint32);
-void runtime·munmap(byte*, uintptr);
-void runtime·madvise(byte*, uintptr, int32);
-void runtime·memclr(byte*, uintptr);
-void runtime·setcallerpc(void*, void*);
-void* runtime·getcallerpc(void*);
-void runtime·printbool(bool);
-void runtime·printbyte(int8);
-void runtime·printfloat(float64);
-void runtime·printint(int64);
-void runtime·printiface(Iface);
-void runtime·printeface(Eface);
-void runtime·printstring(String);
-void runtime·printpc(void*);
-void runtime·printpointer(void*);
-void runtime·printuint(uint64);
-void runtime·printhex(uint64);
-void runtime·printslice(Slice);
-void runtime·printcomplex(Complex128);
-
-/*
- * runtime go-called
- */
-void runtime·gopanic(Eface);
-void runtime·panicindex(void);
-void runtime·panicslice(void);
-void runtime·panicdivide(void);
-
-/*
- * runtime c-called (but written in Go)
- */
-void runtime·printany(Eface);
-void runtime·newTypeAssertionError(String*, String*, String*, String*, Eface*);
-void runtime·fadd64c(uint64, uint64, uint64*);
-void runtime·fsub64c(uint64, uint64, uint64*);
-void runtime·fmul64c(uint64, uint64, uint64*);
-void runtime·fdiv64c(uint64, uint64, uint64*);
-void runtime·fneg64c(uint64, uint64*);
-void runtime·f32to64c(uint32, uint64*);
-void runtime·f64to32c(uint64, uint32*);
-void runtime·fcmp64c(uint64, uint64, int32*, bool*);
-void runtime·fintto64c(int64, uint64*);
-void runtime·f64tointc(uint64, int64*, bool*);
-
-/*
- * wrapped for go users
- */
-float64 runtime·Inf(int32 sign);
-float64 runtime·NaN(void);
-float32 runtime·float32frombits(uint32 i);
-uint32 runtime·float32tobits(float32 f);
-float64 runtime·float64frombits(uint64 i);
-uint64 runtime·float64tobits(float64 f);
-float64 runtime·frexp(float64 d, int32 *ep);
-bool runtime·isInf(float64 f, int32 sign);
-bool runtime·isNaN(float64 f);
-float64 runtime·ldexp(float64 d, int32 e);
-float64 runtime·modf(float64 d, float64 *ip);
-void runtime·semacquire(uint32*, bool);
-void runtime·semrelease(uint32*);
-int32 runtime·gomaxprocsfunc(int32 n);
-void runtime·procyield(uint32);
-void runtime·osyield(void);
-void runtime·lockOSThread(void);
-void runtime·unlockOSThread(void);
-
-bool runtime·showframe(Func*, G*);
-void runtime·printcreatedby(G*);
-
-void runtime·ifaceE2I(InterfaceType*, Eface, Iface*);
-bool runtime·ifaceE2I2(InterfaceType*, Eface, Iface*);
-uintptr runtime·memlimit(void);
-
-// float.c
-extern float64 runtime·nan;
-extern float64 runtime·posinf;
-extern float64 runtime·neginf;
-extern uint64 ·nan;
-extern uint64 ·posinf;
-extern uint64 ·neginf;
-#define ISNAN(f) ((f) != (f))
-
-enum
-{
- UseSpanType = 1,
-};
diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go
new file mode 100644
index 000000000..15dea01a3
--- /dev/null
+++ b/src/runtime/runtime1.go
@@ -0,0 +1,417 @@
+// 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 runtime
+
+import "unsafe"
+
+// Keep a cached value to make gotraceback fast,
+// since we call it on every call to gentraceback.
+// The cached value is a uint32 in which the low bit
+// is the "crash" setting and the top 31 bits are the
+// gotraceback value.
+var traceback_cache uint32 = 2 << 1
+
+// The GOTRACEBACK environment variable controls the
+// behavior of a Go program that is crashing and exiting.
+// GOTRACEBACK=0 suppress all tracebacks
+// GOTRACEBACK=1 default behavior - show tracebacks but exclude runtime frames
+// GOTRACEBACK=2 show tracebacks including runtime frames
+// GOTRACEBACK=crash show tracebacks including runtime frames, then crash (core dump etc)
+//go:nosplit
+func gotraceback(crash *bool) int32 {
+ _g_ := getg()
+ if crash != nil {
+ *crash = false
+ }
+ if _g_.m.traceback != 0 {
+ return int32(_g_.m.traceback)
+ }
+ if crash != nil {
+ *crash = traceback_cache&1 != 0
+ }
+ return int32(traceback_cache >> 1)
+}
+
+var (
+ argc int32
+ argv **byte
+)
+
+// nosplit for use in linux/386 startup linux_setup_vdso
+//go:nosplit
+func argv_index(argv **byte, i int32) *byte {
+ return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*ptrSize))
+}
+
+func args(c int32, v **byte) {
+ argc = c
+ argv = v
+ sysargs(c, v)
+}
+
+var (
+ // TODO: Retire in favor of GOOS== checks.
+ isplan9 int32
+ issolaris int32
+ iswindows int32
+)
+
+// Information about what cpu features are available.
+// Set on startup in asm_{x86/amd64}.s.
+var (
+//cpuid_ecx uint32
+//cpuid_edx uint32
+)
+
+func goargs() {
+ if GOOS == "windows" {
+ return
+ }
+
+ argslice = make([]string, argc)
+ for i := int32(0); i < argc; i++ {
+ argslice[i] = gostringnocopy(argv_index(argv, i))
+ }
+}
+
+func goenvs_unix() {
+ n := int32(0)
+ for argv_index(argv, argc+1+n) != nil {
+ n++
+ }
+
+ envs = make([]string, n)
+ for i := int32(0); i < n; i++ {
+ envs[i] = gostringnocopy(argv_index(argv, argc+1+i))
+ }
+}
+
+func environ() []string {
+ return envs
+}
+
+func testAtomic64() {
+ var z64, x64 uint64
+
+ z64 = 42
+ x64 = 0
+ // TODO: PREFETCH((unsafe.Pointer)(&z64))
+ if cas64(&z64, x64, 1) {
+ gothrow("cas64 failed")
+ }
+ if x64 != 0 {
+ gothrow("cas64 failed")
+ }
+ x64 = 42
+ if !cas64(&z64, x64, 1) {
+ gothrow("cas64 failed")
+ }
+ if x64 != 42 || z64 != 1 {
+ gothrow("cas64 failed")
+ }
+ if atomicload64(&z64) != 1 {
+ gothrow("load64 failed")
+ }
+ atomicstore64(&z64, (1<<40)+1)
+ if atomicload64(&z64) != (1<<40)+1 {
+ gothrow("store64 failed")
+ }
+ if xadd64(&z64, (1<<40)+1) != (2<<40)+2 {
+ gothrow("xadd64 failed")
+ }
+ if atomicload64(&z64) != (2<<40)+2 {
+ gothrow("xadd64 failed")
+ }
+ if xchg64(&z64, (3<<40)+3) != (2<<40)+2 {
+ gothrow("xchg64 failed")
+ }
+ if atomicload64(&z64) != (3<<40)+3 {
+ gothrow("xchg64 failed")
+ }
+}
+
+func check() {
+ var (
+ a int8
+ b uint8
+ c int16
+ d uint16
+ e int32
+ f uint32
+ g int64
+ h uint64
+ i, i1 float32
+ j, j1 float64
+ k, k1 unsafe.Pointer
+ l *uint16
+ m [4]byte
+ )
+ type x1t struct {
+ x uint8
+ }
+ type y1t struct {
+ x1 x1t
+ y uint8
+ }
+ var x1 x1t
+ var y1 y1t
+
+ if unsafe.Sizeof(a) != 1 {
+ gothrow("bad a")
+ }
+ if unsafe.Sizeof(b) != 1 {
+ gothrow("bad b")
+ }
+ if unsafe.Sizeof(c) != 2 {
+ gothrow("bad c")
+ }
+ if unsafe.Sizeof(d) != 2 {
+ gothrow("bad d")
+ }
+ if unsafe.Sizeof(e) != 4 {
+ gothrow("bad e")
+ }
+ if unsafe.Sizeof(f) != 4 {
+ gothrow("bad f")
+ }
+ if unsafe.Sizeof(g) != 8 {
+ gothrow("bad g")
+ }
+ if unsafe.Sizeof(h) != 8 {
+ gothrow("bad h")
+ }
+ if unsafe.Sizeof(i) != 4 {
+ gothrow("bad i")
+ }
+ if unsafe.Sizeof(j) != 8 {
+ gothrow("bad j")
+ }
+ if unsafe.Sizeof(k) != ptrSize {
+ gothrow("bad k")
+ }
+ if unsafe.Sizeof(l) != ptrSize {
+ gothrow("bad l")
+ }
+ if unsafe.Sizeof(x1) != 1 {
+ gothrow("bad unsafe.Sizeof x1")
+ }
+ if unsafe.Offsetof(y1.y) != 1 {
+ gothrow("bad offsetof y1.y")
+ }
+ if unsafe.Sizeof(y1) != 2 {
+ gothrow("bad unsafe.Sizeof y1")
+ }
+
+ if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 {
+ gothrow("bad timediv")
+ }
+
+ var z uint32
+ z = 1
+ if !cas(&z, 1, 2) {
+ gothrow("cas1")
+ }
+ if z != 2 {
+ gothrow("cas2")
+ }
+
+ z = 4
+ if cas(&z, 5, 6) {
+ gothrow("cas3")
+ }
+ if z != 4 {
+ gothrow("cas4")
+ }
+
+ z = 0xffffffff
+ if !cas(&z, 0xffffffff, 0xfffffffe) {
+ gothrow("cas5")
+ }
+ if z != 0xfffffffe {
+ gothrow("cas6")
+ }
+
+ k = unsafe.Pointer(uintptr(0xfedcb123))
+ if ptrSize == 8 {
+ k = unsafe.Pointer(uintptr(unsafe.Pointer(k)) << 10)
+ }
+ if casp(&k, nil, nil) {
+ gothrow("casp1")
+ }
+ k1 = add(k, 1)
+ if !casp(&k, k, k1) {
+ gothrow("casp2")
+ }
+ if k != k1 {
+ gothrow("casp3")
+ }
+
+ m = [4]byte{1, 1, 1, 1}
+ atomicor8(&m[1], 0xf0)
+ if m[0] != 1 || m[1] != 0xf1 || m[2] != 1 || m[3] != 1 {
+ gothrow("atomicor8")
+ }
+
+ *(*uint64)(unsafe.Pointer(&j)) = ^uint64(0)
+ if j == j {
+ gothrow("float64nan")
+ }
+ if !(j != j) {
+ gothrow("float64nan1")
+ }
+
+ *(*uint64)(unsafe.Pointer(&j1)) = ^uint64(1)
+ if j == j1 {
+ gothrow("float64nan2")
+ }
+ if !(j != j1) {
+ gothrow("float64nan3")
+ }
+
+ *(*uint32)(unsafe.Pointer(&i)) = ^uint32(0)
+ if i == i {
+ gothrow("float32nan")
+ }
+ if i == i {
+ gothrow("float32nan1")
+ }
+
+ *(*uint32)(unsafe.Pointer(&i1)) = ^uint32(1)
+ if i == i1 {
+ gothrow("float32nan2")
+ }
+ if i == i1 {
+ gothrow("float32nan3")
+ }
+
+ testAtomic64()
+
+ if _FixedStack != round2(_FixedStack) {
+ gothrow("FixedStack is not power-of-2")
+ }
+}
+
+type dbgVar struct {
+ name string
+ value *int32
+}
+
+// Do we report invalid pointers found during stack or heap scans?
+//var invalidptr int32 = 1
+
+var dbgvars = []dbgVar{
+ {"allocfreetrace", &debug.allocfreetrace},
+ {"invalidptr", &invalidptr},
+ {"efence", &debug.efence},
+ {"gctrace", &debug.gctrace},
+ {"gcdead", &debug.gcdead},
+ {"scheddetail", &debug.scheddetail},
+ {"schedtrace", &debug.schedtrace},
+ {"scavenge", &debug.scavenge},
+}
+
+func parsedebugvars() {
+ for p := gogetenv("GODEBUG"); p != ""; {
+ field := ""
+ i := index(p, ",")
+ if i < 0 {
+ field, p = p, ""
+ } else {
+ field, p = p[:i], p[i+1:]
+ }
+ i = index(field, "=")
+ if i < 0 {
+ continue
+ }
+ key, value := field[:i], field[i+1:]
+ for _, v := range dbgvars {
+ if v.name == key {
+ *v.value = int32(goatoi(value))
+ }
+ }
+ }
+
+ switch p := gogetenv("GOTRACEBACK"); p {
+ case "":
+ traceback_cache = 1 << 1
+ case "crash":
+ traceback_cache = 2<<1 | 1
+ default:
+ traceback_cache = uint32(goatoi(p)) << 1
+ }
+}
+
+// Poor mans 64-bit division.
+// This is a very special function, do not use it if you are not sure what you are doing.
+// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
+// Handles overflow in a time-specific manner.
+//go:nosplit
+func timediv(v int64, div int32, rem *int32) int32 {
+ res := int32(0)
+ for bit := 30; bit >= 0; bit-- {
+ if v >= int64(div)<<uint(bit) {
+ v = v - (int64(div) << uint(bit))
+ res += 1 << uint(bit)
+ }
+ }
+ if v >= int64(div) {
+ if rem != nil {
+ *rem = 0
+ }
+ return 0x7fffffff
+ }
+ if rem != nil {
+ *rem = int32(v)
+ }
+ return res
+}
+
+// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.
+
+//go:nosplit
+func acquirem() *m {
+ _g_ := getg()
+ _g_.m.locks++
+ return _g_.m
+}
+
+//go:nosplit
+func releasem(mp *m) {
+ _g_ := getg()
+ mp.locks--
+ if mp.locks == 0 && _g_.preempt {
+ // restore the preemption request in case we've cleared it in newstack
+ _g_.stackguard0 = stackPreempt
+ }
+}
+
+//go:nosplit
+func gomcache() *mcache {
+ return getg().m.mcache
+}
+
+var typelink, etypelink [0]byte
+
+//go:nosplit
+func typelinks() []*_type {
+ var ret []*_type
+ sp := (*slice)(unsafe.Pointer(&ret))
+ sp.array = (*byte)(unsafe.Pointer(&typelink))
+ sp.len = uint((uintptr(unsafe.Pointer(&etypelink)) - uintptr(unsafe.Pointer(&typelink))) / unsafe.Sizeof(ret[0]))
+ sp.cap = sp.len
+ return ret
+}
+
+// TODO: move back into mgc0.c when converted to Go
+func readgogc() int32 {
+ p := gogetenv("GOGC")
+ if p == "" {
+ return 100
+ }
+ if p == "off" {
+ return -1
+ }
+ return int32(goatoi(p))
+}
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
new file mode 100644
index 000000000..7987a7373
--- /dev/null
+++ b/src/runtime/runtime2.go
@@ -0,0 +1,606 @@
+// 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 runtime
+
+import "unsafe"
+
+/*
+ * defined constants
+ */
+const (
+ // G status
+ //
+ // If you add to this list, add to the list
+ // of "okay during garbage collection" status
+ // in mgc0.c too.
+ _Gidle = iota // 0
+ _Grunnable // 1 runnable and on a run queue
+ _Grunning // 2
+ _Gsyscall // 3
+ _Gwaiting // 4
+ _Gmoribund_unused // 5 currently unused, but hardcoded in gdb scripts
+ _Gdead // 6
+ _Genqueue // 7 Only the Gscanenqueue is used.
+ _Gcopystack // 8 in this state when newstack is moving the stack
+ // the following encode that the GC is scanning the stack and what to do when it is done
+ _Gscan = 0x1000 // atomicstatus&~Gscan = the non-scan state,
+ // _Gscanidle = _Gscan + _Gidle, // Not used. Gidle only used with newly malloced gs
+ _Gscanrunnable = _Gscan + _Grunnable // 0x1001 When scanning complets make Grunnable (it is already on run queue)
+ _Gscanrunning = _Gscan + _Grunning // 0x1002 Used to tell preemption newstack routine to scan preempted stack.
+ _Gscansyscall = _Gscan + _Gsyscall // 0x1003 When scanning completes make is Gsyscall
+ _Gscanwaiting = _Gscan + _Gwaiting // 0x1004 When scanning completes make it Gwaiting
+ // _Gscanmoribund_unused, // not possible
+ // _Gscandead, // not possible
+ _Gscanenqueue = _Gscan + _Genqueue // When scanning completes make it Grunnable and put on runqueue
+)
+
+const (
+ // P status
+ _Pidle = iota
+ _Prunning
+ _Psyscall
+ _Pgcstop
+ _Pdead
+)
+
+// The next line makes 'go generate' write the zgen_*.go files with
+// per-OS and per-arch information, including constants
+// named goos_$GOOS and goarch_$GOARCH for every
+// known GOOS and GOARCH. The constant is 1 on the
+// current system, 0 otherwise; multiplying by them is
+// useful for defining GOOS- or GOARCH-specific constants.
+//go:generate go run gengoos.go
+
+type mutex struct {
+ // Futex-based impl treats it as uint32 key,
+ // while sema-based impl as M* waitm.
+ // Used to be a union, but unions break precise GC.
+ key uintptr
+}
+
+type note struct {
+ // Futex-based impl treats it as uint32 key,
+ // while sema-based impl as M* waitm.
+ // Used to be a union, but unions break precise GC.
+ key uintptr
+}
+
+type _string struct {
+ str *byte
+ len int
+}
+
+type funcval struct {
+ fn uintptr
+ // variable-size, fn-specific data here
+}
+
+type iface struct {
+ tab *itab
+ data unsafe.Pointer
+}
+
+type eface struct {
+ _type *_type
+ data unsafe.Pointer
+}
+
+type slice struct {
+ array *byte // actual data
+ len uint // number of elements
+ cap uint // allocated number of elements
+}
+
+type gobuf struct {
+ // The offsets of sp, pc, and g are known to (hard-coded in) libmach.
+ sp uintptr
+ pc uintptr
+ g *g
+ ctxt unsafe.Pointer // this has to be a pointer so that gc scans it
+ ret uintreg
+ lr uintptr
+}
+
+// Known to compiler.
+// Changes here must also be made in src/cmd/gc/select.c's selecttype.
+type sudog struct {
+ g *g
+ selectdone *uint32
+ next *sudog
+ prev *sudog
+ elem unsafe.Pointer // data element
+ releasetime int64
+ nrelease int32 // -1 for acquire
+ waitlink *sudog // g.waiting list
+}
+
+type gcstats struct {
+ // the struct must consist of only uint64's,
+ // because it is casted to uint64[].
+ nhandoff uint64
+ nhandoffcnt uint64
+ nprocyield uint64
+ nosyield uint64
+ nsleep uint64
+}
+
+type libcall struct {
+ fn uintptr
+ n uintptr // number of parameters
+ args uintptr // parameters
+ r1 uintptr // return values
+ r2 uintptr
+ err uintptr // error number
+}
+
+// describes how to handle callback
+type wincallbackcontext struct {
+ gobody unsafe.Pointer // go function to call
+ argsize uintptr // callback arguments size (in bytes)
+ restorestack uintptr // adjust stack on return by (in bytes) (386 only)
+ cleanstack bool
+}
+
+// Stack describes a Go execution stack.
+// The bounds of the stack are exactly [lo, hi),
+// with no implicit data structures on either side.
+type stack struct {
+ lo uintptr
+ hi uintptr
+}
+
+type g struct {
+ // Stack parameters.
+ // stack describes the actual stack memory: [stack.lo, stack.hi).
+ // stackguard0 is the stack pointer compared in the Go stack growth prologue.
+ // It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption.
+ // stackguard1 is the stack pointer compared in the C stack growth prologue.
+ // It is stack.lo+StackGuard on g0 and gsignal stacks.
+ // It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash).
+ stack stack // offset known to runtime/cgo
+ stackguard0 uintptr // offset known to liblink
+ stackguard1 uintptr // offset known to liblink
+
+ _panic *_panic // innermost panic - offset known to liblink
+ _defer *_defer // innermost defer
+ sched gobuf
+ syscallsp uintptr // if status==gsyscall, syscallsp = sched.sp to use during gc
+ syscallpc uintptr // if status==gsyscall, syscallpc = sched.pc to use during gc
+ param unsafe.Pointer // passed parameter on wakeup
+ atomicstatus uint32
+ goid int64
+ waitsince int64 // approx time when the g become blocked
+ waitreason string // if status==gwaiting
+ schedlink *g
+ issystem bool // do not output in stack dump, ignore in deadlock detector
+ preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
+ 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
+ throwsplit bool // must not split stack
+ raceignore int8 // ignore race detection events
+ m *m // for debuggers, but offset not hard-coded
+ lockedm *m
+ sig uint32
+ writebuf []byte
+ sigcode0 uintptr
+ sigcode1 uintptr
+ sigpc uintptr
+ gopc uintptr // pc of go statement that created this goroutine
+ racectx uintptr
+ waiting *sudog // sudog structures this g is waiting on (that have a valid elem ptr)
+ end [0]byte
+}
+
+type mts struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+type mscratch struct {
+ v [6]uintptr
+}
+
+type m struct {
+ g0 *g // goroutine with scheduling stack
+ morebuf gobuf // gobuf arg to morestack
+
+ // Fields not known to debuggers.
+ procid uint64 // for debuggers, but offset not hard-coded
+ gsignal *g // signal-handling g
+ tls [4]uintptr // thread-local storage (for x86 extern register)
+ mstartfn unsafe.Pointer // todo go func()
+ curg *g // current running goroutine
+ caughtsig *g // goroutine running during fatal signal
+ p *p // attached p for executing go code (nil if not executing go code)
+ nextp *p
+ id int32
+ mallocing int32
+ throwing int32
+ gcing int32
+ locks int32
+ softfloat int32
+ dying int32
+ profilehz int32
+ helpgc int32
+ spinning bool // m is out of work and is actively looking for work
+ blocked bool // m is blocked on a note
+ fastrand uint32
+ ncgocall uint64 // number of cgo calls in total
+ ncgo int32 // number of cgo calls currently in progress
+ cgomal *cgomal
+ park note
+ alllink *m // on allm
+ schedlink *m
+ machport uint32 // return address for mach ipc (os x)
+ mcache *mcache
+ lockedg *g
+ createstack [32]uintptr // stack that created this thread.
+ freglo [16]uint32 // d[i] lsb and f[i]
+ freghi [16]uint32 // d[i] msb and f[i+16]
+ fflag uint32 // floating point compare flags
+ locked uint32 // tracking for lockosthread
+ nextwaitm *m // next m waiting for lock
+ waitsema uintptr // semaphore for parking on locks
+ waitsemacount uint32
+ waitsemalock uint32
+ gcstats gcstats
+ needextram bool
+ traceback uint8
+ waitunlockf unsafe.Pointer // todo go func(*g, unsafe.pointer) bool
+ waitlock unsafe.Pointer
+ //#ifdef GOOS_windows
+ thread uintptr // thread handle
+ // these are here because they are too large to be on the stack
+ // of low-level NOSPLIT functions.
+ libcall libcall
+ libcallpc uintptr // for cpu profiler
+ libcallsp uintptr
+ libcallg *g
+ //#endif
+ //#ifdef GOOS_solaris
+ perrno *int32 // pointer to tls errno
+ // these are here because they are too large to be on the stack
+ // of low-level NOSPLIT functions.
+ //LibCall libcall;
+ ts mts
+ scratch mscratch
+ //#endif
+ //#ifdef GOOS_plan9
+ notesig *int8
+ errstr *byte
+ //#endif
+ end [0]byte
+}
+
+type p struct {
+ lock mutex
+
+ id int32
+ status uint32 // one of pidle/prunning/...
+ link *p
+ schedtick uint32 // incremented on every scheduler call
+ syscalltick uint32 // incremented on every system call
+ m *m // back-link to associated m (nil if idle)
+ mcache *mcache
+ deferpool [5]*_defer // pool of available defer structs of different sizes (see panic.c)
+
+ // Cache of goroutine ids, amortizes accesses to runtime·sched.goidgen.
+ goidcache uint64
+ goidcacheend uint64
+
+ // Queue of runnable goroutines.
+ runqhead uint32
+ runqtail uint32
+ runq [256]*g
+
+ // Available G's (status == Gdead)
+ gfree *g
+ gfreecnt int32
+
+ pad [64]byte
+}
+
+const (
+ // The max value of GOMAXPROCS.
+ // There are no fundamental restrictions on the value.
+ _MaxGomaxprocs = 1 << 8
+)
+
+type schedt struct {
+ lock mutex
+
+ goidgen uint64
+
+ midle *m // idle m's waiting for work
+ nmidle int32 // number of idle m's waiting for work
+ nmidlelocked int32 // number of locked m's waiting for work
+ mcount int32 // number of m's that have been created
+ maxmcount int32 // maximum number of m's allowed (or die)
+
+ pidle *p // idle p's
+ npidle uint32
+ nmspinning uint32
+
+ // Global runnable queue.
+ runqhead *g
+ runqtail *g
+ runqsize int32
+
+ // Global cache of dead G's.
+ gflock mutex
+ gfree *g
+ ngfree int32
+
+ gcwaiting uint32 // gc is waiting to run
+ stopwait int32
+ stopnote note
+ sysmonwait uint32
+ sysmonnote note
+ lastpoll uint64
+
+ profilehz int32 // cpu profiling rate
+}
+
+// The m->locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread.
+// The low bit (LockExternal) is a boolean reporting whether any LockOSThread call is active.
+// External locks are not recursive; a second lock is silently ignored.
+// The upper bits of m->lockedcount record the nesting depth of calls to lockOSThread
+// (counting up by LockInternal), popped by unlockOSThread (counting down by LockInternal).
+// Internal locks can be recursive. For instance, a lock for cgo can occur while the main
+// goroutine is holding the lock during the initialization phase.
+const (
+ _LockExternal = 1
+ _LockInternal = 2
+)
+
+type sigtabtt struct {
+ flags int32
+ name *int8
+}
+
+const (
+ _SigNotify = 1 << 0 // let signal.Notify have signal, even if from kernel
+ _SigKill = 1 << 1 // if signal.Notify doesn't take it, exit quietly
+ _SigThrow = 1 << 2 // if signal.Notify doesn't take it, exit loudly
+ _SigPanic = 1 << 3 // if the signal is from the kernel, panic
+ _SigDefault = 1 << 4 // if the signal isn't explicitly requested, don't monitor it
+ _SigHandling = 1 << 5 // our signal handler is registered
+ _SigIgnored = 1 << 6 // the signal was ignored before we registered for it
+ _SigGoExit = 1 << 7 // cause all runtime procs to exit (only used on Plan 9).
+)
+
+// Layout of in-memory per-function information prepared by linker
+// See http://golang.org/s/go12symtab.
+// Keep in sync with linker and with ../../libmach/sym.c
+// and with package debug/gosym and with symtab.go in package runtime.
+type _func struct {
+ entry uintptr // start pc
+ nameoff int32 // function name
+
+ args int32 // in/out args size
+ frame int32 // legacy frame size; use pcsp if possible
+
+ pcsp int32
+ pcfile int32
+ pcln int32
+ npcdata int32
+ nfuncdata int32
+}
+
+// layout of Itab known to compilers
+// allocated in non-garbage-collected memory
+type itab struct {
+ inter *interfacetype
+ _type *_type
+ link *itab
+ bad int32
+ unused int32
+ fun [0]uintptr
+}
+
+// Lock-free stack node.
+type lfnode struct {
+ next *lfnode
+ 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 {
+ next *cgomal
+ alloc unsafe.Pointer
+}
+
+// Holds variables parsed from GODEBUG env var.
+type debugvars struct {
+ allocfreetrace int32
+ efence int32
+ gctrace int32
+ gcdead int32
+ scheddetail int32
+ schedtrace int32
+ scavenge int32
+}
+
+// Indicates to write barrier and sychronization task to preform.
+const (
+ _GCoff = iota // stop and start nop
+ _GCquiesce // stop and start nop
+ _GCstw // stop the ps nop
+ _GCmark // scan the stacks and start no white to black
+ _GCsweep // stop and start nop
+)
+
+type forcegcstate struct {
+ lock mutex
+ g *g
+ idle uint32
+}
+
+var gcphase uint32
+
+/*
+ * known to compiler
+ */
+const (
+ _Structrnd = regSize
+)
+
+var startup_random_data *byte
+var startup_random_data_len uint32
+
+var invalidptr int32
+
+const (
+ // hashinit wants this many random bytes
+ _HashRandomBytes = 32
+)
+
+/*
+ * deferred subroutine calls
+ */
+type _defer struct {
+ siz int32
+ started bool
+ argp uintptr // where args were copied from
+ pc uintptr
+ fn *funcval
+ _panic *_panic // panic that is running defer
+ link *_defer
+}
+
+/*
+ * panics
+ */
+type _panic struct {
+ argp unsafe.Pointer // pointer to arguments of deferred call run during panic; cannot move - known to liblink
+ arg interface{} // argument to panic
+ link *_panic // link to earlier panic
+ recovered bool // whether this panic is over
+ aborted bool // the panic was aborted
+}
+
+/*
+ * stack traces
+ */
+
+type stkframe struct {
+ fn *_func // function being run
+ pc uintptr // program counter within fn
+ continpc uintptr // program counter where execution can continue, or 0 if not
+ lr uintptr // program counter at caller aka link register
+ sp uintptr // stack pointer at pc
+ fp uintptr // stack pointer at caller aka frame pointer
+ varp uintptr // top of local variables
+ argp uintptr // pointer to function arguments
+ arglen uintptr // number of bytes at argp
+ argmap *bitvector // force use of this argmap
+}
+
+const (
+ _TraceRuntimeFrames = 1 << 0 // include frames for internal runtime functions.
+ _TraceTrap = 1 << 1 // the initial PC, SP are from a trap, not a return PC from a call
+)
+
+const (
+ // The maximum number of frames we print for a traceback
+ _TracebackMaxFrames = 100
+)
+
+var (
+ emptystring string
+ allg **g
+ allglen uintptr
+ lastg *g
+ allm *m
+ allp [_MaxGomaxprocs + 1]*p
+ gomaxprocs int32
+ needextram uint32
+ panicking uint32
+ goos *int8
+ ncpu int32
+ iscgo bool
+ cpuid_ecx uint32
+ cpuid_edx uint32
+ debug debugvars
+ signote note
+ forcegc forcegcstate
+ sched schedt
+ newprocs int32
+)
+
+/*
+ * mutual exclusion locks. in the uncontended case,
+ * as fast as spin locks (just a few user-level instructions),
+ * but on the contention path they sleep in the kernel.
+ * a zeroed Mutex is unlocked (no need to initialize each lock).
+ */
+
+/*
+ * sleep and wakeup on one-time events.
+ * before any calls to notesleep or notewakeup,
+ * must call noteclear to initialize the Note.
+ * then, exactly one thread can call notesleep
+ * and exactly one thread can call notewakeup (once).
+ * once notewakeup has been called, the notesleep
+ * will return. future notesleep will return immediately.
+ * subsequent noteclear must be called only after
+ * previous notesleep has returned, e.g. it's disallowed
+ * to call noteclear straight after notewakeup.
+ *
+ * notetsleep is like notesleep but wakes up after
+ * a given number of nanoseconds even if the event
+ * has not yet happened. if a goroutine uses notetsleep to
+ * wake up early, it must wait to call noteclear until it
+ * can be sure that no other goroutine is calling
+ * notewakeup.
+ *
+ * notesleep/notetsleep are generally called on g0,
+ * notetsleepg is similar to notetsleep but is called on user g.
+ */
+// bool runtime·notetsleep(Note*, int64); // false - timeout
+// bool runtime·notetsleepg(Note*, int64); // false - timeout
+
+/*
+ * Lock-free stack.
+ * Initialize uint64 head to 0, compare with 0 to test for emptiness.
+ * The stack does not keep pointers to nodes,
+ * 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.
diff --git a/src/runtime/runtime2_windows.go b/src/runtime/runtime2_windows.go
new file mode 100644
index 000000000..80fc386e9
--- /dev/null
+++ b/src/runtime/runtime2_windows.go
@@ -0,0 +1,8 @@
+// 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 runtime
+
+// TODO(brainman): move generation of zsys_windows_*.s out from cmd/dist/buildruntime.c and into here
+const cb_max = 2000 // maximum number of windows callbacks allowed (must be in sync with MAXWINCB from cmd/dist/buildruntime.c)
diff --git a/src/runtime/select.go b/src/runtime/select.go
index f735a71e2..6717b9395 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -167,8 +167,8 @@ func selunlock(sel *_select) {
}
}
-func selparkcommit(gp *g, sel *_select) bool {
- selunlock(sel)
+func selparkcommit(gp *g, sel unsafe.Pointer) bool {
+ selunlock((*_select)(sel))
return true
}
@@ -363,7 +363,7 @@ loop:
// wait for someone to wake us up
gp.param = nil
- gopark(unsafe.Pointer(funcPC(selparkcommit)), unsafe.Pointer(sel), "select")
+ gopark(selparkcommit, unsafe.Pointer(sel), "select")
// someone woke us up
sellock(sel)
diff --git a/src/runtime/signal.c b/src/runtime/signal.c
deleted file mode 100644
index 0674bfb22..000000000
--- a/src/runtime/signal.c
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.
-
-#include "runtime.h"
-
-void
-runtime·sigenable_m(void)
-{
- uint32 s;
-
- s = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
- runtime·sigenable(s);
-}
-
-void
-runtime·sigdisable_m(void)
-{
- uint32 s;
-
- s = g->m->scalararg[0];
- g->m->scalararg[0] = 0;
- runtime·sigdisable(s);
-}
diff --git a/src/runtime/signal1_unix.go b/src/runtime/signal1_unix.go
new file mode 100644
index 000000000..25f01e056
--- /dev/null
+++ b/src/runtime/signal1_unix.go
@@ -0,0 +1,111 @@
+// Copyright 2012 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime
+
+const (
+ _SIG_DFL uintptr = 0
+ _SIG_IGN uintptr = 1
+)
+
+func initsig() {
+ // _NSIG is the number of signals on this operating system.
+ // sigtable should describe what to do for all the possible signals.
+ if len(sigtable) != _NSIG {
+ print("runtime: len(sigtable)=", len(sigtable), " _NSIG=", _NSIG, "\n")
+ gothrow("initsig")
+ }
+
+ // First call: basic setup.
+ for i := int32(0); i < _NSIG; i++ {
+ t := &sigtable[i]
+ if t.flags == 0 || t.flags&_SigDefault != 0 {
+ continue
+ }
+
+ // For some signals, we respect an inherited SIG_IGN handler
+ // rather than insist on installing our own default handler.
+ // Even these signals can be fetched using the os/signal package.
+ switch i {
+ case _SIGHUP, _SIGINT:
+ if getsig(i) == _SIG_IGN {
+ t.flags = _SigNotify | _SigIgnored
+ continue
+ }
+ }
+
+ t.flags |= _SigHandling
+ setsig(i, funcPC(sighandler), true)
+ }
+}
+
+func sigenable(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 && t.flags&_SigHandling == 0 {
+ t.flags |= _SigHandling
+ if getsig(int32(sig)) == _SIG_IGN {
+ t.flags |= _SigIgnored
+ }
+ setsig(int32(sig), funcPC(sighandler), true)
+ }
+}
+
+func sigdisable(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 && t.flags&_SigHandling != 0 {
+ t.flags &^= _SigHandling
+ if t.flags&_SigIgnored != 0 {
+ setsig(int32(sig), _SIG_IGN, true)
+ } else {
+ setsig(int32(sig), _SIG_DFL, true)
+ }
+ }
+}
+
+func resetcpuprofiler(hz int32) {
+ var it itimerval
+ if hz == 0 {
+ setitimer(_ITIMER_PROF, &it, nil)
+ } else {
+ it.it_interval.tv_sec = 0
+ it.it_interval.set_usec(1000000 / hz)
+ it.it_value = it.it_interval
+ setitimer(_ITIMER_PROF, &it, nil)
+ }
+ _g_ := getg()
+ _g_.m.profilehz = hz
+}
+
+func sigpipe() {
+ setsig(_SIGPIPE, _SIG_DFL, false)
+ raise(_SIGPIPE)
+}
+
+func crash() {
+ if GOOS == "darwin" {
+ // OS X core dumps are linear dumps of the mapped memory,
+ // from the first virtual byte to the last, with zeros in the gaps.
+ // Because of the way we arrange the address space on 64-bit systems,
+ // this means the OS X core file will be >128 GB and even on a zippy
+ // workstation can take OS X well over an hour to write (uninterruptible).
+ // Save users from making that mistake.
+ if ptrSize == 8 {
+ return
+ }
+ }
+
+ unblocksignals()
+ setsig(_SIGABRT, _SIG_DFL, false)
+ raise(_SIGABRT)
+}
diff --git a/src/runtime/signal_386.c b/src/runtime/signal_386.c
deleted file mode 100644
index 30a7488bd..000000000
--- a/src/runtime/signal_386.c
+++ /dev/null
@@ -1,122 +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.
-
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Siginfo *info, void *ctxt)
-{
- USED(info);
- USED(ctxt);
-
- runtime·printf("eax %x\n", SIG_EAX(info, ctxt));
- runtime·printf("ebx %x\n", SIG_EBX(info, ctxt));
- runtime·printf("ecx %x\n", SIG_ECX(info, ctxt));
- runtime·printf("edx %x\n", SIG_EDX(info, ctxt));
- runtime·printf("edi %x\n", SIG_EDI(info, ctxt));
- runtime·printf("esi %x\n", SIG_ESI(info, ctxt));
- runtime·printf("ebp %x\n", SIG_EBP(info, ctxt));
- runtime·printf("esp %x\n", SIG_ESP(info, ctxt));
- runtime·printf("eip %x\n", SIG_EIP(info, ctxt));
- runtime·printf("eflags %x\n", SIG_EFLAGS(info, ctxt));
- runtime·printf("cs %x\n", SIG_CS(info, ctxt));
- runtime·printf("fs %x\n", SIG_FS(info, ctxt));
- runtime·printf("gs %x\n", SIG_GS(info, ctxt));
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
-{
- uintptr *sp;
- SigTab *t;
- bool crash;
-
- if(sig == SIGPROF) {
- runtime·sigprof((byte*)SIG_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp, g->m);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp->sig = sig;
- gp->sigcode0 = SIG_CODE0(info, ctxt);
- gp->sigcode1 = SIG_CODE1(info, ctxt);
- gp->sigpc = SIG_EIP(info, ctxt);
-
-#ifdef GOOS_darwin
- // Work around Leopard bug that doesn't set FPE_INTDIV.
- // Look at instruction to see if it is a divide.
- // Not necessary in Snow Leopard (si_code will be != 0).
- if(sig == SIGFPE && gp->sigcode0 == 0) {
- byte *pc;
- pc = (byte*)gp->sigpc;
- if(pc[0] == 0x66) // 16-bit instruction prefix
- pc++;
- if(pc[0] == 0xF6 || pc[0] == 0xF7)
- gp->sigcode0 = FPE_INTDIV;
- }
-#endif
-
- // Only push runtime·sigpanic if eip != 0.
- // If eip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(SIG_EIP(info, ctxt) != 0) {
- sp = (uintptr*)SIG_ESP(info, ctxt);
- *--sp = SIG_EIP(info, ctxt);
- SIG_ESP(info, ctxt) = (uintptr)sp;
- }
- SIG_EIP(info, ctxt) = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
- g->m->throwing = 1;
- g->m->caughtsig = gp;
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%x\n", SIG_EIP(info, ctxt));
- if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = g->m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback(&crash)){
- runtime·goroutineheader(gp);
- runtime·tracebacktrap(SIG_EIP(info, ctxt), SIG_ESP(info, ctxt), 0, gp);
- runtime·tracebackothers(gp);
- runtime·printf("\n");
- runtime·dumpregs(info, ctxt);
- }
-
- if(crash)
- runtime·crash();
-
- runtime·exit(2);
-}
diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go
new file mode 100644
index 000000000..5336a4330
--- /dev/null
+++ b/src/runtime/signal_386.go
@@ -0,0 +1,131 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd
+
+package runtime
+
+import "unsafe"
+
+func dumpregs(c *sigctxt) {
+ print("eax ", hex(c.eax()), "\n")
+ print("ebx ", hex(c.ebx()), "\n")
+ print("ecx ", hex(c.ecx()), "\n")
+ print("edx ", hex(c.edx()), "\n")
+ print("edi ", hex(c.edi()), "\n")
+ print("esi ", hex(c.esi()), "\n")
+ print("ebp ", hex(c.ebp()), "\n")
+ print("esp ", hex(c.esp()), "\n")
+ print("eip ", hex(c.eip()), "\n")
+ print("eflags ", hex(c.eflags()), "\n")
+ print("cs ", hex(c.cs()), "\n")
+ print("fs ", hex(c.fs()), "\n")
+ print("gs ", hex(c.gs()), "\n")
+}
+
+func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
+ _g_ := getg()
+ c := &sigctxt{info, ctxt}
+
+ if sig == _SIGPROF {
+ sigprof((*byte)(unsafe.Pointer(uintptr(c.eip()))), (*byte)(unsafe.Pointer(uintptr(c.esp()))), nil, gp, _g_.m)
+ return
+ }
+
+ flags := int32(_SigThrow)
+ if sig < uint32(len(sigtable)) {
+ flags = sigtable[sig].flags
+ }
+ if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp.sig = sig
+ gp.sigcode0 = uintptr(c.sigcode())
+ gp.sigcode1 = uintptr(c.sigaddr())
+ gp.sigpc = uintptr(c.eip())
+
+ if GOOS == "darwin" {
+ // Work around Leopard bug that doesn't set FPE_INTDIV.
+ // Look at instruction to see if it is a divide.
+ // Not necessary in Snow Leopard (si_code will be != 0).
+ if sig == _SIGFPE && gp.sigcode0 == 0 {
+ pc := (*[4]byte)(unsafe.Pointer(gp.sigpc))
+ i := 0
+ if pc[i] == 0x66 { // 16-bit instruction prefix
+ i++
+ }
+ if pc[i] == 0xF6 || pc[i] == 0xF7 {
+ gp.sigcode0 = _FPE_INTDIV
+ }
+ }
+ }
+
+ // Only push runtime.sigpanic if rip != 0.
+ // If rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime.sigpanic instead.
+ // (Otherwise the trace will end at runtime.sigpanic and we
+ // won't get to see who faulted.)
+ if c.eip() != 0 {
+ sp := c.esp()
+ if regSize > ptrSize {
+ sp -= ptrSize
+ *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0
+ }
+ sp -= ptrSize
+ *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(c.eip())
+ c.set_esp(sp)
+ }
+ c.set_eip(uint32(funcPC(sigpanic)))
+ return
+ }
+
+ if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
+ if sigsend(sig) {
+ return
+ }
+ }
+
+ if flags&_SigKill != 0 {
+ exit(2)
+ }
+
+ if flags&_SigThrow == 0 {
+ return
+ }
+
+ _g_.m.throwing = 1
+ _g_.m.caughtsig = gp
+ startpanic()
+
+ if sig < uint32(len(sigtable)) {
+ print(sigtable[sig].name, "\n")
+ } else {
+ print("Signal ", sig, "\n")
+ }
+
+ print("PC=", hex(c.eip()), "\n")
+ if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+ print("signal arrived during cgo execution\n")
+ gp = _g_.m.lockedg
+ }
+ print("\n")
+
+ var docrash bool
+ if gotraceback(&docrash) > 0 {
+ goroutineheader(gp)
+ tracebacktrap(uintptr(c.eip()), uintptr(c.esp()), 0, gp)
+ tracebackothers(gp)
+ print("\n")
+ dumpregs(c)
+ }
+
+ if docrash {
+ crash()
+ }
+
+ exit(2)
+}
diff --git a/src/runtime/signal_amd64x.c b/src/runtime/signal_amd64x.c
deleted file mode 100644
index feb4afcce..000000000
--- a/src/runtime/signal_amd64x.c
+++ /dev/null
@@ -1,156 +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.
-
-// +build amd64 amd64p32
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Siginfo *info, void *ctxt)
-{
- USED(info);
- USED(ctxt);
-
- runtime·printf("rax %X\n", SIG_RAX(info, ctxt));
- runtime·printf("rbx %X\n", SIG_RBX(info, ctxt));
- runtime·printf("rcx %X\n", SIG_RCX(info, ctxt));
- runtime·printf("rdx %X\n", SIG_RDX(info, ctxt));
- runtime·printf("rdi %X\n", SIG_RDI(info, ctxt));
- runtime·printf("rsi %X\n", SIG_RSI(info, ctxt));
- runtime·printf("rbp %X\n", SIG_RBP(info, ctxt));
- runtime·printf("rsp %X\n", SIG_RSP(info, ctxt));
- runtime·printf("r8 %X\n", SIG_R8(info, ctxt) );
- runtime·printf("r9 %X\n", SIG_R9(info, ctxt) );
- runtime·printf("r10 %X\n", SIG_R10(info, ctxt));
- runtime·printf("r11 %X\n", SIG_R11(info, ctxt));
- runtime·printf("r12 %X\n", SIG_R12(info, ctxt));
- runtime·printf("r13 %X\n", SIG_R13(info, ctxt));
- runtime·printf("r14 %X\n", SIG_R14(info, ctxt));
- runtime·printf("r15 %X\n", SIG_R15(info, ctxt));
- runtime·printf("rip %X\n", SIG_RIP(info, ctxt));
- runtime·printf("rflags %X\n", SIG_RFLAGS(info, ctxt));
- runtime·printf("cs %X\n", SIG_CS(info, ctxt));
- runtime·printf("fs %X\n", SIG_FS(info, ctxt));
- runtime·printf("gs %X\n", SIG_GS(info, ctxt));
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
-{
- uintptr *sp;
- SigTab *t;
- bool crash;
-
- if(sig == SIGPROF) {
- runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp, g->m);
- return;
- }
-
-#ifdef GOOS_darwin
- // x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47.
- // The hardware delivers a different kind of fault for a malformed address
- // than it does for an attempt to access a valid but unmapped address.
- // OS X 10.9.2 mishandles the malformed address case, making it look like
- // a user-generated signal (like someone ran kill -SEGV ourpid).
- // We pass user-generated signals to os/signal, or else ignore them.
- // Doing that here - and returning to the faulting code - results in an
- // infinite loop. It appears the best we can do is rewrite what the kernel
- // delivers into something more like the truth. The address used below
- // has very little chance of being the one that caused the fault, but it is
- // malformed, it is clearly not a real pointer, and if it does get printed
- // in real life, people will probably search for it and find this code.
- // There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e
- // as I type this comment.
- if(sig == SIGSEGV && SIG_CODE0(info, ctxt) == SI_USER) {
- SIG_CODE0(info, ctxt) = SI_USER+1;
- info->si_addr = (void*)(uintptr)0xb01dfacedebac1eULL;
- }
-#endif
-
- t = &runtime·sigtab[sig];
- if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp->sig = sig;
- gp->sigcode0 = SIG_CODE0(info, ctxt);
- gp->sigcode1 = SIG_CODE1(info, ctxt);
- gp->sigpc = SIG_RIP(info, ctxt);
-
-#ifdef GOOS_darwin
- // Work around Leopard bug that doesn't set FPE_INTDIV.
- // Look at instruction to see if it is a divide.
- // Not necessary in Snow Leopard (si_code will be != 0).
- if(sig == SIGFPE && gp->sigcode0 == 0) {
- byte *pc;
- pc = (byte*)gp->sigpc;
- if((pc[0]&0xF0) == 0x40) // 64-bit REX prefix
- pc++;
- else if(pc[0] == 0x66) // 16-bit instruction prefix
- pc++;
- if(pc[0] == 0xF6 || pc[0] == 0xF7)
- gp->sigcode0 = FPE_INTDIV;
- }
-#endif
-
- // Only push runtime·sigpanic if rip != 0.
- // If rip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(SIG_RIP(info, ctxt) != 0) {
- sp = (uintptr*)SIG_RSP(info, ctxt);
- if(sizeof(uintreg) > sizeof(uintptr))
- *--sp = 0;
- *--sp = SIG_RIP(info, ctxt);
- SIG_RSP(info, ctxt) = (uintptr)sp;
- }
- SIG_RIP(info, ctxt) = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
- g->m->throwing = 1;
- g->m->caughtsig = gp;
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%X\n", SIG_RIP(info, ctxt));
- if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = g->m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback(&crash)){
- runtime·goroutineheader(gp);
- runtime·tracebacktrap(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp);
- runtime·tracebackothers(gp);
- runtime·printf("\n");
- runtime·dumpregs(info, ctxt);
- }
-
- if(crash)
- runtime·crash();
-
- runtime·exit(2);
-}
diff --git a/src/runtime/signal_amd64x.go b/src/runtime/signal_amd64x.go
new file mode 100644
index 000000000..de88d93a5
--- /dev/null
+++ b/src/runtime/signal_amd64x.go
@@ -0,0 +1,163 @@
+// 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.
+
+// +build amd64 amd64p32
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package runtime
+
+import "unsafe"
+
+func dumpregs(c *sigctxt) {
+ print("rax ", hex(c.rax()), "\n")
+ print("rbx ", hex(c.rbx()), "\n")
+ print("rcx ", hex(c.rcx()), "\n")
+ print("rdx ", hex(c.rdx()), "\n")
+ print("rdi ", hex(c.rdi()), "\n")
+ print("rsi ", hex(c.rsi()), "\n")
+ print("rbp ", hex(c.rbp()), "\n")
+ print("rsp ", hex(c.rsp()), "\n")
+ print("r8 ", hex(c.r8()), "\n")
+ print("r9 ", hex(c.r9()), "\n")
+ print("r10 ", hex(c.r10()), "\n")
+ print("r11 ", hex(c.r11()), "\n")
+ print("r12 ", hex(c.r12()), "\n")
+ print("r13 ", hex(c.r13()), "\n")
+ print("r14 ", hex(c.r14()), "\n")
+ print("r15 ", hex(c.r15()), "\n")
+ print("rip ", hex(c.rip()), "\n")
+ print("rflags ", hex(c.rflags()), "\n")
+ print("cs ", hex(c.cs()), "\n")
+ print("fs ", hex(c.fs()), "\n")
+ print("gs ", hex(c.gs()), "\n")
+}
+
+func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
+ _g_ := getg()
+ c := &sigctxt{info, ctxt}
+
+ if sig == _SIGPROF {
+ sigprof((*byte)(unsafe.Pointer(uintptr(c.rip()))), (*byte)(unsafe.Pointer(uintptr(c.rsp()))), nil, gp, _g_.m)
+ return
+ }
+
+ if GOOS == "darwin" {
+ // x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47.
+ // The hardware delivers a different kind of fault for a malformed address
+ // than it does for an attempt to access a valid but unmapped address.
+ // OS X 10.9.2 mishandles the malformed address case, making it look like
+ // a user-generated signal (like someone ran kill -SEGV ourpid).
+ // We pass user-generated signals to os/signal, or else ignore them.
+ // Doing that here - and returning to the faulting code - results in an
+ // infinite loop. It appears the best we can do is rewrite what the kernel
+ // delivers into something more like the truth. The address used below
+ // has very little chance of being the one that caused the fault, but it is
+ // malformed, it is clearly not a real pointer, and if it does get printed
+ // in real life, people will probably search for it and find this code.
+ // There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e
+ // as I type this comment.
+ if sig == _SIGSEGV && c.sigcode() == _SI_USER {
+ c.set_sigcode(_SI_USER + 1)
+ c.set_sigaddr(0xb01dfacedebac1e)
+ }
+ }
+
+ flags := int32(_SigThrow)
+ if sig < uint32(len(sigtable)) {
+ flags = sigtable[sig].flags
+ }
+ if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp.sig = sig
+ gp.sigcode0 = uintptr(c.sigcode())
+ gp.sigcode1 = uintptr(c.sigaddr())
+ gp.sigpc = uintptr(c.rip())
+
+ if GOOS == "darwin" {
+ // Work around Leopard bug that doesn't set FPE_INTDIV.
+ // Look at instruction to see if it is a divide.
+ // Not necessary in Snow Leopard (si_code will be != 0).
+ if sig == _SIGFPE && gp.sigcode0 == 0 {
+ pc := (*[4]byte)(unsafe.Pointer(gp.sigpc))
+ i := 0
+ if pc[i]&0xF0 == 0x40 { // 64-bit REX prefix
+ i++
+ } else if pc[i] == 0x66 { // 16-bit instruction prefix
+ i++
+ }
+ if pc[i] == 0xF6 || pc[i] == 0xF7 {
+ gp.sigcode0 = _FPE_INTDIV
+ }
+ }
+ }
+
+ // Only push runtime.sigpanic if rip != 0.
+ // If rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime.sigpanic instead.
+ // (Otherwise the trace will end at runtime.sigpanic and we
+ // won't get to see who faulted.)
+ if c.rip() != 0 {
+ sp := c.rsp()
+ if regSize > ptrSize {
+ sp -= ptrSize
+ *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0
+ }
+ sp -= ptrSize
+ *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(c.rip())
+ c.set_rsp(sp)
+ }
+ c.set_rip(uint64(funcPC(sigpanic)))
+ return
+ }
+
+ if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
+ if sigsend(sig) {
+ return
+ }
+ }
+
+ if flags&_SigKill != 0 {
+ exit(2)
+ }
+
+ if flags&_SigThrow == 0 {
+ return
+ }
+
+ _g_.m.throwing = 1
+ _g_.m.caughtsig = gp
+ startpanic()
+
+ if sig < uint32(len(sigtable)) {
+ print(sigtable[sig].name, "\n")
+ } else {
+ print("Signal ", sig, "\n")
+ }
+
+ print("PC=", hex(c.rip()), "\n")
+ if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+ print("signal arrived during cgo execution\n")
+ gp = _g_.m.lockedg
+ }
+ print("\n")
+
+ var docrash bool
+ if gotraceback(&docrash) > 0 {
+ goroutineheader(gp)
+ tracebacktrap(uintptr(c.rip()), uintptr(c.rsp()), 0, gp)
+ tracebackothers(gp)
+ print("\n")
+ dumpregs(c)
+ }
+
+ if docrash {
+ crash()
+ }
+
+ exit(2)
+}
diff --git a/src/runtime/signal_android_386.h b/src/runtime/signal_android_386.h
deleted file mode 100644
index 2a1bb4b3e..000000000
--- a/src/runtime/signal_android_386.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "signal_linux_386.h"
diff --git a/src/runtime/signal_android_arm.h b/src/runtime/signal_android_arm.h
deleted file mode 100644
index 8a05e21e5..000000000
--- a/src/runtime/signal_android_arm.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "signal_linux_arm.h"
diff --git a/src/runtime/signal_arm.c b/src/runtime/signal_arm.c
deleted file mode 100644
index afad5e7d1..000000000
--- a/src/runtime/signal_arm.c
+++ /dev/null
@@ -1,121 +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.
-
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Siginfo *info, void *ctxt)
-{
- USED(info);
- USED(ctxt);
-
- runtime·printf("trap %x\n", SIG_TRAP(info, ctxt));
- runtime·printf("error %x\n", SIG_ERROR(info, ctxt));
- runtime·printf("oldmask %x\n", SIG_OLDMASK(info, ctxt));
- runtime·printf("r0 %x\n", SIG_R0(info, ctxt));
- runtime·printf("r1 %x\n", SIG_R1(info, ctxt));
- runtime·printf("r2 %x\n", SIG_R2(info, ctxt));
- runtime·printf("r3 %x\n", SIG_R3(info, ctxt));
- runtime·printf("r4 %x\n", SIG_R4(info, ctxt));
- runtime·printf("r5 %x\n", SIG_R5(info, ctxt));
- runtime·printf("r6 %x\n", SIG_R6(info, ctxt));
- runtime·printf("r7 %x\n", SIG_R7(info, ctxt));
- runtime·printf("r8 %x\n", SIG_R8(info, ctxt));
- runtime·printf("r9 %x\n", SIG_R9(info, ctxt));
- runtime·printf("r10 %x\n", SIG_R10(info, ctxt));
- runtime·printf("fp %x\n", SIG_FP(info, ctxt));
- runtime·printf("ip %x\n", SIG_IP(info, ctxt));
- runtime·printf("sp %x\n", SIG_SP(info, ctxt));
- runtime·printf("lr %x\n", SIG_LR(info, ctxt));
- runtime·printf("pc %x\n", SIG_PC(info, ctxt));
- runtime·printf("cpsr %x\n", SIG_CPSR(info, ctxt));
- runtime·printf("fault %x\n", SIG_FAULT(info, ctxt));
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
-{
- SigTab *t;
- bool crash;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp, g->m);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp->sig = sig;
- gp->sigcode0 = SIG_CODE0(info, ctxt);
- gp->sigcode1 = SIG_FAULT(info, ctxt);
- gp->sigpc = SIG_PC(info, ctxt);
-
- // We arrange lr, and pc to pretend the panicking
- // function calls sigpanic directly.
- // Always save LR to stack so that panics in leaf
- // functions are correctly handled. This smashes
- // the stack frame but we're not going back there
- // anyway.
- SIG_SP(info, ctxt) -= 4;
- *(uint32*)SIG_SP(info, ctxt) = SIG_LR(info, ctxt);
- // Don't bother saving PC if it's zero, which is
- // probably a call to a nil func: the old link register
- // is more useful in the stack trace.
- if(gp->sigpc != 0)
- SIG_LR(info, ctxt) = gp->sigpc;
- // In case we are panicking from external C code
- SIG_R10(info, ctxt) = (uintptr)gp;
- SIG_PC(info, ctxt) = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
- g->m->throwing = 1;
- g->m->caughtsig = gp;
- if(runtime·panicking) // traceback already printed
- runtime·exit(2);
- runtime·panicking = 1;
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%x\n", SIG_PC(info, ctxt));
- if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = g->m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback(&crash)){
- runtime·goroutineheader(gp);
- runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LR(info, ctxt), gp);
- runtime·tracebackothers(gp);
- runtime·printf("\n");
- runtime·dumpregs(info, ctxt);
- }
-
- if(crash)
- runtime·crash();
-
- runtime·exit(2);
-}
diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go
new file mode 100644
index 000000000..d224ce645
--- /dev/null
+++ b/src/runtime/signal_arm.go
@@ -0,0 +1,126 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd
+
+package runtime
+
+import "unsafe"
+
+func dumpregs(c *sigctxt) {
+ print("trap ", hex(c.trap()), "\n")
+ print("error ", hex(c.error()), "\n")
+ print("oldmask ", hex(c.oldmask()), "\n")
+ print("r0 ", hex(c.r0()), "\n")
+ print("r1 ", hex(c.r1()), "\n")
+ print("r2 ", hex(c.r2()), "\n")
+ print("r3 ", hex(c.r3()), "\n")
+ print("r4 ", hex(c.r4()), "\n")
+ print("r5 ", hex(c.r5()), "\n")
+ print("r6 ", hex(c.r6()), "\n")
+ print("r7 ", hex(c.r7()), "\n")
+ print("r8 ", hex(c.r8()), "\n")
+ print("r9 ", hex(c.r9()), "\n")
+ print("r10 ", hex(c.r10()), "\n")
+ print("fp ", hex(c.fp()), "\n")
+ print("ip ", hex(c.ip()), "\n")
+ print("sp ", hex(c.sp()), "\n")
+ print("lr ", hex(c.lr()), "\n")
+ print("pc ", hex(c.pc()), "\n")
+ print("cpsr ", hex(c.cpsr()), "\n")
+ print("fault ", hex(c.fault()), "\n")
+}
+
+func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
+ _g_ := getg()
+ c := &sigctxt{info, ctxt}
+
+ if sig == _SIGPROF {
+ sigprof((*byte)(unsafe.Pointer(uintptr(c.pc()))), (*byte)(unsafe.Pointer(uintptr(c.sp()))), (*byte)(unsafe.Pointer(uintptr(c.lr()))), gp, _g_.m)
+ return
+ }
+
+ flags := int32(_SigThrow)
+ if sig < uint32(len(sigtable)) {
+ flags = sigtable[sig].flags
+ }
+ if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp.sig = sig
+ gp.sigcode0 = uintptr(c.sigcode())
+ gp.sigcode1 = uintptr(c.fault())
+ gp.sigpc = uintptr(c.pc())
+
+ // We arrange lr, and pc to pretend the panicking
+ // function calls sigpanic directly.
+ // Always save LR to stack so that panics in leaf
+ // functions are correctly handled. This smashes
+ // the stack frame but we're not going back there
+ // anyway.
+ sp := c.sp() - 4
+ c.set_sp(sp)
+ *(*uint32)(unsafe.Pointer(uintptr(sp))) = c.lr()
+
+ // Don't bother saving PC if it's zero, which is
+ // probably a call to a nil func: the old link register
+ // is more useful in the stack trace.
+ if gp.sigpc != 0 {
+ c.set_lr(uint32(gp.sigpc))
+ }
+
+ // In case we are panicking from external C code
+ c.set_r10(uint32(uintptr(unsafe.Pointer(gp))))
+ c.set_pc(uint32(funcPC(sigpanic)))
+ return
+ }
+
+ if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
+ if sigsend(sig) {
+ return
+ }
+ }
+
+ if flags&_SigKill != 0 {
+ exit(2)
+ }
+
+ if flags&_SigThrow == 0 {
+ return
+ }
+
+ _g_.m.throwing = 1
+ _g_.m.caughtsig = gp
+ startpanic()
+
+ if sig < uint32(len(sigtable)) {
+ print(sigtable[sig].name, "\n")
+ } else {
+ print("Signal ", sig, "\n")
+ }
+
+ print("PC=", hex(c.pc()), "\n")
+ if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+ print("signal arrived during cgo execution\n")
+ gp = _g_.m.lockedg
+ }
+ print("\n")
+
+ var docrash bool
+ if gotraceback(&docrash) > 0 {
+ goroutineheader(gp)
+ tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp)
+ tracebackothers(gp)
+ print("\n")
+ dumpregs(c)
+ }
+
+ if docrash {
+ crash()
+ }
+
+ exit(2)
+}
diff --git a/src/runtime/signal_darwin.go b/src/runtime/signal_darwin.go
new file mode 100644
index 000000000..122648bc3
--- /dev/null
+++ b/src/runtime/signal_darwin.go
@@ -0,0 +1,45 @@
+// 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 runtime
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+var sigtable = [...]sigTabT{
+ /* 0 */ {0, "SIGNONE: no trap"},
+ /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+ /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+ /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+ /* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
+ /* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+ /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+ /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+ /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+ /* 9 */ {0, "SIGKILL: kill"},
+ /* 10 */ {_SigPanic, "SIGBUS: bus error"},
+ /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+ /* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+ /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+ /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+ /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+ /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+ /* 17 */ {0, "SIGSTOP: stop"},
+ /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+ /* 19 */ {0, "SIGCONT: continue after stop"},
+ /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+ /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+ /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+ /* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+ /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+ /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+ /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+ /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+ /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+ /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+ /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+ /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+}
diff --git a/src/runtime/signal_darwin_386.go b/src/runtime/signal_darwin_386.go
new file mode 100644
index 000000000..ccf30ef31
--- /dev/null
+++ b/src/runtime/signal_darwin_386.go
@@ -0,0 +1,34 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *regs32 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+func (c *sigctxt) eax() uint32 { return c.regs().eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().edx }
+func (c *sigctxt) edi() uint32 { return c.regs().edi }
+func (c *sigctxt) esi() uint32 { return c.regs().esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().esp }
+func (c *sigctxt) eip() uint32 { return c.regs().eip }
+func (c *sigctxt) eflags() uint32 { return c.regs().eflags }
+func (c *sigctxt) cs() uint32 { return c.regs().cs }
+func (c *sigctxt) fs() uint32 { return c.regs().fs }
+func (c *sigctxt) gs() uint32 { return c.regs().gs }
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 { return uint32(uintptr(unsafe.Pointer(c.info.si_addr))) }
+
+func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x }
+func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x }
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = (*byte)(unsafe.Pointer(uintptr(x))) }
diff --git a/src/runtime/signal_darwin_386.h b/src/runtime/signal_darwin_386.h
deleted file mode 100644
index 5459e10a1..000000000
--- a/src/runtime/signal_darwin_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext->ss)
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_darwin_amd64.go b/src/runtime/signal_darwin_amd64.go
new file mode 100644
index 000000000..409bc6d57
--- /dev/null
+++ b/src/runtime/signal_darwin_amd64.go
@@ -0,0 +1,42 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *regs64 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+func (c *sigctxt) rax() uint64 { return c.regs().rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().r15 }
+func (c *sigctxt) rip() uint64 { return c.regs().rip }
+func (c *sigctxt) rflags() uint64 { return c.regs().rflags }
+func (c *sigctxt) cs() uint64 { return c.regs().cs }
+func (c *sigctxt) fs() uint64 { return c.regs().fs }
+func (c *sigctxt) gs() uint64 { return c.regs().gs }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return uint64(uintptr(unsafe.Pointer(c.info.si_addr))) }
+
+func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x }
+func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x }
+func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) { c.info.si_addr = (*byte)(unsafe.Pointer(uintptr(x))) }
diff --git a/src/runtime/signal_darwin_amd64.h b/src/runtime/signal_darwin_amd64.h
deleted file mode 100644
index e3da6de3a..000000000
--- a/src/runtime/signal_darwin_amd64.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext->ss)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_dragonfly.go b/src/runtime/signal_dragonfly.go
new file mode 100644
index 000000000..d37e11a3e
--- /dev/null
+++ b/src/runtime/signal_dragonfly.go
@@ -0,0 +1,46 @@
+// 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 runtime
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+var sigtable = [...]sigTabT{
+ /* 0 */ {0, "SIGNONE: no trap"},
+ /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+ /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+ /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+ /* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
+ /* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+ /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+ /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+ /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+ /* 9 */ {0, "SIGKILL: kill"},
+ /* 10 */ {_SigPanic, "SIGBUS: bus error"},
+ /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+ /* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+ /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+ /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+ /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+ /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+ /* 17 */ {0, "SIGSTOP: stop"},
+ /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+ /* 19 */ {0, "SIGCONT: continue after stop"},
+ /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+ /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+ /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+ /* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+ /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+ /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+ /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+ /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+ /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+ /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+ /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+ /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+ /* 32 */ {_SigNotify, "SIGTHR: reserved"},
+}
diff --git a/src/runtime/signal_dragonfly_386.go b/src/runtime/signal_dragonfly_386.go
new file mode 100644
index 000000000..a0fec1309
--- /dev/null
+++ b/src/runtime/signal_dragonfly_386.go
@@ -0,0 +1,34 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *mcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
+func (c *sigctxt) eax() uint32 { return c.regs().mc_eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().mc_ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().mc_ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().mc_edx }
+func (c *sigctxt) edi() uint32 { return c.regs().mc_edi }
+func (c *sigctxt) esi() uint32 { return c.regs().mc_esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().mc_ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().mc_esp }
+func (c *sigctxt) eip() uint32 { return c.regs().mc_eip }
+func (c *sigctxt) eflags() uint32 { return c.regs().mc_eflags }
+func (c *sigctxt) cs() uint32 { return uint32(c.regs().mc_cs) }
+func (c *sigctxt) fs() uint32 { return uint32(c.regs().mc_fs) }
+func (c *sigctxt) gs() uint32 { return uint32(c.regs().mc_gs) }
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 { return uint32(c.info.si_addr) }
+
+func (c *sigctxt) set_eip(x uint32) { c.regs().mc_eip = x }
+func (c *sigctxt) set_esp(x uint32) { c.regs().mc_esp = x }
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = uintptr(x) }
diff --git a/src/runtime/signal_dragonfly_386.h b/src/runtime/signal_dragonfly_386.h
deleted file mode 100644
index a24f1ee96..000000000
--- a/src/runtime/signal_dragonfly_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).mc_eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).mc_ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).mc_ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).mc_edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).mc_edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).mc_esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).mc_ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).mc_esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).mc_eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_eflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_dragonfly_amd64.go b/src/runtime/signal_dragonfly_amd64.go
new file mode 100644
index 000000000..740959c58
--- /dev/null
+++ b/src/runtime/signal_dragonfly_amd64.go
@@ -0,0 +1,44 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *mcontext {
+ return (*mcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
+}
+func (c *sigctxt) rax() uint64 { return c.regs().mc_rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().mc_rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().mc_rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().mc_rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().mc_rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().mc_rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().mc_rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().mc_rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().mc_r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().mc_r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().mc_r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().mc_r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().mc_r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().mc_r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().mc_r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().mc_r15 }
+func (c *sigctxt) rip() uint64 { return c.regs().mc_rip }
+func (c *sigctxt) rflags() uint64 { return c.regs().mc_rflags }
+func (c *sigctxt) cs() uint64 { return uint64(c.regs().mc_cs) }
+func (c *sigctxt) fs() uint64 { return uint64(c.regs().mc_ss) }
+func (c *sigctxt) gs() uint64 { return uint64(c.regs().mc_ss) }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return uint64(c.info.si_addr) }
+
+func (c *sigctxt) set_rip(x uint64) { c.regs().mc_rip = x }
+func (c *sigctxt) set_rsp(x uint64) { c.regs().mc_rsp = x }
+func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) { c.info.si_addr = x }
diff --git a/src/runtime/signal_dragonfly_amd64.h b/src/runtime/signal_dragonfly_amd64.h
deleted file mode 100644
index 5b4f97782..000000000
--- a/src/runtime/signal_dragonfly_amd64.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).mc_rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).mc_rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).mc_rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).mc_rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).mc_rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).mc_rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).mc_rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).mc_rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).mc_r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).mc_r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).mc_r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).mc_r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).mc_r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).mc_r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).mc_r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).mc_r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).mc_rip)
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_rflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_ss)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_ss)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_freebsd.go b/src/runtime/signal_freebsd.go
new file mode 100644
index 000000000..1dbdb1bd9
--- /dev/null
+++ b/src/runtime/signal_freebsd.go
@@ -0,0 +1,46 @@
+// 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 runtime
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+var sigtable = [...]sigTabT{
+ /* 0 */ {0, "SIGNONE: no trap"},
+ /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+ /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+ /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+ /* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
+ /* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+ /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+ /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+ /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+ /* 9 */ {0, "SIGKILL: kill"},
+ /* 10 */ {_SigPanic, "SIGBUS: bus error"},
+ /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+ /* 12 */ {_SigNotify, "SIGSYS: bad system call"},
+ /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+ /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+ /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+ /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+ /* 17 */ {0, "SIGSTOP: stop"},
+ /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+ /* 19 */ {0, "SIGCONT: continue after stop"},
+ /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+ /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+ /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+ /* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+ /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+ /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+ /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+ /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+ /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+ /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+ /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+ /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+ /* 32 */ {_SigNotify, "SIGTHR: reserved"},
+}
diff --git a/src/runtime/signal_freebsd_386.go b/src/runtime/signal_freebsd_386.go
new file mode 100644
index 000000000..a0fec1309
--- /dev/null
+++ b/src/runtime/signal_freebsd_386.go
@@ -0,0 +1,34 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *mcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
+func (c *sigctxt) eax() uint32 { return c.regs().mc_eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().mc_ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().mc_ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().mc_edx }
+func (c *sigctxt) edi() uint32 { return c.regs().mc_edi }
+func (c *sigctxt) esi() uint32 { return c.regs().mc_esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().mc_ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().mc_esp }
+func (c *sigctxt) eip() uint32 { return c.regs().mc_eip }
+func (c *sigctxt) eflags() uint32 { return c.regs().mc_eflags }
+func (c *sigctxt) cs() uint32 { return uint32(c.regs().mc_cs) }
+func (c *sigctxt) fs() uint32 { return uint32(c.regs().mc_fs) }
+func (c *sigctxt) gs() uint32 { return uint32(c.regs().mc_gs) }
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 { return uint32(c.info.si_addr) }
+
+func (c *sigctxt) set_eip(x uint32) { c.regs().mc_eip = x }
+func (c *sigctxt) set_esp(x uint32) { c.regs().mc_esp = x }
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = uintptr(x) }
diff --git a/src/runtime/signal_freebsd_386.h b/src/runtime/signal_freebsd_386.h
deleted file mode 100644
index a24f1ee96..000000000
--- a/src/runtime/signal_freebsd_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).mc_eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).mc_ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).mc_ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).mc_edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).mc_edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).mc_esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).mc_ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).mc_esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).mc_eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_eflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_freebsd_amd64.go b/src/runtime/signal_freebsd_amd64.go
new file mode 100644
index 000000000..d10c883d4
--- /dev/null
+++ b/src/runtime/signal_freebsd_amd64.go
@@ -0,0 +1,44 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *mcontext {
+ return (*mcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
+}
+func (c *sigctxt) rax() uint64 { return c.regs().mc_rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().mc_rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().mc_rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().mc_rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().mc_rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().mc_rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().mc_rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().mc_rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().mc_r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().mc_r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().mc_r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().mc_r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().mc_r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().mc_r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().mc_r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().mc_r15 }
+func (c *sigctxt) rip() uint64 { return c.regs().mc_rip }
+func (c *sigctxt) rflags() uint64 { return c.regs().mc_rflags }
+func (c *sigctxt) cs() uint64 { return uint64(c.regs().mc_cs) }
+func (c *sigctxt) fs() uint64 { return uint64(c.regs().mc_fs) }
+func (c *sigctxt) gs() uint64 { return uint64(c.regs().mc_gs) }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return uint64(c.info.si_addr) }
+
+func (c *sigctxt) set_rip(x uint64) { c.regs().mc_rip = x }
+func (c *sigctxt) set_rsp(x uint64) { c.regs().mc_rsp = x }
+func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) { c.info.si_addr = x }
diff --git a/src/runtime/signal_freebsd_amd64.h b/src/runtime/signal_freebsd_amd64.h
deleted file mode 100644
index 7d35b7f85..000000000
--- a/src/runtime/signal_freebsd_amd64.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).mc_rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).mc_rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).mc_rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).mc_rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).mc_rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).mc_rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).mc_rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).mc_rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).mc_r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).mc_r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).mc_r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).mc_r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).mc_r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).mc_r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).mc_r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).mc_r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).mc_rip)
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_rflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_freebsd_arm.go b/src/runtime/signal_freebsd_arm.go
new file mode 100644
index 000000000..12de23d58
--- /dev/null
+++ b/src/runtime/signal_freebsd_arm.go
@@ -0,0 +1,48 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *mcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
+func (c *sigctxt) r0() uint32 { return c.regs().__gregs[0] }
+func (c *sigctxt) r1() uint32 { return c.regs().__gregs[1] }
+func (c *sigctxt) r2() uint32 { return c.regs().__gregs[2] }
+func (c *sigctxt) r3() uint32 { return c.regs().__gregs[3] }
+func (c *sigctxt) r4() uint32 { return c.regs().__gregs[4] }
+func (c *sigctxt) r5() uint32 { return c.regs().__gregs[5] }
+func (c *sigctxt) r6() uint32 { return c.regs().__gregs[6] }
+func (c *sigctxt) r7() uint32 { return c.regs().__gregs[7] }
+func (c *sigctxt) r8() uint32 { return c.regs().__gregs[8] }
+func (c *sigctxt) r9() uint32 { return c.regs().__gregs[9] }
+func (c *sigctxt) r10() uint32 { return c.regs().__gregs[10] }
+func (c *sigctxt) fp() uint32 { return c.regs().__gregs[11] }
+func (c *sigctxt) ip() uint32 { return c.regs().__gregs[12] }
+func (c *sigctxt) sp() uint32 { return c.regs().__gregs[13] }
+func (c *sigctxt) lr() uint32 { return c.regs().__gregs[14] }
+func (c *sigctxt) pc() uint32 { return c.regs().__gregs[15] }
+func (c *sigctxt) cpsr() uint32 { return c.regs().__gregs[16] }
+func (c *sigctxt) fault() uint32 { return uint32(c.info.si_addr) }
+func (c *sigctxt) trap() uint32 { return 0 }
+func (c *sigctxt) error() uint32 { return 0 }
+func (c *sigctxt) oldmask() uint32 { return 0 }
+
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 { return uint32(c.info.si_addr) }
+
+func (c *sigctxt) set_pc(x uint32) { c.regs().__gregs[15] = x }
+func (c *sigctxt) set_sp(x uint32) { c.regs().__gregs[13] = x }
+func (c *sigctxt) set_lr(x uint32) { c.regs().__gregs[14] = x }
+func (c *sigctxt) set_r10(x uint32) { c.regs().__gregs[10] = x }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) {
+ c.info.si_addr = uintptr(x)
+}
diff --git a/src/runtime/signal_freebsd_arm.h b/src/runtime/signal_freebsd_arm.h
deleted file mode 100644
index 87a45aa27..000000000
--- a/src/runtime/signal_freebsd_arm.h
+++ /dev/null
@@ -1,28 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[0])
-#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).__gregs[1])
-#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).__gregs[2])
-#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).__gregs[3])
-#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).__gregs[4])
-#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).__gregs[5])
-#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).__gregs[6])
-#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).__gregs[7])
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[8])
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[9])
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[10])
-#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).__gregs[11])
-#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).__gregs[12])
-#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).__gregs[13])
-#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).__gregs[14])
-#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[15])
-#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).__gregs[16])
-#define SIG_FAULT(info, ctxt) ((uintptr)(info)->si_addr)
-#define SIG_TRAP(info, ctxt) (0)
-#define SIG_ERROR(info, ctxt) (0)
-#define SIG_OLDMASK(info, ctxt) (0)
-#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code)
diff --git a/src/runtime/signal_linux.go b/src/runtime/signal_linux.go
new file mode 100644
index 000000000..1c3d6872b
--- /dev/null
+++ b/src/runtime/signal_linux.go
@@ -0,0 +1,78 @@
+// 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 runtime
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+var sigtable = [...]sigTabT{
+ /* 0 */ {0, "SIGNONE: no trap"},
+ /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+ /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+ /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+ /* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
+ /* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+ /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+ /* 7 */ {_SigPanic, "SIGBUS: bus error"},
+ /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+ /* 9 */ {0, "SIGKILL: kill"},
+ /* 10 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+ /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+ /* 12 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+ /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+ /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+ /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+ /* 16 */ {_SigThrow, "SIGSTKFLT: stack fault"},
+ /* 17 */ {_SigNotify, "SIGCHLD: child status has changed"},
+ /* 18 */ {0, "SIGCONT: continue"},
+ /* 19 */ {0, "SIGSTOP: stop, unblockable"},
+ /* 20 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+ /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+ /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+ /* 23 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+ /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+ /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+ /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+ /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+ /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+ /* 29 */ {_SigNotify, "SIGIO: i/o now possible"},
+ /* 30 */ {_SigNotify, "SIGPWR: power failure restart"},
+ /* 31 */ {_SigNotify, "SIGSYS: bad system call"},
+ /* 32 */ {0, "signal 32"}, /* SIGCANCEL; see issue 6997 */
+ /* 33 */ {0, "signal 33"}, /* SIGSETXID; see issue 3871 */
+ /* 34 */ {_SigNotify, "signal 34"},
+ /* 35 */ {_SigNotify, "signal 35"},
+ /* 36 */ {_SigNotify, "signal 36"},
+ /* 37 */ {_SigNotify, "signal 37"},
+ /* 38 */ {_SigNotify, "signal 38"},
+ /* 39 */ {_SigNotify, "signal 39"},
+ /* 40 */ {_SigNotify, "signal 40"},
+ /* 41 */ {_SigNotify, "signal 41"},
+ /* 42 */ {_SigNotify, "signal 42"},
+ /* 43 */ {_SigNotify, "signal 43"},
+ /* 44 */ {_SigNotify, "signal 44"},
+ /* 45 */ {_SigNotify, "signal 45"},
+ /* 46 */ {_SigNotify, "signal 46"},
+ /* 47 */ {_SigNotify, "signal 47"},
+ /* 48 */ {_SigNotify, "signal 48"},
+ /* 49 */ {_SigNotify, "signal 49"},
+ /* 50 */ {_SigNotify, "signal 50"},
+ /* 51 */ {_SigNotify, "signal 51"},
+ /* 52 */ {_SigNotify, "signal 52"},
+ /* 53 */ {_SigNotify, "signal 53"},
+ /* 54 */ {_SigNotify, "signal 54"},
+ /* 55 */ {_SigNotify, "signal 55"},
+ /* 56 */ {_SigNotify, "signal 56"},
+ /* 57 */ {_SigNotify, "signal 57"},
+ /* 58 */ {_SigNotify, "signal 58"},
+ /* 59 */ {_SigNotify, "signal 59"},
+ /* 60 */ {_SigNotify, "signal 60"},
+ /* 61 */ {_SigNotify, "signal 61"},
+ /* 62 */ {_SigNotify, "signal 62"},
+ /* 63 */ {_SigNotify, "signal 63"},
+ /* 64 */ {_SigNotify, "signal 64"},
+}
diff --git a/src/runtime/signal_linux_386.go b/src/runtime/signal_linux_386.go
new file mode 100644
index 000000000..085f66e89
--- /dev/null
+++ b/src/runtime/signal_linux_386.go
@@ -0,0 +1,36 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
+func (c *sigctxt) eax() uint32 { return c.regs().eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().edx }
+func (c *sigctxt) edi() uint32 { return c.regs().edi }
+func (c *sigctxt) esi() uint32 { return c.regs().esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().esp }
+func (c *sigctxt) eip() uint32 { return c.regs().eip }
+func (c *sigctxt) eflags() uint32 { return c.regs().eflags }
+func (c *sigctxt) cs() uint32 { return uint32(c.regs().cs) }
+func (c *sigctxt) fs() uint32 { return uint32(c.regs().fs) }
+func (c *sigctxt) gs() uint32 { return uint32(c.regs().gs) }
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr }
+
+func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x }
+func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x }
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) {
+ *(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x)
+}
diff --git a/src/runtime/signal_linux_386.h b/src/runtime/signal_linux_386.h
deleted file mode 100644
index f77f1c9d5..000000000
--- a/src/runtime/signal_linux_386.h
+++ /dev/null
@@ -1,24 +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.
-
-#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) (((uintptr*)(info))[2])
-
diff --git a/src/runtime/signal_linux_amd64.go b/src/runtime/signal_linux_amd64.go
new file mode 100644
index 000000000..5e339b8a4
--- /dev/null
+++ b/src/runtime/signal_linux_amd64.go
@@ -0,0 +1,46 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext {
+ return (*sigcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
+}
+func (c *sigctxt) rax() uint64 { return c.regs().rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().r15 }
+func (c *sigctxt) rip() uint64 { return c.regs().rip }
+func (c *sigctxt) rflags() uint64 { return c.regs().eflags }
+func (c *sigctxt) cs() uint64 { return uint64(c.regs().cs) }
+func (c *sigctxt) fs() uint64 { return uint64(c.regs().fs) }
+func (c *sigctxt) gs() uint64 { return uint64(c.regs().gs) }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
+
+func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x }
+func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x }
+func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+ *(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x)
+}
diff --git a/src/runtime/signal_linux_amd64.h b/src/runtime/signal_linux_amd64.h
deleted file mode 100644
index 5a9a3e5da..000000000
--- a/src/runtime/signal_linux_amd64.h
+++ /dev/null
@@ -1,32 +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.
-
-#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
-#define SIG_RFLAGS(info, ctxt) ((uint64)SIG_REGS(ctxt).eflags)
-
-#define SIG_CS(info, ctxt) ((uint64)SIG_REGS(ctxt).cs)
-#define SIG_FS(info, ctxt) ((uint64)SIG_REGS(ctxt).fs)
-#define SIG_GS(info, ctxt) ((uint64)SIG_REGS(ctxt).gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) (((uintptr*)(info))[2])
-
diff --git a/src/runtime/signal_linux_arm.go b/src/runtime/signal_linux_arm.go
new file mode 100644
index 000000000..bdb4314fa
--- /dev/null
+++ b/src/runtime/signal_linux_arm.go
@@ -0,0 +1,48 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
+func (c *sigctxt) r0() uint32 { return c.regs().r0 }
+func (c *sigctxt) r1() uint32 { return c.regs().r1 }
+func (c *sigctxt) r2() uint32 { return c.regs().r2 }
+func (c *sigctxt) r3() uint32 { return c.regs().r3 }
+func (c *sigctxt) r4() uint32 { return c.regs().r4 }
+func (c *sigctxt) r5() uint32 { return c.regs().r5 }
+func (c *sigctxt) r6() uint32 { return c.regs().r6 }
+func (c *sigctxt) r7() uint32 { return c.regs().r7 }
+func (c *sigctxt) r8() uint32 { return c.regs().r8 }
+func (c *sigctxt) r9() uint32 { return c.regs().r9 }
+func (c *sigctxt) r10() uint32 { return c.regs().r10 }
+func (c *sigctxt) fp() uint32 { return c.regs().fp }
+func (c *sigctxt) ip() uint32 { return c.regs().ip }
+func (c *sigctxt) sp() uint32 { return c.regs().sp }
+func (c *sigctxt) lr() uint32 { return c.regs().lr }
+func (c *sigctxt) pc() uint32 { return c.regs().pc }
+func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr }
+func (c *sigctxt) fault() uint32 { return c.regs().fault_address }
+func (c *sigctxt) trap() uint32 { return c.regs().trap_no }
+func (c *sigctxt) error() uint32 { return c.regs().error_code }
+func (c *sigctxt) oldmask() uint32 { return c.regs().oldmask }
+
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr }
+
+func (c *sigctxt) set_pc(x uint32) { c.regs().pc = x }
+func (c *sigctxt) set_sp(x uint32) { c.regs().sp = x }
+func (c *sigctxt) set_lr(x uint32) { c.regs().lr = x }
+func (c *sigctxt) set_r10(x uint32) { c.regs().r10 = x }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) {
+ *(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x)
+}
diff --git a/src/runtime/signal_linux_arm.h b/src/runtime/signal_linux_arm.h
deleted file mode 100644
index a674c0d57..000000000
--- a/src/runtime/signal_linux_arm.h
+++ /dev/null
@@ -1,28 +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.
-
-#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
-
-#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).arm_r0)
-#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).arm_r1)
-#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).arm_r2)
-#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).arm_r3)
-#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).arm_r4)
-#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).arm_r5)
-#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).arm_r6)
-#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).arm_r7)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).arm_r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).arm_r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).arm_r10)
-#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).arm_fp)
-#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).arm_ip)
-#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).arm_sp)
-#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).arm_lr)
-#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).arm_pc)
-#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).arm_cpsr)
-#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).fault_address)
-#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap_no)
-#define SIG_ERROR(info, ctxt) (SIG_REGS(ctxt).error_code)
-#define SIG_OLDMASK(info, ctxt) (SIG_REGS(ctxt).oldmask)
-#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code)
diff --git a/src/runtime/signal_linux_power64x.go b/src/runtime/signal_linux_power64x.go
new file mode 100644
index 000000000..0a406b31f
--- /dev/null
+++ b/src/runtime/signal_linux_power64x.go
@@ -0,0 +1,71 @@
+// 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.
+
+// +build linux
+// +build power64 power64le
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *ptregs { return (*ucontext)(c.ctxt).uc_mcontext.regs }
+func (c *sigctxt) r0() uint64 { return c.regs().gpr[0] }
+func (c *sigctxt) r1() uint64 { return c.regs().gpr[1] }
+func (c *sigctxt) r2() uint64 { return c.regs().gpr[2] }
+func (c *sigctxt) r3() uint64 { return c.regs().gpr[3] }
+func (c *sigctxt) r4() uint64 { return c.regs().gpr[4] }
+func (c *sigctxt) r5() uint64 { return c.regs().gpr[5] }
+func (c *sigctxt) r6() uint64 { return c.regs().gpr[6] }
+func (c *sigctxt) r7() uint64 { return c.regs().gpr[7] }
+func (c *sigctxt) r8() uint64 { return c.regs().gpr[8] }
+func (c *sigctxt) r9() uint64 { return c.regs().gpr[9] }
+func (c *sigctxt) r10() uint64 { return c.regs().gpr[10] }
+func (c *sigctxt) r11() uint64 { return c.regs().gpr[11] }
+func (c *sigctxt) r12() uint64 { return c.regs().gpr[12] }
+func (c *sigctxt) r13() uint64 { return c.regs().gpr[13] }
+func (c *sigctxt) r14() uint64 { return c.regs().gpr[14] }
+func (c *sigctxt) r15() uint64 { return c.regs().gpr[15] }
+func (c *sigctxt) r16() uint64 { return c.regs().gpr[16] }
+func (c *sigctxt) r17() uint64 { return c.regs().gpr[17] }
+func (c *sigctxt) r18() uint64 { return c.regs().gpr[18] }
+func (c *sigctxt) r19() uint64 { return c.regs().gpr[19] }
+func (c *sigctxt) r20() uint64 { return c.regs().gpr[20] }
+func (c *sigctxt) r21() uint64 { return c.regs().gpr[21] }
+func (c *sigctxt) r22() uint64 { return c.regs().gpr[22] }
+func (c *sigctxt) r23() uint64 { return c.regs().gpr[23] }
+func (c *sigctxt) r24() uint64 { return c.regs().gpr[24] }
+func (c *sigctxt) r25() uint64 { return c.regs().gpr[25] }
+func (c *sigctxt) r26() uint64 { return c.regs().gpr[26] }
+func (c *sigctxt) r27() uint64 { return c.regs().gpr[27] }
+func (c *sigctxt) r28() uint64 { return c.regs().gpr[28] }
+func (c *sigctxt) r29() uint64 { return c.regs().gpr[29] }
+func (c *sigctxt) r30() uint64 { return c.regs().gpr[30] }
+func (c *sigctxt) r31() uint64 { return c.regs().gpr[31] }
+func (c *sigctxt) sp() uint64 { return c.regs().gpr[1] }
+func (c *sigctxt) pc() uint64 { return c.regs().nip }
+func (c *sigctxt) trap() uint64 { return c.regs().trap }
+func (c *sigctxt) ctr() uint64 { return c.regs().ctr }
+func (c *sigctxt) link() uint64 { return c.regs().link }
+func (c *sigctxt) xer() uint64 { return c.regs().xer }
+func (c *sigctxt) ccr() uint64 { return c.regs().ccr }
+
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
+func (c *sigctxt) fault() uint64 { return c.regs().dar }
+
+func (c *sigctxt) set_r0(x uint64) { c.regs().gpr[0] = x }
+func (c *sigctxt) set_r30(x uint64) { c.regs().gpr[30] = x }
+func (c *sigctxt) set_pc(x uint64) { c.regs().nip = x }
+func (c *sigctxt) set_sp(x uint64) { c.regs().gpr[1] = x }
+func (c *sigctxt) set_link(x uint64) { c.regs().link = x }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+ *(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x)
+}
diff --git a/src/runtime/signal_nacl.go b/src/runtime/signal_nacl.go
new file mode 100644
index 000000000..122648bc3
--- /dev/null
+++ b/src/runtime/signal_nacl.go
@@ -0,0 +1,45 @@
+// 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 runtime
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+var sigtable = [...]sigTabT{
+ /* 0 */ {0, "SIGNONE: no trap"},
+ /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+ /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+ /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+ /* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
+ /* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+ /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+ /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+ /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+ /* 9 */ {0, "SIGKILL: kill"},
+ /* 10 */ {_SigPanic, "SIGBUS: bus error"},
+ /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+ /* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+ /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+ /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+ /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+ /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+ /* 17 */ {0, "SIGSTOP: stop"},
+ /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+ /* 19 */ {0, "SIGCONT: continue after stop"},
+ /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+ /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+ /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+ /* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+ /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+ /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+ /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+ /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+ /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+ /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+ /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+ /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+}
diff --git a/src/runtime/signal_nacl_386.go b/src/runtime/signal_nacl_386.go
new file mode 100644
index 000000000..0a1e7c6ea
--- /dev/null
+++ b/src/runtime/signal_nacl_386.go
@@ -0,0 +1,34 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *excregs386 { return &(*exccontext)(c.ctxt).regs }
+func (c *sigctxt) eax() uint32 { return c.regs().eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().edx }
+func (c *sigctxt) edi() uint32 { return c.regs().edi }
+func (c *sigctxt) esi() uint32 { return c.regs().esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().esp }
+func (c *sigctxt) eip() uint32 { return c.regs().eip }
+func (c *sigctxt) eflags() uint32 { return c.regs().eflags }
+func (c *sigctxt) cs() uint32 { return ^uint32(0) }
+func (c *sigctxt) fs() uint32 { return ^uint32(0) }
+func (c *sigctxt) gs() uint32 { return ^uint32(0) }
+func (c *sigctxt) sigcode() uint32 { return ^uint32(0) }
+func (c *sigctxt) sigaddr() uint32 { return 0 }
+
+func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x }
+func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x }
+func (c *sigctxt) set_sigcode(x uint32) {}
+func (c *sigctxt) set_sigaddr(x uint32) {}
diff --git a/src/runtime/signal_nacl_386.h b/src/runtime/signal_nacl_386.h
deleted file mode 100644
index c9481b5f4..000000000
--- a/src/runtime/signal_nacl_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs)
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
-
-#define SIG_CS(info, ctxt) (~0)
-#define SIG_FS(info, ctxt) (~0)
-#define SIG_GS(info, ctxt) (~0)
-
-#define SIG_CODE0(info, ctxt) (~0)
-#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/runtime/signal_nacl_amd64p32.go b/src/runtime/signal_nacl_amd64p32.go
new file mode 100644
index 000000000..024cebadd
--- /dev/null
+++ b/src/runtime/signal_nacl_amd64p32.go
@@ -0,0 +1,44 @@
+// 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 runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *excregsamd64 {
+ return &(*exccontext)(c.ctxt).regs
+}
+func (c *sigctxt) rax() uint64 { return c.regs().rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().r15 }
+func (c *sigctxt) rip() uint64 { return c.regs().rip }
+func (c *sigctxt) rflags() uint64 { return uint64(c.regs().rflags) }
+func (c *sigctxt) cs() uint64 { return ^uint64(0) }
+func (c *sigctxt) fs() uint64 { return ^uint64(0) }
+func (c *sigctxt) gs() uint64 { return ^uint64(0) }
+func (c *sigctxt) sigcode() uint64 { return ^uint64(0) }
+func (c *sigctxt) sigaddr() uint64 { return 0 }
+
+func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x }
+func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x }
+func (c *sigctxt) set_sigcode(x uint64) {}
+func (c *sigctxt) set_sigaddr(x uint64) {}
diff --git a/src/runtime/signal_nacl_amd64p32.h b/src/runtime/signal_nacl_amd64p32.h
deleted file mode 100644
index f62305cb5..000000000
--- a/src/runtime/signal_nacl_amd64p32.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs.regs64)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags)
-
-#define SIG_CS(info, ctxt) (~0)
-#define SIG_FS(info, ctxt) (~0)
-#define SIG_GS(info, ctxt) (~0)
-
-#define SIG_CODE0(info, ctxt) (~0)
-#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/runtime/signal_nacl_arm.go b/src/runtime/signal_nacl_arm.go
new file mode 100644
index 000000000..1aeaa4e42
--- /dev/null
+++ b/src/runtime/signal_nacl_arm.go
@@ -0,0 +1,47 @@
+// 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 runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *excregsarm { return &(*exccontext)(c.ctxt).regs }
+
+func (c *sigctxt) r0() uint32 { return c.regs().r0 }
+func (c *sigctxt) r1() uint32 { return c.regs().r1 }
+func (c *sigctxt) r2() uint32 { return c.regs().r2 }
+func (c *sigctxt) r3() uint32 { return c.regs().r3 }
+func (c *sigctxt) r4() uint32 { return c.regs().r4 }
+func (c *sigctxt) r5() uint32 { return c.regs().r5 }
+func (c *sigctxt) r6() uint32 { return c.regs().r6 }
+func (c *sigctxt) r7() uint32 { return c.regs().r7 }
+func (c *sigctxt) r8() uint32 { return c.regs().r8 }
+func (c *sigctxt) r9() uint32 { return c.regs().r9 }
+func (c *sigctxt) r10() uint32 { return c.regs().r10 }
+func (c *sigctxt) fp() uint32 { return c.regs().r11 }
+func (c *sigctxt) ip() uint32 { return c.regs().r12 }
+func (c *sigctxt) sp() uint32 { return c.regs().sp }
+func (c *sigctxt) lr() uint32 { return c.regs().lr }
+func (c *sigctxt) pc() uint32 { return c.regs().pc }
+func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr }
+func (c *sigctxt) fault() uint32 { return ^uint32(0) }
+func (c *sigctxt) trap() uint32 { return ^uint32(0) }
+func (c *sigctxt) error() uint32 { return ^uint32(0) }
+func (c *sigctxt) oldmask() uint32 { return ^uint32(0) }
+
+func (c *sigctxt) sigcode() uint32 { return 0 }
+func (c *sigctxt) sigaddr() uint32 { return 0 }
+
+func (c *sigctxt) set_pc(x uint32) { c.regs().pc = x }
+func (c *sigctxt) set_sp(x uint32) { c.regs().sp = x }
+func (c *sigctxt) set_lr(x uint32) { c.regs().lr = x }
+func (c *sigctxt) set_r10(x uint32) { c.regs().r10 = x }
+
+func (c *sigctxt) set_sigcode(x uint32) {}
+func (c *sigctxt) set_sigaddr(x uint32) {}
diff --git a/src/runtime/signal_nacl_arm.h b/src/runtime/signal_nacl_arm.h
deleted file mode 100644
index e5bbb211d..000000000
--- a/src/runtime/signal_nacl_arm.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-
-#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs)
-
-#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).r0)
-#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).r1)
-#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).r2)
-#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).r3)
-#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).r4)
-#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).r5)
-#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).r6)
-#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).r7)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
-#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).r11)
-#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).r12)
-#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).sp)
-#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).lr)
-#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).pc)
-#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).cpsr)
-#define SIG_FAULT(info, ctxt) (~0)
-#define SIG_TRAP(info, ctxt) (~0)
-#define SIG_ERROR(info, ctxt) (~0)
-#define SIG_OLDMASK(info, ctxt) (~0)
-#define SIG_CODE0(info, ctxt) (~0)
diff --git a/src/runtime/signal_netbsd.go b/src/runtime/signal_netbsd.go
new file mode 100644
index 000000000..78afc59ef
--- /dev/null
+++ b/src/runtime/signal_netbsd.go
@@ -0,0 +1,46 @@
+// 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 runtime
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+var sigtable = [...]sigTabT{
+ /* 0 */ {0, "SIGNONE: no trap"},
+ /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+ /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+ /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+ /* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
+ /* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+ /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+ /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+ /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+ /* 9 */ {0, "SIGKILL: kill"},
+ /* 10 */ {_SigPanic, "SIGBUS: bus error"},
+ /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+ /* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+ /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+ /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+ /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+ /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+ /* 17 */ {0, "SIGSTOP: stop"},
+ /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+ /* 19 */ {0, "SIGCONT: continue after stop"},
+ /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+ /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+ /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+ /* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+ /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+ /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+ /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+ /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+ /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+ /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+ /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+ /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+ /* 32 */ {_SigNotify, "SIGTHR: reserved"},
+}
diff --git a/src/runtime/signal_netbsd_386.go b/src/runtime/signal_netbsd_386.go
new file mode 100644
index 000000000..6702336ab
--- /dev/null
+++ b/src/runtime/signal_netbsd_386.go
@@ -0,0 +1,38 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *mcontextt { return &(*ucontextt)(c.ctxt).uc_mcontext }
+func (c *sigctxt) eax() uint32 { return c.regs().__gregs[_REG_EAX] }
+func (c *sigctxt) ebx() uint32 { return c.regs().__gregs[_REG_EBX] }
+func (c *sigctxt) ecx() uint32 { return c.regs().__gregs[_REG_ECX] }
+func (c *sigctxt) edx() uint32 { return c.regs().__gregs[_REG_EDX] }
+func (c *sigctxt) edi() uint32 { return c.regs().__gregs[_REG_EDI] }
+func (c *sigctxt) esi() uint32 { return c.regs().__gregs[_REG_ESI] }
+func (c *sigctxt) ebp() uint32 { return c.regs().__gregs[_REG_EBP] }
+func (c *sigctxt) esp() uint32 { return c.regs().__gregs[_REG_UESP] }
+func (c *sigctxt) eip() uint32 { return c.regs().__gregs[_REG_EIP] }
+func (c *sigctxt) eflags() uint32 { return c.regs().__gregs[_REG_EFL] }
+func (c *sigctxt) cs() uint32 { return uint32(c.regs().__gregs[_REG_CS]) }
+func (c *sigctxt) fs() uint32 { return uint32(c.regs().__gregs[_REG_FS]) }
+func (c *sigctxt) gs() uint32 { return uint32(c.regs().__gregs[_REG_GS]) }
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info._code) }
+func (c *sigctxt) sigaddr() uint32 {
+ return uint32(*(*uint32)(unsafe.Pointer(&c.info._reason[0])))
+}
+
+func (c *sigctxt) set_eip(x uint32) { c.regs().__gregs[_REG_EIP] = x }
+func (c *sigctxt) set_esp(x uint32) { c.regs().__gregs[_REG_UESP] = x }
+func (c *sigctxt) set_sigcode(x uint32) { c.info._code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) {
+ *(*uint32)(unsafe.Pointer(&c.info._reason[0])) = x
+}
diff --git a/src/runtime/signal_netbsd_386.h b/src/runtime/signal_netbsd_386.h
deleted file mode 100644
index d5a8a0c4b..000000000
--- a/src/runtime/signal_netbsd_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext)
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EAX])
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBX])
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ECX])
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDX])
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDI])
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ESI])
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBP])
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_UESP])
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EIP])
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EFL])
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS])
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS])
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS])
-
-#define SIG_CODE0(info, ctxt) ((info)->_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/runtime/signal_netbsd_amd64.go b/src/runtime/signal_netbsd_amd64.go
new file mode 100644
index 000000000..e22f4a724
--- /dev/null
+++ b/src/runtime/signal_netbsd_amd64.go
@@ -0,0 +1,48 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *mcontextt {
+ return (*mcontextt)(unsafe.Pointer(&(*ucontextt)(c.ctxt).uc_mcontext))
+}
+func (c *sigctxt) rax() uint64 { return c.regs().__gregs[_REG_RAX] }
+func (c *sigctxt) rbx() uint64 { return c.regs().__gregs[_REG_RBX] }
+func (c *sigctxt) rcx() uint64 { return c.regs().__gregs[_REG_RCX] }
+func (c *sigctxt) rdx() uint64 { return c.regs().__gregs[_REG_RDX] }
+func (c *sigctxt) rdi() uint64 { return c.regs().__gregs[_REG_RDI] }
+func (c *sigctxt) rsi() uint64 { return c.regs().__gregs[_REG_RSI] }
+func (c *sigctxt) rbp() uint64 { return c.regs().__gregs[_REG_RBP] }
+func (c *sigctxt) rsp() uint64 { return c.regs().__gregs[_REG_RSP] }
+func (c *sigctxt) r8() uint64 { return c.regs().__gregs[_REG_R8] }
+func (c *sigctxt) r9() uint64 { return c.regs().__gregs[_REG_R8] }
+func (c *sigctxt) r10() uint64 { return c.regs().__gregs[_REG_R10] }
+func (c *sigctxt) r11() uint64 { return c.regs().__gregs[_REG_R11] }
+func (c *sigctxt) r12() uint64 { return c.regs().__gregs[_REG_R12] }
+func (c *sigctxt) r13() uint64 { return c.regs().__gregs[_REG_R13] }
+func (c *sigctxt) r14() uint64 { return c.regs().__gregs[_REG_R14] }
+func (c *sigctxt) r15() uint64 { return c.regs().__gregs[_REG_R15] }
+func (c *sigctxt) rip() uint64 { return c.regs().__gregs[_REG_RIP] }
+func (c *sigctxt) rflags() uint64 { return c.regs().__gregs[_REG_RFLAGS] }
+func (c *sigctxt) cs() uint64 { return c.regs().__gregs[_REG_CS] }
+func (c *sigctxt) fs() uint64 { return c.regs().__gregs[_REG_FS] }
+func (c *sigctxt) gs() uint64 { return c.regs().__gregs[_REG_GS] }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info._code) }
+func (c *sigctxt) sigaddr() uint64 {
+ return uint64(*(*uint64)(unsafe.Pointer(&c.info._reason[0])))
+}
+
+func (c *sigctxt) set_rip(x uint64) { c.regs().__gregs[_REG_RIP] = x }
+func (c *sigctxt) set_rsp(x uint64) { c.regs().__gregs[_REG_RSP] = x }
+func (c *sigctxt) set_sigcode(x uint64) { c.info._code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+ *(*uint64)(unsafe.Pointer(&c.info._reason[0])) = x
+}
diff --git a/src/runtime/signal_netbsd_amd64.h b/src/runtime/signal_netbsd_amd64.h
deleted file mode 100644
index 7ec4cd98c..000000000
--- a/src/runtime/signal_netbsd_amd64.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RAX])
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBX])
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RCX])
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDX])
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDI])
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSI])
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBP])
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSP])
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R8])
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R9])
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R10])
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R11])
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R12])
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R13])
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R14])
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15])
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RIP])
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RFLAGS])
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS])
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS])
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS])
-
-#define SIG_CODE0(info, ctxt) ((info)->_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/runtime/signal_openbsd.go b/src/runtime/signal_openbsd.go
new file mode 100644
index 000000000..78afc59ef
--- /dev/null
+++ b/src/runtime/signal_openbsd.go
@@ -0,0 +1,46 @@
+// 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 runtime
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+var sigtable = [...]sigTabT{
+ /* 0 */ {0, "SIGNONE: no trap"},
+ /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+ /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+ /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+ /* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
+ /* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+ /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+ /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+ /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+ /* 9 */ {0, "SIGKILL: kill"},
+ /* 10 */ {_SigPanic, "SIGBUS: bus error"},
+ /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+ /* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+ /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+ /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+ /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+ /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+ /* 17 */ {0, "SIGSTOP: stop"},
+ /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+ /* 19 */ {0, "SIGCONT: continue after stop"},
+ /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+ /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+ /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+ /* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+ /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+ /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+ /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+ /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+ /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+ /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+ /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+ /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+ /* 32 */ {_SigNotify, "SIGTHR: reserved"},
+}
diff --git a/src/runtime/signal_openbsd_386.go b/src/runtime/signal_openbsd_386.go
new file mode 100644
index 000000000..c582a4493
--- /dev/null
+++ b/src/runtime/signal_openbsd_386.go
@@ -0,0 +1,41 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext {
+ return (*sigcontext)(c.ctxt)
+}
+
+func (c *sigctxt) eax() uint32 { return c.regs().sc_eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().sc_ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().sc_ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().sc_edx }
+func (c *sigctxt) edi() uint32 { return c.regs().sc_edi }
+func (c *sigctxt) esi() uint32 { return c.regs().sc_esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().sc_ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().sc_esp }
+func (c *sigctxt) eip() uint32 { return c.regs().sc_eip }
+func (c *sigctxt) eflags() uint32 { return c.regs().sc_eflags }
+func (c *sigctxt) cs() uint32 { return c.regs().sc_cs }
+func (c *sigctxt) fs() uint32 { return c.regs().sc_fs }
+func (c *sigctxt) gs() uint32 { return c.regs().sc_gs }
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 {
+ return *(*uint32)(add(unsafe.Pointer(c.info), 12))
+}
+
+func (c *sigctxt) set_eip(x uint32) { c.regs().sc_eip = x }
+func (c *sigctxt) set_esp(x uint32) { c.regs().sc_esp = x }
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) {
+ *(*uint32)(add(unsafe.Pointer(c.info), 12)) = x
+}
diff --git a/src/runtime/signal_openbsd_386.h b/src/runtime/signal_openbsd_386.h
deleted file mode 100644
index 6742db8d4..000000000
--- a/src/runtime/signal_openbsd_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (*(Sigcontext*)(ctxt))
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).sc_eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).sc_ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).sc_ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).sc_edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).sc_edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).sc_esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).sc_ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).sc_esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).sc_eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).sc_eflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).sc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).sc_fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)info + 12))
diff --git a/src/runtime/signal_openbsd_amd64.go b/src/runtime/signal_openbsd_amd64.go
new file mode 100644
index 000000000..4f0d19ddd
--- /dev/null
+++ b/src/runtime/signal_openbsd_amd64.go
@@ -0,0 +1,49 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext {
+ return (*sigcontext)(c.ctxt)
+}
+
+func (c *sigctxt) rax() uint64 { return c.regs().sc_rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().sc_rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().sc_rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().sc_rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().sc_rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().sc_rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().sc_rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().sc_rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().sc_r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().sc_r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().sc_r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().sc_r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().sc_r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().sc_r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().sc_r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().sc_r15 }
+func (c *sigctxt) rip() uint64 { return c.regs().sc_rip }
+func (c *sigctxt) rflags() uint64 { return c.regs().sc_rflags }
+func (c *sigctxt) cs() uint64 { return c.regs().sc_cs }
+func (c *sigctxt) fs() uint64 { return c.regs().sc_fs }
+func (c *sigctxt) gs() uint64 { return c.regs().sc_gs }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 {
+ return *(*uint64)(add(unsafe.Pointer(c.info), 16))
+}
+
+func (c *sigctxt) set_rip(x uint64) { c.regs().sc_rip = x }
+func (c *sigctxt) set_rsp(x uint64) { c.regs().sc_rsp = x }
+func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+ *(*uint64)(add(unsafe.Pointer(c.info), 16)) = x
+}
diff --git a/src/runtime/signal_openbsd_amd64.h b/src/runtime/signal_openbsd_amd64.h
deleted file mode 100644
index b46a5dfa6..000000000
--- a/src/runtime/signal_openbsd_amd64.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (*(Sigcontext*)(ctxt))
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).sc_rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).sc_rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).sc_rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).sc_rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).sc_rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).sc_rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).sc_rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).sc_rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).sc_r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).sc_r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).sc_r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).sc_r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).sc_r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).sc_r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).sc_r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).sc_r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).sc_rip)
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).sc_rflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).sc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).sc_fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)(info) + 16))
diff --git a/src/runtime/signals_plan9.h b/src/runtime/signal_plan9.go
index 4ee8e542c..37d24359b 100644
--- a/src/runtime/signals_plan9.h
+++ b/src/runtime/signal_plan9.go
@@ -2,62 +2,53 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "textflag.h"
+package runtime
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define E SigGoExit
+type sigTabT struct {
+ flags int
+ name []byte
+}
// Incoming notes are compared against this table using strncmp, so the
// order matters: longer patterns must appear before their prefixes.
-// There are #defined SIG constants in os_plan9.h for the table index of
-// some of these.
+// There are _SIG constants in os2_plan9.go for the table index of some
+// of these.
//
// If you add entries to this table, you must respect the prefix ordering
-// and also update the constant values is os_plan9.h.
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
+// and also update the constant values is os2_plan9.go.
+var sigtable = [...]sigTabT{
// Traps that we cannot be recovered.
- T, "sys: trap: debug exception",
- T, "sys: trap: invalid opcode",
+ {_SigThrow, []byte("sys: trap: debug exception")},
+ {_SigThrow, []byte("sys: trap: invalid opcode")},
// We can recover from some memory errors in runtime·sigpanic.
- P, "sys: trap: fault read addr", // SIGRFAULT
- P, "sys: trap: fault write addr", // SIGWFAULT
+ {_SigPanic, []byte("sys: trap: fault read addr")}, // SIGRFAULT
+ {_SigPanic, []byte("sys: trap: fault write addr")}, // SIGWFAULT
// We can also recover from math errors.
- P, "sys: trap: divide error", // SIGINTDIV
- P, "sys: fp:", // SIGFLOAT
+ {_SigPanic, []byte("sys: trap: divide error")}, // SIGINTDIV
+ {_SigPanic, []byte("sys: fp:")}, // SIGFLOAT
// All other traps are normally handled as if they were marked SigThrow.
// We mark them SigPanic here so that debug.SetPanicOnFault will work.
- P, "sys: trap:", // SIGTRAP
+ {_SigPanic, []byte("sys: trap:")}, // SIGTRAP
// Writes to a closed pipe can be handled if desired, otherwise they're ignored.
- N, "sys: write on closed pipe",
+ {_SigNotify, []byte("sys: write on closed pipe")},
// Other system notes are more serious and cannot be recovered.
- T, "sys:",
+ {_SigThrow, []byte("sys:")},
// Issued to all other procs when calling runtime·exit.
- E, "go: exit ",
+ {_SigGoExit, []byte("go: exit ")},
// Kill is sent by external programs to cause an exit.
- K, "kill",
+ {_SigKill, []byte("kill")},
// Interrupts can be handled if desired, otherwise they cause an exit.
- N+K, "interrupt",
- N+K, "hangup",
+ {_SigNotify + _SigKill, []byte("interrupt")},
+ {_SigNotify + _SigKill, []byte("hangup")},
// Alarms can be handled if desired, otherwise they're ignored.
- N, "alarm",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef E
+ {_SigNotify, []byte("alarm")},
+}
diff --git a/src/runtime/signal_power64x.go b/src/runtime/signal_power64x.go
new file mode 100644
index 000000000..fc83beb1b
--- /dev/null
+++ b/src/runtime/signal_power64x.go
@@ -0,0 +1,144 @@
+// 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.
+
+// +build linux
+// +build power64 power64le
+
+package runtime
+
+import "unsafe"
+
+func dumpregs(c *sigctxt) {
+ print("r0 ", hex(c.r0()), "\t")
+ print("r1 ", hex(c.r1()), "\n")
+ print("r2 ", hex(c.r2()), "\t")
+ print("r3 ", hex(c.r3()), "\n")
+ print("r4 ", hex(c.r4()), "\t")
+ print("r5 ", hex(c.r5()), "\n")
+ print("r6 ", hex(c.r6()), "\t")
+ print("r7 ", hex(c.r7()), "\n")
+ print("r8 ", hex(c.r8()), "\t")
+ print("r9 ", hex(c.r9()), "\n")
+ print("r10 ", hex(c.r10()), "\t")
+ print("r11 ", hex(c.r11()), "\n")
+ print("r12 ", hex(c.r12()), "\t")
+ print("r13 ", hex(c.r13()), "\n")
+ print("r14 ", hex(c.r14()), "\t")
+ print("r15 ", hex(c.r15()), "\n")
+ print("r16 ", hex(c.r16()), "\t")
+ print("r17 ", hex(c.r17()), "\n")
+ print("r18 ", hex(c.r18()), "\t")
+ print("r19 ", hex(c.r19()), "\n")
+ print("r20 ", hex(c.r20()), "\t")
+ print("r21 ", hex(c.r21()), "\n")
+ print("r22 ", hex(c.r22()), "\t")
+ print("r23 ", hex(c.r23()), "\n")
+ print("r24 ", hex(c.r24()), "\t")
+ print("r25 ", hex(c.r25()), "\n")
+ print("r26 ", hex(c.r26()), "\t")
+ print("r27 ", hex(c.r27()), "\n")
+ print("r28 ", hex(c.r28()), "\t")
+ print("r29 ", hex(c.r29()), "\n")
+ print("r30 ", hex(c.r30()), "\t")
+ print("r31 ", hex(c.r31()), "\n")
+ print("pc ", hex(c.pc()), "\t")
+ print("ctr ", hex(c.ctr()), "\n")
+ print("link ", hex(c.link()), "\t")
+ print("xer ", hex(c.xer()), "\n")
+ print("ccr ", hex(c.ccr()), "\t")
+ print("trap ", hex(c.trap()), "\n")
+}
+
+func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
+ _g_ := getg()
+ c := &sigctxt{info, ctxt}
+
+ if sig == _SIGPROF {
+ sigprof((*byte)(unsafe.Pointer(uintptr(c.pc()))), (*byte)(unsafe.Pointer(uintptr(c.sp()))), (*byte)(unsafe.Pointer(uintptr(c.link()))), gp, _g_.m)
+ return
+ }
+ flags := int32(_SigThrow)
+ if sig < uint32(len(sigtable)) {
+ flags = sigtable[sig].flags
+ }
+ if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp.sig = sig
+ gp.sigcode0 = uintptr(c.sigcode())
+ gp.sigcode1 = uintptr(c.fault())
+ gp.sigpc = uintptr(c.pc())
+
+ // We arrange link, and pc to pretend the panicking
+ // function calls sigpanic directly.
+ // Always save LINK to stack so that panics in leaf
+ // functions are correctly handled. This smashes
+ // the stack frame but we're not going back there
+ // anyway.
+ sp := c.sp() - ptrSize
+ c.set_sp(sp)
+ *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
+
+ // Don't bother saving PC if it's zero, which is
+ // probably a call to a nil func: the old link register
+ // is more useful in the stack trace.
+ if gp.sigpc != 0 {
+ c.set_link(uint64(gp.sigpc))
+ }
+
+ // In case we are panicking from external C code
+ c.set_r0(0)
+ c.set_r30(uint64(uintptr(unsafe.Pointer(gp))))
+ c.set_pc(uint64(funcPC(sigpanic)))
+ return
+ }
+
+ if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
+ if sigsend(sig) {
+ return
+ }
+ }
+
+ if flags&_SigKill != 0 {
+ exit(2)
+ }
+
+ if flags&_SigThrow == 0 {
+ return
+ }
+
+ _g_.m.throwing = 1
+ _g_.m.caughtsig = gp
+ startpanic()
+
+ if sig < uint32(len(sigtable)) {
+ print(sigtable[sig].name, "\n")
+ } else {
+ print("Signal ", sig, "\n")
+ }
+
+ print("PC=", hex(c.pc()), "\n")
+ if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+ print("signal arrived during cgo execution\n")
+ gp = _g_.m.lockedg
+ }
+ print("\n")
+
+ var docrash bool
+ if gotraceback(&docrash) > 0 {
+ goroutineheader(gp)
+ tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp)
+ tracebackothers(gp)
+ print("\n")
+ dumpregs(c)
+ }
+
+ if docrash {
+ crash()
+ }
+
+ exit(2)
+}
diff --git a/src/runtime/signal_solaris.go b/src/runtime/signal_solaris.go
new file mode 100644
index 000000000..2986c5aab
--- /dev/null
+++ b/src/runtime/signal_solaris.go
@@ -0,0 +1,88 @@
+// 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 runtime
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+var sigtable = [...]sigTabT{
+ /* 0 */ {0, "SIGNONE: no trap"},
+ /* 1 */ {_SigNotify + _SigKill, "SIGHUP: hangup"},
+ /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt (rubout)"},
+ /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit (ASCII FS)"},
+ /* 4 */ {_SigThrow, "SIGILL: illegal instruction (not reset when caught)"},
+ /* 5 */ {_SigThrow, "SIGTRAP: trace trap (not reset when caught)"},
+ /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: used by abort, replace SIGIOT in the future"},
+ /* 7 */ {_SigThrow, "SIGEMT: EMT instruction"},
+ /* 8 */ {_SigPanic, "SIGFPE: floating point exception"},
+ /* 9 */ {0, "SIGKILL: kill (cannot be caught or ignored)"},
+ /* 10 */ {_SigPanic, "SIGBUS: bus error"},
+ /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+ /* 12 */ {_SigThrow, "SIGSYS: bad argument to system call"},
+ /* 13 */ {_SigNotify, "SIGPIPE: write on a pipe with no one to read it"},
+ /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+ /* 15 */ {_SigNotify + _SigKill, "SIGTERM: software termination signal from kill"},
+ /* 16 */ {_SigNotify, "SIGUSR1: user defined signal 1"},
+ /* 17 */ {_SigNotify, "SIGUSR2: user defined signal 2"},
+ /* 18 */ {_SigNotify, "SIGCHLD: child status change alias (POSIX)"},
+ /* 19 */ {_SigNotify, "SIGPWR: power-fail restart"},
+ /* 20 */ {_SigNotify, "SIGWINCH: window size change"},
+ /* 21 */ {_SigNotify, "SIGURG: urgent socket condition"},
+ /* 22 */ {_SigNotify, "SIGPOLL: pollable event occured"},
+ /* 23 */ {_SigNotify + _SigDefault, "SIGSTOP: stop (cannot be caught or ignored)"},
+ /* 24 */ {0, "SIGTSTP: user stop requested from tty"},
+ /* 25 */ {0, "SIGCONT: stopped process has been continued"},
+ /* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background tty read attempted"},
+ /* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background tty write attempted"},
+ /* 28 */ {_SigNotify, "SIGVTALRM: virtual timer expired"},
+ /* 29 */ {_SigNotify, "SIGPROF: profiling timer expired"},
+ /* 30 */ {_SigNotify, "SIGXCPU: exceeded cpu limit"},
+ /* 31 */ {_SigNotify, "SIGXFSZ: exceeded file size limit"},
+ /* 32 */ {_SigNotify, "SIGWAITING: reserved signal no longer used by"},
+ /* 33 */ {_SigNotify, "SIGLWP: reserved signal no longer used by"},
+ /* 34 */ {_SigNotify, "SIGFREEZE: special signal used by CPR"},
+ /* 35 */ {_SigNotify, "SIGTHAW: special signal used by CPR"},
+ /* 36 */ {0, "SIGCANCEL: reserved signal for thread cancellation"},
+ /* 37 */ {_SigNotify, "SIGLOST: resource lost (eg, record-lock lost)"},
+ /* 38 */ {_SigNotify, "SIGXRES: resource control exceeded"},
+ /* 39 */ {_SigNotify, "SIGJVM1: reserved signal for Java Virtual Machine"},
+ /* 40 */ {_SigNotify, "SIGJVM2: reserved signal for Java Virtual Machine"},
+
+ /* TODO(aram): what should be do about these signals? _SigDefault or _SigNotify? is this set static? */
+ /* 41 */ {_SigNotify, "real time signal"},
+ /* 42 */ {_SigNotify, "real time signal"},
+ /* 43 */ {_SigNotify, "real time signal"},
+ /* 44 */ {_SigNotify, "real time signal"},
+ /* 45 */ {_SigNotify, "real time signal"},
+ /* 46 */ {_SigNotify, "real time signal"},
+ /* 47 */ {_SigNotify, "real time signal"},
+ /* 48 */ {_SigNotify, "real time signal"},
+ /* 49 */ {_SigNotify, "real time signal"},
+ /* 50 */ {_SigNotify, "real time signal"},
+ /* 51 */ {_SigNotify, "real time signal"},
+ /* 52 */ {_SigNotify, "real time signal"},
+ /* 53 */ {_SigNotify, "real time signal"},
+ /* 54 */ {_SigNotify, "real time signal"},
+ /* 55 */ {_SigNotify, "real time signal"},
+ /* 56 */ {_SigNotify, "real time signal"},
+ /* 57 */ {_SigNotify, "real time signal"},
+ /* 58 */ {_SigNotify, "real time signal"},
+ /* 59 */ {_SigNotify, "real time signal"},
+ /* 60 */ {_SigNotify, "real time signal"},
+ /* 61 */ {_SigNotify, "real time signal"},
+ /* 62 */ {_SigNotify, "real time signal"},
+ /* 63 */ {_SigNotify, "real time signal"},
+ /* 64 */ {_SigNotify, "real time signal"},
+ /* 65 */ {_SigNotify, "real time signal"},
+ /* 66 */ {_SigNotify, "real time signal"},
+ /* 67 */ {_SigNotify, "real time signal"},
+ /* 68 */ {_SigNotify, "real time signal"},
+ /* 69 */ {_SigNotify, "real time signal"},
+ /* 70 */ {_SigNotify, "real time signal"},
+ /* 71 */ {_SigNotify, "real time signal"},
+ /* 72 */ {_SigNotify, "real time signal"},
+}
diff --git a/src/runtime/signal_solaris_amd64.go b/src/runtime/signal_solaris_amd64.go
new file mode 100644
index 000000000..a577c8c19
--- /dev/null
+++ b/src/runtime/signal_solaris_amd64.go
@@ -0,0 +1,46 @@
+// 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 runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *mcontext {
+ return (*mcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
+}
+func (c *sigctxt) rax() uint64 { return uint64(c.regs().gregs[_REG_RAX]) }
+func (c *sigctxt) rbx() uint64 { return uint64(c.regs().gregs[_REG_RBX]) }
+func (c *sigctxt) rcx() uint64 { return uint64(c.regs().gregs[_REG_RCX]) }
+func (c *sigctxt) rdx() uint64 { return uint64(c.regs().gregs[_REG_RDX]) }
+func (c *sigctxt) rdi() uint64 { return uint64(c.regs().gregs[_REG_RDI]) }
+func (c *sigctxt) rsi() uint64 { return uint64(c.regs().gregs[_REG_RSI]) }
+func (c *sigctxt) rbp() uint64 { return uint64(c.regs().gregs[_REG_RBP]) }
+func (c *sigctxt) rsp() uint64 { return uint64(c.regs().gregs[_REG_RSP]) }
+func (c *sigctxt) r8() uint64 { return uint64(c.regs().gregs[_REG_R8]) }
+func (c *sigctxt) r9() uint64 { return uint64(c.regs().gregs[_REG_R9]) }
+func (c *sigctxt) r10() uint64 { return uint64(c.regs().gregs[_REG_R10]) }
+func (c *sigctxt) r11() uint64 { return uint64(c.regs().gregs[_REG_R11]) }
+func (c *sigctxt) r12() uint64 { return uint64(c.regs().gregs[_REG_R12]) }
+func (c *sigctxt) r13() uint64 { return uint64(c.regs().gregs[_REG_R13]) }
+func (c *sigctxt) r14() uint64 { return uint64(c.regs().gregs[_REG_R14]) }
+func (c *sigctxt) r15() uint64 { return uint64(c.regs().gregs[_REG_R15]) }
+func (c *sigctxt) rip() uint64 { return uint64(c.regs().gregs[_REG_RIP]) }
+func (c *sigctxt) rflags() uint64 { return uint64(c.regs().gregs[_REG_RFLAGS]) }
+func (c *sigctxt) cs() uint64 { return uint64(c.regs().gregs[_REG_CS]) }
+func (c *sigctxt) fs() uint64 { return uint64(c.regs().gregs[_REG_FS]) }
+func (c *sigctxt) gs() uint64 { return uint64(c.regs().gregs[_REG_GS]) }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return *(*uint64)(unsafe.Pointer(&c.info.__data[0])) }
+
+func (c *sigctxt) set_rip(x uint64) { c.regs().gregs[_REG_RIP] = int64(x) }
+func (c *sigctxt) set_rsp(x uint64) { c.regs().gregs[_REG_RSP] = int64(x) }
+func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+ *(*uintptr)(unsafe.Pointer(&c.info.__data[0])) = uintptr(x)
+}
diff --git a/src/runtime/signal_solaris_amd64.h b/src/runtime/signal_solaris_amd64.h
deleted file mode 100644
index c2e0a1549..000000000
--- a/src/runtime/signal_solaris_amd64.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RAX])
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RBX])
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RCX])
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RDX])
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RDI])
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RSI])
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RBP])
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RSP])
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R8])
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R9])
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R10])
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R11])
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R12])
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R13])
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R14])
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R15])
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RIP])
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RFLAGS])
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_CS])
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_FS])
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_GS])
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->__data[0])
diff --git a/src/runtime/signal_unix.c b/src/runtime/signal_unix.c
deleted file mode 100644
index 0e33ece49..000000000
--- a/src/runtime/signal_unix.c
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2012 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.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-
-extern SigTab runtime·sigtab[];
-
-void
-runtime·initsig(void)
-{
- int32 i;
- SigTab *t;
-
- // First call: basic setup.
- for(i = 0; i<NSIG; i++) {
- t = &runtime·sigtab[i];
- if((t->flags == 0) || (t->flags & SigDefault))
- continue;
-
- // For some signals, we respect an inherited SIG_IGN handler
- // rather than insist on installing our own default handler.
- // Even these signals can be fetched using the os/signal package.
- switch(i) {
- case SIGHUP:
- case SIGINT:
- if(runtime·getsig(i) == SIG_IGN) {
- t->flags = SigNotify | SigIgnored;
- continue;
- }
- }
-
- t->flags |= SigHandling;
- runtime·setsig(i, runtime·sighandler, true);
- }
-}
-
-void
-runtime·sigenable(uint32 sig)
-{
- SigTab *t;
-
- if(sig >= NSIG)
- return;
-
- t = &runtime·sigtab[sig];
- if((t->flags & SigNotify) && !(t->flags & SigHandling)) {
- t->flags |= SigHandling;
- if(runtime·getsig(sig) == SIG_IGN)
- t->flags |= SigIgnored;
- runtime·setsig(sig, runtime·sighandler, true);
- }
-}
-
-void
-runtime·sigdisable(uint32 sig)
-{
- SigTab *t;
-
- if(sig >= NSIG)
- return;
-
- t = &runtime·sigtab[sig];
- if((t->flags & SigNotify) && (t->flags & SigHandling)) {
- t->flags &= ~SigHandling;
- if(t->flags & SigIgnored)
- runtime·setsig(sig, SIG_IGN, true);
- else
- runtime·setsig(sig, SIG_DFL, true);
- }
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- Itimerval it;
-
- runtime·memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime·setitimer(ITIMER_PROF, &it, nil);
- } else {
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime·setitimer(ITIMER_PROF, &it, nil);
- }
- g->m->profilehz = hz;
-}
-
-void
-runtime·sigpipe(void)
-{
- runtime·setsig(SIGPIPE, SIG_DFL, false);
- runtime·raise(SIGPIPE);
-}
-
-void
-runtime·crash(void)
-{
-#ifdef GOOS_darwin
- // OS X core dumps are linear dumps of the mapped memory,
- // from the first virtual byte to the last, with zeros in the gaps.
- // Because of the way we arrange the address space on 64-bit systems,
- // this means the OS X core file will be >128 GB and even on a zippy
- // workstation can take OS X well over an hour to write (uninterruptible).
- // Save users from making that mistake.
- if(sizeof(void*) == 8)
- return;
-#endif
-
- runtime·unblocksignals();
- runtime·setsig(SIGABRT, SIG_DFL, false);
- runtime·raise(SIGABRT);
-}
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index ba77b6e7b..c457083dc 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -6,8 +6,6 @@
package runtime
-func sigpipe()
-
func os_sigpipe() {
- onM(sigpipe)
+ systemstack(sigpipe)
}
diff --git a/src/runtime/signals_android.h b/src/runtime/signals_android.h
deleted file mode 100644
index 5140d8a18..000000000
--- a/src/runtime/signals_android.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "signals_linux.h"
diff --git a/src/runtime/signals_darwin.h b/src/runtime/signals_darwin.h
deleted file mode 100644
index 8761e1bd9..000000000
--- a/src/runtime/signals_darwin.h
+++ /dev/null
@@ -1,53 +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.
-
-#include "textflag.h"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ N+K, "SIGHUP: terminal line hangup",
- /* 2 */ N+K, "SIGINT: interrupt",
- /* 3 */ N+T, "SIGQUIT: quit",
- /* 4 */ T, "SIGILL: illegal instruction",
- /* 5 */ T, "SIGTRAP: trace trap",
- /* 6 */ N+T, "SIGABRT: abort",
- /* 7 */ T, "SIGEMT: emulate instruction executed",
- /* 8 */ P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ P, "SIGBUS: bus error",
- /* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ T, "SIGSYS: bad system call",
- /* 13 */ N, "SIGPIPE: write to broken pipe",
- /* 14 */ N, "SIGALRM: alarm clock",
- /* 15 */ N+K, "SIGTERM: termination",
- /* 16 */ N, "SIGURG: urgent condition on socket",
- /* 17 */ 0, "SIGSTOP: stop",
- /* 18 */ N+D, "SIGTSTP: keyboard stop",
- /* 19 */ 0, "SIGCONT: continue after stop",
- /* 20 */ N, "SIGCHLD: child status has changed",
- /* 21 */ N+D, "SIGTTIN: background read from tty",
- /* 22 */ N+D, "SIGTTOU: background write to tty",
- /* 23 */ N, "SIGIO: i/o now possible",
- /* 24 */ N, "SIGXCPU: cpu limit exceeded",
- /* 25 */ N, "SIGXFSZ: file size limit exceeded",
- /* 26 */ N, "SIGVTALRM: virtual alarm clock",
- /* 27 */ N, "SIGPROF: profiling alarm clock",
- /* 28 */ N, "SIGWINCH: window size change",
- /* 29 */ N, "SIGINFO: status request from keyboard",
- /* 30 */ N, "SIGUSR1: user-defined signal 1",
- /* 31 */ N, "SIGUSR2: user-defined signal 2",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_dragonfly.h b/src/runtime/signals_dragonfly.h
deleted file mode 100644
index 07343a766..000000000
--- a/src/runtime/signals_dragonfly.h
+++ /dev/null
@@ -1,54 +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.
-
-#include "textflag.h"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ N+K, "SIGHUP: terminal line hangup",
- /* 2 */ N+K, "SIGINT: interrupt",
- /* 3 */ N+T, "SIGQUIT: quit",
- /* 4 */ T, "SIGILL: illegal instruction",
- /* 5 */ T, "SIGTRAP: trace trap",
- /* 6 */ N+T, "SIGABRT: abort",
- /* 7 */ T, "SIGEMT: emulate instruction executed",
- /* 8 */ P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ P, "SIGBUS: bus error",
- /* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ T, "SIGSYS: bad system call",
- /* 13 */ N, "SIGPIPE: write to broken pipe",
- /* 14 */ N, "SIGALRM: alarm clock",
- /* 15 */ N+K, "SIGTERM: termination",
- /* 16 */ N, "SIGURG: urgent condition on socket",
- /* 17 */ 0, "SIGSTOP: stop",
- /* 18 */ N+D, "SIGTSTP: keyboard stop",
- /* 19 */ 0, "SIGCONT: continue after stop",
- /* 20 */ N, "SIGCHLD: child status has changed",
- /* 21 */ N+D, "SIGTTIN: background read from tty",
- /* 22 */ N+D, "SIGTTOU: background write to tty",
- /* 23 */ N, "SIGIO: i/o now possible",
- /* 24 */ N, "SIGXCPU: cpu limit exceeded",
- /* 25 */ N, "SIGXFSZ: file size limit exceeded",
- /* 26 */ N, "SIGVTALRM: virtual alarm clock",
- /* 27 */ N, "SIGPROF: profiling alarm clock",
- /* 28 */ N, "SIGWINCH: window size change",
- /* 29 */ N, "SIGINFO: status request from keyboard",
- /* 30 */ N, "SIGUSR1: user-defined signal 1",
- /* 31 */ N, "SIGUSR2: user-defined signal 2",
- /* 32 */ N, "SIGTHR: reserved",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_freebsd.h b/src/runtime/signals_freebsd.h
deleted file mode 100644
index 39e0a947e..000000000
--- a/src/runtime/signals_freebsd.h
+++ /dev/null
@@ -1,54 +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.
-
-#include "textflag.h"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ N+K, "SIGHUP: terminal line hangup",
- /* 2 */ N+K, "SIGINT: interrupt",
- /* 3 */ N+T, "SIGQUIT: quit",
- /* 4 */ T, "SIGILL: illegal instruction",
- /* 5 */ T, "SIGTRAP: trace trap",
- /* 6 */ N+T, "SIGABRT: abort",
- /* 7 */ T, "SIGEMT: emulate instruction executed",
- /* 8 */ P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ P, "SIGBUS: bus error",
- /* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ N, "SIGSYS: bad system call",
- /* 13 */ N, "SIGPIPE: write to broken pipe",
- /* 14 */ N, "SIGALRM: alarm clock",
- /* 15 */ N+K, "SIGTERM: termination",
- /* 16 */ N, "SIGURG: urgent condition on socket",
- /* 17 */ 0, "SIGSTOP: stop",
- /* 18 */ N+D, "SIGTSTP: keyboard stop",
- /* 19 */ 0, "SIGCONT: continue after stop",
- /* 20 */ N, "SIGCHLD: child status has changed",
- /* 21 */ N+D, "SIGTTIN: background read from tty",
- /* 22 */ N+D, "SIGTTOU: background write to tty",
- /* 23 */ N, "SIGIO: i/o now possible",
- /* 24 */ N, "SIGXCPU: cpu limit exceeded",
- /* 25 */ N, "SIGXFSZ: file size limit exceeded",
- /* 26 */ N, "SIGVTALRM: virtual alarm clock",
- /* 27 */ N, "SIGPROF: profiling alarm clock",
- /* 28 */ N, "SIGWINCH: window size change",
- /* 29 */ N, "SIGINFO: status request from keyboard",
- /* 30 */ N, "SIGUSR1: user-defined signal 1",
- /* 31 */ N, "SIGUSR2: user-defined signal 2",
- /* 32 */ N, "SIGTHR: reserved",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_linux.h b/src/runtime/signals_linux.h
deleted file mode 100644
index 374107609..000000000
--- a/src/runtime/signals_linux.h
+++ /dev/null
@@ -1,86 +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.
-
-#include "textflag.h"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ N+K, "SIGHUP: terminal line hangup",
- /* 2 */ N+K, "SIGINT: interrupt",
- /* 3 */ N+T, "SIGQUIT: quit",
- /* 4 */ T, "SIGILL: illegal instruction",
- /* 5 */ T, "SIGTRAP: trace trap",
- /* 6 */ N+T, "SIGABRT: abort",
- /* 7 */ P, "SIGBUS: bus error",
- /* 8 */ P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ N, "SIGUSR1: user-defined signal 1",
- /* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ N, "SIGUSR2: user-defined signal 2",
- /* 13 */ N, "SIGPIPE: write to broken pipe",
- /* 14 */ N, "SIGALRM: alarm clock",
- /* 15 */ N+K, "SIGTERM: termination",
- /* 16 */ T, "SIGSTKFLT: stack fault",
- /* 17 */ N, "SIGCHLD: child status has changed",
- /* 18 */ 0, "SIGCONT: continue",
- /* 19 */ 0, "SIGSTOP: stop, unblockable",
- /* 20 */ N+D, "SIGTSTP: keyboard stop",
- /* 21 */ N+D, "SIGTTIN: background read from tty",
- /* 22 */ N+D, "SIGTTOU: background write to tty",
- /* 23 */ N, "SIGURG: urgent condition on socket",
- /* 24 */ N, "SIGXCPU: cpu limit exceeded",
- /* 25 */ N, "SIGXFSZ: file size limit exceeded",
- /* 26 */ N, "SIGVTALRM: virtual alarm clock",
- /* 27 */ N, "SIGPROF: profiling alarm clock",
- /* 28 */ N, "SIGWINCH: window size change",
- /* 29 */ N, "SIGIO: i/o now possible",
- /* 30 */ N, "SIGPWR: power failure restart",
- /* 31 */ N, "SIGSYS: bad system call",
- /* 32 */ 0, "signal 32", /* SIGCANCEL; see issue 6997 */
- /* 33 */ 0, "signal 33", /* SIGSETXID; see issue 3871 */
- /* 34 */ N, "signal 34",
- /* 35 */ N, "signal 35",
- /* 36 */ N, "signal 36",
- /* 37 */ N, "signal 37",
- /* 38 */ N, "signal 38",
- /* 39 */ N, "signal 39",
- /* 40 */ N, "signal 40",
- /* 41 */ N, "signal 41",
- /* 42 */ N, "signal 42",
- /* 43 */ N, "signal 43",
- /* 44 */ N, "signal 44",
- /* 45 */ N, "signal 45",
- /* 46 */ N, "signal 46",
- /* 47 */ N, "signal 47",
- /* 48 */ N, "signal 48",
- /* 49 */ N, "signal 49",
- /* 50 */ N, "signal 50",
- /* 51 */ N, "signal 51",
- /* 52 */ N, "signal 52",
- /* 53 */ N, "signal 53",
- /* 54 */ N, "signal 54",
- /* 55 */ N, "signal 55",
- /* 56 */ N, "signal 56",
- /* 57 */ N, "signal 57",
- /* 58 */ N, "signal 58",
- /* 59 */ N, "signal 59",
- /* 60 */ N, "signal 60",
- /* 61 */ N, "signal 61",
- /* 62 */ N, "signal 62",
- /* 63 */ N, "signal 63",
- /* 64 */ N, "signal 64",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_nacl.h b/src/runtime/signals_nacl.h
deleted file mode 100644
index 8761e1bd9..000000000
--- a/src/runtime/signals_nacl.h
+++ /dev/null
@@ -1,53 +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.
-
-#include "textflag.h"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ N+K, "SIGHUP: terminal line hangup",
- /* 2 */ N+K, "SIGINT: interrupt",
- /* 3 */ N+T, "SIGQUIT: quit",
- /* 4 */ T, "SIGILL: illegal instruction",
- /* 5 */ T, "SIGTRAP: trace trap",
- /* 6 */ N+T, "SIGABRT: abort",
- /* 7 */ T, "SIGEMT: emulate instruction executed",
- /* 8 */ P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ P, "SIGBUS: bus error",
- /* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ T, "SIGSYS: bad system call",
- /* 13 */ N, "SIGPIPE: write to broken pipe",
- /* 14 */ N, "SIGALRM: alarm clock",
- /* 15 */ N+K, "SIGTERM: termination",
- /* 16 */ N, "SIGURG: urgent condition on socket",
- /* 17 */ 0, "SIGSTOP: stop",
- /* 18 */ N+D, "SIGTSTP: keyboard stop",
- /* 19 */ 0, "SIGCONT: continue after stop",
- /* 20 */ N, "SIGCHLD: child status has changed",
- /* 21 */ N+D, "SIGTTIN: background read from tty",
- /* 22 */ N+D, "SIGTTOU: background write to tty",
- /* 23 */ N, "SIGIO: i/o now possible",
- /* 24 */ N, "SIGXCPU: cpu limit exceeded",
- /* 25 */ N, "SIGXFSZ: file size limit exceeded",
- /* 26 */ N, "SIGVTALRM: virtual alarm clock",
- /* 27 */ N, "SIGPROF: profiling alarm clock",
- /* 28 */ N, "SIGWINCH: window size change",
- /* 29 */ N, "SIGINFO: status request from keyboard",
- /* 30 */ N, "SIGUSR1: user-defined signal 1",
- /* 31 */ N, "SIGUSR2: user-defined signal 2",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_netbsd.h b/src/runtime/signals_netbsd.h
deleted file mode 100644
index 950a2fe62..000000000
--- a/src/runtime/signals_netbsd.h
+++ /dev/null
@@ -1,54 +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.
-
-#include "textflag.h"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ N+K, "SIGHUP: terminal line hangup",
- /* 2 */ N+K, "SIGINT: interrupt",
- /* 3 */ N+T, "SIGQUIT: quit",
- /* 4 */ T, "SIGILL: illegal instruction",
- /* 5 */ T, "SIGTRAP: trace trap",
- /* 6 */ N+T, "SIGABRT: abort",
- /* 7 */ T, "SIGEMT: emulate instruction executed",
- /* 8 */ P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ P, "SIGBUS: bus error",
- /* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ T, "SIGSYS: bad system call",
- /* 13 */ N, "SIGPIPE: write to broken pipe",
- /* 14 */ N, "SIGALRM: alarm clock",
- /* 15 */ N+K, "SIGTERM: termination",
- /* 16 */ N, "SIGURG: urgent condition on socket",
- /* 17 */ 0, "SIGSTOP: stop",
- /* 18 */ N+D, "SIGTSTP: keyboard stop",
- /* 19 */ 0, "SIGCONT: continue after stop",
- /* 20 */ N, "SIGCHLD: child status has changed",
- /* 21 */ N+D, "SIGTTIN: background read from tty",
- /* 22 */ N+D, "SIGTTOU: background write to tty",
- /* 23 */ N, "SIGIO: i/o now possible",
- /* 24 */ N, "SIGXCPU: cpu limit exceeded",
- /* 25 */ N, "SIGXFSZ: file size limit exceeded",
- /* 26 */ N, "SIGVTALRM: virtual alarm clock",
- /* 27 */ N, "SIGPROF: profiling alarm clock",
- /* 28 */ N, "SIGWINCH: window size change",
- /* 29 */ N, "SIGINFO: status request from keyboard",
- /* 30 */ N, "SIGUSR1: user-defined signal 1",
- /* 31 */ N, "SIGUSR2: user-defined signal 2",
- /* 32 */ N, "SIGTHR: reserved",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_openbsd.h b/src/runtime/signals_openbsd.h
deleted file mode 100644
index 950a2fe62..000000000
--- a/src/runtime/signals_openbsd.h
+++ /dev/null
@@ -1,54 +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.
-
-#include "textflag.h"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ N+K, "SIGHUP: terminal line hangup",
- /* 2 */ N+K, "SIGINT: interrupt",
- /* 3 */ N+T, "SIGQUIT: quit",
- /* 4 */ T, "SIGILL: illegal instruction",
- /* 5 */ T, "SIGTRAP: trace trap",
- /* 6 */ N+T, "SIGABRT: abort",
- /* 7 */ T, "SIGEMT: emulate instruction executed",
- /* 8 */ P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ P, "SIGBUS: bus error",
- /* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ T, "SIGSYS: bad system call",
- /* 13 */ N, "SIGPIPE: write to broken pipe",
- /* 14 */ N, "SIGALRM: alarm clock",
- /* 15 */ N+K, "SIGTERM: termination",
- /* 16 */ N, "SIGURG: urgent condition on socket",
- /* 17 */ 0, "SIGSTOP: stop",
- /* 18 */ N+D, "SIGTSTP: keyboard stop",
- /* 19 */ 0, "SIGCONT: continue after stop",
- /* 20 */ N, "SIGCHLD: child status has changed",
- /* 21 */ N+D, "SIGTTIN: background read from tty",
- /* 22 */ N+D, "SIGTTOU: background write to tty",
- /* 23 */ N, "SIGIO: i/o now possible",
- /* 24 */ N, "SIGXCPU: cpu limit exceeded",
- /* 25 */ N, "SIGXFSZ: file size limit exceeded",
- /* 26 */ N, "SIGVTALRM: virtual alarm clock",
- /* 27 */ N, "SIGPROF: profiling alarm clock",
- /* 28 */ N, "SIGWINCH: window size change",
- /* 29 */ N, "SIGINFO: status request from keyboard",
- /* 30 */ N, "SIGUSR1: user-defined signal 1",
- /* 31 */ N, "SIGUSR2: user-defined signal 2",
- /* 32 */ N, "SIGTHR: reserved",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_solaris.h b/src/runtime/signals_solaris.h
deleted file mode 100644
index 1f0a65ea6..000000000
--- a/src/runtime/signals_solaris.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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.
-
-#include "textflag.h"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ N+K, "SIGHUP: hangup",
- /* 2 */ N+K, "SIGINT: interrupt (rubout)",
- /* 3 */ N+T, "SIGQUIT: quit (ASCII FS)",
- /* 4 */ T, "SIGILL: illegal instruction (not reset when caught)",
- /* 5 */ T, "SIGTRAP: trace trap (not reset when caught)",
- /* 6 */ N+T, "SIGABRT: used by abort, replace SIGIOT in the future",
- /* 7 */ T, "SIGEMT: EMT instruction",
- /* 8 */ P, "SIGFPE: floating point exception",
- /* 9 */ 0, "SIGKILL: kill (cannot be caught or ignored)",
- /* 10 */ P, "SIGBUS: bus error",
- /* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ T, "SIGSYS: bad argument to system call",
- /* 13 */ N, "SIGPIPE: write on a pipe with no one to read it",
- /* 14 */ N, "SIGALRM: alarm clock",
- /* 15 */ N+K, "SIGTERM: software termination signal from kill",
- /* 16 */ N, "SIGUSR1: user defined signal 1",
- /* 17 */ N, "SIGUSR2: user defined signal 2",
- /* 18 */ N, "SIGCLD: child status change",
- /* 18 */ N, "SIGCHLD: child status change alias (POSIX)",
- /* 19 */ N, "SIGPWR: power-fail restart",
- /* 20 */ N, "SIGWINCH: window size change",
- /* 21 */ N, "SIGURG: urgent socket condition",
- /* 22 */ N, "SIGPOLL: pollable event occured",
- /* 23 */ N+D, "SIGSTOP: stop (cannot be caught or ignored)",
- /* 24 */ 0, "SIGTSTP: user stop requested from tty",
- /* 25 */ 0, "SIGCONT: stopped process has been continued",
- /* 26 */ N+D, "SIGTTIN: background tty read attempted",
- /* 27 */ N+D, "SIGTTOU: background tty write attempted",
- /* 28 */ N, "SIGVTALRM: virtual timer expired",
- /* 29 */ N, "SIGPROF: profiling timer expired",
- /* 30 */ N, "SIGXCPU: exceeded cpu limit",
- /* 31 */ N, "SIGXFSZ: exceeded file size limit",
- /* 32 */ N, "SIGWAITING: reserved signal no longer used by",
- /* 33 */ N, "SIGLWP: reserved signal no longer used by",
- /* 34 */ N, "SIGFREEZE: special signal used by CPR",
- /* 35 */ N, "SIGTHAW: special signal used by CPR",
- /* 36 */ 0, "SIGCANCEL: reserved signal for thread cancellation",
- /* 37 */ N, "SIGLOST: resource lost (eg, record-lock lost)",
- /* 38 */ N, "SIGXRES: resource control exceeded",
- /* 39 */ N, "SIGJVM1: reserved signal for Java Virtual Machine",
- /* 40 */ N, "SIGJVM2: reserved signal for Java Virtual Machine",
-
- /* TODO(aram): what should be do about these signals? D or N? is this set static? */
- /* 41 */ N, "real time signal",
- /* 42 */ N, "real time signal",
- /* 43 */ N, "real time signal",
- /* 44 */ N, "real time signal",
- /* 45 */ N, "real time signal",
- /* 46 */ N, "real time signal",
- /* 47 */ N, "real time signal",
- /* 48 */ N, "real time signal",
- /* 49 */ N, "real time signal",
- /* 50 */ N, "real time signal",
- /* 51 */ N, "real time signal",
- /* 52 */ N, "real time signal",
- /* 53 */ N, "real time signal",
- /* 54 */ N, "real time signal",
- /* 55 */ N, "real time signal",
- /* 56 */ N, "real time signal",
- /* 57 */ N, "real time signal",
- /* 58 */ N, "real time signal",
- /* 59 */ N, "real time signal",
- /* 60 */ N, "real time signal",
- /* 61 */ N, "real time signal",
- /* 62 */ N, "real time signal",
- /* 63 */ N, "real time signal",
- /* 64 */ N, "real time signal",
- /* 65 */ N, "real time signal",
- /* 66 */ N, "real time signal",
- /* 67 */ N, "real time signal",
- /* 68 */ N, "real time signal",
- /* 69 */ N, "real time signal",
- /* 70 */ N, "real time signal",
- /* 71 */ N, "real time signal",
- /* 72 */ N, "real time signal",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/sigpanic_unix.go b/src/runtime/sigpanic_unix.go
index 68079859b..7bf2c1540 100644
--- a/src/runtime/sigpanic_unix.go
+++ b/src/runtime/sigpanic_unix.go
@@ -6,8 +6,6 @@
package runtime
-func signame(int32) *byte
-
func sigpanic() {
g := getg()
if !canpanic(g) {
@@ -36,5 +34,10 @@ func sigpanic() {
}
panicfloat()
}
- panic(errorString(gostringnocopy(signame(g.sig))))
+
+ if g.sig >= uint32(len(sigtable)) {
+ // can't happen: we looked up g.sig in sigtable to decide to call sigpanic
+ gothrow("unexpected signal value")
+ }
+ panic(errorString(sigtable[g.sig].name))
}
diff --git a/src/runtime/sigqueue.go b/src/runtime/sigqueue.go
index 2d9c24d2d..82ead228f 100644
--- a/src/runtime/sigqueue.go
+++ b/src/runtime/sigqueue.go
@@ -45,7 +45,7 @@ const (
// Called from sighandler to send a signal back out of the signal handling thread.
// Reports whether the signal was sent. If not, the caller typically crashes the program.
-func sigsend(s int32) bool {
+func sigsend(s uint32) bool {
bit := uint32(1) << uint(s&31)
if !sig.inuse || s < 0 || int(s) >= 32*len(sig.wanted) || sig.wanted[s/32]&bit == 0 {
return false
@@ -139,7 +139,7 @@ func signal_enable(s uint32) {
return
}
sig.wanted[s/32] |= 1 << (s & 31)
- sigenable_go(s)
+ sigenable(s)
}
// Must only be called from a single goroutine at a time.
@@ -148,7 +148,7 @@ func signal_disable(s uint32) {
return
}
sig.wanted[s/32] &^= 1 << (s & 31)
- sigdisable_go(s)
+ sigdisable(s)
}
// This runs on a foreign stack, without an m or a g. No stack split.
@@ -156,18 +156,3 @@ func signal_disable(s uint32) {
func badsignal(sig uintptr) {
cgocallback(unsafe.Pointer(funcPC(sigsend)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
}
-
-func sigenable_m()
-func sigdisable_m()
-
-func sigenable_go(s uint32) {
- g := getg()
- g.m.scalararg[0] = uintptr(s)
- onM(sigenable_m)
-}
-
-func sigdisable_go(s uint32) {
- g := getg()
- g.m.scalararg[0] = uintptr(s)
- onM(sigdisable_m)
-}
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index 171087d7f..93cea5cc3 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -22,11 +22,11 @@ func makeslice(t *slicetype, len64 int64, cap64 int64) sliceStruct {
// but since the cap is only being supplied implicitly, saying len is clearer.
// See issue 4085.
len := int(len64)
- if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > maxmem/uintptr(t.elem.size) {
+ if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > _MaxMem/uintptr(t.elem.size) {
panic(errorString("makeslice: len out of range"))
}
cap := int(cap64)
- if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > maxmem/uintptr(t.elem.size) {
+ if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
panic(errorString("makeslice: cap out of range"))
}
p := newarray(t.elem, uintptr(cap))
@@ -42,7 +42,7 @@ func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct {
cap64 := int64(old.cap) + n
cap := int(cap64)
- if int64(cap) != cap64 || cap < old.cap || t.elem.size > 0 && uintptr(cap) > maxmem/uintptr(t.elem.size) {
+ if int64(cap) != cap64 || cap < old.cap || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
panic(errorString("growslice: cap out of range"))
}
@@ -72,7 +72,7 @@ func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct {
}
}
- if uintptr(newcap) >= maxmem/uintptr(et.size) {
+ if uintptr(newcap) >= _MaxMem/uintptr(et.size) {
panic(errorString("growslice: cap out of range"))
}
lenmem := uintptr(old.len) * uintptr(et.size)
diff --git a/src/runtime/softfloat64.go b/src/runtime/softfloat64.go
index 4fcf8f269..c157a14e2 100644
--- a/src/runtime/softfloat64.go
+++ b/src/runtime/softfloat64.go
@@ -340,7 +340,7 @@ func f32to64(f uint32) uint64 {
return fpack64(fs64, uint64(fm)<<d, fe, 0)
}
-func fcmp64(f, g uint64) (cmp int, isnan bool) {
+func fcmp64(f, g uint64) (cmp int32, isnan bool) {
fs, fm, _, fi, fn := funpack64(f)
gs, gm, _, gi, gn := funpack64(g)
@@ -486,13 +486,13 @@ again2:
// callable from C
-func fadd64c(f, g uint64, ret *uint64) { *ret = fadd64(f, g) }
-func fsub64c(f, g uint64, ret *uint64) { *ret = fsub64(f, g) }
-func fmul64c(f, g uint64, ret *uint64) { *ret = fmul64(f, g) }
-func fdiv64c(f, g uint64, ret *uint64) { *ret = fdiv64(f, g) }
-func fneg64c(f uint64, ret *uint64) { *ret = fneg64(f) }
-func f32to64c(f uint32, ret *uint64) { *ret = f32to64(f) }
-func f64to32c(f uint64, ret *uint32) { *ret = f64to32(f) }
-func fcmp64c(f, g uint64, ret *int, retnan *bool) { *ret, *retnan = fcmp64(f, g) }
-func fintto64c(val int64, ret *uint64) { *ret = fintto64(val) }
-func f64tointc(f uint64, ret *int64, retok *bool) { *ret, *retok = f64toint(f) }
+func fadd64c(f, g uint64, ret *uint64) { *ret = fadd64(f, g) }
+func fsub64c(f, g uint64, ret *uint64) { *ret = fsub64(f, g) }
+func fmul64c(f, g uint64, ret *uint64) { *ret = fmul64(f, g) }
+func fdiv64c(f, g uint64, ret *uint64) { *ret = fdiv64(f, g) }
+func fneg64c(f uint64, ret *uint64) { *ret = fneg64(f) }
+func f32to64c(f uint32, ret *uint64) { *ret = f32to64(f) }
+func f64to32c(f uint64, ret *uint32) { *ret = f64to32(f) }
+func fcmp64c(f, g uint64, ret *int32, retnan *bool) { *ret, *retnan = fcmp64(f, g) }
+func fintto64c(val int64, ret *uint64) { *ret = fintto64(val) }
+func f64tointc(f uint64, ret *int64, retok *bool) { *ret, *retok = f64toint(f) }
diff --git a/src/runtime/softfloat64_test.go b/src/runtime/softfloat64_test.go
index df63010fb..e10887283 100644
--- a/src/runtime/softfloat64_test.go
+++ b/src/runtime/softfloat64_test.go
@@ -182,7 +182,7 @@ func hwcmp(f, g float64) (cmp int, isnan bool) {
func testcmp(t *testing.T, f, g float64) {
hcmp, hisnan := hwcmp(f, g)
scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g))
- if hcmp != scmp || hisnan != sisnan {
+ if int32(hcmp) != scmp || hisnan != sisnan {
err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan)
}
}
diff --git a/src/runtime/softfloat_arm.c b/src/runtime/softfloat_arm.c
deleted file mode 100644
index 3f3f33a19..000000000
--- a/src/runtime/softfloat_arm.c
+++ /dev/null
@@ -1,687 +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.
-
-// Software floating point interpretaton of ARM 7500 FP instructions.
-// The interpretation is not bit compatible with the 7500.
-// It uses true little-endian doubles, while the 7500 used mixed-endian.
-
-#include "runtime.h"
-#include "textflag.h"
-
-#define CPSR 14
-#define FLAGS_N (1U << 31)
-#define FLAGS_Z (1U << 30)
-#define FLAGS_C (1U << 29)
-#define FLAGS_V (1U << 28)
-
-void runtime·abort(void);
-void runtime·sqrtC(uint64, uint64*);
-
-static uint32 trace = 0;
-
-static void
-fabort(void)
-{
- if (1) {
- runtime·printf("Unsupported floating point instruction\n");
- runtime·abort();
- }
-}
-
-static void
-putf(uint32 reg, uint32 val)
-{
- g->m->freglo[reg] = val;
-}
-
-static void
-putd(uint32 reg, uint64 val)
-{
- g->m->freglo[reg] = (uint32)val;
- g->m->freghi[reg] = (uint32)(val>>32);
-}
-
-static uint64
-getd(uint32 reg)
-{
- return (uint64)g->m->freglo[reg] | ((uint64)g->m->freghi[reg]<<32);
-}
-
-static void
-fprint(void)
-{
- uint32 i;
- for (i = 0; i < 16; i++) {
- runtime·printf("\tf%d:\t%X %X\n", i, g->m->freghi[i], g->m->freglo[i]);
- }
-}
-
-static uint32
-d2f(uint64 d)
-{
- uint32 x;
-
- runtime·f64to32c(d, &x);
- return x;
-}
-
-static uint64
-f2d(uint32 f)
-{
- uint64 x;
-
- runtime·f32to64c(f, &x);
- return x;
-}
-
-static uint32
-fstatus(bool nan, int32 cmp)
-{
- if(nan)
- return FLAGS_C | FLAGS_V;
- if(cmp == 0)
- return FLAGS_Z | FLAGS_C;
- if(cmp < 0)
- return FLAGS_N;
- return FLAGS_C;
-}
-
-// conditions array record the required CPSR cond field for the
-// first 5 pairs of conditional execution opcodes
-// higher 4 bits are must set, lower 4 bits are must clear
-#pragma dataflag NOPTR
-static const uint8 conditions[10/2] = {
- [0/2] = (FLAGS_Z >> 24) | 0, // 0: EQ (Z set), 1: NE (Z clear)
- [2/2] = (FLAGS_C >> 24) | 0, // 2: CS/HS (C set), 3: CC/LO (C clear)
- [4/2] = (FLAGS_N >> 24) | 0, // 4: MI (N set), 5: PL (N clear)
- [6/2] = (FLAGS_V >> 24) | 0, // 6: VS (V set), 7: VC (V clear)
- [8/2] = (FLAGS_C >> 24) |
- (FLAGS_Z >> 28), // 8: HI (C set and Z clear), 9: LS (C clear and Z set)
-};
-
-#define FAULT (0x80000000U) // impossible PC offset
-
-// returns number of words that the fp instruction
-// is occupying, 0 if next instruction isn't float.
-static uint32
-stepflt(uint32 *pc, uint32 *regs)
-{
- uint32 i, opc, regd, regm, regn, cpsr;
- int32 delta;
- uint32 *addr;
- uint64 uval;
- int64 sval;
- bool nan, ok;
- int32 cmp;
- M *m;
-
- // m is locked in vlop_arm.s, so g->m cannot change during this function call,
- // so caching it in a local variable is safe.
- m = g->m;
- i = *pc;
-
- if(trace)
- runtime·printf("stepflt %p %x (cpsr %x)\n", pc, i, regs[CPSR] >> 28);
-
- opc = i >> 28;
- if(opc == 14) // common case first
- goto execute;
- cpsr = regs[CPSR] >> 28;
- switch(opc) {
- case 0: case 1: case 2: case 3: case 4:
- case 5: case 6: case 7: case 8: case 9:
- if(((cpsr & (conditions[opc/2] >> 4)) == (conditions[opc/2] >> 4)) &&
- ((cpsr & (conditions[opc/2] & 0xf)) == 0)) {
- if(opc & 1) return 1;
- } else {
- if(!(opc & 1)) return 1;
- }
- break;
- case 10: // GE (N == V)
- case 11: // LT (N != V)
- if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28))) {
- if(opc & 1) return 1;
- } else {
- if(!(opc & 1)) return 1;
- }
- break;
- case 12: // GT (N == V and Z == 0)
- case 13: // LE (N != V or Z == 1)
- if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28)) &&
- (cpsr & (FLAGS_Z >> 28)) == 0) {
- if(opc & 1) return 1;
- } else {
- if(!(opc & 1)) return 1;
- }
- break;
- case 14: // AL
- break;
- case 15: // shouldn't happen
- return 0;
- }
- if(trace)
- runtime·printf("conditional %x (cpsr %x) pass\n", opc, cpsr);
- i = (0xeU << 28) | (i & 0xfffffff);
-
-execute:
- // special cases
- if((i&0xfffff000) == 0xe59fb000) {
- // load r11 from pc-relative address.
- // might be part of a floating point move
- // (or might not, but no harm in simulating
- // one instruction too many).
- addr = (uint32*)((uint8*)pc + (i&0xfff) + 8);
- regs[11] = addr[0];
-
- if(trace)
- runtime·printf("*** cpu R[%d] = *(%p) %x\n",
- 11, addr, regs[11]);
- return 1;
- }
- if(i == 0xe08bb00d) {
- // add sp to r11.
- // might be part of a large stack offset address
- // (or might not, but again no harm done).
- regs[11] += regs[13];
-
- if(trace)
- runtime·printf("*** cpu R[%d] += R[%d] %x\n",
- 11, 13, regs[11]);
- return 1;
- }
- if(i == 0xeef1fa10) {
- regs[CPSR] = (regs[CPSR]&0x0fffffff) | m->fflag;
-
- if(trace)
- runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]);
- return 1;
- }
- if((i&0xff000000) == 0xea000000) {
- // unconditional branch
- // can happen in the middle of floating point
- // if the linker decides it is time to lay down
- // a sequence of instruction stream constants.
- delta = i&0xffffff;
- delta = (delta<<8) >> 8; // sign extend
-
- if(trace)
- runtime·printf("*** cpu PC += %x\n", (delta+2)*4);
- return delta+2;
- }
-
- goto stage1;
-
-stage1: // load/store regn is cpureg, regm is 8bit offset
- regd = i>>12 & 0xf;
- regn = i>>16 & 0xf;
- regm = (i & 0xff) << 2; // PLUS or MINUS ??
-
- switch(i & 0xfff00f00) {
- default:
- goto stage2;
-
- case 0xed900a00: // single load
- addr = (uint32*)(regs[regn] + regm);
- if((uintptr)addr < 4096) {
- if(trace)
- runtime·printf("*** load @%p => fault\n", addr);
- return FAULT;
- }
- m->freglo[regd] = addr[0];
-
- if(trace)
- runtime·printf("*** load F[%d] = %x\n",
- regd, m->freglo[regd]);
- break;
-
- case 0xed900b00: // double load
- addr = (uint32*)(regs[regn] + regm);
- if((uintptr)addr < 4096) {
- if(trace)
- runtime·printf("*** double load @%p => fault\n", addr);
- return FAULT;
- }
- m->freglo[regd] = addr[0];
- m->freghi[regd] = addr[1];
-
- if(trace)
- runtime·printf("*** load D[%d] = %x-%x\n",
- regd, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xed800a00: // single store
- addr = (uint32*)(regs[regn] + regm);
- if((uintptr)addr < 4096) {
- if(trace)
- runtime·printf("*** store @%p => fault\n", addr);
- return FAULT;
- }
- addr[0] = m->freglo[regd];
-
- if(trace)
- runtime·printf("*** *(%p) = %x\n",
- addr, addr[0]);
- break;
-
- case 0xed800b00: // double store
- addr = (uint32*)(regs[regn] + regm);
- if((uintptr)addr < 4096) {
- if(trace)
- runtime·printf("*** double store @%p => fault\n", addr);
- return FAULT;
- }
- addr[0] = m->freglo[regd];
- addr[1] = m->freghi[regd];
-
- if(trace)
- runtime·printf("*** *(%p) = %x-%x\n",
- addr, addr[1], addr[0]);
- break;
- }
- return 1;
-
-stage2: // regd, regm, regn are 4bit variables
- regm = i>>0 & 0xf;
- switch(i & 0xfff00ff0) {
- default:
- goto stage3;
-
- case 0xf3000110: // veor
- m->freglo[regd] = m->freglo[regm]^m->freglo[regn];
- m->freghi[regd] = m->freghi[regm]^m->freghi[regn];
-
- if(trace)
- runtime·printf("*** veor D[%d] = %x-%x\n",
- regd, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xeeb00b00: // D[regd] = const(regn,regm)
- regn = (regn<<4) | regm;
- regm = 0x40000000UL;
- if(regn & 0x80)
- regm |= 0x80000000UL;
- if(regn & 0x40)
- regm ^= 0x7fc00000UL;
- regm |= (regn & 0x3f) << 16;
- m->freglo[regd] = 0;
- m->freghi[regd] = regm;
-
- if(trace)
- runtime·printf("*** immed D[%d] = %x-%x\n",
- regd, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xeeb00a00: // F[regd] = const(regn,regm)
- regn = (regn<<4) | regm;
- regm = 0x40000000UL;
- if(regn & 0x80)
- regm |= 0x80000000UL;
- if(regn & 0x40)
- regm ^= 0x7e000000UL;
- regm |= (regn & 0x3f) << 19;
- m->freglo[regd] = regm;
-
- if(trace)
- runtime·printf("*** immed D[%d] = %x\n",
- regd, m->freglo[regd]);
- break;
-
- case 0xee300b00: // D[regd] = D[regn]+D[regm]
- runtime·fadd64c(getd(regn), getd(regm), &uval);
- putd(regd, uval);
-
- if(trace)
- runtime·printf("*** add D[%d] = D[%d]+D[%d] %x-%x\n",
- regd, regn, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xee300a00: // F[regd] = F[regn]+F[regm]
- runtime·fadd64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
- m->freglo[regd] = d2f(uval);
-
- if(trace)
- runtime·printf("*** add F[%d] = F[%d]+F[%d] %x\n",
- regd, regn, regm, m->freglo[regd]);
- break;
-
- case 0xee300b40: // D[regd] = D[regn]-D[regm]
- runtime·fsub64c(getd(regn), getd(regm), &uval);
- putd(regd, uval);
-
- if(trace)
- runtime·printf("*** sub D[%d] = D[%d]-D[%d] %x-%x\n",
- regd, regn, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xee300a40: // F[regd] = F[regn]-F[regm]
- runtime·fsub64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
- m->freglo[regd] = d2f(uval);
-
- if(trace)
- runtime·printf("*** sub F[%d] = F[%d]-F[%d] %x\n",
- regd, regn, regm, m->freglo[regd]);
- break;
-
- case 0xee200b00: // D[regd] = D[regn]*D[regm]
- runtime·fmul64c(getd(regn), getd(regm), &uval);
- putd(regd, uval);
-
- if(trace)
- runtime·printf("*** mul D[%d] = D[%d]*D[%d] %x-%x\n",
- regd, regn, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xee200a00: // F[regd] = F[regn]*F[regm]
- runtime·fmul64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
- m->freglo[regd] = d2f(uval);
-
- if(trace)
- runtime·printf("*** mul F[%d] = F[%d]*F[%d] %x\n",
- regd, regn, regm, m->freglo[regd]);
- break;
-
- case 0xee800b00: // D[regd] = D[regn]/D[regm]
- runtime·fdiv64c(getd(regn), getd(regm), &uval);
- putd(regd, uval);
-
- if(trace)
- runtime·printf("*** div D[%d] = D[%d]/D[%d] %x-%x\n",
- regd, regn, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xee800a00: // F[regd] = F[regn]/F[regm]
- runtime·fdiv64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
- m->freglo[regd] = d2f(uval);
-
- if(trace)
- runtime·printf("*** div F[%d] = F[%d]/F[%d] %x\n",
- regd, regn, regm, m->freglo[regd]);
- break;
-
- case 0xee000b10: // S[regn] = R[regd] (MOVW) (regm ignored)
- m->freglo[regn] = regs[regd];
-
- if(trace)
- runtime·printf("*** cpy S[%d] = R[%d] %x\n",
- regn, regd, m->freglo[regn]);
- break;
-
- case 0xee100b10: // R[regd] = S[regn] (MOVW) (regm ignored)
- regs[regd] = m->freglo[regn];
-
- if(trace)
- runtime·printf("*** cpy R[%d] = S[%d] %x\n",
- regd, regn, regs[regd]);
- break;
- }
- return 1;
-
-stage3: // regd, regm are 4bit variables
- switch(i & 0xffff0ff0) {
- default:
- goto done;
-
- case 0xeeb00a40: // F[regd] = F[regm] (MOVF)
- m->freglo[regd] = m->freglo[regm];
-
- if(trace)
- runtime·printf("*** F[%d] = F[%d] %x\n",
- regd, regm, m->freglo[regd]);
- break;
-
- case 0xeeb00b40: // D[regd] = D[regm] (MOVD)
- m->freglo[regd] = m->freglo[regm];
- m->freghi[regd] = m->freghi[regm];
-
- if(trace)
- runtime·printf("*** D[%d] = D[%d] %x-%x\n",
- regd, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xeeb10bc0: // D[regd] = sqrt D[regm]
- runtime·sqrtC(getd(regm), &uval);
- putd(regd, uval);
-
- if(trace)
- runtime·printf("*** D[%d] = sqrt D[%d] %x-%x\n",
- regd, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xeeb00bc0: // D[regd] = abs D[regm]
- m->freglo[regd] = m->freglo[regm];
- m->freghi[regd] = m->freghi[regm] & ((1<<31)-1);
-
- if(trace)
- runtime·printf("*** D[%d] = abs D[%d] %x-%x\n",
- regd, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xeeb00ac0: // F[regd] = abs F[regm]
- m->freglo[regd] = m->freglo[regm] & ((1<<31)-1);
-
- if(trace)
- runtime·printf("*** F[%d] = abs F[%d] %x\n",
- regd, regm, m->freglo[regd]);
- break;
-
- case 0xeeb40bc0: // D[regd] :: D[regm] (CMPD)
- runtime·fcmp64c(getd(regd), getd(regm), &cmp, &nan);
- m->fflag = fstatus(nan, cmp);
-
- if(trace)
- runtime·printf("*** cmp D[%d]::D[%d] %x\n",
- regd, regm, m->fflag);
- break;
-
- case 0xeeb40ac0: // F[regd] :: F[regm] (CMPF)
- runtime·fcmp64c(f2d(m->freglo[regd]), f2d(m->freglo[regm]), &cmp, &nan);
- m->fflag = fstatus(nan, cmp);
-
- if(trace)
- runtime·printf("*** cmp F[%d]::F[%d] %x\n",
- regd, regm, m->fflag);
- break;
-
- case 0xeeb70ac0: // D[regd] = F[regm] (MOVFD)
- putd(regd, f2d(m->freglo[regm]));
-
- if(trace)
- runtime·printf("*** f2d D[%d]=F[%d] %x-%x\n",
- regd, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xeeb70bc0: // F[regd] = D[regm] (MOVDF)
- m->freglo[regd] = d2f(getd(regm));
-
- if(trace)
- runtime·printf("*** d2f F[%d]=D[%d] %x-%x\n",
- regd, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xeebd0ac0: // S[regd] = F[regm] (MOVFW)
- runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
- if(!ok || (int32)sval != sval)
- sval = 0;
- m->freglo[regd] = sval;
-
- if(trace)
- runtime·printf("*** fix S[%d]=F[%d] %x\n",
- regd, regm, m->freglo[regd]);
- break;
-
- case 0xeebc0ac0: // S[regd] = F[regm] (MOVFW.U)
- runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
- if(!ok || (uint32)sval != sval)
- sval = 0;
- m->freglo[regd] = sval;
-
- if(trace)
- runtime·printf("*** fix unsigned S[%d]=F[%d] %x\n",
- regd, regm, m->freglo[regd]);
- break;
-
- case 0xeebd0bc0: // S[regd] = D[regm] (MOVDW)
- runtime·f64tointc(getd(regm), &sval, &ok);
- if(!ok || (int32)sval != sval)
- sval = 0;
- m->freglo[regd] = sval;
-
- if(trace)
- runtime·printf("*** fix S[%d]=D[%d] %x\n",
- regd, regm, m->freglo[regd]);
- break;
-
- case 0xeebc0bc0: // S[regd] = D[regm] (MOVDW.U)
- runtime·f64tointc(getd(regm), &sval, &ok);
- if(!ok || (uint32)sval != sval)
- sval = 0;
- m->freglo[regd] = sval;
-
- if(trace)
- runtime·printf("*** fix unsigned S[%d]=D[%d] %x\n",
- regd, regm, m->freglo[regd]);
- break;
-
- case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF)
- cmp = m->freglo[regm];
- if(cmp < 0) {
- runtime·fintto64c(-cmp, &uval);
- putf(regd, d2f(uval));
- m->freglo[regd] ^= 0x80000000;
- } else {
- runtime·fintto64c(cmp, &uval);
- putf(regd, d2f(uval));
- }
-
- if(trace)
- runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
- regd, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xeeb80a40: // D[regd] = S[regm] (MOVWF.U)
- runtime·fintto64c(m->freglo[regm], &uval);
- putf(regd, d2f(uval));
-
- if(trace)
- runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
- regd, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD)
- cmp = m->freglo[regm];
- if(cmp < 0) {
- runtime·fintto64c(-cmp, &uval);
- putd(regd, uval);
- m->freghi[regd] ^= 0x80000000;
- } else {
- runtime·fintto64c(cmp, &uval);
- putd(regd, uval);
- }
-
- if(trace)
- runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
- regd, regm, m->freghi[regd], m->freglo[regd]);
- break;
-
- case 0xeeb80b40: // D[regd] = S[regm] (MOVWD.U)
- runtime·fintto64c(m->freglo[regm], &uval);
- putd(regd, uval);
-
- if(trace)
- runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
- regd, regm, m->freghi[regd], m->freglo[regd]);
- break;
- }
- return 1;
-
-done:
- if((i&0xff000000) == 0xee000000 ||
- (i&0xff000000) == 0xed000000) {
- runtime·printf("stepflt %p %x\n", pc, i);
- fabort();
- }
- return 0;
-}
-
-typedef struct Sfregs Sfregs;
-
-// NOTE: These are all recorded as pointers because they are possibly live registers,
-// and we don't know what they contain. Recording them as pointers should be
-// safer than not.
-struct Sfregs
-{
- uint32 *r0;
- uint32 *r1;
- uint32 *r2;
- uint32 *r3;
- uint32 *r4;
- uint32 *r5;
- uint32 *r6;
- uint32 *r7;
- uint32 *r8;
- uint32 *r9;
- uint32 *r10;
- uint32 *r11;
- uint32 *r12;
- uint32 *r13;
- uint32 cspr;
-};
-
-static void sfloat2(void);
-void _sfloatpanic(void);
-
-#pragma textflag NOSPLIT
-uint32*
-runtime·_sfloat2(uint32 *pc, Sfregs regs)
-{
- void (*fn)(void);
-
- g->m->ptrarg[0] = pc;
- g->m->ptrarg[1] = &regs;
- fn = sfloat2;
- runtime·onM(&fn);
- pc = g->m->ptrarg[0];
- g->m->ptrarg[0] = nil;
- return pc;
-}
-
-static void
-sfloat2(void)
-{
- uint32 *pc;
- G *curg;
- Sfregs *regs;
- int32 skip;
- bool first;
-
- pc = g->m->ptrarg[0];
- regs = g->m->ptrarg[1];
- g->m->ptrarg[0] = nil;
- g->m->ptrarg[1] = nil;
-
- first = true;
- while(skip = stepflt(pc, (uint32*)&regs->r0)) {
- first = false;
- if(skip == FAULT) {
- // Encountered bad address in store/load.
- // Record signal information and return to assembly
- // trampoline that fakes the call.
- enum { SIGSEGV = 11 };
- curg = g->m->curg;
- curg->sig = SIGSEGV;
- curg->sigcode0 = 0;
- curg->sigcode1 = 0;
- curg->sigpc = (uint32)pc;
- pc = (uint32*)_sfloatpanic;
- break;
- }
- pc += skip;
- }
- if(first) {
- runtime·printf("sfloat2 %p %x\n", pc, *pc);
- fabort(); // not ok to fail first instruction
- }
-
- g->m->ptrarg[0] = pc;
-}
diff --git a/src/runtime/softfloat_arm.go b/src/runtime/softfloat_arm.go
new file mode 100644
index 000000000..efee31c4c
--- /dev/null
+++ b/src/runtime/softfloat_arm.go
@@ -0,0 +1,645 @@
+// 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.
+
+// Software floating point interpretaton of ARM 7500 FP instructions.
+// The interpretation is not bit compatible with the 7500.
+// It uses true little-endian doubles, while the 7500 used mixed-endian.
+
+package runtime
+
+import "unsafe"
+
+const (
+ _CPSR = 14
+ _FLAGS_N = 1 << 31
+ _FLAGS_Z = 1 << 30
+ _FLAGS_C = 1 << 29
+ _FLAGS_V = 1 << 28
+)
+
+var fptrace = 0
+
+func fabort() {
+ gothrow("unsupported floating point instruction")
+}
+
+func fputf(reg uint32, val uint32) {
+ _g_ := getg()
+ _g_.m.freglo[reg] = val
+}
+
+func fputd(reg uint32, val uint64) {
+ _g_ := getg()
+ _g_.m.freglo[reg] = uint32(val)
+ _g_.m.freghi[reg] = uint32(val >> 32)
+}
+
+func fgetd(reg uint32) uint64 {
+ _g_ := getg()
+ return uint64(_g_.m.freglo[reg]) | uint64(_g_.m.freghi[reg])<<32
+}
+
+func fprintregs() {
+ _g_ := getg()
+ for i := range _g_.m.freglo {
+ print("\tf", i, ":\t", hex(_g_.m.freghi[i]), " ", hex(_g_.m.freglo[i]), "\n")
+ }
+}
+
+func fstatus(nan bool, cmp int32) uint32 {
+ if nan {
+ return _FLAGS_C | _FLAGS_V
+ }
+ if cmp == 0 {
+ return _FLAGS_Z | _FLAGS_C
+ }
+ if cmp < 0 {
+ return _FLAGS_N
+ }
+ return _FLAGS_C
+}
+
+// conditions array record the required CPSR cond field for the
+// first 5 pairs of conditional execution opcodes
+// higher 4 bits are must set, lower 4 bits are must clear
+var conditions = [10 / 2]uint32{
+ 0 / 2: _FLAGS_Z>>24 | 0, // 0: EQ (Z set), 1: NE (Z clear)
+ 2 / 2: _FLAGS_C>>24 | 0, // 2: CS/HS (C set), 3: CC/LO (C clear)
+ 4 / 2: _FLAGS_N>>24 | 0, // 4: MI (N set), 5: PL (N clear)
+ 6 / 2: _FLAGS_V>>24 | 0, // 6: VS (V set), 7: VC (V clear)
+ 8 / 2: _FLAGS_C>>24 |
+ _FLAGS_Z>>28,
+}
+
+const _FAULT = 0x80000000 // impossible PC offset
+
+// returns number of words that the fp instruction
+// is occupying, 0 if next instruction isn't float.
+func stepflt(pc *uint32, regs *[15]uint32) uint32 {
+ var (
+ i, opc, regd, regm, regn, cpsr uint32
+ cmp, delta int32
+ uval uint64
+ sval int64
+ nan, ok bool
+ )
+
+ // m is locked in vlop_arm.s, so g.m cannot change during this function call,
+ // so caching it in a local variable is safe.
+ m := getg().m
+ i = *pc
+
+ if fptrace > 0 {
+ print("stepflt ", pc, " ", hex(i), " (cpsr ", hex(regs[_CPSR]>>28), ")\n")
+ }
+
+ opc = i >> 28
+ if opc == 14 { // common case first
+ goto execute
+ }
+
+ cpsr = regs[_CPSR] >> 28
+ switch opc {
+ case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9:
+ if cpsr&(conditions[opc/2]>>4) == conditions[opc/2]>>4 &&
+ cpsr&(conditions[opc/2]&0xf) == 0 {
+ if opc&1 != 0 {
+ return 1
+ }
+ } else {
+ if opc&1 == 0 {
+ return 1
+ }
+ }
+
+ case 10, 11: // GE (N == V), LT (N != V)
+ if cpsr&(_FLAGS_N>>28) == cpsr&(_FLAGS_V>>28) {
+ if opc&1 != 0 {
+ return 1
+ }
+ } else {
+ if opc&1 == 0 {
+ return 1
+ }
+ }
+
+ case 12, 13: // GT (N == V and Z == 0), LE (N != V or Z == 1)
+ if cpsr&(_FLAGS_N>>28) == cpsr&(_FLAGS_V>>28) &&
+ cpsr&(_FLAGS_Z>>28) == 0 {
+ if opc&1 != 0 {
+ return 1
+ }
+ } else {
+ if opc&1 == 0 {
+ return 1
+ }
+ }
+
+ case 14: // AL
+ // ok
+
+ case 15: // shouldn't happen
+ return 0
+ }
+
+ if fptrace > 0 {
+ print("conditional ", hex(opc), " (cpsr ", hex(cpsr), ") pass\n")
+ }
+ i = 0xe<<28 | i&(1<<28-1)
+
+execute:
+ // special cases
+ if i&0xfffff000 == 0xe59fb000 {
+ // load r11 from pc-relative address.
+ // might be part of a floating point move
+ // (or might not, but no harm in simulating
+ // one instruction too many).
+ addr := (*[1]uint32)(add(unsafe.Pointer(pc), uintptr(i&0xfff+8)))
+ regs[11] = addr[0]
+
+ if fptrace > 0 {
+ print("*** cpu R[11] = *(", addr, ") ", hex(regs[11]), "\n")
+ }
+ return 1
+ }
+ if i == 0xe08bb00d {
+ // add sp to r11.
+ // might be part of a large stack offset address
+ // (or might not, but again no harm done).
+ regs[11] += regs[13]
+
+ if fptrace > 0 {
+ print("*** cpu R[11] += R[13] ", hex(regs[11]), "\n")
+ }
+ return 1
+ }
+ if i == 0xeef1fa10 {
+ regs[_CPSR] = regs[_CPSR]&0x0fffffff | m.fflag
+
+ if fptrace > 0 {
+ print("*** fpsr R[CPSR] = F[CPSR] ", hex(regs[_CPSR]), "\n")
+ }
+ return 1
+ }
+ if i&0xff000000 == 0xea000000 {
+ // unconditional branch
+ // can happen in the middle of floating point
+ // if the linker decides it is time to lay down
+ // a sequence of instruction stream constants.
+ delta = int32(i&0xffffff) << 8 >> 8 // sign extend
+
+ if fptrace > 0 {
+ print("*** cpu PC += ", hex((delta+2)*4), "\n")
+ }
+ return uint32(delta + 2)
+ }
+
+ goto stage1
+
+stage1: // load/store regn is cpureg, regm is 8bit offset
+ regd = i >> 12 & 0xf
+ regn = i >> 16 & 0xf
+ regm = i & 0xff << 2 // PLUS or MINUS ??
+
+ switch i & 0xfff00f00 {
+ default:
+ goto stage2
+
+ case 0xed900a00: // single load
+ uaddr := uintptr(regs[regn] + regm)
+ if uaddr < 4096 {
+ if fptrace > 0 {
+ print("*** load @", hex(uaddr), " => fault\n")
+ }
+ return _FAULT
+ }
+ addr := (*[1]uint32)(unsafe.Pointer(uaddr))
+ m.freglo[regd] = addr[0]
+
+ if fptrace > 0 {
+ print("*** load F[", regd, "] = ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xed900b00: // double load
+ uaddr := uintptr(regs[regn] + regm)
+ if uaddr < 4096 {
+ if fptrace > 0 {
+ print("*** double load @", hex(uaddr), " => fault\n")
+ }
+ return _FAULT
+ }
+ addr := (*[2]uint32)(unsafe.Pointer(uaddr))
+ m.freglo[regd] = addr[0]
+ m.freghi[regd] = addr[1]
+
+ if fptrace > 0 {
+ print("*** load D[", regd, "] = ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xed800a00: // single store
+ uaddr := uintptr(regs[regn] + regm)
+ if uaddr < 4096 {
+ if fptrace > 0 {
+ print("*** store @", hex(uaddr), " => fault\n")
+ }
+ return _FAULT
+ }
+ addr := (*[1]uint32)(unsafe.Pointer(uaddr))
+ addr[0] = m.freglo[regd]
+
+ if fptrace > 0 {
+ print("*** *(", addr, ") = ", hex(addr[0]), "\n")
+ }
+ break
+
+ case 0xed800b00: // double store
+ uaddr := uintptr(regs[regn] + regm)
+ if uaddr < 4096 {
+ if fptrace > 0 {
+ print("*** double store @", hex(uaddr), " => fault\n")
+ }
+ return _FAULT
+ }
+ addr := (*[2]uint32)(unsafe.Pointer(uaddr))
+ addr[0] = m.freglo[regd]
+ addr[1] = m.freghi[regd]
+
+ if fptrace > 0 {
+ print("*** *(", addr, ") = ", hex(addr[1]), "-", hex(addr[0]), "\n")
+ }
+ break
+ }
+ return 1
+
+stage2: // regd, regm, regn are 4bit variables
+ regm = i >> 0 & 0xf
+ switch i & 0xfff00ff0 {
+ default:
+ goto stage3
+
+ case 0xf3000110: // veor
+ m.freglo[regd] = m.freglo[regm] ^ m.freglo[regn]
+ m.freghi[regd] = m.freghi[regm] ^ m.freghi[regn]
+
+ if fptrace > 0 {
+ print("*** veor D[", regd, "] = ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb00b00: // D[regd] = const(regn,regm)
+ regn = regn<<4 | regm
+ regm = 0x40000000
+ if regn&0x80 != 0 {
+ regm |= 0x80000000
+ }
+ if regn&0x40 != 0 {
+ regm ^= 0x7fc00000
+ }
+ regm |= regn & 0x3f << 16
+ m.freglo[regd] = 0
+ m.freghi[regd] = regm
+
+ if fptrace > 0 {
+ print("*** immed D[", regd, "] = ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb00a00: // F[regd] = const(regn,regm)
+ regn = regn<<4 | regm
+ regm = 0x40000000
+ if regn&0x80 != 0 {
+ regm |= 0x80000000
+ }
+ if regn&0x40 != 0 {
+ regm ^= 0x7e000000
+ }
+ regm |= regn & 0x3f << 19
+ m.freglo[regd] = regm
+
+ if fptrace > 0 {
+ print("*** immed D[", regd, "] = ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xee300b00: // D[regd] = D[regn]+D[regm]
+ fadd64c(fgetd(regn), fgetd(regm), &uval)
+ fputd(regd, uval)
+
+ if fptrace > 0 {
+ print("*** add D[", regd, "] = D[", regn, "]+D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xee300a00: // F[regd] = F[regn]+F[regm]
+ fadd64c(f32to64(m.freglo[regn]), f32to64(m.freglo[regm]), &uval)
+ m.freglo[regd] = f64to32(uval)
+
+ if fptrace > 0 {
+ print("*** add F[", regd, "] = F[", regn, "]+F[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xee300b40: // D[regd] = D[regn]-D[regm]
+ fsub64c(fgetd(regn), fgetd(regm), &uval)
+ fputd(regd, uval)
+
+ if fptrace > 0 {
+ print("*** sub D[", regd, "] = D[", regn, "]-D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xee300a40: // F[regd] = F[regn]-F[regm]
+ fsub64c(f32to64(m.freglo[regn]), f32to64(m.freglo[regm]), &uval)
+ m.freglo[regd] = f64to32(uval)
+
+ if fptrace > 0 {
+ print("*** sub F[", regd, "] = F[", regn, "]-F[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xee200b00: // D[regd] = D[regn]*D[regm]
+ fmul64c(fgetd(regn), fgetd(regm), &uval)
+ fputd(regd, uval)
+
+ if fptrace > 0 {
+ print("*** mul D[", regd, "] = D[", regn, "]*D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xee200a00: // F[regd] = F[regn]*F[regm]
+ fmul64c(f32to64(m.freglo[regn]), f32to64(m.freglo[regm]), &uval)
+ m.freglo[regd] = f64to32(uval)
+
+ if fptrace > 0 {
+ print("*** mul F[", regd, "] = F[", regn, "]*F[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xee800b00: // D[regd] = D[regn]/D[regm]
+ fdiv64c(fgetd(regn), fgetd(regm), &uval)
+ fputd(regd, uval)
+
+ if fptrace > 0 {
+ print("*** div D[", regd, "] = D[", regn, "]/D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xee800a00: // F[regd] = F[regn]/F[regm]
+ fdiv64c(f32to64(m.freglo[regn]), f32to64(m.freglo[regm]), &uval)
+ m.freglo[regd] = f64to32(uval)
+
+ if fptrace > 0 {
+ print("*** div F[", regd, "] = F[", regn, "]/F[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xee000b10: // S[regn] = R[regd] (MOVW) (regm ignored)
+ m.freglo[regn] = regs[regd]
+
+ if fptrace > 0 {
+ print("*** cpy S[", regn, "] = R[", regd, "] ", hex(m.freglo[regn]), "\n")
+ }
+ break
+
+ case 0xee100b10: // R[regd] = S[regn] (MOVW) (regm ignored)
+ regs[regd] = m.freglo[regn]
+
+ if fptrace > 0 {
+ print("*** cpy R[", regd, "] = S[", regn, "] ", hex(regs[regd]), "\n")
+ }
+ break
+ }
+ return 1
+
+stage3: // regd, regm are 4bit variables
+ switch i & 0xffff0ff0 {
+ default:
+ goto done
+
+ case 0xeeb00a40: // F[regd] = F[regm] (MOVF)
+ m.freglo[regd] = m.freglo[regm]
+
+ if fptrace > 0 {
+ print("*** F[", regd, "] = F[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb00b40: // D[regd] = D[regm] (MOVD)
+ m.freglo[regd] = m.freglo[regm]
+ m.freghi[regd] = m.freghi[regm]
+
+ if fptrace > 0 {
+ print("*** D[", regd, "] = D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb10bc0: // D[regd] = sqrt D[regm]
+ uval = float64bits(sqrt(float64frombits(fgetd(regm))))
+ fputd(regd, uval)
+
+ if fptrace > 0 {
+ print("*** D[", regd, "] = sqrt D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb00bc0: // D[regd] = abs D[regm]
+ m.freglo[regd] = m.freglo[regm]
+ m.freghi[regd] = m.freghi[regm] & (1<<31 - 1)
+
+ if fptrace > 0 {
+ print("*** D[", regd, "] = abs D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb00ac0: // F[regd] = abs F[regm]
+ m.freglo[regd] = m.freglo[regm] & (1<<31 - 1)
+
+ if fptrace > 0 {
+ print("*** F[", regd, "] = abs F[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb40bc0: // D[regd] :: D[regm] (CMPD)
+ fcmp64c(fgetd(regd), fgetd(regm), &cmp, &nan)
+ m.fflag = fstatus(nan, cmp)
+
+ if fptrace > 0 {
+ print("*** cmp D[", regd, "]::D[", regm, "] ", hex(m.fflag), "\n")
+ }
+ break
+
+ case 0xeeb40ac0: // F[regd] :: F[regm] (CMPF)
+ fcmp64c(f32to64(m.freglo[regd]), f32to64(m.freglo[regm]), &cmp, &nan)
+ m.fflag = fstatus(nan, cmp)
+
+ if fptrace > 0 {
+ print("*** cmp F[", regd, "]::F[", regm, "] ", hex(m.fflag), "\n")
+ }
+ break
+
+ case 0xeeb70ac0: // D[regd] = F[regm] (MOVFD)
+ fputd(regd, f32to64(m.freglo[regm]))
+
+ if fptrace > 0 {
+ print("*** f2d D[", regd, "]=F[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb70bc0: // F[regd] = D[regm] (MOVDF)
+ m.freglo[regd] = f64to32(fgetd(regm))
+
+ if fptrace > 0 {
+ print("*** d2f F[", regd, "]=D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeebd0ac0: // S[regd] = F[regm] (MOVFW)
+ f64tointc(f32to64(m.freglo[regm]), &sval, &ok)
+ if !ok || int64(int32(sval)) != sval {
+ sval = 0
+ }
+ m.freglo[regd] = uint32(sval)
+ if fptrace > 0 {
+ print("*** fix S[", regd, "]=F[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeebc0ac0: // S[regd] = F[regm] (MOVFW.U)
+ f64tointc(f32to64(m.freglo[regm]), &sval, &ok)
+ if !ok || int64(uint32(sval)) != sval {
+ sval = 0
+ }
+ m.freglo[regd] = uint32(sval)
+
+ if fptrace > 0 {
+ print("*** fix unsigned S[", regd, "]=F[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeebd0bc0: // S[regd] = D[regm] (MOVDW)
+ f64tointc(fgetd(regm), &sval, &ok)
+ if !ok || int64(int32(sval)) != sval {
+ sval = 0
+ }
+ m.freglo[regd] = uint32(sval)
+
+ if fptrace > 0 {
+ print("*** fix S[", regd, "]=D[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeebc0bc0: // S[regd] = D[regm] (MOVDW.U)
+ f64tointc(fgetd(regm), &sval, &ok)
+ if !ok || int64(uint32(sval)) != sval {
+ sval = 0
+ }
+ m.freglo[regd] = uint32(sval)
+
+ if fptrace > 0 {
+ print("*** fix unsigned S[", regd, "]=D[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF)
+ cmp = int32(m.freglo[regm])
+ if cmp < 0 {
+ fintto64c(int64(-cmp), &uval)
+ fputf(regd, f64to32(uval))
+ m.freglo[regd] ^= 0x80000000
+ } else {
+ fintto64c(int64(cmp), &uval)
+ fputf(regd, f64to32(uval))
+ }
+
+ if fptrace > 0 {
+ print("*** float D[", regd, "]=S[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb80a40: // D[regd] = S[regm] (MOVWF.U)
+ fintto64c(int64(m.freglo[regm]), &uval)
+ fputf(regd, f64to32(uval))
+
+ if fptrace > 0 {
+ print("*** float unsigned D[", regd, "]=S[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD)
+ cmp = int32(m.freglo[regm])
+ if cmp < 0 {
+ fintto64c(int64(-cmp), &uval)
+ fputd(regd, uval)
+ m.freghi[regd] ^= 0x80000000
+ } else {
+ fintto64c(int64(cmp), &uval)
+ fputd(regd, uval)
+ }
+
+ if fptrace > 0 {
+ print("*** float D[", regd, "]=S[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+
+ case 0xeeb80b40: // D[regd] = S[regm] (MOVWD.U)
+ fintto64c(int64(m.freglo[regm]), &uval)
+ fputd(regd, uval)
+
+ if fptrace > 0 {
+ print("*** float unsigned D[", regd, "]=S[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ break
+ }
+ return 1
+
+done:
+ if i&0xff000000 == 0xee000000 ||
+ i&0xff000000 == 0xed000000 {
+ print("stepflt ", pc, " ", hex(i), "\n")
+ fabort()
+ }
+ return 0
+}
+
+//go:nosplit
+func _sfloat2(pc uint32, regs [15]uint32) (newpc uint32) {
+ systemstack(func() {
+ newpc = sfloat2(pc, &regs)
+ })
+ return
+}
+
+func _sfloatpanic()
+
+func sfloat2(pc uint32, regs *[15]uint32) uint32 {
+ first := true
+ for {
+ skip := stepflt((*uint32)(unsafe.Pointer(uintptr(pc))), regs)
+ if skip == 0 {
+ break
+ }
+ first = false
+ if skip == _FAULT {
+ // Encountered bad address in store/load.
+ // Record signal information and return to assembly
+ // trampoline that fakes the call.
+ const SIGSEGV = 11
+ curg := getg().m.curg
+ curg.sig = SIGSEGV
+ curg.sigcode0 = 0
+ curg.sigcode1 = 0
+ curg.sigpc = uintptr(pc)
+ pc = uint32(funcPC(_sfloatpanic))
+ break
+ }
+ pc += 4 * uint32(skip)
+ }
+ if first {
+ print("sfloat2 ", pc, " ", hex(*(*uint32)(unsafe.Pointer(uintptr(pc)))), "\n")
+ fabort() // not ok to fail first instruction
+ }
+ return pc
+}
diff --git a/src/runtime/sqrt.go b/src/runtime/sqrt.go
index 34a8c3806..e3a27014b 100644
--- a/src/runtime/sqrt.go
+++ b/src/runtime/sqrt.go
@@ -86,9 +86,6 @@ import "unsafe"
// Notes: Rounding mode detection omitted.
const (
- uvnan = 0x7FF8000000000001
- uvinf = 0x7FF0000000000000
- uvneginf = 0xFFF0000000000000
mask = 0x7FF
shift = 64 - 11 - 1
bias = 1023
@@ -104,7 +101,7 @@ func sqrt(x float64) float64 {
case x == 0 || x != x || x > maxFloat64:
return x
case x < 0:
- return nan
+ return nan()
}
ix := float64bits(x)
// normalize x
@@ -144,7 +141,3 @@ func sqrt(x float64) float64 {
ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
return float64frombits(ix)
}
-
-func sqrtC(f float64, r *float64) {
- *r = sqrt(f)
-}
diff --git a/src/runtime/stack.c b/src/runtime/stack.c
deleted file mode 100644
index cb9557243..000000000
--- a/src/runtime/stack.c
+++ /dev/null
@@ -1,892 +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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "stack.h"
-#include "funcdata.h"
-#include "typekind.h"
-#include "type.h"
-#include "race.h"
-#include "mgc0.h"
-#include "textflag.h"
-
-enum
-{
- // StackDebug == 0: no logging
- // == 1: logging of per-stack operations
- // == 2: logging of per-frame operations
- // == 3: logging of per-word updates
- // == 4: logging of per-word reads
- StackDebug = 0,
- StackFromSystem = 0, // allocate stacks from system memory instead of the heap
- StackFaultOnFree = 0, // old stacks are mapped noaccess to detect use after free
- StackPoisonCopy = 0, // fill stack that should not be accessed with garbage, to detect bad dereferences during copy
-
- StackCache = 1,
-};
-
-// Global pool of spans that have free stacks.
-// Stacks are assigned an order according to size.
-// order = log_2(size/FixedStack)
-// There is a free list for each order.
-MSpan runtime·stackpool[NumStackOrders];
-Mutex runtime·stackpoolmu;
-// TODO: one lock per order?
-
-static Stack stackfreequeue;
-
-void
-runtime·stackinit(void)
-{
- int32 i;
-
- if((StackCacheSize & PageMask) != 0)
- runtime·throw("cache size must be a multiple of page size");
-
- for(i = 0; i < NumStackOrders; i++)
- runtime·MSpanList_Init(&runtime·stackpool[i]);
-}
-
-// Allocates a stack from the free pool. Must be called with
-// stackpoolmu held.
-static MLink*
-poolalloc(uint8 order)
-{
- MSpan *list;
- MSpan *s;
- MLink *x;
- uintptr i;
-
- list = &runtime·stackpool[order];
- s = list->next;
- if(s == list) {
- // no free stacks. Allocate another span worth.
- s = runtime·MHeap_AllocStack(&runtime·mheap, StackCacheSize >> PageShift);
- if(s == nil)
- runtime·throw("out of memory");
- if(s->ref != 0)
- runtime·throw("bad ref");
- if(s->freelist != nil)
- runtime·throw("bad freelist");
- for(i = 0; i < StackCacheSize; i += FixedStack << order) {
- x = (MLink*)((s->start << PageShift) + i);
- x->next = s->freelist;
- s->freelist = x;
- }
- runtime·MSpanList_Insert(list, s);
- }
- x = s->freelist;
- if(x == nil)
- runtime·throw("span has no free stacks");
- s->freelist = x->next;
- s->ref++;
- if(s->freelist == nil) {
- // all stacks in s are allocated.
- runtime·MSpanList_Remove(s);
- }
- return x;
-}
-
-// Adds stack x to the free pool. Must be called with stackpoolmu held.
-static void
-poolfree(MLink *x, uint8 order)
-{
- MSpan *s;
-
- s = runtime·MHeap_Lookup(&runtime·mheap, x);
- if(s->state != MSpanStack)
- runtime·throw("freeing stack not in a stack span");
- if(s->freelist == nil) {
- // s will now have a free stack
- runtime·MSpanList_Insert(&runtime·stackpool[order], s);
- }
- x->next = s->freelist;
- s->freelist = x;
- s->ref--;
- if(s->ref == 0) {
- // span is completely free - return to heap
- runtime·MSpanList_Remove(s);
- s->freelist = nil;
- runtime·MHeap_FreeStack(&runtime·mheap, s);
- }
-}
-
-// stackcacherefill/stackcacherelease implement a global pool of stack segments.
-// The pool is required to prevent unlimited growth of per-thread caches.
-static void
-stackcacherefill(MCache *c, uint8 order)
-{
- MLink *x, *list;
- uintptr size;
-
- if(StackDebug >= 1)
- runtime·printf("stackcacherefill order=%d\n", order);
-
- // Grab some stacks from the global cache.
- // Grab half of the allowed capacity (to prevent thrashing).
- list = nil;
- size = 0;
- runtime·lock(&runtime·stackpoolmu);
- while(size < StackCacheSize/2) {
- x = poolalloc(order);
- x->next = list;
- list = x;
- size += FixedStack << order;
- }
- runtime·unlock(&runtime·stackpoolmu);
-
- c->stackcache[order].list = list;
- c->stackcache[order].size = size;
-}
-
-static void
-stackcacherelease(MCache *c, uint8 order)
-{
- MLink *x, *y;
- uintptr size;
-
- if(StackDebug >= 1)
- runtime·printf("stackcacherelease order=%d\n", order);
- x = c->stackcache[order].list;
- size = c->stackcache[order].size;
- runtime·lock(&runtime·stackpoolmu);
- while(size > StackCacheSize/2) {
- y = x->next;
- poolfree(x, order);
- x = y;
- size -= FixedStack << order;
- }
- runtime·unlock(&runtime·stackpoolmu);
- c->stackcache[order].list = x;
- c->stackcache[order].size = size;
-}
-
-void
-runtime·stackcache_clear(MCache *c)
-{
- uint8 order;
- MLink *x, *y;
-
- if(StackDebug >= 1)
- runtime·printf("stackcache clear\n");
- runtime·lock(&runtime·stackpoolmu);
- for(order = 0; order < NumStackOrders; order++) {
- x = c->stackcache[order].list;
- while(x != nil) {
- y = x->next;
- poolfree(x, order);
- x = y;
- }
- c->stackcache[order].list = nil;
- c->stackcache[order].size = 0;
- }
- runtime·unlock(&runtime·stackpoolmu);
-}
-
-Stack
-runtime·stackalloc(uint32 n)
-{
- uint8 order;
- uint32 n2;
- void *v;
- MLink *x;
- MSpan *s;
- MCache *c;
-
- // Stackalloc must be called on scheduler stack, so that we
- // never try to grow the stack during the code that stackalloc runs.
- // Doing so would cause a deadlock (issue 1547).
- if(g != g->m->g0)
- runtime·throw("stackalloc not on scheduler stack");
- if((n & (n-1)) != 0)
- runtime·throw("stack size not a power of 2");
- if(StackDebug >= 1)
- runtime·printf("stackalloc %d\n", n);
-
- if(runtime·debug.efence || StackFromSystem) {
- v = runtime·sysAlloc(ROUND(n, PageSize), &mstats.stacks_sys);
- if(v == nil)
- runtime·throw("out of memory (stackalloc)");
- return (Stack){(uintptr)v, (uintptr)v+n};
- }
-
- // Small stacks are allocated with a fixed-size free-list allocator.
- // If we need a stack of a bigger size, we fall back on allocating
- // a dedicated span.
- if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize) {
- order = 0;
- n2 = n;
- while(n2 > FixedStack) {
- order++;
- n2 >>= 1;
- }
- c = g->m->mcache;
- if(c == nil || g->m->gcing || g->m->helpgc) {
- // 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
- // as it's flushed concurrently.
- runtime·lock(&runtime·stackpoolmu);
- x = poolalloc(order);
- runtime·unlock(&runtime·stackpoolmu);
- } else {
- x = c->stackcache[order].list;
- if(x == nil) {
- stackcacherefill(c, order);
- x = c->stackcache[order].list;
- }
- c->stackcache[order].list = x->next;
- c->stackcache[order].size -= n;
- }
- v = (byte*)x;
- } else {
- s = runtime·MHeap_AllocStack(&runtime·mheap, ROUND(n, PageSize) >> PageShift);
- if(s == nil)
- runtime·throw("out of memory");
- v = (byte*)(s->start<<PageShift);
- }
-
- if(raceenabled)
- runtime·racemalloc(v, n);
- if(StackDebug >= 1)
- runtime·printf(" allocated %p\n", v);
- return (Stack){(uintptr)v, (uintptr)v+n};
-}
-
-void
-runtime·stackfree(Stack stk)
-{
- uint8 order;
- uintptr n, n2;
- MSpan *s;
- MLink *x;
- MCache *c;
- void *v;
-
- n = stk.hi - stk.lo;
- v = (void*)stk.lo;
- if(n & (n-1))
- runtime·throw("stack not a power of 2");
- if(StackDebug >= 1) {
- runtime·printf("stackfree %p %d\n", v, (int32)n);
- runtime·memclr(v, n); // for testing, clobber stack data
- }
- if(runtime·debug.efence || StackFromSystem) {
- if(runtime·debug.efence || StackFaultOnFree)
- runtime·SysFault(v, n);
- else
- runtime·SysFree(v, n, &mstats.stacks_sys);
- return;
- }
- if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize) {
- order = 0;
- n2 = n;
- while(n2 > FixedStack) {
- order++;
- n2 >>= 1;
- }
- x = (MLink*)v;
- c = g->m->mcache;
- if(c == nil || g->m->gcing || g->m->helpgc) {
- runtime·lock(&runtime·stackpoolmu);
- poolfree(x, order);
- runtime·unlock(&runtime·stackpoolmu);
- } else {
- if(c->stackcache[order].size >= StackCacheSize)
- stackcacherelease(c, order);
- x->next = c->stackcache[order].list;
- c->stackcache[order].list = x;
- c->stackcache[order].size += n;
- }
- } else {
- s = runtime·MHeap_Lookup(&runtime·mheap, v);
- if(s->state != MSpanStack) {
- runtime·printf("%p %p\n", s->start<<PageShift, v);
- runtime·throw("bad span state");
- }
- runtime·MHeap_FreeStack(&runtime·mheap, s);
- }
-}
-
-uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for real
-
-static uint8*
-mapnames[] = {
- (uint8*)"---",
- (uint8*)"scalar",
- (uint8*)"ptr",
- (uint8*)"multi",
-};
-
-// Stack frame layout
-//
-// (x86)
-// +------------------+
-// | args from caller |
-// +------------------+ <- frame->argp
-// | return address |
-// +------------------+ <- frame->varp
-// | locals |
-// +------------------+
-// | args to callee |
-// +------------------+ <- frame->sp
-//
-// (arm)
-// +------------------+
-// | args from caller |
-// +------------------+ <- frame->argp
-// | caller's retaddr |
-// +------------------+ <- frame->varp
-// | locals |
-// +------------------+
-// | args to callee |
-// +------------------+
-// | return address |
-// +------------------+ <- frame->sp
-
-void runtime·main(void);
-void runtime·switchtoM(void(*)(void));
-
-typedef struct AdjustInfo AdjustInfo;
-struct AdjustInfo {
- Stack old;
- uintptr delta; // ptr distance from old to new stack (newbase - oldbase)
-};
-
-// Adjustpointer checks whether *vpp is in the old stack described by adjinfo.
-// If so, it rewrites *vpp to point into the new stack.
-static void
-adjustpointer(AdjustInfo *adjinfo, void *vpp)
-{
- byte **pp, *p;
-
- pp = vpp;
- p = *pp;
- if(StackDebug >= 4)
- runtime·printf(" %p:%p\n", pp, p);
- if(adjinfo->old.lo <= (uintptr)p && (uintptr)p < adjinfo->old.hi) {
- *pp = p + adjinfo->delta;
- if(StackDebug >= 3)
- runtime·printf(" adjust ptr %p: %p -> %p\n", pp, p, *pp);
- }
-}
-
-// bv describes the memory starting at address scanp.
-// Adjust any pointers contained therein.
-static void
-adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
-{
- uintptr delta;
- int32 num, i;
- byte *p, *minp, *maxp;
- Type *t;
- Itab *tab;
-
- minp = (byte*)adjinfo->old.lo;
- maxp = (byte*)adjinfo->old.hi;
- delta = adjinfo->delta;
- num = bv->n / BitsPerPointer;
- for(i = 0; i < num; i++) {
- if(StackDebug >= 4)
- runtime·printf(" %p:%s:%p\n", &scanp[i], mapnames[bv->bytedata[i / (8 / BitsPerPointer)] >> (i * BitsPerPointer & 7) & 3], scanp[i]);
- switch(bv->bytedata[i / (8 / BitsPerPointer)] >> (i * BitsPerPointer & 7) & 3) {
- case BitsDead:
- if(runtime·debug.gcdead)
- scanp[i] = (byte*)PoisonStack;
- break;
- case BitsScalar:
- break;
- case BitsPointer:
- p = scanp[i];
- if(f != nil && (byte*)0 < p && (p < (byte*)PageSize && runtime·invalidptr || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
- // Looks like a junk value in a pointer slot.
- // Live analysis wrong?
- g->m->traceback = 2;
- runtime·printf("runtime: bad pointer in frame %s at %p: %p\n", runtime·funcname(f), &scanp[i], p);
- runtime·throw("invalid stack pointer");
- }
- if(minp <= p && p < maxp) {
- if(StackDebug >= 3)
- runtime·printf("adjust ptr %p %s\n", p, runtime·funcname(f));
- scanp[i] = p + delta;
- }
- break;
- case BitsMultiWord:
- switch(bv->bytedata[(i+1) / (8 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 7) & 3) {
- default:
- runtime·throw("unexpected garbage collection bits");
- case BitsEface:
- t = (Type*)scanp[i];
- if(t != nil && ((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0)) {
- p = scanp[i+1];
- if(minp <= p && p < maxp) {
- if(StackDebug >= 3)
- runtime·printf("adjust eface %p\n", p);
- if(t->size > PtrSize) // currently we always allocate such objects on the heap
- runtime·throw("large interface value found on stack");
- scanp[i+1] = p + delta;
- }
- }
- i++;
- break;
- case BitsIface:
- tab = (Itab*)scanp[i];
- if(tab != nil) {
- t = tab->type;
- //runtime·printf(" type=%p\n", t);
- if((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0) {
- p = scanp[i+1];
- if(minp <= p && p < maxp) {
- if(StackDebug >= 3)
- runtime·printf("adjust iface %p\n", p);
- if(t->size > PtrSize) // currently we always allocate such objects on the heap
- runtime·throw("large interface value found on stack");
- scanp[i+1] = p + delta;
- }
- }
- }
- i++;
- break;
- }
- break;
- }
- }
-}
-
-// Note: the argument/return area is adjusted by the callee.
-static bool
-adjustframe(Stkframe *frame, void *arg)
-{
- AdjustInfo *adjinfo;
- Func *f;
- StackMap *stackmap;
- int32 pcdata;
- BitVector bv;
- uintptr targetpc, size, minsize;
-
- adjinfo = arg;
- targetpc = frame->continpc;
- if(targetpc == 0) {
- // Frame is dead.
- return true;
- }
- f = frame->fn;
- if(StackDebug >= 2)
- runtime·printf(" adjusting %s frame=[%p,%p] pc=%p continpc=%p\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc);
- if(f->entry == (uintptr)runtime·switchtoM) {
- // A special routine at the bottom of stack of a goroutine that does an onM call.
- // We will allow it to be copied even though we don't
- // have full GC info for it (because it is written in asm).
- return true;
- }
- if(targetpc != f->entry)
- targetpc--;
- pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
- if(pcdata == -1)
- pcdata = 0; // in prologue
-
- // Adjust local variables if stack frame has been allocated.
- size = frame->varp - frame->sp;
- if(thechar != '6' && thechar != '8')
- minsize = sizeof(uintptr);
- else
- minsize = 0;
- if(size > minsize) {
- stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
- if(stackmap == nil || stackmap->n <= 0) {
- runtime·printf("runtime: frame %s untyped locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size);
- runtime·throw("missing stackmap");
- }
- // Locals bitmap information, scan just the pointers in locals.
- if(pcdata < 0 || pcdata >= stackmap->n) {
- // don't know where we are
- runtime·printf("runtime: pcdata is %d and %d locals stack map entries for %s (targetpc=%p)\n",
- pcdata, stackmap->n, runtime·funcname(f), targetpc);
- runtime·throw("bad symbol table");
- }
- bv = runtime·stackmapdata(stackmap, pcdata);
- size = (bv.n * PtrSize) / BitsPerPointer;
- if(StackDebug >= 3)
- runtime·printf(" locals\n");
- adjustpointers((byte**)(frame->varp - size), &bv, adjinfo, f);
- }
-
- // Adjust arguments.
- if(frame->arglen > 0) {
- if(frame->argmap != nil) {
- bv = *frame->argmap;
- } else {
- stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
- if(stackmap == nil || stackmap->n <= 0) {
- runtime·printf("runtime: frame %s untyped args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
- runtime·throw("missing stackmap");
- }
- if(pcdata < 0 || pcdata >= stackmap->n) {
- // don't know where we are
- runtime·printf("runtime: pcdata is %d and %d args stack map entries for %s (targetpc=%p)\n",
- pcdata, stackmap->n, runtime·funcname(f), targetpc);
- runtime·throw("bad symbol table");
- }
- bv = runtime·stackmapdata(stackmap, pcdata);
- }
- if(StackDebug >= 3)
- runtime·printf(" args\n");
- adjustpointers((byte**)frame->argp, &bv, adjinfo, nil);
- }
-
- return true;
-}
-
-static void
-adjustctxt(G *gp, AdjustInfo *adjinfo)
-{
- adjustpointer(adjinfo, &gp->sched.ctxt);
-}
-
-static void
-adjustdefers(G *gp, AdjustInfo *adjinfo)
-{
- Defer *d;
- bool (*cb)(Stkframe*, void*);
-
- // Adjust defer argument blocks the same way we adjust active stack frames.
- cb = adjustframe;
- runtime·tracebackdefers(gp, &cb, adjinfo);
-
- // Adjust pointers in the Defer structs.
- // Defer structs themselves are never on the stack.
- for(d = gp->defer; d != nil; d = d->link) {
- adjustpointer(adjinfo, &d->fn);
- adjustpointer(adjinfo, &d->argp);
- adjustpointer(adjinfo, &d->panic);
- }
-}
-
-static void
-adjustpanics(G *gp, AdjustInfo *adjinfo)
-{
- // Panics are on stack and already adjusted.
- // Update pointer to head of list in G.
- adjustpointer(adjinfo, &gp->panic);
-}
-
-static void
-adjustsudogs(G *gp, AdjustInfo *adjinfo)
-{
- SudoG *s;
-
- // the data elements pointed to by a SudoG structure
- // might be in the stack.
- for(s = gp->waiting; s != nil; s = s->waitlink) {
- adjustpointer(adjinfo, &s->elem);
- adjustpointer(adjinfo, &s->selectdone);
- }
-}
-
-// Copies gp's stack to a new stack of a different size.
-static void
-copystack(G *gp, uintptr newsize)
-{
- Stack old, new;
- uintptr used;
- AdjustInfo adjinfo;
- uint32 oldstatus;
- bool (*cb)(Stkframe*, void*);
- byte *p, *ep;
-
- if(gp->syscallsp != 0)
- runtime·throw("stack growth not allowed in system call");
- old = gp->stack;
- if(old.lo == 0)
- runtime·throw("nil stackbase");
- used = old.hi - gp->sched.sp;
-
- // allocate new stack
- new = runtime·stackalloc(newsize);
- if(StackPoisonCopy) {
- p = (byte*)new.lo;
- ep = (byte*)new.hi;
- while(p < ep)
- *p++ = 0xfd;
- }
-
- if(StackDebug >= 1)
- runtime·printf("copystack gp=%p [%p %p %p]/%d -> [%p %p %p]/%d\n", gp, old.lo, old.hi-used, old.hi, (int32)(old.hi-old.lo), new.lo, new.hi-used, new.hi, (int32)newsize);
-
- // adjust pointers in the to-be-copied frames
- adjinfo.old = old;
- adjinfo.delta = new.hi - old.hi;
- cb = adjustframe;
- runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, 0);
-
- // adjust other miscellaneous things that have pointers into stacks.
- adjustctxt(gp, &adjinfo);
- adjustdefers(gp, &adjinfo);
- adjustpanics(gp, &adjinfo);
- adjustsudogs(gp, &adjinfo);
-
- // copy the stack to the new location
- if(StackPoisonCopy) {
- p = (byte*)new.lo;
- ep = (byte*)new.hi;
- while(p < ep)
- *p++ = 0xfb;
- }
- runtime·memmove((byte*)new.hi - used, (byte*)old.hi - used, used);
-
- oldstatus = runtime·casgcopystack(gp); // cas from Gwaiting or Grunnable to Gcopystack, return old status
-
- // Swap out old stack for new one
- gp->stack = new;
- gp->stackguard0 = new.lo + StackGuard; // NOTE: might clobber a preempt request
- gp->sched.sp = new.hi - used;
-
- runtime·casgstatus(gp, Gcopystack, oldstatus); // oldstatus is Gwaiting or Grunnable
-
- // free old stack
- if(StackPoisonCopy) {
- p = (byte*)old.lo;
- ep = (byte*)old.hi;
- while(p < ep)
- *p++ = 0xfc;
- }
- if(newsize > old.hi-old.lo) {
- // growing, free stack immediately
- runtime·stackfree(old);
- } else {
- // shrinking, queue up free operation. We can't actually free the stack
- // just yet because we might run into the following situation:
- // 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer
- // 2) The stack that pointer points to is shrunk
- // 3) The old stack is freed
- // 4) The containing span is marked free
- // 5) GC attempts to mark the SudoG.elem pointer. The marking fails because
- // the pointer looks like a pointer into a free span.
- // By not freeing, we prevent step #4 until GC is done.
- runtime·lock(&runtime·stackpoolmu);
- *(Stack*)old.lo = stackfreequeue;
- stackfreequeue = old;
- runtime·unlock(&runtime·stackpoolmu);
- }
-}
-
-// round x up to a power of 2.
-int32
-runtime·round2(int32 x)
-{
- int32 s;
-
- s = 0;
- while((1 << s) < x)
- s++;
- return 1 << s;
-}
-
-// Called from runtime·morestack when more stack is needed.
-// Allocate larger stack and relocate to new stack.
-// Stack growth is multiplicative, for constant amortized cost.
-//
-// g->atomicstatus will be Grunning or Gscanrunning upon entry.
-// If the GC is trying to stop this g then it will set preemptscan to true.
-void
-runtime·newstack(void)
-{
- int32 oldsize, newsize;
- uintptr sp;
- G *gp;
- Gobuf morebuf;
-
- if(g->m->morebuf.g->stackguard0 == (uintptr)StackFork)
- runtime·throw("stack growth after fork");
- if(g->m->morebuf.g != g->m->curg) {
- runtime·printf("runtime: newstack called from g=%p\n"
- "\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n",
- g->m->morebuf.g, g->m, g->m->curg, g->m->g0, g->m->gsignal);
- morebuf = g->m->morebuf;
- runtime·traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g);
- runtime·throw("runtime: wrong goroutine in newstack");
- }
- if(g->m->curg->throwsplit)
- runtime·throw("runtime: stack split at bad time");
-
- // The goroutine must be executing in order to call newstack,
- // so it must be Grunning or Gscanrunning.
-
- gp = g->m->curg;
- morebuf = g->m->morebuf;
- g->m->morebuf.pc = (uintptr)nil;
- g->m->morebuf.lr = (uintptr)nil;
- g->m->morebuf.sp = (uintptr)nil;
- g->m->morebuf.g = (G*)nil;
-
- runtime·casgstatus(gp, Grunning, Gwaiting);
- gp->waitreason = runtime·gostringnocopy((byte*)"stack growth");
-
- runtime·rewindmorestack(&gp->sched);
-
- if(gp->stack.lo == 0)
- runtime·throw("missing stack in newstack");
- sp = gp->sched.sp;
- if(thechar == '6' || thechar == '8') {
- // The call to morestack cost a word.
- sp -= sizeof(uintreg);
- }
- if(StackDebug >= 1 || sp < gp->stack.lo) {
- runtime·printf("runtime: newstack sp=%p stack=[%p, %p]\n"
- "\tmorebuf={pc:%p sp:%p lr:%p}\n"
- "\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n",
- sp, gp->stack.lo, gp->stack.hi,
- g->m->morebuf.pc, g->m->morebuf.sp, g->m->morebuf.lr,
- gp->sched.pc, gp->sched.sp, gp->sched.lr, gp->sched.ctxt);
- }
- if(sp < gp->stack.lo) {
- runtime·printf("runtime: gp=%p, gp->status=%d\n ", (void*)gp, runtime·readgstatus(gp));
- runtime·printf("runtime: split stack overflow: %p < %p\n", sp, gp->stack.lo);
- runtime·throw("runtime: split stack overflow");
- }
-
- if(gp->stackguard0 == (uintptr)StackPreempt) {
- if(gp == g->m->g0)
- runtime·throw("runtime: preempt g0");
- if(g->m->p == nil && g->m->locks == 0)
- runtime·throw("runtime: g is running but p is not");
- if(gp->preemptscan) {
- runtime·gcphasework(gp);
- runtime·casgstatus(gp, Gwaiting, Grunning);
- gp->stackguard0 = gp->stack.lo + StackGuard;
- gp->preempt = false;
- gp->preemptscan = false; // Tells the GC premption was successful.
- runtime·gogo(&gp->sched); // never return
- }
-
- // Be conservative about where we preempt.
- // We are interested in preempting user Go code, not runtime code.
- if(g->m->locks || g->m->mallocing || g->m->gcing || g->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;
- runtime·casgstatus(gp, Gwaiting, Grunning);
- runtime·gogo(&gp->sched); // never return
- }
- // Act like goroutine called runtime.Gosched.
- runtime·casgstatus(gp, Gwaiting, Grunning);
- runtime·gosched_m(gp); // never return
- }
-
- // Allocate a bigger segment and move the stack.
- oldsize = gp->stack.hi - gp->stack.lo;
- newsize = oldsize * 2;
- if(newsize > runtime·maxstacksize) {
- runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
- runtime·throw("stack overflow");
- }
-
- // Note that the concurrent GC might be scanning the stack as we try to replace it.
- // copystack takes care of the appropriate coordination with the stack scanner.
- copystack(gp, newsize);
- if(StackDebug >= 1)
- runtime·printf("stack grow done\n");
- runtime·casgstatus(gp, Gwaiting, Grunning);
- runtime·gogo(&gp->sched);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·nilfunc(void)
-{
- *(byte*)0 = 0;
-}
-
-// adjust Gobuf as if it executed a call to fn
-// and then did an immediate gosave.
-void
-runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv)
-{
- void *fn;
-
- if(fv != nil)
- fn = fv->fn;
- else
- fn = runtime·nilfunc;
- runtime·gostartcall(gobuf, fn, fv);
-}
-
-// Maybe shrink the stack being used by gp.
-// Called at garbage collection time.
-void
-runtime·shrinkstack(G *gp)
-{
- uintptr used, oldsize, newsize;
-
- if(runtime·readgstatus(gp) == Gdead) {
- if(gp->stack.lo != 0) {
- // Free whole stack - it will get reallocated
- // if G is used again.
- runtime·stackfree(gp->stack);
- gp->stack.lo = 0;
- gp->stack.hi = 0;
- }
- return;
- }
- if(gp->stack.lo == 0)
- runtime·throw("missing stack in shrinkstack");
-
- oldsize = gp->stack.hi - gp->stack.lo;
- newsize = oldsize / 2;
- if(newsize < FixedStack)
- return; // don't shrink below the minimum-sized stack
- used = gp->stack.hi - gp->sched.sp;
- if(used >= oldsize / 4)
- return; // still using at least 1/4 of the segment.
-
- // We can't copy the stack if we're in a syscall.
- // The syscall might have pointers into the stack.
- if(gp->syscallsp != 0)
- return;
-
-#ifdef GOOS_windows
- if(gp->m != nil && gp->m->libcallsp != 0)
- return;
-#endif
- if(StackDebug > 0)
- runtime·printf("shrinking stack %D->%D\n", (uint64)oldsize, (uint64)newsize);
- copystack(gp, newsize);
-}
-
-// Do any delayed stack freeing that was queued up during GC.
-void
-runtime·shrinkfinish(void)
-{
- Stack s, t;
-
- runtime·lock(&runtime·stackpoolmu);
- s = stackfreequeue;
- stackfreequeue = (Stack){0,0};
- runtime·unlock(&runtime·stackpoolmu);
- while(s.lo != 0) {
- t = *(Stack*)s.lo;
- runtime·stackfree(s);
- s = t;
- }
-}
-
-static void badc(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·morestackc(void)
-{
- void (*fn)(void);
-
- fn = badc;
- runtime·onM(&fn);
-}
-
-static void
-badc(void)
-{
- runtime·throw("attempt to execute C code on Go stack");
-}
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
deleted file mode 100644
index f1b7d32d2..000000000
--- a/src/runtime/stack.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2011 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 runtime
-
-const (
- // Goroutine preemption request.
- // Stored into g->stackguard0 to cause split stack check failure.
- // Must be greater than any real sp.
- // 0xfffffade in hex.
- stackPreempt = ^uintptr(1313)
-)
diff --git a/src/runtime/stack.h b/src/runtime/stack.h
index f97dc4ed8..0099d05c2 100644
--- a/src/runtime/stack.h
+++ b/src/runtime/stack.h
@@ -2,117 +2,24 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-/*
-Stack layout parameters.
-Included both by runtime (compiled via 6c) and linkers (compiled via gcc).
-
-The per-goroutine g->stackguard is set to point StackGuard bytes
-above the bottom of the stack. Each function compares its stack
-pointer against g->stackguard to check for overflow. To cut one
-instruction from the check sequence for functions with tiny frames,
-the stack is allowed to protrude StackSmall bytes below the stack
-guard. Functions with large frames don't bother with the check and
-always call morestack. The sequences are (for amd64, others are
-similar):
-
- guard = g->stackguard
- frame = function's stack frame size
- argsize = size of function arguments (call + return)
-
- stack frame size <= StackSmall:
- CMPQ guard, SP
- JHI 3(PC)
- MOVQ m->morearg, $(argsize << 32)
- CALL morestack(SB)
-
- stack frame size > StackSmall but < StackBig
- LEAQ (frame-StackSmall)(SP), R0
- CMPQ guard, R0
- JHI 3(PC)
- MOVQ m->morearg, $(argsize << 32)
- CALL morestack(SB)
-
- stack frame size >= StackBig:
- MOVQ m->morearg, $((argsize << 32) | frame)
- CALL morestack(SB)
-
-The bottom StackGuard - StackSmall bytes are important: there has
-to be enough room to execute functions that refuse to check for
-stack overflow, either because they need to be adjacent to the
-actual caller's frame (deferproc) or because they handle the imminent
-stack overflow (morestack).
-
-For example, deferproc might call malloc, which does one of the
-above checks (without allocating a full frame), which might trigger
-a call to morestack. This sequence needs to fit in the bottom
-section of the stack. On amd64, morestack's frame is 40 bytes, and
-deferproc's frame is 56 bytes. That fits well within the
-StackGuard - StackSmall bytes at the bottom.
-The linkers explore all possible call traces involving non-splitting
-functions to make sure that this limit cannot be violated.
- */
+// For the linkers. Must match Go definitions.
+// TODO(rsc): Share Go definitions with linkers directly.
enum {
- // StackSystem is a number of additional bytes to add
- // to each stack below the usual guard area for OS-specific
- // purposes like signal handling. Used on Windows and on
- // Plan 9 because they do not use a separate stack.
#ifdef GOOS_windows
StackSystem = 512 * sizeof(uintptr),
#else
#ifdef GOOS_plan9
- // The size of the note handler frame varies among architectures,
- // but 512 bytes should be enough for every implementation.
StackSystem = 512,
#else
StackSystem = 0,
#endif // Plan 9
#endif // Windows
- // The minimum size of stack used by Go code
- StackMin = 2048,
-
- // The minimum stack size to allocate.
- // The hackery here rounds FixedStack0 up to a power of 2.
- FixedStack0 = StackMin + StackSystem,
- FixedStack1 = FixedStack0 - 1,
- FixedStack2 = FixedStack1 | (FixedStack1 >> 1),
- FixedStack3 = FixedStack2 | (FixedStack2 >> 2),
- FixedStack4 = FixedStack3 | (FixedStack3 >> 4),
- FixedStack5 = FixedStack4 | (FixedStack4 >> 8),
- FixedStack6 = FixedStack5 | (FixedStack5 >> 16),
- FixedStack = FixedStack6 + 1,
-
- // Functions that need frames bigger than this use an extra
- // instruction to do the stack split check, to avoid overflow
- // in case SP - framesize wraps below zero.
- // This value can be no bigger than the size of the unmapped
- // space at zero.
StackBig = 4096,
-
- // The stack guard is a pointer this many bytes above the
- // bottom of the stack.
StackGuard = 512 + StackSystem,
-
- // After a stack split check the SP is allowed to be this
- // many bytes below the stack guard. This saves an instruction
- // in the checking sequence for tiny frames.
StackSmall = 128,
-
- // The maximum number of bytes that a chain of NOSPLIT
- // functions can use.
StackLimit = StackGuard - StackSystem - StackSmall,
};
-// Goroutine preemption request.
-// Stored into g->stackguard0 to cause split stack check failure.
-// Must be greater than any real sp.
-// 0xfffffade in hex.
#define StackPreempt ((uint64)-1314)
-/*c2go
-enum
-{
- StackPreempt = -1314,
-};
-*/
-#define StackFork ((uint64)-1234)
diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go
new file mode 100644
index 000000000..1fd61ce1a
--- /dev/null
+++ b/src/runtime/stack1.go
@@ -0,0 +1,801 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+const (
+ // StackDebug == 0: no logging
+ // == 1: logging of per-stack operations
+ // == 2: logging of per-frame operations
+ // == 3: logging of per-word updates
+ // == 4: logging of per-word reads
+ stackDebug = 0
+ stackFromSystem = 0 // allocate stacks from system memory instead of the heap
+ stackFaultOnFree = 0 // old stacks are mapped noaccess to detect use after free
+ stackPoisonCopy = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy
+
+ stackCache = 1
+)
+
+const (
+ uintptrMask = 1<<(8*ptrSize) - 1
+ poisonGC = uintptrMask & 0xf969696969696969
+ poisonStack = uintptrMask & 0x6868686868686868
+
+ // Goroutine preemption request.
+ // Stored into g->stackguard0 to cause split stack check failure.
+ // Must be greater than any real sp.
+ // 0xfffffade in hex.
+ stackPreempt = uintptrMask & -1314
+
+ // Thread is forking.
+ // Stored into g->stackguard0 to cause split stack check failure.
+ // Must be greater than any real sp.
+ stackFork = uintptrMask & -1234
+)
+
+// Global pool of spans that have free stacks.
+// Stacks are assigned an order according to size.
+// order = log_2(size/FixedStack)
+// There is a free list for each order.
+// TODO: one lock per order?
+var stackpool [_NumStackOrders]mspan
+var stackpoolmu mutex
+
+var stackfreequeue stack
+
+func stackinit() {
+ if _StackCacheSize&_PageMask != 0 {
+ gothrow("cache size must be a multiple of page size")
+ }
+ for i := range stackpool {
+ mSpanList_Init(&stackpool[i])
+ }
+}
+
+// Allocates a stack from the free pool. Must be called with
+// stackpoolmu held.
+func stackpoolalloc(order uint8) *mlink {
+ list := &stackpool[order]
+ s := list.next
+ if s == list {
+ // no free stacks. Allocate another span worth.
+ s = mHeap_AllocStack(&mheap_, _StackCacheSize>>_PageShift)
+ if s == nil {
+ gothrow("out of memory")
+ }
+ if s.ref != 0 {
+ gothrow("bad ref")
+ }
+ if s.freelist != nil {
+ gothrow("bad freelist")
+ }
+ for i := uintptr(0); i < _StackCacheSize; i += _FixedStack << order {
+ x := (*mlink)(unsafe.Pointer(uintptr(s.start)<<_PageShift + i))
+ x.next = s.freelist
+ s.freelist = x
+ }
+ mSpanList_Insert(list, s)
+ }
+ x := s.freelist
+ if x == nil {
+ gothrow("span has no free stacks")
+ }
+ s.freelist = x.next
+ s.ref++
+ if s.freelist == nil {
+ // all stacks in s are allocated.
+ mSpanList_Remove(s)
+ }
+ return x
+}
+
+// Adds stack x to the free pool. Must be called with stackpoolmu held.
+func stackpoolfree(x *mlink, order uint8) {
+ s := mHeap_Lookup(&mheap_, (unsafe.Pointer)(x))
+ if s.state != _MSpanStack {
+ gothrow("freeing stack not in a stack span")
+ }
+ if s.freelist == nil {
+ // s will now have a free stack
+ mSpanList_Insert(&stackpool[order], s)
+ }
+ x.next = s.freelist
+ s.freelist = x
+ s.ref--
+ if s.ref == 0 {
+ // span is completely free - return to heap
+ mSpanList_Remove(s)
+ s.freelist = nil
+ mHeap_FreeStack(&mheap_, s)
+ }
+}
+
+// stackcacherefill/stackcacherelease implement a global pool of stack segments.
+// The pool is required to prevent unlimited growth of per-thread caches.
+func stackcacherefill(c *mcache, order uint8) {
+ if stackDebug >= 1 {
+ print("stackcacherefill order=", order, "\n")
+ }
+
+ // Grab some stacks from the global cache.
+ // Grab half of the allowed capacity (to prevent thrashing).
+ var list *mlink
+ var size uintptr
+ lock(&stackpoolmu)
+ for size < _StackCacheSize/2 {
+ x := stackpoolalloc(order)
+ x.next = list
+ list = x
+ size += _FixedStack << order
+ }
+ unlock(&stackpoolmu)
+ c.stackcache[order].list = list
+ c.stackcache[order].size = size
+}
+
+func stackcacherelease(c *mcache, order uint8) {
+ if stackDebug >= 1 {
+ print("stackcacherelease order=", order, "\n")
+ }
+ x := c.stackcache[order].list
+ size := c.stackcache[order].size
+ lock(&stackpoolmu)
+ for size > _StackCacheSize/2 {
+ y := x.next
+ stackpoolfree(x, order)
+ x = y
+ size -= _FixedStack << order
+ }
+ unlock(&stackpoolmu)
+ c.stackcache[order].list = x
+ c.stackcache[order].size = size
+}
+
+func stackcache_clear(c *mcache) {
+ if stackDebug >= 1 {
+ print("stackcache clear\n")
+ }
+ lock(&stackpoolmu)
+ for order := uint8(0); order < _NumStackOrders; order++ {
+ x := c.stackcache[order].list
+ for x != nil {
+ y := x.next
+ stackpoolfree(x, order)
+ x = y
+ }
+ c.stackcache[order].list = nil
+ c.stackcache[order].size = 0
+ }
+ unlock(&stackpoolmu)
+}
+
+func stackalloc(n uint32) stack {
+ // Stackalloc must be called on scheduler stack, so that we
+ // never try to grow the stack during the code that stackalloc runs.
+ // Doing so would cause a deadlock (issue 1547).
+ thisg := getg()
+ if thisg != thisg.m.g0 {
+ gothrow("stackalloc not on scheduler stack")
+ }
+ if n&(n-1) != 0 {
+ gothrow("stack size not a power of 2")
+ }
+ if stackDebug >= 1 {
+ print("stackalloc ", n, "\n")
+ }
+
+ if debug.efence != 0 || stackFromSystem != 0 {
+ v := sysAlloc(round(uintptr(n), _PageSize), &memstats.stacks_sys)
+ if v == nil {
+ gothrow("out of memory (stackalloc)")
+ }
+ return stack{uintptr(v), uintptr(v) + uintptr(n)}
+ }
+
+ // Small stacks are allocated with a fixed-size free-list allocator.
+ // If we need a stack of a bigger size, we fall back on allocating
+ // a dedicated span.
+ var v unsafe.Pointer
+ if stackCache != 0 && n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
+ order := uint8(0)
+ n2 := n
+ for n2 > _FixedStack {
+ order++
+ n2 >>= 1
+ }
+ var x *mlink
+ c := thisg.m.mcache
+ if c == nil || thisg.m.gcing != 0 || 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
+ // as it's flushed concurrently.
+ lock(&stackpoolmu)
+ x = stackpoolalloc(order)
+ unlock(&stackpoolmu)
+ } else {
+ x = c.stackcache[order].list
+ if x == nil {
+ stackcacherefill(c, order)
+ x = c.stackcache[order].list
+ }
+ c.stackcache[order].list = x.next
+ c.stackcache[order].size -= uintptr(n)
+ }
+ v = (unsafe.Pointer)(x)
+ } else {
+ s := mHeap_AllocStack(&mheap_, round(uintptr(n), _PageSize)>>_PageShift)
+ if s == nil {
+ gothrow("out of memory")
+ }
+ v = (unsafe.Pointer)(s.start << _PageShift)
+ }
+
+ if raceenabled {
+ racemalloc(v, uintptr(n))
+ }
+ if stackDebug >= 1 {
+ print(" allocated ", v, "\n")
+ }
+ return stack{uintptr(v), uintptr(v) + uintptr(n)}
+}
+
+func stackfree(stk stack) {
+ gp := getg()
+ n := stk.hi - stk.lo
+ v := (unsafe.Pointer)(stk.lo)
+ if n&(n-1) != 0 {
+ gothrow("stack not a power of 2")
+ }
+ if stackDebug >= 1 {
+ println("stackfree", v, n)
+ memclr(v, n) // for testing, clobber stack data
+ }
+ if debug.efence != 0 || stackFromSystem != 0 {
+ if debug.efence != 0 || stackFaultOnFree != 0 {
+ sysFault(v, n)
+ } else {
+ sysFree(v, n, &memstats.stacks_sys)
+ }
+ return
+ }
+ if stackCache != 0 && n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
+ order := uint8(0)
+ n2 := n
+ for n2 > _FixedStack {
+ order++
+ n2 >>= 1
+ }
+ x := (*mlink)(v)
+ c := gp.m.mcache
+ if c == nil || gp.m.gcing != 0 || gp.m.helpgc != 0 {
+ lock(&stackpoolmu)
+ stackpoolfree(x, order)
+ unlock(&stackpoolmu)
+ } else {
+ if c.stackcache[order].size >= _StackCacheSize {
+ stackcacherelease(c, order)
+ }
+ x.next = c.stackcache[order].list
+ c.stackcache[order].list = x
+ c.stackcache[order].size += n
+ }
+ } else {
+ s := mHeap_Lookup(&mheap_, v)
+ if s.state != _MSpanStack {
+ println(hex(s.start<<_PageShift), v)
+ gothrow("bad span state")
+ }
+ mHeap_FreeStack(&mheap_, s)
+ }
+}
+
+var maxstacksize uintptr = 1 << 20 // enough until runtime.main sets it for real
+
+var mapnames = []string{
+ _BitsDead: "---",
+ _BitsScalar: "scalar",
+ _BitsPointer: "ptr",
+}
+
+// Stack frame layout
+//
+// (x86)
+// +------------------+
+// | args from caller |
+// +------------------+ <- frame->argp
+// | return address |
+// +------------------+ <- frame->varp
+// | locals |
+// +------------------+
+// | args to callee |
+// +------------------+ <- frame->sp
+//
+// (arm)
+// +------------------+
+// | args from caller |
+// +------------------+ <- frame->argp
+// | caller's retaddr |
+// +------------------+ <- frame->varp
+// | locals |
+// +------------------+
+// | args to callee |
+// +------------------+
+// | return address |
+// +------------------+ <- frame->sp
+
+type adjustinfo struct {
+ old stack
+ delta uintptr // ptr distance from old to new stack (newbase - oldbase)
+}
+
+// Adjustpointer checks whether *vpp is in the old stack described by adjinfo.
+// If so, it rewrites *vpp to point into the new stack.
+func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
+ pp := (*unsafe.Pointer)(vpp)
+ p := *pp
+ if stackDebug >= 4 {
+ print(" ", pp, ":", p, "\n")
+ }
+ if adjinfo.old.lo <= uintptr(p) && uintptr(p) < adjinfo.old.hi {
+ *pp = add(p, adjinfo.delta)
+ if stackDebug >= 3 {
+ print(" adjust ptr ", pp, ":", p, " -> ", *pp, "\n")
+ }
+ }
+}
+
+type gobitvector struct {
+ n uintptr
+ bytedata []uint8
+}
+
+func gobv(bv bitvector) gobitvector {
+ return gobitvector{
+ uintptr(bv.n),
+ (*[1 << 30]byte)(unsafe.Pointer(bv.bytedata))[:(bv.n+7)/8],
+ }
+}
+
+func ptrbits(bv *gobitvector, i uintptr) uint8 {
+ return (bv.bytedata[i/4] >> ((i & 3) * 2)) & 3
+}
+
+// bv describes the memory starting at address scanp.
+// Adjust any pointers contained therein.
+func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f *_func) {
+ bv := gobv(*cbv)
+ minp := adjinfo.old.lo
+ maxp := adjinfo.old.hi
+ delta := adjinfo.delta
+ num := uintptr(bv.n / _BitsPerPointer)
+ for i := uintptr(0); i < num; i++ {
+ if stackDebug >= 4 {
+ print(" ", add(scanp, i*ptrSize), ":", mapnames[ptrbits(&bv, i)], ":", hex(*(*uintptr)(add(scanp, i*ptrSize))), " # ", i, " ", bv.bytedata[i/4], "\n")
+ }
+ switch ptrbits(&bv, i) {
+ default:
+ gothrow("unexpected pointer bits")
+ case _BitsDead:
+ if debug.gcdead != 0 {
+ *(*unsafe.Pointer)(add(scanp, i*ptrSize)) = unsafe.Pointer(uintptr(poisonStack))
+ }
+ case _BitsScalar:
+ // ok
+ case _BitsPointer:
+ p := *(*unsafe.Pointer)(add(scanp, i*ptrSize))
+ up := uintptr(p)
+ if f != nil && 0 < up && up < _PageSize && invalidptr != 0 || up == poisonGC || up == poisonStack {
+ // Looks like a junk value in a pointer slot.
+ // Live analysis wrong?
+ getg().m.traceback = 2
+ print("runtime: bad pointer in frame ", gofuncname(f), " at ", add(scanp, i*ptrSize), ": ", p, "\n")
+ gothrow("invalid stack pointer")
+ }
+ if minp <= up && up < maxp {
+ if stackDebug >= 3 {
+ print("adjust ptr ", p, " ", gofuncname(f), "\n")
+ }
+ *(*unsafe.Pointer)(add(scanp, i*ptrSize)) = unsafe.Pointer(up + delta)
+ }
+ }
+ }
+}
+
+// Note: the argument/return area is adjusted by the callee.
+func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
+ adjinfo := (*adjustinfo)(arg)
+ targetpc := frame.continpc
+ if targetpc == 0 {
+ // Frame is dead.
+ return true
+ }
+ f := frame.fn
+ if stackDebug >= 2 {
+ print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
+ }
+ if f.entry == systemstack_switchPC {
+ // A special routine at the bottom of stack of a goroutine that does an systemstack call.
+ // We will allow it to be copied even though we don't
+ // have full GC info for it (because it is written in asm).
+ return true
+ }
+ if targetpc != f.entry {
+ targetpc--
+ }
+ pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc)
+ if pcdata == -1 {
+ pcdata = 0 // in prologue
+ }
+
+ // Adjust local variables if stack frame has been allocated.
+ size := frame.varp - frame.sp
+ var minsize uintptr
+ if thechar != '6' && thechar != '8' {
+ minsize = ptrSize
+ } else {
+ minsize = 0
+ }
+ if size > minsize {
+ var bv bitvector
+ stackmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
+ if stackmap == nil || stackmap.n <= 0 {
+ print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n")
+ gothrow("missing stackmap")
+ }
+ // Locals bitmap information, scan just the pointers in locals.
+ if pcdata < 0 || pcdata >= stackmap.n {
+ // don't know where we are
+ print("runtime: pcdata is ", pcdata, " and ", stackmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n")
+ gothrow("bad symbol table")
+ }
+ bv = stackmapdata(stackmap, pcdata)
+ size = (uintptr(bv.n) * ptrSize) / _BitsPerPointer
+ if stackDebug >= 3 {
+ print(" locals ", pcdata, "/", stackmap.n, " ", size/ptrSize, " words ", bv.bytedata, "\n")
+ }
+ adjustpointers(unsafe.Pointer(frame.varp-size), &bv, adjinfo, f)
+ }
+
+ // Adjust arguments.
+ if frame.arglen > 0 {
+ var bv bitvector
+ if frame.argmap != nil {
+ bv = *frame.argmap
+ } else {
+ stackmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps))
+ if stackmap == nil || stackmap.n <= 0 {
+ print("runtime: frame ", funcname(f), " untyped args ", frame.argp, "+", uintptr(frame.arglen), "\n")
+ gothrow("missing stackmap")
+ }
+ if pcdata < 0 || pcdata >= stackmap.n {
+ // don't know where we are
+ print("runtime: pcdata is ", pcdata, " and ", stackmap.n, " args stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n")
+ gothrow("bad symbol table")
+ }
+ bv = stackmapdata(stackmap, pcdata)
+ }
+ if stackDebug >= 3 {
+ print(" args\n")
+ }
+ adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, nil)
+ }
+ return true
+}
+
+func adjustctxt(gp *g, adjinfo *adjustinfo) {
+ adjustpointer(adjinfo, (unsafe.Pointer)(&gp.sched.ctxt))
+}
+
+func adjustdefers(gp *g, adjinfo *adjustinfo) {
+ // Adjust defer argument blocks the same way we adjust active stack frames.
+ tracebackdefers(gp, adjustframe, noescape(unsafe.Pointer(adjinfo)))
+
+ // Adjust pointers in the Defer structs.
+ // Defer structs themselves are never on the stack.
+ for d := gp._defer; d != nil; d = d.link {
+ adjustpointer(adjinfo, (unsafe.Pointer)(&d.fn))
+ adjustpointer(adjinfo, (unsafe.Pointer)(&d.argp))
+ adjustpointer(adjinfo, (unsafe.Pointer)(&d._panic))
+ }
+}
+
+func adjustpanics(gp *g, adjinfo *adjustinfo) {
+ // Panics are on stack and already adjusted.
+ // Update pointer to head of list in G.
+ adjustpointer(adjinfo, (unsafe.Pointer)(&gp._panic))
+}
+
+func adjustsudogs(gp *g, adjinfo *adjustinfo) {
+ // the data elements pointed to by a SudoG structure
+ // might be in the stack.
+ for s := gp.waiting; s != nil; s = s.waitlink {
+ adjustpointer(adjinfo, (unsafe.Pointer)(&s.elem))
+ adjustpointer(adjinfo, (unsafe.Pointer)(&s.selectdone))
+ }
+}
+
+func fillstack(stk stack, b byte) {
+ for p := stk.lo; p < stk.hi; p++ {
+ *(*byte)(unsafe.Pointer(p)) = b
+ }
+}
+
+// Copies gp's stack to a new stack of a different size.
+func copystack(gp *g, newsize uintptr) {
+ if gp.syscallsp != 0 {
+ gothrow("stack growth not allowed in system call")
+ }
+ old := gp.stack
+ if old.lo == 0 {
+ gothrow("nil stackbase")
+ }
+ used := old.hi - gp.sched.sp
+
+ // allocate new stack
+ new := stackalloc(uint32(newsize))
+ if stackPoisonCopy != 0 {
+ fillstack(new, 0xfd)
+ }
+ if stackDebug >= 1 {
+ print("copystack gp=", gp, " [", hex(old.lo), " ", hex(old.hi-used), " ", hex(old.hi), "]/", old.hi-old.lo, " -> [", hex(new.lo), " ", hex(new.hi-used), " ", hex(new.hi), "]/", newsize, "\n")
+ }
+
+ // adjust pointers in the to-be-copied frames
+ var adjinfo adjustinfo
+ adjinfo.old = old
+ adjinfo.delta = new.hi - old.hi
+ gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, adjustframe, noescape(unsafe.Pointer(&adjinfo)), 0)
+
+ // adjust other miscellaneous things that have pointers into stacks.
+ adjustctxt(gp, &adjinfo)
+ adjustdefers(gp, &adjinfo)
+ adjustpanics(gp, &adjinfo)
+ adjustsudogs(gp, &adjinfo)
+
+ // copy the stack to the new location
+ if stackPoisonCopy != 0 {
+ fillstack(new, 0xfb)
+ }
+ memmove(unsafe.Pointer(new.hi-used), unsafe.Pointer(old.hi-used), used)
+
+ oldstatus := casgcopystack(gp) // cas from Gwaiting or Grunnable to Gcopystack, return old status
+
+ // Swap out old stack for new one
+ gp.stack = new
+ gp.stackguard0 = new.lo + _StackGuard // NOTE: might clobber a preempt request
+ gp.sched.sp = new.hi - used
+
+ casgstatus(gp, _Gcopystack, oldstatus) // oldstatus is Gwaiting or Grunnable
+
+ // free old stack
+ if stackPoisonCopy != 0 {
+ fillstack(old, 0xfc)
+ }
+ if newsize > old.hi-old.lo {
+ // growing, free stack immediately
+ stackfree(old)
+ } else {
+ // shrinking, queue up free operation. We can't actually free the stack
+ // just yet because we might run into the following situation:
+ // 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer
+ // 2) The stack that pointer points to is shrunk
+ // 3) The old stack is freed
+ // 4) The containing span is marked free
+ // 5) GC attempts to mark the SudoG.elem pointer. The marking fails because
+ // the pointer looks like a pointer into a free span.
+ // By not freeing, we prevent step #4 until GC is done.
+ lock(&stackpoolmu)
+ *(*stack)(unsafe.Pointer(old.lo)) = stackfreequeue
+ stackfreequeue = old
+ unlock(&stackpoolmu)
+ }
+}
+
+// round x up to a power of 2.
+func round2(x int32) int32 {
+ s := uint(0)
+ for 1<<s < x {
+ s++
+ }
+ return 1 << s
+}
+
+// Called from runtime·morestack when more stack is needed.
+// Allocate larger stack and relocate to new stack.
+// Stack growth is multiplicative, for constant amortized cost.
+//
+// g->atomicstatus will be Grunning or Gscanrunning upon entry.
+// If the GC is trying to stop this g then it will set preemptscan to true.
+func newstack() {
+ thisg := getg()
+ // TODO: double check all gp. shouldn't be getg().
+ if thisg.m.morebuf.g.stackguard0 == stackFork {
+ gothrow("stack growth after fork")
+ }
+ if thisg.m.morebuf.g != thisg.m.curg {
+ print("runtime: newstack called from g=", thisg.m.morebuf.g, "\n"+"\tm=", thisg.m, " m->curg=", thisg.m.curg, " m->g0=", thisg.m.g0, " m->gsignal=", thisg.m.gsignal, "\n")
+ morebuf := thisg.m.morebuf
+ traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g)
+ gothrow("runtime: wrong goroutine in newstack")
+ }
+ if thisg.m.curg.throwsplit {
+ gp := thisg.m.curg
+ // Update syscallsp, syscallpc in case traceback uses them.
+ morebuf := thisg.m.morebuf
+ gp.syscallsp = morebuf.sp
+ gp.syscallpc = morebuf.pc
+ print("runtime: newstack sp=", hex(gp.sched.sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n",
+ "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n",
+ "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n")
+ gothrow("runtime: stack split at bad time")
+ }
+
+ // The goroutine must be executing in order to call newstack,
+ // so it must be Grunning or Gscanrunning.
+
+ gp := thisg.m.curg
+ morebuf := thisg.m.morebuf
+ thisg.m.morebuf.pc = 0
+ thisg.m.morebuf.lr = 0
+ thisg.m.morebuf.sp = 0
+ thisg.m.morebuf.g = nil
+
+ casgstatus(gp, _Grunning, _Gwaiting)
+ gp.waitreason = "stack growth"
+
+ rewindmorestack(&gp.sched)
+
+ if gp.stack.lo == 0 {
+ gothrow("missing stack in newstack")
+ }
+ sp := gp.sched.sp
+ if thechar == '6' || thechar == '8' {
+ // The call to morestack cost a word.
+ sp -= ptrSize
+ }
+ if stackDebug >= 1 || sp < gp.stack.lo {
+ print("runtime: newstack sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n",
+ "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n",
+ "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n")
+ }
+ if sp < gp.stack.lo {
+ print("runtime: gp=", gp, ", gp->status=", hex(readgstatus(gp)), "\n ")
+ print("runtime: split stack overflow: ", hex(sp), " < ", hex(gp.stack.lo), "\n")
+ gothrow("runtime: split stack overflow")
+ }
+
+ if gp.stackguard0 == stackPreempt {
+ if gp == thisg.m.g0 {
+ gothrow("runtime: preempt g0")
+ }
+ if thisg.m.p == nil && thisg.m.locks == 0 {
+ gothrow("runtime: g is running but p is not")
+ }
+ if gp.preemptscan {
+ gcphasework(gp)
+ casgstatus(gp, _Gwaiting, _Grunning)
+ gp.stackguard0 = gp.stack.lo + _StackGuard
+ gp.preempt = false
+ gp.preemptscan = false // Tells the GC premption was successful.
+ gogo(&gp.sched) // never return
+ }
+
+ // Be conservative about where we preempt.
+ // We are interested in preempting user Go code, not runtime code.
+ if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.gcing != 0 || 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
+ casgstatus(gp, _Gwaiting, _Grunning)
+ gogo(&gp.sched) // never return
+ }
+
+ // Act like goroutine called runtime.Gosched.
+ casgstatus(gp, _Gwaiting, _Grunning)
+ gosched_m(gp) // never return
+ }
+
+ // Allocate a bigger segment and move the stack.
+ oldsize := int(gp.stack.hi - gp.stack.lo)
+ newsize := oldsize * 2
+ if uintptr(newsize) > maxstacksize {
+ print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n")
+ gothrow("stack overflow")
+ }
+
+ // Note that the concurrent GC might be scanning the stack as we try to replace it.
+ // copystack takes care of the appropriate coordination with the stack scanner.
+ copystack(gp, uintptr(newsize))
+ if stackDebug >= 1 {
+ print("stack grow done\n")
+ }
+ casgstatus(gp, _Gwaiting, _Grunning)
+ gogo(&gp.sched)
+}
+
+//go:nosplit
+func nilfunc() {
+ *(*uint8)(nil) = 0
+}
+
+// adjust Gobuf as if it executed a call to fn
+// and then did an immediate gosave.
+func gostartcallfn(gobuf *gobuf, fv *funcval) {
+ var fn unsafe.Pointer
+ if fv != nil {
+ fn = (unsafe.Pointer)(fv.fn)
+ } else {
+ fn = unsafe.Pointer(funcPC(nilfunc))
+ }
+ gostartcall(gobuf, fn, (unsafe.Pointer)(fv))
+}
+
+// Maybe shrink the stack being used by gp.
+// Called at garbage collection time.
+func shrinkstack(gp *g) {
+ if readgstatus(gp) == _Gdead {
+ if gp.stack.lo != 0 {
+ // Free whole stack - it will get reallocated
+ // if G is used again.
+ stackfree(gp.stack)
+ gp.stack.lo = 0
+ gp.stack.hi = 0
+ }
+ return
+ }
+ if gp.stack.lo == 0 {
+ gothrow("missing stack in shrinkstack")
+ }
+
+ oldsize := gp.stack.hi - gp.stack.lo
+ newsize := oldsize / 2
+ if newsize < _FixedStack {
+ return // don't shrink below the minimum-sized stack
+ }
+ used := gp.stack.hi - gp.sched.sp
+ if used >= oldsize/4 {
+ return // still using at least 1/4 of the segment.
+ }
+
+ // We can't copy the stack if we're in a syscall.
+ // The syscall might have pointers into the stack.
+ if gp.syscallsp != 0 {
+ return
+ }
+
+ /* TODO
+ if goos_windows && gp.m != nil && gp.m.libcallsp != 0 {
+ return
+ }
+ */
+
+ if stackDebug > 0 {
+ print("shrinking stack ", oldsize, "->", newsize, "\n")
+ }
+ copystack(gp, newsize)
+}
+
+// Do any delayed stack freeing that was queued up during GC.
+func shrinkfinish() {
+ lock(&stackpoolmu)
+ s := stackfreequeue
+ stackfreequeue = stack{}
+ unlock(&stackpoolmu)
+ for s.lo != 0 {
+ t := *(*stack)(unsafe.Pointer(s.lo))
+ stackfree(s)
+ s = t
+ }
+}
+
+//go:nosplit
+func morestackc() {
+ systemstack(func() {
+ gothrow("attempt to execute C code on Go stack")
+ })
+}
diff --git a/src/runtime/stack2.go b/src/runtime/stack2.go
new file mode 100644
index 000000000..e50b32c78
--- /dev/null
+++ b/src/runtime/stack2.go
@@ -0,0 +1,106 @@
+// Copyright 2011 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 runtime
+
+/*
+Stack layout parameters.
+Included both by runtime (compiled via 6c) and linkers (compiled via gcc).
+
+The per-goroutine g->stackguard is set to point StackGuard bytes
+above the bottom of the stack. Each function compares its stack
+pointer against g->stackguard to check for overflow. To cut one
+instruction from the check sequence for functions with tiny frames,
+the stack is allowed to protrude StackSmall bytes below the stack
+guard. Functions with large frames don't bother with the check and
+always call morestack. The sequences are (for amd64, others are
+similar):
+
+ guard = g->stackguard
+ frame = function's stack frame size
+ argsize = size of function arguments (call + return)
+
+ stack frame size <= StackSmall:
+ CMPQ guard, SP
+ JHI 3(PC)
+ MOVQ m->morearg, $(argsize << 32)
+ CALL morestack(SB)
+
+ stack frame size > StackSmall but < StackBig
+ LEAQ (frame-StackSmall)(SP), R0
+ CMPQ guard, R0
+ JHI 3(PC)
+ MOVQ m->morearg, $(argsize << 32)
+ CALL morestack(SB)
+
+ stack frame size >= StackBig:
+ MOVQ m->morearg, $((argsize << 32) | frame)
+ CALL morestack(SB)
+
+The bottom StackGuard - StackSmall bytes are important: there has
+to be enough room to execute functions that refuse to check for
+stack overflow, either because they need to be adjacent to the
+actual caller's frame (deferproc) or because they handle the imminent
+stack overflow (morestack).
+
+For example, deferproc might call malloc, which does one of the
+above checks (without allocating a full frame), which might trigger
+a call to morestack. This sequence needs to fit in the bottom
+section of the stack. On amd64, morestack's frame is 40 bytes, and
+deferproc's frame is 56 bytes. That fits well within the
+StackGuard - StackSmall bytes at the bottom.
+The linkers explore all possible call traces involving non-splitting
+functions to make sure that this limit cannot be violated.
+*/
+
+const (
+ // StackSystem is a number of additional bytes to add
+ // to each stack below the usual guard area for OS-specific
+ // purposes like signal handling. Used on Windows and on
+ // Plan 9 because they do not use a separate stack.
+ _StackSystem = goos_windows*512*ptrSize + goos_plan9*512
+
+ // The minimum size of stack used by Go code
+ _StackMin = 2048
+
+ // The minimum stack size to allocate.
+ // The hackery here rounds FixedStack0 up to a power of 2.
+ _FixedStack0 = _StackMin + _StackSystem
+ _FixedStack1 = _FixedStack0 - 1
+ _FixedStack2 = _FixedStack1 | (_FixedStack1 >> 1)
+ _FixedStack3 = _FixedStack2 | (_FixedStack2 >> 2)
+ _FixedStack4 = _FixedStack3 | (_FixedStack3 >> 4)
+ _FixedStack5 = _FixedStack4 | (_FixedStack4 >> 8)
+ _FixedStack6 = _FixedStack5 | (_FixedStack5 >> 16)
+ _FixedStack = _FixedStack6 + 1
+
+ // Functions that need frames bigger than this use an extra
+ // instruction to do the stack split check, to avoid overflow
+ // in case SP - framesize wraps below zero.
+ // This value can be no bigger than the size of the unmapped
+ // space at zero.
+ _StackBig = 4096
+
+ // The stack guard is a pointer this many bytes above the
+ // bottom of the stack.
+ _StackGuard = 512 + _StackSystem
+
+ // After a stack split check the SP is allowed to be this
+ // many bytes below the stack guard. This saves an instruction
+ // in the checking sequence for tiny frames.
+ _StackSmall = 128
+
+ // The maximum number of bytes that a chain of NOSPLIT
+ // functions can use.
+ _StackLimit = _StackGuard - _StackSystem - _StackSmall
+)
+
+// Goroutine preemption request.
+// Stored into g->stackguard0 to cause split stack check failure.
+// Must be greater than any real sp.
+// 0xfffffade in hex.
+const (
+ _StackPreempt = uintptrMask & -1314
+ _StackFork = uintptrMask & -1234
+)
diff --git a/src/runtime/string.c b/src/runtime/string.c
deleted file mode 100644
index ed5debc33..000000000
--- a/src/runtime/string.c
+++ /dev/null
@@ -1,226 +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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "race.h"
-#include "textflag.h"
-
-String runtime·emptystring;
-
-#pragma textflag NOSPLIT
-intgo
-runtime·findnull(byte *s)
-{
- intgo l;
-
- if(s == nil)
- return 0;
- for(l=0; s[l]!=0; l++)
- ;
- return l;
-}
-
-intgo
-runtime·findnullw(uint16 *s)
-{
- intgo l;
-
- if(s == nil)
- return 0;
- for(l=0; s[l]!=0; l++)
- ;
- return l;
-}
-
-uintptr runtime·maxstring = 256; // a hint for print
-
-#pragma textflag NOSPLIT
-String
-runtime·gostringnocopy(byte *str)
-{
- String s;
- uintptr ms;
-
- s.str = str;
- s.len = runtime·findnull(str);
- while(true) {
- ms = runtime·maxstring;
- if(s.len <= ms || runtime·casp((void**)&runtime·maxstring, (void*)ms, (void*)s.len))
- return s;
- }
-}
-
-// TODO: move this elsewhere
-enum
-{
- Bit1 = 7,
- Bitx = 6,
- Bit2 = 5,
- Bit3 = 4,
- Bit4 = 3,
- Bit5 = 2,
-
- Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
- T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
- T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
- T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
-
- Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
- Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
- Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
-
- Maskx = (1<<Bitx)-1, /* 0011 1111 */
-
- Runeerror = 0xFFFD,
-
- SurrogateMin = 0xD800,
- SurrogateMax = 0xDFFF,
-
- Runemax = 0x10FFFF, /* maximum rune value */
-};
-
-static int32
-runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */
-{
- /* Runes are signed, so convert to unsigned for range check. */
- uint32 c;
-
- /*
- * one character sequence
- * 00000-0007F => 00-7F
- */
- c = rune;
- if(c <= Rune1) {
- str[0] = c;
- return 1;
- }
-
- /*
- * two character sequence
- * 0080-07FF => T2 Tx
- */
- if(c <= Rune2) {
- str[0] = T2 | (c >> 1*Bitx);
- str[1] = Tx | (c & Maskx);
- return 2;
- }
-
- /*
- * If the Rune is out of range or a surrogate half, convert it to the error rune.
- * Do this test here because the error rune encodes to three bytes.
- * Doing it earlier would duplicate work, since an out of range
- * Rune wouldn't have fit in one or two bytes.
- */
- if (c > Runemax)
- c = Runeerror;
- if (SurrogateMin <= c && c <= SurrogateMax)
- c = Runeerror;
-
- /*
- * three character sequence
- * 0800-FFFF => T3 Tx Tx
- */
- if (c <= Rune3) {
- str[0] = T3 | (c >> 2*Bitx);
- str[1] = Tx | ((c >> 1*Bitx) & Maskx);
- str[2] = Tx | (c & Maskx);
- return 3;
- }
-
- /*
- * four character sequence (21-bit value)
- * 10000-1FFFFF => T4 Tx Tx Tx
- */
- str[0] = T4 | (c >> 3*Bitx);
- str[1] = Tx | ((c >> 2*Bitx) & Maskx);
- str[2] = Tx | ((c >> 1*Bitx) & Maskx);
- str[3] = Tx | (c & Maskx);
- return 4;
-}
-
-String runtime·gostringsize(intgo);
-
-String
-runtime·gostringw(uint16 *str)
-{
- intgo n1, n2, i;
- byte buf[8];
- String s;
-
- n1 = 0;
- for(i=0; str[i]; i++)
- n1 += runetochar(buf, str[i]);
- s = runtime·gostringsize(n1+4);
- n2 = 0;
- for(i=0; str[i]; i++) {
- // check for race
- if(n2 >= n1)
- break;
- n2 += runetochar(s.str+n2, str[i]);
- }
- s.len = n2;
- s.str[s.len] = 0;
- return s;
-}
-
-int32
-runtime·strcmp(byte *s1, byte *s2)
-{
- uintptr i;
- byte c1, c2;
-
- for(i=0;; i++) {
- c1 = s1[i];
- c2 = s2[i];
- if(c1 < c2)
- return -1;
- if(c1 > c2)
- return +1;
- if(c1 == 0)
- return 0;
- }
-}
-
-int32
-runtime·strncmp(byte *s1, byte *s2, uintptr n)
-{
- uintptr i;
- byte c1, c2;
-
- for(i=0; i<n; i++) {
- c1 = s1[i];
- c2 = s2[i];
- if(c1 < c2)
- return -1;
- if(c1 > c2)
- return +1;
- if(c1 == 0)
- break;
- }
- return 0;
-}
-
-byte*
-runtime·strstr(byte *s1, byte *s2)
-{
- byte *sp1, *sp2;
-
- if(*s2 == 0)
- return s1;
- for(; *s1; s1++) {
- if(*s1 != *s2)
- continue;
- sp1 = s1;
- sp2 = s2;
- for(;;) {
- if(*sp2 == 0)
- return s1;
- if(*sp1++ != *sp2++)
- break;
- }
- }
- return nil;
-}
diff --git a/src/runtime/string.go b/src/runtime/string.go
index 0809f89bc..e01bc3b84 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -39,22 +39,18 @@ func concatstrings(a []string) string {
return s
}
-//go:nosplit
func concatstring2(a [2]string) string {
return concatstrings(a[:])
}
-//go:nosplit
func concatstring3(a [3]string) string {
return concatstrings(a[:])
}
-//go:nosplit
func concatstring4(a [4]string) string {
return concatstrings(a[:])
}
-//go:nosplit
func concatstring5(a [5]string) string {
return concatstrings(a[:])
}
@@ -225,7 +221,7 @@ func rawbyteslice(size int) (b []byte) {
// rawruneslice allocates a new rune slice. The rune slice is not zeroed.
func rawruneslice(size int) (b []rune) {
- if uintptr(size) > maxmem/4 {
+ if uintptr(size) > _MaxMem/4 {
gothrow("out of memory")
}
mem := goroundupsize(uintptr(size) * 4)
@@ -255,9 +251,6 @@ func gostringsize(n int) string {
return s
}
-//go:noescape
-func findnull(*byte) int
-
func gostring(p *byte) string {
l := findnull(p)
if l == 0 {
@@ -296,3 +289,12 @@ func contains(s, t string) bool {
func hasprefix(s, t string) bool {
return len(s) >= len(t) && s[:len(t)] == t
}
+
+func goatoi(s string) int {
+ n := 0
+ for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
+ n = n*10 + int(s[0]) - '0'
+ s = s[1:]
+ }
+ return n
+}
diff --git a/src/runtime/string1.go b/src/runtime/string1.go
new file mode 100644
index 000000000..35cde43be
--- /dev/null
+++ b/src/runtime/string1.go
@@ -0,0 +1,108 @@
+// 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 runtime
+
+import "unsafe"
+
+//go:nosplit
+func findnull(s *byte) int {
+ if s == nil {
+ return 0
+ }
+ p := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s))
+ l := 0
+ for p[l] != 0 {
+ l++
+ }
+ return l
+}
+
+func findnullw(s *uint16) int {
+ if s == nil {
+ return 0
+ }
+ p := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(s))
+ l := 0
+ for p[l] != 0 {
+ l++
+ }
+ return l
+}
+
+var maxstring uintptr = 256 // a hint for print
+
+//go:nosplit
+func gostringnocopy(str *byte) string {
+ var s string
+ sp := (*stringStruct)(unsafe.Pointer(&s))
+ sp.str = unsafe.Pointer(str)
+ sp.len = findnull(str)
+ for {
+ ms := maxstring
+ if uintptr(len(s)) <= ms || casuintptr(&maxstring, ms, uintptr(len(s))) {
+ break
+ }
+ }
+ return s
+}
+
+func gostringw(strw *uint16) string {
+ var buf [8]byte
+ str := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(strw))
+ n1 := 0
+ for i := 0; str[i] != 0; i++ {
+ n1 += runetochar(buf[:], rune(str[i]))
+ }
+ s, b := rawstring(n1 + 4)
+ n2 := 0
+ for i := 0; str[i] != 0; i++ {
+ // check for race
+ if n2 >= n1 {
+ break
+ }
+ n2 += runetochar(b[n2:], rune(str[i]))
+ }
+ b[n2] = 0 // for luck
+ return s[:n2]
+}
+
+func strcmp(s1, s2 *byte) int32 {
+ p1 := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s1))
+ p2 := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s2))
+
+ for i := uintptr(0); ; i++ {
+ c1 := p1[i]
+ c2 := p2[i]
+ if c1 < c2 {
+ return -1
+ }
+ if c1 > c2 {
+ return +1
+ }
+ if c1 == 0 {
+ return 0
+ }
+ }
+}
+
+func strncmp(s1, s2 *byte, n uintptr) int32 {
+ p1 := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s1))
+ p2 := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s2))
+
+ for i := uintptr(0); i < n; i++ {
+ c1 := p1[i]
+ c2 := p2[i]
+ if c1 < c2 {
+ return -1
+ }
+ if c1 > c2 {
+ return +1
+ }
+ if c1 == 0 {
+ break
+ }
+ }
+ return 0
+}
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index 1282397ad..aa7577cf9 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -23,12 +23,7 @@ func roundup(p unsafe.Pointer, n uintptr) unsafe.Pointer {
return unsafe.Pointer(uintptr(p) + delta)
}
-// in runtime.c
func getg() *g
-func acquirem() *m
-func releasem(mp *m)
-func gomcache() *mcache
-func readgstatus(*g) uint32 // proc.c
// mcall switches from the g to the g0 stack and invokes fn(g),
// where g is the goroutine that made the call.
@@ -43,85 +38,30 @@ func readgstatus(*g) uint32 // proc.c
//go:noescape
func mcall(fn func(*g))
-// onM switches from the g to the g0 stack and invokes fn().
-// When fn returns, onM switches back to the g and returns,
-// continuing execution on the g stack.
-// If arguments must be passed to fn, they can be written to
-// g->m->ptrarg (pointers) and g->m->scalararg (non-pointers)
-// before the call and then consulted during fn.
-// Similarly, fn can pass return values back in those locations.
-// If fn is written in Go, it can be a closure, which avoids the need for
-// ptrarg and scalararg entirely.
-// After reading values out of ptrarg and scalararg it is conventional
-// to zero them to avoid (memory or information) leaks.
+// systemstack runs fn on a system stack.
+// If systemstack is called from the per-OS-thread (g0) stack, or
+// if systemstack is called from the signal handling (gsignal) stack,
+// systemstack calls fn directly and returns.
+// Otherwise, systemstack is being called from the limited stack
+// of an ordinary goroutine. In this case, systemstack switches
+// to the per-OS-thread stack, calls fn, and switches back.
+// It is common to use a func literal as the argument, in order
+// to share inputs and outputs with the code around the call
+// to system stack:
//
-// If onM is called from a g0 stack, it invokes fn and returns,
-// without any stack switches.
-//
-// If onM is called from a gsignal stack, it crashes the program.
-// The implication is that functions used in signal handlers must
-// not use onM.
-//
-// NOTE(rsc): We could introduce a separate onMsignal that is
-// like onM but if called from a gsignal stack would just run fn on
-// that stack. The caller of onMsignal would be required to save the
-// old values of ptrarg/scalararg and restore them when the call
-// was finished, in case the signal interrupted an onM sequence
-// in progress on the g or g0 stacks. Until there is a clear need for this,
-// we just reject onM in signal handling contexts entirely.
-//
-//go:noescape
-func onM(fn func())
-
-// onMsignal is like onM but is allowed to be used in code that
-// might run on the gsignal stack. Code running on a signal stack
-// may be interrupting an onM sequence on the main stack, so
-// if the onMsignal calling sequence writes to ptrarg/scalararg,
-// it must first save the old values and then restore them when
-// finished. As an exception to the rule, it is fine not to save and
-// restore the values if the program is trying to crash rather than
-// return from the signal handler.
-// Once all the runtime is written in Go, there will be no ptrarg/scalararg
-// and the distinction between onM and onMsignal (and perhaps mcall)
-// can go away.
-//
-// If onMsignal is called from a gsignal stack, it invokes fn directly,
-// without a stack switch. Otherwise onMsignal behaves like onM.
+// ... set up y ...
+// systemstack(func() {
+// x = bigcall(y)
+// })
+// ... use x ...
//
//go:noescape
-func onM_signalok(fn func())
+func systemstack(fn func())
-func badonm() {
- gothrow("onM called from signal goroutine")
+func badsystemstack() {
+ gothrow("systemstack called from unexpected goroutine")
}
-// C functions that run on the M stack.
-// Call using mcall.
-func gosched_m(*g)
-func park_m(*g)
-func recovery_m(*g)
-
-// More C functions that run on the M stack.
-// Call using onM.
-func mcacheRefill_m()
-func largeAlloc_m()
-func gc_m()
-func scavenge_m()
-func setFinalizer_m()
-func removeFinalizer_m()
-func markallocated_m()
-func unrollgcprog_m()
-func unrollgcproginplace_m()
-func setgcpercent_m()
-func setmaxthreads_m()
-func ready_m()
-func deferproc_m()
-func goexit_m()
-func startpanic_m()
-func dopanic_m()
-func readmemstats_m()
-func writeheapdump_m()
-
// memclr clears n bytes starting at ptr.
// in memclr_*.s
//go:noescape
@@ -132,12 +72,6 @@ func memclr(ptr unsafe.Pointer, n uintptr)
//go:noescape
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
-func starttheworld()
-func stoptheworld()
-func newextram()
-func lockOSThread()
-func unlockOSThread()
-
// exported value for testing
var hashLoad = loadFactor
@@ -159,16 +93,9 @@ func noescape(p unsafe.Pointer) unsafe.Pointer {
return unsafe.Pointer(x ^ 0)
}
-func entersyscall()
-func reentersyscall(pc uintptr, sp unsafe.Pointer)
-func entersyscallblock()
-func exitsyscall()
-
func cgocallback(fn, frame unsafe.Pointer, framesize uintptr)
func gogo(buf *gobuf)
func gosave(buf *gobuf)
-func read(fd int32, p unsafe.Pointer, n int32) int32
-func close(fd int32) int32
func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32
//go:noescape
@@ -176,35 +103,31 @@ func jmpdefer(fv *funcval, argp uintptr)
func exit1(code int32)
func asminit()
func setg(gg *g)
-func exit(code int32)
func breakpoint()
-func nanotime() int64
-func usleep(usec uint32)
-
-// careful: cputicks is not guaranteed to be monotonic! In particular, we have
-// noticed drift between cpus on certain os/arch combinations. See issue 8976.
-func cputicks() int64
-func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
-func munmap(addr unsafe.Pointer, n uintptr)
-func madvise(addr unsafe.Pointer, n uintptr, flags int32)
func reflectcall(fn, arg unsafe.Pointer, n uint32, retoffset uint32)
-func osyield()
func procyield(cycles uint32)
func cgocallback_gofunc(fv *funcval, frame unsafe.Pointer, framesize uintptr)
-func readgogc() int32
-func purgecachedstats(c *mcache)
-func gostringnocopy(b *byte) string
func goexit()
//go:noescape
-func write(fd uintptr, p unsafe.Pointer, n int32) int32
-
-//go:noescape
func cas(ptr *uint32, old, new uint32) bool
-//go:noescape
-func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
+// casp cannot have a go:noescape annotation, because
+// while ptr and old do not escape, new does. If new is marked as
+// not escaping, the compiler will make incorrect escape analysis
+// decisions about the value being xchg'ed.
+// Instead, make casp a wrapper around the actual atomic.
+// When calling the wrapper we mark ptr as noescape explicitly.
+
+//go:nosplit
+func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
+ return casp1((*unsafe.Pointer)(noescape(unsafe.Pointer(ptr))), noescape(old), new)
+}
+
+func casp1(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
+
+func nop() // call to prevent inlining of function body
//go:noescape
func casuintptr(ptr *uintptr, old, new uintptr) bool
@@ -261,18 +184,10 @@ func asmcgocall(fn, arg unsafe.Pointer)
//go:noescape
func asmcgocall_errno(fn, arg unsafe.Pointer) int32
-//go:noescape
-func open(name *byte, mode, perm int32) int32
-
-//go:noescape
-func gotraceback(*bool) int32
-
+// argp used in Defer structs when there is no argp.
const _NoArgs = ^uintptr(0)
-func newstack()
-func newproc()
func morestack()
-func mstart()
func rt0_go()
// return0 is a stub used to return 0 from deferproc.
@@ -314,3 +229,5 @@ func call134217728(fn, arg unsafe.Pointer, n, retoffset uint32)
func call268435456(fn, arg unsafe.Pointer, n, retoffset uint32)
func call536870912(fn, arg unsafe.Pointer, n, retoffset uint32)
func call1073741824(fn, arg unsafe.Pointer, n, retoffset uint32)
+
+func systemstack_switch()
diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go
new file mode 100644
index 000000000..60751dd34
--- /dev/null
+++ b/src/runtime/stubs2.go
@@ -0,0 +1,30 @@
+// 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.
+
+// +build !plan9
+// +build !solaris
+// +build !windows
+// +build !nacl
+
+package runtime
+
+import "unsafe"
+
+func read(fd int32, p unsafe.Pointer, n int32) int32
+func close(fd int32) int32
+
+func exit(code int32)
+func nanotime() int64
+func usleep(usec uint32)
+
+func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
+func munmap(addr unsafe.Pointer, n uintptr)
+
+//go:noescape
+func write(fd uintptr, p unsafe.Pointer, n int32) int32
+
+//go:noescape
+func open(name *byte, mode, perm int32) int32
+
+func madvise(addr unsafe.Pointer, n uintptr, flags int32)
diff --git a/src/runtime/stubs3.go b/src/runtime/stubs3.go
new file mode 100644
index 000000000..ffaa28775
--- /dev/null
+++ b/src/runtime/stubs3.go
@@ -0,0 +1,12 @@
+// 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.
+
+// +build plan9
+
+package runtime
+
+func close(fd int32) int32
+
+//go:noescape
+func open(name *byte, mode, perm int32) int32
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 45d107b77..749a289cd 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -22,8 +22,7 @@ func (f *Func) raw() *_func {
// funcdata.h
const (
- _PCDATA_ArgSize = 0
- _PCDATA_StackMapIndex = 1
+ _PCDATA_StackMapIndex = 0
_FUNCDATA_ArgsPointerMaps = 0
_FUNCDATA_LocalsPointerMaps = 1
_FUNCDATA_DeadValueMaps = 2
@@ -122,8 +121,8 @@ func (f *Func) Entry() uintptr {
func (f *Func) FileLine(pc uintptr) (file string, line int) {
// Pass strict=false here, because anyone can call this function,
// and they might just be wrong about targetpc belonging to f.
- line = int(funcline1(f.raw(), pc, &file, false))
- return file, line
+ file, line32 := funcline1(f.raw(), pc, false)
+ return file, int(line32)
}
func findfunc(pc uintptr) *_func {
@@ -208,20 +207,19 @@ func gofuncname(f *_func) string {
return gostringnocopy(funcname(f))
}
-func funcline1(f *_func, targetpc uintptr, file *string, strict bool) int32 {
- *file = "?"
+func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
fileno := int(pcvalue(f, f.pcfile, targetpc, strict))
- line := pcvalue(f, f.pcln, targetpc, strict)
+ line = pcvalue(f, f.pcln, targetpc, strict)
if fileno == -1 || line == -1 || fileno >= len(filetab) {
// print("looking for ", hex(targetpc), " in ", gofuncname(f), " got file=", fileno, " line=", lineno, "\n")
- return 0
+ return "?", 0
}
- *file = gostringnocopy(&pclntable[filetab[fileno]])
- return line
+ file = gostringnocopy(&pclntable[filetab[fileno]])
+ return
}
-func funcline(f *_func, targetpc uintptr, file *string) int32 {
- return funcline1(f, targetpc, file, true)
+func funcline(f *_func, targetpc uintptr) (file string, line int32) {
+ return funcline1(f, targetpc, true)
}
func funcspdelta(f *_func, targetpc uintptr) int32 {
diff --git a/src/runtime/sys_arm.c b/src/runtime/sys_arm.c
deleted file mode 100644
index a65560e5b..000000000
--- a/src/runtime/sys_arm.c
+++ /dev/null
@@ -1,35 +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.
-
-#include "runtime.h"
-
-// adjust Gobuf as if it executed a call to fn with context ctxt
-// and then did an immediate Gosave.
-void
-runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
-{
- if(gobuf->lr != 0)
- runtime·throw("invalid use of gostartcall");
- gobuf->lr = gobuf->pc;
- gobuf->pc = (uintptr)fn;
- gobuf->ctxt = ctxt;
-}
-
-// Called to rewind context saved during morestack back to beginning of function.
-// To help us, the linker emits a jmp back to the beginning right after the
-// call to morestack. We just have to decode and apply that jump.
-void
-runtime·rewindmorestack(Gobuf *gobuf)
-{
- uint32 inst;
-
- inst = *(uint32*)gobuf->pc;
- if((gobuf->pc&3) == 0 && (inst>>24) == 0x9a) {
- //runtime·printf("runtime: rewind pc=%p to pc=%p\n", gobuf->pc, gobuf->pc + ((int32)(inst<<8)>>6) + 8);
- gobuf->pc += ((int32)(inst<<8)>>6) + 8;
- return;
- }
- runtime·printf("runtime: pc=%p %x\n", gobuf->pc, inst);
- runtime·throw("runtime: misuse of rewindmorestack");
-}
diff --git a/src/runtime/sys_arm.go b/src/runtime/sys_arm.go
new file mode 100644
index 000000000..81777c710
--- /dev/null
+++ b/src/runtime/sys_arm.go
@@ -0,0 +1,35 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+// adjust Gobuf as if it executed a call to fn with context ctxt
+// and then did an immediate Gosave.
+func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
+ if buf.lr != 0 {
+ gothrow("invalid use of gostartcall")
+ }
+ buf.lr = buf.pc
+ buf.pc = uintptr(fn)
+ buf.ctxt = ctxt
+}
+
+// Called to rewind context saved during morestack back to beginning of function.
+// To help us, the linker emits a jmp back to the beginning right after the
+// call to morestack. We just have to decode and apply that jump.
+func rewindmorestack(buf *gobuf) {
+ var inst uint32
+ if buf.pc&3 == 0 && buf.pc != 0 {
+ inst = *(*uint32)(unsafe.Pointer(buf.pc))
+ if inst>>24 == 0x9a {
+ buf.pc += uintptr(int32(inst<<8)>>6) + 8
+ return
+ }
+ }
+
+ print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
+ gothrow("runtime: misuse of rewindmorestack")
+}
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
index a961c71a8..7cb5695e7 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -6,7 +6,8 @@
// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// Exit the entire program (like C exit)
@@ -248,7 +249,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$40
MOVL BX, 0(SP)
MOVL $runtime·badsignal(SB), AX
CALL AX
- JMP sigtramp_ret
+ JMP ret
// save g
MOVL DI, 20(SP)
@@ -275,7 +276,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$40
MOVL 20(SP), DI
MOVL DI, g(CX)
-sigtramp_ret:
+ret:
// call sigreturn
MOVL context+16(FP), CX
MOVL style+4(FP), BX
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index bd397d72a..0a955f982 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -11,7 +11,8 @@
// The high 8 bits specify the kind of system call: 1=Mach, 2=BSD, 3=Machine-Dependent.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// Exit the entire program (like C exit)
@@ -211,7 +212,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
MOVL DX, 0(SP)
MOVQ $runtime·badsignal(SB), AX
CALL AX
- JMP sigtramp_ret
+ JMP ret
// save g
MOVQ R10, 48(SP)
@@ -233,7 +234,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
MOVQ 48(SP), R10
MOVQ R10, g(BX)
-sigtramp_ret:
+ret:
// call sigreturn
MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle)
MOVQ 32(SP), DI // saved ucontext
diff --git a/src/runtime/sys_dragonfly_386.s b/src/runtime/sys_dragonfly_386.s
index 161eaec19..bb4903ef6 100644
--- a/src/runtime/sys_dragonfly_386.s
+++ b/src/runtime/sys_dragonfly_386.s
@@ -6,7 +6,8 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
TEXT runtime·sys_umtx_sleep(SB),NOSPLIT,$-4
@@ -217,7 +218,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
MOVL BX, 0(SP)
MOVL $runtime·badsignal(SB), AX
CALL AX
- JMP sigtramp_ret
+ JMP ret
// save g
MOVL DI, 20(SP)
@@ -243,7 +244,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
MOVL 20(SP), BX
MOVL BX, g(CX)
-sigtramp_ret:
+ret:
// call sigreturn
MOVL context+8(FP), AX
MOVL $0, 0(SP) // syscall gap
diff --git a/src/runtime/sys_dragonfly_amd64.s b/src/runtime/sys_dragonfly_amd64.s
index 2c756018c..db07ed703 100644
--- a/src/runtime/sys_dragonfly_amd64.s
+++ b/src/runtime/sys_dragonfly_amd64.s
@@ -6,7 +6,8 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
TEXT runtime·sys_umtx_sleep(SB),NOSPLIT,$0
diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s
index 2c40fc433..d1f67c3fc 100644
--- a/src/runtime/sys_freebsd_386.s
+++ b/src/runtime/sys_freebsd_386.s
@@ -6,7 +6,8 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
TEXT runtime·sys_umtx_op(SB),NOSPLIT,$-4
@@ -197,7 +198,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
MOVL BX, 0(SP)
MOVL $runtime·badsignal(SB), AX
CALL AX
- JMP sigtramp_ret
+ JMP ret
// save g
MOVL DI, 20(SP)
@@ -223,7 +224,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
MOVL 20(SP), BX
MOVL BX, g(CX)
-sigtramp_ret:
+ret:
// call sigreturn
MOVL context+8(FP), AX
MOVL $0, 0(SP) // syscall gap
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index 65f8c1a6e..84cee51d8 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -6,7 +6,8 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// FreeBSD 8, FreeBSD 9, and older versions that I have checked
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index d875138b6..198b427bf 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -6,7 +6,8 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// for EABI, as we don't support OABI
@@ -362,7 +363,7 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
SWI $0
RET
-TEXT runtime·casp(SB),NOSPLIT,$0
+TEXT runtime·casp1(SB),NOSPLIT,$0
B runtime·cas(SB)
// TODO(minux): this is only valid for ARMv6+
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 0f6d4bbb5..1861f237f 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -6,7 +6,8 @@
// System calls and other sys.stuff for 386, Linux
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
TEXT runtime·exit(SB),NOSPLIT,$0
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index 33b91e872..6d4dfdbd2 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -6,7 +6,8 @@
// System calls and other sys.stuff for AMD64, Linux
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
TEXT runtime·exit(SB),NOSPLIT,$0-4
@@ -115,7 +116,7 @@ TEXT time·now(SB),NOSPLIT,$16
// That leaves 104 for the gettime code to use. Hope that's enough!
MOVQ runtime·__vdso_clock_gettime_sym(SB), AX
CMPQ AX, $0
- JEQ fallback_gtod
+ JEQ fallback
MOVL $0, DI // CLOCK_REALTIME
LEAQ 0(SP), SI
CALL AX
@@ -124,7 +125,7 @@ TEXT time·now(SB),NOSPLIT,$16
MOVQ AX, sec+0(FP)
MOVL DX, nsec+8(FP)
RET
-fallback_gtod:
+fallback:
LEAQ 0(SP), DI
MOVQ $0, SI
MOVQ runtime·__vdso_gettimeofday_sym(SB), AX
@@ -141,7 +142,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
// See comment above in time.now.
MOVQ runtime·__vdso_clock_gettime_sym(SB), AX
CMPQ AX, $0
- JEQ fallback_gtod_nt
+ JEQ fallback
MOVL $1, DI // CLOCK_MONOTONIC
LEAQ 0(SP), SI
CALL AX
@@ -153,7 +154,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
ADDQ DX, AX
MOVQ AX, ret+0(FP)
RET
-fallback_gtod_nt:
+fallback:
LEAQ 0(SP), DI
MOVQ $0, SI
MOVQ runtime·__vdso_gettimeofday_sym(SB), AX
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index bd285f399..21d97fda9 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -6,7 +6,8 @@
// System calls and other sys.stuff for arm, Linux
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// for EABI, as we don't support OABI
@@ -373,25 +374,25 @@ TEXT cas<>(SB),NOSPLIT,$0
TEXT runtime·cas(SB),NOSPLIT,$0
MOVW ptr+0(FP), R2
MOVW old+4(FP), R0
-casagain:
+loop:
MOVW new+8(FP), R1
BL cas<>(SB)
- BCC cascheck
+ BCC check
MOVW $1, R0
MOVB R0, ret+12(FP)
RET
-cascheck:
+check:
// Kernel lies; double-check.
MOVW ptr+0(FP), R2
MOVW old+4(FP), R0
MOVW 0(R2), R3
CMP R0, R3
- BEQ casagain
+ BEQ loop
MOVW $0, R0
MOVB R0, ret+12(FP)
RET
-TEXT runtime·casp(SB),NOSPLIT,$0
+TEXT runtime·casp1(SB),NOSPLIT,$0
B runtime·cas(SB)
TEXT runtime·osyield(SB),NOSPLIT,$0
diff --git a/src/runtime/sys_linux_power64x.s b/src/runtime/sys_linux_power64x.s
new file mode 100644
index 000000000..395f657bf
--- /dev/null
+++ b/src/runtime/sys_linux_power64x.s
@@ -0,0 +1,384 @@
+// 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.
+
+// +build linux
+// +build power64 power64le
+
+//
+// System calls and other sys.stuff for Power64, Linux
+//
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+#define SYS_exit 1
+#define SYS_read 3
+#define SYS_write 4
+#define SYS_open 5
+#define SYS_close 6
+#define SYS_fcntl 55
+#define SYS_gettimeofday 78
+#define SYS_select 82 // always return -ENOSYS
+#define SYS_mmap 90
+#define SYS_munmap 91
+#define SYS_setitimer 104
+#define SYS_clone 120
+#define SYS_newselect 142
+#define SYS_sched_yield 158
+#define SYS_rt_sigreturn 172
+#define SYS_rt_sigaction 173
+#define SYS_rt_sigprocmask 174
+#define SYS_sigaltstack 185
+#define SYS_ugetrlimit 190
+#define SYS_madvise 205
+#define SYS_mincore 206
+#define SYS_gettid 207
+#define SYS_tkill 208
+#define SYS_futex 221
+#define SYS_sched_getaffinity 223
+#define SYS_exit_group 234
+#define SYS_epoll_create 236
+#define SYS_epoll_ctl 237
+#define SYS_epoll_wait 238
+#define SYS_clock_gettime 246
+#define SYS_epoll_create1 315
+
+TEXT runtime·exit(SB),NOSPLIT,$-8-4
+ MOVW code+0(FP), R3
+ SYSCALL $SYS_exit_group
+ RETURN
+
+TEXT runtime·exit1(SB),NOSPLIT,$-8-4
+ MOVW code+0(FP), R3
+ SYSCALL $SYS_exit
+ RETURN
+
+TEXT runtime·open(SB),NOSPLIT,$-8-20
+ MOVD name+0(FP), R3
+ MOVW mode+8(FP), R4
+ MOVW perm+12(FP), R5
+ SYSCALL $SYS_open
+ MOVW R3, ret+16(FP)
+ RETURN
+
+TEXT runtime·close(SB),NOSPLIT,$-8-12
+ MOVW fd+0(FP), R3
+ SYSCALL $SYS_close
+ MOVW R3, ret+8(FP)
+ RETURN
+
+TEXT runtime·write(SB),NOSPLIT,$-8-28
+ MOVD fd+0(FP), R3
+ MOVD p+8(FP), R4
+ MOVW n+16(FP), R5
+ SYSCALL $SYS_write
+ MOVW R3, ret+24(FP)
+ RETURN
+
+TEXT runtime·read(SB),NOSPLIT,$-8-28
+ MOVW fd+0(FP), R3
+ MOVD p+8(FP), R4
+ MOVW n+16(FP), R5
+ SYSCALL $SYS_read
+ MOVW R3, ret+24(FP)
+ RETURN
+
+TEXT runtime·getrlimit(SB),NOSPLIT,$-8-20
+ MOVW kind+0(FP), R3
+ MOVD limit+8(FP), R4
+ SYSCALL $SYS_ugetrlimit
+ MOVW R3, ret+16(FP)
+ RETURN
+
+TEXT runtime·usleep(SB),NOSPLIT,$16-4
+ MOVW usec+0(FP), R3
+ MOVD R3, R5
+ MOVW $1000000, R4
+ DIVD R4, R3
+ MOVD R3, 8(R1)
+ MULLD R3, R4
+ SUB R4, R5
+ MOVD R5, 16(R1)
+
+ // select(0, 0, 0, 0, &tv)
+ MOVW $0, R3
+ MOVW $0, R4
+ MOVW $0, R5
+ MOVW $0, R6
+ ADD $8, R1, R7
+ SYSCALL $SYS_newselect
+ RETURN
+
+TEXT runtime·raise(SB),NOSPLIT,$-8
+ SYSCALL $SYS_gettid
+ MOVW R3, R3 // arg 1 tid
+ MOVW sig+0(FP), R4 // arg 2
+ SYSCALL $SYS_tkill
+ RETURN
+
+TEXT runtime·setitimer(SB),NOSPLIT,$-8-24
+ MOVW mode+0(FP), R3
+ MOVD new+8(FP), R4
+ MOVD old+16(FP), R5
+ SYSCALL $SYS_setitimer
+ RETURN
+
+TEXT runtime·mincore(SB),NOSPLIT,$-8-28
+ MOVD addr+0(FP), R3
+ MOVD n+8(FP), R4
+ MOVD dst+16(FP), R5
+ SYSCALL $SYS_mincore
+ MOVW R3, ret+24(FP)
+ RETURN
+
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB),NOSPLIT,$16
+ MOVD $0(R1), R3
+ MOVD $0, R4
+ SYSCALL $SYS_gettimeofday
+ MOVD 0(R1), R3 // sec
+ MOVD 8(R1), R5 // usec
+ MOVD $1000, R4
+ MULLD R4, R5
+ MOVD R3, sec+0(FP)
+ MOVW R5, nsec+8(FP)
+ RETURN
+
+TEXT runtime·nanotime(SB),NOSPLIT,$16
+ MOVW $1, R3 // CLOCK_MONOTONIC
+ MOVD $0(R1), R4
+ SYSCALL $SYS_clock_gettime
+ MOVD 0(R1), R3 // sec
+ MOVD 8(R1), R5 // nsec
+ // sec is in R3, nsec in R5
+ // return nsec in R3
+ MOVD $1000000000, R4
+ MULLD R4, R3
+ ADD R5, R3
+ MOVD R3, ret+0(FP)
+ RETURN
+
+TEXT runtime·rtsigprocmask(SB),NOSPLIT,$-8-28
+ MOVW sig+0(FP), R3
+ MOVD new+8(FP), R4
+ MOVD old+16(FP), R5
+ MOVW size+24(FP), R6
+ SYSCALL $SYS_rt_sigprocmask
+ BVC 2(PC)
+ MOVD R0, 0xf1(R0) // crash
+ RETURN
+
+TEXT runtime·rt_sigaction(SB),NOSPLIT,$-8-36
+ MOVD sig+0(FP), R3
+ MOVD new+8(FP), R4
+ MOVD old+16(FP), R5
+ MOVD size+24(FP), R6
+ SYSCALL $SYS_rt_sigaction
+ MOVW R3, ret+32(FP)
+ RETURN
+
+#ifdef GOARCH_power64le
+// power64le doesn't need function descriptors
+TEXT runtime·sigtramp(SB),NOSPLIT,$64
+#else
+// function descriptor for the real sigtramp
+TEXT runtime·sigtramp(SB),NOSPLIT,$-8
+ DWORD $runtime·_sigtramp(SB)
+ DWORD $0
+ DWORD $0
+TEXT runtime·_sigtramp(SB),NOSPLIT,$64
+#endif
+ // initialize essential registers (just in case)
+ BL runtime·reginit(SB)
+
+ // check that g exists
+ CMP g, $0
+ BNE 6(PC)
+ MOVD R3, 8(R1)
+ MOVD $runtime·badsignal(SB), R31
+ MOVD R31, CTR
+ BL (CTR)
+ RETURN
+
+ // save g
+ MOVD g, 40(R1)
+ MOVD g, R6
+
+ // g = m->gsignal
+ MOVD g_m(g), R7
+ MOVD m_gsignal(R7), g
+
+ MOVW R3, 8(R1)
+ MOVD R4, 16(R1)
+ MOVD R5, 24(R1)
+ MOVD R6, 32(R1)
+
+ BL runtime·sighandler(SB)
+
+ // restore g
+ MOVD 40(R1), g
+
+ RETURN
+
+TEXT runtime·mmap(SB),NOSPLIT,$-8
+ MOVD addr+0(FP), R3
+ MOVD n+8(FP), R4
+ MOVW prot+16(FP), R5
+ MOVW flags+20(FP), R6
+ MOVW fd+24(FP), R7
+ MOVW off+28(FP), R8
+
+ SYSCALL $SYS_mmap
+ MOVD R3, ret+32(FP)
+ RETURN
+
+TEXT runtime·munmap(SB),NOSPLIT,$-8
+ MOVD addr+0(FP), R3
+ MOVD n+8(FP), R4
+ SYSCALL $SYS_munmap
+ BVC 2(PC)
+ MOVD R0, 0xf3(R0)
+ RETURN
+
+TEXT runtime·madvise(SB),NOSPLIT,$-8
+ MOVD addr+0(FP), R3
+ MOVD n+8(FP), R4
+ MOVW flags+16(FP), R5
+ SYSCALL $SYS_madvise
+ // ignore failure - maybe pages are locked
+ RETURN
+
+// int64 futex(int32 *uaddr, int32 op, int32 val,
+// struct timespec *timeout, int32 *uaddr2, int32 val2);
+TEXT runtime·futex(SB),NOSPLIT,$-8
+ MOVD addr+0(FP), R3
+ MOVW op+8(FP), R4
+ MOVW val+12(FP), R5
+ MOVD ts+16(FP), R6
+ MOVD addr2+24(FP), R7
+ MOVW val3+32(FP), R8
+ SYSCALL $SYS_futex
+ MOVW R3, ret+40(FP)
+ RETURN
+
+// int64 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
+TEXT runtime·clone(SB),NOSPLIT,$-8
+ MOVW flags+0(FP), R3
+ MOVD stk+8(FP), R4
+
+ // Copy mp, gp, fn off parent stack for use by child.
+ // Careful: Linux system call clobbers ???.
+ MOVD mm+16(FP), R7
+ MOVD gg+24(FP), R8
+ MOVD fn+32(FP), R12
+
+ MOVD R7, -8(R4)
+ MOVD R8, -16(R4)
+ MOVD R12, -24(R4)
+ MOVD $1234, R7
+ MOVD R7, -32(R4)
+
+ SYSCALL $SYS_clone
+
+ // In parent, return.
+ CMP R3, $0
+ BEQ 3(PC)
+ MOVW R3, ret+40(FP)
+ RETURN
+
+ // In child, on new stack.
+ // initialize essential registers
+ BL runtime·reginit(SB)
+ MOVD -32(R1), R7
+ CMP R7, $1234
+ BEQ 2(PC)
+ MOVD R0, 0(R0)
+
+ // Initialize m->procid to Linux tid
+ SYSCALL $SYS_gettid
+
+ MOVD -24(R1), R12
+ MOVD -16(R1), R8
+ MOVD -8(R1), R7
+
+ MOVD R3, m_procid(R7)
+
+ // TODO: setup TLS.
+
+ // In child, set up new stack
+ MOVD R7, g_m(R8)
+ MOVD R8, g
+ //CALL runtime·stackcheck(SB)
+
+ // Call fn
+ MOVD R12, CTR
+ BL (CTR)
+
+ // It shouldn't return. If it does, exit
+ MOVW $111, R3
+ SYSCALL $SYS_exit_group
+ BR -2(PC) // keep exiting
+
+TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
+ MOVD new+0(FP), R3
+ MOVD old+8(FP), R4
+ SYSCALL $SYS_sigaltstack
+ BVC 2(PC)
+ MOVD R0, 0xf1(R0) // crash
+ RETURN
+
+TEXT runtime·osyield(SB),NOSPLIT,$-8
+ SYSCALL $SYS_sched_yield
+ RETURN
+
+TEXT runtime·sched_getaffinity(SB),NOSPLIT,$-8
+ MOVD pid+0(FP), R3
+ MOVD len+8(FP), R4
+ MOVD buf+16(FP), R5
+ SYSCALL $SYS_sched_getaffinity
+ MOVW R3, ret+24(FP)
+ RETURN
+
+// int32 runtime·epollcreate(int32 size);
+TEXT runtime·epollcreate(SB),NOSPLIT,$-8
+ MOVW size+0(FP), R3
+ SYSCALL $SYS_epoll_create
+ MOVW R3, ret+8(FP)
+ RETURN
+
+// int32 runtime·epollcreate1(int32 flags);
+TEXT runtime·epollcreate1(SB),NOSPLIT,$-8
+ MOVW flags+0(FP), R3
+ SYSCALL $SYS_epoll_create1
+ MOVW R3, ret+8(FP)
+ RETURN
+
+// func epollctl(epfd, op, fd int32, ev *epollEvent) int
+TEXT runtime·epollctl(SB),NOSPLIT,$-8
+ MOVW epfd+0(FP), R3
+ MOVW op+4(FP), R4
+ MOVW fd+8(FP), R5
+ MOVD ev+16(FP), R6
+ SYSCALL $SYS_epoll_ctl
+ MOVW R3, ret+24(FP)
+ RETURN
+
+// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
+TEXT runtime·epollwait(SB),NOSPLIT,$-8
+ MOVW epfd+0(FP), R3
+ MOVD ev+8(FP), R4
+ MOVW nev+16(FP), R5
+ MOVW timeout+20(FP), R6
+ SYSCALL $SYS_epoll_wait
+ MOVW R3, ret+24(FP)
+ RETURN
+
+// void runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),NOSPLIT,$-8
+ MOVW fd+0(FP), R3 // fd
+ MOVD $2, R4 // F_SETFD
+ MOVD $1, R5 // FD_CLOEXEC
+ SYSCALL $SYS_fcntl
+ RETURN
diff --git a/src/runtime/sys_nacl_386.s b/src/runtime/sys_nacl_386.s
index 47985f31f..85c8175b1 100644
--- a/src/runtime/sys_nacl_386.s
+++ b/src/runtime/sys_nacl_386.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
#include "syscall_nacl.h"
@@ -293,7 +294,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
MOVL $0, 0(SP)
MOVL $runtime·badsignal(SB), AX
CALL AX
- JMP sigtramp_ret
+ JMP ret
// save g
MOVL DI, 20(SP)
@@ -317,7 +318,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
MOVL 20(SP), BX
MOVL BX, g(CX)
-sigtramp_ret:
+ret:
// Enable exceptions again.
NACL_SYSCALL(SYS_exception_clear_flag)
diff --git a/src/runtime/sys_nacl_amd64p32.s b/src/runtime/sys_nacl_amd64p32.s
index 4eb4aacdd..f5624ca8d 100644
--- a/src/runtime/sys_nacl_amd64p32.s
+++ b/src/runtime/sys_nacl_amd64p32.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
#include "syscall_nacl.h"
@@ -338,7 +339,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$80
MOVL 20(SP), BX
MOVL BX, g(CX)
-sigtramp_ret:
// Enable exceptions again.
NACL_SYSCALL(SYS_exception_clear_flag)
diff --git a/src/runtime/sys_nacl_arm.s b/src/runtime/sys_nacl_arm.s
index d354ab483..ded95a86b 100644
--- a/src/runtime/sys_nacl_arm.s
+++ b/src/runtime/sys_nacl_arm.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
#include "syscall_nacl.h"
@@ -269,7 +270,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$80
// restore g
MOVW 20(R13), g
-sigtramp_ret:
// Enable exceptions again.
NACL_SYSCALL(SYS_exception_clear_flag)
@@ -301,7 +301,7 @@ nog:
TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16
RET
-TEXT runtime·casp(SB),NOSPLIT,$0
+TEXT runtime·casp1(SB),NOSPLIT,$0
B runtime·cas(SB)
// This is only valid for ARMv6+, however, NaCl/ARM is only defined
diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s
index 23f2f6bd1..509d6d4a8 100644
--- a/src/runtime/sys_netbsd_386.s
+++ b/src/runtime/sys_netbsd_386.s
@@ -6,7 +6,8 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// Exit the entire program (like C exit)
diff --git a/src/runtime/sys_netbsd_amd64.s b/src/runtime/sys_netbsd_amd64.s
index eb9766d3f..e26d60667 100644
--- a/src/runtime/sys_netbsd_amd64.s
+++ b/src/runtime/sys_netbsd_amd64.s
@@ -6,7 +6,8 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// int32 lwp_create(void *context, uintptr flags, void *lwpid)
diff --git a/src/runtime/sys_netbsd_arm.s b/src/runtime/sys_netbsd_arm.s
index 039a0832e..fa9bc577a 100644
--- a/src/runtime/sys_netbsd_arm.s
+++ b/src/runtime/sys_netbsd_arm.s
@@ -6,7 +6,8 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// Exit the entire program (like C exit)
@@ -330,7 +331,7 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
SWI $0xa0005c // sys_fcntl
RET
-TEXT runtime·casp(SB),NOSPLIT,$0
+TEXT runtime·casp1(SB),NOSPLIT,$0
B runtime·cas(SB)
// TODO(minux): this is only valid for ARMv6+
diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s
index 5cda7768a..93907577e 100644
--- a/src/runtime/sys_openbsd_386.s
+++ b/src/runtime/sys_openbsd_386.s
@@ -6,7 +6,8 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
#define CLOCK_MONOTONIC $3
@@ -186,7 +187,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
MOVL BX, 0(SP)
MOVL $runtime·badsignal(SB), AX
CALL AX
- JMP sigtramp_ret
+ JMP ret
// save g
MOVL DI, 20(SP)
@@ -212,7 +213,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
MOVL 20(SP), BX
MOVL BX, g(CX)
-sigtramp_ret:
+ret:
// call sigreturn
MOVL context+8(FP), AX
MOVL $0, 0(SP) // syscall gap
diff --git a/src/runtime/sys_openbsd_amd64.s b/src/runtime/sys_openbsd_amd64.s
index 4e9db2390..9dc0fb685 100644
--- a/src/runtime/sys_openbsd_amd64.s
+++ b/src/runtime/sys_openbsd_amd64.s
@@ -6,7 +6,8 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
#define CLOCK_MONOTONIC $3
diff --git a/src/runtime/sys_plan9_386.s b/src/runtime/sys_plan9_386.s
index a41b56258..b9db8cbf1 100644
--- a/src/runtime/sys_plan9_386.s
+++ b/src/runtime/sys_plan9_386.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// setldt(int entry, int address, int limit)
diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s
index 3a96c2bf9..02c7c8743 100644
--- a/src/runtime/sys_plan9_amd64.s
+++ b/src/runtime/sys_plan9_amd64.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// setldt(int entry, int address, int limit)
diff --git a/src/runtime/sys_power64x.go b/src/runtime/sys_power64x.go
new file mode 100644
index 000000000..90ebde7b4
--- /dev/null
+++ b/src/runtime/sys_power64x.go
@@ -0,0 +1,37 @@
+// 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.
+
+// +build power64 power64le
+
+package runtime
+
+import "unsafe"
+
+// adjust Gobuf as if it executed a call to fn with context ctxt
+// and then did an immediate Gosave.
+func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
+ if buf.lr != 0 {
+ gothrow("invalid use of gostartcall")
+ }
+ buf.lr = buf.pc
+ buf.pc = uintptr(fn)
+ buf.ctxt = ctxt
+}
+
+// Called to rewind context saved during morestack back to beginning of function.
+// To help us, the linker emits a jmp back to the beginning right after the
+// call to morestack. We just have to decode and apply that jump.
+func rewindmorestack(buf *gobuf) {
+ var inst uint32
+ if buf.pc&3 == 0 && buf.pc != 0 {
+ inst = *(*uint32)(unsafe.Pointer(buf.pc))
+ if inst>>26 == 18 && inst&3 == 0 {
+ //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<6)>>6)), "\n");
+ buf.pc += uintptr(int32(inst<<6) >> 6)
+ return
+ }
+ }
+ print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
+ gothrow("runtime: misuse of rewindmorestack")
+}
diff --git a/src/runtime/sys_solaris_amd64.s b/src/runtime/sys_solaris_amd64.s
index 0ebdab6ee..54aeaeaf5 100644
--- a/src/runtime/sys_solaris_amd64.s
+++ b/src/runtime/sys_solaris_amd64.s
@@ -6,14 +6,15 @@
// /usr/include/sys/syscall.h for syscall numbers.
//
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// This is needed by asm_amd64.s
TEXT runtime·settls(SB),NOSPLIT,$8
RET
-// void libc·miniterrno(void *(*___errno)(void));
+// void libc_miniterrno(void *(*___errno)(void));
//
// Set the TLS errno pointer in M.
//
@@ -40,7 +41,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$0
SUBQ $64, SP // 16 bytes will do, but who knows in the future?
MOVQ $3, DI // CLOCK_REALTIME from <sys/time_impl.h>
MOVQ SP, SI
- MOVQ libc·clock_gettime(SB), AX
+ MOVQ libc_clock_gettime(SB), AX
CALL AX
MOVQ (SP), AX // tv_sec from struct timespec
IMULQ $1000000000, AX // multiply into nanoseconds
@@ -53,7 +54,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$0
TEXT runtime·pipe1(SB),NOSPLIT,$0
SUBQ $16, SP // 8 bytes will do, but stack has to be 16-byte alligned
MOVQ SP, DI
- MOVQ libc·pipe(SB), AX
+ MOVQ libc_pipe(SB), AX
CALL AX
MOVL 0(SP), AX
MOVL 4(SP), DX
@@ -132,7 +133,7 @@ TEXT runtime·tstart_sysvicall(SB),NOSPLIT,$0
MOVQ AX, (g_stack+stack_hi)(DX)
SUBQ $(0x100000), AX // stack size
MOVQ AX, (g_stack+stack_lo)(DX)
- ADDQ $const_StackGuard, AX
+ ADDQ $const__StackGuard, AX
MOVQ AX, g_stackguard0(DX)
MOVQ AX, g_stackguard1(DX)
@@ -287,24 +288,24 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
// Execute call on m->g0.
get_tls(R15)
CMPQ R15, $0
- JE usleep1_noswitch
+ JE noswitch
MOVQ g(R15), R13
CMPQ R13, $0
- JE usleep1_noswitch
+ JE noswitch
MOVQ g_m(R13), R13
CMPQ R13, $0
- JE usleep1_noswitch
+ JE noswitch
// TODO(aram): do something about the cpu profiler here.
MOVQ m_g0(R13), R14
CMPQ g(R15), R14
- JNE usleep1_switch
+ JNE switch
// executing on m->g0 already
CALL AX
RET
-usleep1_switch:
+switch:
// Switch to m->g0 stack and back.
MOVQ (g_sched+gobuf_sp)(R14), R14
MOVQ SP, -8(R14)
@@ -313,20 +314,20 @@ usleep1_switch:
MOVQ 0(SP), SP
RET
-usleep1_noswitch:
+noswitch:
// Not a Go-managed thread. Do not switch stack.
CALL AX
RET
// Runs on OS stack. duration (in µs units) is in DI.
TEXT runtime·usleep2(SB),NOSPLIT,$0
- MOVQ libc·usleep(SB), AX
+ MOVQ libc_usleep(SB), AX
CALL AX
RET
// Runs on OS stack, called from runtime·osyield.
TEXT runtime·osyield1(SB),NOSPLIT,$0
- MOVQ libc·sched_yield(SB), AX
+ MOVQ libc_sched_yield(SB), AX
CALL AX
RET
diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s
index 932fe9dd2..c8a830cdf 100644
--- a/src/runtime/sys_windows_386.s
+++ b/src/runtime/sys_windows_386.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// void runtime·asmstdcall(void *c);
@@ -43,7 +44,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$24
// stderr
MOVL $-12, 0(SP)
MOVL SP, BP
- CALL *runtime·GetStdHandle(SB)
+ CALL *runtime·_GetStdHandle(SB)
MOVL BP, SP
MOVL AX, 0(SP) // handle
@@ -55,7 +56,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$24
MOVL $0, 0(DX)
MOVL DX, 12(SP)
MOVL $0, 16(SP) // overlapped
- CALL *runtime·WriteFile(SB)
+ CALL *runtime·_WriteFile(SB)
MOVL BP, SI
RET
@@ -106,7 +107,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
MOVL g_m(DX), BX
MOVL m_g0(BX), BX
CMPL DX, BX
- JEQ sigtramp_g0
+ JEQ g0
// switch to the g0 stack
get_tls(BP)
@@ -123,7 +124,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
MOVL SP, 36(DI)
MOVL DI, SP
-sigtramp_g0:
+g0:
MOVL 0(CX), BX // ExceptionRecord*
MOVL 4(CX), CX // Context*
MOVL BX, 0(SP)
@@ -207,7 +208,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
MOVL BX, g_m(SP)
LEAL -8192(SP), CX
MOVL CX, (g_stack+stack_lo)(SP)
- ADDL $const_StackGuard, CX
+ ADDL $const__StackGuard, CX
MOVL CX, g_stackguard0(SP)
MOVL CX, g_stackguard1(SP)
MOVL DX, (g_stack+stack_hi)(SP)
@@ -254,8 +255,8 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
MOVL -4(BX)(AX*4), BX
// extract callback context
- MOVL cbctxt_gobody(BX), AX
- MOVL cbctxt_argsize(BX), DX
+ MOVL wincallbackcontext_gobody(BX), AX
+ MOVL wincallbackcontext_argsize(BX), DX
// preserve whatever's at the memory location that
// the callback will use to store the return value
@@ -265,7 +266,7 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
ADDL $4, DX
// remember how to restore stack on return
- MOVL cbctxt_restorestack(BX), BX
+ MOVL wincallbackcontext_restorestack(BX), BX
PUSHL BX
// call target Go function
@@ -313,7 +314,7 @@ TEXT runtime·tstart(SB),NOSPLIT,$0
MOVL AX, (g_stack+stack_hi)(DX)
SUBL $(64*1024), AX // stack size
MOVL AX, (g_stack+stack_lo)(DX)
- ADDL $const_StackGuard, AX
+ ADDL $const__StackGuard, AX
MOVL AX, g_stackguard0(DX)
MOVL AX, g_stackguard1(DX)
@@ -383,12 +384,12 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
MOVL m_g0(BP), SI
CMPL g(CX), SI
- JNE usleep1_switch
+ JNE switch
// executing on m->g0 already
CALL AX
- JMP usleep1_ret
+ JMP ret
-usleep1_switch:
+switch:
// Switch to m->g0 stack and back.
MOVL (g_sched+gobuf_sp)(SI), SI
MOVL SP, -4(SI)
@@ -396,7 +397,7 @@ usleep1_switch:
CALL AX
MOVL 0(SP), SP
-usleep1_ret:
+ret:
get_tls(CX)
MOVL g(CX), BP
MOVL g_m(BP), BP
@@ -414,7 +415,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20
MOVL $0, alertable-16(SP)
MOVL $-1, handle-20(SP)
MOVL SP, BP
- MOVL runtime·NtWaitForSingleObject(SB), AX
+ MOVL runtime·_NtWaitForSingleObject(SB), AX
CALL AX
MOVL BP, SP
RET
diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
index e6190ce68..68f7cd392 100644
--- a/src/runtime/sys_windows_amd64.s
+++ b/src/runtime/sys_windows_amd64.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
// maxargs should be divisible by 2, as Windows stack
@@ -65,7 +66,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48
// stderr
MOVQ $-12, CX // stderr
MOVQ CX, 0(SP)
- MOVQ runtime·GetStdHandle(SB), AX
+ MOVQ runtime·_GetStdHandle(SB), AX
CALL AX
MOVQ AX, CX // handle
@@ -78,7 +79,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48
MOVQ $0, 0(R9)
MOVQ R9, 24(SP)
MOVQ $0, 32(SP) // overlapped
- MOVQ runtime·WriteFile(SB), AX
+ MOVQ runtime·_WriteFile(SB), AX
CALL AX
RET
@@ -138,7 +139,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
MOVQ g_m(DX), BX
MOVQ m_g0(BX), BX
CMPQ DX, BX
- JEQ sigtramp_g0
+ JEQ g0
// switch to g0 stack
get_tls(BP)
@@ -157,7 +158,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
MOVQ SP, 104(DI)
MOVQ DI, SP
-sigtramp_g0:
+g0:
MOVQ 0(CX), BX // ExceptionRecord*
MOVQ 8(CX), CX // Context*
MOVQ BX, 0(SP)
@@ -244,7 +245,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
LEAQ -8192(SP), CX
MOVQ CX, (g_stack+stack_lo)(SP)
- ADDQ $const_StackGuard, CX
+ ADDQ $const__StackGuard, CX
MOVQ CX, g_stackguard0(SP)
MOVQ CX, g_stackguard1(SP)
MOVQ DX, (g_stack+stack_hi)(SP)
@@ -293,8 +294,8 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0
MOVQ -8(CX)(AX*8), AX
// extract callback context
- MOVQ cbctxt_argsize(AX), DX
- MOVQ cbctxt_gobody(AX), AX
+ MOVQ wincallbackcontext_argsize(AX), DX
+ MOVQ wincallbackcontext_gobody(AX), AX
// preserve whatever's at the memory location that
// the callback will use to store the return value
@@ -354,7 +355,7 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
MOVQ AX, (g_stack+stack_hi)(DX)
SUBQ $(64*1024), AX // stack size
MOVQ AX, (g_stack+stack_lo)(DX)
- ADDQ $const_StackGuard, AX
+ ADDQ $const__StackGuard, AX
MOVQ AX, g_stackguard0(DX)
MOVQ AX, g_stackguard1(DX)
@@ -407,12 +408,12 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
MOVQ m_g0(R13), R14
CMPQ g(R15), R14
- JNE usleep1_switch
+ JNE switch
// executing on m->g0 already
CALL AX
- JMP usleep1_ret
+ JMP ret
-usleep1_switch:
+switch:
// Switch to m->g0 stack and back.
MOVQ (g_sched+gobuf_sp)(R14), R14
MOVQ SP, -8(R14)
@@ -420,7 +421,7 @@ usleep1_switch:
CALL AX
MOVQ 0(SP), SP
-usleep1_ret:
+ret:
MOVQ $0, m_libcallsp(R13)
RET
@@ -435,7 +436,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$16
MOVQ BX, (R8)
MOVQ $-1, CX // handle
MOVQ $0, DX // alertable
- MOVQ runtime·NtWaitForSingleObject(SB), AX
+ MOVQ runtime·_NtWaitForSingleObject(SB), AX
CALL AX
MOVQ 8(SP), SP
RET
diff --git a/src/runtime/sys_x86.c b/src/runtime/sys_x86.go
index a450b3e58..086af8ff1 100644
--- a/src/runtime/sys_x86.c
+++ b/src/runtime/sys_x86.go
@@ -4,54 +4,51 @@
// +build amd64 amd64p32 386
-#include "runtime.h"
+package runtime
+
+import "unsafe"
// adjust Gobuf as it if executed a call to fn with context ctxt
// and then did an immediate gosave.
-void
-runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
-{
- uintptr *sp;
-
- sp = (uintptr*)gobuf->sp;
- if(sizeof(uintreg) > sizeof(uintptr))
- *--sp = 0;
- *--sp = (uintptr)gobuf->pc;
- gobuf->sp = (uintptr)sp;
- gobuf->pc = (uintptr)fn;
- gobuf->ctxt = ctxt;
+func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
+ sp := buf.sp
+ if regSize > ptrSize {
+ sp -= ptrSize
+ *(*uintptr)(unsafe.Pointer(sp)) = 0
+ }
+ sp -= ptrSize
+ *(*uintptr)(unsafe.Pointer(sp)) = buf.pc
+ buf.sp = sp
+ buf.pc = uintptr(fn)
+ buf.ctxt = ctxt
}
// Called to rewind context saved during morestack back to beginning of function.
// To help us, the linker emits a jmp back to the beginning right after the
// call to morestack. We just have to decode and apply that jump.
-void
-runtime·rewindmorestack(Gobuf *gobuf)
-{
- byte *pc;
-
- pc = (byte*)gobuf->pc;
- if(pc[0] == 0xe9) { // jmp 4-byte offset
- gobuf->pc = gobuf->pc + 5 + *(int32*)(pc+1);
- return;
+func rewindmorestack(buf *gobuf) {
+ pc := (*[8]byte)(unsafe.Pointer(buf.pc))
+ if pc[0] == 0xe9 { // jmp 4-byte offset
+ buf.pc = buf.pc + 5 + uintptr(int64(*(*int32)(unsafe.Pointer(&pc[1]))))
+ return
}
- if(pc[0] == 0xeb) { // jmp 1-byte offset
- gobuf->pc = gobuf->pc + 2 + *(int8*)(pc+1);
- return;
+ if pc[0] == 0xeb { // jmp 1-byte offset
+ buf.pc = buf.pc + 2 + uintptr(int64(*(*int8)(unsafe.Pointer(&pc[1]))))
+ return
}
- if(pc[0] == 0xcc) {
+ if pc[0] == 0xcc {
// This is a breakpoint inserted by gdb. We could use
// runtime·findfunc to find the function. But if we
// do that, then we will continue execution at the
// function entry point, and we will not hit the gdb
// breakpoint. So for this case we don't change
- // gobuf->pc, so that when we return we will execute
+ // buf.pc, so that when we return we will execute
// the jump instruction and carry on. This means that
// stack unwinding may not work entirely correctly
// (http://golang.org/issue/5723) but the user is
// running under gdb anyhow.
- return;
+ return
}
- runtime·printf("runtime: pc=%p %x %x %x %x %x\n", pc, pc[0], pc[1], pc[2], pc[3], pc[4]);
- runtime·throw("runtime: misuse of rewindmorestack");
+ print("runtime: pc=", pc, " ", hex(pc[0]), " ", hex(pc[1]), " ", hex(pc[2]), " ", hex(pc[3]), " ", hex(pc[4]), "\n")
+ gothrow("runtime: misuse of rewindmorestack")
}
diff --git a/src/runtime/syscall2_solaris.go b/src/runtime/syscall2_solaris.go
new file mode 100644
index 000000000..f4ffa7410
--- /dev/null
+++ b/src/runtime/syscall2_solaris.go
@@ -0,0 +1,47 @@
+// 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 runtime
+
+import _ "unsafe"
+
+//go:cgo_import_dynamic libc_chdir chdir "libc.so"
+//go:cgo_import_dynamic libc_chroot chroot "libc.so"
+//go:cgo_import_dynamic libc_close close "libc.so"
+//go:cgo_import_dynamic libc_dlclose dlclose "libc.so"
+//go:cgo_import_dynamic libc_dlopen dlopen "libc.so"
+//go:cgo_import_dynamic libc_dlsym dlsym "libc.so"
+//go:cgo_import_dynamic libc_execve execve "libc.so"
+//go:cgo_import_dynamic libc_fcntl fcntl "libc.so"
+//go:cgo_import_dynamic libc_gethostname gethostname "libc.so"
+//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
+//go:cgo_import_dynamic libc_pipe pipe "libc.so"
+//go:cgo_import_dynamic libc_setgid setgid "libc.so"
+//go:cgo_import_dynamic libc_setgroups setgroups "libc.so"
+//go:cgo_import_dynamic libc_setsid setsid "libc.so"
+//go:cgo_import_dynamic libc_setuid setuid "libc.so"
+//go:cgo_import_dynamic libc_setpgid setsid "libc.so"
+//go:cgo_import_dynamic libc_syscall syscall "libc.so"
+//go:cgo_import_dynamic libc_forkx forkx "libc.so"
+//go:cgo_import_dynamic libc_wait4 wait4 "libc.so"
+
+//go:linkname libc_chdir libc_chdir
+//go:linkname libc_chroot libc_chroot
+//go:linkname libc_close libc_close
+//go:linkname libc_dlclose libc_dlclose
+//go:linkname libc_dlopen libc_dlopen
+//go:linkname libc_dlsym libc_dlsym
+//go:linkname libc_execve libc_execve
+//go:linkname libc_fcntl libc_fcntl
+//go:linkname libc_gethostname libc_gethostname
+//go:linkname libc_ioctl libc_ioctl
+//go:linkname libc_pipe libc_pipe
+//go:linkname libc_setgid libc_setgid
+//go:linkname libc_setgroups libc_setgroups
+//go:linkname libc_setsid libc_setsid
+//go:linkname libc_setuid libc_setuid
+//go:linkname libc_setpgid libc_setpgid
+//go:linkname libc_syscall libc_syscall
+//go:linkname libc_forkx libc_forkx
+//go:linkname libc_wait4 libc_wait4
diff --git a/src/runtime/syscall_solaris.c b/src/runtime/syscall_solaris.c
deleted file mode 100644
index 13ac31bde..000000000
--- a/src/runtime/syscall_solaris.c
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.
-
-#pragma dynimport libc·chdir chdir "libc.so"
-#pragma dynimport libc·chroot chroot "libc.so"
-#pragma dynimport libc·close close "libc.so"
-#pragma dynimport libc·dlclose dlclose "libc.so"
-#pragma dynimport libc·dlopen dlopen "libc.so"
-#pragma dynimport libc·dlsym dlsym "libc.so"
-#pragma dynimport libc·execve execve "libc.so"
-#pragma dynimport libc·fcntl fcntl "libc.so"
-#pragma dynimport libc·gethostname gethostname "libc.so"
-#pragma dynimport libc·ioctl ioctl "libc.so"
-#pragma dynimport libc·pipe pipe "libc.so"
-#pragma dynimport libc·setgid setgid "libc.so"
-#pragma dynimport libc·setgroups setgroups "libc.so"
-#pragma dynimport libc·setsid setsid "libc.so"
-#pragma dynimport libc·setuid setuid "libc.so"
-#pragma dynimport libc·setpgid setsid "libc.so"
-#pragma dynimport libc·syscall syscall "libc.so"
-#pragma dynimport libc·forkx forkx "libc.so"
-#pragma dynimport libc·wait4 wait4 "libc.so"
diff --git a/src/runtime/syscall_solaris.go b/src/runtime/syscall_solaris.go
index 50d3a1d36..9b9971674 100644
--- a/src/runtime/syscall_solaris.go
+++ b/src/runtime/syscall_solaris.go
@@ -9,12 +9,10 @@ import "unsafe"
var (
libc_chdir,
libc_chroot,
- libc_close,
libc_dlopen,
libc_dlclose,
libc_dlsym,
libc_execve,
- libc_exit,
libc_fcntl,
libc_forkx,
libc_gethostname,
@@ -27,7 +25,6 @@ var (
libc_setpgid,
libc_syscall,
libc_wait4,
- libc_write,
pipe1 libcFunc
)
@@ -38,9 +35,9 @@ func syscall_sysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err
n: nargs,
args: uintptr(unsafe.Pointer(&a1)),
}
- entersyscallblock()
+ entersyscallblock(0)
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
- exitsyscall()
+ exitsyscall(0)
return call.r1, call.r2, call.err
}
@@ -62,7 +59,7 @@ func syscall_rawsysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, e
//go:nosplit
func syscall_chdir(path uintptr) (err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_chdir)),
+ fn: uintptr(unsafe.Pointer(libc_chdir)),
n: 1,
args: uintptr(unsafe.Pointer(&path)),
}
@@ -73,7 +70,7 @@ func syscall_chdir(path uintptr) (err uintptr) {
//go:nosplit
func syscall_chroot(path uintptr) (err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_chroot)),
+ fn: uintptr(unsafe.Pointer(libc_chroot)),
n: 1,
args: uintptr(unsafe.Pointer(&path)),
}
@@ -84,18 +81,18 @@ func syscall_chroot(path uintptr) (err uintptr) {
// like close, but must not split stack, for forkx.
//go:nosplit
func syscall_close(fd int32) int32 {
- return int32(sysvicall1(&libc_close, uintptr(fd)))
+ return int32(sysvicall1(libc_close, uintptr(fd)))
}
func syscall_dlopen(name *byte, mode uintptr) (handle uintptr, err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_dlopen)),
+ fn: uintptr(unsafe.Pointer(libc_dlopen)),
n: 2,
args: uintptr(unsafe.Pointer(&name)),
}
- entersyscallblock()
+ entersyscallblock(0)
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
- exitsyscall()
+ exitsyscall(0)
if call.r1 == 0 {
return call.r1, call.err
}
@@ -104,25 +101,25 @@ func syscall_dlopen(name *byte, mode uintptr) (handle uintptr, err uintptr) {
func syscall_dlclose(handle uintptr) (err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_dlclose)),
+ fn: uintptr(unsafe.Pointer(libc_dlclose)),
n: 1,
args: uintptr(unsafe.Pointer(&handle)),
}
- entersyscallblock()
+ entersyscallblock(0)
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
- exitsyscall()
+ exitsyscall(0)
return call.r1
}
func syscall_dlsym(handle uintptr, name *byte) (proc uintptr, err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_dlsym)),
+ fn: uintptr(unsafe.Pointer(libc_dlsym)),
n: 2,
args: uintptr(unsafe.Pointer(&handle)),
}
- entersyscallblock()
+ entersyscallblock(0)
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
- exitsyscall()
+ exitsyscall(0)
if call.r1 == 0 {
return call.r1, call.err
}
@@ -132,7 +129,7 @@ func syscall_dlsym(handle uintptr, name *byte) (proc uintptr, err uintptr) {
//go:nosplit
func syscall_execve(path, argv, envp uintptr) (err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_execve)),
+ fn: uintptr(unsafe.Pointer(libc_execve)),
n: 3,
args: uintptr(unsafe.Pointer(&path)),
}
@@ -143,13 +140,13 @@ func syscall_execve(path, argv, envp uintptr) (err uintptr) {
// like exit, but must not split stack, for forkx.
//go:nosplit
func syscall_exit(code uintptr) {
- sysvicall1(&libc_exit, code)
+ sysvicall1(libc_exit, code)
}
//go:nosplit
func syscall_fcntl(fd, cmd, arg uintptr) (val, err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_fcntl)),
+ fn: uintptr(unsafe.Pointer(libc_fcntl)),
n: 3,
args: uintptr(unsafe.Pointer(&fd)),
}
@@ -160,7 +157,7 @@ func syscall_fcntl(fd, cmd, arg uintptr) (val, err uintptr) {
//go:nosplit
func syscall_forkx(flags uintptr) (pid uintptr, err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_forkx)),
+ fn: uintptr(unsafe.Pointer(libc_forkx)),
n: 1,
args: uintptr(unsafe.Pointer(&flags)),
}
@@ -172,13 +169,13 @@ func syscall_gethostname() (name string, err uintptr) {
cname := new([_MAXHOSTNAMELEN]byte)
var args = [2]uintptr{uintptr(unsafe.Pointer(&cname[0])), _MAXHOSTNAMELEN}
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_gethostname)),
+ fn: uintptr(unsafe.Pointer(libc_gethostname)),
n: 2,
args: uintptr(unsafe.Pointer(&args[0])),
}
- entersyscallblock()
+ entersyscallblock(0)
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
- exitsyscall()
+ exitsyscall(0)
if call.r1 != 0 {
return "", call.err
}
@@ -189,7 +186,7 @@ func syscall_gethostname() (name string, err uintptr) {
//go:nosplit
func syscall_ioctl(fd, req, arg uintptr) (err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_ioctl)),
+ fn: uintptr(unsafe.Pointer(libc_ioctl)),
n: 3,
args: uintptr(unsafe.Pointer(&fd)),
}
@@ -203,9 +200,9 @@ func syscall_pipe() (r, w, err uintptr) {
n: 0,
args: uintptr(unsafe.Pointer(&pipe1)), // it's unused but must be non-nil, otherwise crashes
}
- entersyscallblock()
+ entersyscallblock(0)
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
- exitsyscall()
+ exitsyscall(0)
return call.r1, call.r2, call.err
}
@@ -217,7 +214,7 @@ func syscall_pipe() (r, w, err uintptr) {
// TODO(aram): make this panic once we stop calling fcntl(2) in net using it.
func syscall_rawsyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_syscall)),
+ fn: uintptr(unsafe.Pointer(libc_syscall)),
n: 4,
args: uintptr(unsafe.Pointer(&trap)),
}
@@ -228,7 +225,7 @@ func syscall_rawsyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
//go:nosplit
func syscall_setgid(gid uintptr) (err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_setgid)),
+ fn: uintptr(unsafe.Pointer(libc_setgid)),
n: 1,
args: uintptr(unsafe.Pointer(&gid)),
}
@@ -239,7 +236,7 @@ func syscall_setgid(gid uintptr) (err uintptr) {
//go:nosplit
func syscall_setgroups(ngid, gid uintptr) (err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_setgroups)),
+ fn: uintptr(unsafe.Pointer(libc_setgroups)),
n: 2,
args: uintptr(unsafe.Pointer(&ngid)),
}
@@ -250,9 +247,9 @@ func syscall_setgroups(ngid, gid uintptr) (err uintptr) {
//go:nosplit
func syscall_setsid() (pid, err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_setsid)),
+ fn: uintptr(unsafe.Pointer(libc_setsid)),
n: 0,
- args: uintptr(unsafe.Pointer(&libc_setsid)), // it's unused but must be non-nil, otherwise crashes
+ args: uintptr(unsafe.Pointer(libc_setsid)), // it's unused but must be non-nil, otherwise crashes
}
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
return call.r1, call.err
@@ -261,7 +258,7 @@ func syscall_setsid() (pid, err uintptr) {
//go:nosplit
func syscall_setuid(uid uintptr) (err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_setuid)),
+ fn: uintptr(unsafe.Pointer(libc_setuid)),
n: 1,
args: uintptr(unsafe.Pointer(&uid)),
}
@@ -272,7 +269,7 @@ func syscall_setuid(uid uintptr) (err uintptr) {
//go:nosplit
func syscall_setpgid(pid, pgid uintptr) (err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_setpgid)),
+ fn: uintptr(unsafe.Pointer(libc_setpgid)),
n: 2,
args: uintptr(unsafe.Pointer(&pid)),
}
@@ -288,32 +285,32 @@ func syscall_setpgid(pid, pgid uintptr) (err uintptr) {
// TODO(aram): make this panic once we stop calling fcntl(2) in net using it.
func syscall_syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_syscall)),
+ fn: uintptr(unsafe.Pointer(libc_syscall)),
n: 4,
args: uintptr(unsafe.Pointer(&trap)),
}
- entersyscallblock()
+ entersyscallblock(0)
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
- exitsyscall()
+ exitsyscall(0)
return call.r1, call.r2, call.err
}
func syscall_wait4(pid uintptr, wstatus *uint32, options uintptr, rusage unsafe.Pointer) (wpid int, err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_wait4)),
+ fn: uintptr(unsafe.Pointer(libc_wait4)),
n: 4,
args: uintptr(unsafe.Pointer(&pid)),
}
- entersyscallblock()
+ entersyscallblock(0)
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
- exitsyscall()
+ exitsyscall(0)
return int(call.r1), call.err
}
//go:nosplit
func syscall_write(fd, buf, nbyte uintptr) (n, err uintptr) {
call := libcall{
- fn: uintptr(unsafe.Pointer(&libc_write)),
+ fn: uintptr(unsafe.Pointer(libc_write)),
n: 3,
args: uintptr(unsafe.Pointer(&fd)),
}
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
index efbcab510..661ee59d7 100644
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -41,20 +41,20 @@ func callbackasmAddr(i int) uintptr {
func compileCallback(fn eface, cleanstack bool) (code uintptr) {
if fn._type == nil || (fn._type.kind&kindMask) != kindFunc {
- panic("compilecallback: not a function")
+ panic("compileCallback: not a function")
}
ft := (*functype)(unsafe.Pointer(fn._type))
- if len(ft.out) != 1 {
- panic("compilecallback: function must have one output parameter")
+ if ft.out.len != 1 {
+ panic("compileCallback: function must have one output parameter")
}
uintptrSize := unsafe.Sizeof(uintptr(0))
- if t := (**_type)(unsafe.Pointer(&ft.out[0])); (*t).size != uintptrSize {
- panic("compilecallback: output parameter size is wrong")
+ if t := (**_type)(unsafe.Pointer(ft.out.array)); (*t).size != uintptrSize {
+ panic("compileCallback: output parameter size is wrong")
}
argsize := uintptr(0)
- for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] {
+ for _, t := range (*[1024](*_type))(unsafe.Pointer(ft.in.array))[:ft.in.len] {
if (*t).size > uintptrSize {
- panic("compilecallback: input parameter size is wrong")
+ panic("compileCallback: input parameter size is wrong")
}
argsize += uintptrSize
}
@@ -87,8 +87,6 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
return callbackasmAddr(n)
}
-func getLoadLibrary() uintptr
-
//go:nosplit
func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
var c libcall
@@ -103,8 +101,6 @@ func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
return
}
-func getGetProcAddress() uintptr
-
//go:nosplit
func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
var c libcall
diff --git a/src/runtime/thunk.s b/src/runtime/thunk.s
index 0a0f147c4..241dd90af 100644
--- a/src/runtime/thunk.s
+++ b/src/runtime/thunk.s
@@ -4,12 +4,17 @@
// This file exposes various internal runtime functions to other packages in std lib.
-#include "zasm_GOOS_GOARCH.h"
#include "textflag.h"
#ifdef GOARCH_arm
#define JMP B
#endif
+#ifdef GOARCH_power64
+#define JMP BR
+#endif
+#ifdef GOARCH_power64le
+#define JMP BR
+#endif
TEXT net·runtimeNano(SB),NOSPLIT,$0-0
JMP runtime·nanotime(SB)
@@ -181,3 +186,18 @@ TEXT syscall·runtime_envs(SB),NOSPLIT,$0-0
TEXT os·runtime_args(SB),NOSPLIT,$0-0
JMP runtime·runtime_args(SB)
+
+TEXT sync·runtime_procUnpin(SB),NOSPLIT,$0-0
+ JMP runtime·sync_procUnpin(SB)
+
+TEXT sync·runtime_procPin(SB),NOSPLIT,$0-0
+ JMP runtime·sync_procPin(SB)
+
+TEXT syscall·runtime_BeforeFork(SB),NOSPLIT,$0-0
+ JMP runtime·syscall_BeforeFork(SB)
+
+TEXT syscall·runtime_AfterFork(SB),NOSPLIT,$0-0
+ JMP runtime·syscall_AfterFork(SB)
+
+TEXT reflect·typelinks(SB),NOSPLIT,$0-0
+ JMP runtime·typelinks(SB)
diff --git a/src/runtime/thunk_solaris_amd64.s b/src/runtime/thunk_solaris_amd64.s
deleted file mode 100644
index f61188c14..000000000
--- a/src/runtime/thunk_solaris_amd64.s
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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 exposes various external library functions to Go code in the runtime.
-
-#include "zasm_GOOS_GOARCH.h"
-#include "textflag.h"
-
-TEXT runtime·libc_chdir(SB),NOSPLIT,$0
- MOVQ libc·chdir(SB), AX
- JMP AX
-
-TEXT runtime·libc_chroot(SB),NOSPLIT,$0
- MOVQ libc·chroot(SB), AX
- JMP AX
-
-TEXT runtime·libc_close(SB),NOSPLIT,$0
- MOVQ libc·close(SB), AX
- JMP AX
-
-TEXT runtime·libc_dlopen(SB),NOSPLIT,$0
- MOVQ libc·dlopen(SB), AX
- JMP AX
-
-TEXT runtime·libc_dlclose(SB),NOSPLIT,$0
- MOVQ libc·dlclose(SB), AX
- JMP AX
-
-TEXT runtime·libc_dlsym(SB),NOSPLIT,$0
- MOVQ libc·dlsym(SB), AX
- JMP AX
-
-TEXT runtime·libc_execve(SB),NOSPLIT,$0
- MOVQ libc·execve(SB), AX
- JMP AX
-
-TEXT runtime·libc_exit(SB),NOSPLIT,$0
- MOVQ libc·exit(SB), AX
- JMP AX
-
-TEXT runtime·libc_fcntl(SB),NOSPLIT,$0
- MOVQ libc·fcntl(SB), AX
- JMP AX
-
-TEXT runtime·libc_forkx(SB),NOSPLIT,$0
- MOVQ libc·forkx(SB), AX
- JMP AX
-
-TEXT runtime·libc_gethostname(SB),NOSPLIT,$0
- MOVQ libc·gethostname(SB), AX
- JMP AX
-
-TEXT runtime·libc_ioctl(SB),NOSPLIT,$0
- MOVQ libc·ioctl(SB), AX
- JMP AX
-
-TEXT runtime·libc_setgid(SB),NOSPLIT,$0
- MOVQ libc·setgid(SB), AX
- JMP AX
-
-TEXT runtime·libc_setgroups(SB),NOSPLIT,$0
- MOVQ libc·setgroups(SB), AX
- JMP AX
-
-TEXT runtime·libc_setsid(SB),NOSPLIT,$0
- MOVQ libc·setsid(SB), AX
- JMP AX
-
-TEXT runtime·libc_setuid(SB),NOSPLIT,$0
- MOVQ libc·setuid(SB), AX
- JMP AX
-
-TEXT runtime·libc_setpgid(SB),NOSPLIT,$0
- MOVQ libc·setpgid(SB), AX
- JMP AX
-
-TEXT runtime·libc_syscall(SB),NOSPLIT,$0
- MOVQ libc·syscall(SB), AX
- JMP AX
-
-TEXT runtime·libc_wait4(SB),NOSPLIT,$0
- MOVQ libc·wait4(SB), AX
- JMP AX
-
-TEXT runtime·libc_write(SB),NOSPLIT,$0
- MOVQ libc·write(SB), AX
- JMP AX
diff --git a/src/runtime/thunk_windows.s b/src/runtime/thunk_windows.s
index 7ccb98fd4..b1d5d5753 100644
--- a/src/runtime/thunk_windows.s
+++ b/src/runtime/thunk_windows.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
TEXT syscall·Syscall(SB),NOSPLIT,$0-0
diff --git a/src/runtime/tls_arm.s b/src/runtime/tls_arm.s
index 85c3940bf..7c5c0e215 100644
--- a/src/runtime/tls_arm.s
+++ b/src/runtime/tls_arm.s
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "funcdata.h"
#include "textflag.h"
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 1c6ce6e64..e1cc9123f 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -32,15 +32,16 @@ const usesLR = GOARCH != "amd64" && GOARCH != "amd64p32" && GOARCH != "386"
var (
// initialized in tracebackinit
- deferprocPC uintptr
- goexitPC uintptr
- jmpdeferPC uintptr
- mcallPC uintptr
- morestackPC uintptr
- mstartPC uintptr
- newprocPC uintptr
- rt0_goPC uintptr
- sigpanicPC uintptr
+ deferprocPC uintptr
+ goexitPC uintptr
+ jmpdeferPC uintptr
+ mcallPC uintptr
+ morestackPC uintptr
+ mstartPC uintptr
+ newprocPC uintptr
+ rt0_goPC uintptr
+ sigpanicPC uintptr
+ systemstack_switchPC uintptr
externalthreadhandlerp uintptr // initialized elsewhere
)
@@ -59,6 +60,7 @@ func tracebackinit() {
newprocPC = funcPC(newproc)
rt0_goPC = funcPC(rt0_go)
sigpanicPC = funcPC(sigpanic)
+ systemstack_switchPC = funcPC(systemstack_switch)
}
// Traceback over the deferred function calls.
@@ -335,8 +337,7 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
print(hex(argp[i]))
}
print(")\n")
- var file string
- line := funcline(f, tracepc, &file)
+ file, line := funcline(f, tracepc)
print("\t", file, ":", line)
if frame.pc > f.entry {
print(" +", hex(frame.pc-f.entry))
@@ -480,8 +481,7 @@ func printcreatedby(gp *g) {
if pc > f.entry {
tracepc -= _PCQuantum
}
- var file string
- line := funcline(f, tracepc, &file)
+ file, line := funcline(f, tracepc)
print("\t", file, ":", line)
if pc > f.entry {
print(" +", hex(pc-f.entry))
@@ -528,7 +528,7 @@ func callers(skip int, pcbuf *uintptr, m int) int {
sp := getcallersp(unsafe.Pointer(&skip))
pc := uintptr(getcallerpc(unsafe.Pointer(&skip)))
var n int
- onM(func() {
+ systemstack(func() {
n = gentraceback(pc, sp, 0, getg(), skip, pcbuf, m, nil, nil, 0)
})
return n
diff --git a/src/runtime/type.go b/src/runtime/type.go
new file mode 100644
index 000000000..cbd5c9ebc
--- /dev/null
+++ b/src/runtime/type.go
@@ -0,0 +1,99 @@
+// 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.
+
+// Runtime _type representation.
+
+package runtime
+
+import "unsafe"
+
+// Needs to be in sync with ../../cmd/ld/decodesym.c:/^commonsize and pkg/reflect/type.go:/type.
+type _type struct {
+ size uintptr
+ hash uint32
+ _unused uint8
+ align uint8
+ fieldalign uint8
+ kind uint8
+ alg unsafe.Pointer
+ // 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
+ // 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.
+ gc [2]uintptr
+ _string *string
+ x *uncommontype
+ ptrto *_type
+ zero *byte // ptr to the zero value for this _type
+}
+
+type method struct {
+ name *string
+ pkgpath *string
+ mtyp *_type
+ typ *_type
+ ifn unsafe.Pointer
+ tfn unsafe.Pointer
+}
+
+type uncommontype struct {
+ name *string
+ pkgpath *string
+ mhdr []method
+ m [0]method
+}
+
+type imethod struct {
+ name *string
+ pkgpath *string
+ _type *_type
+}
+
+type interfacetype struct {
+ typ _type
+ mhdr []imethod
+ m [0]imethod
+}
+
+type maptype struct {
+ typ _type
+ key *_type
+ elem *_type
+ 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
+ indirectvalue bool // store ptr to value instead of value itself
+ bucketsize uint16 // size of bucket
+}
+
+type chantype struct {
+ typ _type
+ elem *_type
+ dir uintptr
+}
+
+type slicetype struct {
+ typ _type
+ elem *_type
+}
+
+type functype struct {
+ typ _type
+ dotdotdot bool
+ in slice
+ out slice
+}
+
+type ptrtype struct {
+ typ _type
+ elem *_type
+}
diff --git a/src/runtime/type.h b/src/runtime/type.h
deleted file mode 100644
index f5b4f9d13..000000000
--- a/src/runtime/type.h
+++ /dev/null
@@ -1,113 +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.
-
-// Runtime type representation.
-
-typedef struct Type Type;
-typedef struct UncommonType UncommonType;
-typedef struct InterfaceType InterfaceType;
-typedef struct Method Method;
-typedef struct IMethod IMethod;
-typedef struct SliceType SliceType;
-typedef struct FuncType FuncType;
-
-// Needs to be in sync with ../../cmd/ld/decodesym.c:/^commonsize and pkg/reflect/type.go:/type.
-struct Type
-{
- uintptr size;
- uint32 hash;
- uint8 _unused;
- uint8 align;
- uint8 fieldAlign;
- uint8 kind;
- void* alg;
- // 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
- // 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.
- uintptr gc[2];
- String *string;
- UncommonType *x;
- Type *ptrto;
- byte *zero; // ptr to the zero value for this type
-};
-
-struct Method
-{
- String *name;
- String *pkgPath;
- Type *mtyp;
- Type *typ;
- void (*ifn)(void);
- void (*tfn)(void);
-};
-
-struct UncommonType
-{
- String *name;
- String *pkgPath;
- Slice mhdr;
- Method m[];
-};
-
-struct IMethod
-{
- String *name;
- String *pkgPath;
- Type *type;
-};
-
-struct InterfaceType
-{
- Type typ;
- Slice mhdr;
- IMethod m[];
-};
-
-struct MapType
-{
- Type typ;
- Type *key;
- Type *elem;
- Type *bucket; // internal type representing a hash bucket
- Type *hmap; // internal type representing a Hmap
- uint8 keysize; // size of key slot
- bool indirectkey; // store ptr to key instead of key itself
- uint8 valuesize; // size of value slot
- bool indirectvalue; // store ptr to value instead of value itself
- uint16 bucketsize; // size of bucket
-};
-
-struct ChanType
-{
- Type typ;
- Type *elem;
- uintptr dir;
-};
-
-struct SliceType
-{
- Type typ;
- Type *elem;
-};
-
-struct FuncType
-{
- Type typ;
- bool dotdotdot;
- Slice in;
- Slice out;
-};
-
-struct PtrType
-{
- Type typ;
- Type *elem;
-};
diff --git a/src/runtime/typekind.h b/src/runtime/typekind.h
index e0fe177bb..39cd45c2e 100644
--- a/src/runtime/typekind.h
+++ b/src/runtime/typekind.h
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Must match runtime and reflect.
+// Included by cmd/gc.
+
enum {
KindBool = 1,
KindInt,
@@ -30,9 +33,8 @@ enum {
KindStruct,
KindUnsafePointer,
- KindDirectIface = 1<<5,
- KindGCProg = 1<<6, // Type.gc points to GC program
- KindNoPointers = 1<<7,
- KindMask = (1<<5)-1,
+ KindDirectIface = 1 << 5,
+ KindGCProg = 1 << 6, // Type.gc points to GC program
+ KindNoPointers = 1 << 7,
+ KindMask = (1 << 5) - 1,
};
-
diff --git a/src/runtime/typekind1.go b/src/runtime/typekind1.go
new file mode 100644
index 000000000..73028d6f4
--- /dev/null
+++ b/src/runtime/typekind1.go
@@ -0,0 +1,39 @@
+// Copyright 2012 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 runtime
+
+const (
+ _KindBool = 1 + iota
+ _KindInt
+ _KindInt8
+ _KindInt16
+ _KindInt32
+ _KindInt64
+ _KindUint
+ _KindUint8
+ _KindUint16
+ _KindUint32
+ _KindUint64
+ _KindUintptr
+ _KindFloat32
+ _KindFloat64
+ _KindComplex64
+ _KindComplex128
+ _KindArray
+ _KindChan
+ _KindFunc
+ _KindInterface
+ _KindMap
+ _KindPtr
+ _KindSlice
+ _KindString
+ _KindStruct
+ _KindUnsafePointer
+
+ _KindDirectIface = 1 << 5
+ _KindGCProg = 1 << 6 // Type.gc points to GC program
+ _KindNoPointers = 1 << 7
+ _KindMask = (1 << 5) - 1
+)
diff --git a/src/runtime/vdso_linux_amd64.c b/src/runtime/vdso_linux_amd64.c
deleted file mode 100644
index 681340c5b..000000000
--- a/src/runtime/vdso_linux_amd64.c
+++ /dev/null
@@ -1,371 +0,0 @@
-// Copyright 2012 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.
-
-#include "runtime.h"
-#include "textflag.h"
-
-// Look up symbols in the Linux vDSO.
-
-// This code was originally based on the sample Linux vDSO parser at
-// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/vDSO/parse_vdso.c
-
-// This implements the ELF dynamic linking spec at
-// http://sco.com/developers/gabi/latest/ch5.dynamic.html
-
-// The version section is documented at
-// http://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/symversion.html
-
-#define AT_RANDOM 25
-#define AT_SYSINFO_EHDR 33
-#define AT_NULL 0 /* End of vector */
-#define PT_LOAD 1 /* Loadable program segment */
-#define PT_DYNAMIC 2 /* Dynamic linking information */
-#define DT_NULL 0 /* Marks end of dynamic section */
-#define DT_HASH 4 /* Dynamic symbol hash table */
-#define DT_STRTAB 5 /* Address of string table */
-#define DT_SYMTAB 6 /* Address of symbol table */
-#define DT_VERSYM 0x6ffffff0
-#define DT_VERDEF 0x6ffffffc
-
-#define VER_FLG_BASE 0x1 /* Version definition of file itself */
-#define SHN_UNDEF 0 /* Undefined section */
-#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
-#define STT_FUNC 2 /* Symbol is a code object */
-#define STB_GLOBAL 1 /* Global symbol */
-#define STB_WEAK 2 /* Weak symbol */
-
-/* How to extract and insert information held in the st_info field. */
-#define ELF64_ST_BIND(val) (((byte) (val)) >> 4)
-#define ELF64_ST_TYPE(val) ((val) & 0xf)
-
-#define EI_NIDENT (16)
-
-typedef uint16 Elf64_Half;
-typedef uint32 Elf64_Word;
-typedef int32 Elf64_Sword;
-typedef uint64 Elf64_Xword;
-typedef int64 Elf64_Sxword;
-typedef uint64 Elf64_Addr;
-typedef uint64 Elf64_Off;
-typedef uint16 Elf64_Section;
-typedef Elf64_Half Elf64_Versym;
-
-
-typedef struct Elf64_Sym
-{
- Elf64_Word st_name;
- byte st_info;
- byte st_other;
- Elf64_Section st_shndx;
- Elf64_Addr st_value;
- Elf64_Xword st_size;
-} Elf64_Sym;
-
-typedef struct Elf64_Verdef
-{
- Elf64_Half vd_version; /* Version revision */
- Elf64_Half vd_flags; /* Version information */
- Elf64_Half vd_ndx; /* Version Index */
- Elf64_Half vd_cnt; /* Number of associated aux entries */
- Elf64_Word vd_hash; /* Version name hash value */
- Elf64_Word vd_aux; /* Offset in bytes to verdaux array */
- Elf64_Word vd_next; /* Offset in bytes to next verdef entry */
-} Elf64_Verdef;
-
-typedef struct Elf64_Ehdr
-{
- byte e_ident[EI_NIDENT]; /* Magic number and other info */
- Elf64_Half e_type; /* Object file type */
- Elf64_Half e_machine; /* Architecture */
- Elf64_Word e_version; /* Object file version */
- Elf64_Addr e_entry; /* Entry point virtual address */
- Elf64_Off e_phoff; /* Program header table file offset */
- Elf64_Off e_shoff; /* Section header table file offset */
- Elf64_Word e_flags; /* Processor-specific flags */
- Elf64_Half e_ehsize; /* ELF header size in bytes */
- Elf64_Half e_phentsize; /* Program header table entry size */
- Elf64_Half e_phnum; /* Program header table entry count */
- Elf64_Half e_shentsize; /* Section header table entry size */
- Elf64_Half e_shnum; /* Section header table entry count */
- Elf64_Half e_shstrndx; /* Section header string table index */
-} Elf64_Ehdr;
-
-typedef struct Elf64_Phdr
-{
- Elf64_Word p_type; /* Segment type */
- Elf64_Word p_flags; /* Segment flags */
- Elf64_Off p_offset; /* Segment file offset */
- Elf64_Addr p_vaddr; /* Segment virtual address */
- Elf64_Addr p_paddr; /* Segment physical address */
- Elf64_Xword p_filesz; /* Segment size in file */
- Elf64_Xword p_memsz; /* Segment size in memory */
- Elf64_Xword p_align; /* Segment alignment */
-} Elf64_Phdr;
-
-typedef struct Elf64_Shdr
-{
- Elf64_Word sh_name; /* Section name (string tbl index) */
- Elf64_Word sh_type; /* Section type */
- Elf64_Xword sh_flags; /* Section flags */
- Elf64_Addr sh_addr; /* Section virtual addr at execution */
- Elf64_Off sh_offset; /* Section file offset */
- Elf64_Xword sh_size; /* Section size in bytes */
- Elf64_Word sh_link; /* Link to another section */
- Elf64_Word sh_info; /* Additional section information */
- Elf64_Xword sh_addralign; /* Section alignment */
- Elf64_Xword sh_entsize; /* Entry size if section holds table */
-} Elf64_Shdr;
-
-typedef struct Elf64_Dyn
-{
- Elf64_Sxword d_tag; /* Dynamic entry type */
- union
- {
- Elf64_Xword d_val; /* Integer value */
- Elf64_Addr d_ptr; /* Address value */
- } d_un;
-} Elf64_Dyn;
-
-typedef struct Elf64_Verdaux
-{
- Elf64_Word vda_name; /* Version or dependency names */
- Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */
-} Elf64_Verdaux;
-
-typedef struct Elf64_auxv_t
-{
- uint64 a_type; /* Entry type */
- union
- {
- uint64 a_val; /* Integer value */
- } a_un;
-} Elf64_auxv_t;
-
-
-typedef struct symbol_key {
- byte* name;
- int32 sym_hash;
- void** var_ptr;
-} symbol_key;
-
-typedef struct version_key {
- byte* version;
- int32 ver_hash;
-} version_key;
-
-struct vdso_info {
- bool valid;
-
- /* Load information */
- uintptr load_addr;
- uintptr load_offset; /* load_addr - recorded vaddr */
-
- /* Symbol table */
- Elf64_Sym *symtab;
- const byte *symstrings;
- Elf64_Word *bucket, *chain;
- Elf64_Word nbucket, nchain;
-
- /* Version table */
- Elf64_Versym *versym;
- Elf64_Verdef *verdef;
-};
-
-#pragma dataflag NOPTR
-static version_key linux26 = { (byte*)"LINUX_2.6", 0x3ae75f6 };
-
-// initialize with vsyscall fallbacks
-#pragma dataflag NOPTR
-void* runtime·__vdso_time_sym = (void*)0xffffffffff600400ULL;
-#pragma dataflag NOPTR
-void* runtime·__vdso_gettimeofday_sym = (void*)0xffffffffff600000ULL;
-#pragma dataflag NOPTR
-void* runtime·__vdso_clock_gettime_sym = (void*)0;
-
-#pragma dataflag NOPTR
-static symbol_key sym_keys[] = {
- { (byte*)"__vdso_time", 0xa33c485, &runtime·__vdso_time_sym },
- { (byte*)"__vdso_gettimeofday", 0x315ca59, &runtime·__vdso_gettimeofday_sym },
- { (byte*)"__vdso_clock_gettime", 0xd35ec75, &runtime·__vdso_clock_gettime_sym },
-};
-
-static void
-vdso_init_from_sysinfo_ehdr(struct vdso_info *vdso_info, Elf64_Ehdr* hdr)
-{
- uint64 i;
- bool found_vaddr = false;
- Elf64_Phdr *pt;
- Elf64_Dyn *dyn;
- Elf64_Word *hash;
-
- vdso_info->valid = false;
- vdso_info->load_addr = (uintptr) hdr;
-
- pt = (Elf64_Phdr*)(vdso_info->load_addr + hdr->e_phoff);
- dyn = nil;
-
- // We need two things from the segment table: the load offset
- // and the dynamic table.
- for(i=0; i<hdr->e_phnum; i++) {
- if(pt[i].p_type == PT_LOAD && found_vaddr == false) {
- found_vaddr = true;
- vdso_info->load_offset = (uintptr)hdr
- + (uintptr)pt[i].p_offset
- - (uintptr)pt[i].p_vaddr;
- } else if(pt[i].p_type == PT_DYNAMIC) {
- dyn = (Elf64_Dyn*)((uintptr)hdr + pt[i].p_offset);
- }
- }
-
- if(found_vaddr == false || dyn == nil)
- return; // Failed
-
- // Fish out the useful bits of the dynamic table.
- hash = nil;
- vdso_info->symstrings = nil;
- vdso_info->symtab = nil;
- vdso_info->versym = nil;
- vdso_info->verdef = nil;
- for(i=0; dyn[i].d_tag!=DT_NULL; i++) {
- switch(dyn[i].d_tag) {
- case DT_STRTAB:
- vdso_info->symstrings = (const byte *)
- ((uintptr)dyn[i].d_un.d_ptr
- + vdso_info->load_offset);
- break;
- case DT_SYMTAB:
- vdso_info->symtab = (Elf64_Sym *)
- ((uintptr)dyn[i].d_un.d_ptr
- + vdso_info->load_offset);
- break;
- case DT_HASH:
- hash = (Elf64_Word *)
- ((uintptr)dyn[i].d_un.d_ptr
- + vdso_info->load_offset);
- break;
- case DT_VERSYM:
- vdso_info->versym = (Elf64_Versym *)
- ((uintptr)dyn[i].d_un.d_ptr
- + vdso_info->load_offset);
- break;
- case DT_VERDEF:
- vdso_info->verdef = (Elf64_Verdef *)
- ((uintptr)dyn[i].d_un.d_ptr
- + vdso_info->load_offset);
- break;
- }
- }
- if(vdso_info->symstrings == nil || vdso_info->symtab == nil || hash == nil)
- return; // Failed
-
- if(vdso_info->verdef == nil)
- vdso_info->versym = 0;
-
- // Parse the hash table header.
- vdso_info->nbucket = hash[0];
- vdso_info->nchain = hash[1];
- vdso_info->bucket = &hash[2];
- vdso_info->chain = &hash[vdso_info->nbucket + 2];
-
- // That's all we need.
- vdso_info->valid = true;
-}
-
-static int32
-vdso_find_version(struct vdso_info *vdso_info, version_key* ver)
-{
- if(vdso_info->valid == false) {
- return 0;
- }
- Elf64_Verdef *def = vdso_info->verdef;
- while(true) {
- if((def->vd_flags & VER_FLG_BASE) == 0) {
- Elf64_Verdaux *aux = (Elf64_Verdaux*)((byte *)def + def->vd_aux);
- if(def->vd_hash == ver->ver_hash &&
- runtime·strcmp(ver->version, vdso_info->symstrings + aux->vda_name) == 0) {
- return def->vd_ndx & 0x7fff;
- }
- }
-
- if(def->vd_next == 0) {
- break;
- }
- def = (Elf64_Verdef *)((byte *)def + def->vd_next);
- }
- return -1; // can not match any version
-}
-
-static void
-vdso_parse_symbols(struct vdso_info *vdso_info, int32 version)
-{
- int32 i;
- Elf64_Word chain;
- Elf64_Sym *sym;
-
- if(vdso_info->valid == false)
- return;
-
- for(i=0; i<nelem(sym_keys); i++) {
- for(chain = vdso_info->bucket[sym_keys[i].sym_hash % vdso_info->nbucket];
- chain != 0; chain = vdso_info->chain[chain]) {
-
- sym = &vdso_info->symtab[chain];
- if(ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
- continue;
- if(ELF64_ST_BIND(sym->st_info) != STB_GLOBAL &&
- ELF64_ST_BIND(sym->st_info) != STB_WEAK)
- continue;
- if(sym->st_shndx == SHN_UNDEF)
- continue;
- if(runtime·strcmp(sym_keys[i].name, vdso_info->symstrings + sym->st_name) != 0)
- continue;
-
- // Check symbol version.
- if(vdso_info->versym != nil && version != 0
- && vdso_info->versym[chain] & 0x7fff != version)
- continue;
-
- *sym_keys[i].var_ptr = (void *)(vdso_info->load_offset + sym->st_value);
- break;
- }
- }
-}
-
-static void
-runtime·linux_setup_vdso(int32 argc, uint8** argv)
-{
- struct vdso_info vdso_info;
-
- // skip argvc
- byte **p = argv;
- p = &p[argc+1];
-
- // skip envp to get to ELF auxiliary vector.
- for(; *p!=0; p++) {}
-
- // skip NULL separator
- p++;
-
- // now, p points to auxv
- Elf64_auxv_t *elf_auxv = (Elf64_auxv_t*) p;
-
- for(int32 i=0; elf_auxv[i].a_type!=AT_NULL; i++) {
- if(elf_auxv[i].a_type == AT_SYSINFO_EHDR) {
- if(elf_auxv[i].a_un.a_val == 0) {
- // Something went wrong
- continue;
- }
- vdso_init_from_sysinfo_ehdr(&vdso_info, (Elf64_Ehdr*)elf_auxv[i].a_un.a_val);
- vdso_parse_symbols(&vdso_info, vdso_find_version(&vdso_info, &linux26));
- continue;
- }
- if(elf_auxv[i].a_type == AT_RANDOM) {
- runtime·startup_random_data = (byte*)elf_auxv[i].a_un.a_val;
- runtime·startup_random_data_len = 16;
- continue;
- }
- }
-}
-
-void (*runtime·sysargs)(int32, uint8**) = runtime·linux_setup_vdso;
diff --git a/src/runtime/vdso_linux_amd64.go b/src/runtime/vdso_linux_amd64.go
new file mode 100644
index 000000000..7eb698811
--- /dev/null
+++ b/src/runtime/vdso_linux_amd64.go
@@ -0,0 +1,328 @@
+// Copyright 2012 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 runtime
+
+import "unsafe"
+
+// Look up symbols in the Linux vDSO.
+
+// This code was originally based on the sample Linux vDSO parser at
+// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/vDSO/parse_vdso.c
+
+// This implements the ELF dynamic linking spec at
+// http://sco.com/developers/gabi/latest/ch5.dynamic.html
+
+// The version section is documented at
+// http://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/symversion.html
+
+const (
+ _AT_RANDOM = 25
+ _AT_SYSINFO_EHDR = 33
+ _AT_NULL = 0 /* End of vector */
+
+ _PT_LOAD = 1 /* Loadable program segment */
+ _PT_DYNAMIC = 2 /* Dynamic linking information */
+
+ _DT_NULL = 0 /* Marks end of dynamic section */
+ _DT_HASH = 4 /* Dynamic symbol hash table */
+ _DT_STRTAB = 5 /* Address of string table */
+ _DT_SYMTAB = 6 /* Address of symbol table */
+ _DT_VERSYM = 0x6ffffff0
+ _DT_VERDEF = 0x6ffffffc
+
+ _VER_FLG_BASE = 0x1 /* Version definition of file itself */
+
+ _SHN_UNDEF = 0 /* Undefined section */
+
+ _SHT_DYNSYM = 11 /* Dynamic linker symbol table */
+
+ _STT_FUNC = 2 /* Symbol is a code object */
+
+ _STB_GLOBAL = 1 /* Global symbol */
+ _STB_WEAK = 2 /* Weak symbol */
+
+ _EI_NIDENT = 16
+)
+
+/* How to extract and insert information held in the st_info field. */
+func _ELF64_ST_BIND(val byte) byte { return val >> 4 }
+func _ELF64_ST_TYPE(val byte) byte { return val & 0xf }
+
+type elf64Sym struct {
+ st_name uint32
+ st_info byte
+ st_other byte
+ st_shndx uint16
+ st_value uint64
+ st_size uint64
+}
+
+type elf64Verdef struct {
+ vd_version uint16 /* Version revision */
+ vd_flags uint16 /* Version information */
+ vd_ndx uint16 /* Version Index */
+ vd_cnt uint16 /* Number of associated aux entries */
+ vd_hash uint32 /* Version name hash value */
+ vd_aux uint32 /* Offset in bytes to verdaux array */
+ vd_next uint32 /* Offset in bytes to next verdef entry */
+}
+
+type elf64Ehdr struct {
+ e_ident [_EI_NIDENT]byte /* Magic number and other info */
+ e_type uint16 /* Object file type */
+ e_machine uint16 /* Architecture */
+ e_version uint32 /* Object file version */
+ e_entry uint64 /* Entry point virtual address */
+ e_phoff uint64 /* Program header table file offset */
+ e_shoff uint64 /* Section header table file offset */
+ e_flags uint32 /* Processor-specific flags */
+ e_ehsize uint16 /* ELF header size in bytes */
+ e_phentsize uint16 /* Program header table entry size */
+ e_phnum uint16 /* Program header table entry count */
+ e_shentsize uint16 /* Section header table entry size */
+ e_shnum uint16 /* Section header table entry count */
+ e_shstrndx uint16 /* Section header string table index */
+}
+
+type elf64Phdr struct {
+ p_type uint32 /* Segment type */
+ p_flags uint32 /* Segment flags */
+ p_offset uint64 /* Segment file offset */
+ p_vaddr uint64 /* Segment virtual address */
+ p_paddr uint64 /* Segment physical address */
+ p_filesz uint64 /* Segment size in file */
+ p_memsz uint64 /* Segment size in memory */
+ p_align uint64 /* Segment alignment */
+}
+
+type elf64Shdr struct {
+ sh_name uint32 /* Section name (string tbl index) */
+ sh_type uint32 /* Section type */
+ sh_flags uint64 /* Section flags */
+ sh_addr uint64 /* Section virtual addr at execution */
+ sh_offset uint64 /* Section file offset */
+ sh_size uint64 /* Section size in bytes */
+ sh_link uint32 /* Link to another section */
+ sh_info uint32 /* Additional section information */
+ sh_addralign uint64 /* Section alignment */
+ sh_entsize uint64 /* Entry size if section holds table */
+}
+
+type elf64Dyn struct {
+ d_tag int64 /* Dynamic entry type */
+ d_val uint64 /* Integer value */
+}
+
+type elf64Verdaux struct {
+ vda_name uint32 /* Version or dependency names */
+ vda_next uint32 /* Offset in bytes to next verdaux entry */
+}
+
+type elf64Auxv struct {
+ a_type uint64 /* Entry type */
+ a_val uint64 /* Integer value */
+}
+
+type symbol_key struct {
+ name string
+ sym_hash uint32
+ ptr *uintptr
+}
+
+type version_key struct {
+ version string
+ ver_hash uint32
+}
+
+type vdso_info struct {
+ valid bool
+
+ /* Load information */
+ load_addr uintptr
+ load_offset uintptr /* load_addr - recorded vaddr */
+
+ /* Symbol table */
+ symtab *[1 << 32]elf64Sym
+ symstrings *[1 << 32]byte
+ chain []uint32
+ bucket []uint32
+
+ /* Version table */
+ versym *[1 << 32]uint16
+ verdef *elf64Verdef
+}
+
+var linux26 = version_key{"LINUX_2.6", 0x3ae75f6}
+
+var sym_keys = []symbol_key{
+ {"__vdso_time", 0xa33c485, &__vdso_time_sym},
+ {"__vdso_gettimeofday", 0x315ca59, &__vdso_gettimeofday_sym},
+ {"__vdso_clock_gettime", 0xd35ec75, &__vdso_clock_gettime_sym},
+}
+
+// initialize with vsyscall fallbacks
+var (
+ __vdso_time_sym uintptr = 0xffffffffff600400
+ __vdso_gettimeofday_sym uintptr = 0xffffffffff600000
+ __vdso_clock_gettime_sym uintptr = 0
+)
+
+func vdso_init_from_sysinfo_ehdr(info *vdso_info, hdr *elf64Ehdr) {
+ info.valid = false
+ info.load_addr = uintptr(unsafe.Pointer(hdr))
+
+ pt := unsafe.Pointer(info.load_addr + uintptr(hdr.e_phoff))
+
+ // We need two things from the segment table: the load offset
+ // and the dynamic table.
+ var found_vaddr bool
+ var dyn *[1 << 20]elf64Dyn
+ for i := uint16(0); i < hdr.e_phnum; i++ {
+ pt := (*elf64Phdr)(add(pt, uintptr(i)*unsafe.Sizeof(elf64Phdr{})))
+ switch pt.p_type {
+ case _PT_LOAD:
+ if !found_vaddr {
+ found_vaddr = true
+ info.load_offset = info.load_addr + uintptr(pt.p_offset-pt.p_vaddr)
+ }
+
+ case _PT_DYNAMIC:
+ dyn = (*[1 << 20]elf64Dyn)(unsafe.Pointer(info.load_addr + uintptr(pt.p_offset)))
+ }
+ }
+
+ if !found_vaddr || dyn == nil {
+ return // Failed
+ }
+
+ // Fish out the useful bits of the dynamic table.
+
+ var hash *[1 << 30]uint32
+ hash = nil
+ info.symstrings = nil
+ info.symtab = nil
+ info.versym = nil
+ info.verdef = nil
+ for i := 0; dyn[i].d_tag != _DT_NULL; i++ {
+ dt := &dyn[i]
+ p := info.load_offset + uintptr(dt.d_val)
+ switch dt.d_tag {
+ case _DT_STRTAB:
+ info.symstrings = (*[1 << 32]byte)(unsafe.Pointer(p))
+ case _DT_SYMTAB:
+ info.symtab = (*[1 << 32]elf64Sym)(unsafe.Pointer(p))
+ case _DT_HASH:
+ hash = (*[1 << 30]uint32)(unsafe.Pointer(p))
+ case _DT_VERSYM:
+ info.versym = (*[1 << 32]uint16)(unsafe.Pointer(p))
+ case _DT_VERDEF:
+ info.verdef = (*elf64Verdef)(unsafe.Pointer(p))
+ }
+ }
+
+ if info.symstrings == nil || info.symtab == nil || hash == nil {
+ return // Failed
+ }
+
+ if info.verdef == nil {
+ info.versym = nil
+ }
+
+ // Parse the hash table header.
+ nbucket := hash[0]
+ nchain := hash[1]
+ info.bucket = hash[2 : 2+nbucket]
+ info.chain = hash[2+nbucket : 2+nbucket+nchain]
+
+ // That's all we need.
+ info.valid = true
+}
+
+func vdso_find_version(info *vdso_info, ver *version_key) int32 {
+ if !info.valid {
+ return 0
+ }
+
+ def := info.verdef
+ for {
+ if def.vd_flags&_VER_FLG_BASE == 0 {
+ aux := (*elf64Verdaux)(add(unsafe.Pointer(def), uintptr(def.vd_aux)))
+ if def.vd_hash == ver.ver_hash && ver.version == gostringnocopy(&info.symstrings[aux.vda_name]) {
+ return int32(def.vd_ndx & 0x7fff)
+ }
+ }
+
+ if def.vd_next == 0 {
+ break
+ }
+ def = (*elf64Verdef)(add(unsafe.Pointer(def), uintptr(def.vd_next)))
+ }
+
+ return -1 // can not match any version
+}
+
+func vdso_parse_symbols(info *vdso_info, version int32) {
+ if !info.valid {
+ return
+ }
+
+ for _, k := range sym_keys {
+ for chain := info.bucket[k.sym_hash%uint32(len(info.bucket))]; chain != 0; chain = info.chain[chain] {
+ sym := &info.symtab[chain]
+ typ := _ELF64_ST_TYPE(sym.st_info)
+ bind := _ELF64_ST_BIND(sym.st_info)
+ if typ != _STT_FUNC || bind != _STB_GLOBAL && bind != _STB_WEAK || sym.st_shndx == _SHN_UNDEF {
+ continue
+ }
+ if k.name != gostringnocopy(&info.symstrings[sym.st_name]) {
+ continue
+ }
+
+ // Check symbol version.
+ if info.versym != nil && version != 0 && int32(info.versym[chain]&0x7fff) != version {
+ continue
+ }
+
+ *k.ptr = info.load_offset + uintptr(sym.st_value)
+ break
+ }
+ }
+}
+
+func sysargs(argc int32, argv **byte) {
+ n := argc + 1
+
+ // skip envp to get to ELF auxiliary vector.
+ for argv_index(argv, n) != nil {
+ n++
+ }
+
+ // skip NULL separator
+ n++
+
+ // now argv+n is auxv
+ auxv := (*[1 << 32]elf64Auxv)(add(unsafe.Pointer(argv), uintptr(n)*ptrSize))
+
+ for i := 0; auxv[i].a_type != _AT_NULL; i++ {
+ av := &auxv[i]
+ switch av.a_type {
+ case _AT_SYSINFO_EHDR:
+ if av.a_val == 0 {
+ // Something went wrong
+ continue
+ }
+ var info vdso_info
+ // TODO(rsc): I don't understand why the compiler thinks info escapes
+ // when passed to the three functions below.
+ info1 := (*vdso_info)(noescape(unsafe.Pointer(&info)))
+ vdso_init_from_sysinfo_ehdr(info1, (*elf64Ehdr)(unsafe.Pointer(uintptr(av.a_val))))
+ vdso_parse_symbols(info1, vdso_find_version(info1, &linux26))
+
+ case _AT_RANDOM:
+ startup_random_data = (*byte)(unsafe.Pointer(uintptr(av.a_val)))
+ startup_random_data_len = 16
+ }
+ }
+}
diff --git a/src/runtime/vdso_none.go b/src/runtime/vdso_none.go
new file mode 100644
index 000000000..ac6f8cb18
--- /dev/null
+++ b/src/runtime/vdso_none.go
@@ -0,0 +1,10 @@
+// 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.
+
+// +build !linux !amd64
+
+package runtime
+
+func sysargs(argc int32, argv **byte) {
+}
diff --git a/src/runtime/vlop_arm.s b/src/runtime/vlop_arm.s
index b4b905bb7..5354bf911 100644
--- a/src/runtime/vlop_arm.s
+++ b/src/runtime/vlop_arm.s
@@ -23,7 +23,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
#include "textflag.h"
arg=0
@@ -100,7 +101,7 @@ TEXT _sfloat(SB), NOSPLIT, $68-0 // 4 arg + 14*4 saved regs + cpsr + return valu
// load the signal fault address into LR, and jump
// to the real sigpanic.
// This simulates what sighandler does for a memory fault.
-TEXT _sfloatpanic(SB),NOSPLIT,$-4
+TEXT runtime·_sfloatpanic(SB),NOSPLIT,$-4
MOVW $0, R0
MOVW.W R0, -4(R13)
MOVW g_sigpc(g), LR
diff --git a/src/runtime/vlrt.c b/src/runtime/vlrt.c
deleted file mode 100644
index cb0d14796..000000000
--- a/src/runtime/vlrt.c
+++ /dev/null
@@ -1,914 +0,0 @@
-// Inferno's libkern/vlrt-386.c
-// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-386.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
-// Portions Copyright 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// +build arm 386
-
-#include "textflag.h"
-
-/*
- * C runtime for 64-bit divide, others.
- *
- * TODO(rsc): The simple functions are dregs--8c knows how
- * to generate the code directly now. Find and remove.
- */
-
-void runtime·panicdivide(void);
-
-typedef unsigned long ulong;
-typedef unsigned int uint;
-typedef unsigned short ushort;
-typedef unsigned char uchar;
-typedef signed char schar;
-
-#define SIGN(n) (1UL<<(n-1))
-
-typedef struct Vlong Vlong;
-struct Vlong
-{
- ulong lo;
- ulong hi;
-};
-
-typedef union Vlong64 Vlong64;
-union Vlong64
-{
- long long v;
- Vlong v2;
-};
-
-void runtime·abort(void);
-
-#pragma textflag NOSPLIT
-Vlong
-_addv(Vlong a, Vlong b)
-{
- Vlong r;
-
- r.lo = a.lo + b.lo;
- r.hi = a.hi + b.hi;
- if(r.lo < a.lo)
- r.hi++;
- return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_subv(Vlong a, Vlong b)
-{
- Vlong r;
-
- r.lo = a.lo - b.lo;
- r.hi = a.hi - b.hi;
- if(r.lo > a.lo)
- r.hi--;
- return r;
-}
-
-Vlong
-_d2v(double d)
-{
- union { double d; Vlong vl; } x;
- ulong xhi, xlo, ylo, yhi;
- int sh;
- Vlong y;
-
- x.d = d;
-
- xhi = (x.vl.hi & 0xfffff) | 0x100000;
- xlo = x.vl.lo;
- sh = 1075 - ((x.vl.hi >> 20) & 0x7ff);
-
- ylo = 0;
- yhi = 0;
- if(sh >= 0) {
- /* v = (hi||lo) >> sh */
- if(sh < 32) {
- if(sh == 0) {
- ylo = xlo;
- yhi = xhi;
- } else {
- ylo = (xlo >> sh) | (xhi << (32-sh));
- yhi = xhi >> sh;
- }
- } else {
- if(sh == 32) {
- ylo = xhi;
- } else
- if(sh < 64) {
- ylo = xhi >> (sh-32);
- }
- }
- } else {
- /* v = (hi||lo) << -sh */
- sh = -sh;
- if(sh <= 10) { /* NOTE: sh <= 11 on ARM??? */
- ylo = xlo << sh;
- yhi = (xhi << sh) | (xlo >> (32-sh));
- } else {
- /* overflow */
- yhi = d; /* causes something awful */
- }
- }
- if(x.vl.hi & SIGN(32)) {
- if(ylo != 0) {
- ylo = -ylo;
- yhi = ~yhi;
- } else
- yhi = -yhi;
- }
-
- y.hi = yhi;
- y.lo = ylo;
- return y;
-}
-
-Vlong
-_f2v(float f)
-{
- return _d2v(f);
-}
-
-double
-_ul2d(ulong u)
-{
- // compensate for bug in c
- if(u & SIGN(32)) {
- u ^= SIGN(32);
- return 2147483648. + u;
- }
- return u;
-}
-
-double
-_v2d(Vlong x)
-{
- if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
- return -(_ul2d(x.hi)*4294967296. + _ul2d(x.lo));
- }
- return (long)x.hi*4294967296. + x.lo;
-}
-
-float
-_v2f(Vlong x)
-{
- return _v2d(x);
-}
-
-ulong runtime·_div64by32(Vlong, ulong, ulong*);
-int runtime·_mul64by32(Vlong*, Vlong, ulong);
-
-static void
-slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
-{
- ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
- int i;
-
- numhi = num.hi;
- numlo = num.lo;
- denhi = den.hi;
- denlo = den.lo;
-
- /*
- * get a divide by zero
- */
- if(denlo==0 && denhi==0) {
- runtime·panicdivide();
- }
-
- /*
- * set up the divisor and find the number of iterations needed
- */
- if(numhi >= SIGN(32)) {
- quohi = SIGN(32);
- quolo = 0;
- } else {
- quohi = numhi;
- quolo = numlo;
- }
- i = 0;
- while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
- denhi = (denhi<<1) | (denlo>>31);
- denlo <<= 1;
- i++;
- }
-
- quohi = 0;
- quolo = 0;
- for(; i >= 0; i--) {
- quohi = (quohi<<1) | (quolo>>31);
- quolo <<= 1;
- if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
- t = numlo;
- numlo -= denlo;
- if(numlo > t)
- numhi--;
- numhi -= denhi;
- quolo |= 1;
- }
- denlo = (denlo>>1) | (denhi<<31);
- denhi >>= 1;
- }
-
- if(q) {
- q->lo = quolo;
- q->hi = quohi;
- }
- if(r) {
- r->lo = numlo;
- r->hi = numhi;
- }
-}
-
-#ifdef GOARCH_arm
-static void
-dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
-{
- slowdodiv(num, den, qp, rp);
-}
-#endif
-
-#ifdef GOARCH_386
-static void
-dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
-{
- ulong n;
- Vlong x, q, r;
-
- if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
- if(qp) {
- qp->hi = 0;
- qp->lo = 0;
- }
- if(rp) {
- rp->hi = num.hi;
- rp->lo = num.lo;
- }
- return;
- }
-
- if(den.hi != 0){
- q.hi = 0;
- n = num.hi/den.hi;
- if(runtime·_mul64by32(&x, den, n) || x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo))
- slowdodiv(num, den, &q, &r);
- else {
- q.lo = n;
- *(long long*)&r = *(long long*)&num - *(long long*)&x;
- }
- } else {
- if(num.hi >= den.lo){
- if(den.lo == 0)
- runtime·panicdivide();
- q.hi = n = num.hi/den.lo;
- num.hi -= den.lo*n;
- } else {
- q.hi = 0;
- }
- q.lo = runtime·_div64by32(num, den.lo, &r.lo);
- r.hi = 0;
- }
- if(qp) {
- qp->lo = q.lo;
- qp->hi = q.hi;
- }
- if(rp) {
- rp->lo = r.lo;
- rp->hi = r.hi;
- }
-}
-#endif
-
-Vlong
-_divvu(Vlong n, Vlong d)
-{
- Vlong q;
-
- if(n.hi == 0 && d.hi == 0) {
- if(d.lo == 0)
- runtime·panicdivide();
- q.hi = 0;
- q.lo = n.lo / d.lo;
- return q;
- }
- dodiv(n, d, &q, 0);
- return q;
-}
-
-Vlong
-_modvu(Vlong n, Vlong d)
-{
- Vlong r;
-
- if(n.hi == 0 && d.hi == 0) {
- if(d.lo == 0)
- runtime·panicdivide();
- r.hi = 0;
- r.lo = n.lo % d.lo;
- return r;
- }
- dodiv(n, d, 0, &r);
- return r;
-}
-
-static void
-vneg(Vlong *v)
-{
-
- if(v->lo == 0) {
- v->hi = -v->hi;
- return;
- }
- v->lo = -v->lo;
- v->hi = ~v->hi;
-}
-
-Vlong
-_divv(Vlong n, Vlong d)
-{
- long nneg, dneg;
- Vlong q;
-
- if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
- if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
- // special case: 32-bit -0x80000000 / -1 causes divide error,
- // but it's okay in this 64-bit context.
- q.lo = 0x80000000;
- q.hi = 0;
- return q;
- }
- if(d.lo == 0)
- runtime·panicdivide();
- q.lo = (long)n.lo / (long)d.lo;
- q.hi = ((long)q.lo) >> 31;
- return q;
- }
- nneg = n.hi >> 31;
- if(nneg)
- vneg(&n);
- dneg = d.hi >> 31;
- if(dneg)
- vneg(&d);
- dodiv(n, d, &q, 0);
- if(nneg != dneg)
- vneg(&q);
- return q;
-}
-
-Vlong
-_modv(Vlong n, Vlong d)
-{
- long nneg, dneg;
- Vlong r;
-
- if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
- if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
- // special case: 32-bit -0x80000000 % -1 causes divide error,
- // but it's okay in this 64-bit context.
- r.lo = 0;
- r.hi = 0;
- return r;
- }
- if(d.lo == 0)
- runtime·panicdivide();
- r.lo = (long)n.lo % (long)d.lo;
- r.hi = ((long)r.lo) >> 31;
- return r;
- }
- nneg = n.hi >> 31;
- if(nneg)
- vneg(&n);
- dneg = d.hi >> 31;
- if(dneg)
- vneg(&d);
- dodiv(n, d, 0, &r);
- if(nneg)
- vneg(&r);
- return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_rshav(Vlong a, int b)
-{
- long t;
- Vlong r;
-
- t = a.hi;
- if(b >= 32) {
- r.hi = t>>31;
- if(b >= 64) {
- /* this is illegal re C standard */
- r.lo = t>>31;
- return r;
- }
- r.lo = t >> (b-32);
- return r;
- }
- if(b <= 0) {
- r.hi = t;
- r.lo = a.lo;
- return r;
- }
- r.hi = t >> b;
- r.lo = (t << (32-b)) | (a.lo >> b);
- return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_rshlv(Vlong a, int b)
-{
- ulong t;
- Vlong r;
-
- t = a.hi;
- if(b >= 32) {
- r.hi = 0;
- if(b >= 64) {
- /* this is illegal re C standard */
- r.lo = 0;
- return r;
- }
- r.lo = t >> (b-32);
- return r;
- }
- if(b <= 0) {
- r.hi = t;
- r.lo = a.lo;
- return r;
- }
- r.hi = t >> b;
- r.lo = (t << (32-b)) | (a.lo >> b);
- return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_lshv(Vlong a, int b)
-{
- ulong t;
-
- t = a.lo;
- if(b >= 32) {
- if(b >= 64) {
- /* this is illegal re C standard */
- return (Vlong){0, 0};
- }
- return (Vlong){0, t<<(b-32)};
- }
- if(b <= 0) {
- return (Vlong){t, a.hi};
- }
- return (Vlong){t<<b, (t >> (32-b)) | (a.hi << b)};
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_andv(Vlong a, Vlong b)
-{
- Vlong r;
-
- r.hi = a.hi & b.hi;
- r.lo = a.lo & b.lo;
- return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_orv(Vlong a, Vlong b)
-{
- Vlong r;
-
- r.hi = a.hi | b.hi;
- r.lo = a.lo | b.lo;
- return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_xorv(Vlong a, Vlong b)
-{
- Vlong r;
-
- r.hi = a.hi ^ b.hi;
- r.lo = a.lo ^ b.lo;
- return r;
-}
-
-Vlong
-_vpp(Vlong *r)
-{
- Vlong l;
-
- l = *r;
- r->lo++;
- if(r->lo == 0)
- r->hi++;
- return l;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_vmm(Vlong *r)
-{
- Vlong l;
-
- l = *r;
- if(r->lo == 0)
- r->hi--;
- r->lo--;
- return l;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_ppv(Vlong *r)
-{
-
- r->lo++;
- if(r->lo == 0)
- r->hi++;
- return *r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_mmv(Vlong *r)
-{
-
- if(r->lo == 0)
- r->hi--;
- r->lo--;
- return *r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_vasop(void *lv, Vlong fn(Vlong, Vlong), int type, Vlong rv)
-{
- Vlong t, u;
-
- u.lo = 0;
- u.hi = 0;
- switch(type) {
- default:
- runtime·abort();
- break;
-
- case 1: /* schar */
- t.lo = *(schar*)lv;
- t.hi = t.lo >> 31;
- u = fn(t, rv);
- *(schar*)lv = u.lo;
- break;
-
- case 2: /* uchar */
- t.lo = *(uchar*)lv;
- t.hi = 0;
- u = fn(t, rv);
- *(uchar*)lv = u.lo;
- break;
-
- case 3: /* short */
- t.lo = *(short*)lv;
- t.hi = t.lo >> 31;
- u = fn(t, rv);
- *(short*)lv = u.lo;
- break;
-
- case 4: /* ushort */
- t.lo = *(ushort*)lv;
- t.hi = 0;
- u = fn(t, rv);
- *(ushort*)lv = u.lo;
- break;
-
- case 9: /* int */
- t.lo = *(int*)lv;
- t.hi = t.lo >> 31;
- u = fn(t, rv);
- *(int*)lv = u.lo;
- break;
-
- case 10: /* uint */
- t.lo = *(uint*)lv;
- t.hi = 0;
- u = fn(t, rv);
- *(uint*)lv = u.lo;
- break;
-
- case 5: /* long */
- t.lo = *(long*)lv;
- t.hi = t.lo >> 31;
- u = fn(t, rv);
- *(long*)lv = u.lo;
- break;
-
- case 6: /* ulong */
- t.lo = *(ulong*)lv;
- t.hi = 0;
- u = fn(t, rv);
- *(ulong*)lv = u.lo;
- break;
-
- case 7: /* vlong */
- case 8: /* uvlong */
- if((void*)fn == _lshv || (void*)fn == _rshav || (void*)fn == _rshlv)
- u = ((Vlong(*)(Vlong,int))fn)(*(Vlong*)lv, *(int*)&rv);
- else
- u = fn(*(Vlong*)lv, rv);
- *(Vlong*)lv = u;
- break;
- }
- return u;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_p2v(void *p)
-{
- long t;
- Vlong ret;
-
- t = (ulong)p;
- ret.lo = t;
- ret.hi = 0;
- return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_sl2v(long sl)
-{
- long t;
- Vlong ret;
-
- t = sl;
- ret.lo = t;
- ret.hi = t >> 31;
- return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_ul2v(ulong ul)
-{
- long t;
- Vlong ret;
-
- t = ul;
- ret.lo = t;
- ret.hi = 0;
- return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_si2v(int si)
-{
- return (Vlong){si, si>>31};
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_ui2v(uint ui)
-{
- long t;
- Vlong ret;
-
- t = ui;
- ret.lo = t;
- ret.hi = 0;
- return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_sh2v(long sh)
-{
- long t;
- Vlong ret;
-
- t = (sh << 16) >> 16;
- ret.lo = t;
- ret.hi = t >> 31;
- return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_uh2v(ulong ul)
-{
- long t;
- Vlong ret;
-
- t = ul & 0xffff;
- ret.lo = t;
- ret.hi = 0;
- return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_sc2v(long uc)
-{
- long t;
- Vlong ret;
-
- t = (uc << 24) >> 24;
- ret.lo = t;
- ret.hi = t >> 31;
- return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_uc2v(ulong ul)
-{
- long t;
- Vlong ret;
-
- t = ul & 0xff;
- ret.lo = t;
- ret.hi = 0;
- return ret;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2sc(Vlong rv)
-{
- long t;
-
- t = rv.lo & 0xff;
- return (t << 24) >> 24;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2uc(Vlong rv)
-{
-
- return rv.lo & 0xff;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2sh(Vlong rv)
-{
- long t;
-
- t = rv.lo & 0xffff;
- return (t << 16) >> 16;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2uh(Vlong rv)
-{
-
- return rv.lo & 0xffff;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2sl(Vlong rv)
-{
-
- return rv.lo;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2ul(Vlong rv)
-{
-
- return rv.lo;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2si(Vlong rv)
-{
- return rv.lo;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2ui(Vlong rv)
-{
-
- return rv.lo;
-}
-
-#pragma textflag NOSPLIT
-int
-_testv(Vlong rv)
-{
- return rv.lo || rv.hi;
-}
-
-#pragma textflag NOSPLIT
-int
-_eqv(Vlong lv, Vlong rv)
-{
- return lv.lo == rv.lo && lv.hi == rv.hi;
-}
-
-#pragma textflag NOSPLIT
-int
-_nev(Vlong lv, Vlong rv)
-{
- return lv.lo != rv.lo || lv.hi != rv.hi;
-}
-
-#pragma textflag NOSPLIT
-int
-_ltv(Vlong lv, Vlong rv)
-{
- return (long)lv.hi < (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo < rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_lev(Vlong lv, Vlong rv)
-{
- return (long)lv.hi < (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo <= rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_gtv(Vlong lv, Vlong rv)
-{
- return (long)lv.hi > (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo > rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_gev(Vlong lv, Vlong rv)
-{
- return (long)lv.hi > (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo >= rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_lov(Vlong lv, Vlong rv)
-{
- return lv.hi < rv.hi ||
- (lv.hi == rv.hi && lv.lo < rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_lsv(Vlong lv, Vlong rv)
-{
- return lv.hi < rv.hi ||
- (lv.hi == rv.hi && lv.lo <= rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_hiv(Vlong lv, Vlong rv)
-{
- return lv.hi > rv.hi ||
- (lv.hi == rv.hi && lv.lo > rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_hsv(Vlong lv, Vlong rv)
-{
- return lv.hi > rv.hi ||
- (lv.hi == rv.hi && lv.lo >= rv.lo);
-}
diff --git a/src/runtime/zgoarch_386.go b/src/runtime/zgoarch_386.go
new file mode 100644
index 000000000..057a746bb
--- /dev/null
+++ b/src/runtime/zgoarch_386.go
@@ -0,0 +1,12 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `386`
+
+const goarch_386 = 1
+const goarch_amd64 = 0
+const goarch_amd64p32 = 0
+const goarch_arm = 0
+const goarch_power64 = 0
+const goarch_power64le = 0
diff --git a/src/runtime/zgoarch_amd64.go b/src/runtime/zgoarch_amd64.go
new file mode 100644
index 000000000..a71240726
--- /dev/null
+++ b/src/runtime/zgoarch_amd64.go
@@ -0,0 +1,12 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `amd64`
+
+const goarch_386 = 0
+const goarch_amd64 = 1
+const goarch_amd64p32 = 0
+const goarch_arm = 0
+const goarch_power64 = 0
+const goarch_power64le = 0
diff --git a/src/runtime/zgoarch_amd64p32.go b/src/runtime/zgoarch_amd64p32.go
new file mode 100644
index 000000000..2b6a142bb
--- /dev/null
+++ b/src/runtime/zgoarch_amd64p32.go
@@ -0,0 +1,12 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `amd64p32`
+
+const goarch_386 = 0
+const goarch_amd64 = 0
+const goarch_amd64p32 = 1
+const goarch_arm = 0
+const goarch_power64 = 0
+const goarch_power64le = 0
diff --git a/src/runtime/zgoarch_arm.go b/src/runtime/zgoarch_arm.go
new file mode 100644
index 000000000..403021005
--- /dev/null
+++ b/src/runtime/zgoarch_arm.go
@@ -0,0 +1,12 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `arm`
+
+const goarch_386 = 0
+const goarch_amd64 = 0
+const goarch_amd64p32 = 0
+const goarch_arm = 1
+const goarch_power64 = 0
+const goarch_power64le = 0
diff --git a/src/runtime/zgoarch_power64.go b/src/runtime/zgoarch_power64.go
new file mode 100644
index 000000000..cc361f050
--- /dev/null
+++ b/src/runtime/zgoarch_power64.go
@@ -0,0 +1,12 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `power64`
+
+const goarch_386 = 0
+const goarch_amd64 = 0
+const goarch_amd64p32 = 0
+const goarch_arm = 0
+const goarch_power64 = 1
+const goarch_power64le = 0
diff --git a/src/runtime/zgoarch_power64le.go b/src/runtime/zgoarch_power64le.go
new file mode 100644
index 000000000..41294e61b
--- /dev/null
+++ b/src/runtime/zgoarch_power64le.go
@@ -0,0 +1,12 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `power64le`
+
+const goarch_386 = 0
+const goarch_amd64 = 0
+const goarch_amd64p32 = 0
+const goarch_arm = 0
+const goarch_power64 = 0
+const goarch_power64le = 1
diff --git a/src/runtime/zgoos_android.go b/src/runtime/zgoos_android.go
new file mode 100644
index 000000000..0590bd9ab
--- /dev/null
+++ b/src/runtime/zgoos_android.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `android`
+
+const goos_android = 1
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_darwin.go b/src/runtime/zgoos_darwin.go
new file mode 100644
index 000000000..c0a7cd6e7
--- /dev/null
+++ b/src/runtime/zgoos_darwin.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `darwin`
+
+const goos_android = 0
+const goos_darwin = 1
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_dragonfly.go b/src/runtime/zgoos_dragonfly.go
new file mode 100644
index 000000000..008d6de81
--- /dev/null
+++ b/src/runtime/zgoos_dragonfly.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `dragonfly`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 1
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_freebsd.go b/src/runtime/zgoos_freebsd.go
new file mode 100644
index 000000000..247894035
--- /dev/null
+++ b/src/runtime/zgoos_freebsd.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `freebsd`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 1
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_linux.go b/src/runtime/zgoos_linux.go
new file mode 100644
index 000000000..c775ab538
--- /dev/null
+++ b/src/runtime/zgoos_linux.go
@@ -0,0 +1,19 @@
+// generated by gengoos.go using 'go generate'
+
+// +build !android
+
+package runtime
+
+const theGoos = `linux`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 1
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_nacl.go b/src/runtime/zgoos_nacl.go
new file mode 100644
index 000000000..d9d88f450
--- /dev/null
+++ b/src/runtime/zgoos_nacl.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `nacl`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 1
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_netbsd.go b/src/runtime/zgoos_netbsd.go
new file mode 100644
index 000000000..ff2c5cb8f
--- /dev/null
+++ b/src/runtime/zgoos_netbsd.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `netbsd`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 1
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_openbsd.go b/src/runtime/zgoos_openbsd.go
new file mode 100644
index 000000000..b071dc63a
--- /dev/null
+++ b/src/runtime/zgoos_openbsd.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `openbsd`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 1
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_plan9.go b/src/runtime/zgoos_plan9.go
new file mode 100644
index 000000000..4306b0f1e
--- /dev/null
+++ b/src/runtime/zgoos_plan9.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `plan9`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 1
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_solaris.go b/src/runtime/zgoos_solaris.go
new file mode 100644
index 000000000..10f9537d0
--- /dev/null
+++ b/src/runtime/zgoos_solaris.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `solaris`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 1
+const goos_windows = 0
diff --git a/src/runtime/zgoos_windows.go b/src/runtime/zgoos_windows.go
new file mode 100644
index 000000000..56f5c58ce
--- /dev/null
+++ b/src/runtime/zgoos_windows.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `windows`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 1
diff --git a/src/sync/atomic/asm_power64x.s b/src/sync/atomic/asm_power64x.s
new file mode 100644
index 000000000..1130d3c16
--- /dev/null
+++ b/src/sync/atomic/asm_power64x.s
@@ -0,0 +1,184 @@
+// 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.
+
+// +build power64 power64le
+
+#include "textflag.h"
+
+TEXT ·SwapInt32(SB),NOSPLIT,$0-20
+ BR ·SwapUint32(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0-20
+ MOVD addr+0(FP), R3
+ MOVW new+8(FP), R4
+ SYNC
+ LWAR (R3), R5
+ STWCCC R4, (R3)
+ BNE -3(PC)
+ SYNC
+ ISYNC
+ MOVW R5, old+16(FP)
+ RETURN
+
+TEXT ·SwapInt64(SB),NOSPLIT,$0-24
+ BR ·SwapUint64(SB)
+
+TEXT ·SwapUint64(SB),NOSPLIT,$0-24
+ MOVD addr+0(FP), R3
+ MOVD new+8(FP), R4
+ SYNC
+ LDAR (R3), R5
+ STDCCC R4, (R3)
+ BNE -3(PC)
+ SYNC
+ ISYNC
+ MOVD R5, old+16(FP)
+ RETURN
+
+TEXT ·SwapUintptr(SB),NOSPLIT,$0-24
+ BR ·SwapUint64(SB)
+
+TEXT ·SwapPointer(SB),NOSPLIT,$0-24
+ BR ·SwapUint64(SB)
+
+TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
+ BR ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
+ MOVD addr+0(FP), R3
+ MOVW old+8(FP), R4
+ MOVW new+12(FP), R5
+ SYNC
+ LWAR (R3), R6
+ CMPW R6, R4
+ BNE 8(PC)
+ STWCCC R5, (R3)
+ BNE -5(PC)
+ SYNC
+ ISYNC
+ MOVD $1, R3
+ MOVB R3, swapped+16(FP)
+ RETURN
+ MOVB R0, swapped+16(FP)
+ RETURN
+
+TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-25
+ BR ·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0-25
+ BR ·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
+ BR ·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
+ MOVD addr+0(FP), R3
+ MOVD old+8(FP), R4
+ MOVD new+16(FP), R5
+ SYNC
+ LDAR (R3), R6
+ CMP R6, R4
+ BNE 8(PC)
+ STDCCC R5, (R3)
+ BNE -5(PC)
+ SYNC
+ ISYNC
+ MOVD $1, R3
+ MOVB R3, swapped+24(FP)
+ RETURN
+ MOVB R0, swapped+24(FP)
+ RETURN
+
+TEXT ·AddInt32(SB),NOSPLIT,$0-20
+ BR ·AddUint32(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0-20
+ MOVD addr+0(FP), R3
+ MOVW delta+8(FP), R4
+ SYNC
+ LWAR (R3), R5
+ ADD R4, R5
+ STWCCC R5, (R3)
+ BNE -4(PC)
+ SYNC
+ ISYNC
+ MOVW R5, ret+16(FP)
+ RETURN
+
+TEXT ·AddUintptr(SB),NOSPLIT,$0-24
+ BR ·AddUint64(SB)
+
+TEXT ·AddInt64(SB),NOSPLIT,$0-24
+ BR ·AddUint64(SB)
+
+TEXT ·AddUint64(SB),NOSPLIT,$0-24
+ MOVD addr+0(FP), R3
+ MOVD delta+8(FP), R4
+ SYNC
+ LDAR (R3), R5
+ ADD R4, R5
+ STDCCC R5, (R3)
+ BNE -4(PC)
+ SYNC
+ ISYNC
+ MOVD R5, ret+16(FP)
+ RETURN
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0-12
+ BR ·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-12
+ MOVD addr+0(FP), R3
+ SYNC
+ MOVW 0(R3), R3
+ CMPW R3, R3, CR7
+ BC 4, 30, 1(PC) // bne- cr7,0x4
+ ISYNC
+ MOVW R3, val+8(FP)
+ RETURN
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+ BR ·LoadUint64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+ MOVD addr+0(FP), R3
+ SYNC
+ MOVD 0(R3), R3
+ CMP R3, R3, CR7
+ BC 4, 30, 1(PC) // bne- cr7,0x4
+ ISYNC
+ MOVD R3, val+8(FP)
+ RETURN
+
+TEXT ·LoadUintptr(SB),NOSPLIT,$0-16
+ BR ·LoadPointer(SB)
+
+TEXT ·LoadPointer(SB),NOSPLIT,$0-16
+ BR ·LoadUint64(SB)
+
+TEXT ·StoreInt32(SB),NOSPLIT,$0-12
+ BR ·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),NOSPLIT,$0-12
+ MOVD addr+0(FP), R3
+ MOVW val+8(FP), R4
+ SYNC
+ MOVW R4, 0(R3)
+ RETURN
+
+TEXT ·StoreInt64(SB),NOSPLIT,$0-16
+ BR ·StoreUint64(SB)
+
+TEXT ·StoreUint64(SB),NOSPLIT,$0-16
+ MOVD addr+0(FP), R3
+ MOVD val+8(FP), R4
+ SYNC
+ MOVD R4, 0(R3)
+ RETURN
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0-16
+ BR ·StorePointer(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0-16
+ BR ·StoreUint64(SB)
diff --git a/src/syscall/asm.s b/src/syscall/asm.s
index d4ca868f1..43561e201 100644
--- a/src/syscall/asm.s
+++ b/src/syscall/asm.s
@@ -4,5 +4,12 @@
#include "textflag.h"
+#ifdef GOARCH_power64
+#define RET RETURN
+#endif
+#ifdef GOARCH_power64le
+#define RET RETURN
+#endif
+
TEXT ·use(SB),NOSPLIT,$0
RET
diff --git a/src/syscall/asm_linux_power64x.s b/src/syscall/asm_linux_power64x.s
new file mode 100644
index 000000000..be8518a45
--- /dev/null
+++ b/src/syscall/asm_linux_power64x.s
@@ -0,0 +1,104 @@
+// 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.
+
+// +build linux
+// +build power64 power64le
+
+#include "textflag.h"
+
+//
+// System calls for Power64, Linux
+//
+
+// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R3
+ MOVD a2+16(FP), R4
+ MOVD a3+24(FP), R5
+ MOVD R0, R6
+ MOVD R0, R7
+ MOVD R0, R8
+ MOVD trap+0(FP), R9 // syscall entry
+ SYSCALL R9
+ BVC ok
+ MOVD $-1, R4
+ MOVD R4, r1+32(FP) // r1
+ MOVD R0, r2+40(FP) // r2
+ MOVD R3, err+48(FP) // errno
+ BL runtime·exitsyscall(SB)
+ RETURN
+ok:
+ MOVD R3, r1+32(FP) // r1
+ MOVD R4, r2+40(FP) // r2
+ MOVD R0, err+48(FP) // errno
+ BL runtime·exitsyscall(SB)
+ RETURN
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R3
+ MOVD a2+16(FP), R4
+ MOVD a3+24(FP), R5
+ MOVD a4+32(FP), R6
+ MOVD a5+40(FP), R7
+ MOVD a6+48(FP), R8
+ MOVD trap+0(FP), R9 // syscall entry
+ SYSCALL R9
+ BVC ok6
+ MOVD $-1, R4
+ MOVD R4, r1+56(FP) // r1
+ MOVD R0, r2+64(FP) // r2
+ MOVD R3, err+72(FP) // errno
+ BL runtime·exitsyscall(SB)
+ RETURN
+ok6:
+ MOVD R3, r1+56(FP) // r1
+ MOVD R4, r2+64(FP) // r2
+ MOVD R0, err+72(FP) // errno
+ BL runtime·exitsyscall(SB)
+ RETURN
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ MOVD a1+8(FP), R3
+ MOVD a2+16(FP), R4
+ MOVD a3+24(FP), R5
+ MOVD R0, R6
+ MOVD R0, R7
+ MOVD R0, R8
+ MOVD trap+0(FP), R9 // syscall entry
+ SYSCALL R9
+ BVC ok1
+ MOVD $-1, R4
+ MOVD R4, r1+32(FP) // r1
+ MOVD R0, r2+40(FP) // r2
+ MOVD R3, err+48(FP) // errno
+ RETURN
+ok1:
+ MOVD R3, r1+32(FP) // r1
+ MOVD R4, r2+40(FP) // r2
+ MOVD R0, err+48(FP) // errno
+ RETURN
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ MOVD a1+8(FP), R3
+ MOVD a2+16(FP), R4
+ MOVD a3+24(FP), R5
+ MOVD a4+32(FP), R6
+ MOVD a5+40(FP), R7
+ MOVD a6+48(FP), R8
+ MOVD trap+0(FP), R9 // syscall entry
+ SYSCALL R9
+ BVC ok2
+ MOVD $-1, R4
+ MOVD R4, r1+56(FP) // r1
+ MOVD R0, r2+64(FP) // r2
+ MOVD R3, err+72(FP) // errno
+ RETURN
+ok2:
+ MOVD R3, r1+56(FP) // r1
+ MOVD R4, r2+64(FP) // r2
+ MOVD R0, err+72(FP) // errno
+ RETURN
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index 9cb82a608..febd5a262 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -107,6 +107,7 @@ case "$#" in
exit 2
esac
+GOOSARCH_in=syscall_$GOOSARCH.go
case "$GOOSARCH" in
_* | *_ | _)
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
@@ -176,6 +177,20 @@ linux_arm)
mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
+linux_power64)
+ GOOSARCH_in=syscall_linux_power64x.go
+ unistd_h=/usr/include/asm/unistd.h
+ mkerrors="$mkerrors -m64"
+ mksysnum="./mksysnum_linux.pl $unistd_h"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+linux_power64le)
+ GOOSARCH_in=syscall_linux_power64x.go
+ unistd_h=/usr/include/powerpc64le-linux-gnu/asm/unistd.h
+ mkerrors="$mkerrors -m64"
+ mksysnum="./mksysnum_linux.pl $unistd_h"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
nacl_386)
mkerrors=""
mksyscall="./mksyscall.pl -l32 -nacl"
@@ -254,7 +269,7 @@ esac
syscall_goos="syscall_bsd.go $syscall_goos"
;;
esac
- if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
+ if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi
;;
esac
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
diff --git a/src/syscall/mkerrors.sh b/src/syscall/mkerrors.sh
index cf0afe0bd..4711f307a 100755
--- a/src/syscall/mkerrors.sh
+++ b/src/syscall/mkerrors.sh
@@ -242,6 +242,7 @@ ccflags="$@"
$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
$2 ~ /^(SCM_SRCRT)$/ {next}
$2 ~ /^(MAP_FAILED)$/ {next}
+ $2 ~ /^ELF_.*$/ {next} # <asm/elf.h> contains ELF_ARCH, etc.
$2 !~ /^ETH_/ &&
$2 !~ /^EPROC_/ &&
diff --git a/src/syscall/syscall_linux_power64x.go b/src/syscall/syscall_linux_power64x.go
new file mode 100644
index 000000000..fd043627a
--- /dev/null
+++ b/src/syscall/syscall_linux_power64x.go
@@ -0,0 +1,97 @@
+// 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.
+
+// +build linux
+// +build power64 power64le
+
+package syscall
+
+//sys Chown(path string, uid int, gid int) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatfs(fd int, buf *Statfs_t) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
+//sysnb Getegid() (egid int)
+//sysnb Geteuid() (euid int)
+//sysnb Getgid() (gid int)
+//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) = SYS_UGETRLIMIT
+//sysnb Getuid() (uid int)
+//sys Ioperm(from int, num int, on int) (err error)
+//sys Iopl(level int) (err error)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Listen(s int, n int) (err error)
+//sys Lstat(path string, stat *Stat_t) (err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
+//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
+//sys Setfsgid(gid int) (err error)
+//sys Setfsuid(uid int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
+//sysnb Setresuid(ruid int, euid int, suid int) (err error)
+//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sys Shutdown(fd int, how int) (err error)
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
+//sys Stat(path string, stat *Stat_t) (err error)
+//sys Statfs(path string, buf *Statfs_t) (err error)
+//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) = SYS_SYNC_FILE_RANGE2
+//sys Truncate(path string, length int64) (err error)
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
+//sysnb setgroups(n int, list *_Gid_t) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
+//sysnb socket(domain int, typ int, proto int) (fd int, err error)
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
+//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
+
+func Getpagesize() int { return 65536 }
+
+//sysnb Gettimeofday(tv *Timeval) (err error)
+//sysnb Time(t *Time_t) (tt Time_t, err error)
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = nsec / 1e9
+ ts.Nsec = nsec % 1e9
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Sec = nsec / 1e9
+ tv.Usec = nsec % 1e9 / 1e3
+ return
+}
+
+func (r *PtraceRegs) PC() uint64 { return r.Nip }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Nip = pc }
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint64(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint64(length)
+}
diff --git a/src/syscall/types_linux.go b/src/syscall/types_linux.go
index e8396a41f..5e9f698cf 100644
--- a/src/syscall/types_linux.go
+++ b/src/syscall/types_linux.go
@@ -77,8 +77,8 @@ struct sockaddr_any {
// copied from /usr/include/linux/un.h
struct my_sockaddr_un {
sa_family_t sun_family;
-#ifdef __ARM_EABI__
- // on ARM char is by default unsigned
+#if defined(__ARM_EABI__) || defined(__powerpc64__)
+ // on ARM and PPC char is by default unsigned
signed char sun_path[108];
#else
char sun_path[108];
@@ -87,6 +87,8 @@ struct my_sockaddr_un {
#ifdef __ARM_EABI__
typedef struct user_regs PtraceRegs;
+#elif defined(__powerpc64__)
+typedef struct pt_regs PtraceRegs;
#else
typedef struct user_regs_struct PtraceRegs;
#endif
@@ -382,103 +384,9 @@ const (
type Termios C.struct_termios
const (
- VINTR = C.VINTR
- VQUIT = C.VQUIT
- VERASE = C.VERASE
- VKILL = C.VKILL
- VEOF = C.VEOF
- VTIME = C.VTIME
- VMIN = C.VMIN
- VSWTC = C.VSWTC
- VSTART = C.VSTART
- VSTOP = C.VSTOP
- VSUSP = C.VSUSP
- VEOL = C.VEOL
- VREPRINT = C.VREPRINT
- VDISCARD = C.VDISCARD
- VWERASE = C.VWERASE
- VLNEXT = C.VLNEXT
- VEOL2 = C.VEOL2
- IGNBRK = C.IGNBRK
- BRKINT = C.BRKINT
- IGNPAR = C.IGNPAR
- PARMRK = C.PARMRK
- INPCK = C.INPCK
- ISTRIP = C.ISTRIP
- INLCR = C.INLCR
- IGNCR = C.IGNCR
- ICRNL = C.ICRNL
- IUCLC = C.IUCLC
- IXON = C.IXON
- IXANY = C.IXANY
- IXOFF = C.IXOFF
- IMAXBEL = C.IMAXBEL
- IUTF8 = C.IUTF8
- OPOST = C.OPOST
- OLCUC = C.OLCUC
- ONLCR = C.ONLCR
- OCRNL = C.OCRNL
- ONOCR = C.ONOCR
- ONLRET = C.ONLRET
- OFILL = C.OFILL
- OFDEL = C.OFDEL
- B0 = C.B0
- B50 = C.B50
- B75 = C.B75
- B110 = C.B110
- B134 = C.B134
- B150 = C.B150
- B200 = C.B200
- B300 = C.B300
- B600 = C.B600
- B1200 = C.B1200
- B1800 = C.B1800
- B2400 = C.B2400
- B4800 = C.B4800
- B9600 = C.B9600
- B19200 = C.B19200
- B38400 = C.B38400
- CSIZE = C.CSIZE
- CS5 = C.CS5
- CS6 = C.CS6
- CS7 = C.CS7
- CS8 = C.CS8
- CSTOPB = C.CSTOPB
- CREAD = C.CREAD
- PARENB = C.PARENB
- PARODD = C.PARODD
- HUPCL = C.HUPCL
- CLOCAL = C.CLOCAL
- B57600 = C.B57600
- B115200 = C.B115200
- B230400 = C.B230400
- B460800 = C.B460800
- B500000 = C.B500000
- B576000 = C.B576000
- B921600 = C.B921600
- B1000000 = C.B1000000
- B1152000 = C.B1152000
- B1500000 = C.B1500000
- B2000000 = C.B2000000
- B2500000 = C.B2500000
- B3000000 = C.B3000000
- B3500000 = C.B3500000
- B4000000 = C.B4000000
- ISIG = C.ISIG
- ICANON = C.ICANON
- XCASE = C.XCASE
- ECHO = C.ECHO
- ECHOE = C.ECHOE
- ECHOK = C.ECHOK
- ECHONL = C.ECHONL
- NOFLSH = C.NOFLSH
- TOSTOP = C.TOSTOP
- ECHOCTL = C.ECHOCTL
- ECHOPRT = C.ECHOPRT
- ECHOKE = C.ECHOKE
- FLUSHO = C.FLUSHO
- PENDIN = C.PENDIN
- IEXTEN = C.IEXTEN
- TCGETS = C.TCGETS
- TCSETS = C.TCSETS
+ IUCLC = C.IUCLC
+ OLCUC = C.OLCUC
+ TCGETS = C.TCGETS
+ TCSETS = C.TCSETS
+ XCASE = C.XCASE
)
diff --git a/src/syscall/zerrors_linux_power64.go b/src/syscall/zerrors_linux_power64.go
new file mode 100644
index 000000000..15e0770c1
--- /dev/null
+++ b/src/syscall/zerrors_linux_power64.go
@@ -0,0 +1,1878 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+package syscall
+
+const (
+ AF_ALG = 0x26
+ AF_APPLETALK = 0x5
+ AF_ASH = 0x12
+ AF_ATMPVC = 0x8
+ AF_ATMSVC = 0x14
+ AF_AX25 = 0x3
+ AF_BLUETOOTH = 0x1f
+ AF_BRIDGE = 0x7
+ AF_CAIF = 0x25
+ AF_CAN = 0x1d
+ AF_DECnet = 0xc
+ AF_ECONET = 0x13
+ AF_FILE = 0x1
+ AF_IEEE802154 = 0x24
+ AF_INET = 0x2
+ AF_INET6 = 0xa
+ AF_IPX = 0x4
+ AF_IRDA = 0x17
+ AF_ISDN = 0x22
+ AF_IUCV = 0x20
+ AF_KEY = 0xf
+ AF_LLC = 0x1a
+ AF_LOCAL = 0x1
+ AF_MAX = 0x28
+ AF_NETBEUI = 0xd
+ AF_NETLINK = 0x10
+ AF_NETROM = 0x6
+ AF_NFC = 0x27
+ AF_PACKET = 0x11
+ AF_PHONET = 0x23
+ AF_PPPOX = 0x18
+ AF_RDS = 0x15
+ AF_ROSE = 0xb
+ AF_ROUTE = 0x10
+ AF_RXRPC = 0x21
+ AF_SECURITY = 0xe
+ AF_SNA = 0x16
+ AF_TIPC = 0x1e
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ AF_WANPIPE = 0x19
+ AF_X25 = 0x9
+ ARPHRD_ADAPT = 0x108
+ ARPHRD_APPLETLK = 0x8
+ ARPHRD_ARCNET = 0x7
+ ARPHRD_ASH = 0x30d
+ ARPHRD_ATM = 0x13
+ ARPHRD_AX25 = 0x3
+ ARPHRD_BIF = 0x307
+ ARPHRD_CAIF = 0x336
+ ARPHRD_CAN = 0x118
+ ARPHRD_CHAOS = 0x5
+ ARPHRD_CISCO = 0x201
+ ARPHRD_CSLIP = 0x101
+ ARPHRD_CSLIP6 = 0x103
+ ARPHRD_DDCMP = 0x205
+ ARPHRD_DLCI = 0xf
+ ARPHRD_ECONET = 0x30e
+ ARPHRD_EETHER = 0x2
+ ARPHRD_ETHER = 0x1
+ ARPHRD_EUI64 = 0x1b
+ ARPHRD_FCAL = 0x311
+ ARPHRD_FCFABRIC = 0x313
+ ARPHRD_FCPL = 0x312
+ ARPHRD_FCPP = 0x310
+ ARPHRD_FDDI = 0x306
+ ARPHRD_FRAD = 0x302
+ ARPHRD_HDLC = 0x201
+ ARPHRD_HIPPI = 0x30c
+ ARPHRD_HWX25 = 0x110
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ ARPHRD_IEEE80211 = 0x321
+ ARPHRD_IEEE80211_PRISM = 0x322
+ ARPHRD_IEEE80211_RADIOTAP = 0x323
+ ARPHRD_IEEE802154 = 0x324
+ ARPHRD_IEEE802154_MONITOR = 0x325
+ ARPHRD_IEEE802_TR = 0x320
+ ARPHRD_INFINIBAND = 0x20
+ ARPHRD_IP6GRE = 0x337
+ ARPHRD_IPDDP = 0x309
+ ARPHRD_IPGRE = 0x30a
+ ARPHRD_IRDA = 0x30f
+ ARPHRD_LAPB = 0x204
+ ARPHRD_LOCALTLK = 0x305
+ ARPHRD_LOOPBACK = 0x304
+ ARPHRD_METRICOM = 0x17
+ ARPHRD_NETLINK = 0x338
+ ARPHRD_NETROM = 0x0
+ ARPHRD_NONE = 0xfffe
+ ARPHRD_PHONET = 0x334
+ ARPHRD_PHONET_PIPE = 0x335
+ ARPHRD_PIMREG = 0x30b
+ ARPHRD_PPP = 0x200
+ ARPHRD_PRONET = 0x4
+ ARPHRD_RAWHDLC = 0x206
+ ARPHRD_ROSE = 0x10e
+ ARPHRD_RSRVD = 0x104
+ ARPHRD_SIT = 0x308
+ ARPHRD_SKIP = 0x303
+ ARPHRD_SLIP = 0x100
+ ARPHRD_SLIP6 = 0x102
+ ARPHRD_TUNNEL = 0x300
+ ARPHRD_TUNNEL6 = 0x301
+ ARPHRD_VOID = 0xffff
+ ARPHRD_X25 = 0x10f
+ B0 = 0x0
+ B1000000 = 0x17
+ B110 = 0x3
+ B115200 = 0x11
+ B1152000 = 0x18
+ B1200 = 0x9
+ B134 = 0x4
+ B150 = 0x5
+ B1500000 = 0x19
+ B1800 = 0xa
+ B19200 = 0xe
+ B200 = 0x6
+ B2000000 = 0x1a
+ B230400 = 0x12
+ B2400 = 0xb
+ B2500000 = 0x1b
+ B300 = 0x7
+ B3000000 = 0x1c
+ B3500000 = 0x1d
+ B38400 = 0xf
+ B4000000 = 0x1e
+ B460800 = 0x13
+ B4800 = 0xc
+ B50 = 0x1
+ B500000 = 0x14
+ B57600 = 0x10
+ B576000 = 0x15
+ B600 = 0x8
+ B75 = 0x2
+ B921600 = 0x16
+ B9600 = 0xd
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXINSNS = 0x1000
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MOD = 0x90
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ BPF_XOR = 0xa0
+ BRKINT = 0x2
+ CFLUSH = 0xf
+ CLOCAL = 0x8000
+ CLONE_CHILD_CLEARTID = 0x200000
+ CLONE_CHILD_SETTID = 0x1000000
+ CLONE_DETACHED = 0x400000
+ CLONE_FILES = 0x400
+ CLONE_FS = 0x200
+ CLONE_IO = 0x80000000
+ CLONE_NEWIPC = 0x8000000
+ CLONE_NEWNET = 0x40000000
+ CLONE_NEWNS = 0x20000
+ CLONE_NEWPID = 0x20000000
+ CLONE_NEWUSER = 0x10000000
+ CLONE_NEWUTS = 0x4000000
+ CLONE_PARENT = 0x8000
+ CLONE_PARENT_SETTID = 0x100000
+ CLONE_PTRACE = 0x2000
+ CLONE_SETTLS = 0x80000
+ CLONE_SIGHAND = 0x800
+ CLONE_SYSVSEM = 0x40000
+ CLONE_THREAD = 0x10000
+ CLONE_UNTRACED = 0x800000
+ CLONE_VFORK = 0x4000
+ CLONE_VM = 0x100
+ CREAD = 0x800
+ CS5 = 0x0
+ CS6 = 0x100
+ CS7 = 0x200
+ CS8 = 0x300
+ CSIGNAL = 0xff
+ CSIZE = 0x300
+ CSTART = 0x11
+ CSTATUS = 0x0
+ CSTOP = 0x13
+ CSTOPB = 0x400
+ CSUSP = 0x1a
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ DT_WHT = 0xe
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ ENCODING_DEFAULT = 0x0
+ ENCODING_FM_MARK = 0x3
+ ENCODING_FM_SPACE = 0x4
+ ENCODING_MANCHESTER = 0x5
+ ENCODING_NRZ = 0x1
+ ENCODING_NRZI = 0x2
+ EPOLLERR = 0x8
+ EPOLLET = 0x80000000
+ EPOLLHUP = 0x10
+ EPOLLIN = 0x1
+ EPOLLMSG = 0x400
+ EPOLLONESHOT = 0x40000000
+ EPOLLOUT = 0x4
+ EPOLLPRI = 0x2
+ EPOLLRDBAND = 0x80
+ EPOLLRDHUP = 0x2000
+ EPOLLRDNORM = 0x40
+ EPOLLWAKEUP = 0x20000000
+ EPOLLWRBAND = 0x200
+ EPOLLWRNORM = 0x100
+ EPOLL_CLOEXEC = 0x80000
+ EPOLL_CTL_ADD = 0x1
+ EPOLL_CTL_DEL = 0x2
+ EPOLL_CTL_MOD = 0x3
+ EPOLL_NONBLOCK = 0x800
+ ETH_P_1588 = 0x88f7
+ ETH_P_8021AD = 0x88a8
+ ETH_P_8021AH = 0x88e7
+ ETH_P_8021Q = 0x8100
+ ETH_P_802_2 = 0x4
+ ETH_P_802_3 = 0x1
+ ETH_P_802_3_MIN = 0x600
+ ETH_P_802_EX1 = 0x88b5
+ ETH_P_AARP = 0x80f3
+ ETH_P_AF_IUCV = 0xfbfb
+ ETH_P_ALL = 0x3
+ ETH_P_AOE = 0x88a2
+ ETH_P_ARCNET = 0x1a
+ ETH_P_ARP = 0x806
+ ETH_P_ATALK = 0x809b
+ ETH_P_ATMFATE = 0x8884
+ ETH_P_ATMMPOA = 0x884c
+ ETH_P_AX25 = 0x2
+ ETH_P_BATMAN = 0x4305
+ ETH_P_BPQ = 0x8ff
+ ETH_P_CAIF = 0xf7
+ ETH_P_CAN = 0xc
+ ETH_P_CANFD = 0xd
+ ETH_P_CONTROL = 0x16
+ ETH_P_CUST = 0x6006
+ ETH_P_DDCMP = 0x6
+ ETH_P_DEC = 0x6000
+ ETH_P_DIAG = 0x6005
+ ETH_P_DNA_DL = 0x6001
+ ETH_P_DNA_RC = 0x6002
+ ETH_P_DNA_RT = 0x6003
+ ETH_P_DSA = 0x1b
+ ETH_P_ECONET = 0x18
+ ETH_P_EDSA = 0xdada
+ ETH_P_FCOE = 0x8906
+ ETH_P_FIP = 0x8914
+ ETH_P_HDLC = 0x19
+ ETH_P_IEEE802154 = 0xf6
+ ETH_P_IEEEPUP = 0xa00
+ ETH_P_IEEEPUPAT = 0xa01
+ ETH_P_IP = 0x800
+ ETH_P_IPV6 = 0x86dd
+ ETH_P_IPX = 0x8137
+ ETH_P_IRDA = 0x17
+ ETH_P_LAT = 0x6004
+ ETH_P_LINK_CTL = 0x886c
+ ETH_P_LOCALTALK = 0x9
+ ETH_P_LOOP = 0x60
+ ETH_P_MOBITEX = 0x15
+ ETH_P_MPLS_MC = 0x8848
+ ETH_P_MPLS_UC = 0x8847
+ ETH_P_MVRP = 0x88f5
+ ETH_P_PAE = 0x888e
+ ETH_P_PAUSE = 0x8808
+ ETH_P_PHONET = 0xf5
+ ETH_P_PPPTALK = 0x10
+ ETH_P_PPP_DISC = 0x8863
+ ETH_P_PPP_MP = 0x8
+ ETH_P_PPP_SES = 0x8864
+ ETH_P_PRP = 0x88fb
+ ETH_P_PUP = 0x200
+ ETH_P_PUPAT = 0x201
+ ETH_P_QINQ1 = 0x9100
+ ETH_P_QINQ2 = 0x9200
+ ETH_P_QINQ3 = 0x9300
+ ETH_P_RARP = 0x8035
+ ETH_P_SCA = 0x6007
+ ETH_P_SLOW = 0x8809
+ ETH_P_SNAP = 0x5
+ ETH_P_TDLS = 0x890d
+ ETH_P_TEB = 0x6558
+ ETH_P_TIPC = 0x88ca
+ ETH_P_TRAILER = 0x1c
+ ETH_P_TR_802_2 = 0x11
+ ETH_P_WAN_PPP = 0x7
+ ETH_P_WCCP = 0x883e
+ ETH_P_X25 = 0x805
+ EXTA = 0xe
+ EXTB = 0xf
+ EXTPROC = 0x10000000
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ FLUSHO = 0x800000
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x406
+ F_EXLCK = 0x4
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLEASE = 0x401
+ F_GETLK = 0x5
+ F_GETLK64 = 0xc
+ F_GETOWN = 0x9
+ F_GETOWN_EX = 0x10
+ F_GETPIPE_SZ = 0x408
+ F_GETSIG = 0xb
+ F_LOCK = 0x1
+ F_NOTIFY = 0x402
+ F_OK = 0x0
+ F_RDLCK = 0x0
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLEASE = 0x400
+ F_SETLK = 0xd
+ F_SETLK64 = 0xd
+ F_SETLKW = 0xe
+ F_SETLKW64 = 0xe
+ F_SETOWN = 0x8
+ F_SETOWN_EX = 0xf
+ F_SETPIPE_SZ = 0x407
+ F_SETSIG = 0xa
+ F_SHLCK = 0x8
+ F_TEST = 0x3
+ F_TLOCK = 0x2
+ F_ULOCK = 0x0
+ F_UNLCK = 0x2
+ F_WRLCK = 0x1
+ HUPCL = 0x4000
+ ICANON = 0x100
+ ICMPV6_FILTER = 0x1
+ ICRNL = 0x100
+ IEXTEN = 0x400
+ IFA_F_DADFAILED = 0x8
+ IFA_F_DEPRECATED = 0x20
+ IFA_F_HOMEADDRESS = 0x10
+ IFA_F_NODAD = 0x2
+ IFA_F_OPTIMISTIC = 0x4
+ IFA_F_PERMANENT = 0x80
+ IFA_F_SECONDARY = 0x1
+ IFA_F_TEMPORARY = 0x1
+ IFA_F_TENTATIVE = 0x40
+ IFA_MAX = 0x7
+ IFF_802_1Q_VLAN = 0x1
+ IFF_ALLMULTI = 0x200
+ IFF_ATTACH_QUEUE = 0x200
+ IFF_AUTOMEDIA = 0x4000
+ IFF_BONDING = 0x20
+ IFF_BRIDGE_PORT = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_DETACH_QUEUE = 0x400
+ IFF_DISABLE_NETPOLL = 0x1000
+ IFF_DONT_BRIDGE = 0x800
+ IFF_DORMANT = 0x20000
+ IFF_DYNAMIC = 0x8000
+ IFF_EBRIDGE = 0x2
+ IFF_ECHO = 0x40000
+ IFF_ISATAP = 0x80
+ IFF_LIVE_ADDR_CHANGE = 0x100000
+ IFF_LOOPBACK = 0x8
+ IFF_LOWER_UP = 0x10000
+ IFF_MACVLAN = 0x200000
+ IFF_MACVLAN_PORT = 0x2000
+ IFF_MASTER = 0x400
+ IFF_MASTER_8023AD = 0x8
+ IFF_MASTER_ALB = 0x10
+ IFF_MASTER_ARPMON = 0x100
+ IFF_MULTICAST = 0x1000
+ IFF_MULTI_QUEUE = 0x100
+ IFF_NOARP = 0x80
+ IFF_NOFILTER = 0x1000
+ IFF_NOTRAILERS = 0x20
+ IFF_NO_PI = 0x1000
+ IFF_ONE_QUEUE = 0x2000
+ IFF_OVS_DATAPATH = 0x8000
+ IFF_PERSIST = 0x800
+ IFF_POINTOPOINT = 0x10
+ IFF_PORTSEL = 0x2000
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SLAVE = 0x800
+ IFF_SLAVE_INACTIVE = 0x4
+ IFF_SLAVE_NEEDARP = 0x40
+ IFF_SUPP_NOFCS = 0x80000
+ IFF_TAP = 0x2
+ IFF_TEAM_PORT = 0x40000
+ IFF_TUN = 0x1
+ IFF_TUN_EXCL = 0x8000
+ IFF_TX_SKB_SHARING = 0x10000
+ IFF_UNICAST_FLT = 0x20000
+ IFF_UP = 0x1
+ IFF_VNET_HDR = 0x4000
+ IFF_VOLATILE = 0x70c5a
+ IFF_WAN_HDLC = 0x200
+ IFF_XMIT_DST_RELEASE = 0x400
+ IFNAMSIZ = 0x10
+ IGNBRK = 0x1
+ IGNCR = 0x80
+ IGNPAR = 0x4
+ IMAXBEL = 0x2000
+ INLCR = 0x40
+ INPCK = 0x10
+ IN_ACCESS = 0x1
+ IN_ALL_EVENTS = 0xfff
+ IN_ATTRIB = 0x4
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLOEXEC = 0x80000
+ IN_CLOSE = 0x18
+ IN_CLOSE_NOWRITE = 0x10
+ IN_CLOSE_WRITE = 0x8
+ IN_CREATE = 0x100
+ IN_DELETE = 0x200
+ IN_DELETE_SELF = 0x400
+ IN_DONT_FOLLOW = 0x2000000
+ IN_EXCL_UNLINK = 0x4000000
+ IN_IGNORED = 0x8000
+ IN_ISDIR = 0x40000000
+ IN_LOOPBACKNET = 0x7f
+ IN_MASK_ADD = 0x20000000
+ IN_MODIFY = 0x2
+ IN_MOVE = 0xc0
+ IN_MOVED_FROM = 0x40
+ IN_MOVED_TO = 0x80
+ IN_MOVE_SELF = 0x800
+ IN_NONBLOCK = 0x800
+ IN_ONESHOT = 0x80000000
+ IN_ONLYDIR = 0x1000000
+ IN_OPEN = 0x20
+ IN_Q_OVERFLOW = 0x4000
+ IN_UNMOUNT = 0x2000
+ IPPROTO_AH = 0x33
+ IPPROTO_COMP = 0x6c
+ IPPROTO_DCCP = 0x21
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_ESP = 0x32
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MTP = 0x5c
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_SCTP = 0x84
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_UDP = 0x11
+ IPPROTO_UDPLITE = 0x88
+ IPV6_2292DSTOPTS = 0x4
+ IPV6_2292HOPLIMIT = 0x8
+ IPV6_2292HOPOPTS = 0x3
+ IPV6_2292PKTINFO = 0x2
+ IPV6_2292PKTOPTIONS = 0x6
+ IPV6_2292RTHDR = 0x5
+ IPV6_ADDRFORM = 0x1
+ IPV6_ADD_MEMBERSHIP = 0x14
+ IPV6_AUTHHDR = 0xa
+ IPV6_CHECKSUM = 0x7
+ IPV6_DROP_MEMBERSHIP = 0x15
+ IPV6_DSTOPTS = 0x3b
+ IPV6_HOPLIMIT = 0x34
+ IPV6_HOPOPTS = 0x36
+ IPV6_IPSEC_POLICY = 0x22
+ IPV6_JOIN_ANYCAST = 0x1b
+ IPV6_JOIN_GROUP = 0x14
+ IPV6_LEAVE_ANYCAST = 0x1c
+ IPV6_LEAVE_GROUP = 0x15
+ IPV6_MTU = 0x18
+ IPV6_MTU_DISCOVER = 0x17
+ IPV6_MULTICAST_HOPS = 0x12
+ IPV6_MULTICAST_IF = 0x11
+ IPV6_MULTICAST_LOOP = 0x13
+ IPV6_NEXTHOP = 0x9
+ IPV6_PKTINFO = 0x32
+ IPV6_PMTUDISC_DO = 0x2
+ IPV6_PMTUDISC_DONT = 0x0
+ IPV6_PMTUDISC_PROBE = 0x3
+ IPV6_PMTUDISC_WANT = 0x1
+ IPV6_RECVDSTOPTS = 0x3a
+ IPV6_RECVERR = 0x19
+ IPV6_RECVHOPLIMIT = 0x33
+ IPV6_RECVHOPOPTS = 0x35
+ IPV6_RECVPKTINFO = 0x31
+ IPV6_RECVRTHDR = 0x38
+ IPV6_RECVTCLASS = 0x42
+ IPV6_ROUTER_ALERT = 0x16
+ IPV6_RTHDR = 0x39
+ IPV6_RTHDRDSTOPTS = 0x37
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_RXDSTOPTS = 0x3b
+ IPV6_RXHOPOPTS = 0x36
+ IPV6_TCLASS = 0x43
+ IPV6_UNICAST_HOPS = 0x10
+ IPV6_V6ONLY = 0x1a
+ IPV6_XFRM_POLICY = 0x23
+ IP_ADD_MEMBERSHIP = 0x23
+ IP_ADD_SOURCE_MEMBERSHIP = 0x27
+ IP_BLOCK_SOURCE = 0x26
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0x24
+ IP_DROP_SOURCE_MEMBERSHIP = 0x28
+ IP_FREEBIND = 0xf
+ IP_HDRINCL = 0x3
+ IP_IPSEC_POLICY = 0x10
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0x14
+ IP_MF = 0x2000
+ IP_MINTTL = 0x15
+ IP_MSFILTER = 0x29
+ IP_MSS = 0x240
+ IP_MTU = 0xe
+ IP_MTU_DISCOVER = 0xa
+ IP_MULTICAST_ALL = 0x31
+ IP_MULTICAST_IF = 0x20
+ IP_MULTICAST_LOOP = 0x22
+ IP_MULTICAST_TTL = 0x21
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x4
+ IP_ORIGDSTADDR = 0x14
+ IP_PASSSEC = 0x12
+ IP_PKTINFO = 0x8
+ IP_PKTOPTIONS = 0x9
+ IP_PMTUDISC = 0xa
+ IP_PMTUDISC_DO = 0x2
+ IP_PMTUDISC_DONT = 0x0
+ IP_PMTUDISC_PROBE = 0x3
+ IP_PMTUDISC_WANT = 0x1
+ IP_RECVERR = 0xb
+ IP_RECVOPTS = 0x6
+ IP_RECVORIGDSTADDR = 0x14
+ IP_RECVRETOPTS = 0x7
+ IP_RECVTOS = 0xd
+ IP_RECVTTL = 0xc
+ IP_RETOPTS = 0x7
+ IP_RF = 0x8000
+ IP_ROUTER_ALERT = 0x5
+ IP_TOS = 0x1
+ IP_TRANSPARENT = 0x13
+ IP_TTL = 0x2
+ IP_UNBLOCK_SOURCE = 0x25
+ IP_UNICAST_IF = 0x32
+ IP_XFRM_POLICY = 0x11
+ ISIG = 0x80
+ ISTRIP = 0x20
+ IUTF8 = 0x4000
+ IXANY = 0x800
+ IXOFF = 0x400
+ IXON = 0x200
+ LINUX_REBOOT_CMD_CAD_OFF = 0x0
+ LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
+ LINUX_REBOOT_CMD_HALT = 0xcdef0123
+ LINUX_REBOOT_CMD_KEXEC = 0x45584543
+ LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc
+ LINUX_REBOOT_CMD_RESTART = 0x1234567
+ LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4
+ LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2
+ LINUX_REBOOT_MAGIC1 = 0xfee1dead
+ LINUX_REBOOT_MAGIC2 = 0x28121969
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
+ MADV_DODUMP = 0x11
+ MADV_DOFORK = 0xb
+ MADV_DONTDUMP = 0x10
+ MADV_DONTFORK = 0xa
+ MADV_DONTNEED = 0x4
+ MADV_HUGEPAGE = 0xe
+ MADV_HWPOISON = 0x64
+ MADV_MERGEABLE = 0xc
+ MADV_NOHUGEPAGE = 0xf
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_REMOVE = 0x9
+ MADV_SEQUENTIAL = 0x2
+ MADV_UNMERGEABLE = 0xd
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x20
+ MAP_ANONYMOUS = 0x20
+ MAP_DENYWRITE = 0x800
+ MAP_EXECUTABLE = 0x1000
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_GROWSDOWN = 0x100
+ MAP_HUGETLB = 0x40000
+ MAP_LOCKED = 0x80
+ MAP_NONBLOCK = 0x10000
+ MAP_NORESERVE = 0x40
+ MAP_POPULATE = 0x8000
+ MAP_PRIVATE = 0x2
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x20000
+ MAP_TYPE = 0xf
+ MCL_CURRENT = 0x2000
+ MCL_FUTURE = 0x4000
+ MNT_DETACH = 0x2
+ MNT_EXPIRE = 0x4
+ MNT_FORCE = 0x1
+ MSG_CMSG_CLOEXEC = 0x40000000
+ MSG_CONFIRM = 0x800
+ MSG_CTRUNC = 0x8
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x40
+ MSG_EOR = 0x80
+ MSG_ERRQUEUE = 0x2000
+ MSG_FASTOPEN = 0x20000000
+ MSG_FIN = 0x200
+ MSG_MORE = 0x8000
+ MSG_NOSIGNAL = 0x4000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_PROXY = 0x10
+ MSG_RST = 0x1000
+ MSG_SYN = 0x400
+ MSG_TRUNC = 0x20
+ MSG_TRYHARD = 0x4
+ MSG_WAITALL = 0x100
+ MSG_WAITFORONE = 0x10000
+ MS_ACTIVE = 0x40000000
+ MS_ASYNC = 0x1
+ MS_BIND = 0x1000
+ MS_DIRSYNC = 0x80
+ MS_INVALIDATE = 0x2
+ MS_I_VERSION = 0x800000
+ MS_KERNMOUNT = 0x400000
+ MS_MANDLOCK = 0x40
+ MS_MGC_MSK = 0xffff0000
+ MS_MGC_VAL = 0xc0ed0000
+ MS_MOVE = 0x2000
+ MS_NOATIME = 0x400
+ MS_NODEV = 0x4
+ MS_NODIRATIME = 0x800
+ MS_NOEXEC = 0x8
+ MS_NOSUID = 0x2
+ MS_NOUSER = -0x80000000
+ MS_POSIXACL = 0x10000
+ MS_PRIVATE = 0x40000
+ MS_RDONLY = 0x1
+ MS_REC = 0x4000
+ MS_RELATIME = 0x200000
+ MS_REMOUNT = 0x20
+ MS_RMT_MASK = 0x800051
+ MS_SHARED = 0x100000
+ MS_SILENT = 0x8000
+ MS_SLAVE = 0x80000
+ MS_STRICTATIME = 0x1000000
+ MS_SYNC = 0x4
+ MS_SYNCHRONOUS = 0x10
+ MS_UNBINDABLE = 0x20000
+ NAME_MAX = 0xff
+ NETLINK_ADD_MEMBERSHIP = 0x1
+ NETLINK_AUDIT = 0x9
+ NETLINK_BROADCAST_ERROR = 0x4
+ NETLINK_CONNECTOR = 0xb
+ NETLINK_CRYPTO = 0x15
+ NETLINK_DNRTMSG = 0xe
+ NETLINK_DROP_MEMBERSHIP = 0x2
+ NETLINK_ECRYPTFS = 0x13
+ NETLINK_FIB_LOOKUP = 0xa
+ NETLINK_FIREWALL = 0x3
+ NETLINK_GENERIC = 0x10
+ NETLINK_INET_DIAG = 0x4
+ NETLINK_IP6_FW = 0xd
+ NETLINK_ISCSI = 0x8
+ NETLINK_KOBJECT_UEVENT = 0xf
+ NETLINK_NETFILTER = 0xc
+ NETLINK_NFLOG = 0x5
+ NETLINK_NO_ENOBUFS = 0x5
+ NETLINK_PKTINFO = 0x3
+ NETLINK_RDMA = 0x14
+ NETLINK_ROUTE = 0x0
+ NETLINK_RX_RING = 0x6
+ NETLINK_SCSITRANSPORT = 0x12
+ NETLINK_SELINUX = 0x7
+ NETLINK_SOCK_DIAG = 0x4
+ NETLINK_TX_RING = 0x7
+ NETLINK_UNUSED = 0x1
+ NETLINK_USERSOCK = 0x2
+ NETLINK_XFRM = 0x6
+ NLA_ALIGNTO = 0x4
+ NLA_F_NESTED = 0x8000
+ NLA_F_NET_BYTEORDER = 0x4000
+ NLA_HDRLEN = 0x4
+ NLMSG_ALIGNTO = 0x4
+ NLMSG_DONE = 0x3
+ NLMSG_ERROR = 0x2
+ NLMSG_HDRLEN = 0x10
+ NLMSG_MIN_TYPE = 0x10
+ NLMSG_NOOP = 0x1
+ NLMSG_OVERRUN = 0x4
+ NLM_F_ACK = 0x4
+ NLM_F_APPEND = 0x800
+ NLM_F_ATOMIC = 0x400
+ NLM_F_CREATE = 0x400
+ NLM_F_DUMP = 0x300
+ NLM_F_DUMP_INTR = 0x10
+ NLM_F_ECHO = 0x8
+ NLM_F_EXCL = 0x200
+ NLM_F_MATCH = 0x200
+ NLM_F_MULTI = 0x2
+ NLM_F_REPLACE = 0x100
+ NLM_F_REQUEST = 0x1
+ NLM_F_ROOT = 0x100
+ NOFLSH = 0x80000000
+ OCRNL = 0x8
+ OFDEL = 0x80
+ OFILL = 0x40
+ ONLCR = 0x2
+ ONLRET = 0x20
+ ONOCR = 0x10
+ OPOST = 0x1
+ O_ACCMODE = 0x3
+ O_APPEND = 0x400
+ O_ASYNC = 0x2000
+ O_CLOEXEC = 0x80000
+ O_CREAT = 0x40
+ O_DIRECT = 0x20000
+ O_DIRECTORY = 0x4000
+ O_DSYNC = 0x1000
+ O_EXCL = 0x80
+ O_FSYNC = 0x101000
+ O_LARGEFILE = 0x0
+ O_NDELAY = 0x800
+ O_NOATIME = 0x40000
+ O_NOCTTY = 0x100
+ O_NOFOLLOW = 0x8000
+ O_NONBLOCK = 0x800
+ O_PATH = 0x200000
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSYNC = 0x101000
+ O_SYNC = 0x101000
+ O_TRUNC = 0x200
+ O_WRONLY = 0x1
+ PACKET_ADD_MEMBERSHIP = 0x1
+ PACKET_AUXDATA = 0x8
+ PACKET_BROADCAST = 0x1
+ PACKET_COPY_THRESH = 0x7
+ PACKET_DROP_MEMBERSHIP = 0x2
+ PACKET_FANOUT = 0x12
+ PACKET_FANOUT_CPU = 0x2
+ PACKET_FANOUT_FLAG_DEFRAG = 0x8000
+ PACKET_FANOUT_FLAG_ROLLOVER = 0x1000
+ PACKET_FANOUT_HASH = 0x0
+ PACKET_FANOUT_LB = 0x1
+ PACKET_FANOUT_RND = 0x4
+ PACKET_FANOUT_ROLLOVER = 0x3
+ PACKET_FASTROUTE = 0x6
+ PACKET_HDRLEN = 0xb
+ PACKET_HOST = 0x0
+ PACKET_LOOPBACK = 0x5
+ PACKET_LOSS = 0xe
+ PACKET_MR_ALLMULTI = 0x2
+ PACKET_MR_MULTICAST = 0x0
+ PACKET_MR_PROMISC = 0x1
+ PACKET_MR_UNICAST = 0x3
+ PACKET_MULTICAST = 0x2
+ PACKET_ORIGDEV = 0x9
+ PACKET_OTHERHOST = 0x3
+ PACKET_OUTGOING = 0x4
+ PACKET_RECV_OUTPUT = 0x3
+ PACKET_RESERVE = 0xc
+ PACKET_RX_RING = 0x5
+ PACKET_STATISTICS = 0x6
+ PACKET_TIMESTAMP = 0x11
+ PACKET_TX_HAS_OFF = 0x13
+ PACKET_TX_RING = 0xd
+ PACKET_TX_TIMESTAMP = 0x10
+ PACKET_VERSION = 0xa
+ PACKET_VNET_HDR = 0xf
+ PARENB = 0x1000
+ PARITY_CRC16_PR0 = 0x2
+ PARITY_CRC16_PR0_CCITT = 0x4
+ PARITY_CRC16_PR1 = 0x3
+ PARITY_CRC16_PR1_CCITT = 0x5
+ PARITY_CRC32_PR0_CCITT = 0x6
+ PARITY_CRC32_PR1_CCITT = 0x7
+ PARITY_DEFAULT = 0x0
+ PARITY_NONE = 0x1
+ PARMRK = 0x8
+ PARODD = 0x2000
+ PENDIN = 0x20000000
+ PRIO_PGRP = 0x1
+ PRIO_PROCESS = 0x0
+ PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_GROWSDOWN = 0x1000000
+ PROT_GROWSUP = 0x2000000
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_SAO = 0x10
+ PROT_WRITE = 0x2
+ PR_CAPBSET_DROP = 0x18
+ PR_CAPBSET_READ = 0x17
+ PR_ENDIAN_BIG = 0x0
+ PR_ENDIAN_LITTLE = 0x1
+ PR_ENDIAN_PPC_LITTLE = 0x2
+ PR_FPEMU_NOPRINT = 0x1
+ PR_FPEMU_SIGFPE = 0x2
+ PR_FP_EXC_ASYNC = 0x2
+ PR_FP_EXC_DISABLED = 0x0
+ PR_FP_EXC_DIV = 0x10000
+ PR_FP_EXC_INV = 0x100000
+ PR_FP_EXC_NONRECOV = 0x1
+ PR_FP_EXC_OVF = 0x20000
+ PR_FP_EXC_PRECISE = 0x3
+ PR_FP_EXC_RES = 0x80000
+ PR_FP_EXC_SW_ENABLE = 0x80
+ PR_FP_EXC_UND = 0x40000
+ PR_GET_CHILD_SUBREAPER = 0x25
+ PR_GET_DUMPABLE = 0x3
+ PR_GET_ENDIAN = 0x13
+ PR_GET_FPEMU = 0x9
+ PR_GET_FPEXC = 0xb
+ PR_GET_KEEPCAPS = 0x7
+ PR_GET_NAME = 0x10
+ PR_GET_NO_NEW_PRIVS = 0x27
+ PR_GET_PDEATHSIG = 0x2
+ PR_GET_SECCOMP = 0x15
+ PR_GET_SECUREBITS = 0x1b
+ PR_GET_TID_ADDRESS = 0x28
+ PR_GET_TIMERSLACK = 0x1e
+ PR_GET_TIMING = 0xd
+ PR_GET_TSC = 0x19
+ PR_GET_UNALIGN = 0x5
+ PR_MCE_KILL = 0x21
+ PR_MCE_KILL_CLEAR = 0x0
+ PR_MCE_KILL_DEFAULT = 0x2
+ PR_MCE_KILL_EARLY = 0x1
+ PR_MCE_KILL_GET = 0x22
+ PR_MCE_KILL_LATE = 0x0
+ PR_MCE_KILL_SET = 0x1
+ PR_SET_CHILD_SUBREAPER = 0x24
+ PR_SET_DUMPABLE = 0x4
+ PR_SET_ENDIAN = 0x14
+ PR_SET_FPEMU = 0xa
+ PR_SET_FPEXC = 0xc
+ PR_SET_KEEPCAPS = 0x8
+ PR_SET_MM = 0x23
+ PR_SET_MM_ARG_END = 0x9
+ PR_SET_MM_ARG_START = 0x8
+ PR_SET_MM_AUXV = 0xc
+ PR_SET_MM_BRK = 0x7
+ PR_SET_MM_END_CODE = 0x2
+ PR_SET_MM_END_DATA = 0x4
+ PR_SET_MM_ENV_END = 0xb
+ PR_SET_MM_ENV_START = 0xa
+ PR_SET_MM_EXE_FILE = 0xd
+ PR_SET_MM_START_BRK = 0x6
+ PR_SET_MM_START_CODE = 0x1
+ PR_SET_MM_START_DATA = 0x3
+ PR_SET_MM_START_STACK = 0x5
+ PR_SET_NAME = 0xf
+ PR_SET_NO_NEW_PRIVS = 0x26
+ PR_SET_PDEATHSIG = 0x1
+ PR_SET_PTRACER = 0x59616d61
+ PR_SET_PTRACER_ANY = -0x1
+ PR_SET_SECCOMP = 0x16
+ PR_SET_SECUREBITS = 0x1c
+ PR_SET_TIMERSLACK = 0x1d
+ PR_SET_TIMING = 0xe
+ PR_SET_TSC = 0x1a
+ PR_SET_UNALIGN = 0x6
+ PR_TASK_PERF_EVENTS_DISABLE = 0x1f
+ PR_TASK_PERF_EVENTS_ENABLE = 0x20
+ PR_TIMING_STATISTICAL = 0x0
+ PR_TIMING_TIMESTAMP = 0x1
+ PR_TSC_ENABLE = 0x1
+ PR_TSC_SIGSEGV = 0x2
+ PR_UNALIGN_NOPRINT = 0x1
+ PR_UNALIGN_SIGBUS = 0x2
+ PTRACE_ATTACH = 0x10
+ PTRACE_CONT = 0x7
+ PTRACE_DETACH = 0x11
+ PTRACE_EVENT_CLONE = 0x3
+ PTRACE_EVENT_EXEC = 0x4
+ PTRACE_EVENT_EXIT = 0x6
+ PTRACE_EVENT_FORK = 0x1
+ PTRACE_EVENT_SECCOMP = 0x7
+ PTRACE_EVENT_STOP = 0x80
+ PTRACE_EVENT_VFORK = 0x2
+ PTRACE_EVENT_VFORK_DONE = 0x5
+ PTRACE_GETEVENTMSG = 0x4201
+ PTRACE_GETEVRREGS = 0x14
+ PTRACE_GETFPREGS = 0xe
+ PTRACE_GETREGS = 0xc
+ PTRACE_GETREGS64 = 0x16
+ PTRACE_GETREGSET = 0x4204
+ PTRACE_GETSIGINFO = 0x4202
+ PTRACE_GETSIGMASK = 0x420a
+ PTRACE_GETVRREGS = 0x12
+ PTRACE_GETVSRREGS = 0x1b
+ PTRACE_GET_DEBUGREG = 0x19
+ PTRACE_INTERRUPT = 0x4207
+ PTRACE_KILL = 0x8
+ PTRACE_LISTEN = 0x4208
+ PTRACE_O_EXITKILL = 0x100000
+ PTRACE_O_MASK = 0x1000ff
+ PTRACE_O_TRACECLONE = 0x8
+ PTRACE_O_TRACEEXEC = 0x10
+ PTRACE_O_TRACEEXIT = 0x40
+ PTRACE_O_TRACEFORK = 0x2
+ PTRACE_O_TRACESECCOMP = 0x80
+ PTRACE_O_TRACESYSGOOD = 0x1
+ PTRACE_O_TRACEVFORK = 0x4
+ PTRACE_O_TRACEVFORKDONE = 0x20
+ PTRACE_PEEKDATA = 0x2
+ PTRACE_PEEKSIGINFO = 0x4209
+ PTRACE_PEEKSIGINFO_SHARED = 0x1
+ PTRACE_PEEKTEXT = 0x1
+ PTRACE_PEEKUSR = 0x3
+ PTRACE_POKEDATA = 0x5
+ PTRACE_POKETEXT = 0x4
+ PTRACE_POKEUSR = 0x6
+ PTRACE_SEIZE = 0x4206
+ PTRACE_SETEVRREGS = 0x15
+ PTRACE_SETFPREGS = 0xf
+ PTRACE_SETOPTIONS = 0x4200
+ PTRACE_SETREGS = 0xd
+ PTRACE_SETREGS64 = 0x17
+ PTRACE_SETREGSET = 0x4205
+ PTRACE_SETSIGINFO = 0x4203
+ PTRACE_SETSIGMASK = 0x420b
+ PTRACE_SETVRREGS = 0x13
+ PTRACE_SETVSRREGS = 0x1c
+ PTRACE_SET_DEBUGREG = 0x1a
+ PTRACE_SINGLEBLOCK = 0x100
+ PTRACE_SINGLESTEP = 0x9
+ PTRACE_SYSCALL = 0x18
+ PTRACE_TRACEME = 0x0
+ PT_CCR = 0x26
+ PT_CTR = 0x23
+ PT_DAR = 0x29
+ PT_DSCR = 0x2c
+ PT_DSISR = 0x2a
+ PT_FPR0 = 0x30
+ PT_FPSCR = 0x50
+ PT_LNK = 0x24
+ PT_MSR = 0x21
+ PT_NIP = 0x20
+ PT_ORIG_R3 = 0x22
+ PT_R0 = 0x0
+ PT_R1 = 0x1
+ PT_R10 = 0xa
+ PT_R11 = 0xb
+ PT_R12 = 0xc
+ PT_R13 = 0xd
+ PT_R14 = 0xe
+ PT_R15 = 0xf
+ PT_R16 = 0x10
+ PT_R17 = 0x11
+ PT_R18 = 0x12
+ PT_R19 = 0x13
+ PT_R2 = 0x2
+ PT_R20 = 0x14
+ PT_R21 = 0x15
+ PT_R22 = 0x16
+ PT_R23 = 0x17
+ PT_R24 = 0x18
+ PT_R25 = 0x19
+ PT_R26 = 0x1a
+ PT_R27 = 0x1b
+ PT_R28 = 0x1c
+ PT_R29 = 0x1d
+ PT_R3 = 0x3
+ PT_R30 = 0x1e
+ PT_R31 = 0x1f
+ PT_R4 = 0x4
+ PT_R5 = 0x5
+ PT_R6 = 0x6
+ PT_R7 = 0x7
+ PT_R8 = 0x8
+ PT_R9 = 0x9
+ PT_REGS_COUNT = 0x2c
+ PT_RESULT = 0x2b
+ PT_SOFTE = 0x27
+ PT_TRAP = 0x28
+ PT_VR0 = 0x52
+ PT_VRSAVE = 0x94
+ PT_VSCR = 0x93
+ PT_VSR0 = 0x96
+ PT_VSR31 = 0xd4
+ PT_XER = 0x25
+ RLIMIT_AS = 0x9
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x7
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = -0x1
+ RTAX_ADVMSS = 0x8
+ RTAX_CWND = 0x7
+ RTAX_FEATURES = 0xc
+ RTAX_FEATURE_ALLFRAG = 0x8
+ RTAX_FEATURE_ECN = 0x1
+ RTAX_FEATURE_SACK = 0x2
+ RTAX_FEATURE_TIMESTAMP = 0x4
+ RTAX_HOPLIMIT = 0xa
+ RTAX_INITCWND = 0xb
+ RTAX_INITRWND = 0xe
+ RTAX_LOCK = 0x1
+ RTAX_MAX = 0xf
+ RTAX_MTU = 0x2
+ RTAX_QUICKACK = 0xf
+ RTAX_REORDERING = 0x9
+ RTAX_RTO_MIN = 0xd
+ RTAX_RTT = 0x4
+ RTAX_RTTVAR = 0x5
+ RTAX_SSTHRESH = 0x6
+ RTAX_UNSPEC = 0x0
+ RTAX_WINDOW = 0x3
+ RTA_ALIGNTO = 0x4
+ RTA_MAX = 0x11
+ RTCF_DIRECTSRC = 0x4000000
+ RTCF_DOREDIRECT = 0x1000000
+ RTCF_LOG = 0x2000000
+ RTCF_MASQ = 0x400000
+ RTCF_NAT = 0x800000
+ RTCF_VALVE = 0x200000
+ RTF_ADDRCLASSMASK = 0xf8000000
+ RTF_ADDRCONF = 0x40000
+ RTF_ALLONLINK = 0x20000
+ RTF_BROADCAST = 0x10000000
+ RTF_CACHE = 0x1000000
+ RTF_DEFAULT = 0x10000
+ RTF_DYNAMIC = 0x10
+ RTF_FLOW = 0x2000000
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_INTERFACE = 0x40000000
+ RTF_IRTT = 0x100
+ RTF_LINKRT = 0x100000
+ RTF_LOCAL = 0x80000000
+ RTF_MODIFIED = 0x20
+ RTF_MSS = 0x40
+ RTF_MTU = 0x40
+ RTF_MULTICAST = 0x20000000
+ RTF_NAT = 0x8000000
+ RTF_NOFORWARD = 0x1000
+ RTF_NONEXTHOP = 0x200000
+ RTF_NOPMTUDISC = 0x4000
+ RTF_POLICY = 0x4000000
+ RTF_REINSTATE = 0x8
+ RTF_REJECT = 0x200
+ RTF_STATIC = 0x400
+ RTF_THROW = 0x2000
+ RTF_UP = 0x1
+ RTF_WINDOW = 0x80
+ RTF_XRESOLVE = 0x800
+ RTM_BASE = 0x10
+ RTM_DELACTION = 0x31
+ RTM_DELADDR = 0x15
+ RTM_DELADDRLABEL = 0x49
+ RTM_DELLINK = 0x11
+ RTM_DELMDB = 0x55
+ RTM_DELNEIGH = 0x1d
+ RTM_DELQDISC = 0x25
+ RTM_DELROUTE = 0x19
+ RTM_DELRULE = 0x21
+ RTM_DELTCLASS = 0x29
+ RTM_DELTFILTER = 0x2d
+ RTM_F_CLONED = 0x200
+ RTM_F_EQUALIZE = 0x400
+ RTM_F_NOTIFY = 0x100
+ RTM_F_PREFIX = 0x800
+ RTM_GETACTION = 0x32
+ RTM_GETADDR = 0x16
+ RTM_GETADDRLABEL = 0x4a
+ RTM_GETANYCAST = 0x3e
+ RTM_GETDCB = 0x4e
+ RTM_GETLINK = 0x12
+ RTM_GETMDB = 0x56
+ RTM_GETMULTICAST = 0x3a
+ RTM_GETNEIGH = 0x1e
+ RTM_GETNEIGHTBL = 0x42
+ RTM_GETNETCONF = 0x52
+ RTM_GETQDISC = 0x26
+ RTM_GETROUTE = 0x1a
+ RTM_GETRULE = 0x22
+ RTM_GETTCLASS = 0x2a
+ RTM_GETTFILTER = 0x2e
+ RTM_MAX = 0x57
+ RTM_NEWACTION = 0x30
+ RTM_NEWADDR = 0x14
+ RTM_NEWADDRLABEL = 0x48
+ RTM_NEWLINK = 0x10
+ RTM_NEWMDB = 0x54
+ RTM_NEWNDUSEROPT = 0x44
+ RTM_NEWNEIGH = 0x1c
+ RTM_NEWNEIGHTBL = 0x40
+ RTM_NEWNETCONF = 0x50
+ RTM_NEWPREFIX = 0x34
+ RTM_NEWQDISC = 0x24
+ RTM_NEWROUTE = 0x18
+ RTM_NEWRULE = 0x20
+ RTM_NEWTCLASS = 0x28
+ RTM_NEWTFILTER = 0x2c
+ RTM_NR_FAMILIES = 0x12
+ RTM_NR_MSGTYPES = 0x48
+ RTM_SETDCB = 0x4f
+ RTM_SETLINK = 0x13
+ RTM_SETNEIGHTBL = 0x43
+ RTNH_ALIGNTO = 0x4
+ RTNH_F_DEAD = 0x1
+ RTNH_F_ONLINK = 0x4
+ RTNH_F_PERVASIVE = 0x2
+ RTN_MAX = 0xb
+ RTPROT_BIRD = 0xc
+ RTPROT_BOOT = 0x3
+ RTPROT_DHCP = 0x10
+ RTPROT_DNROUTED = 0xd
+ RTPROT_GATED = 0x8
+ RTPROT_KERNEL = 0x2
+ RTPROT_MROUTED = 0x11
+ RTPROT_MRT = 0xa
+ RTPROT_NTK = 0xf
+ RTPROT_RA = 0x9
+ RTPROT_REDIRECT = 0x1
+ RTPROT_STATIC = 0x4
+ RTPROT_UNSPEC = 0x0
+ RTPROT_XORP = 0xe
+ RTPROT_ZEBRA = 0xb
+ RT_CLASS_DEFAULT = 0xfd
+ RT_CLASS_LOCAL = 0xff
+ RT_CLASS_MAIN = 0xfe
+ RT_CLASS_MAX = 0xff
+ RT_CLASS_UNSPEC = 0x0
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
+ SCM_WIFI_STATUS = 0x29
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIOCADDDLCI = 0x8980
+ SIOCADDMULTI = 0x8931
+ SIOCADDRT = 0x890b
+ SIOCATMARK = 0x8905
+ SIOCDARP = 0x8953
+ SIOCDELDLCI = 0x8981
+ SIOCDELMULTI = 0x8932
+ SIOCDELRT = 0x890c
+ SIOCDEVPRIVATE = 0x89f0
+ SIOCDIFADDR = 0x8936
+ SIOCDRARP = 0x8960
+ SIOCGARP = 0x8954
+ SIOCGIFADDR = 0x8915
+ SIOCGIFBR = 0x8940
+ SIOCGIFBRDADDR = 0x8919
+ SIOCGIFCONF = 0x8912
+ SIOCGIFCOUNT = 0x8938
+ SIOCGIFDSTADDR = 0x8917
+ SIOCGIFENCAP = 0x8925
+ SIOCGIFFLAGS = 0x8913
+ SIOCGIFHWADDR = 0x8927
+ SIOCGIFINDEX = 0x8933
+ SIOCGIFMAP = 0x8970
+ SIOCGIFMEM = 0x891f
+ SIOCGIFMETRIC = 0x891d
+ SIOCGIFMTU = 0x8921
+ SIOCGIFNAME = 0x8910
+ SIOCGIFNETMASK = 0x891b
+ SIOCGIFPFLAGS = 0x8935
+ SIOCGIFSLAVE = 0x8929
+ SIOCGIFTXQLEN = 0x8942
+ SIOCGPGRP = 0x8904
+ SIOCGRARP = 0x8961
+ SIOCGSTAMP = 0x8906
+ SIOCGSTAMPNS = 0x8907
+ SIOCPROTOPRIVATE = 0x89e0
+ SIOCRTMSG = 0x890d
+ SIOCSARP = 0x8955
+ SIOCSIFADDR = 0x8916
+ SIOCSIFBR = 0x8941
+ SIOCSIFBRDADDR = 0x891a
+ SIOCSIFDSTADDR = 0x8918
+ SIOCSIFENCAP = 0x8926
+ SIOCSIFFLAGS = 0x8914
+ SIOCSIFHWADDR = 0x8924
+ SIOCSIFHWBROADCAST = 0x8937
+ SIOCSIFLINK = 0x8911
+ SIOCSIFMAP = 0x8971
+ SIOCSIFMEM = 0x8920
+ SIOCSIFMETRIC = 0x891e
+ SIOCSIFMTU = 0x8922
+ SIOCSIFNAME = 0x8923
+ SIOCSIFNETMASK = 0x891c
+ SIOCSIFPFLAGS = 0x8934
+ SIOCSIFSLAVE = 0x8930
+ SIOCSIFTXQLEN = 0x8943
+ SIOCSPGRP = 0x8902
+ SIOCSRARP = 0x8962
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DCCP = 0x6
+ SOCK_DGRAM = 0x2
+ SOCK_NONBLOCK = 0x800
+ SOCK_PACKET = 0xa
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_AAL = 0x109
+ SOL_ATM = 0x108
+ SOL_DECNET = 0x105
+ SOL_ICMPV6 = 0x3a
+ SOL_IP = 0x0
+ SOL_IPV6 = 0x29
+ SOL_IRDA = 0x10a
+ SOL_PACKET = 0x107
+ SOL_RAW = 0xff
+ SOL_SOCKET = 0x1
+ SOL_TCP = 0x6
+ SOL_X25 = 0x106
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x1e
+ SO_ATTACH_FILTER = 0x1a
+ SO_BINDTODEVICE = 0x19
+ SO_BROADCAST = 0x6
+ SO_BSDCOMPAT = 0xe
+ SO_BUSY_POLL = 0x2e
+ SO_DEBUG = 0x1
+ SO_DETACH_FILTER = 0x1b
+ SO_DOMAIN = 0x27
+ SO_DONTROUTE = 0x5
+ SO_ERROR = 0x4
+ SO_GET_FILTER = 0x1a
+ SO_KEEPALIVE = 0x9
+ SO_LINGER = 0xd
+ SO_LOCK_FILTER = 0x2c
+ SO_MARK = 0x24
+ SO_MAX_PACING_RATE = 0x2f
+ SO_NOFCS = 0x2b
+ SO_NO_CHECK = 0xb
+ SO_OOBINLINE = 0xa
+ SO_PASSCRED = 0x14
+ SO_PASSSEC = 0x22
+ SO_PEEK_OFF = 0x2a
+ SO_PEERCRED = 0x15
+ SO_PEERNAME = 0x1c
+ SO_PEERSEC = 0x1f
+ SO_PRIORITY = 0xc
+ SO_PROTOCOL = 0x26
+ SO_RCVBUF = 0x8
+ SO_RCVBUFFORCE = 0x21
+ SO_RCVLOWAT = 0x10
+ SO_RCVTIMEO = 0x12
+ SO_REUSEADDR = 0x2
+ SO_REUSEPORT = 0xf
+ SO_RXQ_OVFL = 0x28
+ SO_SECURITY_AUTHENTICATION = 0x16
+ SO_SECURITY_ENCRYPTION_NETWORK = 0x18
+ SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17
+ SO_SELECT_ERR_QUEUE = 0x2d
+ SO_SNDBUF = 0x7
+ SO_SNDBUFFORCE = 0x20
+ SO_SNDLOWAT = 0x11
+ SO_SNDTIMEO = 0x13
+ SO_TIMESTAMP = 0x1d
+ SO_TIMESTAMPING = 0x25
+ SO_TIMESTAMPNS = 0x23
+ SO_TYPE = 0x3
+ SO_WIFI_STATUS = 0x29
+ S_BLKSIZE = 0x200
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ TCFLSH = 0x2000741f
+ TCIFLUSH = 0x0
+ TCIOFLUSH = 0x2
+ TCOFLUSH = 0x1
+ TCP_CONGESTION = 0xd
+ TCP_CORK = 0x3
+ TCP_DEFER_ACCEPT = 0x9
+ TCP_INFO = 0xb
+ TCP_KEEPCNT = 0x6
+ TCP_KEEPIDLE = 0x4
+ TCP_KEEPINTVL = 0x5
+ TCP_LINGER2 = 0x8
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MD5SIG = 0xe
+ TCP_MD5SIG_MAXKEYLEN = 0x50
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_QUICKACK = 0xc
+ TCP_SYNCNT = 0x7
+ TCP_WINDOW_CLAMP = 0xa
+ TCSAFLUSH = 0x2
+ TIOCCBRK = 0x5428
+ TIOCCONS = 0x541d
+ TIOCEXCL = 0x540c
+ TIOCGDEV = 0x40045432
+ TIOCGETC = 0x40067412
+ TIOCGETD = 0x5424
+ TIOCGETP = 0x40067408
+ TIOCGEXCL = 0x40045440
+ TIOCGICOUNT = 0x545d
+ TIOCGLCKTRMIOS = 0x5456
+ TIOCGLTC = 0x40067474
+ TIOCGPGRP = 0x40047477
+ TIOCGPKT = 0x40045438
+ TIOCGPTLCK = 0x40045439
+ TIOCGPTN = 0x40045430
+ TIOCGRS485 = 0x542e
+ TIOCGSERIAL = 0x541e
+ TIOCGSID = 0x5429
+ TIOCGSOFTCAR = 0x5419
+ TIOCGWINSZ = 0x40087468
+ TIOCINQ = 0x4004667f
+ TIOCLINUX = 0x541c
+ TIOCMBIC = 0x5417
+ TIOCMBIS = 0x5416
+ TIOCMGET = 0x5415
+ TIOCMIWAIT = 0x545c
+ TIOCMSET = 0x5418
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_LOOP = 0x8000
+ TIOCM_OUT1 = 0x2000
+ TIOCM_OUT2 = 0x4000
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x5422
+ TIOCNXCL = 0x540d
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x5420
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCSBRK = 0x5427
+ TIOCSCTTY = 0x540e
+ TIOCSERCONFIG = 0x5453
+ TIOCSERGETLSR = 0x5459
+ TIOCSERGETMULTI = 0x545a
+ TIOCSERGSTRUCT = 0x5458
+ TIOCSERGWILD = 0x5454
+ TIOCSERSETMULTI = 0x545b
+ TIOCSERSWILD = 0x5455
+ TIOCSER_TEMT = 0x1
+ TIOCSETC = 0x80067411
+ TIOCSETD = 0x5423
+ TIOCSETN = 0x8006740a
+ TIOCSETP = 0x80067409
+ TIOCSIG = 0x80045436
+ TIOCSLCKTRMIOS = 0x5457
+ TIOCSLTC = 0x80067475
+ TIOCSPGRP = 0x80047476
+ TIOCSPTLCK = 0x80045431
+ TIOCSRS485 = 0x542f
+ TIOCSSERIAL = 0x541f
+ TIOCSSOFTCAR = 0x541a
+ TIOCSTART = 0x2000746e
+ TIOCSTI = 0x5412
+ TIOCSTOP = 0x2000746f
+ TIOCSWINSZ = 0x80087467
+ TIOCVHANGUP = 0x5437
+ TOSTOP = 0x400000
+ TUNATTACHFILTER = 0x801054d5
+ TUNDETACHFILTER = 0x801054d6
+ TUNGETFEATURES = 0x400454cf
+ TUNGETFILTER = 0x401054db
+ TUNGETIFF = 0x400454d2
+ TUNGETSNDBUF = 0x400454d3
+ TUNGETVNETHDRSZ = 0x400454d7
+ TUNSETDEBUG = 0x800454c9
+ TUNSETGROUP = 0x800454ce
+ TUNSETIFF = 0x800454ca
+ TUNSETIFINDEX = 0x800454da
+ TUNSETLINK = 0x800454cd
+ TUNSETNOCSUM = 0x800454c8
+ TUNSETOFFLOAD = 0x800454d0
+ TUNSETOWNER = 0x800454cc
+ TUNSETPERSIST = 0x800454cb
+ TUNSETQUEUE = 0x800454d9
+ TUNSETSNDBUF = 0x800454d4
+ TUNSETTXFILTER = 0x800454d1
+ TUNSETVNETHDRSZ = 0x800454d8
+ VDISCARD = 0x10
+ VEOF = 0x4
+ VEOL = 0x6
+ VEOL2 = 0x8
+ VERASE = 0x2
+ VINTR = 0x0
+ VKILL = 0x3
+ VLNEXT = 0xf
+ VMIN = 0x5
+ VQUIT = 0x1
+ VREPRINT = 0xb
+ VSTART = 0xd
+ VSTOP = 0xe
+ VSUSP = 0xc
+ VSWTC = 0x9
+ VT0 = 0x0
+ VT1 = 0x10000
+ VTDLY = 0x10000
+ VTIME = 0x7
+ VWERASE = 0xa
+ WALL = 0x40000000
+ WCLONE = 0x80000000
+ WCONTINUED = 0x8
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOTHREAD = 0x20000000
+ WNOWAIT = 0x1000000
+ WORDSIZE = 0x40
+ WSTOPPED = 0x2
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x62)
+ EADDRNOTAVAIL = Errno(0x63)
+ EADV = Errno(0x44)
+ EAFNOSUPPORT = Errno(0x61)
+ EAGAIN = Errno(0xb)
+ EALREADY = Errno(0x72)
+ EBADE = Errno(0x34)
+ EBADF = Errno(0x9)
+ EBADFD = Errno(0x4d)
+ EBADMSG = Errno(0x4a)
+ EBADR = Errno(0x35)
+ EBADRQC = Errno(0x38)
+ EBADSLT = Errno(0x39)
+ EBFONT = Errno(0x3b)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x7d)
+ ECHILD = Errno(0xa)
+ ECHRNG = Errno(0x2c)
+ ECOMM = Errno(0x46)
+ ECONNABORTED = Errno(0x67)
+ ECONNREFUSED = Errno(0x6f)
+ ECONNRESET = Errno(0x68)
+ EDEADLK = Errno(0x23)
+ EDEADLOCK = Errno(0x3a)
+ EDESTADDRREQ = Errno(0x59)
+ EDOM = Errno(0x21)
+ EDOTDOT = Errno(0x49)
+ EDQUOT = Errno(0x7a)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EHOSTDOWN = Errno(0x70)
+ EHOSTUNREACH = Errno(0x71)
+ EHWPOISON = Errno(0x85)
+ EIDRM = Errno(0x2b)
+ EILSEQ = Errno(0x54)
+ EINPROGRESS = Errno(0x73)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x6a)
+ EISDIR = Errno(0x15)
+ EISNAM = Errno(0x78)
+ EKEYEXPIRED = Errno(0x7f)
+ EKEYREJECTED = Errno(0x81)
+ EKEYREVOKED = Errno(0x80)
+ EL2HLT = Errno(0x33)
+ EL2NSYNC = Errno(0x2d)
+ EL3HLT = Errno(0x2e)
+ EL3RST = Errno(0x2f)
+ ELIBACC = Errno(0x4f)
+ ELIBBAD = Errno(0x50)
+ ELIBEXEC = Errno(0x53)
+ ELIBMAX = Errno(0x52)
+ ELIBSCN = Errno(0x51)
+ ELNRNG = Errno(0x30)
+ ELOOP = Errno(0x28)
+ EMEDIUMTYPE = Errno(0x7c)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x5a)
+ EMULTIHOP = Errno(0x48)
+ ENAMETOOLONG = Errno(0x24)
+ ENAVAIL = Errno(0x77)
+ ENETDOWN = Errno(0x64)
+ ENETRESET = Errno(0x66)
+ ENETUNREACH = Errno(0x65)
+ ENFILE = Errno(0x17)
+ ENOANO = Errno(0x37)
+ ENOBUFS = Errno(0x69)
+ ENOCSI = Errno(0x32)
+ ENODATA = Errno(0x3d)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOKEY = Errno(0x7e)
+ ENOLCK = Errno(0x25)
+ ENOLINK = Errno(0x43)
+ ENOMEDIUM = Errno(0x7b)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x2a)
+ ENONET = Errno(0x40)
+ ENOPKG = Errno(0x41)
+ ENOPROTOOPT = Errno(0x5c)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x3f)
+ ENOSTR = Errno(0x3c)
+ ENOSYS = Errno(0x26)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x6b)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x27)
+ ENOTNAM = Errno(0x76)
+ ENOTRECOVERABLE = Errno(0x83)
+ ENOTSOCK = Errno(0x58)
+ ENOTSUP = Errno(0x5f)
+ ENOTTY = Errno(0x19)
+ ENOTUNIQ = Errno(0x4c)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x5f)
+ EOVERFLOW = Errno(0x4b)
+ EOWNERDEAD = Errno(0x82)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x60)
+ EPIPE = Errno(0x20)
+ EPROTO = Errno(0x47)
+ EPROTONOSUPPORT = Errno(0x5d)
+ EPROTOTYPE = Errno(0x5b)
+ ERANGE = Errno(0x22)
+ EREMCHG = Errno(0x4e)
+ EREMOTE = Errno(0x42)
+ EREMOTEIO = Errno(0x79)
+ ERESTART = Errno(0x55)
+ ERFKILL = Errno(0x84)
+ EROFS = Errno(0x1e)
+ ESHUTDOWN = Errno(0x6c)
+ ESOCKTNOSUPPORT = Errno(0x5e)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESRMNT = Errno(0x45)
+ ESTALE = Errno(0x74)
+ ESTRPIPE = Errno(0x56)
+ ETIME = Errno(0x3e)
+ ETIMEDOUT = Errno(0x6e)
+ ETOOMANYREFS = Errno(0x6d)
+ ETXTBSY = Errno(0x1a)
+ EUCLEAN = Errno(0x75)
+ EUNATCH = Errno(0x31)
+ EUSERS = Errno(0x57)
+ EWOULDBLOCK = Errno(0xb)
+ EXDEV = Errno(0x12)
+ EXFULL = Errno(0x36)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0x7)
+ SIGCHLD = Signal(0x11)
+ SIGCLD = Signal(0x11)
+ SIGCONT = Signal(0x12)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x1d)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPOLL = Signal(0x1d)
+ SIGPROF = Signal(0x1b)
+ SIGPWR = Signal(0x1e)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTKFLT = Signal(0x10)
+ SIGSTOP = Signal(0x13)
+ SIGSYS = Signal(0x1f)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x14)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGUNUSED = Signal(0x1f)
+ SIGURG = Signal(0x17)
+ SIGUSR1 = Signal(0xa)
+ SIGUSR2 = Signal(0xc)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "no such device or address",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource temporarily unavailable",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device or resource busy",
+ 17: "file exists",
+ 18: "invalid cross-device link",
+ 19: "no such device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "numerical result out of range",
+ 35: "resource deadlock avoided",
+ 36: "file name too long",
+ 37: "no locks available",
+ 38: "function not implemented",
+ 39: "directory not empty",
+ 40: "too many levels of symbolic links",
+ 42: "no message of desired type",
+ 43: "identifier removed",
+ 44: "channel number out of range",
+ 45: "level 2 not synchronized",
+ 46: "level 3 halted",
+ 47: "level 3 reset",
+ 48: "link number out of range",
+ 49: "protocol driver not attached",
+ 50: "no CSI structure available",
+ 51: "level 2 halted",
+ 52: "invalid exchange",
+ 53: "invalid request descriptor",
+ 54: "exchange full",
+ 55: "no anode",
+ 56: "invalid request code",
+ 57: "invalid slot",
+ 58: "file locking deadlock error",
+ 59: "bad font file format",
+ 60: "device not a stream",
+ 61: "no data available",
+ 62: "timer expired",
+ 63: "out of streams resources",
+ 64: "machine is not on the network",
+ 65: "package not installed",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
+ 71: "protocol error",
+ 72: "multihop attempted",
+ 73: "RFS specific error",
+ 74: "bad message",
+ 75: "value too large for defined data type",
+ 76: "name not unique on network",
+ 77: "file descriptor in bad state",
+ 78: "remote address changed",
+ 79: "can not access a needed shared library",
+ 80: "accessing a corrupted shared library",
+ 81: ".lib section in a.out corrupted",
+ 82: "attempting to link in too many shared libraries",
+ 83: "cannot exec a shared library directly",
+ 84: "invalid or incomplete multibyte or wide character",
+ 85: "interrupted system call should be restarted",
+ 86: "streams pipe error",
+ 87: "too many users",
+ 88: "socket operation on non-socket",
+ 89: "destination address required",
+ 90: "message too long",
+ 91: "protocol wrong type for socket",
+ 92: "protocol not available",
+ 93: "protocol not supported",
+ 94: "socket type not supported",
+ 95: "operation not supported",
+ 96: "protocol family not supported",
+ 97: "address family not supported by protocol",
+ 98: "address already in use",
+ 99: "cannot assign requested address",
+ 100: "network is down",
+ 101: "network is unreachable",
+ 102: "network dropped connection on reset",
+ 103: "software caused connection abort",
+ 104: "connection reset by peer",
+ 105: "no buffer space available",
+ 106: "transport endpoint is already connected",
+ 107: "transport endpoint is not connected",
+ 108: "cannot send after transport endpoint shutdown",
+ 109: "too many references: cannot splice",
+ 110: "connection timed out",
+ 111: "connection refused",
+ 112: "host is down",
+ 113: "no route to host",
+ 114: "operation already in progress",
+ 115: "operation now in progress",
+ 116: "stale NFS file handle",
+ 117: "structure needs cleaning",
+ 118: "not a XENIX named type file",
+ 119: "no XENIX semaphores available",
+ 120: "is a named type file",
+ 121: "remote I/O error",
+ 122: "disk quota exceeded",
+ 123: "no medium found",
+ 124: "wrong medium type",
+ 125: "operation canceled",
+ 126: "required key not available",
+ 127: "key has expired",
+ 128: "key has been revoked",
+ 129: "key was rejected by service",
+ 130: "owner died",
+ 131: "state not recoverable",
+ 132: "operation not possible due to RF-kill",
+ 133: "memory page has hardware error",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/breakpoint trap",
+ 6: "aborted",
+ 7: "bus error",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "user defined signal 1",
+ 11: "segmentation fault",
+ 12: "user defined signal 2",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "stack fault",
+ 17: "child exited",
+ 18: "continued",
+ 19: "stopped (signal)",
+ 20: "stopped",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "urgent I/O condition",
+ 24: "CPU time limit exceeded",
+ 25: "file size limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window changed",
+ 29: "I/O possible",
+ 30: "power failure",
+ 31: "bad system call",
+}
diff --git a/src/syscall/zerrors_linux_power64le.go b/src/syscall/zerrors_linux_power64le.go
new file mode 100644
index 000000000..fdecdf24d
--- /dev/null
+++ b/src/syscall/zerrors_linux_power64le.go
@@ -0,0 +1,1902 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+package syscall
+
+const (
+ AF_ALG = 0x26
+ AF_APPLETALK = 0x5
+ AF_ASH = 0x12
+ AF_ATMPVC = 0x8
+ AF_ATMSVC = 0x14
+ AF_AX25 = 0x3
+ AF_BLUETOOTH = 0x1f
+ AF_BRIDGE = 0x7
+ AF_CAIF = 0x25
+ AF_CAN = 0x1d
+ AF_DECnet = 0xc
+ AF_ECONET = 0x13
+ AF_FILE = 0x1
+ AF_IEEE802154 = 0x24
+ AF_INET = 0x2
+ AF_INET6 = 0xa
+ AF_IPX = 0x4
+ AF_IRDA = 0x17
+ AF_ISDN = 0x22
+ AF_IUCV = 0x20
+ AF_KEY = 0xf
+ AF_LLC = 0x1a
+ AF_LOCAL = 0x1
+ AF_MAX = 0x29
+ AF_NETBEUI = 0xd
+ AF_NETLINK = 0x10
+ AF_NETROM = 0x6
+ AF_NFC = 0x27
+ AF_PACKET = 0x11
+ AF_PHONET = 0x23
+ AF_PPPOX = 0x18
+ AF_RDS = 0x15
+ AF_ROSE = 0xb
+ AF_ROUTE = 0x10
+ AF_RXRPC = 0x21
+ AF_SECURITY = 0xe
+ AF_SNA = 0x16
+ AF_TIPC = 0x1e
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ AF_VSOCK = 0x28
+ AF_WANPIPE = 0x19
+ AF_X25 = 0x9
+ ARPHRD_ADAPT = 0x108
+ ARPHRD_APPLETLK = 0x8
+ ARPHRD_ARCNET = 0x7
+ ARPHRD_ASH = 0x30d
+ ARPHRD_ATM = 0x13
+ ARPHRD_AX25 = 0x3
+ ARPHRD_BIF = 0x307
+ ARPHRD_CAIF = 0x336
+ ARPHRD_CAN = 0x118
+ ARPHRD_CHAOS = 0x5
+ ARPHRD_CISCO = 0x201
+ ARPHRD_CSLIP = 0x101
+ ARPHRD_CSLIP6 = 0x103
+ ARPHRD_DDCMP = 0x205
+ ARPHRD_DLCI = 0xf
+ ARPHRD_ECONET = 0x30e
+ ARPHRD_EETHER = 0x2
+ ARPHRD_ETHER = 0x1
+ ARPHRD_EUI64 = 0x1b
+ ARPHRD_FCAL = 0x311
+ ARPHRD_FCFABRIC = 0x313
+ ARPHRD_FCPL = 0x312
+ ARPHRD_FCPP = 0x310
+ ARPHRD_FDDI = 0x306
+ ARPHRD_FRAD = 0x302
+ ARPHRD_HDLC = 0x201
+ ARPHRD_HIPPI = 0x30c
+ ARPHRD_HWX25 = 0x110
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ ARPHRD_IEEE80211 = 0x321
+ ARPHRD_IEEE80211_PRISM = 0x322
+ ARPHRD_IEEE80211_RADIOTAP = 0x323
+ ARPHRD_IEEE802154 = 0x324
+ ARPHRD_IEEE802154_MONITOR = 0x325
+ ARPHRD_IEEE802_TR = 0x320
+ ARPHRD_INFINIBAND = 0x20
+ ARPHRD_IP6GRE = 0x337
+ ARPHRD_IPDDP = 0x309
+ ARPHRD_IPGRE = 0x30a
+ ARPHRD_IRDA = 0x30f
+ ARPHRD_LAPB = 0x204
+ ARPHRD_LOCALTLK = 0x305
+ ARPHRD_LOOPBACK = 0x304
+ ARPHRD_METRICOM = 0x17
+ ARPHRD_NETLINK = 0x338
+ ARPHRD_NETROM = 0x0
+ ARPHRD_NONE = 0xfffe
+ ARPHRD_PHONET = 0x334
+ ARPHRD_PHONET_PIPE = 0x335
+ ARPHRD_PIMREG = 0x30b
+ ARPHRD_PPP = 0x200
+ ARPHRD_PRONET = 0x4
+ ARPHRD_RAWHDLC = 0x206
+ ARPHRD_ROSE = 0x10e
+ ARPHRD_RSRVD = 0x104
+ ARPHRD_SIT = 0x308
+ ARPHRD_SKIP = 0x303
+ ARPHRD_SLIP = 0x100
+ ARPHRD_SLIP6 = 0x102
+ ARPHRD_TUNNEL = 0x300
+ ARPHRD_TUNNEL6 = 0x301
+ ARPHRD_VOID = 0xffff
+ ARPHRD_X25 = 0x10f
+ B0 = 0x0
+ B1000000 = 0x17
+ B110 = 0x3
+ B115200 = 0x11
+ B1152000 = 0x18
+ B1200 = 0x9
+ B134 = 0x4
+ B150 = 0x5
+ B1500000 = 0x19
+ B1800 = 0xa
+ B19200 = 0xe
+ B200 = 0x6
+ B2000000 = 0x1a
+ B230400 = 0x12
+ B2400 = 0xb
+ B2500000 = 0x1b
+ B300 = 0x7
+ B3000000 = 0x1c
+ B3500000 = 0x1d
+ B38400 = 0xf
+ B4000000 = 0x1e
+ B460800 = 0x13
+ B4800 = 0xc
+ B50 = 0x1
+ B500000 = 0x14
+ B57600 = 0x10
+ B576000 = 0x15
+ B600 = 0x8
+ B75 = 0x2
+ B921600 = 0x16
+ B9600 = 0xd
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXINSNS = 0x1000
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MOD = 0x90
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ BPF_XOR = 0xa0
+ BRKINT = 0x2
+ CFLUSH = 0xf
+ CLOCAL = 0x8000
+ CLONE_CHILD_CLEARTID = 0x200000
+ CLONE_CHILD_SETTID = 0x1000000
+ CLONE_DETACHED = 0x400000
+ CLONE_FILES = 0x400
+ CLONE_FS = 0x200
+ CLONE_IO = 0x80000000
+ CLONE_NEWIPC = 0x8000000
+ CLONE_NEWNET = 0x40000000
+ CLONE_NEWNS = 0x20000
+ CLONE_NEWPID = 0x20000000
+ CLONE_NEWUSER = 0x10000000
+ CLONE_NEWUTS = 0x4000000
+ CLONE_PARENT = 0x8000
+ CLONE_PARENT_SETTID = 0x100000
+ CLONE_PTRACE = 0x2000
+ CLONE_SETTLS = 0x80000
+ CLONE_SIGHAND = 0x800
+ CLONE_SYSVSEM = 0x40000
+ CLONE_THREAD = 0x10000
+ CLONE_UNTRACED = 0x800000
+ CLONE_VFORK = 0x4000
+ CLONE_VM = 0x100
+ CREAD = 0x800
+ CS5 = 0x0
+ CS6 = 0x100
+ CS7 = 0x200
+ CS8 = 0x300
+ CSIGNAL = 0xff
+ CSIZE = 0x300
+ CSTART = 0x11
+ CSTATUS = 0x0
+ CSTOP = 0x13
+ CSTOPB = 0x400
+ CSUSP = 0x1a
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ DT_WHT = 0xe
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ ENCODING_DEFAULT = 0x0
+ ENCODING_FM_MARK = 0x3
+ ENCODING_FM_SPACE = 0x4
+ ENCODING_MANCHESTER = 0x5
+ ENCODING_NRZ = 0x1
+ ENCODING_NRZI = 0x2
+ EPOLLERR = 0x8
+ EPOLLET = 0x80000000
+ EPOLLHUP = 0x10
+ EPOLLIN = 0x1
+ EPOLLMSG = 0x400
+ EPOLLONESHOT = 0x40000000
+ EPOLLOUT = 0x4
+ EPOLLPRI = 0x2
+ EPOLLRDBAND = 0x80
+ EPOLLRDHUP = 0x2000
+ EPOLLRDNORM = 0x40
+ EPOLLWAKEUP = 0x20000000
+ EPOLLWRBAND = 0x200
+ EPOLLWRNORM = 0x100
+ EPOLL_CLOEXEC = 0x80000
+ EPOLL_CTL_ADD = 0x1
+ EPOLL_CTL_DEL = 0x2
+ EPOLL_CTL_MOD = 0x3
+ ETH_P_1588 = 0x88f7
+ ETH_P_8021AD = 0x88a8
+ ETH_P_8021AH = 0x88e7
+ ETH_P_8021Q = 0x8100
+ ETH_P_802_2 = 0x4
+ ETH_P_802_3 = 0x1
+ ETH_P_802_3_MIN = 0x600
+ ETH_P_802_EX1 = 0x88b5
+ ETH_P_AARP = 0x80f3
+ ETH_P_AF_IUCV = 0xfbfb
+ ETH_P_ALL = 0x3
+ ETH_P_AOE = 0x88a2
+ ETH_P_ARCNET = 0x1a
+ ETH_P_ARP = 0x806
+ ETH_P_ATALK = 0x809b
+ ETH_P_ATMFATE = 0x8884
+ ETH_P_ATMMPOA = 0x884c
+ ETH_P_AX25 = 0x2
+ ETH_P_BATMAN = 0x4305
+ ETH_P_BPQ = 0x8ff
+ ETH_P_CAIF = 0xf7
+ ETH_P_CAN = 0xc
+ ETH_P_CANFD = 0xd
+ ETH_P_CONTROL = 0x16
+ ETH_P_CUST = 0x6006
+ ETH_P_DDCMP = 0x6
+ ETH_P_DEC = 0x6000
+ ETH_P_DIAG = 0x6005
+ ETH_P_DNA_DL = 0x6001
+ ETH_P_DNA_RC = 0x6002
+ ETH_P_DNA_RT = 0x6003
+ ETH_P_DSA = 0x1b
+ ETH_P_ECONET = 0x18
+ ETH_P_EDSA = 0xdada
+ ETH_P_FCOE = 0x8906
+ ETH_P_FIP = 0x8914
+ ETH_P_HDLC = 0x19
+ ETH_P_IEEE802154 = 0xf6
+ ETH_P_IEEEPUP = 0xa00
+ ETH_P_IEEEPUPAT = 0xa01
+ ETH_P_IP = 0x800
+ ETH_P_IPV6 = 0x86dd
+ ETH_P_IPX = 0x8137
+ ETH_P_IRDA = 0x17
+ ETH_P_LAT = 0x6004
+ ETH_P_LINK_CTL = 0x886c
+ ETH_P_LOCALTALK = 0x9
+ ETH_P_LOOP = 0x60
+ ETH_P_MOBITEX = 0x15
+ ETH_P_MPLS_MC = 0x8848
+ ETH_P_MPLS_UC = 0x8847
+ ETH_P_MVRP = 0x88f5
+ ETH_P_PAE = 0x888e
+ ETH_P_PAUSE = 0x8808
+ ETH_P_PHONET = 0xf5
+ ETH_P_PPPTALK = 0x10
+ ETH_P_PPP_DISC = 0x8863
+ ETH_P_PPP_MP = 0x8
+ ETH_P_PPP_SES = 0x8864
+ ETH_P_PRP = 0x88fb
+ ETH_P_PUP = 0x200
+ ETH_P_PUPAT = 0x201
+ ETH_P_QINQ1 = 0x9100
+ ETH_P_QINQ2 = 0x9200
+ ETH_P_QINQ3 = 0x9300
+ ETH_P_RARP = 0x8035
+ ETH_P_SCA = 0x6007
+ ETH_P_SLOW = 0x8809
+ ETH_P_SNAP = 0x5
+ ETH_P_TDLS = 0x890d
+ ETH_P_TEB = 0x6558
+ ETH_P_TIPC = 0x88ca
+ ETH_P_TRAILER = 0x1c
+ ETH_P_TR_802_2 = 0x11
+ ETH_P_WAN_PPP = 0x7
+ ETH_P_WCCP = 0x883e
+ ETH_P_X25 = 0x805
+ EXTA = 0xe
+ EXTB = 0xf
+ EXTPROC = 0x10000000
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ FLUSHO = 0x800000
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x406
+ F_EXLCK = 0x4
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLEASE = 0x401
+ F_GETLK = 0x5
+ F_GETLK64 = 0xc
+ F_GETOWN = 0x9
+ F_GETOWN_EX = 0x10
+ F_GETPIPE_SZ = 0x408
+ F_GETSIG = 0xb
+ F_LOCK = 0x1
+ F_NOTIFY = 0x402
+ F_OK = 0x0
+ F_RDLCK = 0x0
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLEASE = 0x400
+ F_SETLK = 0xd
+ F_SETLK64 = 0xd
+ F_SETLKW = 0xe
+ F_SETLKW64 = 0xe
+ F_SETOWN = 0x8
+ F_SETOWN_EX = 0xf
+ F_SETPIPE_SZ = 0x407
+ F_SETSIG = 0xa
+ F_SHLCK = 0x8
+ F_TEST = 0x3
+ F_TLOCK = 0x2
+ F_ULOCK = 0x0
+ F_UNLCK = 0x2
+ F_WRLCK = 0x1
+ HUPCL = 0x4000
+ ICANON = 0x100
+ ICMPV6_FILTER = 0x1
+ ICRNL = 0x100
+ IEXTEN = 0x400
+ IFA_F_DADFAILED = 0x8
+ IFA_F_DEPRECATED = 0x20
+ IFA_F_HOMEADDRESS = 0x10
+ IFA_F_NODAD = 0x2
+ IFA_F_OPTIMISTIC = 0x4
+ IFA_F_PERMANENT = 0x80
+ IFA_F_SECONDARY = 0x1
+ IFA_F_TEMPORARY = 0x1
+ IFA_F_TENTATIVE = 0x40
+ IFA_MAX = 0x7
+ IFF_802_1Q_VLAN = 0x1
+ IFF_ALLMULTI = 0x200
+ IFF_ATTACH_QUEUE = 0x200
+ IFF_AUTOMEDIA = 0x4000
+ IFF_BONDING = 0x20
+ IFF_BRIDGE_PORT = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_DETACH_QUEUE = 0x400
+ IFF_DISABLE_NETPOLL = 0x1000
+ IFF_DONT_BRIDGE = 0x800
+ IFF_DORMANT = 0x20000
+ IFF_DYNAMIC = 0x8000
+ IFF_EBRIDGE = 0x2
+ IFF_ECHO = 0x40000
+ IFF_ISATAP = 0x80
+ IFF_LIVE_ADDR_CHANGE = 0x100000
+ IFF_LOOPBACK = 0x8
+ IFF_LOWER_UP = 0x10000
+ IFF_MACVLAN = 0x200000
+ IFF_MACVLAN_PORT = 0x2000
+ IFF_MASTER = 0x400
+ IFF_MASTER_8023AD = 0x8
+ IFF_MASTER_ALB = 0x10
+ IFF_MASTER_ARPMON = 0x100
+ IFF_MULTICAST = 0x1000
+ IFF_MULTI_QUEUE = 0x100
+ IFF_NOARP = 0x80
+ IFF_NOFILTER = 0x1000
+ IFF_NOTRAILERS = 0x20
+ IFF_NO_PI = 0x1000
+ IFF_ONE_QUEUE = 0x2000
+ IFF_OVS_DATAPATH = 0x8000
+ IFF_PERSIST = 0x800
+ IFF_POINTOPOINT = 0x10
+ IFF_PORTSEL = 0x2000
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SLAVE = 0x800
+ IFF_SLAVE_INACTIVE = 0x4
+ IFF_SLAVE_NEEDARP = 0x40
+ IFF_SUPP_NOFCS = 0x80000
+ IFF_TAP = 0x2
+ IFF_TEAM_PORT = 0x40000
+ IFF_TUN = 0x1
+ IFF_TUN_EXCL = 0x8000
+ IFF_TX_SKB_SHARING = 0x10000
+ IFF_UNICAST_FLT = 0x20000
+ IFF_UP = 0x1
+ IFF_VNET_HDR = 0x4000
+ IFF_VOLATILE = 0x70c5a
+ IFF_WAN_HDLC = 0x200
+ IFF_XMIT_DST_RELEASE = 0x400
+ IFNAMSIZ = 0x10
+ IGNBRK = 0x1
+ IGNCR = 0x80
+ IGNPAR = 0x4
+ IMAXBEL = 0x2000
+ INLCR = 0x40
+ INPCK = 0x10
+ IN_ACCESS = 0x1
+ IN_ALL_EVENTS = 0xfff
+ IN_ATTRIB = 0x4
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLOEXEC = 0x80000
+ IN_CLOSE = 0x18
+ IN_CLOSE_NOWRITE = 0x10
+ IN_CLOSE_WRITE = 0x8
+ IN_CREATE = 0x100
+ IN_DELETE = 0x200
+ IN_DELETE_SELF = 0x400
+ IN_DONT_FOLLOW = 0x2000000
+ IN_EXCL_UNLINK = 0x4000000
+ IN_IGNORED = 0x8000
+ IN_ISDIR = 0x40000000
+ IN_LOOPBACKNET = 0x7f
+ IN_MASK_ADD = 0x20000000
+ IN_MODIFY = 0x2
+ IN_MOVE = 0xc0
+ IN_MOVED_FROM = 0x40
+ IN_MOVED_TO = 0x80
+ IN_MOVE_SELF = 0x800
+ IN_NONBLOCK = 0x800
+ IN_ONESHOT = 0x80000000
+ IN_ONLYDIR = 0x1000000
+ IN_OPEN = 0x20
+ IN_Q_OVERFLOW = 0x4000
+ IN_UNMOUNT = 0x2000
+ IPPROTO_AH = 0x33
+ IPPROTO_BEETPH = 0x5e
+ IPPROTO_COMP = 0x6c
+ IPPROTO_DCCP = 0x21
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_ESP = 0x32
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MH = 0x87
+ IPPROTO_MTP = 0x5c
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_SCTP = 0x84
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_UDP = 0x11
+ IPPROTO_UDPLITE = 0x88
+ IPV6_2292DSTOPTS = 0x4
+ IPV6_2292HOPLIMIT = 0x8
+ IPV6_2292HOPOPTS = 0x3
+ IPV6_2292PKTINFO = 0x2
+ IPV6_2292PKTOPTIONS = 0x6
+ IPV6_2292RTHDR = 0x5
+ IPV6_ADDRFORM = 0x1
+ IPV6_ADD_MEMBERSHIP = 0x14
+ IPV6_AUTHHDR = 0xa
+ IPV6_CHECKSUM = 0x7
+ IPV6_DROP_MEMBERSHIP = 0x15
+ IPV6_DSTOPTS = 0x3b
+ IPV6_HOPLIMIT = 0x34
+ IPV6_HOPOPTS = 0x36
+ IPV6_IPSEC_POLICY = 0x22
+ IPV6_JOIN_ANYCAST = 0x1b
+ IPV6_JOIN_GROUP = 0x14
+ IPV6_LEAVE_ANYCAST = 0x1c
+ IPV6_LEAVE_GROUP = 0x15
+ IPV6_MTU = 0x18
+ IPV6_MTU_DISCOVER = 0x17
+ IPV6_MULTICAST_HOPS = 0x12
+ IPV6_MULTICAST_IF = 0x11
+ IPV6_MULTICAST_LOOP = 0x13
+ IPV6_NEXTHOP = 0x9
+ IPV6_PKTINFO = 0x32
+ IPV6_PMTUDISC_DO = 0x2
+ IPV6_PMTUDISC_DONT = 0x0
+ IPV6_PMTUDISC_PROBE = 0x3
+ IPV6_PMTUDISC_WANT = 0x1
+ IPV6_RECVDSTOPTS = 0x3a
+ IPV6_RECVERR = 0x19
+ IPV6_RECVHOPLIMIT = 0x33
+ IPV6_RECVHOPOPTS = 0x35
+ IPV6_RECVPKTINFO = 0x31
+ IPV6_RECVRTHDR = 0x38
+ IPV6_RECVTCLASS = 0x42
+ IPV6_ROUTER_ALERT = 0x16
+ IPV6_RTHDR = 0x39
+ IPV6_RTHDRDSTOPTS = 0x37
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_RXDSTOPTS = 0x3b
+ IPV6_RXHOPOPTS = 0x36
+ IPV6_TCLASS = 0x43
+ IPV6_UNICAST_HOPS = 0x10
+ IPV6_V6ONLY = 0x1a
+ IPV6_XFRM_POLICY = 0x23
+ IP_ADD_MEMBERSHIP = 0x23
+ IP_ADD_SOURCE_MEMBERSHIP = 0x27
+ IP_BLOCK_SOURCE = 0x26
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0x24
+ IP_DROP_SOURCE_MEMBERSHIP = 0x28
+ IP_FREEBIND = 0xf
+ IP_HDRINCL = 0x3
+ IP_IPSEC_POLICY = 0x10
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0x14
+ IP_MF = 0x2000
+ IP_MINTTL = 0x15
+ IP_MSFILTER = 0x29
+ IP_MSS = 0x240
+ IP_MTU = 0xe
+ IP_MTU_DISCOVER = 0xa
+ IP_MULTICAST_ALL = 0x31
+ IP_MULTICAST_IF = 0x20
+ IP_MULTICAST_LOOP = 0x22
+ IP_MULTICAST_TTL = 0x21
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x4
+ IP_ORIGDSTADDR = 0x14
+ IP_PASSSEC = 0x12
+ IP_PKTINFO = 0x8
+ IP_PKTOPTIONS = 0x9
+ IP_PMTUDISC = 0xa
+ IP_PMTUDISC_DO = 0x2
+ IP_PMTUDISC_DONT = 0x0
+ IP_PMTUDISC_PROBE = 0x3
+ IP_PMTUDISC_WANT = 0x1
+ IP_RECVERR = 0xb
+ IP_RECVOPTS = 0x6
+ IP_RECVORIGDSTADDR = 0x14
+ IP_RECVRETOPTS = 0x7
+ IP_RECVTOS = 0xd
+ IP_RECVTTL = 0xc
+ IP_RETOPTS = 0x7
+ IP_RF = 0x8000
+ IP_ROUTER_ALERT = 0x5
+ IP_TOS = 0x1
+ IP_TRANSPARENT = 0x13
+ IP_TTL = 0x2
+ IP_UNBLOCK_SOURCE = 0x25
+ IP_UNICAST_IF = 0x32
+ IP_XFRM_POLICY = 0x11
+ ISIG = 0x80
+ ISTRIP = 0x20
+ IUTF8 = 0x4000
+ IXANY = 0x800
+ IXOFF = 0x400
+ IXON = 0x200
+ LINUX_REBOOT_CMD_CAD_OFF = 0x0
+ LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
+ LINUX_REBOOT_CMD_HALT = 0xcdef0123
+ LINUX_REBOOT_CMD_KEXEC = 0x45584543
+ LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc
+ LINUX_REBOOT_CMD_RESTART = 0x1234567
+ LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4
+ LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2
+ LINUX_REBOOT_MAGIC1 = 0xfee1dead
+ LINUX_REBOOT_MAGIC2 = 0x28121969
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
+ MADV_DODUMP = 0x11
+ MADV_DOFORK = 0xb
+ MADV_DONTDUMP = 0x10
+ MADV_DONTFORK = 0xa
+ MADV_DONTNEED = 0x4
+ MADV_HUGEPAGE = 0xe
+ MADV_HWPOISON = 0x64
+ MADV_MERGEABLE = 0xc
+ MADV_NOHUGEPAGE = 0xf
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_REMOVE = 0x9
+ MADV_SEQUENTIAL = 0x2
+ MADV_UNMERGEABLE = 0xd
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x20
+ MAP_ANONYMOUS = 0x20
+ MAP_DENYWRITE = 0x800
+ MAP_EXECUTABLE = 0x1000
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_GROWSDOWN = 0x100
+ MAP_HUGETLB = 0x40000
+ MAP_HUGE_MASK = 0x3f
+ MAP_HUGE_SHIFT = 0x1a
+ MAP_LOCKED = 0x80
+ MAP_NONBLOCK = 0x10000
+ MAP_NORESERVE = 0x40
+ MAP_POPULATE = 0x8000
+ MAP_PRIVATE = 0x2
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x20000
+ MAP_TYPE = 0xf
+ MCL_CURRENT = 0x2000
+ MCL_FUTURE = 0x4000
+ MNT_DETACH = 0x2
+ MNT_EXPIRE = 0x4
+ MNT_FORCE = 0x1
+ MSG_CMSG_CLOEXEC = 0x40000000
+ MSG_CONFIRM = 0x800
+ MSG_CTRUNC = 0x8
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x40
+ MSG_EOR = 0x80
+ MSG_ERRQUEUE = 0x2000
+ MSG_FASTOPEN = 0x20000000
+ MSG_FIN = 0x200
+ MSG_MORE = 0x8000
+ MSG_NOSIGNAL = 0x4000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_PROXY = 0x10
+ MSG_RST = 0x1000
+ MSG_SYN = 0x400
+ MSG_TRUNC = 0x20
+ MSG_TRYHARD = 0x4
+ MSG_WAITALL = 0x100
+ MSG_WAITFORONE = 0x10000
+ MS_ACTIVE = 0x40000000
+ MS_ASYNC = 0x1
+ MS_BIND = 0x1000
+ MS_DIRSYNC = 0x80
+ MS_INVALIDATE = 0x2
+ MS_I_VERSION = 0x800000
+ MS_KERNMOUNT = 0x400000
+ MS_MANDLOCK = 0x40
+ MS_MGC_MSK = 0xffff0000
+ MS_MGC_VAL = 0xc0ed0000
+ MS_MOVE = 0x2000
+ MS_NOATIME = 0x400
+ MS_NODEV = 0x4
+ MS_NODIRATIME = 0x800
+ MS_NOEXEC = 0x8
+ MS_NOSUID = 0x2
+ MS_NOUSER = -0x80000000
+ MS_POSIXACL = 0x10000
+ MS_PRIVATE = 0x40000
+ MS_RDONLY = 0x1
+ MS_REC = 0x4000
+ MS_RELATIME = 0x200000
+ MS_REMOUNT = 0x20
+ MS_RMT_MASK = 0x800051
+ MS_SHARED = 0x100000
+ MS_SILENT = 0x8000
+ MS_SLAVE = 0x80000
+ MS_STRICTATIME = 0x1000000
+ MS_SYNC = 0x4
+ MS_SYNCHRONOUS = 0x10
+ MS_UNBINDABLE = 0x20000
+ NAME_MAX = 0xff
+ NETLINK_ADD_MEMBERSHIP = 0x1
+ NETLINK_AUDIT = 0x9
+ NETLINK_BROADCAST_ERROR = 0x4
+ NETLINK_CONNECTOR = 0xb
+ NETLINK_CRYPTO = 0x15
+ NETLINK_DNRTMSG = 0xe
+ NETLINK_DROP_MEMBERSHIP = 0x2
+ NETLINK_ECRYPTFS = 0x13
+ NETLINK_FIB_LOOKUP = 0xa
+ NETLINK_FIREWALL = 0x3
+ NETLINK_GENERIC = 0x10
+ NETLINK_INET_DIAG = 0x4
+ NETLINK_IP6_FW = 0xd
+ NETLINK_ISCSI = 0x8
+ NETLINK_KOBJECT_UEVENT = 0xf
+ NETLINK_NETFILTER = 0xc
+ NETLINK_NFLOG = 0x5
+ NETLINK_NO_ENOBUFS = 0x5
+ NETLINK_PKTINFO = 0x3
+ NETLINK_RDMA = 0x14
+ NETLINK_ROUTE = 0x0
+ NETLINK_RX_RING = 0x6
+ NETLINK_SCSITRANSPORT = 0x12
+ NETLINK_SELINUX = 0x7
+ NETLINK_SOCK_DIAG = 0x4
+ NETLINK_TX_RING = 0x7
+ NETLINK_UNUSED = 0x1
+ NETLINK_USERSOCK = 0x2
+ NETLINK_XFRM = 0x6
+ NLA_ALIGNTO = 0x4
+ NLA_F_NESTED = 0x8000
+ NLA_F_NET_BYTEORDER = 0x4000
+ NLA_HDRLEN = 0x4
+ NLMSG_ALIGNTO = 0x4
+ NLMSG_DONE = 0x3
+ NLMSG_ERROR = 0x2
+ NLMSG_HDRLEN = 0x10
+ NLMSG_MIN_TYPE = 0x10
+ NLMSG_NOOP = 0x1
+ NLMSG_OVERRUN = 0x4
+ NLM_F_ACK = 0x4
+ NLM_F_APPEND = 0x800
+ NLM_F_ATOMIC = 0x400
+ NLM_F_CREATE = 0x400
+ NLM_F_DUMP = 0x300
+ NLM_F_DUMP_INTR = 0x10
+ NLM_F_ECHO = 0x8
+ NLM_F_EXCL = 0x200
+ NLM_F_MATCH = 0x200
+ NLM_F_MULTI = 0x2
+ NLM_F_REPLACE = 0x100
+ NLM_F_REQUEST = 0x1
+ NLM_F_ROOT = 0x100
+ NOFLSH = 0x80000000
+ OCRNL = 0x8
+ OFDEL = 0x80
+ OFILL = 0x40
+ ONLCR = 0x2
+ ONLRET = 0x20
+ ONOCR = 0x10
+ OPOST = 0x1
+ O_ACCMODE = 0x3
+ O_APPEND = 0x400
+ O_ASYNC = 0x2000
+ O_CLOEXEC = 0x80000
+ O_CREAT = 0x40
+ O_DIRECT = 0x20000
+ O_DIRECTORY = 0x4000
+ O_DSYNC = 0x1000
+ O_EXCL = 0x80
+ O_FSYNC = 0x101000
+ O_LARGEFILE = 0x0
+ O_NDELAY = 0x800
+ O_NOATIME = 0x40000
+ O_NOCTTY = 0x100
+ O_NOFOLLOW = 0x8000
+ O_NONBLOCK = 0x800
+ O_PATH = 0x200000
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSYNC = 0x101000
+ O_SYNC = 0x101000
+ O_TMPFILE = 0x410000
+ O_TRUNC = 0x200
+ O_WRONLY = 0x1
+ PACKET_ADD_MEMBERSHIP = 0x1
+ PACKET_AUXDATA = 0x8
+ PACKET_BROADCAST = 0x1
+ PACKET_COPY_THRESH = 0x7
+ PACKET_DROP_MEMBERSHIP = 0x2
+ PACKET_FANOUT = 0x12
+ PACKET_FANOUT_CPU = 0x2
+ PACKET_FANOUT_FLAG_DEFRAG = 0x8000
+ PACKET_FANOUT_FLAG_ROLLOVER = 0x1000
+ PACKET_FANOUT_HASH = 0x0
+ PACKET_FANOUT_LB = 0x1
+ PACKET_FANOUT_RND = 0x4
+ PACKET_FANOUT_ROLLOVER = 0x3
+ PACKET_FASTROUTE = 0x6
+ PACKET_HDRLEN = 0xb
+ PACKET_HOST = 0x0
+ PACKET_LOOPBACK = 0x5
+ PACKET_LOSS = 0xe
+ PACKET_MR_ALLMULTI = 0x2
+ PACKET_MR_MULTICAST = 0x0
+ PACKET_MR_PROMISC = 0x1
+ PACKET_MR_UNICAST = 0x3
+ PACKET_MULTICAST = 0x2
+ PACKET_ORIGDEV = 0x9
+ PACKET_OTHERHOST = 0x3
+ PACKET_OUTGOING = 0x4
+ PACKET_RECV_OUTPUT = 0x3
+ PACKET_RESERVE = 0xc
+ PACKET_RX_RING = 0x5
+ PACKET_STATISTICS = 0x6
+ PACKET_TIMESTAMP = 0x11
+ PACKET_TX_HAS_OFF = 0x13
+ PACKET_TX_RING = 0xd
+ PACKET_TX_TIMESTAMP = 0x10
+ PACKET_VERSION = 0xa
+ PACKET_VNET_HDR = 0xf
+ PARENB = 0x1000
+ PARITY_CRC16_PR0 = 0x2
+ PARITY_CRC16_PR0_CCITT = 0x4
+ PARITY_CRC16_PR1 = 0x3
+ PARITY_CRC16_PR1_CCITT = 0x5
+ PARITY_CRC32_PR0_CCITT = 0x6
+ PARITY_CRC32_PR1_CCITT = 0x7
+ PARITY_DEFAULT = 0x0
+ PARITY_NONE = 0x1
+ PARMRK = 0x8
+ PARODD = 0x2000
+ PENDIN = 0x20000000
+ PRIO_PGRP = 0x1
+ PRIO_PROCESS = 0x0
+ PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_GROWSDOWN = 0x1000000
+ PROT_GROWSUP = 0x2000000
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_SAO = 0x10
+ PROT_WRITE = 0x2
+ PR_CAPBSET_DROP = 0x18
+ PR_CAPBSET_READ = 0x17
+ PR_ENDIAN_BIG = 0x0
+ PR_ENDIAN_LITTLE = 0x1
+ PR_ENDIAN_PPC_LITTLE = 0x2
+ PR_FPEMU_NOPRINT = 0x1
+ PR_FPEMU_SIGFPE = 0x2
+ PR_FP_EXC_ASYNC = 0x2
+ PR_FP_EXC_DISABLED = 0x0
+ PR_FP_EXC_DIV = 0x10000
+ PR_FP_EXC_INV = 0x100000
+ PR_FP_EXC_NONRECOV = 0x1
+ PR_FP_EXC_OVF = 0x20000
+ PR_FP_EXC_PRECISE = 0x3
+ PR_FP_EXC_RES = 0x80000
+ PR_FP_EXC_SW_ENABLE = 0x80
+ PR_FP_EXC_UND = 0x40000
+ PR_GET_CHILD_SUBREAPER = 0x25
+ PR_GET_DUMPABLE = 0x3
+ PR_GET_ENDIAN = 0x13
+ PR_GET_FPEMU = 0x9
+ PR_GET_FPEXC = 0xb
+ PR_GET_KEEPCAPS = 0x7
+ PR_GET_NAME = 0x10
+ PR_GET_NO_NEW_PRIVS = 0x27
+ PR_GET_PDEATHSIG = 0x2
+ PR_GET_SECCOMP = 0x15
+ PR_GET_SECUREBITS = 0x1b
+ PR_GET_TID_ADDRESS = 0x28
+ PR_GET_TIMERSLACK = 0x1e
+ PR_GET_TIMING = 0xd
+ PR_GET_TSC = 0x19
+ PR_GET_UNALIGN = 0x5
+ PR_MCE_KILL = 0x21
+ PR_MCE_KILL_CLEAR = 0x0
+ PR_MCE_KILL_DEFAULT = 0x2
+ PR_MCE_KILL_EARLY = 0x1
+ PR_MCE_KILL_GET = 0x22
+ PR_MCE_KILL_LATE = 0x0
+ PR_MCE_KILL_SET = 0x1
+ PR_SET_CHILD_SUBREAPER = 0x24
+ PR_SET_DUMPABLE = 0x4
+ PR_SET_ENDIAN = 0x14
+ PR_SET_FPEMU = 0xa
+ PR_SET_FPEXC = 0xc
+ PR_SET_KEEPCAPS = 0x8
+ PR_SET_MM = 0x23
+ PR_SET_MM_ARG_END = 0x9
+ PR_SET_MM_ARG_START = 0x8
+ PR_SET_MM_AUXV = 0xc
+ PR_SET_MM_BRK = 0x7
+ PR_SET_MM_END_CODE = 0x2
+ PR_SET_MM_END_DATA = 0x4
+ PR_SET_MM_ENV_END = 0xb
+ PR_SET_MM_ENV_START = 0xa
+ PR_SET_MM_EXE_FILE = 0xd
+ PR_SET_MM_START_BRK = 0x6
+ PR_SET_MM_START_CODE = 0x1
+ PR_SET_MM_START_DATA = 0x3
+ PR_SET_MM_START_STACK = 0x5
+ PR_SET_NAME = 0xf
+ PR_SET_NO_NEW_PRIVS = 0x26
+ PR_SET_PDEATHSIG = 0x1
+ PR_SET_PTRACER = 0x59616d61
+ PR_SET_PTRACER_ANY = -0x1
+ PR_SET_SECCOMP = 0x16
+ PR_SET_SECUREBITS = 0x1c
+ PR_SET_TIMERSLACK = 0x1d
+ PR_SET_TIMING = 0xe
+ PR_SET_TSC = 0x1a
+ PR_SET_UNALIGN = 0x6
+ PR_TASK_PERF_EVENTS_DISABLE = 0x1f
+ PR_TASK_PERF_EVENTS_ENABLE = 0x20
+ PR_TIMING_STATISTICAL = 0x0
+ PR_TIMING_TIMESTAMP = 0x1
+ PR_TSC_ENABLE = 0x1
+ PR_TSC_SIGSEGV = 0x2
+ PR_UNALIGN_NOPRINT = 0x1
+ PR_UNALIGN_SIGBUS = 0x2
+ PTRACE_ATTACH = 0x10
+ PTRACE_CONT = 0x7
+ PTRACE_DETACH = 0x11
+ PTRACE_EVENT_CLONE = 0x3
+ PTRACE_EVENT_EXEC = 0x4
+ PTRACE_EVENT_EXIT = 0x6
+ PTRACE_EVENT_FORK = 0x1
+ PTRACE_EVENT_SECCOMP = 0x7
+ PTRACE_EVENT_STOP = 0x80
+ PTRACE_EVENT_VFORK = 0x2
+ PTRACE_EVENT_VFORK_DONE = 0x5
+ PTRACE_GETEVENTMSG = 0x4201
+ PTRACE_GETEVRREGS = 0x14
+ PTRACE_GETFPREGS = 0xe
+ PTRACE_GETREGS = 0xc
+ PTRACE_GETREGS64 = 0x16
+ PTRACE_GETREGSET = 0x4204
+ PTRACE_GETSIGINFO = 0x4202
+ PTRACE_GETSIGMASK = 0x420a
+ PTRACE_GETVRREGS = 0x12
+ PTRACE_GETVSRREGS = 0x1b
+ PTRACE_GET_DEBUGREG = 0x19
+ PTRACE_INTERRUPT = 0x4207
+ PTRACE_KILL = 0x8
+ PTRACE_LISTEN = 0x4208
+ PTRACE_O_EXITKILL = 0x100000
+ PTRACE_O_MASK = 0x1000ff
+ PTRACE_O_TRACECLONE = 0x8
+ PTRACE_O_TRACEEXEC = 0x10
+ PTRACE_O_TRACEEXIT = 0x40
+ PTRACE_O_TRACEFORK = 0x2
+ PTRACE_O_TRACESECCOMP = 0x80
+ PTRACE_O_TRACESYSGOOD = 0x1
+ PTRACE_O_TRACEVFORK = 0x4
+ PTRACE_O_TRACEVFORKDONE = 0x20
+ PTRACE_PEEKDATA = 0x2
+ PTRACE_PEEKSIGINFO = 0x4209
+ PTRACE_PEEKSIGINFO_SHARED = 0x1
+ PTRACE_PEEKTEXT = 0x1
+ PTRACE_PEEKUSR = 0x3
+ PTRACE_POKEDATA = 0x5
+ PTRACE_POKETEXT = 0x4
+ PTRACE_POKEUSR = 0x6
+ PTRACE_SEIZE = 0x4206
+ PTRACE_SETEVRREGS = 0x15
+ PTRACE_SETFPREGS = 0xf
+ PTRACE_SETOPTIONS = 0x4200
+ PTRACE_SETREGS = 0xd
+ PTRACE_SETREGS64 = 0x17
+ PTRACE_SETREGSET = 0x4205
+ PTRACE_SETSIGINFO = 0x4203
+ PTRACE_SETSIGMASK = 0x420b
+ PTRACE_SETVRREGS = 0x13
+ PTRACE_SETVSRREGS = 0x1c
+ PTRACE_SET_DEBUGREG = 0x1a
+ PTRACE_SINGLEBLOCK = 0x100
+ PTRACE_SINGLESTEP = 0x9
+ PTRACE_SYSCALL = 0x18
+ PTRACE_TRACEME = 0x0
+ PT_CCR = 0x26
+ PT_CTR = 0x23
+ PT_DAR = 0x29
+ PT_DSCR = 0x2c
+ PT_DSISR = 0x2a
+ PT_FPR0 = 0x30
+ PT_FPSCR = 0x50
+ PT_LNK = 0x24
+ PT_MSR = 0x21
+ PT_NIP = 0x20
+ PT_ORIG_R3 = 0x22
+ PT_R0 = 0x0
+ PT_R1 = 0x1
+ PT_R10 = 0xa
+ PT_R11 = 0xb
+ PT_R12 = 0xc
+ PT_R13 = 0xd
+ PT_R14 = 0xe
+ PT_R15 = 0xf
+ PT_R16 = 0x10
+ PT_R17 = 0x11
+ PT_R18 = 0x12
+ PT_R19 = 0x13
+ PT_R2 = 0x2
+ PT_R20 = 0x14
+ PT_R21 = 0x15
+ PT_R22 = 0x16
+ PT_R23 = 0x17
+ PT_R24 = 0x18
+ PT_R25 = 0x19
+ PT_R26 = 0x1a
+ PT_R27 = 0x1b
+ PT_R28 = 0x1c
+ PT_R29 = 0x1d
+ PT_R3 = 0x3
+ PT_R30 = 0x1e
+ PT_R31 = 0x1f
+ PT_R4 = 0x4
+ PT_R5 = 0x5
+ PT_R6 = 0x6
+ PT_R7 = 0x7
+ PT_R8 = 0x8
+ PT_R9 = 0x9
+ PT_REGS_COUNT = 0x2c
+ PT_RESULT = 0x2b
+ PT_SOFTE = 0x27
+ PT_TRAP = 0x28
+ PT_VR0 = 0x52
+ PT_VRSAVE = 0x94
+ PT_VSCR = 0x93
+ PT_VSR0 = 0x96
+ PT_VSR31 = 0xd4
+ PT_XER = 0x25
+ RLIMIT_AS = 0x9
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x7
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = -0x1
+ RTAX_ADVMSS = 0x8
+ RTAX_CWND = 0x7
+ RTAX_FEATURES = 0xc
+ RTAX_FEATURE_ALLFRAG = 0x8
+ RTAX_FEATURE_ECN = 0x1
+ RTAX_FEATURE_SACK = 0x2
+ RTAX_FEATURE_TIMESTAMP = 0x4
+ RTAX_HOPLIMIT = 0xa
+ RTAX_INITCWND = 0xb
+ RTAX_INITRWND = 0xe
+ RTAX_LOCK = 0x1
+ RTAX_MAX = 0xf
+ RTAX_MTU = 0x2
+ RTAX_QUICKACK = 0xf
+ RTAX_REORDERING = 0x9
+ RTAX_RTO_MIN = 0xd
+ RTAX_RTT = 0x4
+ RTAX_RTTVAR = 0x5
+ RTAX_SSTHRESH = 0x6
+ RTAX_UNSPEC = 0x0
+ RTAX_WINDOW = 0x3
+ RTA_ALIGNTO = 0x4
+ RTA_MAX = 0x11
+ RTCF_DIRECTSRC = 0x4000000
+ RTCF_DOREDIRECT = 0x1000000
+ RTCF_LOG = 0x2000000
+ RTCF_MASQ = 0x400000
+ RTCF_NAT = 0x800000
+ RTCF_VALVE = 0x200000
+ RTF_ADDRCLASSMASK = 0xf8000000
+ RTF_ADDRCONF = 0x40000
+ RTF_ALLONLINK = 0x20000
+ RTF_BROADCAST = 0x10000000
+ RTF_CACHE = 0x1000000
+ RTF_DEFAULT = 0x10000
+ RTF_DYNAMIC = 0x10
+ RTF_FLOW = 0x2000000
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_INTERFACE = 0x40000000
+ RTF_IRTT = 0x100
+ RTF_LINKRT = 0x100000
+ RTF_LOCAL = 0x80000000
+ RTF_MODIFIED = 0x20
+ RTF_MSS = 0x40
+ RTF_MTU = 0x40
+ RTF_MULTICAST = 0x20000000
+ RTF_NAT = 0x8000000
+ RTF_NOFORWARD = 0x1000
+ RTF_NONEXTHOP = 0x200000
+ RTF_NOPMTUDISC = 0x4000
+ RTF_POLICY = 0x4000000
+ RTF_REINSTATE = 0x8
+ RTF_REJECT = 0x200
+ RTF_STATIC = 0x400
+ RTF_THROW = 0x2000
+ RTF_UP = 0x1
+ RTF_WINDOW = 0x80
+ RTF_XRESOLVE = 0x800
+ RTM_BASE = 0x10
+ RTM_DELACTION = 0x31
+ RTM_DELADDR = 0x15
+ RTM_DELADDRLABEL = 0x49
+ RTM_DELLINK = 0x11
+ RTM_DELMDB = 0x55
+ RTM_DELNEIGH = 0x1d
+ RTM_DELQDISC = 0x25
+ RTM_DELROUTE = 0x19
+ RTM_DELRULE = 0x21
+ RTM_DELTCLASS = 0x29
+ RTM_DELTFILTER = 0x2d
+ RTM_F_CLONED = 0x200
+ RTM_F_EQUALIZE = 0x400
+ RTM_F_NOTIFY = 0x100
+ RTM_F_PREFIX = 0x800
+ RTM_GETACTION = 0x32
+ RTM_GETADDR = 0x16
+ RTM_GETADDRLABEL = 0x4a
+ RTM_GETANYCAST = 0x3e
+ RTM_GETDCB = 0x4e
+ RTM_GETLINK = 0x12
+ RTM_GETMDB = 0x56
+ RTM_GETMULTICAST = 0x3a
+ RTM_GETNEIGH = 0x1e
+ RTM_GETNEIGHTBL = 0x42
+ RTM_GETNETCONF = 0x52
+ RTM_GETQDISC = 0x26
+ RTM_GETROUTE = 0x1a
+ RTM_GETRULE = 0x22
+ RTM_GETTCLASS = 0x2a
+ RTM_GETTFILTER = 0x2e
+ RTM_MAX = 0x57
+ RTM_NEWACTION = 0x30
+ RTM_NEWADDR = 0x14
+ RTM_NEWADDRLABEL = 0x48
+ RTM_NEWLINK = 0x10
+ RTM_NEWMDB = 0x54
+ RTM_NEWNDUSEROPT = 0x44
+ RTM_NEWNEIGH = 0x1c
+ RTM_NEWNEIGHTBL = 0x40
+ RTM_NEWNETCONF = 0x50
+ RTM_NEWPREFIX = 0x34
+ RTM_NEWQDISC = 0x24
+ RTM_NEWROUTE = 0x18
+ RTM_NEWRULE = 0x20
+ RTM_NEWTCLASS = 0x28
+ RTM_NEWTFILTER = 0x2c
+ RTM_NR_FAMILIES = 0x12
+ RTM_NR_MSGTYPES = 0x48
+ RTM_SETDCB = 0x4f
+ RTM_SETLINK = 0x13
+ RTM_SETNEIGHTBL = 0x43
+ RTNH_ALIGNTO = 0x4
+ RTNH_F_DEAD = 0x1
+ RTNH_F_ONLINK = 0x4
+ RTNH_F_PERVASIVE = 0x2
+ RTN_MAX = 0xb
+ RTPROT_BIRD = 0xc
+ RTPROT_BOOT = 0x3
+ RTPROT_DHCP = 0x10
+ RTPROT_DNROUTED = 0xd
+ RTPROT_GATED = 0x8
+ RTPROT_KERNEL = 0x2
+ RTPROT_MROUTED = 0x11
+ RTPROT_MRT = 0xa
+ RTPROT_NTK = 0xf
+ RTPROT_RA = 0x9
+ RTPROT_REDIRECT = 0x1
+ RTPROT_STATIC = 0x4
+ RTPROT_UNSPEC = 0x0
+ RTPROT_XORP = 0xe
+ RTPROT_ZEBRA = 0xb
+ RT_CLASS_DEFAULT = 0xfd
+ RT_CLASS_LOCAL = 0xff
+ RT_CLASS_MAIN = 0xfe
+ RT_CLASS_MAX = 0xff
+ RT_CLASS_UNSPEC = 0x0
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
+ SCM_WIFI_STATUS = 0x29
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIOCADDDLCI = 0x8980
+ SIOCADDMULTI = 0x8931
+ SIOCADDRT = 0x890b
+ SIOCATMARK = 0x8905
+ SIOCDARP = 0x8953
+ SIOCDELDLCI = 0x8981
+ SIOCDELMULTI = 0x8932
+ SIOCDELRT = 0x890c
+ SIOCDEVPRIVATE = 0x89f0
+ SIOCDIFADDR = 0x8936
+ SIOCDRARP = 0x8960
+ SIOCGARP = 0x8954
+ SIOCGIFADDR = 0x8915
+ SIOCGIFBR = 0x8940
+ SIOCGIFBRDADDR = 0x8919
+ SIOCGIFCONF = 0x8912
+ SIOCGIFCOUNT = 0x8938
+ SIOCGIFDSTADDR = 0x8917
+ SIOCGIFENCAP = 0x8925
+ SIOCGIFFLAGS = 0x8913
+ SIOCGIFHWADDR = 0x8927
+ SIOCGIFINDEX = 0x8933
+ SIOCGIFMAP = 0x8970
+ SIOCGIFMEM = 0x891f
+ SIOCGIFMETRIC = 0x891d
+ SIOCGIFMTU = 0x8921
+ SIOCGIFNAME = 0x8910
+ SIOCGIFNETMASK = 0x891b
+ SIOCGIFPFLAGS = 0x8935
+ SIOCGIFSLAVE = 0x8929
+ SIOCGIFTXQLEN = 0x8942
+ SIOCGPGRP = 0x8904
+ SIOCGRARP = 0x8961
+ SIOCGSTAMP = 0x8906
+ SIOCGSTAMPNS = 0x8907
+ SIOCPROTOPRIVATE = 0x89e0
+ SIOCRTMSG = 0x890d
+ SIOCSARP = 0x8955
+ SIOCSIFADDR = 0x8916
+ SIOCSIFBR = 0x8941
+ SIOCSIFBRDADDR = 0x891a
+ SIOCSIFDSTADDR = 0x8918
+ SIOCSIFENCAP = 0x8926
+ SIOCSIFFLAGS = 0x8914
+ SIOCSIFHWADDR = 0x8924
+ SIOCSIFHWBROADCAST = 0x8937
+ SIOCSIFLINK = 0x8911
+ SIOCSIFMAP = 0x8971
+ SIOCSIFMEM = 0x8920
+ SIOCSIFMETRIC = 0x891e
+ SIOCSIFMTU = 0x8922
+ SIOCSIFNAME = 0x8923
+ SIOCSIFNETMASK = 0x891c
+ SIOCSIFPFLAGS = 0x8934
+ SIOCSIFSLAVE = 0x8930
+ SIOCSIFTXQLEN = 0x8943
+ SIOCSPGRP = 0x8902
+ SIOCSRARP = 0x8962
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DCCP = 0x6
+ SOCK_DGRAM = 0x2
+ SOCK_NONBLOCK = 0x800
+ SOCK_PACKET = 0xa
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_AAL = 0x109
+ SOL_ATM = 0x108
+ SOL_DECNET = 0x105
+ SOL_ICMPV6 = 0x3a
+ SOL_IP = 0x0
+ SOL_IPV6 = 0x29
+ SOL_IRDA = 0x10a
+ SOL_PACKET = 0x107
+ SOL_RAW = 0xff
+ SOL_SOCKET = 0x1
+ SOL_TCP = 0x6
+ SOL_X25 = 0x106
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x1e
+ SO_ATTACH_FILTER = 0x1a
+ SO_BINDTODEVICE = 0x19
+ SO_BROADCAST = 0x6
+ SO_BSDCOMPAT = 0xe
+ SO_BUSY_POLL = 0x2e
+ SO_DEBUG = 0x1
+ SO_DETACH_FILTER = 0x1b
+ SO_DOMAIN = 0x27
+ SO_DONTROUTE = 0x5
+ SO_ERROR = 0x4
+ SO_GET_FILTER = 0x1a
+ SO_KEEPALIVE = 0x9
+ SO_LINGER = 0xd
+ SO_LOCK_FILTER = 0x2c
+ SO_MARK = 0x24
+ SO_MAX_PACING_RATE = 0x2f
+ SO_NOFCS = 0x2b
+ SO_NO_CHECK = 0xb
+ SO_OOBINLINE = 0xa
+ SO_PASSCRED = 0x14
+ SO_PASSSEC = 0x22
+ SO_PEEK_OFF = 0x2a
+ SO_PEERCRED = 0x15
+ SO_PEERNAME = 0x1c
+ SO_PEERSEC = 0x1f
+ SO_PRIORITY = 0xc
+ SO_PROTOCOL = 0x26
+ SO_RCVBUF = 0x8
+ SO_RCVBUFFORCE = 0x21
+ SO_RCVLOWAT = 0x10
+ SO_RCVTIMEO = 0x12
+ SO_REUSEADDR = 0x2
+ SO_REUSEPORT = 0xf
+ SO_RXQ_OVFL = 0x28
+ SO_SECURITY_AUTHENTICATION = 0x16
+ SO_SECURITY_ENCRYPTION_NETWORK = 0x18
+ SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17
+ SO_SELECT_ERR_QUEUE = 0x2d
+ SO_SNDBUF = 0x7
+ SO_SNDBUFFORCE = 0x20
+ SO_SNDLOWAT = 0x11
+ SO_SNDTIMEO = 0x13
+ SO_TIMESTAMP = 0x1d
+ SO_TIMESTAMPING = 0x25
+ SO_TIMESTAMPNS = 0x23
+ SO_TYPE = 0x3
+ SO_WIFI_STATUS = 0x29
+ S_BLKSIZE = 0x200
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ TCFLSH = 0x2000741f
+ TCIFLUSH = 0x0
+ TCIOFLUSH = 0x2
+ TCOFLUSH = 0x1
+ TCP_CONGESTION = 0xd
+ TCP_COOKIE_IN_ALWAYS = 0x1
+ TCP_COOKIE_MAX = 0x10
+ TCP_COOKIE_MIN = 0x8
+ TCP_COOKIE_OUT_NEVER = 0x2
+ TCP_COOKIE_PAIR_SIZE = 0x20
+ TCP_COOKIE_TRANSACTIONS = 0xf
+ TCP_CORK = 0x3
+ TCP_DEFER_ACCEPT = 0x9
+ TCP_FASTOPEN = 0x17
+ TCP_INFO = 0xb
+ TCP_KEEPCNT = 0x6
+ TCP_KEEPIDLE = 0x4
+ TCP_KEEPINTVL = 0x5
+ TCP_LINGER2 = 0x8
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MD5SIG = 0xe
+ TCP_MD5SIG_MAXKEYLEN = 0x50
+ TCP_MSS = 0x200
+ TCP_MSS_DEFAULT = 0x218
+ TCP_MSS_DESIRED = 0x4c4
+ TCP_NODELAY = 0x1
+ TCP_QUEUE_SEQ = 0x15
+ TCP_QUICKACK = 0xc
+ TCP_REPAIR = 0x13
+ TCP_REPAIR_OPTIONS = 0x16
+ TCP_REPAIR_QUEUE = 0x14
+ TCP_SYNCNT = 0x7
+ TCP_S_DATA_IN = 0x4
+ TCP_S_DATA_OUT = 0x8
+ TCP_THIN_DUPACK = 0x11
+ TCP_THIN_LINEAR_TIMEOUTS = 0x10
+ TCP_TIMESTAMP = 0x18
+ TCP_USER_TIMEOUT = 0x12
+ TCP_WINDOW_CLAMP = 0xa
+ TCSAFLUSH = 0x2
+ TIOCCBRK = 0x5428
+ TIOCCONS = 0x541d
+ TIOCEXCL = 0x540c
+ TIOCGDEV = 0x40045432
+ TIOCGETC = 0x40067412
+ TIOCGETD = 0x5424
+ TIOCGETP = 0x40067408
+ TIOCGEXCL = 0x40045440
+ TIOCGICOUNT = 0x545d
+ TIOCGLCKTRMIOS = 0x5456
+ TIOCGLTC = 0x40067474
+ TIOCGPGRP = 0x40047477
+ TIOCGPKT = 0x40045438
+ TIOCGPTLCK = 0x40045439
+ TIOCGPTN = 0x40045430
+ TIOCGRS485 = 0x542e
+ TIOCGSERIAL = 0x541e
+ TIOCGSID = 0x5429
+ TIOCGSOFTCAR = 0x5419
+ TIOCGWINSZ = 0x40087468
+ TIOCINQ = 0x4004667f
+ TIOCLINUX = 0x541c
+ TIOCMBIC = 0x5417
+ TIOCMBIS = 0x5416
+ TIOCMGET = 0x5415
+ TIOCMIWAIT = 0x545c
+ TIOCMSET = 0x5418
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_LOOP = 0x8000
+ TIOCM_OUT1 = 0x2000
+ TIOCM_OUT2 = 0x4000
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x5422
+ TIOCNXCL = 0x540d
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x5420
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCSBRK = 0x5427
+ TIOCSCTTY = 0x540e
+ TIOCSERCONFIG = 0x5453
+ TIOCSERGETLSR = 0x5459
+ TIOCSERGETMULTI = 0x545a
+ TIOCSERGSTRUCT = 0x5458
+ TIOCSERGWILD = 0x5454
+ TIOCSERSETMULTI = 0x545b
+ TIOCSERSWILD = 0x5455
+ TIOCSER_TEMT = 0x1
+ TIOCSETC = 0x80067411
+ TIOCSETD = 0x5423
+ TIOCSETN = 0x8006740a
+ TIOCSETP = 0x80067409
+ TIOCSIG = 0x80045436
+ TIOCSLCKTRMIOS = 0x5457
+ TIOCSLTC = 0x80067475
+ TIOCSPGRP = 0x80047476
+ TIOCSPTLCK = 0x80045431
+ TIOCSRS485 = 0x542f
+ TIOCSSERIAL = 0x541f
+ TIOCSSOFTCAR = 0x541a
+ TIOCSTART = 0x2000746e
+ TIOCSTI = 0x5412
+ TIOCSTOP = 0x2000746f
+ TIOCSWINSZ = 0x80087467
+ TIOCVHANGUP = 0x5437
+ TOSTOP = 0x400000
+ TUNATTACHFILTER = 0x801054d5
+ TUNDETACHFILTER = 0x801054d6
+ TUNGETFEATURES = 0x400454cf
+ TUNGETFILTER = 0x401054db
+ TUNGETIFF = 0x400454d2
+ TUNGETSNDBUF = 0x400454d3
+ TUNGETVNETHDRSZ = 0x400454d7
+ TUNSETDEBUG = 0x800454c9
+ TUNSETGROUP = 0x800454ce
+ TUNSETIFF = 0x800454ca
+ TUNSETIFINDEX = 0x800454da
+ TUNSETLINK = 0x800454cd
+ TUNSETNOCSUM = 0x800454c8
+ TUNSETOFFLOAD = 0x800454d0
+ TUNSETOWNER = 0x800454cc
+ TUNSETPERSIST = 0x800454cb
+ TUNSETQUEUE = 0x800454d9
+ TUNSETSNDBUF = 0x800454d4
+ TUNSETTXFILTER = 0x800454d1
+ TUNSETVNETHDRSZ = 0x800454d8
+ VDISCARD = 0x10
+ VEOF = 0x4
+ VEOL = 0x6
+ VEOL2 = 0x8
+ VERASE = 0x2
+ VINTR = 0x0
+ VKILL = 0x3
+ VLNEXT = 0xf
+ VMIN = 0x5
+ VQUIT = 0x1
+ VREPRINT = 0xb
+ VSTART = 0xd
+ VSTOP = 0xe
+ VSUSP = 0xc
+ VSWTC = 0x9
+ VT0 = 0x0
+ VT1 = 0x10000
+ VTDLY = 0x10000
+ VTIME = 0x7
+ VWERASE = 0xa
+ WALL = 0x40000000
+ WCLONE = 0x80000000
+ WCONTINUED = 0x8
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOTHREAD = 0x20000000
+ WNOWAIT = 0x1000000
+ WORDSIZE = 0x40
+ WSTOPPED = 0x2
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x62)
+ EADDRNOTAVAIL = Errno(0x63)
+ EADV = Errno(0x44)
+ EAFNOSUPPORT = Errno(0x61)
+ EAGAIN = Errno(0xb)
+ EALREADY = Errno(0x72)
+ EBADE = Errno(0x34)
+ EBADF = Errno(0x9)
+ EBADFD = Errno(0x4d)
+ EBADMSG = Errno(0x4a)
+ EBADR = Errno(0x35)
+ EBADRQC = Errno(0x38)
+ EBADSLT = Errno(0x39)
+ EBFONT = Errno(0x3b)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x7d)
+ ECHILD = Errno(0xa)
+ ECHRNG = Errno(0x2c)
+ ECOMM = Errno(0x46)
+ ECONNABORTED = Errno(0x67)
+ ECONNREFUSED = Errno(0x6f)
+ ECONNRESET = Errno(0x68)
+ EDEADLK = Errno(0x23)
+ EDEADLOCK = Errno(0x3a)
+ EDESTADDRREQ = Errno(0x59)
+ EDOM = Errno(0x21)
+ EDOTDOT = Errno(0x49)
+ EDQUOT = Errno(0x7a)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EHOSTDOWN = Errno(0x70)
+ EHOSTUNREACH = Errno(0x71)
+ EHWPOISON = Errno(0x85)
+ EIDRM = Errno(0x2b)
+ EILSEQ = Errno(0x54)
+ EINPROGRESS = Errno(0x73)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x6a)
+ EISDIR = Errno(0x15)
+ EISNAM = Errno(0x78)
+ EKEYEXPIRED = Errno(0x7f)
+ EKEYREJECTED = Errno(0x81)
+ EKEYREVOKED = Errno(0x80)
+ EL2HLT = Errno(0x33)
+ EL2NSYNC = Errno(0x2d)
+ EL3HLT = Errno(0x2e)
+ EL3RST = Errno(0x2f)
+ ELIBACC = Errno(0x4f)
+ ELIBBAD = Errno(0x50)
+ ELIBEXEC = Errno(0x53)
+ ELIBMAX = Errno(0x52)
+ ELIBSCN = Errno(0x51)
+ ELNRNG = Errno(0x30)
+ ELOOP = Errno(0x28)
+ EMEDIUMTYPE = Errno(0x7c)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x5a)
+ EMULTIHOP = Errno(0x48)
+ ENAMETOOLONG = Errno(0x24)
+ ENAVAIL = Errno(0x77)
+ ENETDOWN = Errno(0x64)
+ ENETRESET = Errno(0x66)
+ ENETUNREACH = Errno(0x65)
+ ENFILE = Errno(0x17)
+ ENOANO = Errno(0x37)
+ ENOBUFS = Errno(0x69)
+ ENOCSI = Errno(0x32)
+ ENODATA = Errno(0x3d)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOKEY = Errno(0x7e)
+ ENOLCK = Errno(0x25)
+ ENOLINK = Errno(0x43)
+ ENOMEDIUM = Errno(0x7b)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x2a)
+ ENONET = Errno(0x40)
+ ENOPKG = Errno(0x41)
+ ENOPROTOOPT = Errno(0x5c)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x3f)
+ ENOSTR = Errno(0x3c)
+ ENOSYS = Errno(0x26)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x6b)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x27)
+ ENOTNAM = Errno(0x76)
+ ENOTRECOVERABLE = Errno(0x83)
+ ENOTSOCK = Errno(0x58)
+ ENOTSUP = Errno(0x5f)
+ ENOTTY = Errno(0x19)
+ ENOTUNIQ = Errno(0x4c)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x5f)
+ EOVERFLOW = Errno(0x4b)
+ EOWNERDEAD = Errno(0x82)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x60)
+ EPIPE = Errno(0x20)
+ EPROTO = Errno(0x47)
+ EPROTONOSUPPORT = Errno(0x5d)
+ EPROTOTYPE = Errno(0x5b)
+ ERANGE = Errno(0x22)
+ EREMCHG = Errno(0x4e)
+ EREMOTE = Errno(0x42)
+ EREMOTEIO = Errno(0x79)
+ ERESTART = Errno(0x55)
+ ERFKILL = Errno(0x84)
+ EROFS = Errno(0x1e)
+ ESHUTDOWN = Errno(0x6c)
+ ESOCKTNOSUPPORT = Errno(0x5e)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESRMNT = Errno(0x45)
+ ESTALE = Errno(0x74)
+ ESTRPIPE = Errno(0x56)
+ ETIME = Errno(0x3e)
+ ETIMEDOUT = Errno(0x6e)
+ ETOOMANYREFS = Errno(0x6d)
+ ETXTBSY = Errno(0x1a)
+ EUCLEAN = Errno(0x75)
+ EUNATCH = Errno(0x31)
+ EUSERS = Errno(0x57)
+ EWOULDBLOCK = Errno(0xb)
+ EXDEV = Errno(0x12)
+ EXFULL = Errno(0x36)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0x7)
+ SIGCHLD = Signal(0x11)
+ SIGCLD = Signal(0x11)
+ SIGCONT = Signal(0x12)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x1d)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPOLL = Signal(0x1d)
+ SIGPROF = Signal(0x1b)
+ SIGPWR = Signal(0x1e)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTKFLT = Signal(0x10)
+ SIGSTOP = Signal(0x13)
+ SIGSYS = Signal(0x1f)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x14)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGUNUSED = Signal(0x1f)
+ SIGURG = Signal(0x17)
+ SIGUSR1 = Signal(0xa)
+ SIGUSR2 = Signal(0xc)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "no such device or address",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource temporarily unavailable",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device or resource busy",
+ 17: "file exists",
+ 18: "invalid cross-device link",
+ 19: "no such device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "numerical result out of range",
+ 35: "resource deadlock avoided",
+ 36: "file name too long",
+ 37: "no locks available",
+ 38: "function not implemented",
+ 39: "directory not empty",
+ 40: "too many levels of symbolic links",
+ 42: "no message of desired type",
+ 43: "identifier removed",
+ 44: "channel number out of range",
+ 45: "level 2 not synchronized",
+ 46: "level 3 halted",
+ 47: "level 3 reset",
+ 48: "link number out of range",
+ 49: "protocol driver not attached",
+ 50: "no CSI structure available",
+ 51: "level 2 halted",
+ 52: "invalid exchange",
+ 53: "invalid request descriptor",
+ 54: "exchange full",
+ 55: "no anode",
+ 56: "invalid request code",
+ 57: "invalid slot",
+ 58: "file locking deadlock error",
+ 59: "bad font file format",
+ 60: "device not a stream",
+ 61: "no data available",
+ 62: "timer expired",
+ 63: "out of streams resources",
+ 64: "machine is not on the network",
+ 65: "package not installed",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
+ 71: "protocol error",
+ 72: "multihop attempted",
+ 73: "RFS specific error",
+ 74: "bad message",
+ 75: "value too large for defined data type",
+ 76: "name not unique on network",
+ 77: "file descriptor in bad state",
+ 78: "remote address changed",
+ 79: "can not access a needed shared library",
+ 80: "accessing a corrupted shared library",
+ 81: ".lib section in a.out corrupted",
+ 82: "attempting to link in too many shared libraries",
+ 83: "cannot exec a shared library directly",
+ 84: "invalid or incomplete multibyte or wide character",
+ 85: "interrupted system call should be restarted",
+ 86: "streams pipe error",
+ 87: "too many users",
+ 88: "socket operation on non-socket",
+ 89: "destination address required",
+ 90: "message too long",
+ 91: "protocol wrong type for socket",
+ 92: "protocol not available",
+ 93: "protocol not supported",
+ 94: "socket type not supported",
+ 95: "operation not supported",
+ 96: "protocol family not supported",
+ 97: "address family not supported by protocol",
+ 98: "address already in use",
+ 99: "cannot assign requested address",
+ 100: "network is down",
+ 101: "network is unreachable",
+ 102: "network dropped connection on reset",
+ 103: "software caused connection abort",
+ 104: "connection reset by peer",
+ 105: "no buffer space available",
+ 106: "transport endpoint is already connected",
+ 107: "transport endpoint is not connected",
+ 108: "cannot send after transport endpoint shutdown",
+ 109: "too many references: cannot splice",
+ 110: "connection timed out",
+ 111: "connection refused",
+ 112: "host is down",
+ 113: "no route to host",
+ 114: "operation already in progress",
+ 115: "operation now in progress",
+ 116: "stale file handle",
+ 117: "structure needs cleaning",
+ 118: "not a XENIX named type file",
+ 119: "no XENIX semaphores available",
+ 120: "is a named type file",
+ 121: "remote I/O error",
+ 122: "disk quota exceeded",
+ 123: "no medium found",
+ 124: "wrong medium type",
+ 125: "operation canceled",
+ 126: "required key not available",
+ 127: "key has expired",
+ 128: "key has been revoked",
+ 129: "key was rejected by service",
+ 130: "owner died",
+ 131: "state not recoverable",
+ 132: "operation not possible due to RF-kill",
+ 133: "memory page has hardware error",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/breakpoint trap",
+ 6: "aborted",
+ 7: "bus error",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "user defined signal 1",
+ 11: "segmentation fault",
+ 12: "user defined signal 2",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "stack fault",
+ 17: "child exited",
+ 18: "continued",
+ 19: "stopped (signal)",
+ 20: "stopped",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "urgent I/O condition",
+ 24: "CPU time limit exceeded",
+ 25: "file size limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window changed",
+ 29: "I/O possible",
+ 30: "power failure",
+ 31: "bad system call",
+}
diff --git a/src/syscall/zsyscall_linux_power64.go b/src/syscall/zsyscall_linux_power64.go
new file mode 100644
index 000000000..7808059cc
--- /dev/null
+++ b/src/syscall/zsyscall_linux_power64.go
@@ -0,0 +1,1931 @@
+// mksyscall.pl syscall_linux.go syscall_linux_power64x.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func open(path string, mode int, perm uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe(p *[2]_C_int) (err error) {
+ _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe2(p *[2]_C_int, flags int) (err error) {
+ _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, times *[2]Timeval) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getcwd(buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+ r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+ wpid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(arg)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(source)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(target)
+ if err != nil {
+ return
+ }
+ var _p2 *byte
+ _p2, err = BytePtrFromString(fstype)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Acct(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtimex(buf *Timex) (state int, err error) {
+ r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
+ state = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Creat(path string, mode uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup3(oldfd int, newfd int, flags int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate(size int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate1(flag int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
+ _, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(events) > 0 {
+ _p0 = unsafe.Pointer(&events[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+ Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fdatasync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettid() (tid int) {
+ r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ tid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ var _p2 unsafe.Pointer
+ if len(dest) > 0 {
+ _p2 = unsafe.Pointer(&dest[0])
+ } else {
+ _p2 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
+ sz = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(pathname)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask))
+ watchdesc = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit1(flags int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
+ success = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, sig Signal) (err error) {
+ _, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Klogctl(typ int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(oldpath string, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listxattr(path string, dest []byte) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(dest) > 0 {
+ _p1 = unsafe.Pointer(&dest[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
+ sz = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdirat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+ _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pause() (err error) {
+ _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func PivotRoot(newroot string, putold string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(newroot)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(putold)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(buf) > 0 {
+ _p1 = unsafe.Pointer(&buf[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Removexattr(path string, attr string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(oldpath string, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setdomainname(p []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sethostname(p []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setxattr(path string, attr string, data []byte, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ var _p2 unsafe.Pointer
+ if len(data) > 0 {
+ _p2 = unsafe.Pointer(&data[0])
+ } else {
+ _p2 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(oldpath string, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() {
+ Syscall(SYS_SYNC, 0, 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sysinfo(info *Sysinfo_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
+ r0, _, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
+ n = int64(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Tgkill(tgid int, tid int, sig Signal) (err error) {
+ _, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Times(tms *Tms) (ticks uintptr, err error) {
+ r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
+ ticks = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(mask int) (oldmask int) {
+ r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Uname(buf *Utsname) (err error) {
+ _, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlinkat(dirfd int, path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(target string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(target)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unshare(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ustat(dev int, ubuf *Ustat_t) (err error) {
+ _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Utime(path string, buf *Utimbuf) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func exitThread(code int) (err error) {
+ _, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlen(fd int, p *byte, np int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writelen(fd int, p *byte, np int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Madvise(b []byte, advice int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstatfs(fd int, buf *Statfs_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+ r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (euid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ euid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(resource int, rlim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_UGETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ioperm(from int, num int, on int) (err error) {
+ _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Iopl(level int) (err error) {
+ _, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, n int) (err error) {
+ _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seek(fd int, offset int64, whence int) (off int64, err error) {
+ r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
+ off = int64(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
+ r0, _, e1 := Syscall6(SYS_SELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ r0, _, e1 := Syscall6(SYS_SENDFILE, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
+ written = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setfsgid(gid int) (err error) {
+ _, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setfsuid(uid int) (err error) {
+ _, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresgid(rgid int, egid int, sgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresuid(ruid int, euid int, suid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(resource int, rlim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) {
+ r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
+ n = int64(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Statfs(path string, buf *Statfs_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
+ _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
+ r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(n int, list *_Gid_t) (nn int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ nn = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(n int, list *_Gid_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+ _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
+ r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset))
+ xaddr = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Time(t *Time_t) (tt Time_t, err error) {
+ r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
+ tt = Time_t(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/syscall/zsyscall_linux_power64le.go b/src/syscall/zsyscall_linux_power64le.go
new file mode 100644
index 000000000..7808059cc
--- /dev/null
+++ b/src/syscall/zsyscall_linux_power64le.go
@@ -0,0 +1,1931 @@
+// mksyscall.pl syscall_linux.go syscall_linux_power64x.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func open(path string, mode int, perm uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe(p *[2]_C_int) (err error) {
+ _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe2(p *[2]_C_int, flags int) (err error) {
+ _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, times *[2]Timeval) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getcwd(buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+ r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+ wpid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(arg)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(source)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(target)
+ if err != nil {
+ return
+ }
+ var _p2 *byte
+ _p2, err = BytePtrFromString(fstype)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Acct(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtimex(buf *Timex) (state int, err error) {
+ r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
+ state = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Creat(path string, mode uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup3(oldfd int, newfd int, flags int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate(size int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate1(flag int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
+ _, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(events) > 0 {
+ _p0 = unsafe.Pointer(&events[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+ Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fdatasync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettid() (tid int) {
+ r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ tid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ var _p2 unsafe.Pointer
+ if len(dest) > 0 {
+ _p2 = unsafe.Pointer(&dest[0])
+ } else {
+ _p2 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
+ sz = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(pathname)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask))
+ watchdesc = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit1(flags int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
+ success = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, sig Signal) (err error) {
+ _, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Klogctl(typ int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(oldpath string, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listxattr(path string, dest []byte) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(dest) > 0 {
+ _p1 = unsafe.Pointer(&dest[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
+ sz = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdirat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+ _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pause() (err error) {
+ _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func PivotRoot(newroot string, putold string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(newroot)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(putold)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(buf) > 0 {
+ _p1 = unsafe.Pointer(&buf[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Removexattr(path string, attr string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(oldpath string, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setdomainname(p []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sethostname(p []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setxattr(path string, attr string, data []byte, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ var _p2 unsafe.Pointer
+ if len(data) > 0 {
+ _p2 = unsafe.Pointer(&data[0])
+ } else {
+ _p2 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(oldpath string, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() {
+ Syscall(SYS_SYNC, 0, 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sysinfo(info *Sysinfo_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
+ r0, _, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
+ n = int64(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Tgkill(tgid int, tid int, sig Signal) (err error) {
+ _, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Times(tms *Tms) (ticks uintptr, err error) {
+ r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
+ ticks = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(mask int) (oldmask int) {
+ r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Uname(buf *Utsname) (err error) {
+ _, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlinkat(dirfd int, path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(target string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(target)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unshare(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ustat(dev int, ubuf *Ustat_t) (err error) {
+ _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Utime(path string, buf *Utimbuf) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func exitThread(code int) (err error) {
+ _, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlen(fd int, p *byte, np int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writelen(fd int, p *byte, np int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Madvise(b []byte, advice int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstatfs(fd int, buf *Statfs_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+ r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (euid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ euid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(resource int, rlim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_UGETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ioperm(from int, num int, on int) (err error) {
+ _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Iopl(level int) (err error) {
+ _, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, n int) (err error) {
+ _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seek(fd int, offset int64, whence int) (off int64, err error) {
+ r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
+ off = int64(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
+ r0, _, e1 := Syscall6(SYS_SELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ r0, _, e1 := Syscall6(SYS_SENDFILE, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
+ written = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setfsgid(gid int) (err error) {
+ _, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setfsuid(uid int) (err error) {
+ _, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresgid(rgid int, egid int, sgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresuid(ruid int, euid int, suid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(resource int, rlim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) {
+ r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
+ n = int64(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Statfs(path string, buf *Statfs_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
+ _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
+ r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(n int, list *_Gid_t) (nn int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ nn = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(n int, list *_Gid_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+ _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
+ r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset))
+ xaddr = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Time(t *Time_t) (tt Time_t, err error) {
+ r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
+ tt = Time_t(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/syscall/zsysnum_linux_power64.go b/src/syscall/zsysnum_linux_power64.go
new file mode 100644
index 000000000..0567fd0ea
--- /dev/null
+++ b/src/syscall/zsysnum_linux_power64.go
@@ -0,0 +1,351 @@
+// mksysnum_linux.pl /usr/include/asm/unistd.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_RESTART_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_WAITPID = 7
+ SYS_CREAT = 8
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_EXECVE = 11
+ SYS_CHDIR = 12
+ SYS_TIME = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_LCHOWN = 16
+ SYS_BREAK = 17
+ SYS_OLDSTAT = 18
+ SYS_LSEEK = 19
+ SYS_GETPID = 20
+ SYS_MOUNT = 21
+ SYS_UMOUNT = 22
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_STIME = 25
+ SYS_PTRACE = 26
+ SYS_ALARM = 27
+ SYS_OLDFSTAT = 28
+ SYS_PAUSE = 29
+ SYS_UTIME = 30
+ SYS_STTY = 31
+ SYS_GTTY = 32
+ SYS_ACCESS = 33
+ SYS_NICE = 34
+ SYS_FTIME = 35
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_RENAME = 38
+ SYS_MKDIR = 39
+ SYS_RMDIR = 40
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_TIMES = 43
+ SYS_PROF = 44
+ SYS_BRK = 45
+ SYS_SETGID = 46
+ SYS_GETGID = 47
+ SYS_SIGNAL = 48
+ SYS_GETEUID = 49
+ SYS_GETEGID = 50
+ SYS_ACCT = 51
+ SYS_UMOUNT2 = 52
+ SYS_LOCK = 53
+ SYS_IOCTL = 54
+ SYS_FCNTL = 55
+ SYS_MPX = 56
+ SYS_SETPGID = 57
+ SYS_ULIMIT = 58
+ SYS_OLDOLDUNAME = 59
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_USTAT = 62
+ SYS_DUP2 = 63
+ SYS_GETPPID = 64
+ SYS_GETPGRP = 65
+ SYS_SETSID = 66
+ SYS_SIGACTION = 67
+ SYS_SGETMASK = 68
+ SYS_SSETMASK = 69
+ SYS_SETREUID = 70
+ SYS_SETREGID = 71
+ SYS_SIGSUSPEND = 72
+ SYS_SIGPENDING = 73
+ SYS_SETHOSTNAME = 74
+ SYS_SETRLIMIT = 75
+ SYS_GETRLIMIT = 76
+ SYS_GETRUSAGE = 77
+ SYS_GETTIMEOFDAY = 78
+ SYS_SETTIMEOFDAY = 79
+ SYS_GETGROUPS = 80
+ SYS_SETGROUPS = 81
+ SYS_SELECT = 82
+ SYS_SYMLINK = 83
+ SYS_OLDLSTAT = 84
+ SYS_READLINK = 85
+ SYS_USELIB = 86
+ SYS_SWAPON = 87
+ SYS_REBOOT = 88
+ SYS_READDIR = 89
+ SYS_MMAP = 90
+ SYS_MUNMAP = 91
+ SYS_TRUNCATE = 92
+ SYS_FTRUNCATE = 93
+ SYS_FCHMOD = 94
+ SYS_FCHOWN = 95
+ SYS_GETPRIORITY = 96
+ SYS_SETPRIORITY = 97
+ SYS_PROFIL = 98
+ SYS_STATFS = 99
+ SYS_FSTATFS = 100
+ SYS_IOPERM = 101
+ SYS_SOCKETCALL = 102
+ SYS_SYSLOG = 103
+ SYS_SETITIMER = 104
+ SYS_GETITIMER = 105
+ SYS_STAT = 106
+ SYS_LSTAT = 107
+ SYS_FSTAT = 108
+ SYS_OLDUNAME = 109
+ SYS_IOPL = 110
+ SYS_VHANGUP = 111
+ SYS_IDLE = 112
+ SYS_VM86 = 113
+ SYS_WAIT4 = 114
+ SYS_SWAPOFF = 115
+ SYS_SYSINFO = 116
+ SYS_IPC = 117
+ SYS_FSYNC = 118
+ SYS_SIGRETURN = 119
+ SYS_CLONE = 120
+ SYS_SETDOMAINNAME = 121
+ SYS_UNAME = 122
+ SYS_MODIFY_LDT = 123
+ SYS_ADJTIMEX = 124
+ SYS_MPROTECT = 125
+ SYS_SIGPROCMASK = 126
+ SYS_CREATE_MODULE = 127
+ SYS_INIT_MODULE = 128
+ SYS_DELETE_MODULE = 129
+ SYS_GET_KERNEL_SYMS = 130
+ SYS_QUOTACTL = 131
+ SYS_GETPGID = 132
+ SYS_FCHDIR = 133
+ SYS_BDFLUSH = 134
+ SYS_SYSFS = 135
+ SYS_PERSONALITY = 136
+ SYS_AFS_SYSCALL = 137
+ SYS_SETFSUID = 138
+ SYS_SETFSGID = 139
+ SYS__LLSEEK = 140
+ SYS_GETDENTS = 141
+ SYS__NEWSELECT = 142
+ SYS_FLOCK = 143
+ SYS_MSYNC = 144
+ SYS_READV = 145
+ SYS_WRITEV = 146
+ SYS_GETSID = 147
+ SYS_FDATASYNC = 148
+ SYS__SYSCTL = 149
+ SYS_MLOCK = 150
+ SYS_MUNLOCK = 151
+ SYS_MLOCKALL = 152
+ SYS_MUNLOCKALL = 153
+ SYS_SCHED_SETPARAM = 154
+ SYS_SCHED_GETPARAM = 155
+ SYS_SCHED_SETSCHEDULER = 156
+ SYS_SCHED_GETSCHEDULER = 157
+ SYS_SCHED_YIELD = 158
+ SYS_SCHED_GET_PRIORITY_MAX = 159
+ SYS_SCHED_GET_PRIORITY_MIN = 160
+ SYS_SCHED_RR_GET_INTERVAL = 161
+ SYS_NANOSLEEP = 162
+ SYS_MREMAP = 163
+ SYS_SETRESUID = 164
+ SYS_GETRESUID = 165
+ SYS_QUERY_MODULE = 166
+ SYS_POLL = 167
+ SYS_NFSSERVCTL = 168
+ SYS_SETRESGID = 169
+ SYS_GETRESGID = 170
+ SYS_PRCTL = 171
+ SYS_RT_SIGRETURN = 172
+ SYS_RT_SIGACTION = 173
+ SYS_RT_SIGPROCMASK = 174
+ SYS_RT_SIGPENDING = 175
+ SYS_RT_SIGTIMEDWAIT = 176
+ SYS_RT_SIGQUEUEINFO = 177
+ SYS_RT_SIGSUSPEND = 178
+ SYS_PREAD64 = 179
+ SYS_PWRITE64 = 180
+ SYS_CHOWN = 181
+ SYS_GETCWD = 182
+ SYS_CAPGET = 183
+ SYS_CAPSET = 184
+ SYS_SIGALTSTACK = 185
+ SYS_SENDFILE = 186
+ SYS_GETPMSG = 187
+ SYS_PUTPMSG = 188
+ SYS_VFORK = 189
+ SYS_UGETRLIMIT = 190
+ SYS_READAHEAD = 191
+ SYS_PCICONFIG_READ = 198
+ SYS_PCICONFIG_WRITE = 199
+ SYS_PCICONFIG_IOBASE = 200
+ SYS_MULTIPLEXER = 201
+ SYS_GETDENTS64 = 202
+ SYS_PIVOT_ROOT = 203
+ SYS_MADVISE = 205
+ SYS_MINCORE = 206
+ SYS_GETTID = 207
+ SYS_TKILL = 208
+ SYS_SETXATTR = 209
+ SYS_LSETXATTR = 210
+ SYS_FSETXATTR = 211
+ SYS_GETXATTR = 212
+ SYS_LGETXATTR = 213
+ SYS_FGETXATTR = 214
+ SYS_LISTXATTR = 215
+ SYS_LLISTXATTR = 216
+ SYS_FLISTXATTR = 217
+ SYS_REMOVEXATTR = 218
+ SYS_LREMOVEXATTR = 219
+ SYS_FREMOVEXATTR = 220
+ SYS_FUTEX = 221
+ SYS_SCHED_SETAFFINITY = 222
+ SYS_SCHED_GETAFFINITY = 223
+ SYS_TUXCALL = 225
+ SYS_IO_SETUP = 227
+ SYS_IO_DESTROY = 228
+ SYS_IO_GETEVENTS = 229
+ SYS_IO_SUBMIT = 230
+ SYS_IO_CANCEL = 231
+ SYS_SET_TID_ADDRESS = 232
+ SYS_FADVISE64 = 233
+ SYS_EXIT_GROUP = 234
+ SYS_LOOKUP_DCOOKIE = 235
+ SYS_EPOLL_CREATE = 236
+ SYS_EPOLL_CTL = 237
+ SYS_EPOLL_WAIT = 238
+ SYS_REMAP_FILE_PAGES = 239
+ SYS_TIMER_CREATE = 240
+ SYS_TIMER_SETTIME = 241
+ SYS_TIMER_GETTIME = 242
+ SYS_TIMER_GETOVERRUN = 243
+ SYS_TIMER_DELETE = 244
+ SYS_CLOCK_SETTIME = 245
+ SYS_CLOCK_GETTIME = 246
+ SYS_CLOCK_GETRES = 247
+ SYS_CLOCK_NANOSLEEP = 248
+ SYS_SWAPCONTEXT = 249
+ SYS_TGKILL = 250
+ SYS_UTIMES = 251
+ SYS_STATFS64 = 252
+ SYS_FSTATFS64 = 253
+ SYS_RTAS = 255
+ SYS_SYS_DEBUG_SETCONTEXT = 256
+ SYS_MIGRATE_PAGES = 258
+ SYS_MBIND = 259
+ SYS_GET_MEMPOLICY = 260
+ SYS_SET_MEMPOLICY = 261
+ SYS_MQ_OPEN = 262
+ SYS_MQ_UNLINK = 263
+ SYS_MQ_TIMEDSEND = 264
+ SYS_MQ_TIMEDRECEIVE = 265
+ SYS_MQ_NOTIFY = 266
+ SYS_MQ_GETSETATTR = 267
+ SYS_KEXEC_LOAD = 268
+ SYS_ADD_KEY = 269
+ SYS_REQUEST_KEY = 270
+ SYS_KEYCTL = 271
+ SYS_WAITID = 272
+ SYS_IOPRIO_SET = 273
+ SYS_IOPRIO_GET = 274
+ SYS_INOTIFY_INIT = 275
+ SYS_INOTIFY_ADD_WATCH = 276
+ SYS_INOTIFY_RM_WATCH = 277
+ SYS_SPU_RUN = 278
+ SYS_SPU_CREATE = 279
+ SYS_PSELECT6 = 280
+ SYS_PPOLL = 281
+ SYS_UNSHARE = 282
+ SYS_SPLICE = 283
+ SYS_TEE = 284
+ SYS_VMSPLICE = 285
+ SYS_OPENAT = 286
+ SYS_MKDIRAT = 287
+ SYS_MKNODAT = 288
+ SYS_FCHOWNAT = 289
+ SYS_FUTIMESAT = 290
+ SYS_NEWFSTATAT = 291
+ SYS_UNLINKAT = 292
+ SYS_RENAMEAT = 293
+ SYS_LINKAT = 294
+ SYS_SYMLINKAT = 295
+ SYS_READLINKAT = 296
+ SYS_FCHMODAT = 297
+ SYS_FACCESSAT = 298
+ SYS_GET_ROBUST_LIST = 299
+ SYS_SET_ROBUST_LIST = 300
+ SYS_MOVE_PAGES = 301
+ SYS_GETCPU = 302
+ SYS_EPOLL_PWAIT = 303
+ SYS_UTIMENSAT = 304
+ SYS_SIGNALFD = 305
+ SYS_TIMERFD_CREATE = 306
+ SYS_EVENTFD = 307
+ SYS_SYNC_FILE_RANGE2 = 308
+ SYS_FALLOCATE = 309
+ SYS_SUBPAGE_PROT = 310
+ SYS_TIMERFD_SETTIME = 311
+ SYS_TIMERFD_GETTIME = 312
+ SYS_SIGNALFD4 = 313
+ SYS_EVENTFD2 = 314
+ SYS_EPOLL_CREATE1 = 315
+ SYS_DUP3 = 316
+ SYS_PIPE2 = 317
+ SYS_INOTIFY_INIT1 = 318
+ SYS_PERF_EVENT_OPEN = 319
+ SYS_PREADV = 320
+ SYS_PWRITEV = 321
+ SYS_RT_TGSIGQUEUEINFO = 322
+ SYS_FANOTIFY_INIT = 323
+ SYS_FANOTIFY_MARK = 324
+ SYS_PRLIMIT64 = 325
+ SYS_SOCKET = 326
+ SYS_BIND = 327
+ SYS_CONNECT = 328
+ SYS_LISTEN = 329
+ SYS_ACCEPT = 330
+ SYS_GETSOCKNAME = 331
+ SYS_GETPEERNAME = 332
+ SYS_SOCKETPAIR = 333
+ SYS_SEND = 334
+ SYS_SENDTO = 335
+ SYS_RECV = 336
+ SYS_RECVFROM = 337
+ SYS_SHUTDOWN = 338
+ SYS_SETSOCKOPT = 339
+ SYS_GETSOCKOPT = 340
+ SYS_SENDMSG = 341
+ SYS_RECVMSG = 342
+ SYS_RECVMMSG = 343
+ SYS_ACCEPT4 = 344
+ SYS_NAME_TO_HANDLE_AT = 345
+ SYS_OPEN_BY_HANDLE_AT = 346
+ SYS_CLOCK_ADJTIME = 347
+ SYS_SYNCFS = 348
+ SYS_SENDMMSG = 349
+ SYS_SETNS = 350
+ SYS_PROCESS_VM_READV = 351
+ SYS_PROCESS_VM_WRITEV = 352
+ SYS_FINIT_MODULE = 353
+ SYS_KCMP = 354
+)
diff --git a/src/syscall/zsysnum_linux_power64le.go b/src/syscall/zsysnum_linux_power64le.go
new file mode 100644
index 000000000..52c63e3d3
--- /dev/null
+++ b/src/syscall/zsysnum_linux_power64le.go
@@ -0,0 +1,351 @@
+// mksysnum_linux.pl /usr/include/powerpc64le-linux-gnu/asm/unistd.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_RESTART_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_WAITPID = 7
+ SYS_CREAT = 8
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_EXECVE = 11
+ SYS_CHDIR = 12
+ SYS_TIME = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_LCHOWN = 16
+ SYS_BREAK = 17
+ SYS_OLDSTAT = 18
+ SYS_LSEEK = 19
+ SYS_GETPID = 20
+ SYS_MOUNT = 21
+ SYS_UMOUNT = 22
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_STIME = 25
+ SYS_PTRACE = 26
+ SYS_ALARM = 27
+ SYS_OLDFSTAT = 28
+ SYS_PAUSE = 29
+ SYS_UTIME = 30
+ SYS_STTY = 31
+ SYS_GTTY = 32
+ SYS_ACCESS = 33
+ SYS_NICE = 34
+ SYS_FTIME = 35
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_RENAME = 38
+ SYS_MKDIR = 39
+ SYS_RMDIR = 40
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_TIMES = 43
+ SYS_PROF = 44
+ SYS_BRK = 45
+ SYS_SETGID = 46
+ SYS_GETGID = 47
+ SYS_SIGNAL = 48
+ SYS_GETEUID = 49
+ SYS_GETEGID = 50
+ SYS_ACCT = 51
+ SYS_UMOUNT2 = 52
+ SYS_LOCK = 53
+ SYS_IOCTL = 54
+ SYS_FCNTL = 55
+ SYS_MPX = 56
+ SYS_SETPGID = 57
+ SYS_ULIMIT = 58
+ SYS_OLDOLDUNAME = 59
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_USTAT = 62
+ SYS_DUP2 = 63
+ SYS_GETPPID = 64
+ SYS_GETPGRP = 65
+ SYS_SETSID = 66
+ SYS_SIGACTION = 67
+ SYS_SGETMASK = 68
+ SYS_SSETMASK = 69
+ SYS_SETREUID = 70
+ SYS_SETREGID = 71
+ SYS_SIGSUSPEND = 72
+ SYS_SIGPENDING = 73
+ SYS_SETHOSTNAME = 74
+ SYS_SETRLIMIT = 75
+ SYS_GETRLIMIT = 76
+ SYS_GETRUSAGE = 77
+ SYS_GETTIMEOFDAY = 78
+ SYS_SETTIMEOFDAY = 79
+ SYS_GETGROUPS = 80
+ SYS_SETGROUPS = 81
+ SYS_SELECT = 82
+ SYS_SYMLINK = 83
+ SYS_OLDLSTAT = 84
+ SYS_READLINK = 85
+ SYS_USELIB = 86
+ SYS_SWAPON = 87
+ SYS_REBOOT = 88
+ SYS_READDIR = 89
+ SYS_MMAP = 90
+ SYS_MUNMAP = 91
+ SYS_TRUNCATE = 92
+ SYS_FTRUNCATE = 93
+ SYS_FCHMOD = 94
+ SYS_FCHOWN = 95
+ SYS_GETPRIORITY = 96
+ SYS_SETPRIORITY = 97
+ SYS_PROFIL = 98
+ SYS_STATFS = 99
+ SYS_FSTATFS = 100
+ SYS_IOPERM = 101
+ SYS_SOCKETCALL = 102
+ SYS_SYSLOG = 103
+ SYS_SETITIMER = 104
+ SYS_GETITIMER = 105
+ SYS_STAT = 106
+ SYS_LSTAT = 107
+ SYS_FSTAT = 108
+ SYS_OLDUNAME = 109
+ SYS_IOPL = 110
+ SYS_VHANGUP = 111
+ SYS_IDLE = 112
+ SYS_VM86 = 113
+ SYS_WAIT4 = 114
+ SYS_SWAPOFF = 115
+ SYS_SYSINFO = 116
+ SYS_IPC = 117
+ SYS_FSYNC = 118
+ SYS_SIGRETURN = 119
+ SYS_CLONE = 120
+ SYS_SETDOMAINNAME = 121
+ SYS_UNAME = 122
+ SYS_MODIFY_LDT = 123
+ SYS_ADJTIMEX = 124
+ SYS_MPROTECT = 125
+ SYS_SIGPROCMASK = 126
+ SYS_CREATE_MODULE = 127
+ SYS_INIT_MODULE = 128
+ SYS_DELETE_MODULE = 129
+ SYS_GET_KERNEL_SYMS = 130
+ SYS_QUOTACTL = 131
+ SYS_GETPGID = 132
+ SYS_FCHDIR = 133
+ SYS_BDFLUSH = 134
+ SYS_SYSFS = 135
+ SYS_PERSONALITY = 136
+ SYS_AFS_SYSCALL = 137
+ SYS_SETFSUID = 138
+ SYS_SETFSGID = 139
+ SYS__LLSEEK = 140
+ SYS_GETDENTS = 141
+ SYS__NEWSELECT = 142
+ SYS_FLOCK = 143
+ SYS_MSYNC = 144
+ SYS_READV = 145
+ SYS_WRITEV = 146
+ SYS_GETSID = 147
+ SYS_FDATASYNC = 148
+ SYS__SYSCTL = 149
+ SYS_MLOCK = 150
+ SYS_MUNLOCK = 151
+ SYS_MLOCKALL = 152
+ SYS_MUNLOCKALL = 153
+ SYS_SCHED_SETPARAM = 154
+ SYS_SCHED_GETPARAM = 155
+ SYS_SCHED_SETSCHEDULER = 156
+ SYS_SCHED_GETSCHEDULER = 157
+ SYS_SCHED_YIELD = 158
+ SYS_SCHED_GET_PRIORITY_MAX = 159
+ SYS_SCHED_GET_PRIORITY_MIN = 160
+ SYS_SCHED_RR_GET_INTERVAL = 161
+ SYS_NANOSLEEP = 162
+ SYS_MREMAP = 163
+ SYS_SETRESUID = 164
+ SYS_GETRESUID = 165
+ SYS_QUERY_MODULE = 166
+ SYS_POLL = 167
+ SYS_NFSSERVCTL = 168
+ SYS_SETRESGID = 169
+ SYS_GETRESGID = 170
+ SYS_PRCTL = 171
+ SYS_RT_SIGRETURN = 172
+ SYS_RT_SIGACTION = 173
+ SYS_RT_SIGPROCMASK = 174
+ SYS_RT_SIGPENDING = 175
+ SYS_RT_SIGTIMEDWAIT = 176
+ SYS_RT_SIGQUEUEINFO = 177
+ SYS_RT_SIGSUSPEND = 178
+ SYS_PREAD64 = 179
+ SYS_PWRITE64 = 180
+ SYS_CHOWN = 181
+ SYS_GETCWD = 182
+ SYS_CAPGET = 183
+ SYS_CAPSET = 184
+ SYS_SIGALTSTACK = 185
+ SYS_SENDFILE = 186
+ SYS_GETPMSG = 187
+ SYS_PUTPMSG = 188
+ SYS_VFORK = 189
+ SYS_UGETRLIMIT = 190
+ SYS_READAHEAD = 191
+ SYS_PCICONFIG_READ = 198
+ SYS_PCICONFIG_WRITE = 199
+ SYS_PCICONFIG_IOBASE = 200
+ SYS_MULTIPLEXER = 201
+ SYS_GETDENTS64 = 202
+ SYS_PIVOT_ROOT = 203
+ SYS_MADVISE = 205
+ SYS_MINCORE = 206
+ SYS_GETTID = 207
+ SYS_TKILL = 208
+ SYS_SETXATTR = 209
+ SYS_LSETXATTR = 210
+ SYS_FSETXATTR = 211
+ SYS_GETXATTR = 212
+ SYS_LGETXATTR = 213
+ SYS_FGETXATTR = 214
+ SYS_LISTXATTR = 215
+ SYS_LLISTXATTR = 216
+ SYS_FLISTXATTR = 217
+ SYS_REMOVEXATTR = 218
+ SYS_LREMOVEXATTR = 219
+ SYS_FREMOVEXATTR = 220
+ SYS_FUTEX = 221
+ SYS_SCHED_SETAFFINITY = 222
+ SYS_SCHED_GETAFFINITY = 223
+ SYS_TUXCALL = 225
+ SYS_IO_SETUP = 227
+ SYS_IO_DESTROY = 228
+ SYS_IO_GETEVENTS = 229
+ SYS_IO_SUBMIT = 230
+ SYS_IO_CANCEL = 231
+ SYS_SET_TID_ADDRESS = 232
+ SYS_FADVISE64 = 233
+ SYS_EXIT_GROUP = 234
+ SYS_LOOKUP_DCOOKIE = 235
+ SYS_EPOLL_CREATE = 236
+ SYS_EPOLL_CTL = 237
+ SYS_EPOLL_WAIT = 238
+ SYS_REMAP_FILE_PAGES = 239
+ SYS_TIMER_CREATE = 240
+ SYS_TIMER_SETTIME = 241
+ SYS_TIMER_GETTIME = 242
+ SYS_TIMER_GETOVERRUN = 243
+ SYS_TIMER_DELETE = 244
+ SYS_CLOCK_SETTIME = 245
+ SYS_CLOCK_GETTIME = 246
+ SYS_CLOCK_GETRES = 247
+ SYS_CLOCK_NANOSLEEP = 248
+ SYS_SWAPCONTEXT = 249
+ SYS_TGKILL = 250
+ SYS_UTIMES = 251
+ SYS_STATFS64 = 252
+ SYS_FSTATFS64 = 253
+ SYS_RTAS = 255
+ SYS_SYS_DEBUG_SETCONTEXT = 256
+ SYS_MIGRATE_PAGES = 258
+ SYS_MBIND = 259
+ SYS_GET_MEMPOLICY = 260
+ SYS_SET_MEMPOLICY = 261
+ SYS_MQ_OPEN = 262
+ SYS_MQ_UNLINK = 263
+ SYS_MQ_TIMEDSEND = 264
+ SYS_MQ_TIMEDRECEIVE = 265
+ SYS_MQ_NOTIFY = 266
+ SYS_MQ_GETSETATTR = 267
+ SYS_KEXEC_LOAD = 268
+ SYS_ADD_KEY = 269
+ SYS_REQUEST_KEY = 270
+ SYS_KEYCTL = 271
+ SYS_WAITID = 272
+ SYS_IOPRIO_SET = 273
+ SYS_IOPRIO_GET = 274
+ SYS_INOTIFY_INIT = 275
+ SYS_INOTIFY_ADD_WATCH = 276
+ SYS_INOTIFY_RM_WATCH = 277
+ SYS_SPU_RUN = 278
+ SYS_SPU_CREATE = 279
+ SYS_PSELECT6 = 280
+ SYS_PPOLL = 281
+ SYS_UNSHARE = 282
+ SYS_SPLICE = 283
+ SYS_TEE = 284
+ SYS_VMSPLICE = 285
+ SYS_OPENAT = 286
+ SYS_MKDIRAT = 287
+ SYS_MKNODAT = 288
+ SYS_FCHOWNAT = 289
+ SYS_FUTIMESAT = 290
+ SYS_NEWFSTATAT = 291
+ SYS_UNLINKAT = 292
+ SYS_RENAMEAT = 293
+ SYS_LINKAT = 294
+ SYS_SYMLINKAT = 295
+ SYS_READLINKAT = 296
+ SYS_FCHMODAT = 297
+ SYS_FACCESSAT = 298
+ SYS_GET_ROBUST_LIST = 299
+ SYS_SET_ROBUST_LIST = 300
+ SYS_MOVE_PAGES = 301
+ SYS_GETCPU = 302
+ SYS_EPOLL_PWAIT = 303
+ SYS_UTIMENSAT = 304
+ SYS_SIGNALFD = 305
+ SYS_TIMERFD_CREATE = 306
+ SYS_EVENTFD = 307
+ SYS_SYNC_FILE_RANGE2 = 308
+ SYS_FALLOCATE = 309
+ SYS_SUBPAGE_PROT = 310
+ SYS_TIMERFD_SETTIME = 311
+ SYS_TIMERFD_GETTIME = 312
+ SYS_SIGNALFD4 = 313
+ SYS_EVENTFD2 = 314
+ SYS_EPOLL_CREATE1 = 315
+ SYS_DUP3 = 316
+ SYS_PIPE2 = 317
+ SYS_INOTIFY_INIT1 = 318
+ SYS_PERF_EVENT_OPEN = 319
+ SYS_PREADV = 320
+ SYS_PWRITEV = 321
+ SYS_RT_TGSIGQUEUEINFO = 322
+ SYS_FANOTIFY_INIT = 323
+ SYS_FANOTIFY_MARK = 324
+ SYS_PRLIMIT64 = 325
+ SYS_SOCKET = 326
+ SYS_BIND = 327
+ SYS_CONNECT = 328
+ SYS_LISTEN = 329
+ SYS_ACCEPT = 330
+ SYS_GETSOCKNAME = 331
+ SYS_GETPEERNAME = 332
+ SYS_SOCKETPAIR = 333
+ SYS_SEND = 334
+ SYS_SENDTO = 335
+ SYS_RECV = 336
+ SYS_RECVFROM = 337
+ SYS_SHUTDOWN = 338
+ SYS_SETSOCKOPT = 339
+ SYS_GETSOCKOPT = 340
+ SYS_SENDMSG = 341
+ SYS_RECVMSG = 342
+ SYS_RECVMMSG = 343
+ SYS_ACCEPT4 = 344
+ SYS_NAME_TO_HANDLE_AT = 345
+ SYS_OPEN_BY_HANDLE_AT = 346
+ SYS_CLOCK_ADJTIME = 347
+ SYS_SYNCFS = 348
+ SYS_SENDMMSG = 349
+ SYS_SETNS = 350
+ SYS_PROCESS_VM_READV = 351
+ SYS_PROCESS_VM_WRITEV = 352
+ SYS_FINIT_MODULE = 353
+ SYS_KCMP = 354
+)
diff --git a/src/syscall/ztypes_linux_power64.go b/src/syscall/ztypes_linux_power64.go
new file mode 100644
index 000000000..204d80685
--- /dev/null
+++ b/src/syscall/ztypes_linux_power64.go
@@ -0,0 +1,602 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Timex struct {
+ Modes uint32
+ Pad_cgo_0 [4]byte
+ Offset int64
+ Freq int64
+ Maxerror int64
+ Esterror int64
+ Status int32
+ Pad_cgo_1 [4]byte
+ Constant int64
+ Precision int64
+ Tolerance int64
+ Time Timeval
+ Tick int64
+ Ppsfreq int64
+ Jitter int64
+ Shift int32
+ Pad_cgo_2 [4]byte
+ Stabil int64
+ Jitcnt int64
+ Calcnt int64
+ Errcnt int64
+ Stbcnt int64
+ Tai int32
+ Pad_cgo_3 [44]byte
+}
+
+type Time_t int64
+
+type Tms struct {
+ Utime int64
+ Stime int64
+ Cutime int64
+ Cstime int64
+}
+
+type Utimbuf struct {
+ Actime int64
+ Modtime int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev uint64
+ Ino uint64
+ Nlink uint64
+ Mode uint32
+ Uid uint32
+ Gid uint32
+ X__pad2 int32
+ Rdev uint64
+ Size int64
+ Blksize int64
+ Blocks int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ X__unused4 uint64
+ X__unused5 uint64
+ X__unused6 uint64
+}
+
+type Statfs_t struct {
+ Type int64
+ Bsize int64
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Fsid Fsid
+ Namelen int64
+ Frsize int64
+ Flags int64
+ Spare [4]int64
+}
+
+type Dirent struct {
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Name [256]uint8
+ Pad_cgo_0 [5]byte
+}
+
+type Fsid struct {
+ X__val [2]int32
+}
+
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Pad_cgo_0 [4]byte
+ Start int64
+ Len int64
+ Pid int32
+ Pad_cgo_1 [4]byte
+}
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [108]int8
+}
+
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
+type RawSockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]uint8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [96]uint8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint64
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPMreqn struct {
+ Multiaddr [4]byte /* in_addr */
+ Address [4]byte /* in_addr */
+ Ifindex int32
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Pad_cgo_0 [4]byte
+ Iov *Iovec
+ Iovlen uint64
+ Control *byte
+ Controllen uint64
+ Flags int32
+ Pad_cgo_1 [4]byte
+}
+
+type Cmsghdr struct {
+ Len uint64
+ Level int32
+ Type int32
+ X__cmsg_data [0]uint8
+}
+
+type Inet4Pktinfo struct {
+ Ifindex int32
+ Spec_dst [4]byte /* in_addr */
+ Addr [4]byte /* in_addr */
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+ Addr RawSockaddrInet6
+ Mtu uint32
+}
+
+type ICMPv6Filter struct {
+ Data [8]uint32
+}
+
+type Ucred struct {
+ Pid int32
+ Uid uint32
+ Gid uint32
+}
+
+type TCPInfo struct {
+ State uint8
+ Ca_state uint8
+ Retransmits uint8
+ Probes uint8
+ Backoff uint8
+ Options uint8
+ Pad_cgo_0 [2]byte
+ Rto uint32
+ Ato uint32
+ Snd_mss uint32
+ Rcv_mss uint32
+ Unacked uint32
+ Sacked uint32
+ Lost uint32
+ Retrans uint32
+ Fackets uint32
+ Last_data_sent uint32
+ Last_ack_sent uint32
+ Last_data_recv uint32
+ Last_ack_recv uint32
+ Pmtu uint32
+ Rcv_ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Snd_ssthresh uint32
+ Snd_cwnd uint32
+ Advmss uint32
+ Reordering uint32
+ Rcv_rtt uint32
+ Rcv_space uint32
+ Total_retrans uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofSockaddrNetlink = 0xc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPMreqn = 0xc
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x38
+ SizeofCmsghdr = 0x10
+ SizeofInet4Pktinfo = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofIPv6MTUInfo = 0x20
+ SizeofICMPv6Filter = 0x20
+ SizeofUcred = 0xc
+ SizeofTCPInfo = 0x68
+)
+
+const (
+ IFA_UNSPEC = 0x0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFLA_UNSPEC = 0x0
+ IFLA_ADDRESS = 0x1
+ IFLA_BROADCAST = 0x2
+ IFLA_IFNAME = 0x3
+ IFLA_MTU = 0x4
+ IFLA_LINK = 0x5
+ IFLA_QDISC = 0x6
+ IFLA_STATS = 0x7
+ IFLA_COST = 0x8
+ IFLA_PRIORITY = 0x9
+ IFLA_MASTER = 0xa
+ IFLA_WIRELESS = 0xb
+ IFLA_PROTINFO = 0xc
+ IFLA_TXQLEN = 0xd
+ IFLA_MAP = 0xe
+ IFLA_WEIGHT = 0xf
+ IFLA_OPERSTATE = 0x10
+ IFLA_LINKMODE = 0x11
+ IFLA_LINKINFO = 0x12
+ IFLA_NET_NS_PID = 0x13
+ IFLA_IFALIAS = 0x14
+ IFLA_MAX = 0x22
+ RT_SCOPE_UNIVERSE = 0x0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0x0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0x0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTN_UNSPEC = 0x0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ RTNLGRP_NONE = 0x0
+ RTNLGRP_LINK = 0x1
+ RTNLGRP_NOTIFY = 0x2
+ RTNLGRP_NEIGH = 0x3
+ RTNLGRP_TC = 0x4
+ RTNLGRP_IPV4_IFADDR = 0x5
+ RTNLGRP_IPV4_MROUTE = 0x6
+ RTNLGRP_IPV4_ROUTE = 0x7
+ RTNLGRP_IPV4_RULE = 0x8
+ RTNLGRP_IPV6_IFADDR = 0x9
+ RTNLGRP_IPV6_MROUTE = 0xa
+ RTNLGRP_IPV6_ROUTE = 0xb
+ RTNLGRP_IPV6_IFINFO = 0xc
+ RTNLGRP_IPV6_PREFIX = 0x12
+ RTNLGRP_IPV6_RULE = 0x13
+ RTNLGRP_ND_USEROPT = 0x14
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofIfAddrmsg = 0x8
+ SizeofRtMsg = 0xc
+ SizeofRtNexthop = 0x8
+)
+
+type NlMsghdr struct {
+ Len uint32
+ Type uint16
+ Flags uint16
+ Seq uint32
+ Pid uint32
+}
+
+type NlMsgerr struct {
+ Error int32
+ Msg NlMsghdr
+}
+
+type RtGenmsg struct {
+ Family uint8
+}
+
+type NlAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type RtAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type IfInfomsg struct {
+ Family uint8
+ X__ifi_pad uint8
+ Type uint16
+ Index int32
+ Flags uint32
+ Change uint32
+}
+
+type IfAddrmsg struct {
+ Family uint8
+ Prefixlen uint8
+ Flags uint8
+ Scope uint8
+ Index uint32
+}
+
+type RtMsg struct {
+ Family uint8
+ Dst_len uint8
+ Src_len uint8
+ Tos uint8
+ Table uint8
+ Protocol uint8
+ Scope uint8
+ Type uint8
+ Flags uint32
+}
+
+type RtNexthop struct {
+ Len uint16
+ Flags uint8
+ Hops uint8
+ Ifindex int32
+}
+
+const (
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x10
+)
+
+type SockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type SockFprog struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *SockFilter
+}
+
+type InotifyEvent struct {
+ Wd int32
+ Mask uint32
+ Cookie uint32
+ Len uint32
+ Name [0]uint8
+}
+
+const SizeofInotifyEvent = 0x10
+
+type PtraceRegs struct {
+ Gpr [32]uint64
+ Nip uint64
+ Msr uint64
+ Orig_gpr3 uint64
+ Ctr uint64
+ Link uint64
+ Xer uint64
+ Ccr uint64
+ Softe uint64
+ Trap uint64
+ Dar uint64
+ Dsisr uint64
+ Result uint64
+}
+
+type FdSet struct {
+ Bits [16]int64
+}
+
+type Sysinfo_t struct {
+ Uptime int64
+ Loads [3]uint64
+ Totalram uint64
+ Freeram uint64
+ Sharedram uint64
+ Bufferram uint64
+ Totalswap uint64
+ Freeswap uint64
+ Procs uint16
+ Pad uint16
+ Pad_cgo_0 [4]byte
+ Totalhigh uint64
+ Freehigh uint64
+ Unit uint32
+ X_f [0]byte
+ Pad_cgo_1 [4]byte
+}
+
+type Utsname struct {
+ Sysname [65]uint8
+ Nodename [65]uint8
+ Release [65]uint8
+ Version [65]uint8
+ Machine [65]uint8
+ Domainname [65]uint8
+}
+
+type Ustat_t struct {
+ Tfree int32
+ Pad_cgo_0 [4]byte
+ Tinode uint64
+ Fname [6]uint8
+ Fpack [6]uint8
+ Pad_cgo_1 [4]byte
+}
+
+type EpollEvent struct {
+ Events uint32
+ Fd int32
+ Pad int32
+}
+
+const (
+ _AT_FDCWD = -0x64
+)
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Line uint8
+ Cc [32]uint8
+ Pad_cgo_0 [3]byte
+ Ispeed uint32
+ Ospeed uint32
+}
+
+const (
+ IUCLC = 0x1000
+ OLCUC = 0x4
+ TCGETS = 0x403c7413
+ TCSETS = 0x803c7414
+ XCASE = 0x4000
+)
diff --git a/src/syscall/ztypes_linux_power64le.go b/src/syscall/ztypes_linux_power64le.go
new file mode 100644
index 000000000..df481f5c7
--- /dev/null
+++ b/src/syscall/ztypes_linux_power64le.go
@@ -0,0 +1,602 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Timex struct {
+ Modes uint32
+ Pad_cgo_0 [4]byte
+ Offset int64
+ Freq int64
+ Maxerror int64
+ Esterror int64
+ Status int32
+ Pad_cgo_1 [4]byte
+ Constant int64
+ Precision int64
+ Tolerance int64
+ Time Timeval
+ Tick int64
+ Ppsfreq int64
+ Jitter int64
+ Shift int32
+ Pad_cgo_2 [4]byte
+ Stabil int64
+ Jitcnt int64
+ Calcnt int64
+ Errcnt int64
+ Stbcnt int64
+ Tai int32
+ Pad_cgo_3 [44]byte
+}
+
+type Time_t int64
+
+type Tms struct {
+ Utime int64
+ Stime int64
+ Cutime int64
+ Cstime int64
+}
+
+type Utimbuf struct {
+ Actime int64
+ Modtime int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev uint64
+ Ino uint64
+ Nlink uint64
+ Mode uint32
+ Uid uint32
+ Gid uint32
+ X__pad2 int32
+ Rdev uint64
+ Size int64
+ Blksize int64
+ Blocks int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ X__glibc_reserved4 uint64
+ X__glibc_reserved5 uint64
+ X__glibc_reserved6 uint64
+}
+
+type Statfs_t struct {
+ Type int64
+ Bsize int64
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Fsid Fsid
+ Namelen int64
+ Frsize int64
+ Flags int64
+ Spare [4]int64
+}
+
+type Dirent struct {
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Name [256]uint8
+ Pad_cgo_0 [5]byte
+}
+
+type Fsid struct {
+ X__val [2]int32
+}
+
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Pad_cgo_0 [4]byte
+ Start int64
+ Len int64
+ Pid int32
+ Pad_cgo_1 [4]byte
+}
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [108]int8
+}
+
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
+type RawSockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]uint8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [96]uint8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint64
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPMreqn struct {
+ Multiaddr [4]byte /* in_addr */
+ Address [4]byte /* in_addr */
+ Ifindex int32
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Pad_cgo_0 [4]byte
+ Iov *Iovec
+ Iovlen uint64
+ Control *byte
+ Controllen uint64
+ Flags int32
+ Pad_cgo_1 [4]byte
+}
+
+type Cmsghdr struct {
+ Len uint64
+ Level int32
+ Type int32
+ X__cmsg_data [0]uint8
+}
+
+type Inet4Pktinfo struct {
+ Ifindex int32
+ Spec_dst [4]byte /* in_addr */
+ Addr [4]byte /* in_addr */
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+ Addr RawSockaddrInet6
+ Mtu uint32
+}
+
+type ICMPv6Filter struct {
+ Data [8]uint32
+}
+
+type Ucred struct {
+ Pid int32
+ Uid uint32
+ Gid uint32
+}
+
+type TCPInfo struct {
+ State uint8
+ Ca_state uint8
+ Retransmits uint8
+ Probes uint8
+ Backoff uint8
+ Options uint8
+ Pad_cgo_0 [2]byte
+ Rto uint32
+ Ato uint32
+ Snd_mss uint32
+ Rcv_mss uint32
+ Unacked uint32
+ Sacked uint32
+ Lost uint32
+ Retrans uint32
+ Fackets uint32
+ Last_data_sent uint32
+ Last_ack_sent uint32
+ Last_data_recv uint32
+ Last_ack_recv uint32
+ Pmtu uint32
+ Rcv_ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Snd_ssthresh uint32
+ Snd_cwnd uint32
+ Advmss uint32
+ Reordering uint32
+ Rcv_rtt uint32
+ Rcv_space uint32
+ Total_retrans uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofSockaddrNetlink = 0xc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPMreqn = 0xc
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x38
+ SizeofCmsghdr = 0x10
+ SizeofInet4Pktinfo = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofIPv6MTUInfo = 0x20
+ SizeofICMPv6Filter = 0x20
+ SizeofUcred = 0xc
+ SizeofTCPInfo = 0x68
+)
+
+const (
+ IFA_UNSPEC = 0x0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFLA_UNSPEC = 0x0
+ IFLA_ADDRESS = 0x1
+ IFLA_BROADCAST = 0x2
+ IFLA_IFNAME = 0x3
+ IFLA_MTU = 0x4
+ IFLA_LINK = 0x5
+ IFLA_QDISC = 0x6
+ IFLA_STATS = 0x7
+ IFLA_COST = 0x8
+ IFLA_PRIORITY = 0x9
+ IFLA_MASTER = 0xa
+ IFLA_WIRELESS = 0xb
+ IFLA_PROTINFO = 0xc
+ IFLA_TXQLEN = 0xd
+ IFLA_MAP = 0xe
+ IFLA_WEIGHT = 0xf
+ IFLA_OPERSTATE = 0x10
+ IFLA_LINKMODE = 0x11
+ IFLA_LINKINFO = 0x12
+ IFLA_NET_NS_PID = 0x13
+ IFLA_IFALIAS = 0x14
+ IFLA_MAX = 0x22
+ RT_SCOPE_UNIVERSE = 0x0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0x0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0x0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTN_UNSPEC = 0x0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ RTNLGRP_NONE = 0x0
+ RTNLGRP_LINK = 0x1
+ RTNLGRP_NOTIFY = 0x2
+ RTNLGRP_NEIGH = 0x3
+ RTNLGRP_TC = 0x4
+ RTNLGRP_IPV4_IFADDR = 0x5
+ RTNLGRP_IPV4_MROUTE = 0x6
+ RTNLGRP_IPV4_ROUTE = 0x7
+ RTNLGRP_IPV4_RULE = 0x8
+ RTNLGRP_IPV6_IFADDR = 0x9
+ RTNLGRP_IPV6_MROUTE = 0xa
+ RTNLGRP_IPV6_ROUTE = 0xb
+ RTNLGRP_IPV6_IFINFO = 0xc
+ RTNLGRP_IPV6_PREFIX = 0x12
+ RTNLGRP_IPV6_RULE = 0x13
+ RTNLGRP_ND_USEROPT = 0x14
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofIfAddrmsg = 0x8
+ SizeofRtMsg = 0xc
+ SizeofRtNexthop = 0x8
+)
+
+type NlMsghdr struct {
+ Len uint32
+ Type uint16
+ Flags uint16
+ Seq uint32
+ Pid uint32
+}
+
+type NlMsgerr struct {
+ Error int32
+ Msg NlMsghdr
+}
+
+type RtGenmsg struct {
+ Family uint8
+}
+
+type NlAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type RtAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type IfInfomsg struct {
+ Family uint8
+ X__ifi_pad uint8
+ Type uint16
+ Index int32
+ Flags uint32
+ Change uint32
+}
+
+type IfAddrmsg struct {
+ Family uint8
+ Prefixlen uint8
+ Flags uint8
+ Scope uint8
+ Index uint32
+}
+
+type RtMsg struct {
+ Family uint8
+ Dst_len uint8
+ Src_len uint8
+ Tos uint8
+ Table uint8
+ Protocol uint8
+ Scope uint8
+ Type uint8
+ Flags uint32
+}
+
+type RtNexthop struct {
+ Len uint16
+ Flags uint8
+ Hops uint8
+ Ifindex int32
+}
+
+const (
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x10
+)
+
+type SockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type SockFprog struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *SockFilter
+}
+
+type InotifyEvent struct {
+ Wd int32
+ Mask uint32
+ Cookie uint32
+ Len uint32
+ Name [0]uint8
+}
+
+const SizeofInotifyEvent = 0x10
+
+type PtraceRegs struct {
+ Gpr [32]uint64
+ Nip uint64
+ Msr uint64
+ Orig_gpr3 uint64
+ Ctr uint64
+ Link uint64
+ Xer uint64
+ Ccr uint64
+ Softe uint64
+ Trap uint64
+ Dar uint64
+ Dsisr uint64
+ Result uint64
+}
+
+type FdSet struct {
+ Bits [16]int64
+}
+
+type Sysinfo_t struct {
+ Uptime int64
+ Loads [3]uint64
+ Totalram uint64
+ Freeram uint64
+ Sharedram uint64
+ Bufferram uint64
+ Totalswap uint64
+ Freeswap uint64
+ Procs uint16
+ Pad uint16
+ Pad_cgo_0 [4]byte
+ Totalhigh uint64
+ Freehigh uint64
+ Unit uint32
+ X_f [0]byte
+ Pad_cgo_1 [4]byte
+}
+
+type Utsname struct {
+ Sysname [65]uint8
+ Nodename [65]uint8
+ Release [65]uint8
+ Version [65]uint8
+ Machine [65]uint8
+ Domainname [65]uint8
+}
+
+type Ustat_t struct {
+ Tfree int32
+ Pad_cgo_0 [4]byte
+ Tinode uint64
+ Fname [6]uint8
+ Fpack [6]uint8
+ Pad_cgo_1 [4]byte
+}
+
+type EpollEvent struct {
+ Events uint32
+ Fd int32
+ Pad int32
+}
+
+const (
+ _AT_FDCWD = -0x64
+)
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Line uint8
+ Cc [32]uint8
+ Pad_cgo_0 [3]byte
+ Ispeed uint32
+ Ospeed uint32
+}
+
+const (
+ IUCLC = 0x1000
+ OLCUC = 0x4
+ TCGETS = 0x403c7413
+ TCSETS = 0x803c7414
+ XCASE = 0x4000
+)
diff --git a/test/clearfat.go b/test/clearfat.go
new file mode 100644
index 000000000..45d539306
--- /dev/null
+++ b/test/clearfat.go
@@ -0,0 +1,68 @@
+// runoutput
+
+// 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.
+
+// Check that {5,6,8,9}g/ggen.c:clearfat is zeroing the entire object.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+const ntest = 1100
+
+func main() {
+ var decls, calls bytes.Buffer
+
+ for i := 1; i <= ntest; i++ {
+ s := strconv.Itoa(i)
+ decls.WriteString(strings.Replace(decl, "$", s, -1))
+ calls.WriteString(strings.Replace("poison$()\n\tclearfat$()\n\t", "$", s, -1))
+ }
+
+ program = strings.Replace(program, "$DECLS", decls.String(), 1)
+ program = strings.Replace(program, "$CALLS", calls.String(), 1)
+ fmt.Print(program)
+}
+
+var program = `package main
+
+var count int
+
+$DECLS
+
+func main() {
+ $CALLS
+ if count != 0 {
+ println("failed", count, "case(s)")
+ }
+}
+`
+
+const decl = `
+func poison$() {
+ // Grow and poison the stack space that will be used by clearfat$
+ var t [2*$]byte
+ for i := range t {
+ t[i] = 0xff
+ }
+}
+
+func clearfat$() {
+ var t [$]byte
+
+ for _, x := range t {
+ if x != 0 {
+// println("clearfat$: index", i, "expected 0, got", x)
+ count++
+ break
+ }
+ }
+}
+`
diff --git a/test/live.go b/test/live.go
index f15bb74ba..f69d0a4c1 100644
--- a/test/live.go
+++ b/test/live.go
@@ -614,8 +614,8 @@ func newT40() *T40 {
func bad40() {
t := newT40()
- println()
_ = t
+ println()
}
func good40() {
diff --git a/test/nilptr3.go b/test/nilptr3.go
index 2757daef0..9d65e1e91 100644
--- a/test/nilptr3.go
+++ b/test/nilptr3.go
@@ -1,4 +1,6 @@
// errorcheck -0 -d=nil
+// Fails on power64x because of incomplete optimization. See issue 9058.
+// +build !power64,!power64le
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
diff --git a/test/nosplit.go b/test/nosplit.go
index 953a5bf0a..3a63e8731 100644
--- a/test/nosplit.go
+++ b/test/nosplit.go
@@ -127,8 +127,9 @@ main 136 nosplit; REJECT
# Calling a nosplit function from a nosplit function requires
# having room for the saved caller PC and the called frame.
# Because ARM doesn't save LR in the leaf, it gets an extra 4 bytes.
+# Because Power64 doesn't save LR in the leaf, it gets an extra 8 bytes.
main 112 nosplit call f; f 0 nosplit
-main 116 nosplit call f; f 0 nosplit; REJECT amd64
+main 116 nosplit call f; f 0 nosplit
main 120 nosplit call f; f 0 nosplit; REJECT amd64
main 124 nosplit call f; f 0 nosplit; REJECT amd64 386
main 128 nosplit call f; f 0 nosplit; REJECT
@@ -137,8 +138,8 @@ main 136 nosplit call f; f 0 nosplit; REJECT
# Calling a splitting function from a nosplit function requires
# having room for the saved caller PC of the call but also the
-# saved caller PC for the call to morestack. Again the ARM works
-# in less space.
+# saved caller PC for the call to morestack.
+# Again the ARM and Power64 work in less space.
main 104 nosplit call f; f 0 call f
main 108 nosplit call f; f 0 call f
main 112 nosplit call f; f 0 call f; REJECT amd64
@@ -234,9 +235,17 @@ TestCases:
fmt.Fprintf(&gobuf, "package main\n")
var buf bytes.Buffer
- if goarch == "arm" {
+ ptrSize := 4
+ switch goarch {
+ case "power64", "power64le":
+ ptrSize = 8
+ fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (CTR)\n#define RET RETURN\n")
+ case "arm":
fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n")
- } else {
+ case "amd64":
+ ptrSize = 8
+ fmt.Fprintf(&buf, "#define REGISTER AX\n")
+ default:
fmt.Fprintf(&buf, "#define REGISTER AX\n")
}
@@ -266,7 +275,7 @@ TestCases:
size += 384 - 128
}
- if goarch == "amd64" && size%8 == 4 {
+ if size%ptrSize == 4 {
continue TestCases
}
nosplit := m[3]