summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:11:55 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:11:55 +0200
commit80f18fc933cf3f3e829c5455a1023d69f7b86e52 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /src/cmd
parent28592ee1ea1f5cdffcf85472f9de0285d928cf12 (diff)
downloadgolang-80f18fc933cf3f3e829c5455a1023d69f7b86e52.tar.gz
Imported Upstream version 60
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/5a/Makefile25
-rw-r--r--src/cmd/5a/a.h200
-rw-r--r--src/cmd/5a/a.y708
-rw-r--r--src/cmd/5a/doc.go14
-rw-r--r--src/cmd/5a/lex.c703
-rw-r--r--src/cmd/5c/Makefile34
-rw-r--r--src/cmd/5c/cgen.c1199
-rw-r--r--src/cmd/5c/doc.go14
-rw-r--r--src/cmd/5c/gc.h384
-rw-r--r--src/cmd/5c/list.c340
-rw-r--r--src/cmd/5c/mul.c640
-rw-r--r--src/cmd/5c/peep.c1469
-rw-r--r--src/cmd/5c/reg.c1192
-rw-r--r--src/cmd/5c/sgen.c267
-rw-r--r--src/cmd/5c/swt.c694
-rw-r--r--src/cmd/5c/txt.c1298
-rw-r--r--src/cmd/5g/Makefile36
-rw-r--r--src/cmd/5g/cgen.c1329
-rw-r--r--src/cmd/5g/cgen64.c716
-rw-r--r--src/cmd/5g/doc.go15
-rw-r--r--src/cmd/5g/galign.c38
-rw-r--r--src/cmd/5g/gg.h171
-rw-r--r--src/cmd/5g/ggen.c1003
-rw-r--r--src/cmd/5g/gobj.c623
-rw-r--r--src/cmd/5g/gsubr.c2005
-rw-r--r--src/cmd/5g/list.c331
-rw-r--r--src/cmd/5g/opt.h165
-rw-r--r--src/cmd/5g/peep.c1518
-rw-r--r--src/cmd/5g/reg.c1606
-rw-r--r--src/cmd/5l/5.out.h270
-rw-r--r--src/cmd/5l/Makefile43
-rw-r--r--src/cmd/5l/asm.c1883
-rw-r--r--src/cmd/5l/doc.go39
-rw-r--r--src/cmd/5l/l.h440
-rw-r--r--src/cmd/5l/list.c487
-rw-r--r--src/cmd/5l/mkenam45
-rw-r--r--src/cmd/5l/noop.c539
-rw-r--r--src/cmd/5l/obj.c757
-rw-r--r--src/cmd/5l/optab.c236
-rw-r--r--src/cmd/5l/pass.c333
-rw-r--r--src/cmd/5l/prof.c211
-rw-r--r--src/cmd/5l/softfloat.c89
-rw-r--r--src/cmd/5l/span.c893
-rw-r--r--src/cmd/6a/Makefile25
-rw-r--r--src/cmd/6a/a.h214
-rw-r--r--src/cmd/6a/a.y645
-rw-r--r--src/cmd/6a/doc.go14
-rw-r--r--src/cmd/6a/lex.c1315
-rw-r--r--src/cmd/6c/Makefile36
-rw-r--r--src/cmd/6c/cgen.c1980
-rw-r--r--src/cmd/6c/div.c236
-rw-r--r--src/cmd/6c/doc.go14
-rw-r--r--src/cmd/6c/gc.h407
-rw-r--r--src/cmd/6c/list.c396
-rw-r--r--src/cmd/6c/machcap.c107
-rw-r--r--src/cmd/6c/mul.c458
-rw-r--r--src/cmd/6c/peep.c890
-rw-r--r--src/cmd/6c/reg.c1386
-rw-r--r--src/cmd/6c/sgen.c485
-rw-r--r--src/cmd/6c/swt.c587
-rw-r--r--src/cmd/6c/txt.c1564
-rw-r--r--src/cmd/6g/Makefile35
-rw-r--r--src/cmd/6g/cgen.c1301
-rw-r--r--src/cmd/6g/doc.go13
-rw-r--r--src/cmd/6g/galign.c36
-rw-r--r--src/cmd/6g/gg.h161
-rw-r--r--src/cmd/6g/ggen.c1371
-rw-r--r--src/cmd/6g/gobj.c644
-rw-r--r--src/cmd/6g/gsubr.c2159
-rw-r--r--src/cmd/6g/list.c359
-rw-r--r--src/cmd/6g/opt.h166
-rw-r--r--src/cmd/6g/peep.c999
-rw-r--r--src/cmd/6g/reg.c1690
-rw-r--r--src/cmd/6l/6.out.h863
-rw-r--r--src/cmd/6l/Makefile48
-rw-r--r--src/cmd/6l/asm.c1171
-rw-r--r--src/cmd/6l/doc.go51
-rw-r--r--src/cmd/6l/l.h439
-rw-r--r--src/cmd/6l/list.c458
-rw-r--r--src/cmd/6l/mkenam45
-rw-r--r--src/cmd/6l/obj.c756
-rw-r--r--src/cmd/6l/optab.c1213
-rw-r--r--src/cmd/6l/pass.c725
-rw-r--r--src/cmd/6l/prof.c171
-rw-r--r--src/cmd/6l/span.c1741
-rw-r--r--src/cmd/8a/Makefile25
-rw-r--r--src/cmd/8a/a.h215
-rw-r--r--src/cmd/8a/a.y614
-rw-r--r--src/cmd/8a/doc.go14
-rw-r--r--src/cmd/8a/lex.c971
-rw-r--r--src/cmd/8c/Makefile37
-rw-r--r--src/cmd/8c/cgen.c1857
-rw-r--r--src/cmd/8c/cgen64.c2657
-rw-r--r--src/cmd/8c/div.c236
-rw-r--r--src/cmd/8c/doc.go14
-rw-r--r--src/cmd/8c/gc.h411
-rw-r--r--src/cmd/8c/list.c328
-rw-r--r--src/cmd/8c/machcap.c116
-rw-r--r--src/cmd/8c/mul.c458
-rw-r--r--src/cmd/8c/peep.c801
-rw-r--r--src/cmd/8c/reg.c1287
-rw-r--r--src/cmd/8c/sgen.c485
-rw-r--r--src/cmd/8c/swt.c588
-rw-r--r--src/cmd/8c/txt.c1458
-rw-r--r--src/cmd/8g/Makefile36
-rw-r--r--src/cmd/8g/cgen.c1235
-rw-r--r--src/cmd/8g/cgen64.c512
-rw-r--r--src/cmd/8g/doc.go15
-rw-r--r--src/cmd/8g/galign.c36
-rw-r--r--src/cmd/8g/gg.h187
-rw-r--r--src/cmd/8g/ggen.c1089
-rw-r--r--src/cmd/8g/gobj.c651
-rw-r--r--src/cmd/8g/gsubr.c1959
-rw-r--r--src/cmd/8g/list.c302
-rw-r--r--src/cmd/8g/opt.h164
-rw-r--r--src/cmd/8g/peep.c890
-rw-r--r--src/cmd/8g/reg.c1546
-rw-r--r--src/cmd/8l/8.out.h542
-rw-r--r--src/cmd/8l/Makefile49
-rw-r--r--src/cmd/8l/asm.c1262
-rw-r--r--src/cmd/8l/doc.go50
-rw-r--r--src/cmd/8l/l.h394
-rw-r--r--src/cmd/8l/list.c369
-rw-r--r--src/cmd/8l/mkenam45
-rw-r--r--src/cmd/8l/obj.c740
-rw-r--r--src/cmd/8l/optab.c754
-rw-r--r--src/cmd/8l/pass.c657
-rw-r--r--src/cmd/8l/prof.c173
-rw-r--r--src/cmd/8l/span.c1325
-rw-r--r--src/cmd/Makefile69
-rw-r--r--src/cmd/cc/Makefile36
-rw-r--r--src/cmd/cc/acid.c344
-rw-r--r--src/cmd/cc/bits.c120
-rw-r--r--src/cmd/cc/cc.h831
-rw-r--r--src/cmd/cc/cc.y1215
-rw-r--r--src/cmd/cc/com.c1385
-rw-r--r--src/cmd/cc/com64.c644
-rw-r--r--src/cmd/cc/dcl.c1669
-rw-r--r--src/cmd/cc/doc.go11
-rw-r--r--src/cmd/cc/dpchk.c724
-rw-r--r--src/cmd/cc/funct.c431
-rw-r--r--src/cmd/cc/godefs.c388
-rw-r--r--src/cmd/cc/lex.c1562
-rw-r--r--src/cmd/cc/lexbody769
-rw-r--r--src/cmd/cc/mac.c35
-rw-r--r--src/cmd/cc/macbody852
-rw-r--r--src/cmd/cc/omachcap.c40
-rw-r--r--src/cmd/cc/pgen.c594
-rw-r--r--src/cmd/cc/pswt.c168
-rw-r--r--src/cmd/cc/scon.c637
-rw-r--r--src/cmd/cc/sub.c2056
-rw-r--r--src/cmd/cgo/Makefile15
-rw-r--r--src/cmd/cgo/ast.go410
-rw-r--r--src/cmd/cgo/doc.go80
-rw-r--r--src/cmd/cgo/gcc.go1367
-rw-r--r--src/cmd/cgo/main.go268
-rw-r--r--src/cmd/cgo/out.go730
-rw-r--r--src/cmd/cgo/util.go110
-rw-r--r--src/cmd/cov/Makefile39
-rw-r--r--src/cmd/cov/doc.go33
-rw-r--r--src/cmd/cov/main.c480
-rw-r--r--src/cmd/cov/tree.c246
-rw-r--r--src/cmd/cov/tree.h47
-rw-r--r--src/cmd/ebnflint/Makefile15
-rw-r--r--src/cmd/ebnflint/doc.go22
-rw-r--r--src/cmd/ebnflint/ebnflint.go115
-rw-r--r--src/cmd/gc/Makefile67
-rw-r--r--src/cmd/gc/align.c659
-rwxr-xr-xsrc/cmd/gc/bisonerrors124
-rw-r--r--src/cmd/gc/bits.c158
-rw-r--r--src/cmd/gc/builtin.c.boot115
-rw-r--r--src/cmd/gc/closure.c247
-rw-r--r--src/cmd/gc/const.c1283
-rw-r--r--src/cmd/gc/cplx.c479
-rw-r--r--src/cmd/gc/dcl.c1248
-rw-r--r--src/cmd/gc/doc.go55
-rw-r--r--src/cmd/gc/export.c428
-rw-r--r--src/cmd/gc/gen.c790
-rw-r--r--src/cmd/gc/go.errors70
-rw-r--r--src/cmd/gc/go.h1265
-rw-r--r--src/cmd/gc/go.y1966
-rw-r--r--src/cmd/gc/init.c195
-rw-r--r--src/cmd/gc/lex.c1935
-rw-r--r--src/cmd/gc/md5.c290
-rw-r--r--src/cmd/gc/md5.h16
-rwxr-xr-xsrc/cmd/gc/mkbuiltin31
-rw-r--r--src/cmd/gc/mkbuiltin1.c90
-rwxr-xr-xsrc/cmd/gc/mkopnames24
-rw-r--r--src/cmd/gc/mparith1.c509
-rw-r--r--src/cmd/gc/mparith2.c683
-rw-r--r--src/cmd/gc/mparith3.c313
-rw-r--r--src/cmd/gc/obj.c292
-rw-r--r--src/cmd/gc/pgen.c210
-rw-r--r--src/cmd/gc/print.c454
-rw-r--r--src/cmd/gc/range.c252
-rw-r--r--src/cmd/gc/reflect.c939
-rw-r--r--src/cmd/gc/runtime.go131
-rw-r--r--src/cmd/gc/select.c343
-rw-r--r--src/cmd/gc/sinit.c971
-rw-r--r--src/cmd/gc/subr.c3851
-rw-r--r--src/cmd/gc/swt.c896
-rw-r--r--src/cmd/gc/typecheck.c2822
-rw-r--r--src/cmd/gc/unsafe.c97
-rw-r--r--src/cmd/gc/unsafe.go22
-rw-r--r--src/cmd/gc/walk.c2177
-rw-r--r--src/cmd/godefs/Makefile19
-rw-r--r--src/cmd/godefs/a.h104
-rw-r--r--src/cmd/godefs/doc.go99
-rw-r--r--src/cmd/godefs/main.c606
-rw-r--r--src/cmd/godefs/stabs.c456
-rwxr-xr-xsrc/cmd/godefs/test.sh45
-rw-r--r--src/cmd/godefs/testdata.c41
-rw-r--r--src/cmd/godefs/testdata_darwin_386.golden31
-rw-r--r--src/cmd/godefs/testdata_darwin_amd64.golden31
-rw-r--r--src/cmd/godefs/util.c36
-rw-r--r--src/cmd/godoc/Makefile22
-rw-r--r--src/cmd/godoc/codewalk.go499
-rw-r--r--src/cmd/godoc/dirtrees.go358
-rw-r--r--src/cmd/godoc/doc.go111
-rw-r--r--src/cmd/godoc/filesystem.go96
-rw-r--r--src/cmd/godoc/format.go373
-rw-r--r--src/cmd/godoc/godoc.go1299
-rw-r--r--src/cmd/godoc/index.go1042
-rw-r--r--src/cmd/godoc/main.go410
-rw-r--r--src/cmd/godoc/mapping.go210
-rw-r--r--src/cmd/godoc/parser.go69
-rwxr-xr-xsrc/cmd/godoc/snippet.go109
-rw-r--r--src/cmd/godoc/spec.go212
-rw-r--r--src/cmd/godoc/utils.go176
-rw-r--r--src/cmd/gofix/Makefile33
-rw-r--r--src/cmd/gofix/doc.go36
-rw-r--r--src/cmd/gofix/filepath.go53
-rw-r--r--src/cmd/gofix/filepath_test.go33
-rw-r--r--src/cmd/gofix/fix.go573
-rw-r--r--src/cmd/gofix/httpfinalurl.go56
-rw-r--r--src/cmd/gofix/httpfinalurl_test.go37
-rw-r--r--src/cmd/gofix/httpfs.go63
-rw-r--r--src/cmd/gofix/httpfs_test.go47
-rw-r--r--src/cmd/gofix/httpheaders.go66
-rw-r--r--src/cmd/gofix/httpheaders_test.go73
-rw-r--r--src/cmd/gofix/httpserver.go140
-rw-r--r--src/cmd/gofix/httpserver_test.go53
-rw-r--r--src/cmd/gofix/main.go258
-rw-r--r--src/cmd/gofix/main_test.go126
-rw-r--r--src/cmd/gofix/netdial.go114
-rw-r--r--src/cmd/gofix/netdial_test.go51
-rw-r--r--src/cmd/gofix/oserrorstring.go75
-rw-r--r--src/cmd/gofix/oserrorstring_test.go57
-rw-r--r--src/cmd/gofix/osopen.go122
-rw-r--r--src/cmd/gofix/osopen_test.go59
-rw-r--r--src/cmd/gofix/procattr.go61
-rw-r--r--src/cmd/gofix/procattr_test.go74
-rw-r--r--src/cmd/gofix/reflect.go861
-rw-r--r--src/cmd/gofix/reflect_test.go31
-rw-r--r--src/cmd/gofix/signal.go49
-rw-r--r--src/cmd/gofix/signal_test.go96
-rw-r--r--src/cmd/gofix/sorthelpers.go47
-rw-r--r--src/cmd/gofix/sorthelpers_test.go45
-rw-r--r--src/cmd/gofix/sortslice.go50
-rw-r--r--src/cmd/gofix/sortslice_test.go35
-rw-r--r--src/cmd/gofix/stringssplit.go71
-rw-r--r--src/cmd/gofix/stringssplit_test.go51
-rw-r--r--src/cmd/gofix/testdata/reflect.asn1.go.in815
-rw-r--r--src/cmd/gofix/testdata/reflect.asn1.go.out815
-rw-r--r--src/cmd/gofix/testdata/reflect.datafmt.go.in731
-rw-r--r--src/cmd/gofix/testdata/reflect.datafmt.go.out731
-rw-r--r--src/cmd/gofix/testdata/reflect.decode.go.in907
-rw-r--r--src/cmd/gofix/testdata/reflect.decode.go.out910
-rw-r--r--src/cmd/gofix/testdata/reflect.decoder.go.in196
-rw-r--r--src/cmd/gofix/testdata/reflect.decoder.go.out196
-rw-r--r--src/cmd/gofix/testdata/reflect.dnsmsg.go.in779
-rw-r--r--src/cmd/gofix/testdata/reflect.dnsmsg.go.out779
-rw-r--r--src/cmd/gofix/testdata/reflect.encode.go.in367
-rw-r--r--src/cmd/gofix/testdata/reflect.encode.go.out367
-rw-r--r--src/cmd/gofix/testdata/reflect.encoder.go.in240
-rw-r--r--src/cmd/gofix/testdata/reflect.encoder.go.out240
-rw-r--r--src/cmd/gofix/testdata/reflect.export.go.in400
-rw-r--r--src/cmd/gofix/testdata/reflect.export.go.out400
-rw-r--r--src/cmd/gofix/testdata/reflect.print.go.in945
-rw-r--r--src/cmd/gofix/testdata/reflect.print.go.out945
-rw-r--r--src/cmd/gofix/testdata/reflect.quick.go.in364
-rw-r--r--src/cmd/gofix/testdata/reflect.quick.go.out365
-rw-r--r--src/cmd/gofix/testdata/reflect.read.go.in620
-rw-r--r--src/cmd/gofix/testdata/reflect.read.go.out620
-rw-r--r--src/cmd/gofix/testdata/reflect.scan.go.in1084
-rw-r--r--src/cmd/gofix/testdata/reflect.scan.go.out1084
-rw-r--r--src/cmd/gofix/testdata/reflect.script.go.in359
-rw-r--r--src/cmd/gofix/testdata/reflect.script.go.out359
-rw-r--r--src/cmd/gofix/testdata/reflect.template.go.in1043
-rw-r--r--src/cmd/gofix/testdata/reflect.template.go.out1044
-rw-r--r--src/cmd/gofix/testdata/reflect.type.go.in789
-rw-r--r--src/cmd/gofix/testdata/reflect.type.go.out789
-rw-r--r--src/cmd/gofix/typecheck.go584
-rw-r--r--src/cmd/gofmt/Makefile19
-rw-r--r--src/cmd/gofmt/doc.go69
-rw-r--r--src/cmd/gofmt/gofmt.go271
-rw-r--r--src/cmd/gofmt/gofmt_test.go82
-rw-r--r--src/cmd/gofmt/rewrite.go301
-rw-r--r--src/cmd/gofmt/simplify.go67
-rwxr-xr-xsrc/cmd/gofmt/test.sh162
-rw-r--r--src/cmd/gofmt/testdata/composites.golden104
-rw-r--r--src/cmd/gofmt/testdata/composites.input104
-rw-r--r--src/cmd/gofmt/testdata/rewrite1.golden12
-rw-r--r--src/cmd/gofmt/testdata/rewrite1.input12
-rw-r--r--src/cmd/gofmt/testdata/rewrite2.golden10
-rw-r--r--src/cmd/gofmt/testdata/rewrite2.input10
-rw-r--r--src/cmd/goinstall/Makefile13
-rw-r--r--src/cmd/goinstall/doc.go191
-rw-r--r--src/cmd/goinstall/download.go306
-rw-r--r--src/cmd/goinstall/main.go298
-rw-r--r--src/cmd/goinstall/make.go180
-rw-r--r--src/cmd/gomake/doc.go36
-rw-r--r--src/cmd/gopack/Makefile12
-rw-r--r--src/cmd/gopack/ar.c1717
-rw-r--r--src/cmd/gopack/doc.go26
-rw-r--r--src/cmd/gotest/Makefile12
-rw-r--r--src/cmd/gotest/doc.go113
-rw-r--r--src/cmd/gotest/flag.go159
-rw-r--r--src/cmd/gotest/gotest.go435
-rw-r--r--src/cmd/gotry/Makefile18
-rwxr-xr-xsrc/cmd/gotry/gotry167
-rw-r--r--src/cmd/gotype/Makefile17
-rw-r--r--src/cmd/gotype/doc.go59
-rw-r--r--src/cmd/gotype/gotype.go200
-rw-r--r--src/cmd/gotype/gotype_test.go52
-rw-r--r--src/cmd/gotype/testdata/test1.go6
-rw-r--r--src/cmd/govet/Makefile14
-rw-r--r--src/cmd/govet/doc.go38
-rw-r--r--src/cmd/govet/govet.go405
-rw-r--r--src/cmd/goyacc/Makefile17
-rw-r--r--src/cmd/goyacc/doc.go46
-rw-r--r--src/cmd/goyacc/goyacc.go3311
-rw-r--r--src/cmd/goyacc/units.txt576
-rw-r--r--src/cmd/goyacc/units.y761
-rw-r--r--src/cmd/hgpatch/Makefile11
-rw-r--r--src/cmd/hgpatch/doc.go18
-rw-r--r--src/cmd/hgpatch/main.go361
-rw-r--r--src/cmd/ld/data.c970
-rw-r--r--src/cmd/ld/doc.go11
-rw-r--r--src/cmd/ld/dwarf.c2598
-rw-r--r--src/cmd/ld/dwarf.h30
-rw-r--r--src/cmd/ld/dwarf_defs.h503
-rw-r--r--src/cmd/ld/elf.c558
-rw-r--r--src/cmd/ld/elf.h989
-rw-r--r--src/cmd/ld/go.c710
-rw-r--r--src/cmd/ld/ldelf.c816
-rw-r--r--src/cmd/ld/ldmacho.c821
-rw-r--r--src/cmd/ld/ldpe.c415
-rw-r--r--src/cmd/ld/lib.c1361
-rw-r--r--src/cmd/ld/lib.h281
-rw-r--r--src/cmd/ld/macho.c518
-rw-r--r--src/cmd/ld/macho.h94
-rw-r--r--src/cmd/ld/pe.c583
-rw-r--r--src/cmd/ld/pe.h179
-rw-r--r--src/cmd/ld/symtab.c378
-rw-r--r--src/cmd/nm/Makefile15
-rw-r--r--src/cmd/nm/doc.go21
-rw-r--r--src/cmd/nm/nm.c368
-rw-r--r--src/cmd/prof/Makefile38
-rw-r--r--src/cmd/prof/doc.go48
-rwxr-xr-xsrc/cmd/prof/gopprof4975
-rw-r--r--src/cmd/prof/main.c895
362 files changed, 0 insertions, 183874 deletions
diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile
deleted file mode 100644
index f4463c97b..000000000
--- a/src/cmd/5a/Makefile
+++ /dev/null
@@ -1,25 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=5a
-
-HFILES=\
- a.h\
- y.tab.h\
- ../5l/5.out.h\
-
-OFILES=\
- y.tab.$O\
- lex.$O\
- ../5l/enam.$O\
-
-YFILES=\
- a.y\
-
-include ../../Make.ccmd
-
-lex.$O: ../cc/macbody ../cc/lexbody
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
deleted file mode 100644
index 550b61dcf..000000000
--- a/src/cmd/5a/a.h
+++ /dev/null
@@ -1,200 +0,0 @@
-// Inferno utils/5a/a.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.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 <libc.h>
-#include <bio.h>
-#include "../5l/5.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 Gen Gen;
-typedef struct Io Io;
-typedef struct Hist Hist;
-
-#define MAXALIGN 7
-#define FPCHIP 1
-#define NSYMB 8192
-#define BUFSIZ 8192
-#define HISTSZ 20
-#define EOF (-1)
-#define IGN (-2)
-#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
-#define NHASH 503
-#define STRINGSZ 200
-#define NMACRO 10
-
-struct Sym
-{
- Sym* link;
- char* macro;
- int32 value;
- ushort type;
- char *name;
- char sym;
-};
-#define S ((Sym*)0)
-
-EXTERN struct
-{
- char* p;
- int c;
-} fi;
-
-struct Io
-{
- Io* link;
- char b[BUFSIZ];
- char* p;
- short c;
- short f;
-};
-#define I ((Io*)0)
-
-EXTERN struct
-{
- Sym* sym;
- short type;
-} h[NSYM];
-
-struct Gen
-{
- Sym* sym;
- int32 offset;
- short type;
- short reg;
- short name;
- double dval;
- char sval[8];
-};
-
-struct Hist
-{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
-};
-#define H ((Hist*)0)
-
-enum
-{
- CLAST,
- CMACARG,
- CMACRO,
- CPREPROC,
-
- Always = 14,
-};
-
-EXTERN char debug[256];
-EXTERN Sym* hash[NHASH];
-EXTERN char** Dlist;
-EXTERN int nDlist;
-EXTERN Hist* ehist;
-EXTERN int newflag;
-EXTERN Hist* hist;
-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 ninclude;
-EXTERN int32 nsymb;
-EXTERN Gen nullgen;
-EXTERN char* outfile;
-EXTERN int pass;
-EXTERN char* pathname;
-EXTERN int32 pc;
-EXTERN int peekc;
-EXTERN int32 stmtline;
-EXTERN int sym;
-EXTERN char* symb;
-EXTERN int thechar;
-EXTERN char* thestring;
-EXTERN int32 thunk;
-EXTERN Biobuf obuf;
-
-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);
-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);
-int isreg(Gen*);
-void outcode(int, int, Gen*, int, Gen*);
-void zname(char*, int, int);
-void zaddr(Gen*, int);
-void ieeedtod(Ieee*, double);
-int filbuf(void);
-Sym* getsym(void);
-void domacro(void);
-void macund(void);
-void macdef(void);
-void macexpand(Sym*, char*);
-void macinc(void);
-void maclin(void);
-void macprag(void);
-void macif(int);
-void macend(void);
-void outhist(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/5a/a.y b/src/cmd/5a/a.y
deleted file mode 100644
index b39c916ab..000000000
--- a/src/cmd/5a/a.y
+++ /dev/null
@@ -1,708 +0,0 @@
-// Inferno utils/5a/a.y
-// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.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 <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include "a.h"
-%}
-%union
-{
- Sym *sym;
- int32 lval;
- double dval;
- char sval[8];
- Gen gen;
-}
-%left '|'
-%left '^'
-%left '&'
-%left '<' '>'
-%left '+' '-'
-%left '*' '/' '%'
-%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
-%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
-%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF
-%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
-%token <lval> LTYPEL LTYPEM LTYPEN LTYPEBX
-%token <lval> LCONST LSP LSB LFP LPC
-%token <lval> LTYPEX LR LREG LF LFREG LC LCREG LPSR LFCR
-%token <lval> LCOND LS LAT
-%token <dval> LFCONST
-%token <sval> LSCONST
-%token <sym> LNAME LLAB LVAR
-%type <lval> con expr oexpr pointer offset sreg spreg creg
-%type <lval> rcon cond reglist
-%type <gen> gen rel reg regreg freg shift fcon frcon
-%type <gen> imm ximm name oreg ireg nireg ioreg imsr
-%%
-prog:
-| prog
- {
- stmtline = lineno;
- }
- line
-
-line:
- LLAB ':'
- {
- if($1->value != pc)
- yyerror("redeclaration of %s", $1->name);
- $1->value = pc;
- }
- line
-| LNAME ':'
- {
- $1->type = LLAB;
- $1->value = pc;
- }
- line
-| LNAME '=' expr ';'
- {
- $1->type = LVAR;
- $1->value = $3;
- }
-| LVAR '=' expr ';'
- {
- if($1->value != $3)
- yyerror("redeclaration of %s", $1->name);
- $1->value = $3;
- }
-| ';'
-| inst ';'
-| error ';'
-
-inst:
-/*
- * ADD
- */
- LTYPE1 cond imsr ',' spreg ',' reg
- {
- outcode($1, $2, &$3, $5, &$7);
- }
-| LTYPE1 cond imsr ',' spreg ','
- {
- outcode($1, $2, &$3, $5, &nullgen);
- }
-| LTYPE1 cond imsr ',' reg
- {
- outcode($1, $2, &$3, NREG, &$5);
- }
-/*
- * MVN
- */
-| LTYPE2 cond imsr ',' reg
- {
- outcode($1, $2, &$3, NREG, &$5);
- }
-/*
- * MOVW
- */
-| LTYPE3 cond gen ',' gen
- {
- outcode($1, $2, &$3, NREG, &$5);
- }
-/*
- * B/BL
- */
-| LTYPE4 cond comma rel
- {
- outcode($1, $2, &nullgen, NREG, &$4);
- }
-| LTYPE4 cond comma nireg
- {
- outcode($1, $2, &nullgen, NREG, &$4);
- }
-/*
- * BX
- */
-| LTYPEBX comma ireg
- {
- outcode($1, Always, &nullgen, NREG, &$3);
- }
-/*
- * BEQ
- */
-| LTYPE5 comma rel
- {
- outcode($1, Always, &nullgen, NREG, &$3);
- }
-/*
- * SWI
- */
-| LTYPE6 cond comma gen
- {
- outcode($1, $2, &nullgen, NREG, &$4);
- }
-/*
- * CMP
- */
-| LTYPE7 cond imsr ',' spreg comma
- {
- outcode($1, $2, &$3, $5, &nullgen);
- }
-/*
- * MOVM
- */
-| LTYPE8 cond ioreg ',' '[' reglist ']'
- {
- Gen g;
-
- g = nullgen;
- g.type = D_CONST;
- g.offset = $6;
- outcode($1, $2, &$3, NREG, &g);
- }
-| LTYPE8 cond '[' reglist ']' ',' ioreg
- {
- Gen g;
-
- g = nullgen;
- g.type = D_CONST;
- g.offset = $4;
- outcode($1, $2, &g, NREG, &$7);
- }
-/*
- * SWAP
- */
-| LTYPE9 cond reg ',' ireg ',' reg
- {
- outcode($1, $2, &$5, $3.reg, &$7);
- }
-| LTYPE9 cond reg ',' ireg comma
- {
- outcode($1, $2, &$5, $3.reg, &$3);
- }
-| LTYPE9 cond comma ireg ',' reg
- {
- outcode($1, $2, &$4, $6.reg, &$6);
- }
-/*
- * RET
- */
-| LTYPEA cond comma
- {
- outcode($1, $2, &nullgen, NREG, &nullgen);
- }
-/*
- * TEXT/GLOBL
- */
-| LTYPEB name ',' imm
- {
- outcode($1, Always, &$2, NREG, &$4);
- }
-| LTYPEB name ',' con ',' imm
- {
- outcode($1, Always, &$2, $4, &$6);
- }
-/*
- * DATA
- */
-| LTYPEC name '/' con ',' ximm
- {
- outcode($1, Always, &$2, $4, &$6);
- }
-/*
- * CASE
- */
-| LTYPED cond reg comma
- {
- outcode($1, $2, &$3, NREG, &nullgen);
- }
-/*
- * word
- */
-| LTYPEH comma ximm
- {
- outcode($1, Always, &nullgen, NREG, &$3);
- }
-/*
- * floating-point coprocessor
- */
-| LTYPEI cond freg ',' freg
- {
- outcode($1, $2, &$3, NREG, &$5);
- }
-| LTYPEK cond frcon ',' freg
- {
- outcode($1, $2, &$3, NREG, &$5);
- }
-| LTYPEK cond frcon ',' LFREG ',' freg
- {
- outcode($1, $2, &$3, $5, &$7);
- }
-| LTYPEL cond freg ',' freg comma
- {
- outcode($1, $2, &$3, $5.reg, &nullgen);
- }
-/*
- * MCR MRC
- */
-| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
- {
- Gen g;
-
- g = nullgen;
- g.type = D_CONST;
- g.offset =
- (0xe << 24) | /* opcode */
- ($1 << 20) | /* MCR/MRC */
- ($2 << 28) | /* scond */
- (($3 & 15) << 8) | /* coprocessor number */
- (($5 & 7) << 21) | /* coprocessor operation */
- (($7 & 15) << 12) | /* arm register */
- (($9 & 15) << 16) | /* Crn */
- (($11 & 15) << 0) | /* Crm */
- (($12 & 7) << 5) | /* coprocessor information */
- (1<<4); /* must be set */
- outcode(AWORD, Always, &nullgen, NREG, &g);
- }
-/*
- * MULL hi,lo,r1,r2
- */
-| LTYPEM cond reg ',' reg ',' regreg
- {
- outcode($1, $2, &$3, $5.reg, &$7);
- }
-/*
- * MULA hi,lo,r1,r2
- */
-| LTYPEN cond reg ',' reg ',' reg ',' spreg
- {
- $7.type = D_REGREG;
- $7.offset = $9;
- outcode($1, $2, &$3, $5.reg, &$7);
- }
-/*
- * END
- */
-| LTYPEE comma
- {
- outcode($1, Always, &nullgen, NREG, &nullgen);
- }
-
-cond:
- {
- $$ = Always;
- }
-| cond LCOND
- {
- $$ = ($1 & ~C_SCOND) | $2;
- }
-| cond LS
- {
- $$ = $1 | $2;
- }
-
-comma:
-| ',' comma
-
-rel:
- con '(' LPC ')'
- {
- $$ = nullgen;
- $$.type = D_BRANCH;
- $$.offset = $1 + pc;
- }
-| LNAME offset
- {
- $$ = nullgen;
- if(pass == 2)
- yyerror("undefined label: %s", $1->name);
- $$.type = D_BRANCH;
- $$.sym = $1;
- $$.offset = $2;
- }
-| LLAB offset
- {
- $$ = nullgen;
- $$.type = D_BRANCH;
- $$.sym = $1;
- $$.offset = $1->value + $2;
- }
-
-ximm: '$' con
- {
- $$ = nullgen;
- $$.type = D_CONST;
- $$.offset = $2;
- }
-| '$' oreg
- {
- $$ = $2;
- $$.type = D_CONST;
- }
-| '$' '*' '$' oreg
- {
- $$ = $4;
- $$.type = D_OCONST;
- }
-| '$' LSCONST
- {
- $$ = nullgen;
- $$.type = D_SCONST;
- memcpy($$.sval, $2, sizeof($$.sval));
- }
-| fcon
-
-fcon:
- '$' LFCONST
- {
- $$ = nullgen;
- $$.type = D_FCONST;
- $$.dval = $2;
- }
-| '$' '-' LFCONST
- {
- $$ = nullgen;
- $$.type = D_FCONST;
- $$.dval = -$3;
- }
-
-reglist:
- spreg
- {
- $$ = 1 << $1;
- }
-| spreg '-' spreg
- {
- int i;
- $$=0;
- for(i=$1; i<=$3; i++)
- $$ |= 1<<i;
- for(i=$3; i<=$1; i++)
- $$ |= 1<<i;
- }
-| spreg comma reglist
- {
- $$ = (1<<$1) | $3;
- }
-
-gen:
- reg
-| ximm
-| shift
-| shift '(' spreg ')'
- {
- $$ = $1;
- $$.reg = $3;
- }
-| LPSR
- {
- $$ = nullgen;
- $$.type = D_PSR;
- $$.reg = $1;
- }
-| LFCR
- {
- $$ = nullgen;
- $$.type = D_FPCR;
- $$.reg = $1;
- }
-| con
- {
- $$ = nullgen;
- $$.type = D_OREG;
- $$.offset = $1;
- }
-| oreg
-| freg
-
-nireg:
- ireg
-| name
- {
- $$ = $1;
- if($1.name != D_EXTERN && $1.name != D_STATIC) {
- }
- }
-
-ireg:
- '(' spreg ')'
- {
- $$ = nullgen;
- $$.type = D_OREG;
- $$.reg = $2;
- $$.offset = 0;
- }
-
-ioreg:
- ireg
-| con '(' sreg ')'
- {
- $$ = nullgen;
- $$.type = D_OREG;
- $$.reg = $3;
- $$.offset = $1;
- }
-
-oreg:
- name
-| name '(' sreg ')'
- {
- $$ = $1;
- $$.type = D_OREG;
- $$.reg = $3;
- }
-| ioreg
-
-imsr:
- reg
-| imm
-| shift
-
-imm: '$' con
- {
- $$ = nullgen;
- $$.type = D_CONST;
- $$.offset = $2;
- }
-
-reg:
- spreg
- {
- $$ = nullgen;
- $$.type = D_REG;
- $$.reg = $1;
- }
-
-regreg:
- '(' spreg ',' spreg ')'
- {
- $$ = nullgen;
- $$.type = D_REGREG;
- $$.reg = $2;
- $$.offset = $4;
- }
-
-shift:
- spreg '<' '<' rcon
- {
- $$ = nullgen;
- $$.type = D_SHIFT;
- $$.offset = $1 | $4 | (0 << 5);
- }
-| spreg '>' '>' rcon
- {
- $$ = nullgen;
- $$.type = D_SHIFT;
- $$.offset = $1 | $4 | (1 << 5);
- }
-| spreg '-' '>' rcon
- {
- $$ = nullgen;
- $$.type = D_SHIFT;
- $$.offset = $1 | $4 | (2 << 5);
- }
-| spreg LAT '>' rcon
- {
- $$ = nullgen;
- $$.type = D_SHIFT;
- $$.offset = $1 | $4 | (3 << 5);
- }
-
-rcon:
- spreg
- {
- if($$ < 0 || $$ >= 16)
- print("register value out of range\n");
- $$ = (($1&15) << 8) | (1 << 4);
- }
-| con
- {
- if($$ < 0 || $$ >= 32)
- print("shift value out of range\n");
- $$ = ($1&31) << 7;
- }
-
-sreg:
- LREG
-| LPC
- {
- $$ = REGPC;
- }
-| LR '(' expr ')'
- {
- if($3 < 0 || $3 >= NREG)
- print("register value out of range\n");
- $$ = $3;
- }
-
-spreg:
- sreg
-| LSP
- {
- $$ = REGSP;
- }
-
-creg:
- LCREG
-| LC '(' expr ')'
- {
- if($3 < 0 || $3 >= NREG)
- print("register value out of range\n");
- $$ = $3;
- }
-
-frcon:
- freg
-| fcon
-
-freg:
- LFREG
- {
- $$ = nullgen;
- $$.type = D_FREG;
- $$.reg = $1;
- }
-| LF '(' con ')'
- {
- $$ = nullgen;
- $$.type = D_FREG;
- $$.reg = $3;
- }
-
-name:
- con '(' pointer ')'
- {
- $$ = nullgen;
- $$.type = D_OREG;
- $$.name = $3;
- $$.sym = S;
- $$.offset = $1;
- }
-| LNAME offset '(' pointer ')'
- {
- $$ = nullgen;
- $$.type = D_OREG;
- $$.name = $4;
- $$.sym = $1;
- $$.offset = $2;
- }
-| LNAME '<' '>' offset '(' LSB ')'
- {
- $$ = nullgen;
- $$.type = D_OREG;
- $$.name = D_STATIC;
- $$.sym = $1;
- $$.offset = $4;
- }
-
-offset:
- {
- $$ = 0;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '-' con
- {
- $$ = -$2;
- }
-
-pointer:
- LSB
-| LSP
-| LFP
-
-con:
- LCONST
-| LVAR
- {
- $$ = $1->value;
- }
-| '-' con
- {
- $$ = -$2;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '~' con
- {
- $$ = ~$2;
- }
-| '(' expr ')'
- {
- $$ = $2;
- }
-
-oexpr:
- {
- $$ = 0;
- }
-| ',' 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/5a/doc.go b/src/cmd/5a/doc.go
deleted file mode 100644
index a0d2c4c64..000000000
--- a/src/cmd/5a/doc.go
+++ /dev/null
@@ -1,14 +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.
-
-/*
-
-5a is a version of the Plan 9 assembler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2a
-
-Its target architecture is the ARM, referred to by these tools as arm.
-
-*/
-package documentation
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
deleted file mode 100644
index 3978f1a6c..000000000
--- a/src/cmd/5a/lex.c
+++ /dev/null
@@ -1,703 +0,0 @@
-// Inferno utils/5a/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5a/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.
-
-#define EXTERN
-#include "a.h"
-#include "y.tab.h"
-#include <ctype.h>
-
-enum
-{
- Plan9 = 1<<0,
- Unix = 1<<1,
- Windows = 1<<2,
-};
-
-int
-systemtype(int sys)
-{
- return sys&Plan9;
-}
-
-void
-main(int argc, char *argv[])
-{
- char *p;
- int c;
-
- thechar = '5';
- thestring = "arm";
-
- ensuresymb(NSYMB);
- memset(debug, 0, sizeof(debug));
- cinit();
- outfile = 0;
- setinclude(".");
- ARGBEGIN {
- default:
- c = ARGC();
- if(c >= 0 || c < sizeof(debug))
- debug[c] = 1;
- break;
-
- case 'o':
- outfile = ARGF();
- break;
-
- case 'D':
- p = ARGF();
- if(p) {
- if (nDlist%8 == 0)
- Dlist = allocn(Dlist, nDlist*sizeof(char *),
- 8*sizeof(char *));
- Dlist[nDlist++] = p;
- }
- break;
-
- case 'I':
- p = ARGF();
- setinclude(p);
- break;
- case 't':
- thechar = 't';
- thestring = "thumb";
- break;
- } ARGEND
- if(*argv == 0) {
- print("usage: %ca [-options] file.s\n", thechar);
- errorexit();
- }
- if(argc > 1){
- print("can't assemble multiple files\n");
- errorexit();
- }
- if(assemble(argv[0]))
- errorexit();
- 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, '/');
- 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);
-
- pass = 1;
- pinit(file);
-
- Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
-
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- if(nerrors) {
- cclean();
- return nerrors;
- }
-
- Bprint(&obuf, "\n!\n");
-
- pass = 2;
- outhist();
- pinit(file);
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- cclean();
- return nerrors;
-}
-
-struct
-{
- char *name;
- ushort type;
- ushort value;
-} itab[] =
-{
- "SP", LSP, D_AUTO,
- "SB", LSB, D_EXTERN,
- "FP", LFP, D_PARAM,
- "PC", LPC, D_BRANCH,
-
- "R", LR, 0,
- "R0", LREG, 0,
- "R1", LREG, 1,
- "R2", LREG, 2,
- "R3", LREG, 3,
- "R4", LREG, 4,
- "R5", LREG, 5,
- "R6", LREG, 6,
- "R7", LREG, 7,
- "R8", LREG, 8,
- "R9", LREG, 9,
- "R10", LREG, 10,
- "R11", LREG, 11,
- "R12", LREG, 12,
- "R13", LREG, 13,
- "R14", LREG, 14,
- "R15", LREG, 15,
-
- "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,
-
- "C", LC, 0,
-
- "C0", LCREG, 0,
- "C1", LCREG, 1,
- "C2", LCREG, 2,
- "C3", LCREG, 3,
- "C4", LCREG, 4,
- "C5", LCREG, 5,
- "C6", LCREG, 6,
- "C7", LCREG, 7,
- "C8", LCREG, 8,
- "C9", LCREG, 9,
- "C10", LCREG, 10,
- "C11", LCREG, 11,
- "C12", LCREG, 12,
- "C13", LCREG, 13,
- "C14", LCREG, 14,
- "C15", LCREG, 15,
-
- "CPSR", LPSR, 0,
- "SPSR", LPSR, 1,
-
- "FPSR", LFCR, 0,
- "FPCR", LFCR, 1,
-
- ".EQ", LCOND, 0,
- ".NE", LCOND, 1,
- ".CS", LCOND, 2,
- ".HS", LCOND, 2,
- ".CC", LCOND, 3,
- ".LO", LCOND, 3,
- ".MI", LCOND, 4,
- ".PL", LCOND, 5,
- ".VS", LCOND, 6,
- ".VC", LCOND, 7,
- ".HI", LCOND, 8,
- ".LS", LCOND, 9,
- ".GE", LCOND, 10,
- ".LT", LCOND, 11,
- ".GT", LCOND, 12,
- ".LE", LCOND, 13,
- ".AL", LCOND, Always,
-
- ".U", LS, C_UBIT,
- ".S", LS, C_SBIT,
- ".W", LS, C_WBIT,
- ".P", LS, C_PBIT,
- ".PW", LS, C_WBIT|C_PBIT,
- ".WP", LS, C_WBIT|C_PBIT,
-
- ".F", LS, C_FBIT,
-
- ".IBW", LS, C_WBIT|C_PBIT|C_UBIT,
- ".IAW", LS, C_WBIT|C_UBIT,
- ".DBW", LS, C_WBIT|C_PBIT,
- ".DAW", LS, C_WBIT,
- ".IB", LS, C_PBIT|C_UBIT,
- ".IA", LS, C_UBIT,
- ".DB", LS, C_PBIT,
- ".DA", LS, 0,
-
- "@", LAT, 0,
-
- "AND", LTYPE1, AAND,
- "EOR", LTYPE1, AEOR,
- "SUB", LTYPE1, ASUB,
- "RSB", LTYPE1, ARSB,
- "ADD", LTYPE1, AADD,
- "ADC", LTYPE1, AADC,
- "SBC", LTYPE1, ASBC,
- "RSC", LTYPE1, ARSC,
- "ORR", LTYPE1, AORR,
- "BIC", LTYPE1, ABIC,
-
- "SLL", LTYPE1, ASLL,
- "SRL", LTYPE1, ASRL,
- "SRA", LTYPE1, ASRA,
-
- "MUL", LTYPE1, AMUL,
- "MULA", LTYPEN, AMULA,
- "DIV", LTYPE1, ADIV,
- "MOD", LTYPE1, AMOD,
-
- "MULL", LTYPEM, AMULL,
- "MULAL", LTYPEM, AMULAL,
- "MULLU", LTYPEM, AMULLU,
- "MULALU", LTYPEM, AMULALU,
-
- "MVN", LTYPE2, AMVN, /* op2 ignored */
-
- "MOVB", LTYPE3, AMOVB,
- "MOVBU", LTYPE3, AMOVBU,
- "MOVH", LTYPE3, AMOVH,
- "MOVHU", LTYPE3, AMOVHU,
- "MOVW", LTYPE3, AMOVW,
-
- "MOVD", LTYPE3, AMOVD,
- "MOVDF", LTYPE3, AMOVDF,
- "MOVDW", LTYPE3, AMOVDW,
- "MOVF", LTYPE3, AMOVF,
- "MOVFD", LTYPE3, AMOVFD,
- "MOVFW", LTYPE3, AMOVFW,
- "MOVWD", LTYPE3, AMOVWD,
- "MOVWF", LTYPE3, AMOVWF,
-
- "LDREX", LTYPE3, ALDREX,
- "LDREXD", LTYPE3, ALDREXD,
- "STREX", LTYPE9, ASTREX,
- "STREXD", LTYPE9, ASTREXD,
-
-/*
- "ABSF", LTYPEI, AABSF,
- "ABSD", LTYPEI, AABSD,
- "NEGF", LTYPEI, ANEGF,
- "NEGD", LTYPEI, ANEGD,
- "SQTF", LTYPEI, ASQTF,
- "SQTD", LTYPEI, ASQTD,
- "RNDF", LTYPEI, ARNDF,
- "RNDD", LTYPEI, ARNDD,
- "URDF", LTYPEI, AURDF,
- "URDD", LTYPEI, AURDD,
- "NRMF", LTYPEI, ANRMF,
- "NRMD", LTYPEI, ANRMD,
-*/
-
- "SQRTF", LTYPEI, ASQRTF,
- "SQRTD", LTYPEI, ASQRTD,
- "CMPF", LTYPEL, ACMPF,
- "CMPD", LTYPEL, ACMPD,
- "ADDF", LTYPEK, AADDF,
- "ADDD", LTYPEK, AADDD,
- "SUBF", LTYPEK, ASUBF,
- "SUBD", LTYPEK, ASUBD,
- "MULF", LTYPEK, AMULF,
- "MULD", LTYPEK, AMULD,
- "DIVF", LTYPEK, ADIVF,
- "DIVD", LTYPEK, ADIVD,
-
- "B", LTYPE4, AB,
- "BL", LTYPE4, ABL,
- "BX", LTYPEBX, ABX,
-
- "BEQ", LTYPE5, ABEQ,
- "BNE", LTYPE5, ABNE,
- "BCS", LTYPE5, ABCS,
- "BHS", LTYPE5, ABHS,
- "BCC", LTYPE5, ABCC,
- "BLO", LTYPE5, ABLO,
- "BMI", LTYPE5, ABMI,
- "BPL", LTYPE5, ABPL,
- "BVS", LTYPE5, ABVS,
- "BVC", LTYPE5, ABVC,
- "BHI", LTYPE5, ABHI,
- "BLS", LTYPE5, ABLS,
- "BGE", LTYPE5, ABGE,
- "BLT", LTYPE5, ABLT,
- "BGT", LTYPE5, ABGT,
- "BLE", LTYPE5, ABLE,
- "BCASE", LTYPE5, ABCASE,
-
- "SWI", LTYPE6, ASWI,
-
- "CMP", LTYPE7, ACMP,
- "TST", LTYPE7, ATST,
- "TEQ", LTYPE7, ATEQ,
- "CMN", LTYPE7, ACMN,
-
- "MOVM", LTYPE8, AMOVM,
-
- "SWPBU", LTYPE9, ASWPBU,
- "SWPW", LTYPE9, ASWPW,
-
- "RET", LTYPEA, ARET,
- "RFE", LTYPEA, ARFE,
-
- "TEXT", LTYPEB, ATEXT,
- "GLOBL", LTYPEB, AGLOBL,
- "DATA", LTYPEC, ADATA,
- "CASE", LTYPED, ACASE,
- "END", LTYPEE, AEND,
- "WORD", LTYPEH, AWORD,
- "NOP", LTYPEI, ANOP,
-
- "MCR", LTYPEJ, 0,
- "MRC", LTYPEJ, 1,
- 0
-};
-
-void
-cinit(void)
-{
- Sym *s;
- int i;
-
- nullgen.sym = S;
- nullgen.offset = 0;
- nullgen.type = D_NONE;
- nullgen.name = D_NONE;
- nullgen.reg = NREG;
- if(FPCHIP)
- nullgen.dval = 0;
- for(i=0; i<sizeof(nullgen.sval); i++)
- nullgen.sval[i] = 0;
-
- nerrors = 0;
- iostack = I;
- iofree = I;
- peekc = IGN;
- 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;
- }
-
- pathname = allocn(pathname, 0, 100);
- if(getwd(pathname, 99) == 0) {
- pathname = allocn(pathname, 100, 900);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
- }
-}
-
-void
-syminit(Sym *s)
-{
-
- s->type = LNAME;
- s->value = 0;
-}
-
-int
-isreg(Gen *g)
-{
-
- USED(g);
- return 1;
-}
-
-void
-cclean(void)
-{
-
- outcode(AEND, Always, &nullgen, NREG, &nullgen);
- Bflush(&obuf);
-}
-
-void
-zname(char *n, int t, int s)
-{
-
- Bputc(&obuf, ANAME);
- Bputc(&obuf, t); /* type */
- Bputc(&obuf, s); /* sym */
- while(*n) {
- Bputc(&obuf, *n);
- n++;
- }
- Bputc(&obuf, 0);
-}
-
-void
-zaddr(Gen *a, int s)
-{
- int32 l;
- int i;
- char *n;
- Ieee e;
-
- Bputc(&obuf, a->type);
- Bputc(&obuf, a->reg);
- Bputc(&obuf, s);
- Bputc(&obuf, a->name);
- switch(a->type) {
- default:
- print("unknown type %d\n", a->type);
- exits("arg");
-
- case D_NONE:
- case D_REG:
- case D_FREG:
- case D_PSR:
- case D_FPCR:
- break;
-
- case D_REGREG:
- Bputc(&obuf, a->offset);
- break;
-
- case D_OREG:
- case D_CONST:
- case D_BRANCH:
- case D_SHIFT:
- l = a->offset;
- Bputc(&obuf, l);
- Bputc(&obuf, l>>8);
- Bputc(&obuf, l>>16);
- Bputc(&obuf, l>>24);
- break;
-
- case D_SCONST:
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- Bputc(&obuf, *n);
- n++;
- }
- break;
-
- case D_FCONST:
- ieeedtod(&e, a->dval);
- Bputc(&obuf, e.l);
- Bputc(&obuf, e.l>>8);
- Bputc(&obuf, e.l>>16);
- Bputc(&obuf, e.l>>24);
- Bputc(&obuf, e.h);
- Bputc(&obuf, e.h>>8);
- Bputc(&obuf, e.h>>16);
- Bputc(&obuf, e.h>>24);
- break;
- }
-}
-
-static int bcode[] =
-{
- ABEQ,
- ABNE,
- ABCS,
- ABCC,
- ABMI,
- ABPL,
- ABVS,
- ABVC,
- ABHI,
- ABLS,
- ABGE,
- ABLT,
- ABGT,
- ABLE,
- AB,
- ANOP,
-};
-
-void
-outcode(int a, int scond, Gen *g1, int reg, Gen *g2)
-{
- int sf, st, t;
- Sym *s;
-
- /* hack to make B.NE etc. work: turn it into the corresponding conditional */
- if(a == AB){
- a = bcode[scond&0xf];
- scond = (scond & ~0xf) | Always;
- }
-
- if(pass == 1)
- goto out;
-jackpot:
- sf = 0;
- s = g1->sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = g1->name;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = g2->sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = g2->name;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- Bputc(&obuf, a);
- Bputc(&obuf, scond);
- Bputc(&obuf, reg);
- Bputc(&obuf, stmtline);
- Bputc(&obuf, stmtline>>8);
- Bputc(&obuf, stmtline>>16);
- Bputc(&obuf, stmtline>>24);
- zaddr(g1, sf);
- zaddr(g2, st);
-
-out:
- if(a != AGLOBL && a != ADATA)
- pc++;
-}
-
-void
-outhist(void)
-{
- Gen g;
- Hist *h;
- char *p, *q, *op, c;
- int n;
-
- g = nullgen;
- c = '/';
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- op = 0;
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname+2;
- c = *p;
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = strchr(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- Bputc(&obuf, ANAME);
- Bputc(&obuf, D_FILE); /* type */
- Bputc(&obuf, 1); /* sym */
- Bputc(&obuf, '<');
- Bwrite(&obuf, p, n);
- Bputc(&obuf, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- g.offset = h->offset;
-
- Bputc(&obuf, AHISTORY);
- Bputc(&obuf, Always);
- Bputc(&obuf, 0);
- Bputc(&obuf, h->line);
- Bputc(&obuf, h->line>>8);
- Bputc(&obuf, h->line>>16);
- Bputc(&obuf, h->line>>24);
- zaddr(&nullgen, 0);
- zaddr(&g, 0);
- }
-}
-
-#include "../cc/lexbody"
-#include "../cc/macbody"
diff --git a/src/cmd/5c/Makefile b/src/cmd/5c/Makefile
deleted file mode 100644
index 70b614e8a..000000000
--- a/src/cmd/5c/Makefile
+++ /dev/null
@@ -1,34 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=5c
-
-HFILES=\
- gc.h\
- ../5l/5.out.h\
- ../cc/cc.h\
-
-OFILES=\
- cgen.$O\
- list.$O\
- sgen.$O\
- swt.$O\
- txt.$O\
- mul.$O\
- reg.$O\
- peep.$O\
- pgen.$O\
- pswt.$O\
- ../5l/enam.$O\
-
-LIB=\
- ../cc/cc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../cc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/5c/cgen.c b/src/cmd/5c/cgen.c
deleted file mode 100644
index 9e74f515b..000000000
--- a/src/cmd/5c/cgen.c
+++ /dev/null
@@ -1,1199 +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"
-
-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]) {
- sugen(n, nn, n->type->width);
- return;
- }
- l = n->left;
- r = n->right;
- o = n->op;
- if(n->addable >= INDEXED) {
- if(nn == Z) {
- switch(o) {
- default:
- nullwarn(Z, Z);
- break;
- case OINDEX:
- nullwarn(l, r);
- break;
- }
- return;
- }
- gmove(n, nn);
- return;
- }
- curs = cursafe;
-
- if(n->complex >= FNX)
- if(l->complex >= FNX)
- if(r != Z && r->complex >= FNX)
- switch(o) {
- default:
- regret(&nod, r);
- cgen(r, &nod);
-
- regsalloc(&nod1, r);
- gopcode(OAS, &nod, Z, &nod1);
-
- regfree(&nod);
- nod = *n;
- nod.right = &nod1;
- cgen(&nod, nn);
- return;
-
- case OFUNC:
- case OCOMMA:
- case OANDAND:
- case OOROR:
- case OCOND:
- case ODOT:
- break;
- }
-
- switch(o) {
- default:
- diag(n, "unknown op in cgen: %O", o);
- break;
-
- case OAS:
- if(l->op == OBIT)
- goto bitas;
- if(l->addable >= INDEXED && l->complex < FNX) {
- if(nn != Z || r->addable < INDEXED) {
- if(r->complex >= FNX && nn == Z)
- regret(&nod, r);
- else
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- gmove(&nod, l);
- if(nn != Z)
- gmove(&nod, nn);
- regfree(&nod);
- } else
- gmove(r, l);
- break;
- }
- if(l->complex >= r->complex) {
- reglcgen(&nod1, l, Z);
- if(r->addable >= INDEXED) {
- gmove(r, &nod1);
- if(nn != Z)
- gmove(r, nn);
- regfree(&nod1);
- break;
- }
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- } else {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- reglcgen(&nod1, l, Z);
- }
- gmove(&nod, &nod1);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- bitas:
- n = l->left;
- regalloc(&nod, r, nn);
- if(l->complex >= r->complex) {
- reglcgen(&nod1, n, Z);
- cgen(r, &nod);
- } else {
- cgen(r, &nod);
- reglcgen(&nod1, n, Z);
- }
- regalloc(&nod2, n, Z);
- gopcode(OAS, &nod1, Z, &nod2);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
-
- case OBIT:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- bitload(n, &nod, Z, Z, nn);
- gopcode(OAS, &nod, Z, nn);
- regfree(&nod);
- break;
-
- case 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);
- 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]--;
- if(nn != Z) {
- regret(&nod, n);
- gopcode(OAS, &nod, Z, nn);
- regfree(&nod);
- }
- break;
-
- case OIND:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- regialloc(&nod, n, nn);
- r = l;
- while(r->op == OADD)
- r = r->right;
- if(sconst(r) && (v = r->vconst+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);
- 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 fn call
- */
- if(nn != Z && nn->complex >= FNX) {
- nod1 = *n;
- nod1.type = typ(TIND, n->type);
- regret(&nod2, &nod1);
- lcgen(nn, &nod2);
- regsalloc(&nod0, &nod1);
- gopcode(OAS, &nod2, Z, &nod0);
- regfree(&nod2);
-
- nod1 = *n;
- nod1.op = OIND;
- nod1.left = &nod0;
- nod1.right = Z;
- nod1.complex = 1;
-
- sugen(n, &nod1, w);
- return;
- }
-
- r = n->left;
- for(t = n->type->link; t != T; t = t->down) {
- l = r;
- if(r->op == OLIST) {
- l = r->left;
- r = r->right;
- }
- if(nn == Z) {
- cgen(l, nn);
- continue;
- }
- /*
- * hand craft *(&nn + o) = l
- */
- nod0 = znode;
- nod0.op = OAS;
- nod0.type = t;
- nod0.left = &nod1;
- nod0.right = l;
-
- nod1 = znode;
- nod1.op = OIND;
- nod1.type = t;
- nod1.left = &nod2;
-
- nod2 = znode;
- nod2.op = OADD;
- nod2.type = typ(TIND, t);
- nod2.left = &nod3;
- nod2.right = &nod4;
-
- nod3 = znode;
- nod3.op = OADDR;
- nod3.type = nod2.type;
- nod3.left = nn;
-
- nod4 = znode;
- nod4.op = OCONST;
- nod4.type = nod2.type;
- nod4.vconst = t->offset;
-
- ccom(&nod0);
- acom(&nod0);
- xcom(&nod0);
- nod0.addable = 0;
-
- cgen(&nod0, Z);
- }
- break;
-
- case OAS:
- if(nn == Z) {
- if(n->addable < INDEXED)
- sugen(n->right, n->left, w);
- break;
- }
- sugen(n->right, nodrat, w);
- warn(n, "non-interruptable temporary");
- sugen(nodrat, n->left, w);
- sugen(nodrat, nn, w);
- break;
-
- case OFUNC:
- if(nn == Z) {
- sugen(n, nodrat, w);
- break;
- }
- if(nn->op != OIND) {
- nn = new1(OADDR, nn, Z);
- nn->type = types[TIND];
- nn->addable = 0;
- } else
- nn = nn->left;
- n = new(OFUNC, n->left, new(OLIST, nn, n->right));
- n->type = types[TVOID];
- n->left->type = types[TVOID];
- cgen(n, Z);
- break;
-
- case OCOND:
- bcgen(n->left, 1);
- p1 = p;
- sugen(n->right->left, nn, w);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- sugen(n->right->right, nn, w);
- patch(p1, pc);
- break;
-
- case OCOMMA:
- cgen(n->left, Z);
- sugen(n->right, nn, w);
- break;
- }
- return;
-
-copy:
- if(nn == Z)
- return;
- if(n->complex >= FNX && nn->complex >= FNX) {
- t = nn->type;
- nn->type = types[TLONG];
- regialloc(&nod1, nn, Z);
- lcgen(nn, &nod1);
- regsalloc(&nod2, nn);
- nn->type = t;
-
- gopcode(OAS, &nod1, Z, &nod2);
- regfree(&nod1);
-
- nod2.type = typ(TIND, t);
-
- nod1 = nod2;
- nod1.op = OIND;
- nod1.left = &nod2;
- nod1.right = Z;
- nod1.complex = 1;
- nod1.type = t;
-
- sugen(n, &nod1, w);
- return;
- }
-
- 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 0874293bf..000000000
--- a/src/cmd/5c/doc.go
+++ /dev/null
@@ -1,14 +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.
-
-/*
-
-5c is a version of the Plan 9 C compiler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2c
-
-Its target architecture is the ARM, referred to by these tools as arm.
-
-*/
-package documentation
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h
deleted file mode 100644
index ff6d51916..000000000
--- a/src/cmd/5c/gc.h
+++ /dev/null
@@ -1,384 +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 Adr Adr;
-typedef struct Prog Prog;
-typedef struct Case Case;
-typedef struct C1 C1;
-typedef struct Multab Multab;
-typedef struct Hintab Hintab;
-typedef struct Var Var;
-typedef struct Reg Reg;
-typedef struct Rgn Rgn;
-
-
-#define R0ISZERO 0
-
-struct Adr
-{
- int32 offset;
- int32 offset2;
- double dval;
- char sval[NSNAME];
- Ieee ieee;
-
- Sym* sym;
- char type;
- uchar reg;
- char name;
- char etype;
-};
-#define A ((Adr*)0)
-
-#define INDEXED 9
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* link;
- int32 lineno;
- char as;
- uchar reg;
- uchar scond;
-};
-#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 Var
-{
- int32 offset;
- Sym* sym;
- char name;
- char etype;
-};
-
-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 Prog* firstp;
-EXTERN int32 isbigendian;
-EXTERN Prog* lastp;
-EXTERN int32 maxargsafe;
-EXTERN int mnstring;
-EXTERN Multab multab[20];
-EXTERN int retok;
-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 Var var[NVAR];
-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(void);
-
-/*
- * 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*);
-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*, Adr*);
-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*);
-
-/*
- * swt.c
- */
-int swcmp(const void*, const void*);
-void doswit(Node*);
-void swit1(C1*, int, int32, Node*);
-void cas(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);
-void ieeedtod(Ieee*, double);
-
-/*
- * list
- */
-void listinit(void);
-int Pconv(Fmt*);
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Sconv(Fmt*);
-int Nconv(Fmt*);
-int Bconv(Fmt*);
-int Rconv(Fmt*);
-
-/*
- * reg.c
- */
-Reg* rega(void);
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Adr*, int);
-void prop(Reg*, Bits, Bits);
-void loopit(Reg*, 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(Adr*, int);
-
-/*
- * peep.c
- */
-void peep(void);
-void excise(Reg*);
-Reg* uniqp(Reg*);
-Reg* uniqs(Reg*);
-int regtyp(Adr*);
-int regzer(Adr*);
-int anyvar(Adr*);
-int subprop(Reg*);
-int copyprop(Reg*);
-int shiftprop(Reg*);
-void constprop(Adr*, Adr*, Reg*);
-int copy1(Adr*, Adr*, Reg*, int);
-int copyu(Prog*, Adr*, Adr*);
-
-int copyas(Adr*, Adr*);
-int copyau(Adr*, Adr*);
-int copyau1(Prog*, Adr*);
-int copysub(Adr*, Adr*, Adr*, int);
-int copysub1(Prog*, Adr*, Adr*, int);
-
-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);
-
-#pragma varargck type "A" int
-#pragma varargck type "B" Bits
-#pragma varargck type "D" Adr*
-#pragma varargck type "N" Adr*
-#pragma varargck type "R" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "S" char*
diff --git a/src/cmd/5c/list.c b/src/cmd/5c/list.c
deleted file mode 100644
index ab0fae83c..000000000
--- a/src/cmd/5c/list.c
+++ /dev/null
@@ -1,340 +0,0 @@
-// Inferno utils/5c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/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)
-{
-
- fmtinstall('A', Aconv);
- fmtinstall('P', Pconv);
- fmtinstall('S', Sconv);
- fmtinstall('N', Nconv);
- fmtinstall('B', Bconv);
- fmtinstall('D', Dconv);
- fmtinstall('R', Rconv);
-}
-
-int
-Bconv(Fmt *fp)
-{
- char str[STRINGSZ], ss[STRINGSZ], *s;
- Bits bits;
- int i;
-
- str[0] = 0;
- bits = va_arg(fp->args, Bits);
- while(bany(&bits)) {
- i = bnum(bits);
- if(str[0])
- strcat(str, " ");
- if(var[i].sym == S) {
- sprint(ss, "$%d", 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);
-}
-
-char *extra [] = {
- ".EQ", ".NE", ".CS", ".CC",
- ".MI", ".PL", ".VS", ".VC",
- ".HI", ".LS", ".GE", ".LT",
- ".GT", ".LE", "", ".NV",
-};
-
-int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ], sc[20];
- Prog *p;
- int a, s;
-
- p = va_arg(fp->args, Prog*);
- a = p->as;
- s = p->scond;
- strcpy(sc, extra[s & C_SCOND]);
- if(s & C_SBIT)
- strcat(sc, ".S");
- if(s & C_PBIT)
- strcat(sc, ".P");
- if(s & C_WBIT)
- strcat(sc, ".W");
- if(s & C_UBIT) /* ambiguous with FBIT */
- strcat(sc, ".U");
- if(a == AMOVM) {
- if(p->from.type == D_CONST)
- sprint(str, " %A%s %R,%D", a, sc, &p->from, &p->to);
- else
- if(p->to.type == D_CONST)
- sprint(str, " %A%s %D,%R", a, sc, &p->from, &p->to);
- else
- sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to);
- } else
- if(a == ADATA)
- sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
- else
- if(p->as == ATEXT)
- sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to);
- else
- if(p->reg == NREG)
- sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to);
- else
- if(p->from.type != D_FREG)
- sprint(str, " %A%s %D,R%d,%D", a, sc, &p->from, p->reg, &p->to);
- else
- sprint(str, " %A%s %D,F%d,%D", a, sc, &p->from, p->reg, &p->to);
- return fmtstrcpy(fp, str);
-}
-
-int
-Aconv(Fmt *fp)
-{
- char *s;
- int a;
-
- a = va_arg(fp->args, int);
- s = "???";
- if(a >= AXXX && a < ALAST)
- s = anames[a];
- return fmtstrcpy(fp, s);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Adr *a;
- char *op;
- int v;
-
- a = va_arg(fp->args, Adr*);
- switch(a->type) {
-
- default:
- sprint(str, "GOK-type(%d)", a->type);
- break;
-
- case D_NONE:
- str[0] = 0;
- if(a->name != D_NONE || a->reg != NREG || a->sym != S)
- sprint(str, "%N(R%d)(NONE)", a, a->reg);
- break;
-
- case D_CONST:
- if(a->reg != NREG)
- sprint(str, "$%N(R%d)", a, a->reg);
- else
- sprint(str, "$%N", a);
- break;
-
- case D_CONST2:
- sprint(str, "$%d-%d", a->offset, a->offset2);
- break;
-
- case D_SHIFT:
- v = a->offset;
- op = "<<>>->@>" + (((v>>5) & 3) << 1);
- if(v & (1<<4))
- sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
- else
- sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
- if(a->reg != NREG)
- sprint(str+strlen(str), "(R%d)", a->reg);
- break;
-
- case D_OREG:
- if(a->reg != NREG)
- sprint(str, "%N(R%d)", a, a->reg);
- else
- sprint(str, "%N", a);
- break;
-
- case D_REG:
- sprint(str, "R%d", a->reg);
- if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_FREG:
- sprint(str, "F%d", a->reg);
- if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_PSR:
- sprint(str, "PSR");
- if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(PSR)(REG)", a);
- break;
-
- case D_BRANCH:
- sprint(str, "%d(PC)", a->offset-pc);
- break;
-
- case D_FCONST:
- sprint(str, "$%.17e", a->dval);
- break;
-
- case D_SCONST:
- sprint(str, "$\"%S\"", a->sval);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Adr *a;
- int i, v;
-
- a = va_arg(fp->args, Adr*);
- sprint(str, "GOK-reglist");
- switch(a->type) {
- case D_CONST:
- case D_CONST2:
- if(a->reg != NREG)
- break;
- if(a->sym != S)
- break;
- v = a->offset;
- strcpy(str, "");
- for(i=0; i<NREG; i++) {
- if(v & (1<<i)) {
- if(str[0] == 0)
- strcat(str, "[R");
- else
- strcat(str, ",R");
- sprint(strchr(str, 0), "%d", i);
- }
- }
- strcat(str, "]");
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<NSNAME; i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9' ||
- c == ' ' || c == '%') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- case '\r':
- *p++ = 'r';
- continue;
- case '\f':
- *p++ = 'f';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
-}
-
-int
-Nconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Adr *a;
- Sym *s;
-
- a = va_arg(fp->args, Adr*);
- s = a->sym;
- if(s == S) {
- sprint(str, "%d", a->offset);
- goto out;
- }
- switch(a->name) {
- default:
- sprint(str, "GOK-name(%d)", a->name);
- break;
-
- case D_NONE:
- sprint(str, "%d", a->offset);
- break;
-
- case D_EXTERN:
- sprint(str, "%s+%d(SB)", s->name, a->offset);
- break;
-
- case D_STATIC:
- sprint(str, "%s<>+%d(SB)", s->name, a->offset);
- break;
-
- case D_AUTO:
- sprint(str, "%s-%d(SP)", s->name, -a->offset);
- break;
-
- case D_PARAM:
- sprint(str, "%s+%d(FP)", s->name, a->offset);
- break;
- }
-out:
- return fmtstrcpy(fp, str);
-}
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 c15bf0fc4..000000000
--- a/src/cmd/5c/peep.c
+++ /dev/null
@@ -1,1469 +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*, Adr*);
-
-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 AMOVHU:
- case AMOVB:
- 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 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(Adr *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;
- Adr *v1, *v2;
- Reg *r;
- int t;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case 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;
- Adr *v1, *v2;
- Reg *r;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Adr *v1, Adr *v2, Reg *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, A);
- switch(t) {
- case 2: /* rar, cant split */
- if(debug['P'])
- print("; %Drar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %Dset; return 1\n", v2);
- return 1;
-
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %Dused+set and f=%d; return 0\n", v2, f);
- else
- print("; %Dused and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub%D/%D", v2, v1);
- if(t == 4) {
- if(debug['P'])
- print("; %Dused+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, A);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %Dset and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
-}
-
-/*
- * 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(Adr *c1, Adr *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;
- Adr 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, Adr *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, Adr *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)
-{
- Adr 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, Adr *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, Adr *v)
-{
- Reg *r1;
-
- for(r1=firstr; r1!=R; r1=r1->link)
- r1->active = 0;
- return findu1(r, v);
-}
-
-int
-xtramodes(Reg *r, Adr *a)
-{
- Reg *r1, *r2, *r3;
- Prog *p, *p1;
- Adr v;
-
- p = r->prog;
- if(debug['h'] && p->as == AMOVB && 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 || (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 */
- a->type = D_SHIFT;
- a->offset = p1->from.reg;
- break;
- case D_SHIFT:
- /* scaled register offset */
- 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, Adr *v, Adr *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 AMOVHU:
- case AMOVB:
- 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:
- 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 == (uchar)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 == (uchar)REGARG)
- return 3;
- return 0;
- }
- 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(Adr *a, Adr *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(Adr *a, Adr *v)
-{
-
- if(copyas(a, v))
- return 1;
- if(v->type == D_REG) {
- if(a->type == D_OREG) {
- if(v->reg == a->reg)
- return 1;
- } 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, Adr *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(Adr *a, Adr *v, Adr *s, int f)
-{
-
- if(f)
- if(copyau(a, v)) {
- if(a->type == D_SHIFT) {
- if((a->offset&0xf) == v->reg)
- a->offset = (a->offset&~0xf)|s->reg;
- if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
- a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
- } else
- a->reg = s->reg;
- }
- return 0;
-}
-
-int
-copysub1(Prog *p1, Adr *v, Adr *s, int f)
-{
-
- if(f)
- if(copyau1(p1, v))
- p1->reg = s->reg;
- return 0;
-}
-
-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 8c9794418..000000000
--- a/src/cmd/5c/reg.c
+++ /dev/null
@@ -1,1192 +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;
-
- // TODO(kaib): optimizer disabled because it smashes R8 when running out of registers
- // the disable is unconventionally here because the call is in common code shared by 5c/6c/8c
- return;
-
- firstr = R;
- lastr = R;
- nvar = 0;
- regbits = 0;
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- }
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- val = 5L * 5L * 5L * 5L * 5L;
- lp = log5;
- for(i=0; i<5; i++) {
- lp->m = val;
- lp->c = 0;
- lp->p = R;
- val /= 5L;
- lp++;
- }
- val = 0;
- for(; p != P; p = p->link) {
- switch(p->as) {
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- continue;
- }
- r = rega();
- if(firstr == R) {
- firstr = r;
- lastr = r;
- } else {
- lastr->link = r;
- r->p1 = lastr;
- lastr->s1 = r;
- lastr = r;
- }
- r->prog = p;
- r->pc = val;
- val++;
-
- lp = log5;
- for(i=0; i<5; i++) {
- lp->c--;
- if(lp->c <= 0) {
- lp->c = lp->m;
- if(lp->p != R)
- lp->p->log5 = r;
- lp->p = r;
- (lp+1)->c = 0;
- break;
- }
- lp++;
- }
-
- r1 = r->p1;
- if(r1 != R)
- switch(r1->prog->as) {
- case ARET:
- case 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 AMOVBU:
- case AMOVH:
- case AMOVHU:
- case AMOVW:
- case AMOVF:
- case AMOVD:
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- break;
-
- /*
- * funny
- */
- case ABL:
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- 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) {
- warn(Z, "too many regions");
- goto brk;
- }
- rgp++;
- }
- }
-brk:
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- for(i=0; i<nregion; i++) {
- bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
- vreg = allreg(vreg, rgp);
- if(debug['R']) {
- if(rgp->regno >= NREG)
- print("%L $%d F%d: %B\n",
- rgp->enter->prog->lineno,
- rgp->cost,
- rgp->regno-NREG,
- bit);
- else
- print("%L $%d R%d: %B\n",
- rgp->enter->prog->lineno,
- rgp->cost,
- rgp->regno,
- bit);
- }
- if(rgp->regno != 0)
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- rgp++;
- }
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P'])
- peep();
-
- /*
- * pass 8
- * recalculate pc
- */
- val = initpc;
- for(r = firstr; r != R; r = r1) {
- r->pc = val;
- p = r->prog;
- p1 = P;
- r1 = r->link;
- if(r1 != R)
- p1 = r1->prog;
- for(; p != p1; p = p->link) {
- switch(p->as) {
- default:
- val++;
- break;
-
- case ANOP:
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- break;
- }
- }
- }
- pc = val;
-
- /*
- * fix up branches
- */
- if(debug['R'])
- if(bany(&addrs))
- print("addrs: %B\n", addrs);
-
- r1 = 0; /* set */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH)
- p->to.offset = r->s2->pc;
- r1 = r;
- }
-
- /*
- * last pass
- * eliminate nops
- * free aux structures
- */
- for(p = firstr->prog; p != P; p = p->link){
- while(p->link && p->link->as == ANOP)
- p->link = p->link->link;
- }
- if(r1 != R) {
- r1->link = freer;
- freer = firstr;
- }
-}
-
-void
-addsplits(void)
-{
- Reg *r, *r1;
- int z, i;
- Bits bit;
-
- for(r = firstr; r != R; r = r->link) {
- if(r->loop > 1)
- continue;
- if(r->prog->as == 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;
- Adr *a;
- Var *v;
-
- p1 = alloc(sizeof(*p1));
- *p1 = zprog;
- p = r->prog;
-
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->sym = v->sym;
- a->name = v->name;
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = D_OREG;
- if(a->etype == TARRAY || a->sym == S)
- a->type = D_CONST;
-
- p1->as = AMOVW;
- if(v->etype == TCHAR || v->etype == TUCHAR)
- p1->as = AMOVB;
- if(v->etype == TSHORT || v->etype == TUSHORT)
- p1->as = AMOVH;
- if(v->etype == TFLOAT)
- p1->as = AMOVF;
- if(v->etype == TDOUBLE)
- p1->as = AMOVD;
-
- p1->from.type = D_REG;
- p1->from.reg = rn;
- if(rn >= NREG) {
- p1->from.type = D_FREG;
- p1->from.reg = rn-NREG;
- }
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = D_REG;
- a->reg = rn;
- if(rn >= NREG) {
- a->type = D_FREG;
- a->reg = rn-NREG;
- }
- if(v->etype == TUCHAR)
- p1->as = AMOVBU;
- if(v->etype == TUSHORT)
- p1->as = AMOVHU;
- }
- if(debug['R'])
- print("%P\t.a%P\n", p, p1);
-}
-
-Bits
-mkvar(Adr *a, int docon)
-{
- Var *v;
- int i, t, n, et, z;
- int32 o;
- Bits bit;
- Sym *s;
-
- t = a->type;
- if(t == D_REG && a->reg != NREG)
- regbits |= RtoB(a->reg);
- if(t == D_FREG && a->reg != NREG)
- regbits |= FtoB(a->reg);
- s = a->sym;
- o = a->offset;
- et = a->etype;
- if(s == S) {
- if(t != D_CONST || !docon || a->reg != NREG)
- goto none;
- et = TLONG;
- }
- if(t == D_CONST) {
- if(s == S && sval(o))
- goto none;
- }
-
- n = a->name;
- v = var;
- for(i=0; i<nvar; i++) {
- if(s == v->sym)
- if(n == v->name)
- if(o == v->offset)
- goto out;
- v++;
- }
- if(s)
- if(s->name[0] == '.')
- goto none;
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
- warn(Z, "variable not optimized: %s", s->name);
- goto none;
- }
- i = nvar;
- nvar++;
- v = &var[i];
- v->sym = s;
- v->offset = o;
- v->etype = et;
- v->name = n;
- if(debug['R'])
- print("bit=%2d et=%2d %D\n", i, et, a);
-out:
- bit = blsh(i);
- if(n == D_EXTERN || n == D_STATIC)
- for(z=0; z<BITS; z++)
- externs.b[z] |= bit.b[z];
- if(n == D_PARAM)
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
- if(v->etype != et || !typechlpfd[et]) /* funny punning */
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- if(t == D_CONST) {
- if(s == S) {
- for(z=0; z<BITS; z++)
- consts.b[z] |= bit.b[z];
- return bit;
- }
- if(et != TARRAY)
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
- return bit;
- }
- if(t == D_OREG)
- return bit;
-
-none:
- return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
- Reg *r1, *r2;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->p1) {
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(r1->prog->as) {
- case 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(Adr *a, int rn)
-{
-
- a->sym = 0;
- a->name = D_NONE;
- a->type = D_REG;
- a->reg = rn;
- if(rn >= NREG) {
- a->type = D_FREG;
- a->reg = rn-NREG;
- }
-}
-
-/*
- * bit reg
- * 0 R0
- * 1 R1
- * ... ...
- * 10 R10
- */
-int32
-RtoB(int r)
-{
-
- if(r < 2 || r >= REGTMP-2) // excluded R9 and R10 for m and g
- return 0;
- return 1L << r;
-}
-
-int
-BtoR(int32 b)
-{
- b &= 0x01fcL; // excluded R9 and R10 for m and g
- if(b == 0)
- return 0;
- return bitno(b);
-}
-
-/*
- * bit reg
- * 18 F2
- * 19 F3
- * ... ...
- * 23 F7
- */
-int32
-FtoB(int f)
-{
-
- if(f < 2 || f > NFREG-1)
- return 0;
- return 1L << (f + 16);
-}
-
-int
-BtoF(int32 b)
-{
-
- b &= 0xfc0000L;
- 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 92a0f64f8..000000000
--- a/src/cmd/5c/sgen.c
+++ /dev/null
@@ -1,267 +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 = 0;
- if(!(textflag & NOSPLIT))
- a = argsize();
- else if(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 431f04817..000000000
--- a/src/cmd/5c/swt.c
+++ /dev/null
@@ -1,694 +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)
-{
- C1 *r;
- int i;
- int32 v;
- Prog *sp;
-
- if(nc >= 3) {
- i = (q+nc-1)->val - (q+0)->val;
- if(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);
- swit1(q, i, def, n);
-
- if(debug['W'])
- print("case < %.8ux\n", r->val);
- patch(sp, pc);
- swit1(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.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.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 zname(Biobuf*, Sym*, int);
-char* zaddr(char*, Adr*, int);
-void zwrite(Biobuf*, Prog*, int, int);
-void outhist(Biobuf*);
-
-void
-zwrite(Biobuf *b, Prog *p, int sf, int st)
-{
- char bf[100], *bp;
-
- bf[0] = p->as;
- bf[1] = p->scond;
- bf[2] = p->reg;
- bf[3] = p->lineno;
- bf[4] = p->lineno>>8;
- bf[5] = p->lineno>>16;
- bf[6] = p->lineno>>24;
- bp = zaddr(bf+7, &p->from, sf);
- bp = zaddr(bp, &p->to, st);
- Bwrite(b, bf, bp-bf);
-}
-
-void
-outcode(void)
-{
- struct { Sym *sym; short type; } h[NSYM];
- Prog *p;
- Sym *s;
- int sf, st, t, sym;
-
- if(debug['S']) {
- for(p = firstp; p != P; p = p->link)
- if(p->as != ADATA && p->as != AGLOBL)
- pc--;
- for(p = firstp; p != P; p = p->link) {
- print("%P\n", p);
- if(p->as != ADATA && p->as != AGLOBL)
- pc++;
- }
- }
-
- Bprint(&outbuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
- if(ndynimp > 0 || ndynexp > 0) {
- int i;
-
- Bprint(&outbuf, "\n");
- Bprint(&outbuf, "$$ // exports\n\n");
- Bprint(&outbuf, "$$ // local types\n\n");
- Bprint(&outbuf, "$$ // dynimport\n", thestring);
- for(i=0; i<ndynimp; i++)
- Bprint(&outbuf, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path);
- Bprint(&outbuf, "\n$$ // dynexport\n", thestring);
- for(i=0; i<ndynexp; i++)
- Bprint(&outbuf, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
- Bprint(&outbuf, "\n$$\n\n");
- }
- Bprint(&outbuf, "!\n");
-
- outhist(&outbuf);
- for(sym=0; sym<NSYM; sym++) {
- h[sym].sym = S;
- h[sym].type = 0;
- }
- sym = 1;
- for(p = firstp; p != P; p = p->link) {
- jackpot:
- sf = 0;
- s = p->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = p->from.name;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- s->sym = sym;
- zname(&outbuf, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = p->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = p->to.name;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- s->sym = sym;
- zname(&outbuf, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- zwrite(&outbuf, p, sf, st);
- }
- firstp = P;
- lastp = P;
-}
-
-void
-outhist(Biobuf *b)
-{
- Hist *h;
- char *p, *q, *op, c;
- Prog pg;
- int n;
-
- pg = zprog;
- pg.as = AHISTORY;
- c = pathchar();
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- op = 0;
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname+2;
- c = *p;
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = utfrune(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- Bputc(b, ANAME);
- Bputc(b, D_FILE);
- Bputc(b, 1);
- Bputc(b, '<');
- Bwrite(b, p, n);
- Bputc(b, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- pg.lineno = h->line;
- pg.to.type = zprog.to.type;
- pg.to.offset = h->offset;
- if(h->offset)
- pg.to.type = D_CONST;
-
- zwrite(b, &pg, 0, 0);
- }
-}
-
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- char *n, bf[7];
- uint32 sig;
-
- n = s->name;
- if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
- sig = sign(s);
- bf[0] = ASIGNAME;
- bf[1] = sig;
- bf[2] = sig>>8;
- bf[3] = sig>>16;
- bf[4] = sig>>24;
- bf[5] = t;
- bf[6] = s->sym;
- Bwrite(b, bf, 7);
- s->sig = SIGDONE;
- }
- else{
- bf[0] = ANAME;
- bf[1] = t; /* type */
- bf[2] = s->sym; /* sym */
- Bwrite(b, bf, 3);
- }
- Bwrite(b, n, strlen(n)+1);
-}
-
-char*
-zaddr(char *bp, Adr *a, int s)
-{
- int32 l;
- Ieee e;
-
- bp[0] = a->type;
- bp[1] = a->reg;
- bp[2] = s;
- bp[3] = a->name;
- bp += 4;
- switch(a->type) {
- default:
- diag(Z, "unknown type %d in zaddr", a->type);
-
- case D_NONE:
- case D_REG:
- case D_FREG:
- case D_PSR:
- break;
-
- case D_CONST2:
- l = a->offset2;
- bp[0] = l;
- bp[1] = l>>8;
- bp[2] = l>>16;
- bp[3] = l>>24;
- bp += 4; // fall through
- case D_OREG:
- case D_CONST:
- case D_BRANCH:
- case D_SHIFT:
- l = a->offset;
- bp[0] = l;
- bp[1] = l>>8;
- bp[2] = l>>16;
- bp[3] = l>>24;
- bp += 4;
- break;
-
- case D_SCONST:
- memmove(bp, a->sval, NSNAME);
- bp += NSNAME;
- break;
-
- case D_FCONST:
- ieeedtod(&e, a->dval);
- l = e.l;
- bp[0] = l;
- bp[1] = l>>8;
- bp[2] = l>>16;
- bp[3] = l>>24;
- bp += 4;
- l = e.h;
- bp[0] = l;
- bp[1] = l>>8;
- bp[2] = l>>16;
- bp[3] = l>>24;
- bp += 4;
- break;
- }
- return bp;
-}
-
-int32
-align(int32 i, Type *t, int op, int32 *maxalign)
-{
- int32 o;
- Type *v;
- int w;
-
- o = i;
- w = 1;
- switch(op) {
- default:
- diag(Z, "unknown align opcode %d", op);
- break;
-
- case Asu2: /* padding at end of a struct */
- w = *maxalign;
- if(w < 1)
- w = 1;
- if(packflg)
- w = 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)
- w = 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;
- }
- 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 a32387bc1..000000000
--- a/src/cmd/5c/txt.c
+++ /dev/null
@@ -1,1298 +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"
-
-void
-ginit(void)
-{
- Type *t;
-
- thechar = '5';
- thestring = "arm";
- exregoffset = REGEXT;
- exfregoffset = FREGEXT;
- listinit();
- nstring = 0;
- mnstring = 0;
- nrathole = 0;
- pc = 0;
- breakpc = -1;
- continpc = -1;
- cases = C;
- firstp = P;
- lastp = P;
- tfield = types[TLONG];
-
- 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)
-{
-
- p = alloc(sizeof(*p));
- *p = zprog;
- p->lineno = nearln;
- pc++;
- if(firstp == P) {
- firstp = p;
- lastp = p;
- return;
- }
- lastp->link = p;
- lastp = p;
-}
-
-void
-gargs(Node *n, Node *tn1, Node *tn2)
-{
- 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)
-{
- int r;
-
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET+NREG;
- nodreg(n, nn, r);
- reg[r]++;
-}
-
-int
-tmpreg(void)
-{
- int i;
-
- for(i=REGRET+1; i<NREG; i++)
- if(reg[i] == 0)
- return i;
- diag(Z, "out of fixed registers");
- return 0;
-}
-
-void
-regalloc(Node *n, Node *tn, Node *o)
-{
- int i;
-
- 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 >= sizeof(reg))
- goto err;
- if(reg[i] <= 0)
- goto err;
- reg[i]--;
- return;
-err:
- diag(n, "error in regfree: %d", i);
-}
-
-void
-regsalloc(Node *n, Node *nn)
-{
- cursafe = align(cursafe, nn->type, Aaut3, 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)
-{
- Adr 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, Adr *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 = S;
- a->reg = n->reg;
- if(a->reg >= NREG) {
- a->type = D_FREG;
- a->reg -= NREG;
- }
- break;
-
- case OIND:
- naddr(n->left, a);
- if(a->type == D_REG) {
- a->type = D_OREG;
- break;
- }
- if(a->type == D_CONST) {
- a->type = D_OREG;
- break;
- }
- goto bad;
-
- case OINDREG:
- a->type = D_OREG;
- a->sym = S;
- a->offset = n->xoffset;
- a->reg = n->reg;
- break;
-
- case ONAME:
- a->etype = n->etype;
- a->type = D_OREG;
- a->name = D_STATIC;
- a->sym = n->sym;
- a->offset = n->xoffset;
- if(n->class == CSTATIC)
- break;
- if(n->class == CEXTERN || n->class == CGLOBL) {
- a->name = D_EXTERN;
- break;
- }
- if(n->class == CAUTO) {
- a->name = D_AUTO;
- break;
- }
- if(n->class == CPARAM) {
- a->name = D_PARAM;
- break;
- }
- goto bad;
-
- case OCONST:
- a->sym = S;
- a->reg = NREG;
- if(typefd[n->type->etype]) {
- a->type = D_FCONST;
- a->dval = n->fconst;
- } else {
- a->type = D_CONST;
- a->offset = n->vconst;
- }
- break;
-
- case OADDR:
- naddr(n->left, a);
- if(a->type == D_OREG) {
- a->type = D_CONST;
- break;
- }
- goto bad;
-
- case OADD:
- if(n->left->op == OCONST) {
- naddr(n->left, a);
- v = a->offset;
- naddr(n->right, a);
- } else {
- naddr(n->right, a);
- v = a->offset;
- naddr(n->left, a);
- }
- a->offset += v;
- break;
-
- }
-}
-
-void
-fop(int as, int f1, int f2, Node *t)
-{
- Node nod1, nod2, nod3;
-
- nodreg(&nod1, t, NREG+f1);
- nodreg(&nod2, t, NREG+f2);
- regalloc(&nod3, t, t);
- gopcode(as, &nod1, &nod2, &nod3);
- gmove(&nod3, t);
- regfree(&nod3);
-}
-
-void
-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 = AMOVB;
- break;
- case TUCHAR:
- a = AMOVBU;
- break;
- case TSHORT:
- a = AMOVH;
- 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 = AMOVB;
- break;
- case TUSHORT:
- a = AMOVHU;
- break;
- case TSHORT:
- a = AMOVH;
- 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(AMOVH, f, &nod);
- gins(AMOVWD, &nod, t);
- regfree(&nod);
- return;
- case TFLOAT:
- regalloc(&nod, f, Z);
- gins(AMOVH, f, &nod);
- gins(AMOVWF, &nod, t);
- regfree(&nod);
- return;
- case TUINT:
- case TINT:
- case TULONG:
- case TLONG:
- case TIND:
- a = AMOVH;
- 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(AMOVB, f, &nod);
- gins(AMOVWD, &nod, t);
- regfree(&nod);
- return;
- case TFLOAT:
- regalloc(&nod, f, Z);
- gins(AMOVB, f, &nod);
- gins(AMOVWF, &nod, t);
- regfree(&nod);
- return;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- case TSHORT:
- case TUSHORT:
- a = AMOVB;
- 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 = AMOVH;
- break;
- case TUSHORT:
- a = AMOVHU;
- break;
- case TCHAR:
- a = AMOVB;
- 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;
- Adr 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 = s;
- p->from.name = D_EXTERN;
- if(a == ATEXT) {
- p->reg = textflag;
- textflag = 0;
- }
- if(s->class == CSTATIC)
- p->from.name = D_STATIC;
- naddr(n, &p->to);
- if(a == ADATA || a == AGLOBL)
- pc--;
-}
-
-int
-sconst(Node *n)
-{
- vlong vv;
-
- if(n->op == OCONST) {
- if(!typefd[n->type->etype]) {
- vv = n->vconst;
- if(vv >= (vlong)(-32766) && vv < (vlong)32766)
- return 1;
- /*
- * 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/Makefile b/src/cmd/5g/Makefile
deleted file mode 100644
index b47014a4e..000000000
--- a/src/cmd/5g/Makefile
+++ /dev/null
@@ -1,36 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=5g
-
-HFILES=\
- ../gc/go.h\
- ../5l/5.out.h\
- gg.h\
- opt.h\
-
-OFILES=\
- ../5l/enam.$O\
- cgen.$O\
- cgen64.$O\
- cplx.$O\
- galign.$O\
- ggen.$O\
- gobj.$O\
- gsubr.$O\
- list.$O\
- peep.$O\
- pgen.$O\
- reg.$O\
-
-LIB=\
- ../gc/gc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../gc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
deleted file mode 100644
index 76e2707fa..000000000
--- a/src/cmd/5g/cgen.c
+++ /dev/null
@@ -1,1329 +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 "gg.h"
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- */
-void
-cgen(Node *n, Node *res)
-{
- Node *nl, *nr, *r;
- Node n1, n2, n3, f0, f1;
- int a, w;
- Prog *p1, *p2, *p3;
- Addr addr;
-
- 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;
-
- 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;
- }
-
-
- // 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 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;
- }
-
- // if both are addressable, move
- if(n->addable && res->addable) {
- if(is64(n->type) || is64(res->type) ||
- n->op == OREGISTER || res->op == OREGISTER ||
- iscomplex[n->type->etype] || iscomplex[res->type->etype]) {
- gmove(n, res);
- } else {
- regalloc(&n1, n->type, N);
- gmove(n, &n1);
- cgen(&n1, res);
- regfree(&n1);
- }
- goto ret;
- }
-
- // if both are not addressable, use a temporary.
- if(!n->addable && !res->addable) {
- // could use regalloc here sometimes,
- // but have to check for ullman >= UINF.
- tempname(&n1, n->type);
- cgen(n, &n1);
- cgen(&n1, res);
- return;
- }
-
- // if result is not addressable directly but n is,
- // compute its address and then store via the address.
- if(!res->addable) {
- igen(res, &n1, N);
- cgen(n, &n1);
- regfree(&n1);
- return;
- }
-
- if(complexop(n, res)) {
- complexgen(n, res);
- return;
- }
-
- // if n is sudoaddable generate addr and move
- if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) {
- a = optoas(OAS, n->type);
- if(sudoaddable(a, n, &addr, &w)) {
- if (res->op != OREGISTER) {
- regalloc(&n2, res->type, N);
- p1 = gins(a, N, &n2);
- p1->from = addr;
- if(debug['g'])
- print("%P [ignore previous line]\n", p1);
- gmove(&n2, res);
- regfree(&n2);
- } else {
- p1 = gins(a, N, res);
- p1->from = addr;
- if(debug['g'])
- print("%P [ignore previous line]\n", p1);
- }
- sudoclean();
- goto ret;
- }
- }
-
- // otherwise, the result is addressable but n is not.
- // let's do some computation.
-
- 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;
- }
-
- // 64-bit ops are hard on 32-bit machine.
- if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
- switch(n->op) {
- // math goes to cgen64.
- case OMINUS:
- case OCOM:
- case OADD:
- case OSUB:
- case OMUL:
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- cgen64(n, res);
- return;
- }
- }
-
- if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
- goto flt;
- switch(n->op) {
- default:
- dump("cgen", n);
- fatal("cgen: unknown op %N", n);
- break;
-
- case OREAL:
- case OIMAG:
- case OCOMPLEX:
- fatal("unexpected complex");
- 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(AB, T);
- p2 = pc;
- gmove(nodbool(1), res);
- p3 = gbranch(AB, T);
- patch(p1, pc);
- bgen(n, 1, 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:
- nodconst(&n3, nl->type, 0);
- regalloc(&n2, nl->type, res);
- regalloc(&n1, nl->type, N);
- gmove(&n3, &n2);
- cgen(nl, &n1);
- gins(optoas(OSUB, nl->type), &n1, &n2);
- gmove(&n2, res);
- regfree(&n1);
- regfree(&n2);
- goto ret;
-
- // 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 OLSH:
- case ORSH:
- cgen_shift(n->op, nl, nr, res);
- break;
-
- case OCONV:
- if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
- cgen(nl, res);
- break;
- }
- if(nl->addable && !is64(nl->type)) {
- regalloc(&n1, nl->type, res);
- gmove(nl, &n1);
- } else {
- if(n->type->width > widthptr || is64(nl->type) || isfloat[nl->type->etype])
- tempname(&n1, nl->type);
- else
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- }
- if(n->type->width > widthptr || is64(n->type) || isfloat[n->type->etype])
- tempname(&n2, n->type);
- else
- regalloc(&n2, n->type, N);
- gmove(&n1, &n2);
- gmove(&n2, res);
- if(n1.op == OREGISTER)
- regfree(&n1);
- if(n2.op == OREGISTER)
- regfree(&n2);
- 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 OLEN:
- if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
- // map has len in the first 32-bit word.
- // a zero pointer means zero length
- regalloc(&n1, types[tptr], res);
- cgen(nl, &n1);
-
- nodconst(&n2, types[tptr], 0);
- regalloc(&n3, n2.type, N);
- gmove(&n2, &n3);
- gcmp(optoas(OCMP, types[tptr]), &n1, &n3);
- regfree(&n3);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.type = types[TINT32];
- 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.
- igen(nl, &n1, res);
- n1.op = OREGISTER; // was OINDREG
- regalloc(&n2, types[TUINT32], &n1);
- n1.op = OINDREG;
- n1.type = types[TUINT32];
- n1.xoffset = Array_nel;
- gmove(&n1, &n2);
- gmove(&n2, res);
- regfree(&n1);
- regfree(&n2);
- break;
- }
- fatal("cgen: OLEN: unknown type %lT", nl->type);
- break;
-
- case OCAP:
- if(istype(nl->type, TCHAN)) {
- // chan has cap in the second 32-bit word.
- // a zero pointer means zero length
- regalloc(&n1, types[tptr], res);
- cgen(nl, &n1);
-
- nodconst(&n2, types[tptr], 0);
- regalloc(&n3, n2.type, N);
- gmove(&n2, &n3);
- gcmp(optoas(OCMP, types[tptr]), &n1, &n3);
- regfree(&n3);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 4;
- n2.type = types[TINT32];
- gmove(&n2, &n1);
-
- patch(p1, pc);
-
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- if(isslice(nl->type)) {
- regalloc(&n1, types[tptr], res);
- agen(nl, &n1);
- n1.op = OINDREG;
- n1.type = types[TUINT32];
- n1.xoffset = Array_cap;
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- fatal("cgen: OCAP: unknown type %lT", nl->type);
- break;
-
- case OADDR:
- agen(nl, res);
- 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:
- a = optoas(n->op, nl->type);
- goto abop;
- }
- goto ret;
-
-sbop: // symmetric binary
- if(nl->ullman < nr->ullman) {
- r = nl;
- nl = nr;
- nr = r;
- }
-
-abop: // asymmetric binary
- // TODO(kaib): use fewer registers here.
- if(nl->ullman >= nr->ullman) {
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- } else {
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- }
- gins(a, &n2, &n1);
- gmove(&n1, res);
- regfree(&n1);
- regfree(&n2);
- goto ret;
-
-flt: // floating-point.
- regalloc(&f0, nl->type, res);
- if(nr != N)
- goto flt2;
-
- if(n->op == OMINUS) {
- nr = nodintconst(-1);
- convlit(&nr, n->type);
- n->op = OMUL;
- goto flt2;
- }
-
- // unary
- cgen(nl, &f0);
- if(n->op != OCONV && n->op != OPLUS)
- gins(optoas(n->op, n->type), &f0, &f0);
- gmove(&f0, res);
- regfree(&f0);
- goto ret;
-
-flt2: // binary
- if(nl->ullman >= nr->ullman) {
- cgen(nl, &f0);
- regalloc(&f1, n->type, N);
- gmove(&f0, &f1);
- cgen(nr, &f0);
- gins(optoas(n->op, n->type), &f0, &f1);
- } else {
- cgen(nr, &f0);
- regalloc(&f1, n->type, N);
- cgen(nl, &f1);
- gins(optoas(n->op, n->type), &f0, &f1);
- }
- gmove(&f1, res);
- regfree(&f0);
- regfree(&f1);
- goto ret;
-
-ret:
- ;
-}
-
-/*
- * generate array index into res.
- * n might be any size; res is 32-bit.
- * returns Prog* to patch to panic call.
- */
-Prog*
-cgenindex(Node *n, Node *res)
-{
- Node tmp, lo, hi, zero, n1, n2;
-
- if(!is64(n->type)) {
- cgen(n, res);
- return nil;
- }
-
- tempname(&tmp, types[TINT64]);
- cgen(n, &tmp);
- split64(&tmp, &lo, &hi);
- gmove(&lo, res);
- if(debug['B']) {
- splitclean();
- return nil;
- }
- regalloc(&n1, types[TINT32], N);
- regalloc(&n2, types[TINT32], N);
- nodconst(&zero, types[TINT32], 0);
- gmove(&hi, &n1);
- gmove(&zero, &n2);
- gcmp(ACMP, &n1, &n2);
- regfree(&n2);
- regfree(&n1);
- splitclean();
- return gbranch(ABNE, T);
-}
-
-/*
- * generate:
- * res = &n;
- */
-void
-agen(Node *n, Node *res)
-{
- Node *nl, *nr;
- Node n1, n2, n3, n4, n5, tmp;
- Prog *p1, *p2;
- uint32 w;
- uint64 v;
- int r;
-
- if(debug['g']) {
- dump("\nagen-res", res);
- dump("agen-r", n);
- }
- if(n == N || n->type == T || res == N || res->type == T)
- fatal("agen");
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- if(n->addable) {
- memset(&n1, 0, sizeof n1);
- n1.op = OADDR;
- n1.left = n;
- regalloc(&n2, types[tptr], res);
- gins(AMOVW, &n1, &n2);
- gmove(&n2, res);
- regfree(&n2);
- goto ret;
- }
-
- nl = n->left;
- nr = n->right;
-
- switch(n->op) {
- default:
- fatal("agen: unknown op %N", n);
- break;
-
- case OCALLMETH:
- case OCALLFUNC:
- // Release res so that it is available for cgen_call.
- // Pick it up again after the call.
- r = -1;
- if(n->ullman >= UINF) {
- if(res->op == OREGISTER || res->op == OINDREG) {
- r = res->val.u.reg;
- reg[r]--;
- }
- }
- if(n->op == OCALLMETH)
- cgen_callmeth(n, 0);
- else
- cgen_call(n, 0);
- if(r >= 0)
- reg[r]++;
- cgen_aret(n, res);
- break;
-
- case OCALLINTER:
- cgen_callinter(n, res, 0);
- cgen_aret(n, res);
- break;
-
- case OINDEX:
- p2 = nil; // to be patched to panicindex.
- w = n->type->width;
- if(nr->addable) {
- if(!isconst(nr, CTINT))
- tempname(&tmp, types[TINT32]);
- if(!isconst(nl, CTSTR))
- agenr(nl, &n3, res);
- if(!isconst(nr, CTINT)) {
- p2 = cgenindex(nr, &tmp);
- regalloc(&n1, tmp.type, N);
- gmove(&tmp, &n1);
- }
- } else
- if(nl->addable) {
- if(!isconst(nr, CTINT)) {
- tempname(&tmp, types[TINT32]);
- p2 = cgenindex(nr, &tmp);
- regalloc(&n1, tmp.type, N);
- gmove(&tmp, &n1);
- }
- if(!isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
- }
- } else {
- tempname(&tmp, types[TINT32]);
- p2 = cgenindex(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
-
- if(w == 0)
- fatal("index is zero 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->etype) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- regalloc(&n4, n1.type, N);
- cgen(&n1, &n4);
- nodconst(&n2, types[TUINT32], v);
- regalloc(&n5, n2.type, N);
- gmove(&n2, &n5);
- gcmp(optoas(OCMP, types[TUINT32]), &n4, &n5);
- regfree(&n4);
- regfree(&n5);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, &n3);
- }
-
- nodconst(&n2, types[tptr], v*w);
- regalloc(&n4, n2.type, N);
- gmove(&n2, &n4);
- gins(optoas(OADD, types[tptr]), &n4, &n3);
- regfree(&n4);
-
- gmove(&n3, res);
- regfree(&n3);
- break;
- }
-
- regalloc(&n2, types[TINT32], &n1); // i
- gmove(&n1, &n2);
- regfree(&n1);
-
- if(!debug['B'] && !n->etype) {
- // check bounds
- regalloc(&n4, types[TUINT32], N);
- if(isconst(nl, CTSTR)) {
- nodconst(&n1, types[TUINT32], nl->val.u.sval->len);
- gmove(&n1, &n4);
- } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- cgen(&n1, &n4);
- } else {
- nodconst(&n1, types[TUINT32], nl->type->bound);
- gmove(&n1, &n4);
- }
- gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
- regfree(&n4);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
- if(p2)
- patch(p2, pc);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- if(isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- p1 = gins(AMOVW, N, &n3);
- datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- p1->from.type = D_CONST;
- } 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 == 1 || w == 2 || w == 4 || w == 8) {
- memset(&n4, 0, sizeof n4);
- n4.op = OADDR;
- n4.left = &n2;
- cgen(&n4, &n3);
- if (w == 1)
- gins(AADD, &n2, &n3);
- else if(w == 2)
- gshift(AADD, &n2, SHIFT_LL, 1, &n3);
- else if(w == 4)
- gshift(AADD, &n2, SHIFT_LL, 2, &n3);
- else if(w == 8)
- gshift(AADD, &n2, SHIFT_LL, 3, &n3);
- } else {
- regalloc(&n4, types[TUINT32], N);
- nodconst(&n1, types[TUINT32], w);
- gmove(&n1, &n4);
- gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- regfree(&n4);
- gmove(&n3, res);
- }
-
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- 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) {
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[TINT32], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
-
- case OIND:
- cgen(nl, res);
- break;
-
- case ODOT:
- agen(nl, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[TINT32], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
-
- case ODOTPTR:
- cgen(nl, res);
- if(n->xoffset != 0) {
- // explicit check for nil if struct is large enough
- // that we might derive too big a pointer.
- if(nl->type->type->width >= unmappedzero) {
- regalloc(&n1, types[tptr], N);
- gmove(res, &n1);
- p1 = gins(AMOVW, &n1, &n1);
- p1->from.type = D_OREG;
- p1->from.offset = 0;
- regfree(&n1);
- }
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[tptr], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
- }
-
-ret:
- ;
-}
-
-/*
- * generate:
- * newreg = &n;
- * res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- */
-void
-igen(Node *n, Node *a, Node *res)
-{
- regalloc(a, types[tptr], res);
- agen(n, a);
- a->op = OINDREG;
- a->type = n->type;
-}
-
-/*
- * generate:
- * newreg = &n;
- *
- * caller must regfree(a).
- */
-void
-agenr(Node *n, Node *a, Node *res)
-{
- regalloc(a, types[tptr], res);
- agen(n, a);
-}
-
-void
-gencmp0(Node *n, Type *t, int o, Prog *to)
-{
- Node n1, n2, n3;
- int a;
-
- regalloc(&n1, t, N);
- cgen(n, &n1);
- a = optoas(OCMP, t);
- if(a != ACMP) {
- nodconst(&n2, t, 0);
- regalloc(&n3, t, N);
- gmove(&n2, &n3);
- gcmp(a, &n1, &n3);
- regfree(&n3);
- } else
- gins(ATST, &n1, N);
- a = optoas(o, t);
- patch(gbranch(a, t), to);
- regfree(&n1);
-}
-
-/*
- * generate:
- * if(n == true) goto to;
- */
-void
-bgen(Node *n, int true, Prog *to)
-{
- int et, a;
- Node *nl, *nr, *r;
- Node n1, n2, n3, n4, tmp;
- Prog *p1, *p2;
-
- if(debug['g']) {
- dump("\nbgen", n);
- }
-
- if(n == N)
- n = nodbool(1);
-
- if(n->ninit != nil)
- genlist(n->ninit);
-
- nl = n->left;
- nr = n->right;
-
- 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;
- }
- nl = N;
- nr = N;
-
- switch(n->op) {
- default:
- a = ONE;
- if(!true)
- a = OEQ;
- gencmp0(n, n->type, a, to);
- goto ret;
-
- case OLITERAL:
- // need to ask if it is bool?
- if(!true == !n->val.u.bval)
- patch(gbranch(AB, T), to);
- goto ret;
-
- case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- p1 = gbranch(AB, T);
- p2 = gbranch(AB, T);
- patch(p1, pc);
- bgen(n->left, !true, p2);
- bgen(n->right, !true, p2);
- p1 = gbranch(AB, T);
- patch(p1, to);
- patch(p2, pc);
- goto ret;
-
- case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bgen(n->left, true, to);
- bgen(n->right, true, 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;
- }
-
- switch(n->op) {
-
- case ONOT:
- bgen(nl, !true, to);
- goto ret;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- a = n->op;
- if(!true) {
- if(isfloat[nl->type->etype]) {
- // brcom is not valid on floats when NaN is involved.
- p1 = gbranch(AB, T);
- p2 = gbranch(AB, T);
- patch(p1, pc);
- bgen(n, 1, p2);
- patch(gbranch(AB, T), to);
- patch(p2, pc);
- goto ret;
- }
- a = brcom(a);
- true = !true;
- }
-
- // make simplest on right
- if(nl->op == OLITERAL || (nl->ullman < UINF && nl->ullman < nr->ullman)) {
- a = brrev(a);
- r = nl;
- nl = nr;
- nr = r;
- }
-
- if(isslice(nl->type)) {
- // only valid to cmp darray to literal nil
- if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
- yyerror("illegal array comparison");
- break;
- }
-
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = Array_array;
- gencmp0(&n2, types[tptr], a, to);
- regfree(&n1);
- break;
-
- a = optoas(a, types[tptr]);
- regalloc(&n1, types[tptr], N);
- regalloc(&n3, types[tptr], N);
- regalloc(&n4, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = Array_array;
- gmove(&n2, &n4);
- nodconst(&tmp, types[tptr], 0);
- gmove(&tmp, &n3);
- gcmp(optoas(OCMP, types[tptr]), &n4, &n3);
- patch(gbranch(a, types[tptr]), to);
- regfree(&n4);
- regfree(&n3);
- regfree(&n1);
- break;
- }
-
- if(isinter(nl->type)) {
- // front end shold only leave cmp to literal nil
- if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
- yyerror("illegal interface comparison");
- break;
- }
-
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 0;
- gencmp0(&n2, types[tptr], a, to);
- regfree(&n1);
- break;
-
- a = optoas(a, types[tptr]);
- regalloc(&n1, types[tptr], N);
- regalloc(&n3, types[tptr], N);
- regalloc(&n4, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 0;
- gmove(&n2, &n4);
- nodconst(&tmp, types[tptr], 0);
- gmove(&tmp, &n3);
- gcmp(optoas(OCMP, types[tptr]), &n4, &n3);
- patch(gbranch(a, types[tptr]), to);
- regfree(&n1);
- regfree(&n3);
- regfree(&n4);
- break;
- }
-
- if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, to);
- break;
- }
-
- if(is64(nr->type)) {
- if(!nl->addable) {
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- nl = &n1;
- }
- if(!nr->addable) {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- cmp64(nl, nr, a, to);
- break;
- }
-
- if(nr->op == OLITERAL) {
- if(nr->val.ctype == CTINT && mpgetfix(nr->val.u.xval) == 0) {
- gencmp0(nl, nl->type, a, to);
- break;
- }
- if(nr->val.ctype == CTNIL) {
- gencmp0(nl, nl->type, a, to);
- break;
- }
- }
-
- a = optoas(a, nr->type);
-
- 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);
-
- gcmp(optoas(OCMP, nr->type), &n1, &n2);
- patch(gbranch(a, nr->type), to);
-
- regfree(&n1);
- regfree(&n2);
- break;
- }
-
- tempname(&n3, nl->type);
- cgen(nl, &n3);
-
- tempname(&tmp, nr->type);
- cgen(nr, &tmp);
-
- regalloc(&n1, nl->type, N);
- gmove(&n3, &n1);
-
- regalloc(&n2, nr->type, N);
- gmove(&tmp, &n2);
-
- gcmp(optoas(OCMP, nr->type), &n1, &n2);
- if(isfloat[nl->type->etype]) {
- p1 = gbranch(ABVS, nr->type);
- patch(gbranch(a, nr->type), to);
- if(n->op == ONE)
- patch(p1, to);
- else
- patch(p1, pc);
- } else {
- patch(gbranch(a, nr->type), 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.
- */
-int32
-stkof(Node *n)
-{
- Type *t;
- Iter flist;
- int32 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 + 4; // correct for LR
- break;
- }
-
- // botch - probably failing to recognize address
- // arithmetic on the above. eg INDEX and DOT
- return -1000;
-}
-
-/*
- * block copy:
- * memmove(&res, &n, w);
- * NB: character copy assumed little endian architecture
- */
-void
-sgen(Node *n, Node *res, int32 w)
-{
- Node dst, src, tmp, nend;
- int32 c, odst, osrc;
- int dir, align, op;
- Prog *p, *ploop;
-
- if(debug['g']) {
- print("\nsgen w=%d\n", w);
- dump("r", n);
- dump("res", res);
- }
- if(w == 0)
- return;
- if(w < 0)
- fatal("sgen copy %d", w);
- if(n->ullman >= UINF && res->ullman >= UINF)
- fatal("sgen UINF");
- if(n->type == T)
- fatal("sgen: missing type");
-
- // 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;
- op = 0;
- switch(align) {
- default:
- fatal("sgen: invalid alignment %d for %T", align, n->type);
- case 1:
- op = AMOVB;
- break;
- case 2:
- op = AMOVH;
- break;
- case 4:
- op = AMOVW;
- break;
- }
- if(w%align)
- fatal("sgen: unaligned size %d (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;
-
- regalloc(&dst, types[tptr], res);
- if(n->ullman >= res->ullman) {
- agen(n, &dst); // temporarily use dst
- regalloc(&src, types[tptr], N);
- gins(AMOVW, &dst, &src);
- agen(res, &dst);
- } else {
- agen(res, &dst);
- regalloc(&src, types[tptr], N);
- agen(n, &src);
- }
-
- regalloc(&tmp, types[TUINT32], N);
-
- // set up end marker
- memset(&nend, 0, sizeof nend);
- if(c >= 4) {
- regalloc(&nend, types[TUINT32], N);
-
- p = gins(AMOVW, &src, &nend);
- p->from.type = D_CONST;
- if(dir < 0)
- p->from.offset = dir;
- else
- p->from.offset = w;
- }
-
- // move src and dest to the end of block if necessary
- if(dir < 0) {
- p = gins(AMOVW, &src, &src);
- p->from.type = D_CONST;
- p->from.offset = w + dir;
-
- p = gins(AMOVW, &dst, &dst);
- p->from.type = D_CONST;
- p->from.offset = w + dir;
- }
-
- // move
- if(c >= 4) {
- p = gins(op, &src, &tmp);
- p->from.type = D_OREG;
- p->from.offset = dir;
- p->scond |= C_PBIT;
- ploop = p;
-
- p = gins(op, &tmp, &dst);
- p->to.type = D_OREG;
- p->to.offset = dir;
- p->scond |= C_PBIT;
-
- p = gins(ACMP, &src, N);
- raddr(&nend, p);
-
- patch(gbranch(ABNE, T), ploop);
- regfree(&nend);
- } else {
- while(c-- > 0) {
- p = gins(op, &src, &tmp);
- p->from.type = D_OREG;
- p->from.offset = dir;
- p->scond |= C_PBIT;
- ploop = p;
-
- p = gins(op, &tmp, &dst);
- p->to.type = D_OREG;
- p->to.offset = dir;
- p->scond |= C_PBIT;
- }
- }
-
- regfree(&dst);
- regfree(&src);
- regfree(&tmp);
-}
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
deleted file mode 100644
index 4da8db2ae..000000000
--- a/src/cmd/5g/cgen64.c
+++ /dev/null
@@ -1,716 +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 "gg.h"
-
-/*
- * attempt to generate 64-bit
- * res = n
- * return 1 on success, 0 if op not handled.
- */
-void
-cgen64(Node *n, Node *res)
-{
- Node t1, t2, *l, *r;
- Node lo1, lo2, hi1, hi2;
- Node al, ah, bl, bh, cl, ch, s, n1, creg;
- Prog *p1, *p2, *p3, *p4, *p5, *p6;
-
- uint64 v;
-
- if(res->op != OINDREG && res->op != ONAME) {
- dump("n", n);
- dump("res", res);
- fatal("cgen64 %O of %O", n->op, res->op);
- }
-
- l = n->left;
- if(!l->addable) {
- tempname(&t1, l->type);
- cgen(l, &t1);
- l = &t1;
- }
-
- split64(l, &lo1, &hi1);
- switch(n->op) {
- default:
- fatal("cgen64 %O", n->op);
-
- case OMINUS:
- split64(res, &lo2, &hi2);
-
- regalloc(&t1, lo1.type, N);
- regalloc(&al, lo1.type, N);
- regalloc(&ah, hi1.type, N);
-
- gins(AMOVW, &lo1, &al);
- gins(AMOVW, &hi1, &ah);
-
- gmove(ncon(0), &t1);
- p1 = gins(ASUB, &al, &t1);
- p1->scond |= C_SBIT;
- gins(AMOVW, &t1, &lo2);
-
- gmove(ncon(0), &t1);
- gins(ASBC, &ah, &t1);
- gins(AMOVW, &t1, &hi2);
-
- regfree(&t1);
- regfree(&al);
- regfree(&ah);
- splitclean();
- splitclean();
- return;
-
- case OCOM:
- regalloc(&t1, lo1.type, N);
- gmove(ncon(-1), &t1);
-
- split64(res, &lo2, &hi2);
- regalloc(&n1, lo1.type, N);
-
- gins(AMOVW, &lo1, &n1);
- gins(AEOR, &t1, &n1);
- gins(AMOVW, &n1, &lo2);
-
- gins(AMOVW, &hi1, &n1);
- gins(AEOR, &t1, &n1);
- gins(AMOVW, &n1, &hi2);
-
- regfree(&t1);
- regfree(&n1);
- splitclean();
- splitclean();
- return;
-
- case OADD:
- case OSUB:
- case OMUL:
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- // binary operators.
- // common setup below.
- break;
- }
-
- // setup for binary operators
- r = n->right;
- if(r != N && !r->addable) {
- tempname(&t2, r->type);
- cgen(r, &t2);
- r = &t2;
- }
- if(is64(r->type))
- split64(r, &lo2, &hi2);
-
- regalloc(&al, lo1.type, N);
- regalloc(&ah, hi1.type, N);
-
- // Do op. Leave result in ah:al.
- switch(n->op) {
- default:
- fatal("cgen64: not implemented: %N\n", n);
-
- case OADD:
- // TODO: Constants
- regalloc(&bl, types[TPTR32], N);
- regalloc(&bh, types[TPTR32], N);
- gins(AMOVW, &hi1, &ah);
- gins(AMOVW, &lo1, &al);
- gins(AMOVW, &hi2, &bh);
- gins(AMOVW, &lo2, &bl);
- p1 = gins(AADD, &bl, &al);
- p1->scond |= C_SBIT;
- gins(AADC, &bh, &ah);
- regfree(&bl);
- regfree(&bh);
- break;
-
- case OSUB:
- // TODO: Constants.
- regalloc(&bl, types[TPTR32], N);
- regalloc(&bh, types[TPTR32], N);
- gins(AMOVW, &lo1, &al);
- gins(AMOVW, &hi1, &ah);
- gins(AMOVW, &lo2, &bl);
- gins(AMOVW, &hi2, &bh);
- p1 = gins(ASUB, &bl, &al);
- p1->scond |= C_SBIT;
- gins(ASBC, &bh, &ah);
- regfree(&bl);
- regfree(&bh);
- break;
-
- case OMUL:
- // TODO(kaib): this can be done with 4 regs and does not need 6
- regalloc(&bl, types[TPTR32], N);
- regalloc(&bh, types[TPTR32], N);
- regalloc(&cl, types[TPTR32], N);
- regalloc(&ch, types[TPTR32], N);
-
- // load args into bh:bl and bh:bl.
- gins(AMOVW, &hi1, &bh);
- gins(AMOVW, &lo1, &bl);
- gins(AMOVW, &hi2, &ch);
- gins(AMOVW, &lo2, &cl);
-
- // bl * cl
- p1 = gins(AMULLU, N, N);
- p1->from.type = D_REG;
- p1->from.reg = bl.val.u.reg;
- p1->reg = cl.val.u.reg;
- p1->to.type = D_REGREG;
- p1->to.reg = ah.val.u.reg;
- p1->to.offset = al.val.u.reg;
-//print("%P\n", p1);
-
- // bl * ch
- p1 = gins(AMULA, N, N);
- p1->from.type = D_REG;
- p1->from.reg = bl.val.u.reg;
- p1->reg = ch.val.u.reg;
- p1->to.type = D_REGREG;
- p1->to.reg = ah.val.u.reg;
- p1->to.offset = ah.val.u.reg;
-//print("%P\n", p1);
-
- // bh * cl
- p1 = gins(AMULA, N, N);
- p1->from.type = D_REG;
- p1->from.reg = bh.val.u.reg;
- p1->reg = cl.val.u.reg;
- p1->to.type = D_REGREG;
- p1->to.reg = ah.val.u.reg;
- p1->to.offset = ah.val.u.reg;
-//print("%P\n", p1);
-
- regfree(&bh);
- regfree(&bl);
- regfree(&ch);
- regfree(&cl);
-
- break;
-
- case OLSH:
- regalloc(&bl, lo1.type, N);
- regalloc(&bh, hi1.type, N);
- gins(AMOVW, &hi1, &bh);
- gins(AMOVW, &lo1, &bl);
-
- if(r->op == OLITERAL) {
- v = mpgetfix(r->val.u.xval);
- if(v >= 64) {
- // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
- // here and below (verify it optimizes to EOR)
- gins(AEOR, &al, &al);
- gins(AEOR, &ah, &ah);
- } else
- if(v > 32) {
- gins(AEOR, &al, &al);
- // MOVW bl<<(v-32), ah
- gshift(AMOVW, &bl, SHIFT_LL, (v-32), &ah);
- } else
- if(v == 32) {
- gins(AEOR, &al, &al);
- gins(AMOVW, &bl, &ah);
- } else
- if(v > 0) {
- // MOVW bl<<v, al
- gshift(AMOVW, &bl, SHIFT_LL, v, &al);
-
- // MOVW bh<<v, ah
- gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
-
- // OR bl>>(32-v), ah
- gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
- } else {
- gins(AMOVW, &bl, &al);
- gins(AMOVW, &bh, &ah);
- }
- goto olsh_break;
- }
-
- regalloc(&s, types[TUINT32], N);
- regalloc(&creg, types[TUINT32], N);
- if (is64(r->type)) {
- // shift is >= 1<<32
- split64(r, &cl, &ch);
- gmove(&ch, &s);
- p1 = gins(ATST, &s, N);
- p6 = gbranch(ABNE, T);
- gmove(&cl, &s);
- splitclean();
- } else {
- gmove(r, &s);
- p6 = P;
- }
- p1 = gins(ATST, &s, N);
-
- // shift == 0
- p1 = gins(AMOVW, &bl, &al);
- p1->scond = C_SCOND_EQ;
- p1 = gins(AMOVW, &bh, &ah);
- p1->scond = C_SCOND_EQ;
- p2 = gbranch(ABEQ, T);
-
- // shift is < 32
- nodconst(&n1, types[TUINT32], 32);
- gmove(&n1, &creg);
- gcmp(ACMP, &s, &creg);
-
- // MOVW.LO bl<<s, al
- p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &al);
- p1->scond = C_SCOND_LO;
-
- // MOVW.LO bh<<s, ah
- p1 = gregshift(AMOVW, &bh, SHIFT_LL, &s, &ah);
- p1->scond = C_SCOND_LO;
-
- // SUB.LO s, creg
- p1 = gins(ASUB, &s, &creg);
- p1->scond = C_SCOND_LO;
-
- // OR.LO bl>>creg, ah
- p1 = gregshift(AORR, &bl, SHIFT_LR, &creg, &ah);
- p1->scond = C_SCOND_LO;
-
- // BLO end
- p3 = gbranch(ABLO, T);
-
- // shift == 32
- p1 = gins(AEOR, &al, &al);
- p1->scond = C_SCOND_EQ;
- p1 = gins(AMOVW, &bl, &ah);
- p1->scond = C_SCOND_EQ;
- p4 = gbranch(ABEQ, T);
-
- // shift is < 64
- nodconst(&n1, types[TUINT32], 64);
- gmove(&n1, &creg);
- gcmp(ACMP, &s, &creg);
-
- // EOR.LO al, al
- p1 = gins(AEOR, &al, &al);
- p1->scond = C_SCOND_LO;
-
- // MOVW.LO creg>>1, creg
- p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
- p1->scond = C_SCOND_LO;
-
- // SUB.LO creg, s
- p1 = gins(ASUB, &creg, &s);
- p1->scond = C_SCOND_LO;
-
- // MOVW bl<<s, ah
- p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &ah);
- p1->scond = C_SCOND_LO;
-
- p5 = gbranch(ABLO, T);
-
- // shift >= 64
- if (p6 != P) patch(p6, pc);
- gins(AEOR, &al, &al);
- gins(AEOR, &ah, &ah);
-
- patch(p2, pc);
- patch(p3, pc);
- patch(p4, pc);
- patch(p5, pc);
- regfree(&s);
- regfree(&creg);
-
-olsh_break:
- regfree(&bl);
- regfree(&bh);
- break;
-
-
- case ORSH:
- regalloc(&bl, lo1.type, N);
- regalloc(&bh, hi1.type, N);
- gins(AMOVW, &hi1, &bh);
- gins(AMOVW, &lo1, &bl);
-
- if(r->op == OLITERAL) {
- v = mpgetfix(r->val.u.xval);
- if(v >= 64) {
- if(bh.type->etype == TINT32) {
- // MOVW bh->31, al
- gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
-
- // MOVW bh->31, ah
- gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
- } else {
- gins(AEOR, &al, &al);
- gins(AEOR, &ah, &ah);
- }
- } else
- if(v > 32) {
- if(bh.type->etype == TINT32) {
- // MOVW bh->(v-32), al
- gshift(AMOVW, &bh, SHIFT_AR, v-32, &al);
-
- // MOVW bh->31, ah
- gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
- } else {
- // MOVW bh>>(v-32), al
- gshift(AMOVW, &bh, SHIFT_LR, v-32, &al);
- gins(AEOR, &ah, &ah);
- }
- } else
- if(v == 32) {
- gins(AMOVW, &bh, &al);
- if(bh.type->etype == TINT32) {
- // MOVW bh->31, ah
- gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
- } else {
- gins(AEOR, &ah, &ah);
- }
- } else
- if( v > 0) {
- // MOVW bl>>v, al
- gshift(AMOVW, &bl, SHIFT_LR, v, &al);
-
- // OR bh<<(32-v), al
- gshift(AORR, &bh, SHIFT_LL, 32-v, &al);
-
- if(bh.type->etype == TINT32) {
- // MOVW bh->v, ah
- gshift(AMOVW, &bh, SHIFT_AR, v, &ah);
- } else {
- // MOVW bh>>v, ah
- gshift(AMOVW, &bh, SHIFT_LR, v, &ah);
- }
- } else {
- gins(AMOVW, &bl, &al);
- gins(AMOVW, &bh, &ah);
- }
- goto orsh_break;
- }
-
- regalloc(&s, types[TUINT32], N);
- regalloc(&creg, types[TUINT32], N);
- if(is64(r->type)) {
- // shift is >= 1<<32
- split64(r, &cl, &ch);
- gmove(&ch, &s);
- gins(ATST, &s, N);
- if(bh.type->etype == TINT32)
- p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
- else
- p1 = gins(AEOR, &ah, &ah);
- p1->scond = C_SCOND_NE;
- p6 = gbranch(ABNE, T);
- gmove(&cl, &s);
- splitclean();
- } else {
- gmove(r, &s);
- p6 = P;
- }
- p1 = gins(ATST, &s, N);
-
- // shift == 0
- p1 = gins(AMOVW, &bl, &al);
- p1->scond = C_SCOND_EQ;
- p1 = gins(AMOVW, &bh, &ah);
- p1->scond = C_SCOND_EQ;
- p2 = gbranch(ABEQ, T);
-
- // check if shift is < 32
- nodconst(&n1, types[TUINT32], 32);
- gmove(&n1, &creg);
- gcmp(ACMP, &s, &creg);
-
- // MOVW.LO bl>>s, al
- p1 = gregshift(AMOVW, &bl, SHIFT_LR, &s, &al);
- p1->scond = C_SCOND_LO;
-
- // SUB.LO s,creg
- p1 = gins(ASUB, &s, &creg);
- p1->scond = C_SCOND_LO;
-
- // OR.LO bh<<(32-s), al
- p1 = gregshift(AORR, &bh, SHIFT_LL, &creg, &al);
- p1->scond = C_SCOND_LO;
-
- if(bh.type->etype == TINT32) {
- // MOVW bh->s, ah
- p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &ah);
- } else {
- // MOVW bh>>s, ah
- p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &ah);
- }
- p1->scond = C_SCOND_LO;
-
- // BLO end
- p3 = gbranch(ABLO, T);
-
- // shift == 32
- p1 = gins(AMOVW, &bh, &al);
- p1->scond = C_SCOND_EQ;
- if(bh.type->etype == TINT32)
- p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
- else
- p1 = gins(AEOR, &ah, &ah);
- p4 = gbranch(ABEQ, T);
-
- // check if shift is < 64
- nodconst(&n1, types[TUINT32], 64);
- gmove(&n1, &creg);
- gcmp(ACMP, &s, &creg);
-
- // MOVW.LO creg>>1, creg
- p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
- p1->scond = C_SCOND_LO;
-
- // SUB.LO creg, s
- p1 = gins(ASUB, &creg, &s);
- p1->scond = C_SCOND_LO;
-
- if(bh.type->etype == TINT32) {
- // MOVW bh->(s-32), al
- p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &al);
- p1->scond = C_SCOND_LO;
- } else {
- // MOVW bh>>(v-32), al
- p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &al);
- p1->scond = C_SCOND_LO;
- }
-
- // BLO end
- p5 = gbranch(ABLO, T);
-
- // s >= 64
- if(p6 != P)
- patch(p6, pc);
- if(bh.type->etype == TINT32) {
- // MOVW bh->31, al
- gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
- } else {
- gins(AEOR, &al, &al);
- }
-
- patch(p2, pc);
- patch(p3, pc);
- patch(p4, pc);
- patch(p5, pc);
- regfree(&s);
- regfree(&creg);
-
-
-orsh_break:
- regfree(&bl);
- regfree(&bh);
- break;
-
- case OXOR:
- case OAND:
- case OOR:
- // TODO(kaib): literal optimizations
- // make constant the right side (it usually is anyway).
-// if(lo1.op == OLITERAL) {
-// nswap(&lo1, &lo2);
-// nswap(&hi1, &hi2);
-// }
-// if(lo2.op == OLITERAL) {
-// // special cases for constants.
-// lv = mpgetfix(lo2.val.u.xval);
-// hv = mpgetfix(hi2.val.u.xval);
-// splitclean(); // right side
-// split64(res, &lo2, &hi2);
-// switch(n->op) {
-// case OXOR:
-// gmove(&lo1, &lo2);
-// gmove(&hi1, &hi2);
-// switch(lv) {
-// case 0:
-// break;
-// case 0xffffffffu:
-// gins(ANOTL, N, &lo2);
-// break;
-// default:
-// gins(AXORL, ncon(lv), &lo2);
-// break;
-// }
-// switch(hv) {
-// case 0:
-// break;
-// case 0xffffffffu:
-// gins(ANOTL, N, &hi2);
-// break;
-// default:
-// gins(AXORL, ncon(hv), &hi2);
-// break;
-// }
-// break;
-
-// case OAND:
-// switch(lv) {
-// case 0:
-// gins(AMOVL, ncon(0), &lo2);
-// break;
-// default:
-// gmove(&lo1, &lo2);
-// if(lv != 0xffffffffu)
-// gins(AANDL, ncon(lv), &lo2);
-// break;
-// }
-// switch(hv) {
-// case 0:
-// gins(AMOVL, ncon(0), &hi2);
-// break;
-// default:
-// gmove(&hi1, &hi2);
-// if(hv != 0xffffffffu)
-// gins(AANDL, ncon(hv), &hi2);
-// break;
-// }
-// break;
-
-// case OOR:
-// switch(lv) {
-// case 0:
-// gmove(&lo1, &lo2);
-// break;
-// case 0xffffffffu:
-// gins(AMOVL, ncon(0xffffffffu), &lo2);
-// break;
-// default:
-// gmove(&lo1, &lo2);
-// gins(AORL, ncon(lv), &lo2);
-// break;
-// }
-// switch(hv) {
-// case 0:
-// gmove(&hi1, &hi2);
-// break;
-// case 0xffffffffu:
-// gins(AMOVL, ncon(0xffffffffu), &hi2);
-// break;
-// default:
-// gmove(&hi1, &hi2);
-// gins(AORL, ncon(hv), &hi2);
-// break;
-// }
-// break;
-// }
-// splitclean();
-// splitclean();
-// goto out;
-// }
- regalloc(&n1, lo1.type, N);
- gins(AMOVW, &lo1, &al);
- gins(AMOVW, &hi1, &ah);
- gins(AMOVW, &lo2, &n1);
- gins(optoas(n->op, lo1.type), &n1, &al);
- gins(AMOVW, &hi2, &n1);
- gins(optoas(n->op, lo1.type), &n1, &ah);
- regfree(&n1);
- break;
- }
- if(is64(r->type))
- splitclean();
- splitclean();
-
- split64(res, &lo1, &hi1);
- gins(AMOVW, &al, &lo1);
- gins(AMOVW, &ah, &hi1);
- splitclean();
-
-//out:
- regfree(&al);
- regfree(&ah);
-}
-
-/*
- * generate comparison of nl, nr, both 64-bit.
- * nl is memory; nr is constant or memory.
- */
-void
-cmp64(Node *nl, Node *nr, int op, Prog *to)
-{
- Node lo1, hi1, lo2, hi2, r1, r2;
- Prog *br;
- Type *t;
-
- split64(nl, &lo1, &hi1);
- split64(nr, &lo2, &hi2);
-
- // compare most significant word;
- // if they differ, we're done.
- t = hi1.type;
- regalloc(&r1, types[TINT32], N);
- regalloc(&r2, types[TINT32], N);
- gins(AMOVW, &hi1, &r1);
- gins(AMOVW, &hi2, &r2);
- gcmp(ACMP, &r1, &r2);
- regfree(&r1);
- regfree(&r2);
-
- br = P;
- switch(op) {
- default:
- fatal("cmp64 %O %T", op, t);
- case OEQ:
- // cmp hi
- // bne L
- // cmp lo
- // beq to
- // L:
- br = gbranch(ABNE, T);
- break;
- case ONE:
- // cmp hi
- // bne to
- // cmp lo
- // bne to
- patch(gbranch(ABNE, T), to);
- break;
- case OGE:
- case OGT:
- // cmp hi
- // bgt to
- // blt L
- // cmp lo
- // bge to (or bgt to)
- // L:
- patch(gbranch(optoas(OGT, t), T), to);
- br = gbranch(optoas(OLT, t), T);
- break;
- case OLE:
- case OLT:
- // cmp hi
- // blt to
- // bgt L
- // cmp lo
- // ble to (or jlt to)
- // L:
- patch(gbranch(optoas(OLT, t), T), to);
- br = gbranch(optoas(OGT, t), T);
- break;
- }
-
- // compare least significant word
- t = lo1.type;
- regalloc(&r1, types[TINT32], N);
- regalloc(&r2, types[TINT32], N);
- gins(AMOVW, &lo1, &r1);
- gins(AMOVW, &lo2, &r2);
- gcmp(ACMP, &r1, &r2);
- regfree(&r1);
- regfree(&r2);
-
- // jump again
- patch(gbranch(optoas(op, t), T), to);
-
- // point first branch down here if appropriate
- if(br != P)
- patch(br, pc);
-
- splitclean();
- splitclean();
-}
diff --git a/src/cmd/5g/doc.go b/src/cmd/5g/doc.go
deleted file mode 100644
index e86013bdd..000000000
--- a/src/cmd/5g/doc.go
+++ /dev/null
@@ -1,15 +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.
-
-/*
-
-5g is the version of the gc compiler for the ARM.
-The $GOARCH for these tools is arm.
-
-It reads .go files and outputs .5 files. The flags are documented in ../gc/doc.go.
-
-There is no instruction optimizer, so the -N flag is a no-op.
-
-*/
-package documentation
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
deleted file mode 100644
index 0fece9a08..000000000
--- a/src/cmd/5g/galign.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 "gg.h"
-
-int thechar = '5';
-char* thestring = "arm";
-
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
- */
-Typedef typedefs[] =
-{
- "int", TINT, TINT32,
- "uint", TUINT, TUINT32,
- "uintptr", TUINTPTR, TUINT32,
- 0
-};
-
-void
-betypeinit(void)
-{
- widthptr = 4;
-
- zprog.link = P;
- zprog.as = AGOK;
- zprog.scond = C_SCOND_NONE;
- zprog.reg = NREG;
- zprog.from.type = D_NONE;
- zprog.from.name = D_NONE;
- zprog.from.reg = NREG;
- zprog.to = zprog.from;
-
- listinit();
-}
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
deleted file mode 100644
index ce4558e21..000000000
--- a/src/cmd/5g/gg.h
+++ /dev/null
@@ -1,171 +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 <u.h>
-#include <libc.h>
-
-#include "../gc/go.h"
-#include "../5l/5.out.h"
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-typedef struct Addr Addr;
-
-struct Addr
-{
- int32 offset;
- int32 offset2;
- double dval;
- Prog* branch;
- char sval[NSNAME];
-
- Sym* sym;
- Node* node;
- int width;
- uchar type;
- char name;
- uchar reg;
- char pun;
- uchar etype;
-};
-#define A ((Addr*)0)
-
-struct Prog
-{
- short as; // opcode
- uint32 loc; // pc offset in this func
- uint32 lineno; // source line that generated this
- Addr from; // src address
- Addr to; // dst address
- Prog* link; // next instruction in this func
- void* regp; // points to enclosing Reg struct
- uchar reg; // doubles as width in DATA op
- uchar scond;
-};
-
-#define REGALLOC_R0 0
-#define REGALLOC_RMAX REGEXT
-#define REGALLOC_F0 (REGALLOC_RMAX+1)
-#define REGALLOC_FMAX (REGALLOC_F0 + FREGEXT)
-
-EXTERN Biobuf* bout;
-EXTERN int32 dynloc;
-EXTERN uchar reg[REGALLOC_FMAX+1];
-EXTERN int32 pcloc; // instruction counter
-EXTERN Strlit emptystring;
-extern char* anames[];
-EXTERN Hist* hist;
-EXTERN Prog zprog;
-EXTERN Node* curfn;
-EXTERN Node* newproc;
-EXTERN Node* deferproc;
-EXTERN Node* deferreturn;
-EXTERN Node* panicindex;
-EXTERN Node* panicslice;
-EXTERN Node* throwreturn;
-EXTERN long unmappedzero;
-EXTERN int maxstksize;
-
-/*
- * gen.c
- */
-void compile(Node*);
-void proglist(void);
-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_dcl(Node*);
-int cgen_inline(Node*, Node*);
-int needconvert(Type*, Type*);
-void genconv(Type*, Type*);
-void allocparams(void);
-void checklabels();
-void ginscall(Node*, int);
-
-/*
- * cgen
- */
-void agen(Node*, Node*);
-Prog* cgenindex(Node *, Node *);
-void igen(Node*, Node*, Node*);
-void agenr(Node *n, Node *a, Node *res);
-vlong fieldoffset(Type*, Node*);
-void bgen(Node*, int, Prog*);
-void sgen(Node*, Node*, int32);
-void gmove(Node*, Node*);
-Prog* gins(int, Node*, Node*);
-int samaddr(Node*, Node*);
-void raddr(Node *n, Prog *p);
-Prog* gcmp(int, Node*, Node*);
-Prog* gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs);
-Prog * gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs);
-void naddr(Node*, Addr*, int);
-void cgen_aret(Node*, Node*);
-void cgen_shift(int, Node*, Node*, Node*);
-
-/*
- * cgen64.c
- */
-void cmp64(Node*, Node*, int, Prog*);
-void cgen64(Node*, Node*);
-
-/*
- * gsubr.c
- */
-void clearp(Prog*);
-void proglist(void);
-Prog* gbranch(int, Type*);
-Prog* prog(int);
-void gaddoffset(Node*);
-void gconv(int, int);
-int conv2pt(Type*);
-vlong convvtox(vlong, int);
-void fnparam(Type*, int, int);
-Prog* gop(int, Node*, Node*, Node*);
-void setconst(Addr*, vlong);
-void setaddr(Addr*, 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 buildtxt(void);
-Plist* newplist(void);
-int isfat(Type*);
-int dotaddable(Node*, Node*);
-void sudoclean(void);
-int sudoaddable(int, Node*, Addr*, int*);
-void afunclit(Addr*);
-void datagostring(Strlit*, Addr*);
-void split64(Node*, Node*, Node*);
-void splitclean(void);
-Node* ncon(uint32 i);
-
-/*
- * obj.c
- */
-void datastring(char*, int, Addr*);
-
-/*
- * list.c
- */
-int Aconv(Fmt*);
-int Cconv(Fmt*);
-int Dconv(Fmt*);
-int Mconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Yconv(Fmt*);
-void listinit(void);
-
-void zaddr(Biobuf*, Addr*, int);
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
deleted file mode 100644
index d5b00b34d..000000000
--- a/src/cmd/5g/ggen.c
+++ /dev/null
@@ -1,1003 +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.
-
-#undef EXTERN
-#define EXTERN
-#include "gg.h"
-#include "opt.h"
-
-void
-defframe(Prog *ptxt)
-{
- // fill in argument size
- ptxt->to.type = D_CONST2;
- ptxt->reg = 0; // flags
- ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
-
- // fill in final stack size
- if(stksize > maxstksize)
- maxstksize = stksize;
- ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
- maxstksize = 0;
-}
-
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
- for (; p; p = p->link) {
- if (p->from.name == D_AUTO && p->from.node)
- p->from.node->used++;
-
- if (p->to.name == D_AUTO && p->to.node)
- p->to.node->used++;
- }
-}
-
-// Fixup instructions after compactframe has moved all autos around.
-void
-fixautoused(Prog* p)
-{
- for (; p; p = p->link) {
- 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;
- }
-}
-
-/*
- * generate:
- * call f
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-void
-ginscall(Node *f, int proc)
-{
- Prog *p;
- Node n1, r, con;
-
- switch(proc) {
- default:
- fatal("ginscall: bad proc %d", proc);
- break;
-
- case 0: // normal call
- p = gins(ABL, N, f);
- afunclit(&p->to);
- break;
-
- case 1: // call in new proc (go)
- case 2: // deferred call (defer)
- regalloc(&r, types[tptr], N);
- p = gins(AMOVW, N, &r);
- p->from.type = D_OREG;
- p->from.reg = REGSP;
-
- p = gins(AMOVW, &r, N);
- p->to.type = D_OREG;
- p->to.reg = REGSP;
- p->to.offset = -12;
- p->scond |= C_WBIT;
-
- memset(&n1, 0, sizeof n1);
- n1.op = OADDR;
- n1.left = f;
- gins(AMOVW, &n1, &r);
-
- p = gins(AMOVW, &r, N);
- p->to.type = D_OREG;
- p->to.reg = REGSP;
- p->to.offset = 8;
-
- nodconst(&con, types[TINT32], argsize(f->type));
- gins(AMOVW, &con, &r);
- p = gins(AMOVW, &r, N);
- p->to.type = D_OREG;
- p->to.reg = REGSP;
- p->to.offset = 4;
- regfree(&r);
-
- if(proc == 1)
- ginscall(newproc, 0);
- else
- ginscall(deferproc, 0);
-
- nodreg(&r, types[tptr], 1);
- p = gins(AMOVW, N, N);
- p->from.type = D_CONST;
- p->from.reg = REGSP;
- p->from.offset = 12;
- p->to.reg = REGSP;
- p->to.type = D_REG;
-
- if(proc == 2) {
- nodconst(&con, types[TINT32], 0);
- p = gins(ACMP, &con, N);
- p->reg = 0;
- patch(gbranch(ABNE, T), retpc);
- }
- break;
- }
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-void
-cgen_callinter(Node *n, Node *res, int proc)
-{
- int r;
- Node *i, *f;
- Node tmpi, nodo, nodr, nodsp;
-
- 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
-
- // Release res register during genlist and cgen,
- // which might have their own function calls.
- r = -1;
- if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
- r = res->val.u.reg;
- reg[r]--;
- }
-
- if(!i->addable) {
- tempname(&tmpi, i->type);
- cgen(i, &tmpi);
- i = &tmpi;
- }
-
- genlist(n->list); // args
- if(r >= 0)
- reg[r]++;
-
- regalloc(&nodr, types[tptr], res);
- regalloc(&nodo, types[tptr], &nodr);
- nodo.op = OINDREG;
-
- agen(i, &nodr); // REG = &inter
-
- nodindreg(&nodsp, types[tptr], REGSP);
- nodsp.xoffset = 4;
- nodo.xoffset += widthptr;
- cgen(&nodo, &nodsp); // 4(SP) = 4(REG) -- i.data
-
- nodo.xoffset -= widthptr;
- cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
-
- nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
- cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
-
- // BOTCH nodr.type = fntype;
- nodr.type = n->left->type;
- ginscall(&nodr, proc);
-
- regfree(&nodr);
- regfree(&nodo);
-
- setmaxarg(n->left->type);
-}
-
-/*
- * 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;
-
- setmaxarg(t);
-
- // 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);
- goto ret;
- }
-
- // 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);
- goto ret;
- }
-
- // call direct
- n->left->method = 1;
- ginscall(n->left, proc);
-
-
-ret:
- ;
-}
-
-/*
- * 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 = REGSP;
- nod.addable = 1;
-
- nod.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
- 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 = REGSP;
- nod1.addable = 1;
-
- nod1.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
- nod1.type = fp->type;
-
- if(res->op != OREGISTER) {
- regalloc(&nod2, types[tptr], res);
- agen(&nod1, &nod2);
- gins(AMOVW, &nod2, res);
- regfree(&nod2);
- } else
- agen(&nod1, res);
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-void
-cgen_ret(Node *n)
-{
- genlist(n->list); // copy out args
- if(hasdefer || curfn->exit)
- gjmp(retpc);
- else
- gins(ARET, N, N);
-}
-
-/*
- * generate += *= etc.
- */
-void
-cgen_asop(Node *n)
-{
- Node n1, n2, n3, n4;
- Node *nl, *nr;
- Prog *p1;
- Addr addr;
- int a, w;
-
- nl = n->left;
- nr = n->right;
-
- if(nr->ullman >= UINF && nl->ullman >= UINF) {
- tempname(&n1, nr->type);
- cgen(nr, &n1);
- n2 = *n;
- n2.right = &n1;
- cgen_asop(&n2);
- goto ret;
- }
-
- if(!isint[nl->type->etype])
- goto hard;
- if(!isint[nr->type->etype])
- goto hard;
- if(is64(nl->type) || is64(nr->type))
- goto hard64;
-
- switch(n->etype) {
- case OADD:
- case OSUB:
- case OXOR:
- case OAND:
- case OOR:
- a = optoas(n->etype, nl->type);
- if(nl->addable) {
- regalloc(&n3, nr->type, N);
- cgen(nr, &n3);
- regalloc(&n2, nl->type, N);
- cgen(nl, &n2);
- gins(a, &n3, &n2);
- cgen(&n2, nl);
- regfree(&n2);
- regfree(&n3);
- goto ret;
- }
- if(nr->ullman < UINF)
- if(sudoaddable(a, nl, &addr, &w)) {
- w = optoas(OAS, nl->type);
- regalloc(&n2, nl->type, N);
- p1 = gins(w, N, &n2);
- p1->from = addr;
- regalloc(&n3, nr->type, N);
- cgen(nr, &n3);
- gins(a, &n3, &n2);
- p1 = gins(w, &n2, N);
- p1->to = addr;
- regfree(&n2);
- regfree(&n3);
- sudoclean();
- goto ret;
- }
- }
-
-hard:
- n2.op = 0;
- n1.op = 0;
- if(nr->ullman >= nl->ullman || nl->addable) {
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- nr = &n2;
- } else {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- if(!nl->addable) {
- igen(nl, &n1, N);
- nl = &n1;
- }
-
- n3 = *n;
- n3.left = nl;
- n3.right = nr;
- n3.op = n->etype;
-
- regalloc(&n4, nl->type, N);
- cgen(&n3, &n4);
- gmove(&n4, nl);
-
- if(n1.op)
- regfree(&n1);
- if(n2.op == OREGISTER)
- regfree(&n2);
- regfree(&n4);
- goto ret;
-
-hard64:
- if(nr->ullman > nl->ullman) {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- igen(nl, &n1, N);
- } else {
- igen(nl, &n1, N);
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- }
-
- n3 = *n;
- n3.left = &n1;
- n3.right = &n2;
- n3.op = n->etype;
-
- cgen(&n3, &n1);
-
-ret:
- ;
-}
-
-int
-samereg(Node *a, Node *b)
-{
- 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 shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-void
-cgen_shift(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, t;
- int w;
- Prog *p1, *p2, *p3;
- uvlong sc;
-
- if(nl->type->width > 4)
- fatal("cgen_shift %T", nl->type);
-
- w = nl->type->width * 8;
-
- if(nr->op == OLITERAL) {
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- sc = mpgetfix(nr->val.u.xval);
- if(sc == 0) {
- // nothing to do
- } else if(sc >= nl->type->width*8) {
- if(op == ORSH && issigned[nl->type->etype])
- gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
- else
- gins(AEOR, &n1, &n1);
- } else {
- if(op == ORSH && issigned[nl->type->etype])
- gshift(AMOVW, &n1, SHIFT_AR, sc, &n1);
- else if(op == ORSH)
- gshift(AMOVW, &n1, SHIFT_LR, sc, &n1);
- else // OLSH
- gshift(AMOVW, &n1, SHIFT_LL, sc, &n1);
- }
- gmove(&n1, res);
- regfree(&n1);
- return;
- }
-
- if(nl->ullman >= nr->ullman) {
- regalloc(&n2, nl->type, res);
- cgen(nl, &n2);
- regalloc(&n1, nr->type, N);
- cgen(nr, &n1);
- } else {
- regalloc(&n1, nr->type, N);
- cgen(nr, &n1);
- regalloc(&n2, nl->type, res);
- cgen(nl, &n2);
- }
-
- // test for shift being 0
- p1 = gins(ATST, &n1, N);
- p3 = gbranch(ABEQ, T);
-
- // test and fix up large shifts
- regalloc(&n3, nr->type, N);
- nodconst(&t, types[TUINT32], w);
- gmove(&t, &n3);
- gcmp(ACMP, &n1, &n3);
- if(op == ORSH) {
- if(issigned[nl->type->etype]) {
- p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2);
- p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2);
- } else {
- p1 = gins(AEOR, &n2, &n2);
- p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2);
- }
- p1->scond = C_SCOND_HS;
- p2->scond = C_SCOND_LO;
- } else {
- p1 = gins(AEOR, &n2, &n2);
- p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2);
- p1->scond = C_SCOND_HS;
- p2->scond = C_SCOND_LO;
- }
- regfree(&n3);
-
- patch(p3, pc);
- gmove(&n2, res);
-
- regfree(&n1);
- regfree(&n2);
-}
-
-void
-clearfat(Node *nl)
-{
- uint32 w, c, q;
- Node dst, nc, nz, end;
- Prog *p, *pl;
-
- /* clear a fat object */
- if(debug['g'])
- dump("\nclearfat", nl);
-
- w = nl->type->width;
- c = w % 4; // bytes
- q = w / 4; // quads
-
- regalloc(&dst, types[tptr], N);
- agen(nl, &dst);
- nodconst(&nc, types[TUINT32], 0);
- regalloc(&nz, types[TUINT32], 0);
- cgen(&nc, &nz);
-
- if(q >= 4) {
- regalloc(&end, types[tptr], N);
- p = gins(AMOVW, &dst, &end);
- p->from.type = D_CONST;
- p->from.offset = q*4;
-
- p = gins(AMOVW, &nz, &dst);
- p->to.type = D_OREG;
- p->to.offset = 4;
- p->scond |= C_PBIT;
- pl = p;
-
- p = gins(ACMP, &dst, N);
- raddr(&end, p);
- patch(gbranch(ABNE, T), pl);
-
- regfree(&end);
- } else
- while(q > 0) {
- p = gins(AMOVW, &nz, &dst);
- p->to.type = D_OREG;
- p->to.offset = 4;
- p->scond |= C_PBIT;
-//print("1. %P\n", p);
- q--;
- }
-
- while(c > 0) {
- p = gins(AMOVBU, &nz, &dst);
- p->to.type = D_OREG;
- p->to.offset = 1;
- p->scond |= C_PBIT;
-//print("2. %P\n", p);
- c--;
- }
- regfree(&dst);
- regfree(&nz);
-}
-
-static int
-regcmp(const void *va, const void *vb)
-{
- Node *ra, *rb;
-
- ra = (Node*)va;
- rb = (Node*)vb;
- return ra->local - rb->local;
-}
-
-static Prog* throwpc;
-
-// We're only going to bother inlining if we can
-// convert all the arguments to 32 bits safely. Can we?
-static int
-fix64(NodeList *nn, int n)
-{
- NodeList *l;
- Node *r;
- int i;
-
- l = nn;
- for(i=0; i<n; i++) {
- r = l->n->right;
- if(is64(r->type) && !smallintconst(r)) {
- if(r->op == OCONV)
- r = r->left;
- if(is64(r->type))
- return 0;
- }
- l = l->next;
- }
- return 1;
-}
-
-void
-getargs(NodeList *nn, Node *reg, int n)
-{
- NodeList *l;
- int i;
-
- throwpc = nil;
-
- l = nn;
- for(i=0; i<n; i++) {
- if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) {
- regalloc(reg+i, l->n->right->type, N);
- cgen(l->n->right, reg+i);
- } else
- reg[i] = *l->n->right;
- if(reg[i].local != 0)
- yyerror("local used");
- reg[i].local = l->n->left->xoffset;
- l = l->next;
- }
- qsort((void*)reg, n, sizeof(*reg), regcmp);
- for(i=0; i<n; i++)
- reg[i].local = 0;
-}
-
-void
-cmpandthrow(Node *nl, Node *nr)
-{
- vlong cl;
- Prog *p1;
- int op;
- Node *c, n1, n2;
-
- op = OLE;
- if(smallintconst(nl)) {
- cl = mpgetfix(nl->val.u.xval);
- if(cl == 0)
- return;
- if(smallintconst(nr))
- return;
-
- // put the constant on the right
- op = brrev(op);
- c = nl;
- nl = nr;
- nr = c;
- }
-
- n1.op = OXXX;
- if(nr->op != OREGISTER) {
- regalloc(&n1, types[TUINT32], N);
- gmove(nr, &n1);
- nr = &n1;
- }
- n2.op = OXXX;
- if(nl->op != OREGISTER) {
- regalloc(&n2, types[TUINT32], N);
- gmove(nl, &n2);
- nl = &n2;
- }
- gcmp(optoas(OCMP, types[TUINT32]), nl, nr);
- if(nr == &n1)
- regfree(&n1);
- if(nl == &n2)
- regfree(&n2);
- if(throwpc == nil) {
- p1 = gbranch(optoas(op, types[TUINT32]), T);
- throwpc = pc;
- ginscall(panicslice, 0);
- patch(p1, pc);
- } else {
- op = brcom(op);
- p1 = gbranch(optoas(op, types[TUINT32]), T);
- patch(p1, throwpc);
- }
-}
-
-int
-sleasy(Node *n)
-{
- if(n->op != ONAME)
- return 0;
- if(!n->addable)
- return 0;
- return 1;
-}
-
-// generate inline code for
-// slicearray
-// sliceslice
-// arraytoslice
-int
-cgen_inline(Node *n, Node *res)
-{
- Node nodes[5];
- Node n1, n2, n3, nres, ntemp;
- vlong v;
- int i, narg;
-
- if(n->op != OCALLFUNC)
- goto no;
- if(!n->left->addable)
- goto no;
- if(n->left->sym == S)
- goto no;
- if(n->left->sym->pkg != runtimepkg)
- goto no;
- if(strcmp(n->left->sym->name, "slicearray") == 0)
- goto slicearray;
- if(strcmp(n->left->sym->name, "sliceslice") == 0) {
- narg = 4;
- goto sliceslice;
- }
- if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
- narg = 3;
- goto sliceslice;
- }
- goto no;
-
-slicearray:
- if(!sleasy(res))
- goto no;
- if(!fix64(n->list, 5))
- goto no;
- getargs(n->list, nodes, 5);
-
- // if(hb[3] > nel[1]) goto throw
- cmpandthrow(&nodes[3], &nodes[1]);
-
- // if(lb[2] > hb[3]) goto throw
- cmpandthrow(&nodes[2], &nodes[3]);
-
- // len = hb[3] - lb[2] (destroys hb)
- n2 = *res;
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
-
- if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
- v = mpgetfix(nodes[3].val.u.xval) -
- mpgetfix(nodes[2].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gmove(&n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[3]);
- gmove(&nodes[3], &n1);
- if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
- gmove(&n1, &n2);
- regfree(&n1);
- }
-
- // cap = nel[1] - lb[2] (destroys nel)
- n2 = *res;
- n2.type = types[TUINT32];
- n2.xoffset += Array_cap;
-
- if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
- v = mpgetfix(nodes[1].val.u.xval) -
- mpgetfix(nodes[2].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gmove(&n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[1]);
- gmove(&nodes[1], &n1);
- if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
- gmove(&n1, &n2);
- regfree(&n1);
- }
-
- // if slice could be too big, dereference to
- // catch nil array pointer.
- if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
- n2 = nodes[0];
- n2.xoffset = 0;
- n2.op = OINDREG;
- n2.type = types[TUINT8];
- regalloc(&n1, types[TUINT32], N);
- gins(AMOVB, &n2, &n1);
- regfree(&n1);
- }
-
- // ary = old[0] + (lb[2] * width[4]) (destroys old)
- n2 = *res;
- n2.type = types[tptr];
- n2.xoffset += Array_array;
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
- v = mpgetfix(nodes[2].val.u.xval) *
- mpgetfix(nodes[4].val.u.xval);
- if(v != 0) {
- nodconst(&n1, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- }
- } else {
- regalloc(&n1, types[tptr], &nodes[2]);
- gmove(&nodes[2], &n1);
- if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1) {
- regalloc(&n3, types[tptr], N);
- gmove(&nodes[4], &n3);
- gins(optoas(OMUL, types[tptr]), &n3, &n1);
- regfree(&n3);
- }
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- regfree(&n1);
- }
- gmove(&nodes[0], &n2);
-
- for(i=0; i<5; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
- return 1;
-
-sliceslice:
- if(!fix64(n->list, narg))
- goto no;
- ntemp.op = OXXX;
- if(!sleasy(n->list->n->right)) {
- Node *n0;
-
- n0 = n->list->n->right;
- tempname(&ntemp, res->type);
- cgen(n0, &ntemp);
- n->list->n->right = &ntemp;
- getargs(n->list, nodes, narg);
- n->list->n->right = n0;
- } else
- getargs(n->list, nodes, narg);
-
- nres = *res; // result
- if(!sleasy(res)) {
- if(ntemp.op == OXXX)
- tempname(&ntemp, res->type);
- nres = ntemp;
- }
-
- if(narg == 3) { // old[lb:]
- // move width to where it would be for old[lb:hb]
- nodes[3] = nodes[2];
- nodes[2].op = OXXX;
-
- // if(lb[1] > old.nel[0]) goto throw;
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- cmpandthrow(&nodes[1], &n2);
-
- // ret.nel = old.nel[0]-lb[1];
- n2 = nodes[0];
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
-
- regalloc(&n1, types[TUINT32], N);
- gmove(&n2, &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
-
- n2 = nres;
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
- gmove(&n1, &n2);
- regfree(&n1);
- } else { // old[lb:hb]
- // if(hb[2] > old.cap[0]) goto throw;
- n2 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
- cmpandthrow(&nodes[2], &n2);
-
- // if(lb[1] > hb[2]) goto throw;
- cmpandthrow(&nodes[1], &nodes[2]);
-
- // ret.len = hb[2]-lb[1]; (destroys hb[2])
- n2 = nres;
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
- v = mpgetfix(nodes[2].val.u.xval) -
- mpgetfix(nodes[1].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gmove(&n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gmove(&nodes[2], &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
- gmove(&n1, &n2);
- regfree(&n1);
- }
- }
-
- // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
- n2 = nodes[0];
- n2.type = types[TUINT32];
- n2.xoffset += Array_cap;
-
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gmove(&n2, &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
-
- n2 = nres;
- n2.type = types[TUINT32];
- n2.xoffset += Array_cap;
- gmove(&n1, &n2);
- regfree(&n1);
-
- // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
- n2 = nodes[0];
- n2.type = types[tptr];
- n2.xoffset += Array_array;
- regalloc(&n3, types[tptr], N);
- gmove(&n2, &n3);
-
- regalloc(&n1, types[tptr], &nodes[1]);
- if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
- gmove(&n2, &n1);
- v = mpgetfix(nodes[1].val.u.xval) *
- mpgetfix(nodes[3].val.u.xval);
- if(v != 0) {
- nodconst(&n2, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n3, &n1);
- }
- } else {
- gmove(&nodes[1], &n1);
- if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1) {
- regalloc(&n2, types[tptr], N);
- gmove(&nodes[3], &n2);
- gins(optoas(OMUL, types[tptr]), &n2, &n1);
- regfree(&n2);
- }
- gins(optoas(OADD, types[tptr]), &n3, &n1);
- }
- regfree(&n3);
-
- n2 = nres;
- n2.type = types[tptr];
- n2.xoffset += Array_array;
- gmove(&n1, &n2);
- regfree(&n1);
-
- for(i=0; i<4; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
-
- if(!sleasy(res)) {
- cgen(&nres, res);
- }
- return 1;
-
-no:
- return 0;
-}
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
deleted file mode 100644
index 27c8be67d..000000000
--- a/src/cmd/5g/gobj.c
+++ /dev/null
@@ -1,623 +0,0 @@
-// Derived from 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 "gg.h"
-
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- Bputc(b, ANAME); /* as */
- Bputc(b, t); /* type */
- Bputc(b, s->sym); /* sym */
-
- Bputname(b, s);
-}
-
-void
-zfile(Biobuf *b, char *p, int n)
-{
- Bputc(b, ANAME);
- Bputc(b, D_FILE);
- Bputc(b, 1);
- Bputc(b, '<');
- Bwrite(b, p, n);
- Bputc(b, 0);
-}
-
-void
-zhist(Biobuf *b, int line, vlong offset)
-{
- Addr a;
-
- Bputc(b, AHISTORY);
- Bputc(b, C_SCOND_NONE);
- Bputc(b, NREG);
- Bputc(b, line);
- Bputc(b, line>>8);
- Bputc(b, line>>16);
- Bputc(b, line>>24);
- zaddr(b, &zprog.from, 0);
- a = zprog.to;
- if(offset != 0) {
- a.offset = offset;
- a.type = D_CONST;
- }
- zaddr(b, &a, 0);
-}
-
-void
-zaddr(Biobuf *b, Addr *a, int s)
-{
- int32 l;
- uint64 e;
- int i;
- char *n;
-
- switch(a->type) {
- case D_STATIC:
- case D_AUTO:
- case D_EXTERN:
- case D_PARAM:
- // TODO(kaib): remove once everything seems to work
- fatal("We should no longer generate these as types");
-
- default:
- Bputc(b, a->type);
- Bputc(b, a->reg);
- Bputc(b, s);
- Bputc(b, a->name);
- }
-
- switch(a->type) {
- default:
- print("unknown type %d in zaddr\n", a->type);
-
- case D_NONE:
- case D_REG:
- case D_FREG:
- case D_PSR:
- break;
-
- case D_CONST2:
- l = a->offset2;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24); // fall through
- case D_OREG:
- case D_CONST:
- case D_SHIFT:
- case D_STATIC:
- case D_AUTO:
- case D_EXTERN:
- case D_PARAM:
- l = a->offset;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- break;
-
- case D_BRANCH:
- if(a->branch == nil)
- fatal("unpatched branch");
- a->offset = a->branch->loc;
- l = a->offset;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- break;
-
- case D_SCONST:
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- Bputc(b, *n);
- n++;
- }
- break;
-
- case D_REGREG:
- Bputc(b, a->offset);
- break;
-
- case D_FCONST:
- ieeedtod(&e, a->dval);
- l = e;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- l = e >> 32;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- break;
- }
-}
-
-void
-dumpfuncs(void)
-{
- Plist *pl;
- int sf, st, t, sym;
- struct { Sym *sym; short type; } h[NSYM];
- Sym *s;
- Prog *p;
-
- for(sym=0; sym<NSYM; sym++) {
- h[sym].sym = S;
- h[sym].type = 0;
- }
- sym = 1;
-
- // fix up pc
- pcloc = 0;
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
- for(p=pl->firstpc; p!=P; p=p->link) {
- p->loc = pcloc;
- if(p->as != ADATA && p->as != AGLOBL)
- pcloc++;
- }
- }
-
- // put out functions
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
-
- if(debug['S']) {
- s = S;
- if(pl->name != N)
- s = pl->name->sym;
- print("\n--- prog list \"%S\" ---\n", s);
- for(p=pl->firstpc; p!=P; p=p->link)
- print("%P\n", p);
- }
-
- for(p=pl->firstpc; p!=P; p=p->link) {
- jackpot:
- sf = 0;
- s = p->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = p->from.name;
- if(t == D_ADDR)
- t = p->from.name;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- s->sym = sym;
- zname(bout, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = p->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = p->to.name;
- if(t == D_ADDR)
- t = p->to.name;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- s->sym = sym;
- zname(bout, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- Bputc(bout, p->as);
- Bputc(bout, p->scond);
- Bputc(bout, p->reg);
- Bputc(bout, p->lineno);
- Bputc(bout, p->lineno>>8);
- Bputc(bout, p->lineno>>16);
- Bputc(bout, p->lineno>>24);
- zaddr(bout, &p->from, sf);
- zaddr(bout, &p->to, st);
- }
- }
-}
-
-/* deferred DATA output */
-static Prog *strdat;
-static Prog *estrdat;
-static int gflag;
-static Prog *savepc;
-
-void
-data(void)
-{
- gflag = debug['g'];
- debug['g'] = 0;
-
- if(estrdat == nil) {
- strdat = mal(sizeof(*pc));
- clearp(strdat);
- estrdat = strdat;
- }
- if(savepc)
- fatal("data phase error");
- savepc = pc;
- pc = estrdat;
-}
-
-void
-text(void)
-{
- if(!savepc)
- fatal("text phase error");
- debug['g'] = gflag;
- estrdat = pc;
- pc = savepc;
- savepc = nil;
-}
-
-void
-dumpdata(void)
-{
- Prog *p;
-
- if(estrdat == nil)
- return;
- *pc = *strdat;
- if(gflag)
- for(p=pc; p!=estrdat; p=p->link)
- print("%P\n", p);
- pc = estrdat;
-}
-
-int
-dsname(Sym *sym, int off, char *t, int n)
-{
- Prog *p;
-
- p = gins(ADATA, N, N);
- p->from.type = D_OREG;
- p->from.name = D_EXTERN;
- p->from.etype = TINT32;
- p->from.offset = off;
- p->from.reg = NREG;
- p->from.sym = sym;
-
- p->reg = n;
-
- p->to.type = D_SCONST;
- p->to.name = D_NONE;
- p->to.reg = NREG;
- p->to.offset = 0;
- memmove(p->to.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 = TINT32;
- a->offset = widthptr+4; // skip header
- a->reg = NREG;
- a->sym = sym;
-}
-
-/*
- * 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->etype = TINT32;
- a->offset = 0; // header
- a->reg = NREG;
- a->sym = sym;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
- Prog *p;
- vlong v;
-
- if(wid == 8 && is64(nr->type)) {
- v = mpgetfix(nr->val.u.xval);
- p = gins(ADATA, nam, nodintconst(v));
- p->reg = 4;
- p = gins(ADATA, nam, nodintconst(v>>32));
- p->reg = 4;
- p->from.offset += 4;
- 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.dval = mpgetflt(&cval->real);
-
- p = gins(ADATA, nam, N);
- p->reg = w;
- p->from.offset += w;
- p->to.type = D_FCONST;
- p->to.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 = TINT32;
-//print("%P\n", p);
-
- nodconst(&nod1, types[TINT32], sval->len);
- p = gins(ADATA, nam, &nod1);
- p->reg = types[TINT32]->width;
- p->from.offset += types[tptr]->width;
-}
-
-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 = s;
- p->from.offset = off;
- p->reg = widthptr;
-
- datastring(str, strlen(str)+1, &p->to);
- p->to.type = D_CONST;
- p->to.etype = TINT32;
- 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 = s;
- p->from.offset = off;
- p->reg = widthptr;
- datagostring(lit, &p->to);
- p->to.type = D_CONST;
- p->to.etype = TINT32;
- 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
-duintxx(Sym *s, int off, uint64 v, int wid)
-{
- Prog *p;
-
- off = rnd(off, wid);
-
- p = gins(ADATA, N, N);
- p->from.type = D_OREG;
- p->from.name = D_EXTERN;
- p->from.sym = s;
- p->from.offset = off;
- p->reg = wid;
- p->to.type = D_CONST;
- p->to.name = D_NONE;
- p->to.offset = v;
- off += wid;
-
- return off;
-}
-
-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 = s;
- p->from.offset = off;
- p->reg = widthptr;
- p->to.type = D_CONST;
- p->to.name = D_EXTERN;
- p->to.sym = x;
- p->to.offset = xoff;
- off += widthptr;
-
- return off;
-}
-
-
-void
-genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
-{
- // TODO(kaib): re-implement genembedtramp
- genwrapper(rcvr, method, newnam, iface);
-/*
- Sym *e;
- int c, d, o;
- Prog *p;
- Type *f;
-
- e = method->sym;
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(e, rcvr, d, nil, 0);
- if(c == 1)
- goto out;
- }
- fatal("genembedtramp %T.%S", rcvr, method->sym);
-
-out:
- newplist()->name = newname(newnam);
-
- //TEXT main·S_test2(SB),7,$0
- p = pc;
- gins(ATEXT, N, N);
- p->from.type = D_OREG;
- p->from.name = D_EXTERN;
- p->from.sym = newnam;
- p->to.type = D_CONST2;
- p->reg = 7;
- p->to.offset2 = 0;
- p->to.reg = NREG;
-//print("1. %P\n", p);
-
- o = 0;
- for(c=d-1; c>=0; c--) {
- f = dotlist[c].field;
- o += f->width;
- if(!isptr[f->type->etype])
- continue;
-
- //MOVW o(R0), R0
- p = pc;
- gins(AMOVW, N, N);
- p->from.type = D_OREG;
- p->from.reg = REGARG;
- p->from.offset = o;
- p->to.type = D_REG;
- p->to.reg = REGARG;
-//print("2. %P\n", p);
- o = 0;
- }
- if(o != 0) {
- //MOVW $XX(R0), R0
- p = pc;
- gins(AMOVW, N, N);
- p->from.type = D_CONST;
- p->from.reg = REGARG;
- p->from.offset = o;
- p->to.type = D_REG;
- p->to.reg = REGARG;
-//print("3. %P\n", p);
- }
-
- f = dotlist[0].field;
- //B main·*Sub_test2(SB)
- if(isptr[f->type->etype])
- f = f->type;
- p = pc;
- gins(AB, N, N);
- p->to.type = D_OREG;
- p->to.reg = NREG;
- p->to.name = D_EXTERN;
- p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
-//print("4. %P\n", p);
-
- pc->as = ARET; // overwrite AEND
-*/
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
-}
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
deleted file mode 100644
index 2d9218461..000000000
--- a/src/cmd/5g/gsubr.c
+++ /dev/null
@@ -1,2005 +0,0 @@
-// Derived from 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 "gg.h"
-
-// TODO(kaib): Can make this bigger if we move
-// the text segment up higher in 5l for all GOOS.
-long unmappedzero = 4096;
-
-void
-clearp(Prog *p)
-{
- p->as = AEND;
- p->reg = NREG;
- p->scond = C_SCOND_NONE;
- p->from.type = D_NONE;
- p->from.name = D_NONE;
- p->from.reg = NREG;
- p->to.type = D_NONE;
- p->to.name = D_NONE;
- p->to.reg = NREG;
- p->loc = pcloc;
- pcloc++;
-}
-
-/*
- * generate and return proc with p->as = as,
- * linked into program. pc is next instruction.
- */
-Prog*
-prog(int as)
-{
- Prog *p;
-
- p = pc;
- pc = mal(sizeof(*pc));
-
- clearp(pc);
-
- if(lineno == 0) {
- if(debug['K'])
- warn("prog: line 0");
- }
-
- p->as = as;
- p->lineno = lineno;
- p->link = pc;
- return p;
-}
-
-/*
- * generate a branch.
- * t is ignored.
- */
-Prog*
-gbranch(int as, Type *t)
-{
- Prog *p;
-
- p = prog(as);
- p->to.type = D_BRANCH;
- p->to.branch = P;
- 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.branch = to;
- p->to.offset = to->loc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
- Prog *q;
-
- if(p->to.type != D_BRANCH)
- fatal("unpatch: not a branch");
- q = p->to.branch;
- p->to.branch = P;
- p->to.offset = 0;
- return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
- Plist *pl;
-
- pl = mal(sizeof(*pl));
- if(plist == nil)
- plist = pl;
- else
- plast->link = pl;
- plast = pl;
-
- pc = mal(sizeof(*pc));
- clearp(pc);
- pl->firstpc = pc;
-
- return pl;
-}
-
-void
-clearstk(void)
-{
- Plist *pl;
- Prog *p, *p1, *p2, *p3;
- Node dst, end, zero, con;
-
- if(plast->firstpc->to.offset <= 0)
- return;
-
- // reestablish context for inserting code
- // at beginning of function.
- pl = plast;
- p1 = pl->firstpc;
- p2 = p1->link;
- pc = mal(sizeof(*pc));
- clearp(pc);
- p1->link = pc;
-
- // zero stack frame
-
- // MOVW $4(SP), R1
- nodreg(&dst, types[tptr], 1);
- p = gins(AMOVW, N, &dst);
- p->from.type = D_CONST;
- p->from.reg = REGSP;
- p->from.offset = 4;
-
- // MOVW $n(R1), R2
- nodreg(&end, types[tptr], 2);
- p = gins(AMOVW, N, &end);
- p->from.type = D_CONST;
- p->from.reg = 1;
- p->from.offset = p1->to.offset;
-
- // MOVW $0, R3
- nodreg(&zero, types[TUINT32], 3);
- nodconst(&con, types[TUINT32], 0);
- gmove(&con, &zero);
-
- // L:
- // MOVW.P R3, 0(R1) +4
- // CMP R1, R2
- // BNE L
- p = gins(AMOVW, &zero, &dst);
- p->to.type = D_OREG;
- p->to.offset = 4;
- p->scond |= C_PBIT;
- p3 = p;
- p = gins(ACMP, &dst, N);
- raddr(&end, p);
- patch(gbranch(ABNE, T), p3);
-
- // continue with original code.
- gins(ANOP, N, N)->link = p2;
- pc = P;
-}
-
-void
-gused(Node *n)
-{
- gins(ANOP, n, N); // used
-}
-
-Prog*
-gjmp(Prog *to)
-{
- Prog *p;
-
- p = gbranch(AB, T);
- if(to != P)
- patch(p, to);
- return p;
-}
-
-void
-ggloblnod(Node *nam, int32 width)
-{
- Prog *p;
-
- p = gins(AGLOBL, nam, N);
- p->lineno = nam->lineno;
- p->to.sym = S;
- p->to.type = D_CONST;
- p->to.offset = width;
-}
-
-void
-ggloblsym(Sym *s, int32 width, int dupok)
-{
- Prog *p;
-
- p = gins(AGLOBL, N, N);
- p->from.type = D_OREG;
- p->from.name = D_EXTERN;
- p->from.sym = s;
- p->to.type = D_CONST;
- p->to.name = D_NONE;
- p->to.offset = width;
- if(dupok)
- p->reg = DUPOK;
-}
-
-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.
- * also fix up direct register references to be D_OREG.
- */
-void
-afunclit(Addr *a)
-{
- if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) {
- a->type = D_OREG;
- }
-}
-
-static int resvd[] =
-{
- 9, // reserved for m
- 10, // reserved for g
-};
-
-void
-ginit(void)
-{
- int i;
-
- for(i=0; i<nelem(reg); i++)
- reg[i] = 0;
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i]]++;
-}
-
-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\n", 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, fixfree, floatfree;
-
- if(debug['r']) {
- fixfree = 0;
- for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
- if(reg[i] == 0)
- fixfree++;
- floatfree = 0;
- for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
- if(reg[i] == 0)
- floatfree++;
- print("regalloc fix %d float %d\n", fixfree, floatfree);
- }
-
- if(t == T)
- fatal("regalloc: t nil");
- et = simtype[t->etype];
- if(is64(t))
- fatal("regalloc: 64 bit type %T");
-
- switch(et) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TPTR32:
- case TBOOL:
- if(o != N && o->op == OREGISTER) {
- i = o->val.u.reg;
- if(i >= REGALLOC_R0 && i <= REGALLOC_RMAX)
- goto out;
- }
- for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
- if(reg[i] == 0)
- goto out;
-
- yyerror("out of fixed registers");
- goto err;
-
- case TFLOAT32:
- case TFLOAT64:
- if(o != N && o->op == OREGISTER) {
- i = o->val.u.reg;
- if(i >= REGALLOC_F0 && i <= REGALLOC_FMAX)
- goto out;
- }
- for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
- if(reg[i] == 0)
- goto out;
- yyerror("out of floating point registers");
- goto err;
-
- case TCOMPLEX64:
- case TCOMPLEX128:
- tempname(n, t);
- return;
- }
- yyerror("regalloc: unknown type %T", t);
-
-err:
- nodreg(n, t, 0);
- return;
-
-out:
- reg[i]++;
- nodreg(n, t, i);
-}
-
-void
-regfree(Node *n)
-{
- int i, fixfree, floatfree;
-
- if(debug['r']) {
- fixfree = 0;
- for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
- if(reg[i] == 0)
- fixfree++;
- floatfree = 0;
- for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
- if(reg[i] == 0)
- floatfree++;
- print("regalloc fix %d float %d\n", fixfree, floatfree);
- }
-
- if(n->op == ONAME && iscomplex[n->type->etype])
- return;
- if(n->op != OREGISTER && n->op != OINDREG)
- fatal("regfree: not a register");
- i = n->val.u.reg;
- if(i < 0 || i >= sizeof(reg))
- fatal("regfree: reg out of range");
- if(reg[i] <= 0)
- fatal("regfree: reg not allocated");
- reg[i]--;
-}
-
-/*
- * 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;
- 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);
-
- 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;
-
-fp:
- switch(fp) {
- default:
- fatal("nodarg %T %d", t, fp);
-
- case 0: // output arg for calling another function
- n->op = OINDREG;
- n->val.u.reg = REGSP;
- n->xoffset += 4;
- break;
-
- case 1: // input arg to current function
- n->class = PPARAM;
- break;
- }
- return n;
-}
-
-/*
- * return constant i node.
- * overwritten by next call, but useful in calls to gins.
- */
-Node*
-ncon(uint32 i)
-{
- static Node n;
-
- if(n.type == T)
- nodconst(&n, types[TUINT32], 0);
- mpmovecfix(n.val.u.xval, i);
- return &n;
-}
-
-/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
- switch(n->op) {
- case OINDREG:
- case ONAME:
- case OPARAM:
- return 1;
- }
- return 0;
-}
-
-Node sclean[10];
-int nsclean;
-
-/*
- * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves.
- */
-void
-split64(Node *n, Node *lo, Node *hi)
-{
- Node n1;
- int64 i;
-
- if(!is64(n->type))
- fatal("split64 %T", n->type);
-
- sclean[nsclean].op = OEMPTY;
- if(nsclean >= nelem(sclean))
- fatal("split64 clean");
- nsclean++;
- switch(n->op) {
- default:
- if(!dotaddable(n, &n1)) {
- igen(n, &n1, N);
- sclean[nsclean-1] = n1;
- }
- n = &n1;
- goto common;
- case ONAME:
- if(n->class == PPARAMREF) {
- cgen(n->heapaddr, &n1);
- sclean[nsclean-1] = n1;
- // fall through.
- n = &n1;
- }
- goto common;
- case OINDREG:
- common:
- *lo = *n;
- *hi = *n;
- lo->type = types[TUINT32];
- if(n->type->etype == TINT64)
- hi->type = types[TINT32];
- else
- hi->type = types[TUINT32];
- hi->xoffset += 4;
- break;
-
- case OLITERAL:
- convconst(&n1, n->type, &n->val);
- i = mpgetfix(n1.val.u.xval);
- nodconst(lo, types[TUINT32], (uint32)i);
- i >>= 32;
- if(n->type->etype == TINT64)
- nodconst(hi, types[TINT32], (int32)i);
- else
- nodconst(hi, types[TUINT32], (uint32)i);
- break;
- }
-}
-
-void
-splitclean(void)
-{
- if(nsclean <= 0)
- fatal("splitclean");
- nsclean--;
- if(sclean[nsclean].op != OEMPTY)
- regfree(&sclean[nsclean]);
-}
-
-#define CASE(a,b) (((a)<<16)|((b)<<0))
-
-void
-gmove(Node *f, Node *t)
-{
- int a, ft, tt, fa, ta;
- Type *cvt;
- Node r1, r2, flo, fhi, tlo, thi, con;
- Prog *p1;
-
- if(debug['M'])
- print("gmove %N -> %N\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;
- // except 64-bit, which always copies via registers anyway.
- if(!is64(f->type) && !is64(t->type) && 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 TINT16:
- case TINT8:
- convconst(&con, types[TINT32], &f->val);
- regalloc(&r1, con.type, t);
- gins(AMOVW, &con, &r1);
- gmove(&r1, t);
- regfree(&r1);
- return;
-
- case TUINT16:
- case TUINT8:
- convconst(&con, types[TUINT32], &f->val);
- regalloc(&r1, con.type, t);
- gins(AMOVW, &con, &r1);
- gmove(&r1, t);
- regfree(&r1);
- return;
- }
-
- f = &con;
- ft = simsimtype(con.type);
-
- // constants can't move directly to memory
- if(ismem(t) && !is64(t->type)) 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:
- goto fatal;
-
- /*
- * 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):
- a = AMOVB;
- break;
-
- case CASE(TINT8, TUINT8):
- case CASE(TUINT8, TUINT8):
- case CASE(TINT16, TUINT8):
- case CASE(TUINT16, TUINT8):
- case CASE(TINT32, TUINT8):
- case CASE(TUINT32, TUINT8):
- a = AMOVBU;
- break;
-
- case CASE(TINT64, TINT8): // truncate low word
- case CASE(TUINT64, TINT8):
- a = AMOVB;
- goto trunc64;
-
- case CASE(TINT64, TUINT8):
- case CASE(TUINT64, TUINT8):
- a = AMOVBU;
- goto trunc64;
-
- case CASE(TINT16, TINT16): // same size
- case CASE(TUINT16, TINT16):
- case CASE(TINT32, TINT16): // truncate
- case CASE(TUINT32, TINT16):
- a = AMOVH;
- break;
-
- case CASE(TINT16, TUINT16):
- case CASE(TUINT16, TUINT16):
- case CASE(TINT32, TUINT16):
- case CASE(TUINT32, TUINT16):
- a = AMOVHU;
- break;
-
- case CASE(TINT64, TINT16): // truncate low word
- case CASE(TUINT64, TINT16):
- a = AMOVH;
- goto trunc64;
-
- case CASE(TINT64, TUINT16):
- case CASE(TUINT64, TUINT16):
- a = AMOVHU;
- goto trunc64;
-
- case CASE(TINT32, TINT32): // same size
- case CASE(TINT32, TUINT32):
- case CASE(TUINT32, TINT32):
- case CASE(TUINT32, TUINT32):
- a = AMOVW;
- break;
-
- case CASE(TINT64, TINT32): // truncate
- case CASE(TUINT64, TINT32):
- case CASE(TINT64, TUINT32):
- case CASE(TUINT64, TUINT32):
- split64(f, &flo, &fhi);
- regalloc(&r1, t->type, N);
- gins(AMOVW, &flo, &r1);
- gins(AMOVW, &r1, t);
- regfree(&r1);
- splitclean();
- return;
-
- case CASE(TINT64, TINT64): // same size
- case CASE(TINT64, TUINT64):
- case CASE(TUINT64, TINT64):
- case CASE(TUINT64, TUINT64):
- split64(f, &flo, &fhi);
- split64(t, &tlo, &thi);
- regalloc(&r1, flo.type, N);
- regalloc(&r2, fhi.type, N);
- gins(AMOVW, &flo, &r1);
- gins(AMOVW, &fhi, &r2);
- gins(AMOVW, &r1, &tlo);
- gins(AMOVW, &r2, &thi);
- regfree(&r1);
- regfree(&r2);
- splitclean();
- splitclean();
- return;
-
- /*
- * integer up-conversions
- */
- case CASE(TINT8, TINT16): // sign extend int8
- case CASE(TINT8, TUINT16):
- case CASE(TINT8, TINT32):
- case CASE(TINT8, TUINT32):
- a = AMOVB;
- goto rdst;
- case CASE(TINT8, TINT64): // convert via int32
- case CASE(TINT8, TUINT64):
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT8, TINT16): // zero extend uint8
- case CASE(TUINT8, TUINT16):
- case CASE(TUINT8, TINT32):
- case CASE(TUINT8, TUINT32):
- a = AMOVBU;
- goto rdst;
- case CASE(TUINT8, TINT64): // convert via uint32
- case CASE(TUINT8, TUINT64):
- cvt = types[TUINT32];
- goto hard;
-
- case CASE(TINT16, TINT32): // sign extend int16
- case CASE(TINT16, TUINT32):
- a = AMOVH;
- goto rdst;
- case CASE(TINT16, TINT64): // convert via int32
- case CASE(TINT16, TUINT64):
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT16, TINT32): // zero extend uint16
- case CASE(TUINT16, TUINT32):
- a = AMOVHU;
- goto rdst;
- case CASE(TUINT16, TINT64): // convert via uint32
- case CASE(TUINT16, TUINT64):
- cvt = types[TUINT32];
- goto hard;
-
- case CASE(TINT32, TINT64): // sign extend int32
- case CASE(TINT32, TUINT64):
- split64(t, &tlo, &thi);
- regalloc(&r1, tlo.type, N);
- regalloc(&r2, thi.type, N);
- gmove(f, &r1);
- p1 = gins(AMOVW, &r1, &r2);
- p1->from.type = D_SHIFT;
- p1->from.offset = 2 << 5 | 31 << 7 | r1.val.u.reg; // r1->31
- p1->from.reg = NREG;
-//print("gmove: %P\n", p1);
- gins(AMOVW, &r1, &tlo);
- gins(AMOVW, &r2, &thi);
- regfree(&r1);
- regfree(&r2);
- splitclean();
- return;
-
- case CASE(TUINT32, TINT64): // zero extend uint32
- case CASE(TUINT32, TUINT64):
- split64(t, &tlo, &thi);
- gmove(f, &tlo);
- regalloc(&r1, thi.type, N);
- gins(AMOVW, ncon(0), &r1);
- gins(AMOVW, &r1, &thi);
- regfree(&r1);
- splitclean();
- return;
-
- /*
- * float to integer
- */
- case CASE(TFLOAT32, TINT8):
- case CASE(TFLOAT32, TUINT8):
- case CASE(TFLOAT32, TINT16):
- case CASE(TFLOAT32, TUINT16):
- case CASE(TFLOAT32, TINT32):
- case CASE(TFLOAT32, TUINT32):
-// case CASE(TFLOAT32, TUINT64):
-
- case CASE(TFLOAT64, TINT8):
- case CASE(TFLOAT64, TUINT8):
- case CASE(TFLOAT64, TINT16):
- case CASE(TFLOAT64, TUINT16):
- case CASE(TFLOAT64, TINT32):
- case CASE(TFLOAT64, TUINT32):
-// case CASE(TFLOAT64, TUINT64):
- fa = AMOVF;
- a = AMOVFW;
- if(ft == TFLOAT64) {
- fa = AMOVD;
- a = AMOVDW;
- }
- ta = AMOVW;
- switch(tt) {
- case TINT8:
- ta = AMOVB;
- break;
- case TUINT8:
- ta = AMOVBU;
- break;
- case TINT16:
- ta = AMOVH;
- break;
- case TUINT16:
- ta = AMOVHU;
- break;
- }
-
- regalloc(&r1, types[ft], f);
- regalloc(&r2, types[tt], t);
- gins(fa, f, &r1); // load to fpu
- p1 = gins(a, &r1, &r1); // convert to w
- switch(tt) {
- case TUINT8:
- case TUINT16:
- case TUINT32:
- p1->scond |= C_UBIT;
- }
- gins(AMOVW, &r1, &r2); // copy to cpu
- gins(ta, &r2, t); // store
- regfree(&r1);
- regfree(&r2);
- return;
-
- /*
- * integer to float
- */
- case CASE(TINT8, TFLOAT32):
- case CASE(TUINT8, TFLOAT32):
- case CASE(TINT16, TFLOAT32):
- case CASE(TUINT16, TFLOAT32):
- case CASE(TINT32, TFLOAT32):
- case CASE(TUINT32, TFLOAT32):
- case CASE(TINT8, TFLOAT64):
- case CASE(TUINT8, TFLOAT64):
- case CASE(TINT16, TFLOAT64):
- case CASE(TUINT16, TFLOAT64):
- case CASE(TINT32, TFLOAT64):
- case CASE(TUINT32, TFLOAT64):
- fa = AMOVW;
- switch(ft) {
- case TINT8:
- fa = AMOVB;
- break;
- case TUINT8:
- fa = AMOVBU;
- break;
- case TINT16:
- fa = AMOVH;
- break;
- case TUINT16:
- fa = AMOVHU;
- break;
- }
- a = AMOVWF;
- ta = AMOVF;
- if(tt == TFLOAT64) {
- a = AMOVWD;
- ta = AMOVD;
- }
- regalloc(&r1, types[ft], f);
- regalloc(&r2, types[tt], t);
- gins(fa, f, &r1); // load to cpu
- gins(AMOVW, &r1, &r2); // copy to fpu
- p1 = gins(a, &r2, &r2); // convert
- switch(ft) {
- case TUINT8:
- case TUINT16:
- case TUINT32:
- p1->scond |= C_UBIT;
- }
- gins(ta, &r2, t); // store
- regfree(&r1);
- regfree(&r2);
- return;
-
- case CASE(TUINT64, TFLOAT32):
- case CASE(TUINT64, TFLOAT64):
- fatal("gmove UINT64, TFLOAT not implemented");
- return;
-
-
- /*
- * float to float
- */
- case CASE(TFLOAT32, TFLOAT32):
- a = AMOVF;
- break;
-
- case CASE(TFLOAT64, TFLOAT64):
- a = AMOVD;
- break;
-
- case CASE(TFLOAT32, TFLOAT64):
- regalloc(&r1, types[TFLOAT64], t);
- gins(AMOVF, f, &r1);
- gins(AMOVFD, &r1, &r1);
- gins(AMOVD, &r1, t);
- regfree(&r1);
- return;
-
- case CASE(TFLOAT64, TFLOAT32):
- regalloc(&r1, types[TFLOAT64], t);
- gins(AMOVD, f, &r1);
- gins(AMOVDF, &r1, &r1);
- gins(AMOVF, &r1, t);
- regfree(&r1);
- return;
- }
-
- gins(a, f, t);
- return;
-
-rdst:
- // TODO(kaib): we almost always require a register dest anyway, this can probably be
- // removed.
- // 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;
-
-trunc64:
- // truncate 64 bit integer
- split64(f, &flo, &fhi);
- regalloc(&r1, t->type, N);
- gins(a, &flo, &r1);
- gins(a, &r1, t);
- regfree(&r1);
- splitclean();
- return;
-
-fatal:
- // should not happen
- fatal("gmove %N -> %N", f, t);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
- if(f->op != t->op)
- return 0;
-
- switch(f->op) {
- case OREGISTER:
- if(f->val.u.reg != t->val.u.reg)
- break;
- return 1;
- }
- return 0;
-}
-
-/*
- * generate one instruction:
- * as f, t
- */
-Prog*
-gins(int as, Node *f, Node *t)
-{
-// Node nod;
-// int32 v;
- Prog *p;
- Addr af, at;
-
- if(f != N && f->op == OINDEX) {
- fatal("gins OINDEX not implemented");
-// regalloc(&nod, &regnode, Z);
-// v = constnode.vconst;
-// cgen(f->right, &nod);
-// constnode.vconst = v;
-// idx.reg = nod.reg;
-// regfree(&nod);
- }
- if(t != N && t->op == OINDEX) {
- fatal("gins OINDEX not implemented");
-// regalloc(&nod, &regnode, Z);
-// v = constnode.vconst;
-// cgen(t->right, &nod);
-// constnode.vconst = v;
-// idx.reg = nod.reg;
-// regfree(&nod);
- }
-
- 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(debug['g'])
- print("%P\n", p);
- return p;
-}
-
-/*
- * insert n into reg slot of p
- */
-void
-raddr(Node *n, Prog *p)
-{
- Addr a;
-
- naddr(n, &a, 1);
- if(a.type != D_REG && a.type != D_FREG) {
- if(n)
- fatal("bad in raddr: %O", n->op);
- else
- fatal("bad in raddr: <null>");
- p->reg = NREG;
- } else
- p->reg = a.reg;
-}
-
-/* generate a comparison
-TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
- */
-Prog*
-gcmp(int as, Node *lhs, Node *rhs)
-{
- Prog *p;
-
- if(lhs->op != OREGISTER || rhs->op != OREGISTER)
- fatal("bad operands to gcmp: %O %O", lhs->op, rhs->op);
-
- p = gins(as, rhs, N);
- raddr(lhs, p);
- return p;
-}
-
-/* generate a constant shift
- * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal.
-*/
-Prog*
-gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs)
-{
- Prog *p;
-
- if(sval <= 0 || sval > 32)
- fatal("bad shift value: %d", sval);
-
- sval = sval&0x1f;
-
- p = gins(as, N, rhs);
- p->from.type = D_SHIFT;
- p->from.offset = stype | sval<<7 | lhs->val.u.reg;
- return p;
-}
-
-/* generate a register shift
-*/
-Prog *
-gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
-{
- Prog *p;
- p = gins(as, N, rhs);
- p->from.type = D_SHIFT;
- p->from.offset = stype | reg->val.u.reg << 8 | 1<<4 | lhs->val.u.reg;
- return p;
-}
-
-static void
-checkoffset(Addr *a, int canemitcode)
-{
- Prog *p;
- Node n1;
-
- if(a->offset < unmappedzero)
- return;
- if(!canemitcode)
- fatal("checkoffset %#x, cannot emit code", a->offset);
-
- // cannot rely on unmapped nil page at 0 to catch
- // reference with large offset. instead, emit explicit
- // test of 0(reg).
- regalloc(&n1, types[TUINTPTR], N);
- p = gins(AMOVW, N, &n1);
- p->from = *a;
- p->from.offset = 0;
- regfree(&n1);
-}
-
-/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
- a->type = D_NONE;
- a->name = D_NONE;
- a->reg = NREG;
- a->node = N;
- if(n == N)
- return;
-
- switch(n->op) {
- default:
- fatal("naddr: bad %O %D", n->op, a);
- break;
-
- case OREGISTER:
- if(n->val.u.reg <= REGALLOC_RMAX) {
- a->type = D_REG;
- a->reg = n->val.u.reg;
- } else {
- a->type = D_FREG;
- a->reg = n->val.u.reg - REGALLOC_F0;
- }
- a->sym = S;
- break;
-
- case OINDEX:
- case OIND:
- fatal("naddr: OINDEX");
-// naddr(n->left, a);
-// if(a->type >= D_AX && a->type <= D_DI)
-// a->type += D_INDIR;
-// else
-// if(a->type == D_CONST)
-// a->type = D_NONE+D_INDIR;
-// else
-// if(a->type == D_ADDR) {
-// a->type = a->index;
-// a->index = D_NONE;
-// } else
-// goto bad;
-// if(n->op == OINDEX) {
-// a->index = idx.reg;
-// a->scale = n->scale;
-// }
-// break;
-
- case OINDREG:
- a->type = D_OREG;
- a->reg = n->val.u.reg;
- a->sym = n->sym;
- a->offset = n->xoffset;
- checkoffset(a, canemitcode);
- 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 = n->left->sym;
- a->type = D_OREG;
- a->name = D_PARAM;
- break;
-
- case ONAME:
- a->etype = 0;
- a->width = 0;
- a->reg = NREG;
- if(n->type != T) {
- a->etype = simtype[n->type->etype];
- a->width = n->type->width;
- }
- a->pun = n->pun;
- a->offset = n->xoffset;
- a->sym = n->sym;
- if(a->sym == S)
- a->sym = lookup(".noname");
- if(n->method) {
- if(n->type != T)
- if(n->type->sym != S)
- if(n->type->sym->pkg != nil)
- a->sym = pkglookup(a->sym->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;
- if (n->sym)
- a->node = n->orig;
- break;
- case PPARAM:
- case PPARAMOUT:
- a->name = D_PARAM;
- break;
- case PFUNC:
- a->name = D_EXTERN;
- a->type = D_CONST;
- break;
- }
- break;
-
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- fatal("naddr: const %lT", n->type);
- break;
- case CTFLT:
- a->type = D_FCONST;
- a->dval = mpgetflt(n->val.u.fval);
- break;
- case CTINT:
- a->sym = S;
- 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 = S;
- a->type = D_CONST;
- a->offset = n->val.u.bval;
- break;
- case CTNIL:
- a->sym = S;
- a->type = D_CONST;
- a->offset = 0;
- break;
- }
- break;
-
- case OLEN:
- // len of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == D_CONST && a->offset == 0)
- break; // len(nil)
- a->offset += Array_nel;
- if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
- checkoffset(a, canemitcode);
- break;
-
- case OCAP:
- // cap of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == D_CONST && a->offset == 0)
- break; // cap(nil)
- a->offset += Array_cap;
- if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero)
- checkoffset(a, canemitcode);
- break;
-
- case OADDR:
- naddr(n->left, a, canemitcode);
- 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);
- }
- }
-}
-
-/*
- * 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 %O-%T etype %T simtype %T", op, t, types[t->etype], types[simtype[t->etype]]);
- break;
-
-/* case CASE(OADDR, TPTR32):
- a = ALEAL;
- break;
-
- case CASE(OADDR, TPTR64):
- a = ALEAQ;
- break;
-*/
- // TODO(kaib): make sure the conditional branches work on all edge cases
- 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):
- case CASE(OLT, TINT16):
- case CASE(OLT, TINT32):
- case CASE(OLT, TINT64):
- case CASE(OLT, TFLOAT32):
- case CASE(OLT, TFLOAT64):
- a = ABLT;
- break;
-
- case CASE(OLT, TUINT8):
- case CASE(OLT, TUINT16):
- case CASE(OLT, TUINT32):
- case CASE(OLT, TUINT64):
- a = ABLO;
- break;
-
- case CASE(OLE, TINT8):
- case CASE(OLE, TINT16):
- case CASE(OLE, TINT32):
- case CASE(OLE, TINT64):
- case CASE(OLE, TFLOAT32):
- case CASE(OLE, TFLOAT64):
- a = ABLE;
- break;
-
- case CASE(OLE, TUINT8):
- case CASE(OLE, TUINT16):
- case CASE(OLE, TUINT32):
- case CASE(OLE, TUINT64):
- a = ABLS;
- break;
-
- case CASE(OGT, TINT8):
- case CASE(OGT, TINT16):
- case CASE(OGT, TINT32):
- case CASE(OGT, TINT64):
- case CASE(OGT, TFLOAT32):
- case CASE(OGT, TFLOAT64):
- a = ABGT;
- break;
-
- case CASE(OGT, TUINT8):
- case CASE(OGT, TUINT16):
- case CASE(OGT, TUINT32):
- case CASE(OGT, TUINT64):
- a = ABHI;
- break;
-
- case CASE(OGE, TINT8):
- case CASE(OGE, TINT16):
- case CASE(OGE, TINT32):
- case CASE(OGE, TINT64):
- case CASE(OGE, TFLOAT32):
- case CASE(OGE, TFLOAT64):
- a = ABGE;
- break;
-
- case CASE(OGE, TUINT8):
- case CASE(OGE, TUINT16):
- case CASE(OGE, TUINT32):
- case CASE(OGE, TUINT64):
- a = ABHS;
- break;
-
- case CASE(OCMP, TBOOL):
- case CASE(OCMP, TINT8):
- case CASE(OCMP, TUINT8):
- case CASE(OCMP, TINT16):
- case CASE(OCMP, TUINT16):
- case CASE(OCMP, TINT32):
- case CASE(OCMP, TUINT32):
- case CASE(OCMP, TPTR32):
- a = ACMP;
- break;
-
- case CASE(OCMP, TFLOAT32):
- a = ACMPF;
- break;
-
- case CASE(OCMP, TFLOAT64):
- a = ACMPD;
- break;
-
- case CASE(OAS, TBOOL):
- case CASE(OAS, TINT8):
- a = AMOVB;
- break;
-
- case CASE(OAS, TUINT8):
- a = AMOVBU;
- break;
-
- case CASE(OAS, TINT16):
- a = AMOVH;
- break;
-
- case CASE(OAS, TUINT16):
- a = AMOVHU;
- break;
-
- case CASE(OAS, TINT32):
- case CASE(OAS, TUINT32):
- case CASE(OAS, TPTR32):
- a = AMOVW;
- break;
-
- case CASE(OAS, TFLOAT32):
- a = AMOVF;
- break;
-
- case CASE(OAS, TFLOAT64):
- a = AMOVD;
- 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):
- a = AADD;
- break;
-
- case CASE(OADD, TFLOAT32):
- a = AADDF;
- break;
-
- case CASE(OADD, TFLOAT64):
- a = AADDD;
- 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):
- a = ASUB;
- break;
-
- case CASE(OSUB, TFLOAT32):
- a = ASUBF;
- break;
-
- case CASE(OSUB, TFLOAT64):
- a = ASUBD;
- 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):
- 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):
- a = AORR;
- 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):
- a = AEOR;
- 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):
- a = ASLL;
- break;
-
- case CASE(ORSH, TUINT8):
- case CASE(ORSH, TUINT16):
- case CASE(ORSH, TUINT32):
- case CASE(ORSH, TPTR32):
- a = ASRL;
- break;
-
- case CASE(ORSH, TINT8):
- case CASE(ORSH, TINT16):
- case CASE(ORSH, TINT32):
- a = ASRA;
- break;
-
- case CASE(OMUL, TUINT8):
- case CASE(OMUL, TUINT16):
- case CASE(OMUL, TUINT32):
- case CASE(OMUL, TPTR32):
- a = AMULU;
- break;
-
- case CASE(OMUL, TINT8):
- case CASE(OMUL, TINT16):
- case CASE(OMUL, TINT32):
- a = AMUL;
- break;
-
- case CASE(OMUL, TFLOAT32):
- a = AMULF;
- break;
-
- case CASE(OMUL, TFLOAT64):
- a = AMULD;
- break;
-
- case CASE(ODIV, TUINT8):
- case CASE(ODIV, TUINT16):
- case CASE(ODIV, TUINT32):
- case CASE(ODIV, TPTR32):
- a = ADIVU;
- break;
-
- case CASE(ODIV, TINT8):
- case CASE(ODIV, TINT16):
- case CASE(ODIV, TINT32):
- a = ADIV;
- break;
-
- case CASE(OMOD, TUINT8):
- case CASE(OMOD, TUINT16):
- case CASE(OMOD, TUINT32):
- case CASE(OMOD, TPTR32):
- a = AMODU;
- break;
-
- case CASE(OMOD, TINT8):
- case CASE(OMOD, TINT16):
- case CASE(OMOD, TINT32):
- a = AMOD;
- break;
-
-// case CASE(OEXTEND, TINT16):
-// a = ACWD;
-// break;
-
-// case CASE(OEXTEND, TINT32):
-// a = ACDQ;
-// break;
-
-// case CASE(OEXTEND, TINT64):
-// a = ACQO;
-// break;
-
- case CASE(ODIV, TFLOAT32):
- a = ADIVF;
- break;
-
- case CASE(ODIV, TFLOAT64):
- a = ADIVD;
- break;
-
- }
- return a;
-}
-
-enum
-{
- ODynam = 1<<0,
- OPtrto = 1<<1,
-};
-
-static Node clean[20];
-static int cleani = 0;
-
-void
-sudoclean(void)
-{
- if(clean[cleani-1].op != OEMPTY)
- regfree(&clean[cleani-1]);
- if(clean[cleani-2].op != OEMPTY)
- regfree(&clean[cleani-2]);
- cleani -= 2;
-}
-
-int
-dotaddable(Node *n, Node *n1)
-{
- int o, oary[10];
- Node *nn;
-
- if(n->op != ODOT)
- return 0;
-
- o = dotoffset(n, oary, &nn);
- if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
- *n1 = *nn;
- n1->type = n->type;
- n1->xoffset += oary[0];
- return 1;
- }
- return 0;
-}
-
-/*
- * 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, int *w)
-{
- int o, i;
- int oary[10];
- int64 v;
- Node n1, n2, n3, n4, *nn, *l, *r;
- Node *reg, *reg1;
- Prog *p1, *p2;
- Type *t;
-
- if(n->type == T)
- return 0;
-
- switch(n->op) {
- case OLITERAL:
- if(n->val.ctype != CTINT)
- break;
- v = mpgetfix(n->val.u.xval);
- if(v >= 32000 || v <= -32000)
- break;
- goto lit;
-
- case ODOT:
- case ODOTPTR:
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
- goto odot;
-
- case OINDEX:
- if(n->left->type->etype == TSTRING)
- return 0;
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
- goto oindex;
- }
- return 0;
-
-lit:
- switch(as) {
- default:
- return 0;
- case AADD: case ASUB: case AAND: case AORR: case AEOR:
- case AMOVB: case AMOVBU: case AMOVH: case AMOVHU:
- case AMOVW:
- break;
- }
-
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
- naddr(n, a, 1);
- goto yes;
-
-odot:
- o = dotoffset(n, oary, &nn);
- if(nn == N)
- goto no;
-
- if(nn->addable && o == 1 && oary[0] >= 0) {
- // directly addressable set of DOTs
- n1 = *nn;
- n1.type = n->type;
- n1.xoffset += oary[0];
- naddr(&n1, a, 1);
- goto yes;
- }
-
- regalloc(reg, types[tptr], N);
- n1 = *reg;
- n1.op = OINDREG;
- if(oary[0] >= 0) {
- agen(nn, reg);
- n1.xoffset = oary[0];
- } else {
- cgen(nn, reg);
- n1.xoffset = -(oary[0]+1);
- }
-
- for(i=1; i<o; i++) {
- if(oary[i] >= 0)
- fatal("cant happen");
- gins(AMOVW, &n1, reg);
- n1.xoffset = -(oary[i]+1);
- }
-
- a->type = D_NONE;
- a->name = D_NONE;
- naddr(&n1, a, 1);
- goto yes;
-
-oindex:
- l = n->left;
- r = n->right;
- if(l->ullman >= UINF && r->ullman >= UINF)
- goto no;
-
- // set o to type of array
- o = 0;
- if(isptr[l->type->etype]) {
- o += OPtrto;
- if(l->type->type->etype != TARRAY)
- fatal("not ptr ary");
- if(l->type->type->bound < 0)
- o += ODynam;
- } else {
- if(l->type->etype != TARRAY)
- fatal("not ary");
- if(l->type->bound < 0)
- o += ODynam;
- }
-
- *w = n->type->width;
- if(isconst(r, CTINT))
- goto oindex_const;
-
- switch(*w) {
- default:
- goto no;
- case 1:
- case 2:
- case 4:
- case 8:
- break;
- }
-
- // load the array (reg)
- if(l->ullman > r->ullman) {
- regalloc(reg, types[tptr], N);
- if(o & OPtrto)
- cgen(l, reg);
- else
- agen(l, reg);
- }
-
- // load the index (reg1)
- t = types[TUINT32];
- if(issigned[r->type->etype])
- t = types[TINT32];
- regalloc(reg1, t, N);
- regalloc(&n3, types[TINT32], reg1);
- p2 = cgenindex(r, &n3);
- gmove(&n3, reg1);
- regfree(&n3);
-
- // load the array (reg)
- if(l->ullman <= r->ullman) {
- regalloc(reg, types[tptr], N);
- if(o & OPtrto)
- cgen(l, reg);
- else
- agen(l, reg);
- }
-
- // check bounds
- if(!debug['B']) {
- if(o & ODynam) {
- n2 = *reg;
- n2.op = OINDREG;
- n2.type = types[tptr];
- n2.xoffset = Array_nel;
- } else {
- if(l->type->width >= unmappedzero && l->op == OIND) {
- // cannot rely on page protections to
- // catch array ptr == 0, so dereference.
- n2 = *reg;
- n2.op = OINDREG;
- n2.type = types[TUINTPTR];
- n2.xoffset = 0;
- regalloc(&n3, n2.type, N);
- gins(AMOVW, &n2, &n3);
- regfree(&n3);
- }
- nodconst(&n2, types[TUINT32], l->type->bound);
- if(o & OPtrto)
- nodconst(&n2, types[TUINT32], l->type->type->bound);
- }
- regalloc(&n3, n2.type, N);
- cgen(&n2, &n3);
- gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3);
- regfree(&n3);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
- if(p2)
- patch(p2, pc);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- if(o & ODynam) {
- n2 = *reg;
- n2.op = OINDREG;
- n2.type = types[tptr];
- n2.xoffset = Array_array;
- gmove(&n2, reg);
- }
-
- switch(*w) {
- case 1:
- gins(AADD, reg1, reg);
- break;
- case 2:
- gshift(AADD, reg1, SHIFT_LL, 1, reg);
- break;
- case 4:
- gshift(AADD, reg1, SHIFT_LL, 2, reg);
- break;
- case 8:
- gshift(AADD, reg1, SHIFT_LL, 3, reg);
- break;
- }
-
- naddr(reg1, a, 1);
- a->type = D_OREG;
- a->reg = reg->val.u.reg;
- a->offset = 0;
-
- goto yes;
-
-oindex_const:
- // index is constant
- // can check statically and
- // can multiply by width statically
-
- regalloc(reg, types[tptr], N);
- if(o & OPtrto)
- cgen(l, reg);
- else
- agen(l, reg);
-
- v = mpgetfix(r->val.u.xval);
- if(o & ODynam) {
-
- if(!debug['B'] && !n->etype) {
- n1 = *reg;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- nodconst(&n2, types[TUINT32], v);
- regalloc(&n3, types[TUINT32], N);
- cgen(&n2, &n3);
- regalloc(&n4, n1.type, N);
- cgen(&n1, &n4);
- gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3);
- regfree(&n4);
- regfree(&n3);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- n1 = *reg;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, reg);
- }
-
- n2 = *reg;
- n2.op = OINDREG;
- n2.xoffset = v * (*w);
- a->type = D_NONE;
- a->name = D_NONE;
- naddr(&n2, a, 1);
- goto yes;
-
-yes:
- return 1;
-
-no:
- sudoclean();
- return 0;
-}
diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c
deleted file mode 100644
index 0c6dbbf71..000000000
--- a/src/cmd/5g/list.c
+++ /dev/null
@@ -1,331 +0,0 @@
-// Derived from Inferno utils/5c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/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.
-
-#include "gg.h"
-
-// TODO(kaib): make 5g/list.c congruent with 5l/list.c
-
-static int sconsize;
-void
-listinit(void)
-{
-
- fmtinstall('A', Aconv); // as
- fmtinstall('C', Cconv); // conditional execution bit
- fmtinstall('P', Pconv); // Prog*
- fmtinstall('D', Dconv); // Addr*
- fmtinstall('Y', Yconv); // sconst
- fmtinstall('R', Rconv); // register
- fmtinstall('M', Mconv); // names
-}
-
-int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ], str1[STRINGSZ];
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- sconsize = 8;
- switch(p->as) {
- default:
- snprint(str1, sizeof(str1), "%A%C", p->as, p->scond);
- if(p->reg == NREG)
- snprint(str, sizeof(str), "%.4d (%L) %-7s %D,%D",
- p->loc, p->lineno, str1, &p->from, &p->to);
- else
- if (p->from.type != D_FREG) {
- snprint(str, sizeof(str), "%.4d (%L) %-7s %D,R%d,%D",
- p->loc, p->lineno, str1, &p->from, p->reg, &p->to);
- } else
- snprint(str, sizeof(str), "%.4d (%L) %-7A%C %D,F%d,%D",
- p->loc, p->lineno, p->as, p->scond, &p->from, p->reg, &p->to);
- break;
-
- case ADATA:
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
- p->loc, p->lineno, p->as, &p->from, p->reg, &p->to);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ];
- char *op;
- Addr *a;
- int i;
- int32 v;
-
- a = va_arg(fp->args, Addr*);
- if(a == A) {
- sprint(str, "<nil>");
- goto conv;
- }
- i = a->type;
- switch(i) {
-
- default:
- sprint(str, "GOK-type(%d)", a->type);
- break;
-
- case D_NONE:
- str[0] = 0;
- if(a->name != D_NONE || a->reg != NREG || a->sym != S)
- sprint(str, "%M(R%d)(NONE)", a, a->reg);
- break;
-
- case D_CONST:
- if(a->reg != NREG)
- sprint(str, "$%M(R%d)", a, a->reg);
- else
- sprint(str, "$%M", a);
- break;
-
- case D_CONST2:
- sprint(str, "$%d-%d", a->offset, a->offset2);
- break;
-
- case D_SHIFT:
- v = a->offset;
- op = "<<>>->@>" + (((v>>5) & 3) << 1);
- if(v & (1<<4))
- sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
- else
- sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
- if(a->reg != NREG)
- sprint(str+strlen(str), "(R%d)", a->reg);
- break;
-
- case D_OCONST:
- sprint(str, "$*$%M", a);
- if(a->reg != NREG)
- sprint(str, "%M(R%d)(CONST)", a, a->reg);
- 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 != S)
- sprint(str, "%M(R%d)(REG)", a, a->reg);
- break;
-
- case D_REGREG:
- sprint(str, "(R%d,R%d)", a->reg, (int)a->offset);
- if(a->name != D_NONE || a->sym != S)
- 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 != S)
- sprint(str, "%M(R%d)(REG)", a, a->reg);
- break;
-
- case D_BRANCH:
- if(a->branch == P || a->branch->loc == 0) {
- if(a->sym != S)
- sprint(str, "%s+%d(APC)", a->sym->name, a->offset);
- else
- sprint(str, "%d(APC)", a->offset);
- } else
- if(a->sym != S)
- sprint(str, "%s+%d(APC)", a->sym->name, a->branch->loc);
- else
- sprint(str, "%d(APC)", a->branch->loc);
- break;
-
- case D_FCONST:
- snprint(str, sizeof(str), "$(%.17e)", a->dval);
- break;
-
- case D_SCONST:
- snprint(str, sizeof(str), "$\"%Y\"", a->sval);
- break;
-
- // TODO(kaib): Add back
-// case D_ADDR:
-// a->type = a->index;
-// a->index = D_NONE;
-// snprint(str, sizeof(str), "$%D", a);
-// a->index = a->type;
-// a->type = D_ADDR;
-// goto conv;
- }
-conv:
- return fmtstrcpy(fp, str);
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-char* strcond[16] =
-{
- ".EQ",
- ".NE",
- ".HS",
- ".LO",
- ".MI",
- ".PL",
- ".VS",
- ".VC",
- ".HI",
- ".LS",
- ".GE",
- ".LT",
- ".GT",
- ".LE",
- "",
- ".NV"
-};
-
-int
-Cconv(Fmt *fp)
-{
- char s[STRINGSZ];
- int c;
-
- c = va_arg(fp->args, int);
- strcpy(s, strcond[c & C_SCOND]);
- if(c & C_SBIT)
- strcat(s, ".S");
- if(c & C_PBIT)
- strcat(s, ".P");
- if(c & C_WBIT)
- strcat(s, ".W");
- if(c & C_UBIT) /* ambiguous with FBIT */
- strcat(s, ".U");
- return fmtstrcpy(fp, s);
-}
-
-int
-Yconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sconsize; i++) {
- c = a[i] & 0xff;
- if((c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9')) {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- 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);
-}
-
-int
-Rconv(Fmt *fp)
-{
- int r;
- char str[STRINGSZ];
-
- r = va_arg(fp->args, int);
- snprint(str, sizeof(str), "R%d", r);
- return fmtstrcpy(fp, str);
-}
-
-int
-Mconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Addr *a;
-
- a = va_arg(fp->args, Addr*);
- switch(a->name) {
- default:
- snprint(str, sizeof(str), "GOK-name(%d)", a->name);
- break;
-
- case D_NONE:
- snprint(str, sizeof(str), "%d", a->offset);
- break;
-
- case D_EXTERN:
- snprint(str, sizeof(str), "%S+%d(SB)", a->sym, a->offset);
- break;
-
- case D_STATIC:
- snprint(str, sizeof(str), "%S<>+%d(SB)", a->sym, a->offset);
- break;
-
- case D_AUTO:
- snprint(str, sizeof(str), "%S+%d(SP)", a->sym, a->offset);
- break;
-
- case D_PARAM:
- snprint(str, sizeof(str), "%S+%d(FP)", a->sym, a->offset);
- break;
- }
- return fmtstrcpy(fp, str);
-}
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
deleted file mode 100644
index 7a0070fc9..000000000
--- a/src/cmd/5g/opt.h
+++ /dev/null
@@ -1,165 +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.
-
-#define Z N
-#define Adr Addr
-
-#define D_HI D_NONE
-#define D_LO D_NONE
-
-#define isregtype(t) ((t)>= D_AX && (t)<=D_R15)
-
-#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;
-
-struct Reg
-{
-
- Bits set;
- Bits use1;
- Bits use2;
-
- Bits refbehind;
- Bits refahead;
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- int32 regu; // register used bitmap
- int32 rpo; // reverse post ordering
- int32 active;
-
- uint16 loop; // x5 for every loop
- uchar refset; // diagnostic generated
-
- 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 exregoffset; // not set
-EXTERN int32 exfregoffset; // not set
-EXTERN Reg* firstr;
-EXTERN Reg* lastr;
-EXTERN Reg zreg;
-EXTERN Reg* freer;
-EXTERN Reg** rpo2r;
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-EXTERN int32 regbits;
-EXTERN int32 exregbits;
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-EXTERN Bits ovar;
-EXTERN int change;
-EXTERN int32 maxnr;
-EXTERN int32* idom;
-
-EXTERN struct
-{
- int32 ncvtreg;
- int32 nspill;
- int32 nreload;
- int32 ndelmov;
- int32 nvar;
- int32 naddr;
-} ostats;
-
-/*
- * reg.c
- */
-Reg* rega(void);
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Reg *r, Adr *a);
-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(Adr*, int);
-void dumpit(char *str, Reg *r0);
-int noreturn(Prog *p);
-
-/*
- * peep.c
- */
-void peep(void);
-void excise(Reg*);
-Reg* uniqp(Reg*);
-Reg* uniqs(Reg*);
-int regtyp(Adr*);
-int anyvar(Adr*);
-int subprop(Reg*);
-int copyprop(Reg*);
-int copy1(Adr*, Adr*, Reg*, int);
-int copyu(Prog*, Adr*, Adr*);
-
-int copyas(Adr*, Adr*);
-int copyau(Adr*, Adr*);
-int copysub(Adr*, Adr*, Adr*, int);
-int copysub1(Prog*, Adr*, Adr*, int);
-
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
deleted file mode 100644
index 6f36e12d4..000000000
--- a/src/cmd/5g/peep.c
+++ /dev/null
@@ -1,1518 +0,0 @@
-// Inferno utils/5c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5g/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 "gg.h"
-#include "opt.h"
-
-int xtramodes(Reg*, Adr*);
-int shiftprop(Reg *r);
-void constprop(Adr *c1, Adr *v1, Reg *r);
-void predicate(void);
-int copyau1(Prog *p, Adr *v);
-int isdconst(Addr *a);
-
-void
-peep(void)
-{
- Reg *r, *r1, *r2;
- Prog *p, *p1;
- int t;
-/*
- * complete R structure
- */
- 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;
-
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- p = p->link;
- }
- }
-//dumpit("begin", firstr);
-
-loop1:
-
- t = 0;
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case ASLL:
- case ASRL:
- case ASRA:
- /*
- * elide shift into D_SHIFT operand of subsequent instruction
- */
-// if(shiftprop(r)) {
-// excise(r);
-// t++;
-// break;
-// }
- break;
-
- case AMOVW:
- case AMOVF:
- case AMOVD:
- if(regtyp(&p->from))
- if(p->from.type == p->to.type)
- if(p->scond == C_SCOND_NONE) {
- if(copyprop(r)) {
- excise(r);
- t++;
- break;
- }
- if(subprop(r) && copyprop(r)) {
- excise(r);
- t++;
- break;
- }
- }
- break;
-
- if(p->scond == C_SCOND_NONE)
- if(regtyp(&p->to))
- if(isdconst(&p->from)) {
- constprop(&p->from, &p->to, r->s1);
- }
- break;
- }
- }
- if(t)
- goto loop1;
-
-return;
-
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
-// case AEOR:
-// /*
-// * EOR -1,x,y => MVN x,y
-// */
-// if(isdconst(&p->from) && 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;
-// }
-// break;
-
- case AMOVH:
- case AMOVHU:
- case AMOVB:
- case AMOVBU:
- /*
- * look for MOVB x,R; MOVB R,R
- */
- if(p->to.type != D_REG)
- break;
- if(r1 == R)
- break;
- p1 = r1->prog;
- if(p1->as != p->as)
- break;
- if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
- break;
- if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
- break;
- excise(r1);
- break;
- }
- r1 = r->link;
- }
-
-// for(r=firstr; r!=R; r=r->link) {
-// p = r->prog;
-// switch(p->as) {
-// case AMOVW:
-// case AMOVB:
-// 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(isdconst(&p->from) || 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();
-}
-
-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(Adr *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;
- Adr *v1, *v2;
- Reg *r;
- int t;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case ABL:
- return 0;
-
- case AMULLU:
- case AMULA:
- case AMVN:
- return 0;
-
- case ACMN:
- case AADD:
- case ASUB:
- case ASBC:
- case ARSB:
- case ASLL:
- case ASRL:
- case ASRA:
- case AORR:
- case AAND:
- case AEOR:
- case AMUL:
- case AMULU:
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
-
- 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->scond == C_SCOND_NONE) {
- 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)
- if(p->scond == C_SCOND_NONE)
- 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;
- Adr *v1, *v2;
- Reg *r;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Adr *v1, Adr *v2, Reg *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, A);
- switch(t) {
- case 2: /* rar, cant split */
- if(debug['P'])
- print("; %Drar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %Dset; return 1\n", v2);
- return 1;
-
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %Dused+set and f=%d; return 0\n", v2, f);
- else
- print("; %Dused and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub%D/%D", v2, v1);
- if(t == 4) {
- if(debug['P'])
- print("; %Dused+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, A);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %Dset and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
-}
-
-/*
- * 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(Adr *c1, Adr *v1, Reg *r)
-{
- Prog *p;
-
- if(debug['P'])
- print("constprop %D->%D\n", c1, v1);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(uniqp(r) == R) {
- if(debug['P'])
- print("; merge; return\n");
- return;
- }
- if(p->as == AMOVW && copyas(&p->from, c1)) {
- if(debug['P'])
- print("; sub%D/%D", &p->from, v1);
- p->from = *v1;
- } else if(copyu(p, v1, A) > 1) {
- if(debug['P'])
- print("; %Dset; return\n", v1);
- return;
- }
- if(debug['P'])
- 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['P']) print("\t%s; FAILURE\n", msg); return 0; }
-int
-shiftprop(Reg *r)
-{
- Reg *r1;
- Prog *p, *p1, *p2;
- int n, o;
- Adr 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['P'])
- 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['P'])
- 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 ASBC:
- case ARSB:
- case ARSC:
- if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
- if(p1->from.type != D_REG)
- 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['P'])
- print("\t=>%P", p1);
- }
- case ABIC:
- case ATST:
- 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['P'])
- 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['P'])
- print("\t=>%P\tSUCCEED\n", p2);
- return 1;
-}
-
-Reg*
-findpre(Reg *r, Adr *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, Adr *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(isdconst(&p->from))
- if(p->from.offset > -4096 && p->from.offset < 4096)
- return r1;
- default:
- return R;
- }
- }
- return R;
-}
-
-int
-nochange(Reg *r, Reg *r2, Prog *p)
-{
- Adr 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, Adr *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, Adr *v)
-{
- Reg *r1;
-
- for(r1=firstr; r1!=R; r1=r1->link)
- r1->active = 0;
- return findu1(r, v);
-}
-
-int
-xtramodes(Reg *r, Adr *a)
-{
- Reg *r1, *r2, *r3;
- Prog *p, *p1;
- Adr v;
-
- p = r->prog;
- if(debug['h'] && p->as == AMOVB && 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 || (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 */
- a->type = D_SHIFT;
- a->offset = p1->from.reg;
- break;
- case D_SHIFT:
- /* scaled register offset */
- 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, Adr *v, Adr *s)
-{
-
- switch(p->as) {
-
- default:
- print("copyu: cant find %A\n", p->as);
- 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 AMOVHU:
- case AMOVB:
- case AMOVBU:
- case AMOVFW:
- case AMOVWF:
- 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 AMULLU: /* read, read, write, write */
- case AMULA:
- case AMVN:
- return 2;
-
- case AADD: /* read, read, write */
- case AADC:
- case ASUB:
- case ASBC:
- case ARSB:
- case ASLL:
- case ASRL:
- case ASRA:
- case AORR:
- case AAND:
- case AEOR:
- case AMUL:
- case AMULU:
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
-
- case ACMPF: /* read, read, */
- case ACMPD:
- case ACMP:
- case ACMN:
- case ACASE:
- case ATST: /* read,, */
- 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:
- 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 == (uchar)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 == (uchar)REGARG)
- return 3;
- return 0;
- }
- return 0;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-int
-copyas(Adr *a, Adr *v)
-{
-
- if(regtyp(v)) {
- if(a->type == v->type)
- if(a->reg == v->reg)
- return 1;
- } 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(Adr *a, Adr *v)
-{
-
- if(copyas(a, v))
- return 1;
- if(v->type == D_REG) {
- if(a->type == D_CONST && a->reg != NREG) {
- if(a->reg == v->reg)
- return 1;
- } else
- if(a->type == D_OREG) {
- if(a->reg == v->reg)
- return 1;
- } else
- if(a->type == D_REGREG) {
- if(a->reg == v->reg)
- return 1;
- if(a->offset == v->reg)
- return 1;
- } else
- if(a->type == D_SHIFT) {
- if((a->offset&0xf) == v->reg)
- return 1;
- if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * compare v to the center
- * register in p (p->reg)
- * the trick is that this
- * register might be D_REG
- * D_FREG. there are basically
- * two cases,
- * ADD r,r,r
- * CMP r,r,
- */
-int
-copyau1(Prog *p, Adr *v)
-{
-
- if(regtyp(v))
- if(p->reg == v->reg) {
- if(p->to.type != D_NONE) {
- if(v->type == p->to.type)
- return 1;
- return 0;
- }
- if(p->from.type != D_NONE) {
- if(v->type == p->from.type)
- return 1;
- return 0;
- }
- print("copyau1: cant tell %P\n", p);
- }
- return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-int
-copysub(Adr *a, Adr *v, Adr *s, int f)
-{
-
- if(f)
- if(copyau(a, v)) {
- 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
- if(a->type == D_REGREG) {
- if(a->offset == v->reg)
- a->offset = s->reg;
- if(a->reg == v->reg)
- a->reg = s->reg;
- } else
- a->reg = s->reg;
- }
- return 0;
-}
-
-int
-copysub1(Prog *p1, Adr *v, Adr *s, int f)
-{
-
- if(f)
- if(copyau1(p1, v))
- p1->reg = s->reg;
- return 0;
-}
-
-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)
-{
- switch(p->as) {
- case ANOP:
- case AXXX:
- case ADATA:
- case AGLOBL:
- case AGOK:
- case AHISTORY:
- case ANAME:
- case ASIGNAME:
- case ATEXT:
- case AWORD:
- case ABCASE:
- case ACASE:
- return 0;
- }
- if(isbranch(p))
- 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)
-{
- switch(p->as) {
- case AMULLU:
- case AMULA:
- case AMULU:
- case ADIVU:
-
- case ATEQ:
- case ACMN:
- case ATST:
- case ACMP:
- case AMUL:
- case ADIV:
- case AMOD:
- case AMODU:
- case ABL:
- return 1;
- }
- if(p->scond & C_SBIT)
- return 1;
- return 0;
-}
-
-/*
- * 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;
- }
- }
- }
-}
-
-int
-isdconst(Addr *a)
-{
- if(a->type == D_CONST && a->reg == NREG)
- return 1;
- return 0;
-}
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
deleted file mode 100644
index 77d0a87eb..000000000
--- a/src/cmd/5g/reg.c
+++ /dev/null
@@ -1,1606 +0,0 @@
-// Inferno utils/5c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5g/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 "gg.h"
-#include "opt.h"
-
-#define NREGVAR 24
-#define REGBITS ((uint32)0xffffff)
-#define P2R(p) (Reg*)(p->reg)
-
- void addsplits(void);
- int noreturn(Prog *p);
-static int first = 0;
-
-Reg*
-rega(void)
-{
- Reg *r;
-
- r = freer;
- if(r == R) {
- r = mal(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;
-}
-
-static void
-setoutvar(void)
-{
- Type *t;
- Node *n;
- Addr a;
- Iter save;
- Bits bit;
- int z;
-
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- n = nodarg(t, 1);
- a = zprog.from;
- naddr(n, &a, 0);
- bit = mkvar(R, &a);
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
- t = structnext(&save);
- }
-//if(bany(b))
-//print("ovars = %Q\n", &ovar);
-}
-
-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;
-}
-
-static void
-setaddrs(Bits bit)
-{
- int i, n;
- Var *v;
- Sym *s;
-
- while(bany(&bit)) {
- // convert each bit to a variable
- i = bnum(bit);
- s = var[i].sym;
- n = var[i].name;
- bit.b[i/32] &= ~(1L<<(i%32));
-
- // disable all pieces of that variable
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->sym == s && 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",
- ".F0",
- ".F1",
- ".F2",
- ".F3",
- ".F4",
- ".F5",
- ".F6",
- ".F7",
-};
-
-void
-regopt(Prog *firstp)
-{
- Reg *r, *r1;
- Prog *p;
- int i, z, nr;
- uint32 vreg;
- Bits bit;
-
- if(first == 0) {
- fmtinstall('Q', Qconv);
- }
-
- first++;
- if(debug['K']) {
- if(first != 13)
- return;
-// debug['R'] = 2;
-// debug['P'] = 2;
- print("optimizing %S\n", curfn->nname->sym);
- }
-
- // count instructions
- nr = 0;
- for(p=firstp; p!=P; p=p->link)
- nr++;
-
- // if too big dont bother
- if(nr >= 10000) {
-// print("********** %S is too big (%d)\n", curfn->nname->sym, nr);
- return;
- }
-
- r1 = R;
- firstr = R;
- lastr = R;
-
- /*
- * 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++)
- var[i].sym = lookup(regname[i]);
-
- regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- ovar.b[z] = 0;
- }
-
- // build list of return variables
- setoutvar();
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- nr = 0;
- for(p=firstp; p != P; p = p->link) {
- switch(p->as) {
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- continue;
- }
- r = rega();
- nr++;
- if(firstr == R) {
- firstr = r;
- lastr = r;
- } else {
- lastr->link = r;
- r->p1 = lastr;
- lastr->s1 = r;
- lastr = r;
- }
- r->prog = p;
- p->regp = r;
-
- 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(r, &p->from);
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
-
- /*
- * middle always read when present
- */
- if(p->reg != NREG) {
- if(p->from.type != D_FREG)
- r->use1.b[0] |= RtoB(p->reg);
- else
- r->use1.b[0] |= FtoB(p->reg);
- }
-
- /*
- * right side depends on opcode
- */
- bit = mkvar(r, &p->to);
- if(bany(&bit))
- switch(p->as) {
- default:
- yyerror("reg: unknown op: %A", p->as);
- break;
-
- /*
- * right side read
- */
- case ATST:
- case ATEQ:
- case ACMP:
- case ACMN:
- case ACMPD:
- case ACMPF:
- rightread:
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- break;
-
- /*
- * right side read or read+write, depending on middle
- * ADD x, z => z += x
- * ADD x, y, z => z = x + y
- */
- case AADD:
- case AAND:
- case AEOR:
- case ASUB:
- case ARSB:
- case AADC:
- case ASBC:
- case ARSC:
- case AORR:
- case ABIC:
- case ASLL:
- case ASRL:
- case ASRA:
- case AMUL:
- case AMULU:
- case ADIV:
- case AMOD:
- case AMODU:
- case ADIVU:
- if(p->reg != NREG)
- goto rightread;
- // fall through
-
- /*
- * right side read+write
- */
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- case AMULAL:
- case AMULALU:
- for(z=0; z<BITS; z++) {
- r->use2.b[z] |= bit.b[z];
- r->set.b[z] |= bit.b[z];
- }
- break;
-
- /*
- * right side write
- */
- case ANOP:
- case AMOVB:
- case AMOVBU:
- case AMOVD:
- case AMOVDF:
- case AMOVDW:
- case AMOVF:
- case AMOVFW:
- case AMOVH:
- case AMOVHU:
- case AMOVW:
- case AMOVWD:
- case AMOVWF:
- case AMVN:
- case AMULL:
- case AMULLU:
- if((p->scond & C_SCOND) != C_SCOND_NONE)
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- break;
-
- /*
- * funny
- */
- case ABL:
- setaddrs(bit);
- break;
- }
-
- if(p->as == AMOVM) {
- z = p->to.offset;
- if(p->from.type == D_CONST)
- z = p->from.offset;
- for(i=0; z; i++) {
- if(z&1)
- regbits |= RtoB(i);
- z >>= 1;
- }
- }
- }
- if(firstr == R)
- return;
-
- 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];
- }
-
-// print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n",
-// i, v->addr, v->etype, v->width, v->sym, v->offset);
- }
-
- /*
- * 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) {
- if(p->to.branch == P)
- fatal("pnil %P", p);
- r1 = p->to.branch->regp;
- if(r1 == R)
- fatal("rnil %P", p);
- if(r1 == r) {
- //fatal("ref to self %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);
- print(" addr = %Q\n", addrs);
- }
-
- /*
- * pass 2.5
- * find looping structure
- */
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- change = 0;
- loopit(firstr, nr);
-
- /*
- * 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'] > 1) {
- 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];
- bit.b[z] &= ~addrs.b[z];
- }
-
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->use1))
- print(" u1=%Q", r->use1);
- if(bany(&r->use2))
- print(" u2=%Q", r->use2);
- if(bany(&r->set))
- print(" st=%Q", r->set);
- if(bany(&r->refahead))
- print(" ra=%Q", r->refahead);
- if(bany(&r->calahead))
- print(" ca=%Q", r->calahead);
- if(bany(&r->refbehind))
- print(" rb=%Q", r->refbehind);
- if(bany(&r->calbehind))
- print(" cb=%Q", r->calbehind);
- }
- print("\n");
- }
- }
-
- /*
- * pass 4.5
- * move register pseudo-variables into regu.
- */
- for(r = firstr; r != R; r = r->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;
- }
-
- /*
- * 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->refset) {
- // should never happen - all variables are preset
- if(debug['w'])
- print("%L: used and not set: %Q\n", r->prog->lineno, bit);
- r->refset = 1;
- }
- }
-
- 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) && !r->refset) {
- if(debug['w'])
- print("%L: set and not used: %Q\n", r->prog->lineno, bit);
- r->refset = 1;
- 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'] > 1)
- print("\n");
- paint1(r, i);
- bit.b[i/32] &= ~(1L<<(i%32));
- if(change <= 0) {
- if(debug['R'])
- print("%L $%d: %Q\n",
- r->prog->lineno, change, blsh(i));
- continue;
- }
- rgp->cost = change;
- nregion++;
- if(nregion >= NRGN) {
- if(debug['R'] > 1)
- print("too many regions\n");
- 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: %Q\n",
- rgp->enter->prog->lineno,
- rgp->cost,
- rgp->regno-NREG,
- bit);
- else
- print("%L $%d R%d: %Q\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();
- }
-
- /*
- * last pass
- * eliminate nops
- * free aux structures
- * adjust the stack pointer
- * MOVW.W R1,-12(R13) <<- start
- * MOVW R0,R1
- * MOVW R1,8(R13)
- * MOVW $0,R1
- * MOVW R1,4(R13)
- * BL ,runtime.newproc+0(SB)
- * MOVW &ft+-32(SP),R7 <<- adjust
- * MOVW &j+-40(SP),R6 <<- adjust
- * MOVW autotmp_0003+-24(SP),R5 <<- adjust
- * MOVW $12(R13),R13 <<- finish
- */
- vreg = 0;
- 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.branch != P && p->to.branch->as == ANOP)
- p->to.branch = p->to.branch->link;
- if(p->as == AMOVW && p->to.reg == 13) {
- if(p->scond & C_WBIT) {
- vreg = -p->to.offset; // in adjust region
-// print("%P adjusting %d\n", p, vreg);
- continue;
- }
- if(p->from.type == D_CONST && p->to.type == D_REG) {
- if(p->from.offset != vreg)
- print("in and out different\n");
-// print("%P finish %d\n", p, vreg);
- vreg = 0; // done adjust region
- continue;
- }
-
-// print("%P %d %d from type\n", p, p->from.type, D_CONST);
-// print("%P %d %d to type\n\n", p, p->to.type, D_REG);
- }
-
- if(p->as == AMOVW && vreg != 0) {
- if(p->from.sym != S)
- if(p->from.name == D_AUTO || p->from.name == D_PARAM) {
- p->from.offset += vreg;
-// print("%P adjusting from %d %d\n", p, vreg, p->from.type);
- }
- if(p->to.sym != S)
- if(p->to.name == D_AUTO || p->to.name == D_PARAM) {
- p->to.offset += vreg;
-// print("%P adjusting to %d %d\n", p, vreg, p->from.type);
- }
- }
- }
- 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;
- Adr *a;
- Var *v;
-
- p1 = mal(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->node = v->node;
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = D_OREG;
- if(a->etype == TARRAY || a->sym == S)
- a->type = D_CONST;
-
- if(v->addr)
- fatal("addmove: shouldnt 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:
- p1->as = AMOVBU;
- break;
- case TINT16:
- p1->as = AMOVH;
- break;
- case TUINT16:
- p1->as = AMOVHU;
- break;
- case TINT32:
- case TUINT32:
- case TPTR32:
- p1->as = AMOVW;
- break;
- case TFLOAT32:
- p1->as = AMOVF;
- break;
- case TFLOAT64:
- p1->as = AMOVD;
- 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 = AMOVBU;
- if(v->etype == TUINT16)
- p1->as = AMOVHU;
- }
- if(debug['R'])
- print("%P\t.a%P\n", p, p1);
-}
-
-static int
-overlap(int32 o1, int w1, int32 o2, int w2)
-{
- int32 t1, t2;
-
- t1 = o1+w1;
- t2 = o2+w2;
-
- if(!(t1 > o2 && t2 > o1))
- return 0;
-
- return 1;
-}
-
-Bits
-mkvar(Reg *r, Adr *a)
-{
- Var *v;
- int i, t, n, et, z, w, flag;
- int32 o;
- Bits bit;
- Sym *s;
-
- // mark registers used
- t = a->type;
- n = D_NONE;
-
- flag = 0;
- if(a->pun)
- flag = 1;
-
- switch(t) {
- default:
- print("type %d %d %D\n", t, a->name, a);
- goto none;
-
- case D_NONE:
- case D_FCONST:
- case D_BRANCH:
- break;
-
- case D_CONST:
- flag = 1;
- goto onereg;
-
- case D_REGREG:
- bit = zbits;
- if(a->offset != NREG)
- bit.b[0] |= RtoB(a->offset);
- if(a->reg != NREG)
- bit.b[0] |= RtoB(a->reg);
- return bit;
-
- case D_REG:
- case D_SHIFT:
- onereg:
- if(a->reg != NREG) {
- bit = zbits;
- bit.b[0] = RtoB(a->reg);
- return bit;
- }
- break;
-
- case D_OREG:
- if(a->reg != NREG) {
- if(a == &r->prog->from)
- r->use1.b[0] |= RtoB(a->reg);
- else
- r->use2.b[0] |= RtoB(a->reg);
- if(r->prog->scond & (C_PBIT|C_WBIT))
- r->set.b[0] |= RtoB(a->reg);
- }
- break;
-
- case D_FREG:
- if(a->reg != NREG) {
- bit = zbits;
- bit.b[0] = FtoB(a->reg);
- return bit;
- }
- break;
- }
-
- switch(a->name) {
- default:
- goto none;
-
- case D_EXTERN:
- case D_STATIC:
- case D_AUTO:
- case D_PARAM:
- n = a->name;
- break;
- }
-
- s = a->sym;
- if(s == S)
- goto none;
- if(s->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- w = a->width;
-
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->sym == s && v->name == n) {
- if(v->offset == o)
- if(v->etype == et)
- if(v->width == w)
- if(!flag)
- return blsh(i);
-
- // if they overlaps, disable both
- if(overlap(v->offset, v->width, o, w)) {
- v->addr = 1;
- flag = 1;
- }
- }
- }
-
- switch(et) {
- case 0:
- case TFUNC:
- case TARRAY:
- case TSTRING:
- goto none;
- }
-
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
- fatal("variable not optimized: %D", a);
- goto none;
- }
-
- i = nvar;
- nvar++;
- v = var+i;
- v->sym = s;
- v->offset = o;
- v->name = n;
-// v->gotype = a->gotype;
- v->etype = et;
- v->width = w;
- v->addr = flag; // funny punning
- v->node = a->node;
-
- if(debug['R'])
- print("bit=%2d et=%E pun=%d %D\n", i, et, flag, a);
-
- 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];
-
- 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:
- if(noreturn(r1->prog))
- break;
- 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] | 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->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("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 = mal(nr * sizeof(Reg*));
- idom = mal(nr * sizeof(int32));
- maxnr = nr;
- }
- d = postorder(r, rpo2r, 0);
- if(d > nr)
- fatal("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:
- fatal("unknown etype %d/%E", bitno(b), v->etype);
- break;
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TPTR32:
- 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+NREG;
- return FtoB(i);
- }
- break;
-
- case TINT64:
- case TUINT64:
- case TPTR64:
- case TINTER:
- case TSTRUCT:
- case TARRAY:
- 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'] > 1)
- print("%d%P\td %Q $%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'] > 1)
- print("%d%P\tu1 %Q $%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'] > 1)
- print("%d%P\tu2 %Q $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->loop;
- if(debug['R'] > 1)
- print("%d%P\tst %Q $%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(Adr *a, int rn)
-{
-
- if(a->type == D_CONST)
- fatal("addreg: cant do this %D %d\n", a, 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
- */
-int32
-RtoB(int r)
-{
-
- if(r < 2 || r >= REGTMP-2) // excluded R9 and R10 for m and g
- return 0;
- return 1L << r;
-}
-
-int
-BtoR(int32 b)
-{
- b &= 0x01fcL; // excluded R9 and R10 for m and g
- if(b == 0)
- return 0;
- return bitno(b);
-}
-
-/*
- * bit reg
- * 18 F2
- * 19 F3
- * ... ...
- * 23 F7
- */
-int32
-FtoB(int f)
-{
-
- if(f < 2 || f > NFREG-1)
- return 0;
- return 1L << (f + 16);
-}
-
-int
-BtoF(int32 b)
-{
-
- b &= 0xfc0000L;
- if(b == 0)
- return 0;
- return bitno(b) - 16;
-}
-
-static Sym* symlist[10];
-
-int
-noreturn(Prog *p)
-{
- Sym *s;
- int i;
-
- if(symlist[0] == S) {
- symlist[0] = pkglookup("panicindex", runtimepkg);
- symlist[1] = pkglookup("panicslice", runtimepkg);
- symlist[2] = pkglookup("throwinit", runtimepkg);
- symlist[3] = pkglookup("panic", runtimepkg);
- symlist[4] = pkglookup("panicwrap", runtimepkg);
- }
-
- s = p->to.sym;
- if(s == S)
- return 0;
- for(i=0; symlist[i]!=S; i++)
- if(s == symlist[i])
- return 1;
- return 0;
-}
-
-void
-dumpone(Reg *r)
-{
- int z;
- Bits bit;
-
- print("%d:%P", r->loop, r->prog);
- 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, Reg *r0)
-{
- Reg *r, *r1;
-
- print("\n%s\n", str);
- for(r = r0; r != R; r = r->link) {
- dumpone(r);
- r1 = r->p2;
- if(r1 != R) {
- print(" pred:");
- for(; r1 != R; r1 = r1->p2link)
- print(" %.4ud", r1->prog->loc);
- print("\n");
- }
-// r1 = r->s1;
-// if(r1 != R) {
-// print(" succ:");
-// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", r1->prog->loc);
-// print("\n");
-// }
- }
-}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
deleted file mode 100644
index cf86ae48b..000000000
--- a/src/cmd/5l/5.out.h
+++ /dev/null
@@ -1,270 +0,0 @@
-// Inferno utils/5c/5.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/5.out.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.
-
-#define NSNAME 8
-#define NSYM 50
-#define NREG 16
-
-#define NOPROF (1<<0)
-#define DUPOK (1<<1)
-#define NOSPLIT (1<<2)
-#define ALLTHUMBS (1<<3)
-
-#define REGRET 0
-/* -1 disables use of REGARG */
-#define REGARG -1
-/* compiler allocates R1 up as temps */
-/* compiler allocates register variables R3 up */
-#define REGEXT 10
-/* these two registers are declared in runtime.h */
-#define REGG (REGEXT-0)
-#define REGM (REGEXT-1)
-/* compiler allocates external registers R10 down */
-#define REGTMP 11
-#define REGSB 12
-#define REGSP 13
-#define REGLINK 14
-#define REGPC 15
-
-#define NFREG 8
-#define FREGRET 0
-#define FREGEXT 7
-#define FREGTMP 15
-/* compiler allocates register variables F0 up */
-/* compiler allocates external registers F7 down */
-
-enum as
-{
- AXXX,
-
- AAND,
- AEOR,
- ASUB,
- ARSB,
- AADD,
- AADC,
- ASBC,
- ARSC,
- ATST,
- ATEQ,
- ACMP,
- ACMN,
- AORR,
- ABIC,
-
- AMVN,
-
- AB,
- ABL,
-
-/*
- * Do not reorder or fragment the conditional branch
- * opcodes, or the predication code will break
- */
- ABEQ,
- ABNE,
- ABCS,
- ABHS,
- ABCC,
- ABLO,
- ABMI,
- ABPL,
- ABVS,
- ABVC,
- ABHI,
- ABLS,
- ABGE,
- ABLT,
- ABGT,
- ABLE,
-
- AMOVWD,
- AMOVWF,
- AMOVDW,
- AMOVFW,
- AMOVFD,
- AMOVDF,
- AMOVF,
- AMOVD,
-
- ACMPF,
- ACMPD,
- AADDF,
- AADDD,
- ASUBF,
- ASUBD,
- AMULF,
- AMULD,
- ADIVF,
- ADIVD,
- ASQRTF,
- ASQRTD,
-
- ASRL,
- ASRA,
- ASLL,
- AMULU,
- ADIVU,
- AMUL,
- ADIV,
- AMOD,
- AMODU,
-
- AMOVB,
- AMOVBU,
- AMOVH,
- AMOVHU,
- AMOVW,
- AMOVM,
- ASWPBU,
- ASWPW,
-
- ANOP,
- ARFE,
- ASWI,
- AMULA,
-
- ADATA,
- AGLOBL,
- AGOK,
- AHISTORY,
- ANAME,
- ARET,
- ATEXT,
- AWORD,
- ADYNT_,
- AINIT_,
- ABCASE,
- ACASE,
-
- AEND,
-
- AMULL,
- AMULAL,
- AMULLU,
- AMULALU,
-
- ABX,
- ABXRET,
- ADWORD,
-
- ASIGNAME,
-
- ALDREX,
- ASTREX,
-
- ALDREXD,
- ASTREXD,
-
- ALAST,
-};
-
-/* scond byte */
-#define C_SCOND ((1<<4)-1)
-#define C_SBIT (1<<4)
-#define C_PBIT (1<<5)
-#define C_WBIT (1<<6)
-#define C_FBIT (1<<7) /* psr flags-only */
-#define C_UBIT (1<<7) /* up bit, unsigned bit */
-
-#define C_SCOND_EQ 0
-#define C_SCOND_NE 1
-#define C_SCOND_HS 2
-#define C_SCOND_LO 3
-#define C_SCOND_MI 4
-#define C_SCOND_PL 5
-#define C_SCOND_VS 6
-#define C_SCOND_VC 7
-#define C_SCOND_HI 8
-#define C_SCOND_LS 9
-#define C_SCOND_GE 10
-#define C_SCOND_LT 11
-#define C_SCOND_GT 12
-#define C_SCOND_LE 13
-#define C_SCOND_NONE 14
-#define C_SCOND_NV 15
-
-/* D_SHIFT type */
-#define SHIFT_LL 0<<5
-#define SHIFT_LR 1<<5
-#define SHIFT_AR 2<<5
-#define SHIFT_RR 3<<5
-
-/* type/name */
-#define D_GOK 0
-#define D_NONE 1
-
-/* type */
-#define D_BRANCH (D_NONE+1)
-#define D_OREG (D_NONE+2)
-#define D_CONST (D_NONE+7)
-#define D_FCONST (D_NONE+8)
-#define D_SCONST (D_NONE+9)
-#define D_PSR (D_NONE+10)
-#define D_REG (D_NONE+12)
-#define D_FREG (D_NONE+13)
-#define D_FILE (D_NONE+16)
-#define D_OCONST (D_NONE+17)
-#define D_FILE1 (D_NONE+18)
-
-#define D_SHIFT (D_NONE+19)
-#define D_FPCR (D_NONE+20)
-#define D_REGREG (D_NONE+21)
-#define D_ADDR (D_NONE+22)
-
-#define D_SBIG (D_NONE+23)
-#define D_CONST2 (D_NONE+24)
-
-/* name */
-#define D_EXTERN (D_NONE+3)
-#define D_STATIC (D_NONE+4)
-#define D_AUTO (D_NONE+5)
-#define D_PARAM (D_NONE+6)
-
-/* internal only */
-#define D_SIZE (D_NONE+40)
-#define D_PCREL (D_NONE+41)
-
-/*
- * this is the ranlib header
- */
-#define SYMDEF "__.SYMDEF"
-
-/*
- * this is the simulated IEEE floating point
- */
-typedef struct ieee Ieee;
-struct ieee
-{
- int32 l; /* contains ls-man 0xffffffff */
- int32 h; /* contains sign 0x80000000
- exp 0x7ff00000
- ms-man 0x000fffff */
-};
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
deleted file mode 100644
index 9f4a192aa..000000000
--- a/src/cmd/5l/Makefile
+++ /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.
-
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=5l
-
-OFILES=\
- asm.$O\
- data.$O\
- elf.$O\
- enam.$O\
- ldelf.$O\
- ldmacho.$O\
- ldpe.$O\
- lib.$O\
- list.$O\
- noop.$O\
- obj.$O\
- optab.$O\
- pass.$O\
- prof.$O\
- softfloat.$O\
- span.$O\
- symtab.$O\
- go.$O\
-
-HFILES=\
- l.h\
- ../5l/5.out.h\
- ../ld/elf.h\
-
-include ../../Make.ccmd
-
-enam.c: 5.out.h
- sh mkenam
-
-CLEANFILES+=enam.c
-
-%.$O: ../ld/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
deleted file mode 100644
index 2c9e50d00..000000000
--- a/src/cmd/5l/asm.c
+++ /dev/null
@@ -1,1883 +0,0 @@
-// 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"
-
-static Prog *PP;
-
-char linuxdynld[] = "/lib/ld-linux.so.2";
-
-int32
-entryvalue(void)
-{
- char *a;
- Sym *s;
-
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return atolwhex(a);
- s = lookup(a, 0);
- if(s->type == 0)
- return INITTEXT;
- if(s->type != STEXT)
- diag("entry not text: %s", s->name);
- return s->value;
-}
-
-enum {
- ElfStrEmpty,
- ElfStrInterp,
- ElfStrHash,
- ElfStrGot,
- ElfStrGotPlt,
- ElfStrDynamic,
- ElfStrDynsym,
- ElfStrDynstr,
- ElfStrRel,
- ElfStrText,
- ElfStrData,
- ElfStrBss,
- ElfStrSymtab,
- ElfStrStrtab,
- ElfStrShstrtab,
- ElfStrRelPlt,
- ElfStrPlt,
- NElfStr
-};
-
-vlong elfstr[NElfStr];
-
-static int
-needlib(char *name)
-{
- char *p;
- Sym *s;
-
- if(*name == '\0')
- return 0;
-
- /* reuse hash code in symbol table */
- p = smprint(".dynlib.%s", name);
- s = lookup(p, 0);
- if(s->type == 0) {
- s->type = 100; // avoid SDATA, etc.
- return 1;
- }
- return 0;
-}
-
-int nelfsym = 1;
-
-void
-adddynrel(Sym *s, Reloc *r)
-{
- diag("adddynrel: unsupported binary format");
-}
-
-void
-adddynsym(Sym *s)
-{
- diag("adddynsym: not implemented");
-}
-
-static void
-elfsetupplt(void)
-{
- // TODO
-}
-
-int
-archreloc(Reloc *r, Sym *s, vlong *val)
-{
- return -1;
-}
-
-void
-adddynlib(char *lib)
-{
- Sym *s;
-
- if(!needlib(lib))
- return;
-
- if(iself) {
- s = lookup(".dynstr", 0);
- if(s->size == 0)
- addstring(s, "");
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
- } else {
- diag("adddynlib: unsupported binary format");
- }
-}
-
-void
-doelf(void)
-{
- Sym *s, *shstrtab, *dynstr;
-
- if(!iself)
- return;
-
- /* predefine strings we need for section headers */
- shstrtab = lookup(".shstrtab", 0);
- shstrtab->type = SELFDATA;
- shstrtab->reachable = 1;
-
- elfstr[ElfStrEmpty] = addstring(shstrtab, "");
- elfstr[ElfStrText] = addstring(shstrtab, ".text");
- elfstr[ElfStrData] = addstring(shstrtab, ".data");
- elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
- addstring(shstrtab, ".rodata");
- addstring(shstrtab, ".gosymtab");
- addstring(shstrtab, ".gopclntab");
- if(!debug['s']) {
- elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
- elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
- }
- elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
-
- if(!debug['d']) { /* -d suppresses dynamic loader format */
- elfstr[ElfStrInterp] = addstring(shstrtab, ".interp");
- elfstr[ElfStrHash] = addstring(shstrtab, ".hash");
- elfstr[ElfStrGot] = addstring(shstrtab, ".got");
- elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt");
- elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic");
- elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
- elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
- elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
- elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
- elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
-
- /* interpreter string */
- s = lookup(".interp", 0);
- s->reachable = 1;
- s->type = SELFDATA; // TODO: rodata
-
- /* dynamic symbol table - first entry all zeros */
- s = lookup(".dynsym", 0);
- s->type = SELFDATA;
- s->reachable = 1;
- s->value += ELF32SYMSIZE;
-
- /* dynamic string table */
- s = lookup(".dynstr", 0);
- s->type = SELFDATA;
- s->reachable = 1;
- if(s->size == 0)
- addstring(s, "");
- dynstr = s;
-
- /* relocation table */
- s = lookup(".rel", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /* global offset table */
- s = lookup(".got", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /* hash */
- s = lookup(".hash", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /* got.plt */
- s = lookup(".got.plt", 0);
- s->reachable = 1;
- s->type = SDATA; // writable, so not SELFDATA
-
- s = lookup(".plt", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- s = lookup(".rel.plt", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- elfsetupplt();
-
- /* define dynamic elf table */
- s = lookup(".dynamic", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /*
- * .dynamic table
- */
- elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
- elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
- elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
- elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
- elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
- elfwritedynentsym(s, DT_REL, lookup(".rel", 0));
- elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0));
- elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
- if(rpath)
- elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
- elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
- elfwritedynent(s, DT_PLTREL, DT_REL);
- elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
- elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
- elfwritedynent(s, DT_NULL, 0);
- }
-}
-
-vlong
-datoff(vlong addr)
-{
- if(addr >= segdata.vaddr)
- return addr - segdata.vaddr + segdata.fileoff;
- if(addr >= segtext.vaddr)
- return addr - segtext.vaddr + segtext.fileoff;
- diag("datoff %#x", addr);
- return 0;
-}
-
-void
-shsym(Elf64_Shdr *sh, Sym *s)
-{
- sh->addr = symaddr(s);
- sh->off = datoff(sh->addr);
- sh->size = s->size;
-}
-
-void
-phsh(Elf64_Phdr *ph, Elf64_Shdr *sh)
-{
- ph->vaddr = sh->addr;
- ph->paddr = ph->vaddr;
- ph->off = sh->off;
- ph->filesz = sh->size;
- ph->memsz = sh->size;
- ph->align = sh->addralign;
-}
-
-void
-asmb(void)
-{
- int32 t;
- int a, dynsym;
- uint32 fo, symo, startva;
- ElfEhdr *eh;
- ElfPhdr *ph, *pph;
- ElfShdr *sh;
- Section *sect;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f asmb\n", cputime());
- Bflush(&bso);
-
- sect = segtext.sect;
- seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
- codeblk(sect->vaddr, sect->len);
-
- /* output read-only data in text segment (rodata, gosymtab and pclntab) */
- for(sect = sect->next; sect != nil; sect = sect->next) {
- seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
- datblk(sect->vaddr, sect->len);
- }
-
- if(debug['v'])
- Bprint(&bso, "%5.2f datblk\n", cputime());
- Bflush(&bso);
-
- seek(cout, segdata.fileoff, 0);
- datblk(segdata.vaddr, segdata.filelen);
-
- /* output read-only data in text segment */
- sect = segtext.sect->next;
- seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
- datblk(sect->vaddr, sect->len);
-
- if(iself) {
- /* index of elf text section; needed by asmelfsym, double-checked below */
- /* !debug['d'] causes extra sections before the .text section */
- elftextsh = 1;
- if(!debug['d']) {
- elftextsh += 10;
- if(elfverneed)
- elftextsh += 2;
- }
- }
-
- /* 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 Hnoheader:
- case Hrisc:
- case Hixp1200:
- case Hipaq:
- debug['s'] = 1;
- break;
- case Hplan9x32:
- symo = HEADR+segtext.len+segdata.filelen;
- break;
- case Hnetbsd:
- symo = rnd(segdata.filelen, 4096);
- break;
- ElfSym:
- symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
- symo = rnd(symo, INITRND);
- break;
- }
- seek(cout, symo, 0);
- if(iself) {
- if(debug['v'])
- Bprint(&bso, "%5.2f elfsym\n", cputime());
- asmelfsym();
- cflush();
- ewrite(cout, elfstrdat, elfstrsize);
-
- // if(debug['v'])
- // Bprint(&bso, "%5.2f dwarf\n", cputime());
- // dwarfemitdebugsections();
- }
- cflush();
-
- }
-
- cursym = nil;
- if(debug['v'])
- Bprint(&bso, "%5.2f header\n", cputime());
- Bflush(&bso);
- seek(cout, 0L, 0);
- switch(HEADTYPE) {
- case Hnoheader: /* no header */
- break;
- case Hrisc: /* aif for risc os */
- lputl(0xe1a00000); /* NOP - decompress code */
- lputl(0xe1a00000); /* NOP - relocation code */
- lputl(0xeb000000 + 12); /* BL - zero init code */
- lputl(0xeb000000 +
- (entryvalue()
- - INITTEXT
- + HEADR
- - 12
- - 8) / 4); /* BL - entry code */
-
- lputl(0xef000011); /* SWI - exit code */
- lputl(textsize+HEADR); /* text size */
- lputl(segdata.filelen); /* data size */
- lputl(0); /* sym size */
-
- lputl(segdata.len - segdata.filelen); /* bss size */
- lputl(0); /* sym type */
- lputl(INITTEXT-HEADR); /* text addr */
- lputl(0); /* workspace - ignored */
-
- lputl(32); /* addr mode / data addr flag */
- lputl(0); /* data addr */
- for(t=0; t<2; t++)
- lputl(0); /* reserved */
-
- for(t=0; t<15; t++)
- lputl(0xe1a00000); /* NOP - zero init code */
- lputl(0xe1a0f00e); /* B (R14) - zero init return */
- break;
- case Hplan9x32: /* plan 9 */
- lput(0x647); /* magic */
- lput(textsize); /* sizes */
- lput(segdata.filelen);
- lput(segdata.len - segdata.filelen);
- lput(symsize); /* nsyms */
- lput(entryvalue()); /* va of entry */
- lput(0L);
- lput(lcsize);
- break;
- case Hnetbsd: /* boot for NetBSD */
- lput((143<<16)|0413); /* magic */
- lputl(rnd(HEADR+textsize, 4096));
- lputl(rnd(segdata.filelen, 4096));
- lputl(segdata.len - segdata.filelen);
- lputl(symsize); /* nsyms */
- lputl(entryvalue()); /* va of entry */
- lputl(0L);
- lputl(0L);
- break;
- case Hixp1200: /* boot for IXP1200 */
- break;
- case Hipaq: /* boot for ipaq */
- lputl(0xe3300000); /* nop */
- lputl(0xe3300000); /* nop */
- lputl(0xe3300000); /* nop */
- lputl(0xe3300000); /* nop */
- break;
- case Hlinux:
- /* elf arm */
- eh = getElfEhdr();
- fo = HEADR;
- startva = INITTEXT - fo; /* va of byte 0 of file */
-
- /* This null SHdr must appear before all others */
- sh = newElfShdr(elfstr[ElfStrEmpty]);
-
- /* program header info */
- pph = newElfPhdr();
- pph->type = PT_PHDR;
- pph->flags = PF_R + PF_X;
- pph->off = eh->ehsize;
- pph->vaddr = INITTEXT - HEADR + pph->off;
- pph->paddr = INITTEXT - HEADR + pph->off;
- pph->align = INITRND;
-
- if(!debug['d']) {
- /* interpreter for dynamic linking */
- sh = newElfShdr(elfstr[ElfStrInterp]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->addralign = 1;
- if(interpreter == nil)
- interpreter = linuxdynld;
- elfinterp(sh, startva, interpreter);
-
- ph = newElfPhdr();
- ph->type = PT_INTERP;
- ph->flags = PF_R;
- phsh(ph, sh);
- }
-
- elfphload(&segtext);
- elfphload(&segdata);
-
- /* Dynamic linking sections */
- if (!debug['d']) { /* -d suppresses dynamic loader format */
- /* S headers for dynamic linking */
- sh = newElfShdr(elfstr[ElfStrGot]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 4;
- sh->addralign = 4;
- shsym(sh, lookup(".got", 0));
-
- sh = newElfShdr(elfstr[ElfStrGotPlt]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 4;
- sh->addralign = 4;
- shsym(sh, lookup(".got.plt", 0));
-
- dynsym = eh->shnum;
- sh = newElfShdr(elfstr[ElfStrDynsym]);
- sh->type = SHT_DYNSYM;
- sh->flags = SHF_ALLOC;
- sh->entsize = ELF32SYMSIZE;
- sh->addralign = 4;
- sh->link = dynsym+1; // dynstr
- // sh->info = index of first non-local symbol (number of local symbols)
- shsym(sh, lookup(".dynsym", 0));
-
- sh = newElfShdr(elfstr[ElfStrDynstr]);
- sh->type = SHT_STRTAB;
- sh->flags = SHF_ALLOC;
- sh->addralign = 1;
- shsym(sh, lookup(".dynstr", 0));
-
- sh = newElfShdr(elfstr[ElfStrHash]);
- sh->type = SHT_HASH;
- sh->flags = SHF_ALLOC;
- sh->entsize = 4;
- sh->addralign = 4;
- sh->link = dynsym;
- shsym(sh, lookup(".hash", 0));
-
- sh = newElfShdr(elfstr[ElfStrRel]);
- sh->type = SHT_REL;
- sh->flags = SHF_ALLOC;
- sh->entsize = ELF32RELSIZE;
- sh->addralign = 4;
- sh->link = dynsym;
- shsym(sh, lookup(".rel", 0));
-
- /* sh and PT_DYNAMIC for .dynamic section */
- sh = newElfShdr(elfstr[ElfStrDynamic]);
- sh->type = SHT_DYNAMIC;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 8;
- sh->addralign = 4;
- sh->link = dynsym+1; // dynstr
- shsym(sh, lookup(".dynamic", 0));
-
- ph = newElfPhdr();
- ph->type = PT_DYNAMIC;
- ph->flags = PF_R + PF_W;
- phsh(ph, sh);
-
- /*
- * Thread-local storage segment (really just size).
- if(tlsoffset != 0) {
- ph = newElfPhdr();
- ph->type = PT_TLS;
- ph->flags = PF_R;
- ph->memsz = -tlsoffset;
- ph->align = 4;
- }
- */
- }
-
- ph = newElfPhdr();
- ph->type = PT_GNU_STACK;
- ph->flags = PF_W+PF_R;
- ph->align = 4;
-
- if(elftextsh != eh->shnum)
- diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
- for(sect=segtext.sect; sect!=nil; sect=sect->next)
- elfshbits(sect);
- for(sect=segdata.sect; sect!=nil; sect=sect->next)
- elfshbits(sect);
-
- if (!debug['s']) {
- sh = newElfShdr(elfstr[ElfStrSymtab]);
- sh->type = SHT_SYMTAB;
- sh->off = symo;
- sh->size = symsize;
- sh->addralign = 4;
- sh->entsize = 16;
- sh->link = eh->shnum; // link to strtab
-
- sh = newElfShdr(elfstr[ElfStrStrtab]);
- sh->type = SHT_STRTAB;
- sh->off = symo+symsize;
- sh->size = elfstrsize;
- sh->addralign = 1;
-
- // dwarfaddelfheaders();
- }
-
- sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
- sh->type = SHT_STRTAB;
- sh->addralign = 1;
- shsym(sh, lookup(".shstrtab", 0));
-
- /* Main header */
- eh->ident[EI_MAG0] = '\177';
- eh->ident[EI_MAG1] = 'E';
- eh->ident[EI_MAG2] = 'L';
- eh->ident[EI_MAG3] = 'F';
- eh->ident[EI_CLASS] = ELFCLASS32;
- eh->ident[EI_DATA] = ELFDATA2LSB;
- eh->ident[EI_VERSION] = EV_CURRENT;
-
- eh->type = ET_EXEC;
- eh->machine = EM_ARM;
- eh->version = EV_CURRENT;
- eh->entry = entryvalue();
-
- if(pph != nil) {
- pph->filesz = eh->phnum * eh->phentsize;
- pph->memsz = pph->filesz;
- }
-
- seek(cout, 0, 0);
- a = 0;
- a += elfwritehdr();
- a += elfwritephdrs();
- a += elfwriteshdrs();
- cflush();
- if(a+elfwriteinterp() > ELFRESERVE)
- diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
- break;
- }
- cflush();
- if(debug['c']){
- print("textsize=%d\n", textsize);
- print("datsize=%d\n", segdata.filelen);
- print("bsssize=%d\n", segdata.len - segdata.filelen);
- print("symsize=%d\n", symsize);
- print("lcsize=%d\n", lcsize);
- print("total=%d\n", textsize+segdata.len+symsize+lcsize);
- }
-}
-
-void
-cput(int c)
-{
- cbp[0] = c;
- cbp++;
- cbc--;
- if(cbc <= 0)
- cflush();
-}
-
-/*
-void
-cput(int32 c)
-{
- *cbp++ = c;
- if(--cbc <= 0)
- cflush();
-}
-*/
-
-void
-wput(int32 l)
-{
-
- cbp[0] = l>>8;
- cbp[1] = l;
- cbp += 2;
- cbc -= 2;
- if(cbc <= 0)
- cflush();
-}
-
-
-void
-hput(int32 l)
-{
-
- cbp[0] = l>>8;
- cbp[1] = l;
- cbp += 2;
- cbc -= 2;
- if(cbc <= 0)
- cflush();
-}
-
-void
-lput(int32 l)
-{
-
- cbp[0] = l>>24;
- cbp[1] = l>>16;
- cbp[2] = l>>8;
- cbp[3] = l;
- cbp += 4;
- cbc -= 4;
- if(cbc <= 0)
- cflush();
-}
-
-void
-cflush(void)
-{
- int n;
-
- /* no bug if cbc < 0 since obuf(cbuf) followed by ibuf in buf! */
- n = sizeof(buf.cbuf) - cbc;
- if(n)
- ewrite(cout, buf.cbuf, n);
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
-}
-
-void
-nopstat(char *f, Count *c)
-{
- if(c->outof)
- Bprint(&bso, "%s delay %d/%d (%.2f)\n", f,
- c->outof - c->count, c->outof,
- (double)(c->outof - c->count)/c->outof);
-}
-
-void
-asmout(Prog *p, Optab *o, int32 *out)
-{
- int32 o1, o2, o3, o4, o5, o6, v;
- int r, rf, rt, rt2;
- Reloc *rel;
-
-PP = p;
- o1 = 0;
- o2 = 0;
- o3 = 0;
- o4 = 0;
- o5 = 0;
- o6 = 0;
- armsize += o->size;
-if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type);
- switch(o->type) {
- default:
- diag("unknown asm %d", o->type);
- prasm(p);
- break;
-
- case 0: /* pseudo ops */
-if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr);
- break;
-
- case 1: /* op R,[R],R */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else
- if(r == NREG)
- r = rt;
- o1 |= rf | (r<<16) | (rt<<12);
- break;
-
- case 2: /* movbu $I,[R],R */
- aclass(&p->from);
- o1 = oprrr(p->as, p->scond);
- o1 |= immrot(instoffset);
- rt = p->to.reg;
- r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == NREG)
- r = rt;
- o1 |= (r<<16) | (rt<<12);
- break;
-
- case 3: /* add R<<[IR],[R],R */
- mov:
- aclass(&p->from);
- o1 = oprrr(p->as, p->scond);
- o1 |= p->from.offset;
- rt = p->to.reg;
- r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == NREG)
- r = rt;
- o1 |= (r<<16) | (rt<<12);
- break;
-
- case 4: /* add $I,[R],R */
- aclass(&p->from);
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(instoffset);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 |= r << 16;
- o1 |= p->to.reg << 12;
- break;
-
- case 5: /* bra s */
- v = -8;
- if(p->cond != P)
- v = (p->cond->pc - pc) - 8;
- o1 = opbra(p->as, p->scond);
- o1 |= (v >> 2) & 0xffffff;
- break;
-
- case 6: /* b ,O(R) -> add $O,R,PC */
- aclass(&p->to);
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(instoffset);
- o1 |= p->to.reg << 16;
- o1 |= REGPC << 12;
- break;
-
- case 7: /* bl ,O(R) -> mov PC,link; add $O,R,PC */
- aclass(&p->to);
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(0);
- o1 |= REGPC << 16;
- o1 |= REGLINK << 12;
-
- o2 = oprrr(AADD, p->scond);
- o2 |= immrot(instoffset);
- o2 |= p->to.reg << 16;
- o2 |= REGPC << 12;
- break;
-
- case 8: /* sll $c,[R],R -> mov (R<<$c),R */
- aclass(&p->from);
- o1 = oprrr(p->as, p->scond);
- r = p->reg;
- if(r == NREG)
- r = p->to.reg;
- o1 |= r;
- o1 |= (instoffset&31) << 7;
- o1 |= p->to.reg << 12;
- break;
-
- case 9: /* sll R,[R],R -> mov (R<<R),R */
- o1 = oprrr(p->as, p->scond);
- r = p->reg;
- if(r == NREG)
- r = p->to.reg;
- o1 |= r;
- o1 |= (p->from.reg << 8) | (1<<4);
- o1 |= p->to.reg << 12;
- break;
-
- case 10: /* swi [$con] */
- o1 = oprrr(p->as, p->scond);
- if(p->to.type != D_NONE) {
- aclass(&p->to);
- o1 |= instoffset & 0xffffff;
- }
- break;
-
- case 11: /* word */
- aclass(&p->to);
- o1 = instoffset;
- if(p->to.sym != S) {
- rel = addrel(cursym);
- rel->off = pc - cursym->value;
- rel->siz = 4;
- rel->type = D_ADDR;
- rel->sym = p->to.sym;
- rel->add = p->to.offset;
- o1 = 0;
- }
- break;
-
- case 12: /* movw $lcon, reg */
- o1 = omvl(p, &p->from, p->to.reg);
- break;
-
- case 13: /* op $lcon, [R], R */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = oprrr(p->as, p->scond);
- o2 |= REGTMP;
- r = p->reg;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == NREG)
- r = p->to.reg;
- o2 |= r << 16;
- if(p->to.type != D_NONE)
- o2 |= p->to.reg << 12;
- break;
-
- case 14: /* movb/movbu/movh/movhu R,R */
- o1 = oprrr(ASLL, p->scond);
-
- if(p->as == AMOVBU || p->as == AMOVHU)
- o2 = oprrr(ASRL, p->scond);
- else
- o2 = oprrr(ASRA, p->scond);
-
- r = p->to.reg;
- o1 |= (p->from.reg)|(r<<12);
- o2 |= (r)|(r<<12);
- if(p->as == AMOVB || p->as == AMOVBU) {
- o1 |= (24<<7);
- o2 |= (24<<7);
- } else {
- o1 |= (16<<7);
- o2 |= (16<<7);
- }
- break;
-
- case 15: /* mul r,[r,]r */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- if(r == NREG)
- r = rt;
- if(rt == r) {
- r = rf;
- rf = rt;
- }
- if(0)
- if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
- diag("bad registers in MUL");
- prasm(p);
- }
- o1 |= (rf<<8) | r | (rt<<16);
- break;
-
-
- case 16: /* div r,[r,]r */
- o1 = 0xf << 28;
- o2 = 0;
- break;
-
- case 17:
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- rt2 = p->to.offset;
- r = p->reg;
- o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
- break;
-
- case 20: /* mov/movb/movbu R,O(R) */
- aclass(&p->to);
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o1 = osr(p->as, p->from.reg, instoffset, r, p->scond);
- break;
-
- case 21: /* mov/movbu O(R),R -> lr */
- aclass(&p->from);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 = olr(instoffset, r, p->to.reg, p->scond);
- if(p->as != AMOVW)
- o1 |= 1<<22;
- break;
-
- case 30: /* mov/movb/movbu R,L(R) */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o2 = osrr(p->from.reg, REGTMP,r, p->scond);
- if(p->as != AMOVW)
- o2 |= 1<<22;
- break;
-
- case 31: /* mov/movbu L(R),R -> lr[b] */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 = olrr(REGTMP,r, p->to.reg, p->scond);
- if(p->as == AMOVBU || p->as == AMOVB)
- o2 |= 1<<22;
- break;
-
- case 34: /* mov $lacon,R */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
-
- o2 = oprrr(AADD, p->scond);
- o2 |= REGTMP;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 |= r << 16;
- if(p->to.type != D_NONE)
- o2 |= p->to.reg << 12;
- break;
-
- case 35: /* mov PSR,R */
- o1 = (2<<23) | (0xf<<16) | (0<<0);
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= (p->from.reg & 1) << 22;
- o1 |= p->to.reg << 12;
- break;
-
- case 36: /* mov R,PSR */
- o1 = (2<<23) | (0x29f<<12) | (0<<4);
- if(p->scond & C_FBIT)
- o1 ^= 0x010 << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= (p->to.reg & 1) << 22;
- o1 |= p->from.reg << 0;
- break;
-
- case 37: /* mov $con,PSR */
- aclass(&p->from);
- o1 = (2<<23) | (0x29f<<12) | (0<<4);
- if(p->scond & C_FBIT)
- o1 ^= 0x010 << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= immrot(instoffset);
- o1 |= (p->to.reg & 1) << 22;
- o1 |= p->from.reg << 0;
- break;
-
- case 38: /* movm $con,oreg -> stm */
- o1 = (0x4 << 25);
- o1 |= p->from.offset & 0xffff;
- o1 |= p->to.reg << 16;
- aclass(&p->to);
- goto movm;
-
- case 39: /* movm oreg,$con -> ldm */
- o1 = (0x4 << 25) | (1 << 20);
- o1 |= p->to.offset & 0xffff;
- o1 |= p->from.reg << 16;
- aclass(&p->from);
- movm:
- if(instoffset != 0)
- diag("offset must be zero in MOVM");
- o1 |= (p->scond & C_SCOND) << 28;
- if(p->scond & C_PBIT)
- o1 |= 1 << 24;
- if(p->scond & C_UBIT)
- o1 |= 1 << 23;
- if(p->scond & C_SBIT)
- o1 |= 1 << 22;
- if(p->scond & C_WBIT)
- o1 |= 1 << 21;
- break;
-
- case 40: /* swp oreg,reg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in SWP");
- o1 = (0x2<<23) | (0x9<<4);
- if(p->as != ASWPW)
- o1 |= 1 << 22;
- o1 |= p->from.reg << 16;
- o1 |= p->reg << 0;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
-
- case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
- o1 = 0xe8fd8000;
- break;
-
- case 50: /* floating point store */
- v = regoff(&p->to);
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p);
- break;
-
- case 51: /* floating point load */
- v = regoff(&p->from);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
- break;
-
- case 52: /* floating point store, int32 offset UGLY */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
- o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
- break;
-
- case 53: /* floating point load, int32 offset UGLY */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
- o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
- break;
-
- case 54: /* floating point arith */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- if(r == NREG) {
- r = rt;
- if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD)
- r = 0;
- }
- o1 |= rf | (r<<16) | (rt<<12);
- break;
-
- case 56: /* move to FP[CS]R */
- o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
- o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
- break;
-
- case 57: /* move from FP[CS]R */
- o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
- o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
- break;
- case 58: /* movbu R,R */
- o1 = oprrr(AAND, p->scond);
- o1 |= immrot(0xff);
- rt = p->to.reg;
- r = p->from.reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(r == NREG)
- r = rt;
- o1 |= (r<<16) | (rt<<12);
- break;
-
- case 59: /* movw/bu R<<I(R),R -> ldr indexed */
- if(p->from.reg == NREG) {
- if(p->as != AMOVW)
- diag("byte MOV from shifter operand");
- goto mov;
- }
- if(p->from.offset&(1<<4))
- diag("bad shift in LDR");
- o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
- if(p->as == AMOVBU)
- o1 |= 1<<22;
- break;
-
- case 60: /* movb R(R),R -> ldrsb indexed */
- if(p->from.reg == NREG) {
- diag("byte MOV from shifter operand");
- goto mov;
- }
- if(p->from.offset&(~0xf))
- diag("bad shift in LDRSB");
- o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
- o1 ^= (1<<5)|(1<<6);
- break;
-
- case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
- if(p->to.reg == NREG)
- diag("MOV to shifter operand");
- o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond);
- if(p->as == AMOVB || p->as == AMOVBU)
- o1 |= 1<<22;
- break;
-
- case 62: /* case R -> movw R<<2(PC),PC */
- o1 = olrr(p->from.reg, REGPC, REGPC, p->scond);
- o1 |= 2<<7;
- break;
-
- case 63: /* bcase */
- if(p->cond != P)
- o1 = p->cond->pc;
- break;
-
- /* reloc ops */
- case 64: /* mov/movb/movbu R,addr */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
- break;
-
- case 65: /* mov/movbu addr,R */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = olr(0, REGTMP, p->to.reg, p->scond);
- if(p->as == AMOVBU || p->as == AMOVB)
- o2 |= 1<<22;
- break;
-
- case 68: /* floating point store -> ADDR */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
- break;
-
- case 69: /* floating point load <- ADDR */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
- break;
-
- /* ArmV4 ops: */
- case 70: /* movh/movhu R,O(R) -> strh */
- aclass(&p->to);
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o1 = oshr(p->from.reg, instoffset, r, p->scond);
- break;
- case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
- aclass(&p->from);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 = olhr(instoffset, r, p->to.reg, p->scond);
- if(p->as == AMOVB)
- o1 ^= (1<<5)|(1<<6);
- else if(p->as == AMOVH)
- o1 ^= (1<<6);
- break;
- case 72: /* movh/movhu R,L(R) -> strh */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o2 = oshrr(p->from.reg, REGTMP,r, p->scond);
- break;
- case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 = olhrr(REGTMP, r, p->to.reg, p->scond);
- if(p->as == AMOVB)
- o2 ^= (1<<5)|(1<<6);
- else if(p->as == AMOVH)
- o2 ^= (1<<6);
- break;
- case 74: /* bx $I */
- diag("ABX $I");
- break;
- case 75: /* bx O(R) */
- aclass(&p->to);
- if(instoffset != 0)
- diag("non-zero offset in ABX");
-/*
- o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
- o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
-*/
- // p->to.reg may be REGLINK
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(instoffset);
- o1 |= p->to.reg << 16;
- o1 |= REGTMP << 12;
- o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
- o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
- break;
- case 76: /* bx O(R) when returning from fn*/
- diag("ABXRET");
- break;
- case 77: /* ldrex oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in LDREX");
- o1 = (0x19<<20) | (0xf9f);
- o1 |= p->from.reg << 16;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 78: /* strex reg,oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in STREX");
- o1 = (0x18<<20) | (0xf90);
- o1 |= p->from.reg << 16;
- o1 |= p->reg << 0;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 80: /* fmov zfcon,freg */
- if(p->as == AMOVD) {
- o1 = 0xeeb00b00; // VMOV imm 64
- o2 = oprrr(ASUBD, p->scond);
- } else {
- o1 = 0x0eb00a00; // VMOV imm 32
- o2 = oprrr(ASUBF, p->scond);
- }
- v = 0x70; // 1.0
- r = p->to.reg;
-
- // movf $1.0, r
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= r << 12;
- o1 |= (v&0xf) << 0;
- o1 |= (v&0xf0) << 12;
-
- // subf r,r,r
- o2 |= r | (r<<16) | (r<<12);
- break;
- case 81: /* fmov sfcon,freg */
- o1 = 0x0eb00a00; // VMOV imm 32
- if(p->as == AMOVD)
- o1 = 0xeeb00b00; // VMOV imm 64
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= p->to.reg << 12;
- v = chipfloat(&p->from.ieee);
- o1 |= (v&0xf) << 0;
- o1 |= (v&0xf0) << 12;
- break;
- case 82: /* fcmp freg,freg, */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->reg<<12) | (p->from.reg<<0);
- o2 = 0x0ef1fa10; // VMRS R15
- o2 |= (p->scond & C_SCOND) << 28;
- break;
- case 83: /* fcmp freg,, */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<12) | (1<<16);
- o2 = 0x0ef1fa10; // VMRS R15
- o2 |= (p->scond & C_SCOND) << 28;
- break;
- case 84: /* movfw freg,freg - truncate float-to-fix */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<0);
- o1 |= (p->to.reg<<12);
- break;
- case 85: /* movwf freg,freg - fix-to-float */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<0);
- o1 |= (p->to.reg<<12);
- break;
- case 86: /* movfw freg,reg - truncate float-to-fix */
- // macro for movfw freg,FTMP; movw FTMP,reg
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<0);
- o1 |= (FREGTMP<<12);
- o2 = oprrr(AMOVFW+AEND, p->scond);
- o2 |= (FREGTMP<<16);
- o2 |= (p->to.reg<<12);
- break;
- case 87: /* movwf reg,freg - fix-to-float */
- // macro for movw reg,FTMP; movwf FTMP,freg
- o1 = oprrr(AMOVWF+AEND, p->scond);
- o1 |= (p->from.reg<<12);
- o1 |= (FREGTMP<<16);
- o2 = oprrr(p->as, p->scond);
- o2 |= (FREGTMP<<0);
- o2 |= (p->to.reg<<12);
- break;
- case 88: /* movw reg,freg */
- o1 = oprrr(AMOVWF+AEND, p->scond);
- o1 |= (p->from.reg<<12);
- o1 |= (p->to.reg<<16);
- break;
- case 89: /* movw freg,reg */
- o1 = oprrr(AMOVFW+AEND, p->scond);
- o1 |= (p->from.reg<<16);
- o1 |= (p->to.reg<<12);
- break;
- case 90: /* tst reg */
- o1 = oprrr(ACMP+AEND, p->scond);
- o1 |= p->from.reg<<16;
- break;
- case 91: /* ldrexd oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in LDREX");
- o1 = (0x1b<<20) | (0xf9f);
- o1 |= p->from.reg << 16;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 92: /* strexd reg,oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in STREX");
- o1 = (0x1a<<20) | (0xf90);
- o1 |= p->from.reg << 16;
- o1 |= p->reg << 0;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = olhr(0, REGTMP, p->to.reg, p->scond);
- if(p->as == AMOVB)
- o2 ^= (1<<5)|(1<<6);
- else if(p->as == AMOVH)
- o2 ^= (1<<6);
- break;
- case 94: /* movh/movhu R,addr -> strh */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- o2 = oshr(p->from.reg, 0, REGTMP, p->scond);
- break;
- }
-
- out[0] = o1;
- out[1] = o2;
- out[2] = o3;
- out[3] = o4;
- out[4] = o5;
- out[5] = o6;
- return;
-
- v = p->pc;
- switch(o->size) {
- default:
- if(debug['a'])
- Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
- break;
- case 4:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
- lputl(o1);
- break;
- case 8:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p);
- lputl(o1);
- lputl(o2);
- break;
- case 12:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- break;
- case 16:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- break;
- case 20:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, o5, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- lputl(o5);
- break;
- case 24:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, o5, o6, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- lputl(o5);
- lputl(o6);
- break;
- }
-}
-
-int32
-oprrr(int a, int sc)
-{
- int32 o;
-
- o = (sc & C_SCOND) << 28;
- if(sc & C_SBIT)
- o |= 1 << 20;
- if(sc & (C_PBIT|C_WBIT))
- diag(".P/.W on dp instruction");
- switch(a) {
- case AMULU:
- case AMUL: return o | (0x0<<21) | (0x9<<4);
- case AMULA: return o | (0x1<<21) | (0x9<<4);
- case AMULLU: return o | (0x4<<21) | (0x9<<4);
- case AMULL: return o | (0x6<<21) | (0x9<<4);
- case AMULALU: return o | (0x5<<21) | (0x9<<4);
- case AMULAL: return o | (0x7<<21) | (0x9<<4);
- case AAND: return o | (0x0<<21);
- case AEOR: return o | (0x1<<21);
- case ASUB: return o | (0x2<<21);
- case ARSB: return o | (0x3<<21);
- case AADD: return o | (0x4<<21);
- case AADC: return o | (0x5<<21);
- case ASBC: return o | (0x6<<21);
- case ARSC: return o | (0x7<<21);
- case ATST: return o | (0x8<<21) | (1<<20);
- case ATEQ: return o | (0x9<<21) | (1<<20);
- case ACMP: return o | (0xa<<21) | (1<<20);
- case ACMN: return o | (0xb<<21) | (1<<20);
- case AORR: return o | (0xc<<21);
- case AMOVW: return o | (0xd<<21);
- case ABIC: return o | (0xe<<21);
- case AMVN: return o | (0xf<<21);
- case ASLL: return o | (0xd<<21) | (0<<5);
- case ASRL: return o | (0xd<<21) | (1<<5);
- case ASRA: return o | (0xd<<21) | (2<<5);
- case ASWI: return o | (0xf<<24);
-
- case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4);
- case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4);
- case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4);
- case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4);
- case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4);
- case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
- case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
- case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
- case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4);
- case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4);
- case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
- case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
-
- case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4);
- case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4);
-
- case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
- (1<<8); // dtof
- case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
- (0<<8); // dtof
-
- case AMOVWF:
- if((sc & C_UBIT) == 0)
- o |= 1<<7; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (0<<18) | (0<<8); // toint, double
- case AMOVWD:
- if((sc & C_UBIT) == 0)
- o |= 1<<7; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (0<<18) | (1<<8); // toint, double
-
- case AMOVFW:
- if((sc & C_UBIT) == 0)
- o |= 1<<16; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (1<<18) | (0<<8) | (1<<7); // toint, double, trunc
- case AMOVDW:
- if((sc & C_UBIT) == 0)
- o |= 1<<16; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (1<<18) | (1<<8) | (1<<7); // toint, double, trunc
-
- case AMOVWF+AEND: // copy WtoF
- return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
- case AMOVFW+AEND: // copy FtoW
- return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
- case ACMP+AEND: // cmp imm
- return o | (0x3<<24) | (0x5<<20);
- }
- diag("bad rrr %d", a);
- prasm(curp);
- return 0;
-}
-
-int32
-opbra(int a, int sc)
-{
-
- if(sc & (C_SBIT|C_PBIT|C_WBIT))
- diag(".S/.P/.W on bra instruction");
- sc &= C_SCOND;
- if(a == ABL)
- return (sc<<28)|(0x5<<25)|(0x1<<24);
- if(sc != 0xe)
- diag(".COND on bcond instruction");
- switch(a) {
- case ABEQ: return (0x0<<28)|(0x5<<25);
- case ABNE: return (0x1<<28)|(0x5<<25);
- case ABCS: return (0x2<<28)|(0x5<<25);
- case ABHS: return (0x2<<28)|(0x5<<25);
- case ABCC: return (0x3<<28)|(0x5<<25);
- case ABLO: return (0x3<<28)|(0x5<<25);
- case ABMI: return (0x4<<28)|(0x5<<25);
- case ABPL: return (0x5<<28)|(0x5<<25);
- case ABVS: return (0x6<<28)|(0x5<<25);
- case ABVC: return (0x7<<28)|(0x5<<25);
- case ABHI: return (0x8<<28)|(0x5<<25);
- case ABLS: return (0x9<<28)|(0x5<<25);
- case ABGE: return (0xa<<28)|(0x5<<25);
- case ABLT: return (0xb<<28)|(0x5<<25);
- case ABGT: return (0xc<<28)|(0x5<<25);
- case ABLE: return (0xd<<28)|(0x5<<25);
- case AB: return (0xe<<28)|(0x5<<25);
- }
- diag("bad bra %A", a);
- prasm(curp);
- return 0;
-}
-
-int32
-olr(int32 v, int b, int r, int sc)
-{
- int32 o;
-
- if(sc & C_SBIT)
- diag(".S on LDR/STR instruction");
- o = (sc & C_SCOND) << 28;
- if(!(sc & C_PBIT))
- o |= 1 << 24;
- if(!(sc & C_UBIT))
- o |= 1 << 23;
- if(sc & C_WBIT)
- o |= 1 << 21;
- o |= (1<<26) | (1<<20);
- if(v < 0) {
- if(sc & C_UBIT) diag(".U on neg offset");
- v = -v;
- o ^= 1 << 23;
- }
- if(v >= (1<<12) || v < 0)
- diag("literal span too large: %d (R%d)\n%P", v, b, PP);
- o |= v;
- o |= b << 16;
- o |= r << 12;
- return o;
-}
-
-int32
-olhr(int32 v, int b, int r, int sc)
-{
- int32 o;
-
- if(sc & C_SBIT)
- diag(".S on LDRH/STRH instruction");
- o = (sc & C_SCOND) << 28;
- if(!(sc & C_PBIT))
- o |= 1 << 24;
- if(sc & C_WBIT)
- o |= 1 << 21;
- o |= (1<<23) | (1<<20)|(0xb<<4);
- if(v < 0) {
- v = -v;
- o ^= 1 << 23;
- }
- if(v >= (1<<8) || v < 0)
- diag("literal span too large: %d (R%d)\n%P", v, b, PP);
- o |= (v&0xf)|((v>>4)<<8)|(1<<22);
- o |= b << 16;
- o |= r << 12;
- return o;
-}
-
-int32
-osr(int a, int r, int32 v, int b, int sc)
-{
- int32 o;
-
- o = olr(v, b, r, sc) ^ (1<<20);
- if(a != AMOVW)
- o |= 1<<22;
- return o;
-}
-
-int32
-oshr(int r, int32 v, int b, int sc)
-{
- int32 o;
-
- o = olhr(v, b, r, sc) ^ (1<<20);
- return o;
-}
-
-
-int32
-osrr(int r, int i, int b, int sc)
-{
-
- return olr(i, b, r, sc) ^ ((1<<25) | (1<<20));
-}
-
-int32
-oshrr(int r, int i, int b, int sc)
-{
- return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20));
-}
-
-int32
-olrr(int i, int b, int r, int sc)
-{
-
- return olr(i, b, r, sc) ^ (1<<25);
-}
-
-int32
-olhrr(int i, int b, int r, int sc)
-{
- return olhr(i, b, r, sc) ^ (1<<22);
-}
-
-int32
-ofsr(int a, int r, int32 v, int b, int sc, Prog *p)
-{
- int32 o;
-
- if(sc & C_SBIT)
- diag(".S on FLDR/FSTR instruction");
- o = (sc & C_SCOND) << 28;
- if(!(sc & C_PBIT))
- o |= 1 << 24;
- if(sc & C_WBIT)
- o |= 1 << 21;
- o |= (6<<25) | (1<<24) | (1<<23) | (10<<8);
- if(v < 0) {
- v = -v;
- o ^= 1 << 23;
- }
- if(v & 3)
- diag("odd offset for floating point op: %d\n%P", v, p);
- else
- if(v >= (1<<10) || v < 0)
- diag("literal span too large: %d\n%P", v, p);
- o |= (v>>2) & 0xFF;
- o |= b << 16;
- o |= r << 12;
-
- switch(a) {
- default:
- diag("bad fst %A", a);
- case AMOVD:
- o |= 1 << 8;
- case AMOVF:
- break;
- }
- return o;
-}
-
-int32
-omvl(Prog *p, Adr *a, int dr)
-{
- int32 v, o1;
- if(!p->cond) {
- aclass(a);
- v = immrot(~instoffset);
- if(v == 0) {
- diag("missing literal");
- prasm(p);
- return 0;
- }
- o1 = oprrr(AMVN, p->scond&C_SCOND);
- o1 |= v;
- o1 |= dr << 12;
- } else {
- v = p->cond->pc - p->pc - 8;
- o1 = olr(v, REGPC, dr, p->scond&C_SCOND);
- }
- return o1;
-}
-
-int
-chipzero(Ieee *e)
-{
- if(e->l != 0 || e->h != 0)
- return -1;
- return 0;
-}
-
-int
-chipfloat(Ieee *e)
-{
- int n;
- ulong h;
-
- if(e->l != 0 || (e->h&0xffff) != 0)
- goto no;
- h = e->h & 0x7fc00000;
- if(h != 0x40000000 && h != 0x3fc00000)
- goto no;
- n = 0;
-
- // sign bit (a)
- if(e->h & 0x80000000)
- n |= 1<<7;
-
- // exp sign bit (b)
- if(h == 0x3fc00000)
- n |= 1<<6;
-
- // rest of exp and mantissa (cd-efgh)
- n |= (e->h >> 16) & 0x3f;
-
-//print("match %.8lux %.8lux %d\n", e->l, e->h, n);
- return n;
-
-no:
- return -1;
-}
-
-
-void
-genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
-{
- Auto *a;
- Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- put(s, s->name, 'T', s->value, s->size, s->version, 0);
-
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->hash) {
- if(s->hide)
- continue;
- switch(s->type) {
- case SCONST:
- case SRODATA:
- case SDATA:
- case SELFDATA:
- case STYPE:
- case SSTRING:
- case SGOSTRING:
- if(!s->reachable)
- continue;
- put(s, s->name, 'D', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SBSS:
- if(!s->reachable)
- continue;
- put(s, s->name, 'B', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SFILE:
- put(nil, s->name, 'f', s->value, 0, s->version, 0);
- continue;
- }
- }
- }
-
- for(s = textp; s != nil; s = s->next) {
- /* filenames first */
- for(a=s->autom; a; a=a->link)
- if(a->type == D_FILE)
- put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
- else
- if(a->type == D_FILE1)
- put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
-
- put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
-
- /* frame, auto and param after */
- put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0);
-
- for(a=s->autom; a; a=a->link)
- if(a->type == D_AUTO)
- put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %ud\n", symsize);
- Bflush(&bso);
-}
-
-void
-setpersrc(Sym *s)
-{
- USED(s);
-}
diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go
deleted file mode 100644
index aa7ccebfc..000000000
--- a/src/cmd/5l/doc.go
+++ /dev/null
@@ -1,39 +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.
-
-/*
-
-5l is a modified version of the Plan 9 linker. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2l
-
-Its target architecture is the ARM, referred to by these tools as arm.
-It reads files in .5 format generated by 5g, 5c, and 5a and emits
-a binary called 5.out by default.
-
-Major changes include:
- - support for segmented stacks (this feature is implemented here, not in the compilers).
-
-
-Original options are listed in the link above.
-
-Options new in this version:
-
--F
- Force use of software floating point.
- Also implied by setting GOARM=5 in the environment.
--Hlinux
- Write Linux ELF binaries (default when $GOOS is linux)
--I interpreter
- Set the ELF dynamic linker to use.
--L dir1 -L dir2
- Search for libraries (package files) in dir1, dir2, etc.
- The default is the single location $GOROOT/pkg/$GOOS_arm.
--r dir1:dir2:...
- Set the dynamic linker search path when using ELF.
--V
- Print the linker version.
-
-*/
-package documentation
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
deleted file mode 100644
index 182f3e738..000000000
--- a/src/cmd/5l/l.h
+++ /dev/null
@@ -1,440 +0,0 @@
-// Inferno utils/5l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/l.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 <libc.h>
-#include <bio.h>
-#include "../5l/5.out.h"
-
-enum
-{
- thechar = '5',
- PtrSize = 4
-};
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-/* do not undefine this - code will be removed eventually */
-#define CALLEEBX
-
-#define dynptrsize 0
-
-typedef struct Adr Adr;
-typedef struct Sym Sym;
-typedef struct Autom Auto;
-typedef struct Prog Prog;
-typedef struct Reloc Reloc;
-typedef struct Optab Optab;
-typedef struct Oprang Oprang;
-typedef uchar Opcross[32][2][32];
-typedef struct Count Count;
-
-#define P ((Prog*)0)
-#define S ((Sym*)0)
-#define TNAME (cursym?cursym->name:noname)
-
-struct Adr
-{
- union
- {
- int32 u0offset;
- char* u0sval;
- Ieee u0ieee;
- char* u0sbig;
- } u0;
- Sym* sym;
- char type;
- uchar index; // not used on arm, required by ld/go.c
- char reg;
- char name;
- int32 offset2; // argsize
- char class;
- Sym* gotype;
-};
-
-#define offset u0.u0offset
-#define sval u0.u0sval
-#define scon sval
-#define ieee u0.u0ieee
-#define sbig u0.u0sbig
-
-struct Reloc
-{
- int32 off;
- uchar siz;
- int16 type;
- int32 add;
- Sym* sym;
-};
-
-struct Prog
-{
- Adr from;
- Adr to;
- union
- {
- int32 u0regused;
- Prog* u0forwd;
- } u0;
- Prog* cond;
- Prog* link;
- Prog* dlink;
- int32 pc;
- int32 line;
- int32 spadj;
- uchar mark;
- uchar optab;
- uchar as;
- uchar scond;
- uchar reg;
- uchar align;
-};
-
-#define regused u0.u0regused
-#define forwd u0.u0forwd
-#define datasize reg
-#define textflag reg
-
-#define iscall(p) ((p)->as == ABL)
-
-struct Sym
-{
- char* name;
- short type;
- short version;
- uchar dupok;
- uchar reachable;
- uchar dynexport;
- uchar leaf;
- uchar stkcheck;
- uchar hide;
- int32 dynid;
- int32 plt;
- int32 got;
- int32 value;
- int32 sig;
- int32 size;
- uchar special;
- uchar fnptr; // used as fn ptr
- Sym* hash; // in hash table
- Sym* allsym; // in all symbol list
- Sym* next; // in text or data list
- Sym* sub; // in SSUB list
- Sym* outer; // container of sub
- Sym* gotype;
- char* file;
- char* dynimpname;
- char* dynimplib;
- char* dynimpvers;
-
- // STEXT
- Auto* autom;
- Prog* text;
-
- // SDATA, SBSS
- uchar* p;
- int32 np;
- int32 maxp;
- Reloc* r;
- int32 nr;
- int32 maxr;
-};
-
-#define SIGNINTERN (1729*325*1729)
-
-struct Autom
-{
- Sym* asym;
- Auto* link;
- int32 aoffset;
- short type;
- Sym* gotype;
-};
-struct Optab
-{
- char as;
- uchar a1;
- char a2;
- uchar a3;
- uchar type;
- char size;
- char param;
- char flag;
-};
-struct Oprang
-{
- Optab* start;
- Optab* stop;
-};
-struct Count
-{
- int32 count;
- int32 outof;
-};
-
-enum
-{
- LFROM = 1<<0,
- LTO = 1<<1,
- LPOOL = 1<<2,
-
- C_NONE = 0,
- C_REG,
- C_REGREG,
- C_SHIFT,
- C_FREG,
- C_PSR,
- C_FCR,
-
- C_RCON, /* 0xff rotated */
- C_NCON, /* ~RCON */
- C_SCON, /* 0xffff */
- C_LCON,
- C_ZFCON,
- C_SFCON,
- C_LFCON,
-
- C_RACON,
- C_LACON,
-
- C_SBRA,
- C_LBRA,
-
- C_HAUTO, /* halfword insn offset (-0xff to 0xff) */
- C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */
- C_HFAUTO, /* both H and F */
- C_SAUTO, /* -0xfff to 0xfff */
- C_LAUTO,
-
- C_HOREG,
- C_FOREG,
- C_HFOREG,
- C_SOREG,
- C_ROREG,
- C_SROREG, /* both S and R */
- C_LOREG,
-
- C_PC,
- C_SP,
- C_HREG,
-
- C_ADDR, /* reference to relocatable address */
-
- C_GOK,
-
-/* mark flags */
- FOLL = 1<<0,
- LABEL = 1<<1,
- LEAF = 1<<2,
-
- STRINGSZ = 200,
- MINSIZ = 64,
- NENT = 100,
- MAXIO = 8192,
- MAXHIST = 20, /* limit of path elements for history symbols */
- MINLC = 4,
-};
-
-EXTERN union
-{
- struct
- {
- uchar obuf[MAXIO]; /* output buffer */
- uchar ibuf[MAXIO]; /* input buffer */
- } u;
- char dbuf[1];
-} buf;
-
-#define cbuf u.obuf
-#define xbuf u.ibuf
-
-#ifndef COFFCVT
-
-EXTERN int32 HEADR; /* length of header */
-EXTERN int HEADTYPE; /* type of header */
-EXTERN int32 INITDAT; /* data location */
-EXTERN int32 INITRND; /* data round above text location */
-EXTERN int32 INITTEXT; /* text location */
-EXTERN char* INITENTRY; /* entry point */
-EXTERN int32 autosize;
-EXTERN Biobuf bso;
-EXTERN int cbc;
-EXTERN uchar* cbp;
-EXTERN int cout;
-EXTERN Auto* curauto;
-EXTERN Auto* curhist;
-EXTERN Prog* curp;
-EXTERN Sym* cursym;
-EXTERN Sym* datap;
-EXTERN int32 elfdatsize;
-EXTERN char debug[128];
-EXTERN Sym* etextp;
-EXTERN char* noname;
-EXTERN Prog* lastp;
-EXTERN int32 lcsize;
-EXTERN char literal[32];
-EXTERN int nerrors;
-EXTERN int32 instoffset;
-EXTERN Opcross opcross[8];
-EXTERN Oprang oprange[ALAST];
-EXTERN char* outfile;
-EXTERN int32 pc;
-EXTERN uchar repop[ALAST];
-EXTERN char* interpreter;
-EXTERN char* rpath;
-EXTERN uint32 stroffset;
-EXTERN int32 symsize;
-EXTERN Sym* textp;
-EXTERN int32 textsize;
-EXTERN int version;
-EXTERN char xcmp[C_GOK+1][C_GOK+1];
-EXTERN Prog zprg;
-EXTERN int dtype;
-EXTERN int armsize;
-
-extern char* anames[];
-extern Optab optab[];
-
-void addpool(Prog*, Adr*);
-EXTERN Prog* blitrl;
-EXTERN Prog* elitrl;
-
-void initdiv(void);
-EXTERN Prog* prog_div;
-EXTERN Prog* prog_divu;
-EXTERN Prog* prog_mod;
-EXTERN Prog* prog_modu;
-
-#pragma varargck type "A" int
-#pragma varargck type "C" int
-#pragma varargck type "D" Adr*
-#pragma varargck type "N" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "S" char*
-
-int Aconv(Fmt*);
-int Cconv(Fmt*);
-int Dconv(Fmt*);
-int Iconv(Fmt*);
-int Nconv(Fmt*);
-int Oconv(Fmt*);
-int Pconv(Fmt*);
-int Sconv(Fmt*);
-int aclass(Adr*);
-void addhist(int32, int);
-Prog* appendp(Prog*);
-void asmb(void);
-void asmout(Prog*, Optab*, int32*);
-int32 atolwhex(char*);
-Prog* brloop(Prog*);
-void buildop(void);
-void buildrep(int, int);
-void cflush(void);
-int chipzero(Ieee*);
-int chipfloat(Ieee*);
-int cmp(int, int);
-int compound(Prog*);
-double cputime(void);
-void diag(char*, ...);
-void divsig(void);
-void dodata(void);
-void doprof1(void);
-void doprof2(void);
-int32 entryvalue(void);
-void exchange(Prog*);
-void follow(void);
-void hputl(int);
-int isnop(Prog*);
-void listinit(void);
-Sym* lookup(char*, int);
-void cput(int);
-void hput(int32);
-void lput(int32);
-void lputb(int32);
-void lputl(int32);
-void* mysbrk(uint32);
-void names(void);
-void nocache(Prog*);
-int ocmp(const void*, const void*);
-int32 opirr(int);
-Optab* oplook(Prog*);
-int32 oprrr(int, int);
-int32 olr(int32, int, int, int);
-int32 olhr(int32, int, int, int);
-int32 olrr(int, int, int, int);
-int32 olhrr(int, int, int, int);
-int32 osr(int, int, int32, int, int);
-int32 oshr(int, int32, int, int);
-int32 ofsr(int, int, int32, int, int, Prog*);
-int32 osrr(int, int, int, int);
-int32 oshrr(int, int, int, int);
-int32 omvl(Prog*, Adr*, int);
-void patch(void);
-void prasm(Prog*);
-void prepend(Prog*, Prog*);
-Prog* prg(void);
-int pseudo(Prog*);
-int32 regoff(Adr*);
-int relinv(int);
-int32 rnd(int32, int32);
-void softfloat(void);
-void span(void);
-void strnput(char*, int);
-int32 symaddr(Sym*);
-void undef(void);
-void wput(int32);
-void wputl(ushort w);
-void xdefine(char*, int, int32);
-void noops(void);
-int32 immrot(uint32);
-int32 immaddr(int32);
-int32 opbra(int, int);
-int brextra(Prog*);
-int isbranch(Prog*);
-void fnptrs(void);
-void doelf(void);
-
-vlong addaddr(Sym *s, Sym *t);
-vlong addsize(Sym *s, Sym *t);
-vlong addstring(Sym *s, char *str);
-vlong adduint16(Sym *s, uint16 v);
-vlong adduint32(Sym *s, uint32 v);
-vlong adduint64(Sym *s, uint64 v);
-vlong adduint8(Sym *s, uint8 v);
-vlong adduintxx(Sym *s, uint64 v, int wid);
-
-/* Native is little-endian */
-#define LPUT(a) lputl(a)
-#define WPUT(a) wputl(a)
-#define VPUT(a) abort()
-
-#endif
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
deleted file mode 100644
index fa838215b..000000000
--- a/src/cmd/5l/list.c
+++ /dev/null
@@ -1,487 +0,0 @@
-// 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)
-// 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.
-
-// Printing.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-listinit(void)
-{
-
- fmtinstall('A', Aconv);
- fmtinstall('C', Cconv);
- fmtinstall('D', Dconv);
- fmtinstall('P', Pconv);
- fmtinstall('S', Sconv);
- fmtinstall('N', Nconv);
- fmtinstall('O', Oconv); // C_type constants
- fmtinstall('I', Iconv);
-}
-
-void
-prasm(Prog *p)
-{
- print("%P\n", p);
-}
-
-int
-Pconv(Fmt *fp)
-{
- Prog *p;
- int a;
-
- p = va_arg(fp->args, Prog*);
- curp = p;
- a = p->as;
- switch(a) {
- default:
- fmtprint(fp, "(%d)", p->line);
- if(p->reg == NREG)
- fmtprint(fp, " %A%C %D,%D",
- a, p->scond, &p->from, &p->to);
- else
- if(p->from.type != D_FREG)
- fmtprint(fp, " %A%C %D,R%d,%D",
- a, p->scond, &p->from, p->reg, &p->to);
- else
- fmtprint(fp, " %A%C %D,F%d,%D",
- a, p->scond, &p->from, p->reg, &p->to);
- break;
-
- case ASWPW:
- case ASWPBU:
- fmtprint(fp, "(%d) %A%C R%d,%D,%D",
- p->line, a, p->scond, p->reg, &p->from, &p->to);
- break;
-
- case ADATA:
- case AINIT_:
- case ADYNT_:
- fmtprint(fp, "(%d) %A%C %D/%d,%D",
- p->line, a, p->scond, &p->from, p->reg, &p->to);
- break;
-
- case AWORD:
- fmtprint(fp, "(%d) WORD %D", p->line, &p->to);
- break;
-
- case ADWORD:
- fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to);
- break;
- }
-
- if(p->spadj)
- fmtprint(fp, " (spadj%+d)", p->spadj);
-
- return 0;
-}
-
-int
-Aconv(Fmt *fp)
-{
- char *s;
- int a;
-
- a = va_arg(fp->args, int);
- s = "???";
- if(a >= AXXX && a < ALAST)
- s = anames[a];
- return fmtstrcpy(fp, s);
-}
-
-char* strcond[16] =
-{
- ".EQ",
- ".NE",
- ".HS",
- ".LO",
- ".MI",
- ".PL",
- ".VS",
- ".VC",
- ".HI",
- ".LS",
- ".GE",
- ".LT",
- ".GT",
- ".LE",
- "",
- ".NV"
-};
-
-int
-Cconv(Fmt *fp)
-{
- char s[20];
- int c;
-
- c = va_arg(fp->args, int);
- strcpy(s, strcond[c & C_SCOND]);
- if(c & C_SBIT)
- strcat(s, ".S");
- if(c & C_PBIT)
- strcat(s, ".P");
- if(c & C_WBIT)
- strcat(s, ".W");
- if(c & C_UBIT) /* ambiguous with FBIT */
- strcat(s, ".U");
- return fmtstrcpy(fp, s);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ];
- char *op;
- Adr *a;
- int32 v;
-
- a = va_arg(fp->args, Adr*);
- switch(a->type) {
-
- default:
- snprint(str, sizeof str, "GOK-type(%d)", a->type);
- break;
-
- case D_NONE:
- str[0] = 0;
- if(a->name != D_NONE || a->reg != NREG || a->sym != S)
- snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg);
- break;
-
- case D_CONST:
- if(a->reg == NREG)
- snprint(str, sizeof str, "$%N", a);
- else
- snprint(str, sizeof str, "$%N(R%d)", a, a->reg);
- break;
-
- case D_CONST2:
- snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
- break;
-
- case D_SHIFT:
- v = a->offset;
- op = "<<>>->@>" + (((v>>5) & 3) << 1);
- if(v & (1<<4))
- snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
- else
- snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
- if(a->reg != NREG)
- seprint(str+strlen(str), str+sizeof str, "(R%d)", a->reg);
- break;
-
- case D_OCONST:
- snprint(str, sizeof str, "$*$%N", a);
- if(a->reg != NREG)
- snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg);
- break;
-
- case D_OREG:
- if(a->reg != NREG)
- snprint(str, sizeof str, "%N(R%d)", a, a->reg);
- else
- snprint(str, sizeof str, "%N", a);
- break;
-
- case D_REG:
- snprint(str, sizeof str, "R%d", a->reg);
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_REGREG:
- snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset);
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_FREG:
- snprint(str, sizeof str, "F%d", a->reg);
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_PSR:
- switch(a->reg) {
- case 0:
- snprint(str, sizeof str, "CPSR");
- break;
- case 1:
- snprint(str, sizeof str, "SPSR");
- break;
- default:
- snprint(str, sizeof str, "PSR%d", a->reg);
- break;
- }
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg);
- break;
-
- case D_FPCR:
- switch(a->reg){
- case 0:
- snprint(str, sizeof str, "FPSR");
- break;
- case 1:
- snprint(str, sizeof str, "FPCR");
- break;
- default:
- snprint(str, sizeof str, "FCR%d", a->reg);
- break;
- }
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg);
-
- break;
-
- case D_BRANCH: /* botch */
- if(curp->cond != P) {
- v = curp->cond->pc;
- if(a->sym != S)
- snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v);
- else
- snprint(str, sizeof str, "%.5ux(BRANCH)", v);
- } else
- if(a->sym != S)
- snprint(str, sizeof str, "%s+%d(APC)", a->sym->name, a->offset);
- else
- snprint(str, sizeof str, "%d(APC)", a->offset);
- break;
-
- case D_FCONST:
- snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee));
- break;
-
- case D_SCONST:
- snprint(str, sizeof str, "$\"%S\"", a->sval);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Nconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Adr *a;
- Sym *s;
-
- a = va_arg(fp->args, Adr*);
- s = a->sym;
- switch(a->name) {
- default:
- sprint(str, "GOK-name(%d)", a->name);
- break;
-
- case D_NONE:
- sprint(str, "%d", a->offset);
- break;
-
- case D_EXTERN:
- if(s == S)
- sprint(str, "%d(SB)", a->offset);
- else
- sprint(str, "%s+%d(SB)", s->name, a->offset);
- break;
-
- case D_STATIC:
- if(s == S)
- sprint(str, "<>+%d(SB)", a->offset);
- else
- sprint(str, "%s<>+%d(SB)", s->name, a->offset);
- break;
-
- case D_AUTO:
- if(s == S)
- sprint(str, "%d(SP)", a->offset);
- else
- sprint(str, "%s-%d(SP)", s->name, -a->offset);
- break;
-
- case D_PARAM:
- if(s == S)
- sprint(str, "%d(FP)", a->offset);
- else
- sprint(str, "%s+%d(FP)", s->name, a->offset);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(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);
-}
-
-int
-Iconv(Fmt *fp)
-{
- int i, n;
- uint32 *p;
- char *s;
- Fmt fmt;
-
- n = fp->prec;
- fp->prec = 0;
- if(!(fp->flags&FmtPrec) || n < 0)
- return fmtstrcpy(fp, "%I");
- fp->flags &= ~FmtPrec;
- p = va_arg(fp->args, uint32*);
-
- // format into temporary buffer and
- // call fmtstrcpy to handle padding.
- fmtstrinit(&fmt);
- for(i=0; i<n/4; i++) {
- if(i > 0)
- fmtprint(&fmt, " ");
- fmtprint(&fmt, "%.8ux", *p++);
- }
- s = fmtstrflush(&fmt);
- fmtstrcpy(fp, s);
- free(s);
- return 0;
-}
-
-static char*
-cnames[] =
-{
- [C_ADDR] = "C_ADDR",
- [C_FAUTO] = "C_FAUTO",
- [C_ZFCON] = "C_SFCON",
- [C_SFCON] = "C_SFCON",
- [C_LFCON] = "C_LFCON",
- [C_FCR] = "C_FCR",
- [C_FOREG] = "C_FOREG",
- [C_FREG] = "C_FREG",
- [C_GOK] = "C_GOK",
- [C_HAUTO] = "C_HAUTO",
- [C_HFAUTO] = "C_HFAUTO",
- [C_HFOREG] = "C_HFOREG",
- [C_HOREG] = "C_HOREG",
- [C_HREG] = "C_HREG",
- [C_LACON] = "C_LACON",
- [C_LAUTO] = "C_LAUTO",
- [C_LBRA] = "C_LBRA",
- [C_LCON] = "C_LCON",
- [C_LOREG] = "C_LOREG",
- [C_NCON] = "C_NCON",
- [C_NONE] = "C_NONE",
- [C_PC] = "C_PC",
- [C_PSR] = "C_PSR",
- [C_RACON] = "C_RACON",
- [C_RCON] = "C_RCON",
- [C_REG] = "C_REG",
- [C_REGREG] = "C_REGREG",
- [C_ROREG] = "C_ROREG",
- [C_SAUTO] = "C_SAUTO",
- [C_SBRA] = "C_SBRA",
- [C_SCON] = "C_SCON",
- [C_SHIFT] = "C_SHIFT",
- [C_SOREG] = "C_SOREG",
- [C_SP] = "C_SP",
- [C_SROREG] = "C_SROREG"
-};
-
-int
-Oconv(Fmt *fp)
-{
- char buf[500];
- int o;
-
- o = va_arg(fp->args, int);
- if(o < 0 || o >= nelem(cnames) || cnames[o] == nil) {
- snprint(buf, sizeof(buf), "C_%d", o);
- return fmtstrcpy(fp, buf);
- }
- return fmtstrcpy(fp, cnames[o]);
-}
-
-void
-diag(char *fmt, ...)
-{
- char buf[STRINGSZ], *tn, *sep;
- va_list arg;
-
- tn = "";
- sep = "";
- if(cursym != S) {
- tn = cursym->name;
- sep = ": ";
- }
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- print("%s%s%s\n", tn, sep, buf);
-
- nerrors++;
- if(nerrors > 20) {
- print("too many errors\n");
- errorexit();
- }
-}
diff --git a/src/cmd/5l/mkenam b/src/cmd/5l/mkenam
deleted file mode 100644
index 6cccb0263..000000000
--- a/src/cmd/5l/mkenam
+++ /dev/null
@@ -1,45 +0,0 @@
-# Inferno utils/5c/mkenam
-# http://code.google.com/p/inferno-os/source/browse/utils/5c/mkenam
-#
-# 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.
-
-awk '
-BEGIN {
- print "char* anames[] ="
- print "{"
-}
-
-/^ A/ {
- name=$1
- sub(/,/, "", name)
- sub(/^A/, "", name)
- print "\t\"" name "\","
-}
-
-END { print "};" }
-' ../5l/5.out.h >enam.c
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
deleted file mode 100644
index eb44344f4..000000000
--- a/src/cmd/5l/noop.c
+++ /dev/null
@@ -1,539 +0,0 @@
-// Inferno utils/5l/noop.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/noop.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.
-
-// Code transformations.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-// see ../../runtime/proc.c:/StackGuard
-enum
-{
- StackBig = 4096,
- StackSmall = 128,
-};
-
-static Sym* sym_div;
-static Sym* sym_divu;
-static Sym* sym_mod;
-static Sym* sym_modu;
-
-void
-noops(void)
-{
- Prog *p, *q, *q1;
- int o;
- Prog *pmorestack;
- Sym *symmorestack;
-
- /*
- * find leaf subroutines
- * strip NOPs
- * expand RET
- * expand BECOME pseudo
- */
-
- if(debug['v'])
- Bprint(&bso, "%5.2f noops\n", cputime());
- Bflush(&bso);
-
- symmorestack = lookup("runtime.morestack", 0);
- if(symmorestack->type != STEXT) {
- diag("runtime·morestack not defined");
- errorexit();
- }
- pmorestack = symmorestack->text;
- pmorestack->reg |= NOSPLIT;
-
- q = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- switch(p->as) {
- case ATEXT:
- p->mark |= LEAF;
- break;
-
- case ARET:
- break;
-
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- q = p;
- if(prog_div == P)
- initdiv();
- cursym->text->mark &= ~LEAF;
- continue;
-
- case ANOP:
- q1 = p->link;
- q->link = q1; /* q is non-nop */
- if(q1 != P)
- q1->mark |= p->mark;
- continue;
-
- case ABL:
- case ABX:
- cursym->text->mark &= ~LEAF;
-
- case ABCASE:
- case AB:
-
- case ABEQ:
- 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:
- q1 = p->cond;
- if(q1 != P) {
- while(q1->as == ANOP) {
- q1 = q1->link;
- p->cond = q1;
- }
- }
- break;
- }
- q = p;
- }
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- o = p->as;
- switch(o) {
- case ATEXT:
- autosize = p->to.offset + 4;
- if(autosize <= 4)
- if(cursym->text->mark & LEAF) {
- p->to.offset = -4;
- autosize = 0;
- }
-
- if(!autosize && !(cursym->text->mark & LEAF)) {
- if(debug['v'])
- Bprint(&bso, "save suppressed in: %s\n",
- cursym->name);
- Bflush(&bso);
- cursym->text->mark |= LEAF;
- }
- if(cursym->text->mark & LEAF) {
- cursym->leaf = 1;
- if(!autosize)
- break;
- }
-
- if(p->reg & NOSPLIT) {
- q1 = prg();
- q1->as = AMOVW;
- q1->scond |= C_WBIT;
- q1->line = p->line;
- q1->from.type = D_REG;
- q1->from.reg = REGLINK;
- q1->to.type = D_OREG;
- q1->to.offset = -autosize;
- q1->to.reg = REGSP;
- q1->spadj = autosize;
- q1->link = p->link;
- p->link = q1;
- } else if (autosize < StackBig) {
- // split stack check for small functions
- // MOVW g_stackguard(g), R1
- // CMP R1, $-autosize(SP)
- // MOVW.LO $autosize, R1
- // MOVW.LO $args, R2
- // MOVW.LO R14, R3
- // BL.LO runtime.morestack(SB) // modifies LR
- // MOVW.W R14,$-autosize(SP)
-
- // TODO(kaib): add more trampolines
- // TODO(kaib): put stackguard in register
- // TODO(kaib): add support for -K and underflow detection
-
- // MOVW g_stackguard(g), R1
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.reg = REGG;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- if(autosize < StackSmall) {
- // CMP R1, SP
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->reg = REGSP;
- } else {
- // MOVW $-autosize(SP), R2
- // CMP R1, R2
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.reg = REGSP;
- p->from.offset = -autosize;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->reg = 2;
- }
-
- // MOVW.LO $autosize, R1
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_CONST;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
- p->from.offset = autosize+160;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW.LO $args, R2
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_CONST;
- p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW.LO R14, R3
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- // BL.LO runtime.morestack(SB) // modifies LR
- p = appendp(p);
- p->as = ABL;
- p->scond = C_SCOND_LO;
- p->to.type = D_BRANCH;
- p->to.sym = symmorestack;
- p->cond = pmorestack;
-
- // MOVW.W R14,$-autosize(SP)
- p = appendp(p);
- p->as = AMOVW;
- p->scond |= C_WBIT;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_OREG;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- p->spadj = autosize;
- } else { // > StackBig
- // MOVW $autosize, R1
- // MOVW $args, R2
- // MOVW R14, R3
- // BL runtime.morestack(SB) // modifies LR
- // MOVW.W R14,$-autosize(SP)
-
- // MOVW $autosize, R1
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW $args, R2
- // also need to store the extra 4 bytes.
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW R14, R3
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- // BL runtime.morestack(SB) // modifies LR
- p = appendp(p);
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = symmorestack;
- p->cond = pmorestack;
-
- // MOVW.W R14,$-autosize(SP)
- p = appendp(p);
- p->as = AMOVW;
- p->scond |= C_WBIT;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_OREG;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- p->spadj = autosize;
- }
- break;
-
- case ARET:
- nocache(p);
- if(cursym->text->mark & LEAF) {
- if(!autosize) {
- p->as = AB;
- p->from = zprg.from;
- p->to.type = D_OREG;
- p->to.offset = 0;
- p->to.reg = REGLINK;
- break;
- }
- }
- p->as = AMOVW;
- p->scond |= C_PBIT;
- p->from.type = D_OREG;
- p->from.offset = autosize;
- p->from.reg = REGSP;
- p->to.type = D_REG;
- p->to.reg = REGPC;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so no spadj.
- break;
-
- case AADD:
- if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
- p->spadj = -p->from.offset;
- break;
-
- case ASUB:
- if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
- p->spadj = p->from.offset;
- break;
-
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- if(debug['M'])
- break;
- if(p->from.type != D_REG)
- break;
- if(p->to.type != D_REG)
- break;
- q1 = p;
-
- /* MOV a,4(SP) */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = q1->from.reg;
- p->to.type = D_OREG;
- p->to.reg = REGSP;
- p->to.offset = 4;
-
- /* MOV b,REGTMP */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = q1->reg;
- if(q1->reg == NREG)
- p->from.reg = q1->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
- p->to.offset = 0;
-
- /* CALL appropriate */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = ABL;
- p->line = q1->line;
- p->to.type = D_BRANCH;
- p->cond = p;
- switch(o) {
- case ADIV:
- p->cond = prog_div;
- p->to.sym = sym_div;
- break;
- case ADIVU:
- p->cond = prog_divu;
- p->to.sym = sym_divu;
- break;
- case AMOD:
- p->cond = prog_mod;
- p->to.sym = sym_mod;
- break;
- case AMODU:
- p->cond = prog_modu;
- p->to.sym = sym_modu;
- break;
- }
-
- /* MOV REGTMP, b */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = REGTMP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = q1->to.reg;
-
- /* ADD $8,SP */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.reg = NREG;
- p->from.offset = 8;
- p->reg = NREG;
- p->to.type = D_REG;
- p->to.reg = REGSP;
- p->spadj = -8;
-
- /* SUB $8,SP */
- q1->as = ASUB;
- q1->from.type = D_CONST;
- q1->from.offset = 8;
- q1->from.reg = NREG;
- q1->reg = NREG;
- q1->to.type = D_REG;
- q1->to.reg = REGSP;
- q1->spadj = 8;
-
- break;
- case AMOVW:
- if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
- p->spadj = -p->to.offset;
- if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
- p->spadj = -p->from.offset;
- if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
- p->spadj = -p->from.offset;
- break;
- }
- }
- }
-}
-
-static void
-sigdiv(char *n)
-{
- Sym *s;
-
- s = lookup(n, 0);
- if(s->type == STEXT)
- if(s->sig == 0)
- s->sig = SIGNINTERN;
-}
-
-void
-divsig(void)
-{
- sigdiv("_div");
- sigdiv("_divu");
- sigdiv("_mod");
- sigdiv("_modu");
-}
-
-void
-initdiv(void)
-{
- Sym *s2, *s3, *s4, *s5;
-
- if(prog_div != P)
- return;
- sym_div = s2 = lookup("_div", 0);
- sym_divu = s3 = lookup("_divu", 0);
- sym_mod = s4 = lookup("_mod", 0);
- sym_modu = s5 = lookup("_modu", 0);
- prog_div = s2->text;
- prog_divu = s3->text;
- prog_mod = s4->text;
- prog_modu = s5->text;
- if(prog_div == P) {
- diag("undefined: %s", s2->name);
- prog_div = cursym->text;
- }
- if(prog_divu == P) {
- diag("undefined: %s", s3->name);
- prog_divu = cursym->text;
- }
- if(prog_mod == P) {
- diag("undefined: %s", s4->name);
- prog_mod = cursym->text;
- }
- if(prog_modu == P) {
- diag("undefined: %s", s5->name);
- prog_modu = cursym->text;
- }
-}
-
-void
-nocache(Prog *p)
-{
- p->optab = 0;
- p->from.class = 0;
- p->to.class = 0;
-}
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
deleted file mode 100644
index dd3a7329a..000000000
--- a/src/cmd/5l/obj.c
+++ /dev/null
@@ -1,757 +0,0 @@
-// 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.
-
-#define EXTERN
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-#include <ar.h>
-
-#ifndef DEFAULT
-#define DEFAULT '9'
-#endif
-
-char *noname = "<none>";
-char *thestring = "arm";
-
-Header headers[] = {
- "noheader", Hnoheader,
- "risc", Hrisc,
- "plan9", Hplan9x32,
- "netbsd", Hnetbsd,
- "ixp1200", Hixp1200,
- "ipaq", Hipaq,
- "linux", Hlinux,
- 0, 0
-};
-
-/*
- * -Hrisc -T0x10005000 -R4 is aif for risc os
- * -Hplan9 -T4128 -R4096 is plan9 format
- * -Hnetbsd -T0xF0000020 -R4 is NetBSD format
- * -Hixp1200 is IXP1200 (raw)
- * -Hipaq -T0xC0008010 -R1024 is ipaq
- * -Hlinux -Tx -Rx is linux elf
- */
-
-static char*
-linkername[] =
-{
- "runtime.softfloat",
- "math.sqrtGoC",
-};
-
-void
-usage(void)
-{
- fprint(2, "usage: 5l [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-D data] [-R rnd] [-r path] [-o out] main.5\n");
- errorexit();
-}
-
-void
-main(int argc, char *argv[])
-{
- int c, i;
- char *p;
-
- Binit(&bso, 1, OWRITE);
- cout = -1;
- listinit();
- nerrors = 0;
- outfile = "5.out";
- HEADTYPE = -1;
- INITTEXT = -1;
- INITDAT = -1;
- INITRND = -1;
- INITENTRY = 0;
-
- p = getenv("GOARM");
- if(p != nil && strcmp(p, "5") == 0)
- debug['F'] = 1;
-
- ARGBEGIN {
- default:
- c = ARGC();
- if(c == 'l')
- usage();
- if(c >= 0 && c < sizeof(debug))
- debug[c]++;
- break;
- case 'o':
- outfile = EARGF(usage());
- break;
- case 'E':
- INITENTRY = EARGF(usage());
- break;
- case 'I':
- interpreter = EARGF(usage());
- break;
- case 'L':
- Lflag(EARGF(usage()));
- break;
- case 'T':
- INITTEXT = atolwhex(EARGF(usage()));
- break;
- case 'D':
- INITDAT = atolwhex(EARGF(usage()));
- break;
- case 'R':
- INITRND = atolwhex(EARGF(usage()));
- break;
- case 'r':
- rpath = EARGF(usage());
- break;
- case 'H':
- HEADTYPE = headtype(EARGF(usage()));
- /* do something about setting INITTEXT */
- break;
- case 'V':
- print("%cl version %s\n", thechar, getgoversion());
- errorexit();
- } ARGEND
-
- USED(argc);
-
- if(argc != 1)
- usage();
-
- libinit();
-
- if(!debug['9'] && !debug['U'] && !debug['B'])
- debug[DEFAULT] = 1;
- if(HEADTYPE == -1) {
- if(debug['U'])
- HEADTYPE = Hnoheader;
- if(debug['B'])
- HEADTYPE = Hrisc;
- if(debug['9'])
- HEADTYPE = Hplan9x32;
- HEADTYPE = Hlinux;
- }
- switch(HEADTYPE) {
- default:
- diag("unknown -H option");
- errorexit();
- case Hnoheader: /* no header */
- HEADR = 0L;
- if(INITTEXT == -1)
- INITTEXT = 0;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hrisc: /* aif for risc os */
- HEADR = 128L;
- if(INITTEXT == -1)
- INITTEXT = 0x10005000 + HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hplan9x32: /* plan 9 */
- HEADR = 32L;
- if(INITTEXT == -1)
- INITTEXT = 4128;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Hnetbsd: /* boot for NetBSD */
- HEADR = 32L;
- if(INITTEXT == -1)
- INITTEXT = 0xF0000020L;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Hixp1200: /* boot for IXP1200 */
- HEADR = 0L;
- if(INITTEXT == -1)
- INITTEXT = 0x0;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hipaq: /* boot for ipaq */
- HEADR = 16L;
- if(INITTEXT == -1)
- INITTEXT = 0xC0008010;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 1024;
- break;
- case Hlinux: /* arm elf */
- debug['d'] = 1; // no dynamic linking
- elfinit();
- HEADR = ELFRESERVE;
- if(INITTEXT == -1)
- INITTEXT = 0x10000 + HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- }
- if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%ux is ignored because of -R0x%ux\n",
- INITDAT, INITRND);
- if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
- HEADTYPE, INITTEXT, INITDAT, INITRND);
- Bflush(&bso);
- zprg.as = AGOK;
- zprg.scond = 14;
- zprg.reg = NREG;
- zprg.from.name = D_NONE;
- zprg.from.type = D_NONE;
- zprg.from.reg = NREG;
- zprg.to = zprg.from;
- buildop();
- histgen = 0;
- pc = 0;
- dtype = 4;
- nuxiinit();
-
- version = 0;
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
-
- addlibpath("command line", "command line", argv[0], "main");
- loadlib();
-
- // mark some functions that are only referenced after linker code editing
- // TODO(kaib): this doesn't work, the prog can't be found in runtime
- for(i=0; i<nelem(linkername); i++)
- mark(lookup(linkername[i], 0));
- deadcode();
- if(textp == nil) {
- diag("no code");
- errorexit();
- }
-
- patch();
- if(debug['p'])
- if(debug['1'])
- doprof1();
- else
- doprof2();
- doelf();
- follow();
- softfloat();
- noops();
- dostkcheck();
- span();
- pclntab();
- symtab();
- dodata();
- address();
- doweak();
- reloc();
- asmb();
- undef();
-
- if(debug['c'])
- print("ARM size = %d\n", armsize);
- if(debug['v']) {
- Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
- Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
- }
- Bflush(&bso);
- errorexit();
-}
-
-static void
-zaddr(Biobuf *f, Adr *a, Sym *h[])
-{
- int i, c;
- int32 l;
- Sym *s;
- Auto *u;
-
- a->type = Bgetc(f);
- a->reg = Bgetc(f);
- c = Bgetc(f);
- if(c < 0 || c > NSYM){
- print("sym out of range: %d\n", c);
- Bputc(f, ALAST+1);
- return;
- }
- a->sym = h[c];
- a->name = Bgetc(f);
-
- if((schar)a->reg < 0 || a->reg > NREG) {
- print("register out of range %d\n", a->reg);
- Bputc(f, ALAST+1);
- return; /* force real diagnostic */
- }
-
- if(a->type == D_CONST || a->type == D_OCONST) {
- if(a->name == D_EXTERN || a->name == D_STATIC) {
- s = a->sym;
- if(s != S && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) {
- if(0 && !s->fnptr && s->name[0] != '.')
- print("%s used as function pointer\n", s->name);
- s->fnptr = 1; // over the top cos of SXREF
- }
- }
- }
-
- switch(a->type) {
- default:
- print("unknown type %d\n", a->type);
- Bputc(f, ALAST+1);
- return; /* force real diagnostic */
-
- case D_NONE:
- case D_REG:
- case D_FREG:
- case D_PSR:
- case D_FPCR:
- break;
-
- case D_REGREG:
- a->offset = Bgetc(f);
- c++;
- break;
-
- case D_CONST2:
- a->offset2 = Bget4(f); // fall through
- case D_BRANCH:
- case D_OREG:
- case D_CONST:
- case D_OCONST:
- case D_SHIFT:
- a->offset = Bget4(f);
- break;
-
- case D_SCONST:
- a->sval = mal(NSNAME);
- Bread(f, a->sval, NSNAME);
- c += NSNAME;
- break;
-
- case D_FCONST:
- a->ieee.l = Bget4(f);
- a->ieee.h = Bget4(f);
- break;
- }
- s = a->sym;
- if(s == S)
- return;
- i = a->name;
- if(i != D_AUTO && i != D_PARAM)
- return;
-
- l = a->offset;
- for(u=curauto; u; u=u->link)
- if(u->asym == s)
- if(u->type == i) {
- if(u->aoffset > l)
- u->aoffset = l;
- return;
- }
-
- u = mal(sizeof(Auto));
- u->link = curauto;
- curauto = u;
- u->asym = s;
- u->aoffset = l;
- u->type = i;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
-}
-
-void
-ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- int32 ipc;
- Prog *p;
- Sym *h[NSYM], *s;
- int v, o, r, skip;
- uint32 sig;
- char *name;
- int ntext;
- int32 eof;
- char src[1024], *x;
- Prog *lastp;
-
- lastp = nil;
- ntext = 0;
- eof = Boffset(f) + len;
- src[0] = 0;
-
-newloop:
- memset(h, 0, sizeof(h));
- version++;
- histfrogp = 0;
- ipc = pc;
- skip = 0;
-
-loop:
- if(f->state == Bracteof || Boffset(f) >= eof)
- goto eof;
- o = Bgetc(f);
- if(o == Beof)
- goto eof;
-
- if(o <= AXXX || o >= ALAST) {
- diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
- print(" probably not a .5 file\n");
- errorexit();
- }
- if(o == ANAME || o == ASIGNAME) {
- sig = 0;
- if(o == ASIGNAME)
- sig = Bget4(f);
- v = Bgetc(f); /* type */
- o = Bgetc(f); /* sym */
- r = 0;
- if(v == D_STATIC)
- r = version;
- name = Brdline(f, '\0');
- if(name == nil) {
- if(Blinelen(f) > 0) {
- fprint(2, "%s: name too long\n", pn);
- errorexit();
- }
- goto eof;
- }
- x = expandpkg(name, pkg);
- s = lookup(x, r);
- if(x != name)
- free(x);
- name = nil;
-
- if(sig != 0){
- if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name);
- s->sig = sig;
- s->file = pn;
- }
-
- if(debug['W'])
- print(" ANAME %s\n", s->name);
- if(o < 0 || o >= nelem(h)) {
- fprint(2, "%s: mangled input file\n", pn);
- errorexit();
- }
- h[o] = s;
- if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
- s->type = SXREF;
- if(v == D_FILE) {
- if(s->type != SFILE) {
- histgen++;
- s->type = SFILE;
- s->value = histgen;
- }
- if(histfrogp < MAXHIST) {
- histfrog[histfrogp] = s;
- histfrogp++;
- } else
- collapsefrog(s);
- }
- goto loop;
- }
-
- p = mal(sizeof(Prog));
- p->as = o;
- p->scond = Bgetc(f);
- p->reg = Bgetc(f);
- p->line = Bget4(f);
-
- zaddr(f, &p->from, h);
- zaddr(f, &p->to, h);
-
- if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
- diag("register out of range %A %d", p->as, p->reg);
-
- p->link = P;
- p->cond = P;
-
- if(debug['W'])
- print("%P\n", p);
-
- switch(o) {
- case AHISTORY:
- if(p->to.offset == -1) {
- addlib(src, pn);
- histfrogp = 0;
- goto loop;
- }
- if(src[0] == '\0')
- copyhistfrog(src, sizeof src);
- addhist(p->line, D_FILE); /* 'z' */
- if(p->to.offset)
- addhist(p->to.offset, D_FILE1); /* 'Z' */
- histfrogp = 0;
- goto loop;
-
- case AEND:
- histtoauto();
- if(cursym != nil && cursym->text)
- cursym->autom = curauto;
- curauto = 0;
- cursym = nil;
- if(Boffset(f) == eof)
- return;
- goto newloop;
-
- case AGLOBL:
- s = p->from.sym;
- if(s == S) {
- diag("GLOBL must have a name\n%P", p);
- errorexit();
- }
- if(s->type == 0 || s->type == SXREF) {
- s->type = SBSS;
- s->value = 0;
- }
- if(s->type != SBSS) {
- diag("redefinition: %s\n%P", s->name, p);
- s->type = SBSS;
- s->value = 0;
- }
- if(p->to.offset > s->size)
- s->size = p->to.offset;
- if(p->reg & DUPOK)
- s->dupok = 1;
- break;
-
- case ADATA:
- // Assume that AGLOBL comes after ADATA.
- // If we've seen an AGLOBL that said this sym was DUPOK,
- // ignore any more ADATA we see, which must be
- // redefinitions.
- s = p->from.sym;
- if(s->dupok) {
- if(debug['v'])
- Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
- goto loop;
- }
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
- savedata(s, p, pn);
- unmal(p, sizeof *p);
- break;
-
- case AGOK:
- diag("unknown opcode\n%P", p);
- p->pc = pc;
- pc++;
- break;
-
- case ATEXT:
- if(cursym != nil && cursym->text) {
- histtoauto();
- cursym->autom = curauto;
- curauto = 0;
- }
- s = p->from.sym;
- if(s == S) {
- diag("TEXT must have a name\n%P", p);
- errorexit();
- }
- cursym = s;
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- skip = 0;
- if(s->type != 0 && s->type != SXREF) {
- if(p->reg & DUPOK) {
- skip = 1;
- goto casedef;
- }
- diag("redefinition: %s\n%P", s->name, p);
- }
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- p->align = 4;
- autosize = (p->to.offset+3L) & ~3L;
- p->to.offset = autosize;
- autosize += 4;
- s->type = STEXT;
- s->text = p;
- s->value = pc;
- lastp = p;
- p->pc = pc;
- pc++;
- break;
-
- case ASUB:
- if(p->from.type == D_CONST)
- if(p->from.name == D_NONE)
- if(p->from.offset < 0) {
- p->from.offset = -p->from.offset;
- p->as = AADD;
- }
- goto casedef;
-
- case AADD:
- if(p->from.type == D_CONST)
- if(p->from.name == D_NONE)
- if(p->from.offset < 0) {
- p->from.offset = -p->from.offset;
- p->as = ASUB;
- }
- goto casedef;
-
- case AMOVWD:
- case AMOVWF:
- case AMOVDW:
- case AMOVFW:
- case AMOVFD:
- case AMOVDF:
- // case AMOVF:
- // case AMOVD:
- case ACMPF:
- case ACMPD:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- goto casedef;
-
- case AMOVF:
- if(skip)
- goto casedef;
-
- if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
- (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
- /* size sb 9 max */
- sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SBSS;
- adduint32(s, ieeedtof(&p->from.ieee));
- s->reachable = 0;
- }
- p->from.type = D_OREG;
- p->from.sym = s;
- p->from.name = D_EXTERN;
- p->from.offset = 0;
- }
- goto casedef;
-
- case AMOVD:
- if(skip)
- goto casedef;
-
- if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
- (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
- /* size sb 18 max */
- sprint(literal, "$%ux.%ux",
- p->from.ieee.l, p->from.ieee.h);
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SBSS;
- adduint32(s, p->from.ieee.l);
- adduint32(s, p->from.ieee.h);
- s->reachable = 0;
- }
- p->from.type = D_OREG;
- p->from.sym = s;
- p->from.name = D_EXTERN;
- p->from.offset = 0;
- }
- goto casedef;
-
- default:
- casedef:
- if(skip)
- nopout(p);
- p->pc = pc;
- pc++;
- if(p->to.type == D_BRANCH)
- p->to.offset += ipc;
- if(lastp == nil) {
- if(p->as != ANOP)
- diag("unexpected instruction: %P", p);
- break;
- }
- lastp->link = p;
- lastp = p;
- break;
- }
- goto loop;
-
-eof:
- diag("truncated object file: %s", pn);
-}
-
-Prog*
-prg(void)
-{
- Prog *p;
-
- p = mal(sizeof(Prog));
- *p = zprg;
- return p;
-}
-
-Prog*
-appendp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- p->link = q->link;
- q->link = p;
- p->line = q->line;
- return p;
-}
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
deleted file mode 100644
index 514786f85..000000000
--- a/src/cmd/5l/optab.c
+++ /dev/null
@@ -1,236 +0,0 @@
-// Inferno utils/5l/optab.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/optab.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 "l.h"
-
-Optab optab[] =
-{
- /* struct Optab:
- OPCODE, from, prog->reg, to, type,size,param,flag */
- { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
- { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
-
- { AADD, C_REG, C_REG, C_REG, 1, 4, 0 },
- { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 },
-
- { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 },
- { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 },
- { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 },
- { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 },
- { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 },
-
- { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 },
- { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
- { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
- { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 },
-
- { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP },
-
- { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL },
- { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
- { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 },
- { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
-
- { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
- { ABL, C_NONE, C_NONE, C_ROREG, 7, 8, 0 },
- { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 },
- { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 },
-
- { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 },
- { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 },
-
- { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 },
- { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 },
-
- { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 },
- { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 },
- { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 },
-
- { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
-
- { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
- { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM },
-
- { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 },
- { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 },
- { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 },
- { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 },
- { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM },
- { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
- { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
- { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM },
-
- { AMOVB, C_REG, C_NONE, C_REG, 14, 8, 0 },
- { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_REG, 14, 8, 0 },
- { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 },
-
- { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 },
- { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 },
-
- { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 },
- { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 },
-
- { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
-
- { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
- { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
- { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
- { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
-
- { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
- { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
- { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
- { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
- { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
- { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
-
- { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
-
- { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 },
- { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 },
-
- { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 },
- { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 },
-
- { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 },
-
- { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 },
-
- { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP },
- { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 },
-
- { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP },
- { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 },
-
- { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO },
- { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO },
-
- { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM },
- { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM },
-
- { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO },
- { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM },
-
- { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
- { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
- { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 },
- { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 },
-
- { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
- { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
-
- { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
-
- { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0 },
- { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 },
-
- { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
- { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
- { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
- { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
-
- { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
- { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
- { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
-
- { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
- { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
- { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO },
-
- { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
- { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
- { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
-
- { ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 },
- { ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 },
-
- { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 8, 0 },
- { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 },
-
- { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 },
- { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 },
-
- { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 },
- { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 },
-
- { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 },
- { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 },
-
- { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 },
- { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 },
-
- { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 },
-
- { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 },
- { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 },
-
- { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
-};
diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c
deleted file mode 100644
index 194a1ed5f..000000000
--- a/src/cmd/5l/pass.c
+++ /dev/null
@@ -1,333 +0,0 @@
-// Inferno utils/5l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/pass.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.
-
-// Code and data passes.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-static void xfol(Prog*, Prog**);
-
-Prog*
-brchain(Prog *p)
-{
- int i;
-
- for(i=0; i<20; i++) {
- if(p == P || p->as != AB)
- return p;
- p = p->cond;
- }
- return P;
-}
-
-int
-relinv(int a)
-{
- switch(a) {
- case ABEQ: return ABNE;
- case ABNE: return ABEQ;
- case ABCS: return ABCC;
- case ABHS: return ABLO;
- case ABCC: return ABCS;
- case ABLO: return ABHS;
- case ABMI: return ABPL;
- case ABPL: return ABMI;
- case ABVS: return ABVC;
- case ABVC: return ABVS;
- case ABHI: return ABLS;
- case ABLS: return ABHI;
- case ABGE: return ABLT;
- case ABLT: return ABGE;
- case ABGT: return ABLE;
- case ABLE: return ABGT;
- }
- diag("unknown relation: %s", anames[a]);
- return a;
-}
-
-void
-follow(void)
-{
- Prog *firstp, *lastp;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f follow\n", cputime());
- Bflush(&bso);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- firstp = prg();
- lastp = firstp;
- xfol(cursym->text, &lastp);
- lastp->link = nil;
- cursym->text = firstp->link;
- }
-}
-
-static void
-xfol(Prog *p, Prog **last)
-{
- Prog *q, *r;
- int a, i;
-
-loop:
- if(p == P)
- return;
- a = p->as;
- if(a == AB) {
- q = p->cond;
- if(q != P && q->as != ATEXT) {
- 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 == nil)
- break;
- a = q->as;
- if(a == ANOP) {
- i--;
- continue;
- }
- if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
- goto copy;
- if(q->cond == P || (q->cond->mark&FOLL))
- continue;
- if(a != ABEQ && a != ABNE)
- continue;
- copy:
- for(;;) {
- r = prg();
- *r = *p;
- if(!(r->mark&FOLL))
- print("cant happen 1\n");
- r->mark |= FOLL;
- if(p != q) {
- p = p->link;
- (*last)->link = r;
- *last = r;
- continue;
- }
- (*last)->link = r;
- *last = r;
- if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
- return;
- r->as = ABNE;
- if(a == ABNE)
- r->as = ABEQ;
- r->cond = p->link;
- r->link = p->cond;
- if(!(r->link->mark&FOLL))
- xfol(r->link, last);
- if(!(r->cond->mark&FOLL))
- print("cant happen 2\n");
- return;
- }
- }
- a = AB;
- q = prg();
- q->as = a;
- q->line = p->line;
- q->to.type = D_BRANCH;
- q->to.offset = p->pc;
- q->cond = p;
- p = q;
- }
- p->mark |= FOLL;
- (*last)->link = p;
- *last = p;
- if(a == AB || (a == ARET && p->scond == 14) || a == ARFE){
- return;
- }
- if(p->cond != P)
- if(a != ABL && a != ABX && p->link != P) {
- q = brchain(p->link);
- if(a != ATEXT && a != ABCASE)
- if(q != P && (q->mark&FOLL)) {
- p->as = relinv(a);
- p->link = p->cond;
- p->cond = q;
- }
- xfol(p->link, last);
- q = brchain(p->cond);
- if(q == P)
- q = p->cond;
- if(q->mark&FOLL) {
- p->cond = q;
- return;
- }
- p = q;
- goto loop;
- }
- p = p->link;
- goto loop;
-}
-
-void
-patch(void)
-{
- int32 c, vexit;
- Prog *p, *q;
- Sym *s;
- int a;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f patch\n", cputime());
- Bflush(&bso);
- mkfwd();
- s = lookup("exit", 0);
- vexit = s->value;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- a = p->as;
- if((a == ABL || a == ABX || a == AB || a == ARET) &&
- p->to.type != D_BRANCH && p->to.sym != S) {
- s = p->to.sym;
- switch(s->type) {
- default:
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- p->to.type = D_BRANCH;
- break;
- }
- }
- if(p->to.type != D_BRANCH)
- continue;
- c = p->to.offset;
- for(q = textp->text; q != P;) {
- if(c == q->pc)
- break;
- if(q->forwd != P && c >= q->forwd->pc)
- q = q->forwd;
- else
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range %d\n%P", c, p);
- p->to.type = D_NONE;
- }
- p->cond = q;
- }
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- a = p->as;
- if(p->cond != P) {
- p->cond = brloop(p->cond);
- if(p->cond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->cond->pc;
- }
- }
- }
-}
-
-Prog*
-brloop(Prog *p)
-{
- Prog *q;
- int c;
-
- for(c=0; p!=P;) {
- if(p->as != AB)
- return p;
- q = p->cond;
- if(q <= p) {
- c++;
- if(q == p || c > 5000)
- break;
- }
- p = q;
- }
- return P;
-}
-
-int32
-atolwhex(char *s)
-{
- int32 n;
- int f;
-
- n = 0;
- f = 0;
- while(*s == ' ' || *s == '\t')
- s++;
- if(*s == '-' || *s == '+') {
- if(*s++ == '-')
- f = 1;
- while(*s == ' ' || *s == '\t')
- s++;
- }
- if(s[0]=='0' && s[1]){
- if(s[1]=='x' || s[1]=='X'){
- s += 2;
- for(;;){
- if(*s >= '0' && *s <= '9')
- n = n*16 + *s++ - '0';
- else if(*s >= 'a' && *s <= 'f')
- n = n*16 + *s++ - 'a' + 10;
- else if(*s >= 'A' && *s <= 'F')
- n = n*16 + *s++ - 'A' + 10;
- else
- break;
- }
- } else
- while(*s >= '0' && *s <= '7')
- n = n*8 + *s++ - '0';
- } else
- while(*s >= '0' && *s <= '9')
- n = n*10 + *s++ - '0';
- if(f)
- n = -n;
- return n;
-}
-
-int32
-rnd(int32 v, int32 r)
-{
- int32 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/5l/prof.c b/src/cmd/5l/prof.c
deleted file mode 100644
index 48ad2dc59..000000000
--- a/src/cmd/5l/prof.c
+++ /dev/null
@@ -1,211 +0,0 @@
-// 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.
-
-// Profiling.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-doprof1(void)
-{
-#if 0 // TODO(rsc)
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_OREG;
- q->from.name = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->reg = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_EXTERN;
- p->from.sym = s;
- p->from.offset = n*4 + 4;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = REGTMP;
- p->to.type = D_OREG;
- p->to.name = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_OREG;
- q->from.name = D_EXTERN;
- q->from.sym = s;
- q->reg = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->value = n*4;
-#endif
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
- ps2 = P;
- ps4 = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(cursym == s2) {
- ps2 = p;
- p->reg = 1;
- }
- if(cursym == s4) {
- ps4 = p;
- p->reg = 1;
- }
- }
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- for(p = cursym->text; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->reg & NOPROF) {
- for(;;) {
- q = p->link;
- if(q == P)
- break;
- if(q->as == ATEXT)
- break;
- p = q;
- }
- continue;
- }
-
- /*
- * BL profin, R2
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->cond = ps2;
- p->to.sym = s2;
-
- continue;
- }
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * BL profout
- */
- p->as = ABL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->cond = ps4;
- p->to.sym = s4;
-
- p = q;
-
- continue;
- }
- }
-}
diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c
deleted file mode 100644
index 4f799d17e..000000000
--- a/src/cmd/5l/softfloat.c
+++ /dev/null
@@ -1,89 +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 EXTERN
-#include "l.h"
-#include "../ld/lib.h"
-
-// Software floating point.
-
-void
-softfloat(void)
-{
- Prog *p, *next, *psfloat;
- Sym *symsfloat;
- int wasfloat;
-
- if(!debug['F'])
- return;
-
- symsfloat = lookup("_sfloat", 0);
- psfloat = P;
- if(symsfloat->type == STEXT)
- psfloat = symsfloat->text;
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- wasfloat = 0;
- for(p = cursym->text; p != P; p = p->link)
- if(p->cond != P)
- p->cond->mark |= LABEL;
- for(p = cursym->text; p != P; p = p->link) {
- switch(p->as) {
- case AMOVW:
- if(p->to.type == D_FREG || p->from.type == D_FREG)
- goto soft;
- goto notsoft;
-
- case AMOVWD:
- case AMOVWF:
- case AMOVDW:
- case AMOVFW:
- case AMOVFD:
- case AMOVDF:
- case AMOVF:
- case AMOVD:
-
- case ACMPF:
- case ACMPD:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- case ASQRTF:
- case ASQRTD:
- goto soft;
-
- default:
- goto notsoft;
-
- soft:
- if (psfloat == P)
- diag("floats used with _sfloat not defined");
- if (!wasfloat || (p->mark&LABEL)) {
- next = prg();
- *next = *p;
-
- // BL _sfloat(SB)
- *p = zprg;
- p->link = next;
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = symsfloat;
- p->cond = psfloat;
-
- p = next;
- wasfloat = 1;
- }
- break;
-
- notsoft:
- wasfloat = 0;
- }
- }
- }
-}
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
deleted file mode 100644
index eb79f6b5a..000000000
--- a/src/cmd/5l/span.c
+++ /dev/null
@@ -1,893 +0,0 @@
-// Inferno utils/5l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.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.
-
-// Instruction layout.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-static struct {
- uint32 start;
- uint32 size;
- uint32 extra;
-} pool;
-
-int checkpool(Prog*, int);
-int flushpool(Prog*, int, int);
-
-int
-isbranch(Prog *p)
-{
- int as = p->as;
- return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX;
-}
-
-static int
-scan(Prog *op, Prog *p, int c)
-{
- Prog *q;
-
- for(q = op->link; q != p && q != P; q = q->link){
- q->pc = c;
- c += oplook(q)->size;
- nocache(q);
- }
- return c;
-}
-
-/* size of a case statement including jump table */
-static int32
-casesz(Prog *p)
-{
- int jt = 0;
- int32 n = 0;
- Optab *o;
-
- for( ; p != P; p = p->link){
- if(p->as == ABCASE)
- jt = 1;
- else if(jt)
- break;
- o = oplook(p);
- n += o->size;
- }
- return n;
-}
-
-void
-span(void)
-{
- Prog *p, *op;
- Optab *o;
- int m, bflag, i, v;
- int32 c, otxt, out[6];
- Section *sect;
- uchar *bp;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
- Bflush(&bso);
-
- bflag = 0;
- c = INITTEXT;
- op = nil;
- p = nil;
- otxt = c;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- p->pc = c;
- cursym->value = c;
-
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- /* need passes to resolve branches */
- if(c-otxt >= 1L<<17)
- bflag = 1;
- otxt = c;
-
- for(op = p, p = p->link; p != P; op = p, p = p->link) {
- curp = p;
- p->pc = c;
- o = oplook(p);
- m = o->size;
- // must check literal pool here in case p generates many instructions
- if(blitrl){
- if(checkpool(op, p->as == ACASE ? casesz(p) : m))
- c = p->pc = scan(op, p, c);
- }
- if(m == 0) {
- diag("zero-width instruction\n%P", p);
- continue;
- }
- switch(o->flag & (LFROM|LTO|LPOOL)) {
- case LFROM:
- addpool(p, &p->from);
- break;
- case LTO:
- addpool(p, &p->to);
- break;
- case LPOOL:
- if ((p->scond&C_SCOND) == 14)
- flushpool(p, 0, 0);
- break;
- }
- if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
- flushpool(p, 0, 0);
- c += m;
- }
- if(blitrl){
- if(checkpool(op, 0))
- c = scan(op, P, c);
- }
- cursym->size = c - cursym->value;
- }
-
- /*
- * if any procedure is large enough to
- * generate a large SBRA branch, then
- * generate extra passes putting branches
- * around jmps to fix. this is rare.
- */
- while(bflag) {
- if(debug['v'])
- Bprint(&bso, "%5.2f span1\n", cputime());
- bflag = 0;
- c = INITTEXT;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- cursym->value = c;
- for(p = cursym->text; p != P; p = p->link) {
- curp = p;
- p->pc = c;
- o = oplook(p);
-/* very large branches
- if(o->type == 6 && p->cond) {
- otxt = p->cond->pc - c;
- if(otxt < 0)
- otxt = -otxt;
- if(otxt >= (1L<<17) - 10) {
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->cond;
- p->cond = q;
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = q->link->link;
- bflag = 1;
- }
- }
- */
- m = o->size;
- if(m == 0) {
- if(p->as == ATEXT) {
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- continue;
- }
- diag("zero-width instruction\n%P", p);
- continue;
- }
- c += m;
- }
- cursym->size = c - cursym->value;
- }
- }
-
- c = rnd(c, 8);
-
- /*
- * lay out the code. all the pc-relative code references,
- * even cross-function, are resolved now;
- * only data references need to be relocated.
- * with more work we could leave cross-function
- * code references to be relocated too, and then
- * perhaps we'd be able to parallelize the span loop above.
- */
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- autosize = p->to.offset + 4;
- symgrow(cursym, cursym->size);
-
- bp = cursym->p;
- for(p = p->link; p != P; p = p->link) {
- curp = p;
- pc = p->pc;
- curp = p;
- o = oplook(p);
- asmout(p, o, out);
- for(i=0; i<o->size/4; i++) {
- v = out[i];
- *bp++ = v;
- *bp++ = v>>8;
- *bp++ = v>>16;
- *bp++ = v>>24;
- }
- }
- }
- sect = addsection(&segtext, ".text", 05);
- sect->vaddr = INITTEXT;
- sect->len = c - INITTEXT;
-}
-
-/*
- * when the first reference to the literal pool threatens
- * to go out of range of a 12-bit PC-relative offset,
- * drop the pool now, and branch round it.
- * this happens only in extended basic blocks that exceed 4k.
- */
-int
-checkpool(Prog *p, int sz)
-{
- if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
- return flushpool(p, 1, 0);
- else if(p->link == P)
- return flushpool(p, 2, 0);
- return 0;
-}
-
-int
-flushpool(Prog *p, int skip, int force)
-{
- Prog *q;
-
- if(blitrl) {
- if(skip){
- if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
- q = prg();
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->link;
- q->link = blitrl;
- blitrl = q;
- }
- else if(!force && (p->pc+pool.size-pool.start < 2048))
- return 0;
- elitrl->link = p->link;
- p->link = blitrl;
- blitrl = 0; /* BUG: should refer back to values until out-of-range */
- elitrl = 0;
- pool.size = 0;
- pool.start = 0;
- pool.extra = 0;
- return 1;
- }
- return 0;
-}
-
-void
-addpool(Prog *p, Adr *a)
-{
- Prog *q, t;
- int c;
-
- c = aclass(a);
-
- t = zprg;
- t.as = AWORD;
-
- switch(c) {
- default:
- t.to = *a;
- break;
-
- case C_SROREG:
- case C_LOREG:
- case C_ROREG:
- case C_FOREG:
- case C_SOREG:
- case C_HOREG:
- case C_FAUTO:
- case C_SAUTO:
- case C_LAUTO:
- case C_LACON:
- t.to.type = D_CONST;
- t.to.offset = instoffset;
- break;
- }
-
- for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */
- if(memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
- p->cond = q;
- return;
- }
-
- q = prg();
- *q = t;
- q->pc = pool.size;
-
- if(blitrl == P) {
- blitrl = q;
- pool.start = p->pc;
- q->align = 4;
- } else
- elitrl->link = q;
- elitrl = q;
- pool.size += 4;
-
- p->cond = q;
-}
-
-void
-xdefine(char *p, int t, int32 v)
-{
- Sym *s;
-
- s = lookup(p, 0);
- s->type = t;
- s->value = v;
- s->reachable = 1;
- s->special = 1;
-}
-
-int32
-regoff(Adr *a)
-{
-
- instoffset = 0;
- aclass(a);
- return instoffset;
-}
-
-int32
-immrot(uint32 v)
-{
- int i;
-
- for(i=0; i<16; i++) {
- if((v & ~0xff) == 0)
- return (i<<8) | v | (1<<25);
- v = (v<<2) | (v>>30);
- }
- return 0;
-}
-
-int32
-immaddr(int32 v)
-{
- if(v >= 0 && v <= 0xfff)
- return (v & 0xfff) |
- (1<<24) | /* pre indexing */
- (1<<23); /* pre indexing, up */
- if(v >= -0xfff && v < 0)
- return (-v & 0xfff) |
- (1<<24); /* pre indexing */
- return 0;
-}
-
-int
-immfloat(int32 v)
-{
- return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */
-}
-
-int
-immhalf(int32 v)
-{
- if(v >= 0 && v <= 0xff)
- return v|
- (1<<24)| /* pre indexing */
- (1<<23); /* pre indexing, up */
- if(v >= -0xff && v < 0)
- return (-v & 0xff)|
- (1<<24); /* pre indexing */
- return 0;
-}
-
-int32
-symaddr(Sym *s)
-{
- int32 v;
-
- v = s->value;
- switch(s->type) {
- default:
- diag("unexpected type %d in symaddr(%s)", s->type, s->name);
- return 0;
-
- case STEXT:
- case SELFDATA:
- case SRODATA:
- case SDATA:
- case SBSS:
- case SCONST:
- break;
- }
- return v;
-}
-
-int
-aclass(Adr *a)
-{
- Sym *s;
- int t;
-
- switch(a->type) {
- case D_NONE:
- return C_NONE;
-
- case D_REG:
- return C_REG;
-
- case D_REGREG:
- return C_REGREG;
-
- case D_SHIFT:
- return C_SHIFT;
-
- case D_FREG:
- return C_FREG;
-
- case D_FPCR:
- return C_FCR;
-
- case D_OREG:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- if(a->sym == 0 || a->sym->name == 0) {
- print("null sym external\n");
- print("%D\n", a);
- return C_GOK;
- }
- s = a->sym;
- t = s->type;
- instoffset = 0; // s.b. unused but just in case
- return C_ADDR;
-
- case D_AUTO:
- instoffset = autosize + a->offset;
- t = immaddr(instoffset);
- if(t){
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFAUTO : C_HAUTO;
- if(immfloat(t))
- return C_FAUTO;
- return C_SAUTO;
- }
- return C_LAUTO;
-
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
- t = immaddr(instoffset);
- if(t){
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFAUTO : C_HAUTO;
- if(immfloat(t))
- return C_FAUTO;
- return C_SAUTO;
- }
- return C_LAUTO;
- case D_NONE:
- instoffset = a->offset;
- t = immaddr(instoffset);
- if(t) {
- if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */
- return immfloat(t) ? C_HFOREG : C_HOREG;
- if(immfloat(t))
- return C_FOREG; /* n.b. that it will also satisfy immrot */
- t = immrot(instoffset);
- if(t)
- return C_SROREG;
- if(immhalf(instoffset))
- return C_HOREG;
- return C_SOREG;
- }
- t = immrot(instoffset);
- if(t)
- return C_ROREG;
- return C_LOREG;
- }
- return C_GOK;
-
- case D_PSR:
- return C_PSR;
-
- case D_OCONST:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- s = a->sym;
- t = s->type;
- instoffset = 0; // s.b. unused but just in case
- return C_ADDR;
- }
- return C_GOK;
-
- case D_FCONST:
- if(chipzero(&a->ieee) >= 0)
- return C_ZFCON;
- if(chipfloat(&a->ieee) >= 0)
- return C_SFCON;
- return C_LFCON;
-
- case D_CONST:
- case D_CONST2:
- switch(a->name) {
-
- case D_NONE:
- instoffset = a->offset;
- if(a->reg != NREG)
- goto aconsize;
-
- t = immrot(instoffset);
- if(t)
- return C_RCON;
- t = immrot(~instoffset);
- if(t)
- return C_NCON;
- return C_LCON;
-
- case D_EXTERN:
- case D_STATIC:
- s = a->sym;
- if(s == S)
- break;
- t = s->type;
- instoffset = 0; // s.b. unused but just in case
- return C_LCON;
-
- case D_AUTO:
- instoffset = autosize + a->offset;
- goto aconsize;
-
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
- aconsize:
- t = immrot(instoffset);
- if(t)
- return C_RACON;
- return C_LACON;
- }
- return C_GOK;
-
- case D_BRANCH:
- return C_SBRA;
- }
- return C_GOK;
-}
-
-Optab*
-oplook(Prog *p)
-{
- int a1, a2, a3, r;
- char *c1, *c3;
- Optab *o, *e;
-
- a1 = p->optab;
- if(a1)
- return optab+(a1-1);
- a1 = p->from.class;
- if(a1 == 0) {
- a1 = aclass(&p->from) + 1;
- p->from.class = a1;
- }
- a1--;
- a3 = p->to.class;
- if(a3 == 0) {
- a3 = aclass(&p->to) + 1;
- p->to.class = a3;
- }
- a3--;
- a2 = C_NONE;
- if(p->reg != NREG)
- a2 = C_REG;
- r = p->as;
- o = oprange[r].start;
- if(o == 0) {
- a1 = opcross[repop[r]][a1][a2][a3];
- if(a1) {
- p->optab = a1+1;
- return optab+a1;
- }
- o = oprange[r].stop; /* just generate an error */
- }
- if(debug['O']) {
- print("oplook %A %O %O %O\n",
- (int)p->as, a1, a2, a3);
- print(" %d %d\n", p->from.type, p->to.type);
- }
- e = oprange[r].stop;
- c1 = xcmp[a1];
- c3 = xcmp[a3];
- for(; o<e; o++)
- if(o->a2 == a2)
- if(c1[o->a1])
- if(c3[o->a3]) {
- p->optab = (o-optab)+1;
- return o;
- }
- diag("illegal combination %A %O %O %O, %d %d",
- p->as, a1, a2, a3, p->from.type, p->to.type);
- prasm(p);
- if(o == 0)
- o = optab;
- return o;
-}
-
-int
-cmp(int a, int b)
-{
-
- if(a == b)
- return 1;
- switch(a) {
- case C_LCON:
- if(b == C_RCON || b == C_NCON)
- return 1;
- break;
- case C_LACON:
- if(b == C_RACON)
- return 1;
- break;
- case C_LFCON:
- if(b == C_ZFCON || b == C_SFCON)
- return 1;
- break;
-
- case C_HFAUTO:
- return b == C_HAUTO || b == C_FAUTO;
- case C_FAUTO:
- case C_HAUTO:
- return b == C_HFAUTO;
- case C_SAUTO:
- return cmp(C_HFAUTO, b);
- case C_LAUTO:
- return cmp(C_SAUTO, b);
-
- case C_HFOREG:
- return b == C_HOREG || b == C_FOREG;
- case C_FOREG:
- case C_HOREG:
- return b == C_HFOREG;
- case C_SROREG:
- return cmp(C_SOREG, b) || cmp(C_ROREG, b);
- case C_SOREG:
- case C_ROREG:
- return b == C_SROREG || cmp(C_HFOREG, b);
- case C_LOREG:
- return cmp(C_SROREG, b);
-
- case C_LBRA:
- if(b == C_SBRA)
- return 1;
- break;
-
- case C_HREG:
- return cmp(C_SP, b) || cmp(C_PC, b);
-
- }
- return 0;
-}
-
-int
-ocmp(const void *a1, const void *a2)
-{
- Optab *p1, *p2;
- int n;
-
- p1 = (Optab*)a1;
- p2 = (Optab*)a2;
- n = p1->as - p2->as;
- if(n)
- return n;
- n = p1->a1 - p2->a1;
- if(n)
- return n;
- n = p1->a2 - p2->a2;
- if(n)
- return n;
- n = p1->a3 - p2->a3;
- if(n)
- return n;
- return 0;
-}
-
-void
-buildop(void)
-{
- int i, n, r;
-
- for(i=0; i<C_GOK; i++)
- for(n=0; n<C_GOK; n++)
- xcmp[i][n] = cmp(n, i);
- for(n=0; optab[n].as != AXXX; n++)
- ;
- qsort(optab, n, sizeof(optab[0]), ocmp);
- for(i=0; i<n; i++) {
- r = optab[i].as;
- oprange[r].start = optab+i;
- while(optab[i].as == r)
- i++;
- oprange[r].stop = optab+i;
- i--;
-
- switch(r)
- {
- default:
- diag("unknown op in build: %A", r);
- errorexit();
- case AADD:
- oprange[AAND] = oprange[r];
- oprange[AEOR] = oprange[r];
- oprange[ASUB] = oprange[r];
- oprange[ARSB] = oprange[r];
- oprange[AADC] = oprange[r];
- oprange[ASBC] = oprange[r];
- oprange[ARSC] = oprange[r];
- oprange[AORR] = oprange[r];
- oprange[ABIC] = oprange[r];
- break;
- case ACMP:
- oprange[ATEQ] = oprange[r];
- oprange[ACMN] = oprange[r];
- break;
- case AMVN:
- break;
- case ABEQ:
- oprange[ABNE] = oprange[r];
- oprange[ABCS] = oprange[r];
- oprange[ABHS] = oprange[r];
- oprange[ABCC] = oprange[r];
- oprange[ABLO] = oprange[r];
- oprange[ABMI] = oprange[r];
- oprange[ABPL] = oprange[r];
- oprange[ABVS] = oprange[r];
- oprange[ABVC] = oprange[r];
- oprange[ABHI] = oprange[r];
- oprange[ABLS] = oprange[r];
- oprange[ABGE] = oprange[r];
- oprange[ABLT] = oprange[r];
- oprange[ABGT] = oprange[r];
- oprange[ABLE] = oprange[r];
- break;
- case ASLL:
- oprange[ASRL] = oprange[r];
- oprange[ASRA] = oprange[r];
- break;
- case AMUL:
- oprange[AMULU] = oprange[r];
- break;
- case ADIV:
- oprange[AMOD] = oprange[r];
- oprange[AMODU] = oprange[r];
- oprange[ADIVU] = oprange[r];
- break;
- case AMOVW:
- case AMOVB:
- case AMOVBU:
- case AMOVH:
- case AMOVHU:
- break;
- case ASWPW:
- oprange[ASWPBU] = oprange[r];
- break;
- case AB:
- case ABL:
- case ABX:
- case ABXRET:
- case ASWI:
- case AWORD:
- case AMOVM:
- case ARFE:
- case ATEXT:
- case ACASE:
- case ABCASE:
- break;
- case AADDF:
- oprange[AADDD] = oprange[r];
- oprange[ASUBF] = oprange[r];
- oprange[ASUBD] = oprange[r];
- oprange[AMULF] = oprange[r];
- oprange[AMULD] = oprange[r];
- oprange[ADIVF] = oprange[r];
- oprange[ADIVD] = oprange[r];
- oprange[ASQRTF] = oprange[r];
- oprange[ASQRTD] = oprange[r];
- oprange[AMOVFD] = oprange[r];
- oprange[AMOVDF] = oprange[r];
- break;
-
- case ACMPF:
- oprange[ACMPD] = oprange[r];
- break;
-
- case AMOVF:
- oprange[AMOVD] = oprange[r];
- break;
-
- case AMOVFW:
- oprange[AMOVDW] = oprange[r];
- break;
-
- case AMOVWF:
- oprange[AMOVWD] = oprange[r];
- break;
-
- case AMULL:
- oprange[AMULA] = oprange[r];
- oprange[AMULAL] = oprange[r];
- oprange[AMULLU] = oprange[r];
- oprange[AMULALU] = oprange[r];
- break;
-
- case ALDREX:
- case ASTREX:
- case ALDREXD:
- case ASTREXD:
- case ATST:
- break;
- }
- }
-}
-
-/*
-void
-buildrep(int x, int as)
-{
- Opcross *p;
- Optab *e, *s, *o;
- int a1, a2, a3, n;
-
- if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
- diag("assumptions fail in buildrep");
- errorexit();
- }
- repop[as] = x;
- p = (opcross + x);
- s = oprange[as].start;
- e = oprange[as].stop;
- for(o=e-1; o>=s; o--) {
- n = o-optab;
- for(a2=0; a2<2; a2++) {
- if(a2) {
- if(o->a2 == C_NONE)
- continue;
- } else
- if(o->a2 != C_NONE)
- continue;
- for(a1=0; a1<32; a1++) {
- if(!xcmp[a1][o->a1])
- continue;
- for(a3=0; a3<32; a3++)
- if(xcmp[a3][o->a3])
- (*p)[a1][a2][a3] = n;
- }
- }
- }
- oprange[as].start = 0;
-}
-*/
diff --git a/src/cmd/6a/Makefile b/src/cmd/6a/Makefile
deleted file mode 100644
index 30180bd24..000000000
--- a/src/cmd/6a/Makefile
+++ /dev/null
@@ -1,25 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=6a
-
-HFILES=\
- a.h\
- y.tab.h\
- ../6l/6.out.h\
-
-OFILES=\
- y.tab.$O\
- lex.$O\
- ../6l/enam.$O\
-
-YFILES=\
- a.y\
-
-include ../../Make.ccmd
-
-lex.$O: ../cc/macbody ../cc/lexbody
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
deleted file mode 100644
index 2d4272646..000000000
--- a/src/cmd/6a/a.h
+++ /dev/null
@@ -1,214 +0,0 @@
-// Inferno utils/6a/a.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.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 <libc.h>
-#include <bio.h>
-#include "../6l/6.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 Ref Ref;
-typedef struct Gen Gen;
-typedef struct Io Io;
-typedef struct Hist Hist;
-typedef struct Gen2 Gen2;
-
-#define MAXALIGN 7
-#define FPCHIP 1
-#define NSYMB 500
-#define BUFSIZ 8192
-#define HISTSZ 20
-#define EOF (-1)
-#define IGN (-2)
-#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
-#define NHASH 503
-#define STRINGSZ 200
-#define NMACRO 10
-
-struct Sym
-{
- Sym* link;
- Ref* ref;
- char* macro;
- vlong value;
- ushort type;
- char *name;
- char sym;
-};
-#define S ((Sym*)0)
-
-struct Ref
-{
- int class;
-};
-
-EXTERN struct
-{
- char* p;
- int c;
-} fi;
-
-struct Io
-{
- Io* link;
- char b[BUFSIZ];
- char* p;
- short c;
- short f;
-};
-#define I ((Io*)0)
-
-EXTERN struct
-{
- Sym* sym;
- short type;
-} h[NSYM];
-
-struct Gen
-{
- double dval;
- char sval[8];
- vlong offset;
- Sym* sym;
- short type;
- short index;
- short scale;
-};
-struct Gen2
-{
- Gen from;
- Gen to;
-};
-
-struct Hist
-{
- Hist* link;
- char* name;
- int32 line;
- vlong offset;
-};
-#define H ((Hist*)0)
-
-enum
-{
- CLAST,
- CMACARG,
- CMACRO,
- CPREPROC,
-};
-
-
-EXTERN char debug[256];
-EXTERN Sym* hash[NHASH];
-EXTERN char** Dlist;
-EXTERN int nDlist;
-EXTERN Hist* ehist;
-EXTERN int newflag;
-EXTERN Hist* hist;
-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 ninclude;
-EXTERN int32 nsymb;
-EXTERN Gen nullgen;
-EXTERN char* outfile;
-EXTERN int pass;
-EXTERN char* pathname;
-EXTERN int32 pc;
-EXTERN int peekc;
-EXTERN int32 stmtline;
-EXTERN int sym;
-EXTERN char* symb;
-EXTERN int thechar;
-EXTERN char* thestring;
-EXTERN int32 thunk;
-EXTERN Biobuf obuf;
-
-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);
-void syminit(Sym*);
-int32 yylex(void);
-int getc(void);
-int getnsc(void);
-void unget(int);
-int escchar(int);
-void cinit(void);
-void checkscale(int);
-void pinit(char*);
-void cclean(void);
-int isreg(Gen*);
-void outcode(int, Gen2*);
-void outhist(void);
-void zaddr(Gen*, int);
-void zname(char*, int, int);
-void ieeedtod(Ieee*, double);
-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/6a/a.y b/src/cmd/6a/a.y
deleted file mode 100644
index 770f676fe..000000000
--- a/src/cmd/6a/a.y
+++ /dev/null
@@ -1,645 +0,0 @@
-// Inferno utils/6a/a.y
-// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.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 <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include "a.h"
-%}
-%union {
- Sym *sym;
- vlong lval;
- double dval;
- char sval[8];
- Gen gen;
- Gen2 gen2;
-}
-%left '|'
-%left '^'
-%left '&'
-%left '<' '>'
-%left '+' '-'
-%left '*' '/' '%'
-%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
-%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPEG
-%token <lval> LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT
-%token <lval> LCONST LFP LPC LSB
-%token <lval> LBREG LLREG LSREG LFREG LMREG LXREG
-%token <dval> LFCONST
-%token <sval> LSCONST LSP
-%token <sym> LNAME LLAB LVAR
-%type <lval> con con2 expr pointer offset
-%type <gen> mem imm imm2 reg nam rel rem rim rom omem nmem
-%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim spec10 spec11
-%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
-%%
-prog:
-| prog
- {
- stmtline = lineno;
- }
- line
-
-line:
- LLAB ':'
- {
- if($1->value != pc)
- yyerror("redeclaration of %s", $1->name);
- $1->value = pc;
- }
- line
-| LNAME ':'
- {
- $1->type = LLAB;
- $1->value = pc;
- }
- line
-| ';'
-| inst ';'
-| error ';'
-
-inst:
- LNAME '=' expr
- {
- $1->type = LVAR;
- $1->value = $3;
- }
-| LVAR '=' expr
- {
- if($1->value != $3)
- yyerror("redeclaration of %s", $1->name);
- $1->value = $3;
- }
-| LTYPE0 nonnon { outcode($1, &$2); }
-| LTYPE1 nonrem { outcode($1, &$2); }
-| LTYPE2 rimnon { outcode($1, &$2); }
-| LTYPE3 rimrem { outcode($1, &$2); }
-| LTYPE4 remrim { outcode($1, &$2); }
-| LTYPER nonrel { outcode($1, &$2); }
-| LTYPED spec1 { outcode($1, &$2); }
-| LTYPET spec2 { outcode($1, &$2); }
-| LTYPEC spec3 { outcode($1, &$2); }
-| LTYPEN spec4 { outcode($1, &$2); }
-| LTYPES spec5 { outcode($1, &$2); }
-| LTYPEM spec6 { outcode($1, &$2); }
-| LTYPEI spec7 { outcode($1, &$2); }
-| LTYPEXC spec8 { outcode($1, &$2); }
-| LTYPEX spec9 { outcode($1, &$2); }
-| LTYPERT spec10 { outcode($1, &$2); }
-| LTYPEG spec11 { outcode($1, &$2); }
-
-nonnon:
- {
- $$.from = nullgen;
- $$.to = nullgen;
- }
-| ','
- {
- $$.from = nullgen;
- $$.to = nullgen;
- }
-
-rimrem:
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-remrim:
- rem ',' rim
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-rimnon:
- rim ','
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-
-nonrem:
- ',' rem
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rem
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-
-nonrel:
- ',' rel
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rel
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-
-spec1: /* DATA */
- nam '/' con ',' imm
- {
- $$.from = $1;
- $$.from.scale = $3;
- $$.to = $5;
- }
-
-spec2: /* TEXT */
- mem ',' imm2
- {
- $$.from = $1;
- $$.to = $3;
- }
-| mem ',' con ',' imm2
- {
- $$.from = $1;
- $$.from.scale = $3;
- $$.to = $5;
- }
-
-spec3: /* JMP/CALL */
- ',' rom
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rom
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-
-spec4: /* NOP */
- nonnon
-| nonrem
-
-spec5: /* SHL/SHR */
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-| rim ',' rem ':' LLREG
- {
- $$.from = $1;
- $$.to = $3;
- if($$.from.index != D_NONE)
- yyerror("dp shift with lhs index");
- $$.from.index = $5;
- }
-
-spec6: /* MOVW/MOVL */
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-| rim ',' rem ':' LSREG
- {
- $$.from = $1;
- $$.to = $3;
- if($$.to.index != D_NONE)
- yyerror("dp move with lhs index");
- $$.to.index = $5;
- }
-
-spec7:
- rim ','
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-spec8: /* CMPPS/CMPPD */
- reg ',' rem ',' con
- {
- $$.from = $1;
- $$.to = $3;
- $$.to.offset = $5;
- }
-
-spec9: /* shufl */
- imm ',' rem ',' reg
- {
- $$.from = $3;
- $$.to = $5;
- if($1.type != D_CONST)
- yyerror("illegal constant");
- $$.to.offset = $1.offset;
- }
-
-spec10: /* RET/RETF */
- {
- $$.from = nullgen;
- $$.to = nullgen;
- }
-| imm
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-
-spec11: /* GLOBL */
- mem ',' imm
- {
- $$.from = $1;
- $$.to = $3;
- }
-| mem ',' con ',' imm
- {
- $$.from = $1;
- $$.from.scale = $3;
- $$.to = $5;
- }
-
-rem:
- reg
-| mem
-
-rom:
- rel
-| nmem
-| '*' reg
- {
- $$ = $2;
- }
-| '*' omem
- {
- $$ = $2;
- }
-| reg
-| omem
-
-rim:
- rem
-| imm
-
-rel:
- con '(' LPC ')'
- {
- $$ = nullgen;
- $$.type = D_BRANCH;
- $$.offset = $1 + pc;
- }
-| LNAME offset
- {
- $$ = nullgen;
- if(pass == 2)
- yyerror("undefined label: %s", $1->name);
- $$.type = D_BRANCH;
- $$.sym = $1;
- $$.offset = $2;
- }
-| LLAB offset
- {
- $$ = nullgen;
- $$.type = D_BRANCH;
- $$.sym = $1;
- $$.offset = $1->value + $2;
- }
-
-reg:
- LBREG
- {
- $$ = nullgen;
- $$.type = $1;
- }
-| LFREG
- {
- $$ = nullgen;
- $$.type = $1;
- }
-| LLREG
- {
- $$ = nullgen;
- $$.type = $1;
- }
-| LMREG
- {
- $$ = nullgen;
- $$.type = $1;
- }
-| LSP
- {
- $$ = nullgen;
- $$.type = D_SP;
- }
-| LSREG
- {
- $$ = nullgen;
- $$.type = $1;
- }
-| LXREG
- {
- $$ = nullgen;
- $$.type = $1;
- }
-imm2:
- '$' con2
- {
- $$ = nullgen;
- $$.type = D_CONST;
- $$.offset = $2;
- }
-
-imm:
- '$' con
- {
- $$ = nullgen;
- $$.type = D_CONST;
- $$.offset = $2;
- }
-| '$' nam
- {
- $$ = $2;
- $$.index = $2.type;
- $$.type = D_ADDR;
- /*
- if($2.type == D_AUTO || $2.type == D_PARAM)
- yyerror("constant cannot be automatic: %s",
- $2.sym->name);
- */
- }
-| '$' LSCONST
- {
- $$ = nullgen;
- $$.type = D_SCONST;
- memcpy($$.sval, $2, sizeof($$.sval));
- }
-| '$' LFCONST
- {
- $$ = nullgen;
- $$.type = D_FCONST;
- $$.dval = $2;
- }
-| '$' '(' LFCONST ')'
- {
- $$ = nullgen;
- $$.type = D_FCONST;
- $$.dval = $3;
- }
-| '$' '-' LFCONST
- {
- $$ = nullgen;
- $$.type = D_FCONST;
- $$.dval = -$3;
- }
-
-mem:
- omem
-| nmem
-
-omem:
- con
- {
- $$ = nullgen;
- $$.type = D_INDIR+D_NONE;
- $$.offset = $1;
- }
-| con '(' LLREG ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+$3;
- $$.offset = $1;
- }
-| con '(' LSP ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+D_SP;
- $$.offset = $1;
- }
-| con '(' LSREG ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+$3;
- $$.offset = $1;
- }
-| con '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+D_NONE;
- $$.offset = $1;
- $$.index = $3;
- $$.scale = $5;
- checkscale($$.scale);
- }
-| con '(' LLREG ')' '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+$3;
- $$.offset = $1;
- $$.index = $6;
- $$.scale = $8;
- checkscale($$.scale);
- }
-| '(' LLREG ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+$2;
- }
-| '(' LSP ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+D_SP;
- }
-| '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+D_NONE;
- $$.index = $2;
- $$.scale = $4;
- checkscale($$.scale);
- }
-| '(' LLREG ')' '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+$2;
- $$.index = $5;
- $$.scale = $7;
- checkscale($$.scale);
- }
-
-nmem:
- nam
- {
- $$ = $1;
- }
-| nam '(' LLREG '*' con ')'
- {
- $$ = $1;
- $$.index = $3;
- $$.scale = $5;
- checkscale($$.scale);
- }
-
-nam:
- LNAME offset '(' pointer ')'
- {
- $$ = nullgen;
- $$.type = $4;
- $$.sym = $1;
- $$.offset = $2;
- }
-| LNAME '<' '>' offset '(' LSB ')'
- {
- $$ = nullgen;
- $$.type = D_STATIC;
- $$.sym = $1;
- $$.offset = $4;
- }
-
-offset:
- {
- $$ = 0;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '-' con
- {
- $$ = -$2;
- }
-
-pointer:
- LSB
-| LSP
- {
- $$ = D_AUTO;
- }
-| LFP
-
-con:
- LCONST
-| LVAR
- {
- $$ = $1->value;
- }
-| '-' con
- {
- $$ = -$2;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '~' con
- {
- $$ = ~$2;
- }
-| '(' expr ')'
- {
- $$ = $2;
- }
-
-con2:
- LCONST
- {
- $$ = $1 & 0xffffffffLL;
- }
-| '-' LCONST
- {
- $$ = -$2 & 0xffffffffLL;
- }
-| LCONST '-' LCONST
- {
- $$ = ($1 & 0xffffffffLL) +
- (($3 & 0xffffLL) << 32);
- }
-| '-' LCONST '-' LCONST
- {
- $$ = (-$2 & 0xffffffffLL) +
- (($4 & 0xffffLL) << 32);
- }
-
-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/6a/doc.go b/src/cmd/6a/doc.go
deleted file mode 100644
index 92fb74de6..000000000
--- a/src/cmd/6a/doc.go
+++ /dev/null
@@ -1,14 +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.
-
-/*
-
-6a is a version of the Plan 9 assembler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2a
-
-Its target architecture is the x86-64, referred to by these tools as amd64.
-
-*/
-package documentation
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
deleted file mode 100644
index b4c7d0c2c..000000000
--- a/src/cmd/6a/lex.c
+++ /dev/null
@@ -1,1315 +0,0 @@
-// Inferno utils/6a/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6a/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.
-
-#define EXTERN
-#include "a.h"
-#include "y.tab.h"
-#include <ctype.h>
-
-enum
-{
- Plan9 = 1<<0,
- Unix = 1<<1,
- Windows = 1<<2,
-};
-
-int
-systemtype(int sys)
-{
- return sys&Plan9;
-}
-
-int
-pathchar(void)
-{
- return '/';
-}
-
-void
-main(int argc, char *argv[])
-{
- char *p;
- int c;
-
- thechar = '6';
- thestring = "amd64";
-
- ensuresymb(NSYMB);
- memset(debug, 0, sizeof(debug));
- cinit();
- outfile = 0;
- setinclude(".");
- ARGBEGIN {
- default:
- c = ARGC();
- if(c >= 0 || c < sizeof(debug))
- debug[c] = 1;
- break;
-
- case 'o':
- outfile = ARGF();
- break;
-
- case 'D':
- p = ARGF();
- if(p) {
- if (nDlist%8 == 0)
- Dlist = allocn(Dlist, nDlist*sizeof(char *),
- 8*sizeof(char *));
- Dlist[nDlist++] = p;
- }
- break;
-
- case 'I':
- p = ARGF();
- setinclude(p);
- break;
- } ARGEND
- if(*argv == 0) {
- print("usage: %ca [-options] file.s\n", thechar);
- errorexit();
- }
- if(argc > 1){
- print("can't assemble multiple files\n");
- errorexit();
- }
- if(assemble(argv[0]))
- errorexit();
- 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);
-
- pass = 1;
- pinit(file);
-
- Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
-
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- if(nerrors) {
- cclean();
- return nerrors;
- }
-
- Bprint(&obuf, "\n!\n");
-
- pass = 2;
- outhist();
- pinit(file);
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- cclean();
- return nerrors;
-}
-
-struct
-{
- char *name;
- ushort type;
- ushort value;
-} itab[] =
-{
- "SP", LSP, D_AUTO,
- "SB", LSB, D_EXTERN,
- "FP", LFP, D_PARAM,
- "PC", LPC, D_BRANCH,
-
- "AL", LBREG, D_AL,
- "CL", LBREG, D_CL,
- "DL", LBREG, D_DL,
- "BL", LBREG, D_BL,
-/* "SPB", LBREG, D_SPB, */
- "SIB", LBREG, D_SIB,
- "DIB", LBREG, D_DIB,
- "BPB", LBREG, D_BPB,
- "R8B", LBREG, D_R8B,
- "R9B", LBREG, D_R9B,
- "R10B", LBREG, D_R10B,
- "R11B", LBREG, D_R11B,
- "R12B", LBREG, D_R12B,
- "R13B", LBREG, D_R13B,
- "R14B", LBREG, D_R14B,
- "R15B", LBREG, D_R15B,
-
- "AH", LBREG, D_AH,
- "CH", LBREG, D_CH,
- "DH", LBREG, D_DH,
- "BH", LBREG, D_BH,
-
- "AX", LLREG, D_AX,
- "CX", LLREG, D_CX,
- "DX", LLREG, D_DX,
- "BX", LLREG, D_BX,
-/* "SP", LLREG, D_SP, */
- "BP", LLREG, D_BP,
- "SI", LLREG, D_SI,
- "DI", LLREG, D_DI,
- "R8", LLREG, D_R8,
- "R9", LLREG, D_R9,
- "R10", LLREG, D_R10,
- "R11", LLREG, D_R11,
- "R12", LLREG, D_R12,
- "R13", LLREG, D_R13,
- "R14", LLREG, D_R14,
- "R15", LLREG, D_R15,
-
- "RARG", LLREG, REGARG,
-
- "F0", LFREG, D_F0+0,
- "F1", LFREG, D_F0+1,
- "F2", LFREG, D_F0+2,
- "F3", LFREG, D_F0+3,
- "F4", LFREG, D_F0+4,
- "F5", LFREG, D_F0+5,
- "F6", LFREG, D_F0+6,
- "F7", LFREG, D_F0+7,
-
- "M0", LMREG, D_M0+0,
- "M1", LMREG, D_M0+1,
- "M2", LMREG, D_M0+2,
- "M3", LMREG, D_M0+3,
- "M4", LMREG, D_M0+4,
- "M5", LMREG, D_M0+5,
- "M6", LMREG, D_M0+6,
- "M7", LMREG, D_M0+7,
-
- "X0", LXREG, D_X0+0,
- "X1", LXREG, D_X0+1,
- "X2", LXREG, D_X0+2,
- "X3", LXREG, D_X0+3,
- "X4", LXREG, D_X0+4,
- "X5", LXREG, D_X0+5,
- "X6", LXREG, D_X0+6,
- "X7", LXREG, D_X0+7,
- "X8", LXREG, D_X0+8,
- "X9", LXREG, D_X0+9,
- "X10", LXREG, D_X0+10,
- "X11", LXREG, D_X0+11,
- "X12", LXREG, D_X0+12,
- "X13", LXREG, D_X0+13,
- "X14", LXREG, D_X0+14,
- "X15", LXREG, D_X0+15,
-
- "CS", LSREG, D_CS,
- "SS", LSREG, D_SS,
- "DS", LSREG, D_DS,
- "ES", LSREG, D_ES,
- "FS", LSREG, D_FS,
- "GS", LSREG, D_GS,
-
- "GDTR", LBREG, D_GDTR,
- "IDTR", LBREG, D_IDTR,
- "LDTR", LBREG, D_LDTR,
- "MSW", LBREG, D_MSW,
- "TASK", LBREG, D_TASK,
-
- "CR0", LBREG, D_CR+0,
- "CR1", LBREG, D_CR+1,
- "CR2", LBREG, D_CR+2,
- "CR3", LBREG, D_CR+3,
- "CR4", LBREG, D_CR+4,
- "CR5", LBREG, D_CR+5,
- "CR6", LBREG, D_CR+6,
- "CR7", LBREG, D_CR+7,
- "CR8", LBREG, D_CR+8,
- "CR9", LBREG, D_CR+9,
- "CR10", LBREG, D_CR+10,
- "CR11", LBREG, D_CR+11,
- "CR12", LBREG, D_CR+12,
- "CR13", LBREG, D_CR+13,
- "CR14", LBREG, D_CR+14,
- "CR15", LBREG, D_CR+15,
-
- "DR0", LBREG, D_DR+0,
- "DR1", LBREG, D_DR+1,
- "DR2", LBREG, D_DR+2,
- "DR3", LBREG, D_DR+3,
- "DR4", LBREG, D_DR+4,
- "DR5", LBREG, D_DR+5,
- "DR6", LBREG, D_DR+6,
- "DR7", LBREG, D_DR+7,
-
- "TR0", LBREG, D_TR+0,
- "TR1", LBREG, D_TR+1,
- "TR2", LBREG, D_TR+2,
- "TR3", LBREG, D_TR+3,
- "TR4", LBREG, D_TR+4,
- "TR5", LBREG, D_TR+5,
- "TR6", LBREG, D_TR+6,
- "TR7", LBREG, D_TR+7,
-
- "AAA", LTYPE0, AAAA,
- "AAD", LTYPE0, AAAD,
- "AAM", LTYPE0, AAAM,
- "AAS", LTYPE0, AAAS,
- "ADCB", LTYPE3, AADCB,
- "ADCL", LTYPE3, AADCL,
- "ADCQ", LTYPE3, AADCQ,
- "ADCW", LTYPE3, AADCW,
- "ADDB", LTYPE3, AADDB,
- "ADDL", LTYPE3, AADDL,
- "ADDQ", LTYPE3, AADDQ,
- "ADDW", LTYPE3, AADDW,
- "ADJSP", LTYPE2, AADJSP,
- "ANDB", LTYPE3, AANDB,
- "ANDL", LTYPE3, AANDL,
- "ANDQ", LTYPE3, AANDQ,
- "ANDW", LTYPE3, AANDW,
- "ARPL", LTYPE3, AARPL,
- "BOUNDL", LTYPE3, ABOUNDL,
- "BOUNDW", LTYPE3, ABOUNDW,
- "BSFL", LTYPE3, ABSFL,
- "BSFQ", LTYPE3, ABSFQ,
- "BSFW", LTYPE3, ABSFW,
- "BSRL", LTYPE3, ABSRL,
- "BSRQ", LTYPE3, ABSRQ,
- "BSRW", LTYPE3, ABSRW,
- "BTCL", LTYPE3, ABTCL,
- "BTCQ", LTYPE3, ABTCQ,
- "BTCW", LTYPE3, ABTCW,
- "BTL", LTYPE3, ABTL,
- "BTQ", LTYPE3, ABTQ,
- "BTRL", LTYPE3, ABTRL,
- "BTRQ", LTYPE3, ABTRQ,
- "BTRW", LTYPE3, ABTRW,
- "BTSL", LTYPE3, ABTSL,
- "BTSQ", LTYPE3, ABTSQ,
- "BTSW", LTYPE3, ABTSW,
- "BTW", LTYPE3, ABTW,
- "BYTE", LTYPE2, ABYTE,
- "CALL", LTYPEC, ACALL,
- "CLC", LTYPE0, ACLC,
- "CLD", LTYPE0, ACLD,
- "CLI", LTYPE0, ACLI,
- "CLTS", LTYPE0, ACLTS,
- "CMC", LTYPE0, ACMC,
- "CMPB", LTYPE4, ACMPB,
- "CMPL", LTYPE4, ACMPL,
- "CMPQ", LTYPE4, ACMPQ,
- "CMPW", LTYPE4, ACMPW,
- "CMPSB", LTYPE0, ACMPSB,
- "CMPSL", LTYPE0, ACMPSL,
- "CMPSQ", LTYPE0, ACMPSQ,
- "CMPSW", LTYPE0, ACMPSW,
- "CMPXCHG8B", LTYPE1, ACMPXCHG8B,
- "CMPXCHGB", LTYPE3, ACMPXCHGB, /* LTYPE3? */
- "CMPXCHGL", LTYPE3, ACMPXCHGL,
- "CMPXCHGQ", LTYPE3, ACMPXCHGQ,
- "CMPXCHGW", LTYPE3, ACMPXCHGW,
- "CPUID", LTYPE0, ACPUID,
- "DAA", LTYPE0, ADAA,
- "DAS", LTYPE0, ADAS,
- "DATA", LTYPED, ADATA,
- "DECB", LTYPE1, ADECB,
- "DECL", LTYPE1, ADECL,
- "DECQ", LTYPE1, ADECQ,
- "DECW", LTYPE1, ADECW,
- "DIVB", LTYPE2, ADIVB,
- "DIVL", LTYPE2, ADIVL,
- "DIVQ", LTYPE2, ADIVQ,
- "DIVW", LTYPE2, ADIVW,
- "EMMS", LTYPE0, AEMMS,
- "END", LTYPE0, AEND,
- "ENTER", LTYPE2, AENTER,
- "GLOBL", LTYPEG, AGLOBL,
- "HLT", LTYPE0, AHLT,
- "IDIVB", LTYPE2, AIDIVB,
- "IDIVL", LTYPE2, AIDIVL,
- "IDIVQ", LTYPE2, AIDIVQ,
- "IDIVW", LTYPE2, AIDIVW,
- "IMULB", LTYPEI, AIMULB,
- "IMULL", LTYPEI, AIMULL,
- "IMULQ", LTYPEI, AIMULQ,
- "IMULW", LTYPEI, AIMULW,
- "INB", LTYPE0, AINB,
- "INL", LTYPE0, AINL,
- "INW", LTYPE0, AINW,
- "INCB", LTYPE1, AINCB,
- "INCL", LTYPE1, AINCL,
- "INCQ", LTYPE1, AINCQ,
- "INCW", LTYPE1, AINCW,
- "INSB", LTYPE0, AINSB,
- "INSL", LTYPE0, AINSL,
- "INSW", LTYPE0, AINSW,
- "INT", LTYPE2, AINT,
- "INTO", LTYPE0, AINTO,
- "INVD", LTYPE0, AINVD,
- "INVLPG", LTYPE2, AINVLPG,
- "IRETL", LTYPE0, AIRETL,
- "IRETQ", LTYPE0, AIRETQ,
- "IRETW", LTYPE0, AIRETW,
-
- "JOS", LTYPER, AJOS,
- "JO", LTYPER, AJOS, /* alternate */
- "JOC", LTYPER, AJOC,
- "JNO", LTYPER, AJOC, /* alternate */
- "JCS", LTYPER, AJCS,
- "JB", LTYPER, AJCS, /* alternate */
- "JC", LTYPER, AJCS, /* alternate */
- "JNAE", LTYPER, AJCS, /* alternate */
- "JLO", LTYPER, AJCS, /* alternate */
- "JCC", LTYPER, AJCC,
- "JAE", LTYPER, AJCC, /* alternate */
- "JNB", LTYPER, AJCC, /* alternate */
- "JNC", LTYPER, AJCC, /* alternate */
- "JHS", LTYPER, AJCC, /* alternate */
- "JEQ", LTYPER, AJEQ,
- "JE", LTYPER, AJEQ, /* alternate */
- "JZ", LTYPER, AJEQ, /* alternate */
- "JNE", LTYPER, AJNE,
- "JNZ", LTYPER, AJNE, /* alternate */
- "JLS", LTYPER, AJLS,
- "JBE", LTYPER, AJLS, /* alternate */
- "JNA", LTYPER, AJLS, /* alternate */
- "JHI", LTYPER, AJHI,
- "JA", LTYPER, AJHI, /* alternate */
- "JNBE", LTYPER, AJHI, /* alternate */
- "JMI", LTYPER, AJMI,
- "JS", LTYPER, AJMI, /* alternate */
- "JPL", LTYPER, AJPL,
- "JNS", LTYPER, AJPL, /* alternate */
- "JPS", LTYPER, AJPS,
- "JP", LTYPER, AJPS, /* alternate */
- "JPE", LTYPER, AJPS, /* alternate */
- "JPC", LTYPER, AJPC,
- "JNP", LTYPER, AJPC, /* alternate */
- "JPO", LTYPER, AJPC, /* alternate */
- "JLT", LTYPER, AJLT,
- "JL", LTYPER, AJLT, /* alternate */
- "JNGE", LTYPER, AJLT, /* alternate */
- "JGE", LTYPER, AJGE,
- "JNL", LTYPER, AJGE, /* alternate */
- "JLE", LTYPER, AJLE,
- "JNG", LTYPER, AJLE, /* alternate */
- "JGT", LTYPER, AJGT,
- "JG", LTYPER, AJGT, /* alternate */
- "JNLE", LTYPER, AJGT, /* alternate */
-
- "JCXZ", LTYPER, AJCXZ,
- "JMP", LTYPEC, AJMP,
- "LAHF", LTYPE0, ALAHF,
- "LARL", LTYPE3, ALARL,
- "LARW", LTYPE3, ALARW,
- "LEAL", LTYPE3, ALEAL,
- "LEAQ", LTYPE3, ALEAQ,
- "LEAW", LTYPE3, ALEAW,
- "LEAVEL", LTYPE0, ALEAVEL,
- "LEAVEQ", LTYPE0, ALEAVEQ,
- "LEAVEW", LTYPE0, ALEAVEW,
- "LFENCE", LTYPE0, ALFENCE,
- "LOCK", LTYPE0, ALOCK,
- "LODSB", LTYPE0, ALODSB,
- "LODSL", LTYPE0, ALODSL,
- "LODSQ", LTYPE0, ALODSQ,
- "LODSW", LTYPE0, ALODSW,
- "LONG", LTYPE2, ALONG,
- "LOOP", LTYPER, ALOOP,
- "LOOPEQ", LTYPER, ALOOPEQ,
- "LOOPNE", LTYPER, ALOOPNE,
- "LSLL", LTYPE3, ALSLL,
- "LSLW", LTYPE3, ALSLW,
- "MFENCE", LTYPE0, AMFENCE,
- "MODE", LTYPE2, AMODE,
- "MOVB", LTYPE3, AMOVB,
- "MOVL", LTYPEM, AMOVL,
- "MOVQ", LTYPEM, AMOVQ,
- "MOVW", LTYPEM, AMOVW,
- "MOVBLSX", LTYPE3, AMOVBLSX,
- "MOVBLZX", LTYPE3, AMOVBLZX,
- "MOVBQSX", LTYPE3, AMOVBQSX,
- "MOVBQZX", LTYPE3, AMOVBQZX,
- "MOVBWSX", LTYPE3, AMOVBWSX,
- "MOVBWZX", LTYPE3, AMOVBWZX,
- "MOVLQSX", LTYPE3, AMOVLQSX,
- "MOVLQZX", LTYPE3, AMOVLQZX,
- "MOVNTIL", LTYPE3, AMOVNTIL,
- "MOVNTIQ", LTYPE3, AMOVNTIQ,
- "MOVWLSX", LTYPE3, AMOVWLSX,
- "MOVWLZX", LTYPE3, AMOVWLZX,
- "MOVWQSX", LTYPE3, AMOVWQSX,
- "MOVWQZX", LTYPE3, AMOVWQZX,
- "MOVSB", LTYPE0, AMOVSB,
- "MOVSL", LTYPE0, AMOVSL,
- "MOVSQ", LTYPE0, AMOVSQ,
- "MOVSW", LTYPE0, AMOVSW,
- "MULB", LTYPE2, AMULB,
- "MULL", LTYPE2, AMULL,
- "MULQ", LTYPE2, AMULQ,
- "MULW", LTYPE2, AMULW,
- "NEGB", LTYPE1, ANEGB,
- "NEGL", LTYPE1, ANEGL,
- "NEGQ", LTYPE1, ANEGQ,
- "NEGW", LTYPE1, ANEGW,
- "NOP", LTYPEN, ANOP,
- "NOTB", LTYPE1, ANOTB,
- "NOTL", LTYPE1, ANOTL,
- "NOTQ", LTYPE1, ANOTQ,
- "NOTW", LTYPE1, ANOTW,
- "ORB", LTYPE3, AORB,
- "ORL", LTYPE3, AORL,
- "ORQ", LTYPE3, AORQ,
- "ORW", LTYPE3, AORW,
- "OUTB", LTYPE0, AOUTB,
- "OUTL", LTYPE0, AOUTL,
- "OUTW", LTYPE0, AOUTW,
- "OUTSB", LTYPE0, AOUTSB,
- "OUTSL", LTYPE0, AOUTSL,
- "OUTSW", LTYPE0, AOUTSW,
- "POPAL", LTYPE0, APOPAL,
- "POPAW", LTYPE0, APOPAW,
- "POPFL", LTYPE0, APOPFL,
- "POPFQ", LTYPE0, APOPFQ,
- "POPFW", LTYPE0, APOPFW,
- "POPL", LTYPE1, APOPL,
- "POPQ", LTYPE1, APOPQ,
- "POPW", LTYPE1, APOPW,
- "PUSHAL", LTYPE0, APUSHAL,
- "PUSHAW", LTYPE0, APUSHAW,
- "PUSHFL", LTYPE0, APUSHFL,
- "PUSHFQ", LTYPE0, APUSHFQ,
- "PUSHFW", LTYPE0, APUSHFW,
- "PUSHL", LTYPE2, APUSHL,
- "PUSHQ", LTYPE2, APUSHQ,
- "PUSHW", LTYPE2, APUSHW,
- "RCLB", LTYPE3, ARCLB,
- "RCLL", LTYPE3, ARCLL,
- "RCLQ", LTYPE3, ARCLQ,
- "RCLW", LTYPE3, ARCLW,
- "RCRB", LTYPE3, ARCRB,
- "RCRL", LTYPE3, ARCRL,
- "RCRQ", LTYPE3, ARCRQ,
- "RCRW", LTYPE3, ARCRW,
- "RDMSR", LTYPE0, ARDMSR,
- "RDPMC", LTYPE0, ARDPMC,
- "RDTSC", LTYPE0, ARDTSC,
- "REP", LTYPE0, AREP,
- "REPN", LTYPE0, AREPN,
- "RET", LTYPE0, ARET,
- "RETFL", LTYPERT,ARETFL,
- "RETFW", LTYPERT,ARETFW,
- "RETFQ", LTYPERT,ARETFQ,
- "ROLB", LTYPE3, AROLB,
- "ROLL", LTYPE3, AROLL,
- "ROLQ", LTYPE3, AROLQ,
- "ROLW", LTYPE3, AROLW,
- "RORB", LTYPE3, ARORB,
- "RORL", LTYPE3, ARORL,
- "RORQ", LTYPE3, ARORQ,
- "RORW", LTYPE3, ARORW,
- "RSM", LTYPE0, ARSM,
- "SAHF", LTYPE0, ASAHF,
- "SALB", LTYPE3, ASALB,
- "SALL", LTYPE3, ASALL,
- "SALQ", LTYPE3, ASALQ,
- "SALW", LTYPE3, ASALW,
- "SARB", LTYPE3, ASARB,
- "SARL", LTYPE3, ASARL,
- "SARQ", LTYPE3, ASARQ,
- "SARW", LTYPE3, ASARW,
- "SBBB", LTYPE3, ASBBB,
- "SBBL", LTYPE3, ASBBL,
- "SBBQ", LTYPE3, ASBBQ,
- "SBBW", LTYPE3, ASBBW,
- "SCASB", LTYPE0, ASCASB,
- "SCASL", LTYPE0, ASCASL,
- "SCASQ", LTYPE0, ASCASQ,
- "SCASW", LTYPE0, ASCASW,
- "SETCC", LTYPE1, ASETCC,
- "SETCS", LTYPE1, ASETCS,
- "SETEQ", LTYPE1, ASETEQ,
- "SETGE", LTYPE1, ASETGE,
- "SETGT", LTYPE1, ASETGT,
- "SETHI", LTYPE1, ASETHI,
- "SETLE", LTYPE1, ASETLE,
- "SETLS", LTYPE1, ASETLS,
- "SETLT", LTYPE1, ASETLT,
- "SETMI", LTYPE1, ASETMI,
- "SETNE", LTYPE1, ASETNE,
- "SETOC", LTYPE1, ASETOC,
- "SETOS", LTYPE1, ASETOS,
- "SETPC", LTYPE1, ASETPC,
- "SETPL", LTYPE1, ASETPL,
- "SETPS", LTYPE1, ASETPS,
- "SFENCE", LTYPE0, ASFENCE,
- "CDQ", LTYPE0, ACDQ,
- "CWD", LTYPE0, ACWD,
- "CQO", LTYPE0, ACQO,
- "SHLB", LTYPE3, ASHLB,
- "SHLL", LTYPES, ASHLL,
- "SHLQ", LTYPES, ASHLQ,
- "SHLW", LTYPES, ASHLW,
- "SHRB", LTYPE3, ASHRB,
- "SHRL", LTYPES, ASHRL,
- "SHRQ", LTYPES, ASHRQ,
- "SHRW", LTYPES, ASHRW,
- "STC", LTYPE0, ASTC,
- "STD", LTYPE0, ASTD,
- "STI", LTYPE0, ASTI,
- "STOSB", LTYPE0, ASTOSB,
- "STOSL", LTYPE0, ASTOSL,
- "STOSQ", LTYPE0, ASTOSQ,
- "STOSW", LTYPE0, ASTOSW,
- "SUBB", LTYPE3, ASUBB,
- "SUBL", LTYPE3, ASUBL,
- "SUBQ", LTYPE3, ASUBQ,
- "SUBW", LTYPE3, ASUBW,
- "SYSCALL", LTYPE0, ASYSCALL,
- "SYSRET", LTYPE0, ASYSRET,
- "SWAPGS", LTYPE0, ASWAPGS,
- "TESTB", LTYPE3, ATESTB,
- "TESTL", LTYPE3, ATESTL,
- "TESTQ", LTYPE3, ATESTQ,
- "TESTW", LTYPE3, ATESTW,
- "TEXT", LTYPET, ATEXT,
- "VERR", LTYPE2, AVERR,
- "VERW", LTYPE2, AVERW,
- "QUAD", LTYPE2, AQUAD,
- "WAIT", LTYPE0, AWAIT,
- "WBINVD", LTYPE0, AWBINVD,
- "WRMSR", LTYPE0, AWRMSR,
- "WORD", LTYPE2, AWORD,
- "XADDB", LTYPE3, AXADDB,
- "XADDL", LTYPE3, AXADDL,
- "XADDQ", LTYPE3, AXADDQ,
- "XADDW", LTYPE3, AXADDW,
- "XCHGB", LTYPE3, AXCHGB,
- "XCHGL", LTYPE3, AXCHGL,
- "XCHGQ", LTYPE3, AXCHGQ,
- "XCHGW", LTYPE3, AXCHGW,
- "XLAT", LTYPE2, AXLAT,
- "XORB", LTYPE3, AXORB,
- "XORL", LTYPE3, AXORL,
- "XORQ", LTYPE3, AXORQ,
- "XORW", LTYPE3, AXORW,
-
- "CMOVLCC", LTYPE3, ACMOVLCC,
- "CMOVLCS", LTYPE3, ACMOVLCS,
- "CMOVLEQ", LTYPE3, ACMOVLEQ,
- "CMOVLGE", LTYPE3, ACMOVLGE,
- "CMOVLGT", LTYPE3, ACMOVLGT,
- "CMOVLHI", LTYPE3, ACMOVLHI,
- "CMOVLLE", LTYPE3, ACMOVLLE,
- "CMOVLLS", LTYPE3, ACMOVLLS,
- "CMOVLLT", LTYPE3, ACMOVLLT,
- "CMOVLMI", LTYPE3, ACMOVLMI,
- "CMOVLNE", LTYPE3, ACMOVLNE,
- "CMOVLOC", LTYPE3, ACMOVLOC,
- "CMOVLOS", LTYPE3, ACMOVLOS,
- "CMOVLPC", LTYPE3, ACMOVLPC,
- "CMOVLPL", LTYPE3, ACMOVLPL,
- "CMOVLPS", LTYPE3, ACMOVLPS,
- "CMOVQCC", LTYPE3, ACMOVQCC,
- "CMOVQCS", LTYPE3, ACMOVQCS,
- "CMOVQEQ", LTYPE3, ACMOVQEQ,
- "CMOVQGE", LTYPE3, ACMOVQGE,
- "CMOVQGT", LTYPE3, ACMOVQGT,
- "CMOVQHI", LTYPE3, ACMOVQHI,
- "CMOVQLE", LTYPE3, ACMOVQLE,
- "CMOVQLS", LTYPE3, ACMOVQLS,
- "CMOVQLT", LTYPE3, ACMOVQLT,
- "CMOVQMI", LTYPE3, ACMOVQMI,
- "CMOVQNE", LTYPE3, ACMOVQNE,
- "CMOVQOC", LTYPE3, ACMOVQOC,
- "CMOVQOS", LTYPE3, ACMOVQOS,
- "CMOVQPC", LTYPE3, ACMOVQPC,
- "CMOVQPL", LTYPE3, ACMOVQPL,
- "CMOVQPS", LTYPE3, ACMOVQPS,
- "CMOVWCC", LTYPE3, ACMOVWCC,
- "CMOVWCS", LTYPE3, ACMOVWCS,
- "CMOVWEQ", LTYPE3, ACMOVWEQ,
- "CMOVWGE", LTYPE3, ACMOVWGE,
- "CMOVWGT", LTYPE3, ACMOVWGT,
- "CMOVWHI", LTYPE3, ACMOVWHI,
- "CMOVWLE", LTYPE3, ACMOVWLE,
- "CMOVWLS", LTYPE3, ACMOVWLS,
- "CMOVWLT", LTYPE3, ACMOVWLT,
- "CMOVWMI", LTYPE3, ACMOVWMI,
- "CMOVWNE", LTYPE3, ACMOVWNE,
- "CMOVWOC", LTYPE3, ACMOVWOC,
- "CMOVWOS", LTYPE3, ACMOVWOS,
- "CMOVWPC", LTYPE3, ACMOVWPC,
- "CMOVWPL", LTYPE3, ACMOVWPL,
- "CMOVWPS", LTYPE3, ACMOVWPS,
-
- "FMOVB", LTYPE3, AFMOVB,
- "FMOVBP", LTYPE3, AFMOVBP,
- "FMOVD", LTYPE3, AFMOVD,
- "FMOVDP", LTYPE3, AFMOVDP,
- "FMOVF", LTYPE3, AFMOVF,
- "FMOVFP", LTYPE3, AFMOVFP,
- "FMOVL", LTYPE3, AFMOVL,
- "FMOVLP", LTYPE3, AFMOVLP,
- "FMOVV", LTYPE3, AFMOVV,
- "FMOVVP", LTYPE3, AFMOVVP,
- "FMOVW", LTYPE3, AFMOVW,
- "FMOVWP", LTYPE3, AFMOVWP,
- "FMOVX", LTYPE3, AFMOVX,
- "FMOVXP", LTYPE3, AFMOVXP,
- "FCOMB", LTYPE3, AFCOMB,
- "FCOMBP", LTYPE3, AFCOMBP,
- "FCOMD", LTYPE3, AFCOMD,
- "FCOMDP", LTYPE3, AFCOMDP,
- "FCOMDPP", LTYPE3, AFCOMDPP,
- "FCOMF", LTYPE3, AFCOMF,
- "FCOMFP", LTYPE3, AFCOMFP,
- "FCOML", LTYPE3, AFCOML,
- "FCOMLP", LTYPE3, AFCOMLP,
- "FCOMW", LTYPE3, AFCOMW,
- "FCOMWP", LTYPE3, AFCOMWP,
- "FUCOM", LTYPE3, AFUCOM,
- "FUCOMP", LTYPE3, AFUCOMP,
- "FUCOMPP", LTYPE3, AFUCOMPP,
- "FADDW", LTYPE3, AFADDW,
- "FADDL", LTYPE3, AFADDL,
- "FADDF", LTYPE3, AFADDF,
- "FADDD", LTYPE3, AFADDD,
- "FADDDP", LTYPE3, AFADDDP,
- "FSUBDP", LTYPE3, AFSUBDP,
- "FSUBW", LTYPE3, AFSUBW,
- "FSUBL", LTYPE3, AFSUBL,
- "FSUBF", LTYPE3, AFSUBF,
- "FSUBD", LTYPE3, AFSUBD,
- "FSUBRDP", LTYPE3, AFSUBRDP,
- "FSUBRW", LTYPE3, AFSUBRW,
- "FSUBRL", LTYPE3, AFSUBRL,
- "FSUBRF", LTYPE3, AFSUBRF,
- "FSUBRD", LTYPE3, AFSUBRD,
- "FMULDP", LTYPE3, AFMULDP,
- "FMULW", LTYPE3, AFMULW,
- "FMULL", LTYPE3, AFMULL,
- "FMULF", LTYPE3, AFMULF,
- "FMULD", LTYPE3, AFMULD,
- "FDIVDP", LTYPE3, AFDIVDP,
- "FDIVW", LTYPE3, AFDIVW,
- "FDIVL", LTYPE3, AFDIVL,
- "FDIVF", LTYPE3, AFDIVF,
- "FDIVD", LTYPE3, AFDIVD,
- "FDIVRDP", LTYPE3, AFDIVRDP,
- "FDIVRW", LTYPE3, AFDIVRW,
- "FDIVRL", LTYPE3, AFDIVRL,
- "FDIVRF", LTYPE3, AFDIVRF,
- "FDIVRD", LTYPE3, AFDIVRD,
- "FXCHD", LTYPE3, AFXCHD,
- "FFREE", LTYPE1, AFFREE,
- "FLDCW", LTYPE2, AFLDCW,
- "FLDENV", LTYPE1, AFLDENV,
- "FRSTOR", LTYPE2, AFRSTOR,
- "FSAVE", LTYPE1, AFSAVE,
- "FSTCW", LTYPE1, AFSTCW,
- "FSTENV", LTYPE1, AFSTENV,
- "FSTSW", LTYPE1, AFSTSW,
- "F2XM1", LTYPE0, AF2XM1,
- "FABS", LTYPE0, AFABS,
- "FCHS", LTYPE0, AFCHS,
- "FCLEX", LTYPE0, AFCLEX,
- "FCOS", LTYPE0, AFCOS,
- "FDECSTP", LTYPE0, AFDECSTP,
- "FINCSTP", LTYPE0, AFINCSTP,
- "FINIT", LTYPE0, AFINIT,
- "FLD1", LTYPE0, AFLD1,
- "FLDL2E", LTYPE0, AFLDL2E,
- "FLDL2T", LTYPE0, AFLDL2T,
- "FLDLG2", LTYPE0, AFLDLG2,
- "FLDLN2", LTYPE0, AFLDLN2,
- "FLDPI", LTYPE0, AFLDPI,
- "FLDZ", LTYPE0, AFLDZ,
- "FNOP", LTYPE0, AFNOP,
- "FPATAN", LTYPE0, AFPATAN,
- "FPREM", LTYPE0, AFPREM,
- "FPREM1", LTYPE0, AFPREM1,
- "FPTAN", LTYPE0, AFPTAN,
- "FRNDINT", LTYPE0, AFRNDINT,
- "FSCALE", LTYPE0, AFSCALE,
- "FSIN", LTYPE0, AFSIN,
- "FSINCOS", LTYPE0, AFSINCOS,
- "FSQRT", LTYPE0, AFSQRT,
- "FTST", LTYPE0, AFTST,
- "FXAM", LTYPE0, AFXAM,
- "FXTRACT", LTYPE0, AFXTRACT,
- "FYL2X", LTYPE0, AFYL2X,
- "FYL2XP1", LTYPE0, AFYL2XP1,
-
- "ADDPD", LTYPE3, AADDPD,
- "ADDPS", LTYPE3, AADDPS,
- "ADDSD", LTYPE3, AADDSD,
- "ADDSS", LTYPE3, AADDSS,
- "ANDNPD", LTYPE3, AANDNPD,
- "ANDNPS", LTYPE3, AANDNPS,
- "ANDPD", LTYPE3, AANDPD,
- "ANDPS", LTYPE3, AANDPS,
- "CMPPD", LTYPEXC,ACMPPD,
- "CMPPS", LTYPEXC,ACMPPS,
- "CMPSD", LTYPEXC,ACMPSD,
- "CMPSS", LTYPEXC,ACMPSS,
- "COMISD", LTYPE3, ACOMISD,
- "COMISS", LTYPE3, ACOMISS,
- "CVTPL2PD", LTYPE3, ACVTPL2PD,
- "CVTPL2PS", LTYPE3, ACVTPL2PS,
- "CVTPD2PL", LTYPE3, ACVTPD2PL,
- "CVTPD2PS", LTYPE3, ACVTPD2PS,
- "CVTPS2PL", LTYPE3, ACVTPS2PL,
- "PF2IW", LTYPE3, APF2IW,
- "PF2IL", LTYPE3, APF2IL,
- "PF2ID", LTYPE3, APF2IL, /* syn */
- "PI2FL", LTYPE3, API2FL,
- "PI2FD", LTYPE3, API2FL, /* syn */
- "PI2FW", LTYPE3, API2FW,
- "CVTPS2PD", LTYPE3, ACVTPS2PD,
- "CVTSD2SL", LTYPE3, ACVTSD2SL,
- "CVTSD2SQ", LTYPE3, ACVTSD2SQ,
- "CVTSD2SS", LTYPE3, ACVTSD2SS,
- "CVTSL2SD", LTYPE3, ACVTSL2SD,
- "CVTSQ2SD", LTYPE3, ACVTSQ2SD,
- "CVTSL2SS", LTYPE3, ACVTSL2SS,
- "CVTSQ2SS", LTYPE3, ACVTSQ2SS,
- "CVTSS2SD", LTYPE3, ACVTSS2SD,
- "CVTSS2SL", LTYPE3, ACVTSS2SL,
- "CVTSS2SQ", LTYPE3, ACVTSS2SQ,
- "CVTTPD2PL", LTYPE3, ACVTTPD2PL,
- "CVTTPS2PL", LTYPE3, ACVTTPS2PL,
- "CVTTSD2SL", LTYPE3, ACVTTSD2SL,
- "CVTTSD2SQ", LTYPE3, ACVTTSD2SQ,
- "CVTTSS2SL", LTYPE3, ACVTTSS2SL,
- "CVTTSS2SQ", LTYPE3, ACVTTSS2SQ,
- "DIVPD", LTYPE3, ADIVPD,
- "DIVPS", LTYPE3, ADIVPS,
- "DIVSD", LTYPE3, ADIVSD,
- "DIVSS", LTYPE3, ADIVSS,
- "FXRSTOR", LTYPE2, AFXRSTOR,
- "FXRSTOR64", LTYPE2, AFXRSTOR64,
- "FXSAVE", LTYPE1, AFXSAVE,
- "FXSAVE64", LTYPE1, AFXSAVE64,
- "LDMXCSR", LTYPE2, ALDMXCSR,
- "MASKMOVOU", LTYPE3, AMASKMOVOU,
- "MASKMOVDQU", LTYPE3, AMASKMOVOU, /* syn */
- "MASKMOVQ", LTYPE3, AMASKMOVQ,
- "MAXPD", LTYPE3, AMAXPD,
- "MAXPS", LTYPE3, AMAXPS,
- "MAXSD", LTYPE3, AMAXSD,
- "MAXSS", LTYPE3, AMAXSS,
- "MINPD", LTYPE3, AMINPD,
- "MINPS", LTYPE3, AMINPS,
- "MINSD", LTYPE3, AMINSD,
- "MINSS", LTYPE3, AMINSS,
- "MOVAPD", LTYPE3, AMOVAPD,
- "MOVAPS", LTYPE3, AMOVAPS,
- "MOVD", LTYPE3, AMOVQ, /* syn */
- "MOVDQ2Q", LTYPE3, AMOVQ, /* syn */
- "MOVO", LTYPE3, AMOVO,
- "MOVOA", LTYPE3, AMOVO, /* syn */
- "MOVOU", LTYPE3, AMOVOU,
- "MOVHLPS", LTYPE3, AMOVHLPS,
- "MOVHPD", LTYPE3, AMOVHPD,
- "MOVHPS", LTYPE3, AMOVHPS,
- "MOVLHPS", LTYPE3, AMOVLHPS,
- "MOVLPD", LTYPE3, AMOVLPD,
- "MOVLPS", LTYPE3, AMOVLPS,
- "MOVMSKPD", LTYPE3, AMOVMSKPD,
- "MOVMSKPS", LTYPE3, AMOVMSKPS,
- "MOVNTO", LTYPE3, AMOVNTO,
- "MOVNTDQ", LTYPE3, AMOVNTO, /* syn */
- "MOVNTPD", LTYPE3, AMOVNTPD,
- "MOVNTPS", LTYPE3, AMOVNTPS,
- "MOVNTQ", LTYPE3, AMOVNTQ,
- "MOVQOZX", LTYPE3, AMOVQOZX,
- "MOVSD", LTYPE3, AMOVSD,
- "MOVSS", LTYPE3, AMOVSS,
- "MOVUPD", LTYPE3, AMOVUPD,
- "MOVUPS", LTYPE3, AMOVUPS,
- "MULPD", LTYPE3, AMULPD,
- "MULPS", LTYPE3, AMULPS,
- "MULSD", LTYPE3, AMULSD,
- "MULSS", LTYPE3, AMULSS,
- "ORPD", LTYPE3, AORPD,
- "ORPS", LTYPE3, AORPS,
- "PACKSSLW", LTYPE3, APACKSSLW,
- "PACKSSWB", LTYPE3, APACKSSWB,
- "PACKUSWB", LTYPE3, APACKUSWB,
- "PADDB", LTYPE3, APADDB,
- "PADDL", LTYPE3, APADDL,
- "PADDQ", LTYPE3, APADDQ,
- "PADDSB", LTYPE3, APADDSB,
- "PADDSW", LTYPE3, APADDSW,
- "PADDUSB", LTYPE3, APADDUSB,
- "PADDUSW", LTYPE3, APADDUSW,
- "PADDW", LTYPE3, APADDW,
- "PAND", LTYPE3, APAND,
- "PANDB", LTYPE3, APANDB,
- "PANDL", LTYPE3, APANDL,
- "PANDSB", LTYPE3, APANDSB,
- "PANDSW", LTYPE3, APANDSW,
- "PANDUSB", LTYPE3, APANDUSB,
- "PANDUSW", LTYPE3, APANDUSW,
- "PANDW", LTYPE3, APANDW,
- "PANDN", LTYPE3, APANDN,
- "PAVGB", LTYPE3, APAVGB,
- "PAVGW", LTYPE3, APAVGW,
- "PCMPEQB", LTYPE3, APCMPEQB,
- "PCMPEQL", LTYPE3, APCMPEQL,
- "PCMPEQW", LTYPE3, APCMPEQW,
- "PCMPGTB", LTYPE3, APCMPGTB,
- "PCMPGTL", LTYPE3, APCMPGTL,
- "PCMPGTW", LTYPE3, APCMPGTW,
- "PEXTRW", LTYPEX, APEXTRW,
- "PINSRW", LTYPEX, APINSRW,
- "PMADDWL", LTYPE3, APMADDWL,
- "PMAXSW", LTYPE3, APMAXSW,
- "PMAXUB", LTYPE3, APMAXUB,
- "PMINSW", LTYPE3, APMINSW,
- "PMINUB", LTYPE3, APMINUB,
- "PMOVMSKB", LTYPE3, APMOVMSKB,
- "PMULHRW", LTYPE3, APMULHRW,
- "PMULHUW", LTYPE3, APMULHUW,
- "PMULHW", LTYPE3, APMULHW,
- "PMULLW", LTYPE3, APMULLW,
- "PMULULQ", LTYPE3, APMULULQ,
- "POR", LTYPE3, APOR,
- "PSADBW", LTYPE3, APSADBW,
- "PSHUFHW", LTYPEX, APSHUFHW,
- "PSHUFL", LTYPEX, APSHUFL,
- "PSHUFLW", LTYPEX, APSHUFLW,
- "PSHUFW", LTYPEX, APSHUFW,
- "PSLLO", LTYPE3, APSLLO,
- "PSLLDQ", LTYPE3, APSLLO, /* syn */
- "PSLLL", LTYPE3, APSLLL,
- "PSLLQ", LTYPE3, APSLLQ,
- "PSLLW", LTYPE3, APSLLW,
- "PSRAL", LTYPE3, APSRAL,
- "PSRAW", LTYPE3, APSRAW,
- "PSRLO", LTYPE3, APSRLO,
- "PSRLDQ", LTYPE3, APSRLO, /* syn */
- "PSRLL", LTYPE3, APSRLL,
- "PSRLQ", LTYPE3, APSRLQ,
- "PSRLW", LTYPE3, APSRLW,
- "PSUBB", LTYPE3, APSUBB,
- "PSUBL", LTYPE3, APSUBL,
- "PSUBQ", LTYPE3, APSUBQ,
- "PSUBSB", LTYPE3, APSUBSB,
- "PSUBSW", LTYPE3, APSUBSW,
- "PSUBUSB", LTYPE3, APSUBUSB,
- "PSUBUSW", LTYPE3, APSUBUSW,
- "PSUBW", LTYPE3, APSUBW,
- "PUNPCKHBW", LTYPE3, APUNPCKHBW,
- "PUNPCKHLQ", LTYPE3, APUNPCKHLQ,
- "PUNPCKHQDQ", LTYPE3, APUNPCKHQDQ,
- "PUNPCKHWL", LTYPE3, APUNPCKHWL,
- "PUNPCKLBW", LTYPE3, APUNPCKLBW,
- "PUNPCKLLQ", LTYPE3, APUNPCKLLQ,
- "PUNPCKLQDQ", LTYPE3, APUNPCKLQDQ,
- "PUNPCKLWL", LTYPE3, APUNPCKLWL,
- "PXOR", LTYPE3, APXOR,
- "RCPPS", LTYPE3, ARCPPS,
- "RCPSS", LTYPE3, ARCPSS,
- "RSQRTPS", LTYPE3, ARSQRTPS,
- "RSQRTSS", LTYPE3, ARSQRTSS,
- "SHUFPD", LTYPEX, ASHUFPD,
- "SHUFPS", LTYPEX, ASHUFPS,
- "SQRTPD", LTYPE3, ASQRTPD,
- "SQRTPS", LTYPE3, ASQRTPS,
- "SQRTSD", LTYPE3, ASQRTSD,
- "SQRTSS", LTYPE3, ASQRTSS,
- "STMXCSR", LTYPE1, ASTMXCSR,
- "SUBPD", LTYPE3, ASUBPD,
- "SUBPS", LTYPE3, ASUBPS,
- "SUBSD", LTYPE3, ASUBSD,
- "SUBSS", LTYPE3, ASUBSS,
- "UCOMISD", LTYPE3, AUCOMISD,
- "UCOMISS", LTYPE3, AUCOMISS,
- "UNPCKHPD", LTYPE3, AUNPCKHPD,
- "UNPCKHPS", LTYPE3, AUNPCKHPS,
- "UNPCKLPD", LTYPE3, AUNPCKLPD,
- "UNPCKLPS", LTYPE3, AUNPCKLPS,
- "XORPD", LTYPE3, AXORPD,
- "XORPS", LTYPE3, AXORPS,
-
- 0
-};
-
-void
-cinit(void)
-{
- Sym *s;
- int i;
-
- nullgen.sym = S;
- nullgen.offset = 0;
- if(FPCHIP)
- nullgen.dval = 0;
- for(i=0; i<sizeof(nullgen.sval); i++)
- nullgen.sval[i] = 0;
- nullgen.type = D_NONE;
- nullgen.index = D_NONE;
- nullgen.scale = 0;
-
- 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);
- if(s->type != LNAME)
- yyerror("double initialization %s", itab[i].name);
- s->type = itab[i].type;
- s->value = itab[i].value;
- }
-
- pathname = allocn(pathname, 0, 100);
- if(getwd(pathname, 99) == 0) {
- pathname = allocn(pathname, 100, 900);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
- }
-}
-
-void
-checkscale(int scale)
-{
-
- switch(scale) {
- case 1:
- case 2:
- case 4:
- case 8:
- return;
- }
- yyerror("scale must be 1248: %d", scale);
-}
-
-void
-syminit(Sym *s)
-{
-
- s->type = LNAME;
- s->value = 0;
-}
-
-void
-cclean(void)
-{
- Gen2 g2;
-
- g2.from = nullgen;
- g2.to = nullgen;
- outcode(AEND, &g2);
- Bflush(&obuf);
-}
-
-void
-zname(char *n, int t, int s)
-{
-
- Bputc(&obuf, ANAME); /* as(2) */
- Bputc(&obuf, ANAME>>8);
- Bputc(&obuf, t); /* type */
- Bputc(&obuf, s); /* sym */
- while(*n) {
- Bputc(&obuf, *n);
- n++;
- }
- Bputc(&obuf, 0);
-}
-
-void
-zaddr(Gen *a, int s)
-{
- int32 l;
- int i, t;
- char *n;
- Ieee e;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(a->offset != 0) {
- t |= T_OFFSET;
- l = a->offset;
- if((vlong)l != a->offset)
- t |= T_64;
- }
- if(s != 0)
- t |= T_SYM;
-
- switch(a->type) {
- default:
- t |= T_TYPE;
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- case D_NONE:
- break;
- }
- Bputc(&obuf, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- Bputc(&obuf, a->index);
- Bputc(&obuf, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- Bputc(&obuf, l);
- Bputc(&obuf, l>>8);
- Bputc(&obuf, l>>16);
- Bputc(&obuf, l>>24);
- if(t & T_64) {
- l = a->offset>>32;
- Bputc(&obuf, l);
- Bputc(&obuf, l>>8);
- Bputc(&obuf, l>>16);
- Bputc(&obuf, l>>24);
- }
- }
- if(t & T_SYM) /* implies sym */
- Bputc(&obuf, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->dval);
- l = e.l;
- Bputc(&obuf, l);
- Bputc(&obuf, l>>8);
- Bputc(&obuf, l>>16);
- Bputc(&obuf, l>>24);
- l = e.h;
- Bputc(&obuf, l);
- Bputc(&obuf, l>>8);
- Bputc(&obuf, l>>16);
- Bputc(&obuf, l>>24);
- return;
- }
- if(t & T_SCONST) {
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- Bputc(&obuf, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- Bputc(&obuf, a->type);
-}
-
-void
-outcode(int a, Gen2 *g2)
-{
- int sf, st, t;
- Sym *s;
-
- if(pass == 1)
- goto out;
-
-jackpot:
- sf = 0;
- s = g2->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = g2->from.type;
- if(t == D_ADDR)
- t = g2->from.index;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = g2->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = g2->to.type;
- if(t == D_ADDR)
- t = g2->to.index;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- Bputc(&obuf, a);
- Bputc(&obuf, a>>8);
- Bputc(&obuf, stmtline);
- Bputc(&obuf, stmtline>>8);
- Bputc(&obuf, stmtline>>16);
- Bputc(&obuf, stmtline>>24);
- zaddr(&g2->from, sf);
- zaddr(&g2->to, st);
-
-out:
- if(a != AGLOBL && a != ADATA)
- pc++;
-}
-
-void
-outhist(void)
-{
- Gen g;
- Hist *h;
- char *p, *q, *op, c;
- int n;
-
- g = nullgen;
- c = pathchar();
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- op = 0;
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname+2;
- c = *p;
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = strchr(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- Bputc(&obuf, ANAME);
- Bputc(&obuf, ANAME>>8);
- Bputc(&obuf, D_FILE); /* type */
- Bputc(&obuf, 1); /* sym */
- Bputc(&obuf, '<');
- Bwrite(&obuf, p, n);
- Bputc(&obuf, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- g.offset = h->offset;
-
- Bputc(&obuf, AHISTORY);
- Bputc(&obuf, AHISTORY>>8);
- Bputc(&obuf, h->line);
- Bputc(&obuf, h->line>>8);
- Bputc(&obuf, h->line>>16);
- Bputc(&obuf, h->line>>24);
- zaddr(&nullgen, 0);
- zaddr(&g, 0);
- }
-}
-
-void
-pragbldicks(void)
-{
- while(getnsc() != '\n')
- ;
-}
-
-void
-praghjdicks(void)
-{
- while(getnsc() != '\n')
- ;
-}
-
-#include "../cc/lexbody"
-#include "../cc/macbody"
diff --git a/src/cmd/6c/Makefile b/src/cmd/6c/Makefile
deleted file mode 100644
index 484e16def..000000000
--- a/src/cmd/6c/Makefile
+++ /dev/null
@@ -1,36 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=6c
-
-HFILES=\
- gc.h\
- ../6l/6.out.h\
- ../cc/cc.h\
-
-OFILES=\
- cgen.$O\
- list.$O\
- sgen.$O\
- swt.$O\
- txt.$O\
- pgen.$O\
- pswt.$O\
- div.$O\
- mul.$O\
- reg.$O\
- peep.$O\
- machcap.$O\
- ../6l/enam.$O\
-
-LIB=\
- ../cc/cc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../cc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
deleted file mode 100644
index 7aa4aa976..000000000
--- a/src/cmd/6c/cgen.c
+++ /dev/null
@@ -1,1980 +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"
-
-/* ,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]) {
- 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);
- 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);
- 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 == 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) {
- if(l->addable >= INDEXED) {
- t = l;
- l = r;
- r = t;
- }
- /* should favour AX */
- 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);
- 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);
- 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;
- }
- o = 0;
- if(REGARG >= 0)
- o = reg[REGARG];
- 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)
- if(o != reg[REGARG])
- reg[REGARG]--;
- if(nn != Z) {
- regret(&nod, n);
- gmove(&nod, nn);
- regfree(&nod);
- }
- break;
-
- case OIND:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- regialloc(&nod, n, nn);
- r = l;
- while(r->op == OADD)
- r = r->right;
- if(sconst(r)) {
- v = r->vconst;
- r->vconst = 0;
- cgen(l, &nod);
- nod.xoffset += v;
- r->vconst = v;
- } else
- cgen(l, &nod);
- regind(&nod, n);
- 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;
- 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:
- 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)
- o = comrel[relindex(o)];
- if(l->complex >= FNX && r->complex >= FNX) {
- regret(&nod, r);
- cgen(r, &nod);
- regsalloc(&nod1, r);
- gmove(&nod, &nod1);
- regfree(&nod);
- nod = *n;
- nod.right = &nod1;
- boolgen(&nod, true, nn);
- break;
- }
- if(immconst(l)) {
- 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 com;
- }
- 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);
-
- 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);
- 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(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[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;
- }
-
- 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[TLONG];
- 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[TLONG];
- 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[TLONG];
- 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[TLONG];
- 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 249a8ed80..000000000
--- a/src/cmd/6c/doc.go
+++ /dev/null
@@ -1,14 +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.
-
-/*
-
-6c is a version of the Plan 9 C compiler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2c
-
-Its target architecture is the x86-64, referred to by these tools as amd64.
-
-*/
-package documentation
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
deleted file mode 100644
index 775d97281..000000000
--- a/src/cmd/6c/gc.h
+++ /dev/null
@@ -1,407 +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 Adr Adr;
-typedef struct Prog Prog;
-typedef struct Case Case;
-typedef struct C1 C1;
-typedef struct Var Var;
-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;
-
-struct Adr
-{
- vlong offset;
- double dval;
- char sval[NSNAME];
-
- Sym* sym;
- uchar type;
- uchar index;
- uchar etype;
- uchar scale; /* doubles as width in DATA op */
-};
-#define A ((Adr*)0)
-
-#define INDEXED 9
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* link;
- int32 lineno;
- short as;
-};
-#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 Var
-{
- vlong offset;
- Sym* sym;
- char name;
- char etype;
-};
-
-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* firstp;
-EXTERN Prog* lastp;
-EXTERN int32 maxargsafe;
-EXTERN int mnstring;
-EXTERN int retok;
-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 Var var[NVAR];
-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(void);
-
-/*
- * 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*);
-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*, Adr*);
-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*);
-
-/*
- * swt.c
- */
-int swcmp(const void*, const void*);
-void doswit(Node*);
-void swit1(C1*, int, int32, Node*);
-void cas(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);
-void ieeedtod(Ieee*, double);
-
-/*
- * list
- */
-void listinit(void);
-int Pconv(Fmt*);
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Sconv(Fmt*);
-int Rconv(Fmt*);
-int Xconv(Fmt*);
-int Bconv(Fmt*);
-
-/*
- * reg.c
- */
-Reg* rega(void);
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Adr*);
-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(Adr*, int);
-
-/*
- * peep.c
- */
-void peep(void);
-void excise(Reg*);
-Reg* uniqp(Reg*);
-Reg* uniqs(Reg*);
-int regtyp(Adr*);
-int anyvar(Adr*);
-int subprop(Reg*);
-int copyprop(Reg*);
-int copy1(Adr*, Adr*, Reg*, int);
-int copyu(Prog*, Adr*, Adr*);
-
-int copyas(Adr*, Adr*);
-int copyau(Adr*, Adr*);
-int copysub(Adr*, Adr*, Adr*, int);
-int copysub1(Prog*, Adr*, Adr*, int);
-
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
-
-#define D_HI D_NONE
-#define D_LO D_NONE
-
-#define isregtype(t) ((t)>= D_AX && (t)<=D_R15)
-
-/*
- * 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*);
-
-#pragma varargck type "A" int
-#pragma varargck type "B" Bits
-#pragma varargck type "D" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "S" char*
-
-#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 4293203c0..000000000
--- a/src/cmd/6c/list.c
+++ /dev/null
@@ -1,396 +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)
-{
-
- fmtinstall('A', Aconv);
- fmtinstall('B', Bconv);
- fmtinstall('P', Pconv);
- fmtinstall('S', Sconv);
- fmtinstall('D', Dconv);
- fmtinstall('R', Rconv);
-}
-
-int
-Bconv(Fmt *fp)
-{
- char str[STRINGSZ], ss[STRINGSZ], *s;
- Bits bits;
- int i;
-
- str[0] = 0;
- bits = va_arg(fp->args, Bits);
- while(bany(&bits)) {
- i = bnum(bits);
- if(str[0])
- strcat(str, " ");
- if(var[i].sym == S) {
- sprint(ss, "$%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);
-}
-
-int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- switch(p->as) {
- case ADATA:
- sprint(str, "(%L) %A %D/%d,%D",
- p->lineno, p->as, &p->from, p->from.scale, &p->to);
- break;
-
- case ATEXT:
- if(p->from.scale) {
- sprint(str, "(%L) %A %D,%d,%lD",
- p->lineno, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- sprint(str, "(%L) %A %D,%lD",
- p->lineno, p->as, &p->from, &p->to);
- break;
-
- default:
- sprint(str, "(%L) %A %D,%lD",
- p->lineno, p->as, &p->from, &p->to);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Adr *a;
- int i;
-
- a = va_arg(fp->args, Adr*);
- i = a->type;
-
- if(fp->flags & FmtLong) {
- if(i != D_CONST) {
- // ATEXT dst is not constant
- sprint(str, "!!%D", a);
- goto brk;
- }
- sprint(str, "$%lld-%lld", a->offset&0xffffffffLL,
- (a->offset>>32)&0xffffffffLL);
- goto brk;
- }
-
- if(i >= D_INDIR) {
- if(a->offset)
- sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
- else
- sprint(str, "(%R)", i-D_INDIR);
- goto brk;
- }
- switch(i) {
-
- default:
- if(a->offset)
- sprint(str, "$%lld,%R", a->offset, i);
- else
- sprint(str, "%R", i);
- break;
-
- case D_NONE:
- str[0] = 0;
- break;
-
- case D_BRANCH:
- sprint(str, "%lld(PC)", a->offset-pc);
- break;
-
- case D_EXTERN:
- sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
- break;
-
- case D_STATIC:
- sprint(str, "%s<>+%lld(SB)", a->sym->name,
- a->offset);
- break;
-
- case D_AUTO:
- if(a->sym) {
- sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
- break;
- }
- sprint(str, "%lld(SP)", a->offset);
- break;
-
- case D_PARAM:
- if(a->sym) {
- sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
- break;
- }
- sprint(str, "%lld(FP)", a->offset);
- break;
-
- case D_CONST:
- sprint(str, "$%lld", a->offset);
- break;
-
- case D_FCONST:
- sprint(str, "$(%.17e)", a->dval);
- break;
-
- case D_SCONST:
- sprint(str, "$\"%S\"", a->sval);
- break;
-
- case D_ADDR:
- a->type = a->index;
- a->index = D_NONE;
- sprint(str, "$%D", a);
- a->index = a->type;
- a->type = D_ADDR;
- goto conv;
- }
-brk:
- if(a->index != D_NONE) {
- sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
- strcat(str, s);
- }
-conv:
- return fmtstrcpy(fp, str);
-}
-
-char* regstr[] =
-{
- "AL", /* [D_AL] */
- "CL",
- "DL",
- "BL",
- "SPB",
- "BPB",
- "SIB",
- "DIB",
- "R8B",
- "R9B",
- "R10B",
- "R11B",
- "R12B",
- "R13B",
- "R14B",
- "R15B",
-
- "AX", /* [D_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
- "R8",
- "R9",
- "R10",
- "R11",
- "R12",
- "R13",
- "R14",
- "R15",
-
- "AH",
- "CH",
- "DH",
- "BH",
-
- "F0", /* [D_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "M0",
- "M1",
- "M2",
- "M3",
- "M4",
- "M5",
- "M6",
- "M7",
-
- "X0",
- "X1",
- "X2",
- "X3",
- "X4",
- "X5",
- "X6",
- "X7",
- "X8",
- "X9",
- "X10",
- "X11",
- "X12",
- "X13",
- "X14",
- "X15",
-
- "CS", /* [D_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
-
- "CR0", /* [D_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
- "CR8",
- "CR9",
- "CR10",
- "CR11",
- "CR12",
- "CR13",
- "CR14",
- "CR15",
-
- "DR0", /* [D_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [D_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "NONE", /* [D_NONE] */
-};
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r >= D_AL && r <= D_NONE)
- sprint(str, "%s", regstr[r-D_AL]);
- else
- sprint(str, "gok(%d)", r);
-
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(double); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- 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/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 ab6883e7a..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
-{
- char vals[10];
-};
-
-struct Mparam
-{
- uint32 value;
- char alg;
- char neg;
- char shift;
- char arg;
- char 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;
- char *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 8b82adbf5..000000000
--- a/src/cmd/6c/peep.c
+++ /dev/null
@@ -1,890 +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(Adr *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;
- Adr *v1, *v2;
- Reg *r;
- int t;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case ACALL:
- return 0;
-
- case AIMULL:
- case AIMULQ:
- case AIMULW:
- if(p->to.type != D_NONE)
- break;
-
- 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 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:
-
- case AREP:
- case AREPN:
-
- case ACWD:
- case ACDQ:
- case ACQO:
-
- case ASTOSB:
- case ASTOSL:
- case ASTOSQ:
- case AMOVSB:
- case AMOVSL:
- case AMOVSQ:
- 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;
- Adr *v1, *v2;
- Reg *r;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Adr *v1, Adr *v2, Reg *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, A);
- switch(t) {
- case 2: /* rar, cant split */
- if(debug['P'])
- print("; %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, Adr *v, Adr *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 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 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(Adr *a, Adr *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(Adr *a, Adr *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(Adr *a, Adr *v, Adr *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 996128f75..000000000
--- a/src/cmd/6c/reg.c
+++ /dev/null
@@ -1,1386 +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"
-
-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:
- 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 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 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.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) {
- warn(Z, "too many regions");
- goto brk;
- }
- rgp++;
- }
- }
-brk:
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- for(i=0; i<nregion; i++) {
- bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
- vreg = allreg(vreg, rgp);
- if(debug['R']) {
- 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:
- break;
- }
- }
- }
- pc = val;
-
- /*
- * fix up branches
- */
- if(debug['R'])
- if(bany(&addrs))
- print("addrs: %B\n", addrs);
-
- r1 = 0; /* set */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH)
- p->to.offset = r->s2->pc;
- r1 = r;
- }
-
- /*
- * last pass
- * eliminate nops
- * free aux structures
- */
- for(p = firstr->prog; p != P; p = p->link){
- while(p->link && p->link->as == ANOP)
- p->link = p->link->link;
- }
- if(r1 != R) {
- r1->link = freer;
- freer = firstr;
- }
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Adr *a;
- Var *v;
-
- p1 = alloc(sizeof(*p1));
- *p1 = zprog;
- p = r->prog;
-
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->sym = v->sym;
- a->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)
- 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, Adr *a)
-{
- Var *v;
- int i, t, n, et, z;
- int32 o;
- Bits bit;
- Sym *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 == S)
- 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) {
- if(debug['w'] > 1 && s)
- warn(Z, "variable not optimized: %s", s->name);
- goto none;
- }
- i = nvar;
- nvar++;
- v = &var[i];
- v->sym = s;
- v->offset = o;
- v->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;
- 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)
- 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;
- 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->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(Adr *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(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;
-}
diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c
deleted file mode 100644
index 42045f8fa..000000000
--- a/src/cmd/6c/sgen.c
+++ /dev/null
@@ -1,485 +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"
-
-Prog*
-gtext(Sym *s, int32 stkoff)
-{
- vlong v;
-
- v = 0;
- if(!(textflag & NOSPLIT))
- v |= argsize() << 32;
- v |= 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 = 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++;
-
- 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 6d886f459..000000000
--- a/src/cmd/6c/swt.c
+++ /dev/null
@@ -1,587 +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)
-{
- 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);
- swit1(q, i, def, n);
-
- if(debug['W'])
- print("case < %.8llux\n", r->val);
- patch(sp, pc);
- swit1(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.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.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 zname(Biobuf*, Sym*, int);
-void zaddr(Biobuf*, Adr*, int);
-void outhist(Biobuf*);
-
-void
-outcode(void)
-{
- struct { Sym *sym; short type; } h[NSYM];
- Prog *p;
- Sym *s;
- int f, sf, st, t, sym;
- Biobuf b;
-
- if(debug['S']) {
- for(p = firstp; p != P; p = p->link)
- if(p->as != ADATA && p->as != AGLOBL)
- pc--;
- for(p = firstp; p != P; p = p->link) {
- print("%P\n", p);
- if(p->as != ADATA && p->as != AGLOBL)
- pc++;
- }
- }
-
- 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(), thestring, getgoversion());
- if(ndynimp > 0 || ndynexp > 0) {
- int i;
-
- Bprint(&b, "\n");
- Bprint(&b, "$$ // exports\n\n");
- Bprint(&b, "$$ // local types\n\n");
- Bprint(&b, "$$ // dynimport\n", thestring);
- for(i=0; i<ndynimp; i++)
- Bprint(&b, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path);
- Bprint(&b, "\n$$ // dynexport\n", thestring);
- for(i=0; i<ndynexp; i++)
- Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
- Bprint(&b, "\n$$\n\n");
- }
- Bprint(&b, "!\n");
-
- outhist(&b);
- for(sym=0; sym<NSYM; sym++) {
- h[sym].sym = S;
- h[sym].type = 0;
- }
- sym = 1;
- for(p = firstp; p != P; p = p->link) {
- jackpot:
- sf = 0;
- s = p->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = p->from.type;
- if(t == D_ADDR)
- t = p->from.index;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- s->sym = sym;
- zname(&b, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = p->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = p->to.type;
- if(t == D_ADDR)
- t = p->to.index;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- s->sym = sym;
- zname(&b, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- Bputc(&b, p->as);
- Bputc(&b, p->as>>8);
- Bputc(&b, p->lineno);
- Bputc(&b, p->lineno>>8);
- Bputc(&b, p->lineno>>16);
- Bputc(&b, p->lineno>>24);
- zaddr(&b, &p->from, sf);
- zaddr(&b, &p->to, st);
- }
- Bflush(&b);
- close(f);
- firstp = P;
- lastp = P;
-}
-
-void
-outhist(Biobuf *b)
-{
- Hist *h;
- char *p, *q, *op, c;
- Prog pg;
- int n;
-
- pg = zprog;
- pg.as = AHISTORY;
- c = pathchar();
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- op = 0;
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname+2;
- c = *p;
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = utfrune(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- Bputc(b, ANAME);
- Bputc(b, ANAME>>8);
- Bputc(b, D_FILE);
- Bputc(b, 1);
- Bputc(b, '<');
- Bwrite(b, p, n);
- Bputc(b, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- pg.lineno = h->line;
- pg.to.type = zprog.to.type;
- pg.to.offset = h->offset;
- if(h->offset)
- pg.to.type = D_CONST;
-
- Bputc(b, pg.as);
- Bputc(b, pg.as>>8);
- Bputc(b, pg.lineno);
- Bputc(b, pg.lineno>>8);
- Bputc(b, pg.lineno>>16);
- Bputc(b, pg.lineno>>24);
- zaddr(b, &pg.from, 0);
- zaddr(b, &pg.to, 0);
- }
-}
-
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- char *n;
- uint32 sig;
-
- if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
- sig = sign(s);
- Bputc(b, ASIGNAME);
- Bputc(b, ASIGNAME>>8);
- Bputc(b, sig);
- Bputc(b, sig>>8);
- Bputc(b, sig>>16);
- Bputc(b, sig>>24);
- s->sig = SIGDONE;
- }
- else{
- Bputc(b, ANAME); /* as */
- Bputc(b, ANAME>>8); /* as */
- }
- Bputc(b, t); /* type */
- Bputc(b, s->sym); /* sym */
- n = s->name;
- while(*n) {
- Bputc(b, *n);
- n++;
- }
- Bputc(b, 0);
-}
-
-void
-zaddr(Biobuf *b, Adr *a, int s)
-{
- int32 l;
- int i, t;
- char *n;
- Ieee e;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(s != 0)
- t |= T_SYM;
-
- switch(a->type) {
- default:
- t |= T_TYPE;
- case D_NONE:
- if(a->offset != 0) {
- t |= T_OFFSET;
- l = a->offset;
- if((vlong)l != a->offset)
- t |= T_64;
- }
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- }
- Bputc(b, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- Bputc(b, a->index);
- Bputc(b, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- if(t & T_64) {
- l = a->offset>>32;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- }
- }
- if(t & T_SYM) /* implies sym */
- Bputc(b, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->dval);
- l = e.l;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- l = e.h;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- return;
- }
- if(t & T_SCONST) {
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- Bputc(b, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- Bputc(b, a->type);
-}
-
-int32
-align(int32 i, Type *t, int op, int32 *maxalign)
-{
- int32 o;
- Type *v;
- int w;
-
- o = i;
- w = 1;
- switch(op) {
- default:
- diag(Z, "unknown align opcode %d", op);
- break;
-
- case Asu2: /* padding at end of a struct */
- w = *maxalign;
- if(w < 1)
- w = 1;
- if(packflg)
- w = 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)
- w = packflg;
- break;
-
- case Ael2: /* width of a struct element */
- o += t->width;
- break;
-
- case Aarg0: /* initial passbyptr argument in arg list */
- if(typesu[t->etype]) {
- o = align(o, types[TIND], Aarg1, nil);
- o = align(o, types[TIND], Aarg2, nil);
- }
- break;
-
- case Aarg1: /* initial align of parameter */
- 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;
- 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;
- }
- 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 += SZ_VLONG-1;
- if(v > max)
- max = xround(v, SZ_VLONG);
- return max;
-}
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
deleted file mode 100644
index 12fc5b498..000000000
--- a/src/cmd/6c/txt.c
+++ /dev/null
@@ -1,1564 +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"
-
-void
-ginit(void)
-{
- int i;
- Type *t;
-
- thechar = '6';
- thestring = "amd64";
- dodefine("_64BIT");
- listinit();
- nstring = 0;
- mnstring = 0;
- nrathole = 0;
- pc = 0;
- breakpc = -1;
- continpc = -1;
- cases = C;
- firstp = P;
- 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;
- }
-}
-
-void
-gclean(void)
-{
- int i;
- Sym *s;
-
- reg[D_SP]--;
- 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)
-{
-
- p = alloc(sizeof(*p));
- *p = zprog;
- p->lineno = nearln;
- pc++;
- if(firstp == P) {
- firstp = p;
- lastp = p;
- return;
- }
- lastp->link = p;
- lastp = p;
-}
-
-void
-gargs(Node *n, Node *tn1, Node *tn2)
-{
- 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)
-{
- int r;
-
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET;
- nodreg(n, nn, r);
- reg[r]++;
-}
-
-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 >= sizeof(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, Adr *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 = S;
- break;
-
- case OEXREG:
- a->type = D_INDIR + D_GS;
- 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 = S;
- a->offset = n->xoffset;
- break;
-
- case ONAME:
- a->etype = n->etype;
- a->type = D_STATIC;
- a->sym = 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->dval = n->fconst;
- break;
- }
- a->sym = S;
- a->type = D_CONST;
- if(typev[n->type->etype] || n->type->etype == TIND)
- 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;
- 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;
-
- 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( 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( TUINT, TIND):
- case CASE( TVLONG, TUINT):
- case CASE( TVLONG, TULONG):
- case CASE( TUVLONG, TUINT):
- case CASE( TUVLONG, TULONG):
- *****/
- a = AMOVL;
- break;
-
- case CASE( TVLONG, TCHAR):
- case CASE( TVLONG, TSHORT):
- case CASE( TVLONG, TINT):
- case CASE( TVLONG, TLONG):
- case CASE( TUVLONG, TCHAR):
- case CASE( TUVLONG, TSHORT):
- case CASE( TUVLONG, TINT):
- case CASE( TUVLONG, TLONG):
- case CASE( TINT, TVLONG):
- case CASE( TINT, TUVLONG):
- case CASE( TLONG, TVLONG):
- case CASE( TINT, TIND):
- case CASE( TLONG, TIND):
- 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 = AMOVL; /* same effect as AMOVLQZX */
- if(f->op == OCONST) {
- f->vconst &= (uvlong)0xffffffffU;
- a = AMOVQ;
- }
- break;
-
- case CASE( TIND, TVLONG):
- case CASE( TVLONG, TVLONG):
- case CASE( TUVLONG, TVLONG):
- case CASE( TVLONG, TUVLONG):
- case CASE( TUVLONG, TUVLONG):
- case CASE( TIND, TUVLONG):
- case CASE( TVLONG, TIND):
- case CASE( TUVLONG, TIND):
- case CASE( TIND, TIND):
- 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]++; // cant 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(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 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;
-}
-
-void
-gpseudo(int a, Sym *s, Node *n)
-{
-
- nextpc();
- p->as = a;
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.scale = textflag;
- textflag = 0;
-
- if(s->class == CSTATIC)
- p->from.type = D_STATIC;
- naddr(n, &p->to);
- if(a == ADATA || a == AGLOBL)
- pc--;
-}
-
-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 += 8;
- 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/Makefile b/src/cmd/6g/Makefile
deleted file mode 100644
index 64fa15399..000000000
--- a/src/cmd/6g/Makefile
+++ /dev/null
@@ -1,35 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=6g
-
-HFILES=\
- ../gc/go.h\
- ../6l/6.out.h\
- gg.h\
- opt.h\
-
-OFILES=\
- ../6l/enam.$O\
- cgen.$O\
- cplx.$O\
- galign.$O\
- ggen.$O\
- gobj.$O\
- gsubr.$O\
- list.$O\
- peep.$O\
- pgen.$O\
- reg.$O\
-
-LIB=\
- ../gc/gc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../gc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
deleted file mode 100644
index fca4b64dd..000000000
--- a/src/cmd/6g/cgen.c
+++ /dev/null
@@ -1,1301 +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 "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;
-
- 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;
-
- // inline slices
- if(cgen_inline(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 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;
- }
-
- if(complexop(n, res)) {
- complexgen(n, res);
- goto ret;
- }
-
- if(n->addable) {
- gmove(n, res);
- 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;
- }
- }
-
- switch(n->op) {
- default:
- dump("cgen", n);
- fatal("cgen: unknown op %N", 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(AJMP, T);
- p2 = pc;
- gmove(nodbool(1), res);
- p3 = gbranch(AJMP, T);
- patch(p1, pc);
- bgen(n, 1, 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);
- if(a != AIMULB)
- goto sbop;
- cgen_bmul(n->op, nl, nr, res);
- break;
-
- // asymmetric binary
- case OSUB:
- a = optoas(n->op, nl->type);
- goto abop;
-
- case OCONV:
- 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 OLEN:
- if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
- // map and chan have len in the first 32-bit 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);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.type = types[TINT32];
- 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[TUINT32];
- 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 32-bit 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);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 4;
- n2.type = types[TINT32];
- gmove(&n2, &n1);
-
- patch(p1, pc);
-
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- if(isslice(nl->type)) {
- igen(nl, &n1, res);
- n1.type = types[TUINT32];
- n1.xoffset += Array_cap;
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- fatal("cgen: OCAP: unknown type %lT", nl->type);
- break;
-
- case OADDR:
- agen(nl, res);
- 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;
- }
- cgen_div(n->op, nl, nr, res);
- break;
-
- case OLSH:
- case ORSH:
- cgen_shift(n->op, nl, nr, res);
- break;
- }
- goto ret;
-
-sbop: // symmetric binary
- if(nl->ullman < nr->ullman) {
- r = nl;
- nl = nr;
- nr = r;
- }
-
-abop: // asymmetric binary
- if(nl->ullman >= nr->ullman) {
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
-
- if(sudoaddable(a, nr, &addr)) {
- p1 = gins(a, N, &n1);
- p1->from = addr;
- gmove(&n1, res);
- sudoclean();
- regfree(&n1);
- goto ret;
- }
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- } else {
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- }
- gins(a, &n2, &n1);
- gmove(&n1, res);
- regfree(&n1);
- 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:
- ;
-}
-
-/*
- * generate:
- * res = &n;
- */
-void
-agen(Node *n, Node *res)
-{
- Node *nl, *nr;
- Node n1, n2, n3, tmp, n4, n5;
- Prog *p1;
- uint32 w;
- uint64 v;
- Type *t;
-
- 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(n->addable) {
- regalloc(&n1, types[tptr], res);
- gins(ALEAQ, n, &n1);
- gmove(&n1, res);
- regfree(&n1);
- goto ret;
- }
-
- nl = n->left;
- nr = n->right;
-
- switch(n->op) {
- default:
- fatal("agen: unknown op %N", n);
- break;
-
- case OCALLMETH:
- 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 OINDEX:
- w = n->type->width;
- if(nr->addable)
- goto irad;
- if(nl->addable) {
- if(!isconst(nr, CTINT)) {
- regalloc(&n1, nr->type, N);
- cgen(nr, &n1);
- }
- if(!isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
- }
- goto index;
- }
- tempname(&tmp, nr->type);
- cgen(nr, &tmp);
- nr = &tmp;
-
- irad:
- if(!isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
- }
- if(!isconst(nr, CTINT)) {
- regalloc(&n1, nr->type, N);
- cgen(nr, &n1);
- }
- goto index;
-
- index:
- // &a is in &n3 (allocated in res)
- // i is in &n1 (if not constant)
- // w is width
-
- // explicit check for nil if array is large enough
- // that we might derive too big a pointer.
- if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
- regalloc(&n4, types[tptr], &n3);
- gmove(&n3, &n4);
- n4.op = OINDREG;
- n4.type = types[TUINT8];
- n4.xoffset = 0;
- gins(ATESTB, nodintconst(0), &n4);
- regfree(&n4);
- }
-
- if(w == 0)
- fatal("index is zero width");
-
- // constant index
- if(isconst(nr, CTINT)) {
- if(isconst(nl, CTSTR))
- fatal("constant string constant index"); // front end should handle
- v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type) || nl->type->etype == TSTRING) {
- if(!debug['B'] && !n->etype) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- nodconst(&n2, types[TUINT32], v);
- gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- 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);
- gmove(&n3, res);
- regfree(&n3);
- break;
- }
-
- // type of the index
- t = types[TUINT64];
- if(issigned[n1.type->etype])
- t = types[TINT64];
-
- regalloc(&n2, t, &n1); // i
- gmove(&n1, &n2);
- regfree(&n1);
-
- if(!debug['B'] && !n->etype) {
- // check bounds
- n5.op = OXXX;
- t = types[TUINT32];
- if(is64(nr->type))
- t = types[TUINT64];
- if(isconst(nl, CTSTR)) {
- nodconst(&n1, t, nl->val.u.sval->len);
- } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[TUINT32];
- n1.xoffset = Array_nel;
- if(is64(nr->type)) {
- regalloc(&n5, t, N);
- gmove(&n1, &n5);
- n1 = n5;
- }
- } else {
- nodconst(&n1, t, nl->type->bound);
- }
- gins(optoas(OCMP, t), &n2, &n1);
- p1 = gbranch(optoas(OLT, t), T);
- if(n5.op != OXXX)
- regfree(&n5);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- if(isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- p1 = gins(ALEAQ, N, &n3);
- datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- p1->from.scale = 1;
- p1->from.index = n2.val.u.reg;
- goto indexdone;
- }
-
- 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 == 1 || w == 2 || w == 4 || w == 8) {
- p1 = gins(ALEAQ, &n2, &n3);
- p1->from.scale = w;
- p1->from.index = p1->from.type;
- p1->from.type = p1->to.type + D_INDIR;
- } else {
- ginscon(optoas(OMUL, t), w, &n2);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- }
-
- indexdone:
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- 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)
- ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
- break;
-
- case OIND:
- cgen(nl, res);
- break;
-
- case ODOT:
- agen(nl, res);
- if(n->xoffset != 0)
- ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
- break;
-
- case ODOTPTR:
- cgen(nl, res);
- if(n->xoffset != 0) {
- // explicit check for nil if struct is large enough
- // that we might derive too big a pointer.
- if(nl->type->type->width >= unmappedzero) {
- regalloc(&n1, types[tptr], res);
- gmove(res, &n1);
- n1.op = OINDREG;
- n1.type = types[TUINT8];
- n1.xoffset = 0;
- gins(ATESTB, nodintconst(0), &n1);
- regfree(&n1);
- }
- ginscon(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).
- */
-void
-igen(Node *n, Node *a, Node *res)
-{
- Type *fp;
- Iter flist;
-
- switch(n->op) {
- case ONAME:
- if((n->class&PHEAP) || n->class == PPARAMREF)
- break;
- *a = *n;
- return;
-
- case OCALLFUNC:
- fp = structfirst(&flist, getoutarg(n->left->type));
- cgen_call(n, 0);
- memset(a, 0, sizeof *a);
- a->op = OINDREG;
- a->val.u.reg = D_SP;
- a->addable = 1;
- a->xoffset = fp->width;
- a->type = n->type;
- return;
- }
-
- regalloc(a, types[tptr], res);
- agen(n, a);
- a->op = OINDREG;
- a->type = n->type;
-}
-
-/*
- * generate:
- * if(n == true) goto to;
- */
-void
-bgen(Node *n, int true, Prog *to)
-{
- int et, a;
- Node *nl, *nr, *l, *r;
- Node n1, n2, tmp;
- Prog *p1, *p2;
-
- if(debug['g']) {
- dump("\nbgen", n);
- }
-
- if(n == N)
- n = nodbool(1);
-
- if(n->ninit != nil)
- genlist(n->ninit);
-
- nl = n->left;
- nr = n->right;
-
- 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;
- }
- nl = N;
- nr = N;
-
- switch(n->op) {
- default:
- def:
- regalloc(&n1, n->type, N);
- cgen(n, &n1);
- nodconst(&n2, n->type, 0);
- gins(optoas(OCMP, n->type), &n1, &n2);
- a = AJNE;
- if(!true)
- a = AJEQ;
- patch(gbranch(a, n->type), to);
- regfree(&n1);
- goto ret;
-
- case OLITERAL:
- // need to ask if it is bool?
- if(!true == !n->val.u.bval)
- patch(gbranch(AJMP, T), to);
- goto ret;
-
- case ONAME:
- if(n->addable == 0)
- goto def;
- nodconst(&n1, n->type, 0);
- gins(optoas(OCMP, n->type), n, &n1);
- a = AJNE;
- if(!true)
- a = AJEQ;
- patch(gbranch(a, n->type), to);
- goto ret;
-
- case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- p1 = gbranch(AJMP, T);
- p2 = gbranch(AJMP, T);
- patch(p1, pc);
- bgen(n->left, !true, p2);
- bgen(n->right, !true, p2);
- p1 = gbranch(AJMP, T);
- patch(p1, to);
- patch(p2, pc);
- goto ret;
-
- case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bgen(n->left, true, to);
- bgen(n->right, true, 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, 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(AJMP, T);
- p2 = gbranch(AJMP, T);
- patch(p1, pc);
- bgen(n, 1, p2);
- patch(gbranch(AJMP, T), 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)) {
- // only valid to cmp darray to literal nil
- if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
- yyerror("illegal array comparison");
- break;
- }
- a = optoas(a, types[tptr]);
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = Array_array;
- n2.type = types[tptr];
- nodconst(&tmp, types[tptr], 0);
- gins(optoas(OCMP, types[tptr]), &n2, &tmp);
- patch(gbranch(a, types[tptr]), to);
- regfree(&n1);
- break;
- }
-
- if(isinter(nl->type)) {
- // front end shold only leave cmp to literal nil
- if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
- yyerror("illegal interface comparison");
- break;
- }
- a = optoas(a, types[tptr]);
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 0;
- nodconst(&tmp, types[tptr], 0);
- gins(optoas(OCMP, types[tptr]), &n2, &tmp);
- patch(gbranch(a, types[tptr]), to);
- regfree(&n1);
- break;
- }
- if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, 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);
-
- if(smallintconst(nr)) {
- gins(optoas(OCMP, nr->type), &n1, nr);
- patch(gbranch(optoas(a, nr->type), nr->type), to);
- regfree(&n1);
- break;
- }
-
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- cmp:
- // only < and <= work right with NaN; reverse if needed
- l = &n1;
- r = &n2;
- if(isfloat[nl->type->etype] && (a == OGT || a == OGE)) {
- l = &n2;
- r = &n1;
- a = brrev(a);
- }
-
- gins(optoas(OCMP, nr->type), l, r);
-
- if(isfloat[nr->type->etype] && (n->op == OEQ || n->op == ONE)) {
- if(n->op == OEQ) {
- // neither NE nor P
- p1 = gbranch(AJNE, T);
- p2 = gbranch(AJPS, T);
- patch(gbranch(AJMP, T), to);
- patch(p1, pc);
- patch(p2, pc);
- } else {
- // either NE or P
- patch(gbranch(AJNE, T), to);
- patch(gbranch(AJPS, T), to);
- }
- } else
- patch(gbranch(optoas(a, nr->type), nr->type), 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.
- */
-int32
-stkof(Node *n)
-{
- Type *t;
- Iter flist;
- int32 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;
- 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, int32 w)
-{
- Node nodl, nodr, oldl, oldr, cx, oldcx, tmp;
- int32 c, q, odst, osrc;
-
- if(debug['g']) {
- print("\nsgen w=%d\n", w);
- dump("r", n);
- dump("res", ns);
- }
- if(w == 0)
- return;
- if(n->ullman >= UINF && ns->ullman >= UINF) {
- fatal("sgen UINF");
- }
-
- if(w < 0)
- fatal("sgen copy %d", w);
-
- if(w == 16)
- if(componentgen(n, ns))
- return;
-
- // offset on the stack
- osrc = stkof(n);
- odst = stkof(ns);
-
- 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, ns, w);
- return;
- }
-
- if(n->ullman >= ns->ullman) {
- savex(D_SI, &nodr, &oldr, N, types[tptr]);
- agen(n, &nodr);
-
- regalloc(&nodr, types[tptr], &nodr); // mark nodr as live
- savex(D_DI, &nodl, &oldl, N, types[tptr]);
- agen(ns, &nodl);
- regfree(&nodr);
- } else {
- savex(D_DI, &nodl, &oldl, N, types[tptr]);
- agen(ns, &nodl);
-
- regalloc(&nodl, types[tptr], &nodl); // mark nodl as live
- savex(D_SI, &nodr, &oldr, N, types[tptr]);
- agen(n, &nodr);
- regfree(&nodl);
- }
-
- c = w % 8; // bytes
- q = w / 8; // quads
-
- savex(D_CX, &cx, &oldcx, N, types[TINT64]);
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- if(osrc < odst && odst < osrc+w) {
- // reverse direction
- gins(ASTD, N, N); // set direction flag
- if(c > 0) {
- gconreg(AADDQ, w-1, D_SI);
- gconreg(AADDQ, w-1, D_DI);
-
- gconreg(AMOVQ, c, D_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
- }
-
- if(q > 0) {
- if(c > 0) {
- gconreg(AADDQ, -7, D_SI);
- gconreg(AADDQ, -7, D_DI);
- } else {
- gconreg(AADDQ, w-8, D_SI);
- gconreg(AADDQ, w-8, D_DI);
- }
- gconreg(AMOVQ, q, D_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)-
- }
- // we leave with the flag clear
- gins(ACLD, N, N);
- } else {
- // normal direction
- if(q >= 4) {
- gconreg(AMOVQ, q, D_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
- } else
- while(q > 0) {
- gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
- q--;
- }
-
- if(c >= 4) {
- gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
- c -= 4;
- }
- while(c > 0) {
- gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
- c--;
- }
- }
-
-
- restx(&nodl, &oldl);
- restx(&nodr, &oldr);
- restx(&cx, &oldcx);
-}
-
-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 structure component by component
- * return 1 if can do, 0 if cant.
- * nr is N for copy zero
- */
-int
-componentgen(Node *nr, Node *nl)
-{
- Node nodl, nodr;
- int freel, freer;
-
- freel = 0;
- freer = 0;
-
- switch(nl->type->etype) {
- default:
- goto no;
-
- case TARRAY:
- if(!isslice(nl->type))
- goto no;
- 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;
- }
- }
-
- switch(nl->type->etype) {
- case TARRAY:
- if(!isslice(nl->type))
- goto no;
-
- 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[TUINT32];
-
- 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[TUINT32];
-
- 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:
- 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[TUINT32];
-
- 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:
- 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:
- goto no;
- }
-
-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/6g/doc.go b/src/cmd/6g/doc.go
deleted file mode 100644
index 64f1d2ba9..000000000
--- a/src/cmd/6g/doc.go
+++ /dev/null
@@ -1,13 +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.
-
-/*
-
-6g is the version of the gc compiler for the x86-64.
-The $GOARCH for these tools is amd64.
-
-It reads .go files and outputs .6 files. The flags are documented in ../gc/doc.go.
-
-*/
-package documentation
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
deleted file mode 100644
index 97bfb58e8..000000000
--- a/src/cmd/6g/galign.c
+++ /dev/null
@@ -1,36 +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 "gg.h"
-
-int thechar = '6';
-char* thestring = "amd64";
-
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
- */
-Typedef typedefs[] =
-{
- "int", TINT, TINT32,
- "uint", TUINT, TUINT32,
- "uintptr", TUINTPTR, TUINT64,
- 0
-};
-
-void
-betypeinit(void)
-{
- widthptr = 8;
-
- zprog.link = P;
- zprog.as = AGOK;
- zprog.from.type = D_NONE;
- zprog.from.index = D_NONE;
- zprog.from.scale = 0;
- zprog.to = zprog.from;
-
- listinit();
-}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
deleted file mode 100644
index 2493771a0..000000000
--- a/src/cmd/6g/gg.h
+++ /dev/null
@@ -1,161 +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 <u.h>
-#include <libc.h>
-
-#include "../gc/go.h"
-#include "../6l/6.out.h"
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-typedef struct Addr Addr;
-
-struct Addr
-{
- vlong offset;
- double dval;
- Prog* branch;
- char sval[NSNAME];
-
- Sym* gotype;
- Sym* sym;
- Node* node;
- int width;
- uchar type;
- uchar index;
- uchar etype;
- uchar scale; /* doubles as width in DATA op */
- uchar pun; /* dont register variable */
-};
-#define A ((Addr*)0)
-
-struct Prog
-{
- short as; // opcode
- uint32 loc; // pc offset in this func
- uint32 lineno; // source line that generated this
- Addr from; // src address
- Addr to; // dst address
- Prog* link; // next instruction in this func
- void* reg; // pointer to containing Reg struct
-};
-
-EXTERN Biobuf* bout;
-EXTERN int32 dynloc;
-EXTERN uchar reg[D_NONE];
-EXTERN int32 pcloc; // instruction counter
-EXTERN Strlit emptystring;
-extern char* anames[];
-EXTERN Hist* hist;
-EXTERN Prog zprog;
-EXTERN Node* curfn;
-EXTERN Node* newproc;
-EXTERN Node* deferproc;
-EXTERN Node* deferreturn;
-EXTERN Node* panicindex;
-EXTERN Node* panicslice;
-EXTERN Node* throwreturn;
-EXTERN vlong unmappedzero;
-
-/*
- * gen.c
- */
-void compile(Node*);
-void proglist(void);
-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_bmul(int, Node*, Node*, Node*);
-void cgen_shift(int, Node*, Node*, Node*);
-void cgen_dcl(Node*);
-int needconvert(Type*, Type*);
-void genconv(Type*, Type*);
-void allocparams(void);
-void checklabels();
-void ginscall(Node*, int);
-int gen_as_init(Node*);
-
-/*
- * cgen
- */
-void agen(Node*, Node*);
-void igen(Node*, Node*, Node*);
-vlong fieldoffset(Type*, Node*);
-void bgen(Node*, int, Prog*);
-void sgen(Node*, Node*, int32);
-void gmove(Node*, Node*);
-Prog* gins(int, Node*, Node*);
-int samaddr(Node*, Node*);
-void naddr(Node*, Addr*, int);
-void cgen_aret(Node*, Node*);
-int cgen_inline(Node*, Node*);
-void restx(Node*, Node*);
-void savex(int, Node*, Node*, Node*, Type*);
-int componentgen(Node*, Node*);
-
-/*
- * gsubr.c
- */
-void clearp(Prog*);
-void proglist(void);
-Prog* gbranch(int, Type*);
-Prog* prog(int);
-void gaddoffset(Node*);
-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 gconreg(int, vlong, int);
-void ginscon(int, vlong, Node*);
-void buildtxt(void);
-Plist* newplist(void);
-int isfat(Type*);
-void sudoclean(void);
-int sudoaddable(int, Node*, Addr*);
-void afunclit(Addr*);
-void datagostring(Strlit*, Addr*);
-void nodfconst(Node*, Type*, Mpflt*);
-
-/*
- * cplx.c
- */
-int complexop(Node*, Node*);
-void complexmove(Node*, Node*);
-void complexgen(Node*, Node*);
-void complexbool(int, Node*, Node*, int, Prog*);
-
-/*
- * gobj.c
- */
-void datastring(char*, int, Addr*);
-
-/*
- * list.c
- */
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Yconv(Fmt*);
-void listinit(void);
-
-void zaddr(Biobuf*, Addr*, int, int);
-
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
deleted file mode 100644
index 9e7fbab0d..000000000
--- a/src/cmd/6g/ggen.c
+++ /dev/null
@@ -1,1371 +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.
-
-#undef EXTERN
-#define EXTERN
-#include "gg.h"
-#include "opt.h"
-
-void
-defframe(Prog *ptxt)
-{
- // fill in argument size
- ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
-
- // fill in final stack size
- ptxt->to.offset <<= 32;
- ptxt->to.offset |= rnd(stksize+maxarg, widthptr);
-}
-
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
- for (; p; p = p->link) {
- if (p->from.type == D_AUTO && p->from.node)
- p->from.node->used++;
-
- if (p->to.type == D_AUTO && p->to.node)
- p->to.node->used++;
- }
-}
-
-// Fixup instructions after compactframe has moved all autos around.
-void
-fixautoused(Prog* p)
-{
- for (; p; p = p->link) {
- if (p->from.type == D_AUTO && p->from.node)
- p->from.offset += p->from.node->stkdelta;
-
- if (p->to.type == D_AUTO && p->to.node)
- p->to.offset += p->to.node->stkdelta;
- }
-}
-
-
-/*
- * generate:
- * call f
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-void
-ginscall(Node *f, int proc)
-{
- Prog *p;
- Node reg, con;
-
- switch(proc) {
- default:
- fatal("ginscall: bad proc %d", proc);
- break;
-
- case 0: // normal call
- p = gins(ACALL, N, f);
- afunclit(&p->to);
- break;
-
- case 1: // call in new proc (go)
- case 2: // deferred call (defer)
- nodreg(&reg, types[TINT64], D_CX);
- gins(APUSHQ, f, N);
- nodconst(&con, types[TINT32], argsize(f->type));
- gins(APUSHQ, &con, N);
- if(proc == 1)
- ginscall(newproc, 0);
- else {
- if(!hasdefer)
- fatal("hasdefer=0 but has defer");
- ginscall(deferproc, 0);
- }
- gins(APOPQ, N, &reg);
- gins(APOPQ, N, &reg);
- if(proc == 2) {
- nodreg(&reg, types[TINT64], D_AX);
- gins(ATESTQ, &reg, &reg);
- patch(gbranch(AJNE, T), retpc);
- }
- break;
- }
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-void
-cgen_callinter(Node *n, Node *res, int proc)
-{
- Node *i, *f;
- Node tmpi, nodo, nodr, nodsp;
-
- 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
-
- regalloc(&nodr, types[tptr], res);
- regalloc(&nodo, types[tptr], &nodr);
- nodo.op = OINDREG;
-
- agen(i, &nodr); // REG = &inter
-
- nodindreg(&nodsp, types[tptr], D_SP);
- nodo.xoffset += widthptr;
- cgen(&nodo, &nodsp); // 0(SP) = 8(REG) -- i.data
-
- nodo.xoffset -= widthptr;
- cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
-
- nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
- cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f]
-
- // BOTCH nodr.type = fntype;
- nodr.type = n->left->type;
- ginscall(&nodr, proc);
-
- regfree(&nodr);
- regfree(&nodo);
-
- setmaxarg(n->left->type);
-}
-
-/*
- * 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;
-
- setmaxarg(t);
-
- // 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);
- goto ret;
- }
-
- // 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);
- goto ret;
- }
-
- // call direct
- n->left->method = 1;
- ginscall(n->left, proc);
-
-
-ret:
- ;
-}
-
-/*
- * 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_SP;
- nod.addable = 1;
-
- nod.xoffset = fp->width;
- 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_SP;
- nod1.addable = 1;
-
- nod1.xoffset = fp->width;
- nod1.type = fp->type;
-
- if(res->op != OREGISTER) {
- regalloc(&nod2, types[tptr], res);
- gins(ALEAQ, &nod1, &nod2);
- gins(AMOVQ, &nod2, res);
- regfree(&nod2);
- } else
- gins(ALEAQ, &nod1, res);
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-void
-cgen_ret(Node *n)
-{
- genlist(n->list); // copy out args
- if(hasdefer || curfn->exit)
- gjmp(retpc);
- else
- gins(ARET, N, N);
-}
-
-/*
- * generate += *= etc.
- */
-void
-cgen_asop(Node *n)
-{
- Node n1, n2, n3, n4;
- Node *nl, *nr;
- Prog *p1;
- Addr addr;
- int a;
-
- nl = n->left;
- nr = n->right;
-
- if(nr->ullman >= UINF && nl->ullman >= UINF) {
- tempname(&n1, nr->type);
- cgen(nr, &n1);
- n2 = *n;
- n2.right = &n1;
- cgen_asop(&n2);
- goto ret;
- }
-
- if(!isint[nl->type->etype])
- goto hard;
- if(!isint[nr->type->etype])
- goto hard;
-
- switch(n->etype) {
- case OADD:
- if(smallintconst(nr))
- if(mpgetfix(nr->val.u.xval) == 1) {
- a = optoas(OINC, nl->type);
- if(nl->addable) {
- gins(a, N, nl);
- goto ret;
- }
- if(sudoaddable(a, nl, &addr)) {
- p1 = gins(a, N, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- }
- break;
-
- case OSUB:
- if(smallintconst(nr))
- if(mpgetfix(nr->val.u.xval) == 1) {
- a = optoas(ODEC, nl->type);
- if(nl->addable) {
- gins(a, N, nl);
- goto ret;
- }
- if(sudoaddable(a, nl, &addr)) {
- p1 = gins(a, N, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- }
- break;
- }
-
- switch(n->etype) {
- case OADD:
- case OSUB:
- case OXOR:
- case OAND:
- case OOR:
- a = optoas(n->etype, nl->type);
- if(nl->addable) {
- if(smallintconst(nr)) {
- gins(a, nr, nl);
- goto ret;
- }
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- gins(a, &n2, nl);
- regfree(&n2);
- goto ret;
- }
- if(nr->ullman < UINF)
- if(sudoaddable(a, nl, &addr)) {
- if(smallintconst(nr)) {
- p1 = gins(a, nr, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- p1 = gins(a, &n2, N);
- p1->to = addr;
- regfree(&n2);
- sudoclean();
- goto ret;
- }
- }
-
-hard:
- n2.op = 0;
- n1.op = 0;
- if(nr->ullman >= nl->ullman || nl->addable) {
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- nr = &n2;
- } else {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- if(!nl->addable) {
- igen(nl, &n1, N);
- nl = &n1;
- }
-
- n3 = *n;
- n3.left = nl;
- n3.right = nr;
- n3.op = n->etype;
-
- regalloc(&n4, nl->type, N);
- cgen(&n3, &n4);
- gmove(&n4, nl);
-
- if(n1.op)
- regfree(&n1);
- if(n2.op == OREGISTER)
- regfree(&n2);
- regfree(&n4);
-
-ret:
- ;
-}
-
-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.
- * caller must set:
- * ax = allocated AX register
- * dx = allocated DX register
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-void
-dodiv(int op, Node *nl, Node *nr, Node *res)
-{
- int a;
- Node n3, n4;
- Type *t;
- Node ax, dx, oldax, olddx;
-
- t = nl->type;
- if(t->width == 1) {
- if(issigned[t->etype])
- t = types[TINT32];
- else
- t = types[TUINT32];
- }
- a = optoas(op, t);
-
- regalloc(&n3, t, N);
- if(nl->ullman >= nr->ullman) {
- savex(D_AX, &ax, &oldax, res, t);
- cgen(nl, &ax);
- regalloc(&ax, t, &ax); // mark ax live during cgen
- cgen(nr, &n3);
- regfree(&ax);
- } else {
- cgen(nr, &n3);
- savex(D_AX, &ax, &oldax, res, t);
- cgen(nl, &ax);
- }
- savex(D_DX, &dx, &olddx, res, t);
- if(!issigned[t->etype]) {
- nodconst(&n4, t, 0);
- gmove(&n4, &dx);
- } else
- gins(optoas(OEXTEND, t), N, N);
- gins(a, &n3, N);
- regfree(&n3);
-
- if(op == ODIV)
- gmove(&ax, res);
- else
- gmove(&dx, res);
- restx(&ax, &oldax);
- restx(&dx, &olddx);
-}
-
-/*
- * register dr is one of the special ones (AX, CX, DI, SI, etc.).
- * we need to use it. if it is already allocated as a temporary
- * (r > 1; can only happen if a routine like sgen passed a
- * special as cgen's res and then cgen used regalloc to reuse
- * it as its own temporary), then move it for now to another
- * register. caller must call restx to move it back.
- * the move is not necessary if dr == res, because res is
- * known to be dead.
- */
-void
-savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
-{
- int r;
-
- r = reg[dr];
-
- // save current ax and dx if they are live
- // and not the destination
- memset(oldx, 0, sizeof *oldx);
- nodreg(x, t, dr);
- if(r > 1 && !samereg(x, res)) {
- regalloc(oldx, types[TINT64], N);
- x->type = types[TINT64];
- gmove(x, oldx);
- x->type = t;
- oldx->ostk = r; // squirrel away old r value
- reg[dr] = 1;
- }
-}
-
-void
-restx(Node *x, Node *oldx)
-{
- if(oldx->op != 0) {
- x->type = types[TINT64];
- reg[x->val.u.reg] = oldx->ostk;
- gmove(oldx, x);
- regfree(oldx);
- }
-}
-
-/*
- * 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, savl, savr;
- Node ax, dx, oldax, olddx;
- int n, w, s, a;
- Magic m;
-
- if(nl->ullman >= UINF) {
- tempname(&savl, nl->type);
- cgen(nl, &savl);
- nl = &savl;
- }
- if(nr->ullman >= UINF) {
- tempname(&savr, nr->type);
- cgen(nr, &savr);
- nr = &savr;
- }
-
- if(nr->op != OLITERAL)
- goto longdiv;
-
- // special cases of mod/div
- // by a constant
- w = nl->type->width*8;
- s = 0;
- n = powtwo(nr);
- if(n >= 1000) {
- // negative power of 2
- s = 1;
- n -= 1000;
- }
-
- if(n+1 >= w) {
- // just sign bit
- goto longdiv;
- }
-
- if(n < 0)
- goto divbymul;
- switch(n) {
- case 0:
- // divide by 1
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- if(op == OMOD) {
- gins(optoas(OXOR, nl->type), &n1, &n1);
- } else
- if(s)
- gins(optoas(OMINUS, nl->type), N, &n1);
- gmove(&n1, res);
- regfree(&n1);
- return;
- case 1:
- // divide by 2
- if(op == OMOD) {
- if(issigned[nl->type->etype])
- goto longmod;
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- nodconst(&n2, nl->type, 1);
- gins(optoas(OAND, nl->type), &n2, &n1);
- gmove(&n1, res);
- regfree(&n1);
- return;
- }
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- if(!issigned[nl->type->etype])
- break;
-
- // develop -1 iff nl is negative
- regalloc(&n2, nl->type, N);
- gmove(&n1, &n2);
- nodconst(&n3, nl->type, w-1);
- gins(optoas(ORSH, nl->type), &n3, &n2);
- gins(optoas(OSUB, nl->type), &n2, &n1);
- regfree(&n2);
- break;
- default:
- if(op == OMOD) {
- if(issigned[nl->type->etype])
- goto longmod;
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- nodconst(&n2, nl->type, mpgetfix(nr->val.u.xval)-1);
- if(!smallintconst(&n2)) {
- regalloc(&n3, nl->type, N);
- gmove(&n2, &n3);
- gins(optoas(OAND, nl->type), &n3, &n1);
- regfree(&n3);
- } else
- gins(optoas(OAND, nl->type), &n2, &n1);
- gmove(&n1, res);
- regfree(&n1);
- return;
- }
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- if(!issigned[nl->type->etype])
- break;
-
- // develop (2^k)-1 iff nl is negative
- regalloc(&n2, nl->type, N);
- gmove(&n1, &n2);
- nodconst(&n3, nl->type, w-1);
- gins(optoas(ORSH, nl->type), &n3, &n2);
- nodconst(&n3, nl->type, w-n);
- gins(optoas(ORSH, tounsigned(nl->type)), &n3, &n2);
- gins(optoas(OADD, nl->type), &n2, &n1);
- regfree(&n2);
- break;
- }
- nodconst(&n2, nl->type, n);
- gins(optoas(ORSH, nl->type), &n2, &n1);
- if(s)
- gins(optoas(OMINUS, nl->type), N, &n1);
- gmove(&n1, res);
- regfree(&n1);
- return;
-
-divbymul:
- // 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 TUINT8:
- case TUINT16:
- case TUINT32:
- case TUINT64:
- m.w = w;
- m.ud = mpgetfix(nr->val.u.xval);
- umagic(&m);
- if(m.bad)
- break;
- if(op == OMOD)
- goto longmod;
-
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1); // num -> reg(n1)
-
- savex(D_AX, &ax, &oldax, res, nl->type);
- savex(D_DX, &dx, &olddx, res, nl->type);
-
- nodconst(&n2, nl->type, m.um);
- gmove(&n2, &ax); // const->ax
-
- gins(optoas(OHMUL, nl->type), &n1, N); // imul reg
- if(w == 8) {
- // fix up 8-bit multiply
- Node ah, dl;
- nodreg(&ah, types[TUINT8], D_AH);
- nodreg(&dl, types[TUINT8], D_DL);
- gins(AMOVB, &ah, &dl);
- }
-
- if(m.ua) {
- // need to add numerator accounting for overflow
- gins(optoas(OADD, nl->type), &n1, &dx);
- nodconst(&n2, nl->type, 1);
- gins(optoas(ORRC, nl->type), &n2, &dx);
- nodconst(&n2, nl->type, m.s-1);
- gins(optoas(ORSH, nl->type), &n2, &dx);
- } else {
- nodconst(&n2, nl->type, m.s);
- gins(optoas(ORSH, nl->type), &n2, &dx); // shift dx
- }
-
-
- regfree(&n1);
- gmove(&dx, res);
-
- restx(&ax, &oldax);
- restx(&dx, &olddx);
- return;
-
- case TINT8:
- case TINT16:
- case TINT32:
- case TINT64:
- m.w = w;
- m.sd = mpgetfix(nr->val.u.xval);
- smagic(&m);
- if(m.bad)
- break;
- if(op == OMOD)
- goto longmod;
-
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1); // num -> reg(n1)
-
- savex(D_AX, &ax, &oldax, res, nl->type);
- savex(D_DX, &dx, &olddx, res, nl->type);
-
- nodconst(&n2, nl->type, m.sm);
- gmove(&n2, &ax); // const->ax
-
- gins(optoas(OHMUL, nl->type), &n1, N); // imul reg
- if(w == 8) {
- // fix up 8-bit multiply
- Node ah, dl;
- nodreg(&ah, types[TUINT8], D_AH);
- nodreg(&dl, types[TUINT8], D_DL);
- gins(AMOVB, &ah, &dl);
- }
-
- if(m.sm < 0) {
- // need to add numerator
- gins(optoas(OADD, nl->type), &n1, &dx);
- }
-
- nodconst(&n2, nl->type, m.s);
- gins(optoas(ORSH, nl->type), &n2, &dx); // shift dx
-
- nodconst(&n2, nl->type, w-1);
- gins(optoas(ORSH, nl->type), &n2, &n1); // -1 iff num is neg
- gins(optoas(OSUB, nl->type), &n1, &dx); // added
-
- if(m.sd < 0) {
- // this could probably be removed
- // by factoring it into the multiplier
- gins(optoas(OMINUS, nl->type), N, &dx);
- }
-
- regfree(&n1);
- gmove(&dx, res);
-
- restx(&ax, &oldax);
- restx(&dx, &olddx);
- 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 shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-void
-cgen_shift(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, n4, n5, cx, oldcx;
- int a, rcx;
- 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
- 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;
- }
-
- rcx = reg[D_CX];
- nodreg(&n1, types[TUINT32], D_CX);
-
- // 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, &n1); // to hold the shift type in CX
- regalloc(&n3, tcount, &n1); // to clear high bits of CX
-
- nodreg(&cx, types[TUINT64], D_CX);
- memset(&oldcx, 0, sizeof oldcx);
- if(rcx > 0 && !samereg(&cx, res)) {
- regalloc(&oldcx, types[TUINT64], N);
- gmove(&cx, &oldcx);
- }
- cx.type = tcount;
-
- if(samereg(&cx, res))
- regalloc(&n2, nl->type, N);
- else
- 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
- nodconst(&n3, tcount, nl->type->width*8);
- gins(optoas(OCMP, tcount), &n1, &n3);
- p1 = gbranch(optoas(OLT, tcount), T);
- 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);
-
- if(oldcx.op != 0) {
- cx.type = types[TUINT64];
- gmove(&oldcx, &cx);
- regfree(&oldcx);
- }
-
- gmove(&n2, res);
-
- regfree(&n1);
- regfree(&n2);
-
-ret:
- ;
-}
-
-/*
- * generate byte multiply:
- * res = nl * nr
- * no 2-operand byte multiply instruction so have to do
- * 16-bit multiply and take bottom half.
- */
-void
-cgen_bmul(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1b, n2b, n1w, n2w;
- Type *t;
- int a;
-
- if(nl->ullman >= nr->ullman) {
- regalloc(&n1b, nl->type, res);
- cgen(nl, &n1b);
- regalloc(&n2b, nr->type, N);
- cgen(nr, &n2b);
- } else {
- regalloc(&n2b, nr->type, N);
- cgen(nr, &n2b);
- regalloc(&n1b, nl->type, res);
- cgen(nl, &n1b);
- }
-
- // copy from byte to short registers
- t = types[TUINT16];
- if(issigned[nl->type->etype])
- t = types[TINT16];
-
- regalloc(&n2w, t, &n2b);
- cgen(&n2b, &n2w);
-
- regalloc(&n1w, t, &n1b);
- cgen(&n1b, &n1w);
-
- a = optoas(op, t);
- gins(a, &n2w, &n1w);
- cgen(&n1w, &n1b);
- cgen(&n1b, res);
-
- regfree(&n1w);
- regfree(&n2w);
- regfree(&n1b);
- regfree(&n2b);
-}
-
-void
-clearfat(Node *nl)
-{
- uint32 w, c, q;
- Node n1, oldn1, ax, oldax;
-
- /* clear a fat object */
- if(debug['g'])
- dump("\nclearfat", nl);
-
-
- w = nl->type->width;
- if(w == 16)
- if(componentgen(N, nl))
- return;
-
- c = w % 8; // bytes
- q = w / 8; // quads
-
- savex(D_DI, &n1, &oldn1, N, types[tptr]);
- agen(nl, &n1);
-
- savex(D_AX, &ax, &oldax, N, types[tptr]);
- gconreg(AMOVQ, 0, D_AX);
-
- if(q >= 4) {
- gconreg(AMOVQ, q, D_CX);
- gins(AREP, N, N); // repeat
- gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
- } else
- while(q > 0) {
- gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
- q--;
- }
-
- if(c >= 4) {
- gconreg(AMOVQ, c, D_CX);
- gins(AREP, N, N); // repeat
- gins(ASTOSB, N, N); // STOB AL,*(DI)+
- } else
- while(c > 0) {
- gins(ASTOSB, N, N); // STOB AL,*(DI)+
- c--;
- }
-
- restx(&n1, &oldn1);
- restx(&ax, &oldax);
-}
-
-static int
-regcmp(const void *va, const void *vb)
-{
- Node *ra, *rb;
-
- ra = (Node*)va;
- rb = (Node*)vb;
- return ra->local - rb->local;
-}
-
-static Prog* throwpc;
-
-void
-getargs(NodeList *nn, Node *reg, int n)
-{
- NodeList *l;
- int i;
-
- throwpc = nil;
-
- l = nn;
- for(i=0; i<n; i++) {
- if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) {
- regalloc(reg+i, l->n->right->type, N);
- cgen(l->n->right, reg+i);
- } else
- reg[i] = *l->n->right;
- if(reg[i].local != 0)
- yyerror("local used");
- reg[i].local = l->n->left->xoffset;
- l = l->next;
- }
- qsort((void*)reg, n, sizeof(*reg), regcmp);
- for(i=0; i<n; i++)
- reg[i].local = 0;
-}
-
-void
-cmpandthrow(Node *nl, Node *nr)
-{
- vlong cl;
- Prog *p1;
- int op;
- Node *c;
- Type *t;
- Node n1;
-
- if(nl->op == OCONV && is64(nl->type))
- nl = nl->left;
- if(nr->op == OCONV && is64(nr->type))
- nr = nr->left;
-
- op = OLE;
- if(smallintconst(nl)) {
- cl = mpgetfix(nl->val.u.xval);
- if(cl == 0)
- return;
- if(smallintconst(nr))
- return;
- // put the constant on the right
- op = brrev(op);
- c = nl;
- nl = nr;
- nr = c;
- }
- if(is64(nr->type) && smallintconst(nr))
- nr->type = types[TUINT32];
-
- n1.op = OXXX;
- t = types[TUINT32];
- if(nl->type->width != t->width || nr->type->width != t->width) {
- if((is64(nl->type) && nl->op != OLITERAL) || (is64(nr->type) && nr->op != OLITERAL))
- t = types[TUINT64];
-
- // Check if we need to use a temporary.
- // At least one of the arguments is 32 bits
- // (the len or cap) so one temporary suffices.
- if(nl->type->width != t->width && nl->op != OLITERAL) {
- regalloc(&n1, t, nl);
- gmove(nl, &n1);
- nl = &n1;
- } else if(nr->type->width != t->width && nr->op != OLITERAL) {
- regalloc(&n1, t, nr);
- gmove(nr, &n1);
- nr = &n1;
- }
- }
- gins(optoas(OCMP, t), nl, nr);
- if(n1.op != OXXX)
- regfree(&n1);
- if(throwpc == nil) {
- p1 = gbranch(optoas(op, t), T);
- throwpc = pc;
- ginscall(panicslice, 0);
- patch(p1, pc);
- } else {
- op = brcom(op);
- p1 = gbranch(optoas(op, t), T);
- patch(p1, throwpc);
- }
-}
-
-int
-sleasy(Node *n)
-{
- if(n->op != ONAME)
- return 0;
- if(!n->addable)
- return 0;
- return 1;
-}
-
-// generate inline code for
-// slicearray
-// sliceslice
-// arraytoslice
-int
-cgen_inline(Node *n, Node *res)
-{
- Node nodes[5];
- Node n1, n2, nres, ntemp;
- vlong v;
- int i, narg, nochk;
-
- if(n->op != OCALLFUNC)
- goto no;
- if(!n->left->addable)
- goto no;
- if(n->left->sym == S)
- goto no;
- if(n->left->sym->pkg != runtimepkg)
- goto no;
- if(strcmp(n->left->sym->name, "slicearray") == 0)
- goto slicearray;
- if(strcmp(n->left->sym->name, "sliceslice") == 0) {
- narg = 4;
- goto sliceslice;
- }
- if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
- narg = 3;
- goto sliceslice;
- }
- goto no;
-
-slicearray:
- if(!sleasy(res))
- goto no;
- getargs(n->list, nodes, 5);
-
- // if(hb[3] > nel[1]) goto throw
- cmpandthrow(&nodes[3], &nodes[1]);
-
- // if(lb[2] > hb[3]) goto throw
- cmpandthrow(&nodes[2], &nodes[3]);
-
- // len = hb[3] - lb[2] (destroys hb)
- n2 = *res;
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
-
- if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
- v = mpgetfix(nodes[3].val.u.xval) -
- mpgetfix(nodes[2].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[3]);
- gmove(&nodes[3], &n1);
- if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
- }
-
- // cap = nel[1] - lb[2] (destroys nel)
- n2 = *res;
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
-
- if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
- v = mpgetfix(nodes[1].val.u.xval) -
- mpgetfix(nodes[2].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[1]);
- gmove(&nodes[1], &n1);
- if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
- }
-
- // if slice could be too big, dereference to
- // catch nil array pointer.
- if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
- n2 = nodes[0];
- n2.xoffset = 0;
- n2.op = OINDREG;
- n2.type = types[TUINT8];
- gins(ATESTB, nodintconst(0), &n2);
- }
-
- // ary = old[0] + (lb[2] * width[4]) (destroys old)
- n2 = *res;
- n2.xoffset += Array_array;
- n2.type = types[tptr];
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
- v = mpgetfix(nodes[2].val.u.xval) *
- mpgetfix(nodes[4].val.u.xval);
- if(v != 0)
- ginscon(optoas(OADD, types[tptr]), v, &nodes[0]);
- } else {
- regalloc(&n1, types[tptr], &nodes[2]);
- gmove(&nodes[2], &n1);
- if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1)
- gins(optoas(OMUL, types[tptr]), &nodes[4], &n1);
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- regfree(&n1);
- }
- gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
-
- for(i=0; i<5; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
- return 1;
-
-sliceslice:
- nochk = n->etype; // skip bounds checking
- ntemp.op = OXXX;
- if(!sleasy(n->list->n->right)) {
- Node *n0;
-
- n0 = n->list->n->right;
- tempname(&ntemp, res->type);
- cgen(n0, &ntemp);
- n->list->n->right = &ntemp;
- getargs(n->list, nodes, narg);
- n->list->n->right = n0;
- } else
- getargs(n->list, nodes, narg);
-
- nres = *res; // result
- if(!sleasy(res)) {
- if(ntemp.op == OXXX)
- tempname(&ntemp, res->type);
- nres = ntemp;
- }
-
- if(narg == 3) { // old[lb:]
- // move width to where it would be for old[lb:hb]
- nodes[3] = nodes[2];
- nodes[2].op = OXXX;
-
- // if(lb[1] > old.nel[0]) goto throw;
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- if(!nochk)
- cmpandthrow(&nodes[1], &n2);
-
- // ret.nel = old.nel[0]-lb[1];
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
-
- regalloc(&n1, types[TUINT32], N);
- gins(optoas(OAS, types[TUINT32]), &n2, &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
-
- n2 = nres;
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
- } else { // old[lb:hb]
- n2 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
- if(!nochk) {
- // if(hb[2] > old.cap[0]) goto throw;
- cmpandthrow(&nodes[2], &n2);
- // if(lb[1] > hb[2]) goto throw;
- cmpandthrow(&nodes[1], &nodes[2]);
- }
- // ret.len = hb[2]-lb[1]; (destroys hb[2])
- n2 = nres;
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
- v = mpgetfix(nodes[2].val.u.xval) -
- mpgetfix(nodes[1].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gmove(&nodes[2], &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
- }
- }
-
- // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
- n2 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
-
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gins(optoas(OAS, types[TUINT32]), &n2, &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
-
- n2 = nres;
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
-
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
-
- // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
- n2 = nodes[0];
- n2.xoffset += Array_array;
- n2.type = types[tptr];
- regalloc(&n1, types[tptr], &nodes[1]);
- if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
- gins(optoas(OAS, types[tptr]), &n2, &n1);
- v = mpgetfix(nodes[1].val.u.xval) *
- mpgetfix(nodes[3].val.u.xval);
- if(v != 0)
- ginscon(optoas(OADD, types[tptr]), v, &n1);
- } else {
- gmove(&nodes[1], &n1);
- if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1)
- gins(optoas(OMUL, types[tptr]), &nodes[3], &n1);
- gins(optoas(OADD, types[tptr]), &n2, &n1);
- }
-
- n2 = nres;
- n2.xoffset += Array_array;
- n2.type = types[tptr];
- gins(optoas(OAS, types[tptr]), &n1, &n2);
- regfree(&n1);
-
- for(i=0; i<4; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
-
- if(!sleasy(res)) {
- cgen(&nres, res);
- }
- return 1;
-
-no:
- return 0;
-}
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
deleted file mode 100644
index ba8a4870e..000000000
--- a/src/cmd/6g/gobj.c
+++ /dev/null
@@ -1,644 +0,0 @@
-// 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 "gg.h"
-
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- Bputc(b, ANAME); /* as */
- Bputc(b, ANAME>>8); /* as */
- Bputc(b, t); /* type */
- Bputc(b, s->sym); /* sym */
-
- Bputname(b, s);
-}
-
-void
-zfile(Biobuf *b, char *p, int n)
-{
- Bputc(b, ANAME);
- Bputc(b, ANAME>>8);
- Bputc(b, D_FILE);
- Bputc(b, 1);
- Bputc(b, '<');
- Bwrite(b, p, n);
- Bputc(b, 0);
-}
-
-void
-zhist(Biobuf *b, int line, vlong offset)
-{
- Addr a;
-
- Bputc(b, AHISTORY);
- Bputc(b, AHISTORY>>8);
- Bputc(b, line);
- Bputc(b, line>>8);
- Bputc(b, line>>16);
- Bputc(b, line>>24);
- zaddr(b, &zprog.from, 0, 0);
- a = zprog.to;
- if(offset != 0) {
- a.offset = offset;
- a.type = D_CONST;
- }
- zaddr(b, &a, 0, 0);
-}
-
-void
-zaddr(Biobuf *b, Addr *a, int s, int gotype)
-{
- int32 l;
- uint64 e;
- int i, t;
- char *n;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(s != 0)
- t |= T_SYM;
- if(gotype != 0)
- t |= T_GOTYPE;
-
- switch(a->type) {
-
- case D_BRANCH:
- if(a->branch == nil)
- fatal("unpatched branch");
- a->offset = a->branch->loc;
-
- default:
- t |= T_TYPE;
-
- case D_NONE:
- if(a->offset != 0) {
- t |= T_OFFSET;
- l = a->offset;
- if((vlong)l != a->offset)
- t |= T_64;
- }
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- }
- Bputc(b, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- Bputc(b, a->index);
- Bputc(b, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- if(t & T_64) {
- l = a->offset>>32;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- }
- }
- if(t & T_SYM) /* implies sym */
- Bputc(b, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->dval);
- l = e;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- l = e >> 32;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- return;
- }
- if(t & T_SCONST) {
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- Bputc(b, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- Bputc(b, a->type);
- if(t & T_GOTYPE)
- Bputc(b, gotype);
-}
-
-static struct {
- struct { Sym *sym; short type; } h[NSYM];
- int sym;
-} z;
-
-static void
-zsymreset(void)
-{
- for(z.sym=0; z.sym<NSYM; z.sym++) {
- z.h[z.sym].sym = S;
- z.h[z.sym].type = 0;
- }
- z.sym = 1;
-}
-
-static int
-zsym(Sym *s, int t, int *new)
-{
- int i;
-
- *new = 0;
- if(s == S)
- return 0;
-
- i = s->sym;
- if(i < 0 || i >= NSYM)
- i = 0;
- if(z.h[i].type == t && z.h[i].sym == s)
- return i;
- i = z.sym;
- s->sym = i;
- zname(bout, s, t);
- z.h[i].sym = s;
- z.h[i].type = t;
- if(++z.sym >= NSYM)
- z.sym = 1;
- *new = 1;
- return i;
-}
-
-static int
-zsymaddr(Addr *a, int *new)
-{
- int t;
-
- t = a->type;
- if(t == D_ADDR)
- t = a->index;
- return zsym(a->sym, t, new);
-}
-
-void
-dumpfuncs(void)
-{
- Plist *pl;
- int sf, st, gf, gt, new;
- Sym *s;
- Prog *p;
-
- zsymreset();
-
- // fix up pc
- pcloc = 0;
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
- for(p=pl->firstpc; p!=P; p=p->link) {
- p->loc = pcloc;
- if(p->as != ADATA && p->as != AGLOBL)
- pcloc++;
- }
- }
-
- // put out functions
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
-
- if(debug['S']) {
- s = S;
- if(pl->name != N)
- s = pl->name->sym;
- print("\n--- prog list \"%S\" ---\n", s);
- for(p=pl->firstpc; p!=P; p=p->link)
- print("%P\n", p);
- }
-
- for(p=pl->firstpc; p!=P; p=p->link) {
- for(;;) {
- sf = zsymaddr(&p->from, &new);
- gf = zsym(p->from.gotype, D_EXTERN, &new);
- if(new && sf == gf)
- continue;
- st = zsymaddr(&p->to, &new);
- if(new && (st == sf || st == gf))
- continue;
- gt = zsym(p->to.gotype, D_EXTERN, &new);
- if(new && (gt == sf || gt == gf || gt == st))
- continue;
- break;
- }
-
- Bputc(bout, p->as);
- Bputc(bout, p->as>>8);
- Bputc(bout, p->lineno);
- Bputc(bout, p->lineno>>8);
- Bputc(bout, p->lineno>>16);
- Bputc(bout, p->lineno>>24);
- zaddr(bout, &p->from, sf, gf);
- zaddr(bout, &p->to, st, gt);
- }
- }
-}
-
-/* deferred DATA output */
-static Prog *strdat;
-static Prog *estrdat;
-static int gflag;
-static Prog *savepc;
-
-void
-data(void)
-{
- gflag = debug['g'];
- debug['g'] = 0;
-
- if(estrdat == nil) {
- strdat = mal(sizeof(*pc));
- clearp(strdat);
- estrdat = strdat;
- }
- if(savepc)
- fatal("data phase error");
- savepc = pc;
- pc = estrdat;
-}
-
-void
-text(void)
-{
- if(!savepc)
- fatal("text phase error");
- debug['g'] = gflag;
- estrdat = pc;
- pc = savepc;
- savepc = nil;
-}
-
-void
-dumpdata(void)
-{
- Prog *p;
-
- if(estrdat == nil)
- return;
- *pc = *strdat;
- if(gflag)
- for(p=pc; p!=estrdat; p=p->link)
- print("%P\n", p);
- pc = estrdat;
-}
-
-int
-dsname(Sym *s, int off, char *t, int n)
-{
- Prog *p;
-
- p = gins(ADATA, N, N);
- p->from.type = D_EXTERN;
- p->from.index = D_NONE;
- p->from.offset = off;
- p->from.scale = n;
- p->from.sym = s;
-
- p->to.type = D_SCONST;
- p->to.index = D_NONE;
- memmove(p->to.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_EXTERN;
- a->sym = sym;
- a->offset = widthptr+4; // skip header
- a->etype = TINT32;
-}
-
-/*
- * 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_EXTERN;
- a->sym = sym;
- a->offset = 0; // header
- a->etype = TINT32;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
- Prog *p;
-
- p = gins(ADATA, nam, nr);
- p->from.scale = 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->from.scale = w;
- p->to.type = D_FCONST;
- p->to.dval = mpgetflt(&cval->real);
-
- p = gins(ADATA, nam, N);
- p->from.scale = w;
- p->from.offset += w;
- p->to.type = D_FCONST;
- p->to.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->from.scale = types[tptr]->width;
- p->to.index = p->to.type;
- p->to.type = D_ADDR;
-//print("%P\n", p);
-
- nodconst(&nod1, types[TINT32], sval->len);
- p = gins(ADATA, nam, &nod1);
- p->from.scale = types[TINT32]->width;
- p->from.offset += types[tptr]->width;
-}
-
-int
-dstringptr(Sym *s, int off, char *str)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
- p = gins(ADATA, N, N);
- p->from.type = D_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->from.offset = off;
- p->from.scale = widthptr;
-
- datastring(str, strlen(str)+1, &p->to);
- p->to.index = p->to.type;
- p->to.type = D_ADDR;
- p->to.etype = TINT32;
- 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_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->from.offset = off;
- p->from.scale = widthptr;
- datagostring(lit, &p->to);
- p->to.index = p->to.type;
- p->to.type = D_ADDR;
- p->to.etype = TINT32;
- 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
-duintxx(Sym *s, int off, uint64 v, int wid)
-{
- Prog *p;
-
- off = rnd(off, wid);
-
- p = gins(ADATA, N, N);
- p->from.type = D_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->from.offset = off;
- p->from.scale = wid;
- p->to.type = D_CONST;
- p->to.index = D_NONE;
- p->to.offset = v;
- off += wid;
-
- return off;
-}
-
-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_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->from.offset = off;
- p->from.scale = widthptr;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.sym = x;
- p->to.offset = xoff;
- off += widthptr;
-
- return off;
-}
-
-void
-genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
-{
- Sym *e;
- int c, d, o, mov, add, loaded;
- Prog *p;
- Type *f;
-
- if(debug['r'])
- print("genembedtramp %T %T %S\n", rcvr, method, newnam);
-
- e = method->sym;
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(e, rcvr, d, nil, 0);
- if(c == 1)
- goto out;
- }
- fatal("genembedtramp %T.%S", rcvr, method->sym);
-
-out:
- newplist()->name = newname(newnam);
-
- //TEXT main·S_test2(SB),7,$0
- p = pc;
- gins(ATEXT, N, N);
- p->from.type = D_EXTERN;
- p->from.sym = newnam;
- p->to.type = D_CONST;
- p->to.offset = 0;
- p->from.scale = 7;
-//print("1. %P\n", p);
-
- mov = AMOVQ;
- add = AADDQ;
- loaded = 0;
- o = 0;
- for(c=d-1; c>=0; c--) {
- f = dotlist[c].field;
- o += f->width;
- if(!isptr[f->type->etype])
- continue;
- if(!loaded) {
- loaded = 1;
- //MOVQ 8(SP), AX
- p = pc;
- gins(mov, N, N);
- p->from.type = D_INDIR+D_SP;
- p->from.offset = widthptr;
- p->to.type = D_AX;
-//print("2. %P\n", p);
- }
-
- //MOVQ o(AX), AX
- p = pc;
- gins(mov, N, N);
- p->from.type = D_INDIR+D_AX;
- p->from.offset = o;
- p->to.type = D_AX;
-//print("3. %P\n", p);
- o = 0;
- }
- if(o != 0) {
- //ADDQ $XX, AX
- p = pc;
- gins(add, N, N);
- p->from.type = D_CONST;
- p->from.offset = o;
- if(loaded)
- p->to.type = D_AX;
- else {
- p->to.type = D_INDIR+D_SP;
- p->to.offset = widthptr;
- }
-//print("4. %P\n", p);
- }
-
- //MOVQ AX, 8(SP)
- if(loaded) {
- p = pc;
- gins(mov, N, N);
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_SP;
- p->to.offset = widthptr;
-//print("5. %P\n", p);
- } else {
- // TODO(rsc): obviously this is unnecessary,
- // but 6l has a bug, and it can't handle
- // JMP instructions too close to the top of
- // a new function.
- p = pc;
- gins(ANOP, N, N);
- }
-
- f = dotlist[0].field;
- //JMP main·*Sub_test2(SB)
- if(isptr[f->type->etype])
- f = f->type;
- p = pc;
- gins(AJMP, N, N);
- p->to.type = D_EXTERN;
- p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
-//print("6. %P\n", p);
-
- pc->as = ARET; // overwrite AEND
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
-}
-
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
deleted file mode 100644
index 211915f54..000000000
--- a/src/cmd/6g/gsubr.c
+++ /dev/null
@@ -1,2159 +0,0 @@
-// 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 "gg.h"
-
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 6l for all GOOS.
-vlong unmappedzero = 4096;
-
-void
-clearp(Prog *p)
-{
- p->as = AEND;
- p->from.type = D_NONE;
- p->from.index = D_NONE;
- p->to.type = D_NONE;
- p->to.index = D_NONE;
- p->loc = pcloc;
- pcloc++;
-}
-
-/*
- * generate and return proc with p->as = as,
- * linked into program. pc is next instruction.
- */
-Prog*
-prog(int as)
-{
- Prog *p;
-
- p = pc;
- pc = mal(sizeof(*pc));
-
- clearp(pc);
-
- if(lineno == 0) {
- if(debug['K'])
- warn("prog: line 0");
- }
-
- p->as = as;
- p->lineno = lineno;
- p->link = pc;
- return p;
-}
-
-/*
- * generate a branch.
- * t is ignored.
- */
-Prog*
-gbranch(int as, Type *t)
-{
- Prog *p;
-
- p = prog(as);
- p->to.type = D_BRANCH;
- p->to.branch = P;
- 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.branch = to;
- p->to.offset = to->loc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
- Prog *q;
-
- if(p->to.type != D_BRANCH)
- fatal("unpatch: not a branch");
- q = p->to.branch;
- p->to.branch = P;
- p->to.offset = 0;
- return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
- Plist *pl;
-
- pl = mal(sizeof(*pl));
- if(plist == nil)
- plist = pl;
- else
- plast->link = pl;
- plast = pl;
-
- pc = mal(sizeof(*pc));
- clearp(pc);
- pl->firstpc = pc;
-
- return pl;
-}
-
-void
-clearstk(void)
-{
- Plist *pl;
- Prog *p1, *p2;
- Node sp, di, cx, con, ax;
-
- if((uint32)plast->firstpc->to.offset <= 0)
- return;
-
- // reestablish context for inserting code
- // at beginning of function.
- pl = plast;
- p1 = pl->firstpc;
- p2 = p1->link;
- pc = mal(sizeof(*pc));
- clearp(pc);
- p1->link = pc;
-
- // zero stack frame
- nodreg(&sp, types[tptr], D_SP);
- nodreg(&di, types[tptr], D_DI);
- nodreg(&cx, types[TUINT64], D_CX);
- nodconst(&con, types[TUINT64], (uint32)p1->to.offset / widthptr);
- gins(ACLD, N, N);
- gins(AMOVQ, &sp, &di);
- gins(AMOVQ, &con, &cx);
- nodconst(&con, types[TUINT64], 0);
- nodreg(&ax, types[TUINT64], D_AX);
- gins(AMOVQ, &con, &ax);
- gins(AREP, N, N);
- gins(ASTOSQ, N, N);
-
- // continue with original code.
- gins(ANOP, N, N)->link = p2;
- pc = P;
-}
-
-void
-gused(Node *n)
-{
- gins(ANOP, n, N); // used
-}
-
-Prog*
-gjmp(Prog *to)
-{
- Prog *p;
-
- p = gbranch(AJMP, T);
- if(to != P)
- patch(p, to);
- return p;
-}
-
-void
-ggloblnod(Node *nam, int32 width)
-{
- Prog *p;
-
- p = gins(AGLOBL, nam, N);
- p->lineno = nam->lineno;
- p->to.sym = S;
- p->to.type = D_CONST;
- p->to.offset = width;
- if(nam->readonly)
- p->from.scale = RODATA;
-}
-
-void
-ggloblsym(Sym *s, int32 width, int dupok)
-{
- Prog *p;
-
- p = gins(AGLOBL, N, N);
- p->from.type = D_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->to.type = D_CONST;
- p->to.index = D_NONE;
- p->to.offset = width;
- if(dupok)
- p->from.scale = DUPOK;
- p->from.scale |= RODATA;
-}
-
-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)
-{
- if(a->type == D_ADDR && a->index == D_EXTERN) {
- a->type = D_EXTERN;
- a->index = D_NONE;
- }
-}
-
-static int resvd[] =
-{
- D_DI, // for movstring
- D_SI, // for movstring
-
- D_AX, // for divide
- D_CX, // for shift
- D_DX, // for divide
- D_SP, // for stack
- D_R14, // reserved for m
- D_R15, // reserved for u
-};
-
-void
-ginit(void)
-{
- int i;
-
- for(i=0; i<nelem(reg); i++)
- reg[i] = 1;
- for(i=D_AX; i<=D_R15; i++)
- reg[i] = 0;
- for(i=D_X0; i<=D_X7; i++)
- reg[i] = 0;
-
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i]]++;
-}
-
-void
-gclean(void)
-{
- int i;
-
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i]]--;
-
- for(i=D_AX; i<=D_R15; i++)
- if(reg[i])
- yyerror("reg %R left allocated\n", i);
- for(i=D_X0; i<=D_X7; i++)
- if(reg[i])
- yyerror("reg %R left allocated\n", i);
-}
-
-int32
-anyregalloc(void)
-{
- int i, j;
-
- for(i=D_AX; i<=D_R15; 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;
-
- if(t == T)
- fatal("regalloc: t nil");
- et = simtype[t->etype];
-
- 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_AX && i <= D_R15)
- goto out;
- }
- for(i=D_AX; i<=D_R15; i++)
- if(reg[i] == 0)
- goto out;
-
- yyerror("out of fixed registers");
- goto err;
-
- case TFLOAT32:
- case TFLOAT64:
- if(o != N && o->op == OREGISTER) {
- i = o->val.u.reg;
- if(i >= D_X0 && i <= D_X7)
- goto out;
- }
- for(i=D_X0; i<=D_X7; i++)
- if(reg[i] == 0)
- goto out;
- yyerror("out of floating registers");
- goto err;
-
- case TCOMPLEX64:
- case TCOMPLEX128:
- tempname(n, t);
- return;
- }
- yyerror("regalloc: unknown type %T", t);
-
-err:
- nodreg(n, t, 0);
- 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_SP)
- return;
- if(i < 0 || i >= sizeof(reg))
- fatal("regfree: reg out of range");
- if(reg[i] <= 0)
- fatal("regfree: reg not allocated");
- reg[i]--;
-}
-
-/*
- * 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;
- 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);
-
- 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;
-
-fp:
- switch(fp) {
- case 0: // output arg
- n->op = OINDREG;
- n->val.u.reg = D_SP;
- break;
-
- case 1: // input arg
- n->class = PPARAM;
- break;
-
- case 2: // offset output arg
-fatal("shouldnt be used");
- n->op = OINDREG;
- n->val.u.reg = D_SP;
- n->xoffset += types[tptr]->width;
- break;
- }
- return n;
-}
-
-/*
- * generate
- * as $c, reg
- */
-void
-gconreg(int as, vlong c, int reg)
-{
- Node nr;
-
- nodreg(&nr, types[TINT64], reg);
- ginscon(as, c, &nr);
-}
-
-/*
- * generate
- * as $c, n
- */
-void
-ginscon(int as, vlong c, Node *n2)
-{
- Node n1, ntmp;
-
- nodconst(&n1, types[TINT64], c);
-
- if(as != AMOVQ && (c < -1LL<<31 || c >= 1LL<<31)) {
- // cannot have 64-bit immediokate in ADD, etc.
- // instead, MOV into register first.
- regalloc(&ntmp, types[TINT64], N);
- gins(AMOVQ, &n1, &ntmp);
- gins(as, &ntmp, n2);
- regfree(&ntmp);
- return;
- }
- gins(as, &n1, n2);
-}
-
-#define CASE(a,b) (((a)<<16)|((b)<<0))
-
-/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
- switch(n->op) {
- case OLEN:
- case OCAP:
- case OINDREG:
- case ONAME:
- case OPARAM:
- 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.
- */
-// TODO: lost special constants for floating point. XORPD for 0.0?
-void
-gmove(Node *f, Node *t)
-{
- int a, ft, tt;
- Type *cvt;
- Node r1, r2, r3, r4, zero, one, con;
- Prog *p1, *p2;
-
- if(debug['M'])
- print("gmove %N -> %N\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) {
- convconst(&con, t->type, &f->val);
- f = &con;
- ft = tt; // so big switch will choose a simple mov
-
- // some constants can't move directly to memory.
- if(ismem(t)) {
- // float constants come from memory.
- if(isfloat[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(TINT8, TUINT8):
- case CASE(TUINT8, TINT8):
- case CASE(TUINT8, TUINT8):
- 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):
- case CASE(TINT16, TUINT8):
- case CASE(TUINT16, TUINT8):
- case CASE(TINT32, TUINT8):
- case CASE(TUINT32, TUINT8):
- case CASE(TINT64, TUINT8):
- case CASE(TUINT64, TUINT8):
- a = AMOVB;
- break;
-
- case CASE(TINT16, TINT16): // same size
- case CASE(TINT16, TUINT16):
- case CASE(TUINT16, TINT16):
- case CASE(TUINT16, TUINT16):
- case CASE(TINT32, TINT16): // truncate
- case CASE(TUINT32, TINT16):
- case CASE(TINT64, TINT16):
- case CASE(TUINT64, TINT16):
- case CASE(TINT32, TUINT16):
- case CASE(TUINT32, TUINT16):
- case CASE(TINT64, TUINT16):
- case CASE(TUINT64, TUINT16):
- a = AMOVW;
- break;
-
- case CASE(TINT32, TINT32): // same size
- case CASE(TINT32, TUINT32):
- case CASE(TUINT32, TINT32):
- case CASE(TUINT32, TUINT32):
- case CASE(TINT64, TINT32): // truncate
- case CASE(TUINT64, TINT32):
- case CASE(TINT64, TUINT32):
- case CASE(TUINT64, TUINT32):
- a = AMOVL;
- break;
-
- case CASE(TINT64, TINT64): // same size
- case CASE(TINT64, TUINT64):
- case CASE(TUINT64, TINT64):
- case CASE(TUINT64, TUINT64):
- a = AMOVQ;
- break;
-
- /*
- * integer up-conversions
- */
- case CASE(TINT8, TINT16): // sign extend int8
- case CASE(TINT8, TUINT16):
- a = AMOVBWSX;
- goto rdst;
- case CASE(TINT8, TINT32):
- case CASE(TINT8, TUINT32):
- a = AMOVBLSX;
- goto rdst;
- case CASE(TINT8, TINT64):
- case CASE(TINT8, TUINT64):
- a = AMOVBQSX;
- goto rdst;
-
- case CASE(TUINT8, TINT16): // zero extend uint8
- case CASE(TUINT8, TUINT16):
- a = AMOVBWZX;
- goto rdst;
- case CASE(TUINT8, TINT32):
- case CASE(TUINT8, TUINT32):
- a = AMOVBLZX;
- goto rdst;
- case CASE(TUINT8, TINT64):
- case CASE(TUINT8, TUINT64):
- a = AMOVBQZX;
- goto rdst;
-
- case CASE(TINT16, TINT32): // sign extend int16
- case CASE(TINT16, TUINT32):
- a = AMOVWLSX;
- goto rdst;
- case CASE(TINT16, TINT64):
- case CASE(TINT16, TUINT64):
- a = AMOVWQSX;
- goto rdst;
-
- case CASE(TUINT16, TINT32): // zero extend uint16
- case CASE(TUINT16, TUINT32):
- a = AMOVWLZX;
- goto rdst;
- case CASE(TUINT16, TINT64):
- case CASE(TUINT16, TUINT64):
- a = AMOVWQZX;
- goto rdst;
-
- case CASE(TINT32, TINT64): // sign extend int32
- case CASE(TINT32, TUINT64):
- a = AMOVLQSX;
- goto rdst;
-
- case CASE(TUINT32, TINT64): // zero extend uint32
- case CASE(TUINT32, TUINT64):
- // AMOVL into a register zeros the top of the register,
- // so this is not always necessary, but if we rely on AMOVL
- // the optimizer is almost certain to screw with us.
- a = AMOVLQZX;
- goto rdst;
-
- /*
- * float to integer
- */
- case CASE(TFLOAT32, TINT32):
- a = ACVTTSS2SL;
- goto rdst;
-
- case CASE(TFLOAT64, TINT32):
- a = ACVTTSD2SL;
- goto rdst;
-
- case CASE(TFLOAT32, TINT64):
- a = ACVTTSS2SQ;
- goto rdst;
-
- case CASE(TFLOAT64, TINT64):
- a = ACVTTSD2SQ;
- goto rdst;
-
- 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):
- // convert via int32.
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TFLOAT32, TUINT32):
- case CASE(TFLOAT64, TUINT32):
- // convert via int64.
- cvt = types[TINT64];
- goto hard;
-
- case CASE(TFLOAT32, TUINT64):
- case CASE(TFLOAT64, TUINT64):
- // algorithm is:
- // if small enough, use native float64 -> int64 conversion.
- // otherwise, subtract 2^63, convert, and add it back.
- a = ACVTSS2SQ;
- if(ft == TFLOAT64)
- a = ACVTSD2SQ;
- bignodes();
- regalloc(&r1, types[ft], N);
- regalloc(&r2, types[tt], t);
- regalloc(&r3, types[ft], N);
- regalloc(&r4, types[tt], N);
- gins(optoas(OAS, f->type), f, &r1);
- gins(optoas(OCMP, f->type), &bigf, &r1);
- p1 = gbranch(optoas(OLE, f->type), T);
- gins(a, &r1, &r2);
- p2 = gbranch(AJMP, T);
- patch(p1, pc);
- gins(optoas(OAS, f->type), &bigf, &r3);
- gins(optoas(OSUB, f->type), &r3, &r1);
- gins(a, &r1, &r2);
- gins(AMOVQ, &bigi, &r4);
- gins(AXORQ, &r4, &r2);
- patch(p2, pc);
- gmove(&r2, t);
- regfree(&r4);
- regfree(&r3);
- regfree(&r2);
- regfree(&r1);
- return;
-
- /*
- * integer to float
- */
- case CASE(TINT32, TFLOAT32):
- a = ACVTSL2SS;
- goto rdst;
-
-
- case CASE(TINT32, TFLOAT64):
- a = ACVTSL2SD;
- goto rdst;
-
- case CASE(TINT64, TFLOAT32):
- a = ACVTSQ2SS;
- goto rdst;
-
- case CASE(TINT64, TFLOAT64):
- a = ACVTSQ2SD;
- goto rdst;
-
- 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):
- // convert via int32
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT32, TFLOAT32):
- case CASE(TUINT32, TFLOAT64):
- // convert via int64.
- cvt = types[TINT64];
- goto hard;
-
- case CASE(TUINT64, TFLOAT32):
- case CASE(TUINT64, TFLOAT64):
- // algorithm is:
- // if small enough, use native int64 -> uint64 conversion.
- // otherwise, halve (rounding to odd?), convert, and double.
- a = ACVTSQ2SS;
- if(tt == TFLOAT64)
- a = ACVTSQ2SD;
- nodconst(&zero, types[TUINT64], 0);
- nodconst(&one, types[TUINT64], 1);
- regalloc(&r1, f->type, f);
- regalloc(&r2, t->type, t);
- regalloc(&r3, f->type, N);
- regalloc(&r4, f->type, N);
- gmove(f, &r1);
- gins(ACMPQ, &r1, &zero);
- p1 = gbranch(AJLT, T);
- gins(a, &r1, &r2);
- p2 = gbranch(AJMP, T);
- patch(p1, pc);
- gmove(&r1, &r3);
- gins(ASHRQ, &one, &r3);
- gmove(&r1, &r4);
- gins(AANDL, &one, &r4);
- gins(AORQ, &r4, &r3);
- gins(a, &r3, &r2);
- gins(optoas(OADD, t->type), &r2, &r2);
- patch(p2, pc);
- gmove(&r2, t);
- regfree(&r4);
- regfree(&r3);
- regfree(&r2);
- regfree(&r1);
- return;
-
- /*
- * float to float
- */
- case CASE(TFLOAT32, TFLOAT32):
- a = AMOVSS;
- break;
-
- case CASE(TFLOAT64, TFLOAT64):
- a = AMOVSD;
- break;
-
- case CASE(TFLOAT32, TFLOAT64):
- a = ACVTSS2SD;
- goto rdst;
-
- case CASE(TFLOAT64, TFLOAT32):
- a = ACVTSD2SS;
- 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;
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
- if(f->op != t->op)
- return 0;
-
- switch(f->op) {
- case OREGISTER:
- if(f->val.u.reg != t->val.u.reg)
- break;
- return 1;
- }
- return 0;
-}
-
-/*
- * generate one instruction:
- * as f, t
- */
-Prog*
-gins(int as, Node *f, Node *t)
-{
-// Node nod;
- int32 w;
- Prog *p;
- Addr af, at;
-
-// if(f != N && f->op == OINDEX) {
-// regalloc(&nod, &regnode, Z);
-// v = constnode.vconst;
-// cgen(f->right, &nod);
-// constnode.vconst = v;
-// idx.reg = nod.reg;
-// regfree(&nod);
-// }
-// if(t != N && t->op == OINDEX) {
-// regalloc(&nod, &regnode, Z);
-// v = constnode.vconst;
-// cgen(t->right, &nod);
-// constnode.vconst = v;
-// idx.reg = nod.reg;
-// regfree(&nod);
-// }
-
- switch(as) {
- case AMOVB:
- case AMOVW:
- case AMOVL:
- case AMOVQ:
- case AMOVSS:
- case AMOVSD:
- if(f != N && t != N && samaddr(f, t))
- return nil;
- }
-
- 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(debug['g'])
- print("%P\n", p);
-
-
- w = 0;
- switch(as) {
- case AMOVB:
- w = 1;
- break;
- case AMOVW:
- w = 2;
- break;
- case AMOVL:
- w = 4;
- break;
- case AMOVQ:
- w = 8;
- break;
- }
- if(w != 0 && f != N && (af.width > w || at.width > w)) {
- fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
- }
-
- return p;
-}
-
-static void
-checkoffset(Addr *a, int canemitcode)
-{
- Prog *p;
-
- if(a->offset < unmappedzero)
- return;
- if(!canemitcode)
- fatal("checkoffset %#llx, cannot emit code", a->offset);
-
- // cannot rely on unmapped nil page at 0 to catch
- // reference with large offset. instead, emit explicit
- // test of 0(reg).
- p = gins(ATESTB, nodintconst(0), N);
- p->to = *a;
- p->to.offset = 0;
-}
-
-/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
- a->scale = 0;
- a->index = D_NONE;
- a->type = D_NONE;
- a->gotype = S;
- a->node = N;
- if(n == N)
- return;
-
- switch(n->op) {
- default:
- fatal("naddr: bad %O %D", n->op, a);
- break;
-
- case OREGISTER:
- a->type = n->val.u.reg;
- a->sym = S;
- break;
-
-// case OINDEX:
-// case OIND:
-// naddr(n->left, a);
-// if(a->type >= D_AX && a->type <= D_DI)
-// a->type += D_INDIR;
-// else
-// if(a->type == D_CONST)
-// a->type = D_NONE+D_INDIR;
-// else
-// if(a->type == D_ADDR) {
-// a->type = a->index;
-// a->index = D_NONE;
-// } else
-// goto bad;
-// if(n->op == OINDEX) {
-// a->index = idx.reg;
-// a->scale = n->scale;
-// }
-// break;
-
- case OINDREG:
- a->type = n->val.u.reg+D_INDIR;
- a->sym = n->sym;
- a->offset = n->xoffset;
- checkoffset(a, canemitcode);
- 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 = n->left->sym;
- a->type = D_PARAM;
- break;
-
- case ONAME:
- a->etype = 0;
- a->width = 0;
- if(n->type != T) {
- a->etype = simtype[n->type->etype];
- a->width = n->type->width;
- a->gotype = ngotype(n);
- }
- a->pun = n->pun;
- a->offset = n->xoffset;
- a->sym = n->sym;
- if(a->sym == S)
- a->sym = lookup(".noname");
- if(n->method) {
- if(n->type != T)
- if(n->type->sym != S)
- if(n->type->sym->pkg != nil)
- a->sym = pkglookup(a->sym->name, n->type->sym->pkg);
- }
-
- switch(n->class) {
- default:
- fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
- case PEXTERN:
- a->type = D_EXTERN;
- break;
- case PAUTO:
- a->type = D_AUTO;
- if (n->sym)
- a->node = n->orig;
- break;
- case PPARAM:
- case PPARAMOUT:
- a->type = D_PARAM;
- break;
- case PFUNC:
- a->index = D_EXTERN;
- a->type = D_ADDR;
- break;
- }
- break;
-
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- fatal("naddr: const %lT", n->type);
- break;
- case CTFLT:
- a->type = D_FCONST;
- a->dval = mpgetflt(n->val.u.fval);
- break;
- case CTINT:
- a->sym = S;
- 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 = S;
- a->type = D_CONST;
- a->offset = n->val.u.bval;
- break;
- case CTNIL:
- a->sym = S;
- a->type = D_CONST;
- a->offset = 0;
- break;
- }
- break;
-
- case OADDR:
- naddr(n->left, a, canemitcode);
- if(a->type >= D_INDIR) {
- a->type -= D_INDIR;
- break;
- }
- if(a->type == D_EXTERN || a->type == D_STATIC ||
- a->type == D_AUTO || a->type == D_PARAM)
- if(a->index == D_NONE) {
- a->index = a->type;
- a->type = D_ADDR;
- break;
- }
- fatal("naddr: OADDR\n");
-
- case OLEN:
- // len of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == D_CONST && a->offset == 0)
- break; // len(nil)
- a->etype = TUINT32;
- a->offset += Array_nel;
- a->width = 4;
- if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
- checkoffset(a, canemitcode);
- break;
-
- case OCAP:
- // cap of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == D_CONST && a->offset == 0)
- break; // cap(nil)
- a->etype = TUINT32;
- a->offset += Array_cap;
- a->width = 4;
- if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero)
- checkoffset(a, canemitcode);
- break;
-
-// case OADD:
-// if(n->right->op == OLITERAL) {
-// v = n->right->vconst;
-// naddr(n->left, a, canemitcode);
-// } else
-// if(n->left->op == OLITERAL) {
-// v = n->left->vconst;
-// naddr(n->right, a, canemitcode);
-// } else
-// goto bad;
-// a->offset += v;
-// 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 %O-%T", op, t);
- break;
-
- case CASE(OADDR, TPTR32):
- a = ALEAL;
- break;
-
- case CASE(OADDR, TPTR64):
- a = ALEAQ;
- 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 = AJEQ;
- 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 = AJNE;
- break;
-
- case CASE(OLT, TINT8):
- case CASE(OLT, TINT16):
- case CASE(OLT, TINT32):
- case CASE(OLT, TINT64):
- a = AJLT;
- break;
-
- case CASE(OLT, TUINT8):
- case CASE(OLT, TUINT16):
- case CASE(OLT, TUINT32):
- case CASE(OLT, TUINT64):
- a = AJCS;
- break;
-
- case CASE(OLE, TINT8):
- case CASE(OLE, TINT16):
- case CASE(OLE, TINT32):
- case CASE(OLE, TINT64):
- a = AJLE;
- break;
-
- case CASE(OLE, TUINT8):
- case CASE(OLE, TUINT16):
- case CASE(OLE, TUINT32):
- case CASE(OLE, TUINT64):
- a = AJLS;
- break;
-
- case CASE(OGT, TINT8):
- case CASE(OGT, TINT16):
- case CASE(OGT, TINT32):
- case CASE(OGT, TINT64):
- a = AJGT;
- break;
-
- case CASE(OGT, TUINT8):
- case CASE(OGT, TUINT16):
- case CASE(OGT, TUINT32):
- case CASE(OGT, TUINT64):
- case CASE(OLT, TFLOAT32):
- case CASE(OLT, TFLOAT64):
- a = AJHI;
- break;
-
- case CASE(OGE, TINT8):
- case CASE(OGE, TINT16):
- case CASE(OGE, TINT32):
- case CASE(OGE, TINT64):
- a = AJGE;
- break;
-
- case CASE(OGE, TUINT8):
- case CASE(OGE, TUINT16):
- case CASE(OGE, TUINT32):
- case CASE(OGE, TUINT64):
- case CASE(OLE, TFLOAT32):
- case CASE(OLE, TFLOAT64):
- a = AJCC;
- break;
-
- case CASE(OCMP, TBOOL):
- case CASE(OCMP, TINT8):
- case CASE(OCMP, TUINT8):
- a = ACMPB;
- break;
-
- case CASE(OCMP, TINT16):
- case CASE(OCMP, TUINT16):
- a = ACMPW;
- break;
-
- case CASE(OCMP, TINT32):
- case CASE(OCMP, TUINT32):
- case CASE(OCMP, TPTR32):
- a = ACMPL;
- break;
-
- case CASE(OCMP, TINT64):
- case CASE(OCMP, TUINT64):
- case CASE(OCMP, TPTR64):
- a = ACMPQ;
- break;
-
- case CASE(OCMP, TFLOAT32):
- a = AUCOMISS;
- break;
-
- case CASE(OCMP, TFLOAT64):
- a = AUCOMISD;
- break;
-
- case CASE(OAS, TBOOL):
- case CASE(OAS, TINT8):
- case CASE(OAS, TUINT8):
- a = AMOVB;
- break;
-
- case CASE(OAS, TINT16):
- case CASE(OAS, TUINT16):
- a = AMOVW;
- break;
-
- case CASE(OAS, TINT32):
- case CASE(OAS, TUINT32):
- case CASE(OAS, TPTR32):
- a = AMOVL;
- break;
-
- case CASE(OAS, TINT64):
- case CASE(OAS, TUINT64):
- case CASE(OAS, TPTR64):
- a = AMOVQ;
- break;
-
- case CASE(OAS, TFLOAT32):
- a = AMOVSS;
- break;
-
- case CASE(OAS, TFLOAT64):
- a = AMOVSD;
- break;
-
- case CASE(OADD, TINT8):
- case CASE(OADD, TUINT8):
- a = AADDB;
- break;
-
- case CASE(OADD, TINT16):
- case CASE(OADD, TUINT16):
- a = AADDW;
- break;
-
- case CASE(OADD, TINT32):
- case CASE(OADD, TUINT32):
- case CASE(OADD, TPTR32):
- a = AADDL;
- break;
-
- case CASE(OADD, TINT64):
- case CASE(OADD, TUINT64):
- case CASE(OADD, TPTR64):
- a = AADDQ;
- break;
-
- case CASE(OADD, TFLOAT32):
- a = AADDSS;
- break;
-
- case CASE(OADD, TFLOAT64):
- a = AADDSD;
- break;
-
- case CASE(OSUB, TINT8):
- case CASE(OSUB, TUINT8):
- a = ASUBB;
- break;
-
- case CASE(OSUB, TINT16):
- case CASE(OSUB, TUINT16):
- a = ASUBW;
- break;
-
- case CASE(OSUB, TINT32):
- case CASE(OSUB, TUINT32):
- case CASE(OSUB, TPTR32):
- a = ASUBL;
- break;
-
- case CASE(OSUB, TINT64):
- case CASE(OSUB, TUINT64):
- case CASE(OSUB, TPTR64):
- a = ASUBQ;
- break;
-
- case CASE(OSUB, TFLOAT32):
- a = ASUBSS;
- break;
-
- case CASE(OSUB, TFLOAT64):
- a = ASUBSD;
- break;
-
- case CASE(OINC, TINT8):
- case CASE(OINC, TUINT8):
- a = AINCB;
- break;
-
- case CASE(OINC, TINT16):
- case CASE(OINC, TUINT16):
- a = AINCW;
- break;
-
- case CASE(OINC, TINT32):
- case CASE(OINC, TUINT32):
- case CASE(OINC, TPTR32):
- a = AINCL;
- break;
-
- case CASE(OINC, TINT64):
- case CASE(OINC, TUINT64):
- case CASE(OINC, TPTR64):
- a = AINCQ;
- break;
-
- case CASE(ODEC, TINT8):
- case CASE(ODEC, TUINT8):
- a = ADECB;
- break;
-
- case CASE(ODEC, TINT16):
- case CASE(ODEC, TUINT16):
- a = ADECW;
- break;
-
- case CASE(ODEC, TINT32):
- case CASE(ODEC, TUINT32):
- case CASE(ODEC, TPTR32):
- a = ADECL;
- break;
-
- case CASE(ODEC, TINT64):
- case CASE(ODEC, TUINT64):
- case CASE(ODEC, TPTR64):
- a = ADECQ;
- break;
-
- case CASE(OMINUS, TINT8):
- case CASE(OMINUS, TUINT8):
- a = ANEGB;
- break;
-
- case CASE(OMINUS, TINT16):
- case CASE(OMINUS, TUINT16):
- a = ANEGW;
- break;
-
- case CASE(OMINUS, TINT32):
- case CASE(OMINUS, TUINT32):
- case CASE(OMINUS, TPTR32):
- a = ANEGL;
- break;
-
- case CASE(OMINUS, TINT64):
- case CASE(OMINUS, TUINT64):
- case CASE(OMINUS, TPTR64):
- a = ANEGQ;
- break;
-
- case CASE(OAND, TINT8):
- case CASE(OAND, TUINT8):
- a = AANDB;
- break;
-
- case CASE(OAND, TINT16):
- case CASE(OAND, TUINT16):
- a = AANDW;
- break;
-
- case CASE(OAND, TINT32):
- case CASE(OAND, TUINT32):
- case CASE(OAND, TPTR32):
- a = AANDL;
- break;
-
- case CASE(OAND, TINT64):
- case CASE(OAND, TUINT64):
- case CASE(OAND, TPTR64):
- a = AANDQ;
- break;
-
- case CASE(OOR, TINT8):
- case CASE(OOR, TUINT8):
- a = AORB;
- break;
-
- case CASE(OOR, TINT16):
- case CASE(OOR, TUINT16):
- a = AORW;
- break;
-
- case CASE(OOR, TINT32):
- case CASE(OOR, TUINT32):
- case CASE(OOR, TPTR32):
- a = AORL;
- break;
-
- case CASE(OOR, TINT64):
- case CASE(OOR, TUINT64):
- case CASE(OOR, TPTR64):
- a = AORQ;
- break;
-
- case CASE(OXOR, TINT8):
- case CASE(OXOR, TUINT8):
- a = AXORB;
- break;
-
- case CASE(OXOR, TINT16):
- case CASE(OXOR, TUINT16):
- a = AXORW;
- break;
-
- case CASE(OXOR, TINT32):
- case CASE(OXOR, TUINT32):
- case CASE(OXOR, TPTR32):
- a = AXORL;
- break;
-
- case CASE(OXOR, TINT64):
- case CASE(OXOR, TUINT64):
- case CASE(OXOR, TPTR64):
- a = AXORQ;
- break;
-
- case CASE(OLSH, TINT8):
- case CASE(OLSH, TUINT8):
- a = ASHLB;
- break;
-
- case CASE(OLSH, TINT16):
- case CASE(OLSH, TUINT16):
- a = ASHLW;
- break;
-
- case CASE(OLSH, TINT32):
- case CASE(OLSH, TUINT32):
- case CASE(OLSH, TPTR32):
- a = ASHLL;
- break;
-
- case CASE(OLSH, TINT64):
- case CASE(OLSH, TUINT64):
- case CASE(OLSH, TPTR64):
- a = ASHLQ;
- break;
-
- case CASE(ORSH, TUINT8):
- a = ASHRB;
- break;
-
- case CASE(ORSH, TUINT16):
- a = ASHRW;
- break;
-
- case CASE(ORSH, TUINT32):
- case CASE(ORSH, TPTR32):
- a = ASHRL;
- break;
-
- case CASE(ORSH, TUINT64):
- case CASE(ORSH, TPTR64):
- a = ASHRQ;
- break;
-
- case CASE(ORSH, TINT8):
- a = ASARB;
- break;
-
- case CASE(ORSH, TINT16):
- a = ASARW;
- break;
-
- case CASE(ORSH, TINT32):
- a = ASARL;
- break;
-
- case CASE(ORSH, TINT64):
- a = ASARQ;
- break;
-
- case CASE(ORRC, TINT8):
- case CASE(ORRC, TUINT8):
- a = ARCRB;
- break;
-
- case CASE(ORRC, TINT16):
- case CASE(ORRC, TUINT16):
- a = ARCRW;
- break;
-
- case CASE(ORRC, TINT32):
- case CASE(ORRC, TUINT32):
- a = ARCRL;
- break;
-
- case CASE(ORRC, TINT64):
- case CASE(ORRC, TUINT64):
- a = ARCRQ;
- break;
-
- case CASE(OHMUL, TINT8):
- case CASE(OMUL, TINT8):
- case CASE(OMUL, TUINT8):
- a = AIMULB;
- break;
-
- case CASE(OHMUL, TINT16):
- case CASE(OMUL, TINT16):
- case CASE(OMUL, TUINT16):
- a = AIMULW;
- break;
-
- case CASE(OHMUL, TINT32):
- case CASE(OMUL, TINT32):
- case CASE(OMUL, TUINT32):
- case CASE(OMUL, TPTR32):
- a = AIMULL;
- break;
-
- case CASE(OHMUL, TINT64):
- case CASE(OMUL, TINT64):
- case CASE(OMUL, TUINT64):
- case CASE(OMUL, TPTR64):
- a = AIMULQ;
- break;
-
- case CASE(OHMUL, TUINT8):
- a = AMULB;
- break;
-
- case CASE(OHMUL, TUINT16):
- a = AMULW;
- break;
-
- case CASE(OHMUL, TUINT32):
- case CASE(OHMUL, TPTR32):
- a = AMULL;
- break;
-
- case CASE(OHMUL, TUINT64):
- case CASE(OHMUL, TPTR64):
- a = AMULQ;
- break;
-
- case CASE(OMUL, TFLOAT32):
- a = AMULSS;
- break;
-
- case CASE(OMUL, TFLOAT64):
- a = AMULSD;
- break;
-
- case CASE(ODIV, TINT8):
- case CASE(OMOD, TINT8):
- a = AIDIVB;
- break;
-
- case CASE(ODIV, TUINT8):
- case CASE(OMOD, TUINT8):
- a = ADIVB;
- break;
-
- case CASE(ODIV, TINT16):
- case CASE(OMOD, TINT16):
- a = AIDIVW;
- break;
-
- case CASE(ODIV, TUINT16):
- case CASE(OMOD, TUINT16):
- a = ADIVW;
- break;
-
- case CASE(ODIV, TINT32):
- case CASE(OMOD, TINT32):
- a = AIDIVL;
- break;
-
- case CASE(ODIV, TUINT32):
- case CASE(ODIV, TPTR32):
- case CASE(OMOD, TUINT32):
- case CASE(OMOD, TPTR32):
- a = ADIVL;
- break;
-
- case CASE(ODIV, TINT64):
- case CASE(OMOD, TINT64):
- a = AIDIVQ;
- break;
-
- case CASE(ODIV, TUINT64):
- case CASE(ODIV, TPTR64):
- case CASE(OMOD, TUINT64):
- case CASE(OMOD, TPTR64):
- a = ADIVQ;
- break;
-
- case CASE(OEXTEND, TINT16):
- a = ACWD;
- break;
-
- case CASE(OEXTEND, TINT32):
- a = ACDQ;
- break;
-
- case CASE(OEXTEND, TINT64):
- a = ACQO;
- break;
-
- case CASE(ODIV, TFLOAT32):
- a = ADIVSS;
- break;
-
- case CASE(ODIV, TFLOAT64):
- a = ADIVSD;
- break;
-
- }
- return a;
-}
-
-enum
-{
- ODynam = 1<<0,
- OAddable = 1<<1,
-};
-
-static Node clean[20];
-static int cleani = 0;
-
-int
-xgen(Node *n, Node *a, int o)
-{
- regalloc(a, types[tptr], N);
-
- if(o & ODynam)
- if(n->addable)
- if(n->op != OINDREG)
- if(n->op != OREGISTER)
- return 1;
-
- agen(n, a);
- return 0;
-}
-
-void
-sudoclean(void)
-{
- if(clean[cleani-1].op != OEMPTY)
- regfree(&clean[cleani-1]);
- if(clean[cleani-2].op != OEMPTY)
- regfree(&clean[cleani-2]);
- cleani -= 2;
-}
-
-/*
- * 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)
-{
- int o, i, w;
- int oary[10];
- int64 v;
- Node n1, n2, n3, n4, *nn, *l, *r;
- Node *reg, *reg1;
- Prog *p1;
- Type *t;
-
- if(n->type == T)
- return 0;
-
- switch(n->op) {
- case OLITERAL:
- if(n->val.ctype != CTINT)
- break;
- v = mpgetfix(n->val.u.xval);
- if(v >= 32000 || v <= -32000)
- break;
- goto lit;
-
- case ODOT:
- case ODOTPTR:
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
- goto odot;
-
- case OINDEX:
- if(n->left->type->etype == TSTRING)
- return 0;
- goto oindex;
- }
- return 0;
-
-lit:
- switch(as) {
- default:
- return 0;
- case AADDB: case AADDW: case AADDL: case AADDQ:
- case ASUBB: case ASUBW: case ASUBL: case ASUBQ:
- case AANDB: case AANDW: case AANDL: case AANDQ:
- case AORB: case AORW: case AORL: case AORQ:
- case AXORB: case AXORW: case AXORL: case AXORQ:
- case AINCB: case AINCW: case AINCL: case AINCQ:
- case ADECB: case ADECW: case ADECL: case ADECQ:
- case AMOVB: case AMOVW: case AMOVL: case AMOVQ:
- break;
- }
-
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
- naddr(n, a, 1);
- goto yes;
-
-odot:
- o = dotoffset(n, oary, &nn);
- if(nn == N)
- goto no;
-
- if(nn->addable && o == 1 && oary[0] >= 0) {
- // directly addressable set of DOTs
- n1 = *nn;
- n1.type = n->type;
- n1.xoffset += oary[0];
- naddr(&n1, a, 1);
- goto yes;
- }
-
- regalloc(reg, types[tptr], N);
- n1 = *reg;
- n1.op = OINDREG;
- if(oary[0] >= 0) {
- agen(nn, reg);
- n1.xoffset = oary[0];
- } else {
- cgen(nn, reg);
- n1.xoffset = -(oary[0]+1);
- }
-
- for(i=1; i<o; i++) {
- if(oary[i] >= 0)
- fatal("cant happen");
- gins(AMOVQ, &n1, reg);
- n1.xoffset = -(oary[i]+1);
- }
-
- a->type = D_NONE;
- a->index = D_NONE;
- naddr(&n1, a, 1);
- goto yes;
-
-oindex:
- l = n->left;
- r = n->right;
- if(l->ullman >= UINF && r->ullman >= UINF)
- return 0;
-
- // set o to type of array
- o = 0;
- if(isptr[l->type->etype])
- fatal("ptr ary");
- if(l->type->etype != TARRAY)
- fatal("not ary");
- if(l->type->bound < 0)
- o |= ODynam;
-
- w = n->type->width;
- if(isconst(r, CTINT))
- goto oindex_const;
-
- switch(w) {
- default:
- return 0;
- case 1:
- case 2:
- case 4:
- case 8:
- break;
- }
-
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
-
- // load the array (reg)
- if(l->ullman > r->ullman) {
- if(xgen(l, reg, o))
- o |= OAddable;
- }
-
- // load the index (reg1)
- t = types[TUINT64];
- if(issigned[r->type->etype])
- t = types[TINT64];
- regalloc(reg1, t, N);
- regalloc(&n3, r->type, reg1);
- cgen(r, &n3);
- gmove(&n3, reg1);
- regfree(&n3);
-
- // load the array (reg)
- if(l->ullman <= r->ullman) {
- if(xgen(l, reg, o))
- o |= OAddable;
- }
-
- if(!(o & ODynam) && l->type->width >= unmappedzero && l->op == OIND) {
- // cannot rely on page protections to
- // catch array ptr == 0, so dereference.
- n2 = *reg;
- n2.xoffset = 0;
- n2.op = OINDREG;
- n2.type = types[TUINT8];
- gins(ATESTB, nodintconst(0), &n2);
- }
-
- // check bounds
- if(!debug['B'] && !n->etype) {
- // check bounds
- n4.op = OXXX;
- t = types[TUINT32];
- if(o & ODynam) {
- if(o & OAddable) {
- n2 = *l;
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- if(is64(r->type)) {
- t = types[TUINT64];
- regalloc(&n4, t, N);
- gmove(&n2, &n4);
- n2 = n4;
- }
- } else {
- n2 = *reg;
- n2.xoffset = Array_nel;
- n2.op = OINDREG;
- n2.type = types[TUINT32];
- if(is64(r->type)) {
- t = types[TUINT64];
- regalloc(&n4, t, N);
- gmove(&n2, &n4);
- n2 = n4;
- }
- }
- } else {
- if(is64(r->type))
- t = types[TUINT64];
- nodconst(&n2, types[TUINT64], l->type->bound);
- }
- gins(optoas(OCMP, t), reg1, &n2);
- p1 = gbranch(optoas(OLT, t), T);
- if(n4.op != OXXX)
- regfree(&n4);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- if(o & ODynam) {
- if(o & OAddable) {
- n2 = *l;
- n2.xoffset += Array_array;
- n2.type = types[tptr];
- gmove(&n2, reg);
- } else {
- n2 = *reg;
- n2.op = OINDREG;
- n2.xoffset = Array_array;
- n2.type = types[tptr];
- gmove(&n2, reg);
- }
- }
-
- if(o & OAddable) {
- naddr(reg1, a, 1);
- a->offset = 0;
- a->scale = w;
- a->index = a->type;
- a->type = reg->val.u.reg + D_INDIR;
- } else {
- naddr(reg1, a, 1);
- a->offset = 0;
- a->scale = w;
- a->index = a->type;
- a->type = reg->val.u.reg + D_INDIR;
- }
-
- goto yes;
-
-oindex_const:
- // index is constant
- // can check statically and
- // can multiply by width statically
-
- v = mpgetfix(r->val.u.xval);
-
- if(sudoaddable(as, l, a))
- goto oindex_const_sudo;
-
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
-
- regalloc(reg, types[tptr], N);
- agen(l, reg);
-
- if(o & ODynam) {
- if(!debug['B'] && !n->etype) {
- n1 = *reg;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- nodconst(&n2, types[TUINT64], v);
- gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- n1 = *reg;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, reg);
-
- }
-
- n2 = *reg;
- n2.op = OINDREG;
- n2.xoffset = v*w;
- a->type = D_NONE;
- a->index = D_NONE;
- naddr(&n2, a, 1);
- goto yes;
-
-oindex_const_sudo:
- if((o & ODynam) == 0) {
- // array indexed by a constant
- a->offset += v*w;
- goto yes;
- }
-
- // slice indexed by a constant
- if(!debug['B'] && !n->etype) {
- a->offset += Array_nel;
- nodconst(&n2, types[TUINT64], v);
- p1 = gins(optoas(OCMP, types[TUINT32]), N, &n2);
- p1->from = *a;
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- ginscall(panicindex, 0);
- patch(p1, pc);
- a->offset -= Array_nel;
- }
-
- a->offset += Array_array;
- reg = &clean[cleani-1];
- if(reg->op == OEMPTY)
- regalloc(reg, types[tptr], N);
-
- p1 = gins(AMOVQ, N, reg);
- p1->from = *a;
-
- n2 = *reg;
- n2.op = OINDREG;
- n2.xoffset = v*w;
- a->type = D_NONE;
- a->index = D_NONE;
- naddr(&n2, a, 1);
- goto yes;
-
-yes:
- return 1;
-
-no:
- sudoclean();
- return 0;
-}
diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c
deleted file mode 100644
index c8077c97a..000000000
--- a/src/cmd/6g/list.c
+++ /dev/null
@@ -1,359 +0,0 @@
-// Derived from 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.
-
-#include "gg.h"
-
-static int sconsize;
-void
-listinit(void)
-{
-
- fmtinstall('A', Aconv); // as
- fmtinstall('P', Pconv); // Prog*
- fmtinstall('D', Dconv); // Addr*
- fmtinstall('R', Rconv); // reg
- fmtinstall('Y', Yconv); // sconst
-}
-
-int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Prog *p;
- char scale[40];
-
- p = va_arg(fp->args, Prog*);
- sconsize = 8;
- scale[0] = '\0';
- if(p->from.scale != 0 && (p->as == AGLOBL || p->as == ATEXT))
- snprint(scale, sizeof scale, "%d,", p->from.scale);
- switch(p->as) {
- default:
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%D",
- p->loc, p->lineno, p->as, &p->from, scale, &p->to);
- break;
-
- case ADATA:
- sconsize = p->from.scale;
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
- p->loc, p->lineno, p->as, &p->from, sconsize, &p->to);
- break;
-
- case ATEXT:
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%lD",
- p->loc, p->lineno, p->as, &p->from, scale, &p->to);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Addr *a;
- int i;
- uint32 d1, d2;
-
- a = va_arg(fp->args, Addr*);
- i = a->type;
- if(i >= D_INDIR) {
- if(a->offset)
- snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR);
- else
- snprint(str, sizeof(str), "(%R)", i-D_INDIR);
- goto brk;
- }
- switch(i) {
-
- default:
- if(a->offset)
- snprint(str, sizeof(str), "$%lld,%R", a->offset, i);
- else
- snprint(str, sizeof(str), "%R", i);
- break;
-
- case D_NONE:
- str[0] = 0;
- break;
-
- case D_BRANCH:
- if(a->branch == nil)
- snprint(str, sizeof(str), "<nil>");
- else
- snprint(str, sizeof(str), "%d", a->branch->loc);
- break;
-
- case D_EXTERN:
- snprint(str, sizeof(str), "%S+%lld(SB)", a->sym, a->offset);
- break;
-
- case D_STATIC:
- snprint(str, sizeof(str), "%S<>+%lld(SB)", a->sym, a->offset);
- break;
-
- case D_AUTO:
- snprint(str, sizeof(str), "%S+%lld(SP)", a->sym, a->offset);
- break;
-
- case D_PARAM:
- snprint(str, sizeof(str), "%S+%lld(FP)", a->sym, a->offset);
- break;
-
- case D_CONST:
- if(fp->flags & FmtLong) {
- d1 = a->offset & 0xffffffffLL;
- d2 = (a->offset>>32) & 0xffffffffLL;
- snprint(str, sizeof(str), "$%ud-%ud", (ulong)d1, (ulong)d2);
- break;
- }
- snprint(str, sizeof(str), "$%lld", a->offset);
- break;
-
- case D_FCONST:
- snprint(str, sizeof(str), "$(%.17e)", a->dval);
- break;
-
- case D_SCONST:
- snprint(str, sizeof(str), "$\"%Y\"", a->sval);
- break;
-
- case D_ADDR:
- a->type = a->index;
- a->index = D_NONE;
- snprint(str, sizeof(str), "$%D", a);
- a->index = a->type;
- a->type = D_ADDR;
- goto conv;
- }
-brk:
- if(a->index != D_NONE) {
- snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale);
- strcat(str, s);
- }
-conv:
- return fmtstrcpy(fp, str);
-}
-
-static char* regstr[] =
-{
- "AL", /* [D_AL] */
- "CL",
- "DL",
- "BL",
- "SPB",
- "BPB",
- "SIB",
- "DIB",
- "R8B",
- "R9B",
- "R10B",
- "R11B",
- "R12B",
- "R13B",
- "R14B",
- "R15B",
-
- "AX", /* [D_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
- "R8",
- "R9",
- "R10",
- "R11",
- "R12",
- "R13",
- "R14",
- "R15",
-
- "AH",
- "CH",
- "DH",
- "BH",
-
- "F0", /* [D_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "M0",
- "M1",
- "M2",
- "M3",
- "M4",
- "M5",
- "M6",
- "M7",
-
- "X0",
- "X1",
- "X2",
- "X3",
- "X4",
- "X5",
- "X6",
- "X7",
- "X8",
- "X9",
- "X10",
- "X11",
- "X12",
- "X13",
- "X14",
- "X15",
-
- "CS", /* [D_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
-
- "CR0", /* [D_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
- "CR8",
- "CR9",
- "CR10",
- "CR11",
- "CR12",
- "CR13",
- "CR14",
- "CR15",
-
- "DR0", /* [D_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [D_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "NONE", /* [D_NONE] */
-};
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) {
- snprint(str, sizeof(str), "BAD_R(%d)", r);
- return fmtstrcpy(fp, str);
- }
- return fmtstrcpy(fp, regstr[r]);
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-
-int
-Yconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sconsize; i++) {
- c = a[i] & 0xff;
- if((c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9')) {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- 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/cmd/6g/opt.h b/src/cmd/6g/opt.h
deleted file mode 100644
index 9a8866b8d..000000000
--- a/src/cmd/6g/opt.h
+++ /dev/null
@@ -1,166 +0,0 @@
-// 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.
-
-#define Z N
-#define Adr Addr
-
-#define D_HI D_NONE
-#define D_LO D_NONE
-
-#define isregtype(t) ((t)>= D_AX && (t)<=D_R15)
-
-#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;
-
-struct Reg
-{
-
- Bits set;
- Bits use1;
- Bits use2;
-
- Bits refbehind;
- Bits refahead;
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- int32 regu; // register used bitmap
- int32 rpo; // reverse post ordering
- int32 active;
-
- uint16 loop; // x5 for every loop
- uchar refset; // diagnostic generated
-
- 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 exregoffset; // not set
-EXTERN int32 exfregoffset; // not set
-EXTERN Reg* firstr;
-EXTERN Reg* lastr;
-EXTERN Reg zreg;
-EXTERN Reg* freer;
-EXTERN Reg** rpo2r;
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-EXTERN int32 regbits;
-EXTERN int32 exregbits;
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-EXTERN Bits ovar;
-EXTERN int change;
-EXTERN int32 maxnr;
-EXTERN int32* idom;
-
-EXTERN struct
-{
- int32 ncvtreg;
- int32 nspill;
- int32 nreload;
- int32 ndelmov;
- int32 nvar;
- int32 naddr;
-} ostats;
-
-/*
- * reg.c
- */
-Reg* rega(void);
-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 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(Adr*, int);
-void dumpone(Reg*);
-void dumpit(char*, Reg*);
-int noreturn(Prog *p);
-
-/*
- * peep.c
- */
-void peep(void);
-void excise(Reg*);
-Reg* uniqp(Reg*);
-Reg* uniqs(Reg*);
-int regtyp(Adr*);
-int anyvar(Adr*);
-int subprop(Reg*);
-int copyprop(Reg*);
-int copy1(Adr*, Adr*, Reg*, int);
-int copyu(Prog*, Adr*, Adr*);
-
-int copyas(Adr*, Adr*);
-int copyau(Adr*, Adr*);
-int copysub(Adr*, Adr*, Adr*, int);
-int copysub1(Prog*, Adr*, Adr*, int);
-
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
deleted file mode 100644
index 4432203f2..000000000
--- a/src/cmd/6g/peep.c
+++ /dev/null
@@ -1,999 +0,0 @@
-// 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 "gg.h"
-#include "opt.h"
-
-static void conprop(Reg *r);
-
-// do we need the carry bit
-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;
- p->reg = r2;
-
- 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;
- }
- }
-
- // constant propagation
- // find MOV $con,R followed by
- // another MOV $con,R without
- // setting R in the interim
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case ALEAL:
- case ALEAQ:
- if(regtyp(&p->to))
- if(p->from.sym != S)
- conprop(r);
- break;
-
- case AMOVB:
- case AMOVW:
- case AMOVL:
- case AMOVQ:
- case AMOVSS:
- case AMOVSD:
- if(regtyp(&p->to))
- if(p->from.type == D_CONST)
- conprop(r);
- break;
- }
- }
-
-loop1:
- if(debug['P'] && debug['v'])
- dumpit("loop1", firstr);
-
- 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;
- break;
- }
- 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;
- }
- 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;
- break;
- }
- 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;
- }
- break;
- }
- }
- if(t)
- goto loop1;
-}
-
-void
-excise(Reg *r)
-{
- Prog *p;
-
- p = r->prog;
- if(debug['P'] && debug['v'])
- print("%P ===delete===\n", p);
-
- p->as = ANOP;
- p->from = zprog.from;
- p->to = zprog.to;
-
- ostats.ndelmov++;
-}
-
-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(Adr *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;
- Adr *v1, *v2;
- Reg *r;
- int t;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case ACALL:
- return 0;
-
- case AIMULL:
- case AIMULQ:
- case AIMULW:
- if(p->to.type != D_NONE)
- break;
-
- 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 ARCLB:
- case ARCLL:
- case ARCLQ:
- case ARCLW:
- case ARCRB:
- case ARCRL:
- case ARCRQ:
- case ARCRW:
- 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:
-
- case AREP:
- case AREPN:
-
- case ACWD:
- case ACDQ:
- case ACQO:
-
- case ASTOSB:
- case ASTOSL:
- case ASTOSQ:
- case AMOVSB:
- case AMOVSL:
- case AMOVSQ:
- 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;
- Adr *v1, *v2;
- Reg *r;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Adr *v1, Adr *v2, Reg *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, A);
- switch(t) {
- case 2: /* rar, cant split */
- if(debug['P'])
- print("; %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, Adr *v, Adr *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 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 ARCLB:
- case ARCLL:
- case ARCLQ:
- case ARCLW:
- case ARCRB:
- case ARCRL:
- case ARCRQ:
- case ARCRW:
- 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 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(REGEXT && v->type <= REGEXT && v->type > exregoffset)
- return 2;
- 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(Adr *a, Adr *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(Adr *a, Adr *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(Adr *a, Adr *v, Adr *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;
-}
-
-static void
-conprop(Reg *r0)
-{
- Reg *r;
- Prog *p, *p0;
- int t;
- Adr *v0;
-
- p0 = r0->prog;
- v0 = &p0->to;
- r = r0;
-
-loop:
- r = uniqs(r);
- if(r == R || r == r0)
- return;
- if(uniqp(r) == R)
- return;
-
- p = r->prog;
- t = copyu(p, v0, A);
- switch(t) {
- case 0: // miss
- case 1: // use
- goto loop;
-
- case 2: // rar
- case 4: // use and set
- break;
-
- case 3: // set
- if(p->as == p0->as)
- if(p->from.type == p0->from.type)
- if(p->from.sym == p0->from.sym)
- if(p->from.offset == p0->from.offset)
- if(p->from.scale == p0->from.scale)
- if(p->from.dval == p0->from.dval)
- if(p->from.index == p0->from.index) {
- excise(r);
- t++;
- goto loop;
- }
- break;
- }
-}
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
deleted file mode 100644
index 4d4263047..000000000
--- a/src/cmd/6g/reg.c
+++ /dev/null
@@ -1,1690 +0,0 @@
-// 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 "gg.h"
-#undef EXTERN
-#define EXTERN
-#include "opt.h"
-
-#define NREGVAR 32 /* 16 general + 16 floating */
-#define REGBITS ((uint32)0xffffffff)
-#define P2R(p) (Reg*)(p->reg)
-
-static int first = 1;
-
-Reg*
-rega(void)
-{
- Reg *r;
-
- r = freer;
- if(r == R) {
- r = mal(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;
-}
-
-static void
-setoutvar(void)
-{
- Type *t;
- Node *n;
- Addr a;
- Iter save;
- Bits bit;
- int z;
-
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- n = nodarg(t, 1);
- a = zprog.from;
- naddr(n, &a, 0);
- bit = mkvar(R, &a);
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
- t = structnext(&save);
- }
-//if(bany(b))
-//print("ovars = %Q\n", &ovar);
-}
-
-static void
-setaddrs(Bits bit)
-{
- int i, n;
- Var *v;
- Sym *s;
-
- while(bany(&bit)) {
- // convert each bit to a variable
- i = bnum(bit);
- s = var[i].sym;
- n = var[i].name;
- bit.b[i/32] &= ~(1L<<(i%32));
-
- // disable all pieces of that variable
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->sym == s && v->name == n)
- v->addr = 2;
- }
- }
-}
-
-static char* regname[] = {
- ".AX",
- ".CX",
- ".DX",
- ".BX",
- ".SP",
- ".BP",
- ".SI",
- ".DI",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".X0",
- ".X1",
- ".X2",
- ".X3",
- ".X4",
- ".X5",
- ".X6",
- ".X7",
- ".X8",
- ".X9",
- ".X10",
- ".X11",
- ".X12",
- ".X13",
- ".X14",
- ".X15",
-};
-
-void
-regopt(Prog *firstp)
-{
- Reg *r, *r1;
- Prog *p;
- int i, z, nr;
- uint32 vreg;
- Bits bit;
-
- if(first) {
- fmtinstall('Q', Qconv);
- exregoffset = D_R13; // R14,R15 are external
- first = 0;
- }
-
- // count instructions
- nr = 0;
- for(p=firstp; p!=P; p=p->link)
- nr++;
- // if too big dont bother
- if(nr >= 10000) {
-// print("********** %S is too big (%d)\n", curfn->nname->sym, nr);
- return;
- }
-
- r1 = R;
- firstr = R;
- lastr = R;
- nvar = 0;
-
- /*
- * 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++)
- var[i].sym = lookup(regname[i]);
-
- regbits = RtoB(D_SP);
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- ovar.b[z] = 0;
- }
-
- // build list of return variables
- setoutvar();
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- nr = 0;
- for(p=firstp; p!=P; p=p->link) {
- switch(p->as) {
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- continue;
- }
- r = rega();
- nr++;
- if(firstr == R) {
- firstr = r;
- lastr = r;
- } else {
- lastr->link = r;
- r->p1 = lastr;
- lastr->s1 = r;
- lastr = r;
- }
- r->prog = p;
- p->reg = r;
-
- 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:
- setaddrs(bit);
- break;
-
- /*
- * left side read
- */
- default:
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
- break;
-
- /*
- * left side read+write
- */
- case AXCHGB:
- case AXCHGW:
- case AXCHGL:
- case AXCHGQ:
- for(z=0; z<BITS; z++) {
- r->use1.b[z] |= bit.b[z];
- r->set.b[z] |= bit.b[z];
- }
- break;
- }
-
- bit = mkvar(r, &p->to);
- if(bany(&bit))
- switch(p->as) {
- default:
- yyerror("reg: unknown op: %A", p->as);
- break;
-
- /*
- * right side read
- */
- case ACMPB:
- case ACMPL:
- case ACMPQ:
- case ACMPW:
- case ACOMISS:
- case ACOMISD:
- case AUCOMISS:
- case AUCOMISD:
- case ATESTB:
- case ATESTL:
- case ATESTQ:
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- break;
-
- /*
- * right side write
- */
- case ALEAQ:
- case ANOP:
- case AMOVL:
- case AMOVQ:
- case AMOVB:
- case AMOVW:
- case AMOVBLSX:
- case AMOVBLZX:
- case AMOVBWSX:
- case AMOVBWZX:
- case AMOVBQSX:
- case AMOVBQZX:
- case AMOVLQSX:
- case AMOVLQZX:
- case AMOVWLSX:
- case AMOVWLZX:
- case AMOVWQSX:
- case AMOVWQZX:
- case APOPQ:
-
- 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 AINCB:
- case AINCL:
- case AINCQ:
- case AINCW:
- case ADECB:
- case ADECL:
- case ADECQ:
- case ADECW:
-
- 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 ARCLB:
- case ARCLL:
- case ARCLQ:
- case ARCLW:
- case ARCRB:
- case ARCRL:
- case ARCRQ:
- case ARCRW:
- 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 ANEGB:
- case ANEGW:
- case ANEGL:
- case ANEGQ:
- case ANOTL:
- case ANOTQ:
- case AADCL:
- case AADCQ:
- case ASBBL:
- case ASBBQ:
-
- case ASETCC:
- case ASETCS:
- case ASETEQ:
- case ASETGE:
- case ASETGT:
- case ASETHI:
- case ASETLE:
- case ASETLS:
- case ASETLT:
- case ASETMI:
- case ASETNE:
- case ASETOC:
- case ASETOS:
- case ASETPC:
- case ASETPL:
- case ASETPS:
-
- case AXCHGB:
- case AXCHGW:
- case AXCHGL:
- case AXCHGQ:
-
- 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:
- setaddrs(bit);
- break;
- }
-
- switch(p->as) {
- case AIMULL:
- case AIMULQ:
- case AIMULW:
- if(p->to.type != D_NONE)
- break;
-
- case AIDIVL:
- case AIDIVW:
- case AIDIVQ:
- case ADIVL:
- case ADIVW:
- case ADIVQ:
- case AMULL:
- case AMULW:
- case AMULQ:
- r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
- r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DX);
- break;
-
- case AIDIVB:
- case AIMULB:
- case ADIVB:
- case AMULB:
- r->set.b[0] |= RtoB(D_AX);
- r->use1.b[0] |= RtoB(D_AX);
- break;
-
- case ACWD:
- r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
- r->use1.b[0] |= RtoB(D_AX);
- break;
-
- case ACDQ:
- r->set.b[0] |= RtoB(D_DX);
- r->use1.b[0] |= RtoB(D_AX);
- break;
-
- case AREP:
- case AREPN:
- case ALOOP:
- case ALOOPEQ:
- case ALOOPNE:
- r->set.b[0] |= RtoB(D_CX);
- r->use1.b[0] |= RtoB(D_CX);
- break;
-
- case AMOVSB:
- case AMOVSL:
- case AMOVSQ:
- case AMOVSW:
- case ACMPSB:
- case ACMPSL:
- case ACMPSQ:
- case ACMPSW:
- r->set.b[0] |= RtoB(D_SI) | RtoB(D_DI);
- r->use1.b[0] |= RtoB(D_SI) | RtoB(D_DI);
- break;
-
- case ASTOSB:
- case ASTOSL:
- case ASTOSQ:
- case ASTOSW:
- case ASCASB:
- case ASCASL:
- case ASCASQ:
- case ASCASW:
- r->set.b[0] |= RtoB(D_DI);
- r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DI);
- break;
-
- case AINSB:
- case AINSL:
- case AINSW:
- r->set.b[0] |= RtoB(D_DX) | RtoB(D_DI);
- r->use1.b[0] |= RtoB(D_DI);
- break;
-
- case AOUTSB:
- case AOUTSL:
- case AOUTSW:
- r->set.b[0] |= RtoB(D_DI);
- r->use1.b[0] |= RtoB(D_DX) | RtoB(D_DI);
- break;
- }
- }
- if(firstr == R)
- return;
-
- 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];
- }
-
-// print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n",
-// i, v->addr, v->etype, v->width, v->sym, v->offset);
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass1", firstr);
-
- /*
- * 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) {
- if(p->to.branch == P)
- fatal("pnil %P", p);
- r1 = p->to.branch->reg;
- if(r1 == R)
- fatal("rnil %P", p);
- if(r1 == r) {
- //fatal("ref to self %P", p);
- continue;
- }
- r->s2 = r1;
- r->p2link = r1->p2;
- r1->p2 = r;
- }
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass2", firstr);
-
- /*
- * pass 2.5
- * find looping structure
- */
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- change = 0;
- loopit(firstr, nr);
-
- if(debug['R'] && debug['v'])
- dumpit("pass2.5", firstr);
-
- /*
- * 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;
-
- if(debug['R'] && debug['v'])
- dumpit("pass3", firstr);
-
- /*
- * 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;
-
- if(debug['R'] && debug['v'])
- dumpit("pass4", firstr);
-
- /*
- * pass 4.5
- * move register pseudo-variables into regu.
- */
- for(r = firstr; r != R; r = r->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;
- }
-
- /*
- * 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->refset) {
- // should never happen - all variables are preset
- if(debug['w'])
- print("%L: used and not set: %Q\n", r->prog->lineno, bit);
- r->refset = 1;
- }
- }
- 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) && !r->refset) {
- if(debug['w'])
- print("%L: set and not used: %Q\n", r->prog->lineno, bit);
- r->refset = 1;
- 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;
- paint1(r, i);
- bit.b[i/32] &= ~(1L<<(i%32));
- 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);
-
- /*
- * 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(rgp->regno != 0)
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- rgp++;
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass6", firstr);
-
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P']) {
- peep();
- }
-
- /*
- * eliminate nops
- * free aux structures
- */
- 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.branch != P && p->to.branch->as == ANOP)
- p->to.branch = p->to.branch->link;
- }
-
- if(r1 != R) {
- r1->link = freer;
- freer = firstr;
- }
-
- if(debug['R']) {
- if(ostats.ncvtreg ||
- ostats.nspill ||
- ostats.nreload ||
- ostats.ndelmov ||
- ostats.nvar ||
- ostats.naddr ||
- 0)
- print("\nstats\n");
-
- if(ostats.ncvtreg)
- print(" %4d cvtreg\n", ostats.ncvtreg);
- if(ostats.nspill)
- print(" %4d spill\n", ostats.nspill);
- if(ostats.nreload)
- print(" %4d reload\n", ostats.nreload);
- if(ostats.ndelmov)
- print(" %4d delmov\n", ostats.ndelmov);
- if(ostats.nvar)
- print(" %4d delmov\n", ostats.nvar);
- if(ostats.naddr)
- print(" %4d delmov\n", ostats.naddr);
-
- memset(&ostats, 0, sizeof(ostats));
- }
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Adr *a;
- Var *v;
-
- p1 = mal(sizeof(*p1));
- clearp(p1);
- p1->loc = 9999;
-
- 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;
- a->gotype = v->gotype;
- a->node = v->node;
-
- // need to clean this up with wptr and
- // some of the defaults
- p1->as = AMOVL;
- switch(v->etype) {
- default:
- fatal("unknown type\n");
- case TINT8:
- case TUINT8:
- case TBOOL:
- p1->as = AMOVB;
- break;
- case TINT16:
- case TUINT16:
- p1->as = AMOVW;
- break;
- case TINT64:
- case TUINT64:
- case TUINTPTR:
- case TPTR64:
- p1->as = AMOVQ;
- break;
- case TFLOAT32:
- p1->as = AMOVSS;
- break;
- case TFLOAT64:
- p1->as = AMOVSD;
- break;
- case TINT:
- case TUINT:
- case TINT32:
- case TUINT32:
- case TPTR32:
- break;
- }
-
- p1->from.type = rn;
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = rn;
- if(v->etype == TUINT8)
- p1->as = AMOVB;
- if(v->etype == TUINT16)
- p1->as = AMOVW;
- }
- if(debug['R'] && debug['v'])
- print("%P ===add=== %P\n", p, p1);
- ostats.nspill++;
-}
-
-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;
-}
-
-static int
-overlap(int32 o1, int w1, int32 o2, int w2)
-{
- int32 t1, t2;
-
- t1 = o1+w1;
- t2 = o2+w2;
-
- if(!(t1 > o2 && t2 > o1))
- return 0;
-
- return 1;
-}
-
-Bits
-mkvar(Reg *r, Adr *a)
-{
- Var *v;
- int i, t, n, et, z, w, flag;
- uint32 regu;
- int32 o;
- Bits bit;
- Sym *s;
-
- /*
- * mark registers used
- */
- t = a->type;
- if(t == D_NONE)
- goto none;
-
- if(r != R)
- r->use1.b[0] |= doregbits(a->index);
-
- switch(t) {
- default:
- regu = doregbits(t);
- if(regu == 0)
- goto none;
- bit = zbits;
- bit.b[0] = regu;
- return bit;
-
- case D_ADDR:
- a->type = a->index;
- bit = mkvar(r, a);
- setaddrs(bit);
- a->type = t;
- ostats.naddr++;
- goto none;
-
- case D_EXTERN:
- case D_STATIC:
- case D_PARAM:
- case D_AUTO:
- n = t;
- break;
- }
- s = a->sym;
- if(s == S)
- goto none;
- if(s->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- w = a->width;
-
- flag = 0;
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->sym == s && v->name == n) {
- if(v->offset == o)
- if(v->etype == et)
- if(v->width == w)
- return blsh(i);
-
- // if they overlaps, disable both
- if(overlap(v->offset, v->width, o, w)) {
-// print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
- v->addr = 1;
- flag = 1;
- }
- }
- }
- if(a->pun) {
-// print("disable pun %s\n", s->name);
- flag = 1;
-
- }
- switch(et) {
- case 0:
- case TFUNC:
- goto none;
- }
-
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
- fatal("variable not optimized: %D", a);
- goto none;
- }
-
- i = nvar;
- nvar++;
- v = var+i;
- v->sym = s;
- v->offset = o;
- v->name = n;
- v->gotype = a->gotype;
- v->etype = et;
- v->width = w;
- v->addr = flag; // funny punning
- v->node = a->node;
-
- if(debug['R'])
- print("bit=%2d et=%2d w=%d %S %D\n", i, et, w, s, a);
- ostats.nvar++;
-
- 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];
-
- 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:
- if(noreturn(r1->prog))
- break;
- 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] | 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->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("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 = mal(nr * sizeof(Reg*));
- idom = mal(nr * sizeof(int32));
- maxnr = nr;
- }
-
- d = postorder(r, rpo2r, 0);
- if(d > nr)
- fatal("too many reg nodes %d %d", d, nr);
- 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:
- 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;
- 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;
- }
- for(;;) {
- r->act.b[z] |= bb;
-
- if(r->use1.b[z] & bb) {
- change += CREF * r->loop;
- }
-
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->loop;
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->loop;
- }
-
- 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;
- 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->prog, &v, A);
- 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->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'] && 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 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Adr *a, int rn)
-{
-
- a->sym = 0;
- a->offset = 0;
- a->type = rn;
-
- ostats.ncvtreg++;
-}
-
-int32
-RtoB(int r)
-{
-
- if(r < D_AX || r > D_R15)
- return 0;
- return 1L << (r-D_AX);
-}
-
-int
-BtoR(int32 b)
-{
- b &= 0x3fffL; // no R14 or R15
- if(b == 0)
- return 0;
- return bitno(b) + D_AX;
-}
-
-/*
- * bit reg
- * 16 X5 (FREGMIN)
- * ...
- * 26 X15 (FREGEXT)
- */
-int32
-FtoB(int f)
-{
- if(f < FREGMIN || f > FREGEXT)
- return 0;
- return 1L << (f - FREGMIN + 16);
-}
-
-int
-BtoF(int32 b)
-{
-
- b &= 0xFF0000L;
- if(b == 0)
- return 0;
- return bitno(b) - 16 + FREGMIN;
-}
-
-void
-dumpone(Reg *r)
-{
- int z;
- Bits bit;
-
- print("%d:%P", r->loop, r->prog);
- 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, Reg *r0)
-{
- Reg *r, *r1;
-
- print("\n%s\n", str);
- for(r = r0; r != R; r = r->link) {
- dumpone(r);
- r1 = r->p2;
- if(r1 != R) {
- print(" pred:");
- for(; r1 != R; r1 = r1->p2link)
- print(" %.4ud", r1->prog->loc);
- print("\n");
- }
-// r1 = r->s1;
-// if(r1 != R) {
-// print(" succ:");
-// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", r1->prog->loc);
-// print("\n");
-// }
- }
-}
-
-static Sym* symlist[10];
-
-int
-noreturn(Prog *p)
-{
- Sym *s;
- int i;
-
- if(symlist[0] == S) {
- symlist[0] = pkglookup("panicindex", runtimepkg);
- symlist[1] = pkglookup("panicslice", runtimepkg);
- symlist[2] = pkglookup("throwinit", runtimepkg);
- symlist[3] = pkglookup("panic", runtimepkg);
- symlist[4] = pkglookup("panicwrap", runtimepkg);
- }
-
- s = p->to.sym;
- if(s == S)
- return 0;
- for(i=0; symlist[i]!=S; i++)
- if(s == symlist[i])
- return 1;
- return 0;
-}
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
deleted file mode 100644
index 709f82ccc..000000000
--- a/src/cmd/6l/6.out.h
+++ /dev/null
@@ -1,863 +0,0 @@
-// Inferno utils/6c/6.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.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.
-
-#define NSYM 50
-#define NSNAME 8
-#define NOPROF (1<<0)
-#define DUPOK (1<<1)
-#define NOSPLIT (1<<2)
-#define RODATA (1<<3)
-
-/*
- * amd64
- */
-
-enum as
-{
- AXXX,
- AAAA,
- AAAD,
- AAAM,
- AAAS,
- AADCB,
- AADCL,
- AADCW,
- AADDB,
- AADDL,
- AADDW,
- AADJSP,
- AANDB,
- AANDL,
- AANDW,
- AARPL,
- ABOUNDL,
- ABOUNDW,
- ABSFL,
- ABSFW,
- ABSRL,
- ABSRW,
- ABTL,
- ABTW,
- ABTCL,
- ABTCW,
- ABTRL,
- ABTRW,
- ABTSL,
- ABTSW,
- ABYTE,
- ACALL,
- ACLC,
- ACLD,
- ACLI,
- ACLTS,
- ACMC,
- ACMPB,
- ACMPL,
- ACMPW,
- ACMPSB,
- ACMPSL,
- ACMPSW,
- ADAA,
- ADAS,
- ADATA,
- ADECB,
- ADECL,
- ADECQ,
- ADECW,
- ADIVB,
- ADIVL,
- ADIVW,
- AENTER,
- AGLOBL,
- AGOK,
- AHISTORY,
- AHLT,
- AIDIVB,
- AIDIVL,
- AIDIVW,
- AIMULB,
- AIMULL,
- AIMULW,
- AINB,
- AINL,
- AINW,
- AINCB,
- AINCL,
- AINCQ,
- AINCW,
- AINSB,
- AINSL,
- AINSW,
- AINT,
- AINTO,
- AIRETL,
- AIRETW,
- AJCC,
- AJCS,
- AJCXZ,
- AJEQ,
- AJGE,
- AJGT,
- AJHI,
- AJLE,
- AJLS,
- AJLT,
- AJMI,
- AJMP,
- AJNE,
- AJOC,
- AJOS,
- AJPC,
- AJPL,
- AJPS,
- ALAHF,
- ALARL,
- ALARW,
- ALEAL,
- ALEAW,
- ALEAVEL,
- ALEAVEW,
- ALOCK,
- ALODSB,
- ALODSL,
- ALODSW,
- ALONG,
- ALOOP,
- ALOOPEQ,
- ALOOPNE,
- ALSLL,
- ALSLW,
- AMOVB,
- AMOVL,
- AMOVW,
- AMOVBLSX,
- AMOVBLZX,
- AMOVBQSX,
- AMOVBQZX,
- AMOVBWSX,
- AMOVBWZX,
- AMOVWLSX,
- AMOVWLZX,
- AMOVWQSX,
- AMOVWQZX,
- AMOVSB,
- AMOVSL,
- AMOVSW,
- AMULB,
- AMULL,
- AMULW,
- ANAME,
- ANEGB,
- ANEGL,
- ANEGW,
- ANOP,
- ANOTB,
- ANOTL,
- ANOTW,
- AORB,
- AORL,
- AORW,
- AOUTB,
- AOUTL,
- AOUTW,
- AOUTSB,
- AOUTSL,
- AOUTSW,
- APOPAL,
- APOPAW,
- APOPFL,
- APOPFW,
- APOPL,
- APOPW,
- APUSHAL,
- APUSHAW,
- APUSHFL,
- APUSHFW,
- APUSHL,
- APUSHW,
- ARCLB,
- ARCLL,
- ARCLW,
- ARCRB,
- ARCRL,
- ARCRW,
- AREP,
- AREPN,
- ARET,
- AROLB,
- AROLL,
- AROLW,
- ARORB,
- ARORL,
- ARORW,
- ASAHF,
- ASALB,
- ASALL,
- ASALW,
- ASARB,
- ASARL,
- ASARW,
- ASBBB,
- ASBBL,
- ASBBW,
- ASCASB,
- ASCASL,
- ASCASW,
- ASETCC,
- ASETCS,
- ASETEQ,
- ASETGE,
- ASETGT,
- ASETHI,
- ASETLE,
- ASETLS,
- ASETLT,
- ASETMI,
- ASETNE,
- ASETOC,
- ASETOS,
- ASETPC,
- ASETPL,
- ASETPS,
- ACDQ,
- ACWD,
- ASHLB,
- ASHLL,
- ASHLW,
- ASHRB,
- ASHRL,
- ASHRW,
- ASTC,
- ASTD,
- ASTI,
- ASTOSB,
- ASTOSL,
- ASTOSW,
- ASUBB,
- ASUBL,
- ASUBW,
- ASYSCALL,
- ATESTB,
- ATESTL,
- ATESTW,
- ATEXT,
- AVERR,
- AVERW,
- AWAIT,
- AWORD,
- AXCHGB,
- AXCHGL,
- AXCHGW,
- AXLAT,
- AXORB,
- AXORL,
- AXORW,
-
- AFMOVB,
- AFMOVBP,
- AFMOVD,
- AFMOVDP,
- AFMOVF,
- AFMOVFP,
- AFMOVL,
- AFMOVLP,
- AFMOVV,
- AFMOVVP,
- AFMOVW,
- AFMOVWP,
- AFMOVX,
- AFMOVXP,
-
- AFCOMB,
- AFCOMBP,
- AFCOMD,
- AFCOMDP,
- AFCOMDPP,
- AFCOMF,
- AFCOMFP,
- AFCOML,
- AFCOMLP,
- AFCOMW,
- AFCOMWP,
- AFUCOM,
- AFUCOMP,
- AFUCOMPP,
-
- AFADDDP,
- AFADDW,
- AFADDL,
- AFADDF,
- AFADDD,
-
- AFMULDP,
- AFMULW,
- AFMULL,
- AFMULF,
- AFMULD,
-
- AFSUBDP,
- AFSUBW,
- AFSUBL,
- AFSUBF,
- AFSUBD,
-
- AFSUBRDP,
- AFSUBRW,
- AFSUBRL,
- AFSUBRF,
- AFSUBRD,
-
- AFDIVDP,
- AFDIVW,
- AFDIVL,
- AFDIVF,
- AFDIVD,
-
- AFDIVRDP,
- AFDIVRW,
- AFDIVRL,
- AFDIVRF,
- AFDIVRD,
-
- AFXCHD,
- AFFREE,
-
- AFLDCW,
- AFLDENV,
- AFRSTOR,
- AFSAVE,
- AFSTCW,
- AFSTENV,
- AFSTSW,
-
- AF2XM1,
- AFABS,
- AFCHS,
- AFCLEX,
- AFCOS,
- AFDECSTP,
- AFINCSTP,
- AFINIT,
- AFLD1,
- AFLDL2E,
- AFLDL2T,
- AFLDLG2,
- AFLDLN2,
- AFLDPI,
- AFLDZ,
- AFNOP,
- AFPATAN,
- AFPREM,
- AFPREM1,
- AFPTAN,
- AFRNDINT,
- AFSCALE,
- AFSIN,
- AFSINCOS,
- AFSQRT,
- AFTST,
- AFXAM,
- AFXTRACT,
- AFYL2X,
- AFYL2XP1,
-
- AEND,
-
- ADYNT_,
- AINIT_,
-
- ASIGNAME,
-
- /* extra 32-bit operations */
- ACMPXCHGB,
- ACMPXCHGL,
- ACMPXCHGW,
- ACMPXCHG8B,
- ACPUID,
- AINVD,
- AINVLPG,
- ALFENCE,
- AMFENCE,
- AMOVNTIL,
- ARDMSR,
- ARDPMC,
- ARDTSC,
- ARSM,
- ASFENCE,
- ASYSRET,
- AWBINVD,
- AWRMSR,
- AXADDB,
- AXADDL,
- AXADDW,
-
- /* conditional move */
- ACMOVLCC,
- ACMOVLCS,
- ACMOVLEQ,
- ACMOVLGE,
- ACMOVLGT,
- ACMOVLHI,
- ACMOVLLE,
- ACMOVLLS,
- ACMOVLLT,
- ACMOVLMI,
- ACMOVLNE,
- ACMOVLOC,
- ACMOVLOS,
- ACMOVLPC,
- ACMOVLPL,
- ACMOVLPS,
- ACMOVQCC,
- ACMOVQCS,
- ACMOVQEQ,
- ACMOVQGE,
- ACMOVQGT,
- ACMOVQHI,
- ACMOVQLE,
- ACMOVQLS,
- ACMOVQLT,
- ACMOVQMI,
- ACMOVQNE,
- ACMOVQOC,
- ACMOVQOS,
- ACMOVQPC,
- ACMOVQPL,
- ACMOVQPS,
- ACMOVWCC,
- ACMOVWCS,
- ACMOVWEQ,
- ACMOVWGE,
- ACMOVWGT,
- ACMOVWHI,
- ACMOVWLE,
- ACMOVWLS,
- ACMOVWLT,
- ACMOVWMI,
- ACMOVWNE,
- ACMOVWOC,
- ACMOVWOS,
- ACMOVWPC,
- ACMOVWPL,
- ACMOVWPS,
-
- /* 64-bit */
- AADCQ,
- AADDQ,
- AANDQ,
- ABSFQ,
- ABSRQ,
- ABTCQ,
- ABTQ,
- ABTRQ,
- ABTSQ,
- ACMPQ,
- ACMPSQ,
- ACMPXCHGQ,
- ACQO,
- ADIVQ,
- AIDIVQ,
- AIMULQ,
- AIRETQ,
- ALEAQ,
- ALEAVEQ,
- ALODSQ,
- AMOVQ,
- AMOVLQSX,
- AMOVLQZX,
- AMOVNTIQ,
- AMOVSQ,
- AMULQ,
- ANEGQ,
- ANOTQ,
- AORQ,
- APOPFQ,
- APOPQ,
- APUSHFQ,
- APUSHQ,
- ARCLQ,
- ARCRQ,
- AROLQ,
- ARORQ,
- AQUAD,
- ASALQ,
- ASARQ,
- ASBBQ,
- ASCASQ,
- ASHLQ,
- ASHRQ,
- ASTOSQ,
- ASUBQ,
- ATESTQ,
- AXADDQ,
- AXCHGQ,
- AXORQ,
-
- /* media */
- AADDPD,
- AADDPS,
- AADDSD,
- AADDSS,
- AANDNPD,
- AANDNPS,
- AANDPD,
- AANDPS,
- ACMPPD,
- ACMPPS,
- ACMPSD,
- ACMPSS,
- ACOMISD,
- ACOMISS,
- ACVTPD2PL,
- ACVTPD2PS,
- ACVTPL2PD,
- ACVTPL2PS,
- ACVTPS2PD,
- ACVTPS2PL,
- ACVTSD2SL,
- ACVTSD2SQ,
- ACVTSD2SS,
- ACVTSL2SD,
- ACVTSL2SS,
- ACVTSQ2SD,
- ACVTSQ2SS,
- ACVTSS2SD,
- ACVTSS2SL,
- ACVTSS2SQ,
- ACVTTPD2PL,
- ACVTTPS2PL,
- ACVTTSD2SL,
- ACVTTSD2SQ,
- ACVTTSS2SL,
- ACVTTSS2SQ,
- ADIVPD,
- ADIVPS,
- ADIVSD,
- ADIVSS,
- AEMMS,
- AFXRSTOR,
- AFXRSTOR64,
- AFXSAVE,
- AFXSAVE64,
- ALDMXCSR,
- AMASKMOVOU,
- AMASKMOVQ,
- AMAXPD,
- AMAXPS,
- AMAXSD,
- AMAXSS,
- AMINPD,
- AMINPS,
- AMINSD,
- AMINSS,
- AMOVAPD,
- AMOVAPS,
- AMOVOU,
- AMOVHLPS,
- AMOVHPD,
- AMOVHPS,
- AMOVLHPS,
- AMOVLPD,
- AMOVLPS,
- AMOVMSKPD,
- AMOVMSKPS,
- AMOVNTO,
- AMOVNTPD,
- AMOVNTPS,
- AMOVNTQ,
- AMOVO,
- AMOVQOZX,
- AMOVSD,
- AMOVSS,
- AMOVUPD,
- AMOVUPS,
- AMULPD,
- AMULPS,
- AMULSD,
- AMULSS,
- AORPD,
- AORPS,
- APACKSSLW,
- APACKSSWB,
- APACKUSWB,
- APADDB,
- APADDL,
- APADDQ,
- APADDSB,
- APADDSW,
- APADDUSB,
- APADDUSW,
- APADDW,
- APANDB,
- APANDL,
- APANDSB,
- APANDSW,
- APANDUSB,
- APANDUSW,
- APANDW,
- APAND,
- APANDN,
- APAVGB,
- APAVGW,
- APCMPEQB,
- APCMPEQL,
- APCMPEQW,
- APCMPGTB,
- APCMPGTL,
- APCMPGTW,
- APEXTRW,
- APFACC,
- APFADD,
- APFCMPEQ,
- APFCMPGE,
- APFCMPGT,
- APFMAX,
- APFMIN,
- APFMUL,
- APFNACC,
- APFPNACC,
- APFRCP,
- APFRCPIT1,
- APFRCPI2T,
- APFRSQIT1,
- APFRSQRT,
- APFSUB,
- APFSUBR,
- APINSRW,
- APMADDWL,
- APMAXSW,
- APMAXUB,
- APMINSW,
- APMINUB,
- APMOVMSKB,
- APMULHRW,
- APMULHUW,
- APMULHW,
- APMULLW,
- APMULULQ,
- APOR,
- APSADBW,
- APSHUFHW,
- APSHUFL,
- APSHUFLW,
- APSHUFW,
- APSLLO,
- APSLLL,
- APSLLQ,
- APSLLW,
- APSRAL,
- APSRAW,
- APSRLO,
- APSRLL,
- APSRLQ,
- APSRLW,
- APSUBB,
- APSUBL,
- APSUBQ,
- APSUBSB,
- APSUBSW,
- APSUBUSB,
- APSUBUSW,
- APSUBW,
- APSWAPL,
- APUNPCKHBW,
- APUNPCKHLQ,
- APUNPCKHQDQ,
- APUNPCKHWL,
- APUNPCKLBW,
- APUNPCKLLQ,
- APUNPCKLQDQ,
- APUNPCKLWL,
- APXOR,
- ARCPPS,
- ARCPSS,
- ARSQRTPS,
- ARSQRTSS,
- ASHUFPD,
- ASHUFPS,
- ASQRTPD,
- ASQRTPS,
- ASQRTSD,
- ASQRTSS,
- ASTMXCSR,
- ASUBPD,
- ASUBPS,
- ASUBSD,
- ASUBSS,
- AUCOMISD,
- AUCOMISS,
- AUNPCKHPD,
- AUNPCKHPS,
- AUNPCKLPD,
- AUNPCKLPS,
- AXORPD,
- AXORPS,
-
- APF2IW,
- APF2IL,
- API2FW,
- API2FL,
- ARETFW,
- ARETFL,
- ARETFQ,
- ASWAPGS,
-
- AMODE,
-
- ALAST
-};
-
-enum
-{
-
- D_AL = 0,
- D_CL,
- D_DL,
- D_BL,
- D_SPB,
- D_BPB,
- D_SIB,
- D_DIB,
- D_R8B,
- D_R9B,
- D_R10B,
- D_R11B,
- D_R12B,
- D_R13B,
- D_R14B,
- D_R15B,
-
- D_AX = 16,
- D_CX,
- D_DX,
- D_BX,
- D_SP,
- D_BP,
- D_SI,
- D_DI,
- D_R8,
- D_R9,
- D_R10,
- D_R11,
- D_R12,
- D_R13,
- D_R14,
- D_R15,
-
- D_AH = 32,
- D_CH,
- D_DH,
- D_BH,
-
- D_F0 = 36,
-
- D_M0 = 44,
-
- D_X0 = 52,
- D_X1,
- D_X2,
- D_X3,
- D_X4,
- D_X5,
- D_X6,
- D_X7,
-
- D_CS = 68,
- D_SS,
- D_DS,
- D_ES,
- D_FS,
- D_GS,
-
- D_GDTR, /* global descriptor table register */
- D_IDTR, /* interrupt descriptor table register */
- D_LDTR, /* local descriptor table register */
- D_MSW, /* machine status word */
- D_TASK, /* task register */
-
- D_CR = 79,
- D_DR = 95,
- D_TR = 103,
-
- D_NONE = 111,
-
- D_BRANCH = 112,
- D_EXTERN = 113,
- D_STATIC = 114,
- D_AUTO = 115,
- D_PARAM = 116,
- D_CONST = 117,
- D_FCONST = 118,
- D_SCONST = 119,
- D_ADDR = 120,
-
- D_FILE,
- D_FILE1,
-
- D_INDIR, /* additive */
-
- D_SIZE = D_INDIR + D_INDIR, /* 6l internal */
- D_PCREL,
-
- T_TYPE = 1<<0,
- T_INDEX = 1<<1,
- T_OFFSET = 1<<2,
- T_FCONST = 1<<3,
- T_SYM = 1<<4,
- T_SCONST = 1<<5,
- T_64 = 1<<6,
- T_GOTYPE = 1<<7,
-
- REGARG = -1,
- REGRET = D_AX,
- FREGRET = D_X0,
- REGSP = D_SP,
- REGTMP = D_DI,
- REGEXT = D_R15, /* compiler allocates external registers R15 down */
- FREGMIN = D_X0+5, /* first register variable */
- FREGEXT = D_X0+15 /* first external register */
-};
-
-/*
- * this is the ranlib header
- */
-#define SYMDEF "__.SYMDEF"
-
-/*
- * this is the simulated IEEE floating point
- */
-typedef struct ieee Ieee;
-struct ieee
-{
- int32 l; /* contains ls-man 0xffffffff */
- int32 h; /* contains sign 0x80000000
- exp 0x7ff00000
- ms-man 0x000fffff */
-};
diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile
deleted file mode 100644
index abe204d4f..000000000
--- a/src/cmd/6l/Makefile
+++ /dev/null
@@ -1,48 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=6l
-
-OFILES=\
- asm.$O\
- data.$O\
- dwarf.$O\
- elf.$O\
- enam.$O\
- go.$O\
- ldelf.$O\
- ldmacho.$O\
- ldpe.$O\
- lib.$O\
- list.$O\
- macho.$O\
- obj.$O\
- optab.$O\
- pass.$O\
- pe.$O\
- prof.$O\
- span.$O\
- symtab.$O\
-
-HFILES=\
- l.h\
- ../6l/6.out.h\
- ../ld/lib.h\
- ../ld/elf.h\
- ../ld/macho.h\
- ../ld/dwarf.h\
- ../ld/pe.h\
-
-include ../../Make.ccmd
-
-enam.c: 6.out.h
- sh mkenam
-
-CLEANFILES+=enam.c
-
-%.$O: ../ld/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
deleted file mode 100644
index 9136e0379..000000000
--- a/src/cmd/6l/asm.c
+++ /dev/null
@@ -1,1171 +0,0 @@
-// Inferno utils/6l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/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"
-#include "../ld/macho.h"
-#include "../ld/pe.h"
-
-#define Dbufslop 100
-
-#define PADDR(a) ((uint32)(a) & ~0x80000000)
-
-char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
-char freebsddynld[] = "/libexec/ld-elf.so.1";
-
-char zeroes[32];
-
-vlong
-entryvalue(void)
-{
- char *a;
- Sym *s;
-
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return atolwhex(a);
- s = lookup(a, 0);
- if(s->type == 0)
- return INITTEXT;
- if(s->type != STEXT)
- diag("entry not text: %s", s->name);
- return s->value;
-}
-
-vlong
-datoff(vlong addr)
-{
- if(addr >= segdata.vaddr)
- return addr - segdata.vaddr + segdata.fileoff;
- if(addr >= segtext.vaddr)
- return addr - segtext.vaddr + segtext.fileoff;
- diag("datoff %#llx", addr);
- return 0;
-}
-
-enum {
- ElfStrEmpty,
- ElfStrInterp,
- ElfStrHash,
- ElfStrGot,
- ElfStrGotPlt,
- ElfStrDynamic,
- ElfStrDynsym,
- ElfStrDynstr,
- ElfStrRela,
- ElfStrText,
- ElfStrData,
- ElfStrBss,
- ElfStrShstrtab,
- ElfStrSymtab,
- ElfStrStrtab,
- ElfStrRelaPlt,
- ElfStrPlt,
- ElfStrGnuVersion,
- ElfStrGnuVersionR,
- NElfStr
-};
-
-vlong elfstr[NElfStr];
-
-static int
-needlib(char *name)
-{
- char *p;
- Sym *s;
-
- if(*name == '\0')
- return 0;
-
- /* reuse hash code in symbol table */
- p = smprint(".elfload.%s", name);
- s = lookup(p, 0);
- if(s->type == 0) {
- s->type = 100; // avoid SDATA, etc.
- return 1;
- }
- return 0;
-}
-
-int nelfsym = 1;
-
-static void addpltsym(Sym*);
-static void addgotsym(Sym*);
-
-void
-adddynrel(Sym *s, Reloc *r)
-{
- Sym *targ, *rela, *got;
-
- targ = r->sym;
- cursym = s;
-
- switch(r->type) {
- default:
- if(r->type >= 256) {
- diag("unexpected relocation type %d", r->type);
- return;
- }
- break;
-
- // Handle relocations found in ELF object files.
- case 256 + R_X86_64_PC32:
- if(targ->dynimpname != nil && !targ->dynexport)
- diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
- if(targ->type == 0 || targ->type == SXREF)
- diag("unknown symbol %s in pcrel", targ->name);
- r->type = D_PCREL;
- r->add += 4;
- return;
-
- case 256 + R_X86_64_PLT32:
- r->type = D_PCREL;
- r->add += 4;
- if(targ->dynimpname != nil && !targ->dynexport) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
- r->add += targ->plt;
- }
- return;
-
- case 256 + R_X86_64_GOTPCREL:
- if(targ->dynimpname == nil || targ->dynexport) {
- // have symbol
- if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
- // turn MOVQ of GOT entry into LEAQ of symbol itself
- s->p[r->off-2] = 0x8d;
- r->type = D_PCREL;
- r->add += 4;
- return;
- }
- // fall back to using GOT and hope for the best (CMOV*)
- // TODO: just needs relocation, no need to put in .dynsym
- targ->dynimpname = targ->name;
- }
- addgotsym(targ);
- r->type = D_PCREL;
- r->sym = lookup(".got", 0);
- r->add += 4;
- r->add += targ->got;
- return;
-
- case 256 + R_X86_64_64:
- if(targ->dynimpname != nil && !targ->dynexport)
- diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
- r->type = D_ADDR;
- return;
-
- // Handle relocations found in Mach-O object files.
- case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0:
- case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
- case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
- // TODO: What is the difference between all these?
- r->type = D_ADDR;
- if(targ->dynimpname != nil && !targ->dynexport)
- diag("unexpected reloc for dynamic symbol %s", targ->name);
- return;
-
- case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
- if(targ->dynimpname != nil && !targ->dynexport) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
- r->add = targ->plt;
- r->type = D_PCREL;
- return;
- }
- // fall through
- case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1:
- case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1:
- case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
- case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
- case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
- r->type = D_PCREL;
- if(targ->dynimpname != nil && !targ->dynexport)
- diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
- return;
-
- case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
- if(targ->dynimpname == nil || targ->dynexport) {
- // have symbol
- // turn MOVQ of GOT entry into LEAQ of symbol itself
- if(r->off < 2 || s->p[r->off-2] != 0x8b) {
- diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
- return;
- }
- s->p[r->off-2] = 0x8d;
- r->type = D_PCREL;
- return;
- }
- // fall through
- case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
- if(targ->dynimpname == nil || targ->dynexport)
- diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
- addgotsym(targ);
- r->type = D_PCREL;
- r->sym = lookup(".got", 0);
- r->add += targ->got;
- return;
- }
-
- // Handle references to ELF symbols from our own object files.
- if(targ->dynimpname == nil || targ->dynexport)
- return;
-
- switch(r->type) {
- case D_PCREL:
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
- r->add = targ->plt;
- return;
-
- case D_ADDR:
- if(s->type != SDATA)
- break;
- if(iself) {
- adddynsym(targ);
- rela = lookup(".rela", 0);
- addaddrplus(rela, s, r->off);
- if(r->siz == 8)
- adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
- else
- adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
- adduint64(rela, r->add);
- r->type = 256; // ignore during relocsym
- return;
- }
- if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
- // Mach-O relocations are a royal pain to lay out.
- // They use a compact stateful bytecode representation
- // that is too much bother to deal with.
- // Instead, interpret the C declaration
- // void *_Cvar_stderr = &stderr;
- // as making _Cvar_stderr the name of a GOT entry
- // for stderr. This is separate from the usual GOT entry,
- // just in case the C code assigns to the variable,
- // and of course it only works for single pointers,
- // but we only need to support cgo and that's all it needs.
- adddynsym(targ);
- got = lookup(".got", 0);
- s->type = got->type | SSUB;
- s->outer = got;
- s->sub = got->sub;
- got->sub = s;
- s->value = got->size;
- adduint64(got, 0);
- adduint32(lookup(".linkedit.got", 0), targ->dynid);
- r->type = 256; // ignore during relocsym
- return;
- }
- break;
- }
-
- cursym = s;
- diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
-}
-
-int
-archreloc(Reloc *r, Sym *s, vlong *val)
-{
- return -1;
-}
-
-static void
-elfsetupplt(void)
-{
- Sym *plt, *got;
-
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
- if(plt->size == 0) {
- // pushq got+8(IP)
- adduint8(plt, 0xff);
- adduint8(plt, 0x35);
- addpcrelplus(plt, got, 8);
-
- // jmpq got+16(IP)
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addpcrelplus(plt, got, 16);
-
- // nopl 0(AX)
- adduint32(plt, 0x00401f0f);
-
- // assume got->size == 0 too
- addaddrplus(got, lookup(".dynamic", 0), 0);
- adduint64(got, 0);
- adduint64(got, 0);
- }
-}
-
-static void
-addpltsym(Sym *s)
-{
- if(s->plt >= 0)
- return;
-
- adddynsym(s);
-
- if(iself) {
- Sym *plt, *got, *rela;
-
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
- rela = lookup(".rela.plt", 0);
- if(plt->size == 0)
- elfsetupplt();
-
- // jmpq *got+size(IP)
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addpcrelplus(plt, got, got->size);
-
- // add to got: pointer to current pos in plt
- addaddrplus(got, plt, plt->size);
-
- // pushq $x
- adduint8(plt, 0x68);
- adduint32(plt, (got->size-24-8)/8);
-
- // jmpq .plt
- adduint8(plt, 0xe9);
- adduint32(plt, -(plt->size+4));
-
- // rela
- addaddrplus(rela, got, got->size-8);
- adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
- adduint64(rela, 0);
-
- s->plt = plt->size - 16;
- } else if(HEADTYPE == Hdarwin) {
- // To do lazy symbol lookup right, we're supposed
- // to tell the dynamic loader which library each
- // symbol comes from and format the link info
- // section just so. I'm too lazy (ha!) to do that
- // so for now we'll just use non-lazy pointers,
- // which don't need to be told which library to use.
- //
- // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
- // has details about what we're avoiding.
-
- Sym *plt;
-
- addgotsym(s);
- plt = lookup(".plt", 0);
-
- adduint32(lookup(".linkedit.plt", 0), s->dynid);
-
- // jmpq *got+size(IP)
- s->plt = plt->size;
-
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addpcrelplus(plt, lookup(".got", 0), s->got);
- } else {
- diag("addpltsym: unsupported binary format");
- }
-}
-
-static void
-addgotsym(Sym *s)
-{
- Sym *got, *rela;
-
- if(s->got >= 0)
- return;
-
- adddynsym(s);
- got = lookup(".got", 0);
- s->got = got->size;
- adduint64(got, 0);
-
- if(iself) {
- rela = lookup(".rela", 0);
- addaddrplus(rela, got, s->got);
- adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
- adduint64(rela, 0);
- } else if(HEADTYPE == Hdarwin) {
- adduint32(lookup(".linkedit.got", 0), s->dynid);
- } else {
- diag("addgotsym: unsupported binary format");
- }
-}
-
-void
-adddynsym(Sym *s)
-{
- Sym *d, *str;
- int t;
- char *name;
-
- if(s->dynid >= 0)
- return;
-
- if(s->dynimpname == nil)
- diag("adddynsym: no dynamic name for %s", s->name);
-
- if(iself) {
- s->dynid = nelfsym++;
-
- d = lookup(".dynsym", 0);
-
- name = s->dynimpname;
- if(name == nil)
- name = s->name;
- adduint32(d, addstring(lookup(".dynstr", 0), name));
- /* type */
- t = STB_GLOBAL << 4;
- if(s->dynexport && s->type == STEXT)
- t |= STT_FUNC;
- else
- t |= STT_OBJECT;
- adduint8(d, t);
-
- /* reserved */
- adduint8(d, 0);
-
- /* section where symbol is defined */
- if(!s->dynexport && s->dynimpname != nil)
- adduint16(d, SHN_UNDEF);
- else {
- switch(s->type) {
- default:
- case STEXT:
- t = 11;
- break;
- case SRODATA:
- t = 12;
- break;
- case SDATA:
- t = 13;
- break;
- case SBSS:
- t = 14;
- break;
- }
- adduint16(d, t);
- }
-
- /* value */
- if(s->type == SDYNIMPORT)
- adduint64(d, 0);
- else
- addaddr(d, s);
-
- /* size of object */
- adduint64(d, 0);
-
- if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) {
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
- addstring(lookup(".dynstr", 0), s->dynimplib));
- }
- } else if(HEADTYPE == Hdarwin) {
- // Mach-o symbol nlist64
- d = lookup(".dynsym", 0);
- name = s->dynimpname;
- if(name == nil)
- name = s->name;
- s->dynid = d->size/16;
- // darwin still puts _ prefixes on all C symbols
- str = lookup(".dynstr", 0);
- adduint32(d, str->size);
- adduint8(str, '_');
- addstring(str, name);
- if(s->type == SDYNIMPORT) {
- adduint8(d, 0x01); // type - N_EXT - external symbol
- adduint8(d, 0); // section
- } else {
- adduint8(d, 0x0f);
- switch(s->type) {
- default:
- case STEXT:
- adduint8(d, 1);
- break;
- case SDATA:
- adduint8(d, 2);
- break;
- case SBSS:
- adduint8(d, 4);
- break;
- }
- }
- adduint16(d, 0); // desc
- if(s->type == SDYNIMPORT)
- adduint64(d, 0); // value
- else
- addaddr(d, s);
- } else {
- diag("adddynsym: unsupported binary format");
- }
-}
-
-void
-adddynlib(char *lib)
-{
- Sym *s;
-
- if(!needlib(lib))
- return;
-
- if(iself) {
- s = lookup(".dynstr", 0);
- if(s->size == 0)
- addstring(s, "");
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
- } else if(HEADTYPE == Hdarwin) {
- machoadddynlib(lib);
- } else {
- diag("adddynlib: unsupported binary format");
- }
-}
-
-void
-doelf(void)
-{
- Sym *s, *shstrtab, *dynstr;
-
- if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd)
- return;
-
- /* predefine strings we need for section headers */
- shstrtab = lookup(".shstrtab", 0);
- shstrtab->type = SELFDATA;
- shstrtab->reachable = 1;
-
- elfstr[ElfStrEmpty] = addstring(shstrtab, "");
- elfstr[ElfStrText] = addstring(shstrtab, ".text");
- elfstr[ElfStrData] = addstring(shstrtab, ".data");
- elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
- addstring(shstrtab, ".elfdata");
- addstring(shstrtab, ".rodata");
- addstring(shstrtab, ".gosymtab");
- addstring(shstrtab, ".gopclntab");
- if(!debug['s']) {
- elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
- elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
- dwarfaddshstrings(shstrtab);
- }
- elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
-
- if(!debug['d']) { /* -d suppresses dynamic loader format */
- elfstr[ElfStrInterp] = addstring(shstrtab, ".interp");
- elfstr[ElfStrHash] = addstring(shstrtab, ".hash");
- elfstr[ElfStrGot] = addstring(shstrtab, ".got");
- elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt");
- elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic");
- elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
- elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
- elfstr[ElfStrRela] = addstring(shstrtab, ".rela");
- elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt");
- elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
- elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
- elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
-
- /* dynamic symbol table - first entry all zeros */
- s = lookup(".dynsym", 0);
- s->type = SELFDATA;
- s->reachable = 1;
- s->size += ELF64SYMSIZE;
-
- /* dynamic string table */
- s = lookup(".dynstr", 0);
- s->type = SELFDATA;
- s->reachable = 1;
- if(s->size == 0)
- addstring(s, "");
- dynstr = s;
-
- /* relocation table */
- s = lookup(".rela", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /* global offset table */
- s = lookup(".got", 0);
- s->reachable = 1;
- s->type = SDATA; // writable, so not SELFDATA
-
- /* hash */
- s = lookup(".hash", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- s = lookup(".got.plt", 0);
- s->reachable = 1;
- s->type = SDATA; // writable, not SELFDATA
-
- s = lookup(".plt", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- elfsetupplt();
-
- s = lookup(".rela.plt", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- s = lookup(".gnu.version", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- s = lookup(".gnu.version_r", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /* define dynamic elf table */
- s = lookup(".dynamic", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /*
- * .dynamic table
- */
- elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
- elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
- elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
- elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
- elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
- elfwritedynentsym(s, DT_RELA, lookup(".rela", 0));
- elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0));
- elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
- if(rpath)
- elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
-
- elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
- elfwritedynent(s, DT_PLTREL, DT_RELA);
- elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
- elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
-
- // Do not write DT_NULL. elfdynhash will finish it.
- }
-}
-
-void
-shsym(ElfShdr *sh, Sym *s)
-{
- sh->addr = symaddr(s);
- sh->off = datoff(sh->addr);
- sh->size = s->size;
-}
-
-void
-phsh(ElfPhdr *ph, ElfShdr *sh)
-{
- ph->vaddr = sh->addr;
- ph->paddr = ph->vaddr;
- ph->off = sh->off;
- ph->filesz = sh->size;
- ph->memsz = sh->size;
- ph->align = sh->addralign;
-}
-
-void
-asmb(void)
-{
- int32 magic;
- int a, dynsym;
- vlong vl, startva, symo, machlink;
- ElfEhdr *eh;
- ElfPhdr *ph, *pph;
- ElfShdr *sh;
- Section *sect;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f asmb\n", cputime());
- Bflush(&bso);
-
- elftextsh = 0;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f codeblk\n", cputime());
- Bflush(&bso);
-
- sect = segtext.sect;
- seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
- codeblk(sect->vaddr, sect->len);
-
- /* output read-only data in text segment (rodata, gosymtab and pclntab) */
- for(sect = sect->next; sect != nil; sect = sect->next) {
- seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
- datblk(sect->vaddr, sect->len);
- }
-
- if(debug['v'])
- Bprint(&bso, "%5.2f datblk\n", cputime());
- Bflush(&bso);
-
- seek(cout, segdata.fileoff, 0);
- datblk(segdata.vaddr, segdata.filelen);
-
- machlink = 0;
- if(HEADTYPE == Hdarwin)
- machlink = domacholink();
-
- switch(HEADTYPE) {
- default:
- diag("unknown header type %d", HEADTYPE);
- case Hplan9x32:
- case Helf:
- break;
- case Hdarwin:
- debug['8'] = 1; /* 64-bit addresses */
- break;
- case Hlinux:
- case Hfreebsd:
- debug['8'] = 1; /* 64-bit addresses */
- /* index of elf text section; needed by asmelfsym, double-checked below */
- /* !debug['d'] causes extra sections before the .text section */
- elftextsh = 1;
- if(!debug['d']) {
- elftextsh += 10;
- if(elfverneed)
- elftextsh += 2;
- }
- break;
- case Hwindows:
- break;
- }
-
- symsize = 0;
- spsize = 0;
- lcsize = 0;
- symo = 0;
- if(!debug['s']) {
- if(debug['v'])
- Bprint(&bso, "%5.2f sym\n", cputime());
- Bflush(&bso);
- switch(HEADTYPE) {
- default:
- case Hplan9x32:
- case Helf:
- debug['s'] = 1;
- symo = HEADR+segtext.len+segdata.filelen;
- break;
- case Hdarwin:
- symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
- break;
- case Hlinux:
- case Hfreebsd:
- symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen;
- symo = rnd(symo, INITRND);
- break;
- case Hwindows:
- symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
- symo = rnd(symo, PEFILEALIGN);
- break;
- }
- seek(cout, symo, 0);
- switch(HEADTYPE) {
- default:
- if(iself) {
- seek(cout, symo, 0);
- asmelfsym();
- cflush();
- ewrite(cout, elfstrdat, elfstrsize);
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dwarf\n", cputime());
-
- dwarfemitdebugsections();
- }
- break;
- case Hdarwin:
- case Hwindows:
- if(debug['v'])
- Bprint(&bso, "%5.2f dwarf\n", cputime());
-
- dwarfemitdebugsections();
- break;
- }
- }
-
- if(debug['v'])
- Bprint(&bso, "%5.2f headr\n", cputime());
- Bflush(&bso);
- seek(cout, 0L, 0);
- switch(HEADTYPE) {
- default:
- case Hplan9x32: /* plan9 */
- magic = 4*26*26+7;
- magic |= 0x00008000; /* fat header */
- lputb(magic); /* magic */
- lputb(segtext.filelen); /* sizes */
- lputb(segdata.filelen);
- lputb(segdata.len - segdata.filelen);
- lputb(symsize); /* nsyms */
- vl = entryvalue();
- lputb(PADDR(vl)); /* va of entry */
- lputb(spsize); /* sp offsets */
- lputb(lcsize); /* line offsets */
- vputb(vl); /* va of entry */
- break;
- case Hplan9x64: /* plan9 */
- magic = 4*26*26+7;
- lputb(magic); /* magic */
- lputb(segtext.filelen); /* sizes */
- lputb(segdata.filelen);
- lputb(segdata.len - segdata.filelen);
- lputb(symsize); /* nsyms */
- lputb(entryvalue()); /* va of entry */
- lputb(spsize); /* sp offsets */
- lputb(lcsize); /* line offsets */
- break;
- case Hdarwin:
- asmbmacho();
- break;
- case Hlinux:
- case Hfreebsd:
- /* elf amd-64 */
-
- eh = getElfEhdr();
- startva = INITTEXT - HEADR;
-
- /* This null SHdr must appear before all others */
- sh = newElfShdr(elfstr[ElfStrEmpty]);
-
- /* program header info */
- pph = newElfPhdr();
- pph->type = PT_PHDR;
- pph->flags = PF_R + PF_X;
- pph->off = eh->ehsize;
- pph->vaddr = INITTEXT - HEADR + pph->off;
- pph->paddr = INITTEXT - HEADR + pph->off;
- pph->align = INITRND;
-
- if(!debug['d']) {
- /* interpreter */
- sh = newElfShdr(elfstr[ElfStrInterp]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->addralign = 1;
- if(interpreter == nil) {
- switch(HEADTYPE) {
- case Hlinux:
- interpreter = linuxdynld;
- break;
- case Hfreebsd:
- interpreter = freebsddynld;
- break;
- }
- }
- elfinterp(sh, startva, interpreter);
-
- ph = newElfPhdr();
- ph->type = PT_INTERP;
- ph->flags = PF_R;
- phsh(ph, sh);
- }
-
- elfphload(&segtext);
- elfphload(&segdata);
-
- /* Dynamic linking sections */
- if (!debug['d']) { /* -d suppresses dynamic loader format */
- /* S headers for dynamic linking */
- sh = newElfShdr(elfstr[ElfStrGot]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 8;
- sh->addralign = 8;
- shsym(sh, lookup(".got", 0));
-
- sh = newElfShdr(elfstr[ElfStrGotPlt]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 8;
- sh->addralign = 8;
- shsym(sh, lookup(".got.plt", 0));
-
- dynsym = eh->shnum;
- sh = newElfShdr(elfstr[ElfStrDynsym]);
- sh->type = SHT_DYNSYM;
- sh->flags = SHF_ALLOC;
- sh->entsize = ELF64SYMSIZE;
- sh->addralign = 8;
- sh->link = dynsym+1; // dynstr
- // sh->info = index of first non-local symbol (number of local symbols)
- shsym(sh, lookup(".dynsym", 0));
-
- sh = newElfShdr(elfstr[ElfStrDynstr]);
- sh->type = SHT_STRTAB;
- sh->flags = SHF_ALLOC;
- sh->addralign = 1;
- shsym(sh, lookup(".dynstr", 0));
-
- if(elfverneed) {
- sh = newElfShdr(elfstr[ElfStrGnuVersion]);
- sh->type = SHT_GNU_VERSYM;
- sh->flags = SHF_ALLOC;
- sh->addralign = 2;
- sh->link = dynsym;
- sh->entsize = 2;
- shsym(sh, lookup(".gnu.version", 0));
-
- sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
- sh->type = SHT_GNU_VERNEED;
- sh->flags = SHF_ALLOC;
- sh->addralign = 8;
- sh->info = elfverneed;
- sh->link = dynsym+1; // dynstr
- shsym(sh, lookup(".gnu.version_r", 0));
- }
-
- sh = newElfShdr(elfstr[ElfStrRelaPlt]);
- sh->type = SHT_RELA;
- sh->flags = SHF_ALLOC;
- sh->entsize = ELF64RELASIZE;
- sh->addralign = 8;
- sh->link = dynsym;
- sh->info = eh->shnum; // .plt
- shsym(sh, lookup(".rela.plt", 0));
-
- sh = newElfShdr(elfstr[ElfStrPlt]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_EXECINSTR;
- sh->entsize = 16;
- sh->addralign = 4;
- shsym(sh, lookup(".plt", 0));
-
- sh = newElfShdr(elfstr[ElfStrHash]);
- sh->type = SHT_HASH;
- sh->flags = SHF_ALLOC;
- sh->entsize = 4;
- sh->addralign = 8;
- sh->link = dynsym;
- shsym(sh, lookup(".hash", 0));
-
- sh = newElfShdr(elfstr[ElfStrRela]);
- sh->type = SHT_RELA;
- sh->flags = SHF_ALLOC;
- sh->entsize = ELF64RELASIZE;
- sh->addralign = 8;
- sh->link = dynsym;
- shsym(sh, lookup(".rela", 0));
-
- /* sh and PT_DYNAMIC for .dynamic section */
- sh = newElfShdr(elfstr[ElfStrDynamic]);
- sh->type = SHT_DYNAMIC;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 16;
- sh->addralign = 8;
- sh->link = dynsym+1; // dynstr
- shsym(sh, lookup(".dynamic", 0));
- ph = newElfPhdr();
- ph->type = PT_DYNAMIC;
- ph->flags = PF_R + PF_W;
- phsh(ph, sh);
-
- /*
- * Thread-local storage segment (really just size).
- */
- if(tlsoffset != 0) {
- ph = newElfPhdr();
- ph->type = PT_TLS;
- ph->flags = PF_R;
- ph->memsz = -tlsoffset;
- ph->align = 8;
- }
- }
-
- ph = newElfPhdr();
- ph->type = PT_GNU_STACK;
- ph->flags = PF_W+PF_R;
- ph->align = 8;
-
- if(elftextsh != eh->shnum)
- diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
- for(sect=segtext.sect; sect!=nil; sect=sect->next)
- elfshbits(sect);
- for(sect=segdata.sect; sect!=nil; sect=sect->next)
- elfshbits(sect);
-
- if (!debug['s']) {
- sh = newElfShdr(elfstr[ElfStrSymtab]);
- sh->type = SHT_SYMTAB;
- sh->off = symo;
- sh->size = symsize;
- sh->addralign = 8;
- sh->entsize = 24;
- sh->link = eh->shnum; // link to strtab
-
- sh = newElfShdr(elfstr[ElfStrStrtab]);
- sh->type = SHT_STRTAB;
- sh->off = symo+symsize;
- sh->size = elfstrsize;
- sh->addralign = 1;
-
- dwarfaddelfheaders();
- }
-
- sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
- sh->type = SHT_STRTAB;
- sh->addralign = 1;
- shsym(sh, lookup(".shstrtab", 0));
-
- /* Main header */
- eh->ident[EI_MAG0] = '\177';
- eh->ident[EI_MAG1] = 'E';
- eh->ident[EI_MAG2] = 'L';
- eh->ident[EI_MAG3] = 'F';
- if(HEADTYPE == Hfreebsd)
- eh->ident[EI_OSABI] = 9;
- eh->ident[EI_CLASS] = ELFCLASS64;
- eh->ident[EI_DATA] = ELFDATA2LSB;
- eh->ident[EI_VERSION] = EV_CURRENT;
-
- eh->type = ET_EXEC;
- eh->machine = EM_X86_64;
- eh->version = EV_CURRENT;
- eh->entry = entryvalue();
-
- pph->filesz = eh->phnum * eh->phentsize;
- pph->memsz = pph->filesz;
-
- seek(cout, 0, 0);
- a = 0;
- a += elfwritehdr();
- a += elfwritephdrs();
- a += elfwriteshdrs();
- cflush();
- if(a+elfwriteinterp() > ELFRESERVE)
- diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
- break;
- case Hwindows:
- asmbpe();
- break;
- }
- cflush();
-}
-
-void
-cflush(void)
-{
- int n;
-
- n = sizeof(buf.cbuf) - cbc;
- if(n)
- ewrite(cout, buf.cbuf, n);
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
-}
-
-/* Current position in file */
-vlong
-cpos(void)
-{
- return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc;
-}
-
-vlong
-rnd(vlong v, vlong r)
-{
- vlong c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
-
-void
-genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
-{
- Auto *a;
- Sym *s;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- put(s, s->name, 'T', s->value, s->size, s->version, 0);
-
- for(s=allsym; s!=S; s=s->allsym) {
- if(s->hide)
- continue;
- switch(s->type&~SSUB) {
- case SCONST:
- case SRODATA:
- case SDATA:
- case SELFDATA:
- case SMACHOGOT:
- case STYPE:
- case SSTRING:
- case SGOSTRING:
- case SWINDOWS:
- if(!s->reachable)
- continue;
- put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
- continue;
-
- case SBSS:
- if(!s->reachable)
- continue;
- put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
- continue;
-
- case SFILE:
- put(nil, s->name, 'f', s->value, 0, s->version, 0);
- continue;
- }
- }
-
- for(s = textp; s != nil; s = s->next) {
- if(s->text == nil)
- continue;
-
- /* filenames first */
- for(a=s->autom; a; a=a->link)
- if(a->type == D_FILE)
- put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
- else
- if(a->type == D_FILE1)
- put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
-
- put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
-
- /* frame, auto and param after */
- put(nil, ".frame", 'm', s->text->to.offset+8, 0, 0, 0);
-
- for(a=s->autom; a; a=a->link)
- if(a->type == D_AUTO)
- put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %ud\n", symsize);
- Bflush(&bso);
-}
diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go
deleted file mode 100644
index cc7782cfe..000000000
--- a/src/cmd/6l/doc.go
+++ /dev/null
@@ -1,51 +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.
-
-/*
-
-6l is a modified version of the Plan 9 linker. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2l
-
-Its target architecture is the x86-64, referred to by these tools as amd64.
-It reads files in .6 format generated by 6g, 6c, and 6a and emits
-a binary called 6.out by default.
-
-Major changes include:
- - support for ELF and Mach-O binary files
- - support for segmented stacks (this feature is implemented here, not in the compilers).
-
-
-Original options are listed in the link above.
-
-Options new in this version:
-
--d
- Elide the dynamic linking header. With this option, the binary
- is statically linked and does not refer to dynld. Without this option
- (the default), the binary's contents are identical but it is loaded with dynld.
--e
- Emit an extra ELF-compatible symbol table useful with tools such as
- nm, gdb, and oprofile. This option makes the binary file considerably larger.
--Hdarwin
- Write Apple Mach-O binaries (default when $GOOS is darwin)
--Hlinux
- Write Linux ELF binaries (default when $GOOS is linux)
--Hfreebsd
- Write FreeBSD ELF binaries (default when $GOOS is freebsd)
--Hwindows
- Write Windows PE32+ binaries (default when $GOOS is windows)
--I interpreter
- Set the ELF dynamic linker to use.
--L dir1 -L dir2
- Search for libraries (package files) in dir1, dir2, etc.
- The default is the single location $GOROOT/pkg/$GOOS_amd64.
--r dir1:dir2:...
- Set the dynamic linker search path when using ELF.
--V
- Print the linker version.
-
-
-*/
-package documentation
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
deleted file mode 100644
index f4ee6aa92..000000000
--- a/src/cmd/6l/l.h
+++ /dev/null
@@ -1,439 +0,0 @@
-// Inferno utils/6l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.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 <libc.h>
-#include <bio.h>
-#include "../6l/6.out.h"
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-enum
-{
- thechar = '6',
- PtrSize = 8
-};
-
-#define P ((Prog*)0)
-#define S ((Sym*)0)
-#define TNAME (cursym?cursym->name:noname)
-#define cput(c)\
- { *cbp++ = c;\
- if(--cbc <= 0)\
- cflush(); }
-
-typedef struct Adr Adr;
-typedef struct Prog Prog;
-typedef struct Sym Sym;
-typedef struct Auto Auto;
-typedef struct Optab Optab;
-typedef struct Movtab Movtab;
-typedef struct Reloc Reloc;
-
-struct Adr
-{
- union
- {
- vlong u0offset;
- char u0scon[8];
- Prog *u0cond; /* not used, but should be D_BRANCH */
- Ieee u0ieee;
- char *u0sbig;
- } u0;
- Sym* sym;
- short type;
- char index;
- char scale;
-};
-
-#define offset u0.u0offset
-#define scon u0.u0scon
-#define cond u0.u0cond
-#define ieee u0.u0ieee
-#define sbig u0.u0sbig
-
-struct Reloc
-{
- int32 off;
- uchar siz;
- int32 type;
- int64 add;
- Sym* sym;
-};
-
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* forwd;
- Prog* comefrom;
- Prog* link;
- Prog* pcond; /* work on this */
- vlong pc;
- int32 spadj;
- int32 line;
- short as;
- char ft; /* oclass cache */
- char tt;
- uchar mark; /* work on these */
- uchar back;
-
- char width; /* fake for DATA */
- char mode; /* 16, 32, or 64 */
-};
-#define datasize from.scale
-#define textflag from.scale
-#define iscall(p) ((p)->as == ACALL)
-
-struct Auto
-{
- Sym* asym;
- Auto* link;
- int32 aoffset;
- short type;
- Sym* gotype;
-};
-struct Sym
-{
- char* name;
- short type;
- short version;
- uchar dupok;
- uchar reachable;
- uchar dynexport;
- uchar special;
- uchar stkcheck;
- uchar hide;
- int32 dynid;
- int32 sig;
- int32 plt;
- int32 got;
- Sym* hash; // in hash table
- Sym* allsym; // in all symbol list
- Sym* next; // in text or data list
- Sym* sub; // in SSUB list
- Sym* outer; // container of sub
- vlong value;
- vlong size;
- Sym* gotype;
- char* file;
- char* dynimpname;
- char* dynimplib;
- char* dynimpvers;
-
- // STEXT
- Auto* autom;
- Prog* text;
-
- // SDATA, SBSS
- uchar* p;
- int32 np;
- int32 maxp;
- Reloc* r;
- int32 nr;
- int32 maxr;
-};
-struct Optab
-{
- short as;
- uchar* ytab;
- uchar prefix;
- uchar op[20];
-};
-struct Movtab
-{
- short as;
- uchar ft;
- uchar tt;
- uchar code;
- uchar op[4];
-};
-
-enum
-{
- MINSIZ = 8,
- STRINGSZ = 200,
- MINLC = 1,
- MAXIO = 8192,
- MAXHIST = 20, /* limit of path elements for history symbols */
-
- Yxxx = 0,
- Ynone,
- Yi0,
- Yi1,
- Yi8,
- Ys32,
- Yi32,
- Yi64,
- Yiauto,
- Yal,
- Ycl,
- Yax,
- Ycx,
- Yrb,
- Yrl,
- Yrf,
- Yf0,
- Yrx,
- Ymb,
- Yml,
- Ym,
- Ybr,
- Ycol,
-
- Ycs, Yss, Yds, Yes, Yfs, Ygs,
- Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
- Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8,
- Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
- Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64,
- Ymr, Ymm,
- Yxr, Yxm,
- Ymax,
-
- Zxxx = 0,
-
- Zlit,
- Z_rp,
- Zbr,
- Zcall,
- Zib_,
- Zib_rp,
- Zibo_m,
- Zibo_m_xm,
- Zil_,
- Zil_rp,
- Ziq_rp,
- Zilo_m,
- Ziqo_m,
- Zjmp,
- Zloop,
- Zo_iw,
- Zm_o,
- Zm_r,
- Zm_r_xm,
- Zm_r_i_xm,
- Zm_r_3d,
- Zm_r_xm_nr,
- Zr_m_xm_nr,
- Zibm_r, /* mmx1,mmx2/mem64,imm8 */
- Zmb_r,
- Zaut_r,
- Zo_m,
- Zo_m64,
- Zpseudo,
- Zr_m,
- Zr_m_xm,
- Zr_m_i_xm,
- Zrp_,
- Z_ib,
- Z_il,
- Zm_ibo,
- Zm_ilo,
- Zib_rr,
- Zil_rr,
- Zclr,
- Zbyte,
- Zmax,
-
- Px = 0,
- P32 = 0x32, /* 32-bit only */
- Pe = 0x66, /* operand escape */
- Pm = 0x0f, /* 2byte opcode escape */
- Pq = 0xff, /* both escape */
- Pb = 0xfe, /* byte operands */
- Pf2 = 0xf2, /* xmm escape 1 */
- Pf3 = 0xf3, /* xmm escape 2 */
- Pw = 0x48, /* Rex.w */
- Py = 0x80, /* defaults to 64-bit mode */
-
- Rxf = 1<<9, /* internal flag for Rxr on from */
- Rxt = 1<<8, /* internal flag for Rxr on to */
- Rxw = 1<<3, /* =1, 64-bit operand size */
- Rxr = 1<<2, /* extend modrm reg */
- Rxx = 1<<1, /* extend sib index */
- Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
-
- Maxand = 10, /* in -a output width of the byte codes */
-};
-
-EXTERN union
-{
- struct
- {
- char obuf[MAXIO]; /* output buffer */
- uchar ibuf[MAXIO]; /* input buffer */
- } u;
- char dbuf[1];
-} buf;
-
-#define cbuf u.obuf
-#define xbuf u.ibuf
-
-#pragma varargck type "A" uint
-#pragma varargck type "D" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "S" char*
-
-EXTERN int32 HEADR;
-EXTERN int32 HEADTYPE;
-EXTERN int32 INITRND;
-EXTERN vlong INITTEXT;
-EXTERN vlong INITDAT;
-EXTERN char* INITENTRY; /* entry point */
-EXTERN Biobuf bso;
-EXTERN int cbc;
-EXTERN char* cbp;
-EXTERN char* pcstr;
-EXTERN Auto* curauto;
-EXTERN Auto* curhist;
-EXTERN Prog* curp;
-EXTERN Sym* cursym;
-EXTERN Sym* datap;
-EXTERN vlong elfdatsize;
-EXTERN char debug[128];
-EXTERN char literal[32];
-EXTERN Sym* textp;
-EXTERN Sym* etextp;
-EXTERN char ycover[Ymax*Ymax];
-EXTERN uchar* andptr;
-EXTERN uchar* rexptr;
-EXTERN uchar and[30];
-EXTERN int reg[D_NONE];
-EXTERN int regrex[D_NONE+1];
-EXTERN int32 lcsize;
-EXTERN int nerrors;
-EXTERN char* noname;
-EXTERN char* outfile;
-EXTERN vlong pc;
-EXTERN char* interpreter;
-EXTERN char* rpath;
-EXTERN int32 spsize;
-EXTERN Sym* symlist;
-EXTERN int32 symsize;
-EXTERN int tlsoffset;
-EXTERN int version;
-EXTERN Prog zprg;
-EXTERN int dtype;
-EXTERN char* paramspace;
-EXTERN Sym* adrgotype; // type symbol on last Adr read
-EXTERN Sym* fromgotype; // type symbol on last p->from read
-
-EXTERN vlong textstksiz;
-EXTERN vlong textarg;
-
-extern Optab optab[];
-extern Optab* opindex[];
-extern char* anames[];
-
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Iconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Sconv(Fmt*);
-void addhist(int32, int);
-void addstackmark(void);
-Prog* appendp(Prog*);
-void asmb(void);
-void asmdyn(void);
-void asmins(Prog*);
-void asmsym(void);
-void asmelfsym(void);
-vlong atolwhex(char*);
-Prog* brchain(Prog*);
-Prog* brloop(Prog*);
-void buildop(void);
-void cflush(void);
-Prog* copyp(Prog*);
-vlong cpos(void);
-double cputime(void);
-void datblk(int32, int32);
-void deadcode(void);
-void diag(char*, ...);
-void dodata(void);
-void doelf(void);
-void domacho(void);
-void doprof1(void);
-void doprof2(void);
-void dostkoff(void);
-vlong entryvalue(void);
-void follow(void);
-void gethunk(void);
-void gotypestrings(void);
-void listinit(void);
-Sym* lookup(char*, int);
-void lputb(int32);
-void lputl(int32);
-void instinit(void);
-void main(int, char*[]);
-void* mysbrk(uint32);
-Prog* newtext(Prog*, Sym*);
-void nopout(Prog*);
-int opsize(Prog*);
-void patch(void);
-Prog* prg(void);
-void parsetextconst(vlong);
-int relinv(int);
-vlong rnd(vlong, vlong);
-void span(void);
-void undef(void);
-vlong symaddr(Sym*);
-void vputb(uint64);
-void vputl(uint64);
-void wputb(uint16);
-void wputl(uint16);
-void xdefine(char*, int, vlong);
-
-void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32);
-void machsymseg(uint32, uint32);
-void machsect(char*, char*, vlong, vlong, uint32, uint32, uint32, uint32, uint32);
-void machstack(vlong);
-void machdylink(void);
-uint32 machheadr(void);
-
-/* Native is little-endian */
-#define LPUT(a) lputl(a)
-#define WPUT(a) wputl(a)
-#define VPUT(a) vputl(a)
-
-#pragma varargck type "D" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "A" int
-#pragma varargck argpos diag 1
-
-/* Used by ../ld/dwarf.c */
-enum
-{
- DWARFREGSP = 7
-};
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
deleted file mode 100644
index f39efa2e8..000000000
--- a/src/cmd/6l/list.c
+++ /dev/null
@@ -1,458 +0,0 @@
-// Inferno utils/6l/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/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.
-
-// Printing.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-static Prog* bigP;
-
-void
-listinit(void)
-{
-
- fmtinstall('R', Rconv);
- fmtinstall('A', Aconv);
- fmtinstall('D', Dconv);
- fmtinstall('S', Sconv);
- fmtinstall('P', Pconv);
- fmtinstall('I', Iconv);
-}
-
-int
-Pconv(Fmt *fp)
-{
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- bigP = p;
- switch(p->as) {
- case ATEXT:
- if(p->from.scale) {
- fmtprint(fp, "(%d) %A %D,%d,%D",
- p->line, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- default:
- fmtprint(fp, "(%d) %A %D,%D",
- p->line, p->as, &p->from, &p->to);
- break;
- case ADATA:
- case AINIT_:
- case ADYNT_:
- fmtprint(fp, "(%d) %A %D/%d,%D",
- p->line, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- bigP = P;
- return 0;
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Adr *a;
- int i;
-
- a = va_arg(fp->args, Adr*);
- i = a->type;
-
- if(fp->flags & FmtLong) {
- if(i != D_CONST) {
- // ATEXT dst is not constant
- snprint(str, sizeof(str), "!!%D", a);
- goto brk;
- }
- parsetextconst(a->offset);
- if(textarg == 0) {
- snprint(str, sizeof(str), "$%lld", textstksiz);
- goto brk;
- }
- snprint(str, sizeof(str), "$%lld-%lld", textstksiz, textarg);
- goto brk;
- }
-
- if(i >= D_INDIR) {
- if(a->offset)
- snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR);
- else
- snprint(str, sizeof(str), "(%R)", i-D_INDIR);
- goto brk;
- }
- switch(i) {
-
- default:
- if(a->offset)
- snprint(str, sizeof(str), "$%lld,%R", a->offset, i);
- else
- snprint(str, sizeof(str), "%R", i);
- break;
-
- case D_NONE:
- str[0] = 0;
- break;
-
- case D_BRANCH:
- if(bigP != P && bigP->pcond != P)
- if(a->sym != S)
- snprint(str, sizeof(str), "%llux+%s", bigP->pcond->pc,
- a->sym->name);
- else
- snprint(str, sizeof(str), "%llux", bigP->pcond->pc);
- else
- snprint(str, sizeof(str), "%lld(PC)", a->offset);
- break;
-
- case D_EXTERN:
- if(a->sym) {
- snprint(str, sizeof(str), "%s+%lld(SB)", a->sym->name, a->offset);
- break;
- }
- snprint(str, sizeof(str), "!!noname!!+%lld(SB)", a->offset);
- break;
-
- case D_STATIC:
- if(a->sym) {
- snprint(str, sizeof(str), "%s<%d>+%lld(SB)", a->sym->name,
- a->sym->version, a->offset);
- break;
- }
- snprint(str, sizeof(str), "!!noname!!<999>+%lld(SB)", a->offset);
- break;
-
- case D_AUTO:
- if(a->sym) {
- snprint(str, sizeof(str), "%s+%lld(SP)", a->sym->name, a->offset);
- break;
- }
- snprint(str, sizeof(str), "!!noname!!+%lld(SP)", a->offset);
- break;
-
- case D_PARAM:
- if(a->sym) {
- snprint(str, sizeof(str), "%s+%lld(%s)", a->sym->name, a->offset, paramspace);
- break;
- }
- snprint(str, sizeof(str), "!!noname!!+%lld(%s)", a->offset, paramspace);
- break;
-
- case D_CONST:
- snprint(str, sizeof(str), "$%lld", a->offset);
- break;
-
- case D_FCONST:
- snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
- break;
-
- case D_SCONST:
- snprint(str, sizeof(str), "$\"%S\"", a->scon);
- break;
-
- case D_ADDR:
- a->type = a->index;
- a->index = D_NONE;
- snprint(str, sizeof(str), "$%D", a);
- a->index = a->type;
- a->type = D_ADDR;
- goto conv;
- }
-brk:
- if(a->index != D_NONE) {
- snprint(s, sizeof(s), "(%R*%d)", a->index, a->scale);
- strcat(str, s);
- }
-conv:
- fmtstrcpy(fp, str);
-// if(a->gotype)
-// fmtprint(fp, "«%s»", a->gotype->name);
- return 0;
-
-}
-
-char* regstr[] =
-{
- "AL", /* [D_AL] */
- "CL",
- "DL",
- "BL",
- "SPB",
- "BPB",
- "SIB",
- "DIB",
- "R8B",
- "R9B",
- "R10B",
- "R11B",
- "R12B",
- "R13B",
- "R14B",
- "R15B",
-
- "AX", /* [D_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
- "R8",
- "R9",
- "R10",
- "R11",
- "R12",
- "R13",
- "R14",
- "R15",
-
- "AH",
- "CH",
- "DH",
- "BH",
-
- "F0", /* [D_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "M0",
- "M1",
- "M2",
- "M3",
- "M4",
- "M5",
- "M6",
- "M7",
-
- "X0",
- "X1",
- "X2",
- "X3",
- "X4",
- "X5",
- "X6",
- "X7",
- "X8",
- "X9",
- "X10",
- "X11",
- "X12",
- "X13",
- "X14",
- "X15",
-
- "CS", /* [D_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
-
- "CR0", /* [D_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
- "CR8",
- "CR9",
- "CR10",
- "CR11",
- "CR12",
- "CR13",
- "CR14",
- "CR15",
-
- "DR0", /* [D_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [D_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "NONE", /* [D_NONE] */
-};
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r >= D_AL && r <= D_NONE)
- snprint(str, sizeof(str), "%s", regstr[r-D_AL]);
- else
- snprint(str, sizeof(str), "gok(%d)", r);
-
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(double); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- 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);
-}
-
-int
-Iconv(Fmt *fp)
-{
- int i, n;
- uchar *p;
- char *s;
- Fmt fmt;
-
- n = fp->prec;
- fp->prec = 0;
- if(!(fp->flags&FmtPrec) || n < 0)
- return fmtstrcpy(fp, "%I");
- fp->flags &= ~FmtPrec;
- p = va_arg(fp->args, uchar*);
-
- // format into temporary buffer and
- // call fmtstrcpy to handle padding.
- fmtstrinit(&fmt);
- for(i=0; i<n; i++)
- fmtprint(&fmt, "%.2ux", *p++);
- s = fmtstrflush(&fmt);
- fmtstrcpy(fp, s);
- free(s);
- return 0;
-}
-
-void
-diag(char *fmt, ...)
-{
- char buf[STRINGSZ], *tn, *sep;
- va_list arg;
-
- tn = "";
- sep = "";
- if(cursym != S) {
- tn = cursym->name;
- sep = ": ";
- }
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- print("%s%s%s\n", tn, sep, buf);
-
- nerrors++;
- if(nerrors > 20) {
- print("too many errors\n");
- errorexit();
- }
-}
-
-void
-parsetextconst(vlong arg)
-{
- textstksiz = arg & 0xffffffffLL;
- if(textstksiz & 0x80000000LL)
- textstksiz = -(-textstksiz & 0xffffffffLL);
-
- textarg = (arg >> 32) & 0xffffffffLL;
- if(textarg & 0x80000000LL)
- textarg = 0;
- textarg = (textarg+7) & ~7LL;
-}
diff --git a/src/cmd/6l/mkenam b/src/cmd/6l/mkenam
deleted file mode 100644
index 3001dbe93..000000000
--- a/src/cmd/6l/mkenam
+++ /dev/null
@@ -1,45 +0,0 @@
-# Inferno utils/6c/mkenam
-# http://code.google.com/p/inferno-os/source/browse/utils/6c/mkenam
-#
-# 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.
-
-awk '
-BEGIN {
- print "char* anames[] ="
- print "{"
-}
-
-/^ A/ {
- name=$1
- sub(/,/, "", name)
- sub(/^A/, "", name)
- print "\t\"" name "\","
-}
-
-END { print "};" }
-' ../6l/6.out.h >enam.c
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
deleted file mode 100644
index e3191bb4d..000000000
--- a/src/cmd/6l/obj.c
+++ /dev/null
@@ -1,756 +0,0 @@
-// Inferno utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/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.
-
-#define EXTERN
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-#include "../ld/macho.h"
-#include "../ld/dwarf.h"
-#include "../ld/pe.h"
-#include <ar.h>
-
-char *noname = "<none>";
-char* thestring = "amd64";
-char* paramspace = "FP";
-
-Header headers[] = {
- "plan9x32", Hplan9x32,
- "plan9", Hplan9x64,
- "elf", Helf,
- "darwin", Hdarwin,
- "linux", Hlinux,
- "freebsd", Hfreebsd,
- "windows", Hwindows,
- "windowsgui", Hwindows,
- 0, 0
-};
-
-/*
- * -Hplan9x32 -T4136 -R4096 is plan9 64-bit format
- * -Hplan9 -T4128 -R4096 is plan9 32-bit format
- * -Helf -T0x80110000 -R4096 is ELF32
- * -Hdarwin -Tx -Rx is apple MH-exec
- * -Hlinux -Tx -Rx is linux elf-exec
- * -Hfreebsd -Tx -Rx is FreeBSD elf-exec
- * -Hwindows -Tx -Rx is MS Windows PE32+
- *
- * options used: 189BLQSWabcjlnpsvz
- */
-
-void
-usage(void)
-{
- fprint(2, "usage: 6l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.6\n");
- exits("usage");
-}
-
-void
-main(int argc, char *argv[])
-{
- int c;
-
- Binit(&bso, 1, OWRITE);
- cout = -1;
- listinit();
- memset(debug, 0, sizeof(debug));
- nerrors = 0;
- outfile = "6.out";
- HEADTYPE = -1;
- INITTEXT = -1;
- INITDAT = -1;
- INITRND = -1;
- INITENTRY = 0;
-
- ARGBEGIN {
- default:
- c = ARGC();
- if(c == 'l')
- usage();
- if(c >= 0 && c < sizeof(debug))
- debug[c]++;
- break;
- case 'o': /* output to (next arg) */
- outfile = EARGF(usage());
- break;
- case 'E':
- INITENTRY = EARGF(usage());
- break;
- case 'H':
- HEADTYPE = headtype(EARGF(usage()));
- break;
- case 'I':
- interpreter = EARGF(usage());
- break;
- case 'L':
- Lflag(EARGF(usage()));
- break;
- case 'T':
- INITTEXT = atolwhex(EARGF(usage()));
- break;
- case 'D':
- INITDAT = atolwhex(EARGF(usage()));
- break;
- case 'R':
- INITRND = atolwhex(EARGF(usage()));
- break;
- case 'r':
- rpath = EARGF(usage());
- break;
- case 'V':
- print("%cl version %s\n", thechar, getgoversion());
- errorexit();
- } ARGEND
-
- if(argc != 1)
- usage();
-
- libinit();
-
- if(HEADTYPE == -1)
- HEADTYPE = headtype(goos);
-
- switch(HEADTYPE) {
- default:
- diag("unknown -H option");
- errorexit();
- case Hplan9x32: /* plan 9 */
- HEADR = 32L+8L;
- if(INITTEXT == -1)
- INITTEXT = 4096+HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Hplan9x64: /* plan 9 */
- HEADR = 32L;
- if(INITTEXT == -1)
- INITTEXT = 4096+32;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Helf: /* elf32 executable */
- HEADR = rnd(52L+3*32L, 16);
- if(INITTEXT == -1)
- INITTEXT = 0x80110000L;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Hdarwin: /* apple MACH */
- /*
- * OS X system constant - offset from 0(GS) to our TLS.
- * Explained in ../../libcgo/darwin_amd64.c.
- */
- tlsoffset = 0x8a0;
- machoinit();
- HEADR = INITIAL_MACHO_HEADR;
- if(INITRND == -1)
- INITRND = 4096;
- if(INITTEXT == -1)
- INITTEXT = 4096+HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- break;
- case Hlinux: /* elf64 executable */
- case Hfreebsd: /* freebsd */
- /*
- * ELF uses TLS offset negative from FS.
- * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
- * Also known to ../../pkg/runtime/linux/amd64/sys.s
- * and ../../libcgo/linux_amd64.s.
- */
- tlsoffset = -16;
- elfinit();
- HEADR = ELFRESERVE;
- if(INITTEXT == -1)
- INITTEXT = (1<<22)+HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Hwindows: /* PE executable */
- peinit();
- HEADR = PEFILEHEADR;
- if(INITTEXT == -1)
- INITTEXT = PEBASE+PESECTHEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = PESECTALIGN;
- break;
- }
- if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%llux is ignored because of -R0x%ux\n",
- INITDAT, INITRND);
- if(debug['v'])
- Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
- HEADTYPE, INITTEXT, INITDAT, INITRND);
- Bflush(&bso);
- instinit();
-
- zprg.link = P;
- zprg.pcond = P;
- zprg.back = 2;
- zprg.as = AGOK;
- zprg.from.type = D_NONE;
- zprg.from.index = D_NONE;
- zprg.from.scale = 1;
- zprg.to = zprg.from;
- zprg.mode = 64;
-
- pcstr = "%.6llux ";
- nuxiinit();
- histgen = 0;
- pc = 0;
- dtype = 4;
- version = 0;
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
-
- addlibpath("command line", "command line", argv[0], "main");
- loadlib();
- deadcode();
- patch();
- follow();
- doelf();
- if(HEADTYPE == Hdarwin)
- domacho();
- dostkoff();
- dostkcheck();
- paramspace = "SP"; /* (FP) now (SP) on output */
- if(debug['p'])
- if(debug['1'])
- doprof1();
- else
- doprof2();
- span();
- if(HEADTYPE == Hwindows)
- dope();
- addexport();
- textaddress();
- pclntab();
- symtab();
- dodata();
- address();
- doweak();
- reloc();
- asmb();
- undef();
- if(debug['v']) {
- Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%d symbols\n", nsymbol);
- Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
- Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
- }
- Bflush(&bso);
-
- errorexit();
-}
-
-static Sym*
-zsym(char *pn, Biobuf *f, Sym *h[])
-{
- int o;
-
- o = BGETC(f);
- if(o < 0 || o >= NSYM || h[o] == nil)
- mangle(pn);
- return h[o];
-}
-
-static void
-zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
-{
- int t;
- int32 l;
- Sym *s;
- Auto *u;
-
- t = BGETC(f);
- a->index = D_NONE;
- a->scale = 0;
- if(t & T_INDEX) {
- a->index = BGETC(f);
- a->scale = BGETC(f);
- }
- a->offset = 0;
- if(t & T_OFFSET) {
- a->offset = Bget4(f);
- if(t & T_64) {
- a->offset &= 0xFFFFFFFFULL;
- a->offset |= (vlong)Bget4(f) << 32;
- }
- }
- a->sym = S;
- if(t & T_SYM)
- a->sym = zsym(pn, f, h);
- a->type = D_NONE;
- if(t & T_FCONST) {
- a->ieee.l = Bget4(f);
- a->ieee.h = Bget4(f);
- a->type = D_FCONST;
- } else
- if(t & T_SCONST) {
- Bread(f, a->scon, NSNAME);
- a->type = D_SCONST;
- }
- if(t & T_TYPE)
- a->type = BGETC(f);
- if(a->type < 0 || a->type >= D_SIZE)
- mangle(pn);
- adrgotype = S;
- if(t & T_GOTYPE)
- adrgotype = zsym(pn, f, h);
- s = a->sym;
- t = a->type;
- if(t == D_INDIR+D_GS)
- a->offset += tlsoffset;
- if(t != D_AUTO && t != D_PARAM) {
- if(s && adrgotype)
- s->gotype = adrgotype;
- return;
- }
- l = a->offset;
- for(u=curauto; u; u=u->link) {
- if(u->asym == s)
- if(u->type == t) {
- if(u->aoffset > l)
- u->aoffset = l;
- if(adrgotype)
- u->gotype = adrgotype;
- return;
- }
- }
-
- switch(t) {
- case D_FILE:
- case D_FILE1:
- case D_AUTO:
- case D_PARAM:
- if(s == S)
- mangle(pn);
- }
-
- u = mal(sizeof(*u));
- u->link = curauto;
- curauto = u;
- u->asym = s;
- u->aoffset = l;
- u->type = t;
- u->gotype = adrgotype;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
-}
-
-void
-ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- vlong ipc;
- Prog *p;
- int v, o, r, skip, mode;
- Sym *h[NSYM], *s;
- uint32 sig;
- char *name, *x;
- int ntext;
- vlong eof;
- char src[1024];
- Prog *lastp;
-
- lastp = nil;
- ntext = 0;
- eof = Boffset(f) + len;
- src[0] = 0;
-
-newloop:
- memset(h, 0, sizeof(h));
- version++;
- histfrogp = 0;
- ipc = pc;
- skip = 0;
- mode = 64;
-
-loop:
- if(f->state == Bracteof || Boffset(f) >= eof)
- goto eof;
- o = BGETC(f);
- if(o == Beof)
- goto eof;
- o |= BGETC(f) << 8;
- if(o <= AXXX || o >= ALAST) {
- if(o < 0)
- goto eof;
- diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
- print(" probably not a .6 file\n");
- errorexit();
- }
-
- if(o == ANAME || o == ASIGNAME) {
- sig = 0;
- if(o == ASIGNAME)
- sig = Bget4(f);
- v = BGETC(f); /* type */
- o = BGETC(f); /* sym */
- r = 0;
- if(v == D_STATIC)
- r = version;
- name = Brdline(f, '\0');
- if(name == nil) {
- if(Blinelen(f) > 0) {
- fprint(2, "%s: name too long\n", pn);
- errorexit();
- }
- goto eof;
- }
- x = expandpkg(name, pkg);
- s = lookup(x, r);
- if(x != name)
- free(x);
- name = nil;
-
- if(debug['S'] && r == 0)
- sig = 1729;
- if(sig != 0){
- if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures"
- "%ux(%s) and %ux(%s) for %s",
- s->sig, s->file, sig, pn, s->name);
- s->sig = sig;
- s->file = pn;
- }
-
- if(debug['W'])
- print(" ANAME %s\n", s->name);
- if(o < 0 || o >= nelem(h))
- mangle(pn);
- h[o] = s;
- if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
- s->type = SXREF;
- if(v == D_FILE) {
- if(s->type != SFILE) {
- histgen++;
- s->type = SFILE;
- s->value = histgen;
- }
- if(histfrogp < MAXHIST) {
- histfrog[histfrogp] = s;
- histfrogp++;
- } else
- collapsefrog(s);
- dwarfaddfrag(s->value, s->name);
- }
- goto loop;
- }
-
- p = mal(sizeof(*p));
- p->as = o;
- p->line = Bget4(f);
- p->back = 2;
- p->mode = mode;
- p->ft = 0;
- p->tt = 0;
- zaddr(pn, f, &p->from, h);
- fromgotype = adrgotype;
- zaddr(pn, f, &p->to, h);
-
- switch(p->as) {
- case ATEXT:
- case ADATA:
- case AGLOBL:
- if(p->from.sym == S)
- mangle(pn);
- break;
- }
-
- if(debug['W'])
- print("%P\n", p);
-
- switch(p->as) {
- case AHISTORY:
- if(p->to.offset == -1) {
- addlib(src, pn);
- histfrogp = 0;
- goto loop;
- }
- if(src[0] == '\0')
- copyhistfrog(src, sizeof src);
- addhist(p->line, D_FILE); /* 'z' */
- if(p->to.offset)
- addhist(p->to.offset, D_FILE1); /* 'Z' */
- histfrogp = 0;
- goto loop;
-
- case AEND:
- histtoauto();
- if(cursym != nil && cursym->text)
- cursym->autom = curauto;
- curauto = 0;
- cursym = nil;
- if(Boffset(f) == eof)
- return;
- goto newloop;
-
- case AGLOBL:
- s = p->from.sym;
- if(s->type == 0 || s->type == SXREF) {
- s->type = SBSS;
- s->size = 0;
- }
- if(s->type != SBSS && !s->dupok) {
- diag("%s: redefinition: %s in %s",
- pn, s->name, TNAME);
- s->type = SBSS;
- s->size = 0;
- }
- if(p->to.offset > s->size)
- s->size = p->to.offset;
- if(p->from.scale & DUPOK)
- s->dupok = 1;
- if(p->from.scale & RODATA)
- s->type = SRODATA;
- goto loop;
-
- case ADATA:
- // Assume that AGLOBL comes after ADATA.
- // If we've seen an AGLOBL that said this sym was DUPOK,
- // ignore any more ADATA we see, which must be
- // redefinitions.
- s = p->from.sym;
- if(s->dupok) {
-// if(debug['v'])
-// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
- goto loop;
- }
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
- savedata(s, p, pn);
- unmal(p, sizeof *p);
- goto loop;
-
- case AGOK:
- diag("%s: GOK opcode in %s", pn, TNAME);
- pc++;
- goto loop;
-
- case ATEXT:
- s = p->from.sym;
- if(s->text != nil) {
- diag("%s: %s: redefinition", pn, s->name);
- return;
- }
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- if(cursym != nil && cursym->text) {
- histtoauto();
- cursym->autom = curauto;
- curauto = 0;
- }
- skip = 0;
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- s->text = p;
- cursym = s;
- if(s->type != 0 && s->type != SXREF) {
- if(p->from.scale & DUPOK) {
- skip = 1;
- goto casdef;
- }
- diag("%s: redefinition: %s\n%P", pn, s->name, p);
- }
- if(fromgotype) {
- if(s->gotype && s->gotype != fromgotype)
- diag("%s: type mismatch for %s", pn, s->name);
- s->gotype = fromgotype;
- }
- s->type = STEXT;
- s->value = pc;
- lastp = p;
- p->pc = pc++;
- goto loop;
-
- case AMODE:
- if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
- switch((int)p->from.offset){
- case 16: case 32: case 64:
- mode = p->from.offset;
- break;
- }
- }
- goto loop;
-
- case AFMOVF:
- case AFADDF:
- case AFSUBF:
- case AFSUBRF:
- case AFMULF:
- case AFDIVF:
- case AFDIVRF:
- case AFCOMF:
- case AFCOMFP:
- case AMOVSS:
- case AADDSS:
- case ASUBSS:
- case AMULSS:
- case ADIVSS:
- case ACOMISS:
- case AUCOMISS:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 9 max */
- sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SDATA;
- adduint32(s, ieeedtof(&p->from.ieee));
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- case AFMOVD:
- case AFADDD:
- case AFSUBD:
- case AFSUBRD:
- case AFMULD:
- case AFDIVD:
- case AFDIVRD:
- case AFCOMD:
- case AFCOMDP:
- case AMOVSD:
- case AADDSD:
- case ASUBSD:
- case AMULSD:
- case ADIVSD:
- case ACOMISD:
- case AUCOMISD:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 18 max */
- sprint(literal, "$%ux.%ux",
- p->from.ieee.l, p->from.ieee.h);
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SDATA;
- adduint32(s, p->from.ieee.l);
- adduint32(s, p->from.ieee.h);
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- casdef:
- default:
- if(skip)
- nopout(p);
- p->pc = pc;
- pc++;
-
- if(p->to.type == D_BRANCH)
- p->to.offset += ipc;
- if(lastp == nil) {
- if(p->as != ANOP)
- diag("unexpected instruction: %P", p);
- goto loop;
- }
- lastp->link = p;
- lastp = p;
- goto loop;
- }
- goto loop;
-
-eof:
- diag("truncated object file: %s", pn);
-}
-
-Prog*
-prg(void)
-{
- Prog *p;
-
- p = mal(sizeof(*p));
-
- *p = zprg;
- return p;
-}
-
-Prog*
-copyp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- *p = *q;
- return p;
-}
-
-Prog*
-appendp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- p->link = q->link;
- q->link = p;
- p->line = q->line;
- p->mode = q->mode;
- return p;
-}
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
deleted file mode 100644
index 6cc50313e..000000000
--- a/src/cmd/6l/optab.c
+++ /dev/null
@@ -1,1213 +0,0 @@
-// Inferno utils/6l/optab.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/optab.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 "l.h"
-
-uchar ynone[] =
-{
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar ytext[] =
-{
- Ymb, Yi64, Zpseudo,1,
- 0
-};
-uchar ynop[] =
-{
- Ynone, Ynone, Zpseudo,1,
- Ynone, Yml, Zpseudo,1,
- Ynone, Yrf, Zpseudo,1,
- Yml, Ynone, Zpseudo,1,
- Yrf, Ynone, Zpseudo,1,
- 0
-};
-uchar yxorb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yxorl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yaddl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yincb[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yincw[] =
-{
- Ynone, Yml, Zo_m, 2,
- 0
-};
-uchar yincl[] =
-{
- Ynone, Yml, Zo_m, 2,
- 0
-};
-uchar ycmpb[] =
-{
- Yal, Yi32, Z_ib, 1,
- Ymb, Yi32, Zm_ibo, 2,
- Ymb, Yrb, Zm_r, 1,
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar ycmpl[] =
-{
- Yml, Yi8, Zm_ibo, 2,
- Yax, Yi32, Z_il, 1,
- Yml, Yi32, Zm_ilo, 2,
- Yml, Yrl, Zm_r, 1,
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yshb[] =
-{
- Yi1, Ymb, Zo_m, 2,
- Yi32, Ymb, Zibo_m, 2,
- Ycx, Ymb, Zo_m, 2,
- 0
-};
-uchar yshl[] =
-{
- Yi1, Yml, Zo_m, 2,
- Yi32, Yml, Zibo_m, 2,
- Ycl, Yml, Zo_m, 2,
- Ycx, Yml, Zo_m, 2,
- 0
-};
-uchar ytestb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar ytestl[] =
-{
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ymovb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- Yi32, Yrb, Zib_rp, 1,
- Yi32, Ymb, Zibo_m, 2,
- 0
-};
-uchar ymbs[] =
-{
- Ymb, Ynone, Zm_o, 2,
- 0
-};
-uchar ybtl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar ymovw[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1,
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yiauto, Yrl, Zaut_r, 2,
- 0
-};
-uchar ymovl[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1,
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yml, Ymr, Zm_r_xm, 1, // MMX MOVD
- Ymr, Yml, Zr_m_xm, 1, // MMX MOVD
- Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
- Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
- Yiauto, Yrl, Zaut_r, 2,
- 0
-};
-uchar yret[] =
-{
- Ynone, Ynone, Zo_iw, 1,
- Yi32, Ynone, Zo_iw, 1,
- 0
-};
-uchar ymovq[] =
-{
- Yrl, Yml, Zr_m, 1, // 0x89
- Yml, Yrl, Zm_r, 1, // 0x8b
- Yi0, Yrl, Zclr, 1, // 0x31
- Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0)
- Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate
- Yi32, Yml, Zilo_m, 2, // 0xc7,(0)
- Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding)
- Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ
- Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD
- Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD
- Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q
- Yxr, Ym, Zr_m_xm_nr, 2, // MOVQ xmm store
- Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load
- Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store
- Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ
- 0
-};
-uchar ym_rl[] =
-{
- Ym, Yrl, Zm_r, 1,
- 0
-};
-uchar yrl_m[] =
-{
- Yrl, Ym, Zr_m, 1,
- 0
-};
-uchar ymb_rl[] =
-{
- Ymb, Yrl, Zmb_r, 1,
- 0
-};
-uchar yml_rl[] =
-{
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yrl_ml[] =
-{
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yml_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yrb_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar yml_ml[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ydivl[] =
-{
- Yml, Ynone, Zm_o, 2,
- 0
-};
-uchar ydivb[] =
-{
- Ymb, Ynone, Zm_o, 2,
- 0
-};
-uchar yimul[] =
-{
- Yml, Ynone, Zm_o, 2,
- Yi8, Yrl, Zib_rr, 1,
- Yi32, Yrl, Zil_rr, 1,
- Yml, Yrl, Zm_r, 2,
- 0
-};
-uchar ybyte[] =
-{
- Yi64, Ynone, Zbyte, 1,
- 0
-};
-uchar yin[] =
-{
- Yi32, Ynone, Zib_, 1,
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar yint[] =
-{
- Yi32, Ynone, Zib_, 1,
- 0
-};
-uchar ypushl[] =
-{
- Yrl, Ynone, Zrp_, 1,
- Ym, Ynone, Zm_o, 2,
- Yi8, Ynone, Zib_, 1,
- Yi32, Ynone, Zil_, 1,
- 0
-};
-uchar ypopl[] =
-{
- Ynone, Yrl, Z_rp, 1,
- Ynone, Ym, Zo_m, 2,
- 0
-};
-uchar yscond[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yjcond[] =
-{
- Ynone, Ybr, Zbr, 1,
- 0
-};
-uchar yloop[] =
-{
- Ynone, Ybr, Zloop, 1,
- 0
-};
-uchar ycall[] =
-{
- Ynone, Yml, Zo_m64, 2,
- Ynone, Ybr, Zcall, 1,
- 0
-};
-uchar yjmp[] =
-{
- Ynone, Yml, Zo_m64, 2,
- Ynone, Ybr, Zjmp, 1,
- 0
-};
-
-uchar yfmvd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvdp[] =
-{
- Yf0, Ym, Zo_m, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvf[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfmvx[] =
-{
- Ym, Yf0, Zm_o, 2,
- 0
-};
-uchar yfmvp[] =
-{
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfadd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfaddp[] =
-{
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfxch[] =
-{
- Yf0, Yrf, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- 0
-};
-uchar ycompp[] =
-{
- Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
- 0
-};
-uchar ystsw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ynone, Yax, Zlit, 1,
- 0
-};
-uchar ystcw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ysvrs[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ymm[] =
-{
- Ymm, Ymr, Zm_r_xm, 1,
- Yxm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxm[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcvm1[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- Yxm, Ymr, Zm_r_xm, 2,
- 0
-};
-uchar yxcvm2[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- Ymm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxmq[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxr[] =
-{
- Yxr, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxr_ml[] =
-{
- Yxr, Yml, Zr_m_xm, 1,
- 0
-};
-uchar ymr[] =
-{
- Ymr, Ymr, Zm_r, 1,
- 0
-};
-uchar ymr_ml[] =
-{
- Ymr, Yml, Zr_m_xm, 1,
- 0
-};
-uchar yxcmp[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcmpi[] =
-{
- Yxm, Yxr, Zm_r_i_xm, 2,
- 0
-};
-uchar yxmov[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- Yxr, Yxm, Zr_m_xm, 1,
- 0
-};
-uchar yxcvfl[] =
-{
- Yxm, Yrl, Zm_r_xm, 1,
- 0
-};
-uchar yxcvlf[] =
-{
- Yml, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcvfq[] =
-{
- Yxm, Yrl, Zm_r_xm, 2,
- 0
-};
-uchar yxcvqf[] =
-{
- Yml, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yps[] =
-{
- Ymm, Ymr, Zm_r_xm, 1,
- Yi8, Ymr, Zibo_m_xm, 2,
- Yxm, Yxr, Zm_r_xm, 2,
- Yi8, Yxr, Zibo_m_xm, 3,
- 0
-};
-uchar yxrrl[] =
-{
- Yxr, Yrl, Zm_r, 1,
- 0
-};
-uchar ymfp[] =
-{
- Ymm, Ymr, Zm_r_3d, 1,
- 0,
-};
-uchar ymrxr[] =
-{
- Ymr, Yxr, Zm_r, 1,
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar ymshuf[] =
-{
- Ymm, Ymr, Zibm_r, 1,
- 0
-};
-uchar yxshuf[] =
-{
- Yxm, Yxr, Zibm_r, 1,
- 0
-};
-uchar yextrw[] =
-{
- Yxr, Yrl, Zibm_r, 1,
- 0
-};
-uchar ypsdq[] =
-{
- Yi8, Yxr, Zibo_m, 2,
- 0
-};
-uchar ymskb[] =
-{
- Yxr, Yrl, Zm_r_xm, 2,
- Ymr, Yrl, Zm_r_xm, 1,
- 0
-};
-
-Optab optab[] =
-/* as, ytab, andproto, opcode */
-{
- { AXXX },
- { AAAA, ynone, P32, 0x37 },
- { AAAD, ynone, P32, 0xd5,0x0a },
- { AAAM, ynone, P32, 0xd4,0x0a },
- { AAAS, ynone, P32, 0x3f },
- { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
- { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 },
- { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADDPD, yxm, Pq, 0x58 },
- { AADDPS, yxm, Pm, 0x58 },
- { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADDSD, yxm, Pf2, 0x58 },
- { AADDSS, yxm, Pf3, 0x58 },
- { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADJSP },
- { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
- { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AANDNPD, yxm, Pq, 0x55 },
- { AANDNPS, yxm, Pm, 0x55 },
- { AANDPD, yxm, Pq, 0x54 },
- { AANDPS, yxm, Pq, 0x54 },
- { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AARPL, yrl_ml, P32, 0x63 },
- { ABOUNDL, yrl_m, P32, 0x62 },
- { ABOUNDW, yrl_m, Pe, 0x62 },
- { ABSFL, yml_rl, Pm, 0xbc },
- { ABSFQ, yml_rl, Pw, 0x0f,0xbc },
- { ABSFW, yml_rl, Pq, 0xbc },
- { ABSRL, yml_rl, Pm, 0xbd },
- { ABSRQ, yml_rl, Pw, 0x0f,0xbd },
- { ABSRW, yml_rl, Pq, 0xbd },
- { ABTCL, ybtl, Pm, 0xba,(07),0xbb },
- { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb },
- { ABTCW, ybtl, Pq, 0xba,(07),0xbb },
- { ABTL, ybtl, Pm, 0xba,(04),0xa3 },
- { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3},
- { ABTRL, ybtl, Pm, 0xba,(06),0xb3 },
- { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 },
- { ABTRW, ybtl, Pq, 0xba,(06),0xb3 },
- { ABTSL, ybtl, Pm, 0xba,(05),0xab },
- { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab },
- { ABTSW, ybtl, Pq, 0xba,(05),0xab },
- { ABTW, ybtl, Pq, 0xba,(04),0xa3 },
- { ABYTE, ybyte, Px, 1 },
- { ACALL, ycall, Px, 0xff,(02),0xe8 },
- { ACDQ, ynone, Px, 0x99 },
- { ACLC, ynone, Px, 0xf8 },
- { ACLD, ynone, Px, 0xfc },
- { ACLI, ynone, Px, 0xfa },
- { ACLTS, ynone, Pm, 0x06 },
- { ACMC, ynone, Px, 0xf5 },
- { ACMOVLCC, yml_rl, Pm, 0x43 },
- { ACMOVLCS, yml_rl, Pm, 0x42 },
- { ACMOVLEQ, yml_rl, Pm, 0x44 },
- { ACMOVLGE, yml_rl, Pm, 0x4d },
- { ACMOVLGT, yml_rl, Pm, 0x4f },
- { ACMOVLHI, yml_rl, Pm, 0x47 },
- { ACMOVLLE, yml_rl, Pm, 0x4e },
- { ACMOVLLS, yml_rl, Pm, 0x46 },
- { ACMOVLLT, yml_rl, Pm, 0x4c },
- { ACMOVLMI, yml_rl, Pm, 0x48 },
- { ACMOVLNE, yml_rl, Pm, 0x45 },
- { ACMOVLOC, yml_rl, Pm, 0x41 },
- { ACMOVLOS, yml_rl, Pm, 0x40 },
- { ACMOVLPC, yml_rl, Pm, 0x4b },
- { ACMOVLPL, yml_rl, Pm, 0x49 },
- { ACMOVLPS, yml_rl, Pm, 0x4a },
- { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 },
- { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 },
- { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 },
- { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d },
- { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f },
- { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 },
- { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e },
- { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 },
- { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c },
- { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 },
- { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 },
- { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 },
- { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 },
- { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b },
- { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 },
- { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a },
- { ACMOVWCC, yml_rl, Pq, 0x43 },
- { ACMOVWCS, yml_rl, Pq, 0x42 },
- { ACMOVWEQ, yml_rl, Pq, 0x44 },
- { ACMOVWGE, yml_rl, Pq, 0x4d },
- { ACMOVWGT, yml_rl, Pq, 0x4f },
- { ACMOVWHI, yml_rl, Pq, 0x47 },
- { ACMOVWLE, yml_rl, Pq, 0x4e },
- { ACMOVWLS, yml_rl, Pq, 0x46 },
- { ACMOVWLT, yml_rl, Pq, 0x4c },
- { ACMOVWMI, yml_rl, Pq, 0x48 },
- { ACMOVWNE, yml_rl, Pq, 0x45 },
- { ACMOVWOC, yml_rl, Pq, 0x41 },
- { ACMOVWOS, yml_rl, Pq, 0x40 },
- { ACMOVWPC, yml_rl, Pq, 0x4b },
- { ACMOVWPL, yml_rl, Pq, 0x49 },
- { ACMOVWPS, yml_rl, Pq, 0x4a },
- { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
- { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPPD, yxcmpi, Px, Pe,0xc2 },
- { ACMPPS, yxcmpi, Pm, 0xc2,0 },
- { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPSB, ynone, Pb, 0xa6 },
- { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
- { ACMPSL, ynone, Px, 0xa7 },
- { ACMPSQ, ynone, Pw, 0xa7 },
- { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
- { ACMPSW, ynone, Pe, 0xa7 },
- { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACOMISD, yxcmp, Pe, 0x2f },
- { ACOMISS, yxcmp, Pm, 0x2f },
- { ACPUID, ynone, Pm, 0xa2 },
- { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
- { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
- { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
- { ACVTPD2PS, yxm, Pe, 0x5a },
- { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
- { ACVTPS2PD, yxm, Pm, 0x5a },
- { API2FW, ymfp, Px, 0x0c },
- { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
- { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d },
- { ACVTSD2SS, yxm, Pf2, 0x5a },
- { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
- { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a },
- { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
- { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a },
- { ACVTSS2SD, yxm, Pf3, 0x5a },
- { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
- { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d },
- { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
- { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
- { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
- { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c },
- { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
- { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c },
- { ACWD, ynone, Pe, 0x99 },
- { ACQO, ynone, Pw, 0x99 },
- { ADAA, ynone, P32, 0x27 },
- { ADAS, ynone, P32, 0x2f },
- { ADATA },
- { ADECB, yincb, Pb, 0xfe,(01) },
- { ADECL, yincl, Px, 0xff,(01) },
- { ADECQ, yincl, Pw, 0xff,(01) },
- { ADECW, yincw, Pe, 0xff,(01) },
- { ADIVB, ydivb, Pb, 0xf6,(06) },
- { ADIVL, ydivl, Px, 0xf7,(06) },
- { ADIVPD, yxm, Pe, 0x5e },
- { ADIVPS, yxm, Pm, 0x5e },
- { ADIVQ, ydivl, Pw, 0xf7,(06) },
- { ADIVSD, yxm, Pf2, 0x5e },
- { ADIVSS, yxm, Pf3, 0x5e },
- { ADIVW, ydivl, Pe, 0xf7,(06) },
- { AEMMS, ynone, Pm, 0x77 },
- { AENTER }, /* botch */
- { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) },
- { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) },
- { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) },
- { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) },
- { AGLOBL },
- { AGOK },
- { AHISTORY },
- { AHLT, ynone, Px, 0xf4 },
- { AIDIVB, ydivb, Pb, 0xf6,(07) },
- { AIDIVL, ydivl, Px, 0xf7,(07) },
- { AIDIVQ, ydivl, Pw, 0xf7,(07) },
- { AIDIVW, ydivl, Pe, 0xf7,(07) },
- { AIMULB, ydivb, Pb, 0xf6,(05) },
- { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf },
- { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf },
- { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf },
- { AINB, yin, Pb, 0xe4,0xec },
- { AINCB, yincb, Pb, 0xfe,(00) },
- { AINCL, yincl, Px, 0xff,(00) },
- { AINCQ, yincl, Pw, 0xff,(00) },
- { AINCW, yincw, Pe, 0xff,(00) },
- { AINL, yin, Px, 0xe5,0xed },
- { AINSB, ynone, Pb, 0x6c },
- { AINSL, ynone, Px, 0x6d },
- { AINSW, ynone, Pe, 0x6d },
- { AINT, yint, Px, 0xcd },
- { AINTO, ynone, P32, 0xce },
- { AINW, yin, Pe, 0xe5,0xed },
- { AIRETL, ynone, Px, 0xcf },
- { AIRETQ, ynone, Pw, 0xcf },
- { AIRETW, ynone, Pe, 0xcf },
- { AJCC, yjcond, Px, 0x73,0x83,(00) },
- { AJCS, yjcond, Px, 0x72,0x82 },
- { AJCXZ, yloop, Px, 0xe3 },
- { AJEQ, yjcond, Px, 0x74,0x84 },
- { AJGE, yjcond, Px, 0x7d,0x8d },
- { AJGT, yjcond, Px, 0x7f,0x8f },
- { AJHI, yjcond, Px, 0x77,0x87 },
- { AJLE, yjcond, Px, 0x7e,0x8e },
- { AJLS, yjcond, Px, 0x76,0x86 },
- { AJLT, yjcond, Px, 0x7c,0x8c },
- { AJMI, yjcond, Px, 0x78,0x88 },
- { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
- { AJNE, yjcond, Px, 0x75,0x85 },
- { AJOC, yjcond, Px, 0x71,0x81,(00) },
- { AJOS, yjcond, Px, 0x70,0x80,(00) },
- { AJPC, yjcond, Px, 0x7b,0x8b },
- { AJPL, yjcond, Px, 0x79,0x89 },
- { AJPS, yjcond, Px, 0x7a,0x8a },
- { ALAHF, ynone, Px, 0x9f },
- { ALARL, yml_rl, Pm, 0x02 },
- { ALARW, yml_rl, Pq, 0x02 },
- { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) },
- { ALEAL, ym_rl, Px, 0x8d },
- { ALEAQ, ym_rl, Pw, 0x8d },
- { ALEAVEL, ynone, P32, 0xc9 },
- { ALEAVEQ, ynone, Py, 0xc9 },
- { ALEAVEW, ynone, Pe, 0xc9 },
- { ALEAW, ym_rl, Pe, 0x8d },
- { ALOCK, ynone, Px, 0xf0 },
- { ALODSB, ynone, Pb, 0xac },
- { ALODSL, ynone, Px, 0xad },
- { ALODSQ, ynone, Pw, 0xad },
- { ALODSW, ynone, Pe, 0xad },
- { ALONG, ybyte, Px, 4 },
- { ALOOP, yloop, Px, 0xe2 },
- { ALOOPEQ, yloop, Px, 0xe1 },
- { ALOOPNE, yloop, Px, 0xe0 },
- { ALSLL, yml_rl, Pm, 0x03 },
- { ALSLW, yml_rl, Pq, 0x03 },
- { AMASKMOVOU, yxr, Pe, 0xf7 },
- { AMASKMOVQ, ymr, Pm, 0xf7 },
- { AMAXPD, yxm, Pe, 0x5f },
- { AMAXPS, yxm, Pm, 0x5f },
- { AMAXSD, yxm, Pf2, 0x5f },
- { AMAXSS, yxm, Pf3, 0x5f },
- { AMINPD, yxm, Pe, 0x5d },
- { AMINPS, yxm, Pm, 0x5d },
- { AMINSD, yxm, Pf2, 0x5d },
- { AMINSS, yxm, Pf3, 0x5d },
- { AMOVAPD, yxmov, Pe, 0x28,0x29 },
- { AMOVAPS, yxmov, Pm, 0x28,0x29 },
- { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
- { AMOVBLSX, ymb_rl, Pm, 0xbe },
- { AMOVBLZX, ymb_rl, Pm, 0xb6 },
- { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe },
- { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 },
- { AMOVBWSX, ymb_rl, Pq, 0xbe },
- { AMOVBWZX, ymb_rl, Pq, 0xb6 },
- { AMOVO, yxmov, Pe, 0x6f,0x7f },
- { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
- { AMOVHLPS, yxr, Pm, 0x12 },
- { AMOVHPD, yxmov, Pe, 0x16,0x17 },
- { AMOVHPS, yxmov, Pm, 0x16,0x17 },
- { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e },
- { AMOVLHPS, yxr, Pm, 0x16 },
- { AMOVLPD, yxmov, Pe, 0x12,0x13 },
- { AMOVLPS, yxmov, Pm, 0x12,0x13 },
- { AMOVLQSX, yml_rl, Pw, 0x63 },
- { AMOVLQZX, yml_rl, Px, 0x8b },
- { AMOVMSKPD, yxrrl, Pq, 0x50 },
- { AMOVMSKPS, yxrrl, Pm, 0x50 },
- { AMOVNTO, yxr_ml, Pe, 0xe7 },
- { AMOVNTPD, yxr_ml, Pe, 0x2b },
- { AMOVNTPS, yxr_ml, Pm, 0x2b },
- { AMOVNTQ, ymr_ml, Pm, 0xe7 },
- { AMOVQ, ymovq, Pw, 0x89,0x8b,0x31,0xc7,(00),0xb8,0xc7,(00),0x6f,0x7f,0x6e,0x7e,Pf2,0xd6,Pe,0xd6,Pe,0x6e,Pe,0x7e },
- { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e },
- { AMOVSB, ynone, Pb, 0xa4 },
- { AMOVSD, yxmov, Pf2, 0x10,0x11 },
- { AMOVSL, ynone, Px, 0xa5 },
- { AMOVSQ, ynone, Pw, 0xa5 },
- { AMOVSS, yxmov, Pf3, 0x10,0x11 },
- { AMOVSW, ynone, Pe, 0xa5 },
- { AMOVUPD, yxmov, Pe, 0x10,0x11 },
- { AMOVUPS, yxmov, Pm, 0x10,0x11 },
- { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00) },
- { AMOVWLSX, yml_rl, Pm, 0xbf },
- { AMOVWLZX, yml_rl, Pm, 0xb7 },
- { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf },
- { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 },
- { AMULB, ydivb, Pb, 0xf6,(04) },
- { AMULL, ydivl, Px, 0xf7,(04) },
- { AMULPD, yxm, Pe, 0x59 },
- { AMULPS, yxm, Ym, 0x59 },
- { AMULQ, ydivl, Pw, 0xf7,(04) },
- { AMULSD, yxm, Pf2, 0x59 },
- { AMULSS, yxm, Pf3, 0x59 },
- { AMULW, ydivl, Pe, 0xf7,(04) },
- { ANAME },
- { ANEGB, yscond, Pb, 0xf6,(03) },
- { ANEGL, yscond, Px, 0xf7,(03) },
- { ANEGQ, yscond, Pw, 0xf7,(03) },
- { ANEGW, yscond, Pe, 0xf7,(03) },
- { ANOP, ynop, Px, 0,0 },
- { ANOTB, yscond, Pb, 0xf6,(02) },
- { ANOTL, yscond, Px, 0xf7,(02) },
- { ANOTQ, yscond, Pw, 0xf7,(02) },
- { ANOTW, yscond, Pe, 0xf7,(02) },
- { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
- { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AORPD, yxm, Pq, 0x56 },
- { AORPS, yxm, Pm, 0x56 },
- { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AOUTB, yin, Pb, 0xe6,0xee },
- { AOUTL, yin, Px, 0xe7,0xef },
- { AOUTSB, ynone, Pb, 0x6e },
- { AOUTSL, ynone, Px, 0x6f },
- { AOUTSW, ynone, Pe, 0x6f },
- { AOUTW, yin, Pe, 0xe7,0xef },
- { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b },
- { APACKSSWB, ymm, Py, 0x63,Pe,0x63 },
- { APACKUSWB, ymm, Py, 0x67,Pe,0x67 },
- { APADDB, ymm, Py, 0xfc,Pe,0xfc },
- { APADDL, ymm, Py, 0xfe,Pe,0xfe },
- { APADDQ, yxm, Pe, 0xd4 },
- { APADDSB, ymm, Py, 0xec,Pe,0xec },
- { APADDSW, ymm, Py, 0xed,Pe,0xed },
- { APADDUSB, ymm, Py, 0xdc,Pe,0xdc },
- { APADDUSW, ymm, Py, 0xdd,Pe,0xdd },
- { APADDW, ymm, Py, 0xfd,Pe,0xfd },
- { APAND, ymm, Py, 0xdb,Pe,0xdb },
- { APANDN, ymm, Py, 0xdf,Pe,0xdf },
- { APAVGB, ymm, Py, 0xe0,Pe,0xe0 },
- { APAVGW, ymm, Py, 0xe3,Pe,0xe3 },
- { APCMPEQB, ymm, Py, 0x74,Pe,0x74 },
- { APCMPEQL, ymm, Py, 0x76,Pe,0x76 },
- { APCMPEQW, ymm, Py, 0x75,Pe,0x75 },
- { APCMPGTB, ymm, Py, 0x64,Pe,0x64 },
- { APCMPGTL, ymm, Py, 0x66,Pe,0x66 },
- { APCMPGTW, ymm, Py, 0x65,Pe,0x65 },
- { APEXTRW, yextrw, Pq, 0xc5 },
- { APF2IL, ymfp, Px, 0x1d },
- { APF2IW, ymfp, Px, 0x1c },
- { API2FL, ymfp, Px, 0x0d },
- { APFACC, ymfp, Px, 0xae },
- { APFADD, ymfp, Px, 0x9e },
- { APFCMPEQ, ymfp, Px, 0xb0 },
- { APFCMPGE, ymfp, Px, 0x90 },
- { APFCMPGT, ymfp, Px, 0xa0 },
- { APFMAX, ymfp, Px, 0xa4 },
- { APFMIN, ymfp, Px, 0x94 },
- { APFMUL, ymfp, Px, 0xb4 },
- { APFNACC, ymfp, Px, 0x8a },
- { APFPNACC, ymfp, Px, 0x8e },
- { APFRCP, ymfp, Px, 0x96 },
- { APFRCPIT1, ymfp, Px, 0xa6 },
- { APFRCPI2T, ymfp, Px, 0xb6 },
- { APFRSQIT1, ymfp, Px, 0xa7 },
- { APFRSQRT, ymfp, Px, 0x97 },
- { APFSUB, ymfp, Px, 0x9a },
- { APFSUBR, ymfp, Px, 0xaa },
- { APINSRW, yextrw, Pq, 0xc4 },
- { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 },
- { APMAXSW, yxm, Pe, 0xee },
- { APMAXUB, yxm, Pe, 0xde },
- { APMINSW, yxm, Pe, 0xea },
- { APMINUB, yxm, Pe, 0xda },
- { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
- { APMULHRW, ymfp, Px, 0xb7 },
- { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 },
- { APMULHW, ymm, Py, 0xe5,Pe,0xe5 },
- { APMULLW, ymm, Py, 0xd5,Pe,0xd5 },
- { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 },
- { APOPAL, ynone, P32, 0x61 },
- { APOPAW, ynone, Pe, 0x61 },
- { APOPFL, ynone, P32, 0x9d },
- { APOPFQ, ynone, Py, 0x9d },
- { APOPFW, ynone, Pe, 0x9d },
- { APOPL, ypopl, P32, 0x58,0x8f,(00) },
- { APOPQ, ypopl, Py, 0x58,0x8f,(00) },
- { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
- { APOR, ymm, Py, 0xeb,Pe,0xeb },
- { APSADBW, yxm, Pq, 0xf6 },
- { APSHUFHW, yxshuf, Pf3, 0x70 },
- { APSHUFL, yxshuf, Pq, 0x70 },
- { APSHUFLW, yxshuf, Pf2, 0x70 },
- { APSHUFW, ymshuf, Pm, 0x70 },
- { APSLLO, ypsdq, Pq, 0x73,(07) },
- { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) },
- { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x7e,(06) },
- { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) },
- { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) },
- { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) },
- { APSRLO, ypsdq, Pq, 0x73,(03) },
- { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) },
- { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) },
- { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) },
- { APSUBB, yxm, Pe, 0xf8 },
- { APSUBL, yxm, Pe, 0xfa },
- { APSUBQ, yxm, Pe, 0xfb },
- { APSUBSB, yxm, Pe, 0xe8 },
- { APSUBSW, yxm, Pe, 0xe9 },
- { APSUBUSB, yxm, Pe, 0xd8 },
- { APSUBUSW, yxm, Pe, 0xd9 },
- { APSUBW, yxm, Pe, 0xf9 },
- { APSWAPL, ymfp, Px, 0xbb },
- { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 },
- { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a },
- { APUNPCKHQDQ, yxm, Pe, 0x6d },
- { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 },
- { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 },
- { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 },
- { APUNPCKLQDQ, yxm, Pe, 0x6c },
- { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 },
- { APUSHAL, ynone, P32, 0x60 },
- { APUSHAW, ynone, Pe, 0x60 },
- { APUSHFL, ynone, P32, 0x9c },
- { APUSHFQ, ynone, Py, 0x9c },
- { APUSHFW, ynone, Pe, 0x9c },
- { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 },
- { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 },
- { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
- { APXOR, ymm, Py, 0xef,Pe,0xef },
- { AQUAD, ybyte, Px, 8 },
- { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
- { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCPPS, yxm, Pm, 0x53 },
- { ARCPSS, yxm, Pf3, 0x53 },
- { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
- { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { AREP, ynone, Px, 0xf3 },
- { AREPN, ynone, Px, 0xf2 },
- { ARET, ynone, Px, 0xc3 },
- { ARETFW, yret, Pe, 0xcb,0xca },
- { ARETFL, yret, Px, 0xcb,0xca },
- { ARETFQ, yret, Pw, 0xcb,0xca },
- { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
- { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
- { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARSQRTPS, yxm, Pm, 0x52 },
- { ARSQRTSS, yxm, Pf3, 0x52 },
- { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */
- { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
- { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
- { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASCASB, ynone, Pb, 0xae },
- { ASCASL, ynone, Px, 0xaf },
- { ASCASQ, ynone, Pw, 0xaf },
- { ASCASW, ynone, Pe, 0xaf },
- { ASETCC, yscond, Pm, 0x93,(00) },
- { ASETCS, yscond, Pm, 0x92,(00) },
- { ASETEQ, yscond, Pm, 0x94,(00) },
- { ASETGE, yscond, Pm, 0x9d,(00) },
- { ASETGT, yscond, Pm, 0x9f,(00) },
- { ASETHI, yscond, Pm, 0x97,(00) },
- { ASETLE, yscond, Pm, 0x9e,(00) },
- { ASETLS, yscond, Pm, 0x96,(00) },
- { ASETLT, yscond, Pm, 0x9c,(00) },
- { ASETMI, yscond, Pm, 0x98,(00) },
- { ASETNE, yscond, Pm, 0x95,(00) },
- { ASETOC, yscond, Pm, 0x91,(00) },
- { ASETOS, yscond, Pm, 0x90,(00) },
- { ASETPC, yscond, Pm, 0x96,(00) },
- { ASETPL, yscond, Pm, 0x99,(00) },
- { ASETPS, yscond, Pm, 0x9a,(00) },
- { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
- { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHUFPD, yxshuf, Pq, 0xc6 },
- { ASHUFPS, yxshuf, Pm, 0xc6 },
- { ASQRTPD, yxm, Pe, 0x51 },
- { ASQRTPS, yxm, Pm, 0x51 },
- { ASQRTSD, yxm, Pf2, 0x51 },
- { ASQRTSS, yxm, Pf3, 0x51 },
- { ASTC, ynone, Px, 0xf9 },
- { ASTD, ynone, Px, 0xfd },
- { ASTI, ynone, Px, 0xfb },
- { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) },
- { ASTOSB, ynone, Pb, 0xaa },
- { ASTOSL, ynone, Px, 0xab },
- { ASTOSQ, ynone, Pw, 0xab },
- { ASTOSW, ynone, Pe, 0xab },
- { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
- { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASUBPD, yxm, Pe, 0x5c },
- { ASUBPS, yxm, Pm, 0x5c },
- { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASUBSD, yxm, Pf2, 0x5c },
- { ASUBSS, yxm, Pf3, 0x5c },
- { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASWAPGS, ynone, Pm, 0x01,0xf8 },
- { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */
- { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
- { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
- { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 },
- { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
- { ATEXT, ytext, Px },
- { AUCOMISD, yxcmp, Pe, 0x2e },
- { AUCOMISS, yxcmp, Pm, 0x2e },
- { AUNPCKHPD, yxm, Pe, 0x15 },
- { AUNPCKHPS, yxm, Pm, 0x15 },
- { AUNPCKLPD, yxm, Pe, 0x14 },
- { AUNPCKLPS, yxm, Pm, 0x14 },
- { AVERR, ydivl, Pm, 0x00,(04) },
- { AVERW, ydivl, Pm, 0x00,(05) },
- { AWAIT, ynone, Px, 0x9b },
- { AWORD, ybyte, Px, 2 },
- { AXCHGB, yml_mb, Pb, 0x86,0x86 },
- { AXCHGL, yml_ml, Px, 0x87,0x87 },
- { AXCHGQ, yml_ml, Pw, 0x87,0x87 },
- { AXCHGW, yml_ml, Pe, 0x87,0x87 },
- { AXLAT, ynone, Px, 0xd7 },
- { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
- { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
- { AXORPD, yxm, Pe, 0x57 },
- { AXORPS, yxm, Pm, 0x57 },
- { AXORQ, yxorl, Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
- { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
-
- { AFMOVB, yfmvx, Px, 0xdf,(04) },
- { AFMOVBP, yfmvp, Px, 0xdf,(06) },
- { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
- { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
- { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
- { AFMOVFP, yfmvp, Px, 0xd9,(03) },
- { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
- { AFMOVLP, yfmvp, Px, 0xdb,(03) },
- { AFMOVV, yfmvx, Px, 0xdf,(05) },
- { AFMOVVP, yfmvp, Px, 0xdf,(07) },
- { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
- { AFMOVWP, yfmvp, Px, 0xdf,(03) },
- { AFMOVX, yfmvx, Px, 0xdb,(05) },
- { AFMOVXP, yfmvp, Px, 0xdb,(07) },
-
- { AFCOMB },
- { AFCOMBP },
- { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
- { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
- { AFCOMDPP, ycompp, Px, 0xde,(03) },
- { AFCOMF, yfmvx, Px, 0xd8,(02) },
- { AFCOMFP, yfmvx, Px, 0xd8,(03) },
- { AFCOML, yfmvx, Px, 0xda,(02) },
- { AFCOMLP, yfmvx, Px, 0xda,(03) },
- { AFCOMW, yfmvx, Px, 0xde,(02) },
- { AFCOMWP, yfmvx, Px, 0xde,(03) },
-
- { AFUCOM, ycompp, Px, 0xdd,(04) },
- { AFUCOMP, ycompp, Px, 0xdd,(05) },
- { AFUCOMPP, ycompp, Px, 0xda,(13) },
-
- { AFADDDP, yfaddp, Px, 0xde,(00) },
- { AFADDW, yfmvx, Px, 0xde,(00) },
- { AFADDL, yfmvx, Px, 0xda,(00) },
- { AFADDF, yfmvx, Px, 0xd8,(00) },
- { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
-
- { AFMULDP, yfaddp, Px, 0xde,(01) },
- { AFMULW, yfmvx, Px, 0xde,(01) },
- { AFMULL, yfmvx, Px, 0xda,(01) },
- { AFMULF, yfmvx, Px, 0xd8,(01) },
- { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
-
- { AFSUBDP, yfaddp, Px, 0xde,(05) },
- { AFSUBW, yfmvx, Px, 0xde,(04) },
- { AFSUBL, yfmvx, Px, 0xda,(04) },
- { AFSUBF, yfmvx, Px, 0xd8,(04) },
- { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
-
- { AFSUBRDP, yfaddp, Px, 0xde,(04) },
- { AFSUBRW, yfmvx, Px, 0xde,(05) },
- { AFSUBRL, yfmvx, Px, 0xda,(05) },
- { AFSUBRF, yfmvx, Px, 0xd8,(05) },
- { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
-
- { AFDIVDP, yfaddp, Px, 0xde,(07) },
- { AFDIVW, yfmvx, Px, 0xde,(06) },
- { AFDIVL, yfmvx, Px, 0xda,(06) },
- { AFDIVF, yfmvx, Px, 0xd8,(06) },
- { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
-
- { AFDIVRDP, yfaddp, Px, 0xde,(06) },
- { AFDIVRW, yfmvx, Px, 0xde,(07) },
- { AFDIVRL, yfmvx, Px, 0xda,(07) },
- { AFDIVRF, yfmvx, Px, 0xd8,(07) },
- { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
-
- { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
- { AFFREE },
- { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
- { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
- { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
- { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
- { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
- { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
- { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
- { AF2XM1, ynone, Px, 0xd9, 0xf0 },
- { AFABS, ynone, Px, 0xd9, 0xe1 },
- { AFCHS, ynone, Px, 0xd9, 0xe0 },
- { AFCLEX, ynone, Px, 0xdb, 0xe2 },
- { AFCOS, ynone, Px, 0xd9, 0xff },
- { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
- { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
- { AFINIT, ynone, Px, 0xdb, 0xe3 },
- { AFLD1, ynone, Px, 0xd9, 0xe8 },
- { AFLDL2E, ynone, Px, 0xd9, 0xea },
- { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
- { AFLDLG2, ynone, Px, 0xd9, 0xec },
- { AFLDLN2, ynone, Px, 0xd9, 0xed },
- { AFLDPI, ynone, Px, 0xd9, 0xeb },
- { AFLDZ, ynone, Px, 0xd9, 0xee },
- { AFNOP, ynone, Px, 0xd9, 0xd0 },
- { AFPATAN, ynone, Px, 0xd9, 0xf3 },
- { AFPREM, ynone, Px, 0xd9, 0xf8 },
- { AFPREM1, ynone, Px, 0xd9, 0xf5 },
- { AFPTAN, ynone, Px, 0xd9, 0xf2 },
- { AFRNDINT, ynone, Px, 0xd9, 0xfc },
- { AFSCALE, ynone, Px, 0xd9, 0xfd },
- { AFSIN, ynone, Px, 0xd9, 0xfe },
- { AFSINCOS, ynone, Px, 0xd9, 0xfb },
- { AFSQRT, ynone, Px, 0xd9, 0xfa },
- { AFTST, ynone, Px, 0xd9, 0xe4 },
- { AFXAM, ynone, Px, 0xd9, 0xe5 },
- { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
- { AFYL2X, ynone, Px, 0xd9, 0xf1 },
- { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
-
- { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 },
- { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 },
- { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 },
- { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 },
- { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
- { AINVD, ynone, Pm, 0x08 },
- { AINVLPG, ymbs, Pm, 0x01,(07) },
- { ALFENCE, ynone, Pm, 0xae,0xe8 },
- { AMFENCE, ynone, Pm, 0xae,0xf0 },
- { AMOVNTIL, yrl_ml, Pm, 0xc3 },
- { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 },
- { ARDMSR, ynone, Pm, 0x32 },
- { ARDPMC, ynone, Pm, 0x33 },
- { ARDTSC, ynone, Pm, 0x31 },
- { ARSM, ynone, Pm, 0xaa },
- { ASFENCE, ynone, Pm, 0xae,0xf8 },
- { ASYSRET, ynone, Pm, 0x07 },
- { AWBINVD, ynone, Pm, 0x09 },
- { AWRMSR, ynone, Pm, 0x30 },
-
- { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
- { AXADDL, yrl_ml, Px, 0x0f,0xc1 },
- { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 },
- { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
-
- { AEND },
- 0
-};
-
-Optab* opindex[ALAST+1];
-
-/*
-AMOVD 0f 6e/r mmx,reg/mem32[mem64-rex?]
-AMOVD 0f 7e/r reg/mem32[64],mmx STORE
-AMOVQ 0f 6f/r mmx1,mmx2/mem64
-AMOVQ 0f 7f/r mmx1/mem64,mmx2
-*/
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
deleted file mode 100644
index 0b0ee1253..000000000
--- a/src/cmd/6l/pass.c
+++ /dev/null
@@ -1,725 +0,0 @@
-// Inferno utils/6l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.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.
-
-// Code and data passes.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../../pkg/runtime/stack.h"
-
-static void xfol(Prog*, Prog**);
-
-Prog*
-brchain(Prog *p)
-{
- int i;
-
- for(i=0; i<20; i++) {
- if(p == P || p->as != AJMP)
- return p;
- p = p->pcond;
- }
- return P;
-}
-
-void
-follow(void)
-{
- Prog *firstp, *lastp;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f follow\n", cputime());
- Bflush(&bso);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- firstp = prg();
- lastp = firstp;
- xfol(cursym->text, &lastp);
- lastp->link = nil;
- cursym->text = firstp->link;
- }
-}
-
-static int
-nofollow(int a)
-{
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
- case AIRETQ:
- case AIRETW:
- case ARETFL:
- case ARETFQ:
- case ARETFW:
- return 1;
- }
- return 0;
-}
-
-static int
-pushpop(int a)
-{
- switch(a) {
- case APUSHL:
- case APUSHFL:
- case APUSHQ:
- case APUSHFQ:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPQ:
- case APOPFQ:
- case APOPW:
- case APOPFW:
- return 1;
- }
- return 0;
-}
-
-static void
-xfol(Prog *p, Prog **last)
-{
- Prog *q;
- int i;
- enum as a;
-
-loop:
- if(p == P)
- return;
- if(p->as == AJMP)
- if((q = p->pcond) != P && q->as != ATEXT) {
- /* mark instruction as done and continue layout at target of jump */
- p->mark = 1;
- p = q;
- if(p->mark == 0)
- goto loop;
- }
- if(p->mark) {
- /*
- * p goes here, but already used it elsewhere.
- * copy up to 4 instructions or else branch to other copy.
- */
- for(i=0,q=p; i<4; i++,q=q->link) {
- if(q == P)
- break;
- if(q == *last)
- break;
- a = q->as;
- if(a == ANOP) {
- i--;
- continue;
- }
- if(nofollow(a) || pushpop(a))
- break; // NOTE(rsc): arm does goto copy
- if(q->pcond == P || q->pcond->mark)
- continue;
- if(a == ACALL || a == ALOOP)
- continue;
- for(;;) {
- if(p->as == ANOP) {
- p = p->link;
- continue;
- }
- q = copyp(p);
- p = p->link;
- q->mark = 1;
- (*last)->link = q;
- *last = q;
- if(q->as != a || q->pcond == P || q->pcond->mark)
- continue;
-
- q->as = relinv(q->as);
- p = q->pcond;
- q->pcond = q->link;
- q->link = p;
- xfol(q->link, last);
- p = q->link;
- if(p->mark)
- return;
- goto loop;
- }
- } /* */
- q = prg();
- q->as = AJMP;
- q->line = p->line;
- q->to.type = D_BRANCH;
- q->to.offset = p->pc;
- q->pcond = p;
- p = q;
- }
-
- /* emit p */
- p->mark = 1;
- (*last)->link = p;
- *last = p;
- a = p->as;
-
- /* continue loop with what comes after p */
- if(nofollow(a))
- return;
- if(p->pcond != P && a != ACALL) {
- /*
- * some kind of conditional branch.
- * recurse to follow one path.
- * continue loop on the other.
- */
- q = brchain(p->link);
- if(q != P && q->mark)
- if(a != ALOOP) {
- p->as = relinv(a);
- p->link = p->pcond;
- p->pcond = q;
- }
- xfol(p->link, last);
- q = brchain(p->pcond);
- if(q->mark) {
- p->pcond = q;
- return;
- }
- p = q;
- goto loop;
- }
- p = p->link;
- goto loop;
-}
-
-Prog*
-byteq(int v)
-{
- Prog *p;
-
- p = prg();
- p->as = ABYTE;
- p->from.type = D_CONST;
- p->from.offset = v&0xff;
- return p;
-}
-
-int
-relinv(int a)
-{
-
- switch(a) {
- case AJEQ: return AJNE;
- case AJNE: return AJEQ;
- case AJLE: return AJGT;
- case AJLS: return AJHI;
- case AJLT: return AJGE;
- case AJMI: return AJPL;
- case AJGE: return AJLT;
- case AJPL: return AJMI;
- case AJGT: return AJLE;
- case AJHI: return AJLS;
- case AJCS: return AJCC;
- case AJCC: return AJCS;
- case AJPS: return AJPC;
- case AJPC: return AJPS;
- case AJOS: return AJOC;
- case AJOC: return AJOS;
- }
- diag("unknown relation: %s in %s", anames[a], TNAME);
- errorexit();
- return a;
-}
-
-void
-patch(void)
-{
- int32 c;
- Prog *p, *q;
- Sym *s;
- int32 vexit;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f mkfwd\n", cputime());
- Bflush(&bso);
- mkfwd();
- if(debug['v'])
- Bprint(&bso, "%5.2f patch\n", cputime());
- Bflush(&bso);
-
- s = lookup("exit", 0);
- vexit = s->value;
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- for(p = cursym->text; p != P; p = p->link) {
- if(HEADTYPE == Hwindows) {
- // Windows
- // Convert
- // op n(GS), reg
- // to
- // MOVL 0x58(GS), reg
- // op n(reg), reg
- // The purpose of this patch is to fix some accesses
- // to extern register variables (TLS) on Windows, as
- // a different method is used to access them.
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI
- && p->from.offset <= 8) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0x58;
- }
- }
- if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd) {
- // ELF uses FS instead of GS.
- if(p->from.type == D_INDIR+D_GS)
- p->from.type = D_INDIR+D_FS;
- if(p->to.type == D_INDIR+D_GS)
- p->to.type = D_INDIR+D_FS;
- }
- if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
- s = p->to.sym;
- if(s) {
- if(debug['c'])
- Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- if((s->type&~SSUB) != STEXT) {
- /* diag prints TNAME first */
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- }
- if(s->text == nil)
- continue;
- p->to.type = D_BRANCH;
- p->to.offset = s->text->pc;
- p->pcond = s->text;
- continue;
- }
- }
- if(p->to.type != D_BRANCH)
- continue;
- c = p->to.offset;
- for(q = cursym->text; q != P;) {
- if(c == q->pc)
- break;
- if(q->forwd != P && c >= q->forwd->pc)
- q = q->forwd;
- else
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range in %s (%#ux)\n%P [%s]",
- TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
- p->to.type = D_NONE;
- }
- p->pcond = q;
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- for(p = cursym->text; p != P; p = p->link) {
- p->mark = 0; /* initialization for follow */
- if(p->pcond != P) {
- p->pcond = brloop(p->pcond);
- if(p->pcond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->pcond->pc;
- }
- }
-}
-
-Prog*
-brloop(Prog *p)
-{
- int c;
- Prog *q;
-
- c = 0;
- for(q = p; q != P; q = q->pcond) {
- if(q->as != AJMP)
- break;
- c++;
- if(c >= 5000)
- return P;
- }
- return q;
-}
-
-static char*
-morename[] =
-{
- "runtime.morestack00",
- "runtime.morestack10",
- "runtime.morestack01",
- "runtime.morestack11",
-
- "runtime.morestack8",
- "runtime.morestack16",
- "runtime.morestack24",
- "runtime.morestack32",
- "runtime.morestack40",
- "runtime.morestack48",
-};
-Prog* pmorestack[nelem(morename)];
-Sym* symmorestack[nelem(morename)];
-
-void
-dostkoff(void)
-{
- Prog *p, *q, *q1;
- int32 autoffset, deltasp;
- int a, pcsize;
- uint32 moreconst1, moreconst2, i;
-
- for(i=0; i<nelem(morename); i++) {
- symmorestack[i] = lookup(morename[i], 0);
- if(symmorestack[i]->type != STEXT)
- diag("morestack trampoline not defined - %s", morename[i]);
- pmorestack[i] = symmorestack[i]->text;
- }
-
- autoffset = 0;
- deltasp = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
-
- p = cursym->text;
- parsetextconst(p->to.offset);
- autoffset = textstksiz;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
- q1 = P;
- if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
- diag("nosplit func likely to overflow stack");
-
- if(!(p->from.scale & NOSPLIT)) {
- p = appendp(p); // load g into CX
- p->as = AMOVQ;
- if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd) // ELF uses FS
- p->from.type = D_INDIR+D_FS;
- else
- p->from.type = D_INDIR+D_GS;
- p->from.offset = tlsoffset+0;
- p->to.type = D_CX;
- if(HEADTYPE == Hwindows) {
- // movq %gs:0x58, %rcx
- // movq (%rcx), %rcx
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0x58;
- p->to.type = D_CX;
-
-
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_CX;
- }
-
- if(debug['K']) {
- // 6l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 8;
- p->to.type = D_SP;
-
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
-
- p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- q1 = P;
- }
-
- if(autoffset < StackBig) { // do we need to call morestack?
- if(autoffset <= StackSmall) {
- // small stack
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_CX;
- } else {
- // large stack
- p = appendp(p);
- p->as = ALEAQ;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(autoffset-StackSmall);
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_CX;
- }
-
- // common
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
- }
-
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
- moreconst1 = 0;
- if(autoffset+160+textarg > 4096)
- moreconst1 = (autoffset+160) & ~7LL;
- moreconst2 = textarg;
-
- // 4 varieties varieties (const1==0 cross const2==0)
- // and 6 subvarieties of (const1==0 and const2!=0)
- p = appendp(p);
- if(moreconst1 == 0 && moreconst2 == 0) {
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[0];
- p->to.sym = symmorestack[0];
- } else
- if(moreconst1 != 0 && moreconst2 == 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst1;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[1];
- p->to.sym = symmorestack[1];
- } else
- if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
- i = moreconst2/8 + 3;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[i];
- p->to.sym = symmorestack[i];
- } else
- if(moreconst1 == 0 && moreconst2 != 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst2;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[2];
- p->to.sym = symmorestack[2];
- } else {
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = (uint64)moreconst2 << 32;
- p->from.offset |= moreconst1;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[3];
- p->to.sym = symmorestack[3];
- }
- }
-
- if(q != P)
- q->pcond = p->link;
-
- if(autoffset) {
- p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- p->spadj = autoffset;
- if(q != P)
- q->pcond = p;
- }
- deltasp = autoffset;
-
- if(debug['K'] > 1 && autoffset) {
- // 6l -KK means double-check for stack overflow
- // even after calling morestack and even if the
- // function is marked as nosplit.
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = ASUBQ;
- p->from.type = D_CONST;
- p->from.offset = StackSmall+32;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
-
- p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- q1 = P;
- }
-
- for(; p != P; p = p->link) {
- pcsize = p->mode/8;
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + pcsize;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + pcsize;
-
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- p->spadj = 4;
- continue;
- case APUSHQ:
- case APUSHFQ:
- deltasp += 8;
- p->spadj = 8;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- p->spadj = 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- p->spadj = -4;
- continue;
- case APOPQ:
- case APOPFQ:
- deltasp -= 8;
- p->spadj = -8;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- p->spadj = -2;
- continue;
- case ARET:
- break;
- }
-
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
-
- if(autoffset) {
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = -autoffset;
- p->spadj = -autoffset;
- p = appendp(p);
- p->as = ARET;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so undo
- // the cleanup.
- p->spadj = +autoffset;
- }
- }
- }
-}
-
-vlong
-atolwhex(char *s)
-{
- vlong n;
- int f;
-
- n = 0;
- f = 0;
- while(*s == ' ' || *s == '\t')
- s++;
- if(*s == '-' || *s == '+') {
- if(*s++ == '-')
- f = 1;
- while(*s == ' ' || *s == '\t')
- s++;
- }
- if(s[0]=='0' && s[1]){
- if(s[1]=='x' || s[1]=='X'){
- s += 2;
- for(;;){
- if(*s >= '0' && *s <= '9')
- n = n*16 + *s++ - '0';
- else if(*s >= 'a' && *s <= 'f')
- n = n*16 + *s++ - 'a' + 10;
- else if(*s >= 'A' && *s <= 'F')
- n = n*16 + *s++ - 'A' + 10;
- else
- break;
- }
- } else
- while(*s >= '0' && *s <= '7')
- n = n*8 + *s++ - '0';
- } else
- while(*s >= '0' && *s <= '9')
- n = n*10 + *s++ - '0';
- if(f)
- n = -n;
- return n;
-}
diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c
deleted file mode 100644
index 25992a40b..000000000
--- a/src/cmd/6l/prof.c
+++ /dev/null
@@ -1,171 +0,0 @@
-// Inferno utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/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.
-
-// Profiling.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-doprof1(void)
-{
-#if 0
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->size = n*4;
-#endif
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
-
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
-
- ps2 = P;
- ps4 = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
-
- if(p->from.scale & NOPROF) /* dont profile */
- continue;
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- for(; p; p=p->link) {
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
- }
- }
- }
-}
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
deleted file mode 100644
index 5251f19bb..000000000
--- a/src/cmd/6l/span.c
+++ /dev/null
@@ -1,1741 +0,0 @@
-// Inferno utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.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.
-
-// Instruction layout.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-static int rexflag;
-static int asmode;
-static vlong vaddr(Adr*, Reloc*);
-
-void
-span1(Sym *s)
-{
- Prog *p, *q;
- int32 c, v, loop;
- uchar *bp;
- int n, m, i;
-
- cursym = s;
-
- if(s->p != nil)
- return;
-
- for(p = s->text; p != P; p = p->link) {
- p->back = 2; // use short branches first time through
- if((q = p->pcond) != P && (q->back & 2))
- p->back |= 1; // backward jump
-
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = p->mode != 64? AADDL: AADDQ;
- if(v < 0) {
- p->as = p->mode != 64? ASUBL: ASUBQ;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
-
- n = 0;
- do {
- loop = 0;
- memset(s->r, 0, s->nr*sizeof s->r[0]);
- s->nr = 0;
- s->np = 0;
- c = 0;
- for(p = s->text; p != P; p = p->link) {
- p->pc = c;
-
- // process forward jumps to p
- for(q = p->comefrom; q != P; q = q->forwd) {
- v = p->pc - (q->pc + q->mark);
- if(q->back & 2) { // short
- if(v > 127) {
- loop++;
- q->back ^= 2;
- }
- s->p[q->pc+1] = v;
- } else {
- bp = s->p + q->pc + q->mark - 4;
- *bp++ = v;
- *bp++ = v>>8;
- *bp++ = v>>16;
- *bp++ = v>>24;
- }
- }
- p->comefrom = P;
-
- asmins(p);
- p->pc = c;
- m = andptr-and;
- symgrow(s, p->pc+m);
- memmove(s->p+p->pc, and, m);
- p->mark = m;
- c += m;
- }
- if(++n > 20) {
- diag("span must be looping");
- errorexit();
- }
- } while(loop);
- s->size = c;
-
- if(debug['a'] > 1) {
- print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
- for(i=0; i<s->np; i++) {
- print(" %.2ux", s->p[i]);
- if(i%16 == 15)
- print("\n %.6ux", i+1);
- }
- if(i%16)
- print("\n");
-
- for(i=0; i<s->nr; i++) {
- Reloc *r;
-
- r = &s->r[i];
- print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
- }
- }
-}
-
-void
-span(void)
-{
- Prog *p, *q;
- int32 v;
- int n;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
-
- // NOTE(rsc): If we get rid of the globals we should
- // be able to parallelize these iterations.
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->p != nil)
- continue;
- // TODO: move into span1
- for(p = cursym->text; p != P; p = p->link) {
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = p->mode != 64? AADDL: AADDQ;
- if(v < 0) {
- p->as = p->mode != 64? ASUBL: ASUBQ;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
- span1(cursym);
- }
-}
-
-void
-xdefine(char *p, int t, vlong v)
-{
- Sym *s;
-
- s = lookup(p, 0);
- s->type = t;
- s->value = v;
- s->reachable = 1;
- s->special = 1;
-}
-
-void
-instinit(void)
-{
- int c, i;
-
- for(i=1; optab[i].as; i++) {
- c = optab[i].as;
- if(opindex[c] != nil) {
- diag("phase error in optab: %d (%A)", i, c);
- errorexit();
- }
- opindex[c] = &optab[i];
- }
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Ys32] = 1;
- ycover[Yi1*Ymax + Ys32] = 1;
- ycover[Yi8*Ymax + Ys32] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
- ycover[Ys32*Ymax + Yi32] = 1;
-
- ycover[Yi0*Ymax + Yi64] = 1;
- ycover[Yi1*Ymax + Yi64] = 1;
- ycover[Yi8*Ymax + Yi64] = 1;
- ycover[Ys32*Ymax + Yi64] = 1;
- ycover[Yi32*Ymax + Yi64] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
- ycover[Yrl*Ymax + Yrb] = 1;
-
- ycover[Ycl*Ymax + Ycx] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Yrl*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- ycover[Yax*Ymax + Ymm] = 1;
- ycover[Ycx*Ymax + Ymm] = 1;
- ycover[Yrx*Ymax + Ymm] = 1;
- ycover[Yrl*Ymax + Ymm] = 1;
- ycover[Ym*Ymax + Ymm] = 1;
- ycover[Ymr*Ymax + Ymm] = 1;
-
- ycover[Yax*Ymax + Yxm] = 1;
- ycover[Ycx*Ymax + Yxm] = 1;
- ycover[Yrx*Ymax + Yxm] = 1;
- ycover[Yrl*Ymax + Yxm] = 1;
- ycover[Ym*Ymax + Yxm] = 1;
- ycover[Yxr*Ymax + Yxm] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_R15B) {
- reg[i] = (i-D_AL) & 7;
- if(i >= D_SPB && i <= D_DIB)
- regrex[i] = 0x40;
- if(i >= D_R8B && i <= D_R15B)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_AH && i<= D_BH)
- reg[i] = 4 + ((i-D_AH) & 7);
- if(i >= D_AX && i <= D_R15) {
- reg[i] = (i-D_AX) & 7;
- if(i >= D_R8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- if(i >= D_M0 && i <= D_M0+7)
- reg[i] = (i-D_M0) & 7;
- if(i >= D_X0 && i <= D_X0+15) {
- reg[i] = (i-D_X0) & 7;
- if(i >= D_X0+8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_CR+8 && i <= D_CR+15)
- regrex[i] = Rxr;
- }
-}
-
-int
-prefixof(Adr *a)
-{
- switch(a->type) {
- case D_INDIR+D_CS:
- return 0x2e;
- case D_INDIR+D_DS:
- return 0x3e;
- case D_INDIR+D_ES:
- return 0x26;
- case D_INDIR+D_FS:
- return 0x64;
- case D_INDIR+D_GS:
- return 0x65;
- }
- return 0;
-}
-
-int
-oclass(Adr *a)
-{
- vlong v;
- int32 l;
-
- if(a->type >= D_INDIR || a->index != D_NONE) {
- if(a->index != D_NONE && a->scale == 0) {
- if(a->type == D_ADDR) {
- switch(a->index) {
- case D_EXTERN:
- case D_STATIC:
- return Yi32; /* TO DO: Yi64 */
- case D_AUTO:
- case D_PARAM:
- return Yiauto;
- }
- return Yxxx;
- }
- return Ycol;
- }
- return Ym;
- }
- switch(a->type)
- {
- case D_AL:
- return Yal;
-
- case D_AX:
- return Yax;
-
-/*
- case D_SPB:
-*/
- case D_BPB:
- case D_SIB:
- case D_DIB:
- case D_R8B:
- case D_R9B:
- case D_R10B:
- case D_R11B:
- case D_R12B:
- case D_R13B:
- case D_R14B:
- case D_R15B:
- if(asmode != 64)
- return Yxxx;
- case D_DL:
- case D_BL:
- case D_AH:
- case D_CH:
- case D_DH:
- case D_BH:
- return Yrb;
-
- case D_CL:
- return Ycl;
-
- case D_CX:
- return Ycx;
-
- case D_DX:
- case D_BX:
- return Yrx;
-
- case D_R8: /* not really Yrl */
- case D_R9:
- case D_R10:
- case D_R11:
- case D_R12:
- case D_R13:
- case D_R14:
- case D_R15:
- if(asmode != 64)
- return Yxxx;
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- return Yrl;
-
- case D_F0+0:
- return Yf0;
-
- case D_F0+1:
- case D_F0+2:
- case D_F0+3:
- case D_F0+4:
- case D_F0+5:
- case D_F0+6:
- case D_F0+7:
- return Yrf;
-
- case D_M0+0:
- case D_M0+1:
- case D_M0+2:
- case D_M0+3:
- case D_M0+4:
- case D_M0+5:
- case D_M0+6:
- case D_M0+7:
- return Ymr;
-
- case D_X0+0:
- case D_X0+1:
- case D_X0+2:
- case D_X0+3:
- case D_X0+4:
- case D_X0+5:
- case D_X0+6:
- case D_X0+7:
- case D_X0+8:
- case D_X0+9:
- case D_X0+10:
- case D_X0+11:
- case D_X0+12:
- case D_X0+13:
- case D_X0+14:
- case D_X0+15:
- return Yxr;
-
- case D_NONE:
- return Ynone;
-
- case D_CS: return Ycs;
- case D_SS: return Yss;
- case D_DS: return Yds;
- case D_ES: return Yes;
- case D_FS: return Yfs;
- case D_GS: return Ygs;
-
- case D_GDTR: return Ygdtr;
- case D_IDTR: return Yidtr;
- case D_LDTR: return Yldtr;
- case D_MSW: return Ymsw;
- case D_TASK: return Ytask;
-
- case D_CR+0: return Ycr0;
- case D_CR+1: return Ycr1;
- case D_CR+2: return Ycr2;
- case D_CR+3: return Ycr3;
- case D_CR+4: return Ycr4;
- case D_CR+5: return Ycr5;
- case D_CR+6: return Ycr6;
- case D_CR+7: return Ycr7;
- case D_CR+8: return Ycr8;
-
- case D_DR+0: return Ydr0;
- case D_DR+1: return Ydr1;
- case D_DR+2: return Ydr2;
- case D_DR+3: return Ydr3;
- case D_DR+4: return Ydr4;
- case D_DR+5: return Ydr5;
- case D_DR+6: return Ydr6;
- case D_DR+7: return Ydr7;
-
- case D_TR+0: return Ytr0;
- case D_TR+1: return Ytr1;
- case D_TR+2: return Ytr2;
- case D_TR+3: return Ytr3;
- case D_TR+4: return Ytr4;
- case D_TR+5: return Ytr5;
- case D_TR+6: return Ytr6;
- case D_TR+7: return Ytr7;
-
- case D_EXTERN:
- case D_STATIC:
- case D_AUTO:
- case D_PARAM:
- return Ym;
-
- case D_CONST:
- case D_ADDR:
- if(a->sym == S) {
- v = a->offset;
- if(v == 0)
- return Yi0;
- if(v == 1)
- return Yi1;
- if(v >= -128 && v <= 127)
- return Yi8;
- l = v;
- if((vlong)l == v)
- return Ys32; /* can sign extend */
- if((v>>32) == 0)
- return Yi32; /* unsigned */
- return Yi64;
- }
- return Yi32; /* TO DO: D_ADDR as Yi64 */
-
- case D_BRANCH:
- return Ybr;
- }
- return Yxxx;
-}
-
-void
-asmidx(int scale, int index, int base)
-{
- int i;
-
- switch(index) {
- default:
- goto bad;
-
- case D_NONE:
- i = 4 << 3;
- goto bas;
-
- case D_R8:
- case D_R9:
- case D_R10:
- case D_R11:
- case D_R12:
- case D_R13:
- case D_R14:
- case D_R15:
- if(asmode != 64)
- goto bad;
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_BP:
- case D_SI:
- case D_DI:
- i = reg[index] << 3;
- break;
- }
- switch(scale) {
- default:
- goto bad;
- case 1:
- break;
- case 2:
- i |= (1<<6);
- break;
- case 4:
- i |= (2<<6);
- break;
- case 8:
- i |= (3<<6);
- break;
- }
-bas:
- switch(base) {
- default:
- goto bad;
- case D_NONE: /* must be mod=00 */
- i |= 5;
- break;
- case D_R8:
- case D_R9:
- case D_R10:
- case D_R11:
- case D_R12:
- case D_R13:
- case D_R14:
- case D_R15:
- if(asmode != 64)
- goto bad;
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- i |= reg[base];
- break;
- }
- *andptr++ = i;
- return;
-bad:
- diag("asmidx: bad address %d/%d/%d", scale, index, base);
- *andptr++ = 0;
- return;
-}
-
-static void
-put4(int32 v)
-{
- andptr[0] = v;
- andptr[1] = v>>8;
- andptr[2] = v>>16;
- andptr[3] = v>>24;
- andptr += 4;
-}
-
-static void
-relput4(Prog *p, Adr *a)
-{
- vlong v;
- Reloc rel, *r;
-
- v = vaddr(a, &rel);
- if(rel.siz != 0) {
- if(rel.siz != 4)
- diag("bad reloc");
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put4(v);
-}
-
-static void
-put8(vlong v)
-{
- andptr[0] = v;
- andptr[1] = v>>8;
- andptr[2] = v>>16;
- andptr[3] = v>>24;
- andptr[4] = v>>32;
- andptr[5] = v>>40;
- andptr[6] = v>>48;
- andptr[7] = v>>56;
- andptr += 8;
-}
-
-/*
-static void
-relput8(Prog *p, Adr *a)
-{
- vlong v;
- Reloc rel, *r;
-
- v = vaddr(a, &rel);
- if(rel.siz != 0) {
- r = addrel(cursym);
- *r = rel;
- r->siz = 8;
- r->off = p->pc + andptr - and;
- }
- put8(v);
-}
-*/
-
-vlong
-symaddr(Sym *s)
-{
- if(!s->reachable)
- diag("unreachable symbol in symaddr - %s", s->name);
- return s->value;
-}
-
-static vlong
-vaddr(Adr *a, Reloc *r)
-{
- int t;
- vlong v;
- Sym *s;
-
- if(r != nil)
- memset(r, 0, sizeof *r);
-
- t = a->type;
- v = a->offset;
- if(t == D_ADDR)
- t = a->index;
- switch(t) {
- case D_STATIC:
- case D_EXTERN:
- s = a->sym;
- if(!s->reachable)
- diag("unreachable symbol in vaddr - %s", s->name);
- if(r == nil) {
- diag("need reloc for %D", a);
- errorexit();
- }
- r->type = D_ADDR;
- r->siz = 4; // TODO: 8 for external symbols
- r->off = -1; // caller must fill in
- r->sym = s;
- r->add = v;
- v = 0;
- }
- return v;
-}
-
-static void
-asmandsz(Adr *a, int r, int rex, int m64)
-{
- int32 v;
- int t, scale;
- Reloc rel;
-
- rex &= (0x40 | Rxr);
- v = a->offset;
- t = a->type;
- rel.siz = 0;
- if(a->index != D_NONE) {
- if(t < D_INDIR) {
- switch(t) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- } else
- t -= D_INDIR;
- rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- return;
- }
- if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(t >= D_AL && t <= D_X0+15) {
- if(v)
- goto bad;
- *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
- rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
- return;
- }
-
- scale = a->scale;
- if(t < D_INDIR) {
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- scale = 1;
- } else
- t -= D_INDIR;
-
- rexflag |= (regrex[t] & Rxb) | rex;
- if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
- if(asmode != 64){
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- goto putrelv;
- }
- /* temporary */
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
- *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
- goto putrelv;
- }
- if(t == D_SP || t == D_R12) {
- if(v == 0) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- goto putrelv;
- }
- if(t >= D_AX && t <= D_R15) {
- if(v == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- goto putrelv;
- }
- goto bad;
-
-putrelv:
- if(rel.siz != 0) {
- Reloc *r;
-
- if(rel.siz != 4) {
- diag("bad rel");
- goto bad;
- }
- r = addrel(cursym);
- *r = rel;
- r->off = curp->pc + andptr - and;
- }
- put4(v);
- return;
-
-bad:
- diag("asmand: bad address %D", a);
- return;
-}
-
-void
-asmand(Adr *a, Adr *ra)
-{
- asmandsz(a, reg[ra->type], regrex[ra->type], 0);
-}
-
-void
-asmando(Adr *a, int o)
-{
- asmandsz(a, o, 0, 0);
-}
-
-static void
-bytereg(Adr *a, char *t)
-{
- if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) {
- a->type = D_AL + (a->type-D_AX);
- *t = 0;
- }
-}
-
-#define E 0xff
-Movtab ymovtab[] =
-{
-/* push */
- {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0},
- {APUSHL, Yss, Ynone, 0, 0x16,E,0,0},
- {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0},
- {APUSHL, Yes, Ynone, 0, 0x06,E,0,0},
- {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
- {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
- {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
- {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
-
- {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0},
- {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0},
- {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0},
- {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0},
- {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E},
- {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E},
-
-/* pop */
- {APOPL, Ynone, Yds, 0, 0x1f,E,0,0},
- {APOPL, Ynone, Yes, 0, 0x07,E,0,0},
- {APOPL, Ynone, Yss, 0, 0x17,E,0,0},
- {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
- {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
- {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
- {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
-
- {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0},
- {APOPW, Ynone, Yes, 0, Pe,0x07,E,0},
- {APOPW, Ynone, Yss, 0, Pe,0x17,E,0},
- {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E},
- {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E},
-
-/* mov seg */
- {AMOVW, Yes, Yml, 1, 0x8c,0,0,0},
- {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0},
- {AMOVW, Yss, Yml, 1, 0x8c,2,0,0},
- {AMOVW, Yds, Yml, 1, 0x8c,3,0,0},
- {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0},
- {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0},
-
- {AMOVW, Yml, Yes, 2, 0x8e,0,0,0},
- {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0},
- {AMOVW, Yml, Yss, 2, 0x8e,2,0,0},
- {AMOVW, Yml, Yds, 2, 0x8e,3,0,0},
- {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0},
- {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0},
-
-/* mov cr */
- {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0},
- {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0},
- {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0},
- {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0},
- {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0},
- {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0},
- {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0},
- {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0},
- {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0},
- {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0},
-
- {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0},
- {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0},
- {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0},
- {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0},
- {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0},
- {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0},
- {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0},
- {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0},
- {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0},
- {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0},
-
-/* mov dr */
- {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0},
- {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0},
- {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0},
- {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0},
- {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0},
- {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0},
-
- {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0},
- {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0},
- {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0},
- {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0},
- {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0},
- {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0},
-
-/* mov tr */
- {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0},
- {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0},
-
- {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E},
- {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E},
-
-/* lgdt, sgdt, lidt, sidt */
- {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
- {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
- {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0},
- {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0},
- {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
- {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
- {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0},
- {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0},
-
-/* lldt, sldt */
- {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0},
- {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0},
-
-/* lmsw, smsw */
- {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0},
- {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0},
-
-/* ltr, str */
- {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0},
- {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0},
-
-/* load full pointer */
- {AMOVL, Yml, Ycol, 5, 0,0,0,0},
- {AMOVW, Yml, Ycol, 5, Pe,0,0,0},
-
-/* double shift */
- {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0},
- {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0},
- {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0},
- {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0},
- {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0},
- {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0},
- 0
-};
-
-int
-isax(Adr *a)
-{
-
- switch(a->type) {
- case D_AX:
- case D_AL:
- case D_AH:
- case D_INDIR+D_AX:
- return 1;
- }
- if(a->index == D_AX)
- return 1;
- return 0;
-}
-
-void
-subreg(Prog *p, int from, int to)
-{
-
- if(debug['Q'])
- print("\n%P s/%R/%R/\n", p, from, to);
-
- if(p->from.type == from)
- p->from.type = to;
- if(p->to.type == from)
- p->to.type = to;
-
- if(p->from.index == from)
- p->from.index = to;
- if(p->to.index == from)
- p->to.index = to;
-
- from += D_INDIR;
- if(p->from.type == from)
- p->from.type = to+D_INDIR;
- if(p->to.type == from)
- p->to.type = to+D_INDIR;
-
- if(debug['Q'])
- print("%P\n", p);
-}
-
-static int
-mediaop(Optab *o, int op, int osize, int z)
-{
- switch(op){
- case Pm:
- case Pe:
- case Pf2:
- case Pf3:
- if(osize != 1){
- if(op != Pm)
- *andptr++ = op;
- *andptr++ = Pm;
- op = o->op[++z];
- break;
- }
- default:
- if(andptr == and || andptr[-1] != Pm)
- *andptr++ = Pm;
- break;
- }
- *andptr++ = op;
- return z;
-}
-
-void
-doasm(Prog *p)
-{
- Optab *o;
- Prog *q, pp;
- uchar *t;
- Movtab *mo;
- int z, op, ft, tt, xo, l, pre;
- vlong v;
- Reloc rel, *r;
- Adr *a;
-
- curp = p; // TODO
-
- o = opindex[p->as];
- if(o == nil) {
- diag("asmins: missing op %P", p);
- return;
- }
-
- pre = prefixof(&p->from);
- if(pre)
- *andptr++ = pre;
- pre = prefixof(&p->to);
- if(pre)
- *andptr++ = pre;
-
- if(p->ft == 0)
- p->ft = oclass(&p->from);
- if(p->tt == 0)
- p->tt = oclass(&p->to);
-
- ft = p->ft * Ymax;
- tt = p->tt * Ymax;
-
- t = o->ytab;
- if(t == 0) {
- diag("asmins: noproto %P", p);
- return;
- }
- xo = o->op[0] == 0x0f;
- for(z=0; *t; z+=t[3]+xo,t+=4)
- if(ycover[ft+t[0]])
- if(ycover[tt+t[1]])
- goto found;
- goto domov;
-
-found:
- switch(o->prefix) {
- case Pq: /* 16 bit escape and opcode escape */
- *andptr++ = Pe;
- *andptr++ = Pm;
- break;
-
- case Pf2: /* xmm opcode escape */
- case Pf3:
- *andptr++ = o->prefix;
- *andptr++ = Pm;
- break;
-
- case Pm: /* opcode escape */
- *andptr++ = Pm;
- break;
-
- case Pe: /* 16 bit escape */
- *andptr++ = Pe;
- break;
-
- case Pw: /* 64-bit escape */
- if(p->mode != 64)
- diag("asmins: illegal 64: %P", p);
- rexflag |= Pw;
- break;
-
- case Pb: /* botch */
- bytereg(&p->from, &p->ft);
- bytereg(&p->to, &p->tt);
- break;
-
- case P32: /* 32 bit but illegal if 64-bit mode */
- if(p->mode == 64)
- diag("asmins: illegal in 64-bit mode: %P", p);
- break;
-
- case Py: /* 64-bit only, no prefix */
- if(p->mode != 64)
- diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
- break;
- }
-
- op = o->op[z];
- if(op == 0x0f) {
- *andptr++ = op;
- op = o->op[++z];
- }
- switch(t[2]) {
- default:
- diag("asmins: unknown z %d %P", t[2], p);
- return;
-
- case Zpseudo:
- break;
-
- case Zlit:
- for(; op = o->op[z]; z++)
- *andptr++ = op;
- break;
-
- case Zmb_r:
- bytereg(&p->from, &p->ft);
- /* fall through */
- case Zm_r:
- *andptr++ = op;
- asmand(&p->from, &p->to);
- break;
-
- case Zm_r_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->from, &p->to);
- break;
-
- case Zm_r_xm_nr:
- rexflag = 0;
- mediaop(o, op, t[3], z);
- asmand(&p->from, &p->to);
- break;
-
- case Zm_r_i_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->from, &p->to);
- *andptr++ = p->to.offset;
- break;
-
- case Zm_r_3d:
- *andptr++ = 0x0f;
- *andptr++ = 0x0f;
- asmand(&p->from, &p->to);
- *andptr++ = op;
- break;
-
- case Zibm_r:
- *andptr++ = op;
- asmand(&p->from, &p->to);
- *andptr++ = p->to.offset;
- break;
-
- case Zaut_r:
- *andptr++ = 0x8d; /* leal */
- if(p->from.type != D_ADDR)
- diag("asmins: Zaut sb type ADDR");
- p->from.type = p->from.index;
- p->from.index = D_NONE;
- asmand(&p->from, &p->to);
- p->from.index = p->from.type;
- p->from.type = D_ADDR;
- break;
-
- case Zm_o:
- *andptr++ = op;
- asmando(&p->from, o->op[z+1]);
- break;
-
- case Zr_m:
- *andptr++ = op;
- asmand(&p->to, &p->from);
- break;
-
- case Zr_m_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->to, &p->from);
- break;
-
- case Zr_m_xm_nr:
- rexflag = 0;
- mediaop(o, op, t[3], z);
- asmand(&p->to, &p->from);
- break;
-
- case Zr_m_i_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->to, &p->from);
- *andptr++ = p->from.offset;
- break;
-
- case Zo_m:
- *andptr++ = op;
- asmando(&p->to, o->op[z+1]);
- break;
-
- case Zo_m64:
- *andptr++ = op;
- asmandsz(&p->to, o->op[z+1], 0, 1);
- break;
-
- case Zm_ibo:
- *andptr++ = op;
- asmando(&p->from, o->op[z+1]);
- *andptr++ = vaddr(&p->to, nil);
- break;
-
- case Zibo_m:
- *andptr++ = op;
- asmando(&p->to, o->op[z+1]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Zibo_m_xm:
- z = mediaop(o, op, t[3], z);
- asmando(&p->to, o->op[z+1]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_ib:
- case Zib_:
- if(t[2] == Zib_)
- a = &p->from;
- else
- a = &p->to;
- *andptr++ = op;
- *andptr++ = vaddr(a, nil);
- break;
-
- case Zib_rp:
- rexflag |= regrex[p->to.type] & (Rxb|0x40);
- *andptr++ = op + reg[p->to.type];
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Zil_rp:
- rexflag |= regrex[p->to.type] & Rxb;
- *andptr++ = op + reg[p->to.type];
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Zo_iw:
- *andptr++ = op;
- if(p->from.type != D_NONE){
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- break;
-
- case Ziq_rp:
- v = vaddr(&p->from, &rel);
- l = v>>32;
- if(l == 0 && rel.siz != 8){
- //p->mark |= 0100;
- //print("zero: %llux %P\n", v, p);
- rexflag &= ~(0x40|Rxw);
- rexflag |= regrex[p->to.type] & Rxb;
- *andptr++ = 0xb8 + reg[p->to.type];
- if(rel.type != 0) {
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put4(v);
- }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */
- //p->mark |= 0100;
- //print("sign: %llux %P\n", v, p);
- *andptr ++ = 0xc7;
- asmando(&p->to, 0);
- put4(v);
- }else{ /* need all 8 */
- //print("all: %llux %P\n", v, p);
- rexflag |= regrex[p->to.type] & Rxb;
- *andptr++ = op + reg[p->to.type];
- if(rel.type != 0) {
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put8(v);
- }
- break;
-
- case Zib_rr:
- *andptr++ = op;
- asmand(&p->to, &p->to);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_il:
- case Zil_:
- if(t[2] == Zil_)
- a = &p->from;
- else
- a = &p->to;
- *andptr++ = op;
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zm_ilo:
- case Zilo_m:
- *andptr++ = op;
- if(t[2] == Zilo_m) {
- a = &p->from;
- asmando(&p->to, o->op[z+1]);
- } else {
- a = &p->to;
- asmando(&p->from, o->op[z+1]);
- }
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zil_rr:
- *andptr++ = op;
- asmand(&p->to, &p->to);
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Z_rp:
- rexflag |= regrex[p->to.type] & (Rxb|0x40);
- *andptr++ = op + reg[p->to.type];
- break;
-
- case Zrp_:
- rexflag |= regrex[p->from.type] & (Rxb|0x40);
- *andptr++ = op + reg[p->from.type];
- break;
-
- case Zclr:
- *andptr++ = op;
- asmand(&p->to, &p->to);
- break;
-
- case Zcall:
- q = p->pcond;
- if(q == nil) {
- diag("call without target");
- errorexit();
- }
- if(q->as != ATEXT) {
- // Could handle this case by making D_PCREL
- // record the Prog* instead of the Sym*, but let's
- // wait until the need arises.
- diag("call of non-TEXT %P", q);
- errorexit();
- }
- *andptr++ = op;
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->sym = q->from.sym;
- r->type = D_PCREL;
- r->siz = 4;
- put4(0);
- break;
-
- case Zbr:
- case Zjmp:
- // TODO: jump across functions needs reloc
- q = p->pcond;
- if(q == nil) {
- diag("jmp/branch without target");
- errorexit();
- }
- if(q->as == ATEXT) {
- if(t[2] == Zbr) {
- diag("branch to ATEXT");
- errorexit();
- }
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->sym = q->from.sym;
- r->type = D_PCREL;
- r->siz = 4;
- put4(0);
- break;
- }
- // Assumes q is in this function.
- // TODO: Check in input, preserve in brchain.
-
- // Fill in backward jump now.
- if(p->back & 1) {
- v = q->pc - (p->pc + 2);
- if(v >= -128) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- v -= 5-2;
- if(t[2] == Zbr) {
- *andptr++ = 0x0f;
- v--;
- }
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- break;
- }
-
- // Annotate target; will fill in later.
- p->forwd = q->comefrom;
- q->comefrom = p;
- if(p->back & 2) { // short
- *andptr++ = op;
- *andptr++ = 0;
- } else {
- if(t[2] == Zbr)
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- }
- break;
-
-/*
- v = q->pc - p->pc - 2;
- if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- v -= 5-2;
- if(t[2] == Zbr) {
- *andptr++ = 0x0f;
- v--;
- }
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
-*/
- break;
-
- case Zloop:
- q = p->pcond;
- if(q == nil) {
- diag("loop without target");
- errorexit();
- }
- v = q->pc - p->pc - 2;
- if(v < -128 && v > 127)
- diag("loop too far: %P", p);
- *andptr++ = op;
- *andptr++ = v;
- break;
-
- case Zbyte:
- v = vaddr(&p->from, &rel);
- if(rel.siz != 0) {
- rel.siz = op;
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- *andptr++ = v;
- if(op > 1) {
- *andptr++ = v>>8;
- if(op > 2) {
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- if(op > 4) {
- *andptr++ = v>>32;
- *andptr++ = v>>40;
- *andptr++ = v>>48;
- *andptr++ = v>>56;
- }
- }
- }
- break;
- }
- return;
-
-domov:
- for(mo=ymovtab; mo->as; mo++)
- if(p->as == mo->as)
- if(ycover[ft+mo->ft])
- if(ycover[tt+mo->tt]){
- t = mo->op;
- goto mfound;
- }
-bad:
- if(p->mode != 64){
- /*
- * here, the assembly has failed.
- * if its a byte instruction that has
- * unaddressable registers, try to
- * exchange registers and reissue the
- * instruction with the operands renamed.
- */
- pp = *p;
- z = p->from.type;
- if(z >= D_BP && z <= D_DI) {
- if(isax(&p->to)) {
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmando(&p->from, reg[D_BX]);
- subreg(&pp, z, D_BX);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmando(&p->from, reg[D_BX]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- }
- return;
- }
- z = p->to.type;
- if(z >= D_BP && z <= D_DI) {
- if(isax(&p->from)) {
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmando(&p->to, reg[D_BX]);
- subreg(&pp, z, D_BX);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmando(&p->to, reg[D_BX]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- }
- return;
- }
- }
- diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
- return;
-
-mfound:
- switch(mo->code) {
- default:
- diag("asmins: unknown mov %d %P", mo->code, p);
- break;
-
- case 0: /* lit */
- for(z=0; t[z]!=E; z++)
- *andptr++ = t[z];
- break;
-
- case 1: /* r,m */
- *andptr++ = t[0];
- asmando(&p->to, t[1]);
- break;
-
- case 2: /* m,r */
- *andptr++ = t[0];
- asmando(&p->from, t[1]);
- break;
-
- case 3: /* r,m - 2op */
- *andptr++ = t[0];
- *andptr++ = t[1];
- asmando(&p->to, t[2]);
- rexflag |= regrex[p->from.type] & (Rxr|0x40);
- break;
-
- case 4: /* m,r - 2op */
- *andptr++ = t[0];
- *andptr++ = t[1];
- asmando(&p->from, t[2]);
- rexflag |= regrex[p->to.type] & (Rxr|0x40);
- break;
-
- case 5: /* load full pointer, trash heap */
- if(t[0])
- *andptr++ = t[0];
- switch(p->to.index) {
- default:
- goto bad;
- case D_DS:
- *andptr++ = 0xc5;
- break;
- case D_SS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb2;
- break;
- case D_ES:
- *andptr++ = 0xc4;
- break;
- case D_FS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb4;
- break;
- case D_GS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb5;
- break;
- }
- asmand(&p->from, &p->to);
- break;
-
- case 6: /* double shift */
- if(t[0] == Pw){
- if(p->mode != 64)
- diag("asmins: illegal 64: %P", p);
- rexflag |= Pw;
- t++;
- }else if(t[0] == Pe){
- *andptr++ = Pe;
- t++;
- }
- z = p->from.type;
- switch(z) {
- default:
- goto bad;
- case D_CONST:
- *andptr++ = 0x0f;
- *andptr++ = t[0];
- asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
- *andptr++ = p->from.offset;
- break;
- case D_CL:
- case D_CX:
- *andptr++ = 0x0f;
- *andptr++ = t[1];
- asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
- break;
- }
- break;
- }
-}
-
-void
-asmins(Prog *p)
-{
- int n, np, c;
- Reloc *r;
-
- rexflag = 0;
- andptr = and;
- asmode = p->mode;
- doasm(p);
- if(rexflag){
- /*
- * as befits the whole approach of the architecture,
- * the rex prefix must appear before the first opcode byte
- * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
- * before the 0f opcode escape!), or it might be ignored.
- * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
- */
- if(p->mode != 64)
- diag("asmins: illegal in mode %d: %P", p->mode, p);
- n = andptr - and;
- for(np = 0; np < n; np++) {
- c = and[np];
- if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
- break;
- }
- for(r=cursym->r+cursym->nr; r-- > cursym->r; ) {
- if(r->off < p->pc)
- break;
- r->off++;
- }
- memmove(and+np+1, and+np, n-np);
- and[np] = 0x40 | rexflag;
- andptr++;
- }
-}
diff --git a/src/cmd/8a/Makefile b/src/cmd/8a/Makefile
deleted file mode 100644
index 78d361dbd..000000000
--- a/src/cmd/8a/Makefile
+++ /dev/null
@@ -1,25 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=8a
-
-HFILES=\
- a.h\
- y.tab.h\
- ../8l/8.out.h\
-
-OFILES=\
- y.tab.$O\
- lex.$O\
- ../8l/enam.$O\
-
-YFILES=\
- a.y\
-
-include ../../Make.ccmd
-
-lex.$O: ../cc/macbody ../cc/lexbody
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
deleted file mode 100644
index c5c22d7ba..000000000
--- a/src/cmd/8a/a.h
+++ /dev/null
@@ -1,215 +0,0 @@
-// Inferno utils/8a/a.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.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 <bio.h>
-#include "../8l/8.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 Ref Ref;
-typedef struct Gen Gen;
-typedef struct Io Io;
-typedef struct Hist Hist;
-typedef struct Gen2 Gen2;
-
-#define MAXALIGN 7
-#define FPCHIP 1
-#define NSYMB 500
-#define BUFSIZ 8192
-#define HISTSZ 20
-#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;
- Ref* ref;
- char* macro;
- int32 value;
- ushort type;
- char *name;
- char sym;
-};
-#define S ((Sym*)0)
-
-struct Ref
-{
- int class;
-};
-
-EXTERN struct
-{
- char* p;
- int c;
-} fi;
-
-struct Io
-{
- Io* link;
- char b[BUFSIZ];
- char* p;
- short c;
- short f;
-};
-#define I ((Io*)0)
-
-EXTERN struct
-{
- Sym* sym;
- short type;
-} h[NSYM];
-
-struct Gen
-{
- double dval;
- char sval[8];
- int32 offset;
- int32 offset2;
- Sym* sym;
- short type;
- short index;
- short scale;
-};
-struct Gen2
-{
- Gen from;
- Gen to;
-};
-
-struct Hist
-{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
-};
-#define H ((Hist*)0)
-
-enum
-{
- CLAST,
- CMACARG,
- CMACRO,
- CPREPROC,
-};
-
-
-EXTERN char debug[256];
-EXTERN Sym* hash[NHASH];
-EXTERN char** Dlist;
-EXTERN int nDlist;
-EXTERN Hist* ehist;
-EXTERN int newflag;
-EXTERN Hist* hist;
-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 ninclude;
-EXTERN int32 nsymb;
-EXTERN Gen nullgen;
-EXTERN char* outfile;
-EXTERN int pass;
-EXTERN char* pathname;
-EXTERN int32 pc;
-EXTERN int peekc;
-EXTERN int32 stmtline;
-EXTERN int sym;
-EXTERN char* symb;
-EXTERN int thechar;
-EXTERN char* thestring;
-EXTERN int32 thunk;
-EXTERN Biobuf obuf;
-
-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);
-void syminit(Sym*);
-int32 yylex(void);
-int getc(void);
-int getnsc(void);
-void unget(int);
-int escchar(int);
-void cinit(void);
-void checkscale(int);
-void pinit(char*);
-void cclean(void);
-int isreg(Gen*);
-void outcode(int, Gen2*);
-void outhist(void);
-void zaddr(Gen*, int);
-void zname(char*, int, int);
-void ieeedtod(Ieee*, double);
-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/8a/a.y b/src/cmd/8a/a.y
deleted file mode 100644
index a8ac773da..000000000
--- a/src/cmd/8a/a.y
+++ /dev/null
@@ -1,614 +0,0 @@
-// Inferno utils/8a/a.y
-// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.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 a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-%}
-%union {
- Sym *sym;
- int32 lval;
- struct {
- int32 v1;
- int32 v2;
- } con2;
- double dval;
- char sval[8];
- Gen gen;
- Gen2 gen2;
-}
-%left '|'
-%left '^'
-%left '&'
-%left '<' '>'
-%left '+' '-'
-%left '*' '/' '%'
-%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
-%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEG
-%token <lval> LCONST LFP LPC LSB
-%token <lval> LBREG LLREG LSREG LFREG
-%token <dval> LFCONST
-%token <sval> LSCONST LSP
-%token <sym> LNAME LLAB LVAR
-%type <lval> con expr pointer offset
-%type <con2> con2
-%type <gen> mem imm imm2 reg nam rel rem rim rom omem nmem
-%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim
-%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8
-%%
-prog:
-| prog
- {
- stmtline = lineno;
- }
- line
-
-line:
- LLAB ':'
- {
- if($1->value != pc)
- yyerror("redeclaration of %s", $1->name);
- $1->value = pc;
- }
- line
-| LNAME ':'
- {
- $1->type = LLAB;
- $1->value = pc;
- }
- line
-| ';'
-| inst ';'
-| error ';'
-
-inst:
- LNAME '=' expr
- {
- $1->type = LVAR;
- $1->value = $3;
- }
-| LVAR '=' expr
- {
- if($1->value != $3)
- yyerror("redeclaration of %s", $1->name);
- $1->value = $3;
- }
-| LTYPE0 nonnon { outcode($1, &$2); }
-| LTYPE1 nonrem { outcode($1, &$2); }
-| LTYPE2 rimnon { outcode($1, &$2); }
-| LTYPE3 rimrem { outcode($1, &$2); }
-| LTYPE4 remrim { outcode($1, &$2); }
-| LTYPER nonrel { outcode($1, &$2); }
-| LTYPED spec1 { outcode($1, &$2); }
-| LTYPET spec2 { outcode($1, &$2); }
-| LTYPEC spec3 { outcode($1, &$2); }
-| LTYPEN spec4 { outcode($1, &$2); }
-| LTYPES spec5 { outcode($1, &$2); }
-| LTYPEM spec6 { outcode($1, &$2); }
-| LTYPEI spec7 { outcode($1, &$2); }
-| LTYPEG spec8 { outcode($1, &$2); }
-
-nonnon:
- {
- $$.from = nullgen;
- $$.to = nullgen;
- }
-| ','
- {
- $$.from = nullgen;
- $$.to = nullgen;
- }
-
-rimrem:
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-remrim:
- rem ',' rim
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-rimnon:
- rim ','
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-
-nonrem:
- ',' rem
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rem
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-
-nonrel:
- ',' rel
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rel
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-
-spec1: /* DATA */
- nam '/' con ',' imm
- {
- $$.from = $1;
- $$.from.scale = $3;
- $$.to = $5;
- }
-
-spec2: /* TEXT */
- mem ',' imm2
- {
- $$.from = $1;
- $$.to = $3;
- }
-| mem ',' con ',' imm2
- {
- $$.from = $1;
- $$.from.scale = $3;
- $$.to = $5;
- }
-
-spec3: /* JMP/CALL */
- ',' rom
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rom
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-
-spec4: /* NOP */
- nonnon
-| nonrem
-
-spec5: /* SHL/SHR */
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-| rim ',' rem ':' LLREG
- {
- $$.from = $1;
- $$.to = $3;
- if($$.from.index != D_NONE)
- yyerror("dp shift with lhs index");
- $$.from.index = $5;
- }
-
-spec6: /* MOVW/MOVL */
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-| rim ',' rem ':' LSREG
- {
- $$.from = $1;
- $$.to = $3;
- if($$.to.index != D_NONE)
- yyerror("dp move with lhs index");
- $$.to.index = $5;
- }
-
-spec7:
- rim ','
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-spec8: /* GLOBL */
- mem ',' imm
- {
- $$.from = $1;
- $$.to = $3;
- }
-| mem ',' con ',' imm
- {
- $$.from = $1;
- $$.from.scale = $3;
- $$.to = $5;
- }
-
-rem:
- reg
-| mem
-
-rom:
- rel
-| nmem
-| '*' reg
- {
- $$ = $2;
- }
-| '*' omem
- {
- $$ = $2;
- }
-| reg
-| omem
-| imm
-
-rim:
- rem
-| imm
-
-rel:
- con '(' LPC ')'
- {
- $$ = nullgen;
- $$.type = D_BRANCH;
- $$.offset = $1 + pc;
- }
-| LNAME offset
- {
- $$ = nullgen;
- if(pass == 2)
- yyerror("undefined label: %s", $1->name);
- $$.type = D_BRANCH;
- $$.sym = $1;
- $$.offset = $2;
- }
-| LLAB offset
- {
- $$ = nullgen;
- $$.type = D_BRANCH;
- $$.sym = $1;
- $$.offset = $1->value + $2;
- }
-
-reg:
- LBREG
- {
- $$ = nullgen;
- $$.type = $1;
- }
-| LFREG
- {
- $$ = nullgen;
- $$.type = $1;
- }
-| LLREG
- {
- $$ = nullgen;
- $$.type = $1;
- }
-| LSP
- {
- $$ = nullgen;
- $$.type = D_SP;
- }
-| LSREG
- {
- $$ = nullgen;
- $$.type = $1;
- }
-
-imm:
- '$' con
- {
- $$ = nullgen;
- $$.type = D_CONST;
- $$.offset = $2;
- }
-| '$' nam
- {
- $$ = $2;
- $$.index = $2.type;
- $$.type = D_ADDR;
- /*
- if($2.type == D_AUTO || $2.type == D_PARAM)
- yyerror("constant cannot be automatic: %s",
- $2.sym->name);
- */
- }
-| '$' LSCONST
- {
- $$ = nullgen;
- $$.type = D_SCONST;
- memcpy($$.sval, $2, sizeof($$.sval));
- }
-| '$' LFCONST
- {
- $$ = nullgen;
- $$.type = D_FCONST;
- $$.dval = $2;
- }
-| '$' '(' LFCONST ')'
- {
- $$ = nullgen;
- $$.type = D_FCONST;
- $$.dval = $3;
- }
-| '$' '-' LFCONST
- {
- $$ = nullgen;
- $$.type = D_FCONST;
- $$.dval = -$3;
- }
-
-imm2:
- '$' con2
- {
- $$ = nullgen;
- $$.type = D_CONST2;
- $$.offset = $2.v1;
- $$.offset2 = $2.v2;
- }
-
-con2:
- LCONST
- {
- $$.v1 = $1;
- $$.v2 = 0;
- }
-| '-' LCONST
- {
- $$.v1 = -$2;
- $$.v2 = 0;
- }
-| LCONST '-' LCONST
- {
- $$.v1 = $1;
- $$.v2 = $3;
- }
-| '-' LCONST '-' LCONST
- {
- $$.v1 = -$2;
- $$.v2 = $4;
- }
-
-mem:
- omem
-| nmem
-
-omem:
- con
- {
- $$ = nullgen;
- $$.type = D_INDIR+D_NONE;
- $$.offset = $1;
- }
-| con '(' LLREG ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+$3;
- $$.offset = $1;
- }
-| con '(' LSP ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+D_SP;
- $$.offset = $1;
- }
-| con '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+D_NONE;
- $$.offset = $1;
- $$.index = $3;
- $$.scale = $5;
- checkscale($$.scale);
- }
-| con '(' LLREG ')' '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+$3;
- $$.offset = $1;
- $$.index = $6;
- $$.scale = $8;
- checkscale($$.scale);
- }
-| '(' LLREG ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+$2;
- }
-| '(' LSP ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+D_SP;
- }
-| con '(' LSREG ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+$3;
- $$.offset = $1;
- }
-| '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+D_NONE;
- $$.index = $2;
- $$.scale = $4;
- checkscale($$.scale);
- }
-| '(' LLREG ')' '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.type = D_INDIR+$2;
- $$.index = $5;
- $$.scale = $7;
- checkscale($$.scale);
- }
-
-nmem:
- nam
- {
- $$ = $1;
- }
-| nam '(' LLREG '*' con ')'
- {
- $$ = $1;
- $$.index = $3;
- $$.scale = $5;
- checkscale($$.scale);
- }
-
-nam:
- LNAME offset '(' pointer ')'
- {
- $$ = nullgen;
- $$.type = $4;
- $$.sym = $1;
- $$.offset = $2;
- }
-| LNAME '<' '>' offset '(' LSB ')'
- {
- $$ = nullgen;
- $$.type = D_STATIC;
- $$.sym = $1;
- $$.offset = $4;
- }
-
-offset:
- {
- $$ = 0;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '-' con
- {
- $$ = -$2;
- }
-
-pointer:
- LSB
-| LSP
- {
- $$ = D_AUTO;
- }
-| 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/8a/doc.go b/src/cmd/8a/doc.go
deleted file mode 100644
index a43b4461f..000000000
--- a/src/cmd/8a/doc.go
+++ /dev/null
@@ -1,14 +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.
-
-/*
-
-8a is a version of the Plan 9 assembler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2a
-
-Its target architecture is the x86, referred to by these tools for historical reasons as 386.
-
-*/
-package documentation
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
deleted file mode 100644
index ab4de417a..000000000
--- a/src/cmd/8a/lex.c
+++ /dev/null
@@ -1,971 +0,0 @@
-// Inferno utils/8a/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8a/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.
-
-#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)
-{
- return sys&Plan9;
-}
-
-int
-pathchar(void)
-{
- return '/';
-}
-
-void
-main(int argc, char *argv[])
-{
- char *p;
- int c;
-
- thechar = '8';
- thestring = "386";
-
- ensuresymb(NSYMB);
- memset(debug, 0, sizeof(debug));
- cinit();
- outfile = 0;
- setinclude(".");
- ARGBEGIN {
- default:
- c = ARGC();
- if(c >= 0 || c < sizeof(debug))
- debug[c] = 1;
- break;
-
- case 'o':
- outfile = ARGF();
- break;
-
- case 'D':
- p = ARGF();
- if(p) {
- if (nDlist%8 == 0)
- Dlist = allocn(Dlist, nDlist*sizeof(char *),
- 8*sizeof(char *));
- Dlist[nDlist++] = p;
- }
- break;
-
- case 'I':
- p = ARGF();
- setinclude(p);
- break;
- } ARGEND
- if(*argv == 0) {
- print("usage: %ca [-options] file.s\n", thechar);
- errorexit();
- }
- if(argc > 1){
- print("can't assemble multiple files\n");
- errorexit();
- }
- if(assemble(argv[0]))
- errorexit();
- 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);
-
- pass = 1;
- pinit(file);
-
- Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
-
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- if(nerrors) {
- cclean();
- return nerrors;
- }
-
- Bprint(&obuf, "\n!\n");
-
- pass = 2;
- outhist();
- pinit(file);
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- cclean();
- return nerrors;
-}
-
-struct
-{
- char *name;
- ushort type;
- ushort value;
-} itab[] =
-{
- "SP", LSP, D_AUTO,
- "SB", LSB, D_EXTERN,
- "FP", LFP, D_PARAM,
- "PC", LPC, D_BRANCH,
-
- "AL", LBREG, D_AL,
- "CL", LBREG, D_CL,
- "DL", LBREG, D_DL,
- "BL", LBREG, D_BL,
- "AH", LBREG, D_AH,
- "CH", LBREG, D_CH,
- "DH", LBREG, D_DH,
- "BH", LBREG, D_BH,
-
- "AX", LLREG, D_AX,
- "CX", LLREG, D_CX,
- "DX", LLREG, D_DX,
- "BX", LLREG, D_BX,
-/* "SP", LLREG, D_SP, */
- "BP", LLREG, D_BP,
- "SI", LLREG, D_SI,
- "DI", LLREG, D_DI,
-
- "F0", LFREG, D_F0+0,
- "F1", LFREG, D_F0+1,
- "F2", LFREG, D_F0+2,
- "F3", LFREG, D_F0+3,
- "F4", LFREG, D_F0+4,
- "F5", LFREG, D_F0+5,
- "F6", LFREG, D_F0+6,
- "F7", LFREG, D_F0+7,
-
- "CS", LSREG, D_CS,
- "SS", LSREG, D_SS,
- "DS", LSREG, D_DS,
- "ES", LSREG, D_ES,
- "FS", LSREG, D_FS,
- "GS", LSREG, D_GS,
-
- "GDTR", LBREG, D_GDTR,
- "IDTR", LBREG, D_IDTR,
- "LDTR", LBREG, D_LDTR,
- "MSW", LBREG, D_MSW,
- "TASK", LBREG, D_TASK,
-
- "CR0", LBREG, D_CR+0,
- "CR1", LBREG, D_CR+1,
- "CR2", LBREG, D_CR+2,
- "CR3", LBREG, D_CR+3,
- "CR4", LBREG, D_CR+4,
- "CR5", LBREG, D_CR+5,
- "CR6", LBREG, D_CR+6,
- "CR7", LBREG, D_CR+7,
-
- "DR0", LBREG, D_DR+0,
- "DR1", LBREG, D_DR+1,
- "DR2", LBREG, D_DR+2,
- "DR3", LBREG, D_DR+3,
- "DR4", LBREG, D_DR+4,
- "DR5", LBREG, D_DR+5,
- "DR6", LBREG, D_DR+6,
- "DR7", LBREG, D_DR+7,
-
- "TR0", LBREG, D_TR+0,
- "TR1", LBREG, D_TR+1,
- "TR2", LBREG, D_TR+2,
- "TR3", LBREG, D_TR+3,
- "TR4", LBREG, D_TR+4,
- "TR5", LBREG, D_TR+5,
- "TR6", LBREG, D_TR+6,
- "TR7", LBREG, D_TR+7,
-
- "AAA", LTYPE0, AAAA,
- "AAD", LTYPE0, AAAD,
- "AAM", LTYPE0, AAAM,
- "AAS", LTYPE0, AAAS,
- "ADCB", LTYPE3, AADCB,
- "ADCL", LTYPE3, AADCL,
- "ADCW", LTYPE3, AADCW,
- "ADDB", LTYPE3, AADDB,
- "ADDL", LTYPE3, AADDL,
- "ADDW", LTYPE3, AADDW,
- "ADJSP", LTYPE2, AADJSP,
- "ANDB", LTYPE3, AANDB,
- "ANDL", LTYPE3, AANDL,
- "ANDW", LTYPE3, AANDW,
- "ARPL", LTYPE3, AARPL,
- "BOUNDL", LTYPE3, ABOUNDL,
- "BOUNDW", LTYPE3, ABOUNDW,
- "BSFL", LTYPE3, ABSFL,
- "BSFW", LTYPE3, ABSFW,
- "BSRL", LTYPE3, ABSRL,
- "BSRW", LTYPE3, ABSRW,
- "BTCL", LTYPE3, ABTCL,
- "BTCW", LTYPE3, ABTCW,
- "BTL", LTYPE3, ABTL,
- "BTRL", LTYPE3, ABTRL,
- "BTRW", LTYPE3, ABTRW,
- "BTSL", LTYPE3, ABTSL,
- "BTSW", LTYPE3, ABTSW,
- "BTW", LTYPE3, ABTW,
- "BYTE", LTYPE2, ABYTE,
- "CALL", LTYPEC, ACALL,
- "CLC", LTYPE0, ACLC,
- "CLD", LTYPE0, ACLD,
- "CLI", LTYPE0, ACLI,
- "CLTS", LTYPE0, ACLTS,
- "CMC", LTYPE0, ACMC,
- "CMPB", LTYPE4, ACMPB,
- "CMPL", LTYPE4, ACMPL,
- "CMPW", LTYPE4, ACMPW,
- "CMPSB", LTYPE0, ACMPSB,
- "CMPSL", LTYPE0, ACMPSL,
- "CMPSW", LTYPE0, ACMPSW,
- "CMPXCHG8B", LTYPE1, ACMPXCHG8B,
- "CMPXCHGB", LTYPE3, ACMPXCHGB,
- "CMPXCHGL", LTYPE3, ACMPXCHGL,
- "CMPXCHGW", LTYPE3, ACMPXCHGW,
- "DAA", LTYPE0, ADAA,
- "DAS", LTYPE0, ADAS,
- "DATA", LTYPED, ADATA,
- "DECB", LTYPE1, ADECB,
- "DECL", LTYPE1, ADECL,
- "DECW", LTYPE1, ADECW,
- "DIVB", LTYPE2, ADIVB,
- "DIVL", LTYPE2, ADIVL,
- "DIVW", LTYPE2, ADIVW,
- "END", LTYPE0, AEND,
- "ENTER", LTYPE2, AENTER,
- "GLOBL", LTYPEG, AGLOBL,
- "HLT", LTYPE0, AHLT,
- "IDIVB", LTYPE2, AIDIVB,
- "IDIVL", LTYPE2, AIDIVL,
- "IDIVW", LTYPE2, AIDIVW,
- "IMULB", LTYPE2, AIMULB,
- "IMULL", LTYPE2, AIMULL,
- "IMULW", LTYPE2, AIMULW,
- "INB", LTYPE0, AINB,
- "INL", LTYPE0, AINL,
- "INW", LTYPE0, AINW,
- "INCB", LTYPE1, AINCB,
- "INCL", LTYPE1, AINCL,
- "INCW", LTYPE1, AINCW,
- "INSB", LTYPE0, AINSB,
- "INSL", LTYPE0, AINSL,
- "INSW", LTYPE0, AINSW,
- "INT", LTYPE2, AINT,
- "INTO", LTYPE0, AINTO,
- "IRETL", LTYPE0, AIRETL,
- "IRETW", LTYPE0, AIRETW,
-
- "JOS", LTYPER, AJOS,
- "JO", LTYPER, AJOS, /* alternate */
- "JOC", LTYPER, AJOC,
- "JNO", LTYPER, AJOC, /* alternate */
- "JCS", LTYPER, AJCS,
- "JB", LTYPER, AJCS, /* alternate */
- "JC", LTYPER, AJCS, /* alternate */
- "JNAE", LTYPER, AJCS, /* alternate */
- "JLO", LTYPER, AJCS, /* alternate */
- "JCC", LTYPER, AJCC,
- "JAE", LTYPER, AJCC, /* alternate */
- "JNB", LTYPER, AJCC, /* alternate */
- "JNC", LTYPER, AJCC, /* alternate */
- "JHS", LTYPER, AJCC, /* alternate */
- "JEQ", LTYPER, AJEQ,
- "JE", LTYPER, AJEQ, /* alternate */
- "JZ", LTYPER, AJEQ, /* alternate */
- "JNE", LTYPER, AJNE,
- "JNZ", LTYPER, AJNE, /* alternate */
- "JLS", LTYPER, AJLS,
- "JBE", LTYPER, AJLS, /* alternate */
- "JNA", LTYPER, AJLS, /* alternate */
- "JHI", LTYPER, AJHI,
- "JA", LTYPER, AJHI, /* alternate */
- "JNBE", LTYPER, AJHI, /* alternate */
- "JMI", LTYPER, AJMI,
- "JS", LTYPER, AJMI, /* alternate */
- "JPL", LTYPER, AJPL,
- "JNS", LTYPER, AJPL, /* alternate */
- "JPS", LTYPER, AJPS,
- "JP", LTYPER, AJPS, /* alternate */
- "JPE", LTYPER, AJPS, /* alternate */
- "JPC", LTYPER, AJPC,
- "JNP", LTYPER, AJPC, /* alternate */
- "JPO", LTYPER, AJPC, /* alternate */
- "JLT", LTYPER, AJLT,
- "JL", LTYPER, AJLT, /* alternate */
- "JNGE", LTYPER, AJLT, /* alternate */
- "JGE", LTYPER, AJGE,
- "JNL", LTYPER, AJGE, /* alternate */
- "JLE", LTYPER, AJLE,
- "JNG", LTYPER, AJLE, /* alternate */
- "JGT", LTYPER, AJGT,
- "JG", LTYPER, AJGT, /* alternate */
- "JNLE", LTYPER, AJGT, /* alternate */
-
- "JCXZ", LTYPER, AJCXZ,
- "JMP", LTYPEC, AJMP,
- "LAHF", LTYPE0, ALAHF,
- "LARL", LTYPE3, ALARL,
- "LARW", LTYPE3, ALARW,
- "LEAL", LTYPE3, ALEAL,
- "LEAW", LTYPE3, ALEAW,
- "LEAVEL", LTYPE0, ALEAVEL,
- "LEAVEW", LTYPE0, ALEAVEW,
- "LOCK", LTYPE0, ALOCK,
- "LODSB", LTYPE0, ALODSB,
- "LODSL", LTYPE0, ALODSL,
- "LODSW", LTYPE0, ALODSW,
- "LONG", LTYPE2, ALONG,
- "LOOP", LTYPER, ALOOP,
- "LOOPEQ", LTYPER, ALOOPEQ,
- "LOOPNE", LTYPER, ALOOPNE,
- "LSLL", LTYPE3, ALSLL,
- "LSLW", LTYPE3, ALSLW,
- "MOVB", LTYPE3, AMOVB,
- "MOVL", LTYPEM, AMOVL,
- "MOVW", LTYPEM, AMOVW,
- "MOVBLSX", LTYPE3, AMOVBLSX,
- "MOVBLZX", LTYPE3, AMOVBLZX,
- "MOVBWSX", LTYPE3, AMOVBWSX,
- "MOVBWZX", LTYPE3, AMOVBWZX,
- "MOVWLSX", LTYPE3, AMOVWLSX,
- "MOVWLZX", LTYPE3, AMOVWLZX,
- "MOVSB", LTYPE0, AMOVSB,
- "MOVSL", LTYPE0, AMOVSL,
- "MOVSW", LTYPE0, AMOVSW,
- "MULB", LTYPE2, AMULB,
- "MULL", LTYPE2, AMULL,
- "MULW", LTYPE2, AMULW,
- "NEGB", LTYPE1, ANEGB,
- "NEGL", LTYPE1, ANEGL,
- "NEGW", LTYPE1, ANEGW,
- "NOP", LTYPEN, ANOP,
- "NOTB", LTYPE1, ANOTB,
- "NOTL", LTYPE1, ANOTL,
- "NOTW", LTYPE1, ANOTW,
- "ORB", LTYPE3, AORB,
- "ORL", LTYPE3, AORL,
- "ORW", LTYPE3, AORW,
- "OUTB", LTYPE0, AOUTB,
- "OUTL", LTYPE0, AOUTL,
- "OUTW", LTYPE0, AOUTW,
- "OUTSB", LTYPE0, AOUTSB,
- "OUTSL", LTYPE0, AOUTSL,
- "OUTSW", LTYPE0, AOUTSW,
- "POPAL", LTYPE0, APOPAL,
- "POPAW", LTYPE0, APOPAW,
- "POPFL", LTYPE0, APOPFL,
- "POPFW", LTYPE0, APOPFW,
- "POPL", LTYPE1, APOPL,
- "POPW", LTYPE1, APOPW,
- "PUSHAL", LTYPE0, APUSHAL,
- "PUSHAW", LTYPE0, APUSHAW,
- "PUSHFL", LTYPE0, APUSHFL,
- "PUSHFW", LTYPE0, APUSHFW,
- "PUSHL", LTYPE2, APUSHL,
- "PUSHW", LTYPE2, APUSHW,
- "RCLB", LTYPE3, ARCLB,
- "RCLL", LTYPE3, ARCLL,
- "RCLW", LTYPE3, ARCLW,
- "RCRB", LTYPE3, ARCRB,
- "RCRL", LTYPE3, ARCRL,
- "RCRW", LTYPE3, ARCRW,
- "REP", LTYPE0, AREP,
- "REPN", LTYPE0, AREPN,
- "RET", LTYPE0, ARET,
- "ROLB", LTYPE3, AROLB,
- "ROLL", LTYPE3, AROLL,
- "ROLW", LTYPE3, AROLW,
- "RORB", LTYPE3, ARORB,
- "RORL", LTYPE3, ARORL,
- "RORW", LTYPE3, ARORW,
- "SAHF", LTYPE0, ASAHF,
- "SALB", LTYPE3, ASALB,
- "SALL", LTYPE3, ASALL,
- "SALW", LTYPE3, ASALW,
- "SARB", LTYPE3, ASARB,
- "SARL", LTYPE3, ASARL,
- "SARW", LTYPE3, ASARW,
- "SBBB", LTYPE3, ASBBB,
- "SBBL", LTYPE3, ASBBL,
- "SBBW", LTYPE3, ASBBW,
- "SCASB", LTYPE0, ASCASB,
- "SCASL", LTYPE0, ASCASL,
- "SCASW", LTYPE0, ASCASW,
- "SETCC", LTYPE1, ASETCC,
- "SETCS", LTYPE1, ASETCS,
- "SETEQ", LTYPE1, ASETEQ,
- "SETGE", LTYPE1, ASETGE,
- "SETGT", LTYPE1, ASETGT,
- "SETHI", LTYPE1, ASETHI,
- "SETLE", LTYPE1, ASETLE,
- "SETLS", LTYPE1, ASETLS,
- "SETLT", LTYPE1, ASETLT,
- "SETMI", LTYPE1, ASETMI,
- "SETNE", LTYPE1, ASETNE,
- "SETOC", LTYPE1, ASETOC,
- "SETOS", LTYPE1, ASETOS,
- "SETPC", LTYPE1, ASETPC,
- "SETPL", LTYPE1, ASETPL,
- "SETPS", LTYPE1, ASETPS,
- "CDQ", LTYPE0, ACDQ,
- "CWD", LTYPE0, ACWD,
- "SHLB", LTYPE3, ASHLB,
- "SHLL", LTYPES, ASHLL,
- "SHLW", LTYPES, ASHLW,
- "SHRB", LTYPE3, ASHRB,
- "SHRL", LTYPES, ASHRL,
- "SHRW", LTYPES, ASHRW,
- "STC", LTYPE0, ASTC,
- "STD", LTYPE0, ASTD,
- "STI", LTYPE0, ASTI,
- "STOSB", LTYPE0, ASTOSB,
- "STOSL", LTYPE0, ASTOSL,
- "STOSW", LTYPE0, ASTOSW,
- "SUBB", LTYPE3, ASUBB,
- "SUBL", LTYPE3, ASUBL,
- "SUBW", LTYPE3, ASUBW,
- "SYSCALL", LTYPE0, ASYSCALL,
- "TESTB", LTYPE3, ATESTB,
- "TESTL", LTYPE3, ATESTL,
- "TESTW", LTYPE3, ATESTW,
- "TEXT", LTYPET, ATEXT,
- "VERR", LTYPE2, AVERR,
- "VERW", LTYPE2, AVERW,
- "WAIT", LTYPE0, AWAIT,
- "WORD", LTYPE2, AWORD,
- "XADDB", LTYPE3, AXADDB,
- "XADDL", LTYPE3, AXADDL,
- "XADDW", LTYPE3, AXADDW,
- "XCHGB", LTYPE3, AXCHGB,
- "XCHGL", LTYPE3, AXCHGL,
- "XCHGW", LTYPE3, AXCHGW,
- "XLAT", LTYPE2, AXLAT,
- "XORB", LTYPE3, AXORB,
- "XORL", LTYPE3, AXORL,
- "XORW", LTYPE3, AXORW,
-
- "CMOVLCC", LTYPE3, ACMOVLCC,
- "CMOVLCS", LTYPE3, ACMOVLCS,
- "CMOVLEQ", LTYPE3, ACMOVLEQ,
- "CMOVLGE", LTYPE3, ACMOVLGE,
- "CMOVLGT", LTYPE3, ACMOVLGT,
- "CMOVLHI", LTYPE3, ACMOVLHI,
- "CMOVLLE", LTYPE3, ACMOVLLE,
- "CMOVLLS", LTYPE3, ACMOVLLS,
- "CMOVLLT", LTYPE3, ACMOVLLT,
- "CMOVLMI", LTYPE3, ACMOVLMI,
- "CMOVLNE", LTYPE3, ACMOVLNE,
- "CMOVLOC", LTYPE3, ACMOVLOC,
- "CMOVLOS", LTYPE3, ACMOVLOS,
- "CMOVLPC", LTYPE3, ACMOVLPC,
- "CMOVLPL", LTYPE3, ACMOVLPL,
- "CMOVLPS", LTYPE3, ACMOVLPS,
- "CMOVWCC", LTYPE3, ACMOVWCC,
- "CMOVWCS", LTYPE3, ACMOVWCS,
- "CMOVWEQ", LTYPE3, ACMOVWEQ,
- "CMOVWGE", LTYPE3, ACMOVWGE,
- "CMOVWGT", LTYPE3, ACMOVWGT,
- "CMOVWHI", LTYPE3, ACMOVWHI,
- "CMOVWLE", LTYPE3, ACMOVWLE,
- "CMOVWLS", LTYPE3, ACMOVWLS,
- "CMOVWLT", LTYPE3, ACMOVWLT,
- "CMOVWMI", LTYPE3, ACMOVWMI,
- "CMOVWNE", LTYPE3, ACMOVWNE,
- "CMOVWOC", LTYPE3, ACMOVWOC,
- "CMOVWOS", LTYPE3, ACMOVWOS,
- "CMOVWPC", LTYPE3, ACMOVWPC,
- "CMOVWPL", LTYPE3, ACMOVWPL,
- "CMOVWPS", LTYPE3, ACMOVWPS,
-
- "FMOVB", LTYPE3, AFMOVB,
- "FMOVBP", LTYPE3, AFMOVBP,
- "FMOVD", LTYPE3, AFMOVD,
- "FMOVDP", LTYPE3, AFMOVDP,
- "FMOVF", LTYPE3, AFMOVF,
- "FMOVFP", LTYPE3, AFMOVFP,
- "FMOVL", LTYPE3, AFMOVL,
- "FMOVLP", LTYPE3, AFMOVLP,
- "FMOVV", LTYPE3, AFMOVV,
- "FMOVVP", LTYPE3, AFMOVVP,
- "FMOVW", LTYPE3, AFMOVW,
- "FMOVWP", LTYPE3, AFMOVWP,
- "FMOVX", LTYPE3, AFMOVX,
- "FMOVXP", LTYPE3, AFMOVXP,
- "FCMOVCC", LTYPE3, AFCMOVCC,
- "FCMOVCS", LTYPE3, AFCMOVCS,
- "FCMOVEQ", LTYPE3, AFCMOVEQ,
- "FCMOVHI", LTYPE3, AFCMOVHI,
- "FCMOVLS", LTYPE3, AFCMOVLS,
- "FCMOVNE", LTYPE3, AFCMOVNE,
- "FCMOVNU", LTYPE3, AFCMOVNU,
- "FCMOVUN", LTYPE3, AFCMOVUN,
- "FCOMB", LTYPE3, AFCOMB,
- "FCOMBP", LTYPE3, AFCOMBP,
- "FCOMD", LTYPE3, AFCOMD,
- "FCOMDP", LTYPE3, AFCOMDP,
- "FCOMDPP", LTYPE3, AFCOMDPP,
- "FCOMF", LTYPE3, AFCOMF,
- "FCOMFP", LTYPE3, AFCOMFP,
- "FCOMI", LTYPE3, AFCOMI,
- "FCOMIP", LTYPE3, AFCOMIP,
- "FCOML", LTYPE3, AFCOML,
- "FCOMLP", LTYPE3, AFCOMLP,
- "FCOMW", LTYPE3, AFCOMW,
- "FCOMWP", LTYPE3, AFCOMWP,
- "FUCOM", LTYPE3, AFUCOM,
- "FUCOMI", LTYPE3, AFUCOMI,
- "FUCOMIP", LTYPE3, AFUCOMIP,
- "FUCOMP", LTYPE3, AFUCOMP,
- "FUCOMPP", LTYPE3, AFUCOMPP,
- "FADDW", LTYPE3, AFADDW,
- "FADDL", LTYPE3, AFADDL,
- "FADDF", LTYPE3, AFADDF,
- "FADDD", LTYPE3, AFADDD,
- "FADDDP", LTYPE3, AFADDDP,
- "FSUBDP", LTYPE3, AFSUBDP,
- "FSUBW", LTYPE3, AFSUBW,
- "FSUBL", LTYPE3, AFSUBL,
- "FSUBF", LTYPE3, AFSUBF,
- "FSUBD", LTYPE3, AFSUBD,
- "FSUBRDP", LTYPE3, AFSUBRDP,
- "FSUBRW", LTYPE3, AFSUBRW,
- "FSUBRL", LTYPE3, AFSUBRL,
- "FSUBRF", LTYPE3, AFSUBRF,
- "FSUBRD", LTYPE3, AFSUBRD,
- "FMULDP", LTYPE3, AFMULDP,
- "FMULW", LTYPE3, AFMULW,
- "FMULL", LTYPE3, AFMULL,
- "FMULF", LTYPE3, AFMULF,
- "FMULD", LTYPE3, AFMULD,
- "FDIVDP", LTYPE3, AFDIVDP,
- "FDIVW", LTYPE3, AFDIVW,
- "FDIVL", LTYPE3, AFDIVL,
- "FDIVF", LTYPE3, AFDIVF,
- "FDIVD", LTYPE3, AFDIVD,
- "FDIVRDP", LTYPE3, AFDIVRDP,
- "FDIVRW", LTYPE3, AFDIVRW,
- "FDIVRL", LTYPE3, AFDIVRL,
- "FDIVRF", LTYPE3, AFDIVRF,
- "FDIVRD", LTYPE3, AFDIVRD,
- "FXCHD", LTYPE3, AFXCHD,
- "FFREE", LTYPE1, AFFREE,
- "FLDCW", LTYPE2, AFLDCW,
- "FLDENV", LTYPE1, AFLDENV,
- "FRSTOR", LTYPE2, AFRSTOR,
- "FSAVE", LTYPE1, AFSAVE,
- "FSTCW", LTYPE1, AFSTCW,
- "FSTENV", LTYPE1, AFSTENV,
- "FSTSW", LTYPE1, AFSTSW,
- "F2XM1", LTYPE0, AF2XM1,
- "FABS", LTYPE0, AFABS,
- "FCHS", LTYPE0, AFCHS,
- "FCLEX", LTYPE0, AFCLEX,
- "FCOS", LTYPE0, AFCOS,
- "FDECSTP", LTYPE0, AFDECSTP,
- "FINCSTP", LTYPE0, AFINCSTP,
- "FINIT", LTYPE0, AFINIT,
- "FLD1", LTYPE0, AFLD1,
- "FLDL2E", LTYPE0, AFLDL2E,
- "FLDL2T", LTYPE0, AFLDL2T,
- "FLDLG2", LTYPE0, AFLDLG2,
- "FLDLN2", LTYPE0, AFLDLN2,
- "FLDPI", LTYPE0, AFLDPI,
- "FLDZ", LTYPE0, AFLDZ,
- "FNOP", LTYPE0, AFNOP,
- "FPATAN", LTYPE0, AFPATAN,
- "FPREM", LTYPE0, AFPREM,
- "FPREM1", LTYPE0, AFPREM1,
- "FPTAN", LTYPE0, AFPTAN,
- "FRNDINT", LTYPE0, AFRNDINT,
- "FSCALE", LTYPE0, AFSCALE,
- "FSIN", LTYPE0, AFSIN,
- "FSINCOS", LTYPE0, AFSINCOS,
- "FSQRT", LTYPE0, AFSQRT,
- "FTST", LTYPE0, AFTST,
- "FXAM", LTYPE0, AFXAM,
- "FXTRACT", LTYPE0, AFXTRACT,
- "FYL2X", LTYPE0, AFYL2X,
- "FYL2XP1", LTYPE0, AFYL2XP1,
-
- 0
-};
-
-void
-cinit(void)
-{
- Sym *s;
- int i;
-
- nullgen.sym = S;
- nullgen.offset = 0;
- if(FPCHIP)
- nullgen.dval = 0;
- for(i=0; i<sizeof(nullgen.sval); i++)
- nullgen.sval[i] = 0;
- nullgen.type = D_NONE;
- nullgen.index = D_NONE;
- nullgen.scale = 0;
-
- 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);
- if(s->type != LNAME)
- yyerror("double initialization %s", itab[i].name);
- s->type = itab[i].type;
- s->value = itab[i].value;
- }
-
- pathname = allocn(pathname, 0, 100);
- if(getwd(pathname, 99) == 0) {
- pathname = allocn(pathname, 100, 900);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
- }
-}
-
-void
-checkscale(int scale)
-{
-
- switch(scale) {
- case 1:
- case 2:
- case 4:
- case 8:
- return;
- }
- yyerror("scale must be 1248: %d", scale);
-}
-
-void
-syminit(Sym *s)
-{
-
- s->type = LNAME;
- s->value = 0;
-}
-
-void
-cclean(void)
-{
- Gen2 g2;
-
- g2.from = nullgen;
- g2.to = nullgen;
- outcode(AEND, &g2);
- Bflush(&obuf);
-}
-
-void
-zname(char *n, int t, int s)
-{
-
- Bputc(&obuf, ANAME); /* as(2) */
- Bputc(&obuf, ANAME>>8);
- Bputc(&obuf, t); /* type */
- Bputc(&obuf, s); /* sym */
- while(*n) {
- Bputc(&obuf, *n);
- n++;
- }
- Bputc(&obuf, 0);
-}
-
-void
-zaddr(Gen *a, int s)
-{
- int32 l;
- int i, t;
- char *n;
- Ieee e;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(a->offset != 0)
- t |= T_OFFSET;
- if(s != 0)
- t |= T_SYM;
-
- switch(a->type) {
- default:
- t |= T_TYPE;
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_CONST2:
- t |= T_OFFSET|T_OFFSET2;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- case D_NONE:
- break;
- }
- Bputc(&obuf, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- Bputc(&obuf, a->index);
- Bputc(&obuf, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- Bputc(&obuf, l);
- Bputc(&obuf, l>>8);
- Bputc(&obuf, l>>16);
- Bputc(&obuf, l>>24);
- }
- if(t & T_OFFSET2) {
- l = a->offset2;
- Bputc(&obuf, l);
- Bputc(&obuf, l>>8);
- Bputc(&obuf, l>>16);
- Bputc(&obuf, l>>24);
- }
- if(t & T_SYM) /* implies sym */
- Bputc(&obuf, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->dval);
- l = e.l;
- Bputc(&obuf, l);
- Bputc(&obuf, l>>8);
- Bputc(&obuf, l>>16);
- Bputc(&obuf, l>>24);
- l = e.h;
- Bputc(&obuf, l);
- Bputc(&obuf, l>>8);
- Bputc(&obuf, l>>16);
- Bputc(&obuf, l>>24);
- return;
- }
- if(t & T_SCONST) {
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- Bputc(&obuf, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- Bputc(&obuf, a->type);
-}
-
-void
-outcode(int a, Gen2 *g2)
-{
- int sf, st, t;
- Sym *s;
-
- if(pass == 1)
- goto out;
-
-jackpot:
- sf = 0;
- s = g2->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = g2->from.type;
- if(t == D_ADDR)
- t = g2->from.index;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = g2->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = g2->to.type;
- if(t == D_ADDR)
- t = g2->to.index;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- Bputc(&obuf, a);
- Bputc(&obuf, a>>8);
- Bputc(&obuf, stmtline);
- Bputc(&obuf, stmtline>>8);
- Bputc(&obuf, stmtline>>16);
- Bputc(&obuf, stmtline>>24);
- zaddr(&g2->from, sf);
- zaddr(&g2->to, st);
-
-out:
- if(a != AGLOBL && a != ADATA)
- pc++;
-}
-
-void
-outhist(void)
-{
- Gen g;
- Hist *h;
- char *p, *q, *op, c;
- int n;
-
- g = nullgen;
- c = pathchar();
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- op = 0;
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname+2;
- c = *p;
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = strchr(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- Bputc(&obuf, ANAME);
- Bputc(&obuf, ANAME>>8);
- Bputc(&obuf, D_FILE); /* type */
- Bputc(&obuf, 1); /* sym */
- Bputc(&obuf, '<');
- Bwrite(&obuf, p, n);
- Bputc(&obuf, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- g.offset = h->offset;
-
- Bputc(&obuf, AHISTORY);
- Bputc(&obuf, AHISTORY>>8);
- Bputc(&obuf, h->line);
- Bputc(&obuf, h->line>>8);
- Bputc(&obuf, h->line>>16);
- Bputc(&obuf, h->line>>24);
- zaddr(&nullgen, 0);
- zaddr(&g, 0);
- }
-}
-
-#include "../cc/lexbody"
-#include "../cc/macbody"
diff --git a/src/cmd/8c/Makefile b/src/cmd/8c/Makefile
deleted file mode 100644
index 60f46d3c9..000000000
--- a/src/cmd/8c/Makefile
+++ /dev/null
@@ -1,37 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=8c
-
-HFILES=\
- gc.h\
- ../8l/8.out.h\
- ../cc/cc.h\
-
-OFILES=\
- cgen.$O\
- cgen64.$O\
- div.$O\
- list.$O\
- machcap.$O\
- mul.$O\
- pgen.$O\
- pswt.$O\
- peep.$O\
- reg.$O\
- sgen.$O\
- swt.$O\
- txt.$O\
- ../8l/enam.$O\
-
-LIB=\
- ../cc/cc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../cc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/8c/cgen.c b/src/cmd/8c/cgen.c
deleted file mode 100644
index 7f02bd96e..000000000
--- a/src/cmd/8c/cgen.c
+++ /dev/null
@@ -1,1857 +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"
-
-/* ,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]) {
- 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);
- 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);
- 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 == 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) {
- if(l->addable >= INDEXED) {
- t = l;
- l = r;
- r = t;
- }
- /* should favour AX */
- 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);
- 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);
- 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]--;
- if(nn != Z) {
- regret(&nod, n);
- gmove(&nod, nn);
- regfree(&nod);
- } else
- if(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;
- 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)
- o = comrel[relindex(o)];
- if(l->complex >= FNX && r->complex >= FNX) {
- regret(&nod, r);
- 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);
- }
- 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);
- 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(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;
- }
- }
-
- 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;
- v = w == 8;
- if(v) {
- 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 e3aae857f..000000000
--- a/src/cmd/8c/doc.go
+++ /dev/null
@@ -1,14 +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.
-
-/*
-
-8c is a version of the Plan 9 C compiler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2c
-
-Its target architecture is the x86, referred to by these tools for historical reasons as 386.
-
-*/
-package documentation
diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h
deleted file mode 100644
index 32b80e995..000000000
--- a/src/cmd/8c/gc.h
+++ /dev/null
@@ -1,411 +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 Adr Adr;
-typedef struct Prog Prog;
-typedef struct Case Case;
-typedef struct C1 C1;
-typedef struct Var Var;
-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;
-
-struct Adr
-{
- int32 offset;
- int32 offset2;
- double dval;
- char sval[NSNAME];
-
- Sym* sym;
- uchar type;
- uchar index;
- uchar etype;
- uchar scale; /* doubles as width in DATA op */
-};
-#define A ((Adr*)0)
-
-#define INDEXED 9
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* link;
- int32 lineno;
- short as;
-};
-#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 Var
-{
- int32 offset;
- Sym* sym;
- char name;
- char etype;
-};
-
-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* firstp;
-EXTERN Prog* lastp;
-EXTERN int32 maxargsafe;
-EXTERN int mnstring;
-EXTERN int retok;
-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 Var var[NVAR];
-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(void);
-
-/*
- * 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*);
-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*, Adr*);
-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*);
-
-/*
- * swt.c
- */
-int swcmp(const void*, const void*);
-void doswit(Node*);
-void swit1(C1*, int, int32, Node*);
-void cas(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);
-void ieeedtod(Ieee*, double);
-
-/*
- * list
- */
-void listinit(void);
-int Pconv(Fmt*);
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Sconv(Fmt*);
-int Rconv(Fmt*);
-int Xconv(Fmt*);
-int Bconv(Fmt*);
-
-/*
- * reg.c
- */
-Reg* rega(void);
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Adr*);
-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(Adr*, int);
-
-/*
- * peep.c
- */
-void peep(void);
-void excise(Reg*);
-Reg* uniqp(Reg*);
-Reg* uniqs(Reg*);
-int regtyp(Adr*);
-int anyvar(Adr*);
-int subprop(Reg*);
-int copyprop(Reg*);
-int copy1(Adr*, Adr*, Reg*, int);
-int copyu(Prog*, Adr*, Adr*);
-
-int copyas(Adr*, Adr*);
-int copyau(Adr*, Adr*);
-int copysub(Adr*, Adr*, Adr*, int);
-int copysub1(Prog*, Adr*, Adr*, 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*);
-
-#pragma varargck type "A" int
-#pragma varargck type "B" Bits
-#pragma varargck type "D" Adr*
-#pragma varargck type "lD" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "S" char*
-
-/* 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 c422905cd..000000000
--- a/src/cmd/8c/list.c
+++ /dev/null
@@ -1,328 +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)
-{
-
- fmtinstall('A', Aconv);
- fmtinstall('B', Bconv);
- fmtinstall('P', Pconv);
- fmtinstall('S', Sconv);
- fmtinstall('D', Dconv);
- fmtinstall('R', Rconv);
-}
-
-int
-Bconv(Fmt *fp)
-{
- char str[STRINGSZ], ss[STRINGSZ], *s;
- Bits bits;
- int i;
-
- str[0] = 0;
- bits = va_arg(fp->args, Bits);
- while(bany(&bits)) {
- i = bnum(bits);
- if(str[0])
- strcat(str, " ");
- if(var[i].sym == S) {
- sprint(ss, "$%d", var[i].offset);
- s = ss;
- } else
- s = var[i].sym->name;
- if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
- break;
- strcat(str, s);
- bits.b[i/32] &= ~(1L << (i%32));
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- switch(p->as) {
- case ADATA:
- sprint(str, "(%L) %A %D/%d,%D",
- p->lineno, p->as, &p->from, p->from.scale, &p->to);
- break;
-
- case ATEXT:
- if(p->from.scale) {
- sprint(str, "(%L) %A %D,%d,%lD",
- p->lineno, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- sprint(str, "(%L) %A %D,%lD",
- p->lineno, p->as, &p->from, &p->to);
- break;
-
- default:
- sprint(str, "(%L) %A %D,%lD",
- p->lineno, p->as, &p->from, &p->to);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Adr *a;
- int i;
-
- a = va_arg(fp->args, Adr*);
- i = a->type;
- if(i >= D_INDIR) {
- if(a->offset)
- sprint(str, "%d(%R)", a->offset, i-D_INDIR);
- else
- sprint(str, "(%R)", i-D_INDIR);
- goto brk;
- }
- switch(i) {
-
- default:
- if(a->offset)
- sprint(str, "$%d,%R", a->offset, i);
- else
- sprint(str, "%R", i);
- break;
-
- case D_NONE:
- str[0] = 0;
- break;
-
- case D_BRANCH:
- sprint(str, "%d(PC)", a->offset-pc);
- break;
-
- case D_EXTERN:
- sprint(str, "%s+%d(SB)", a->sym->name, a->offset);
- break;
-
- case D_STATIC:
- sprint(str, "%s<>+%d(SB)", a->sym->name,
- a->offset);
- break;
-
- case D_AUTO:
- sprint(str, "%s+%d(SP)", a->sym->name, a->offset);
- break;
-
- case D_PARAM:
- if(a->sym)
- sprint(str, "%s+%d(FP)", a->sym->name, a->offset);
- else
- sprint(str, "%d(FP)", a->offset);
- break;
-
- case D_CONST:
- sprint(str, "$%d", a->offset);
- break;
-
- case D_CONST2:
- sprint(str, "$%d-%d", a->offset, a->offset2);
- break;
-
- case D_FCONST:
- sprint(str, "$(%.17e)", a->dval);
- break;
-
- case D_SCONST:
- sprint(str, "$\"%S\"", a->sval);
- break;
-
- case D_ADDR:
- a->type = a->index;
- a->index = D_NONE;
- sprint(str, "$%D", a);
- a->index = a->type;
- a->type = D_ADDR;
- goto conv;
- }
-brk:
- if(a->index != D_NONE) {
- sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
- strcat(str, s);
- }
-conv:
- return fmtstrcpy(fp, str);
-}
-
-char* regstr[] =
-{
- "AL", /*[D_AL]*/
- "CL",
- "DL",
- "BL",
- "AH",
- "CH",
- "DH",
- "BH",
-
- "AX", /*[D_AX]*/
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
-
- "F0", /*[D_F0]*/
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "CS", /*[D_CS]*/
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /*[D_GDTR]*/
- "IDTR", /*[D_IDTR]*/
- "LDTR", /*[D_LDTR]*/
- "MSW", /*[D_MSW] */
- "TASK", /*[D_TASK]*/
-
- "CR0", /*[D_CR]*/
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
-
- "DR0", /*[D_DR]*/
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /*[D_TR]*/
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "NONE", /*[D_NONE]*/
-};
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r >= D_AL && r <= D_NONE)
- sprint(str, "%s", regstr[r-D_AL]);
- else
- sprint(str, "gok(%d)", r);
-
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(double); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- 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/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 a0742807e..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
-{
- char vals[10];
-};
-
-struct Mparam
-{
- uint32 value;
- char alg;
- char neg;
- char shift;
- char arg;
- char 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;
- char *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 9511a5579..000000000
--- a/src/cmd/8c/peep.c
+++ /dev/null
@@ -1,801 +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(Adr *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;
- Adr *v1, *v2;
- Reg *r;
- int t;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case 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;
- Adr *v1, *v2;
- Reg *r;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Adr *v1, Adr *v2, Reg *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, A);
- switch(t) {
- case 2: /* rar, cant split */
- if(debug['P'])
- print("; %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, Adr *v, Adr *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 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(Adr *a, Adr *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(Adr *a, Adr *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(Adr *a, Adr *v, Adr *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 6ba07bed2..000000000
--- a/src/cmd/8c/reg.c
+++ /dev/null
@@ -1,1287 +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"
-
-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:
- 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:
- 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.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) {
- warn(Z, "too many regions");
- goto brk;
- }
- rgp++;
- }
- }
-brk:
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- for(i=0; i<nregion; i++) {
- bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
- vreg = allreg(vreg, rgp);
- if(debug['R']) {
- 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:
- break;
- }
- }
- }
- pc = val;
-
- /*
- * fix up branches
- */
- if(debug['R'])
- if(bany(&addrs))
- print("addrs: %B\n", addrs);
-
- r1 = 0; /* set */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH)
- p->to.offset = r->s2->pc;
- r1 = r;
- }
-
- /*
- * last pass
- * eliminate nops
- * free aux structures
- */
- for(p = firstr->prog; p != P; p = p->link){
- while(p->link && p->link->as == ANOP)
- p->link = p->link->link;
- }
- if(r1 != R) {
- r1->link = freer;
- freer = firstr;
- }
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Adr *a;
- Var *v;
-
- p1 = alloc(sizeof(*p1));
- *p1 = zprog;
- p = r->prog;
-
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->sym = v->sym;
- a->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, Adr *a)
-{
- Var *v;
- int i, t, n, et, z;
- int32 o;
- Bits bit;
- Sym *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 == S)
- 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) {
- if(debug['w'] > 1 && s)
- warn(Z, "variable not optimized: %s", s->name);
- goto none;
- }
- i = nvar;
- nvar++;
- v = &var[i];
- v->sym = s;
- v->offset = o;
- v->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;
- Adr 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;
- Adr 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(Adr *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;
-}
diff --git a/src/cmd/8c/sgen.c b/src/cmd/8c/sgen.c
deleted file mode 100644
index b0f2bc544..000000000
--- a/src/cmd/8c/sgen.c
+++ /dev/null
@@ -1,485 +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 = 0;
- if(!(textflag & NOSPLIT))
- a = argsize();
- else if(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 769ef2c66..000000000
--- a/src/cmd/8c/swt.c
+++ /dev/null
@@ -1,588 +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)
-{
- 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);
- swit1(q, i, def, n);
-
- if(debug['W'])
- print("case < %.8ux\n", r->val);
- patch(sp, pc);
- swit1(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.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.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 zname(Biobuf*, Sym*, int);
-void zaddr(Biobuf*, Adr*, int);
-void outhist(Biobuf*);
-
-void
-outcode(void)
-{
- struct { Sym *sym; short type; } h[NSYM];
- Prog *p;
- Sym *s;
- int f, sf, st, t, sym;
- Biobuf b;
-
- if(debug['S']) {
- for(p = firstp; p != P; p = p->link)
- if(p->as != ADATA && p->as != AGLOBL)
- pc--;
- for(p = firstp; p != P; p = p->link) {
- print("%P\n", p);
- if(p->as != ADATA && p->as != AGLOBL)
- pc++;
- }
- }
- 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(), thestring, getgoversion());
- if(ndynimp > 0 || ndynexp > 0) {
- int i;
-
- Bprint(&b, "\n");
- Bprint(&b, "$$ // exports\n\n");
- Bprint(&b, "$$ // local types\n\n");
- Bprint(&b, "$$ // dynimport\n");
- for(i=0; i<ndynimp; i++)
- Bprint(&b, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path);
- Bprint(&b, "\n$$ // dynexport\n");
- for(i=0; i<ndynexp; i++)
- Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
- Bprint(&b, "\n$$\n\n");
- }
- Bprint(&b, "!\n");
-
- outhist(&b);
- for(sym=0; sym<NSYM; sym++) {
- h[sym].sym = S;
- h[sym].type = 0;
- }
- sym = 1;
- for(p = firstp; p != P; p = p->link) {
- jackpot:
- sf = 0;
- s = p->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = p->from.type;
- if(t == D_ADDR)
- t = p->from.index;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- s->sym = sym;
- zname(&b, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = p->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = p->to.type;
- if(t == D_ADDR)
- t = p->to.index;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- s->sym = sym;
- zname(&b, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- Bputc(&b, p->as);
- Bputc(&b, p->as>>8);
- Bputc(&b, p->lineno);
- Bputc(&b, p->lineno>>8);
- Bputc(&b, p->lineno>>16);
- Bputc(&b, p->lineno>>24);
- zaddr(&b, &p->from, sf);
- zaddr(&b, &p->to, st);
- }
- Bflush(&b);
- close(f);
- firstp = P;
- lastp = P;
-}
-
-void
-outhist(Biobuf *b)
-{
- Hist *h;
- char *p, *q, *op, c;
- Prog pg;
- int n;
-
- pg = zprog;
- pg.as = AHISTORY;
- c = pathchar();
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- op = 0;
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname+2;
- c = *p;
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = utfrune(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- Bputc(b, ANAME);
- Bputc(b, ANAME>>8);
- Bputc(b, D_FILE);
- Bputc(b, 1);
- Bputc(b, '<');
- Bwrite(b, p, n);
- Bputc(b, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- pg.lineno = h->line;
- pg.to.type = zprog.to.type;
- pg.to.offset = h->offset;
- if(h->offset)
- pg.to.type = D_CONST;
-
- Bputc(b, pg.as);
- Bputc(b, pg.as>>8);
- Bputc(b, pg.lineno);
- Bputc(b, pg.lineno>>8);
- Bputc(b, pg.lineno>>16);
- Bputc(b, pg.lineno>>24);
- zaddr(b, &pg.from, 0);
- zaddr(b, &pg.to, 0);
- }
-}
-
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- char *n;
- uint32 sig;
-
- if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
- sig = sign(s);
- Bputc(b, ASIGNAME);
- Bputc(b, ASIGNAME>>8);
- Bputc(b, sig);
- Bputc(b, sig>>8);
- Bputc(b, sig>>16);
- Bputc(b, sig>>24);
- s->sig = SIGDONE;
- }
- else{
- Bputc(b, ANAME); /* as */
- Bputc(b, ANAME>>8); /* as */
- }
- Bputc(b, t); /* type */
- Bputc(b, s->sym); /* sym */
- n = s->name;
- while(*n) {
- Bputc(b, *n);
- n++;
- }
- Bputc(b, 0);
-}
-
-void
-zaddr(Biobuf *b, Adr *a, int s)
-{
- int32 l;
- int i, t;
- char *n;
- Ieee e;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(s != 0)
- t |= T_SYM;
-
- switch(a->type) {
- default:
- t |= T_TYPE;
- case D_NONE:
- if(a->offset != 0)
- t |= T_OFFSET;
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- case D_CONST2:
- t |= T_OFFSET|T_OFFSET2;
- break;
- }
- Bputc(b, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- Bputc(b, a->index);
- Bputc(b, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- }
- if(t & T_OFFSET2) { /* implies offset2 */
- l = a->offset2;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- }
- if(t & T_SYM) /* implies sym */
- Bputc(b, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->dval);
- l = e.l;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- l = e.h;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- return;
- }
- if(t & T_SCONST) {
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- Bputc(b, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- Bputc(b, a->type);
-}
-
-int32
-align(int32 i, Type *t, int op, int32 *maxalign)
-{
- int32 o;
- Type *v;
- int w;
-
- o = i;
- w = 1;
- switch(op) {
- default:
- diag(Z, "unknown align opcode %d", op);
- break;
-
- case Asu2: /* padding at end of a struct */
- w = *maxalign;
- if(w < 1)
- w = 1;
- if(packflg)
- w = 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)
- w = 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;
- }
- 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 += SZ_LONG-1;
- if(v > max)
- max = xround(v, SZ_LONG);
- return max;
-}
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
deleted file mode 100644
index b2e0148a0..000000000
--- a/src/cmd/8c/txt.c
+++ /dev/null
@@ -1,1458 +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"
-
-void
-ginit(void)
-{
- int i;
- Type *t;
-
- thechar = '8';
- thestring = "386";
- exregoffset = 0;
- exfregoffset = 0;
- listinit();
- nstring = 0;
- mnstring = 0;
- nrathole = 0;
- pc = 0;
- breakpc = -1;
- continpc = -1;
- cases = C;
- firstp = P;
- 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)
-{
-
- p = alloc(sizeof(*p));
- *p = zprog;
- p->lineno = nearln;
- pc++;
- if(firstp == P) {
- firstp = p;
- lastp = p;
- return;
- }
- lastp->link = p;
- lastp = p;
-}
-
-void
-gargs(Node *n, Node *tn1, Node *tn2)
-{
- 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)
-{
- int r;
-
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET;
- nodreg(n, nn, r);
- reg[r]++;
-}
-
-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 >= sizeof(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, Adr *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 = S;
- break;
-
- case OEXREG:
- a->type = D_INDIR + D_GS;
- 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 = S;
- a->offset = n->xoffset;
- break;
-
- case ONAME:
- a->etype = n->etype;
- a->type = D_STATIC;
- a->sym = 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->dval = n->fconst;
- break;
- }
- a->sym = S;
- 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]++; // cant 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 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;
-}
-
-void
-gpseudo(int a, Sym *s, Node *n)
-{
-
- nextpc();
- p->as = a;
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.scale = textflag;
- textflag = 0;
-
- if(s->class == CSTATIC)
- p->from.type = D_STATIC;
- naddr(n, &p->to);
- if(a == ADATA || a == AGLOBL)
- pc--;
-}
-
-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/Makefile b/src/cmd/8g/Makefile
deleted file mode 100644
index b459782a3..000000000
--- a/src/cmd/8g/Makefile
+++ /dev/null
@@ -1,36 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=8g
-
-HFILES=\
- ../gc/go.h\
- ../8l/8.out.h\
- gg.h\
- opt.h\
-
-OFILES=\
- ../8l/enam.$O\
- cgen.$O\
- cgen64.$O\
- cplx.$O\
- galign.$O\
- ggen.$O\
- gobj.$O\
- gsubr.$O\
- list.$O\
- peep.$O\
- pgen.$O\
- reg.$O\
-
-LIB=\
- ../gc/gc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../gc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
deleted file mode 100644
index 1614a2d77..000000000
--- a/src/cmd/8g/cgen.c
+++ /dev/null
@@ -1,1235 +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.
-
-// TODO(rsc):
-// assume CLD?
-
-#include "gg.h"
-
-void
-mgen(Node *n, Node *n1, Node *rg)
-{
- Node n2;
-
- n1->op = OEMPTY;
-
- if(n->addable) {
- *n1 = *n;
- if(n1->op == OREGISTER || n1->op == OINDREG)
- reg[n->val.u.reg]++;
- return;
- }
- tempname(n1, n->type);
- cgen(n, n1);
- if(n->type->width <= widthptr || isfloat[n->type->etype]) {
- n2 = *n1;
- regalloc(n1, n->type, rg);
- gmove(&n2, n1);
- }
-}
-
-void
-mfree(Node *n)
-{
- if(n->op == OREGISTER)
- regfree(n);
-}
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- *
- * TODO:
- * sudoaddable
- */
-void
-cgen(Node *n, Node *res)
-{
- Node *nl, *nr, *r, n1, n2, nt, f0, f1;
- Prog *p1, *p2, *p3;
- int a;
-
- if(debug['g']) {
- dump("\ncgen-n", n);
- dump("cgen-res", res);
- }
-
- if(n == N || n->type == T)
- fatal("cgen: n nil");
- if(res == N || res->type == T)
- fatal("cgen: res nil");
-
- // inline slices
- if(cgen_inline(n, res))
- return;
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- // function calls on both sides? introduce temporary
- if(n->ullman >= UINF && res->ullman >= UINF) {
- tempname(&n1, n->type);
- cgen(n, &n1);
- cgen(&n1, res);
- return;
- }
-
- // structs etc get handled specially
- if(isfat(n->type)) {
- if(n->type->width < 0)
- fatal("forgot to compute width for %T", n->type);
- sgen(n, res, n->type->width);
- return;
- }
-
- // 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 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;
- }
-
- // if both are addressable, move
- if(n->addable && res->addable) {
- gmove(n, res);
- return;
- }
-
- // if both are not addressable, use a temporary.
- if(!n->addable && !res->addable) {
- // could use regalloc here sometimes,
- // but have to check for ullman >= UINF.
- tempname(&n1, n->type);
- cgen(n, &n1);
- cgen(&n1, res);
- return;
- }
-
- // if result is not addressable directly but n is,
- // compute its address and then store via the address.
- if(!res->addable) {
- igen(res, &n1, N);
- cgen(n, &n1);
- regfree(&n1);
- return;
- }
-
- // complex types
- if(complexop(n, res)) {
- complexgen(n, res);
- return;
- }
-
- // otherwise, the result is addressable but n is not.
- // let's do some computation.
-
- // use ullman to pick operand to eval first.
- nl = n->left;
- nr = n->right;
- if(nl != N && nl->ullman >= UINF)
- if(nr != N && nr->ullman >= UINF) {
- // both are hard
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- n2 = *n;
- n2.left = &n1;
- cgen(&n2, res);
- return;
- }
-
- // 64-bit ops are hard on 32-bit machine.
- if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
- switch(n->op) {
- // math goes to cgen64.
- case OMINUS:
- case OCOM:
- case OADD:
- case OSUB:
- case OMUL:
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- cgen64(n, res);
- return;
- }
- }
-
- if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
- goto flt;
-
- switch(n->op) {
- default:
- dump("cgen", n);
- fatal("cgen %O", n->op);
- break;
-
- case OREAL:
- case OIMAG:
- case OCOMPLEX:
- fatal("unexpected complex");
- return;
-
- // 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(AJMP, T);
- p2 = pc;
- gmove(nodbool(1), res);
- p3 = gbranch(AJMP, T);
- patch(p1, pc);
- bgen(n, 1, p2);
- gmove(nodbool(0), res);
- patch(p3, pc);
- return;
-
- case OPLUS:
- cgen(nl, res);
- return;
-
- case OMINUS:
- case OCOM:
- 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);
- if(a == AIMULB) {
- cgen_bmul(n->op, nl, nr, res);
- break;
- }
- goto sbop;
-
- // asymmetric binary
- case OSUB:
- a = optoas(n->op, nl->type);
- goto abop;
-
- case OCONV:
- if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
- cgen(nl, res);
- break;
- }
-
- tempname(&n2, n->type);
- mgen(nl, &n1, res);
- gmove(&n1, &n2);
- gmove(&n2, res);
- mfree(&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 OLEN:
- if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
- // map has len in the first 32-bit word.
- // a zero pointer means zero length
- tempname(&n1, types[tptr]);
- cgen(nl, &n1);
- regalloc(&n2, types[tptr], N);
- gmove(&n1, &n2);
- n1 = n2;
-
- nodconst(&n2, types[tptr], 0);
- gins(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.type = types[TINT32];
- 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.
- igen(nl, &n1, res);
- n1.type = types[TUINT32];
- 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 32-bit 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);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 4;
- n2.type = types[TINT32];
- gmove(&n2, &n1);
-
- patch(p1, pc);
-
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- if(isslice(nl->type)) {
- igen(nl, &n1, res);
- n1.op = OINDREG;
- n1.type = types[TUINT32];
- n1.xoffset = Array_cap;
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- fatal("cgen: OCAP: unknown type %lT", nl->type);
- break;
-
- case OADDR:
- agen(nl, res);
- 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:
- cgen_div(n->op, nl, nr, res);
- break;
-
- case OLSH:
- case ORSH:
- cgen_shift(n->op, nl, nr, res);
- break;
- }
- return;
-
-sbop: // symmetric binary
- if(nl->ullman < nr->ullman) {
- r = nl;
- nl = nr;
- nr = r;
- }
-
-abop: // asymmetric binary
- if(nl->ullman >= nr->ullman) {
- tempname(&nt, nl->type);
- cgen(nl, &nt);
- mgen(nr, &n2, N);
- regalloc(&n1, nl->type, res);
- gmove(&nt, &n1);
- gins(a, &n2, &n1);
- gmove(&n1, res);
- regfree(&n1);
- mfree(&n2);
- } else {
- regalloc(&n2, nr->type, res);
- cgen(nr, &n2);
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
- gins(a, &n2, &n1);
- regfree(&n2);
- gmove(&n1, res);
- regfree(&n1);
- }
- return;
-
-uop: // unary
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- gins(a, N, &n1);
- gmove(&n1, res);
- return;
-
-flt: // floating-point. 387 (not SSE2) to interoperate with 8c
- nodreg(&f0, nl->type, D_F0);
- nodreg(&f1, n->type, D_F0+1);
- if(nr != N)
- goto flt2;
-
- // unary
- cgen(nl, &f0);
- if(n->op != OCONV && n->op != OPLUS)
- gins(foptoas(n->op, n->type, 0), N, N);
- gmove(&f0, res);
- return;
-
-flt2: // binary
- if(nl->ullman >= nr->ullman) {
- cgen(nl, &f0);
- if(nr->addable)
- gins(foptoas(n->op, n->type, 0), nr, &f0);
- else {
- cgen(nr, &f0);
- gins(foptoas(n->op, n->type, Fpop), &f0, &f1);
- }
- } else {
- cgen(nr, &f0);
- if(nl->addable)
- gins(foptoas(n->op, n->type, Frev), nl, &f0);
- else {
- cgen(nl, &f0);
- gins(foptoas(n->op, n->type, Frev|Fpop), &f0, &f1);
- }
- }
- gmove(&f0, res);
- return;
-}
-
-/*
- * generate array index into res.
- * n might be any size; res is 32-bit.
- * returns Prog* to patch to panic call.
- */
-Prog*
-cgenindex(Node *n, Node *res)
-{
- Node tmp, lo, hi, zero;
-
- if(!is64(n->type)) {
- cgen(n, res);
- return nil;
- }
-
- tempname(&tmp, types[TINT64]);
- cgen(n, &tmp);
- split64(&tmp, &lo, &hi);
- gmove(&lo, res);
- if(debug['B']) {
- splitclean();
- return nil;
- }
- nodconst(&zero, types[TINT32], 0);
- gins(ACMPL, &hi, &zero);
- splitclean();
- return gbranch(AJNE, T);
-}
-
-/*
- * address gen
- * res = &n;
- */
-void
-agen(Node *n, Node *res)
-{
- Node *nl, *nr;
- Node n1, n2, n3, n4, tmp;
- Type *t;
- uint32 w;
- uint64 v;
- Prog *p1, *p2;
-
- if(debug['g']) {
- dump("\nagen-res", res);
- dump("agen-r", n);
- }
- if(n == N || n->type == T || res == N || res->type == T)
- fatal("agen");
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- // addressable var is easy
- if(n->addable) {
- if(n->op == OREGISTER)
- fatal("agen OREGISTER");
- regalloc(&n1, types[tptr], res);
- gins(ALEAL, n, &n1);
- gmove(&n1, res);
- regfree(&n1);
- return;
- }
-
- // let's compute
- nl = n->left;
- nr = n->right;
-
- switch(n->op) {
- default:
- fatal("agen %O", n->op);
-
- case OCALLMETH:
- 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 OINDEX:
- p2 = nil; // to be patched to panicindex.
- w = n->type->width;
- if(nr->addable) {
- if(!isconst(nr, CTINT))
- tempname(&tmp, types[TINT32]);
- if(!isconst(nl, CTSTR))
- agenr(nl, &n3, res);
- if(!isconst(nr, CTINT)) {
- p2 = cgenindex(nr, &tmp);
- regalloc(&n1, tmp.type, N);
- gmove(&tmp, &n1);
- }
- } else if(nl->addable) {
- if(!isconst(nr, CTINT)) {
- tempname(&tmp, types[TINT32]);
- p2 = cgenindex(nr, &tmp);
- regalloc(&n1, tmp.type, N);
- gmove(&tmp, &n1);
- }
- if(!isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
- }
- } else {
- tempname(&tmp, types[TINT32]);
- p2 = cgenindex(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
-
- // explicit check for nil if array is large enough
- // that we might derive too big a pointer.
- if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
- regalloc(&n4, types[tptr], &n3);
- gmove(&n3, &n4);
- n4.op = OINDREG;
- n4.type = types[TUINT8];
- n4.xoffset = 0;
- gins(ATESTB, nodintconst(0), &n4);
- regfree(&n4);
- }
-
- if(w == 0)
- fatal("index is zero 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->etype) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- nodconst(&n2, types[TUINT32], v);
- gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- 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) {
- nodconst(&n2, types[tptr], v*w);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- }
- gmove(&n3, res);
- regfree(&n3);
- break;
- }
-
- regalloc(&n2, types[TINT32], &n1); // i
- gmove(&n1, &n2);
- regfree(&n1);
-
- if(!debug['B'] && !n->etype) {
- // check bounds
- if(isconst(nl, CTSTR))
- nodconst(&n1, types[TUINT32], 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;
- } else
- nodconst(&n1, types[TUINT32], nl->type->bound);
- gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
- if(p2)
- patch(p2, pc);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- if(isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- p1 = gins(ALEAL, N, &n3);
- datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- p1->from.scale = 1;
- p1->from.index = n2.val.u.reg;
- goto indexdone;
- }
-
- 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 == 1 || w == 2 || w == 4 || w == 8) {
- p1 = gins(ALEAL, &n2, &n3);
- p1->from.scale = w;
- p1->from.index = p1->from.type;
- p1->from.type = p1->to.type + D_INDIR;
- } else {
- nodconst(&n1, types[TUINT32], w);
- gins(optoas(OMUL, types[TUINT32]), &n1, &n2);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- }
-
- indexdone:
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- 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) {
- nodconst(&n1, types[tptr], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
- }
- break;
-
- case OIND:
- cgen(nl, res);
- break;
-
- case ODOT:
- t = nl->type;
- agen(nl, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[tptr], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
- }
- break;
-
- case ODOTPTR:
- t = nl->type;
- if(!isptr[t->etype])
- fatal("agen: not ptr %N", n);
- cgen(nl, res);
- if(n->xoffset != 0) {
- // explicit check for nil if struct is large enough
- // that we might derive too big a pointer.
- if(nl->type->type->width >= unmappedzero) {
- regalloc(&n1, types[tptr], res);
- gmove(res, &n1);
- n1.op = OINDREG;
- n1.type = types[TUINT8];
- n1.xoffset = 0;
- gins(ATESTB, nodintconst(0), &n1);
- regfree(&n1);
- }
- nodconst(&n1, types[tptr], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
- }
- break;
- }
-}
-
-/*
- * generate:
- * newreg = &n;
- * res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- */
-void
-igen(Node *n, Node *a, Node *res)
-{
- Node n1;
- Type *fp;
- Iter flist;
-
- switch(n->op) {
- case ONAME:
- if((n->class&PHEAP) || n->class == PPARAMREF)
- break;
- *a = *n;
- return;
-
- case OCALLFUNC:
- fp = structfirst(&flist, getoutarg(n->left->type));
- cgen_call(n, 0);
- memset(a, 0, sizeof *a);
- a->op = OINDREG;
- a->val.u.reg = D_SP;
- a->addable = 1;
- a->xoffset = fp->width;
- a->type = n->type;
- return;
- }
- // release register for now, to avoid
- // confusing tempname.
- if(res != N && res->op == OREGISTER)
- reg[res->val.u.reg]--;
- tempname(&n1, types[tptr]);
- agen(n, &n1);
- if(res != N && res->op == OREGISTER)
- reg[res->val.u.reg]++;
- regalloc(a, types[tptr], res);
- gmove(&n1, a);
- a->op = OINDREG;
- a->type = n->type;
-}
-
-/*
- * generate:
- * newreg = &n;
- *
- * caller must regfree(a).
- */
-void
-agenr(Node *n, Node *a, Node *res)
-{
- Node n1;
-
- tempname(&n1, types[tptr]);
- agen(n, &n1);
- regalloc(a, types[tptr], res);
- gmove(&n1, a);
-}
-
-/*
- * branch gen
- * if(n == true) goto to;
- */
-void
-bgen(Node *n, int true, Prog *to)
-{
- int et, a;
- Node *nl, *nr, *r;
- Node n1, n2, tmp, t1, t2, ax;
- Prog *p1, *p2;
-
- if(debug['g']) {
- dump("\nbgen", n);
- }
-
- if(n == N)
- n = nodbool(1);
-
- if(n->ninit != nil)
- genlist(n->ninit);
-
- nl = n->left;
- nr = n->right;
-
- if(n->type == T) {
- convlit(&n, types[TBOOL]);
- if(n->type == T)
- return;
- }
-
- et = n->type->etype;
- if(et != TBOOL) {
- yyerror("cgen: bad type %T for %O", n->type, n->op);
- patch(gins(AEND, N, N), to);
- return;
- }
- nl = N;
- nr = N;
-
- switch(n->op) {
- default:
- def:
- regalloc(&n1, n->type, N);
- cgen(n, &n1);
- nodconst(&n2, n->type, 0);
- gins(optoas(OCMP, n->type), &n1, &n2);
- a = AJNE;
- if(!true)
- a = AJEQ;
- patch(gbranch(a, n->type), to);
- regfree(&n1);
- return;
-
- case OLITERAL:
- // need to ask if it is bool?
- if(!true == !n->val.u.bval)
- patch(gbranch(AJMP, T), to);
- return;
-
- case ONAME:
- if(!n->addable)
- goto def;
- nodconst(&n1, n->type, 0);
- gins(optoas(OCMP, n->type), n, &n1);
- a = AJNE;
- if(!true)
- a = AJEQ;
- patch(gbranch(a, n->type), to);
- return;
-
- case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- p1 = gbranch(AJMP, T);
- p2 = gbranch(AJMP, T);
- patch(p1, pc);
- bgen(n->left, !true, p2);
- bgen(n->right, !true, p2);
- p1 = gbranch(AJMP, T);
- patch(p1, to);
- patch(p2, pc);
- return;
-
- case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bgen(n->left, true, to);
- bgen(n->right, true, to);
- return;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- nr = n->right;
- if(nr == N || nr->type == T)
- return;
-
- case ONOT: // unary
- nl = n->left;
- if(nl == N || nl->type == T)
- return;
- }
-
- switch(n->op) {
- case ONOT:
- bgen(nl, !true, to);
- break;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- a = n->op;
- if(!true) {
- if(isfloat[nl->type->etype]) {
- // brcom is not valid on floats when NaN is involved.
- p1 = gbranch(AJMP, T);
- p2 = gbranch(AJMP, T);
- patch(p1, pc);
- bgen(n, 1, p2);
- patch(gbranch(AJMP, T), to);
- patch(p2, pc);
- break;
- }
- 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 array comparison");
- break;
- }
- a = optoas(a, types[tptr]);
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = Array_array;
- n2.type = types[tptr];
- nodconst(&tmp, types[tptr], 0);
- gins(optoas(OCMP, types[tptr]), &n2, &tmp);
- patch(gbranch(a, types[tptr]), 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]);
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 0;
- nodconst(&tmp, types[tptr], 0);
- gins(optoas(OCMP, types[tptr]), &n2, &tmp);
- patch(gbranch(a, types[tptr]), to);
- regfree(&n1);
- break;
- }
-
- if(isfloat[nr->type->etype]) {
- a = brrev(a); // because the args are stacked
- if(a == OGE || a == OGT) {
- // only < and <= work right with NaN; reverse if needed
- r = nr;
- nr = nl;
- nl = r;
- a = brrev(a);
- }
- nodreg(&tmp, nr->type, D_F0);
- nodreg(&n2, nr->type, D_F0 + 1);
- nodreg(&ax, types[TUINT16], D_AX);
- et = simsimtype(nr->type);
- if(et == TFLOAT64) {
- if(nl->ullman > nr->ullman) {
- cgen(nl, &tmp);
- cgen(nr, &tmp);
- gins(AFXCHD, &tmp, &n2);
- } else {
- cgen(nr, &tmp);
- cgen(nl, &tmp);
- }
- gins(AFUCOMIP, &tmp, &n2);
- gins(AFMOVDP, &tmp, &tmp); // annoying pop but still better than STSW+SAHF
- } else {
- // TODO(rsc): The moves back and forth to memory
- // here are for truncating the value to 32 bits.
- // This handles 32-bit comparison but presumably
- // all the other ops have the same problem.
- // We need to figure out what the right general
- // solution is, besides telling people to use float64.
- tempname(&t1, types[TFLOAT32]);
- tempname(&t2, types[TFLOAT32]);
- cgen(nr, &t1);
- cgen(nl, &t2);
- gmove(&t2, &tmp);
- gins(AFCOMFP, &t1, &tmp);
- gins(AFSTSW, N, &ax);
- gins(ASAHF, N, N);
- }
- if(a == OEQ) {
- // neither NE nor P
- p1 = gbranch(AJNE, T);
- p2 = gbranch(AJPS, T);
- patch(gbranch(AJMP, T), to);
- patch(p1, pc);
- patch(p2, pc);
- } else if(a == ONE) {
- // either NE or P
- patch(gbranch(AJNE, T), to);
- patch(gbranch(AJPS, T), to);
- } else
- patch(gbranch(optoas(a, nr->type), T), to);
- break;
- }
- if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, to);
- break;
- }
-
- if(is64(nr->type)) {
- if(!nl->addable) {
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- nl = &n1;
- }
- if(!nr->addable) {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- cmp64(nl, nr, a, to);
- break;
- }
-
- a = optoas(a, nr->type);
-
- if(nr->ullman >= UINF) {
- tempname(&n1, nl->type);
- tempname(&tmp, nr->type);
- cgen(nl, &n1);
- cgen(nr, &tmp);
- regalloc(&n2, nr->type, N);
- cgen(&tmp, &n2);
- goto cmp;
- }
-
- tempname(&n1, nl->type);
- cgen(nl, &n1);
-
- if(smallintconst(nr)) {
- gins(optoas(OCMP, nr->type), &n1, nr);
- patch(gbranch(a, nr->type), to);
- break;
- }
-
- tempname(&tmp, nr->type);
- cgen(nr, &tmp);
- regalloc(&n2, nr->type, N);
- gmove(&tmp, &n2);
-
-cmp:
- gins(optoas(OCMP, nr->type), &n1, &n2);
- patch(gbranch(a, nr->type), to);
- regfree(&n2);
- break;
- }
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-int32
-stkof(Node *n)
-{
- Type *t;
- Iter flist;
- int32 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;
- break;
- }
-
- // botch - probably failing to recognize address
- // arithmetic on the above. eg INDEX and DOT
- return -1000;
-}
-
-/*
- * struct gen
- * memmove(&res, &n, w);
- */
-void
-sgen(Node *n, Node *res, int32 w)
-{
- Node dst, src, tdst, tsrc;
- int32 c, q, odst, osrc;
-
- if(debug['g']) {
- print("\nsgen w=%d\n", w);
- dump("r", n);
- dump("res", res);
- }
- if(w == 0)
- return;
- if(n->ullman >= UINF && res->ullman >= UINF) {
- fatal("sgen UINF");
- }
-
- if(w < 0)
- fatal("sgen copy %d", w);
-
- // 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(&tsrc, n->type);
- sgen(n, &tsrc, w);
- sgen(&tsrc, res, w);
- return;
- }
-
- nodreg(&dst, types[tptr], D_DI);
- nodreg(&src, types[tptr], D_SI);
-
- tempname(&tsrc, types[tptr]);
- tempname(&tdst, types[tptr]);
- if(!n->addable)
- agen(n, &tsrc);
- if(!res->addable)
- agen(res, &tdst);
- if(n->addable)
- agen(n, &src);
- else
- gmove(&tsrc, &src);
- if(res->addable)
- agen(res, &dst);
- else
- gmove(&tdst, &dst);
-
- c = w % 4; // bytes
- q = w / 4; // doublewords
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- if(osrc < odst && odst < osrc+w) {
- // reverse direction
- gins(ASTD, N, N); // set direction flag
- if(c > 0) {
- gconreg(AADDL, w-1, D_SI);
- gconreg(AADDL, w-1, D_DI);
-
- gconreg(AMOVL, c, D_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
- }
-
- if(q > 0) {
- if(c > 0) {
- gconreg(AADDL, -3, D_SI);
- gconreg(AADDL, -3, D_DI);
- } else {
- gconreg(AADDL, w-4, D_SI);
- gconreg(AADDL, w-4, D_DI);
- }
- gconreg(AMOVL, q, D_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSL, N, N); // MOVL *(SI)-,*(DI)-
- }
- // we leave with the flag clear
- gins(ACLD, N, N);
- } else {
- gins(ACLD, N, N); // paranoia. TODO(rsc): remove?
- // normal direction
- if(q >= 4) {
- gconreg(AMOVL, q, D_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
- } else
- while(q > 0) {
- gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
- q--;
- }
- while(c > 0) {
- gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
- c--;
- }
- }
-}
-
diff --git a/src/cmd/8g/cgen64.c b/src/cmd/8g/cgen64.c
deleted file mode 100644
index ba99cec74..000000000
--- a/src/cmd/8g/cgen64.c
+++ /dev/null
@@ -1,512 +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 "gg.h"
-
-/*
- * attempt to generate 64-bit
- * res = n
- * return 1 on success, 0 if op not handled.
- */
-void
-cgen64(Node *n, Node *res)
-{
- Node t1, t2, ax, dx, cx, ex, fx, *l, *r;
- Node lo1, lo2, hi1, hi2;
- Prog *p1, *p2;
- uint64 v;
- uint32 lv, hv;
-
- if(res->op != OINDREG && res->op != ONAME) {
- dump("n", n);
- dump("res", res);
- fatal("cgen64 %O of %O", n->op, res->op);
- }
- switch(n->op) {
- default:
- fatal("cgen64 %O", n->op);
-
- case OMINUS:
- cgen(n->left, res);
- split64(res, &lo1, &hi1);
- gins(ANEGL, N, &lo1);
- gins(AADCL, ncon(0), &hi1);
- gins(ANEGL, N, &hi1);
- splitclean();
- return;
-
- case OCOM:
- cgen(n->left, res);
- split64(res, &lo1, &hi1);
- gins(ANOTL, N, &lo1);
- gins(ANOTL, N, &hi1);
- splitclean();
- return;
-
- case OADD:
- case OSUB:
- case OMUL:
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- // binary operators.
- // common setup below.
- break;
- }
-
- l = n->left;
- r = n->right;
- if(!l->addable) {
- tempname(&t1, l->type);
- cgen(l, &t1);
- l = &t1;
- }
- if(r != N && !r->addable) {
- tempname(&t2, r->type);
- cgen(r, &t2);
- r = &t2;
- }
-
- nodreg(&ax, types[TINT32], D_AX);
- nodreg(&cx, types[TINT32], D_CX);
- nodreg(&dx, types[TINT32], D_DX);
-
- // Setup for binary operation.
- split64(l, &lo1, &hi1);
- if(is64(r->type))
- split64(r, &lo2, &hi2);
-
- // Do op. Leave result in DX:AX.
- switch(n->op) {
- case OADD:
- // TODO: Constants
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- gins(AADDL, &lo2, &ax);
- gins(AADCL, &hi2, &dx);
- break;
-
- case OSUB:
- // TODO: Constants.
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- gins(ASUBL, &lo2, &ax);
- gins(ASBBL, &hi2, &dx);
- break;
-
- case OMUL:
- // let's call the next two EX and FX.
- regalloc(&ex, types[TPTR32], N);
- regalloc(&fx, types[TPTR32], N);
-
- // load args into DX:AX and EX:CX.
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- gins(AMOVL, &lo2, &cx);
- gins(AMOVL, &hi2, &ex);
-
- // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
- gins(AMOVL, &dx, &fx);
- gins(AORL, &ex, &fx);
- p1 = gbranch(AJNE, T);
- gins(AMULL, &cx, N); // implicit &ax
- p2 = gbranch(AJMP, T);
- patch(p1, pc);
-
- // full 64x64 -> 64, from 32x32 -> 64.
- gins(AIMULL, &cx, &dx);
- gins(AMOVL, &ax, &fx);
- gins(AIMULL, &ex, &fx);
- gins(AADDL, &dx, &fx);
- gins(AMOVL, &cx, &dx);
- gins(AMULL, &dx, N); // implicit &ax
- gins(AADDL, &fx, &dx);
- patch(p2, pc);
-
- regfree(&ex);
- regfree(&fx);
- break;
-
- case OLSH:
- if(r->op == OLITERAL) {
- v = mpgetfix(r->val.u.xval);
- if(v >= 64) {
- if(is64(r->type))
- splitclean();
- splitclean();
- split64(res, &lo2, &hi2);
- gins(AMOVL, ncon(0), &lo2);
- gins(AMOVL, ncon(0), &hi2);
- splitclean();
- goto out;
- }
- if(v >= 32) {
- if(is64(r->type))
- splitclean();
- split64(res, &lo2, &hi2);
- gmove(&lo1, &hi2);
- if(v > 32) {
- gins(ASHLL, ncon(v - 32), &hi2);
- }
- gins(AMOVL, ncon(0), &lo2);
- splitclean();
- splitclean();
- goto out;
- }
-
- // general shift
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- p1 = gins(ASHLL, ncon(v), &dx);
- p1->from.index = D_AX; // double-width shift
- p1->from.scale = 0;
- gins(ASHLL, ncon(v), &ax);
- break;
- }
-
- // load value into DX:AX.
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
-
- // load shift value into register.
- // if high bits are set, zero value.
- p1 = P;
- if(is64(r->type)) {
- gins(ACMPL, &hi2, ncon(0));
- p1 = gbranch(AJNE, T);
- gins(AMOVL, &lo2, &cx);
- } else {
- cx.type = types[TUINT32];
- gmove(r, &cx);
- }
-
- // if shift count is >=64, zero value
- gins(ACMPL, &cx, ncon(64));
- p2 = gbranch(optoas(OLT, types[TUINT32]), T);
- if(p1 != P)
- patch(p1, pc);
- gins(AXORL, &dx, &dx);
- gins(AXORL, &ax, &ax);
- patch(p2, pc);
-
- // if shift count is >= 32, zero low.
- gins(ACMPL, &cx, ncon(32));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
- gins(AMOVL, &ax, &dx);
- gins(ASHLL, &cx, &dx); // SHLL only uses bottom 5 bits of count
- gins(AXORL, &ax, &ax);
- p2 = gbranch(AJMP, T);
- patch(p1, pc);
-
- // general shift
- p1 = gins(ASHLL, &cx, &dx);
- p1->from.index = D_AX; // double-width shift
- p1->from.scale = 0;
- gins(ASHLL, &cx, &ax);
- patch(p2, pc);
- break;
-
- case ORSH:
- if(r->op == OLITERAL) {
- v = mpgetfix(r->val.u.xval);
- if(v >= 64) {
- if(is64(r->type))
- splitclean();
- splitclean();
- split64(res, &lo2, &hi2);
- if(hi1.type->etype == TINT32) {
- gmove(&hi1, &lo2);
- gins(ASARL, ncon(31), &lo2);
- gmove(&hi1, &hi2);
- gins(ASARL, ncon(31), &hi2);
- } else {
- gins(AMOVL, ncon(0), &lo2);
- gins(AMOVL, ncon(0), &hi2);
- }
- splitclean();
- goto out;
- }
- if(v >= 32) {
- if(is64(r->type))
- splitclean();
- split64(res, &lo2, &hi2);
- gmove(&hi1, &lo2);
- if(v > 32)
- gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2);
- if(hi1.type->etype == TINT32) {
- gmove(&hi1, &hi2);
- gins(ASARL, ncon(31), &hi2);
- } else
- gins(AMOVL, ncon(0), &hi2);
- splitclean();
- splitclean();
- goto out;
- }
-
- // general shift
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- p1 = gins(ASHRL, ncon(v), &ax);
- p1->from.index = D_DX; // double-width shift
- p1->from.scale = 0;
- gins(optoas(ORSH, hi1.type), ncon(v), &dx);
- break;
- }
-
- // load value into DX:AX.
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
-
- // load shift value into register.
- // if high bits are set, zero value.
- p1 = P;
- if(is64(r->type)) {
- gins(ACMPL, &hi2, ncon(0));
- p1 = gbranch(AJNE, T);
- gins(AMOVL, &lo2, &cx);
- } else {
- cx.type = types[TUINT32];
- gmove(r, &cx);
- }
-
- // if shift count is >=64, zero or sign-extend value
- gins(ACMPL, &cx, ncon(64));
- p2 = gbranch(optoas(OLT, types[TUINT32]), T);
- if(p1 != P)
- patch(p1, pc);
- if(hi1.type->etype == TINT32) {
- gins(ASARL, ncon(31), &dx);
- gins(AMOVL, &dx, &ax);
- } else {
- gins(AXORL, &dx, &dx);
- gins(AXORL, &ax, &ax);
- }
- patch(p2, pc);
-
- // if shift count is >= 32, sign-extend hi.
- gins(ACMPL, &cx, ncon(32));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
- gins(AMOVL, &dx, &ax);
- if(hi1.type->etype == TINT32) {
- gins(ASARL, &cx, &ax); // SARL only uses bottom 5 bits of count
- gins(ASARL, ncon(31), &dx);
- } else {
- gins(ASHRL, &cx, &ax);
- gins(AXORL, &dx, &dx);
- }
- p2 = gbranch(AJMP, T);
- patch(p1, pc);
-
- // general shift
- p1 = gins(ASHRL, &cx, &ax);
- p1->from.index = D_DX; // double-width shift
- p1->from.scale = 0;
- gins(optoas(ORSH, hi1.type), &cx, &dx);
- patch(p2, pc);
- break;
-
- case OXOR:
- case OAND:
- case OOR:
- // make constant the right side (it usually is anyway).
- if(lo1.op == OLITERAL) {
- nswap(&lo1, &lo2);
- nswap(&hi1, &hi2);
- }
- if(lo2.op == OLITERAL) {
- // special cases for constants.
- lv = mpgetfix(lo2.val.u.xval);
- hv = mpgetfix(hi2.val.u.xval);
- splitclean(); // right side
- split64(res, &lo2, &hi2);
- switch(n->op) {
- case OXOR:
- gmove(&lo1, &lo2);
- gmove(&hi1, &hi2);
- switch(lv) {
- case 0:
- break;
- case 0xffffffffu:
- gins(ANOTL, N, &lo2);
- break;
- default:
- gins(AXORL, ncon(lv), &lo2);
- break;
- }
- switch(hv) {
- case 0:
- break;
- case 0xffffffffu:
- gins(ANOTL, N, &hi2);
- break;
- default:
- gins(AXORL, ncon(hv), &hi2);
- break;
- }
- break;
-
- case OAND:
- switch(lv) {
- case 0:
- gins(AMOVL, ncon(0), &lo2);
- break;
- default:
- gmove(&lo1, &lo2);
- if(lv != 0xffffffffu)
- gins(AANDL, ncon(lv), &lo2);
- break;
- }
- switch(hv) {
- case 0:
- gins(AMOVL, ncon(0), &hi2);
- break;
- default:
- gmove(&hi1, &hi2);
- if(hv != 0xffffffffu)
- gins(AANDL, ncon(hv), &hi2);
- break;
- }
- break;
-
- case OOR:
- switch(lv) {
- case 0:
- gmove(&lo1, &lo2);
- break;
- case 0xffffffffu:
- gins(AMOVL, ncon(0xffffffffu), &lo2);
- break;
- default:
- gmove(&lo1, &lo2);
- gins(AORL, ncon(lv), &lo2);
- break;
- }
- switch(hv) {
- case 0:
- gmove(&hi1, &hi2);
- break;
- case 0xffffffffu:
- gins(AMOVL, ncon(0xffffffffu), &hi2);
- break;
- default:
- gmove(&hi1, &hi2);
- gins(AORL, ncon(hv), &hi2);
- break;
- }
- break;
- }
- splitclean();
- splitclean();
- goto out;
- }
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- gins(optoas(n->op, lo1.type), &lo2, &ax);
- gins(optoas(n->op, lo1.type), &hi2, &dx);
- break;
- }
- if(is64(r->type))
- splitclean();
- splitclean();
-
- split64(res, &lo1, &hi1);
- gins(AMOVL, &ax, &lo1);
- gins(AMOVL, &dx, &hi1);
- splitclean();
-
-out:;
-}
-
-/*
- * generate comparison of nl, nr, both 64-bit.
- * nl is memory; nr is constant or memory.
- */
-void
-cmp64(Node *nl, Node *nr, int op, Prog *to)
-{
- Node lo1, hi1, lo2, hi2, rr;
- Prog *br;
- Type *t;
-
- split64(nl, &lo1, &hi1);
- split64(nr, &lo2, &hi2);
-
- // compare most significant word;
- // if they differ, we're done.
- t = hi1.type;
- if(nl->op == OLITERAL || nr->op == OLITERAL)
- gins(ACMPL, &hi1, &hi2);
- else {
- regalloc(&rr, types[TINT32], N);
- gins(AMOVL, &hi1, &rr);
- gins(ACMPL, &rr, &hi2);
- regfree(&rr);
- }
- br = P;
- switch(op) {
- default:
- fatal("cmp64 %O %T", op, t);
- case OEQ:
- // cmp hi
- // jne L
- // cmp lo
- // jeq to
- // L:
- br = gbranch(AJNE, T);
- break;
- case ONE:
- // cmp hi
- // jne to
- // cmp lo
- // jne to
- patch(gbranch(AJNE, T), to);
- break;
- case OGE:
- case OGT:
- // cmp hi
- // jgt to
- // jlt L
- // cmp lo
- // jge to (or jgt to)
- // L:
- patch(gbranch(optoas(OGT, t), T), to);
- br = gbranch(optoas(OLT, t), T);
- break;
- case OLE:
- case OLT:
- // cmp hi
- // jlt to
- // jgt L
- // cmp lo
- // jle to (or jlt to)
- // L:
- patch(gbranch(optoas(OLT, t), T), to);
- br = gbranch(optoas(OGT, t), T);
- break;
- }
-
- // compare least significant word
- t = lo1.type;
- if(nl->op == OLITERAL || nr->op == OLITERAL)
- gins(ACMPL, &lo1, &lo2);
- else {
- regalloc(&rr, types[TINT32], N);
- gins(AMOVL, &lo1, &rr);
- gins(ACMPL, &rr, &lo2);
- regfree(&rr);
- }
-
- // jump again
- patch(gbranch(optoas(op, t), T), to);
-
- // point first branch down here if appropriate
- if(br != P)
- patch(br, pc);
-
- splitclean();
- splitclean();
-}
-
diff --git a/src/cmd/8g/doc.go b/src/cmd/8g/doc.go
deleted file mode 100644
index 2d9ff9a42..000000000
--- a/src/cmd/8g/doc.go
+++ /dev/null
@@ -1,15 +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.
-
-/*
-
-8g is the version of the gc compiler for the x86.
-The $GOARCH for these tools is 386.
-
-It reads .go files and outputs .8 files. The flags are documented in ../gc/doc.go.
-
-There is no instruction optimizer, so the -N flag is a no-op.
-
-*/
-package documentation
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
deleted file mode 100644
index 48edfdf3c..000000000
--- a/src/cmd/8g/galign.c
+++ /dev/null
@@ -1,36 +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 "gg.h"
-
-int thechar = '8';
-char* thestring = "386";
-
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
- */
-Typedef typedefs[] =
-{
- "int", TINT, TINT32,
- "uint", TUINT, TUINT32,
- "uintptr", TUINTPTR, TUINT32,
- 0
-};
-
-void
-betypeinit(void)
-{
- widthptr = 4;
-
- zprog.link = P;
- zprog.as = AGOK;
- zprog.from.type = D_NONE;
- zprog.from.index = D_NONE;
- zprog.from.scale = 0;
- zprog.to = zprog.from;
-
- listinit();
-}
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
deleted file mode 100644
index 7da60d767..000000000
--- a/src/cmd/8g/gg.h
+++ /dev/null
@@ -1,187 +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 <u.h>
-#include <libc.h>
-
-#include "../gc/go.h"
-#include "../8l/8.out.h"
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-typedef struct Addr Addr;
-
-struct Addr
-{
- int32 offset;
- int32 offset2;
-
- double dval;
- Prog* branch;
- char sval[NSNAME];
-
- Sym* gotype;
- Sym* sym;
- Node* node;
- int width;
- uchar type;
- uchar index;
- uchar etype;
- uchar scale; /* doubles as width in DATA op */
- uchar pun; /* dont register variable */
-};
-#define A ((Addr*)0)
-
-struct Prog
-{
- short as; // opcode
- uint32 loc; // pc offset in this func
- uint32 lineno; // source line that generated this
- Addr from; // src address
- Addr to; // dst address
- Prog* link; // next instruction in this func
- void* reg; // pointer to containing Reg struct
-};
-
-// foptoas flags
-enum
-{
- Frev = 1<<0,
- Fpop = 1<<1,
- Fpop2 = 1<<2,
-};
-
-EXTERN Biobuf* bout;
-EXTERN int32 dynloc;
-EXTERN uchar reg[D_NONE];
-EXTERN int32 pcloc; // instruction counter
-EXTERN Strlit emptystring;
-extern char* anames[];
-EXTERN Hist* hist;
-EXTERN Prog zprog;
-EXTERN Node* curfn;
-EXTERN Node* newproc;
-EXTERN Node* deferproc;
-EXTERN Node* deferreturn;
-EXTERN Node* panicindex;
-EXTERN Node* panicslice;
-EXTERN Node* throwreturn;
-EXTERN int maxstksize;
-extern uint32 unmappedzero;
-
-
-/*
- * ggen.c
- */
-void compile(Node*);
-void proglist(void);
-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_bmul(int, Node*, Node*, Node*);
-void cgen_shift(int, Node*, Node*, Node*);
-void cgen_dcl(Node*);
-int needconvert(Type*, Type*);
-void genconv(Type*, Type*);
-void allocparams(void);
-void checklabels();
-void ginscall(Node*, int);
-
-/*
- * cgen.c
- */
-void agen(Node*, Node*);
-void agenr(Node *n, Node *a, Node *res);
-void igen(Node*, Node*, Node*);
-vlong fieldoffset(Type*, Node*);
-void bgen(Node*, int, Prog*);
-void sgen(Node*, Node*, int32);
-void gmove(Node*, Node*);
-Prog* gins(int, Node*, Node*);
-int samaddr(Node*, Node*);
-void naddr(Node*, Addr*, int);
-void cgen_aret(Node*, Node*);
-int cgen_inline(Node*, Node*);
-Node* ncon(uint32);
-void mgen(Node*, Node*, Node*);
-void mfree(Node*);
-
-/*
- * cgen64.c
- */
-void cmp64(Node*, Node*, int, Prog*);
-void cgen64(Node*, Node*);
-
-/*
- * gsubr.c
- */
-void clearp(Prog*);
-void proglist(void);
-Prog* gbranch(int, Type*);
-Prog* prog(int);
-void gaddoffset(Node*);
-void gconv(int, int);
-int conv2pt(Type*);
-vlong convvtox(vlong, int);
-void fnparam(Type*, int, int);
-Prog* gop(int, Node*, Node*, Node*);
-void setconst(Addr*, vlong);
-void setaddr(Addr*, Node*);
-int optoas(int, Type*);
-int foptoas(int, Type*, int);
-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 nodconst(Node*, Type*, int64);
-void gconreg(int, vlong, int);
-void datagostring(Strlit*, Addr*);
-void datastring(char*, int, Addr*);
-void buildtxt(void);
-Plist* newplist(void);
-int isfat(Type*);
-void sudoclean(void);
-int sudoaddable(int, Node*, Addr*);
-int dotaddable(Node*, Node*);
-void afunclit(Addr*);
-void split64(Node*, Node*, Node*);
-void splitclean(void);
-void nswap(Node*, Node*);
-
-/*
- * cplx.c
- */
-int complexop(Node*, Node*);
-void complexmove(Node*, Node*);
-void complexgen(Node*, Node*);
-void complexbool(int, Node*, Node*, int, Prog*);
-
-/*
- * gobj.c
- */
-void data(void);
-void text(void);
-
-/*
- * list.c
- */
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Yconv(Fmt*);
-void listinit(void);
-
-void zaddr(Biobuf*, Addr*, int, int);
-
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
deleted file mode 100644
index 6db0474c9..000000000
--- a/src/cmd/8g/ggen.c
+++ /dev/null
@@ -1,1089 +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.
-
-#undef EXTERN
-#define EXTERN
-#include "gg.h"
-#include "opt.h"
-
-void
-defframe(Prog *ptxt)
-{
- // fill in argument size
- ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
-
- // fill in final stack size
- if(stksize > maxstksize)
- maxstksize = stksize;
- ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
- maxstksize = 0;
-}
-
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
- for (; p; p = p->link) {
- if (p->from.type == D_AUTO && p->from.node)
- p->from.node->used++;
-
- if (p->to.type == D_AUTO && p->to.node)
- p->to.node->used++;
- }
-}
-
-// Fixup instructions after compactframe has moved all autos around.
-void
-fixautoused(Prog* p)
-{
- for (; p; p = p->link) {
- if (p->from.type == D_AUTO && p->from.node)
- p->from.offset += p->from.node->stkdelta;
-
- if (p->to.type == D_AUTO && p->to.node)
- p->to.offset += p->to.node->stkdelta;
- }
-}
-
-void
-clearfat(Node *nl)
-{
- uint32 w, c, q;
- Node n1;
-
- /* clear a fat object */
- if(debug['g'])
- dump("\nclearfat", nl);
-
- w = nl->type->width;
- c = w % 4; // bytes
- q = w / 4; // quads
-
- gconreg(AMOVL, 0, D_AX);
- nodreg(&n1, types[tptr], D_DI);
- agen(nl, &n1);
-
- if(q >= 4) {
- gconreg(AMOVL, q, D_CX);
- gins(AREP, N, N); // repeat
- gins(ASTOSL, N, N); // STOL AL,*(DI)+
- } else
- while(q > 0) {
- gins(ASTOSL, N, N); // STOL AL,*(DI)+
- q--;
- }
-
- if(c >= 4) {
- gconreg(AMOVL, c, D_CX);
- gins(AREP, N, N); // repeat
- gins(ASTOSB, N, N); // STOB AL,*(DI)+
- } else
- while(c > 0) {
- gins(ASTOSB, N, N); // STOB AL,*(DI)+
- c--;
- }
-}
-
-/*
- * generate:
- * call f
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-void
-ginscall(Node *f, int proc)
-{
- Prog *p;
- Node reg, con;
-
- switch(proc) {
- default:
- fatal("ginscall: bad proc %d", proc);
- break;
-
- case 0: // normal call
- p = gins(ACALL, N, f);
- afunclit(&p->to);
- break;
-
- case 1: // call in new proc (go)
- case 2: // deferred call (defer)
- nodreg(&reg, types[TINT32], D_CX);
- gins(APUSHL, f, N);
- nodconst(&con, types[TINT32], argsize(f->type));
- gins(APUSHL, &con, N);
- if(proc == 1)
- ginscall(newproc, 0);
- else
- ginscall(deferproc, 0);
- gins(APOPL, N, &reg);
- gins(APOPL, N, &reg);
- if(proc == 2) {
- nodreg(&reg, types[TINT64], D_AX);
- gins(ATESTL, &reg, &reg);
- patch(gbranch(AJNE, T), retpc);
- }
- break;
- }
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-void
-cgen_callinter(Node *n, Node *res, int proc)
-{
- Node *i, *f;
- Node tmpi, nodo, nodr, nodsp;
-
- 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
-
- // Can regalloc now; i is known to be addable,
- // so the agen will be easy.
- regalloc(&nodr, types[tptr], res);
- regalloc(&nodo, types[tptr], &nodr);
- nodo.op = OINDREG;
-
- agen(i, &nodr); // REG = &inter
-
- nodindreg(&nodsp, types[tptr], D_SP);
- nodo.xoffset += widthptr;
- cgen(&nodo, &nodsp); // 0(SP) = 4(REG) -- i.data
-
- nodo.xoffset -= widthptr;
- cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
-
- if(n->left->xoffset == BADWIDTH)
- fatal("cgen_callinter: badwidth");
- nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
- cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
-
- // BOTCH nodr.type = fntype;
- nodr.type = n->left->type;
- ginscall(&nodr, proc);
-
- regfree(&nodr);
- regfree(&nodo);
-
- setmaxarg(n->left->type);
-}
-
-/*
- * 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;
-
- setmaxarg(t);
-
- // 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_SP;
- nod.addable = 1;
-
- nod.xoffset = fp->width;
- 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_SP;
- nod1.addable = 1;
-
- nod1.xoffset = fp->width;
- nod1.type = fp->type;
-
- if(res->op != OREGISTER) {
- regalloc(&nod2, types[tptr], res);
- gins(ALEAL, &nod1, &nod2);
- gins(AMOVL, &nod2, res);
- regfree(&nod2);
- } else
- gins(ALEAL, &nod1, res);
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-void
-cgen_ret(Node *n)
-{
- genlist(n->list); // copy out args
- if(retpc)
- gjmp(retpc);
- else
- gins(ARET, N, N);
-}
-
-/*
- * generate += *= etc.
- */
-void
-cgen_asop(Node *n)
-{
- Node n1, n2, n3, n4;
- Node *nl, *nr;
- Prog *p1;
- Addr addr;
- int a;
-
- nl = n->left;
- nr = n->right;
-
- if(nr->ullman >= UINF && nl->ullman >= UINF) {
- tempname(&n1, nr->type);
- cgen(nr, &n1);
- n2 = *n;
- n2.right = &n1;
- cgen_asop(&n2);
- goto ret;
- }
-
- if(!isint[nl->type->etype])
- goto hard;
- if(!isint[nr->type->etype])
- goto hard;
- if(is64(nl->type) || is64(nr->type))
- goto hard;
-
- switch(n->etype) {
- case OADD:
- if(smallintconst(nr))
- if(mpgetfix(nr->val.u.xval) == 1) {
- a = optoas(OINC, nl->type);
- if(nl->addable) {
- gins(a, N, nl);
- goto ret;
- }
- if(sudoaddable(a, nl, &addr)) {
- p1 = gins(a, N, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- }
- break;
-
- case OSUB:
- if(smallintconst(nr))
- if(mpgetfix(nr->val.u.xval) == 1) {
- a = optoas(ODEC, nl->type);
- if(nl->addable) {
- gins(a, N, nl);
- goto ret;
- }
- if(sudoaddable(a, nl, &addr)) {
- p1 = gins(a, N, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- }
- break;
- }
-
- switch(n->etype) {
- case OADD:
- case OSUB:
- case OXOR:
- case OAND:
- case OOR:
- a = optoas(n->etype, nl->type);
- if(nl->addable) {
- if(smallintconst(nr)) {
- gins(a, nr, nl);
- goto ret;
- }
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- gins(a, &n2, nl);
- regfree(&n2);
- goto ret;
- }
- if(nr->ullman < UINF)
- if(sudoaddable(a, nl, &addr)) {
- if(smallintconst(nr)) {
- p1 = gins(a, nr, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- p1 = gins(a, &n2, N);
- p1->to = addr;
- regfree(&n2);
- sudoclean();
- goto ret;
- }
- }
-
-hard:
- n2.op = 0;
- n1.op = 0;
- if(nr->ullman >= nl->ullman || nl->addable) {
- mgen(nr, &n2, N);
- nr = &n2;
- nr = &n2;
- } else {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- if(!nl->addable) {
- igen(nl, &n1, N);
- nl = &n1;
- }
-
- n3 = *n;
- n3.left = nl;
- n3.right = nr;
- n3.op = n->etype;
-
- mgen(&n3, &n4, N);
- gmove(&n4, nl);
-
- if(n1.op)
- regfree(&n1);
- mfree(&n2);
- mfree(&n4);
-
-ret:
- ;
-}
-
-int
-samereg(Node *a, Node *b)
-{
- 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.
- * caller must set:
- * ax = allocated AX register
- * dx = allocated DX register
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-void
-dodiv(int op, Type *t, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
-{
- Node n1, t1, t2, nz;
-
- tempname(&t1, nl->type);
- tempname(&t2, nr->type);
- cgen(nl, &t1);
- cgen(nr, &t2);
-
- if(!samereg(ax, res) && !samereg(dx, res))
- regalloc(&n1, t, res);
- else
- regalloc(&n1, t, N);
- gmove(&t2, &n1);
- gmove(&t1, ax);
- if(!issigned[t->etype]) {
- nodconst(&nz, t, 0);
- gmove(&nz, dx);
- } else
- gins(optoas(OEXTEND, t), N, N);
- gins(optoas(op, t), &n1, N);
- regfree(&n1);
-
- if(op == ODIV)
- gmove(ax, res);
- else
- gmove(dx, res);
-}
-
-static void
-savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
-{
- int r;
-
- r = reg[dr];
- nodreg(x, types[TINT32], dr);
-
- // save current ax and dx if they are live
- // and not the destination
- memset(oldx, 0, sizeof *oldx);
- if(r > 0 && !samereg(x, res)) {
- tempname(oldx, types[TINT32]);
- gmove(x, oldx);
- }
-
- regalloc(x, t, x);
-}
-
-static void
-restx(Node *x, Node *oldx)
-{
- regfree(x);
-
- if(oldx->op != 0) {
- x->type = types[TINT32];
- gmove(oldx, x);
- }
-}
-
-/*
- * 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 ax, dx, oldax, olddx;
- Type *t;
-
- if(is64(nl->type))
- fatal("cgen_div %T", nl->type);
-
- t = nl->type;
- if(t->width == 1)
- t = types[t->etype+2]; // int8 -> int16, uint8 -> uint16
-
- savex(D_AX, &ax, &oldax, res, t);
- savex(D_DX, &dx, &olddx, res, t);
- dodiv(op, t, nl, nr, res, &ax, &dx);
- restx(&dx, &olddx);
- restx(&ax, &oldax);
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-void
-cgen_shift(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, cx, oldcx;
- int a, w;
- Prog *p1;
- uvlong sc;
-
- if(nl->type->width > 4)
- fatal("cgen_shift %T", nl->type);
-
- w = nl->type->width * 8;
-
- a = optoas(op, nl->type);
-
- if(nr->op == OLITERAL) {
- tempname(&n2, nl->type);
- cgen(nl, &n2);
- regalloc(&n1, nl->type, res);
- gmove(&n2, &n1);
- sc = mpgetfix(nr->val.u.xval);
- if(sc >= nl->type->width*8) {
- // large shift gets 2 shifts by width
- gins(a, ncon(w-1), &n1);
- gins(a, ncon(w-1), &n1);
- } else
- gins(a, nr, &n1);
- gmove(&n1, res);
- regfree(&n1);
- return;
- }
-
- memset(&oldcx, 0, sizeof oldcx);
- nodreg(&cx, types[TUINT32], D_CX);
- if(reg[D_CX] > 1 && !samereg(&cx, res)) {
- tempname(&oldcx, types[TUINT32]);
- gmove(&cx, &oldcx);
- }
-
- nodreg(&n1, types[TUINT32], D_CX);
- regalloc(&n1, nr->type, &n1); // to hold the shift type in CX
-
- if(samereg(&cx, res))
- regalloc(&n2, nl->type, N);
- else
- regalloc(&n2, nl->type, res);
- if(nl->ullman >= nr->ullman) {
- cgen(nl, &n2);
- cgen(nr, &n1);
- } else {
- cgen(nr, &n1);
- cgen(nl, &n2);
- }
-
- // test and fix up large shifts
- gins(optoas(OCMP, nr->type), &n1, ncon(w));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
- if(op == ORSH && issigned[nl->type->etype]) {
- gins(a, ncon(w-1), &n2);
- } else {
- gmove(ncon(0), &n2);
- }
- patch(p1, pc);
- gins(a, &n1, &n2);
-
- if(oldcx.op != 0)
- gmove(&oldcx, &cx);
-
- gmove(&n2, res);
-
- regfree(&n1);
- regfree(&n2);
-}
-
-/*
- * generate byte multiply:
- * res = nl * nr
- * no byte multiply instruction so have to do
- * 16-bit multiply and take bottom half.
- */
-void
-cgen_bmul(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1b, n2b, n1w, n2w;
- Type *t;
- int a;
-
- if(nl->ullman >= nr->ullman) {
- regalloc(&n1b, nl->type, res);
- cgen(nl, &n1b);
- regalloc(&n2b, nr->type, N);
- cgen(nr, &n2b);
- } else {
- regalloc(&n2b, nr->type, N);
- cgen(nr, &n2b);
- regalloc(&n1b, nl->type, res);
- cgen(nl, &n1b);
- }
-
- // copy from byte to short registers
- t = types[TUINT16];
- if(issigned[nl->type->etype])
- t = types[TINT16];
-
- regalloc(&n2w, t, &n2b);
- cgen(&n2b, &n2w);
-
- regalloc(&n1w, t, &n1b);
- cgen(&n1b, &n1w);
-
- a = optoas(op, t);
- gins(a, &n2w, &n1w);
- cgen(&n1w, &n1b);
- cgen(&n1b, res);
-
- regfree(&n1w);
- regfree(&n2w);
- regfree(&n1b);
- regfree(&n2b);
-}
-
-static int
-regcmp(const void *va, const void *vb)
-{
- Node *ra, *rb;
-
- ra = (Node*)va;
- rb = (Node*)vb;
- return ra->local - rb->local;
-}
-
-static Prog* throwpc;
-
-// We're only going to bother inlining if we can
-// convert all the arguments to 32 bits safely. Can we?
-static int
-fix64(NodeList *nn, int n)
-{
- NodeList *l;
- Node *r;
- int i;
-
- l = nn;
- for(i=0; i<n; i++) {
- r = l->n->right;
- if(is64(r->type) && !smallintconst(r)) {
- if(r->op == OCONV)
- r = r->left;
- if(is64(r->type))
- return 0;
- }
- l = l->next;
- }
- return 1;
-}
-
-void
-getargs(NodeList *nn, Node *reg, int n)
-{
- NodeList *l;
- Node *r;
- int i;
-
- throwpc = nil;
-
- l = nn;
- for(i=0; i<n; i++) {
- r = l->n->right;
- if(is64(r->type)) {
- if(r->op == OCONV)
- r = r->left;
- else if(smallintconst(r))
- r->type = types[TUINT32];
- if(is64(r->type))
- fatal("getargs");
- }
- if(!smallintconst(r) && !isslice(r->type)) {
- if(i < 3) // AX CX DX
- nodreg(reg+i, r->type, D_AX+i);
- else
- reg[i].op = OXXX;
- regalloc(reg+i, r->type, reg+i);
- cgen(r, reg+i);
- } else
- reg[i] = *r;
- if(reg[i].local != 0)
- yyerror("local used");
- reg[i].local = l->n->left->xoffset;
- l = l->next;
- }
- qsort((void*)reg, n, sizeof(*reg), regcmp);
- for(i=0; i<n; i++)
- reg[i].local = 0;
-}
-
-void
-cmpandthrow(Node *nl, Node *nr)
-{
- vlong cl;
- Prog *p1;
- int op;
- Node *c, n1;
- Type *t;
-
- op = OLE;
- if(smallintconst(nl)) {
- cl = mpgetfix(nl->val.u.xval);
- if(cl == 0)
- return;
- if(smallintconst(nr))
- return;
- // put the constant on the right
- op = brrev(op);
- c = nl;
- nl = nr;
- nr = c;
- }
-
- // Arguments are known not to be 64-bit,
- // but they might be smaller than 32 bits.
- // Check if we need to use a temporary.
- // At least one of the arguments is 32 bits
- // (the len or cap) so one temporary suffices.
- n1.op = OXXX;
- t = types[TUINT32];
- if(nl->type->width != t->width) {
- regalloc(&n1, t, nl);
- gmove(nl, &n1);
- nl = &n1;
- } else if(nr->type->width != t->width) {
- regalloc(&n1, t, nr);
- gmove(nr, &n1);
- nr = &n1;
- }
- gins(optoas(OCMP, t), nl, nr);
- if(n1.op != OXXX)
- regfree(&n1);
- if(throwpc == nil) {
- p1 = gbranch(optoas(op, t), T);
- throwpc = pc;
- ginscall(panicslice, 0);
- patch(p1, pc);
- } else {
- op = brcom(op);
- p1 = gbranch(optoas(op, t), T);
- patch(p1, throwpc);
- }
-}
-
-int
-sleasy(Node *n)
-{
- if(n->op != ONAME)
- return 0;
- if(!n->addable)
- return 0;
- return 1;
-}
-
-// generate inline code for
-// slicearray
-// sliceslice
-// arraytoslice
-int
-cgen_inline(Node *n, Node *res)
-{
- Node nodes[5];
- Node n1, n2, nres, ntemp;
- vlong v;
- int i, narg, nochk;
-
- if(n->op != OCALLFUNC)
- goto no;
- if(!n->left->addable)
- goto no;
- if(n->left->sym == S)
- goto no;
- if(n->left->sym->pkg != runtimepkg)
- goto no;
- if(strcmp(n->left->sym->name, "slicearray") == 0)
- goto slicearray;
- if(strcmp(n->left->sym->name, "sliceslice") == 0) {
- narg = 4;
- goto sliceslice;
- }
- if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
- narg = 3;
- goto sliceslice;
- }
- goto no;
-
-slicearray:
- if(!sleasy(res))
- goto no;
- if(!fix64(n->list, 5))
- goto no;
- getargs(n->list, nodes, 5);
-
- // if(hb[3] > nel[1]) goto throw
- cmpandthrow(&nodes[3], &nodes[1]);
-
- // if(lb[2] > hb[3]) goto throw
- cmpandthrow(&nodes[2], &nodes[3]);
-
- // len = hb[3] - lb[2] (destroys hb)
- n2 = *res;
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
-
- if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
- v = mpgetfix(nodes[3].val.u.xval) -
- mpgetfix(nodes[2].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[3]);
- gmove(&nodes[3], &n1);
- if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
- }
-
- // cap = nel[1] - lb[2] (destroys nel)
- n2 = *res;
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
-
- if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
- v = mpgetfix(nodes[1].val.u.xval) -
- mpgetfix(nodes[2].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[1]);
- gmove(&nodes[1], &n1);
- if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
- }
-
- // if slice could be too big, dereference to
- // catch nil array pointer.
- if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
- n2 = nodes[0];
- n2.xoffset = 0;
- n2.op = OINDREG;
- n2.type = types[TUINT8];
- gins(ATESTB, nodintconst(0), &n2);
- }
-
- // ary = old[0] + (lb[2] * width[4]) (destroys old)
- n2 = *res;
- n2.xoffset += Array_array;
- n2.type = types[tptr];
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
- v = mpgetfix(nodes[2].val.u.xval) *
- mpgetfix(nodes[4].val.u.xval);
- if(v != 0) {
- nodconst(&n1, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- }
- } else {
- regalloc(&n1, types[tptr], &nodes[2]);
- gmove(&nodes[2], &n1);
- if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1)
- gins(optoas(OMUL, types[tptr]), &nodes[4], &n1);
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- regfree(&n1);
- }
- gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
-
- for(i=0; i<5; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
- return 1;
-
-sliceslice:
- if(!fix64(n->list, narg))
- goto no;
- nochk = n->etype; // skip bounds checking
- ntemp.op = OXXX;
- if(!sleasy(n->list->n->right)) {
- Node *n0;
-
- n0 = n->list->n->right;
- tempname(&ntemp, res->type);
- cgen(n0, &ntemp);
- n->list->n->right = &ntemp;
- getargs(n->list, nodes, narg);
- n->list->n->right = n0;
- } else
- getargs(n->list, nodes, narg);
-
- nres = *res; // result
- if(!sleasy(res)) {
- if(ntemp.op == OXXX)
- tempname(&ntemp, res->type);
- nres = ntemp;
- }
-
- if(narg == 3) { // old[lb:]
- // move width to where it would be for old[lb:hb]
- nodes[3] = nodes[2];
- nodes[2].op = OXXX;
-
- // if(lb[1] > old.nel[0]) goto throw;
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- if(!nochk)
- cmpandthrow(&nodes[1], &n2);
-
- // ret.nel = old.nel[0]-lb[1];
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
-
- regalloc(&n1, types[TUINT32], N);
- gins(optoas(OAS, types[TUINT32]), &n2, &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
-
- n2 = nres;
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
- } else { // old[lb:hb]
- n2 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
- if (!nochk) {
- // if(hb[2] > old.cap[0]) goto throw;
- cmpandthrow(&nodes[2], &n2);
- // if(lb[1] > hb[2]) goto throw;
- cmpandthrow(&nodes[1], &nodes[2]);
- }
-
- // ret.len = hb[2]-lb[1]; (destroys hb[2])
- n2 = nres;
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
- v = mpgetfix(nodes[2].val.u.xval) -
- mpgetfix(nodes[1].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gmove(&nodes[2], &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
- }
- }
-
- // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
- n2 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
-
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gins(optoas(OAS, types[TUINT32]), &n2, &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
-
- n2 = nres;
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
-
- // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
- n2 = nodes[0];
- n2.xoffset += Array_array;
- n2.type = types[tptr];
-
- regalloc(&n1, types[tptr], &nodes[1]);
- if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
- gins(optoas(OAS, types[tptr]), &n2, &n1);
- v = mpgetfix(nodes[1].val.u.xval) *
- mpgetfix(nodes[3].val.u.xval);
- if(v != 0) {
- nodconst(&n2, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n2, &n1);
- }
- } else {
- gmove(&nodes[1], &n1);
- if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1)
- gins(optoas(OMUL, types[tptr]), &nodes[3], &n1);
- gins(optoas(OADD, types[tptr]), &n2, &n1);
- }
-
- n2 = nres;
- n2.xoffset += Array_array;
- n2.type = types[tptr];
- gins(optoas(OAS, types[tptr]), &n1, &n2);
- regfree(&n1);
-
- for(i=0; i<4; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
-
- if(!sleasy(res)) {
- cgen(&nres, res);
- }
- return 1;
-
-no:
- return 0;
-}
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
deleted file mode 100644
index 31c42a3f2..000000000
--- a/src/cmd/8g/gobj.c
+++ /dev/null
@@ -1,651 +0,0 @@
-// Derived from 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 "gg.h"
-
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- Bputc(b, ANAME); /* as */
- Bputc(b, ANAME>>8); /* as */
- Bputc(b, t); /* type */
- Bputc(b, s->sym); /* sym */
-
- Bputname(b, s);
-}
-
-void
-zfile(Biobuf *b, char *p, int n)
-{
- Bputc(b, ANAME);
- Bputc(b, ANAME>>8);
- Bputc(b, D_FILE);
- Bputc(b, 1);
- Bputc(b, '<');
- Bwrite(b, p, n);
- Bputc(b, 0);
-}
-
-void
-zhist(Biobuf *b, int line, vlong offset)
-{
- Addr a;
-
- Bputc(b, AHISTORY);
- Bputc(b, AHISTORY>>8);
- Bputc(b, line);
- Bputc(b, line>>8);
- Bputc(b, line>>16);
- Bputc(b, line>>24);
- zaddr(b, &zprog.from, 0, 0);
- a = zprog.to;
- if(offset != 0) {
- a.offset = offset;
- a.type = D_CONST;
- }
- zaddr(b, &a, 0, 0);
-}
-
-void
-zaddr(Biobuf *b, Addr *a, int s, int gotype)
-{
- int32 l;
- uint64 e;
- int i, t;
- char *n;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(s != 0)
- t |= T_SYM;
- if(gotype != 0)
- t |= T_GOTYPE;
-
- switch(a->type) {
-
- case D_BRANCH:
- if(a->branch == nil)
- fatal("unpatched branch");
- a->offset = a->branch->loc;
-
- default:
- t |= T_TYPE;
-
- case D_NONE:
- if(a->offset != 0)
- t |= T_OFFSET;
- if(a->offset2 != 0)
- t |= T_OFFSET2;
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- }
- Bputc(b, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- Bputc(b, a->index);
- Bputc(b, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- }
- if(t & T_OFFSET2) { /* implies offset */
- l = a->offset2;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- }
- if(t & T_SYM) /* implies sym */
- Bputc(b, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->dval);
- l = e;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- l = e >> 32;
- Bputc(b, l);
- Bputc(b, l>>8);
- Bputc(b, l>>16);
- Bputc(b, l>>24);
- return;
- }
- if(t & T_SCONST) {
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- Bputc(b, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- Bputc(b, a->type);
- if(t & T_GOTYPE)
- Bputc(b, gotype);
-}
-
-static struct {
- struct { Sym *sym; short type; } h[NSYM];
- int sym;
-} z;
-
-static void
-zsymreset(void)
-{
- for(z.sym=0; z.sym<NSYM; z.sym++) {
- z.h[z.sym].sym = S;
- z.h[z.sym].type = 0;
- }
- z.sym = 1;
-}
-
-static int
-zsym(Sym *s, int t, int *new)
-{
- int i;
-
- *new = 0;
- if(s == S)
- return 0;
-
- i = s->sym;
- if(i < 0 || i >= NSYM)
- i = 0;
- if(z.h[i].type == t && z.h[i].sym == s)
- return i;
- i = z.sym;
- s->sym = i;
- zname(bout, s, t);
- z.h[i].sym = s;
- z.h[i].type = t;
- if(++z.sym >= NSYM)
- z.sym = 1;
- *new = 1;
- return i;
-}
-
-static int
-zsymaddr(Addr *a, int *new)
-{
- int t;
-
- t = a->type;
- if(t == D_ADDR)
- t = a->index;
- return zsym(a->sym, t, new);
-}
-
-void
-dumpfuncs(void)
-{
- Plist *pl;
- int sf, st, gf, gt, new;
- Sym *s;
- Prog *p;
-
- zsymreset();
-
- // fix up pc
- pcloc = 0;
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
- for(p=pl->firstpc; p!=P; p=p->link) {
- p->loc = pcloc;
- if(p->as != ADATA && p->as != AGLOBL)
- pcloc++;
- }
- }
-
- // put out functions
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
-
- if(debug['S']) {
- s = S;
- if(pl->name != N)
- s = pl->name->sym;
- print("\n--- prog list \"%S\" ---\n", s);
- for(p=pl->firstpc; p!=P; p=p->link)
- print("%P\n", p);
- }
-
- for(p=pl->firstpc; p!=P; p=p->link) {
- for(;;) {
- sf = zsymaddr(&p->from, &new);
- gf = zsym(p->from.gotype, D_EXTERN, &new);
- if(new && sf == gf)
- continue;
- st = zsymaddr(&p->to, &new);
- if(new && (st == sf || st == gf))
- continue;
- gt = zsym(p->to.gotype, D_EXTERN, &new);
- if(new && (gt == sf || gt == gf || gt == st))
- continue;
- break;
- }
-
- Bputc(bout, p->as);
- Bputc(bout, p->as>>8);
- Bputc(bout, p->lineno);
- Bputc(bout, p->lineno>>8);
- Bputc(bout, p->lineno>>16);
- Bputc(bout, p->lineno>>24);
- zaddr(bout, &p->from, sf, gf);
- zaddr(bout, &p->to, st, gt);
- }
- }
-}
-
-/* deferred DATA output */
-static Prog *strdat;
-static Prog *estrdat;
-static int gflag;
-static Prog *savepc;
-
-void
-data(void)
-{
- gflag = debug['g'];
- debug['g'] = 0;
-
- if(estrdat == nil) {
- strdat = mal(sizeof(*pc));
- clearp(strdat);
- estrdat = strdat;
- }
- if(savepc)
- fatal("data phase error");
- savepc = pc;
- pc = estrdat;
-}
-
-void
-text(void)
-{
- if(!savepc)
- fatal("text phase error");
- debug['g'] = gflag;
- estrdat = pc;
- pc = savepc;
- savepc = nil;
-}
-
-void
-dumpdata(void)
-{
- Prog *p;
-
- if(estrdat == nil)
- return;
- *pc = *strdat;
- if(gflag)
- for(p=pc; p!=estrdat; p=p->link)
- print("%P\n", p);
- pc = estrdat;
-}
-
-int
-dsname(Sym *s, int off, char *t, int n)
-{
- Prog *p;
-
- p = gins(ADATA, N, N);
- p->from.type = D_EXTERN;
- p->from.index = D_NONE;
- p->from.offset = off;
- p->from.scale = n;
- p->from.sym = s;
-
- p->to.type = D_SCONST;
- p->to.index = D_NONE;
- memmove(p->to.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_EXTERN;
- a->sym = sym;
- a->offset = widthptr+4; // skip header
- a->etype = TINT32;
-}
-
-/*
- * 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_EXTERN;
- a->sym = sym;
- a->offset = 0; // header
- a->etype = TINT32;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
- Prog *p;
- vlong v;
-
- if(wid == 8 && is64(nr->type)) {
- v = mpgetfix(nr->val.u.xval);
- p = gins(ADATA, nam, nodintconst(v));
- p->from.scale = 4;
- p = gins(ADATA, nam, nodintconst(v>>32));
- p->from.scale = 4;
- p->from.offset += 4;
- return;
- }
- p = gins(ADATA, nam, nr);
- p->from.scale = 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->from.scale = w;
- p->to.type = D_FCONST;
- p->to.dval = mpgetflt(&cval->real);
-
- p = gins(ADATA, nam, N);
- p->from.scale = w;
- p->from.offset += w;
- p->to.type = D_FCONST;
- p->to.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->from.scale = types[tptr]->width;
- p->to.index = p->to.type;
- p->to.type = D_ADDR;
-//print("%P\n", p);
-
- nodconst(&nod1, types[TINT32], sval->len);
- p = gins(ADATA, nam, &nod1);
- p->from.scale = types[TINT32]->width;
- p->from.offset += types[tptr]->width;
-}
-
-int
-dstringptr(Sym *s, int off, char *str)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
- p = gins(ADATA, N, N);
- p->from.type = D_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->from.offset = off;
- p->from.scale = widthptr;
-
- datastring(str, strlen(str)+1, &p->to);
- p->to.index = p->to.type;
- p->to.type = D_ADDR;
- p->to.etype = TINT32;
- 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_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->from.offset = off;
- p->from.scale = widthptr;
- datagostring(lit, &p->to);
- p->to.index = p->to.type;
- p->to.type = D_ADDR;
- p->to.etype = TINT32;
- 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
-duintxx(Sym *s, int off, uint64 v, int wid)
-{
- Prog *p;
-
- off = rnd(off, wid);
-
- p = gins(ADATA, N, N);
- p->from.type = D_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->from.offset = off;
- p->from.scale = wid;
- p->to.type = D_CONST;
- p->to.index = D_NONE;
- p->to.offset = v;
- off += wid;
-
- return off;
-}
-
-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_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->from.offset = off;
- p->from.scale = widthptr;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.sym = x;
- p->to.offset = xoff;
- off += widthptr;
-
- return off;
-}
-
-void
-genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
-{
- Sym *e;
- int c, d, o, mov, add, loaded;
- Prog *p;
- Type *f;
-
- e = method->sym;
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(e, rcvr, d, nil, 0);
- if(c == 1)
- goto out;
- }
- fatal("genembedtramp %T.%S", rcvr, method->sym);
-
-out:
- newplist()->name = newname(newnam);
-
- //TEXT main·S_test2(SB),7,$0
- p = pc;
- gins(ATEXT, N, N);
- p->from.type = D_EXTERN;
- p->from.sym = newnam;
- p->to.type = D_CONST;
- p->to.offset = 0;
- p->from.scale = 7;
-//print("1. %P\n", p);
-
- mov = AMOVL;
- add = AADDL;
-
- loaded = 0;
- o = 0;
- for(c=d-1; c>=0; c--) {
- f = dotlist[c].field;
- o += f->width;
- if(!isptr[f->type->etype])
- continue;
- if(!loaded) {
- loaded = 1;
- //MOVL 4(SP), AX
- p = pc;
- gins(mov, N, N);
- p->from.type = D_INDIR+D_SP;
- p->from.offset = widthptr;
- p->to.type = D_AX;
-//print("2. %P\n", p);
- }
-
- //MOVL o(AX), AX
- p = pc;
- gins(mov, N, N);
- p->from.type = D_INDIR+D_AX;
- p->from.offset = o;
- p->to.type = D_AX;
-//print("3. %P\n", p);
- o = 0;
- }
- if(o != 0) {
- //ADDL $XX, AX
- p = pc;
- gins(add, N, N);
- p->from.type = D_CONST;
- p->from.offset = o;
- if(loaded)
- p->to.type = D_AX;
- else {
- p->to.type = D_INDIR+D_SP;
- p->to.offset = widthptr;
- }
-//print("4. %P\n", p);
- }
-
- //MOVL AX, 4(SP)
- if(loaded) {
- p = pc;
- gins(mov, N, N);
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_SP;
- p->to.offset = widthptr;
-//print("5. %P\n", p);
- } else {
- // TODO(rsc): obviously this is unnecessary,
- // but 6l has a bug, and it can't handle
- // JMP instructions too close to the top of
- // a new function.
- p = pc;
- gins(ANOP, N, N);
- }
-
- f = dotlist[0].field;
- //JMP main·*Sub_test2(SB)
- if(isptr[f->type->etype])
- f = f->type;
- p = pc;
- gins(AJMP, N, N);
- p->to.type = D_EXTERN;
- p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
-//print("6. %P\n", p);
-
- pc->as = ARET; // overwrite AEND
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
-}
-
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
deleted file mode 100644
index a35c81eb1..000000000
--- a/src/cmd/8g/gsubr.c
+++ /dev/null
@@ -1,1959 +0,0 @@
-// Derived from 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 "gg.h"
-
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 8l for all GOOS.
-uint32 unmappedzero = 4096;
-
-#define CASE(a,b) (((a)<<16)|((b)<<0))
-
-void
-clearp(Prog *p)
-{
- p->as = AEND;
- p->from.type = D_NONE;
- p->from.index = D_NONE;
- p->to.type = D_NONE;
- p->to.index = D_NONE;
- p->loc = pcloc;
- pcloc++;
-}
-
-/*
- * generate and return proc with p->as = as,
- * linked into program. pc is next instruction.
- */
-Prog*
-prog(int as)
-{
- Prog *p;
-
- p = pc;
- pc = mal(sizeof(*pc));
-
- clearp(pc);
-
- if(lineno == 0) {
- if(debug['K'])
- warn("prog: line 0");
- }
-
- p->as = as;
- p->lineno = lineno;
- p->link = pc;
- return p;
-}
-
-/*
- * generate a branch.
- * t is ignored.
- */
-Prog*
-gbranch(int as, Type *t)
-{
- Prog *p;
-
- p = prog(as);
- p->to.type = D_BRANCH;
- p->to.branch = P;
- 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.branch = to;
- p->to.offset = to->loc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
- Prog *q;
-
- if(p->to.type != D_BRANCH)
- fatal("unpatch: not a branch");
- q = p->to.branch;
- p->to.branch = P;
- p->to.offset = 0;
- return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
- Plist *pl;
-
- pl = mal(sizeof(*pl));
- if(plist == nil)
- plist = pl;
- else
- plast->link = pl;
- plast = pl;
-
- pc = mal(sizeof(*pc));
- clearp(pc);
- pl->firstpc = pc;
-
- return pl;
-}
-
-void
-clearstk(void)
-{
- Plist *pl;
- Prog *p1, *p2;
- Node sp, di, cx, con, ax;
-
- if(plast->firstpc->to.offset <= 0)
- return;
-
- // reestablish context for inserting code
- // at beginning of function.
- pl = plast;
- p1 = pl->firstpc;
- p2 = p1->link;
- pc = mal(sizeof(*pc));
- clearp(pc);
- p1->link = pc;
-
- // zero stack frame
- nodreg(&sp, types[tptr], D_SP);
- nodreg(&di, types[tptr], D_DI);
- nodreg(&cx, types[TUINT32], D_CX);
- nodconst(&con, types[TUINT32], p1->to.offset / widthptr);
- gins(ACLD, N, N);
- gins(AMOVL, &sp, &di);
- gins(AMOVL, &con, &cx);
- nodconst(&con, types[TUINT32], 0);
- nodreg(&ax, types[TUINT32], D_AX);
- gins(AMOVL, &con, &ax);
- gins(AREP, N, N);
- gins(ASTOSL, N, N);
-
- // continue with original code.
- gins(ANOP, N, N)->link = p2;
- pc = P;
-}
-
-void
-gused(Node *n)
-{
- gins(ANOP, n, N); // used
-}
-
-Prog*
-gjmp(Prog *to)
-{
- Prog *p;
-
- p = gbranch(AJMP, T);
- if(to != P)
- patch(p, to);
- return p;
-}
-
-void
-ggloblnod(Node *nam, int32 width)
-{
- Prog *p;
-
- p = gins(AGLOBL, nam, N);
- p->lineno = nam->lineno;
- p->to.sym = S;
- p->to.type = D_CONST;
- p->to.offset = width;
- if(nam->readonly)
- p->from.scale = RODATA;
-}
-
-void
-ggloblsym(Sym *s, int32 width, int dupok)
-{
- Prog *p;
-
- p = gins(AGLOBL, N, N);
- p->from.type = D_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->to.type = D_CONST;
- p->to.index = D_NONE;
- p->to.offset = width;
- if(dupok)
- p->from.scale = DUPOK;
- p->from.scale |= RODATA;
-}
-
-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)
-{
- if(a->type == D_ADDR && a->index == D_EXTERN) {
- a->type = D_EXTERN;
- a->index = D_NONE;
- }
-}
-
-/*
- * 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 %O-%T", op, t);
- break;
-
- case CASE(OADDR, TPTR32):
- a = ALEAL;
- 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 = AJEQ;
- 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 = AJNE;
- break;
-
- case CASE(OLT, TINT8):
- case CASE(OLT, TINT16):
- case CASE(OLT, TINT32):
- case CASE(OLT, TINT64):
- a = AJLT;
- break;
-
- case CASE(OLT, TUINT8):
- case CASE(OLT, TUINT16):
- case CASE(OLT, TUINT32):
- case CASE(OLT, TUINT64):
- a = AJCS;
- break;
-
- case CASE(OLE, TINT8):
- case CASE(OLE, TINT16):
- case CASE(OLE, TINT32):
- case CASE(OLE, TINT64):
- a = AJLE;
- break;
-
- case CASE(OLE, TUINT8):
- case CASE(OLE, TUINT16):
- case CASE(OLE, TUINT32):
- case CASE(OLE, TUINT64):
- a = AJLS;
- break;
-
- case CASE(OGT, TINT8):
- case CASE(OGT, TINT16):
- case CASE(OGT, TINT32):
- case CASE(OGT, TINT64):
- a = AJGT;
- break;
-
- case CASE(OGT, TUINT8):
- case CASE(OGT, TUINT16):
- case CASE(OGT, TUINT32):
- case CASE(OGT, TUINT64):
- case CASE(OLT, TFLOAT32):
- case CASE(OLT, TFLOAT64):
- a = AJHI;
- break;
-
- case CASE(OGE, TINT8):
- case CASE(OGE, TINT16):
- case CASE(OGE, TINT32):
- case CASE(OGE, TINT64):
- a = AJGE;
- break;
-
- case CASE(OGE, TUINT8):
- case CASE(OGE, TUINT16):
- case CASE(OGE, TUINT32):
- case CASE(OGE, TUINT64):
- case CASE(OLE, TFLOAT32):
- case CASE(OLE, TFLOAT64):
- a = AJCC;
- break;
-
- case CASE(OCMP, TBOOL):
- case CASE(OCMP, TINT8):
- case CASE(OCMP, TUINT8):
- a = ACMPB;
- break;
-
- case CASE(OCMP, TINT16):
- case CASE(OCMP, TUINT16):
- a = ACMPW;
- break;
-
- case CASE(OCMP, TINT32):
- case CASE(OCMP, TUINT32):
- case CASE(OCMP, TPTR32):
- a = ACMPL;
- break;
-
- case CASE(OAS, TBOOL):
- case CASE(OAS, TINT8):
- case CASE(OAS, TUINT8):
- a = AMOVB;
- break;
-
- case CASE(OAS, TINT16):
- case CASE(OAS, TUINT16):
- a = AMOVW;
- break;
-
- case CASE(OAS, TINT32):
- case CASE(OAS, TUINT32):
- case CASE(OAS, TPTR32):
- a = AMOVL;
- break;
-
- case CASE(OADD, TINT8):
- case CASE(OADD, TUINT8):
- a = AADDB;
- break;
-
- case CASE(OADD, TINT16):
- case CASE(OADD, TUINT16):
- a = AADDW;
- break;
-
- case CASE(OADD, TINT32):
- case CASE(OADD, TUINT32):
- case CASE(OADD, TPTR32):
- a = AADDL;
- break;
-
- case CASE(OSUB, TINT8):
- case CASE(OSUB, TUINT8):
- a = ASUBB;
- break;
-
- case CASE(OSUB, TINT16):
- case CASE(OSUB, TUINT16):
- a = ASUBW;
- break;
-
- case CASE(OSUB, TINT32):
- case CASE(OSUB, TUINT32):
- case CASE(OSUB, TPTR32):
- a = ASUBL;
- break;
-
- case CASE(OINC, TINT8):
- case CASE(OINC, TUINT8):
- a = AINCB;
- break;
-
- case CASE(OINC, TINT16):
- case CASE(OINC, TUINT16):
- a = AINCW;
- break;
-
- case CASE(OINC, TINT32):
- case CASE(OINC, TUINT32):
- case CASE(OINC, TPTR32):
- a = AINCL;
- break;
-
- case CASE(ODEC, TINT8):
- case CASE(ODEC, TUINT8):
- a = ADECB;
- break;
-
- case CASE(ODEC, TINT16):
- case CASE(ODEC, TUINT16):
- a = ADECW;
- break;
-
- case CASE(ODEC, TINT32):
- case CASE(ODEC, TUINT32):
- case CASE(ODEC, TPTR32):
- a = ADECL;
- break;
-
- case CASE(OCOM, TINT8):
- case CASE(OCOM, TUINT8):
- a = ANOTB;
- break;
-
- case CASE(OCOM, TINT16):
- case CASE(OCOM, TUINT16):
- a = ANOTW;
- break;
-
- case CASE(OCOM, TINT32):
- case CASE(OCOM, TUINT32):
- case CASE(OCOM, TPTR32):
- a = ANOTL;
- break;
-
- case CASE(OMINUS, TINT8):
- case CASE(OMINUS, TUINT8):
- a = ANEGB;
- break;
-
- case CASE(OMINUS, TINT16):
- case CASE(OMINUS, TUINT16):
- a = ANEGW;
- break;
-
- case CASE(OMINUS, TINT32):
- case CASE(OMINUS, TUINT32):
- case CASE(OMINUS, TPTR32):
- a = ANEGL;
- break;
-
- case CASE(OAND, TINT8):
- case CASE(OAND, TUINT8):
- a = AANDB;
- break;
-
- case CASE(OAND, TINT16):
- case CASE(OAND, TUINT16):
- a = AANDW;
- break;
-
- case CASE(OAND, TINT32):
- case CASE(OAND, TUINT32):
- case CASE(OAND, TPTR32):
- a = AANDL;
- break;
-
- case CASE(OOR, TINT8):
- case CASE(OOR, TUINT8):
- a = AORB;
- break;
-
- case CASE(OOR, TINT16):
- case CASE(OOR, TUINT16):
- a = AORW;
- break;
-
- case CASE(OOR, TINT32):
- case CASE(OOR, TUINT32):
- case CASE(OOR, TPTR32):
- a = AORL;
- break;
-
- case CASE(OXOR, TINT8):
- case CASE(OXOR, TUINT8):
- a = AXORB;
- break;
-
- case CASE(OXOR, TINT16):
- case CASE(OXOR, TUINT16):
- a = AXORW;
- break;
-
- case CASE(OXOR, TINT32):
- case CASE(OXOR, TUINT32):
- case CASE(OXOR, TPTR32):
- a = AXORL;
- break;
-
- case CASE(OLSH, TINT8):
- case CASE(OLSH, TUINT8):
- a = ASHLB;
- break;
-
- case CASE(OLSH, TINT16):
- case CASE(OLSH, TUINT16):
- a = ASHLW;
- break;
-
- case CASE(OLSH, TINT32):
- case CASE(OLSH, TUINT32):
- case CASE(OLSH, TPTR32):
- a = ASHLL;
- break;
-
- case CASE(ORSH, TUINT8):
- a = ASHRB;
- break;
-
- case CASE(ORSH, TUINT16):
- a = ASHRW;
- break;
-
- case CASE(ORSH, TUINT32):
- case CASE(ORSH, TPTR32):
- a = ASHRL;
- break;
-
- case CASE(ORSH, TINT8):
- a = ASARB;
- break;
-
- case CASE(ORSH, TINT16):
- a = ASARW;
- break;
-
- case CASE(ORSH, TINT32):
- a = ASARL;
- break;
-
- case CASE(OMUL, TINT8):
- case CASE(OMUL, TUINT8):
- a = AIMULB;
- break;
-
- case CASE(OMUL, TINT16):
- case CASE(OMUL, TUINT16):
- a = AIMULW;
- break;
-
- case CASE(OMUL, TINT32):
- case CASE(OMUL, TUINT32):
- case CASE(OMUL, TPTR32):
- a = AIMULL;
- break;
-
- case CASE(ODIV, TINT8):
- case CASE(OMOD, TINT8):
- a = AIDIVB;
- break;
-
- case CASE(ODIV, TUINT8):
- case CASE(OMOD, TUINT8):
- a = ADIVB;
- break;
-
- case CASE(ODIV, TINT16):
- case CASE(OMOD, TINT16):
- a = AIDIVW;
- break;
-
- case CASE(ODIV, TUINT16):
- case CASE(OMOD, TUINT16):
- a = ADIVW;
- break;
-
- case CASE(ODIV, TINT32):
- case CASE(OMOD, TINT32):
- a = AIDIVL;
- break;
-
- case CASE(ODIV, TUINT32):
- case CASE(ODIV, TPTR32):
- case CASE(OMOD, TUINT32):
- case CASE(OMOD, TPTR32):
- a = ADIVL;
- break;
-
- case CASE(OEXTEND, TINT16):
- a = ACWD;
- break;
-
- case CASE(OEXTEND, TINT32):
- a = ACDQ;
- break;
- }
- return a;
-}
-
-#define FCASE(a, b, c) (((a)<<16)|((b)<<8)|(c))
-int
-foptoas(int op, Type *t, int flg)
-{
- int et;
-
- et = simtype[t->etype];
-
- // If we need Fpop, it means we're working on
- // two different floating-point registers, not memory.
- // There the instruction only has a float64 form.
- if(flg & Fpop)
- et = TFLOAT64;
-
- // clear Frev if unneeded
- switch(op) {
- case OADD:
- case OMUL:
- flg &= ~Frev;
- break;
- }
-
- switch(FCASE(op, et, flg)) {
- case FCASE(OADD, TFLOAT32, 0):
- return AFADDF;
- case FCASE(OADD, TFLOAT64, 0):
- return AFADDD;
- case FCASE(OADD, TFLOAT64, Fpop):
- return AFADDDP;
-
- case FCASE(OSUB, TFLOAT32, 0):
- return AFSUBF;
- case FCASE(OSUB, TFLOAT32, Frev):
- return AFSUBRF;
-
- case FCASE(OSUB, TFLOAT64, 0):
- return AFSUBD;
- case FCASE(OSUB, TFLOAT64, Frev):
- return AFSUBRD;
- case FCASE(OSUB, TFLOAT64, Fpop):
- return AFSUBDP;
- case FCASE(OSUB, TFLOAT64, Fpop|Frev):
- return AFSUBRDP;
-
- case FCASE(OMUL, TFLOAT32, 0):
- return AFMULF;
- case FCASE(OMUL, TFLOAT64, 0):
- return AFMULD;
- case FCASE(OMUL, TFLOAT64, Fpop):
- return AFMULDP;
-
- case FCASE(ODIV, TFLOAT32, 0):
- return AFDIVF;
- case FCASE(ODIV, TFLOAT32, Frev):
- return AFDIVRF;
-
- case FCASE(ODIV, TFLOAT64, 0):
- return AFDIVD;
- case FCASE(ODIV, TFLOAT64, Frev):
- return AFDIVRD;
- case FCASE(ODIV, TFLOAT64, Fpop):
- return AFDIVDP;
- case FCASE(ODIV, TFLOAT64, Fpop|Frev):
- return AFDIVRDP;
-
- case FCASE(OCMP, TFLOAT32, 0):
- return AFCOMF;
- case FCASE(OCMP, TFLOAT32, Fpop):
- return AFCOMFP;
- case FCASE(OCMP, TFLOAT64, 0):
- return AFCOMD;
- case FCASE(OCMP, TFLOAT64, Fpop):
- return AFCOMDP;
- case FCASE(OCMP, TFLOAT64, Fpop2):
- return AFCOMDPP;
-
- case FCASE(OMINUS, TFLOAT32, 0):
- return AFCHS;
- case FCASE(OMINUS, TFLOAT64, 0):
- return AFCHS;
- }
-
- fatal("foptoas %O %T %#x", op, t, flg);
- return 0;
-}
-
-static int resvd[] =
-{
-// D_DI, // for movstring
-// D_SI, // for movstring
-
- D_AX, // for divide
- D_CX, // for shift
- D_DX, // for divide
- D_SP, // for stack
-
- D_BL, // because D_BX can be allocated
- D_BH,
-};
-
-void
-ginit(void)
-{
- int i;
-
- for(i=0; i<nelem(reg); i++)
- reg[i] = 1;
- for(i=D_AL; i<=D_DI; i++)
- reg[i] = 0;
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i]]++;
-}
-
-ulong regpc[D_NONE];
-
-void
-gclean(void)
-{
- int i;
-
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i]]--;
-
- for(i=D_AL; i<=D_DI; i++)
- if(reg[i])
- yyerror("reg %R left allocated at %ux", i, regpc[i]);
-}
-
-int32
-anyregalloc(void)
-{
- int i, j;
-
- for(i=D_AL; i<=D_DI; 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;
-
- if(t == T)
- fatal("regalloc: t nil");
- et = simtype[t->etype];
-
- 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_AX && i <= D_DI)
- goto out;
- }
- for(i=D_AX; i<=D_DI; i++)
- if(reg[i] == 0)
- goto out;
-
- fprint(2, "registers allocated at\n");
- for(i=D_AX; i<=D_DI; i++)
- fprint(2, "\t%R\t%#ux\n", i, regpc[i]);
- yyerror("out of fixed registers");
- goto err;
-
- case TFLOAT32:
- case TFLOAT64:
- i = D_F0;
- goto out;
- }
- yyerror("regalloc: unknown type %T", t);
- i = 0;
-
-err:
- nodreg(n, t, 0);
- return;
-
-out:
- if (i == D_SP)
- print("alloc SP\n");
- if(reg[i] == 0) {
- regpc[i] = (ulong)__builtin_return_address(0);
- if(i == D_AX || i == D_CX || i == D_DX || i == D_SP) {
- dump("regalloc-o", o);
- fatal("regalloc %R", i);
- }
- }
- 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_SP)
- return;
- if(i < 0 || i >= sizeof(reg))
- fatal("regfree: reg out of range");
- if(reg[i] <= 0)
- fatal("regfree: reg not allocated");
- reg[i]--;
- if(reg[i] == 0 && (i == D_AX || i == D_CX || i == D_DX || i == D_SP))
- fatal("regfree %R", i);
-}
-
-/*
- * 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;
- Type *first;
- Iter savet;
-
- // entire argument struct, not just one arg
- switch(t->etype) {
- default:
- fatal("nodarg %T", t);
-
- case TSTRUCT:
- if(!t->funarg)
- fatal("nodarg: TSTRUCT but not 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;
- break;
-
- case TFIELD:
- 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;
- break;
- }
-
- switch(fp) {
- default:
- fatal("nodarg %T %d", t, fp);
-
- case 0: // output arg
- n->op = OINDREG;
- n->val.u.reg = D_SP;
- break;
-
- case 1: // input arg
- n->class = PPARAM;
- break;
- }
-
- n->typecheck = 1;
- return n;
-}
-
-/*
- * generate
- * as $c, reg
- */
-void
-gconreg(int as, vlong c, int reg)
-{
- Node n1, n2;
-
- nodconst(&n1, types[TINT64], c);
- nodreg(&n2, types[TINT64], reg);
- gins(as, &n1, &n2);
-}
-
-/*
- * swap node contents
- */
-void
-nswap(Node *a, Node *b)
-{
- Node t;
-
- t = *a;
- *a = *b;
- *b = t;
-}
-
-/*
- * return constant i node.
- * overwritten by next call, but useful in calls to gins.
- */
-Node*
-ncon(uint32 i)
-{
- static Node n;
-
- if(n.type == T)
- nodconst(&n, types[TUINT32], 0);
- mpmovecfix(n.val.u.xval, i);
- return &n;
-}
-
-/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
- switch(n->op) {
- case OLEN:
- case OCAP:
- case OINDREG:
- case ONAME:
- case OPARAM:
- return 1;
- }
- return 0;
-}
-
-Node sclean[10];
-int nsclean;
-
-/*
- * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves.
- */
-void
-split64(Node *n, Node *lo, Node *hi)
-{
- Node n1;
- int64 i;
-
- if(!is64(n->type))
- fatal("split64 %T", n->type);
-
- sclean[nsclean].op = OEMPTY;
- if(nsclean >= nelem(sclean))
- fatal("split64 clean");
- nsclean++;
- switch(n->op) {
- default:
- if(!dotaddable(n, &n1)) {
- igen(n, &n1, N);
- sclean[nsclean-1] = n1;
- }
- n = &n1;
- goto common;
- case ONAME:
- if(n->class == PPARAMREF) {
- cgen(n->heapaddr, &n1);
- sclean[nsclean-1] = n1;
- // fall through.
- n = &n1;
- }
- goto common;
- case OINDREG:
- common:
- *lo = *n;
- *hi = *n;
- lo->type = types[TUINT32];
- if(n->type->etype == TINT64)
- hi->type = types[TINT32];
- else
- hi->type = types[TUINT32];
- hi->xoffset += 4;
- break;
-
- case OLITERAL:
- convconst(&n1, n->type, &n->val);
- i = mpgetfix(n1.val.u.xval);
- nodconst(lo, types[TUINT32], (uint32)i);
- i >>= 32;
- if(n->type->etype == TINT64)
- nodconst(hi, types[TINT32], (int32)i);
- else
- nodconst(hi, types[TUINT32], (uint32)i);
- break;
- }
-}
-
-void
-splitclean(void)
-{
- if(nsclean <= 0)
- fatal("splitclean");
- nsclean--;
- if(sclean[nsclean].op != OEMPTY)
- regfree(&sclean[nsclean]);
-}
-
-/*
- * set up nodes representing fp constants
- */
-Node zerof;
-Node two64f;
-Node two63f;
-
-void
-bignodes(void)
-{
- static int did;
-
- if(did)
- return;
- did = 1;
-
- two64f = *ncon(0);
- two64f.type = types[TFLOAT64];
- two64f.val.ctype = CTFLT;
- two64f.val.u.fval = mal(sizeof *two64f.val.u.fval);
- mpmovecflt(two64f.val.u.fval, 18446744073709551616.);
-
- two63f = two64f;
- two63f.val.u.fval = mal(sizeof *two63f.val.u.fval);
- mpmovecflt(two63f.val.u.fval, 9223372036854775808.);
-
- zerof = two64f;
- zerof.val.u.fval = mal(sizeof *zerof.val.u.fval);
- mpmovecflt(zerof.val.u.fval, 0);
-}
-
-void
-memname(Node *n, Type *t)
-{
- tempname(n, t);
- strcpy(namebuf, n->sym->name);
- namebuf[0] = '.'; // keep optimizer from registerizing
- n->sym = lookup(namebuf);
-}
-
-void
-gmove(Node *f, Node *t)
-{
- int a, ft, tt;
- Type *cvt;
- Node r1, r2, t1, t2, flo, fhi, tlo, thi, con, f0, f1, ax, dx, cx;
- Prog *p1, *p2, *p3;
-
- if(debug['M'])
- print("gmove %N -> %N\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 integer memory operands;
- // except 64-bit, which always copies via registers anyway.
- if(isint[ft] && isint[tt] && !is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
- goto hard;
-
- // convert constant to desired type
- if(f->op == OLITERAL) {
- if(tt == TFLOAT32)
- convconst(&con, types[TFLOAT64], &f->val);
- else
- convconst(&con, t->type, &f->val);
- f = &con;
- ft = simsimtype(con.type);
-
- // some constants can't move directly to memory.
- if(ismem(t)) {
- // float constants come from memory.
- if(isfloat[tt])
- 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:
- goto fatal;
-
- /*
- * integer copy and truncate
- */
- case CASE(TINT8, TINT8): // same size
- case CASE(TINT8, TUINT8):
- case CASE(TUINT8, TINT8):
- case CASE(TUINT8, TUINT8):
- a = AMOVB;
- break;
-
- case CASE(TINT16, TINT8): // truncate
- case CASE(TUINT16, TINT8):
- case CASE(TINT32, TINT8):
- case CASE(TUINT32, TINT8):
- case CASE(TINT16, TUINT8):
- case CASE(TUINT16, TUINT8):
- case CASE(TINT32, TUINT8):
- case CASE(TUINT32, TUINT8):
- a = AMOVB;
- goto rsrc;
-
- case CASE(TINT64, TINT8): // truncate low word
- case CASE(TUINT64, TINT8):
- case CASE(TINT64, TUINT8):
- case CASE(TUINT64, TUINT8):
- split64(f, &flo, &fhi);
- nodreg(&r1, t->type, D_AX);
- gmove(&flo, &r1);
- gins(AMOVB, &r1, t);
- splitclean();
- return;
-
- case CASE(TINT16, TINT16): // same size
- case CASE(TINT16, TUINT16):
- case CASE(TUINT16, TINT16):
- case CASE(TUINT16, TUINT16):
- a = AMOVW;
- break;
-
- case CASE(TINT32, TINT16): // truncate
- case CASE(TUINT32, TINT16):
- case CASE(TINT32, TUINT16):
- case CASE(TUINT32, TUINT16):
- a = AMOVW;
- goto rsrc;
-
- case CASE(TINT64, TINT16): // truncate low word
- case CASE(TUINT64, TINT16):
- case CASE(TINT64, TUINT16):
- case CASE(TUINT64, TUINT16):
- split64(f, &flo, &fhi);
- nodreg(&r1, t->type, D_AX);
- gmove(&flo, &r1);
- gins(AMOVW, &r1, t);
- splitclean();
- return;
-
- case CASE(TINT32, TINT32): // same size
- case CASE(TINT32, TUINT32):
- case CASE(TUINT32, TINT32):
- case CASE(TUINT32, TUINT32):
- a = AMOVL;
- break;
-
- case CASE(TINT64, TINT32): // truncate
- case CASE(TUINT64, TINT32):
- case CASE(TINT64, TUINT32):
- case CASE(TUINT64, TUINT32):
- split64(f, &flo, &fhi);
- nodreg(&r1, t->type, D_AX);
- gmove(&flo, &r1);
- gins(AMOVL, &r1, t);
- splitclean();
- return;
-
- case CASE(TINT64, TINT64): // same size
- case CASE(TINT64, TUINT64):
- case CASE(TUINT64, TINT64):
- case CASE(TUINT64, TUINT64):
- split64(f, &flo, &fhi);
- split64(t, &tlo, &thi);
- if(f->op == OLITERAL) {
- gins(AMOVL, &flo, &tlo);
- gins(AMOVL, &fhi, &thi);
- } else {
- nodreg(&r1, t->type, D_AX);
- nodreg(&r2, t->type, D_DX);
- gins(AMOVL, &flo, &r1);
- gins(AMOVL, &fhi, &r2);
- gins(AMOVL, &r1, &tlo);
- gins(AMOVL, &r2, &thi);
- }
- splitclean();
- splitclean();
- return;
-
- /*
- * integer up-conversions
- */
- case CASE(TINT8, TINT16): // sign extend int8
- case CASE(TINT8, TUINT16):
- a = AMOVBWSX;
- goto rdst;
- case CASE(TINT8, TINT32):
- case CASE(TINT8, TUINT32):
- a = AMOVBLSX;
- goto rdst;
- case CASE(TINT8, TINT64): // convert via int32
- case CASE(TINT8, TUINT64):
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT8, TINT16): // zero extend uint8
- case CASE(TUINT8, TUINT16):
- a = AMOVBWZX;
- goto rdst;
- case CASE(TUINT8, TINT32):
- case CASE(TUINT8, TUINT32):
- a = AMOVBLZX;
- goto rdst;
- case CASE(TUINT8, TINT64): // convert via uint32
- case CASE(TUINT8, TUINT64):
- cvt = types[TUINT32];
- goto hard;
-
- case CASE(TINT16, TINT32): // sign extend int16
- case CASE(TINT16, TUINT32):
- a = AMOVWLSX;
- goto rdst;
- case CASE(TINT16, TINT64): // convert via int32
- case CASE(TINT16, TUINT64):
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT16, TINT32): // zero extend uint16
- case CASE(TUINT16, TUINT32):
- a = AMOVWLZX;
- goto rdst;
- case CASE(TUINT16, TINT64): // convert via uint32
- case CASE(TUINT16, TUINT64):
- cvt = types[TUINT32];
- goto hard;
-
- case CASE(TINT32, TINT64): // sign extend int32
- case CASE(TINT32, TUINT64):
- split64(t, &tlo, &thi);
- nodreg(&flo, tlo.type, D_AX);
- nodreg(&fhi, thi.type, D_DX);
- gmove(f, &flo);
- gins(ACDQ, N, N);
- gins(AMOVL, &flo, &tlo);
- gins(AMOVL, &fhi, &thi);
- splitclean();
- return;
-
- case CASE(TUINT32, TINT64): // zero extend uint32
- case CASE(TUINT32, TUINT64):
- split64(t, &tlo, &thi);
- gmove(f, &tlo);
- gins(AMOVL, ncon(0), &thi);
- splitclean();
- return;
-
- /*
- * float to integer
- */
- case CASE(TFLOAT32, TINT16):
- case CASE(TFLOAT32, TINT32):
- case CASE(TFLOAT32, TINT64):
- case CASE(TFLOAT64, TINT16):
- case CASE(TFLOAT64, TINT32):
- case CASE(TFLOAT64, TINT64):
- if(t->op == OREGISTER)
- goto hardmem;
- nodreg(&r1, types[ft], D_F0);
- if(f->op != OREGISTER) {
- if(ft == TFLOAT32)
- gins(AFMOVF, f, &r1);
- else
- gins(AFMOVD, f, &r1);
- }
-
- // set round to zero mode during conversion
- memname(&t1, types[TUINT16]);
- memname(&t2, types[TUINT16]);
- gins(AFSTCW, N, &t1);
- gins(AMOVW, ncon(0xf7f), &t2);
- gins(AFLDCW, &t2, N);
- if(tt == TINT16)
- gins(AFMOVWP, &r1, t);
- else if(tt == TINT32)
- gins(AFMOVLP, &r1, t);
- else
- gins(AFMOVVP, &r1, t);
- gins(AFLDCW, &t1, N);
- return;
-
- case CASE(TFLOAT32, TINT8):
- case CASE(TFLOAT32, TUINT16):
- case CASE(TFLOAT32, TUINT8):
- case CASE(TFLOAT64, TINT8):
- case CASE(TFLOAT64, TUINT16):
- case CASE(TFLOAT64, TUINT8):
- // convert via int32.
- tempname(&t1, types[TINT32]);
- gmove(f, &t1);
- switch(tt) {
- default:
- fatal("gmove %T", t);
- case TINT8:
- gins(ACMPL, &t1, ncon(-0x80));
- p1 = gbranch(optoas(OLT, types[TINT32]), T);
- gins(ACMPL, &t1, ncon(0x7f));
- p2 = gbranch(optoas(OGT, types[TINT32]), T);
- p3 = gbranch(AJMP, T);
- patch(p1, pc);
- patch(p2, pc);
- gmove(ncon(-0x80), &t1);
- patch(p3, pc);
- gmove(&t1, t);
- break;
- case TUINT8:
- gins(ATESTL, ncon(0xffffff00), &t1);
- p1 = gbranch(AJEQ, T);
- gins(AMOVL, ncon(0), &t1);
- patch(p1, pc);
- gmove(&t1, t);
- break;
- case TUINT16:
- gins(ATESTL, ncon(0xffff0000), &t1);
- p1 = gbranch(AJEQ, T);
- gins(AMOVL, ncon(0), &t1);
- patch(p1, pc);
- gmove(&t1, t);
- break;
- }
- return;
-
- case CASE(TFLOAT32, TUINT32):
- case CASE(TFLOAT64, TUINT32):
- // convert via int64.
- tempname(&t1, types[TINT64]);
- gmove(f, &t1);
- split64(&t1, &tlo, &thi);
- gins(ACMPL, &thi, ncon(0));
- p1 = gbranch(AJEQ, T);
- gins(AMOVL, ncon(0), &tlo);
- patch(p1, pc);
- gmove(&tlo, t);
- splitclean();
- return;
-
- case CASE(TFLOAT32, TUINT64):
- case CASE(TFLOAT64, TUINT64):
- bignodes();
- nodreg(&f0, types[ft], D_F0);
- nodreg(&f1, types[ft], D_F0 + 1);
- nodreg(&ax, types[TUINT16], D_AX);
-
- gmove(f, &f0);
-
- // if 0 > v { answer = 0 }
- gmove(&zerof, &f0);
- gins(AFUCOMIP, &f0, &f1);
- p1 = gbranch(optoas(OGT, types[tt]), T);
- // if 1<<64 <= v { answer = 0 too }
- gmove(&two64f, &f0);
- gins(AFUCOMIP, &f0, &f1);
- p2 = gbranch(optoas(OGT, types[tt]), T);
- patch(p1, pc);
- gins(AFMOVVP, &f0, t); // don't care about t, but will pop the stack
- split64(t, &tlo, &thi);
- gins(AMOVL, ncon(0), &tlo);
- gins(AMOVL, ncon(0), &thi);
- splitclean();
- p1 = gbranch(AJMP, T);
- patch(p2, pc);
-
- // in range; algorithm is:
- // if small enough, use native float64 -> int64 conversion.
- // otherwise, subtract 2^63, convert, and add it back.
-
- // set round to zero mode during conversion
- memname(&t1, types[TUINT16]);
- memname(&t2, types[TUINT16]);
- gins(AFSTCW, N, &t1);
- gins(AMOVW, ncon(0xf7f), &t2);
- gins(AFLDCW, &t2, N);
-
- // actual work
- gmove(&two63f, &f0);
- gins(AFUCOMIP, &f0, &f1);
- p2 = gbranch(optoas(OLE, types[tt]), T);
- gins(AFMOVVP, &f0, t);
- p3 = gbranch(AJMP, T);
- patch(p2, pc);
- gmove(&two63f, &f0);
- gins(AFSUBDP, &f0, &f1);
- gins(AFMOVVP, &f0, t);
- split64(t, &tlo, &thi);
- gins(AXORL, ncon(0x80000000), &thi); // + 2^63
- patch(p3, pc);
- splitclean();
- // restore rounding mode
- gins(AFLDCW, &t1, N);
-
- patch(p1, pc);
- return;
-
- /*
- * integer to float
- */
- case CASE(TINT16, TFLOAT32):
- case CASE(TINT16, TFLOAT64):
- case CASE(TINT32, TFLOAT32):
- case CASE(TINT32, TFLOAT64):
- case CASE(TINT64, TFLOAT32):
- case CASE(TINT64, TFLOAT64):
- if(t->op != OREGISTER)
- goto hard;
- if(f->op == OREGISTER) {
- cvt = f->type;
- goto hardmem;
- }
- switch(ft) {
- case TINT16:
- a = AFMOVW;
- break;
- case TINT32:
- a = AFMOVL;
- break;
- default:
- a = AFMOVV;
- break;
- }
- break;
-
- case CASE(TINT8, TFLOAT32):
- case CASE(TINT8, TFLOAT64):
- case CASE(TUINT16, TFLOAT32):
- case CASE(TUINT16, TFLOAT64):
- case CASE(TUINT8, TFLOAT32):
- case CASE(TUINT8, TFLOAT64):
- // convert via int32 memory
- cvt = types[TINT32];
- goto hardmem;
-
- case CASE(TUINT32, TFLOAT32):
- case CASE(TUINT32, TFLOAT64):
- // convert via int64 memory
- cvt = types[TINT64];
- goto hardmem;
-
- case CASE(TUINT64, TFLOAT32):
- case CASE(TUINT64, TFLOAT64):
- // algorithm is:
- // if small enough, use native int64 -> uint64 conversion.
- // otherwise, halve (rounding to odd?), convert, and double.
- nodreg(&ax, types[TUINT32], D_AX);
- nodreg(&dx, types[TUINT32], D_DX);
- nodreg(&cx, types[TUINT32], D_CX);
- tempname(&t1, f->type);
- split64(&t1, &tlo, &thi);
- gmove(f, &t1);
- gins(ACMPL, &thi, ncon(0));
- p1 = gbranch(AJLT, T);
- // native
- t1.type = types[TINT64];
- gmove(&t1, t);
- p2 = gbranch(AJMP, T);
- // simulated
- patch(p1, pc);
- gmove(&tlo, &ax);
- gmove(&thi, &dx);
- p1 = gins(ASHRL, ncon(1), &ax);
- p1->from.index = D_DX; // double-width shift DX -> AX
- p1->from.scale = 0;
- gins(ASETCC, N, &cx);
- gins(AORB, &cx, &ax);
- gins(ASHRL, ncon(1), &dx);
- gmove(&dx, &thi);
- gmove(&ax, &tlo);
- nodreg(&r1, types[tt], D_F0);
- nodreg(&r2, types[tt], D_F0 + 1);
- gmove(&t1, &r1); // t1.type is TINT64 now, set above
- gins(AFMOVD, &r1, &r1);
- gins(AFADDDP, &r1, &r2);
- gmove(&r1, t);
- patch(p2, pc);
- splitclean();
- return;
-
- /*
- * float to float
- */
- case CASE(TFLOAT32, TFLOAT32):
- case CASE(TFLOAT64, TFLOAT64):
- // The way the code generator uses floating-point
- // registers, a move from F0 to F0 is intended as a no-op.
- // On the x86, it's not: it pushes a second copy of F0
- // on the floating point stack. So toss it away here.
- // Also, F0 is the *only* register we ever evaluate
- // into, so we should only see register/register as F0/F0.
- if(ismem(f) && ismem(t))
- goto hard;
- if(f->op == OREGISTER && t->op == OREGISTER) {
- if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
- goto fatal;
- return;
- }
- a = AFMOVF;
- if(ft == TFLOAT64)
- a = AFMOVD;
- if(ismem(t)) {
- if(f->op != OREGISTER || f->val.u.reg != D_F0)
- fatal("gmove %N", f);
- a = AFMOVFP;
- if(ft == TFLOAT64)
- a = AFMOVDP;
- }
- break;
-
- case CASE(TFLOAT32, TFLOAT64):
- if(ismem(f) && ismem(t))
- goto hard;
- if(f->op == OREGISTER && t->op == OREGISTER) {
- if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
- goto fatal;
- return;
- }
- if(f->op == OREGISTER)
- gins(AFMOVDP, f, t);
- else
- gins(AFMOVF, f, t);
- return;
-
- case CASE(TFLOAT64, TFLOAT32):
- if(ismem(f) && ismem(t))
- goto hard;
- if(f->op == OREGISTER && t->op == OREGISTER) {
- tempname(&r1, types[TFLOAT32]);
- gins(AFMOVFP, f, &r1);
- gins(AFMOVF, &r1, t);
- return;
- }
- if(f->op == OREGISTER)
- gins(AFMOVFP, f, t);
- else
- gins(AFMOVD, f, t);
- return;
- }
-
- gins(a, f, t);
- return;
-
-rsrc:
- // requires register source
- regalloc(&r1, f->type, t);
- gmove(f, &r1);
- gins(a, &r1, t);
- regfree(&r1);
- 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;
-
-hardmem:
- // requires memory intermediate
- tempname(&r1, cvt);
- gmove(f, &r1);
- gmove(&r1, t);
- return;
-
-fatal:
- // should not happen
- fatal("gmove %N -> %N", f, t);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
- if(f->op != t->op)
- return 0;
-
- switch(f->op) {
- case OREGISTER:
- if(f->val.u.reg != t->val.u.reg)
- break;
- return 1;
- }
- return 0;
-}
-/*
- * generate one instruction:
- * as f, t
- */
-Prog*
-gins(int as, Node *f, Node *t)
-{
- Prog *p;
- Addr af, at;
- int w;
-
- if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER)
- fatal("gins MOVF reg, reg");
-
- switch(as) {
- case AMOVB:
- case AMOVW:
- case AMOVL:
- if(f != N && t != N && samaddr(f, t))
- return nil;
- }
-
- 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(debug['g'])
- print("%P\n", p);
-
- w = 0;
- switch(as) {
- case AMOVB:
- w = 1;
- break;
- case AMOVW:
- w = 2;
- break;
- case AMOVL:
- w = 4;
- break;
- }
-
- if(1 && w != 0 && f != N && (af.width > w || at.width > w)) {
- dump("bad width from:", f);
- dump("bad width to:", t);
- fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
- }
-
- return p;
-}
-
-static void
-checkoffset(Addr *a, int canemitcode)
-{
- Prog *p;
-
- if(a->offset < unmappedzero)
- return;
- if(!canemitcode)
- fatal("checkoffset %#x, cannot emit code", a->offset);
-
- // cannot rely on unmapped nil page at 0 to catch
- // reference with large offset. instead, emit explicit
- // test of 0(reg).
- p = gins(ATESTB, nodintconst(0), N);
- p->to = *a;
- p->to.offset = 0;
-}
-
-/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
- a->scale = 0;
- a->index = D_NONE;
- a->type = D_NONE;
- a->gotype = S;
- a->node = N;
- if(n == N)
- return;
-
- switch(n->op) {
- default:
- fatal("naddr: bad %O %D", n->op, a);
- break;
-
- case OREGISTER:
- a->type = n->val.u.reg;
- a->sym = S;
- break;
-
- case OINDREG:
- a->type = n->val.u.reg+D_INDIR;
- a->sym = n->sym;
- a->offset = n->xoffset;
- break;
-
- case OPARAM:
- // n->left is PHEAP ONAME for stack parameter.
- // compute address of actual parameter on stack.
- a->etype = n->left->type->etype;
- a->width = n->left->type->width;
- a->offset = n->xoffset;
- a->sym = n->left->sym;
- a->type = D_PARAM;
- break;
-
- case ONAME:
- a->etype = 0;
- a->width = 0;
- if(n->type != T) {
- a->etype = simtype[n->type->etype];
- a->width = n->type->width;
- a->gotype = ngotype(n);
- }
- a->pun = n->pun;
- a->offset = n->xoffset;
- a->sym = n->sym;
- if(a->sym == S)
- a->sym = lookup(".noname");
- if(n->method) {
- if(n->type != T)
- if(n->type->sym != S)
- if(n->type->sym->pkg != nil)
- a->sym = pkglookup(a->sym->name, n->type->sym->pkg);
- }
-
- switch(n->class) {
- default:
- fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
- case PEXTERN:
- a->type = D_EXTERN;
- break;
- case PAUTO:
- a->type = D_AUTO;
- if (n->sym)
- a->node = n->orig;
- break;
- case PPARAM:
- case PPARAMOUT:
- a->type = D_PARAM;
- break;
- case PFUNC:
- a->index = D_EXTERN;
- a->type = D_ADDR;
- break;
- }
- break;
-
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- fatal("naddr: const %lT", n->type);
- break;
- case CTFLT:
- a->type = D_FCONST;
- a->dval = mpgetflt(n->val.u.fval);
- break;
- case CTINT:
- a->sym = S;
- 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 = S;
- a->type = D_CONST;
- a->offset = n->val.u.bval;
- break;
- case CTNIL:
- a->sym = S;
- a->type = D_CONST;
- a->offset = 0;
- break;
- }
- break;
-
- case OADDR:
- naddr(n->left, a, canemitcode);
- if(a->type >= D_INDIR) {
- a->type -= D_INDIR;
- break;
- }
- if(a->type == D_EXTERN || a->type == D_STATIC ||
- a->type == D_AUTO || a->type == D_PARAM)
- if(a->index == D_NONE) {
- a->index = a->type;
- a->type = D_ADDR;
- break;
- }
- fatal("naddr: OADDR\n");
-
- case OLEN:
- // len of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == D_CONST && a->offset == 0)
- break; // len(nil)
- a->etype = TUINT32;
- a->offset += Array_nel;
- a->width = 4;
- if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
- checkoffset(a, canemitcode);
- break;
-
- case OCAP:
- // cap of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == D_CONST && a->offset == 0)
- break; // cap(nil)
- a->etype = TUINT32;
- a->offset += Array_cap;
- a->width = 4;
- if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
- checkoffset(a, canemitcode);
- break;
-
-// case OADD:
-// if(n->right->op == OLITERAL) {
-// v = n->right->vconst;
-// naddr(n->left, a, canemitcode);
-// } else
-// if(n->left->op == OLITERAL) {
-// v = n->left->vconst;
-// naddr(n->right, a, canemitcode);
-// } else
-// goto bad;
-// a->offset += v;
-// break;
-
- }
-}
-
-int
-dotaddable(Node *n, Node *n1)
-{
- int o, oary[10];
- Node *nn;
-
- if(n->op != ODOT)
- return 0;
-
- o = dotoffset(n, oary, &nn);
- if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
- *n1 = *nn;
- n1->type = n->type;
- n1->xoffset += oary[0];
- return 1;
- }
- return 0;
-}
-
-void
-sudoclean(void)
-{
-}
-
-int
-sudoaddable(int as, Node *n, Addr *a)
-{
- return 0;
-}
diff --git a/src/cmd/8g/list.c b/src/cmd/8g/list.c
deleted file mode 100644
index edb1ece84..000000000
--- a/src/cmd/8g/list.c
+++ /dev/null
@@ -1,302 +0,0 @@
-// Derived from 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.
-
-#include "gg.h"
-
-static int sconsize;
-void
-listinit(void)
-{
-
- fmtinstall('A', Aconv); // as
- fmtinstall('P', Pconv); // Prog*
- fmtinstall('D', Dconv); // Addr*
- fmtinstall('R', Rconv); // reg
- fmtinstall('Y', Yconv); // sconst
-}
-
-int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Prog *p;
- char scale[40];
-
- p = va_arg(fp->args, Prog*);
- sconsize = 8;
- scale[0] = '\0';
- if(p->from.scale != 0 && (p->as == AGLOBL || p->as == ATEXT))
- snprint(scale, sizeof scale, "%d,", p->from.scale);
- switch(p->as) {
- default:
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%D",
- p->loc, p->lineno, p->as, &p->from, scale, &p->to);
- break;
-
- case ADATA:
- sconsize = p->from.scale;
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
- p->loc, p->lineno, p->as, &p->from, sconsize, &p->to);
- break;
-
- case ATEXT:
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%lD",
- p->loc, p->lineno, p->as, &p->from, scale, &p->to);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Addr *a;
- int i;
- uint32 d1, d2;
-
- a = va_arg(fp->args, Addr*);
- i = a->type;
- if(i >= D_INDIR) {
- if(a->offset)
- snprint(str, sizeof(str), "%d(%R)", a->offset, i-D_INDIR);
- else
- snprint(str, sizeof(str), "(%R)", i-D_INDIR);
- goto brk;
- }
- switch(i) {
-
- default:
- if(a->offset)
- snprint(str, sizeof(str), "$%d,%R", a->offset, i);
- else
- snprint(str, sizeof(str), "%R", i);
- break;
-
- case D_NONE:
- str[0] = 0;
- break;
-
- case D_BRANCH:
- snprint(str, sizeof(str), "%d", a->branch->loc);
- break;
-
- case D_EXTERN:
- snprint(str, sizeof(str), "%S+%d(SB)", a->sym, a->offset);
- break;
-
- case D_STATIC:
- snprint(str, sizeof(str), "%S<>+%d(SB)", a->sym, a->offset);
- break;
-
- case D_AUTO:
- snprint(str, sizeof(str), "%S+%d(SP)", a->sym, a->offset);
- break;
-
- case D_PARAM:
- snprint(str, sizeof(str), "%S+%d(FP)", a->sym, a->offset);
- break;
-
- case D_CONST:
- if(fp->flags & FmtLong) {
- d1 = a->offset;
- d2 = a->offset2;
- snprint(str, sizeof(str), "$%ud-%ud", (ulong)d1, (ulong)d2);
- break;
- }
- snprint(str, sizeof(str), "$%d", a->offset);
- break;
-
- case D_FCONST:
- snprint(str, sizeof(str), "$(%.17e)", a->dval);
- break;
-
- case D_SCONST:
- snprint(str, sizeof(str), "$\"%Y\"", a->sval);
- break;
-
- case D_ADDR:
- a->type = a->index;
- a->index = D_NONE;
- snprint(str, sizeof(str), "$%D", a);
- a->index = a->type;
- a->type = D_ADDR;
- goto conv;
- }
-brk:
- if(a->index != D_NONE) {
- snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale);
- strcat(str, s);
- }
-conv:
- return fmtstrcpy(fp, str);
-}
-
-static char* regstr[] =
-{
- "AL", /* [D_AL] */
- "CL",
- "DL",
- "BL",
-
- "AH", /* [D_AH] */
- "CH",
- "DH",
- "BH",
-
- "AX", /* [D_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
-
- "F0", /* [D_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "CS", /* [D_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
-
- "CR0", /* [D_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
-
- "DR0", /* [D_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [D_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "NONE", /* [D_NONE] */
-};
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) {
- snprint(str, sizeof(str), "BAD_R(%d)", r);
- return fmtstrcpy(fp, str);
- }
- return fmtstrcpy(fp, regstr[r]);
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-
-int
-Yconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sconsize; i++) {
- c = a[i] & 0xff;
- if((c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9')) {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- 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/cmd/8g/opt.h b/src/cmd/8g/opt.h
deleted file mode 100644
index 8f31dec3b..000000000
--- a/src/cmd/8g/opt.h
+++ /dev/null
@@ -1,164 +0,0 @@
-// 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.
-
-#define Z N
-#define Adr Addr
-
-#define D_HI D_NONE
-#define D_LO D_NONE
-
-#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
-#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
-#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
-#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;
-
-struct Reg
-{
-
- Bits set;
- Bits use1;
- Bits use2;
-
- Bits refbehind;
- Bits refahead;
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- int32 regu; // register used bitmap
- int32 rpo; // reverse post ordering
- int32 active;
-
- uint16 loop; // x5 for every loop
- uchar refset; // diagnostic generated
-
- 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 exregoffset; // not set
-EXTERN int32 exfregoffset; // not set
-EXTERN Reg* firstr;
-EXTERN Reg* lastr;
-EXTERN Reg zreg;
-EXTERN Reg* freer;
-EXTERN Reg** rpo2r;
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-EXTERN int32 regbits;
-EXTERN int32 exregbits;
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-EXTERN Bits ovar;
-EXTERN int change;
-EXTERN int32 maxnr;
-EXTERN int32* idom;
-
-EXTERN struct
-{
- int32 ncvtreg;
- int32 nspill;
- int32 nreload;
- int32 ndelmov;
- int32 nvar;
- int32 naddr;
-} ostats;
-
-/*
- * reg.c
- */
-Reg* rega(void);
-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 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(Adr*, int);
-void dumpone(Reg*);
-void dumpit(char*, Reg*);
-int noreturn(Prog *p);
-
-/*
- * peep.c
- */
-void peep(void);
-void excise(Reg*);
-Reg* uniqp(Reg*);
-Reg* uniqs(Reg*);
-int regtyp(Adr*);
-int anyvar(Adr*);
-int subprop(Reg*);
-int copyprop(Reg*);
-int copy1(Adr*, Adr*, Reg*, int);
-int copyu(Prog*, Adr*, Adr*);
-
-int copyas(Adr*, Adr*);
-int copyau(Adr*, Adr*);
-int copysub(Adr*, Adr*, Adr*, int);
-int copysub1(Prog*, Adr*, Adr*, int);
-
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
deleted file mode 100644
index 5ad29e1b2..000000000
--- a/src/cmd/8g/peep.c
+++ /dev/null
@@ -1,890 +0,0 @@
-// 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 "gg.h"
-#include "opt.h"
-
-#define REGEXT 0
-
-static void conprop(Reg *r);
-
-// do we need the carry bit
-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;
-}
-
-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;
- p->reg = r2;
-
- 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;
- }
- }
-
- // movb elimination.
- // movb is simulated by the linker
- // when a register other than ax, bx, cx, dx
- // is used, so rewrite to other instructions
- // when possible. a movb into a register
- // can smash the entire 32-bit register without
- // causing any trouble.
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- if(p->as == AMOVB && regtyp(&p->to)) {
- // movb into register.
- // from another register or constant can be movl.
- if(regtyp(&p->from) || p->from.type == D_CONST)
- p->as = AMOVL;
- else
- p->as = AMOVBLZX;
- }
- }
-
- // constant propagation
- // find MOV $con,R followed by
- // another MOV $con,R without
- // setting R in the interim
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case ALEAL:
- if(regtyp(&p->to))
- if(p->from.sym != S)
- conprop(r);
- break;
-
- case AMOVB:
- case AMOVW:
- case AMOVL:
- if(regtyp(&p->to))
- if(p->from.type == D_CONST)
- conprop(r);
- break;
- }
- }
-
-loop1:
- if(debug['P'] && debug['v'])
- dumpit("loop1", firstr);
-
- t = 0;
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AMOVB:
- case AMOVW:
- case AMOVL:
- 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 AADDB:
- 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;
- break;
- }
- if(p->from.offset == 1){
- if(p->as == AADDL)
- p->as = AINCL;
- else
- p->as = AINCW;
- p->from = zprog.from;
- break;
- }
- break;
-
- case ASUBB:
- 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;
- break;
- }
- if(p->from.offset == 1){
- if(p->as == ASUBL)
- p->as = ADECL;
- else
- p->as = ADECW;
- p->from = zprog.from;
- break;
- }
- break;
- }
- }
- if(t)
- goto loop1;
-}
-
-void
-excise(Reg *r)
-{
- Prog *p;
-
- p = r->prog;
- if(debug['P'] && debug['v'])
- print("%P ===delete===\n", p);
-
- p->as = ANOP;
- p->from = zprog.from;
- p->to = zprog.to;
-
- ostats.ndelmov++;
-}
-
-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(Adr *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;
- Adr *v1, *v2;
- Reg *r;
- int t;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case 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 ARCLB:
- case ARCLL:
- case ARCLW:
- case ARCRB:
- case ARCRL:
- case ARCRW:
- 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:
- return 0;
-
- case AMOVB:
- case AMOVW:
- 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;
- Adr *v1, *v2;
- Reg *r;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Adr *v1, Adr *v2, Reg *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, A);
- switch(t) {
- case 2: /* rar, cant split */
- if(debug['P'])
- print("; %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, Adr *v, Adr *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 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 AMOVB:
- case AMOVW:
- 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 ARCLB:
- case ARCLL:
- case ARCLW:
- case ARCRB:
- case ARCRL:
- case ARCRW:
- 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:
- if(copyas(&p->to, v))
- return 2;
- goto caseread;
-
- case ACMPL: /* read only */
- case ACMPW:
- case ACMPB:
- 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 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 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(REGEXT && v->type <= REGEXT && v->type > exregoffset)
- return 2;
- 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(Adr *a, Adr *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(Adr *a, Adr *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(Adr *a, Adr *v, Adr *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;
-}
-
-static void
-conprop(Reg *r0)
-{
- Reg *r;
- Prog *p, *p0;
- int t;
- Adr *v0;
-
- p0 = r0->prog;
- v0 = &p0->to;
- r = r0;
-
-loop:
- r = uniqs(r);
- if(r == R || r == r0)
- return;
- if(uniqp(r) == R)
- return;
-
- p = r->prog;
- t = copyu(p, v0, A);
- switch(t) {
- case 0: // miss
- case 1: // use
- goto loop;
-
- case 2: // rar
- case 4: // use and set
- break;
-
- case 3: // set
- if(p->as == p0->as)
- if(p->from.type == p0->from.type)
- if(p->from.sym == p0->from.sym)
- if(p->from.offset == p0->from.offset)
- if(p->from.scale == p0->from.scale)
- if(p->from.dval == p0->from.dval)
- if(p->from.index == p0->from.index) {
- excise(r);
- t++;
- goto loop;
- }
- break;
- }
-}
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
deleted file mode 100644
index a4828c3a3..000000000
--- a/src/cmd/8g/reg.c
+++ /dev/null
@@ -1,1546 +0,0 @@
-// 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 "gg.h"
-#undef EXTERN
-#define EXTERN
-#include "opt.h"
-
-#define NREGVAR 8
-#define REGBITS ((uint32)0xff)
-#define P2R(p) (Reg*)(p->reg)
-
-static int first = 1;
-
-Reg*
-rega(void)
-{
- Reg *r;
-
- r = freer;
- if(r == R) {
- r = mal(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;
-}
-
-static void
-setoutvar(void)
-{
- Type *t;
- Node *n;
- Addr a;
- Iter save;
- Bits bit;
- int z;
-
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- n = nodarg(t, 1);
- a = zprog.from;
- naddr(n, &a, 0);
- bit = mkvar(R, &a);
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
- t = structnext(&save);
- }
-//if(bany(b))
-//print("ovars = %Q\n", &ovar);
-}
-
-static void
-setaddrs(Bits bit)
-{
- int i, n;
- Var *v;
- Sym *s;
-
- while(bany(&bit)) {
- // convert each bit to a variable
- i = bnum(bit);
- s = var[i].sym;
- n = var[i].name;
- bit.b[i/32] &= ~(1L<<(i%32));
-
- // disable all pieces of that variable
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->sym == s && v->name == n)
- v->addr = 2;
- }
- }
-}
-
-static char* regname[] = { ".ax", ".cx", ".dx", ".bx", ".sp", ".bp", ".si", ".di" };
-
-void
-regopt(Prog *firstp)
-{
- Reg *r, *r1;
- Prog *p;
- int i, z, nr;
- uint32 vreg;
- Bits bit;
-
- if(first) {
- fmtinstall('Q', Qconv);
- exregoffset = D_DI; // no externals
- first = 0;
- }
-
- // count instructions
- nr = 0;
- for(p=firstp; p!=P; p=p->link)
- nr++;
- // if too big dont bother
- if(nr >= 10000) {
-// print("********** %S is too big (%d)\n", curfn->nname->sym, nr);
- return;
- }
-
- r1 = R;
- firstr = R;
- lastr = R;
-
- /*
- * 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++)
- var[i].sym = lookup(regname[i]);
-
- regbits = RtoB(D_SP);
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- ovar.b[z] = 0;
- }
-
- // build list of return variables
- setoutvar();
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- nr = 0;
- for(p=firstp; p!=P; p=p->link) {
- switch(p->as) {
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- continue;
- }
- r = rega();
- nr++;
- if(firstr == R) {
- firstr = r;
- lastr = r;
- } else {
- lastr->link = r;
- r->p1 = lastr;
- lastr->s1 = r;
- lastr = r;
- }
- r->prog = p;
- p->reg = r;
-
- 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:
- setaddrs(bit);
- break;
-
- /*
- * left side read
- */
- default:
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
- break;
-
- /*
- * left side read+write
- */
- case AXCHGB:
- case AXCHGW:
- case AXCHGL:
- for(z=0; z<BITS; z++) {
- r->use1.b[z] |= bit.b[z];
- r->set.b[z] |= bit.b[z];
- }
- break;
- }
-
- bit = mkvar(r, &p->to);
- if(bany(&bit))
- switch(p->as) {
- default:
- yyerror("reg: unknown op: %A", p->as);
- break;
-
- /*
- * right side read
- */
- case ACMPB:
- case ACMPL:
- case ACMPW:
- case ATESTB:
- case ATESTL:
- case ATESTW:
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- break;
-
- /*
- * right side write
- */
- case AFSTSW:
- case ALEAL:
- case ANOP:
- case AMOVL:
- case AMOVB:
- case AMOVW:
- case AMOVBLSX:
- case AMOVBLZX:
- case AMOVBWSX:
- case AMOVBWZX:
- case AMOVWLSX:
- case AMOVWLZX:
- case APOPL:
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- break;
-
- /*
- * right side read+write
- */
- case AINCB:
- case AINCL:
- case AINCW:
- case ADECB:
- case ADECL:
- case ADECW:
-
- 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 ARCLB:
- case ARCLL:
- case ARCLW:
- case ARCRB:
- case ARCRL:
- case ARCRW:
- 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 ANEGB:
- case ANEGL:
- case ANEGW:
- case ANOTB:
- case ANOTL:
- case ANOTW:
- case AADCL:
- case ASBBL:
-
- case ASETCC:
- case ASETCS:
- case ASETEQ:
- case ASETGE:
- case ASETGT:
- case ASETHI:
- case ASETLE:
- case ASETLS:
- case ASETLT:
- case ASETMI:
- case ASETNE:
- case ASETOC:
- case ASETOS:
- case ASETPC:
- case ASETPL:
- case ASETPS:
-
- case AXCHGB:
- case AXCHGW:
- case AXCHGL:
- 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:
- setaddrs(bit);
- break;
- }
-
- switch(p->as) {
- case AIMULL:
- case AIMULW:
- if(p->to.type != D_NONE)
- break;
-
- case AIDIVL:
- case AIDIVW:
- case ADIVL:
- case ADIVW:
- case AMULL:
- case AMULW:
- r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
- r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DX);
- break;
-
- case AIDIVB:
- case AIMULB:
- case ADIVB:
- case AMULB:
- r->set.b[0] |= RtoB(D_AX);
- r->use1.b[0] |= RtoB(D_AX);
- break;
-
- case ACWD:
- r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
- r->use1.b[0] |= RtoB(D_AX);
- break;
-
- case ACDQ:
- r->set.b[0] |= RtoB(D_DX);
- r->use1.b[0] |= RtoB(D_AX);
- break;
-
- case AREP:
- case AREPN:
- case ALOOP:
- case ALOOPEQ:
- case ALOOPNE:
- r->set.b[0] |= RtoB(D_CX);
- r->use1.b[0] |= RtoB(D_CX);
- break;
-
- case AMOVSB:
- case AMOVSL:
- case AMOVSW:
- case ACMPSB:
- case ACMPSL:
- case ACMPSW:
- r->set.b[0] |= RtoB(D_SI) | RtoB(D_DI);
- r->use1.b[0] |= RtoB(D_SI) | RtoB(D_DI);
- break;
-
- case ASTOSB:
- case ASTOSL:
- case ASTOSW:
- case ASCASB:
- case ASCASL:
- case ASCASW:
- r->set.b[0] |= RtoB(D_DI);
- r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DI);
- break;
-
- case AINSB:
- case AINSL:
- case AINSW:
- r->set.b[0] |= RtoB(D_DX) | RtoB(D_DI);
- r->use1.b[0] |= RtoB(D_DI);
- break;
-
- case AOUTSB:
- case AOUTSL:
- case AOUTSW:
- r->set.b[0] |= RtoB(D_DI);
- r->use1.b[0] |= RtoB(D_DX) | RtoB(D_DI);
- break;
- }
- }
- if(firstr == R)
- return;
-
- 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];
- }
-
-// print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n",
-// i, v->addr, v->etype, v->width, v->sym, v->offset);
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass1", firstr);
-
- /*
- * 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) {
- if(p->to.branch == P)
- fatal("pnil %P", p);
- r1 = p->to.branch->reg;
- if(r1 == R)
- fatal("rnil %P", p);
- if(r1 == r) {
- //fatal("ref to self %P", p);
- continue;
- }
- r->s2 = r1;
- r->p2link = r1->p2;
- r1->p2 = r;
- }
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass2", firstr);
-
- /*
- * pass 2.5
- * find looping structure
- */
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- change = 0;
- loopit(firstr, nr);
-
- if(debug['R'] && debug['v'])
- dumpit("pass2.5", firstr);
-
- /*
- * 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;
-
- if(debug['R'] && debug['v'])
- dumpit("pass3", firstr);
-
- /*
- * 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;
-
- if(debug['R'] && debug['v'])
- dumpit("pass4", firstr);
-
- /*
- * pass 4.5
- * move register pseudo-variables into regu.
- */
- for(r = firstr; r != R; r = r->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;
- }
-
- /*
- * 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->refset) {
- // should never happen - all variables are preset
- if(debug['w'])
- print("%L: used and not set: %Q\n", r->prog->lineno, bit);
- r->refset = 1;
- }
- }
- 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) && !r->refset) {
- if(debug['w'])
- print("%L: set and not used: %Q\n", r->prog->lineno, bit);
- r->refset = 1;
- 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;
- paint1(r, i);
- bit.b[i/32] &= ~(1L<<(i%32));
- 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);
-
- /*
- * 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(rgp->regno != 0)
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- rgp++;
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass6", firstr);
-
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P']) {
- peep();
- }
-
- /*
- * eliminate nops
- * free aux structures
- */
- 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.branch != P && p->to.branch->as == ANOP)
- p->to.branch = p->to.branch->link;
- }
-
- if(r1 != R) {
- r1->link = freer;
- freer = firstr;
- }
-
- if(debug['R']) {
- if(ostats.ncvtreg ||
- ostats.nspill ||
- ostats.nreload ||
- ostats.ndelmov ||
- ostats.nvar ||
- ostats.naddr ||
- 0)
- print("\nstats\n");
-
- if(ostats.ncvtreg)
- print(" %4d cvtreg\n", ostats.ncvtreg);
- if(ostats.nspill)
- print(" %4d spill\n", ostats.nspill);
- if(ostats.nreload)
- print(" %4d reload\n", ostats.nreload);
- if(ostats.ndelmov)
- print(" %4d delmov\n", ostats.ndelmov);
- if(ostats.nvar)
- print(" %4d delmov\n", ostats.nvar);
- if(ostats.naddr)
- print(" %4d delmov\n", ostats.naddr);
-
- memset(&ostats, 0, sizeof(ostats));
- }
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Adr *a;
- Var *v;
-
- p1 = mal(sizeof(*p1));
- clearp(p1);
- p1->loc = 9999;
-
- 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;
- a->gotype = v->gotype;
- a->node = v->node;
-
- // need to clean this up with wptr and
- // some of the defaults
- p1->as = AMOVL;
- switch(v->etype) {
- default:
- fatal("unknown type\n");
- case TINT8:
- case TUINT8:
- case TBOOL:
- p1->as = AMOVB;
- break;
- case TINT16:
- case TUINT16:
- p1->as = AMOVW;
- break;
- case TINT:
- case TUINT:
- case TINT32:
- case TUINT32:
- case TPTR32:
- break;
- }
-
- p1->from.type = rn;
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = rn;
- if(v->etype == TUINT8)
- p1->as = AMOVB;
- if(v->etype == TUINT16)
- p1->as = AMOVW;
- }
- if(debug['R'] && debug['v'])
- print("%P ===add=== %P\n", p, p1);
- ostats.nspill++;
-}
-
-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;
-}
-
-static int
-overlap(int32 o1, int w1, int32 o2, int w2)
-{
- int32 t1, t2;
-
- t1 = o1+w1;
- t2 = o2+w2;
-
- if(!(t1 > o2 && t2 > o1))
- return 0;
-
- return 1;
-}
-
-Bits
-mkvar(Reg *r, Adr *a)
-{
- Var *v;
- int i, t, n, et, z, w, flag, regu;
- int32 o;
- Bits bit;
- Sym *s;
-
- /*
- * mark registers used
- */
- t = a->type;
- if(t == D_NONE)
- goto none;
-
- if(r != R)
- r->use1.b[0] |= doregbits(a->index);
-
- switch(t) {
- default:
- regu = doregbits(t);
- if(regu == 0)
- goto none;
- bit = zbits;
- bit.b[0] = regu;
- return bit;
-
- case D_ADDR:
- a->type = a->index;
- bit = mkvar(r, a);
- setaddrs(bit);
- a->type = t;
- ostats.naddr++;
- goto none;
-
- case D_EXTERN:
- case D_STATIC:
- case D_PARAM:
- case D_AUTO:
- n = t;
- break;
- }
-
- s = a->sym;
- if(s == S)
- goto none;
- if(s->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- w = a->width;
-
- flag = 0;
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->sym == s && v->name == n) {
- if(v->offset == o)
- if(v->etype == et)
- if(v->width == w)
- return blsh(i);
-
- // if they overlaps, disable both
- if(overlap(v->offset, v->width, o, w)) {
- if(debug['R'])
- print("disable %s\n", v->sym->name);
- v->addr = 1;
- flag = 1;
- }
- }
- }
- if(a->pun)
- flag = 1;
-
- switch(et) {
- case 0:
- case TFUNC:
- goto none;
- }
-
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
- fatal("variable not optimized: %D", a);
- goto none;
- }
-
- i = nvar;
- nvar++;
- v = var+i;
- v->sym = s;
- v->offset = o;
- v->name = n;
- v->gotype = a->gotype;
- v->etype = et;
- v->width = w;
- v->addr = flag; // funny punning
- v->node = a->node;
-
- if(debug['R'])
- print("bit=%2d et=%2d w=%d %S %D flag=%d\n", i, et, w, s, a, v->addr);
- ostats.nvar++;
-
- 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];
-
- 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:
- if(noreturn(r1->prog))
- break;
- 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] | 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->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("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 = mal(nr * sizeof(Reg*));
- idom = mal(nr * sizeof(int32));
- maxnr = nr;
- }
-
- d = postorder(r, rpo2r, 0);
- if(d > nr)
- fatal("too many reg nodes %d %d", d, nr);
- 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:
- 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 TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TPTR32:
- i = BtoR(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TFLOAT32:
- case TFLOAT64:
- 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;
- }
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- change += CREF * r->loop;
- if(p->as == AFMOVL || p->as == AFMOVW)
- if(BtoR(bb) != D_F0)
- change = -CINF;
- }
-
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->loop;
- if(p->as == AFMOVL || p->as == AFMOVW)
- if(BtoR(bb) != D_F0)
- change = -CINF;
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->loop;
- if(p->as == AFMOVL || p->as == AFMOVW)
- if(BtoR(bb) != D_F0)
- change = -CINF;
- }
-
- 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;
- Adr 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;
- Adr 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'] && 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 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Adr *a, int rn)
-{
-
- a->sym = 0;
- a->offset = 0;
- a->type = rn;
-
- ostats.ncvtreg++;
-}
-
-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;
-}
-
-void
-dumpone(Reg *r)
-{
- int z;
- Bits bit;
-
- print("%d:%P", r->loop, r->prog);
- 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, Reg *r0)
-{
- Reg *r, *r1;
-
- print("\n%s\n", str);
- for(r = r0; r != R; r = r->link) {
- dumpone(r);
- r1 = r->p2;
- if(r1 != R) {
- print(" pred:");
- for(; r1 != R; r1 = r1->p2link)
- print(" %.4ud", r1->prog->loc);
- print("\n");
- }
-// r1 = r->s1;
-// if(r1 != R) {
-// print(" succ:");
-// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", r1->prog->loc);
-// print("\n");
-// }
- }
-}
-
-static Sym* symlist[10];
-
-int
-noreturn(Prog *p)
-{
- Sym *s;
- int i;
-
- if(symlist[0] == S) {
- symlist[0] = pkglookup("panicindex", runtimepkg);
- symlist[1] = pkglookup("panicslice", runtimepkg);
- symlist[2] = pkglookup("throwinit", runtimepkg);
- symlist[3] = pkglookup("panic", runtimepkg);
- symlist[4] = pkglookup("panicwrap", runtimepkg);
- }
-
- s = p->to.sym;
- if(s == S)
- return 0;
- for(i=0; symlist[i]!=S; i++)
- if(s == symlist[i])
- return 1;
- return 0;
-}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
deleted file mode 100644
index 03db0016b..000000000
--- a/src/cmd/8l/8.out.h
+++ /dev/null
@@ -1,542 +0,0 @@
-// Inferno utils/8c/8.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/8.out.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.
-
-#define NSYM 50
-#define NSNAME 8
-#define NOPROF (1<<0)
-#define DUPOK (1<<1)
-#define NOSPLIT (1<<2)
-#define RODATA (1<<3)
-
-enum as
-{
- AXXX,
- AAAA,
- AAAD,
- AAAM,
- AAAS,
- AADCB,
- AADCL,
- AADCW,
- AADDB,
- AADDL,
- AADDW,
- AADJSP,
- AANDB,
- AANDL,
- AANDW,
- AARPL,
- ABOUNDL,
- ABOUNDW,
- ABSFL,
- ABSFW,
- ABSRL,
- ABSRW,
- ABTL,
- ABTW,
- ABTCL,
- ABTCW,
- ABTRL,
- ABTRW,
- ABTSL,
- ABTSW,
- ABYTE,
- ACALL,
- ACLC,
- ACLD,
- ACLI,
- ACLTS,
- ACMC,
- ACMPB,
- ACMPL,
- ACMPW,
- ACMPSB,
- ACMPSL,
- ACMPSW,
- ADAA,
- ADAS,
- ADATA,
- ADECB,
- ADECL,
- ADECW,
- ADIVB,
- ADIVL,
- ADIVW,
- AENTER,
- AGLOBL,
- AGOK,
- AHISTORY,
- AHLT,
- AIDIVB,
- AIDIVL,
- AIDIVW,
- AIMULB,
- AIMULL,
- AIMULW,
- AINB,
- AINL,
- AINW,
- AINCB,
- AINCL,
- AINCW,
- AINSB,
- AINSL,
- AINSW,
- AINT,
- AINTO,
- AIRETL,
- AIRETW,
- AJCC,
- AJCS,
- AJCXZ,
- AJEQ,
- AJGE,
- AJGT,
- AJHI,
- AJLE,
- AJLS,
- AJLT,
- AJMI,
- AJMP,
- AJNE,
- AJOC,
- AJOS,
- AJPC,
- AJPL,
- AJPS,
- ALAHF,
- ALARL,
- ALARW,
- ALEAL,
- ALEAW,
- ALEAVEL,
- ALEAVEW,
- ALOCK,
- ALODSB,
- ALODSL,
- ALODSW,
- ALONG,
- ALOOP,
- ALOOPEQ,
- ALOOPNE,
- ALSLL,
- ALSLW,
- AMOVB,
- AMOVL,
- AMOVW,
- AMOVBLSX,
- AMOVBLZX,
- AMOVBWSX,
- AMOVBWZX,
- AMOVWLSX,
- AMOVWLZX,
- AMOVSB,
- AMOVSL,
- AMOVSW,
- AMULB,
- AMULL,
- AMULW,
- ANAME,
- ANEGB,
- ANEGL,
- ANEGW,
- ANOP,
- ANOTB,
- ANOTL,
- ANOTW,
- AORB,
- AORL,
- AORW,
- AOUTB,
- AOUTL,
- AOUTW,
- AOUTSB,
- AOUTSL,
- AOUTSW,
- APOPAL,
- APOPAW,
- APOPFL,
- APOPFW,
- APOPL,
- APOPW,
- APUSHAL,
- APUSHAW,
- APUSHFL,
- APUSHFW,
- APUSHL,
- APUSHW,
- ARCLB,
- ARCLL,
- ARCLW,
- ARCRB,
- ARCRL,
- ARCRW,
- AREP,
- AREPN,
- ARET,
- AROLB,
- AROLL,
- AROLW,
- ARORB,
- ARORL,
- ARORW,
- ASAHF,
- ASALB,
- ASALL,
- ASALW,
- ASARB,
- ASARL,
- ASARW,
- ASBBB,
- ASBBL,
- ASBBW,
- ASCASB,
- ASCASL,
- ASCASW,
- ASETCC,
- ASETCS,
- ASETEQ,
- ASETGE,
- ASETGT,
- ASETHI,
- ASETLE,
- ASETLS,
- ASETLT,
- ASETMI,
- ASETNE,
- ASETOC,
- ASETOS,
- ASETPC,
- ASETPL,
- ASETPS,
- ACDQ,
- ACWD,
- ASHLB,
- ASHLL,
- ASHLW,
- ASHRB,
- ASHRL,
- ASHRW,
- ASTC,
- ASTD,
- ASTI,
- ASTOSB,
- ASTOSL,
- ASTOSW,
- ASUBB,
- ASUBL,
- ASUBW,
- ASYSCALL,
- ATESTB,
- ATESTL,
- ATESTW,
- ATEXT,
- AVERR,
- AVERW,
- AWAIT,
- AWORD,
- AXCHGB,
- AXCHGL,
- AXCHGW,
- AXLAT,
- AXORB,
- AXORL,
- AXORW,
-
- AFMOVB,
- AFMOVBP,
- AFMOVD,
- AFMOVDP,
- AFMOVF,
- AFMOVFP,
- AFMOVL,
- AFMOVLP,
- AFMOVV,
- AFMOVVP,
- AFMOVW,
- AFMOVWP,
- AFMOVX,
- AFMOVXP,
-
- AFCOMB,
- AFCOMBP,
- AFCOMD,
- AFCOMDP,
- AFCOMDPP,
- AFCOMF,
- AFCOMFP,
- AFCOMI,
- AFCOMIP,
- AFCOML,
- AFCOMLP,
- AFCOMW,
- AFCOMWP,
- AFUCOM,
- AFUCOMI,
- AFUCOMIP,
- AFUCOMP,
- AFUCOMPP,
-
- AFADDDP,
- AFADDW,
- AFADDL,
- AFADDF,
- AFADDD,
-
- AFMULDP,
- AFMULW,
- AFMULL,
- AFMULF,
- AFMULD,
-
- AFSUBDP,
- AFSUBW,
- AFSUBL,
- AFSUBF,
- AFSUBD,
-
- AFSUBRDP,
- AFSUBRW,
- AFSUBRL,
- AFSUBRF,
- AFSUBRD,
-
- AFDIVDP,
- AFDIVW,
- AFDIVL,
- AFDIVF,
- AFDIVD,
-
- AFDIVRDP,
- AFDIVRW,
- AFDIVRL,
- AFDIVRF,
- AFDIVRD,
-
- AFXCHD,
- AFFREE,
-
- AFLDCW,
- AFLDENV,
- AFRSTOR,
- AFSAVE,
- AFSTCW,
- AFSTENV,
- AFSTSW,
-
- AF2XM1,
- AFABS,
- AFCHS,
- AFCLEX,
- AFCOS,
- AFDECSTP,
- AFINCSTP,
- AFINIT,
- AFLD1,
- AFLDL2E,
- AFLDL2T,
- AFLDLG2,
- AFLDLN2,
- AFLDPI,
- AFLDZ,
- AFNOP,
- AFPATAN,
- AFPREM,
- AFPREM1,
- AFPTAN,
- AFRNDINT,
- AFSCALE,
- AFSIN,
- AFSINCOS,
- AFSQRT,
- AFTST,
- AFXAM,
- AFXTRACT,
- AFYL2X,
- AFYL2XP1,
-
- AEND,
-
- ADYNT_,
- AINIT_,
-
- ASIGNAME,
-
- ACMPXCHGB,
- ACMPXCHGL,
- ACMPXCHGW,
- ACMPXCHG8B,
-
- AXADDB,
- AXADDL,
- AXADDW,
-
- /* conditional move */
- ACMOVLCC,
- ACMOVLCS,
- ACMOVLEQ,
- ACMOVLGE,
- ACMOVLGT,
- ACMOVLHI,
- ACMOVLLE,
- ACMOVLLS,
- ACMOVLLT,
- ACMOVLMI,
- ACMOVLNE,
- ACMOVLOC,
- ACMOVLOS,
- ACMOVLPC,
- ACMOVLPL,
- ACMOVLPS,
- ACMOVWCC,
- ACMOVWCS,
- ACMOVWEQ,
- ACMOVWGE,
- ACMOVWGT,
- ACMOVWHI,
- ACMOVWLE,
- ACMOVWLS,
- ACMOVWLT,
- ACMOVWMI,
- ACMOVWNE,
- ACMOVWOC,
- ACMOVWOS,
- ACMOVWPC,
- ACMOVWPL,
- ACMOVWPS,
-
- AFCMOVCC,
- AFCMOVCS,
- AFCMOVEQ,
- AFCMOVHI,
- AFCMOVLS,
- AFCMOVNE,
- AFCMOVNU,
- AFCMOVUN,
-
- ALAST
-};
-
-enum
-{
- D_AL = 0,
- D_CL,
- D_DL,
- D_BL,
-
- D_AH = 4,
- D_CH,
- D_DH,
- D_BH,
-
- D_AX = 8,
- D_CX,
- D_DX,
- D_BX,
- D_SP,
- D_BP,
- D_SI,
- D_DI,
-
- D_F0 = 16,
- D_F7 = D_F0 + 7,
-
- D_CS = 24,
- D_SS,
- D_DS,
- D_ES,
- D_FS,
- D_GS,
-
- D_GDTR, /* global descriptor table register */
- D_IDTR, /* interrupt descriptor table register */
- D_LDTR, /* local descriptor table register */
- D_MSW, /* machine status word */
- D_TASK, /* task register */
-
- D_CR = 35,
- D_DR = 43,
- D_TR = 51,
-
- D_NONE = 59,
-
- D_BRANCH = 60,
- D_EXTERN = 61,
- D_STATIC = 62,
- D_AUTO = 63,
- D_PARAM = 64,
- D_CONST = 65,
- D_FCONST = 66,
- D_SCONST = 67,
- D_ADDR = 68,
-
- D_FILE,
- D_FILE1,
-
- D_INDIR, /* additive */
-
- D_CONST2 = D_INDIR+D_INDIR,
- D_SIZE, /* 8l internal */
- D_PCREL,
- D_GOTOFF,
- D_GOTREL,
-
- T_TYPE = 1<<0,
- T_INDEX = 1<<1,
- T_OFFSET = 1<<2,
- T_FCONST = 1<<3,
- T_SYM = 1<<4,
- T_SCONST = 1<<5,
- T_OFFSET2 = 1<<6,
- T_GOTYPE = 1<<7,
-
- REGARG = -1,
- REGRET = D_AX,
- FREGRET = D_F0,
- REGSP = D_SP,
- REGTMP = D_DI,
-};
-
-/*
- * this is the ranlib header
- */
-#define SYMDEF "__.SYMDEF"
-
-/*
- * this is the simulated IEEE floating point
- */
-typedef struct ieee Ieee;
-struct ieee
-{
- int32 l; /* contains ls-man 0xffffffff */
- int32 h; /* contains sign 0x80000000
- exp 0x7ff00000
- ms-man 0x000fffff */
-};
diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile
deleted file mode 100644
index a85e3ffa7..000000000
--- a/src/cmd/8l/Makefile
+++ /dev/null
@@ -1,49 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=8l
-
-OFILES=\
- asm.$O\
- data.$O\
- dwarf.$O\
- elf.$O\
- enam.$O\
- go.$O\
- ldelf.$O\
- ldmacho.$O\
- ldpe.$O\
- lib.$O\
- list.$O\
- macho.$O\
- obj.$O\
- optab.$O\
- pass.$O\
- pe.$O\
- prof.$O\
- span.$O\
- symtab.$O\
-
-
-HFILES=\
- l.h\
- ../8l/8.out.h\
- ../ld/dwarf.h\
- ../ld/elf.h\
- ../ld/macho.h\
- ../ld/pe.h\
-
-include ../../Make.ccmd
-
-enam.c: 8.out.h
- sh mkenam
-
-CLEANFILES+=enam.c
-
-
-%.$O: ../ld/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
deleted file mode 100644
index e1ccfb8a3..000000000
--- a/src/cmd/8l/asm.c
+++ /dev/null
@@ -1,1262 +0,0 @@
-// Inferno utils/8l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/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"
-#include "../ld/macho.h"
-#include "../ld/pe.h"
-
-#define Dbufslop 100
-
-char linuxdynld[] = "/lib/ld-linux.so.2";
-char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
-
-int32
-entryvalue(void)
-{
- char *a;
- Sym *s;
-
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return atolwhex(a);
- s = lookup(a, 0);
- if(s->type == 0)
- return INITTEXT;
- if(s->type != STEXT)
- diag("entry not text: %s", s->name);
- return s->value;
-}
-
-vlong
-datoff(vlong addr)
-{
- if(addr >= segdata.vaddr)
- return addr - segdata.vaddr + segdata.fileoff;
- if(addr >= segtext.vaddr)
- return addr - segtext.vaddr + segtext.fileoff;
- diag("datoff %#llx", addr);
- return 0;
-}
-
-enum {
- ElfStrEmpty,
- ElfStrInterp,
- ElfStrHash,
- ElfStrGot,
- ElfStrGotPlt,
- ElfStrDynamic,
- ElfStrDynsym,
- ElfStrDynstr,
- ElfStrRel,
- ElfStrText,
- ElfStrData,
- ElfStrBss,
- ElfStrShstrtab,
- ElfStrSymtab,
- ElfStrStrtab,
- ElfStrRelPlt,
- ElfStrPlt,
- ElfStrGnuVersion,
- ElfStrGnuVersionR,
- NElfStr
-};
-
-vlong elfstr[NElfStr];
-
-static int
-needlib(char *name)
-{
- char *p;
- Sym *s;
-
- if(*name == '\0')
- return 0;
-
- /* reuse hash code in symbol table */
- p = smprint(".dynlib.%s", name);
- s = lookup(p, 0);
- if(s->type == 0) {
- s->type = 100; // avoid SDATA, etc.
- return 1;
- }
- return 0;
-}
-
-int nelfsym = 1;
-
-static void addpltsym(Sym*);
-static void addgotsym(Sym*);
-
-void
-adddynrel(Sym *s, Reloc *r)
-{
- Sym *targ, *rel, *got;
-
- targ = r->sym;
- cursym = s;
-
- switch(r->type) {
- default:
- if(r->type >= 256) {
- diag("unexpected relocation type %d", r->type);
- return;
- }
- break;
-
- // Handle relocations found in ELF object files.
- case 256 + R_386_PC32:
- if(targ->dynimpname != nil && !targ->dynexport)
- diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
- if(targ->type == 0 || targ->type == SXREF)
- diag("unknown symbol %s in pcrel", targ->name);
- r->type = D_PCREL;
- r->add += 4;
- return;
-
- case 256 + R_386_PLT32:
- r->type = D_PCREL;
- r->add += 4;
- if(targ->dynimpname != nil && !targ->dynexport) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
- r->add += targ->plt;
- }
- return;
-
- case 256 + R_386_GOT32:
- if(targ->dynimpname == nil || targ->dynexport) {
- // have symbol
- // turn MOVL of GOT entry into LEAL of symbol itself
- if(r->off < 2 || s->p[r->off-2] != 0x8b) {
- diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
- return;
- }
- s->p[r->off-2] = 0x8d;
- r->type = D_GOTOFF;
- return;
- }
- addgotsym(targ);
- r->type = D_CONST; // write r->add during relocsym
- r->sym = S;
- r->add += targ->got;
- return;
-
- case 256 + R_386_GOTOFF:
- r->type = D_GOTOFF;
- return;
-
- case 256 + R_386_GOTPC:
- r->type = D_PCREL;
- r->sym = lookup(".got", 0);
- r->add += 4;
- return;
-
- case 256 + R_386_32:
- if(targ->dynimpname != nil && !targ->dynexport)
- diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
- r->type = D_ADDR;
- return;
-
- case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
- r->type = D_ADDR;
- if(targ->dynimpname != nil && !targ->dynexport)
- diag("unexpected reloc for dynamic symbol %s", targ->name);
- return;
-
- case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
- if(targ->dynimpname != nil && !targ->dynexport) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
- r->add = targ->plt;
- r->type = D_PCREL;
- return;
- }
- r->type = D_PCREL;
- return;
-
- case 512 + MACHO_FAKE_GOTPCREL:
- if(targ->dynimpname == nil || targ->dynexport) {
- // have symbol
- // turn MOVL of GOT entry into LEAL of symbol itself
- if(r->off < 2 || s->p[r->off-2] != 0x8b) {
- diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
- return;
- }
- s->p[r->off-2] = 0x8d;
- r->type = D_PCREL;
- return;
- }
- addgotsym(targ);
- r->sym = lookup(".got", 0);
- r->add += targ->got;
- r->type = D_PCREL;
- return;
- }
-
- // Handle references to ELF symbols from our own object files.
- if(targ->dynimpname == nil || targ->dynexport)
- return;
-
- switch(r->type) {
- case D_PCREL:
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
- r->add = targ->plt;
- return;
-
- case D_ADDR:
- if(s->type != SDATA)
- break;
- if(iself) {
- adddynsym(targ);
- rel = lookup(".rel", 0);
- addaddrplus(rel, s, r->off);
- adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32));
- r->type = D_CONST; // write r->add during relocsym
- r->sym = S;
- return;
- }
- if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
- // Mach-O relocations are a royal pain to lay out.
- // They use a compact stateful bytecode representation
- // that is too much bother to deal with.
- // Instead, interpret the C declaration
- // void *_Cvar_stderr = &stderr;
- // as making _Cvar_stderr the name of a GOT entry
- // for stderr. This is separate from the usual GOT entry,
- // just in case the C code assigns to the variable,
- // and of course it only works for single pointers,
- // but we only need to support cgo and that's all it needs.
- adddynsym(targ);
- got = lookup(".got", 0);
- s->type = got->type | SSUB;
- s->outer = got;
- s->sub = got->sub;
- got->sub = s;
- s->value = got->size;
- adduint32(got, 0);
- adduint32(lookup(".linkedit.got", 0), targ->dynid);
- r->type = 256; // ignore during relocsym
- return;
- }
- break;
- }
-
- cursym = s;
- diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
-}
-
-static void
-elfsetupplt(void)
-{
- Sym *plt, *got;
-
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
- if(plt->size == 0) {
- // pushl got+4
- adduint8(plt, 0xff);
- adduint8(plt, 0x35);
- addaddrplus(plt, got, 4);
-
- // jmp *got+8
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addaddrplus(plt, got, 8);
-
- // zero pad
- adduint32(plt, 0);
-
- // assume got->size == 0 too
- addaddrplus(got, lookup(".dynamic", 0), 0);
- adduint32(got, 0);
- adduint32(got, 0);
- }
-}
-
-int
-archreloc(Reloc *r, Sym *s, vlong *val)
-{
- USED(s);
- switch(r->type) {
- case D_CONST:
- *val = r->add;
- return 0;
- case D_GOTOFF:
- *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
- return 0;
- }
- return -1;
-}
-
-static void
-addpltsym(Sym *s)
-{
- Sym *plt, *got, *rel;
-
- if(s->plt >= 0)
- return;
-
- adddynsym(s);
-
- if(iself) {
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
- rel = lookup(".rel.plt", 0);
- if(plt->size == 0)
- elfsetupplt();
-
- // jmpq *got+size
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addaddrplus(plt, got, got->size);
-
- // add to got: pointer to current pos in plt
- addaddrplus(got, plt, plt->size);
-
- // pushl $x
- adduint8(plt, 0x68);
- adduint32(plt, rel->size);
-
- // jmp .plt
- adduint8(plt, 0xe9);
- adduint32(plt, -(plt->size+4));
-
- // rel
- addaddrplus(rel, got, got->size-4);
- adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
-
- s->plt = plt->size - 16;
- } else if(HEADTYPE == Hdarwin) {
- // Same laziness as in 6l.
-
- Sym *plt;
-
- plt = lookup(".plt", 0);
-
- addgotsym(s);
-
- adduint32(lookup(".linkedit.plt", 0), s->dynid);
-
- // jmpq *got+size(IP)
- s->plt = plt->size;
-
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addaddrplus(plt, lookup(".got", 0), s->got);
- } else {
- diag("addpltsym: unsupported binary format");
- }
-}
-
-static void
-addgotsym(Sym *s)
-{
- Sym *got, *rel;
-
- if(s->got >= 0)
- return;
-
- adddynsym(s);
- got = lookup(".got", 0);
- s->got = got->size;
- adduint32(got, 0);
-
- if(iself) {
- rel = lookup(".rel", 0);
- addaddrplus(rel, got, s->got);
- adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
- } else if(HEADTYPE == Hdarwin) {
- adduint32(lookup(".linkedit.got", 0), s->dynid);
- } else {
- diag("addgotsym: unsupported binary format");
- }
-}
-
-void
-adddynsym(Sym *s)
-{
- Sym *d, *str;
- int t;
- char *name;
-
- if(s->dynid >= 0)
- return;
-
- if(s->dynimpname == nil)
- diag("adddynsym: no dynamic name for %s", s->name, *(int32*)0);
-
- if(iself) {
- s->dynid = nelfsym++;
-
- d = lookup(".dynsym", 0);
-
- /* name */
- name = s->dynimpname;
- if(name == nil)
- name = s->name;
- adduint32(d, addstring(lookup(".dynstr", 0), name));
-
- /* value */
- if(s->type == SDYNIMPORT)
- adduint32(d, 0);
- else
- addaddr(d, s);
-
- /* size */
- adduint32(d, 0);
-
- /* type */
- t = STB_GLOBAL << 4;
- if(s->dynexport && s->type == STEXT)
- t |= STT_FUNC;
- else
- t |= STT_OBJECT;
- adduint8(d, t);
- adduint8(d, 0);
-
- /* shndx */
- if(!s->dynexport && s->dynimpname != nil)
- adduint16(d, SHN_UNDEF);
- else {
- switch(s->type) {
- default:
- case STEXT:
- t = 11;
- break;
- case SRODATA:
- t = 12;
- break;
- case SDATA:
- t = 13;
- break;
- case SBSS:
- t = 14;
- break;
- }
- adduint16(d, t);
- }
- } else if(HEADTYPE == Hdarwin) {
- // Mach-O symbol nlist32
- d = lookup(".dynsym", 0);
- name = s->dynimpname;
- if(name == nil)
- name = s->name;
- s->dynid = d->size/12;
- // darwin still puts _ prefixes on all C symbols
- str = lookup(".dynstr", 0);
- adduint32(d, str->size);
- adduint8(str, '_');
- addstring(str, name);
- adduint8(d, 0x01); // type - N_EXT - external symbol
- adduint8(d, 0); // section
- adduint16(d, 0); // desc
- adduint32(d, 0); // value
- } else if(HEADTYPE != Hwindows) {
- diag("adddynsym: unsupported binary format");
- }
-}
-
-void
-adddynlib(char *lib)
-{
- Sym *s;
-
- if(!needlib(lib))
- return;
-
- if(iself) {
- s = lookup(".dynstr", 0);
- if(s->size == 0)
- addstring(s, "");
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
- } else if(HEADTYPE == Hdarwin) {
- machoadddynlib(lib);
- } else if(HEADTYPE != Hwindows) {
- diag("adddynlib: unsupported binary format");
- }
-}
-
-void
-doelf(void)
-{
- Sym *s, *shstrtab, *dynstr;
-
- if(!iself)
- return;
-
- /* predefine strings we need for section headers */
- shstrtab = lookup(".shstrtab", 0);
- shstrtab->type = SELFDATA;
- shstrtab->reachable = 1;
-
- elfstr[ElfStrEmpty] = addstring(shstrtab, "");
- elfstr[ElfStrText] = addstring(shstrtab, ".text");
- elfstr[ElfStrData] = addstring(shstrtab, ".data");
- elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
- addstring(shstrtab, ".elfdata");
- addstring(shstrtab, ".rodata");
- addstring(shstrtab, ".gosymtab");
- addstring(shstrtab, ".gopclntab");
- if(!debug['s']) {
- elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
- elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
- dwarfaddshstrings(shstrtab);
- }
- elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
-
- if(!debug['d']) { /* -d suppresses dynamic loader format */
- elfstr[ElfStrInterp] = addstring(shstrtab, ".interp");
- elfstr[ElfStrHash] = addstring(shstrtab, ".hash");
- elfstr[ElfStrGot] = addstring(shstrtab, ".got");
- elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt");
- elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic");
- elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
- elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
- elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
- elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
- elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
- elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
- elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
-
- /* interpreter string */
- s = lookup(".interp", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /* dynamic symbol table - first entry all zeros */
- s = lookup(".dynsym", 0);
- s->type = SELFDATA;
- s->reachable = 1;
- s->size += ELF32SYMSIZE;
-
- /* dynamic string table */
- s = lookup(".dynstr", 0);
- s->reachable = 1;
- s->type = SELFDATA;
- if(s->size == 0)
- addstring(s, "");
- dynstr = s;
-
- /* relocation table */
- s = lookup(".rel", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /* global offset table */
- s = lookup(".got", 0);
- s->reachable = 1;
- s->type = SDATA; // writable, so not SELFDATA
-
- /* hash */
- s = lookup(".hash", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /* got.plt */
- s = lookup(".got.plt", 0);
- s->reachable = 1;
- s->type = SDATA; // writable, so not SELFDATA
-
- s = lookup(".plt", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- s = lookup(".rel.plt", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- s = lookup(".gnu.version", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- s = lookup(".gnu.version_r", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- elfsetupplt();
-
- /* define dynamic elf table */
- s = lookup(".dynamic", 0);
- s->reachable = 1;
- s->type = SELFDATA;
-
- /*
- * .dynamic table
- */
- elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
- elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
- elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
- elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
- elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
- elfwritedynentsym(s, DT_REL, lookup(".rel", 0));
- elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0));
- elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
- if(rpath)
- elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
- elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
- elfwritedynent(s, DT_PLTREL, DT_REL);
- elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
- elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
-
- // Do not write DT_NULL. elfdynhash will finish it.
- }
-}
-
-void
-shsym(Elf64_Shdr *sh, Sym *s)
-{
- sh->addr = symaddr(s);
- sh->off = datoff(sh->addr);
- sh->size = s->size;
-}
-
-void
-phsh(Elf64_Phdr *ph, Elf64_Shdr *sh)
-{
- ph->vaddr = sh->addr;
- ph->paddr = ph->vaddr;
- ph->off = sh->off;
- ph->filesz = sh->size;
- ph->memsz = sh->size;
- ph->align = sh->addralign;
-}
-
-void
-asmb(void)
-{
- int32 v, magic;
- int a, dynsym;
- uint32 symo, startva, machlink;
- ElfEhdr *eh;
- ElfPhdr *ph, *pph;
- ElfShdr *sh;
- Section *sect;
- Sym *sym;
- int i;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f asmb\n", cputime());
- Bflush(&bso);
-
- sect = segtext.sect;
- seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
- codeblk(sect->vaddr, sect->len);
-
- /* output read-only data in text segment (rodata, gosymtab and pclntab) */
- for(sect = sect->next; sect != nil; sect = sect->next) {
- seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
- datblk(sect->vaddr, sect->len);
- }
-
- if(debug['v'])
- Bprint(&bso, "%5.2f datblk\n", cputime());
- Bflush(&bso);
-
- seek(cout, segdata.fileoff, 0);
- datblk(segdata.vaddr, segdata.filelen);
-
- machlink = 0;
- if(HEADTYPE == Hdarwin)
- machlink = domacholink();
-
- if(iself) {
- /* index of elf text section; needed by asmelfsym, double-checked below */
- /* !debug['d'] causes extra sections before the .text section */
- elftextsh = 1;
- if(!debug['d']) {
- elftextsh += 10;
- if(elfverneed)
- elftextsh += 2;
- }
- }
-
- symsize = 0;
- spsize = 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 Hgarbunix:
- symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen;
- break;
- case Hunixcoff:
- symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
- break;
- case Hplan9x32:
- symo = HEADR+segtext.filelen+segdata.filelen;
- break;
- case Hmsdoscom:
- case Hmsdosexe:
- debug['s'] = 1;
- symo = HEADR+segtext.filelen+segdata.filelen;
- break;
- case Hdarwin:
- symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
- break;
- Elfsym:
- symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
- symo = rnd(symo, INITRND);
- break;
- case Hwindows:
- symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
- symo = rnd(symo, PEFILEALIGN);
- break;
- }
- seek(cout, symo, 0);
- switch(HEADTYPE) {
- default:
- if(iself) {
- if(debug['v'])
- Bprint(&bso, "%5.2f elfsym\n", cputime());
- asmelfsym();
- cflush();
- ewrite(cout, elfstrdat, elfstrsize);
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dwarf\n", cputime());
- dwarfemitdebugsections();
- }
- break;
- case Hplan9x32:
- asmplan9sym();
- cflush();
-
- sym = lookup("pclntab", 0);
- if(sym != nil) {
- lcsize = sym->np;
- for(i=0; i < lcsize; i++)
- cput(sym->p[i]);
-
- cflush();
- }
- break;
- case Hdarwin:
- case Hwindows:
- if(debug['v'])
- Bprint(&bso, "%5.2f dwarf\n", cputime());
- dwarfemitdebugsections();
- break;
- }
- }
- if(debug['v'])
- Bprint(&bso, "%5.2f headr\n", cputime());
- Bflush(&bso);
- seek(cout, 0L, 0);
- switch(HEADTYPE) {
- default:
- if(iself)
- goto Elfput;
- case Hgarbunix: /* garbage */
- lputb(0x160L<<16); /* magic and sections */
- lputb(0L); /* time and date */
- lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
- lputb(symsize); /* nsyms */
- lputb((0x38L<<16)|7L); /* size of optional hdr and flags */
- lputb((0413<<16)|0437L); /* magic and version */
- lputb(rnd(HEADR+segtext.filelen, 4096)); /* sizes */
- lputb(segdata.filelen);
- lputb(segdata.len - segdata.filelen);
- lputb(entryvalue()); /* va of entry */
- lputb(INITTEXT-HEADR); /* va of base of text */
- lputb(segdata.vaddr); /* va of base of data */
- lputb(segdata.vaddr+segdata.filelen); /* va of base of bss */
- lputb(~0L); /* gp reg mask */
- lputb(0L);
- lputb(0L);
- lputb(0L);
- lputb(0L);
- lputb(~0L); /* gp value ?? */
- break;
- case Hunixcoff: /* unix coff */
- /*
- * file header
- */
- lputl(0x0004014c); /* 4 sections, magic */
- lputl(0); /* unix time stamp */
- lputl(0); /* symbol table */
- lputl(0); /* nsyms */
- lputl(0x0003001c); /* flags, sizeof a.out header */
- /*
- * a.out header
- */
- lputl(0x10b); /* magic, version stamp */
- lputl(rnd(segtext.filelen, INITRND)); /* text sizes */
- lputl(segdata.filelen); /* data sizes */
- lputl(segdata.len - segdata.filelen); /* bss sizes */
- lputb(entryvalue()); /* va of entry */
- lputl(INITTEXT); /* text start */
- lputl(segdata.vaddr); /* data start */
- /*
- * text section header
- */
- s8put(".text");
- lputl(HEADR); /* pa */
- lputl(HEADR); /* va */
- lputl(segtext.filelen); /* text size */
- lputl(HEADR); /* file offset */
- lputl(0); /* relocation */
- lputl(0); /* line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x20); /* flags text only */
- /*
- * data section header
- */
- s8put(".data");
- lputl(segdata.vaddr); /* pa */
- lputl(segdata.vaddr); /* va */
- lputl(segdata.filelen); /* data size */
- lputl(HEADR+segtext.filelen); /* file offset */
- lputl(0); /* relocation */
- lputl(0); /* line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x40); /* flags data only */
- /*
- * bss section header
- */
- s8put(".bss");
- lputl(segdata.vaddr+segdata.filelen); /* pa */
- lputl(segdata.vaddr+segdata.filelen); /* va */
- lputl(segdata.len - segdata.filelen); /* bss size */
- lputl(0); /* file offset */
- lputl(0); /* relocation */
- lputl(0); /* line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x80); /* flags bss only */
- /*
- * comment section header
- */
- s8put(".comment");
- lputl(0); /* pa */
- lputl(0); /* va */
- lputl(symsize+lcsize); /* comment size */
- lputl(HEADR+segtext.filelen+segdata.filelen); /* file offset */
- lputl(HEADR+segtext.filelen+segdata.filelen); /* offset of syms */
- lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x200); /* flags comment only */
- break;
- case Hplan9x32: /* plan9 */
- magic = 4*11*11+7;
- lputb(magic); /* magic */
- lputb(segtext.filelen); /* sizes */
- lputb(segdata.filelen);
- lputb(segdata.len - segdata.filelen);
- lputb(symsize); /* nsyms */
- lputb(entryvalue()); /* va of entry */
- lputb(spsize); /* sp offsets */
- lputb(lcsize); /* line offsets */
- break;
- case Hmsdoscom:
- /* MS-DOS .COM */
- break;
- case Hmsdosexe:
- /* fake MS-DOS .EXE */
- v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
- wputl(0x5A4D); /* 'MZ' */
- wputl(v % 512); /* bytes in last page */
- wputl(rnd(v, 512)/512); /* total number of pages */
- wputl(0x0000); /* number of reloc items */
- v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
- wputl(v/16); /* size of header */
- wputl(0x0000); /* minimum allocation */
- wputl(0xFFFF); /* maximum allocation */
- wputl(0x0000); /* initial ss value */
- wputl(0x0100); /* initial sp value */
- wputl(0x0000); /* complemented checksum */
- v = entryvalue();
- wputl(v); /* initial ip value (!) */
- wputl(0x0000); /* initial cs value */
- wputl(0x0000);
- wputl(0x0000);
- wputl(0x003E); /* reloc table offset */
- wputl(0x0000); /* overlay number */
- break;
-
- case Hdarwin:
- asmbmacho();
- break;
-
- Elfput:
- eh = getElfEhdr();
- startva = INITTEXT - HEADR;
-
- /* This null SHdr must appear before all others */
- newElfShdr(elfstr[ElfStrEmpty]);
-
- /* program header info */
- pph = newElfPhdr();
- pph->type = PT_PHDR;
- pph->flags = PF_R + PF_X;
- pph->off = eh->ehsize;
- pph->vaddr = INITTEXT - HEADR + pph->off;
- pph->paddr = INITTEXT - HEADR + pph->off;
- pph->align = INITRND;
-
- if(!debug['d']) {
- /* interpreter */
- sh = newElfShdr(elfstr[ElfStrInterp]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->addralign = 1;
- if(interpreter == nil) {
- switch(HEADTYPE) {
- case Hlinux:
- interpreter = linuxdynld;
- break;
- case Hfreebsd:
- interpreter = freebsddynld;
- break;
- }
- }
- elfinterp(sh, startva, interpreter);
-
- ph = newElfPhdr();
- ph->type = PT_INTERP;
- ph->flags = PF_R;
- phsh(ph, sh);
- }
-
- elfphload(&segtext);
- elfphload(&segdata);
-
- /* Dynamic linking sections */
- if (!debug['d']) { /* -d suppresses dynamic loader format */
- /* S headers for dynamic linking */
- sh = newElfShdr(elfstr[ElfStrGot]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 4;
- sh->addralign = 4;
- shsym(sh, lookup(".got", 0));
-
- sh = newElfShdr(elfstr[ElfStrGotPlt]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 4;
- sh->addralign = 4;
- shsym(sh, lookup(".got.plt", 0));
-
- dynsym = eh->shnum;
- sh = newElfShdr(elfstr[ElfStrDynsym]);
- sh->type = SHT_DYNSYM;
- sh->flags = SHF_ALLOC;
- sh->entsize = ELF32SYMSIZE;
- sh->addralign = 4;
- sh->link = dynsym+1; // dynstr
- // sh->info = index of first non-local symbol (number of local symbols)
- shsym(sh, lookup(".dynsym", 0));
-
- sh = newElfShdr(elfstr[ElfStrDynstr]);
- sh->type = SHT_STRTAB;
- sh->flags = SHF_ALLOC;
- sh->addralign = 1;
- shsym(sh, lookup(".dynstr", 0));
-
- if(elfverneed) {
- sh = newElfShdr(elfstr[ElfStrGnuVersion]);
- sh->type = SHT_GNU_VERSYM;
- sh->flags = SHF_ALLOC;
- sh->addralign = 2;
- sh->link = dynsym;
- sh->entsize = 2;
- shsym(sh, lookup(".gnu.version", 0));
-
- sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
- sh->type = SHT_GNU_VERNEED;
- sh->flags = SHF_ALLOC;
- sh->addralign = 4;
- sh->info = elfverneed;
- sh->link = dynsym+1; // dynstr
- shsym(sh, lookup(".gnu.version_r", 0));
- }
-
- sh = newElfShdr(elfstr[ElfStrRelPlt]);
- sh->type = SHT_REL;
- sh->flags = SHF_ALLOC;
- sh->entsize = ELF32RELSIZE;
- sh->addralign = 4;
- sh->link = dynsym;
- sh->info = eh->shnum; // .plt
- shsym(sh, lookup(".rel.plt", 0));
-
- sh = newElfShdr(elfstr[ElfStrPlt]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_EXECINSTR;
- sh->entsize = 4;
- sh->addralign = 4;
- shsym(sh, lookup(".plt", 0));
-
- sh = newElfShdr(elfstr[ElfStrHash]);
- sh->type = SHT_HASH;
- sh->flags = SHF_ALLOC;
- sh->entsize = 4;
- sh->addralign = 4;
- sh->link = dynsym;
- shsym(sh, lookup(".hash", 0));
-
- sh = newElfShdr(elfstr[ElfStrRel]);
- sh->type = SHT_REL;
- sh->flags = SHF_ALLOC;
- sh->entsize = ELF32RELSIZE;
- sh->addralign = 4;
- sh->link = dynsym;
- shsym(sh, lookup(".rel", 0));
-
- /* sh and PT_DYNAMIC for .dynamic section */
- sh = newElfShdr(elfstr[ElfStrDynamic]);
- sh->type = SHT_DYNAMIC;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 8;
- sh->addralign = 4;
- sh->link = dynsym+1; // dynstr
- shsym(sh, lookup(".dynamic", 0));
- ph = newElfPhdr();
- ph->type = PT_DYNAMIC;
- ph->flags = PF_R + PF_W;
- phsh(ph, sh);
-
- /*
- * Thread-local storage segment (really just size).
- */
- if(tlsoffset != 0) {
- ph = newElfPhdr();
- ph->type = PT_TLS;
- ph->flags = PF_R;
- ph->memsz = -tlsoffset;
- ph->align = 4;
- }
- }
-
- ph = newElfPhdr();
- ph->type = PT_GNU_STACK;
- ph->flags = PF_W+PF_R;
- ph->align = 4;
-
- if(elftextsh != eh->shnum)
- diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
- for(sect=segtext.sect; sect!=nil; sect=sect->next)
- elfshbits(sect);
- for(sect=segdata.sect; sect!=nil; sect=sect->next)
- elfshbits(sect);
-
- if (!debug['s']) {
- sh = newElfShdr(elfstr[ElfStrSymtab]);
- sh->type = SHT_SYMTAB;
- sh->off = symo;
- sh->size = symsize;
- sh->addralign = 4;
- sh->entsize = 16;
- sh->link = eh->shnum; // link to strtab
-
- sh = newElfShdr(elfstr[ElfStrStrtab]);
- sh->type = SHT_STRTAB;
- sh->off = symo+symsize;
- sh->size = elfstrsize;
- sh->addralign = 1;
-
- dwarfaddelfheaders();
- }
-
- sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
- sh->type = SHT_STRTAB;
- sh->addralign = 1;
- shsym(sh, lookup(".shstrtab", 0));
-
- /* Main header */
- eh->ident[EI_MAG0] = '\177';
- eh->ident[EI_MAG1] = 'E';
- eh->ident[EI_MAG2] = 'L';
- eh->ident[EI_MAG3] = 'F';
- eh->ident[EI_CLASS] = ELFCLASS32;
- eh->ident[EI_DATA] = ELFDATA2LSB;
- eh->ident[EI_VERSION] = EV_CURRENT;
- switch(HEADTYPE) {
- case Hfreebsd:
- eh->ident[EI_OSABI] = 9;
- break;
- }
-
- eh->type = ET_EXEC;
- eh->machine = EM_386;
- eh->version = EV_CURRENT;
- eh->entry = entryvalue();
-
- if(pph != nil) {
- pph->filesz = eh->phnum * eh->phentsize;
- pph->memsz = pph->filesz;
- }
-
- seek(cout, 0, 0);
- a = 0;
- a += elfwritehdr();
- a += elfwritephdrs();
- a += elfwriteshdrs();
- cflush();
- if(a+elfwriteinterp() > ELFRESERVE)
- diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
- break;
-
- case Hwindows:
- asmbpe();
- break;
- }
- cflush();
-}
-
-void
-s8put(char *n)
-{
- char name[8];
- int i;
-
- strncpy(name, n, sizeof(name));
- for(i=0; i<sizeof(name); i++)
- cput(name[i]);
-}
-
-void
-cflush(void)
-{
- int n;
-
- n = sizeof(buf.cbuf) - cbc;
- if(n)
- ewrite(cout, buf.cbuf, n);
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
-}
-
-/* Current position in file */
-vlong
-cpos(void)
-{
- return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc;
-}
-
-int32
-rnd(int32 v, int32 r)
-{
- int32 c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
-
-void
-genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
-{
- Auto *a;
- Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- put(s, s->name, 'T', s->value, s->size, s->version, 0);
-
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->hash) {
- if(s->hide)
- continue;
- switch(s->type&~SSUB) {
- case SCONST:
- case SRODATA:
- case SDATA:
- case SELFDATA:
- case SMACHO:
- case SMACHOGOT:
- case STYPE:
- case SSTRING:
- case SGOSTRING:
- case SWINDOWS:
- if(!s->reachable)
- continue;
- put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
- continue;
-
- case SBSS:
- if(!s->reachable)
- continue;
- put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
- continue;
-
- case SFILE:
- put(nil, s->name, 'f', s->value, 0, s->version, 0);
- continue;
- }
- }
- }
-
- for(s = textp; s != nil; s = s->next) {
- if(s->text == nil)
- continue;
-
- /* filenames first */
- for(a=s->autom; a; a=a->link)
- if(a->type == D_FILE)
- put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
- else
- if(a->type == D_FILE1)
- put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
-
- put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
-
- /* frame, auto and param after */
- put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0);
-
- for(a=s->autom; a; a=a->link)
- if(a->type == D_AUTO)
- put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %d\n", symsize);
- Bflush(&bso);
-}
diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go
deleted file mode 100644
index b70888907..000000000
--- a/src/cmd/8l/doc.go
+++ /dev/null
@@ -1,50 +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.
-
-/*
-
-8l is a modified version of the Plan 9 linker. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2l
-
-Its target architecture is the x86, referred to by these tools for historical reasons as 386.
-It reads files in .8 format generated by 8g, 8c, and 8a and emits
-a binary called 8.out by default.
-
-Major changes include:
- - support for ELF and Mach-O binary files
- - support for segmented stacks (this feature is implemented here, not in the compilers).
-
-
-Original options are listed in the link above.
-
-Options new in this version:
-
--d
- Elide the dynamic linking header. With this option, the binary
- is statically linked and does not refer to dynld. Without this option
- (the default), the binary's contents are identical but it is loaded with dynld.
--Hplan9
- Write Plan 9 32-bit format binaries (default when $GOOS is plan9)
--Hdarwin
- Write Apple Mach-O binaries (default when $GOOS is darwin)
--Hlinux
- Write Linux ELF binaries (default when $GOOS is linux)
--Hfreebsd
- Write FreeBSD ELF binaries (default when $GOOS is freebsd)
--Hwindows
- Write Windows PE32 binaries (default when $GOOS is windows)
--I interpreter
- Set the ELF dynamic linker to use.
--L dir1 -L dir2
- Search for libraries (package files) in dir1, dir2, etc.
- The default is the single location $GOROOT/pkg/$GOOS_386.
--r dir1:dir2:...
- Set the dynamic linker search path when using ELF.
--V
- Print the linker version.
-
-
-*/
-package documentation
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
deleted file mode 100644
index 7e7cd5d63..000000000
--- a/src/cmd/8l/l.h
+++ /dev/null
@@ -1,394 +0,0 @@
-// Inferno utils/8l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.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 <libc.h>
-#include <bio.h>
-#include "../8l/8.out.h"
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-enum
-{
- thechar = '8',
- PtrSize = 4
-};
-
-#define P ((Prog*)0)
-#define S ((Sym*)0)
-#define TNAME (cursym?cursym->name:noname)
-#define cput(c)\
- { *cbp++ = c;\
- if(--cbc <= 0)\
- cflush(); }
-
-typedef struct Adr Adr;
-typedef struct Prog Prog;
-typedef struct Sym Sym;
-typedef struct Auto Auto;
-typedef struct Optab Optab;
-typedef struct Reloc Reloc;
-
-struct Adr
-{
- union
- {
- int32 u0offset;
- char u0scon[8];
- Prog *u0cond; /* not used, but should be D_BRANCH */
- Ieee u0ieee;
- char *u0sbig;
- } u0;
- Sym* sym;
- short type;
- uchar index;
- char scale;
- int32 offset2;
-};
-
-#define offset u0.u0offset
-#define scon u0.u0scon
-#define cond u0.u0cond
-#define ieee u0.u0ieee
-#define sbig u0.u0sbig
-
-struct Reloc
-{
- int32 off;
- uchar siz;
- int32 type;
- int32 add;
- Sym* sym;
-};
-
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* forwd;
- Prog* comefrom;
- Prog* link;
- Prog* pcond; /* work on this */
- int32 pc;
- int32 spadj;
- int32 line;
- short as;
- char width; /* fake for DATA */
- char ft; /* oclass cache */
- char tt;
- uchar mark; /* work on these */
- uchar back;
- uchar bigjmp;
-};
-#define datasize from.scale
-#define textflag from.scale
-#define iscall(p) ((p)->as == ACALL)
-
-struct Auto
-{
- Sym* asym;
- Auto* link;
- int32 aoffset;
- short type;
- Sym* gotype;
-};
-struct Sym
-{
- char* name;
- short type;
- short version;
- uchar dupok;
- uchar reachable;
- uchar dynexport;
- uchar special;
- uchar stkcheck;
- uchar hide;
- int32 value;
- int32 size;
- int32 sig;
- int32 dynid;
- int32 plt;
- int32 got;
- Sym* hash; // in hash table
- Sym* allsym; // in all symbol list
- Sym* next; // in text or data list
- Sym* sub; // in sub list
- Sym* outer; // container of sub
- Sym* gotype;
- char* file;
- char* dynimpname;
- char* dynimplib;
- char* dynimpvers;
-
- // STEXT
- Auto* autom;
- Prog* text;
-
- // SDATA, SBSS
- uchar* p;
- int32 np;
- int32 maxp;
- Reloc* r;
- int32 nr;
- int32 maxr;
-};
-struct Optab
-{
- short as;
- uchar* ytab;
- uchar prefix;
- uchar op[10];
-};
-
-enum
-{
- MINSIZ = 4,
- STRINGSZ = 200,
- MINLC = 1,
- MAXIO = 8192,
- MAXHIST = 20, /* limit of path elements for history symbols */
-
- Yxxx = 0,
- Ynone,
- Yi0,
- Yi1,
- Yi8,
- Yi32,
- Yiauto,
- Yal,
- Ycl,
- Yax,
- Ycx,
- Yrb,
- Yrl,
- Yrf,
- Yf0,
- Yrx,
- Ymb,
- Yml,
- Ym,
- Ybr,
- Ycol,
-
- Ycs, Yss, Yds, Yes, Yfs, Ygs,
- Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
- Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7,
- Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
- Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7,
- Ymax,
-
- Zxxx = 0,
-
- Zlit,
- Z_rp,
- Zbr,
- Zcall,
- Zcallcon,
- Zib_,
- Zib_rp,
- Zibo_m,
- Zil_,
- Zil_rp,
- Zilo_m,
- Zjmp,
- Zjmpcon,
- Zloop,
- Zm_o,
- Zm_r,
- Zaut_r,
- Zo_m,
- Zpseudo,
- Zr_m,
- Zrp_,
- Z_ib,
- Z_il,
- Zm_ibo,
- Zm_ilo,
- Zib_rr,
- Zil_rr,
- Zclr,
- Zbyte,
- Zmov,
- Zmax,
-
- Px = 0,
- Pe = 0x66, /* operand escape */
- Pm = 0x0f, /* 2byte opcode escape */
- Pq = 0xff, /* both escape */
- Pb = 0xfe, /* byte operands */
-};
-
-EXTERN union
-{
- struct
- {
- char obuf[MAXIO]; /* output buffer */
- uchar ibuf[MAXIO]; /* input buffer */
- } u;
- char dbuf[1];
-} buf;
-
-#define cbuf u.obuf
-#define xbuf u.ibuf
-
-#pragma varargck type "A" int
-#pragma varargck type "D" Adr*
-#pragma varargck type "I" int
-#pragma varargck type "I" uchar*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "S" char*
-#pragma varargck type "Y" Sym*
-#pragma varargck type "i" char*
-
-EXTERN int32 HEADR;
-EXTERN int32 HEADTYPE;
-EXTERN int32 INITRND;
-EXTERN int32 INITTEXT;
-EXTERN int32 INITDAT;
-EXTERN char* INITENTRY; /* entry point */
-EXTERN Biobuf bso;
-EXTERN int32 casepc;
-EXTERN int cbc;
-EXTERN char* cbp;
-EXTERN char* pcstr;
-EXTERN Auto* curauto;
-EXTERN Auto* curhist;
-EXTERN Prog* curp;
-EXTERN Sym* cursym;
-EXTERN Sym* datap;
-EXTERN int32 elfdatsize;
-EXTERN char debug[128];
-EXTERN char literal[32];
-EXTERN Sym* etextp;
-EXTERN Prog* firstp;
-EXTERN uchar ycover[Ymax*Ymax];
-EXTERN uchar* andptr;
-EXTERN uchar and[100];
-EXTERN char reg[D_NONE];
-EXTERN int32 lcsize;
-EXTERN int maxop;
-EXTERN int nerrors;
-EXTERN char* noname;
-EXTERN int32 pc;
-EXTERN char* interpreter;
-EXTERN char* rpath;
-EXTERN int32 spsize;
-EXTERN Sym* symlist;
-EXTERN int32 symsize;
-EXTERN Sym* textp;
-EXTERN int32 textsize;
-EXTERN int version;
-EXTERN Prog zprg;
-EXTERN int dtype;
-EXTERN int tlsoffset;
-EXTERN Sym* adrgotype; // type symbol on last Adr read
-EXTERN Sym* fromgotype; // type symbol on last p->from read
-EXTERN int elftextsh;
-
-extern Optab optab[];
-extern char* anames[];
-
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Iconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Sconv(Fmt*);
-void addhist(int32, int);
-Prog* appendp(Prog*);
-void asmb(void);
-void asmdyn(void);
-void asmins(Prog*);
-void asmsym(void);
-int32 atolwhex(char*);
-Prog* brchain(Prog*);
-Prog* brloop(Prog*);
-void cflush(void);
-Prog* copyp(Prog*);
-vlong cpos(void);
-double cputime(void);
-void diag(char*, ...);
-void dodata(void);
-void doelf(void);
-void doprof1(void);
-void doprof2(void);
-void dostkoff(void);
-int32 entryvalue(void);
-void follow(void);
-void instinit(void);
-void listinit(void);
-Sym* lookup(char*, int);
-void lputb(int32);
-void lputl(int32);
-void vputl(uint64);
-void strnput(char*, int);
-void main(int, char*[]);
-void* mal(uint32);
-int opsize(Prog*);
-void patch(void);
-Prog* prg(void);
-int relinv(int);
-int32 rnd(int32, int32);
-void s8put(char*);
-void span(void);
-void undef(void);
-int32 symaddr(Sym*);
-void wput(ushort);
-void wputl(ushort);
-void xdefine(char*, int, int32);
-
-uint32 machheadr(void);
-vlong addaddr(Sym *s, Sym *t);
-vlong addsize(Sym *s, Sym *t);
-vlong addstring(Sym *s, char *str);
-vlong adduint16(Sym *s, uint16 v);
-vlong adduint32(Sym *s, uint32 v);
-vlong adduint64(Sym *s, uint64 v);
-vlong adduint8(Sym *s, uint8 v);
-vlong adduintxx(Sym *s, uint64 v, int wid);
-
-/*
- * go.c
- */
-void deadcode(void);
-
-/* Native is little-endian */
-#define LPUT(a) lputl(a)
-#define WPUT(a) wputl(a)
-#define VPUT(a) vputl(a)
-
-/* Used by ../ld/dwarf.c */
-enum
-{
- DWARFREGSP = 4
-};
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
deleted file mode 100644
index 31ae02346..000000000
--- a/src/cmd/8l/list.c
+++ /dev/null
@@ -1,369 +0,0 @@
-// Inferno utils/8l/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/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.
-
-// Printing.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-listinit(void)
-{
-
- fmtinstall('R', Rconv);
- fmtinstall('A', Aconv);
- fmtinstall('D', Dconv);
- fmtinstall('S', Sconv);
- fmtinstall('P', Pconv);
- fmtinstall('I', Iconv);
-}
-
-static Prog *bigP;
-
-int
-Pconv(Fmt *fp)
-{
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- bigP = p;
- switch(p->as) {
- case ATEXT:
- if(p->from.scale) {
- fmtprint(fp, "(%d) %A %D,%d,%D",
- p->line, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- default:
- fmtprint(fp, "(%d) %A %D,%D",
- p->line, p->as, &p->from, &p->to);
- break;
- case ADATA:
- case AINIT_:
- case ADYNT_:
- fmtprint(fp, "(%d) %A %D/%d,%D",
- p->line, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- bigP = P;
- return 0;
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-char*
-xsymname(Sym *s)
-{
- if(s == nil)
- return "!!noname!!";
- return s->name;
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Adr *a;
- int i;
-
- a = va_arg(fp->args, Adr*);
- i = a->type;
- if(i >= D_INDIR && i < 2*D_INDIR) {
- if(a->offset)
- snprint(str, sizeof str, "%d(%R)", a->offset, i-D_INDIR);
- else
- snprint(str, sizeof str, "(%R)", i-D_INDIR);
- goto brk;
- }
- switch(i) {
-
- default:
- snprint(str, sizeof str, "%R", i);
- break;
-
- case D_NONE:
- str[0] = 0;
- break;
-
- case D_BRANCH:
- if(bigP != P && bigP->pcond != P)
- if(a->sym != S)
- snprint(str, sizeof str, "%ux+%s", bigP->pcond->pc,
- a->sym->name);
- else
- snprint(str, sizeof str, "%ux", bigP->pcond->pc);
- else
- snprint(str, sizeof str, "%d(PC)", a->offset);
- break;
-
- case D_EXTERN:
- snprint(str, sizeof str, "%s+%d(SB)", xsymname(a->sym), a->offset);
- break;
-
- case D_STATIC:
- snprint(str, sizeof str, "%s<%d>+%d(SB)", xsymname(a->sym),
- a->sym->version, a->offset);
- break;
-
- case D_AUTO:
- snprint(str, sizeof str, "%s+%d(SP)", xsymname(a->sym), a->offset);
- break;
-
- case D_PARAM:
- if(a->sym)
- snprint(str, sizeof str, "%s+%d(FP)", a->sym->name, a->offset);
- else
- snprint(str, sizeof str, "%d(FP)", a->offset);
- break;
-
- case D_CONST:
- snprint(str, sizeof str, "$%d", a->offset);
- break;
-
- case D_CONST2:
- snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
- break;
-
- case D_FCONST:
- snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
- break;
-
- case D_SCONST:
- snprint(str, sizeof str, "$\"%S\"", a->scon);
- break;
-
- case D_ADDR:
- a->type = a->index;
- a->index = D_NONE;
- snprint(str, sizeof str, "$%D", a);
- a->index = a->type;
- a->type = D_ADDR;
- goto conv;
- }
-brk:
- if(a->index != D_NONE) {
- sprint(s, "(%R*%d)", (int)a->index, a->scale);
- strcat(str, s);
- }
-conv:
- fmtstrcpy(fp, str);
-// if(a->gotype)
-// fmtprint(fp, "«%s»", a->gotype->name);
- return 0;
-}
-
-char* regstr[] =
-{
- "AL", /* [D_AL] */
- "CL",
- "DL",
- "BL",
- "AH",
- "CH",
- "DH",
- "BH",
-
- "AX", /* [D_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
-
- "F0", /* [D_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "CS", /* [D_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
-
- "CR0", /* [D_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
-
- "DR0", /* [D_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [D_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "NONE", /* [D_NONE] */
-};
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r >= D_AL && r <= D_NONE)
- sprint(str, "%s", regstr[r-D_AL]);
- else
- sprint(str, "gok(%d)", r);
-
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(double); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- 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);
-}
-
-int
-Iconv(Fmt *fp)
-{
- int i, n;
- uchar *p;
- char *s;
- Fmt fmt;
-
- n = fp->prec;
- fp->prec = 0;
- if(!(fp->flags&FmtPrec) || n < 0)
- return fmtstrcpy(fp, "%I");
- fp->flags &= ~FmtPrec;
- p = va_arg(fp->args, uchar*);
-
- // format into temporary buffer and
- // call fmtstrcpy to handle padding.
- fmtstrinit(&fmt);
- for(i=0; i<n; i++)
- fmtprint(&fmt, "%.2ux", *p++);
- s = fmtstrflush(&fmt);
- fmtstrcpy(fp, s);
- free(s);
- return 0;
-}
-
-void
-diag(char *fmt, ...)
-{
- char buf[STRINGSZ], *tn, *sep;
- va_list arg;
-
- tn = "";
- sep = "";
- if(cursym != S) {
- tn = cursym->name;
- sep = ": ";
- }
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- print("%s%s%s\n", tn, sep, buf);
-
- nerrors++;
- if(nerrors > 20) {
- print("too many errors\n");
- errorexit();
- }
-}
diff --git a/src/cmd/8l/mkenam b/src/cmd/8l/mkenam
deleted file mode 100644
index 992aa3160..000000000
--- a/src/cmd/8l/mkenam
+++ /dev/null
@@ -1,45 +0,0 @@
-# Inferno utils/8c/mkenam
-# http://code.google.com/p/inferno-os/source/browse/utils/8c/mkenam
-#
-# 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.
-
-awk '
-BEGIN {
- print "char* anames[] ="
- print "{"
-}
-
-/^ A/ {
- name=$1
- sub(/,/, "", name)
- sub(/^A/, "", name)
- print "\t\"" name "\","
-}
-
-END { print "};" }
-' ../8l/8.out.h >enam.c
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
deleted file mode 100644
index ce7b59518..000000000
--- a/src/cmd/8l/obj.c
+++ /dev/null
@@ -1,740 +0,0 @@
-// Inferno utils/8l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/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.
-
-#define EXTERN
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-#include "../ld/macho.h"
-#include "../ld/dwarf.h"
-#include "../ld/pe.h"
-#include <ar.h>
-
-#ifndef DEFAULT
-#define DEFAULT '9'
-#endif
-
-char *noname = "<none>";
-char *thestring = "386";
-
-Header headers[] = {
- "garbunix", Hgarbunix,
- "unixcoff", Hunixcoff,
- "plan9", Hplan9x32,
- "msdoscom", Hmsdoscom,
- "msdosexe", Hmsdosexe,
- "darwin", Hdarwin,
- "linux", Hlinux,
- "freebsd", Hfreebsd,
- "windows", Hwindows,
- "windowsgui", Hwindows,
- 0, 0
-};
-
-/*
- * -Hgarbunix -T0x40004C -D0x10000000 is garbage unix
- * -Hunixcoff -T0xd0 -R4 is unix coff
- * -Hplan9 -T4128 -R4096 is plan9 format
- * -Hmsdoscom -Tx -Rx is MS-DOS .COM
- * -Hmsdosexe -Tx -Rx is fake MS-DOS .EXE
- * -Hdarwin -Tx -Rx is Apple Mach-O
- * -Hlinux -Tx -Rx is Linux ELF32
- * -Hfreebsd -Tx -Rx is FreeBSD ELF32
- * -Hwindows -Tx -Rx is MS Windows PE32
- */
-
-void
-usage(void)
-{
- fprint(2, "usage: 8l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.8\n");
- exits("usage");
-}
-
-void
-main(int argc, char *argv[])
-{
- int c;
-
- Binit(&bso, 1, OWRITE);
- cout = -1;
- listinit();
- memset(debug, 0, sizeof(debug));
- nerrors = 0;
- outfile = nil;
- HEADTYPE = -1;
- INITTEXT = -1;
- INITDAT = -1;
- INITRND = -1;
- INITENTRY = 0;
-
- ARGBEGIN {
- default:
- c = ARGC();
- if(c == 'l')
- usage();
- if(c >= 0 && c < sizeof(debug))
- debug[c]++;
- break;
- case 'o': /* output to (next arg) */
- outfile = EARGF(usage());
- break;
- case 'E':
- INITENTRY = EARGF(usage());
- break;
- case 'H':
- HEADTYPE = headtype(EARGF(usage()));
- break;
- case 'I':
- interpreter = EARGF(usage());
- break;
- case 'L':
- Lflag(EARGF(usage()));
- break;
- case 'T':
- INITTEXT = atolwhex(EARGF(usage()));
- break;
- case 'D':
- INITDAT = atolwhex(EARGF(usage()));
- break;
- case 'R':
- INITRND = atolwhex(EARGF(usage()));
- break;
- case 'r':
- rpath = EARGF(usage());
- break;
- case 'V':
- print("%cl version %s\n", thechar, getgoversion());
- errorexit();
- } ARGEND
-
- if(argc != 1)
- usage();
-
- mywhatsys(); // get goos
-
- if(HEADTYPE == -1)
- HEADTYPE = headtype(goos);
-
- if(outfile == nil) {
- if(HEADTYPE == Hwindows)
- outfile = "8.out.exe";
- else
- outfile = "8.out";
- }
-
- libinit();
-
- switch(HEADTYPE) {
- default:
- diag("unknown -H option");
- errorexit();
-
- case Hgarbunix: /* this is garbage */
- HEADR = 20L+56L;
- if(INITTEXT == -1)
- INITTEXT = 0x40004CL;
- if(INITDAT == -1)
- INITDAT = 0x10000000L;
- if(INITRND == -1)
- INITRND = 0;
- break;
- case Hunixcoff: /* is unix coff */
- HEADR = 0xd0L;
- if(INITTEXT == -1)
- INITTEXT = 0xd0;
- if(INITDAT == -1)
- INITDAT = 0x400000;
- if(INITRND == -1)
- INITRND = 0;
- break;
- case Hplan9x32: /* plan 9 */
- tlsoffset = -8;
- HEADR = 32L;
- if(INITTEXT == -1)
- INITTEXT = 4096+32;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Hmsdoscom: /* MS-DOS .COM */
- HEADR = 0;
- if(INITTEXT == -1)
- INITTEXT = 0x0100;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hmsdosexe: /* fake MS-DOS .EXE */
- HEADR = 0x200;
- if(INITTEXT == -1)
- INITTEXT = 0x0100;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- HEADR += (INITTEXT & 0xFFFF);
- if(debug['v'])
- Bprint(&bso, "HEADR = 0x%d\n", HEADR);
- break;
- case Hdarwin: /* apple MACH */
- /*
- * OS X system constant - offset from %gs to our TLS.
- * Explained in ../../libcgo/darwin_386.c.
- */
- tlsoffset = 0x468;
- machoinit();
- HEADR = INITIAL_MACHO_HEADR;
- if(INITTEXT == -1)
- INITTEXT = 4096+HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Hlinux: /* elf32 executable */
- case Hfreebsd:
- /*
- * ELF uses TLS offsets negative from %gs.
- * Translate 0(GS) and 4(GS) into -8(GS) and -4(GS).
- * Also known to ../../pkg/runtime/linux/386/sys.s
- * and ../../libcgo/linux_386.c.
- */
- tlsoffset = -8;
- elfinit();
- HEADR = ELFRESERVE;
- if(INITTEXT == -1)
- INITTEXT = 0x08048000+HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Hwindows: /* PE executable */
- peinit();
- HEADR = PEFILEHEADR;
- if(INITTEXT == -1)
- INITTEXT = PEBASE+PESECTHEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = PESECTALIGN;
- break;
- }
- if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%ux is ignored because of -R0x%ux\n",
- INITDAT, INITRND);
- if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
- HEADTYPE, INITTEXT, INITDAT, INITRND);
- Bflush(&bso);
-
- instinit();
- zprg.link = P;
- zprg.pcond = P;
- zprg.back = 2;
- zprg.as = AGOK;
- zprg.from.type = D_NONE;
- zprg.from.index = D_NONE;
- zprg.from.scale = 1;
- zprg.to = zprg.from;
-
- pcstr = "%.6ux ";
- nuxiinit();
- histgen = 0;
- pc = 0;
- dtype = 4;
- version = 0;
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
-
- addlibpath("command line", "command line", argv[0], "main");
- loadlib();
- deadcode();
- patch();
- follow();
- doelf();
- if(HEADTYPE == Hdarwin)
- domacho();
- if(HEADTYPE == Hwindows)
- dope();
- dostkoff();
- if(debug['p'])
- if(debug['1'])
- doprof1();
- else
- doprof2();
- span();
- addexport();
- textaddress();
- pclntab();
- symtab();
- dodata();
- address();
- doweak();
- reloc();
- asmb();
- undef();
- if(debug['v']) {
- Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%d symbols\n", nsymbol);
- Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
- Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
- }
- Bflush(&bso);
-
- errorexit();
-}
-
-static Sym*
-zsym(char *pn, Biobuf *f, Sym *h[])
-{
- int o;
-
- o = Bgetc(f);
- if(o < 0 || o >= NSYM || h[o] == nil)
- mangle(pn);
- return h[o];
-}
-
-static void
-zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
-{
- int t;
- int32 l;
- Sym *s;
- Auto *u;
-
- t = Bgetc(f);
- a->index = D_NONE;
- a->scale = 0;
- if(t & T_INDEX) {
- a->index = Bgetc(f);
- a->scale = Bgetc(f);
- }
- a->type = D_NONE;
- a->offset = 0;
- if(t & T_OFFSET)
- a->offset = Bget4(f);
- a->offset2 = 0;
- if(t & T_OFFSET2) {
- a->offset2 = Bget4(f);
- a->type = D_CONST2;
- }
- a->sym = S;
- if(t & T_SYM)
- a->sym = zsym(pn, f, h);
- if(t & T_FCONST) {
- a->ieee.l = Bget4(f);
- a->ieee.h = Bget4(f);
- a->type = D_FCONST;
- } else
- if(t & T_SCONST) {
- Bread(f, a->scon, NSNAME);
- a->type = D_SCONST;
- }
- if(t & T_TYPE)
- a->type = Bgetc(f);
- adrgotype = S;
- if(t & T_GOTYPE)
- adrgotype = zsym(pn, f, h);
-
- t = a->type;
- if(t == D_INDIR+D_GS)
- a->offset += tlsoffset;
-
- s = a->sym;
- if(s == S)
- return;
- if(t != D_AUTO && t != D_PARAM) {
- if(adrgotype)
- s->gotype = adrgotype;
- return;
- }
- l = a->offset;
- for(u=curauto; u; u=u->link) {
- if(u->asym == s)
- if(u->type == t) {
- if(u->aoffset > l)
- u->aoffset = l;
- if(adrgotype)
- u->gotype = adrgotype;
- return;
- }
- }
-
- u = mal(sizeof(*u));
- u->link = curauto;
- curauto = u;
- u->asym = s;
- u->aoffset = l;
- u->type = t;
- u->gotype = adrgotype;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
-}
-
-void
-ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- int32 ipc;
- Prog *p;
- int v, o, r, skip;
- Sym *h[NSYM], *s;
- uint32 sig;
- int ntext;
- int32 eof;
- char *name, *x;
- char src[1024];
- Prog *lastp;
-
- lastp = nil;
- ntext = 0;
- eof = Boffset(f) + len;
- src[0] = 0;
-
-
-newloop:
- memset(h, 0, sizeof(h));
- version++;
- histfrogp = 0;
- ipc = pc;
- skip = 0;
-
-loop:
- if(f->state == Bracteof || Boffset(f) >= eof)
- goto eof;
- o = Bgetc(f);
- if(o == Beof)
- goto eof;
- o |= Bgetc(f) << 8;
- if(o <= AXXX || o >= ALAST) {
- if(o < 0)
- goto eof;
- diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
- print(" probably not a .%c file\n", thechar);
- errorexit();
- }
-
- if(o == ANAME || o == ASIGNAME) {
- sig = 0;
- if(o == ASIGNAME)
- sig = Bget4(f);
- v = Bgetc(f); /* type */
- o = Bgetc(f); /* sym */
- r = 0;
- if(v == D_STATIC)
- r = version;
- name = Brdline(f, '\0');
- if(name == nil) {
- if(Blinelen(f) > 0) {
- fprint(2, "%s: name too long\n", pn);
- errorexit();
- }
- goto eof;
- }
- x = expandpkg(name, pkg);
- s = lookup(x, r);
- if(x != name)
- free(x);
-
- if(debug['S'] && r == 0)
- sig = 1729;
- if(sig != 0){
- if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures"
- "%ux(%s) and %ux(%s) for %s",
- s->sig, s->file, sig, pn, s->name);
- s->sig = sig;
- s->file = pn;
- }
-
- if(debug['W'])
- print(" ANAME %s\n", s->name);
- if(o < 0 || o >= nelem(h))
- mangle(pn);
- h[o] = s;
- if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
- s->type = SXREF;
- if(v == D_FILE) {
- if(s->type != SFILE) {
- histgen++;
- s->type = SFILE;
- s->value = histgen;
- }
- if(histfrogp < MAXHIST) {
- histfrog[histfrogp] = s;
- histfrogp++;
- } else
- collapsefrog(s);
- dwarfaddfrag(s->value, s->name);
- }
- goto loop;
- }
-
- p = mal(sizeof(*p));
- p->as = o;
- p->line = Bget4(f);
- p->back = 2;
- p->ft = 0;
- p->tt = 0;
- zaddr(pn, f, &p->from, h);
- fromgotype = adrgotype;
- zaddr(pn, f, &p->to, h);
-
- if(debug['W'])
- print("%P\n", p);
-
- switch(p->as) {
- case AHISTORY:
- if(p->to.offset == -1) {
- addlib(src, pn);
- histfrogp = 0;
- goto loop;
- }
- if(src[0] == '\0')
- copyhistfrog(src, sizeof src);
- addhist(p->line, D_FILE); /* 'z' */
- if(p->to.offset)
- addhist(p->to.offset, D_FILE1); /* 'Z' */
- histfrogp = 0;
- goto loop;
-
- case AEND:
- histtoauto();
- if(cursym != nil && cursym->text)
- cursym->autom = curauto;
- curauto = 0;
- cursym = nil;
- if(Boffset(f) == eof)
- return;
- goto newloop;
-
- case AGLOBL:
- s = p->from.sym;
- if(s->type == 0 || s->type == SXREF) {
- s->type = SBSS;
- s->size = 0;
- }
- if(s->type != SBSS && !s->dupok) {
- diag("%s: redefinition: %s in %s",
- pn, s->name, TNAME);
- s->type = SBSS;
- s->size = 0;
- }
- if(p->to.offset > s->size)
- s->size = p->to.offset;
- if(p->from.scale & DUPOK)
- s->dupok = 1;
- if(p->from.scale & RODATA)
- s->type = SRODATA;
- goto loop;
-
- case ADATA:
- // Assume that AGLOBL comes after ADATA.
- // If we've seen an AGLOBL that said this sym was DUPOK,
- // ignore any more ADATA we see, which must be
- // redefinitions.
- s = p->from.sym;
- if(s->dupok) {
-// if(debug['v'])
-// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
- goto loop;
- }
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
- savedata(s, p, pn);
- unmal(p, sizeof *p);
- goto loop;
-
- case AGOK:
- diag("%s: GOK opcode in %s", pn, TNAME);
- pc++;
- goto loop;
-
- case ATEXT:
- s = p->from.sym;
- if(s->text != nil) {
- diag("%s: %s: redefinition", pn, s->name);
- return;
- }
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- diag("skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- if(cursym != nil && cursym->text) {
- histtoauto();
- cursym->autom = curauto;
- curauto = 0;
- }
- skip = 0;
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- s->text = p;
- cursym = s;
- if(s->type != 0 && s->type != SXREF) {
- if(p->from.scale & DUPOK) {
- skip = 1;
- goto casdef;
- }
- diag("%s: redefinition: %s\n%P", pn, s->name, p);
- }
- s->type = STEXT;
- s->value = pc;
- lastp = p;
- p->pc = pc++;
- goto loop;
-
- case AFMOVF:
- case AFADDF:
- case AFSUBF:
- case AFSUBRF:
- case AFMULF:
- case AFDIVF:
- case AFDIVRF:
- case AFCOMF:
- case AFCOMFP:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 9 max */
- sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SDATA;
- adduint32(s, ieeedtof(&p->from.ieee));
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- case AFMOVD:
- case AFADDD:
- case AFSUBD:
- case AFSUBRD:
- case AFMULD:
- case AFDIVD:
- case AFDIVRD:
- case AFCOMD:
- case AFCOMDP:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 18 max */
- sprint(literal, "$%ux.%ux",
- p->from.ieee.l, p->from.ieee.h);
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SDATA;
- adduint32(s, p->from.ieee.l);
- adduint32(s, p->from.ieee.h);
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- casdef:
- default:
- if(skip)
- nopout(p);
- p->pc = pc;
- pc++;
-
- if(p->to.type == D_BRANCH)
- p->to.offset += ipc;
- if(lastp == nil) {
- if(p->as != ANOP)
- diag("unexpected instruction: %P", p);
- goto loop;
- }
- lastp->link = p;
- lastp = p;
- goto loop;
- }
-
-eof:
- diag("truncated object file: %s", pn);
-}
-
-Prog*
-prg(void)
-{
- Prog *p;
-
- p = mal(sizeof(Prog));
- *p = zprg;
- return p;
-}
-
-Prog*
-copyp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- *p = *q;
- return p;
-}
-
-Prog*
-appendp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- p->link = q->link;
- q->link = p;
- p->line = q->line;
- return p;
-}
diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c
deleted file mode 100644
index 1e89a2105..000000000
--- a/src/cmd/8l/optab.c
+++ /dev/null
@@ -1,754 +0,0 @@
-// Inferno utils/8l/optab.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/optab.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 "l.h"
-
-uchar ynone[] =
-{
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar ytext[] =
-{
- Ymb, Yi32, Zpseudo,1,
- 0
-};
-uchar ynop[] =
-{
- Ynone, Ynone, Zpseudo,1,
- Ynone, Yml, Zpseudo,1,
- Ynone, Yrf, Zpseudo,1,
- Yml, Ynone, Zpseudo,1,
- Yrf, Ynone, Zpseudo,1,
- 0
-};
-uchar yxorb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yxorl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yaddl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yincb[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yincl[] =
-{
- Ynone, Yrl, Z_rp, 1,
- Ynone, Yml, Zo_m, 2,
- 0
-};
-uchar ycmpb[] =
-{
- Yal, Yi32, Z_ib, 1,
- Ymb, Yi32, Zm_ibo, 2,
- Ymb, Yrb, Zm_r, 1,
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar ycmpl[] =
-{
- Yml, Yi8, Zm_ibo, 2,
- Yax, Yi32, Z_il, 1,
- Yml, Yi32, Zm_ilo, 2,
- Yml, Yrl, Zm_r, 1,
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yshb[] =
-{
- Yi1, Ymb, Zo_m, 2,
- Yi32, Ymb, Zibo_m, 2,
- Ycx, Ymb, Zo_m, 2,
- 0
-};
-uchar yshl[] =
-{
- Yi1, Yml, Zo_m, 2,
- Yi32, Yml, Zibo_m, 2,
- Ycl, Yml, Zo_m, 2,
- Ycx, Yml, Zo_m, 2,
- 0
-};
-uchar ytestb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar ytestl[] =
-{
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ymovb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- Yi32, Yrb, Zib_rp, 1,
- Yi32, Ymb, Zibo_m, 2,
- 0
-};
-uchar ymovl[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1+2,
-// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yiauto, Yrl, Zaut_r, 2,
- 0
-};
-uchar ym_rl[] =
-{
- Ym, Yrl, Zm_r, 1,
- 0
-};
-uchar yrl_m[] =
-{
- Yrl, Ym, Zr_m, 1,
- 0
-};
-uchar ymb_rl[] =
-{
- Ymb, Yrl, Zm_r, 1,
- 0
-};
-uchar yml_rl[] =
-{
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yrb_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar yrl_ml[] =
-{
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yml_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yml_ml[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ydivl[] =
-{
- Yml, Ynone, Zm_o, 2,
- 0
-};
-uchar ydivb[] =
-{
- Ymb, Ynone, Zm_o, 2,
- 0
-};
-uchar yimul[] =
-{
- Yml, Ynone, Zm_o, 2,
- Yi8, Yrl, Zib_rr, 1,
- Yi32, Yrl, Zil_rr, 1,
- 0
-};
-uchar ybyte[] =
-{
- Yi32, Ynone, Zbyte, 1,
- 0
-};
-uchar yin[] =
-{
- Yi32, Ynone, Zib_, 1,
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar yint[] =
-{
- Yi32, Ynone, Zib_, 1,
- 0
-};
-uchar ypushl[] =
-{
- Yrl, Ynone, Zrp_, 1,
- Ym, Ynone, Zm_o, 2,
- Yi8, Ynone, Zib_, 1,
- Yi32, Ynone, Zil_, 1,
- 0
-};
-uchar ypopl[] =
-{
- Ynone, Yrl, Z_rp, 1,
- Ynone, Ym, Zo_m, 2,
- 0
-};
-uchar yscond[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yjcond[] =
-{
- Ynone, Ybr, Zbr, 1,
- 0
-};
-uchar yloop[] =
-{
- Ynone, Ybr, Zloop, 1,
- 0
-};
-uchar ycall[] =
-{
- Ynone, Yml, Zo_m, 2,
- Ynone, Ybr, Zcall, 0,
- Ynone, Yi32, Zcallcon, 1,
- 0
-};
-uchar yjmp[] =
-{
- Ynone, Yml, Zo_m, 2,
- Ynone, Ybr, Zjmp, 0,
- Ynone, Yi32, Zjmpcon, 1,
- 0
-};
-
-uchar yfmvd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvdp[] =
-{
- Yf0, Ym, Zo_m, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvf[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfmvx[] =
-{
- Ym, Yf0, Zm_o, 2,
- 0
-};
-uchar yfmvp[] =
-{
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfcmv[] =
-{
- Yrf, Yf0, Zm_o, 2,
- 0
-};
-uchar yfadd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfaddp[] =
-{
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfxch[] =
-{
- Yf0, Yrf, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- 0
-};
-uchar ycompp[] =
-{
- Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
- 0
-};
-uchar ystsw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ynone, Yax, Zlit, 1,
- 0
-};
-uchar ystcw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ysvrs[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-
-Optab optab[] =
-/* as, ytab, andproto, opcode */
-{
- { AXXX },
- { AAAA, ynone, Px, 0x37 },
- { AAAD, ynone, Px, 0xd5,0x0a },
- { AAAM, ynone, Px, 0xd4,0x0a },
- { AAAS, ynone, Px, 0x3f },
- { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
- { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 },
- { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADJSP },
- { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
- { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AARPL, yrl_ml, Px, 0x63 },
- { ABOUNDL, yrl_m, Px, 0x62 },
- { ABOUNDW, yrl_m, Pe, 0x62 },
- { ABSFL, yml_rl, Pm, 0xbc },
- { ABSFW, yml_rl, Pq, 0xbc },
- { ABSRL, yml_rl, Pm, 0xbd },
- { ABSRW, yml_rl, Pq, 0xbd },
- { ABTL, yml_rl, Pm, 0xa3 },
- { ABTW, yml_rl, Pq, 0xa3 },
- { ABTCL, yml_rl, Pm, 0xbb },
- { ABTCW, yml_rl, Pq, 0xbb },
- { ABTRL, yml_rl, Pm, 0xb3 },
- { ABTRW, yml_rl, Pq, 0xb3 },
- { ABTSL, yml_rl, Pm, 0xab },
- { ABTSW, yml_rl, Pq, 0xab },
- { ABYTE, ybyte, Px, 1 },
- { ACALL, ycall, Px, 0xff,(02),0xe8 },
- { ACLC, ynone, Px, 0xf8 },
- { ACLD, ynone, Px, 0xfc },
- { ACLI, ynone, Px, 0xfa },
- { ACLTS, ynone, Pm, 0x06 },
- { ACMC, ynone, Px, 0xf5 },
- { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
- { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPSB, ynone, Pb, 0xa6 },
- { ACMPSL, ynone, Px, 0xa7 },
- { ACMPSW, ynone, Pe, 0xa7 },
- { ADAA, ynone, Px, 0x27 },
- { ADAS, ynone, Px, 0x2f },
- { ADATA },
- { ADECB, yincb, Pb, 0xfe,(01) },
- { ADECL, yincl, Px, 0x48,0xff,(01) },
- { ADECW, yincl, Pe, 0x48,0xff,(01) },
- { ADIVB, ydivb, Pb, 0xf6,(06) },
- { ADIVL, ydivl, Px, 0xf7,(06) },
- { ADIVW, ydivl, Pe, 0xf7,(06) },
- { AENTER }, /* botch */
- { AGLOBL },
- { AGOK },
- { AHISTORY },
- { AHLT, ynone, Px, 0xf4 },
- { AIDIVB, ydivb, Pb, 0xf6,(07) },
- { AIDIVL, ydivl, Px, 0xf7,(07) },
- { AIDIVW, ydivl, Pe, 0xf7,(07) },
- { AIMULB, ydivb, Pb, 0xf6,(05) },
- { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 },
- { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 },
- { AINB, yin, Pb, 0xe4,0xec },
- { AINL, yin, Px, 0xe5,0xed },
- { AINW, yin, Pe, 0xe5,0xed },
- { AINCB, yincb, Pb, 0xfe,(00) },
- { AINCL, yincl, Px, 0x40,0xff,(00) },
- { AINCW, yincl, Pe, 0x40,0xff,(00) },
- { AINSB, ynone, Pb, 0x6c },
- { AINSL, ynone, Px, 0x6d },
- { AINSW, ynone, Pe, 0x6d },
- { AINT, yint, Px, 0xcd },
- { AINTO, ynone, Px, 0xce },
- { AIRETL, ynone, Px, 0xcf },
- { AIRETW, ynone, Pe, 0xcf },
- { AJCC, yjcond, Px, 0x73,0x83,(00) },
- { AJCS, yjcond, Px, 0x72,0x82 },
- { AJCXZ, yloop, Px, 0xe3 },
- { AJEQ, yjcond, Px, 0x74,0x84 },
- { AJGE, yjcond, Px, 0x7d,0x8d },
- { AJGT, yjcond, Px, 0x7f,0x8f },
- { AJHI, yjcond, Px, 0x77,0x87 },
- { AJLE, yjcond, Px, 0x7e,0x8e },
- { AJLS, yjcond, Px, 0x76,0x86 },
- { AJLT, yjcond, Px, 0x7c,0x8c },
- { AJMI, yjcond, Px, 0x78,0x88 },
- { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
- { AJNE, yjcond, Px, 0x75,0x85 },
- { AJOC, yjcond, Px, 0x71,0x81,(00) },
- { AJOS, yjcond, Px, 0x70,0x80,(00) },
- { AJPC, yjcond, Px, 0x7b,0x8b },
- { AJPL, yjcond, Px, 0x79,0x89 },
- { AJPS, yjcond, Px, 0x7a,0x8a },
- { ALAHF, ynone, Px, 0x9f },
- { ALARL, yml_rl, Pm, 0x02 },
- { ALARW, yml_rl, Pq, 0x02 },
- { ALEAL, ym_rl, Px, 0x8d },
- { ALEAW, ym_rl, Pe, 0x8d },
- { ALEAVEL, ynone, Px, 0xc9 },
- { ALEAVEW, ynone, Pe, 0xc9 },
- { ALOCK, ynone, Px, 0xf0 },
- { ALODSB, ynone, Pb, 0xac },
- { ALODSL, ynone, Px, 0xad },
- { ALODSW, ynone, Pe, 0xad },
- { ALONG, ybyte, Px, 4 },
- { ALOOP, yloop, Px, 0xe2 },
- { ALOOPEQ, yloop, Px, 0xe1 },
- { ALOOPNE, yloop, Px, 0xe0 },
- { ALSLL, yml_rl, Pm, 0x03 },
- { ALSLW, yml_rl, Pq, 0x03 },
- { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
- { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
- { AMOVW, ymovl, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
- { AMOVBLSX, ymb_rl, Pm, 0xbe },
- { AMOVBLZX, ymb_rl, Pm, 0xb6 },
- { AMOVBWSX, ymb_rl, Pq, 0xbe },
- { AMOVBWZX, ymb_rl, Pq, 0xb6 },
- { AMOVWLSX, yml_rl, Pm, 0xbf },
- { AMOVWLZX, yml_rl, Pm, 0xb7 },
- { AMOVSB, ynone, Pb, 0xa4 },
- { AMOVSL, ynone, Px, 0xa5 },
- { AMOVSW, ynone, Pe, 0xa5 },
- { AMULB, ydivb, Pb, 0xf6,(04) },
- { AMULL, ydivl, Px, 0xf7,(04) },
- { AMULW, ydivl, Pe, 0xf7,(04) },
- { ANAME },
- { ANEGB, yscond, Px, 0xf6,(03) },
- { ANEGL, yscond, Px, 0xf7,(03) },
- { ANEGW, yscond, Pe, 0xf7,(03) },
- { ANOP, ynop, Px,0,0 },
- { ANOTB, yscond, Px, 0xf6,(02) },
- { ANOTL, yscond, Px, 0xf7,(02) },
- { ANOTW, yscond, Pe, 0xf7,(02) },
- { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
- { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AOUTB, yin, Pb, 0xe6,0xee },
- { AOUTL, yin, Px, 0xe7,0xef },
- { AOUTW, yin, Pe, 0xe7,0xef },
- { AOUTSB, ynone, Pb, 0x6e },
- { AOUTSL, ynone, Px, 0x6f },
- { AOUTSW, ynone, Pe, 0x6f },
- { APOPAL, ynone, Px, 0x61 },
- { APOPAW, ynone, Pe, 0x61 },
- { APOPFL, ynone, Px, 0x9d },
- { APOPFW, ynone, Pe, 0x9d },
- { APOPL, ypopl, Px, 0x58,0x8f,(00) },
- { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
- { APUSHAL, ynone, Px, 0x60 },
- { APUSHAW, ynone, Pe, 0x60 },
- { APUSHFL, ynone, Px, 0x9c },
- { APUSHFW, ynone, Pe, 0x9c },
- { APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 },
- { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
- { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
- { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
- { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { AREP, ynone, Px, 0xf3 },
- { AREPN, ynone, Px, 0xf2 },
- { ARET, ynone, Px, 0xc3 },
- { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
- { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
- { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ASAHF, ynone, Px, 0x9e },
- { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
- { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
- { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASCASB, ynone, Pb, 0xae },
- { ASCASL, ynone, Px, 0xaf },
- { ASCASW, ynone, Pe, 0xaf },
- { ASETCC, yscond, Pm, 0x93,(00) },
- { ASETCS, yscond, Pm, 0x92,(00) },
- { ASETEQ, yscond, Pm, 0x94,(00) },
- { ASETGE, yscond, Pm, 0x9d,(00) },
- { ASETGT, yscond, Pm, 0x9f,(00) },
- { ASETHI, yscond, Pm, 0x97,(00) },
- { ASETLE, yscond, Pm, 0x9e,(00) },
- { ASETLS, yscond, Pm, 0x96,(00) },
- { ASETLT, yscond, Pm, 0x9c,(00) },
- { ASETMI, yscond, Pm, 0x98,(00) },
- { ASETNE, yscond, Pm, 0x95,(00) },
- { ASETOC, yscond, Pm, 0x91,(00) },
- { ASETOS, yscond, Pm, 0x90,(00) },
- { ASETPC, yscond, Pm, 0x96,(00) },
- { ASETPL, yscond, Pm, 0x99,(00) },
- { ASETPS, yscond, Pm, 0x9a,(00) },
- { ACDQ, ynone, Px, 0x99 },
- { ACWD, ynone, Pe, 0x99 },
- { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
- { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASTC, ynone, Px, 0xf9 },
- { ASTD, ynone, Px, 0xfd },
- { ASTI, ynone, Px, 0xfb },
- { ASTOSB, ynone, Pb, 0xaa },
- { ASTOSL, ynone, Px, 0xab },
- { ASTOSW, ynone, Pe, 0xab },
- { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
- { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASYSCALL, ynone, Px, 0xcd,100 },
- { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
- { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
- { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
- { ATEXT, ytext, Px },
- { AVERR, ydivl, Pm, 0x00,(04) },
- { AVERW, ydivl, Pm, 0x00,(05) },
- { AWAIT, ynone, Px, 0x9b },
- { AWORD, ybyte, Px, 2 },
- { AXCHGB, yml_mb, Pb, 0x86,0x86 },
- { AXCHGL, yml_ml, Px, 0x87,0x87 },
- { AXCHGW, yml_ml, Pe, 0x87,0x87 },
- { AXLAT, ynone, Px, 0xd7 },
- { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
- { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
- { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
-
- { AFMOVB, yfmvx, Px, 0xdf,(04) },
- { AFMOVBP, yfmvp, Px, 0xdf,(06) },
- { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
- { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
- { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
- { AFMOVFP, yfmvp, Px, 0xd9,(03) },
- { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
- { AFMOVLP, yfmvp, Px, 0xdb,(03) },
- { AFMOVV, yfmvx, Px, 0xdf,(05) },
- { AFMOVVP, yfmvp, Px, 0xdf,(07) },
- { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
- { AFMOVWP, yfmvp, Px, 0xdf,(03) },
- { AFMOVX, yfmvx, Px, 0xdb,(05) },
- { AFMOVXP, yfmvp, Px, 0xdb,(07) },
-
- { AFCOMB },
- { AFCOMBP },
- { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
- { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
- { AFCOMDPP, ycompp, Px, 0xde,(03) },
- { AFCOMF, yfmvx, Px, 0xd8,(02) },
- { AFCOMFP, yfmvx, Px, 0xd8,(03) },
- { AFCOMI, yfmvx, Px, 0xdb,(06) },
- { AFCOMIP, yfmvx, Px, 0xdf,(06) },
- { AFCOML, yfmvx, Px, 0xda,(02) },
- { AFCOMLP, yfmvx, Px, 0xda,(03) },
- { AFCOMW, yfmvx, Px, 0xde,(02) },
- { AFCOMWP, yfmvx, Px, 0xde,(03) },
-
- { AFUCOM, ycompp, Px, 0xdd,(04) },
- { AFUCOMI, ycompp, Px, 0xdb,(05) },
- { AFUCOMIP, ycompp, Px, 0xdf,(05) },
- { AFUCOMP, ycompp, Px, 0xdd,(05) },
- { AFUCOMPP, ycompp, Px, 0xda,(13) },
-
- { AFADDDP, yfaddp, Px, 0xde,(00) },
- { AFADDW, yfmvx, Px, 0xde,(00) },
- { AFADDL, yfmvx, Px, 0xda,(00) },
- { AFADDF, yfmvx, Px, 0xd8,(00) },
- { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
-
- { AFMULDP, yfaddp, Px, 0xde,(01) },
- { AFMULW, yfmvx, Px, 0xde,(01) },
- { AFMULL, yfmvx, Px, 0xda,(01) },
- { AFMULF, yfmvx, Px, 0xd8,(01) },
- { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
-
- { AFSUBDP, yfaddp, Px, 0xde,(05) },
- { AFSUBW, yfmvx, Px, 0xde,(04) },
- { AFSUBL, yfmvx, Px, 0xda,(04) },
- { AFSUBF, yfmvx, Px, 0xd8,(04) },
- { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
-
- { AFSUBRDP, yfaddp, Px, 0xde,(04) },
- { AFSUBRW, yfmvx, Px, 0xde,(05) },
- { AFSUBRL, yfmvx, Px, 0xda,(05) },
- { AFSUBRF, yfmvx, Px, 0xd8,(05) },
- { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
-
- { AFDIVDP, yfaddp, Px, 0xde,(07) },
- { AFDIVW, yfmvx, Px, 0xde,(06) },
- { AFDIVL, yfmvx, Px, 0xda,(06) },
- { AFDIVF, yfmvx, Px, 0xd8,(06) },
- { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
-
- { AFDIVRDP, yfaddp, Px, 0xde,(06) },
- { AFDIVRW, yfmvx, Px, 0xde,(07) },
- { AFDIVRL, yfmvx, Px, 0xda,(07) },
- { AFDIVRF, yfmvx, Px, 0xd8,(07) },
- { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
-
- { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
- { AFFREE },
- { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
- { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
- { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
- { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
- { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
- { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
- { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
- { AF2XM1, ynone, Px, 0xd9, 0xf0 },
- { AFABS, ynone, Px, 0xd9, 0xe1 },
- { AFCHS, ynone, Px, 0xd9, 0xe0 },
- { AFCLEX, ynone, Px, 0xdb, 0xe2 },
- { AFCOS, ynone, Px, 0xd9, 0xff },
- { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
- { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
- { AFINIT, ynone, Px, 0xdb, 0xe3 },
- { AFLD1, ynone, Px, 0xd9, 0xe8 },
- { AFLDL2E, ynone, Px, 0xd9, 0xea },
- { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
- { AFLDLG2, ynone, Px, 0xd9, 0xec },
- { AFLDLN2, ynone, Px, 0xd9, 0xed },
- { AFLDPI, ynone, Px, 0xd9, 0xeb },
- { AFLDZ, ynone, Px, 0xd9, 0xee },
- { AFNOP, ynone, Px, 0xd9, 0xd0 },
- { AFPATAN, ynone, Px, 0xd9, 0xf3 },
- { AFPREM, ynone, Px, 0xd9, 0xf8 },
- { AFPREM1, ynone, Px, 0xd9, 0xf5 },
- { AFPTAN, ynone, Px, 0xd9, 0xf2 },
- { AFRNDINT, ynone, Px, 0xd9, 0xfc },
- { AFSCALE, ynone, Px, 0xd9, 0xfd },
- { AFSIN, ynone, Px, 0xd9, 0xfe },
- { AFSINCOS, ynone, Px, 0xd9, 0xfb },
- { AFSQRT, ynone, Px, 0xd9, 0xfa },
- { AFTST, ynone, Px, 0xd9, 0xe4 },
- { AFXAM, ynone, Px, 0xd9, 0xe5 },
- { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
- { AFYL2X, ynone, Px, 0xd9, 0xf1 },
- { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
- { AEND },
- { ADYNT_ },
- { AINIT_ },
- { ASIGNAME },
- { ACMPXCHGB, yrb_mb, Pm, 0xb0 },
- { ACMPXCHGL, yrl_ml, Pm, 0xb1 },
- { ACMPXCHGW, yrl_ml, Pm, 0xb1 },
- { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
-
- { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
- { AXADDL, yrl_ml, Pm, 0xc1 },
- { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
-
- { ACMOVLCC, yml_rl, Pm, 0x43 },
- { ACMOVLCS, yml_rl, Pm, 0x42 },
- { ACMOVLEQ, yml_rl, Pm, 0x44 },
- { ACMOVLGE, yml_rl, Pm, 0x4d },
- { ACMOVLGT, yml_rl, Pm, 0x4f },
- { ACMOVLHI, yml_rl, Pm, 0x47 },
- { ACMOVLLE, yml_rl, Pm, 0x4e },
- { ACMOVLLS, yml_rl, Pm, 0x46 },
- { ACMOVLLT, yml_rl, Pm, 0x4c },
- { ACMOVLMI, yml_rl, Pm, 0x48 },
- { ACMOVLNE, yml_rl, Pm, 0x45 },
- { ACMOVLOC, yml_rl, Pm, 0x41 },
- { ACMOVLOS, yml_rl, Pm, 0x40 },
- { ACMOVLPC, yml_rl, Pm, 0x4b },
- { ACMOVLPL, yml_rl, Pm, 0x49 },
- { ACMOVLPS, yml_rl, Pm, 0x4a },
- { ACMOVWCC, yml_rl, Pq, 0x43 },
- { ACMOVWCS, yml_rl, Pq, 0x42 },
- { ACMOVWEQ, yml_rl, Pq, 0x44 },
- { ACMOVWGE, yml_rl, Pq, 0x4d },
- { ACMOVWGT, yml_rl, Pq, 0x4f },
- { ACMOVWHI, yml_rl, Pq, 0x47 },
- { ACMOVWLE, yml_rl, Pq, 0x4e },
- { ACMOVWLS, yml_rl, Pq, 0x46 },
- { ACMOVWLT, yml_rl, Pq, 0x4c },
- { ACMOVWMI, yml_rl, Pq, 0x48 },
- { ACMOVWNE, yml_rl, Pq, 0x45 },
- { ACMOVWOC, yml_rl, Pq, 0x41 },
- { ACMOVWOS, yml_rl, Pq, 0x40 },
- { ACMOVWPC, yml_rl, Pq, 0x4b },
- { ACMOVWPL, yml_rl, Pq, 0x49 },
- { ACMOVWPS, yml_rl, Pq, 0x4a },
-
- { AFCMOVCC, yfcmv, Px, 0xdb,(00) },
- { AFCMOVCS, yfcmv, Px, 0xda,(00) },
- { AFCMOVEQ, yfcmv, Px, 0xda,(01) },
- { AFCMOVHI, yfcmv, Px, 0xdb,(02) },
- { AFCMOVLS, yfcmv, Px, 0xda,(02) },
- { AFCMOVNE, yfcmv, Px, 0xdb,(01) },
- { AFCMOVNU, yfcmv, Px, 0xdb,(03) },
- { AFCMOVUN, yfcmv, Px, 0xda,(03) },
-
- 0
-};
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
deleted file mode 100644
index 2e0990c5a..000000000
--- a/src/cmd/8l/pass.c
+++ /dev/null
@@ -1,657 +0,0 @@
-// Inferno utils/8l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.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.
-
-// Code and data passes.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../../pkg/runtime/stack.h"
-
-static void xfol(Prog*, Prog**);
-
-Prog*
-brchain(Prog *p)
-{
- int i;
-
- for(i=0; i<20; i++) {
- if(p == P || p->as != AJMP)
- return p;
- p = p->pcond;
- }
- return P;
-}
-
-void
-follow(void)
-{
- Prog *firstp, *lastp;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f follow\n", cputime());
- Bflush(&bso);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- firstp = prg();
- lastp = firstp;
- xfol(cursym->text, &lastp);
- lastp->link = nil;
- cursym->text = firstp->link;
- }
-}
-
-static int
-nofollow(int a)
-{
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
- case AIRETW:
- return 1;
- }
- return 0;
-}
-
-static int
-pushpop(int a)
-{
- switch(a) {
- case APUSHL:
- case APUSHFL:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPW:
- case APOPFW:
- return 1;
- }
- return 0;
-}
-
-static void
-xfol(Prog *p, Prog **last)
-{
- Prog *q;
- int i;
- enum as a;
-
-loop:
- if(p == P)
- return;
- if(p->as == AJMP)
- if((q = p->pcond) != P && q->as != ATEXT) {
- /* mark instruction as done and continue layout at target of jump */
- p->mark = 1;
- p = q;
- if(p->mark == 0)
- goto loop;
- }
- if(p->mark) {
- /*
- * p goes here, but already used it elsewhere.
- * copy up to 4 instructions or else branch to other copy.
- */
- for(i=0,q=p; i<4; i++,q=q->link) {
- if(q == P)
- break;
- if(q == *last)
- break;
- a = q->as;
- if(a == ANOP) {
- i--;
- continue;
- }
- if(nofollow(a) || pushpop(a))
- break; // NOTE(rsc): arm does goto copy
- if(q->pcond == P || q->pcond->mark)
- continue;
- if(a == ACALL || a == ALOOP)
- continue;
- for(;;) {
- if(p->as == ANOP) {
- p = p->link;
- continue;
- }
- q = copyp(p);
- p = p->link;
- q->mark = 1;
- (*last)->link = q;
- *last = q;
- if(q->as != a || q->pcond == P || q->pcond->mark)
- continue;
-
- q->as = relinv(q->as);
- p = q->pcond;
- q->pcond = q->link;
- q->link = p;
- xfol(q->link, last);
- p = q->link;
- if(p->mark)
- return;
- goto loop;
- }
- } /* */
- q = prg();
- q->as = AJMP;
- q->line = p->line;
- q->to.type = D_BRANCH;
- q->to.offset = p->pc;
- q->pcond = p;
- p = q;
- }
-
- /* emit p */
- p->mark = 1;
- (*last)->link = p;
- *last = p;
- a = p->as;
-
- /* continue loop with what comes after p */
- if(nofollow(a))
- return;
- if(p->pcond != P && a != ACALL) {
- /*
- * some kind of conditional branch.
- * recurse to follow one path.
- * continue loop on the other.
- */
- q = brchain(p->link);
- if(q != P && q->mark)
- if(a != ALOOP) {
- p->as = relinv(a);
- p->link = p->pcond;
- p->pcond = q;
- }
- xfol(p->link, last);
- q = brchain(p->pcond);
- if(q->mark) {
- p->pcond = q;
- return;
- }
- p = q;
- goto loop;
- }
- p = p->link;
- goto loop;
-}
-
-int
-relinv(int a)
-{
-
- switch(a) {
- case AJEQ: return AJNE;
- case AJNE: return AJEQ;
- case AJLE: return AJGT;
- case AJLS: return AJHI;
- case AJLT: return AJGE;
- case AJMI: return AJPL;
- case AJGE: return AJLT;
- case AJPL: return AJMI;
- case AJGT: return AJLE;
- case AJHI: return AJLS;
- case AJCS: return AJCC;
- case AJCC: return AJCS;
- case AJPS: return AJPC;
- case AJPC: return AJPS;
- case AJOS: return AJOC;
- case AJOC: return AJOS;
- }
- diag("unknown relation: %s in %s", anames[a], TNAME);
- return a;
-}
-
-void
-patch(void)
-{
- int32 c;
- Prog *p, *q;
- Sym *s;
- int32 vexit;
- Sym *plan9_tos;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f mkfwd\n", cputime());
- Bflush(&bso);
- mkfwd();
- if(debug['v'])
- Bprint(&bso, "%5.2f patch\n", cputime());
- Bflush(&bso);
- s = lookup("exit", 0);
- vexit = s->value;
-
- plan9_tos = S;
- if(HEADTYPE == Hplan9x32)
- plan9_tos = lookup("_tos", 0);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- if(HEADTYPE == Hwindows) {
- // Convert
- // op n(GS), reg
- // to
- // MOVL 0x2C(FS), reg
- // op n(reg), reg
- // The purpose of this patch is to fix some accesses
- // to extern register variables (TLS) on Windows, as
- // a different method is used to access them.
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x2C;
- }
- }
- if(HEADTYPE == Hlinux) {
- // Running binaries under Xen requires using
- // MOVL 0(GS), reg
- // and then off(reg) instead of saying off(GS) directly
- // when the offset is negative.
- if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0;
- }
- }
- if(HEADTYPE == Hplan9x32) {
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_EXTERN;
- p->from.sym = plan9_tos;
- p->from.offset = 0;
- }
- }
- if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
- s = p->to.sym;
- if(s) {
- if(debug['c'])
- Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- if((s->type&~SSUB) != STEXT) {
- /* diag prints TNAME first */
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- }
- if(s->text == nil)
- continue;
- p->to.type = D_BRANCH;
- p->to.offset = s->text->pc;
- p->pcond = s->text;
- continue;
- }
- }
- if(p->to.type != D_BRANCH)
- continue;
- c = p->to.offset;
- for(q = cursym->text; q != P;) {
- if(c == q->pc)
- break;
- if(q->forwd != P && c >= q->forwd->pc)
- q = q->forwd;
- else
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range in %s (%#ux)\n%P [%s]",
- TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
- p->to.type = D_NONE;
- }
- p->pcond = q;
- }
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->p != nil)
- continue;
-
- for(p = cursym->text; p != P; p = p->link) {
- p->mark = 0; /* initialization for follow */
- if(p->pcond != P) {
- p->pcond = brloop(p->pcond);
- if(p->pcond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->pcond->pc;
- }
- }
- }
-}
-
-Prog*
-brloop(Prog *p)
-{
- int c;
- Prog *q;
-
- c = 0;
- for(q = p; q != P; q = q->pcond) {
- if(q->as != AJMP)
- break;
- c++;
- if(c >= 5000)
- return P;
- }
- return q;
-}
-
-void
-dostkoff(void)
-{
- Prog *p, *q, *q1;
- int32 autoffset, deltasp;
- int a;
- Prog *pmorestack;
- Sym *symmorestack;
- Sym *plan9_tos;
-
- pmorestack = P;
- symmorestack = lookup("runtime.morestack", 0);
-
- if(symmorestack->type != STEXT)
- diag("runtime.morestack not defined");
- else {
- pmorestack = symmorestack->text;
- symmorestack->text->from.scale |= NOSPLIT;
- }
-
- plan9_tos = S;
- if(HEADTYPE == Hplan9x32)
- plan9_tos = lookup("_tos", 0);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
-
- p = cursym->text;
- autoffset = p->to.offset;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
- if(pmorestack != P)
- if(!(p->from.scale & NOSPLIT)) {
- p = appendp(p); // load g into CX
- switch(HEADTYPE) {
- case Hwindows:
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x2c;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_CX;
- break;
-
- case Hlinux:
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- break;
-
- case Hplan9x32:
- p->as = AMOVL;
- p->from.type = D_EXTERN;
- p->from.sym = plan9_tos;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- break;
-
- default:
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- }
-
- if(debug['K']) {
- // 8l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info.
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 4;
- p->to.type = D_SP;
-
- p = appendp(p);
- p->as = AJCC;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
-
- p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- }
-
- if(autoffset < StackBig) { // do we need to call morestack
- if(autoffset <= StackSmall) {
- // small stack
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_CX;
- } else {
- // large stack
- p = appendp(p);
- p->as = ALEAL;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(autoffset-StackSmall);
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_CX;
- }
-
- // common
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
- }
-
- p = appendp(p); // save frame size in DX
- p->as = AMOVL;
- p->to.type = D_DX;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
- p->from.type = D_CONST;
- if(autoffset+160+cursym->text->to.offset2 > 4096)
- p->from.offset = (autoffset+160) & ~7LL;
-
- p = appendp(p); // save arg size in AX
- p->as = AMOVL;
- p->to.type = D_AX;
- p->from.type = D_CONST;
- p->from.offset = cursym->text->to.offset2;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack;
- p->to.sym = symmorestack;
-
- }
-
- if(q != P)
- q->pcond = p->link;
-
- if(autoffset) {
- p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- p->spadj = autoffset;
- if(q != P)
- q->pcond = p;
- }
- deltasp = autoffset;
-
- for(; p != P; p = p->link) {
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + 4;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + 4;
-
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- p->spadj = 4;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- p->spadj = 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- p->spadj = -4;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- p->spadj = -2;
- continue;
- case ARET:
- break;
- }
-
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
-
- if(autoffset) {
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = -autoffset;
- p->spadj = -autoffset;
- p = appendp(p);
- p->as = ARET;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so undo
- // the cleanup.
- p->spadj = +autoffset;
- }
- }
- }
-}
-
-int32
-atolwhex(char *s)
-{
- int32 n;
- int f;
-
- n = 0;
- f = 0;
- while(*s == ' ' || *s == '\t')
- s++;
- if(*s == '-' || *s == '+') {
- if(*s++ == '-')
- f = 1;
- while(*s == ' ' || *s == '\t')
- s++;
- }
- if(s[0]=='0' && s[1]){
- if(s[1]=='x' || s[1]=='X'){
- s += 2;
- for(;;){
- if(*s >= '0' && *s <= '9')
- n = n*16 + *s++ - '0';
- else if(*s >= 'a' && *s <= 'f')
- n = n*16 + *s++ - 'a' + 10;
- else if(*s >= 'A' && *s <= 'F')
- n = n*16 + *s++ - 'A' + 10;
- else
- break;
- }
- } else
- while(*s >= '0' && *s <= '7')
- n = n*8 + *s++ - '0';
- } else
- while(*s >= '0' && *s <= '9')
- n = n*10 + *s++ - '0';
- if(f)
- n = -n;
- return n;
-}
diff --git a/src/cmd/8l/prof.c b/src/cmd/8l/prof.c
deleted file mode 100644
index d99c5e408..000000000
--- a/src/cmd/8l/prof.c
+++ /dev/null
@@ -1,173 +0,0 @@
-// Inferno utils/8l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/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.
-
-// Profiling.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-doprof1(void)
-{
-#ifdef NOTDEF // TODO(rsc)
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->size = n*4;
-#endif
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
-
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
-
- ps2 = P;
- ps4 = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
-
- if(p->from.scale & NOPROF) /* dont profile */
- continue;
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- for(; p; p=p->link) {
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
- }
- }
- }
-}
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c
deleted file mode 100644
index a4cba1257..000000000
--- a/src/cmd/8l/span.c
+++ /dev/null
@@ -1,1325 +0,0 @@
-// Inferno utils/8l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/span.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.
-
-// Instruction layout.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-static int32 vaddr(Adr*, Reloc*);
-
-void
-span1(Sym *s)
-{
- Prog *p, *q;
- int32 c, v, loop;
- uchar *bp;
- int n, m, i;
-
- cursym = s;
-
- for(p = s->text; p != P; p = p->link) {
- p->back = 2; // use short branches first time through
- if((q = p->pcond) != P && (q->back & 2))
- p->back |= 1; // backward jump
-
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = AADDL;
- if(v < 0) {
- p->as = ASUBL;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
-
- n = 0;
- do {
- loop = 0;
- memset(s->r, 0, s->nr*sizeof s->r[0]);
- s->nr = 0;
- s->np = 0;
- c = 0;
- for(p = s->text; p != P; p = p->link) {
- p->pc = c;
-
- // process forward jumps to p
- for(q = p->comefrom; q != P; q = q->forwd) {
- v = p->pc - (q->pc + q->mark);
- if(q->back & 2) { // short
- if(v > 127) {
- loop++;
- q->back ^= 2;
- }
- s->p[q->pc+1] = v;
- } else {
- bp = s->p + q->pc + q->mark - 4;
- *bp++ = v;
- *bp++ = v>>8;
- *bp++ = v>>16;
- *bp = v>>24;
- }
- }
- p->comefrom = P;
-
- asmins(p);
- p->pc = c;
- m = andptr-and;
- symgrow(s, p->pc+m);
- memmove(s->p+p->pc, and, m);
- p->mark = m;
- c += m;
- }
- if(++n > 20) {
- diag("span must be looping");
- errorexit();
- }
- } while(loop);
- s->size = c;
-
- if(debug['a'] > 1) {
- print("span1 %s %d (%d tries)\n %.6ux", s->name, s->size, n, 0);
- for(i=0; i<s->np; i++) {
- print(" %.2ux", s->p[i]);
- if(i%16 == 15)
- print("\n %.6ux", i+1);
- }
- if(i%16)
- print("\n");
-
- for(i=0; i<s->nr; i++) {
- Reloc *r;
-
- r = &s->r[i];
- print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add);
- }
- }
-}
-
-void
-span(void)
-{
- Prog *p, *q;
- int32 v;
- int n;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
-
- // NOTE(rsc): If we get rid of the globals we should
- // be able to parallelize these iterations.
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
-
- // TODO: move into span1
- for(p = cursym->text; p != P; p = p->link) {
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = AADDL;
- if(v < 0) {
- p->as = ASUBL;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
- span1(cursym);
- }
-}
-
-void
-xdefine(char *p, int t, int32 v)
-{
- Sym *s;
-
- s = lookup(p, 0);
- s->type = t;
- s->value = v;
- s->reachable = 1;
- s->special = 1;
-}
-
-void
-instinit(void)
-{
- int i;
-
- for(i=1; optab[i].as; i++)
- if(i != optab[i].as) {
- diag("phase error in optab: %d", i);
- errorexit();
- }
- maxop = i;
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_BH)
- reg[i] = (i-D_AL) & 7;
- if(i >= D_AX && i <= D_DI)
- reg[i] = (i-D_AX) & 7;
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- }
-}
-
-int
-prefixof(Adr *a)
-{
- switch(a->type) {
- case D_INDIR+D_CS:
- return 0x2e;
- case D_INDIR+D_DS:
- return 0x3e;
- case D_INDIR+D_ES:
- return 0x26;
- case D_INDIR+D_FS:
- return 0x64;
- case D_INDIR+D_GS:
- return 0x65;
- }
- return 0;
-}
-
-int
-oclass(Adr *a)
-{
- int32 v;
-
- if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) {
- if(a->index != D_NONE && a->scale == 0) {
- if(a->type == D_ADDR) {
- switch(a->index) {
- case D_EXTERN:
- case D_STATIC:
- return Yi32;
- case D_AUTO:
- case D_PARAM:
- return Yiauto;
- }
- return Yxxx;
- }
- return Ycol;
- }
- return Ym;
- }
- switch(a->type)
- {
- case D_AL:
- return Yal;
-
- case D_AX:
- return Yax;
-
- case D_CL:
- case D_DL:
- case D_BL:
- case D_AH:
- case D_CH:
- case D_DH:
- case D_BH:
- return Yrb;
-
- case D_CX:
- return Ycx;
-
- case D_DX:
- case D_BX:
- return Yrx;
-
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- return Yrl;
-
- case D_F0+0:
- return Yf0;
-
- case D_F0+1:
- case D_F0+2:
- case D_F0+3:
- case D_F0+4:
- case D_F0+5:
- case D_F0+6:
- case D_F0+7:
- return Yrf;
-
- case D_NONE:
- return Ynone;
-
- case D_CS: return Ycs;
- case D_SS: return Yss;
- case D_DS: return Yds;
- case D_ES: return Yes;
- case D_FS: return Yfs;
- case D_GS: return Ygs;
-
- case D_GDTR: return Ygdtr;
- case D_IDTR: return Yidtr;
- case D_LDTR: return Yldtr;
- case D_MSW: return Ymsw;
- case D_TASK: return Ytask;
-
- case D_CR+0: return Ycr0;
- case D_CR+1: return Ycr1;
- case D_CR+2: return Ycr2;
- case D_CR+3: return Ycr3;
- case D_CR+4: return Ycr4;
- case D_CR+5: return Ycr5;
- case D_CR+6: return Ycr6;
- case D_CR+7: return Ycr7;
-
- case D_DR+0: return Ydr0;
- case D_DR+1: return Ydr1;
- case D_DR+2: return Ydr2;
- case D_DR+3: return Ydr3;
- case D_DR+4: return Ydr4;
- case D_DR+5: return Ydr5;
- case D_DR+6: return Ydr6;
- case D_DR+7: return Ydr7;
-
- case D_TR+0: return Ytr0;
- case D_TR+1: return Ytr1;
- case D_TR+2: return Ytr2;
- case D_TR+3: return Ytr3;
- case D_TR+4: return Ytr4;
- case D_TR+5: return Ytr5;
- case D_TR+6: return Ytr6;
- case D_TR+7: return Ytr7;
-
- case D_EXTERN:
- case D_STATIC:
- case D_AUTO:
- case D_PARAM:
- return Ym;
-
- case D_CONST:
- case D_CONST2:
- case D_ADDR:
- if(a->sym == S) {
- v = a->offset;
- if(v == 0)
- return Yi0;
- if(v == 1)
- return Yi1;
- if(v >= -128 && v <= 127)
- return Yi8;
- }
- return Yi32;
-
- case D_BRANCH:
- return Ybr;
- }
- return Yxxx;
-}
-
-void
-asmidx(int scale, int index, int base)
-{
- int i;
-
- switch(index) {
- default:
- goto bad;
-
- case D_NONE:
- i = 4 << 3;
- goto bas;
-
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_BP:
- case D_SI:
- case D_DI:
- i = reg[index] << 3;
- break;
- }
- switch(scale) {
- default:
- goto bad;
- case 1:
- break;
- case 2:
- i |= (1<<6);
- break;
- case 4:
- i |= (2<<6);
- break;
- case 8:
- i |= (3<<6);
- break;
- }
-bas:
- switch(base) {
- default:
- goto bad;
- case D_NONE: /* must be mod=00 */
- i |= 5;
- break;
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- i |= reg[base];
- break;
- }
- *andptr++ = i;
- return;
-bad:
- diag("asmidx: bad address %d,%d,%d", scale, index, base);
- *andptr++ = 0;
- return;
-}
-
-static void
-put4(int32 v)
-{
- andptr[0] = v;
- andptr[1] = v>>8;
- andptr[2] = v>>16;
- andptr[3] = v>>24;
- andptr += 4;
-}
-
-static void
-relput4(Prog *p, Adr *a)
-{
- vlong v;
- Reloc rel, *r;
-
- v = vaddr(a, &rel);
- if(rel.siz != 0) {
- if(rel.siz != 4)
- diag("bad reloc");
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put4(v);
-}
-
-int32
-symaddr(Sym *s)
-{
- if(!s->reachable)
- diag("unreachable symbol in symaddr - %s", s->name);
- return s->value;
-}
-
-static int32
-vaddr(Adr *a, Reloc *r)
-{
- int t;
- int32 v;
- Sym *s;
-
- if(r != nil)
- memset(r, 0, sizeof *r);
-
- t = a->type;
- v = a->offset;
- if(t == D_ADDR)
- t = a->index;
- switch(t) {
- case D_STATIC:
- case D_EXTERN:
- s = a->sym;
- if(s != nil) {
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- if(r == nil) {
- diag("need reloc for %D", a);
- errorexit();
- }
- r->type = D_ADDR;
- r->siz = 4;
- r->off = -1;
- r->sym = s;
- r->add = v;
- v = 0;
- }
- }
- return v;
-}
-
-void
-asmand(Adr *a, int r)
-{
- int32 v;
- int t, scale;
- Reloc rel;
-
- v = a->offset;
- t = a->type;
- rel.siz = 0;
- if(a->index != D_NONE) {
- if(t < D_INDIR || t >= 2*D_INDIR) {
- switch(t) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- } else
- t -= D_INDIR;
-
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(v == 0 && rel.siz == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(t >= D_AL && t <= D_F0+7) {
- if(v)
- goto bad;
- *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
-
- scale = a->scale;
- if(t < D_INDIR || t >= 2*D_INDIR) {
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- scale = 1;
- } else
- t -= D_INDIR;
-
- if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- goto putrelv;
- }
- if(t == D_SP) {
- if(v == 0 && rel.siz == 0) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- goto putrelv;
- }
- if(t >= D_AX && t <= D_DI) {
- if(v == 0 && rel.siz == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- goto putrelv;
- }
- goto bad;
-
-putrelv:
- if(rel.siz != 0) {
- Reloc *r;
-
- if(rel.siz != 4) {
- diag("bad rel");
- goto bad;
- }
- r = addrel(cursym);
- *r = rel;
- r->off = curp->pc + andptr - and;
- }
- put4(v);
- return;
-
-bad:
- diag("asmand: bad address %D", a);
- return;
-}
-
-#define E 0xff
-uchar ymovtab[] =
-{
-/* push */
- APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0,
- APUSHL, Yss, Ynone, 0, 0x16,E,0,0,
- APUSHL, Yds, Ynone, 0, 0x1e,E,0,0,
- APUSHL, Yes, Ynone, 0, 0x06,E,0,0,
- APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0,
- APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0,
-
- APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0,
- APUSHW, Yss, Ynone, 0, Pe,0x16,E,0,
- APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0,
- APUSHW, Yes, Ynone, 0, Pe,0x06,E,0,
- APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E,
- APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E,
-
-/* pop */
- APOPL, Ynone, Yds, 0, 0x1f,E,0,0,
- APOPL, Ynone, Yes, 0, 0x07,E,0,0,
- APOPL, Ynone, Yss, 0, 0x17,E,0,0,
- APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0,
- APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0,
-
- APOPW, Ynone, Yds, 0, Pe,0x1f,E,0,
- APOPW, Ynone, Yes, 0, Pe,0x07,E,0,
- APOPW, Ynone, Yss, 0, Pe,0x17,E,0,
- APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E,
- APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E,
-
-/* mov seg */
- AMOVW, Yes, Yml, 1, 0x8c,0,0,0,
- AMOVW, Ycs, Yml, 1, 0x8c,1,0,0,
- AMOVW, Yss, Yml, 1, 0x8c,2,0,0,
- AMOVW, Yds, Yml, 1, 0x8c,3,0,0,
- AMOVW, Yfs, Yml, 1, 0x8c,4,0,0,
- AMOVW, Ygs, Yml, 1, 0x8c,5,0,0,
-
- AMOVW, Yml, Yes, 2, 0x8e,0,0,0,
- AMOVW, Yml, Ycs, 2, 0x8e,1,0,0,
- AMOVW, Yml, Yss, 2, 0x8e,2,0,0,
- AMOVW, Yml, Yds, 2, 0x8e,3,0,0,
- AMOVW, Yml, Yfs, 2, 0x8e,4,0,0,
- AMOVW, Yml, Ygs, 2, 0x8e,5,0,0,
-
-/* mov cr */
- AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0,
- AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0,
- AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0,
- AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0,
-
- AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0,
- AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0,
- AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0,
- AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0,
-
-/* mov dr */
- AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0,
- AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0,
- AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0,
-
- AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0,
- AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0,
- AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0,
-
-/* mov tr */
- AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0,
- AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0,
-
- AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E,
- AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E,
-
-/* lgdt, sgdt, lidt, sidt */
- AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0,
- AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0,
- AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0,
- AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0,
-
-/* lldt, sldt */
- AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0,
- AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0,
-
-/* lmsw, smsw */
- AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0,
- AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0,
-
-/* ltr, str */
- AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0,
- AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0,
-
-/* load full pointer */
- AMOVL, Yml, Ycol, 5, 0,0,0,0,
- AMOVW, Yml, Ycol, 5, Pe,0,0,0,
-
-/* double shift */
- ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0,
- ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0,
-
-/* extra imul */
- AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0,
- AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0,
- 0
-};
-
-int
-isax(Adr *a)
-{
-
- switch(a->type) {
- case D_AX:
- case D_AL:
- case D_AH:
- case D_INDIR+D_AX:
- return 1;
- }
- if(a->index == D_AX)
- return 1;
- return 0;
-}
-
-void
-subreg(Prog *p, int from, int to)
-{
-
- if(debug['Q'])
- print("\n%P s/%R/%R/\n", p, from, to);
-
- if(p->from.type == from) {
- p->from.type = to;
- p->ft = 0;
- }
- if(p->to.type == from) {
- p->to.type = to;
- p->tt = 0;
- }
-
- if(p->from.index == from) {
- p->from.index = to;
- p->ft = 0;
- }
- if(p->to.index == from) {
- p->to.index = to;
- p->tt = 0;
- }
-
- from += D_INDIR;
- if(p->from.type == from) {
- p->from.type = to+D_INDIR;
- p->ft = 0;
- }
- if(p->to.type == from) {
- p->to.type = to+D_INDIR;
- p->tt = 0;
- }
-
- if(debug['Q'])
- print("%P\n", p);
-}
-
-void
-doasm(Prog *p)
-{
- Optab *o;
- Prog *q, pp;
- uchar *t;
- int z, op, ft, tt;
- int32 v, pre;
- Reloc rel, *r;
- Adr *a;
-
- curp = p; // TODO
-
- pre = prefixof(&p->from);
- if(pre)
- *andptr++ = pre;
- pre = prefixof(&p->to);
- if(pre)
- *andptr++ = pre;
-
- if(p->ft == 0)
- p->ft = oclass(&p->from);
- if(p->tt == 0)
- p->tt = oclass(&p->to);
-
- ft = p->ft * Ymax;
- tt = p->tt * Ymax;
- o = &optab[p->as];
- t = o->ytab;
- if(t == 0) {
- diag("asmins: noproto %P", p);
- return;
- }
- for(z=0; *t; z+=t[3],t+=4)
- if(ycover[ft+t[0]])
- if(ycover[tt+t[1]])
- goto found;
- goto domov;
-
-found:
- switch(o->prefix) {
- case Pq: /* 16 bit escape and opcode escape */
- *andptr++ = Pe;
- *andptr++ = Pm;
- break;
-
- case Pm: /* opcode escape */
- *andptr++ = Pm;
- break;
-
- case Pe: /* 16 bit escape */
- *andptr++ = Pe;
- break;
-
- case Pb: /* botch */
- break;
- }
-
- op = o->op[z];
- switch(t[2]) {
- default:
- diag("asmins: unknown z %d %P", t[2], p);
- return;
-
- case Zpseudo:
- break;
-
- case Zlit:
- for(; op = o->op[z]; z++)
- *andptr++ = op;
- break;
-
- case Zm_r:
- *andptr++ = op;
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case Zaut_r:
- *andptr++ = 0x8d; /* leal */
- if(p->from.type != D_ADDR)
- diag("asmins: Zaut sb type ADDR");
- p->from.type = p->from.index;
- p->from.index = D_NONE;
- p->ft = 0;
- asmand(&p->from, reg[p->to.type]);
- p->from.index = p->from.type;
- p->from.type = D_ADDR;
- p->ft = 0;
- break;
-
- case Zm_o:
- *andptr++ = op;
- asmand(&p->from, o->op[z+1]);
- break;
-
- case Zr_m:
- *andptr++ = op;
- asmand(&p->to, reg[p->from.type]);
- break;
-
- case Zo_m:
- *andptr++ = op;
- asmand(&p->to, o->op[z+1]);
- break;
-
- case Zm_ibo:
- *andptr++ = op;
- asmand(&p->from, o->op[z+1]);
- *andptr++ = vaddr(&p->to, nil);
- break;
-
- case Zibo_m:
- *andptr++ = op;
- asmand(&p->to, o->op[z+1]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_ib:
- case Zib_:
- if(t[2] == Zib_)
- a = &p->from;
- else
- a = &p->to;
- v = vaddr(a, nil);
- *andptr++ = op;
- *andptr++ = v;
- break;
-
- case Zib_rp:
- *andptr++ = op + reg[p->to.type];
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Zil_rp:
- *andptr++ = op + reg[p->to.type];
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Zib_rr:
- *andptr++ = op;
- asmand(&p->to, reg[p->to.type]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_il:
- case Zil_:
- if(t[2] == Zil_)
- a = &p->from;
- else
- a = &p->to;
- *andptr++ = op;
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zm_ilo:
- case Zilo_m:
- *andptr++ = op;
- if(t[2] == Zilo_m) {
- a = &p->from;
- asmand(&p->to, o->op[z+1]);
- } else {
- a = &p->to;
- asmand(&p->from, o->op[z+1]);
- }
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zil_rr:
- *andptr++ = op;
- asmand(&p->to, reg[p->to.type]);
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Z_rp:
- *andptr++ = op + reg[p->to.type];
- break;
-
- case Zrp_:
- *andptr++ = op + reg[p->from.type];
- break;
-
- case Zclr:
- *andptr++ = op;
- asmand(&p->to, reg[p->to.type]);
- break;
-
- case Zcall:
- q = p->pcond;
- if(q == nil) {
- diag("call without target");
- errorexit();
- }
- if(q->as != ATEXT) {
- // Could handle this case by making D_PCREL
- // record the Prog* instead of the Sym*, but let's
- // wait until the need arises.
- diag("call of non-TEXT %P", q);
- errorexit();
- }
- *andptr++ = op;
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->type = D_PCREL;
- r->siz = 4;
- r->sym = q->from.sym;
- put4(0);
- break;
-
- case Zbr:
- case Zjmp:
- q = p->pcond;
- if(q == nil) {
- diag("jmp/branch without target");
- errorexit();
- }
- if(q->as == ATEXT) {
- // jump out of function
- if(t[2] == Zbr) {
- diag("branch to ATEXT");
- errorexit();
- }
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->sym = q->from.sym;
- r->type = D_PCREL;
- r->siz = 4;
- put4(0);
- break;
- }
-
- // Assumes q is in this function.
- // TODO: Check in input, preserve in brchain.
-
- // Fill in backward jump now.
- if(p->back & 1) {
- v = q->pc - (p->pc + 2);
- if(v >= -128) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- v -= 5-2;
- if(t[2] == Zbr) {
- *andptr++ = 0x0f;
- v--;
- }
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- break;
- }
-
- // Annotate target; will fill in later.
- p->forwd = q->comefrom;
- q->comefrom = p;
- if(p->back & 2) { // short
- *andptr++ = op;
- *andptr++ = 0;
- } else {
- if(t[2] == Zbr)
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- }
- break;
-
- case Zcallcon:
- case Zjmpcon:
- if(t[2] == Zcallcon)
- *andptr++ = op;
- else
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->type = D_PCREL;
- r->siz = 4;
- r->add = p->to.offset;
- put4(0);
- break;
-
- case Zloop:
- q = p->pcond;
- if(q == nil) {
- diag("loop without target");
- errorexit();
- }
- v = q->pc - p->pc - 2;
- if(v < -128 && v > 127)
- diag("loop too far: %P", p);
- *andptr++ = op;
- *andptr++ = v;
- break;
-
- case Zbyte:
- v = vaddr(&p->from, &rel);
- if(rel.siz != 0) {
- rel.siz = op;
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- *andptr++ = v;
- if(op > 1) {
- *andptr++ = v>>8;
- if(op > 2) {
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- }
- break;
-
- case Zmov:
- goto domov;
- }
- return;
-
-domov:
- for(t=ymovtab; *t; t+=8)
- if(p->as == t[0])
- if(ycover[ft+t[1]])
- if(ycover[tt+t[2]])
- goto mfound;
-bad:
- /*
- * here, the assembly has failed.
- * if its a byte instruction that has
- * unaddressable registers, try to
- * exchange registers and reissue the
- * instruction with the operands renamed.
- */
- pp = *p;
- z = p->from.type;
- if(z >= D_BP && z <= D_DI) {
- if(isax(&p->to)) {
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmand(&p->from, reg[D_BX]);
- subreg(&pp, z, D_BX);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmand(&p->from, reg[D_BX]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- }
- return;
- }
- z = p->to.type;
- if(z >= D_BP && z <= D_DI) {
- if(isax(&p->from)) {
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmand(&p->to, reg[D_BX]);
- subreg(&pp, z, D_BX);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmand(&p->to, reg[D_BX]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- }
- return;
- }
- diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
- return;
-
-mfound:
- switch(t[3]) {
- default:
- diag("asmins: unknown mov %d %P", t[3], p);
- break;
-
- case 0: /* lit */
- for(z=4; t[z]!=E; z++)
- *andptr++ = t[z];
- break;
-
- case 1: /* r,m */
- *andptr++ = t[4];
- asmand(&p->to, t[5]);
- break;
-
- case 2: /* m,r */
- *andptr++ = t[4];
- asmand(&p->from, t[5]);
- break;
-
- case 3: /* r,m - 2op */
- *andptr++ = t[4];
- *andptr++ = t[5];
- asmand(&p->to, t[6]);
- break;
-
- case 4: /* m,r - 2op */
- *andptr++ = t[4];
- *andptr++ = t[5];
- asmand(&p->from, t[6]);
- break;
-
- case 5: /* load full pointer, trash heap */
- if(t[4])
- *andptr++ = t[4];
- switch(p->to.index) {
- default:
- goto bad;
- case D_DS:
- *andptr++ = 0xc5;
- break;
- case D_SS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb2;
- break;
- case D_ES:
- *andptr++ = 0xc4;
- break;
- case D_FS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb4;
- break;
- case D_GS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb5;
- break;
- }
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case 6: /* double shift */
- z = p->from.type;
- switch(z) {
- default:
- goto bad;
- case D_CONST:
- *andptr++ = 0x0f;
- *andptr++ = t[4];
- asmand(&p->to, reg[p->from.index]);
- *andptr++ = p->from.offset;
- break;
- case D_CL:
- case D_CX:
- *andptr++ = 0x0f;
- *andptr++ = t[5];
- asmand(&p->to, reg[p->from.index]);
- break;
- }
- break;
-
- case 7: /* imul rm,r */
- if(t[4] == Pq) {
- *andptr++ = Pe;
- *andptr++ = Pm;
- } else
- *andptr++ = t[4];
- *andptr++ = t[5];
- asmand(&p->from, reg[p->to.type]);
- break;
- }
-}
-
-void
-asmins(Prog *p)
-{
- andptr = and;
- doasm(p);
- if(andptr > and+sizeof and) {
- print("and[] is too short - %ld byte instruction\n", andptr - and);
- errorexit();
- }
-}
diff --git a/src/cmd/Makefile b/src/cmd/Makefile
deleted file mode 100644
index 5a37733de..000000000
--- a/src/cmd/Makefile
+++ /dev/null
@@ -1,69 +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 ../Make.inc
-
-all: install
-
-# Only build tools for current architecture, and only tools written in C.
-# The tools written in Go are managed by ../pkg/Makefile.
-DIRS=\
- $(O)a\
- $(O)c\
- $(O)g\
- $(O)l\
- cc\
- cov\
- gc\
- godefs\
- gopack\
- gotry\
- nm\
- prof\
-
-# Clean applies to all directories, even for other architectures or
-# written in Go.
-CLEANDIRS=\
- $(DIRS)\
- 5a\
- 5c\
- 5g\
- 5l\
- 6a\
- 6c\
- 6g\
- 6l\
- 8a\
- 8c\
- 8g\
- 8l\
- cgo\
- ebnflint\
- godoc\
- gofix\
- gofmt\
- goinstall\
- gotest\
- gotype\
- goyacc\
- hgpatch\
-
-install: $(patsubst %,%.install,$(DIRS))
-clean: $(patsubst %,%.clean,$(CLEANDIRS))
-
-%.install:
- @echo
- @echo %%%% making $* %%%%
- @echo
- $(MAKE) -C $* install
-
-gc.install $(O)c.install: cc.install
-$(O)g.install: gc.install
-$(O)a.install $(O)c.install $(O)g.install: $(O)l.install
-
-%.clean:
- $(MAKE) -C $* clean
-
-echo-dirs:
- @echo $(DIRS)
diff --git a/src/cmd/cc/Makefile b/src/cmd/cc/Makefile
deleted file mode 100644
index 8327d9516..000000000
--- a/src/cmd/cc/Makefile
+++ /dev/null
@@ -1,36 +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 ../../Make.inc
-O:=$(HOST_O)
-
-LIB=cc.a
-
-HFILES=\
- cc.h\
- y.tab.h\
-
-YFILES=\
- cc.y\
-
-OFILES=\
- y.tab.$O\
- lex.$O\
- mac.$O\
- dcl.$O\
- acid.$O\
- godefs.$O\
- bits.$O\
- com.$O\
- scon.$O\
- funct.$O\
- sub.$O\
- com64.$O\
- dpchk.$O\
- omachcap.$O\
-
-NOINSTALL=1
-include ../../Make.clib
-
-install: $(LIB)
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 a38e658ce..000000000
--- a/src/cmd/cc/cc.h
+++ /dev/null
@@ -1,831 +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>
-
-#pragma lib "../cc/cc.a$O"
-
-#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 Hist Hist;
-typedef struct Term Term;
-typedef struct Init Init;
-typedef struct Bits Bits;
-typedef struct Dynimp Dynimp;
-typedef struct Dynexp Dynexp;
-
-#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 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 */
- ushort* 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;
- 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;
-};
-#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 Hist
-{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
-};
-#define H ((Hist*)0)
-EXTERN Hist* hist;
-
-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,
- 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,
-
- 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,
-};
-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];
-};
-
-struct Dynimp
-{
- char* local;
- char* remote;
- char* path;
-};
-
-EXTERN Dynimp *dynimp;
-EXTERN int ndynimp;
-
-struct Dynexp
-{
- char* local;
- char* remote;
-};
-
-EXTERN Dynexp *dynexp;
-EXTERN int ndynexp;
-
-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 char debug[256];
-EXTERN Hist* ehist;
-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 char* pathname;
-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 Type* thisfn;
-EXTERN int32 thunk;
-EXTERN Type* types[NTYPE];
-EXTERN Type* fntypes[NTYPE];
-EXTERN Node* initlist;
-EXTERN Term term[NTERM];
-EXTERN int nterm;
-EXTERN int packflg;
-EXTERN int fproundflg;
-EXTERN int textflag;
-EXTERN int ncontin;
-EXTERN int canreach;
-EXTERN int warnreach;
-EXTERN Bits zbits;
-
-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 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*);
-void setinclude(char*);
-
-/*
- * mac.c
- */
-void dodefine(char*);
-void domacro(void);
-Sym* getsym(void);
-int32 getnsn(void);
-void linehist(char*, int);
-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*, ...);
-
-/*
- * 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 pragtextflag(void);
-void pragincomplete(void);
-void pragdynimport(void);
-void pragdynexport(void);
-
-/*
- * 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(ushort*, int32);
-void sextern(Sym*, Node*, int32, int32);
-void xcom(Node*);
-int32 exreg(Type*);
-int32 align(int32, Type*, int, int32*);
-int32 maxround(int32, int32);
-
-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 "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 515a80372..000000000
--- a/src/cmd/cc/cc.y
+++ /dev/null
@@ -1,1215 +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 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);
- }
-| 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[TUSHORT]);
- $$->type->width = $1.l + sizeof(ushort);
- $$->rstring = (ushort*)$1.s;
- $$->sym = symstring;
- $$->etype = TARRAY;
- $$->class = CSTATIC;
- }
-| lstring LLSTRING
- {
- char *s;
- int n;
-
- n = $1->type->width - sizeof(ushort);
- s = alloc(n+$2.l+MAXALIGN);
-
- memcpy(s, $1->rstring, n);
- memcpy(s+n, $2.s, $2.l);
- *(ushort*)(s+n+$2.l) = 0;
-
- $$ = $1;
- $$->type->width += $2.l;
- $$->rstring = (ushort*)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
- {
- 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 6e470ee64..000000000
--- a/src/cmd/cc/com.c
+++ /dev/null
@@ -1,1385 +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;
-
- 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[TUSHORT]) {
- o = outstring(0, 0);
- while(o & 3) {
- ushort a[1];
- a[0] = 0;
- outlstring(a, sizeof(ushort));
- 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, (1LL<<(l->type->width*8))-1);
- }else{
- lo = big(~0ULL, -(1LL<<(l->type->width*8-1)));
- hi = big(0, (1LL<<(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 fb7a3f750..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[NTYPE]; /* 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 d624bf247..000000000
--- a/src/cmd/cc/dcl.c
+++ /dev/null
@@ -1,1669 +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"
-
-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);
- 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, TUSHORT);
- 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);
-}
-
-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;
- 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;
-
- 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*));
- 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;
- 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) {
- if(!typesu[t->etype])
- diag(Z, "unnamed structure element must be struct/union");
- if(c != CXXX)
- diag(Z, "unnamed structure element cannot have class");
- } 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/doc.go b/src/cmd/cc/doc.go
deleted file mode 100644
index 51aa8b192..000000000
--- a/src/cmd/cc/doc.go
+++ /dev/null
@@ -1,11 +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.
-
-/*
-
-This directory contains the portable section of the Plan 9 C compilers.
-See ../6c, ../8c, and ../5c for more information.
-
-*/
-package documentation
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
deleted file mode 100644
index 42c245b56..000000000
--- a/src/cmd/cc/dpchk.c
+++ /dev/null
@@ -1,724 +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 <ctype.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;
-
- textflag = 0;
- s = getsym();
- textflag = 7;
- if(s)
- textflag = atoi(s->name+1);
- while(getnsc() != '\n')
- ;
- if(debug['f'])
- print("%4d: textflag %d\n", lineno, textflag);
-}
-
-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();
-}
-
-void
-pragdynimport(void)
-{
- Sym *local, *remote;
- char *path;
- Dynimp *f;
-
- local = getimpsym();
- if(local == nil)
- goto err;
-
- remote = getimpsym();
- if(remote == nil)
- goto err;
-
- path = getquoted();
- if(path == nil)
- goto err;
-
- if(ndynimp%32 == 0)
- dynimp = realloc(dynimp, (ndynimp+32)*sizeof dynimp[0]);
- f = &dynimp[ndynimp++];
- f->local = local->name;
- f->remote = remote->name;
- f->path = path;
- goto out;
-
-err:
- yyerror("usage: #pragma dynimport local remote \"path\"");
-
-out:
- while(getnsc() != '\n')
- ;
-}
-
-void
-pragdynexport(void)
-{
- Sym *local, *remote;
- Dynexp *f;
-
- local = getsym();
- if(local == nil)
- goto err;
-
- remote = getsym();
- if(remote == nil)
- goto err;
-
- if(ndynexp%32 == 0)
- dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
- f = &dynexp[ndynexp++];
- f->local = local->name;
- f->remote = remote->name;
- goto out;
-
-err:
- yyerror("usage: #pragma dynexport local remote");
-
-out:
- while(getnsc() != '\n')
- ;
-}
diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c
deleted file mode 100644
index 99477b2b2..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[NTYPE];
-
-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, "cant 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<sizeof(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[NTYPE] =
-{
- 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 3ba979c8a..000000000
--- a/src/cmd/cc/godefs.c
+++ /dev/null
@@ -1,388 +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(*s);
- else
- str[0] = tolower(*s);
- for(i = 1; i < STRINGSZ && s[i] != 0; i++)
- str[i] = tolower(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;
- Type *t1;
- 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:
- Bprint(&outbuf, "int");
- break;
- case TUINT:
- Bprint(&outbuf, "uint");
- break;
- case TCHAR:
- Bprint(&outbuf, "int8");
- break;
- case TUCHAR:
- Bprint(&outbuf, "uint8");
- break;
- case TSHORT:
- Bprint(&outbuf, "int16");
- break;
- case TUSHORT:
- Bprint(&outbuf, "uint16");
- break;
- case TLONG:
- Bprint(&outbuf, "int32");
- break;
- case TULONG:
- Bprint(&outbuf, "uint32");
- break;
- case TVLONG:
- Bprint(&outbuf, "int64");
- break;
- case TUVLONG:
- Bprint(&outbuf, "uint64");
- break;
- case TFLOAT:
- Bprint(&outbuf, "float32");
- break;
- case TDOUBLE:
- Bprint(&outbuf, "float64");
- 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
- Bprint(&outbuf, "%U", n);
- break;
- case TFUNC:
- Bprint(&outbuf, "func(");
- for(t1 = t->down; t1 != T; t1 = t1->down) {
- if(t1->etype == TVOID)
- break;
- if(t1 != t->down)
- Bprint(&outbuf, ", ");
- printtypename(t1);
- }
- Bprint(&outbuf, ")");
- if(t->link && t->link->etype != TVOID) {
- Bprint(&outbuf, " ");
- printtypename(t->link);
- }
- 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 %U = %lld\n", s->name, s->vconst);
- else
- Bprint(&outbuf, "const %U = %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) // TODO(lvd)
- 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 15f2d374d..000000000
--- a/src/cmd/cc/lex.c
+++ /dev/null
@@ -1,1562 +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 <ctype.h>
-#include "cc.h"
-#include "y.tab.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
-main(int argc, char *argv[])
-{
- char **defs, *p;
- int c, ndef;
-
- ensuresymb(NSYMB);
- memset(debug, 0, sizeof(debug));
- tinit();
- cinit();
- ginit();
- arginit();
-
- tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
- ndef = 0;
- defs = nil;
- outfile = 0;
- setinclude(".");
- ARGBEGIN {
- default:
- c = ARGC();
- if(c >= 0 && c < sizeof(debug))
- debug[c]++;
- break;
-
- case 'l': /* for little-endian mips */
- if(thechar != 'v'){
- print("can only use -l with vc");
- errorexit();
- }
- thechar = '0';
- thestring = "spim";
- break;
-
- case 'o':
- outfile = ARGF();
- break;
-
- case 'D':
- p = ARGF();
- if(p) {
- if(ndef%8 == 0)
- defs = allocn(defs, ndef*sizeof(char *),
- 8*sizeof(char *));
- defs[ndef++] = p;
- dodefine(p);
- }
- break;
-
- case 'I':
- p = ARGF();
- setinclude(p);
- break;
- } ARGEND
- if(argc < 1 && outfile == 0) {
- print("usage: %cc [-options] files\n", thechar);
- errorexit();
- }
- 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);
-
- 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)
-{
- if(outfile)
- remove(outfile);
- exits("error");
-}
-
-void
-pushio(void)
-{
- Io *i;
-
- i = iostack;
- if(i == I) {
- yyerror("botch in pushio");
- errorexit();
- }
- i->p = fi.p;
- i->c = fi.c;
-}
-
-void
-newio(void)
-{
- Io *i;
- static int pushdepth = 0;
-
- i = iofree;
- if(i == I) {
- pushdepth++;
- if(pushdepth > 1000) {
- yyerror("macro/io expansion too deep");
- errorexit();
- }
- i = alloc(sizeof(*i));
- } else
- iofree = i->link;
- i->c = 0;
- i->f = -1;
- ionext = i;
-}
-
-void
-newfile(char *s, int f)
-{
- Io *i;
-
- if(debug['e'])
- print("%L: %s\n", lineno, s);
-
- i = ionext;
- i->link = iostack;
- iostack = i;
- i->f = f;
- if(f < 0)
- i->f = open(s, 0);
- if(i->f < 0) {
- yyerror("%cc: %r: %s", thechar, s);
- errorexit();
- }
- fi.c = 0;
- linehist(s, 0);
-}
-
-Sym*
-slookup(char *s)
-{
- 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] = '"';
- }
-
- // turn · into .
- for(r=w=symb; *r; r++) {
- if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) {
- *w++ = '.';
- 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, TUSHORT);
- 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(ushort));
- *(ushort*)(cp + c1) = c;
- c1 += sizeof(ushort);
- }
- yylval.sval.l = c1;
- do {
- cp = allocn(cp, c1, sizeof(ushort));
- *(ushort*)(cp + c1) = 0;
- c1 += sizeof(ushort);
- } 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 = 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(!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 = 4;
- 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 = 5;
- l = c - '0';
- for(; i>0; i--) {
- c = getc();
- if(c >= '0' && c <= '7') {
- l = l*8 + c-'0';
- continue;
- }
- unget(c);
- }
- if(escflg)
- l |= ESC;
- return l;
- }
- switch(c)
- {
- case '\n': goto loop;
- case 'n': return '\n';
- case 't': return '\t';
- case 'b': return '\b';
- case 'r': return '\r';
- case 'f': return '\f';
- case 'a': return '\a';
- case 'v': return '\v';
- }
- return c;
-}
-
-struct
-{
- char *name;
- ushort lexical;
- ushort type;
-} itab[] =
-{
- "auto", LAUTO, 0,
- "break", LBREAK, 0,
- "case", LCASE, 0,
- "char", LCHAR, TCHAR,
- "const", LCONSTNT, 0,
- "continue", LCONTINUE, 0,
- "default", LDEFAULT, 0,
- "do", LDO, 0,
- "double", LDOUBLE, TDOUBLE,
- "else", LELSE, 0,
- "enum", LENUM, 0,
- "extern", LEXTERN, 0,
- "float", LFLOAT, TFLOAT,
- "for", LFOR, 0,
- "goto", LGOTO, 0,
- "if", LIF, 0,
- "inline", LINLINE, 0,
- "int", LINT, TINT,
- "long", LLONG, TLONG,
- "register", LREGISTER, 0,
- "restrict", LRESTRICT, 0,
- "return", LRETURN, 0,
- "SET", LSET, 0,
- "short", LSHORT, TSHORT,
- "signed", LSIGNED, 0,
- "signof", LSIGNOF, 0,
- "sizeof", LSIZEOF, 0,
- "static", LSTATIC, 0,
- "struct", LSTRUCT, 0,
- "switch", LSWITCH, 0,
- "typedef", LTYPEDEF, 0,
- "typestr", LTYPESTR, 0,
- "union", LUNION, 0,
- "unsigned", LUNSIGNED, 0,
- "USED", LUSED, 0,
- "void", LVOID, TVOID,
- "volatile", LVOLATILE, 0,
- "while", LWHILE, 0,
- 0
-};
-
-void
-cinit(void)
-{
- Sym *s;
- int i;
- Type *t;
-
- nerrors = 0;
- lineno = 1;
- iostack = I;
- iofree = I;
- peekc = IGN;
- nhunk = 0;
-
- types[TXXX] = T;
- types[TCHAR] = typ(TCHAR, T);
- types[TUCHAR] = typ(TUCHAR, T);
- types[TSHORT] = typ(TSHORT, T);
- types[TUSHORT] = typ(TUSHORT, T);
- types[TINT] = typ(TINT, T);
- types[TUINT] = typ(TUINT, T);
- types[TLONG] = typ(TLONG, T);
- types[TULONG] = typ(TULONG, T);
- types[TVLONG] = typ(TVLONG, T);
- types[TUVLONG] = typ(TUVLONG, T);
- types[TFLOAT] = typ(TFLOAT, T);
- types[TDOUBLE] = typ(TDOUBLE, T);
- types[TVOID] = typ(TVOID, T);
- types[TENUM] = typ(TENUM, T);
- types[TFUNC] = typ(TFUNC, types[TINT]);
- types[TIND] = typ(TIND, types[TVOID]);
-
- for(i=0; i<NHASH; i++)
- hash[i] = S;
- for(i=0; itab[i].name; i++) {
- s = slookup(itab[i].name);
- s->lexical = itab[i].lexical;
- if(itab[i].type != 0)
- s->type = types[itab[i].type];
- }
- blockno = 0;
- autobn = 0;
- autoffset = 0;
-
- t = typ(TARRAY, types[TCHAR]);
- t->width = 0;
- symstring = slookup(".string");
- symstring->class = CSTATIC;
- symstring->type = t;
-
- t = typ(TARRAY, types[TCHAR]);
- t->width = 0;
-
- nodproto = new(OPROTO, Z, Z);
- dclstack = D;
-
- pathname = allocn(pathname, 0, 100);
- if(getwd(pathname, 99) == 0) {
- pathname = allocn(pathname, 100, 900);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
- }
-
- fmtinstall('O', Oconv);
- fmtinstall('T', Tconv);
- fmtinstall('F', FNconv);
- fmtinstall('L', Lconv);
- fmtinstall('Q', Qconv);
- fmtinstall('|', VBconv);
- fmtinstall('U', Uconv);
-}
-
-int
-filbuf(void)
-{
- Io *i;
-
-loop:
- i = iostack;
- if(i == I)
- return EOF;
- if(i->f < 0)
- goto pop;
- fi.c = read(i->f, i->b, BUFSIZ) - 1;
- if(fi.c < 0) {
- close(i->f);
- linehist(0, 0);
- goto pop;
- }
- fi.p = i->b + 1;
- return i->b[0] & 0xff;
-
-pop:
- iostack = i->link;
- i->link = iofree;
- iofree = i;
- i = iostack;
- if(i == I)
- return EOF;
- fi.p = i->p;
- fi.c = i->c;
- if(--fi.c < 0)
- goto loop;
- return *fi.p++ & 0xff;
-}
-
-int
-Oconv(Fmt *fp)
-{
- int a;
-
- a = va_arg(fp->args, int);
- if(a < OXXX || a > OEND)
- return fmtprint(fp, "***badO %d***", a);
-
- return fmtstrcpy(fp, onames[a]);
-}
-
-int
-Lconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Hist *h;
- struct
- {
- Hist* incl; /* start of this include file */
- int32 idel; /* delta line number to apply to include */
- Hist* line; /* start of this #line directive */
- int32 ldel; /* delta line number to apply to #line */
- } a[HISTSZ];
- int32 l, d;
- int i, n;
-
- l = va_arg(fp->args, int32);
- n = 0;
- for(h = hist; h != H; h = h->link) {
- if(l < h->line)
- break;
- if(h->name) {
- if(h->offset != 0) { /* #line directive, not #pragma */
- if(n > 0 && n < HISTSZ && h->offset >= 0) {
- a[n-1].line = h;
- a[n-1].ldel = h->line - h->offset + 1;
- }
- } else {
- if(n < HISTSZ) { /* beginning of file */
- a[n].incl = h;
- a[n].idel = h->line;
- a[n].line = 0;
- }
- n++;
- }
- continue;
- }
- n--;
- if(n > 0 && n < HISTSZ) {
- d = h->line - a[n].incl->line;
- a[n-1].ldel += d;
- a[n-1].idel += d;
- }
- }
- if(n > HISTSZ)
- n = HISTSZ;
- str[0] = 0;
- for(i=n-1; i>=0; i--) {
- if(i != n-1) {
- if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
- break;
- strcat(str, " ");
- }
- if(a[i].line)
- snprint(s, STRINGSZ, "%s:%d[%s:%d]",
- a[i].line->name, l-a[i].ldel+1,
- a[i].incl->name, l-a[i].idel+1);
- else
- snprint(s, STRINGSZ, "%s:%d",
- a[i].incl->name, l-a[i].idel+1);
- if(strlen(s)+strlen(str) >= STRINGSZ-10)
- break;
- strcat(str, s);
- l = a[i].incl->line - 1; /* now print out start of this file */
- }
- if(n == 0)
- strcat(str, "<eof>");
- return fmtstrcpy(fp, str);
-}
-
-int
-Tconv(Fmt *fp)
-{
- char str[STRINGSZ+20], s[STRINGSZ+20];
- Type *t, *t1;
- int et;
- 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);
-}
-
-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
deleted file mode 100644
index f4cc19c2e..000000000
--- a/src/cmd/cc/lexbody
+++ /dev/null
@@ -1,769 +0,0 @@
-// Inferno utils/cc/lexbody
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody
-//
-// 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.
-
-/*
- * common code for all the assemblers
- */
-
-void
-pragpack(void)
-{
- while(getnsc() != '\n')
- ;
-}
-
-void
-pragvararg(void)
-{
- while(getnsc() != '\n')
- ;
-}
-
-void
-pragdynimport(void)
-{
- while(getnsc() != '\n')
- ;
-}
-
-void
-pragdynexport(void)
-{
- while(getnsc() != '\n')
- ;
-}
-
-void
-pragfpround(void)
-{
- while(getnsc() != '\n')
- ;
-}
-
-void
-pragtextflag(void)
-{
- while(getnsc() != '\n')
- ;
-}
-
-void
-pragprofile(void)
-{
- while(getnsc() != '\n')
- ;
-}
-
-void
-pragincomplete(void)
-{
- while(getnsc() != '\n')
- ;
-}
-
-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;
- }
-}
-
-void
-setinclude(char *p)
-{
- int i;
-
- if(p == 0)
- return;
- 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
-errorexit(void)
-{
-
- if(outfile)
- remove(outfile);
- exits("error");
-}
-
-void
-pushio(void)
-{
- Io *i;
-
- i = iostack;
- if(i == I) {
- yyerror("botch in pushio");
- errorexit();
- }
- i->p = fi.p;
- i->c = fi.c;
-}
-
-void
-newio(void)
-{
- Io *i;
- static int pushdepth = 0;
-
- i = iofree;
- if(i == I) {
- pushdepth++;
- if(pushdepth > 1000) {
- yyerror("macro/io expansion too deep");
- errorexit();
- }
- i = alloc(sizeof(*i));
- } else
- iofree = i->link;
- i->c = 0;
- i->f = -1;
- ionext = i;
-}
-
-void
-newfile(char *s, int f)
-{
- Io *i;
-
- i = ionext;
- i->link = iostack;
- iostack = i;
- i->f = f;
- if(f < 0)
- i->f = open(s, 0);
- if(i->f < 0) {
- yyerror("%ca: %r: %s", thechar, s);
- errorexit();
- }
- fi.c = 0;
- linehist(s, 0);
-}
-
-Sym*
-slookup(char *s)
-{
- ensuresymb(strlen(s));
- strcpy(symb, s);
- return lookup();
-}
-
-Sym*
-lookup(void)
-{
- Sym *s;
- int32 h;
- char *p;
- int c, l;
- 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] = '"';
- }
-
- // turn · into .
- for(r=w=symb; *r; r++) {
- if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) {
- *w++ = '.';
- r++;
- }else
- *w++ = *r;
- }
- *w = '\0';
-
- h = 0;
- for(p=symb; c = *p; p++)
- h = h+h+h + c;
- l = (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(memcmp(s->name, symb, l) == 0)
- return s;
- }
- s = alloc(sizeof(*s));
- s->name = alloc(l);
- memmove(s->name, symb, l);
-
- s->link = hash[h];
- hash[h] = s;
- syminit(s);
- return s;
-}
-
-int
-ISALPHA(int c)
-{
- if(isalpha(c))
- return 1;
- if(c >= Runeself)
- return 1;
- return 0;
-}
-
-int32
-yylex(void)
-{
- int c, c1;
- char *cp;
- Sym *s;
-
- c = peekc;
- if(c != IGN) {
- peekc = IGN;
- goto l1;
- }
-l0:
- c = GETC();
-
-l1:
- if(c == EOF) {
- peekc = EOF;
- return -1;
- }
- if(isspace(c)) {
- if(c == '\n') {
- lineno++;
- return ';';
- }
- goto l0;
- }
- if(ISALPHA(c))
- goto talph;
- if(isdigit(c))
- goto tnum;
- switch(c)
- {
- case '\n':
- lineno++;
- return ';';
-
- case '#':
- domacro();
- goto l0;
-
- case '.':
- c = GETC();
- if(ISALPHA(c)) {
- cp = symb;
- *cp++ = '.';
- goto aloop;
- }
- if(isdigit(c)) {
- cp = symb;
- *cp++ = '.';
- goto casedot;
- }
- peekc = c;
- return '.';
-
- talph:
- case '_':
- case '@':
- cp = symb;
-
- aloop:
- *cp++ = c;
- c = GETC();
- if(ISALPHA(c) || isdigit(c) || c == '_' || c == '$')
- goto aloop;
- *cp = 0;
- 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;
- }
- if(s->type == 0)
- s->type = LNAME;
- if(s->type == LNAME ||
- s->type == LVAR ||
- s->type == LLAB) {
- yylval.sym = s;
- return s->type;
- }
- yylval.lval = s->value;
- return s->type;
-
- tnum:
- cp = symb;
- if(c != '0')
- goto dc;
- *cp++ = c;
- c = GETC();
- c1 = 3;
- if(c == 'x' || c == 'X') {
- c1 = 4;
- c = GETC();
- } else
- if(c < '0' || c > '7')
- goto dc;
- yylval.lval = 0;
- for(;;) {
- if(c >= '0' && c <= '9') {
- if(c > '7' && c1 == 3)
- break;
- yylval.lval <<= c1;
- yylval.lval += c - '0';
- c = GETC();
- continue;
- }
- if(c1 == 3)
- break;
- if(c >= 'A' && c <= 'F')
- c += 'a' - 'A';
- if(c >= 'a' && c <= 'f') {
- yylval.lval <<= c1;
- yylval.lval += c - 'a' + 10;
- c = GETC();
- continue;
- }
- break;
- }
- goto ncu;
-
- dc:
- for(;;) {
- if(!isdigit(c))
- break;
- *cp++ = c;
- c = GETC();
- }
- if(c == '.')
- goto casedot;
- if(c == 'e' || c == 'E')
- goto casee;
- *cp = 0;
- if(sizeof(yylval.lval) == sizeof(vlong))
- yylval.lval = strtoll(symb, nil, 10);
- else
- yylval.lval = strtol(symb, nil, 10);
-
- ncu:
- while(c == 'U' || c == 'u' || c == 'l' || c == 'L')
- c = GETC();
- peekc = c;
- return LCONST;
-
- casedot:
- for(;;) {
- *cp++ = c;
- c = GETC();
- if(!isdigit(c))
- break;
- }
- if(c == 'e' || c == 'E')
- goto casee;
- goto caseout;
-
- casee:
- *cp++ = 'e';
- c = GETC();
- if(c == '+' || c == '-') {
- *cp++ = c;
- c = GETC();
- }
- while(isdigit(c)) {
- *cp++ = c;
- c = GETC();
- }
-
- caseout:
- *cp = 0;
- peekc = c;
- if(FPCHIP) {
- yylval.dval = atof(symb);
- return LFCONST;
- }
- yyerror("assembler cannot interpret fp constants");
- yylval.lval = 1L;
- return LCONST;
-
- case '"':
- memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval));
- cp = yylval.sval;
- c1 = 0;
- for(;;) {
- c = escchar('"');
- if(c == EOF)
- break;
- if(c1 < sizeof(yylval.sval))
- *cp++ = c;
- c1++;
- }
- if(c1 > sizeof(yylval.sval))
- yyerror("string constant too long");
- return LSCONST;
-
- case '\'':
- c = escchar('\'');
- if(c == EOF)
- c = '\'';
- if(escchar('\'') != EOF)
- yyerror("missing '");
- yylval.lval = c;
- return LCONST;
-
- case '/':
- c1 = GETC();
- if(c1 == '/') {
- for(;;) {
- c = GETC();
- if(c == '\n')
- goto l1;
- if(c == EOF) {
- yyerror("eof in comment");
- errorexit();
- }
- }
- }
- if(c1 == '*') {
- for(;;) {
- c = GETC();
- while(c == '*') {
- c = GETC();
- if(c == '/')
- goto l0;
- }
- if(c == EOF) {
- yyerror("eof in comment");
- errorexit();
- }
- if(c == '\n')
- lineno++;
- }
- }
- break;
-
- default:
- return c;
- }
- peekc = c1;
- return c;
-}
-
-int
-getc(void)
-{
- int c;
-
- c = peekc;
- if(c != IGN) {
- peekc = IGN;
- return c;
- }
- c = GETC();
- if(c == '\n')
- lineno++;
- if(c == EOF) {
- yyerror("End of file");
- errorexit();
- }
- return c;
-}
-
-int
-getnsc(void)
-{
- int c;
-
- for(;;) {
- c = getc();
- if(!isspace(c) || c == '\n')
- return c;
- }
-}
-
-void
-unget(int c)
-{
-
- peekc = c;
- if(c == '\n')
- lineno--;
-}
-
-int
-escchar(int e)
-{
- int c, l;
-
-loop:
- c = getc();
- if(c == '\n') {
- yyerror("newline in string");
- return EOF;
- }
- if(c != '\\') {
- if(c == e)
- return EOF;
- return c;
- }
- c = getc();
- if(c >= '0' && c <= '7') {
- l = c - '0';
- c = getc();
- if(c >= '0' && c <= '7') {
- l = l*8 + c-'0';
- c = getc();
- if(c >= '0' && c <= '7') {
- l = l*8 + c-'0';
- return l;
- }
- }
- peekc = c;
- 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 0x07;
- case 'v': return 0x0b;
- case 'z': return 0x00;
- }
- return c;
-}
-
-void
-pinit(char *f)
-{
- int i;
- Sym *s;
-
- lineno = 1;
- newio();
- newfile(f, -1);
- pc = 0;
- peekc = IGN;
- sym = 1;
- for(i=0; i<NSYM; i++) {
- h[i].type = 0;
- h[i].sym = S;
- }
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- s->macro = 0;
-}
-
-int
-filbuf(void)
-{
- Io *i;
-
-loop:
- i = iostack;
- if(i == I)
- return EOF;
- if(i->f < 0)
- goto pop;
- fi.c = read(i->f, i->b, BUFSIZ) - 1;
- if(fi.c < 0) {
- close(i->f);
- linehist(0, 0);
- goto pop;
- }
- fi.p = i->b + 1;
- return i->b[0];
-
-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++;
-}
-
-void
-yyerror(char *a, ...)
-{
- char buf[200];
- va_list arg;
-
- /*
- * hack to intercept message from yaccpar
- */
- if(strcmp(a, "syntax error") == 0) {
- yyerror("syntax error, last name: %s", symb);
- return;
- }
- prfile(lineno);
- va_start(arg, a);
- vseprint(buf, buf+sizeof(buf), a, arg);
- va_end(arg);
- print("%s\n", buf);
- nerrors++;
- if(nerrors > 10) {
- print("too many errors\n");
- errorexit();
- }
-}
-
-void
-prfile(int32 l)
-{
- int i, n;
- Hist a[HISTSZ], *h;
- int32 d;
-
- n = 0;
- for(h = hist; h != H; h = h->link) {
- if(l < h->line)
- break;
- if(h->name) {
- if(h->offset == 0) {
- if(n >= 0 && n < HISTSZ)
- a[n] = *h;
- n++;
- continue;
- }
- if(n > 0 && n < HISTSZ)
- if(a[n-1].offset == 0) {
- a[n] = *h;
- n++;
- } else
- a[n-1] = *h;
- continue;
- }
- n--;
- if(n >= 0 && n < HISTSZ) {
- d = h->line - a[n].line;
- for(i=0; i<n; i++)
- a[i].line += d;
- }
- }
- if(n > HISTSZ)
- n = HISTSZ;
- for(i=0; i<n; i++)
- print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
-}
-
-void
-ieeedtod(Ieee *ieee, double native)
-{
- double fr, ho, f;
- int exp;
-
- if(native < 0) {
- ieeedtod(ieee, -native);
- ieee->h |= 0x80000000L;
- return;
- }
- if(native == 0) {
- ieee->l = 0;
- ieee->h = 0;
- return;
- }
- fr = frexp(native, &exp);
- f = 2097152L; /* shouldnt use fp constants here */
- fr = modf(fr*f, &ho);
- ieee->h = ho;
- ieee->h &= 0xfffffL;
- ieee->h |= (exp+1022L) << 20;
- f = 65536L;
- fr = modf(fr*f, &ho);
- ieee->l = ho;
- ieee->l <<= 16;
- ieee->l |= (int32)(fr*f);
-}
diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c
deleted file mode 100644
index 43ae214d7..000000000
--- a/src/cmd/cc/mac.c
+++ /dev/null
@@ -1,35 +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 <ctype.h>
-#include "cc.h"
-
-#include "macbody"
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
deleted file mode 100644
index ed66361f1..000000000
--- a/src/cmd/cc/macbody
+++ /dev/null
@@ -1,852 +0,0 @@
-// Inferno utils/cc/macbody
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody
-//
-// 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 VARMAC 0x80
-
-int32
-getnsn(void)
-{
- int32 n;
- int c;
-
- c = getnsc();
- if(c < '0' || c > '9')
- return -1;
- n = 0;
- while(c >= '0' && c <= '9') {
- n = n*10 + c-'0';
- c = getc();
- }
- unget(c);
- return n;
-}
-
-Sym*
-getsym(void)
-{
- int c;
- char *cp;
-
- c = getnsc();
- if(!isalpha(c) && c != '_' && c < 0x80) {
- unget(c);
- return S;
- }
- for(cp = symb;;) {
- if(cp <= symb+NSYMB-4)
- *cp++ = c;
- c = getc();
- if(isalnum(c) || c == '_' || c >= 0x80)
- continue;
- unget(c);
- break;
- }
- *cp = 0;
- if(cp > symb+NSYMB-4)
- yyerror("symbol too large: %s", symb);
- return lookup();
-}
-
-Sym*
-getsymdots(int *dots)
-{
- int c;
- Sym *s;
-
- s = getsym();
- if(s != S)
- return s;
-
- c = getnsc();
- if(c != '.'){
- unget(c);
- return S;
- }
- if(getc() != '.' || getc() != '.')
- yyerror("bad dots in macro");
- *dots = 1;
- return slookup("__VA_ARGS__");
-}
-
-int
-getcom(void)
-{
- int c;
-
- for(;;) {
- c = getnsc();
- if(c != '/')
- break;
- c = getc();
- if(c == '/') {
- while(c != '\n')
- c = getc();
- break;
- }
- if(c != '*')
- break;
- c = getc();
- for(;;) {
- if(c == '*') {
- c = getc();
- if(c != '/')
- continue;
- c = getc();
- break;
- }
- if(c == '\n') {
- yyerror("comment across newline");
- break;
- }
- c = getc();
- }
- if(c == '\n')
- break;
- }
- return c;
-}
-
-void
-dodefine(char *cp)
-{
- Sym *s;
- char *p;
- int32 l;
-
- ensuresymb(strlen(cp));
- strcpy(symb, cp);
- p = strchr(symb, '=');
- if(p) {
- *p++ = 0;
- s = lookup();
- l = strlen(p) + 2; /* +1 null, +1 nargs */
- s->macro = alloc(l);
- strcpy(s->macro+1, p);
- } else {
- s = lookup();
- s->macro = "\0001"; /* \000 is nargs */
- }
- if(debug['m'])
- print("#define (-D) %s %s\n", s->name, s->macro+1);
-}
-
-struct
-{
- char *macname;
- void (*macf)(void);
-} mactab[] =
-{
- "ifdef", 0, /* macif(0) */
- "ifndef", 0, /* macif(1) */
- "else", 0, /* macif(2) */
-
- "line", maclin,
- "define", macdef,
- "include", macinc,
- "undef", macund,
-
- "pragma", macprag,
- "endif", macend,
- 0
-};
-
-void
-domacro(void)
-{
- int i;
- Sym *s;
-
- s = getsym();
- if(s == S)
- s = slookup("endif");
- for(i=0; mactab[i].macname; i++)
- if(strcmp(s->name, mactab[i].macname) == 0) {
- if(mactab[i].macf)
- (*mactab[i].macf)();
- else
- macif(i);
- return;
- }
- yyerror("unknown #: %s", s->name);
- macend();
-}
-
-void
-macund(void)
-{
- Sym *s;
-
- s = getsym();
- macend();
- if(s == S) {
- yyerror("syntax in #undef");
- return;
- }
- s->macro = 0;
-}
-
-#define NARG 25
-void
-macdef(void)
-{
- Sym *s, *a;
- char *args[NARG], *np, *base;
- int n, i, c, len, dots;
- int ischr;
-
- s = getsym();
- if(s == S)
- goto bad;
- if(s->macro)
- yyerror("macro redefined: %s", s->name);
- c = getc();
- n = -1;
- dots = 0;
- if(c == '(') {
- n++;
- c = getnsc();
- if(c != ')') {
- unget(c);
- for(;;) {
- a = getsymdots(&dots);
- if(a == S)
- goto bad;
- if(n >= NARG) {
- yyerror("too many arguments in #define: %s", s->name);
- goto bad;
- }
- args[n++] = a->name;
- c = getnsc();
- if(c == ')')
- break;
- if(c != ',' || dots)
- goto bad;
- }
- }
- c = getc();
- }
- if(isspace(c))
- if(c != '\n')
- c = getnsc();
- base = hunk;
- len = 1;
- ischr = 0;
- for(;;) {
- if(isalpha(c) || c == '_') {
- np = symb;
- *np++ = c;
- c = getc();
- while(isalnum(c) || c == '_') {
- *np++ = c;
- c = getc();
- }
- *np = 0;
- for(i=0; i<n; i++)
- if(strcmp(symb, args[i]) == 0)
- break;
- if(i >= n) {
- i = strlen(symb);
- base = allocn(base, len, i);
- memcpy(base+len, symb, i);
- len += i;
- continue;
- }
- base = allocn(base, len, 2);
- base[len++] = '#';
- base[len++] = 'a' + i;
- continue;
- }
- if(ischr){
- if(c == '\\'){
- base = allocn(base, len, 1);
- base[len++] = c;
- c = getc();
- }else if(c == ischr)
- ischr = 0;
- }else{
- if(c == '"' || c == '\''){
- base = allocn(base, len, 1);
- base[len++] = c;
- ischr = c;
- c = getc();
- continue;
- }
- if(c == '/') {
- c = getc();
- if(c == '/'){
- c = getc();
- for(;;) {
- if(c == '\n')
- break;
- c = getc();
- }
- continue;
- }
- if(c == '*'){
- c = getc();
- for(;;) {
- if(c == '*') {
- c = getc();
- if(c != '/')
- continue;
- c = getc();
- break;
- }
- if(c == '\n') {
- yyerror("comment and newline in define: %s", s->name);
- break;
- }
- c = getc();
- }
- continue;
- }
- base = allocn(base, len, 1);
- base[len++] = '/';
- continue;
- }
- }
- if(c == '\\') {
- c = getc();
- if(c == '\n') {
- c = getc();
- continue;
- }
- else if(c == '\r') {
- c = getc();
- if(c == '\n') {
- c = getc();
- continue;
- }
- }
- base = allocn(base, len, 1);
- base[len++] = '\\';
- continue;
- }
- if(c == '\n')
- break;
- if(c == '#')
- if(n > 0) {
- base = allocn(base, len, 1);
- base[len++] = c;
- }
- base = allocn(base, len, 1);
- base[len++] = c;
- c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
- if(c == '\n')
- lineno++;
- if(c == -1) {
- yyerror("eof in a macro: %s", s->name);
- break;
- }
- }
- do {
- base = allocn(base, len, 1);
- base[len++] = 0;
- } while(len & 3);
-
- *base = n+1;
- if(dots)
- *base |= VARMAC;
- s->macro = base;
- if(debug['m'])
- print("#define %s %s\n", s->name, s->macro+1);
- return;
-
-bad:
- if(s == S)
- yyerror("syntax in #define");
- else
- yyerror("syntax in #define: %s", s->name);
- macend();
-}
-
-void
-macexpand(Sym *s, char *b)
-{
- char buf[2000];
- int n, l, c, nargs;
- char *arg[NARG], *cp, *ob, *ecp, dots;
-
- ob = b;
- if(*s->macro == 0) {
- strcpy(b, s->macro+1);
- if(debug['m'])
- print("#expand %s %s\n", s->name, ob);
- return;
- }
-
- nargs = (char)(*s->macro & ~VARMAC) - 1;
- dots = *s->macro & VARMAC;
-
- c = getnsc();
- if(c != '(')
- goto bad;
- n = 0;
- c = getc();
- if(c != ')') {
- unget(c);
- l = 0;
- cp = buf;
- ecp = cp + sizeof(buf)-4;
- arg[n++] = cp;
- for(;;) {
- if(cp >= ecp)
- goto toobig;
- c = getc();
- if(c == '"')
- for(;;) {
- if(cp >= ecp)
- goto toobig;
- *cp++ = c;
- c = getc();
- if(c == '\\') {
- *cp++ = c;
- c = getc();
- continue;
- }
- if(c == '\n')
- goto bad;
- if(c == '"')
- break;
- }
- if(c == '\'')
- for(;;) {
- if(cp >= ecp)
- goto toobig;
- *cp++ = c;
- c = getc();
- if(c == '\\') {
- *cp++ = c;
- c = getc();
- continue;
- }
- if(c == '\n')
- goto bad;
- if(c == '\'')
- break;
- }
- if(c == '/') {
- c = getc();
- switch(c) {
- case '*':
- for(;;) {
- c = getc();
- if(c == '*') {
- c = getc();
- if(c == '/')
- break;
- }
- }
- *cp++ = ' ';
- continue;
- case '/':
- while((c = getc()) != '\n')
- ;
- break;
- default:
- unget(c);
- c = '/';
- }
- }
- if(l == 0) {
- if(c == ',') {
- if(n == nargs && dots) {
- *cp++ = ',';
- continue;
- }
- *cp++ = 0;
- arg[n++] = cp;
- if(n > nargs)
- break;
- continue;
- }
- if(c == ')')
- break;
- }
- if(c == '\n')
- c = ' ';
- *cp++ = c;
- if(c == '(')
- l++;
- if(c == ')')
- l--;
- }
- *cp = 0;
- }
- if(n != nargs) {
- yyerror("argument mismatch expanding: %s", s->name);
- *b = 0;
- return;
- }
- cp = s->macro+1;
- for(;;) {
- c = *cp++;
- if(c == '\n')
- c = ' ';
- if(c != '#') {
- *b++ = c;
- if(c == 0)
- break;
- continue;
- }
- c = *cp++;
- if(c == 0)
- goto bad;
- if(c == '#') {
- *b++ = c;
- continue;
- }
- c -= 'a';
- if(c < 0 || c >= n)
- continue;
- strcpy(b, arg[c]);
- b += strlen(arg[c]);
- }
- *b = 0;
- if(debug['m'])
- print("#expand %s %s\n", s->name, ob);
- return;
-
-bad:
- yyerror("syntax in macro expansion: %s", s->name);
- *b = 0;
- return;
-
-toobig:
- yyerror("too much text in macro expansion: %s", s->name);
- *b = 0;
-}
-
-void
-macinc(void)
-{
- int c0, c, i, f;
- char str[STRINGSZ], *hp;
-
- c0 = getnsc();
- if(c0 != '"') {
- c = c0;
- if(c0 != '<')
- goto bad;
- c0 = '>';
- }
- for(hp = str;;) {
- c = getc();
- if(c == c0)
- break;
- if(c == '\n')
- goto bad;
- *hp++ = c;
- }
- *hp = 0;
-
- c = getcom();
- if(c != '\n')
- goto bad;
-
- f = -1;
- for(i=0; i<ninclude; i++) {
- if(i == 0 && c0 == '>')
- continue;
- ensuresymb(strlen(include[i])+strlen(str)+2);
- strcpy(symb, include[i]);
- strcat(symb, "/");
- if(strcmp(symb, "./") == 0)
- symb[0] = 0;
- strcat(symb, str);
- f = open(symb, OREAD);
- if(f >= 0)
- break;
- }
- if(f < 0)
- strcpy(symb, str);
- c = strlen(symb) + 1;
- hp = alloc(c);
- memcpy(hp, symb, c);
- newio();
- pushio();
- newfile(hp, f);
- return;
-
-bad:
- unget(c);
- yyerror("syntax in #include");
- macend();
-}
-
-void
-maclin(void)
-{
- char *cp;
- int c;
- int32 n;
-
- n = getnsn();
- c = getc();
- if(n < 0)
- goto bad;
-
- for(;;) {
- if(c == ' ' || c == '\t') {
- c = getc();
- continue;
- }
- if(c == '"')
- break;
- if(c == '\n') {
- strcpy(symb, "<noname>");
- goto nn;
- }
- goto bad;
- }
- cp = symb;
- for(;;) {
- c = getc();
- if(c == '"')
- break;
- *cp++ = c;
- }
- *cp = 0;
- c = getcom();
- if(c != '\n')
- goto bad;
-
-nn:
- c = strlen(symb) + 1;
- cp = alloc(c);
- memcpy(cp, symb, c);
- linehist(cp, n);
- return;
-
-bad:
- unget(c);
- yyerror("syntax in #line");
- macend();
-}
-
-void
-macif(int f)
-{
- int c, l, bol;
- Sym *s;
-
- if(f == 2)
- goto skip;
- s = getsym();
- if(s == S)
- goto bad;
- if(getcom() != '\n')
- goto bad;
- if((s->macro != 0) ^ f)
- return;
-
-skip:
- bol = 1;
- l = 0;
- for(;;) {
- c = getc();
- if(c != '#') {
- if(!isspace(c))
- bol = 0;
- if(c == '\n')
- bol = 1;
- continue;
- }
- if(!bol)
- continue;
- s = getsym();
- if(s == S)
- continue;
- if(strcmp(s->name, "endif") == 0) {
- if(l) {
- l--;
- continue;
- }
- macend();
- return;
- }
- if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
- l++;
- continue;
- }
- if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
- macend();
- return;
- }
- }
-
-bad:
- yyerror("syntax in #if(n)def");
- macend();
-}
-
-void
-macprag(void)
-{
- Sym *s;
- int c0, c;
- char *hp;
- Hist *h;
-
- s = getsym();
-
- if(s && strcmp(s->name, "lib") == 0)
- goto praglib;
- if(s && strcmp(s->name, "pack") == 0) {
- pragpack();
- return;
- }
- if(s && strcmp(s->name, "fpround") == 0) {
- pragfpround();
- return;
- }
- if(s && strcmp(s->name, "textflag") == 0) {
- pragtextflag();
- return;
- }
- if(s && strcmp(s->name, "varargck") == 0) {
- pragvararg();
- return;
- }
- if(s && strcmp(s->name, "incomplete") == 0) {
- pragincomplete();
- return;
- }
- if(s && strcmp(s->name, "dynimport") == 0) {
- pragdynimport();
- return;
- }
- if(s && strcmp(s->name, "dynexport") == 0) {
- pragdynexport();
- return;
- }
- while(getnsc() != '\n')
- ;
- return;
-
-praglib:
- c0 = getnsc();
- if(c0 != '"') {
- c = c0;
- if(c0 != '<')
- goto bad;
- c0 = '>';
- }
- for(hp = symb;;) {
- c = getc();
- if(c == c0)
- break;
- if(c == '\n')
- goto bad;
- *hp++ = c;
- }
- *hp = 0;
- c = getcom();
- if(c != '\n')
- goto bad;
-
- /*
- * put pragma-line in as a funny history
- */
- c = strlen(symb) + 1;
- hp = alloc(c);
- memcpy(hp, symb, c);
-
- h = alloc(sizeof(Hist));
- h->name = hp;
- h->line = lineno;
- h->offset = -1;
- h->link = H;
- if(ehist == H) {
- hist = h;
- ehist = h;
- return;
- }
- ehist->link = h;
- ehist = h;
- return;
-
-bad:
- unget(c);
- yyerror("syntax in #pragma lib");
- macend();
-}
-
-void
-macend(void)
-{
- int c;
-
- for(;;) {
- c = getnsc();
- if(c < 0 || c == '\n')
- return;
- }
-}
-
-void
-linehist(char *f, int offset)
-{
- Hist *h;
-
- /*
- * overwrite the last #line directive if
- * no alloc has happened since the last one
- */
- if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
- if(f && ehist->name && strcmp(f, ehist->name) == 0) {
- ehist->line = lineno;
- ehist->offset = offset;
- return;
- }
-
- if(debug['f'])
- if(f) {
- if(offset)
- print("%4d: %s (#line %d)\n", lineno, f, offset);
- else
- print("%4d: %s\n", lineno, f);
- } else
- print("%4d: <pop>\n", lineno);
- newflag = 0;
-
- h = alloc(sizeof(Hist));
- h->name = f;
- h->line = lineno;
- h->offset = offset;
- h->link = H;
- if(ehist == H) {
- hist = h;
- ehist = h;
- return;
- }
- ehist->link = h;
- ehist = h;
-}
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 0e5e8c059..000000000
--- a/src/cmd/cc/pgen.c
+++ /dev/null
@@ -1,594 +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"
-
-vlong
-argsize(void)
-{
- Type *t;
- int32 s;
-
-//print("t=%T\n", thisfn);
- s = align(0, thisfn->link, Aarg0, nil);
- for(t=thisfn->down; t!=T; t=t->down) {
- switch(t->etype) {
- case TVOID:
- break;
- case TDOT:
- yyerror("function takes ... without textflag NOSPLIT");
- s += 64;
- break;
- 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;
- 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, "cant find function name");
- return;
- }
- if(n1->op == ONAME)
- break;
- }
- nearln = nn->lineno;
-
- p = gtext(n1->sym, stkoff);
- 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);
- }
- }
-
- retok = 0;
-
- 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;
- 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]) {
- sugen(l, nodret, n->type->width);
- noretval(3);
- gbranch(ORETURN);
- break;
- }
- regret(&nod, n);
- cgen(l, &nod);
- 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) {
- cas();
- 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) {
- cas();
- 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(!typeword[l->type->etype] || l->type->etype == TIND) {
- diag(n, "switch expression must be integer");
- break;
- }
-
- gbranch(OGOTO); /* entry */
- sp = p;
-
- cn = cases;
- cases = C;
- cas();
-
- 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);
- regalloc(&nod, l, Z);
- /* always signed */
- if(typev[l->type->etype])
- nod.type = types[TVLONG];
- else
- nod.type = types[TLONG];
- cgen(l, &nod);
- doswit(&nod);
- regfree(&nod);
- 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:
- 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);
- 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 0e402dea7..000000000
--- a/src/cmd/cc/pswt.c
+++ /dev/null
@@ -1,168 +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
-cas(void)
-{
- Case *c;
-
- c = alloc(sizeof(*c));
- c->link = cases;
- cases = c;
-}
-
-int32
-outlstring(ushort *s, int32 n)
-{
- char buf[2];
- int c;
- int32 r;
-
- if(suppress)
- return nstring;
- while(nstring & 1)
- outstring("", 1);
- r = nstring;
- while(n > 0) {
- c = *s++;
- if(align(0, types[TCHAR], Aarg1, nil)) {
- buf[0] = c>>8;
- buf[1] = c;
- } else {
- buf[0] = c;
- buf[1] = c>>8;
- }
- outstring(buf, 2);
- n -= sizeof(ushort);
- }
- 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);
-}
-
-void
-ieeedtod(Ieee *ieee, double native)
-{
- double fr, ho, f;
- int exp;
-
- if(native < 0) {
- ieeedtod(ieee, -native);
- ieee->h |= 0x80000000L;
- return;
- }
- if(native == 0) {
- ieee->l = 0;
- ieee->h = 0;
- return;
- }
- fr = frexp(native, &exp);
- f = 2097152L; /* shouldnt use fp constants here */
- fr = modf(fr*f, &ho);
- ieee->h = ho;
- ieee->h &= 0xfffffL;
- ieee->h |= (exp+1022L) << 20;
- f = 65536L;
- fr = modf(fr*f, &ho);
- ieee->l = ho;
- ieee->l <<= 16;
- ieee->l |= (int32)(fr*f);
-}
diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c
deleted file mode 100644
index 193331f77..000000000
--- a/src/cmd/cc/scon.c
+++ /dev/null
@@ -1,637 +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:
- v = (uvlong)l->vconst >> r->vconst;
- break;
-
- case OASHR:
- v = l->vconst >> r->vconst;
- break;
-
- case OASHL:
- v = 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 e5992e213..000000000
--- a/src/cmd/cc/sub.c
+++ /dev/null
@@ -1,2056 +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:
- print(" \"%S\"", n->rstring);
- 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;
- t->width = ewidth[et];
- 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;
-
-/*
- if(debug['h'])
- print("%.3o %d %d %d #%.ux\n",
- (s1<<3)|s2, c1, c2, topbit(c3), c3);
-*/
-
- 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",
- 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",
- 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[NTYPE];
-int typeiinit[] =
-{
- TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
-};
-uchar typeu[NTYPE];
-int typeuinit[] =
-{
- TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
-};
-
-uchar typesuv[NTYPE];
-int typesuvinit[] =
-{
- TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
-};
-
-uchar typeilp[NTYPE];
-int typeilpinit[] =
-{
- TINT, TUINT, TLONG, TULONG, TIND, -1
-};
-
-uchar typechl[NTYPE];
-uchar typechlv[NTYPE];
-uchar typechlvp[NTYPE];
-int typechlinit[] =
-{
- TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
-};
-
-uchar typechlp[NTYPE];
-int typechlpinit[] =
-{
- TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
-};
-
-uchar typechlpfd[NTYPE];
-int typechlpfdinit[] =
-{
- TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
-};
-
-uchar typec[NTYPE];
-int typecinit[] =
-{
- TCHAR, TUCHAR, -1
-};
-
-uchar typeh[NTYPE];
-int typehinit[] =
-{
- TSHORT, TUSHORT, -1,
-};
-
-uchar typeil[NTYPE];
-int typeilinit[] =
-{
- TINT, TUINT, TLONG, TULONG, -1,
-};
-
-uchar typev[NTYPE];
-int typevinit[] =
-{
- TVLONG, TUVLONG, -1,
-};
-
-uchar typefd[NTYPE];
-int typefdinit[] =
-{
- TFLOAT, TDOUBLE, -1,
-};
-
-uchar typeaf[NTYPE];
-int typeafinit[] =
-{
- TFUNC, TARRAY, -1,
-};
-
-uchar typesu[NTYPE];
-int typesuinit[] =
-{
- TSTRUCT, TUNION, -1,
-};
-
-int32 tasign[NTYPE];
-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[NTYPE];
-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[NTYPE];
-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[NTYPE];
-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[NTYPE];
-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[NTYPE];
-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[NTYPE];
-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[NTYPE];
-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];
-}
diff --git a/src/cmd/cgo/Makefile b/src/cmd/cgo/Makefile
deleted file mode 100644
index 5458c3e4f..000000000
--- a/src/cmd/cgo/Makefile
+++ /dev/null
@@ -1,15 +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 ../../Make.inc
-
-TARG=cgo
-GOFILES=\
- ast.go\
- gcc.go\
- main.go\
- out.go\
- util.go\
-
-include ../../Make.cmd
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
deleted file mode 100644
index 46e33686d..000000000
--- a/src/cmd/cgo/ast.go
+++ /dev/null
@@ -1,410 +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.
-
-// Parse input AST and prepare Prog structure.
-
-package main
-
-import (
- "fmt"
- "go/ast"
- "go/doc"
- "go/parser"
- "go/scanner"
- "go/token"
- "os"
- "strings"
-)
-
-func parse(name string, flags uint) *ast.File {
- ast1, err := parser.ParseFile(fset, name, nil, flags)
- if err != nil {
- if list, ok := err.(scanner.ErrorList); ok {
- // If err is a scanner.ErrorList, its String will print just
- // the first error and then (+n more errors).
- // Instead, turn it into a new Error that will return
- // details for all the errors.
- for _, e := range list {
- fmt.Fprintln(os.Stderr, e)
- }
- os.Exit(2)
- }
- fatalf("parsing %s: %s", name, err)
- }
- return ast1
-}
-
-func sourceLine(n ast.Node) int {
- return fset.Position(n.Pos()).Line
-}
-
-// ReadGo populates f with information learned from reading the
-// Go source file with the given file name. It gathers the C preamble
-// attached to the import "C" comment, a list of references to C.xxx,
-// a list of exported functions, and the actual AST, to be rewritten and
-// printed.
-func (f *File) ReadGo(name string) {
- // Two different parses: once with comments, once without.
- // The printer is not good enough at printing comments in the
- // right place when we start editing the AST behind its back,
- // so we use ast1 to look for the doc comments on import "C"
- // and on exported functions, and we use ast2 for translating
- // and reprinting.
- ast1 := parse(name, parser.ParseComments)
- ast2 := parse(name, 0)
-
- f.Package = ast1.Name.Name
- f.Name = make(map[string]*Name)
-
- // In ast1, find the import "C" line and get any extra C preamble.
- sawC := false
- for _, decl := range ast1.Decls {
- d, ok := decl.(*ast.GenDecl)
- if !ok {
- continue
- }
- for _, spec := range d.Specs {
- s, ok := spec.(*ast.ImportSpec)
- if !ok || string(s.Path.Value) != `"C"` {
- continue
- }
- sawC = true
- if s.Name != nil {
- error(s.Path.Pos(), `cannot rename import "C"`)
- }
- cg := s.Doc
- if cg == nil && len(d.Specs) == 1 {
- cg = d.Doc
- }
- if cg != nil {
- f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
- f.Preamble += doc.CommentText(cg) + "\n"
- }
- }
- }
- if !sawC {
- error(token.NoPos, `cannot find import "C"`)
- }
-
- // In ast2, strip the import "C" line.
- w := 0
- for _, decl := range ast2.Decls {
- d, ok := decl.(*ast.GenDecl)
- if !ok {
- ast2.Decls[w] = decl
- w++
- continue
- }
- ws := 0
- for _, spec := range d.Specs {
- s, ok := spec.(*ast.ImportSpec)
- if !ok || string(s.Path.Value) != `"C"` {
- d.Specs[ws] = spec
- ws++
- }
- }
- if ws == 0 {
- continue
- }
- d.Specs = d.Specs[0:ws]
- ast2.Decls[w] = d
- w++
- }
- ast2.Decls = ast2.Decls[0:w]
-
- // Accumulate pointers to uses of C.x.
- if f.Ref == nil {
- f.Ref = make([]*Ref, 0, 8)
- }
- f.walk(ast2, "prog", (*File).saveRef)
-
- // Accumulate exported functions.
- // The comments are only on ast1 but we need to
- // save the function bodies from ast2.
- // The first walk fills in ExpFunc, and the
- // second walk changes the entries to
- // refer to ast2 instead.
- f.walk(ast1, "prog", (*File).saveExport)
- f.walk(ast2, "prog", (*File).saveExport2)
-
- f.AST = ast2
-}
-
-// Save references to C.xxx for later processing.
-func (f *File) saveRef(x interface{}, context string) {
- n, ok := x.(*ast.Expr)
- if !ok {
- return
- }
- if sel, ok := (*n).(*ast.SelectorExpr); ok {
- // For now, assume that the only instance of capital C is
- // when used as the imported package identifier.
- // The parser should take care of scoping in the future,
- // so that we will be able to distinguish a "top-level C"
- // from a local C.
- if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
- if context == "as2" {
- context = "expr"
- }
- goname := sel.Sel.Name
- if goname == "errno" {
- error(sel.Pos(), "cannot refer to errno directly; see documentation")
- return
- }
- name := f.Name[goname]
- if name == nil {
- name = &Name{
- Go: goname,
- }
- f.Name[goname] = name
- }
- f.Ref = append(f.Ref, &Ref{
- Name: name,
- Expr: n,
- Context: context,
- })
- return
- }
- }
-}
-
-// If a function should be exported add it to ExpFunc.
-func (f *File) saveExport(x interface{}, context string) {
- n, ok := x.(*ast.FuncDecl)
- if !ok {
- return
- }
-
- if n.Doc == nil {
- return
- }
- for _, c := range n.Doc.List {
- if !strings.HasPrefix(string(c.Text), "//export ") {
- continue
- }
-
- name := strings.TrimSpace(string(c.Text[9:]))
- if name == "" {
- error(c.Pos(), "export missing name")
- }
-
- f.ExpFunc = append(f.ExpFunc, &ExpFunc{
- Func: n,
- ExpName: name,
- })
- break
- }
-}
-
-// Make f.ExpFunc[i] point at the Func from this AST instead of the other one.
-func (f *File) saveExport2(x interface{}, context string) {
- n, ok := x.(*ast.FuncDecl)
- if !ok {
- return
- }
-
- for _, exp := range f.ExpFunc {
- if exp.Func.Name.Name == n.Name.Name {
- exp.Func = n
- break
- }
- }
-}
-
-// walk walks the AST x, calling visit(f, x, context) for each node.
-func (f *File) walk(x interface{}, context string, visit func(*File, interface{}, string)) {
- visit(f, x, context)
- switch n := x.(type) {
- case *ast.Expr:
- f.walk(*n, context, visit)
-
- // everything else just recurs
- default:
- error(token.NoPos, "unexpected type %T in walk", x, visit)
- panic("unexpected type")
-
- case nil:
-
- // These are ordered and grouped to match ../../pkg/go/ast/ast.go
- case *ast.Field:
- f.walk(&n.Type, "type", visit)
- case *ast.FieldList:
- for _, field := range n.List {
- f.walk(field, context, visit)
- }
- case *ast.BadExpr:
- case *ast.Ident:
- case *ast.Ellipsis:
- case *ast.BasicLit:
- case *ast.FuncLit:
- f.walk(n.Type, "type", visit)
- f.walk(n.Body, "stmt", visit)
- case *ast.CompositeLit:
- f.walk(&n.Type, "type", visit)
- f.walk(n.Elts, "expr", visit)
- case *ast.ParenExpr:
- f.walk(&n.X, context, visit)
- case *ast.SelectorExpr:
- f.walk(&n.X, "selector", visit)
- case *ast.IndexExpr:
- f.walk(&n.X, "expr", visit)
- f.walk(&n.Index, "expr", visit)
- case *ast.SliceExpr:
- f.walk(&n.X, "expr", visit)
- if n.Low != nil {
- f.walk(&n.Low, "expr", visit)
- }
- if n.High != nil {
- f.walk(&n.High, "expr", visit)
- }
- case *ast.TypeAssertExpr:
- f.walk(&n.X, "expr", visit)
- f.walk(&n.Type, "type", visit)
- case *ast.CallExpr:
- if context == "as2" {
- f.walk(&n.Fun, "call2", visit)
- } else {
- f.walk(&n.Fun, "call", visit)
- }
- f.walk(n.Args, "expr", visit)
- case *ast.StarExpr:
- f.walk(&n.X, context, visit)
- case *ast.UnaryExpr:
- f.walk(&n.X, "expr", visit)
- case *ast.BinaryExpr:
- f.walk(&n.X, "expr", visit)
- f.walk(&n.Y, "expr", visit)
- case *ast.KeyValueExpr:
- f.walk(&n.Key, "expr", visit)
- f.walk(&n.Value, "expr", visit)
-
- case *ast.ArrayType:
- f.walk(&n.Len, "expr", visit)
- f.walk(&n.Elt, "type", visit)
- case *ast.StructType:
- f.walk(n.Fields, "field", visit)
- case *ast.FuncType:
- f.walk(n.Params, "field", visit)
- if n.Results != nil {
- f.walk(n.Results, "field", visit)
- }
- case *ast.InterfaceType:
- f.walk(n.Methods, "field", visit)
- case *ast.MapType:
- f.walk(&n.Key, "type", visit)
- f.walk(&n.Value, "type", visit)
- case *ast.ChanType:
- f.walk(&n.Value, "type", visit)
-
- case *ast.BadStmt:
- case *ast.DeclStmt:
- f.walk(n.Decl, "decl", visit)
- case *ast.EmptyStmt:
- case *ast.LabeledStmt:
- f.walk(n.Stmt, "stmt", visit)
- case *ast.ExprStmt:
- f.walk(&n.X, "expr", visit)
- case *ast.SendStmt:
- f.walk(&n.Chan, "expr", visit)
- f.walk(&n.Value, "expr", visit)
- case *ast.IncDecStmt:
- f.walk(&n.X, "expr", visit)
- case *ast.AssignStmt:
- f.walk(n.Lhs, "expr", visit)
- if len(n.Lhs) == 2 && len(n.Rhs) == 1 {
- f.walk(n.Rhs, "as2", visit)
- } else {
- f.walk(n.Rhs, "expr", visit)
- }
- case *ast.GoStmt:
- f.walk(n.Call, "expr", visit)
- case *ast.DeferStmt:
- f.walk(n.Call, "expr", visit)
- case *ast.ReturnStmt:
- f.walk(n.Results, "expr", visit)
- case *ast.BranchStmt:
- case *ast.BlockStmt:
- f.walk(n.List, context, visit)
- case *ast.IfStmt:
- f.walk(n.Init, "stmt", visit)
- f.walk(&n.Cond, "expr", visit)
- f.walk(n.Body, "stmt", visit)
- f.walk(n.Else, "stmt", visit)
- case *ast.CaseClause:
- if context == "typeswitch" {
- context = "type"
- } else {
- context = "expr"
- }
- f.walk(n.List, context, visit)
- f.walk(n.Body, "stmt", visit)
- case *ast.SwitchStmt:
- f.walk(n.Init, "stmt", visit)
- f.walk(&n.Tag, "expr", visit)
- f.walk(n.Body, "switch", visit)
- case *ast.TypeSwitchStmt:
- f.walk(n.Init, "stmt", visit)
- f.walk(n.Assign, "stmt", visit)
- f.walk(n.Body, "typeswitch", visit)
- case *ast.CommClause:
- f.walk(n.Comm, "stmt", visit)
- f.walk(n.Body, "stmt", visit)
- case *ast.SelectStmt:
- f.walk(n.Body, "stmt", visit)
- case *ast.ForStmt:
- f.walk(n.Init, "stmt", visit)
- f.walk(&n.Cond, "expr", visit)
- f.walk(n.Post, "stmt", visit)
- f.walk(n.Body, "stmt", visit)
- case *ast.RangeStmt:
- f.walk(&n.Key, "expr", visit)
- f.walk(&n.Value, "expr", visit)
- f.walk(&n.X, "expr", visit)
- f.walk(n.Body, "stmt", visit)
-
- case *ast.ImportSpec:
- case *ast.ValueSpec:
- f.walk(&n.Type, "type", visit)
- f.walk(n.Values, "expr", visit)
- case *ast.TypeSpec:
- f.walk(&n.Type, "type", visit)
-
- case *ast.BadDecl:
- case *ast.GenDecl:
- f.walk(n.Specs, "spec", visit)
- case *ast.FuncDecl:
- if n.Recv != nil {
- f.walk(n.Recv, "field", visit)
- }
- f.walk(n.Type, "type", visit)
- if n.Body != nil {
- f.walk(n.Body, "stmt", visit)
- }
-
- case *ast.File:
- f.walk(n.Decls, "decl", visit)
-
- case *ast.Package:
- for _, file := range n.Files {
- f.walk(file, "file", visit)
- }
-
- case []ast.Decl:
- for _, d := range n {
- f.walk(d, context, visit)
- }
- case []ast.Expr:
- for i := range n {
- f.walk(&n[i], context, visit)
- }
- case []ast.Stmt:
- for _, s := range n {
- f.walk(s, context, visit)
- }
- case []ast.Spec:
- for _, s := range n {
- f.walk(s, context, visit)
- }
- }
-}
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
deleted file mode 100644
index 064725c1d..000000000
--- a/src/cmd/cgo/doc.go
+++ /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.
-
-/*
-
-Cgo enables the creation of Go packages that call C code.
-
-Usage: cgo [compiler options] file.go
-
-The compiler options are passed through uninterpreted when
-invoking gcc to compile the C parts of the package.
-
-The input file.go is a syntactically valid Go source file that imports
-the pseudo-package "C" and then refers to types such as C.size_t,
-variables such as C.stdout, or functions such as C.putchar.
-
-If the import of "C" is immediately preceded by a comment, that
-comment is used as a header when compiling the C parts of
-the package. For example:
-
- // #include <stdio.h>
- // #include <errno.h>
- import "C"
-
-CFLAGS and LDFLAGS may be defined with pseudo #cgo directives
-within these comments to tweak the behavior of gcc. Values defined
-in multiple directives are concatenated together. Options prefixed
-by $GOOS, $GOARCH, or $GOOS/$GOARCH are only defined in matching
-systems. For example:
-
- // #cgo CFLAGS: -DPNG_DEBUG=1
- // #cgo linux CFLAGS: -DLINUX=1
- // #cgo LDFLAGS: -lpng
- // #include <png.h>
- import "C"
-
-Alternatively, CFLAGS and LDFLAGS may be obtained via the pkg-config
-tool using a '#cgo pkg-config:' directive followed by the package names.
-For example:
-
- // #cgo pkg-config: png cairo
- // #include <png.h>
- import "C"
-
-Within the Go file, C identifiers or field names that are keywords in Go
-can be accessed by prefixing them with an underscore: if x points at a C
-struct with a field named "type", x._type accesses the field.
-
-The standard C numeric types are available under the names
-C.char, C.schar (signed char), C.uchar (unsigned char),
-C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
-C.long, C.ulong (unsigned long), C.longlong (long long),
-C.ulonglong (unsigned long long), C.float, C.double.
-
-To access a struct, union, or enum type directly, prefix it with
-struct_, union_, or enum_, as in C.struct_stat.
-
-Any C function that returns a value may be called in a multiple
-assignment context to retrieve both the return value and the
-C errno variable as an os.Error. For example:
-
- n, err := C.atoi("abc")
-
-In C, a function argument written as a fixed size array
-actually requires a pointer to the first element of the array.
-C compilers are aware of this calling convention and adjust
-the call accordingly, but Go cannot. In Go, you must pass
-the pointer to the first element explicitly: C.f(&x[0]).
-
-Cgo transforms the input file into four output files: two Go source
-files, a C file for 6c (or 8c or 5c), and a C file for gcc.
-
-The standard package makefile rules in Make.pkg automate the
-process of using cgo. See $GOROOT/misc/cgo/stdio and
-$GOROOT/misc/cgo/gmp for examples.
-
-Cgo does not yet work with gccgo.
-*/
-package documentation
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
deleted file mode 100644
index a4d83f1e7..000000000
--- a/src/cmd/cgo/gcc.go
+++ /dev/null
@@ -1,1367 +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.
-
-// Annotate Ref in Prog with C types by parsing gcc debug output.
-// Conversion of debug output to Go types.
-
-package main
-
-import (
- "bytes"
- "debug/dwarf"
- "debug/elf"
- "debug/macho"
- "debug/pe"
- "encoding/binary"
- "flag"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "os"
- "runtime"
- "strconv"
- "strings"
- "unicode"
-)
-
-var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
-var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations")
-
-var nameToC = map[string]string{
- "schar": "signed char",
- "uchar": "unsigned char",
- "ushort": "unsigned short",
- "uint": "unsigned int",
- "ulong": "unsigned long",
- "longlong": "long long",
- "ulonglong": "unsigned long long",
- "complexfloat": "float complex",
- "complexdouble": "double complex",
-}
-
-// cname returns the C name to use for C.s.
-// The expansions are listed in nameToC and also
-// struct_foo becomes "struct foo", and similarly for
-// union and enum.
-func cname(s string) string {
- if t, ok := nameToC[s]; ok {
- return t
- }
-
- if strings.HasPrefix(s, "struct_") {
- return "struct " + s[len("struct_"):]
- }
- if strings.HasPrefix(s, "union_") {
- return "union " + s[len("union_"):]
- }
- if strings.HasPrefix(s, "enum_") {
- return "enum " + s[len("enum_"):]
- }
- return s
-}
-
-// ParseFlags extracts #cgo CFLAGS and LDFLAGS options from the file
-// preamble. Multiple occurrences are concatenated with a separating space,
-// even across files.
-func (p *Package) ParseFlags(f *File, srcfile string) {
- linesIn := strings.Split(f.Preamble, "\n")
- linesOut := make([]string, 0, len(linesIn))
-
-NextLine:
- for _, line := range linesIn {
- l := strings.TrimSpace(line)
- if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(int(l[4])) {
- linesOut = append(linesOut, line)
- continue
- }
-
- l = strings.TrimSpace(l[4:])
- fields := strings.SplitN(l, ":", 2)
- if len(fields) != 2 {
- fatalf("%s: bad #cgo line: %s", srcfile, line)
- }
-
- var k string
- kf := strings.Fields(fields[0])
- switch len(kf) {
- case 1:
- k = kf[0]
- case 2:
- k = kf[1]
- switch kf[0] {
- case runtime.GOOS:
- case runtime.GOARCH:
- case runtime.GOOS + "/" + runtime.GOARCH:
- default:
- continue NextLine
- }
- default:
- fatalf("%s: bad #cgo option: %s", srcfile, fields[0])
- }
-
- args, err := splitQuoted(fields[1])
- if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
- }
- for _, arg := range args {
- if !safeName(arg) {
- fatalf("%s: #cgo option %s is unsafe: %s", srcfile, k, arg)
- }
- }
-
- switch k {
-
- case "CFLAGS", "LDFLAGS":
- p.addToFlag(k, args)
-
- case "pkg-config":
- cflags, ldflags, err := pkgConfig(args)
- if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
- }
- p.addToFlag("CFLAGS", cflags)
- p.addToFlag("LDFLAGS", ldflags)
-
- default:
- fatalf("%s: unsupported #cgo option %s", srcfile, k)
-
- }
- }
- f.Preamble = strings.Join(linesOut, "\n")
-}
-
-// addToFlag appends args to flag. All flags are later written out onto the
-// _cgo_flags file for the build system to use.
-func (p *Package) addToFlag(flag string, args []string) {
- if oldv, ok := p.CgoFlags[flag]; ok {
- p.CgoFlags[flag] = oldv + " " + strings.Join(args, " ")
- } else {
- p.CgoFlags[flag] = strings.Join(args, " ")
- }
- if flag == "CFLAGS" {
- // We'll also need these when preprocessing for dwarf information.
- p.GccOptions = append(p.GccOptions, args...)
- }
-}
-
-// pkgConfig runs pkg-config and extracts --libs and --cflags information
-// for packages.
-func pkgConfig(packages []string) (cflags, ldflags []string, err os.Error) {
- for _, name := range packages {
- if len(name) == 0 || name[0] == '-' {
- return nil, nil, os.NewError(fmt.Sprintf("invalid name: %q", name))
- }
- }
-
- args := append([]string{"pkg-config", "--cflags"}, packages...)
- stdout, stderr, ok := run(nil, args)
- if !ok {
- os.Stderr.Write(stderr)
- return nil, nil, os.NewError("pkg-config failed")
- }
- cflags, err = splitQuoted(string(stdout))
- if err != nil {
- return
- }
-
- args = append([]string{"pkg-config", "--libs"}, packages...)
- stdout, stderr, ok = run(nil, args)
- if !ok {
- os.Stderr.Write(stderr)
- return nil, nil, os.NewError("pkg-config failed")
- }
- ldflags, err = splitQuoted(string(stdout))
- return
-}
-
-// splitQuoted splits the string s around each instance of one or more consecutive
-// white space characters while taking into account quotes and escaping, and
-// returns an array of substrings of s or an empty list if s contains only white space.
-// Single quotes and double quotes are recognized to prevent splitting within the
-// quoted region, and are removed from the resulting substrings. If a quote in s
-// isn't closed err will be set and r will have the unclosed argument as the
-// last element. The backslash is used for escaping.
-//
-// For example, the following string:
-//
-// `a b:"c d" 'e''f' "g\""`
-//
-// Would be parsed as:
-//
-// []string{"a", "b:c d", "ef", `g"`}
-//
-func splitQuoted(s string) (r []string, err os.Error) {
- var args []string
- arg := make([]int, len(s))
- escaped := false
- quoted := false
- quote := 0
- i := 0
- for _, rune := range s {
- switch {
- case escaped:
- escaped = false
- case rune == '\\':
- escaped = true
- continue
- case quote != 0:
- if rune == quote {
- quote = 0
- continue
- }
- case rune == '"' || rune == '\'':
- quoted = true
- quote = rune
- continue
- case unicode.IsSpace(rune):
- if quoted || i > 0 {
- quoted = false
- args = append(args, string(arg[:i]))
- i = 0
- }
- continue
- }
- arg[i] = rune
- i++
- }
- if quoted || i > 0 {
- args = append(args, string(arg[:i]))
- }
- if quote != 0 {
- err = os.NewError("unclosed quote")
- } else if escaped {
- err = os.NewError("unfinished escaping")
- }
- return args, err
-}
-
-var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
-
-func safeName(s string) bool {
- if s == "" {
- return false
- }
- for i := 0; i < len(s); i++ {
- if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
- return false
- }
- }
- return true
-}
-
-// Translate rewrites f.AST, the original Go input, to remove
-// references to the imported package C, replacing them with
-// references to the equivalent Go types, functions, and variables.
-func (p *Package) Translate(f *File) {
- for _, cref := range f.Ref {
- // Convert C.ulong to C.unsigned long, etc.
- cref.Name.C = cname(cref.Name.Go)
- }
- p.loadDefines(f)
- needType := p.guessKinds(f)
- if len(needType) > 0 {
- p.loadDWARF(f, needType)
- }
- p.rewriteRef(f)
-}
-
-// loadDefines coerces gcc into spitting out the #defines in use
-// in the file f and saves relevant renamings in f.Name[name].Define.
-func (p *Package) loadDefines(f *File) {
- var b bytes.Buffer
- b.WriteString(builtinProlog)
- b.WriteString(f.Preamble)
- stdout := p.gccDefines(b.Bytes())
-
- for _, line := range strings.Split(stdout, "\n") {
- if len(line) < 9 || line[0:7] != "#define" {
- continue
- }
-
- line = strings.TrimSpace(line[8:])
-
- var key, val string
- spaceIndex := strings.Index(line, " ")
- tabIndex := strings.Index(line, "\t")
-
- if spaceIndex == -1 && tabIndex == -1 {
- continue
- } else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) {
- key = line[0:spaceIndex]
- val = strings.TrimSpace(line[spaceIndex:])
- } else {
- key = line[0:tabIndex]
- val = strings.TrimSpace(line[tabIndex:])
- }
-
- if n := f.Name[key]; n != nil {
- if *debugDefine {
- fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
- }
- n.Define = val
- }
- }
-}
-
-// guessKinds tricks gcc into revealing the kind of each
-// name xxx for the references C.xxx in the Go input.
-// The kind is either a constant, type, or variable.
-func (p *Package) guessKinds(f *File) []*Name {
- // Coerce gcc into telling us whether each name is
- // a type, a value, or undeclared. We compile a function
- // containing the line:
- // name;
- // If name is a type, gcc will print:
- // cgo-test:2: warning: useless type name in empty declaration
- // If name is a value, gcc will print
- // cgo-test:2: warning: statement with no effect
- // If name is undeclared, gcc will print
- // cgo-test:2: error: 'name' undeclared (first use in this function)
- // A line number directive causes the line number to
- // correspond to the index in the names array.
- //
- // The line also has an enum declaration:
- // name; enum { _cgo_enum_1 = name };
- // If name is not a constant, gcc will print:
- // cgo-test:4: error: enumerator value for '_cgo_enum_4' is not an integer constant
- // we assume lines without that error are constants.
-
- // Make list of names that need sniffing, type lookup.
- toSniff := make([]*Name, 0, len(f.Name))
- needType := make([]*Name, 0, len(f.Name))
-
- for _, n := range f.Name {
- // If we've already found this name as a #define
- // and we can translate it as a constant value, do so.
- if n.Define != "" {
- ok := false
- if _, err := strconv.Atoi(n.Define); err == nil {
- ok = true
- } else if n.Define[0] == '"' || n.Define[0] == '\'' {
- _, err := parser.ParseExpr(fset, "", n.Define)
- if err == nil {
- ok = true
- }
- }
- if ok {
- n.Kind = "const"
- n.Const = n.Define
- continue
- }
-
- if isName(n.Define) {
- n.C = n.Define
- }
- }
-
- // If this is a struct, union, or enum type name,
- // record the kind but also that we need type information.
- if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
- n.Kind = "type"
- i := len(needType)
- needType = needType[0 : i+1]
- needType[i] = n
- continue
- }
-
- i := len(toSniff)
- toSniff = toSniff[0 : i+1]
- toSniff[i] = n
- }
-
- if len(toSniff) == 0 {
- return needType
- }
-
- var b bytes.Buffer
- b.WriteString(builtinProlog)
- b.WriteString(f.Preamble)
- b.WriteString("void __cgo__f__(void) {\n")
- b.WriteString("#line 0 \"cgo-test\"\n")
- for i, n := range toSniff {
- fmt.Fprintf(&b, "%s; enum { _cgo_enum_%d = %s }; /* cgo-test:%d */\n", n.C, i, n.C, i)
- }
- b.WriteString("}\n")
- stderr := p.gccErrors(b.Bytes())
- if stderr == "" {
- fatalf("gcc produced no output\non input:\n%s", b.Bytes())
- }
-
- names := make([]*Name, len(toSniff))
- copy(names, toSniff)
-
- isConst := make([]bool, len(toSniff))
- for i := range isConst {
- isConst[i] = true // until proven otherwise
- }
-
- for _, line := range strings.Split(stderr, "\n") {
- if len(line) < 9 || line[0:9] != "cgo-test:" {
- // the user will see any compiler errors when the code is compiled later.
- continue
- }
- line = line[9:]
- colon := strings.Index(line, ":")
- if colon < 0 {
- continue
- }
- i, err := strconv.Atoi(line[0:colon])
- if err != nil {
- continue
- }
- what := ""
- switch {
- default:
- continue
- case strings.Contains(line, ": useless type name in empty declaration"):
- what = "type"
- isConst[i] = false
- case strings.Contains(line, ": statement with no effect"):
- what = "not-type" // const or func or var
- case strings.Contains(line, "undeclared"):
- error(token.NoPos, "%s", strings.TrimSpace(line[colon+1:]))
- case strings.Contains(line, "is not an integer constant"):
- isConst[i] = false
- continue
- }
- n := toSniff[i]
- if n == nil {
- continue
- }
- toSniff[i] = nil
- n.Kind = what
-
- j := len(needType)
- needType = needType[0 : j+1]
- needType[j] = n
- }
- for i, b := range isConst {
- if b {
- names[i].Kind = "const"
- }
- }
- for _, n := range toSniff {
- if n == nil {
- continue
- }
- if n.Kind != "" {
- continue
- }
- error(token.NoPos, "could not determine kind of name for C.%s", n.Go)
- }
- if nerrors > 0 {
- fatalf("unresolved names")
- }
- return needType
-}
-
-// loadDWARF parses the DWARF debug information generated
-// by gcc to learn the details of the constants, variables, and types
-// being referred to as C.xxx.
-func (p *Package) loadDWARF(f *File, names []*Name) {
- // Extract the types from the DWARF section of an object
- // from a well-formed C program. Gcc only generates DWARF info
- // for symbols in the object file, so it is not enough to print the
- // preamble and hope the symbols we care about will be there.
- // Instead, emit
- // typeof(names[i]) *__cgo__i;
- // for each entry in names and then dereference the type we
- // learn for __cgo__i.
- var b bytes.Buffer
- b.WriteString(builtinProlog)
- b.WriteString(f.Preamble)
- for i, n := range names {
- fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n.C, i)
- if n.Kind == "const" {
- fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
- }
- }
-
- // Apple's LLVM-based gcc does not include the enumeration
- // names and values in its DWARF debug output. In case we're
- // using such a gcc, create a data block initialized with the values.
- // We can read them out of the object file.
- fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
- for _, n := range names {
- if n.Kind == "const" {
- fmt.Fprintf(&b, "\t%s,\n", n.C)
- } else {
- fmt.Fprintf(&b, "\t0,\n")
- }
- }
- fmt.Fprintf(&b, "\t0\n")
- fmt.Fprintf(&b, "};\n")
-
- d, bo, debugData := p.gccDebug(b.Bytes())
- enumVal := make([]int64, len(debugData)/8)
- for i := range enumVal {
- enumVal[i] = int64(bo.Uint64(debugData[i*8:]))
- }
-
- // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
- types := make([]dwarf.Type, len(names))
- enums := make([]dwarf.Offset, len(names))
- nameToIndex := make(map[*Name]int)
- for i, n := range names {
- nameToIndex[n] = i
- }
- r := d.Reader()
- for {
- e, err := r.Next()
- if err != nil {
- fatalf("reading DWARF entry: %s", err)
- }
- if e == nil {
- break
- }
- switch e.Tag {
- case dwarf.TagEnumerationType:
- offset := e.Offset
- for {
- e, err := r.Next()
- if err != nil {
- fatalf("reading DWARF entry: %s", err)
- }
- if e.Tag == 0 {
- break
- }
- if e.Tag == dwarf.TagEnumerator {
- entryName := e.Val(dwarf.AttrName).(string)
- if strings.HasPrefix(entryName, "__cgo_enum__") {
- n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):])
- if 0 <= n && n < len(names) {
- enums[n] = offset
- }
- }
- }
- }
- case dwarf.TagVariable:
- name, _ := e.Val(dwarf.AttrName).(string)
- typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
- if name == "" || typOff == 0 {
- fatalf("malformed DWARF TagVariable entry")
- }
- if !strings.HasPrefix(name, "__cgo__") {
- break
- }
- typ, err := d.Type(typOff)
- if err != nil {
- fatalf("loading DWARF type: %s", err)
- }
- t, ok := typ.(*dwarf.PtrType)
- if !ok || t == nil {
- fatalf("internal error: %s has non-pointer type", name)
- }
- i, err := strconv.Atoi(name[7:])
- if err != nil {
- fatalf("malformed __cgo__ name: %s", name)
- }
- if enums[i] != 0 {
- t, err := d.Type(enums[i])
- if err != nil {
- fatalf("loading DWARF type: %s", err)
- }
- types[i] = t
- } else {
- types[i] = t.Type
- }
- }
- if e.Tag != dwarf.TagCompileUnit {
- r.SkipChildren()
- }
- }
-
- // Record types and typedef information.
- var conv typeConv
- conv.Init(p.PtrSize)
- for i, n := range names {
- f, fok := types[i].(*dwarf.FuncType)
- if n.Kind != "type" && fok {
- n.Kind = "func"
- n.FuncType = conv.FuncType(f)
- } else {
- n.Type = conv.Type(types[i])
- if enums[i] != 0 && n.Type.EnumValues != nil {
- k := fmt.Sprintf("__cgo_enum__%d", i)
- n.Kind = "const"
- n.Const = strconv.Itoa64(n.Type.EnumValues[k])
- // Remove injected enum to ensure the value will deep-compare
- // equally in future loads of the same constant.
- n.Type.EnumValues[k] = 0, false
- } else if n.Kind == "const" && i < len(enumVal) {
- n.Const = strconv.Itoa64(enumVal[i])
- }
- }
- }
-
-}
-
-// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
-// Go equivalents, now that we have figured out the meaning of all
-// the xxx.
-func (p *Package) rewriteRef(f *File) {
- // Assign mangled names.
- for _, n := range f.Name {
- if n.Kind == "not-type" {
- n.Kind = "var"
- }
- if n.Mangle == "" {
- n.Mangle = "_C" + n.Kind + "_" + n.Go
- }
- }
-
- // Now that we have all the name types filled in,
- // scan through the Refs to identify the ones that
- // are trying to do a ,err call. Also check that
- // functions are only used in calls.
- for _, r := range f.Ref {
- if r.Name.Kind == "const" && r.Name.Const == "" {
- error(r.Pos(), "unable to find value of constant C.%s", r.Name.Go)
- }
- var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
- switch r.Context {
- case "call", "call2":
- if r.Name.Kind != "func" {
- if r.Name.Kind == "type" {
- r.Context = "type"
- expr = r.Name.Type.Go
- break
- }
- error(r.Pos(), "call of non-function C.%s", r.Name.Go)
- break
- }
- if r.Context == "call2" {
- if r.Name.FuncType.Result == nil {
- error(r.Pos(), "assignment count mismatch: 2 = 0")
- }
- // Invent new Name for the two-result function.
- n := f.Name["2"+r.Name.Go]
- if n == nil {
- n = new(Name)
- *n = *r.Name
- n.AddError = true
- n.Mangle = "_C2func_" + n.Go
- f.Name["2"+r.Name.Go] = n
- }
- expr = ast.NewIdent(n.Mangle)
- r.Name = n
- break
- }
- case "expr":
- if r.Name.Kind == "func" {
- error(r.Pos(), "must call C.%s", r.Name.Go)
- }
- if r.Name.Kind == "type" {
- // Okay - might be new(T)
- expr = r.Name.Type.Go
- }
- if r.Name.Kind == "var" {
- expr = &ast.StarExpr{X: expr}
- }
-
- case "type":
- if r.Name.Kind != "type" {
- error(r.Pos(), "expression C.%s used as type", r.Name.Go)
- } else {
- expr = r.Name.Type.Go
- }
- default:
- if r.Name.Kind == "func" {
- error(r.Pos(), "must call C.%s", r.Name.Go)
- }
- }
- *r.Expr = expr
- }
-}
-
-// gccName returns the name of the compiler to run. Use $GCC if set in
-// the environment, otherwise just "gcc".
-
-func (p *Package) gccName() (ret string) {
- if ret = os.Getenv("GCC"); ret == "" {
- ret = "gcc"
- }
- return
-}
-
-// gccMachine returns the gcc -m flag to use, either "-m32" or "-m64".
-func (p *Package) gccMachine() []string {
- switch runtime.GOARCH {
- case "amd64":
- return []string{"-m64"}
- case "386":
- return []string{"-m32"}
- }
- return nil
-}
-
-var gccTmp = objDir + "_cgo_.o"
-
-// gccCmd returns the gcc command line to use for compiling
-// the input.
-func (p *Package) gccCmd() []string {
- c := []string{
- p.gccName(),
- "-Wall", // many warnings
- "-Werror", // warnings are errors
- "-o" + gccTmp, // write object to tmp
- "-gdwarf-2", // generate DWARF v2 debugging symbols
- "-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise
- "-c", // do not link
- "-xc", // input language is C
- }
- c = append(c, p.GccOptions...)
- c = append(c, p.gccMachine()...)
- c = append(c, "-") //read input from standard input
- return c
-}
-
-// gccDebug runs gcc -gdwarf-2 over the C program stdin and
-// returns the corresponding DWARF data and, if present, debug data block.
-func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
- runGcc(stdin, p.gccCmd())
-
- if f, err := macho.Open(gccTmp); err == nil {
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
- }
- var data []byte
- if f.Symtab != nil {
- for i := range f.Symtab.Syms {
- s := &f.Symtab.Syms[i]
- // Mach-O still uses a leading _ to denote non-assembly symbols.
- if s.Name == "_"+"__cgodebug_data" {
- // Found it. Now find data section.
- if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
- sect := f.Sections[i]
- if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
- if sdat, err := sect.Data(); err == nil {
- data = sdat[s.Value-sect.Addr:]
- }
- }
- }
- }
- }
- }
- return d, f.ByteOrder, data
- }
-
- // Can skip debug data block in ELF and PE for now.
- // The DWARF information is complete.
-
- if f, err := elf.Open(gccTmp); err == nil {
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
- }
- return d, f.ByteOrder, nil
- }
-
- if f, err := pe.Open(gccTmp); err == nil {
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
- }
- return d, binary.LittleEndian, nil
- }
-
- fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp)
- panic("not reached")
-}
-
-// gccDefines runs gcc -E -dM -xc - over the C program stdin
-// and returns the corresponding standard output, which is the
-// #defines that gcc encountered while processing the input
-// and its included files.
-func (p *Package) gccDefines(stdin []byte) string {
- base := []string{p.gccName(), "-E", "-dM", "-xc"}
- base = append(base, p.gccMachine()...)
- stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
- return stdout
-}
-
-// gccErrors runs gcc over the C program stdin and returns
-// the errors that gcc prints. That is, this function expects
-// gcc to fail.
-func (p *Package) gccErrors(stdin []byte) string {
- // TODO(rsc): require failure
- args := p.gccCmd()
- if *debugGcc {
- fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
- os.Stderr.Write(stdin)
- fmt.Fprint(os.Stderr, "EOF\n")
- }
- stdout, stderr, _ := run(stdin, args)
- if *debugGcc {
- os.Stderr.Write(stdout)
- os.Stderr.Write(stderr)
- }
- return string(stderr)
-}
-
-// runGcc runs the gcc command line args with stdin on standard input.
-// If the command exits with a non-zero exit status, runGcc prints
-// details about what was run and exits.
-// Otherwise runGcc returns the data written to standard output and standard error.
-// Note that for some of the uses we expect useful data back
-// on standard error, but for those uses gcc must still exit 0.
-func runGcc(stdin []byte, args []string) (string, string) {
- if *debugGcc {
- fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
- os.Stderr.Write(stdin)
- fmt.Fprint(os.Stderr, "EOF\n")
- }
- stdout, stderr, ok := run(stdin, args)
- if *debugGcc {
- os.Stderr.Write(stdout)
- os.Stderr.Write(stderr)
- }
- if !ok {
- os.Stderr.Write(stderr)
- os.Exit(2)
- }
- return string(stdout), string(stderr)
-}
-
-// A typeConv is a translator from dwarf types to Go types
-// with equivalent memory layout.
-type typeConv struct {
- // Cache of already-translated or in-progress types.
- m map[dwarf.Type]*Type
- typedef map[string]ast.Expr
-
- // Predeclared types.
- bool ast.Expr
- byte ast.Expr // denotes padding
- int8, int16, int32, int64 ast.Expr
- uint8, uint16, uint32, uint64, uintptr ast.Expr
- float32, float64 ast.Expr
- complex64, complex128 ast.Expr
- void ast.Expr
- unsafePointer ast.Expr
- string ast.Expr
-
- ptrSize int64
-}
-
-var tagGen int
-var typedef = make(map[string]ast.Expr)
-
-func (c *typeConv) Init(ptrSize int64) {
- c.ptrSize = ptrSize
- c.m = make(map[dwarf.Type]*Type)
- c.bool = c.Ident("bool")
- c.byte = c.Ident("byte")
- c.int8 = c.Ident("int8")
- c.int16 = c.Ident("int16")
- c.int32 = c.Ident("int32")
- c.int64 = c.Ident("int64")
- c.uint8 = c.Ident("uint8")
- c.uint16 = c.Ident("uint16")
- c.uint32 = c.Ident("uint32")
- c.uint64 = c.Ident("uint64")
- c.uintptr = c.Ident("uintptr")
- c.float32 = c.Ident("float32")
- c.float64 = c.Ident("float64")
- c.complex64 = c.Ident("complex64")
- c.complex128 = c.Ident("complex128")
- c.unsafePointer = c.Ident("unsafe.Pointer")
- c.void = c.Ident("void")
- c.string = c.Ident("string")
-}
-
-// base strips away qualifiers and typedefs to get the underlying type
-func base(dt dwarf.Type) dwarf.Type {
- for {
- if d, ok := dt.(*dwarf.QualType); ok {
- dt = d.Type
- continue
- }
- if d, ok := dt.(*dwarf.TypedefType); ok {
- dt = d.Type
- continue
- }
- break
- }
- return dt
-}
-
-// Map from dwarf text names to aliases we use in package "C".
-var dwarfToName = map[string]string{
- "long int": "long",
- "long unsigned int": "ulong",
- "unsigned int": "uint",
- "short unsigned int": "ushort",
- "short int": "short",
- "long long int": "longlong",
- "long long unsigned int": "ulonglong",
- "signed char": "schar",
- "float complex": "complexfloat",
- "double complex": "complexdouble",
-}
-
-const signedDelta = 64
-
-// String returns the current type representation. Format arguments
-// are assembled within this method so that any changes in mutable
-// values are taken into account.
-func (tr *TypeRepr) String() string {
- if len(tr.Repr) == 0 {
- return ""
- }
- if len(tr.FormatArgs) == 0 {
- return tr.Repr
- }
- return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
-}
-
-// Empty returns true if the result of String would be "".
-func (tr *TypeRepr) Empty() bool {
- return len(tr.Repr) == 0
-}
-
-// Set modifies the type representation.
-// If fargs are provided, repr is used as a format for fmt.Sprintf.
-// Otherwise, repr is used unprocessed as the type representation.
-func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
- tr.Repr = repr
- tr.FormatArgs = fargs
-}
-
-// Type returns a *Type with the same memory layout as
-// dtype when used as the type of a variable or a struct field.
-func (c *typeConv) Type(dtype dwarf.Type) *Type {
- if t, ok := c.m[dtype]; ok {
- if t.Go == nil {
- fatalf("type conversion loop at %s", dtype)
- }
- return t
- }
-
- t := new(Type)
- t.Size = dtype.Size()
- t.Align = -1
- t.C = &TypeRepr{Repr: dtype.Common().Name}
- c.m[dtype] = t
-
- if t.Size < 0 {
- // Unsized types are [0]byte
- t.Size = 0
- t.Go = c.Opaque(0)
- if t.C.Empty() {
- t.C.Set("void")
- }
- return t
- }
-
- switch dt := dtype.(type) {
- default:
- fatalf("unexpected type: %s", dtype)
-
- case *dwarf.AddrType:
- if t.Size != c.ptrSize {
- fatalf("unexpected: %d-byte address type - %s", t.Size, dtype)
- }
- t.Go = c.uintptr
- t.Align = t.Size
-
- case *dwarf.ArrayType:
- if dt.StrideBitSize > 0 {
- // Cannot represent bit-sized elements in Go.
- t.Go = c.Opaque(t.Size)
- break
- }
- gt := &ast.ArrayType{
- Len: c.intExpr(dt.Count),
- }
- t.Go = gt // publish before recursive call
- sub := c.Type(dt.Type)
- t.Align = sub.Align
- gt.Elt = sub.Go
- t.C.Set("typeof(%s[%d])", sub.C, dt.Count)
-
- case *dwarf.BoolType:
- t.Go = c.bool
- t.Align = c.ptrSize
-
- case *dwarf.CharType:
- if t.Size != 1 {
- fatalf("unexpected: %d-byte char type - %s", t.Size, dtype)
- }
- t.Go = c.int8
- t.Align = 1
-
- case *dwarf.EnumType:
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
- t.C.Set("enum " + dt.EnumName)
- signed := 0
- t.EnumValues = make(map[string]int64)
- for _, ev := range dt.Val {
- t.EnumValues[ev.Name] = ev.Val
- if ev.Val < 0 {
- signed = signedDelta
- }
- }
- switch t.Size + int64(signed) {
- default:
- fatalf("unexpected: %d-byte enum type - %s", t.Size, dtype)
- case 1:
- t.Go = c.uint8
- case 2:
- t.Go = c.uint16
- case 4:
- t.Go = c.uint32
- case 8:
- t.Go = c.uint64
- case 1 + signedDelta:
- t.Go = c.int8
- case 2 + signedDelta:
- t.Go = c.int16
- case 4 + signedDelta:
- t.Go = c.int32
- case 8 + signedDelta:
- t.Go = c.int64
- }
-
- case *dwarf.FloatType:
- switch t.Size {
- default:
- fatalf("unexpected: %d-byte float type - %s", t.Size, dtype)
- case 4:
- t.Go = c.float32
- case 8:
- t.Go = c.float64
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
-
- case *dwarf.ComplexType:
- switch t.Size {
- default:
- fatalf("unexpected: %d-byte complex type - %s", t.Size, dtype)
- case 8:
- t.Go = c.complex64
- case 16:
- t.Go = c.complex128
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
-
- case *dwarf.FuncType:
- // No attempt at translation: would enable calls
- // directly between worlds, but we need to moderate those.
- t.Go = c.uintptr
- t.Align = c.ptrSize
-
- case *dwarf.IntType:
- if dt.BitSize > 0 {
- fatalf("unexpected: %d-bit int type - %s", dt.BitSize, dtype)
- }
- switch t.Size {
- default:
- fatalf("unexpected: %d-byte int type - %s", t.Size, dtype)
- case 1:
- t.Go = c.int8
- case 2:
- t.Go = c.int16
- case 4:
- t.Go = c.int32
- case 8:
- t.Go = c.int64
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
-
- case *dwarf.PtrType:
- t.Align = c.ptrSize
-
- // Translate void* as unsafe.Pointer
- if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
- t.Go = c.unsafePointer
- t.C.Set("void*")
- break
- }
-
- gt := &ast.StarExpr{}
- t.Go = gt // publish before recursive call
- sub := c.Type(dt.Type)
- gt.X = sub.Go
- t.C.Set("%s*", sub.C)
-
- case *dwarf.QualType:
- // Ignore qualifier.
- t = c.Type(dt.Type)
- c.m[dtype] = t
- return t
-
- case *dwarf.StructType:
- // Convert to Go struct, being careful about alignment.
- // Have to give it a name to simulate C "struct foo" references.
- tag := dt.StructName
- if tag == "" {
- tag = "__" + strconv.Itoa(tagGen)
- tagGen++
- } else if t.C.Empty() {
- t.C.Set(dt.Kind + " " + tag)
- }
- name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
- t.Go = name // publish before recursive calls
- switch dt.Kind {
- case "union", "class":
- typedef[name.Name] = c.Opaque(t.Size)
- if t.C.Empty() {
- t.C.Set("typeof(unsigned char[%d])", t.Size)
- }
- case "struct":
- g, csyntax, align := c.Struct(dt)
- if t.C.Empty() {
- t.C.Set(csyntax)
- }
- t.Align = align
- typedef[name.Name] = g
- }
-
- case *dwarf.TypedefType:
- // Record typedef for printing.
- if dt.Name == "_GoString_" {
- // Special C name for Go string type.
- // Knows string layout used by compilers: pointer plus length,
- // which rounds up to 2 pointers after alignment.
- t.Go = c.string
- t.Size = c.ptrSize * 2
- t.Align = c.ptrSize
- break
- }
- name := c.Ident("_Ctypedef_" + dt.Name)
- t.Go = name // publish before recursive call
- sub := c.Type(dt.Type)
- t.Size = sub.Size
- t.Align = sub.Align
- if _, ok := typedef[name.Name]; !ok {
- typedef[name.Name] = sub.Go
- }
-
- case *dwarf.UcharType:
- if t.Size != 1 {
- fatalf("unexpected: %d-byte uchar type - %s", t.Size, dtype)
- }
- t.Go = c.uint8
- t.Align = 1
-
- case *dwarf.UintType:
- if dt.BitSize > 0 {
- fatalf("unexpected: %d-bit uint type - %s", dt.BitSize, dtype)
- }
- switch t.Size {
- default:
- fatalf("unexpected: %d-byte uint type - %s", t.Size, dtype)
- case 1:
- t.Go = c.uint8
- case 2:
- t.Go = c.uint16
- case 4:
- t.Go = c.uint32
- case 8:
- t.Go = c.uint64
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
-
- case *dwarf.VoidType:
- t.Go = c.void
- t.C.Set("void")
- }
-
- switch dtype.(type) {
- case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
- s := dtype.Common().Name
- if s != "" {
- if ss, ok := dwarfToName[s]; ok {
- s = ss
- }
- s = strings.Join(strings.Split(s, " "), "") // strip spaces
- name := c.Ident("_Ctype_" + s)
- typedef[name.Name] = t.Go
- t.Go = name
- }
- }
-
- if t.C.Empty() {
- fatalf("internal error: did not create C name for %s", dtype)
- }
-
- return t
-}
-
-// FuncArg returns a Go type with the same memory layout as
-// dtype when used as the type of a C function argument.
-func (c *typeConv) FuncArg(dtype dwarf.Type) *Type {
- t := c.Type(dtype)
- switch dt := dtype.(type) {
- case *dwarf.ArrayType:
- // Arrays are passed implicitly as pointers in C.
- // In Go, we must be explicit.
- tr := &TypeRepr{}
- tr.Set("%s*", t.C)
- return &Type{
- Size: c.ptrSize,
- Align: c.ptrSize,
- Go: &ast.StarExpr{X: t.Go},
- C: tr,
- }
- case *dwarf.TypedefType:
- // C has much more relaxed rules than Go for
- // implicit type conversions. When the parameter
- // is type T defined as *X, simulate a little of the
- // laxness of C by making the argument *X instead of T.
- if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
- // Unless the typedef happens to point to void* since
- // Go has special rules around using unsafe.Pointer.
- if _, void := base(ptr.Type).(*dwarf.VoidType); !void {
- return c.Type(ptr)
- }
- }
- }
- return t
-}
-
-// FuncType returns the Go type analogous to dtype.
-// There is no guarantee about matching memory layout.
-func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType {
- p := make([]*Type, len(dtype.ParamType))
- gp := make([]*ast.Field, len(dtype.ParamType))
- for i, f := range dtype.ParamType {
- // gcc's DWARF generator outputs a single DotDotDotType parameter for
- // function pointers that specify no parameters (e.g. void
- // (*__cgo_0)()). Treat this special case as void. This case is
- // invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
- // legal).
- if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
- p, gp = nil, nil
- break
- }
- p[i] = c.FuncArg(f)
- gp[i] = &ast.Field{Type: p[i].Go}
- }
- var r *Type
- var gr []*ast.Field
- if _, ok := dtype.ReturnType.(*dwarf.VoidType); !ok && dtype.ReturnType != nil {
- r = c.Type(dtype.ReturnType)
- gr = []*ast.Field{&ast.Field{Type: r.Go}}
- }
- return &FuncType{
- Params: p,
- Result: r,
- Go: &ast.FuncType{
- Params: &ast.FieldList{List: gp},
- Results: &ast.FieldList{List: gr},
- },
- }
-}
-
-// Identifier
-func (c *typeConv) Ident(s string) *ast.Ident {
- return ast.NewIdent(s)
-}
-
-// Opaque type of n bytes.
-func (c *typeConv) Opaque(n int64) ast.Expr {
- return &ast.ArrayType{
- Len: c.intExpr(n),
- Elt: c.byte,
- }
-}
-
-// Expr for integer n.
-func (c *typeConv) intExpr(n int64) ast.Expr {
- return &ast.BasicLit{
- Kind: token.INT,
- Value: strconv.Itoa64(n),
- }
-}
-
-// Add padding of given size to fld.
-func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
- n := len(fld)
- fld = fld[0 : n+1]
- fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
- return fld
-}
-
-// Struct conversion: return Go and (6g) C syntax for type.
-func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax string, align int64) {
- var buf bytes.Buffer
- buf.WriteString("struct {")
- fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
- off := int64(0)
-
- // Rename struct fields that happen to be named Go keywords into
- // _{keyword}. Create a map from C ident -> Go ident. The Go ident will
- // be mangled. Any existing identifier that already has the same name on
- // the C-side will cause the Go-mangled version to be prefixed with _.
- // (e.g. in a struct with fields '_type' and 'type', the latter would be
- // rendered as '__type' in Go).
- ident := make(map[string]string)
- used := make(map[string]bool)
- for _, f := range dt.Field {
- ident[f.Name] = f.Name
- used[f.Name] = true
- }
- for cid, goid := range ident {
- if token.Lookup([]byte(goid)).IsKeyword() {
- // Avoid keyword
- goid = "_" + goid
-
- // Also avoid existing fields
- for _, exist := used[goid]; exist; _, exist = used[goid] {
- goid = "_" + goid
- }
-
- used[goid] = true
- ident[cid] = goid
- }
- }
-
- for _, f := range dt.Field {
- if f.BitSize > 0 && f.BitSize != f.ByteSize*8 {
- continue
- }
- if f.ByteOffset > off {
- fld = c.pad(fld, f.ByteOffset-off)
- off = f.ByteOffset
- }
- t := c.Type(f.Type)
- n := len(fld)
- fld = fld[0 : n+1]
-
- fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[f.Name])}, Type: t.Go}
- off += t.Size
- buf.WriteString(t.C.String())
- buf.WriteString(" ")
- buf.WriteString(f.Name)
- buf.WriteString("; ")
- if t.Align > align {
- align = t.Align
- }
- }
- if off < dt.ByteSize {
- fld = c.pad(fld, dt.ByteSize-off)
- off = dt.ByteSize
- }
- if off != dt.ByteSize {
- fatalf("struct size calculation error")
- }
- buf.WriteString("}")
- csyntax = buf.String()
- expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
- return
-}
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
deleted file mode 100644
index be9c2bc4f..000000000
--- a/src/cmd/cgo/main.go
+++ /dev/null
@@ -1,268 +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.
-
-// Cgo; see gmp.go for an overview.
-
-// TODO(rsc):
-// Emit correct line number annotations.
-// Make 6g understand the annotations.
-
-package main
-
-import (
- "crypto/md5"
- "flag"
- "fmt"
- "go/ast"
- "go/token"
- "io"
- "os"
- "path/filepath"
- "reflect"
- "strings"
-)
-
-// A Package collects information about the package we're going to write.
-type Package struct {
- PackageName string // name of package
- PackagePath string
- PtrSize int64
- GccOptions []string
- CgoFlags map[string]string // #cgo flags (CFLAGS, LDFLAGS)
- Written map[string]bool
- Name map[string]*Name // accumulated Name from Files
- Typedef map[string]ast.Expr // accumulated Typedef from Files
- ExpFunc []*ExpFunc // accumulated ExpFunc from Files
- Decl []ast.Decl
- GoFiles []string // list of Go files
- GccFiles []string // list of gcc output files
-}
-
-// A File collects information about a single Go input file.
-type File struct {
- AST *ast.File // parsed AST
- Package string // Package name
- Preamble string // C preamble (doc comment on import "C")
- Ref []*Ref // all references to C.xxx in AST
- ExpFunc []*ExpFunc // exported functions for this file
- Name map[string]*Name // map from Go name to Name
- Typedef map[string]ast.Expr // translations of all necessary types from C
-}
-
-// A Ref refers to an expression of the form C.xxx in the AST.
-type Ref struct {
- Name *Name
- Expr *ast.Expr
- Context string // "type", "expr", "call", or "call2"
-}
-
-func (r *Ref) Pos() token.Pos {
- return (*r.Expr).Pos()
-}
-
-// A Name collects information about C.xxx.
-type Name struct {
- Go string // name used in Go referring to package C
- Mangle string // name used in generated Go
- C string // name used in C
- Define string // #define expansion
- Kind string // "const", "type", "var", "func", "not-type"
- Type *Type // the type of xxx
- FuncType *FuncType
- AddError bool
- Const string // constant definition
-}
-
-// A ExpFunc is an exported function, callable from C.
-// Such functions are identified in the Go input file
-// by doc comments containing the line //export ExpName
-type ExpFunc struct {
- Func *ast.FuncDecl
- ExpName string // name to use from C
-}
-
-// A TypeRepr contains the string representation of a type.
-type TypeRepr struct {
- Repr string
- FormatArgs []interface{}
-}
-
-// A Type collects information about a type in both the C and Go worlds.
-type Type struct {
- Size int64
- Align int64
- C *TypeRepr
- Go ast.Expr
- EnumValues map[string]int64
-}
-
-// A FuncType collects information about a function type in both the C and Go worlds.
-type FuncType struct {
- Params []*Type
- Result *Type
- Go *ast.FuncType
-}
-
-func usage() {
- fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-var ptrSizeMap = map[string]int64{
- "386": 4,
- "amd64": 8,
- "arm": 4,
-}
-
-var cPrefix string
-
-var fset = token.NewFileSet()
-
-var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
-
-func main() {
- flag.Usage = usage
- flag.Parse()
-
- if *dynobj != "" {
- // cgo -dynimport is essentially a separate helper command
- // built into the cgo binary. It scans a gcc-produced executable
- // and dumps information about the imported symbols and the
- // imported libraries. The Make.pkg rules for cgo prepare an
- // appropriate executable and then use its import information
- // instead of needing to make the linkers duplicate all the
- // specialized knowledge gcc has about where to look for imported
- // symbols and which ones to use.
- dynimport(*dynobj)
- return
- }
-
- args := flag.Args()
- if len(args) < 1 {
- usage()
- }
-
- // Find first arg that looks like a go file and assume everything before
- // that are options to pass to gcc.
- var i int
- for i = len(args); i > 0; i-- {
- if !strings.HasSuffix(args[i-1], ".go") {
- break
- }
- }
- if i == len(args) {
- usage()
- }
-
- // Copy it to a new slice so it can grow.
- gccOptions := make([]string, i)
- copy(gccOptions, args[0:i])
-
- goFiles := args[i:]
-
- arch := os.Getenv("GOARCH")
- if arch == "" {
- fatalf("$GOARCH is not set")
- }
- ptrSize := ptrSizeMap[arch]
- if ptrSize == 0 {
- fatalf("unknown $GOARCH %q", arch)
- }
-
- // Clear locale variables so gcc emits English errors [sic].
- os.Setenv("LANG", "en_US.UTF-8")
- os.Setenv("LC_ALL", "C")
- os.Setenv("LC_CTYPE", "C")
-
- p := &Package{
- PtrSize: ptrSize,
- GccOptions: gccOptions,
- CgoFlags: make(map[string]string),
- Written: make(map[string]bool),
- }
-
- // Need a unique prefix for the global C symbols that
- // we use to coordinate between gcc and ourselves.
- // We already put _cgo_ at the beginning, so the main
- // concern is other cgo wrappers for the same functions.
- // Use the beginning of the md5 of the input to disambiguate.
- h := md5.New()
- for _, input := range goFiles {
- f, err := os.Open(input)
- if err != nil {
- fatalf("%s", err)
- }
- io.Copy(h, f)
- f.Close()
- }
- cPrefix = fmt.Sprintf("_%x", h.Sum()[0:6])
-
- fs := make([]*File, len(goFiles))
- for i, input := range goFiles {
- // Parse flags for all files before translating due to CFLAGS.
- f := new(File)
- f.ReadGo(input)
- p.ParseFlags(f, input)
- fs[i] = f
- }
-
- // make sure that _obj directory exists, so that we can write
- // all the output files there.
- os.Mkdir("_obj", 0777)
-
- for i, input := range goFiles {
- f := fs[i]
- p.Translate(f)
- for _, cref := range f.Ref {
- switch cref.Context {
- case "call", "call2":
- if cref.Name.Kind != "type" {
- break
- }
- *cref.Expr = cref.Name.Type.Go
- }
- }
- if nerrors > 0 {
- os.Exit(2)
- }
- pkg := f.Package
- if dir := os.Getenv("CGOPKGPATH"); dir != "" {
- pkg = filepath.Join(dir, pkg)
- }
- p.PackagePath = pkg
- p.writeOutput(f, input)
-
- p.Record(f)
- }
-
- p.writeDefs()
- if nerrors > 0 {
- os.Exit(2)
- }
-}
-
-// Record what needs to be recorded about f.
-func (p *Package) Record(f *File) {
- if p.PackageName == "" {
- p.PackageName = f.Package
- } else if p.PackageName != f.Package {
- error(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
- }
-
- if p.Name == nil {
- p.Name = f.Name
- } else {
- for k, v := range f.Name {
- if p.Name[k] == nil {
- p.Name[k] = v
- } else if !reflect.DeepEqual(p.Name[k], v) {
- error(token.NoPos, "inconsistent definitions for C.%s", k)
- }
- }
- }
-
- p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
- p.Decl = append(p.Decl, f.AST.Decls...)
-}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
deleted file mode 100644
index 6802dd1cf..000000000
--- a/src/cmd/cgo/out.go
+++ /dev/null
@@ -1,730 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "bytes"
- "debug/elf"
- "debug/macho"
- "debug/pe"
- "fmt"
- "go/ast"
- "go/printer"
- "go/token"
- "os"
- "path/filepath"
- "strings"
-)
-
-var objDir = "_obj" + string(filepath.Separator)
-
-// 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")
- fm := creat(objDir + "_cgo_main.c")
-
- fflg := creat(objDir + "_cgo_flags")
- for k, v := range p.CgoFlags {
- fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
- }
- fflg.Close()
-
- // Write C main file for using gcc to resolve imports.
- fmt.Fprintf(fm, "int main() { return 0; }\n")
- fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
- fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
- fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
-
- // Write second Go output: definitions of _C_xxx.
- // In a separate file so that the import of "unsafe" does not
- // pollute the original file.
- fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
- fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
- fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
- fmt.Fprintf(fgo2, "import \"os\"\n\n")
- fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
- fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
- fmt.Fprintf(fgo2, "func _Cerrno(dst *os.Error, x int) { *dst = os.Errno(x) }\n")
-
- for name, def := range typedef {
- fmt.Fprintf(fgo2, "type %s ", name)
- printer.Fprint(fgo2, fset, def)
- fmt.Fprintf(fgo2, "\n")
- }
- fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
-
- fmt.Fprintf(fc, cProlog)
-
- var cVars []string
- for _, n := range p.Name {
- if n.Kind != "var" {
- continue
- }
- cVars = append(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)
-
- fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
- fmt.Fprintf(fc, "void *·%s = &%s;\n", n.Mangle, n.C)
- fmt.Fprintf(fc, "\n")
-
- fmt.Fprintf(fgo2, "var %s ", n.Mangle)
- printer.Fprint(fgo2, fset, &ast.StarExpr{X: n.Type.Go})
- fmt.Fprintf(fgo2, "\n")
- }
- fmt.Fprintf(fc, "\n")
-
- for _, n := range p.Name {
- if n.Const != "" {
- fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
- }
- }
- fmt.Fprintf(fgo2, "\n")
-
- for _, n := range p.Name {
- if n.FuncType != nil {
- p.writeDefsFunc(fc, fgo2, n)
- }
- }
-
- p.writeExports(fgo2, fc, fm)
-
- fgo2.Close()
- fc.Close()
-}
-
-func dynimport(obj string) {
- if f, err := elf.Open(obj); err == nil {
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
- }
- for _, s := range sym {
- targ := s.Name
- if s.Version != "" {
- targ += "@" + s.Version
- }
- fmt.Printf("#pragma dynimport %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.Printf("#pragma dynimport _ _ %q\n", l)
- }
- return
- }
-
- if f, err := macho.Open(obj); err == nil {
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
- }
- for _, s := range sym {
- if len(s) > 0 && s[0] == '_' {
- s = s[1:]
- }
- fmt.Printf("#pragma dynimport %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.Printf("#pragma dynimport _ _ %q\n", l)
- }
- return
- }
-
- if f, err := pe.Open(obj); err == nil {
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
- }
- for _, s := range sym {
- ss := strings.Split(s, ":")
- fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
- }
- return
- }
-
- fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
-}
-
-// Construct a gcc struct matching the 6c argument frame.
-// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
-// These assumptions are checked by the gccProlog.
-// Also assumes that 6c convention is to word-align the
-// input and output parameters.
-func (p *Package) structType(n *Name) (string, int64) {
- var buf bytes.Buffer
- fmt.Fprint(&buf, "struct {\n")
- off := int64(0)
- for i, t := range n.FuncType.Params {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
- off += pad
- }
- fmt.Fprintf(&buf, "\t\t%s p%d;\n", t.C, i)
- off += t.Size
- }
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
- off += pad
- }
- if t := n.FuncType.Result; t != nil {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
- off += pad
- }
- qual := ""
- if c := t.C.String(); c[len(c)-1] == '*' {
- qual = "const "
- }
- fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C)
- off += t.Size
- }
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
- off += pad
- }
- if n.AddError {
- fmt.Fprint(&buf, "\t\tvoid *e[2]; /* os.Error */\n")
- off += 2 * p.PtrSize
- }
- if off == 0 {
- fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
- }
- fmt.Fprintf(&buf, "\t}")
- return buf.String(), off
-}
-
-func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
- name := n.Go
- gtype := n.FuncType.Go
- if n.AddError {
- // Add "os.Error" to return type list.
- // Type list is known to be 0 or 1 element - it's a C function.
- err := &ast.Field{Type: ast.NewIdent("os.Error")}
- l := gtype.Results.List
- if len(l) == 0 {
- l = []*ast.Field{err}
- } else {
- l = []*ast.Field{l[0], err}
- }
- t := new(ast.FuncType)
- *t = *gtype
- t.Results = &ast.FieldList{List: l}
- gtype = t
- }
-
- // Go func declaration.
- d := &ast.FuncDecl{
- Name: ast.NewIdent(n.Mangle),
- Type: gtype,
- }
- printer.Fprint(fgo2, fset, d)
- fmt.Fprintf(fgo2, "\n")
-
- if name == "CString" || name == "GoString" || name == "GoStringN" {
- // The builtins are already defined in the C prolog.
- return
- }
-
- var argSize int64
- _, argSize = p.structType(n)
-
- // C wrapper calls into gcc, passing a pointer to the argument frame.
- fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
- fmt.Fprintf(fc, "\n")
- fmt.Fprintf(fc, "void\n")
- if argSize == 0 {
- argSize++
- }
- fmt.Fprintf(fc, "·%s(struct{uint8 x[%d];}p)\n", n.Mangle, argSize)
- fmt.Fprintf(fc, "{\n")
- fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
- if n.AddError {
- // gcc leaves errno in first word of interface at end of p.
- // check whether it is zero; if so, turn interface into nil.
- // if not, turn interface into errno.
- // Go init function initializes ·_Cerrno with an os.Errno
- // for us to copy.
- fmt.Fprintln(fc, ` {
- int32 e;
- void **v;
- v = (void**)(&p+1) - 2; /* v = final two void* of p */
- e = *(int32*)v;
- v[0] = (void*)0xdeadbeef;
- v[1] = (void*)0xdeadbeef;
- if(e == 0) {
- /* nil interface */
- v[0] = 0;
- v[1] = 0;
- } else {
- ·_Cerrno(v, e); /* fill in v as os.Error for errno e */
- }
- }`)
- }
- fmt.Fprintf(fc, "}\n")
- fmt.Fprintf(fc, "\n")
-}
-
-// writeOutput creates stubs for a specific source file to be compiled by 6g
-// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
-func (p *Package) writeOutput(f *File, srcfile string) {
- base := srcfile
- if strings.HasSuffix(base, ".go") {
- base = base[0 : len(base)-3]
- }
- base = strings.Map(slashToUnderscore, base)
- fgo1 := creat(objDir + base + ".cgo1.go")
- fgcc := creat(objDir + base + ".cgo2.c")
-
- p.GoFiles = append(p.GoFiles, base+".cgo1.go")
- p.GccFiles = append(p.GccFiles, base+".cgo2.c")
-
- // Write Go output: Go input with rewrites of C.xxx to _C_xxx.
- fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
- fmt.Fprintf(fgo1, "//line %s:1\n", srcfile)
- printer.Fprint(fgo1, fset, f.AST)
-
- // While we process the vars and funcs, also write 6c and gcc output.
- // Gcc output starts with the preamble.
- fmt.Fprintf(fgcc, "%s\n", f.Preamble)
- fmt.Fprintf(fgcc, "%s\n", gccProlog)
-
- for _, n := range f.Name {
- if n.FuncType != nil {
- p.writeOutputFunc(fgcc, n)
- }
- }
-
- fgo1.Close()
- fgcc.Close()
-}
-
-func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
- name := n.Mangle
- if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || p.Written[name] {
- // The builtins are already defined in the C prolog, and we don't
- // want to duplicate function definitions we've already done.
- return
- }
- p.Written[name] = true
-
- ctype, _ := p.structType(n)
-
- // Gcc wrapper unpacks the C argument struct
- // and calls the actual C function.
- fmt.Fprintf(fgcc, "void\n")
- fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
- fmt.Fprintf(fgcc, "{\n")
- if n.AddError {
- fmt.Fprintf(fgcc, "\tint e;\n") // assuming 32 bit (see comment above structType)
- fmt.Fprintf(fgcc, "\terrno = 0;\n")
- }
- // We're trying to write a gcc struct that matches 6c/8c/5c's layout.
- // Use packed attribute to force no padding in this struct in case
- // gcc has different packing requirements. For example,
- // on 386 Windows, gcc wants to 8-align int64s, but 8c does not.
- fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__)) *a = v;\n", ctype)
- fmt.Fprintf(fgcc, "\t")
- if t := n.FuncType.Result; t != nil {
- fmt.Fprintf(fgcc, "a->r = ")
- if c := t.C.String(); c[len(c)-1] == '*' {
- fmt.Fprintf(fgcc, "(const %s) ", t.C)
- }
- }
- fmt.Fprintf(fgcc, "%s(", n.C)
- for i := range n.FuncType.Params {
- if i > 0 {
- fmt.Fprintf(fgcc, ", ")
- }
- fmt.Fprintf(fgcc, "a->p%d", i)
- }
- fmt.Fprintf(fgcc, ");\n")
- if n.AddError {
- fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
- }
- fmt.Fprintf(fgcc, "}\n")
- fmt.Fprintf(fgcc, "\n")
-}
-
-// 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) {
- fgcc := creat(objDir + "_cgo_export.c")
- fgcch := creat("_cgo_export.h")
-
- fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
- fmt.Fprintf(fgcch, "%s\n", gccExportHeaderProlog)
-
- fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
- fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
-
- for _, exp := range p.ExpFunc {
- fn := exp.Func
-
- // Construct a gcc struct matching the 6c argument and
- // result frame. The gcc struct will be compiled with
- // __attribute__((packed)) so all padding must be accounted
- // for explicitly.
- ctype := "struct {\n"
- off := int64(0)
- npad := 0
- if fn.Recv != nil {
- t := p.cgoType(fn.Recv.List[0].Type)
- ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
- off += t.Size
- }
- fntype := fn.Type
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- t := p.cgoType(atype)
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
- off += t.Size
- })
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- t := p.cgoType(atype)
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d]\n", npad, pad)
- off += pad
- npad++
- }
- ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
- off += t.Size
- })
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- if ctype == "struct {\n" {
- ctype += "\t\tchar unused;\n" // avoid empty struct
- }
- ctype += "\t}"
-
- // Get the return type of the wrapper function
- // compiled by gcc.
- gccResult := ""
- if fntype.Results == nil || len(fntype.Results.List) == 0 {
- gccResult = "void"
- } else if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
- gccResult = p.cgoType(fntype.Results.List[0].Type).C.String()
- } else {
- fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
- fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
- forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i)
- })
- fmt.Fprintf(fgcch, "};\n")
- gccResult = "struct " + exp.ExpName + "_return"
- }
-
- // Build the wrapper function compiled by gcc.
- s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
- if fn.Recv != nil {
- s += p.cgoType(fn.Recv.List[0].Type).C.String()
- s += " recv"
- }
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- if i > 0 || fn.Recv != nil {
- s += ", "
- }
- s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
- })
- s += ")"
- fmt.Fprintf(fgcch, "\nextern %s;\n", s)
-
- fmt.Fprintf(fgcc, "extern _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
- fmt.Fprintf(fgcc, "\n%s\n", s)
- fmt.Fprintf(fgcc, "{\n")
- fmt.Fprintf(fgcc, "\t%s __attribute__((packed)) a;\n", ctype)
- if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
- fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
- }
- if fn.Recv != nil {
- fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
- }
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
- })
- fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
- if gccResult != "void" {
- if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
- fmt.Fprintf(fgcc, "\treturn a.r0;\n")
- } else {
- forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
- })
- fmt.Fprintf(fgcc, "\treturn r;\n")
- }
- }
- fmt.Fprintf(fgcc, "}\n")
-
- // Build the wrapper function compiled by 6c/8c
- goname := exp.Func.Name.Name
- if fn.Recv != nil {
- goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
- }
- fmt.Fprintf(fc, "extern void ·%s();\n", goname)
- fmt.Fprintf(fc, "\nvoid\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(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
-
- // Calling a function with a receiver from C requires
- // a Go wrapper function.
- if fn.Recv != nil {
- fmt.Fprintf(fgo2, "func %s(recv ", goname)
- printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgo2, ", p%d ", i)
- printer.Fprint(fgo2, fset, atype)
- })
- fmt.Fprintf(fgo2, ")")
- if gccResult != "void" {
- fmt.Fprint(fgo2, " (")
- forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- if i > 0 {
- fmt.Fprint(fgo2, ", ")
- }
- printer.Fprint(fgo2, fset, atype)
- })
- fmt.Fprint(fgo2, ")")
- }
- fmt.Fprint(fgo2, " {\n")
- fmt.Fprint(fgo2, "\t")
- if gccResult != "void" {
- fmt.Fprint(fgo2, "return ")
- }
- fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- if i > 0 {
- fmt.Fprint(fgo2, ", ")
- }
- fmt.Fprintf(fgo2, "p%d", i)
- })
- fmt.Fprint(fgo2, ")\n")
- fmt.Fprint(fgo2, "}\n")
- }
- }
-}
-
-// Call a function for each entry in an ast.FieldList, passing the
-// index into the list and the type.
-func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
- if fl == nil {
- return
- }
- i := 0
- for _, r := range fl.List {
- if r.Names == nil {
- fn(i, r.Type)
- i++
- } else {
- for _ = range r.Names {
- fn(i, r.Type)
- i++
- }
- }
- }
-}
-
-func c(repr string, args ...interface{}) *TypeRepr {
- return &TypeRepr{repr, args}
-}
-
-// Map predeclared Go types to Type.
-var goTypes = map[string]*Type{
- "int": &Type{Size: 4, Align: 4, C: c("int")},
- "uint": &Type{Size: 4, Align: 4, C: c("uint")},
- "int8": &Type{Size: 1, Align: 1, C: c("schar")},
- "uint8": &Type{Size: 1, Align: 1, C: c("uchar")},
- "int16": &Type{Size: 2, Align: 2, C: c("short")},
- "uint16": &Type{Size: 2, Align: 2, C: c("ushort")},
- "int32": &Type{Size: 4, Align: 4, C: c("int")},
- "uint32": &Type{Size: 4, Align: 4, C: c("uint")},
- "int64": &Type{Size: 8, Align: 8, C: c("int64")},
- "uint64": &Type{Size: 8, Align: 8, C: c("uint64")},
- "float": &Type{Size: 4, Align: 4, C: c("float")},
- "float32": &Type{Size: 4, Align: 4, C: c("float")},
- "float64": &Type{Size: 8, Align: 8, C: c("double")},
- "complex": &Type{Size: 8, Align: 8, C: c("__complex float")},
- "complex64": &Type{Size: 8, Align: 8, C: c("__complex float")},
- "complex128": &Type{Size: 16, Align: 16, C: c("__complex double")},
-}
-
-// Map an ast type to a Type.
-func (p *Package) cgoType(e ast.Expr) *Type {
- switch t := e.(type) {
- case *ast.StarExpr:
- x := p.cgoType(t.X)
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)}
- case *ast.ArrayType:
- if t.Len == nil {
- return &Type{Size: p.PtrSize + 8, Align: p.PtrSize, C: c("GoSlice")}
- }
- case *ast.StructType:
- // TODO
- case *ast.FuncType:
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
- case *ast.InterfaceType:
- return &Type{Size: 3 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
- case *ast.MapType:
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")}
- case *ast.ChanType:
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")}
- case *ast.Ident:
- // Look up the type in the top level declarations.
- // TODO: Handle types defined within a function.
- for _, d := range p.Decl {
- gd, ok := d.(*ast.GenDecl)
- if !ok || gd.Tok != token.TYPE {
- continue
- }
- for _, spec := range gd.Specs {
- ts, ok := spec.(*ast.TypeSpec)
- if !ok {
- continue
- }
- if ts.Name.Name == t.Name {
- return p.cgoType(ts.Type)
- }
- }
- }
- for name, def := range typedef {
- if name == t.Name {
- return p.cgoType(def)
- }
- }
- if t.Name == "uintptr" {
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("uintptr")}
- }
- if t.Name == "string" {
- return &Type{Size: p.PtrSize + 4, Align: p.PtrSize, C: c("GoString")}
- }
- if r, ok := goTypes[t.Name]; ok {
- if r.Align > p.PtrSize {
- r.Align = p.PtrSize
- }
- return r
- }
- case *ast.SelectorExpr:
- id, ok := t.X.(*ast.Ident)
- if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
- }
- }
- error(e.Pos(), "unrecognized Go type %T", e)
- return &Type{Size: 4, Align: 4, C: c("int")}
-}
-
-const gccProlog = `
-// Usual nonsense: if x and y are not equal, the type will be invalid
-// (have a negative array count) and an inscrutable error will come
-// out of the compiler and hopefully mention "name".
-#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
-
-// Check at compile time that the sizes we use match our expectations.
-#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
-
-__cgo_size_assert(char, 1)
-__cgo_size_assert(short, 2)
-__cgo_size_assert(int, 4)
-typedef long long __cgo_long_long;
-__cgo_size_assert(__cgo_long_long, 8)
-__cgo_size_assert(float, 4)
-__cgo_size_assert(double, 8)
-
-#include <errno.h>
-#include <string.h>
-`
-
-const builtinProlog = `
-typedef struct { char *p; int n; } _GoString_;
-_GoString_ GoString(char *p);
-_GoString_ GoStringN(char *p, int l);
-char *CString(_GoString_);
-`
-
-const cProlog = `
-#include "runtime.h"
-#include "cgocall.h"
-
-void ·_Cerrno(void*, int32);
-
-void
-·_Cfunc_GoString(int8 *p, String s)
-{
- s = runtime·gostring((byte*)p);
- FLUSH(&s);
-}
-
-void
-·_Cfunc_GoStringN(int8 *p, int32 l, String s)
-{
- s = runtime·gostringn((byte*)p, l);
- FLUSH(&s);
-}
-
-void
-·_Cfunc_CString(String s, int8 *p)
-{
- p = runtime·cmalloc(s.len+1);
- runtime·mcpy((byte*)p, s.str, s.len);
- p[s.len] = 0;
- FLUSH(&p);
-}
-`
-
-const gccExportHeaderProlog = `
-typedef unsigned int uint;
-typedef signed char schar;
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef long long int64;
-typedef unsigned long long uint64;
-typedef __SIZE_TYPE__ uintptr;
-
-typedef struct { char *p; int n; } GoString;
-typedef void *GoMap;
-typedef void *GoChan;
-typedef struct { void *t; void *v; } GoInterface;
-`
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
deleted file mode 100644
index e79b0e1bf..000000000
--- a/src/cmd/cgo/util.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "exec"
- "fmt"
- "go/token"
- "io/ioutil"
- "os"
-)
-
-// run runs the command argv, feeding in stdin on standard input.
-// It returns the output to standard output and standard error.
-// ok indicates whether the command exited successfully.
-func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
- cmd, err := exec.LookPath(argv[0])
- if err != nil {
- fatalf("exec %s: %s", argv[0], err)
- }
- r0, w0, err := os.Pipe()
- if err != nil {
- fatalf("%s", err)
- }
- r1, w1, err := os.Pipe()
- if err != nil {
- fatalf("%s", err)
- }
- r2, w2, err := os.Pipe()
- if err != nil {
- fatalf("%s", err)
- }
- p, err := os.StartProcess(cmd, argv, &os.ProcAttr{Files: []*os.File{r0, w1, w2}})
- if err != nil {
- fatalf("%s", err)
- }
- defer p.Release()
- r0.Close()
- w1.Close()
- w2.Close()
- c := make(chan bool)
- go func() {
- w0.Write(stdin)
- w0.Close()
- c <- true
- }()
- go func() {
- stdout, _ = ioutil.ReadAll(r1)
- r1.Close()
- c <- true
- }()
- stderr, _ = ioutil.ReadAll(r2)
- r2.Close()
- <-c
- <-c
-
- w, err := p.Wait(0)
- if err != nil {
- fatalf("%s", err)
- }
- ok = w.Exited() && w.ExitStatus() == 0
- return
-}
-
-// Die with an error message.
-func fatalf(msg string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, msg+"\n", args...)
- os.Exit(2)
-}
-
-var nerrors int
-
-func error(pos token.Pos, msg string, args ...interface{}) {
- nerrors++
- if pos.IsValid() {
- fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
- }
- fmt.Fprintf(os.Stderr, msg, args...)
- fmt.Fprintf(os.Stderr, "\n")
-}
-
-// isName returns true if s is a valid C identifier
-func isName(s string) bool {
- for i, v := range s {
- if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') {
- return false
- }
- if i == 0 && '0' <= v && v <= '9' {
- return false
- }
- }
- return s != ""
-}
-
-func creat(name string) *os.File {
- f, err := os.Create(name)
- if err != nil {
- fatalf("%s", err)
- }
- return f
-}
-
-func slashToUnderscore(c int) int {
- if c == '/' || c == '\\' || c == ':' {
- c = '_'
- }
- return c
-}
diff --git a/src/cmd/cov/Makefile b/src/cmd/cov/Makefile
deleted file mode 100644
index 95dba9c60..000000000
--- a/src/cmd/cov/Makefile
+++ /dev/null
@@ -1,39 +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 ../../Make.inc
-O:=$(HOST_O)
-
-# The directory is cov because the source is portable and general.
-# We call the binary 6cov to avoid confusion and because this binary
-# is linked only with amd64 and x86 support.
-
-TARG=6cov
-OFILES=\
- main.$O\
- tree.$O\
-
-HFILES=\
- tree.h\
-
-NOINSTALL=1
-include ../../Make.ccmd
-
-ifeq ($(GOOS),windows)
-NAME=windows
-else
-NAME=$(shell uname | tr A-Z a-z)
-endif
-
-install: install-$(NAME)
-install-linux: install-default
-install-freebsd: install-default
-install-windows: install-default
-
-# on Darwin, have to install and setgid; see $GOROOT/src/sudo.bash
-install-darwin: $(TARG)
- @true
-
-install-default: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
diff --git a/src/cmd/cov/doc.go b/src/cmd/cov/doc.go
deleted file mode 100644
index 5de00e19c..000000000
--- a/src/cmd/cov/doc.go
+++ /dev/null
@@ -1,33 +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.
-
-/*
-
-Cov is a rudimentary code coverage tool.
-
-Given a command to run, it runs the command while tracking which
-sections of code have been executed. When the command finishes,
-cov prints the line numbers of sections of code in the binary that
-were not executed. With no arguments it assumes the command "6.out".
-
-Usage: cov [-lsv] [-g substring] [-m minlines] [6.out args]
-
-The options are:
-
- -l
- print full path names instead of paths relative to the current directory
- -s
- show the source code that didn't execute, in addition to the line numbers.
- -v
- print debugging information during the run.
- -g substring
- restrict the coverage analysis to functions or files whose names contain substring
- -m minlines
- only report uncovered sections of code larger than minlines lines
-
-For reasons of disambiguation it is installed as 6cov although it also serves
-as an 8cov and a 5cov.
-
-*/
-package documentation
diff --git a/src/cmd/cov/main.c b/src/cmd/cov/main.c
deleted file mode 100644
index 5ff22c00a..000000000
--- a/src/cmd/cov/main.c
+++ /dev/null
@@ -1,480 +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.
-
-/*
- * code coverage
- */
-
-#include <u.h>
-#include <time.h>
-#include <libc.h>
-#include <bio.h>
-#include <ctype.h>
-#include "tree.h"
-
-#include <ureg_amd64.h>
-#include <mach.h>
-typedef struct Ureg Ureg;
-
-void
-usage(void)
-{
- fprint(2, "usage: cov [-lsv] [-g substring] [-m minlines] [6.out args...]\n");
- fprint(2, "-g specifies pattern of interesting functions or files\n");
- exits("usage");
-}
-
-typedef struct Range Range;
-struct Range
-{
- uvlong pc;
- uvlong epc;
-};
-
-int chatty;
-int fd;
-int longnames;
-int pid;
-int doshowsrc;
-Map *mem;
-Map *text;
-Fhdr fhdr;
-char *substring;
-char cwd[1000];
-int ncwd;
-int minlines = -1000;
-
-Tree breakpoints; // code ranges not run
-
-/*
- * comparison for Range structures
- * they are "equal" if they overlap, so
- * that a search for [pc, pc+1) finds the
- * Range containing pc.
- */
-int
-rangecmp(void *va, void *vb)
-{
- Range *a = va, *b = vb;
- if(a->epc <= b->pc)
- return 1;
- if(b->epc <= a->pc)
- return -1;
- return 0;
-}
-
-/*
- * remember that we ran the section of code [pc, epc).
- */
-void
-ran(uvlong pc, uvlong epc)
-{
- Range key;
- Range *r;
- uvlong oldepc;
-
- if(chatty)
- print("run %#llux-%#llux\n", pc, epc);
-
- key.pc = pc;
- key.epc = pc+1;
- r = treeget(&breakpoints, &key);
- if(r == nil)
- sysfatal("unchecked breakpoint at %#llux+%d", pc, (int)(epc-pc));
-
- // Might be that the tail of the sequence
- // was run already, so r->epc is before the end.
- // Adjust len.
- if(epc > r->epc)
- epc = r->epc;
-
- if(r->pc == pc) {
- r->pc = epc;
- } else {
- // Chop r to before pc;
- // add new entry for after if needed.
- // Changing r->epc does not affect r's position in the tree.
- oldepc = r->epc;
- r->epc = pc;
- if(epc < oldepc) {
- Range *n;
- n = malloc(sizeof *n);
- n->pc = epc;
- n->epc = oldepc;
- treeput(&breakpoints, n, n);
- }
- }
-}
-
-void
-showsrc(char *file, int line1, int line2)
-{
- Biobuf *b;
- char *p;
- int n, stop;
-
- if((b = Bopen(file, OREAD)) == nil) {
- print("\topen %s: %r\n", file);
- return;
- }
-
- for(n=1; n<line1 && (p = Brdstr(b, '\n', 1)) != nil; n++)
- free(p);
-
- // print up to five lines (this one and 4 more).
- // if there are more than five lines, print 4 and "..."
- stop = n+4;
- if(stop > line2)
- stop = line2;
- if(stop < line2)
- stop--;
- for(; n<=stop && (p = Brdstr(b, '\n', 1)) != nil; n++) {
- print(" %d %s\n", n, p);
- free(p);
- }
- if(n < line2)
- print(" ...\n");
- Bterm(b);
-}
-
-/*
- * if s is in the current directory or below,
- * return the relative path.
- */
-char*
-shortname(char *s)
-{
- if(!longnames && strlen(s) > ncwd && memcmp(s, cwd, ncwd) == 0 && s[ncwd] == '/')
- return s+ncwd+1;
- return s;
-}
-
-/*
- * we've decided that [pc, epc) did not run.
- * do something about it.
- */
-void
-missing(uvlong pc, uvlong epc)
-{
- char file[1000];
- int line1, line2;
- char buf[100];
- Symbol s;
- char *p;
- uvlong uv;
-
- if(!findsym(pc, CTEXT, &s) || !fileline(file, sizeof file, pc)) {
- notfound:
- print("%#llux-%#llux\n", pc, epc);
- return;
- }
- p = strrchr(file, ':');
- *p++ = 0;
- line1 = atoi(p);
- for(uv=pc; uv<epc; ) {
- if(!fileline(file, sizeof file, epc-2))
- goto notfound;
- uv += machdata->instsize(text, uv);
- }
- p = strrchr(file, ':');
- *p++ = 0;
- line2 = atoi(p);
-
- if(line2+1-line2 < minlines)
- return;
-
- if(pc == s.value) {
- // never entered function
- print("%s:%d %s never called (%#llux-%#llux)\n", shortname(file), line1, s.name, pc, epc);
- return;
- }
- if(pc <= s.value+13) {
- // probably stub for stack growth.
- // check whether last instruction is call to morestack.
- // the -5 below is the length of
- // CALL sys.morestack.
- buf[0] = 0;
- machdata->das(text, epc-5, 0, buf, sizeof buf);
- if(strstr(buf, "morestack"))
- return;
- }
-
- if(epc - pc == 5) {
- // check for CALL sys.panicindex
- buf[0] = 0;
- machdata->das(text, pc, 0, buf, sizeof buf);
- if(strstr(buf, "panicindex"))
- return;
- }
-
- if(epc - pc == 2 || epc -pc == 3) {
- // check for XORL inside shift.
- // (on x86 have to implement large left or unsigned right shift with explicit zeroing).
- // f+90 0x00002c9f CMPL CX,$20
- // f+93 0x00002ca2 JCS f+97(SB)
- // f+95 0x00002ca4 XORL AX,AX <<<
- // f+97 0x00002ca6 SHLL CL,AX
- // f+99 0x00002ca8 MOVL $1,CX
- //
- // f+c8 0x00002cd7 CMPL CX,$40
- // f+cb 0x00002cda JCS f+d0(SB)
- // f+cd 0x00002cdc XORQ AX,AX <<<
- // f+d0 0x00002cdf SHLQ CL,AX
- // f+d3 0x00002ce2 MOVQ $1,CX
- buf[0] = 0;
- machdata->das(text, pc, 0, buf, sizeof buf);
- if(strncmp(buf, "XOR", 3) == 0) {
- machdata->das(text, epc, 0, buf, sizeof buf);
- if(strncmp(buf, "SHL", 3) == 0 || strncmp(buf, "SHR", 3) == 0)
- return;
- }
- }
-
- if(epc - pc == 3) {
- // check for SAR inside shift.
- // (on x86 have to implement large signed right shift as >>31).
- // f+36 0x00016216 CMPL CX,$20
- // f+39 0x00016219 JCS f+3e(SB)
- // f+3b 0x0001621b SARL $1f,AX <<<
- // f+3e 0x0001621e SARL CL,AX
- // f+40 0x00016220 XORL CX,CX
- // f+42 0x00016222 CMPL CX,AX
- buf[0] = 0;
- machdata->das(text, pc, 0, buf, sizeof buf);
- if(strncmp(buf, "SAR", 3) == 0) {
- machdata->das(text, epc, 0, buf, sizeof buf);
- if(strncmp(buf, "SAR", 3) == 0)
- return;
- }
- }
-
- // show first instruction to make clear where we were.
- machdata->das(text, pc, 0, buf, sizeof buf);
-
- if(line1 != line2)
- print("%s:%d,%d %#llux-%#llux %s\n",
- shortname(file), line1, line2, pc, epc, buf);
- else
- print("%s:%d %#llux-%#llux %s\n",
- shortname(file), line1, pc, epc, buf);
- if(doshowsrc)
- showsrc(file, line1, line2);
-}
-
-/*
- * walk the tree, calling missing for each non-empty
- * section of missing code.
- */
-void
-walktree(TreeNode *t)
-{
- Range *n;
-
- if(t == nil)
- return;
- walktree(t->left);
- n = t->key;
- if(n->pc < n->epc)
- missing(n->pc, n->epc);
- walktree(t->right);
-}
-
-/*
- * set a breakpoint all over [pc, epc)
- * and remember that we did.
- */
-void
-breakpoint(uvlong pc, uvlong epc)
-{
- Range *r;
-
- r = malloc(sizeof *r);
- r->pc = pc;
- r->epc = epc;
- treeput(&breakpoints, r, r);
-
- for(; pc < epc; pc+=machdata->bpsize)
- put1(mem, pc, machdata->bpinst, machdata->bpsize);
-}
-
-/*
- * install breakpoints over all text symbols
- * that match the pattern.
- */
-void
-cover(void)
-{
- Symbol s;
- char *lastfn;
- uvlong lastpc;
- int i;
- char buf[200];
-
- lastfn = nil;
- lastpc = 0;
- for(i=0; textsym(&s, i); i++) {
- switch(s.type) {
- case 'T':
- case 't':
- if(lastpc != 0) {
- breakpoint(lastpc, s.value);
- lastpc = 0;
- }
- // Ignore second entry for a given name;
- // that's the debugging blob.
- if(lastfn && strcmp(s.name, lastfn) == 0)
- break;
- lastfn = s.name;
- buf[0] = 0;
- fileline(buf, sizeof buf, s.value);
- if(substring == nil || strstr(buf, substring) || strstr(s.name, substring))
- lastpc = s.value;
- }
- }
-}
-
-uvlong
-rgetzero(Map *map, char *reg)
-{
- return 0;
-}
-
-/*
- * remove the breakpoints at pc and successive instructions,
- * up to and including the first jump or other control flow transfer.
- */
-void
-uncover(uvlong pc)
-{
- uchar buf[1000];
- int n, n1, n2;
- uvlong foll[2];
-
- // Double-check that we stopped at a breakpoint.
- if(get1(mem, pc, buf, machdata->bpsize) < 0)
- sysfatal("read mem inst at %#llux: %r", pc);
- if(memcmp(buf, machdata->bpinst, machdata->bpsize) != 0)
- sysfatal("stopped at %#llux; not at breakpoint %d", pc, machdata->bpsize);
-
- // Figure out how many bytes of straight-line code
- // there are in the text starting at pc.
- n = 0;
- while(n < sizeof buf) {
- n1 = machdata->instsize(text, pc+n);
- if(n+n1 > sizeof buf)
- break;
- n2 = machdata->foll(text, pc+n, rgetzero, foll);
- n += n1;
- if(n2 != 1 || foll[0] != pc+n)
- break;
- }
-
- // Record that this section of code ran.
- ran(pc, pc+n);
-
- // Put original instructions back.
- if(get1(text, pc, buf, n) < 0)
- sysfatal("get1: %r");
- if(put1(mem, pc, buf, n) < 0)
- sysfatal("put1: %r");
-}
-
-int
-startprocess(char **argv)
-{
- int pid;
-
- if((pid = fork()) < 0)
- sysfatal("fork: %r");
- if(pid == 0) {
- pid = getpid();
- if(ctlproc(pid, "hang") < 0)
- sysfatal("ctlproc hang: %r");
- execv(argv[0], argv);
- sysfatal("exec %s: %r", argv[0]);
- }
- if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0)
- sysfatal("attach %d %s: %r", pid, argv[0]);
- return pid;
-}
-
-int
-go(void)
-{
- uvlong pc;
- char buf[100];
- int n;
-
- for(n = 0;; n++) {
- ctlproc(pid, "startstop");
- if(get8(mem, offsetof(Ureg, ip), &pc) < 0) {
- rerrstr(buf, sizeof buf);
- if(strstr(buf, "exited") || strstr(buf, "No such process"))
- return n;
- sysfatal("cannot read pc: %r");
- }
- pc--;
- if(put8(mem, offsetof(Ureg, ip), pc) < 0)
- sysfatal("cannot write pc: %r");
- uncover(pc);
- }
-}
-
-void
-main(int argc, char **argv)
-{
- int n;
-
- ARGBEGIN{
- case 'g':
- substring = EARGF(usage());
- break;
- case 'l':
- longnames++;
- break;
- case 'n':
- minlines = atoi(EARGF(usage()));
- break;
- case 's':
- doshowsrc = 1;
- break;
- case 'v':
- chatty++;
- break;
- default:
- usage();
- }ARGEND
-
- getwd(cwd, sizeof cwd);
- ncwd = strlen(cwd);
-
- if(argc == 0) {
- *--argv = "6.out";
- argc++;
- }
- fd = open(argv[0], OREAD);
- if(fd < 0)
- sysfatal("open %s: %r", argv[0]);
- if(crackhdr(fd, &fhdr) <= 0)
- sysfatal("crackhdr: %r");
- machbytype(fhdr.type);
- if(syminit(fd, &fhdr) <= 0)
- sysfatal("syminit: %r");
- text = loadmap(nil, fd, &fhdr);
- if(text == nil)
- sysfatal("loadmap: %r");
- pid = startprocess(argv);
- mem = attachproc(pid, &fhdr);
- if(mem == nil)
- sysfatal("attachproc: %r");
- breakpoints.cmp = rangecmp;
- cover();
- n = go();
- walktree(breakpoints.root);
- if(chatty)
- print("%d breakpoints\n", n);
- detachproc(mem);
- exits(0);
-}
-
diff --git a/src/cmd/cov/tree.c b/src/cmd/cov/tree.c
deleted file mode 100644
index 116772e42..000000000
--- a/src/cmd/cov/tree.c
+++ /dev/null
@@ -1,246 +0,0 @@
-// Renamed from Map to Tree to avoid conflict with libmach.
-
-/*
-Copyright (c) 2003-2007 Russ Cox, Tom Bergan, Austin Clements,
- Massachusetts Institute of Technology
-Portions Copyright (c) 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.
-*/
-
-// Mutable map structure, but still based on
-// Okasaki, Red Black Trees in a Functional Setting, JFP 1999,
-// which is a lot easier than the traditional red-black
-// and plenty fast enough for me. (Also I could copy
-// and edit fmap.c.)
-
-#include <u.h>
-#include <libc.h>
-#include "tree.h"
-
-#define TreeNode TreeNode
-#define Tree Tree
-
-enum
-{
- Red = 0,
- Black = 1
-};
-
-
-// Red-black trees are binary trees with this property:
-// 1. No red node has a red parent.
-// 2. Every path from the root to a leaf contains the
-// same number of black nodes.
-
-static TreeNode*
-rwTreeNode(TreeNode *p, int color, TreeNode *left, void *key, void *value, TreeNode *right)
-{
- if(p == nil)
- p = malloc(sizeof *p);
- p->color = color;
- p->left = left;
- p->key = key;
- p->value = value;
- p->right = right;
- return p;
-}
-
-static TreeNode*
-balance(TreeNode *m0)
-{
- void *xk, *xv, *yk, *yv, *zk, *zv;
- TreeNode *a, *b, *c, *d;
- TreeNode *m1, *m2;
- int color;
- TreeNode *left, *right;
- void *key, *value;
-
- color = m0->color;
- left = m0->left;
- key = m0->key;
- value = m0->value;
- right = m0->right;
-
- // Okasaki notation: (T is mkTreeNode, B is Black, R is Red, x, y, z are key-value.
- //
- // balance B (T R (T R a x b) y c) z d
- // balance B (T R a x (T R b y c)) z d
- // balance B a x (T R (T R b y c) z d)
- // balance B a x (T R b y (T R c z d))
- //
- // = T R (T B a x b) y (T B c z d)
-
- if(color == Black){
- if(left && left->color == Red){
- if(left->left && left->left->color == Red){
- a = left->left->left;
- xk = left->left->key;
- xv = left->left->value;
- b = left->left->right;
- yk = left->key;
- yv = left->value;
- c = left->right;
- zk = key;
- zv = value;
- d = right;
- m1 = left;
- m2 = left->left;
- goto hard;
- }else if(left->right && left->right->color == Red){
- a = left->left;
- xk = left->key;
- xv = left->value;
- b = left->right->left;
- yk = left->right->key;
- yv = left->right->value;
- c = left->right->right;
- zk = key;
- zv = value;
- d = right;
- m1 = left;
- m2 = left->right;
- goto hard;
- }
- }else if(right && right->color == Red){
- if(right->left && right->left->color == Red){
- a = left;
- xk = key;
- xv = value;
- b = right->left->left;
- yk = right->left->key;
- yv = right->left->value;
- c = right->left->right;
- zk = right->key;
- zv = right->value;
- d = right->right;
- m1 = right;
- m2 = right->left;
- goto hard;
- }else if(right->right && right->right->color == Red){
- a = left;
- xk = key;
- xv = value;
- b = right->left;
- yk = right->key;
- yv = right->value;
- c = right->right->left;
- zk = right->right->key;
- zv = right->right->value;
- d = right->right->right;
- m1 = right;
- m2 = right->right;
- goto hard;
- }
- }
- }
- return rwTreeNode(m0, color, left, key, value, right);
-
-hard:
- return rwTreeNode(m0, Red, rwTreeNode(m1, Black, a, xk, xv, b),
- yk, yv, rwTreeNode(m2, Black, c, zk, zv, d));
-}
-
-static TreeNode*
-ins0(TreeNode *p, void *k, void *v, TreeNode *rw)
-{
- if(p == nil)
- return rwTreeNode(rw, Red, nil, k, v, nil);
- if(p->key == k){
- if(rw)
- return rwTreeNode(rw, p->color, p->left, k, v, p->right);
- p->value = v;
- return p;
- }
- if(p->key < k)
- p->left = ins0(p->left, k, v, rw);
- else
- p->right = ins0(p->right, k, v, rw);
- return balance(p);
-}
-
-static TreeNode*
-ins1(Tree *m, TreeNode *p, void *k, void *v, TreeNode *rw)
-{
- int i;
-
- if(p == nil)
- return rwTreeNode(rw, Red, nil, k, v, nil);
- i = m->cmp(p->key, k);
- if(i == 0){
- if(rw)
- return rwTreeNode(rw, p->color, p->left, k, v, p->right);
- p->value = v;
- return p;
- }
- if(i < 0)
- p->left = ins1(m, p->left, k, v, rw);
- else
- p->right = ins1(m, p->right, k, v, rw);
- return balance(p);
-}
-
-void
-treeputelem(Tree *m, void *key, void *val, TreeNode *rw)
-{
- if(m->cmp)
- m->root = ins1(m, m->root, key, val, rw);
- else
- m->root = ins0(m->root, key, val, rw);
-}
-
-void
-treeput(Tree *m, void *key, void *val)
-{
- treeputelem(m, key, val, nil);
-}
-
-void*
-treeget(Tree *m, void *key)
-{
- int i;
- TreeNode *p;
-
- p = m->root;
- if(m->cmp){
- for(;;){
- if(p == nil)
- return nil;
- i = m->cmp(p->key, key);
- if(i < 0)
- p = p->left;
- else if(i > 0)
- p = p->right;
- else
- return p->value;
- }
- }else{
- for(;;){
- if(p == nil)
- return nil;
- if(p->key == key)
- return p->value;
- if(p->key < key)
- p = p->left;
- else
- p = p->right;
- }
- }
-}
diff --git a/src/cmd/cov/tree.h b/src/cmd/cov/tree.h
deleted file mode 100644
index a716d83ad..000000000
--- a/src/cmd/cov/tree.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Renamed from Map to Tree to avoid conflict with libmach.
-
-/*
-Copyright (c) 2003-2007 Russ Cox, Tom Bergan, Austin Clements,
- Massachusetts Institute of Technology
-Portions Copyright (c) 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.
-*/
-
-typedef struct Tree Tree;
-typedef struct TreeNode TreeNode;
-struct Tree
-{
- int (*cmp)(void*, void*);
- TreeNode *root;
-};
-
-struct TreeNode
-{
- int color;
- TreeNode *left;
- void *key;
- void *value;
- TreeNode *right;
-};
-
-void *treeget(Tree*, void*);
-void treeput(Tree*, void*, void*);
-void treeputelem(Tree*, void*, void*, TreeNode*);
diff --git a/src/cmd/ebnflint/Makefile b/src/cmd/ebnflint/Makefile
deleted file mode 100644
index 8f030aaef..000000000
--- a/src/cmd/ebnflint/Makefile
+++ /dev/null
@@ -1,15 +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 ../../Make.inc
-
-TARG=ebnflint
-GOFILES=\
- ebnflint.go\
-
-include ../../Make.cmd
-
-test: $(TARG)
- $(TARG) -start="SourceFile" "$(GOROOT)"/doc/go_spec.html
-
diff --git a/src/cmd/ebnflint/doc.go b/src/cmd/ebnflint/doc.go
deleted file mode 100644
index f35976eea..000000000
--- a/src/cmd/ebnflint/doc.go
+++ /dev/null
@@ -1,22 +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.
-
-/*
-
-Ebnflint verifies that EBNF productions are consistent and gramatically correct.
-It reads them from an HTML document such as the Go specification.
-
-Grammar productions are grouped in boxes demarcated by the HTML elements
- <pre class="ebnf">
- </pre>
-
-
-Usage:
- ebnflint [--start production] [file]
-
-The --start flag specifies the name of the start production for
-the grammar; it defaults to "Start".
-
-*/
-package documentation
diff --git a/src/cmd/ebnflint/ebnflint.go b/src/cmd/ebnflint/ebnflint.go
deleted file mode 100644
index 0b0443156..000000000
--- a/src/cmd/ebnflint/ebnflint.go
+++ /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.
-
-package main
-
-import (
- "bytes"
- "ebnf"
- "flag"
- "fmt"
- "go/scanner"
- "go/token"
- "io/ioutil"
- "os"
- "path/filepath"
-)
-
-
-var fset = token.NewFileSet()
-var start = flag.String("start", "Start", "name of start production")
-
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: ebnflint [flags] [filename]\n")
- flag.PrintDefaults()
- os.Exit(1)
-}
-
-
-// Markers around EBNF sections in .html files
-var (
- open = []byte(`<pre class="ebnf">`)
- close = []byte(`</pre>`)
-)
-
-
-func report(err os.Error) {
- scanner.PrintError(os.Stderr, err)
- os.Exit(1)
-}
-
-
-func extractEBNF(src []byte) []byte {
- var buf bytes.Buffer
-
- for {
- // i = beginning of EBNF text
- i := bytes.Index(src, open)
- if i < 0 {
- break // no EBNF found - we are done
- }
- i += len(open)
-
- // write as many newlines as found in the excluded text
- // to maintain correct line numbers in error messages
- for _, ch := range src[0:i] {
- if ch == '\n' {
- buf.WriteByte('\n')
- }
- }
-
- // j = end of EBNF text (or end of source)
- j := bytes.Index(src[i:], close) // close marker
- if j < 0 {
- j = len(src) - i
- }
- j += i
-
- // copy EBNF text
- buf.Write(src[i:j])
-
- // advance
- src = src[j:]
- }
-
- return buf.Bytes()
-}
-
-
-func main() {
- flag.Parse()
-
- var (
- filename string
- src []byte
- err os.Error
- )
- switch flag.NArg() {
- case 0:
- filename = "<stdin>"
- src, err = ioutil.ReadAll(os.Stdin)
- case 1:
- filename = flag.Arg(0)
- src, err = ioutil.ReadFile(filename)
- default:
- usage()
- }
- if err != nil {
- report(err)
- }
-
- if filepath.Ext(filename) == ".html" || bytes.Index(src, open) >= 0 {
- src = extractEBNF(src)
- }
-
- grammar, err := ebnf.Parse(fset, filename, src)
- if err != nil {
- report(err)
- }
-
- if err = ebnf.Verify(fset, grammar, *start); err != nil {
- report(err)
- }
-}
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
deleted file mode 100644
index 286618ec1..000000000
--- a/src/cmd/gc/Makefile
+++ /dev/null
@@ -1,67 +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 ../../Make.inc
-O:=$(HOST_O)
-
-LIB=gc.a
-
-HFILES=\
- go.h\
- y.tab.h\
- md5.h\
-
-YFILES=\
- go.y\
-
-OFILES=\
- align.$O\
- bits.$O\
- builtin.$O\
- closure.$O\
- const.$O\
- dcl.$O\
- export.$O\
- gen.$O\
- init.$O\
- lex.$O\
- md5.$O\
- mparith1.$O\
- mparith2.$O\
- mparith3.$O\
- obj.$O\
- print.$O\
- range.$O\
- reflect.$O\
- select.$O\
- sinit.$O\
- subr.$O\
- swt.$O\
- typecheck.$O\
- unsafe.$O\
- walk.$O\
- y1.tab.$O\
-
-NOINSTALL=1
-include ../../Make.clib
-
-install: $(LIB)
-
-y1.tab.c: y.tab.c # make yystate global, yytname mutable
- cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c
-
-yerr.h: bisonerrors go.errors y.tab.h # y.tab.h rule generates y.output too
- awk -f bisonerrors y.output go.errors >yerr.h
-
-subr.$O: yerr.h
-
-builtin.c: builtin.c.boot
- cp builtin.c.boot builtin.c
-
-subr.$O: opnames.h
-
-opnames.h: mkopnames go.h
- ./mkopnames go.h >opnames.h
-
-CLEANFILES+=*.[568] [568].out y1.tab.c yerr.h mkbuiltin1 builtin.c _builtin.c opnames.h
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
deleted file mode 100644
index 7fcac4833..000000000
--- a/src/cmd/gc/align.c
+++ /dev/null
@@ -1,659 +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 "go.h"
-
-/*
- * machine size and rounding
- * alignment is dictated around
- * the size of a pointer, set in betypeinit
- * (see ../6g/galign.c).
- */
-
-static int defercalc;
-
-uint32
-rnd(uint32 o, uint32 r)
-{
- if(r < 1 || r > 8 || (r&(r-1)) != 0)
- fatal("rnd");
- return (o+r-1)&~(r-1);
-}
-
-static void
-offmod(Type *t)
-{
- Type *f;
- int32 o;
-
- o = 0;
- for(f=t->type; f!=T; f=f->down) {
- if(f->etype != TFIELD)
- fatal("widstruct: not TFIELD: %lT", f);
- f->width = o;
- o += widthptr;
- }
-}
-
-static uint32
-widstruct(Type *t, uint32 o, int flag)
-{
- Type *f;
- int32 w, maxalign;
-
- maxalign = flag;
- if(maxalign < 1)
- maxalign = 1;
- for(f=t->type; f!=T; f=f->down) {
- if(f->etype != TFIELD)
- fatal("widstruct: not TFIELD: %lT", f);
- dowidth(f->type);
- if(f->type->align > maxalign)
- maxalign = f->type->align;
- if(f->type->width < 0)
- fatal("invalid width %lld", f->type->width);
- w = f->type->width;
- if(f->type->align > 0)
- o = rnd(o, f->type->align);
- f->width = o; // really offset for TFIELD
- if(f->nname != N) {
- // this same stackparam logic is in addrescapes
- // in typecheck.c. usually addrescapes runs after
- // widstruct, in which case we could drop this,
- // but function closure functions are the exception.
- if(f->nname->stackparam) {
- f->nname->stackparam->xoffset = o;
- f->nname->xoffset = 0;
- } else
- f->nname->xoffset = o;
- }
- o += w;
- }
- // final width is rounded
- if(flag)
- o = rnd(o, maxalign);
- t->align = maxalign;
-
- // type width only includes back to first field's offset
- if(t->type == T)
- t->width = 0;
- else
- t->width = o - t->type->width;
- return o;
-}
-
-void
-dowidth(Type *t)
-{
- int32 et;
- int64 w;
- int lno;
- Type *t1;
-
- if(widthptr == 0)
- fatal("dowidth without betypeinit");
-
- if(t == T)
- return;
-
- if(t->width > 0)
- return;
-
- if(t->width == -2) {
- lno = lineno;
- lineno = t->lineno;
- yyerror("invalid recursive type %T", t);
- t->width = 0;
- lineno = lno;
- return;
- }
-
- // defer checkwidth calls until after we're done
- defercalc++;
-
- lno = lineno;
- lineno = t->lineno;
- t->width = -2;
- t->align = 0;
-
- et = t->etype;
- switch(et) {
- case TFUNC:
- case TCHAN:
- case TMAP:
- case TSTRING:
- break;
-
- default:
- /* simtype == 0 during bootstrap */
- if(simtype[t->etype] != 0)
- et = simtype[t->etype];
- break;
- }
-
- w = 0;
- switch(et) {
- default:
- fatal("dowidth: unknown type: %T", t);
- break;
-
- /* compiler-specific stuff */
- case TINT8:
- case TUINT8:
- case TBOOL: // bool is int8
- w = 1;
- break;
- case TINT16:
- case TUINT16:
- w = 2;
- break;
- case TINT32:
- case TUINT32:
- case TFLOAT32:
- w = 4;
- break;
- case TINT64:
- case TUINT64:
- case TFLOAT64:
- case TCOMPLEX64:
- w = 8;
- t->align = widthptr;
- break;
- case TCOMPLEX128:
- w = 16;
- t->align = widthptr;
- break;
- case TPTR32:
- w = 4;
- checkwidth(t->type);
- break;
- case TPTR64:
- w = 8;
- checkwidth(t->type);
- break;
- case TUNSAFEPTR:
- w = widthptr;
- break;
- case TINTER: // implemented as 2 pointers
- w = 2*widthptr;
- t->align = widthptr;
- offmod(t);
- break;
- case TCHAN: // implemented as pointer
- w = widthptr;
- checkwidth(t->type);
-
- // make fake type to check later to
- // trigger channel argument check.
- t1 = typ(TCHANARGS);
- t1->type = t;
- checkwidth(t1);
- break;
- case TCHANARGS:
- t1 = t->type;
- dowidth(t->type); // just in case
- if(t1->type->width >= (1<<16))
- yyerror("channel element type too large (>64kB)");
- t->width = 1;
- break;
- case TMAP: // implemented as pointer
- w = widthptr;
- checkwidth(t->type);
- checkwidth(t->down);
- break;
- case TFORW: // should have been filled in
- yyerror("invalid recursive type %T", t);
- w = 1; // anything will do
- break;
- case TANY:
- // dummy type; should be replaced before use.
- if(!debug['A'])
- fatal("dowidth any");
- w = 1; // anything will do
- break;
- case TSTRING:
- if(sizeof_String == 0)
- fatal("early dowidth string");
- w = sizeof_String;
- t->align = widthptr;
- break;
- case TARRAY:
- if(t->type == T)
- break;
- if(t->bound >= 0) {
- uint64 cap;
-
- dowidth(t->type);
- if(t->type->width == 0)
- fatal("no width for type %T", t->type);
- if(tptr == TPTR32)
- cap = ((uint32)-1) / t->type->width;
- else
- cap = ((uint64)-1) / t->type->width;
- if(t->bound > cap)
- yyerror("type %lT larger than address space", t);
- w = t->bound * t->type->width;
- t->align = t->type->align;
- if(w == 0) {
- w = 1;
- t->align = 1;
- }
- }
- else if(t->bound == -1) {
- w = sizeof_Array;
- checkwidth(t->type);
- t->align = widthptr;
- }
- else if(t->bound == -100)
- yyerror("use of [...] array outside of array literal");
- else
- fatal("dowidth %T", t); // probably [...]T
- break;
-
- case TSTRUCT:
- if(t->funarg)
- fatal("dowidth fn struct %T", t);
- w = widstruct(t, 0, 1);
- if(w == 0) {
- w = 1;
- t->align = 1;
- }
- break;
-
- case TFUNC:
- // make fake type to check later to
- // trigger function argument computation.
- t1 = typ(TFUNCARGS);
- t1->type = t;
- checkwidth(t1);
-
- // width of func type is pointer
- w = widthptr;
- break;
-
- case TFUNCARGS:
- // function is 3 cated structures;
- // compute their widths as side-effect.
- t1 = t->type;
- w = widstruct(*getthis(t1), 0, 0);
- w = widstruct(*getinarg(t1), w, widthptr);
- w = widstruct(*getoutarg(t1), w, widthptr);
- t1->argwid = w;
- if(w%widthptr)
- warn("bad type %T %d\n", t1, w);
- t->align = 1;
- break;
- }
-
- // catch all for error cases; avoid divide by zero later
- if(w == 0)
- w = 1;
- t->width = w;
- if(t->align == 0) {
- if(w > 8 || (w&(w-1)) != 0)
- fatal("invalid alignment for %T", t);
- t->align = w;
- }
- lineno = lno;
-
- if(defercalc == 1)
- resumecheckwidth();
- else
- --defercalc;
-}
-
-/*
- * when a type's width should be known, we call checkwidth
- * to compute it. during a declaration like
- *
- * type T *struct { next T }
- *
- * it is necessary to defer the calculation of the struct width
- * until after T has been initialized to be a pointer to that struct.
- * similarly, during import processing structs may be used
- * before their definition. in those situations, calling
- * defercheckwidth() stops width calculations until
- * resumecheckwidth() is called, at which point all the
- * checkwidths that were deferred are executed.
- * dowidth should only be called when the type's size
- * is needed immediately. checkwidth makes sure the
- * size is evaluated eventually.
- */
-typedef struct TypeList TypeList;
-struct TypeList {
- Type *t;
- TypeList *next;
-};
-
-static TypeList *tlfree;
-static TypeList *tlq;
-
-void
-checkwidth(Type *t)
-{
- TypeList *l;
-
- if(t == T)
- return;
-
- // function arg structs should not be checked
- // outside of the enclosing function.
- if(t->funarg)
- fatal("checkwidth %T", t);
-
- if(!defercalc) {
- dowidth(t);
- return;
- }
- if(t->deferwidth)
- return;
- t->deferwidth = 1;
-
- l = tlfree;
- if(l != nil)
- tlfree = l->next;
- else
- l = mal(sizeof *l);
-
- l->t = t;
- l->next = tlq;
- tlq = l;
-}
-
-void
-defercheckwidth(void)
-{
- // we get out of sync on syntax errors, so don't be pedantic.
- if(defercalc && nerrors == 0)
- fatal("defercheckwidth");
- defercalc = 1;
-}
-
-void
-resumecheckwidth(void)
-{
- TypeList *l;
-
- if(!defercalc)
- fatal("resumecheckwidth");
- for(l = tlq; l != nil; l = tlq) {
- l->t->deferwidth = 0;
- tlq = l->next;
- dowidth(l->t);
- l->next = tlfree;
- tlfree = l;
- }
- defercalc = 0;
-}
-
-void
-typeinit(void)
-{
- int i, etype, sameas;
- Type *t;
- Sym *s, *s1;
-
- if(widthptr == 0)
- fatal("typeinit before betypeinit");
-
- for(i=0; i<NTYPE; i++)
- simtype[i] = i;
-
- types[TPTR32] = typ(TPTR32);
- dowidth(types[TPTR32]);
-
- types[TPTR64] = typ(TPTR64);
- dowidth(types[TPTR64]);
-
- t = typ(TUNSAFEPTR);
- types[TUNSAFEPTR] = t;
- t->sym = pkglookup("Pointer", unsafepkg);
- t->sym->def = typenod(t);
-
- dowidth(types[TUNSAFEPTR]);
-
- tptr = TPTR32;
- if(widthptr == 8)
- tptr = TPTR64;
-
- for(i=TINT8; i<=TUINT64; i++)
- isint[i] = 1;
- isint[TINT] = 1;
- isint[TUINT] = 1;
- isint[TUINTPTR] = 1;
-
- isfloat[TFLOAT32] = 1;
- isfloat[TFLOAT64] = 1;
-
- iscomplex[TCOMPLEX64] = 1;
- iscomplex[TCOMPLEX128] = 1;
-
- isptr[TPTR32] = 1;
- isptr[TPTR64] = 1;
-
- isforw[TFORW] = 1;
-
- issigned[TINT] = 1;
- issigned[TINT8] = 1;
- issigned[TINT16] = 1;
- issigned[TINT32] = 1;
- issigned[TINT64] = 1;
-
- /*
- * initialize okfor
- */
- for(i=0; i<NTYPE; i++) {
- if(isint[i] || i == TIDEAL) {
- okforeq[i] = 1;
- okforcmp[i] = 1;
- okforarith[i] = 1;
- okforadd[i] = 1;
- okforand[i] = 1;
- okforconst[i] = 1;
- issimple[i] = 1;
- minintval[i] = mal(sizeof(*minintval[i]));
- maxintval[i] = mal(sizeof(*maxintval[i]));
- }
- if(isfloat[i]) {
- okforeq[i] = 1;
- okforcmp[i] = 1;
- okforadd[i] = 1;
- okforarith[i] = 1;
- okforconst[i] = 1;
- issimple[i] = 1;
- minfltval[i] = mal(sizeof(*minfltval[i]));
- maxfltval[i] = mal(sizeof(*maxfltval[i]));
- }
- if(iscomplex[i]) {
- okforeq[i] = 1;
- okforadd[i] = 1;
- okforarith[i] = 1;
- okforconst[i] = 1;
- issimple[i] = 1;
- }
- }
-
- issimple[TBOOL] = 1;
-
- okforadd[TSTRING] = 1;
-
- okforbool[TBOOL] = 1;
-
- okforcap[TARRAY] = 1;
- okforcap[TCHAN] = 1;
-
- okforconst[TBOOL] = 1;
- okforconst[TSTRING] = 1;
-
- okforlen[TARRAY] = 1;
- okforlen[TCHAN] = 1;
- okforlen[TMAP] = 1;
- okforlen[TSTRING] = 1;
-
- okforeq[TPTR32] = 1;
- okforeq[TPTR64] = 1;
- okforeq[TUNSAFEPTR] = 1;
- okforeq[TINTER] = 1;
- okforeq[TMAP] = 1;
- okforeq[TCHAN] = 1;
- okforeq[TFUNC] = 1;
- okforeq[TSTRING] = 1;
- okforeq[TBOOL] = 1;
- okforeq[TARRAY] = 1; // refined in typecheck
-
- okforcmp[TSTRING] = 1;
-
- for(i=0; i<nelem(okfor); i++)
- okfor[i] = okfornone;
-
- // binary
- okfor[OADD] = okforadd;
- okfor[OAND] = okforand;
- okfor[OANDAND] = okforbool;
- okfor[OANDNOT] = okforand;
- okfor[ODIV] = okforarith;
- okfor[OEQ] = okforeq;
- okfor[OGE] = okforcmp;
- okfor[OGT] = okforcmp;
- okfor[OLE] = okforcmp;
- okfor[OLT] = okforcmp;
- okfor[OMOD] = okforand;
- okfor[OMUL] = okforarith;
- okfor[ONE] = okforeq;
- okfor[OOR] = okforand;
- okfor[OOROR] = okforbool;
- okfor[OSUB] = okforarith;
- okfor[OXOR] = okforand;
- okfor[OLSH] = okforand;
- okfor[ORSH] = okforand;
-
- // unary
- okfor[OCOM] = okforand;
- okfor[OMINUS] = okforarith;
- okfor[ONOT] = okforbool;
- okfor[OPLUS] = okforarith;
-
- // special
- okfor[OCAP] = okforcap;
- okfor[OLEN] = okforlen;
-
- // comparison
- iscmp[OLT] = 1;
- iscmp[OGT] = 1;
- iscmp[OGE] = 1;
- iscmp[OLE] = 1;
- iscmp[OEQ] = 1;
- iscmp[ONE] = 1;
-
- mpatofix(maxintval[TINT8], "0x7f");
- mpatofix(minintval[TINT8], "-0x80");
- mpatofix(maxintval[TINT16], "0x7fff");
- mpatofix(minintval[TINT16], "-0x8000");
- mpatofix(maxintval[TINT32], "0x7fffffff");
- mpatofix(minintval[TINT32], "-0x80000000");
- mpatofix(maxintval[TINT64], "0x7fffffffffffffff");
- mpatofix(minintval[TINT64], "-0x8000000000000000");
-
- mpatofix(maxintval[TUINT8], "0xff");
- mpatofix(maxintval[TUINT16], "0xffff");
- mpatofix(maxintval[TUINT32], "0xffffffff");
- mpatofix(maxintval[TUINT64], "0xffffffffffffffff");
-
- /* f is valid float if min < f < max. (min and max are not themselves valid.) */
- mpatoflt(maxfltval[TFLOAT32], "33554431p103"); /* 2^24-1 p (127-23) + 1/2 ulp*/
- mpatoflt(minfltval[TFLOAT32], "-33554431p103");
- mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970"); /* 2^53-1 p (1023-52) + 1/2 ulp */
- mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970");
-
- maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32];
- minfltval[TCOMPLEX64] = minfltval[TFLOAT32];
- maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64];
- minfltval[TCOMPLEX128] = minfltval[TFLOAT64];
-
- /* for walk to use in error messages */
- types[TFUNC] = functype(N, nil, nil);
-
- /* types used in front end */
- // types[TNIL] got set early in lexinit
- types[TIDEAL] = typ(TIDEAL);
- types[TINTER] = typ(TINTER);
-
- /* simple aliases */
- simtype[TMAP] = tptr;
- simtype[TCHAN] = tptr;
- simtype[TFUNC] = tptr;
- simtype[TUNSAFEPTR] = tptr;
-
- /* pick up the backend typedefs */
- for(i=0; typedefs[i].name; i++) {
- s = lookup(typedefs[i].name);
- s1 = pkglookup(typedefs[i].name, builtinpkg);
-
- etype = typedefs[i].etype;
- if(etype < 0 || etype >= nelem(types))
- fatal("typeinit: %s bad etype", s->name);
- sameas = typedefs[i].sameas;
- if(sameas < 0 || sameas >= nelem(types))
- fatal("typeinit: %s bad sameas", s->name);
- simtype[etype] = sameas;
- minfltval[etype] = minfltval[sameas];
- maxfltval[etype] = maxfltval[sameas];
- minintval[etype] = minintval[sameas];
- maxintval[etype] = maxintval[sameas];
-
- t = types[etype];
- if(t != T)
- fatal("typeinit: %s already defined", s->name);
-
- t = typ(etype);
- t->sym = s;
-
- dowidth(t);
- types[etype] = t;
- s1->def = typenod(t);
- }
-
- Array_array = rnd(0, widthptr);
- Array_nel = rnd(Array_array+widthptr, types[TUINT32]->width);
- Array_cap = rnd(Array_nel+types[TUINT32]->width, types[TUINT32]->width);
- sizeof_Array = rnd(Array_cap+types[TUINT32]->width, widthptr);
-
- // string is same as slice wo the cap
- sizeof_String = rnd(Array_nel+types[TUINT32]->width, widthptr);
-
- dowidth(types[TSTRING]);
- dowidth(idealstring);
-}
-
-/*
- * compute total size of f's in/out arguments.
- */
-int
-argsize(Type *t)
-{
- Iter save;
- Type *fp;
- int w, x;
-
- w = 0;
-
- fp = structfirst(&save, getoutarg(t));
- while(fp != T) {
- x = fp->width + fp->type->width;
- if(x > w)
- w = x;
- fp = structnext(&save);
- }
-
- fp = funcfirst(&save, t);
- while(fp != T) {
- x = fp->width + fp->type->width;
- if(x > w)
- w = x;
- fp = funcnext(&save);
- }
-
- w = (w+widthptr-1) & ~(widthptr-1);
- return w;
-}
diff --git a/src/cmd/gc/bisonerrors b/src/cmd/gc/bisonerrors
deleted file mode 100755
index 5110f5350..000000000
--- a/src/cmd/gc/bisonerrors
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/usr/bin/awk -f
-# 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.
-
-# This program implements the core idea from
-#
-# Clinton L. Jeffery, Generating LR syntax error messages from examples,
-# ACM TOPLAS 25(5) (September 2003). http://doi.acm.org/10.1145/937563.937566
-#
-# It reads Bison's summary of a grammar followed by a file
-# like go.errors, replacing lines beginning with % by the
-# yystate and yychar that will be active when an error happens
-# while parsing that line.
-#
-# Unlike the system described in the paper, the lines in go.errors
-# give grammar symbol name lists, not actual program fragments.
-# This is a little less programmer-friendly but doesn't require being
-# able to run the text through lex.c.
-
-BEGIN{
- bison = 1
- grammar = 0
- states = 0
-}
-
-# In Grammar section of y.output,
-# record lhs and length of rhs for each rule.
-bison && /^Grammar/ { grammar = 1 }
-bison && /^(Terminals|state 0)/ { grammar = 0 }
-grammar && NF>0 {
- if($2 != "|") {
- r = $2
- sub(/:$/, "", r)
- }
- rulelhs[$1] = r
- rulesize[$1] = NF-2
- if(rulesize[$1] == 3 && $3 $4 $5 == "/*empty*/") {
- rulesize[$1] = 0
- }
-}
-
-# In state dumps, record shift/reduce actions.
-bison && /^state 0/ { grammar = 0; states = 1 }
-
-states && /^state / { state = $2 }
-states { statetext[state] = statetext[state] $0 "\n" }
-
-states && / shift, and go to state/ {
- n = nshift[state]++
- shift[state,n] = $7
- shifttoken[state,n] = $1
- next
-}
-states && / go to state/ {
- n = nshift[state]++
- shift[state,n] = $5
- shifttoken[state,n] = $1
- next
-}
-states && / reduce using rule/ {
- n = nreduce[state]++
- reduce[state,n] = $5
- reducetoken[state,n] = $1
- next
-}
-
-# First // comment marks the beginning of the pattern file.
-/^\/\// { bison = 0; grammar = 0; state = 0 }
-bison { next }
-
-# Treat % as first field on line as introducing a pattern (token sequence).
-# Run it through the LR machine and print the induced "yystate, yychar,"
-# at the point where the error happens.
-$1 == "%" {
- nstack = 0
- state = 0
- f = 2
- tok = ""
- for(;;) {
- if(tok == "" && f <= NF) {
- tok = $f
- f++
- }
- found = 0
- for(j=0; j<nshift[state]; j++) {
- if(shifttoken[state,j] == tok) {
- # print "SHIFT " tok " " state " -> " shift[state,j]
- stack[nstack++] = state
- state = shift[state,j]
- found = 1
- tok = ""
- break
- }
- }
- if(found)
- continue
- for(j=0; j<nreduce[state]; j++) {
- if(reducetoken[state,j] == tok || reducetoken[state,j] == "$default") {
- stack[nstack++] = state
- rule = reduce[state,j]
- nstack -= rulesize[rule]
- state = stack[--nstack]
- lhs = rulelhs[rule]
- if(tok != "")
- --f
- tok = rulelhs[rule]
- # print "REDUCE " nstack " " state " " tok " rule " rule " size " rulesize[rule]
- found = 1
- break
- }
- }
- if(found)
- continue
-
- # No shift or reduce applied - found the error.
- printf("\t%s, %s,\n", state, tok);
- break
- }
- next
-}
-
-# Print other lines verbatim.
-{print}
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
deleted file mode 100644
index 1f2a776fd..000000000
--- a/src/cmd/gc/bits.c
+++ /dev/null
@@ -1,158 +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 "go.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);
- fatal("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;
-}
-*/
-
-int
-bitno(int32 b)
-{
- int i;
-
- for(i=0; i<32; i++)
- if(b & (1L<<i))
- return i;
- fatal("bad in bitno");
- return 0;
-}
-
-int
-Qconv(Fmt *fp)
-{
- Bits bits;
- int i, first;
-
- first = 1;
- bits = va_arg(fp->args, Bits);
- while(bany(&bits)) {
- i = bnum(bits);
- if(first)
- first = 0;
- else
- fmtprint(fp, " ");
- if(var[i].sym == S)
- fmtprint(fp, "$%lld", var[i].offset);
- else
- fmtprint(fp, var[i].sym->name);
- bits.b[i/32] &= ~(1L << (i%32));
- }
- return 0;
-}
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
deleted file mode 100644
index 95098c8af..000000000
--- a/src/cmd/gc/builtin.c.boot
+++ /dev/null
@@ -1,115 +0,0 @@
-char *runtimeimport =
- "package runtime\n"
- "import runtime \"runtime\"\n"
- "func \"\".new (? int32) *any\n"
- "func \"\".panicindex ()\n"
- "func \"\".panicslice ()\n"
- "func \"\".throwreturn ()\n"
- "func \"\".throwinit ()\n"
- "func \"\".panicwrap (? string, ? string, ? string)\n"
- "func \"\".panic (? interface { })\n"
- "func \"\".recover (? *int32) interface { }\n"
- "func \"\".printbool (? bool)\n"
- "func \"\".printfloat (? float64)\n"
- "func \"\".printint (? int64)\n"
- "func \"\".printuint (? uint64)\n"
- "func \"\".printcomplex (? complex128)\n"
- "func \"\".printstring (? string)\n"
- "func \"\".printpointer (? any)\n"
- "func \"\".printiface (? any)\n"
- "func \"\".printeface (? any)\n"
- "func \"\".printslice (? any)\n"
- "func \"\".printnl ()\n"
- "func \"\".printsp ()\n"
- "func \"\".goprintf ()\n"
- "func \"\".concatstring ()\n"
- "func \"\".append ()\n"
- "func \"\".appendslice (typ *uint8, x any, y []any) any\n"
- "func \"\".cmpstring (? string, ? string) int\n"
- "func \"\".slicestring (? string, ? int, ? int) string\n"
- "func \"\".slicestring1 (? string, ? int) string\n"
- "func \"\".intstring (? int64) string\n"
- "func \"\".slicebytetostring (? []uint8) string\n"
- "func \"\".sliceinttostring (? []int) string\n"
- "func \"\".stringtoslicebyte (? string) []uint8\n"
- "func \"\".stringtosliceint (? string) []int\n"
- "func \"\".stringiter (? string, ? int) int\n"
- "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
- "func \"\".slicecopy (to any, fr any, wid uint32) int\n"
- "func \"\".slicestringcopy (to any, fr any) int\n"
- "func \"\".convI2E (elem any) any\n"
- "func \"\".convI2I (typ *uint8, elem any) any\n"
- "func \"\".convT2E (typ *uint8, elem any) any\n"
- "func \"\".convT2I (typ *uint8, typ2 *uint8, elem any) any\n"
- "func \"\".assertE2E (typ *uint8, iface any) any\n"
- "func \"\".assertE2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertE2I (typ *uint8, iface any) any\n"
- "func \"\".assertE2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertE2T (typ *uint8, iface any) any\n"
- "func \"\".assertE2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertI2E (typ *uint8, iface any) any\n"
- "func \"\".assertI2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertI2I (typ *uint8, iface any) any\n"
- "func \"\".assertI2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertI2T (typ *uint8, iface any) any\n"
- "func \"\".assertI2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".ifaceeq (i1 any, i2 any) bool\n"
- "func \"\".efaceeq (i1 any, i2 any) bool\n"
- "func \"\".ifacethash (i1 any) uint32\n"
- "func \"\".efacethash (i1 any) uint32\n"
- "func \"\".makemap (key *uint8, val *uint8, hint int64) map[any] any\n"
- "func \"\".mapaccess1 (hmap map[any] any, key any) any\n"
- "func \"\".mapaccess2 (hmap map[any] any, key any) (val any, pres bool)\n"
- "func \"\".mapassign1 (hmap map[any] any, key any, val any)\n"
- "func \"\".mapassign2 (hmap map[any] any, key any, val any, pres bool)\n"
- "func \"\".mapiterinit (hmap map[any] any, hiter *any)\n"
- "func \"\".mapiternext (hiter *any)\n"
- "func \"\".mapiter1 (hiter *any) any\n"
- "func \"\".mapiter2 (hiter *any) (key any, val any)\n"
- "func \"\".makechan (elem *uint8, hint int64) chan any\n"
- "func \"\".chanrecv1 (hchan <-chan any) any\n"
- "func \"\".chanrecv2 (hchan <-chan any) (elem any, received bool)\n"
- "func \"\".chansend1 (hchan chan<- any, elem any)\n"
- "func \"\".closechan (hchan any)\n"
- "func \"\".closedchan (hchan any) bool\n"
- "func \"\".selectnbsend (hchan chan<- any, elem any) bool\n"
- "func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n"
- "func \"\".selectnbrecv2 (elem *any, received *bool, hchan <-chan any) bool\n"
- "func \"\".newselect (size int) *uint8\n"
- "func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) bool\n"
- "func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n"
- "func \"\".selectrecv2 (sel *uint8, hchan <-chan any, elem *any, received *bool) bool\n"
- "func \"\".selectdefault (sel *uint8) bool\n"
- "func \"\".selectgo (sel *uint8)\n"
- "func \"\".block ()\n"
- "func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
- "func \"\".growslice (typ *uint8, old []any, n int64) []any\n"
- "func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
- "func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
- "func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n"
- "func \"\".closure ()\n"
- "func \"\".int64div (? int64, ? int64) int64\n"
- "func \"\".uint64div (? uint64, ? uint64) uint64\n"
- "func \"\".int64mod (? int64, ? int64) int64\n"
- "func \"\".uint64mod (? uint64, ? uint64) uint64\n"
- "func \"\".float64toint64 (? float64) int64\n"
- "func \"\".float64touint64 (? float64) uint64\n"
- "func \"\".int64tofloat64 (? int64) float64\n"
- "func \"\".uint64tofloat64 (? uint64) float64\n"
- "func \"\".complex128div (num complex128, den complex128) complex128\n"
- "\n"
- "$$\n";
-char *unsafeimport =
- "package unsafe\n"
- "import runtime \"runtime\"\n"
- "type \"\".Pointer uintptr\n"
- "func \"\".Offsetof (? any) uintptr\n"
- "func \"\".Sizeof (? any) uintptr\n"
- "func \"\".Alignof (? any) uintptr\n"
- "func \"\".Typeof (i interface { }) interface { }\n"
- "func \"\".Reflect (i interface { }) (typ interface { }, addr \"\".Pointer)\n"
- "func \"\".Unreflect (typ interface { }, addr \"\".Pointer) interface { }\n"
- "func \"\".New (typ interface { }) \"\".Pointer\n"
- "func \"\".NewArray (typ interface { }, n int) \"\".Pointer\n"
- "\n"
- "$$\n";
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
deleted file mode 100644
index 7e7b40526..000000000
--- a/src/cmd/gc/closure.c
+++ /dev/null
@@ -1,247 +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.
-
-/*
- * function literals aka closures
- */
-
-#include "go.h"
-
-void
-closurehdr(Node *ntype)
-{
- Node *n, *name, *a;
- NodeList *l;
-
- n = nod(OCLOSURE, N, N);
- n->ntype = ntype;
- n->funcdepth = funcdepth;
-
- funchdr(n);
-
- // steal ntype's argument names and
- // leave a fresh copy in their place.
- // references to these variables need to
- // refer to the variables in the external
- // function declared below; see walkclosure.
- n->list = ntype->list;
- n->rlist = ntype->rlist;
- ntype->list = nil;
- ntype->rlist = nil;
- for(l=n->list; l; l=l->next) {
- name = l->n->left;
- if(name)
- name = newname(name->sym);
- a = nod(ODCLFIELD, name, l->n->right);
- a->isddd = l->n->isddd;
- if(name)
- name->isddd = a->isddd;
- ntype->list = list(ntype->list, a);
- }
- for(l=n->rlist; l; l=l->next) {
- name = l->n->left;
- if(name)
- name = newname(name->sym);
- ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right));
- }
-}
-
-Node*
-closurebody(NodeList *body)
-{
- Node *func, *v;
- NodeList *l;
-
- if(body == nil)
- body = list1(nod(OEMPTY, N, N));
-
- func = curfn;
- l = func->dcl;
- func->nbody = body;
- funcbody(func);
-
- // closure-specific variables are hanging off the
- // ordinary ones in the symbol table; see oldname.
- // unhook them.
- // make the list of pointers for the closure call.
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- v->closure->closure = v->outer;
- v->heapaddr = nod(OADDR, oldname(v->sym), N);
- }
-
- return func;
-}
-
-void
-typecheckclosure(Node *func, int top)
-{
- Node *oldfn;
- NodeList *l;
- Node *v;
-
- oldfn = curfn;
- typecheck(&func->ntype, Etype);
- func->type = func->ntype->type;
- if(func->type != T) {
- curfn = func;
- typechecklist(func->nbody, Etop);
- curfn = oldfn;
- }
-
- // type check the & of closed variables outside the closure,
- // so that the outer frame also grabs them and knows they
- // escape.
- func->enter = nil;
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- if(v->type == T) {
- // if v->type is nil, it means v looked like it was
- // going to be used in the closure but wasn't.
- // this happens because when parsing a, b, c := f()
- // the a, b, c gets parsed as references to older
- // a, b, c before the parser figures out this is a
- // declaration.
- v->op = 0;
- continue;
- }
- // For a closure that is called in place, but not
- // inside a go statement, avoid moving variables to the heap.
- if ((top & (Ecall|Eproc)) == Ecall)
- v->heapaddr->etype = 1;
- typecheck(&v->heapaddr, Erv);
- func->enter = list(func->enter, v->heapaddr);
- v->heapaddr = N;
- }
-}
-
-static Node*
-makeclosure(Node *func, NodeList **init, int nowrap)
-{
- Node *xtype, *v, *addr, *xfunc;
- NodeList *l;
- static int closgen;
- char *p;
-
- /*
- * wrap body in external function
- * with extra closure parameters.
- */
- xtype = nod(OTFUNC, N, N);
-
- // each closure variable has a corresponding
- // address parameter.
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- if(v->op == 0)
- continue;
- addr = nod(ONAME, N, N);
- p = smprint("&%s", v->sym->name);
- addr->sym = lookup(p);
- free(p);
- addr->ntype = nod(OIND, typenod(v->type), N);
- addr->class = PPARAM;
- addr->addable = 1;
- addr->ullman = 1;
-
- v->heapaddr = addr;
-
- xtype->list = list(xtype->list, nod(ODCLFIELD, addr, addr->ntype));
- }
-
- // then a dummy arg where the closure's caller pc sits
- if (!nowrap)
- xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
-
- // then the function arguments
- xtype->list = concat(xtype->list, func->list);
- xtype->rlist = concat(xtype->rlist, func->rlist);
-
- // create the function
- xfunc = nod(ODCLFUNC, N, N);
- snprint(namebuf, sizeof namebuf, "_func_%.3d", ++closgen);
- xfunc->nname = newname(lookup(namebuf));
- xfunc->nname->ntype = xtype;
- xfunc->nname->defn = xfunc;
- declare(xfunc->nname, PFUNC);
- xfunc->nname->funcdepth = func->funcdepth;
- xfunc->funcdepth = func->funcdepth;
- xfunc->nbody = func->nbody;
- xfunc->dcl = func->dcl;
- if(xfunc->nbody == nil)
- fatal("empty body - won't generate any code");
- typecheck(&xfunc, Etop);
- closures = list(closures, xfunc);
-
- return xfunc;
-}
-
-Node*
-walkclosure(Node *func, NodeList **init)
-{
- int narg;
- Node *xtype, *xfunc, *call, *clos;
- NodeList *l, *in;
-
- /*
- * wrap body in external function
- * with extra closure parameters.
- */
-
- // create the function
- xfunc = makeclosure(func, init, 0);
- xtype = xfunc->nname->ntype;
-
- // prepare call of sys.closure that turns external func into func literal value.
- clos = syslook("closure", 1);
- clos->type = T;
- clos->ntype = nod(OTFUNC, N, N);
- in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // siz
- in = list(in, nod(ODCLFIELD, N, xtype));
- narg = 0;
- for(l=func->cvars; l; l=l->next) {
- if(l->n->op == 0)
- continue;
- narg++;
- in = list(in, nod(ODCLFIELD, N, l->n->heapaddr->ntype));
- }
- clos->ntype->list = in;
- clos->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(func->type)));
- typecheck(&clos, Erv);
-
- call = nod(OCALL, clos, N);
- if(narg*widthptr > 100)
- yyerror("closure needs too many variables; runtime will reject it");
- in = list1(nodintconst(narg*widthptr));
- in = list(in, xfunc->nname);
- in = concat(in, func->enter);
- call->list = in;
-
- typecheck(&call, Erv);
- walkexpr(&call, init);
- return call;
-}
-
-// Special case for closures that get called in place.
-// Optimize runtime.closure(X, __func__xxxx_, .... ) away
-// to __func__xxxx_(Y ....).
-// On entry, expect n->op == OCALL, n->left->op == OCLOSURE.
-void
-walkcallclosure(Node *n, NodeList **init)
-{
- if (n->op != OCALLFUNC || n->left->op != OCLOSURE) {
- dump("walkcallclosure", n);
- fatal("abuse of walkcallclosure");
- }
-
- // New arg list for n. First the closure-args
- // and then the original parameter list.
- n->list = concat(n->left->enter, n->list);
- n->left = makeclosure(n->left, init, 1)->nname;
- dowidth(n->left->type);
- n->type = getoutargx(n->left->type);
- // for a single valued function, pull the field type out of the struct
- if (n->type && n->type->type && !n->type->type->down)
- n->type = n->type->type->type;
-}
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
deleted file mode 100644
index 8fe9072b2..000000000
--- a/src/cmd/gc/const.c
+++ /dev/null
@@ -1,1283 +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 "go.h"
-#define TUP(x,y) (((x)<<16)|(y))
-
-static Val tocplx(Val);
-static Val toflt(Val);
-static Val tostr(Val);
-static Val copyval(Val);
-static void cmplxmpy(Mpcplx*, Mpcplx*);
-static void cmplxdiv(Mpcplx*, Mpcplx*);
-
-/*
- * truncate float literal fv to 32-bit or 64-bit precision
- * according to type; return truncated value.
- */
-Mpflt*
-truncfltlit(Mpflt *oldv, Type *t)
-{
- double d;
- float f;
- Mpflt *fv;
-
- if(t == T)
- return oldv;
-
- fv = mal(sizeof *fv);
- *fv = *oldv;
-
- // convert large precision literal floating
- // into limited precision (float64 or float32)
- // botch -- this assumes that compiler fp
- // has same precision as runtime fp
- switch(t->etype) {
- case TFLOAT64:
- d = mpgetflt(fv);
- mpmovecflt(fv, d);
- break;
-
- case TFLOAT32:
- d = mpgetflt(fv);
- f = d;
- d = f;
- mpmovecflt(fv, d);
- break;
- }
- return fv;
-}
-
-/*
- * convert n, if literal, to type t.
- * implicit conversion.
- */
-void
-convlit(Node **np, Type *t)
-{
- convlit1(np, t, 0);
-}
-
-/*
- * convert n, if literal, to type t.
- * return a new node if necessary
- * (if n is a named constant, can't edit n->type directly).
- */
-void
-convlit1(Node **np, Type *t, int explicit)
-{
- int ct, et;
- Node *n, *nn;
-
- n = *np;
- if(n == N || t == T || n->type == T || isideal(t) || n->type == t)
- return;
- if(!explicit && !isideal(n->type))
- return;
-
- if(n->op == OLITERAL) {
- nn = nod(OXXX, N, N);
- *nn = *n;
- n = nn;
- *np = n;
- }
-
- switch(n->op) {
- default:
- if(n->type->etype == TIDEAL) {
- convlit(&n->left, t);
- convlit(&n->right, t);
- n->type = t;
- }
- return;
- case OLITERAL:
- // target is invalid type for a constant? leave alone.
- if(!okforconst[t->etype] && n->type->etype != TNIL) {
- defaultlit(&n, T);
- *np = n;
- return;
- }
- break;
- case OLSH:
- case ORSH:
- convlit1(&n->left, t, explicit && isideal(n->left->type));
- t = n->left->type;
- if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT)
- n->val = toint(n->val);
- if(t != T && !isint[t->etype]) {
- yyerror("invalid operation: %#N (shift of type %T)", n, t);
- t = T;
- }
- n->type = t;
- return;
- }
-
- // avoided repeated calculations, errors
- if(eqtype(n->type, t))
- return;
-
- ct = consttype(n);
- if(ct < 0)
- goto bad;
-
- et = t->etype;
- if(et == TINTER) {
- if(ct == CTNIL && n->type == types[TNIL]) {
- n->type = t;
- return;
- }
- defaultlit(np, T);
- return;
- }
-
- switch(ct) {
- default:
- goto bad;
-
- case CTNIL:
- switch(et) {
- default:
- n->type = T;
- goto bad;
-
- case TSTRING:
- // let normal conversion code handle it
- return;
-
- case TARRAY:
- if(!isslice(t))
- goto bad;
- break;
-
- case TPTR32:
- case TPTR64:
- case TINTER:
- case TMAP:
- case TCHAN:
- case TFUNC:
- case TUNSAFEPTR:
- break;
- }
- break;
-
- case CTSTR:
- case CTBOOL:
- if(et != n->type->etype)
- goto bad;
- break;
-
- case CTINT:
- case CTFLT:
- case CTCPLX:
- ct = n->val.ctype;
- if(isint[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTCPLX:
- case CTFLT:
- n->val = toint(n->val);
- // flowthrough
- case CTINT:
- overflow(n->val, t);
- break;
- }
- } else
- if(isfloat[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTCPLX:
- case CTINT:
- n->val = toflt(n->val);
- // flowthrough
- case CTFLT:
- overflow(n->val, t);
- n->val.u.fval = truncfltlit(n->val.u.fval, t);
- break;
- }
- } else
- if(iscomplex[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTFLT:
- case CTINT:
- n->val = tocplx(n->val);
- break;
- case CTCPLX:
- overflow(n->val, t);
- break;
- }
- } else
- if(et == TSTRING && ct == CTINT && explicit)
- n->val = tostr(n->val);
- else
- goto bad;
- break;
- }
- n->type = t;
- return;
-
-bad:
- if(!n->diag) {
- yyerror("cannot convert %#N to type %T", n, t);
- n->diag = 1;
- }
- if(isideal(n->type)) {
- defaultlit(&n, T);
- *np = n;
- }
- return;
-}
-
-static Val
-copyval(Val v)
-{
- Mpint *i;
- Mpflt *f;
- Mpcplx *c;
-
- switch(v.ctype) {
- case CTINT:
- i = mal(sizeof(*i));
- mpmovefixfix(i, v.u.xval);
- v.u.xval = i;
- break;
- case CTFLT:
- f = mal(sizeof(*f));
- mpmovefltflt(f, v.u.fval);
- v.u.fval = f;
- break;
- case CTCPLX:
- c = mal(sizeof(*c));
- mpmovefltflt(&c->real, &v.u.cval->real);
- mpmovefltflt(&c->imag, &v.u.cval->imag);
- v.u.cval = c;
- break;
- }
- return v;
-}
-
-static Val
-tocplx(Val v)
-{
- Mpcplx *c;
-
- switch(v.ctype) {
- case CTINT:
- c = mal(sizeof(*c));
- mpmovefixflt(&c->real, v.u.xval);
- mpmovecflt(&c->imag, 0.0);
- v.ctype = CTCPLX;
- v.u.cval = c;
- break;
- case CTFLT:
- c = mal(sizeof(*c));
- mpmovefltflt(&c->real, v.u.fval);
- mpmovecflt(&c->imag, 0.0);
- v.ctype = CTCPLX;
- v.u.cval = c;
- break;
- }
- return v;
-}
-
-static Val
-toflt(Val v)
-{
- Mpflt *f;
-
- switch(v.ctype) {
- case CTINT:
- f = mal(sizeof(*f));
- mpmovefixflt(f, v.u.xval);
- v.ctype = CTFLT;
- v.u.fval = f;
- break;
- case CTCPLX:
- f = mal(sizeof(*f));
- mpmovefltflt(f, &v.u.cval->real);
- if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
- v.ctype = CTFLT;
- v.u.fval = f;
- break;
- }
- return v;
-}
-
-Val
-toint(Val v)
-{
- Mpint *i;
-
- switch(v.ctype) {
- case CTFLT:
- i = mal(sizeof(*i));
- if(mpmovefltfix(i, v.u.fval) < 0)
- yyerror("constant %#F truncated to integer", v.u.fval);
- v.ctype = CTINT;
- v.u.xval = i;
- break;
- case CTCPLX:
- i = mal(sizeof(*i));
- if(mpmovefltfix(i, &v.u.cval->real) < 0)
- yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag);
- if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
- v.ctype = CTINT;
- v.u.xval = i;
- break;
- }
- return v;
-}
-
-void
-overflow(Val v, Type *t)
-{
- // v has already been converted
- // to appropriate form for t.
- if(t == T || t->etype == TIDEAL)
- return;
- switch(v.ctype) {
- case CTINT:
- if(!isint[t->etype])
- fatal("overflow: %T integer constant", t);
- if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 ||
- mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0)
- yyerror("constant %B overflows %T", v.u.xval, t);
- break;
- case CTFLT:
- if(!isfloat[t->etype])
- fatal("overflow: %T floating-point constant", t);
- if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0)
- yyerror("constant %#F overflows %T", v.u.fval, t);
- break;
- case CTCPLX:
- if(!iscomplex[t->etype])
- fatal("overflow: %T complex constant", t);
- if(mpcmpfltflt(&v.u.cval->real, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(&v.u.cval->real, maxfltval[t->etype]) >= 0 ||
- mpcmpfltflt(&v.u.cval->imag, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(&v.u.cval->imag, maxfltval[t->etype]) >= 0)
- yyerror("constant %#F overflows %T", v.u.fval, t);
- break;
- }
-}
-
-static Val
-tostr(Val v)
-{
- Rune rune;
- int l;
- Strlit *s;
-
- switch(v.ctype) {
- case CTINT:
- if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 ||
- mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0)
- yyerror("overflow in int -> string");
- rune = mpgetfix(v.u.xval);
- l = runelen(rune);
- s = mal(sizeof(*s)+l);
- s->len = l;
- runetochar((char*)s->s, &rune);
- memset(&v, 0, sizeof v);
- v.ctype = CTSTR;
- v.u.sval = s;
- break;
-
- case CTFLT:
- yyerror("no float -> string");
-
- case CTNIL:
- memset(&v, 0, sizeof v);
- v.ctype = CTSTR;
- v.u.sval = mal(sizeof *s);
- break;
- }
- return v;
-}
-
-int
-consttype(Node *n)
-{
- if(n == N || n->op != OLITERAL)
- return -1;
- return n->val.ctype;
-}
-
-int
-isconst(Node *n, int ct)
-{
- return consttype(n) == ct;
-}
-
-/*
- * if n is constant, rewrite as OLITERAL node.
- */
-void
-evconst(Node *n)
-{
- Node *nl, *nr;
- int32 len;
- Strlit *str;
- int wl, wr, lno, et;
- Val v, rv;
- Mpint b;
-
- // pick off just the opcodes that can be
- // constant evaluated.
- switch(n->op) {
- default:
- return;
- case OADD:
- case OADDSTR:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case OARRAYBYTESTR:
- case OCOM:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLSH:
- case OLT:
- case OMINUS:
- case OMOD:
- case OMUL:
- case ONE:
- case ONOT:
- case OOR:
- case OOROR:
- case OPLUS:
- case ORSH:
- case OSUB:
- case OXOR:
- break;
- case OCONV:
- if(n->type == T)
- return;
- if(!okforconst[n->type->etype] && n->type->etype != TNIL)
- return;
- break;
- }
-
- nl = n->left;
- if(nl == N || nl->type == T)
- return;
- if(consttype(nl) < 0)
- return;
- wl = nl->type->etype;
- if(isint[wl] || isfloat[wl] || iscomplex[wl])
- wl = TIDEAL;
-
- nr = n->right;
- if(nr == N)
- goto unary;
- if(nr->type == T)
- return;
- if(consttype(nr) < 0)
- return;
- wr = nr->type->etype;
- if(isint[wr] || isfloat[wr] || iscomplex[wr])
- wr = TIDEAL;
-
- // check for compatible general types (numeric, string, etc)
- if(wl != wr)
- goto illegal;
-
- // check for compatible types.
- switch(n->op) {
- default:
- // ideal const mixes with anything but otherwise must match.
- if(nl->type->etype != TIDEAL) {
- defaultlit(&nr, nl->type);
- n->right = nr;
- }
- if(nr->type->etype != TIDEAL) {
- defaultlit(&nl, nr->type);
- n->left = nl;
- }
- if(nl->type->etype != nr->type->etype)
- goto illegal;
- break;
-
- case OLSH:
- case ORSH:
- // right must be unsigned.
- // left can be ideal.
- defaultlit(&nr, types[TUINT]);
- n->right = nr;
- if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype]))
- goto illegal;
- nl->val = toint(nl->val);
- nr->val = toint(nr->val);
- break;
- }
-
- // copy numeric value to avoid modifying
- // n->left, in case someone still refers to it (e.g. iota).
- v = nl->val;
- if(wl == TIDEAL)
- v = copyval(v);
-
- rv = nr->val;
-
- // convert to common ideal
- if(v.ctype == CTCPLX || rv.ctype == CTCPLX) {
- v = tocplx(v);
- rv = tocplx(rv);
- }
- if(v.ctype == CTFLT || rv.ctype == CTFLT) {
- v = toflt(v);
- rv = toflt(rv);
- }
- if(v.ctype != rv.ctype) {
- // Use of undefined name as constant?
- if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0)
- return;
- fatal("constant type mismatch %T(%d) %T(%d)", nl->type, v.ctype, nr->type, rv.ctype);
- }
-
- // run op
- switch(TUP(n->op, v.ctype)) {
- default:
- illegal:
- if(!n->diag) {
- yyerror("illegal constant expression: %T %O %T",
- nl->type, n->op, nr->type);
- n->diag = 1;
- }
- return;
-
- case TUP(OADD, CTINT):
- mpaddfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OSUB, CTINT):
- mpsubfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OMUL, CTINT):
- mpmulfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(ODIV, CTINT):
- if(mpcmpfixc(rv.u.xval, 0) == 0) {
- yyerror("division by zero");
- mpmovecfix(v.u.xval, 1);
- break;
- }
- mpdivfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OMOD, CTINT):
- if(mpcmpfixc(rv.u.xval, 0) == 0) {
- yyerror("division by zero");
- mpmovecfix(v.u.xval, 1);
- break;
- }
- mpmodfixfix(v.u.xval, rv.u.xval);
- break;
-
- case TUP(OLSH, CTINT):
- mplshfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(ORSH, CTINT):
- mprshfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OOR, CTINT):
- mporfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OAND, CTINT):
- mpandfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OANDNOT, CTINT):
- mpandnotfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OXOR, CTINT):
- mpxorfixfix(v.u.xval, rv.u.xval);
- break;
-
- case TUP(OADD, CTFLT):
- mpaddfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(OSUB, CTFLT):
- mpsubfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(OMUL, CTFLT):
- mpmulfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(ODIV, CTFLT):
- if(mpcmpfltc(rv.u.fval, 0) == 0) {
- yyerror("division by zero");
- mpmovecflt(v.u.fval, 1.0);
- break;
- }
- mpdivfltflt(v.u.fval, rv.u.fval);
- break;
-
- case TUP(OADD, CTCPLX):
- mpaddfltflt(&v.u.cval->real, &rv.u.cval->real);
- mpaddfltflt(&v.u.cval->imag, &rv.u.cval->imag);
- break;
- case TUP(OSUB, CTCPLX):
- mpsubfltflt(&v.u.cval->real, &rv.u.cval->real);
- mpsubfltflt(&v.u.cval->imag, &rv.u.cval->imag);
- break;
- case TUP(OMUL, CTCPLX):
- cmplxmpy(v.u.cval, rv.u.cval);
- break;
- case TUP(ODIV, CTCPLX):
- if(mpcmpfltc(&rv.u.cval->real, 0) == 0 &&
- mpcmpfltc(&rv.u.cval->imag, 0) == 0) {
- yyerror("complex division by zero");
- mpmovecflt(&rv.u.cval->real, 1.0);
- mpmovecflt(&rv.u.cval->imag, 0.0);
- break;
- }
- cmplxdiv(v.u.cval, rv.u.cval);
- break;
-
- case TUP(OEQ, CTNIL):
- goto settrue;
- case TUP(ONE, CTNIL):
- goto setfalse;
-
- case TUP(OEQ, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) >= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) > 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTCPLX):
- if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) == 0 &&
- mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTCPLX):
- if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) != 0 ||
- mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) != 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTSTR):
- if(cmpslit(nl, nr) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTSTR):
- if(cmpslit(nl, nr) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTSTR):
- if(cmpslit(nl, nr) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTSTR):
- if(cmpslit(nl, nr) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTSTR):
- if(cmpslit(nl, nr) >= 0l)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTSTR):
- if(cmpslit(nl, nr) > 0)
- goto settrue;
- goto setfalse;
- case TUP(OADDSTR, CTSTR):
- len = v.u.sval->len + rv.u.sval->len;
- str = mal(sizeof(*str) + len);
- str->len = len;
- memcpy(str->s, v.u.sval->s, v.u.sval->len);
- memcpy(str->s+v.u.sval->len, rv.u.sval->s, rv.u.sval->len);
- str->len = len;
- v.u.sval = str;
- break;
-
- case TUP(OOROR, CTBOOL):
- if(v.u.bval || rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(OANDAND, CTBOOL):
- if(v.u.bval && rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(OEQ, CTBOOL):
- if(v.u.bval == rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTBOOL):
- if(v.u.bval != rv.u.bval)
- goto settrue;
- goto setfalse;
- }
- goto ret;
-
-unary:
- // copy numeric value to avoid modifying
- // nl, in case someone still refers to it (e.g. iota).
- v = nl->val;
- if(wl == TIDEAL)
- v = copyval(v);
-
- switch(TUP(n->op, v.ctype)) {
- default:
- if(!n->diag) {
- yyerror("illegal constant expression %O %T", n->op, nl->type);
- n->diag = 1;
- }
- return;
-
- case TUP(OCONV, CTNIL):
- case TUP(OARRAYBYTESTR, CTNIL):
- if(n->type->etype == TSTRING) {
- v = tostr(v);
- nl->type = n->type;
- break;
- }
- // fall through
- case TUP(OCONV, CTINT):
- case TUP(OCONV, CTFLT):
- case TUP(OCONV, CTSTR):
- convlit1(&nl, n->type, 1);
- break;
-
- case TUP(OPLUS, CTINT):
- break;
- case TUP(OMINUS, CTINT):
- mpnegfix(v.u.xval);
- break;
- case TUP(OCOM, CTINT):
- et = Txxx;
- if(nl->type != T)
- et = nl->type->etype;
-
- // calculate the mask in b
- // result will be (a ^ mask)
- switch(et) {
- default:
- // signed guys change sign
- mpmovecfix(&b, -1);
- break;
-
- case TUINT8:
- case TUINT16:
- case TUINT32:
- case TUINT64:
- case TUINT:
- case TUINTPTR:
- // unsigned guys invert their bits
- mpmovefixfix(&b, maxintval[et]);
- break;
- }
- mpxorfixfix(v.u.xval, &b);
- break;
-
- case TUP(OPLUS, CTFLT):
- break;
- case TUP(OMINUS, CTFLT):
- mpnegflt(v.u.fval);
- break;
-
- case TUP(OPLUS, CTCPLX):
- break;
- case TUP(OMINUS, CTCPLX):
- mpnegflt(&v.u.cval->real);
- mpnegflt(&v.u.cval->imag);
- break;
-
- case TUP(ONOT, CTBOOL):
- if(!v.u.bval)
- goto settrue;
- goto setfalse;
- }
-
-ret:
- // rewrite n in place.
- *n = *nl;
- n->val = v;
-
- // check range.
- lno = setlineno(n);
- overflow(v, n->type);
- lineno = lno;
-
- // truncate precision for non-ideal float.
- if(v.ctype == CTFLT && n->type->etype != TIDEAL)
- n->val.u.fval = truncfltlit(v.u.fval, n->type);
- return;
-
-settrue:
- *n = *nodbool(1);
- return;
-
-setfalse:
- *n = *nodbool(0);
- return;
-}
-
-Node*
-nodlit(Val v)
-{
- Node *n;
-
- n = nod(OLITERAL, N, N);
- n->val = v;
- switch(v.ctype) {
- default:
- fatal("nodlit ctype %d", v.ctype);
- case CTSTR:
- n->type = idealstring;
- break;
- case CTBOOL:
- n->type = idealbool;
- break;
- case CTINT:
- case CTFLT:
- case CTCPLX:
- n->type = types[TIDEAL];
- break;
- case CTNIL:
- n->type = types[TNIL];
- break;
- }
- return n;
-}
-
-Node*
-nodcplxlit(Val r, Val i)
-{
- Node *n;
- Mpcplx *c;
-
- r = toflt(r);
- i = toflt(i);
-
- c = mal(sizeof(*c));
- n = nod(OLITERAL, N, N);
- n->type = types[TIDEAL];
- n->val.u.cval = c;
- n->val.ctype = CTCPLX;
-
- if(r.ctype != CTFLT || i.ctype != CTFLT)
- fatal("nodcplxlit ctype %d/%d", r.ctype, i.ctype);
-
- mpmovefltflt(&c->real, r.u.fval);
- mpmovefltflt(&c->imag, i.u.fval);
- return n;
-}
-
-// TODO(rsc): combine with convlit
-void
-defaultlit(Node **np, Type *t)
-{
- int lno;
- Node *n, *nn;
-
- n = *np;
- if(n == N || !isideal(n->type))
- return;
-
- switch(n->op) {
- case OLITERAL:
- nn = nod(OXXX, N, N);
- *nn = *n;
- n = nn;
- *np = n;
- break;
- case OLSH:
- case ORSH:
- defaultlit(&n->left, t);
- t = n->left->type;
- if(t != T && !isint[t->etype]) {
- yyerror("invalid operation: %#N (shift of type %T)", n, t);
- t = T;
- }
- n->type = t;
- return;
- default:
- if(n->left == N) {
- dump("defaultlit", n);
- fatal("defaultlit");
- }
- defaultlit(&n->left, t);
- defaultlit(&n->right, t);
- if(n->type == idealbool || n->type == idealstring)
- n->type = types[n->type->etype];
- else
- n->type = n->left->type;
- return;
- }
-
- lno = setlineno(n);
- switch(n->val.ctype) {
- default:
- if(t != T) {
- convlit(np, t);
- break;
- }
- if(n->val.ctype == CTNIL) {
- lineno = lno;
- yyerror("use of untyped nil");
- n->type = T;
- break;
- }
- if(n->val.ctype == CTSTR) {
- n->type = types[TSTRING];
- break;
- }
- yyerror("defaultlit: unknown literal: %#N", n);
- break;
- case CTBOOL:
- n->type = types[TBOOL];
- if(t != T && t->etype == TBOOL)
- n->type = t;
- break;
- case CTINT:
- n->type = types[TINT];
- goto num;
- case CTFLT:
- n->type = types[TFLOAT64];
- goto num;
- case CTCPLX:
- n->type = types[TCOMPLEX128];
- goto num;
- num:
- if(t != T) {
- if(isint[t->etype]) {
- n->type = t;
- n->val = toint(n->val);
- }
- else
- if(isfloat[t->etype]) {
- n->type = t;
- n->val = toflt(n->val);
- }
- else
- if(iscomplex[t->etype]) {
- n->type = t;
- n->val = tocplx(n->val);
- }
- }
- overflow(n->val, n->type);
- break;
- }
- lineno = lno;
-}
-
-/*
- * defaultlit on both nodes simultaneously;
- * if they're both ideal going in they better
- * get the same type going out.
- * force means must assign concrete (non-ideal) type.
- */
-void
-defaultlit2(Node **lp, Node **rp, int force)
-{
- Node *l, *r;
-
- l = *lp;
- r = *rp;
- if(l->type == T || r->type == T)
- return;
- if(!isideal(l->type)) {
- convlit(rp, l->type);
- return;
- }
- if(!isideal(r->type)) {
- convlit(lp, r->type);
- return;
- }
- if(!force)
- return;
- if(isconst(l, CTCPLX) || isconst(r, CTCPLX)) {
- convlit(lp, types[TCOMPLEX128]);
- convlit(rp, types[TCOMPLEX128]);
- return;
- }
- if(isconst(l, CTFLT) || isconst(r, CTFLT)) {
- convlit(lp, types[TFLOAT64]);
- convlit(rp, types[TFLOAT64]);
- return;
- }
- convlit(lp, types[TINT]);
- convlit(rp, types[TINT]);
-}
-
-int
-cmpslit(Node *l, Node *r)
-{
- int32 l1, l2, i, m;
- uchar *s1, *s2;
-
- l1 = l->val.u.sval->len;
- l2 = r->val.u.sval->len;
- s1 = (uchar*)l->val.u.sval->s;
- s2 = (uchar*)r->val.u.sval->s;
-
- m = l1;
- if(l2 < m)
- m = l2;
-
- for(i=0; i<m; i++) {
- if(s1[i] == s2[i])
- continue;
- if(s1[i] > s2[i])
- return +1;
- return -1;
- }
- if(l1 == l2)
- return 0;
- if(l1 > l2)
- return +1;
- return -1;
-}
-
-int
-smallintconst(Node *n)
-{
- if(n->op == OLITERAL && n->type != T)
- switch(simtype[n->type->etype]) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TBOOL:
- case TPTR32:
- return 1;
- case TINT64:
- case TUINT64:
- if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0
- || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
- break;
- return 1;
- }
- return 0;
-}
-
-long
-nonnegconst(Node *n)
-{
- if(n->op == OLITERAL && n->type != T)
- switch(simtype[n->type->etype]) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TIDEAL:
- // check negative and 2^31
- if(mpcmpfixfix(n->val.u.xval, minintval[TUINT32]) < 0
- || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
- break;
- return mpgetfix(n->val.u.xval);
- }
- return -1;
-}
-
-/*
- * convert x to type et and back to int64
- * for sign extension and truncation.
- */
-static int64
-iconv(int64 x, int et)
-{
- switch(et) {
- case TINT8:
- x = (int8)x;
- break;
- case TUINT8:
- x = (uint8)x;
- break;
- case TINT16:
- x = (int16)x;
- break;
- case TUINT16:
- x = (uint64)x;
- break;
- case TINT32:
- x = (int32)x;
- break;
- case TUINT32:
- x = (uint32)x;
- break;
- case TINT64:
- case TUINT64:
- break;
- }
- return x;
-}
-
-/*
- * convert constant val to type t; leave in con.
- * for back end.
- */
-void
-convconst(Node *con, Type *t, Val *val)
-{
- int64 i;
- int tt;
-
- tt = simsimtype(t);
-
- // copy the constant for conversion
- nodconst(con, types[TINT8], 0);
- con->type = t;
- con->val = *val;
-
- if(isint[tt]) {
- con->val.ctype = CTINT;
- con->val.u.xval = mal(sizeof *con->val.u.xval);
- switch(val->ctype) {
- default:
- fatal("convconst ctype=%d %lT", val->ctype, t);
- case CTINT:
- i = mpgetfix(val->u.xval);
- break;
- case CTBOOL:
- i = val->u.bval;
- break;
- case CTNIL:
- i = 0;
- break;
- }
- i = iconv(i, tt);
- mpmovecfix(con->val.u.xval, i);
- return;
- }
-
- if(isfloat[tt]) {
- con->val = toflt(con->val);
- if(con->val.ctype != CTFLT)
- fatal("convconst ctype=%d %T", con->val.ctype, t);
- if(tt == TFLOAT32)
- con->val.u.fval = truncfltlit(con->val.u.fval, t);
- return;
- }
-
- if(iscomplex[tt]) {
- con->val = tocplx(con->val);
- if(tt == TCOMPLEX64) {
- con->val.u.cval->real = *truncfltlit(&con->val.u.cval->real, types[TFLOAT32]);
- con->val.u.cval->imag = *truncfltlit(&con->val.u.cval->imag, types[TFLOAT32]);
- }
- return;
- }
-
- fatal("convconst %lT constant", t);
-
-}
-
-// complex multiply v *= rv
-// (a, b) * (c, d) = (a*c - b*d, b*c + a*d)
-static void
-cmplxmpy(Mpcplx *v, Mpcplx *rv)
-{
- Mpflt ac, bd, bc, ad;
-
- mpmovefltflt(&ac, &v->real);
- mpmulfltflt(&ac, &rv->real); // ac
-
- mpmovefltflt(&bd, &v->imag);
- mpmulfltflt(&bd, &rv->imag); // bd
-
- mpmovefltflt(&bc, &v->imag);
- mpmulfltflt(&bc, &rv->real); // bc
-
- mpmovefltflt(&ad, &v->real);
- mpmulfltflt(&ad, &rv->imag); // ad
-
- mpmovefltflt(&v->real, &ac);
- mpsubfltflt(&v->real, &bd); // ac-bd
-
- mpmovefltflt(&v->imag, &bc);
- mpaddfltflt(&v->imag, &ad); // bc+ad
-}
-
-// complex divide v /= rv
-// (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
-static void
-cmplxdiv(Mpcplx *v, Mpcplx *rv)
-{
- Mpflt ac, bd, bc, ad, cc_plus_dd;
-
- mpmovefltflt(&cc_plus_dd, &rv->real);
- mpmulfltflt(&cc_plus_dd, &rv->real); // cc
-
- mpmovefltflt(&ac, &rv->imag);
- mpmulfltflt(&ac, &rv->imag); // dd
-
- mpaddfltflt(&cc_plus_dd, &ac); // cc+dd
-
- mpmovefltflt(&ac, &v->real);
- mpmulfltflt(&ac, &rv->real); // ac
-
- mpmovefltflt(&bd, &v->imag);
- mpmulfltflt(&bd, &rv->imag); // bd
-
- mpmovefltflt(&bc, &v->imag);
- mpmulfltflt(&bc, &rv->real); // bc
-
- mpmovefltflt(&ad, &v->real);
- mpmulfltflt(&ad, &rv->imag); // ad
-
- mpmovefltflt(&v->real, &ac);
- mpaddfltflt(&v->real, &bd); // ac+bd
- mpdivfltflt(&v->real, &cc_plus_dd); // (ac+bd)/(cc+dd)
-
- mpmovefltflt(&v->imag, &bc);
- mpsubfltflt(&v->imag, &ad); // bc-ad
- mpdivfltflt(&v->imag, &cc_plus_dd); // (bc+ad)/(cc+dd)
-}
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
deleted file mode 100644
index 890cf7f10..000000000
--- a/src/cmd/gc/cplx.c
+++ /dev/null
@@ -1,479 +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 "gg.h"
-
-static void subnode(Node *nr, Node *ni, Node *nc);
-static void minus(Node *nl, Node *res);
- void complexminus(Node*, Node*);
- void complexadd(int op, Node*, Node*, Node*);
- void complexmul(Node*, Node*, Node*);
-
-#define CASE(a,b) (((a)<<16)|((b)<<0))
-
-static int
-overlap(Node *f, Node *t)
-{
- // check whether f and t could be overlapping stack references.
- // not exact, because it's hard to check for the stack register
- // in portable code. close enough: worst case we will allocate
- // an extra temporary and the registerizer will clean it up.
- return f->op == OINDREG &&
- t->op == OINDREG &&
- f->xoffset+f->type->width >= t->xoffset &&
- t->xoffset+t->type->width >= f->xoffset;
-}
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- */
-void
-complexmove(Node *f, Node *t)
-{
- int ft, tt;
- Node n1, n2, n3, n4;
-
- if(debug['g']) {
- dump("\ncomplexmove-f", f);
- dump("complexmove-t", t);
- }
-
- if(!t->addable)
- fatal("complexmove: to not addable");
-
- ft = simsimtype(f->type);
- tt = simsimtype(t->type);
- switch(CASE(ft,tt)) {
-
- default:
- fatal("complexmove: unknown conversion: %T -> %T\n",
- f->type, t->type);
-
- case CASE(TCOMPLEX64,TCOMPLEX64):
- case CASE(TCOMPLEX64,TCOMPLEX128):
- case CASE(TCOMPLEX128,TCOMPLEX64):
- case CASE(TCOMPLEX128,TCOMPLEX128):
- // complex to complex move/convert.
- // make f addable.
- // also use temporary if possible stack overlap.
- if(!f->addable || overlap(f, t)) {
- tempname(&n1, f->type);
- complexmove(f, &n1);
- f = &n1;
- }
-
- subnode(&n1, &n2, f);
- subnode(&n3, &n4, t);
-
- cgen(&n1, &n3);
- cgen(&n2, &n4);
- break;
- }
-}
-
-int
-complexop(Node *n, Node *res)
-{
- if(n != N && n->type != T)
- if(iscomplex[n->type->etype]) {
- goto maybe;
- }
- if(res != N && res->type != T)
- if(iscomplex[res->type->etype]) {
- goto maybe;
- }
-
- if(n->op == OREAL || n->op == OIMAG)
- goto yes;
-
- goto no;
-
-maybe:
- switch(n->op) {
- case OCONV: // implemented ops
- case OADD:
- case OSUB:
- case OMUL:
- case OMINUS:
- case OCOMPLEX:
- case OREAL:
- case OIMAG:
- goto yes;
-
- case ODOT:
- case ODOTPTR:
- case OINDEX:
- case OIND:
- case ONAME:
- goto yes;
- }
-
-no:
-//dump("\ncomplex-no", n);
- return 0;
-yes:
-//dump("\ncomplex-yes", n);
- return 1;
-}
-
-void
-complexgen(Node *n, Node *res)
-{
- Node *nl, *nr;
- Node tnl, tnr;
- Node n1, n2, tmp;
- int tl, tr;
-
- if(debug['g']) {
- dump("\ncomplexgen-n", n);
- dump("complexgen-res", res);
- }
-
- // pick off float/complex opcodes
- switch(n->op) {
- case OCOMPLEX:
- if(res->addable) {
- subnode(&n1, &n2, res);
- tempname(&tmp, n1.type);
- cgen(n->left, &tmp);
- cgen(n->right, &n2);
- cgen(&tmp, &n1);
- return;
- }
- break;
-
- case OREAL:
- case OIMAG:
- nl = n->left;
- if(!nl->addable) {
- tempname(&tmp, nl->type);
- complexgen(nl, &tmp);
- nl = &tmp;
- }
- subnode(&n1, &n2, nl);
- if(n->op == OREAL) {
- cgen(&n1, res);
- return;
- }
- cgen(&n2, res);
- return;
- }
-
- // perform conversion from n to res
- tl = simsimtype(res->type);
- tl = cplxsubtype(tl);
- tr = simsimtype(n->type);
- tr = cplxsubtype(tr);
- if(tl != tr) {
- if(!n->addable) {
- tempname(&n1, n->type);
- complexmove(n, &n1);
- n = &n1;
- }
- complexmove(n, res);
- return;
- }
-
- if(!res->addable) {
- igen(res, &n1, N);
- cgen(n, &n1);
- regfree(&n1);
- return;
- }
- if(n->addable) {
- complexmove(n, res);
- return;
- }
-
- switch(n->op) {
- default:
- dump("complexgen: unknown op", n);
- fatal("complexgen: unknown op %O", n->op);
-
- case ODOT:
- case ODOTPTR:
- case OINDEX:
- case OIND:
- case ONAME: // PHEAP or PPARAMREF var
- case OCALLFUNC:
- igen(n, &n1, res);
- complexmove(&n1, res);
- regfree(&n1);
- return;
-
- case OCONV:
- case OADD:
- case OSUB:
- case OMUL:
- case OMINUS:
- case OCOMPLEX:
- case OREAL:
- case OIMAG:
- break;
- }
-
- nl = n->left;
- if(nl == N)
- return;
- nr = n->right;
-
- // make both sides addable in ullman order
- if(nr != N) {
- if(nl->ullman > nr->ullman && !nl->addable) {
- tempname(&tnl, nl->type);
- cgen(nl, &tnl);
- nl = &tnl;
- }
- if(!nr->addable) {
- tempname(&tnr, nr->type);
- cgen(nr, &tnr);
- nr = &tnr;
- }
- }
- if(!nl->addable) {
- tempname(&tnl, nl->type);
- cgen(nl, &tnl);
- nl = &tnl;
- }
-
- switch(n->op) {
- default:
- fatal("complexgen: unknown op %O", n->op);
- break;
-
- case OCONV:
- complexmove(nl, res);
- break;
-
- case OMINUS:
- complexminus(nl, res);
- break;
-
- case OADD:
- case OSUB:
- complexadd(n->op, nl, nr, res);
- break;
-
- case OMUL:
- complexmul(nl, nr, res);
- break;
- }
-}
-
-void
-complexbool(int op, Node *nl, Node *nr, int true, Prog *to)
-{
- Node tnl, tnr;
- Node n1, n2, n3, n4;
- Node na, nb, nc;
-
- // make both sides addable in ullman order
- if(nr != N) {
- if(nl->ullman > nr->ullman && !nl->addable) {
- tempname(&tnl, nl->type);
- cgen(nl, &tnl);
- nl = &tnl;
- }
- if(!nr->addable) {
- tempname(&tnr, nr->type);
- cgen(nr, &tnr);
- nr = &tnr;
- }
- }
- if(!nl->addable) {
- tempname(&tnl, nl->type);
- cgen(nl, &tnl);
- nl = &tnl;
- }
-
- // build tree
- // real(l) == real(r) && imag(l) == imag(r)
-
- subnode(&n1, &n2, nl);
- subnode(&n3, &n4, nr);
-
- memset(&na, 0, sizeof(na));
- na.op = OANDAND;
- na.left = &nb;
- na.right = &nc;
- na.type = types[TBOOL];
-
- memset(&nb, 0, sizeof(na));
- nb.op = OEQ;
- nb.left = &n1;
- nb.right = &n3;
- nb.type = types[TBOOL];
-
- memset(&nc, 0, sizeof(na));
- nc.op = OEQ;
- nc.left = &n2;
- nc.right = &n4;
- nc.type = types[TBOOL];
-
- if(op == ONE)
- true = !true;
-
- bgen(&na, true, to);
-}
-
-void
-nodfconst(Node *n, Type *t, Mpflt* fval)
-{
- memset(n, 0, sizeof(*n));
- n->op = OLITERAL;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.fval = fval;
- n->val.ctype = CTFLT;
- n->type = t;
-
- if(!isfloat[t->etype])
- fatal("nodfconst: bad type %T", t);
-}
-
-// break addable nc-complex into nr-real and ni-imaginary
-static void
-subnode(Node *nr, Node *ni, Node *nc)
-{
- int tc;
- Type *t;
-
- if(!nc->addable)
- fatal("subnode not addable");
-
- tc = simsimtype(nc->type);
- tc = cplxsubtype(tc);
- t = types[tc];
-
- if(nc->op == OLITERAL) {
- nodfconst(nr, t, &nc->val.u.cval->real);
- nodfconst(ni, t, &nc->val.u.cval->imag);
- return;
- }
-
- *nr = *nc;
- nr->type = t;
-
- *ni = *nc;
- ni->type = t;
- ni->xoffset += t->width;
-}
-
-// generate code res = -nl
-static void
-minus(Node *nl, Node *res)
-{
- Node ra;
-
- memset(&ra, 0, sizeof(ra));
- ra.op = OMINUS;
- ra.left = nl;
- ra.type = nl->type;
- cgen(&ra, res);
-}
-
-// build and execute tree
-// real(res) = -real(nl)
-// imag(res) = -imag(nl)
-void
-complexminus(Node *nl, Node *res)
-{
- Node n1, n2, n5, n6;
-
- subnode(&n1, &n2, nl);
- subnode(&n5, &n6, res);
-
- minus(&n1, &n5);
- minus(&n2, &n6);
-}
-
-
-// build and execute tree
-// real(res) = real(nl) op real(nr)
-// imag(res) = imag(nl) op imag(nr)
-void
-complexadd(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, n4, n5, n6;
- Node ra;
-
- subnode(&n1, &n2, nl);
- subnode(&n3, &n4, nr);
- subnode(&n5, &n6, res);
-
- memset(&ra, 0, sizeof(ra));
- ra.op = op;
- ra.left = &n1;
- ra.right = &n3;
- ra.type = n1.type;
- cgen(&ra, &n5);
-
- memset(&ra, 0, sizeof(ra));
- ra.op = op;
- ra.left = &n2;
- ra.right = &n4;
- ra.type = n2.type;
- cgen(&ra, &n6);
-}
-
-// build and execute tree
-// tmp = real(nl)*real(nr) - imag(nl)*imag(nr)
-// imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
-// real(res) = tmp
-void
-complexmul(Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, n4, n5, n6;
- Node rm1, rm2, ra, tmp;
-
- subnode(&n1, &n2, nl);
- subnode(&n3, &n4, nr);
- subnode(&n5, &n6, res);
- tempname(&tmp, n5.type);
-
- // real part -> tmp
- memset(&rm1, 0, sizeof(ra));
- rm1.op = OMUL;
- rm1.left = &n1;
- rm1.right = &n3;
- rm1.type = n1.type;
-
- memset(&rm2, 0, sizeof(ra));
- rm2.op = OMUL;
- rm2.left = &n2;
- rm2.right = &n4;
- rm2.type = n2.type;
-
- memset(&ra, 0, sizeof(ra));
- ra.op = OSUB;
- ra.left = &rm1;
- ra.right = &rm2;
- ra.type = rm1.type;
- cgen(&ra, &tmp);
-
- // imag part
- memset(&rm1, 0, sizeof(ra));
- rm1.op = OMUL;
- rm1.left = &n1;
- rm1.right = &n4;
- rm1.type = n1.type;
-
- memset(&rm2, 0, sizeof(ra));
- rm2.op = OMUL;
- rm2.left = &n2;
- rm2.right = &n3;
- rm2.type = n2.type;
-
- memset(&ra, 0, sizeof(ra));
- ra.op = OADD;
- ra.left = &rm1;
- ra.right = &rm2;
- ra.type = rm1.type;
- cgen(&ra, &n6);
-
- // tmp ->real part
- cgen(&tmp, &n5);
-}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
deleted file mode 100644
index 7290f9d3b..000000000
--- a/src/cmd/gc/dcl.c
+++ /dev/null
@@ -1,1248 +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 "go.h"
-#include "y.tab.h"
-
-static void funcargs(Node*);
-
-static int
-dflag(void)
-{
- if(!debug['d'])
- return 0;
- if(debug['y'])
- return 1;
- if(incannedimport)
- return 0;
- return 1;
-}
-
-/*
- * declaration stack & operations
- */
-
-static void
-dcopy(Sym *a, Sym *b)
-{
- a->pkg = b->pkg;
- a->name = b->name;
- a->def = b->def;
- a->block = b->block;
- a->lastlineno = b->lastlineno;
-}
-
-static Sym*
-push(void)
-{
- Sym *d;
-
- d = mal(sizeof(*d));
- d->lastlineno = lineno;
- d->link = dclstack;
- dclstack = d;
- return d;
-}
-
-static Sym*
-pushdcl(Sym *s)
-{
- Sym *d;
-
- d = push();
- dcopy(d, s);
- if(dflag())
- print("\t%L push %S %p\n", lineno, s, s->def);
- return d;
-}
-
-void
-popdcl(void)
-{
- Sym *d, *s;
- int lno;
-
-// if(dflag())
-// print("revert\n");
-
- for(d=dclstack; d!=S; d=d->link) {
- if(d->name == nil)
- break;
- s = pkglookup(d->name, d->pkg);
- lno = s->lastlineno;
- dcopy(s, d);
- d->lastlineno = lno;
- if(dflag())
- print("\t%L pop %S %p\n", lineno, s, s->def);
- }
- if(d == S)
- fatal("popdcl: no mark");
- dclstack = d->link;
- block = d->block;
-}
-
-void
-poptodcl(void)
-{
- // pop the old marker and push a new one
- // (cannot reuse the existing one)
- // because we use the markers to identify blocks
- // for the goto restriction checks.
- popdcl();
- markdcl();
-}
-
-void
-markdcl(void)
-{
- Sym *d;
-
- d = push();
- d->name = nil; // used as a mark in fifo
- d->block = block;
-
- blockgen++;
- block = blockgen;
-
-// if(dflag())
-// print("markdcl\n");
-}
-
-void
-dumpdcl(char *st)
-{
- Sym *s, *d;
- int i;
-
- i = 0;
- for(d=dclstack; d!=S; d=d->link) {
- i++;
- print(" %.2d %p", i, d);
- if(d->name == nil) {
- print("\n");
- continue;
- }
- print(" '%s'", d->name);
- s = pkglookup(d->name, d->pkg);
- print(" %lS\n", s);
- }
-}
-
-void
-testdclstack(void)
-{
- Sym *d;
-
- for(d=dclstack; d!=S; d=d->link) {
- if(d->name == nil) {
- yyerror("mark left on the stack");
- continue;
- }
- }
-}
-
-void
-redeclare(Sym *s, char *where)
-{
- if(s->lastlineno == 0)
- yyerror("%S redeclared %s\n"
- "\tprevious declaration during import",
- s, where);
- else
- yyerror("%S redeclared %s\n"
- "\tprevious declaration at %L",
- s, where, s->lastlineno);
-}
-
-/*
- * declare individual names - var, typ, const
- */
-void
-declare(Node *n, int ctxt)
-{
- Sym *s;
- int gen;
- static int typegen, vargen;
-
- if(isblank(n))
- return;
-
- n->lineno = parserline();
- s = n->sym;
- gen = 0;
- if(ctxt == PEXTERN) {
- externdcl = list(externdcl, n);
- if(dflag())
- print("\t%L global decl %S %p\n", lineno, s, n);
- } else {
- if(curfn == nil && ctxt == PAUTO)
- fatal("automatic outside function");
- if(curfn != nil)
- curfn->dcl = list(curfn->dcl, n);
- if(n->op == OTYPE)
- gen = ++typegen;
- else if(n->op == ONAME)
- gen = ++vargen;
- pushdcl(s);
- n->curfn = curfn;
- }
- if(ctxt == PAUTO)
- n->xoffset = BADWIDTH;
-
- if(s->block == block)
- redeclare(s, "in this block");
-
- s->block = block;
- s->lastlineno = parserline();
- s->def = n;
- n->vargen = gen;
- n->funcdepth = funcdepth;
- n->class = ctxt;
-
- autoexport(n, ctxt);
-}
-
-void
-addvar(Node *n, Type *t, int ctxt)
-{
- if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T)
- fatal("addvar: n=%N t=%T nil", n, t);
-
- n->op = ONAME;
- declare(n, ctxt);
- n->type = t;
-}
-
-/*
- * declare variables from grammar
- * new_name_list (type | [type] = expr_list)
- */
-NodeList*
-variter(NodeList *vl, Node *t, NodeList *el)
-{
- int doexpr;
- Node *v, *e, *as2;
- NodeList *init;
-
- init = nil;
- doexpr = el != nil;
-
- if(count(el) == 1 && count(vl) > 1) {
- e = el->n;
- as2 = nod(OAS2, N, N);
- as2->list = vl;
- as2->rlist = list1(e);
- for(; vl; vl=vl->next) {
- v = vl->n;
- v->op = ONAME;
- declare(v, dclcontext);
- v->ntype = t;
- v->defn = as2;
- if(funcdepth > 0)
- init = list(init, nod(ODCL, v, N));
- }
- return list(init, as2);
- }
-
- for(; vl; vl=vl->next) {
- if(doexpr) {
- if(el == nil) {
- yyerror("missing expr in var dcl");
- break;
- }
- e = el->n;
- el = el->next;
- } else
- e = N;
-
- v = vl->n;
- v->op = ONAME;
- declare(v, dclcontext);
- v->ntype = t;
-
- if(e != N || funcdepth > 0 || isblank(v)) {
- if(funcdepth > 0)
- init = list(init, nod(ODCL, v, N));
- e = nod(OAS, v, e);
- init = list(init, e);
- if(e->right != N)
- v->defn = e;
- }
- }
- if(el != nil)
- yyerror("extra expr in var dcl");
- return init;
-}
-
-/*
- * declare constants from grammar
- * new_name_list [[type] = expr_list]
- */
-NodeList*
-constiter(NodeList *vl, Node *t, NodeList *cl)
-{
- Node *v, *c;
- NodeList *vv;
-
- vv = nil;
- if(cl == nil) {
- if(t != N)
- yyerror("constdcl cannot have type without expr");
- cl = lastconst;
- t = lasttype;
- } else {
- lastconst = cl;
- lasttype = t;
- }
- cl = listtreecopy(cl);
-
- for(; vl; vl=vl->next) {
- if(cl == nil) {
- yyerror("missing expr in const dcl");
- break;
- }
- c = cl->n;
- cl = cl->next;
-
- v = vl->n;
- v->op = OLITERAL;
- declare(v, dclcontext);
-
- v->ntype = t;
- v->defn = c;
-
- vv = list(vv, nod(ODCLCONST, v, N));
- }
- if(cl != nil)
- yyerror("extra expr in const dcl");
- iota += 1;
- return vv;
-}
-
-/*
- * this generates a new name node,
- * typically for labels or other one-off names.
- */
-Node*
-newname(Sym *s)
-{
- Node *n;
-
- if(s == S)
- fatal("newname nil");
-
- n = nod(ONAME, N, N);
- n->sym = s;
- n->type = T;
- n->addable = 1;
- n->ullman = 1;
- n->xoffset = 0;
- return n;
-}
-
-/*
- * this generates a new name node for a name
- * being declared.
- */
-Node*
-dclname(Sym *s)
-{
- Node *n;
-
- n = newname(s);
- n->op = ONONAME; // caller will correct it
- return n;
-}
-
-Node*
-typenod(Type *t)
-{
- // if we copied another type with *t = *u
- // then t->nod might be out of date, so
- // check t->nod->type too
- if(t->nod == N || t->nod->type != t) {
- t->nod = nod(OTYPE, N, N);
- t->nod->type = t;
- t->nod->sym = t->sym;
- }
- return t->nod;
-}
-
-
-/*
- * this will return an old name
- * that has already been pushed on the
- * declaration list. a diagnostic is
- * generated if no name has been defined.
- */
-Node*
-oldname(Sym *s)
-{
- Node *n;
- Node *c;
-
- n = s->def;
- if(n == N) {
- // maybe a top-level name will come along
- // to give this a definition later.
- // walkdef will check s->def again once
- // all the input source has been processed.
- n = newname(s);
- n->op = ONONAME;
- n->iota = iota; // save current iota value in const declarations
- }
- if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
- // inner func is referring to var in outer func.
- //
- // TODO(rsc): If there is an outer variable x and we
- // are parsing x := 5 inside the closure, until we get to
- // the := it looks like a reference to the outer x so we'll
- // make x a closure variable unnecessarily.
- if(n->closure == N || n->closure->funcdepth != funcdepth) {
- // create new closure var.
- c = nod(ONAME, N, N);
- c->sym = s;
- c->class = PPARAMREF;
- c->isddd = n->isddd;
- c->defn = n;
- c->addable = 0;
- c->ullman = 2;
- c->funcdepth = funcdepth;
- c->outer = n->closure;
- n->closure = c;
- c->closure = n;
- c->xoffset = 0;
- curfn->cvars = list(curfn->cvars, c);
- }
- // return ref to closure var, not original
- return n->closure;
- }
- return n;
-}
-
-/*
- * same for types
- */
-Type*
-newtype(Sym *s)
-{
- Type *t;
-
- t = typ(TFORW);
- t->sym = s;
- t->type = T;
- return t;
-}
-
-
-/*
- * := declarations
- */
-
-static int
-colasname(Node *n)
-{
- switch(n->op) {
- case ONAME:
- case ONONAME:
- case OPACK:
- case OTYPE:
- case OLITERAL:
- return n->sym != S;
- }
- return 0;
-}
-
-void
-colasdefn(NodeList *left, Node *defn)
-{
- int nnew;
- NodeList *l;
- Node *n;
-
- nnew = 0;
- for(l=left; l; l=l->next) {
- n = l->n;
- if(isblank(n))
- continue;
- if(!colasname(n)) {
- yyerror("non-name %#N on left side of :=", n);
- continue;
- }
- if(n->sym->block == block)
- continue;
-
- nnew++;
- n = newname(n->sym);
- declare(n, dclcontext);
- n->defn = defn;
- defn->ninit = list(defn->ninit, nod(ODCL, n, N));
- l->n = n;
- }
- if(nnew == 0)
- yyerror("no new variables on left side of :=");
-}
-
-Node*
-colas(NodeList *left, NodeList *right)
-{
- Node *as;
-
- as = nod(OAS2, N, N);
- as->list = left;
- as->rlist = right;
- as->colas = 1;
- colasdefn(left, as);
-
- // make the tree prettier; not necessary
- if(count(left) == 1 && count(right) == 1) {
- as->left = as->list->n;
- as->right = as->rlist->n;
- as->list = nil;
- as->rlist = nil;
- as->op = OAS;
- }
-
- return as;
-}
-
-/*
- * declare the arguments in an
- * interface field declaration.
- */
-void
-ifacedcl(Node *n)
-{
- if(n->op != ODCLFIELD || n->right == N)
- fatal("ifacedcl");
-
- dclcontext = PAUTO;
- markdcl();
- funcdepth++;
- n->outer = curfn;
- curfn = n;
- funcargs(n->right);
-
- // funcbody is normally called after the parser has
- // seen the body of a function but since an interface
- // field declaration does not have a body, we must
- // call it now to pop the current declaration context.
- funcbody(n);
-}
-
-/*
- * declare the function proper
- * and declare the arguments.
- * called in extern-declaration context
- * returns in auto-declaration context.
- */
-void
-funchdr(Node *n)
-{
-
- if(n->nname != N) {
- n->nname->op = ONAME;
- declare(n->nname, PFUNC);
- n->nname->defn = n;
- }
-
- // change the declaration context from extern to auto
- if(funcdepth == 0 && dclcontext != PEXTERN)
- fatal("funchdr: dclcontext");
-
- dclcontext = PAUTO;
- markdcl();
- funcdepth++;
-
- n->outer = curfn;
- curfn = n;
- if(n->nname)
- funcargs(n->nname->ntype);
- else
- funcargs(n->ntype);
-}
-
-static void
-funcargs(Node *nt)
-{
- Node *n;
- NodeList *l;
- int gen;
-
- if(nt->op != OTFUNC)
- fatal("funcargs %O", nt->op);
-
- // declare the receiver and in arguments.
- // no n->defn because type checking of func header
- // will fill in the types before we can demand them.
- if(nt->left != N) {
- n = nt->left;
- if(n->op != ODCLFIELD)
- fatal("funcargs1 %O", n->op);
- if(n->left != N) {
- n->left->op = ONAME;
- n->left->ntype = n->right;
- declare(n->left, PPARAM);
- }
- }
- for(l=nt->list; l; l=l->next) {
- n = l->n;
- if(n->op != ODCLFIELD)
- fatal("funcargs2 %O", n->op);
- if(n->left != N) {
- n->left->op = ONAME;
- n->left->ntype = n->right;
- declare(n->left, PPARAM);
- }
- }
-
- // declare the out arguments.
- gen = 0;
- for(l=nt->rlist; l; l=l->next) {
- n = l->n;
- if(n->op != ODCLFIELD)
- fatal("funcargs3 %O", n->op);
- if(n->left != N) {
- n->left->op = ONAME;
- n->left->ntype = n->right;
- if(isblank(n->left)) {
- // Give it a name so we can assign to it during return.
- snprint(namebuf, sizeof(namebuf), ".anon%d", gen++);
- n->left->sym = lookup(namebuf);
- }
- declare(n->left, PPARAMOUT);
- }
- }
-}
-
-/*
- * finish the body.
- * called in auto-declaration context.
- * returns in extern-declaration context.
- */
-void
-funcbody(Node *n)
-{
- // change the declaration context from auto to extern
- if(dclcontext != PAUTO)
- fatal("funcbody: dclcontext");
- popdcl();
- funcdepth--;
- curfn = n->outer;
- n->outer = N;
- if(funcdepth == 0)
- dclcontext = PEXTERN;
-}
-
-/*
- * new type being defined with name s.
- */
-Node*
-typedcl0(Sym *s)
-{
- Node *n;
-
- n = dclname(s);
- n->op = OTYPE;
- declare(n, dclcontext);
- return n;
-}
-
-/*
- * node n, which was returned by typedcl0
- * is being declared to have uncompiled type t.
- * return the ODCLTYPE node to use.
- */
-Node*
-typedcl1(Node *n, Node *t, int local)
-{
- n->ntype = t;
- n->local = local;
- return nod(ODCLTYPE, n, N);
-}
-
-/*
- * typedcl1 but during imports
- */
-void
-typedcl2(Type *pt, Type *t)
-{
- Node *n;
-
- // override declaration in unsafe.go for Pointer.
- // there is no way in Go code to define unsafe.Pointer
- // so we have to supply it.
- if(incannedimport &&
- strcmp(importpkg->name, "unsafe") == 0 &&
- strcmp(pt->nod->sym->name, "Pointer") == 0) {
- t = types[TUNSAFEPTR];
- }
-
- if(pt->etype == TFORW)
- goto ok;
- if(!eqtype(pt->orig, t))
- yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t);
- return;
-
-ok:
- n = pt->nod;
- copytype(pt->nod, t);
- // unzero nod
- pt->nod = n;
-
- pt->sym->lastlineno = parserline();
- declare(n, PEXTERN);
-
- checkwidth(pt);
-}
-
-/*
- * structs, functions, and methods.
- * they don't belong here, but where do they belong?
- */
-
-
-/*
- * turn a parsed struct into a type
- */
-static Type**
-stotype(NodeList *l, int et, Type **t, int funarg)
-{
- Type *f, *t1, *t2, **t0;
- Strlit *note;
- int lno;
- Node *n, *left;
- char *what;
-
- t0 = t;
- lno = lineno;
- what = "field";
- if(et == TINTER)
- what = "method";
-
- for(; l; l=l->next) {
- n = l->n;
- lineno = n->lineno;
- note = nil;
-
- if(n->op != ODCLFIELD)
- fatal("stotype: oops %N\n", n);
- left = n->left;
- if(funarg && isblank(left))
- left = N;
- if(n->right != N) {
- if(et == TINTER && left != N) {
- // queue resolution of method type for later.
- // right now all we need is the name list.
- // avoids cycles for recursive interface types.
- n->type = typ(TINTERMETH);
- n->type->nname = n->right;
- n->right = N;
- left->type = n->type;
- queuemethod(n);
- } else {
- typecheck(&n->right, Etype);
- n->type = n->right->type;
- if(n->type == T) {
- *t0 = T;
- return t0;
- }
- if(left != N)
- left->type = n->type;
- n->right = N;
- if(n->embedded && n->type != T) {
- t1 = n->type;
- if(t1->sym == S && isptr[t1->etype]) {
- t1 = t1->type;
- if(t1->etype == TINTER)
- yyerror("embedded type cannot be a pointer to interface");
- }
- if(isptr[t1->etype])
- yyerror("embedded type cannot be a pointer");
- else if(t1->etype == TFORW && t1->embedlineno == 0)
- t1->embedlineno = lineno;
- }
- }
- }
-
- if(n->type == T) {
- // assume error already printed
- continue;
- }
-
- switch(n->val.ctype) {
- case CTSTR:
- if(et != TSTRUCT)
- yyerror("interface method cannot have annotation");
- note = n->val.u.sval;
- break;
- default:
- if(et != TSTRUCT)
- yyerror("interface method cannot have annotation");
- else
- yyerror("field annotation must be string");
- case CTxxx:
- note = nil;
- break;
- }
-
- if(et == TINTER && left == N) {
- // embedded interface - inline the methods
- if(n->type->etype != TINTER) {
- if(n->type->etype == TFORW)
- yyerror("interface type loop involving %T", n->type);
- else
- yyerror("interface contains embedded non-interface %T", n->type);
- continue;
- }
- for(t1=n->type->type; t1!=T; t1=t1->down) {
- f = typ(TFIELD);
- f->type = t1->type;
- f->width = BADWIDTH;
- f->nname = newname(t1->sym);
- f->sym = t1->sym;
- for(t2=*t0; t2!=T; t2=t2->down) {
- if(t2->sym == f->sym) {
- yyerror("duplicate method %s", t2->sym->name);
- break;
- }
- }
- *t = f;
- t = &f->down;
- }
- continue;
- }
-
- f = typ(TFIELD);
- f->type = n->type;
- f->note = note;
- f->width = BADWIDTH;
- f->isddd = n->isddd;
-
- if(left != N && left->op == ONAME) {
- f->nname = left;
- f->embedded = n->embedded;
- f->sym = f->nname->sym;
- if(importpkg && !exportname(f->sym->name))
- f->sym = pkglookup(f->sym->name, structpkg);
- if(f->sym && !isblank(f->nname)) {
- for(t1=*t0; t1!=T; t1=t1->down) {
- if(t1->sym == f->sym) {
- yyerror("duplicate %s %s", what, t1->sym->name);
- break;
- }
- }
- }
- }
-
- *t = f;
- t = &f->down;
- }
-
- *t = T;
- lineno = lno;
- return t;
-}
-
-Type*
-dostruct(NodeList *l, int et)
-{
- Type *t;
- int funarg;
-
- /*
- * convert a parsed id/type list into
- * a type for struct/interface/arglist
- */
-
- funarg = 0;
- if(et == TFUNC) {
- funarg = 1;
- et = TSTRUCT;
- }
- t = typ(et);
- t->funarg = funarg;
- stotype(l, et, &t->type, funarg);
- if(t->type == T && l != nil) {
- t->broke = 1;
- return t;
- }
- if(et == TINTER)
- t = sortinter(t);
- if(!funarg)
- checkwidth(t);
- return t;
-}
-
-
-Node*
-embedded(Sym *s)
-{
- Node *n;
- char *name;
-
- // Names sometimes have disambiguation junk
- // appended after a center dot. Discard it when
- // making the name for the embedded struct field.
- enum { CenterDot = 0xB7 };
- name = s->name;
- if(utfrune(s->name, CenterDot)) {
- name = strdup(s->name);
- *utfrune(name, CenterDot) = 0;
- }
-
- n = newname(lookup(name));
- n = nod(ODCLFIELD, n, oldname(s));
- n->embedded = 1;
- return n;
-}
-
-/*
- * check that the list of declarations is either all anonymous or all named
- */
-
-static Node*
-findtype(NodeList *l)
-{
- for(; l; l=l->next)
- if(l->n->op == OKEY)
- return l->n->right;
- return N;
-}
-
-NodeList*
-checkarglist(NodeList *all, int input)
-{
- int named;
- Node *n, *t, *nextt;
- NodeList *l;
-
- named = 0;
- for(l=all; l; l=l->next) {
- if(l->n->op == OKEY) {
- named = 1;
- break;
- }
- }
- if(named) {
- n = N;
- for(l=all; l; l=l->next) {
- n = l->n;
- if(n->op != OKEY && n->sym == S) {
- yyerror("mixed named and unnamed function parameters");
- break;
- }
- }
- if(l == nil && n != N && n->op != OKEY)
- yyerror("final function parameter must have type");
- }
-
- nextt = nil;
- for(l=all; l; l=l->next) {
- // can cache result from findtype to avoid
- // quadratic behavior here, but unlikely to matter.
- n = l->n;
- if(named) {
- if(n->op == OKEY) {
- t = n->right;
- n = n->left;
- nextt = nil;
- } else {
- if(nextt == nil)
- nextt = findtype(l);
- t = nextt;
- }
- } else {
- t = n;
- n = N;
- }
- if(n != N && n->sym == S) {
- t = n;
- n = N;
- }
- if(n != N)
- n = newname(n->sym);
- n = nod(ODCLFIELD, n, t);
- if(n->right != N && n->right->op == ODDD) {
- if(!input)
- yyerror("cannot use ... in output argument list");
- else if(l->next != nil)
- yyerror("can only use ... as final argument in list");
- n->right->op = OTARRAY;
- n->right->right = n->right->left;
- n->right->left = N;
- n->isddd = 1;
- if(n->left != N)
- n->left->isddd = 1;
- }
- l->n = n;
- }
- return all;
-}
-
-
-Node*
-fakethis(void)
-{
- Node *n;
-
- n = nod(ODCLFIELD, N, typenod(ptrto(typ(TSTRUCT))));
- return n;
-}
-
-/*
- * Is this field a method on an interface?
- * Those methods have an anonymous
- * *struct{} as the receiver.
- * (See fakethis above.)
- */
-int
-isifacemethod(Type *f)
-{
- Type *rcvr;
- Type *t;
-
- rcvr = getthisx(f)->type;
- if(rcvr->sym != S)
- return 0;
- t = rcvr->type;
- if(!isptr[t->etype])
- return 0;
- t = t->type;
- if(t->sym != S || t->etype != TSTRUCT || t->type != T)
- return 0;
- return 1;
-}
-
-/*
- * turn a parsed function declaration
- * into a type
- */
-Type*
-functype(Node *this, NodeList *in, NodeList *out)
-{
- Type *t;
- NodeList *rcvr;
-
- t = typ(TFUNC);
-
- rcvr = nil;
- if(this)
- rcvr = list1(this);
- t->type = dostruct(rcvr, TFUNC);
- t->type->down = dostruct(out, TFUNC);
- t->type->down->down = dostruct(in, TFUNC);
-
- if(this)
- t->thistuple = 1;
- t->outtuple = count(out);
- t->intuple = count(in);
- t->outnamed = t->outtuple > 0 && out->n->left != N;
-
- return t;
-}
-
-Sym*
-methodsym(Sym *nsym, Type *t0, int iface)
-{
- Sym *s;
- char *p;
- Type *t;
- char *suffix;
-
- t = t0;
- if(t == T)
- goto bad;
- s = t->sym;
- if(s == S) {
- if(!isptr[t->etype])
- goto bad;
- t = t->type;
- if(t == T)
- goto bad;
- s = t->sym;
- if(s == S)
- goto bad;
- }
-
- // if t0 == *t and t0 has a sym,
- // we want to see *t, not t0, in the method name.
- if(t != t0 && t0->sym)
- t0 = ptrto(t);
-
- suffix = "";
- if(iface) {
- dowidth(t0);
- if(t0->width < types[tptr]->width)
- suffix = "·i";
- }
- p = smprint("%#hT·%s%s", t0, nsym->name, suffix);
- s = pkglookup(p, s->pkg);
- free(p);
- return s;
-
-bad:
- yyerror("illegal receiver type: %T", t0);
- return S;
-}
-
-Node*
-methodname(Node *n, Type *t)
-{
- Sym *s;
-
- s = methodsym(n->sym, t, 0);
- if(s == S)
- return n;
- return newname(s);
-}
-
-Node*
-methodname1(Node *n, Node *t)
-{
- char *star;
- char *p;
-
- star = "";
- if(t->op == OIND) {
- star = "*";
- t = t->left;
- }
- if(t->sym == S || isblank(n))
- return newname(n->sym);
- p = smprint("%s%S·%S", star, t->sym, n->sym);
- n = newname(pkglookup(p, t->sym->pkg));
- free(p);
- return n;
-}
-
-/*
- * add a method, declared as a function,
- * n is fieldname, pa is base type, t is function type
- */
-void
-addmethod(Sym *sf, Type *t, int local)
-{
- Type *f, *d, *pa;
- Node *n;
-
- pa = nil;
-
- // get field sym
- if(sf == S)
- fatal("no method symbol");
-
- // get parent type sym
- pa = getthisx(t)->type; // ptr to this structure
- if(pa == T) {
- yyerror("missing receiver");
- return;
- }
-
- pa = pa->type;
- f = methtype(pa);
- if(f == T) {
- t = pa;
- if(t != T) {
- if(isptr[t->etype]) {
- if(t->sym != S) {
- yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
- return;
- }
- t = t->type;
- }
- }
- if(t != T) {
- if(t->sym == S) {
- yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t);
- return;
- }
- if(isptr[t->etype]) {
- yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
- return;
- }
- if(t->etype == TINTER) {
- yyerror("invalid receiver type %T (%T is an interface type)", pa, t);
- return;
- }
- }
- // Should have picked off all the reasons above,
- // but just in case, fall back to generic error.
- yyerror("invalid receiver type %T", pa);
- return;
- }
-
- pa = f;
- if(importpkg && !exportname(sf->name))
- sf = pkglookup(sf->name, importpkg);
-
- n = nod(ODCLFIELD, newname(sf), N);
- n->type = t;
-
- d = T; // last found
- for(f=pa->method; f!=T; f=f->down) {
- d = f;
- if(f->etype != TFIELD)
- fatal("addmethod: not TFIELD: %N", f);
- if(strcmp(sf->name, f->sym->name) != 0)
- continue;
- if(!eqtype(t, f->type))
- yyerror("method redeclared: %T.%S\n\t%T\n\t%T", pa, sf, f->type, t);
- return;
- }
-
- if(local && !pa->local) {
- // defining method on non-local type.
- yyerror("cannot define new methods on non-local type %T", pa);
- return;
- }
-
- if(d == T)
- stotype(list1(n), 0, &pa->method, 0);
- else
- stotype(list1(n), 0, &d->down, 0);
- return;
-}
-
-void
-funccompile(Node *n, int isclosure)
-{
- stksize = BADWIDTH;
- maxarg = 0;
-
- if(n->type == T) {
- if(nerrors == 0)
- fatal("funccompile missing type");
- return;
- }
-
- // assign parameter offsets
- checkwidth(n->type);
-
- // record offset to actual frame pointer.
- // for closure, have to skip over leading pointers and PC slot.
- nodfp->xoffset = 0;
- if(isclosure) {
- NodeList *l;
- for(l=n->nname->ntype->list; l; l=l->next) {
- nodfp->xoffset += widthptr;
- if(l->n->left == N) // found slot for PC
- break;
- }
- }
-
- if(curfn)
- fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym);
-
- stksize = 0;
- dclcontext = PAUTO;
- funcdepth = n->funcdepth + 1;
- compile(n);
- curfn = nil;
- funcdepth = 0;
- dclcontext = PEXTERN;
-}
-
-
-
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
deleted file mode 100644
index 3fe7fafdd..000000000
--- a/src/cmd/gc/doc.go
+++ /dev/null
@@ -1,55 +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.
-
-/*
-
-Gc is the generic label for the family of Go compilers
-that function as part of the (modified) Plan 9 tool chain. The C compiler
-documentation at
-
- http://plan9.bell-labs.com/sys/doc/comp.pdf (Tools overview)
- http://plan9.bell-labs.com/sys/doc/compiler.pdf (C compiler architecture)
-
-gives the overall design of the tool chain. Aside from a few adapted pieces,
-such as the optimizer, the Go compilers are wholly new programs.
-
-The compiler reads in a set of Go files, typically suffixed ".go". They
-must all be part of one package. The output is a single intermediate file
-representing the "binary assembly" of the compiled package, ready as input
-for the linker (6l, etc.).
-
-The generated files contain type information about the symbols exported by
-the package and about types used by symbols imported by the package from
-other packages. It is therefore not necessary when compiling client C of
-package P to read the files of P's dependencies, only the compiled output
-of P.
-
-Usage:
- 6g [flags] file...
-The specified files must be Go source files and all part of the same package.
-Substitute 6g with 8g or 5g where appropriate.
-
-Flags:
- -o file
- output file, default file.6 for 6g, etc.
- -e
- normally the compiler quits after 10 errors; -e prints all errors
- -L
- show entire file path when printing line numbers in errors
- -I dir1 -I dir2
- add dir1 and dir2 to the list of paths to check for imported packages
- -N
- disable optimization
- -S
- write assembly language text to standard output
- -u
- disallow importing packages not marked as safe
- -V
- print the compiler version
-
-There are also a number of debugging flags; run the command with no arguments
-to get a usage message.
-
-*/
-package documentation
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
deleted file mode 100644
index 014f0c5f0..000000000
--- a/src/cmd/gc/export.c
+++ /dev/null
@@ -1,428 +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 "go.h"
-#include "y.tab.h"
-
-static void dumpsym(Sym*);
-static void dumpexporttype(Sym*);
-static void dumpexportvar(Sym*);
-static void dumpexportconst(Sym*);
-
-void
-exportsym(Node *n)
-{
- if(n == N || n->sym == S)
- return;
- if(n->sym->flags & (SymExport|SymPackage)) {
- if(n->sym->flags & SymPackage)
- yyerror("export/package mismatch: %S", n->sym);
- return;
- }
- n->sym->flags |= SymExport;
-
- exportlist = list(exportlist, n);
-}
-
-static void
-packagesym(Node *n)
-{
- if(n == N || n->sym == S)
- return;
- if(n->sym->flags & (SymExport|SymPackage)) {
- if(n->sym->flags & SymExport)
- yyerror("export/package mismatch: %S", n->sym);
- return;
- }
- n->sym->flags |= SymPackage;
-
- exportlist = list(exportlist, n);
-}
-
-int
-exportname(char *s)
-{
- Rune r;
-
- if((uchar)s[0] < Runeself)
- return 'A' <= s[0] && s[0] <= 'Z';
- chartorune(&r, s);
- return isupperrune(r);
-}
-
-static int
-initname(char *s)
-{
- return strcmp(s, "init") == 0;
-}
-
-void
-autoexport(Node *n, int ctxt)
-{
- if(n == N || n->sym == S)
- return;
- if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
- return;
- if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method
- return;
- if(exportname(n->sym->name) || initname(n->sym->name))
- exportsym(n);
- else
- packagesym(n);
-}
-
-static void
-dumppkg(Pkg *p)
-{
- char *suffix;
-
- if(p == nil || p == localpkg || p->exported)
- return;
- p->exported = 1;
- suffix = "";
- if(!p->direct)
- suffix = " // indirect";
- Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
-}
-
-static void
-dumpprereq(Type *t)
-{
- if(t == T)
- return;
-
- if(t->printed || t == types[t->etype])
- return;
- t->printed = 1;
-
- if(t->sym != S) {
- dumppkg(t->sym->pkg);
- if(t->etype != TFIELD)
- dumpsym(t->sym);
- }
- dumpprereq(t->type);
- dumpprereq(t->down);
-}
-
-static void
-dumpexportconst(Sym *s)
-{
- Node *n;
- Type *t;
-
- n = s->def;
- typecheck(&n, Erv);
- if(n == N || n->op != OLITERAL)
- fatal("dumpexportconst: oconst nil: %S", s);
-
- t = n->type; // may or may not be specified
- if(t != T)
- dumpprereq(t);
-
- Bprint(bout, "\t");
- Bprint(bout, "const %#S", s);
- if(t != T && !isideal(t))
- Bprint(bout, " %#T", t);
- Bprint(bout, " = ");
-
- switch(n->val.ctype) {
- default:
- fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype);
- case CTINT:
- Bprint(bout, "%B\n", n->val.u.xval);
- break;
- case CTBOOL:
- if(n->val.u.bval)
- Bprint(bout, "true\n");
- else
- Bprint(bout, "false\n");
- break;
- case CTFLT:
- Bprint(bout, "%F\n", n->val.u.fval);
- break;
- case CTCPLX:
- Bprint(bout, "(%F+%F)\n", &n->val.u.cval->real, &n->val.u.cval->imag);
- break;
- case CTSTR:
- Bprint(bout, "\"%Z\"\n", n->val.u.sval);
- break;
- }
-}
-
-static void
-dumpexportvar(Sym *s)
-{
- Node *n;
- Type *t;
-
- n = s->def;
- typecheck(&n, Erv);
- if(n == N || n->type == T) {
- yyerror("variable exported but not defined: %S", s);
- return;
- }
-
- t = n->type;
- dumpprereq(t);
-
- Bprint(bout, "\t");
- if(t->etype == TFUNC && n->class == PFUNC)
- Bprint(bout, "func %#S %#hhT", s, t);
- else
- Bprint(bout, "var %#S %#T", s, t);
- Bprint(bout, "\n");
-}
-
-static void
-dumpexporttype(Sym *s)
-{
- Type *t;
-
- t = s->def->type;
- dumpprereq(t);
- Bprint(bout, "\t");
- switch (t->etype) {
- case TFORW:
- yyerror("export of incomplete type %T", t);
- return;
- }
- if(Bprint(bout, "type %#T %l#T\n", t, t) < 0)
- fatal("Bprint failed for %T", t);
-}
-
-static int
-methcmp(const void *va, const void *vb)
-{
- Type *a, *b;
-
- a = *(Type**)va;
- b = *(Type**)vb;
- return strcmp(a->sym->name, b->sym->name);
-}
-
-static void
-dumpsym(Sym *s)
-{
- Type *f, *t;
- Type **m;
- int i, n;
-
- if(s->flags & SymExported)
- return;
- s->flags |= SymExported;
-
- if(s->def == N) {
- yyerror("unknown export symbol: %S", s);
- return;
- }
-
- dumppkg(s->pkg);
-
- switch(s->def->op) {
- default:
- yyerror("unexpected export symbol: %O %S", s->def->op, s);
- break;
- case OLITERAL:
- dumpexportconst(s);
- break;
- case OTYPE:
- t = s->def->type;
- n = 0;
- for(f=t->method; f!=T; f=f->down) {
- dumpprereq(f);
- n++;
- }
- m = mal(n*sizeof m[0]);
- i = 0;
- for(f=t->method; f!=T; f=f->down)
- m[i++] = f;
- qsort(m, n, sizeof m[0], methcmp);
-
- dumpexporttype(s);
- for(i=0; i<n; i++) {
- f = m[i];
- Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
- f->type->type->type, f->sym, f->type);
- }
- break;
- case ONAME:
- dumpexportvar(s);
- break;
- }
-}
-
-static void
-dumptype(Type *t)
-{
- // no need to re-dump type if already exported
- if(t->printed)
- return;
-
- // no need to dump type if it's not ours (was imported)
- if(t->sym != S && t->sym->def == typenod(t) && !t->local)
- return;
-
- Bprint(bout, "type %#T %l#T\n", t, t);
-}
-
-void
-dumpexport(void)
-{
- NodeList *l;
- int32 i, lno;
- Pkg *p;
-
- lno = lineno;
-
- packagequotes = 1;
- Bprint(bout, "\n$$ // exports\n");
-
- Bprint(bout, " package %s", localpkg->name);
- if(safemode)
- Bprint(bout, " safe");
- Bprint(bout, "\n");
-
- for(i=0; i<nelem(phash); i++)
- for(p=phash[i]; p; p=p->link)
- if(p->direct)
- dumppkg(p);
-
- for(l=exportlist; l; l=l->next) {
- lineno = l->n->lineno;
- dumpsym(l->n->sym);
- }
-
- Bprint(bout, "\n$$ // local types\n");
-
- for(l=typelist; l; l=l->next) {
- lineno = l->n->lineno;
- dumptype(l->n->type);
- }
-
- Bprint(bout, "\n$$\n");
- packagequotes = 0;
-
- lineno = lno;
-}
-
-/*
- * import
- */
-
-/*
- * return the sym for ss, which should match lexical
- */
-Sym*
-importsym(Sym *s, int op)
-{
- if(s->def != N && s->def->op != op)
- redeclare(s, "during import");
-
- // mark the symbol so it is not reexported
- if(s->def == N) {
- if(exportname(s->name) || initname(s->name))
- s->flags |= SymExport;
- else
- s->flags |= SymPackage; // package scope
- }
- return s;
-}
-
-/*
- * return the type pkg.name, forward declaring if needed
- */
-Type*
-pkgtype(Sym *s)
-{
- Type *t;
-
- importsym(s, OTYPE);
- if(s->def == N || s->def->op != OTYPE) {
- t = typ(TFORW);
- t->sym = s;
- s->def = typenod(t);
- }
- if(s->def->type == T)
- yyerror("pkgtype %lS", s);
- return s->def->type;
-}
-
-static int
-mypackage(Sym *s)
-{
- // we import all definitions for runtime.
- // lowercase ones can only be used by the compiler.
- return s->pkg == localpkg || s->pkg == runtimepkg;
-}
-
-void
-importconst(Sym *s, Type *t, Node *n)
-{
- Node *n1;
-
- if(!exportname(s->name) && !mypackage(s))
- return;
- importsym(s, OLITERAL);
- convlit(&n, t);
- if(s->def != N) {
- // TODO: check if already the same.
- return;
- }
-
- if(n->op != OLITERAL) {
- yyerror("expression must be a constant");
- return;
- }
- if(n->sym != S) {
- n1 = nod(OXXX, N, N);
- *n1 = *n;
- n = n1;
- }
- n->sym = s;
- declare(n, PEXTERN);
-
- if(debug['E'])
- print("import const %S\n", s);
-}
-
-void
-importvar(Sym *s, Type *t, int ctxt)
-{
- Node *n;
-
- if(!exportname(s->name) && !initname(s->name) && !mypackage(s))
- return;
-
- importsym(s, ONAME);
- if(s->def != N && s->def->op == ONAME) {
- if(eqtype(t, s->def->type))
- return;
- yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
- s, s->def->type, t);
- }
- n = newname(s);
- n->type = t;
- declare(n, ctxt);
-
- if(debug['E'])
- print("import var %S %lT\n", s, t);
-}
-
-void
-importtype(Type *pt, Type *t)
-{
- if(pt != T && t != T)
- typedcl2(pt, t);
-
- if(debug['E'])
- print("import type %T %lT\n", pt, t);
-}
-
-void
-importmethod(Sym *s, Type *t)
-{
- checkwidth(t);
- addmethod(s, t, 0);
-}
-
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
deleted file mode 100644
index cb66921ba..000000000
--- a/src/cmd/gc/gen.c
+++ /dev/null
@@ -1,790 +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.
-
-/*
- * portable half of code generator.
- * mainly statements and control flow.
- */
-
-#include "go.h"
-
-static void cgen_dcl(Node *n);
-static void cgen_proc(Node *n, int proc);
-static void checkgoto(Node*, Node*);
-
-static Label *labellist;
-static Label *lastlabel;
-
-Node*
-sysfunc(char *name)
-{
- Node *n;
-
- n = newname(pkglookup(name, runtimepkg));
- n->class = PFUNC;
- return n;
-}
-
-void
-allocparams(void)
-{
- NodeList *l;
- Node *n;
- uint32 w;
- Sym *s;
- int lno;
-
- if(stksize < 0)
- fatal("allocparams not during code generation");
-
- /*
- * allocate (set xoffset) the stack
- * slots for all automatics.
- * allocated starting at -w down.
- */
- lno = lineno;
- for(l=curfn->dcl; l; l=l->next) {
- n = l->n;
- if(n->op == ONAME && n->class == PHEAP-1) {
- // heap address variable; finish the job
- // started in addrescapes.
- s = n->sym;
- tempname(n, n->type);
- n->sym = s;
- }
- if(n->op != ONAME || n->class != PAUTO)
- continue;
- if (n->xoffset != BADWIDTH)
- continue;
- if(n->type == T)
- continue;
- dowidth(n->type);
- w = n->type->width;
- if(w >= MAXWIDTH)
- fatal("bad width");
- stksize += w;
- stksize = rnd(stksize, n->type->align);
- if(thechar == '5')
- stksize = rnd(stksize, widthptr);
- n->xoffset = -stksize;
- }
- lineno = lno;
-}
-
-void
-clearlabels(void)
-{
- Label *l;
-
- for(l=labellist; l!=L; l=l->link)
- l->sym->label = L;
-
- labellist = L;
- lastlabel = L;
-}
-
-static Label*
-newlab(Node *n)
-{
- Sym *s;
- Label *lab;
-
- s = n->left->sym;
- if((lab = s->label) == L) {
- lab = mal(sizeof(*lab));
- if(lastlabel == nil)
- labellist = lab;
- else
- lastlabel->link = lab;
- lastlabel = lab;
- lab->sym = s;
- s->label = lab;
- }
-
- if(n->op == OLABEL) {
- if(lab->def != N)
- yyerror("label %S already defined at %L", s, lab->def->lineno);
- else
- lab->def = n;
- } else
- lab->use = list(lab->use, n);
-
- return lab;
-}
-
-void
-checklabels(void)
-{
- Label *lab;
- NodeList *l;
-
- for(lab=labellist; lab!=L; lab=lab->link) {
- if(lab->def == N) {
- for(l=lab->use; l; l=l->next)
- yyerrorl(l->n->lineno, "label %S not defined", lab->sym);
- continue;
- }
- if(lab->use == nil && !lab->used) {
- yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym);
- continue;
- }
- if(lab->gotopc != P)
- fatal("label %S never resolved", lab->sym);
- for(l=lab->use; l; l=l->next)
- checkgoto(l->n, lab->def);
- }
-}
-
-static void
-checkgoto(Node *from, Node *to)
-{
- int nf, nt;
- Sym *block, *dcl, *fs, *ts;
- int lno;
-
- if(from->sym == to->sym)
- return;
-
- nf = 0;
- for(fs=from->sym; fs; fs=fs->link)
- nf++;
- nt = 0;
- for(fs=to->sym; fs; fs=fs->link)
- nt++;
- fs = from->sym;
- for(; nf > nt; nf--)
- fs = fs->link;
- if(fs != to->sym) {
- lno = lineno;
- setlineno(from);
-
- // decide what to complain about.
- // prefer to complain about 'into block' over declarations,
- // so scan backward to find most recent block or else dcl.
- block = S;
- dcl = S;
- ts = to->sym;
- for(; nt > nf; nt--) {
- if(ts->pkg == nil)
- block = ts;
- else
- dcl = ts;
- ts = ts->link;
- }
- while(ts != fs) {
- if(ts->pkg == nil)
- block = ts;
- else
- dcl = ts;
- ts = ts->link;
- fs = fs->link;
- }
-
- if(block)
- yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno);
- else
- yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno);
- lineno = lno;
- }
-}
-
-static Label*
-stmtlabel(Node *n)
-{
- Label *lab;
-
- if(n->sym != S)
- if((lab = n->sym->label) != L)
- if(lab->def != N)
- if(lab->def->right == n)
- return lab;
- return L;
-}
-
-/*
- * compile statements
- */
-void
-genlist(NodeList *l)
-{
- for(; l; l=l->next)
- gen(l->n);
-}
-
-void
-gen(Node *n)
-{
- int32 lno;
- Prog *scontin, *sbreak;
- Prog *p1, *p2, *p3;
- Label *lab;
- int32 wasregalloc;
-
- lno = setlineno(n);
- wasregalloc = anyregalloc();
-
- if(n == N)
- goto ret;
-
- p3 = pc; // save pc for loop labels
- if(n->ninit)
- genlist(n->ninit);
-
- setlineno(n);
-
- switch(n->op) {
- default:
- fatal("gen: unknown op %N", n);
- break;
-
- case OCASE:
- case OFALL:
- case OXCASE:
- case OXFALL:
- case ODCLCONST:
- case ODCLFUNC:
- case ODCLTYPE:
- break;
-
- case OEMPTY:
- break;
-
- case OBLOCK:
- genlist(n->list);
- break;
-
- case OLABEL:
- lab = newlab(n);
-
- // if there are pending gotos, resolve them all to the current pc.
- for(p1=lab->gotopc; p1; p1=p2) {
- p2 = unpatch(p1);
- patch(p1, pc);
- }
- lab->gotopc = P;
- if(lab->labelpc == P)
- lab->labelpc = pc;
-
- if(n->right) {
- switch(n->right->op) {
- case OFOR:
- case OSWITCH:
- case OSELECT:
- // so stmtlabel can find the label
- n->right->sym = lab->sym;
- }
- }
- break;
-
- case OGOTO:
- // if label is defined, emit jump to it.
- // otherwise save list of pending gotos in lab->gotopc.
- // the list is linked through the normal jump target field
- // to avoid a second list. (the jumps are actually still
- // valid code, since they're just going to another goto
- // to the same label. we'll unwind it when we learn the pc
- // of the label in the OLABEL case above.)
- lab = newlab(n);
- if(lab->labelpc != P)
- gjmp(lab->labelpc);
- else
- lab->gotopc = gjmp(lab->gotopc);
- break;
-
- case OBREAK:
- if(n->left != N) {
- lab = n->left->sym->label;
- if(lab == L) {
- yyerror("break label not defined: %S", n->left->sym);
- break;
- }
- lab->used = 1;
- if(lab->breakpc == P) {
- yyerror("invalid break label %S", n->left->sym);
- break;
- }
- gjmp(lab->breakpc);
- break;
- }
- if(breakpc == P) {
- yyerror("break is not in a loop");
- break;
- }
- gjmp(breakpc);
- break;
-
- case OCONTINUE:
- if(n->left != N) {
- lab = n->left->sym->label;
- if(lab == L) {
- yyerror("continue label not defined: %S", n->left->sym);
- break;
- }
- lab->used = 1;
- if(lab->continpc == P) {
- yyerror("invalid continue label %S", n->left->sym);
- break;
- }
- gjmp(lab->continpc);
- break;
- }
- if(continpc == P) {
- yyerror("continue is not in a loop");
- break;
- }
- gjmp(continpc);
- break;
-
- case OFOR:
- sbreak = breakpc;
- p1 = gjmp(P); // goto test
- breakpc = gjmp(P); // break: goto done
- scontin = continpc;
- continpc = pc;
-
- // define break and continue labels
- if((lab = stmtlabel(n)) != L) {
- lab->breakpc = breakpc;
- lab->continpc = continpc;
- }
- gen(n->nincr); // contin: incr
- patch(p1, pc); // test:
- bgen(n->ntest, 0, breakpc); // if(!test) goto break
- genlist(n->nbody); // body
- gjmp(continpc);
- patch(breakpc, pc); // done:
- continpc = scontin;
- breakpc = sbreak;
- if(lab) {
- lab->breakpc = P;
- lab->continpc = P;
- }
- break;
-
- case OIF:
- p1 = gjmp(P); // goto test
- p2 = gjmp(P); // p2: goto else
- patch(p1, pc); // test:
- bgen(n->ntest, 0, p2); // if(!test) goto p2
- genlist(n->nbody); // then
- p3 = gjmp(P); // goto done
- patch(p2, pc); // else:
- genlist(n->nelse); // else
- patch(p3, pc); // done:
- break;
-
- case OSWITCH:
- sbreak = breakpc;
- p1 = gjmp(P); // goto test
- breakpc = gjmp(P); // break: goto done
-
- // define break label
- if((lab = stmtlabel(n)) != L)
- lab->breakpc = breakpc;
-
- patch(p1, pc); // test:
- genlist(n->nbody); // switch(test) body
- patch(breakpc, pc); // done:
- breakpc = sbreak;
- if(lab != L)
- lab->breakpc = P;
- break;
-
- case OSELECT:
- sbreak = breakpc;
- p1 = gjmp(P); // goto test
- breakpc = gjmp(P); // break: goto done
-
- // define break label
- if((lab = stmtlabel(n)) != L)
- lab->breakpc = breakpc;
-
- patch(p1, pc); // test:
- genlist(n->nbody); // select() body
- patch(breakpc, pc); // done:
- breakpc = sbreak;
- if(lab != L)
- lab->breakpc = P;
- break;
-
- case OASOP:
- cgen_asop(n);
- break;
-
- case ODCL:
- cgen_dcl(n->left);
- break;
-
- case OAS:
- if(gen_as_init(n))
- break;
- cgen_as(n->left, n->right);
- break;
-
- case OCALLMETH:
- cgen_callmeth(n, 0);
- break;
-
- case OCALLINTER:
- cgen_callinter(n, N, 0);
- break;
-
- case OCALLFUNC:
- cgen_call(n, 0);
- break;
-
- case OPROC:
- cgen_proc(n, 1);
- break;
-
- case ODEFER:
- cgen_proc(n, 2);
- break;
-
- case ORETURN:
- cgen_ret(n);
- break;
- }
-
-ret:
- if(anyregalloc() != wasregalloc) {
- dump("node", n);
- fatal("registers left allocated");
- }
-
- lineno = lno;
-}
-
-/*
- * generate call to non-interface method
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-void
-cgen_callmeth(Node *n, int proc)
-{
- Node *l;
-
- // generate a rewrite for method call
- // (p.f)(...) goes to (f)(p,...)
-
- l = n->left;
- if(l->op != ODOTMETH)
- fatal("cgen_callmeth: not dotmethod: %N");
-
- n->op = OCALLFUNC;
- n->left = n->left->right;
- n->left->type = l->type;
-
- if(n->left->op == ONAME)
- n->left->class = PFUNC;
- cgen_call(n, proc);
-}
-
-/*
- * generate code to start new proc running call n.
- */
-void
-cgen_proc(Node *n, int proc)
-{
- switch(n->left->op) {
- default:
- fatal("cgen_proc: unknown call %O", n->left->op);
-
- case OCALLMETH:
- cgen_callmeth(n->left, proc);
- break;
-
- case OCALLINTER:
- cgen_callinter(n->left, N, proc);
- break;
-
- case OCALLFUNC:
- cgen_call(n->left, proc);
- break;
- }
-
-}
-
-/*
- * generate declaration.
- * nothing to do for on-stack automatics,
- * but might have to allocate heap copy
- * for escaped variables.
- */
-static void
-cgen_dcl(Node *n)
-{
- if(debug['g'])
- dump("\ncgen-dcl", n);
- if(n->op != ONAME) {
- dump("cgen_dcl", n);
- fatal("cgen_dcl");
- }
- if(!(n->class & PHEAP))
- return;
- if(n->alloc == nil)
- n->alloc = callnew(n->type);
- cgen_as(n->heapaddr, n->alloc);
-}
-
-/*
- * generate discard of value
- */
-static void
-cgen_discard(Node *nr)
-{
- Node tmp;
-
- if(nr == N)
- return;
-
- switch(nr->op) {
- case ONAME:
- if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
- gused(nr);
- break;
-
- // unary
- case OADD:
- case OAND:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLSH:
- case OLT:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case ORSH:
- case OSUB:
- case OXOR:
- cgen_discard(nr->left);
- cgen_discard(nr->right);
- break;
-
- // binary
- case OCAP:
- case OCOM:
- case OLEN:
- case OMINUS:
- case ONOT:
- case OPLUS:
- cgen_discard(nr->left);
- break;
-
- // special enough to just evaluate
- default:
- tempname(&tmp, nr->type);
- cgen_as(&tmp, nr);
- gused(&tmp);
- }
-}
-
-/*
- * generate assignment:
- * nl = nr
- * nr == N means zero nl.
- */
-void
-cgen_as(Node *nl, Node *nr)
-{
- Node nc;
- Type *tl;
- int iszer;
-
- if(nl == N)
- return;
-
- if(debug['g']) {
- dump("cgen_as", nl);
- dump("cgen_as = ", nr);
- }
-
- if(isblank(nl)) {
- cgen_discard(nr);
- return;
- }
-
- iszer = 0;
- if(nr == N || isnil(nr)) {
- // externals and heaps should already be clear
- if(nr == N) {
- if(nl->class == PEXTERN)
- return;
- if(nl->class & PHEAP)
- return;
- }
-
- tl = nl->type;
- if(tl == T)
- return;
- if(isfat(tl)) {
- clearfat(nl);
- goto ret;
- }
-
- /* invent a "zero" for the rhs */
- iszer = 1;
- nr = &nc;
- memset(nr, 0, sizeof(*nr));
- switch(simtype[tl->etype]) {
- default:
- fatal("cgen_as: tl %T", tl);
- break;
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- nr->val.u.xval = mal(sizeof(*nr->val.u.xval));
- mpmovecfix(nr->val.u.xval, 0);
- nr->val.ctype = CTINT;
- break;
-
- case TFLOAT32:
- case TFLOAT64:
- nr->val.u.fval = mal(sizeof(*nr->val.u.fval));
- mpmovecflt(nr->val.u.fval, 0.0);
- nr->val.ctype = CTFLT;
- break;
-
- case TBOOL:
- nr->val.u.bval = 0;
- nr->val.ctype = CTBOOL;
- break;
-
- case TPTR32:
- case TPTR64:
- nr->val.ctype = CTNIL;
- break;
-
- case TCOMPLEX64:
- case TCOMPLEX128:
- nr->val.u.cval = mal(sizeof(*nr->val.u.cval));
- mpmovecflt(&nr->val.u.cval->real, 0.0);
- mpmovecflt(&nr->val.u.cval->imag, 0.0);
- break;
- }
- nr->op = OLITERAL;
- nr->type = tl;
- nr->addable = 1;
- ullmancalc(nr);
- }
-
- tl = nl->type;
- if(tl == T)
- return;
-
- cgen(nr, nl);
- if(iszer && nl->addable)
- gused(nl);
-
-ret:
- ;
-}
-
-/*
- * gather series of offsets
- * >=0 is direct addressed field
- * <0 is pointer to next field (+1)
- */
-int
-dotoffset(Node *n, int *oary, Node **nn)
-{
- int i;
-
- switch(n->op) {
- case ODOT:
- if(n->xoffset == BADWIDTH) {
- dump("bad width in dotoffset", n);
- fatal("bad width in dotoffset");
- }
- i = dotoffset(n->left, oary, nn);
- if(i > 0) {
- if(oary[i-1] >= 0)
- oary[i-1] += n->xoffset;
- else
- oary[i-1] -= n->xoffset;
- break;
- }
- if(i < 10)
- oary[i++] = n->xoffset;
- break;
-
- case ODOTPTR:
- if(n->xoffset == BADWIDTH) {
- dump("bad width in dotoffset", n);
- fatal("bad width in dotoffset");
- }
- i = dotoffset(n->left, oary, nn);
- if(i < 10)
- oary[i++] = -(n->xoffset+1);
- break;
-
- default:
- *nn = n;
- return 0;
- }
- if(i >= 10)
- *nn = N;
- return i;
-}
-
-/*
- * make a new off the books
- */
-void
-tempname(Node *nn, Type *t)
-{
- Node *n;
- Sym *s;
- uint32 w;
-
- if(stksize < 0)
- fatal("tempname not during code generation");
-
- if (curfn == N)
- fatal("no curfn for tempname");
-
- if(t == T) {
- yyerror("tempname called with nil type");
- t = types[TINT32];
- }
-
- // give each tmp a different name so that there
- // a chance to registerizer them
- snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
- statuniqgen++;
- s = lookup(namebuf);
- n = nod(ONAME, N, N);
- n->sym = s;
- n->type = t;
- n->class = PAUTO;
- n->addable = 1;
- n->ullman = 1;
- n->noescape = 1;
- n->curfn = curfn;
- curfn->dcl = list(curfn->dcl, n);
-
- dowidth(t);
- w = t->width;
- stksize += w;
- stksize = rnd(stksize, t->align);
- if(thechar == '5')
- stksize = rnd(stksize, widthptr);
- n->xoffset = -stksize;
-
- // print("\ttmpname (%d): %N\n", stksize, n);
-
- *nn = *n;
-}
diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors
deleted file mode 100644
index b5af4678c..000000000
--- a/src/cmd/gc/go.errors
+++ /dev/null
@@ -1,70 +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.
-
-// Example-based syntax error messages.
-// See bisonerrors, Makefile, go.y.
-
-static struct {
- int yystate;
- int yychar;
- char *msg;
-} yymsg[] = {
- // Each line of the form % token list
- // is converted by bisonerrors into the yystate and yychar caused
- // by that token list.
-
- % loadsys package LIMPORT '(' LLITERAL import_package import_there ','
- "unexpected comma during import block",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';'
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';'
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';'
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LFUNC LNAME '(' ')' ';' '{'
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LTYPE LNAME ';'
- "unexpected semicolon or newline in type declaration",
-
- % loadsys package imports LCHAN '}'
- "unexpected } in channel type",
-
- % loadsys package imports LCHAN ')'
- "unexpected ) in channel type",
-
- % loadsys package imports LCHAN ','
- "unexpected comma in channel type",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE
- "unexpected semicolon or newline before else",
-
- % loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME
- "name list not allowed in interface type",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME
- "var declaration not allowed in for initializer",
-
- % loadsys package imports LVAR LNAME '[' ']' LNAME '{'
- "unexpected { at end of statement",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{'
- "unexpected { at end of statement",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';'
- "argument to go/defer must be function call",
-
- % loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';'
- "need trailing comma before newline in composite literal",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME
- "nested func not allowed",
-};
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
deleted file mode 100644
index 8ca086ee0..000000000
--- a/src/cmd/gc/go.h
+++ /dev/null
@@ -1,1265 +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 <u.h>
-#include <libc.h>
-#include <bio.h>
-
-#undef OAPPEND
-
-// avoid <ctype.h>
-#undef isblank
-#define isblank goisblank
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#undef BUFSIZ
-
-enum
-{
- NHUNK = 50000,
- BUFSIZ = 8192,
- NSYMB = 500,
- NHASH = 1024,
- STRINGSZ = 200,
- YYMAXDEPTH = 500,
- MAXALIGN = 7,
- UINF = 100,
- HISTSZ = 10,
-
- PRIME1 = 3,
-
- AUNK = 100,
-
- // these values are known by runtime
- AMEM = 0,
- ANOEQ,
- ASTRING,
- AINTER,
- ANILINTER,
- AMEMWORD,
-
- BADWIDTH = -1000000000,
- MAXWIDTH = 1<<30
-};
-
-/*
- * note this is the representation
- * of the compilers string literals,
- * it is not the runtime representation
- */
-typedef struct Strlit Strlit;
-struct Strlit
-{
- int32 len;
- char s[3]; // variable
-};
-
-/*
- * note this is the runtime representation
- * of hashmap iterator. it is probably
- * insafe to use it this way, but it puts
- * all the changes in one place.
- * only flag is referenced from go.
- * actual placement does not matter as long
- * as the size is >= actual size.
- */
-typedef struct Hiter Hiter;
-struct Hiter
-{
- uchar data[8]; // return val from next
- int32 elemsize; // size of elements in table */
- int32 changes; // number of changes observed last time */
- int32 i; // stack pointer in subtable_state */
- uchar last[8]; // last hash value returned */
- uchar h[8]; // the hash table */
- struct
- {
- uchar sub[8]; // pointer into subtable */
- uchar start[8]; // pointer into start of subtable */
- uchar end[8]; // pointer into end of subtable */
- uchar pad[8];
- } sub[4];
-};
-
-enum
-{
- Mpscale = 29, // safely smaller than bits in a long
- Mpprec = 16, // Mpscale*Mpprec is max number of bits
- Mpnorm = Mpprec - 1, // significant words in a normalized float
- Mpbase = 1L << Mpscale,
- Mpsign = Mpbase >> 1,
- Mpmask = Mpbase - 1,
- Mpdebug = 0,
-};
-
-typedef struct Mpint Mpint;
-struct Mpint
-{
- long a[Mpprec];
- uchar neg;
- uchar ovf;
-};
-
-typedef struct Mpflt Mpflt;
-struct Mpflt
-{
- Mpint val;
- short exp;
-};
-
-typedef struct Mpcplx Mpcplx;
-struct Mpcplx
-{
- Mpflt real;
- Mpflt imag;
-};
-
-typedef struct Val Val;
-struct Val
-{
- short ctype;
- union
- {
- short reg; // OREGISTER
- short bval; // bool value CTBOOL
- Mpint* xval; // int CTINT
- Mpflt* fval; // float CTFLT
- Mpcplx* cval; // float CTCPLX
- Strlit* sval; // string CTSTR
- } u;
-};
-
-typedef struct Pkg Pkg;
-typedef struct Sym Sym;
-typedef struct Node Node;
-typedef struct NodeList NodeList;
-typedef struct Type Type;
-typedef struct Label Label;
-
-struct Type
-{
- uchar etype;
- uchar chan;
- uchar recur; // to detect loops
- uchar trecur; // to detect loops
- uchar printed;
- uchar embedded; // TFIELD embedded type
- uchar siggen;
- uchar funarg;
- uchar copyany;
- uchar local; // created in this file
- uchar deferwidth;
- uchar broke;
- uchar isddd; // TFIELD is ... argument
- uchar align;
-
- Node* nod; // canonical OTYPE node
- Type* orig; // original type (type literal or predefined type)
- int lineno;
-
- // TFUNCT
- uchar thistuple;
- uchar outtuple;
- uchar intuple;
- uchar outnamed;
-
- Type* method;
- Type* xmethod;
-
- Sym* sym;
- int32 vargen; // unique name for OTYPE/ONAME
-
- Node* nname;
- vlong argwid;
-
- // most nodes
- Type* type;
- vlong width; // offset in TFIELD, width in all others
-
- // TFIELD
- Type* down; // also used in TMAP
- Strlit* note; // literal string annotation
-
- // TARRAY
- int32 bound; // negative is dynamic array
-
- int32 maplineno; // first use of TFORW as map key
- int32 embedlineno; // first use of TFORW as embedded type
-};
-#define T ((Type*)0)
-
-struct Node
-{
- uchar op;
- uchar ullman; // sethi/ullman number
- uchar addable; // type of addressability - 0 is not addressable
- uchar trecur; // to detect loops
- uchar etype; // op for OASOP, etype for OTYPE, exclam for export
- uchar class; // PPARAM, PAUTO, PEXTERN, etc
- uchar method; // OCALLMETH name
- uchar embedded; // ODCLFIELD embedded type
- uchar colas; // OAS resulting from :=
- uchar diag; // already printed error about this
- uchar noescape; // ONAME never move to heap
- uchar funcdepth;
- uchar builtin; // built-in name, like len or close
- uchar walkdef;
- uchar typecheck;
- uchar local;
- uchar initorder;
- uchar dodata; // compile literal assignment as data statement
- uchar used;
- uchar isddd;
- uchar pun; // don't registerize variable ONAME
- uchar readonly;
- uchar implicit; // don't show in printout
-
- // most nodes
- Node* left;
- Node* right;
- Type* type;
- Type* realtype; // as determined by typecheck
- NodeList* list;
- NodeList* rlist;
- Node* orig; // original form, for printing, and tracking copies of ONAMEs
-
- // for-body
- NodeList* ninit;
- Node* ntest;
- Node* nincr;
- NodeList* nbody;
-
- // if-body
- NodeList* nelse;
-
- // cases
- Node* ncase;
-
- // func
- Node* nname;
- Node* shortname;
- NodeList* enter;
- NodeList* exit;
- NodeList* cvars; // closure params
- NodeList* dcl; // autodcl for this func/closure
-
- // OLITERAL/OREGISTER
- Val val;
-
- // ONAME
- Node* ntype;
- Node* defn;
- Node* pack; // real package for import . names
- Node* curfn; // function for local variables
-
- // ONAME func param with PHEAP
- Node* heapaddr; // temp holding heap address of param
- Node* stackparam; // OPARAM node referring to stack copy of param
- Node* alloc; // allocation call
-
- // ONAME closure param with PPARAMREF
- Node* outer; // outer PPARAMREF in nested closure
- Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF
-
- // OPACK
- Pkg* pkg;
-
- Sym* sym; // various
- int32 vargen; // unique name for OTYPE/ONAME
- int32 lineno;
- int32 endlineno;
- vlong xoffset;
- int32 stkdelta; // offset added by stack frame compaction phase.
- int32 ostk;
- int32 iota;
-};
-#define N ((Node*)0)
-EXTERN int32 walkgen;
-
-struct NodeList
-{
- Node* n;
- NodeList* next;
- NodeList* end;
-};
-
-enum
-{
- SymExport = 1<<0,
- SymPackage = 1<<1,
- SymExported = 1<<2,
- SymUniq = 1<<3,
- SymSiggen = 1<<4,
-};
-
-struct Sym
-{
- ushort lexical;
- uchar flags;
- uchar sym; // huffman encoding in object file
- Sym* link;
- int32 npkg; // number of imported packages with this name
-
- // saved and restored by dcopy
- Pkg* pkg;
- char* name; // variable name
- Node* def; // definition: ONAME OTYPE OPACK or OLITERAL
- Label* label; // corresponding label (ephemeral)
- int32 block; // blocknumber to catch redeclaration
- int32 lastlineno; // last declaration for diagnostic
-};
-#define S ((Sym*)0)
-
-EXTERN Sym* dclstack;
-
-struct Pkg
-{
- char* name;
- Strlit* path;
- Sym* pathsym;
- char* prefix;
- Pkg* link;
- char exported; // import line written in export data
- char direct; // imported directly
-};
-
-typedef struct Iter Iter;
-struct Iter
-{
- int done;
- Type* tfunc;
- Type* t;
- Node** an;
- Node* n;
-};
-
-typedef struct Hist Hist;
-struct Hist
-{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
-};
-#define H ((Hist*)0)
-
-enum
-{
- OXXX,
-
- // names
- ONAME,
- ONONAME,
- OTYPE,
- OPACK,
- OLITERAL,
-
- // exprs
- OADD, OSUB, OOR, OXOR, OADDSTR,
- OADDR,
- OANDAND,
- OAPPEND,
- OARRAY,
- OARRAYBYTESTR, OARRAYRUNESTR,
- OSTRARRAYBYTE, OSTRARRAYRUNE,
- OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
- OBAD,
- OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
- OCAP,
- OCLOSE,
- OCLOSURE,
- OCMPIFACE, OCMPSTR,
- OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
- OCONV, OCONVIFACE, OCONVNOP,
- OCOPY,
- ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
- ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
- ODOTTYPE,
- ODOTTYPE2,
- OEQ, ONE, OLT, OLE, OGE, OGT,
- OIND,
- OINDEX, OINDEXMAP,
- OKEY, OPARAM,
- OLEN,
- OMAKE, OMAKECHAN, OMAKEMAP, OMAKESLICE,
- OHMUL, ORRC, OLRC, // high-mul and rotate-carry
- OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT,
- ONEW,
- ONOT, OCOM, OPLUS, OMINUS,
- OOROR,
- OPANIC, OPRINT, OPRINTN,
- OSEND,
- OSLICE, OSLICEARR, OSLICESTR,
- ORECOVER,
- ORECV,
- ORUNESTR,
- OSELRECV,
- OSELRECV2,
- OIOTA,
- OREAL, OIMAG, OCOMPLEX,
-
- // stmts
- OBLOCK,
- OBREAK,
- OCASE, OXCASE,
- OCONTINUE,
- ODEFER,
- OEMPTY,
- OFALL, OXFALL,
- OFOR,
- OGOTO,
- OIF,
- OLABEL,
- OPROC,
- ORANGE,
- ORETURN,
- OSELECT,
- OSWITCH,
- OTYPESW, // l = r.(type)
-
- // types
- OTCHAN,
- OTMAP,
- OTSTRUCT,
- OTINTER,
- OTFUNC,
- OTARRAY,
- OTPAREN,
-
- // misc
- ODDD,
-
- // for back ends
- OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG,
-
- OEND,
-};
-enum
-{
- Txxx, // 0
-
- TINT8, TUINT8, // 1
- TINT16, TUINT16,
- TINT32, TUINT32,
- TINT64, TUINT64,
- TINT, TUINT, TUINTPTR,
-
- TCOMPLEX64, // 12
- TCOMPLEX128,
-
- TFLOAT32, // 14
- TFLOAT64,
-
- TBOOL, // 16
-
- TPTR32, TPTR64, // 17
-
- TFUNC, // 19
- TARRAY,
- T_old_DARRAY,
- TSTRUCT, // 22
- TCHAN,
- TMAP,
- TINTER, // 25
- TFORW,
- TFIELD,
- TANY,
- TSTRING,
- TUNSAFEPTR,
-
- // pseudo-types for literals
- TIDEAL, // 31
- TNIL,
- TBLANK,
-
- // pseudo-type for frame layout
- TFUNCARGS,
- TCHANARGS,
- TINTERMETH,
-
- NTYPE,
-};
-enum
-{
- CTxxx,
-
- CTINT,
- CTFLT,
- CTCPLX,
- CTSTR,
- CTBOOL,
- CTNIL,
-};
-
-enum
-{
- /* types of channel */
- /* must match ../../pkg/nreflect/type.go:/Chandir */
- Cxxx,
- Crecv = 1<<0,
- Csend = 1<<1,
- Cboth = Crecv | Csend,
-};
-
-enum
-{
- Pxxx,
-
- PEXTERN, // declaration context
- PAUTO,
- PPARAM,
- PPARAMOUT,
- PPARAMREF, // param passed by reference
- PFUNC,
-
- PHEAP = 1<<7,
-};
-
-enum
-{
- Etop = 1<<1, // evaluated at statement level
- Erv = 1<<2, // evaluated in value context
- Etype = 1<<3,
- Ecall = 1<<4, // call-only expressions are ok
- Efnstruct = 1<<5, // multivalue function returns are ok
- Eiota = 1<<6, // iota is ok
- Easgn = 1<<7, // assigning to expression
- Eindir = 1<<8, // indirecting through expression
- Eaddr = 1<<9, // taking address of expression
- Eproc = 1<<10, // inside a go statement
-};
-
-#define BITS 5
-#define NVAR (BITS*sizeof(uint32)*8)
-
-typedef struct Bits Bits;
-struct Bits
-{
- uint32 b[BITS];
-};
-
-EXTERN Bits zbits;
-
-typedef struct Var Var;
-struct Var
-{
- vlong offset;
- Sym* sym;
- Sym* gotype;
- Node* node;
- int width;
- char name;
- char etype;
- char addr;
-};
-
-EXTERN Var var[NVAR];
-
-typedef struct Typedef Typedef;
-struct Typedef
-{
- char* name;
- int etype;
- int sameas;
-};
-
-extern Typedef typedefs[];
-
-typedef struct Sig Sig;
-struct Sig
-{
- char* name;
- Pkg* pkg;
- Sym* isym;
- Sym* tsym;
- Type* type;
- Type* mtype;
- int32 offset;
- Sig* link;
-};
-
-typedef struct Io Io;
-struct Io
-{
- char* infile;
- Biobuf* bin;
- int32 ilineno;
- int nlsemi;
- int eofnl;
- int peekc;
- int peekc1; // second peekc for ...
- char* cp; // used for content when bin==nil
- int importsafe;
-};
-
-typedef struct Dlist Dlist;
-struct Dlist
-{
- Type* field;
-};
-
-typedef struct Idir Idir;
-struct Idir
-{
- Idir* link;
- char* dir;
-};
-
-/*
- * argument passing to/from
- * smagic and umagic
- */
-typedef struct Magic Magic;
-struct Magic
-{
- int w; // input for both - width
- int s; // output for both - shift
- int bad; // output for both - unexpected failure
-
- // magic multiplier for signed literal divisors
- int64 sd; // input - literal divisor
- int64 sm; // output - multiplier
-
- // magic multiplier for unsigned literal divisors
- uint64 ud; // input - literal divisor
- uint64 um; // output - multiplier
- int ua; // output - adder
-};
-
-typedef struct Prog Prog;
-
-struct Label
-{
- uchar used;
- Sym* sym;
- Node* def;
- NodeList* use;
- Label* link;
-
- // for use during gen
- Prog* gotopc; // pointer to unresolved gotos
- Prog* labelpc; // pointer to code
- Prog* breakpc; // pointer to code
- Prog* continpc; // pointer to code
-};
-#define L ((Label*)0)
-
-/*
- * note this is the runtime representation
- * of the compilers arrays.
- *
- * typedef struct
- * { // must not move anything
- * uchar array[8]; // pointer to data
- * uchar nel[4]; // number of elements
- * uchar cap[4]; // allocated number of elements
- * } Array;
- */
-EXTERN int Array_array; // runtime offsetof(Array,array) - same for String
-EXTERN int Array_nel; // runtime offsetof(Array,nel) - same for String
-EXTERN int Array_cap; // runtime offsetof(Array,cap)
-EXTERN int sizeof_Array; // runtime sizeof(Array)
-
-
-/*
- * note this is the runtime representation
- * of the compilers strings.
- *
- * typedef struct
- * { // must not move anything
- * uchar array[8]; // pointer to data
- * uchar nel[4]; // number of elements
- * } String;
- */
-EXTERN int sizeof_String; // runtime sizeof(String)
-
-EXTERN Dlist dotlist[10]; // size is max depth of embeddeds
-
-EXTERN Io curio;
-EXTERN Io pushedio;
-EXTERN int32 lexlineno;
-EXTERN int32 lineno;
-EXTERN int32 prevlineno;
-EXTERN char* pathname;
-EXTERN Hist* hist;
-EXTERN Hist* ehist;
-
-EXTERN char* infile;
-EXTERN char* outfile;
-EXTERN Biobuf* bout;
-EXTERN int nerrors;
-EXTERN int nsavederrors;
-EXTERN int nsyntaxerrors;
-EXTERN int safemode;
-EXTERN char namebuf[NSYMB];
-EXTERN char lexbuf[NSYMB];
-EXTERN char debug[256];
-EXTERN Sym* hash[NHASH];
-EXTERN Sym* importmyname; // my name for package
-EXTERN Pkg* localpkg; // package being compiled
-EXTERN Pkg* importpkg; // package being imported
-EXTERN Pkg* structpkg; // package that declared struct, during import
-EXTERN Pkg* builtinpkg; // fake package for builtins
-EXTERN Pkg* gostringpkg; // fake pkg for Go strings
-EXTERN Pkg* runtimepkg; // package runtime
-EXTERN Pkg* stringpkg; // fake package for C strings
-EXTERN Pkg* typepkg; // fake package for runtime type info
-EXTERN Pkg* unsafepkg; // package unsafe
-EXTERN Pkg* phash[128];
-EXTERN int tptr; // either TPTR32 or TPTR64
-extern char* runtimeimport;
-extern char* unsafeimport;
-EXTERN Idir* idirs;
-
-EXTERN Type* types[NTYPE];
-EXTERN Type* idealstring;
-EXTERN Type* idealbool;
-EXTERN uchar simtype[NTYPE];
-EXTERN uchar isptr[NTYPE];
-EXTERN uchar isforw[NTYPE];
-EXTERN uchar isint[NTYPE];
-EXTERN uchar isfloat[NTYPE];
-EXTERN uchar iscomplex[NTYPE];
-EXTERN uchar issigned[NTYPE];
-EXTERN uchar issimple[NTYPE];
-
-EXTERN uchar okforeq[NTYPE];
-EXTERN uchar okforadd[NTYPE];
-EXTERN uchar okforand[NTYPE];
-EXTERN uchar okfornone[NTYPE];
-EXTERN uchar okforcmp[NTYPE];
-EXTERN uchar okforbool[NTYPE];
-EXTERN uchar okforcap[NTYPE];
-EXTERN uchar okforlen[NTYPE];
-EXTERN uchar okforarith[NTYPE];
-EXTERN uchar okforconst[NTYPE];
-EXTERN uchar* okfor[OEND];
-EXTERN uchar iscmp[OEND];
-
-EXTERN Mpint* minintval[NTYPE];
-EXTERN Mpint* maxintval[NTYPE];
-EXTERN Mpflt* minfltval[NTYPE];
-EXTERN Mpflt* maxfltval[NTYPE];
-
-EXTERN NodeList* xtop;
-EXTERN NodeList* externdcl;
-EXTERN NodeList* closures;
-EXTERN NodeList* exportlist;
-EXTERN NodeList* typelist;
-EXTERN int dclcontext; // PEXTERN/PAUTO
-EXTERN int incannedimport;
-EXTERN int statuniqgen; // name generator for static temps
-EXTERN int loophack;
-
-EXTERN int32 iota;
-EXTERN NodeList* lastconst;
-EXTERN Node* lasttype;
-EXTERN int32 maxarg;
-EXTERN int32 stksize; // stack size for current frame
-EXTERN int32 blockgen; // max block number
-EXTERN int32 block; // current block number
-EXTERN int hasdefer; // flag that curfn has defer statetment
-
-EXTERN Node* curfn;
-
-EXTERN int widthptr;
-
-EXTERN Node* typesw;
-EXTERN Node* nblank;
-
-extern int thechar;
-extern char* thestring;
-EXTERN char* hunk;
-EXTERN int32 nhunk;
-EXTERN int32 thunk;
-
-EXTERN int exporting;
-EXTERN int erroring;
-EXTERN int noargnames;
-
-EXTERN int funcdepth;
-EXTERN int typecheckok;
-EXTERN int packagequotes;
-EXTERN int longsymnames;
-EXTERN int compiling_runtime;
-
-/*
- * y.tab.c
- */
-int yyparse(void);
-
-/*
- * align.c
- */
-int argsize(Type *t);
-void checkwidth(Type *t);
-void defercheckwidth(void);
-void dowidth(Type *t);
-void resumecheckwidth(void);
-uint32 rnd(uint32 o, uint32 r);
-void typeinit(void);
-
-/*
- * bits.c
- */
-int Qconv(Fmt *fp);
-Bits band(Bits a, Bits b);
-int bany(Bits *a);
-int beq(Bits a, Bits b);
-int bitno(int32 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);
-
-/*
- * closure.c
- */
-Node* closurebody(NodeList *body);
-void closurehdr(Node *ntype);
-void typecheckclosure(Node *func, int top);
-Node* walkclosure(Node *func, NodeList **init);
-void walkcallclosure(Node *n, NodeList **init);
-
-/*
- * const.c
- */
-int cmpslit(Node *l, Node *r);
-int consttype(Node *n);
-void convconst(Node *con, Type *t, Val *val);
-void convlit(Node **np, Type *t);
-void convlit1(Node **np, Type *t, int explicit);
-void defaultlit(Node **np, Type *t);
-void defaultlit2(Node **lp, Node **rp, int force);
-void evconst(Node *n);
-int isconst(Node *n, int ct);
-Node* nodcplxlit(Val r, Val i);
-Node* nodlit(Val v);
-long nonnegconst(Node *n);
-void overflow(Val v, Type *t);
-int smallintconst(Node *n);
-Val toint(Val v);
-Mpflt* truncfltlit(Mpflt *oldv, Type *t);
-
-/*
- * cplx.c
- */
-void complexadd(int op, Node *nl, Node *nr, Node *res);
-void complexbool(int op, Node *nl, Node *nr, int true, Prog *to);
-void complexgen(Node *n, Node *res);
-void complexminus(Node *nl, Node *res);
-void complexmove(Node *f, Node *t);
-void complexmul(Node *nl, Node *nr, Node *res);
-int complexop(Node *n, Node *res);
-void nodfconst(Node *n, Type *t, Mpflt* fval);
-
-/*
- * dcl.c
- */
-void addmethod(Sym *sf, Type *t, int local);
-void addvar(Node *n, Type *t, int ctxt);
-NodeList* checkarglist(NodeList *all, int input);
-Node* colas(NodeList *left, NodeList *right);
-void colasdefn(NodeList *left, Node *defn);
-NodeList* constiter(NodeList *vl, Node *t, NodeList *cl);
-Node* dclname(Sym *s);
-void declare(Node *n, int ctxt);
-Type* dostruct(NodeList *l, int et);
-void dumpdcl(char *st);
-Node* embedded(Sym *s);
-Node* fakethis(void);
-void funcbody(Node *n);
-void funccompile(Node *n, int isclosure);
-void funchdr(Node *n);
-Type* functype(Node *this, NodeList *in, NodeList *out);
-void ifacedcl(Node *n);
-int isifacemethod(Type *f);
-void markdcl(void);
-Node* methodname(Node *n, Type *t);
-Node* methodname1(Node *n, Node *t);
-Sym* methodsym(Sym *nsym, Type *t0, int iface);
-Node* newname(Sym *s);
-Type* newtype(Sym *s);
-Node* oldname(Sym *s);
-void popdcl(void);
-void poptodcl(void);
-void redeclare(Sym *s, char *where);
-void testdclstack(void);
-Node* typedcl0(Sym *s);
-Node* typedcl1(Node *n, Node *t, int local);
-void typedcl2(Type *pt, Type *t);
-Node* typenod(Type *t);
-NodeList* variter(NodeList *vl, Node *t, NodeList *el);
-
-/*
- * export.c
- */
-void autoexport(Node *n, int ctxt);
-void dumpexport(void);
-int exportname(char *s);
-void exportsym(Node *n);
-void importconst(Sym *s, Type *t, Node *n);
-void importmethod(Sym *s, Type *t);
-Sym* importsym(Sym *s, int op);
-void importtype(Type *pt, Type *t);
-void importvar(Sym *s, Type *t, int ctxt);
-Type* pkgtype(Sym *s);
-
-/*
- * gen.c
- */
-void allocparams(void);
-void cgen_as(Node *nl, Node *nr);
-void cgen_callmeth(Node *n, int proc);
-void clearlabels(void);
-void checklabels(void);
-int dotoffset(Node *n, int *oary, Node **nn);
-void gen(Node *n);
-void genlist(NodeList *l);
-Node* sysfunc(char *name);
-void tempname(Node *n, Type *t);
-
-/*
- * init.c
- */
-void fninit(NodeList *n);
-Node* renameinit(Node *n);
-
-/*
- * lex.c
- */
-void cannedimports(char *file, char *cp);
-void importfile(Val *f, int line);
-char* lexname(int lex);
-void mkpackage(char* pkgname);
-void unimportfile(void);
-int32 yylex(void);
-extern int windows;
-extern int yylast;
-extern int yyprev;
-
-/*
- * mparith1.c
- */
-int Bconv(Fmt *fp);
-int Fconv(Fmt *fp);
-void mpaddcfix(Mpint *a, vlong c);
-void mpaddcflt(Mpflt *a, double c);
-void mpatofix(Mpint *a, char *as);
-void mpatoflt(Mpflt *a, char *as);
-int mpcmpfixc(Mpint *b, vlong c);
-int mpcmpfixfix(Mpint *a, Mpint *b);
-int mpcmpfixflt(Mpint *a, Mpflt *b);
-int mpcmpfltc(Mpflt *b, double c);
-int mpcmpfltfix(Mpflt *a, Mpint *b);
-int mpcmpfltflt(Mpflt *a, Mpflt *b);
-void mpcomfix(Mpint *a);
-void mpdivfixfix(Mpint *a, Mpint *b);
-void mpmodfixfix(Mpint *a, Mpint *b);
-void mpmovefixfix(Mpint *a, Mpint *b);
-void mpmovefixflt(Mpflt *a, Mpint *b);
-int mpmovefltfix(Mpint *a, Mpflt *b);
-void mpmovefltflt(Mpflt *a, Mpflt *b);
-void mpmulcfix(Mpint *a, vlong c);
-void mpmulcflt(Mpflt *a, double c);
-void mpsubfixfix(Mpint *a, Mpint *b);
-void mpsubfltflt(Mpflt *a, Mpflt *b);
-
-/*
- * mparith2.c
- */
-void mpaddfixfix(Mpint *a, Mpint *b);
-void mpandfixfix(Mpint *a, Mpint *b);
-void mpandnotfixfix(Mpint *a, Mpint *b);
-void mpdivfract(Mpint *a, Mpint *b);
-void mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d);
-vlong mpgetfix(Mpint *a);
-void mplshfixfix(Mpint *a, Mpint *b);
-void mpmovecfix(Mpint *a, vlong c);
-void mpmulfixfix(Mpint *a, Mpint *b);
-void mpmulfract(Mpint *a, Mpint *b);
-void mpnegfix(Mpint *a);
-void mporfixfix(Mpint *a, Mpint *b);
-void mprshfixfix(Mpint *a, Mpint *b);
-void mpshiftfix(Mpint *a, int s);
-int mptestfix(Mpint *a);
-void mpxorfixfix(Mpint *a, Mpint *b);
-
-/*
- * mparith3.c
- */
-void mpaddfltflt(Mpflt *a, Mpflt *b);
-void mpdivfltflt(Mpflt *a, Mpflt *b);
-double mpgetflt(Mpflt *a);
-void mpmovecflt(Mpflt *a, double c);
-void mpmulfltflt(Mpflt *a, Mpflt *b);
-void mpnegflt(Mpflt *a);
-void mpnorm(Mpflt *a);
-int mptestflt(Mpflt *a);
-int sigfig(Mpflt *a);
-
-/*
- * obj.c
- */
-void Bputname(Biobuf *b, Sym *s);
-int duint16(Sym *s, int off, uint16 v);
-int duint32(Sym *s, int off, uint32 v);
-int duint64(Sym *s, int off, uint64 v);
-int duint8(Sym *s, int off, uint8 v);
-int duintptr(Sym *s, int off, uint64 v);
-int dsname(Sym *s, int off, char *dat, int ndat);
-void dumpobj(void);
-void ieeedtod(uint64 *ieee, double native);
-Sym* stringsym(char*, int);
-
-/*
- * print.c
- */
-void exprfmt(Fmt *f, Node *n, int prec);
-void exprlistfmt(Fmt *f, NodeList *l);
-
-/*
- * range.c
- */
-void typecheckrange(Node *n);
-void walkrange(Node *n);
-
-/*
- * reflect.c
- */
-void dumptypestructs(void);
-Type* methodfunc(Type *f, Type*);
-Node* typename(Type *t);
-Sym* typesym(Type *t);
-
-/*
- * select.c
- */
-void typecheckselect(Node *sel);
-void walkselect(Node *sel);
-
-/*
- * sinit.c
- */
-void anylit(int, Node *n, Node *var, NodeList **init);
-int gen_as_init(Node *n);
-NodeList* initfix(NodeList *l);
-int oaslit(Node *n, NodeList **init);
-int stataddr(Node *nam, Node *n);
-
-/*
- * subr.c
- */
-int Econv(Fmt *fp);
-int Jconv(Fmt *fp);
-int Lconv(Fmt *fp);
-int Nconv(Fmt *fp);
-int Oconv(Fmt *fp);
-int Sconv(Fmt *fp);
-int Tconv(Fmt *fp);
-int Tpretty(Fmt *fp, Type *t);
-int Zconv(Fmt *fp);
-Node* adddot(Node *n);
-int adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase);
-Type* aindex(Node *b, Type *t);
-int algtype(Type *t);
-void argtype(Node *on, Type *t);
-Node* assignconv(Node *n, Type *t, char *context);
-int assignop(Type *src, Type *dst, char **why);
-void badtype(int o, Type *tl, Type *tr);
-int brcom(int a);
-int brrev(int a);
-NodeList* concat(NodeList *a, NodeList *b);
-int convertop(Type *src, Type *dst, char **why);
-int count(NodeList *l);
-int cplxsubtype(int et);
-void dump(char *s, Node *n);
-void dumplist(char *s, NodeList *l);
-int eqtype(Type *t1, Type *t2);
-int eqtypenoname(Type *t1, Type *t2);
-void errorexit(void);
-void expandmeth(Sym *s, Type *t);
-void fatal(char *fmt, ...);
-void flusherrors(void);
-void frame(int context);
-Type* funcfirst(Iter *s, Type *t);
-Type* funcnext(Iter *s);
-void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface);
-Type** getinarg(Type *t);
-Type* getinargx(Type *t);
-Type** getoutarg(Type *t);
-Type* getoutargx(Type *t);
-Type** getthis(Type *t);
-Type* getthisx(Type *t);
-int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr);
-void importdot(Pkg *opkg, Node *pack);
-int is64(Type *t);
-int isblank(Node *n);
-int isfixedarray(Type *t);
-int isideal(Type *t);
-int isinter(Type *t);
-int isnil(Node *n);
-int isnilinter(Type *t);
-int isptrto(Type *t, int et);
-int isselect(Node *n);
-int isslice(Type *t);
-int istype(Type *t, int et);
-void linehist(char *file, int32 off, int relative);
-NodeList* list(NodeList *l, Node *n);
-NodeList* list1(Node *n);
-void listsort(NodeList**, int(*f)(Node*, Node*));
-Node* liststmt(NodeList *l);
-NodeList* listtreecopy(NodeList *l);
-Sym* lookup(char *name);
-void* mal(int32 n);
-Type* maptype(Type *key, Type *val);
-Type* methtype(Type *t);
-Pkg* mkpkg(Strlit *path);
-Sym* ngotype(Node *n);
-int noconv(Type *t1, Type *t2);
-Node* nod(int op, Node *nleft, Node *nright);
-Node* nodbool(int b);
-void nodconst(Node *n, Type *t, int64 v);
-Node* nodintconst(int64 v);
-Node* nodfltconst(Mpflt *v);
-Node* nodnil(void);
-int parserline(void);
-Sym* pkglookup(char *name, Pkg *pkg);
-int powtwo(Node *n);
-Type* ptrto(Type *t);
-void* remal(void *p, int32 on, int32 n);
-Sym* restrictlookup(char *name, Pkg *pkg);
-Node* safeexpr(Node *n, NodeList **init);
-void saveerrors(void);
-Node* cheapexpr(Node *n, NodeList **init);
-int32 setlineno(Node *n);
-void setmaxarg(Type *t);
-Type* shallow(Type *t);
-int simsimtype(Type *t);
-void smagic(Magic *m);
-Type* sortinter(Type *t);
-uint32 stringhash(char *p);
-Strlit* strlit(char *s);
-int structcount(Type *t);
-Type* structfirst(Iter *s, Type **nn);
-Type* structnext(Iter *s);
-Node* syslook(char *name, int copy);
-Type* tounsigned(Type *t);
-Node* treecopy(Node *n);
-Type* typ(int et);
-uint32 typehash(Type *t);
-void ullmancalc(Node *n);
-void umagic(Magic *m);
-void warn(char *fmt, ...);
-void yyerror(char *fmt, ...);
-void yyerrorl(int line, char *fmt, ...);
-
-/*
- * swt.c
- */
-void typecheckswitch(Node *n);
-void walkswitch(Node *sw);
-
-/*
- * typecheck.c
- */
-int exportassignok(Type *t, char *desc);
-int islvalue(Node *n);
-Node* typecheck(Node **np, int top);
-void typechecklist(NodeList *l, int top);
-Node* typecheckdef(Node *n);
-void resumetypecopy(void);
-void copytype(Node *n, Type *t);
-void defertypecopy(Node *n, Type *t);
-void queuemethod(Node *n);
-
-/*
- * unsafe.c
- */
-Node* unsafenmagic(Node *n);
-
-/*
- * walk.c
- */
-Node* callnew(Type *t);
-Node* chanfn(char *name, int n, Type *t);
-Node* mkcall(char *name, Type *t, NodeList **init, ...);
-Node* mkcall1(Node *fn, Type *t, NodeList **init, ...);
-int vmatch1(Node *l, Node *r);
-void walk(Node *fn);
-void walkexpr(Node **np, NodeList **init);
-void walkexprlist(NodeList *l, NodeList **init);
-void walkexprlistsafe(NodeList *l, NodeList **init);
-void walkstmt(Node **np);
-void walkstmtlist(NodeList *l);
-
-/*
- * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c
- */
-#define P ((Prog*)0)
-
-typedef struct Plist Plist;
-struct Plist
-{
- Node* name;
- Prog* firstpc;
- int recur;
- Plist* link;
-};
-
-EXTERN Plist* plist;
-EXTERN Plist* plast;
-
-EXTERN Prog* continpc;
-EXTERN Prog* breakpc;
-EXTERN Prog* pc;
-EXTERN Prog* firstpc;
-EXTERN Prog* retpc;
-
-EXTERN Node* nodfp;
-
-int anyregalloc(void);
-void betypeinit(void);
-void bgen(Node *n, int true, Prog *to);
-void cgen(Node*, Node*);
-void cgen_asop(Node *n);
-void cgen_call(Node *n, int proc);
-void cgen_callinter(Node *n, Node *res, int proc);
-void cgen_ret(Node *n);
-void clearfat(Node *n);
-void compile(Node*);
-void defframe(Prog*);
-int dgostringptr(Sym*, int off, char *str);
-int dgostrlitptr(Sym*, int off, Strlit*);
-int dstringptr(Sym *s, int off, char *str);
-int dsymptr(Sym *s, int off, Sym *x, int xoff);
-int duintxx(Sym *s, int off, uint64 v, int wid);
-void dumpdata(void);
-void dumpfuncs(void);
-void fixautoused(Prog*);
-void gdata(Node*, Node*, int);
-void gdatacomplex(Node*, Mpcplx*);
-void gdatastring(Node*, Strlit*);
-void genembedtramp(Type*, Type*, Sym*, int iface);
-void ggloblnod(Node *nam, int32 width);
-void ggloblsym(Sym *s, int32 width, int dupok);
-Prog* gjmp(Prog*);
-void gused(Node*);
-int isfat(Type*);
-void markautoused(Prog*);
-Plist* newplist(void);
-Node* nodarg(Type*, int);
-void nopout(Prog*);
-void patch(Prog*, Prog*);
-Prog* unpatch(Prog*);
-void zfile(Biobuf *b, char *p, int n);
-void zhist(Biobuf *b, int line, vlong offset);
-void zname(Biobuf *b, Sym *s, int t);
-void data(void);
-void text(void);
-
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
deleted file mode 100644
index 01a4e822f..000000000
--- a/src/cmd/gc/go.y
+++ /dev/null
@@ -1,1966 +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.
-
-/*
- * Go language grammar.
- *
- * The Go semicolon rules are:
- *
- * 1. all statements and declarations are terminated by semicolons.
- * 2. semicolons can be omitted before a closing ) or }.
- * 3. semicolons are inserted by the lexer before a newline
- * following a specific list of tokens.
- *
- * Rules #1 and #2 are accomplished by writing the lists as
- * semicolon-separated lists with an optional trailing semicolon.
- * Rule #3 is implemented in yylex.
- */
-
-%{
-#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
-#include "go.h"
-
-static void fixlbrace(int);
-%}
-%union {
- Node* node;
- NodeList* list;
- Type* type;
- Sym* sym;
- struct Val val;
- int lint;
-}
-
-// |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /'
-
-%token <val> LLITERAL
-%token <lint> LASOP
-%token <sym> LBREAK LCASE LCHAN LCOLAS LCONST LCONTINUE LDDD
-%token <sym> LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO
-%token <sym> LIF LIMPORT LINTERFACE LMAP LNAME
-%token <sym> LPACKAGE LRANGE LRETURN LSELECT LSTRUCT LSWITCH
-%token <sym> LTYPE LVAR
-
-%token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT
-%token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH
-
-%type <lint> lbrace import_here
-%type <sym> sym packname
-%type <val> oliteral
-
-%type <node> stmt ntype
-%type <node> arg_type
-%type <node> case caseblock
-%type <node> compound_stmt dotname embed expr complitexpr
-%type <node> expr_or_type
-%type <node> fndcl fnliteral
-%type <node> for_body for_header for_stmt if_header if_stmt non_dcl_stmt
-%type <node> interfacedcl keyval labelname name
-%type <node> name_or_type non_expr_type
-%type <node> new_name dcl_name oexpr typedclname
-%type <node> onew_name
-%type <node> osimple_stmt pexpr pexpr_no_paren
-%type <node> pseudocall range_stmt select_stmt
-%type <node> simple_stmt
-%type <node> switch_stmt uexpr
-%type <node> xfndcl typedcl
-
-%type <list> xdcl fnbody fnres loop_body dcl_name_list
-%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
-%type <list> oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
-%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
-%type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list
-
-%type <node> convtype comptype dotdotdot
-%type <node> indcl interfacetype structtype ptrtype
-%type <node> recvchantype non_recvchantype othertype fnret_type fntype
-
-%type <val> hidden_tag
-
-%type <sym> hidden_importsym hidden_pkg_importsym
-
-%type <node> hidden_constant hidden_literal hidden_dcl
-%type <node> hidden_interfacedcl hidden_structdcl hidden_opt_sym
-
-%type <list> hidden_funres
-%type <list> ohidden_funres
-%type <list> hidden_funarg_list ohidden_funarg_list
-%type <list> hidden_interfacedcl_list ohidden_interfacedcl_list
-%type <list> hidden_structdcl_list ohidden_structdcl_list
-
-%type <type> hidden_type hidden_type_misc hidden_pkgtype
-%type <type> hidden_type_func
-%type <type> hidden_type_recv_chan hidden_type_non_recv_chan
-
-%left LCOMM /* outside the usual hierarchy; here for good error messages */
-
-%left LOROR
-%left LANDAND
-%left LEQ LNE LLE LGE LLT LGT
-%left '+' '-' '|' '^'
-%left '*' '/' '%' '&' LLSH LRSH LANDNOT
-
-/*
- * manual override of shift/reduce conflicts.
- * the general form is that we assign a precedence
- * to the token being shifted and then introduce
- * NotToken with lower precedence or PreferToToken with higher
- * and annotate the reducing rule accordingly.
- */
-%left NotPackage
-%left LPACKAGE
-
-%left NotParen
-%left '('
-
-%left ')'
-%left PreferToRightParen
-
-%error-verbose
-
-%%
-file:
- loadsys
- package
- imports
- xdcl_list
- {
- xtop = concat(xtop, $4);
- }
-
-package:
- %prec NotPackage
- {
- prevlineno = lineno;
- yyerror("package statement must be first");
- flusherrors();
- mkpackage("main");
- }
-| LPACKAGE sym ';'
- {
- mkpackage($2->name);
- }
-
-/*
- * this loads the definitions for the low-level runtime functions,
- * so that the compiler can generate calls to them,
- * but does not make the name "runtime" visible as a package.
- */
-loadsys:
- {
- importpkg = runtimepkg;
-
- if(debug['A'])
- cannedimports("runtime.builtin", "package runtime\n\n$$\n\n");
- else
- cannedimports("runtime.builtin", runtimeimport);
- curio.importsafe = 1;
- }
- import_package
- import_there
- {
- importpkg = nil;
- }
-
-imports:
-| imports import ';'
-
-import:
- LIMPORT import_stmt
-| LIMPORT '(' import_stmt_list osemi ')'
-| LIMPORT '(' ')'
-
-import_stmt:
- import_here import_package import_there
- {
- Pkg *ipkg;
- Sym *my;
- Node *pack;
-
- ipkg = importpkg;
- my = importmyname;
- importpkg = nil;
- importmyname = S;
-
- if(my == nil)
- my = lookup(ipkg->name);
-
- pack = nod(OPACK, N, N);
- pack->sym = my;
- pack->pkg = ipkg;
- pack->lineno = $1;
-
- if(my->name[0] == '.') {
- importdot(ipkg, pack);
- break;
- }
- if(my->name[0] == '_' && my->name[1] == '\0')
- break;
- if(my->def) {
- lineno = $1;
- redeclare(my, "as imported package name");
- }
- my->def = pack;
- my->lastlineno = $1;
- my->block = 1; // at top level
- }
-
-
-import_stmt_list:
- import_stmt
-| import_stmt_list ';' import_stmt
-
-import_here:
- LLITERAL
- {
- // import with original name
- $$ = parserline();
- importmyname = S;
- importfile(&$1, $$);
- }
-| sym LLITERAL
- {
- // import with given name
- $$ = parserline();
- importmyname = $1;
- importfile(&$2, $$);
- }
-| '.' LLITERAL
- {
- // import into my name space
- $$ = parserline();
- importmyname = lookup(".");
- importfile(&$2, $$);
- }
-
-import_package:
- LPACKAGE sym import_safety ';'
- {
- if(importpkg->name == nil) {
- importpkg->name = $2->name;
- pkglookup($2->name, nil)->npkg++;
- } else if(strcmp(importpkg->name, $2->name) != 0)
- yyerror("conflicting names %s and %s for package %Z", importpkg->name, $2->name, importpkg->path);
- importpkg->direct = 1;
-
- if(safemode && !curio.importsafe)
- yyerror("cannot import unsafe package %Z", importpkg->path);
- }
-
-import_safety:
-| LNAME
- {
- if(strcmp($1->name, "safe") == 0)
- curio.importsafe = 1;
- }
-
-import_there:
- {
- defercheckwidth();
- }
- hidden_import_list '$' '$'
- {
- resumecheckwidth();
- unimportfile();
- }
-
-/*
- * declarations
- */
-xdcl:
- {
- yyerror("empty top-level declaration");
- $$ = nil;
- }
-| common_dcl
-| xfndcl
- {
- $$ = list1($1);
- }
-| non_dcl_stmt
- {
- yyerror("non-declaration statement outside function body");
- $$ = nil;
- }
-| error
- {
- $$ = nil;
- }
-
-common_dcl:
- LVAR vardcl
- {
- $$ = $2;
- }
-| LVAR '(' vardcl_list osemi ')'
- {
- $$ = $3;
- }
-| LVAR '(' ')'
- {
- $$ = nil;
- }
-| lconst constdcl
- {
- $$ = $2;
- iota = -100000;
- lastconst = nil;
- }
-| lconst '(' constdcl osemi ')'
- {
- $$ = $3;
- iota = -100000;
- lastconst = nil;
- }
-| lconst '(' constdcl ';' constdcl_list osemi ')'
- {
- $$ = concat($3, $5);
- iota = -100000;
- lastconst = nil;
- }
-| lconst '(' ')'
- {
- $$ = nil;
- iota = -100000;
- }
-| LTYPE typedcl
- {
- $$ = list1($2);
- }
-| LTYPE '(' typedcl_list osemi ')'
- {
- $$ = $3;
- }
-| LTYPE '(' ')'
- {
- $$ = nil;
- }
-
-lconst:
- LCONST
- {
- iota = 0;
- }
-
-vardcl:
- dcl_name_list ntype
- {
- $$ = variter($1, $2, nil);
- }
-| dcl_name_list ntype '=' expr_list
- {
- $$ = variter($1, $2, $4);
- }
-| dcl_name_list '=' expr_list
- {
- $$ = variter($1, nil, $3);
- }
-
-constdcl:
- dcl_name_list ntype '=' expr_list
- {
- $$ = constiter($1, $2, $4);
- }
-| dcl_name_list '=' expr_list
- {
- $$ = constiter($1, N, $3);
- }
-
-constdcl1:
- constdcl
-| dcl_name_list ntype
- {
- $$ = constiter($1, $2, nil);
- }
-| dcl_name_list
- {
- $$ = constiter($1, N, nil);
- }
-
-typedclname:
- sym
- {
- // different from dclname because the name
- // becomes visible right here, not at the end
- // of the declaration.
- $$ = typedcl0($1);
- }
-
-typedcl:
- typedclname ntype
- {
- $$ = typedcl1($1, $2, 1);
- }
-
-simple_stmt:
- expr
- {
- $$ = $1;
- }
-| expr LASOP expr
- {
- $$ = nod(OASOP, $1, $3);
- $$->etype = $2; // rathole to pass opcode
- }
-| expr_list '=' expr_list
- {
- if($1->next == nil && $3->next == nil) {
- // simple
- $$ = nod(OAS, $1->n, $3->n);
- break;
- }
- // multiple
- $$ = nod(OAS2, N, N);
- $$->list = $1;
- $$->rlist = $3;
- }
-| expr_list LCOLAS expr_list
- {
- if($3->n->op == OTYPESW) {
- Node *n;
-
- n = N;
- if($3->next != nil)
- yyerror("expr.(type) must be alone in list");
- if($1->next != nil)
- yyerror("argument count mismatch: %d = %d", count($1), 1);
- else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME)
- yyerror("invalid variable name %#N in type switch", $1->n);
- else
- n = $1->n;
- $$ = nod(OTYPESW, n, $3->n->right);
- break;
- }
- $$ = colas($1, $3);
- }
-| expr LINC
- {
- $$ = nod(OASOP, $1, nodintconst(1));
- $$->etype = OADD;
- }
-| expr LDEC
- {
- $$ = nod(OASOP, $1, nodintconst(1));
- $$->etype = OSUB;
- }
-
-case:
- LCASE expr_or_type_list ':'
- {
- Node *n;
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- $$ = nod(OXCASE, N, N);
- $$->list = $2;
- if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
- // type switch - declare variable
- n = newname(n->sym);
- n->used = 1; // TODO(rsc): better job here
- declare(n, dclcontext);
- $$->nname = n;
- }
- break;
- }
-| LCASE expr_or_type_list '=' expr ':'
- {
- Node *n;
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- $$ = nod(OXCASE, N, N);
- if($2->next == nil)
- n = nod(OAS, $2->n, $4);
- else {
- n = nod(OAS2, N, N);
- n->list = $2;
- n->rlist = list1($4);
- }
- $$->list = list1(n);
- }
-| LCASE expr_or_type_list LCOLAS expr ':'
- {
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- $$ = nod(OXCASE, N, N);
- $$->list = list1(colas($2, list1($4)));
- }
-| LDEFAULT ':'
- {
- Node *n;
-
- markdcl();
- $$ = nod(OXCASE, N, N);
- if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
- // type switch - declare variable
- n = newname(n->sym);
- n->used = 1; // TODO(rsc): better job here
- declare(n, dclcontext);
- $$->nname = n;
- }
- }
-
-compound_stmt:
- '{'
- {
- markdcl();
- }
- stmt_list '}'
- {
- $$ = liststmt($3);
- popdcl();
- }
-
-caseblock:
- case
- {
- // If the last token read by the lexer was consumed
- // as part of the case, clear it (parser has cleared yychar).
- // If the last token read by the lexer was the lookahead
- // leave it alone (parser has it cached in yychar).
- // This is so that the stmt_list action doesn't look at
- // the case tokens if the stmt_list is empty.
- yylast = yychar;
- }
- stmt_list
- {
- int last;
-
- // This is the only place in the language where a statement
- // list is not allowed to drop the final semicolon, because
- // it's the only place where a statement list is not followed
- // by a closing brace. Handle the error for pedantry.
-
- // Find the final token of the statement list.
- // yylast is lookahead; yyprev is last of stmt_list
- last = yyprev;
-
- if(last > 0 && last != ';' && yychar != '}')
- yyerror("missing statement after label");
- $$ = $1;
- $$->nbody = $3;
- popdcl();
- }
-
-caseblock_list:
- {
- $$ = nil;
- }
-| caseblock_list caseblock
- {
- $$ = list($1, $2);
- }
-
-loop_body:
- LBODY
- {
- markdcl();
- }
- stmt_list '}'
- {
- $$ = $3;
- popdcl();
- }
-
-range_stmt:
- expr_list '=' LRANGE expr
- {
- $$ = nod(ORANGE, N, $4);
- $$->list = $1;
- $$->etype = 0; // := flag
- }
-| expr_list LCOLAS LRANGE expr
- {
- $$ = nod(ORANGE, N, $4);
- $$->list = $1;
- $$->colas = 1;
- colasdefn($1, $$);
- }
-
-for_header:
- osimple_stmt ';' osimple_stmt ';' osimple_stmt
- {
- // init ; test ; incr
- if($5 != N && $5->colas != 0)
- yyerror("cannot declare in the for-increment");
- $$ = nod(OFOR, N, N);
- if($1 != N)
- $$->ninit = list1($1);
- $$->ntest = $3;
- $$->nincr = $5;
- }
-| osimple_stmt
- {
- // normal test
- $$ = nod(OFOR, N, N);
- $$->ntest = $1;
- }
-| range_stmt
-
-for_body:
- for_header loop_body
- {
- $$ = $1;
- $$->nbody = concat($$->nbody, $2);
- }
-
-for_stmt:
- LFOR
- {
- markdcl();
- }
- for_body
- {
- $$ = $3;
- popdcl();
- }
-
-if_header:
- osimple_stmt
- {
- // test
- $$ = nod(OIF, N, N);
- $$->ntest = $1;
- }
-| osimple_stmt ';' osimple_stmt
- {
- // init ; test
- $$ = nod(OIF, N, N);
- if($1 != N)
- $$->ninit = list1($1);
- $$->ntest = $3;
- }
-
-if_stmt:
- LIF
- {
- markdcl();
- }
- if_header
- {
- if($3->ntest == N)
- yyerror("missing condition in if statement");
- }
- loop_body
- {
- $$ = $3;
- $$->nbody = $5;
- // no popdcl; maybe there's an LELSE
- }
-
-switch_stmt:
- LSWITCH
- {
- markdcl();
- }
- if_header
- {
- Node *n;
- n = $3->ntest;
- if(n != N && n->op != OTYPESW)
- n = N;
- typesw = nod(OXXX, typesw, n);
- }
- LBODY caseblock_list '}'
- {
- $$ = $3;
- $$->op = OSWITCH;
- $$->list = $6;
- typesw = typesw->left;
- popdcl();
- }
-
-select_stmt:
- LSELECT
- {
- typesw = nod(OXXX, typesw, N);
- }
- LBODY caseblock_list '}'
- {
- $$ = nod(OSELECT, N, N);
- $$->list = $4;
- typesw = typesw->left;
- }
-
-/*
- * expressions
- */
-expr:
- uexpr
-| expr LOROR expr
- {
- $$ = nod(OOROR, $1, $3);
- }
-| expr LANDAND expr
- {
- $$ = nod(OANDAND, $1, $3);
- }
-| expr LEQ expr
- {
- $$ = nod(OEQ, $1, $3);
- }
-| expr LNE expr
- {
- $$ = nod(ONE, $1, $3);
- }
-| expr LLT expr
- {
- $$ = nod(OLT, $1, $3);
- }
-| expr LLE expr
- {
- $$ = nod(OLE, $1, $3);
- }
-| expr LGE expr
- {
- $$ = nod(OGE, $1, $3);
- }
-| expr LGT expr
- {
- $$ = nod(OGT, $1, $3);
- }
-| expr '+' expr
- {
- $$ = nod(OADD, $1, $3);
- }
-| expr '-' expr
- {
- $$ = nod(OSUB, $1, $3);
- }
-| expr '|' expr
- {
- $$ = nod(OOR, $1, $3);
- }
-| expr '^' expr
- {
- $$ = nod(OXOR, $1, $3);
- }
-| expr '*' expr
- {
- $$ = nod(OMUL, $1, $3);
- }
-| expr '/' expr
- {
- $$ = nod(ODIV, $1, $3);
- }
-| expr '%' expr
- {
- $$ = nod(OMOD, $1, $3);
- }
-| expr '&' expr
- {
- $$ = nod(OAND, $1, $3);
- }
-| expr LANDNOT expr
- {
- $$ = nod(OANDNOT, $1, $3);
- }
-| expr LLSH expr
- {
- $$ = nod(OLSH, $1, $3);
- }
-| expr LRSH expr
- {
- $$ = nod(ORSH, $1, $3);
- }
- /* not an expression anymore, but left in so we can give a good error */
-| expr LCOMM expr
- {
- $$ = nod(OSEND, $1, $3);
- }
-
-uexpr:
- pexpr
-| '*' uexpr
- {
- $$ = nod(OIND, $2, N);
- }
-| '&' uexpr
- {
- $$ = nod(OADDR, $2, N);
- }
-| '+' uexpr
- {
- $$ = nod(OPLUS, $2, N);
- }
-| '-' uexpr
- {
- $$ = nod(OMINUS, $2, N);
- }
-| '!' uexpr
- {
- $$ = nod(ONOT, $2, N);
- }
-| '~' uexpr
- {
- yyerror("the bitwise complement operator is ^");
- $$ = nod(OCOM, $2, N);
- }
-| '^' uexpr
- {
- $$ = nod(OCOM, $2, N);
- }
-| LCOMM uexpr
- {
- $$ = nod(ORECV, $2, N);
- }
-
-/*
- * call-like statements that
- * can be preceded by 'defer' and 'go'
- */
-pseudocall:
- pexpr '(' ')'
- {
- $$ = nod(OCALL, $1, N);
- }
-| pexpr '(' expr_or_type_list ocomma ')'
- {
- $$ = nod(OCALL, $1, N);
- $$->list = $3;
- }
-| pexpr '(' expr_or_type_list LDDD ocomma ')'
- {
- $$ = nod(OCALL, $1, N);
- $$->list = $3;
- $$->isddd = 1;
- }
-
-pexpr_no_paren:
- LLITERAL
- {
- $$ = nodlit($1);
- }
-| name
-| pexpr '.' sym
- {
- if($1->op == OPACK) {
- Sym *s;
- s = restrictlookup($3->name, $1->pkg);
- $1->used = 1;
- $$ = oldname(s);
- break;
- }
- $$ = nod(OXDOT, $1, newname($3));
- }
-| pexpr '.' '(' expr_or_type ')'
- {
- $$ = nod(ODOTTYPE, $1, $4);
- }
-| pexpr '.' '(' LTYPE ')'
- {
- $$ = nod(OTYPESW, N, $1);
- }
-| pexpr '[' expr ']'
- {
- $$ = nod(OINDEX, $1, $3);
- }
-| pexpr '[' oexpr ':' oexpr ']'
- {
- $$ = nod(OSLICE, $1, nod(OKEY, $3, $5));
- }
-| pseudocall
-| convtype '(' expr ')'
- {
- // conversion
- $$ = nod(OCALL, $1, N);
- $$->list = list1($3);
- }
-| comptype lbrace braced_keyval_list '}'
- {
- // composite expression
- $$ = nod(OCOMPLIT, N, $1);
- $$->list = $3;
-
- fixlbrace($2);
- }
-| pexpr_no_paren '{' braced_keyval_list '}'
- {
- // composite expression
- $$ = nod(OCOMPLIT, N, $1);
- $$->list = $3;
- }
-| '(' expr_or_type ')' '{' braced_keyval_list '}'
- {
- yyerror("cannot parenthesize type in composite literal");
- // composite expression
- $$ = nod(OCOMPLIT, N, $2);
- $$->list = $5;
- }
-| fnliteral
-
-keyval:
- expr ':' complitexpr
- {
- $$ = nod(OKEY, $1, $3);
- }
-
-complitexpr:
- expr
-| '{' braced_keyval_list '}'
- {
- $$ = nod(OCOMPLIT, N, N);
- $$->list = $2;
- }
-
-pexpr:
- pexpr_no_paren
-| '(' expr_or_type ')'
- {
- $$ = $2;
- }
-
-expr_or_type:
- expr
-| non_expr_type %prec PreferToRightParen
-
-name_or_type:
- ntype
-
-lbrace:
- LBODY
- {
- $$ = LBODY;
- }
-| '{'
- {
- $$ = '{';
- }
-
-/*
- * names and types
- * newname is used before declared
- * oldname is used after declared
- */
-new_name:
- sym
- {
- $$ = newname($1);
- }
-
-dcl_name:
- sym
- {
- $$ = dclname($1);
- }
-
-onew_name:
- {
- $$ = N;
- }
-| new_name
-
-sym:
- LNAME
-
-name:
- sym %prec NotParen
- {
- $$ = oldname($1);
- if($$->pack != N)
- $$->pack->used = 1;
- }
-
-labelname:
- new_name
-
-/*
- * to avoid parsing conflicts, type is split into
- * channel types
- * function types
- * parenthesized types
- * any other type
- * the type system makes additional restrictions,
- * but those are not implemented in the grammar.
- */
-dotdotdot:
- LDDD
- {
- yyerror("final argument in variadic function missing type");
- $$ = nod(ODDD, typenod(typ(TINTER)), N);
- }
-| LDDD ntype
- {
- $$ = nod(ODDD, $2, N);
- }
-
-ntype:
- recvchantype
-| fntype
-| othertype
-| ptrtype
-| dotname
-| '(' ntype ')'
- {
- $$ = nod(OTPAREN, $2, N);
- }
-
-non_expr_type:
- recvchantype
-| fntype
-| othertype
-| '*' non_expr_type
- {
- $$ = nod(OIND, $2, N);
- }
-
-non_recvchantype:
- fntype
-| othertype
-| ptrtype
-| dotname
-| '(' ntype ')'
- {
- $$ = nod(OTPAREN, $2, N);
- }
-
-convtype:
- fntype
-| othertype
-
-comptype:
- othertype
-
-fnret_type:
- recvchantype
-| fntype
-| othertype
-| ptrtype
-| dotname
-
-dotname:
- name
-| name '.' sym
- {
- if($1->op == OPACK) {
- Sym *s;
- s = restrictlookup($3->name, $1->pkg);
- $1->used = 1;
- $$ = oldname(s);
- break;
- }
- $$ = nod(OXDOT, $1, newname($3));
- }
-
-othertype:
- '[' oexpr ']' ntype
- {
- $$ = nod(OTARRAY, $2, $4);
- }
-| '[' LDDD ']' ntype
- {
- // array literal of nelem
- $$ = nod(OTARRAY, nod(ODDD, N, N), $4);
- }
-| LCHAN non_recvchantype
- {
- $$ = nod(OTCHAN, $2, N);
- $$->etype = Cboth;
- }
-| LCHAN LCOMM ntype
- {
- $$ = nod(OTCHAN, $3, N);
- $$->etype = Csend;
- }
-| LMAP '[' ntype ']' ntype
- {
- $$ = nod(OTMAP, $3, $5);
- }
-| structtype
-| interfacetype
-
-ptrtype:
- '*' ntype
- {
- $$ = nod(OIND, $2, N);
- }
-
-recvchantype:
- LCOMM LCHAN ntype
- {
- $$ = nod(OTCHAN, $3, N);
- $$->etype = Crecv;
- }
-
-structtype:
- LSTRUCT lbrace structdcl_list osemi '}'
- {
- $$ = nod(OTSTRUCT, N, N);
- $$->list = $3;
- fixlbrace($2);
- }
-| LSTRUCT lbrace '}'
- {
- $$ = nod(OTSTRUCT, N, N);
- fixlbrace($2);
- }
-
-interfacetype:
- LINTERFACE lbrace interfacedcl_list osemi '}'
- {
- $$ = nod(OTINTER, N, N);
- $$->list = $3;
- fixlbrace($2);
- }
-| LINTERFACE lbrace '}'
- {
- $$ = nod(OTINTER, N, N);
- fixlbrace($2);
- }
-
-/*
- * function stuff
- * all in one place to show how crappy it all is
- */
-xfndcl:
- LFUNC fndcl fnbody
- {
- $$ = $2;
- if($$ == N)
- break;
- $$->nbody = $3;
- $$->endlineno = lineno;
- funcbody($$);
- }
-
-fndcl:
- dcl_name '(' oarg_type_list_ocomma ')' fnres
- {
- Node *n;
-
- $3 = checkarglist($3, 1);
- $$ = nod(ODCLFUNC, N, N);
- $$->nname = $1;
- n = nod(OTFUNC, N, N);
- n->list = $3;
- n->rlist = $5;
- if(strcmp($1->sym->name, "init") == 0) {
- $$->nname = renameinit($1);
- if($3 != nil || $5 != nil)
- yyerror("func init must have no arguments and no return values");
- }
- if(strcmp(localpkg->name, "main") == 0 && strcmp($1->sym->name, "main") == 0) {
- if($3 != nil || $5 != nil)
- yyerror("func main must have no arguments and no return values");
- }
- // TODO: check if nname already has an ntype
- $$->nname->ntype = n;
- funchdr($$);
- }
-| '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
- {
- Node *rcvr, *t;
- Node *name;
-
- name = newname($4);
- $2 = checkarglist($2, 0);
- $6 = checkarglist($6, 1);
- $$ = N;
- if($2 == nil) {
- yyerror("method has no receiver");
- break;
- }
- if($2->next != nil) {
- yyerror("method has multiple receivers");
- break;
- }
- rcvr = $2->n;
- if(rcvr->op != ODCLFIELD) {
- yyerror("bad receiver in method");
- break;
- }
- if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN))
- yyerror("cannot parenthesize receiver type");
-
- $$ = nod(ODCLFUNC, N, N);
- $$->nname = methodname1(name, rcvr->right);
- t = nod(OTFUNC, rcvr, N);
- t->list = $6;
- t->rlist = $8;
- $$->nname->ntype = t;
- $$->shortname = name;
- funchdr($$);
- }
-
-fntype:
- LFUNC '(' oarg_type_list_ocomma ')' fnres
- {
- $3 = checkarglist($3, 1);
- $$ = nod(OTFUNC, N, N);
- $$->list = $3;
- $$->rlist = $5;
- }
-
-fnbody:
- {
- $$ = nil;
- }
-| '{' stmt_list '}'
- {
- $$ = $2;
- if($$ == nil)
- $$ = list1(nod(OEMPTY, N, N));
- }
-
-fnres:
- %prec NotParen
- {
- $$ = nil;
- }
-| fnret_type
- {
- $$ = list1(nod(ODCLFIELD, N, $1));
- }
-| '(' oarg_type_list_ocomma ')'
- {
- $2 = checkarglist($2, 0);
- $$ = $2;
- }
-
-fnlitdcl:
- fntype
- {
- closurehdr($1);
- }
-
-fnliteral:
- fnlitdcl lbrace stmt_list '}'
- {
- $$ = closurebody($3);
- fixlbrace($2);
- }
-
-
-/*
- * lists of things
- * note that they are left recursive
- * to conserve yacc stack. they need to
- * be reversed to interpret correctly
- */
-xdcl_list:
- {
- $$ = nil;
- }
-| xdcl_list xdcl ';'
- {
- $$ = concat($1, $2);
- if(nsyntaxerrors == 0)
- testdclstack();
- }
-
-vardcl_list:
- vardcl
-| vardcl_list ';' vardcl
- {
- $$ = concat($1, $3);
- }
-
-constdcl_list:
- constdcl1
-| constdcl_list ';' constdcl1
- {
- $$ = concat($1, $3);
- }
-
-typedcl_list:
- typedcl
- {
- $$ = list1($1);
- }
-| typedcl_list ';' typedcl
- {
- $$ = list($1, $3);
- }
-
-structdcl_list:
- structdcl
-| structdcl_list ';' structdcl
- {
- $$ = concat($1, $3);
- }
-
-interfacedcl_list:
- interfacedcl
- {
- $$ = list1($1);
- }
-| interfacedcl_list ';' interfacedcl
- {
- $$ = list($1, $3);
- }
-
-structdcl:
- new_name_list ntype oliteral
- {
- NodeList *l;
-
- for(l=$1; l; l=l->next) {
- l->n = nod(ODCLFIELD, l->n, $2);
- l->n->val = $3;
- }
- }
-| embed oliteral
- {
- $1->val = $2;
- $$ = list1($1);
- }
-| '(' embed ')' oliteral
- {
- $2->val = $4;
- $$ = list1($2);
- yyerror("cannot parenthesize embedded type");
- }
-| '*' embed oliteral
- {
- $2->right = nod(OIND, $2->right, N);
- $2->val = $3;
- $$ = list1($2);
- }
-| '(' '*' embed ')' oliteral
- {
- $3->right = nod(OIND, $3->right, N);
- $3->val = $5;
- $$ = list1($3);
- yyerror("cannot parenthesize embedded type");
- }
-| '*' '(' embed ')' oliteral
- {
- $3->right = nod(OIND, $3->right, N);
- $3->val = $5;
- $$ = list1($3);
- yyerror("cannot parenthesize embedded type");
- }
-
-packname:
- LNAME
- {
- Node *n;
-
- $$ = $1;
- n = oldname($1);
- if(n->pack != N)
- n->pack->used = 1;
- }
-| LNAME '.' sym
- {
- Pkg *pkg;
-
- if($1->def == N || $1->def->op != OPACK) {
- yyerror("%S is not a package", $1);
- pkg = localpkg;
- } else {
- $1->def->used = 1;
- pkg = $1->def->pkg;
- }
- $$ = restrictlookup($3->name, pkg);
- }
-
-embed:
- packname
- {
- $$ = embedded($1);
- }
-
-interfacedcl:
- new_name indcl
- {
- $$ = nod(ODCLFIELD, $1, $2);
- ifacedcl($$);
- }
-| packname
- {
- $$ = nod(ODCLFIELD, N, oldname($1));
- }
-| '(' packname ')'
- {
- $$ = nod(ODCLFIELD, N, oldname($2));
- yyerror("cannot parenthesize embedded type");
- }
-
-indcl:
- '(' oarg_type_list_ocomma ')' fnres
- {
- // without func keyword
- $2 = checkarglist($2, 1);
- $$ = nod(OTFUNC, fakethis(), N);
- $$->list = $2;
- $$->rlist = $4;
- }
-
-/*
- * function arguments.
- */
-arg_type:
- name_or_type
-| sym name_or_type
- {
- $$ = nod(ONONAME, N, N);
- $$->sym = $1;
- $$ = nod(OKEY, $$, $2);
- }
-| sym dotdotdot
- {
- $$ = nod(ONONAME, N, N);
- $$->sym = $1;
- $$ = nod(OKEY, $$, $2);
- }
-| dotdotdot
-
-arg_type_list:
- arg_type
- {
- $$ = list1($1);
- }
-| arg_type_list ',' arg_type
- {
- $$ = list($1, $3);
- }
-
-oarg_type_list_ocomma:
- {
- $$ = nil;
- }
-| arg_type_list ocomma
- {
- $$ = $1;
- }
-
-/*
- * statement
- */
-stmt:
- {
- $$ = N;
- }
-| compound_stmt
-| common_dcl
- {
- $$ = liststmt($1);
- }
-| non_dcl_stmt
-| error
- {
- $$ = N;
- }
-
-non_dcl_stmt:
- simple_stmt
-| for_stmt
-| switch_stmt
-| select_stmt
-| if_stmt
- {
- popdcl();
- $$ = $1;
- }
-| if_stmt LELSE stmt
- {
- popdcl();
- $$ = $1;
- $$->nelse = list1($3);
- }
-| labelname ':'
- {
- $1 = nod(OLABEL, $1, N);
- $1->sym = dclstack; // context, for goto restrictions
- }
- stmt
- {
- NodeList *l;
-
- $1->right = $4;
- l = list1($1);
- if($4)
- l = list(l, $4);
- $$ = liststmt(l);
- }
-| LFALL
- {
- // will be converted to OFALL
- $$ = nod(OXFALL, N, N);
- }
-| LBREAK onew_name
- {
- $$ = nod(OBREAK, $2, N);
- }
-| LCONTINUE onew_name
- {
- $$ = nod(OCONTINUE, $2, N);
- }
-| LGO pseudocall
- {
- $$ = nod(OPROC, $2, N);
- }
-| LDEFER pseudocall
- {
- $$ = nod(ODEFER, $2, N);
- }
-| LGOTO new_name
- {
- $$ = nod(OGOTO, $2, N);
- $$->sym = dclstack; // context, for goto restrictions
- }
-| LRETURN oexpr_list
- {
- $$ = nod(ORETURN, N, N);
- $$->list = $2;
- }
-
-stmt_list:
- stmt
- {
- $$ = nil;
- if($1 != N)
- $$ = list1($1);
- }
-| stmt_list ';' stmt
- {
- $$ = $1;
- if($3 != N)
- $$ = list($$, $3);
- }
-
-new_name_list:
- new_name
- {
- $$ = list1($1);
- }
-| new_name_list ',' new_name
- {
- $$ = list($1, $3);
- }
-
-dcl_name_list:
- dcl_name
- {
- $$ = list1($1);
- }
-| dcl_name_list ',' dcl_name
- {
- $$ = list($1, $3);
- }
-
-expr_list:
- expr
- {
- $$ = list1($1);
- }
-| expr_list ',' expr
- {
- $$ = list($1, $3);
- }
-
-expr_or_type_list:
- expr_or_type
- {
- $$ = list1($1);
- }
-| expr_or_type_list ',' expr_or_type
- {
- $$ = list($1, $3);
- }
-
-/*
- * list of combo of keyval and val
- */
-keyval_list:
- keyval
- {
- $$ = list1($1);
- }
-| complitexpr
- {
- $$ = list1($1);
- }
-| keyval_list ',' keyval
- {
- $$ = list($1, $3);
- }
-| keyval_list ',' complitexpr
- {
- $$ = list($1, $3);
- }
-
-braced_keyval_list:
- {
- $$ = nil;
- }
-| keyval_list ocomma
- {
- $$ = $1;
- }
-
-/*
- * optional things
- */
-osemi:
-| ';'
-
-ocomma:
-| ','
-
-oexpr:
- {
- $$ = N;
- }
-| expr
-
-oexpr_list:
- {
- $$ = nil;
- }
-| expr_list
-
-osimple_stmt:
- {
- $$ = N;
- }
-| simple_stmt
-
-ohidden_funarg_list:
- {
- $$ = nil;
- }
-| hidden_funarg_list
-
-ohidden_structdcl_list:
- {
- $$ = nil;
- }
-| hidden_structdcl_list
-
-ohidden_interfacedcl_list:
- {
- $$ = nil;
- }
-| hidden_interfacedcl_list
-
-oliteral:
- {
- $$.ctype = CTxxx;
- }
-| LLITERAL
-
-/*
- * import syntax from header of
- * an output package
- */
-hidden_import:
- LIMPORT sym LLITERAL ';'
- {
- // Informational: record package name
- // associated with import path, for use in
- // human-readable messages.
- Pkg *p;
-
- p = mkpkg($3.u.sval);
- if(p->name == nil) {
- p->name = $2->name;
- pkglookup($2->name, nil)->npkg++;
- } else if(strcmp(p->name, $2->name) != 0)
- yyerror("conflicting names %s and %s for package %Z", p->name, $2->name, p->path);
- }
-| LVAR hidden_pkg_importsym hidden_type ';'
- {
- importvar($2, $3, PEXTERN);
- }
-| LCONST hidden_pkg_importsym '=' hidden_constant ';'
- {
- importconst($2, types[TIDEAL], $4);
- }
-| LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'
- {
- importconst($2, $3, $5);
- }
-| LTYPE hidden_pkgtype hidden_type ';'
- {
- importtype($2, $3);
- }
-| LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres ';'
- {
- importvar($2, functype(N, $4, $6), PFUNC);
- }
-| LFUNC '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres ';'
- {
- if($3->next != nil || $3->n->op != ODCLFIELD) {
- yyerror("bad receiver in method");
- YYERROR;
- }
- importmethod($5, functype($3->n, $7, $9));
- }
-
-hidden_pkgtype:
- hidden_pkg_importsym
- {
- $$ = pkgtype($1);
- importsym($1, OTYPE);
- }
-
-hidden_type:
- hidden_type_misc
-| hidden_type_recv_chan
-| hidden_type_func
-
-hidden_type_non_recv_chan:
- hidden_type_misc
-| hidden_type_func
-
-hidden_type_misc:
- hidden_importsym
- {
- $$ = pkgtype($1);
- }
-| LNAME
- {
- // predefined name like uint8
- $1 = pkglookup($1->name, builtinpkg);
- if($1->def == N || $1->def->op != OTYPE) {
- yyerror("%s is not a type", $1->name);
- $$ = T;
- } else
- $$ = $1->def->type;
- }
-| '[' ']' hidden_type
- {
- $$ = aindex(N, $3);
- }
-| '[' LLITERAL ']' hidden_type
- {
- $$ = aindex(nodlit($2), $4);
- }
-| LMAP '[' hidden_type ']' hidden_type
- {
- $$ = maptype($3, $5);
- }
-| LSTRUCT '{' ohidden_structdcl_list '}'
- {
- $$ = dostruct($3, TSTRUCT);
- }
-| LINTERFACE '{' ohidden_interfacedcl_list '}'
- {
- $$ = dostruct($3, TINTER);
- }
-| '*' hidden_type
- {
- $$ = ptrto($2);
- }
-| LCHAN hidden_type_non_recv_chan
- {
- $$ = typ(TCHAN);
- $$->type = $2;
- $$->chan = Cboth;
- }
-| LCHAN '(' hidden_type_recv_chan ')'
- {
- $$ = typ(TCHAN);
- $$->type = $3;
- $$->chan = Cboth;
- }
-| LCHAN LCOMM hidden_type
- {
- $$ = typ(TCHAN);
- $$->type = $3;
- $$->chan = Csend;
- }
-
-hidden_type_recv_chan:
- LCOMM LCHAN hidden_type
- {
- $$ = typ(TCHAN);
- $$->type = $3;
- $$->chan = Crecv;
- }
-
-hidden_type_func:
- LFUNC '(' ohidden_funarg_list ')' ohidden_funres
- {
- $$ = functype(nil, $3, $5);
- }
-
-hidden_opt_sym:
- sym
- {
- $$ = newname($1);
- }
-| '?'
- {
- $$ = N;
- }
-
-hidden_dcl:
- hidden_opt_sym hidden_type hidden_tag
- {
- $$ = nod(ODCLFIELD, $1, typenod($2));
- $$->val = $3;
- }
-| hidden_opt_sym LDDD hidden_type hidden_tag
- {
- Type *t;
-
- t = typ(TARRAY);
- t->bound = -1;
- t->type = $3;
- $$ = nod(ODCLFIELD, $1, typenod(t));
- $$->isddd = 1;
- $$->val = $4;
- }
-
-hidden_structdcl:
- sym hidden_type hidden_tag
- {
- $$ = nod(ODCLFIELD, newname($1), typenod($2));
- $$->val = $3;
- }
-| '?' hidden_type hidden_tag
- {
- Sym *s;
-
- s = $2->sym;
- if(s == S && isptr[$2->etype])
- s = $2->type->sym;
- if(s && s->pkg == builtinpkg)
- s = lookup(s->name);
- $$ = embedded(s);
- $$->right = typenod($2);
- $$->val = $3;
- }
-
-hidden_tag:
- {
- $$.ctype = CTxxx;
- }
-| ':' LLITERAL // extra colon avoids conflict with "" looking like beginning of "".typename
- {
- $$ = $2;
- }
-
-hidden_interfacedcl:
- sym '(' ohidden_funarg_list ')' ohidden_funres
- {
- $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
- }
-| hidden_importsym '(' ohidden_funarg_list ')' ohidden_funres
- {
- $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
- }
-
-ohidden_funres:
- {
- $$ = nil;
- }
-| hidden_funres
-
-hidden_funres:
- '(' ohidden_funarg_list ')'
- {
- $$ = $2;
- }
-| hidden_type
- {
- $$ = list1(nod(ODCLFIELD, N, typenod($1)));
- }
-
-hidden_literal:
- LLITERAL
- {
- $$ = nodlit($1);
- }
-| '-' LLITERAL
- {
- $$ = nodlit($2);
- switch($$->val.ctype){
- case CTINT:
- mpnegfix($$->val.u.xval);
- break;
- case CTFLT:
- mpnegflt($$->val.u.fval);
- break;
- default:
- yyerror("bad negated constant");
- }
- }
-| sym
- {
- $$ = oldname(pkglookup($1->name, builtinpkg));
- if($$->op != OLITERAL)
- yyerror("bad constant %S", $$->sym);
- }
-
-hidden_constant:
- hidden_literal
-| '(' hidden_literal '+' hidden_literal ')'
- {
- $$ = nodcplxlit($2->val, $4->val);
- }
-
-hidden_importsym:
- LLITERAL '.' sym
- {
- Pkg *p;
-
- if($1.u.sval->len == 0)
- p = importpkg;
- else
- p = mkpkg($1.u.sval);
- $$ = pkglookup($3->name, p);
- }
-
-hidden_pkg_importsym:
- hidden_importsym
- {
- $$ = $1;
- structpkg = $$->pkg;
- }
-
-hidden_import_list:
-| hidden_import_list hidden_import
-
-hidden_funarg_list:
- hidden_dcl
- {
- $$ = list1($1);
- }
-| hidden_funarg_list ',' hidden_dcl
- {
- $$ = list($1, $3);
- }
-
-hidden_structdcl_list:
- hidden_structdcl
- {
- $$ = list1($1);
- }
-| hidden_structdcl_list ';' hidden_structdcl
- {
- $$ = list($1, $3);
- }
-
-hidden_interfacedcl_list:
- hidden_interfacedcl
- {
- $$ = list1($1);
- }
-| hidden_interfacedcl_list ';' hidden_interfacedcl
- {
- $$ = list($1, $3);
- }
-
-%%
-
-static void
-fixlbrace(int lbr)
-{
- // If the opening brace was an LBODY,
- // set up for another one now that we're done.
- // See comment in lex.c about loophack.
- if(lbr == LBODY)
- loophack = 1;
-}
-
diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c
deleted file mode 100644
index 8818db08c..000000000
--- a/src/cmd/gc/init.c
+++ /dev/null
@@ -1,195 +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 "go.h"
-
-/*
- * a function named init is a special case.
- * it is called by the initialization before
- * main is run. to make it unique within a
- * package and also uncallable, the name,
- * normally "pkg.init", is altered to "pkg.init·1".
- */
-Node*
-renameinit(Node *n)
-{
- Sym *s;
- static int initgen;
-
- s = n->sym;
- if(s == S)
- return n;
- if(strcmp(s->name, "init") != 0)
- return n;
-
- snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
- s = lookup(namebuf);
- return newname(s);
-}
-
-/*
- * hand-craft the following initialization code
- * var initdone· uint8 (1)
- * func init() (2)
- * if initdone· != 0 { (3)
- * if initdone· == 2 (4)
- * return
- * throw(); (5)
- * }
- * initdone· = 1; (6)
- * // over all matching imported symbols
- * <pkg>.init() (7)
- * { <init stmts> } (8)
- * init·<n>() // if any (9)
- * initdone· = 2; (10)
- * return (11)
- * }
- */
-static int
-anyinit(NodeList *n)
-{
- uint32 h;
- Sym *s;
- NodeList *l;
-
- // are there any interesting init statements
- for(l=n; l; l=l->next) {
- switch(l->n->op) {
- case ODCLFUNC:
- case ODCLCONST:
- case ODCLTYPE:
- case OEMPTY:
- break;
- default:
- return 1;
- }
- }
-
- // is this main
- if(strcmp(localpkg->name, "main") == 0)
- return 1;
-
- // is there an explicit init function
- snprint(namebuf, sizeof(namebuf), "init·1");
- s = lookup(namebuf);
- if(s->def != N)
- return 1;
-
- // are there any imported init functions
- for(h=0; h<NHASH; h++)
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
- continue;
- if(s->def == N)
- continue;
- return 1;
- }
-
- // then none
- return 0;
-}
-
-void
-fninit(NodeList *n)
-{
- int i;
- Node *gatevar;
- Node *a, *b, *fn;
- NodeList *r;
- uint32 h;
- Sym *s, *initsym;
-
- if(debug['A']) {
- // sys.go or unsafe.go during compiler build
- return;
- }
-
- n = initfix(n);
- if(!anyinit(n))
- return;
-
- r = nil;
-
- // (1)
- snprint(namebuf, sizeof(namebuf), "initdone·");
- gatevar = newname(lookup(namebuf));
- addvar(gatevar, types[TUINT8], PEXTERN);
-
- // (2)
- maxarg = 0;
- snprint(namebuf, sizeof(namebuf), "init");
-
- fn = nod(ODCLFUNC, N, N);
- initsym = lookup(namebuf);
- fn->nname = newname(initsym);
- fn->nname->ntype = nod(OTFUNC, N, N);
- funchdr(fn);
-
- // (3)
- a = nod(OIF, N, N);
- a->ntest = nod(ONE, gatevar, nodintconst(0));
- r = list(r, a);
-
- // (4)
- b = nod(OIF, N, N);
- b->ntest = nod(OEQ, gatevar, nodintconst(2));
- b->nbody = list1(nod(ORETURN, N, N));
- a->nbody = list1(b);
-
- // (5)
- b = syslook("throwinit", 0);
- b = nod(OCALL, b, N);
- a->nbody = list(a->nbody, b);
-
- // (6)
- a = nod(OAS, gatevar, nodintconst(1));
- r = list(r, a);
-
- // (7)
- for(h=0; h<NHASH; h++)
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
- continue;
- if(s->def == N)
- continue;
- if(s == initsym)
- continue;
-
- // could check that it is fn of no args/returns
- a = nod(OCALL, s->def, N);
- r = list(r, a);
- }
-
- // (8)
- r = concat(r, n);
-
- // (9)
- // could check that it is fn of no args/returns
- for(i=1;; i++) {
- snprint(namebuf, sizeof(namebuf), "init·%d", i);
- s = lookup(namebuf);
- if(s->def == N)
- break;
- a = nod(OCALL, s->def, N);
- r = list(r, a);
- }
-
- // (10)
- a = nod(OAS, gatevar, nodintconst(2));
- r = list(r, a);
-
- // (11)
- a = nod(ORETURN, N, N);
- r = list(r, a);
- exportsym(fn->nname);
-
- fn->nbody = r;
- funcbody(fn);
-
- curfn = fn;
- typecheck(&fn, Etop);
- typechecklist(r, Etop);
- curfn = nil;
- funccompile(fn, 0);
-}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
deleted file mode 100644
index 5c642375a..000000000
--- a/src/cmd/gc/lex.c
+++ /dev/null
@@ -1,1935 +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 EXTERN
-#include "go.h"
-#include "y.tab.h"
-#include <ar.h>
-
-#undef getc
-#undef ungetc
-#define getc ccgetc
-#define ungetc ccungetc
-
-extern int yychar;
-int windows;
-int yyprev;
-int yylast;
-
-static void lexinit(void);
-static void lexfini(void);
-static void yytinit(void);
-static int getc(void);
-static void ungetc(int);
-static int32 getr(void);
-static int escchar(int, int*, vlong*);
-static void addidir(char*);
-static int getlinepragma(void);
-static char *goos, *goarch, *goroot;
-
-// Our own isdigit, isspace, isalpha, isalnum that take care
-// of EOF and other out of range arguments.
-static int
-yy_isdigit(int c)
-{
- return c >= 0 && c <= 0xFF && isdigit(c);
-}
-
-static int
-yy_isspace(int c)
-{
- return c >= 0 && c <= 0xFF && isspace(c);
-}
-
-static int
-yy_isalpha(int c)
-{
- return c >= 0 && c <= 0xFF && isalpha(c);
-}
-
-static int
-yy_isalnum(int c)
-{
- return c >= 0 && c <= 0xFF && isalnum(c);
-}
-
-// Disallow use of isdigit etc.
-#undef isdigit
-#undef isspace
-#undef isalpha
-#undef isalnum
-#define isdigit use_yy_isdigit_instead_of_isdigit
-#define isspace use_yy_isspace_instead_of_isspace
-#define isalpha use_yy_isalpha_instead_of_isalpha
-#define isalnum use_yy_isalnum_instead_of_isalnum
-
-#define DBG if(!debug['x']);else print
-enum
-{
- EOF = -1,
-};
-
-void
-usage(void)
-{
- print("gc: usage: %cg [flags] file.go...\n", thechar);
- print("flags:\n");
- // -A is allow use of "any" type, for bootstrapping
- print(" -I DIR search for packages in DIR\n");
- print(" -d print declarations\n");
- print(" -e no limit on number of errors printed\n");
- print(" -f print stack frame structure\n");
- print(" -h panic on an error\n");
- print(" -o file specify output file\n");
- print(" -S print the assembly language\n");
- print(" -V print the compiler version\n");
- print(" -u disable package unsafe\n");
- print(" -w print the parse tree after typing\n");
- print(" -x print lex tokens\n");
- exit(0);
-}
-
-void
-fault(int s)
-{
- // If we've already complained about things
- // in the program, don't bother complaining
- // about the seg fault too; let the user clean up
- // the code and try again.
- if(nsavederrors + nerrors > 0)
- errorexit();
- fatal("fault");
-}
-
-int
-main(int argc, char *argv[])
-{
- int i, c;
- NodeList *l;
- char *p;
-
- signal(SIGBUS, fault);
- signal(SIGSEGV, fault);
-
- localpkg = mkpkg(strlit(""));
- localpkg->prefix = "\"\"";
-
- builtinpkg = mkpkg(strlit("go.builtin"));
-
- gostringpkg = mkpkg(strlit("go.string"));
- gostringpkg->name = "go.string";
- gostringpkg->prefix = "go.string"; // not go%2estring
-
- runtimepkg = mkpkg(strlit("runtime"));
- runtimepkg->name = "runtime";
-
- typepkg = mkpkg(strlit("type"));
- typepkg->name = "type";
-
- unsafepkg = mkpkg(strlit("unsafe"));
- unsafepkg->name = "unsafe";
-
- goroot = getgoroot();
- goos = getgoos();
- goarch = thestring;
-
- outfile = nil;
- ARGBEGIN {
- default:
- c = ARGC();
- if(c >= 0 && c < sizeof(debug))
- debug[c]++;
- break;
-
- case 'o':
- outfile = EARGF(usage());
- break;
-
- case 'I':
- addidir(EARGF(usage()));
- break;
-
- case 'u':
- safemode = 1;
- break;
-
- case 'V':
- print("%cg version %s\n", thechar, getgoversion());
- exit(0);
- } ARGEND
-
- if(argc < 1)
- usage();
-
- // special flag to detect compilation of package runtime
- compiling_runtime = debug['+'];
-
- pathname = mal(1000);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
-
- if(yy_isalpha(pathname[0]) && pathname[1] == ':') {
- // On Windows.
- windows = 1;
-
- // Canonicalize path by converting \ to / (Windows accepts both).
- for(p=pathname; *p; p++)
- if(*p == '\\')
- *p = '/';
- }
-
- fmtinstall('O', Oconv); // node opcodes
- fmtinstall('E', Econv); // etype opcodes
- fmtinstall('J', Jconv); // all the node flags
- fmtinstall('S', Sconv); // sym pointer
- fmtinstall('T', Tconv); // type pointer
- fmtinstall('N', Nconv); // node pointer
- fmtinstall('Z', Zconv); // escaped string
- fmtinstall('L', Lconv); // line number
- fmtinstall('B', Bconv); // big numbers
- fmtinstall('F', Fconv); // big float numbers
-
- betypeinit();
- if(widthptr == 0)
- fatal("betypeinit failed");
-
- lexinit();
- typeinit();
- yytinit();
-
- blockgen = 1;
- dclcontext = PEXTERN;
- nerrors = 0;
- lexlineno = 1;
-
- for(i=0; i<argc; i++) {
- infile = argv[i];
- linehist(infile, 0, 0);
-
- curio.infile = infile;
- curio.bin = Bopen(infile, OREAD);
- if(curio.bin == nil) {
- print("open %s: %r\n", infile);
- errorexit();
- }
- curio.peekc = 0;
- curio.peekc1 = 0;
- curio.nlsemi = 0;
-
- block = 1;
-
- yyparse();
- if(nsyntaxerrors != 0)
- errorexit();
-
- linehist(nil, 0, 0);
- if(curio.bin != nil)
- Bterm(curio.bin);
- }
- testdclstack();
- mkpackage(localpkg->name); // final import not used checks
- lexfini();
-
- typecheckok = 1;
- if(debug['f'])
- frame(1);
-
- // Process top-level declarations in four phases.
- // Phase 1: const, type, and names and types of funcs.
- // This will gather all the information about types
- // and methods but doesn't depend on any of it.
- // Phase 2: Variable assignments.
- // To check interface assignments, depends on phase 1.
- // Phase 3: Type check function bodies.
- // Phase 4: Compile function bodies.
- defercheckwidth();
- for(l=xtop; l; l=l->next)
- if(l->n->op != ODCL && l->n->op != OAS)
- typecheck(&l->n, Etop);
- for(l=xtop; l; l=l->next)
- if(l->n->op == ODCL || l->n->op == OAS)
- typecheck(&l->n, Etop);
- resumetypecopy();
- resumecheckwidth();
-
- for(l=xtop; l; l=l->next)
- if(l->n->op == ODCLFUNC) {
- curfn = l->n;
- saveerrors();
- typechecklist(l->n->nbody, Etop);
- if(nerrors != 0)
- l->n->nbody = nil; // type errors; do not compile
- }
- curfn = nil;
-
- for(l=xtop; l; l=l->next)
- if(l->n->op == ODCLFUNC)
- funccompile(l->n, 0);
-
- if(nsavederrors+nerrors == 0)
- fninit(xtop);
-
- while(closures) {
- l = closures;
- closures = nil;
- for(; l; l=l->next)
- funccompile(l->n, 1);
- }
-
- for(l=externdcl; l; l=l->next)
- if(l->n->op == ONAME)
- typecheck(&l->n, Erv);
-
- if(nerrors+nsavederrors)
- errorexit();
-
- dumpobj();
-
- if(nerrors+nsavederrors)
- errorexit();
-
- flusherrors();
- exit(0);
- return 0;
-}
-
-void
-saveerrors(void)
-{
- nsavederrors += nerrors;
- nerrors = 0;
-}
-
-static int
-arsize(Biobuf *b, char *name)
-{
- struct ar_hdr *a;
-
- if((a = Brdline(b, '\n')) == nil)
- return -1;
- if(Blinelen(b) != sizeof(struct ar_hdr))
- return -1;
- if(strncmp(a->name, name, strlen(name)) != 0)
- return -1;
- return atoi(a->size);
-}
-
-static int
-skiptopkgdef(Biobuf *b)
-{
- char *p;
- int sz;
-
- /* archive header */
- if((p = Brdline(b, '\n')) == nil)
- return 0;
- if(Blinelen(b) != 8)
- return 0;
- if(memcmp(p, "!<arch>\n", 8) != 0)
- return 0;
- /* symbol table is first; skip it */
- sz = arsize(b, "__.SYMDEF");
- if(sz < 0)
- return 0;
- Bseek(b, sz, 1);
- /* package export block is second */
- sz = arsize(b, "__.PKGDEF");
- if(sz <= 0)
- return 0;
- return 1;
-}
-
-static void
-addidir(char* dir)
-{
- Idir** pp;
-
- if(dir == nil)
- return;
-
- for(pp = &idirs; *pp != nil; pp = &(*pp)->link)
- ;
- *pp = mal(sizeof(Idir));
- (*pp)->link = nil;
- (*pp)->dir = dir;
-}
-
-// is this path a local name? begins with ./ or ../ or /
-static int
-islocalname(Strlit *name)
-{
- if(!windows && name->len >= 1 && name->s[0] == '/')
- return 1;
- if(windows && name->len >= 3 &&
- yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
- return 1;
- if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
- return 1;
- if(name->len >= 3 && strncmp(name->s, "../", 3) == 0)
- return 1;
- return 0;
-}
-
-static int
-findpkg(Strlit *name)
-{
- Idir *p;
- char *q;
-
- if(islocalname(name)) {
- if(safemode)
- return 0;
- // try .a before .6. important for building libraries:
- // if there is an array.6 in the array.a library,
- // want to find all of array.a, not just array.6.
- snprint(namebuf, sizeof(namebuf), "%Z.a", name);
- if(access(namebuf, 0) >= 0)
- return 1;
- snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thechar);
- if(access(namebuf, 0) >= 0)
- return 1;
- return 0;
- }
-
- // local imports should be canonicalized already.
- // don't want to see "container/../container/vector"
- // as different from "container/vector".
- q = mal(name->len+1);
- memmove(q, name->s, name->len);
- q[name->len] = '\0';
- cleanname(q);
- if(strlen(q) != name->len || memcmp(q, name->s, name->len) != 0) {
- yyerror("non-canonical import path %Z (should be %s)", name, q);
- return 0;
- }
-
- for(p = idirs; p != nil; p = p->link) {
- snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
- if(access(namebuf, 0) >= 0)
- return 1;
- snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thechar);
- if(access(namebuf, 0) >= 0)
- return 1;
- }
- if(goroot != nil) {
- snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s/%Z.a", goroot, goos, goarch, name);
- if(access(namebuf, 0) >= 0)
- return 1;
- snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s/%Z.%c", goroot, goos, goarch, name, thechar);
- if(access(namebuf, 0) >= 0)
- return 1;
- }
- return 0;
-}
-
-void
-importfile(Val *f, int line)
-{
- Biobuf *imp;
- char *file, *p, *q;
- int32 c;
- int len;
- Strlit *path;
- char *cleanbuf;
-
- // TODO(rsc): don't bother reloading imports more than once?
-
- if(f->ctype != CTSTR) {
- yyerror("import statement not a string");
- return;
- }
-
- if(strlen(f->u.sval->s) != f->u.sval->len) {
- yyerror("import path contains NUL");
- errorexit();
- }
-
- // The package name main is no longer reserved,
- // but we reserve the import path "main" to identify
- // the main package, just as we reserve the import
- // path "math" to identify the standard math package.
- if(strcmp(f->u.sval->s, "main") == 0) {
- yyerror("cannot import \"main\"");
- errorexit();
- }
-
- if(strcmp(f->u.sval->s, "unsafe") == 0) {
- if(safemode) {
- yyerror("cannot import package unsafe");
- errorexit();
- }
- importpkg = mkpkg(f->u.sval);
- cannedimports("unsafe.6", unsafeimport);
- return;
- }
-
- path = f->u.sval;
- if(islocalname(path)) {
- cleanbuf = mal(strlen(pathname) + strlen(path->s) + 2);
- strcpy(cleanbuf, pathname);
- strcat(cleanbuf, "/");
- strcat(cleanbuf, path->s);
- cleanname(cleanbuf);
- path = strlit(cleanbuf);
- }
-
- if(!findpkg(path)) {
- yyerror("can't find import: %Z", f->u.sval);
- errorexit();
- }
- importpkg = mkpkg(path);
-
- imp = Bopen(namebuf, OREAD);
- if(imp == nil) {
- yyerror("can't open import: %Z: %r", f->u.sval);
- errorexit();
- }
- file = strdup(namebuf);
-
- len = strlen(namebuf);
- if(len > 2 && namebuf[len-2] == '.' && namebuf[len-1] == 'a') {
- if(!skiptopkgdef(imp)) {
- yyerror("import %s: not a package file", file);
- errorexit();
- }
- }
-
- // check object header
- p = Brdstr(imp, '\n', 1);
- if(strcmp(p, "empty archive") != 0) {
- if(strncmp(p, "go object ", 10) != 0) {
- yyerror("import %s: not a go object file", file);
- errorexit();
- }
- q = smprint("%s %s %s", getgoos(), thestring, getgoversion());
- if(strcmp(p+10, q) != 0) {
- yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
- errorexit();
- }
- free(q);
- }
-
- // assume files move (get installed)
- // so don't record the full path.
- linehist(file + len - path->len - 2, -1, 1); // acts as #pragma lib
-
- /*
- * position the input right
- * after $$ and return
- */
- pushedio = curio;
- curio.bin = imp;
- curio.peekc = 0;
- curio.peekc1 = 0;
- curio.infile = file;
- curio.nlsemi = 0;
- typecheckok = 1;
-
- for(;;) {
- c = getc();
- if(c == EOF)
- break;
- if(c != '$')
- continue;
- c = getc();
- if(c == EOF)
- break;
- if(c != '$')
- continue;
- return;
- }
- yyerror("no import in: %Z", f->u.sval);
- unimportfile();
-}
-
-void
-unimportfile(void)
-{
- if(curio.bin != nil) {
- Bterm(curio.bin);
- curio.bin = nil;
- } else
- lexlineno--; // re correct sys.6 line number
-
- curio = pushedio;
- pushedio.bin = nil;
- incannedimport = 0;
- typecheckok = 0;
-}
-
-void
-cannedimports(char *file, char *cp)
-{
- lexlineno++; // if sys.6 is included on line 1,
-
- pushedio = curio;
- curio.bin = nil;
- curio.peekc = 0;
- curio.peekc1 = 0;
- curio.infile = file;
- curio.cp = cp;
- curio.nlsemi = 0;
- curio.importsafe = 0;
-
- typecheckok = 1;
- incannedimport = 1;
-}
-
-static int
-isfrog(int c)
-{
- // complain about possibly invisible control characters
- if(c < 0)
- return 1;
- if(c < ' ') {
- if(c == '\n' || c== '\r' || c == '\t') // good white space
- return 0;
- return 1;
- }
- if(0x7f <= c && c <= 0xa0) // DEL, unicode block including unbreakable space.
- return 1;
- return 0;
-}
-
-typedef struct Loophack Loophack;
-struct Loophack {
- int v;
- Loophack *next;
-};
-
-static int32
-_yylex(void)
-{
- int c, c1, clen, escflag, ncp;
- vlong v;
- char *cp, *ep;
- Rune rune;
- Sym *s;
- static Loophack *lstk;
- Loophack *h;
-
- prevlineno = lineno;
-
-l0:
- c = getc();
- if(yy_isspace(c)) {
- if(c == '\n' && curio.nlsemi) {
- ungetc(c);
- DBG("lex: implicit semi\n");
- return ';';
- }
- goto l0;
- }
-
- lineno = lexlineno; /* start of token */
-
- if(c >= Runeself) {
- /* all multibyte runes are alpha */
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- goto talph;
- }
-
- if(yy_isalpha(c)) {
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- goto talph;
- }
-
- if(yy_isdigit(c))
- goto tnum;
-
- switch(c) {
- case EOF:
- lineno = prevlineno;
- ungetc(EOF);
- return -1;
-
- case '_':
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- goto talph;
-
- case '.':
- c1 = getc();
- if(yy_isdigit(c1)) {
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- *cp++ = c;
- c = c1;
- c1 = 0;
- goto casedot;
- }
- if(c1 == '.') {
- c1 = getc();
- if(c1 == '.') {
- c = LDDD;
- goto lx;
- }
- ungetc(c1);
- c1 = '.';
- }
- break;
-
- case '"':
- /* "..." */
- strcpy(lexbuf, "\"<string>\"");
- cp = mal(8);
- clen = sizeof(int32);
- ncp = 8;
-
- for(;;) {
- if(clen+UTFmax > ncp) {
- cp = remal(cp, ncp, ncp);
- ncp += ncp;
- }
- if(escchar('"', &escflag, &v))
- break;
- if(v < Runeself || escflag) {
- cp[clen++] = v;
- } else {
- rune = v;
- c = runelen(rune);
- runetochar(cp+clen, &rune);
- clen += c;
- }
- }
- goto strlit;
-
- case '`':
- /* `...` */
- strcpy(lexbuf, "`<string>`");
- cp = mal(8);
- clen = sizeof(int32);
- ncp = 8;
-
- for(;;) {
- if(clen+UTFmax > ncp) {
- cp = remal(cp, ncp, ncp);
- ncp += ncp;
- }
- c = getr();
- if(c == EOF) {
- yyerror("eof in string");
- break;
- }
- if(c == '`')
- break;
- rune = c;
- clen += runetochar(cp+clen, &rune);
- }
-
- strlit:
- *(int32*)cp = clen-sizeof(int32); // length
- do {
- cp[clen++] = 0;
- } while(clen & MAXALIGN);
- yylval.val.u.sval = (Strlit*)cp;
- yylval.val.ctype = CTSTR;
- DBG("lex: string literal\n");
- return LLITERAL;
-
- case '\'':
- /* '.' */
- if(escchar('\'', &escflag, &v)) {
- yyerror("empty character literal or unescaped ' in character literal");
- v = '\'';
- }
- if(!escchar('\'', &escflag, &v)) {
- yyerror("missing '");
- ungetc(v);
- }
- yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
- mpmovecfix(yylval.val.u.xval, v);
- yylval.val.ctype = CTINT;
- DBG("lex: codepoint literal\n");
- return LLITERAL;
-
- case '/':
- c1 = getc();
- if(c1 == '*') {
- int nl;
-
- nl = 0;
- for(;;) {
- c = getr();
- if(c == '\n')
- nl = 1;
- while(c == '*') {
- c = getr();
- if(c == '/') {
- if(nl)
- ungetc('\n');
- goto l0;
- }
- if(c == '\n')
- nl = 1;
- }
- if(c == EOF) {
- yyerror("eof in comment");
- errorexit();
- }
- }
- }
- if(c1 == '/') {
- c = getlinepragma();
- for(;;) {
- if(c == '\n' || c == EOF) {
- ungetc(c);
- goto l0;
- }
- c = getr();
- }
- }
- if(c1 == '=') {
- c = ODIV;
- goto asop;
- }
- break;
-
- case ':':
- c1 = getc();
- if(c1 == '=') {
- c = LCOLAS;
- goto lx;
- }
- break;
-
- case '*':
- c1 = getc();
- if(c1 == '=') {
- c = OMUL;
- goto asop;
- }
- break;
-
- case '%':
- c1 = getc();
- if(c1 == '=') {
- c = OMOD;
- goto asop;
- }
- break;
-
- case '+':
- c1 = getc();
- if(c1 == '+') {
- c = LINC;
- goto lx;
- }
- if(c1 == '=') {
- c = OADD;
- goto asop;
- }
- break;
-
- case '-':
- c1 = getc();
- if(c1 == '-') {
- c = LDEC;
- goto lx;
- }
- if(c1 == '=') {
- c = OSUB;
- goto asop;
- }
- break;
-
- case '>':
- c1 = getc();
- if(c1 == '>') {
- c = LRSH;
- c1 = getc();
- if(c1 == '=') {
- c = ORSH;
- goto asop;
- }
- break;
- }
- if(c1 == '=') {
- c = LGE;
- goto lx;
- }
- c = LGT;
- break;
-
- case '<':
- c1 = getc();
- if(c1 == '<') {
- c = LLSH;
- c1 = getc();
- if(c1 == '=') {
- c = OLSH;
- goto asop;
- }
- break;
- }
- if(c1 == '=') {
- c = LLE;
- goto lx;
- }
- if(c1 == '-') {
- c = LCOMM;
- goto lx;
- }
- c = LLT;
- break;
-
- case '=':
- c1 = getc();
- if(c1 == '=') {
- c = LEQ;
- goto lx;
- }
- break;
-
- case '!':
- c1 = getc();
- if(c1 == '=') {
- c = LNE;
- goto lx;
- }
- break;
-
- case '&':
- c1 = getc();
- if(c1 == '&') {
- c = LANDAND;
- goto lx;
- }
- if(c1 == '^') {
- c = LANDNOT;
- c1 = getc();
- if(c1 == '=') {
- c = OANDNOT;
- goto asop;
- }
- break;
- }
- if(c1 == '=') {
- c = OAND;
- goto asop;
- }
- break;
-
- case '|':
- c1 = getc();
- if(c1 == '|') {
- c = LOROR;
- goto lx;
- }
- if(c1 == '=') {
- c = OOR;
- goto asop;
- }
- break;
-
- case '^':
- c1 = getc();
- if(c1 == '=') {
- c = OXOR;
- goto asop;
- }
- break;
-
- /*
- * clumsy dance:
- * to implement rule that disallows
- * if T{1}[0] { ... }
- * but allows
- * if (T{1}[0]) { ... }
- * the block bodies for if/for/switch/select
- * begin with an LBODY token, not '{'.
- *
- * when we see the keyword, the next
- * non-parenthesized '{' becomes an LBODY.
- * loophack is normally 0.
- * a keyword makes it go up to 1.
- * parens push loophack onto a stack and go back to 0.
- * a '{' with loophack == 1 becomes LBODY and disables loophack.
- *
- * i said it was clumsy.
- */
- case '(':
- case '[':
- if(loophack || lstk != nil) {
- h = malloc(sizeof *h);
- h->v = loophack;
- h->next = lstk;
- lstk = h;
- loophack = 0;
- }
- goto lx;
- case ')':
- case ']':
- if(lstk != nil) {
- h = lstk;
- loophack = h->v;
- lstk = h->next;
- free(h);
- }
- goto lx;
- case '{':
- if(loophack == 1) {
- DBG("%L lex: LBODY\n", lexlineno);
- loophack = 0;
- return LBODY;
- }
- goto lx;
-
- default:
- goto lx;
- }
- ungetc(c1);
-
-lx:
- if(c > 0xff)
- DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c));
- else
- DBG("%L lex: TOKEN '%c'\n", lexlineno, c);
- if(isfrog(c)) {
- yyerror("illegal character 0x%ux", c);
- goto l0;
- }
- if(importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\')) {
- yyerror("%s: unexpected %c", "syntax error", c);
- goto l0;
- }
- return c;
-
-asop:
- yylval.lint = c; // rathole to hold which asop
- DBG("lex: TOKEN ASOP %c\n", c);
- return LASOP;
-
-talph:
- /*
- * cp is set to lexbuf and some
- * prefix has been stored
- */
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- if(c >= Runeself) {
- ungetc(c);
- rune = getr();
- // 0xb7 · is used for internal names
- if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
- yyerror("invalid identifier character 0x%ux", rune);
- cp += runetochar(cp, &rune);
- } else if(!yy_isalnum(c) && c != '_')
- break;
- else
- *cp++ = c;
- c = getc();
- }
- *cp = 0;
- ungetc(c);
-
- s = lookup(lexbuf);
- switch(s->lexical) {
- case LIGNORE:
- goto l0;
-
- case LFOR:
- case LIF:
- case LSWITCH:
- case LSELECT:
- loophack = 1; // see comment about loophack above
- break;
- }
-
- DBG("lex: %S %s\n", s, lexname(s->lexical));
- yylval.sym = s;
- return s->lexical;
-
-tnum:
- c1 = 0;
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- if(c != '0') {
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- if(yy_isdigit(c))
- continue;
- goto dc;
- }
- }
- *cp++ = c;
- c = getc();
- if(c == 'x' || c == 'X') {
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- if(yy_isdigit(c))
- continue;
- if(c >= 'a' && c <= 'f')
- continue;
- if(c >= 'A' && c <= 'F')
- continue;
- if(cp == lexbuf+2)
- yyerror("malformed hex constant");
- goto ncu;
- }
- }
-
- if(c == 'p') // 0p begins floating point zero
- goto casep;
-
- c1 = 0;
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- if(!yy_isdigit(c))
- break;
- if(c < '0' || c > '7')
- c1 = 1; // not octal
- *cp++ = c;
- c = getc();
- }
- if(c == '.')
- goto casedot;
- if(c == 'e' || c == 'E')
- goto casee;
- if(c == 'i')
- goto casei;
- if(c1)
- yyerror("malformed octal constant");
- goto ncu;
-
-dc:
- if(c == '.')
- goto casedot;
- if(c == 'e' || c == 'E')
- goto casee;
- if(c == 'p' || c == 'P')
- goto casep;
- if(c == 'i')
- goto casei;
-
-ncu:
- *cp = 0;
- ungetc(c);
-
- yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
- mpatofix(yylval.val.u.xval, lexbuf);
- if(yylval.val.u.xval->ovf) {
- yyerror("overflow in constant");
- mpmovecfix(yylval.val.u.xval, 0);
- }
- yylval.val.ctype = CTINT;
- DBG("lex: integer literal\n");
- return LLITERAL;
-
-casedot:
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- if(!yy_isdigit(c))
- break;
- }
- if(c == 'i')
- goto casei;
- if(c != 'e' && c != 'E')
- goto caseout;
-
-casee:
- *cp++ = 'e';
- c = getc();
- if(c == '+' || c == '-') {
- *cp++ = c;
- c = getc();
- }
- if(!yy_isdigit(c))
- yyerror("malformed fp constant exponent");
- while(yy_isdigit(c)) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- }
- if(c == 'i')
- goto casei;
- goto caseout;
-
-casep:
- *cp++ = 'p';
- c = getc();
- if(c == '+' || c == '-') {
- *cp++ = c;
- c = getc();
- }
- if(!yy_isdigit(c))
- yyerror("malformed fp constant exponent");
- while(yy_isdigit(c)) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- }
- if(c == 'i')
- goto casei;
- goto caseout;
-
-casei:
- // imaginary constant
- *cp = 0;
- yylval.val.u.cval = mal(sizeof(*yylval.val.u.cval));
- mpmovecflt(&yylval.val.u.cval->real, 0.0);
- mpatoflt(&yylval.val.u.cval->imag, lexbuf);
- if(yylval.val.u.cval->imag.val.ovf) {
- yyerror("overflow in imaginary constant");
- mpmovecflt(&yylval.val.u.cval->real, 0.0);
- }
- yylval.val.ctype = CTCPLX;
- DBG("lex: imaginary literal\n");
- return LLITERAL;
-
-caseout:
- *cp = 0;
- ungetc(c);
-
- yylval.val.u.fval = mal(sizeof(*yylval.val.u.fval));
- mpatoflt(yylval.val.u.fval, lexbuf);
- if(yylval.val.u.fval->val.ovf) {
- yyerror("overflow in float constant");
- mpmovecflt(yylval.val.u.fval, 0.0);
- }
- yylval.val.ctype = CTFLT;
- DBG("lex: floating literal\n");
- return LLITERAL;
-}
-
-/*
- * read and interpret syntax that looks like
- * //line parse.y:15
- * as a discontinuity in sequential line numbers.
- * the next line of input comes from parse.y:15
- */
-static int
-getlinepragma(void)
-{
- int i, c, n;
- char *cp, *ep;
- Hist *h;
-
- for(i=0; i<5; i++) {
- c = getr();
- if(c != "line "[i])
- goto out;
- }
-
- cp = lexbuf;
- ep = lexbuf+sizeof(lexbuf)-5;
- for(;;) {
- c = getr();
- if(c == '\n' || c == EOF)
- goto out;
- if(c == ' ')
- continue;
- if(c == ':')
- break;
- if(cp < ep)
- *cp++ = c;
- }
- *cp = 0;
-
- n = 0;
- for(;;) {
- c = getr();
- if(!yy_isdigit(c))
- break;
- n = n*10 + (c-'0');
- if(n > 1e8) {
- yyerror("line number out of range");
- errorexit();
- }
- }
-
- if(c != '\n' || n <= 0)
- goto out;
-
- // try to avoid allocating file name over and over
- for(h=hist; h!=H; h=h->link) {
- if(h->name != nil && strcmp(h->name, lexbuf) == 0) {
- linehist(h->name, n, 0);
- goto out;
- }
- }
- linehist(strdup(lexbuf), n, 0);
-
-out:
- return c;
-}
-
-int32
-yylex(void)
-{
- int lx;
-
- lx = _yylex();
-
- if(curio.nlsemi && lx == EOF) {
- // Treat EOF as "end of line" for the purposes
- // of inserting a semicolon.
- lx = ';';
- }
-
- switch(lx) {
- case LNAME:
- case LLITERAL:
- case LBREAK:
- case LCONTINUE:
- case LFALL:
- case LRETURN:
- case LINC:
- case LDEC:
- case ')':
- case '}':
- case ']':
- curio.nlsemi = 1;
- break;
- default:
- curio.nlsemi = 0;
- break;
- }
-
- // Track last two tokens returned by yylex.
- yyprev = yylast;
- yylast = lx;
- return lx;
-}
-
-static int
-getc(void)
-{
- int c;
-
- c = curio.peekc;
- if(c != 0) {
- curio.peekc = curio.peekc1;
- curio.peekc1 = 0;
- if(c == '\n' && pushedio.bin == nil)
- lexlineno++;
- return c;
- }
-
- if(curio.bin == nil) {
- c = *curio.cp & 0xff;
- if(c != 0)
- curio.cp++;
- } else
- c = Bgetc(curio.bin);
-
- switch(c) {
- case 0:
- if(curio.bin != nil) {
- yyerror("illegal NUL byte");
- break;
- }
- case EOF:
- // insert \n at EOF
- if(curio.eofnl)
- return EOF;
- curio.eofnl = 1;
- c = '\n';
- case '\n':
- if(pushedio.bin == nil)
- lexlineno++;
- break;
- }
- return c;
-}
-
-static void
-ungetc(int c)
-{
- curio.peekc1 = curio.peekc;
- curio.peekc = c;
- if(c == '\n' && pushedio.bin == nil)
- lexlineno--;
-}
-
-static 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) {
- lineno = lexlineno;
- yyerror("illegal UTF-8 sequence");
- flusherrors();
- print("\t");
- for(c=0; c<i; c++)
- print("%s%.2x", c > 0 ? " " : "", *(uchar*)(str+c));
- print("\n");
- }
- return rune;
-}
-
-static int
-escchar(int e, int *escflg, vlong *val)
-{
- int i, u, c;
- vlong l;
-
- *escflg = 0;
-
- c = getr();
- switch(c) {
- case EOF:
- yyerror("eof in string");
- return 1;
- case '\n':
- yyerror("newline in string");
- return 1;
- case '\\':
- break;
- default:
- if(c == e)
- return 1;
- *val = c;
- return 0;
- }
-
- u = 0;
- c = getr();
- switch(c) {
- case 'x':
- *escflg = 1; // it's a byte
- i = 2;
- goto hex;
-
- case 'u':
- i = 4;
- u = 1;
- goto hex;
-
- case 'U':
- i = 8;
- u = 1;
- goto hex;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- *escflg = 1; // it's a byte
- goto oct;
-
- case 'a': c = '\a'; break;
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'v': c = '\v'; break;
- case '\\': c = '\\'; break;
-
- default:
- if(c != e)
- yyerror("unknown escape sequence: %c", c);
- }
- *val = c;
- return 0;
-
-hex:
- 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;
- }
- yyerror("non-hex character in escape sequence: %c", c);
- ungetc(c);
- break;
- }
- if(u && (l > Runemax || (0xd800 <= l && l < 0xe000))) {
- yyerror("invalid Unicode code point in escape sequence: %#llx", l);
- l = Runeerror;
- }
- *val = l;
- return 0;
-
-oct:
- l = c - '0';
- for(i=2; i>0; i--) {
- c = getc();
- if(c >= '0' && c <= '7') {
- l = l*8 + c-'0';
- continue;
- }
- yyerror("non-octal character in escape sequence: %c", c);
- ungetc(c);
- }
- if(l > 255)
- yyerror("octal escape value > 255: %d", l);
-
- *val = l;
- return 0;
-}
-
-static struct
-{
- char* name;
- int lexical;
- int etype;
- int op;
-} syms[] =
-{
-/* name lexical etype op
- */
-/* basic types */
- "int8", LNAME, TINT8, OXXX,
- "int16", LNAME, TINT16, OXXX,
- "int32", LNAME, TINT32, OXXX,
- "int64", LNAME, TINT64, OXXX,
-
- "uint8", LNAME, TUINT8, OXXX,
- "uint16", LNAME, TUINT16, OXXX,
- "uint32", LNAME, TUINT32, OXXX,
- "uint64", LNAME, TUINT64, OXXX,
-
- "float32", LNAME, TFLOAT32, OXXX,
- "float64", LNAME, TFLOAT64, OXXX,
-
- "complex64", LNAME, TCOMPLEX64, OXXX,
- "complex128", LNAME, TCOMPLEX128, OXXX,
-
- "bool", LNAME, TBOOL, OXXX,
- "byte", LNAME, TUINT8, OXXX,
- "string", LNAME, TSTRING, OXXX,
-
- "any", LNAME, TANY, OXXX,
-
- "break", LBREAK, Txxx, OXXX,
- "case", LCASE, Txxx, OXXX,
- "chan", LCHAN, Txxx, OXXX,
- "const", LCONST, Txxx, OXXX,
- "continue", LCONTINUE, Txxx, OXXX,
- "default", LDEFAULT, Txxx, OXXX,
- "else", LELSE, Txxx, OXXX,
- "defer", LDEFER, Txxx, OXXX,
- "fallthrough", LFALL, Txxx, OXXX,
- "for", LFOR, Txxx, OXXX,
- "func", LFUNC, Txxx, OXXX,
- "go", LGO, Txxx, OXXX,
- "goto", LGOTO, Txxx, OXXX,
- "if", LIF, Txxx, OXXX,
- "import", LIMPORT, Txxx, OXXX,
- "interface", LINTERFACE, Txxx, OXXX,
- "map", LMAP, Txxx, OXXX,
- "package", LPACKAGE, Txxx, OXXX,
- "range", LRANGE, Txxx, OXXX,
- "return", LRETURN, Txxx, OXXX,
- "select", LSELECT, Txxx, OXXX,
- "struct", LSTRUCT, Txxx, OXXX,
- "switch", LSWITCH, Txxx, OXXX,
- "type", LTYPE, Txxx, OXXX,
- "var", LVAR, Txxx, OXXX,
-
- "append", LNAME, Txxx, OAPPEND,
- "cap", LNAME, Txxx, OCAP,
- "close", LNAME, Txxx, OCLOSE,
- "complex", LNAME, Txxx, OCOMPLEX,
- "copy", LNAME, Txxx, OCOPY,
- "imag", LNAME, Txxx, OIMAG,
- "len", LNAME, Txxx, OLEN,
- "make", LNAME, Txxx, OMAKE,
- "new", LNAME, Txxx, ONEW,
- "panic", LNAME, Txxx, OPANIC,
- "print", LNAME, Txxx, OPRINT,
- "println", LNAME, Txxx, OPRINTN,
- "real", LNAME, Txxx, OREAL,
- "recover", LNAME, Txxx, ORECOVER,
-
- "notwithstanding", LIGNORE, Txxx, OXXX,
- "thetruthofthematter", LIGNORE, Txxx, OXXX,
- "despiteallobjections", LIGNORE, Txxx, OXXX,
- "whereas", LIGNORE, Txxx, OXXX,
- "insofaras", LIGNORE, Txxx, OXXX,
-};
-
-static void
-lexinit(void)
-{
- int i, lex;
- Sym *s, *s1;
- Type *t;
- int etype;
-
- /*
- * initialize basic types array
- * initialize known symbols
- */
- for(i=0; i<nelem(syms); i++) {
- lex = syms[i].lexical;
- s = lookup(syms[i].name);
- s->lexical = lex;
-
- etype = syms[i].etype;
- if(etype != Txxx) {
- if(etype < 0 || etype >= nelem(types))
- fatal("lexinit: %s bad etype", s->name);
- t = types[etype];
- if(t == T) {
- t = typ(etype);
- t->sym = s;
-
- if(etype != TANY && etype != TSTRING)
- dowidth(t);
- types[etype] = t;
- }
- s1 = pkglookup(syms[i].name, builtinpkg);
- s1->lexical = LNAME;
- s1->def = typenod(t);
- continue;
- }
- }
-
- // logically, the type of a string literal.
- // types[TSTRING] is the named type string
- // (the type of x in var x string or var x = "hello").
- // this is the ideal form
- // (the type of x in const x = "hello").
- idealstring = typ(TSTRING);
- idealbool = typ(TBOOL);
-
- s = pkglookup("true", builtinpkg);
- s->def = nodbool(1);
- s->def->sym = lookup("true");
- s->def->type = idealbool;
-
- s = pkglookup("false", builtinpkg);
- s->def = nodbool(0);
- s->def->sym = lookup("false");
- s->def->type = idealbool;
-
- s = lookup("_");
- s->block = -100;
- s->def = nod(ONAME, N, N);
- s->def->sym = s;
- types[TBLANK] = typ(TBLANK);
- s->def->type = types[TBLANK];
- nblank = s->def;
-}
-
-static void
-lexfini(void)
-{
- Sym *s;
- int lex, etype, i;
- Val v;
-
- for(i=0; i<nelem(syms); i++) {
- lex = syms[i].lexical;
- if(lex != LNAME)
- continue;
- s = lookup(syms[i].name);
- s->lexical = lex;
-
- etype = syms[i].etype;
- if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N)
- s->def = typenod(types[etype]);
-
- etype = syms[i].op;
- if(etype != OXXX && s->def == N) {
- s->def = nod(ONAME, N, N);
- s->def->sym = s;
- s->def->etype = etype;
- s->def->builtin = 1;
- }
- }
-
- for(i=0; typedefs[i].name; i++) {
- s = lookup(typedefs[i].name);
- if(s->def == N)
- s->def = typenod(types[typedefs[i].etype]);
- }
-
- // there's only so much table-driven we can handle.
- // these are special cases.
- types[TNIL] = typ(TNIL);
- s = lookup("nil");
- if(s->def == N) {
- v.ctype = CTNIL;
- s->def = nodlit(v);
- s->def->sym = s;
- }
-
- s = lookup("iota");
- if(s->def == N) {
- s->def = nod(OIOTA, N, N);
- s->def->sym = s;
- }
-
- s = lookup("true");
- if(s->def == N) {
- s->def = nodbool(1);
- s->def->sym = s;
- }
-
- s = lookup("false");
- if(s->def == N) {
- s->def = nodbool(0);
- s->def->sym = s;
- }
-
- nodfp = nod(ONAME, N, N);
- nodfp->noescape = 1;
- nodfp->type = types[TINT32];
- nodfp->xoffset = 0;
- nodfp->class = PPARAM;
- nodfp->sym = lookup(".fp");
-}
-
-struct
-{
- int lex;
- char* name;
-} lexn[] =
-{
- LANDAND, "ANDAND",
- LASOP, "ASOP",
- LBREAK, "BREAK",
- LCASE, "CASE",
- LCHAN, "CHAN",
- LCOLAS, "COLAS",
- LCONST, "CONST",
- LCONTINUE, "CONTINUE",
- LDEC, "DEC",
- LDEFER, "DEFER",
- LELSE, "ELSE",
- LEQ, "EQ",
- LFALL, "FALL",
- LFOR, "FOR",
- LFUNC, "FUNC",
- LGE, "GE",
- LGO, "GO",
- LGOTO, "GOTO",
- LGT, "GT",
- LIF, "IF",
- LIMPORT, "IMPORT",
- LINC, "INC",
- LINTERFACE, "INTERFACE",
- LLE, "LE",
- LLITERAL, "LITERAL",
- LLSH, "LSH",
- LLT, "LT",
- LMAP, "MAP",
- LNAME, "NAME",
- LNE, "NE",
- LOROR, "OROR",
- LPACKAGE, "PACKAGE",
- LRANGE, "RANGE",
- LRETURN, "RETURN",
- LRSH, "RSH",
- LSTRUCT, "STRUCT",
- LSWITCH, "SWITCH",
- LTYPE, "TYPE",
- LVAR, "VAR",
-};
-
-char*
-lexname(int lex)
-{
- int i;
- static char buf[100];
-
- for(i=0; i<nelem(lexn); i++)
- if(lexn[i].lex == lex)
- return lexn[i].name;
- snprint(buf, sizeof(buf), "LEX-%d", lex);
- return buf;
-}
-
-struct
-{
- char *have;
- char *want;
-} yytfix[] =
-{
- "$end", "EOF",
- "LLITERAL", "literal",
- "LASOP", "op=",
- "LBREAK", "break",
- "LCASE", "case",
- "LCOLAS", ":=",
- "LCONST", "const",
- "LCONTINUE", "continue",
- "LDDD", "...",
- "LDEFAULT", "default",
- "LDEFER", "defer",
- "LELSE", "else",
- "LFALL", "fallthrough",
- "LFOR", "for",
- "LFUNC", "func",
- "LGO", "go",
- "LGOTO", "goto",
- "LIF", "if",
- "LIMPORT", "import",
- "LINTERFACE", "interface",
- "LMAP", "map",
- "LNAME", "name",
- "LPACKAGE", "package",
- "LRANGE", "range",
- "LRETURN", "return",
- "LSELECT", "select",
- "LSTRUCT", "struct",
- "LSWITCH", "switch",
- "LTYPE", "type",
- "LVAR", "var",
- "LANDAND", "&&",
- "LANDNOT", "&^",
- "LBODY", "{",
- "LCOMM", "<-",
- "LDEC", "--",
- "LINC", "++",
- "LEQ", "==",
- "LGE", ">=",
- "LGT", ">",
- "LLE", "<=",
- "LLT", "<",
- "LLSH", "<<",
- "LRSH", ">>",
- "LOROR", "||",
- "LNE", "!=",
-
- // spell out to avoid confusion with punctuation in error messages
- "';'", "semicolon or newline",
- "','", "comma",
-};
-
-static void
-yytinit(void)
-{
- int i, j;
- extern char *yytname[];
- char *s, *t;
-
- for(i=0; yytname[i] != nil; i++) {
- s = yytname[i];
-
- // apply yytfix if possible
- for(j=0; j<nelem(yytfix); j++) {
- if(strcmp(s, yytfix[j].have) == 0) {
- yytname[i] = yytfix[j].want;
- goto loop;
- }
- }
-
- // turn 'x' into x.
- if(s[0] == '\'') {
- t = strdup(s+1);
- t[strlen(t)-1] = '\0';
- yytname[i] = t;
- }
- loop:;
- }
-}
-
-void
-mkpackage(char* pkgname)
-{
- Sym *s;
- int32 h;
- char *p;
-
- if(localpkg->name == nil) {
- if(strcmp(pkgname, "_") == 0)
- yyerror("invalid package name _");
- localpkg->name = pkgname;
- } else {
- if(strcmp(pkgname, localpkg->name) != 0)
- yyerror("package %s; expected %s", pkgname, localpkg->name);
- for(h=0; h<NHASH; h++) {
- for(s = hash[h]; s != S; s = s->link) {
- if(s->def == N || s->pkg != localpkg)
- continue;
- if(s->def->op == OPACK) {
- // throw away top-level package name leftover
- // from previous file.
- // leave s->block set to cause redeclaration
- // errors if a conflicting top-level name is
- // introduced by a different file.
- if(!s->def->used && !nsyntaxerrors)
- yyerrorl(s->def->lineno, "imported and not used: %Z", s->def->pkg->path);
- s->def = N;
- continue;
- }
- if(s->def->sym != s) {
- // throw away top-level name left over
- // from previous import . "x"
- if(s->def->pack != N && !s->def->pack->used && !nsyntaxerrors) {
- yyerrorl(s->def->pack->lineno, "imported and not used: %Z", s->def->pack->pkg->path);
- s->def->pack->used = 1;
- }
- s->def = N;
- continue;
- }
- }
- }
- }
-
- if(outfile == nil) {
- p = strrchr(infile, '/');
- if(p == nil)
- p = infile;
- else
- p = p+1;
- snprint(namebuf, sizeof(namebuf), "%s", p);
- p = strrchr(namebuf, '.');
- if(p != nil)
- *p = 0;
- outfile = smprint("%s.%c", namebuf, thechar);
- }
-}
diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c
deleted file mode 100644
index 7cea1a6cf..000000000
--- a/src/cmd/gc/md5.c
+++ /dev/null
@@ -1,290 +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.
-
-// 64-bit MD5 (does full MD5 but returns 64 bits only).
-// Translation of ../../pkg/crypto/md5/md5*.go.
-
-#include "go.h"
-#include "md5.h"
-
-static int md5block(MD5 *dig, uchar *p, int nn);
-
-enum {
- _Chunk = 64
-};
-
-#define _Init0 0x67452301
-#define _Init1 0xEFCDAB89
-#define _Init2 0x98BADCFE
-#define _Init3 0x10325476
-
-void
-md5reset(MD5 *d)
-{
- d->s[0] = _Init0;
- d->s[1] = _Init1;
- d->s[2] = _Init2;
- d->s[3] = _Init3;
- d->nx = 0;
- d->len = 0;
-}
-
-void
-md5write(MD5 *d, uchar *p, int nn)
-{
- int i, n;
-
- d->len += nn;
- if(d->nx > 0) {
- n = nn;
- if(n > _Chunk - d->nx)
- n = _Chunk - d->nx;
- for(i=0; i<n; i++)
- d->x[d->nx+i] = p[i];
- d->nx += n;
- if(d->nx == _Chunk) {
- md5block(d, d->x, _Chunk);
- d->nx = 0;
- }
- p += n;
- nn -= n;
- }
- n = md5block(d, p, nn);
- p += n;
- nn -= n;
- if(nn > 0) {
- for(i=0; i<nn; i++)
- d->x[i] = p[i];
- d->nx = nn;
- }
-}
-
-uint64
-md5sum(MD5 *d)
-{
- uchar tmp[64];
- int i;
- uint64 len;
-
- // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
- len = d->len;
- memset(tmp, 0, sizeof tmp);
- tmp[0] = 0x80;
- if(len%64 < 56)
- md5write(d, tmp, 56-len%64);
- else
- md5write(d, tmp, 64+56-len%64);
-
- // Length in bits.
- len <<= 3;
- for(i=0; i<8; i++)
- tmp[i] = len>>(8*i);
- md5write(d, tmp, 8);
-
- if(d->nx != 0)
- fatal("md5sum");
-
- return d->s[0] | ((uint64)d->s[1]<<32);
-}
-
-
-// MD5 block step.
-// In its own file so that a faster assembly or C version
-// can be substituted easily.
-
-// table[i] = int((1<<32) * abs(sin(i+1 radians))).
-static uint32 table[64] = {
- // round 1
- 0xd76aa478,
- 0xe8c7b756,
- 0x242070db,
- 0xc1bdceee,
- 0xf57c0faf,
- 0x4787c62a,
- 0xa8304613,
- 0xfd469501,
- 0x698098d8,
- 0x8b44f7af,
- 0xffff5bb1,
- 0x895cd7be,
- 0x6b901122,
- 0xfd987193,
- 0xa679438e,
- 0x49b40821,
-
- // round 2
- 0xf61e2562,
- 0xc040b340,
- 0x265e5a51,
- 0xe9b6c7aa,
- 0xd62f105d,
- 0x2441453,
- 0xd8a1e681,
- 0xe7d3fbc8,
- 0x21e1cde6,
- 0xc33707d6,
- 0xf4d50d87,
- 0x455a14ed,
- 0xa9e3e905,
- 0xfcefa3f8,
- 0x676f02d9,
- 0x8d2a4c8a,
-
- // round3
- 0xfffa3942,
- 0x8771f681,
- 0x6d9d6122,
- 0xfde5380c,
- 0xa4beea44,
- 0x4bdecfa9,
- 0xf6bb4b60,
- 0xbebfbc70,
- 0x289b7ec6,
- 0xeaa127fa,
- 0xd4ef3085,
- 0x4881d05,
- 0xd9d4d039,
- 0xe6db99e5,
- 0x1fa27cf8,
- 0xc4ac5665,
-
- // round 4
- 0xf4292244,
- 0x432aff97,
- 0xab9423a7,
- 0xfc93a039,
- 0x655b59c3,
- 0x8f0ccc92,
- 0xffeff47d,
- 0x85845dd1,
- 0x6fa87e4f,
- 0xfe2ce6e0,
- 0xa3014314,
- 0x4e0811a1,
- 0xf7537e82,
- 0xbd3af235,
- 0x2ad7d2bb,
- 0xeb86d391,
-};
-
-static uint32 shift1[] = { 7, 12, 17, 22 };
-static uint32 shift2[] = { 5, 9, 14, 20 };
-static uint32 shift3[] = { 4, 11, 16, 23 };
-static uint32 shift4[] = { 6, 10, 15, 21 };
-
-static int
-md5block(MD5 *dig, uchar *p, int nn)
-{
- uint32 a, b, c, d, aa, bb, cc, dd;
- int i, j, n;
- uint32 X[16];
-
- a = dig->s[0];
- b = dig->s[1];
- c = dig->s[2];
- d = dig->s[3];
- n = 0;
-
- while(nn >= _Chunk) {
- aa = a;
- bb = b;
- cc = c;
- dd = d;
-
- for(i=0; i<16; i++) {
- j = i*4;
- X[i] = p[j] | (p[j+1]<<8) | (p[j+2]<<16) | (p[j+3]<<24);
- }
-
- // Round 1.
- for(i=0; i<16; i++) {
- uint32 x, t, s, f;
- x = i;
- t = i;
- s = shift1[i%4];
- f = ((c ^ d) & b) ^ d;
- a += f + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- // Round 2.
- for(i=0; i<16; i++) {
- uint32 x, t, s, g;
-
- x = (1+5*i)%16;
- t = 16+i;
- s = shift2[i%4];
- g = ((b ^ c) & d) ^ c;
- a += g + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- // Round 3.
- for(i=0; i<16; i++) {
- uint32 x, t, s, h;
-
- x = (5+3*i)%16;
- t = 32+i;
- s = shift3[i%4];
- h = b ^ c ^ d;
- a += h + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- // Round 4.
- for(i=0; i<16; i++) {
- uint32 x, s, t, ii;
-
- x = (7*i)%16;
- s = shift4[i%4];
- t = 48+i;
- ii = c ^ (b | ~d);
- a += ii + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- a += aa;
- b += bb;
- c += cc;
- d += dd;
-
- p += _Chunk;
- n += _Chunk;
- nn -= _Chunk;
- }
-
- dig->s[0] = a;
- dig->s[1] = b;
- dig->s[2] = c;
- dig->s[3] = d;
- return n;
-}
diff --git a/src/cmd/gc/md5.h b/src/cmd/gc/md5.h
deleted file mode 100644
index f153e30f2..000000000
--- a/src/cmd/gc/md5.h
+++ /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.
-
-typedef struct MD5 MD5;
-struct MD5
-{
- uint32 s[4];
- uchar x[64];
- int nx;
- uint64 len;
-};
-
-void md5reset(MD5*);
-void md5write(MD5*, uchar*, int);
-uint64 md5sum(MD5*);
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
deleted file mode 100755
index 4dfff1caa..000000000
--- a/src/cmd/gc/mkbuiltin
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-# 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.
-
-# Generate builtin.c and builtin.c.boot from $* (runtime.go and unsafe.go).
-# Run this after changing runtime.go and unsafe.go
-# or after changing the export metadata format in the compiler.
-# Either way, you need to have a working compiler binary first.
-
-set -e
-
-eval $(gomake --no-print-directory -f ../../Make.inc go-env)
-if [ -z "$GC" ]; then
- echo 'missing $GC - gomake failed?' 1>&2
- exit 1
-fi
-
-gcc -o mkbuiltin1 mkbuiltin1.c
-rm -f _builtin.c
-for i in runtime unsafe
-do
- $GC -A $i.go
- O=$O ./mkbuiltin1 $i >>_builtin.c
-done
-
-# If _builtin.c has changed vs builtin.c.boot,
-# check in the new change.
-cmp -s _builtin.c builtin.c.boot || cp _builtin.c builtin.c.boot
-
-mv _builtin.c builtin.c
diff --git a/src/cmd/gc/mkbuiltin1.c b/src/cmd/gc/mkbuiltin1.c
deleted file mode 100644
index aa28e295b..000000000
--- a/src/cmd/gc/mkbuiltin1.c
+++ /dev/null
@@ -1,90 +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.
-
-// Compile .go file, import data from .6 file, and generate C string version.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-
-void esc(char*);
-
-int
-main(int argc, char **argv)
-{
- char *name;
- FILE *fin;
- char buf[1024], initfunc[1024], *p, *q;
-
- if(argc != 2) {
- fprintf(stderr, "usage: mkbuiltin1 sys\n");
- fprintf(stderr, "in file $1.6 s/PACKAGE/$1/\n");
- exit(1);
- }
-
- name = argv[1];
- snprintf(initfunc, sizeof(initfunc), "init_%s_function", name);
-
- snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O"));
- if((fin = fopen(buf, "r")) == NULL) {
- fprintf(stderr, "open %s: %s\n", buf, strerror(errno));
- exit(1);
- }
-
- // look for $$ that introduces imports
- while(fgets(buf, sizeof buf, fin) != NULL)
- if(strstr(buf, "$$"))
- goto begin;
- fprintf(stderr, "did not find beginning of imports\n");
- exit(1);
-
-begin:
- printf("char *%simport =\n", name);
-
- // process imports, stopping at $$ that closes them
- while(fgets(buf, sizeof buf, fin) != NULL) {
- buf[strlen(buf)-1] = 0; // chop \n
- if(strstr(buf, "$$"))
- goto end;
-
- // chop leading white space
- for(p=buf; *p==' ' || *p == '\t'; p++)
- ;
-
- // cut out decl of init_$1_function - it doesn't exist
- if(strstr(buf, initfunc))
- continue;
-
- // sys.go claims to be in package PACKAGE to avoid
- // conflicts during "6g sys.go". rename PACKAGE to $2.
- printf("\t\"");
- while(q = strstr(p, "PACKAGE")) {
- *q = 0;
- esc(p); // up to the substitution
- printf("%s", name); // the sub name
- p = q+7; // continue with rest
- }
-
- esc(p);
- printf("\\n\"\n", p);
- }
- fprintf(stderr, "did not find end of imports\n");
- exit(1);
-
-end:
- printf("\t\"$$\\n\";\n");
- return 0;
-}
-
-void
-esc(char *p)
-{
- for(; *p; p++) {
- if(*p == '\\' || *p == '\"')
- printf("\\");
- putchar(*p);
- }
-}
diff --git a/src/cmd/gc/mkopnames b/src/cmd/gc/mkopnames
deleted file mode 100755
index fb2ceec81..000000000
--- a/src/cmd/gc/mkopnames
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-# 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.
-
-# Disable colored grep if user has it set to --color=always.
-# (Arguably user error.)
-export GREP_OPTIONS=""
-
-echo '// auto generated by mkopnames'
-echo 'static char*'
-echo 'opnames[] = '
-echo '{'
-sed -n '/OXXX/,/OEND/p' go.h |
- cpp |
- sed 's!//.*!!; /^#/d' |
- tr ' ' '\n' |
- tr -d ' \t,' |
- grep . |
- sort |
- grep -v '^OEND$' |
- sed 's/O//; s/.*/ [O&] = "&",/'
-echo '};'
-
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
deleted file mode 100644
index 6cd4e2500..000000000
--- a/src/cmd/gc/mparith1.c
+++ /dev/null
@@ -1,509 +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 "go.h"
-
-/// uses arithmetic
-
-int
-mpcmpfixflt(Mpint *a, Mpflt *b)
-{
- char buf[500];
- Mpflt c;
-
- snprint(buf, sizeof(buf), "%B", a);
- mpatoflt(&c, buf);
- return mpcmpfltflt(&c, b);
-}
-
-int
-mpcmpfltfix(Mpflt *a, Mpint *b)
-{
- char buf[500];
- Mpflt c;
-
- snprint(buf, sizeof(buf), "%B", b);
- mpatoflt(&c, buf);
- return mpcmpfltflt(a, &c);
-}
-
-int
-mpcmpfixfix(Mpint *a, Mpint *b)
-{
- Mpint c;
-
- mpmovefixfix(&c, a);
- mpsubfixfix(&c, b);
- return mptestfix(&c);
-}
-
-int
-mpcmpfixc(Mpint *b, vlong c)
-{
- Mpint a;
-
- mpmovecfix(&a, c);
- return mpcmpfixfix(&a, b);
-}
-
-int
-mpcmpfltflt(Mpflt *a, Mpflt *b)
-{
- Mpflt c;
-
- mpmovefltflt(&c, a);
- mpsubfltflt(&c, b);
- return mptestflt(&c);
-}
-
-int
-mpcmpfltc(Mpflt *b, double c)
-{
- Mpflt a;
-
- mpmovecflt(&a, c);
- return mpcmpfltflt(&a, b);
-}
-
-void
-mpsubfixfix(Mpint *a, Mpint *b)
-{
- mpnegfix(a);
- mpaddfixfix(a, b);
- mpnegfix(a);
-}
-
-void
-mpsubfltflt(Mpflt *a, Mpflt *b)
-{
- mpnegflt(a);
- mpaddfltflt(a, b);
- mpnegflt(a);
-}
-
-void
-mpaddcfix(Mpint *a, vlong c)
-{
- Mpint b;
-
- mpmovecfix(&b, c);
- mpaddfixfix(a, &b);
-}
-
-void
-mpaddcflt(Mpflt *a, double c)
-{
- Mpflt b;
-
- mpmovecflt(&b, c);
- mpaddfltflt(a, &b);
-}
-
-void
-mpmulcfix(Mpint *a, vlong c)
-{
- Mpint b;
-
- mpmovecfix(&b, c);
- mpmulfixfix(a, &b);
-}
-
-void
-mpmulcflt(Mpflt *a, double c)
-{
- Mpflt b;
-
- mpmovecflt(&b, c);
- mpmulfltflt(a, &b);
-}
-
-void
-mpdivfixfix(Mpint *a, Mpint *b)
-{
- Mpint q, r;
-
- mpdivmodfixfix(&q, &r, a, b);
- mpmovefixfix(a, &q);
-}
-
-void
-mpmodfixfix(Mpint *a, Mpint *b)
-{
- Mpint q, r;
-
- mpdivmodfixfix(&q, &r, a, b);
- mpmovefixfix(a, &r);
-}
-
-void
-mpcomfix(Mpint *a)
-{
- Mpint b;
-
- mpmovecfix(&b, 1);
- mpnegfix(a);
- mpsubfixfix(a, &b);
-}
-
-void
-mpmovefixflt(Mpflt *a, Mpint *b)
-{
- a->val = *b;
- a->exp = 0;
- mpnorm(a);
-}
-
-// convert (truncate) b to a.
-// return -1 (but still convert) if b was non-integer.
-static int
-mpexactfltfix(Mpint *a, Mpflt *b)
-{
- Mpflt f;
-
- *a = b->val;
- mpshiftfix(a, b->exp);
- if(b->exp < 0) {
- f.val = *a;
- f.exp = 0;
- mpnorm(&f);
- if(mpcmpfltflt(b, &f) != 0)
- return -1;
- }
- return 0;
-}
-
-int
-mpmovefltfix(Mpint *a, Mpflt *b)
-{
- Mpflt f;
- int i;
-
- if(mpexactfltfix(a, b) == 0)
- return 0;
-
- // try rounding down a little
- f = *b;
- f.val.a[0] = 0;
- if(mpexactfltfix(a, &f) == 0)
- return 0;
-
- // try rounding up a little
- for(i=1; i<Mpprec; i++) {
- f.val.a[i]++;
- if(f.val.a[i] != Mpbase)
- break;
- f.val.a[i] = 0;
- }
- mpnorm(&f);
- if(mpexactfltfix(a, &f) == 0)
- return 0;
-
- return -1;
-}
-
-void
-mpmovefixfix(Mpint *a, Mpint *b)
-{
- *a = *b;
-}
-
-void
-mpmovefltflt(Mpflt *a, Mpflt *b)
-{
- *a = *b;
-}
-
-static double tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
-static void
-mppow10flt(Mpflt *a, int p)
-{
- if(p < 0)
- abort();
- if(p < nelem(tab)) {
- mpmovecflt(a, tab[p]);
- return;
- }
- mppow10flt(a, p>>1);
- mpmulfltflt(a, a);
- if(p & 1)
- mpmulcflt(a, 10);
-}
-
-//
-// floating point input
-// required syntax is [+-]d*[.]d*[e[+-]d*]
-//
-void
-mpatoflt(Mpflt *a, char *as)
-{
- Mpflt b;
- int dp, c, f, ef, ex, eb;
- char *s;
-
- s = as;
- dp = 0; /* digits after decimal point */
- f = 0; /* sign */
- ex = 0; /* exponent */
- eb = 0; /* binary point */
-
- mpmovecflt(a, 0.0);
- for(;;) {
- switch(c = *s++) {
- default:
- goto bad;
-
- case '-':
- f = 1;
-
- case ' ':
- case '\t':
- case '+':
- continue;
-
- case '.':
- dp = 1;
- continue;
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '0':
- mpmulcflt(a, 10);
- mpaddcflt(a, c-'0');
- if(dp)
- dp++;
- continue;
-
- case 'P':
- case 'p':
- eb = 1;
-
- case 'E':
- case 'e':
- ex = 0;
- ef = 0;
- for(;;) {
- c = *s++;
- if(c == '+' || c == ' ' || c == '\t')
- continue;
- if(c == '-') {
- ef = 1;
- continue;
- }
- if(c >= '0' && c <= '9') {
- ex = ex*10 + (c-'0');
- if(ex > 1e8) {
- yyerror("exponent out of range");
- errorexit();
- }
- continue;
- }
- break;
- }
- if(ef)
- ex = -ex;
-
- case 0:
- break;
- }
- break;
- }
-
- if(eb) {
- if(dp)
- goto bad;
- a->exp += ex;
- goto out;
- }
-
- if(dp)
- dp--;
- if(mpcmpfltc(a, 0.0) != 0) {
- if(ex >= dp) {
- mppow10flt(&b, ex-dp);
- mpmulfltflt(a, &b);
- } else {
- mppow10flt(&b, dp-ex);
- mpdivfltflt(a, &b);
- }
- }
-
-out:
- if(f)
- mpnegflt(a);
- return;
-
-bad:
- yyerror("set ovf in mpatof");
- mpmovecflt(a, 0.0);
-}
-
-//
-// fixed point input
-// required syntax is [+-][0[x]]d*
-//
-void
-mpatofix(Mpint *a, char *as)
-{
- int c, f;
- char *s;
-
- s = as;
- f = 0;
- mpmovecfix(a, 0);
-
- c = *s++;
- switch(c) {
- case '-':
- f = 1;
-
- case '+':
- c = *s++;
- if(c != '0')
- break;
-
- case '0':
- goto oct;
- }
-
- while(c) {
- if(c >= '0' && c <= '9') {
- mpmulcfix(a, 10);
- mpaddcfix(a, c-'0');
- c = *s++;
- continue;
- }
- goto bad;
- }
- goto out;
-
-oct:
- c = *s++;
- if(c == 'x' || c == 'X')
- goto hex;
- while(c) {
- if(c >= '0' && c <= '7') {
- mpmulcfix(a, 8);
- mpaddcfix(a, c-'0');
- c = *s++;
- continue;
- }
- goto bad;
- }
- goto out;
-
-hex:
- c = *s++;
- while(c) {
- if(c >= '0' && c <= '9') {
- mpmulcfix(a, 16);
- mpaddcfix(a, c-'0');
- c = *s++;
- continue;
- }
- if(c >= 'a' && c <= 'f') {
- mpmulcfix(a, 16);
- mpaddcfix(a, c+10-'a');
- c = *s++;
- continue;
- }
- if(c >= 'A' && c <= 'F') {
- mpmulcfix(a, 16);
- mpaddcfix(a, c+10-'A');
- c = *s++;
- continue;
- }
- goto bad;
- }
-
-out:
- if(f)
- mpnegfix(a);
- return;
-
-bad:
- yyerror("set ovf in mpatov: %s", as);
- mpmovecfix(a, 0);
-}
-
-int
-Bconv(Fmt *fp)
-{
- char buf[500], *p;
- Mpint *xval, q, r, ten;
- int f;
-
- xval = va_arg(fp->args, Mpint*);
- mpmovefixfix(&q, xval);
- f = 0;
- if(mptestfix(&q) < 0) {
- f = 1;
- mpnegfix(&q);
- }
- mpmovecfix(&ten, 10);
-
- p = &buf[sizeof(buf)];
- *--p = 0;
- for(;;) {
- mpdivmodfixfix(&q, &r, &q, &ten);
- *--p = mpgetfix(&r) + '0';
- if(mptestfix(&q) <= 0)
- break;
- }
- if(f)
- *--p = '-';
- return fmtstrcpy(fp, p);
-}
-
-int
-Fconv(Fmt *fp)
-{
- char buf[500];
- Mpflt *fvp, fv;
- double d;
-
- fvp = va_arg(fp->args, Mpflt*);
- if(fp->flags & FmtSharp) {
- // alternate form - decimal for error messages.
- // for well in range, convert to double and use print's %g
- if(-900 < fvp->exp && fvp->exp < 900) {
- d = mpgetflt(fvp);
- if(d >= 0 && (fp->flags & FmtSign))
- fmtprint(fp, "+");
- return fmtprint(fp, "%g", d);
- }
- // TODO(rsc): for well out of range, print
- // an approximation like 1.234e1000
- }
-
- if(sigfig(fvp) == 0) {
- snprint(buf, sizeof(buf), "0p+0");
- goto out;
- }
- fv = *fvp;
-
- while(fv.val.a[0] == 0) {
- mpshiftfix(&fv.val, -Mpscale);
- fv.exp += Mpscale;
- }
- while((fv.val.a[0]&1) == 0) {
- mpshiftfix(&fv.val, -1);
- fv.exp += 1;
- }
-
- if(fv.exp >= 0) {
- snprint(buf, sizeof(buf), "%Bp+%d", &fv.val, fv.exp);
- goto out;
- }
- snprint(buf, sizeof(buf), "%Bp-%d", &fv.val, -fv.exp);
-
-out:
- return fmtstrcpy(fp, buf);
-}
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
deleted file mode 100644
index 403255005..000000000
--- a/src/cmd/gc/mparith2.c
+++ /dev/null
@@ -1,683 +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 "go.h"
-
-//
-// return the significant
-// words of the argument
-//
-static int
-mplen(Mpint *a)
-{
- int i, n;
- long *a1;
-
- n = -1;
- a1 = &a->a[0];
- for(i=0; i<Mpprec; i++) {
- if(*a1++ != 0)
- n = i;
- }
- return n+1;
-}
-
-//
-// left shift mpint by one
-// ignores sign and overflow
-//
-static void
-mplsh(Mpint *a)
-{
- long *a1, x;
- int i, c;
-
- c = 0;
- a1 = &a->a[0];
- for(i=0; i<Mpprec; i++) {
- x = (*a1 << 1) + c;
- c = 0;
- if(x >= Mpbase) {
- x -= Mpbase;
- c = 1;
- }
- *a1++ = x;
- }
-}
-
-//
-// left shift mpint by Mpscale
-// ignores sign and overflow
-//
-static void
-mplshw(Mpint *a)
-{
- long *a1;
- int i;
-
- a1 = &a->a[Mpprec-1];
- for(i=1; i<Mpprec; i++) {
- a1[0] = a1[-1];
- a1--;
- }
- a1[0] = 0;
-}
-
-//
-// right shift mpint by one
-// ignores sign and overflow
-//
-static void
-mprsh(Mpint *a)
-{
- long *a1, x, lo;
- int i, c;
-
- c = 0;
- lo = a->a[0] & 1;
- a1 = &a->a[Mpprec];
- for(i=0; i<Mpprec; i++) {
- x = *--a1;
- *a1 = (x + c) >> 1;
- c = 0;
- if(x & 1)
- c = Mpbase;
- }
- if(a->neg && lo != 0)
- mpaddcfix(a, -1);
-}
-
-//
-// right shift mpint by Mpscale
-// ignores sign and overflow
-//
-static void
-mprshw(Mpint *a)
-{
- long *a1, lo;
- int i;
-
- lo = a->a[0];
- a1 = &a->a[0];
- for(i=1; i<Mpprec; i++) {
- a1[0] = a1[1];
- a1++;
- }
- a1[0] = 0;
- if(a->neg && lo != 0)
- mpaddcfix(a, -1);
-}
-
-//
-// return the sign of (abs(a)-abs(b))
-//
-static int
-mpcmp(Mpint *a, Mpint *b)
-{
- long x, *a1, *b1;
- int i;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in cmp");
- return 0;
- }
-
- a1 = &a->a[0] + Mpprec;
- b1 = &b->a[0] + Mpprec;
-
- for(i=0; i<Mpprec; i++) {
- x = *--a1 - *--b1;
- if(x > 0)
- return +1;
- if(x < 0)
- return -1;
- }
- return 0;
-}
-
-//
-// negate a
-// ignore sign and ovf
-//
-static void
-mpneg(Mpint *a)
-{
- long x, *a1;
- int i, c;
-
- a1 = &a->a[0];
- c = 0;
- for(i=0; i<Mpprec; i++) {
- x = -*a1 -c;
- c = 0;
- if(x < 0) {
- x += Mpbase;
- c = 1;
- }
- *a1++ = x;
- }
-}
-
-// shift left by s (or right by -s)
-void
-mpshiftfix(Mpint *a, int s)
-{
- if(s >= 0) {
- while(s >= Mpscale) {
- mplshw(a);
- s -= Mpscale;
- }
- while(s > 0) {
- mplsh(a);
- s--;
- }
- } else {
- s = -s;
- while(s >= Mpscale) {
- mprshw(a);
- s -= Mpscale;
- }
- while(s > 0) {
- mprsh(a);
- s--;
- }
- }
-}
-
-/// implements fix arihmetic
-
-void
-mpaddfixfix(Mpint *a, Mpint *b)
-{
- int i, c;
- long x, *a1, *b1;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mpaddxx");
- a->ovf = 1;
- return;
- }
-
- c = 0;
- a1 = &a->a[0];
- b1 = &b->a[0];
- if(a->neg != b->neg)
- goto sub;
-
- // perform a+b
- for(i=0; i<Mpprec; i++) {
- x = *a1 + *b1++ + c;
- c = 0;
- if(x >= Mpbase) {
- x -= Mpbase;
- c = 1;
- }
- *a1++ = x;
- }
- a->ovf = c;
- if(a->ovf)
- yyerror("set ovf in mpaddxx");
-
- return;
-
-sub:
- // perform a-b
- switch(mpcmp(a, b)) {
- case 0:
- mpmovecfix(a, 0);
- break;
-
- case 1:
- for(i=0; i<Mpprec; i++) {
- x = *a1 - *b1++ - c;
- c = 0;
- if(x < 0) {
- x += Mpbase;
- c = 1;
- }
- *a1++ = x;
- }
- break;
-
- case -1:
- a->neg ^= 1;
- for(i=0; i<Mpprec; i++) {
- x = *b1++ - *a1 - c;
- c = 0;
- if(x < 0) {
- x += Mpbase;
- c = 1;
- }
- *a1++ = x;
- }
- break;
- }
-}
-
-void
-mpmulfixfix(Mpint *a, Mpint *b)
-{
-
- int i, j, na, nb;
- long *a1, x;
- Mpint s, q;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mpmulfixfix");
- a->ovf = 1;
- return;
- }
-
- // pick the smaller
- // to test for bits
- na = mplen(a);
- nb = mplen(b);
- if(na > nb) {
- mpmovefixfix(&s, a);
- a1 = &b->a[0];
- na = nb;
- } else {
- mpmovefixfix(&s, b);
- a1 = &a->a[0];
- }
- s.neg = 0;
-
- mpmovecfix(&q, 0);
- for(i=0; i<na; i++) {
- x = *a1++;
- for(j=0; j<Mpscale; j++) {
- if(x & 1)
- mpaddfixfix(&q, &s);
- mplsh(&s);
- x >>= 1;
- }
- }
-
- q.neg = a->neg ^ b->neg;
- mpmovefixfix(a, &q);
- if(a->ovf)
- yyerror("set ovf in mpmulfixfix");
-}
-
-void
-mpmulfract(Mpint *a, Mpint *b)
-{
-
- int i, j;
- long *a1, x;
- Mpint s, q;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mpmulflt");
- a->ovf = 1;
- return;
- }
-
- mpmovefixfix(&s, b);
- a1 = &a->a[Mpprec];
- s.neg = 0;
- mpmovecfix(&q, 0);
-
- x = *--a1;
- if(x != 0)
- yyerror("mpmulfract not normal");
-
- for(i=0; i<Mpprec-1; i++) {
- x = *--a1;
- if(x == 0) {
- mprshw(&s);
- continue;
- }
- for(j=0; j<Mpscale; j++) {
- x <<= 1;
- if(x & Mpbase)
- mpaddfixfix(&q, &s);
- mprsh(&s);
- }
- }
-
- q.neg = a->neg ^ b->neg;
- mpmovefixfix(a, &q);
- if(a->ovf)
- yyerror("set ovf in mpmulflt");
-}
-
-void
-mporfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x, *a1, *b1;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mporfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- a1 = &a->a[0];
- b1 = &b->a[0];
- for(i=0; i<Mpprec; i++) {
- x = *a1 | *b1++;
- *a1++ = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mpandfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x, *a1, *b1;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mpandfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- a1 = &a->a[0];
- b1 = &b->a[0];
- for(i=0; i<Mpprec; i++) {
- x = *a1 & *b1++;
- *a1++ = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mpandnotfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x, *a1, *b1;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mpandnotfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- a1 = &a->a[0];
- b1 = &b->a[0];
- for(i=0; i<Mpprec; i++) {
- x = *a1 & ~*b1++;
- *a1++ = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mpxorfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x, *a1, *b1;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mporfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- a1 = &a->a[0];
- b1 = &b->a[0];
- for(i=0; i<Mpprec; i++) {
- x = *a1 ^ *b1++;
- *a1++ = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mplshfixfix(Mpint *a, Mpint *b)
-{
- vlong s;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mporfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- s = mpgetfix(b);
- if(s < 0 || s >= Mpprec*Mpscale) {
- yyerror("stupid shift: %lld", s);
- mpmovecfix(a, 0);
- return;
- }
-
- mpshiftfix(a, s);
-}
-
-void
-mprshfixfix(Mpint *a, Mpint *b)
-{
- vlong s;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mprshfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- s = mpgetfix(b);
- if(s < 0 || s >= Mpprec*Mpscale) {
- yyerror("stupid shift: %lld", s);
- if(a->neg)
- mpmovecfix(a, -1);
- else
- mpmovecfix(a, 0);
- return;
- }
-
- mpshiftfix(a, -s);
-}
-
-void
-mpnegfix(Mpint *a)
-{
- a->neg ^= 1;
-}
-
-vlong
-mpgetfix(Mpint *a)
-{
- vlong v;
-
- if(a->ovf) {
- yyerror("constant overflow");
- return 0;
- }
-
- v = (vlong)a->a[0];
- v |= (vlong)a->a[1] << Mpscale;
- v |= (vlong)a->a[2] << (Mpscale+Mpscale);
- if(a->neg)
- v = -v;
- return v;
-}
-
-void
-mpmovecfix(Mpint *a, vlong c)
-{
- int i;
- long *a1;
- vlong x;
-
- a->neg = 0;
- a->ovf = 0;
-
- x = c;
- if(x < 0) {
- a->neg = 1;
- x = -x;
- }
-
- a1 = &a->a[0];
- for(i=0; i<Mpprec; i++) {
- *a1++ = x&Mpmask;
- x >>= Mpscale;
- }
-}
-
-void
-mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
-{
- int i, ns, ds;
-
- ns = n->neg;
- ds = d->neg;
- n->neg = 0;
- d->neg = 0;
-
- mpmovefixfix(r, n);
- mpmovecfix(q, 0);
-
- // shift denominator until it
- // is larger than numerator
- for(i=0; i<Mpprec*Mpscale; i++) {
- if(mpcmp(d, r) > 0)
- break;
- mplsh(d);
- }
-
- // if it never happens
- // denominator is probably zero
- if(i >= Mpprec*Mpscale) {
- q->ovf = 1;
- r->ovf = 1;
- n->neg = ns;
- d->neg = ds;
- yyerror("set ovf in mpdivmodfixfix");
- return;
- }
-
- // shift denominator back creating
- // quotient a bit at a time
- // when done the remaining numerator
- // will be the remainder
- for(; i>0; i--) {
- mplsh(q);
- mprsh(d);
- if(mpcmp(d, r) <= 0) {
- mpaddcfix(q, 1);
- mpsubfixfix(r, d);
- }
- }
-
- n->neg = ns;
- d->neg = ds;
- r->neg = ns;
- q->neg = ns^ds;
-}
-
-static int
-iszero(Mpint *a)
-{
- long *a1;
- int i;
- a1 = &a->a[0] + Mpprec;
- for(i=0; i<Mpprec; i++) {
- if(*--a1 != 0)
- return 0;
- }
- return 1;
-}
-
-void
-mpdivfract(Mpint *a, Mpint *b)
-{
- Mpint n, d;
- int i, j, neg;
- long *a1, x;
-
- mpmovefixfix(&n, a); // numerator
- mpmovefixfix(&d, b); // denominator
- a1 = &a->a[Mpprec]; // quotient
-
- neg = n.neg ^ d.neg;
- n.neg = 0;
- d.neg = 0;
- for(i=0; i<Mpprec; i++) {
- x = 0;
- for(j=0; j<Mpscale; j++) {
- x <<= 1;
- if(mpcmp(&d, &n) <= 0) {
- if(!iszero(&d))
- x |= 1;
- mpsubfixfix(&n, &d);
- }
- mprsh(&d);
- }
- *--a1 = x;
- }
- a->neg = neg;
-}
-
-int
-mptestfix(Mpint *a)
-{
- Mpint b;
- int r;
-
- mpmovecfix(&b, 0);
- r = mpcmp(a, &b);
- if(a->neg) {
- if(r > 0)
- return -1;
- if(r < 0)
- return +1;
- }
- return r;
-}
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
deleted file mode 100644
index b11a4f5f1..000000000
--- a/src/cmd/gc/mparith3.c
+++ /dev/null
@@ -1,313 +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 "go.h"
-
-/*
- * returns the leading non-zero
- * word of the number
- */
-int
-sigfig(Mpflt *a)
-{
- int i;
-
- for(i=Mpprec-1; i>=0; i--)
- if(a->val.a[i] != 0)
- break;
-//print("sigfig %d %d\n", i-z+1, z);
- return i+1;
-}
-
-/*
- * shifts the leading non-zero
- * word of the number to Mpnorm
- */
-void
-mpnorm(Mpflt *a)
-{
- int s, os;
- long x;
-
- os = sigfig(a);
- if(os == 0) {
- // zero
- a->exp = 0;
- a->val.neg = 0;
- return;
- }
-
- // this will normalize to the nearest word
- x = a->val.a[os-1];
- s = (Mpnorm-os) * Mpscale;
-
- // further normalize to the nearest bit
- for(;;) {
- x <<= 1;
- if(x & Mpbase)
- break;
- s++;
- if(x == 0) {
- // this error comes from trying to
- // convert an Inf or something
- // where the initial x=0x80000000
- s = (Mpnorm-os) * Mpscale;
- break;
- }
- }
-
- mpshiftfix(&a->val, s);
- a->exp -= s;
-}
-
-/// implements float arihmetic
-
-void
-mpaddfltflt(Mpflt *a, Mpflt *b)
-{
- int sa, sb, s;
- Mpflt c;
-
- if(Mpdebug)
- print("\n%F + %F", a, b);
-
- sa = sigfig(a);
- if(sa == 0) {
- mpmovefltflt(a, b);
- goto out;
- }
-
- sb = sigfig(b);
- if(sb == 0)
- goto out;
-
- s = a->exp - b->exp;
- if(s > 0) {
- // a is larger, shift b right
- mpmovefltflt(&c, b);
- mpshiftfix(&c.val, -s);
- mpaddfixfix(&a->val, &c.val);
- goto out;
- }
- if(s < 0) {
- // b is larger, shift a right
- mpshiftfix(&a->val, s);
- a->exp -= s;
- mpaddfixfix(&a->val, &b->val);
- goto out;
- }
- mpaddfixfix(&a->val, &b->val);
-
-out:
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n\n", a);
-}
-
-void
-mpmulfltflt(Mpflt *a, Mpflt *b)
-{
- int sa, sb;
-
- if(Mpdebug)
- print("%F\n * %F\n", a, b);
-
- sa = sigfig(a);
- if(sa == 0) {
- // zero
- a->exp = 0;
- a->val.neg = 0;
- return;
- }
-
- sb = sigfig(b);
- if(sb == 0) {
- // zero
- mpmovefltflt(a, b);
- return;
- }
-
- mpmulfract(&a->val, &b->val);
- a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1;
-
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n\n", a);
-}
-
-void
-mpdivfltflt(Mpflt *a, Mpflt *b)
-{
- int sa, sb;
- Mpflt c;
-
- if(Mpdebug)
- print("%F\n / %F\n", a, b);
-
- sb = sigfig(b);
- if(sb == 0) {
- // zero and ovfl
- a->exp = 0;
- a->val.neg = 0;
- a->val.ovf = 1;
- yyerror("mpdivfltflt divide by zero");
- return;
- }
-
- sa = sigfig(a);
- if(sa == 0) {
- // zero
- a->exp = 0;
- a->val.neg = 0;
- return;
- }
-
- // adjust b to top
- mpmovefltflt(&c, b);
- mpshiftfix(&c.val, Mpscale);
-
- // divide
- mpdivfract(&a->val, &c.val);
- a->exp = (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1;
-
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n\n", a);
-}
-
-double
-mpgetflt(Mpflt *a)
-{
- int s, i, e;
- uvlong v, vm;
- double f;
-
- if(a->val.ovf)
- yyerror("mpgetflt ovf");
-
- s = sigfig(a);
- if(s == 0)
- return 0;
-
- if(s != Mpnorm) {
- yyerror("mpgetflt norm");
- mpnorm(a);
- }
-
- while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
- mpshiftfix(&a->val, 1);
- a->exp -= 1;
- }
-
- // the magic numbers (64, 63, 53, 10, -1074) are
- // IEEE specific. this should be done machine
- // independently or in the 6g half of the compiler
-
- // pick up the mantissa and a rounding bit in a uvlong
- s = 53+1;
- v = 0;
- for(i=Mpnorm-1; s>=Mpscale; i--) {
- v = (v<<Mpscale) | a->val.a[i];
- s -= Mpscale;
- }
- vm = v;
- if(s > 0)
- vm = (vm<<s) | (a->val.a[i]>>(Mpscale-s));
-
- // continue with 64 more bits
- s += 64;
- for(; s>=Mpscale; i--) {
- v = (v<<Mpscale) | a->val.a[i];
- s -= Mpscale;
- }
- if(s > 0)
- v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
-
- // gradual underflow
- e = Mpnorm*Mpscale + a->exp - 53;
- if(e < -1074) {
- s = -e - 1074;
- if(s > 54)
- s = 54;
- v |= vm & ((1ULL<<s) - 1);
- vm >>= s;
- e = -1074;
- }
-
-//print("vm=%.16llux v=%.16llux\n", vm, v);
- // round toward even
- if(v != 0 || (vm&2ULL) != 0)
- vm = (vm>>1) + (vm&1ULL);
- else
- vm >>= 1;
-
- f = (double)(vm);
- f = ldexp(f, e);
-
- if(a->val.neg)
- f = -f;
- return f;
-}
-
-void
-mpmovecflt(Mpflt *a, double c)
-{
- int i;
- double f;
- long l;
-
- if(Mpdebug)
- print("\nconst %g", c);
- mpmovecfix(&a->val, 0);
- a->exp = 0;
- if(c == 0)
- goto out;
- if(c < 0) {
- a->val.neg = 1;
- c = -c;
- }
-
- f = frexp(c, &i);
- a->exp = i;
-
- for(i=0; i<10; i++) {
- f = f*Mpbase;
- l = floor(f);
- f = f - l;
- a->exp -= Mpscale;
- a->val.a[0] = l;
- if(f == 0)
- break;
- mpshiftfix(&a->val, Mpscale);
- }
-
-out:
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n", a);
-}
-
-void
-mpnegflt(Mpflt *a)
-{
- a->val.neg ^= 1;
-}
-
-int
-mptestflt(Mpflt *a)
-{
- int s;
-
- if(Mpdebug)
- print("\n%F?", a);
- s = sigfig(a);
- if(s != 0) {
- s = +1;
- if(a->val.neg)
- s = -1;
- }
- if(Mpdebug)
- print(" = %d\n", s);
- return s;
-}
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
deleted file mode 100644
index f34fc76c8..000000000
--- a/src/cmd/gc/obj.c
+++ /dev/null
@@ -1,292 +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 "go.h"
-
-/*
- * architecture-independent object file output
- */
-
-static void outhist(Biobuf *b);
-static void dumpglobls(void);
-
-void
-dumpobj(void)
-{
- bout = Bopen(outfile, OWRITE);
- if(bout == nil) {
- flusherrors();
- print("can't create %s: %r\n", outfile);
- errorexit();
- }
-
- Bprint(bout, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
- Bprint(bout, " exports automatically generated from\n");
- Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name);
- dumpexport();
- Bprint(bout, "\n!\n");
-
- outhist(bout);
-
- // add nil plist w AEND to catch
- // auto-generated trampolines, data
- newplist();
-
- dumpglobls();
- dumptypestructs();
- dumpdata();
- dumpfuncs();
-
- Bterm(bout);
-}
-
-static void
-dumpglobls(void)
-{
- Node *n;
- NodeList *l;
-
- // add globals
- for(l=externdcl; l; l=l->next) {
- n = l->n;
- if(n->op != ONAME)
- continue;
-
- if(n->type == T)
- fatal("external %#N nil type\n", n);
- if(n->class == PFUNC)
- continue;
- if(n->sym->pkg != localpkg)
- continue;
- dowidth(n->type);
-
- ggloblnod(n, n->type->width);
- }
-}
-
-void
-Bputname(Biobuf *b, Sym *s)
-{
- Bprint(b, "%s", s->pkg->prefix);
- Bputc(b, '.');
- Bwrite(b, s->name, strlen(s->name)+1);
-}
-
-static void
-outzfile(Biobuf *b, char *p)
-{
- char *q, *q2;
-
- while(p) {
- q = utfrune(p, '/');
- if(windows) {
- q2 = utfrune(p, '\\');
- if(q2 && (!q || q2 < q))
- q = q2;
- }
- if(!q) {
- zfile(b, p, strlen(p));
- return;
- }
- if(q > p)
- zfile(b, p, q-p);
- p = q + 1;
- }
-}
-
-#define isdelim(c) (c == '/' || c == '\\')
-
-static void
-outwinname(Biobuf *b, Hist *h, char *ds, char *p)
-{
- if(isdelim(p[0])) {
- // full rooted name
- zfile(b, ds, 3); // leading "c:/"
- outzfile(b, p+1);
- } else {
- // relative name
- if(h->offset == 0 && pathname && pathname[1] == ':') {
- if(tolowerrune(ds[0]) == tolowerrune(pathname[0])) {
- // using current drive
- zfile(b, pathname, 3); // leading "c:/"
- outzfile(b, pathname+3);
- } else {
- // using drive other then current,
- // we don't have any simple way to
- // determine current working directory
- // there, therefore will output name as is
- zfile(b, ds, 2); // leading "c:"
- }
- }
- outzfile(b, p);
- }
-}
-
-static void
-outhist(Biobuf *b)
-{
- Hist *h;
- char *p, ds[] = {'c', ':', '/', 0};
-
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- if(p) {
- if(windows) {
- // if windows variable is set, then, we know already,
- // pathname is started with windows drive specifier
- // and all '\' were replaced with '/' (see lex.c)
- if(isdelim(p[0]) && isdelim(p[1])) {
- // file name has network name in it,
- // like \\server\share\dir\file.go
- zfile(b, "//", 2); // leading "//"
- outzfile(b, p+2);
- } else if(p[1] == ':') {
- // file name has drive letter in it
- ds[0] = p[0];
- outwinname(b, h, ds, p+2);
- } else {
- // no drive letter in file name
- outwinname(b, h, pathname, p);
- }
- } else {
- if(p[0] == '/') {
- // full rooted name, like /home/rsc/dir/file.go
- zfile(b, "/", 1); // leading "/"
- outzfile(b, p+1);
- } else {
- // relative name, like dir/file.go
- if(h->offset == 0 && pathname && pathname[0] == '/') {
- zfile(b, "/", 1); // leading "/"
- outzfile(b, pathname+1);
- }
- outzfile(b, p);
- }
- }
- }
- zhist(b, h->line, h->offset);
- }
-}
-
-void
-ieeedtod(uint64 *ieee, double native)
-{
- double fr, ho, f;
- int exp;
- uint32 h, l;
- uint64 bits;
-
- if(native < 0) {
- ieeedtod(ieee, -native);
- *ieee |= 1ULL<<63;
- return;
- }
- if(native == 0) {
- *ieee = 0;
- return;
- }
- fr = frexp(native, &exp);
- f = 2097152L; /* shouldnt use fp constants here */
- fr = modf(fr*f, &ho);
- h = ho;
- h &= 0xfffffL;
- f = 65536L;
- fr = modf(fr*f, &ho);
- l = ho;
- l <<= 16;
- l |= (int32)(fr*f);
- bits = ((uint64)h<<32) | l;
- if(exp < -1021) {
- // gradual underflow
- bits |= 1LL<<52;
- bits >>= -1021 - exp;
- exp = -1022;
- }
- bits |= (uint64)(exp+1022L) << 52;
- *ieee = bits;
-}
-
-int
-duint8(Sym *s, int off, uint8 v)
-{
- return duintxx(s, off, v, 1);
-}
-
-int
-duint16(Sym *s, int off, uint16 v)
-{
- return duintxx(s, off, v, 2);
-}
-
-int
-duint32(Sym *s, int off, uint32 v)
-{
- return duintxx(s, off, v, 4);
-}
-
-int
-duint64(Sym *s, int off, uint64 v)
-{
- return duintxx(s, off, v, 8);
-}
-
-int
-duintptr(Sym *s, int off, uint64 v)
-{
- return duintxx(s, off, v, widthptr);
-}
-
-Sym*
-stringsym(char *s, int len)
-{
- static int gen;
- Sym *sym;
- int off, n, m;
- struct {
- Strlit lit;
- char buf[110];
- } tmp;
- Pkg *pkg;
-
- if(len > 100) {
- // huge strings are made static to avoid long names
- snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen);
- pkg = localpkg;
- } else {
- // small strings get named by their contents,
- // so that multiple modules using the same string
- // can share it.
- tmp.lit.len = len;
- memmove(tmp.lit.s, s, len);
- tmp.lit.s[len] = '\0';
- snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp);
- pkg = gostringpkg;
- }
- sym = pkglookup(namebuf, pkg);
-
- // SymUniq flag indicates that data is generated already
- if(sym->flags & SymUniq)
- return sym;
- sym->flags |= SymUniq;
-
- data();
- off = 0;
-
- // string header
- off = dsymptr(sym, off, sym, widthptr+4);
- off = duint32(sym, off, len);
-
- // string data
- for(n=0; n<len; n+=m) {
- m = 8;
- if(m > len-n)
- m = len-n;
- off = dsname(sym, off, s+n, m);
- }
- off = duint8(sym, off, 0); // terminating NUL for runtime
- off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment
- ggloblsym(sym, off, 1);
- text();
-
- return sym;
-}
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
deleted file mode 100644
index 552e405d8..000000000
--- a/src/cmd/gc/pgen.c
+++ /dev/null
@@ -1,210 +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 "gg.h"
-#include "opt.h"
-
-static void compactframe(Prog* p);
-
-void
-compile(Node *fn)
-{
- Plist *pl;
- Node nod1, *n;
- Prog *ptxt;
- int32 lno;
- Type *t;
- Iter save;
- vlong oldstksize;
-
- if(newproc == N) {
- newproc = sysfunc("newproc");
- deferproc = sysfunc("deferproc");
- deferreturn = sysfunc("deferreturn");
- panicindex = sysfunc("panicindex");
- panicslice = sysfunc("panicslice");
- throwreturn = sysfunc("throwreturn");
- }
-
- if(fn->nbody == nil)
- return;
-
- saveerrors();
-
- // set up domain for labels
- clearlabels();
-
- lno = setlineno(fn);
-
- curfn = fn;
- dowidth(curfn->type);
-
- if(curfn->type->outnamed) {
- // add clearing of the output parameters
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- if(t->nname != N) {
- n = nod(OAS, t->nname, N);
- typecheck(&n, Etop);
- curfn->nbody = concat(list1(n), curfn->nbody);
- }
- t = structnext(&save);
- }
- }
-
- hasdefer = 0;
- walk(curfn);
- if(nerrors != 0)
- goto ret;
-
- allocparams();
-
- continpc = P;
- breakpc = P;
-
- pl = newplist();
- pl->name = curfn->nname;
-
- setlineno(curfn);
-
- nodconst(&nod1, types[TINT32], 0);
- ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
- afunclit(&ptxt->from);
-
- ginit();
- genlist(curfn->enter);
-
- retpc = nil;
- if(hasdefer || curfn->exit) {
- Prog *p1;
-
- p1 = gjmp(nil);
- retpc = gjmp(nil);
- patch(p1, pc);
- }
-
- genlist(curfn->nbody);
- gclean();
- checklabels();
- if(nerrors != 0)
- goto ret;
- if(curfn->endlineno)
- lineno = curfn->endlineno;
-
- if(curfn->type->outtuple != 0)
- ginscall(throwreturn, 0);
-
- if(retpc)
- patch(retpc, pc);
- ginit();
- if(hasdefer)
- ginscall(deferreturn, 0);
- if(curfn->exit)
- genlist(curfn->exit);
- gclean();
- if(nerrors != 0)
- goto ret;
- pc->as = ARET; // overwrite AEND
- pc->lineno = lineno;
-
- if(!debug['N'] || debug['R'] || debug['P']) {
- regopt(ptxt);
- }
-
- oldstksize = stksize;
- compactframe(ptxt);
- if(0)
- print("compactframe: %ld to %ld\n", oldstksize, stksize);
-
- defframe(ptxt);
-
- if(0)
- frame(0);
-
-ret:
- lineno = lno;
-}
-
-
-// Sort the list of stack variables. autos after anything else,
-// within autos, unused after used, and within used on reverse alignment.
-// non-autos sort on offset.
-static int
-cmpstackvar(Node *a, Node *b)
-{
- if (a->class != b->class)
- return (a->class == PAUTO) ? 1 : -1;
- if (a->class != PAUTO)
- return a->xoffset - b->xoffset;
- if ((a->used == 0) != (b->used == 0))
- return b->used - a->used;
- return b->type->align - a->type->align;
-
-}
-
-// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
-static void
-compactframe(Prog* ptxt)
-{
- NodeList *ll;
- Node* n;
- uint32 w;
-
- if (stksize == 0)
- return;
-
- // Mark the PAUTO's unused.
- for(ll=curfn->dcl; ll != nil; ll=ll->next)
- if (ll->n->class == PAUTO)
- ll->n->used = 0;
-
- markautoused(ptxt);
-
- listsort(&curfn->dcl, cmpstackvar);
-
- // Unused autos are at the end, chop 'em off.
- ll = curfn->dcl;
- n = ll->n;
- if (n->class == PAUTO && n->op == ONAME && !n->used) {
- curfn->dcl = nil;
- stksize = 0;
- return;
- }
-
- for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
- n = ll->next->n;
- if (n->class == PAUTO && n->op == ONAME && !n->used) {
- ll->next = nil;
- curfn->dcl->end = ll;
- break;
- }
- }
-
- // Reassign stack offsets of the locals that are still there.
- stksize = 0;
- for(ll = curfn->dcl; ll != nil; ll=ll->next) {
- n = ll->n;
- if (n->class != PAUTO || n->op != ONAME)
- continue;
-
- w = n->type->width;
- if((w >= MAXWIDTH) || (w < 1))
- fatal("bad width");
- stksize += w;
- stksize = rnd(stksize, n->type->align);
- if(thechar == '5')
- stksize = rnd(stksize, widthptr);
- n->stkdelta = -stksize - n->xoffset;
- }
-
- fixautoused(ptxt);
-
- // The debug information needs accurate offsets on the symbols.
- for(ll = curfn->dcl ;ll != nil; ll=ll->next) {
- if (ll->n->class != PAUTO || ll->n->op != ONAME)
- continue;
- ll->n->xoffset += ll->n->stkdelta;
- ll->n->stkdelta = 0;
- }
-}
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
deleted file mode 100644
index e88e0f844..000000000
--- a/src/cmd/gc/print.c
+++ /dev/null
@@ -1,454 +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 "go.h"
-
-enum
-{
- PFIXME = 0,
-};
-
-void
-exprlistfmt(Fmt *f, NodeList *l)
-{
- for(; l; l=l->next) {
- exprfmt(f, l->n, 0);
- if(l->next)
- fmtprint(f, ", ");
- }
-}
-
-void
-exprfmt(Fmt *f, Node *n, int prec)
-{
- int nprec;
- char *p;
-
- nprec = 0;
- if(n == nil) {
- fmtprint(f, "<nil>");
- return;
- }
-
- if(n->implicit) {
- exprfmt(f, n->left, prec);
- return;
- }
-
- switch(n->op) {
- case OAPPEND:
- case ONAME:
- case ONONAME:
- case OPACK:
- case OLITERAL:
- case ODOT:
- case ODOTPTR:
- case ODOTINTER:
- case ODOTMETH:
- case ODOTTYPE:
- case ODOTTYPE2:
- case OXDOT:
- case OARRAYBYTESTR:
- case OCAP:
- case OCLOSE:
- case OCOPY:
- case OLEN:
- case OMAKE:
- case ONEW:
- case OPANIC:
- case OPRINT:
- case OPRINTN:
- case OCALL:
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- case OCONV:
- case OCONVNOP:
- case OMAKESLICE:
- case ORUNESTR:
- case OADDR:
- case OCOM:
- case OIND:
- case OMINUS:
- case ONOT:
- case OPLUS:
- case ORECV:
- case OCONVIFACE:
- case OTPAREN:
- case OINDEX:
- case OINDEXMAP:
- nprec = 7;
- break;
-
- case OMUL:
- case ODIV:
- case OMOD:
- case OLSH:
- case ORSH:
- case OAND:
- case OANDNOT:
- nprec = 6;
- break;
-
- case OADD:
- case OSUB:
- case OOR:
- case OXOR:
- nprec = 5;
- break;
-
- case OEQ:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case ONE:
- nprec = 4;
- break;
-
- case OSEND:
- nprec = 3;
- break;
-
- case OANDAND:
- nprec = 2;
- break;
-
- case OOROR:
- nprec = 1;
- break;
-
- case OTYPE:
- if(n->sym != S)
- nprec = 7;
- break;
- }
-
- if(prec > nprec)
- fmtprint(f, "(");
-
- switch(n->op) {
- default:
- bad:
- fmtprint(f, "(node %O)", n->op);
- break;
-
- case OREGISTER:
- fmtprint(f, "%R", n->val.u.reg);
- break;
-
- case OLITERAL:
- if(n->sym != S) {
- fmtprint(f, "%S", n->sym);
- break;
- }
- switch(n->val.ctype) {
- default:
- goto bad;
- case CTINT:
- fmtprint(f, "%B", n->val.u.xval);
- break;
- case CTBOOL:
- if(n->val.u.bval)
- fmtprint(f, "true");
- else
- fmtprint(f, "false");
- break;
- case CTCPLX:
- fmtprint(f, "%.17g+%.17gi",
- mpgetflt(&n->val.u.cval->real),
- mpgetflt(&n->val.u.cval->imag));
- break;
- case CTFLT:
- fmtprint(f, "%.17g", mpgetflt(n->val.u.fval));
- break;
- case CTSTR:
- fmtprint(f, "\"%Z\"", n->val.u.sval);
- break;
- case CTNIL:
- fmtprint(f, "nil");
- break;
- }
- break;
-
- case ONAME:
- case OPACK:
- case ONONAME:
- fmtprint(f, "%S", n->sym);
- break;
-
- case OTYPE:
- if(n->type == T && n->sym != S) {
- fmtprint(f, "%S", n->sym);
- break;
- }
- fmtprint(f, "%T", n->type);
- break;
-
- case OTARRAY:
- fmtprint(f, "[]");
- exprfmt(f, n->left, PFIXME);
- break;
-
- case OTPAREN:
- fmtprint(f, "(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OTMAP:
- fmtprint(f, "map[");
- exprfmt(f, n->left, 0);
- fmtprint(f, "] ");
- exprfmt(f, n->right, 0);
- break;
-
- case OTCHAN:
- if(n->etype == Crecv)
- fmtprint(f, "<-");
- fmtprint(f, "chan");
- if(n->etype == Csend) {
- fmtprint(f, "<- ");
- exprfmt(f, n->left, 0);
- } else {
- fmtprint(f, " ");
- if(n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) {
- fmtprint(f, "(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- } else
- exprfmt(f, n->left, 0);
- }
- break;
-
- case OTSTRUCT:
- fmtprint(f, "<struct>");
- break;
-
- case OTINTER:
- fmtprint(f, "<inter>");
- break;
-
- case OTFUNC:
- fmtprint(f, "<func>");
- break;
-
- case OAS:
- exprfmt(f, n->left, 0);
- fmtprint(f, " = ");
- exprfmt(f, n->right, 0);
- break;
-
- case OASOP:
- exprfmt(f, n->left, 0);
- fmtprint(f, " %#O= ", n->etype);
- exprfmt(f, n->right, 0);
- break;
-
- case OAS2:
- case OAS2DOTTYPE:
- case OAS2FUNC:
- case OAS2MAPR:
- case OAS2MAPW:
- case OAS2RECV:
- exprlistfmt(f, n->list);
- fmtprint(f, " = ");
- exprlistfmt(f, n->rlist);
- break;
-
- case OADD:
- case OANDAND:
- case OANDNOT:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLT:
- case OLSH:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case OOROR:
- case ORSH:
- case OSEND:
- case OSUB:
- case OXOR:
- exprfmt(f, n->left, nprec);
- fmtprint(f, " %#O ", n->op);
- exprfmt(f, n->right, nprec+1);
- break;
-
- case OADDR:
- case OCOM:
- case OIND:
- case OMINUS:
- case ONOT:
- case OPLUS:
- case ORECV:
- fmtprint(f, "%#O", n->op);
- if((n->op == OMINUS || n->op == OPLUS) && n->left->op == n->op)
- fmtprint(f, " ");
- exprfmt(f, n->left, 0);
- break;
-
- case OCLOSURE:
- fmtprint(f, "func literal");
- break;
-
- case OCOMPLIT:
- fmtprint(f, "composite literal");
- break;
-
- case OARRAYLIT:
- if(isslice(n->type))
- fmtprint(f, "slice literal");
- else
- fmtprint(f, "array literal");
- break;
-
- case OMAPLIT:
- fmtprint(f, "map literal");
- break;
-
- case OSTRUCTLIT:
- fmtprint(f, "struct literal");
- break;
-
- case OXDOT:
- case ODOT:
- case ODOTPTR:
- case ODOTINTER:
- case ODOTMETH:
- exprfmt(f, n->left, 7);
- if(n->right == N || n->right->sym == S)
- fmtprint(f, ".<nil>");
- else {
- // skip leading type· in method name
- p = utfrrune(n->right->sym->name, 0xb7);
- if(p)
- p+=2;
- else
- p = n->right->sym->name;
- fmtprint(f, ".%s", p);
- }
- break;
-
- case ODOTTYPE:
- case ODOTTYPE2:
- exprfmt(f, n->left, 7);
- fmtprint(f, ".(");
- if(n->right != N)
- exprfmt(f, n->right, 0);
- else
- fmtprint(f, "%T", n->type);
- fmtprint(f, ")");
- break;
-
- case OINDEX:
- case OINDEXMAP:
- exprfmt(f, n->left, 7);
- fmtprint(f, "[");
- exprfmt(f, n->right, 0);
- fmtprint(f, "]");
- break;
-
- case OSLICE:
- case OSLICESTR:
- case OSLICEARR:
- exprfmt(f, n->left, 7);
- fmtprint(f, "[");
- if(n->right->left != N)
- exprfmt(f, n->right->left, 0);
- fmtprint(f, ":");
- if(n->right->right != N)
- exprfmt(f, n->right->right, 0);
- fmtprint(f, "]");
- break;
-
- case OCALL:
- case OCALLFUNC:
- case OCALLINTER:
- case OCALLMETH:
- exprfmt(f, n->left, 7);
- fmtprint(f, "(");
- exprlistfmt(f, n->list);
- if(n->isddd)
- fmtprint(f, "...");
- fmtprint(f, ")");
- break;
-
- case OCOMPLEX:
- fmtprint(f, "complex(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ", ");
- exprfmt(f, n->right, 0);
- fmtprint(f, ")");
- break;
-
- case OREAL:
- fmtprint(f, "real(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OIMAG:
- fmtprint(f, "imag(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OCONV:
- case OCONVIFACE:
- case OCONVNOP:
- case OARRAYBYTESTR:
- case ORUNESTR:
- if(n->type == T || n->type->sym == S)
- fmtprint(f, "(%T)(", n->type);
- else
- fmtprint(f, "%T(", n->type);
- if(n->left == N)
- exprlistfmt(f, n->list);
- else
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OAPPEND:
- case OCAP:
- case OCLOSE:
- case OLEN:
- case OCOPY:
- case OMAKE:
- case ONEW:
- case OPANIC:
- case OPRINT:
- case OPRINTN:
- fmtprint(f, "%#O(", n->op);
- if(n->left)
- exprfmt(f, n->left, 0);
- else
- exprlistfmt(f, n->list);
- fmtprint(f, ")");
- break;
-
- case OMAKESLICE:
- fmtprint(f, "make(%#T, ", n->type);
- exprfmt(f, n->left, 0);
- if(count(n->list) > 2) {
- fmtprint(f, ", ");
- exprfmt(f, n->right, 0);
- }
- fmtprint(f, ")");
- break;
-
- case OMAKEMAP:
- fmtprint(f, "make(%#T)", n->type);
- break;
- }
-
- if(prec > nprec)
- fmtprint(f, ")");
-}
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
deleted file mode 100644
index dfb2b8efd..000000000
--- a/src/cmd/gc/range.c
+++ /dev/null
@@ -1,252 +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.
-
-/*
- * range
- */
-
-#include "go.h"
-
-void
-typecheckrange(Node *n)
-{
- char *why;
- Type *t, *t1, *t2;
- Node *v1, *v2;
- NodeList *ll;
-
- // delicate little dance. see typecheckas2
- for(ll=n->list; ll; ll=ll->next)
- if(ll->n->defn != n)
- typecheck(&ll->n, Erv | Easgn);
-
- typecheck(&n->right, Erv);
- if((t = n->right->type) == T)
- goto out;
- if(isptr[t->etype] && isfixedarray(t->type))
- t = t->type;
- n->type = t;
-
- switch(t->etype) {
- default:
- yyerror("cannot range over %+N", n->right);
- goto out;
-
- case TARRAY:
- t1 = types[TINT];
- t2 = t->type;
- break;
-
- case TMAP:
- t1 = t->down;
- t2 = t->type;
- break;
-
- case TCHAN:
- t1 = t->type;
- t2 = nil;
- if(count(n->list) == 2)
- goto toomany;
- break;
-
- case TSTRING:
- t1 = types[TINT];
- t2 = types[TINT];
- break;
- }
-
- if(count(n->list) > 2) {
- toomany:
- yyerror("too many variables in range");
- }
-
- v1 = n->list->n;
- v2 = N;
- if(n->list->next)
- v2 = n->list->next->n;
-
- if(v1->defn == n)
- v1->type = t1;
- else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
- yyerror("cannot assign type %T to %+N in range%s", t1, v1, why);
- if(v2) {
- if(v2->defn == n)
- v2->type = t2;
- else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
- yyerror("cannot assign type %T to %+N in range%s", t2, v2, why);
- }
-
-out:
- typechecklist(n->nbody, Etop);
-
- // second half of dance
- n->typecheck = 1;
- for(ll=n->list; ll; ll=ll->next)
- if(ll->n->typecheck == 0)
- typecheck(&ll->n, Erv | Easgn);
-}
-
-void
-walkrange(Node *n)
-{
- Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2
- Node *ha, *hit; // hidden aggregate, iterator
- Node *hn, *hp; // hidden len, pointer
- Node *hb; // hidden bool
- Node *a, *v1, *v2; // not hidden aggregate, val 1, 2
- Node *fn, *tmp;
- NodeList *body, *init;
- Type *th, *t;
-
- t = n->type;
- init = nil;
-
- a = n->right;
- if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) {
- a = nod(OCONV, n->right, N);
- a->type = types[TSTRING];
- }
-
- v1 = n->list->n;
- hv1 = N;
-
- v2 = N;
- if(n->list->next)
- v2 = n->list->next->n;
- hv2 = N;
-
- if(v2 == N && t->etype == TARRAY) {
- // will have just one reference to argument.
- // no need to make a potentially expensive copy.
- ha = a;
- } else {
- ha = nod(OXXX, N, N);
- tempname(ha, a->type);
- init = list(init, nod(OAS, ha, a));
- }
-
- switch(t->etype) {
- default:
- fatal("walkrange");
-
- case TARRAY:
- hv1 = nod(OXXX, N, n);
- tempname(hv1, types[TINT]);
- hn = nod(OXXX, N, N);
- tempname(hn, types[TINT]);
- hp = nil;
-
- init = list(init, nod(OAS, hv1, N));
- init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
- if(v2) {
- hp = nod(OXXX, N, N);
- tempname(hp, ptrto(n->type->type));
- tmp = nod(OINDEX, ha, nodintconst(0));
- tmp->etype = 1; // no bounds check
- init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
- }
-
- n->ntest = nod(OLT, hv1, hn);
- n->nincr = nod(OASOP, hv1, nodintconst(1));
- n->nincr->etype = OADD;
- body = list1(nod(OAS, v1, hv1));
- if(v2) {
- body = list(body, nod(OAS, v2, nod(OIND, hp, N)));
- tmp = nod(OADD, hp, nodintconst(t->type->width));
- tmp->type = hp->type;
- tmp->typecheck = 1;
- tmp->right->type = types[tptr];
- tmp->right->typecheck = 1;
- body = list(body, nod(OAS, hp, tmp));
- }
- break;
-
- case TMAP:
- th = typ(TARRAY);
- th->type = ptrto(types[TUINT8]);
- th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr;
- hit = nod(OXXX, N, N);
- tempname(hit, th);
-
- fn = syslook("mapiterinit", 1);
- argtype(fn, t->down);
- argtype(fn, t->type);
- argtype(fn, th);
- init = list(init, mkcall1(fn, T, nil, ha, nod(OADDR, hit, N)));
- n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil());
-
- fn = syslook("mapiternext", 1);
- argtype(fn, th);
- n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));
-
- if(v2 == N) {
- fn = syslook("mapiter1", 1);
- argtype(fn, th);
- argtype(fn, t->down);
- a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N)));
- } else {
- fn = syslook("mapiter2", 1);
- argtype(fn, th);
- argtype(fn, t->down);
- argtype(fn, t->type);
- a = nod(OAS2, N, N);
- a->list = list(list1(v1), v2);
- a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N)));
- }
- body = list1(a);
- break;
-
- case TCHAN:
- hv1 = nod(OXXX, N, n);
- tempname(hv1, t->type);
- hb = nod(OXXX, N, N);
- tempname(hb, types[TBOOL]);
-
- n->ntest = nod(ONE, hb, nodbool(0));
- a = nod(OAS2RECV, N, N);
- a->typecheck = 1;
- a->list = list(list1(hv1), hb);
- a->rlist = list1(nod(ORECV, ha, N));
- n->ntest->ninit = list1(a);
- body = list1(nod(OAS, v1, hv1));
- break;
-
- case TSTRING:
- ohv1 = nod(OXXX, N, N);
- tempname(ohv1, types[TINT]);
-
- hv1 = nod(OXXX, N, N);
- tempname(hv1, types[TINT]);
- init = list(init, nod(OAS, hv1, N));
-
- if(v2 == N)
- a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
- else {
- hv2 = nod(OXXX, N, N);
- tempname(hv2, types[TINT]);
- a = nod(OAS2, N, N);
- a->list = list(list1(hv1), hv2);
- fn = syslook("stringiter2", 0);
- a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1));
- }
- n->ntest = nod(ONE, hv1, nodintconst(0));
- n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
-
- body = list1(nod(OAS, v1, ohv1));
- if(v2 != N)
- body = list(body, nod(OAS, v2, hv2));
- break;
- }
-
- n->op = OFOR;
- typechecklist(init, Etop);
- n->ninit = concat(n->ninit, init);
- typechecklist(n->ntest->ninit, Etop);
- typecheck(&n->ntest, Erv);
- typecheck(&n->nincr, Etop);
- typechecklist(body, Etop);
- n->nbody = concat(body, n->nbody);
- walkstmt(&n);
-}
-
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
deleted file mode 100644
index 810787d30..000000000
--- a/src/cmd/gc/reflect.c
+++ /dev/null
@@ -1,939 +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 "go.h"
-
-/*
- * runtime interface and reflection data structures
- */
-
-static NodeList* signatlist;
-static Sym* dtypesym(Type*);
-static Sym* weaktypesym(Type*);
-
-static int
-sigcmp(Sig *a, Sig *b)
-{
- int i;
-
- i = strcmp(a->name, b->name);
- if(i != 0)
- return i;
- if(a->pkg == b->pkg)
- return 0;
- if(a->pkg == nil)
- return -1;
- if(b->pkg == nil)
- return +1;
- return strcmp(a->pkg->path->s, b->pkg->path->s);
-}
-
-static Sig*
-lsort(Sig *l, int(*f)(Sig*, Sig*))
-{
- Sig *l1, *l2, *le;
-
- if(l == 0 || l->link == 0)
- return l;
-
- l1 = l;
- l2 = l;
- for(;;) {
- l2 = l2->link;
- if(l2 == 0)
- break;
- l2 = l2->link;
- if(l2 == 0)
- break;
- l1 = l1->link;
- }
-
- l2 = l1->link;
- l1->link = 0;
- l1 = lsort(l, f);
- l2 = lsort(l2, f);
-
- /* set up lead element */
- if((*f)(l1, l2) < 0) {
- l = l1;
- l1 = l1->link;
- } else {
- l = l2;
- l2 = l2->link;
- }
- le = l;
-
- for(;;) {
- if(l1 == 0) {
- while(l2) {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- le->link = 0;
- break;
- }
- if(l2 == 0) {
- while(l1) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- }
- break;
- }
- if((*f)(l1, l2) < 0) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- } else {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- }
- le->link = 0;
- return l;
-}
-
-/*
- * f is method type, with receiver.
- * return function type, receiver as first argument (or not).
- */
-Type*
-methodfunc(Type *f, Type *receiver)
-{
- NodeList *in, *out;
- Node *d;
- Type *t;
-
- in = nil;
- if(receiver) {
- d = nod(ODCLFIELD, N, N);
- d->type = receiver;
- in = list(in, d);
- }
- for(t=getinargx(f)->type; t; t=t->down) {
- d = nod(ODCLFIELD, N, N);
- d->type = t->type;
- d->isddd = t->isddd;
- in = list(in, d);
- }
-
- out = nil;
- for(t=getoutargx(f)->type; t; t=t->down) {
- d = nod(ODCLFIELD, N, N);
- d->type = t->type;
- out = list(out, d);
- }
-
- return functype(N, in, out);
-}
-
-/*
- * return methods of non-interface type t, sorted by name.
- * generates stub functions as needed.
- */
-static Sig*
-methods(Type *t)
-{
- Type *f, *mt, *it, *this;
- Sig *a, *b;
- Sym *method;
- Prog *oldlist;
-
- // named method type
- mt = methtype(t);
- if(mt == T)
- return nil;
- expandmeth(mt->sym, mt);
-
- // type stored in interface word
- it = t;
- if(it->width > widthptr)
- it = ptrto(t);
-
- // make list of methods for t,
- // generating code if necessary.
- a = nil;
- oldlist = nil;
- for(f=mt->xmethod; f; f=f->down) {
- if(f->type->etype != TFUNC)
- continue;
- if(f->etype != TFIELD)
- fatal("methods: not field");
- method = f->sym;
- if(method == nil)
- continue;
-
- // get receiver type for this particular method.
- // if pointer receiver but non-pointer t and
- // this is not an embedded pointer inside a struct,
- // method does not apply.
- this = getthisx(f->type)->type->type;
- if(isptr[this->etype] && this->type == t)
- continue;
- if(isptr[this->etype] && !isptr[t->etype]
- && f->embedded != 2 && !isifacemethod(f->type))
- continue;
-
- b = mal(sizeof(*b));
- b->link = a;
- a = b;
-
- a->name = method->name;
- if(!exportname(method->name)) {
- if(method->pkg == nil)
- fatal("methods: missing package");
- a->pkg = method->pkg;
- }
- a->isym = methodsym(method, it, 1);
- a->tsym = methodsym(method, t, 0);
- a->type = methodfunc(f->type, t);
- a->mtype = methodfunc(f->type, nil);
-
- if(!(a->isym->flags & SymSiggen)) {
- a->isym->flags |= SymSiggen;
- if(!eqtype(this, it) || this->width < types[tptr]->width) {
- if(oldlist == nil)
- oldlist = pc;
- // Is okay to call genwrapper here always,
- // but we can generate more efficient code
- // using genembedtramp if all that is necessary
- // is a pointer adjustment and a JMP.
- if(isptr[it->etype] && isptr[this->etype]
- && f->embedded && !isifacemethod(f->type))
- genembedtramp(it, f, a->isym, 1);
- else
- genwrapper(it, f, a->isym, 1);
- }
- }
-
- if(!(a->tsym->flags & SymSiggen)) {
- a->tsym->flags |= SymSiggen;
- if(!eqtype(this, t)) {
- if(oldlist == nil)
- oldlist = pc;
- if(isptr[t->etype] && isptr[this->etype]
- && f->embedded && !isifacemethod(f->type))
- genembedtramp(t, f, a->tsym, 0);
- else
- genwrapper(t, f, a->tsym, 0);
- }
- }
- }
-
- // restore data output
- if(oldlist) {
- // old list ended with AEND; change to ANOP
- // so that the trampolines that follow can be found.
- nopout(oldlist);
-
- // start new data list
- newplist();
- }
-
- return lsort(a, sigcmp);
-}
-
-/*
- * return methods of interface type t, sorted by name.
- */
-static Sig*
-imethods(Type *t)
-{
- Sig *a, *all, *last;
- Type *f;
- Sym *method, *isym;
- Prog *oldlist;
-
- all = nil;
- last = nil;
- oldlist = nil;
- for(f=t->type; f; f=f->down) {
- if(f->etype != TFIELD)
- fatal("imethods: not field");
- if(f->type->etype != TFUNC || f->sym == nil)
- continue;
- method = f->sym;
- a = mal(sizeof(*a));
- a->name = method->name;
- if(!exportname(method->name)) {
- if(method->pkg == nil)
- fatal("imethods: missing package");
- a->pkg = method->pkg;
- }
- a->mtype = f->type;
- a->offset = 0;
- a->type = methodfunc(f->type, nil);
-
- if(last && sigcmp(last, a) >= 0)
- fatal("sigcmp vs sortinter %s %s", last->name, a->name);
- if(last == nil)
- all = a;
- else
- last->link = a;
- last = a;
-
- // Compiler can only refer to wrappers for
- // named interface types.
- if(t->sym == S)
- continue;
-
- // NOTE(rsc): Perhaps an oversight that
- // IfaceType.Method is not in the reflect data.
- // Generate the method body, so that compiled
- // code can refer to it.
- isym = methodsym(method, t, 0);
- if(!(isym->flags & SymSiggen)) {
- isym->flags |= SymSiggen;
- if(oldlist == nil)
- oldlist = pc;
- genwrapper(t, f, isym, 0);
- }
- }
-
- if(oldlist) {
- // old list ended with AEND; change to ANOP
- // so that the trampolines that follow can be found.
- nopout(oldlist);
-
- // start new data list
- newplist();
- }
-
- return all;
-}
-
-static void
-dimportpath(Pkg *p)
-{
- static Pkg *gopkg;
- char *nam;
- Node *n;
-
- if(p->pathsym != S)
- return;
-
- if(gopkg == nil) {
- gopkg = mkpkg(strlit("go"));
- gopkg->name = "go";
- }
- nam = smprint("importpath.%s.", p->prefix);
-
- n = nod(ONAME, N, N);
- n->sym = pkglookup(nam, gopkg);
- free(nam);
- n->class = PEXTERN;
- n->xoffset = 0;
- p->pathsym = n->sym;
-
- gdatastring(n, p->path);
- ggloblsym(n->sym, types[TSTRING]->width, 1);
-}
-
-static int
-dgopkgpath(Sym *s, int ot, Pkg *pkg)
-{
- if(pkg == nil)
- return dgostringptr(s, ot, nil);
-
- // Emit reference to go.importpath.""., which 6l will
- // rewrite using the correct import path. Every package
- // that imports this one directly defines the symbol.
- if(pkg == localpkg) {
- static Sym *ns;
-
- if(ns == nil)
- ns = pkglookup("importpath.\"\".", mkpkg(strlit("go")));
- return dsymptr(s, ot, ns, 0);
- }
-
- dimportpath(pkg);
- return dsymptr(s, ot, pkg->pathsym, 0);
-}
-
-/*
- * uncommonType
- * ../../pkg/runtime/type.go:/uncommonType
- */
-static int
-dextratype(Sym *sym, int off, Type *t, int ptroff)
-{
- int ot, n;
- Sym *s;
- Sig *a, *m;
-
- m = methods(t);
- if(t->sym == nil && m == nil)
- return off;
-
- // fill in *extraType pointer in header
- dsymptr(sym, ptroff, sym, off);
-
- n = 0;
- for(a=m; a; a=a->link) {
- dtypesym(a->type);
- n++;
- }
-
- ot = off;
- s = sym;
- if(t->sym) {
- ot = dgostringptr(s, ot, t->sym->name);
- if(t != types[t->etype])
- ot = dgopkgpath(s, ot, t->sym->pkg);
- else
- ot = dgostringptr(s, ot, nil);
- } else {
- ot = dgostringptr(s, ot, nil);
- ot = dgostringptr(s, ot, nil);
- }
-
- // slice header
- ot = dsymptr(s, ot, s, ot + widthptr + 2*4);
- ot = duint32(s, ot, n);
- ot = duint32(s, ot, n);
-
- // methods
- for(a=m; a; a=a->link) {
- // method
- // ../../pkg/runtime/type.go:/method
- ot = dgostringptr(s, ot, a->name);
- ot = dgopkgpath(s, ot, a->pkg);
- ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
- ot = dsymptr(s, ot, dtypesym(a->type), 0);
- if(a->isym)
- ot = dsymptr(s, ot, a->isym, 0);
- else
- ot = duintptr(s, ot, 0);
- if(a->tsym)
- ot = dsymptr(s, ot, a->tsym, 0);
- else
- ot = duintptr(s, ot, 0);
- }
-
- return ot;
-}
-
-enum {
- KindBool = 1,
- 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,
-
- KindNoPointers = 1<<7,
-};
-
-static int
-kinds[] =
-{
- [TINT] = KindInt,
- [TUINT] = KindUint,
- [TINT8] = KindInt8,
- [TUINT8] = KindUint8,
- [TINT16] = KindInt16,
- [TUINT16] = KindUint16,
- [TINT32] = KindInt32,
- [TUINT32] = KindUint32,
- [TINT64] = KindInt64,
- [TUINT64] = KindUint64,
- [TUINTPTR] = KindUintptr,
- [TFLOAT32] = KindFloat32,
- [TFLOAT64] = KindFloat64,
- [TBOOL] = KindBool,
- [TSTRING] = KindString,
- [TPTR32] = KindPtr,
- [TPTR64] = KindPtr,
- [TSTRUCT] = KindStruct,
- [TINTER] = KindInterface,
- [TCHAN] = KindChan,
- [TMAP] = KindMap,
- [TARRAY] = KindArray,
- [TFUNC] = KindFunc,
- [TCOMPLEX64] = KindComplex64,
- [TCOMPLEX128] = KindComplex128,
- [TUNSAFEPTR] = KindUnsafePointer,
-};
-
-static char*
-structnames[] =
-{
- [TINT] = "*runtime.IntType",
- [TUINT] = "*runtime.UintType",
- [TINT8] = "*runtime.IntType",
- [TUINT8] = "*runtime.UintType",
- [TINT16] = "*runtime.IntType",
- [TUINT16] = "*runtime.UintType",
- [TINT32] = "*runtime.IntType",
- [TUINT32] = "*runtime.UintType",
- [TINT64] = "*runtime.IntType",
- [TUINT64] = "*runtime.UintType",
- [TUINTPTR] = "*runtime.UintType",
- [TCOMPLEX64] = "*runtime.ComplexType",
- [TCOMPLEX128] = "*runtime.ComplexType",
- [TFLOAT32] = "*runtime.FloatType",
- [TFLOAT64] = "*runtime.FloatType",
- [TBOOL] = "*runtime.BoolType",
- [TSTRING] = "*runtime.StringType",
- [TUNSAFEPTR] = "*runtime.UnsafePointerType",
-
- [TPTR32] = "*runtime.PtrType",
- [TPTR64] = "*runtime.PtrType",
- [TSTRUCT] = "*runtime.StructType",
- [TINTER] = "*runtime.InterfaceType",
- [TCHAN] = "*runtime.ChanType",
- [TMAP] = "*runtime.MapType",
- [TARRAY] = "*runtime.ArrayType",
- [TFUNC] = "*runtime.FuncType",
-};
-
-static Sym*
-typestruct(Type *t)
-{
- char *name;
- int et;
-
- et = t->etype;
- if(et < 0 || et >= nelem(structnames) || (name = structnames[et]) == nil) {
- fatal("typestruct %lT", t);
- return nil; // silence gcc
- }
-
- if(isslice(t))
- name = "*runtime.SliceType";
-
- return pkglookup(name, typepkg);
-}
-
-static int
-haspointers(Type *t)
-{
- Type *t1;
-
- switch(t->etype) {
- case TINT:
- case TUINT:
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TUINTPTR:
- case TFLOAT32:
- case TFLOAT64:
- case TBOOL:
- return 0;
- case TARRAY:
- if(t->bound < 0) // slice
- return 1;
- return haspointers(t->type);
- case TSTRUCT:
- for(t1=t->type; t1!=T; t1=t1->down)
- if(haspointers(t1->type))
- return 1;
- return 0;
- case TSTRING:
- case TPTR32:
- case TPTR64:
- case TUNSAFEPTR:
- case TINTER:
- case TCHAN:
- case TMAP:
- case TFUNC:
- default:
- return 1;
- }
-}
-
-/*
- * commonType
- * ../../pkg/runtime/type.go:/commonType
- */
-static int
-dcommontype(Sym *s, int ot, Type *t)
-{
- int i;
- Sym *sptr;
- char *p;
-
- dowidth(t);
-
- sptr = nil;
- if(t->sym != nil && !isptr[t->etype])
- sptr = dtypesym(ptrto(t));
- else
- sptr = weaktypesym(ptrto(t));
-
- // empty interface pointing at this type.
- // all the references that we emit are *interface{};
- // they point here.
- ot = rnd(ot, widthptr);
- ot = dsymptr(s, ot, typestruct(t), 0);
- ot = dsymptr(s, ot, s, 2*widthptr);
-
- // ../../pkg/runtime/type.go:/commonType
- // actual type structure
- // type commonType struct {
- // size uintptr;
- // hash uint32;
- // alg uint8;
- // align uint8;
- // fieldAlign uint8;
- // kind uint8;
- // string *string;
- // *extraType;
- // ptrToThis *Type
- // }
- ot = duintptr(s, ot, t->width);
- ot = duint32(s, ot, typehash(t));
- ot = duint8(s, ot, algtype(t));
- ot = duint8(s, ot, t->align); // align
- ot = duint8(s, ot, t->align); // fieldAlign
- i = kinds[t->etype];
- if(t->etype == TARRAY && t->bound < 0)
- i = KindSlice;
- if(!haspointers(t))
- i |= KindNoPointers;
- ot = duint8(s, ot, i); // kind
- longsymnames = 1;
- p = smprint("%-T", t);
- longsymnames = 0;
- ot = dgostringptr(s, ot, p); // string
- free(p);
-
- // skip pointer to extraType,
- // which follows the rest of this type structure.
- // caller will fill in if needed.
- // otherwise linker will assume 0.
- ot += widthptr;
-
- ot = dsymptr(s, ot, sptr, 0); // ptrto type
- return ot;
-}
-
-Sym*
-typesym(Type *t)
-{
- char *p;
- Sym *s;
-
- p = smprint("%#-T", t);
- s = pkglookup(p, typepkg);
- free(p);
- return s;
-}
-
-Node*
-typename(Type *t)
-{
- Sym *s;
- Node *n;
-
- if(t == T || (isptr[t->etype] && t->type == T) || isideal(t))
- fatal("typename %T", t);
- s = typesym(t);
- if(s->def == N) {
- n = nod(ONAME, N, N);
- n->sym = s;
- n->type = types[TUINT8];
- n->addable = 1;
- n->ullman = 1;
- n->class = PEXTERN;
- n->xoffset = 0;
- s->def = n;
-
- signatlist = list(signatlist, typenod(t));
- }
-
- n = nod(OADDR, s->def, N);
- n->type = ptrto(s->def->type);
- n->addable = 1;
- n->ullman = 2;
- return n;
-}
-
-static Sym*
-weaktypesym(Type *t)
-{
- char *p;
- Sym *s;
- static Pkg *weak;
-
- if(weak == nil) {
- weak = mkpkg(strlit("weak.type"));
- weak->name = "weak.type";
- weak->prefix = "weak.type"; // not weak%2etype
- }
-
- p = smprint("%#-T", t);
- s = pkglookup(p, weak);
- free(p);
- return s;
-}
-
-static Sym*
-dtypesym(Type *t)
-{
- int ot, xt, n, isddd, dupok;
- Sym *s, *s1, *s2;
- Sig *a, *m;
- Type *t1, *tbase, *t2;
-
- if(isideal(t))
- fatal("dtypesym %T", t);
-
- s = typesym(t);
- if(s->flags & SymSiggen)
- return s;
- s->flags |= SymSiggen;
-
- // special case (look for runtime below):
- // when compiling package runtime,
- // emit the type structures for int, float, etc.
- tbase = t;
- if(isptr[t->etype] && t->sym == S && t->type->sym != S)
- tbase = t->type;
- dupok = tbase->sym == S;
-
- if(compiling_runtime && tbase == types[tbase->etype]) // int, float, etc
- goto ok;
-
- // named types from other files are defined only by those files
- if(tbase->sym && !tbase->local)
- return s;
- if(isforw[tbase->etype])
- return s;
-
-ok:
- ot = 0;
- xt = 0;
- switch(t->etype) {
- default:
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- break;
-
- case TARRAY:
- if(t->bound >= 0) {
- // ../../pkg/runtime/type.go:/ArrayType
- s1 = dtypesym(t->type);
- t2 = typ(TARRAY);
- t2->type = t->type;
- t2->bound = -1; // slice
- s2 = dtypesym(t2);
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- ot = dsymptr(s, ot, s2, 0);
- ot = duintptr(s, ot, t->bound);
- } else {
- // ../../pkg/runtime/type.go:/SliceType
- s1 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- }
- break;
-
- case TCHAN:
- // ../../pkg/runtime/type.go:/ChanType
- s1 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- ot = duintptr(s, ot, t->chan);
- break;
-
- case TFUNC:
- for(t1=getthisx(t)->type; t1; t1=t1->down)
- dtypesym(t1->type);
- isddd = 0;
- for(t1=getinargx(t)->type; t1; t1=t1->down) {
- isddd = t1->isddd;
- dtypesym(t1->type);
- }
- for(t1=getoutargx(t)->type; t1; t1=t1->down)
- dtypesym(t1->type);
-
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = duint8(s, ot, isddd);
-
- // two slice headers: in and out.
- ot = rnd(ot, widthptr);
- ot = dsymptr(s, ot, s, ot+2*(widthptr+2*4));
- n = t->thistuple + t->intuple;
- ot = duint32(s, ot, n);
- ot = duint32(s, ot, n);
- ot = dsymptr(s, ot, s, ot+1*(widthptr+2*4)+n*widthptr);
- ot = duint32(s, ot, t->outtuple);
- ot = duint32(s, ot, t->outtuple);
-
- // slice data
- for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- break;
-
- case TINTER:
- m = imethods(t);
- n = 0;
- for(a=m; a; a=a->link) {
- dtypesym(a->type);
- n++;
- }
-
- // ../../pkg/runtime/type.go:/InterfaceType
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s, ot+widthptr+2*4);
- ot = duint32(s, ot, n);
- ot = duint32(s, ot, n);
- for(a=m; a; a=a->link) {
- // ../../pkg/runtime/type.go:/imethod
- ot = dgostringptr(s, ot, a->name);
- ot = dgopkgpath(s, ot, a->pkg);
- ot = dsymptr(s, ot, dtypesym(a->type), 0);
- }
- break;
-
- case TMAP:
- // ../../pkg/runtime/type.go:/MapType
- s1 = dtypesym(t->down);
- s2 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- ot = dsymptr(s, ot, s2, 0);
- break;
-
- case TPTR32:
- case TPTR64:
- if(t->type->etype == TANY) {
- // ../../pkg/runtime/type.go:/UnsafePointerType
- ot = dcommontype(s, ot, t);
- break;
- }
- // ../../pkg/runtime/type.go:/PtrType
- s1 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- break;
-
- case TSTRUCT:
- // ../../pkg/runtime/type.go:/StructType
- // for security, only the exported fields.
- n = 0;
- for(t1=t->type; t1!=T; t1=t1->down) {
- dtypesym(t1->type);
- n++;
- }
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s, ot+widthptr+2*4);
- ot = duint32(s, ot, n);
- ot = duint32(s, ot, n);
- for(t1=t->type; t1!=T; t1=t1->down) {
- // ../../pkg/runtime/type.go:/structField
- if(t1->sym && !t1->embedded) {
- ot = dgostringptr(s, ot, t1->sym->name);
- if(exportname(t1->sym->name))
- ot = dgostringptr(s, ot, nil);
- else
- ot = dgopkgpath(s, ot, t1->sym->pkg);
- } else {
- ot = dgostringptr(s, ot, nil);
- ot = dgostringptr(s, ot, nil);
- }
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- ot = dgostrlitptr(s, ot, t1->note);
- ot = duintptr(s, ot, t1->width); // field offset
- }
- break;
- }
- ot = dextratype(s, ot, t, xt);
- ggloblsym(s, ot, dupok);
- return s;
-}
-
-void
-dumptypestructs(void)
-{
- int i;
- NodeList *l;
- Node *n;
- Type *t;
- Pkg *p;
-
- // copy types from externdcl list to signatlist
- for(l=externdcl; l; l=l->next) {
- n = l->n;
- if(n->op != OTYPE)
- continue;
- signatlist = list(signatlist, n);
- }
-
- // process signatlist
- for(l=signatlist; l; l=l->next) {
- n = l->n;
- if(n->op != OTYPE)
- continue;
- t = n->type;
- dtypesym(t);
- if(t->sym)
- dtypesym(ptrto(t));
- }
-
- // generate import strings for imported packages
- for(i=0; i<nelem(phash); i++)
- for(p=phash[i]; p; p=p->link)
- if(p->direct)
- dimportpath(p);
-
- // do basic types if compiling package runtime.
- // they have to be in at least one package,
- // and runtime is always loaded implicitly,
- // so this is as good as any.
- // another possible choice would be package main,
- // but using runtime means fewer copies in .6 files.
- if(compiling_runtime) {
- for(i=1; i<=TBOOL; i++)
- dtypesym(ptrto(types[i]));
- dtypesym(ptrto(types[TSTRING]));
- dtypesym(ptrto(types[TUNSAFEPTR]));
-
- // add paths for runtime and main, which 6l imports implicitly.
- dimportpath(runtimepkg);
- dimportpath(mkpkg(strlit("main")));
- }
-}
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
deleted file mode 100644
index e13c95db9..000000000
--- a/src/cmd/gc/runtime.go
+++ /dev/null
@@ -1,131 +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.
-
-// NOTE: If you change this file you must run "./mkbuiltin"
-// to update builtin.c.boot. This is not done automatically
-// to avoid depending on having a working compiler binary.
-
-package PACKAGE
-
-// emitted by compiler, not referred to by go programs
-
-func new(int32) *any
-func panicindex()
-func panicslice()
-func throwreturn()
-func throwinit()
-func panicwrap(string, string, string)
-
-func panic(interface{})
-func recover(*int32) interface{}
-
-func printbool(bool)
-func printfloat(float64)
-func printint(int64)
-func printuint(uint64)
-func printcomplex(complex128)
-func printstring(string)
-func printpointer(any)
-func printiface(any)
-func printeface(any)
-func printslice(any)
-func printnl()
-func printsp()
-func goprintf()
-
-// filled in by compiler: int n, string, string, ...
-func concatstring()
-
-// filled in by compiler: Type*, int n, Slice, ...
-func append()
-func appendslice(typ *byte, x any, y []any) any
-
-func cmpstring(string, string) int
-func slicestring(string, int, int) string
-func slicestring1(string, int) string
-func intstring(int64) string
-func slicebytetostring([]byte) string
-func sliceinttostring([]int) string
-func stringtoslicebyte(string) []byte
-func stringtosliceint(string) []int
-func stringiter(string, int) int
-func stringiter2(string, int) (retk int, retv int)
-func slicecopy(to any, fr any, wid uint32) int
-func slicestringcopy(to any, fr any) int
-
-// interface conversions
-func convI2E(elem any) (ret any)
-func convI2I(typ *byte, elem any) (ret any)
-func convT2E(typ *byte, elem any) (ret any)
-func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
-
-// interface type assertions x.(T)
-func assertE2E(typ *byte, iface any) (ret any)
-func assertE2E2(typ *byte, iface any) (ret any, ok bool)
-func assertE2I(typ *byte, iface any) (ret any)
-func assertE2I2(typ *byte, iface any) (ret any, ok bool)
-func assertE2T(typ *byte, iface any) (ret any)
-func assertE2T2(typ *byte, iface any) (ret any, ok bool)
-func assertI2E(typ *byte, iface any) (ret any)
-func assertI2E2(typ *byte, iface any) (ret any, ok bool)
-func assertI2I(typ *byte, iface any) (ret any)
-func assertI2I2(typ *byte, iface any) (ret any, ok bool)
-func assertI2T(typ *byte, iface any) (ret any)
-func assertI2T2(typ *byte, iface any) (ret any, ok bool)
-
-func ifaceeq(i1 any, i2 any) (ret bool)
-func efaceeq(i1 any, i2 any) (ret bool)
-func ifacethash(i1 any) (ret uint32)
-func efacethash(i1 any) (ret uint32)
-
-// *byte is really *runtime.Type
-func makemap(key, val *byte, hint int64) (hmap map[any]any)
-func mapaccess1(hmap map[any]any, key any) (val any)
-func mapaccess2(hmap map[any]any, key any) (val any, pres bool)
-func mapassign1(hmap map[any]any, key any, val any)
-func mapassign2(hmap map[any]any, key any, val any, pres bool)
-func mapiterinit(hmap map[any]any, hiter *any)
-func mapiternext(hiter *any)
-func mapiter1(hiter *any) (key any)
-func mapiter2(hiter *any) (key any, val any)
-
-// *byte is really *runtime.Type
-func makechan(elem *byte, hint int64) (hchan chan any)
-func chanrecv1(hchan <-chan any) (elem any)
-func chanrecv2(hchan <-chan any) (elem any, received bool)
-func chansend1(hchan chan<- any, elem any)
-func closechan(hchan any)
-func closedchan(hchan any) bool
-
-func selectnbsend(hchan chan<- any, elem any) bool
-func selectnbrecv(elem *any, hchan <-chan any) bool
-func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool
-
-func newselect(size int) (sel *byte)
-func selectsend(sel *byte, hchan chan<- any, elem any) (selected bool)
-func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
-func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
-func selectdefault(sel *byte) (selected bool)
-func selectgo(sel *byte)
-func block()
-
-func makeslice(typ *byte, nel int64, cap int64) (ary []any)
-func growslice(typ *byte, old []any, n int64) (ary []any)
-func sliceslice1(old []any, lb uint64, width uint64) (ary []any)
-func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
-func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any)
-
-func closure() // has args, but compiler fills in
-
-// only used on 32-bit
-func int64div(int64, int64) int64
-func uint64div(uint64, uint64) uint64
-func int64mod(int64, int64) int64
-func uint64mod(uint64, uint64) uint64
-func float64toint64(float64) int64
-func float64touint64(float64) uint64
-func int64tofloat64(int64) float64
-func uint64tofloat64(uint64) float64
-
-func complex128div(num complex128, den complex128) (quo complex128)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
deleted file mode 100644
index 91d4ebfd5..000000000
--- a/src/cmd/gc/select.c
+++ /dev/null
@@ -1,343 +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.
-
-/*
- * select
- */
-
-#include "go.h"
-
-void
-typecheckselect(Node *sel)
-{
- Node *ncase, *n, *def;
- NodeList *l;
- int lno, count;
-
- def = nil;
- lno = setlineno(sel);
- count = 0;
- typechecklist(sel->ninit, Etop);
- for(l=sel->list; l; l=l->next) {
- count++;
- ncase = l->n;
- setlineno(ncase);
- if(ncase->op != OXCASE)
- fatal("typecheckselect %O", ncase->op);
-
- if(ncase->list == nil) {
- // default
- if(def != N)
- yyerror("multiple defaults in select (first at %L)", def->lineno);
- else
- def = ncase;
- } else if(ncase->list->next) {
- yyerror("select cases cannot be lists");
- } else {
- n = typecheck(&ncase->list->n, Etop);
- ncase->left = n;
- ncase->list = nil;
- setlineno(n);
- switch(n->op) {
- default:
- yyerror("select case must be receive, send or assign recv");
- break;
-
- case OAS:
- // convert x = <-c into OSELRECV(x, <-c).
- // remove implicit conversions; the eventual assignment
- // will reintroduce them.
- if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit)
- n->right = n->right->left;
-
- if(n->right->op != ORECV) {
- yyerror("select assignment must have receive on right hand side");
- break;
- }
- n->op = OSELRECV;
- break;
-
- case OAS2RECV:
- // convert x, ok = <-c into OSELRECV(x, <-c) with ntest=ok
- if(n->right->op != ORECV) {
- yyerror("select assignment must have receive on right hand side");
- break;
- }
- n->op = OSELRECV2;
- n->left = n->list->n;
- n->ntest = n->list->next->n;
- n->right = n->rlist->n;
- break;
-
- case ORECV:
- // convert <-c into OSELRECV(N, <-c)
- n = nod(OSELRECV, N, n);
- ncase->left = n;
- break;
-
- case OSEND:
- break;
- }
- }
- typechecklist(ncase->nbody, Etop);
- }
- sel->xoffset = count;
- lineno = lno;
-}
-
-void
-walkselect(Node *sel)
-{
- int lno, i;
- Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch;
- NodeList *l, *init;
-
- if(sel->list == nil && sel->xoffset != 0)
- fatal("double walkselect"); // already rewrote
-
- lno = setlineno(sel);
- i = count(sel->list);
-
- // optimization: zero-case select
- if(i == 0) {
- sel->nbody = list1(mkcall("block", nil, nil));
- goto out;
- }
-
- // optimization: one-case select: single op.
- if(i == 1) {
- cas = sel->list->n;
- l = cas->ninit;
- if(cas->left != N) { // not default:
- n = cas->left;
- l = concat(l, n->ninit);
- n->ninit = nil;
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- ch = cheapexpr(n->left, &l);
- n->left = ch;
- break;
-
- case OSELRECV:
- r = n->right;
- ch = cheapexpr(r->left, &l);
- r->left = ch;
-
- if(n->left == N)
- n = r;
- else {
- n = nod(OAS, n->left, r);
- typecheck(&n, Etop);
- }
- break;
-
- case OSELRECV2:
- r = n->right;
- ch = cheapexpr(r->left, &l);
- r->left = ch;
-
- a = nod(OAS2, N, N);
- a->list = n->list;
- a->rlist = n->rlist;
- n = a;
- typecheck(&n, Etop);
- break;
- }
-
- // if ch == nil { block() }; n;
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, ch, nodnil());
- a->nbody = list1(mkcall("block", nil, &l));
- typecheck(&a, Etop);
- l = list(l, a);
- l = list(l, n);
- }
- l = concat(l, cas->nbody);
- sel->nbody = l;
- goto out;
- }
-
- // introduce temporary variables for OSELRECV where needed.
- // this rewrite is used by both the general code and the next optimization.
- for(l=sel->list; l; l=l->next) {
- cas = l->n;
- n = cas->left;
- if(n == N)
- continue;
- switch(n->op) {
- case OSELRECV:
- case OSELRECV2:
- ch = n->right->left;
-
- // If we can use the address of the target without
- // violating addressability or order of operations, do so.
- // Otherwise introduce a temporary.
- // Also introduce a temporary for := variables that escape,
- // so that we can delay the heap allocation until the case
- // is selected.
- if(n->op == OSELRECV2) {
- if(n->ntest == N || isblank(n->ntest))
- n->ntest = nodnil();
- else if(n->ntest->op == ONAME &&
- (!n->colas || (n->ntest->class&PHEAP) == 0) &&
- convertop(types[TBOOL], n->ntest->type, nil) == OCONVNOP) {
- n->ntest = nod(OADDR, n->ntest, N);
- n->ntest->etype = 1; // pointer does not escape
- typecheck(&n->ntest, Erv);
- } else {
- tmp = nod(OXXX, N, N);
- tempname(tmp, types[TBOOL]);
- a = nod(OADDR, tmp, N);
- a->etype = 1; // pointer does not escape
- typecheck(&a, Erv);
- r = nod(OAS, n->ntest, tmp);
- typecheck(&r, Etop);
- cas->nbody = concat(list1(r), cas->nbody);
- n->ntest = a;
- }
- }
-
- if(n->left == N || isblank(n->left))
- n->left = nodnil();
- else if(n->left->op == ONAME &&
- (!n->colas || (n->left->class&PHEAP) == 0) &&
- convertop(ch->type->type, n->left->type, nil) == OCONVNOP) {
- n->left = nod(OADDR, n->left, N);
- n->left->etype = 1; // pointer does not escape
- typecheck(&n->left, Erv);
- } else {
- tmp = nod(OXXX, N, N);
- tempname(tmp, ch->type->type);
- a = nod(OADDR, tmp, N);
- a->etype = 1; // pointer does not escape
- typecheck(&a, Erv);
- r = nod(OAS, n->left, tmp);
- typecheck(&r, Etop);
- cas->nbody = concat(list1(r), cas->nbody);
- n->left = a;
- }
-
- cas->nbody = concat(n->ninit, cas->nbody);
- n->ninit = nil;
- break;
- }
- }
-
- // optimization: two-case select but one is default: single non-blocking op.
- if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) {
- if(sel->list->n->left == nil) {
- cas = sel->list->next->n;
- dflt = sel->list->n;
- } else {
- dflt = sel->list->next->n;
- cas = sel->list->n;
- }
-
- n = cas->left;
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- // if c != nil && selectnbsend(c, v) { body } else { default body }
- ch = cheapexpr(n->left, &r->ninit);
- r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
- mkcall1(chanfn("selectnbsend", 2, ch->type),
- types[TBOOL], &r->ninit, ch, n->right));
- break;
-
- case OSELRECV:
- // if c != nil && selectnbrecv(&v, c) { body } else { default body }
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- ch = cheapexpr(n->right->left, &r->ninit);
- r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
- mkcall1(chanfn("selectnbrecv", 2, ch->type),
- types[TBOOL], &r->ninit, n->left, ch));
- break;
-
- case OSELRECV2:
- // if c != nil && selectnbrecv2(&v, c) { body } else { default body }
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- ch = cheapexpr(n->right->left, &r->ninit);
- r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
- mkcall1(chanfn("selectnbrecv2", 2, ch->type),
- types[TBOOL], &r->ninit, n->left, n->ntest, ch));
- break;
- }
- typecheck(&r->ntest, Erv);
- r->nbody = cas->nbody;
- r->nelse = concat(dflt->ninit, dflt->nbody);
- sel->nbody = list1(r);
- goto out;
- }
-
- init = sel->ninit;
- sel->ninit = nil;
-
- // generate sel-struct
- var = nod(OXXX, N, N);
- tempname(var, ptrto(types[TUINT8]));
- r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(sel->xoffset)));
- typecheck(&r, Etop);
- init = list(init, r);
-
- // register cases
- for(l=sel->list; l; l=l->next) {
- cas = l->n;
- n = cas->left;
- r = nod(OIF, N, N);
- r->nbody = cas->ninit;
- cas->ninit = nil;
- if(n != nil) {
- r->nbody = concat(r->nbody, n->ninit);
- n->ninit = nil;
- }
- if(n == nil) {
- // selectdefault(sel *byte);
- r->ntest = mkcall("selectdefault", types[TBOOL], &init, var);
- } else {
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
- r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
- &init, var, n->left, n->right);
- break;
-
- case OSELRECV:
- // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
- r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
- &init, var, n->right->left, n->left);
- break;
-
- case OSELRECV2:
- // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
- r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL],
- &init, var, n->right->left, n->left, n->ntest);
- break;
- }
- }
- r->nbody = concat(r->nbody, cas->nbody);
- r->nbody = list(r->nbody, nod(OBREAK, N, N));
- init = list(init, r);
- }
-
- // run the select
- init = list(init, mkcall("selectgo", T, nil, var));
- sel->nbody = init;
-
-out:
- sel->list = nil;
- walkstmtlist(sel->nbody);
- lineno = lno;
-}
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
deleted file mode 100644
index eb7ef31ec..000000000
--- a/src/cmd/gc/sinit.c
+++ /dev/null
@@ -1,971 +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.
-
-/*
- * static initialization
- */
-
-#include "go.h"
-
-static NodeList *initlist;
-static void init2(Node*, NodeList**);
-static void init2list(NodeList*, NodeList**);
-
-static void
-init1(Node *n, NodeList **out)
-{
- NodeList *l;
-
- if(n == N)
- return;
- init1(n->left, out);
- init1(n->right, out);
- for(l=n->list; l; l=l->next)
- init1(l->n, out);
-
- if(n->op != ONAME)
- return;
- switch(n->class) {
- case PEXTERN:
- case PFUNC:
- break;
- default:
- if(isblank(n) && n->defn != N && !n->defn->initorder) {
- n->defn->initorder = 1;
- *out = list(*out, n->defn);
- }
- return;
- }
-
- if(n->initorder == 1)
- return;
- if(n->initorder == 2) {
- if(n->class == PFUNC)
- return;
-
- // if there have already been errors printed,
- // those errors probably confused us and
- // there might not be a loop. let the user
- // fix those first.
- flusherrors();
- if(nerrors > 0)
- errorexit();
-
- print("initialization loop:\n");
- for(l=initlist;; l=l->next) {
- if(l->next == nil)
- break;
- l->next->end = l;
- }
- for(; l; l=l->end)
- print("\t%L %S refers to\n", l->n->lineno, l->n->sym);
- print("\t%L %S\n", n->lineno, n->sym);
- errorexit();
- }
- n->initorder = 2;
- l = malloc(sizeof *l);
- l->next = initlist;
- l->n = n;
- l->end = nil;
- initlist = l;
-
- // make sure that everything n depends on is initialized.
- // n->defn is an assignment to n
- if(n->defn != N) {
- switch(n->defn->op) {
- default:
- goto bad;
-
- case ODCLFUNC:
- init2list(n->defn->nbody, out);
- break;
-
- case OAS:
- if(n->defn->left != n)
- goto bad;
- n->defn->dodata = 1;
- init1(n->defn->right, out);
- if(debug['j'])
- print("%S\n", n->sym);
- *out = list(*out, n->defn);
- break;
-
- case OAS2FUNC:
- case OAS2MAPR:
- case OAS2DOTTYPE:
- case OAS2RECV:
- if(n->defn->initorder)
- break;
- n->defn->initorder = 1;
- for(l=n->defn->rlist; l; l=l->next)
- init1(l->n, out);
- *out = list(*out, n->defn);
- break;
- }
- }
- l = initlist;
- initlist = l->next;
- if(l->n != n)
- fatal("bad initlist");
- free(l);
- n->initorder = 1;
- return;
-
-bad:
- dump("defn", n->defn);
- fatal("init1: bad defn");
-}
-
-// recurse over n, doing init1 everywhere.
-static void
-init2(Node *n, NodeList **out)
-{
- if(n == N || n->initorder == 1)
- return;
- init1(n, out);
- init2(n->left, out);
- init2(n->right, out);
- init2(n->ntest, out);
- init2list(n->ninit, out);
- init2list(n->list, out);
- init2list(n->rlist, out);
- init2list(n->nbody, out);
- init2list(n->nelse, out);
-}
-
-static void
-init2list(NodeList *l, NodeList **out)
-{
- for(; l; l=l->next)
- init2(l->n, out);
-}
-
-
-static void
-initreorder(NodeList *l, NodeList **out)
-{
- Node *n;
-
- for(; l; l=l->next) {
- n = l->n;
- switch(n->op) {
- case ODCLFUNC:
- case ODCLCONST:
- case ODCLTYPE:
- continue;
- }
- initreorder(n->ninit, out);
- n->ninit = nil;
- init1(n, out);
- }
-}
-
-NodeList*
-initfix(NodeList *l)
-{
- NodeList *lout;
-
- lout = nil;
- initreorder(l, &lout);
- return lout;
-}
-
-/*
- * from here down is the walk analysis
- * of composite literals.
- * most of the work is to generate
- * data statements for the constant
- * part of the composite literal.
- */
-
-static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
-static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
-static void slicelit(int ctxt, Node *n, Node *var, NodeList **init);
-static void maplit(int ctxt, Node *n, Node *var, NodeList **init);
-
-static Node*
-staticname(Type *t, int ctxt)
-{
- Node *n;
-
- snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen);
- statuniqgen++;
- n = newname(lookup(namebuf));
- if(!ctxt)
- n->readonly = 1;
- addvar(n, t, PEXTERN);
- return n;
-}
-
-static int
-isliteral(Node *n)
-{
- if(n->op == OLITERAL)
- if(n->val.ctype != CTNIL)
- return 1;
- return 0;
-}
-
-static int
-simplename(Node *n)
-{
- if(n->op != ONAME)
- goto no;
- if(!n->addable)
- goto no;
- if(n->class & PHEAP)
- goto no;
- if(n->class == PPARAMREF)
- goto no;
- return 1;
-
-no:
- return 0;
-}
-
-static void
-litas(Node *l, Node *r, NodeList **init)
-{
- Node *a;
-
- a = nod(OAS, l, r);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-}
-
-enum
-{
- MODEDYNAM = 1,
- MODECONST = 2,
-};
-
-static int
-getdyn(Node *n, int top)
-{
- NodeList *nl;
- Node *value;
- int mode;
-
- mode = 0;
- switch(n->op) {
- default:
- if(isliteral(n))
- return MODECONST;
- return MODEDYNAM;
- case OARRAYLIT:
- if(!top && n->type->bound < 0)
- return MODEDYNAM;
- case OSTRUCTLIT:
- break;
- }
-
- for(nl=n->list; nl; nl=nl->next) {
- value = nl->n->right;
- mode |= getdyn(value, 0);
- if(mode == (MODEDYNAM|MODECONST))
- break;
- }
- return mode;
-}
-
-static void
-structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *nl;
- Node *index, *value;
-
- for(nl=n->list; nl; nl=nl->next) {
- r = nl->n;
- if(r->op != OKEY)
- fatal("structlit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- switch(value->op) {
- case OARRAYLIT:
- if(value->type->bound < 0) {
- if(pass == 1 && ctxt != 0) {
- a = nod(ODOT, var, newname(index->sym));
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 2 && ctxt == 0) {
- a = nod(ODOT, var, newname(index->sym));
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 3)
- break;
- continue;
- }
- a = nod(ODOT, var, newname(index->sym));
- arraylit(ctxt, pass, value, a, init);
- continue;
-
- case OSTRUCTLIT:
- a = nod(ODOT, var, newname(index->sym));
- structlit(ctxt, pass, value, a, init);
- continue;
- }
-
- if(isliteral(value)) {
- if(pass == 2)
- continue;
- } else
- if(pass == 1)
- continue;
-
- // build list of var.field = expr
- a = nod(ODOT, var, newname(index->sym));
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- if(pass == 1) {
- if(a->op != OAS)
- fatal("structlit: not as");
- a->dodata = 2;
- }
- *init = list(*init, a);
- }
-}
-
-static void
-arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *l;
- Node *index, *value;
-
- for(l=n->list; l; l=l->next) {
- r = l->n;
- if(r->op != OKEY)
- fatal("arraylit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- switch(value->op) {
- case OARRAYLIT:
- if(value->type->bound < 0) {
- if(pass == 1 && ctxt != 0) {
- a = nod(OINDEX, var, index);
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 2 && ctxt == 0) {
- a = nod(OINDEX, var, index);
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 3)
- break;
- continue;
- }
- a = nod(OINDEX, var, index);
- arraylit(ctxt, pass, value, a, init);
- continue;
-
- case OSTRUCTLIT:
- a = nod(OINDEX, var, index);
- structlit(ctxt, pass, value, a, init);
- continue;
- }
-
- if(isliteral(index) && isliteral(value)) {
- if(pass == 2)
- continue;
- } else
- if(pass == 1)
- continue;
-
- // build list of var[index] = value
- a = nod(OINDEX, var, index);
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- walkexpr(&a, init); // add any assignments in r to top
- if(pass == 1) {
- if(a->op != OAS)
- fatal("structlit: not as");
- a->dodata = 2;
- }
- *init = list(*init, a);
- }
-}
-
-static void
-slicelit(int ctxt, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *l;
- Type *t;
- Node *vstat, *vauto;
- Node *index, *value;
- int mode;
-
- // make an array type
- t = shallow(n->type);
- t->bound = mpgetfix(n->right->val.u.xval);
- t->width = 0;
- t->sym = nil;
- dowidth(t);
-
- if(ctxt != 0) {
-
- // put everything into static array
- vstat = staticname(t, ctxt);
- arraylit(ctxt, 1, n, vstat, init);
- arraylit(ctxt, 2, n, vstat, init);
-
- // copy static to slice
- a = nod(OSLICE, vstat, nod(OKEY, N, N));
- a = nod(OAS, var, a);
- typecheck(&a, Etop);
- a->dodata = 2;
- *init = list(*init, a);
- return;
- }
-
- // recipe for var = []t{...}
- // 1. make a static array
- // var vstat [...]t
- // 2. assign (data statements) the constant part
- // vstat = constpart{}
- // 3. make an auto pointer to array and allocate heap to it
- // var vauto *[...]t = new([...]t)
- // 4. copy the static array to the auto array
- // *vauto = vstat
- // 5. assign slice of allocated heap to var
- // var = [0:]*auto
- // 6. for each dynamic part assign to the slice
- // var[i] = dynamic part
- //
- // an optimization is done if there is no constant part
- // 3. var vauto *[...]t = new([...]t)
- // 5. var = [0:]*auto
- // 6. var[i] = dynamic part
-
- // if the literal contains constants,
- // make static initialized array (1),(2)
- vstat = N;
- mode = getdyn(n, 1);
- if(mode & MODECONST) {
- vstat = staticname(t, ctxt);
- arraylit(ctxt, 1, n, vstat, init);
- }
-
- // make new auto *array (3 declare)
- vauto = nod(OXXX, N, N);
- tempname(vauto, ptrto(t));
-
- // set auto to point at new heap (3 assign)
- a = nod(ONEW, N, N);
- a->list = list1(typenod(t));
- a = nod(OAS, vauto, a);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- if(vstat != N) {
- // copy static to heap (4)
- a = nod(OIND, vauto, N);
- a = nod(OAS, a, vstat);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
-
- // make slice out of heap (5)
- a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N)));
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- // put dynamics into slice (6)
- for(l=n->list; l; l=l->next) {
- r = l->n;
- if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
- a = nod(OINDEX, var, index);
- a->etype = 1; // no bounds checking
- // TODO need to check bounds?
-
- switch(value->op) {
- case OARRAYLIT:
- if(value->type->bound < 0)
- break;
- arraylit(ctxt, 2, value, a, init);
- continue;
-
- case OSTRUCTLIT:
- structlit(ctxt, 2, value, a, init);
- continue;
- }
-
- if(isliteral(index) && isliteral(value))
- continue;
-
- // build list of var[c] = expr
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
-}
-
-static void
-maplit(int ctxt, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *l;
- int nerr, b;
- Type *t, *tk, *tv, *t1;
- Node *vstat, *index, *value;
- Sym *syma, *symb;
-
-ctxt = 0;
-
- // make the map var
- nerr = nerrors;
-
- a = nod(OMAKE, N, N);
- a->list = list1(typenod(n->type));
- litas(var, a, init);
-
- // count the initializers
- b = 0;
- for(l=n->list; l; l=l->next) {
- r = l->n;
-
- if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- if(isliteral(index) && isliteral(value))
- b++;
- }
-
- t = T;
- if(b != 0) {
- // build type [count]struct { a Tindex, b Tvalue }
- t = n->type;
- tk = t->down;
- tv = t->type;
-
- symb = lookup("b");
- t = typ(TFIELD);
- t->type = tv;
- t->sym = symb;
-
- syma = lookup("a");
- t1 = t;
- t = typ(TFIELD);
- t->type = tk;
- t->sym = syma;
- t->down = t1;
-
- t1 = t;
- t = typ(TSTRUCT);
- t->type = t1;
-
- t1 = t;
- t = typ(TARRAY);
- t->bound = b;
- t->type = t1;
-
- dowidth(t);
-
- // make and initialize static array
- vstat = staticname(t, ctxt);
- b = 0;
- for(l=n->list; l; l=l->next) {
- r = l->n;
-
- if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- if(isliteral(index) && isliteral(value)) {
- // build vstat[b].a = key;
- a = nodintconst(b);
- a = nod(OINDEX, vstat, a);
- a = nod(ODOT, a, newname(syma));
- a = nod(OAS, a, index);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- a->dodata = 2;
- *init = list(*init, a);
-
- // build vstat[b].b = value;
- a = nodintconst(b);
- a = nod(OINDEX, vstat, a);
- a = nod(ODOT, a, newname(symb));
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- a->dodata = 2;
- *init = list(*init, a);
-
- b++;
- }
- }
-
- // loop adding structure elements to map
- // for i = 0; i < len(vstat); i++ {
- // map[vstat[i].a] = vstat[i].b
- // }
- index = nod(OXXX, N, N);
- tempname(index, types[TINT]);
-
- a = nod(OINDEX, vstat, index);
- a->etype = 1; // no bounds checking
- a = nod(ODOT, a, newname(symb));
-
- r = nod(OINDEX, vstat, index);
- r->etype = 1; // no bounds checking
- r = nod(ODOT, r, newname(syma));
- r = nod(OINDEX, var, r);
-
- r = nod(OAS, r, a);
-
- a = nod(OFOR, N, N);
- a->nbody = list1(r);
-
- a->ninit = list1(nod(OAS, index, nodintconst(0)));
- a->ntest = nod(OLT, index, nodintconst(t->bound));
- a->nincr = nod(OASOP, index, nodintconst(1));
- a->nincr->etype = OADD;
-
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
- }
-
- // put in dynamic entries one-at-a-time
- for(l=n->list; l; l=l->next) {
- r = l->n;
-
- if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- if(isliteral(index) && isliteral(value))
- continue;
-
- // build list of var[c] = expr
- a = nod(OINDEX, var, r->left);
- a = nod(OAS, a, r->right);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- if(nerr != nerrors)
- break;
-
- *init = list(*init, a);
- }
-}
-
-void
-anylit(int ctxt, Node *n, Node *var, NodeList **init)
-{
- Type *t;
- Node *a, *vstat;
-
- t = n->type;
- switch(n->op) {
- default:
- fatal("anylit: not lit");
-
- case OSTRUCTLIT:
- if(t->etype != TSTRUCT)
- fatal("anylit: not struct");
-
- if(simplename(var)) {
-
- if(ctxt == 0) {
- // lay out static data
- vstat = staticname(t, ctxt);
- structlit(1, 1, n, vstat, init);
-
- // copy static to var
- a = nod(OAS, var, vstat);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- // add expressions to automatic
- structlit(ctxt, 2, n, var, init);
- break;
- }
- structlit(ctxt, 1, n, var, init);
- structlit(ctxt, 2, n, var, init);
- break;
- }
-
- // initialize of not completely specified
- if(count(n->list) < structcount(t)) {
- a = nod(OAS, var, N);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
- structlit(ctxt, 3, n, var, init);
- break;
-
- case OARRAYLIT:
- if(t->etype != TARRAY)
- fatal("anylit: not array");
- if(t->bound < 0) {
- slicelit(ctxt, n, var, init);
- break;
- }
-
- if(simplename(var)) {
-
- if(ctxt == 0) {
- // lay out static data
- vstat = staticname(t, ctxt);
- arraylit(1, 1, n, vstat, init);
-
- // copy static to automatic
- a = nod(OAS, var, vstat);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- // add expressions to automatic
- arraylit(ctxt, 2, n, var, init);
- break;
- }
- arraylit(ctxt, 1, n, var, init);
- arraylit(ctxt, 2, n, var, init);
- break;
- }
-
- // initialize of not completely specified
- if(count(n->list) < t->bound) {
- a = nod(OAS, var, N);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
- arraylit(ctxt, 3, n, var, init);
- break;
-
- case OMAPLIT:
- if(t->etype != TMAP)
- fatal("anylit: not map");
- maplit(ctxt, n, var, init);
- break;
- }
-}
-
-int
-oaslit(Node *n, NodeList **init)
-{
- int ctxt;
-
- if(n->left == N || n->right == N)
- goto no;
- if(n->left->type == T || n->right->type == T)
- goto no;
- if(!simplename(n->left))
- goto no;
- if(!eqtype(n->left->type, n->right->type))
- goto no;
-
- // context is init() function.
- // implies generated data executed
- // exactly once and not subject to races.
- ctxt = 0;
-// if(n->dodata == 1)
-// ctxt = 1;
-
- switch(n->right->op) {
- default:
- goto no;
-
- case OSTRUCTLIT:
- case OARRAYLIT:
- case OMAPLIT:
- if(vmatch1(n->left, n->right))
- goto no;
- anylit(ctxt, n->right, n->left, init);
- break;
- }
- n->op = OEMPTY;
- return 1;
-
-no:
- // not a special composit literal assignment
- return 0;
-}
-
-static int
-getlit(Node *lit)
-{
- if(smallintconst(lit))
- return mpgetfix(lit->val.u.xval);
- return -1;
-}
-
-int
-stataddr(Node *nam, Node *n)
-{
- int l;
-
- if(n == N)
- goto no;
-
- switch(n->op) {
-
- case ONAME:
- *nam = *n;
- return n->addable;
-
- case ODOT:
- if(!stataddr(nam, n->left))
- break;
- nam->xoffset += n->xoffset;
- nam->type = n->type;
- return 1;
-
- case OINDEX:
- if(n->left->type->bound < 0)
- break;
- if(!stataddr(nam, n->left))
- break;
- l = getlit(n->right);
- if(l < 0)
- break;
- nam->xoffset += l*n->type->width;
- nam->type = n->type;
- return 1;
- }
-
-no:
- return 0;
-}
-
-int
-gen_as_init(Node *n)
-{
- Node *nr, *nl;
- Node nam, nod1;
-
- if(n->dodata == 0)
- goto no;
-
- nr = n->right;
- nl = n->left;
- if(nr == N) {
- if(!stataddr(&nam, nl))
- goto no;
- if(nam.class != PEXTERN)
- goto no;
- goto yes;
- }
-
- if(nr->type == T || !eqtype(nl->type, nr->type))
- goto no;
-
- if(!stataddr(&nam, nl))
- goto no;
-
- if(nam.class != PEXTERN)
- goto no;
-
- switch(nr->op) {
- default:
- goto no;
-
- case OCONVNOP:
- nr = nr->left;
- if(nr == N || nr->op != OSLICEARR)
- goto no;
- // fall through
-
- case OSLICEARR:
- if(nr->right->op == OKEY && nr->right->left == N && nr->right->right == N) {
- nr = nr->left;
- goto slice;
- }
- goto no;
-
- case OLITERAL:
- break;
- }
-
- switch(nr->type->etype) {
- default:
- goto no;
-
- case TBOOL:
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TPTR32:
- case TPTR64:
- case TFLOAT32:
- case TFLOAT64:
- gused(N); // in case the data is the dest of a goto
- gdata(&nam, nr, nr->type->width);
- break;
-
- case TCOMPLEX64:
- case TCOMPLEX128:
- gused(N); // in case the data is the dest of a goto
- gdatacomplex(&nam, nr->val.u.cval);
- break;
-
- case TSTRING:
- gused(N); // in case the data is the dest of a goto
- gdatastring(&nam, nr->val.u.sval);
- break;
- }
-
-yes:
- return 1;
-
-slice:
- gused(N); // in case the data is the dest of a goto
- nl = nr;
- if(nr == N || nr->op != OADDR)
- goto no;
- nr = nr->left;
- if(nr == N || nr->op != ONAME)
- goto no;
-
- // nr is the array being converted to a slice
- if(nr->type == T || nr->type->etype != TARRAY || nr->type->bound < 0)
- goto no;
-
- nam.xoffset += Array_array;
- gdata(&nam, nl, types[tptr]->width);
-
- nam.xoffset += Array_nel-Array_array;
- nodconst(&nod1, types[TINT32], nr->type->bound);
- gdata(&nam, &nod1, types[TINT32]->width);
-
- nam.xoffset += Array_cap-Array_nel;
- gdata(&nam, &nod1, types[TINT32]->width);
-
- goto yes;
-
-no:
- if(n->dodata == 2) {
- dump("\ngen_as_init", n);
- fatal("gen_as_init couldnt make data statement");
- }
- return 0;
-}
-
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
deleted file mode 100644
index 40b0c4fd1..000000000
--- a/src/cmd/gc/subr.c
+++ /dev/null
@@ -1,3851 +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 "go.h"
-#include "md5.h"
-#include "y.tab.h"
-#include "opnames.h"
-#include "yerr.h"
-
-static void dodump(Node*, int);
-
-typedef struct Error Error;
-struct Error
-{
- int lineno;
- int seq;
- char *msg;
-};
-static Error *err;
-static int nerr;
-static int merr;
-
-void
-errorexit(void)
-{
- flusherrors();
- if(outfile)
- remove(outfile);
- exit(1);
-}
-
-extern int yychar;
-int
-parserline(void)
-{
- if(yychar != 0 && yychar != -2) // parser has one symbol lookahead
- return prevlineno;
- return lineno;
-}
-
-static void
-adderr(int line, char *fmt, va_list arg)
-{
- Fmt f;
- Error *p;
-
- erroring++;
- fmtstrinit(&f);
- fmtprint(&f, "%L: ", line);
- fmtvprint(&f, fmt, arg);
- fmtprint(&f, "\n");
- erroring--;
-
- if(nerr >= merr) {
- if(merr == 0)
- merr = 16;
- else
- merr *= 2;
- p = realloc(err, merr*sizeof err[0]);
- if(p == nil) {
- merr = nerr;
- flusherrors();
- print("out of memory\n");
- errorexit();
- }
- err = p;
- }
- err[nerr].seq = nerr;
- err[nerr].lineno = line;
- err[nerr].msg = fmtstrflush(&f);
- nerr++;
-}
-
-static int
-errcmp(const void *va, const void *vb)
-{
- Error *a, *b;
-
- a = (Error*)va;
- b = (Error*)vb;
- if(a->lineno != b->lineno)
- return a->lineno - b->lineno;
- if(a->seq != b->seq)
- return a->seq - b->seq;
- return strcmp(a->msg, b->msg);
-}
-
-void
-flusherrors(void)
-{
- int i;
-
- if(nerr == 0)
- return;
- qsort(err, nerr, sizeof err[0], errcmp);
- for(i=0; i<nerr; i++)
- if(i==0 || strcmp(err[i].msg, err[i-1].msg) != 0)
- print("%s", err[i].msg);
- nerr = 0;
-}
-
-static void
-hcrash(void)
-{
- if(debug['h']) {
- flusherrors();
- if(outfile)
- unlink(outfile);
- *(volatile int*)0 = 0;
- }
-}
-
-void
-yyerrorl(int line, char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- adderr(line, fmt, arg);
- va_end(arg);
-
- hcrash();
- nerrors++;
- if(nerrors >= 10 && !debug['e']) {
- flusherrors();
- print("%L: too many errors\n", line);
- errorexit();
- }
-}
-
-extern int yystate, yychar;
-
-void
-yyerror(char *fmt, ...)
-{
- int i;
- static int lastsyntax;
- va_list arg;
- char buf[512], *p;
-
- if(strncmp(fmt, "syntax error", 12) == 0) {
- nsyntaxerrors++;
-
- if(debug['x'])
- print("yyerror: yystate=%d yychar=%d\n", yystate, yychar);
-
- // only one syntax error per line
- if(lastsyntax == lexlineno)
- return;
- lastsyntax = lexlineno;
-
- if(strstr(fmt, "{ or {")) {
- // The grammar has { and LBRACE but both show up as {.
- // Rewrite syntax error referring to "{ or {" to say just "{".
- strecpy(buf, buf+sizeof buf, fmt);
- p = strstr(buf, "{ or {");
- if(p)
- memmove(p+1, p+6, strlen(p+6)+1);
- fmt = buf;
- }
-
- // look for parse state-specific errors in list (see go.errors).
- for(i=0; i<nelem(yymsg); i++) {
- if(yymsg[i].yystate == yystate && yymsg[i].yychar == yychar) {
- yyerrorl(lexlineno, "syntax error: %s", yymsg[i].msg);
- return;
- }
- }
-
- // plain "syntax error" gets "near foo" added
- if(strcmp(fmt, "syntax error") == 0) {
- yyerrorl(lexlineno, "syntax error near %s", lexbuf);
- return;
- }
-
- // if bison says "syntax error, more info"; print "syntax error: more info".
- if(fmt[12] == ',') {
- yyerrorl(lexlineno, "syntax error:%s", fmt+13);
- return;
- }
-
- yyerrorl(lexlineno, "%s", fmt);
- return;
- }
-
- va_start(arg, fmt);
- adderr(parserline(), fmt, arg);
- va_end(arg);
-
- hcrash();
- nerrors++;
- if(nerrors >= 10 && !debug['e']) {
- flusherrors();
- print("%L: too many errors\n", parserline());
- errorexit();
- }
-}
-
-void
-warn(char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- adderr(parserline(), fmt, arg);
- va_end(arg);
-
- hcrash();
-}
-
-void
-fatal(char *fmt, ...)
-{
- va_list arg;
-
- flusherrors();
-
- print("%L: internal compiler error: ", lineno);
- va_start(arg, fmt);
- vfprint(1, fmt, arg);
- va_end(arg);
- print("\n");
-
- // If this is a released compiler version, ask for a bug report.
- if(strncmp(getgoversion(), "release", 7) == 0) {
- print("\n");
- print("Please file a bug report including a short program that triggers the error.\n");
- print("http://code.google.com/p/go/issues/entry?template=compilerbug\n");
- }
- hcrash();
- errorexit();
-}
-
-void
-linehist(char *file, int32 off, int relative)
-{
- Hist *h;
- char *cp;
-
- if(debug['i']) {
- if(file != nil) {
- if(off < 0)
- print("pragma %s", file);
- else
- if(off > 0)
- print("line %s", file);
- else
- print("import %s", file);
- } else
- print("end of import");
- print(" at line %L\n", lexlineno);
- }
-
- if(off < 0 && file[0] != '/' && !relative) {
- cp = mal(strlen(file) + strlen(pathname) + 2);
- sprint(cp, "%s/%s", pathname, file);
- file = cp;
- }
-
- h = mal(sizeof(Hist));
- h->name = file;
- h->line = lexlineno;
- h->offset = off;
- h->link = H;
- if(ehist == H) {
- hist = h;
- ehist = h;
- return;
- }
- ehist->link = h;
- ehist = h;
-}
-
-int32
-setlineno(Node *n)
-{
- int32 lno;
-
- lno = lineno;
- if(n != N)
- switch(n->op) {
- case ONAME:
- case OTYPE:
- case OPACK:
- case OLITERAL:
- break;
- default:
- lineno = n->lineno;
- if(lineno == 0) {
- if(debug['K'])
- warn("setlineno: line 0");
- lineno = lno;
- }
- }
- return lno;
-}
-
-uint32
-stringhash(char *p)
-{
- int32 h;
- int c;
-
- h = 0;
- for(;;) {
- c = *p++;
- if(c == 0)
- break;
- h = h*PRIME1 + c;
- }
-
- if(h < 0) {
- h = -h;
- if(h < 0)
- h = 0;
- }
- return h;
-}
-
-Sym*
-lookup(char *name)
-{
- return pkglookup(name, localpkg);
-}
-
-Sym*
-pkglookup(char *name, Pkg *pkg)
-{
- Sym *s;
- uint32 h;
- int c;
-
- h = stringhash(name) % NHASH;
- c = name[0];
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != c || s->pkg != pkg)
- continue;
- if(strcmp(s->name, name) == 0)
- return s;
- }
-
- s = mal(sizeof(*s));
- s->name = mal(strlen(name)+1);
- strcpy(s->name, name);
-
- s->pkg = pkg;
-
- s->link = hash[h];
- hash[h] = s;
- s->lexical = LNAME;
-
- return s;
-}
-
-Sym*
-restrictlookup(char *name, Pkg *pkg)
-{
- if(!exportname(name) && pkg != localpkg)
- yyerror("cannot refer to unexported name %s.%s", pkg->name, name);
- return pkglookup(name, pkg);
-}
-
-
-// find all the exported symbols in package opkg
-// and make them available in the current package
-void
-importdot(Pkg *opkg, Node *pack)
-{
- Sym *s, *s1;
- uint32 h;
- int n;
-
- n = 0;
- for(h=0; h<NHASH; h++) {
- for(s = hash[h]; s != S; s = s->link) {
- if(s->pkg != opkg)
- continue;
- if(s->def == N)
- continue;
- if(!exportname(s->name) || utfrune(s->name, 0xb7)) // 0xb7 = center dot
- continue;
- s1 = lookup(s->name);
- if(s1->def != N) {
- redeclare(s1, "during import");
- continue;
- }
- s1->def = s->def;
- s1->block = s->block;
- s1->def->pack = pack;
- n++;
- }
- }
- if(n == 0) {
- // can't possibly be used - there were no symbols
- yyerrorl(pack->lineno, "imported and not used: %Z", opkg->path);
- }
-}
-
-static void
-gethunk(void)
-{
- char *h;
- int32 nh;
-
- nh = NHUNK;
- if(thunk >= 10L*NHUNK)
- nh = 10L*NHUNK;
- h = (char*)malloc(nh);
- if(h == nil) {
- flusherrors();
- yyerror("out of memory");
- errorexit();
- }
- hunk = h;
- nhunk = nh;
- thunk += nh;
-}
-
-void*
-mal(int32 n)
-{
- void *p;
-
- if(n >= NHUNK) {
- p = malloc(n);
- if(p == nil) {
- flusherrors();
- yyerror("out of memory");
- errorexit();
- }
- memset(p, 0, n);
- return p;
- }
-
- while((uintptr)hunk & MAXALIGN) {
- hunk++;
- nhunk--;
- }
- if(nhunk < n)
- gethunk();
-
- p = hunk;
- nhunk -= n;
- hunk += n;
- memset(p, 0, n);
- return p;
-}
-
-void*
-remal(void *p, int32 on, int32 n)
-{
- void *q;
-
- q = (uchar*)p + on;
- if(q != hunk || nhunk < n) {
- if(on+n >= NHUNK) {
- q = mal(on+n);
- memmove(q, p, on);
- return q;
- }
- if(nhunk < on+n)
- gethunk();
- memmove(hunk, p, on);
- p = hunk;
- hunk += on;
- nhunk -= on;
- }
- hunk += n;
- nhunk -= n;
- return p;
-}
-
-Node*
-nod(int op, Node *nleft, Node *nright)
-{
- Node *n;
-
- n = mal(sizeof(*n));
- n->op = op;
- n->left = nleft;
- n->right = nright;
- n->lineno = parserline();
- n->xoffset = BADWIDTH;
- n->orig = n;
- return n;
-}
-
-int
-algtype(Type *t)
-{
- int a;
-
- if(issimple[t->etype] || isptr[t->etype] ||
- t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) {
- if(t->width == widthptr)
- a = AMEMWORD;
- else
- a = AMEM; // just bytes (int, ptr, etc)
- } else if(t->etype == TSTRING)
- a = ASTRING; // string
- else if(isnilinter(t))
- a = ANILINTER; // nil interface
- else if(t->etype == TINTER)
- a = AINTER; // interface
- else
- a = ANOEQ; // just bytes, but no hash/eq
- return a;
-}
-
-Type*
-maptype(Type *key, Type *val)
-{
- Type *t;
-
-
- if(key != nil && key->etype != TANY && algtype(key) == ANOEQ) {
- if(key->etype == TFORW) {
- // map[key] used during definition of key.
- // postpone check until key is fully defined.
- // if there are multiple uses of map[key]
- // before key is fully defined, the error
- // will only be printed for the first one.
- // good enough.
- if(key->maplineno == 0)
- key->maplineno = lineno;
- } else
- yyerror("invalid map key type %T", key);
- }
- t = typ(TMAP);
- t->down = key;
- t->type = val;
- return t;
-}
-
-Type*
-typ(int et)
-{
- Type *t;
-
- t = mal(sizeof(*t));
- t->etype = et;
- t->width = BADWIDTH;
- t->lineno = lineno;
- t->orig = t;
- return t;
-}
-
-static int
-methcmp(const void *va, const void *vb)
-{
- Type *a, *b;
- int i;
-
- a = *(Type**)va;
- b = *(Type**)vb;
- i = strcmp(a->sym->name, b->sym->name);
- if(i != 0)
- return i;
- if(!exportname(a->sym->name)) {
- i = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s);
- if(i != 0)
- return i;
- }
- return 0;
-}
-
-Type*
-sortinter(Type *t)
-{
- Type *f;
- int i;
- Type **a;
-
- if(t->type == nil || t->type->down == nil)
- return t;
-
- i=0;
- for(f=t->type; f; f=f->down)
- i++;
- a = mal(i*sizeof f);
- i = 0;
- for(f=t->type; f; f=f->down)
- a[i++] = f;
- qsort(a, i, sizeof a[0], methcmp);
- while(i-- > 0) {
- a[i]->down = f;
- f = a[i];
- }
- t->type = f;
- return t;
-}
-
-Node*
-nodintconst(int64 v)
-{
- Node *c;
-
- c = nod(OLITERAL, N, N);
- c->addable = 1;
- c->val.u.xval = mal(sizeof(*c->val.u.xval));
- mpmovecfix(c->val.u.xval, v);
- c->val.ctype = CTINT;
- c->type = types[TIDEAL];
- ullmancalc(c);
- return c;
-}
-
-Node*
-nodfltconst(Mpflt* v)
-{
- Node *c;
-
- c = nod(OLITERAL, N, N);
- c->addable = 1;
- c->val.u.fval = mal(sizeof(*c->val.u.fval));
- mpmovefltflt(c->val.u.fval, v);
- c->val.ctype = CTFLT;
- c->type = types[TIDEAL];
- ullmancalc(c);
- return c;
-}
-
-void
-nodconst(Node *n, Type *t, int64 v)
-{
- memset(n, 0, sizeof(*n));
- n->op = OLITERAL;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.xval = mal(sizeof(*n->val.u.xval));
- mpmovecfix(n->val.u.xval, v);
- n->val.ctype = CTINT;
- n->type = t;
-
- if(isfloat[t->etype])
- fatal("nodconst: bad type %T", t);
-}
-
-Node*
-nodnil(void)
-{
- Node *c;
-
- c = nodintconst(0);
- c->val.ctype = CTNIL;
- c->type = types[TNIL];
- return c;
-}
-
-Node*
-nodbool(int b)
-{
- Node *c;
-
- c = nodintconst(0);
- c->val.ctype = CTBOOL;
- c->val.u.bval = b;
- c->type = idealbool;
- return c;
-}
-
-Type*
-aindex(Node *b, Type *t)
-{
- Type *r;
- int bound;
-
- bound = -1; // open bound
- typecheck(&b, Erv);
- if(b != nil) {
- switch(consttype(b)) {
- default:
- yyerror("array bound must be an integer expression");
- break;
- case CTINT:
- bound = mpgetfix(b->val.u.xval);
- if(bound < 0)
- yyerror("array bound must be non negative");
- break;
- }
- }
-
- // fixed array
- r = typ(TARRAY);
- r->type = t;
- r->bound = bound;
- return r;
-}
-
-static void
-indent(int dep)
-{
- int i;
-
- for(i=0; i<dep; i++)
- print(". ");
-}
-
-static void
-dodumplist(NodeList *l, int dep)
-{
- for(; l; l=l->next)
- dodump(l->n, dep);
-}
-
-static void
-dodump(Node *n, int dep)
-{
- if(n == N)
- return;
-
- indent(dep);
- if(dep > 10) {
- print("...\n");
- return;
- }
-
- if(n->ninit != nil) {
- print("%O-init\n", n->op);
- dodumplist(n->ninit, dep+1);
- indent(dep);
- }
-
- switch(n->op) {
- default:
- print("%N\n", n);
- dodump(n->left, dep+1);
- dodump(n->right, dep+1);
- break;
-
- case OTYPE:
- print("%O %S type=%T\n", n->op, n->sym, n->type);
- if(n->type == T && n->ntype) {
- indent(dep);
- print("%O-ntype\n", n->op);
- dodump(n->ntype, dep+1);
- }
- break;
-
- case OIF:
- print("%O%J\n", n->op, n);
- dodump(n->ntest, dep+1);
- if(n->nbody != nil) {
- indent(dep);
- print("%O-then\n", n->op);
- dodumplist(n->nbody, dep+1);
- }
- if(n->nelse != nil) {
- indent(dep);
- print("%O-else\n", n->op);
- dodumplist(n->nelse, dep+1);
- }
- break;
-
- case OSELECT:
- print("%O%J\n", n->op, n);
- dodumplist(n->nbody, dep+1);
- break;
-
- case OSWITCH:
- case OFOR:
- print("%O%J\n", n->op, n);
- dodump(n->ntest, dep+1);
-
- if(n->nbody != nil) {
- indent(dep);
- print("%O-body\n", n->op);
- dodumplist(n->nbody, dep+1);
- }
-
- if(n->nincr != N) {
- indent(dep);
- print("%O-incr\n", n->op);
- dodump(n->nincr, dep+1);
- }
- break;
-
- case OCASE:
- // the right side points to label of the body
- if(n->right != N && n->right->op == OGOTO && n->right->left->op == ONAME)
- print("%O%J GOTO %N\n", n->op, n, n->right->left);
- else
- print("%O%J\n", n->op, n);
- dodump(n->left, dep+1);
- break;
-
- case OXCASE:
- print("%N\n", n);
- dodump(n->left, dep+1);
- dodump(n->right, dep+1);
- indent(dep);
- print("%O-nbody\n", n->op);
- dodumplist(n->nbody, dep+1);
- break;
- }
-
- if(0 && n->ntype != nil) {
- indent(dep);
- print("%O-ntype\n", n->op);
- dodump(n->ntype, dep+1);
- }
- if(n->list != nil) {
- indent(dep);
- print("%O-list\n", n->op);
- dodumplist(n->list, dep+1);
- }
- if(n->rlist != nil) {
- indent(dep);
- print("%O-rlist\n", n->op);
- dodumplist(n->rlist, dep+1);
- }
- if(n->op != OIF && n->nbody != nil) {
- indent(dep);
- print("%O-nbody\n", n->op);
- dodumplist(n->nbody, dep+1);
- }
-}
-
-void
-dumplist(char *s, NodeList *l)
-{
- print("%s\n", s);
- dodumplist(l, 1);
-}
-
-void
-dump(char *s, Node *n)
-{
- print("%s [%p]\n", s, n);
- dodump(n, 1);
-}
-
-static char*
-goopnames[] =
-{
- [OADDR] = "&",
- [OADD] = "+",
- [OANDAND] = "&&",
- [OANDNOT] = "&^",
- [OAND] = "&",
- [OAPPEND] = "append",
- [OAS] = "=",
- [OAS2] = "=",
- [OBREAK] = "break",
- [OCALL] = "function call",
- [OCAP] = "cap",
- [OCASE] = "case",
- [OCLOSE] = "close",
- [OCOMPLEX] = "complex",
- [OCOM] = "^",
- [OCONTINUE] = "continue",
- [OCOPY] = "copy",
- [ODEC] = "--",
- [ODEFER] = "defer",
- [ODIV] = "/",
- [OEQ] = "==",
- [OFALL] = "fallthrough",
- [OFOR] = "for",
- [OGE] = ">=",
- [OGOTO] = "goto",
- [OGT] = ">",
- [OIF] = "if",
- [OIMAG] = "imag",
- [OINC] = "++",
- [OIND] = "*",
- [OLEN] = "len",
- [OLE] = "<=",
- [OLSH] = "<<",
- [OLT] = "<",
- [OMAKE] = "make",
- [OMINUS] = "-",
- [OMOD] = "%",
- [OMUL] = "*",
- [ONEW] = "new",
- [ONE] = "!=",
- [ONOT] = "!",
- [OOROR] = "||",
- [OOR] = "|",
- [OPANIC] = "panic",
- [OPLUS] = "+",
- [OPRINTN] = "println",
- [OPRINT] = "print",
- [ORANGE] = "range",
- [OREAL] = "real",
- [ORECV] = "<-",
- [ORETURN] = "return",
- [ORSH] = ">>",
- [OSELECT] = "select",
- [OSEND] = "<-",
- [OSUB] = "-",
- [OSWITCH] = "switch",
- [OXOR] = "^",
-};
-
-int
-Oconv(Fmt *fp)
-{
- int o;
-
- o = va_arg(fp->args, int);
- if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
- return fmtstrcpy(fp, goopnames[o]);
- if(o < 0 || o >= nelem(opnames) || opnames[o] == nil)
- return fmtprint(fp, "O-%d", o);
- return fmtstrcpy(fp, opnames[o]);
-}
-
-int
-Lconv(Fmt *fp)
-{
- struct
- {
- Hist* incl; /* start of this include file */
- int32 idel; /* delta line number to apply to include */
- Hist* line; /* start of this #line directive */
- int32 ldel; /* delta line number to apply to #line */
- } a[HISTSZ];
- int32 lno, d;
- int i, n;
- Hist *h;
-
- lno = va_arg(fp->args, int32);
-
- n = 0;
- for(h=hist; h!=H; h=h->link) {
- if(h->offset < 0)
- continue;
- if(lno < h->line)
- break;
- if(h->name) {
- if(h->offset > 0) {
- // #line directive
- if(n > 0 && n < HISTSZ) {
- a[n-1].line = h;
- a[n-1].ldel = h->line - h->offset + 1;
- }
- } else {
- // beginning of file
- if(n < HISTSZ) {
- a[n].incl = h;
- a[n].idel = h->line;
- a[n].line = 0;
- }
- n++;
- }
- continue;
- }
- n--;
- if(n > 0 && n < HISTSZ) {
- d = h->line - a[n].incl->line;
- a[n-1].ldel += d;
- a[n-1].idel += d;
- }
- }
-
- if(n > HISTSZ)
- n = HISTSZ;
-
- for(i=n-1; i>=0; i--) {
- if(i != n-1) {
- if(fp->flags & ~(FmtWidth|FmtPrec))
- break;
- fmtprint(fp, " ");
- }
- if(debug['L'])
- fmtprint(fp, "%s/", pathname);
- if(a[i].line)
- fmtprint(fp, "%s:%d[%s:%d]",
- a[i].line->name, lno-a[i].ldel+1,
- a[i].incl->name, lno-a[i].idel+1);
- else
- fmtprint(fp, "%s:%d",
- a[i].incl->name, lno-a[i].idel+1);
- lno = a[i].incl->line - 1; // now print out start of this file
- }
- if(n == 0)
- fmtprint(fp, "<epoch>");
-
- return 0;
-}
-
-/*
-s%,%,\n%g
-s%\n+%\n%g
-s%^[ ]*T%%g
-s%,.*%%g
-s%.+% [T&] = "&",%g
-s%^ ........*\]%&~%g
-s%~ %%g
-*/
-
-static char*
-etnames[] =
-{
- [TINT] = "INT",
- [TUINT] = "UINT",
- [TINT8] = "INT8",
- [TUINT8] = "UINT8",
- [TINT16] = "INT16",
- [TUINT16] = "UINT16",
- [TINT32] = "INT32",
- [TUINT32] = "UINT32",
- [TINT64] = "INT64",
- [TUINT64] = "UINT64",
- [TUINTPTR] = "UINTPTR",
- [TFLOAT32] = "FLOAT32",
- [TFLOAT64] = "FLOAT64",
- [TCOMPLEX64] = "COMPLEX64",
- [TCOMPLEX128] = "COMPLEX128",
- [TBOOL] = "BOOL",
- [TPTR32] = "PTR32",
- [TPTR64] = "PTR64",
- [TFUNC] = "FUNC",
- [TARRAY] = "ARRAY",
- [TSTRUCT] = "STRUCT",
- [TCHAN] = "CHAN",
- [TMAP] = "MAP",
- [TINTER] = "INTER",
- [TFORW] = "FORW",
- [TFIELD] = "FIELD",
- [TSTRING] = "STRING",
- [TANY] = "ANY",
-};
-
-int
-Econv(Fmt *fp)
-{
- int et;
-
- et = va_arg(fp->args, int);
- if(et < 0 || et >= nelem(etnames) || etnames[et] == nil)
- return fmtprint(fp, "E-%d", et);
- return fmtstrcpy(fp, etnames[et]);
-}
-
-static const char* classnames[] = {
- "Pxxx",
- "PEXTERN",
- "PAUTO",
- "PPARAM",
- "PPARAMOUT",
- "PPARAMREF",
- "PFUNC",
-};
-
-int
-Jconv(Fmt *fp)
-{
- Node *n;
- char *s;
-
- n = va_arg(fp->args, Node*);
- if(n->ullman != 0)
- fmtprint(fp, " u(%d)", n->ullman);
-
- if(n->addable != 0)
- fmtprint(fp, " a(%d)", n->addable);
-
- if(n->vargen != 0)
- fmtprint(fp, " g(%d)", n->vargen);
-
- if(n->lineno != 0)
- fmtprint(fp, " l(%d)", n->lineno);
-
- if(n->xoffset != BADWIDTH)
- fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
-
- if(n->class != 0) {
- s = "";
- if (n->class & PHEAP) s = ",heap";
- if ((n->class & ~PHEAP) < nelem(classnames))
- fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s);
- else
- fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s);
- }
-
- if(n->colas != 0)
- fmtprint(fp, " colas(%d)", n->colas);
-
- if(n->funcdepth != 0)
- fmtprint(fp, " f(%d)", n->funcdepth);
-
- if(n->typecheck != 0)
- fmtprint(fp, " tc(%d)", n->typecheck);
-
- if(n->dodata != 0)
- fmtprint(fp, " dd(%d)", n->dodata);
-
- if(n->isddd != 0)
- fmtprint(fp, " isddd(%d)", n->isddd);
-
- if(n->implicit != 0)
- fmtprint(fp, " implicit(%d)", n->implicit);
-
- if(n->pun != 0)
- fmtprint(fp, " pun(%d)", n->pun);
-
- if(n->used != 0)
- fmtprint(fp, " used(%d)", n->used);
- return 0;
-}
-
-int
-Sconv(Fmt *fp)
-{
- Sym *s;
-
- s = va_arg(fp->args, Sym*);
- if(s == S) {
- fmtstrcpy(fp, "<S>");
- return 0;
- }
-
- if(fp->flags & FmtShort)
- goto shrt;
-
- if(exporting || (fp->flags & FmtSharp)) {
- if(packagequotes)
- fmtprint(fp, "\"%Z\"", s->pkg->path);
- else
- fmtprint(fp, "%s", s->pkg->prefix);
- fmtprint(fp, ".%s", s->name);
- return 0;
- }
-
- if(s->pkg && s->pkg != localpkg || longsymnames || (fp->flags & FmtLong)) {
- // This one is for the user. If the package name
- // was used by multiple packages, give the full
- // import path to disambiguate.
- if(erroring && pkglookup(s->pkg->name, nil)->npkg > 1) {
- fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
- return 0;
- }
- fmtprint(fp, "%s.%s", s->pkg->name, s->name);
- return 0;
- }
-
-shrt:
- fmtstrcpy(fp, s->name);
- return 0;
-}
-
-static char*
-basicnames[] =
-{
- [TINT] = "int",
- [TUINT] = "uint",
- [TINT8] = "int8",
- [TUINT8] = "uint8",
- [TINT16] = "int16",
- [TUINT16] = "uint16",
- [TINT32] = "int32",
- [TUINT32] = "uint32",
- [TINT64] = "int64",
- [TUINT64] = "uint64",
- [TUINTPTR] = "uintptr",
- [TFLOAT32] = "float32",
- [TFLOAT64] = "float64",
- [TCOMPLEX64] = "complex64",
- [TCOMPLEX128] = "complex128",
- [TBOOL] = "bool",
- [TANY] = "any",
- [TSTRING] = "string",
- [TNIL] = "nil",
- [TIDEAL] = "ideal",
- [TBLANK] = "blank",
-};
-
-int
-Tpretty(Fmt *fp, Type *t)
-{
- Type *t1;
- Sym *s;
-
- if(0 && debug['r']) {
- debug['r'] = 0;
- fmtprint(fp, "%T (orig=%T)", t, t->orig);
- debug['r'] = 1;
- return 0;
- }
-
- if(t->etype != TFIELD
- && t->sym != S
- && !(fp->flags&FmtLong)) {
- s = t->sym;
- if(t == types[t->etype] && t->etype != TUNSAFEPTR)
- return fmtprint(fp, "%s", s->name);
- if(exporting) {
- if(fp->flags & FmtShort)
- fmtprint(fp, "%hS", s);
- else
- fmtprint(fp, "%S", s);
- if(s->pkg != localpkg)
- return 0;
- if(t->vargen)
- fmtprint(fp, "·%d", t->vargen);
- return 0;
- }
- return fmtprint(fp, "%S", s);
- }
-
- if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) {
- if(isideal(t) && t->etype != TIDEAL && t->etype != TNIL)
- fmtprint(fp, "ideal ");
- return fmtprint(fp, "%s", basicnames[t->etype]);
- }
-
- switch(t->etype) {
- case TPTR32:
- case TPTR64:
- if(fp->flags&FmtShort) // pass flag thru for methodsym
- return fmtprint(fp, "*%hT", t->type);
- return fmtprint(fp, "*%T", t->type);
-
- case TCHAN:
- switch(t->chan) {
- case Crecv:
- return fmtprint(fp, "<-chan %T", t->type);
- case Csend:
- return fmtprint(fp, "chan<- %T", t->type);
- }
- if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv)
- return fmtprint(fp, "chan (%T)", t->type);
- return fmtprint(fp, "chan %T", t->type);
-
- case TMAP:
- return fmtprint(fp, "map[%T] %T", t->down, t->type);
-
- case TFUNC:
- // t->type is method struct
- // t->type->down is result struct
- // t->type->down->down is arg struct
- if(t->thistuple && !(fp->flags&FmtSharp) && !(fp->flags&FmtShort)) {
- fmtprint(fp, "method(");
- for(t1=getthisx(t)->type; t1; t1=t1->down) {
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- fmtprint(fp, ")");
- }
-
- if(!(fp->flags&FmtByte))
- fmtprint(fp, "func");
- fmtprint(fp, "(");
- for(t1=getinargx(t)->type; t1; t1=t1->down) {
- if(noargnames && t1->etype == TFIELD) {
- if(t1->isddd)
- fmtprint(fp, "...%T", t1->type->type);
- else
- fmtprint(fp, "%T", t1->type);
- } else
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- fmtprint(fp, ")");
- switch(t->outtuple) {
- case 0:
- break;
- case 1:
- t1 = getoutargx(t)->type;
- if(t1 == T) {
- // failure to typecheck earlier; don't know the type
- fmtprint(fp, " ?unknown-type?");
- break;
- }
- if(t1->etype == TFIELD)
- t1 = t1->type;
- fmtprint(fp, " %T", t1);
- break;
- default:
- t1 = getoutargx(t)->type;
- fmtprint(fp, " (");
- for(; t1; t1=t1->down) {
- if(noargnames && t1->etype == TFIELD)
- fmtprint(fp, "%T", t1->type);
- else
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- fmtprint(fp, ")");
- break;
- }
- return 0;
-
- case TARRAY:
- if(t->bound >= 0)
- return fmtprint(fp, "[%d]%T", (int)t->bound, t->type);
- if(t->bound == -100)
- return fmtprint(fp, "[...]%T", t->type);
- return fmtprint(fp, "[]%T", t->type);
-
- case TINTER:
- fmtprint(fp, "interface {");
- for(t1=t->type; t1!=T; t1=t1->down) {
- fmtprint(fp, " ");
- if(exportname(t1->sym->name))
- fmtprint(fp, "%hS", t1->sym);
- else
- fmtprint(fp, "%S", t1->sym);
- fmtprint(fp, "%hhT", t1->type);
- if(t1->down)
- fmtprint(fp, ";");
- }
- return fmtprint(fp, " }");
-
- case TSTRUCT:
- if(t->funarg) {
- fmtprint(fp, "(");
- for(t1=t->type; t1!=T; t1=t1->down) {
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- return fmtprint(fp, ")");
- }
- fmtprint(fp, "struct {");
- for(t1=t->type; t1!=T; t1=t1->down) {
- fmtprint(fp, " %T", t1);
- if(t1->down)
- fmtprint(fp, ";");
- }
- return fmtprint(fp, " }");
-
- case TFIELD:
- if(t->sym == S || t->embedded) {
- if(exporting)
- fmtprint(fp, "? ");
- } else
- fmtprint(fp, "%hS ", t->sym);
- if(t->isddd)
- fmtprint(fp, "...%T", t->type->type);
- else
- fmtprint(fp, "%T", t->type);
- if(t->note) {
- fmtprint(fp, " ");
- if(exporting)
- fmtprint(fp, ":");
- fmtprint(fp, "\"%Z\"", t->note);
- }
- return 0;
-
- case TFORW:
- if(exporting)
- yyerror("undefined type %S", t->sym);
- if(t->sym)
- return fmtprint(fp, "undefined %S", t->sym);
- return fmtprint(fp, "undefined");
-
- case TUNSAFEPTR:
- if(exporting)
- return fmtprint(fp, "\"unsafe\".Pointer");
- return fmtprint(fp, "unsafe.Pointer");
- }
-
- // Don't know how to handle - fall back to detailed prints.
- return -1;
-}
-
-int
-Tconv(Fmt *fp)
-{
- Type *t, *t1;
- int r, et, sharp, minus;
-
- sharp = (fp->flags & FmtSharp);
- minus = (fp->flags & FmtLeft);
- fp->flags &= ~(FmtSharp|FmtLeft);
-
- t = va_arg(fp->args, Type*);
- if(t == T)
- return fmtstrcpy(fp, "<T>");
-
- t->trecur++;
- if(t->trecur > 5) {
- fmtprint(fp, "...");
- goto out;
- }
-
- if(!debug['t']) {
- if(sharp)
- exporting++;
- if(minus)
- noargnames++;
- r = Tpretty(fp, t);
- if(sharp)
- exporting--;
- if(minus)
- noargnames--;
- if(r >= 0) {
- t->trecur--;
- return 0;
- }
- }
-
- if(sharp || exporting)
- fatal("missing %E case during export", t->etype);
-
- et = t->etype;
- fmtprint(fp, "%E ", et);
- if(t->sym != S)
- fmtprint(fp, "<%S>", t->sym);
-
- switch(et) {
- default:
- if(t->type != T)
- fmtprint(fp, " %T", t->type);
- break;
-
- case TFIELD:
- fmtprint(fp, "%T", t->type);
- break;
-
- case TFUNC:
- if(fp->flags & FmtLong)
- fmtprint(fp, "%d%d%d(%lT,%lT)%lT",
- t->thistuple, t->intuple, t->outtuple,
- t->type, t->type->down->down, t->type->down);
- else
- fmtprint(fp, "%d%d%d(%T,%T)%T",
- t->thistuple, t->intuple, t->outtuple,
- t->type, t->type->down->down, t->type->down);
- break;
-
- case TINTER:
- fmtprint(fp, "{");
- if(fp->flags & FmtLong)
- for(t1=t->type; t1!=T; t1=t1->down)
- fmtprint(fp, "%lT;", t1);
- fmtprint(fp, "}");
- break;
-
- case TSTRUCT:
- fmtprint(fp, "{");
- if(fp->flags & FmtLong)
- for(t1=t->type; t1!=T; t1=t1->down)
- fmtprint(fp, "%lT;", t1);
- fmtprint(fp, "}");
- break;
-
- case TMAP:
- fmtprint(fp, "[%T]%T", t->down, t->type);
- break;
-
- case TARRAY:
- if(t->bound >= 0)
- fmtprint(fp, "[%d]%T", t->bound, t->type);
- else
- fmtprint(fp, "[]%T", t->type);
- break;
-
- case TPTR32:
- case TPTR64:
- fmtprint(fp, "%T", t->type);
- break;
- }
-
-out:
- t->trecur--;
- return 0;
-}
-
-int
-Nconv(Fmt *fp)
-{
- char buf1[500];
- Node *n;
-
- n = va_arg(fp->args, Node*);
- if(n == N) {
- fmtprint(fp, "<N>");
- goto out;
- }
-
- if(fp->flags & FmtSign) {
- if(n->type == T)
- fmtprint(fp, "%#N", n);
- else if(n->type->etype == TNIL)
- fmtprint(fp, "nil");
- else
- fmtprint(fp, "%#N (type %T)", n, n->type);
- goto out;
- }
-
- if(fp->flags & FmtSharp) {
- if(n->orig != N)
- n = n->orig;
- exprfmt(fp, n, 0);
- goto out;
- }
-
- switch(n->op) {
- default:
- fmtprint(fp, "%O%J", n->op, n);
- break;
-
- case ONAME:
- case ONONAME:
- if(n->sym == S) {
- fmtprint(fp, "%O%J", n->op, n);
- break;
- }
- fmtprint(fp, "%O-%S G%d%J", n->op,
- n->sym, n->vargen, n);
- goto ptyp;
-
- case OREGISTER:
- fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n);
- break;
-
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- snprint(buf1, sizeof(buf1), "LITERAL-ctype=%d", n->val.ctype);
- break;
- case CTINT:
- snprint(buf1, sizeof(buf1), "I%B", n->val.u.xval);
- break;
- case CTFLT:
- snprint(buf1, sizeof(buf1), "F%g", mpgetflt(n->val.u.fval));
- break;
- case CTCPLX:
- snprint(buf1, sizeof(buf1), "(F%g+F%gi)",
- mpgetflt(&n->val.u.cval->real),
- mpgetflt(&n->val.u.cval->imag));
- break;
- case CTSTR:
- snprint(buf1, sizeof(buf1), "S\"%Z\"", n->val.u.sval);
- break;
- case CTBOOL:
- snprint(buf1, sizeof(buf1), "B%d", n->val.u.bval);
- break;
- case CTNIL:
- snprint(buf1, sizeof(buf1), "N");
- break;
- }
- fmtprint(fp, "%O-%s%J", n->op, buf1, n);
- break;
-
- case OASOP:
- fmtprint(fp, "%O-%O%J", n->op, n->etype, n);
- break;
-
- case OTYPE:
- fmtprint(fp, "%O %T", n->op, n->type);
- break;
- }
- if(n->sym != S)
- fmtprint(fp, " %S G%d", n->sym, n->vargen);
-
-ptyp:
- if(n->type != T)
- fmtprint(fp, " %T", n->type);
-
-out:
- return 0;
-}
-
-Node*
-treecopy(Node *n)
-{
- Node *m;
-
- if(n == N)
- return N;
-
- switch(n->op) {
- default:
- m = nod(OXXX, N, N);
- *m = *n;
- m->left = treecopy(n->left);
- m->right = treecopy(n->right);
- m->list = listtreecopy(n->list);
- if(m->defn)
- abort();
- break;
-
- case ONONAME:
- if(n->sym == lookup("iota")) {
- // Not sure yet whether this is the real iota,
- // but make a copy of the Node* just in case,
- // so that all the copies of this const definition
- // don't have the same iota value.
- m = nod(OXXX, N, N);
- *m = *n;
- m->iota = iota;
- break;
- }
- // fall through
- case ONAME:
- case OLITERAL:
- case OTYPE:
- m = n;
- break;
- }
- return m;
-}
-
-int
-Zconv(Fmt *fp)
-{
- Rune r;
- Strlit *sp;
- char *s, *se;
- int n;
-
- sp = va_arg(fp->args, Strlit*);
- if(sp == nil)
- return fmtstrcpy(fp, "<nil>");
-
- s = sp->s;
- se = s + sp->len;
- while(s < se) {
- n = chartorune(&r, s);
- s += n;
- switch(r) {
- case Runeerror:
- if(n == 1) {
- fmtprint(fp, "\\x%02x", (uchar)*(s-1));
- break;
- }
- // fall through
- default:
- if(r < ' ') {
- fmtprint(fp, "\\x%02x", r);
- break;
- }
- fmtrune(fp, r);
- break;
- case '\t':
- fmtstrcpy(fp, "\\t");
- break;
- case '\n':
- fmtstrcpy(fp, "\\n");
- break;
- case '\"':
- case '\\':
- fmtrune(fp, '\\');
- fmtrune(fp, r);
- break;
- }
- }
- return 0;
-}
-
-int
-isnil(Node *n)
-{
- if(n == N)
- return 0;
- if(n->op != OLITERAL)
- return 0;
- if(n->val.ctype != CTNIL)
- return 0;
- return 1;
-}
-
-int
-isptrto(Type *t, int et)
-{
- if(t == T)
- return 0;
- if(!isptr[t->etype])
- return 0;
- t = t->type;
- if(t == T)
- return 0;
- if(t->etype != et)
- return 0;
- return 1;
-}
-
-int
-istype(Type *t, int et)
-{
- return t != T && t->etype == et;
-}
-
-int
-isfixedarray(Type *t)
-{
- return t != T && t->etype == TARRAY && t->bound >= 0;
-}
-
-int
-isslice(Type *t)
-{
- return t != T && t->etype == TARRAY && t->bound < 0;
-}
-
-int
-isblank(Node *n)
-{
- char *p;
-
- if(n == N || n->sym == S)
- return 0;
- p = n->sym->name;
- if(p == nil)
- return 0;
- return p[0] == '_' && p[1] == '\0';
-}
-
-int
-isselect(Node *n)
-{
- Sym *s;
-
- if(n == N)
- return 0;
- n = n->left;
- s = pkglookup("selectsend", runtimepkg);
- if(s == n->sym)
- return 1;
- s = pkglookup("selectrecv", runtimepkg);
- if(s == n->sym)
- return 1;
- s = pkglookup("selectrecv2", runtimepkg);
- if(s == n->sym)
- return 1;
- s = pkglookup("selectdefault", runtimepkg);
- if(s == n->sym)
- return 1;
- return 0;
-}
-
-int
-isinter(Type *t)
-{
- return t != T && t->etype == TINTER;
-}
-
-int
-isnilinter(Type *t)
-{
- if(!isinter(t))
- return 0;
- if(t->type != T)
- return 0;
- return 1;
-}
-
-int
-isideal(Type *t)
-{
- if(t == T)
- return 0;
- if(t == idealstring || t == idealbool)
- return 1;
- switch(t->etype) {
- case TNIL:
- case TIDEAL:
- return 1;
- }
- return 0;
-}
-
-/*
- * given receiver of type t (t == r or t == *r)
- * return type to hang methods off (r).
- */
-Type*
-methtype(Type *t)
-{
- if(t == T)
- return T;
-
- // strip away pointer if it's there
- if(isptr[t->etype]) {
- if(t->sym != S)
- return T;
- t = t->type;
- if(t == T)
- return T;
- }
-
- // need a type name
- if(t->sym == S)
- return T;
-
- // check types
- if(!issimple[t->etype])
- switch(t->etype) {
- default:
- return T;
- case TSTRUCT:
- case TARRAY:
- case TMAP:
- case TCHAN:
- case TSTRING:
- case TFUNC:
- break;
- }
-
- return t;
-}
-
-int
-cplxsubtype(int et)
-{
- switch(et) {
- case TCOMPLEX64:
- return TFLOAT32;
- case TCOMPLEX128:
- return TFLOAT64;
- }
- fatal("cplxsubtype: %E\n", et);
- return 0;
-}
-
-static int
-eqnote(Strlit *a, Strlit *b)
-{
- if(a == b)
- return 1;
- if(a == nil || b == nil)
- return 0;
- if(a->len != b->len)
- return 0;
- return memcmp(a->s, b->s, a->len) == 0;
-}
-
-// Return 1 if t1 and t2 are identical, following the spec rules.
-//
-// Any cyclic type must go through a named type, and if one is
-// named, it is only identical to the other if they are the same
-// pointer (t1 == t2), so there's no chance of chasing cycles
-// ad infinitum, so no need for a depth counter.
-int
-eqtype(Type *t1, Type *t2)
-{
- if(t1 == t2)
- return 1;
- if(t1 == T || t2 == T || t1->etype != t2->etype || t1->sym || t2->sym)
- return 0;
-
- switch(t1->etype) {
- case TINTER:
- case TSTRUCT:
- for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
- if(t1->etype != TFIELD || t2->etype != TFIELD)
- fatal("struct/interface missing field: %T %T", t1, t2);
- if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type) || !eqnote(t1->note, t2->note))
- return 0;
- }
- return t1 == T && t2 == T;
-
- case TFUNC:
- // Loop over structs: receiver, in, out.
- for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
- Type *ta, *tb;
-
- if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
- fatal("func missing struct: %T %T", t1, t2);
-
- // Loop over fields in structs, ignoring argument names.
- for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
- if(ta->etype != TFIELD || tb->etype != TFIELD)
- fatal("func struct missing field: %T %T", ta, tb);
- if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type))
- return 0;
- }
- if(ta != T || tb != T)
- return 0;
- }
- return t1 == T && t2 == T;
-
- case TARRAY:
- if(t1->bound != t2->bound)
- return 0;
- break;
-
- case TCHAN:
- if(t1->chan != t2->chan)
- return 0;
- break;
- }
-
- return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type);
-}
-
-// Are t1 and t2 equal struct types when field names are ignored?
-// For deciding whether the result struct from g can be copied
-// directly when compiling f(g()).
-int
-eqtypenoname(Type *t1, Type *t2)
-{
- if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT)
- return 0;
-
- t1 = t1->type;
- t2 = t2->type;
- for(;;) {
- if(!eqtype(t1, t2))
- return 0;
- if(t1 == T)
- return 1;
- t1 = t1->down;
- t2 = t2->down;
- }
-}
-
-// Is type src assignment compatible to type dst?
-// If so, return op code to use in conversion.
-// If not, return 0.
-//
-// It is the caller's responsibility to call exportassignok
-// to check for assignments to other packages' unexported fields,
-int
-assignop(Type *src, Type *dst, char **why)
-{
- Type *missing, *have;
- int ptr;
-
- if(why != nil)
- *why = "";
-
- if(safemode && src != T && src->etype == TUNSAFEPTR) {
- yyerror("cannot use unsafe.Pointer");
- errorexit();
- }
-
- if(src == dst)
- return OCONVNOP;
- if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T)
- return 0;
-
- // 1. src type is identical to dst.
- if(eqtype(src, dst))
- return OCONVNOP;
-
- // 2. src and dst have identical underlying types
- // and either src or dst is not a named type or
- // both are interface types.
- if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || src->etype == TINTER))
- return OCONVNOP;
-
- // 3. dst is an interface type and src implements dst.
- if(dst->etype == TINTER && src->etype != TNIL) {
- if(implements(src, dst, &missing, &have, &ptr))
- return OCONVIFACE;
- if(why != nil) {
- if(isptrto(src, TINTER))
- *why = smprint(":\n\t%T is pointer to interface, not interface", src);
- else if(have && have->sym == missing->sym)
- *why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n"
- "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
- have->sym, have->type, missing->sym, missing->type);
- else if(ptr)
- *why = smprint(":\n\t%T does not implement %T (%S method requires pointer receiver)",
- src, dst, missing->sym);
- else if(have)
- *why = smprint(":\n\t%T does not implement %T (missing %S method)\n"
- "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
- have->sym, have->type, missing->sym, missing->type);
- else
- *why = smprint(":\n\t%T does not implement %T (missing %S method)",
- src, dst, missing->sym);
- }
- return 0;
- }
- if(isptrto(dst, TINTER)) {
- if(why != nil)
- *why = smprint(":\n\t%T is pointer to interface, not interface", dst);
- return 0;
- }
- if(src->etype == TINTER && dst->etype != TBLANK) {
- if(why != nil)
- *why = ": need type assertion";
- return 0;
- }
-
- // 4. src is a bidirectional channel value, dst is a channel type,
- // src and dst have identical element types, and
- // either src or dst is not a named type.
- if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN)
- if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S))
- return OCONVNOP;
-
- // 5. src is the predeclared identifier nil and dst is a nillable type.
- if(src->etype == TNIL) {
- switch(dst->etype) {
- case TARRAY:
- if(dst->bound != -100) // not slice
- break;
- case TPTR32:
- case TPTR64:
- case TFUNC:
- case TMAP:
- case TCHAN:
- case TINTER:
- return OCONVNOP;
- }
- }
-
- // 6. rule about untyped constants - already converted by defaultlit.
-
- // 7. Any typed value can be assigned to the blank identifier.
- if(dst->etype == TBLANK)
- return OCONVNOP;
-
- return 0;
-}
-
-// Can we convert a value of type src to a value of type dst?
-// If so, return op code to use in conversion (maybe OCONVNOP).
-// If not, return 0.
-int
-convertop(Type *src, Type *dst, char **why)
-{
- int op;
-
- if(why != nil)
- *why = "";
-
- if(src == dst)
- return OCONVNOP;
- if(src == T || dst == T)
- return 0;
-
- // 1. src can be assigned to dst.
- if((op = assignop(src, dst, why)) != 0)
- return op;
-
- // The rules for interfaces are no different in conversions
- // than assignments. If interfaces are involved, stop now
- // with the good message from assignop.
- // Otherwise clear the error.
- if(src->etype == TINTER || dst->etype == TINTER)
- return 0;
- if(why != nil)
- *why = "";
-
- // 2. src and dst have identical underlying types.
- if(eqtype(src->orig, dst->orig))
- return OCONVNOP;
-
- // 3. src and dst are unnamed pointer types
- // and their base types have identical underlying types.
- if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S)
- if(eqtype(src->type->orig, dst->type->orig))
- return OCONVNOP;
-
- // 4. src and dst are both integer or floating point types.
- if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) {
- if(simtype[src->etype] == simtype[dst->etype])
- return OCONVNOP;
- return OCONV;
- }
-
- // 5. src and dst are both complex types.
- if(iscomplex[src->etype] && iscomplex[dst->etype]) {
- if(simtype[src->etype] == simtype[dst->etype])
- return OCONVNOP;
- return OCONV;
- }
-
- // 6. src is an integer or has type []byte or []int
- // and dst is a string type.
- if(isint[src->etype] && dst->etype == TSTRING)
- return ORUNESTR;
-
- if(isslice(src) && src->sym == nil && src->type == types[src->type->etype] && dst->etype == TSTRING) {
- switch(src->type->etype) {
- case TUINT8:
- return OARRAYBYTESTR;
- case TINT:
- return OARRAYRUNESTR;
- }
- }
-
- // 7. src is a string and dst is []byte or []int.
- // String to slice.
- if(src->etype == TSTRING && isslice(dst) && dst->sym == nil && dst->type == types[dst->type->etype]) {
- switch(dst->type->etype) {
- case TUINT8:
- return OSTRARRAYBYTE;
- case TINT:
- return OSTRARRAYRUNE;
- }
- }
-
- // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
- if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR)
- return OCONVNOP;
-
- // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
- if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR))
- return OCONVNOP;
-
- return 0;
-}
-
-// Convert node n for assignment to type t.
-Node*
-assignconv(Node *n, Type *t, char *context)
-{
- int op;
- Node *r, *old;
- char *why;
-
- if(n == N || n->type == T)
- return n;
-
- old = n;
- old->diag++; // silence errors about n; we'll issue one below
- defaultlit(&n, t);
- old->diag--;
- if(t->etype == TBLANK)
- return n;
-
- exportassignok(n->type, context);
- if(eqtype(n->type, t))
- return n;
-
- op = assignop(n->type, t, &why);
- if(op == 0) {
- yyerror("cannot use %+N as type %T in %s%s", n, t, context, why);
- op = OCONV;
- }
-
- r = nod(op, n, N);
- r->type = t;
- r->typecheck = 1;
- r->implicit = 1;
- return r;
-}
-
-static int
-subtype(Type **stp, Type *t, int d)
-{
- Type *st;
-
-loop:
- st = *stp;
- if(st == T)
- return 0;
-
- d++;
- if(d >= 10)
- return 0;
-
- switch(st->etype) {
- default:
- return 0;
-
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TARRAY:
- stp = &st->type;
- goto loop;
-
- case TANY:
- if(!st->copyany)
- return 0;
- *stp = t;
- break;
-
- case TMAP:
- if(subtype(&st->down, t, d))
- break;
- stp = &st->type;
- goto loop;
-
- case TFUNC:
- for(;;) {
- if(subtype(&st->type, t, d))
- break;
- if(subtype(&st->type->down->down, t, d))
- break;
- if(subtype(&st->type->down, t, d))
- break;
- return 0;
- }
- break;
-
- case TSTRUCT:
- for(st=st->type; st!=T; st=st->down)
- if(subtype(&st->type, t, d))
- return 1;
- return 0;
- }
- return 1;
-}
-
-/*
- * Is this a 64-bit type?
- */
-int
-is64(Type *t)
-{
- if(t == T)
- return 0;
- switch(simtype[t->etype]) {
- case TINT64:
- case TUINT64:
- case TPTR64:
- return 1;
- }
- return 0;
-}
-
-/*
- * Is a conversion between t1 and t2 a no-op?
- */
-int
-noconv(Type *t1, Type *t2)
-{
- int e1, e2;
-
- e1 = simtype[t1->etype];
- e2 = simtype[t2->etype];
-
- switch(e1) {
- case TINT8:
- case TUINT8:
- return e2 == TINT8 || e2 == TUINT8;
-
- case TINT16:
- case TUINT16:
- return e2 == TINT16 || e2 == TUINT16;
-
- case TINT32:
- case TUINT32:
- case TPTR32:
- return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32;
-
- case TINT64:
- case TUINT64:
- case TPTR64:
- return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64;
-
- case TFLOAT32:
- return e2 == TFLOAT32;
-
- case TFLOAT64:
- return e2 == TFLOAT64;
- }
- return 0;
-}
-
-void
-argtype(Node *on, Type *t)
-{
- dowidth(t);
- if(!subtype(&on->type, t, 0))
- fatal("argtype: failed %N %T\n", on, t);
-}
-
-Type*
-shallow(Type *t)
-{
- Type *nt;
-
- if(t == T)
- return T;
- nt = typ(0);
- *nt = *t;
- if(t->orig == t)
- nt->orig = nt;
- return nt;
-}
-
-static Type*
-deep(Type *t)
-{
- Type *nt, *xt;
-
- if(t == T)
- return T;
-
- switch(t->etype) {
- default:
- nt = t; // share from here down
- break;
-
- case TANY:
- nt = shallow(t);
- nt->copyany = 1;
- break;
-
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TARRAY:
- nt = shallow(t);
- nt->type = deep(t->type);
- break;
-
- case TMAP:
- nt = shallow(t);
- nt->down = deep(t->down);
- nt->type = deep(t->type);
- break;
-
- case TFUNC:
- nt = shallow(t);
- nt->type = deep(t->type);
- nt->type->down = deep(t->type->down);
- nt->type->down->down = deep(t->type->down->down);
- break;
-
- case TSTRUCT:
- nt = shallow(t);
- nt->type = shallow(t->type);
- xt = nt->type;
-
- for(t=t->type; t!=T; t=t->down) {
- xt->type = deep(t->type);
- xt->down = shallow(t->down);
- xt = xt->down;
- }
- break;
- }
- return nt;
-}
-
-Node*
-syslook(char *name, int copy)
-{
- Sym *s;
- Node *n;
-
- s = pkglookup(name, runtimepkg);
- if(s == S || s->def == N)
- fatal("syslook: can't find runtime.%s", name);
-
- if(!copy)
- return s->def;
-
- n = nod(0, N, N);
- *n = *s->def;
- n->type = deep(s->def->type);
-
- return n;
-}
-
-/*
- * compute a hash value for type t.
- * if t is a method type, ignore the receiver
- * so that the hash can be used in interface checks.
- * %-T (which calls Tpretty, above) already contains
- * all the necessary logic to generate a representation
- * of the type that completely describes it.
- * using smprint here avoids duplicating that code.
- * using md5 here is overkill, but i got tired of
- * accidental collisions making the runtime think
- * two types are equal when they really aren't.
- */
-uint32
-typehash(Type *t)
-{
- char *p;
- MD5 d;
-
- longsymnames = 1;
- if(t->thistuple) {
- // hide method receiver from Tpretty
- t->thistuple = 0;
- p = smprint("%-T", t);
- t->thistuple = 1;
- }else
- p = smprint("%-T", t);
- longsymnames = 0;
- md5reset(&d);
- md5write(&d, (uchar*)p, strlen(p));
- free(p);
- return md5sum(&d);
-}
-
-Type*
-ptrto(Type *t)
-{
- Type *t1;
-
- if(tptr == 0)
- fatal("ptrto: nil");
- t1 = typ(tptr);
- t1->type = t;
- t1->width = widthptr;
- t1->align = widthptr;
- return t1;
-}
-
-void
-frame(int context)
-{
- char *p;
- NodeList *l;
- Node *n;
- int flag;
-
- p = "stack";
- l = nil;
- if(curfn)
- l = curfn->dcl;
- if(context) {
- p = "external";
- l = externdcl;
- }
-
- flag = 1;
- for(; l; l=l->next) {
- n = l->n;
- switch(n->op) {
- case ONAME:
- if(flag)
- print("--- %s frame ---\n", p);
- print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type);
- flag = 0;
- break;
-
- case OTYPE:
- if(flag)
- print("--- %s frame ---\n", p);
- print("%O %T\n", n->op, n->type);
- flag = 0;
- break;
- }
- }
-}
-
-/*
- * calculate sethi/ullman number
- * roughly how many registers needed to
- * compile a node. used to compile the
- * hardest side first to minimize registers.
- */
-void
-ullmancalc(Node *n)
-{
- int ul, ur;
-
- if(n == N)
- return;
-
- switch(n->op) {
- case OREGISTER:
- case OLITERAL:
- case ONAME:
- ul = 1;
- if(n->class == PPARAMREF || (n->class & PHEAP))
- ul++;
- goto out;
- case OCALL:
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- ul = UINF;
- goto out;
- }
- ul = 1;
- if(n->left != N)
- ul = n->left->ullman;
- ur = 1;
- if(n->right != N)
- ur = n->right->ullman;
- if(ul == ur)
- ul += 1;
- if(ur > ul)
- ul = ur;
-
-out:
- n->ullman = ul;
-}
-
-void
-badtype(int o, Type *tl, Type *tr)
-{
- Fmt fmt;
- char *s;
-
- fmtstrinit(&fmt);
- if(tl != T)
- fmtprint(&fmt, "\n %T", tl);
- if(tr != T)
- fmtprint(&fmt, "\n %T", tr);
-
- // common mistake: *struct and *interface.
- if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) {
- if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER)
- fmtprint(&fmt, "\n (*struct vs *interface)");
- else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT)
- fmtprint(&fmt, "\n (*interface vs *struct)");
- }
- s = fmtstrflush(&fmt);
- yyerror("illegal types for operand: %O%s", o, s);
-}
-
-/*
- * iterator to walk a structure declaration
- */
-Type*
-structfirst(Iter *s, Type **nn)
-{
- Type *n, *t;
-
- n = *nn;
- if(n == T)
- goto bad;
-
- switch(n->etype) {
- default:
- goto bad;
-
- case TSTRUCT:
- case TINTER:
- case TFUNC:
- break;
- }
-
- t = n->type;
- if(t == T)
- goto rnil;
-
- if(t->etype != TFIELD)
- fatal("structfirst: not field %T", t);
-
- s->t = t;
- return t;
-
-bad:
- fatal("structfirst: not struct %T", n);
-
-rnil:
- return T;
-}
-
-Type*
-structnext(Iter *s)
-{
- Type *n, *t;
-
- n = s->t;
- t = n->down;
- if(t == T)
- goto rnil;
-
- if(t->etype != TFIELD)
- goto bad;
-
- s->t = t;
- return t;
-
-bad:
- fatal("structnext: not struct %T", n);
-
-rnil:
- return T;
-}
-
-/*
- * iterator to this and inargs in a function
- */
-Type*
-funcfirst(Iter *s, Type *t)
-{
- Type *fp;
-
- if(t == T)
- goto bad;
-
- if(t->etype != TFUNC)
- goto bad;
-
- s->tfunc = t;
- s->done = 0;
- fp = structfirst(s, getthis(t));
- if(fp == T) {
- s->done = 1;
- fp = structfirst(s, getinarg(t));
- }
- return fp;
-
-bad:
- fatal("funcfirst: not func %T", t);
- return T;
-}
-
-Type*
-funcnext(Iter *s)
-{
- Type *fp;
-
- fp = structnext(s);
- if(fp == T && !s->done) {
- s->done = 1;
- fp = structfirst(s, getinarg(s->tfunc));
- }
- return fp;
-}
-
-Type**
-getthis(Type *t)
-{
- if(t->etype != TFUNC)
- fatal("getthis: not a func %T", t);
- return &t->type;
-}
-
-Type**
-getoutarg(Type *t)
-{
- if(t->etype != TFUNC)
- fatal("getoutarg: not a func %T", t);
- return &t->type->down;
-}
-
-Type**
-getinarg(Type *t)
-{
- if(t->etype != TFUNC)
- fatal("getinarg: not a func %T", t);
- return &t->type->down->down;
-}
-
-Type*
-getthisx(Type *t)
-{
- return *getthis(t);
-}
-
-Type*
-getoutargx(Type *t)
-{
- return *getoutarg(t);
-}
-
-Type*
-getinargx(Type *t)
-{
- return *getinarg(t);
-}
-
-/*
- * return !(op)
- * eg == <=> !=
- */
-int
-brcom(int a)
-{
- switch(a) {
- case OEQ: return ONE;
- case ONE: return OEQ;
- case OLT: return OGE;
- case OGT: return OLE;
- case OLE: return OGT;
- case OGE: return OLT;
- }
- fatal("brcom: no com for %A\n", a);
- return a;
-}
-
-/*
- * return reverse(op)
- * eg a op b <=> b r(op) a
- */
-int
-brrev(int a)
-{
- switch(a) {
- case OEQ: return OEQ;
- case ONE: return ONE;
- case OLT: return OGT;
- case OGT: return OLT;
- case OLE: return OGE;
- case OGE: return OLE;
- }
- fatal("brcom: no rev for %A\n", a);
- return a;
-}
-
-/*
- * return side effect-free n, appending side effects to init.
- * result is assignable if n is.
- */
-Node*
-safeexpr(Node *n, NodeList **init)
-{
- Node *l;
- Node *r;
- Node *a;
-
- if(n == N)
- return N;
-
- switch(n->op) {
- case ONAME:
- case OLITERAL:
- return n;
-
- case ODOT:
- l = safeexpr(n->left, init);
- if(l == n->left)
- return n;
- r = nod(OXXX, N, N);
- *r = *n;
- r->left = l;
- typecheck(&r, Erv);
- walkexpr(&r, init);
- return r;
-
- case ODOTPTR:
- case OIND:
- l = safeexpr(n->left, init);
- if(l == n->left)
- return n;
- a = nod(OXXX, N, N);
- *a = *n;
- a->left = l;
- walkexpr(&a, init);
- return a;
-
- case OINDEX:
- case OINDEXMAP:
- l = safeexpr(n->left, init);
- r = safeexpr(n->right, init);
- if(l == n->left && r == n->right)
- return n;
- a = nod(OXXX, N, N);
- *a = *n;
- a->left = l;
- a->right = r;
- walkexpr(&a, init);
- return a;
- }
-
- // make a copy; must not be used as an lvalue
- if(islvalue(n))
- fatal("missing lvalue case in safeexpr: %N", n);
- return cheapexpr(n, init);
-}
-
-/*
- * return side-effect free and cheap n, appending side effects to init.
- * result may not be assignable.
- */
-Node*
-cheapexpr(Node *n, NodeList **init)
-{
- Node *a, *l;
-
- switch(n->op) {
- case ONAME:
- case OLITERAL:
- return n;
- }
-
- l = nod(OXXX, N, N);
- tempname(l, n->type);
- a = nod(OAS, l, n);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- return l;
-}
-
-void
-setmaxarg(Type *t)
-{
- int32 w;
-
- dowidth(t);
- w = t->argwid;
- if(t->argwid >= MAXWIDTH)
- fatal("bad argwid %T", t);
- if(w > maxarg)
- maxarg = w;
-}
-
-/* unicode-aware case-insensitive strcmp */
-
-static int
-cistrcmp(char *p, char *q)
-{
- Rune rp, rq;
-
- while(*p || *q) {
- if(*p == 0)
- return +1;
- if(*q == 0)
- return -1;
- p += chartorune(&rp, p);
- q += chartorune(&rq, q);
- rp = tolowerrune(rp);
- rq = tolowerrune(rq);
- if(rp < rq)
- return -1;
- if(rp > rq)
- return +1;
- }
- return 0;
-}
-
-/*
- * code to resolve elided DOTs
- * in embedded types
- */
-
-// search depth 0 --
-// return count of fields+methods
-// found with a given name
-static int
-lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
-{
- Type *f, *u;
- int c;
-
- u = t;
- if(isptr[u->etype])
- u = u->type;
-
- c = 0;
- if(u->etype == TSTRUCT || u->etype == TINTER) {
- for(f=u->type; f!=T; f=f->down)
- if(f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0)) {
- if(save)
- *save = f;
- c++;
- }
- }
- u = methtype(t);
- if(u != T) {
- for(f=u->method; f!=T; f=f->down)
- if(f->embedded == 0 && (f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0))) {
- if(save)
- *save = f;
- c++;
- }
- }
- return c;
-}
-
-// search depth d --
-// return count of fields+methods
-// found at search depth.
-// answer is in dotlist array and
-// count of number of ways is returned.
-int
-adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase)
-{
- Type *f, *u;
- int c, a;
-
- if(t->trecur)
- return 0;
- t->trecur = 1;
-
- if(d == 0) {
- c = lookdot0(s, t, save, ignorecase);
- goto out;
- }
-
- c = 0;
- u = t;
- if(isptr[u->etype])
- u = u->type;
- if(u->etype != TSTRUCT && u->etype != TINTER)
- goto out;
-
- d--;
- for(f=u->type; f!=T; f=f->down) {
- if(!f->embedded)
- continue;
- if(f->sym == S)
- continue;
- a = adddot1(s, f->type, d, save, ignorecase);
- if(a != 0 && c == 0)
- dotlist[d].field = f;
- c += a;
- }
-
-out:
- t->trecur = 0;
- return c;
-}
-
-// in T.field
-// find missing fields that
-// will give shortest unique addressing.
-// modify the tree with missing type names.
-Node*
-adddot(Node *n)
-{
- Type *t;
- Sym *s;
- int c, d;
-
- typecheck(&n->left, Etype|Erv);
- t = n->left->type;
- if(t == T)
- goto ret;
-
- if(n->left->op == OTYPE)
- goto ret;
-
- if(n->right->op != ONAME)
- goto ret;
- s = n->right->sym;
- if(s == S)
- goto ret;
-
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(s, t, d, nil, 0);
- if(c > 0)
- goto out;
- }
- goto ret;
-
-out:
- if(c > 1)
- yyerror("ambiguous DOT reference %T.%S", t, s);
-
- // rebuild elided dots
- for(c=d-1; c>=0; c--)
- n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym));
-ret:
- return n;
-}
-
-
-/*
- * code to help generate trampoline
- * functions for methods on embedded
- * subtypes.
- * these are approx the same as
- * the corresponding adddot routines
- * except that they expect to be called
- * with unique tasks and they return
- * the actual methods.
- */
-
-typedef struct Symlink Symlink;
-struct Symlink
-{
- Type* field;
- uchar good;
- uchar followptr;
- Symlink* link;
-};
-static Symlink* slist;
-
-static void
-expand0(Type *t, int followptr)
-{
- Type *f, *u;
- Symlink *sl;
-
- u = t;
- if(isptr[u->etype]) {
- followptr = 1;
- u = u->type;
- }
-
- if(u->etype == TINTER) {
- for(f=u->type; f!=T; f=f->down) {
- if(!exportname(f->sym->name) && f->sym->pkg != localpkg)
- continue;
- if(f->sym->flags & SymUniq)
- continue;
- f->sym->flags |= SymUniq;
- sl = mal(sizeof(*sl));
- sl->field = f;
- sl->link = slist;
- sl->followptr = followptr;
- slist = sl;
- }
- return;
- }
-
- u = methtype(t);
- if(u != T) {
- for(f=u->method; f!=T; f=f->down) {
- if(!exportname(f->sym->name) && f->sym->pkg != localpkg)
- continue;
- if(f->sym->flags & SymUniq)
- continue;
- f->sym->flags |= SymUniq;
- sl = mal(sizeof(*sl));
- sl->field = f;
- sl->link = slist;
- sl->followptr = followptr;
- slist = sl;
- }
- }
-}
-
-static void
-expand1(Type *t, int d, int followptr)
-{
- Type *f, *u;
-
- if(t->trecur)
- return;
- if(d == 0)
- return;
- t->trecur = 1;
-
- if(d != nelem(dotlist)-1)
- expand0(t, followptr);
-
- u = t;
- if(isptr[u->etype]) {
- followptr = 1;
- u = u->type;
- }
- if(u->etype != TSTRUCT && u->etype != TINTER)
- goto out;
-
- for(f=u->type; f!=T; f=f->down) {
- if(!f->embedded)
- continue;
- if(f->sym == S)
- continue;
- expand1(f->type, d-1, followptr);
- }
-
-out:
- t->trecur = 0;
-}
-
-void
-expandmeth(Sym *s, Type *t)
-{
- Symlink *sl;
- Type *f;
- int c, d;
-
- if(s == S)
- return;
- if(t == T || t->xmethod != nil)
- return;
-
- // mark top-level method symbols
- // so that expand1 doesn't consider them.
- for(f=t->method; f != nil; f=f->down)
- f->sym->flags |= SymUniq;
-
- // generate all reachable methods
- slist = nil;
- expand1(t, nelem(dotlist)-1, 0);
-
- // check each method to be uniquely reachable
- for(sl=slist; sl!=nil; sl=sl->link) {
- sl->field->sym->flags &= ~SymUniq;
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(sl->field->sym, t, d, &f, 0);
- if(c == 0)
- continue;
- if(c == 1) {
- sl->good = 1;
- sl->field = f;
- }
- break;
- }
- }
-
- for(f=t->method; f != nil; f=f->down)
- f->sym->flags &= ~SymUniq;
-
- t->xmethod = t->method;
- for(sl=slist; sl!=nil; sl=sl->link) {
- if(sl->good) {
- // add it to the base type method list
- f = typ(TFIELD);
- *f = *sl->field;
- f->embedded = 1; // needs a trampoline
- if(sl->followptr)
- f->embedded = 2;
- f->down = t->xmethod;
- t->xmethod = f;
- }
- }
-}
-
-/*
- * Given funarg struct list, return list of ODCLFIELD Node fn args.
- */
-static NodeList*
-structargs(Type **tl, int mustname)
-{
- Iter savet;
- Node *a, *n;
- NodeList *args;
- Type *t;
- char buf[100];
- int gen;
-
- args = nil;
- gen = 0;
- for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) {
- n = N;
- if(t->sym)
- n = newname(t->sym);
- else if(mustname) {
- // have to give it a name so we can refer to it in trampoline
- snprint(buf, sizeof buf, ".anon%d", gen++);
- n = newname(lookup(buf));
- }
- a = nod(ODCLFIELD, n, typenod(t->type));
- a->isddd = t->isddd;
- if(n != N)
- n->isddd = t->isddd;
- args = list(args, a);
- }
- return args;
-}
-
-/*
- * Generate a wrapper function to convert from
- * a receiver of type T to a receiver of type U.
- * That is,
- *
- * func (t T) M() {
- * ...
- * }
- *
- * already exists; this function generates
- *
- * func (u U) M() {
- * u.M()
- * }
- *
- * where the types T and U are such that u.M() is valid
- * and calls the T.M method.
- * The resulting function is for use in method tables.
- *
- * rcvr - U
- * method - M func (t T)(), a TFIELD type struct
- * newnam - the eventual mangled name of this function
- */
-void
-genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
-{
- Node *this, *fn, *call, *n, *t, *pad;
- NodeList *l, *args, *in, *out;
- Type *tpad;
- int isddd;
- Val v;
-
- if(debug['r'])
- print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
- rcvr, method, newnam);
-
- lineno = 1; // less confusing than end of input
-
- dclcontext = PEXTERN;
- markdcl();
-
- this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr));
- this->left->ntype = this->right;
- in = structargs(getinarg(method->type), 1);
- out = structargs(getoutarg(method->type), 0);
-
- fn = nod(ODCLFUNC, N, N);
- fn->nname = newname(newnam);
- t = nod(OTFUNC, N, N);
- l = list1(this);
- if(iface && rcvr->width < types[tptr]->width) {
- // Building method for interface table and receiver
- // is smaller than the single pointer-sized word
- // that the interface call will pass in.
- // Add a dummy padding argument after the
- // receiver to make up the difference.
- tpad = typ(TARRAY);
- tpad->type = types[TUINT8];
- tpad->bound = types[tptr]->width - rcvr->width;
- pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad));
- l = list(l, pad);
- }
- t->list = concat(l, in);
- t->rlist = out;
- fn->nname->ntype = t;
- funchdr(fn);
-
- // arg list
- args = nil;
- isddd = 0;
- for(l=in; l; l=l->next) {
- args = list(args, l->n->left);
- isddd = l->n->left->isddd;
- }
-
- // generate nil pointer check for better error
- if(isptr[rcvr->etype] && rcvr->type == getthisx(method->type)->type->type) {
- // generating wrapper from *T to T.
- n = nod(OIF, N, N);
- n->ntest = nod(OEQ, this->left, nodnil());
- // these strings are already in the reflect tables,
- // so no space cost to use them here.
- l = nil;
- v.ctype = CTSTR;
- v.u.sval = strlit(rcvr->type->sym->pkg->name); // package name
- l = list(l, nodlit(v));
- v.u.sval = strlit(rcvr->type->sym->name); // type name
- l = list(l, nodlit(v));
- v.u.sval = strlit(method->sym->name);
- l = list(l, nodlit(v)); // method name
- call = nod(OCALL, syslook("panicwrap", 0), N);
- call->list = l;
- n->nbody = list1(call);
- fn->nbody = list(fn->nbody, n);
- }
-
- // generate call
- call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N);
- call->list = args;
- call->isddd = isddd;
- if(method->type->outtuple > 0) {
- n = nod(ORETURN, N, N);
- n->list = list1(call);
- call = n;
- }
- fn->nbody = list(fn->nbody, call);
-
- if(0 && debug['r'])
- dumplist("genwrapper body", fn->nbody);
-
- funcbody(fn);
- curfn = fn;
- typecheck(&fn, Etop);
- typechecklist(fn->nbody, Etop);
- curfn = nil;
- funccompile(fn, 0);
-}
-
-static Type*
-ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase)
-{
- int i, c, d;
- Type *m;
-
- *followptr = 0;
-
- if(t == T)
- return T;
-
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(s, t, d, &m, ignorecase);
- if(c > 1) {
- yyerror("%T.%S is ambiguous", t, s);
- return T;
- }
- if(c == 1) {
- for(i=0; i<d; i++) {
- if(isptr[dotlist[i].field->type->etype]) {
- *followptr = 1;
- break;
- }
- }
- if(m->type->etype != TFUNC || m->type->thistuple == 0) {
- yyerror("%T.%S is a field, not a method", t, s);
- return T;
- }
- return m;
- }
- }
- return T;
-}
-
-int
-implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
-{
- Type *t0, *im, *tm, *rcvr, *imtype;
- int followptr;
-
- t0 = t;
- if(t == T)
- return 0;
-
- // if this is too slow,
- // could sort these first
- // and then do one loop.
-
- if(t->etype == TINTER) {
- for(im=iface->type; im; im=im->down) {
- for(tm=t->type; tm; tm=tm->down) {
- if(tm->sym == im->sym) {
- if(eqtype(tm->type, im->type))
- goto found;
- *m = im;
- *samename = tm;
- *ptr = 0;
- return 0;
- }
- }
- *m = im;
- *samename = nil;
- *ptr = 0;
- return 0;
- found:;
- }
- return 1;
- }
-
- t = methtype(t);
- if(t != T)
- expandmeth(t->sym, t);
- for(im=iface->type; im; im=im->down) {
- imtype = methodfunc(im->type, 0);
- tm = ifacelookdot(im->sym, t, &followptr, 0);
- if(tm == T || !eqtype(methodfunc(tm->type, 0), imtype)) {
- if(tm == T)
- tm = ifacelookdot(im->sym, t, &followptr, 1);
- *m = im;
- *samename = tm;
- *ptr = 0;
- return 0;
- }
- // if pointer receiver in method,
- // the method does not exist for value types.
- rcvr = getthisx(tm->type)->type->type;
- if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) {
- if(0 && debug['r'])
- yyerror("interface pointer mismatch");
-
- *m = im;
- *samename = nil;
- *ptr = 1;
- return 0;
- }
- }
- return 1;
-}
-
-/*
- * even simpler simtype; get rid of ptr, bool.
- * assuming that the front end has rejected
- * all the invalid conversions (like ptr -> bool)
- */
-int
-simsimtype(Type *t)
-{
- int et;
-
- if(t == 0)
- return 0;
-
- et = simtype[t->etype];
- switch(et) {
- case TPTR32:
- et = TUINT32;
- break;
- case TPTR64:
- et = TUINT64;
- break;
- case TBOOL:
- et = TUINT8;
- break;
- }
- return et;
-}
-
-NodeList*
-concat(NodeList *a, NodeList *b)
-{
- if(a == nil)
- return b;
- if(b == nil)
- return a;
-
- a->end->next = b;
- a->end = b->end;
- b->end = nil;
- return a;
-}
-
-NodeList*
-list1(Node *n)
-{
- NodeList *l;
-
- if(n == nil)
- return nil;
- if(n->op == OBLOCK && n->ninit == nil)
- return n->list;
- l = mal(sizeof *l);
- l->n = n;
- l->end = l;
- return l;
-}
-
-NodeList*
-list(NodeList *l, Node *n)
-{
- return concat(l, list1(n));
-}
-
-void
-listsort(NodeList** l, int(*f)(Node*, Node*))
-{
- NodeList *l1, *l2, *le;
-
- if(*l == nil || (*l)->next == nil)
- return;
-
- l1 = *l;
- l2 = *l;
- for(;;) {
- l2 = l2->next;
- if(l2 == nil)
- break;
- l2 = l2->next;
- if(l2 == nil)
- break;
- l1 = l1->next;
- }
-
- l2 = l1->next;
- l1->next = nil;
- l2->end = (*l)->end;
- (*l)->end = l1;
-
- l1 = *l;
- listsort(&l1, f);
- listsort(&l2, f);
-
- if ((*f)(l1->n, l2->n) < 0) {
- *l = l1;
- } else {
- *l = l2;
- l2 = l1;
- l1 = *l;
- }
-
- // now l1 == *l; and l1 < l2
-
- while ((l1 != nil) && (l2 != nil)) {
- while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0)
- l1 = l1->next;
-
- // l1 is last one from l1 that is < l2
- le = l1->next; // le is the rest of l1, first one that is >= l2
- if (le != nil)
- le->end = (*l)->end;
-
- (*l)->end = l1; // cut *l at l1
- *l = concat(*l, l2); // glue l2 to *l's tail
-
- l1 = l2; // l1 is the first element of *l that is < the new l2
- l2 = le; // ... because l2 now is the old tail of l1
- }
-
- *l = concat(*l, l2); // any remainder
-}
-
-NodeList*
-listtreecopy(NodeList *l)
-{
- NodeList *out;
-
- out = nil;
- for(; l; l=l->next)
- out = list(out, treecopy(l->n));
- return out;
-}
-
-Node*
-liststmt(NodeList *l)
-{
- Node *n;
-
- n = nod(OBLOCK, N, N);
- n->list = l;
- if(l)
- n->lineno = l->n->lineno;
- return n;
-}
-
-/*
- * return nelem of list
- */
-int
-count(NodeList *l)
-{
- int n;
-
- n = 0;
- for(; l; l=l->next)
- n++;
- return n;
-}
-
-/*
- * return nelem of list
- */
-int
-structcount(Type *t)
-{
- int v;
- Iter s;
-
- v = 0;
- for(t = structfirst(&s, &t); t != T; t = structnext(&s))
- v++;
- return v;
-}
-
-/*
- * return power of 2 of the constant
- * operand. -1 if it is not a power of 2.
- * 1000+ if it is a -(power of 2)
- */
-int
-powtwo(Node *n)
-{
- uvlong v, b;
- int i;
-
- if(n == N || n->op != OLITERAL || n->type == T)
- goto no;
- if(!isint[n->type->etype])
- goto no;
-
- v = mpgetfix(n->val.u.xval);
- b = 1ULL;
- for(i=0; i<64; i++) {
- if(b == v)
- return i;
- b = b<<1;
- }
-
- if(!issigned[n->type->etype])
- goto no;
-
- v = -v;
- b = 1ULL;
- for(i=0; i<64; i++) {
- if(b == v)
- return i+1000;
- b = b<<1;
- }
-
-no:
- return -1;
-}
-
-/*
- * return the unsigned type for
- * a signed integer type.
- * returns T if input is not a
- * signed integer type.
- */
-Type*
-tounsigned(Type *t)
-{
-
- // this is types[et+1], but not sure
- // that this relation is immutable
- switch(t->etype) {
- default:
- print("tounsigned: unknown type %T\n", t);
- t = T;
- break;
- case TINT:
- t = types[TUINT];
- break;
- case TINT8:
- t = types[TUINT8];
- break;
- case TINT16:
- t = types[TUINT16];
- break;
- case TINT32:
- t = types[TUINT32];
- break;
- case TINT64:
- t = types[TUINT64];
- break;
- }
- return t;
-}
-
-/*
- * magic number for signed division
- * see hacker's delight chapter 10
- */
-void
-smagic(Magic *m)
-{
- int p;
- uint64 ad, anc, delta, q1, r1, q2, r2, t;
- uint64 mask, two31;
-
- m->bad = 0;
- switch(m->w) {
- default:
- m->bad = 1;
- return;
- case 8:
- mask = 0xffLL;
- break;
- case 16:
- mask = 0xffffLL;
- break;
- case 32:
- mask = 0xffffffffLL;
- break;
- case 64:
- mask = 0xffffffffffffffffLL;
- break;
- }
- two31 = mask ^ (mask>>1);
-
- p = m->w-1;
- ad = m->sd;
- if(m->sd < 0)
- ad = -m->sd;
-
- // bad denominators
- if(ad == 0 || ad == 1 || ad == two31) {
- m->bad = 1;
- return;
- }
-
- t = two31;
- ad &= mask;
-
- anc = t - 1 - t%ad;
- anc &= mask;
-
- q1 = two31/anc;
- r1 = two31 - q1*anc;
- q1 &= mask;
- r1 &= mask;
-
- q2 = two31/ad;
- r2 = two31 - q2*ad;
- q2 &= mask;
- r2 &= mask;
-
- for(;;) {
- p++;
- q1 <<= 1;
- r1 <<= 1;
- q1 &= mask;
- r1 &= mask;
- if(r1 >= anc) {
- q1++;
- r1 -= anc;
- q1 &= mask;
- r1 &= mask;
- }
-
- q2 <<= 1;
- r2 <<= 1;
- q2 &= mask;
- r2 &= mask;
- if(r2 >= ad) {
- q2++;
- r2 -= ad;
- q2 &= mask;
- r2 &= mask;
- }
-
- delta = ad - r2;
- delta &= mask;
- if(q1 < delta || (q1 == delta && r1 == 0)) {
- continue;
- }
- break;
- }
-
- m->sm = q2+1;
- if(m->sm & two31)
- m->sm |= ~mask;
- m->s = p-m->w;
-}
-
-/*
- * magic number for unsigned division
- * see hacker's delight chapter 10
- */
-void
-umagic(Magic *m)
-{
- int p;
- uint64 nc, delta, q1, r1, q2, r2;
- uint64 mask, two31;
-
- m->bad = 0;
- m->ua = 0;
-
- switch(m->w) {
- default:
- m->bad = 1;
- return;
- case 8:
- mask = 0xffLL;
- break;
- case 16:
- mask = 0xffffLL;
- break;
- case 32:
- mask = 0xffffffffLL;
- break;
- case 64:
- mask = 0xffffffffffffffffLL;
- break;
- }
- two31 = mask ^ (mask>>1);
-
- m->ud &= mask;
- if(m->ud == 0 || m->ud == two31) {
- m->bad = 1;
- return;
- }
- nc = mask - (-m->ud&mask)%m->ud;
- p = m->w-1;
-
- q1 = two31/nc;
- r1 = two31 - q1*nc;
- q1 &= mask;
- r1 &= mask;
-
- q2 = (two31-1) / m->ud;
- r2 = (two31-1) - q2*m->ud;
- q2 &= mask;
- r2 &= mask;
-
- for(;;) {
- p++;
- if(r1 >= nc-r1) {
- q1 <<= 1;
- q1++;
- r1 <<= 1;
- r1 -= nc;
- } else {
- q1 <<= 1;
- r1 <<= 1;
- }
- q1 &= mask;
- r1 &= mask;
- if(r2+1 >= m->ud-r2) {
- if(q2 >= two31-1) {
- m->ua = 1;
- }
- q2 <<= 1;
- q2++;
- r2 <<= 1;
- r2++;
- r2 -= m->ud;
- } else {
- if(q2 >= two31) {
- m->ua = 1;
- }
- q2 <<= 1;
- r2 <<= 1;
- r2++;
- }
- q2 &= mask;
- r2 &= mask;
-
- delta = m->ud - 1 - r2;
- delta &= mask;
-
- if(p < m->w+m->w)
- if(q1 < delta || (q1 == delta && r1 == 0)) {
- continue;
- }
- break;
- }
- m->um = q2+1;
- m->s = p-m->w;
-}
-
-Sym*
-ngotype(Node *n)
-{
- if(n->sym != S && n->realtype != T)
- if(strncmp(n->sym->name, "autotmp_", 8) != 0)
- if(strncmp(n->sym->name, "statictmp_", 8) != 0)
- return typename(n->realtype)->left->sym;
-
- return S;
-}
-
-/*
- * Convert raw string to the prefix that will be used in the symbol table.
- * Invalid bytes turn into %xx. Right now the only bytes that need
- * escaping are %, ., and ", but we escape all control characters too.
- */
-static char*
-pathtoprefix(char *s)
-{
- static char hex[] = "0123456789abcdef";
- char *p, *r, *w;
- int n;
-
- // check for chars that need escaping
- n = 0;
- for(r=s; *r; r++)
- if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"')
- n++;
-
- // quick exit
- if(n == 0)
- return s;
-
- // escape
- p = mal((r-s)+1+2*n);
- for(r=s, w=p; *r; r++) {
- if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') {
- *w++ = '%';
- *w++ = hex[(*r>>4)&0xF];
- *w++ = hex[*r&0xF];
- } else
- *w++ = *r;
- }
- *w = '\0';
- return p;
-}
-
-Pkg*
-mkpkg(Strlit *path)
-{
- Pkg *p;
- int h;
-
- if(strlen(path->s) != path->len) {
- yyerror("import path contains NUL byte");
- errorexit();
- }
-
- h = stringhash(path->s) & (nelem(phash)-1);
- for(p=phash[h]; p; p=p->link)
- if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0)
- return p;
-
- p = mal(sizeof *p);
- p->path = path;
- p->prefix = pathtoprefix(path->s);
- p->link = phash[h];
- phash[h] = p;
- return p;
-}
-
-Strlit*
-strlit(char *s)
-{
- Strlit *t;
-
- t = mal(sizeof *t + strlen(s));
- strcpy(t->s, s);
- t->len = strlen(s);
- return t;
-}
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
deleted file mode 100644
index c2968c44b..000000000
--- a/src/cmd/gc/swt.c
+++ /dev/null
@@ -1,896 +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 "go.h"
-
-enum
-{
- Snorm = 0,
- Strue,
- Sfalse,
- Stype,
-
- Tdefault, // default case
- Texprconst, // normal constant case
- Texprvar, // normal variable case
- Ttypenil, // case nil
- Ttypeconst, // type hashes
- Ttypevar, // interface type
-
- Ncase = 4, // count needed to split
-};
-
-typedef struct Case Case;
-struct Case
-{
- Node* node; // points at case statement
- uint32 hash; // hash of a type switch
- uint8 type; // type of case
- uint8 diag; // suppress multiple diagnostics
- uint16 ordinal; // position in switch
- Case* link; // linked list to link
-};
-#define C ((Case*)nil)
-
-void
-dumpcase(Case *c0)
-{
- Case *c;
-
- for(c=c0; c!=C; c=c->link) {
- switch(c->type) {
- case Tdefault:
- print("case-default\n");
- print(" ord=%d\n", c->ordinal);
- break;
- case Texprconst:
- print("case-exprconst\n");
- print(" ord=%d\n", c->ordinal);
- break;
- case Texprvar:
- print("case-exprvar\n");
- print(" ord=%d\n", c->ordinal);
- print(" op=%O\n", c->node->left->op);
- break;
- case Ttypenil:
- print("case-typenil\n");
- print(" ord=%d\n", c->ordinal);
- break;
- case Ttypeconst:
- print("case-typeconst\n");
- print(" ord=%d\n", c->ordinal);
- print(" hash=%ux\n", c->hash);
- break;
- case Ttypevar:
- print("case-typevar\n");
- print(" ord=%d\n", c->ordinal);
- break;
- default:
- print("case-???\n");
- print(" ord=%d\n", c->ordinal);
- print(" op=%O\n", c->node->left->op);
- print(" hash=%ux\n", c->hash);
- break;
- }
- }
- print("\n");
-}
-
-static int
-ordlcmp(Case *c1, Case *c2)
-{
- // sort default first
- if(c1->type == Tdefault)
- return -1;
- if(c2->type == Tdefault)
- return +1;
-
- // sort nil second
- if(c1->type == Ttypenil)
- return -1;
- if(c2->type == Ttypenil)
- return +1;
-
- // sort by ordinal
- if(c1->ordinal > c2->ordinal)
- return +1;
- if(c1->ordinal < c2->ordinal)
- return -1;
- return 0;
-}
-
-static int
-exprcmp(Case *c1, Case *c2)
-{
- int ct, n;
- Node *n1, *n2;
-
- // sort non-constants last
- if(c1->type != Texprconst)
- return +1;
- if(c2->type != Texprconst)
- return -1;
-
- n1 = c1->node->left;
- n2 = c2->node->left;
-
- ct = n1->val.ctype;
- if(ct != n2->val.ctype) {
- // invalid program, but return a sort
- // order so that we can give a better
- // error later.
- return ct - n2->val.ctype;
- }
-
- // sort by constant value
- n = 0;
- switch(ct) {
- case CTFLT:
- n = mpcmpfltflt(n1->val.u.fval, n2->val.u.fval);
- break;
- case CTINT:
- n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval);
- break;
- case CTSTR:
- n = cmpslit(n1, n2);
- break;
- }
-
- return n;
-}
-
-static int
-typecmp(Case *c1, Case *c2)
-{
-
- // sort non-constants last
- if(c1->type != Ttypeconst)
- return +1;
- if(c2->type != Ttypeconst)
- return -1;
-
- // sort by hash code
- if(c1->hash > c2->hash)
- return +1;
- if(c1->hash < c2->hash)
- return -1;
-
- // sort by ordinal so duplicate error
- // happens on later case.
- if(c1->ordinal > c2->ordinal)
- return +1;
- if(c1->ordinal < c2->ordinal)
- return -1;
- return 0;
-}
-
-static Case*
-csort(Case *l, int(*f)(Case*, Case*))
-{
- Case *l1, *l2, *le;
-
- if(l == C || l->link == C)
- return l;
-
- l1 = l;
- l2 = l;
- for(;;) {
- l2 = l2->link;
- if(l2 == C)
- break;
- l2 = l2->link;
- if(l2 == C)
- break;
- l1 = l1->link;
- }
-
- l2 = l1->link;
- l1->link = C;
- l1 = csort(l, f);
- l2 = csort(l2, f);
-
- /* set up lead element */
- if((*f)(l1, l2) < 0) {
- l = l1;
- l1 = l1->link;
- } else {
- l = l2;
- l2 = l2->link;
- }
- le = l;
-
- for(;;) {
- if(l1 == C) {
- while(l2) {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- le->link = C;
- break;
- }
- if(l2 == C) {
- while(l1) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- }
- break;
- }
- if((*f)(l1, l2) < 0) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- } else {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- }
- le->link = C;
- return l;
-}
-
-static Node*
-newlabel(void)
-{
- static int label;
-
- label++;
- snprint(namebuf, sizeof(namebuf), "%.6d", label);
- return newname(lookup(namebuf));
-}
-
-/*
- * build separate list of statements and cases
- * make labels between cases and statements
- * deal with fallthrough, break, unreachable statements
- */
-static void
-casebody(Node *sw, Node *typeswvar)
-{
- Node *n, *c, *last;
- Node *def;
- NodeList *cas, *stat, *l, *lc;
- Node *go, *br;
- int32 lno, needvar;
-
- lno = setlineno(sw);
- if(sw->list == nil)
- return;
-
- cas = nil; // cases
- stat = nil; // statements
- def = N; // defaults
- br = nod(OBREAK, N, N);
-
- for(l=sw->list; l; l=l->next) {
- n = l->n;
- lno = setlineno(n);
- if(n->op != OXCASE)
- fatal("casebody %O", n->op);
- n->op = OCASE;
- needvar = count(n->list) != 1 || n->list->n->op == OLITERAL;
-
- go = nod(OGOTO, newlabel(), N);
- if(n->list == nil) {
- if(def != N)
- yyerror("more than one default case");
- // reuse original default case
- n->right = go;
- def = n;
- }
-
- if(n->list != nil && n->list->next == nil) {
- // one case - reuse OCASE node.
- c = n->list->n;
- n->left = c;
- n->right = go;
- n->list = nil;
- cas = list(cas, n);
- } else {
- // expand multi-valued cases
- for(lc=n->list; lc; lc=lc->next) {
- c = lc->n;
- cas = list(cas, nod(OCASE, c, go));
- }
- }
-
- stat = list(stat, nod(OLABEL, go->left, N));
- if(typeswvar && needvar && n->nname != N) {
- NodeList *l;
-
- l = list1(nod(ODCL, n->nname, N));
- l = list(l, nod(OAS, n->nname, typeswvar));
- typechecklist(l, Etop);
- stat = concat(stat, l);
- }
- stat = concat(stat, n->nbody);
-
- // botch - shouldnt fall thru declaration
- last = stat->end->n;
- if(last->op == OXFALL) {
- if(typeswvar) {
- setlineno(last);
- yyerror("cannot fallthrough in type switch");
- }
- last->op = OFALL;
- } else
- stat = list(stat, br);
- }
-
- stat = list(stat, br);
- if(def)
- cas = list(cas, def);
-
- sw->list = cas;
- sw->nbody = stat;
- lineno = lno;
-}
-
-static Case*
-mkcaselist(Node *sw, int arg)
-{
- Node *n;
- Case *c, *c1, *c2;
- NodeList *l;
- int ord;
-
- c = C;
- ord = 0;
-
- for(l=sw->list; l; l=l->next) {
- n = l->n;
- c1 = mal(sizeof(*c1));
- c1->link = c;
- c = c1;
-
- ord++;
- c->ordinal = ord;
- c->node = n;
-
- if(n->left == N) {
- c->type = Tdefault;
- continue;
- }
-
- switch(arg) {
- case Stype:
- c->hash = 0;
- if(n->left->op == OLITERAL) {
- c->type = Ttypenil;
- continue;
- }
- if(istype(n->left->type, TINTER)) {
- c->type = Ttypevar;
- continue;
- }
-
- c->hash = typehash(n->left->type);
- c->type = Ttypeconst;
- continue;
-
- case Snorm:
- case Strue:
- case Sfalse:
- c->type = Texprvar;
- switch(consttype(n->left)) {
- case CTFLT:
- case CTINT:
- case CTSTR:
- c->type = Texprconst;
- }
- continue;
- }
- }
-
- if(c == C)
- return C;
-
- // sort by value and diagnose duplicate cases
- switch(arg) {
- case Stype:
- c = csort(c, typecmp);
- for(c1=c; c1!=C; c1=c1->link) {
- for(c2=c1->link; c2!=C && c2->hash==c1->hash; c2=c2->link) {
- if(c1->type == Ttypenil || c1->type == Tdefault)
- break;
- if(c2->type == Ttypenil || c2->type == Tdefault)
- break;
- if(!eqtype(c1->node->left->type, c2->node->left->type))
- continue;
- yyerrorl(c2->node->lineno, "duplicate case in switch\n\tprevious case at %L", c1->node->lineno);
- }
- }
- break;
- case Snorm:
- case Strue:
- case Sfalse:
- c = csort(c, exprcmp);
- for(c1=c; c1->link!=C; c1=c1->link) {
- if(exprcmp(c1, c1->link) != 0)
- continue;
- setlineno(c1->link->node);
- yyerror("duplicate case in switch\n\tprevious case at %L", c1->node->lineno);
- }
- break;
- }
-
- // put list back in processing order
- c = csort(c, ordlcmp);
- return c;
-}
-
-static Node* exprname;
-
-static Node*
-exprbsw(Case *c0, int ncase, int arg)
-{
- NodeList *cas;
- Node *a, *n;
- Case *c;
- int i, half, lno;
-
- cas = nil;
- if(ncase < Ncase) {
- for(i=0; i<ncase; i++) {
- n = c0->node;
- lno = setlineno(n);
-
- switch(arg) {
- case Strue:
- a = nod(OIF, N, N);
- a->ntest = n->left; // if val
- a->nbody = list1(n->right); // then goto l
- break;
-
- case Sfalse:
- a = nod(OIF, N, N);
- a->ntest = nod(ONOT, n->left, N); // if !val
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right); // then goto l
- break;
-
- default:
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, exprname, n->left); // if name == val
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right); // then goto l
- break;
- }
-
- cas = list(cas, a);
- c0 = c0->link;
- lineno = lno;
- }
- return liststmt(cas);
- }
-
- // find the middle and recur
- c = c0;
- half = ncase>>1;
- for(i=1; i<half; i++)
- c = c->link;
- a = nod(OIF, N, N);
- a->ntest = nod(OLE, exprname, c->node->left);
- typecheck(&a->ntest, Erv);
- a->nbody = list1(exprbsw(c0, half, arg));
- a->nelse = list1(exprbsw(c->link, ncase-half, arg));
- return a;
-}
-
-/*
- * normal (expression) switch.
- * rebulid case statements into if .. goto
- */
-static void
-exprswitch(Node *sw)
-{
- Node *def;
- NodeList *cas;
- Node *a;
- Case *c0, *c, *c1;
- Type *t;
- int arg, ncase;
-
- casebody(sw, N);
-
- arg = Snorm;
- if(isconst(sw->ntest, CTBOOL)) {
- arg = Strue;
- if(sw->ntest->val.u.bval == 0)
- arg = Sfalse;
- }
- walkexpr(&sw->ntest, &sw->ninit);
- t = sw->type;
- if(t == T)
- return;
-
- /*
- * convert the switch into OIF statements
- */
- exprname = N;
- cas = nil;
- if(arg != Strue && arg != Sfalse) {
- exprname = nod(OXXX, N, N);
- tempname(exprname, sw->ntest->type);
- cas = list1(nod(OAS, exprname, sw->ntest));
- typechecklist(cas, Etop);
- }
-
- c0 = mkcaselist(sw, arg);
- if(c0 != C && c0->type == Tdefault) {
- def = c0->node->right;
- c0 = c0->link;
- } else {
- def = nod(OBREAK, N, N);
- }
-
-loop:
- if(c0 == C) {
- cas = list(cas, def);
- sw->nbody = concat(cas, sw->nbody);
- sw->list = nil;
- walkstmtlist(sw->nbody);
- return;
- }
-
- // deal with the variables one-at-a-time
- if(c0->type != Texprconst) {
- a = exprbsw(c0, 1, arg);
- cas = list(cas, a);
- c0 = c0->link;
- goto loop;
- }
-
- // do binary search on run of constants
- ncase = 1;
- for(c=c0; c->link!=C; c=c->link) {
- if(c->link->type != Texprconst)
- break;
- ncase++;
- }
-
- // break the chain at the count
- c1 = c->link;
- c->link = C;
-
- // sort and compile constants
- c0 = csort(c0, exprcmp);
- a = exprbsw(c0, ncase, arg);
- cas = list(cas, a);
-
- c0 = c1;
- goto loop;
-
-}
-
-static Node* hashname;
-static Node* facename;
-static Node* boolname;
-
-static Node*
-typeone(Node *t)
-{
- NodeList *init;
- Node *a, *b, *var;
-
- var = t->nname;
- init = nil;
- if(var == N) {
- typecheck(&nblank, Erv | Easgn);
- var = nblank;
- } else
- init = list1(nod(ODCL, var, N));
-
- a = nod(OAS2, N, N);
- a->list = list(list1(var), boolname); // var,bool =
- b = nod(ODOTTYPE, facename, N);
- b->type = t->left->type; // interface.(type)
- a->rlist = list1(b);
- typecheck(&a, Etop);
- init = list(init, a);
-
- b = nod(OIF, N, N);
- b->ntest = boolname;
- b->nbody = list1(t->right); // if bool { goto l }
- a = liststmt(list(init, b));
- return a;
-}
-
-static Node*
-typebsw(Case *c0, int ncase)
-{
- NodeList *cas;
- Node *a, *n;
- Case *c;
- int i, half;
-
- cas = nil;
-
- if(ncase < Ncase) {
- for(i=0; i<ncase; i++) {
- n = c0->node;
- if(c0->type != Ttypeconst)
- fatal("typebsw");
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, hashname, nodintconst(c0->hash));
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right);
- cas = list(cas, a);
- c0 = c0->link;
- }
- return liststmt(cas);
- }
-
- // find the middle and recur
- c = c0;
- half = ncase>>1;
- for(i=1; i<half; i++)
- c = c->link;
- a = nod(OIF, N, N);
- a->ntest = nod(OLE, hashname, nodintconst(c->hash));
- typecheck(&a->ntest, Erv);
- a->nbody = list1(typebsw(c0, half));
- a->nelse = list1(typebsw(c->link, ncase-half));
- return a;
-}
-
-/*
- * convert switch of the form
- * switch v := i.(type) { case t1: ..; case t2: ..; }
- * into if statements
- */
-static void
-typeswitch(Node *sw)
-{
- Node *def;
- NodeList *cas, *hash;
- Node *a, *n;
- Case *c, *c0, *c1;
- int ncase;
- Type *t;
- Val v;
-
- if(sw->ntest == nil)
- return;
- if(sw->ntest->right == nil) {
- setlineno(sw);
- yyerror("type switch must have an assignment");
- return;
- }
- walkexpr(&sw->ntest->right, &sw->ninit);
- if(!istype(sw->ntest->right->type, TINTER)) {
- yyerror("type switch must be on an interface");
- return;
- }
- cas = nil;
-
- /*
- * predeclare temporary variables
- * and the boolean var
- */
- facename = nod(OXXX, N, N);
- tempname(facename, sw->ntest->right->type);
- a = nod(OAS, facename, sw->ntest->right);
- typecheck(&a, Etop);
- cas = list(cas, a);
-
- casebody(sw, facename);
-
- boolname = nod(OXXX, N, N);
- tempname(boolname, types[TBOOL]);
- typecheck(&boolname, Erv);
-
- hashname = nod(OXXX, N, N);
- tempname(hashname, types[TUINT32]);
- typecheck(&hashname, Erv);
-
- t = sw->ntest->right->type;
- if(isnilinter(t))
- a = syslook("efacethash", 1);
- else
- a = syslook("ifacethash", 1);
- argtype(a, t);
- a = nod(OCALL, a, N);
- a->list = list1(facename);
- a = nod(OAS, hashname, a);
- typecheck(&a, Etop);
- cas = list(cas, a);
-
- c0 = mkcaselist(sw, Stype);
- if(c0 != C && c0->type == Tdefault) {
- def = c0->node->right;
- c0 = c0->link;
- } else {
- def = nod(OBREAK, N, N);
- }
-
- /*
- * insert if statement into each case block
- */
- for(c=c0; c!=C; c=c->link) {
- n = c->node;
- switch(c->type) {
-
- case Ttypenil:
- v.ctype = CTNIL;
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, facename, nodlit(v));
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right); // if i==nil { goto l }
- n->right = a;
- break;
-
- case Ttypevar:
- case Ttypeconst:
- n->right = typeone(n);
- break;
- }
- }
-
- /*
- * generate list of if statements, binary search for constant sequences
- */
- while(c0 != C) {
- if(c0->type != Ttypeconst) {
- n = c0->node;
- cas = list(cas, n->right);
- c0=c0->link;
- continue;
- }
-
- // identify run of constants
- c1 = c = c0;
- while(c->link!=C && c->link->type==Ttypeconst)
- c = c->link;
- c0 = c->link;
- c->link = nil;
-
- // sort by hash
- c1 = csort(c1, typecmp);
-
- // for debugging: linear search
- if(0) {
- for(c=c1; c!=C; c=c->link) {
- n = c->node;
- cas = list(cas, n->right);
- }
- continue;
- }
-
- // combine adjacent cases with the same hash
- ncase = 0;
- for(c=c1; c!=C; c=c->link) {
- ncase++;
- hash = list1(c->node->right);
- while(c->link != C && c->link->hash == c->hash) {
- hash = list(hash, c->link->node->right);
- c->link = c->link->link;
- }
- c->node->right = liststmt(hash);
- }
-
- // binary search among cases to narrow by hash
- cas = list(cas, typebsw(c1, ncase));
- }
- if(nerrors == 0) {
- cas = list(cas, def);
- sw->nbody = concat(cas, sw->nbody);
- sw->list = nil;
- walkstmtlist(sw->nbody);
- }
-}
-
-void
-walkswitch(Node *sw)
-{
-
- /*
- * reorder the body into (OLIST, cases, statements)
- * cases have OGOTO into statements.
- * both have inserted OBREAK statements
- */
- walkstmtlist(sw->ninit);
- if(sw->ntest == N) {
- sw->ntest = nodbool(1);
- typecheck(&sw->ntest, Erv);
- }
-
- if(sw->ntest->op == OTYPESW) {
- typeswitch(sw);
-//dump("sw", sw);
- return;
- }
- exprswitch(sw);
-}
-
-/*
- * type check switch statement
- */
-void
-typecheckswitch(Node *n)
-{
- int top, lno;
- Type *t;
- NodeList *l, *ll;
- Node *ncase, *nvar;
- Node *def;
-
- lno = lineno;
- typechecklist(n->ninit, Etop);
-
- if(n->ntest != N && n->ntest->op == OTYPESW) {
- // type switch
- top = Etype;
- typecheck(&n->ntest->right, Erv);
- t = n->ntest->right->type;
- if(t != T && t->etype != TINTER)
- yyerror("cannot type switch on non-interface value %+N", n->ntest->right);
- } else {
- // value switch
- top = Erv;
- if(n->ntest) {
- typecheck(&n->ntest, Erv);
- defaultlit(&n->ntest, T);
- t = n->ntest->type;
- } else
- t = types[TBOOL];
- }
- n->type = t;
-
- def = N;
- for(l=n->list; l; l=l->next) {
- ncase = l->n;
- setlineno(n);
- if(ncase->list == nil) {
- // default
- if(def != N)
- yyerror("multiple defaults in switch (first at %L)", def->lineno);
- else
- def = ncase;
- } else {
- for(ll=ncase->list; ll; ll=ll->next) {
- setlineno(ll->n);
- typecheck(&ll->n, Erv | Etype);
- if(ll->n->type == T || t == T)
- continue;
- switch(top) {
- case Erv: // expression switch
- defaultlit(&ll->n, t);
- if(ll->n->op == OTYPE)
- yyerror("type %T is not an expression", ll->n->type);
- else if(ll->n->type != T && !eqtype(ll->n->type, t))
- yyerror("case %+N in %T switch", ll->n, t);
- break;
- case Etype: // type switch
- if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL))
- ;
- else if(ll->n->op != OTYPE && ll->n->type != T) {
- yyerror("%#N is not a type", ll->n);
- // reset to original type
- ll->n = n->ntest->right;
- }
- break;
- }
- }
- }
- if(top == Etype && n->type != T) {
- ll = ncase->list;
- nvar = ncase->nname;
- if(nvar != N) {
- if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) {
- // single entry type switch
- nvar->ntype = typenod(ll->n->type);
- } else {
- // multiple entry type switch or default
- nvar->ntype = typenod(n->type);
- }
- }
- }
- typechecklist(ncase->nbody, Etop);
- }
-
- lineno = lno;
-}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
deleted file mode 100644
index dfe0f30f7..000000000
--- a/src/cmd/gc/typecheck.c
+++ /dev/null
@@ -1,2822 +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.
-
-/*
- * type check the whole tree of an expression.
- * calculates expression types.
- * evaluates compile time constants.
- * marks variables that escape the local frame.
- * rewrites n->op to be more specific in some cases.
- */
-
-#include "go.h"
-
-static void implicitstar(Node**);
-static int onearg(Node*, char*, ...);
-static int twoarg(Node*);
-static int lookdot(Node*, Type*, int);
-static int looktypedot(Node*, Type*, int);
-static void typecheckaste(int, Node*, int, Type*, NodeList*, char*);
-static Type* lookdot1(Sym *s, Type *t, Type *f, int);
-static int nokeys(NodeList*);
-static void typecheckcomplit(Node**);
-static void addrescapes(Node*);
-static void typecheckas2(Node*);
-static void typecheckas(Node*);
-static void typecheckfunc(Node*);
-static void checklvalue(Node*, char*);
-static void checkassign(Node*);
-static void checkassignlist(NodeList*);
-static void stringtoarraylit(Node**);
-static Node* resolve(Node*);
-static Type* getforwtype(Node*);
-
-static NodeList* typecheckdefstack;
-
-/*
- * resolve ONONAME to definition, if any.
- */
-Node*
-resolve(Node *n)
-{
- Node *r;
-
- if(n != N && n->op == ONONAME && (r = n->sym->def) != N) {
- if(r->op != OIOTA)
- n = r;
- else if(n->iota >= 0)
- n = nodintconst(n->iota);
- }
- return n;
-}
-
-void
-typechecklist(NodeList *l, int top)
-{
- for(; l; l=l->next)
- typecheck(&l->n, top);
-}
-
-static char* _typekind[] = {
- [TINT] = "int",
- [TUINT] = "uint",
- [TINT8] = "int8",
- [TUINT8] = "uint8",
- [TINT16] = "int16",
- [TUINT16] = "uint16",
- [TINT32] = "int32",
- [TUINT32] = "uint32",
- [TINT64] = "int64",
- [TUINT64] = "uint64",
- [TUINTPTR] = "uintptr",
- [TCOMPLEX64] = "complex64",
- [TCOMPLEX128] = "complex128",
- [TFLOAT32] = "float32",
- [TFLOAT64] = "float64",
- [TBOOL] = "bool",
- [TSTRING] = "string",
- [TPTR32] = "pointer",
- [TPTR64] = "pointer",
- [TSTRUCT] = "struct",
- [TINTER] = "interface",
- [TCHAN] = "chan",
- [TMAP] = "map",
- [TARRAY] = "array",
- [TFUNC] = "func",
- [TNIL] = "nil",
- [TIDEAL] = "ideal number",
-};
-
-static char*
-typekind(int et)
-{
- static char buf[50];
- char *s;
-
- if(0 <= et && et < nelem(_typekind) && (s=_typekind[et]) != nil)
- return s;
- snprint(buf, sizeof buf, "etype=%d", et);
- return buf;
-}
-
-/*
- * type check node *np.
- * replaces *np with a new pointer in some cases.
- * returns the final value of *np as a convenience.
- */
-Node*
-typecheck(Node **np, int top)
-{
- int et, aop, op, ptr;
- Node *n, *l, *r;
- NodeList *args;
- int lno, ok, ntop;
- Type *t, *tp, *ft, *missing, *have;
- Sym *sym;
- Val v;
- char *why;
-
- // cannot type check until all the source has been parsed
- if(!typecheckok)
- fatal("early typecheck");
-
- n = *np;
- if(n == N)
- return N;
-
- // Resolve definition of name and value of iota lazily.
- n = resolve(n);
- *np = n;
-
- // Skip typecheck if already done.
- // But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
- if(n->typecheck == 1) {
- switch(n->op) {
- case ONAME:
- case OTYPE:
- case OLITERAL:
- case OPACK:
- break;
- default:
- return n;
- }
- }
-
- if(n->typecheck == 2) {
- yyerror("typechecking loop");
- return n;
- }
- n->typecheck = 2;
-
- lno = setlineno(n);
- if(n->sym) {
- if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) {
- yyerror("use of builtin %S not in function call", n->sym);
- goto error;
- }
-
- // a dance to handle forward-declared recursive pointer types.
- if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T)
- defertypecopy(n, ft);
-
- typecheckdef(n);
- n->realtype = n->type;
- if(n->op == ONONAME)
- goto error;
- }
- *np = n;
-
-reswitch:
- ok = 0;
- switch(n->op) {
- default:
- // until typecheck is complete, do nothing.
- dump("typecheck", n);
- fatal("typecheck %O", n->op);
-
- /*
- * names
- */
- case OLITERAL:
- ok |= Erv;
- if(n->type == T && n->val.ctype == CTSTR)
- n->type = idealstring;
- goto ret;
-
- case ONONAME:
- ok |= Erv;
- goto ret;
-
- case ONAME:
- if(n->etype != 0) {
- ok |= Ecall;
- goto ret;
- }
- if(!(top & Easgn)) {
- // not a write to the variable
- if(isblank(n)) {
- yyerror("cannot use _ as value");
- goto error;
- }
- n->used = 1;
- }
- ok |= Erv;
- goto ret;
-
- case OPACK:
- yyerror("use of package %S not in selector", n->sym);
- goto error;
-
- case ODDD:
- break;
-
- /*
- * types (OIND is with exprs)
- */
- case OTYPE:
- ok |= Etype;
- if(n->type == T)
- goto error;
- break;
-
- case OTPAREN:
- ok |= Etype;
- l = typecheck(&n->left, Etype);
- if(l->type == T)
- goto error;
- n->op = OTYPE;
- n->type = l->type;
- n->left = N;
- break;
-
- case OTARRAY:
- ok |= Etype;
- t = typ(TARRAY);
- l = n->left;
- r = n->right;
- if(l == nil) {
- t->bound = -1; // slice
- } else if(l->op == ODDD) {
- t->bound = -100; // to be filled in
- } else {
- l = typecheck(&n->left, Erv);
- switch(consttype(l)) {
- case CTINT:
- v = l->val;
- break;
- case CTFLT:
- v = toint(l->val);
- break;
- default:
- yyerror("invalid array bound %#N", l);
- goto error;
- }
- t->bound = mpgetfix(v.u.xval);
- if(t->bound < 0) {
- yyerror("array bound must be non-negative");
- goto error;
- } else
- overflow(v, types[TINT]);
- }
- typecheck(&r, Etype);
- if(r->type == T)
- goto error;
- t->type = r->type;
- n->op = OTYPE;
- n->type = t;
- n->left = N;
- n->right = N;
- if(t->bound != -100)
- checkwidth(t);
- break;
-
- case OTMAP:
- ok |= Etype;
- l = typecheck(&n->left, Etype);
- r = typecheck(&n->right, Etype);
- if(l->type == T || r->type == T)
- goto error;
- n->op = OTYPE;
- n->type = maptype(l->type, r->type);
- n->left = N;
- n->right = N;
- break;
-
- case OTCHAN:
- ok |= Etype;
- l = typecheck(&n->left, Etype);
- if(l->type == T)
- goto error;
- t = typ(TCHAN);
- t->type = l->type;
- t->chan = n->etype;
- n->op = OTYPE;
- n->type = t;
- n->left = N;
- n->etype = 0;
- break;
-
- case OTSTRUCT:
- ok |= Etype;
- n->op = OTYPE;
- n->type = dostruct(n->list, TSTRUCT);
- if(n->type == T)
- goto error;
- n->list = nil;
- break;
-
- case OTINTER:
- ok |= Etype;
- n->op = OTYPE;
- n->type = dostruct(n->list, TINTER);
- if(n->type == T)
- goto error;
- break;
-
- case OTFUNC:
- ok |= Etype;
- n->op = OTYPE;
- n->type = functype(n->left, n->list, n->rlist);
- if(n->type == T)
- goto error;
- break;
-
- /*
- * type or expr
- */
- case OIND:
- ntop = Erv | Etype;
- if(!(top & Eaddr))
- ntop |= Eindir;
- l = typecheck(&n->left, ntop);
- if((t = l->type) == T)
- goto error;
- if(l->op == OTYPE) {
- ok |= Etype;
- n->op = OTYPE;
- n->type = ptrto(l->type);
- n->left = N;
- goto ret;
- }
- if(!isptr[t->etype]) {
- yyerror("invalid indirect of %+N", n->left);
- goto error;
- }
- ok |= Erv;
- n->type = t->type;
- goto ret;
-
- /*
- * arithmetic exprs
- */
- case OASOP:
- ok |= Etop;
- l = typecheck(&n->left, Erv);
- checkassign(n->left);
- r = typecheck(&n->right, Erv);
- if(l->type == T || r->type == T)
- goto error;
- op = n->etype;
- goto arith;
-
- case OADD:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLT:
- case OLSH:
- case ORSH:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case OOROR:
- case OSUB:
- case OXOR:
- ok |= Erv;
- l = typecheck(&n->left, Erv | (top & Eiota));
- r = typecheck(&n->right, Erv | (top & Eiota));
- if(l->type == T || r->type == T)
- goto error;
- op = n->op;
- arith:
- if(op == OLSH || op == ORSH)
- goto shift;
- // ideal mixed with non-ideal
- defaultlit2(&l, &r, 0);
- n->left = l;
- n->right = r;
- if(l->type == T || r->type == T)
- goto error;
- t = l->type;
- if(t->etype == TIDEAL)
- t = r->type;
- et = t->etype;
- if(et == TIDEAL)
- et = TINT;
- if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- // comparison is okay as long as one side is
- // assignable to the other. convert so they have
- // the same type. (the only conversion that isn't
- // a no-op is concrete == interface.)
- if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
- l = nod(aop, l, N);
- l->type = r->type;
- l->typecheck = 1;
- n->left = l;
- t = l->type;
- } else if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
- r = nod(aop, r, N);
- r->type = l->type;
- r->typecheck = 1;
- n->right = r;
- t = r->type;
- }
- et = t->etype;
- }
- if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- defaultlit2(&l, &r, 1);
- yyerror("invalid operation: %#N (mismatched types %T and %T)", n, l->type, r->type);
- goto error;
- }
- if(!okfor[op][et]) {
- notokfor:
- yyerror("invalid operation: %#N (operator %#O not defined on %s)", n, op, typekind(et));
- goto error;
- }
- // okfor allows any array == array;
- // restrict to slice == nil and nil == slice.
- if(l->type->etype == TARRAY && !isslice(l->type))
- goto notokfor;
- if(r->type->etype == TARRAY && !isslice(r->type))
- goto notokfor;
- if(isslice(l->type) && !isnil(l) && !isnil(r)) {
- yyerror("invalid operation: %#N (slice can only be compared to nil)", n);
- goto error;
- }
- t = l->type;
- if(iscmp[n->op]) {
- evconst(n);
- t = types[TBOOL];
- if(n->op != OLITERAL) {
- defaultlit2(&l, &r, 1);
- n->left = l;
- n->right = r;
- }
- }
- if(et == TSTRING) {
- if(iscmp[n->op]) {
- n->etype = n->op;
- n->op = OCMPSTR;
- } else if(n->op == OADD)
- n->op = OADDSTR;
- }
- if(et == TINTER) {
- if(l->op == OLITERAL && l->val.ctype == CTNIL) {
- // swap for back end
- n->left = r;
- n->right = l;
- } else if(r->op == OLITERAL && r->val.ctype == CTNIL) {
- // leave alone for back end
- } else {
- n->etype = n->op;
- n->op = OCMPIFACE;
- }
- }
- n->type = t;
- goto ret;
-
- shift:
- defaultlit(&r, types[TUINT]);
- n->right = r;
- t = r->type;
- if(!isint[t->etype] || issigned[t->etype]) {
- yyerror("invalid operation: %#N (shift count type %T, must be unsigned integer)", n, r->type);
- goto error;
- }
- t = l->type;
- if(t != T && t->etype != TIDEAL && !isint[t->etype]) {
- yyerror("invalid operation: %#N (shift of type %T)", n, t);
- goto error;
- }
- // no defaultlit for left
- // the outer context gives the type
- n->type = l->type;
- goto ret;
-
- case OCOM:
- case OMINUS:
- case ONOT:
- case OPLUS:
- ok |= Erv;
- l = typecheck(&n->left, Erv | (top & Eiota));
- if((t = l->type) == T)
- goto error;
- if(!okfor[n->op][t->etype]) {
- yyerror("invalid operation: %#O %T", n->op, t);
- goto error;
- }
- n->type = t;
- goto ret;
-
- /*
- * exprs
- */
- case OADDR:
- ok |= Erv;
- typecheck(&n->left, Erv | Eaddr);
- if(n->left->type == T)
- goto error;
- switch(n->left->op) {
- case OMAPLIT:
- case OSTRUCTLIT:
- case OARRAYLIT:
- break;
- default:
- checklvalue(n->left, "take the address of");
- }
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(!(top & Eindir) && !n->etype)
- addrescapes(n->left);
- n->type = ptrto(t);
- goto ret;
-
- case OCOMPLIT:
- ok |= Erv;
- typecheckcomplit(&n);
- if(n->type == T)
- goto error;
- goto ret;
-
- case OXDOT:
- n = adddot(n);
- n->op = ODOT;
- // fall through
- case ODOT:
- typecheck(&n->left, Erv|Etype);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(n->right->op != ONAME) {
- yyerror("rhs of . must be a name"); // impossible
- goto error;
- }
- sym = n->right->sym;
- if(l->op == OTYPE) {
- if(!looktypedot(n, t, 0)) {
- if(looktypedot(n, t, 1))
- yyerror("%#N undefined (cannot refer to unexported method %S)", n, n->right->sym);
- else
- yyerror("%#N undefined (type %T has no method %S)", n, t, n->right->sym);
- goto error;
- }
- if(n->type->etype != TFUNC || n->type->thistuple != 1) {
- yyerror("type %T has no method %hS", n->left->type, sym);
- n->type = T;
- goto error;
- }
- n->op = ONAME;
- n->sym = methodsym(sym, l->type, 0);
- n->type = methodfunc(n->type, l->type);
- n->xoffset = 0;
- n->class = PFUNC;
- ok = Erv;
- goto ret;
- }
- tp = t;
- if(isptr[t->etype] && t->type->etype != TINTER) {
- t = t->type;
- if(t == T)
- goto error;
- n->op = ODOTPTR;
- checkwidth(t);
- }
- if(!lookdot(n, t, 0)) {
- if(lookdot(n, t, 1))
- yyerror("%#N undefined (cannot refer to unexported field or method %S)", n, n->right->sym);
- else
- yyerror("%#N undefined (type %T has no field or method %S)", n, tp, n->right->sym);
- goto error;
- }
- switch(n->op) {
- case ODOTINTER:
- case ODOTMETH:
- ok |= Ecall;
- break;
- default:
- ok |= Erv;
- break;
- }
- goto ret;
-
- case ODOTTYPE:
- ok |= Erv;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(!isinter(t)) {
- yyerror("invalid type assertion: %#N (non-interface type %T on left)", n, t);
- goto error;
- }
- if(n->right != N) {
- typecheck(&n->right, Etype);
- n->type = n->right->type;
- n->right = N;
- if(n->type == T)
- goto error;
- }
- if(n->type != T && n->type->etype != TINTER)
- if(!implements(n->type, t, &missing, &have, &ptr)) {
- if(have)
- yyerror("impossible type assertion: %+N cannot have dynamic type %T"
- " (wrong type for %S method)\n\thave %S%hhT\n\twant %S%hhT",
- l, n->type, missing->sym, have->sym, have->type,
- missing->sym, missing->type);
- else
- yyerror("impossible type assertion: %+N cannot have dynamic type %T"
- " (missing %S method)", l, n->type, missing->sym);
- goto error;
- }
- goto ret;
-
- case OINDEX:
- ok |= Erv;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- implicitstar(&n->left);
- l = n->left;
- typecheck(&n->right, Erv);
- r = n->right;
- if((t = l->type) == T || r->type == T)
- goto error;
- switch(t->etype) {
- default:
- yyerror("invalid operation: %#N (index of type %T)", n, t);
- goto error;
-
- case TARRAY:
- defaultlit(&n->right, T);
- if(n->right->type != T && !isint[n->right->type->etype])
- yyerror("non-integer array index %#N", n->right);
- n->type = t->type;
- break;
-
- case TMAP:
- n->etype = 0;
- defaultlit(&n->right, t->down);
- if(n->right->type != T)
- n->right = assignconv(n->right, t->down, "map index");
- n->type = t->type;
- n->op = OINDEXMAP;
- break;
-
- case TSTRING:
- defaultlit(&n->right, types[TUINT]);
- if(n->right->type != T && !isint[n->right->type->etype])
- yyerror("non-integer string index %#N", n->right);
- n->type = types[TUINT8];
- break;
- }
- goto ret;
-
- case ORECV:
- ok |= Etop | Erv;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(t->etype != TCHAN) {
- yyerror("invalid operation: %#N (receive from non-chan type %T)", n, t);
- goto error;
- }
- if(!(t->chan & Crecv)) {
- yyerror("invalid operation: %#N (receive from send-only type %T)", n, t);
- goto error;
- }
- n->type = t->type;
- goto ret;
-
- case OSEND:
- if(top & Erv) {
- yyerror("send statement %#N used as value; use select for non-blocking send", n);
- goto error;
- }
- ok |= Etop | Erv;
- l = typecheck(&n->left, Erv);
- typecheck(&n->right, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(t->etype != TCHAN) {
- yyerror("invalid operation: %#N (send to non-chan type %T)", n, t);
- goto error;
- }
- if(!(t->chan & Csend)) {
- yyerror("invalid operation: %#N (send to receive-only type %T)", n, t);
- goto error;
- }
- defaultlit(&n->right, t->type);
- r = n->right;
- if((t = r->type) == T)
- goto error;
- r = assignconv(r, l->type->type, "send");
- // TODO: more aggressive
- n->etype = 0;
- n->type = T;
- goto ret;
-
- case OSLICE:
- ok |= Erv;
- typecheck(&n->left, top);
- typecheck(&n->right->left, Erv);
- typecheck(&n->right->right, Erv);
- defaultlit(&n->left, T);
- defaultlit(&n->right->left, T);
- defaultlit(&n->right->right, T);
- if(isfixedarray(n->left->type)) {
- n->left = nod(OADDR, n->left, N);
- typecheck(&n->left, top);
- }
- if(n->right->left != N) {
- if((t = n->right->left->type) == T)
- goto error;
- if(!isint[t->etype]) {
- yyerror("invalid slice index %#N (type %T)", n->right->left, t);
- goto error;
- }
- }
- if(n->right->right != N) {
- if((t = n->right->right->type) == T)
- goto error;
- if(!isint[t->etype]) {
- yyerror("invalid slice index %#N (type %T)", n->right->right, t);
- goto error;
- }
- }
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(istype(t, TSTRING)) {
- n->type = t;
- n->op = OSLICESTR;
- goto ret;
- }
- if(isptr[t->etype] && isfixedarray(t->type)) {
- n->type = typ(TARRAY);
- n->type->type = t->type->type;
- n->type->bound = -1;
- dowidth(n->type);
- n->op = OSLICEARR;
- goto ret;
- }
- if(isslice(t)) {
- n->type = t;
- goto ret;
- }
- yyerror("cannot slice %#N (type %T)", l, t);
- goto error;
-
- /*
- * call and call like
- */
- case OCALL:
- l = n->left;
- if(l->op == ONAME && (r = unsafenmagic(n)) != N) {
- if(n->isddd)
- yyerror("invalid use of ... with builtin %#N", l);
- n = r;
- goto reswitch;
- }
- typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc));
- l = n->left;
- if(l->op == ONAME && l->etype != 0) {
- if(n->isddd && l->etype != OAPPEND)
- yyerror("invalid use of ... with builtin %#N", l);
- // builtin: OLEN, OCAP, etc.
- n->op = l->etype;
- n->left = n->right;
- n->right = N;
- goto reswitch;
- }
- defaultlit(&n->left, T);
- l = n->left;
- if(l->op == OTYPE) {
- if(n->isddd || l->type->bound == -100)
- yyerror("invalid use of ... in type conversion", l);
- // pick off before type-checking arguments
- ok |= Erv;
- // turn CALL(type, arg) into CONV(arg) w/ type
- n->left = N;
- n->op = OCONV;
- n->type = l->type;
- if(onearg(n, "conversion to %T", l->type) < 0)
- goto error;
- goto doconv;
- }
-
- if(count(n->list) == 1)
- typecheck(&n->list->n, Erv | Efnstruct);
- else
- typechecklist(n->list, Erv);
- if((t = l->type) == T)
- goto error;
- checkwidth(t);
-
- switch(l->op) {
- case ODOTINTER:
- n->op = OCALLINTER;
- break;
-
- case ODOTMETH:
- n->op = OCALLMETH;
- // typecheckaste was used here but there wasn't enough
- // information further down the call chain to know if we
- // were testing a method receiver for unexported fields.
- // It isn't necessary, so just do a sanity check.
- tp = getthisx(t)->type->type;
- if(l->left == N || !eqtype(l->left->type, tp))
- fatal("method receiver");
- break;
-
- default:
- n->op = OCALLFUNC;
- if(t->etype != TFUNC) {
- yyerror("cannot call non-function %#N (type %T)", l, t);
- goto error;
- }
- break;
- }
- typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument");
- ok |= Etop;
- if(t->outtuple == 0)
- goto ret;
- ok |= Erv;
- if(t->outtuple == 1) {
- t = getoutargx(l->type)->type;
- if(t == T)
- goto error;
- if(t->etype == TFIELD)
- t = t->type;
- n->type = t;
- goto ret;
- }
- // multiple return
- if(!(top & (Efnstruct | Etop))) {
- yyerror("multiple-value %#N() in single-value context", l);
- goto ret;
- }
- n->type = getoutargx(l->type);
- goto ret;
-
- case OCAP:
- case OLEN:
- case OREAL:
- case OIMAG:
- ok |= Erv;
- if(onearg(n, "%#O", n->op) < 0)
- goto error;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- implicitstar(&n->left);
- l = n->left;
- t = l->type;
- if(t == T)
- goto error;
- switch(n->op) {
- case OCAP:
- if(!okforcap[t->etype])
- goto badcall1;
- break;
- case OLEN:
- if(!okforlen[t->etype])
- goto badcall1;
- break;
- case OREAL:
- case OIMAG:
- if(!iscomplex[t->etype])
- goto badcall1;
- if(isconst(l, CTCPLX)){
- if(n->op == OREAL)
- n = nodfltconst(&l->val.u.cval->real);
- else
- n = nodfltconst(&l->val.u.cval->imag);
- }
- n->type = types[cplxsubtype(t->etype)];
- goto ret;
- }
- // might be constant
- switch(t->etype) {
- case TSTRING:
- if(isconst(l, CTSTR)) {
- r = nod(OXXX, N, N);
- nodconst(r, types[TINT], l->val.u.sval->len);
- r->orig = n;
- n = r;
- }
- break;
- case TARRAY:
- if(t->bound >= 0 && l->op == ONAME) {
- r = nod(OXXX, N, N);
- nodconst(r, types[TINT], t->bound);
- r->orig = n;
- n = r;
- }
- break;
- }
- n->type = types[TINT];
- goto ret;
-
- case OCOMPLEX:
- ok |= Erv;
- if(twoarg(n) < 0)
- goto error;
- l = typecheck(&n->left, Erv | (top & Eiota));
- r = typecheck(&n->right, Erv | (top & Eiota));
- if(l->type == T || r->type == T)
- goto error;
- defaultlit2(&l, &r, 0);
- n->left = l;
- n->right = r;
- if(l->type->etype != r->type->etype) {
- badcmplx:
- yyerror("invalid operation: %#N (complex of types %T, %T)", n, l->type, r->type);
- goto error;
- }
- switch(l->type->etype) {
- default:
- goto badcmplx;
- case TIDEAL:
- t = types[TIDEAL];
- break;
- case TFLOAT32:
- t = types[TCOMPLEX64];
- break;
- case TFLOAT64:
- t = types[TCOMPLEX128];
- break;
- }
- if(l->op == OLITERAL && r->op == OLITERAL) {
- // make it a complex literal
- n = nodcplxlit(l->val, r->val);
- }
- n->type = t;
- goto ret;
-
- case OCLOSE:
- if(onearg(n, "%#O", n->op) < 0)
- goto error;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(t->etype != TCHAN) {
- yyerror("invalid operation: %#N (non-chan type %T)", n, t);
- goto error;
- }
- ok |= Etop;
- goto ret;
-
- case OAPPEND:
- ok |= Erv;
- args = n->list;
- if(args == nil) {
- yyerror("missing arguments to append");
- goto error;
- }
- typechecklist(args, Erv);
- if((t = args->n->type) == T)
- goto error;
- n->type = t;
- if(!isslice(t)) {
- yyerror("first argument to append must be slice; have %lT", t);
- goto error;
- }
- if(n->isddd) {
- if(args->next == nil) {
- yyerror("cannot use ... on first argument to append");
- goto error;
- }
- if(args->next->next != nil) {
- yyerror("too many arguments to append");
- goto error;
- }
- args->next->n = assignconv(args->next->n, t->orig, "append");
- goto ret;
- }
- for(args=args->next; args != nil; args=args->next) {
- if(args->n->type == T)
- continue;
- args->n = assignconv(args->n, t->type, "append");
- }
- goto ret;
-
- case OCOPY:
- ok |= Etop|Erv;
- args = n->list;
- if(args == nil || args->next == nil) {
- yyerror("missing arguments to copy");
- goto error;
- }
- if(args->next->next != nil) {
- yyerror("too many arguments to copy");
- goto error;
- }
- n->left = args->n;
- n->right = args->next->n;
- n->type = types[TINT];
- typecheck(&n->left, Erv);
- typecheck(&n->right, Erv);
- if(n->left->type == T || n->right->type == T)
- goto error;
- defaultlit(&n->left, T);
- defaultlit(&n->right, T);
-
- // copy([]byte, string)
- if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
- if (n->left->type->type == types[TUINT8])
- goto ret;
- yyerror("arguments to copy have different element types: %lT and string", n->left->type);
- goto error;
- }
-
- if(!isslice(n->left->type) || !isslice(n->right->type)) {
- if(!isslice(n->left->type) && !isslice(n->right->type))
- yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
- else if(!isslice(n->left->type))
- yyerror("first argument to copy should be slice; have %lT", n->left->type);
- else
- yyerror("second argument to copy should be slice or string; have %lT", n->right->type);
- goto error;
- }
- if(!eqtype(n->left->type->type, n->right->type->type)) {
- yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type);
- goto error;
- }
- goto ret;
-
- case OCONV:
- doconv:
- ok |= Erv;
- typecheck(&n->left, Erv | (top & (Eindir | Eiota)));
- convlit1(&n->left, n->type, 1);
- if((t = n->left->type) == T || n->type == T)
- goto error;
- if((n->op = convertop(t, n->type, &why)) == 0) {
- yyerror("cannot convert %+N to type %T%s", n->left, n->type, why);
- op = OCONV;
- }
- switch(n->op) {
- case OCONVNOP:
- if(n->left->op == OLITERAL) {
- n->op = OLITERAL;
- n->val = n->left->val;
- }
- break;
- case OSTRARRAYBYTE:
- case OSTRARRAYRUNE:
- if(n->left->op == OLITERAL)
- stringtoarraylit(&n);
- break;
- }
- goto ret;
-
- case OMAKE:
- ok |= Erv;
- args = n->list;
- if(args == nil) {
- yyerror("missing argument to make");
- goto error;
- }
- l = args->n;
- args = args->next;
- typecheck(&l, Etype);
- if((t = l->type) == T)
- goto error;
-
- switch(t->etype) {
- default:
- badmake:
- yyerror("cannot make type %T", t);
- goto error;
-
- case TARRAY:
- if(!isslice(t))
- goto badmake;
- if(args == nil) {
- yyerror("missing len argument to make(%T)", t);
- goto error;
- }
- l = args->n;
- args = args->next;
- typecheck(&l, Erv);
- defaultlit(&l, types[TINT]);
- r = N;
- if(args != nil) {
- r = args->n;
- args = args->next;
- typecheck(&r, Erv);
- defaultlit(&r, types[TINT]);
- }
- if(l->type == T || (r && r->type == T))
- goto error;
- if(!isint[l->type->etype]) {
- yyerror("non-integer len argument to make(%T)", t);
- goto error;
- }
- if(r && !isint[r->type->etype]) {
- yyerror("non-integer cap argument to make(%T)", t);
- goto error;
- }
- n->left = l;
- n->right = r;
- n->op = OMAKESLICE;
- break;
-
- case TMAP:
- if(args != nil) {
- l = args->n;
- args = args->next;
- typecheck(&l, Erv);
- defaultlit(&l, types[TINT]);
- if(l->type == T)
- goto error;
- if(!isint[l->type->etype]) {
- yyerror("non-integer size argument to make(%T)", t);
- goto error;
- }
- n->left = l;
- } else
- n->left = nodintconst(0);
- n->op = OMAKEMAP;
- break;
-
- case TCHAN:
- l = N;
- if(args != nil) {
- l = args->n;
- args = args->next;
- typecheck(&l, Erv);
- defaultlit(&l, types[TINT]);
- if(l->type == T)
- goto error;
- if(!isint[l->type->etype]) {
- yyerror("non-integer buffer argument to make(%T)", t);
- goto error;
- }
- n->left = l;
- } else
- n->left = nodintconst(0);
- n->op = OMAKECHAN;
- break;
- }
- if(args != nil) {
- yyerror("too many arguments to make(%T)", t);
- n->op = OMAKE;
- goto error;
- }
- n->type = t;
- goto ret;
-
- case ONEW:
- ok |= Erv;
- args = n->list;
- if(args == nil) {
- yyerror("missing argument to new");
- goto error;
- }
- l = args->n;
- typecheck(&l, Etype);
- if((t = l->type) == T)
- goto error;
- if(args->next != nil) {
- yyerror("too many arguments to new(%T)", t);
- goto error;
- }
- n->left = l;
- n->type = ptrto(t);
- goto ret;
-
- case OPRINT:
- case OPRINTN:
- ok |= Etop;
- typechecklist(n->list, Erv | Eindir); // Eindir: address does not escape
- goto ret;
-
- case OPANIC:
- ok |= Etop;
- if(onearg(n, "panic") < 0)
- goto error;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, types[TINTER]);
- if(n->left->type == T)
- goto error;
- goto ret;
-
- case ORECOVER:
- ok |= Erv|Etop;
- if(n->list != nil) {
- yyerror("too many arguments to recover");
- goto error;
- }
- n->type = types[TINTER];
- goto ret;
-
- case OCLOSURE:
- ok |= Erv;
- typecheckclosure(n, top);
- if(n->type == T)
- goto error;
- goto ret;
-
- /*
- * statements
- */
- case OAS:
- ok |= Etop;
- typecheckas(n);
- goto ret;
-
- case OAS2:
- ok |= Etop;
- typecheckas2(n);
- goto ret;
-
- case OBREAK:
- case OCONTINUE:
- case ODCL:
- case OEMPTY:
- case OGOTO:
- case OLABEL:
- case OXFALL:
- ok |= Etop;
- goto ret;
-
- case ODEFER:
- ok |= Etop;
- typecheck(&n->left, Etop);
- goto ret;
-
- case OPROC:
- ok |= Etop;
- typecheck(&n->left, Etop|Eproc);
- goto ret;
-
- case OFOR:
- ok |= Etop;
- typechecklist(n->ninit, Etop);
- typecheck(&n->ntest, Erv);
- if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
- yyerror("non-bool %+N used as for condition", n->ntest);
- typecheck(&n->nincr, Etop);
- typechecklist(n->nbody, Etop);
- goto ret;
-
- case OIF:
- ok |= Etop;
- typechecklist(n->ninit, Etop);
- typecheck(&n->ntest, Erv);
- if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
- yyerror("non-bool %+N used as if condition", n->ntest);
- typechecklist(n->nbody, Etop);
- typechecklist(n->nelse, Etop);
- goto ret;
-
- case ORETURN:
- ok |= Etop;
- typechecklist(n->list, Erv | Efnstruct);
- if(curfn == N) {
- yyerror("return outside function");
- goto error;
- }
- if(curfn->type->outnamed && n->list == nil)
- goto ret;
- typecheckaste(ORETURN, nil, 0, getoutargx(curfn->type), n->list, "return argument");
- goto ret;
-
- case OSELECT:
- ok |= Etop;
- typecheckselect(n);
- goto ret;
-
- case OSWITCH:
- ok |= Etop;
- typecheckswitch(n);
- goto ret;
-
- case ORANGE:
- ok |= Etop;
- typecheckrange(n);
- goto ret;
-
- case OTYPESW:
- yyerror("use of .(type) outside type switch");
- goto error;
-
- case OXCASE:
- ok |= Etop;
- typechecklist(n->list, Erv);
- typechecklist(n->nbody, Etop);
- goto ret;
-
- case ODCLFUNC:
- ok |= Etop;
- typecheckfunc(n);
- goto ret;
-
- case ODCLCONST:
- ok |= Etop;
- typecheck(&n->left, Erv);
- goto ret;
-
- case ODCLTYPE:
- ok |= Etop;
- typecheck(&n->left, Etype);
- if(!incannedimport)
- checkwidth(n->left->type);
- goto ret;
- }
-
-ret:
- t = n->type;
- if(t && !t->funarg && n->op != OTYPE) {
- switch(t->etype) {
- case TFUNC: // might have TANY; wait until its called
- case TANY:
- case TFORW:
- case TIDEAL:
- case TNIL:
- case TBLANK:
- break;
- case TARRAY:
- if(t->bound == -100) {
- yyerror("use of [...] array outside of array literal");
- t->bound = 1;
- }
- default:
- checkwidth(t);
- }
- }
-
- // TODO(rsc): should not need to check importpkg,
- // but reflect mentions unsafe.Pointer.
- if(safemode && !incannedimport && !importpkg && t && t->etype == TUNSAFEPTR)
- yyerror("cannot use unsafe.Pointer");
-
- evconst(n);
- if(n->op == OTYPE && !(top & Etype)) {
- yyerror("type %T is not an expression", n->type);
- goto error;
- }
- if((top & (Erv|Etype)) == Etype && n->op != OTYPE) {
- yyerror("%#N is not a type", n);
- goto error;
- }
- if((ok & Ecall) && !(top & Ecall)) {
- yyerror("method %#N is not an expression, must be called", n);
- goto error;
- }
- // TODO(rsc): simplify
- if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
- yyerror("%#N used as value", n);
- goto error;
- }
- if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
- if(n->diag == 0) {
- yyerror("%#N not used", n);
- n->diag = 1;
- }
- goto error;
- }
-
- /* TODO
- if(n->type == T)
- fatal("typecheck nil type");
- */
- goto out;
-
-badcall1:
- yyerror("invalid argument %#N (type %T) for %#O", n->left, n->left->type, n->op);
- goto error;
-
-error:
- n->type = T;
-
-out:
- lineno = lno;
- n->typecheck = 1;
- *np = n;
- return n;
-}
-
-static void
-implicitstar(Node **nn)
-{
- Type *t;
- Node *n;
-
- // insert implicit * if needed for fixed array
- n = *nn;
- t = n->type;
- if(t == T || !isptr[t->etype])
- return;
- t = t->type;
- if(t == T)
- return;
- if(!isfixedarray(t))
- return;
- n = nod(OIND, n, N);
- typecheck(&n, Erv);
- *nn = n;
-}
-
-static int
-onearg(Node *n, char *f, ...)
-{
- va_list arg;
- char *p;
-
- if(n->left != N)
- return 0;
- if(n->list == nil) {
- va_start(arg, f);
- p = vsmprint(f, arg);
- va_end(arg);
- yyerror("missing argument to %s: %#N", p, n);
- return -1;
- }
- if(n->list->next != nil) {
- va_start(arg, f);
- p = vsmprint(f, arg);
- va_end(arg);
- yyerror("too many arguments to %s: %#N", p, n);
- n->left = n->list->n;
- n->list = nil;
- return -1;
- }
- n->left = n->list->n;
- n->list = nil;
- return 0;
-}
-
-static int
-twoarg(Node *n)
-{
- if(n->left != N)
- return 0;
- if(n->list == nil) {
- yyerror("missing argument to %#O - %#N", n->op, n);
- return -1;
- }
- n->left = n->list->n;
- if(n->list->next == nil) {
- yyerror("missing argument to %#O - %#N", n->op, n);
- n->list = nil;
- return -1;
- }
- if(n->list->next->next != nil) {
- yyerror("too many arguments to %#O - %#N", n->op, n);
- n->list = nil;
- return -1;
- }
- n->right = n->list->next->n;
- n->list = nil;
- return 0;
-}
-
-static Type*
-lookdot1(Sym *s, Type *t, Type *f, int dostrcmp)
-{
- Type *r;
-
- r = T;
- for(; f!=T; f=f->down) {
- if(dostrcmp && strcmp(f->sym->name, s->name) == 0)
- return f;
- if(f->sym != s)
- continue;
- if(r != T) {
- yyerror("ambiguous DOT reference %T.%S", t, s);
- break;
- }
- r = f;
- }
- return r;
-}
-
-static int
-looktypedot(Node *n, Type *t, int dostrcmp)
-{
- Type *f1, *f2, *tt;
- Sym *s;
-
- s = n->right->sym;
-
- if(t->etype == TINTER) {
- f1 = lookdot1(s, t, t->type, dostrcmp);
- if(f1 == T)
- return 0;
-
- if(f1->width == BADWIDTH)
- fatal("lookdot badwidth %T %p", f1, f1);
- n->right = methodname(n->right, t);
- n->xoffset = f1->width;
- n->type = f1->type;
- n->op = ODOTINTER;
- return 1;
- }
-
- tt = t;
- if(t->sym == S && isptr[t->etype])
- tt = t->type;
-
- f2 = methtype(tt);
- if(f2 == T)
- return 0;
-
- expandmeth(f2->sym, f2);
- f2 = lookdot1(s, f2, f2->xmethod, dostrcmp);
- if(f2 == T)
- return 0;
-
- // disallow T.m if m requires *T receiver
- if(isptr[getthisx(f2->type)->type->type->etype]
- && !isptr[t->etype]
- && f2->embedded != 2
- && !isifacemethod(f2->type)) {
- yyerror("invalid method expression %#N (needs pointer receiver: (*%T).%s)", n, t, f2->sym->name);
- return 0;
- }
-
- n->right = methodname(n->right, t);
- n->xoffset = f2->width;
- n->type = f2->type;
- n->op = ODOTMETH;
- return 1;
-}
-
-static int
-lookdot(Node *n, Type *t, int dostrcmp)
-{
- Type *f1, *f2, *tt, *rcvr;
- Sym *s;
-
- s = n->right->sym;
-
- dowidth(t);
- f1 = T;
- if(t->etype == TSTRUCT || t->etype == TINTER)
- f1 = lookdot1(s, t, t->type, dostrcmp);
-
- f2 = T;
- if(n->left->type == t || n->left->type->sym == S) {
- f2 = methtype(t);
- if(f2 != T) {
- // Use f2->method, not f2->xmethod: adddot has
- // already inserted all the necessary embedded dots.
- f2 = lookdot1(s, f2, f2->method, dostrcmp);
- }
- }
-
- if(f1 != T) {
- if(f2 != T)
- yyerror("ambiguous DOT reference %S as both field and method",
- n->right->sym);
- if(f1->width == BADWIDTH)
- fatal("lookdot badwidth %T %p", f1, f1);
- n->xoffset = f1->width;
- n->type = f1->type;
- if(t->etype == TINTER) {
- if(isptr[n->left->type->etype]) {
- n->left = nod(OIND, n->left, N); // implicitstar
- typecheck(&n->left, Erv);
- }
- n->op = ODOTINTER;
- }
- return 1;
- }
-
- if(f2 != T) {
- tt = n->left->type;
- dowidth(tt);
- rcvr = getthisx(f2->type)->type->type;
- if(!eqtype(rcvr, tt)) {
- if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
- checklvalue(n->left, "call pointer method on");
- addrescapes(n->left);
- n->left = nod(OADDR, n->left, N);
- n->left->implicit = 1;
- typecheck(&n->left, Etype|Erv);
- } else if(tt->etype == tptr && eqtype(tt->type, rcvr)) {
- n->left = nod(OIND, n->left, N);
- n->left->implicit = 1;
- typecheck(&n->left, Etype|Erv);
- } else {
- // method is attached to wrong type?
- fatal("method mismatch: %T for %T", rcvr, tt);
- }
- }
- n->right = methodname(n->right, n->left->type);
- n->xoffset = f2->width;
- n->type = f2->type;
- n->op = ODOTMETH;
- return 1;
- }
-
- return 0;
-}
-
-static int
-nokeys(NodeList *l)
-{
- for(; l; l=l->next)
- if(l->n->op == OKEY)
- return 0;
- return 1;
-}
-
-/*
- * typecheck assignment: type list = expression list
- */
-static void
-typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *desc)
-{
- Type *t, *tl, *tn;
- Node *n;
- int lno;
- char *why;
-
- lno = lineno;
-
- if(tstruct->broke)
- goto out;
-
- if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
- if(n->type->etype == TSTRUCT && n->type->funarg) {
- tn = n->type->type;
- for(tl=tstruct->type; tl; tl=tl->down) {
- if(tl->isddd) {
- for(; tn; tn=tn->down) {
- exportassignok(tn->type, desc);
- if(assignop(tn->type, tl->type->type, &why) == 0) {
- if(call != N)
- yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type->type, call, why);
- else
- yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
- }
- }
- goto out;
- }
- if(tn == T)
- goto notenough;
- exportassignok(tn->type, desc);
- if(assignop(tn->type, tl->type, &why) == 0) {
- if(call != N)
- yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type, call, why);
- else
- yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
- }
- tn = tn->down;
- }
- if(tn != T)
- goto toomany;
- goto out;
- }
-
- for(tl=tstruct->type; tl; tl=tl->down) {
- t = tl->type;
- if(tl->isddd) {
- if(isddd) {
- if(nl == nil)
- goto notenough;
- if(nl->next != nil)
- goto toomany;
- n = nl->n;
- setlineno(n);
- if(n->type != T)
- nl->n = assignconv(n, t, desc);
- goto out;
- }
- for(; nl; nl=nl->next) {
- n = nl->n;
- setlineno(nl->n);
- if(n->type != T)
- nl->n = assignconv(n, t->type, desc);
- }
- goto out;
- }
- if(nl == nil)
- goto notenough;
- n = nl->n;
- setlineno(n);
- if(n->type != T)
- nl->n = assignconv(n, t, desc);
- nl = nl->next;
- }
- if(nl != nil)
- goto toomany;
- if(isddd) {
- if(call != N)
- yyerror("invalid use of ... in call to %#N", call);
- else
- yyerror("invalid use of ... in %#O", op);
- }
-
-out:
- lineno = lno;
- return;
-
-notenough:
- if(call != N)
- yyerror("not enough arguments in call to %#N", call);
- else
- yyerror("not enough arguments to %#O", op);
- goto out;
-
-toomany:
- if(call != N)
- yyerror("too many arguments in call to %#N", call);
- else
- yyerror("too many arguments to %#O", op);
- goto out;
-}
-
-/*
- * do the export rules allow writing to this type?
- * cannot be implicitly assigning to any type with
- * an unavailable field.
- */
-int
-exportassignok(Type *t, char *desc)
-{
- Type *f;
- Sym *s;
-
- if(t == T)
- return 1;
- if(t->trecur)
- return 1;
- t->trecur = 1;
-
- switch(t->etype) {
- default:
- // most types can't contain others; they're all fine.
- break;
- case TSTRUCT:
- for(f=t->type; f; f=f->down) {
- if(f->etype != TFIELD)
- fatal("structas: not field");
- s = f->sym;
- // s == nil doesn't happen for embedded fields (they get the type symbol).
- // it only happens for fields in a ... struct.
- if(s != nil && !exportname(s->name) && s->pkg != localpkg) {
- char *prefix;
-
- prefix = "";
- if(desc != nil)
- prefix = " in ";
- else
- desc = "";
- yyerror("implicit assignment of unexported field '%s' of %T%s%s", s->name, t, prefix, desc);
- goto no;
- }
- if(!exportassignok(f->type, desc))
- goto no;
- }
- break;
-
- case TARRAY:
- if(t->bound < 0) // slices are pointers; that's fine
- break;
- if(!exportassignok(t->type, desc))
- goto no;
- break;
- }
- t->trecur = 0;
- return 1;
-
-no:
- t->trecur = 0;
- return 0;
-}
-
-
-/*
- * type check composite
- */
-
-static void
-fielddup(Node *n, Node *hash[], ulong nhash)
-{
- uint h;
- char *s;
- Node *a;
-
- if(n->op != ONAME)
- fatal("fielddup: not ONAME");
- s = n->sym->name;
- h = stringhash(s)%nhash;
- for(a=hash[h]; a!=N; a=a->ntest) {
- if(strcmp(a->sym->name, s) == 0) {
- yyerror("duplicate field name in struct literal: %s", s);
- return;
- }
- }
- n->ntest = hash[h];
- hash[h] = n;
-}
-
-static void
-keydup(Node *n, Node *hash[], ulong nhash)
-{
- uint h;
- ulong b;
- double d;
- int i;
- Node *a;
- Node cmp;
- char *s;
-
- evconst(n);
- if(n->op != OLITERAL)
- return; // we dont check variables
-
- switch(n->val.ctype) {
- default: // unknown, bool, nil
- b = 23;
- break;
- case CTINT:
- b = mpgetfix(n->val.u.xval);
- break;
- case CTFLT:
- d = mpgetflt(n->val.u.fval);
- s = (char*)&d;
- b = 0;
- for(i=sizeof(d); i>0; i--)
- b = b*PRIME1 + *s++;
- break;
- case CTSTR:
- b = 0;
- s = n->val.u.sval->s;
- for(i=n->val.u.sval->len; i>0; i--)
- b = b*PRIME1 + *s++;
- break;
- }
-
- h = b%nhash;
- memset(&cmp, 0, sizeof(cmp));
- for(a=hash[h]; a!=N; a=a->ntest) {
- cmp.op = OEQ;
- cmp.left = n;
- cmp.right = a;
- evconst(&cmp);
- b = cmp.val.u.bval;
- if(b) {
- // too lazy to print the literal
- yyerror("duplicate key in map literal");
- return;
- }
- }
- n->ntest = hash[h];
- hash[h] = n;
-}
-
-static void
-indexdup(Node *n, Node *hash[], ulong nhash)
-{
- uint h;
- Node *a;
- ulong b, c;
-
- if(n->op != OLITERAL)
- fatal("indexdup: not OLITERAL");
-
- b = mpgetfix(n->val.u.xval);
- h = b%nhash;
- for(a=hash[h]; a!=N; a=a->ntest) {
- c = mpgetfix(a->val.u.xval);
- if(b == c) {
- yyerror("duplicate index in array literal: %ld", b);
- return;
- }
- }
- n->ntest = hash[h];
- hash[h] = n;
-}
-
-static int
-prime(ulong h, ulong sr)
-{
- ulong n;
-
- for(n=3; n<=sr; n+=2)
- if(h%n == 0)
- return 0;
- return 1;
-}
-
-static ulong
-inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash)
-{
- ulong h, sr;
- NodeList *ll;
- int i;
-
- // count the number of entries
- h = 0;
- for(ll=n->list; ll; ll=ll->next)
- h++;
-
- // if the auto hash table is
- // large enough use it.
- if(h <= nautohash) {
- *hash = autohash;
- memset(*hash, 0, nautohash * sizeof(**hash));
- return nautohash;
- }
-
- // make hash size odd and 12% larger than entries
- h += h/8;
- h |= 1;
-
- // calculate sqrt of h
- sr = h/2;
- for(i=0; i<5; i++)
- sr = (sr + h/sr)/2;
-
- // check for primeality
- while(!prime(h, sr))
- h += 2;
-
- // build and return a throw-away hash table
- *hash = mal(h * sizeof(**hash));
- memset(*hash, 0, h * sizeof(**hash));
- return h;
-}
-
-static void
-typecheckcomplit(Node **np)
-{
- int bad, i, len, nerr;
- Node *l, *n, **hash;
- NodeList *ll;
- Type *t, *f, *pushtype;
- Sym *s;
- int32 lno;
- ulong nhash;
- Node *autohash[101];
-
- n = *np;
- lno = lineno;
-
- if(n->right == N) {
- if(n->list != nil)
- setlineno(n->list->n);
- yyerror("missing type in composite literal");
- goto error;
- }
-
- setlineno(n->right);
- l = typecheck(&n->right /* sic */, Etype);
- if((t = l->type) == T)
- goto error;
- nerr = nerrors;
-
- // can omit type on composite literal values if the outer
- // composite literal is array, slice, or map, and the
- // element type is itself a struct, array, slice, or map.
- pushtype = T;
- if(t->etype == TARRAY || t->etype == TMAP) {
- pushtype = t->type;
- if(pushtype != T) {
- switch(pushtype->etype) {
- case TSTRUCT:
- case TARRAY:
- case TMAP:
- break;
- default:
- pushtype = T;
- break;
- }
- }
- }
-
- switch(t->etype) {
- default:
- yyerror("invalid type for composite literal: %T", t);
- n->type = T;
- break;
-
- case TARRAY:
- nhash = inithash(n, &hash, autohash, nelem(autohash));
-
- len = 0;
- i = 0;
- for(ll=n->list; ll; ll=ll->next) {
- l = ll->n;
- setlineno(l);
- if(l->op != OKEY) {
- l = nod(OKEY, nodintconst(i), l);
- l->left->type = types[TINT];
- l->left->typecheck = 1;
- ll->n = l;
- }
-
- typecheck(&l->left, Erv);
- evconst(l->left);
- i = nonnegconst(l->left);
- if(i < 0) {
- yyerror("array index must be non-negative integer constant");
- i = -(1<<30); // stay negative for a while
- }
- if(i >= 0)
- indexdup(l->left, hash, nhash);
- i++;
- if(i > len) {
- len = i;
- if(t->bound >= 0 && len > t->bound) {
- setlineno(l);
- yyerror("array index %d out of bounds [0:%d]", len, t->bound);
- t->bound = -1; // no more errors
- }
- }
-
- if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T)
- l->right->right = typenod(pushtype);
- typecheck(&l->right, Erv);
- defaultlit(&l->right, t->type);
- l->right = assignconv(l->right, t->type, "array index");
- }
- if(t->bound == -100)
- t->bound = len;
- if(t->bound < 0)
- n->right = nodintconst(len);
- n->op = OARRAYLIT;
- break;
-
- case TMAP:
- nhash = inithash(n, &hash, autohash, nelem(autohash));
-
- for(ll=n->list; ll; ll=ll->next) {
- l = ll->n;
- setlineno(l);
- if(l->op != OKEY) {
- typecheck(&ll->n, Erv);
- yyerror("missing key in map literal");
- continue;
- }
-
- typecheck(&l->left, Erv);
- defaultlit(&l->left, t->down);
- l->left = assignconv(l->left, t->down, "map key");
- keydup(l->left, hash, nhash);
-
- if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T)
- l->right->right = typenod(pushtype);
- typecheck(&l->right, Erv);
- defaultlit(&l->right, t->type);
- l->right = assignconv(l->right, t->type, "map value");
- }
- n->op = OMAPLIT;
- break;
-
- case TSTRUCT:
- bad = 0;
- if(n->list != nil && nokeys(n->list)) {
- // simple list of variables
- f = t->type;
- for(ll=n->list; ll; ll=ll->next) {
- setlineno(ll->n);
- typecheck(&ll->n, Erv);
- if(f == nil) {
- if(!bad++)
- yyerror("too many values in struct initializer");
- continue;
- }
- s = f->sym;
- if(s != nil && !exportname(s->name) && s->pkg != localpkg)
- yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t);
- ll->n = assignconv(ll->n, f->type, "field value");
- ll->n = nod(OKEY, newname(f->sym), ll->n);
- ll->n->left->typecheck = 1;
- f = f->down;
- }
- if(f != nil)
- yyerror("too few values in struct initializer");
- } else {
- nhash = inithash(n, &hash, autohash, nelem(autohash));
-
- // keyed list
- for(ll=n->list; ll; ll=ll->next) {
- l = ll->n;
- setlineno(l);
- if(l->op != OKEY) {
- if(!bad++)
- yyerror("mixture of field:value and value initializers");
- typecheck(&ll->n, Erv);
- continue;
- }
- s = l->left->sym;
- if(s == S) {
- yyerror("invalid field name %#N in struct initializer", l->left);
- typecheck(&l->right, Erv);
- continue;
- }
- // Sym might have resolved to name in other top-level
- // package, because of import dot. Redirect to correct sym
- // before we do the lookup.
- if(s->pkg != localpkg)
- s = lookup(s->name);
- l->left = newname(s);
- l->left->typecheck = 1;
- f = lookdot1(s, t, t->type, 0);
- typecheck(&l->right, Erv);
- if(f == nil) {
- yyerror("unknown %T field '%s' in struct literal", t, s->name);
- continue;
- }
- s = f->sym;
- fielddup(newname(s), hash, nhash);
- l->right = assignconv(l->right, f->type, "field value");
- }
- }
- n->op = OSTRUCTLIT;
- break;
- }
- if(nerr != nerrors)
- goto error;
- n->type = t;
-
- *np = n;
- lineno = lno;
- return;
-
-error:
- n->type = T;
- *np = n;
- lineno = lno;
-}
-
-/*
- * the address of n has been taken and might be used after
- * the current function returns. mark any local vars
- * as needing to move to the heap.
- */
-static void
-addrescapes(Node *n)
-{
- char buf[100];
- switch(n->op) {
- default:
- // probably a type error already.
- // dump("addrescapes", n);
- break;
-
- case ONAME:
- if(n->noescape)
- break;
- switch(n->class) {
- case PPARAMREF:
- addrescapes(n->defn);
- break;
- case PPARAM:
- case PPARAMOUT:
- // if func param, need separate temporary
- // to hold heap pointer.
- // the function type has already been checked
- // (we're in the function body)
- // so the param already has a valid xoffset.
-
- // expression to refer to stack copy
- n->stackparam = nod(OPARAM, n, N);
- n->stackparam->type = n->type;
- n->stackparam->addable = 1;
- if(n->xoffset == BADWIDTH)
- fatal("addrescapes before param assignment");
- n->stackparam->xoffset = n->xoffset;
- n->xoffset = 0;
- // fallthrough
- case PAUTO:
-
- n->class |= PHEAP;
- n->addable = 0;
- n->ullman = 2;
- n->xoffset = 0;
-
- // create stack variable to hold pointer to heap
- n->heapaddr = nod(ONAME, N, N);
- n->heapaddr->type = ptrto(n->type);
- snprint(buf, sizeof buf, "&%S", n->sym);
- n->heapaddr->sym = lookup(buf);
- n->heapaddr->class = PHEAP-1; // defer tempname to allocparams
- n->heapaddr->ullman = 1;
- n->curfn->dcl = list(n->curfn->dcl, n->heapaddr);
-
- break;
- }
- break;
-
- case OIND:
- case ODOTPTR:
- break;
-
- case ODOT:
- case OINDEX:
- // ODOTPTR has already been introduced,
- // so these are the non-pointer ODOT and OINDEX.
- // In &x[0], if x is a slice, then x does not
- // escape--the pointer inside x does, but that
- // is always a heap pointer anyway.
- if(!isslice(n->left->type))
- addrescapes(n->left);
- break;
- }
-}
-
-/*
- * lvalue etc
- */
-int
-islvalue(Node *n)
-{
- switch(n->op) {
- case OINDEX:
- if(isfixedarray(n->left->type))
- return islvalue(n->left);
- if(n->left->type != T && n->left->type->etype == TSTRING)
- return 0;
- // fall through
- case OIND:
- case ODOTPTR:
- return 1;
- case ODOT:
- return islvalue(n->left);
- case ONAME:
- if(n->class == PFUNC)
- return 0;
- return 1;
- }
- return 0;
-}
-
-static void
-checklvalue(Node *n, char *verb)
-{
- if(!islvalue(n))
- yyerror("cannot %s %#N", verb, n);
-}
-
-static void
-checkassign(Node *n)
-{
- if(islvalue(n))
- return;
- if(n->op == OINDEXMAP) {
- n->etype = 1;
- return;
- }
- yyerror("cannot assign to %#N", n);
-}
-
-static void
-checkassignlist(NodeList *l)
-{
- for(; l; l=l->next)
- checkassign(l->n);
-}
-
-/*
- * type check assignment.
- * if this assignment is the definition of a var on the left side,
- * fill in the var's type.
- */
-
-static void
-typecheckas(Node *n)
-{
- // delicate little dance.
- // the definition of n may refer to this assignment
- // as its definition, in which case it will call typecheckas.
- // in that case, do not call typecheck back, or it will cycle.
- // if the variable has a type (ntype) then typechecking
- // will not look at defn, so it is okay (and desirable,
- // so that the conversion below happens).
- n->left = resolve(n->left);
- if(n->left->defn != n || n->left->ntype)
- typecheck(&n->left, Erv | Easgn);
-
- checkassign(n->left);
- typecheck(&n->right, Erv);
- if(n->right && n->right->type != T) {
- if(n->left->type != T)
- n->right = assignconv(n->right, n->left->type, "assignment");
- else if(!isblank(n->left))
- exportassignok(n->right->type, "assignment");
- }
- if(n->left->defn == n && n->left->ntype == N) {
- defaultlit(&n->right, T);
- n->left->type = n->right->type;
- }
-
- // second half of dance.
- // now that right is done, typecheck the left
- // just to get it over with. see dance above.
- n->typecheck = 1;
- if(n->left->typecheck == 0)
- typecheck(&n->left, Erv | Easgn);
-}
-
-static void
-checkassignto(Type *src, Node *dst)
-{
- char *why;
-
- if(assignop(src, dst->type, &why) == 0) {
- yyerror("cannot assign %T to %+N in multiple assignment%s", src, dst, why);
- return;
- }
- exportassignok(dst->type, "multiple assignment");
-}
-
-static void
-typecheckas2(Node *n)
-{
- int cl, cr;
- NodeList *ll, *lr;
- Node *l, *r;
- Iter s;
- Type *t;
-
- for(ll=n->list; ll; ll=ll->next) {
- // delicate little dance.
- ll->n = resolve(ll->n);
- if(ll->n->defn != n || ll->n->ntype)
- typecheck(&ll->n, Erv | Easgn);
- }
- cl = count(n->list);
- cr = count(n->rlist);
- checkassignlist(n->list);
- if(cl > 1 && cr == 1)
- typecheck(&n->rlist->n, Erv | Efnstruct);
- else
- typechecklist(n->rlist, Erv);
-
- if(cl == cr) {
- // easy
- for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) {
- if(ll->n->type != T && lr->n->type != T)
- lr->n = assignconv(lr->n, ll->n->type, "assignment");
- if(ll->n->defn == n && ll->n->ntype == N) {
- defaultlit(&lr->n, T);
- ll->n->type = lr->n->type;
- }
- }
- goto out;
- }
-
-
- l = n->list->n;
- r = n->rlist->n;
-
- // m[i] = x, ok
- if(cl == 1 && cr == 2 && l->op == OINDEXMAP) {
- if(l->type == T)
- goto out;
- n->op = OAS2MAPW;
- n->rlist->n = assignconv(r, l->type, "assignment");
- r = n->rlist->next->n;
- n->rlist->next->n = assignconv(r, types[TBOOL], "assignment");
- goto out;
- }
-
- // x,y,z = f()
- if(cr == 1) {
- if(r->type == T)
- goto out;
- switch(r->op) {
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- if(r->type->etype != TSTRUCT || r->type->funarg == 0)
- break;
- cr = structcount(r->type);
- if(cr != cl)
- goto mismatch;
- n->op = OAS2FUNC;
- t = structfirst(&s, &r->type);
- for(ll=n->list; ll; ll=ll->next) {
- if(ll->n->type != T)
- checkassignto(t->type, ll->n);
- if(ll->n->defn == n && ll->n->ntype == N)
- ll->n->type = t->type;
- t = structnext(&s);
- }
- goto out;
- }
- }
-
- // x, ok = y
- if(cl == 2 && cr == 1) {
- if(r->type == T)
- goto out;
- switch(r->op) {
- case OINDEXMAP:
- n->op = OAS2MAPR;
- goto common;
- case ORECV:
- n->op = OAS2RECV;
- n->right = n->rlist->n;
- goto common;
- case ODOTTYPE:
- n->op = OAS2DOTTYPE;
- r->op = ODOTTYPE2;
- common:
- if(l->type != T)
- checkassignto(r->type, l);
- if(l->defn == n)
- l->type = r->type;
- l = n->list->next->n;
- if(l->type != T)
- checkassignto(types[TBOOL], l);
- if(l->defn == n && l->ntype == N)
- l->type = types[TBOOL];
- goto out;
- }
- }
-
-mismatch:
- yyerror("assignment count mismatch: %d = %d", cl, cr);
-
-out:
- // second half of dance
- n->typecheck = 1;
- for(ll=n->list; ll; ll=ll->next)
- if(ll->n->typecheck == 0)
- typecheck(&ll->n, Erv | Easgn);
-}
-
-/*
- * type check function definition
- */
-static void
-typecheckfunc(Node *n)
-{
- Type *t, *rcvr;
-
-//dump("nname", n->nname);
- typecheck(&n->nname, Erv | Easgn);
- if((t = n->nname->type) == T)
- return;
- n->type = t;
-
- rcvr = getthisx(t)->type;
- if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
- addmethod(n->shortname->sym, t, 1);
-}
-
-static void
-stringtoarraylit(Node **np)
-{
- int32 i;
- NodeList *l;
- Strlit *s;
- char *p, *ep;
- Rune r;
- Node *nn, *n;
-
- n = *np;
- if(n->left->op != OLITERAL || n->left->val.ctype != CTSTR)
- fatal("stringtoarraylit %N", n);
-
- s = n->left->val.u.sval;
- l = nil;
- p = s->s;
- ep = s->s + s->len;
- i = 0;
- if(n->type->type->etype == TUINT8) {
- // raw []byte
- while(p < ep)
- l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++)));
- } else {
- // utf-8 []int
- while(p < ep) {
- p += chartorune(&r, p);
- l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r)));
- }
- }
- nn = nod(OCOMPLIT, N, typenod(n->type));
- nn->list = l;
- typecheck(&nn, Erv);
- *np = nn;
-}
-
-static Type*
-getforwtype(Node *n)
-{
- Node *f1, *f2;
-
- for(f1=f2=n; ; n=n->ntype) {
- if((n = resolve(n)) == N || n->op != OTYPE)
- return T;
-
- if(n->type != T && n->type->etype == TFORW)
- return n->type;
-
- // Check for ntype cycle.
- if((f2 = resolve(f2)) != N && (f1 = resolve(f2->ntype)) != N) {
- f2 = resolve(f1->ntype);
- if(f1 == n || f2 == n)
- return T;
- }
- }
-}
-
-static int ntypecheckdeftype;
-static NodeList *methodqueue;
-
-static void
-domethod(Node *n)
-{
- Node *nt;
-
- nt = n->type->nname;
- typecheck(&nt, Etype);
- if(nt->type == T) {
- // type check failed; leave empty func
- n->type->etype = TFUNC;
- n->type->nod = N;
- return;
- }
- *n->type = *nt->type;
- n->type->nod = N;
- checkwidth(n->type);
-}
-
-typedef struct NodeTypeList NodeTypeList;
-struct NodeTypeList {
- Node *n;
- Type *t;
- NodeTypeList *next;
-};
-
-static NodeTypeList *dntq;
-static NodeTypeList *dntend;
-
-void
-defertypecopy(Node *n, Type *t)
-{
- NodeTypeList *ntl;
-
- if(n == N || t == T)
- return;
-
- ntl = mal(sizeof *ntl);
- ntl->n = n;
- ntl->t = t;
- ntl->next = nil;
-
- if(dntq == nil)
- dntq = ntl;
- else
- dntend->next = ntl;
-
- dntend = ntl;
-}
-
-void
-resumetypecopy(void)
-{
- NodeTypeList *l;
-
- for(l=dntq; l; l=l->next)
- copytype(l->n, l->t);
-}
-
-void
-copytype(Node *n, Type *t)
-{
- *n->type = *t;
-
- t = n->type;
- t->sym = n->sym;
- t->local = n->local;
- t->vargen = n->vargen;
- t->siggen = 0;
- t->method = nil;
- t->nod = N;
- t->printed = 0;
- t->deferwidth = 0;
-}
-
-static void
-typecheckdeftype(Node *n)
-{
- int maplineno, embedlineno, lno;
- Type *t;
- NodeList *l;
-
- ntypecheckdeftype++;
- lno = lineno;
- setlineno(n);
- n->type->sym = n->sym;
- n->typecheck = 1;
- typecheck(&n->ntype, Etype);
- if((t = n->ntype->type) == T) {
- n->diag = 1;
- goto ret;
- }
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
-
- maplineno = n->type->maplineno;
- embedlineno = n->type->embedlineno;
-
- // copy new type and clear fields
- // that don't come along.
- // anything zeroed here must be zeroed in
- // typedcl2 too.
- copytype(n, t);
-
- // double-check use of type as map key.
- if(maplineno) {
- lineno = maplineno;
- maptype(n->type, types[TBOOL]);
- }
- if(embedlineno) {
- lineno = embedlineno;
- if(isptr[t->etype])
- yyerror("embedded type cannot be a pointer");
- }
-
-ret:
- lineno = lno;
-
- // if there are no type definitions going on, it's safe to
- // try to resolve the method types for the interfaces
- // we just read.
- if(ntypecheckdeftype == 1) {
- while((l = methodqueue) != nil) {
- methodqueue = nil;
- for(; l; l=l->next)
- domethod(l->n);
- }
- }
- ntypecheckdeftype--;
-}
-
-void
-queuemethod(Node *n)
-{
- if(ntypecheckdeftype == 0) {
- domethod(n);
- return;
- }
- methodqueue = list(methodqueue, n);
-}
-
-Node*
-typecheckdef(Node *n)
-{
- int lno;
- Node *e;
- Type *t;
- NodeList *l;
-
- lno = lineno;
- setlineno(n);
-
- if(n->op == ONONAME) {
- if(!n->diag) {
- n->diag = 1;
- if(n->lineno != 0)
- lineno = n->lineno;
- yyerror("undefined: %S", n->sym);
- }
- return n;
- }
-
- if(n->walkdef == 1)
- return n;
-
- l = mal(sizeof *l);
- l->n = n;
- l->next = typecheckdefstack;
- typecheckdefstack = l;
-
- if(n->walkdef == 2) {
- flusherrors();
- print("typecheckdef loop:");
- for(l=typecheckdefstack; l; l=l->next)
- print(" %S", l->n->sym);
- print("\n");
- fatal("typecheckdef loop");
- }
- n->walkdef = 2;
-
- if(n->type != T || n->sym == S) // builtin or no name
- goto ret;
-
- switch(n->op) {
- default:
- fatal("typecheckdef %O", n->op);
-
- case OGOTO:
- case OLABEL:
- // not really syms
- break;
-
- case OLITERAL:
- if(n->ntype != N) {
- typecheck(&n->ntype, Etype);
- n->type = n->ntype->type;
- n->ntype = N;
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
- }
- e = n->defn;
- n->defn = N;
- if(e == N) {
- lineno = n->lineno;
- dump("typecheckdef nil defn", n);
- yyerror("xxx");
- }
- typecheck(&e, Erv | Eiota);
- if(e->type != T && e->op != OLITERAL) {
- yyerror("const initializer must be constant");
- goto ret;
- }
- if(isconst(e, CTNIL)) {
- yyerror("const initializer cannot be nil");
- goto ret;
- }
- t = n->type;
- if(t != T) {
- if(!okforconst[t->etype]) {
- yyerror("invalid constant type %T", t);
- goto ret;
- }
- if(!isideal(e->type) && !eqtype(t, e->type)) {
- yyerror("cannot use %+N as type %T in const initializer", e, t);
- goto ret;
- }
- convlit(&e, t);
- }
- n->val = e->val;
- n->type = e->type;
- break;
-
- case ONAME:
- if(n->ntype != N) {
- typecheck(&n->ntype, Etype);
- n->type = n->ntype->type;
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
- }
- if(n->type != T)
- break;
- if(n->defn == N) {
- if(n->etype != 0) // like OPRINTN
- break;
- if(nsavederrors+nerrors > 0) {
- // Can have undefined variables in x := foo
- // that make x have an n->ndefn == nil.
- // If there are other errors anyway, don't
- // bother adding to the noise.
- break;
- }
- fatal("var without type, init: %S", n->sym);
- }
- if(n->defn->op == ONAME) {
- typecheck(&n->defn, Erv);
- n->type = n->defn->type;
- break;
- }
- typecheck(&n->defn, Etop); // fills in n->type
- break;
-
- case OTYPE:
- if(curfn)
- defercheckwidth();
- n->walkdef = 1;
- n->type = typ(TFORW);
- n->type->sym = n->sym;
- typecheckdeftype(n);
- if(curfn)
- resumecheckwidth();
- break;
-
- case OPACK:
- // nothing to see here
- break;
- }
-
-ret:
- if(typecheckdefstack->n != n)
- fatal("typecheckdefstack mismatch");
- l = typecheckdefstack;
- typecheckdefstack = l->next;
-
- lineno = lno;
- n->walkdef = 1;
- return n;
-}
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
deleted file mode 100644
index d304077c8..000000000
--- a/src/cmd/gc/unsafe.c
+++ /dev/null
@@ -1,97 +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 "go.h"
-
-/*
- * look for
- * unsafe.Sizeof
- * unsafe.Offsetof
- * rewrite with a constant
- */
-Node*
-unsafenmagic(Node *nn)
-{
- Node *r, *n;
- Sym *s;
- Type *t, *tr;
- long v;
- Val val;
- Node *fn;
- NodeList *args;
-
- fn = nn->left;
- args = nn->list;
-
- if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S)
- goto no;
- if(s->pkg != unsafepkg)
- goto no;
-
- if(args == nil) {
- yyerror("missing argument for %S", s);
- goto no;
- }
- r = args->n;
-
- if(strcmp(s->name, "Sizeof") == 0) {
- typecheck(&r, Erv);
- defaultlit(&r, T);
- tr = r->type;
- if(tr == T)
- goto bad;
- dowidth(tr);
- v = tr->width;
- goto yes;
- }
- if(strcmp(s->name, "Offsetof") == 0) {
- typecheck(&r, Erv);
- if(r->op != ODOT && r->op != ODOTPTR)
- goto bad;
- typecheck(&r, Erv);
- v = r->xoffset;
- goto yes;
- }
- if(strcmp(s->name, "Alignof") == 0) {
- typecheck(&r, Erv);
- defaultlit(&r, T);
- tr = r->type;
- if(tr == T)
- goto bad;
-
- // make struct { byte; T; }
- t = typ(TSTRUCT);
- t->type = typ(TFIELD);
- t->type->type = types[TUINT8];
- t->type->down = typ(TFIELD);
- t->type->down->type = tr;
- // compute struct widths
- dowidth(t);
-
- // the offset of T is its required alignment
- v = t->type->down->width;
- goto yes;
- }
-
-no:
- return N;
-
-bad:
- yyerror("invalid expression %#N", nn);
- v = 0;
- goto ret;
-
-yes:
- if(args->next != nil)
- yyerror("extra arguments for %S", s);
-ret:
- // any side effects disappear; ignore init
- val.ctype = CTINT;
- val.u.xval = mal(sizeof(*n->val.u.xval));
- mpmovecfix(val.u.xval, v);
- n = nod(OLITERAL, N, N);
- n->val = val;
- n->type = types[TUINTPTR];
- return n;
-}
diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go
deleted file mode 100644
index db27d7425..000000000
--- a/src/cmd/gc/unsafe.go
+++ /dev/null
@@ -1,22 +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.
-
-// NOTE: If you change this file you must run "./mkbuiltin"
-// to update builtin.c.boot. This is not done automatically
-// to avoid depending on having a working compiler binary.
-
-package PACKAGE
-
-type Pointer uintptr // not really; filled in by compiler
-
-// return types here are ignored; see unsafe.c
-func Offsetof(any) uintptr
-func Sizeof(any) uintptr
-func Alignof(any) uintptr
-
-func Typeof(i interface{}) (typ interface{})
-func Reflect(i interface{}) (typ interface{}, addr Pointer)
-func Unreflect(typ interface{}, addr Pointer) (ret interface{})
-func New(typ interface{}) Pointer
-func NewArray(typ interface{}, n int) Pointer
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
deleted file mode 100644
index c9ca9b3b3..000000000
--- a/src/cmd/gc/walk.c
+++ /dev/null
@@ -1,2177 +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 "go.h"
-
-static Node* walkprint(Node*, NodeList**, int);
-static Node* conv(Node*, Type*);
-static Node* mapfn(char*, Type*);
-static Node* makenewvar(Type*, NodeList**, Node**);
-static Node* ascompatee1(int, Node*, Node*, NodeList**);
-static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
-static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
-static NodeList* ascompatte(int, int, Type**, NodeList*, int, NodeList**);
-static Node* convas(Node*, NodeList**);
-static void heapmoves(void);
-static NodeList* paramstoheap(Type **argin, int out);
-static NodeList* reorder1(NodeList*);
-static NodeList* reorder3(NodeList*);
-static Node* addstr(Node*, NodeList**);
-static Node* appendslice(Node*, NodeList**);
-static Node* append(Node*, NodeList**);
-
-// can this code branch reach the end
-// without an unconditional RETURN
-// this is hard, so it is conservative
-static int
-walkret(NodeList *l)
-{
- Node *n;
-
-loop:
- while(l && l->next)
- l = l->next;
- if(l == nil)
- return 1;
-
- // at this point, we have the last
- // statement of the function
- n = l->n;
- switch(n->op) {
- case OBLOCK:
- l = n->list;
- goto loop;
-
- case OGOTO:
- case ORETURN:
- case OPANIC:
- return 0;
- break;
- }
-
- // all other statements
- // will flow to the end
- return 1;
-}
-
-void
-walk(Node *fn)
-{
- char s[50];
- NodeList *l;
- Node *n;
- int lno;
-
- curfn = fn;
-
- if(debug['W']) {
- snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym);
- dumplist(s, curfn->nbody);
- }
- if(curfn->type->outtuple)
- if(walkret(curfn->nbody))
- yyerror("function ends without a return statement");
-
- lno = lineno;
- for(l=fn->dcl; l; l=l->next) {
- n = l->n;
- if(n->op != ONAME || n->class != PAUTO)
- continue;
- lineno = n->lineno;
- typecheck(&n, Erv | Easgn); // only needed for unused variables
- if(!n->used && n->sym->name[0] != '&' && !nsyntaxerrors)
- yyerror("%S declared and not used", n->sym);
- }
- lineno = lno;
- if(nerrors != 0)
- return;
- walkstmtlist(curfn->nbody);
- if(debug['W']) {
- snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
- dumplist(s, curfn->nbody);
- }
- heapmoves();
- if(debug['W'] && curfn->enter != nil) {
- snprint(s, sizeof(s), "enter %S", curfn->nname->sym);
- dumplist(s, curfn->enter);
- }
-}
-
-
-void
-walkstmtlist(NodeList *l)
-{
- for(; l; l=l->next)
- walkstmt(&l->n);
-}
-
-static int
-samelist(NodeList *a, NodeList *b)
-{
- for(; a && b; a=a->next, b=b->next)
- if(a->n != b->n)
- return 0;
- return a == b;
-}
-
-static int
-paramoutheap(Node *fn)
-{
- NodeList *l;
-
- for(l=fn->dcl; l; l=l->next) {
- switch(l->n->class) {
- case PPARAMOUT|PHEAP:
- return 1;
- case PAUTO:
- case PAUTO|PHEAP:
- // stop early - parameters are over
- return 0;
- }
- }
- return 0;
-}
-
-void
-walkstmt(Node **np)
-{
- NodeList *init;
- NodeList *ll, *rl;
- int cl;
- Node *n, *f;
-
- n = *np;
- if(n == N)
- return;
-
- setlineno(n);
-
- switch(n->op) {
- default:
- if(n->op == ONAME)
- yyerror("%S is not a top level statement", n->sym);
- else
- yyerror("%O is not a top level statement", n->op);
- dump("nottop", n);
- break;
-
- case OASOP:
- case OAS:
- case OAS2:
- case OAS2DOTTYPE:
- case OAS2RECV:
- case OAS2FUNC:
- case OAS2MAPW:
- case OAS2MAPR:
- case OCLOSE:
- case OCOPY:
- case OCALLMETH:
- case OCALLINTER:
- case OCALL:
- case OCALLFUNC:
- case OSEND:
- case ORECV:
- case OPRINT:
- case OPRINTN:
- case OPANIC:
- case OEMPTY:
- case ORECOVER:
- if(n->typecheck == 0) {
- dump("missing typecheck:", n);
- fatal("missing typecheck");
- }
- init = n->ninit;
- n->ninit = nil;
- walkexpr(&n, &init);
- n->ninit = concat(init, n->ninit);
- break;
-
- case OBREAK:
- case ODCL:
- case OCONTINUE:
- case OFALL:
- case OGOTO:
- case OLABEL:
- case ODCLCONST:
- case ODCLTYPE:
- break;
-
- case OBLOCK:
- walkstmtlist(n->list);
- break;
-
- case OXCASE:
- yyerror("case statement out of place");
- n->op = OCASE;
- case OCASE:
- walkstmt(&n->right);
- break;
-
- case ODEFER:
- hasdefer = 1;
- switch(n->left->op) {
- case OPRINT:
- case OPRINTN:
- walkexprlist(n->left->list, &n->ninit);
- n->left = walkprint(n->left, &n->ninit, 1);
- break;
- default:
- walkexpr(&n->left, &n->ninit);
- break;
- }
- break;
-
- case OFOR:
- walkstmtlist(n->ninit);
- if(n->ntest != N) {
- walkstmtlist(n->ntest->ninit);
- init = n->ntest->ninit;
- n->ntest->ninit = nil;
- walkexpr(&n->ntest, &init);
- n->ntest->ninit = concat(init, n->ntest->ninit);
- }
- walkstmt(&n->nincr);
- walkstmtlist(n->nbody);
- break;
-
- case OIF:
- walkstmtlist(n->ninit);
- walkexpr(&n->ntest, &n->ninit);
- walkstmtlist(n->nbody);
- walkstmtlist(n->nelse);
- break;
-
- case OPROC:
- switch(n->left->op) {
- case OPRINT:
- case OPRINTN:
- walkexprlist(n->left->list, &n->ninit);
- n->left = walkprint(n->left, &n->ninit, 1);
- break;
- default:
- walkexpr(&n->left, &n->ninit);
- break;
- }
- break;
-
- case ORETURN:
- walkexprlist(n->list, &n->ninit);
- if(n->list == nil)
- break;
- if((curfn->type->outnamed && count(n->list) > 1) || paramoutheap(curfn)) {
- // assign to the function out parameters,
- // so that reorder3 can fix up conflicts
- rl = nil;
- for(ll=curfn->dcl; ll != nil; ll=ll->next) {
- cl = ll->n->class & ~PHEAP;
- if(cl == PAUTO)
- break;
- if(cl == PPARAMOUT)
- rl = list(rl, ll->n);
- }
- if(samelist(rl, n->list)) {
- // special return in disguise
- n->list = nil;
- break;
- }
- if(count(n->list) == 1 && count(rl) > 1) {
- // OAS2FUNC in disguise
- f = n->list->n;
- if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER)
- fatal("expected return of call, have %#N", f);
- n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit));
- break;
- }
- ll = ascompatee(n->op, rl, n->list, &n->ninit);
- n->list = reorder3(ll);
- break;
- }
- ll = ascompatte(n->op, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
- n->list = ll;
- break;
-
- case OSELECT:
- walkselect(n);
- break;
-
- case OSWITCH:
- walkswitch(n);
- break;
-
- case ORANGE:
- walkrange(n);
- break;
-
- case OXFALL:
- yyerror("fallthrough statement out of place");
- n->op = OFALL;
- break;
- }
-
- *np = n;
-}
-
-
-/*
- * walk the whole tree of the body of an
- * expression or simple statement.
- * the types expressions are calculated.
- * compile-time constants are evaluated.
- * complex side effects like statements are appended to init
- */
-
-void
-walkexprlist(NodeList *l, NodeList **init)
-{
- for(; l; l=l->next)
- walkexpr(&l->n, init);
-}
-
-void
-walkexprlistsafe(NodeList *l, NodeList **init)
-{
- for(; l; l=l->next) {
- l->n = safeexpr(l->n, init);
- walkexpr(&l->n, init);
- }
-}
-
-void
-walkexpr(Node **np, NodeList **init)
-{
- Node *r, *l, *var, *a;
- NodeList *ll, *lr, *lpost;
- Type *t;
- int et;
- int64 v, v1, v2, len;
- int32 lno;
- Node *n, *fn;
- char buf[100], *p;
-
- n = *np;
-
- if(n == N)
- return;
-
- if(init == &n->ninit) {
- // not okay to use n->ninit when walking n,
- // because we might replace n with some other node
- // and would lose the init list.
- fatal("walkexpr init == &n->ninit");
- }
-
- // annoying case - not typechecked
- if(n->op == OKEY) {
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- return;
- }
-
- lno = setlineno(n);
-
- if(debug['w'] > 1)
- dump("walk-before", n);
-
- if(n->typecheck != 1) {
- dump("missed typecheck", n);
- fatal("missed typecheck");
- }
-
- t = T;
- et = Txxx;
-
- switch(n->op) {
- default:
- dump("walk", n);
- fatal("walkexpr: switch 1 unknown op %N", n);
- goto ret;
-
- case OTYPE:
- case ONONAME:
- case OINDREG:
- case OEMPTY:
- goto ret;
-
- case ONOT:
- case OMINUS:
- case OPLUS:
- case OCOM:
- case OREAL:
- case OIMAG:
- case ODOT:
- case ODOTPTR:
- case ODOTMETH:
- case ODOTINTER:
- case OIND:
- walkexpr(&n->left, init);
- goto ret;
-
- case OLEN:
- case OCAP:
- walkexpr(&n->left, init);
-
- // replace len(*[10]int) with 10.
- // delayed until now to preserve side effects.
- t = n->left->type;
- if(isptr[t->etype])
- t = t->type;
- if(isfixedarray(t)) {
- safeexpr(n->left, init);
- nodconst(n, n->type, t->bound);
- n->typecheck = 1;
- }
- goto ret;
-
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- case OSUB:
- case OMUL:
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case OADD:
- case OCOMPLEX:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- goto ret;
-
- case OANDAND:
- case OOROR:
- walkexpr(&n->left, init);
- // cannot put side effects from n->right on init,
- // because they cannot run before n->left is checked.
- // save elsewhere and store on the eventual n->right.
- ll = nil;
- walkexpr(&n->right, &ll);
- n->right->ninit = concat(n->right->ninit, ll);
- goto ret;
-
- case OPRINT:
- case OPRINTN:
- walkexprlist(n->list, init);
- n = walkprint(n, init, 0);
- goto ret;
-
- case OPANIC:
- n = mkcall("panic", T, init, n->left);
- goto ret;
-
- case ORECOVER:
- n = mkcall("recover", n->type, init, nod(OADDR, nodfp, N));
- goto ret;
-
- case OLITERAL:
- n->addable = 1;
- goto ret;
-
- case ONAME:
- if(!(n->class & PHEAP) && n->class != PPARAMREF)
- n->addable = 1;
- goto ret;
-
- case OCALLINTER:
- t = n->left->type;
- if(n->list && n->list->n->op == OAS)
- goto ret;
- walkexpr(&n->left, init);
- walkexprlist(n->list, init);
- ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
- n->list = reorder1(ll);
- goto ret;
-
- case OCALLFUNC:
- t = n->left->type;
- if(n->list && n->list->n->op == OAS)
- goto ret;
-
- if(n->left->op == OCLOSURE) {
- walkcallclosure(n, init);
- t = n->left->type;
- }
-
- walkexpr(&n->left, init);
- walkexprlist(n->list, init);
-
- ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
- n->list = reorder1(ll);
- if(isselect(n)) {
- // special prob with selectsend and selectrecv:
- // if chan is nil, they don't know big the channel
- // element is and therefore don't know how to find
- // the output bool, so we clear it before the call.
- Node *b;
- b = nodbool(0);
- typecheck(&b, Erv);
- lr = ascompatte(n->op, 0, getoutarg(t), list1(b), 0, init);
- n->list = concat(n->list, lr);
- }
- goto ret;
-
- case OCALLMETH:
- t = n->left->type;
- if(n->list && n->list->n->op == OAS)
- goto ret;
- walkexpr(&n->left, init);
- walkexprlist(n->list, init);
- ll = ascompatte(n->op, 0, getthis(t), list1(n->left->left), 0, init);
- lr = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
- ll = concat(ll, lr);
- n->left->left = N;
- ullmancalc(n->left);
- n->list = reorder1(ll);
- goto ret;
-
- case OAS:
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- walkexpr(&n->left, init);
- n->left = safeexpr(n->left, init);
-
- if(oaslit(n, init))
- goto ret;
-
- walkexpr(&n->right, init);
- if(n->left != N && n->right != N) {
- r = convas(nod(OAS, n->left, n->right), init);
- r->dodata = n->dodata;
- n = r;
- }
-
- goto ret;
-
- case OAS2:
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- walkexprlistsafe(n->list, init);
- walkexprlistsafe(n->rlist, init);
- ll = ascompatee(OAS, n->list, n->rlist, init);
- ll = reorder3(ll);
- n = liststmt(ll);
- goto ret;
-
- case OAS2FUNC:
- as2func:
- // a,b,... = fn()
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- walkexpr(&r, init);
- l = n->list->n;
-
- // all the really hard stuff - explicit function calls and so on -
- // is gone, but map assignments remain.
- // if there are map assignments here, assign via
- // temporaries, because ascompatet assumes
- // the targets can be addressed without function calls
- // and map index has an implicit one.
- lpost = nil;
- if(l->op == OINDEXMAP) {
- var = nod(OXXX, N, N);
- tempname(var, l->type);
- n->list->n = var;
- a = nod(OAS, l, var);
- typecheck(&a, Etop);
- lpost = list(lpost, a);
- }
- l = n->list->next->n;
- if(l->op == OINDEXMAP) {
- var = nod(OXXX, N, N);
- tempname(var, l->type);
- n->list->next->n = var;
- a = nod(OAS, l, var);
- typecheck(&a, Etop);
- lpost = list(lpost, a);
- }
- ll = ascompatet(n->op, n->list, &r->type, 0, init);
- walkexprlist(lpost, init);
- n = liststmt(concat(concat(list1(r), ll), lpost));
- goto ret;
-
- case OAS2RECV:
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- walkexpr(&r->left, init);
- fn = chanfn("chanrecv2", 2, r->left->type);
- r = mkcall1(fn, getoutargx(fn->type), init, r->left);
- n->rlist->n = r;
- n->op = OAS2FUNC;
- goto as2func;
-
- case OAS2MAPR:
- // a,b = m[i];
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- walkexpr(&r->left, init);
- fn = mapfn("mapaccess2", r->left->type);
- r = mkcall1(fn, getoutargx(fn->type), init, r->left, r->right);
- n->rlist = list1(r);
- n->op = OAS2FUNC;
- goto as2func;
-
- case OAS2MAPW:
- // map[] = a,b - mapassign2
- // a,b = m[i];
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- walkexprlistsafe(n->list, init);
- l = n->list->n;
- t = l->left->type;
- n = mkcall1(mapfn("mapassign2", t), T, init, l->left, l->right, n->rlist->n, n->rlist->next->n);
- goto ret;
-
- case OAS2DOTTYPE:
- // a,b = i.(T)
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- r->op = ODOTTYPE2;
- walkexpr(&r, init);
- ll = ascompatet(n->op, n->list, &r->type, 0, init);
- n = liststmt(concat(list1(r), ll));
- goto ret;
-
- case ODOTTYPE:
- case ODOTTYPE2:
- // Build name of function: assertI2E2 etc.
- strcpy(buf, "assert");
- p = buf+strlen(buf);
- if(isnilinter(n->left->type))
- *p++ = 'E';
- else
- *p++ = 'I';
- *p++ = '2';
- if(isnilinter(n->type))
- *p++ = 'E';
- else if(isinter(n->type))
- *p++ = 'I';
- else
- *p++ = 'T';
- if(n->op == ODOTTYPE2)
- *p++ = '2';
- *p = '\0';
-
- fn = syslook(buf, 1);
- ll = list1(typename(n->type));
- ll = list(ll, n->left);
- argtype(fn, n->left->type);
- argtype(fn, n->type);
- n = nod(OCALL, fn, N);
- n->list = ll;
- typecheck(&n, Erv | Efnstruct);
- walkexpr(&n, init);
- goto ret;
-
- case OCONVIFACE:
- // Build name of function: convI2E etc.
- // Not all names are possible
- // (e.g., we'll never generate convE2E or convE2I).
- walkexpr(&n->left, init);
- strcpy(buf, "conv");
- p = buf+strlen(buf);
- if(isnilinter(n->left->type))
- *p++ = 'E';
- else if(isinter(n->left->type))
- *p++ = 'I';
- else
- *p++ = 'T';
- *p++ = '2';
- if(isnilinter(n->type))
- *p++ = 'E';
- else
- *p++ = 'I';
- *p = '\0';
-
- fn = syslook(buf, 1);
- ll = nil;
- if(!isinter(n->left->type))
- ll = list(ll, typename(n->left->type));
- if(!isnilinter(n->type))
- ll = list(ll, typename(n->type));
- ll = list(ll, n->left);
- argtype(fn, n->left->type);
- argtype(fn, n->type);
- dowidth(fn->type);
- n = nod(OCALL, fn, N);
- n->list = ll;
- typecheck(&n, Erv);
- walkexpr(&n, init);
- goto ret;
-
- case OCONV:
- case OCONVNOP:
- if(thechar == '5') {
- if(isfloat[n->left->type->etype]) {
- if(n->type->etype == TINT64) {
- n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
- goto ret;
- }
- if(n->type->etype == TUINT64) {
- n = mkcall("float64touint64", n->type, init, conv(n->left, types[TFLOAT64]));
- goto ret;
- }
- }
- if(isfloat[n->type->etype]) {
- if(n->left->type->etype == TINT64) {
- n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64]));
- goto ret;
- }
- if(n->left->type->etype == TUINT64) {
- n = mkcall("uint64tofloat64", n->type, init, conv(n->left, types[TUINT64]));
- goto ret;
- }
- }
- }
- walkexpr(&n->left, init);
- goto ret;
-
- case OASOP:
- if(n->etype == OANDNOT) {
- n->etype = OAND;
- n->right = nod(OCOM, n->right, N);
- typecheck(&n->right, Erv);
- }
- n->left = safeexpr(n->left, init);
- walkexpr(&n->left, init);
- l = n->left;
- walkexpr(&n->right, init);
-
- /*
- * on 32-bit arch, rewrite 64-bit ops into l = l op r.
- * on 386, rewrite float ops into l = l op r.
- * everywhere, rewrite map ops into l = l op r.
- * everywhere, rewrite string += into l = l op r.
- * everywhere, rewrite complex /= into l = l op r.
- * TODO(rsc): Maybe this rewrite should be done always?
- */
- et = n->left->type->etype;
- if((widthptr == 4 && (et == TUINT64 || et == TINT64)) ||
- (thechar == '8' && isfloat[et]) ||
- l->op == OINDEXMAP ||
- et == TSTRING ||
- (iscomplex[et] && n->etype == ODIV)) {
- l = safeexpr(n->left, init);
- a = l;
- if(a->op == OINDEXMAP) {
- // map index has "lhs" bit set in a->etype.
- // make a copy so we can clear it on the rhs.
- a = nod(OXXX, N, N);
- *a = *l;
- a->etype = 0;
- }
- r = nod(OAS, l, nod(n->etype, a, n->right));
- typecheck(&r, Etop);
- walkexpr(&r, init);
- n = r;
- }
- goto ret;
-
- case OANDNOT:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- n->op = OAND;
- n->right = nod(OCOM, n->right, N);
- typecheck(&n->right, Erv);
- goto ret;
-
- case ODIV:
- case OMOD:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- /*
- * rewrite complex div into function call.
- */
- et = n->left->type->etype;
- if(iscomplex[et] && n->op == ODIV) {
- t = n->type;
- n = mkcall("complex128div", types[TCOMPLEX128], init,
- conv(n->left, types[TCOMPLEX128]),
- conv(n->right, types[TCOMPLEX128]));
- n = conv(n, t);
- goto ret;
- }
- /*
- * rewrite div and mod into function calls
- * on 32-bit architectures.
- */
- if(widthptr > 4 || (et != TUINT64 && et != TINT64))
- goto ret;
- if(et == TINT64)
- strcpy(namebuf, "int64");
- else
- strcpy(namebuf, "uint64");
- if(n->op == ODIV)
- strcat(namebuf, "div");
- else
- strcat(namebuf, "mod");
- n = mkcall(namebuf, n->type, init,
- conv(n->left, types[et]), conv(n->right, types[et]));
- goto ret;
-
- case OINDEX:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
-
- // if range of type cannot exceed static array bound,
- // disable bounds check
- if(isfixedarray(n->left->type))
- if(n->right->type->width < 4)
- if((1<<(8*n->right->type->width)) <= n->left->type->bound)
- n->etype = 1;
-
- if(isconst(n->left, CTSTR))
- if(n->right->type->width < 4)
- if((1<<(8*n->right->type->width)) <= n->left->val.u.sval->len)
- n->etype = 1;
-
- // check for static out of bounds
- if(isconst(n->right, CTINT) && !n->etype) {
- v = mpgetfix(n->right->val.u.xval);
- len = 1LL<<60;
- t = n->left->type;
- if(isconst(n->left, CTSTR))
- len = n->left->val.u.sval->len;
- if(t != T && isptr[t->etype])
- t = t->type;
- if(isfixedarray(t))
- len = t->bound;
- if(v < 0 || v >= (1LL<<31) || v >= len)
- yyerror("index out of bounds");
- else if(isconst(n->left, CTSTR)) {
- // replace "abc"[2] with 'b'.
- // delayed until now because "abc"[2] is not
- // an ideal constant.
- nodconst(n, n->type, n->left->val.u.sval->s[v]);
- }
- }
- goto ret;
-
- case OINDEXMAP:
- if(n->etype == 1)
- goto ret;
-
- t = n->left->type;
- n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
- goto ret;
-
- case ORECV:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, n->left);
- goto ret;
-
- case OSLICE:
- case OSLICEARR:
- walkexpr(&n->left, init);
- n->left = safeexpr(n->left, init);
- walkexpr(&n->right->left, init);
- n->right->left = safeexpr(n->right->left, init);
- walkexpr(&n->right->right, init);
- n->right->right = safeexpr(n->right->right, init);
-
- len = 1LL<<60;
- t = n->left->type;
- if(t != T && isptr[t->etype])
- t = t->type;
- if(isfixedarray(t))
- len = t->bound;
-
- // check for static out of bounds
- // NOTE: v > len not v >= len.
- v1 = -1;
- v2 = -1;
- if(isconst(n->right->left, CTINT)) {
- v1 = mpgetfix(n->right->left->val.u.xval);
- if(v1 < 0 || v1 >= (1LL<<31) || v1 > len) {
- yyerror("slice index out of bounds");
- v1 = -1;
- }
- }
- if(isconst(n->right->right, CTINT)) {
- v2 = mpgetfix(n->right->right->val.u.xval);
- if(v2 < 0 || v2 >= (1LL<<31) || v2 > len) {
- yyerror("slice index out of bounds");
- v2 = -1;
- }
- }
- if(v1 >= 0 && v2 >= 0 && v1 > v2)
- yyerror("inverted slice range");
-
- if(n->op == OSLICEARR)
- goto slicearray;
-
- // dynamic slice
- // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
- // sliceslice1(old []any, lb uint64, width uint64) (ary []any)
- t = n->type;
- et = n->etype;
- if(n->right->left == N)
- l = nodintconst(0);
- else
- l = conv(n->right->left, types[TUINT64]);
- if(n->right->right != N) {
- fn = syslook("sliceslice", 1);
- argtype(fn, t->type); // any-1
- argtype(fn, t->type); // any-2
- n = mkcall1(fn, t, init,
- n->left,
- l,
- conv(n->right->right, types[TUINT64]),
- nodintconst(t->type->width));
- } else {
- fn = syslook("sliceslice1", 1);
- argtype(fn, t->type); // any-1
- argtype(fn, t->type); // any-2
- n = mkcall1(fn, t, init,
- n->left,
- l,
- nodintconst(t->type->width));
- }
- n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
- goto ret;
-
- slicearray:
- // static slice
- // slicearray(old *any, uint64 nel, lb uint64, hb uint64, width uint64) (ary []any)
- t = n->type;
- fn = syslook("slicearray", 1);
- argtype(fn, n->left->type->type); // any-1
- argtype(fn, t->type); // any-2
- if(n->right->left == N)
- l = nodintconst(0);
- else
- l = conv(n->right->left, types[TUINT64]);
- if(n->right->right == N)
- r = nodintconst(n->left->type->type->bound);
- else
- r = conv(n->right->right, types[TUINT64]);
- n = mkcall1(fn, t, init,
- n->left, nodintconst(n->left->type->type->bound),
- l,
- r,
- nodintconst(t->type->width));
- goto ret;
-
- case OADDR:;
- Node *nvar, *nstar;
-
- // turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation.
- // initialize with
- // nvar := new(*Point);
- // *nvar = Point(1, 2);
- // and replace expression with nvar
- switch(n->left->op) {
- case OARRAYLIT:
- case OMAPLIT:
- case OSTRUCTLIT:
- nvar = makenewvar(n->type, init, &nstar);
- anylit(0, n->left, nstar, init);
- n = nvar;
- goto ret;
- }
-
- walkexpr(&n->left, init);
- goto ret;
-
- case ONEW:
- n = callnew(n->type->type);
- goto ret;
-
- case OCMPSTR:
- // If one argument to the comparison is an empty string,
- // comparing the lengths instead will yield the same result
- // without the function call.
- if((isconst(n->left, CTSTR) && n->left->val.u.sval->len == 0) ||
- (isconst(n->right, CTSTR) && n->right->val.u.sval->len == 0)) {
- r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N));
- typecheck(&r, Erv);
- walkexpr(&r, init);
- n = r;
- goto ret;
- }
-
- // s + "badgerbadgerbadger" == "badgerbadgerbadger"
- if((n->etype == OEQ || n->etype == ONE) &&
- isconst(n->right, CTSTR) &&
- n->left->op == OADDSTR && isconst(n->left->right, CTSTR) &&
- cmpslit(n->right, n->left->right) == 0) {
- r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0));
- typecheck(&r, Erv);
- walkexpr(&r, init);
- n = r;
- goto ret;
- }
-
- // prepare for rewrite below
- if(n->etype == OEQ || n->etype == ONE) {
- n->left = cheapexpr(n->left, init);
- n->right = cheapexpr(n->right, init);
- }
-
- // sys_cmpstring(s1, s2) :: 0
- r = mkcall("cmpstring", types[TINT], init,
- conv(n->left, types[TSTRING]),
- conv(n->right, types[TSTRING]));
- r = nod(n->etype, r, nodintconst(0));
-
- // quick check of len before full compare for == or !=
- if(n->etype == OEQ || n->etype == ONE) {
- if(n->etype == OEQ)
- r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
- else
- r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
- typecheck(&r, Erv);
- walkexpr(&r, nil);
- }
- typecheck(&r, Erv);
- n = r;
- goto ret;
-
- case OADDSTR:
- n = addstr(n, init);
- goto ret;
-
- case OSLICESTR:
- // sys_slicestring(s, lb, hb)
- if(n->right->left == N)
- l = nodintconst(0);
- else
- l = conv(n->right->left, types[TINT]);
- if(n->right->right) {
- n = mkcall("slicestring", n->type, init,
- conv(n->left, types[TSTRING]),
- l,
- conv(n->right->right, types[TINT]));
- } else {
- n = mkcall("slicestring1", n->type, init,
- conv(n->left, types[TSTRING]),
- l);
- }
- goto ret;
-
- case OAPPEND:
- if(n->isddd)
- n = appendslice(n, init);
- else
- n = append(n, init);
- goto ret;
-
- case OCOPY:
- if(n->right->type->etype == TSTRING)
- fn = syslook("slicestringcopy", 1);
- else
- fn = syslook("slicecopy", 1);
- argtype(fn, n->left->type);
- argtype(fn, n->right->type);
- n = mkcall1(fn, n->type, init,
- n->left, n->right,
- nodintconst(n->left->type->type->width));
- goto ret;
-
- case OCLOSE:
- // cannot use chanfn - closechan takes any, not chan any
- fn = syslook("closechan", 1);
- argtype(fn, n->left->type);
- n = mkcall1(fn, T, init, n->left);
- goto ret;
-
- case OMAKECHAN:
- n = mkcall1(chanfn("makechan", 1, n->type), n->type, init,
- typename(n->type->type),
- conv(n->left, types[TINT64]));
- goto ret;
-
- case OMAKEMAP:
- t = n->type;
-
- fn = syslook("makemap", 1);
- argtype(fn, t->down); // any-1
- argtype(fn, t->type); // any-2
-
- n = mkcall1(fn, n->type, init,
- typename(t->down), // key type
- typename(t->type), // value type
- conv(n->left, types[TINT64]));
- goto ret;
-
- case OMAKESLICE:
- // makeslice(t *Type, nel int64, max int64) (ary []any)
- l = n->left;
- r = n->right;
- if(r == nil)
- l = r = safeexpr(l, init);
- t = n->type;
- fn = syslook("makeslice", 1);
- argtype(fn, t->type); // any-1
- n = mkcall1(fn, n->type, init,
- typename(n->type),
- conv(l, types[TINT64]),
- conv(r, types[TINT64]));
- goto ret;
-
- case ORUNESTR:
- // sys_intstring(v)
- n = mkcall("intstring", n->type, init,
- conv(n->left, types[TINT64]));
- goto ret;
-
- case OARRAYBYTESTR:
- // slicebytetostring([]byte) string;
- n = mkcall("slicebytetostring", n->type, init, n->left);
- goto ret;
-
- case OARRAYRUNESTR:
- // sliceinttostring([]int) string;
- n = mkcall("sliceinttostring", n->type, init, n->left);
- goto ret;
-
- case OSTRARRAYBYTE:
- // stringtoslicebyte(string) []byte;
- n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING]));
- goto ret;
-
- case OSTRARRAYRUNE:
- // stringtosliceint(string) []int
- n = mkcall("stringtosliceint", n->type, init, n->left);
- goto ret;
-
- case OCMPIFACE:
- // ifaceeq(i1 any-1, i2 any-2) (ret bool);
- if(!eqtype(n->left->type, n->right->type))
- fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type);
- if(isnilinter(n->left->type))
- fn = syslook("efaceeq", 1);
- else
- fn = syslook("ifaceeq", 1);
- argtype(fn, n->right->type);
- argtype(fn, n->left->type);
- r = mkcall1(fn, n->type, init, n->left, n->right);
- if(n->etype == ONE) {
- r = nod(ONOT, r, N);
- typecheck(&r, Erv);
- }
- n = r;
- goto ret;
-
- case OARRAYLIT:
- case OMAPLIT:
- case OSTRUCTLIT:
- nvar = nod(OXXX, N, N);
- tempname(nvar, n->type);
- anylit(0, n, nvar, init);
- n = nvar;
- goto ret;
-
- case OSEND:
- n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, n->left, n->right);
- goto ret;
-
- case OCLOSURE:
- n = walkclosure(n, init);
- goto ret;
- }
- fatal("missing switch %O", n->op);
-
-ret:
- if(debug['w'] && n != N)
- dump("walk", n);
-
- ullmancalc(n);
- lineno = lno;
- *np = n;
-}
-
-static Node*
-makenewvar(Type *t, NodeList **init, Node **nstar)
-{
- Node *nvar, *nas;
-
- nvar = nod(OXXX, N, N);
- tempname(nvar, t);
- nas = nod(OAS, nvar, callnew(t->type));
- typecheck(&nas, Etop);
- walkexpr(&nas, init);
- *init = list(*init, nas);
-
- *nstar = nod(OIND, nvar, N);
- typecheck(nstar, Erv);
- return nvar;
-}
-
-static Node*
-ascompatee1(int op, Node *l, Node *r, NodeList **init)
-{
- return convas(nod(OAS, l, r), init);
-}
-
-static NodeList*
-ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
-{
- NodeList *ll, *lr, *nn;
-
- /*
- * check assign expression list to
- * a expression list. called in
- * expr-list = expr-list
- */
-
- // ensure order of evaluation for function calls
- for(ll=nl; ll; ll=ll->next)
- ll->n = safeexpr(ll->n, init);
- for(lr=nr; lr; lr=lr->next)
- lr->n = safeexpr(lr->n, init);
-
- nn = nil;
- for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next)
- nn = list(nn, ascompatee1(op, ll->n, lr->n, init));
-
- // cannot happen: caller checked that lists had same length
- if(ll || lr)
- yyerror("error in shape across %O", op);
- return nn;
-}
-
-/*
- * l is an lv and rt is the type of an rv
- * return 1 if this implies a function call
- * evaluating the lv or a function call
- * in the conversion of the types
- */
-static int
-fncall(Node *l, Type *rt)
-{
- if(l->ullman >= UINF || l->op == OINDEXMAP)
- return 1;
- if(eqtype(l->type, rt))
- return 0;
- return 1;
-}
-
-static NodeList*
-ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
-{
- Node *l, *tmp, *a;
- NodeList *ll;
- Type *r;
- Iter saver;
- int ucount;
- NodeList *nn, *mm;
-
- /*
- * check assign type list to
- * a expression list. called in
- * expr-list = func()
- */
- r = structfirst(&saver, nr);
- nn = nil;
- mm = nil;
- ucount = 0;
- for(ll=nl; ll; ll=ll->next) {
- if(r == T)
- break;
- l = ll->n;
- if(isblank(l)) {
- r = structnext(&saver);
- continue;
- }
-
- // any lv that causes a fn call must be
- // deferred until all the return arguments
- // have been pulled from the output arguments
- if(fncall(l, r->type)) {
- tmp = nod(OXXX, N, N);
- tempname(tmp, r->type);
- typecheck(&tmp, Erv);
- a = nod(OAS, l, tmp);
- a = convas(a, init);
- mm = list(mm, a);
- l = tmp;
- }
-
- a = nod(OAS, l, nodarg(r, fp));
- a = convas(a, init);
- ullmancalc(a);
- if(a->ullman >= UINF)
- ucount++;
- nn = list(nn, a);
- r = structnext(&saver);
- }
-
- if(ll != nil || r != T)
- yyerror("assignment count mismatch: %d = %d",
- count(nl), structcount(*nr));
- if(ucount)
- fatal("reorder2: too many function calls evaluating parameters");
- return concat(nn, mm);
-}
-
- /*
- * package all the arguments that match a ... T parameter into a []T.
- */
-static NodeList*
-mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
-{
- Node *a, *n;
- Type *tslice;
-
- tslice = typ(TARRAY);
- tslice->type = l->type->type;
- tslice->bound = -1;
-
- n = nod(OCOMPLIT, N, typenod(tslice));
- n->list = lr0;
- typecheck(&n, Erv);
- if(n->type == T)
- fatal("mkdotargslice: typecheck failed");
- walkexpr(&n, init);
-
- a = nod(OAS, nodarg(l, fp), n);
- nn = list(nn, convas(a, init));
- return nn;
-}
-
-/*
- * helpers for shape errors
- */
-static char*
-dumptypes(Type **nl, char *what)
-{
- int first;
- Type *l;
- Iter savel;
- Fmt fmt;
-
- fmtstrinit(&fmt);
- fmtprint(&fmt, "\t");
- l = structfirst(&savel, nl);
- first = 1;
- for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
- if(first)
- first = 0;
- else
- fmtprint(&fmt, ", ");
- fmtprint(&fmt, "%T", l);
- }
- if(first)
- fmtprint(&fmt, "[no arguments %s]", what);
- return fmtstrflush(&fmt);
-}
-
-static char*
-dumpnodetypes(NodeList *l, char *what)
-{
- int first;
- Node *r;
- Fmt fmt;
-
- fmtstrinit(&fmt);
- fmtprint(&fmt, "\t");
- first = 1;
- for(; l; l=l->next) {
- r = l->n;
- if(first)
- first = 0;
- else
- fmtprint(&fmt, ", ");
- fmtprint(&fmt, "%T", r->type);
- }
- if(first)
- fmtprint(&fmt, "[no arguments %s]", what);
- return fmtstrflush(&fmt);
-}
-
-/*
- * check assign expression list to
- * a type list. called in
- * return expr-list
- * func(expr-list)
- */
-static NodeList*
-ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
-{
- Type *l, *ll;
- Node *r, *a;
- NodeList *nn, *lr0, *alist;
- Iter savel;
- char *l1, *l2;
-
- lr0 = lr;
- l = structfirst(&savel, nl);
- r = N;
- if(lr)
- r = lr->n;
- nn = nil;
-
- // f(g()) where g has multiple return values
- if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
- // optimization - can do block copy
- if(eqtypenoname(r->type, *nl)) {
- a = nodarg(*nl, fp);
- a->type = r->type;
- nn = list1(convas(nod(OAS, a, r), init));
- goto ret;
- }
-
- // conversions involved.
- // copy into temporaries.
- alist = nil;
- for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) {
- a = nod(OXXX, N, N);
- tempname(a, l->type);
- alist = list(alist, a);
- }
- a = nod(OAS2, N, N);
- a->list = alist;
- a->rlist = lr;
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
- lr = alist;
- r = lr->n;
- l = structfirst(&savel, nl);
- }
-
-loop:
- if(l != T && l->isddd) {
- // the ddd parameter must be last
- ll = structnext(&savel);
- if(ll != T)
- yyerror("... must be last argument");
-
- // special case --
- // only if we are assigning a single ddd
- // argument to a ddd parameter then it is
- // passed thru unencapsulated
- if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) {
- a = nod(OAS, nodarg(l, fp), r);
- a = convas(a, init);
- nn = list(nn, a);
- goto ret;
- }
-
- // normal case -- make a slice of all
- // remaining arguments and pass it to
- // the ddd parameter.
- nn = mkdotargslice(lr, nn, l, fp, init);
- goto ret;
- }
-
- if(l == T || r == N) {
- if(l != T || r != N) {
- l1 = dumptypes(nl, "expected");
- l2 = dumpnodetypes(lr0, "given");
- if(l != T)
- yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2);
- else
- yyerror("too many arguments to %O\n%s\n%s", op, l1, l2);
- }
- goto ret;
- }
-
- a = nod(OAS, nodarg(l, fp), r);
- a = convas(a, init);
- nn = list(nn, a);
-
- l = structnext(&savel);
- r = N;
- lr = lr->next;
- if(lr != nil)
- r = lr->n;
- goto loop;
-
-ret:
- for(lr=nn; lr; lr=lr->next)
- lr->n->typecheck = 1;
- return nn;
-}
-
-// generate code for print
-static Node*
-walkprint(Node *nn, NodeList **init, int defer)
-{
- Node *r;
- Node *n;
- NodeList *l, *all;
- Node *on;
- Type *t;
- int notfirst, et, op;
- NodeList *calls, *intypes, *args;
- Fmt fmt;
-
- on = nil;
- op = nn->op;
- all = nn->list;
- calls = nil;
- notfirst = 0;
- intypes = nil;
- args = nil;
-
- memset(&fmt, 0, sizeof fmt);
- if(defer) {
- // defer print turns into defer printf with format string
- fmtstrinit(&fmt);
- intypes = list(intypes, nod(ODCLFIELD, N, typenod(types[TSTRING])));
- args = list1(nod(OXXX, N, N));
- }
-
- for(l=all; l; l=l->next) {
- if(notfirst) {
- if(defer)
- fmtprint(&fmt, " ");
- else
- calls = list(calls, mkcall("printsp", T, init));
- }
- notfirst = op == OPRINTN;
-
- n = l->n;
- if(n->op == OLITERAL) {
- switch(n->val.ctype) {
- case CTINT:
- defaultlit(&n, types[TINT64]);
- break;
- case CTFLT:
- defaultlit(&n, types[TFLOAT64]);
- break;
- }
- }
- if(n->op != OLITERAL && n->type && n->type->etype == TIDEAL)
- defaultlit(&n, types[TINT64]);
- defaultlit(&n, nil);
- l->n = n;
- if(n->type == T || n->type->etype == TFORW)
- continue;
-
- t = n->type;
- et = n->type->etype;
- if(isinter(n->type)) {
- if(defer) {
- if(isnilinter(n->type))
- fmtprint(&fmt, "%%e");
- else
- fmtprint(&fmt, "%%i");
- } else {
- if(isnilinter(n->type))
- on = syslook("printeface", 1);
- else
- on = syslook("printiface", 1);
- argtype(on, n->type); // any-1
- }
- } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) {
- if(defer) {
- fmtprint(&fmt, "%%p");
- } else {
- on = syslook("printpointer", 1);
- argtype(on, n->type); // any-1
- }
- } else if(isslice(n->type)) {
- if(defer) {
- fmtprint(&fmt, "%%a");
- } else {
- on = syslook("printslice", 1);
- argtype(on, n->type); // any-1
- }
- } else if(isint[et]) {
- if(defer) {
- if(et == TUINT64)
- fmtprint(&fmt, "%%U");
- else {
- fmtprint(&fmt, "%%D");
- t = types[TINT64];
- }
- } else {
- if(et == TUINT64)
- on = syslook("printuint", 0);
- else
- on = syslook("printint", 0);
- }
- } else if(isfloat[et]) {
- if(defer) {
- fmtprint(&fmt, "%%f");
- t = types[TFLOAT64];
- } else
- on = syslook("printfloat", 0);
- } else if(iscomplex[et]) {
- if(defer) {
- fmtprint(&fmt, "%%C");
- t = types[TCOMPLEX128];
- } else
- on = syslook("printcomplex", 0);
- } else if(et == TBOOL) {
- if(defer)
- fmtprint(&fmt, "%%t");
- else
- on = syslook("printbool", 0);
- } else if(et == TSTRING) {
- if(defer)
- fmtprint(&fmt, "%%S");
- else
- on = syslook("printstring", 0);
- } else {
- badtype(OPRINT, n->type, T);
- continue;
- }
-
- if(!defer) {
- t = *getinarg(on->type);
- if(t != nil)
- t = t->type;
- if(t != nil)
- t = t->type;
- }
-
- if(!eqtype(t, n->type)) {
- n = nod(OCONV, n, N);
- n->type = t;
- }
-
- if(defer) {
- intypes = list(intypes, nod(ODCLFIELD, N, typenod(t)));
- args = list(args, n);
- } else {
- r = nod(OCALL, on, N);
- r->list = list1(n);
- calls = list(calls, r);
- }
- }
-
- if(defer) {
- if(op == OPRINTN)
- fmtprint(&fmt, "\n");
- on = syslook("goprintf", 1);
- on->type = functype(nil, intypes, nil);
- args->n = nod(OLITERAL, N, N);
- args->n->val.ctype = CTSTR;
- args->n->val.u.sval = strlit(fmtstrflush(&fmt));
- r = nod(OCALL, on, N);
- r->list = args;
- typecheck(&r, Etop);
- walkexpr(&r, init);
- } else {
- if(op == OPRINTN)
- calls = list(calls, mkcall("printnl", T, nil));
- typechecklist(calls, Etop);
- walkexprlist(calls, init);
-
- r = nod(OEMPTY, N, N);
- typecheck(&r, Etop);
- walkexpr(&r, init);
- r->ninit = calls;
- }
- return r;
-}
-
-Node*
-callnew(Type *t)
-{
- Node *fn;
-
- dowidth(t);
- fn = syslook("new", 1);
- argtype(fn, t);
- return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
-}
-
-static Node*
-convas(Node *n, NodeList **init)
-{
- Type *lt, *rt;
-
- if(n->op != OAS)
- fatal("convas: not OAS %O", n->op);
-
- n->typecheck = 1;
-
- if(n->left == N || n->right == N)
- goto out;
-
- lt = n->left->type;
- rt = n->right->type;
- if(lt == T || rt == T)
- goto out;
-
- if(isblank(n->left)) {
- defaultlit(&n->right, T);
- goto out;
- }
-
- if(n->left->op == OINDEXMAP) {
- n = mkcall1(mapfn("mapassign1", n->left->left->type), T, init,
- n->left->left, n->left->right, n->right);
- goto out;
- }
-
- if(eqtype(lt, rt))
- goto out;
-
- n->right = assignconv(n->right, lt, "assignment");
- walkexpr(&n->right, init);
-
-out:
- ullmancalc(n);
- return n;
-}
-
-/*
- * from ascompat[te]
- * evaluating actual function arguments.
- * f(a,b)
- * if there is exactly one function expr,
- * then it is done first. otherwise must
- * make temp variables
- */
-NodeList*
-reorder1(NodeList *all)
-{
- Node *f, *a, *n;
- NodeList *l, *r, *g;
- int c, d, t;
-
- c = 0; // function calls
- t = 0; // total parameters
-
- for(l=all; l; l=l->next) {
- n = l->n;
- t++;
- ullmancalc(n);
- if(n->ullman >= UINF)
- c++;
- }
- if(c == 0 || t == 1)
- return all;
-
- g = nil; // fncalls assigned to tempnames
- f = N; // last fncall assigned to stack
- r = nil; // non fncalls and tempnames assigned to stack
- d = 0;
- for(l=all; l; l=l->next) {
- n = l->n;
- if(n->ullman < UINF) {
- r = list(r, n);
- continue;
- }
- d++;
- if(d == c) {
- f = n;
- continue;
- }
-
- // make assignment of fncall to tempname
- a = nod(OXXX, N, N);
- tempname(a, n->right->type);
- a = nod(OAS, a, n->right);
- g = list(g, a);
-
- // put normal arg assignment on list
- // with fncall replaced by tempname
- n->right = a->left;
- r = list(r, n);
- }
-
- if(f != N)
- g = list(g, f);
- return concat(g, r);
-}
-
-/*
- * from ascompat[ee]
- * a,b = c,d
- * simultaneous assignment. there cannot
- * be later use of an earlier lvalue.
- */
-
-static int
-vmatch2(Node *l, Node *r)
-{
- NodeList *ll;
-
- /*
- * isolate all right sides
- */
- if(r == N)
- return 0;
- switch(r->op) {
- case ONAME:
- // match each right given left
- if(l == r)
- return 1;
- case OLITERAL:
- return 0;
- }
- if(vmatch2(l, r->left))
- return 1;
- if(vmatch2(l, r->right))
- return 1;
- for(ll=r->list; ll; ll=ll->next)
- if(vmatch2(l, ll->n))
- return 1;
- return 0;
-}
-
-int
-vmatch1(Node *l, Node *r)
-{
- NodeList *ll;
-
- /*
- * isolate all left sides
- */
- if(l == N || r == N)
- return 0;
- switch(l->op) {
- case ONAME:
- switch(l->class) {
- case PPARAM:
- case PPARAMREF:
- case PAUTO:
- break;
- default:
- // assignment to non-stack variable
- // must be delayed if right has function calls.
- if(r->ullman >= UINF)
- return 1;
- break;
- }
- return vmatch2(l, r);
- case OLITERAL:
- return 0;
- }
- if(vmatch1(l->left, r))
- return 1;
- if(vmatch1(l->right, r))
- return 1;
- for(ll=l->list; ll; ll=ll->next)
- if(vmatch1(ll->n, r))
- return 1;
- return 0;
-}
-
-NodeList*
-reorder3(NodeList *all)
-{
- Node *n1, *n2, *q;
- int c1, c2;
- NodeList *l1, *l2, *r;
-
- r = nil;
- for(l1=all, c1=0; l1; l1=l1->next, c1++) {
- n1 = l1->n;
- for(l2=all, c2=0; l2; l2=l2->next, c2++) {
- n2 = l2->n;
- if(c2 > c1) {
- if(vmatch1(n1->left, n2->right)) {
- // delay assignment to n1->left
- q = nod(OXXX, N, N);
- tempname(q, n1->right->type);
- q = nod(OAS, n1->left, q);
- n1->left = q->right;
- r = list(r, q);
- break;
- }
- }
- }
- }
- return concat(all, r);
-}
-
-/*
- * walk through argin parameters.
- * generate and return code to allocate
- * copies of escaped parameters to the heap.
- */
-static NodeList*
-paramstoheap(Type **argin, int out)
-{
- Type *t;
- Iter savet;
- Node *v;
- NodeList *nn;
-
- nn = nil;
- for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
- v = t->nname;
- if(v == N && out && hasdefer) {
- // Defer might stop a panic and show the
- // return values as they exist at the time of panic.
- // Make sure to zero them on entry to the function.
- nn = list(nn, nod(OAS, nodarg(t, 1), N));
- }
- if(v == N || !(v->class & PHEAP))
- continue;
-
- // generate allocation & copying code
- if(v->alloc == nil)
- v->alloc = callnew(v->type);
- nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
- if((v->class & ~PHEAP) != PPARAMOUT)
- nn = list(nn, nod(OAS, v, v->stackparam));
- }
- return nn;
-}
-
-/*
- * walk through argout parameters copying back to stack
- */
-static NodeList*
-returnsfromheap(Type **argin)
-{
- Type *t;
- Iter savet;
- Node *v;
- NodeList *nn;
-
- nn = nil;
- for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
- v = t->nname;
- if(v == N || v->class != (PHEAP|PPARAMOUT))
- continue;
- nn = list(nn, nod(OAS, v->stackparam, v));
- }
- return nn;
-}
-
-/*
- * take care of migrating any function in/out args
- * between the stack and the heap. adds code to
- * curfn's before and after lists.
- */
-static void
-heapmoves(void)
-{
- NodeList *nn;
- int32 lno;
-
- lno = lineno;
- lineno = curfn->lineno;
- nn = paramstoheap(getthis(curfn->type), 0);
- nn = concat(nn, paramstoheap(getinarg(curfn->type), 0));
- nn = concat(nn, paramstoheap(getoutarg(curfn->type), 1));
- curfn->enter = concat(curfn->enter, nn);
- lineno = curfn->endlineno;
- curfn->exit = returnsfromheap(getoutarg(curfn->type));
- lineno = lno;
-}
-
-static Node*
-vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
-{
- int i, n;
- Node *r;
- NodeList *args;
-
- if(fn->type == T || fn->type->etype != TFUNC)
- fatal("mkcall %#N %T", fn, fn->type);
-
- args = nil;
- n = fn->type->intuple;
- for(i=0; i<n; i++)
- args = list(args, va_arg(va, Node*));
-
- r = nod(OCALL, fn, N);
- r->list = args;
- if(fn->type->outtuple > 0)
- typecheck(&r, Erv | Efnstruct);
- else
- typecheck(&r, Etop);
- walkexpr(&r, init);
- r->type = t;
- return r;
-}
-
-Node*
-mkcall(char *name, Type *t, NodeList **init, ...)
-{
- Node *r;
- va_list va;
-
- va_start(va, init);
- r = vmkcall(syslook(name, 0), t, init, va);
- va_end(va);
- return r;
-}
-
-Node*
-mkcall1(Node *fn, Type *t, NodeList **init, ...)
-{
- Node *r;
- va_list va;
-
- va_start(va, init);
- r = vmkcall(fn, t, init, va);
- va_end(va);
- return r;
-}
-
-static Node*
-conv(Node *n, Type *t)
-{
- if(eqtype(n->type, t))
- return n;
- n = nod(OCONV, n, N);
- n->type = t;
- typecheck(&n, Erv);
- return n;
-}
-
-Node*
-chanfn(char *name, int n, Type *t)
-{
- Node *fn;
- int i;
-
- if(t->etype != TCHAN)
- fatal("chanfn %T", t);
- fn = syslook(name, 1);
- for(i=0; i<n; i++)
- argtype(fn, t->type);
- return fn;
-}
-
-static Node*
-mapfn(char *name, Type *t)
-{
- Node *fn;
-
- if(t->etype != TMAP)
- fatal("mapfn %T", t);
- fn = syslook(name, 1);
- argtype(fn, t->down);
- argtype(fn, t->type);
- argtype(fn, t->down);
- argtype(fn, t->type);
- return fn;
-}
-
-static Node*
-addstr(Node *n, NodeList **init)
-{
- Node *r, *cat, *typstr;
- NodeList *in, *args;
- int i, count;
-
- count = 0;
- for(r=n; r->op == OADDSTR; r=r->left)
- count++; // r->right
- count++; // r
-
- // prepare call of runtime.catstring of type int, string, string, string
- // with as many strings as we have.
- cat = syslook("concatstring", 1);
- cat->type = T;
- cat->ntype = nod(OTFUNC, N, N);
- in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count
- typstr = typenod(types[TSTRING]);
- for(i=0; i<count; i++)
- in = list(in, nod(ODCLFIELD, N, typstr));
- cat->ntype->list = in;
- cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr));
-
- args = nil;
- for(r=n; r->op == OADDSTR; r=r->left)
- args = concat(list1(conv(r->right, types[TSTRING])), args);
- args = concat(list1(conv(r, types[TSTRING])), args);
- args = concat(list1(nodintconst(count)), args);
-
- r = nod(OCALL, cat, N);
- r->list = args;
- typecheck(&r, Erv);
- walkexpr(&r, init);
- r->type = n->type;
-
- return r;
-}
-
-static Node*
-appendslice(Node *n, NodeList **init)
-{
- Node *f;
-
- f = syslook("appendslice", 1);
- argtype(f, n->type);
- argtype(f, n->type->type);
- argtype(f, n->type);
- return mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
-}
-
-// expand append(src, a [, b]* ) to
-//
-// init {
-// s := src
-// const argc = len(args) - 1
-// if cap(s) - len(s) < argc {
-// s = growslice(s, argc)
-// }
-// n := len(s)
-// s = s[:n+argc]
-// s[n] = a
-// s[n+1] = b
-// ...
-// }
-// s
-static Node*
-append(Node *n, NodeList **init)
-{
- NodeList *l, *a;
- Node *nsrc, *ns, *nn, *na, *nx, *fn;
- int argc;
-
- walkexprlistsafe(n->list, init);
-
- nsrc = n->list->n;
- argc = count(n->list) - 1;
- if (argc < 1) {
- return nsrc;
- }
-
- l = nil;
-
- ns = nod(OXXX, N, N); // var s
- tempname(ns, nsrc->type);
- l = list(l, nod(OAS, ns, nsrc)); // s = src
-
- na = nodintconst(argc); // const argc
- nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
- nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
-
- fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
- argtype(fn, ns->type->type); // 1 old []any
- argtype(fn, ns->type->type); // 2 ret []any
-
- nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit,
- typename(ns->type),
- ns,
- conv(na, types[TINT64]))));
- l = list(l, nx);
-
- nn = nod(OXXX, N, N); // var n
- tempname(nn, types[TINT]);
- l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
-
- nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
- nx->etype = 1; // disable bounds check
- l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
-
- for (a = n->list->next; a != nil; a = a->next) {
- nx = nod(OINDEX, ns, nn); // s[n] ...
- nx->etype = 1; // disable bounds check
- l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
- if (a->next != nil)
- l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1
- }
-
- typechecklist(l, Etop);
- walkstmtlist(l);
- *init = concat(*init, l);
- return ns;
-}
diff --git a/src/cmd/godefs/Makefile b/src/cmd/godefs/Makefile
deleted file mode 100644
index 77cd26c04..000000000
--- a/src/cmd/godefs/Makefile
+++ /dev/null
@@ -1,19 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=godefs
-OFILES=\
- main.$O\
- stabs.$O\
- util.$O\
-
-HFILES=a.h
-
-include ../../Make.ccmd
-
-test: $(TARG)
- ./test.sh
diff --git a/src/cmd/godefs/a.h b/src/cmd/godefs/a.h
deleted file mode 100644
index 9b4957467..000000000
--- a/src/cmd/godefs/a.h
+++ /dev/null
@@ -1,104 +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 <u.h>
-#include <libc.h>
-#include <bio.h>
-
-enum
-{
- Void = 1,
- Int8,
- Uint8,
- Int16,
- Uint16,
- Int32,
- Uint32,
- Int64,
- Uint64,
- Float32,
- Float64,
- Ptr,
- Struct,
- Array,
- Union,
- Typedef,
-};
-
-typedef struct Field Field;
-typedef struct Type Type;
-
-struct Type
-{
- Type *next; // next in hash table
-
- // stabs name and two-integer id
- char *name;
- int n1;
- int n2;
-
- // int kind
- int kind;
-
- // sub-type for ptr, array
- Type *type;
-
- // struct fields
- Field *f;
- int nf;
- int size;
-
- int saved; // recorded in typ array
- int warned; // warned about needing type
- int printed; // has the definition been printed yet?
-};
-
-struct Field
-{
- char *name;
- Type *type;
- int offset;
- int size;
-};
-
-// Constants
-typedef struct Const Const;
-struct Const
-{
- char *name;
- vlong value;
-};
-
-// Recorded constants and types, to be printed.
-extern Const *con;
-extern int ncon;
-extern Type **typ;
-extern int ntyp;
-extern int kindsize[];
-
-// Language output
-typedef struct Lang Lang;
-struct Lang
-{
- char *constbegin;
- char *constfmt;
- char *constend;
-
- char *typdef;
- char *typdefend;
-
- char *structbegin;
- char *unionbegin;
- char *structpadfmt;
- char *structend;
-
- int (*typefmt)(Fmt*);
-};
-
-extern Lang go, c;
-
-void* emalloc(int);
-char* estrdup(char*);
-void* erealloc(void*, int);
-void parsestabtype(char*);
diff --git a/src/cmd/godefs/doc.go b/src/cmd/godefs/doc.go
deleted file mode 100644
index 365c7cf6e..000000000
--- a/src/cmd/godefs/doc.go
+++ /dev/null
@@ -1,99 +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.
-
-/*
-
-Godefs is a bootstrapping tool for porting the Go runtime to new systems.
-It translates C type declarations into C or Go type declarations
-with the same memory layout.
-
-Usage: godefs [-g package] [-c cc] [-f cc-arg]... [defs.c ...]
-
-Godefs takes as input a host-compilable C file that includes
-standard system headers. From that input file, it generates
-a standalone (no #includes) C or Go file containing equivalent
-definitions.
-
-The input to godefs is a C input file that can be compiled by
-the host system's standard C compiler (typically gcc).
-This file is expected to define new types and enumerated constants
-whose names begin with $ (a legal identifier character in gcc).
-Godefs compile the given input file with the host compiler and
-then parses the debug info embedded in the assembly output.
-This is far easier than reading system headers on most machines.
-
-The output from godefs is either C output intended for the
-Plan 9 C compiler tool chain (6c, 8c, or 5c) or Go output.
-
-The options are:
-
- -g package
- generate Go output using the given package name.
- In the Go output, struct fields have leading xx_ prefixes
- removed and the first character capitalized (exported).
-
- -c cc
- set the name of the host system's C compiler (default "gcc")
-
- -f cc-arg
- add cc-arg to the command line when invoking the system C compiler
- (for example, -f -m64 to invoke gcc -m64).
- Repeating this option adds multiple flags to the command line.
-
-For example, if this is x.c:
-
- #include <sys/stat.h>
-
- typedef struct timespec $Timespec;
- enum {
- $S_IFMT = S_IFMT,
- $S_IFIFO = S_IFIFO,
- $S_IFCHR = S_IFCHR,
- };
-
-then "godefs x.c" generates:
-
- // godefs x.c
- // MACHINE GENERATED - DO NOT EDIT.
-
- // Constants
- enum {
- S_IFMT = 0xf000,
- S_IFIFO = 0x1000,
- S_IFCHR = 0x2000,
- };
-
- // Types
- #pragma pack on
-
- typedef struct Timespec Timespec;
- struct Timespec {
- int64 tv_sec;
- int64 tv_nsec;
- };
- #pragma pack off
-
-and "godefs -g MyPackage x.c" generates:
-
- // godefs -g MyPackage x.c
- // MACHINE GENERATED - DO NOT EDIT.
-
- package MyPackage
-
- // Constants
- const (
- S_IFMT = 0xf000;
- S_IFIFO = 0x1000;
- S_IFCHR = 0x2000;
- )
-
- // Types
-
- type Timespec struct {
- Sec int64;
- Nsec int64;
- }
-
-*/
-package documentation
diff --git a/src/cmd/godefs/main.c b/src/cmd/godefs/main.c
deleted file mode 100644
index 6a8630179..000000000
--- a/src/cmd/godefs/main.c
+++ /dev/null
@@ -1,606 +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.
-
-// Godefs takes as input a host-compilable C file that includes
-// standard system headers. From that input file, it generates
-// a standalone (no #includes) C or Go file containing equivalent
-// definitions.
-//
-// The input C file is expected to define new types and enumerated
-// constants whose names begin with $ (a legal identifier character
-// in gcc). The output is the standalone definitions of those names,
-// with the $ removed.
-//
-// For example, if this is x.c:
-//
-// #include <sys/stat.h>
-//
-// typedef struct timespec $Timespec;
-// typedef struct stat $Stat;
-// enum {
-// $S_IFMT = S_IFMT,
-// $S_IFIFO = S_IFIFO,
-// $S_IFCHR = S_IFCHR,
-// };
-//
-// then "godefs x.c" generates:
-//
-// // godefs x.c
-//
-// // MACHINE GENERATED - DO NOT EDIT.
-//
-// // Constants
-// enum {
-// S_IFMT = 0xf000,
-// S_IFIFO = 0x1000,
-// S_IFCHR = 0x2000,
-// };
-//
-// // Types
-// #pragma pack on
-//
-// typedef struct Timespec Timespec;
-// struct Timespec {
-// int32 tv_sec;
-// int32 tv_nsec;
-// };
-//
-// typedef struct Stat Stat;
-// struct Stat {
-// int32 st_dev;
-// uint32 st_ino;
-// uint16 st_mode;
-// uint16 st_nlink;
-// uint32 st_uid;
-// uint32 st_gid;
-// int32 st_rdev;
-// Timespec st_atimespec;
-// Timespec st_mtimespec;
-// Timespec st_ctimespec;
-// int64 st_size;
-// int64 st_blocks;
-// int32 st_blksize;
-// uint32 st_flags;
-// uint32 st_gen;
-// int32 st_lspare;
-// int64 st_qspare[2];
-// };
-// #pragma pack off
-//
-// The -g flag to godefs causes it to generate Go output, not C.
-// In the Go output, struct fields have leading xx_ prefixes removed
-// and the first character capitalized (exported).
-//
-// Godefs works by invoking gcc to compile the given input file
-// and then parses the debug info embedded in the assembly output.
-// This is far easier than reading system headers on most machines.
-//
-// The -c flag sets the compiler (default "gcc").
-//
-// The -f flag adds a flag to pass to the compiler (e.g., -f -m64).
-
-#include "a.h"
-
-#ifdef _WIN32
-int
-spawn(char *prog, char **argv)
-{
- return _spawnvp(P_NOWAIT, prog, (const char**)argv);
-}
-#undef waitfor
-void
-waitfor(int pid)
-{
- _cwait(0, pid, 0);
-}
-#else
-int
-spawn(char *prog, char **argv)
-{
- int pid = fork();
- if(pid < 0)
- sysfatal("fork: %r");
- if(pid == 0) {
- exec(argv[0], argv);
- fprint(2, "exec gcc: %r\n");
- exit(1);
- }
- return pid;
-}
-#endif
-
-void
-usage(void)
-{
- fprint(2, "usage: godefs [-g package] [-c cc] [-f cc-arg] [defs.c ...]\n");
- exit(1);
-}
-
-int gotypefmt(Fmt*);
-int ctypefmt(Fmt*);
-int prefixlen(Type*);
-int cutprefix(char*);
-
-Lang go =
-{
- "const (\n",
- "\t%s = %#llx;\n",
- ")\n",
-
- "type",
- "\n",
-
- "type %s struct {\n",
- "type %s struct {\n",
- "\tPad_godefs_%d [%d]byte;\n",
- "}\n",
-
- gotypefmt,
-};
-
-Lang c =
-{
- "enum {\n",
- "\t%s = %#llx,\n",
- "};\n",
-
- "typedef",
- ";\n",
-
- "typedef struct %s %s;\nstruct %s {\n",
- "typedef union %s %s;\nunion %s {\n",
- "\tbyte pad_godefs_%d[%d];\n",
- "};\n",
-
- ctypefmt,
-};
-
-char *pkg;
-
-int oargc;
-char **oargv;
-Lang *lang = &c;
-
-Const *con;
-int ncon;
-
-Type **typ;
-int ntyp;
-
-void
-waitforgcc(void)
-{
- waitpid();
-}
-
-void
-main(int argc, char **argv)
-{
- int p[2], pid, i, j, n, off, npad, prefix;
- char **av, *q, *r, *tofree, *name;
- char nambuf[100];
- Biobuf *bin, *bout;
- Type *t, *tt;
- Field *f;
- int orig_output_fd;
-
- quotefmtinstall();
-
- oargc = argc;
- oargv = argv;
- av = emalloc((30+argc)*sizeof av[0]);
- atexit(waitforgcc);
-
- n = 0;
- av[n++] = "gcc";
- av[n++] = "-fdollars-in-identifiers";
- av[n++] = "-S"; // write assembly
- av[n++] = "-gstabs+"; // include stabs info
- av[n++] = "-o"; // to ...
- av[n++] = "-"; // ... stdout
- av[n++] = "-xc"; // read C
-
- ARGBEGIN{
- case 'g':
- lang = &go;
- pkg = EARGF(usage());
- break;
- case 'c':
- av[0] = EARGF(usage());
- break;
- case 'f':
- av[n++] = EARGF(usage());
- break;
- default:
- usage();
- }ARGEND
-
- if(argc == 0)
- av[n++] = "-";
- else
- av[n++] = argv[0];
- av[n] = nil;
-
- orig_output_fd = dup(1, -1);
- for(i=0; i==0 || i < argc; i++) {
- // Some versions of gcc do not accept -S with multiple files.
- // Run gcc once for each file.
- // Write assembly and stabs debugging to p[1].
- if(pipe(p) < 0)
- sysfatal("pipe: %r");
- dup(p[1], 1);
- close(p[1]);
- if (argc)
- av[n-1] = argv[i];
- pid = spawn(av[0], av);
- dup(orig_output_fd, 1);
-
- // Read assembly, pulling out .stabs lines.
- bin = Bfdopen(p[0], OREAD);
- while((q = Brdstr(bin, '\n', 1)) != nil) {
- // .stabs "float:t(0,12)=r(0,1);4;0;",128,0,0,0
- tofree = q;
- while(*q == ' ' || *q == '\t')
- q++;
- if(strncmp(q, ".stabs", 6) != 0)
- goto Continue;
- q += 6;
- while(*q == ' ' || *q == '\t')
- q++;
- if(*q++ != '\"') {
-Bad:
- sysfatal("cannot parse .stabs line:\n%s", tofree);
- }
-
- r = strchr(q, '\"');
- if(r == nil)
- goto Bad;
- *r++ = '\0';
- if(*r++ != ',')
- goto Bad;
- if(*r < '0' || *r > '9')
- goto Bad;
- if(atoi(r) != 128) // stabs kind = local symbol
- goto Continue;
-
- parsestabtype(q);
-
-Continue:
- free(tofree);
- }
- Bterm(bin);
- waitfor(pid);
- }
- close(orig_output_fd);
-
- // Write defs to standard output.
- bout = Bfdopen(1, OWRITE);
- fmtinstall('T', lang->typefmt);
-
- // Echo original command line in header.
- Bprint(bout, "//");
- for(i=0; i<oargc; i++)
- Bprint(bout, " %q", oargv[i]);
- Bprint(bout, "\n");
- Bprint(bout, "\n");
- Bprint(bout, "// MACHINE GENERATED - DO NOT EDIT.\n");
- Bprint(bout, "\n");
-
- if(pkg)
- Bprint(bout, "package %s\n\n", pkg);
-
- // Constants.
- Bprint(bout, "// Constants\n");
- if(ncon > 0) {
- Bprint(bout, lang->constbegin);
- for(i=0; i<ncon; i++) {
- // Go can handle negative constants,
- // but C enums may not be able to.
- if(lang == &go)
- Bprint(bout, lang->constfmt, con[i].name, con[i].value);
- else
- Bprint(bout, lang->constfmt, con[i].name, con[i].value & 0xFFFFFFFF);
- }
- Bprint(bout, lang->constend);
- }
- Bprint(bout, "\n");
-
- // Types
-
- // push our names down
- for(i=0; i<ntyp; i++) {
- t = typ[i];
- name = t->name;
- while(t && t->kind == Typedef)
- t = t->type;
- if(t)
- t->name = name;
- }
-
- Bprint(bout, "// Types\n");
-
- // Have to turn off structure padding in Plan 9 compiler,
- // mainly because it is more aggressive than gcc tends to be.
- if(lang == &c)
- Bprint(bout, "#pragma pack on\n");
-
- for(i=0; i<ntyp; i++) {
- Bprint(bout, "\n");
- t = typ[i];
- name = t->name;
- while(t && t->kind == Typedef) {
- if(name == nil && t->name != nil) {
- name = t->name;
- if(t->printed)
- break;
- }
- t = t->type;
- }
- if(name == nil && t->name != nil) {
- name = t->name;
- if(t->printed)
- continue;
- t->printed = 1;
- }
- if(name == nil) {
- fprint(2, "unknown name for %T", typ[i]);
- continue;
- }
- if(name[0] == '$')
- name++;
- npad = 0;
- off = 0;
- switch(t->kind) {
- case 0:
- fprint(2, "unknown type definition for %s\n", name);
- break;
- default: // numeric, array, or pointer
- case Array:
- case Ptr:
- Bprint(bout, "%s %lT%s", lang->typdef, name, t, lang->typdefend);
- break;
- case Union:
- // In Go, print union as struct with only first element,
- // padded the rest of the way.
- Bprint(bout, lang->unionbegin, name, name, name);
- goto StructBody;
- case Struct:
- Bprint(bout, lang->structbegin, name, name, name);
- StructBody:
- prefix = 0;
- if(lang == &go)
- prefix = prefixlen(t);
- for(j=0; j<t->nf; j++) {
- f = &t->f[j];
- if(f->type->kind == 0 && f->size <= 64 && (f->size&(f->size-1)) == 0) {
- // unknown type but <= 64 bits and bit size is a power of two.
- // could be enum - make Uint64 and then let it reduce
- tt = emalloc(sizeof *tt);
- *tt = *f->type;
- f->type = tt;
- tt->kind = Uint64;
- while(tt->kind > Uint8 && kindsize[tt->kind] > f->size)
- tt->kind -= 2;
- }
- // padding
- if(t->kind == Struct || lang == &go) {
- if(f->offset%8 != 0 || f->size%8 != 0) {
- fprint(2, "ignoring bitfield %s.%s\n", t->name, f->name);
- continue;
- }
- if(f->offset < off)
- sysfatal("%s: struct fields went backward", t->name);
- if(off < f->offset) {
- Bprint(bout, lang->structpadfmt, npad++, (f->offset - off) / 8);
- off = f->offset;
- }
- off += f->size;
- }
- name = f->name;
- if(cutprefix(name))
- name += prefix;
- if(strcmp(name, "") == 0) {
- snprint(nambuf, sizeof nambuf, "Pad_godefs_%d", npad++);
- name = nambuf;
- }
- Bprint(bout, "\t%#lT;\n", name, f->type);
- if(t->kind == Union && lang == &go)
- break;
- }
- // final padding
- if(t->kind == Struct || lang == &go) {
- if(off/8 < t->size)
- Bprint(bout, lang->structpadfmt, npad++, t->size - off/8);
- }
- Bprint(bout, lang->structend);
- }
- }
- if(lang == &c)
- Bprint(bout, "#pragma pack off\n");
- Bterm(bout);
- exit(0);
-}
-
-char *kindnames[] = {
- "void", // actually unknown, but byte is good for pointers
- "void",
- "int8",
- "uint8",
- "int16",
- "uint16",
- "int32",
- "uint32",
- "int64",
- "uint64",
- "float32",
- "float64",
- "ptr",
- "struct",
- "array",
- "union",
- "typedef",
-};
-
-int
-ctypefmt(Fmt *f)
-{
- char *name, *s;
- Type *t;
-
- name = nil;
- if(f->flags & FmtLong) {
- name = va_arg(f->args, char*);
- if(name == nil || name[0] == '\0')
- name = "_anon_";
- }
- t = va_arg(f->args, Type*);
- while(t && t->kind == Typedef)
- t = t->type;
- switch(t->kind) {
- case Struct:
- case Union:
- // must be named
- s = t->name;
- if(s == nil) {
- fprint(2, "need name for anonymous struct\n");
- goto bad;
- }
- else if(s[0] != '$')
- fprint(2, "need name for struct %s\n", s);
- else
- s++;
- fmtprint(f, "%s", s);
- if(name)
- fmtprint(f, " %s", name);
- break;
-
- case Array:
- if(name)
- fmtprint(f, "%T %s[%d]", t->type, name, t->size);
- else
- fmtprint(f, "%T[%d]", t->type, t->size);
- break;
-
- case Ptr:
- if(name)
- fmtprint(f, "%T *%s", t->type, name);
- else
- fmtprint(f, "%T*", t->type);
- break;
-
- default:
- fmtprint(f, "%s", kindnames[t->kind]);
- if(name)
- fmtprint(f, " %s", name);
- break;
-
- bad:
- if(name)
- fmtprint(f, "byte %s[%d]", name, t->size);
- else
- fmtprint(f, "byte[%d]", t->size);
- break;
- }
-
- return 0;
-}
-
-int
-gotypefmt(Fmt *f)
-{
- char *name, *s;
- Type *t;
-
- if(f->flags & FmtLong) {
- name = va_arg(f->args, char*);
- if('a' <= name[0] && name[0] <= 'z')
- name[0] += 'A' - 'a';
- if(name[0] == '_' && (f->flags & FmtSharp))
- fmtprint(f, "X");
- fmtprint(f, "%s ", name);
- }
- t = va_arg(f->args, Type*);
- while(t && t->kind == Typedef)
- t = t->type;
-
- switch(t->kind) {
- case Struct:
- case Union:
- // must be named
- s = t->name;
- if(s == nil) {
- fprint(2, "need name for anonymous struct\n");
- fmtprint(f, "STRUCT");
- }
- else if(s[0] != '$') {
- fprint(2, "warning: missing name for struct %s\n", s);
- fmtprint(f, "[%d]byte /* %s */", t->size, s);
- } else
- fmtprint(f, "%s", s+1);
- break;
-
- case Array:
- fmtprint(f, "[%d]%T", t->size, t->type);
- break;
-
- case Ptr:
- fmtprint(f, "*%T", t->type);
- break;
-
- default:
- s = kindnames[t->kind];
- if(strcmp(s, "void") == 0)
- s = "byte";
- fmtprint(f, "%s", s);
- }
-
- return 0;
-}
-
-// Is this the kind of name we should cut a prefix from?
-// The rule is that the name cannot begin with underscore
-// and must have an underscore eventually.
-int
-cutprefix(char *name)
-{
- char *p;
-
- // special case: orig_ in register struct
- if(strncmp(name, "orig_", 5) == 0)
- return 0;
-
- for(p=name; *p; p++) {
- if(*p == '_')
- return p-name > 0;
- }
- return 0;
-}
-
-// Figure out common struct prefix len
-int
-prefixlen(Type *t)
-{
- int i;
- int len;
- char *p, *name;
- Field *f;
-
- len = 0;
- name = nil;
- for(i=0; i<t->nf; i++) {
- f = &t->f[i];
- if(!cutprefix(f->name))
- continue;
- p = strchr(f->name, '_');
- if(p == nil)
- return 0;
- if(name == nil) {
- name = f->name;
- len = p+1 - name;
- }
- else if(strncmp(f->name, name, len) != 0)
- return 0;
- }
- return len;
-}
diff --git a/src/cmd/godefs/stabs.c b/src/cmd/godefs/stabs.c
deleted file mode 100644
index 2c3d431b8..000000000
--- a/src/cmd/godefs/stabs.c
+++ /dev/null
@@ -1,456 +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.
-
-// Parse stabs debug info.
-
-#include "a.h"
-
-int stabsdebug = 1;
-
-// Hash table for type lookup by number.
-Type *hash[1024];
-
-// Look up type by number pair.
-// TODO(rsc): Iant points out that n1 and n2 are always small and dense,
-// so an array of arrays would be a better representation.
-Type*
-typebynum(uint n1, uint n2)
-{
- uint h;
- Type *t;
-
- h = (n1*53+n2) % nelem(hash);
- for(t=hash[h]; t; t=t->next)
- if(t->n1 == n1 && t->n2 == n2)
- return t;
- t = emalloc(sizeof *t);
- t->next = hash[h];
- hash[h] = t;
- t->n1 = n1;
- t->n2 = n2;
- return t;
-}
-
-// Parse name and colon from *pp, leaving copy in *sp.
-static int
-parsename(char **pp, char **sp)
-{
- char *p;
- char *s;
-
- p = *pp;
- while(*p != '\0' && *p != ':')
- p++;
- if(*p == '\0') {
- fprint(2, "parsename expected colon\n");
- return -1;
- }
- s = emalloc(p - *pp + 1);
- memmove(s, *pp, p - *pp);
- *sp = s;
- *pp = p+1;
- return 0;
-}
-
-// Parse single number from *pp.
-static int
-parsenum1(char **pp, vlong *np)
-{
- char *p;
-
- p = *pp;
- if(*p != '-' && (*p < '0' || *p > '9')) {
- fprint(2, "parsenum expected minus or digit\n");
- return -1;
- }
- *np = strtoll(p, pp, 10);
- return 0;
-}
-
-// Parse type number - either single number or (n1, n2).
-static int
-parsetypenum(char **pp, vlong *n1p, vlong *n2p)
-{
- char *p;
-
- p = *pp;
- if(*p == '(') {
- p++;
- if(parsenum1(&p, n1p) < 0)
- return -1;
- if(*p++ != ',') {
- if(stabsdebug)
- fprint(2, "parsetypenum expected comma\n");
- return -1;
- }
- if(parsenum1(&p, n2p) < 0)
- return -1;
- if(*p++ != ')') {
- if(stabsdebug)
- fprint(2, "parsetypenum expected right paren\n");
- return -1;
- }
- *pp = p;
- return 0;
- }
-
- if(parsenum1(&p, n1p) < 0)
- return -1;
- *n2p = 0;
- *pp = p;
- return 0;
-}
-
-// Written to parse max/min of vlong correctly.
-static vlong
-parseoctal(char **pp)
-{
- char *p;
- vlong n;
-
- p = *pp;
- if(*p++ != '0')
- return 0;
- n = 0;
- while(*p >= '0' && *p <= '9')
- n = n << 3 | *p++ - '0';
- *pp = p;
- return n;
-}
-
-// Integer types are represented in stabs as a "range"
-// type with a lo and a hi value. The lo and hi used to
-// be lo and hi for the type, but there are now odd
-// extensions for floating point and 64-bit numbers.
-//
-// Have to keep signs separate from values because
-// Int64's lo is -0.
-typedef struct Intrange Intrange;
-struct Intrange
-{
- vlong lo;
- vlong hi;
- int kind;
-};
-
-Intrange intranges[] = {
- 0, 127, Int8, // char
- -128, 127, Int8, // signed char
- 0, 255, Uint8,
- -32768, 32767, Int16,
- 0, 65535, Uint16,
- -2147483648LL, 2147483647LL, Int32,
- 0, 4294967295LL, Uint32,
- 1LL << 63, ~(1LL << 63), Int64,
- 0, -1, Uint64,
- 4, 0, Float32,
- 8, 0, Float64,
- 16, 0, Void,
-};
-
-int kindsize[] = {
- 0,
- 0,
- 8,
- 8,
- 16,
- 16,
- 32,
- 32,
- 64,
- 64,
-};
-
-// Parse a single type definition from *pp.
-static Type*
-parsedef(char **pp, char *name)
-{
- char *p;
- Type *t, *tt;
- int i;
- vlong n1, n2, lo, hi;
- Field *f;
- Intrange *r;
-
- p = *pp;
-
- // reference to another type?
- if(isdigit(*p) || *p == '(') {
- if(parsetypenum(&p, &n1, &n2) < 0)
- return nil;
- t = typebynum(n1, n2);
- if(name && t->name == nil) {
- t->name = name;
- // save definitions of names beginning with $
- if(name[0] == '$' && !t->saved) {
- typ = erealloc(typ, (ntyp+1)*sizeof typ[0]);
- typ[ntyp] = t;
- ntyp++;
- }
- }
-
- // is there an =def suffix?
- if(*p == '=') {
- p++;
- tt = parsedef(&p, name);
- if(tt == nil)
- return nil;
-
- if(tt == t) {
- tt->kind = Void;
- } else {
- t->type = tt;
- t->kind = Typedef;
- }
-
- // assign given name, but do not record in typ.
- // assume the name came from a typedef
- // which will be recorded.
- if(name)
- tt->name = name;
- }
-
- *pp = p;
- return t;
- }
-
- // otherwise a type literal. first letter identifies kind
- t = emalloc(sizeof *t);
- switch(*p) {
- default:
- fprint(2, "unknown type char %c in %s\n", *p, p);
- *pp = "";
- return t;
-
- case '@': // type attribute
- while (*++p != ';');
- *pp = ++p;
- return parsedef(pp, nil);
-
- case '*': // pointer
- p++;
- t->kind = Ptr;
- tt = parsedef(&p, nil);
- if(tt == nil)
- return nil;
- t->type = tt;
- break;
-
- case 'a': // array
- p++;
- t->kind = Array;
- // index type
- tt = parsedef(&p, nil);
- if(tt == nil)
- return nil;
- t->size = tt->size;
- // element type
- tt = parsedef(&p, nil);
- if(tt == nil)
- return nil;
- t->type = tt;
- break;
-
- case 'e': // enum type - record $names in con array.
- p++;
- for(;;) {
- if(*p == '\0')
- return nil;
- if(*p == ';') {
- p++;
- break;
- }
- if(parsename(&p, &name) < 0)
- return nil;
- if(parsenum1(&p, &n1) < 0)
- return nil;
- if(name[0] == '$') {
- con = erealloc(con, (ncon+1)*sizeof con[0]);
- name++;
- con[ncon].name = name;
- con[ncon].value = n1;
- ncon++;
- }
- if(*p != ',')
- return nil;
- p++;
- }
- break;
-
- case 'f': // function
- p++;
- if(parsedef(&p, nil) == nil)
- return nil;
- break;
-
- case 'B': // volatile
- case 'k': // const
- ++*pp;
- return parsedef(pp, nil);
-
- case 'r': // sub-range (used for integers)
- p++;
- if(parsedef(&p, nil) == nil)
- return nil;
- // usually, the return from parsedef == t, but not always.
-
- if(*p != ';' || *++p == ';') {
- if(stabsdebug)
- fprint(2, "range expected number: %s\n", p);
- return nil;
- }
- if(*p == '0')
- lo = parseoctal(&p);
- else
- lo = strtoll(p, &p, 10);
- if(*p != ';' || *++p == ';') {
- if(stabsdebug)
- fprint(2, "range expected number: %s\n", p);
- return nil;
- }
- if(*p == '0')
- hi = parseoctal(&p);
- else
- hi = strtoll(p, &p, 10);
- if(*p != ';') {
- if(stabsdebug)
- fprint(2, "range expected trailing semi: %s\n", p);
- return nil;
- }
- p++;
- t->size = hi+1; // might be array size
- for(i=0; i<nelem(intranges); i++) {
- r = &intranges[i];
- if(r->lo == lo && r->hi == hi) {
- t->kind = r->kind;
- break;
- }
- }
- break;
-
- case 's': // struct
- case 'u': // union
- t->kind = Struct;
- if(*p == 'u')
- t->kind = Union;
-
- // assign given name, but do not record in typ.
- // assume the name came from a typedef
- // which will be recorded.
- if(name)
- t->name = name;
- p++;
- if(parsenum1(&p, &n1) < 0)
- return nil;
- t->size = n1;
- for(;;) {
- if(*p == '\0')
- return nil;
- if(*p == ';') {
- p++;
- break;
- }
- t->f = erealloc(t->f, (t->nf+1)*sizeof t->f[0]);
- f = &t->f[t->nf];
- if(parsename(&p, &f->name) < 0)
- return nil;
- f->type = parsedef(&p, nil);
- if(f->type == nil)
- return nil;
- if(*p != ',') {
- fprint(2, "expected comma after def of %s:\n%s\n", f->name, p);
- return nil;
- }
- p++;
- if(parsenum1(&p, &n1) < 0)
- return nil;
- f->offset = n1;
- if(*p != ',') {
- fprint(2, "expected comma after offset of %s:\n%s\n", f->name, p);
- return nil;
- }
- p++;
- if(parsenum1(&p, &n1) < 0)
- return nil;
- f->size = n1;
- if(*p != ';') {
- fprint(2, "expected semi after size of %s:\n%s\n", f->name, p);
- return nil;
- }
-
- while(f->type->kind == Typedef)
- f->type = f->type->type;
-
- // rewrite
- // uint32 x : 8;
- // into
- // uint8 x;
- // hooray for bitfields.
- while(Int16 <= f->type->kind && f->type->kind <= Uint64 && kindsize[f->type->kind] > f->size) {
- tt = emalloc(sizeof *tt);
- *tt = *f->type;
- f->type = tt;
- f->type->kind -= 2;
- }
- p++;
- t->nf++;
- }
- break;
-
- case 'x':
- // reference to struct, union not yet defined.
- p++;
- switch(*p) {
- case 's':
- t->kind = Struct;
- break;
- case 'u':
- t->kind = Union;
- break;
- default:
- fprint(2, "unknown x type char x%c", *p);
- *pp = "";
- return t;
- }
- if(parsename(&p, &t->name) < 0)
- return nil;
- break;
- }
- *pp = p;
- return t;
-}
-
-
-// Parse a stab type in p, saving info in the type hash table
-// and also in the list of recorded types if appropriate.
-void
-parsestabtype(char *p)
-{
- char *p0, *name;
-
- p0 = p;
-
- // p is the quoted string output from gcc -gstabs on a .stabs line.
- // name:t(1,2)
- // name:t(1,2)=def
- if(parsename(&p, &name) < 0) {
- Bad:
- // Use fprint instead of sysfatal to avoid
- // sysfatal's internal buffer size limit.
- fprint(2, "cannot parse stabs type:\n%s\n(at %s)\n", p0, p);
- sysfatal("stabs parse");
- }
- if(*p != 't' && *p != 'T')
- goto Bad;
- p++;
-
- // parse the definition.
- if(name[0] == '\0')
- name = nil;
- if(parsedef(&p, name) == nil)
- goto Bad;
- if(*p != '\0')
- goto Bad;
-}
-
diff --git a/src/cmd/godefs/test.sh b/src/cmd/godefs/test.sh
deleted file mode 100755
index c035af8f4..000000000
--- a/src/cmd/godefs/test.sh
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-eval $(gomake --no-print-directory -f ../../Make.inc go-env)
-
-TMP="testdata_tmp.go"
-TEST="testdata.c"
-GOLDEN="testdata_${GOOS}_${GOARCH}.golden"
-
-case ${GOARCH} in
-"amd64") CCARG="-f-m64";;
-"386") CCARG="-f-m32";;
-*) CCARG="";;
-esac
-
-cleanup() {
- rm ${TMP}
-}
-
-error() {
- cleanup
- echo $1
- exit 1
-}
-
-if [ ! -e ${GOLDEN} ]; then
- echo "skipping - no golden defined for this platform"
- exit
-fi
-
-./godefs -g test ${CCARG} ${TEST} > ${TMP}
-if [ $? != 0 ]; then
- error "Error: Could not run godefs for ${TEST}"
-fi
-
-diff ${TMP} ${GOLDEN}
-if [ $? != 0 ]; then
- error "FAIL: godefs for ${TEST} did not match ${GOLDEN}"
-fi
-
-cleanup
-
-echo "PASS"
diff --git a/src/cmd/godefs/testdata.c b/src/cmd/godefs/testdata.c
deleted file mode 100644
index 3f459c41b..000000000
--- a/src/cmd/godefs/testdata.c
+++ /dev/null
@@ -1,41 +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 <stdint.h>
-
-// Issue 432 - enum fields in struct can cause misaligned struct fields
-typedef enum {
- a
-} T1;
-
-struct T2 {
- uint8_t a;
- T1 b;
- T1 c;
- uint16_t d;
-};
-
-typedef struct T2 T2;
-typedef T2 $T2;
-
-// Issue 1162 - structs with fields named Pad[0-9]+ conflict with field
-// names used by godefs for padding
-struct T3 {
- uint8_t a;
- int Pad0;
-};
-
-typedef struct T3 $T3;
-
-// Issue 1466 - forward references to types in stabs debug info were
-// always treated as enums
-struct T4 {};
-
-struct T5 {
- struct T4 *a;
-};
-
-typedef struct T5 T5;
-typedef struct T4 $T4;
-typedef T5 $T5; \ No newline at end of file
diff --git a/src/cmd/godefs/testdata_darwin_386.golden b/src/cmd/godefs/testdata_darwin_386.golden
deleted file mode 100644
index d929238b0..000000000
--- a/src/cmd/godefs/testdata_darwin_386.golden
+++ /dev/null
@@ -1,31 +0,0 @@
-// ./godefs -g test -f-m32 testdata.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-package test
-
-// Constants
-
-// Types
-
-type T2 struct {
- A uint8;
- Pad_godefs_0 [3]byte;
- B uint32;
- C uint32;
- D uint16;
- Pad_godefs_1 [2]byte;
-}
-
-type T3 struct {
- A uint8;
- Pad_godefs_0 [3]byte;
- Pad0 int32;
-}
-
-type T4 struct {
-}
-
-type T5 struct {
- A *T4;
-}
diff --git a/src/cmd/godefs/testdata_darwin_amd64.golden b/src/cmd/godefs/testdata_darwin_amd64.golden
deleted file mode 100644
index a694f4a73..000000000
--- a/src/cmd/godefs/testdata_darwin_amd64.golden
+++ /dev/null
@@ -1,31 +0,0 @@
-// ./godefs -g test -f-m64 testdata.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-package test
-
-// Constants
-
-// Types
-
-type T2 struct {
- A uint8;
- Pad_godefs_0 [3]byte;
- B uint32;
- C uint32;
- D uint16;
- Pad_godefs_1 [2]byte;
-}
-
-type T3 struct {
- A uint8;
- Pad_godefs_0 [3]byte;
- Pad0 int32;
-}
-
-type T4 struct {
-}
-
-type T5 struct {
- A *T4;
-}
diff --git a/src/cmd/godefs/util.c b/src/cmd/godefs/util.c
deleted file mode 100644
index 18be00453..000000000
--- a/src/cmd/godefs/util.c
+++ /dev/null
@@ -1,36 +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 "a.h"
-
-void*
-emalloc(int n)
-{
- void *p;
-
- p = malloc(n);
- if(p == nil)
- sysfatal("out of memory");
- memset(p, 0, n);
- return p;
-}
-
-char*
-estrdup(char *s)
-{
- s = strdup(s);
- if(s == nil)
- sysfatal("out of memory");
- return s;
-}
-
-void*
-erealloc(void *v, int n)
-{
- v = realloc(v, n);
- if(v == nil)
- sysfatal("out of memory");
- return v;
-}
-
diff --git a/src/cmd/godoc/Makefile b/src/cmd/godoc/Makefile
deleted file mode 100644
index 06a18be70..000000000
--- a/src/cmd/godoc/Makefile
+++ /dev/null
@@ -1,22 +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 ../../Make.inc
-
-TARG=godoc
-GOFILES=\
- codewalk.go\
- dirtrees.go\
- filesystem.go\
- format.go\
- godoc.go\
- index.go\
- main.go\
- mapping.go\
- parser.go\
- snippet.go\
- spec.go\
- utils.go\
-
-include ../../Make.cmd
diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go
deleted file mode 100644
index 50043e2ab..000000000
--- a/src/cmd/godoc/codewalk.go
+++ /dev/null
@@ -1,499 +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.
-
-// The /doc/codewalk/ tree is synthesized from codewalk descriptions,
-// files named $GOROOT/doc/codewalk/*.xml.
-// For an example and a description of the format, see
-// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
-// and see http://localhost:6060/doc/codewalk/codewalk .
-// That page is itself a codewalk; the source code for it is
-// $GOROOT/doc/codewalk/codewalk.xml.
-
-package main
-
-import (
- "container/vector"
- "fmt"
- "http"
- "io"
- "log"
- "os"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "template"
- "utf8"
- "xml"
-)
-
-
-// Handler for /doc/codewalk/ and below.
-func codewalk(w http.ResponseWriter, r *http.Request) {
- relpath := r.URL.Path[len("/doc/codewalk/"):]
- abspath := absolutePath(r.URL.Path[1:], *goroot)
-
- r.ParseForm()
- if f := r.FormValue("fileprint"); f != "" {
- codewalkFileprint(w, r, f)
- return
- }
-
- // If directory exists, serve list of code walks.
- dir, err := fs.Lstat(abspath)
- if err == nil && dir.IsDirectory() {
- codewalkDir(w, r, relpath, abspath)
- return
- }
-
- // If file exists, serve using standard file server.
- if err == nil {
- serveFile(w, r)
- return
- }
-
- // Otherwise append .xml and hope to find
- // a codewalk description.
- cw, err := loadCodewalk(abspath + ".xml")
- if err != nil {
- log.Print(err)
- serveError(w, r, relpath, err)
- return
- }
-
- // Canonicalize the path and redirect if changed
- if redirect(w, r) {
- return
- }
-
- b := applyTemplate(codewalkHTML, "codewalk", cw)
- servePage(w, "Codewalk: "+cw.Title, "", "", b)
-}
-
-
-// A Codewalk represents a single codewalk read from an XML file.
-type Codewalk struct {
- Title string `xml:"attr"`
- File []string
- Step []*Codestep
-}
-
-
-// A Codestep is a single step in a codewalk.
-type Codestep struct {
- // Filled in from XML
- Src string `xml:"attr"`
- Title string `xml:"attr"`
- XML string `xml:"innerxml"`
-
- // Derived from Src; not in XML.
- Err os.Error
- File string
- Lo int
- LoByte int
- Hi int
- HiByte int
- Data []byte
-}
-
-
-// String method for printing in template.
-// Formats file address nicely.
-func (st *Codestep) String() string {
- s := st.File
- if st.Lo != 0 || st.Hi != 0 {
- s += fmt.Sprintf(":%d", st.Lo)
- if st.Lo != st.Hi {
- s += fmt.Sprintf(",%d", st.Hi)
- }
- }
- return s
-}
-
-
-// loadCodewalk reads a codewalk from the named XML file.
-func loadCodewalk(filename string) (*Codewalk, os.Error) {
- f, err := fs.Open(filename)
- if err != nil {
- return nil, err
- }
- defer f.Close()
- cw := new(Codewalk)
- p := xml.NewParser(f)
- p.Entity = xml.HTMLEntity
- err = p.Unmarshal(cw, nil)
- if err != nil {
- return nil, &os.PathError{"parsing", filename, err}
- }
-
- // Compute file list, evaluate line numbers for addresses.
- m := make(map[string]bool)
- for _, st := range cw.Step {
- i := strings.Index(st.Src, ":")
- if i < 0 {
- i = len(st.Src)
- }
- filename := st.Src[0:i]
- data, err := fs.ReadFile(absolutePath(filename, *goroot))
- if err != nil {
- st.Err = err
- continue
- }
- if i < len(st.Src) {
- lo, hi, err := addrToByteRange(st.Src[i+1:], 0, data)
- if err != nil {
- st.Err = err
- continue
- }
- // Expand match to line boundaries.
- for lo > 0 && data[lo-1] != '\n' {
- lo--
- }
- for hi < len(data) && (hi == 0 || data[hi-1] != '\n') {
- hi++
- }
- st.Lo = byteToLine(data, lo)
- st.Hi = byteToLine(data, hi-1)
- }
- st.Data = data
- st.File = filename
- m[filename] = true
- }
-
- // Make list of files
- cw.File = make([]string, len(m))
- i := 0
- for f := range m {
- cw.File[i] = f
- i++
- }
- sort.Strings(cw.File)
-
- return cw, nil
-}
-
-
-// codewalkDir serves the codewalk directory listing.
-// It scans the directory for subdirectories or files named *.xml
-// and prepares a table.
-func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string) {
- type elem struct {
- Name string
- Title string
- }
-
- dir, err := fs.ReadDir(abspath)
- if err != nil {
- log.Print(err)
- serveError(w, r, relpath, err)
- return
- }
- var v vector.Vector
- for _, fi := range dir {
- name := fi.Name()
- if fi.IsDirectory() {
- v.Push(&elem{name + "/", ""})
- } else if strings.HasSuffix(name, ".xml") {
- cw, err := loadCodewalk(abspath + "/" + name)
- if err != nil {
- continue
- }
- v.Push(&elem{name[0 : len(name)-len(".xml")], cw.Title})
- }
- }
-
- b := applyTemplate(codewalkdirHTML, "codewalkdir", v)
- servePage(w, "Codewalks", "", "", b)
-}
-
-
-// codewalkFileprint serves requests with ?fileprint=f&lo=lo&hi=hi.
-// The filename f has already been retrieved and is passed as an argument.
-// Lo and hi are the numbers of the first and last line to highlight
-// in the response. This format is used for the middle window pane
-// of the codewalk pages. It is a separate iframe and does not get
-// the usual godoc HTML wrapper.
-func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
- abspath := absolutePath(f, *goroot)
- data, err := fs.ReadFile(abspath)
- if err != nil {
- log.Print(err)
- serveError(w, r, f, err)
- return
- }
- lo, _ := strconv.Atoi(r.FormValue("lo"))
- hi, _ := strconv.Atoi(r.FormValue("hi"))
- if hi < lo {
- hi = lo
- }
- lo = lineToByte(data, lo)
- hi = lineToByte(data, hi+1)
-
- // Put the mark 4 lines before lo, so that the iframe
- // shows a few lines of context before the highlighted
- // section.
- n := 4
- mark := lo
- for ; mark > 0 && n > 0; mark-- {
- if data[mark-1] == '\n' {
- if n--; n == 0 {
- break
- }
- }
- }
-
- io.WriteString(w, `<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`)
- template.HTMLEscape(w, data[0:mark])
- io.WriteString(w, "<a name='mark'></a>")
- template.HTMLEscape(w, data[mark:lo])
- if lo < hi {
- io.WriteString(w, "<div class='codewalkhighlight'>")
- template.HTMLEscape(w, data[lo:hi])
- io.WriteString(w, "</div>")
- }
- template.HTMLEscape(w, data[hi:])
- io.WriteString(w, "</pre>")
-}
-
-
-// addrToByte evaluates the given address starting at offset start in data.
-// It returns the lo and hi byte offset of the matched region within data.
-// See http://plan9.bell-labs.com/sys/doc/sam/sam.html Table II
-// for details on the syntax.
-func addrToByteRange(addr string, start int, data []byte) (lo, hi int, err os.Error) {
- var (
- dir byte
- prevc byte
- charOffset bool
- )
- lo = start
- hi = start
- for addr != "" && err == nil {
- c := addr[0]
- switch c {
- default:
- err = os.NewError("invalid address syntax near " + string(c))
- case ',':
- if len(addr) == 1 {
- hi = len(data)
- } else {
- _, hi, err = addrToByteRange(addr[1:], hi, data)
- }
- return
-
- case '+', '-':
- if prevc == '+' || prevc == '-' {
- lo, hi, err = addrNumber(data, lo, hi, prevc, 1, charOffset)
- }
- dir = c
-
- case '$':
- lo = len(data)
- hi = len(data)
- if len(addr) > 1 {
- dir = '+'
- }
-
- case '#':
- charOffset = true
-
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- var i int
- for i = 1; i < len(addr); i++ {
- if addr[i] < '0' || addr[i] > '9' {
- break
- }
- }
- var n int
- n, err = strconv.Atoi(addr[0:i])
- if err != nil {
- break
- }
- lo, hi, err = addrNumber(data, lo, hi, dir, n, charOffset)
- dir = 0
- charOffset = false
- prevc = c
- addr = addr[i:]
- continue
-
- case '/':
- var i, j int
- Regexp:
- for i = 1; i < len(addr); i++ {
- switch addr[i] {
- case '\\':
- i++
- case '/':
- j = i + 1
- break Regexp
- }
- }
- if j == 0 {
- j = i
- }
- pattern := addr[1:i]
- lo, hi, err = addrRegexp(data, lo, hi, dir, pattern)
- prevc = c
- addr = addr[j:]
- continue
- }
- prevc = c
- addr = addr[1:]
- }
-
- if err == nil && dir != 0 {
- lo, hi, err = addrNumber(data, lo, hi, dir, 1, charOffset)
- }
- if err != nil {
- return 0, 0, err
- }
- return lo, hi, nil
-}
-
-
-// addrNumber applies the given dir, n, and charOffset to the address lo, hi.
-// dir is '+' or '-', n is the count, and charOffset is true if the syntax
-// used was #n. Applying +n (or +#n) means to advance n lines
-// (or characters) after hi. Applying -n (or -#n) means to back up n lines
-// (or characters) before lo.
-// The return value is the new lo, hi.
-func addrNumber(data []byte, lo, hi int, dir byte, n int, charOffset bool) (int, int, os.Error) {
- switch dir {
- case 0:
- lo = 0
- hi = 0
- fallthrough
-
- case '+':
- if charOffset {
- pos := hi
- for ; n > 0 && pos < len(data); n-- {
- _, size := utf8.DecodeRune(data[pos:])
- pos += size
- }
- if n == 0 {
- return pos, pos, nil
- }
- break
- }
- // find next beginning of line
- if hi > 0 {
- for hi < len(data) && data[hi-1] != '\n' {
- hi++
- }
- }
- lo = hi
- if n == 0 {
- return lo, hi, nil
- }
- for ; hi < len(data); hi++ {
- if data[hi] != '\n' {
- continue
- }
- switch n--; n {
- case 1:
- lo = hi + 1
- case 0:
- return lo, hi + 1, nil
- }
- }
-
- case '-':
- if charOffset {
- // Scan backward for bytes that are not UTF-8 continuation bytes.
- pos := lo
- for ; pos > 0 && n > 0; pos-- {
- if data[pos]&0xc0 != 0x80 {
- n--
- }
- }
- if n == 0 {
- return pos, pos, nil
- }
- break
- }
- // find earlier beginning of line
- for lo > 0 && data[lo-1] != '\n' {
- lo--
- }
- hi = lo
- if n == 0 {
- return lo, hi, nil
- }
- for ; lo >= 0; lo-- {
- if lo > 0 && data[lo-1] != '\n' {
- continue
- }
- switch n--; n {
- case 1:
- hi = lo
- case 0:
- return lo, hi, nil
- }
- }
- }
-
- return 0, 0, os.NewError("address out of range")
-}
-
-
-// addrRegexp searches for pattern in the given direction starting at lo, hi.
-// The direction dir is '+' (search forward from hi) or '-' (search backward from lo).
-// Backward searches are unimplemented.
-func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, os.Error) {
- re, err := regexp.Compile(pattern)
- if err != nil {
- return 0, 0, err
- }
- if dir == '-' {
- // Could implement reverse search using binary search
- // through file, but that seems like overkill.
- return 0, 0, os.NewError("reverse search not implemented")
- }
- m := re.FindIndex(data[hi:])
- if len(m) > 0 {
- m[0] += hi
- m[1] += hi
- } else if hi > 0 {
- // No match. Wrap to beginning of data.
- m = re.FindIndex(data)
- }
- if len(m) == 0 {
- return 0, 0, os.NewError("no match for " + pattern)
- }
- return m[0], m[1], nil
-}
-
-
-// lineToByte returns the byte index of the first byte of line n.
-// Line numbers begin at 1.
-func lineToByte(data []byte, n int) int {
- if n <= 1 {
- return 0
- }
- n--
- for i, c := range data {
- if c == '\n' {
- if n--; n == 0 {
- return i + 1
- }
- }
- }
- return len(data)
-}
-
-
-// byteToLine returns the number of the line containing the byte at index i.
-func byteToLine(data []byte, i int) int {
- l := 1
- for j, c := range data {
- if j == i {
- return l
- }
- if c == '\n' {
- l++
- }
- }
- return l
-}
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go
deleted file mode 100644
index e98e93a46..000000000
--- a/src/cmd/godoc/dirtrees.go
+++ /dev/null
@@ -1,358 +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.
-
-// This file contains the code dealing with package directory trees.
-
-package main
-
-import (
- "bytes"
- "go/doc"
- "go/parser"
- "go/token"
- "log"
- "path/filepath"
- "strings"
- "unicode"
-)
-
-
-type Directory struct {
- Depth int
- Path string // includes Name
- Name string
- Text string // package documentation, if any
- Dirs []*Directory // subdirectories
-}
-
-
-func isGoFile(fi FileInfo) bool {
- name := fi.Name()
- return fi.IsRegular() &&
- len(name) > 0 && name[0] != '.' && // ignore .files
- filepath.Ext(name) == ".go"
-}
-
-
-func isPkgFile(fi FileInfo) bool {
- return isGoFile(fi) &&
- !strings.HasSuffix(fi.Name(), "_test.go") // ignore test files
-}
-
-
-func isPkgDir(fi FileInfo) bool {
- name := fi.Name()
- return fi.IsDirectory() && len(name) > 0 &&
- name[0] != '_' && name[0] != '.' // ignore _files and .files
-}
-
-
-func firstSentence(s string) string {
- i := -1 // index+1 of first terminator (punctuation ending a sentence)
- j := -1 // index+1 of first terminator followed by white space
- prev := 'A'
- for k, ch := range s {
- k1 := k + 1
- if ch == '.' || ch == '!' || ch == '?' {
- if i < 0 {
- i = k1 // first terminator
- }
- if k1 < len(s) && s[k1] <= ' ' {
- if j < 0 {
- j = k1 // first terminator followed by white space
- }
- if !unicode.IsUpper(prev) {
- j = k1
- break
- }
- }
- }
- prev = ch
- }
-
- if j < 0 {
- // use the next best terminator
- j = i
- if j < 0 {
- // no terminator at all, use the entire string
- j = len(s)
- }
- }
-
- return s[0:j]
-}
-
-
-type treeBuilder struct {
- pathFilter func(string) bool
- maxDepth int
-}
-
-
-func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth int) *Directory {
- if b.pathFilter != nil && !b.pathFilter(path) {
- return nil
- }
-
- if depth >= b.maxDepth {
- // return a dummy directory so that the parent directory
- // doesn't get discarded just because we reached the max
- // directory depth
- return &Directory{depth, path, name, "", nil}
- }
-
- list, err := fs.ReadDir(path)
- if err != nil {
- // newDirTree is called with a path that should be a package
- // directory; errors here should not happen, but if they do,
- // we want to know about them
- log.Printf("ReadDir(%s): %s", path, err)
- }
-
- // determine number of subdirectories and if there are package files
- ndirs := 0
- hasPkgFiles := false
- var synopses [4]string // prioritized package documentation (0 == highest priority)
- for _, d := range list {
- switch {
- case isPkgDir(d):
- ndirs++
- case isPkgFile(d):
- // looks like a package file, but may just be a file ending in ".go";
- // don't just count it yet (otherwise we may end up with hasPkgFiles even
- // though the directory doesn't contain any real package files - was bug)
- if synopses[0] == "" {
- // no "optimal" package synopsis yet; continue to collect synopses
- file, err := parser.ParseFile(fset, filepath.Join(path, d.Name()), nil,
- parser.ParseComments|parser.PackageClauseOnly)
- if err == nil {
- hasPkgFiles = true
- if file.Doc != nil {
- // prioritize documentation
- i := -1
- switch file.Name.Name {
- case name:
- i = 0 // normal case: directory name matches package name
- case fakePkgName:
- i = 1 // synopses for commands
- case "main":
- i = 2 // directory contains a main package
- default:
- i = 3 // none of the above
- }
- if 0 <= i && i < len(synopses) && synopses[i] == "" {
- synopses[i] = firstSentence(doc.CommentText(file.Doc))
- }
- }
- }
- }
- }
- }
-
- // create subdirectory tree
- var dirs []*Directory
- if ndirs > 0 {
- dirs = make([]*Directory, ndirs)
- i := 0
- for _, d := range list {
- if isPkgDir(d) {
- name := d.Name()
- dd := b.newDirTree(fset, filepath.Join(path, name), name, depth+1)
- if dd != nil {
- dirs[i] = dd
- i++
- }
- }
- }
- dirs = dirs[0:i]
- }
-
- // if there are no package files and no subdirectories
- // containing package files, ignore the directory
- if !hasPkgFiles && len(dirs) == 0 {
- return nil
- }
-
- // select the highest-priority synopsis for the directory entry, if any
- synopsis := ""
- for _, synopsis = range synopses {
- if synopsis != "" {
- break
- }
- }
-
- return &Directory{depth, path, name, synopsis, dirs}
-}
-
-
-// newDirectory creates a new package directory tree with at most maxDepth
-// levels, anchored at root. The result tree is pruned such that it only
-// contains directories that contain package files or that contain
-// subdirectories containing package files (transitively). If a non-nil
-// pathFilter is provided, directory paths additionally must be accepted
-// by the filter (i.e., pathFilter(path) must be true). If a value >= 0 is
-// provided for maxDepth, nodes at larger depths are pruned as well; they
-// are assumed to contain package files even if their contents are not known
-// (i.e., in this case the tree may contain directories w/o any package files).
-//
-func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Directory {
- // The root could be a symbolic link so use Stat not Lstat.
- d, err := fs.Stat(root)
- // If we fail here, report detailed error messages; otherwise
- // is is hard to see why a directory tree was not built.
- switch {
- case err != nil:
- log.Printf("newDirectory(%s): %s", root, err)
- return nil
- case !isPkgDir(d):
- log.Printf("newDirectory(%s): not a package directory", root)
- return nil
- }
- if maxDepth < 0 {
- maxDepth = 1e6 // "infinity"
- }
- b := treeBuilder{pathFilter, maxDepth}
- // the file set provided is only for local parsing, no position
- // information escapes and thus we don't need to save the set
- return b.newDirTree(token.NewFileSet(), root, d.Name(), 0)
-}
-
-
-func (dir *Directory) writeLeafs(buf *bytes.Buffer) {
- if dir != nil {
- if len(dir.Dirs) == 0 {
- buf.WriteString(dir.Path)
- buf.WriteByte('\n')
- return
- }
-
- for _, d := range dir.Dirs {
- d.writeLeafs(buf)
- }
- }
-}
-
-
-func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
- if dir != nil {
- if !skipRoot {
- c <- dir
- }
- for _, d := range dir.Dirs {
- d.walk(c, false)
- }
- }
-}
-
-
-func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
- c := make(chan *Directory)
- go func() {
- dir.walk(c, skipRoot)
- close(c)
- }()
- return c
-}
-
-
-func (dir *Directory) lookupLocal(name string) *Directory {
- for _, d := range dir.Dirs {
- if d.Name == name {
- return d
- }
- }
- return nil
-}
-
-
-// lookup looks for the *Directory for a given path, relative to dir.
-func (dir *Directory) lookup(path string) *Directory {
- d := strings.Split(dir.Path, string(filepath.Separator))
- p := strings.Split(path, string(filepath.Separator))
- i := 0
- for i < len(d) {
- if i >= len(p) || d[i] != p[i] {
- return nil
- }
- i++
- }
- for dir != nil && i < len(p) {
- dir = dir.lookupLocal(p[i])
- i++
- }
- return dir
-}
-
-
-// DirEntry describes a directory entry. The Depth and Height values
-// are useful for presenting an entry in an indented fashion.
-//
-type DirEntry struct {
- Depth int // >= 0
- Height int // = DirList.MaxHeight - Depth, > 0
- Path string // includes Name, relative to DirList root
- Name string
- Synopsis string
-}
-
-
-type DirList struct {
- MaxHeight int // directory tree height, > 0
- List []DirEntry
-}
-
-
-// listing creates a (linear) directory listing from a directory tree.
-// If skipRoot is set, the root directory itself is excluded from the list.
-//
-func (root *Directory) listing(skipRoot bool) *DirList {
- if root == nil {
- return nil
- }
-
- // determine number of entries n and maximum height
- n := 0
- minDepth := 1 << 30 // infinity
- maxDepth := 0
- for d := range root.iter(skipRoot) {
- n++
- if minDepth > d.Depth {
- minDepth = d.Depth
- }
- if maxDepth < d.Depth {
- maxDepth = d.Depth
- }
- }
- maxHeight := maxDepth - minDepth + 1
-
- if n == 0 {
- return nil
- }
-
- // create list
- list := make([]DirEntry, n)
- i := 0
- for d := range root.iter(skipRoot) {
- p := &list[i]
- p.Depth = d.Depth - minDepth
- p.Height = maxHeight - p.Depth
- // the path is relative to root.Path - remove the root.Path
- // prefix (the prefix should always be present but avoid
- // crashes and check)
- path := d.Path
- if strings.HasPrefix(d.Path, root.Path) {
- path = d.Path[len(root.Path):]
- }
- // remove trailing separator if any - path must be relative
- if len(path) > 0 && path[0] == filepath.Separator {
- path = path[1:]
- }
- p.Path = path
- p.Name = d.Name
- p.Synopsis = d.Text
- i++
- }
-
- return &DirList{maxHeight, list}
-}
diff --git a/src/cmd/godoc/doc.go b/src/cmd/godoc/doc.go
deleted file mode 100644
index 26d436d72..000000000
--- a/src/cmd/godoc/doc.go
+++ /dev/null
@@ -1,111 +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.
-
-/*
-
-Godoc extracts and generates documentation for Go programs.
-
-It has two modes.
-
-Without the -http flag, it runs in command-line mode and prints plain text
-documentation to standard output and exits. If the -src flag is specified,
-godoc prints the exported interface of a package in Go source form, or the
-implementation of a specific exported language entity:
-
- godoc fmt # documentation for package fmt
- godoc fmt Printf # documentation for fmt.Printf
- godoc -src fmt # fmt package interface in Go source form
- godoc -src fmt Printf # implementation of fmt.Printf
-
-In command-line mode, the -q flag enables search queries against a godoc running
-as a webserver. If no explicit server address is specified with the -server flag,
-godoc first tries localhost:6060 and then http://golang.org.
-
- godoc -q Reader Writer
- godoc -q math.Sin
- godoc -server=:6060 -q sin
-
-With the -http flag, it runs as a web server and presents the documentation as a
-web page.
-
- godoc -http=:6060
-
-Usage:
- godoc [flag] package [name ...]
-
-The flags are:
- -v
- verbose mode
- -q
- arguments are considered search queries: a legal query is a
- single identifier (such as ToLower) or a qualified identifier
- (such as math.Sin).
- -src
- print (exported) source in command-line mode
- -tabwidth=4
- width of tabs in units of spaces
- -timestamps=true
- show timestamps with directory listings
- -index
- enable identifier and full text search index
- (no search box is shown if -index is not set)
- -maxresults=10000
- maximum number of full text search results shown
- (no full text index is built if maxresults <= 0)
- -path=""
- additional package directories (colon-separated)
- -html
- print HTML in command-line mode
- -goroot=$GOROOT
- Go root directory
- -http=addr
- HTTP service address (e.g., '127.0.0.1:6060' or just ':6060')
- -server=addr
- webserver address for command line searches
- -sync="command"
- if this and -sync_minutes are set, run the argument as a
- command every sync_minutes; it is intended to update the
- repository holding the source files.
- -sync_minutes=0
- sync interval in minutes; sync is disabled if <= 0
- -filter=""
- filter file containing permitted package directory paths
- -filter_minutes=0
- filter file update interval in minutes; update is disabled if <= 0
-
-The -path flag accepts a list of colon-separated paths; unrooted paths are relative
-to the current working directory. Each path is considered as an additional root for
-packages in order of appearance. The last (absolute) path element is the prefix for
-the package path. For instance, given the flag value:
-
- path=".:/home/bar:/public"
-
-for a godoc started in /home/user/godoc, absolute paths are mapped to package paths
-as follows:
-
- /home/user/godoc/x -> godoc/x
- /home/bar/x -> bar/x
- /public/x -> public/x
-
-Paths provided via -path may point to very large file systems that contain
-non-Go files. Creating the subtree of directories with Go packages may take
-a long amount of time. A file containing newline-separated directory paths
-may be provided with the -filter flag; if it exists, only directories
-on those paths are considered. If -filter_minutes is set, the filter_file is
-updated regularly by walking the entire directory tree.
-
-When godoc runs as a web server, it creates a search index from all .go files
-under -goroot (excluding files starting with .). The index is created at startup
-and is automatically updated every time the -sync command terminates with exit
-status 0, indicating that files have changed.
-
-If the sync exit status is 1, godoc assumes that it succeeded without errors
-but that no files changed; the index is not updated in this case.
-
-In all other cases, sync is assumed to have failed and godoc backs off running
-sync exponentially (up to 1 day). As soon as sync succeeds again (exit status 0
-or 1), the normal sync rhythm is re-established.
-
-*/
-package documentation
diff --git a/src/cmd/godoc/filesystem.go b/src/cmd/godoc/filesystem.go
deleted file mode 100644
index bf68378d4..000000000
--- a/src/cmd/godoc/filesystem.go
+++ /dev/null
@@ -1,96 +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.
-
-// This file defines abstract file system access.
-
-package main
-
-import (
- "io"
- "io/ioutil"
- "os"
-)
-
-
-// The FileInfo interface provides access to file information.
-type FileInfo interface {
- Name() string
- Size() int64
- IsRegular() bool
- IsDirectory() bool
-}
-
-
-// The FileSystem interface specifies the methods godoc is using
-// to access the file system for which it serves documentation.
-type FileSystem interface {
- Open(path string) (io.ReadCloser, os.Error)
- Lstat(path string) (FileInfo, os.Error)
- Stat(path string) (FileInfo, os.Error)
- ReadDir(path string) ([]FileInfo, os.Error)
- ReadFile(path string) ([]byte, os.Error)
-}
-
-
-// ----------------------------------------------------------------------------
-// OS-specific FileSystem implementation
-
-var OS FileSystem = osFS{}
-
-
-// osFI is the OS-specific implementation of FileInfo.
-type osFI struct {
- *os.FileInfo
-}
-
-
-func (fi osFI) Name() string {
- return fi.FileInfo.Name
-}
-
-
-func (fi osFI) Size() int64 {
- if fi.IsDirectory() {
- return 0
- }
- return fi.FileInfo.Size
-}
-
-
-// osFS is the OS-specific implementation of FileSystem
-type osFS struct{}
-
-func (osFS) Open(path string) (io.ReadCloser, os.Error) {
- return os.Open(path)
-}
-
-
-func (osFS) Lstat(path string) (FileInfo, os.Error) {
- fi, err := os.Lstat(path)
- return osFI{fi}, err
-}
-
-
-func (osFS) Stat(path string) (FileInfo, os.Error) {
- fi, err := os.Stat(path)
- return osFI{fi}, err
-}
-
-
-func (osFS) ReadDir(path string) ([]FileInfo, os.Error) {
- l0, err := ioutil.ReadDir(path)
- if err != nil {
- return nil, err
- }
- l1 := make([]FileInfo, len(l0))
- for i, e := range l0 {
- l1[i] = osFI{e}
- }
- return l1, nil
-}
-
-
-func (osFS) ReadFile(path string) ([]byte, os.Error) {
- return ioutil.ReadFile(path)
-}
diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go
deleted file mode 100644
index 7e6470846..000000000
--- a/src/cmd/godoc/format.go
+++ /dev/null
@@ -1,373 +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.
-
-// This file implements FormatSelections and FormatText.
-// FormatText is used to HTML-format Go and non-Go source
-// text with line numbers and highlighted sections. It is
-// built on top of FormatSelections, a generic formatter
-// for "selected" text.
-
-package main
-
-import (
- "fmt"
- "go/scanner"
- "go/token"
- "io"
- "regexp"
- "strconv"
- "template"
-)
-
-
-// ----------------------------------------------------------------------------
-// Implementation of FormatSelections
-
-// A Selection is a function returning offset pairs []int{a, b}
-// describing consecutive non-overlapping text segments [a, b).
-// If there are no more segments, a Selection must return nil.
-//
-// TODO It's more efficient to return a pair (a, b int) instead
-// of creating lots of slices. Need to determine how to
-// indicate the end of a Selection.
-//
-type Selection func() []int
-
-
-// A LinkWriter writes some start or end "tag" to w for the text offset offs.
-// It is called by FormatSelections at the start or end of each link segment.
-//
-type LinkWriter func(w io.Writer, offs int, start bool)
-
-
-// A SegmentWriter formats a text according to selections and writes it to w.
-// The selections parameter is a bit set indicating which selections provided
-// to FormatSelections overlap with the text segment: If the n'th bit is set
-// in selections, the n'th selection provided to FormatSelections is overlapping
-// with the text.
-//
-type SegmentWriter func(w io.Writer, text []byte, selections int)
-
-
-// FormatSelections takes a text and writes it to w using link and segment
-// writers lw and sw as follows: lw is invoked for consecutive segment starts
-// and ends as specified through the links selection, and sw is invoked for
-// consecutive segments of text overlapped by the same selections as specified
-// by selections. The link writer lw may be nil, in which case the links
-// Selection is ignored.
-//
-func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection, sw SegmentWriter, selections ...Selection) {
- if lw != nil {
- selections = append(selections, links)
- }
-
- // compute the sequence of consecutive segment changes
- changes := newMerger(selections)
-
- // The i'th bit in bitset indicates that the text
- // at the current offset is covered by selections[i].
- bitset := 0
- lastOffs := 0
-
- // Text segments are written in a delayed fashion
- // such that consecutive segments belonging to the
- // same selection can be combined (peephole optimization).
- // last describes the last segment which has not yet been written.
- var last struct {
- begin, end int // valid if begin < end
- bitset int
- }
-
- // flush writes the last delayed text segment
- flush := func() {
- if last.begin < last.end {
- sw(w, text[last.begin:last.end], last.bitset)
- }
- last.begin = last.end // invalidate last
- }
-
- // segment runs the segment [lastOffs, end) with the selection
- // indicated by bitset through the segment peephole optimizer.
- segment := func(end int) {
- if lastOffs < end { // ignore empty segments
- if last.end != lastOffs || last.bitset != bitset {
- // the last segment is not adjacent to or
- // differs from the new one
- flush()
- // start a new segment
- last.begin = lastOffs
- }
- last.end = end
- last.bitset = bitset
- }
- }
-
- for {
- // get the next segment change
- index, offs, start := changes.next()
- if index < 0 || offs > len(text) {
- // no more segment changes or the next change
- // is past the end of the text - we're done
- break
- }
- // determine the kind of segment change
- if index == len(selections)-1 {
- // we have a link segment change:
- // format the previous selection segment, write the
- // link tag and start a new selection segment
- segment(offs)
- flush()
- lastOffs = offs
- lw(w, offs, start)
- } else {
- // we have a selection change:
- // format the previous selection segment, determine
- // the new selection bitset and start a new segment
- segment(offs)
- lastOffs = offs
- mask := 1 << uint(index)
- if start {
- bitset |= mask
- } else {
- bitset &^= mask
- }
- }
- }
- segment(len(text))
- flush()
-}
-
-
-// A merger merges a slice of Selections and produces a sequence of
-// consecutive segment change events through repeated next() calls.
-//
-type merger struct {
- selections []Selection
- segments [][]int // segments[i] is the next segment of selections[i]
-}
-
-
-const infinity int = 2e9
-
-func newMerger(selections []Selection) *merger {
- segments := make([][]int, len(selections))
- for i, sel := range selections {
- segments[i] = []int{infinity, infinity}
- if sel != nil {
- if seg := sel(); seg != nil {
- segments[i] = seg
- }
- }
- }
- return &merger{selections, segments}
-}
-
-
-// next returns the next segment change: index specifies the Selection
-// to which the segment belongs, offs is the segment start or end offset
-// as determined by the start value. If there are no more segment changes,
-// next returns an index value < 0.
-//
-func (m *merger) next() (index, offs int, start bool) {
- // find the next smallest offset where a segment starts or ends
- offs = infinity
- index = -1
- for i, seg := range m.segments {
- switch {
- case seg[0] < offs:
- offs = seg[0]
- index = i
- start = true
- case seg[1] < offs:
- offs = seg[1]
- index = i
- start = false
- }
- }
- if index < 0 {
- // no offset found => all selections merged
- return
- }
- // offset found - it's either the start or end offset but
- // either way it is ok to consume the start offset: set it
- // to infinity so it won't be considered in the following
- // next call
- m.segments[index][0] = infinity
- if start {
- return
- }
- // end offset found - consume it
- m.segments[index][1] = infinity
- // advance to the next segment for that selection
- seg := m.selections[index]()
- if seg == nil {
- return
- }
- m.segments[index] = seg
- return
-}
-
-
-// ----------------------------------------------------------------------------
-// Implementation of FormatText
-
-// lineSelection returns the line segments for text as a Selection.
-func lineSelection(text []byte) Selection {
- i, j := 0, 0
- return func() (seg []int) {
- // find next newline, if any
- for j < len(text) {
- j++
- if text[j-1] == '\n' {
- break
- }
- }
- if i < j {
- // text[i:j] constitutes a line
- seg = []int{i, j}
- i = j
- }
- return
- }
-}
-
-
-// commentSelection returns the sequence of consecutive comments
-// in the Go src text as a Selection.
-//
-func commentSelection(src []byte) Selection {
- var s scanner.Scanner
- fset := token.NewFileSet()
- file := fset.AddFile("", fset.Base(), len(src))
- s.Init(file, src, nil, scanner.ScanComments+scanner.InsertSemis)
- return func() (seg []int) {
- for {
- pos, tok, lit := s.Scan()
- if tok == token.EOF {
- break
- }
- offs := file.Offset(pos)
- if tok == token.COMMENT {
- seg = []int{offs, offs + len(lit)}
- break
- }
- }
- return
- }
-}
-
-
-// makeSelection is a helper function to make a Selection from a slice of pairs.
-func makeSelection(matches [][]int) Selection {
- return func() (seg []int) {
- if len(matches) > 0 {
- seg = matches[0]
- matches = matches[1:]
- }
- return
- }
-}
-
-
-// regexpSelection computes the Selection for the regular expression expr in text.
-func regexpSelection(text []byte, expr string) Selection {
- var matches [][]int
- if rx, err := regexp.Compile(expr); err == nil {
- matches = rx.FindAllIndex(text, -1)
- }
- return makeSelection(matches)
-}
-
-
-var selRx = regexp.MustCompile(`^([0-9]+):([0-9]+)`)
-
-// rangeSelection computes the Selection for a text range described
-// by the argument str; the range description must match the selRx
-// regular expression.
-//
-func rangeSelection(str string) Selection {
- m := selRx.FindStringSubmatch(str)
- if len(m) >= 2 {
- from, _ := strconv.Atoi(m[1])
- to, _ := strconv.Atoi(m[2])
- if from < to {
- return makeSelection([][]int{{from, to}})
- }
- }
- return nil
-}
-
-
-// Span tags for all the possible selection combinations that may
-// be generated by FormatText. Selections are indicated by a bitset,
-// and the value of the bitset specifies the tag to be used.
-//
-// bit 0: comments
-// bit 1: highlights
-// bit 2: selections
-//
-var startTags = [][]byte{
- /* 000 */ []byte(``),
- /* 001 */ []byte(`<span class="comment">`),
- /* 010 */ []byte(`<span class="highlight">`),
- /* 011 */ []byte(`<span class="highlight-comment">`),
- /* 100 */ []byte(`<span class="selection">`),
- /* 101 */ []byte(`<span class="selection-comment">`),
- /* 110 */ []byte(`<span class="selection-highlight">`),
- /* 111 */ []byte(`<span class="selection-highlight-comment">`),
-}
-
-var endTag = []byte(`</span>`)
-
-
-func selectionTag(w io.Writer, text []byte, selections int) {
- if selections < len(startTags) {
- if tag := startTags[selections]; len(tag) > 0 {
- w.Write(tag)
- template.HTMLEscape(w, text)
- w.Write(endTag)
- return
- }
- }
- template.HTMLEscape(w, text)
-}
-
-
-// FormatText HTML-escapes text and writes it to w.
-// Consecutive text segments are wrapped in HTML spans (with tags as
-// defined by startTags and endTag) as follows:
-//
-// - if line >= 0, line number (ln) spans are inserted before each line,
-// starting with the value of line
-// - if the text is Go source, comments get the "comment" span class
-// - each occurrence of the regular expression pattern gets the "highlight"
-// span class
-// - text segments covered by selection get the "selection" span class
-//
-// Comments, highlights, and selections may overlap arbitrarily; the respective
-// HTML span classes are specified in the startTags variable.
-//
-func FormatText(w io.Writer, text []byte, line int, goSource bool, pattern string, selection Selection) {
- var comments, highlights Selection
- if goSource {
- comments = commentSelection(text)
- }
- if pattern != "" {
- highlights = regexpSelection(text, pattern)
- }
- if line >= 0 || comments != nil || highlights != nil || selection != nil {
- var lineTag LinkWriter
- if line >= 0 {
- lineTag = func(w io.Writer, _ int, start bool) {
- if start {
- fmt.Fprintf(w, "<a id=\"L%d\"></a><span class=\"ln\">%6d</span>\t", line, line)
- line++
- }
- }
- }
- FormatSelections(w, text, lineTag, lineSelection(text), selectionTag, comments, highlights, selection)
- } else {
- template.HTMLEscape(w, text)
- }
-}
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
deleted file mode 100644
index 20ebd3183..000000000
--- a/src/cmd/godoc/godoc.go
+++ /dev/null
@@ -1,1299 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "bytes"
- "flag"
- "fmt"
- "go/ast"
- "go/build"
- "go/doc"
- "go/printer"
- "go/token"
- "http"
- "io"
- "log"
- "os"
- "path"
- "path/filepath"
- "regexp"
- "runtime"
- "sort"
- "strings"
- "template"
- "time"
-)
-
-
-// ----------------------------------------------------------------------------
-// Globals
-
-type delayTime struct {
- RWValue
-}
-
-
-func (dt *delayTime) backoff(max int) {
- dt.mutex.Lock()
- v := dt.value.(int) * 2
- if v > max {
- v = max
- }
- dt.value = v
- // don't change dt.timestamp - calling backoff indicates an error condition
- dt.mutex.Unlock()
-}
-
-
-var (
- verbose = flag.Bool("v", false, "verbose mode")
-
- // file system roots
- // TODO(gri) consider the invariant that goroot always end in '/'
- goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
- testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
- pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
- filter = flag.String("filter", "", "filter file containing permitted package directory paths")
- filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0")
- filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
-
- // layout control
- tabwidth = flag.Int("tabwidth", 4, "tab width")
- showTimestamps = flag.Bool("timestamps", true, "show timestamps with directory listings")
- templateDir = flag.String("templates", "", "directory containing alternate template files")
-
- // search index
- indexEnabled = flag.Bool("index", false, "enable search index")
- maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
-
- // file system mapping
- fs FileSystem // the underlying file system
- fsMap Mapping // user-defined mapping
- fsTree RWValue // *Directory tree of packages, updated with each sync
- pathFilter RWValue // filter used when building fsMap directory trees
- fsModified RWValue // timestamp of last call to invalidateIndex
-
- // http handlers
- fileServer http.Handler // default file server
- cmdHandler httpHandler
- pkgHandler httpHandler
-)
-
-
-func initHandlers() {
- paths := filepath.SplitList(*pkgPath)
- for _, t := range build.Path {
- if t.Goroot {
- continue
- }
- paths = append(paths, t.SrcDir())
- }
- fsMap.Init(paths)
-
- fileServer = http.FileServer(http.Dir(*goroot))
- cmdHandler = httpHandler{"/cmd/", filepath.Join(*goroot, "src", "cmd"), false}
- pkgHandler = httpHandler{"/pkg/", filepath.Join(*goroot, "src", "pkg"), true}
-}
-
-
-func registerPublicHandlers(mux *http.ServeMux) {
- mux.Handle(cmdHandler.pattern, &cmdHandler)
- mux.Handle(pkgHandler.pattern, &pkgHandler)
- mux.HandleFunc("/doc/codewalk/", codewalk)
- mux.HandleFunc("/search", search)
- mux.Handle("/robots.txt", fileServer)
- mux.HandleFunc("/", serveFile)
-}
-
-
-func initFSTree() {
- fsTree.set(newDirectory(filepath.Join(*goroot, *testDir), nil, -1))
- invalidateIndex()
-}
-
-
-// ----------------------------------------------------------------------------
-// Directory filters
-
-// isParentOf returns true if p is a parent of (or the same as) q
-// where p and q are directory paths.
-func isParentOf(p, q string) bool {
- n := len(p)
- return strings.HasPrefix(q, p) && (len(q) <= n || q[n] == '/')
-}
-
-
-func setPathFilter(list []string) {
- if len(list) == 0 {
- pathFilter.set(nil)
- return
- }
-
- // len(list) > 0
- pathFilter.set(func(path string) bool {
- // list is sorted in increasing order and for each path all its children are removed
- i := sort.Search(len(list), func(i int) bool { return list[i] > path })
- // Now we have list[i-1] <= path < list[i].
- // Path may be a child of list[i-1] or a parent of list[i].
- return i > 0 && isParentOf(list[i-1], path) || i < len(list) && isParentOf(path, list[i])
- })
-}
-
-
-func getPathFilter() func(string) bool {
- f, _ := pathFilter.get()
- if f != nil {
- return f.(func(string) bool)
- }
- return nil
-}
-
-
-// readDirList reads a file containing a newline-separated list
-// of directory paths and returns the list of paths.
-func readDirList(filename string) ([]string, os.Error) {
- contents, err := fs.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- // create a sorted list of valid directory names
- filter := func(path string) bool {
- d, e := fs.Lstat(path)
- if e != nil && err == nil {
- // remember first error and return it from readDirList
- // so we have at least some information if things go bad
- err = e
- }
- return e == nil && isPkgDir(d)
- }
- list := canonicalizePaths(strings.Split(string(contents), "\n"), filter)
- // for each parent path, remove all it's children q
- // (requirement for binary search to work when filtering)
- i := 0
- for _, q := range list {
- if i == 0 || !isParentOf(list[i-1], q) {
- list[i] = q
- i++
- }
- }
- return list[0:i], err
-}
-
-
-// updateMappedDirs computes the directory tree for
-// each user-defined file system mapping. If a filter
-// is provided, it is used to filter directories.
-//
-func updateMappedDirs(filter func(string) bool) {
- if !fsMap.IsEmpty() {
- fsMap.Iterate(func(path string, value *RWValue) bool {
- value.set(newDirectory(path, filter, -1))
- return true
- })
- invalidateIndex()
- }
-}
-
-
-func updateFilterFile() {
- updateMappedDirs(nil) // no filter for accuracy
-
- // collect directory tree leaf node paths
- var buf bytes.Buffer
- fsMap.Iterate(func(_ string, value *RWValue) bool {
- v, _ := value.get()
- if v != nil && v.(*Directory) != nil {
- v.(*Directory).writeLeafs(&buf)
- }
- return true
- })
-
- // update filter file
- if err := writeFileAtomically(*filter, buf.Bytes()); err != nil {
- log.Printf("writeFileAtomically(%s): %s", *filter, err)
- filterDelay.backoff(24 * 60) // back off exponentially, but try at least once a day
- } else {
- filterDelay.set(*filterMin) // revert to regular filter update schedule
- }
-}
-
-
-func initDirTrees() {
- // setup initial path filter
- if *filter != "" {
- list, err := readDirList(*filter)
- if err != nil {
- log.Printf("readDirList(%s): %s", *filter, err)
- }
- if *verbose || len(list) == 0 {
- log.Printf("found %d directory paths in file %s", len(list), *filter)
- }
- setPathFilter(list)
- }
-
- go updateMappedDirs(getPathFilter()) // use filter for speed
-
- // start filter update goroutine, if enabled.
- if *filter != "" && *filterMin > 0 {
- filterDelay.set(*filterMin) // initial filter update delay
- go func() {
- for {
- if *verbose {
- log.Printf("start update of %s", *filter)
- }
- updateFilterFile()
- delay, _ := filterDelay.get()
- if *verbose {
- log.Printf("next filter update in %dmin", delay.(int))
- }
- time.Sleep(int64(delay.(int)) * 60e9)
- }
- }()
- }
-}
-
-
-// ----------------------------------------------------------------------------
-// Path mapping
-
-// Absolute paths are file system paths (backslash-separated on Windows),
-// but relative paths are always slash-separated.
-
-func absolutePath(relpath, defaultRoot string) string {
- abspath := fsMap.ToAbsolute(relpath)
- if abspath == "" {
- // no user-defined mapping found; use default mapping
- abspath = filepath.Join(defaultRoot, filepath.FromSlash(relpath))
- }
- return abspath
-}
-
-
-func relativeURL(abspath string) string {
- relpath := fsMap.ToRelative(abspath)
- if relpath == "" {
- // prefix must end in a path separator
- prefix := *goroot
- if len(prefix) > 0 && prefix[len(prefix)-1] != filepath.Separator {
- prefix += string(filepath.Separator)
- }
- if strings.HasPrefix(abspath, prefix) {
- // no user-defined mapping found; use default mapping
- relpath = filepath.ToSlash(abspath[len(prefix):])
- }
- }
- // Only if path is an invalid absolute path is relpath == ""
- // at this point. This should never happen since absolute paths
- // are only created via godoc for files that do exist. However,
- // it is ok to return ""; it will simply provide a link to the
- // top of the pkg or src directories.
- return relpath
-}
-
-
-// ----------------------------------------------------------------------------
-// Tab conversion
-
-var spaces = []byte(" ") // 32 spaces seems like a good number
-
-const (
- indenting = iota
- collecting
-)
-
-// A tconv is an io.Writer filter for converting leading tabs into spaces.
-type tconv struct {
- output io.Writer
- state int // indenting or collecting
- indent int // valid if state == indenting
-}
-
-
-func (p *tconv) writeIndent() (err os.Error) {
- i := p.indent
- for i >= len(spaces) {
- i -= len(spaces)
- if _, err = p.output.Write(spaces); err != nil {
- return
- }
- }
- // i < len(spaces)
- if i > 0 {
- _, err = p.output.Write(spaces[0:i])
- }
- return
-}
-
-
-func (p *tconv) Write(data []byte) (n int, err os.Error) {
- if len(data) == 0 {
- return
- }
- pos := 0 // valid if p.state == collecting
- var b byte
- for n, b = range data {
- switch p.state {
- case indenting:
- switch b {
- case '\t':
- p.indent += *tabwidth
- case '\n':
- p.indent = 0
- if _, err = p.output.Write(data[n : n+1]); err != nil {
- return
- }
- case ' ':
- p.indent++
- default:
- p.state = collecting
- pos = n
- if err = p.writeIndent(); err != nil {
- return
- }
- }
- case collecting:
- if b == '\n' {
- p.state = indenting
- p.indent = 0
- if _, err = p.output.Write(data[pos : n+1]); err != nil {
- return
- }
- }
- }
- }
- n = len(data)
- if pos < n && p.state == collecting {
- _, err = p.output.Write(data[pos:])
- }
- return
-}
-
-
-// ----------------------------------------------------------------------------
-// Templates
-
-// Write an AST node to w.
-func writeNode(w io.Writer, fset *token.FileSet, x interface{}) {
- // convert trailing tabs into spaces using a tconv filter
- // to ensure a good outcome in most browsers (there may still
- // be tabs in comments and strings, but converting those into
- // the right number of spaces is much harder)
- //
- // TODO(gri) rethink printer flags - perhaps tconv can be eliminated
- // with an another printer mode (which is more efficiently
- // implemented in the printer than here with another layer)
- mode := printer.TabIndent | printer.UseSpaces
- (&printer.Config{mode, *tabwidth}).Fprint(&tconv{output: w}, fset, x)
-}
-
-
-// Write anything to w.
-func writeAny(w io.Writer, fset *token.FileSet, x interface{}) {
- switch v := x.(type) {
- case []byte:
- w.Write(v)
- case string:
- w.Write([]byte(v))
- case ast.Decl, ast.Expr, ast.Stmt, *ast.File:
- writeNode(w, fset, x)
- default:
- fmt.Fprint(w, x)
- }
-}
-
-
-// Write anything html-escaped to w.
-func writeAnyHTML(w io.Writer, fset *token.FileSet, x interface{}) {
- switch v := x.(type) {
- case []byte:
- template.HTMLEscape(w, v)
- case string:
- template.HTMLEscape(w, []byte(v))
- case ast.Decl, ast.Expr, ast.Stmt, *ast.File:
- var buf bytes.Buffer
- writeNode(&buf, fset, x)
- FormatText(w, buf.Bytes(), -1, true, "", nil)
- default:
- var buf bytes.Buffer
- fmt.Fprint(&buf, x)
- template.HTMLEscape(w, buf.Bytes())
- }
-}
-
-
-func fileset(x []interface{}) *token.FileSet {
- if len(x) > 1 {
- if fset, ok := x[1].(*token.FileSet); ok {
- return fset
- }
- }
- return nil
-}
-
-
-// Template formatter for "html-esc" format.
-func htmlEscFmt(w io.Writer, format string, x ...interface{}) {
- writeAnyHTML(w, fileset(x), x[0])
-}
-
-
-// Template formatter for "html-comment" format.
-func htmlCommentFmt(w io.Writer, format string, x ...interface{}) {
- var buf bytes.Buffer
- writeAny(&buf, fileset(x), x[0])
- // TODO(gri) Provide list of words (e.g. function parameters)
- // to be emphasized by ToHTML.
- doc.ToHTML(w, buf.Bytes(), nil) // does html-escaping
-}
-
-
-// Template formatter for "" (default) format.
-func textFmt(w io.Writer, format string, x ...interface{}) {
- writeAny(w, fileset(x), x[0])
-}
-
-
-// Template formatter for "urlquery-esc" format.
-func urlQueryEscFmt(w io.Writer, format string, x ...interface{}) {
- var buf bytes.Buffer
- writeAny(&buf, fileset(x), x[0])
- template.HTMLEscape(w, []byte(http.URLEscape(string(buf.Bytes()))))
-}
-
-
-// Template formatter for the various "url-xxx" formats excluding url-esc.
-func urlFmt(w io.Writer, format string, x ...interface{}) {
- var path string
- var line int
- var low, high int // selection
-
- // determine path and position info, if any
- type positioner interface {
- Pos() token.Pos
- End() token.Pos
- }
- switch t := x[0].(type) {
- case string:
- path = t
- case positioner:
- fset := fileset(x)
- if p := t.Pos(); p.IsValid() {
- pos := fset.Position(p)
- path = pos.Filename
- line = pos.Line
- low = pos.Offset
- }
- if p := t.End(); p.IsValid() {
- high = fset.Position(p).Offset
- }
- default:
- // we should never reach here, but be resilient
- // and assume the position is invalid (empty path,
- // and line 0)
- log.Printf("INTERNAL ERROR: urlFmt(%s) without a string or positioner", format)
- }
-
- // map path
- relpath := relativeURL(path)
-
- // convert to relative URLs so that they can also
- // be used as relative file names in .txt templates
- switch format {
- default:
- // we should never reach here, but be resilient
- // and assume the url-pkg format instead
- log.Printf("INTERNAL ERROR: urlFmt(%s)", format)
- fallthrough
- case "url-pkg":
- // because of the irregular mapping under goroot
- // we need to correct certain relative paths
- if strings.HasPrefix(relpath, "src/pkg/") {
- relpath = relpath[len("src/pkg/"):]
- }
- template.HTMLEscape(w, []byte(pkgHandler.pattern[1:]+relpath)) // remove trailing '/' for relative URL
- case "url-src":
- template.HTMLEscape(w, []byte(relpath))
- case "url-pos":
- template.HTMLEscape(w, []byte(relpath))
- // selection ranges are of form "s=low:high"
- if low < high {
- fmt.Fprintf(w, "?s=%d:%d", low, high)
- // if we have a selection, position the page
- // such that the selection is a bit below the top
- line -= 10
- if line < 1 {
- line = 1
- }
- }
- // line id's in html-printed source are of the
- // form "L%d" where %d stands for the line number
- if line > 0 {
- fmt.Fprintf(w, "#L%d", line)
- }
- }
-}
-
-
-// The strings in infoKinds must be properly html-escaped.
-var infoKinds = [nKinds]string{
- PackageClause: "package&nbsp;clause",
- ImportDecl: "import&nbsp;decl",
- ConstDecl: "const&nbsp;decl",
- TypeDecl: "type&nbsp;decl",
- VarDecl: "var&nbsp;decl",
- FuncDecl: "func&nbsp;decl",
- MethodDecl: "method&nbsp;decl",
- Use: "use",
-}
-
-
-// Template formatter for "infoKind" format.
-func infoKindFmt(w io.Writer, format string, x ...interface{}) {
- fmt.Fprintf(w, infoKinds[x[0].(SpotKind)]) // infoKind entries are html-escaped
-}
-
-
-// Template formatter for "infoLine" format.
-func infoLineFmt(w io.Writer, format string, x ...interface{}) {
- info := x[0].(SpotInfo)
- line := info.Lori()
- if info.IsIndex() {
- index, _ := searchIndex.get()
- if index != nil {
- line = index.(*Index).Snippet(line).Line
- } else {
- // no line information available because
- // we don't have an index - this should
- // never happen; be conservative and don't
- // crash
- line = 0
- }
- }
- fmt.Fprintf(w, "%d", line)
-}
-
-
-// Template formatter for "infoSnippet" format.
-func infoSnippetFmt(w io.Writer, format string, x ...interface{}) {
- info := x[0].(SpotInfo)
- text := []byte(`<span class="alert">no snippet text available</span>`)
- if info.IsIndex() {
- index, _ := searchIndex.get()
- // no escaping of snippet text needed;
- // snippet text is escaped when generated
- text = index.(*Index).Snippet(info.Lori()).Text
- }
- w.Write(text)
-}
-
-
-// Template formatter for "padding" format.
-func paddingFmt(w io.Writer, format string, x ...interface{}) {
- for i := x[0].(int); i > 0; i-- {
- fmt.Fprint(w, `<td width="25"></td>`)
- }
-}
-
-
-// Template formatter for "time" format.
-func timeFmt(w io.Writer, format string, x ...interface{}) {
- template.HTMLEscape(w, []byte(time.SecondsToLocalTime(x[0].(int64)/1e9).String()))
-}
-
-
-// Template formatter for "dir/" format.
-func dirslashFmt(w io.Writer, format string, x ...interface{}) {
- if x[0].(FileInfo).IsDirectory() {
- w.Write([]byte{'/'})
- }
-}
-
-
-// Template formatter for "localname" format.
-func localnameFmt(w io.Writer, format string, x ...interface{}) {
- _, localname := filepath.Split(x[0].(string))
- template.HTMLEscape(w, []byte(localname))
-}
-
-
-// Template formatter for "numlines" format.
-func numlinesFmt(w io.Writer, format string, x ...interface{}) {
- list := x[0].([]int)
- fmt.Fprintf(w, "%d", len(list))
-}
-
-
-var fmap = template.FormatterMap{
- "": textFmt,
- "html-esc": htmlEscFmt,
- "html-comment": htmlCommentFmt,
- "urlquery-esc": urlQueryEscFmt,
- "url-pkg": urlFmt,
- "url-src": urlFmt,
- "url-pos": urlFmt,
- "infoKind": infoKindFmt,
- "infoLine": infoLineFmt,
- "infoSnippet": infoSnippetFmt,
- "padding": paddingFmt,
- "time": timeFmt,
- "dir/": dirslashFmt,
- "localname": localnameFmt,
- "numlines": numlinesFmt,
-}
-
-
-func readTemplate(name string) *template.Template {
- path := filepath.Join(*goroot, "lib", "godoc", name)
- if *templateDir != "" {
- defaultpath := path
- path = filepath.Join(*templateDir, name)
- if _, err := fs.Stat(path); err != nil {
- log.Print("readTemplate:", err)
- path = defaultpath
- }
- }
- data, err := fs.ReadFile(path)
- if err != nil {
- log.Fatalf("ReadFile %s: %v", path, err)
- }
- t, err := template.Parse(string(data), fmap)
- if err != nil {
- log.Fatalf("%s: %v", name, err)
- }
- return t
-}
-
-
-var (
- codewalkHTML,
- codewalkdirHTML,
- dirlistHTML,
- errorHTML,
- godocHTML,
- packageHTML,
- packageText,
- searchHTML,
- searchText *template.Template
-)
-
-func readTemplates() {
- // have to delay until after flags processing since paths depend on goroot
- codewalkHTML = readTemplate("codewalk.html")
- codewalkdirHTML = readTemplate("codewalkdir.html")
- dirlistHTML = readTemplate("dirlist.html")
- errorHTML = readTemplate("error.html")
- godocHTML = readTemplate("godoc.html")
- packageHTML = readTemplate("package.html")
- packageText = readTemplate("package.txt")
- searchHTML = readTemplate("search.html")
- searchText = readTemplate("search.txt")
-}
-
-
-// ----------------------------------------------------------------------------
-// Generic HTML wrapper
-
-func servePage(w http.ResponseWriter, title, subtitle, query string, content []byte) {
- d := struct {
- Title string
- Subtitle string
- PkgRoots []string
- SearchBox bool
- Query string
- Version string
- Menu []byte
- Content []byte
- }{
- title,
- subtitle,
- fsMap.PrefixList(),
- *indexEnabled,
- query,
- runtime.Version(),
- nil,
- content,
- }
-
- if err := godocHTML.Execute(w, &d); err != nil {
- log.Printf("godocHTML.Execute: %s", err)
- }
-}
-
-
-func serveText(w http.ResponseWriter, text []byte) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.Write(text)
-}
-
-
-// ----------------------------------------------------------------------------
-// Files
-
-var (
- titleRx = regexp.MustCompile(`<!-- title ([^\-]*)-->`)
- subtitleRx = regexp.MustCompile(`<!-- subtitle ([^\-]*)-->`)
- firstCommentRx = regexp.MustCompile(`<!--([^\-]*)-->`)
-)
-
-
-func extractString(src []byte, rx *regexp.Regexp) (s string) {
- m := rx.FindSubmatch(src)
- if m != nil {
- s = strings.TrimSpace(string(m[1]))
- }
- return
-}
-
-
-func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
- // get HTML body contents
- src, err := fs.ReadFile(abspath)
- if err != nil {
- log.Printf("ReadFile: %s", err)
- serveError(w, r, relpath, err)
- return
- }
-
- // if it begins with "<!DOCTYPE " assume it is standalone
- // html that doesn't need the template wrapping.
- if bytes.HasPrefix(src, []byte("<!DOCTYPE ")) {
- w.Write(src)
- return
- }
-
- // if it's the language spec, add tags to EBNF productions
- if strings.HasSuffix(abspath, "go_spec.html") {
- var buf bytes.Buffer
- linkify(&buf, src)
- src = buf.Bytes()
- }
-
- // get title and subtitle, if any
- title := extractString(src, titleRx)
- if title == "" {
- // no title found; try first comment for backward-compatibility
- title = extractString(src, firstCommentRx)
- }
- subtitle := extractString(src, subtitleRx)
-
- servePage(w, title, subtitle, "", src)
-}
-
-
-func applyTemplate(t *template.Template, name string, data interface{}) []byte {
- var buf bytes.Buffer
- if err := t.Execute(&buf, data); err != nil {
- log.Printf("%s.Execute: %s", name, err)
- }
- return buf.Bytes()
-}
-
-
-func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
- if canonical := path.Clean(r.URL.Path) + "/"; r.URL.Path != canonical {
- http.Redirect(w, r, canonical, http.StatusMovedPermanently)
- redirected = true
- }
- return
-}
-
-func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
- src, err := fs.ReadFile(abspath)
- if err != nil {
- log.Printf("ReadFile: %s", err)
- serveError(w, r, relpath, err)
- return
- }
-
- var buf bytes.Buffer
- buf.WriteString("<pre>")
- FormatText(&buf, src, 1, filepath.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s")))
- buf.WriteString("</pre>")
-
- servePage(w, title+" "+relpath, "", "", buf.Bytes())
-}
-
-
-func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
- if redirect(w, r) {
- return
- }
-
- list, err := fs.ReadDir(abspath)
- if err != nil {
- log.Printf("ReadDir: %s", err)
- serveError(w, r, relpath, err)
- return
- }
-
- contents := applyTemplate(dirlistHTML, "dirlistHTML", list)
- servePage(w, "Directory "+relpath, "", "", contents)
-}
-
-
-func serveFile(w http.ResponseWriter, r *http.Request) {
- relpath := r.URL.Path[1:] // serveFile URL paths start with '/'
- abspath := absolutePath(relpath, *goroot)
-
- // pick off special cases and hand the rest to the standard file server
- switch r.URL.Path {
- case "/":
- serveHTMLDoc(w, r, filepath.Join(*goroot, "doc", "root.html"), "doc/root.html")
- return
-
- case "/doc/root.html":
- // hide landing page from its real name
- http.Redirect(w, r, "/", http.StatusMovedPermanently)
- return
- }
-
- switch path.Ext(relpath) {
- case ".html":
- if strings.HasSuffix(relpath, "/index.html") {
- // We'll show index.html for the directory.
- // Use the dir/ version as canonical instead of dir/index.html.
- http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
- return
- }
- serveHTMLDoc(w, r, abspath, relpath)
- return
-
- case ".go":
- serveTextFile(w, r, abspath, relpath, "Source file")
- return
- }
-
- dir, err := fs.Lstat(abspath)
- if err != nil {
- log.Print(err)
- serveError(w, r, relpath, err)
- return
- }
-
- if dir != nil && dir.IsDirectory() {
- if redirect(w, r) {
- return
- }
- if index := filepath.Join(abspath, "index.html"); isTextFile(index) {
- serveHTMLDoc(w, r, index, relativeURL(index))
- return
- }
- serveDirectory(w, r, abspath, relpath)
- return
- }
-
- if isTextFile(abspath) {
- serveTextFile(w, r, abspath, relpath, "Text file")
- return
- }
-
- fileServer.ServeHTTP(w, r)
-}
-
-
-// ----------------------------------------------------------------------------
-// Packages
-
-// Fake package file and name for commands. Contains the command documentation.
-const fakePkgFile = "doc.go"
-const fakePkgName = "documentation"
-
-type PageInfoMode uint
-
-const (
- exportsOnly PageInfoMode = 1 << iota // only keep exported stuff
- genDoc // generate documentation
-)
-
-
-type PageInfo struct {
- Dirname string // directory containing the package
- PList []string // list of package names found
- FSet *token.FileSet // corresponding file set
- PAst *ast.File // nil if no single AST with package exports
- PDoc *doc.PackageDoc // nil if no single package documentation
- Dirs *DirList // nil if no directory information
- DirTime int64 // directory time stamp in seconds since epoch
- IsPkg bool // false if this is not documenting a real package
- Err os.Error // directory read error or nil
-}
-
-
-func (info *PageInfo) IsEmpty() bool {
- return info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil
-}
-
-
-type httpHandler struct {
- pattern string // url pattern; e.g. "/pkg/"
- fsRoot string // file system root to which the pattern is mapped
- isPkg bool // true if this handler serves real package documentation (as opposed to command documentation)
-}
-
-
-// getPageInfo returns the PageInfo for a package directory abspath. If the
-// parameter genAST is set, an AST containing only the package exports is
-// computed (PageInfo.PAst), otherwise package documentation (PageInfo.Doc)
-// is extracted from the AST. If there is no corresponding package in the
-// directory, PageInfo.PAst and PageInfo.PDoc are nil. If there are no sub-
-// directories, PageInfo.Dirs is nil. If a directory read error occurred,
-// PageInfo.Err is set to the respective error but the error is not logged.
-//
-func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInfoMode) PageInfo {
- // filter function to select the desired .go files
- filter := func(d FileInfo) bool {
- // If we are looking at cmd documentation, only accept
- // the special fakePkgFile containing the documentation.
- return isPkgFile(d) && (h.isPkg || d.Name() == fakePkgFile)
- }
-
- // get package ASTs
- fset := token.NewFileSet()
- pkgs, err := parseDir(fset, abspath, filter)
- if err != nil && pkgs == nil {
- // only report directory read errors, ignore parse errors
- // (may be able to extract partial package information)
- return PageInfo{Dirname: abspath, Err: err}
- }
-
- // select package
- var pkg *ast.Package // selected package
- var plist []string // list of other package (names), if any
- if len(pkgs) == 1 {
- // Exactly one package - select it.
- for _, p := range pkgs {
- pkg = p
- }
-
- } else if len(pkgs) > 1 {
- // Multiple packages - select the best matching package: The
- // 1st choice is the package with pkgname, the 2nd choice is
- // the package with dirname, and the 3rd choice is a package
- // that is not called "main" if there is exactly one such
- // package. Otherwise, don't select a package.
- dirpath, dirname := filepath.Split(abspath)
-
- // If the dirname is "go" we might be in a sub-directory for
- // .go files - use the outer directory name instead for better
- // results.
- if dirname == "go" {
- _, dirname = filepath.Split(filepath.Clean(dirpath))
- }
-
- var choice3 *ast.Package
- loop:
- for _, p := range pkgs {
- switch {
- case p.Name == pkgname:
- pkg = p
- break loop // 1st choice; we are done
- case p.Name == dirname:
- pkg = p // 2nd choice
- case p.Name != "main":
- choice3 = p
- }
- }
- if pkg == nil && len(pkgs) == 2 {
- pkg = choice3
- }
-
- // Compute the list of other packages
- // (excluding the selected package, if any).
- plist = make([]string, len(pkgs))
- i := 0
- for name := range pkgs {
- if pkg == nil || name != pkg.Name {
- plist[i] = name
- i++
- }
- }
- plist = plist[0:i]
- }
-
- // compute package documentation
- var past *ast.File
- var pdoc *doc.PackageDoc
- if pkg != nil {
- if mode&exportsOnly != 0 {
- ast.PackageExports(pkg)
- }
- if mode&genDoc != 0 {
- pdoc = doc.NewPackageDoc(pkg, path.Clean(relpath)) // no trailing '/' in importpath
- } else {
- past = ast.MergePackageFiles(pkg, ast.FilterUnassociatedComments)
- }
- }
-
- // get directory information
- var dir *Directory
- var timestamp int64
- if tree, ts := fsTree.get(); tree != nil && tree.(*Directory) != nil {
- // directory tree is present; lookup respective directory
- // (may still fail if the file system was updated and the
- // new directory tree has not yet been computed)
- dir = tree.(*Directory).lookup(abspath)
- timestamp = ts
- }
- if dir == nil {
- // the path may refer to a user-specified file system mapped
- // via fsMap; lookup that mapping and corresponding RWValue
- // if any
- var v *RWValue
- fsMap.Iterate(func(path string, value *RWValue) bool {
- if isParentOf(path, abspath) {
- // mapping found
- v = value
- return false
- }
- return true
- })
- if v != nil {
- // found a RWValue associated with a user-specified file
- // system; a non-nil RWValue stores a (possibly out-of-date)
- // directory tree for that file system
- if tree, ts := v.get(); tree != nil && tree.(*Directory) != nil {
- dir = tree.(*Directory).lookup(abspath)
- timestamp = ts
- }
- }
- }
- if dir == nil {
- // no directory tree present (too early after startup or
- // command-line mode); compute one level for this page
- // note: cannot use path filter here because in general
- // it doesn't contain the fsTree path
- dir = newDirectory(abspath, nil, 1)
- timestamp = time.Seconds()
- }
-
- return PageInfo{abspath, plist, fset, past, pdoc, dir.listing(true), timestamp, h.isPkg, nil}
-}
-
-
-func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- if redirect(w, r) {
- return
- }
-
- relpath := r.URL.Path[len(h.pattern):]
- abspath := absolutePath(relpath, h.fsRoot)
- mode := exportsOnly
- if r.FormValue("m") != "src" {
- mode |= genDoc
- }
- info := h.getPageInfo(abspath, relpath, r.FormValue("p"), mode)
- if info.Err != nil {
- log.Print(info.Err)
- serveError(w, r, relpath, info.Err)
- return
- }
-
- if r.FormValue("f") == "text" {
- contents := applyTemplate(packageText, "packageText", info)
- serveText(w, contents)
- return
- }
-
- var title, subtitle string
- switch {
- case info.PAst != nil:
- title = "Package " + info.PAst.Name.Name
- case info.PDoc != nil:
- switch {
- case h.isPkg:
- title = "Package " + info.PDoc.PackageName
- case info.PDoc.PackageName == fakePkgName:
- // assume that the directory name is the command name
- _, pkgname := path.Split(path.Clean(relpath))
- title = "Command " + pkgname
- default:
- title = "Command " + info.PDoc.PackageName
- }
- default:
- title = "Directory " + relativeURL(info.Dirname)
- if *showTimestamps {
- subtitle = "Last update: " + time.SecondsToLocalTime(info.DirTime).String()
- }
- }
-
- contents := applyTemplate(packageHTML, "packageHTML", info)
- servePage(w, title, subtitle, "", contents)
-}
-
-
-// ----------------------------------------------------------------------------
-// Search
-
-var searchIndex RWValue
-
-type SearchResult struct {
- Query string
- Alert string // error or warning message
-
- // identifier matches
- Hit *LookupResult // identifier matches of Query
- Alt *AltWords // alternative identifiers to look for
-
- // textual matches
- Found int // number of textual occurrences found
- Textual []FileLines // textual matches of Query
- Complete bool // true if all textual occurrences of Query are reported
-}
-
-
-func lookup(query string) (result SearchResult) {
- result.Query = query
-
- index, timestamp := searchIndex.get()
- if index != nil {
- index := index.(*Index)
-
- // identifier search
- var err os.Error
- result.Hit, result.Alt, err = index.Lookup(query)
- if err != nil && *maxResults <= 0 {
- // ignore the error if full text search is enabled
- // since the query may be a valid regular expression
- result.Alert = "Error in query string: " + err.String()
- return
- }
-
- // full text search
- if *maxResults > 0 && query != "" {
- rx, err := regexp.Compile(query)
- if err != nil {
- result.Alert = "Error in query regular expression: " + err.String()
- return
- }
- // If we get maxResults+1 results we know that there are more than
- // maxResults results and thus the result may be incomplete (to be
- // precise, we should remove one result from the result set, but
- // nobody is going to count the results on the result page).
- result.Found, result.Textual = index.LookupRegexp(rx, *maxResults+1)
- result.Complete = result.Found <= *maxResults
- if !result.Complete {
- result.Found-- // since we looked for maxResults+1
- }
- }
- }
-
- // is the result accurate?
- if *indexEnabled {
- if _, ts := fsModified.get(); timestamp < ts {
- // The index is older than the latest file system change
- // under godoc's observation. Indexing may be in progress
- // or start shortly (see indexer()).
- result.Alert = "Indexing in progress: result may be inaccurate"
- }
- } else {
- result.Alert = "Search index disabled: no results available"
- }
-
- return
-}
-
-
-func search(w http.ResponseWriter, r *http.Request) {
- query := strings.TrimSpace(r.FormValue("q"))
- result := lookup(query)
-
- if r.FormValue("f") == "text" {
- contents := applyTemplate(searchText, "searchText", result)
- serveText(w, contents)
- return
- }
-
- var title string
- if result.Hit != nil || len(result.Textual) > 0 {
- title = fmt.Sprintf(`Results for query %q`, query)
- } else {
- title = fmt.Sprintf(`No results found for query %q`, query)
- }
-
- contents := applyTemplate(searchHTML, "searchHTML", result)
- servePage(w, title, "", query, contents)
-}
-
-
-// ----------------------------------------------------------------------------
-// Indexer
-
-// invalidateIndex should be called whenever any of the file systems
-// under godoc's observation change so that the indexer is kicked on.
-//
-func invalidateIndex() {
- fsModified.set(nil)
-}
-
-
-// indexUpToDate() returns true if the search index is not older
-// than any of the file systems under godoc's observation.
-//
-func indexUpToDate() bool {
- _, fsTime := fsModified.get()
- _, siTime := searchIndex.get()
- return fsTime <= siTime
-}
-
-
-// feedDirnames feeds the directory names of all directories
-// under the file system given by root to channel c.
-//
-func feedDirnames(root *RWValue, c chan<- string) {
- if dir, _ := root.get(); dir != nil {
- for d := range dir.(*Directory).iter(false) {
- c <- d.Path
- }
- }
-}
-
-
-// fsDirnames() returns a channel sending all directory names
-// of all the file systems under godoc's observation.
-//
-func fsDirnames() <-chan string {
- c := make(chan string, 256) // asynchronous for fewer context switches
- go func() {
- feedDirnames(&fsTree, c)
- fsMap.Iterate(func(_ string, root *RWValue) bool {
- feedDirnames(root, c)
- return true
- })
- close(c)
- }()
- return c
-}
-
-
-func indexer() {
- for {
- if !indexUpToDate() {
- // index possibly out of date - make a new one
- if *verbose {
- log.Printf("updating index...")
- }
- start := time.Nanoseconds()
- index := NewIndex(fsDirnames(), *maxResults > 0)
- stop := time.Nanoseconds()
- searchIndex.set(index)
- if *verbose {
- secs := float64((stop-start)/1e6) / 1e3
- stats := index.Stats()
- log.Printf("index updated (%gs, %d bytes of source, %d files, %d lines, %d unique words, %d spots)",
- secs, stats.Bytes, stats.Files, stats.Lines, stats.Words, stats.Spots)
- }
- log.Printf("before GC: bytes = %d footprint = %d", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
- runtime.GC()
- log.Printf("after GC: bytes = %d footprint = %d", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
- }
- var delay int64 = 60 * 1e9 // by default, try every 60s
- if *testDir != "" {
- // in test mode, try once a second for fast startup
- delay = 1 * 1e9
- }
- time.Sleep(delay)
- }
-}
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
deleted file mode 100644
index e0c89e794..000000000
--- a/src/cmd/godoc/index.go
+++ /dev/null
@@ -1,1042 +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.
-
-// This file contains the infrastructure to create an
-// identifier and full-text index for a set of Go files.
-//
-// Algorithm for identifier index:
-// - traverse all .go files of the file tree specified by root
-// - for each word (identifier) encountered, collect all occurrences (spots)
-// into a list; this produces a list of spots for each word
-// - reduce the lists: from a list of spots to a list of FileRuns,
-// and from a list of FileRuns into a list of PakRuns
-// - make a HitList from the PakRuns
-//
-// Details:
-// - keep two lists per word: one containing package-level declarations
-// that have snippets, and one containing all other spots
-// - keep the snippets in a separate table indexed by snippet index
-// and store the snippet index in place of the line number in a SpotInfo
-// (the line number for spots with snippets is stored in the snippet)
-// - at the end, create lists of alternative spellings for a given
-// word
-//
-// Algorithm for full text index:
-// - concatenate all source code in a byte buffer (in memory)
-// - add the files to a file set in lockstep as they are added to the byte
-// buffer such that a byte buffer offset corresponds to the Pos value for
-// that file location
-// - create a suffix array from the concatenated sources
-//
-// String lookup in full text index:
-// - use the suffix array to lookup a string's offsets - the offsets
-// correspond to the Pos values relative to the file set
-// - translate the Pos values back into file and line information and
-// sort the result
-
-package main
-
-import (
- "bytes"
- "container/vector"
- "go/ast"
- "go/parser"
- "go/token"
- "go/scanner"
- "index/suffixarray"
- "os"
- "path/filepath"
- "regexp"
- "sort"
- "strings"
-)
-
-
-// ----------------------------------------------------------------------------
-// RunList
-
-// A RunList is a vector of entries that can be sorted according to some
-// criteria. A RunList may be compressed by grouping "runs" of entries
-// which are equal (according to the sort critera) into a new RunList of
-// runs. For instance, a RunList containing pairs (x, y) may be compressed
-// into a RunList containing pair runs (x, {y}) where each run consists of
-// a list of y's with the same x.
-type RunList struct {
- vector.Vector
- less func(x, y interface{}) bool
-}
-
-func (h *RunList) Less(i, j int) bool { return h.less(h.At(i), h.At(j)) }
-
-
-func (h *RunList) sort(less func(x, y interface{}) bool) {
- h.less = less
- sort.Sort(h)
-}
-
-
-// Compress entries which are the same according to a sort criteria
-// (specified by less) into "runs".
-func (h *RunList) reduce(less func(x, y interface{}) bool, newRun func(h *RunList, i, j int) interface{}) *RunList {
- // create runs of entries with equal values
- h.sort(less)
-
- // for each run, make a new run object and collect them in a new RunList
- var hh RunList
- i := 0
- for j := 0; j < h.Len(); j++ {
- if less(h.At(i), h.At(j)) {
- hh.Push(newRun(h, i, j))
- i = j // start a new run
- }
- }
- // add final run, if any
- if i < h.Len() {
- hh.Push(newRun(h, i, h.Len()))
- }
-
- return &hh
-}
-
-
-// ----------------------------------------------------------------------------
-// SpotInfo
-
-// A SpotInfo value describes a particular identifier spot in a given file;
-// It encodes three values: the SpotKind (declaration or use), a line or
-// snippet index "lori", and whether it's a line or index.
-//
-// The following encoding is used:
-//
-// bits 32 4 1 0
-// value [lori|kind|isIndex]
-//
-type SpotInfo uint32
-
-// SpotKind describes whether an identifier is declared (and what kind of
-// declaration) or used.
-type SpotKind uint32
-
-const (
- PackageClause SpotKind = iota
- ImportDecl
- ConstDecl
- TypeDecl
- VarDecl
- FuncDecl
- MethodDecl
- Use
- nKinds
-)
-
-
-func init() {
- // sanity check: if nKinds is too large, the SpotInfo
- // accessor functions may need to be updated
- if nKinds > 8 {
- panic("nKinds > 8")
- }
-}
-
-
-// makeSpotInfo makes a SpotInfo.
-func makeSpotInfo(kind SpotKind, lori int, isIndex bool) SpotInfo {
- // encode lori: bits [4..32)
- x := SpotInfo(lori) << 4
- if int(x>>4) != lori {
- // lori value doesn't fit - since snippet indices are
- // most certainly always smaller then 1<<28, this can
- // only happen for line numbers; give it no line number (= 0)
- x = 0
- }
- // encode kind: bits [1..4)
- x |= SpotInfo(kind) << 1
- // encode isIndex: bit 0
- if isIndex {
- x |= 1
- }
- return x
-}
-
-
-func (x SpotInfo) Kind() SpotKind { return SpotKind(x >> 1 & 7) }
-func (x SpotInfo) Lori() int { return int(x >> 4) }
-func (x SpotInfo) IsIndex() bool { return x&1 != 0 }
-
-
-// ----------------------------------------------------------------------------
-// KindRun
-
-// Debugging support. Disable to see multiple entries per line.
-const removeDuplicates = true
-
-// A KindRun is a run of SpotInfos of the same kind in a given file.
-type KindRun struct {
- Kind SpotKind
- Infos []SpotInfo
-}
-
-
-// KindRuns are sorted by line number or index. Since the isIndex bit
-// is always the same for all infos in one list we can compare lori's.
-func (f *KindRun) Len() int { return len(f.Infos) }
-func (f *KindRun) Less(i, j int) bool { return f.Infos[i].Lori() < f.Infos[j].Lori() }
-func (f *KindRun) Swap(i, j int) { f.Infos[i], f.Infos[j] = f.Infos[j], f.Infos[i] }
-
-
-// FileRun contents are sorted by Kind for the reduction into KindRuns.
-func lessKind(x, y interface{}) bool { return x.(SpotInfo).Kind() < y.(SpotInfo).Kind() }
-
-
-// newKindRun allocates a new KindRun from the SpotInfo run [i, j) in h.
-func newKindRun(h *RunList, i, j int) interface{} {
- kind := h.At(i).(SpotInfo).Kind()
- infos := make([]SpotInfo, j-i)
- k := 0
- for ; i < j; i++ {
- infos[k] = h.At(i).(SpotInfo)
- k++
- }
- run := &KindRun{kind, infos}
-
- // Spots were sorted by file and kind to create this run.
- // Within this run, sort them by line number or index.
- sort.Sort(run)
-
- if removeDuplicates {
- // Since both the lori and kind field must be
- // same for duplicates, and since the isIndex
- // bit is always the same for all infos in one
- // list we can simply compare the entire info.
- k := 0
- var prev SpotInfo
- for i, x := range infos {
- if x != prev || i == 0 {
- infos[k] = x
- k++
- prev = x
- }
- }
- run.Infos = infos[0:k]
- }
-
- return run
-}
-
-
-// ----------------------------------------------------------------------------
-// FileRun
-
-// A Pak describes a Go package.
-type Pak struct {
- Path string // path of directory containing the package
- Name string // package name as declared by package clause
-}
-
-// Paks are sorted by name (primary key) and by import path (secondary key).
-func (p *Pak) less(q *Pak) bool {
- return p.Name < q.Name || p.Name == q.Name && p.Path < q.Path
-}
-
-
-// A File describes a Go file.
-type File struct {
- Path string // complete file name
- Pak Pak // the package to which the file belongs
-}
-
-
-// A Spot describes a single occurrence of a word.
-type Spot struct {
- File *File
- Info SpotInfo
-}
-
-
-// A FileRun is a list of KindRuns belonging to the same file.
-type FileRun struct {
- File *File
- Groups []*KindRun
-}
-
-
-// Spots are sorted by path for the reduction into FileRuns.
-func lessSpot(x, y interface{}) bool { return x.(Spot).File.Path < y.(Spot).File.Path }
-
-
-// newFileRun allocates a new FileRun from the Spot run [i, j) in h.
-func newFileRun(h0 *RunList, i, j int) interface{} {
- file := h0.At(i).(Spot).File
-
- // reduce the list of Spots into a list of KindRuns
- var h1 RunList
- h1.Vector.Resize(j-i, 0)
- k := 0
- for ; i < j; i++ {
- h1.Set(k, h0.At(i).(Spot).Info)
- k++
- }
- h2 := h1.reduce(lessKind, newKindRun)
-
- // create the FileRun
- groups := make([]*KindRun, h2.Len())
- for i := 0; i < h2.Len(); i++ {
- groups[i] = h2.At(i).(*KindRun)
- }
- return &FileRun{file, groups}
-}
-
-
-// ----------------------------------------------------------------------------
-// PakRun
-
-// A PakRun describes a run of *FileRuns of a package.
-type PakRun struct {
- Pak Pak
- Files []*FileRun
-}
-
-// Sorting support for files within a PakRun.
-func (p *PakRun) Len() int { return len(p.Files) }
-func (p *PakRun) Less(i, j int) bool { return p.Files[i].File.Path < p.Files[j].File.Path }
-func (p *PakRun) Swap(i, j int) { p.Files[i], p.Files[j] = p.Files[j], p.Files[i] }
-
-
-// FileRuns are sorted by package for the reduction into PakRuns.
-func lessFileRun(x, y interface{}) bool {
- return x.(*FileRun).File.Pak.less(&y.(*FileRun).File.Pak)
-}
-
-
-// newPakRun allocates a new PakRun from the *FileRun run [i, j) in h.
-func newPakRun(h *RunList, i, j int) interface{} {
- pak := h.At(i).(*FileRun).File.Pak
- files := make([]*FileRun, j-i)
- k := 0
- for ; i < j; i++ {
- files[k] = h.At(i).(*FileRun)
- k++
- }
- run := &PakRun{pak, files}
- sort.Sort(run) // files were sorted by package; sort them by file now
- return run
-}
-
-
-// ----------------------------------------------------------------------------
-// HitList
-
-// A HitList describes a list of PakRuns.
-type HitList []*PakRun
-
-
-// PakRuns are sorted by package.
-func lessPakRun(x, y interface{}) bool { return x.(*PakRun).Pak.less(&y.(*PakRun).Pak) }
-
-
-func reduce(h0 *RunList) HitList {
- // reduce a list of Spots into a list of FileRuns
- h1 := h0.reduce(lessSpot, newFileRun)
- // reduce a list of FileRuns into a list of PakRuns
- h2 := h1.reduce(lessFileRun, newPakRun)
- // sort the list of PakRuns by package
- h2.sort(lessPakRun)
- // create a HitList
- h := make(HitList, h2.Len())
- for i := 0; i < h2.Len(); i++ {
- h[i] = h2.At(i).(*PakRun)
- }
- return h
-}
-
-
-func (h HitList) filter(pakname string) HitList {
- // determine number of matching packages (most of the time just one)
- n := 0
- for _, p := range h {
- if p.Pak.Name == pakname {
- n++
- }
- }
- // create filtered HitList
- hh := make(HitList, n)
- i := 0
- for _, p := range h {
- if p.Pak.Name == pakname {
- hh[i] = p
- i++
- }
- }
- return hh
-}
-
-
-// ----------------------------------------------------------------------------
-// AltWords
-
-type wordPair struct {
- canon string // canonical word spelling (all lowercase)
- alt string // alternative spelling
-}
-
-
-// An AltWords describes a list of alternative spellings for a
-// canonical (all lowercase) spelling of a word.
-type AltWords struct {
- Canon string // canonical word spelling (all lowercase)
- Alts []string // alternative spelling for the same word
-}
-
-
-// wordPairs are sorted by their canonical spelling.
-func lessWordPair(x, y interface{}) bool { return x.(*wordPair).canon < y.(*wordPair).canon }
-
-
-// newAltWords allocates a new AltWords from the *wordPair run [i, j) in h.
-func newAltWords(h *RunList, i, j int) interface{} {
- canon := h.At(i).(*wordPair).canon
- alts := make([]string, j-i)
- k := 0
- for ; i < j; i++ {
- alts[k] = h.At(i).(*wordPair).alt
- k++
- }
- return &AltWords{canon, alts}
-}
-
-
-func (a *AltWords) filter(s string) *AltWords {
- if len(a.Alts) == 1 && a.Alts[0] == s {
- // there are no different alternatives
- return nil
- }
-
- // make a new AltWords with the current spelling removed
- alts := make([]string, len(a.Alts))
- i := 0
- for _, w := range a.Alts {
- if w != s {
- alts[i] = w
- i++
- }
- }
- return &AltWords{a.Canon, alts[0:i]}
-}
-
-
-// ----------------------------------------------------------------------------
-// Indexer
-
-// Adjust these flags as seems best.
-const includeMainPackages = true
-const includeTestFiles = true
-
-
-type IndexResult struct {
- Decls RunList // package-level declarations (with snippets)
- Others RunList // all other occurrences
-}
-
-
-// Statistics provides statistics information for an index.
-type Statistics struct {
- Bytes int // total size of indexed source files
- Files int // number of indexed source files
- Lines int // number of lines (all files)
- Words int // number of different identifiers
- Spots int // number of identifier occurrences
-}
-
-
-// An Indexer maintains the data structures and provides the machinery
-// for indexing .go files under a file tree. It implements the path.Visitor
-// interface for walking file trees, and the ast.Visitor interface for
-// walking Go ASTs.
-type Indexer struct {
- fset *token.FileSet // file set for all indexed files
- sources bytes.Buffer // concatenated sources
- words map[string]*IndexResult // RunLists of Spots
- snippets vector.Vector // vector of *Snippets, indexed by snippet indices
- current *token.File // last file added to file set
- file *File // AST for current file
- decl ast.Decl // AST for current decl
- stats Statistics
-}
-
-
-func (x *Indexer) addSnippet(s *Snippet) int {
- index := x.snippets.Len()
- x.snippets.Push(s)
- return index
-}
-
-
-func (x *Indexer) visitComment(c *ast.CommentGroup) {
- if c != nil {
- ast.Walk(x, c)
- }
-}
-
-
-func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
- if id != nil {
- lists, found := x.words[id.Name]
- if !found {
- lists = new(IndexResult)
- x.words[id.Name] = lists
- }
-
- if kind == Use || x.decl == nil {
- // not a declaration or no snippet required
- info := makeSpotInfo(kind, x.current.Line(id.Pos()), false)
- lists.Others.Push(Spot{x.file, info})
- } else {
- // a declaration with snippet
- index := x.addSnippet(NewSnippet(x.fset, x.decl, id))
- info := makeSpotInfo(kind, index, true)
- lists.Decls.Push(Spot{x.file, info})
- }
-
- x.stats.Spots++
- }
-}
-
-
-func (x *Indexer) visitSpec(spec ast.Spec, isVarDecl bool) {
- switch n := spec.(type) {
- case *ast.ImportSpec:
- x.visitComment(n.Doc)
- x.visitIdent(ImportDecl, n.Name)
- ast.Walk(x, n.Path)
- x.visitComment(n.Comment)
-
- case *ast.ValueSpec:
- x.visitComment(n.Doc)
- kind := ConstDecl
- if isVarDecl {
- kind = VarDecl
- }
- for _, n := range n.Names {
- x.visitIdent(kind, n)
- }
- ast.Walk(x, n.Type)
- for _, v := range n.Values {
- ast.Walk(x, v)
- }
- x.visitComment(n.Comment)
-
- case *ast.TypeSpec:
- x.visitComment(n.Doc)
- x.visitIdent(TypeDecl, n.Name)
- ast.Walk(x, n.Type)
- x.visitComment(n.Comment)
- }
-}
-
-
-func (x *Indexer) Visit(node ast.Node) ast.Visitor {
- // TODO(gri): methods in interface types are categorized as VarDecl
- switch n := node.(type) {
- case nil:
- return nil
-
- case *ast.Ident:
- x.visitIdent(Use, n)
-
- case *ast.Field:
- x.decl = nil // no snippets for fields
- x.visitComment(n.Doc)
- for _, m := range n.Names {
- x.visitIdent(VarDecl, m)
- }
- ast.Walk(x, n.Type)
- ast.Walk(x, n.Tag)
- x.visitComment(n.Comment)
-
- case *ast.DeclStmt:
- if decl, ok := n.Decl.(*ast.GenDecl); ok {
- // local declarations can only be *ast.GenDecls
- x.decl = nil // no snippets for local declarations
- x.visitComment(decl.Doc)
- for _, s := range decl.Specs {
- x.visitSpec(s, decl.Tok == token.VAR)
- }
- } else {
- // handle error case gracefully
- ast.Walk(x, n.Decl)
- }
-
- case *ast.GenDecl:
- x.decl = n
- x.visitComment(n.Doc)
- for _, s := range n.Specs {
- x.visitSpec(s, n.Tok == token.VAR)
- }
-
- case *ast.FuncDecl:
- x.visitComment(n.Doc)
- kind := FuncDecl
- if n.Recv != nil {
- kind = MethodDecl
- ast.Walk(x, n.Recv)
- }
- x.decl = n
- x.visitIdent(kind, n.Name)
- ast.Walk(x, n.Type)
- if n.Body != nil {
- ast.Walk(x, n.Body)
- }
-
- case *ast.File:
- x.visitComment(n.Doc)
- x.decl = nil
- x.visitIdent(PackageClause, n.Name)
- for _, d := range n.Decls {
- ast.Walk(x, d)
- }
- // don't visit package level comments for now
- // to avoid duplicate visiting from individual
- // nodes
-
- default:
- return x
- }
-
- return nil
-}
-
-
-func pkgName(filename string) string {
- // use a new file set each time in order to not pollute the indexer's
- // file set (which must stay in sync with the concatenated source code)
- file, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.PackageClauseOnly)
- if err != nil || file == nil {
- return ""
- }
- return file.Name.Name
-}
-
-
-// addFile adds a file to the index if possible and returns the file set file
-// and the file's AST if it was successfully parsed as a Go file. If addFile
-// failed (that is, if the file was not added), it returns file == nil.
-func (x *Indexer) addFile(filename string, goFile bool) (file *token.File, ast *ast.File) {
- // open file
- f, err := fs.Open(filename)
- if err != nil {
- return
- }
- defer f.Close()
-
- // The file set's base offset and x.sources size must be in lock-step;
- // this permits the direct mapping of suffix array lookup results to
- // to corresponding Pos values.
- //
- // When a file is added to the file set, it's offset base increases by
- // the size of the file + 1; and the initial base offset is 1. Add an
- // extra byte to the sources here.
- x.sources.WriteByte(0)
-
- // If the sources length doesn't match the file set base at this point
- // the file set implementation changed or we have another error.
- base := x.fset.Base()
- if x.sources.Len() != base {
- panic("internal error - file base incorrect")
- }
-
- // append file contents (src) to x.sources
- if _, err := x.sources.ReadFrom(f); err == nil {
- src := x.sources.Bytes()[base:]
-
- if goFile {
- // parse the file and in the process add it to the file set
- if ast, err = parser.ParseFile(x.fset, filename, src, parser.ParseComments); err == nil {
- file = x.fset.File(ast.Pos()) // ast.Pos() is inside the file
- return
- }
- // file has parse errors, and the AST may be incorrect -
- // set lines information explicitly and index as ordinary
- // text file (cannot fall through to the text case below
- // because the file has already been added to the file set
- // by the parser)
- file = x.fset.File(token.Pos(base)) // token.Pos(base) is inside the file
- file.SetLinesForContent(src)
- ast = nil
- return
- }
-
- if isText(src) {
- // only add the file to the file set (for the full text index)
- file = x.fset.AddFile(filename, x.fset.Base(), len(src))
- file.SetLinesForContent(src)
- return
- }
- }
-
- // discard possibly added data
- x.sources.Truncate(base - 1) // -1 to remove added byte 0 since no file was added
- return
-}
-
-
-// Design note: Using an explicit white list of permitted files for indexing
-// makes sure that the important files are included and massively reduces the
-// number of files to index. The advantage over a blacklist is that unexpected
-// (non-blacklisted) files won't suddenly explode the index.
-//
-// TODO(gri): We may want to make this list customizable, perhaps via a flag.
-
-// Files are whitelisted if they have a file name or extension
-// present as key in whitelisted.
-var whitelisted = map[string]bool{
- ".bash": true,
- ".c": true,
- ".css": true,
- ".go": true,
- ".goc": true,
- ".h": true,
- ".html": true,
- ".js": true,
- ".out": true,
- ".py": true,
- ".s": true,
- ".sh": true,
- ".txt": true,
- ".xml": true,
- "AUTHORS": true,
- "CONTRIBUTORS": true,
- "LICENSE": true,
- "Makefile": true,
- "PATENTS": true,
- "README": true,
-}
-
-
-// isWhitelisted returns true if a file is on the list
-// of "permitted" files for indexing. The filename must
-// be the directory-local name of the file.
-func isWhitelisted(filename string) bool {
- key := filepath.Ext(filename)
- if key == "" {
- // file has no extension - use entire filename
- key = filename
- }
- return whitelisted[key]
-}
-
-
-func (x *Indexer) visitFile(dirname string, f FileInfo, fulltextIndex bool) {
- if !f.IsRegular() {
- return
- }
-
- filename := filepath.Join(dirname, f.Name())
- goFile := false
-
- switch {
- case isGoFile(f):
- if !includeTestFiles && (!isPkgFile(f) || strings.HasPrefix(filename, "test/")) {
- return
- }
- if !includeMainPackages && pkgName(filename) == "main" {
- return
- }
- goFile = true
-
- case !fulltextIndex || !isWhitelisted(f.Name()):
- return
- }
-
- file, fast := x.addFile(filename, goFile)
- if file == nil {
- return // addFile failed
- }
-
- if fast != nil {
- // we've got a Go file to index
- x.current = file
- dir, _ := filepath.Split(filename)
- pak := Pak{dir, fast.Name.Name}
- x.file = &File{filename, pak}
- ast.Walk(x, fast)
- }
-
- // update statistics
- x.stats.Bytes += file.Size()
- x.stats.Files++
- x.stats.Lines += file.LineCount()
-}
-
-
-// ----------------------------------------------------------------------------
-// Index
-
-type LookupResult struct {
- Decls HitList // package-level declarations (with snippets)
- Others HitList // all other occurrences
-}
-
-
-type Index struct {
- fset *token.FileSet // file set used during indexing; nil if no textindex
- suffixes *suffixarray.Index // suffixes for concatenated sources; nil if no textindex
- words map[string]*LookupResult // maps words to hit lists
- alts map[string]*AltWords // maps canonical(words) to lists of alternative spellings
- snippets []*Snippet // all snippets, indexed by snippet index
- stats Statistics
-}
-
-
-func canonical(w string) string { return strings.ToLower(w) }
-
-
-// NewIndex creates a new index for the .go files
-// in the directories given by dirnames.
-//
-func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
- var x Indexer
-
- // initialize Indexer
- x.fset = token.NewFileSet()
- x.words = make(map[string]*IndexResult)
-
- // index all files in the directories given by dirnames
- for dirname := range dirnames {
- list, err := fs.ReadDir(dirname)
- if err != nil {
- continue // ignore this directory
- }
- for _, f := range list {
- if !f.IsDirectory() {
- x.visitFile(dirname, f, fulltextIndex)
- }
- }
- }
-
- if !fulltextIndex {
- // the file set, the current file, and the sources are
- // not needed after indexing if no text index is built -
- // help GC and clear them
- x.fset = nil
- x.sources.Reset()
- x.current = nil // contains reference to fset!
- }
-
- // for each word, reduce the RunLists into a LookupResult;
- // also collect the word with its canonical spelling in a
- // word list for later computation of alternative spellings
- words := make(map[string]*LookupResult)
- var wlist RunList
- for w, h := range x.words {
- decls := reduce(&h.Decls)
- others := reduce(&h.Others)
- words[w] = &LookupResult{
- Decls: decls,
- Others: others,
- }
- wlist.Push(&wordPair{canonical(w), w})
- }
- x.stats.Words = len(words)
-
- // reduce the word list {canonical(w), w} into
- // a list of AltWords runs {canonical(w), {w}}
- alist := wlist.reduce(lessWordPair, newAltWords)
-
- // convert alist into a map of alternative spellings
- alts := make(map[string]*AltWords)
- for i := 0; i < alist.Len(); i++ {
- a := alist.At(i).(*AltWords)
- alts[a.Canon] = a
- }
-
- // convert snippet vector into a list
- snippets := make([]*Snippet, x.snippets.Len())
- for i := 0; i < x.snippets.Len(); i++ {
- snippets[i] = x.snippets.At(i).(*Snippet)
- }
-
- // create text index
- var suffixes *suffixarray.Index
- if fulltextIndex {
- suffixes = suffixarray.New(x.sources.Bytes())
- }
-
- return &Index{x.fset, suffixes, words, alts, snippets, x.stats}
-}
-
-
-// Stats() returns index statistics.
-func (x *Index) Stats() Statistics {
- return x.stats
-}
-
-
-func (x *Index) LookupWord(w string) (match *LookupResult, alt *AltWords) {
- match = x.words[w]
- alt = x.alts[canonical(w)]
- // remove current spelling from alternatives
- // (if there is no match, the alternatives do
- // not contain the current spelling)
- if match != nil && alt != nil {
- alt = alt.filter(w)
- }
- return
-}
-
-
-func isIdentifier(s string) bool {
- var S scanner.Scanner
- fset := token.NewFileSet()
- S.Init(fset.AddFile("", fset.Base(), len(s)), []byte(s), nil, 0)
- if _, tok, _ := S.Scan(); tok == token.IDENT {
- _, tok, _ := S.Scan()
- return tok == token.EOF
- }
- return false
-}
-
-
-// For a given query, which is either a single identifier or a qualified
-// identifier, Lookup returns a LookupResult, and a list of alternative
-// spellings, if any. If the query syntax is wrong, an error is reported.
-func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, err os.Error) {
- ss := strings.Split(query, ".")
-
- // check query syntax
- for _, s := range ss {
- if !isIdentifier(s) {
- err = os.NewError("all query parts must be identifiers")
- return
- }
- }
-
- switch len(ss) {
- case 1:
- match, alt = x.LookupWord(ss[0])
-
- case 2:
- pakname := ss[0]
- match, alt = x.LookupWord(ss[1])
- if match != nil {
- // found a match - filter by package name
- decls := match.Decls.filter(pakname)
- others := match.Others.filter(pakname)
- match = &LookupResult{decls, others}
- }
-
- default:
- err = os.NewError("query is not a (qualified) identifier")
- }
-
- return
-}
-
-
-func (x *Index) Snippet(i int) *Snippet {
- // handle illegal snippet indices gracefully
- if 0 <= i && i < len(x.snippets) {
- return x.snippets[i]
- }
- return nil
-}
-
-
-type positionList []struct {
- filename string
- line int
-}
-
-func (list positionList) Len() int { return len(list) }
-func (list positionList) Less(i, j int) bool { return list[i].filename < list[j].filename }
-func (list positionList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
-
-
-// unique returns the list sorted and with duplicate entries removed
-func unique(list []int) []int {
- sort.Ints(list)
- var last int
- i := 0
- for _, x := range list {
- if i == 0 || x != last {
- last = x
- list[i] = x
- i++
- }
- }
- return list[0:i]
-}
-
-
-// A FileLines value specifies a file and line numbers within that file.
-type FileLines struct {
- Filename string
- Lines []int
-}
-
-
-// LookupRegexp returns the number of matches and the matches where a regular
-// expression r is found in the full text index. At most n matches are
-// returned (thus found <= n).
-//
-func (x *Index) LookupRegexp(r *regexp.Regexp, n int) (found int, result []FileLines) {
- if x.suffixes == nil || n <= 0 {
- return
- }
- // n > 0
-
- var list positionList
- // FindAllIndex may returns matches that span across file boundaries.
- // Such matches are unlikely, buf after eliminating them we may end up
- // with fewer than n matches. If we don't have enough at the end, redo
- // the search with an increased value n1, but only if FindAllIndex
- // returned all the requested matches in the first place (if it
- // returned fewer than that there cannot be more).
- for n1 := n; found < n; n1 += n - found {
- found = 0
- matches := x.suffixes.FindAllIndex(r, n1)
- // compute files, exclude matches that span file boundaries,
- // and map offsets to file-local offsets
- list = make(positionList, len(matches))
- for _, m := range matches {
- // by construction, an offset corresponds to the Pos value
- // for the file set - use it to get the file and line
- p := token.Pos(m[0])
- if file := x.fset.File(p); file != nil {
- if base := file.Base(); base <= m[1] && m[1] <= base+file.Size() {
- // match [m[0], m[1]) is within the file boundaries
- list[found].filename = file.Name()
- list[found].line = file.Line(p)
- found++
- }
- }
- }
- if found == n || len(matches) < n1 {
- // found all matches or there's no chance to find more
- break
- }
- }
- list = list[0:found]
- sort.Sort(list) // sort by filename
-
- // collect matches belonging to the same file
- var last string
- var lines []int
- addLines := func() {
- if len(lines) > 0 {
- // remove duplicate lines
- result = append(result, FileLines{last, unique(lines)})
- lines = nil
- }
- }
- for _, m := range list {
- if m.filename != last {
- addLines()
- last = m.filename
- }
- lines = append(lines, m.line)
- }
- addLines()
-
- return
-}
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
deleted file mode 100644
index 51fcf8dd0..000000000
--- a/src/cmd/godoc/main.go
+++ /dev/null
@@ -1,410 +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.
-
-// godoc: Go Documentation Server
-
-// Web server tree:
-//
-// http://godoc/ main landing page
-// http://godoc/doc/ serve from $GOROOT/doc - spec, mem, tutorial, etc.
-// http://godoc/src/ serve files from $GOROOT/src; .go gets pretty-printed
-// http://godoc/cmd/ serve documentation about commands
-// http://godoc/pkg/ serve documentation about packages
-// (idea is if you say import "compress/zlib", you go to
-// http://godoc/pkg/compress/zlib)
-//
-// Command-line interface:
-//
-// godoc packagepath [name ...]
-//
-// godoc compress/zlib
-// - prints doc for package compress/zlib
-// godoc crypto/block Cipher NewCMAC
-// - prints doc for Cipher and NewCMAC in package crypto/block
-
-package main
-
-import (
- "bytes"
- _ "expvar" // to serve /debug/vars
- "flag"
- "fmt"
- "go/ast"
- "go/build"
- "http"
- _ "http/pprof" // to serve /debug/pprof/*
- "io"
- "log"
- "os"
- "path/filepath"
- "regexp"
- "runtime"
- "strings"
- "time"
-)
-
-const defaultAddr = ":6060" // default webserver address
-
-var (
- // periodic sync
- syncCmd = flag.String("sync", "", "sync command; disabled if empty")
- syncMin = flag.Int("sync_minutes", 0, "sync interval in minutes; disabled if <= 0")
- syncDelay delayTime // actual sync interval in minutes; usually syncDelay == syncMin, but syncDelay may back off exponentially
-
- // network
- httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')")
- serverAddr = flag.String("server", "", "webserver address for command line searches")
-
- // layout control
- html = flag.Bool("html", false, "print HTML in command-line mode")
- srcMode = flag.Bool("src", false, "print (exported) source in command-line mode")
-
- // command-line searches
- query = flag.Bool("q", false, "arguments are considered search queries")
-)
-
-
-func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
- contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
- w.WriteHeader(http.StatusNotFound)
- servePage(w, "File "+relpath, "", "", contents)
-}
-
-
-func exec(rw http.ResponseWriter, args []string) (status int) {
- r, w, err := os.Pipe()
- if err != nil {
- log.Printf("os.Pipe(): %v", err)
- return 2
- }
-
- bin := args[0]
- fds := []*os.File{nil, w, w}
- if *verbose {
- log.Printf("executing %v", args)
- }
- p, err := os.StartProcess(bin, args, &os.ProcAttr{Files: fds, Dir: *goroot})
- defer r.Close()
- w.Close()
- if err != nil {
- log.Printf("os.StartProcess(%q): %v", bin, err)
- return 2
- }
- defer p.Release()
-
- var buf bytes.Buffer
- io.Copy(&buf, r)
- wait, err := p.Wait(0)
- if err != nil {
- os.Stderr.Write(buf.Bytes())
- log.Printf("os.Wait(%d, 0): %v", p.Pid, err)
- return 2
- }
- status = wait.ExitStatus()
- if !wait.Exited() || status > 1 {
- os.Stderr.Write(buf.Bytes())
- log.Printf("executing %v failed (exit status = %d)", args, status)
- return
- }
-
- if *verbose {
- os.Stderr.Write(buf.Bytes())
- }
- if rw != nil {
- rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
- rw.Write(buf.Bytes())
- }
-
- return
-}
-
-
-func dosync(w http.ResponseWriter, r *http.Request) {
- args := []string{"/bin/sh", "-c", *syncCmd}
- switch exec(w, args) {
- case 0:
- // sync succeeded and some files have changed;
- // update package tree.
- // TODO(gri): The directory tree may be temporarily out-of-sync.
- // Consider keeping separate time stamps so the web-
- // page can indicate this discrepancy.
- initFSTree()
- fallthrough
- case 1:
- // sync failed because no files changed;
- // don't change the package tree
- syncDelay.set(*syncMin) // revert to regular sync schedule
- default:
- // sync failed because of an error - back off exponentially, but try at least once a day
- syncDelay.backoff(24 * 60)
- }
-}
-
-
-func usage() {
- fmt.Fprintf(os.Stderr,
- "usage: godoc package [name ...]\n"+
- " godoc -http="+defaultAddr+"\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-
-func loggingHandler(h http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- log.Printf("%s\t%s", req.RemoteAddr, req.URL)
- h.ServeHTTP(w, req)
- })
-}
-
-
-func remoteSearch(query string) (res *http.Response, err os.Error) {
- search := "/search?f=text&q=" + http.URLEscape(query)
-
- // list of addresses to try
- var addrs []string
- if *serverAddr != "" {
- // explicit server address - only try this one
- addrs = []string{*serverAddr}
- } else {
- addrs = []string{
- defaultAddr,
- "golang.org",
- }
- }
-
- // remote search
- for _, addr := range addrs {
- url := "http://" + addr + search
- res, err = http.Get(url)
- if err == nil && res.StatusCode == http.StatusOK {
- break
- }
- }
-
- if err == nil && res.StatusCode != http.StatusOK {
- err = os.NewError(res.Status)
- }
-
- return
-}
-
-
-// Does s look like a regular expression?
-func isRegexp(s string) bool {
- return strings.IndexAny(s, ".(|)*+?^$[]") >= 0
-}
-
-
-// Make a regular expression of the form
-// names[0]|names[1]|...names[len(names)-1].
-// Returns nil if the regular expression is illegal.
-func makeRx(names []string) (rx *regexp.Regexp) {
- if len(names) > 0 {
- s := ""
- for i, name := range names {
- if i > 0 {
- s += "|"
- }
- if isRegexp(name) {
- s += name
- } else {
- s += "^" + name + "$" // must match exactly
- }
- }
- rx, _ = regexp.Compile(s) // rx is nil if there's a compilation error
- }
- return
-}
-
-
-func main() {
- flag.Usage = usage
- flag.Parse()
-
- // Determine file system to use.
- // TODO(gri) Complete this - for now we only have one.
- fs = OS
-
- // Clean goroot: normalize path separator.
- *goroot = filepath.Clean(*goroot)
-
- // Check usage: either server and no args, or command line and args
- if (*httpAddr != "") != (flag.NArg() == 0) {
- usage()
- }
-
- if *tabwidth < 0 {
- log.Fatalf("negative tabwidth %d", *tabwidth)
- }
-
- initHandlers()
- readTemplates()
-
- if *httpAddr != "" {
- // HTTP server mode.
- var handler http.Handler = http.DefaultServeMux
- if *verbose {
- log.Printf("Go Documentation Server")
- log.Printf("version = %s", runtime.Version())
- log.Printf("address = %s", *httpAddr)
- log.Printf("goroot = %s", *goroot)
- log.Printf("tabwidth = %d", *tabwidth)
- switch {
- case !*indexEnabled:
- log.Print("search index disabled")
- case *maxResults > 0:
- log.Printf("full text index enabled (maxresults = %d)", *maxResults)
- default:
- log.Print("identifier search index enabled")
- }
- if !fsMap.IsEmpty() {
- log.Print("user-defined mapping:")
- fsMap.Fprint(os.Stderr)
- }
- handler = loggingHandler(handler)
- }
-
- registerPublicHandlers(http.DefaultServeMux)
- if *syncCmd != "" {
- http.Handle("/debug/sync", http.HandlerFunc(dosync))
- }
-
- // Initialize default directory tree with corresponding timestamp.
- // (Do it in a goroutine so that launch is quick.)
- go initFSTree()
-
- // Initialize directory trees for user-defined file systems (-path flag).
- initDirTrees()
-
- // Start sync goroutine, if enabled.
- if *syncCmd != "" && *syncMin > 0 {
- syncDelay.set(*syncMin) // initial sync delay
- go func() {
- for {
- dosync(nil, nil)
- delay, _ := syncDelay.get()
- if *verbose {
- log.Printf("next sync in %dmin", delay.(int))
- }
- time.Sleep(int64(delay.(int)) * 60e9)
- }
- }()
- }
-
- // Start indexing goroutine.
- if *indexEnabled {
- go indexer()
- }
-
- // Start http server.
- if err := http.ListenAndServe(*httpAddr, handler); err != nil {
- log.Fatalf("ListenAndServe %s: %v", *httpAddr, err)
- }
-
- return
- }
-
- // Command line mode.
- if *html {
- packageText = packageHTML
- searchText = packageHTML
- }
-
- if *query {
- // Command-line queries.
- for i := 0; i < flag.NArg(); i++ {
- res, err := remoteSearch(flag.Arg(i))
- if err != nil {
- log.Fatalf("remoteSearch: %s", err)
- }
- io.Copy(os.Stdout, res.Body)
- }
- return
- }
-
- // determine paths
- path := flag.Arg(0)
- if len(path) > 0 && path[0] == '.' {
- // assume cwd; don't assume -goroot
- cwd, _ := os.Getwd() // ignore errors
- path = filepath.Join(cwd, path)
- }
- relpath := path
- abspath := path
- if t, pkg, err := build.FindTree(path); err == nil {
- relpath = pkg
- abspath = filepath.Join(t.SrcDir(), pkg)
- } else if !filepath.IsAbs(path) {
- abspath = absolutePath(path, pkgHandler.fsRoot)
- } else {
- relpath = relativeURL(path)
- }
-
- var mode PageInfoMode
- if *srcMode {
- // only filter exports if we don't have explicit command-line filter arguments
- if flag.NArg() == 1 {
- mode |= exportsOnly
- }
- } else {
- mode = exportsOnly | genDoc
- }
- // TODO(gri): Provide a mechanism (flag?) to select a package
- // if there are multiple packages in a directory.
- info := pkgHandler.getPageInfo(abspath, relpath, "", mode)
-
- if info.IsEmpty() {
- // try again, this time assume it's a command
- if !filepath.IsAbs(path) {
- abspath = absolutePath(path, cmdHandler.fsRoot)
- }
- cmdInfo := cmdHandler.getPageInfo(abspath, relpath, "", mode)
- // only use the cmdInfo if it actually contains a result
- // (don't hide errors reported from looking up a package)
- if !cmdInfo.IsEmpty() {
- info = cmdInfo
- }
- }
- if info.Err != nil {
- log.Fatalf("%v", info.Err)
- }
-
- // If we have more than one argument, use the remaining arguments for filtering
- if flag.NArg() > 1 {
- args := flag.Args()[1:]
- rx := makeRx(args)
- if rx == nil {
- log.Fatalf("illegal regular expression from %v", args)
- }
-
- filter := func(s string) bool { return rx.MatchString(s) }
- switch {
- case info.PAst != nil:
- ast.FilterFile(info.PAst, filter)
- // Special case: Don't use templates for printing
- // so we only get the filtered declarations without
- // package clause or extra whitespace.
- for i, d := range info.PAst.Decls {
- if i > 0 {
- fmt.Println()
- }
- if *html {
- writeAnyHTML(os.Stdout, info.FSet, d)
- } else {
- writeAny(os.Stdout, info.FSet, d)
- }
- fmt.Println()
- }
- return
-
- case info.PDoc != nil:
- info.PDoc.Filter(filter)
- }
- }
-
- if err := packageText.Execute(os.Stdout, info); err != nil {
- log.Printf("packageText.Execute: %s", err)
- }
-}
diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go
deleted file mode 100644
index 92614e83e..000000000
--- a/src/cmd/godoc/mapping.go
+++ /dev/null
@@ -1,210 +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.
-
-// This file implements the Mapping data structure.
-
-package main
-
-import (
- "fmt"
- "io"
- "path"
- "path/filepath"
- "sort"
- "strings"
-)
-
-
-// A Mapping object maps relative paths (e.g. from URLs)
-// to absolute paths (of the file system) and vice versa.
-//
-// A Mapping object consists of a list of individual mappings
-// of the form: prefix -> path which are interpreted as follows:
-// A relative path of the form prefix/tail is to be mapped to
-// the absolute path/tail, if that absolute path exists in the file
-// system. Given a Mapping object, a relative path is mapped to an
-// absolute path by trying each of the individual mappings in order,
-// until a valid mapping is found. For instance, for the mapping:
-//
-// user -> /home/user
-// public -> /home/user/public
-// public -> /home/build/public
-//
-// the relative paths below are mapped to absolute paths as follows:
-//
-// user/foo -> /home/user/foo
-// public/net/rpc/file1.go -> /home/user/public/net/rpc/file1.go
-//
-// If there is no /home/user/public/net/rpc/file2.go, the next public
-// mapping entry is used to map the relative path to:
-//
-// public/net/rpc/file2.go -> /home/build/public/net/rpc/file2.go
-//
-// (assuming that file exists).
-//
-// Each individual mapping also has a RWValue associated with it that
-// may be used to store mapping-specific information. See the Iterate
-// method.
-//
-type Mapping struct {
- list []mapping
- prefixes []string // lazily computed from list
-}
-
-
-type mapping struct {
- prefix, path string
- value *RWValue
-}
-
-
-// Init initializes the Mapping from a list of paths.
-// Empty paths are ignored; relative paths are assumed to be relative to
-// the current working directory and converted to absolute paths.
-// For each path of the form:
-//
-// dirname/localname
-//
-// a mapping
-//
-// localname -> path
-//
-// is added to the Mapping object, in the order of occurrence.
-// For instance, under Unix, the argument:
-//
-// /home/user:/home/build/public
-//
-// leads to the following mapping:
-//
-// user -> /home/user
-// public -> /home/build/public
-//
-func (m *Mapping) Init(paths []string) {
- pathlist := canonicalizePaths(paths, nil)
- list := make([]mapping, len(pathlist))
-
- // create mapping list
- for i, path := range pathlist {
- _, prefix := filepath.Split(path)
- list[i] = mapping{prefix, path, new(RWValue)}
- }
-
- m.list = list
-}
-
-
-// IsEmpty returns true if there are no mappings specified.
-func (m *Mapping) IsEmpty() bool { return len(m.list) == 0 }
-
-
-// PrefixList returns a list of all prefixes, with duplicates removed.
-// For instance, for the mapping:
-//
-// user -> /home/user
-// public -> /home/user/public
-// public -> /home/build/public
-//
-// the prefix list is:
-//
-// user, public
-//
-func (m *Mapping) PrefixList() []string {
- // compute the list lazily
- if m.prefixes == nil {
- list := make([]string, len(m.list))
-
- // populate list
- for i, e := range m.list {
- list[i] = e.prefix
- }
-
- // sort the list and remove duplicate entries
- sort.Strings(list)
- i := 0
- prev := ""
- for _, path := range list {
- if path != prev {
- list[i] = path
- i++
- prev = path
- }
- }
-
- m.prefixes = list[0:i]
- }
-
- return m.prefixes
-}
-
-
-// Fprint prints the mapping.
-func (m *Mapping) Fprint(w io.Writer) {
- for _, e := range m.list {
- fmt.Fprintf(w, "\t%s -> %s\n", e.prefix, e.path)
- }
-}
-
-
-func splitFirst(path string) (head, tail string) {
- i := strings.Index(path, string(filepath.Separator))
- if i > 0 {
- // 0 < i < len(path)
- return path[0:i], path[i+1:]
- }
- return "", path
-}
-
-
-// ToAbsolute maps a slash-separated relative path to an absolute filesystem
-// path using the Mapping specified by the receiver. If the path cannot
-// be mapped, the empty string is returned.
-//
-func (m *Mapping) ToAbsolute(spath string) string {
- fpath := filepath.FromSlash(spath)
- prefix, tail := splitFirst(fpath)
- for _, e := range m.list {
- switch {
- case e.prefix == prefix:
- // use tail
- case e.prefix == "":
- tail = fpath
- default:
- continue // no match
- }
- abspath := filepath.Join(e.path, tail)
- if _, err := fs.Stat(abspath); err == nil {
- return abspath
- }
- }
-
- return "" // no match
-}
-
-
-// ToRelative maps an absolute filesystem path to a relative slash-separated
-// path using the Mapping specified by the receiver. If the path cannot
-// be mapped, the empty string is returned.
-//
-func (m *Mapping) ToRelative(fpath string) string {
- for _, e := range m.list {
- if strings.HasPrefix(fpath, e.path) {
- spath := filepath.ToSlash(fpath)
- // /absolute/prefix/foo -> prefix/foo
- return path.Join(e.prefix, spath[len(e.path):]) // Join will remove a trailing '/'
- }
- }
- return "" // no match
-}
-
-
-// Iterate calls f for each path and RWValue in the mapping (in uspecified order)
-// until f returns false.
-//
-func (m *Mapping) Iterate(f func(path string, value *RWValue) bool) {
- for _, e := range m.list {
- if !f(e.path, e.value) {
- return
- }
- }
-}
diff --git a/src/cmd/godoc/parser.go b/src/cmd/godoc/parser.go
deleted file mode 100644
index 423db222d..000000000
--- a/src/cmd/godoc/parser.go
+++ /dev/null
@@ -1,69 +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.
-
-// This file contains support functions for parsing .go files.
-// Similar functionality is found in package go/parser but the
-// functions here operate using godoc's file system fs instead
-// of calling the OS's file operations directly.
-
-package main
-
-import (
- "go/ast"
- "go/parser"
- "go/token"
- "os"
- "path/filepath"
-)
-
-func parseFiles(fset *token.FileSet, filenames []string) (pkgs map[string]*ast.Package, first os.Error) {
- pkgs = make(map[string]*ast.Package)
- for _, filename := range filenames {
- src, err := fs.ReadFile(filename)
- if err != nil {
- if first == nil {
- first = err
- }
- continue
- }
-
- file, err := parser.ParseFile(fset, filename, src, parser.ParseComments)
- if err != nil {
- if first == nil {
- first = err
- }
- continue
- }
-
- name := file.Name.Name
- pkg, found := pkgs[name]
- if !found {
- // TODO(gri) Use NewPackage here; reconsider ParseFiles API.
- pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
- pkgs[name] = pkg
- }
- pkg.Files[filename] = file
- }
- return
-}
-
-
-func parseDir(fset *token.FileSet, path string, filter func(FileInfo) bool) (map[string]*ast.Package, os.Error) {
- list, err := fs.ReadDir(path)
- if err != nil {
- return nil, err
- }
-
- filenames := make([]string, len(list))
- i := 0
- for _, d := range list {
- if filter == nil || filter(d) {
- filenames[i] = filepath.Join(path, d.Name())
- i++
- }
- }
- filenames = filenames[0:i]
-
- return parseFiles(fset, filenames)
-}
diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go
deleted file mode 100755
index c5f4c1edf..000000000
--- a/src/cmd/godoc/snippet.go
+++ /dev/null
@@ -1,109 +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.
-
-// This file contains the infrastructure to create a code
-// snippet for search results.
-//
-// Note: At the moment, this only creates HTML snippets.
-
-package main
-
-import (
- "bytes"
- "go/ast"
- "go/token"
- "fmt"
-)
-
-
-type Snippet struct {
- Line int
- Text []byte
-}
-
-
-func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
- // TODO instead of pretty-printing the node, should use the original source instead
- var buf1 bytes.Buffer
- writeNode(&buf1, fset, decl)
- // wrap text with <pre> tag
- var buf2 bytes.Buffer
- buf2.WriteString("<pre>")
- FormatText(&buf2, buf1.Bytes(), -1, true, id.Name, nil)
- buf2.WriteString("</pre>")
- return &Snippet{fset.Position(id.Pos()).Line, buf2.Bytes()}
-}
-
-
-func findSpec(list []ast.Spec, id *ast.Ident) ast.Spec {
- for _, spec := range list {
- switch s := spec.(type) {
- case *ast.ImportSpec:
- if s.Name == id {
- return s
- }
- case *ast.ValueSpec:
- for _, n := range s.Names {
- if n == id {
- return s
- }
- }
- case *ast.TypeSpec:
- if s.Name == id {
- return s
- }
- }
- }
- return nil
-}
-
-
-func genSnippet(fset *token.FileSet, d *ast.GenDecl, id *ast.Ident) *Snippet {
- s := findSpec(d.Specs, id)
- if s == nil {
- return nil // declaration doesn't contain id - exit gracefully
- }
-
- // only use the spec containing the id for the snippet
- dd := &ast.GenDecl{d.Doc, d.Pos(), d.Tok, d.Lparen, []ast.Spec{s}, d.Rparen}
-
- return newSnippet(fset, dd, id)
-}
-
-
-func funcSnippet(fset *token.FileSet, d *ast.FuncDecl, id *ast.Ident) *Snippet {
- if d.Name != id {
- return nil // declaration doesn't contain id - exit gracefully
- }
-
- // only use the function signature for the snippet
- dd := &ast.FuncDecl{d.Doc, d.Recv, d.Name, d.Type, nil}
-
- return newSnippet(fset, dd, id)
-}
-
-
-// NewSnippet creates a text snippet from a declaration decl containing an
-// identifier id. Parts of the declaration not containing the identifier
-// may be removed for a more compact snippet.
-//
-func NewSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) (s *Snippet) {
- switch d := decl.(type) {
- case *ast.GenDecl:
- s = genSnippet(fset, d, id)
- case *ast.FuncDecl:
- s = funcSnippet(fset, d, id)
- }
-
- // handle failure gracefully
- if s == nil {
- var buf bytes.Buffer
- fmt.Fprintf(&buf, `<span class="alert">could not generate a snippet for <span class="highlight">%s</span></span>`, id.Name)
- s = &Snippet{
- fset.Position(id.Pos()).Line,
- buf.Bytes(),
- }
- }
- return
-}
diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go
deleted file mode 100644
index 444e36e08..000000000
--- a/src/cmd/godoc/spec.go
+++ /dev/null
@@ -1,212 +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.
-
-// This file contains the mechanism to "linkify" html source
-// text containing EBNF sections (as found in go_spec.html).
-// The result is the input source text with the EBNF sections
-// modified such that identifiers are linked to the respective
-// definitions.
-
-package main
-
-import (
- "bytes"
- "fmt"
- "go/scanner"
- "go/token"
- "io"
-)
-
-
-type ebnfParser struct {
- out io.Writer // parser output
- src []byte // parser source
- file *token.File // for position information
- scanner scanner.Scanner
- prev int // offset of previous token
- pos token.Pos // token position
- tok token.Token // one token look-ahead
- lit string // token literal
-}
-
-
-func (p *ebnfParser) flush() {
- offs := p.file.Offset(p.pos)
- p.out.Write(p.src[p.prev:offs])
- p.prev = offs
-}
-
-
-func (p *ebnfParser) next() {
- if p.pos.IsValid() {
- p.flush()
- }
- p.pos, p.tok, p.lit = p.scanner.Scan()
- if p.tok.IsKeyword() {
- // TODO Should keyword mapping always happen outside scanner?
- // Or should there be a flag to scanner to enable keyword mapping?
- p.tok = token.IDENT
- }
-}
-
-
-func (p *ebnfParser) Error(pos token.Position, msg string) {
- fmt.Fprintf(p.out, `<span class="alert">error: %s</span>`, msg)
-}
-
-
-func (p *ebnfParser) errorExpected(pos token.Pos, msg string) {
- msg = "expected " + msg
- if pos == p.pos {
- // the error happened at the current position;
- // make the error message more specific
- msg += ", found '" + p.tok.String() + "'"
- if p.tok.IsLiteral() {
- msg += " " + p.lit
- }
- }
- p.Error(p.file.Position(pos), msg)
-}
-
-
-func (p *ebnfParser) expect(tok token.Token) token.Pos {
- pos := p.pos
- if p.tok != tok {
- p.errorExpected(pos, "'"+tok.String()+"'")
- }
- p.next() // make progress in any case
- return pos
-}
-
-
-func (p *ebnfParser) parseIdentifier(def bool) {
- name := p.lit
- p.expect(token.IDENT)
- if def {
- fmt.Fprintf(p.out, `<a id="%s">%s</a>`, name, name)
- } else {
- fmt.Fprintf(p.out, `<a href="#%s" class="noline">%s</a>`, name, name)
- }
- p.prev += len(name) // skip identifier when calling flush
-}
-
-
-func (p *ebnfParser) parseTerm() bool {
- switch p.tok {
- case token.IDENT:
- p.parseIdentifier(false)
-
- case token.STRING:
- p.next()
- const ellipsis = "…" // U+2026, the horizontal ellipsis character
- if p.tok == token.ILLEGAL && p.lit == ellipsis {
- p.next()
- p.expect(token.STRING)
- }
-
- case token.LPAREN:
- p.next()
- p.parseExpression()
- p.expect(token.RPAREN)
-
- case token.LBRACK:
- p.next()
- p.parseExpression()
- p.expect(token.RBRACK)
-
- case token.LBRACE:
- p.next()
- p.parseExpression()
- p.expect(token.RBRACE)
-
- default:
- return false
- }
-
- return true
-}
-
-
-func (p *ebnfParser) parseSequence() {
- if !p.parseTerm() {
- p.errorExpected(p.pos, "term")
- }
- for p.parseTerm() {
- }
-}
-
-
-func (p *ebnfParser) parseExpression() {
- for {
- p.parseSequence()
- if p.tok != token.OR {
- break
- }
- p.next()
- }
-}
-
-
-func (p *ebnfParser) parseProduction() {
- p.parseIdentifier(true)
- p.expect(token.ASSIGN)
- if p.tok != token.PERIOD {
- p.parseExpression()
- }
- p.expect(token.PERIOD)
-}
-
-
-func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) {
- // initialize ebnfParser
- p.out = out
- p.src = src
- p.file = fset.AddFile("", fset.Base(), len(src))
- p.scanner.Init(p.file, src, p, scanner.AllowIllegalChars)
- p.next() // initializes pos, tok, lit
-
- // process source
- for p.tok != token.EOF {
- p.parseProduction()
- }
- p.flush()
-}
-
-
-// Markers around EBNF sections
-var (
- openTag = []byte(`<pre class="ebnf">`)
- closeTag = []byte(`</pre>`)
-)
-
-
-func linkify(out io.Writer, src []byte) {
- fset := token.NewFileSet()
- for len(src) > 0 {
- n := len(src)
-
- // i: beginning of EBNF text (or end of source)
- i := bytes.Index(src, openTag)
- if i < 0 {
- i = n - len(openTag)
- }
- i += len(openTag)
-
- // j: end of EBNF text (or end of source)
- j := bytes.Index(src[i:n], closeTag) // close marker
- if j < 0 {
- j = n - i
- }
- j += i
-
- // write text before EBNF
- out.Write(src[0:i])
- // parse and write EBNF
- var p ebnfParser
- p.parse(fset, out, src[i:j])
-
- // advance
- src = src[j:n]
- }
-}
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
deleted file mode 100644
index e2637ab3d..000000000
--- a/src/cmd/godoc/utils.go
+++ /dev/null
@@ -1,176 +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.
-
-// This file contains support functionality for godoc.
-
-package main
-
-import (
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "strings"
- "sync"
- "time"
- "utf8"
-)
-
-
-// An RWValue wraps a value and permits mutually exclusive
-// access to it and records the time the value was last set.
-//
-type RWValue struct {
- mutex sync.RWMutex
- value interface{}
- timestamp int64 // time of last set(), in seconds since epoch
-}
-
-
-func (v *RWValue) set(value interface{}) {
- v.mutex.Lock()
- v.value = value
- v.timestamp = time.Seconds()
- v.mutex.Unlock()
-}
-
-
-func (v *RWValue) get() (interface{}, int64) {
- v.mutex.RLock()
- defer v.mutex.RUnlock()
- return v.value, v.timestamp
-}
-
-
-// TODO(gri) For now, using os.Getwd() is ok here since the functionality
-// based on this code is not invoked for the appengine version,
-// but this is fragile. Determine what the right thing to do is,
-// here (possibly have some Getwd-equivalent in FileSystem).
-var cwd, _ = os.Getwd() // ignore errors
-
-// canonicalizePaths takes a list of (directory/file) paths and returns
-// the list of corresponding absolute paths in sorted (increasing) order.
-// Relative paths are assumed to be relative to the current directory,
-// empty and duplicate paths as well as paths for which filter(path) is
-// false are discarded. filter may be nil in which case it is not used.
-//
-func canonicalizePaths(list []string, filter func(path string) bool) []string {
- i := 0
- for _, path := range list {
- path = strings.TrimSpace(path)
- if len(path) == 0 {
- continue // ignore empty paths (don't assume ".")
- }
- // len(path) > 0: normalize path
- if filepath.IsAbs(path) {
- path = filepath.Clean(path)
- } else {
- path = filepath.Join(cwd, path)
- }
- // we have a non-empty absolute path
- if filter != nil && !filter(path) {
- continue
- }
- // keep the path
- list[i] = path
- i++
- }
- list = list[0:i]
-
- // sort the list and remove duplicate entries
- sort.Strings(list)
- i = 0
- prev := ""
- for _, path := range list {
- if path != prev {
- list[i] = path
- i++
- prev = path
- }
- }
-
- return list[0:i]
-}
-
-
-// writeFileAtomically writes data to a temporary file and then
-// atomically renames that file to the file named by filename.
-//
-func writeFileAtomically(filename string, data []byte) os.Error {
- // TODO(gri) this won't work on appengine
- f, err := ioutil.TempFile(filepath.Split(filename))
- if err != nil {
- return err
- }
- n, err := f.Write(data)
- f.Close()
- if err != nil {
- return err
- }
- if n < len(data) {
- return io.ErrShortWrite
- }
- return os.Rename(f.Name(), filename)
-}
-
-
-// isText returns true if a significant prefix of s looks like correct UTF-8;
-// that is, if it is likely that s is human-readable text.
-//
-func isText(s []byte) bool {
- const max = 1024 // at least utf8.UTFMax
- if len(s) > max {
- s = s[0:max]
- }
- for i, c := range string(s) {
- if i+utf8.UTFMax > len(s) {
- // last char may be incomplete - ignore
- break
- }
- if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' {
- // decoding error or control character - not a text file
- return false
- }
- }
- return true
-}
-
-
-// TODO(gri): Should have a mapping from extension to handler, eventually.
-
-// textExt[x] is true if the extension x indicates a text file, and false otherwise.
-var textExt = map[string]bool{
- ".css": false, // must be served raw
- ".js": false, // must be served raw
-}
-
-
-// isTextFile returns true if the file has a known extension indicating
-// a text file, or if a significant chunk of the specified file looks like
-// correct UTF-8; that is, if it is likely that the file contains human-
-// readable text.
-//
-func isTextFile(filename string) bool {
- // if the extension is known, use it for decision making
- if isText, found := textExt[filepath.Ext(filename)]; found {
- return isText
- }
-
- // the extension is not known; read an initial chunk
- // of the file and check if it looks like text
- f, err := fs.Open(filename)
- if err != nil {
- return false
- }
- defer f.Close()
-
- var buf [1024]byte
- n, err := f.Read(buf[0:])
- if err != nil {
- return false
- }
-
- return isText(buf[0:n])
-}
diff --git a/src/cmd/gofix/Makefile b/src/cmd/gofix/Makefile
deleted file mode 100644
index 7ce21e8aa..000000000
--- a/src/cmd/gofix/Makefile
+++ /dev/null
@@ -1,33 +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 ../../Make.inc
-
-TARG=gofix
-GOFILES=\
- filepath.go\
- fix.go\
- httpfinalurl.go\
- httpfs.go\
- httpheaders.go\
- httpserver.go\
- main.go\
- netdial.go\
- oserrorstring.go\
- osopen.go\
- procattr.go\
- reflect.go\
- signal.go\
- sorthelpers.go\
- sortslice.go\
- stringssplit.go\
- typecheck.go\
-
-include ../../Make.cmd
-
-test:
- gotest
-
-testshort:
- gotest -test.short
diff --git a/src/cmd/gofix/doc.go b/src/cmd/gofix/doc.go
deleted file mode 100644
index a9790e685..000000000
--- a/src/cmd/gofix/doc.go
+++ /dev/null
@@ -1,36 +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.
-
-/*
-Gofix finds Go programs that use old APIs and rewrites them to use
-newer ones. After you update to a new Go release, gofix helps make
-the necessary changes to your programs.
-
-Usage:
- gofix [-r name,...] [path ...]
-
-Without an explicit path, gofix reads standard input and writes the
-result to standard output.
-
-If the named path is a file, gofix rewrites the named files in place.
-If the named path is a directory, gofix rewrites all .go files in that
-directory tree. When gofix rewrites a file, it prints a line to standard
-error giving the name of the file and the rewrite applied.
-
-If the -diff flag is set, no files are rewritten. Instead gofix prints
-the differences a rewrite would introduce.
-
-The -r flag restricts the set of rewrites considered to those in the
-named list. By default gofix considers all known rewrites. Gofix's
-rewrites are idempotent, so that it is safe to apply gofix to updated
-or partially updated code even without using the -r flag.
-
-Gofix prints the full list of fixes it can apply in its help output;
-to see them, run gofix -?.
-
-Gofix does not make backup copies of the files that it edits.
-Instead, use a version control system's ``diff'' functionality to inspect
-the changes that gofix makes before committing them.
-*/
-package documentation
diff --git a/src/cmd/gofix/filepath.go b/src/cmd/gofix/filepath.go
deleted file mode 100644
index 1d0ad6879..000000000
--- a/src/cmd/gofix/filepath.go
+++ /dev/null
@@ -1,53 +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 main
-
-import (
- "go/ast"
-)
-
-func init() {
- register(fix{
- "filepath",
- filepathFunc,
- `Adapt code from filepath.[List]SeparatorString to string(filepath.[List]Separator).
-
-http://codereview.appspot.com/4527090
-`,
- })
-}
-
-func filepathFunc(f *ast.File) (fixed bool) {
- if !imports(f, "path/filepath") {
- return
- }
-
- walk(f, func(n interface{}) {
- e, ok := n.(*ast.Expr)
- if !ok {
- return
- }
-
- var ident string
- switch {
- case isPkgDot(*e, "filepath", "SeparatorString"):
- ident = "filepath.Separator"
- case isPkgDot(*e, "filepath", "ListSeparatorString"):
- ident = "filepath.ListSeparator"
- default:
- return
- }
-
- // string(filepath.[List]Separator)
- *e = &ast.CallExpr{
- Fun: ast.NewIdent("string"),
- Args: []ast.Expr{ast.NewIdent(ident)},
- }
-
- fixed = true
- })
-
- return
-}
diff --git a/src/cmd/gofix/filepath_test.go b/src/cmd/gofix/filepath_test.go
deleted file mode 100644
index d170c3ae3..000000000
--- a/src/cmd/gofix/filepath_test.go
+++ /dev/null
@@ -1,33 +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 main
-
-func init() {
- addTestCases(filepathTests)
-}
-
-var filepathTests = []testCase{
- {
- Name: "filepath.0",
- In: `package main
-
-import (
- "path/filepath"
-)
-
-var _ = filepath.SeparatorString
-var _ = filepath.ListSeparatorString
-`,
- Out: `package main
-
-import (
- "path/filepath"
-)
-
-var _ = string(filepath.Separator)
-var _ = string(filepath.ListSeparator)
-`,
- },
-}
diff --git a/src/cmd/gofix/fix.go b/src/cmd/gofix/fix.go
deleted file mode 100644
index c1c5a746c..000000000
--- a/src/cmd/gofix/fix.go
+++ /dev/null
@@ -1,573 +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 main
-
-import (
- "fmt"
- "go/ast"
- "go/token"
- "os"
- "strconv"
- "strings"
-)
-
-type fix struct {
- name string
- f func(*ast.File) bool
- desc string
-}
-
-// main runs sort.Sort(fixes) after init process is done.
-type fixlist []fix
-
-func (f fixlist) Len() int { return len(f) }
-func (f fixlist) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f fixlist) Less(i, j int) bool { return f[i].name < f[j].name }
-
-var fixes fixlist
-
-func register(f fix) {
- fixes = append(fixes, f)
-}
-
-// walk traverses the AST x, calling visit(y) for each node y in the tree but
-// also with a pointer to each ast.Expr, ast.Stmt, and *ast.BlockStmt,
-// in a bottom-up traversal.
-func walk(x interface{}, visit func(interface{})) {
- walkBeforeAfter(x, nop, visit)
-}
-
-func nop(interface{}) {}
-
-// walkBeforeAfter is like walk but calls before(x) before traversing
-// x's children and after(x) afterward.
-func walkBeforeAfter(x interface{}, before, after func(interface{})) {
- before(x)
-
- switch n := x.(type) {
- default:
- panic(fmt.Errorf("unexpected type %T in walkBeforeAfter", x))
-
- case nil:
-
- // pointers to interfaces
- case *ast.Decl:
- walkBeforeAfter(*n, before, after)
- case *ast.Expr:
- walkBeforeAfter(*n, before, after)
- case *ast.Spec:
- walkBeforeAfter(*n, before, after)
- case *ast.Stmt:
- walkBeforeAfter(*n, before, after)
-
- // pointers to struct pointers
- case **ast.BlockStmt:
- walkBeforeAfter(*n, before, after)
- case **ast.CallExpr:
- walkBeforeAfter(*n, before, after)
- case **ast.FieldList:
- walkBeforeAfter(*n, before, after)
- case **ast.FuncType:
- walkBeforeAfter(*n, before, after)
-
- // pointers to slices
- case *[]ast.Stmt:
- walkBeforeAfter(*n, before, after)
- case *[]ast.Expr:
- walkBeforeAfter(*n, before, after)
- case *[]ast.Decl:
- walkBeforeAfter(*n, before, after)
- case *[]ast.Spec:
- walkBeforeAfter(*n, before, after)
- case *[]*ast.File:
- walkBeforeAfter(*n, before, after)
-
- // These are ordered and grouped to match ../../pkg/go/ast/ast.go
- case *ast.Field:
- walkBeforeAfter(&n.Type, before, after)
- case *ast.FieldList:
- for _, field := range n.List {
- walkBeforeAfter(field, before, after)
- }
- case *ast.BadExpr:
- case *ast.Ident:
- case *ast.Ellipsis:
- case *ast.BasicLit:
- case *ast.FuncLit:
- walkBeforeAfter(&n.Type, before, after)
- walkBeforeAfter(&n.Body, before, after)
- case *ast.CompositeLit:
- walkBeforeAfter(&n.Type, before, after)
- walkBeforeAfter(&n.Elts, before, after)
- case *ast.ParenExpr:
- walkBeforeAfter(&n.X, before, after)
- case *ast.SelectorExpr:
- walkBeforeAfter(&n.X, before, after)
- case *ast.IndexExpr:
- walkBeforeAfter(&n.X, before, after)
- walkBeforeAfter(&n.Index, before, after)
- case *ast.SliceExpr:
- walkBeforeAfter(&n.X, before, after)
- if n.Low != nil {
- walkBeforeAfter(&n.Low, before, after)
- }
- if n.High != nil {
- walkBeforeAfter(&n.High, before, after)
- }
- case *ast.TypeAssertExpr:
- walkBeforeAfter(&n.X, before, after)
- walkBeforeAfter(&n.Type, before, after)
- case *ast.CallExpr:
- walkBeforeAfter(&n.Fun, before, after)
- walkBeforeAfter(&n.Args, before, after)
- case *ast.StarExpr:
- walkBeforeAfter(&n.X, before, after)
- case *ast.UnaryExpr:
- walkBeforeAfter(&n.X, before, after)
- case *ast.BinaryExpr:
- walkBeforeAfter(&n.X, before, after)
- walkBeforeAfter(&n.Y, before, after)
- case *ast.KeyValueExpr:
- walkBeforeAfter(&n.Key, before, after)
- walkBeforeAfter(&n.Value, before, after)
-
- case *ast.ArrayType:
- walkBeforeAfter(&n.Len, before, after)
- walkBeforeAfter(&n.Elt, before, after)
- case *ast.StructType:
- walkBeforeAfter(&n.Fields, before, after)
- case *ast.FuncType:
- walkBeforeAfter(&n.Params, before, after)
- if n.Results != nil {
- walkBeforeAfter(&n.Results, before, after)
- }
- case *ast.InterfaceType:
- walkBeforeAfter(&n.Methods, before, after)
- case *ast.MapType:
- walkBeforeAfter(&n.Key, before, after)
- walkBeforeAfter(&n.Value, before, after)
- case *ast.ChanType:
- walkBeforeAfter(&n.Value, before, after)
-
- case *ast.BadStmt:
- case *ast.DeclStmt:
- walkBeforeAfter(&n.Decl, before, after)
- case *ast.EmptyStmt:
- case *ast.LabeledStmt:
- walkBeforeAfter(&n.Stmt, before, after)
- case *ast.ExprStmt:
- walkBeforeAfter(&n.X, before, after)
- case *ast.SendStmt:
- walkBeforeAfter(&n.Chan, before, after)
- walkBeforeAfter(&n.Value, before, after)
- case *ast.IncDecStmt:
- walkBeforeAfter(&n.X, before, after)
- case *ast.AssignStmt:
- walkBeforeAfter(&n.Lhs, before, after)
- walkBeforeAfter(&n.Rhs, before, after)
- case *ast.GoStmt:
- walkBeforeAfter(&n.Call, before, after)
- case *ast.DeferStmt:
- walkBeforeAfter(&n.Call, before, after)
- case *ast.ReturnStmt:
- walkBeforeAfter(&n.Results, before, after)
- case *ast.BranchStmt:
- case *ast.BlockStmt:
- walkBeforeAfter(&n.List, before, after)
- case *ast.IfStmt:
- walkBeforeAfter(&n.Init, before, after)
- walkBeforeAfter(&n.Cond, before, after)
- walkBeforeAfter(&n.Body, before, after)
- walkBeforeAfter(&n.Else, before, after)
- case *ast.CaseClause:
- walkBeforeAfter(&n.List, before, after)
- walkBeforeAfter(&n.Body, before, after)
- case *ast.SwitchStmt:
- walkBeforeAfter(&n.Init, before, after)
- walkBeforeAfter(&n.Tag, before, after)
- walkBeforeAfter(&n.Body, before, after)
- case *ast.TypeSwitchStmt:
- walkBeforeAfter(&n.Init, before, after)
- walkBeforeAfter(&n.Assign, before, after)
- walkBeforeAfter(&n.Body, before, after)
- case *ast.CommClause:
- walkBeforeAfter(&n.Comm, before, after)
- walkBeforeAfter(&n.Body, before, after)
- case *ast.SelectStmt:
- walkBeforeAfter(&n.Body, before, after)
- case *ast.ForStmt:
- walkBeforeAfter(&n.Init, before, after)
- walkBeforeAfter(&n.Cond, before, after)
- walkBeforeAfter(&n.Post, before, after)
- walkBeforeAfter(&n.Body, before, after)
- case *ast.RangeStmt:
- walkBeforeAfter(&n.Key, before, after)
- walkBeforeAfter(&n.Value, before, after)
- walkBeforeAfter(&n.X, before, after)
- walkBeforeAfter(&n.Body, before, after)
-
- case *ast.ImportSpec:
- case *ast.ValueSpec:
- walkBeforeAfter(&n.Type, before, after)
- walkBeforeAfter(&n.Values, before, after)
- case *ast.TypeSpec:
- walkBeforeAfter(&n.Type, before, after)
-
- case *ast.BadDecl:
- case *ast.GenDecl:
- walkBeforeAfter(&n.Specs, before, after)
- case *ast.FuncDecl:
- if n.Recv != nil {
- walkBeforeAfter(&n.Recv, before, after)
- }
- walkBeforeAfter(&n.Type, before, after)
- if n.Body != nil {
- walkBeforeAfter(&n.Body, before, after)
- }
-
- case *ast.File:
- walkBeforeAfter(&n.Decls, before, after)
-
- case *ast.Package:
- walkBeforeAfter(&n.Files, before, after)
-
- case []*ast.File:
- for i := range n {
- walkBeforeAfter(&n[i], before, after)
- }
- case []ast.Decl:
- for i := range n {
- walkBeforeAfter(&n[i], before, after)
- }
- case []ast.Expr:
- for i := range n {
- walkBeforeAfter(&n[i], before, after)
- }
- case []ast.Stmt:
- for i := range n {
- walkBeforeAfter(&n[i], before, after)
- }
- case []ast.Spec:
- for i := range n {
- walkBeforeAfter(&n[i], before, after)
- }
- }
- after(x)
-}
-
-// imports returns true if f imports path.
-func imports(f *ast.File, path string) bool {
- return importSpec(f, path) != nil
-}
-
-// importSpec returns the import spec if f imports path,
-// or nil otherwise.
-func importSpec(f *ast.File, path string) *ast.ImportSpec {
- for _, s := range f.Imports {
- if importPath(s) == path {
- return s
- }
- }
- return nil
-}
-
-// importPath returns the unquoted import path of s,
-// or "" if the path is not properly quoted.
-func importPath(s *ast.ImportSpec) string {
- t, err := strconv.Unquote(s.Path.Value)
- if err == nil {
- return t
- }
- return ""
-}
-
-// isPkgDot returns true if t is the expression "pkg.name"
-// where pkg is an imported identifier.
-func isPkgDot(t ast.Expr, pkg, name string) bool {
- sel, ok := t.(*ast.SelectorExpr)
- return ok && isTopName(sel.X, pkg) && sel.Sel.String() == name
-}
-
-// isPtrPkgDot returns true if f is the expression "*pkg.name"
-// where pkg is an imported identifier.
-func isPtrPkgDot(t ast.Expr, pkg, name string) bool {
- ptr, ok := t.(*ast.StarExpr)
- return ok && isPkgDot(ptr.X, pkg, name)
-}
-
-// isTopName returns true if n is a top-level unresolved identifier with the given name.
-func isTopName(n ast.Expr, name string) bool {
- id, ok := n.(*ast.Ident)
- return ok && id.Name == name && id.Obj == nil
-}
-
-// isName returns true if n is an identifier with the given name.
-func isName(n ast.Expr, name string) bool {
- id, ok := n.(*ast.Ident)
- return ok && id.String() == name
-}
-
-// isCall returns true if t is a call to pkg.name.
-func isCall(t ast.Expr, pkg, name string) bool {
- call, ok := t.(*ast.CallExpr)
- return ok && isPkgDot(call.Fun, pkg, name)
-}
-
-// If n is an *ast.Ident, isIdent returns it; otherwise isIdent returns nil.
-func isIdent(n interface{}) *ast.Ident {
- id, _ := n.(*ast.Ident)
- return id
-}
-
-// refersTo returns true if n is a reference to the same object as x.
-func refersTo(n ast.Node, x *ast.Ident) bool {
- id, ok := n.(*ast.Ident)
- // The test of id.Name == x.Name handles top-level unresolved
- // identifiers, which all have Obj == nil.
- return ok && id.Obj == x.Obj && id.Name == x.Name
-}
-
-// isBlank returns true if n is the blank identifier.
-func isBlank(n ast.Expr) bool {
- return isName(n, "_")
-}
-
-// isEmptyString returns true if n is an empty string literal.
-func isEmptyString(n ast.Expr) bool {
- lit, ok := n.(*ast.BasicLit)
- return ok && lit.Kind == token.STRING && len(lit.Value) == 2
-}
-
-func warn(pos token.Pos, msg string, args ...interface{}) {
- if pos.IsValid() {
- msg = "%s: " + msg
- arg1 := []interface{}{fset.Position(pos).String()}
- args = append(arg1, args...)
- }
- fmt.Fprintf(os.Stderr, msg+"\n", args...)
-}
-
-// countUses returns the number of uses of the identifier x in scope.
-func countUses(x *ast.Ident, scope []ast.Stmt) int {
- count := 0
- ff := func(n interface{}) {
- if n, ok := n.(ast.Node); ok && refersTo(n, x) {
- count++
- }
- }
- for _, n := range scope {
- walk(n, ff)
- }
- return count
-}
-
-// rewriteUses replaces all uses of the identifier x and !x in scope
-// with f(x.Pos()) and fnot(x.Pos()).
-func rewriteUses(x *ast.Ident, f, fnot func(token.Pos) ast.Expr, scope []ast.Stmt) {
- var lastF ast.Expr
- ff := func(n interface{}) {
- ptr, ok := n.(*ast.Expr)
- if !ok {
- return
- }
- nn := *ptr
-
- // The child node was just walked and possibly replaced.
- // If it was replaced and this is a negation, replace with fnot(p).
- not, ok := nn.(*ast.UnaryExpr)
- if ok && not.Op == token.NOT && not.X == lastF {
- *ptr = fnot(nn.Pos())
- return
- }
- if refersTo(nn, x) {
- lastF = f(nn.Pos())
- *ptr = lastF
- }
- }
- for _, n := range scope {
- walk(n, ff)
- }
-}
-
-// assignsTo returns true if any of the code in scope assigns to or takes the address of x.
-func assignsTo(x *ast.Ident, scope []ast.Stmt) bool {
- assigned := false
- ff := func(n interface{}) {
- if assigned {
- return
- }
- switch n := n.(type) {
- case *ast.UnaryExpr:
- // use of &x
- if n.Op == token.AND && refersTo(n.X, x) {
- assigned = true
- return
- }
- case *ast.AssignStmt:
- for _, l := range n.Lhs {
- if refersTo(l, x) {
- assigned = true
- return
- }
- }
- }
- }
- for _, n := range scope {
- if assigned {
- break
- }
- walk(n, ff)
- }
- return assigned
-}
-
-// newPkgDot returns an ast.Expr referring to "pkg.name" at position pos.
-func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
- return &ast.SelectorExpr{
- X: &ast.Ident{
- NamePos: pos,
- Name: pkg,
- },
- Sel: &ast.Ident{
- NamePos: pos,
- Name: name,
- },
- }
-}
-
-// addImport adds the import path to the file f, if absent.
-func addImport(f *ast.File, path string) {
- if imports(f, path) {
- return
- }
-
- newImport := &ast.ImportSpec{
- Path: &ast.BasicLit{
- Kind: token.STRING,
- Value: strconv.Quote(path),
- },
- }
-
- var impdecl *ast.GenDecl
-
- // Find an import decl to add to.
- for _, decl := range f.Decls {
- gen, ok := decl.(*ast.GenDecl)
-
- if ok && gen.Tok == token.IMPORT {
- impdecl = gen
- break
- }
- }
-
- // No import decl found. Add one.
- if impdecl == nil {
- impdecl = &ast.GenDecl{
- Tok: token.IMPORT,
- }
- f.Decls = append(f.Decls, nil)
- copy(f.Decls[1:], f.Decls)
- f.Decls[0] = impdecl
- }
-
- // Ensure the import decl has parentheses, if needed.
- if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() {
- impdecl.Lparen = impdecl.Pos()
- }
-
- // Assume the import paths are alphabetically ordered.
- // If they are not, the result is ugly, but legal.
- insertAt := len(impdecl.Specs) // default to end of specs
- for i, spec := range impdecl.Specs {
- impspec := spec.(*ast.ImportSpec)
- if importPath(impspec) > path {
- insertAt = i
- break
- }
- }
-
- impdecl.Specs = append(impdecl.Specs, nil)
- copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:])
- impdecl.Specs[insertAt] = newImport
-
- f.Imports = append(f.Imports, newImport)
-}
-
-// deleteImport deletes the import path from the file f, if present.
-func deleteImport(f *ast.File, path string) {
- oldImport := importSpec(f, path)
-
- // Find the import node that imports path, if any.
- for i, decl := range f.Decls {
- gen, ok := decl.(*ast.GenDecl)
- if !ok || gen.Tok != token.IMPORT {
- continue
- }
- for j, spec := range gen.Specs {
- impspec := spec.(*ast.ImportSpec)
-
- if oldImport != impspec {
- continue
- }
-
- // We found an import spec that imports path.
- // Delete it.
- copy(gen.Specs[j:], gen.Specs[j+1:])
- gen.Specs = gen.Specs[:len(gen.Specs)-1]
-
- // If this was the last import spec in this decl,
- // delete the decl, too.
- if len(gen.Specs) == 0 {
- copy(f.Decls[i:], f.Decls[i+1:])
- f.Decls = f.Decls[:len(f.Decls)-1]
- } else if len(gen.Specs) == 1 {
- gen.Lparen = token.NoPos // drop parens
- }
-
- break
- }
- }
-
- // Delete it from f.Imports.
- for i, imp := range f.Imports {
- if imp == oldImport {
- copy(f.Imports[i:], f.Imports[i+1:])
- f.Imports = f.Imports[:len(f.Imports)-1]
- break
- }
- }
-}
-
-func usesImport(f *ast.File, path string) (used bool) {
- spec := importSpec(f, path)
- if spec == nil {
- return
- }
-
- name := spec.Name.String()
- switch name {
- case "<nil>":
- // If the package name is not explicitly specified,
- // make an educated guess. This is not guaranteed to be correct.
- lastSlash := strings.LastIndex(path, "/")
- if lastSlash == -1 {
- name = path
- } else {
- name = path[lastSlash+1:]
- }
- case "_", ".":
- // Not sure if this import is used - err on the side of caution.
- return true
- }
-
- walk(f, func(n interface{}) {
- sel, ok := n.(*ast.SelectorExpr)
- if ok && isTopName(sel.X, name) {
- used = true
- }
- })
-
- return
-}
diff --git a/src/cmd/gofix/httpfinalurl.go b/src/cmd/gofix/httpfinalurl.go
deleted file mode 100644
index 9e6cbf6bc..000000000
--- a/src/cmd/gofix/httpfinalurl.go
+++ /dev/null
@@ -1,56 +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 main
-
-import (
- "go/ast"
-)
-
-var httpFinalURLFix = fix{
- "httpfinalurl",
- httpfinalurl,
- `Adapt http Get calls to not have a finalURL result parameter.
-
-http://codereview.appspot.com/4535056/
-`,
-}
-
-func init() {
- register(httpFinalURLFix)
-}
-
-func httpfinalurl(f *ast.File) bool {
- if !imports(f, "http") {
- return false
- }
-
- fixed := false
- walk(f, func(n interface{}) {
- // Fix up calls to http.Get.
- //
- // If they have blank identifiers, remove them:
- // resp, _, err := http.Get(url)
- // -> resp, err := http.Get(url)
- //
- // But if they're using the finalURL parameter, warn:
- // resp, finalURL, err := http.Get(url)
- as, ok := n.(*ast.AssignStmt)
- if !ok || len(as.Lhs) != 3 || len(as.Rhs) != 1 {
- return
- }
-
- if !isCall(as.Rhs[0], "http", "Get") {
- return
- }
-
- if isBlank(as.Lhs[1]) {
- as.Lhs = []ast.Expr{as.Lhs[0], as.Lhs[2]}
- fixed = true
- } else {
- warn(as.Pos(), "call to http.Get records final URL")
- }
- })
- return fixed
-}
diff --git a/src/cmd/gofix/httpfinalurl_test.go b/src/cmd/gofix/httpfinalurl_test.go
deleted file mode 100644
index 9e7d6242d..000000000
--- a/src/cmd/gofix/httpfinalurl_test.go
+++ /dev/null
@@ -1,37 +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 main
-
-func init() {
- addTestCases(httpfinalurlTests)
-}
-
-var httpfinalurlTests = []testCase{
- {
- Name: "finalurl.0",
- In: `package main
-
-import (
- "http"
-)
-
-func f() {
- resp, _, err := http.Get("http://www.google.com/")
- _, _ = resp, err
-}
-`,
- Out: `package main
-
-import (
- "http"
-)
-
-func f() {
- resp, err := http.Get("http://www.google.com/")
- _, _ = resp, err
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/httpfs.go b/src/cmd/gofix/httpfs.go
deleted file mode 100644
index 7f2765680..000000000
--- a/src/cmd/gofix/httpfs.go
+++ /dev/null
@@ -1,63 +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 main
-
-import (
- "go/ast"
- "go/token"
-)
-
-var httpFileSystemFix = fix{
- "httpfs",
- httpfs,
- `Adapt http FileServer to take a FileSystem.
-
-http://codereview.appspot.com/4629047 http FileSystem interface
-`,
-}
-
-func init() {
- register(httpFileSystemFix)
-}
-
-func httpfs(f *ast.File) bool {
- if !imports(f, "http") {
- return false
- }
-
- fixed := false
- walk(f, func(n interface{}) {
- call, ok := n.(*ast.CallExpr)
- if !ok || !isPkgDot(call.Fun, "http", "FileServer") {
- return
- }
- if len(call.Args) != 2 {
- return
- }
- dir, prefix := call.Args[0], call.Args[1]
- call.Args = []ast.Expr{&ast.CallExpr{
- Fun: &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("Dir")},
- Args: []ast.Expr{dir},
- }}
- wrapInStripHandler := true
- if prefixLit, ok := prefix.(*ast.BasicLit); ok {
- if prefixLit.Kind == token.STRING && (prefixLit.Value == `"/"` || prefixLit.Value == `""`) {
- wrapInStripHandler = false
- }
- }
- if wrapInStripHandler {
- call.Fun.(*ast.SelectorExpr).Sel = ast.NewIdent("StripPrefix")
- call.Args = []ast.Expr{
- prefix,
- &ast.CallExpr{
- Fun: &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("FileServer")},
- Args: call.Args,
- },
- }
- }
- fixed = true
- })
- return fixed
-}
diff --git a/src/cmd/gofix/httpfs_test.go b/src/cmd/gofix/httpfs_test.go
deleted file mode 100644
index d1804e93b..000000000
--- a/src/cmd/gofix/httpfs_test.go
+++ /dev/null
@@ -1,47 +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 main
-
-func init() {
- addTestCases(httpFileSystemTests)
-}
-
-var httpFileSystemTests = []testCase{
- {
- Name: "httpfs.0",
- In: `package httpfs
-
-import (
- "http"
-)
-
-func f() {
- _ = http.FileServer("/var/www/foo", "/")
- _ = http.FileServer("/var/www/foo", "")
- _ = http.FileServer("/var/www/foo/bar", "/bar")
- s := "/foo"
- _ = http.FileServer(s, "/")
- prefix := "/p"
- _ = http.FileServer(s, prefix)
-}
-`,
- Out: `package httpfs
-
-import (
- "http"
-)
-
-func f() {
- _ = http.FileServer(http.Dir("/var/www/foo"))
- _ = http.FileServer(http.Dir("/var/www/foo"))
- _ = http.StripPrefix("/bar", http.FileServer(http.Dir("/var/www/foo/bar")))
- s := "/foo"
- _ = http.FileServer(http.Dir(s))
- prefix := "/p"
- _ = http.StripPrefix(prefix, http.FileServer(http.Dir(s)))
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/httpheaders.go b/src/cmd/gofix/httpheaders.go
deleted file mode 100644
index 8a9080e8e..000000000
--- a/src/cmd/gofix/httpheaders.go
+++ /dev/null
@@ -1,66 +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 main
-
-import (
- "go/ast"
-)
-
-var httpHeadersFix = fix{
- "httpheaders",
- httpheaders,
- `Rename http Referer, UserAgent, Cookie, SetCookie, which are now methods.
-
-http://codereview.appspot.com/4620049/
-`,
-}
-
-func init() {
- register(httpHeadersFix)
-}
-
-func httpheaders(f *ast.File) bool {
- if !imports(f, "http") {
- return false
- }
-
- called := make(map[ast.Node]bool)
- walk(f, func(ni interface{}) {
- switch n := ni.(type) {
- case *ast.CallExpr:
- called[n.Fun] = true
- }
- })
-
- fixed := false
- typeof := typecheck(headerTypeConfig, f)
- walk(f, func(ni interface{}) {
- switch n := ni.(type) {
- case *ast.SelectorExpr:
- if called[n] {
- break
- }
- if t := typeof[n.X]; t != "*http.Request" && t != "*http.Response" {
- break
- }
- switch n.Sel.Name {
- case "Referer", "UserAgent":
- n.Sel.Name += "()"
- fixed = true
- case "Cookie":
- n.Sel.Name = "Cookies()"
- fixed = true
- }
- }
- })
- return fixed
-}
-
-var headerTypeConfig = &TypeConfig{
- Type: map[string]*Type{
- "*http.Request": &Type{},
- "*http.Response": &Type{},
- },
-}
diff --git a/src/cmd/gofix/httpheaders_test.go b/src/cmd/gofix/httpheaders_test.go
deleted file mode 100644
index cc82b5893..000000000
--- a/src/cmd/gofix/httpheaders_test.go
+++ /dev/null
@@ -1,73 +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 main
-
-func init() {
- addTestCases(httpHeadersTests)
-}
-
-var httpHeadersTests = []testCase{
- {
- Name: "httpheaders.0",
- In: `package headertest
-
-import (
- "http"
-)
-
-type Other struct {
- Referer string
- UserAgent string
- Cookie []*http.Cookie
-}
-
-func f(req *http.Request, res *http.Response, other *Other) {
- _ = req.Referer
- _ = req.UserAgent
- _ = req.Cookie
-
- _ = res.Cookie
-
- _ = other.Referer
- _ = other.UserAgent
- _ = other.Cookie
-
- _ = req.Referer()
- _ = req.UserAgent()
- _ = req.Cookies()
- _ = res.Cookies()
-}
-`,
- Out: `package headertest
-
-import (
- "http"
-)
-
-type Other struct {
- Referer string
- UserAgent string
- Cookie []*http.Cookie
-}
-
-func f(req *http.Request, res *http.Response, other *Other) {
- _ = req.Referer()
- _ = req.UserAgent()
- _ = req.Cookies()
-
- _ = res.Cookies()
-
- _ = other.Referer
- _ = other.UserAgent
- _ = other.Cookie
-
- _ = req.Referer()
- _ = req.UserAgent()
- _ = req.Cookies()
- _ = res.Cookies()
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/httpserver.go b/src/cmd/gofix/httpserver.go
deleted file mode 100644
index 37866e88b..000000000
--- a/src/cmd/gofix/httpserver.go
+++ /dev/null
@@ -1,140 +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 main
-
-import (
- "go/ast"
- "go/token"
-)
-
-var httpserverFix = fix{
- "httpserver",
- httpserver,
- `Adapt http server methods and functions to changes
-made to the http ResponseWriter interface.
-
-http://codereview.appspot.com/4245064 Hijacker
-http://codereview.appspot.com/4239076 Header
-http://codereview.appspot.com/4239077 Flusher
-http://codereview.appspot.com/4248075 RemoteAddr, UsingTLS
-`,
-}
-
-func init() {
- register(httpserverFix)
-}
-
-func httpserver(f *ast.File) bool {
- if !imports(f, "http") {
- return false
- }
-
- fixed := false
- for _, decl := range f.Decls {
- fn, ok := decl.(*ast.FuncDecl)
- if !ok {
- continue
- }
- w, req, ok := isServeHTTP(fn)
- if !ok {
- continue
- }
- walk(fn.Body, func(n interface{}) {
- // Want to replace expression sometimes,
- // so record pointer to it for updating below.
- ptr, ok := n.(*ast.Expr)
- if ok {
- n = *ptr
- }
-
- // Look for w.UsingTLS() and w.Remoteaddr().
- call, ok := n.(*ast.CallExpr)
- if !ok || (len(call.Args) != 0 && len(call.Args) != 2) {
- return
- }
- sel, ok := call.Fun.(*ast.SelectorExpr)
- if !ok {
- return
- }
- if !refersTo(sel.X, w) {
- return
- }
- switch sel.Sel.String() {
- case "Hijack":
- // replace w with w.(http.Hijacker)
- sel.X = &ast.TypeAssertExpr{
- X: sel.X,
- Type: ast.NewIdent("http.Hijacker"),
- }
- fixed = true
- case "Flush":
- // replace w with w.(http.Flusher)
- sel.X = &ast.TypeAssertExpr{
- X: sel.X,
- Type: ast.NewIdent("http.Flusher"),
- }
- fixed = true
- case "UsingTLS":
- if ptr == nil {
- // can only replace expression if we have pointer to it
- break
- }
- // replace with req.TLS != nil
- *ptr = &ast.BinaryExpr{
- X: &ast.SelectorExpr{
- X: ast.NewIdent(req.String()),
- Sel: ast.NewIdent("TLS"),
- },
- Op: token.NEQ,
- Y: ast.NewIdent("nil"),
- }
- fixed = true
- case "RemoteAddr":
- if ptr == nil {
- // can only replace expression if we have pointer to it
- break
- }
- // replace with req.RemoteAddr
- *ptr = &ast.SelectorExpr{
- X: ast.NewIdent(req.String()),
- Sel: ast.NewIdent("RemoteAddr"),
- }
- fixed = true
- case "SetHeader":
- // replace w.SetHeader with w.Header().Set
- // or w.Header().Del if second argument is ""
- sel.X = &ast.CallExpr{
- Fun: &ast.SelectorExpr{
- X: ast.NewIdent(w.String()),
- Sel: ast.NewIdent("Header"),
- },
- }
- sel.Sel = ast.NewIdent("Set")
- if len(call.Args) == 2 && isEmptyString(call.Args[1]) {
- sel.Sel = ast.NewIdent("Del")
- call.Args = call.Args[:1]
- }
- fixed = true
- }
- })
- }
- return fixed
-}
-
-func isServeHTTP(fn *ast.FuncDecl) (w, req *ast.Ident, ok bool) {
- for _, field := range fn.Type.Params.List {
- if isPkgDot(field.Type, "http", "ResponseWriter") {
- w = field.Names[0]
- continue
- }
- if isPtrPkgDot(field.Type, "http", "Request") {
- req = field.Names[0]
- continue
- }
- }
-
- ok = w != nil && req != nil
- return
-}
diff --git a/src/cmd/gofix/httpserver_test.go b/src/cmd/gofix/httpserver_test.go
deleted file mode 100644
index 89bb4fa71..000000000
--- a/src/cmd/gofix/httpserver_test.go
+++ /dev/null
@@ -1,53 +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 main
-
-func init() {
- addTestCases(httpserverTests)
-}
-
-var httpserverTests = []testCase{
- {
- Name: "httpserver.0",
- In: `package main
-
-import "http"
-
-func f(xyz http.ResponseWriter, abc *http.Request, b string) {
- xyz.SetHeader("foo", "bar")
- xyz.SetHeader("baz", "")
- xyz.Hijack()
- xyz.Flush()
- go xyz.Hijack()
- defer xyz.Flush()
- _ = xyz.UsingTLS()
- _ = true == xyz.UsingTLS()
- _ = xyz.RemoteAddr()
- _ = xyz.RemoteAddr() == "hello"
- if xyz.UsingTLS() {
- }
-}
-`,
- Out: `package main
-
-import "http"
-
-func f(xyz http.ResponseWriter, abc *http.Request, b string) {
- xyz.Header().Set("foo", "bar")
- xyz.Header().Del("baz")
- xyz.(http.Hijacker).Hijack()
- xyz.(http.Flusher).Flush()
- go xyz.(http.Hijacker).Hijack()
- defer xyz.(http.Flusher).Flush()
- _ = abc.TLS != nil
- _ = true == (abc.TLS != nil)
- _ = abc.RemoteAddr
- _ = abc.RemoteAddr == "hello"
- if abc.TLS != nil {
- }
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/main.go b/src/cmd/gofix/main.go
deleted file mode 100644
index e7e7013c5..000000000
--- a/src/cmd/gofix/main.go
+++ /dev/null
@@ -1,258 +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 main
-
-import (
- "bytes"
- "exec"
- "flag"
- "fmt"
- "go/parser"
- "go/printer"
- "go/scanner"
- "go/token"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "strings"
-)
-
-var (
- fset = token.NewFileSet()
- exitCode = 0
-)
-
-var allowedRewrites = flag.String("r", "",
- "restrict the rewrites to this comma-separated list")
-
-var allowed map[string]bool
-
-var doDiff = flag.Bool("diff", false, "display diffs instead of rewriting files")
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: gofix [-diff] [-r fixname,...] [path ...]\n")
- flag.PrintDefaults()
- fmt.Fprintf(os.Stderr, "\nAvailable rewrites are:\n")
- for _, f := range fixes {
- fmt.Fprintf(os.Stderr, "\n%s\n", f.name)
- desc := strings.TrimSpace(f.desc)
- desc = strings.Replace(desc, "\n", "\n\t", -1)
- fmt.Fprintf(os.Stderr, "\t%s\n", desc)
- }
- os.Exit(2)
-}
-
-func main() {
- sort.Sort(fixes)
-
- flag.Usage = usage
- flag.Parse()
-
- if *allowedRewrites != "" {
- allowed = make(map[string]bool)
- for _, f := range strings.Split(*allowedRewrites, ",") {
- allowed[f] = true
- }
- }
-
- if flag.NArg() == 0 {
- if err := processFile("standard input", true); err != nil {
- report(err)
- }
- os.Exit(exitCode)
- }
-
- for i := 0; i < flag.NArg(); i++ {
- path := flag.Arg(i)
- switch dir, err := os.Stat(path); {
- case err != nil:
- report(err)
- case dir.IsRegular():
- if err := processFile(path, false); err != nil {
- report(err)
- }
- case dir.IsDirectory():
- walkDir(path)
- }
- }
-
- os.Exit(exitCode)
-}
-
-const (
- tabWidth = 8
- parserMode = parser.ParseComments
- printerMode = printer.TabIndent | printer.UseSpaces
-)
-
-var printConfig = &printer.Config{
- printerMode,
- tabWidth,
-}
-
-func processFile(filename string, useStdin bool) os.Error {
- var f *os.File
- var err os.Error
- var fixlog bytes.Buffer
- var buf bytes.Buffer
-
- if useStdin {
- f = os.Stdin
- } else {
- f, err = os.Open(filename)
- if err != nil {
- return err
- }
- defer f.Close()
- }
-
- src, err := ioutil.ReadAll(f)
- if err != nil {
- return err
- }
-
- file, err := parser.ParseFile(fset, filename, src, parserMode)
- if err != nil {
- return err
- }
-
- // Apply all fixes to file.
- newFile := file
- fixed := false
- for _, fix := range fixes {
- if allowed != nil && !allowed[fix.name] {
- continue
- }
- if fix.f(newFile) {
- fixed = true
- fmt.Fprintf(&fixlog, " %s", fix.name)
-
- // AST changed.
- // Print and parse, to update any missing scoping
- // or position information for subsequent fixers.
- buf.Reset()
- _, err = printConfig.Fprint(&buf, fset, newFile)
- if err != nil {
- return err
- }
- newSrc := buf.Bytes()
- newFile, err = parser.ParseFile(fset, filename, newSrc, parserMode)
- if err != nil {
- return err
- }
- }
- }
- if !fixed {
- return nil
- }
- fmt.Fprintf(os.Stderr, "%s: fixed %s\n", filename, fixlog.String()[1:])
-
- // Print AST. We did that after each fix, so this appears
- // redundant, but it is necessary to generate gofmt-compatible
- // source code in a few cases. The official gofmt style is the
- // output of the printer run on a standard AST generated by the parser,
- // but the source we generated inside the loop above is the
- // output of the printer run on a mangled AST generated by a fixer.
- buf.Reset()
- _, err = printConfig.Fprint(&buf, fset, newFile)
- if err != nil {
- return err
- }
- newSrc := buf.Bytes()
-
- if *doDiff {
- data, err := diff(src, newSrc)
- if err != nil {
- return fmt.Errorf("computing diff: %s", err)
- }
- fmt.Printf("diff %s fixed/%s\n", filename, filename)
- os.Stdout.Write(data)
- return nil
- }
-
- if useStdin {
- os.Stdout.Write(newSrc)
- return nil
- }
-
- return ioutil.WriteFile(f.Name(), newSrc, 0)
-}
-
-var gofmtBuf bytes.Buffer
-
-func gofmt(n interface{}) string {
- gofmtBuf.Reset()
- _, err := printConfig.Fprint(&gofmtBuf, fset, n)
- if err != nil {
- return "<" + err.String() + ">"
- }
- return gofmtBuf.String()
-}
-
-func report(err os.Error) {
- scanner.PrintError(os.Stderr, err)
- exitCode = 2
-}
-
-func walkDir(path string) {
- v := make(fileVisitor)
- go func() {
- filepath.Walk(path, v, v)
- close(v)
- }()
- for err := range v {
- if err != nil {
- report(err)
- }
- }
-}
-
-type fileVisitor chan os.Error
-
-func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
- return true
-}
-
-func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
- if isGoFile(f) {
- v <- nil // synchronize error handler
- if err := processFile(path, false); err != nil {
- v <- err
- }
- }
-}
-
-func isGoFile(f *os.FileInfo) bool {
- // ignore non-Go files
- return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
-}
-
-func diff(b1, b2 []byte) (data []byte, err os.Error) {
- f1, err := ioutil.TempFile("", "gofix")
- if err != nil {
- return nil, err
- }
- defer os.Remove(f1.Name())
- defer f1.Close()
-
- f2, err := ioutil.TempFile("", "gofix")
- if err != nil {
- return nil, err
- }
- defer os.Remove(f2.Name())
- defer f2.Close()
-
- f1.Write(b1)
- f2.Write(b2)
-
- data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
- if len(data) > 0 {
- // diff exits with a non-zero status when the files don't match.
- // Ignore that failure as long as we get output.
- err = nil
- }
- return
-}
diff --git a/src/cmd/gofix/main_test.go b/src/cmd/gofix/main_test.go
deleted file mode 100644
index 275778e5b..000000000
--- a/src/cmd/gofix/main_test.go
+++ /dev/null
@@ -1,126 +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 main
-
-import (
- "bytes"
- "go/ast"
- "go/parser"
- "go/printer"
- "strings"
- "testing"
-)
-
-type testCase struct {
- Name string
- Fn func(*ast.File) bool
- In string
- Out string
-}
-
-var testCases []testCase
-
-func addTestCases(t []testCase) {
- testCases = append(testCases, t...)
-}
-
-func fnop(*ast.File) bool { return false }
-
-func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string) (out string, fixed, ok bool) {
- file, err := parser.ParseFile(fset, desc, in, parserMode)
- if err != nil {
- t.Errorf("%s: parsing: %v", desc, err)
- return
- }
-
- var buf bytes.Buffer
- buf.Reset()
- _, err = (&printer.Config{printerMode, tabWidth}).Fprint(&buf, fset, file)
- if err != nil {
- t.Errorf("%s: printing: %v", desc, err)
- return
- }
- if s := buf.String(); in != s && fn != fnop {
- t.Errorf("%s: not gofmt-formatted.\n--- %s\n%s\n--- %s | gofmt\n%s",
- desc, desc, in, desc, s)
- tdiff(t, in, s)
- return
- }
-
- if fn == nil {
- for _, fix := range fixes {
- if fix.f(file) {
- fixed = true
- }
- }
- } else {
- fixed = fn(file)
- }
-
- buf.Reset()
- _, err = (&printer.Config{printerMode, tabWidth}).Fprint(&buf, fset, file)
- if err != nil {
- t.Errorf("%s: printing: %v", desc, err)
- return
- }
-
- return buf.String(), fixed, true
-}
-
-func TestRewrite(t *testing.T) {
- for _, tt := range testCases {
- // Apply fix: should get tt.Out.
- out, fixed, ok := parseFixPrint(t, tt.Fn, tt.Name, tt.In)
- if !ok {
- continue
- }
-
- // reformat to get printing right
- out, _, ok = parseFixPrint(t, fnop, tt.Name, out)
- if !ok {
- continue
- }
-
- if out != tt.Out {
- t.Errorf("%s: incorrect output.\n", tt.Name)
- if !strings.HasPrefix(tt.Name, "testdata/") {
- t.Errorf("--- have\n%s\n--- want\n%s", out, tt.Out)
- }
- tdiff(t, out, tt.Out)
- continue
- }
-
- if changed := out != tt.In; changed != fixed {
- t.Errorf("%s: changed=%v != fixed=%v", tt.Name, changed, fixed)
- continue
- }
-
- // Should not change if run again.
- out2, fixed2, ok := parseFixPrint(t, tt.Fn, tt.Name+" output", out)
- if !ok {
- continue
- }
-
- if fixed2 {
- t.Errorf("%s: applied fixes during second round", tt.Name)
- continue
- }
-
- if out2 != out {
- t.Errorf("%s: changed output after second round of fixes.\n--- output after first round\n%s\n--- output after second round\n%s",
- tt.Name, out, out2)
- tdiff(t, out, out2)
- }
- }
-}
-
-func tdiff(t *testing.T, a, b string) {
- data, err := diff([]byte(a), []byte(b))
- if err != nil {
- t.Error(err)
- return
- }
- t.Error(string(data))
-}
diff --git a/src/cmd/gofix/netdial.go b/src/cmd/gofix/netdial.go
deleted file mode 100644
index afa98953b..000000000
--- a/src/cmd/gofix/netdial.go
+++ /dev/null
@@ -1,114 +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 main
-
-import (
- "go/ast"
-)
-
-var netdialFix = fix{
- "netdial",
- netdial,
- `Adapt 3-argument calls of net.Dial to use 2-argument form.
-
-http://codereview.appspot.com/4244055
-`,
-}
-
-var tlsdialFix = fix{
- "tlsdial",
- tlsdial,
- `Adapt 4-argument calls of tls.Dial to use 3-argument form.
-
-http://codereview.appspot.com/4244055
-`,
-}
-
-var netlookupFix = fix{
- "netlookup",
- netlookup,
- `Adapt 3-result calls to net.LookupHost to use 2-result form.
-
-http://codereview.appspot.com/4244055
-`,
-}
-
-func init() {
- register(netdialFix)
- register(tlsdialFix)
- register(netlookupFix)
-}
-
-func netdial(f *ast.File) bool {
- if !imports(f, "net") {
- return false
- }
-
- fixed := false
- walk(f, func(n interface{}) {
- call, ok := n.(*ast.CallExpr)
- if !ok || !isPkgDot(call.Fun, "net", "Dial") || len(call.Args) != 3 {
- return
- }
- // net.Dial(a, "", b) -> net.Dial(a, b)
- if !isEmptyString(call.Args[1]) {
- warn(call.Pos(), "call to net.Dial with non-empty second argument")
- return
- }
- call.Args[1] = call.Args[2]
- call.Args = call.Args[:2]
- fixed = true
- })
- return fixed
-}
-
-func tlsdial(f *ast.File) bool {
- if !imports(f, "crypto/tls") {
- return false
- }
-
- fixed := false
- walk(f, func(n interface{}) {
- call, ok := n.(*ast.CallExpr)
- if !ok || !isPkgDot(call.Fun, "tls", "Dial") || len(call.Args) != 4 {
- return
- }
- // tls.Dial(a, "", b, c) -> tls.Dial(a, b, c)
- if !isEmptyString(call.Args[1]) {
- warn(call.Pos(), "call to tls.Dial with non-empty second argument")
- return
- }
- call.Args[1] = call.Args[2]
- call.Args[2] = call.Args[3]
- call.Args = call.Args[:3]
- fixed = true
- })
- return fixed
-}
-
-func netlookup(f *ast.File) bool {
- if !imports(f, "net") {
- return false
- }
-
- fixed := false
- walk(f, func(n interface{}) {
- as, ok := n.(*ast.AssignStmt)
- if !ok || len(as.Lhs) != 3 || len(as.Rhs) != 1 {
- return
- }
- call, ok := as.Rhs[0].(*ast.CallExpr)
- if !ok || !isPkgDot(call.Fun, "net", "LookupHost") {
- return
- }
- if !isBlank(as.Lhs[2]) {
- warn(as.Pos(), "call to net.LookupHost expecting cname; use net.LookupCNAME")
- return
- }
- as.Lhs = as.Lhs[:2]
- fixed = true
- })
- return fixed
-}
diff --git a/src/cmd/gofix/netdial_test.go b/src/cmd/gofix/netdial_test.go
deleted file mode 100644
index 272aa526a..000000000
--- a/src/cmd/gofix/netdial_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package main
-
-func init() {
- addTestCases(netdialTests)
-}
-
-var netdialTests = []testCase{
- {
- Name: "netdial.0",
- In: `package main
-
-import "net"
-
-func f() {
- c, err := net.Dial(net, "", addr)
- c, err = net.Dial(net, "", addr)
-}
-`,
- Out: `package main
-
-import "net"
-
-func f() {
- c, err := net.Dial(net, addr)
- c, err = net.Dial(net, addr)
-}
-`,
- },
-
- {
- Name: "netlookup.0",
- In: `package main
-
-import "net"
-
-func f() {
- foo, bar, _ := net.LookupHost(host)
- foo, bar, _ = net.LookupHost(host)
-}
-`,
- Out: `package main
-
-import "net"
-
-func f() {
- foo, bar := net.LookupHost(host)
- foo, bar = net.LookupHost(host)
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/oserrorstring.go b/src/cmd/gofix/oserrorstring.go
deleted file mode 100644
index 5e61ab952..000000000
--- a/src/cmd/gofix/oserrorstring.go
+++ /dev/null
@@ -1,75 +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 main
-
-import (
- "go/ast"
-)
-
-var oserrorstringFix = fix{
- "oserrorstring",
- oserrorstring,
- `Replace os.ErrorString() conversions with calls to os.NewError().
-
-http://codereview.appspot.com/4607052
-`,
-}
-
-func init() {
- register(oserrorstringFix)
-}
-
-func oserrorstring(f *ast.File) bool {
- if !imports(f, "os") {
- return false
- }
-
- fixed := false
- walk(f, func(n interface{}) {
- // The conversion os.ErrorString(x) looks like a call
- // of os.ErrorString with one argument.
- if call := callExpr(n, "os", "ErrorString"); call != nil {
- // os.ErrorString(args) -> os.NewError(args)
- call.Fun.(*ast.SelectorExpr).Sel.Name = "NewError"
- // os.ErrorString(args) -> os.NewError(args)
- call.Fun.(*ast.SelectorExpr).Sel.Name = "NewError"
- fixed = true
- return
- }
-
- // Remove os.Error type from variable declarations initialized
- // with an os.NewError.
- // (An *ast.ValueSpec may also be used in a const declaration
- // but those won't be initialized with a call to os.NewError.)
- if spec, ok := n.(*ast.ValueSpec); ok &&
- len(spec.Names) == 1 &&
- isPkgDot(spec.Type, "os", "Error") &&
- len(spec.Values) == 1 &&
- callExpr(spec.Values[0], "os", "NewError") != nil {
- // var name os.Error = os.NewError(x) ->
- // var name = os.NewError(x)
- spec.Type = nil
- fixed = true
- return
- }
-
- // Other occurrences of os.ErrorString are not fixed
- // but they are rare.
-
- })
- return fixed
-}
-
-
-// callExpr returns the call expression if x is a call to pkg.name with one argument;
-// otherwise it returns nil.
-func callExpr(x interface{}, pkg, name string) *ast.CallExpr {
- if call, ok := x.(*ast.CallExpr); ok &&
- len(call.Args) == 1 &&
- isPkgDot(call.Fun, pkg, name) {
- return call
- }
- return nil
-}
diff --git a/src/cmd/gofix/oserrorstring_test.go b/src/cmd/gofix/oserrorstring_test.go
deleted file mode 100644
index 070d9222b..000000000
--- a/src/cmd/gofix/oserrorstring_test.go
+++ /dev/null
@@ -1,57 +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 main
-
-func init() {
- addTestCases(oserrorstringTests)
-}
-
-var oserrorstringTests = []testCase{
- {
- Name: "oserrorstring.0",
- In: `package main
-
-import "os"
-
-var _ = os.ErrorString("foo")
-var _ os.Error = os.ErrorString("bar1")
-var _ os.Error = os.NewError("bar2")
-var _ os.Error = MyError("bal") // don't rewrite this one
-
-var (
- _ = os.ErrorString("foo")
- _ os.Error = os.ErrorString("bar1")
- _ os.Error = os.NewError("bar2")
- _ os.Error = MyError("bal") // don't rewrite this one
-)
-
-func _() (err os.Error) {
- err = os.ErrorString("foo")
- return os.ErrorString("foo")
-}
-`,
- Out: `package main
-
-import "os"
-
-var _ = os.NewError("foo")
-var _ = os.NewError("bar1")
-var _ = os.NewError("bar2")
-var _ os.Error = MyError("bal") // don't rewrite this one
-
-var (
- _ = os.NewError("foo")
- _ = os.NewError("bar1")
- _ = os.NewError("bar2")
- _ os.Error = MyError("bal") // don't rewrite this one
-)
-
-func _() (err os.Error) {
- err = os.NewError("foo")
- return os.NewError("foo")
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/osopen.go b/src/cmd/gofix/osopen.go
deleted file mode 100644
index 56147c390..000000000
--- a/src/cmd/gofix/osopen.go
+++ /dev/null
@@ -1,122 +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 main
-
-import (
- "go/ast"
-)
-
-var osopenFix = fix{
- "osopen",
- osopen,
- `Adapt os.Open calls to new, easier API and rename O_CREAT O_CREATE.
-
-http://codereview.appspot.com/4357052
-`,
-}
-
-func init() {
- register(osopenFix)
-}
-
-func osopen(f *ast.File) bool {
- if !imports(f, "os") {
- return false
- }
-
- fixed := false
- walk(f, func(n interface{}) {
- // Rename O_CREAT to O_CREATE.
- if expr, ok := n.(ast.Expr); ok && isPkgDot(expr, "os", "O_CREAT") {
- expr.(*ast.SelectorExpr).Sel.Name = "O_CREATE"
- return
- }
-
- // Fix up calls to Open.
- call, ok := n.(*ast.CallExpr)
- if !ok || len(call.Args) != 3 {
- return
- }
- if !isPkgDot(call.Fun, "os", "Open") {
- return
- }
- sel := call.Fun.(*ast.SelectorExpr)
- args := call.Args
- // os.Open(a, os.O_RDONLY, c) -> os.Open(a)
- if isPkgDot(args[1], "os", "O_RDONLY") || isPkgDot(args[1], "syscall", "O_RDONLY") {
- call.Args = call.Args[0:1]
- fixed = true
- return
- }
- // os.Open(a, createlike_flags, c) -> os.Create(a, c)
- if isCreateFlag(args[1]) {
- sel.Sel.Name = "Create"
- if !isSimplePerm(args[2]) {
- warn(sel.Pos(), "rewrote os.Open to os.Create with permission not 0666")
- }
- call.Args = args[0:1]
- fixed = true
- return
- }
- // Fallback: os.Open(a, b, c) -> os.OpenFile(a, b, c)
- sel.Sel.Name = "OpenFile"
- fixed = true
- })
- return fixed
-}
-
-func isCreateFlag(flag ast.Expr) bool {
- foundCreate := false
- foundTrunc := false
- // OR'ing of flags: is O_CREATE on? + or | would be fine; we just look for os.O_CREATE
- // and don't worry about the actual operator.
- p := flag.Pos()
- for {
- lhs := flag
- expr, isBinary := flag.(*ast.BinaryExpr)
- if isBinary {
- lhs = expr.Y
- }
- sel, ok := lhs.(*ast.SelectorExpr)
- if !ok || !isTopName(sel.X, "os") {
- return false
- }
- switch sel.Sel.Name {
- case "O_CREATE":
- foundCreate = true
- case "O_TRUNC":
- foundTrunc = true
- case "O_RDONLY", "O_WRONLY", "O_RDWR":
- // okay
- default:
- // Unexpected flag, like O_APPEND or O_EXCL.
- // Be conservative and do not rewrite.
- return false
- }
- if !isBinary {
- break
- }
- flag = expr.X
- }
- if !foundCreate {
- return false
- }
- if !foundTrunc {
- warn(p, "rewrote os.Open with O_CREATE but not O_TRUNC to os.Create")
- }
- return foundCreate
-}
-
-func isSimplePerm(perm ast.Expr) bool {
- basicLit, ok := perm.(*ast.BasicLit)
- if !ok {
- return false
- }
- switch basicLit.Value {
- case "0666":
- return true
- }
- return false
-}
diff --git a/src/cmd/gofix/osopen_test.go b/src/cmd/gofix/osopen_test.go
deleted file mode 100644
index 43ddd1a40..000000000
--- a/src/cmd/gofix/osopen_test.go
+++ /dev/null
@@ -1,59 +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 main
-
-func init() {
- addTestCases(osopenTests)
-}
-
-var osopenTests = []testCase{
- {
- Name: "osopen.0",
- In: `package main
-
-import (
- "os"
-)
-
-func f() {
- os.OpenFile(a, b, c)
- os.Open(a, os.O_RDONLY, 0)
- os.Open(a, os.O_RDONLY, 0666)
- os.Open(a, os.O_RDWR, 0)
- os.Open(a, os.O_CREAT, 0666)
- os.Open(a, os.O_CREAT|os.O_TRUNC, 0664)
- os.Open(a, os.O_CREATE, 0666)
- os.Open(a, os.O_CREATE|os.O_TRUNC, 0664)
- os.Open(a, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
- os.Open(a, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
- os.Open(a, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
- os.Open(a, os.O_SURPRISE|os.O_CREATE, 0666)
- _ = os.O_CREAT
-}
-`,
- Out: `package main
-
-import (
- "os"
-)
-
-func f() {
- os.OpenFile(a, b, c)
- os.Open(a)
- os.Open(a)
- os.OpenFile(a, os.O_RDWR, 0)
- os.Create(a)
- os.Create(a)
- os.Create(a)
- os.Create(a)
- os.Create(a)
- os.OpenFile(a, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
- os.OpenFile(a, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
- os.OpenFile(a, os.O_SURPRISE|os.O_CREATE, 0666)
- _ = os.O_CREATE
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/procattr.go b/src/cmd/gofix/procattr.go
deleted file mode 100644
index 0e2190b1f..000000000
--- a/src/cmd/gofix/procattr.go
+++ /dev/null
@@ -1,61 +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 main
-
-import (
- "go/ast"
- "go/token"
-)
-
-var procattrFix = fix{
- "procattr",
- procattr,
- `Adapt calls to os.StartProcess to use new ProcAttr type.
-
-http://codereview.appspot.com/4253052
-`,
-}
-
-func init() {
- register(procattrFix)
-}
-
-func procattr(f *ast.File) bool {
- if !imports(f, "os") && !imports(f, "syscall") {
- return false
- }
-
- fixed := false
- walk(f, func(n interface{}) {
- call, ok := n.(*ast.CallExpr)
- if !ok || len(call.Args) != 5 {
- return
- }
- var pkg string
- if isPkgDot(call.Fun, "os", "StartProcess") {
- pkg = "os"
- } else if isPkgDot(call.Fun, "syscall", "StartProcess") {
- pkg = "syscall"
- } else {
- return
- }
- // os.StartProcess(a, b, c, d, e) -> os.StartProcess(a, b, &os.ProcAttr{Env: c, Dir: d, Files: e})
- lit := &ast.CompositeLit{Type: ast.NewIdent(pkg + ".ProcAttr")}
- env, dir, files := call.Args[2], call.Args[3], call.Args[4]
- if !isName(env, "nil") && !isCall(env, "os", "Environ") {
- lit.Elts = append(lit.Elts, &ast.KeyValueExpr{Key: ast.NewIdent("Env"), Value: env})
- }
- if !isEmptyString(dir) {
- lit.Elts = append(lit.Elts, &ast.KeyValueExpr{Key: ast.NewIdent("Dir"), Value: dir})
- }
- if !isName(files, "nil") {
- lit.Elts = append(lit.Elts, &ast.KeyValueExpr{Key: ast.NewIdent("Files"), Value: files})
- }
- call.Args[2] = &ast.UnaryExpr{Op: token.AND, X: lit}
- call.Args = call.Args[:3]
- fixed = true
- })
- return fixed
-}
diff --git a/src/cmd/gofix/procattr_test.go b/src/cmd/gofix/procattr_test.go
deleted file mode 100644
index b973b9684..000000000
--- a/src/cmd/gofix/procattr_test.go
+++ /dev/null
@@ -1,74 +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 main
-
-func init() {
- addTestCases(procattrTests)
-}
-
-var procattrTests = []testCase{
- {
- Name: "procattr.0",
- In: `package main
-
-import (
- "os"
- "syscall"
-)
-
-func f() {
- os.StartProcess(a, b, c, d, e)
- os.StartProcess(a, b, os.Environ(), d, e)
- os.StartProcess(a, b, nil, d, e)
- os.StartProcess(a, b, c, "", e)
- os.StartProcess(a, b, c, d, nil)
- os.StartProcess(a, b, nil, "", nil)
-
- os.StartProcess(
- a,
- b,
- c,
- d,
- e,
- )
-
- syscall.StartProcess(a, b, c, d, e)
- syscall.StartProcess(a, b, os.Environ(), d, e)
- syscall.StartProcess(a, b, nil, d, e)
- syscall.StartProcess(a, b, c, "", e)
- syscall.StartProcess(a, b, c, d, nil)
- syscall.StartProcess(a, b, nil, "", nil)
-}
-`,
- Out: `package main
-
-import (
- "os"
- "syscall"
-)
-
-func f() {
- os.StartProcess(a, b, &os.ProcAttr{Env: c, Dir: d, Files: e})
- os.StartProcess(a, b, &os.ProcAttr{Dir: d, Files: e})
- os.StartProcess(a, b, &os.ProcAttr{Dir: d, Files: e})
- os.StartProcess(a, b, &os.ProcAttr{Env: c, Files: e})
- os.StartProcess(a, b, &os.ProcAttr{Env: c, Dir: d})
- os.StartProcess(a, b, &os.ProcAttr{})
-
- os.StartProcess(
- a,
- b, &os.ProcAttr{Env: c, Dir: d, Files: e},
- )
-
- syscall.StartProcess(a, b, &syscall.ProcAttr{Env: c, Dir: d, Files: e})
- syscall.StartProcess(a, b, &syscall.ProcAttr{Dir: d, Files: e})
- syscall.StartProcess(a, b, &syscall.ProcAttr{Dir: d, Files: e})
- syscall.StartProcess(a, b, &syscall.ProcAttr{Env: c, Files: e})
- syscall.StartProcess(a, b, &syscall.ProcAttr{Env: c, Dir: d})
- syscall.StartProcess(a, b, &syscall.ProcAttr{})
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/reflect.go b/src/cmd/gofix/reflect.go
deleted file mode 100644
index 3c8becaef..000000000
--- a/src/cmd/gofix/reflect.go
+++ /dev/null
@@ -1,861 +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.
-
-// TODO(rsc): Once there is better support for writing
-// multi-package commands, this should really be in
-// its own package, and then we can drop all the "reflect"
-// prefixes on the global variables and functions.
-
-package main
-
-import (
- "go/ast"
- "go/token"
- "strings"
-)
-
-var reflectFix = fix{
- "reflect",
- reflectFn,
- `Adapt code to new reflect API.
-
-http://codereview.appspot.com/4281055
-http://codereview.appspot.com/4433066
-`,
-}
-
-func init() {
- register(reflectFix)
-}
-
-// The reflect API change dropped the concrete types *reflect.ArrayType etc.
-// Any type assertions prior to method calls can be deleted:
-// x.(*reflect.ArrayType).Len() -> x.Len()
-//
-// Any type checks can be replaced by assignment and check of Kind:
-// x, y := z.(*reflect.ArrayType)
-// ->
-// x := z
-// y := x.Kind() == reflect.Array
-//
-// If z is an ordinary variable name and x is not subsequently assigned to,
-// references to x can be replaced by z and the assignment deleted.
-// We only bother if x and z are the same name.
-// If y is not subsequently assigned to and neither is x, references to
-// y can be replaced by its expression. We only bother when there is
-// just one use or when the use appears in an if clause.
-//
-// Not all type checks result in a single Kind check. The rewrite of the type check for
-// reflect.ArrayOrSliceType checks x.Kind() against reflect.Array and reflect.Slice.
-// The rewrite for *reflect.IntType checks againt Int, Int8, Int16, Int32, Int64.
-// The rewrite for *reflect.UintType adds Uintptr.
-//
-// A type switch turns into an assignment and a switch on Kind:
-// switch x := y.(type) {
-// case reflect.ArrayOrSliceType:
-// ...
-// case *reflect.ChanType:
-// ...
-// case *reflect.IntType:
-// ...
-// }
-// ->
-// switch x := y; x.Kind() {
-// case reflect.Array, reflect.Slice:
-// ...
-// case reflect.Chan:
-// ...
-// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-// ...
-// }
-//
-// The same simplification applies: we drop x := x if x is not assigned
-// to in the switch cases.
-//
-// Because the type check assignment includes a type assertion in its
-// syntax and the rewrite traversal is bottom up, we must do a pass to
-// rewrite the type check assignments and then a separate pass to
-// rewrite the type assertions.
-//
-// The same process applies to the API changes for reflect.Value.
-//
-// For both cases, but especially Value, the code needs to be aware
-// of the type of a receiver when rewriting a method call. For example,
-// x.(*reflect.ArrayValue).Elem(i) becomes x.Index(i) while
-// x.(*reflect.MapValue).Elem(v) becomes x.MapIndex(v).
-// In general, reflectFn needs to know the type of the receiver expression.
-// In most cases (and in all the cases in the Go source tree), the toy
-// type checker in typecheck.go provides enough information for gofix
-// to make the rewrite. If gofix misses a rewrite, the code that is left over
-// will not compile, so it will be noticed immediately.
-
-func reflectFn(f *ast.File) bool {
- if !imports(f, "reflect") {
- return false
- }
-
- fixed := false
-
- // Rewrite names in method calls.
- // Needs basic type information (see above).
- typeof := typecheck(reflectTypeConfig, f)
- walk(f, func(n interface{}) {
- switch n := n.(type) {
- case *ast.SelectorExpr:
- typ := typeof[n.X]
- if m := reflectRewriteMethod[typ]; m != nil {
- if replace := m[n.Sel.Name]; replace != "" {
- n.Sel.Name = replace
- fixed = true
- return
- }
- }
-
- // For all reflect Values, replace SetValue with Set.
- if isReflectValue[typ] && n.Sel.Name == "SetValue" {
- n.Sel.Name = "Set"
- fixed = true
- return
- }
-
- // Replace reflect.MakeZero with reflect.Zero.
- if isPkgDot(n, "reflect", "MakeZero") {
- n.Sel.Name = "Zero"
- fixed = true
- return
- }
- }
- })
-
- // Replace PtrValue's PointTo(x) with Set(x.Addr()).
- walk(f, func(n interface{}) {
- call, ok := n.(*ast.CallExpr)
- if !ok || len(call.Args) != 1 {
- return
- }
- sel, ok := call.Fun.(*ast.SelectorExpr)
- if !ok || sel.Sel.Name != "PointTo" {
- return
- }
- typ := typeof[sel.X]
- if typ != "*reflect.PtrValue" {
- return
- }
- sel.Sel.Name = "Set"
- if !isTopName(call.Args[0], "nil") {
- call.Args[0] = &ast.SelectorExpr{
- X: call.Args[0],
- Sel: ast.NewIdent("Addr()"),
- }
- }
- fixed = true
- })
-
- // Fix type switches.
- walk(f, func(n interface{}) {
- if reflectFixSwitch(n) {
- fixed = true
- }
- })
-
- // Fix type assertion checks (multiple assignment statements).
- // Have to work on the statement context (statement list or if statement)
- // so that we can insert an extra statement occasionally.
- // Ignoring for and switch because they don't come up in
- // typical code.
- walk(f, func(n interface{}) {
- switch n := n.(type) {
- case *[]ast.Stmt:
- // v is the replacement statement list.
- var v []ast.Stmt
- insert := func(x ast.Stmt) {
- v = append(v, x)
- }
- for i, x := range *n {
- // Tentatively append to v; if we rewrite x
- // we'll have to update the entry, so remember
- // the index.
- j := len(v)
- v = append(v, x)
- if reflectFixTypecheck(&x, insert, (*n)[i+1:]) {
- // reflectFixTypecheck may have overwritten x.
- // Update the entry we appended just before the call.
- v[j] = x
- fixed = true
- }
- }
- *n = v
- case *ast.IfStmt:
- x := &ast.ExprStmt{n.Cond}
- if reflectFixTypecheck(&n.Init, nil, []ast.Stmt{x, n.Body, n.Else}) {
- n.Cond = x.X
- fixed = true
- }
- }
- })
-
- // Warn about any typecheck statements that we missed.
- walk(f, reflectWarnTypecheckStmt)
-
- // Now that those are gone, fix remaining type assertions.
- // Delayed because the type checks have
- // type assertions as part of their syntax.
- walk(f, func(n interface{}) {
- if reflectFixAssert(n) {
- fixed = true
- }
- })
-
- // Now that the type assertions are gone, rewrite remaining
- // references to specific reflect types to use the general ones.
- walk(f, func(n interface{}) {
- ptr, ok := n.(*ast.Expr)
- if !ok {
- return
- }
- nn := *ptr
- typ := reflectType(nn)
- if typ == "" {
- return
- }
- if strings.HasSuffix(typ, "Type") {
- *ptr = newPkgDot(nn.Pos(), "reflect", "Type")
- } else {
- *ptr = newPkgDot(nn.Pos(), "reflect", "Value")
- }
- fixed = true
- })
-
- // Rewrite v.Set(nil) to v.Set(reflect.MakeZero(v.Type())).
- walk(f, func(n interface{}) {
- call, ok := n.(*ast.CallExpr)
- if !ok || len(call.Args) != 1 || !isTopName(call.Args[0], "nil") {
- return
- }
- sel, ok := call.Fun.(*ast.SelectorExpr)
- if !ok || !isReflectValue[typeof[sel.X]] || sel.Sel.Name != "Set" {
- return
- }
- call.Args[0] = &ast.CallExpr{
- Fun: newPkgDot(call.Args[0].Pos(), "reflect", "Zero"),
- Args: []ast.Expr{
- &ast.CallExpr{
- Fun: &ast.SelectorExpr{
- X: sel.X,
- Sel: &ast.Ident{Name: "Type"},
- },
- },
- },
- }
- fixed = true
- })
-
- // Rewrite v != nil to v.IsValid().
- // Rewrite nil used as reflect.Value (in function argument or return) to reflect.Value{}.
- walk(f, func(n interface{}) {
- ptr, ok := n.(*ast.Expr)
- if !ok {
- return
- }
- if isTopName(*ptr, "nil") && isReflectValue[typeof[*ptr]] {
- *ptr = ast.NewIdent("reflect.Value{}")
- fixed = true
- return
- }
- nn, ok := (*ptr).(*ast.BinaryExpr)
- if !ok || (nn.Op != token.EQL && nn.Op != token.NEQ) || !isTopName(nn.Y, "nil") || !isReflectValue[typeof[nn.X]] {
- return
- }
- var call ast.Expr = &ast.CallExpr{
- Fun: &ast.SelectorExpr{
- X: nn.X,
- Sel: &ast.Ident{Name: "IsValid"},
- },
- }
- if nn.Op == token.EQL {
- call = &ast.UnaryExpr{Op: token.NOT, X: call}
- }
- *ptr = call
- fixed = true
- })
-
- // Rewrite
- // reflect.Typeof -> reflect.TypeOf,
- walk(f, func(n interface{}) {
- sel, ok := n.(*ast.SelectorExpr)
- if !ok {
- return
- }
- if isTopName(sel.X, "reflect") && sel.Sel.Name == "Typeof" {
- sel.Sel.Name = "TypeOf"
- fixed = true
- }
- if isTopName(sel.X, "reflect") && sel.Sel.Name == "NewValue" {
- sel.Sel.Name = "ValueOf"
- fixed = true
- }
- })
-
- return fixed
-}
-
-// reflectFixSwitch rewrites *n (if n is an *ast.Stmt) corresponding
-// to a type switch.
-func reflectFixSwitch(n interface{}) bool {
- ptr, ok := n.(*ast.Stmt)
- if !ok {
- return false
- }
- n = *ptr
-
- ts, ok := n.(*ast.TypeSwitchStmt)
- if !ok {
- return false
- }
-
- // Are any switch cases referring to reflect types?
- // (That is, is this an old reflect type switch?)
- for _, cas := range ts.Body.List {
- for _, typ := range cas.(*ast.CaseClause).List {
- if reflectType(typ) != "" {
- goto haveReflect
- }
- }
- }
- return false
-
-haveReflect:
- // Now we know it's an old reflect type switch. Prepare the new version,
- // but don't replace or edit the original until we're sure of success.
-
- // Figure out the initializer statement, if any, and the receiver for the Kind call.
- var init ast.Stmt
- var rcvr ast.Expr
-
- init = ts.Init
- switch n := ts.Assign.(type) {
- default:
- warn(ts.Pos(), "unexpected form in type switch")
- return false
-
- case *ast.AssignStmt:
- as := n
- ta := as.Rhs[0].(*ast.TypeAssertExpr)
- x := isIdent(as.Lhs[0])
- z := isIdent(ta.X)
-
- if isBlank(x) || x != nil && z != nil && x.Name == z.Name && !assignsTo(x, ts.Body.List) {
- // Can drop the variable creation.
- rcvr = ta.X
- } else {
- // Need to use initialization statement.
- if init != nil {
- warn(ts.Pos(), "cannot rewrite reflect type switch with initializing statement")
- return false
- }
- init = &ast.AssignStmt{
- Lhs: []ast.Expr{as.Lhs[0]},
- TokPos: as.TokPos,
- Tok: token.DEFINE,
- Rhs: []ast.Expr{ta.X},
- }
- rcvr = as.Lhs[0]
- }
-
- case *ast.ExprStmt:
- rcvr = n.X.(*ast.TypeAssertExpr).X
- }
-
- // Prepare rewritten type switch (see large comment above for form).
- sw := &ast.SwitchStmt{
- Switch: ts.Switch,
- Init: init,
- Tag: &ast.CallExpr{
- Fun: &ast.SelectorExpr{
- X: rcvr,
- Sel: &ast.Ident{
- NamePos: rcvr.End(),
- Name: "Kind",
- Obj: nil,
- },
- },
- Lparen: rcvr.End(),
- Rparen: rcvr.End(),
- },
- Body: &ast.BlockStmt{
- Lbrace: ts.Body.Lbrace,
- List: nil, // to be filled in
- Rbrace: ts.Body.Rbrace,
- },
- }
-
- // Translate cases.
- for _, tcas := range ts.Body.List {
- tcas := tcas.(*ast.CaseClause)
- cas := &ast.CaseClause{
- Case: tcas.Case,
- Colon: tcas.Colon,
- Body: tcas.Body,
- }
- for _, t := range tcas.List {
- if isTopName(t, "nil") {
- cas.List = append(cas.List, newPkgDot(t.Pos(), "reflect", "Invalid"))
- continue
- }
-
- typ := reflectType(t)
- if typ == "" {
- warn(t.Pos(), "cannot rewrite reflect type switch case with non-reflect type %s", gofmt(t))
- cas.List = append(cas.List, t)
- continue
- }
-
- for _, k := range reflectKind[typ] {
- cas.List = append(cas.List, newPkgDot(t.Pos(), "reflect", k))
- }
- }
- sw.Body.List = append(sw.Body.List, cas)
- }
-
- // Everything worked. Rewrite AST.
- *ptr = sw
- return true
-}
-
-// Rewrite x, y = z.(T) into
-// x = z
-// y = x.Kind() == K
-// as described in the long comment above.
-//
-// If insert != nil, it can be called to insert a statement after *ptr in its block.
-// If insert == nil, insertion is not possible.
-// At most one call to insert is allowed.
-//
-// Scope gives the statements for which a declaration
-// in *ptr would be in scope.
-//
-// The result is true of the statement was rewritten.
-//
-func reflectFixTypecheck(ptr *ast.Stmt, insert func(ast.Stmt), scope []ast.Stmt) bool {
- st := *ptr
- as, ok := st.(*ast.AssignStmt)
- if !ok || len(as.Lhs) != 2 || len(as.Rhs) != 1 {
- return false
- }
-
- ta, ok := as.Rhs[0].(*ast.TypeAssertExpr)
- if !ok {
- return false
- }
- typ := reflectType(ta.Type)
- if typ == "" {
- return false
- }
-
- // Have x, y := z.(t).
- x := isIdent(as.Lhs[0])
- y := isIdent(as.Lhs[1])
- z := isIdent(ta.X)
-
- // First step is x := z, unless it's x := x and the resulting x is never reassigned.
- // rcvr is the x in x.Kind().
- var rcvr ast.Expr
- if isBlank(x) ||
- as.Tok == token.DEFINE && x != nil && z != nil && x.Name == z.Name && !assignsTo(x, scope) {
- // Can drop the statement.
- // If we need to insert a statement later, now we have a slot.
- *ptr = &ast.EmptyStmt{}
- insert = func(x ast.Stmt) { *ptr = x }
- rcvr = ta.X
- } else {
- *ptr = &ast.AssignStmt{
- Lhs: []ast.Expr{as.Lhs[0]},
- TokPos: as.TokPos,
- Tok: as.Tok,
- Rhs: []ast.Expr{ta.X},
- }
- rcvr = as.Lhs[0]
- }
-
- // Prepare x.Kind() == T expression appropriate to t.
- // If x is not a simple identifier, warn that we might be
- // reevaluating x.
- if x == nil {
- warn(as.Pos(), "rewrite reevaluates expr with possible side effects: %s", gofmt(as.Lhs[0]))
- }
- yExpr, yNotExpr := reflectKindEq(rcvr, reflectKind[typ])
-
- // Second step is y := x.Kind() == T, unless it's only used once
- // or we have no way to insert that statement.
- var yStmt *ast.AssignStmt
- if as.Tok == token.DEFINE && countUses(y, scope) <= 1 || insert == nil {
- // Can drop the statement and use the expression directly.
- rewriteUses(y,
- func(token.Pos) ast.Expr { return yExpr },
- func(token.Pos) ast.Expr { return yNotExpr },
- scope)
- } else {
- yStmt = &ast.AssignStmt{
- Lhs: []ast.Expr{as.Lhs[1]},
- TokPos: as.End(),
- Tok: as.Tok,
- Rhs: []ast.Expr{yExpr},
- }
- insert(yStmt)
- }
- return true
-}
-
-// reflectKindEq returns the expression z.Kind() == kinds[0] || z.Kind() == kinds[1] || ...
-// and its negation.
-// The qualifier "reflect." is inserted before each kinds[i] expression.
-func reflectKindEq(z ast.Expr, kinds []string) (ast.Expr, ast.Expr) {
- n := len(kinds)
- if n == 1 {
- y := &ast.BinaryExpr{
- X: &ast.CallExpr{
- Fun: &ast.SelectorExpr{
- X: z,
- Sel: ast.NewIdent("Kind"),
- },
- },
- Op: token.EQL,
- Y: newPkgDot(token.NoPos, "reflect", kinds[0]),
- }
- ynot := &ast.BinaryExpr{
- X: &ast.CallExpr{
- Fun: &ast.SelectorExpr{
- X: z,
- Sel: ast.NewIdent("Kind"),
- },
- },
- Op: token.NEQ,
- Y: newPkgDot(token.NoPos, "reflect", kinds[0]),
- }
- return y, ynot
- }
-
- x, xnot := reflectKindEq(z, kinds[0:n-1])
- y, ynot := reflectKindEq(z, kinds[n-1:])
-
- or := &ast.BinaryExpr{
- X: x,
- Op: token.LOR,
- Y: y,
- }
- andnot := &ast.BinaryExpr{
- X: xnot,
- Op: token.LAND,
- Y: ynot,
- }
- return or, andnot
-}
-
-// if x represents a known old reflect type/value like *reflect.PtrType or reflect.ArrayOrSliceValue,
-// reflectType returns the string form of that type.
-func reflectType(x ast.Expr) string {
- ptr, ok := x.(*ast.StarExpr)
- if ok {
- x = ptr.X
- }
-
- sel, ok := x.(*ast.SelectorExpr)
- if !ok || !isName(sel.X, "reflect") {
- return ""
- }
-
- var s = "reflect."
- if ptr != nil {
- s = "*reflect."
- }
- s += sel.Sel.Name
-
- if reflectKind[s] != nil {
- return s
- }
- return ""
-}
-
-// reflectWarnTypecheckStmt warns about statements
-// of the form x, y = z.(T) for any old reflect type T.
-// The last pass should have gotten them all, and if it didn't,
-// the next pass is going to turn them into x, y = z.
-func reflectWarnTypecheckStmt(n interface{}) {
- as, ok := n.(*ast.AssignStmt)
- if !ok || len(as.Lhs) != 2 || len(as.Rhs) != 1 {
- return
- }
- ta, ok := as.Rhs[0].(*ast.TypeAssertExpr)
- if !ok || reflectType(ta.Type) == "" {
- return
- }
- warn(n.(ast.Node).Pos(), "unfixed reflect type check")
-}
-
-// reflectFixAssert rewrites x.(T) to x for any old reflect type T.
-func reflectFixAssert(n interface{}) bool {
- ptr, ok := n.(*ast.Expr)
- if ok {
- ta, ok := (*ptr).(*ast.TypeAssertExpr)
- if ok && reflectType(ta.Type) != "" {
- *ptr = ta.X
- return true
- }
- }
- return false
-}
-
-// Tables describing the transformations.
-
-// Description of old reflect API for partial type checking.
-// We pretend the Elem method is on Type and Value instead
-// of enumerating all the types it is actually on.
-// Also, we pretend that ArrayType etc embeds Type for the
-// purposes of describing the API. (In fact they embed commonType,
-// which implements Type.)
-var reflectTypeConfig = &TypeConfig{
- Type: map[string]*Type{
- "reflect.ArrayOrSliceType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.ArrayOrSliceValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.ArrayType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.ArrayValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.BoolType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.BoolValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.ChanType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.ChanValue": &Type{
- Method: map[string]string{
- "Recv": "func() (reflect.Value, bool)",
- "TryRecv": "func() (reflect.Value, bool)",
- },
- Embed: []string{"reflect.Value"},
- },
- "reflect.ComplexType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.ComplexValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.FloatType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.FloatValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.FuncType": &Type{
- Method: map[string]string{
- "In": "func(int) reflect.Type",
- "Out": "func(int) reflect.Type",
- },
- Embed: []string{"reflect.Type"},
- },
- "reflect.FuncValue": &Type{
- Method: map[string]string{
- "Call": "func([]reflect.Value) []reflect.Value",
- },
- },
- "reflect.IntType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.IntValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.InterfaceType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.InterfaceValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.MapType": &Type{
- Method: map[string]string{
- "Key": "func() reflect.Type",
- },
- Embed: []string{"reflect.Type"},
- },
- "reflect.MapValue": &Type{
- Method: map[string]string{
- "Keys": "func() []reflect.Value",
- },
- Embed: []string{"reflect.Value"},
- },
- "reflect.Method": &Type{
- Field: map[string]string{
- "Type": "*reflect.FuncType",
- "Func": "*reflect.FuncValue",
- },
- },
- "reflect.PtrType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.PtrValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.SliceType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.SliceValue": &Type{
- Method: map[string]string{
- "Slice": "func(int, int) *reflect.SliceValue",
- },
- Embed: []string{"reflect.Value"},
- },
- "reflect.StringType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.StringValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.StructField": &Type{
- Field: map[string]string{
- "Type": "reflect.Type",
- },
- },
- "reflect.StructType": &Type{
- Method: map[string]string{
- "Field": "func() reflect.StructField",
- "FieldByIndex": "func() reflect.StructField",
- "FieldByName": "func() reflect.StructField,bool",
- "FieldByNameFunc": "func() reflect.StructField,bool",
- },
- Embed: []string{"reflect.Type"},
- },
- "reflect.StructValue": &Type{
- Method: map[string]string{
- "Field": "func() reflect.Value",
- "FieldByIndex": "func() reflect.Value",
- "FieldByName": "func() reflect.Value",
- "FieldByNameFunc": "func() reflect.Value",
- },
- Embed: []string{"reflect.Value"},
- },
- "reflect.Type": &Type{
- Method: map[string]string{
- "Elem": "func() reflect.Type",
- "Method": "func() reflect.Method",
- },
- },
- "reflect.UintType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.UintValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.UnsafePointerType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.UnsafePointerValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.Value": &Type{
- Method: map[string]string{
- "Addr": "func() *reflect.PtrValue",
- "Elem": "func() reflect.Value",
- "Method": "func() *reflect.FuncValue",
- "SetValue": "func(reflect.Value)",
- },
- },
- },
- Func: map[string]string{
- "reflect.Append": "*reflect.SliceValue",
- "reflect.AppendSlice": "*reflect.SliceValue",
- "reflect.Indirect": "reflect.Value",
- "reflect.MakeSlice": "*reflect.SliceValue",
- "reflect.MakeChan": "*reflect.ChanValue",
- "reflect.MakeMap": "*reflect.MapValue",
- "reflect.MakeZero": "reflect.Value",
- "reflect.NewValue": "reflect.Value",
- "reflect.PtrTo": "*reflect.PtrType",
- "reflect.Typeof": "reflect.Type",
- },
-}
-
-var reflectRewriteMethod = map[string]map[string]string{
- // The type API didn't change much.
- "*reflect.ChanType": {"Dir": "ChanDir"},
- "*reflect.FuncType": {"DotDotDot": "IsVariadic"},
-
- // The value API has longer names to disambiguate
- // methods with different signatures.
- "reflect.ArrayOrSliceValue": { // interface, not pointer
- "Elem": "Index",
- },
- "*reflect.ArrayValue": {
- "Elem": "Index",
- },
- "*reflect.BoolValue": {
- "Get": "Bool",
- "Set": "SetBool",
- },
- "*reflect.ChanValue": {
- "Get": "Pointer",
- },
- "*reflect.ComplexValue": {
- "Get": "Complex",
- "Set": "SetComplex",
- "Overflow": "OverflowComplex",
- },
- "*reflect.FloatValue": {
- "Get": "Float",
- "Set": "SetFloat",
- "Overflow": "OverflowFloat",
- },
- "*reflect.FuncValue": {
- "Get": "Pointer",
- },
- "*reflect.IntValue": {
- "Get": "Int",
- "Set": "SetInt",
- "Overflow": "OverflowInt",
- },
- "*reflect.InterfaceValue": {
- "Get": "InterfaceData",
- },
- "*reflect.MapValue": {
- "Elem": "MapIndex",
- "Get": "Pointer",
- "Keys": "MapKeys",
- "SetElem": "SetMapIndex",
- },
- "*reflect.PtrValue": {
- "Get": "Pointer",
- },
- "*reflect.SliceValue": {
- "Elem": "Index",
- "Get": "Pointer",
- },
- "*reflect.StringValue": {
- "Get": "String",
- "Set": "SetString",
- },
- "*reflect.UintValue": {
- "Get": "Uint",
- "Set": "SetUint",
- "Overflow": "OverflowUint",
- },
- "*reflect.UnsafePointerValue": {
- "Get": "Pointer",
- "Set": "SetPointer",
- },
-}
-
-var reflectKind = map[string][]string{
- "reflect.ArrayOrSliceType": {"Array", "Slice"}, // interface, not pointer
- "*reflect.ArrayType": {"Array"},
- "*reflect.BoolType": {"Bool"},
- "*reflect.ChanType": {"Chan"},
- "*reflect.ComplexType": {"Complex64", "Complex128"},
- "*reflect.FloatType": {"Float32", "Float64"},
- "*reflect.FuncType": {"Func"},
- "*reflect.IntType": {"Int", "Int8", "Int16", "Int32", "Int64"},
- "*reflect.InterfaceType": {"Interface"},
- "*reflect.MapType": {"Map"},
- "*reflect.PtrType": {"Ptr"},
- "*reflect.SliceType": {"Slice"},
- "*reflect.StringType": {"String"},
- "*reflect.StructType": {"Struct"},
- "*reflect.UintType": {"Uint", "Uint8", "Uint16", "Uint32", "Uint64", "Uintptr"},
- "*reflect.UnsafePointerType": {"UnsafePointer"},
-
- "reflect.ArrayOrSliceValue": {"Array", "Slice"}, // interface, not pointer
- "*reflect.ArrayValue": {"Array"},
- "*reflect.BoolValue": {"Bool"},
- "*reflect.ChanValue": {"Chan"},
- "*reflect.ComplexValue": {"Complex64", "Complex128"},
- "*reflect.FloatValue": {"Float32", "Float64"},
- "*reflect.FuncValue": {"Func"},
- "*reflect.IntValue": {"Int", "Int8", "Int16", "Int32", "Int64"},
- "*reflect.InterfaceValue": {"Interface"},
- "*reflect.MapValue": {"Map"},
- "*reflect.PtrValue": {"Ptr"},
- "*reflect.SliceValue": {"Slice"},
- "*reflect.StringValue": {"String"},
- "*reflect.StructValue": {"Struct"},
- "*reflect.UintValue": {"Uint", "Uint8", "Uint16", "Uint32", "Uint64", "Uintptr"},
- "*reflect.UnsafePointerValue": {"UnsafePointer"},
-}
-
-var isReflectValue = map[string]bool{
- "reflect.ArrayOrSliceValue": true, // interface, not pointer
- "*reflect.ArrayValue": true,
- "*reflect.BoolValue": true,
- "*reflect.ChanValue": true,
- "*reflect.ComplexValue": true,
- "*reflect.FloatValue": true,
- "*reflect.FuncValue": true,
- "*reflect.IntValue": true,
- "*reflect.InterfaceValue": true,
- "*reflect.MapValue": true,
- "*reflect.PtrValue": true,
- "*reflect.SliceValue": true,
- "*reflect.StringValue": true,
- "*reflect.StructValue": true,
- "*reflect.UintValue": true,
- "*reflect.UnsafePointerValue": true,
- "reflect.Value": true, // interface, not pointer
-}
diff --git a/src/cmd/gofix/reflect_test.go b/src/cmd/gofix/reflect_test.go
deleted file mode 100644
index 00edf30e9..000000000
--- a/src/cmd/gofix/reflect_test.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package main
-
-import (
- "io/ioutil"
- "log"
- "path/filepath"
-)
-
-func init() {
- addTestCases(reflectTests())
-}
-
-func reflectTests() []testCase {
- var tests []testCase
-
- names, _ := filepath.Glob("testdata/reflect.*.in")
- for _, in := range names {
- out := in[:len(in)-len(".in")] + ".out"
- inb, err := ioutil.ReadFile(in)
- if err != nil {
- log.Fatal(err)
- }
- outb, err := ioutil.ReadFile(out)
- if err != nil {
- log.Fatal(err)
- }
- tests = append(tests, testCase{Name: in, In: string(inb), Out: string(outb)})
- }
-
- return tests
-}
diff --git a/src/cmd/gofix/signal.go b/src/cmd/gofix/signal.go
deleted file mode 100644
index 53c338851..000000000
--- a/src/cmd/gofix/signal.go
+++ /dev/null
@@ -1,49 +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 main
-
-import (
- "go/ast"
- "strings"
-)
-
-func init() {
- register(fix{
- "signal",
- signal,
- `Adapt code to types moved from os/signal to signal.
-
-http://codereview.appspot.com/4437091
-`,
- })
-}
-
-func signal(f *ast.File) (fixed bool) {
- if !imports(f, "os/signal") {
- return
- }
-
- walk(f, func(n interface{}) {
- s, ok := n.(*ast.SelectorExpr)
-
- if !ok || !isTopName(s.X, "signal") {
- return
- }
-
- sel := s.Sel.String()
- if sel == "Signal" || sel == "UnixSignal" || strings.HasPrefix(sel, "SIG") {
- s.X = &ast.Ident{Name: "os"}
- fixed = true
- }
- })
-
- if fixed {
- addImport(f, "os")
- if !usesImport(f, "os/signal") {
- deleteImport(f, "os/signal")
- }
- }
- return
-}
diff --git a/src/cmd/gofix/signal_test.go b/src/cmd/gofix/signal_test.go
deleted file mode 100644
index 2500e9cee..000000000
--- a/src/cmd/gofix/signal_test.go
+++ /dev/null
@@ -1,96 +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 main
-
-func init() {
- addTestCases(signalTests)
-}
-
-var signalTests = []testCase{
- {
- Name: "signal.0",
- In: `package main
-
-import (
- _ "a"
- "os/signal"
- _ "z"
-)
-
-type T1 signal.UnixSignal
-type T2 signal.Signal
-
-func f() {
- _ = signal.SIGHUP
- _ = signal.Incoming
-}
-`,
- Out: `package main
-
-import (
- _ "a"
- "os"
- "os/signal"
- _ "z"
-)
-
-type T1 os.UnixSignal
-type T2 os.Signal
-
-func f() {
- _ = os.SIGHUP
- _ = signal.Incoming
-}
-`,
- },
- {
- Name: "signal.1",
- In: `package main
-
-import (
- "os"
- "os/signal"
-)
-
-func f() {
- var _ os.Error
- _ = signal.SIGHUP
-}
-`,
- Out: `package main
-
-import "os"
-
-
-func f() {
- var _ os.Error
- _ = os.SIGHUP
-}
-`,
- },
- {
- Name: "signal.2",
- In: `package main
-
-import "os"
-import "os/signal"
-
-func f() {
- var _ os.Error
- _ = signal.SIGHUP
-}
-`,
- Out: `package main
-
-import "os"
-
-
-func f() {
- var _ os.Error
- _ = os.SIGHUP
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/sorthelpers.go b/src/cmd/gofix/sorthelpers.go
deleted file mode 100644
index 4d0bee6e7..000000000
--- a/src/cmd/gofix/sorthelpers.go
+++ /dev/null
@@ -1,47 +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 main
-
-import (
- "go/ast"
-)
-
-func init() {
- register(fix{
- "sorthelpers",
- sorthelpers,
- `Adapt code from sort.Sort[Ints|Float64s|Strings] to sort.[Ints|Float64s|Strings].
-`,
- })
-}
-
-
-func sorthelpers(f *ast.File) (fixed bool) {
- if !imports(f, "sort") {
- return
- }
-
- walk(f, func(n interface{}) {
- s, ok := n.(*ast.SelectorExpr)
- if !ok || !isTopName(s.X, "sort") {
- return
- }
-
- switch s.Sel.String() {
- case "SortFloat64s":
- s.Sel.Name = "Float64s"
- case "SortInts":
- s.Sel.Name = "Ints"
- case "SortStrings":
- s.Sel.Name = "Strings"
- default:
- return
- }
-
- fixed = true
- })
-
- return
-}
diff --git a/src/cmd/gofix/sorthelpers_test.go b/src/cmd/gofix/sorthelpers_test.go
deleted file mode 100644
index 6c37858fd..000000000
--- a/src/cmd/gofix/sorthelpers_test.go
+++ /dev/null
@@ -1,45 +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 main
-
-func init() {
- addTestCases(sorthelpersTests)
-}
-
-var sorthelpersTests = []testCase{
- {
- Name: "sortslice.0",
- In: `package main
-
-import (
- "sort"
-)
-
-func main() {
- var s []string
- sort.SortStrings(s)
- var i []ints
- sort.SortInts(i)
- var f []float64
- sort.SortFloat64s(f)
-}
-`,
- Out: `package main
-
-import (
- "sort"
-)
-
-func main() {
- var s []string
- sort.Strings(s)
- var i []ints
- sort.Ints(i)
- var f []float64
- sort.Float64s(f)
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/sortslice.go b/src/cmd/gofix/sortslice.go
deleted file mode 100644
index b9c108b5a..000000000
--- a/src/cmd/gofix/sortslice.go
+++ /dev/null
@@ -1,50 +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 main
-
-import (
- "go/ast"
-)
-
-func init() {
- register(fix{
- "sortslice",
- sortslice,
- `Adapt code from sort.[Float64|Int|String]Array to sort.[Float64|Int|String]Slice.
-
-http://codereview.appspot.com/4602054
-http://codereview.appspot.com/4639041
-`,
- })
-}
-
-
-func sortslice(f *ast.File) (fixed bool) {
- if !imports(f, "sort") {
- return
- }
-
- walk(f, func(n interface{}) {
- s, ok := n.(*ast.SelectorExpr)
- if !ok || !isTopName(s.X, "sort") {
- return
- }
-
- switch s.Sel.String() {
- case "Float64Array":
- s.Sel.Name = "Float64Slice"
- case "IntArray":
- s.Sel.Name = "IntSlice"
- case "StringArray":
- s.Sel.Name = "StringSlice"
- default:
- return
- }
-
- fixed = true
- })
-
- return
-}
diff --git a/src/cmd/gofix/sortslice_test.go b/src/cmd/gofix/sortslice_test.go
deleted file mode 100644
index 404feb26f..000000000
--- a/src/cmd/gofix/sortslice_test.go
+++ /dev/null
@@ -1,35 +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 main
-
-func init() {
- addTestCases(sortsliceTests)
-}
-
-var sortsliceTests = []testCase{
- {
- Name: "sortslice.0",
- In: `package main
-
-import (
- "sort"
-)
-
-var _ = sort.Float64Array
-var _ = sort.IntArray
-var _ = sort.StringArray
-`,
- Out: `package main
-
-import (
- "sort"
-)
-
-var _ = sort.Float64Slice
-var _ = sort.IntSlice
-var _ = sort.StringSlice
-`,
- },
-}
diff --git a/src/cmd/gofix/stringssplit.go b/src/cmd/gofix/stringssplit.go
deleted file mode 100644
index 4a1fe93d3..000000000
--- a/src/cmd/gofix/stringssplit.go
+++ /dev/null
@@ -1,71 +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 main
-
-import (
- "go/ast"
- "go/token"
-)
-
-var stringssplitFix = fix{
- "stringssplit",
- stringssplit,
- `Restore strings.Split to its original meaning and add strings.SplitN. Bytes too.
-
-http://codereview.appspot.com/4661051
-`,
-}
-
-func init() {
- register(stringssplitFix)
-}
-
-func stringssplit(f *ast.File) bool {
- if !imports(f, "bytes") && !imports(f, "strings") {
- return false
- }
-
- fixed := false
- walk(f, func(n interface{}) {
- call, ok := n.(*ast.CallExpr)
- // func Split(s, sep string, n int) []string
- // func SplitAfter(s, sep string, n int) []string
- if !ok || len(call.Args) != 3 {
- return
- }
- // Is this our function?
- switch {
- case isPkgDot(call.Fun, "bytes", "Split"):
- case isPkgDot(call.Fun, "bytes", "SplitAfter"):
- case isPkgDot(call.Fun, "strings", "Split"):
- case isPkgDot(call.Fun, "strings", "SplitAfter"):
- default:
- return
- }
-
- sel := call.Fun.(*ast.SelectorExpr)
- args := call.Args
- fixed = true // We're committed.
-
- // Is the last argument -1? If so, drop the arg.
- // (Actually we just look for a negative integer literal.)
- // Otherwise, Split->SplitN and keep the arg.
- final := args[2]
- if unary, ok := final.(*ast.UnaryExpr); ok && unary.Op == token.SUB {
- if lit, ok := unary.X.(*ast.BasicLit); ok {
- // Is it an integer? If so, it's a negative integer and that's what we're after.
- if lit.Kind == token.INT {
- // drop the last arg.
- call.Args = args[0:2]
- return
- }
- }
- }
-
- // If not, rename and keep the argument list.
- sel.Sel.Name += "N"
- })
- return fixed
-}
diff --git a/src/cmd/gofix/stringssplit_test.go b/src/cmd/gofix/stringssplit_test.go
deleted file mode 100644
index b925722af..000000000
--- a/src/cmd/gofix/stringssplit_test.go
+++ /dev/null
@@ -1,51 +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 main
-
-func init() {
- addTestCases(stringssplitTests)
-}
-
-var stringssplitTests = []testCase{
- {
- Name: "stringssplit.0",
- In: `package main
-
-import (
- "bytes"
- "strings"
-)
-
-func f() {
- bytes.Split(a, b, c)
- bytes.Split(a, b, -1)
- bytes.SplitAfter(a, b, c)
- bytes.SplitAfter(a, b, -1)
- strings.Split(a, b, c)
- strings.Split(a, b, -1)
- strings.SplitAfter(a, b, c)
- strings.SplitAfter(a, b, -1)
-}
-`,
- Out: `package main
-
-import (
- "bytes"
- "strings"
-)
-
-func f() {
- bytes.SplitN(a, b, c)
- bytes.Split(a, b)
- bytes.SplitAfterN(a, b, c)
- bytes.SplitAfter(a, b)
- strings.SplitN(a, b, c)
- strings.Split(a, b)
- strings.SplitAfterN(a, b, c)
- strings.SplitAfter(a, b)
-}
-`,
- },
-}
diff --git a/src/cmd/gofix/testdata/reflect.asn1.go.in b/src/cmd/gofix/testdata/reflect.asn1.go.in
deleted file mode 100644
index c5314517b..000000000
--- a/src/cmd/gofix/testdata/reflect.asn1.go.in
+++ /dev/null
@@ -1,815 +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.
-
-// The asn1 package implements parsing of DER-encoded ASN.1 data structures,
-// as defined in ITU-T Rec X.690.
-//
-// See also ``A Layman's Guide to a Subset of ASN.1, BER, and DER,''
-// http://luca.ntop.org/Teaching/Appunti/asn1.html.
-package asn1
-
-// ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc
-// are different encoding formats for those objects. Here, we'll be dealing
-// with DER, the Distinguished Encoding Rules. DER is used in X.509 because
-// it's fast to parse and, unlike BER, has a unique encoding for every object.
-// When calculating hashes over objects, it's important that the resulting
-// bytes be the same at both ends and DER removes this margin of error.
-//
-// ASN.1 is very complex and this package doesn't attempt to implement
-// everything by any means.
-
-import (
- "fmt"
- "os"
- "reflect"
- "time"
-)
-
-// A StructuralError suggests that the ASN.1 data is valid, but the Go type
-// which is receiving it doesn't match.
-type StructuralError struct {
- Msg string
-}
-
-func (e StructuralError) String() string { return "ASN.1 structure error: " + e.Msg }
-
-// A SyntaxError suggests that the ASN.1 data is invalid.
-type SyntaxError struct {
- Msg string
-}
-
-func (e SyntaxError) String() string { return "ASN.1 syntax error: " + e.Msg }
-
-// We start by dealing with each of the primitive types in turn.
-
-// BOOLEAN
-
-func parseBool(bytes []byte) (ret bool, err os.Error) {
- if len(bytes) != 1 {
- err = SyntaxError{"invalid boolean"}
- return
- }
-
- return bytes[0] != 0, nil
-}
-
-// INTEGER
-
-// parseInt64 treats the given bytes as a big-endian, signed integer and
-// returns the result.
-func parseInt64(bytes []byte) (ret int64, err os.Error) {
- if len(bytes) > 8 {
- // We'll overflow an int64 in this case.
- err = StructuralError{"integer too large"}
- return
- }
- for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
- ret <<= 8
- ret |= int64(bytes[bytesRead])
- }
-
- // Shift up and down in order to sign extend the result.
- ret <<= 64 - uint8(len(bytes))*8
- ret >>= 64 - uint8(len(bytes))*8
- return
-}
-
-// parseInt treats the given bytes as a big-endian, signed integer and returns
-// the result.
-func parseInt(bytes []byte) (int, os.Error) {
- ret64, err := parseInt64(bytes)
- if err != nil {
- return 0, err
- }
- if ret64 != int64(int(ret64)) {
- return 0, StructuralError{"integer too large"}
- }
- return int(ret64), nil
-}
-
-// BIT STRING
-
-// BitString is the structure to use when you want an ASN.1 BIT STRING type. A
-// bit string is padded up to the nearest byte in memory and the number of
-// valid bits is recorded. Padding bits will be zero.
-type BitString struct {
- Bytes []byte // bits packed into bytes.
- BitLength int // length in bits.
-}
-
-// At returns the bit at the given index. If the index is out of range it
-// returns false.
-func (b BitString) At(i int) int {
- if i < 0 || i >= b.BitLength {
- return 0
- }
- x := i / 8
- y := 7 - uint(i%8)
- return int(b.Bytes[x]>>y) & 1
-}
-
-// RightAlign returns a slice where the padding bits are at the beginning. The
-// slice may share memory with the BitString.
-func (b BitString) RightAlign() []byte {
- shift := uint(8 - (b.BitLength % 8))
- if shift == 8 || len(b.Bytes) == 0 {
- return b.Bytes
- }
-
- a := make([]byte, len(b.Bytes))
- a[0] = b.Bytes[0] >> shift
- for i := 1; i < len(b.Bytes); i++ {
- a[i] = b.Bytes[i-1] << (8 - shift)
- a[i] |= b.Bytes[i] >> shift
- }
-
- return a
-}
-
-// parseBitString parses an ASN.1 bit string from the given byte array and returns it.
-func parseBitString(bytes []byte) (ret BitString, err os.Error) {
- if len(bytes) == 0 {
- err = SyntaxError{"zero length BIT STRING"}
- return
- }
- paddingBits := int(bytes[0])
- if paddingBits > 7 ||
- len(bytes) == 1 && paddingBits > 0 ||
- bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {
- err = SyntaxError{"invalid padding bits in BIT STRING"}
- return
- }
- ret.BitLength = (len(bytes)-1)*8 - paddingBits
- ret.Bytes = bytes[1:]
- return
-}
-
-// OBJECT IDENTIFIER
-
-// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
-type ObjectIdentifier []int
-
-// Equal returns true iff oi and other represent the same identifier.
-func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
- if len(oi) != len(other) {
- return false
- }
- for i := 0; i < len(oi); i++ {
- if oi[i] != other[i] {
- return false
- }
- }
-
- return true
-}
-
-// parseObjectIdentifier parses an OBJECT IDENTIFER from the given bytes and
-// returns it. An object identifer is a sequence of variable length integers
-// that are assigned in a hierarachy.
-func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
- if len(bytes) == 0 {
- err = SyntaxError{"zero length OBJECT IDENTIFIER"}
- return
- }
-
- // In the worst case, we get two elements from the first byte (which is
- // encoded differently) and then every varint is a single byte long.
- s = make([]int, len(bytes)+1)
-
- // The first byte is 40*value1 + value2:
- s[0] = int(bytes[0]) / 40
- s[1] = int(bytes[0]) % 40
- i := 2
- for offset := 1; offset < len(bytes); i++ {
- var v int
- v, offset, err = parseBase128Int(bytes, offset)
- if err != nil {
- return
- }
- s[i] = v
- }
- s = s[0:i]
- return
-}
-
-// ENUMERATED
-
-// An Enumerated is represented as a plain int.
-type Enumerated int
-
-
-// FLAG
-
-// A Flag accepts any data and is set to true if present.
-type Flag bool
-
-// parseBase128Int parses a base-128 encoded int from the given offset in the
-// given byte array. It returns the value and the new offset.
-func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) {
- offset = initOffset
- for shifted := 0; offset < len(bytes); shifted++ {
- if shifted > 4 {
- err = StructuralError{"base 128 integer too large"}
- return
- }
- ret <<= 7
- b := bytes[offset]
- ret |= int(b & 0x7f)
- offset++
- if b&0x80 == 0 {
- return
- }
- }
- err = SyntaxError{"truncated base 128 integer"}
- return
-}
-
-// UTCTime
-
-func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
- s := string(bytes)
- ret, err = time.Parse("0601021504Z0700", s)
- if err == nil {
- return
- }
- ret, err = time.Parse("060102150405Z0700", s)
- return
-}
-
-// parseGeneralizedTime parses the GeneralizedTime from the given byte array
-// and returns the resulting time.
-func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
- return time.Parse("20060102150405Z0700", string(bytes))
-}
-
-// PrintableString
-
-// parsePrintableString parses a ASN.1 PrintableString from the given byte
-// array and returns it.
-func parsePrintableString(bytes []byte) (ret string, err os.Error) {
- for _, b := range bytes {
- if !isPrintable(b) {
- err = SyntaxError{"PrintableString contains invalid character"}
- return
- }
- }
- ret = string(bytes)
- return
-}
-
-// isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
-func isPrintable(b byte) bool {
- return 'a' <= b && b <= 'z' ||
- 'A' <= b && b <= 'Z' ||
- '0' <= b && b <= '9' ||
- '\'' <= b && b <= ')' ||
- '+' <= b && b <= '/' ||
- b == ' ' ||
- b == ':' ||
- b == '=' ||
- b == '?' ||
- // This is techincally not allowed in a PrintableString.
- // However, x509 certificates with wildcard strings don't
- // always use the correct string type so we permit it.
- b == '*'
-}
-
-// IA5String
-
-// parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
-// byte array and returns it.
-func parseIA5String(bytes []byte) (ret string, err os.Error) {
- for _, b := range bytes {
- if b >= 0x80 {
- err = SyntaxError{"IA5String contains invalid character"}
- return
- }
- }
- ret = string(bytes)
- return
-}
-
-// T61String
-
-// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
-// byte array and returns it.
-func parseT61String(bytes []byte) (ret string, err os.Error) {
- return string(bytes), nil
-}
-
-// A RawValue represents an undecoded ASN.1 object.
-type RawValue struct {
- Class, Tag int
- IsCompound bool
- Bytes []byte
- FullBytes []byte // includes the tag and length
-}
-
-// RawContent is used to signal that the undecoded, DER data needs to be
-// preserved for a struct. To use it, the first field of the struct must have
-// this type. It's an error for any of the other fields to have this type.
-type RawContent []byte
-
-// Tagging
-
-// parseTagAndLength parses an ASN.1 tag and length pair from the given offset
-// into a byte array. It returns the parsed data and the new offset. SET and
-// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
-// don't distinguish between ordered and unordered objects in this code.
-func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err os.Error) {
- offset = initOffset
- b := bytes[offset]
- offset++
- ret.class = int(b >> 6)
- ret.isCompound = b&0x20 == 0x20
- ret.tag = int(b & 0x1f)
-
- // If the bottom five bits are set, then the tag number is actually base 128
- // encoded afterwards
- if ret.tag == 0x1f {
- ret.tag, offset, err = parseBase128Int(bytes, offset)
- if err != nil {
- return
- }
- }
- if offset >= len(bytes) {
- err = SyntaxError{"truncated tag or length"}
- return
- }
- b = bytes[offset]
- offset++
- if b&0x80 == 0 {
- // The length is encoded in the bottom 7 bits.
- ret.length = int(b & 0x7f)
- } else {
- // Bottom 7 bits give the number of length bytes to follow.
- numBytes := int(b & 0x7f)
- // We risk overflowing a signed 32-bit number if we accept more than 3 bytes.
- if numBytes > 3 {
- err = StructuralError{"length too large"}
- return
- }
- if numBytes == 0 {
- err = SyntaxError{"indefinite length found (not DER)"}
- return
- }
- ret.length = 0
- for i := 0; i < numBytes; i++ {
- if offset >= len(bytes) {
- err = SyntaxError{"truncated tag or length"}
- return
- }
- b = bytes[offset]
- offset++
- ret.length <<= 8
- ret.length |= int(b)
- }
- }
-
- return
-}
-
-// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
-// a number of ASN.1 values from the given byte array and returns them as a
-// slice of Go values of the given type.
-func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflect.Type) (ret *reflect.SliceValue, err os.Error) {
- expectedTag, compoundType, ok := getUniversalType(elemType)
- if !ok {
- err = StructuralError{"unknown Go type for slice"}
- return
- }
-
- // First we iterate over the input and count the number of elements,
- // checking that the types are correct in each case.
- numElements := 0
- for offset := 0; offset < len(bytes); {
- var t tagAndLength
- t, offset, err = parseTagAndLength(bytes, offset)
- if err != nil {
- return
- }
- // We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
- // that a sequence of them can be parsed into a []string.
- if t.tag == tagGeneralString {
- t.tag = tagPrintableString
- }
- if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
- err = StructuralError{"sequence tag mismatch"}
- return
- }
- if invalidLength(offset, t.length, len(bytes)) {
- err = SyntaxError{"truncated sequence"}
- return
- }
- offset += t.length
- numElements++
- }
- ret = reflect.MakeSlice(sliceType, numElements, numElements)
- params := fieldParameters{}
- offset := 0
- for i := 0; i < numElements; i++ {
- offset, err = parseField(ret.Elem(i), bytes, offset, params)
- if err != nil {
- return
- }
- }
- return
-}
-
-var (
- bitStringType = reflect.Typeof(BitString{})
- objectIdentifierType = reflect.Typeof(ObjectIdentifier{})
- enumeratedType = reflect.Typeof(Enumerated(0))
- flagType = reflect.Typeof(Flag(false))
- timeType = reflect.Typeof(&time.Time{})
- rawValueType = reflect.Typeof(RawValue{})
- rawContentsType = reflect.Typeof(RawContent(nil))
-)
-
-// invalidLength returns true iff offset + length > sliceLength, or if the
-// addition would overflow.
-func invalidLength(offset, length, sliceLength int) bool {
- return offset+length < offset || offset+length > sliceLength
-}
-
-// parseField is the main parsing function. Given a byte array and an offset
-// into the array, it will try to parse a suitable ASN.1 value out and store it
-// in the given Value.
-func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err os.Error) {
- offset = initOffset
- fieldType := v.Type()
-
- // If we have run out of data, it may be that there are optional elements at the end.
- if offset == len(bytes) {
- if !setDefaultValue(v, params) {
- err = SyntaxError{"sequence truncated"}
- }
- return
- }
-
- // Deal with raw values.
- if fieldType == rawValueType {
- var t tagAndLength
- t, offset, err = parseTagAndLength(bytes, offset)
- if err != nil {
- return
- }
- if invalidLength(offset, t.length, len(bytes)) {
- err = SyntaxError{"data truncated"}
- return
- }
- result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length], bytes[initOffset : offset+t.length]}
- offset += t.length
- v.(*reflect.StructValue).Set(reflect.NewValue(result).(*reflect.StructValue))
- return
- }
-
- // Deal with the ANY type.
- if ifaceType, ok := fieldType.(*reflect.InterfaceType); ok && ifaceType.NumMethod() == 0 {
- ifaceValue := v.(*reflect.InterfaceValue)
- var t tagAndLength
- t, offset, err = parseTagAndLength(bytes, offset)
- if err != nil {
- return
- }
- if invalidLength(offset, t.length, len(bytes)) {
- err = SyntaxError{"data truncated"}
- return
- }
- var result interface{}
- if !t.isCompound && t.class == classUniversal {
- innerBytes := bytes[offset : offset+t.length]
- switch t.tag {
- case tagPrintableString:
- result, err = parsePrintableString(innerBytes)
- case tagIA5String:
- result, err = parseIA5String(innerBytes)
- case tagT61String:
- result, err = parseT61String(innerBytes)
- case tagInteger:
- result, err = parseInt64(innerBytes)
- case tagBitString:
- result, err = parseBitString(innerBytes)
- case tagOID:
- result, err = parseObjectIdentifier(innerBytes)
- case tagUTCTime:
- result, err = parseUTCTime(innerBytes)
- case tagOctetString:
- result = innerBytes
- default:
- // If we don't know how to handle the type, we just leave Value as nil.
- }
- }
- offset += t.length
- if err != nil {
- return
- }
- if result != nil {
- ifaceValue.Set(reflect.NewValue(result))
- }
- return
- }
- universalTag, compoundType, ok1 := getUniversalType(fieldType)
- if !ok1 {
- err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType)}
- return
- }
-
- t, offset, err := parseTagAndLength(bytes, offset)
- if err != nil {
- return
- }
- if params.explicit {
- expectedClass := classContextSpecific
- if params.application {
- expectedClass = classApplication
- }
- if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
- if t.length > 0 {
- t, offset, err = parseTagAndLength(bytes, offset)
- if err != nil {
- return
- }
- } else {
- if fieldType != flagType {
- err = StructuralError{"Zero length explicit tag was not an asn1.Flag"}
- return
- }
-
- flagValue := v.(*reflect.BoolValue)
- flagValue.Set(true)
- return
- }
- } else {
- // The tags didn't match, it might be an optional element.
- ok := setDefaultValue(v, params)
- if ok {
- offset = initOffset
- } else {
- err = StructuralError{"explicitly tagged member didn't match"}
- }
- return
- }
- }
-
- // Special case for strings: PrintableString and IA5String both map to
- // the Go type string. getUniversalType returns the tag for
- // PrintableString when it sees a string so, if we see an IA5String on
- // the wire, we change the universal type to match.
- if universalTag == tagPrintableString && t.tag == tagIA5String {
- universalTag = tagIA5String
- }
- // Likewise for GeneralString
- if universalTag == tagPrintableString && t.tag == tagGeneralString {
- universalTag = tagGeneralString
- }
-
- // Special case for time: UTCTime and GeneralizedTime both map to the
- // Go type time.Time.
- if universalTag == tagUTCTime && t.tag == tagGeneralizedTime {
- universalTag = tagGeneralizedTime
- }
-
- expectedClass := classUniversal
- expectedTag := universalTag
-
- if !params.explicit && params.tag != nil {
- expectedClass = classContextSpecific
- expectedTag = *params.tag
- }
-
- if !params.explicit && params.application && params.tag != nil {
- expectedClass = classApplication
- expectedTag = *params.tag
- }
-
- // We have unwrapped any explicit tagging at this point.
- if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
- // Tags don't match. Again, it could be an optional element.
- ok := setDefaultValue(v, params)
- if ok {
- offset = initOffset
- } else {
- err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset)}
- }
- return
- }
- if invalidLength(offset, t.length, len(bytes)) {
- err = SyntaxError{"data truncated"}
- return
- }
- innerBytes := bytes[offset : offset+t.length]
- offset += t.length
-
- // We deal with the structures defined in this package first.
- switch fieldType {
- case objectIdentifierType:
- newSlice, err1 := parseObjectIdentifier(innerBytes)
- sliceValue := v.(*reflect.SliceValue)
- sliceValue.Set(reflect.MakeSlice(sliceValue.Type().(*reflect.SliceType), len(newSlice), len(newSlice)))
- if err1 == nil {
- reflect.Copy(sliceValue, reflect.NewValue(newSlice).(reflect.ArrayOrSliceValue))
- }
- err = err1
- return
- case bitStringType:
- structValue := v.(*reflect.StructValue)
- bs, err1 := parseBitString(innerBytes)
- if err1 == nil {
- structValue.Set(reflect.NewValue(bs).(*reflect.StructValue))
- }
- err = err1
- return
- case timeType:
- ptrValue := v.(*reflect.PtrValue)
- var time *time.Time
- var err1 os.Error
- if universalTag == tagUTCTime {
- time, err1 = parseUTCTime(innerBytes)
- } else {
- time, err1 = parseGeneralizedTime(innerBytes)
- }
- if err1 == nil {
- ptrValue.Set(reflect.NewValue(time).(*reflect.PtrValue))
- }
- err = err1
- return
- case enumeratedType:
- parsedInt, err1 := parseInt(innerBytes)
- enumValue := v.(*reflect.IntValue)
- if err1 == nil {
- enumValue.Set(int64(parsedInt))
- }
- err = err1
- return
- case flagType:
- flagValue := v.(*reflect.BoolValue)
- flagValue.Set(true)
- return
- }
- switch val := v.(type) {
- case *reflect.BoolValue:
- parsedBool, err1 := parseBool(innerBytes)
- if err1 == nil {
- val.Set(parsedBool)
- }
- err = err1
- return
- case *reflect.IntValue:
- switch val.Type().Kind() {
- case reflect.Int:
- parsedInt, err1 := parseInt(innerBytes)
- if err1 == nil {
- val.Set(int64(parsedInt))
- }
- err = err1
- return
- case reflect.Int64:
- parsedInt, err1 := parseInt64(innerBytes)
- if err1 == nil {
- val.Set(parsedInt)
- }
- err = err1
- return
- }
- case *reflect.StructValue:
- structType := fieldType.(*reflect.StructType)
-
- if structType.NumField() > 0 &&
- structType.Field(0).Type == rawContentsType {
- bytes := bytes[initOffset:offset]
- val.Field(0).SetValue(reflect.NewValue(RawContent(bytes)))
- }
-
- innerOffset := 0
- for i := 0; i < structType.NumField(); i++ {
- field := structType.Field(i)
- if i == 0 && field.Type == rawContentsType {
- continue
- }
- innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag))
- if err != nil {
- return
- }
- }
- // We allow extra bytes at the end of the SEQUENCE because
- // adding elements to the end has been used in X.509 as the
- // version numbers have increased.
- return
- case *reflect.SliceValue:
- sliceType := fieldType.(*reflect.SliceType)
- if sliceType.Elem().Kind() == reflect.Uint8 {
- val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes)))
- reflect.Copy(val, reflect.NewValue(innerBytes).(reflect.ArrayOrSliceValue))
- return
- }
- newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
- if err1 == nil {
- val.Set(newSlice)
- }
- err = err1
- return
- case *reflect.StringValue:
- var v string
- switch universalTag {
- case tagPrintableString:
- v, err = parsePrintableString(innerBytes)
- case tagIA5String:
- v, err = parseIA5String(innerBytes)
- case tagT61String:
- v, err = parseT61String(innerBytes)
- case tagGeneralString:
- // GeneralString is specified in ISO-2022/ECMA-35,
- // A brief review suggests that it includes structures
- // that allow the encoding to change midstring and
- // such. We give up and pass it as an 8-bit string.
- v, err = parseT61String(innerBytes)
- default:
- err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
- }
- if err == nil {
- val.Set(v)
- }
- return
- }
- err = StructuralError{"unknown Go type"}
- return
-}
-
-// setDefaultValue is used to install a default value, from a tag string, into
-// a Value. It is successful is the field was optional, even if a default value
-// wasn't provided or it failed to install it into the Value.
-func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
- if !params.optional {
- return
- }
- ok = true
- if params.defaultValue == nil {
- return
- }
- switch val := v.(type) {
- case *reflect.IntValue:
- val.Set(*params.defaultValue)
- }
- return
-}
-
-// Unmarshal parses the DER-encoded ASN.1 data structure b
-// and uses the reflect package to fill in an arbitrary value pointed at by val.
-// Because Unmarshal uses the reflect package, the structs
-// being written to must use upper case field names.
-//
-// An ASN.1 INTEGER can be written to an int or int64.
-// If the encoded value does not fit in the Go type,
-// Unmarshal returns a parse error.
-//
-// An ASN.1 BIT STRING can be written to a BitString.
-//
-// An ASN.1 OCTET STRING can be written to a []byte.
-//
-// An ASN.1 OBJECT IDENTIFIER can be written to an
-// ObjectIdentifier.
-//
-// An ASN.1 ENUMERATED can be written to an Enumerated.
-//
-// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
-//
-// An ASN.1 PrintableString or IA5String can be written to a string.
-//
-// Any of the above ASN.1 values can be written to an interface{}.
-// The value stored in the interface has the corresponding Go type.
-// For integers, that type is int64.
-//
-// An ASN.1 SEQUENCE OF x or SET OF x can be written
-// to a slice if an x can be written to the slice's element type.
-//
-// An ASN.1 SEQUENCE or SET can be written to a struct
-// if each of the elements in the sequence can be
-// written to the corresponding element in the struct.
-//
-// The following tags on struct fields have special meaning to Unmarshal:
-//
-// optional marks the field as ASN.1 OPTIONAL
-// [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
-// default:x sets the default value for optional integer fields
-//
-// If the type of the first field of a structure is RawContent then the raw
-// ASN1 contents of the struct will be stored in it.
-//
-// Other ASN.1 types are not supported; if it encounters them,
-// Unmarshal returns a parse error.
-func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
- return UnmarshalWithParams(b, val, "")
-}
-
-// UnmarshalWithParams allows field parameters to be specified for the
-// top-level element. The form of the params is the same as the field tags.
-func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err os.Error) {
- v := reflect.NewValue(val).(*reflect.PtrValue).Elem()
- offset, err := parseField(v, b, 0, parseFieldParameters(params))
- if err != nil {
- return nil, err
- }
- return b[offset:], nil
-}
diff --git a/src/cmd/gofix/testdata/reflect.asn1.go.out b/src/cmd/gofix/testdata/reflect.asn1.go.out
deleted file mode 100644
index f5716f273..000000000
--- a/src/cmd/gofix/testdata/reflect.asn1.go.out
+++ /dev/null
@@ -1,815 +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.
-
-// The asn1 package implements parsing of DER-encoded ASN.1 data structures,
-// as defined in ITU-T Rec X.690.
-//
-// See also ``A Layman's Guide to a Subset of ASN.1, BER, and DER,''
-// http://luca.ntop.org/Teaching/Appunti/asn1.html.
-package asn1
-
-// ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc
-// are different encoding formats for those objects. Here, we'll be dealing
-// with DER, the Distinguished Encoding Rules. DER is used in X.509 because
-// it's fast to parse and, unlike BER, has a unique encoding for every object.
-// When calculating hashes over objects, it's important that the resulting
-// bytes be the same at both ends and DER removes this margin of error.
-//
-// ASN.1 is very complex and this package doesn't attempt to implement
-// everything by any means.
-
-import (
- "fmt"
- "os"
- "reflect"
- "time"
-)
-
-// A StructuralError suggests that the ASN.1 data is valid, but the Go type
-// which is receiving it doesn't match.
-type StructuralError struct {
- Msg string
-}
-
-func (e StructuralError) String() string { return "ASN.1 structure error: " + e.Msg }
-
-// A SyntaxError suggests that the ASN.1 data is invalid.
-type SyntaxError struct {
- Msg string
-}
-
-func (e SyntaxError) String() string { return "ASN.1 syntax error: " + e.Msg }
-
-// We start by dealing with each of the primitive types in turn.
-
-// BOOLEAN
-
-func parseBool(bytes []byte) (ret bool, err os.Error) {
- if len(bytes) != 1 {
- err = SyntaxError{"invalid boolean"}
- return
- }
-
- return bytes[0] != 0, nil
-}
-
-// INTEGER
-
-// parseInt64 treats the given bytes as a big-endian, signed integer and
-// returns the result.
-func parseInt64(bytes []byte) (ret int64, err os.Error) {
- if len(bytes) > 8 {
- // We'll overflow an int64 in this case.
- err = StructuralError{"integer too large"}
- return
- }
- for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
- ret <<= 8
- ret |= int64(bytes[bytesRead])
- }
-
- // Shift up and down in order to sign extend the result.
- ret <<= 64 - uint8(len(bytes))*8
- ret >>= 64 - uint8(len(bytes))*8
- return
-}
-
-// parseInt treats the given bytes as a big-endian, signed integer and returns
-// the result.
-func parseInt(bytes []byte) (int, os.Error) {
- ret64, err := parseInt64(bytes)
- if err != nil {
- return 0, err
- }
- if ret64 != int64(int(ret64)) {
- return 0, StructuralError{"integer too large"}
- }
- return int(ret64), nil
-}
-
-// BIT STRING
-
-// BitString is the structure to use when you want an ASN.1 BIT STRING type. A
-// bit string is padded up to the nearest byte in memory and the number of
-// valid bits is recorded. Padding bits will be zero.
-type BitString struct {
- Bytes []byte // bits packed into bytes.
- BitLength int // length in bits.
-}
-
-// At returns the bit at the given index. If the index is out of range it
-// returns false.
-func (b BitString) At(i int) int {
- if i < 0 || i >= b.BitLength {
- return 0
- }
- x := i / 8
- y := 7 - uint(i%8)
- return int(b.Bytes[x]>>y) & 1
-}
-
-// RightAlign returns a slice where the padding bits are at the beginning. The
-// slice may share memory with the BitString.
-func (b BitString) RightAlign() []byte {
- shift := uint(8 - (b.BitLength % 8))
- if shift == 8 || len(b.Bytes) == 0 {
- return b.Bytes
- }
-
- a := make([]byte, len(b.Bytes))
- a[0] = b.Bytes[0] >> shift
- for i := 1; i < len(b.Bytes); i++ {
- a[i] = b.Bytes[i-1] << (8 - shift)
- a[i] |= b.Bytes[i] >> shift
- }
-
- return a
-}
-
-// parseBitString parses an ASN.1 bit string from the given byte array and returns it.
-func parseBitString(bytes []byte) (ret BitString, err os.Error) {
- if len(bytes) == 0 {
- err = SyntaxError{"zero length BIT STRING"}
- return
- }
- paddingBits := int(bytes[0])
- if paddingBits > 7 ||
- len(bytes) == 1 && paddingBits > 0 ||
- bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {
- err = SyntaxError{"invalid padding bits in BIT STRING"}
- return
- }
- ret.BitLength = (len(bytes)-1)*8 - paddingBits
- ret.Bytes = bytes[1:]
- return
-}
-
-// OBJECT IDENTIFIER
-
-// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
-type ObjectIdentifier []int
-
-// Equal returns true iff oi and other represent the same identifier.
-func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
- if len(oi) != len(other) {
- return false
- }
- for i := 0; i < len(oi); i++ {
- if oi[i] != other[i] {
- return false
- }
- }
-
- return true
-}
-
-// parseObjectIdentifier parses an OBJECT IDENTIFER from the given bytes and
-// returns it. An object identifer is a sequence of variable length integers
-// that are assigned in a hierarachy.
-func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
- if len(bytes) == 0 {
- err = SyntaxError{"zero length OBJECT IDENTIFIER"}
- return
- }
-
- // In the worst case, we get two elements from the first byte (which is
- // encoded differently) and then every varint is a single byte long.
- s = make([]int, len(bytes)+1)
-
- // The first byte is 40*value1 + value2:
- s[0] = int(bytes[0]) / 40
- s[1] = int(bytes[0]) % 40
- i := 2
- for offset := 1; offset < len(bytes); i++ {
- var v int
- v, offset, err = parseBase128Int(bytes, offset)
- if err != nil {
- return
- }
- s[i] = v
- }
- s = s[0:i]
- return
-}
-
-// ENUMERATED
-
-// An Enumerated is represented as a plain int.
-type Enumerated int
-
-
-// FLAG
-
-// A Flag accepts any data and is set to true if present.
-type Flag bool
-
-// parseBase128Int parses a base-128 encoded int from the given offset in the
-// given byte array. It returns the value and the new offset.
-func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) {
- offset = initOffset
- for shifted := 0; offset < len(bytes); shifted++ {
- if shifted > 4 {
- err = StructuralError{"base 128 integer too large"}
- return
- }
- ret <<= 7
- b := bytes[offset]
- ret |= int(b & 0x7f)
- offset++
- if b&0x80 == 0 {
- return
- }
- }
- err = SyntaxError{"truncated base 128 integer"}
- return
-}
-
-// UTCTime
-
-func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
- s := string(bytes)
- ret, err = time.Parse("0601021504Z0700", s)
- if err == nil {
- return
- }
- ret, err = time.Parse("060102150405Z0700", s)
- return
-}
-
-// parseGeneralizedTime parses the GeneralizedTime from the given byte array
-// and returns the resulting time.
-func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
- return time.Parse("20060102150405Z0700", string(bytes))
-}
-
-// PrintableString
-
-// parsePrintableString parses a ASN.1 PrintableString from the given byte
-// array and returns it.
-func parsePrintableString(bytes []byte) (ret string, err os.Error) {
- for _, b := range bytes {
- if !isPrintable(b) {
- err = SyntaxError{"PrintableString contains invalid character"}
- return
- }
- }
- ret = string(bytes)
- return
-}
-
-// isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
-func isPrintable(b byte) bool {
- return 'a' <= b && b <= 'z' ||
- 'A' <= b && b <= 'Z' ||
- '0' <= b && b <= '9' ||
- '\'' <= b && b <= ')' ||
- '+' <= b && b <= '/' ||
- b == ' ' ||
- b == ':' ||
- b == '=' ||
- b == '?' ||
- // This is techincally not allowed in a PrintableString.
- // However, x509 certificates with wildcard strings don't
- // always use the correct string type so we permit it.
- b == '*'
-}
-
-// IA5String
-
-// parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
-// byte array and returns it.
-func parseIA5String(bytes []byte) (ret string, err os.Error) {
- for _, b := range bytes {
- if b >= 0x80 {
- err = SyntaxError{"IA5String contains invalid character"}
- return
- }
- }
- ret = string(bytes)
- return
-}
-
-// T61String
-
-// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
-// byte array and returns it.
-func parseT61String(bytes []byte) (ret string, err os.Error) {
- return string(bytes), nil
-}
-
-// A RawValue represents an undecoded ASN.1 object.
-type RawValue struct {
- Class, Tag int
- IsCompound bool
- Bytes []byte
- FullBytes []byte // includes the tag and length
-}
-
-// RawContent is used to signal that the undecoded, DER data needs to be
-// preserved for a struct. To use it, the first field of the struct must have
-// this type. It's an error for any of the other fields to have this type.
-type RawContent []byte
-
-// Tagging
-
-// parseTagAndLength parses an ASN.1 tag and length pair from the given offset
-// into a byte array. It returns the parsed data and the new offset. SET and
-// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
-// don't distinguish between ordered and unordered objects in this code.
-func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err os.Error) {
- offset = initOffset
- b := bytes[offset]
- offset++
- ret.class = int(b >> 6)
- ret.isCompound = b&0x20 == 0x20
- ret.tag = int(b & 0x1f)
-
- // If the bottom five bits are set, then the tag number is actually base 128
- // encoded afterwards
- if ret.tag == 0x1f {
- ret.tag, offset, err = parseBase128Int(bytes, offset)
- if err != nil {
- return
- }
- }
- if offset >= len(bytes) {
- err = SyntaxError{"truncated tag or length"}
- return
- }
- b = bytes[offset]
- offset++
- if b&0x80 == 0 {
- // The length is encoded in the bottom 7 bits.
- ret.length = int(b & 0x7f)
- } else {
- // Bottom 7 bits give the number of length bytes to follow.
- numBytes := int(b & 0x7f)
- // We risk overflowing a signed 32-bit number if we accept more than 3 bytes.
- if numBytes > 3 {
- err = StructuralError{"length too large"}
- return
- }
- if numBytes == 0 {
- err = SyntaxError{"indefinite length found (not DER)"}
- return
- }
- ret.length = 0
- for i := 0; i < numBytes; i++ {
- if offset >= len(bytes) {
- err = SyntaxError{"truncated tag or length"}
- return
- }
- b = bytes[offset]
- offset++
- ret.length <<= 8
- ret.length |= int(b)
- }
- }
-
- return
-}
-
-// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
-// a number of ASN.1 values from the given byte array and returns them as a
-// slice of Go values of the given type.
-func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type) (ret reflect.Value, err os.Error) {
- expectedTag, compoundType, ok := getUniversalType(elemType)
- if !ok {
- err = StructuralError{"unknown Go type for slice"}
- return
- }
-
- // First we iterate over the input and count the number of elements,
- // checking that the types are correct in each case.
- numElements := 0
- for offset := 0; offset < len(bytes); {
- var t tagAndLength
- t, offset, err = parseTagAndLength(bytes, offset)
- if err != nil {
- return
- }
- // We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
- // that a sequence of them can be parsed into a []string.
- if t.tag == tagGeneralString {
- t.tag = tagPrintableString
- }
- if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
- err = StructuralError{"sequence tag mismatch"}
- return
- }
- if invalidLength(offset, t.length, len(bytes)) {
- err = SyntaxError{"truncated sequence"}
- return
- }
- offset += t.length
- numElements++
- }
- ret = reflect.MakeSlice(sliceType, numElements, numElements)
- params := fieldParameters{}
- offset := 0
- for i := 0; i < numElements; i++ {
- offset, err = parseField(ret.Index(i), bytes, offset, params)
- if err != nil {
- return
- }
- }
- return
-}
-
-var (
- bitStringType = reflect.TypeOf(BitString{})
- objectIdentifierType = reflect.TypeOf(ObjectIdentifier{})
- enumeratedType = reflect.TypeOf(Enumerated(0))
- flagType = reflect.TypeOf(Flag(false))
- timeType = reflect.TypeOf(&time.Time{})
- rawValueType = reflect.TypeOf(RawValue{})
- rawContentsType = reflect.TypeOf(RawContent(nil))
-)
-
-// invalidLength returns true iff offset + length > sliceLength, or if the
-// addition would overflow.
-func invalidLength(offset, length, sliceLength int) bool {
- return offset+length < offset || offset+length > sliceLength
-}
-
-// parseField is the main parsing function. Given a byte array and an offset
-// into the array, it will try to parse a suitable ASN.1 value out and store it
-// in the given Value.
-func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err os.Error) {
- offset = initOffset
- fieldType := v.Type()
-
- // If we have run out of data, it may be that there are optional elements at the end.
- if offset == len(bytes) {
- if !setDefaultValue(v, params) {
- err = SyntaxError{"sequence truncated"}
- }
- return
- }
-
- // Deal with raw values.
- if fieldType == rawValueType {
- var t tagAndLength
- t, offset, err = parseTagAndLength(bytes, offset)
- if err != nil {
- return
- }
- if invalidLength(offset, t.length, len(bytes)) {
- err = SyntaxError{"data truncated"}
- return
- }
- result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length], bytes[initOffset : offset+t.length]}
- offset += t.length
- v.Set(reflect.ValueOf(result))
- return
- }
-
- // Deal with the ANY type.
- if ifaceType := fieldType; ifaceType.Kind() == reflect.Interface && ifaceType.NumMethod() == 0 {
- ifaceValue := v
- var t tagAndLength
- t, offset, err = parseTagAndLength(bytes, offset)
- if err != nil {
- return
- }
- if invalidLength(offset, t.length, len(bytes)) {
- err = SyntaxError{"data truncated"}
- return
- }
- var result interface{}
- if !t.isCompound && t.class == classUniversal {
- innerBytes := bytes[offset : offset+t.length]
- switch t.tag {
- case tagPrintableString:
- result, err = parsePrintableString(innerBytes)
- case tagIA5String:
- result, err = parseIA5String(innerBytes)
- case tagT61String:
- result, err = parseT61String(innerBytes)
- case tagInteger:
- result, err = parseInt64(innerBytes)
- case tagBitString:
- result, err = parseBitString(innerBytes)
- case tagOID:
- result, err = parseObjectIdentifier(innerBytes)
- case tagUTCTime:
- result, err = parseUTCTime(innerBytes)
- case tagOctetString:
- result = innerBytes
- default:
- // If we don't know how to handle the type, we just leave Value as nil.
- }
- }
- offset += t.length
- if err != nil {
- return
- }
- if result != nil {
- ifaceValue.Set(reflect.ValueOf(result))
- }
- return
- }
- universalTag, compoundType, ok1 := getUniversalType(fieldType)
- if !ok1 {
- err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType)}
- return
- }
-
- t, offset, err := parseTagAndLength(bytes, offset)
- if err != nil {
- return
- }
- if params.explicit {
- expectedClass := classContextSpecific
- if params.application {
- expectedClass = classApplication
- }
- if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
- if t.length > 0 {
- t, offset, err = parseTagAndLength(bytes, offset)
- if err != nil {
- return
- }
- } else {
- if fieldType != flagType {
- err = StructuralError{"Zero length explicit tag was not an asn1.Flag"}
- return
- }
-
- flagValue := v
- flagValue.SetBool(true)
- return
- }
- } else {
- // The tags didn't match, it might be an optional element.
- ok := setDefaultValue(v, params)
- if ok {
- offset = initOffset
- } else {
- err = StructuralError{"explicitly tagged member didn't match"}
- }
- return
- }
- }
-
- // Special case for strings: PrintableString and IA5String both map to
- // the Go type string. getUniversalType returns the tag for
- // PrintableString when it sees a string so, if we see an IA5String on
- // the wire, we change the universal type to match.
- if universalTag == tagPrintableString && t.tag == tagIA5String {
- universalTag = tagIA5String
- }
- // Likewise for GeneralString
- if universalTag == tagPrintableString && t.tag == tagGeneralString {
- universalTag = tagGeneralString
- }
-
- // Special case for time: UTCTime and GeneralizedTime both map to the
- // Go type time.Time.
- if universalTag == tagUTCTime && t.tag == tagGeneralizedTime {
- universalTag = tagGeneralizedTime
- }
-
- expectedClass := classUniversal
- expectedTag := universalTag
-
- if !params.explicit && params.tag != nil {
- expectedClass = classContextSpecific
- expectedTag = *params.tag
- }
-
- if !params.explicit && params.application && params.tag != nil {
- expectedClass = classApplication
- expectedTag = *params.tag
- }
-
- // We have unwrapped any explicit tagging at this point.
- if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
- // Tags don't match. Again, it could be an optional element.
- ok := setDefaultValue(v, params)
- if ok {
- offset = initOffset
- } else {
- err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset)}
- }
- return
- }
- if invalidLength(offset, t.length, len(bytes)) {
- err = SyntaxError{"data truncated"}
- return
- }
- innerBytes := bytes[offset : offset+t.length]
- offset += t.length
-
- // We deal with the structures defined in this package first.
- switch fieldType {
- case objectIdentifierType:
- newSlice, err1 := parseObjectIdentifier(innerBytes)
- sliceValue := v
- sliceValue.Set(reflect.MakeSlice(sliceValue.Type(), len(newSlice), len(newSlice)))
- if err1 == nil {
- reflect.Copy(sliceValue, reflect.ValueOf(newSlice))
- }
- err = err1
- return
- case bitStringType:
- structValue := v
- bs, err1 := parseBitString(innerBytes)
- if err1 == nil {
- structValue.Set(reflect.ValueOf(bs))
- }
- err = err1
- return
- case timeType:
- ptrValue := v
- var time *time.Time
- var err1 os.Error
- if universalTag == tagUTCTime {
- time, err1 = parseUTCTime(innerBytes)
- } else {
- time, err1 = parseGeneralizedTime(innerBytes)
- }
- if err1 == nil {
- ptrValue.Set(reflect.ValueOf(time))
- }
- err = err1
- return
- case enumeratedType:
- parsedInt, err1 := parseInt(innerBytes)
- enumValue := v
- if err1 == nil {
- enumValue.SetInt(int64(parsedInt))
- }
- err = err1
- return
- case flagType:
- flagValue := v
- flagValue.SetBool(true)
- return
- }
- switch val := v; val.Kind() {
- case reflect.Bool:
- parsedBool, err1 := parseBool(innerBytes)
- if err1 == nil {
- val.SetBool(parsedBool)
- }
- err = err1
- return
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- switch val.Type().Kind() {
- case reflect.Int:
- parsedInt, err1 := parseInt(innerBytes)
- if err1 == nil {
- val.SetInt(int64(parsedInt))
- }
- err = err1
- return
- case reflect.Int64:
- parsedInt, err1 := parseInt64(innerBytes)
- if err1 == nil {
- val.SetInt(parsedInt)
- }
- err = err1
- return
- }
- case reflect.Struct:
- structType := fieldType
-
- if structType.NumField() > 0 &&
- structType.Field(0).Type == rawContentsType {
- bytes := bytes[initOffset:offset]
- val.Field(0).Set(reflect.ValueOf(RawContent(bytes)))
- }
-
- innerOffset := 0
- for i := 0; i < structType.NumField(); i++ {
- field := structType.Field(i)
- if i == 0 && field.Type == rawContentsType {
- continue
- }
- innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag))
- if err != nil {
- return
- }
- }
- // We allow extra bytes at the end of the SEQUENCE because
- // adding elements to the end has been used in X.509 as the
- // version numbers have increased.
- return
- case reflect.Slice:
- sliceType := fieldType
- if sliceType.Elem().Kind() == reflect.Uint8 {
- val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes)))
- reflect.Copy(val, reflect.ValueOf(innerBytes))
- return
- }
- newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
- if err1 == nil {
- val.Set(newSlice)
- }
- err = err1
- return
- case reflect.String:
- var v string
- switch universalTag {
- case tagPrintableString:
- v, err = parsePrintableString(innerBytes)
- case tagIA5String:
- v, err = parseIA5String(innerBytes)
- case tagT61String:
- v, err = parseT61String(innerBytes)
- case tagGeneralString:
- // GeneralString is specified in ISO-2022/ECMA-35,
- // A brief review suggests that it includes structures
- // that allow the encoding to change midstring and
- // such. We give up and pass it as an 8-bit string.
- v, err = parseT61String(innerBytes)
- default:
- err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
- }
- if err == nil {
- val.SetString(v)
- }
- return
- }
- err = StructuralError{"unknown Go type"}
- return
-}
-
-// setDefaultValue is used to install a default value, from a tag string, into
-// a Value. It is successful is the field was optional, even if a default value
-// wasn't provided or it failed to install it into the Value.
-func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
- if !params.optional {
- return
- }
- ok = true
- if params.defaultValue == nil {
- return
- }
- switch val := v; val.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- val.SetInt(*params.defaultValue)
- }
- return
-}
-
-// Unmarshal parses the DER-encoded ASN.1 data structure b
-// and uses the reflect package to fill in an arbitrary value pointed at by val.
-// Because Unmarshal uses the reflect package, the structs
-// being written to must use upper case field names.
-//
-// An ASN.1 INTEGER can be written to an int or int64.
-// If the encoded value does not fit in the Go type,
-// Unmarshal returns a parse error.
-//
-// An ASN.1 BIT STRING can be written to a BitString.
-//
-// An ASN.1 OCTET STRING can be written to a []byte.
-//
-// An ASN.1 OBJECT IDENTIFIER can be written to an
-// ObjectIdentifier.
-//
-// An ASN.1 ENUMERATED can be written to an Enumerated.
-//
-// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
-//
-// An ASN.1 PrintableString or IA5String can be written to a string.
-//
-// Any of the above ASN.1 values can be written to an interface{}.
-// The value stored in the interface has the corresponding Go type.
-// For integers, that type is int64.
-//
-// An ASN.1 SEQUENCE OF x or SET OF x can be written
-// to a slice if an x can be written to the slice's element type.
-//
-// An ASN.1 SEQUENCE or SET can be written to a struct
-// if each of the elements in the sequence can be
-// written to the corresponding element in the struct.
-//
-// The following tags on struct fields have special meaning to Unmarshal:
-//
-// optional marks the field as ASN.1 OPTIONAL
-// [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
-// default:x sets the default value for optional integer fields
-//
-// If the type of the first field of a structure is RawContent then the raw
-// ASN1 contents of the struct will be stored in it.
-//
-// Other ASN.1 types are not supported; if it encounters them,
-// Unmarshal returns a parse error.
-func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
- return UnmarshalWithParams(b, val, "")
-}
-
-// UnmarshalWithParams allows field parameters to be specified for the
-// top-level element. The form of the params is the same as the field tags.
-func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err os.Error) {
- v := reflect.ValueOf(val).Elem()
- offset, err := parseField(v, b, 0, parseFieldParameters(params))
- if err != nil {
- return nil, err
- }
- return b[offset:], nil
-}
diff --git a/src/cmd/gofix/testdata/reflect.datafmt.go.in b/src/cmd/gofix/testdata/reflect.datafmt.go.in
deleted file mode 100644
index 46c412342..000000000
--- a/src/cmd/gofix/testdata/reflect.datafmt.go.in
+++ /dev/null
@@ -1,731 +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.
-
-/* The datafmt package implements syntax-directed, type-driven formatting
- of arbitrary data structures. Formatting a data structure consists of
- two phases: first, a parser reads a format specification and builds a
- "compiled" format. Then, the format can be applied repeatedly to
- arbitrary values. Applying a format to a value evaluates to a []byte
- containing the formatted value bytes, or nil.
-
- A format specification is a set of package declarations and format rules:
-
- Format = [ Entry { ";" Entry } [ ";" ] ] .
- Entry = PackageDecl | FormatRule .
-
- (The syntax of a format specification is presented in the same EBNF
- notation as used in the Go language specification. The syntax of white
- space, comments, identifiers, and string literals is the same as in Go.)
-
- A package declaration binds a package name (such as 'ast') to a
- package import path (such as '"go/ast"'). Each package used (in
- a type name, see below) must be declared once before use.
-
- PackageDecl = PackageName ImportPath .
- PackageName = identifier .
- ImportPath = string .
-
- A format rule binds a rule name to a format expression. A rule name
- may be a type name or one of the special names 'default' or '/'.
- A type name may be the name of a predeclared type (for example, 'int',
- 'float32', etc.), the package-qualified name of a user-defined type
- (for example, 'ast.MapType'), or an identifier indicating the structure
- of unnamed composite types ('array', 'chan', 'func', 'interface', 'map',
- or 'ptr'). Each rule must have a unique name; rules can be declared in
- any order.
-
- FormatRule = RuleName "=" Expression .
- RuleName = TypeName | "default" | "/" .
- TypeName = [ PackageName "." ] identifier .
-
- To format a value, the value's type name is used to select the format rule
- (there is an override mechanism, see below). The format expression of the
- selected rule specifies how the value is formatted. Each format expression,
- when applied to a value, evaluates to a byte sequence or nil.
-
- In its most general form, a format expression is a list of alternatives,
- each of which is a sequence of operands:
-
- Expression = [ Sequence ] { "|" [ Sequence ] } .
- Sequence = Operand { Operand } .
-
- The formatted result produced by an expression is the result of the first
- alternative sequence that evaluates to a non-nil result; if there is no
- such alternative, the expression evaluates to nil. The result produced by
- an operand sequence is the concatenation of the results of its operands.
- If any operand in the sequence evaluates to nil, the entire sequence
- evaluates to nil.
-
- There are five kinds of operands:
-
- Operand = Literal | Field | Group | Option | Repetition .
-
- Literals evaluate to themselves, with two substitutions. First,
- %-formats expand in the manner of fmt.Printf, with the current value
- passed as the parameter. Second, the current indentation (see below)
- is inserted after every newline or form feed character.
-
- Literal = string .
-
- This table shows string literals applied to the value 42 and the
- corresponding formatted result:
-
- "foo" foo
- "%x" 2a
- "x = %d" x = 42
- "%#x = %d" 0x2a = 42
-
- A field operand is a field name optionally followed by an alternate
- rule name. The field name may be an identifier or one of the special
- names @ or *.
-
- Field = FieldName [ ":" RuleName ] .
- FieldName = identifier | "@" | "*" .
-
- If the field name is an identifier, the current value must be a struct,
- and there must be a field with that name in the struct. The same lookup
- rules apply as in the Go language (for instance, the name of an anonymous
- field is the unqualified type name). The field name denotes the field
- value in the struct. If the field is not found, formatting is aborted
- and an error message is returned. (TODO consider changing the semantics
- such that if a field is not found, it evaluates to nil).
-
- The special name '@' denotes the current value.
-
- The meaning of the special name '*' depends on the type of the current
- value:
-
- array, slice types array, slice element (inside {} only, see below)
- interfaces value stored in interface
- pointers value pointed to by pointer
-
- (Implementation restriction: channel, function and map types are not
- supported due to missing reflection support).
-
- Fields are evaluated as follows: If the field value is nil, or an array
- or slice element does not exist, the result is nil (see below for details
- on array/slice elements). If the value is not nil the field value is
- formatted (recursively) using the rule corresponding to its type name,
- or the alternate rule name, if given.
-
- The following example shows a complete format specification for a
- struct 'myPackage.Point'. Assume the package
-
- package myPackage // in directory myDir/myPackage
- type Point struct {
- name string;
- x, y int;
- }
-
- Applying the format specification
-
- myPackage "myDir/myPackage";
- int = "%d";
- hexInt = "0x%x";
- string = "---%s---";
- myPackage.Point = name "{" x ", " y:hexInt "}";
-
- to the value myPackage.Point{"foo", 3, 15} results in
-
- ---foo---{3, 0xf}
-
- Finally, an operand may be a grouped, optional, or repeated expression.
- A grouped expression ("group") groups a more complex expression (body)
- so that it can be used in place of a single operand:
-
- Group = "(" [ Indentation ">>" ] Body ")" .
- Indentation = Expression .
- Body = Expression .
-
- A group body may be prefixed by an indentation expression followed by '>>'.
- The indentation expression is applied to the current value like any other
- expression and the result, if not nil, is appended to the current indentation
- during the evaluation of the body (see also formatting state, below).
-
- An optional expression ("option") is enclosed in '[]' brackets.
-
- Option = "[" Body "]" .
-
- An option evaluates to its body, except that if the body evaluates to nil,
- the option expression evaluates to an empty []byte. Thus an option's purpose
- is to protect the expression containing the option from a nil operand.
-
- A repeated expression ("repetition") is enclosed in '{}' braces.
-
- Repetition = "{" Body [ "/" Separator ] "}" .
- Separator = Expression .
-
- A repeated expression is evaluated as follows: The body is evaluated
- repeatedly and its results are concatenated until the body evaluates
- to nil. The result of the repetition is the (possibly empty) concatenation,
- but it is never nil. An implicit index is supplied for the evaluation of
- the body: that index is used to address elements of arrays or slices. If
- the corresponding elements do not exist, the field denoting the element
- evaluates to nil (which in turn may terminate the repetition).
-
- The body of a repetition may be followed by a '/' and a "separator"
- expression. If the separator is present, it is invoked between repetitions
- of the body.
-
- The following example shows a complete format specification for formatting
- a slice of unnamed type. Applying the specification
-
- int = "%b";
- array = { * / ", " }; // array is the type name for an unnamed slice
-
- to the value '[]int{2, 3, 5, 7}' results in
-
- 10, 11, 101, 111
-
- Default rule: If a format rule named 'default' is present, it is used for
- formatting a value if no other rule was found. A common default rule is
-
- default = "%v"
-
- to provide default formatting for basic types without having to specify
- a specific rule for each basic type.
-
- Global separator rule: If a format rule named '/' is present, it is
- invoked with the current value between literals. If the separator
- expression evaluates to nil, it is ignored.
-
- For instance, a global separator rule may be used to punctuate a sequence
- of values with commas. The rules:
-
- default = "%v";
- / = ", ";
-
- will format an argument list by printing each one in its default format,
- separated by a comma and a space.
-*/
-package datafmt
-
-import (
- "bytes"
- "fmt"
- "go/token"
- "io"
- "os"
- "reflect"
- "runtime"
-)
-
-
-// ----------------------------------------------------------------------------
-// Format representation
-
-// Custom formatters implement the Formatter function type.
-// A formatter is invoked with the current formatting state, the
-// value to format, and the rule name under which the formatter
-// was installed (the same formatter function may be installed
-// under different names). The formatter may access the current state
-// to guide formatting and use State.Write to append to the state's
-// output.
-//
-// A formatter must return a boolean value indicating if it evaluated
-// to a non-nil value (true), or a nil value (false).
-//
-type Formatter func(state *State, value interface{}, ruleName string) bool
-
-
-// A FormatterMap is a set of custom formatters.
-// It maps a rule name to a formatter function.
-//
-type FormatterMap map[string]Formatter
-
-
-// A parsed format expression is built from the following nodes.
-//
-type (
- expr interface{}
-
- alternatives []expr // x | y | z
-
- sequence []expr // x y z
-
- literal [][]byte // a list of string segments, possibly starting with '%'
-
- field struct {
- fieldName string // including "@", "*"
- ruleName string // "" if no rule name specified
- }
-
- group struct {
- indent, body expr // (indent >> body)
- }
-
- option struct {
- body expr // [body]
- }
-
- repetition struct {
- body, separator expr // {body / separator}
- }
-
- custom struct {
- ruleName string
- fun Formatter
- }
-)
-
-
-// A Format is the result of parsing a format specification.
-// The format may be applied repeatedly to format values.
-//
-type Format map[string]expr
-
-
-// ----------------------------------------------------------------------------
-// Formatting
-
-// An application-specific environment may be provided to Format.Apply;
-// the environment is available inside custom formatters via State.Env().
-// Environments must implement copying; the Copy method must return an
-// complete copy of the receiver. This is necessary so that the formatter
-// can save and restore an environment (in case of an absent expression).
-//
-// If the Environment doesn't change during formatting (this is under
-// control of the custom formatters), the Copy function can simply return
-// the receiver, and thus can be very light-weight.
-//
-type Environment interface {
- Copy() Environment
-}
-
-
-// State represents the current formatting state.
-// It is provided as argument to custom formatters.
-//
-type State struct {
- fmt Format // format in use
- env Environment // user-supplied environment
- errors chan os.Error // not chan *Error (errors <- nil would be wrong!)
- hasOutput bool // true after the first literal has been written
- indent bytes.Buffer // current indentation
- output bytes.Buffer // format output
- linePos token.Position // position of line beginning (Column == 0)
- default_ expr // possibly nil
- separator expr // possibly nil
-}
-
-
-func newState(fmt Format, env Environment, errors chan os.Error) *State {
- s := new(State)
- s.fmt = fmt
- s.env = env
- s.errors = errors
- s.linePos = token.Position{Line: 1}
-
- // if we have a default rule, cache it's expression for fast access
- if x, found := fmt["default"]; found {
- s.default_ = x
- }
-
- // if we have a global separator rule, cache it's expression for fast access
- if x, found := fmt["/"]; found {
- s.separator = x
- }
-
- return s
-}
-
-
-// Env returns the environment passed to Format.Apply.
-func (s *State) Env() interface{} { return s.env }
-
-
-// LinePos returns the position of the current line beginning
-// in the state's output buffer. Line numbers start at 1.
-//
-func (s *State) LinePos() token.Position { return s.linePos }
-
-
-// Pos returns the position of the next byte to be written to the
-// output buffer. Line numbers start at 1.
-//
-func (s *State) Pos() token.Position {
- offs := s.output.Len()
- return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs}
-}
-
-
-// Write writes data to the output buffer, inserting the indentation
-// string after each newline or form feed character. It cannot return an error.
-//
-func (s *State) Write(data []byte) (int, os.Error) {
- n := 0
- i0 := 0
- for i, ch := range data {
- if ch == '\n' || ch == '\f' {
- // write text segment and indentation
- n1, _ := s.output.Write(data[i0 : i+1])
- n2, _ := s.output.Write(s.indent.Bytes())
- n += n1 + n2
- i0 = i + 1
- s.linePos.Offset = s.output.Len()
- s.linePos.Line++
- }
- }
- n3, _ := s.output.Write(data[i0:])
- return n + n3, nil
-}
-
-
-type checkpoint struct {
- env Environment
- hasOutput bool
- outputLen int
- linePos token.Position
-}
-
-
-func (s *State) save() checkpoint {
- saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
- if s.env != nil {
- saved.env = s.env.Copy()
- }
- return saved
-}
-
-
-func (s *State) restore(m checkpoint) {
- s.env = m.env
- s.output.Truncate(m.outputLen)
-}
-
-
-func (s *State) error(msg string) {
- s.errors <- os.NewError(msg)
- runtime.Goexit()
-}
-
-
-// TODO At the moment, unnamed types are simply mapped to the default
-// names below. For instance, all unnamed arrays are mapped to
-// 'array' which is not really sufficient. Eventually one may want
-// to be able to specify rules for say an unnamed slice of T.
-//
-
-func typename(typ reflect.Type) string {
- switch typ.(type) {
- case *reflect.ArrayType:
- return "array"
- case *reflect.SliceType:
- return "array"
- case *reflect.ChanType:
- return "chan"
- case *reflect.FuncType:
- return "func"
- case *reflect.InterfaceType:
- return "interface"
- case *reflect.MapType:
- return "map"
- case *reflect.PtrType:
- return "ptr"
- }
- return typ.String()
-}
-
-func (s *State) getFormat(name string) expr {
- if fexpr, found := s.fmt[name]; found {
- return fexpr
- }
-
- if s.default_ != nil {
- return s.default_
- }
-
- s.error(fmt.Sprintf("no format rule for type: '%s'", name))
- return nil
-}
-
-
-// eval applies a format expression fexpr to a value. If the expression
-// evaluates internally to a non-nil []byte, that slice is appended to
-// the state's output buffer and eval returns true. Otherwise, eval
-// returns false and the state remains unchanged.
-//
-func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
- // an empty format expression always evaluates
- // to a non-nil (but empty) []byte
- if fexpr == nil {
- return true
- }
-
- switch t := fexpr.(type) {
- case alternatives:
- // append the result of the first alternative that evaluates to
- // a non-nil []byte to the state's output
- mark := s.save()
- for _, x := range t {
- if s.eval(x, value, index) {
- return true
- }
- s.restore(mark)
- }
- return false
-
- case sequence:
- // append the result of all operands to the state's output
- // unless a nil result is encountered
- mark := s.save()
- for _, x := range t {
- if !s.eval(x, value, index) {
- s.restore(mark)
- return false
- }
- }
- return true
-
- case literal:
- // write separator, if any
- if s.hasOutput {
- // not the first literal
- if s.separator != nil {
- sep := s.separator // save current separator
- s.separator = nil // and disable it (avoid recursion)
- mark := s.save()
- if !s.eval(sep, value, index) {
- s.restore(mark)
- }
- s.separator = sep // enable it again
- }
- }
- s.hasOutput = true
- // write literal segments
- for _, lit := range t {
- if len(lit) > 1 && lit[0] == '%' {
- // segment contains a %-format at the beginning
- if lit[1] == '%' {
- // "%%" is printed as a single "%"
- s.Write(lit[1:])
- } else {
- // use s instead of s.output to get indentation right
- fmt.Fprintf(s, string(lit), value.Interface())
- }
- } else {
- // segment contains no %-formats
- s.Write(lit)
- }
- }
- return true // a literal never evaluates to nil
-
- case *field:
- // determine field value
- switch t.fieldName {
- case "@":
- // field value is current value
-
- case "*":
- // indirection: operation is type-specific
- switch v := value.(type) {
- case *reflect.ArrayValue:
- if v.Len() <= index {
- return false
- }
- value = v.Elem(index)
-
- case *reflect.SliceValue:
- if v.IsNil() || v.Len() <= index {
- return false
- }
- value = v.Elem(index)
-
- case *reflect.MapValue:
- s.error("reflection support for maps incomplete")
-
- case *reflect.PtrValue:
- if v.IsNil() {
- return false
- }
- value = v.Elem()
-
- case *reflect.InterfaceValue:
- if v.IsNil() {
- return false
- }
- value = v.Elem()
-
- case *reflect.ChanValue:
- s.error("reflection support for chans incomplete")
-
- case *reflect.FuncValue:
- s.error("reflection support for funcs incomplete")
-
- default:
- s.error(fmt.Sprintf("error: * does not apply to `%s`", value.Type()))
- }
-
- default:
- // value is value of named field
- var field reflect.Value
- if sval, ok := value.(*reflect.StructValue); ok {
- field = sval.FieldByName(t.fieldName)
- if field == nil {
- // TODO consider just returning false in this case
- s.error(fmt.Sprintf("error: no field `%s` in `%s`", t.fieldName, value.Type()))
- }
- }
- value = field
- }
-
- // determine rule
- ruleName := t.ruleName
- if ruleName == "" {
- // no alternate rule name, value type determines rule
- ruleName = typename(value.Type())
- }
- fexpr = s.getFormat(ruleName)
-
- mark := s.save()
- if !s.eval(fexpr, value, index) {
- s.restore(mark)
- return false
- }
- return true
-
- case *group:
- // remember current indentation
- indentLen := s.indent.Len()
-
- // update current indentation
- mark := s.save()
- s.eval(t.indent, value, index)
- // if the indentation evaluates to nil, the state's output buffer
- // didn't change - either way it's ok to append the difference to
- // the current identation
- s.indent.Write(s.output.Bytes()[mark.outputLen:s.output.Len()])
- s.restore(mark)
-
- // format group body
- mark = s.save()
- b := true
- if !s.eval(t.body, value, index) {
- s.restore(mark)
- b = false
- }
-
- // reset indentation
- s.indent.Truncate(indentLen)
- return b
-
- case *option:
- // evaluate the body and append the result to the state's output
- // buffer unless the result is nil
- mark := s.save()
- if !s.eval(t.body, value, 0) { // TODO is 0 index correct?
- s.restore(mark)
- }
- return true // an option never evaluates to nil
-
- case *repetition:
- // evaluate the body and append the result to the state's output
- // buffer until a result is nil
- for i := 0; ; i++ {
- mark := s.save()
- // write separator, if any
- if i > 0 && t.separator != nil {
- // nil result from separator is ignored
- mark := s.save()
- if !s.eval(t.separator, value, i) {
- s.restore(mark)
- }
- }
- if !s.eval(t.body, value, i) {
- s.restore(mark)
- break
- }
- }
- return true // a repetition never evaluates to nil
-
- case *custom:
- // invoke the custom formatter to obtain the result
- mark := s.save()
- if !t.fun(s, value.Interface(), t.ruleName) {
- s.restore(mark)
- return false
- }
- return true
- }
-
- panic("unreachable")
- return false
-}
-
-
-// Eval formats each argument according to the format
-// f and returns the resulting []byte and os.Error. If
-// an error occurred, the []byte contains the partially
-// formatted result. An environment env may be passed
-// in which is available in custom formatters through
-// the state parameter.
-//
-func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
- if f == nil {
- return nil, os.NewError("format is nil")
- }
-
- errors := make(chan os.Error)
- s := newState(f, env, errors)
-
- go func() {
- for _, v := range args {
- fld := reflect.NewValue(v)
- if fld == nil {
- errors <- os.NewError("nil argument")
- return
- }
- mark := s.save()
- if !s.eval(s.getFormat(typename(fld.Type())), fld, 0) { // TODO is 0 index correct?
- s.restore(mark)
- }
- }
- errors <- nil // no errors
- }()
-
- err := <-errors
- return s.output.Bytes(), err
-}
-
-
-// ----------------------------------------------------------------------------
-// Convenience functions
-
-// Fprint formats each argument according to the format f
-// and writes to w. The result is the total number of bytes
-// written and an os.Error, if any.
-//
-func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int, os.Error) {
- data, err := f.Eval(env, args...)
- if err != nil {
- // TODO should we print partial result in case of error?
- return 0, err
- }
- return w.Write(data)
-}
-
-
-// Print formats each argument according to the format f
-// and writes to standard output. The result is the total
-// number of bytes written and an os.Error, if any.
-//
-func (f Format) Print(args ...interface{}) (int, os.Error) {
- return f.Fprint(os.Stdout, nil, args...)
-}
-
-
-// Sprint formats each argument according to the format f
-// and returns the resulting string. If an error occurs
-// during formatting, the result string contains the
-// partially formatted result followed by an error message.
-//
-func (f Format) Sprint(args ...interface{}) string {
- var buf bytes.Buffer
- _, err := f.Fprint(&buf, nil, args...)
- if err != nil {
- var i interface{} = args
- fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(i), err)
- }
- return buf.String()
-}
diff --git a/src/cmd/gofix/testdata/reflect.datafmt.go.out b/src/cmd/gofix/testdata/reflect.datafmt.go.out
deleted file mode 100644
index bd7f5fd31..000000000
--- a/src/cmd/gofix/testdata/reflect.datafmt.go.out
+++ /dev/null
@@ -1,731 +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.
-
-/* The datafmt package implements syntax-directed, type-driven formatting
- of arbitrary data structures. Formatting a data structure consists of
- two phases: first, a parser reads a format specification and builds a
- "compiled" format. Then, the format can be applied repeatedly to
- arbitrary values. Applying a format to a value evaluates to a []byte
- containing the formatted value bytes, or nil.
-
- A format specification is a set of package declarations and format rules:
-
- Format = [ Entry { ";" Entry } [ ";" ] ] .
- Entry = PackageDecl | FormatRule .
-
- (The syntax of a format specification is presented in the same EBNF
- notation as used in the Go language specification. The syntax of white
- space, comments, identifiers, and string literals is the same as in Go.)
-
- A package declaration binds a package name (such as 'ast') to a
- package import path (such as '"go/ast"'). Each package used (in
- a type name, see below) must be declared once before use.
-
- PackageDecl = PackageName ImportPath .
- PackageName = identifier .
- ImportPath = string .
-
- A format rule binds a rule name to a format expression. A rule name
- may be a type name or one of the special names 'default' or '/'.
- A type name may be the name of a predeclared type (for example, 'int',
- 'float32', etc.), the package-qualified name of a user-defined type
- (for example, 'ast.MapType'), or an identifier indicating the structure
- of unnamed composite types ('array', 'chan', 'func', 'interface', 'map',
- or 'ptr'). Each rule must have a unique name; rules can be declared in
- any order.
-
- FormatRule = RuleName "=" Expression .
- RuleName = TypeName | "default" | "/" .
- TypeName = [ PackageName "." ] identifier .
-
- To format a value, the value's type name is used to select the format rule
- (there is an override mechanism, see below). The format expression of the
- selected rule specifies how the value is formatted. Each format expression,
- when applied to a value, evaluates to a byte sequence or nil.
-
- In its most general form, a format expression is a list of alternatives,
- each of which is a sequence of operands:
-
- Expression = [ Sequence ] { "|" [ Sequence ] } .
- Sequence = Operand { Operand } .
-
- The formatted result produced by an expression is the result of the first
- alternative sequence that evaluates to a non-nil result; if there is no
- such alternative, the expression evaluates to nil. The result produced by
- an operand sequence is the concatenation of the results of its operands.
- If any operand in the sequence evaluates to nil, the entire sequence
- evaluates to nil.
-
- There are five kinds of operands:
-
- Operand = Literal | Field | Group | Option | Repetition .
-
- Literals evaluate to themselves, with two substitutions. First,
- %-formats expand in the manner of fmt.Printf, with the current value
- passed as the parameter. Second, the current indentation (see below)
- is inserted after every newline or form feed character.
-
- Literal = string .
-
- This table shows string literals applied to the value 42 and the
- corresponding formatted result:
-
- "foo" foo
- "%x" 2a
- "x = %d" x = 42
- "%#x = %d" 0x2a = 42
-
- A field operand is a field name optionally followed by an alternate
- rule name. The field name may be an identifier or one of the special
- names @ or *.
-
- Field = FieldName [ ":" RuleName ] .
- FieldName = identifier | "@" | "*" .
-
- If the field name is an identifier, the current value must be a struct,
- and there must be a field with that name in the struct. The same lookup
- rules apply as in the Go language (for instance, the name of an anonymous
- field is the unqualified type name). The field name denotes the field
- value in the struct. If the field is not found, formatting is aborted
- and an error message is returned. (TODO consider changing the semantics
- such that if a field is not found, it evaluates to nil).
-
- The special name '@' denotes the current value.
-
- The meaning of the special name '*' depends on the type of the current
- value:
-
- array, slice types array, slice element (inside {} only, see below)
- interfaces value stored in interface
- pointers value pointed to by pointer
-
- (Implementation restriction: channel, function and map types are not
- supported due to missing reflection support).
-
- Fields are evaluated as follows: If the field value is nil, or an array
- or slice element does not exist, the result is nil (see below for details
- on array/slice elements). If the value is not nil the field value is
- formatted (recursively) using the rule corresponding to its type name,
- or the alternate rule name, if given.
-
- The following example shows a complete format specification for a
- struct 'myPackage.Point'. Assume the package
-
- package myPackage // in directory myDir/myPackage
- type Point struct {
- name string;
- x, y int;
- }
-
- Applying the format specification
-
- myPackage "myDir/myPackage";
- int = "%d";
- hexInt = "0x%x";
- string = "---%s---";
- myPackage.Point = name "{" x ", " y:hexInt "}";
-
- to the value myPackage.Point{"foo", 3, 15} results in
-
- ---foo---{3, 0xf}
-
- Finally, an operand may be a grouped, optional, or repeated expression.
- A grouped expression ("group") groups a more complex expression (body)
- so that it can be used in place of a single operand:
-
- Group = "(" [ Indentation ">>" ] Body ")" .
- Indentation = Expression .
- Body = Expression .
-
- A group body may be prefixed by an indentation expression followed by '>>'.
- The indentation expression is applied to the current value like any other
- expression and the result, if not nil, is appended to the current indentation
- during the evaluation of the body (see also formatting state, below).
-
- An optional expression ("option") is enclosed in '[]' brackets.
-
- Option = "[" Body "]" .
-
- An option evaluates to its body, except that if the body evaluates to nil,
- the option expression evaluates to an empty []byte. Thus an option's purpose
- is to protect the expression containing the option from a nil operand.
-
- A repeated expression ("repetition") is enclosed in '{}' braces.
-
- Repetition = "{" Body [ "/" Separator ] "}" .
- Separator = Expression .
-
- A repeated expression is evaluated as follows: The body is evaluated
- repeatedly and its results are concatenated until the body evaluates
- to nil. The result of the repetition is the (possibly empty) concatenation,
- but it is never nil. An implicit index is supplied for the evaluation of
- the body: that index is used to address elements of arrays or slices. If
- the corresponding elements do not exist, the field denoting the element
- evaluates to nil (which in turn may terminate the repetition).
-
- The body of a repetition may be followed by a '/' and a "separator"
- expression. If the separator is present, it is invoked between repetitions
- of the body.
-
- The following example shows a complete format specification for formatting
- a slice of unnamed type. Applying the specification
-
- int = "%b";
- array = { * / ", " }; // array is the type name for an unnamed slice
-
- to the value '[]int{2, 3, 5, 7}' results in
-
- 10, 11, 101, 111
-
- Default rule: If a format rule named 'default' is present, it is used for
- formatting a value if no other rule was found. A common default rule is
-
- default = "%v"
-
- to provide default formatting for basic types without having to specify
- a specific rule for each basic type.
-
- Global separator rule: If a format rule named '/' is present, it is
- invoked with the current value between literals. If the separator
- expression evaluates to nil, it is ignored.
-
- For instance, a global separator rule may be used to punctuate a sequence
- of values with commas. The rules:
-
- default = "%v";
- / = ", ";
-
- will format an argument list by printing each one in its default format,
- separated by a comma and a space.
-*/
-package datafmt
-
-import (
- "bytes"
- "fmt"
- "go/token"
- "io"
- "os"
- "reflect"
- "runtime"
-)
-
-
-// ----------------------------------------------------------------------------
-// Format representation
-
-// Custom formatters implement the Formatter function type.
-// A formatter is invoked with the current formatting state, the
-// value to format, and the rule name under which the formatter
-// was installed (the same formatter function may be installed
-// under different names). The formatter may access the current state
-// to guide formatting and use State.Write to append to the state's
-// output.
-//
-// A formatter must return a boolean value indicating if it evaluated
-// to a non-nil value (true), or a nil value (false).
-//
-type Formatter func(state *State, value interface{}, ruleName string) bool
-
-
-// A FormatterMap is a set of custom formatters.
-// It maps a rule name to a formatter function.
-//
-type FormatterMap map[string]Formatter
-
-
-// A parsed format expression is built from the following nodes.
-//
-type (
- expr interface{}
-
- alternatives []expr // x | y | z
-
- sequence []expr // x y z
-
- literal [][]byte // a list of string segments, possibly starting with '%'
-
- field struct {
- fieldName string // including "@", "*"
- ruleName string // "" if no rule name specified
- }
-
- group struct {
- indent, body expr // (indent >> body)
- }
-
- option struct {
- body expr // [body]
- }
-
- repetition struct {
- body, separator expr // {body / separator}
- }
-
- custom struct {
- ruleName string
- fun Formatter
- }
-)
-
-
-// A Format is the result of parsing a format specification.
-// The format may be applied repeatedly to format values.
-//
-type Format map[string]expr
-
-
-// ----------------------------------------------------------------------------
-// Formatting
-
-// An application-specific environment may be provided to Format.Apply;
-// the environment is available inside custom formatters via State.Env().
-// Environments must implement copying; the Copy method must return an
-// complete copy of the receiver. This is necessary so that the formatter
-// can save and restore an environment (in case of an absent expression).
-//
-// If the Environment doesn't change during formatting (this is under
-// control of the custom formatters), the Copy function can simply return
-// the receiver, and thus can be very light-weight.
-//
-type Environment interface {
- Copy() Environment
-}
-
-
-// State represents the current formatting state.
-// It is provided as argument to custom formatters.
-//
-type State struct {
- fmt Format // format in use
- env Environment // user-supplied environment
- errors chan os.Error // not chan *Error (errors <- nil would be wrong!)
- hasOutput bool // true after the first literal has been written
- indent bytes.Buffer // current indentation
- output bytes.Buffer // format output
- linePos token.Position // position of line beginning (Column == 0)
- default_ expr // possibly nil
- separator expr // possibly nil
-}
-
-
-func newState(fmt Format, env Environment, errors chan os.Error) *State {
- s := new(State)
- s.fmt = fmt
- s.env = env
- s.errors = errors
- s.linePos = token.Position{Line: 1}
-
- // if we have a default rule, cache it's expression for fast access
- if x, found := fmt["default"]; found {
- s.default_ = x
- }
-
- // if we have a global separator rule, cache it's expression for fast access
- if x, found := fmt["/"]; found {
- s.separator = x
- }
-
- return s
-}
-
-
-// Env returns the environment passed to Format.Apply.
-func (s *State) Env() interface{} { return s.env }
-
-
-// LinePos returns the position of the current line beginning
-// in the state's output buffer. Line numbers start at 1.
-//
-func (s *State) LinePos() token.Position { return s.linePos }
-
-
-// Pos returns the position of the next byte to be written to the
-// output buffer. Line numbers start at 1.
-//
-func (s *State) Pos() token.Position {
- offs := s.output.Len()
- return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs}
-}
-
-
-// Write writes data to the output buffer, inserting the indentation
-// string after each newline or form feed character. It cannot return an error.
-//
-func (s *State) Write(data []byte) (int, os.Error) {
- n := 0
- i0 := 0
- for i, ch := range data {
- if ch == '\n' || ch == '\f' {
- // write text segment and indentation
- n1, _ := s.output.Write(data[i0 : i+1])
- n2, _ := s.output.Write(s.indent.Bytes())
- n += n1 + n2
- i0 = i + 1
- s.linePos.Offset = s.output.Len()
- s.linePos.Line++
- }
- }
- n3, _ := s.output.Write(data[i0:])
- return n + n3, nil
-}
-
-
-type checkpoint struct {
- env Environment
- hasOutput bool
- outputLen int
- linePos token.Position
-}
-
-
-func (s *State) save() checkpoint {
- saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
- if s.env != nil {
- saved.env = s.env.Copy()
- }
- return saved
-}
-
-
-func (s *State) restore(m checkpoint) {
- s.env = m.env
- s.output.Truncate(m.outputLen)
-}
-
-
-func (s *State) error(msg string) {
- s.errors <- os.NewError(msg)
- runtime.Goexit()
-}
-
-
-// TODO At the moment, unnamed types are simply mapped to the default
-// names below. For instance, all unnamed arrays are mapped to
-// 'array' which is not really sufficient. Eventually one may want
-// to be able to specify rules for say an unnamed slice of T.
-//
-
-func typename(typ reflect.Type) string {
- switch typ.Kind() {
- case reflect.Array:
- return "array"
- case reflect.Slice:
- return "array"
- case reflect.Chan:
- return "chan"
- case reflect.Func:
- return "func"
- case reflect.Interface:
- return "interface"
- case reflect.Map:
- return "map"
- case reflect.Ptr:
- return "ptr"
- }
- return typ.String()
-}
-
-func (s *State) getFormat(name string) expr {
- if fexpr, found := s.fmt[name]; found {
- return fexpr
- }
-
- if s.default_ != nil {
- return s.default_
- }
-
- s.error(fmt.Sprintf("no format rule for type: '%s'", name))
- return nil
-}
-
-
-// eval applies a format expression fexpr to a value. If the expression
-// evaluates internally to a non-nil []byte, that slice is appended to
-// the state's output buffer and eval returns true. Otherwise, eval
-// returns false and the state remains unchanged.
-//
-func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
- // an empty format expression always evaluates
- // to a non-nil (but empty) []byte
- if fexpr == nil {
- return true
- }
-
- switch t := fexpr.(type) {
- case alternatives:
- // append the result of the first alternative that evaluates to
- // a non-nil []byte to the state's output
- mark := s.save()
- for _, x := range t {
- if s.eval(x, value, index) {
- return true
- }
- s.restore(mark)
- }
- return false
-
- case sequence:
- // append the result of all operands to the state's output
- // unless a nil result is encountered
- mark := s.save()
- for _, x := range t {
- if !s.eval(x, value, index) {
- s.restore(mark)
- return false
- }
- }
- return true
-
- case literal:
- // write separator, if any
- if s.hasOutput {
- // not the first literal
- if s.separator != nil {
- sep := s.separator // save current separator
- s.separator = nil // and disable it (avoid recursion)
- mark := s.save()
- if !s.eval(sep, value, index) {
- s.restore(mark)
- }
- s.separator = sep // enable it again
- }
- }
- s.hasOutput = true
- // write literal segments
- for _, lit := range t {
- if len(lit) > 1 && lit[0] == '%' {
- // segment contains a %-format at the beginning
- if lit[1] == '%' {
- // "%%" is printed as a single "%"
- s.Write(lit[1:])
- } else {
- // use s instead of s.output to get indentation right
- fmt.Fprintf(s, string(lit), value.Interface())
- }
- } else {
- // segment contains no %-formats
- s.Write(lit)
- }
- }
- return true // a literal never evaluates to nil
-
- case *field:
- // determine field value
- switch t.fieldName {
- case "@":
- // field value is current value
-
- case "*":
- // indirection: operation is type-specific
- switch v := value; v.Kind() {
- case reflect.Array:
- if v.Len() <= index {
- return false
- }
- value = v.Index(index)
-
- case reflect.Slice:
- if v.IsNil() || v.Len() <= index {
- return false
- }
- value = v.Index(index)
-
- case reflect.Map:
- s.error("reflection support for maps incomplete")
-
- case reflect.Ptr:
- if v.IsNil() {
- return false
- }
- value = v.Elem()
-
- case reflect.Interface:
- if v.IsNil() {
- return false
- }
- value = v.Elem()
-
- case reflect.Chan:
- s.error("reflection support for chans incomplete")
-
- case reflect.Func:
- s.error("reflection support for funcs incomplete")
-
- default:
- s.error(fmt.Sprintf("error: * does not apply to `%s`", value.Type()))
- }
-
- default:
- // value is value of named field
- var field reflect.Value
- if sval := value; sval.Kind() == reflect.Struct {
- field = sval.FieldByName(t.fieldName)
- if !field.IsValid() {
- // TODO consider just returning false in this case
- s.error(fmt.Sprintf("error: no field `%s` in `%s`", t.fieldName, value.Type()))
- }
- }
- value = field
- }
-
- // determine rule
- ruleName := t.ruleName
- if ruleName == "" {
- // no alternate rule name, value type determines rule
- ruleName = typename(value.Type())
- }
- fexpr = s.getFormat(ruleName)
-
- mark := s.save()
- if !s.eval(fexpr, value, index) {
- s.restore(mark)
- return false
- }
- return true
-
- case *group:
- // remember current indentation
- indentLen := s.indent.Len()
-
- // update current indentation
- mark := s.save()
- s.eval(t.indent, value, index)
- // if the indentation evaluates to nil, the state's output buffer
- // didn't change - either way it's ok to append the difference to
- // the current identation
- s.indent.Write(s.output.Bytes()[mark.outputLen:s.output.Len()])
- s.restore(mark)
-
- // format group body
- mark = s.save()
- b := true
- if !s.eval(t.body, value, index) {
- s.restore(mark)
- b = false
- }
-
- // reset indentation
- s.indent.Truncate(indentLen)
- return b
-
- case *option:
- // evaluate the body and append the result to the state's output
- // buffer unless the result is nil
- mark := s.save()
- if !s.eval(t.body, value, 0) { // TODO is 0 index correct?
- s.restore(mark)
- }
- return true // an option never evaluates to nil
-
- case *repetition:
- // evaluate the body and append the result to the state's output
- // buffer until a result is nil
- for i := 0; ; i++ {
- mark := s.save()
- // write separator, if any
- if i > 0 && t.separator != nil {
- // nil result from separator is ignored
- mark := s.save()
- if !s.eval(t.separator, value, i) {
- s.restore(mark)
- }
- }
- if !s.eval(t.body, value, i) {
- s.restore(mark)
- break
- }
- }
- return true // a repetition never evaluates to nil
-
- case *custom:
- // invoke the custom formatter to obtain the result
- mark := s.save()
- if !t.fun(s, value.Interface(), t.ruleName) {
- s.restore(mark)
- return false
- }
- return true
- }
-
- panic("unreachable")
- return false
-}
-
-
-// Eval formats each argument according to the format
-// f and returns the resulting []byte and os.Error. If
-// an error occurred, the []byte contains the partially
-// formatted result. An environment env may be passed
-// in which is available in custom formatters through
-// the state parameter.
-//
-func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
- if f == nil {
- return nil, os.NewError("format is nil")
- }
-
- errors := make(chan os.Error)
- s := newState(f, env, errors)
-
- go func() {
- for _, v := range args {
- fld := reflect.ValueOf(v)
- if !fld.IsValid() {
- errors <- os.NewError("nil argument")
- return
- }
- mark := s.save()
- if !s.eval(s.getFormat(typename(fld.Type())), fld, 0) { // TODO is 0 index correct?
- s.restore(mark)
- }
- }
- errors <- nil // no errors
- }()
-
- err := <-errors
- return s.output.Bytes(), err
-}
-
-
-// ----------------------------------------------------------------------------
-// Convenience functions
-
-// Fprint formats each argument according to the format f
-// and writes to w. The result is the total number of bytes
-// written and an os.Error, if any.
-//
-func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int, os.Error) {
- data, err := f.Eval(env, args...)
- if err != nil {
- // TODO should we print partial result in case of error?
- return 0, err
- }
- return w.Write(data)
-}
-
-
-// Print formats each argument according to the format f
-// and writes to standard output. The result is the total
-// number of bytes written and an os.Error, if any.
-//
-func (f Format) Print(args ...interface{}) (int, os.Error) {
- return f.Fprint(os.Stdout, nil, args...)
-}
-
-
-// Sprint formats each argument according to the format f
-// and returns the resulting string. If an error occurs
-// during formatting, the result string contains the
-// partially formatted result followed by an error message.
-//
-func (f Format) Sprint(args ...interface{}) string {
- var buf bytes.Buffer
- _, err := f.Fprint(&buf, nil, args...)
- if err != nil {
- var i interface{} = args
- fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(i), err)
- }
- return buf.String()
-}
diff --git a/src/cmd/gofix/testdata/reflect.decode.go.in b/src/cmd/gofix/testdata/reflect.decode.go.in
deleted file mode 100644
index 501230c0c..000000000
--- a/src/cmd/gofix/testdata/reflect.decode.go.in
+++ /dev/null
@@ -1,907 +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.
-
-// Represents JSON data structure using native Go types: booleans, floats,
-// strings, arrays, and maps.
-
-package json
-
-import (
- "container/vector"
- "encoding/base64"
- "os"
- "reflect"
- "runtime"
- "strconv"
- "strings"
- "unicode"
- "utf16"
- "utf8"
-)
-
-// Unmarshal parses the JSON-encoded data and stores the result
-// in the value pointed to by v.
-//
-// Unmarshal traverses the value v recursively.
-// If an encountered value implements the Unmarshaler interface,
-// Unmarshal calls its UnmarshalJSON method with a well-formed
-// JSON encoding.
-//
-// Otherwise, Unmarshal uses the inverse of the encodings that
-// Marshal uses, allocating maps, slices, and pointers as necessary,
-// with the following additional rules:
-//
-// To unmarshal a JSON value into a nil interface value, the
-// type stored in the interface value is one of:
-//
-// bool, for JSON booleans
-// float64, for JSON numbers
-// string, for JSON strings
-// []interface{}, for JSON arrays
-// map[string]interface{}, for JSON objects
-// nil for JSON null
-//
-// If a JSON value is not appropriate for a given target type,
-// or if a JSON number overflows the target type, Unmarshal
-// skips that field and completes the unmarshalling as best it can.
-// If no more serious errors are encountered, Unmarshal returns
-// an UnmarshalTypeError describing the earliest such error.
-//
-func Unmarshal(data []byte, v interface{}) os.Error {
- d := new(decodeState).init(data)
-
- // Quick check for well-formedness.
- // Avoids filling out half a data structure
- // before discovering a JSON syntax error.
- err := checkValid(data, &d.scan)
- if err != nil {
- return err
- }
-
- return d.unmarshal(v)
-}
-
-// Unmarshaler is the interface implemented by objects
-// that can unmarshal a JSON description of themselves.
-// The input can be assumed to be a valid JSON object
-// encoding. UnmarshalJSON must copy the JSON data
-// if it wishes to retain the data after returning.
-type Unmarshaler interface {
- UnmarshalJSON([]byte) os.Error
-}
-
-
-// An UnmarshalTypeError describes a JSON value that was
-// not appropriate for a value of a specific Go type.
-type UnmarshalTypeError struct {
- Value string // description of JSON value - "bool", "array", "number -5"
- Type reflect.Type // type of Go value it could not be assigned to
-}
-
-func (e *UnmarshalTypeError) String() string {
- return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
-}
-
-// An UnmarshalFieldError describes a JSON object key that
-// led to an unexported (and therefore unwritable) struct field.
-type UnmarshalFieldError struct {
- Key string
- Type *reflect.StructType
- Field reflect.StructField
-}
-
-func (e *UnmarshalFieldError) String() string {
- return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
-}
-
-// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
-// (The argument to Unmarshal must be a non-nil pointer.)
-type InvalidUnmarshalError struct {
- Type reflect.Type
-}
-
-func (e *InvalidUnmarshalError) String() string {
- if e.Type == nil {
- return "json: Unmarshal(nil)"
- }
-
- if _, ok := e.Type.(*reflect.PtrType); !ok {
- return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
- }
- return "json: Unmarshal(nil " + e.Type.String() + ")"
-}
-
-func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
- defer func() {
- if r := recover(); r != nil {
- if _, ok := r.(runtime.Error); ok {
- panic(r)
- }
- err = r.(os.Error)
- }
- }()
-
- rv := reflect.NewValue(v)
- pv, ok := rv.(*reflect.PtrValue)
- if !ok || pv.IsNil() {
- return &InvalidUnmarshalError{reflect.Typeof(v)}
- }
-
- d.scan.reset()
- // We decode rv not pv.Elem because the Unmarshaler interface
- // test must be applied at the top level of the value.
- d.value(rv)
- return d.savedError
-}
-
-// decodeState represents the state while decoding a JSON value.
-type decodeState struct {
- data []byte
- off int // read offset in data
- scan scanner
- nextscan scanner // for calls to nextValue
- savedError os.Error
-}
-
-// errPhase is used for errors that should not happen unless
-// there is a bug in the JSON decoder or something is editing
-// the data slice while the decoder executes.
-var errPhase = os.NewError("JSON decoder out of sync - data changing underfoot?")
-
-func (d *decodeState) init(data []byte) *decodeState {
- d.data = data
- d.off = 0
- d.savedError = nil
- return d
-}
-
-// error aborts the decoding by panicking with err.
-func (d *decodeState) error(err os.Error) {
- panic(err)
-}
-
-// saveError saves the first err it is called with,
-// for reporting at the end of the unmarshal.
-func (d *decodeState) saveError(err os.Error) {
- if d.savedError == nil {
- d.savedError = err
- }
-}
-
-// next cuts off and returns the next full JSON value in d.data[d.off:].
-// The next value is known to be an object or array, not a literal.
-func (d *decodeState) next() []byte {
- c := d.data[d.off]
- item, rest, err := nextValue(d.data[d.off:], &d.nextscan)
- if err != nil {
- d.error(err)
- }
- d.off = len(d.data) - len(rest)
-
- // Our scanner has seen the opening brace/bracket
- // and thinks we're still in the middle of the object.
- // invent a closing brace/bracket to get it out.
- if c == '{' {
- d.scan.step(&d.scan, '}')
- } else {
- d.scan.step(&d.scan, ']')
- }
-
- return item
-}
-
-// scanWhile processes bytes in d.data[d.off:] until it
-// receives a scan code not equal to op.
-// It updates d.off and returns the new scan code.
-func (d *decodeState) scanWhile(op int) int {
- var newOp int
- for {
- if d.off >= len(d.data) {
- newOp = d.scan.eof()
- d.off = len(d.data) + 1 // mark processed EOF with len+1
- } else {
- c := int(d.data[d.off])
- d.off++
- newOp = d.scan.step(&d.scan, c)
- }
- if newOp != op {
- break
- }
- }
- return newOp
-}
-
-// value decodes a JSON value from d.data[d.off:] into the value.
-// it updates d.off to point past the decoded value.
-func (d *decodeState) value(v reflect.Value) {
- if v == nil {
- _, rest, err := nextValue(d.data[d.off:], &d.nextscan)
- if err != nil {
- d.error(err)
- }
- d.off = len(d.data) - len(rest)
-
- // d.scan thinks we're still at the beginning of the item.
- // Feed in an empty string - the shortest, simplest value -
- // so that it knows we got to the end of the value.
- if d.scan.step == stateRedo {
- panic("redo")
- }
- d.scan.step(&d.scan, '"')
- d.scan.step(&d.scan, '"')
- return
- }
-
- switch op := d.scanWhile(scanSkipSpace); op {
- default:
- d.error(errPhase)
-
- case scanBeginArray:
- d.array(v)
-
- case scanBeginObject:
- d.object(v)
-
- case scanBeginLiteral:
- d.literal(v)
- }
-}
-
-// indirect walks down v allocating pointers as needed,
-// until it gets to a non-pointer.
-// if it encounters an Unmarshaler, indirect stops and returns that.
-// if wantptr is true, indirect stops at the last pointer.
-func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
- for {
- var isUnmarshaler bool
- if v.Type().NumMethod() > 0 {
- // Remember that this is an unmarshaler,
- // but wait to return it until after allocating
- // the pointer (if necessary).
- _, isUnmarshaler = v.Interface().(Unmarshaler)
- }
-
- if iv, ok := v.(*reflect.InterfaceValue); ok && !iv.IsNil() {
- v = iv.Elem()
- continue
- }
- pv, ok := v.(*reflect.PtrValue)
- if !ok {
- break
- }
- _, isptrptr := pv.Elem().(*reflect.PtrValue)
- if !isptrptr && wantptr && !isUnmarshaler {
- return nil, pv
- }
- if pv.IsNil() {
- pv.PointTo(reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()))
- }
- if isUnmarshaler {
- // Using v.Interface().(Unmarshaler)
- // here means that we have to use a pointer
- // as the struct field. We cannot use a value inside
- // a pointer to a struct, because in that case
- // v.Interface() is the value (x.f) not the pointer (&x.f).
- // This is an unfortunate consequence of reflect.
- // An alternative would be to look up the
- // UnmarshalJSON method and return a FuncValue.
- return v.Interface().(Unmarshaler), nil
- }
- v = pv.Elem()
- }
- return nil, v
-}
-
-// array consumes an array from d.data[d.off-1:], decoding into the value v.
-// the first byte of the array ('[') has been read already.
-func (d *decodeState) array(v reflect.Value) {
- // Check for unmarshaler.
- unmarshaler, pv := d.indirect(v, false)
- if unmarshaler != nil {
- d.off--
- err := unmarshaler.UnmarshalJSON(d.next())
- if err != nil {
- d.error(err)
- }
- return
- }
- v = pv
-
- // Decoding into nil interface? Switch to non-reflect code.
- iv, ok := v.(*reflect.InterfaceValue)
- if ok {
- iv.Set(reflect.NewValue(d.arrayInterface()))
- return
- }
-
- // Check type of target.
- av, ok := v.(reflect.ArrayOrSliceValue)
- if !ok {
- d.saveError(&UnmarshalTypeError{"array", v.Type()})
- d.off--
- d.next()
- return
- }
-
- sv, _ := v.(*reflect.SliceValue)
-
- i := 0
- for {
- // Look ahead for ] - can only happen on first iteration.
- op := d.scanWhile(scanSkipSpace)
- if op == scanEndArray {
- break
- }
-
- // Back up so d.value can have the byte we just read.
- d.off--
- d.scan.undo(op)
-
- // Get element of array, growing if necessary.
- if i >= av.Cap() && sv != nil {
- newcap := sv.Cap() + sv.Cap()/2
- if newcap < 4 {
- newcap = 4
- }
- newv := reflect.MakeSlice(sv.Type().(*reflect.SliceType), sv.Len(), newcap)
- reflect.Copy(newv, sv)
- sv.Set(newv)
- }
- if i >= av.Len() && sv != nil {
- // Must be slice; gave up on array during i >= av.Cap().
- sv.SetLen(i + 1)
- }
-
- // Decode into element.
- if i < av.Len() {
- d.value(av.Elem(i))
- } else {
- // Ran out of fixed array: skip.
- d.value(nil)
- }
- i++
-
- // Next token must be , or ].
- op = d.scanWhile(scanSkipSpace)
- if op == scanEndArray {
- break
- }
- if op != scanArrayValue {
- d.error(errPhase)
- }
- }
- if i < av.Len() {
- if sv == nil {
- // Array. Zero the rest.
- z := reflect.MakeZero(av.Type().(*reflect.ArrayType).Elem())
- for ; i < av.Len(); i++ {
- av.Elem(i).SetValue(z)
- }
- } else {
- sv.SetLen(i)
- }
- }
-}
-
-// matchName returns true if key should be written to a field named name.
-func matchName(key, name string) bool {
- return strings.ToLower(key) == strings.ToLower(name)
-}
-
-// object consumes an object from d.data[d.off-1:], decoding into the value v.
-// the first byte of the object ('{') has been read already.
-func (d *decodeState) object(v reflect.Value) {
- // Check for unmarshaler.
- unmarshaler, pv := d.indirect(v, false)
- if unmarshaler != nil {
- d.off--
- err := unmarshaler.UnmarshalJSON(d.next())
- if err != nil {
- d.error(err)
- }
- return
- }
- v = pv
-
- // Decoding into nil interface? Switch to non-reflect code.
- iv, ok := v.(*reflect.InterfaceValue)
- if ok {
- iv.Set(reflect.NewValue(d.objectInterface()))
- return
- }
-
- // Check type of target: struct or map[string]T
- var (
- mv *reflect.MapValue
- sv *reflect.StructValue
- )
- switch v := v.(type) {
- case *reflect.MapValue:
- // map must have string type
- t := v.Type().(*reflect.MapType)
- if t.Key() != reflect.Typeof("") {
- d.saveError(&UnmarshalTypeError{"object", v.Type()})
- break
- }
- mv = v
- if mv.IsNil() {
- mv.SetValue(reflect.MakeMap(t))
- }
- case *reflect.StructValue:
- sv = v
- default:
- d.saveError(&UnmarshalTypeError{"object", v.Type()})
- }
-
- if mv == nil && sv == nil {
- d.off--
- d.next() // skip over { } in input
- return
- }
-
- for {
- // Read opening " of string key or closing }.
- op := d.scanWhile(scanSkipSpace)
- if op == scanEndObject {
- // closing } - can only happen on first iteration.
- break
- }
- if op != scanBeginLiteral {
- d.error(errPhase)
- }
-
- // Read string key.
- start := d.off - 1
- op = d.scanWhile(scanContinue)
- item := d.data[start : d.off-1]
- key, ok := unquote(item)
- if !ok {
- d.error(errPhase)
- }
-
- // Figure out field corresponding to key.
- var subv reflect.Value
- if mv != nil {
- subv = reflect.MakeZero(mv.Type().(*reflect.MapType).Elem())
- } else {
- var f reflect.StructField
- var ok bool
- st := sv.Type().(*reflect.StructType)
- // First try for field with that tag.
- if isValidTag(key) {
- for i := 0; i < sv.NumField(); i++ {
- f = st.Field(i)
- if f.Tag == key {
- ok = true
- break
- }
- }
- }
- if !ok {
- // Second, exact match.
- f, ok = st.FieldByName(key)
- }
- if !ok {
- // Third, case-insensitive match.
- f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
- }
-
- // Extract value; name must be exported.
- if ok {
- if f.PkgPath != "" {
- d.saveError(&UnmarshalFieldError{key, st, f})
- } else {
- subv = sv.FieldByIndex(f.Index)
- }
- }
- }
-
- // Read : before value.
- if op == scanSkipSpace {
- op = d.scanWhile(scanSkipSpace)
- }
- if op != scanObjectKey {
- d.error(errPhase)
- }
-
- // Read value.
- d.value(subv)
-
- // Write value back to map;
- // if using struct, subv points into struct already.
- if mv != nil {
- mv.SetElem(reflect.NewValue(key), subv)
- }
-
- // Next token must be , or }.
- op = d.scanWhile(scanSkipSpace)
- if op == scanEndObject {
- break
- }
- if op != scanObjectValue {
- d.error(errPhase)
- }
- }
-}
-
-// literal consumes a literal from d.data[d.off-1:], decoding into the value v.
-// The first byte of the literal has been read already
-// (that's how the caller knows it's a literal).
-func (d *decodeState) literal(v reflect.Value) {
- // All bytes inside literal return scanContinue op code.
- start := d.off - 1
- op := d.scanWhile(scanContinue)
-
- // Scan read one byte too far; back up.
- d.off--
- d.scan.undo(op)
- item := d.data[start:d.off]
-
- // Check for unmarshaler.
- wantptr := item[0] == 'n' // null
- unmarshaler, pv := d.indirect(v, wantptr)
- if unmarshaler != nil {
- err := unmarshaler.UnmarshalJSON(item)
- if err != nil {
- d.error(err)
- }
- return
- }
- v = pv
-
- switch c := item[0]; c {
- case 'n': // null
- switch v.(type) {
- default:
- d.saveError(&UnmarshalTypeError{"null", v.Type()})
- case *reflect.InterfaceValue, *reflect.PtrValue, *reflect.MapValue:
- v.SetValue(nil)
- }
-
- case 't', 'f': // true, false
- value := c == 't'
- switch v := v.(type) {
- default:
- d.saveError(&UnmarshalTypeError{"bool", v.Type()})
- case *reflect.BoolValue:
- v.Set(value)
- case *reflect.InterfaceValue:
- v.Set(reflect.NewValue(value))
- }
-
- case '"': // string
- s, ok := unquoteBytes(item)
- if !ok {
- d.error(errPhase)
- }
- switch v := v.(type) {
- default:
- d.saveError(&UnmarshalTypeError{"string", v.Type()})
- case *reflect.SliceValue:
- if v.Type() != byteSliceType {
- d.saveError(&UnmarshalTypeError{"string", v.Type()})
- break
- }
- b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
- n, err := base64.StdEncoding.Decode(b, s)
- if err != nil {
- d.saveError(err)
- break
- }
- v.Set(reflect.NewValue(b[0:n]).(*reflect.SliceValue))
- case *reflect.StringValue:
- v.Set(string(s))
- case *reflect.InterfaceValue:
- v.Set(reflect.NewValue(string(s)))
- }
-
- default: // number
- if c != '-' && (c < '0' || c > '9') {
- d.error(errPhase)
- }
- s := string(item)
- switch v := v.(type) {
- default:
- d.error(&UnmarshalTypeError{"number", v.Type()})
- case *reflect.InterfaceValue:
- n, err := strconv.Atof64(s)
- if err != nil {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
- break
- }
- v.Set(reflect.NewValue(n))
-
- case *reflect.IntValue:
- n, err := strconv.Atoi64(s)
- if err != nil || v.Overflow(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
- break
- }
- v.Set(n)
-
- case *reflect.UintValue:
- n, err := strconv.Atoui64(s)
- if err != nil || v.Overflow(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
- break
- }
- v.Set(n)
-
- case *reflect.FloatValue:
- n, err := strconv.AtofN(s, v.Type().Bits())
- if err != nil || v.Overflow(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
- break
- }
- v.Set(n)
- }
- }
-}
-
-// The xxxInterface routines build up a value to be stored
-// in an empty interface. They are not strictly necessary,
-// but they avoid the weight of reflection in this common case.
-
-// valueInterface is like value but returns interface{}
-func (d *decodeState) valueInterface() interface{} {
- switch d.scanWhile(scanSkipSpace) {
- default:
- d.error(errPhase)
- case scanBeginArray:
- return d.arrayInterface()
- case scanBeginObject:
- return d.objectInterface()
- case scanBeginLiteral:
- return d.literalInterface()
- }
- panic("unreachable")
-}
-
-// arrayInterface is like array but returns []interface{}.
-func (d *decodeState) arrayInterface() []interface{} {
- var v vector.Vector
- for {
- // Look ahead for ] - can only happen on first iteration.
- op := d.scanWhile(scanSkipSpace)
- if op == scanEndArray {
- break
- }
-
- // Back up so d.value can have the byte we just read.
- d.off--
- d.scan.undo(op)
-
- v.Push(d.valueInterface())
-
- // Next token must be , or ].
- op = d.scanWhile(scanSkipSpace)
- if op == scanEndArray {
- break
- }
- if op != scanArrayValue {
- d.error(errPhase)
- }
- }
- return v
-}
-
-// objectInterface is like object but returns map[string]interface{}.
-func (d *decodeState) objectInterface() map[string]interface{} {
- m := make(map[string]interface{})
- for {
- // Read opening " of string key or closing }.
- op := d.scanWhile(scanSkipSpace)
- if op == scanEndObject {
- // closing } - can only happen on first iteration.
- break
- }
- if op != scanBeginLiteral {
- d.error(errPhase)
- }
-
- // Read string key.
- start := d.off - 1
- op = d.scanWhile(scanContinue)
- item := d.data[start : d.off-1]
- key, ok := unquote(item)
- if !ok {
- d.error(errPhase)
- }
-
- // Read : before value.
- if op == scanSkipSpace {
- op = d.scanWhile(scanSkipSpace)
- }
- if op != scanObjectKey {
- d.error(errPhase)
- }
-
- // Read value.
- m[key] = d.valueInterface()
-
- // Next token must be , or }.
- op = d.scanWhile(scanSkipSpace)
- if op == scanEndObject {
- break
- }
- if op != scanObjectValue {
- d.error(errPhase)
- }
- }
- return m
-}
-
-
-// literalInterface is like literal but returns an interface value.
-func (d *decodeState) literalInterface() interface{} {
- // All bytes inside literal return scanContinue op code.
- start := d.off - 1
- op := d.scanWhile(scanContinue)
-
- // Scan read one byte too far; back up.
- d.off--
- d.scan.undo(op)
- item := d.data[start:d.off]
-
- switch c := item[0]; c {
- case 'n': // null
- return nil
-
- case 't', 'f': // true, false
- return c == 't'
-
- case '"': // string
- s, ok := unquote(item)
- if !ok {
- d.error(errPhase)
- }
- return s
-
- default: // number
- if c != '-' && (c < '0' || c > '9') {
- d.error(errPhase)
- }
- n, err := strconv.Atof64(string(item))
- if err != nil {
- d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.Typeof(0.0)})
- }
- return n
- }
- panic("unreachable")
-}
-
-// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
-// or it returns -1.
-func getu4(s []byte) int {
- if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
- return -1
- }
- rune, err := strconv.Btoui64(string(s[2:6]), 16)
- if err != nil {
- return -1
- }
- return int(rune)
-}
-
-// unquote converts a quoted JSON string literal s into an actual string t.
-// The rules are different than for Go, so cannot use strconv.Unquote.
-func unquote(s []byte) (t string, ok bool) {
- s, ok = unquoteBytes(s)
- t = string(s)
- return
-}
-
-func unquoteBytes(s []byte) (t []byte, ok bool) {
- if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
- return
- }
- s = s[1 : len(s)-1]
-
- // Check for unusual characters. If there are none,
- // then no unquoting is needed, so return a slice of the
- // original bytes.
- r := 0
- for r < len(s) {
- c := s[r]
- if c == '\\' || c == '"' || c < ' ' {
- break
- }
- if c < utf8.RuneSelf {
- r++
- continue
- }
- rune, size := utf8.DecodeRune(s[r:])
- if rune == utf8.RuneError && size == 1 {
- break
- }
- r += size
- }
- if r == len(s) {
- return s, true
- }
-
- b := make([]byte, len(s)+2*utf8.UTFMax)
- w := copy(b, s[0:r])
- for r < len(s) {
- // Out of room? Can only happen if s is full of
- // malformed UTF-8 and we're replacing each
- // byte with RuneError.
- if w >= len(b)-2*utf8.UTFMax {
- nb := make([]byte, (len(b)+utf8.UTFMax)*2)
- copy(nb, b[0:w])
- b = nb
- }
- switch c := s[r]; {
- case c == '\\':
- r++
- if r >= len(s) {
- return
- }
- switch s[r] {
- default:
- return
- case '"', '\\', '/', '\'':
- b[w] = s[r]
- r++
- w++
- case 'b':
- b[w] = '\b'
- r++
- w++
- case 'f':
- b[w] = '\f'
- r++
- w++
- case 'n':
- b[w] = '\n'
- r++
- w++
- case 'r':
- b[w] = '\r'
- r++
- w++
- case 't':
- b[w] = '\t'
- r++
- w++
- case 'u':
- r--
- rune := getu4(s[r:])
- if rune < 0 {
- return
- }
- r += 6
- if utf16.IsSurrogate(rune) {
- rune1 := getu4(s[r:])
- if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
- // A valid pair; consume.
- r += 6
- w += utf8.EncodeRune(b[w:], dec)
- break
- }
- // Invalid surrogate; fall back to replacement rune.
- rune = unicode.ReplacementChar
- }
- w += utf8.EncodeRune(b[w:], rune)
- }
-
- // Quote, control characters are invalid.
- case c == '"', c < ' ':
- return
-
- // ASCII
- case c < utf8.RuneSelf:
- b[w] = c
- r++
- w++
-
- // Coerce to well-formed UTF-8.
- default:
- rune, size := utf8.DecodeRune(s[r:])
- r += size
- w += utf8.EncodeRune(b[w:], rune)
- }
- }
- return b[0:w], true
-}
diff --git a/src/cmd/gofix/testdata/reflect.decode.go.out b/src/cmd/gofix/testdata/reflect.decode.go.out
deleted file mode 100644
index feeb7b867..000000000
--- a/src/cmd/gofix/testdata/reflect.decode.go.out
+++ /dev/null
@@ -1,910 +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.
-
-// Represents JSON data structure using native Go types: booleans, floats,
-// strings, arrays, and maps.
-
-package json
-
-import (
- "container/vector"
- "encoding/base64"
- "os"
- "reflect"
- "runtime"
- "strconv"
- "strings"
- "unicode"
- "utf16"
- "utf8"
-)
-
-// Unmarshal parses the JSON-encoded data and stores the result
-// in the value pointed to by v.
-//
-// Unmarshal traverses the value v recursively.
-// If an encountered value implements the Unmarshaler interface,
-// Unmarshal calls its UnmarshalJSON method with a well-formed
-// JSON encoding.
-//
-// Otherwise, Unmarshal uses the inverse of the encodings that
-// Marshal uses, allocating maps, slices, and pointers as necessary,
-// with the following additional rules:
-//
-// To unmarshal a JSON value into a nil interface value, the
-// type stored in the interface value is one of:
-//
-// bool, for JSON booleans
-// float64, for JSON numbers
-// string, for JSON strings
-// []interface{}, for JSON arrays
-// map[string]interface{}, for JSON objects
-// nil for JSON null
-//
-// If a JSON value is not appropriate for a given target type,
-// or if a JSON number overflows the target type, Unmarshal
-// skips that field and completes the unmarshalling as best it can.
-// If no more serious errors are encountered, Unmarshal returns
-// an UnmarshalTypeError describing the earliest such error.
-//
-func Unmarshal(data []byte, v interface{}) os.Error {
- d := new(decodeState).init(data)
-
- // Quick check for well-formedness.
- // Avoids filling out half a data structure
- // before discovering a JSON syntax error.
- err := checkValid(data, &d.scan)
- if err != nil {
- return err
- }
-
- return d.unmarshal(v)
-}
-
-// Unmarshaler is the interface implemented by objects
-// that can unmarshal a JSON description of themselves.
-// The input can be assumed to be a valid JSON object
-// encoding. UnmarshalJSON must copy the JSON data
-// if it wishes to retain the data after returning.
-type Unmarshaler interface {
- UnmarshalJSON([]byte) os.Error
-}
-
-
-// An UnmarshalTypeError describes a JSON value that was
-// not appropriate for a value of a specific Go type.
-type UnmarshalTypeError struct {
- Value string // description of JSON value - "bool", "array", "number -5"
- Type reflect.Type // type of Go value it could not be assigned to
-}
-
-func (e *UnmarshalTypeError) String() string {
- return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
-}
-
-// An UnmarshalFieldError describes a JSON object key that
-// led to an unexported (and therefore unwritable) struct field.
-type UnmarshalFieldError struct {
- Key string
- Type reflect.Type
- Field reflect.StructField
-}
-
-func (e *UnmarshalFieldError) String() string {
- return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
-}
-
-// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
-// (The argument to Unmarshal must be a non-nil pointer.)
-type InvalidUnmarshalError struct {
- Type reflect.Type
-}
-
-func (e *InvalidUnmarshalError) String() string {
- if e.Type == nil {
- return "json: Unmarshal(nil)"
- }
-
- if e.Type.Kind() != reflect.Ptr {
- return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
- }
- return "json: Unmarshal(nil " + e.Type.String() + ")"
-}
-
-func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
- defer func() {
- if r := recover(); r != nil {
- if _, ok := r.(runtime.Error); ok {
- panic(r)
- }
- err = r.(os.Error)
- }
- }()
-
- rv := reflect.ValueOf(v)
- pv := rv
- if pv.Kind() != reflect.Ptr ||
- pv.IsNil() {
- return &InvalidUnmarshalError{reflect.TypeOf(v)}
- }
-
- d.scan.reset()
- // We decode rv not pv.Elem because the Unmarshaler interface
- // test must be applied at the top level of the value.
- d.value(rv)
- return d.savedError
-}
-
-// decodeState represents the state while decoding a JSON value.
-type decodeState struct {
- data []byte
- off int // read offset in data
- scan scanner
- nextscan scanner // for calls to nextValue
- savedError os.Error
-}
-
-// errPhase is used for errors that should not happen unless
-// there is a bug in the JSON decoder or something is editing
-// the data slice while the decoder executes.
-var errPhase = os.NewError("JSON decoder out of sync - data changing underfoot?")
-
-func (d *decodeState) init(data []byte) *decodeState {
- d.data = data
- d.off = 0
- d.savedError = nil
- return d
-}
-
-// error aborts the decoding by panicking with err.
-func (d *decodeState) error(err os.Error) {
- panic(err)
-}
-
-// saveError saves the first err it is called with,
-// for reporting at the end of the unmarshal.
-func (d *decodeState) saveError(err os.Error) {
- if d.savedError == nil {
- d.savedError = err
- }
-}
-
-// next cuts off and returns the next full JSON value in d.data[d.off:].
-// The next value is known to be an object or array, not a literal.
-func (d *decodeState) next() []byte {
- c := d.data[d.off]
- item, rest, err := nextValue(d.data[d.off:], &d.nextscan)
- if err != nil {
- d.error(err)
- }
- d.off = len(d.data) - len(rest)
-
- // Our scanner has seen the opening brace/bracket
- // and thinks we're still in the middle of the object.
- // invent a closing brace/bracket to get it out.
- if c == '{' {
- d.scan.step(&d.scan, '}')
- } else {
- d.scan.step(&d.scan, ']')
- }
-
- return item
-}
-
-// scanWhile processes bytes in d.data[d.off:] until it
-// receives a scan code not equal to op.
-// It updates d.off and returns the new scan code.
-func (d *decodeState) scanWhile(op int) int {
- var newOp int
- for {
- if d.off >= len(d.data) {
- newOp = d.scan.eof()
- d.off = len(d.data) + 1 // mark processed EOF with len+1
- } else {
- c := int(d.data[d.off])
- d.off++
- newOp = d.scan.step(&d.scan, c)
- }
- if newOp != op {
- break
- }
- }
- return newOp
-}
-
-// value decodes a JSON value from d.data[d.off:] into the value.
-// it updates d.off to point past the decoded value.
-func (d *decodeState) value(v reflect.Value) {
- if !v.IsValid() {
- _, rest, err := nextValue(d.data[d.off:], &d.nextscan)
- if err != nil {
- d.error(err)
- }
- d.off = len(d.data) - len(rest)
-
- // d.scan thinks we're still at the beginning of the item.
- // Feed in an empty string - the shortest, simplest value -
- // so that it knows we got to the end of the value.
- if d.scan.step == stateRedo {
- panic("redo")
- }
- d.scan.step(&d.scan, '"')
- d.scan.step(&d.scan, '"')
- return
- }
-
- switch op := d.scanWhile(scanSkipSpace); op {
- default:
- d.error(errPhase)
-
- case scanBeginArray:
- d.array(v)
-
- case scanBeginObject:
- d.object(v)
-
- case scanBeginLiteral:
- d.literal(v)
- }
-}
-
-// indirect walks down v allocating pointers as needed,
-// until it gets to a non-pointer.
-// if it encounters an Unmarshaler, indirect stops and returns that.
-// if wantptr is true, indirect stops at the last pointer.
-func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
- for {
- var isUnmarshaler bool
- if v.Type().NumMethod() > 0 {
- // Remember that this is an unmarshaler,
- // but wait to return it until after allocating
- // the pointer (if necessary).
- _, isUnmarshaler = v.Interface().(Unmarshaler)
- }
-
- if iv := v; iv.Kind() == reflect.Interface && !iv.IsNil() {
- v = iv.Elem()
- continue
- }
- pv := v
- if pv.Kind() != reflect.Ptr {
- break
- }
-
- if pv.Elem().Kind() != reflect.Ptr &&
- wantptr && !isUnmarshaler {
- return nil, pv
- }
- if pv.IsNil() {
- pv.Set(reflect.Zero(pv.Type().Elem()).Addr())
- }
- if isUnmarshaler {
- // Using v.Interface().(Unmarshaler)
- // here means that we have to use a pointer
- // as the struct field. We cannot use a value inside
- // a pointer to a struct, because in that case
- // v.Interface() is the value (x.f) not the pointer (&x.f).
- // This is an unfortunate consequence of reflect.
- // An alternative would be to look up the
- // UnmarshalJSON method and return a FuncValue.
- return v.Interface().(Unmarshaler), reflect.Value{}
- }
- v = pv.Elem()
- }
- return nil, v
-}
-
-// array consumes an array from d.data[d.off-1:], decoding into the value v.
-// the first byte of the array ('[') has been read already.
-func (d *decodeState) array(v reflect.Value) {
- // Check for unmarshaler.
- unmarshaler, pv := d.indirect(v, false)
- if unmarshaler != nil {
- d.off--
- err := unmarshaler.UnmarshalJSON(d.next())
- if err != nil {
- d.error(err)
- }
- return
- }
- v = pv
-
- // Decoding into nil interface? Switch to non-reflect code.
- iv := v
- ok := iv.Kind() == reflect.Interface
- if ok {
- iv.Set(reflect.ValueOf(d.arrayInterface()))
- return
- }
-
- // Check type of target.
- av := v
- if av.Kind() != reflect.Array && av.Kind() != reflect.Slice {
- d.saveError(&UnmarshalTypeError{"array", v.Type()})
- d.off--
- d.next()
- return
- }
-
- sv := v
-
- i := 0
- for {
- // Look ahead for ] - can only happen on first iteration.
- op := d.scanWhile(scanSkipSpace)
- if op == scanEndArray {
- break
- }
-
- // Back up so d.value can have the byte we just read.
- d.off--
- d.scan.undo(op)
-
- // Get element of array, growing if necessary.
- if i >= av.Cap() && sv.IsValid() {
- newcap := sv.Cap() + sv.Cap()/2
- if newcap < 4 {
- newcap = 4
- }
- newv := reflect.MakeSlice(sv.Type(), sv.Len(), newcap)
- reflect.Copy(newv, sv)
- sv.Set(newv)
- }
- if i >= av.Len() && sv.IsValid() {
- // Must be slice; gave up on array during i >= av.Cap().
- sv.SetLen(i + 1)
- }
-
- // Decode into element.
- if i < av.Len() {
- d.value(av.Index(i))
- } else {
- // Ran out of fixed array: skip.
- d.value(reflect.Value{})
- }
- i++
-
- // Next token must be , or ].
- op = d.scanWhile(scanSkipSpace)
- if op == scanEndArray {
- break
- }
- if op != scanArrayValue {
- d.error(errPhase)
- }
- }
- if i < av.Len() {
- if !sv.IsValid() {
- // Array. Zero the rest.
- z := reflect.Zero(av.Type().Elem())
- for ; i < av.Len(); i++ {
- av.Index(i).Set(z)
- }
- } else {
- sv.SetLen(i)
- }
- }
-}
-
-// matchName returns true if key should be written to a field named name.
-func matchName(key, name string) bool {
- return strings.ToLower(key) == strings.ToLower(name)
-}
-
-// object consumes an object from d.data[d.off-1:], decoding into the value v.
-// the first byte of the object ('{') has been read already.
-func (d *decodeState) object(v reflect.Value) {
- // Check for unmarshaler.
- unmarshaler, pv := d.indirect(v, false)
- if unmarshaler != nil {
- d.off--
- err := unmarshaler.UnmarshalJSON(d.next())
- if err != nil {
- d.error(err)
- }
- return
- }
- v = pv
-
- // Decoding into nil interface? Switch to non-reflect code.
- iv := v
- if iv.Kind() == reflect.Interface {
- iv.Set(reflect.ValueOf(d.objectInterface()))
- return
- }
-
- // Check type of target: struct or map[string]T
- var (
- mv reflect.Value
- sv reflect.Value
- )
- switch v.Kind() {
- case reflect.Map:
- // map must have string type
- t := v.Type()
- if t.Key() != reflect.TypeOf("") {
- d.saveError(&UnmarshalTypeError{"object", v.Type()})
- break
- }
- mv = v
- if mv.IsNil() {
- mv.Set(reflect.MakeMap(t))
- }
- case reflect.Struct:
- sv = v
- default:
- d.saveError(&UnmarshalTypeError{"object", v.Type()})
- }
-
- if !mv.IsValid() && !sv.IsValid() {
- d.off--
- d.next() // skip over { } in input
- return
- }
-
- for {
- // Read opening " of string key or closing }.
- op := d.scanWhile(scanSkipSpace)
- if op == scanEndObject {
- // closing } - can only happen on first iteration.
- break
- }
- if op != scanBeginLiteral {
- d.error(errPhase)
- }
-
- // Read string key.
- start := d.off - 1
- op = d.scanWhile(scanContinue)
- item := d.data[start : d.off-1]
- key, ok := unquote(item)
- if !ok {
- d.error(errPhase)
- }
-
- // Figure out field corresponding to key.
- var subv reflect.Value
- if mv.IsValid() {
- subv = reflect.Zero(mv.Type().Elem())
- } else {
- var f reflect.StructField
- var ok bool
- st := sv.Type()
- // First try for field with that tag.
- if isValidTag(key) {
- for i := 0; i < sv.NumField(); i++ {
- f = st.Field(i)
- if f.Tag == key {
- ok = true
- break
- }
- }
- }
- if !ok {
- // Second, exact match.
- f, ok = st.FieldByName(key)
- }
- if !ok {
- // Third, case-insensitive match.
- f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
- }
-
- // Extract value; name must be exported.
- if ok {
- if f.PkgPath != "" {
- d.saveError(&UnmarshalFieldError{key, st, f})
- } else {
- subv = sv.FieldByIndex(f.Index)
- }
- }
- }
-
- // Read : before value.
- if op == scanSkipSpace {
- op = d.scanWhile(scanSkipSpace)
- }
- if op != scanObjectKey {
- d.error(errPhase)
- }
-
- // Read value.
- d.value(subv)
-
- // Write value back to map;
- // if using struct, subv points into struct already.
- if mv.IsValid() {
- mv.SetMapIndex(reflect.ValueOf(key), subv)
- }
-
- // Next token must be , or }.
- op = d.scanWhile(scanSkipSpace)
- if op == scanEndObject {
- break
- }
- if op != scanObjectValue {
- d.error(errPhase)
- }
- }
-}
-
-// literal consumes a literal from d.data[d.off-1:], decoding into the value v.
-// The first byte of the literal has been read already
-// (that's how the caller knows it's a literal).
-func (d *decodeState) literal(v reflect.Value) {
- // All bytes inside literal return scanContinue op code.
- start := d.off - 1
- op := d.scanWhile(scanContinue)
-
- // Scan read one byte too far; back up.
- d.off--
- d.scan.undo(op)
- item := d.data[start:d.off]
-
- // Check for unmarshaler.
- wantptr := item[0] == 'n' // null
- unmarshaler, pv := d.indirect(v, wantptr)
- if unmarshaler != nil {
- err := unmarshaler.UnmarshalJSON(item)
- if err != nil {
- d.error(err)
- }
- return
- }
- v = pv
-
- switch c := item[0]; c {
- case 'n': // null
- switch v.Kind() {
- default:
- d.saveError(&UnmarshalTypeError{"null", v.Type()})
- case reflect.Interface, reflect.Ptr, reflect.Map:
- v.Set(reflect.Zero(v.Type()))
- }
-
- case 't', 'f': // true, false
- value := c == 't'
- switch v.Kind() {
- default:
- d.saveError(&UnmarshalTypeError{"bool", v.Type()})
- case reflect.Bool:
- v.SetBool(value)
- case reflect.Interface:
- v.Set(reflect.ValueOf(value))
- }
-
- case '"': // string
- s, ok := unquoteBytes(item)
- if !ok {
- d.error(errPhase)
- }
- switch v.Kind() {
- default:
- d.saveError(&UnmarshalTypeError{"string", v.Type()})
- case reflect.Slice:
- if v.Type() != byteSliceType {
- d.saveError(&UnmarshalTypeError{"string", v.Type()})
- break
- }
- b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
- n, err := base64.StdEncoding.Decode(b, s)
- if err != nil {
- d.saveError(err)
- break
- }
- v.Set(reflect.ValueOf(b[0:n]))
- case reflect.String:
- v.SetString(string(s))
- case reflect.Interface:
- v.Set(reflect.ValueOf(string(s)))
- }
-
- default: // number
- if c != '-' && (c < '0' || c > '9') {
- d.error(errPhase)
- }
- s := string(item)
- switch v.Kind() {
- default:
- d.error(&UnmarshalTypeError{"number", v.Type()})
- case reflect.Interface:
- n, err := strconv.Atof64(s)
- if err != nil {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
- break
- }
- v.Set(reflect.ValueOf(n))
-
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n, err := strconv.Atoi64(s)
- if err != nil || v.OverflowInt(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
- break
- }
- v.SetInt(n)
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- n, err := strconv.Atoui64(s)
- if err != nil || v.OverflowUint(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
- break
- }
- v.SetUint(n)
-
- case reflect.Float32, reflect.Float64:
- n, err := strconv.AtofN(s, v.Type().Bits())
- if err != nil || v.OverflowFloat(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
- break
- }
- v.SetFloat(n)
- }
- }
-}
-
-// The xxxInterface routines build up a value to be stored
-// in an empty interface. They are not strictly necessary,
-// but they avoid the weight of reflection in this common case.
-
-// valueInterface is like value but returns interface{}
-func (d *decodeState) valueInterface() interface{} {
- switch d.scanWhile(scanSkipSpace) {
- default:
- d.error(errPhase)
- case scanBeginArray:
- return d.arrayInterface()
- case scanBeginObject:
- return d.objectInterface()
- case scanBeginLiteral:
- return d.literalInterface()
- }
- panic("unreachable")
-}
-
-// arrayInterface is like array but returns []interface{}.
-func (d *decodeState) arrayInterface() []interface{} {
- var v vector.Vector
- for {
- // Look ahead for ] - can only happen on first iteration.
- op := d.scanWhile(scanSkipSpace)
- if op == scanEndArray {
- break
- }
-
- // Back up so d.value can have the byte we just read.
- d.off--
- d.scan.undo(op)
-
- v.Push(d.valueInterface())
-
- // Next token must be , or ].
- op = d.scanWhile(scanSkipSpace)
- if op == scanEndArray {
- break
- }
- if op != scanArrayValue {
- d.error(errPhase)
- }
- }
- return v
-}
-
-// objectInterface is like object but returns map[string]interface{}.
-func (d *decodeState) objectInterface() map[string]interface{} {
- m := make(map[string]interface{})
- for {
- // Read opening " of string key or closing }.
- op := d.scanWhile(scanSkipSpace)
- if op == scanEndObject {
- // closing } - can only happen on first iteration.
- break
- }
- if op != scanBeginLiteral {
- d.error(errPhase)
- }
-
- // Read string key.
- start := d.off - 1
- op = d.scanWhile(scanContinue)
- item := d.data[start : d.off-1]
- key, ok := unquote(item)
- if !ok {
- d.error(errPhase)
- }
-
- // Read : before value.
- if op == scanSkipSpace {
- op = d.scanWhile(scanSkipSpace)
- }
- if op != scanObjectKey {
- d.error(errPhase)
- }
-
- // Read value.
- m[key] = d.valueInterface()
-
- // Next token must be , or }.
- op = d.scanWhile(scanSkipSpace)
- if op == scanEndObject {
- break
- }
- if op != scanObjectValue {
- d.error(errPhase)
- }
- }
- return m
-}
-
-
-// literalInterface is like literal but returns an interface value.
-func (d *decodeState) literalInterface() interface{} {
- // All bytes inside literal return scanContinue op code.
- start := d.off - 1
- op := d.scanWhile(scanContinue)
-
- // Scan read one byte too far; back up.
- d.off--
- d.scan.undo(op)
- item := d.data[start:d.off]
-
- switch c := item[0]; c {
- case 'n': // null
- return nil
-
- case 't', 'f': // true, false
- return c == 't'
-
- case '"': // string
- s, ok := unquote(item)
- if !ok {
- d.error(errPhase)
- }
- return s
-
- default: // number
- if c != '-' && (c < '0' || c > '9') {
- d.error(errPhase)
- }
- n, err := strconv.Atof64(string(item))
- if err != nil {
- d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.TypeOf(0.0)})
- }
- return n
- }
- panic("unreachable")
-}
-
-// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
-// or it returns -1.
-func getu4(s []byte) int {
- if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
- return -1
- }
- rune, err := strconv.Btoui64(string(s[2:6]), 16)
- if err != nil {
- return -1
- }
- return int(rune)
-}
-
-// unquote converts a quoted JSON string literal s into an actual string t.
-// The rules are different than for Go, so cannot use strconv.Unquote.
-func unquote(s []byte) (t string, ok bool) {
- s, ok = unquoteBytes(s)
- t = string(s)
- return
-}
-
-func unquoteBytes(s []byte) (t []byte, ok bool) {
- if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
- return
- }
- s = s[1 : len(s)-1]
-
- // Check for unusual characters. If there are none,
- // then no unquoting is needed, so return a slice of the
- // original bytes.
- r := 0
- for r < len(s) {
- c := s[r]
- if c == '\\' || c == '"' || c < ' ' {
- break
- }
- if c < utf8.RuneSelf {
- r++
- continue
- }
- rune, size := utf8.DecodeRune(s[r:])
- if rune == utf8.RuneError && size == 1 {
- break
- }
- r += size
- }
- if r == len(s) {
- return s, true
- }
-
- b := make([]byte, len(s)+2*utf8.UTFMax)
- w := copy(b, s[0:r])
- for r < len(s) {
- // Out of room? Can only happen if s is full of
- // malformed UTF-8 and we're replacing each
- // byte with RuneError.
- if w >= len(b)-2*utf8.UTFMax {
- nb := make([]byte, (len(b)+utf8.UTFMax)*2)
- copy(nb, b[0:w])
- b = nb
- }
- switch c := s[r]; {
- case c == '\\':
- r++
- if r >= len(s) {
- return
- }
- switch s[r] {
- default:
- return
- case '"', '\\', '/', '\'':
- b[w] = s[r]
- r++
- w++
- case 'b':
- b[w] = '\b'
- r++
- w++
- case 'f':
- b[w] = '\f'
- r++
- w++
- case 'n':
- b[w] = '\n'
- r++
- w++
- case 'r':
- b[w] = '\r'
- r++
- w++
- case 't':
- b[w] = '\t'
- r++
- w++
- case 'u':
- r--
- rune := getu4(s[r:])
- if rune < 0 {
- return
- }
- r += 6
- if utf16.IsSurrogate(rune) {
- rune1 := getu4(s[r:])
- if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
- // A valid pair; consume.
- r += 6
- w += utf8.EncodeRune(b[w:], dec)
- break
- }
- // Invalid surrogate; fall back to replacement rune.
- rune = unicode.ReplacementChar
- }
- w += utf8.EncodeRune(b[w:], rune)
- }
-
- // Quote, control characters are invalid.
- case c == '"', c < ' ':
- return
-
- // ASCII
- case c < utf8.RuneSelf:
- b[w] = c
- r++
- w++
-
- // Coerce to well-formed UTF-8.
- default:
- rune, size := utf8.DecodeRune(s[r:])
- r += size
- w += utf8.EncodeRune(b[w:], rune)
- }
- }
- return b[0:w], true
-}
diff --git a/src/cmd/gofix/testdata/reflect.decoder.go.in b/src/cmd/gofix/testdata/reflect.decoder.go.in
deleted file mode 100644
index 34364161a..000000000
--- a/src/cmd/gofix/testdata/reflect.decoder.go.in
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gob
-
-import (
- "bufio"
- "bytes"
- "io"
- "os"
- "reflect"
- "sync"
-)
-
-// A Decoder manages the receipt of type and data information read from the
-// remote side of a connection.
-type Decoder struct {
- mutex sync.Mutex // each item must be received atomically
- r io.Reader // source of the data
- buf bytes.Buffer // buffer for more efficient i/o from r
- wireType map[typeId]*wireType // map from remote ID to local description
- decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
- ignorerCache map[typeId]**decEngine // ditto for ignored objects
- freeList *decoderState // list of free decoderStates; avoids reallocation
- countBuf []byte // used for decoding integers while parsing messages
- tmp []byte // temporary storage for i/o; saves reallocating
- err os.Error
-}
-
-// NewDecoder returns a new decoder that reads from the io.Reader.
-func NewDecoder(r io.Reader) *Decoder {
- dec := new(Decoder)
- dec.r = bufio.NewReader(r)
- dec.wireType = make(map[typeId]*wireType)
- dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
- dec.ignorerCache = make(map[typeId]**decEngine)
- dec.countBuf = make([]byte, 9) // counts may be uint64s (unlikely!), require 9 bytes
-
- return dec
-}
-
-// recvType loads the definition of a type.
-func (dec *Decoder) recvType(id typeId) {
- // Have we already seen this type? That's an error
- if id < firstUserId || dec.wireType[id] != nil {
- dec.err = os.ErrorString("gob: duplicate type received")
- return
- }
-
- // Type:
- wire := new(wireType)
- dec.decodeValue(tWireType, reflect.NewValue(wire))
- if dec.err != nil {
- return
- }
- // Remember we've seen this type.
- dec.wireType[id] = wire
-}
-
-// recvMessage reads the next count-delimited item from the input. It is the converse
-// of Encoder.writeMessage. It returns false on EOF or other error reading the message.
-func (dec *Decoder) recvMessage() bool {
- // Read a count.
- nbytes, _, err := decodeUintReader(dec.r, dec.countBuf)
- if err != nil {
- dec.err = err
- return false
- }
- dec.readMessage(int(nbytes))
- return dec.err == nil
-}
-
-// readMessage reads the next nbytes bytes from the input.
-func (dec *Decoder) readMessage(nbytes int) {
- // Allocate the buffer.
- if cap(dec.tmp) < nbytes {
- dec.tmp = make([]byte, nbytes+100) // room to grow
- }
- dec.tmp = dec.tmp[:nbytes]
-
- // Read the data
- _, dec.err = io.ReadFull(dec.r, dec.tmp)
- if dec.err != nil {
- if dec.err == os.EOF {
- dec.err = io.ErrUnexpectedEOF
- }
- return
- }
- dec.buf.Write(dec.tmp)
-}
-
-// toInt turns an encoded uint64 into an int, according to the marshaling rules.
-func toInt(x uint64) int64 {
- i := int64(x >> 1)
- if x&1 != 0 {
- i = ^i
- }
- return i
-}
-
-func (dec *Decoder) nextInt() int64 {
- n, _, err := decodeUintReader(&dec.buf, dec.countBuf)
- if err != nil {
- dec.err = err
- }
- return toInt(n)
-}
-
-func (dec *Decoder) nextUint() uint64 {
- n, _, err := decodeUintReader(&dec.buf, dec.countBuf)
- if err != nil {
- dec.err = err
- }
- return n
-}
-
-// decodeTypeSequence parses:
-// TypeSequence
-// (TypeDefinition DelimitedTypeDefinition*)?
-// and returns the type id of the next value. It returns -1 at
-// EOF. Upon return, the remainder of dec.buf is the value to be
-// decoded. If this is an interface value, it can be ignored by
-// simply resetting that buffer.
-func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
- for dec.err == nil {
- if dec.buf.Len() == 0 {
- if !dec.recvMessage() {
- break
- }
- }
- // Receive a type id.
- id := typeId(dec.nextInt())
- if id >= 0 {
- // Value follows.
- return id
- }
- // Type definition for (-id) follows.
- dec.recvType(-id)
- // When decoding an interface, after a type there may be a
- // DelimitedValue still in the buffer. Skip its count.
- // (Alternatively, the buffer is empty and the byte count
- // will be absorbed by recvMessage.)
- if dec.buf.Len() > 0 {
- if !isInterface {
- dec.err = os.ErrorString("extra data in buffer")
- break
- }
- dec.nextUint()
- }
- }
- return -1
-}
-
-// Decode reads the next value from the connection and stores
-// it in the data represented by the empty interface value.
-// If e is nil, the value will be discarded. Otherwise,
-// the value underlying e must either be the correct type for the next
-// data item received, and must be a pointer.
-func (dec *Decoder) Decode(e interface{}) os.Error {
- if e == nil {
- return dec.DecodeValue(nil)
- }
- value := reflect.NewValue(e)
- // If e represents a value as opposed to a pointer, the answer won't
- // get back to the caller. Make sure it's a pointer.
- if value.Type().Kind() != reflect.Ptr {
- dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
- return dec.err
- }
- return dec.DecodeValue(value)
-}
-
-// DecodeValue reads the next value from the connection and stores
-// it in the data represented by the reflection value.
-// The value must be the correct type for the next
-// data item received, or it may be nil, which means the
-// value will be discarded.
-func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
- // Make sure we're single-threaded through here.
- dec.mutex.Lock()
- defer dec.mutex.Unlock()
-
- dec.buf.Reset() // In case data lingers from previous invocation.
- dec.err = nil
- id := dec.decodeTypeSequence(false)
- if dec.err == nil {
- dec.decodeValue(id, value)
- }
- return dec.err
-}
-
-// If debug.go is compiled into the program , debugFunc prints a human-readable
-// representation of the gob data read from r by calling that file's Debug function.
-// Otherwise it is nil.
-var debugFunc func(io.Reader)
diff --git a/src/cmd/gofix/testdata/reflect.decoder.go.out b/src/cmd/gofix/testdata/reflect.decoder.go.out
deleted file mode 100644
index ece88ecbe..000000000
--- a/src/cmd/gofix/testdata/reflect.decoder.go.out
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gob
-
-import (
- "bufio"
- "bytes"
- "io"
- "os"
- "reflect"
- "sync"
-)
-
-// A Decoder manages the receipt of type and data information read from the
-// remote side of a connection.
-type Decoder struct {
- mutex sync.Mutex // each item must be received atomically
- r io.Reader // source of the data
- buf bytes.Buffer // buffer for more efficient i/o from r
- wireType map[typeId]*wireType // map from remote ID to local description
- decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
- ignorerCache map[typeId]**decEngine // ditto for ignored objects
- freeList *decoderState // list of free decoderStates; avoids reallocation
- countBuf []byte // used for decoding integers while parsing messages
- tmp []byte // temporary storage for i/o; saves reallocating
- err os.Error
-}
-
-// NewDecoder returns a new decoder that reads from the io.Reader.
-func NewDecoder(r io.Reader) *Decoder {
- dec := new(Decoder)
- dec.r = bufio.NewReader(r)
- dec.wireType = make(map[typeId]*wireType)
- dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
- dec.ignorerCache = make(map[typeId]**decEngine)
- dec.countBuf = make([]byte, 9) // counts may be uint64s (unlikely!), require 9 bytes
-
- return dec
-}
-
-// recvType loads the definition of a type.
-func (dec *Decoder) recvType(id typeId) {
- // Have we already seen this type? That's an error
- if id < firstUserId || dec.wireType[id] != nil {
- dec.err = os.NewError("gob: duplicate type received")
- return
- }
-
- // Type:
- wire := new(wireType)
- dec.decodeValue(tWireType, reflect.ValueOf(wire))
- if dec.err != nil {
- return
- }
- // Remember we've seen this type.
- dec.wireType[id] = wire
-}
-
-// recvMessage reads the next count-delimited item from the input. It is the converse
-// of Encoder.writeMessage. It returns false on EOF or other error reading the message.
-func (dec *Decoder) recvMessage() bool {
- // Read a count.
- nbytes, _, err := decodeUintReader(dec.r, dec.countBuf)
- if err != nil {
- dec.err = err
- return false
- }
- dec.readMessage(int(nbytes))
- return dec.err == nil
-}
-
-// readMessage reads the next nbytes bytes from the input.
-func (dec *Decoder) readMessage(nbytes int) {
- // Allocate the buffer.
- if cap(dec.tmp) < nbytes {
- dec.tmp = make([]byte, nbytes+100) // room to grow
- }
- dec.tmp = dec.tmp[:nbytes]
-
- // Read the data
- _, dec.err = io.ReadFull(dec.r, dec.tmp)
- if dec.err != nil {
- if dec.err == os.EOF {
- dec.err = io.ErrUnexpectedEOF
- }
- return
- }
- dec.buf.Write(dec.tmp)
-}
-
-// toInt turns an encoded uint64 into an int, according to the marshaling rules.
-func toInt(x uint64) int64 {
- i := int64(x >> 1)
- if x&1 != 0 {
- i = ^i
- }
- return i
-}
-
-func (dec *Decoder) nextInt() int64 {
- n, _, err := decodeUintReader(&dec.buf, dec.countBuf)
- if err != nil {
- dec.err = err
- }
- return toInt(n)
-}
-
-func (dec *Decoder) nextUint() uint64 {
- n, _, err := decodeUintReader(&dec.buf, dec.countBuf)
- if err != nil {
- dec.err = err
- }
- return n
-}
-
-// decodeTypeSequence parses:
-// TypeSequence
-// (TypeDefinition DelimitedTypeDefinition*)?
-// and returns the type id of the next value. It returns -1 at
-// EOF. Upon return, the remainder of dec.buf is the value to be
-// decoded. If this is an interface value, it can be ignored by
-// simply resetting that buffer.
-func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
- for dec.err == nil {
- if dec.buf.Len() == 0 {
- if !dec.recvMessage() {
- break
- }
- }
- // Receive a type id.
- id := typeId(dec.nextInt())
- if id >= 0 {
- // Value follows.
- return id
- }
- // Type definition for (-id) follows.
- dec.recvType(-id)
- // When decoding an interface, after a type there may be a
- // DelimitedValue still in the buffer. Skip its count.
- // (Alternatively, the buffer is empty and the byte count
- // will be absorbed by recvMessage.)
- if dec.buf.Len() > 0 {
- if !isInterface {
- dec.err = os.NewError("extra data in buffer")
- break
- }
- dec.nextUint()
- }
- }
- return -1
-}
-
-// Decode reads the next value from the connection and stores
-// it in the data represented by the empty interface value.
-// If e is nil, the value will be discarded. Otherwise,
-// the value underlying e must either be the correct type for the next
-// data item received, and must be a pointer.
-func (dec *Decoder) Decode(e interface{}) os.Error {
- if e == nil {
- return dec.DecodeValue(reflect.Value{})
- }
- value := reflect.ValueOf(e)
- // If e represents a value as opposed to a pointer, the answer won't
- // get back to the caller. Make sure it's a pointer.
- if value.Type().Kind() != reflect.Ptr {
- dec.err = os.NewError("gob: attempt to decode into a non-pointer")
- return dec.err
- }
- return dec.DecodeValue(value)
-}
-
-// DecodeValue reads the next value from the connection and stores
-// it in the data represented by the reflection value.
-// The value must be the correct type for the next
-// data item received, or it may be nil, which means the
-// value will be discarded.
-func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
- // Make sure we're single-threaded through here.
- dec.mutex.Lock()
- defer dec.mutex.Unlock()
-
- dec.buf.Reset() // In case data lingers from previous invocation.
- dec.err = nil
- id := dec.decodeTypeSequence(false)
- if dec.err == nil {
- dec.decodeValue(id, value)
- }
- return dec.err
-}
-
-// If debug.go is compiled into the program , debugFunc prints a human-readable
-// representation of the gob data read from r by calling that file's Debug function.
-// Otherwise it is nil.
-var debugFunc func(io.Reader)
diff --git a/src/cmd/gofix/testdata/reflect.dnsmsg.go.in b/src/cmd/gofix/testdata/reflect.dnsmsg.go.in
deleted file mode 100644
index 5209c1a06..000000000
--- a/src/cmd/gofix/testdata/reflect.dnsmsg.go.in
+++ /dev/null
@@ -1,779 +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.
-
-// DNS packet assembly. See RFC 1035.
-//
-// This is intended to support name resolution during net.Dial.
-// It doesn't have to be blazing fast.
-//
-// Rather than write the usual handful of routines to pack and
-// unpack every message that can appear on the wire, we use
-// reflection to write a generic pack/unpack for structs and then
-// use it. Thus, if in the future we need to define new message
-// structs, no new pack/unpack/printing code needs to be written.
-//
-// The first half of this file defines the DNS message formats.
-// The second half implements the conversion to and from wire format.
-// A few of the structure elements have string tags to aid the
-// generic pack/unpack routines.
-//
-// TODO(rsc): There are enough names defined in this file that they're all
-// prefixed with dns. Perhaps put this in its own package later.
-
-package net
-
-import (
- "fmt"
- "os"
- "reflect"
-)
-
-// Packet formats
-
-// Wire constants.
-const (
- // valid dnsRR_Header.Rrtype and dnsQuestion.qtype
- dnsTypeA = 1
- dnsTypeNS = 2
- dnsTypeMD = 3
- dnsTypeMF = 4
- dnsTypeCNAME = 5
- dnsTypeSOA = 6
- dnsTypeMB = 7
- dnsTypeMG = 8
- dnsTypeMR = 9
- dnsTypeNULL = 10
- dnsTypeWKS = 11
- dnsTypePTR = 12
- dnsTypeHINFO = 13
- dnsTypeMINFO = 14
- dnsTypeMX = 15
- dnsTypeTXT = 16
- dnsTypeAAAA = 28
- dnsTypeSRV = 33
-
- // valid dnsQuestion.qtype only
- dnsTypeAXFR = 252
- dnsTypeMAILB = 253
- dnsTypeMAILA = 254
- dnsTypeALL = 255
-
- // valid dnsQuestion.qclass
- dnsClassINET = 1
- dnsClassCSNET = 2
- dnsClassCHAOS = 3
- dnsClassHESIOD = 4
- dnsClassANY = 255
-
- // dnsMsg.rcode
- dnsRcodeSuccess = 0
- dnsRcodeFormatError = 1
- dnsRcodeServerFailure = 2
- dnsRcodeNameError = 3
- dnsRcodeNotImplemented = 4
- dnsRcodeRefused = 5
-)
-
-// The wire format for the DNS packet header.
-type dnsHeader struct {
- Id uint16
- Bits uint16
- Qdcount, Ancount, Nscount, Arcount uint16
-}
-
-const (
- // dnsHeader.Bits
- _QR = 1 << 15 // query/response (response=1)
- _AA = 1 << 10 // authoritative
- _TC = 1 << 9 // truncated
- _RD = 1 << 8 // recursion desired
- _RA = 1 << 7 // recursion available
-)
-
-// DNS queries.
-type dnsQuestion struct {
- Name string "domain-name" // "domain-name" specifies encoding; see packers below
- Qtype uint16
- Qclass uint16
-}
-
-// DNS responses (resource records).
-// There are many types of messages,
-// but they all share the same header.
-type dnsRR_Header struct {
- Name string "domain-name"
- Rrtype uint16
- Class uint16
- Ttl uint32
- Rdlength uint16 // length of data after header
-}
-
-func (h *dnsRR_Header) Header() *dnsRR_Header {
- return h
-}
-
-type dnsRR interface {
- Header() *dnsRR_Header
-}
-
-
-// Specific DNS RR formats for each query type.
-
-type dnsRR_CNAME struct {
- Hdr dnsRR_Header
- Cname string "domain-name"
-}
-
-func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_HINFO struct {
- Hdr dnsRR_Header
- Cpu string
- Os string
-}
-
-func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_MB struct {
- Hdr dnsRR_Header
- Mb string "domain-name"
-}
-
-func (rr *dnsRR_MB) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_MG struct {
- Hdr dnsRR_Header
- Mg string "domain-name"
-}
-
-func (rr *dnsRR_MG) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_MINFO struct {
- Hdr dnsRR_Header
- Rmail string "domain-name"
- Email string "domain-name"
-}
-
-func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_MR struct {
- Hdr dnsRR_Header
- Mr string "domain-name"
-}
-
-func (rr *dnsRR_MR) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_MX struct {
- Hdr dnsRR_Header
- Pref uint16
- Mx string "domain-name"
-}
-
-func (rr *dnsRR_MX) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_NS struct {
- Hdr dnsRR_Header
- Ns string "domain-name"
-}
-
-func (rr *dnsRR_NS) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_PTR struct {
- Hdr dnsRR_Header
- Ptr string "domain-name"
-}
-
-func (rr *dnsRR_PTR) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_SOA struct {
- Hdr dnsRR_Header
- Ns string "domain-name"
- Mbox string "domain-name"
- Serial uint32
- Refresh uint32
- Retry uint32
- Expire uint32
- Minttl uint32
-}
-
-func (rr *dnsRR_SOA) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_TXT struct {
- Hdr dnsRR_Header
- Txt string // not domain name
-}
-
-func (rr *dnsRR_TXT) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_SRV struct {
- Hdr dnsRR_Header
- Priority uint16
- Weight uint16
- Port uint16
- Target string "domain-name"
-}
-
-func (rr *dnsRR_SRV) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_A struct {
- Hdr dnsRR_Header
- A uint32 "ipv4"
-}
-
-func (rr *dnsRR_A) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_AAAA struct {
- Hdr dnsRR_Header
- AAAA [16]byte "ipv6"
-}
-
-func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-// Packing and unpacking.
-//
-// All the packers and unpackers take a (msg []byte, off int)
-// and return (off1 int, ok bool). If they return ok==false, they
-// also return off1==len(msg), so that the next unpacker will
-// also fail. This lets us avoid checks of ok until the end of a
-// packing sequence.
-
-// Map of constructors for each RR wire type.
-var rr_mk = map[int]func() dnsRR{
- dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
- dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
- dnsTypeMB: func() dnsRR { return new(dnsRR_MB) },
- dnsTypeMG: func() dnsRR { return new(dnsRR_MG) },
- dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
- dnsTypeMR: func() dnsRR { return new(dnsRR_MR) },
- dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
- dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
- dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
- dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) },
- dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
- dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
- dnsTypeA: func() dnsRR { return new(dnsRR_A) },
- dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) },
-}
-
-// Pack a domain name s into msg[off:].
-// Domain names are a sequence of counted strings
-// split at the dots. They end with a zero-length string.
-func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
- // Add trailing dot to canonicalize name.
- if n := len(s); n == 0 || s[n-1] != '.' {
- s += "."
- }
-
- // Each dot ends a segment of the name.
- // We trade each dot byte for a length byte.
- // There is also a trailing zero.
- // Check that we have all the space we need.
- tot := len(s) + 1
- if off+tot > len(msg) {
- return len(msg), false
- }
-
- // Emit sequence of counted strings, chopping at dots.
- begin := 0
- for i := 0; i < len(s); i++ {
- if s[i] == '.' {
- if i-begin >= 1<<6 { // top two bits of length must be clear
- return len(msg), false
- }
- msg[off] = byte(i - begin)
- off++
- for j := begin; j < i; j++ {
- msg[off] = s[j]
- off++
- }
- begin = i + 1
- }
- }
- msg[off] = 0
- off++
- return off, true
-}
-
-// Unpack a domain name.
-// In addition to the simple sequences of counted strings above,
-// domain names are allowed to refer to strings elsewhere in the
-// packet, to avoid repeating common suffixes when returning
-// many entries in a single domain. The pointers are marked
-// by a length byte with the top two bits set. Ignoring those
-// two bits, that byte and the next give a 14 bit offset from msg[0]
-// where we should pick up the trail.
-// Note that if we jump elsewhere in the packet,
-// we return off1 == the offset after the first pointer we found,
-// which is where the next record will start.
-// In theory, the pointers are only allowed to jump backward.
-// We let them jump anywhere and stop jumping after a while.
-func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
- s = ""
- ptr := 0 // number of pointers followed
-Loop:
- for {
- if off >= len(msg) {
- return "", len(msg), false
- }
- c := int(msg[off])
- off++
- switch c & 0xC0 {
- case 0x00:
- if c == 0x00 {
- // end of name
- break Loop
- }
- // literal string
- if off+c > len(msg) {
- return "", len(msg), false
- }
- s += string(msg[off:off+c]) + "."
- off += c
- case 0xC0:
- // pointer to somewhere else in msg.
- // remember location after first ptr,
- // since that's how many bytes we consumed.
- // also, don't follow too many pointers --
- // maybe there's a loop.
- if off >= len(msg) {
- return "", len(msg), false
- }
- c1 := msg[off]
- off++
- if ptr == 0 {
- off1 = off
- }
- if ptr++; ptr > 10 {
- return "", len(msg), false
- }
- off = (c^0xC0)<<8 | int(c1)
- default:
- // 0x80 and 0x40 are reserved
- return "", len(msg), false
- }
- }
- if ptr == 0 {
- off1 = off
- }
- return s, off1, true
-}
-
-// TODO(rsc): Move into generic library?
-// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string,
-// [n]byte, and other (often anonymous) structs.
-func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
- for i := 0; i < val.NumField(); i++ {
- f := val.Type().(*reflect.StructType).Field(i)
- switch fv := val.Field(i).(type) {
- default:
- BadType:
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- case *reflect.StructValue:
- off, ok = packStructValue(fv, msg, off)
- case *reflect.UintValue:
- i := fv.Get()
- switch fv.Type().Kind() {
- default:
- goto BadType
- case reflect.Uint16:
- if off+2 > len(msg) {
- return len(msg), false
- }
- msg[off] = byte(i >> 8)
- msg[off+1] = byte(i)
- off += 2
- case reflect.Uint32:
- if off+4 > len(msg) {
- return len(msg), false
- }
- msg[off] = byte(i >> 24)
- msg[off+1] = byte(i >> 16)
- msg[off+2] = byte(i >> 8)
- msg[off+3] = byte(i)
- off += 4
- }
- case *reflect.ArrayValue:
- if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 {
- goto BadType
- }
- n := fv.Len()
- if off+n > len(msg) {
- return len(msg), false
- }
- reflect.Copy(reflect.NewValue(msg[off:off+n]).(*reflect.SliceValue), fv)
- off += n
- case *reflect.StringValue:
- // There are multiple string encodings.
- // The tag distinguishes ordinary strings from domain names.
- s := fv.Get()
- switch f.Tag {
- default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
- return len(msg), false
- case "domain-name":
- off, ok = packDomainName(s, msg, off)
- if !ok {
- return len(msg), false
- }
- case "":
- // Counted string: 1 byte length.
- if len(s) > 255 || off+1+len(s) > len(msg) {
- return len(msg), false
- }
- msg[off] = byte(len(s))
- off++
- off += copy(msg[off:], s)
- }
- }
- }
- return off, true
-}
-
-func structValue(any interface{}) *reflect.StructValue {
- return reflect.NewValue(any).(*reflect.PtrValue).Elem().(*reflect.StructValue)
-}
-
-func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
- off, ok = packStructValue(structValue(any), msg, off)
- return off, ok
-}
-
-// TODO(rsc): Move into generic library?
-// Unpack a reflect.StructValue from msg.
-// Same restrictions as packStructValue.
-func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
- for i := 0; i < val.NumField(); i++ {
- f := val.Type().(*reflect.StructType).Field(i)
- switch fv := val.Field(i).(type) {
- default:
- BadType:
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- case *reflect.StructValue:
- off, ok = unpackStructValue(fv, msg, off)
- case *reflect.UintValue:
- switch fv.Type().Kind() {
- default:
- goto BadType
- case reflect.Uint16:
- if off+2 > len(msg) {
- return len(msg), false
- }
- i := uint16(msg[off])<<8 | uint16(msg[off+1])
- fv.Set(uint64(i))
- off += 2
- case reflect.Uint32:
- if off+4 > len(msg) {
- return len(msg), false
- }
- i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
- fv.Set(uint64(i))
- off += 4
- }
- case *reflect.ArrayValue:
- if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 {
- goto BadType
- }
- n := fv.Len()
- if off+n > len(msg) {
- return len(msg), false
- }
- reflect.Copy(fv, reflect.NewValue(msg[off:off+n]).(*reflect.SliceValue))
- off += n
- case *reflect.StringValue:
- var s string
- switch f.Tag {
- default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
- return len(msg), false
- case "domain-name":
- s, off, ok = unpackDomainName(msg, off)
- if !ok {
- return len(msg), false
- }
- case "":
- if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
- return len(msg), false
- }
- n := int(msg[off])
- off++
- b := make([]byte, n)
- for i := 0; i < n; i++ {
- b[i] = msg[off+i]
- }
- off += n
- s = string(b)
- }
- fv.Set(s)
- }
- }
- return off, true
-}
-
-func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
- off, ok = unpackStructValue(structValue(any), msg, off)
- return off, ok
-}
-
-// Generic struct printer.
-// Doesn't care about the string tag "domain-name",
-// but does look for an "ipv4" tag on uint32 variables
-// and the "ipv6" tag on array variables,
-// printing them as IP addresses.
-func printStructValue(val *reflect.StructValue) string {
- s := "{"
- for i := 0; i < val.NumField(); i++ {
- if i > 0 {
- s += ", "
- }
- f := val.Type().(*reflect.StructType).Field(i)
- if !f.Anonymous {
- s += f.Name + "="
- }
- fval := val.Field(i)
- if fv, ok := fval.(*reflect.StructValue); ok {
- s += printStructValue(fv)
- } else if fv, ok := fval.(*reflect.UintValue); ok && f.Tag == "ipv4" {
- i := fv.Get()
- s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
- } else if fv, ok := fval.(*reflect.ArrayValue); ok && f.Tag == "ipv6" {
- i := fv.Interface().([]byte)
- s += IP(i).String()
- } else {
- s += fmt.Sprint(fval.Interface())
- }
- }
- s += "}"
- return s
-}
-
-func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
-
-// Resource record packer.
-func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
- var off1 int
- // pack twice, once to find end of header
- // and again to find end of packet.
- // a bit inefficient but this doesn't need to be fast.
- // off1 is end of header
- // off2 is end of rr
- off1, ok = packStruct(rr.Header(), msg, off)
- off2, ok = packStruct(rr, msg, off)
- if !ok {
- return len(msg), false
- }
- // pack a third time; redo header with correct data length
- rr.Header().Rdlength = uint16(off2 - off1)
- packStruct(rr.Header(), msg, off)
- return off2, true
-}
-
-// Resource record unpacker.
-func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
- // unpack just the header, to find the rr type and length
- var h dnsRR_Header
- off0 := off
- if off, ok = unpackStruct(&h, msg, off); !ok {
- return nil, len(msg), false
- }
- end := off + int(h.Rdlength)
-
- // make an rr of that type and re-unpack.
- // again inefficient but doesn't need to be fast.
- mk, known := rr_mk[int(h.Rrtype)]
- if !known {
- return &h, end, true
- }
- rr = mk()
- off, ok = unpackStruct(rr, msg, off0)
- if off != end {
- return &h, end, true
- }
- return rr, off, ok
-}
-
-// Usable representation of a DNS packet.
-
-// A manually-unpacked version of (id, bits).
-// This is in its own struct for easy printing.
-type dnsMsgHdr struct {
- id uint16
- response bool
- opcode int
- authoritative bool
- truncated bool
- recursion_desired bool
- recursion_available bool
- rcode int
-}
-
-type dnsMsg struct {
- dnsMsgHdr
- question []dnsQuestion
- answer []dnsRR
- ns []dnsRR
- extra []dnsRR
-}
-
-
-func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
- var dh dnsHeader
-
- // Convert convenient dnsMsg into wire-like dnsHeader.
- dh.Id = dns.id
- dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
- if dns.recursion_available {
- dh.Bits |= _RA
- }
- if dns.recursion_desired {
- dh.Bits |= _RD
- }
- if dns.truncated {
- dh.Bits |= _TC
- }
- if dns.authoritative {
- dh.Bits |= _AA
- }
- if dns.response {
- dh.Bits |= _QR
- }
-
- // Prepare variable sized arrays.
- question := dns.question
- answer := dns.answer
- ns := dns.ns
- extra := dns.extra
-
- dh.Qdcount = uint16(len(question))
- dh.Ancount = uint16(len(answer))
- dh.Nscount = uint16(len(ns))
- dh.Arcount = uint16(len(extra))
-
- // Could work harder to calculate message size,
- // but this is far more than we need and not
- // big enough to hurt the allocator.
- msg = make([]byte, 2000)
-
- // Pack it in: header and then the pieces.
- off := 0
- off, ok = packStruct(&dh, msg, off)
- for i := 0; i < len(question); i++ {
- off, ok = packStruct(&question[i], msg, off)
- }
- for i := 0; i < len(answer); i++ {
- off, ok = packRR(answer[i], msg, off)
- }
- for i := 0; i < len(ns); i++ {
- off, ok = packRR(ns[i], msg, off)
- }
- for i := 0; i < len(extra); i++ {
- off, ok = packRR(extra[i], msg, off)
- }
- if !ok {
- return nil, false
- }
- return msg[0:off], true
-}
-
-func (dns *dnsMsg) Unpack(msg []byte) bool {
- // Header.
- var dh dnsHeader
- off := 0
- var ok bool
- if off, ok = unpackStruct(&dh, msg, off); !ok {
- return false
- }
- dns.id = dh.Id
- dns.response = (dh.Bits & _QR) != 0
- dns.opcode = int(dh.Bits>>11) & 0xF
- dns.authoritative = (dh.Bits & _AA) != 0
- dns.truncated = (dh.Bits & _TC) != 0
- dns.recursion_desired = (dh.Bits & _RD) != 0
- dns.recursion_available = (dh.Bits & _RA) != 0
- dns.rcode = int(dh.Bits & 0xF)
-
- // Arrays.
- dns.question = make([]dnsQuestion, dh.Qdcount)
- dns.answer = make([]dnsRR, dh.Ancount)
- dns.ns = make([]dnsRR, dh.Nscount)
- dns.extra = make([]dnsRR, dh.Arcount)
-
- for i := 0; i < len(dns.question); i++ {
- off, ok = unpackStruct(&dns.question[i], msg, off)
- }
- for i := 0; i < len(dns.answer); i++ {
- dns.answer[i], off, ok = unpackRR(msg, off)
- }
- for i := 0; i < len(dns.ns); i++ {
- dns.ns[i], off, ok = unpackRR(msg, off)
- }
- for i := 0; i < len(dns.extra); i++ {
- dns.extra[i], off, ok = unpackRR(msg, off)
- }
- if !ok {
- return false
- }
- // if off != len(msg) {
- // println("extra bytes in dns packet", off, "<", len(msg));
- // }
- return true
-}
-
-func (dns *dnsMsg) String() string {
- s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
- if len(dns.question) > 0 {
- s += "-- Questions\n"
- for i := 0; i < len(dns.question); i++ {
- s += printStruct(&dns.question[i]) + "\n"
- }
- }
- if len(dns.answer) > 0 {
- s += "-- Answers\n"
- for i := 0; i < len(dns.answer); i++ {
- s += printStruct(dns.answer[i]) + "\n"
- }
- }
- if len(dns.ns) > 0 {
- s += "-- Name servers\n"
- for i := 0; i < len(dns.ns); i++ {
- s += printStruct(dns.ns[i]) + "\n"
- }
- }
- if len(dns.extra) > 0 {
- s += "-- Extra\n"
- for i := 0; i < len(dns.extra); i++ {
- s += printStruct(dns.extra[i]) + "\n"
- }
- }
- return s
-}
diff --git a/src/cmd/gofix/testdata/reflect.dnsmsg.go.out b/src/cmd/gofix/testdata/reflect.dnsmsg.go.out
deleted file mode 100644
index 12e4c34c3..000000000
--- a/src/cmd/gofix/testdata/reflect.dnsmsg.go.out
+++ /dev/null
@@ -1,779 +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.
-
-// DNS packet assembly. See RFC 1035.
-//
-// This is intended to support name resolution during net.Dial.
-// It doesn't have to be blazing fast.
-//
-// Rather than write the usual handful of routines to pack and
-// unpack every message that can appear on the wire, we use
-// reflection to write a generic pack/unpack for structs and then
-// use it. Thus, if in the future we need to define new message
-// structs, no new pack/unpack/printing code needs to be written.
-//
-// The first half of this file defines the DNS message formats.
-// The second half implements the conversion to and from wire format.
-// A few of the structure elements have string tags to aid the
-// generic pack/unpack routines.
-//
-// TODO(rsc): There are enough names defined in this file that they're all
-// prefixed with dns. Perhaps put this in its own package later.
-
-package net
-
-import (
- "fmt"
- "os"
- "reflect"
-)
-
-// Packet formats
-
-// Wire constants.
-const (
- // valid dnsRR_Header.Rrtype and dnsQuestion.qtype
- dnsTypeA = 1
- dnsTypeNS = 2
- dnsTypeMD = 3
- dnsTypeMF = 4
- dnsTypeCNAME = 5
- dnsTypeSOA = 6
- dnsTypeMB = 7
- dnsTypeMG = 8
- dnsTypeMR = 9
- dnsTypeNULL = 10
- dnsTypeWKS = 11
- dnsTypePTR = 12
- dnsTypeHINFO = 13
- dnsTypeMINFO = 14
- dnsTypeMX = 15
- dnsTypeTXT = 16
- dnsTypeAAAA = 28
- dnsTypeSRV = 33
-
- // valid dnsQuestion.qtype only
- dnsTypeAXFR = 252
- dnsTypeMAILB = 253
- dnsTypeMAILA = 254
- dnsTypeALL = 255
-
- // valid dnsQuestion.qclass
- dnsClassINET = 1
- dnsClassCSNET = 2
- dnsClassCHAOS = 3
- dnsClassHESIOD = 4
- dnsClassANY = 255
-
- // dnsMsg.rcode
- dnsRcodeSuccess = 0
- dnsRcodeFormatError = 1
- dnsRcodeServerFailure = 2
- dnsRcodeNameError = 3
- dnsRcodeNotImplemented = 4
- dnsRcodeRefused = 5
-)
-
-// The wire format for the DNS packet header.
-type dnsHeader struct {
- Id uint16
- Bits uint16
- Qdcount, Ancount, Nscount, Arcount uint16
-}
-
-const (
- // dnsHeader.Bits
- _QR = 1 << 15 // query/response (response=1)
- _AA = 1 << 10 // authoritative
- _TC = 1 << 9 // truncated
- _RD = 1 << 8 // recursion desired
- _RA = 1 << 7 // recursion available
-)
-
-// DNS queries.
-type dnsQuestion struct {
- Name string "domain-name" // "domain-name" specifies encoding; see packers below
- Qtype uint16
- Qclass uint16
-}
-
-// DNS responses (resource records).
-// There are many types of messages,
-// but they all share the same header.
-type dnsRR_Header struct {
- Name string "domain-name"
- Rrtype uint16
- Class uint16
- Ttl uint32
- Rdlength uint16 // length of data after header
-}
-
-func (h *dnsRR_Header) Header() *dnsRR_Header {
- return h
-}
-
-type dnsRR interface {
- Header() *dnsRR_Header
-}
-
-
-// Specific DNS RR formats for each query type.
-
-type dnsRR_CNAME struct {
- Hdr dnsRR_Header
- Cname string "domain-name"
-}
-
-func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_HINFO struct {
- Hdr dnsRR_Header
- Cpu string
- Os string
-}
-
-func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_MB struct {
- Hdr dnsRR_Header
- Mb string "domain-name"
-}
-
-func (rr *dnsRR_MB) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_MG struct {
- Hdr dnsRR_Header
- Mg string "domain-name"
-}
-
-func (rr *dnsRR_MG) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_MINFO struct {
- Hdr dnsRR_Header
- Rmail string "domain-name"
- Email string "domain-name"
-}
-
-func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_MR struct {
- Hdr dnsRR_Header
- Mr string "domain-name"
-}
-
-func (rr *dnsRR_MR) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_MX struct {
- Hdr dnsRR_Header
- Pref uint16
- Mx string "domain-name"
-}
-
-func (rr *dnsRR_MX) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_NS struct {
- Hdr dnsRR_Header
- Ns string "domain-name"
-}
-
-func (rr *dnsRR_NS) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_PTR struct {
- Hdr dnsRR_Header
- Ptr string "domain-name"
-}
-
-func (rr *dnsRR_PTR) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_SOA struct {
- Hdr dnsRR_Header
- Ns string "domain-name"
- Mbox string "domain-name"
- Serial uint32
- Refresh uint32
- Retry uint32
- Expire uint32
- Minttl uint32
-}
-
-func (rr *dnsRR_SOA) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_TXT struct {
- Hdr dnsRR_Header
- Txt string // not domain name
-}
-
-func (rr *dnsRR_TXT) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_SRV struct {
- Hdr dnsRR_Header
- Priority uint16
- Weight uint16
- Port uint16
- Target string "domain-name"
-}
-
-func (rr *dnsRR_SRV) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_A struct {
- Hdr dnsRR_Header
- A uint32 "ipv4"
-}
-
-func (rr *dnsRR_A) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-type dnsRR_AAAA struct {
- Hdr dnsRR_Header
- AAAA [16]byte "ipv6"
-}
-
-func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-// Packing and unpacking.
-//
-// All the packers and unpackers take a (msg []byte, off int)
-// and return (off1 int, ok bool). If they return ok==false, they
-// also return off1==len(msg), so that the next unpacker will
-// also fail. This lets us avoid checks of ok until the end of a
-// packing sequence.
-
-// Map of constructors for each RR wire type.
-var rr_mk = map[int]func() dnsRR{
- dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
- dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
- dnsTypeMB: func() dnsRR { return new(dnsRR_MB) },
- dnsTypeMG: func() dnsRR { return new(dnsRR_MG) },
- dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
- dnsTypeMR: func() dnsRR { return new(dnsRR_MR) },
- dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
- dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
- dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
- dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) },
- dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
- dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
- dnsTypeA: func() dnsRR { return new(dnsRR_A) },
- dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) },
-}
-
-// Pack a domain name s into msg[off:].
-// Domain names are a sequence of counted strings
-// split at the dots. They end with a zero-length string.
-func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
- // Add trailing dot to canonicalize name.
- if n := len(s); n == 0 || s[n-1] != '.' {
- s += "."
- }
-
- // Each dot ends a segment of the name.
- // We trade each dot byte for a length byte.
- // There is also a trailing zero.
- // Check that we have all the space we need.
- tot := len(s) + 1
- if off+tot > len(msg) {
- return len(msg), false
- }
-
- // Emit sequence of counted strings, chopping at dots.
- begin := 0
- for i := 0; i < len(s); i++ {
- if s[i] == '.' {
- if i-begin >= 1<<6 { // top two bits of length must be clear
- return len(msg), false
- }
- msg[off] = byte(i - begin)
- off++
- for j := begin; j < i; j++ {
- msg[off] = s[j]
- off++
- }
- begin = i + 1
- }
- }
- msg[off] = 0
- off++
- return off, true
-}
-
-// Unpack a domain name.
-// In addition to the simple sequences of counted strings above,
-// domain names are allowed to refer to strings elsewhere in the
-// packet, to avoid repeating common suffixes when returning
-// many entries in a single domain. The pointers are marked
-// by a length byte with the top two bits set. Ignoring those
-// two bits, that byte and the next give a 14 bit offset from msg[0]
-// where we should pick up the trail.
-// Note that if we jump elsewhere in the packet,
-// we return off1 == the offset after the first pointer we found,
-// which is where the next record will start.
-// In theory, the pointers are only allowed to jump backward.
-// We let them jump anywhere and stop jumping after a while.
-func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
- s = ""
- ptr := 0 // number of pointers followed
-Loop:
- for {
- if off >= len(msg) {
- return "", len(msg), false
- }
- c := int(msg[off])
- off++
- switch c & 0xC0 {
- case 0x00:
- if c == 0x00 {
- // end of name
- break Loop
- }
- // literal string
- if off+c > len(msg) {
- return "", len(msg), false
- }
- s += string(msg[off:off+c]) + "."
- off += c
- case 0xC0:
- // pointer to somewhere else in msg.
- // remember location after first ptr,
- // since that's how many bytes we consumed.
- // also, don't follow too many pointers --
- // maybe there's a loop.
- if off >= len(msg) {
- return "", len(msg), false
- }
- c1 := msg[off]
- off++
- if ptr == 0 {
- off1 = off
- }
- if ptr++; ptr > 10 {
- return "", len(msg), false
- }
- off = (c^0xC0)<<8 | int(c1)
- default:
- // 0x80 and 0x40 are reserved
- return "", len(msg), false
- }
- }
- if ptr == 0 {
- off1 = off
- }
- return s, off1, true
-}
-
-// TODO(rsc): Move into generic library?
-// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string,
-// [n]byte, and other (often anonymous) structs.
-func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
- for i := 0; i < val.NumField(); i++ {
- f := val.Type().Field(i)
- switch fv := val.Field(i); fv.Kind() {
- default:
- BadType:
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- case reflect.Struct:
- off, ok = packStructValue(fv, msg, off)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- i := fv.Uint()
- switch fv.Type().Kind() {
- default:
- goto BadType
- case reflect.Uint16:
- if off+2 > len(msg) {
- return len(msg), false
- }
- msg[off] = byte(i >> 8)
- msg[off+1] = byte(i)
- off += 2
- case reflect.Uint32:
- if off+4 > len(msg) {
- return len(msg), false
- }
- msg[off] = byte(i >> 24)
- msg[off+1] = byte(i >> 16)
- msg[off+2] = byte(i >> 8)
- msg[off+3] = byte(i)
- off += 4
- }
- case reflect.Array:
- if fv.Type().Elem().Kind() != reflect.Uint8 {
- goto BadType
- }
- n := fv.Len()
- if off+n > len(msg) {
- return len(msg), false
- }
- reflect.Copy(reflect.ValueOf(msg[off:off+n]), fv)
- off += n
- case reflect.String:
- // There are multiple string encodings.
- // The tag distinguishes ordinary strings from domain names.
- s := fv.String()
- switch f.Tag {
- default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
- return len(msg), false
- case "domain-name":
- off, ok = packDomainName(s, msg, off)
- if !ok {
- return len(msg), false
- }
- case "":
- // Counted string: 1 byte length.
- if len(s) > 255 || off+1+len(s) > len(msg) {
- return len(msg), false
- }
- msg[off] = byte(len(s))
- off++
- off += copy(msg[off:], s)
- }
- }
- }
- return off, true
-}
-
-func structValue(any interface{}) reflect.Value {
- return reflect.ValueOf(any).Elem()
-}
-
-func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
- off, ok = packStructValue(structValue(any), msg, off)
- return off, ok
-}
-
-// TODO(rsc): Move into generic library?
-// Unpack a reflect.StructValue from msg.
-// Same restrictions as packStructValue.
-func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
- for i := 0; i < val.NumField(); i++ {
- f := val.Type().Field(i)
- switch fv := val.Field(i); fv.Kind() {
- default:
- BadType:
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- case reflect.Struct:
- off, ok = unpackStructValue(fv, msg, off)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- switch fv.Type().Kind() {
- default:
- goto BadType
- case reflect.Uint16:
- if off+2 > len(msg) {
- return len(msg), false
- }
- i := uint16(msg[off])<<8 | uint16(msg[off+1])
- fv.SetUint(uint64(i))
- off += 2
- case reflect.Uint32:
- if off+4 > len(msg) {
- return len(msg), false
- }
- i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
- fv.SetUint(uint64(i))
- off += 4
- }
- case reflect.Array:
- if fv.Type().Elem().Kind() != reflect.Uint8 {
- goto BadType
- }
- n := fv.Len()
- if off+n > len(msg) {
- return len(msg), false
- }
- reflect.Copy(fv, reflect.ValueOf(msg[off:off+n]))
- off += n
- case reflect.String:
- var s string
- switch f.Tag {
- default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
- return len(msg), false
- case "domain-name":
- s, off, ok = unpackDomainName(msg, off)
- if !ok {
- return len(msg), false
- }
- case "":
- if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
- return len(msg), false
- }
- n := int(msg[off])
- off++
- b := make([]byte, n)
- for i := 0; i < n; i++ {
- b[i] = msg[off+i]
- }
- off += n
- s = string(b)
- }
- fv.SetString(s)
- }
- }
- return off, true
-}
-
-func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
- off, ok = unpackStructValue(structValue(any), msg, off)
- return off, ok
-}
-
-// Generic struct printer.
-// Doesn't care about the string tag "domain-name",
-// but does look for an "ipv4" tag on uint32 variables
-// and the "ipv6" tag on array variables,
-// printing them as IP addresses.
-func printStructValue(val reflect.Value) string {
- s := "{"
- for i := 0; i < val.NumField(); i++ {
- if i > 0 {
- s += ", "
- }
- f := val.Type().Field(i)
- if !f.Anonymous {
- s += f.Name + "="
- }
- fval := val.Field(i)
- if fv := fval; fv.Kind() == reflect.Struct {
- s += printStructValue(fv)
- } else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == "ipv4" {
- i := fv.Uint()
- s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
- } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == "ipv6" {
- i := fv.Interface().([]byte)
- s += IP(i).String()
- } else {
- s += fmt.Sprint(fval.Interface())
- }
- }
- s += "}"
- return s
-}
-
-func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
-
-// Resource record packer.
-func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
- var off1 int
- // pack twice, once to find end of header
- // and again to find end of packet.
- // a bit inefficient but this doesn't need to be fast.
- // off1 is end of header
- // off2 is end of rr
- off1, ok = packStruct(rr.Header(), msg, off)
- off2, ok = packStruct(rr, msg, off)
- if !ok {
- return len(msg), false
- }
- // pack a third time; redo header with correct data length
- rr.Header().Rdlength = uint16(off2 - off1)
- packStruct(rr.Header(), msg, off)
- return off2, true
-}
-
-// Resource record unpacker.
-func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
- // unpack just the header, to find the rr type and length
- var h dnsRR_Header
- off0 := off
- if off, ok = unpackStruct(&h, msg, off); !ok {
- return nil, len(msg), false
- }
- end := off + int(h.Rdlength)
-
- // make an rr of that type and re-unpack.
- // again inefficient but doesn't need to be fast.
- mk, known := rr_mk[int(h.Rrtype)]
- if !known {
- return &h, end, true
- }
- rr = mk()
- off, ok = unpackStruct(rr, msg, off0)
- if off != end {
- return &h, end, true
- }
- return rr, off, ok
-}
-
-// Usable representation of a DNS packet.
-
-// A manually-unpacked version of (id, bits).
-// This is in its own struct for easy printing.
-type dnsMsgHdr struct {
- id uint16
- response bool
- opcode int
- authoritative bool
- truncated bool
- recursion_desired bool
- recursion_available bool
- rcode int
-}
-
-type dnsMsg struct {
- dnsMsgHdr
- question []dnsQuestion
- answer []dnsRR
- ns []dnsRR
- extra []dnsRR
-}
-
-
-func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
- var dh dnsHeader
-
- // Convert convenient dnsMsg into wire-like dnsHeader.
- dh.Id = dns.id
- dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
- if dns.recursion_available {
- dh.Bits |= _RA
- }
- if dns.recursion_desired {
- dh.Bits |= _RD
- }
- if dns.truncated {
- dh.Bits |= _TC
- }
- if dns.authoritative {
- dh.Bits |= _AA
- }
- if dns.response {
- dh.Bits |= _QR
- }
-
- // Prepare variable sized arrays.
- question := dns.question
- answer := dns.answer
- ns := dns.ns
- extra := dns.extra
-
- dh.Qdcount = uint16(len(question))
- dh.Ancount = uint16(len(answer))
- dh.Nscount = uint16(len(ns))
- dh.Arcount = uint16(len(extra))
-
- // Could work harder to calculate message size,
- // but this is far more than we need and not
- // big enough to hurt the allocator.
- msg = make([]byte, 2000)
-
- // Pack it in: header and then the pieces.
- off := 0
- off, ok = packStruct(&dh, msg, off)
- for i := 0; i < len(question); i++ {
- off, ok = packStruct(&question[i], msg, off)
- }
- for i := 0; i < len(answer); i++ {
- off, ok = packRR(answer[i], msg, off)
- }
- for i := 0; i < len(ns); i++ {
- off, ok = packRR(ns[i], msg, off)
- }
- for i := 0; i < len(extra); i++ {
- off, ok = packRR(extra[i], msg, off)
- }
- if !ok {
- return nil, false
- }
- return msg[0:off], true
-}
-
-func (dns *dnsMsg) Unpack(msg []byte) bool {
- // Header.
- var dh dnsHeader
- off := 0
- var ok bool
- if off, ok = unpackStruct(&dh, msg, off); !ok {
- return false
- }
- dns.id = dh.Id
- dns.response = (dh.Bits & _QR) != 0
- dns.opcode = int(dh.Bits>>11) & 0xF
- dns.authoritative = (dh.Bits & _AA) != 0
- dns.truncated = (dh.Bits & _TC) != 0
- dns.recursion_desired = (dh.Bits & _RD) != 0
- dns.recursion_available = (dh.Bits & _RA) != 0
- dns.rcode = int(dh.Bits & 0xF)
-
- // Arrays.
- dns.question = make([]dnsQuestion, dh.Qdcount)
- dns.answer = make([]dnsRR, dh.Ancount)
- dns.ns = make([]dnsRR, dh.Nscount)
- dns.extra = make([]dnsRR, dh.Arcount)
-
- for i := 0; i < len(dns.question); i++ {
- off, ok = unpackStruct(&dns.question[i], msg, off)
- }
- for i := 0; i < len(dns.answer); i++ {
- dns.answer[i], off, ok = unpackRR(msg, off)
- }
- for i := 0; i < len(dns.ns); i++ {
- dns.ns[i], off, ok = unpackRR(msg, off)
- }
- for i := 0; i < len(dns.extra); i++ {
- dns.extra[i], off, ok = unpackRR(msg, off)
- }
- if !ok {
- return false
- }
- // if off != len(msg) {
- // println("extra bytes in dns packet", off, "<", len(msg));
- // }
- return true
-}
-
-func (dns *dnsMsg) String() string {
- s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
- if len(dns.question) > 0 {
- s += "-- Questions\n"
- for i := 0; i < len(dns.question); i++ {
- s += printStruct(&dns.question[i]) + "\n"
- }
- }
- if len(dns.answer) > 0 {
- s += "-- Answers\n"
- for i := 0; i < len(dns.answer); i++ {
- s += printStruct(dns.answer[i]) + "\n"
- }
- }
- if len(dns.ns) > 0 {
- s += "-- Name servers\n"
- for i := 0; i < len(dns.ns); i++ {
- s += printStruct(dns.ns[i]) + "\n"
- }
- }
- if len(dns.extra) > 0 {
- s += "-- Extra\n"
- for i := 0; i < len(dns.extra); i++ {
- s += printStruct(dns.extra[i]) + "\n"
- }
- }
- return s
-}
diff --git a/src/cmd/gofix/testdata/reflect.encode.go.in b/src/cmd/gofix/testdata/reflect.encode.go.in
deleted file mode 100644
index 26ce47039..000000000
--- a/src/cmd/gofix/testdata/reflect.encode.go.in
+++ /dev/null
@@ -1,367 +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.
-
-// The json package implements encoding and decoding of JSON objects as
-// defined in RFC 4627.
-package json
-
-import (
- "bytes"
- "encoding/base64"
- "os"
- "reflect"
- "runtime"
- "sort"
- "strconv"
- "unicode"
- "utf8"
-)
-
-// Marshal returns the JSON encoding of v.
-//
-// Marshal traverses the value v recursively.
-// If an encountered value implements the Marshaler interface,
-// Marshal calls its MarshalJSON method to produce JSON.
-//
-// Otherwise, Marshal uses the following type-dependent default encodings:
-//
-// Boolean values encode as JSON booleans.
-//
-// Floating point and integer values encode as JSON numbers.
-//
-// String values encode as JSON strings, with each invalid UTF-8 sequence
-// replaced by the encoding of the Unicode replacement character U+FFFD.
-//
-// Array and slice values encode as JSON arrays, except that
-// []byte encodes as a base64-encoded string.
-//
-// Struct values encode as JSON objects. Each struct field becomes
-// a member of the object. By default the object's key name is the
-// struct field name. If the struct field has a non-empty tag consisting
-// of only Unicode letters, digits, and underscores, that tag will be used
-// as the name instead. Only exported fields will be encoded.
-//
-// Map values encode as JSON objects.
-// The map's key type must be string; the object keys are used directly
-// as map keys.
-//
-// Pointer values encode as the value pointed to.
-// A nil pointer encodes as the null JSON object.
-//
-// Interface values encode as the value contained in the interface.
-// A nil interface value encodes as the null JSON object.
-//
-// Channel, complex, and function values cannot be encoded in JSON.
-// Attempting to encode such a value causes Marshal to return
-// an InvalidTypeError.
-//
-// JSON cannot represent cyclic data structures and Marshal does not
-// handle them. Passing cyclic structures to Marshal will result in
-// an infinite recursion.
-//
-func Marshal(v interface{}) ([]byte, os.Error) {
- e := &encodeState{}
- err := e.marshal(v)
- if err != nil {
- return nil, err
- }
- return e.Bytes(), nil
-}
-
-// MarshalIndent is like Marshal but applies Indent to format the output.
-func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
- b, err := Marshal(v)
- if err != nil {
- return nil, err
- }
- var buf bytes.Buffer
- err = Indent(&buf, b, prefix, indent)
- if err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
-}
-
-// MarshalForHTML is like Marshal but applies HTMLEscape to the output.
-func MarshalForHTML(v interface{}) ([]byte, os.Error) {
- b, err := Marshal(v)
- if err != nil {
- return nil, err
- }
- var buf bytes.Buffer
- HTMLEscape(&buf, b)
- return buf.Bytes(), nil
-}
-
-// HTMLEscape appends to dst the JSON-encoded src with <, >, and &
-// characters inside string literals changed to \u003c, \u003e, \u0026
-// so that the JSON will be safe to embed inside HTML <script> tags.
-// For historical reasons, web browsers don't honor standard HTML
-// escaping within <script> tags, so an alternative JSON encoding must
-// be used.
-func HTMLEscape(dst *bytes.Buffer, src []byte) {
- // < > & can only appear in string literals,
- // so just scan the string one byte at a time.
- start := 0
- for i, c := range src {
- if c == '<' || c == '>' || c == '&' {
- if start < i {
- dst.Write(src[start:i])
- }
- dst.WriteString(`\u00`)
- dst.WriteByte(hex[c>>4])
- dst.WriteByte(hex[c&0xF])
- start = i + 1
- }
- }
- if start < len(src) {
- dst.Write(src[start:])
- }
-}
-
-// Marshaler is the interface implemented by objects that
-// can marshal themselves into valid JSON.
-type Marshaler interface {
- MarshalJSON() ([]byte, os.Error)
-}
-
-type UnsupportedTypeError struct {
- Type reflect.Type
-}
-
-func (e *UnsupportedTypeError) String() string {
- return "json: unsupported type: " + e.Type.String()
-}
-
-type InvalidUTF8Error struct {
- S string
-}
-
-func (e *InvalidUTF8Error) String() string {
- return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
-}
-
-type MarshalerError struct {
- Type reflect.Type
- Error os.Error
-}
-
-func (e *MarshalerError) String() string {
- return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
-}
-
-type interfaceOrPtrValue interface {
- IsNil() bool
- Elem() reflect.Value
-}
-
-var hex = "0123456789abcdef"
-
-// An encodeState encodes JSON into a bytes.Buffer.
-type encodeState struct {
- bytes.Buffer // accumulated output
-}
-
-func (e *encodeState) marshal(v interface{}) (err os.Error) {
- defer func() {
- if r := recover(); r != nil {
- if _, ok := r.(runtime.Error); ok {
- panic(r)
- }
- err = r.(os.Error)
- }
- }()
- e.reflectValue(reflect.NewValue(v))
- return nil
-}
-
-func (e *encodeState) error(err os.Error) {
- panic(err)
-}
-
-var byteSliceType = reflect.Typeof([]byte(nil))
-
-func (e *encodeState) reflectValue(v reflect.Value) {
- if v == nil {
- e.WriteString("null")
- return
- }
-
- if j, ok := v.Interface().(Marshaler); ok {
- b, err := j.MarshalJSON()
- if err == nil {
- // copy JSON into buffer, checking validity.
- err = Compact(&e.Buffer, b)
- }
- if err != nil {
- e.error(&MarshalerError{v.Type(), err})
- }
- return
- }
-
- switch v := v.(type) {
- case *reflect.BoolValue:
- x := v.Get()
- if x {
- e.WriteString("true")
- } else {
- e.WriteString("false")
- }
-
- case *reflect.IntValue:
- e.WriteString(strconv.Itoa64(v.Get()))
-
- case *reflect.UintValue:
- e.WriteString(strconv.Uitoa64(v.Get()))
-
- case *reflect.FloatValue:
- e.WriteString(strconv.FtoaN(v.Get(), 'g', -1, v.Type().Bits()))
-
- case *reflect.StringValue:
- e.string(v.Get())
-
- case *reflect.StructValue:
- e.WriteByte('{')
- t := v.Type().(*reflect.StructType)
- n := v.NumField()
- first := true
- for i := 0; i < n; i++ {
- f := t.Field(i)
- if f.PkgPath != "" {
- continue
- }
- if first {
- first = false
- } else {
- e.WriteByte(',')
- }
- if isValidTag(f.Tag) {
- e.string(f.Tag)
- } else {
- e.string(f.Name)
- }
- e.WriteByte(':')
- e.reflectValue(v.Field(i))
- }
- e.WriteByte('}')
-
- case *reflect.MapValue:
- if _, ok := v.Type().(*reflect.MapType).Key().(*reflect.StringType); !ok {
- e.error(&UnsupportedTypeError{v.Type()})
- }
- if v.IsNil() {
- e.WriteString("null")
- break
- }
- e.WriteByte('{')
- var sv stringValues = v.Keys()
- sort.Sort(sv)
- for i, k := range sv {
- if i > 0 {
- e.WriteByte(',')
- }
- e.string(k.(*reflect.StringValue).Get())
- e.WriteByte(':')
- e.reflectValue(v.Elem(k))
- }
- e.WriteByte('}')
-
- case reflect.ArrayOrSliceValue:
- if v.Type() == byteSliceType {
- e.WriteByte('"')
- s := v.Interface().([]byte)
- if len(s) < 1024 {
- // for small buffers, using Encode directly is much faster.
- dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
- base64.StdEncoding.Encode(dst, s)
- e.Write(dst)
- } else {
- // for large buffers, avoid unnecessary extra temporary
- // buffer space.
- enc := base64.NewEncoder(base64.StdEncoding, e)
- enc.Write(s)
- enc.Close()
- }
- e.WriteByte('"')
- break
- }
- e.WriteByte('[')
- n := v.Len()
- for i := 0; i < n; i++ {
- if i > 0 {
- e.WriteByte(',')
- }
- e.reflectValue(v.Elem(i))
- }
- e.WriteByte(']')
-
- case interfaceOrPtrValue:
- if v.IsNil() {
- e.WriteString("null")
- return
- }
- e.reflectValue(v.Elem())
-
- default:
- e.error(&UnsupportedTypeError{v.Type()})
- }
- return
-}
-
-func isValidTag(s string) bool {
- if s == "" {
- return false
- }
- for _, c := range s {
- if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
- return false
- }
- }
- return true
-}
-
-// stringValues is a slice of reflect.Value holding *reflect.StringValue.
-// It implements the methods to sort by string.
-type stringValues []reflect.Value
-
-func (sv stringValues) Len() int { return len(sv) }
-func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
-func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
-func (sv stringValues) get(i int) string { return sv[i].(*reflect.StringValue).Get() }
-
-func (e *encodeState) string(s string) {
- e.WriteByte('"')
- start := 0
- for i := 0; i < len(s); {
- if b := s[i]; b < utf8.RuneSelf {
- if 0x20 <= b && b != '\\' && b != '"' {
- i++
- continue
- }
- if start < i {
- e.WriteString(s[start:i])
- }
- if b == '\\' || b == '"' {
- e.WriteByte('\\')
- e.WriteByte(b)
- } else {
- e.WriteString(`\u00`)
- e.WriteByte(hex[b>>4])
- e.WriteByte(hex[b&0xF])
- }
- i++
- start = i
- continue
- }
- c, size := utf8.DecodeRuneInString(s[i:])
- if c == utf8.RuneError && size == 1 {
- e.error(&InvalidUTF8Error{s})
- }
- i += size
- }
- if start < len(s) {
- e.WriteString(s[start:])
- }
- e.WriteByte('"')
-}
diff --git a/src/cmd/gofix/testdata/reflect.encode.go.out b/src/cmd/gofix/testdata/reflect.encode.go.out
deleted file mode 100644
index 9a13a75ab..000000000
--- a/src/cmd/gofix/testdata/reflect.encode.go.out
+++ /dev/null
@@ -1,367 +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.
-
-// The json package implements encoding and decoding of JSON objects as
-// defined in RFC 4627.
-package json
-
-import (
- "bytes"
- "encoding/base64"
- "os"
- "reflect"
- "runtime"
- "sort"
- "strconv"
- "unicode"
- "utf8"
-)
-
-// Marshal returns the JSON encoding of v.
-//
-// Marshal traverses the value v recursively.
-// If an encountered value implements the Marshaler interface,
-// Marshal calls its MarshalJSON method to produce JSON.
-//
-// Otherwise, Marshal uses the following type-dependent default encodings:
-//
-// Boolean values encode as JSON booleans.
-//
-// Floating point and integer values encode as JSON numbers.
-//
-// String values encode as JSON strings, with each invalid UTF-8 sequence
-// replaced by the encoding of the Unicode replacement character U+FFFD.
-//
-// Array and slice values encode as JSON arrays, except that
-// []byte encodes as a base64-encoded string.
-//
-// Struct values encode as JSON objects. Each struct field becomes
-// a member of the object. By default the object's key name is the
-// struct field name. If the struct field has a non-empty tag consisting
-// of only Unicode letters, digits, and underscores, that tag will be used
-// as the name instead. Only exported fields will be encoded.
-//
-// Map values encode as JSON objects.
-// The map's key type must be string; the object keys are used directly
-// as map keys.
-//
-// Pointer values encode as the value pointed to.
-// A nil pointer encodes as the null JSON object.
-//
-// Interface values encode as the value contained in the interface.
-// A nil interface value encodes as the null JSON object.
-//
-// Channel, complex, and function values cannot be encoded in JSON.
-// Attempting to encode such a value causes Marshal to return
-// an InvalidTypeError.
-//
-// JSON cannot represent cyclic data structures and Marshal does not
-// handle them. Passing cyclic structures to Marshal will result in
-// an infinite recursion.
-//
-func Marshal(v interface{}) ([]byte, os.Error) {
- e := &encodeState{}
- err := e.marshal(v)
- if err != nil {
- return nil, err
- }
- return e.Bytes(), nil
-}
-
-// MarshalIndent is like Marshal but applies Indent to format the output.
-func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
- b, err := Marshal(v)
- if err != nil {
- return nil, err
- }
- var buf bytes.Buffer
- err = Indent(&buf, b, prefix, indent)
- if err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
-}
-
-// MarshalForHTML is like Marshal but applies HTMLEscape to the output.
-func MarshalForHTML(v interface{}) ([]byte, os.Error) {
- b, err := Marshal(v)
- if err != nil {
- return nil, err
- }
- var buf bytes.Buffer
- HTMLEscape(&buf, b)
- return buf.Bytes(), nil
-}
-
-// HTMLEscape appends to dst the JSON-encoded src with <, >, and &
-// characters inside string literals changed to \u003c, \u003e, \u0026
-// so that the JSON will be safe to embed inside HTML <script> tags.
-// For historical reasons, web browsers don't honor standard HTML
-// escaping within <script> tags, so an alternative JSON encoding must
-// be used.
-func HTMLEscape(dst *bytes.Buffer, src []byte) {
- // < > & can only appear in string literals,
- // so just scan the string one byte at a time.
- start := 0
- for i, c := range src {
- if c == '<' || c == '>' || c == '&' {
- if start < i {
- dst.Write(src[start:i])
- }
- dst.WriteString(`\u00`)
- dst.WriteByte(hex[c>>4])
- dst.WriteByte(hex[c&0xF])
- start = i + 1
- }
- }
- if start < len(src) {
- dst.Write(src[start:])
- }
-}
-
-// Marshaler is the interface implemented by objects that
-// can marshal themselves into valid JSON.
-type Marshaler interface {
- MarshalJSON() ([]byte, os.Error)
-}
-
-type UnsupportedTypeError struct {
- Type reflect.Type
-}
-
-func (e *UnsupportedTypeError) String() string {
- return "json: unsupported type: " + e.Type.String()
-}
-
-type InvalidUTF8Error struct {
- S string
-}
-
-func (e *InvalidUTF8Error) String() string {
- return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
-}
-
-type MarshalerError struct {
- Type reflect.Type
- Error os.Error
-}
-
-func (e *MarshalerError) String() string {
- return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
-}
-
-type interfaceOrPtrValue interface {
- IsNil() bool
- Elem() reflect.Value
-}
-
-var hex = "0123456789abcdef"
-
-// An encodeState encodes JSON into a bytes.Buffer.
-type encodeState struct {
- bytes.Buffer // accumulated output
-}
-
-func (e *encodeState) marshal(v interface{}) (err os.Error) {
- defer func() {
- if r := recover(); r != nil {
- if _, ok := r.(runtime.Error); ok {
- panic(r)
- }
- err = r.(os.Error)
- }
- }()
- e.reflectValue(reflect.ValueOf(v))
- return nil
-}
-
-func (e *encodeState) error(err os.Error) {
- panic(err)
-}
-
-var byteSliceType = reflect.TypeOf([]byte(nil))
-
-func (e *encodeState) reflectValue(v reflect.Value) {
- if !v.IsValid() {
- e.WriteString("null")
- return
- }
-
- if j, ok := v.Interface().(Marshaler); ok {
- b, err := j.MarshalJSON()
- if err == nil {
- // copy JSON into buffer, checking validity.
- err = Compact(&e.Buffer, b)
- }
- if err != nil {
- e.error(&MarshalerError{v.Type(), err})
- }
- return
- }
-
- switch v.Kind() {
- case reflect.Bool:
- x := v.Bool()
- if x {
- e.WriteString("true")
- } else {
- e.WriteString("false")
- }
-
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- e.WriteString(strconv.Itoa64(v.Int()))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- e.WriteString(strconv.Uitoa64(v.Uint()))
-
- case reflect.Float32, reflect.Float64:
- e.WriteString(strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()))
-
- case reflect.String:
- e.string(v.String())
-
- case reflect.Struct:
- e.WriteByte('{')
- t := v.Type()
- n := v.NumField()
- first := true
- for i := 0; i < n; i++ {
- f := t.Field(i)
- if f.PkgPath != "" {
- continue
- }
- if first {
- first = false
- } else {
- e.WriteByte(',')
- }
- if isValidTag(f.Tag) {
- e.string(f.Tag)
- } else {
- e.string(f.Name)
- }
- e.WriteByte(':')
- e.reflectValue(v.Field(i))
- }
- e.WriteByte('}')
-
- case reflect.Map:
- if v.Type().Key().Kind() != reflect.String {
- e.error(&UnsupportedTypeError{v.Type()})
- }
- if v.IsNil() {
- e.WriteString("null")
- break
- }
- e.WriteByte('{')
- var sv stringValues = v.MapKeys()
- sort.Sort(sv)
- for i, k := range sv {
- if i > 0 {
- e.WriteByte(',')
- }
- e.string(k.String())
- e.WriteByte(':')
- e.reflectValue(v.MapIndex(k))
- }
- e.WriteByte('}')
-
- case reflect.Array, reflect.Slice:
- if v.Type() == byteSliceType {
- e.WriteByte('"')
- s := v.Interface().([]byte)
- if len(s) < 1024 {
- // for small buffers, using Encode directly is much faster.
- dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
- base64.StdEncoding.Encode(dst, s)
- e.Write(dst)
- } else {
- // for large buffers, avoid unnecessary extra temporary
- // buffer space.
- enc := base64.NewEncoder(base64.StdEncoding, e)
- enc.Write(s)
- enc.Close()
- }
- e.WriteByte('"')
- break
- }
- e.WriteByte('[')
- n := v.Len()
- for i := 0; i < n; i++ {
- if i > 0 {
- e.WriteByte(',')
- }
- e.reflectValue(v.Index(i))
- }
- e.WriteByte(']')
-
- case interfaceOrPtrValue:
- if v.IsNil() {
- e.WriteString("null")
- return
- }
- e.reflectValue(v.Elem())
-
- default:
- e.error(&UnsupportedTypeError{v.Type()})
- }
- return
-}
-
-func isValidTag(s string) bool {
- if s == "" {
- return false
- }
- for _, c := range s {
- if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
- return false
- }
- }
- return true
-}
-
-// stringValues is a slice of reflect.Value holding *reflect.StringValue.
-// It implements the methods to sort by string.
-type stringValues []reflect.Value
-
-func (sv stringValues) Len() int { return len(sv) }
-func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
-func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
-func (sv stringValues) get(i int) string { return sv[i].String() }
-
-func (e *encodeState) string(s string) {
- e.WriteByte('"')
- start := 0
- for i := 0; i < len(s); {
- if b := s[i]; b < utf8.RuneSelf {
- if 0x20 <= b && b != '\\' && b != '"' {
- i++
- continue
- }
- if start < i {
- e.WriteString(s[start:i])
- }
- if b == '\\' || b == '"' {
- e.WriteByte('\\')
- e.WriteByte(b)
- } else {
- e.WriteString(`\u00`)
- e.WriteByte(hex[b>>4])
- e.WriteByte(hex[b&0xF])
- }
- i++
- start = i
- continue
- }
- c, size := utf8.DecodeRuneInString(s[i:])
- if c == utf8.RuneError && size == 1 {
- e.error(&InvalidUTF8Error{s})
- }
- i += size
- }
- if start < len(s) {
- e.WriteString(s[start:])
- }
- e.WriteByte('"')
-}
diff --git a/src/cmd/gofix/testdata/reflect.encoder.go.in b/src/cmd/gofix/testdata/reflect.encoder.go.in
deleted file mode 100644
index e52a4de29..000000000
--- a/src/cmd/gofix/testdata/reflect.encoder.go.in
+++ /dev/null
@@ -1,240 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gob
-
-import (
- "bytes"
- "io"
- "os"
- "reflect"
- "sync"
-)
-
-// An Encoder manages the transmission of type and data information to the
-// other side of a connection.
-type Encoder struct {
- mutex sync.Mutex // each item must be sent atomically
- w []io.Writer // where to send the data
- sent map[reflect.Type]typeId // which types we've already sent
- countState *encoderState // stage for writing counts
- freeList *encoderState // list of free encoderStates; avoids reallocation
- buf []byte // for collecting the output.
- byteBuf bytes.Buffer // buffer for top-level encoderState
- err os.Error
-}
-
-// NewEncoder returns a new encoder that will transmit on the io.Writer.
-func NewEncoder(w io.Writer) *Encoder {
- enc := new(Encoder)
- enc.w = []io.Writer{w}
- enc.sent = make(map[reflect.Type]typeId)
- enc.countState = enc.newEncoderState(new(bytes.Buffer))
- return enc
-}
-
-// writer() returns the innermost writer the encoder is using
-func (enc *Encoder) writer() io.Writer {
- return enc.w[len(enc.w)-1]
-}
-
-// pushWriter adds a writer to the encoder.
-func (enc *Encoder) pushWriter(w io.Writer) {
- enc.w = append(enc.w, w)
-}
-
-// popWriter pops the innermost writer.
-func (enc *Encoder) popWriter() {
- enc.w = enc.w[0 : len(enc.w)-1]
-}
-
-func (enc *Encoder) badType(rt reflect.Type) {
- enc.setError(os.ErrorString("gob: can't encode type " + rt.String()))
-}
-
-func (enc *Encoder) setError(err os.Error) {
- if enc.err == nil { // remember the first.
- enc.err = err
- }
-}
-
-// writeMessage sends the data item preceded by a unsigned count of its length.
-func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) {
- enc.countState.encodeUint(uint64(b.Len()))
- // Build the buffer.
- countLen := enc.countState.b.Len()
- total := countLen + b.Len()
- if total > len(enc.buf) {
- enc.buf = make([]byte, total+1000) // extra for growth
- }
- // Place the length before the data.
- // TODO(r): avoid the extra copy here.
- enc.countState.b.Read(enc.buf[0:countLen])
- // Now the data.
- b.Read(enc.buf[countLen:total])
- // Write the data.
- _, err := w.Write(enc.buf[0:total])
- if err != nil {
- enc.setError(err)
- }
-}
-
-// sendActualType sends the requested type, without further investigation, unless
-// it's been sent before.
-func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTypeInfo, actual reflect.Type) (sent bool) {
- if _, alreadySent := enc.sent[actual]; alreadySent {
- return false
- }
- typeLock.Lock()
- info, err := getTypeInfo(ut)
- typeLock.Unlock()
- if err != nil {
- enc.setError(err)
- return
- }
- // Send the pair (-id, type)
- // Id:
- state.encodeInt(-int64(info.id))
- // Type:
- enc.encode(state.b, reflect.NewValue(info.wire), wireTypeUserInfo)
- enc.writeMessage(w, state.b)
- if enc.err != nil {
- return
- }
-
- // Remember we've sent this type, both what the user gave us and the base type.
- enc.sent[ut.base] = info.id
- if ut.user != ut.base {
- enc.sent[ut.user] = info.id
- }
- // Now send the inner types
- switch st := actual.(type) {
- case *reflect.StructType:
- for i := 0; i < st.NumField(); i++ {
- enc.sendType(w, state, st.Field(i).Type)
- }
- case reflect.ArrayOrSliceType:
- enc.sendType(w, state, st.Elem())
- }
- return true
-}
-
-// sendType sends the type info to the other side, if necessary.
-func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Type) (sent bool) {
- ut := userType(origt)
- if ut.isGobEncoder {
- // The rules are different: regardless of the underlying type's representation,
- // we need to tell the other side that this exact type is a GobEncoder.
- return enc.sendActualType(w, state, ut, ut.user)
- }
-
- // It's a concrete value, so drill down to the base type.
- switch rt := ut.base.(type) {
- default:
- // Basic types and interfaces do not need to be described.
- return
- case *reflect.SliceType:
- // If it's []uint8, don't send; it's considered basic.
- if rt.Elem().Kind() == reflect.Uint8 {
- return
- }
- // Otherwise we do send.
- break
- case *reflect.ArrayType:
- // arrays must be sent so we know their lengths and element types.
- break
- case *reflect.MapType:
- // maps must be sent so we know their lengths and key/value types.
- break
- case *reflect.StructType:
- // structs must be sent so we know their fields.
- break
- case *reflect.ChanType, *reflect.FuncType:
- // Probably a bad field in a struct.
- enc.badType(rt)
- return
- }
-
- return enc.sendActualType(w, state, ut, ut.base)
-}
-
-// Encode transmits the data item represented by the empty interface value,
-// guaranteeing that all necessary type information has been transmitted first.
-func (enc *Encoder) Encode(e interface{}) os.Error {
- return enc.EncodeValue(reflect.NewValue(e))
-}
-
-// sendTypeDescriptor makes sure the remote side knows about this type.
-// It will send a descriptor if this is the first time the type has been
-// sent.
-func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *userTypeInfo) {
- // Make sure the type is known to the other side.
- // First, have we already sent this type?
- rt := ut.base
- if ut.isGobEncoder {
- rt = ut.user
- }
- if _, alreadySent := enc.sent[rt]; !alreadySent {
- // No, so send it.
- sent := enc.sendType(w, state, rt)
- if enc.err != nil {
- return
- }
- // If the type info has still not been transmitted, it means we have
- // a singleton basic type (int, []byte etc.) at top level. We don't
- // need to send the type info but we do need to update enc.sent.
- if !sent {
- typeLock.Lock()
- info, err := getTypeInfo(ut)
- typeLock.Unlock()
- if err != nil {
- enc.setError(err)
- return
- }
- enc.sent[rt] = info.id
- }
- }
-}
-
-// sendTypeId sends the id, which must have already been defined.
-func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
- // Identify the type of this top-level value.
- state.encodeInt(int64(enc.sent[ut.base]))
-}
-
-// EncodeValue transmits the data item represented by the reflection value,
-// guaranteeing that all necessary type information has been transmitted first.
-func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
- // Make sure we're single-threaded through here, so multiple
- // goroutines can share an encoder.
- enc.mutex.Lock()
- defer enc.mutex.Unlock()
-
- // Remove any nested writers remaining due to previous errors.
- enc.w = enc.w[0:1]
-
- ut, err := validUserType(value.Type())
- if err != nil {
- return err
- }
-
- enc.err = nil
- enc.byteBuf.Reset()
- state := enc.newEncoderState(&enc.byteBuf)
-
- enc.sendTypeDescriptor(enc.writer(), state, ut)
- enc.sendTypeId(state, ut)
- if enc.err != nil {
- return enc.err
- }
-
- // Encode the object.
- enc.encode(state.b, value, ut)
- if enc.err == nil {
- enc.writeMessage(enc.writer(), state.b)
- }
-
- enc.freeEncoderState(state)
- return enc.err
-}
diff --git a/src/cmd/gofix/testdata/reflect.encoder.go.out b/src/cmd/gofix/testdata/reflect.encoder.go.out
deleted file mode 100644
index 925d39301..000000000
--- a/src/cmd/gofix/testdata/reflect.encoder.go.out
+++ /dev/null
@@ -1,240 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gob
-
-import (
- "bytes"
- "io"
- "os"
- "reflect"
- "sync"
-)
-
-// An Encoder manages the transmission of type and data information to the
-// other side of a connection.
-type Encoder struct {
- mutex sync.Mutex // each item must be sent atomically
- w []io.Writer // where to send the data
- sent map[reflect.Type]typeId // which types we've already sent
- countState *encoderState // stage for writing counts
- freeList *encoderState // list of free encoderStates; avoids reallocation
- buf []byte // for collecting the output.
- byteBuf bytes.Buffer // buffer for top-level encoderState
- err os.Error
-}
-
-// NewEncoder returns a new encoder that will transmit on the io.Writer.
-func NewEncoder(w io.Writer) *Encoder {
- enc := new(Encoder)
- enc.w = []io.Writer{w}
- enc.sent = make(map[reflect.Type]typeId)
- enc.countState = enc.newEncoderState(new(bytes.Buffer))
- return enc
-}
-
-// writer() returns the innermost writer the encoder is using
-func (enc *Encoder) writer() io.Writer {
- return enc.w[len(enc.w)-1]
-}
-
-// pushWriter adds a writer to the encoder.
-func (enc *Encoder) pushWriter(w io.Writer) {
- enc.w = append(enc.w, w)
-}
-
-// popWriter pops the innermost writer.
-func (enc *Encoder) popWriter() {
- enc.w = enc.w[0 : len(enc.w)-1]
-}
-
-func (enc *Encoder) badType(rt reflect.Type) {
- enc.setError(os.NewError("gob: can't encode type " + rt.String()))
-}
-
-func (enc *Encoder) setError(err os.Error) {
- if enc.err == nil { // remember the first.
- enc.err = err
- }
-}
-
-// writeMessage sends the data item preceded by a unsigned count of its length.
-func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) {
- enc.countState.encodeUint(uint64(b.Len()))
- // Build the buffer.
- countLen := enc.countState.b.Len()
- total := countLen + b.Len()
- if total > len(enc.buf) {
- enc.buf = make([]byte, total+1000) // extra for growth
- }
- // Place the length before the data.
- // TODO(r): avoid the extra copy here.
- enc.countState.b.Read(enc.buf[0:countLen])
- // Now the data.
- b.Read(enc.buf[countLen:total])
- // Write the data.
- _, err := w.Write(enc.buf[0:total])
- if err != nil {
- enc.setError(err)
- }
-}
-
-// sendActualType sends the requested type, without further investigation, unless
-// it's been sent before.
-func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTypeInfo, actual reflect.Type) (sent bool) {
- if _, alreadySent := enc.sent[actual]; alreadySent {
- return false
- }
- typeLock.Lock()
- info, err := getTypeInfo(ut)
- typeLock.Unlock()
- if err != nil {
- enc.setError(err)
- return
- }
- // Send the pair (-id, type)
- // Id:
- state.encodeInt(-int64(info.id))
- // Type:
- enc.encode(state.b, reflect.ValueOf(info.wire), wireTypeUserInfo)
- enc.writeMessage(w, state.b)
- if enc.err != nil {
- return
- }
-
- // Remember we've sent this type, both what the user gave us and the base type.
- enc.sent[ut.base] = info.id
- if ut.user != ut.base {
- enc.sent[ut.user] = info.id
- }
- // Now send the inner types
- switch st := actual; st.Kind() {
- case reflect.Struct:
- for i := 0; i < st.NumField(); i++ {
- enc.sendType(w, state, st.Field(i).Type)
- }
- case reflect.Array, reflect.Slice:
- enc.sendType(w, state, st.Elem())
- }
- return true
-}
-
-// sendType sends the type info to the other side, if necessary.
-func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Type) (sent bool) {
- ut := userType(origt)
- if ut.isGobEncoder {
- // The rules are different: regardless of the underlying type's representation,
- // we need to tell the other side that this exact type is a GobEncoder.
- return enc.sendActualType(w, state, ut, ut.user)
- }
-
- // It's a concrete value, so drill down to the base type.
- switch rt := ut.base; rt.Kind() {
- default:
- // Basic types and interfaces do not need to be described.
- return
- case reflect.Slice:
- // If it's []uint8, don't send; it's considered basic.
- if rt.Elem().Kind() == reflect.Uint8 {
- return
- }
- // Otherwise we do send.
- break
- case reflect.Array:
- // arrays must be sent so we know their lengths and element types.
- break
- case reflect.Map:
- // maps must be sent so we know their lengths and key/value types.
- break
- case reflect.Struct:
- // structs must be sent so we know their fields.
- break
- case reflect.Chan, reflect.Func:
- // Probably a bad field in a struct.
- enc.badType(rt)
- return
- }
-
- return enc.sendActualType(w, state, ut, ut.base)
-}
-
-// Encode transmits the data item represented by the empty interface value,
-// guaranteeing that all necessary type information has been transmitted first.
-func (enc *Encoder) Encode(e interface{}) os.Error {
- return enc.EncodeValue(reflect.ValueOf(e))
-}
-
-// sendTypeDescriptor makes sure the remote side knows about this type.
-// It will send a descriptor if this is the first time the type has been
-// sent.
-func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *userTypeInfo) {
- // Make sure the type is known to the other side.
- // First, have we already sent this type?
- rt := ut.base
- if ut.isGobEncoder {
- rt = ut.user
- }
- if _, alreadySent := enc.sent[rt]; !alreadySent {
- // No, so send it.
- sent := enc.sendType(w, state, rt)
- if enc.err != nil {
- return
- }
- // If the type info has still not been transmitted, it means we have
- // a singleton basic type (int, []byte etc.) at top level. We don't
- // need to send the type info but we do need to update enc.sent.
- if !sent {
- typeLock.Lock()
- info, err := getTypeInfo(ut)
- typeLock.Unlock()
- if err != nil {
- enc.setError(err)
- return
- }
- enc.sent[rt] = info.id
- }
- }
-}
-
-// sendTypeId sends the id, which must have already been defined.
-func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
- // Identify the type of this top-level value.
- state.encodeInt(int64(enc.sent[ut.base]))
-}
-
-// EncodeValue transmits the data item represented by the reflection value,
-// guaranteeing that all necessary type information has been transmitted first.
-func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
- // Make sure we're single-threaded through here, so multiple
- // goroutines can share an encoder.
- enc.mutex.Lock()
- defer enc.mutex.Unlock()
-
- // Remove any nested writers remaining due to previous errors.
- enc.w = enc.w[0:1]
-
- ut, err := validUserType(value.Type())
- if err != nil {
- return err
- }
-
- enc.err = nil
- enc.byteBuf.Reset()
- state := enc.newEncoderState(&enc.byteBuf)
-
- enc.sendTypeDescriptor(enc.writer(), state, ut)
- enc.sendTypeId(state, ut)
- if enc.err != nil {
- return enc.err
- }
-
- // Encode the object.
- enc.encode(state.b, value, ut)
- if enc.err == nil {
- enc.writeMessage(enc.writer(), state.b)
- }
-
- enc.freeEncoderState(state)
- return enc.err
-}
diff --git a/src/cmd/gofix/testdata/reflect.export.go.in b/src/cmd/gofix/testdata/reflect.export.go.in
deleted file mode 100644
index e91e777e3..000000000
--- a/src/cmd/gofix/testdata/reflect.export.go.in
+++ /dev/null
@@ -1,400 +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.
-
-/*
- The netchan package implements type-safe networked channels:
- it allows the two ends of a channel to appear on different
- computers connected by a network. It does this by transporting
- data sent to a channel on one machine so it can be recovered
- by a receive of a channel of the same type on the other.
-
- An exporter publishes a set of channels by name. An importer
- connects to the exporting machine and imports the channels
- by name. After importing the channels, the two machines can
- use the channels in the usual way.
-
- Networked channels are not synchronized; they always behave
- as if they are buffered channels of at least one element.
-*/
-package netchan
-
-// BUG: can't use range clause to receive when using ImportNValues to limit the count.
-
-import (
- "log"
- "io"
- "net"
- "os"
- "reflect"
- "strconv"
- "sync"
-)
-
-// Export
-
-// expLog is a logging convenience function. The first argument must be a string.
-func expLog(args ...interface{}) {
- args[0] = "netchan export: " + args[0].(string)
- log.Print(args...)
-}
-
-// An Exporter allows a set of channels to be published on a single
-// network port. A single machine may have multiple Exporters
-// but they must use different ports.
-type Exporter struct {
- *clientSet
-}
-
-type expClient struct {
- *encDec
- exp *Exporter
- chans map[int]*netChan // channels in use by client
- mu sync.Mutex // protects remaining fields
- errored bool // client has been sent an error
- seqNum int64 // sequences messages sent to client; has value of highest sent
- ackNum int64 // highest sequence number acknowledged
- seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
-}
-
-func newClient(exp *Exporter, conn io.ReadWriter) *expClient {
- client := new(expClient)
- client.exp = exp
- client.encDec = newEncDec(conn)
- client.seqNum = 0
- client.ackNum = 0
- client.chans = make(map[int]*netChan)
- return client
-}
-
-func (client *expClient) sendError(hdr *header, err string) {
- error := &error{err}
- expLog("sending error to client:", error.Error)
- client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
- client.mu.Lock()
- client.errored = true
- client.mu.Unlock()
-}
-
-func (client *expClient) newChan(hdr *header, dir Dir, name string, size int, count int64) *netChan {
- exp := client.exp
- exp.mu.Lock()
- ech, ok := exp.names[name]
- exp.mu.Unlock()
- if !ok {
- client.sendError(hdr, "no such channel: "+name)
- return nil
- }
- if ech.dir != dir {
- client.sendError(hdr, "wrong direction for channel: "+name)
- return nil
- }
- nch := newNetChan(name, hdr.Id, ech, client.encDec, size, count)
- client.chans[hdr.Id] = nch
- return nch
-}
-
-func (client *expClient) getChan(hdr *header, dir Dir) *netChan {
- nch := client.chans[hdr.Id]
- if nch == nil {
- return nil
- }
- if nch.dir != dir {
- client.sendError(hdr, "wrong direction for channel: "+nch.name)
- }
- return nch
-}
-
-// The function run manages sends and receives for a single client. For each
-// (client Recv) request, this will launch a serveRecv goroutine to deliver
-// the data for that channel, while (client Send) requests are handled as
-// data arrives from the client.
-func (client *expClient) run() {
- hdr := new(header)
- hdrValue := reflect.NewValue(hdr)
- req := new(request)
- reqValue := reflect.NewValue(req)
- error := new(error)
- for {
- *hdr = header{}
- if err := client.decode(hdrValue); err != nil {
- if err != os.EOF {
- expLog("error decoding client header:", err)
- }
- break
- }
- switch hdr.PayloadType {
- case payRequest:
- *req = request{}
- if err := client.decode(reqValue); err != nil {
- expLog("error decoding client request:", err)
- break
- }
- if req.Size < 1 {
- panic("netchan: remote requested " + strconv.Itoa(req.Size) + " values")
- }
- switch req.Dir {
- case Recv:
- // look up channel before calling serveRecv to
- // avoid a lock around client.chans.
- if nch := client.newChan(hdr, Send, req.Name, req.Size, req.Count); nch != nil {
- go client.serveRecv(nch, *hdr, req.Count)
- }
- case Send:
- client.newChan(hdr, Recv, req.Name, req.Size, req.Count)
- // The actual sends will have payload type payData.
- // TODO: manage the count?
- default:
- error.Error = "request: can't handle channel direction"
- expLog(error.Error, req.Dir)
- client.encode(hdr, payError, error)
- }
- case payData:
- client.serveSend(*hdr)
- case payClosed:
- client.serveClosed(*hdr)
- case payAck:
- client.mu.Lock()
- if client.ackNum != hdr.SeqNum-1 {
- // Since the sequence number is incremented and the message is sent
- // in a single instance of locking client.mu, the messages are guaranteed
- // to be sent in order. Therefore receipt of acknowledgement N means
- // all messages <=N have been seen by the recipient. We check anyway.
- expLog("sequence out of order:", client.ackNum, hdr.SeqNum)
- }
- if client.ackNum < hdr.SeqNum { // If there has been an error, don't back up the count.
- client.ackNum = hdr.SeqNum
- }
- client.mu.Unlock()
- case payAckSend:
- if nch := client.getChan(hdr, Send); nch != nil {
- nch.acked()
- }
- default:
- log.Fatal("netchan export: unknown payload type", hdr.PayloadType)
- }
- }
- client.exp.delClient(client)
-}
-
-// Send all the data on a single channel to a client asking for a Recv.
-// The header is passed by value to avoid issues of overwriting.
-func (client *expClient) serveRecv(nch *netChan, hdr header, count int64) {
- for {
- val, ok := nch.recv()
- if !ok {
- if err := client.encode(&hdr, payClosed, nil); err != nil {
- expLog("error encoding server closed message:", err)
- }
- break
- }
- // We hold the lock during transmission to guarantee messages are
- // sent in sequence number order. Also, we increment first so the
- // value of client.SeqNum is the value of the highest used sequence
- // number, not one beyond.
- client.mu.Lock()
- client.seqNum++
- hdr.SeqNum = client.seqNum
- client.seqLock.Lock() // guarantee ordering of messages
- client.mu.Unlock()
- err := client.encode(&hdr, payData, val.Interface())
- client.seqLock.Unlock()
- if err != nil {
- expLog("error encoding client response:", err)
- client.sendError(&hdr, err.String())
- break
- }
- // Negative count means run forever.
- if count >= 0 {
- if count--; count <= 0 {
- break
- }
- }
- }
-}
-
-// Receive and deliver locally one item from a client asking for a Send
-// The header is passed by value to avoid issues of overwriting.
-func (client *expClient) serveSend(hdr header) {
- nch := client.getChan(&hdr, Recv)
- if nch == nil {
- return
- }
- // Create a new value for each received item.
- val := reflect.MakeZero(nch.ch.Type().(*reflect.ChanType).Elem())
- if err := client.decode(val); err != nil {
- expLog("value decode:", err, "; type ", nch.ch.Type())
- return
- }
- nch.send(val)
-}
-
-// Report that client has closed the channel that is sending to us.
-// The header is passed by value to avoid issues of overwriting.
-func (client *expClient) serveClosed(hdr header) {
- nch := client.getChan(&hdr, Recv)
- if nch == nil {
- return
- }
- nch.close()
-}
-
-func (client *expClient) unackedCount() int64 {
- client.mu.Lock()
- n := client.seqNum - client.ackNum
- client.mu.Unlock()
- return n
-}
-
-func (client *expClient) seq() int64 {
- client.mu.Lock()
- n := client.seqNum
- client.mu.Unlock()
- return n
-}
-
-func (client *expClient) ack() int64 {
- client.mu.Lock()
- n := client.seqNum
- client.mu.Unlock()
- return n
-}
-
-// Serve waits for incoming connections on the listener
-// and serves the Exporter's channels on each.
-// It blocks until the listener is closed.
-func (exp *Exporter) Serve(listener net.Listener) {
- for {
- conn, err := listener.Accept()
- if err != nil {
- expLog("listen:", err)
- break
- }
- go exp.ServeConn(conn)
- }
-}
-
-// ServeConn exports the Exporter's channels on conn.
-// It blocks until the connection is terminated.
-func (exp *Exporter) ServeConn(conn io.ReadWriter) {
- exp.addClient(conn).run()
-}
-
-// NewExporter creates a new Exporter that exports a set of channels.
-func NewExporter() *Exporter {
- e := &Exporter{
- clientSet: &clientSet{
- names: make(map[string]*chanDir),
- clients: make(map[unackedCounter]bool),
- },
- }
- return e
-}
-
-// ListenAndServe exports the exporter's channels through the
-// given network and local address defined as in net.Listen.
-func (exp *Exporter) ListenAndServe(network, localaddr string) os.Error {
- listener, err := net.Listen(network, localaddr)
- if err != nil {
- return err
- }
- go exp.Serve(listener)
- return nil
-}
-
-// addClient creates a new expClient and records its existence
-func (exp *Exporter) addClient(conn io.ReadWriter) *expClient {
- client := newClient(exp, conn)
- exp.mu.Lock()
- exp.clients[client] = true
- exp.mu.Unlock()
- return client
-}
-
-// delClient forgets the client existed
-func (exp *Exporter) delClient(client *expClient) {
- exp.mu.Lock()
- exp.clients[client] = false, false
- exp.mu.Unlock()
-}
-
-// Drain waits until all messages sent from this exporter/importer, including
-// those not yet sent to any client and possibly including those sent while
-// Drain was executing, have been received by the importer. In short, it
-// waits until all the exporter's messages have been received by a client.
-// If the timeout (measured in nanoseconds) is positive and Drain takes
-// longer than that to complete, an error is returned.
-func (exp *Exporter) Drain(timeout int64) os.Error {
- // This wrapper function is here so the method's comment will appear in godoc.
- return exp.clientSet.drain(timeout)
-}
-
-// Sync waits until all clients of the exporter have received the messages
-// that were sent at the time Sync was invoked. Unlike Drain, it does not
-// wait for messages sent while it is running or messages that have not been
-// dispatched to any client. If the timeout (measured in nanoseconds) is
-// positive and Sync takes longer than that to complete, an error is
-// returned.
-func (exp *Exporter) Sync(timeout int64) os.Error {
- // This wrapper function is here so the method's comment will appear in godoc.
- return exp.clientSet.sync(timeout)
-}
-
-func checkChan(chT interface{}, dir Dir) (*reflect.ChanValue, os.Error) {
- chanType, ok := reflect.Typeof(chT).(*reflect.ChanType)
- if !ok {
- return nil, os.ErrorString("not a channel")
- }
- if dir != Send && dir != Recv {
- return nil, os.ErrorString("unknown channel direction")
- }
- switch chanType.Dir() {
- case reflect.BothDir:
- case reflect.SendDir:
- if dir != Recv {
- return nil, os.ErrorString("to import/export with Send, must provide <-chan")
- }
- case reflect.RecvDir:
- if dir != Send {
- return nil, os.ErrorString("to import/export with Recv, must provide chan<-")
- }
- }
- return reflect.NewValue(chT).(*reflect.ChanValue), nil
-}
-
-// Export exports a channel of a given type and specified direction. The
-// channel to be exported is provided in the call and may be of arbitrary
-// channel type.
-// Despite the literal signature, the effective signature is
-// Export(name string, chT chan T, dir Dir)
-func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
- ch, err := checkChan(chT, dir)
- if err != nil {
- return err
- }
- exp.mu.Lock()
- defer exp.mu.Unlock()
- _, present := exp.names[name]
- if present {
- return os.ErrorString("channel name already being exported:" + name)
- }
- exp.names[name] = &chanDir{ch, dir}
- return nil
-}
-
-// Hangup disassociates the named channel from the Exporter and closes
-// the channel. Messages in flight for the channel may be dropped.
-func (exp *Exporter) Hangup(name string) os.Error {
- exp.mu.Lock()
- chDir, ok := exp.names[name]
- if ok {
- exp.names[name] = nil, false
- }
- // TODO drop all instances of channel from client sets
- exp.mu.Unlock()
- if !ok {
- return os.ErrorString("netchan export: hangup: no such channel: " + name)
- }
- chDir.ch.Close()
- return nil
-}
diff --git a/src/cmd/gofix/testdata/reflect.export.go.out b/src/cmd/gofix/testdata/reflect.export.go.out
deleted file mode 100644
index 460edb40b..000000000
--- a/src/cmd/gofix/testdata/reflect.export.go.out
+++ /dev/null
@@ -1,400 +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.
-
-/*
- The netchan package implements type-safe networked channels:
- it allows the two ends of a channel to appear on different
- computers connected by a network. It does this by transporting
- data sent to a channel on one machine so it can be recovered
- by a receive of a channel of the same type on the other.
-
- An exporter publishes a set of channels by name. An importer
- connects to the exporting machine and imports the channels
- by name. After importing the channels, the two machines can
- use the channels in the usual way.
-
- Networked channels are not synchronized; they always behave
- as if they are buffered channels of at least one element.
-*/
-package netchan
-
-// BUG: can't use range clause to receive when using ImportNValues to limit the count.
-
-import (
- "log"
- "io"
- "net"
- "os"
- "reflect"
- "strconv"
- "sync"
-)
-
-// Export
-
-// expLog is a logging convenience function. The first argument must be a string.
-func expLog(args ...interface{}) {
- args[0] = "netchan export: " + args[0].(string)
- log.Print(args...)
-}
-
-// An Exporter allows a set of channels to be published on a single
-// network port. A single machine may have multiple Exporters
-// but they must use different ports.
-type Exporter struct {
- *clientSet
-}
-
-type expClient struct {
- *encDec
- exp *Exporter
- chans map[int]*netChan // channels in use by client
- mu sync.Mutex // protects remaining fields
- errored bool // client has been sent an error
- seqNum int64 // sequences messages sent to client; has value of highest sent
- ackNum int64 // highest sequence number acknowledged
- seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
-}
-
-func newClient(exp *Exporter, conn io.ReadWriter) *expClient {
- client := new(expClient)
- client.exp = exp
- client.encDec = newEncDec(conn)
- client.seqNum = 0
- client.ackNum = 0
- client.chans = make(map[int]*netChan)
- return client
-}
-
-func (client *expClient) sendError(hdr *header, err string) {
- error := &error{err}
- expLog("sending error to client:", error.Error)
- client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
- client.mu.Lock()
- client.errored = true
- client.mu.Unlock()
-}
-
-func (client *expClient) newChan(hdr *header, dir Dir, name string, size int, count int64) *netChan {
- exp := client.exp
- exp.mu.Lock()
- ech, ok := exp.names[name]
- exp.mu.Unlock()
- if !ok {
- client.sendError(hdr, "no such channel: "+name)
- return nil
- }
- if ech.dir != dir {
- client.sendError(hdr, "wrong direction for channel: "+name)
- return nil
- }
- nch := newNetChan(name, hdr.Id, ech, client.encDec, size, count)
- client.chans[hdr.Id] = nch
- return nch
-}
-
-func (client *expClient) getChan(hdr *header, dir Dir) *netChan {
- nch := client.chans[hdr.Id]
- if nch == nil {
- return nil
- }
- if nch.dir != dir {
- client.sendError(hdr, "wrong direction for channel: "+nch.name)
- }
- return nch
-}
-
-// The function run manages sends and receives for a single client. For each
-// (client Recv) request, this will launch a serveRecv goroutine to deliver
-// the data for that channel, while (client Send) requests are handled as
-// data arrives from the client.
-func (client *expClient) run() {
- hdr := new(header)
- hdrValue := reflect.ValueOf(hdr)
- req := new(request)
- reqValue := reflect.ValueOf(req)
- error := new(error)
- for {
- *hdr = header{}
- if err := client.decode(hdrValue); err != nil {
- if err != os.EOF {
- expLog("error decoding client header:", err)
- }
- break
- }
- switch hdr.PayloadType {
- case payRequest:
- *req = request{}
- if err := client.decode(reqValue); err != nil {
- expLog("error decoding client request:", err)
- break
- }
- if req.Size < 1 {
- panic("netchan: remote requested " + strconv.Itoa(req.Size) + " values")
- }
- switch req.Dir {
- case Recv:
- // look up channel before calling serveRecv to
- // avoid a lock around client.chans.
- if nch := client.newChan(hdr, Send, req.Name, req.Size, req.Count); nch != nil {
- go client.serveRecv(nch, *hdr, req.Count)
- }
- case Send:
- client.newChan(hdr, Recv, req.Name, req.Size, req.Count)
- // The actual sends will have payload type payData.
- // TODO: manage the count?
- default:
- error.Error = "request: can't handle channel direction"
- expLog(error.Error, req.Dir)
- client.encode(hdr, payError, error)
- }
- case payData:
- client.serveSend(*hdr)
- case payClosed:
- client.serveClosed(*hdr)
- case payAck:
- client.mu.Lock()
- if client.ackNum != hdr.SeqNum-1 {
- // Since the sequence number is incremented and the message is sent
- // in a single instance of locking client.mu, the messages are guaranteed
- // to be sent in order. Therefore receipt of acknowledgement N means
- // all messages <=N have been seen by the recipient. We check anyway.
- expLog("sequence out of order:", client.ackNum, hdr.SeqNum)
- }
- if client.ackNum < hdr.SeqNum { // If there has been an error, don't back up the count.
- client.ackNum = hdr.SeqNum
- }
- client.mu.Unlock()
- case payAckSend:
- if nch := client.getChan(hdr, Send); nch != nil {
- nch.acked()
- }
- default:
- log.Fatal("netchan export: unknown payload type", hdr.PayloadType)
- }
- }
- client.exp.delClient(client)
-}
-
-// Send all the data on a single channel to a client asking for a Recv.
-// The header is passed by value to avoid issues of overwriting.
-func (client *expClient) serveRecv(nch *netChan, hdr header, count int64) {
- for {
- val, ok := nch.recv()
- if !ok {
- if err := client.encode(&hdr, payClosed, nil); err != nil {
- expLog("error encoding server closed message:", err)
- }
- break
- }
- // We hold the lock during transmission to guarantee messages are
- // sent in sequence number order. Also, we increment first so the
- // value of client.SeqNum is the value of the highest used sequence
- // number, not one beyond.
- client.mu.Lock()
- client.seqNum++
- hdr.SeqNum = client.seqNum
- client.seqLock.Lock() // guarantee ordering of messages
- client.mu.Unlock()
- err := client.encode(&hdr, payData, val.Interface())
- client.seqLock.Unlock()
- if err != nil {
- expLog("error encoding client response:", err)
- client.sendError(&hdr, err.String())
- break
- }
- // Negative count means run forever.
- if count >= 0 {
- if count--; count <= 0 {
- break
- }
- }
- }
-}
-
-// Receive and deliver locally one item from a client asking for a Send
-// The header is passed by value to avoid issues of overwriting.
-func (client *expClient) serveSend(hdr header) {
- nch := client.getChan(&hdr, Recv)
- if nch == nil {
- return
- }
- // Create a new value for each received item.
- val := reflect.Zero(nch.ch.Type().Elem())
- if err := client.decode(val); err != nil {
- expLog("value decode:", err, "; type ", nch.ch.Type())
- return
- }
- nch.send(val)
-}
-
-// Report that client has closed the channel that is sending to us.
-// The header is passed by value to avoid issues of overwriting.
-func (client *expClient) serveClosed(hdr header) {
- nch := client.getChan(&hdr, Recv)
- if nch == nil {
- return
- }
- nch.close()
-}
-
-func (client *expClient) unackedCount() int64 {
- client.mu.Lock()
- n := client.seqNum - client.ackNum
- client.mu.Unlock()
- return n
-}
-
-func (client *expClient) seq() int64 {
- client.mu.Lock()
- n := client.seqNum
- client.mu.Unlock()
- return n
-}
-
-func (client *expClient) ack() int64 {
- client.mu.Lock()
- n := client.seqNum
- client.mu.Unlock()
- return n
-}
-
-// Serve waits for incoming connections on the listener
-// and serves the Exporter's channels on each.
-// It blocks until the listener is closed.
-func (exp *Exporter) Serve(listener net.Listener) {
- for {
- conn, err := listener.Accept()
- if err != nil {
- expLog("listen:", err)
- break
- }
- go exp.ServeConn(conn)
- }
-}
-
-// ServeConn exports the Exporter's channels on conn.
-// It blocks until the connection is terminated.
-func (exp *Exporter) ServeConn(conn io.ReadWriter) {
- exp.addClient(conn).run()
-}
-
-// NewExporter creates a new Exporter that exports a set of channels.
-func NewExporter() *Exporter {
- e := &Exporter{
- clientSet: &clientSet{
- names: make(map[string]*chanDir),
- clients: make(map[unackedCounter]bool),
- },
- }
- return e
-}
-
-// ListenAndServe exports the exporter's channels through the
-// given network and local address defined as in net.Listen.
-func (exp *Exporter) ListenAndServe(network, localaddr string) os.Error {
- listener, err := net.Listen(network, localaddr)
- if err != nil {
- return err
- }
- go exp.Serve(listener)
- return nil
-}
-
-// addClient creates a new expClient and records its existence
-func (exp *Exporter) addClient(conn io.ReadWriter) *expClient {
- client := newClient(exp, conn)
- exp.mu.Lock()
- exp.clients[client] = true
- exp.mu.Unlock()
- return client
-}
-
-// delClient forgets the client existed
-func (exp *Exporter) delClient(client *expClient) {
- exp.mu.Lock()
- exp.clients[client] = false, false
- exp.mu.Unlock()
-}
-
-// Drain waits until all messages sent from this exporter/importer, including
-// those not yet sent to any client and possibly including those sent while
-// Drain was executing, have been received by the importer. In short, it
-// waits until all the exporter's messages have been received by a client.
-// If the timeout (measured in nanoseconds) is positive and Drain takes
-// longer than that to complete, an error is returned.
-func (exp *Exporter) Drain(timeout int64) os.Error {
- // This wrapper function is here so the method's comment will appear in godoc.
- return exp.clientSet.drain(timeout)
-}
-
-// Sync waits until all clients of the exporter have received the messages
-// that were sent at the time Sync was invoked. Unlike Drain, it does not
-// wait for messages sent while it is running or messages that have not been
-// dispatched to any client. If the timeout (measured in nanoseconds) is
-// positive and Sync takes longer than that to complete, an error is
-// returned.
-func (exp *Exporter) Sync(timeout int64) os.Error {
- // This wrapper function is here so the method's comment will appear in godoc.
- return exp.clientSet.sync(timeout)
-}
-
-func checkChan(chT interface{}, dir Dir) (reflect.Value, os.Error) {
- chanType := reflect.TypeOf(chT)
- if chanType.Kind() != reflect.Chan {
- return reflect.Value{}, os.NewError("not a channel")
- }
- if dir != Send && dir != Recv {
- return reflect.Value{}, os.NewError("unknown channel direction")
- }
- switch chanType.ChanDir() {
- case reflect.BothDir:
- case reflect.SendDir:
- if dir != Recv {
- return reflect.Value{}, os.NewError("to import/export with Send, must provide <-chan")
- }
- case reflect.RecvDir:
- if dir != Send {
- return reflect.Value{}, os.NewError("to import/export with Recv, must provide chan<-")
- }
- }
- return reflect.ValueOf(chT), nil
-}
-
-// Export exports a channel of a given type and specified direction. The
-// channel to be exported is provided in the call and may be of arbitrary
-// channel type.
-// Despite the literal signature, the effective signature is
-// Export(name string, chT chan T, dir Dir)
-func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
- ch, err := checkChan(chT, dir)
- if err != nil {
- return err
- }
- exp.mu.Lock()
- defer exp.mu.Unlock()
- _, present := exp.names[name]
- if present {
- return os.NewError("channel name already being exported:" + name)
- }
- exp.names[name] = &chanDir{ch, dir}
- return nil
-}
-
-// Hangup disassociates the named channel from the Exporter and closes
-// the channel. Messages in flight for the channel may be dropped.
-func (exp *Exporter) Hangup(name string) os.Error {
- exp.mu.Lock()
- chDir, ok := exp.names[name]
- if ok {
- exp.names[name] = nil, false
- }
- // TODO drop all instances of channel from client sets
- exp.mu.Unlock()
- if !ok {
- return os.NewError("netchan export: hangup: no such channel: " + name)
- }
- chDir.ch.Close()
- return nil
-}
diff --git a/src/cmd/gofix/testdata/reflect.print.go.in b/src/cmd/gofix/testdata/reflect.print.go.in
deleted file mode 100644
index 194bcdb3b..000000000
--- a/src/cmd/gofix/testdata/reflect.print.go.in
+++ /dev/null
@@ -1,945 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package fmt
-
-import (
- "bytes"
- "io"
- "os"
- "reflect"
- "utf8"
-)
-
-// Some constants in the form of bytes, to avoid string overhead.
-// Needlessly fastidious, I suppose.
-var (
- commaSpaceBytes = []byte(", ")
- nilAngleBytes = []byte("<nil>")
- nilParenBytes = []byte("(nil)")
- nilBytes = []byte("nil")
- mapBytes = []byte("map[")
- missingBytes = []byte("(MISSING)")
- extraBytes = []byte("%!(EXTRA ")
- irparenBytes = []byte("i)")
- bytesBytes = []byte("[]byte{")
- widthBytes = []byte("%!(BADWIDTH)")
- precBytes = []byte("%!(BADPREC)")
- noVerbBytes = []byte("%!(NOVERB)")
-)
-
-// State represents the printer state passed to custom formatters.
-// It provides access to the io.Writer interface plus information about
-// the flags and options for the operand's format specifier.
-type State interface {
- // Write is the function to call to emit formatted output to be printed.
- Write(b []byte) (ret int, err os.Error)
- // Width returns the value of the width option and whether it has been set.
- Width() (wid int, ok bool)
- // Precision returns the value of the precision option and whether it has been set.
- Precision() (prec int, ok bool)
-
- // Flag returns whether the flag c, a character, has been set.
- Flag(int) bool
-}
-
-// Formatter is the interface implemented by values with a custom formatter.
-// The implementation of Format may call Sprintf or Fprintf(f) etc.
-// to generate its output.
-type Formatter interface {
- Format(f State, c int)
-}
-
-// Stringer is implemented by any value that has a String method(),
-// which defines the ``native'' format for that value.
-// The String method is used to print values passed as an operand
-// to a %s or %v format or to an unformatted printer such as Print.
-type Stringer interface {
- String() string
-}
-
-// GoStringer is implemented by any value that has a GoString() method,
-// which defines the Go syntax for that value.
-// The GoString method is used to print values passed as an operand
-// to a %#v format.
-type GoStringer interface {
- GoString() string
-}
-
-type pp struct {
- n int
- buf bytes.Buffer
- runeBuf [utf8.UTFMax]byte
- fmt fmt
-}
-
-// A cache holds a set of reusable objects.
-// The buffered channel holds the currently available objects.
-// If more are needed, the cache creates them by calling new.
-type cache struct {
- saved chan interface{}
- new func() interface{}
-}
-
-func (c *cache) put(x interface{}) {
- select {
- case c.saved <- x:
- // saved in cache
- default:
- // discard
- }
-}
-
-func (c *cache) get() interface{} {
- select {
- case x := <-c.saved:
- return x // reused from cache
- default:
- return c.new()
- }
- panic("not reached")
-}
-
-func newCache(f func() interface{}) *cache {
- return &cache{make(chan interface{}, 100), f}
-}
-
-var ppFree = newCache(func() interface{} { return new(pp) })
-
-// Allocate a new pp struct or grab a cached one.
-func newPrinter() *pp {
- p := ppFree.get().(*pp)
- p.fmt.init(&p.buf)
- return p
-}
-
-// Save used pp structs in ppFree; avoids an allocation per invocation.
-func (p *pp) free() {
- // Don't hold on to pp structs with large buffers.
- if cap(p.buf.Bytes()) > 1024 {
- return
- }
- p.buf.Reset()
- ppFree.put(p)
-}
-
-func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
-
-func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
-
-func (p *pp) Flag(b int) bool {
- switch b {
- case '-':
- return p.fmt.minus
- case '+':
- return p.fmt.plus
- case '#':
- return p.fmt.sharp
- case ' ':
- return p.fmt.space
- case '0':
- return p.fmt.zero
- }
- return false
-}
-
-func (p *pp) add(c int) {
- p.buf.WriteRune(c)
-}
-
-// Implement Write so we can call Fprintf on a pp (through State), for
-// recursive use in custom verbs.
-func (p *pp) Write(b []byte) (ret int, err os.Error) {
- return p.buf.Write(b)
-}
-
-// These routines end in 'f' and take a format string.
-
-// Fprintf formats according to a format specifier and writes to w.
-// It returns the number of bytes written and any write error encountered.
-func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Error) {
- p := newPrinter()
- p.doPrintf(format, a)
- n64, error := p.buf.WriteTo(w)
- p.free()
- return int(n64), error
-}
-
-// Printf formats according to a format specifier and writes to standard output.
-// It returns the number of bytes written and any write error encountered.
-func Printf(format string, a ...interface{}) (n int, errno os.Error) {
- n, errno = Fprintf(os.Stdout, format, a...)
- return n, errno
-}
-
-// Sprintf formats according to a format specifier and returns the resulting string.
-func Sprintf(format string, a ...interface{}) string {
- p := newPrinter()
- p.doPrintf(format, a)
- s := p.buf.String()
- p.free()
- return s
-}
-
-// Errorf formats according to a format specifier and returns the string
-// converted to an os.ErrorString, which satisfies the os.Error interface.
-func Errorf(format string, a ...interface{}) os.Error {
- return os.ErrorString(Sprintf(format, a...))
-}
-
-// These routines do not take a format string
-
-// Fprint formats using the default formats for its operands and writes to w.
-// Spaces are added between operands when neither is a string.
-// It returns the number of bytes written and any write error encountered.
-func Fprint(w io.Writer, a ...interface{}) (n int, error os.Error) {
- p := newPrinter()
- p.doPrint(a, false, false)
- n64, error := p.buf.WriteTo(w)
- p.free()
- return int(n64), error
-}
-
-// Print formats using the default formats for its operands and writes to standard output.
-// Spaces are added between operands when neither is a string.
-// It returns the number of bytes written and any write error encountered.
-func Print(a ...interface{}) (n int, errno os.Error) {
- n, errno = Fprint(os.Stdout, a...)
- return n, errno
-}
-
-// Sprint formats using the default formats for its operands and returns the resulting string.
-// Spaces are added between operands when neither is a string.
-func Sprint(a ...interface{}) string {
- p := newPrinter()
- p.doPrint(a, false, false)
- s := p.buf.String()
- p.free()
- return s
-}
-
-// These routines end in 'ln', do not take a format string,
-// always add spaces between operands, and add a newline
-// after the last operand.
-
-// Fprintln formats using the default formats for its operands and writes to w.
-// Spaces are always added between operands and a newline is appended.
-// It returns the number of bytes written and any write error encountered.
-func Fprintln(w io.Writer, a ...interface{}) (n int, error os.Error) {
- p := newPrinter()
- p.doPrint(a, true, true)
- n64, error := p.buf.WriteTo(w)
- p.free()
- return int(n64), error
-}
-
-// Println formats using the default formats for its operands and writes to standard output.
-// Spaces are always added between operands and a newline is appended.
-// It returns the number of bytes written and any write error encountered.
-func Println(a ...interface{}) (n int, errno os.Error) {
- n, errno = Fprintln(os.Stdout, a...)
- return n, errno
-}
-
-// Sprintln formats using the default formats for its operands and returns the resulting string.
-// Spaces are always added between operands and a newline is appended.
-func Sprintln(a ...interface{}) string {
- p := newPrinter()
- p.doPrint(a, true, true)
- s := p.buf.String()
- p.free()
- return s
-}
-
-
-// Get the i'th arg of the struct value.
-// If the arg itself is an interface, return a value for
-// the thing inside the interface, not the interface itself.
-func getField(v *reflect.StructValue, i int) reflect.Value {
- val := v.Field(i)
- if i, ok := val.(*reflect.InterfaceValue); ok {
- if inter := i.Interface(); inter != nil {
- return reflect.NewValue(inter)
- }
- }
- return val
-}
-
-// Convert ASCII to integer. n is 0 (and got is false) if no number present.
-func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
- if start >= end {
- return 0, false, end
- }
- for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
- num = num*10 + int(s[newi]-'0')
- isnum = true
- }
- return
-}
-
-func (p *pp) unknownType(v interface{}) {
- if v == nil {
- p.buf.Write(nilAngleBytes)
- return
- }
- p.buf.WriteByte('?')
- p.buf.WriteString(reflect.Typeof(v).String())
- p.buf.WriteByte('?')
-}
-
-func (p *pp) badVerb(verb int, val interface{}) {
- p.add('%')
- p.add('!')
- p.add(verb)
- p.add('(')
- if val == nil {
- p.buf.Write(nilAngleBytes)
- } else {
- p.buf.WriteString(reflect.Typeof(val).String())
- p.add('=')
- p.printField(val, 'v', false, false, 0)
- }
- p.add(')')
-}
-
-func (p *pp) fmtBool(v bool, verb int, value interface{}) {
- switch verb {
- case 't', 'v':
- p.fmt.fmt_boolean(v)
- default:
- p.badVerb(verb, value)
- }
-}
-
-// fmtC formats a rune for the 'c' format.
-func (p *pp) fmtC(c int64) {
- rune := int(c) // Check for overflow.
- if int64(rune) != c {
- rune = utf8.RuneError
- }
- w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune)
- p.fmt.pad(p.runeBuf[0:w])
-}
-
-func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
- switch verb {
- case 'b':
- p.fmt.integer(v, 2, signed, ldigits)
- case 'c':
- p.fmtC(v)
- case 'd', 'v':
- p.fmt.integer(v, 10, signed, ldigits)
- case 'o':
- p.fmt.integer(v, 8, signed, ldigits)
- case 'x':
- p.fmt.integer(v, 16, signed, ldigits)
- case 'U':
- p.fmtUnicode(v)
- case 'X':
- p.fmt.integer(v, 16, signed, udigits)
- default:
- p.badVerb(verb, value)
- }
-}
-
-// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
-// not, as requested, by temporarily setting the sharp flag.
-func (p *pp) fmt0x64(v uint64, leading0x bool) {
- sharp := p.fmt.sharp
- p.fmt.sharp = leading0x
- p.fmt.integer(int64(v), 16, unsigned, ldigits)
- p.fmt.sharp = sharp
-}
-
-// fmtUnicode formats a uint64 in U+1234 form by
-// temporarily turning on the unicode flag and tweaking the precision.
-func (p *pp) fmtUnicode(v int64) {
- precPresent := p.fmt.precPresent
- prec := p.fmt.prec
- if !precPresent {
- // If prec is already set, leave it alone; otherwise 4 is minimum.
- p.fmt.prec = 4
- p.fmt.precPresent = true
- }
- p.fmt.unicode = true // turn on U+
- p.fmt.integer(int64(v), 16, unsigned, udigits)
- p.fmt.unicode = false
- p.fmt.prec = prec
- p.fmt.precPresent = precPresent
-}
-
-func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
- switch verb {
- case 'b':
- p.fmt.integer(int64(v), 2, unsigned, ldigits)
- case 'c':
- p.fmtC(int64(v))
- case 'd':
- p.fmt.integer(int64(v), 10, unsigned, ldigits)
- case 'v':
- if goSyntax {
- p.fmt0x64(v, true)
- } else {
- p.fmt.integer(int64(v), 10, unsigned, ldigits)
- }
- case 'o':
- p.fmt.integer(int64(v), 8, unsigned, ldigits)
- case 'x':
- p.fmt.integer(int64(v), 16, unsigned, ldigits)
- case 'X':
- p.fmt.integer(int64(v), 16, unsigned, udigits)
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
- switch verb {
- case 'b':
- p.fmt.fmt_fb32(v)
- case 'e':
- p.fmt.fmt_e32(v)
- case 'E':
- p.fmt.fmt_E32(v)
- case 'f':
- p.fmt.fmt_f32(v)
- case 'g', 'v':
- p.fmt.fmt_g32(v)
- case 'G':
- p.fmt.fmt_G32(v)
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
- switch verb {
- case 'b':
- p.fmt.fmt_fb64(v)
- case 'e':
- p.fmt.fmt_e64(v)
- case 'E':
- p.fmt.fmt_E64(v)
- case 'f':
- p.fmt.fmt_f64(v)
- case 'g', 'v':
- p.fmt.fmt_g64(v)
- case 'G':
- p.fmt.fmt_G64(v)
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
- switch verb {
- case 'e', 'E', 'f', 'F', 'g', 'G':
- p.fmt.fmt_c64(v, verb)
- case 'v':
- p.fmt.fmt_c64(v, 'g')
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
- switch verb {
- case 'e', 'E', 'f', 'F', 'g', 'G':
- p.fmt.fmt_c128(v, verb)
- case 'v':
- p.fmt.fmt_c128(v, 'g')
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
- switch verb {
- case 'v':
- if goSyntax {
- p.fmt.fmt_q(v)
- } else {
- p.fmt.fmt_s(v)
- }
- case 's':
- p.fmt.fmt_s(v)
- case 'x':
- p.fmt.fmt_sx(v)
- case 'X':
- p.fmt.fmt_sX(v)
- case 'q':
- p.fmt.fmt_q(v)
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) {
- if verb == 'v' || verb == 'd' {
- if goSyntax {
- p.buf.Write(bytesBytes)
- } else {
- p.buf.WriteByte('[')
- }
- for i, c := range v {
- if i > 0 {
- if goSyntax {
- p.buf.Write(commaSpaceBytes)
- } else {
- p.buf.WriteByte(' ')
- }
- }
- p.printField(c, 'v', p.fmt.plus, goSyntax, depth+1)
- }
- if goSyntax {
- p.buf.WriteByte('}')
- } else {
- p.buf.WriteByte(']')
- }
- return
- }
- s := string(v)
- switch verb {
- case 's':
- p.fmt.fmt_s(s)
- case 'x':
- p.fmt.fmt_sx(s)
- case 'X':
- p.fmt.fmt_sX(s)
- case 'q':
- p.fmt.fmt_q(s)
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
- var u uintptr
- switch value.(type) {
- case *reflect.ChanValue, *reflect.FuncValue, *reflect.MapValue, *reflect.PtrValue, *reflect.SliceValue, *reflect.UnsafePointerValue:
- u = value.Pointer()
- default:
- p.badVerb(verb, field)
- return
- }
- if goSyntax {
- p.add('(')
- p.buf.WriteString(reflect.Typeof(field).String())
- p.add(')')
- p.add('(')
- if u == 0 {
- p.buf.Write(nilBytes)
- } else {
- p.fmt0x64(uint64(u), true)
- }
- p.add(')')
- } else {
- p.fmt0x64(uint64(u), !p.fmt.sharp)
- }
-}
-
-var (
- intBits = reflect.Typeof(0).Bits()
- floatBits = reflect.Typeof(0.0).Bits()
- complexBits = reflect.Typeof(1i).Bits()
- uintptrBits = reflect.Typeof(uintptr(0)).Bits()
-)
-
-func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
- if field == nil {
- if verb == 'T' || verb == 'v' {
- p.buf.Write(nilAngleBytes)
- } else {
- p.badVerb(verb, field)
- }
- return false
- }
-
- // Special processing considerations.
- // %T (the value's type) and %p (its address) are special; we always do them first.
- switch verb {
- case 'T':
- p.printField(reflect.Typeof(field).String(), 's', false, false, 0)
- return false
- case 'p':
- p.fmtPointer(field, reflect.NewValue(field), verb, goSyntax)
- return false
- }
- // Is it a Formatter?
- if formatter, ok := field.(Formatter); ok {
- formatter.Format(p, verb)
- return false // this value is not a string
-
- }
- // Must not touch flags before Formatter looks at them.
- if plus {
- p.fmt.plus = false
- }
- // If we're doing Go syntax and the field knows how to supply it, take care of it now.
- if goSyntax {
- p.fmt.sharp = false
- if stringer, ok := field.(GoStringer); ok {
- // Print the result of GoString unadorned.
- p.fmtString(stringer.GoString(), 's', false, field)
- return false // this value is not a string
- }
- } else {
- // Is it a Stringer?
- if stringer, ok := field.(Stringer); ok {
- p.printField(stringer.String(), verb, plus, false, depth)
- return false // this value is not a string
- }
- }
-
- // Some types can be done without reflection.
- switch f := field.(type) {
- case bool:
- p.fmtBool(f, verb, field)
- return false
- case float32:
- p.fmtFloat32(f, verb, field)
- return false
- case float64:
- p.fmtFloat64(f, verb, field)
- return false
- case complex64:
- p.fmtComplex64(complex64(f), verb, field)
- return false
- case complex128:
- p.fmtComplex128(f, verb, field)
- return false
- case int:
- p.fmtInt64(int64(f), verb, field)
- return false
- case int8:
- p.fmtInt64(int64(f), verb, field)
- return false
- case int16:
- p.fmtInt64(int64(f), verb, field)
- return false
- case int32:
- p.fmtInt64(int64(f), verb, field)
- return false
- case int64:
- p.fmtInt64(f, verb, field)
- return false
- case uint:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
- case uint8:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
- case uint16:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
- case uint32:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
- case uint64:
- p.fmtUint64(f, verb, goSyntax, field)
- return false
- case uintptr:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
- case string:
- p.fmtString(f, verb, goSyntax, field)
- return verb == 's' || verb == 'v'
- case []byte:
- p.fmtBytes(f, verb, goSyntax, depth, field)
- return verb == 's'
- }
-
- // Need to use reflection
- value := reflect.NewValue(field)
-
-BigSwitch:
- switch f := value.(type) {
- case *reflect.BoolValue:
- p.fmtBool(f.Get(), verb, field)
- case *reflect.IntValue:
- p.fmtInt64(f.Get(), verb, field)
- case *reflect.UintValue:
- p.fmtUint64(uint64(f.Get()), verb, goSyntax, field)
- case *reflect.FloatValue:
- if f.Type().Size() == 4 {
- p.fmtFloat32(float32(f.Get()), verb, field)
- } else {
- p.fmtFloat64(float64(f.Get()), verb, field)
- }
- case *reflect.ComplexValue:
- if f.Type().Size() == 8 {
- p.fmtComplex64(complex64(f.Get()), verb, field)
- } else {
- p.fmtComplex128(complex128(f.Get()), verb, field)
- }
- case *reflect.StringValue:
- p.fmtString(f.Get(), verb, goSyntax, field)
- case *reflect.MapValue:
- if goSyntax {
- p.buf.WriteString(f.Type().String())
- p.buf.WriteByte('{')
- } else {
- p.buf.Write(mapBytes)
- }
- keys := f.Keys()
- for i, key := range keys {
- if i > 0 {
- if goSyntax {
- p.buf.Write(commaSpaceBytes)
- } else {
- p.buf.WriteByte(' ')
- }
- }
- p.printField(key.Interface(), verb, plus, goSyntax, depth+1)
- p.buf.WriteByte(':')
- p.printField(f.Elem(key).Interface(), verb, plus, goSyntax, depth+1)
- }
- if goSyntax {
- p.buf.WriteByte('}')
- } else {
- p.buf.WriteByte(']')
- }
- case *reflect.StructValue:
- if goSyntax {
- p.buf.WriteString(reflect.Typeof(field).String())
- }
- p.add('{')
- v := f
- t := v.Type().(*reflect.StructType)
- for i := 0; i < v.NumField(); i++ {
- if i > 0 {
- if goSyntax {
- p.buf.Write(commaSpaceBytes)
- } else {
- p.buf.WriteByte(' ')
- }
- }
- if plus || goSyntax {
- if f := t.Field(i); f.Name != "" {
- p.buf.WriteString(f.Name)
- p.buf.WriteByte(':')
- }
- }
- p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1)
- }
- p.buf.WriteByte('}')
- case *reflect.InterfaceValue:
- value := f.Elem()
- if value == nil {
- if goSyntax {
- p.buf.WriteString(reflect.Typeof(field).String())
- p.buf.Write(nilParenBytes)
- } else {
- p.buf.Write(nilAngleBytes)
- }
- } else {
- return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
- }
- case reflect.ArrayOrSliceValue:
- // Byte slices are special.
- if f.Type().(reflect.ArrayOrSliceType).Elem().Kind() == reflect.Uint8 {
- // We know it's a slice of bytes, but we also know it does not have static type
- // []byte, or it would have been caught above. Therefore we cannot convert
- // it directly in the (slightly) obvious way: f.Interface().([]byte); it doesn't have
- // that type, and we can't write an expression of the right type and do a
- // conversion because we don't have a static way to write the right type.
- // So we build a slice by hand. This is a rare case but it would be nice
- // if reflection could help a little more.
- bytes := make([]byte, f.Len())
- for i := range bytes {
- bytes[i] = byte(f.Elem(i).(*reflect.UintValue).Get())
- }
- p.fmtBytes(bytes, verb, goSyntax, depth, field)
- return verb == 's'
- }
- if goSyntax {
- p.buf.WriteString(reflect.Typeof(field).String())
- p.buf.WriteByte('{')
- } else {
- p.buf.WriteByte('[')
- }
- for i := 0; i < f.Len(); i++ {
- if i > 0 {
- if goSyntax {
- p.buf.Write(commaSpaceBytes)
- } else {
- p.buf.WriteByte(' ')
- }
- }
- p.printField(f.Elem(i).Interface(), verb, plus, goSyntax, depth+1)
- }
- if goSyntax {
- p.buf.WriteByte('}')
- } else {
- p.buf.WriteByte(']')
- }
- case *reflect.PtrValue:
- v := f.Get()
- // pointer to array or slice or struct? ok at top level
- // but not embedded (avoid loops)
- if v != 0 && depth == 0 {
- switch a := f.Elem().(type) {
- case reflect.ArrayOrSliceValue:
- p.buf.WriteByte('&')
- p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
- break BigSwitch
- case *reflect.StructValue:
- p.buf.WriteByte('&')
- p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
- break BigSwitch
- }
- }
- if goSyntax {
- p.buf.WriteByte('(')
- p.buf.WriteString(reflect.Typeof(field).String())
- p.buf.WriteByte(')')
- p.buf.WriteByte('(')
- if v == 0 {
- p.buf.Write(nilBytes)
- } else {
- p.fmt0x64(uint64(v), true)
- }
- p.buf.WriteByte(')')
- break
- }
- if v == 0 {
- p.buf.Write(nilAngleBytes)
- break
- }
- p.fmt0x64(uint64(v), true)
- case *reflect.ChanValue, *reflect.FuncValue, *reflect.UnsafePointerValue:
- p.fmtPointer(field, value, verb, goSyntax)
- default:
- p.unknownType(f)
- }
- return false
-}
-
-// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
-func intFromArg(a []interface{}, end, i, fieldnum int) (num int, isInt bool, newi, newfieldnum int) {
- newi, newfieldnum = end, fieldnum
- if i < end && fieldnum < len(a) {
- num, isInt = a[fieldnum].(int)
- newi, newfieldnum = i+1, fieldnum+1
- }
- return
-}
-
-func (p *pp) doPrintf(format string, a []interface{}) {
- end := len(format)
- fieldnum := 0 // we process one field per non-trivial format
- for i := 0; i < end; {
- lasti := i
- for i < end && format[i] != '%' {
- i++
- }
- if i > lasti {
- p.buf.WriteString(format[lasti:i])
- }
- if i >= end {
- // done processing format string
- break
- }
-
- // Process one verb
- i++
- // flags and widths
- p.fmt.clearflags()
- F:
- for ; i < end; i++ {
- switch format[i] {
- case '#':
- p.fmt.sharp = true
- case '0':
- p.fmt.zero = true
- case '+':
- p.fmt.plus = true
- case '-':
- p.fmt.minus = true
- case ' ':
- p.fmt.space = true
- default:
- break F
- }
- }
- // do we have width?
- if i < end && format[i] == '*' {
- p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
- if !p.fmt.widPresent {
- p.buf.Write(widthBytes)
- }
- } else {
- p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
- }
- // do we have precision?
- if i < end && format[i] == '.' {
- if format[i+1] == '*' {
- p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
- if !p.fmt.precPresent {
- p.buf.Write(precBytes)
- }
- } else {
- p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
- }
- }
- if i >= end {
- p.buf.Write(noVerbBytes)
- continue
- }
- c, w := utf8.DecodeRuneInString(format[i:])
- i += w
- // percent is special - absorbs no operand
- if c == '%' {
- p.buf.WriteByte('%') // We ignore width and prec.
- continue
- }
- if fieldnum >= len(a) { // out of operands
- p.buf.WriteByte('%')
- p.add(c)
- p.buf.Write(missingBytes)
- continue
- }
- field := a[fieldnum]
- fieldnum++
-
- goSyntax := c == 'v' && p.fmt.sharp
- plus := c == 'v' && p.fmt.plus
- p.printField(field, c, plus, goSyntax, 0)
- }
-
- if fieldnum < len(a) {
- p.buf.Write(extraBytes)
- for ; fieldnum < len(a); fieldnum++ {
- field := a[fieldnum]
- if field != nil {
- p.buf.WriteString(reflect.Typeof(field).String())
- p.buf.WriteByte('=')
- }
- p.printField(field, 'v', false, false, 0)
- if fieldnum+1 < len(a) {
- p.buf.Write(commaSpaceBytes)
- }
- }
- p.buf.WriteByte(')')
- }
-}
-
-func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
- prevString := false
- for fieldnum := 0; fieldnum < len(a); fieldnum++ {
- p.fmt.clearflags()
- // always add spaces if we're doing println
- field := a[fieldnum]
- if fieldnum > 0 {
- isString := field != nil && reflect.Typeof(field).Kind() == reflect.String
- if addspace || !isString && !prevString {
- p.buf.WriteByte(' ')
- }
- }
- prevString = p.printField(field, 'v', false, false, 0)
- }
- if addnewline {
- p.buf.WriteByte('\n')
- }
-}
diff --git a/src/cmd/gofix/testdata/reflect.print.go.out b/src/cmd/gofix/testdata/reflect.print.go.out
deleted file mode 100644
index 10379bd20..000000000
--- a/src/cmd/gofix/testdata/reflect.print.go.out
+++ /dev/null
@@ -1,945 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package fmt
-
-import (
- "bytes"
- "io"
- "os"
- "reflect"
- "utf8"
-)
-
-// Some constants in the form of bytes, to avoid string overhead.
-// Needlessly fastidious, I suppose.
-var (
- commaSpaceBytes = []byte(", ")
- nilAngleBytes = []byte("<nil>")
- nilParenBytes = []byte("(nil)")
- nilBytes = []byte("nil")
- mapBytes = []byte("map[")
- missingBytes = []byte("(MISSING)")
- extraBytes = []byte("%!(EXTRA ")
- irparenBytes = []byte("i)")
- bytesBytes = []byte("[]byte{")
- widthBytes = []byte("%!(BADWIDTH)")
- precBytes = []byte("%!(BADPREC)")
- noVerbBytes = []byte("%!(NOVERB)")
-)
-
-// State represents the printer state passed to custom formatters.
-// It provides access to the io.Writer interface plus information about
-// the flags and options for the operand's format specifier.
-type State interface {
- // Write is the function to call to emit formatted output to be printed.
- Write(b []byte) (ret int, err os.Error)
- // Width returns the value of the width option and whether it has been set.
- Width() (wid int, ok bool)
- // Precision returns the value of the precision option and whether it has been set.
- Precision() (prec int, ok bool)
-
- // Flag returns whether the flag c, a character, has been set.
- Flag(int) bool
-}
-
-// Formatter is the interface implemented by values with a custom formatter.
-// The implementation of Format may call Sprintf or Fprintf(f) etc.
-// to generate its output.
-type Formatter interface {
- Format(f State, c int)
-}
-
-// Stringer is implemented by any value that has a String method(),
-// which defines the ``native'' format for that value.
-// The String method is used to print values passed as an operand
-// to a %s or %v format or to an unformatted printer such as Print.
-type Stringer interface {
- String() string
-}
-
-// GoStringer is implemented by any value that has a GoString() method,
-// which defines the Go syntax for that value.
-// The GoString method is used to print values passed as an operand
-// to a %#v format.
-type GoStringer interface {
- GoString() string
-}
-
-type pp struct {
- n int
- buf bytes.Buffer
- runeBuf [utf8.UTFMax]byte
- fmt fmt
-}
-
-// A cache holds a set of reusable objects.
-// The buffered channel holds the currently available objects.
-// If more are needed, the cache creates them by calling new.
-type cache struct {
- saved chan interface{}
- new func() interface{}
-}
-
-func (c *cache) put(x interface{}) {
- select {
- case c.saved <- x:
- // saved in cache
- default:
- // discard
- }
-}
-
-func (c *cache) get() interface{} {
- select {
- case x := <-c.saved:
- return x // reused from cache
- default:
- return c.new()
- }
- panic("not reached")
-}
-
-func newCache(f func() interface{}) *cache {
- return &cache{make(chan interface{}, 100), f}
-}
-
-var ppFree = newCache(func() interface{} { return new(pp) })
-
-// Allocate a new pp struct or grab a cached one.
-func newPrinter() *pp {
- p := ppFree.get().(*pp)
- p.fmt.init(&p.buf)
- return p
-}
-
-// Save used pp structs in ppFree; avoids an allocation per invocation.
-func (p *pp) free() {
- // Don't hold on to pp structs with large buffers.
- if cap(p.buf.Bytes()) > 1024 {
- return
- }
- p.buf.Reset()
- ppFree.put(p)
-}
-
-func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
-
-func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
-
-func (p *pp) Flag(b int) bool {
- switch b {
- case '-':
- return p.fmt.minus
- case '+':
- return p.fmt.plus
- case '#':
- return p.fmt.sharp
- case ' ':
- return p.fmt.space
- case '0':
- return p.fmt.zero
- }
- return false
-}
-
-func (p *pp) add(c int) {
- p.buf.WriteRune(c)
-}
-
-// Implement Write so we can call Fprintf on a pp (through State), for
-// recursive use in custom verbs.
-func (p *pp) Write(b []byte) (ret int, err os.Error) {
- return p.buf.Write(b)
-}
-
-// These routines end in 'f' and take a format string.
-
-// Fprintf formats according to a format specifier and writes to w.
-// It returns the number of bytes written and any write error encountered.
-func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Error) {
- p := newPrinter()
- p.doPrintf(format, a)
- n64, error := p.buf.WriteTo(w)
- p.free()
- return int(n64), error
-}
-
-// Printf formats according to a format specifier and writes to standard output.
-// It returns the number of bytes written and any write error encountered.
-func Printf(format string, a ...interface{}) (n int, errno os.Error) {
- n, errno = Fprintf(os.Stdout, format, a...)
- return n, errno
-}
-
-// Sprintf formats according to a format specifier and returns the resulting string.
-func Sprintf(format string, a ...interface{}) string {
- p := newPrinter()
- p.doPrintf(format, a)
- s := p.buf.String()
- p.free()
- return s
-}
-
-// Errorf formats according to a format specifier and returns the string
-// converted to an os.ErrorString, which satisfies the os.Error interface.
-func Errorf(format string, a ...interface{}) os.Error {
- return os.NewError(Sprintf(format, a...))
-}
-
-// These routines do not take a format string
-
-// Fprint formats using the default formats for its operands and writes to w.
-// Spaces are added between operands when neither is a string.
-// It returns the number of bytes written and any write error encountered.
-func Fprint(w io.Writer, a ...interface{}) (n int, error os.Error) {
- p := newPrinter()
- p.doPrint(a, false, false)
- n64, error := p.buf.WriteTo(w)
- p.free()
- return int(n64), error
-}
-
-// Print formats using the default formats for its operands and writes to standard output.
-// Spaces are added between operands when neither is a string.
-// It returns the number of bytes written and any write error encountered.
-func Print(a ...interface{}) (n int, errno os.Error) {
- n, errno = Fprint(os.Stdout, a...)
- return n, errno
-}
-
-// Sprint formats using the default formats for its operands and returns the resulting string.
-// Spaces are added between operands when neither is a string.
-func Sprint(a ...interface{}) string {
- p := newPrinter()
- p.doPrint(a, false, false)
- s := p.buf.String()
- p.free()
- return s
-}
-
-// These routines end in 'ln', do not take a format string,
-// always add spaces between operands, and add a newline
-// after the last operand.
-
-// Fprintln formats using the default formats for its operands and writes to w.
-// Spaces are always added between operands and a newline is appended.
-// It returns the number of bytes written and any write error encountered.
-func Fprintln(w io.Writer, a ...interface{}) (n int, error os.Error) {
- p := newPrinter()
- p.doPrint(a, true, true)
- n64, error := p.buf.WriteTo(w)
- p.free()
- return int(n64), error
-}
-
-// Println formats using the default formats for its operands and writes to standard output.
-// Spaces are always added between operands and a newline is appended.
-// It returns the number of bytes written and any write error encountered.
-func Println(a ...interface{}) (n int, errno os.Error) {
- n, errno = Fprintln(os.Stdout, a...)
- return n, errno
-}
-
-// Sprintln formats using the default formats for its operands and returns the resulting string.
-// Spaces are always added between operands and a newline is appended.
-func Sprintln(a ...interface{}) string {
- p := newPrinter()
- p.doPrint(a, true, true)
- s := p.buf.String()
- p.free()
- return s
-}
-
-
-// Get the i'th arg of the struct value.
-// If the arg itself is an interface, return a value for
-// the thing inside the interface, not the interface itself.
-func getField(v reflect.Value, i int) reflect.Value {
- val := v.Field(i)
- if i := val; i.Kind() == reflect.Interface {
- if inter := i.Interface(); inter != nil {
- return reflect.ValueOf(inter)
- }
- }
- return val
-}
-
-// Convert ASCII to integer. n is 0 (and got is false) if no number present.
-func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
- if start >= end {
- return 0, false, end
- }
- for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
- num = num*10 + int(s[newi]-'0')
- isnum = true
- }
- return
-}
-
-func (p *pp) unknownType(v interface{}) {
- if v == nil {
- p.buf.Write(nilAngleBytes)
- return
- }
- p.buf.WriteByte('?')
- p.buf.WriteString(reflect.TypeOf(v).String())
- p.buf.WriteByte('?')
-}
-
-func (p *pp) badVerb(verb int, val interface{}) {
- p.add('%')
- p.add('!')
- p.add(verb)
- p.add('(')
- if val == nil {
- p.buf.Write(nilAngleBytes)
- } else {
- p.buf.WriteString(reflect.TypeOf(val).String())
- p.add('=')
- p.printField(val, 'v', false, false, 0)
- }
- p.add(')')
-}
-
-func (p *pp) fmtBool(v bool, verb int, value interface{}) {
- switch verb {
- case 't', 'v':
- p.fmt.fmt_boolean(v)
- default:
- p.badVerb(verb, value)
- }
-}
-
-// fmtC formats a rune for the 'c' format.
-func (p *pp) fmtC(c int64) {
- rune := int(c) // Check for overflow.
- if int64(rune) != c {
- rune = utf8.RuneError
- }
- w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune)
- p.fmt.pad(p.runeBuf[0:w])
-}
-
-func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
- switch verb {
- case 'b':
- p.fmt.integer(v, 2, signed, ldigits)
- case 'c':
- p.fmtC(v)
- case 'd', 'v':
- p.fmt.integer(v, 10, signed, ldigits)
- case 'o':
- p.fmt.integer(v, 8, signed, ldigits)
- case 'x':
- p.fmt.integer(v, 16, signed, ldigits)
- case 'U':
- p.fmtUnicode(v)
- case 'X':
- p.fmt.integer(v, 16, signed, udigits)
- default:
- p.badVerb(verb, value)
- }
-}
-
-// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
-// not, as requested, by temporarily setting the sharp flag.
-func (p *pp) fmt0x64(v uint64, leading0x bool) {
- sharp := p.fmt.sharp
- p.fmt.sharp = leading0x
- p.fmt.integer(int64(v), 16, unsigned, ldigits)
- p.fmt.sharp = sharp
-}
-
-// fmtUnicode formats a uint64 in U+1234 form by
-// temporarily turning on the unicode flag and tweaking the precision.
-func (p *pp) fmtUnicode(v int64) {
- precPresent := p.fmt.precPresent
- prec := p.fmt.prec
- if !precPresent {
- // If prec is already set, leave it alone; otherwise 4 is minimum.
- p.fmt.prec = 4
- p.fmt.precPresent = true
- }
- p.fmt.unicode = true // turn on U+
- p.fmt.integer(int64(v), 16, unsigned, udigits)
- p.fmt.unicode = false
- p.fmt.prec = prec
- p.fmt.precPresent = precPresent
-}
-
-func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
- switch verb {
- case 'b':
- p.fmt.integer(int64(v), 2, unsigned, ldigits)
- case 'c':
- p.fmtC(int64(v))
- case 'd':
- p.fmt.integer(int64(v), 10, unsigned, ldigits)
- case 'v':
- if goSyntax {
- p.fmt0x64(v, true)
- } else {
- p.fmt.integer(int64(v), 10, unsigned, ldigits)
- }
- case 'o':
- p.fmt.integer(int64(v), 8, unsigned, ldigits)
- case 'x':
- p.fmt.integer(int64(v), 16, unsigned, ldigits)
- case 'X':
- p.fmt.integer(int64(v), 16, unsigned, udigits)
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
- switch verb {
- case 'b':
- p.fmt.fmt_fb32(v)
- case 'e':
- p.fmt.fmt_e32(v)
- case 'E':
- p.fmt.fmt_E32(v)
- case 'f':
- p.fmt.fmt_f32(v)
- case 'g', 'v':
- p.fmt.fmt_g32(v)
- case 'G':
- p.fmt.fmt_G32(v)
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
- switch verb {
- case 'b':
- p.fmt.fmt_fb64(v)
- case 'e':
- p.fmt.fmt_e64(v)
- case 'E':
- p.fmt.fmt_E64(v)
- case 'f':
- p.fmt.fmt_f64(v)
- case 'g', 'v':
- p.fmt.fmt_g64(v)
- case 'G':
- p.fmt.fmt_G64(v)
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
- switch verb {
- case 'e', 'E', 'f', 'F', 'g', 'G':
- p.fmt.fmt_c64(v, verb)
- case 'v':
- p.fmt.fmt_c64(v, 'g')
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
- switch verb {
- case 'e', 'E', 'f', 'F', 'g', 'G':
- p.fmt.fmt_c128(v, verb)
- case 'v':
- p.fmt.fmt_c128(v, 'g')
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
- switch verb {
- case 'v':
- if goSyntax {
- p.fmt.fmt_q(v)
- } else {
- p.fmt.fmt_s(v)
- }
- case 's':
- p.fmt.fmt_s(v)
- case 'x':
- p.fmt.fmt_sx(v)
- case 'X':
- p.fmt.fmt_sX(v)
- case 'q':
- p.fmt.fmt_q(v)
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) {
- if verb == 'v' || verb == 'd' {
- if goSyntax {
- p.buf.Write(bytesBytes)
- } else {
- p.buf.WriteByte('[')
- }
- for i, c := range v {
- if i > 0 {
- if goSyntax {
- p.buf.Write(commaSpaceBytes)
- } else {
- p.buf.WriteByte(' ')
- }
- }
- p.printField(c, 'v', p.fmt.plus, goSyntax, depth+1)
- }
- if goSyntax {
- p.buf.WriteByte('}')
- } else {
- p.buf.WriteByte(']')
- }
- return
- }
- s := string(v)
- switch verb {
- case 's':
- p.fmt.fmt_s(s)
- case 'x':
- p.fmt.fmt_sx(s)
- case 'X':
- p.fmt.fmt_sX(s)
- case 'q':
- p.fmt.fmt_q(s)
- default:
- p.badVerb(verb, value)
- }
-}
-
-func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
- var u uintptr
- switch value.Kind() {
- case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
- u = value.Pointer()
- default:
- p.badVerb(verb, field)
- return
- }
- if goSyntax {
- p.add('(')
- p.buf.WriteString(reflect.TypeOf(field).String())
- p.add(')')
- p.add('(')
- if u == 0 {
- p.buf.Write(nilBytes)
- } else {
- p.fmt0x64(uint64(u), true)
- }
- p.add(')')
- } else {
- p.fmt0x64(uint64(u), !p.fmt.sharp)
- }
-}
-
-var (
- intBits = reflect.TypeOf(0).Bits()
- floatBits = reflect.TypeOf(0.0).Bits()
- complexBits = reflect.TypeOf(1i).Bits()
- uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
-)
-
-func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
- if field == nil {
- if verb == 'T' || verb == 'v' {
- p.buf.Write(nilAngleBytes)
- } else {
- p.badVerb(verb, field)
- }
- return false
- }
-
- // Special processing considerations.
- // %T (the value's type) and %p (its address) are special; we always do them first.
- switch verb {
- case 'T':
- p.printField(reflect.TypeOf(field).String(), 's', false, false, 0)
- return false
- case 'p':
- p.fmtPointer(field, reflect.ValueOf(field), verb, goSyntax)
- return false
- }
- // Is it a Formatter?
- if formatter, ok := field.(Formatter); ok {
- formatter.Format(p, verb)
- return false // this value is not a string
-
- }
- // Must not touch flags before Formatter looks at them.
- if plus {
- p.fmt.plus = false
- }
- // If we're doing Go syntax and the field knows how to supply it, take care of it now.
- if goSyntax {
- p.fmt.sharp = false
- if stringer, ok := field.(GoStringer); ok {
- // Print the result of GoString unadorned.
- p.fmtString(stringer.GoString(), 's', false, field)
- return false // this value is not a string
- }
- } else {
- // Is it a Stringer?
- if stringer, ok := field.(Stringer); ok {
- p.printField(stringer.String(), verb, plus, false, depth)
- return false // this value is not a string
- }
- }
-
- // Some types can be done without reflection.
- switch f := field.(type) {
- case bool:
- p.fmtBool(f, verb, field)
- return false
- case float32:
- p.fmtFloat32(f, verb, field)
- return false
- case float64:
- p.fmtFloat64(f, verb, field)
- return false
- case complex64:
- p.fmtComplex64(complex64(f), verb, field)
- return false
- case complex128:
- p.fmtComplex128(f, verb, field)
- return false
- case int:
- p.fmtInt64(int64(f), verb, field)
- return false
- case int8:
- p.fmtInt64(int64(f), verb, field)
- return false
- case int16:
- p.fmtInt64(int64(f), verb, field)
- return false
- case int32:
- p.fmtInt64(int64(f), verb, field)
- return false
- case int64:
- p.fmtInt64(f, verb, field)
- return false
- case uint:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
- case uint8:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
- case uint16:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
- case uint32:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
- case uint64:
- p.fmtUint64(f, verb, goSyntax, field)
- return false
- case uintptr:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
- case string:
- p.fmtString(f, verb, goSyntax, field)
- return verb == 's' || verb == 'v'
- case []byte:
- p.fmtBytes(f, verb, goSyntax, depth, field)
- return verb == 's'
- }
-
- // Need to use reflection
- value := reflect.ValueOf(field)
-
-BigSwitch:
- switch f := value; f.Kind() {
- case reflect.Bool:
- p.fmtBool(f.Bool(), verb, field)
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p.fmtInt64(f.Int(), verb, field)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p.fmtUint64(uint64(f.Uint()), verb, goSyntax, field)
- case reflect.Float32, reflect.Float64:
- if f.Type().Size() == 4 {
- p.fmtFloat32(float32(f.Float()), verb, field)
- } else {
- p.fmtFloat64(float64(f.Float()), verb, field)
- }
- case reflect.Complex64, reflect.Complex128:
- if f.Type().Size() == 8 {
- p.fmtComplex64(complex64(f.Complex()), verb, field)
- } else {
- p.fmtComplex128(complex128(f.Complex()), verb, field)
- }
- case reflect.String:
- p.fmtString(f.String(), verb, goSyntax, field)
- case reflect.Map:
- if goSyntax {
- p.buf.WriteString(f.Type().String())
- p.buf.WriteByte('{')
- } else {
- p.buf.Write(mapBytes)
- }
- keys := f.MapKeys()
- for i, key := range keys {
- if i > 0 {
- if goSyntax {
- p.buf.Write(commaSpaceBytes)
- } else {
- p.buf.WriteByte(' ')
- }
- }
- p.printField(key.Interface(), verb, plus, goSyntax, depth+1)
- p.buf.WriteByte(':')
- p.printField(f.MapIndex(key).Interface(), verb, plus, goSyntax, depth+1)
- }
- if goSyntax {
- p.buf.WriteByte('}')
- } else {
- p.buf.WriteByte(']')
- }
- case reflect.Struct:
- if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
- }
- p.add('{')
- v := f
- t := v.Type()
- for i := 0; i < v.NumField(); i++ {
- if i > 0 {
- if goSyntax {
- p.buf.Write(commaSpaceBytes)
- } else {
- p.buf.WriteByte(' ')
- }
- }
- if plus || goSyntax {
- if f := t.Field(i); f.Name != "" {
- p.buf.WriteString(f.Name)
- p.buf.WriteByte(':')
- }
- }
- p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1)
- }
- p.buf.WriteByte('}')
- case reflect.Interface:
- value := f.Elem()
- if !value.IsValid() {
- if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
- p.buf.Write(nilParenBytes)
- } else {
- p.buf.Write(nilAngleBytes)
- }
- } else {
- return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
- }
- case reflect.Array, reflect.Slice:
- // Byte slices are special.
- if f.Type().Elem().Kind() == reflect.Uint8 {
- // We know it's a slice of bytes, but we also know it does not have static type
- // []byte, or it would have been caught above. Therefore we cannot convert
- // it directly in the (slightly) obvious way: f.Interface().([]byte); it doesn't have
- // that type, and we can't write an expression of the right type and do a
- // conversion because we don't have a static way to write the right type.
- // So we build a slice by hand. This is a rare case but it would be nice
- // if reflection could help a little more.
- bytes := make([]byte, f.Len())
- for i := range bytes {
- bytes[i] = byte(f.Index(i).Uint())
- }
- p.fmtBytes(bytes, verb, goSyntax, depth, field)
- return verb == 's'
- }
- if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
- p.buf.WriteByte('{')
- } else {
- p.buf.WriteByte('[')
- }
- for i := 0; i < f.Len(); i++ {
- if i > 0 {
- if goSyntax {
- p.buf.Write(commaSpaceBytes)
- } else {
- p.buf.WriteByte(' ')
- }
- }
- p.printField(f.Index(i).Interface(), verb, plus, goSyntax, depth+1)
- }
- if goSyntax {
- p.buf.WriteByte('}')
- } else {
- p.buf.WriteByte(']')
- }
- case reflect.Ptr:
- v := f.Pointer()
- // pointer to array or slice or struct? ok at top level
- // but not embedded (avoid loops)
- if v != 0 && depth == 0 {
- switch a := f.Elem(); a.Kind() {
- case reflect.Array, reflect.Slice:
- p.buf.WriteByte('&')
- p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
- break BigSwitch
- case reflect.Struct:
- p.buf.WriteByte('&')
- p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
- break BigSwitch
- }
- }
- if goSyntax {
- p.buf.WriteByte('(')
- p.buf.WriteString(reflect.TypeOf(field).String())
- p.buf.WriteByte(')')
- p.buf.WriteByte('(')
- if v == 0 {
- p.buf.Write(nilBytes)
- } else {
- p.fmt0x64(uint64(v), true)
- }
- p.buf.WriteByte(')')
- break
- }
- if v == 0 {
- p.buf.Write(nilAngleBytes)
- break
- }
- p.fmt0x64(uint64(v), true)
- case reflect.Chan, reflect.Func, reflect.UnsafePointer:
- p.fmtPointer(field, value, verb, goSyntax)
- default:
- p.unknownType(f)
- }
- return false
-}
-
-// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
-func intFromArg(a []interface{}, end, i, fieldnum int) (num int, isInt bool, newi, newfieldnum int) {
- newi, newfieldnum = end, fieldnum
- if i < end && fieldnum < len(a) {
- num, isInt = a[fieldnum].(int)
- newi, newfieldnum = i+1, fieldnum+1
- }
- return
-}
-
-func (p *pp) doPrintf(format string, a []interface{}) {
- end := len(format)
- fieldnum := 0 // we process one field per non-trivial format
- for i := 0; i < end; {
- lasti := i
- for i < end && format[i] != '%' {
- i++
- }
- if i > lasti {
- p.buf.WriteString(format[lasti:i])
- }
- if i >= end {
- // done processing format string
- break
- }
-
- // Process one verb
- i++
- // flags and widths
- p.fmt.clearflags()
- F:
- for ; i < end; i++ {
- switch format[i] {
- case '#':
- p.fmt.sharp = true
- case '0':
- p.fmt.zero = true
- case '+':
- p.fmt.plus = true
- case '-':
- p.fmt.minus = true
- case ' ':
- p.fmt.space = true
- default:
- break F
- }
- }
- // do we have width?
- if i < end && format[i] == '*' {
- p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
- if !p.fmt.widPresent {
- p.buf.Write(widthBytes)
- }
- } else {
- p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
- }
- // do we have precision?
- if i < end && format[i] == '.' {
- if format[i+1] == '*' {
- p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
- if !p.fmt.precPresent {
- p.buf.Write(precBytes)
- }
- } else {
- p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
- }
- }
- if i >= end {
- p.buf.Write(noVerbBytes)
- continue
- }
- c, w := utf8.DecodeRuneInString(format[i:])
- i += w
- // percent is special - absorbs no operand
- if c == '%' {
- p.buf.WriteByte('%') // We ignore width and prec.
- continue
- }
- if fieldnum >= len(a) { // out of operands
- p.buf.WriteByte('%')
- p.add(c)
- p.buf.Write(missingBytes)
- continue
- }
- field := a[fieldnum]
- fieldnum++
-
- goSyntax := c == 'v' && p.fmt.sharp
- plus := c == 'v' && p.fmt.plus
- p.printField(field, c, plus, goSyntax, 0)
- }
-
- if fieldnum < len(a) {
- p.buf.Write(extraBytes)
- for ; fieldnum < len(a); fieldnum++ {
- field := a[fieldnum]
- if field != nil {
- p.buf.WriteString(reflect.TypeOf(field).String())
- p.buf.WriteByte('=')
- }
- p.printField(field, 'v', false, false, 0)
- if fieldnum+1 < len(a) {
- p.buf.Write(commaSpaceBytes)
- }
- }
- p.buf.WriteByte(')')
- }
-}
-
-func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
- prevString := false
- for fieldnum := 0; fieldnum < len(a); fieldnum++ {
- p.fmt.clearflags()
- // always add spaces if we're doing println
- field := a[fieldnum]
- if fieldnum > 0 {
- isString := field != nil && reflect.TypeOf(field).Kind() == reflect.String
- if addspace || !isString && !prevString {
- p.buf.WriteByte(' ')
- }
- }
- prevString = p.printField(field, 'v', false, false, 0)
- }
- if addnewline {
- p.buf.WriteByte('\n')
- }
-}
diff --git a/src/cmd/gofix/testdata/reflect.quick.go.in b/src/cmd/gofix/testdata/reflect.quick.go.in
deleted file mode 100644
index a5568b048..000000000
--- a/src/cmd/gofix/testdata/reflect.quick.go.in
+++ /dev/null
@@ -1,364 +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.
-
-// This package implements utility functions to help with black box testing.
-package quick
-
-import (
- "flag"
- "fmt"
- "math"
- "os"
- "rand"
- "reflect"
- "strings"
-)
-
-var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
-
-// A Generator can generate random values of its own type.
-type Generator interface {
- // Generate returns a random instance of the type on which it is a
- // method using the size as a size hint.
- Generate(rand *rand.Rand, size int) reflect.Value
-}
-
-// randFloat32 generates a random float taking the full range of a float32.
-func randFloat32(rand *rand.Rand) float32 {
- f := rand.Float64() * math.MaxFloat32
- if rand.Int()&1 == 1 {
- f = -f
- }
- return float32(f)
-}
-
-// randFloat64 generates a random float taking the full range of a float64.
-func randFloat64(rand *rand.Rand) float64 {
- f := rand.Float64()
- if rand.Int()&1 == 1 {
- f = -f
- }
- return f
-}
-
-// randInt64 returns a random integer taking half the range of an int64.
-func randInt64(rand *rand.Rand) int64 { return rand.Int63() - 1<<62 }
-
-// complexSize is the maximum length of arbitrary values that contain other
-// values.
-const complexSize = 50
-
-// Value returns an arbitrary value of the given type.
-// If the type implements the Generator interface, that will be used.
-// Note: in order to create arbitrary values for structs, all the members must be public.
-func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
- if m, ok := reflect.MakeZero(t).Interface().(Generator); ok {
- return m.Generate(rand, complexSize), true
- }
-
- switch concrete := t.(type) {
- case *reflect.BoolType:
- return reflect.NewValue(rand.Int()&1 == 0), true
- case *reflect.FloatType, *reflect.IntType, *reflect.UintType, *reflect.ComplexType:
- switch t.Kind() {
- case reflect.Float32:
- return reflect.NewValue(randFloat32(rand)), true
- case reflect.Float64:
- return reflect.NewValue(randFloat64(rand)), true
- case reflect.Complex64:
- return reflect.NewValue(complex(randFloat32(rand), randFloat32(rand))), true
- case reflect.Complex128:
- return reflect.NewValue(complex(randFloat64(rand), randFloat64(rand))), true
- case reflect.Int16:
- return reflect.NewValue(int16(randInt64(rand))), true
- case reflect.Int32:
- return reflect.NewValue(int32(randInt64(rand))), true
- case reflect.Int64:
- return reflect.NewValue(randInt64(rand)), true
- case reflect.Int8:
- return reflect.NewValue(int8(randInt64(rand))), true
- case reflect.Int:
- return reflect.NewValue(int(randInt64(rand))), true
- case reflect.Uint16:
- return reflect.NewValue(uint16(randInt64(rand))), true
- case reflect.Uint32:
- return reflect.NewValue(uint32(randInt64(rand))), true
- case reflect.Uint64:
- return reflect.NewValue(uint64(randInt64(rand))), true
- case reflect.Uint8:
- return reflect.NewValue(uint8(randInt64(rand))), true
- case reflect.Uint:
- return reflect.NewValue(uint(randInt64(rand))), true
- case reflect.Uintptr:
- return reflect.NewValue(uintptr(randInt64(rand))), true
- }
- case *reflect.MapType:
- numElems := rand.Intn(complexSize)
- m := reflect.MakeMap(concrete)
- for i := 0; i < numElems; i++ {
- key, ok1 := Value(concrete.Key(), rand)
- value, ok2 := Value(concrete.Elem(), rand)
- if !ok1 || !ok2 {
- return nil, false
- }
- m.SetElem(key, value)
- }
- return m, true
- case *reflect.PtrType:
- v, ok := Value(concrete.Elem(), rand)
- if !ok {
- return nil, false
- }
- p := reflect.MakeZero(concrete)
- p.(*reflect.PtrValue).PointTo(v)
- return p, true
- case *reflect.SliceType:
- numElems := rand.Intn(complexSize)
- s := reflect.MakeSlice(concrete, numElems, numElems)
- for i := 0; i < numElems; i++ {
- v, ok := Value(concrete.Elem(), rand)
- if !ok {
- return nil, false
- }
- s.Elem(i).SetValue(v)
- }
- return s, true
- case *reflect.StringType:
- numChars := rand.Intn(complexSize)
- codePoints := make([]int, numChars)
- for i := 0; i < numChars; i++ {
- codePoints[i] = rand.Intn(0x10ffff)
- }
- return reflect.NewValue(string(codePoints)), true
- case *reflect.StructType:
- s := reflect.MakeZero(t).(*reflect.StructValue)
- for i := 0; i < s.NumField(); i++ {
- v, ok := Value(concrete.Field(i).Type, rand)
- if !ok {
- return nil, false
- }
- s.Field(i).SetValue(v)
- }
- return s, true
- default:
- return nil, false
- }
-
- return
-}
-
-// A Config structure contains options for running a test.
-type Config struct {
- // MaxCount sets the maximum number of iterations. If zero,
- // MaxCountScale is used.
- MaxCount int
- // MaxCountScale is a non-negative scale factor applied to the default
- // maximum. If zero, the default is unchanged.
- MaxCountScale float64
- // If non-nil, rand is a source of random numbers. Otherwise a default
- // pseudo-random source will be used.
- Rand *rand.Rand
- // If non-nil, Values is a function which generates a slice of arbitrary
- // Values that are congruent with the arguments to the function being
- // tested. Otherwise, Values is used to generate the values.
- Values func([]reflect.Value, *rand.Rand)
-}
-
-var defaultConfig Config
-
-// getRand returns the *rand.Rand to use for a given Config.
-func (c *Config) getRand() *rand.Rand {
- if c.Rand == nil {
- return rand.New(rand.NewSource(0))
- }
- return c.Rand
-}
-
-// getMaxCount returns the maximum number of iterations to run for a given
-// Config.
-func (c *Config) getMaxCount() (maxCount int) {
- maxCount = c.MaxCount
- if maxCount == 0 {
- if c.MaxCountScale != 0 {
- maxCount = int(c.MaxCountScale * float64(*defaultMaxCount))
- } else {
- maxCount = *defaultMaxCount
- }
- }
-
- return
-}
-
-// A SetupError is the result of an error in the way that check is being
-// used, independent of the functions being tested.
-type SetupError string
-
-func (s SetupError) String() string { return string(s) }
-
-// A CheckError is the result of Check finding an error.
-type CheckError struct {
- Count int
- In []interface{}
-}
-
-func (s *CheckError) String() string {
- return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In))
-}
-
-// A CheckEqualError is the result CheckEqual finding an error.
-type CheckEqualError struct {
- CheckError
- Out1 []interface{}
- Out2 []interface{}
-}
-
-func (s *CheckEqualError) String() string {
- return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2))
-}
-
-// Check looks for an input to f, any function that returns bool,
-// such that f returns false. It calls f repeatedly, with arbitrary
-// values for each argument. If f returns false on a given input,
-// Check returns that input as a *CheckError.
-// For example:
-//
-// func TestOddMultipleOfThree(t *testing.T) {
-// f := func(x int) bool {
-// y := OddMultipleOfThree(x)
-// return y%2 == 1 && y%3 == 0
-// }
-// if err := quick.Check(f, nil); err != nil {
-// t.Error(err)
-// }
-// }
-func Check(function interface{}, config *Config) (err os.Error) {
- if config == nil {
- config = &defaultConfig
- }
-
- f, fType, ok := functionAndType(function)
- if !ok {
- err = SetupError("argument is not a function")
- return
- }
-
- if fType.NumOut() != 1 {
- err = SetupError("function returns more than one value.")
- return
- }
- if _, ok := fType.Out(0).(*reflect.BoolType); !ok {
- err = SetupError("function does not return a bool")
- return
- }
-
- arguments := make([]reflect.Value, fType.NumIn())
- rand := config.getRand()
- maxCount := config.getMaxCount()
-
- for i := 0; i < maxCount; i++ {
- err = arbitraryValues(arguments, fType, config, rand)
- if err != nil {
- return
- }
-
- if !f.Call(arguments)[0].(*reflect.BoolValue).Get() {
- err = &CheckError{i + 1, toInterfaces(arguments)}
- return
- }
- }
-
- return
-}
-
-// CheckEqual looks for an input on which f and g return different results.
-// It calls f and g repeatedly with arbitrary values for each argument.
-// If f and g return different answers, CheckEqual returns a *CheckEqualError
-// describing the input and the outputs.
-func CheckEqual(f, g interface{}, config *Config) (err os.Error) {
- if config == nil {
- config = &defaultConfig
- }
-
- x, xType, ok := functionAndType(f)
- if !ok {
- err = SetupError("f is not a function")
- return
- }
- y, yType, ok := functionAndType(g)
- if !ok {
- err = SetupError("g is not a function")
- return
- }
-
- if xType != yType {
- err = SetupError("functions have different types")
- return
- }
-
- arguments := make([]reflect.Value, xType.NumIn())
- rand := config.getRand()
- maxCount := config.getMaxCount()
-
- for i := 0; i < maxCount; i++ {
- err = arbitraryValues(arguments, xType, config, rand)
- if err != nil {
- return
- }
-
- xOut := toInterfaces(x.Call(arguments))
- yOut := toInterfaces(y.Call(arguments))
-
- if !reflect.DeepEqual(xOut, yOut) {
- err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
- return
- }
- }
-
- return
-}
-
-// arbitraryValues writes Values to args such that args contains Values
-// suitable for calling f.
-func arbitraryValues(args []reflect.Value, f *reflect.FuncType, config *Config, rand *rand.Rand) (err os.Error) {
- if config.Values != nil {
- config.Values(args, rand)
- return
- }
-
- for j := 0; j < len(args); j++ {
- var ok bool
- args[j], ok = Value(f.In(j), rand)
- if !ok {
- err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j))
- return
- }
- }
-
- return
-}
-
-func functionAndType(f interface{}) (v *reflect.FuncValue, t *reflect.FuncType, ok bool) {
- v, ok = reflect.NewValue(f).(*reflect.FuncValue)
- if !ok {
- return
- }
- t = v.Type().(*reflect.FuncType)
- return
-}
-
-func toInterfaces(values []reflect.Value) []interface{} {
- ret := make([]interface{}, len(values))
- for i, v := range values {
- ret[i] = v.Interface()
- }
- return ret
-}
-
-func toString(interfaces []interface{}) string {
- s := make([]string, len(interfaces))
- for i, v := range interfaces {
- s[i] = fmt.Sprintf("%#v", v)
- }
- return strings.Join(s, ", ")
-}
diff --git a/src/cmd/gofix/testdata/reflect.quick.go.out b/src/cmd/gofix/testdata/reflect.quick.go.out
deleted file mode 100644
index c62305b83..000000000
--- a/src/cmd/gofix/testdata/reflect.quick.go.out
+++ /dev/null
@@ -1,365 +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.
-
-// This package implements utility functions to help with black box testing.
-package quick
-
-import (
- "flag"
- "fmt"
- "math"
- "os"
- "rand"
- "reflect"
- "strings"
-)
-
-var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
-
-// A Generator can generate random values of its own type.
-type Generator interface {
- // Generate returns a random instance of the type on which it is a
- // method using the size as a size hint.
- Generate(rand *rand.Rand, size int) reflect.Value
-}
-
-// randFloat32 generates a random float taking the full range of a float32.
-func randFloat32(rand *rand.Rand) float32 {
- f := rand.Float64() * math.MaxFloat32
- if rand.Int()&1 == 1 {
- f = -f
- }
- return float32(f)
-}
-
-// randFloat64 generates a random float taking the full range of a float64.
-func randFloat64(rand *rand.Rand) float64 {
- f := rand.Float64()
- if rand.Int()&1 == 1 {
- f = -f
- }
- return f
-}
-
-// randInt64 returns a random integer taking half the range of an int64.
-func randInt64(rand *rand.Rand) int64 { return rand.Int63() - 1<<62 }
-
-// complexSize is the maximum length of arbitrary values that contain other
-// values.
-const complexSize = 50
-
-// Value returns an arbitrary value of the given type.
-// If the type implements the Generator interface, that will be used.
-// Note: in order to create arbitrary values for structs, all the members must be public.
-func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
- if m, ok := reflect.Zero(t).Interface().(Generator); ok {
- return m.Generate(rand, complexSize), true
- }
-
- switch concrete := t; concrete.Kind() {
- case reflect.Bool:
- return reflect.ValueOf(rand.Int()&1 == 0), true
- case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Complex64, reflect.Complex128:
- switch t.Kind() {
- case reflect.Float32:
- return reflect.ValueOf(randFloat32(rand)), true
- case reflect.Float64:
- return reflect.ValueOf(randFloat64(rand)), true
- case reflect.Complex64:
- return reflect.ValueOf(complex(randFloat32(rand), randFloat32(rand))), true
- case reflect.Complex128:
- return reflect.ValueOf(complex(randFloat64(rand), randFloat64(rand))), true
- case reflect.Int16:
- return reflect.ValueOf(int16(randInt64(rand))), true
- case reflect.Int32:
- return reflect.ValueOf(int32(randInt64(rand))), true
- case reflect.Int64:
- return reflect.ValueOf(randInt64(rand)), true
- case reflect.Int8:
- return reflect.ValueOf(int8(randInt64(rand))), true
- case reflect.Int:
- return reflect.ValueOf(int(randInt64(rand))), true
- case reflect.Uint16:
- return reflect.ValueOf(uint16(randInt64(rand))), true
- case reflect.Uint32:
- return reflect.ValueOf(uint32(randInt64(rand))), true
- case reflect.Uint64:
- return reflect.ValueOf(uint64(randInt64(rand))), true
- case reflect.Uint8:
- return reflect.ValueOf(uint8(randInt64(rand))), true
- case reflect.Uint:
- return reflect.ValueOf(uint(randInt64(rand))), true
- case reflect.Uintptr:
- return reflect.ValueOf(uintptr(randInt64(rand))), true
- }
- case reflect.Map:
- numElems := rand.Intn(complexSize)
- m := reflect.MakeMap(concrete)
- for i := 0; i < numElems; i++ {
- key, ok1 := Value(concrete.Key(), rand)
- value, ok2 := Value(concrete.Elem(), rand)
- if !ok1 || !ok2 {
- return reflect.Value{}, false
- }
- m.SetMapIndex(key, value)
- }
- return m, true
- case reflect.Ptr:
- v, ok := Value(concrete.Elem(), rand)
- if !ok {
- return reflect.Value{}, false
- }
- p := reflect.Zero(concrete)
- p.Set(v.Addr())
- return p, true
- case reflect.Slice:
- numElems := rand.Intn(complexSize)
- s := reflect.MakeSlice(concrete, numElems, numElems)
- for i := 0; i < numElems; i++ {
- v, ok := Value(concrete.Elem(), rand)
- if !ok {
- return reflect.Value{}, false
- }
- s.Index(i).Set(v)
- }
- return s, true
- case reflect.String:
- numChars := rand.Intn(complexSize)
- codePoints := make([]int, numChars)
- for i := 0; i < numChars; i++ {
- codePoints[i] = rand.Intn(0x10ffff)
- }
- return reflect.ValueOf(string(codePoints)), true
- case reflect.Struct:
- s := reflect.Zero(t)
- for i := 0; i < s.NumField(); i++ {
- v, ok := Value(concrete.Field(i).Type, rand)
- if !ok {
- return reflect.Value{}, false
- }
- s.Field(i).Set(v)
- }
- return s, true
- default:
- return reflect.Value{}, false
- }
-
- return
-}
-
-// A Config structure contains options for running a test.
-type Config struct {
- // MaxCount sets the maximum number of iterations. If zero,
- // MaxCountScale is used.
- MaxCount int
- // MaxCountScale is a non-negative scale factor applied to the default
- // maximum. If zero, the default is unchanged.
- MaxCountScale float64
- // If non-nil, rand is a source of random numbers. Otherwise a default
- // pseudo-random source will be used.
- Rand *rand.Rand
- // If non-nil, Values is a function which generates a slice of arbitrary
- // Values that are congruent with the arguments to the function being
- // tested. Otherwise, Values is used to generate the values.
- Values func([]reflect.Value, *rand.Rand)
-}
-
-var defaultConfig Config
-
-// getRand returns the *rand.Rand to use for a given Config.
-func (c *Config) getRand() *rand.Rand {
- if c.Rand == nil {
- return rand.New(rand.NewSource(0))
- }
- return c.Rand
-}
-
-// getMaxCount returns the maximum number of iterations to run for a given
-// Config.
-func (c *Config) getMaxCount() (maxCount int) {
- maxCount = c.MaxCount
- if maxCount == 0 {
- if c.MaxCountScale != 0 {
- maxCount = int(c.MaxCountScale * float64(*defaultMaxCount))
- } else {
- maxCount = *defaultMaxCount
- }
- }
-
- return
-}
-
-// A SetupError is the result of an error in the way that check is being
-// used, independent of the functions being tested.
-type SetupError string
-
-func (s SetupError) String() string { return string(s) }
-
-// A CheckError is the result of Check finding an error.
-type CheckError struct {
- Count int
- In []interface{}
-}
-
-func (s *CheckError) String() string {
- return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In))
-}
-
-// A CheckEqualError is the result CheckEqual finding an error.
-type CheckEqualError struct {
- CheckError
- Out1 []interface{}
- Out2 []interface{}
-}
-
-func (s *CheckEqualError) String() string {
- return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2))
-}
-
-// Check looks for an input to f, any function that returns bool,
-// such that f returns false. It calls f repeatedly, with arbitrary
-// values for each argument. If f returns false on a given input,
-// Check returns that input as a *CheckError.
-// For example:
-//
-// func TestOddMultipleOfThree(t *testing.T) {
-// f := func(x int) bool {
-// y := OddMultipleOfThree(x)
-// return y%2 == 1 && y%3 == 0
-// }
-// if err := quick.Check(f, nil); err != nil {
-// t.Error(err)
-// }
-// }
-func Check(function interface{}, config *Config) (err os.Error) {
- if config == nil {
- config = &defaultConfig
- }
-
- f, fType, ok := functionAndType(function)
- if !ok {
- err = SetupError("argument is not a function")
- return
- }
-
- if fType.NumOut() != 1 {
- err = SetupError("function returns more than one value.")
- return
- }
- if fType.Out(0).Kind() != reflect.Bool {
- err = SetupError("function does not return a bool")
- return
- }
-
- arguments := make([]reflect.Value, fType.NumIn())
- rand := config.getRand()
- maxCount := config.getMaxCount()
-
- for i := 0; i < maxCount; i++ {
- err = arbitraryValues(arguments, fType, config, rand)
- if err != nil {
- return
- }
-
- if !f.Call(arguments)[0].Bool() {
- err = &CheckError{i + 1, toInterfaces(arguments)}
- return
- }
- }
-
- return
-}
-
-// CheckEqual looks for an input on which f and g return different results.
-// It calls f and g repeatedly with arbitrary values for each argument.
-// If f and g return different answers, CheckEqual returns a *CheckEqualError
-// describing the input and the outputs.
-func CheckEqual(f, g interface{}, config *Config) (err os.Error) {
- if config == nil {
- config = &defaultConfig
- }
-
- x, xType, ok := functionAndType(f)
- if !ok {
- err = SetupError("f is not a function")
- return
- }
- y, yType, ok := functionAndType(g)
- if !ok {
- err = SetupError("g is not a function")
- return
- }
-
- if xType != yType {
- err = SetupError("functions have different types")
- return
- }
-
- arguments := make([]reflect.Value, xType.NumIn())
- rand := config.getRand()
- maxCount := config.getMaxCount()
-
- for i := 0; i < maxCount; i++ {
- err = arbitraryValues(arguments, xType, config, rand)
- if err != nil {
- return
- }
-
- xOut := toInterfaces(x.Call(arguments))
- yOut := toInterfaces(y.Call(arguments))
-
- if !reflect.DeepEqual(xOut, yOut) {
- err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
- return
- }
- }
-
- return
-}
-
-// arbitraryValues writes Values to args such that args contains Values
-// suitable for calling f.
-func arbitraryValues(args []reflect.Value, f reflect.Type, config *Config, rand *rand.Rand) (err os.Error) {
- if config.Values != nil {
- config.Values(args, rand)
- return
- }
-
- for j := 0; j < len(args); j++ {
- var ok bool
- args[j], ok = Value(f.In(j), rand)
- if !ok {
- err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j))
- return
- }
- }
-
- return
-}
-
-func functionAndType(f interface{}) (v reflect.Value, t reflect.Type, ok bool) {
- v = reflect.ValueOf(f)
- ok = v.Kind() == reflect.Func
- if !ok {
- return
- }
- t = v.Type()
- return
-}
-
-func toInterfaces(values []reflect.Value) []interface{} {
- ret := make([]interface{}, len(values))
- for i, v := range values {
- ret[i] = v.Interface()
- }
- return ret
-}
-
-func toString(interfaces []interface{}) string {
- s := make([]string, len(interfaces))
- for i, v := range interfaces {
- s[i] = fmt.Sprintf("%#v", v)
- }
- return strings.Join(s, ", ")
-}
diff --git a/src/cmd/gofix/testdata/reflect.read.go.in b/src/cmd/gofix/testdata/reflect.read.go.in
deleted file mode 100644
index 9ae3bb8ee..000000000
--- a/src/cmd/gofix/testdata/reflect.read.go.in
+++ /dev/null
@@ -1,620 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xml
-
-import (
- "bytes"
- "fmt"
- "io"
- "os"
- "reflect"
- "strconv"
- "strings"
- "unicode"
- "utf8"
-)
-
-// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
-// an XML element is an order-dependent collection of anonymous
-// values, while a data structure is an order-independent collection
-// of named values.
-// See package json for a textual representation more suitable
-// to data structures.
-
-// Unmarshal parses an XML element from r and uses the
-// reflect library to fill in an arbitrary struct, slice, or string
-// pointed at by val. Well-formed data that does not fit
-// into val is discarded.
-//
-// For example, given these definitions:
-//
-// type Email struct {
-// Where string "attr"
-// Addr string
-// }
-//
-// type Result struct {
-// XMLName xml.Name "result"
-// Name string
-// Phone string
-// Email []Email
-// Groups []string "group>value"
-// }
-//
-// result := Result{Name: "name", Phone: "phone", Email: nil}
-//
-// unmarshalling the XML input
-//
-// <result>
-// <email where="home">
-// <addr>gre@example.com</addr>
-// </email>
-// <email where='work'>
-// <addr>gre@work.com</addr>
-// </email>
-// <name>Grace R. Emlin</name>
-// <group>
-// <value>Friends</value>
-// <value>Squash</value>
-// </group>
-// <address>123 Main Street</address>
-// </result>
-//
-// via Unmarshal(r, &result) is equivalent to assigning
-//
-// r = Result{xml.Name{"", "result"},
-// "Grace R. Emlin", // name
-// "phone", // no phone given
-// []Email{
-// Email{"home", "gre@example.com"},
-// Email{"work", "gre@work.com"},
-// },
-// []string{"Friends", "Squash"},
-// }
-//
-// Note that the field r.Phone has not been modified and
-// that the XML <address> element was discarded. Also, the field
-// Groups was assigned considering the element path provided in the
-// field tag.
-//
-// Because Unmarshal uses the reflect package, it can only
-// assign to upper case fields. Unmarshal uses a case-insensitive
-// comparison to match XML element names to struct field names.
-//
-// Unmarshal maps an XML element to a struct using the following rules:
-//
-// * If the struct has a field of type []byte or string with tag "innerxml",
-// Unmarshal accumulates the raw XML nested inside the element
-// in that field. The rest of the rules still apply.
-//
-// * If the struct has a field named XMLName of type xml.Name,
-// Unmarshal records the element name in that field.
-//
-// * If the XMLName field has an associated tag string of the form
-// "tag" or "namespace-URL tag", the XML element must have
-// the given tag (and, optionally, name space) or else Unmarshal
-// returns an error.
-//
-// * If the XML element has an attribute whose name matches a
-// struct field of type string with tag "attr", Unmarshal records
-// the attribute value in that field.
-//
-// * If the XML element contains character data, that data is
-// accumulated in the first struct field that has tag "chardata".
-// The struct field may have type []byte or string.
-// If there is no such field, the character data is discarded.
-//
-// * If the XML element contains a sub-element whose name matches
-// the prefix of a struct field tag formatted as "a>b>c", unmarshal
-// will descend into the XML structure looking for elements with the
-// given names, and will map the innermost elements to that struct field.
-// A struct field tag starting with ">" is equivalent to one starting
-// with the field name followed by ">".
-//
-// * If the XML element contains a sub-element whose name
-// matches a struct field whose tag is neither "attr" nor "chardata",
-// Unmarshal maps the sub-element to that struct field.
-// Otherwise, if the struct has a field named Any, unmarshal
-// maps the sub-element to that struct field.
-//
-// Unmarshal maps an XML element to a string or []byte by saving the
-// concatenation of that element's character data in the string or []byte.
-//
-// Unmarshal maps an XML element to a slice by extending the length
-// of the slice and mapping the element to the newly created value.
-//
-// Unmarshal maps an XML element to a bool by setting it to the boolean
-// value represented by the string.
-//
-// Unmarshal maps an XML element to an integer or floating-point
-// field by setting the field to the result of interpreting the string
-// value in decimal. There is no check for overflow.
-//
-// Unmarshal maps an XML element to an xml.Name by recording the
-// element name.
-//
-// Unmarshal maps an XML element to a pointer by setting the pointer
-// to a freshly allocated value and then mapping the element to that value.
-//
-func Unmarshal(r io.Reader, val interface{}) os.Error {
- v, ok := reflect.NewValue(val).(*reflect.PtrValue)
- if !ok {
- return os.NewError("non-pointer passed to Unmarshal")
- }
- p := NewParser(r)
- elem := v.Elem()
- err := p.unmarshal(elem, nil)
- if err != nil {
- return err
- }
- return nil
-}
-
-// An UnmarshalError represents an error in the unmarshalling process.
-type UnmarshalError string
-
-func (e UnmarshalError) String() string { return string(e) }
-
-// A TagPathError represents an error in the unmarshalling process
-// caused by the use of field tags with conflicting paths.
-type TagPathError struct {
- Struct reflect.Type
- Field1, Tag1 string
- Field2, Tag2 string
-}
-
-func (e *TagPathError) String() string {
- return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2)
-}
-
-// The Parser's Unmarshal method is like xml.Unmarshal
-// except that it can be passed a pointer to the initial start element,
-// useful when a client reads some raw XML tokens itself
-// but also defers to Unmarshal for some elements.
-// Passing a nil start element indicates that Unmarshal should
-// read the token stream to find the start element.
-func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
- v, ok := reflect.NewValue(val).(*reflect.PtrValue)
- if !ok {
- return os.NewError("non-pointer passed to Unmarshal")
- }
- return p.unmarshal(v.Elem(), start)
-}
-
-// fieldName strips invalid characters from an XML name
-// to create a valid Go struct name. It also converts the
-// name to lower case letters.
-func fieldName(original string) string {
-
- var i int
- //remove leading underscores
- for i = 0; i < len(original) && original[i] == '_'; i++ {
- }
-
- return strings.Map(
- func(x int) int {
- if x == '_' || unicode.IsDigit(x) || unicode.IsLetter(x) {
- return unicode.ToLower(x)
- }
- return -1
- },
- original[i:])
-}
-
-// Unmarshal a single XML element into val.
-func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
- // Find start element if we need it.
- if start == nil {
- for {
- tok, err := p.Token()
- if err != nil {
- return err
- }
- if t, ok := tok.(StartElement); ok {
- start = &t
- break
- }
- }
- }
-
- if pv, ok := val.(*reflect.PtrValue); ok {
- if pv.Get() == 0 {
- zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem())
- pv.PointTo(zv)
- val = zv
- } else {
- val = pv.Elem()
- }
- }
-
- var (
- data []byte
- saveData reflect.Value
- comment []byte
- saveComment reflect.Value
- saveXML reflect.Value
- saveXMLIndex int
- saveXMLData []byte
- sv *reflect.StructValue
- styp *reflect.StructType
- fieldPaths map[string]pathInfo
- )
-
- switch v := val.(type) {
- default:
- return os.ErrorString("unknown type " + v.Type().String())
-
- case *reflect.SliceValue:
- typ := v.Type().(*reflect.SliceType)
- if typ.Elem().Kind() == reflect.Uint8 {
- // []byte
- saveData = v
- break
- }
-
- // Slice of element values.
- // Grow slice.
- n := v.Len()
- if n >= v.Cap() {
- ncap := 2 * n
- if ncap < 4 {
- ncap = 4
- }
- new := reflect.MakeSlice(typ, n, ncap)
- reflect.Copy(new, v)
- v.Set(new)
- }
- v.SetLen(n + 1)
-
- // Recur to read element into slice.
- if err := p.unmarshal(v.Elem(n), start); err != nil {
- v.SetLen(n)
- return err
- }
- return nil
-
- case *reflect.BoolValue, *reflect.FloatValue, *reflect.IntValue, *reflect.UintValue, *reflect.StringValue:
- saveData = v
-
- case *reflect.StructValue:
- if _, ok := v.Interface().(Name); ok {
- v.Set(reflect.NewValue(start.Name).(*reflect.StructValue))
- break
- }
-
- sv = v
- typ := sv.Type().(*reflect.StructType)
- styp = typ
- // Assign name.
- if f, ok := typ.FieldByName("XMLName"); ok {
- // Validate element name.
- if f.Tag != "" {
- tag := f.Tag
- ns := ""
- i := strings.LastIndex(tag, " ")
- if i >= 0 {
- ns, tag = tag[0:i], tag[i+1:]
- }
- if tag != start.Name.Local {
- return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
- }
- if ns != "" && ns != start.Name.Space {
- e := "expected element <" + tag + "> in name space " + ns + " but have "
- if start.Name.Space == "" {
- e += "no name space"
- } else {
- e += start.Name.Space
- }
- return UnmarshalError(e)
- }
- }
-
- // Save
- v := sv.FieldByIndex(f.Index)
- if _, ok := v.Interface().(Name); !ok {
- return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
- }
- v.(*reflect.StructValue).Set(reflect.NewValue(start.Name).(*reflect.StructValue))
- }
-
- // Assign attributes.
- // Also, determine whether we need to save character data or comments.
- for i, n := 0, typ.NumField(); i < n; i++ {
- f := typ.Field(i)
- switch f.Tag {
- case "attr":
- strv, ok := sv.FieldByIndex(f.Index).(*reflect.StringValue)
- if !ok {
- return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
- }
- // Look for attribute.
- val := ""
- k := strings.ToLower(f.Name)
- for _, a := range start.Attr {
- if fieldName(a.Name.Local) == k {
- val = a.Value
- break
- }
- }
- strv.Set(val)
-
- case "comment":
- if saveComment == nil {
- saveComment = sv.FieldByIndex(f.Index)
- }
-
- case "chardata":
- if saveData == nil {
- saveData = sv.FieldByIndex(f.Index)
- }
-
- case "innerxml":
- if saveXML == nil {
- saveXML = sv.FieldByIndex(f.Index)
- if p.saved == nil {
- saveXMLIndex = 0
- p.saved = new(bytes.Buffer)
- } else {
- saveXMLIndex = p.savedOffset()
- }
- }
-
- default:
- if strings.Contains(f.Tag, ">") {
- if fieldPaths == nil {
- fieldPaths = make(map[string]pathInfo)
- }
- path := strings.ToLower(f.Tag)
- if strings.HasPrefix(f.Tag, ">") {
- path = strings.ToLower(f.Name) + path
- }
- if strings.HasSuffix(f.Tag, ">") {
- path = path[:len(path)-1]
- }
- err := addFieldPath(sv, fieldPaths, path, f.Index)
- if err != nil {
- return err
- }
- }
- }
- }
- }
-
- // Find end element.
- // Process sub-elements along the way.
-Loop:
- for {
- var savedOffset int
- if saveXML != nil {
- savedOffset = p.savedOffset()
- }
- tok, err := p.Token()
- if err != nil {
- return err
- }
- switch t := tok.(type) {
- case StartElement:
- // Sub-element.
- // Look up by tag name.
- if sv != nil {
- k := fieldName(t.Name.Local)
-
- if fieldPaths != nil {
- if _, found := fieldPaths[k]; found {
- if err := p.unmarshalPaths(sv, fieldPaths, k, &t); err != nil {
- return err
- }
- continue Loop
- }
- }
-
- match := func(s string) bool {
- // check if the name matches ignoring case
- if strings.ToLower(s) != k {
- return false
- }
- // now check that it's public
- c, _ := utf8.DecodeRuneInString(s)
- return unicode.IsUpper(c)
- }
-
- f, found := styp.FieldByNameFunc(match)
- if !found { // fall back to mop-up field named "Any"
- f, found = styp.FieldByName("Any")
- }
- if found {
- if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
- return err
- }
- continue Loop
- }
- }
- // Not saving sub-element but still have to skip over it.
- if err := p.Skip(); err != nil {
- return err
- }
-
- case EndElement:
- if saveXML != nil {
- saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
- if saveXMLIndex == 0 {
- p.saved = nil
- }
- }
- break Loop
-
- case CharData:
- if saveData != nil {
- data = append(data, t...)
- }
-
- case Comment:
- if saveComment != nil {
- comment = append(comment, t...)
- }
- }
- }
-
- var err os.Error
- // Helper functions for integer and unsigned integer conversions
- var itmp int64
- getInt64 := func() bool {
- itmp, err = strconv.Atoi64(string(data))
- // TODO: should check sizes
- return err == nil
- }
- var utmp uint64
- getUint64 := func() bool {
- utmp, err = strconv.Atoui64(string(data))
- // TODO: check for overflow?
- return err == nil
- }
- var ftmp float64
- getFloat64 := func() bool {
- ftmp, err = strconv.Atof64(string(data))
- // TODO: check for overflow?
- return err == nil
- }
-
- // Save accumulated data and comments
- switch t := saveData.(type) {
- case nil:
- // Probably a comment, handled below
- default:
- return os.ErrorString("cannot happen: unknown type " + t.Type().String())
- case *reflect.IntValue:
- if !getInt64() {
- return err
- }
- t.Set(itmp)
- case *reflect.UintValue:
- if !getUint64() {
- return err
- }
- t.Set(utmp)
- case *reflect.FloatValue:
- if !getFloat64() {
- return err
- }
- t.Set(ftmp)
- case *reflect.BoolValue:
- value, err := strconv.Atob(strings.TrimSpace(string(data)))
- if err != nil {
- return err
- }
- t.Set(value)
- case *reflect.StringValue:
- t.Set(string(data))
- case *reflect.SliceValue:
- t.Set(reflect.NewValue(data).(*reflect.SliceValue))
- }
-
- switch t := saveComment.(type) {
- case *reflect.StringValue:
- t.Set(string(comment))
- case *reflect.SliceValue:
- t.Set(reflect.NewValue(comment).(*reflect.SliceValue))
- }
-
- switch t := saveXML.(type) {
- case *reflect.StringValue:
- t.Set(string(saveXMLData))
- case *reflect.SliceValue:
- t.Set(reflect.NewValue(saveXMLData).(*reflect.SliceValue))
- }
-
- return nil
-}
-
-type pathInfo struct {
- fieldIdx []int
- complete bool
-}
-
-// addFieldPath takes an element path such as "a>b>c" and fills the
-// paths map with all paths leading to it ("a", "a>b", and "a>b>c").
-// It is okay for paths to share a common, shorter prefix but not ok
-// for one path to itself be a prefix of another.
-func addFieldPath(sv *reflect.StructValue, paths map[string]pathInfo, path string, fieldIdx []int) os.Error {
- if info, found := paths[path]; found {
- return tagError(sv, info.fieldIdx, fieldIdx)
- }
- paths[path] = pathInfo{fieldIdx, true}
- for {
- i := strings.LastIndex(path, ">")
- if i < 0 {
- break
- }
- path = path[:i]
- if info, found := paths[path]; found {
- if info.complete {
- return tagError(sv, info.fieldIdx, fieldIdx)
- }
- } else {
- paths[path] = pathInfo{fieldIdx, false}
- }
- }
- return nil
-
-}
-
-func tagError(sv *reflect.StructValue, idx1 []int, idx2 []int) os.Error {
- t := sv.Type().(*reflect.StructType)
- f1 := t.FieldByIndex(idx1)
- f2 := t.FieldByIndex(idx2)
- return &TagPathError{t, f1.Name, f1.Tag, f2.Name, f2.Tag}
-}
-
-// unmarshalPaths walks down an XML structure looking for
-// wanted paths, and calls unmarshal on them.
-func (p *Parser) unmarshalPaths(sv *reflect.StructValue, paths map[string]pathInfo, path string, start *StartElement) os.Error {
- if info, _ := paths[path]; info.complete {
- return p.unmarshal(sv.FieldByIndex(info.fieldIdx), start)
- }
- for {
- tok, err := p.Token()
- if err != nil {
- return err
- }
- switch t := tok.(type) {
- case StartElement:
- k := path + ">" + fieldName(t.Name.Local)
- if _, found := paths[k]; found {
- if err := p.unmarshalPaths(sv, paths, k, &t); err != nil {
- return err
- }
- continue
- }
- if err := p.Skip(); err != nil {
- return err
- }
- case EndElement:
- return nil
- }
- }
- panic("unreachable")
-}
-
-// Have already read a start element.
-// Read tokens until we find the end element.
-// Token is taking care of making sure the
-// end element matches the start element we saw.
-func (p *Parser) Skip() os.Error {
- for {
- tok, err := p.Token()
- if err != nil {
- return err
- }
- switch t := tok.(type) {
- case StartElement:
- if err := p.Skip(); err != nil {
- return err
- }
- case EndElement:
- return nil
- }
- }
- panic("unreachable")
-}
diff --git a/src/cmd/gofix/testdata/reflect.read.go.out b/src/cmd/gofix/testdata/reflect.read.go.out
deleted file mode 100644
index a6b126744..000000000
--- a/src/cmd/gofix/testdata/reflect.read.go.out
+++ /dev/null
@@ -1,620 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xml
-
-import (
- "bytes"
- "fmt"
- "io"
- "os"
- "reflect"
- "strconv"
- "strings"
- "unicode"
- "utf8"
-)
-
-// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
-// an XML element is an order-dependent collection of anonymous
-// values, while a data structure is an order-independent collection
-// of named values.
-// See package json for a textual representation more suitable
-// to data structures.
-
-// Unmarshal parses an XML element from r and uses the
-// reflect library to fill in an arbitrary struct, slice, or string
-// pointed at by val. Well-formed data that does not fit
-// into val is discarded.
-//
-// For example, given these definitions:
-//
-// type Email struct {
-// Where string "attr"
-// Addr string
-// }
-//
-// type Result struct {
-// XMLName xml.Name "result"
-// Name string
-// Phone string
-// Email []Email
-// Groups []string "group>value"
-// }
-//
-// result := Result{Name: "name", Phone: "phone", Email: nil}
-//
-// unmarshalling the XML input
-//
-// <result>
-// <email where="home">
-// <addr>gre@example.com</addr>
-// </email>
-// <email where='work'>
-// <addr>gre@work.com</addr>
-// </email>
-// <name>Grace R. Emlin</name>
-// <group>
-// <value>Friends</value>
-// <value>Squash</value>
-// </group>
-// <address>123 Main Street</address>
-// </result>
-//
-// via Unmarshal(r, &result) is equivalent to assigning
-//
-// r = Result{xml.Name{"", "result"},
-// "Grace R. Emlin", // name
-// "phone", // no phone given
-// []Email{
-// Email{"home", "gre@example.com"},
-// Email{"work", "gre@work.com"},
-// },
-// []string{"Friends", "Squash"},
-// }
-//
-// Note that the field r.Phone has not been modified and
-// that the XML <address> element was discarded. Also, the field
-// Groups was assigned considering the element path provided in the
-// field tag.
-//
-// Because Unmarshal uses the reflect package, it can only
-// assign to upper case fields. Unmarshal uses a case-insensitive
-// comparison to match XML element names to struct field names.
-//
-// Unmarshal maps an XML element to a struct using the following rules:
-//
-// * If the struct has a field of type []byte or string with tag "innerxml",
-// Unmarshal accumulates the raw XML nested inside the element
-// in that field. The rest of the rules still apply.
-//
-// * If the struct has a field named XMLName of type xml.Name,
-// Unmarshal records the element name in that field.
-//
-// * If the XMLName field has an associated tag string of the form
-// "tag" or "namespace-URL tag", the XML element must have
-// the given tag (and, optionally, name space) or else Unmarshal
-// returns an error.
-//
-// * If the XML element has an attribute whose name matches a
-// struct field of type string with tag "attr", Unmarshal records
-// the attribute value in that field.
-//
-// * If the XML element contains character data, that data is
-// accumulated in the first struct field that has tag "chardata".
-// The struct field may have type []byte or string.
-// If there is no such field, the character data is discarded.
-//
-// * If the XML element contains a sub-element whose name matches
-// the prefix of a struct field tag formatted as "a>b>c", unmarshal
-// will descend into the XML structure looking for elements with the
-// given names, and will map the innermost elements to that struct field.
-// A struct field tag starting with ">" is equivalent to one starting
-// with the field name followed by ">".
-//
-// * If the XML element contains a sub-element whose name
-// matches a struct field whose tag is neither "attr" nor "chardata",
-// Unmarshal maps the sub-element to that struct field.
-// Otherwise, if the struct has a field named Any, unmarshal
-// maps the sub-element to that struct field.
-//
-// Unmarshal maps an XML element to a string or []byte by saving the
-// concatenation of that element's character data in the string or []byte.
-//
-// Unmarshal maps an XML element to a slice by extending the length
-// of the slice and mapping the element to the newly created value.
-//
-// Unmarshal maps an XML element to a bool by setting it to the boolean
-// value represented by the string.
-//
-// Unmarshal maps an XML element to an integer or floating-point
-// field by setting the field to the result of interpreting the string
-// value in decimal. There is no check for overflow.
-//
-// Unmarshal maps an XML element to an xml.Name by recording the
-// element name.
-//
-// Unmarshal maps an XML element to a pointer by setting the pointer
-// to a freshly allocated value and then mapping the element to that value.
-//
-func Unmarshal(r io.Reader, val interface{}) os.Error {
- v := reflect.ValueOf(val)
- if v.Kind() != reflect.Ptr {
- return os.NewError("non-pointer passed to Unmarshal")
- }
- p := NewParser(r)
- elem := v.Elem()
- err := p.unmarshal(elem, nil)
- if err != nil {
- return err
- }
- return nil
-}
-
-// An UnmarshalError represents an error in the unmarshalling process.
-type UnmarshalError string
-
-func (e UnmarshalError) String() string { return string(e) }
-
-// A TagPathError represents an error in the unmarshalling process
-// caused by the use of field tags with conflicting paths.
-type TagPathError struct {
- Struct reflect.Type
- Field1, Tag1 string
- Field2, Tag2 string
-}
-
-func (e *TagPathError) String() string {
- return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2)
-}
-
-// The Parser's Unmarshal method is like xml.Unmarshal
-// except that it can be passed a pointer to the initial start element,
-// useful when a client reads some raw XML tokens itself
-// but also defers to Unmarshal for some elements.
-// Passing a nil start element indicates that Unmarshal should
-// read the token stream to find the start element.
-func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
- v := reflect.ValueOf(val)
- if v.Kind() != reflect.Ptr {
- return os.NewError("non-pointer passed to Unmarshal")
- }
- return p.unmarshal(v.Elem(), start)
-}
-
-// fieldName strips invalid characters from an XML name
-// to create a valid Go struct name. It also converts the
-// name to lower case letters.
-func fieldName(original string) string {
-
- var i int
- //remove leading underscores
- for i = 0; i < len(original) && original[i] == '_'; i++ {
- }
-
- return strings.Map(
- func(x int) int {
- if x == '_' || unicode.IsDigit(x) || unicode.IsLetter(x) {
- return unicode.ToLower(x)
- }
- return -1
- },
- original[i:])
-}
-
-// Unmarshal a single XML element into val.
-func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
- // Find start element if we need it.
- if start == nil {
- for {
- tok, err := p.Token()
- if err != nil {
- return err
- }
- if t, ok := tok.(StartElement); ok {
- start = &t
- break
- }
- }
- }
-
- if pv := val; pv.Kind() == reflect.Ptr {
- if pv.Pointer() == 0 {
- zv := reflect.Zero(pv.Type().Elem())
- pv.Set(zv.Addr())
- val = zv
- } else {
- val = pv.Elem()
- }
- }
-
- var (
- data []byte
- saveData reflect.Value
- comment []byte
- saveComment reflect.Value
- saveXML reflect.Value
- saveXMLIndex int
- saveXMLData []byte
- sv reflect.Value
- styp reflect.Type
- fieldPaths map[string]pathInfo
- )
-
- switch v := val; v.Kind() {
- default:
- return os.NewError("unknown type " + v.Type().String())
-
- case reflect.Slice:
- typ := v.Type()
- if typ.Elem().Kind() == reflect.Uint8 {
- // []byte
- saveData = v
- break
- }
-
- // Slice of element values.
- // Grow slice.
- n := v.Len()
- if n >= v.Cap() {
- ncap := 2 * n
- if ncap < 4 {
- ncap = 4
- }
- new := reflect.MakeSlice(typ, n, ncap)
- reflect.Copy(new, v)
- v.Set(new)
- }
- v.SetLen(n + 1)
-
- // Recur to read element into slice.
- if err := p.unmarshal(v.Index(n), start); err != nil {
- v.SetLen(n)
- return err
- }
- return nil
-
- case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
- saveData = v
-
- case reflect.Struct:
- if _, ok := v.Interface().(Name); ok {
- v.Set(reflect.ValueOf(start.Name))
- break
- }
-
- sv = v
- typ := sv.Type()
- styp = typ
- // Assign name.
- if f, ok := typ.FieldByName("XMLName"); ok {
- // Validate element name.
- if f.Tag != "" {
- tag := f.Tag
- ns := ""
- i := strings.LastIndex(tag, " ")
- if i >= 0 {
- ns, tag = tag[0:i], tag[i+1:]
- }
- if tag != start.Name.Local {
- return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
- }
- if ns != "" && ns != start.Name.Space {
- e := "expected element <" + tag + "> in name space " + ns + " but have "
- if start.Name.Space == "" {
- e += "no name space"
- } else {
- e += start.Name.Space
- }
- return UnmarshalError(e)
- }
- }
-
- // Save
- v := sv.FieldByIndex(f.Index)
- if _, ok := v.Interface().(Name); !ok {
- return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
- }
- v.Set(reflect.ValueOf(start.Name))
- }
-
- // Assign attributes.
- // Also, determine whether we need to save character data or comments.
- for i, n := 0, typ.NumField(); i < n; i++ {
- f := typ.Field(i)
- switch f.Tag {
- case "attr":
- strv := sv.FieldByIndex(f.Index)
- if strv.Kind() != reflect.String {
- return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
- }
- // Look for attribute.
- val := ""
- k := strings.ToLower(f.Name)
- for _, a := range start.Attr {
- if fieldName(a.Name.Local) == k {
- val = a.Value
- break
- }
- }
- strv.SetString(val)
-
- case "comment":
- if !saveComment.IsValid() {
- saveComment = sv.FieldByIndex(f.Index)
- }
-
- case "chardata":
- if !saveData.IsValid() {
- saveData = sv.FieldByIndex(f.Index)
- }
-
- case "innerxml":
- if !saveXML.IsValid() {
- saveXML = sv.FieldByIndex(f.Index)
- if p.saved == nil {
- saveXMLIndex = 0
- p.saved = new(bytes.Buffer)
- } else {
- saveXMLIndex = p.savedOffset()
- }
- }
-
- default:
- if strings.Contains(f.Tag, ">") {
- if fieldPaths == nil {
- fieldPaths = make(map[string]pathInfo)
- }
- path := strings.ToLower(f.Tag)
- if strings.HasPrefix(f.Tag, ">") {
- path = strings.ToLower(f.Name) + path
- }
- if strings.HasSuffix(f.Tag, ">") {
- path = path[:len(path)-1]
- }
- err := addFieldPath(sv, fieldPaths, path, f.Index)
- if err != nil {
- return err
- }
- }
- }
- }
- }
-
- // Find end element.
- // Process sub-elements along the way.
-Loop:
- for {
- var savedOffset int
- if saveXML.IsValid() {
- savedOffset = p.savedOffset()
- }
- tok, err := p.Token()
- if err != nil {
- return err
- }
- switch t := tok.(type) {
- case StartElement:
- // Sub-element.
- // Look up by tag name.
- if sv.IsValid() {
- k := fieldName(t.Name.Local)
-
- if fieldPaths != nil {
- if _, found := fieldPaths[k]; found {
- if err := p.unmarshalPaths(sv, fieldPaths, k, &t); err != nil {
- return err
- }
- continue Loop
- }
- }
-
- match := func(s string) bool {
- // check if the name matches ignoring case
- if strings.ToLower(s) != k {
- return false
- }
- // now check that it's public
- c, _ := utf8.DecodeRuneInString(s)
- return unicode.IsUpper(c)
- }
-
- f, found := styp.FieldByNameFunc(match)
- if !found { // fall back to mop-up field named "Any"
- f, found = styp.FieldByName("Any")
- }
- if found {
- if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
- return err
- }
- continue Loop
- }
- }
- // Not saving sub-element but still have to skip over it.
- if err := p.Skip(); err != nil {
- return err
- }
-
- case EndElement:
- if saveXML.IsValid() {
- saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
- if saveXMLIndex == 0 {
- p.saved = nil
- }
- }
- break Loop
-
- case CharData:
- if saveData.IsValid() {
- data = append(data, t...)
- }
-
- case Comment:
- if saveComment.IsValid() {
- comment = append(comment, t...)
- }
- }
- }
-
- var err os.Error
- // Helper functions for integer and unsigned integer conversions
- var itmp int64
- getInt64 := func() bool {
- itmp, err = strconv.Atoi64(string(data))
- // TODO: should check sizes
- return err == nil
- }
- var utmp uint64
- getUint64 := func() bool {
- utmp, err = strconv.Atoui64(string(data))
- // TODO: check for overflow?
- return err == nil
- }
- var ftmp float64
- getFloat64 := func() bool {
- ftmp, err = strconv.Atof64(string(data))
- // TODO: check for overflow?
- return err == nil
- }
-
- // Save accumulated data and comments
- switch t := saveData; t.Kind() {
- case reflect.Invalid:
- // Probably a comment, handled below
- default:
- return os.NewError("cannot happen: unknown type " + t.Type().String())
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if !getInt64() {
- return err
- }
- t.SetInt(itmp)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- if !getUint64() {
- return err
- }
- t.SetUint(utmp)
- case reflect.Float32, reflect.Float64:
- if !getFloat64() {
- return err
- }
- t.SetFloat(ftmp)
- case reflect.Bool:
- value, err := strconv.Atob(strings.TrimSpace(string(data)))
- if err != nil {
- return err
- }
- t.SetBool(value)
- case reflect.String:
- t.SetString(string(data))
- case reflect.Slice:
- t.Set(reflect.ValueOf(data))
- }
-
- switch t := saveComment; t.Kind() {
- case reflect.String:
- t.SetString(string(comment))
- case reflect.Slice:
- t.Set(reflect.ValueOf(comment))
- }
-
- switch t := saveXML; t.Kind() {
- case reflect.String:
- t.SetString(string(saveXMLData))
- case reflect.Slice:
- t.Set(reflect.ValueOf(saveXMLData))
- }
-
- return nil
-}
-
-type pathInfo struct {
- fieldIdx []int
- complete bool
-}
-
-// addFieldPath takes an element path such as "a>b>c" and fills the
-// paths map with all paths leading to it ("a", "a>b", and "a>b>c").
-// It is okay for paths to share a common, shorter prefix but not ok
-// for one path to itself be a prefix of another.
-func addFieldPath(sv reflect.Value, paths map[string]pathInfo, path string, fieldIdx []int) os.Error {
- if info, found := paths[path]; found {
- return tagError(sv, info.fieldIdx, fieldIdx)
- }
- paths[path] = pathInfo{fieldIdx, true}
- for {
- i := strings.LastIndex(path, ">")
- if i < 0 {
- break
- }
- path = path[:i]
- if info, found := paths[path]; found {
- if info.complete {
- return tagError(sv, info.fieldIdx, fieldIdx)
- }
- } else {
- paths[path] = pathInfo{fieldIdx, false}
- }
- }
- return nil
-
-}
-
-func tagError(sv reflect.Value, idx1 []int, idx2 []int) os.Error {
- t := sv.Type()
- f1 := t.FieldByIndex(idx1)
- f2 := t.FieldByIndex(idx2)
- return &TagPathError{t, f1.Name, f1.Tag, f2.Name, f2.Tag}
-}
-
-// unmarshalPaths walks down an XML structure looking for
-// wanted paths, and calls unmarshal on them.
-func (p *Parser) unmarshalPaths(sv reflect.Value, paths map[string]pathInfo, path string, start *StartElement) os.Error {
- if info, _ := paths[path]; info.complete {
- return p.unmarshal(sv.FieldByIndex(info.fieldIdx), start)
- }
- for {
- tok, err := p.Token()
- if err != nil {
- return err
- }
- switch t := tok.(type) {
- case StartElement:
- k := path + ">" + fieldName(t.Name.Local)
- if _, found := paths[k]; found {
- if err := p.unmarshalPaths(sv, paths, k, &t); err != nil {
- return err
- }
- continue
- }
- if err := p.Skip(); err != nil {
- return err
- }
- case EndElement:
- return nil
- }
- }
- panic("unreachable")
-}
-
-// Have already read a start element.
-// Read tokens until we find the end element.
-// Token is taking care of making sure the
-// end element matches the start element we saw.
-func (p *Parser) Skip() os.Error {
- for {
- tok, err := p.Token()
- if err != nil {
- return err
- }
- switch t := tok.(type) {
- case StartElement:
- if err := p.Skip(); err != nil {
- return err
- }
- case EndElement:
- return nil
- }
- }
- panic("unreachable")
-}
diff --git a/src/cmd/gofix/testdata/reflect.scan.go.in b/src/cmd/gofix/testdata/reflect.scan.go.in
deleted file mode 100644
index 36271a8d4..000000000
--- a/src/cmd/gofix/testdata/reflect.scan.go.in
+++ /dev/null
@@ -1,1084 +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.
-
-package fmt
-
-import (
- "bytes"
- "io"
- "math"
- "os"
- "reflect"
- "strconv"
- "strings"
- "unicode"
- "utf8"
-)
-
-// runeUnreader is the interface to something that can unread runes.
-// If the object provided to Scan does not satisfy this interface,
-// a local buffer will be used to back up the input, but its contents
-// will be lost when Scan returns.
-type runeUnreader interface {
- UnreadRune() os.Error
-}
-
-// ScanState represents the scanner state passed to custom scanners.
-// Scanners may do rune-at-a-time scanning or ask the ScanState
-// to discover the next space-delimited token.
-type ScanState interface {
- // ReadRune reads the next rune (Unicode code point) from the input.
- // If invoked during Scanln, Fscanln, or Sscanln, ReadRune() will
- // return EOF after returning the first '\n' or when reading beyond
- // the specified width.
- ReadRune() (rune int, size int, err os.Error)
- // UnreadRune causes the next call to ReadRune to return the same rune.
- UnreadRune() os.Error
- // Token skips space in the input if skipSpace is true, then returns the
- // run of Unicode code points c satisfying f(c). If f is nil,
- // !unicode.IsSpace(c) is used; that is, the token will hold non-space
- // characters. Newlines are treated as space unless the scan operation
- // is Scanln, Fscanln or Sscanln, in which case a newline is treated as
- // EOF. The returned slice points to shared data that may be overwritten
- // by the next call to Token, a call to a Scan function using the ScanState
- // as input, or when the calling Scan method returns.
- Token(skipSpace bool, f func(int) bool) (token []byte, err os.Error)
- // Width returns the value of the width option and whether it has been set.
- // The unit is Unicode code points.
- Width() (wid int, ok bool)
- // Because ReadRune is implemented by the interface, Read should never be
- // called by the scanning routines and a valid implementation of
- // ScanState may choose always to return an error from Read.
- Read(buf []byte) (n int, err os.Error)
-}
-
-// Scanner is implemented by any value that has a Scan method, which scans
-// the input for the representation of a value and stores the result in the
-// receiver, which must be a pointer to be useful. The Scan method is called
-// for any argument to Scan, Scanf, or Scanln that implements it.
-type Scanner interface {
- Scan(state ScanState, verb int) os.Error
-}
-
-// Scan scans text read from standard input, storing successive
-// space-separated values into successive arguments. Newlines count
-// as space. It returns the number of items successfully scanned.
-// If that is less than the number of arguments, err will report why.
-func Scan(a ...interface{}) (n int, err os.Error) {
- return Fscan(os.Stdin, a...)
-}
-
-// Scanln is similar to Scan, but stops scanning at a newline and
-// after the final item there must be a newline or EOF.
-func Scanln(a ...interface{}) (n int, err os.Error) {
- return Fscanln(os.Stdin, a...)
-}
-
-// Scanf scans text read from standard input, storing successive
-// space-separated values into successive arguments as determined by
-// the format. It returns the number of items successfully scanned.
-func Scanf(format string, a ...interface{}) (n int, err os.Error) {
- return Fscanf(os.Stdin, format, a...)
-}
-
-// Sscan scans the argument string, storing successive space-separated
-// values into successive arguments. Newlines count as space. It
-// returns the number of items successfully scanned. If that is less
-// than the number of arguments, err will report why.
-func Sscan(str string, a ...interface{}) (n int, err os.Error) {
- return Fscan(strings.NewReader(str), a...)
-}
-
-// Sscanln is similar to Sscan, but stops scanning at a newline and
-// after the final item there must be a newline or EOF.
-func Sscanln(str string, a ...interface{}) (n int, err os.Error) {
- return Fscanln(strings.NewReader(str), a...)
-}
-
-// Sscanf scans the argument string, storing successive space-separated
-// values into successive arguments as determined by the format. It
-// returns the number of items successfully parsed.
-func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
- return Fscanf(strings.NewReader(str), format, a...)
-}
-
-// Fscan scans text read from r, storing successive space-separated
-// values into successive arguments. Newlines count as space. It
-// returns the number of items successfully scanned. If that is less
-// than the number of arguments, err will report why.
-func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
- s, old := newScanState(r, true, false)
- n, err = s.doScan(a)
- s.free(old)
- return
-}
-
-// Fscanln is similar to Fscan, but stops scanning at a newline and
-// after the final item there must be a newline or EOF.
-func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
- s, old := newScanState(r, false, true)
- n, err = s.doScan(a)
- s.free(old)
- return
-}
-
-// Fscanf scans text read from r, storing successive space-separated
-// values into successive arguments as determined by the format. It
-// returns the number of items successfully parsed.
-func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
- s, old := newScanState(r, false, false)
- n, err = s.doScanf(format, a)
- s.free(old)
- return
-}
-
-// scanError represents an error generated by the scanning software.
-// It's used as a unique signature to identify such errors when recovering.
-type scanError struct {
- err os.Error
-}
-
-const eof = -1
-
-// ss is the internal implementation of ScanState.
-type ss struct {
- rr io.RuneReader // where to read input
- buf bytes.Buffer // token accumulator
- peekRune int // one-rune lookahead
- prevRune int // last rune returned by ReadRune
- count int // runes consumed so far.
- atEOF bool // already read EOF
- ssave
-}
-
-// ssave holds the parts of ss that need to be
-// saved and restored on recursive scans.
-type ssave struct {
- validSave bool // is or was a part of an actual ss.
- nlIsEnd bool // whether newline terminates scan
- nlIsSpace bool // whether newline counts as white space
- fieldLimit int // max value of ss.count for this field; fieldLimit <= limit
- limit int // max value of ss.count.
- maxWid int // width of this field.
-}
-
-// The Read method is only in ScanState so that ScanState
-// satisfies io.Reader. It will never be called when used as
-// intended, so there is no need to make it actually work.
-func (s *ss) Read(buf []byte) (n int, err os.Error) {
- return 0, os.ErrorString("ScanState's Read should not be called. Use ReadRune")
-}
-
-func (s *ss) ReadRune() (rune int, size int, err os.Error) {
- if s.peekRune >= 0 {
- s.count++
- rune = s.peekRune
- size = utf8.RuneLen(rune)
- s.prevRune = rune
- s.peekRune = -1
- return
- }
- if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.fieldLimit {
- err = os.EOF
- return
- }
-
- rune, size, err = s.rr.ReadRune()
- if err == nil {
- s.count++
- s.prevRune = rune
- } else if err == os.EOF {
- s.atEOF = true
- }
- return
-}
-
-func (s *ss) Width() (wid int, ok bool) {
- if s.maxWid == hugeWid {
- return 0, false
- }
- return s.maxWid, true
-}
-
-// The public method returns an error; this private one panics.
-// If getRune reaches EOF, the return value is EOF (-1).
-func (s *ss) getRune() (rune int) {
- rune, _, err := s.ReadRune()
- if err != nil {
- if err == os.EOF {
- return eof
- }
- s.error(err)
- }
- return
-}
-
-// mustReadRune turns os.EOF into a panic(io.ErrUnexpectedEOF).
-// It is called in cases such as string scanning where an EOF is a
-// syntax error.
-func (s *ss) mustReadRune() (rune int) {
- rune = s.getRune()
- if rune == eof {
- s.error(io.ErrUnexpectedEOF)
- }
- return
-}
-
-func (s *ss) UnreadRune() os.Error {
- if u, ok := s.rr.(runeUnreader); ok {
- u.UnreadRune()
- } else {
- s.peekRune = s.prevRune
- }
- s.count--
- return nil
-}
-
-func (s *ss) error(err os.Error) {
- panic(scanError{err})
-}
-
-func (s *ss) errorString(err string) {
- panic(scanError{os.ErrorString(err)})
-}
-
-func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
- defer func() {
- if e := recover(); e != nil {
- if se, ok := e.(scanError); ok {
- err = se.err
- } else {
- panic(e)
- }
- }
- }()
- if f == nil {
- f = notSpace
- }
- s.buf.Reset()
- tok = s.token(skipSpace, f)
- return
-}
-
-// notSpace is the default scanning function used in Token.
-func notSpace(r int) bool {
- return !unicode.IsSpace(r)
-}
-
-// readRune is a structure to enable reading UTF-8 encoded code points
-// from an io.Reader. It is used if the Reader given to the scanner does
-// not already implement io.RuneReader.
-type readRune struct {
- reader io.Reader
- buf [utf8.UTFMax]byte // used only inside ReadRune
- pending int // number of bytes in pendBuf; only >0 for bad UTF-8
- pendBuf [utf8.UTFMax]byte // bytes left over
-}
-
-// readByte returns the next byte from the input, which may be
-// left over from a previous read if the UTF-8 was ill-formed.
-func (r *readRune) readByte() (b byte, err os.Error) {
- if r.pending > 0 {
- b = r.pendBuf[0]
- copy(r.pendBuf[0:], r.pendBuf[1:])
- r.pending--
- return
- }
- _, err = r.reader.Read(r.pendBuf[0:1])
- return r.pendBuf[0], err
-}
-
-// unread saves the bytes for the next read.
-func (r *readRune) unread(buf []byte) {
- copy(r.pendBuf[r.pending:], buf)
- r.pending += len(buf)
-}
-
-// ReadRune returns the next UTF-8 encoded code point from the
-// io.Reader inside r.
-func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
- r.buf[0], err = r.readByte()
- if err != nil {
- return 0, 0, err
- }
- if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
- rune = int(r.buf[0])
- return
- }
- var n int
- for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
- r.buf[n], err = r.readByte()
- if err != nil {
- if err == os.EOF {
- err = nil
- break
- }
- return
- }
- }
- rune, size = utf8.DecodeRune(r.buf[0:n])
- if size < n { // an error
- r.unread(r.buf[size:n])
- }
- return
-}
-
-
-var ssFree = newCache(func() interface{} { return new(ss) })
-
-// Allocate a new ss struct or grab a cached one.
-func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
- // If the reader is a *ss, then we've got a recursive
- // call to Scan, so re-use the scan state.
- s, ok := r.(*ss)
- if ok {
- old = s.ssave
- s.limit = s.fieldLimit
- s.nlIsEnd = nlIsEnd || s.nlIsEnd
- s.nlIsSpace = nlIsSpace
- return
- }
-
- s = ssFree.get().(*ss)
- if rr, ok := r.(io.RuneReader); ok {
- s.rr = rr
- } else {
- s.rr = &readRune{reader: r}
- }
- s.nlIsSpace = nlIsSpace
- s.nlIsEnd = nlIsEnd
- s.prevRune = -1
- s.peekRune = -1
- s.atEOF = false
- s.limit = hugeWid
- s.fieldLimit = hugeWid
- s.maxWid = hugeWid
- s.validSave = true
- return
-}
-
-// Save used ss structs in ssFree; avoid an allocation per invocation.
-func (s *ss) free(old ssave) {
- // If it was used recursively, just restore the old state.
- if old.validSave {
- s.ssave = old
- return
- }
- // Don't hold on to ss structs with large buffers.
- if cap(s.buf.Bytes()) > 1024 {
- return
- }
- s.buf.Reset()
- s.rr = nil
- ssFree.put(s)
-}
-
-// skipSpace skips spaces and maybe newlines.
-func (s *ss) skipSpace(stopAtNewline bool) {
- for {
- rune := s.getRune()
- if rune == eof {
- return
- }
- if rune == '\n' {
- if stopAtNewline {
- break
- }
- if s.nlIsSpace {
- continue
- }
- s.errorString("unexpected newline")
- return
- }
- if !unicode.IsSpace(rune) {
- s.UnreadRune()
- break
- }
- }
-}
-
-
-// token returns the next space-delimited string from the input. It
-// skips white space. For Scanln, it stops at newlines. For Scan,
-// newlines are treated as spaces.
-func (s *ss) token(skipSpace bool, f func(int) bool) []byte {
- if skipSpace {
- s.skipSpace(false)
- }
- // read until white space or newline
- for {
- rune := s.getRune()
- if rune == eof {
- break
- }
- if !f(rune) {
- s.UnreadRune()
- break
- }
- s.buf.WriteRune(rune)
- }
- return s.buf.Bytes()
-}
-
-// typeError indicates that the type of the operand did not match the format
-func (s *ss) typeError(field interface{}, expected string) {
- s.errorString("expected field of type pointer to " + expected + "; found " + reflect.Typeof(field).String())
-}
-
-var complexError = os.ErrorString("syntax error scanning complex number")
-var boolError = os.ErrorString("syntax error scanning boolean")
-
-// consume reads the next rune in the input and reports whether it is in the ok string.
-// If accept is true, it puts the character into the input token.
-func (s *ss) consume(ok string, accept bool) bool {
- rune := s.getRune()
- if rune == eof {
- return false
- }
- if strings.IndexRune(ok, rune) >= 0 {
- if accept {
- s.buf.WriteRune(rune)
- }
- return true
- }
- if rune != eof && accept {
- s.UnreadRune()
- }
- return false
-}
-
-// peek reports whether the next character is in the ok string, without consuming it.
-func (s *ss) peek(ok string) bool {
- rune := s.getRune()
- if rune != eof {
- s.UnreadRune()
- }
- return strings.IndexRune(ok, rune) >= 0
-}
-
-// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
-// buffer and returns true. Otherwise it return false.
-func (s *ss) accept(ok string) bool {
- return s.consume(ok, true)
-}
-
-// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
-func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
- for _, v := range okVerbs {
- if v == verb {
- return true
- }
- }
- s.errorString("bad verb %" + string(verb) + " for " + typ)
- return false
-}
-
-// scanBool returns the value of the boolean represented by the next token.
-func (s *ss) scanBool(verb int) bool {
- if !s.okVerb(verb, "tv", "boolean") {
- return false
- }
- // Syntax-checking a boolean is annoying. We're not fastidious about case.
- switch s.mustReadRune() {
- case '0':
- return false
- case '1':
- return true
- case 't', 'T':
- if s.accept("rR") && (!s.accept("uU") || !s.accept("eE")) {
- s.error(boolError)
- }
- return true
- case 'f', 'F':
- if s.accept("aL") && (!s.accept("lL") || !s.accept("sS") || !s.accept("eE")) {
- s.error(boolError)
- }
- return false
- }
- return false
-}
-
-// Numerical elements
-const (
- binaryDigits = "01"
- octalDigits = "01234567"
- decimalDigits = "0123456789"
- hexadecimalDigits = "0123456789aAbBcCdDeEfF"
- sign = "+-"
- period = "."
- exponent = "eEp"
-)
-
-// getBase returns the numeric base represented by the verb and its digit string.
-func (s *ss) getBase(verb int) (base int, digits string) {
- s.okVerb(verb, "bdoUxXv", "integer") // sets s.err
- base = 10
- digits = decimalDigits
- switch verb {
- case 'b':
- base = 2
- digits = binaryDigits
- case 'o':
- base = 8
- digits = octalDigits
- case 'x', 'X', 'U':
- base = 16
- digits = hexadecimalDigits
- }
- return
-}
-
-// scanNumber returns the numerical string with specified digits starting here.
-func (s *ss) scanNumber(digits string, haveDigits bool) string {
- if !haveDigits && !s.accept(digits) {
- s.errorString("expected integer")
- }
- for s.accept(digits) {
- }
- return s.buf.String()
-}
-
-// scanRune returns the next rune value in the input.
-func (s *ss) scanRune(bitSize int) int64 {
- rune := int64(s.mustReadRune())
- n := uint(bitSize)
- x := (rune << (64 - n)) >> (64 - n)
- if x != rune {
- s.errorString("overflow on character value " + string(rune))
- }
- return rune
-}
-
-// scanBasePrefix reports whether the integer begins with a 0 or 0x,
-// and returns the base, digit string, and whether a zero was found.
-// It is called only if the verb is %v.
-func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
- if !s.peek("0") {
- return 10, decimalDigits, false
- }
- s.accept("0")
- found = true // We've put a digit into the token buffer.
- // Special cases for '0' && '0x'
- base, digits = 8, octalDigits
- if s.peek("xX") {
- s.consume("xX", false)
- base, digits = 16, hexadecimalDigits
- }
- return
-}
-
-// scanInt returns the value of the integer represented by the next
-// token, checking for overflow. Any error is stored in s.err.
-func (s *ss) scanInt(verb int, bitSize int) int64 {
- if verb == 'c' {
- return s.scanRune(bitSize)
- }
- s.skipSpace(false)
- base, digits := s.getBase(verb)
- haveDigits := false
- if verb == 'U' {
- if !s.consume("U", false) || !s.consume("+", false) {
- s.errorString("bad unicode format ")
- }
- } else {
- s.accept(sign) // If there's a sign, it will be left in the token buffer.
- if verb == 'v' {
- base, digits, haveDigits = s.scanBasePrefix()
- }
- }
- tok := s.scanNumber(digits, haveDigits)
- i, err := strconv.Btoi64(tok, base)
- if err != nil {
- s.error(err)
- }
- n := uint(bitSize)
- x := (i << (64 - n)) >> (64 - n)
- if x != i {
- s.errorString("integer overflow on token " + tok)
- }
- return i
-}
-
-// scanUint returns the value of the unsigned integer represented
-// by the next token, checking for overflow. Any error is stored in s.err.
-func (s *ss) scanUint(verb int, bitSize int) uint64 {
- if verb == 'c' {
- return uint64(s.scanRune(bitSize))
- }
- s.skipSpace(false)
- base, digits := s.getBase(verb)
- haveDigits := false
- if verb == 'U' {
- if !s.consume("U", false) || !s.consume("+", false) {
- s.errorString("bad unicode format ")
- }
- } else if verb == 'v' {
- base, digits, haveDigits = s.scanBasePrefix()
- }
- tok := s.scanNumber(digits, haveDigits)
- i, err := strconv.Btoui64(tok, base)
- if err != nil {
- s.error(err)
- }
- n := uint(bitSize)
- x := (i << (64 - n)) >> (64 - n)
- if x != i {
- s.errorString("unsigned integer overflow on token " + tok)
- }
- return i
-}
-
-// floatToken returns the floating-point number starting here, no longer than swid
-// if the width is specified. It's not rigorous about syntax because it doesn't check that
-// we have at least some digits, but Atof will do that.
-func (s *ss) floatToken() string {
- s.buf.Reset()
- // NaN?
- if s.accept("nN") && s.accept("aA") && s.accept("nN") {
- return s.buf.String()
- }
- // leading sign?
- s.accept(sign)
- // Inf?
- if s.accept("iI") && s.accept("nN") && s.accept("fF") {
- return s.buf.String()
- }
- // digits?
- for s.accept(decimalDigits) {
- }
- // decimal point?
- if s.accept(period) {
- // fraction?
- for s.accept(decimalDigits) {
- }
- }
- // exponent?
- if s.accept(exponent) {
- // leading sign?
- s.accept(sign)
- // digits?
- for s.accept(decimalDigits) {
- }
- }
- return s.buf.String()
-}
-
-// complexTokens returns the real and imaginary parts of the complex number starting here.
-// The number might be parenthesized and has the format (N+Ni) where N is a floating-point
-// number and there are no spaces within.
-func (s *ss) complexTokens() (real, imag string) {
- // TODO: accept N and Ni independently?
- parens := s.accept("(")
- real = s.floatToken()
- s.buf.Reset()
- // Must now have a sign.
- if !s.accept("+-") {
- s.error(complexError)
- }
- // Sign is now in buffer
- imagSign := s.buf.String()
- imag = s.floatToken()
- if !s.accept("i") {
- s.error(complexError)
- }
- if parens && !s.accept(")") {
- s.error(complexError)
- }
- return real, imagSign + imag
-}
-
-// convertFloat converts the string to a float64value.
-func (s *ss) convertFloat(str string, n int) float64 {
- if p := strings.Index(str, "p"); p >= 0 {
- // Atof doesn't handle power-of-2 exponents,
- // but they're easy to evaluate.
- f, err := strconv.AtofN(str[:p], n)
- if err != nil {
- // Put full string into error.
- if e, ok := err.(*strconv.NumError); ok {
- e.Num = str
- }
- s.error(err)
- }
- n, err := strconv.Atoi(str[p+1:])
- if err != nil {
- // Put full string into error.
- if e, ok := err.(*strconv.NumError); ok {
- e.Num = str
- }
- s.error(err)
- }
- return math.Ldexp(f, n)
- }
- f, err := strconv.AtofN(str, n)
- if err != nil {
- s.error(err)
- }
- return f
-}
-
-// convertComplex converts the next token to a complex128 value.
-// The atof argument is a type-specific reader for the underlying type.
-// If we're reading complex64, atof will parse float32s and convert them
-// to float64's to avoid reproducing this code for each complex type.
-func (s *ss) scanComplex(verb int, n int) complex128 {
- if !s.okVerb(verb, floatVerbs, "complex") {
- return 0
- }
- s.skipSpace(false)
- sreal, simag := s.complexTokens()
- real := s.convertFloat(sreal, n/2)
- imag := s.convertFloat(simag, n/2)
- return complex(real, imag)
-}
-
-// convertString returns the string represented by the next input characters.
-// The format of the input is determined by the verb.
-func (s *ss) convertString(verb int) (str string) {
- if !s.okVerb(verb, "svqx", "string") {
- return ""
- }
- s.skipSpace(false)
- switch verb {
- case 'q':
- str = s.quotedString()
- case 'x':
- str = s.hexString()
- default:
- str = string(s.token(true, notSpace)) // %s and %v just return the next word
- }
- // Empty strings other than with %q are not OK.
- if len(str) == 0 && verb != 'q' && s.maxWid > 0 {
- s.errorString("Scan: no data for string")
- }
- return
-}
-
-// quotedString returns the double- or back-quoted string represented by the next input characters.
-func (s *ss) quotedString() string {
- quote := s.mustReadRune()
- switch quote {
- case '`':
- // Back-quoted: Anything goes until EOF or back quote.
- for {
- rune := s.mustReadRune()
- if rune == quote {
- break
- }
- s.buf.WriteRune(rune)
- }
- return s.buf.String()
- case '"':
- // Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
- s.buf.WriteRune(quote)
- for {
- rune := s.mustReadRune()
- s.buf.WriteRune(rune)
- if rune == '\\' {
- // In a legal backslash escape, no matter how long, only the character
- // immediately after the escape can itself be a backslash or quote.
- // Thus we only need to protect the first character after the backslash.
- rune := s.mustReadRune()
- s.buf.WriteRune(rune)
- } else if rune == '"' {
- break
- }
- }
- result, err := strconv.Unquote(s.buf.String())
- if err != nil {
- s.error(err)
- }
- return result
- default:
- s.errorString("expected quoted string")
- }
- return ""
-}
-
-// hexDigit returns the value of the hexadecimal digit
-func (s *ss) hexDigit(digit int) int {
- switch digit {
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- return digit - '0'
- case 'a', 'b', 'c', 'd', 'e', 'f':
- return 10 + digit - 'a'
- case 'A', 'B', 'C', 'D', 'E', 'F':
- return 10 + digit - 'A'
- }
- s.errorString("Scan: illegal hex digit")
- return 0
-}
-
-// hexByte returns the next hex-encoded (two-character) byte from the input.
-// There must be either two hexadecimal digits or a space character in the input.
-func (s *ss) hexByte() (b byte, ok bool) {
- rune1 := s.getRune()
- if rune1 == eof {
- return
- }
- if unicode.IsSpace(rune1) {
- s.UnreadRune()
- return
- }
- rune2 := s.mustReadRune()
- return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
-}
-
-// hexString returns the space-delimited hexpair-encoded string.
-func (s *ss) hexString() string {
- for {
- b, ok := s.hexByte()
- if !ok {
- break
- }
- s.buf.WriteByte(b)
- }
- if s.buf.Len() == 0 {
- s.errorString("Scan: no hex data for %x string")
- return ""
- }
- return s.buf.String()
-}
-
-const floatVerbs = "beEfFgGv"
-
-const hugeWid = 1 << 30
-
-// scanOne scans a single value, deriving the scanner from the type of the argument.
-func (s *ss) scanOne(verb int, field interface{}) {
- s.buf.Reset()
- var err os.Error
- // If the parameter has its own Scan method, use that.
- if v, ok := field.(Scanner); ok {
- err = v.Scan(s, verb)
- if err != nil {
- if err == os.EOF {
- err = io.ErrUnexpectedEOF
- }
- s.error(err)
- }
- return
- }
- switch v := field.(type) {
- case *bool:
- *v = s.scanBool(verb)
- case *complex64:
- *v = complex64(s.scanComplex(verb, 64))
- case *complex128:
- *v = s.scanComplex(verb, 128)
- case *int:
- *v = int(s.scanInt(verb, intBits))
- case *int8:
- *v = int8(s.scanInt(verb, 8))
- case *int16:
- *v = int16(s.scanInt(verb, 16))
- case *int32:
- *v = int32(s.scanInt(verb, 32))
- case *int64:
- *v = s.scanInt(verb, 64)
- case *uint:
- *v = uint(s.scanUint(verb, intBits))
- case *uint8:
- *v = uint8(s.scanUint(verb, 8))
- case *uint16:
- *v = uint16(s.scanUint(verb, 16))
- case *uint32:
- *v = uint32(s.scanUint(verb, 32))
- case *uint64:
- *v = s.scanUint(verb, 64)
- case *uintptr:
- *v = uintptr(s.scanUint(verb, uintptrBits))
- // Floats are tricky because you want to scan in the precision of the result, not
- // scan in high precision and convert, in order to preserve the correct error condition.
- case *float32:
- if s.okVerb(verb, floatVerbs, "float32") {
- s.skipSpace(false)
- *v = float32(s.convertFloat(s.floatToken(), 32))
- }
- case *float64:
- if s.okVerb(verb, floatVerbs, "float64") {
- s.skipSpace(false)
- *v = s.convertFloat(s.floatToken(), 64)
- }
- case *string:
- *v = s.convertString(verb)
- case *[]byte:
- // We scan to string and convert so we get a copy of the data.
- // If we scanned to bytes, the slice would point at the buffer.
- *v = []byte(s.convertString(verb))
- default:
- val := reflect.NewValue(v)
- ptr, ok := val.(*reflect.PtrValue)
- if !ok {
- s.errorString("Scan: type not a pointer: " + val.Type().String())
- return
- }
- switch v := ptr.Elem().(type) {
- case *reflect.BoolValue:
- v.Set(s.scanBool(verb))
- case *reflect.IntValue:
- v.Set(s.scanInt(verb, v.Type().Bits()))
- case *reflect.UintValue:
- v.Set(s.scanUint(verb, v.Type().Bits()))
- case *reflect.StringValue:
- v.Set(s.convertString(verb))
- case *reflect.SliceValue:
- // For now, can only handle (renamed) []byte.
- typ := v.Type().(*reflect.SliceType)
- if typ.Elem().Kind() != reflect.Uint8 {
- goto CantHandle
- }
- str := s.convertString(verb)
- v.Set(reflect.MakeSlice(typ, len(str), len(str)))
- for i := 0; i < len(str); i++ {
- v.Elem(i).(*reflect.UintValue).Set(uint64(str[i]))
- }
- case *reflect.FloatValue:
- s.skipSpace(false)
- v.Set(s.convertFloat(s.floatToken(), v.Type().Bits()))
- case *reflect.ComplexValue:
- v.Set(s.scanComplex(verb, v.Type().Bits()))
- default:
- CantHandle:
- s.errorString("Scan: can't handle type: " + val.Type().String())
- }
- }
-}
-
-// errorHandler turns local panics into error returns. EOFs are benign.
-func errorHandler(errp *os.Error) {
- if e := recover(); e != nil {
- if se, ok := e.(scanError); ok { // catch local error
- if se.err != os.EOF {
- *errp = se.err
- }
- } else {
- panic(e)
- }
- }
-}
-
-// doScan does the real work for scanning without a format string.
-func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
- defer errorHandler(&err)
- for _, field := range a {
- s.scanOne('v', field)
- numProcessed++
- }
- // Check for newline if required.
- if !s.nlIsSpace {
- for {
- rune := s.getRune()
- if rune == '\n' || rune == eof {
- break
- }
- if !unicode.IsSpace(rune) {
- s.errorString("Scan: expected newline")
- break
- }
- }
- }
- return
-}
-
-// advance determines whether the next characters in the input match
-// those of the format. It returns the number of bytes (sic) consumed
-// in the format. Newlines included, all runs of space characters in
-// either input or format behave as a single space. This routine also
-// handles the %% case. If the return value is zero, either format
-// starts with a % (with no following %) or the input is empty.
-// If it is negative, the input did not match the string.
-func (s *ss) advance(format string) (i int) {
- for i < len(format) {
- fmtc, w := utf8.DecodeRuneInString(format[i:])
- if fmtc == '%' {
- // %% acts like a real percent
- nextc, _ := utf8.DecodeRuneInString(format[i+w:]) // will not match % if string is empty
- if nextc != '%' {
- return
- }
- i += w // skip the first %
- }
- sawSpace := false
- for unicode.IsSpace(fmtc) && i < len(format) {
- sawSpace = true
- i += w
- fmtc, w = utf8.DecodeRuneInString(format[i:])
- }
- if sawSpace {
- // There was space in the format, so there should be space (EOF)
- // in the input.
- inputc := s.getRune()
- if inputc == eof {
- return
- }
- if !unicode.IsSpace(inputc) {
- // Space in format but not in input: error
- s.errorString("expected space in input to match format")
- }
- s.skipSpace(true)
- continue
- }
- inputc := s.mustReadRune()
- if fmtc != inputc {
- s.UnreadRune()
- return -1
- }
- i += w
- }
- return
-}
-
-// doScanf does the real work when scanning with a format string.
-// At the moment, it handles only pointers to basic types.
-func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) {
- defer errorHandler(&err)
- end := len(format) - 1
- // We process one item per non-trivial format
- for i := 0; i <= end; {
- w := s.advance(format[i:])
- if w > 0 {
- i += w
- continue
- }
- // Either we failed to advance, we have a percent character, or we ran out of input.
- if format[i] != '%' {
- // Can't advance format. Why not?
- if w < 0 {
- s.errorString("input does not match format")
- }
- // Otherwise at EOF; "too many operands" error handled below
- break
- }
- i++ // % is one byte
-
- // do we have 20 (width)?
- var widPresent bool
- s.maxWid, widPresent, i = parsenum(format, i, end)
- if !widPresent {
- s.maxWid = hugeWid
- }
- s.fieldLimit = s.limit
- if f := s.count + s.maxWid; f < s.fieldLimit {
- s.fieldLimit = f
- }
-
- c, w := utf8.DecodeRuneInString(format[i:])
- i += w
-
- if numProcessed >= len(a) { // out of operands
- s.errorString("too few operands for format %" + format[i-w:])
- break
- }
- field := a[numProcessed]
-
- s.scanOne(c, field)
- numProcessed++
- s.fieldLimit = s.limit
- }
- if numProcessed < len(a) {
- s.errorString("too many operands")
- }
- return
-}
diff --git a/src/cmd/gofix/testdata/reflect.scan.go.out b/src/cmd/gofix/testdata/reflect.scan.go.out
deleted file mode 100644
index 2b07115e9..000000000
--- a/src/cmd/gofix/testdata/reflect.scan.go.out
+++ /dev/null
@@ -1,1084 +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.
-
-package fmt
-
-import (
- "bytes"
- "io"
- "math"
- "os"
- "reflect"
- "strconv"
- "strings"
- "unicode"
- "utf8"
-)
-
-// runeUnreader is the interface to something that can unread runes.
-// If the object provided to Scan does not satisfy this interface,
-// a local buffer will be used to back up the input, but its contents
-// will be lost when Scan returns.
-type runeUnreader interface {
- UnreadRune() os.Error
-}
-
-// ScanState represents the scanner state passed to custom scanners.
-// Scanners may do rune-at-a-time scanning or ask the ScanState
-// to discover the next space-delimited token.
-type ScanState interface {
- // ReadRune reads the next rune (Unicode code point) from the input.
- // If invoked during Scanln, Fscanln, or Sscanln, ReadRune() will
- // return EOF after returning the first '\n' or when reading beyond
- // the specified width.
- ReadRune() (rune int, size int, err os.Error)
- // UnreadRune causes the next call to ReadRune to return the same rune.
- UnreadRune() os.Error
- // Token skips space in the input if skipSpace is true, then returns the
- // run of Unicode code points c satisfying f(c). If f is nil,
- // !unicode.IsSpace(c) is used; that is, the token will hold non-space
- // characters. Newlines are treated as space unless the scan operation
- // is Scanln, Fscanln or Sscanln, in which case a newline is treated as
- // EOF. The returned slice points to shared data that may be overwritten
- // by the next call to Token, a call to a Scan function using the ScanState
- // as input, or when the calling Scan method returns.
- Token(skipSpace bool, f func(int) bool) (token []byte, err os.Error)
- // Width returns the value of the width option and whether it has been set.
- // The unit is Unicode code points.
- Width() (wid int, ok bool)
- // Because ReadRune is implemented by the interface, Read should never be
- // called by the scanning routines and a valid implementation of
- // ScanState may choose always to return an error from Read.
- Read(buf []byte) (n int, err os.Error)
-}
-
-// Scanner is implemented by any value that has a Scan method, which scans
-// the input for the representation of a value and stores the result in the
-// receiver, which must be a pointer to be useful. The Scan method is called
-// for any argument to Scan, Scanf, or Scanln that implements it.
-type Scanner interface {
- Scan(state ScanState, verb int) os.Error
-}
-
-// Scan scans text read from standard input, storing successive
-// space-separated values into successive arguments. Newlines count
-// as space. It returns the number of items successfully scanned.
-// If that is less than the number of arguments, err will report why.
-func Scan(a ...interface{}) (n int, err os.Error) {
- return Fscan(os.Stdin, a...)
-}
-
-// Scanln is similar to Scan, but stops scanning at a newline and
-// after the final item there must be a newline or EOF.
-func Scanln(a ...interface{}) (n int, err os.Error) {
- return Fscanln(os.Stdin, a...)
-}
-
-// Scanf scans text read from standard input, storing successive
-// space-separated values into successive arguments as determined by
-// the format. It returns the number of items successfully scanned.
-func Scanf(format string, a ...interface{}) (n int, err os.Error) {
- return Fscanf(os.Stdin, format, a...)
-}
-
-// Sscan scans the argument string, storing successive space-separated
-// values into successive arguments. Newlines count as space. It
-// returns the number of items successfully scanned. If that is less
-// than the number of arguments, err will report why.
-func Sscan(str string, a ...interface{}) (n int, err os.Error) {
- return Fscan(strings.NewReader(str), a...)
-}
-
-// Sscanln is similar to Sscan, but stops scanning at a newline and
-// after the final item there must be a newline or EOF.
-func Sscanln(str string, a ...interface{}) (n int, err os.Error) {
- return Fscanln(strings.NewReader(str), a...)
-}
-
-// Sscanf scans the argument string, storing successive space-separated
-// values into successive arguments as determined by the format. It
-// returns the number of items successfully parsed.
-func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
- return Fscanf(strings.NewReader(str), format, a...)
-}
-
-// Fscan scans text read from r, storing successive space-separated
-// values into successive arguments. Newlines count as space. It
-// returns the number of items successfully scanned. If that is less
-// than the number of arguments, err will report why.
-func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
- s, old := newScanState(r, true, false)
- n, err = s.doScan(a)
- s.free(old)
- return
-}
-
-// Fscanln is similar to Fscan, but stops scanning at a newline and
-// after the final item there must be a newline or EOF.
-func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
- s, old := newScanState(r, false, true)
- n, err = s.doScan(a)
- s.free(old)
- return
-}
-
-// Fscanf scans text read from r, storing successive space-separated
-// values into successive arguments as determined by the format. It
-// returns the number of items successfully parsed.
-func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
- s, old := newScanState(r, false, false)
- n, err = s.doScanf(format, a)
- s.free(old)
- return
-}
-
-// scanError represents an error generated by the scanning software.
-// It's used as a unique signature to identify such errors when recovering.
-type scanError struct {
- err os.Error
-}
-
-const eof = -1
-
-// ss is the internal implementation of ScanState.
-type ss struct {
- rr io.RuneReader // where to read input
- buf bytes.Buffer // token accumulator
- peekRune int // one-rune lookahead
- prevRune int // last rune returned by ReadRune
- count int // runes consumed so far.
- atEOF bool // already read EOF
- ssave
-}
-
-// ssave holds the parts of ss that need to be
-// saved and restored on recursive scans.
-type ssave struct {
- validSave bool // is or was a part of an actual ss.
- nlIsEnd bool // whether newline terminates scan
- nlIsSpace bool // whether newline counts as white space
- fieldLimit int // max value of ss.count for this field; fieldLimit <= limit
- limit int // max value of ss.count.
- maxWid int // width of this field.
-}
-
-// The Read method is only in ScanState so that ScanState
-// satisfies io.Reader. It will never be called when used as
-// intended, so there is no need to make it actually work.
-func (s *ss) Read(buf []byte) (n int, err os.Error) {
- return 0, os.NewError("ScanState's Read should not be called. Use ReadRune")
-}
-
-func (s *ss) ReadRune() (rune int, size int, err os.Error) {
- if s.peekRune >= 0 {
- s.count++
- rune = s.peekRune
- size = utf8.RuneLen(rune)
- s.prevRune = rune
- s.peekRune = -1
- return
- }
- if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.fieldLimit {
- err = os.EOF
- return
- }
-
- rune, size, err = s.rr.ReadRune()
- if err == nil {
- s.count++
- s.prevRune = rune
- } else if err == os.EOF {
- s.atEOF = true
- }
- return
-}
-
-func (s *ss) Width() (wid int, ok bool) {
- if s.maxWid == hugeWid {
- return 0, false
- }
- return s.maxWid, true
-}
-
-// The public method returns an error; this private one panics.
-// If getRune reaches EOF, the return value is EOF (-1).
-func (s *ss) getRune() (rune int) {
- rune, _, err := s.ReadRune()
- if err != nil {
- if err == os.EOF {
- return eof
- }
- s.error(err)
- }
- return
-}
-
-// mustReadRune turns os.EOF into a panic(io.ErrUnexpectedEOF).
-// It is called in cases such as string scanning where an EOF is a
-// syntax error.
-func (s *ss) mustReadRune() (rune int) {
- rune = s.getRune()
- if rune == eof {
- s.error(io.ErrUnexpectedEOF)
- }
- return
-}
-
-func (s *ss) UnreadRune() os.Error {
- if u, ok := s.rr.(runeUnreader); ok {
- u.UnreadRune()
- } else {
- s.peekRune = s.prevRune
- }
- s.count--
- return nil
-}
-
-func (s *ss) error(err os.Error) {
- panic(scanError{err})
-}
-
-func (s *ss) errorString(err string) {
- panic(scanError{os.NewError(err)})
-}
-
-func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
- defer func() {
- if e := recover(); e != nil {
- if se, ok := e.(scanError); ok {
- err = se.err
- } else {
- panic(e)
- }
- }
- }()
- if f == nil {
- f = notSpace
- }
- s.buf.Reset()
- tok = s.token(skipSpace, f)
- return
-}
-
-// notSpace is the default scanning function used in Token.
-func notSpace(r int) bool {
- return !unicode.IsSpace(r)
-}
-
-// readRune is a structure to enable reading UTF-8 encoded code points
-// from an io.Reader. It is used if the Reader given to the scanner does
-// not already implement io.RuneReader.
-type readRune struct {
- reader io.Reader
- buf [utf8.UTFMax]byte // used only inside ReadRune
- pending int // number of bytes in pendBuf; only >0 for bad UTF-8
- pendBuf [utf8.UTFMax]byte // bytes left over
-}
-
-// readByte returns the next byte from the input, which may be
-// left over from a previous read if the UTF-8 was ill-formed.
-func (r *readRune) readByte() (b byte, err os.Error) {
- if r.pending > 0 {
- b = r.pendBuf[0]
- copy(r.pendBuf[0:], r.pendBuf[1:])
- r.pending--
- return
- }
- _, err = r.reader.Read(r.pendBuf[0:1])
- return r.pendBuf[0], err
-}
-
-// unread saves the bytes for the next read.
-func (r *readRune) unread(buf []byte) {
- copy(r.pendBuf[r.pending:], buf)
- r.pending += len(buf)
-}
-
-// ReadRune returns the next UTF-8 encoded code point from the
-// io.Reader inside r.
-func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
- r.buf[0], err = r.readByte()
- if err != nil {
- return 0, 0, err
- }
- if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
- rune = int(r.buf[0])
- return
- }
- var n int
- for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
- r.buf[n], err = r.readByte()
- if err != nil {
- if err == os.EOF {
- err = nil
- break
- }
- return
- }
- }
- rune, size = utf8.DecodeRune(r.buf[0:n])
- if size < n { // an error
- r.unread(r.buf[size:n])
- }
- return
-}
-
-
-var ssFree = newCache(func() interface{} { return new(ss) })
-
-// Allocate a new ss struct or grab a cached one.
-func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
- // If the reader is a *ss, then we've got a recursive
- // call to Scan, so re-use the scan state.
- s, ok := r.(*ss)
- if ok {
- old = s.ssave
- s.limit = s.fieldLimit
- s.nlIsEnd = nlIsEnd || s.nlIsEnd
- s.nlIsSpace = nlIsSpace
- return
- }
-
- s = ssFree.get().(*ss)
- if rr, ok := r.(io.RuneReader); ok {
- s.rr = rr
- } else {
- s.rr = &readRune{reader: r}
- }
- s.nlIsSpace = nlIsSpace
- s.nlIsEnd = nlIsEnd
- s.prevRune = -1
- s.peekRune = -1
- s.atEOF = false
- s.limit = hugeWid
- s.fieldLimit = hugeWid
- s.maxWid = hugeWid
- s.validSave = true
- return
-}
-
-// Save used ss structs in ssFree; avoid an allocation per invocation.
-func (s *ss) free(old ssave) {
- // If it was used recursively, just restore the old state.
- if old.validSave {
- s.ssave = old
- return
- }
- // Don't hold on to ss structs with large buffers.
- if cap(s.buf.Bytes()) > 1024 {
- return
- }
- s.buf.Reset()
- s.rr = nil
- ssFree.put(s)
-}
-
-// skipSpace skips spaces and maybe newlines.
-func (s *ss) skipSpace(stopAtNewline bool) {
- for {
- rune := s.getRune()
- if rune == eof {
- return
- }
- if rune == '\n' {
- if stopAtNewline {
- break
- }
- if s.nlIsSpace {
- continue
- }
- s.errorString("unexpected newline")
- return
- }
- if !unicode.IsSpace(rune) {
- s.UnreadRune()
- break
- }
- }
-}
-
-
-// token returns the next space-delimited string from the input. It
-// skips white space. For Scanln, it stops at newlines. For Scan,
-// newlines are treated as spaces.
-func (s *ss) token(skipSpace bool, f func(int) bool) []byte {
- if skipSpace {
- s.skipSpace(false)
- }
- // read until white space or newline
- for {
- rune := s.getRune()
- if rune == eof {
- break
- }
- if !f(rune) {
- s.UnreadRune()
- break
- }
- s.buf.WriteRune(rune)
- }
- return s.buf.Bytes()
-}
-
-// typeError indicates that the type of the operand did not match the format
-func (s *ss) typeError(field interface{}, expected string) {
- s.errorString("expected field of type pointer to " + expected + "; found " + reflect.TypeOf(field).String())
-}
-
-var complexError = os.NewError("syntax error scanning complex number")
-var boolError = os.NewError("syntax error scanning boolean")
-
-// consume reads the next rune in the input and reports whether it is in the ok string.
-// If accept is true, it puts the character into the input token.
-func (s *ss) consume(ok string, accept bool) bool {
- rune := s.getRune()
- if rune == eof {
- return false
- }
- if strings.IndexRune(ok, rune) >= 0 {
- if accept {
- s.buf.WriteRune(rune)
- }
- return true
- }
- if rune != eof && accept {
- s.UnreadRune()
- }
- return false
-}
-
-// peek reports whether the next character is in the ok string, without consuming it.
-func (s *ss) peek(ok string) bool {
- rune := s.getRune()
- if rune != eof {
- s.UnreadRune()
- }
- return strings.IndexRune(ok, rune) >= 0
-}
-
-// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
-// buffer and returns true. Otherwise it return false.
-func (s *ss) accept(ok string) bool {
- return s.consume(ok, true)
-}
-
-// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
-func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
- for _, v := range okVerbs {
- if v == verb {
- return true
- }
- }
- s.errorString("bad verb %" + string(verb) + " for " + typ)
- return false
-}
-
-// scanBool returns the value of the boolean represented by the next token.
-func (s *ss) scanBool(verb int) bool {
- if !s.okVerb(verb, "tv", "boolean") {
- return false
- }
- // Syntax-checking a boolean is annoying. We're not fastidious about case.
- switch s.mustReadRune() {
- case '0':
- return false
- case '1':
- return true
- case 't', 'T':
- if s.accept("rR") && (!s.accept("uU") || !s.accept("eE")) {
- s.error(boolError)
- }
- return true
- case 'f', 'F':
- if s.accept("aL") && (!s.accept("lL") || !s.accept("sS") || !s.accept("eE")) {
- s.error(boolError)
- }
- return false
- }
- return false
-}
-
-// Numerical elements
-const (
- binaryDigits = "01"
- octalDigits = "01234567"
- decimalDigits = "0123456789"
- hexadecimalDigits = "0123456789aAbBcCdDeEfF"
- sign = "+-"
- period = "."
- exponent = "eEp"
-)
-
-// getBase returns the numeric base represented by the verb and its digit string.
-func (s *ss) getBase(verb int) (base int, digits string) {
- s.okVerb(verb, "bdoUxXv", "integer") // sets s.err
- base = 10
- digits = decimalDigits
- switch verb {
- case 'b':
- base = 2
- digits = binaryDigits
- case 'o':
- base = 8
- digits = octalDigits
- case 'x', 'X', 'U':
- base = 16
- digits = hexadecimalDigits
- }
- return
-}
-
-// scanNumber returns the numerical string with specified digits starting here.
-func (s *ss) scanNumber(digits string, haveDigits bool) string {
- if !haveDigits && !s.accept(digits) {
- s.errorString("expected integer")
- }
- for s.accept(digits) {
- }
- return s.buf.String()
-}
-
-// scanRune returns the next rune value in the input.
-func (s *ss) scanRune(bitSize int) int64 {
- rune := int64(s.mustReadRune())
- n := uint(bitSize)
- x := (rune << (64 - n)) >> (64 - n)
- if x != rune {
- s.errorString("overflow on character value " + string(rune))
- }
- return rune
-}
-
-// scanBasePrefix reports whether the integer begins with a 0 or 0x,
-// and returns the base, digit string, and whether a zero was found.
-// It is called only if the verb is %v.
-func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
- if !s.peek("0") {
- return 10, decimalDigits, false
- }
- s.accept("0")
- found = true // We've put a digit into the token buffer.
- // Special cases for '0' && '0x'
- base, digits = 8, octalDigits
- if s.peek("xX") {
- s.consume("xX", false)
- base, digits = 16, hexadecimalDigits
- }
- return
-}
-
-// scanInt returns the value of the integer represented by the next
-// token, checking for overflow. Any error is stored in s.err.
-func (s *ss) scanInt(verb int, bitSize int) int64 {
- if verb == 'c' {
- return s.scanRune(bitSize)
- }
- s.skipSpace(false)
- base, digits := s.getBase(verb)
- haveDigits := false
- if verb == 'U' {
- if !s.consume("U", false) || !s.consume("+", false) {
- s.errorString("bad unicode format ")
- }
- } else {
- s.accept(sign) // If there's a sign, it will be left in the token buffer.
- if verb == 'v' {
- base, digits, haveDigits = s.scanBasePrefix()
- }
- }
- tok := s.scanNumber(digits, haveDigits)
- i, err := strconv.Btoi64(tok, base)
- if err != nil {
- s.error(err)
- }
- n := uint(bitSize)
- x := (i << (64 - n)) >> (64 - n)
- if x != i {
- s.errorString("integer overflow on token " + tok)
- }
- return i
-}
-
-// scanUint returns the value of the unsigned integer represented
-// by the next token, checking for overflow. Any error is stored in s.err.
-func (s *ss) scanUint(verb int, bitSize int) uint64 {
- if verb == 'c' {
- return uint64(s.scanRune(bitSize))
- }
- s.skipSpace(false)
- base, digits := s.getBase(verb)
- haveDigits := false
- if verb == 'U' {
- if !s.consume("U", false) || !s.consume("+", false) {
- s.errorString("bad unicode format ")
- }
- } else if verb == 'v' {
- base, digits, haveDigits = s.scanBasePrefix()
- }
- tok := s.scanNumber(digits, haveDigits)
- i, err := strconv.Btoui64(tok, base)
- if err != nil {
- s.error(err)
- }
- n := uint(bitSize)
- x := (i << (64 - n)) >> (64 - n)
- if x != i {
- s.errorString("unsigned integer overflow on token " + tok)
- }
- return i
-}
-
-// floatToken returns the floating-point number starting here, no longer than swid
-// if the width is specified. It's not rigorous about syntax because it doesn't check that
-// we have at least some digits, but Atof will do that.
-func (s *ss) floatToken() string {
- s.buf.Reset()
- // NaN?
- if s.accept("nN") && s.accept("aA") && s.accept("nN") {
- return s.buf.String()
- }
- // leading sign?
- s.accept(sign)
- // Inf?
- if s.accept("iI") && s.accept("nN") && s.accept("fF") {
- return s.buf.String()
- }
- // digits?
- for s.accept(decimalDigits) {
- }
- // decimal point?
- if s.accept(period) {
- // fraction?
- for s.accept(decimalDigits) {
- }
- }
- // exponent?
- if s.accept(exponent) {
- // leading sign?
- s.accept(sign)
- // digits?
- for s.accept(decimalDigits) {
- }
- }
- return s.buf.String()
-}
-
-// complexTokens returns the real and imaginary parts of the complex number starting here.
-// The number might be parenthesized and has the format (N+Ni) where N is a floating-point
-// number and there are no spaces within.
-func (s *ss) complexTokens() (real, imag string) {
- // TODO: accept N and Ni independently?
- parens := s.accept("(")
- real = s.floatToken()
- s.buf.Reset()
- // Must now have a sign.
- if !s.accept("+-") {
- s.error(complexError)
- }
- // Sign is now in buffer
- imagSign := s.buf.String()
- imag = s.floatToken()
- if !s.accept("i") {
- s.error(complexError)
- }
- if parens && !s.accept(")") {
- s.error(complexError)
- }
- return real, imagSign + imag
-}
-
-// convertFloat converts the string to a float64value.
-func (s *ss) convertFloat(str string, n int) float64 {
- if p := strings.Index(str, "p"); p >= 0 {
- // Atof doesn't handle power-of-2 exponents,
- // but they're easy to evaluate.
- f, err := strconv.AtofN(str[:p], n)
- if err != nil {
- // Put full string into error.
- if e, ok := err.(*strconv.NumError); ok {
- e.Num = str
- }
- s.error(err)
- }
- n, err := strconv.Atoi(str[p+1:])
- if err != nil {
- // Put full string into error.
- if e, ok := err.(*strconv.NumError); ok {
- e.Num = str
- }
- s.error(err)
- }
- return math.Ldexp(f, n)
- }
- f, err := strconv.AtofN(str, n)
- if err != nil {
- s.error(err)
- }
- return f
-}
-
-// convertComplex converts the next token to a complex128 value.
-// The atof argument is a type-specific reader for the underlying type.
-// If we're reading complex64, atof will parse float32s and convert them
-// to float64's to avoid reproducing this code for each complex type.
-func (s *ss) scanComplex(verb int, n int) complex128 {
- if !s.okVerb(verb, floatVerbs, "complex") {
- return 0
- }
- s.skipSpace(false)
- sreal, simag := s.complexTokens()
- real := s.convertFloat(sreal, n/2)
- imag := s.convertFloat(simag, n/2)
- return complex(real, imag)
-}
-
-// convertString returns the string represented by the next input characters.
-// The format of the input is determined by the verb.
-func (s *ss) convertString(verb int) (str string) {
- if !s.okVerb(verb, "svqx", "string") {
- return ""
- }
- s.skipSpace(false)
- switch verb {
- case 'q':
- str = s.quotedString()
- case 'x':
- str = s.hexString()
- default:
- str = string(s.token(true, notSpace)) // %s and %v just return the next word
- }
- // Empty strings other than with %q are not OK.
- if len(str) == 0 && verb != 'q' && s.maxWid > 0 {
- s.errorString("Scan: no data for string")
- }
- return
-}
-
-// quotedString returns the double- or back-quoted string represented by the next input characters.
-func (s *ss) quotedString() string {
- quote := s.mustReadRune()
- switch quote {
- case '`':
- // Back-quoted: Anything goes until EOF or back quote.
- for {
- rune := s.mustReadRune()
- if rune == quote {
- break
- }
- s.buf.WriteRune(rune)
- }
- return s.buf.String()
- case '"':
- // Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
- s.buf.WriteRune(quote)
- for {
- rune := s.mustReadRune()
- s.buf.WriteRune(rune)
- if rune == '\\' {
- // In a legal backslash escape, no matter how long, only the character
- // immediately after the escape can itself be a backslash or quote.
- // Thus we only need to protect the first character after the backslash.
- rune := s.mustReadRune()
- s.buf.WriteRune(rune)
- } else if rune == '"' {
- break
- }
- }
- result, err := strconv.Unquote(s.buf.String())
- if err != nil {
- s.error(err)
- }
- return result
- default:
- s.errorString("expected quoted string")
- }
- return ""
-}
-
-// hexDigit returns the value of the hexadecimal digit
-func (s *ss) hexDigit(digit int) int {
- switch digit {
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- return digit - '0'
- case 'a', 'b', 'c', 'd', 'e', 'f':
- return 10 + digit - 'a'
- case 'A', 'B', 'C', 'D', 'E', 'F':
- return 10 + digit - 'A'
- }
- s.errorString("Scan: illegal hex digit")
- return 0
-}
-
-// hexByte returns the next hex-encoded (two-character) byte from the input.
-// There must be either two hexadecimal digits or a space character in the input.
-func (s *ss) hexByte() (b byte, ok bool) {
- rune1 := s.getRune()
- if rune1 == eof {
- return
- }
- if unicode.IsSpace(rune1) {
- s.UnreadRune()
- return
- }
- rune2 := s.mustReadRune()
- return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
-}
-
-// hexString returns the space-delimited hexpair-encoded string.
-func (s *ss) hexString() string {
- for {
- b, ok := s.hexByte()
- if !ok {
- break
- }
- s.buf.WriteByte(b)
- }
- if s.buf.Len() == 0 {
- s.errorString("Scan: no hex data for %x string")
- return ""
- }
- return s.buf.String()
-}
-
-const floatVerbs = "beEfFgGv"
-
-const hugeWid = 1 << 30
-
-// scanOne scans a single value, deriving the scanner from the type of the argument.
-func (s *ss) scanOne(verb int, field interface{}) {
- s.buf.Reset()
- var err os.Error
- // If the parameter has its own Scan method, use that.
- if v, ok := field.(Scanner); ok {
- err = v.Scan(s, verb)
- if err != nil {
- if err == os.EOF {
- err = io.ErrUnexpectedEOF
- }
- s.error(err)
- }
- return
- }
- switch v := field.(type) {
- case *bool:
- *v = s.scanBool(verb)
- case *complex64:
- *v = complex64(s.scanComplex(verb, 64))
- case *complex128:
- *v = s.scanComplex(verb, 128)
- case *int:
- *v = int(s.scanInt(verb, intBits))
- case *int8:
- *v = int8(s.scanInt(verb, 8))
- case *int16:
- *v = int16(s.scanInt(verb, 16))
- case *int32:
- *v = int32(s.scanInt(verb, 32))
- case *int64:
- *v = s.scanInt(verb, 64)
- case *uint:
- *v = uint(s.scanUint(verb, intBits))
- case *uint8:
- *v = uint8(s.scanUint(verb, 8))
- case *uint16:
- *v = uint16(s.scanUint(verb, 16))
- case *uint32:
- *v = uint32(s.scanUint(verb, 32))
- case *uint64:
- *v = s.scanUint(verb, 64)
- case *uintptr:
- *v = uintptr(s.scanUint(verb, uintptrBits))
- // Floats are tricky because you want to scan in the precision of the result, not
- // scan in high precision and convert, in order to preserve the correct error condition.
- case *float32:
- if s.okVerb(verb, floatVerbs, "float32") {
- s.skipSpace(false)
- *v = float32(s.convertFloat(s.floatToken(), 32))
- }
- case *float64:
- if s.okVerb(verb, floatVerbs, "float64") {
- s.skipSpace(false)
- *v = s.convertFloat(s.floatToken(), 64)
- }
- case *string:
- *v = s.convertString(verb)
- case *[]byte:
- // We scan to string and convert so we get a copy of the data.
- // If we scanned to bytes, the slice would point at the buffer.
- *v = []byte(s.convertString(verb))
- default:
- val := reflect.ValueOf(v)
- ptr := val
- if ptr.Kind() != reflect.Ptr {
- s.errorString("Scan: type not a pointer: " + val.Type().String())
- return
- }
- switch v := ptr.Elem(); v.Kind() {
- case reflect.Bool:
- v.SetBool(s.scanBool(verb))
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- v.SetInt(s.scanInt(verb, v.Type().Bits()))
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- v.SetUint(s.scanUint(verb, v.Type().Bits()))
- case reflect.String:
- v.SetString(s.convertString(verb))
- case reflect.Slice:
- // For now, can only handle (renamed) []byte.
- typ := v.Type()
- if typ.Elem().Kind() != reflect.Uint8 {
- goto CantHandle
- }
- str := s.convertString(verb)
- v.Set(reflect.MakeSlice(typ, len(str), len(str)))
- for i := 0; i < len(str); i++ {
- v.Index(i).SetUint(uint64(str[i]))
- }
- case reflect.Float32, reflect.Float64:
- s.skipSpace(false)
- v.SetFloat(s.convertFloat(s.floatToken(), v.Type().Bits()))
- case reflect.Complex64, reflect.Complex128:
- v.SetComplex(s.scanComplex(verb, v.Type().Bits()))
- default:
- CantHandle:
- s.errorString("Scan: can't handle type: " + val.Type().String())
- }
- }
-}
-
-// errorHandler turns local panics into error returns. EOFs are benign.
-func errorHandler(errp *os.Error) {
- if e := recover(); e != nil {
- if se, ok := e.(scanError); ok { // catch local error
- if se.err != os.EOF {
- *errp = se.err
- }
- } else {
- panic(e)
- }
- }
-}
-
-// doScan does the real work for scanning without a format string.
-func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
- defer errorHandler(&err)
- for _, field := range a {
- s.scanOne('v', field)
- numProcessed++
- }
- // Check for newline if required.
- if !s.nlIsSpace {
- for {
- rune := s.getRune()
- if rune == '\n' || rune == eof {
- break
- }
- if !unicode.IsSpace(rune) {
- s.errorString("Scan: expected newline")
- break
- }
- }
- }
- return
-}
-
-// advance determines whether the next characters in the input match
-// those of the format. It returns the number of bytes (sic) consumed
-// in the format. Newlines included, all runs of space characters in
-// either input or format behave as a single space. This routine also
-// handles the %% case. If the return value is zero, either format
-// starts with a % (with no following %) or the input is empty.
-// If it is negative, the input did not match the string.
-func (s *ss) advance(format string) (i int) {
- for i < len(format) {
- fmtc, w := utf8.DecodeRuneInString(format[i:])
- if fmtc == '%' {
- // %% acts like a real percent
- nextc, _ := utf8.DecodeRuneInString(format[i+w:]) // will not match % if string is empty
- if nextc != '%' {
- return
- }
- i += w // skip the first %
- }
- sawSpace := false
- for unicode.IsSpace(fmtc) && i < len(format) {
- sawSpace = true
- i += w
- fmtc, w = utf8.DecodeRuneInString(format[i:])
- }
- if sawSpace {
- // There was space in the format, so there should be space (EOF)
- // in the input.
- inputc := s.getRune()
- if inputc == eof {
- return
- }
- if !unicode.IsSpace(inputc) {
- // Space in format but not in input: error
- s.errorString("expected space in input to match format")
- }
- s.skipSpace(true)
- continue
- }
- inputc := s.mustReadRune()
- if fmtc != inputc {
- s.UnreadRune()
- return -1
- }
- i += w
- }
- return
-}
-
-// doScanf does the real work when scanning with a format string.
-// At the moment, it handles only pointers to basic types.
-func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) {
- defer errorHandler(&err)
- end := len(format) - 1
- // We process one item per non-trivial format
- for i := 0; i <= end; {
- w := s.advance(format[i:])
- if w > 0 {
- i += w
- continue
- }
- // Either we failed to advance, we have a percent character, or we ran out of input.
- if format[i] != '%' {
- // Can't advance format. Why not?
- if w < 0 {
- s.errorString("input does not match format")
- }
- // Otherwise at EOF; "too many operands" error handled below
- break
- }
- i++ // % is one byte
-
- // do we have 20 (width)?
- var widPresent bool
- s.maxWid, widPresent, i = parsenum(format, i, end)
- if !widPresent {
- s.maxWid = hugeWid
- }
- s.fieldLimit = s.limit
- if f := s.count + s.maxWid; f < s.fieldLimit {
- s.fieldLimit = f
- }
-
- c, w := utf8.DecodeRuneInString(format[i:])
- i += w
-
- if numProcessed >= len(a) { // out of operands
- s.errorString("too few operands for format %" + format[i-w:])
- break
- }
- field := a[numProcessed]
-
- s.scanOne(c, field)
- numProcessed++
- s.fieldLimit = s.limit
- }
- if numProcessed < len(a) {
- s.errorString("too many operands")
- }
- return
-}
diff --git a/src/cmd/gofix/testdata/reflect.script.go.in b/src/cmd/gofix/testdata/reflect.script.go.in
deleted file mode 100644
index b341b1f89..000000000
--- a/src/cmd/gofix/testdata/reflect.script.go.in
+++ /dev/null
@@ -1,359 +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.
-
-// This package aids in the testing of code that uses channels.
-package script
-
-import (
- "fmt"
- "os"
- "rand"
- "reflect"
- "strings"
-)
-
-// An Event is an element in a partially ordered set that either sends a value
-// to a channel or expects a value from a channel.
-type Event struct {
- name string
- occurred bool
- predecessors []*Event
- action action
-}
-
-type action interface {
- // getSend returns nil if the action is not a send action.
- getSend() sendAction
- // getRecv returns nil if the action is not a receive action.
- getRecv() recvAction
- // getChannel returns the channel that the action operates on.
- getChannel() interface{}
-}
-
-type recvAction interface {
- recvMatch(interface{}) bool
-}
-
-type sendAction interface {
- send()
-}
-
-// isReady returns true if all the predecessors of an Event have occurred.
-func (e Event) isReady() bool {
- for _, predecessor := range e.predecessors {
- if !predecessor.occurred {
- return false
- }
- }
-
- return true
-}
-
-// A Recv action reads a value from a channel and uses reflect.DeepMatch to
-// compare it with an expected value.
-type Recv struct {
- Channel interface{}
- Expected interface{}
-}
-
-func (r Recv) getRecv() recvAction { return r }
-
-func (Recv) getSend() sendAction { return nil }
-
-func (r Recv) getChannel() interface{} { return r.Channel }
-
-func (r Recv) recvMatch(chanEvent interface{}) bool {
- c, ok := chanEvent.(channelRecv)
- if !ok || c.channel != r.Channel {
- return false
- }
-
- return reflect.DeepEqual(c.value, r.Expected)
-}
-
-// A RecvMatch action reads a value from a channel and calls a function to
-// determine if the value matches.
-type RecvMatch struct {
- Channel interface{}
- Match func(interface{}) bool
-}
-
-func (r RecvMatch) getRecv() recvAction { return r }
-
-func (RecvMatch) getSend() sendAction { return nil }
-
-func (r RecvMatch) getChannel() interface{} { return r.Channel }
-
-func (r RecvMatch) recvMatch(chanEvent interface{}) bool {
- c, ok := chanEvent.(channelRecv)
- if !ok || c.channel != r.Channel {
- return false
- }
-
- return r.Match(c.value)
-}
-
-// A Closed action matches if the given channel is closed. The closing is
-// treated as an event, not a state, thus Closed will only match once for a
-// given channel.
-type Closed struct {
- Channel interface{}
-}
-
-func (r Closed) getRecv() recvAction { return r }
-
-func (Closed) getSend() sendAction { return nil }
-
-func (r Closed) getChannel() interface{} { return r.Channel }
-
-func (r Closed) recvMatch(chanEvent interface{}) bool {
- c, ok := chanEvent.(channelClosed)
- if !ok || c.channel != r.Channel {
- return false
- }
-
- return true
-}
-
-// A Send action sends a value to a channel. The value must match the
-// type of the channel exactly unless the channel if of type chan interface{}.
-type Send struct {
- Channel interface{}
- Value interface{}
-}
-
-func (Send) getRecv() recvAction { return nil }
-
-func (s Send) getSend() sendAction { return s }
-
-func (s Send) getChannel() interface{} { return s.Channel }
-
-type empty struct {
- x interface{}
-}
-
-func newEmptyInterface(e empty) reflect.Value {
- return reflect.NewValue(e).(*reflect.StructValue).Field(0)
-}
-
-func (s Send) send() {
- // With reflect.ChanValue.Send, we must match the types exactly. So, if
- // s.Channel is a chan interface{} we convert s.Value to an interface{}
- // first.
- c := reflect.NewValue(s.Channel).(*reflect.ChanValue)
- var v reflect.Value
- if iface, ok := c.Type().(*reflect.ChanType).Elem().(*reflect.InterfaceType); ok && iface.NumMethod() == 0 {
- v = newEmptyInterface(empty{s.Value})
- } else {
- v = reflect.NewValue(s.Value)
- }
- c.Send(v)
-}
-
-// A Close action closes the given channel.
-type Close struct {
- Channel interface{}
-}
-
-func (Close) getRecv() recvAction { return nil }
-
-func (s Close) getSend() sendAction { return s }
-
-func (s Close) getChannel() interface{} { return s.Channel }
-
-func (s Close) send() { reflect.NewValue(s.Channel).(*reflect.ChanValue).Close() }
-
-// A ReceivedUnexpected error results if no active Events match a value
-// received from a channel.
-type ReceivedUnexpected struct {
- Value interface{}
- ready []*Event
-}
-
-func (r ReceivedUnexpected) String() string {
- names := make([]string, len(r.ready))
- for i, v := range r.ready {
- names[i] = v.name
- }
- return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "))
-}
-
-// A SetupError results if there is a error with the configuration of a set of
-// Events.
-type SetupError string
-
-func (s SetupError) String() string { return string(s) }
-
-func NewEvent(name string, predecessors []*Event, action action) *Event {
- e := &Event{name, false, predecessors, action}
- return e
-}
-
-// Given a set of Events, Perform repeatedly iterates over the set and finds the
-// subset of ready Events (that is, all of their predecessors have
-// occurred). From that subset, it pseudo-randomly selects an Event to perform.
-// If the Event is a send event, the send occurs and Perform recalculates the ready
-// set. If the event is a receive event, Perform waits for a value from any of the
-// channels that are contained in any of the events. That value is then matched
-// against the ready events. The first event that matches is considered to
-// have occurred and Perform recalculates the ready set.
-//
-// Perform continues this until all Events have occurred.
-//
-// Note that uncollected goroutines may still be reading from any of the
-// channels read from after Perform returns.
-//
-// For example, consider the problem of testing a function that reads values on
-// one channel and echos them to two output channels. To test this we would
-// create three events: a send event and two receive events. Each of the
-// receive events must list the send event as a predecessor but there is no
-// ordering between the receive events.
-//
-// send := NewEvent("send", nil, Send{c, 1})
-// recv1 := NewEvent("recv 1", []*Event{send}, Recv{c, 1})
-// recv2 := NewEvent("recv 2", []*Event{send}, Recv{c, 1})
-// Perform(0, []*Event{send, recv1, recv2})
-//
-// At first, only the send event would be in the ready set and thus Perform will
-// send a value to the input channel. Now the two receive events are ready and
-// Perform will match each of them against the values read from the output channels.
-//
-// It would be invalid to list one of the receive events as a predecessor of
-// the other. At each receive step, all the receive channels are considered,
-// thus Perform may see a value from a channel that is not in the current ready
-// set and fail.
-func Perform(seed int64, events []*Event) (err os.Error) {
- r := rand.New(rand.NewSource(seed))
-
- channels, err := getChannels(events)
- if err != nil {
- return
- }
- multiplex := make(chan interface{})
- for _, channel := range channels {
- go recvValues(multiplex, channel)
- }
-
-Outer:
- for {
- ready, err := readyEvents(events)
- if err != nil {
- return err
- }
-
- if len(ready) == 0 {
- // All events occurred.
- break
- }
-
- event := ready[r.Intn(len(ready))]
- if send := event.action.getSend(); send != nil {
- send.send()
- event.occurred = true
- continue
- }
-
- v := <-multiplex
- for _, event := range ready {
- if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {
- event.occurred = true
- continue Outer
- }
- }
-
- return ReceivedUnexpected{v, ready}
- }
-
- return nil
-}
-
-// getChannels returns all the channels listed in any receive events.
-func getChannels(events []*Event) ([]interface{}, os.Error) {
- channels := make([]interface{}, len(events))
-
- j := 0
- for _, event := range events {
- if recv := event.action.getRecv(); recv == nil {
- continue
- }
- c := event.action.getChannel()
- if _, ok := reflect.NewValue(c).(*reflect.ChanValue); !ok {
- return nil, SetupError("one of the channel values is not a channel")
- }
-
- duplicate := false
- for _, other := range channels[0:j] {
- if c == other {
- duplicate = true
- break
- }
- }
-
- if !duplicate {
- channels[j] = c
- j++
- }
- }
-
- return channels[0:j], nil
-}
-
-// recvValues is a multiplexing helper function. It reads values from the given
-// channel repeatedly, wrapping them up as either a channelRecv or
-// channelClosed structure, and forwards them to the multiplex channel.
-func recvValues(multiplex chan<- interface{}, channel interface{}) {
- c := reflect.NewValue(channel).(*reflect.ChanValue)
-
- for {
- v, ok := c.Recv()
- if !ok {
- multiplex <- channelClosed{channel}
- return
- }
-
- multiplex <- channelRecv{channel, v.Interface()}
- }
-}
-
-type channelClosed struct {
- channel interface{}
-}
-
-type channelRecv struct {
- channel interface{}
- value interface{}
-}
-
-// readyEvents returns the subset of events that are ready.
-func readyEvents(events []*Event) ([]*Event, os.Error) {
- ready := make([]*Event, len(events))
-
- j := 0
- eventsWaiting := false
- for _, event := range events {
- if event.occurred {
- continue
- }
-
- eventsWaiting = true
- if event.isReady() {
- ready[j] = event
- j++
- }
- }
-
- if j == 0 && eventsWaiting {
- names := make([]string, len(events))
- for _, event := range events {
- if event.occurred {
- continue
- }
- names[j] = event.name
- }
-
- return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "))
- }
-
- return ready[0:j], nil
-}
diff --git a/src/cmd/gofix/testdata/reflect.script.go.out b/src/cmd/gofix/testdata/reflect.script.go.out
deleted file mode 100644
index bc5a6a41d..000000000
--- a/src/cmd/gofix/testdata/reflect.script.go.out
+++ /dev/null
@@ -1,359 +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.
-
-// This package aids in the testing of code that uses channels.
-package script
-
-import (
- "fmt"
- "os"
- "rand"
- "reflect"
- "strings"
-)
-
-// An Event is an element in a partially ordered set that either sends a value
-// to a channel or expects a value from a channel.
-type Event struct {
- name string
- occurred bool
- predecessors []*Event
- action action
-}
-
-type action interface {
- // getSend returns nil if the action is not a send action.
- getSend() sendAction
- // getRecv returns nil if the action is not a receive action.
- getRecv() recvAction
- // getChannel returns the channel that the action operates on.
- getChannel() interface{}
-}
-
-type recvAction interface {
- recvMatch(interface{}) bool
-}
-
-type sendAction interface {
- send()
-}
-
-// isReady returns true if all the predecessors of an Event have occurred.
-func (e Event) isReady() bool {
- for _, predecessor := range e.predecessors {
- if !predecessor.occurred {
- return false
- }
- }
-
- return true
-}
-
-// A Recv action reads a value from a channel and uses reflect.DeepMatch to
-// compare it with an expected value.
-type Recv struct {
- Channel interface{}
- Expected interface{}
-}
-
-func (r Recv) getRecv() recvAction { return r }
-
-func (Recv) getSend() sendAction { return nil }
-
-func (r Recv) getChannel() interface{} { return r.Channel }
-
-func (r Recv) recvMatch(chanEvent interface{}) bool {
- c, ok := chanEvent.(channelRecv)
- if !ok || c.channel != r.Channel {
- return false
- }
-
- return reflect.DeepEqual(c.value, r.Expected)
-}
-
-// A RecvMatch action reads a value from a channel and calls a function to
-// determine if the value matches.
-type RecvMatch struct {
- Channel interface{}
- Match func(interface{}) bool
-}
-
-func (r RecvMatch) getRecv() recvAction { return r }
-
-func (RecvMatch) getSend() sendAction { return nil }
-
-func (r RecvMatch) getChannel() interface{} { return r.Channel }
-
-func (r RecvMatch) recvMatch(chanEvent interface{}) bool {
- c, ok := chanEvent.(channelRecv)
- if !ok || c.channel != r.Channel {
- return false
- }
-
- return r.Match(c.value)
-}
-
-// A Closed action matches if the given channel is closed. The closing is
-// treated as an event, not a state, thus Closed will only match once for a
-// given channel.
-type Closed struct {
- Channel interface{}
-}
-
-func (r Closed) getRecv() recvAction { return r }
-
-func (Closed) getSend() sendAction { return nil }
-
-func (r Closed) getChannel() interface{} { return r.Channel }
-
-func (r Closed) recvMatch(chanEvent interface{}) bool {
- c, ok := chanEvent.(channelClosed)
- if !ok || c.channel != r.Channel {
- return false
- }
-
- return true
-}
-
-// A Send action sends a value to a channel. The value must match the
-// type of the channel exactly unless the channel if of type chan interface{}.
-type Send struct {
- Channel interface{}
- Value interface{}
-}
-
-func (Send) getRecv() recvAction { return nil }
-
-func (s Send) getSend() sendAction { return s }
-
-func (s Send) getChannel() interface{} { return s.Channel }
-
-type empty struct {
- x interface{}
-}
-
-func newEmptyInterface(e empty) reflect.Value {
- return reflect.ValueOf(e).Field(0)
-}
-
-func (s Send) send() {
- // With reflect.ChanValue.Send, we must match the types exactly. So, if
- // s.Channel is a chan interface{} we convert s.Value to an interface{}
- // first.
- c := reflect.ValueOf(s.Channel)
- var v reflect.Value
- if iface := c.Type().Elem(); iface.Kind() == reflect.Interface && iface.NumMethod() == 0 {
- v = newEmptyInterface(empty{s.Value})
- } else {
- v = reflect.ValueOf(s.Value)
- }
- c.Send(v)
-}
-
-// A Close action closes the given channel.
-type Close struct {
- Channel interface{}
-}
-
-func (Close) getRecv() recvAction { return nil }
-
-func (s Close) getSend() sendAction { return s }
-
-func (s Close) getChannel() interface{} { return s.Channel }
-
-func (s Close) send() { reflect.ValueOf(s.Channel).Close() }
-
-// A ReceivedUnexpected error results if no active Events match a value
-// received from a channel.
-type ReceivedUnexpected struct {
- Value interface{}
- ready []*Event
-}
-
-func (r ReceivedUnexpected) String() string {
- names := make([]string, len(r.ready))
- for i, v := range r.ready {
- names[i] = v.name
- }
- return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "))
-}
-
-// A SetupError results if there is a error with the configuration of a set of
-// Events.
-type SetupError string
-
-func (s SetupError) String() string { return string(s) }
-
-func NewEvent(name string, predecessors []*Event, action action) *Event {
- e := &Event{name, false, predecessors, action}
- return e
-}
-
-// Given a set of Events, Perform repeatedly iterates over the set and finds the
-// subset of ready Events (that is, all of their predecessors have
-// occurred). From that subset, it pseudo-randomly selects an Event to perform.
-// If the Event is a send event, the send occurs and Perform recalculates the ready
-// set. If the event is a receive event, Perform waits for a value from any of the
-// channels that are contained in any of the events. That value is then matched
-// against the ready events. The first event that matches is considered to
-// have occurred and Perform recalculates the ready set.
-//
-// Perform continues this until all Events have occurred.
-//
-// Note that uncollected goroutines may still be reading from any of the
-// channels read from after Perform returns.
-//
-// For example, consider the problem of testing a function that reads values on
-// one channel and echos them to two output channels. To test this we would
-// create three events: a send event and two receive events. Each of the
-// receive events must list the send event as a predecessor but there is no
-// ordering between the receive events.
-//
-// send := NewEvent("send", nil, Send{c, 1})
-// recv1 := NewEvent("recv 1", []*Event{send}, Recv{c, 1})
-// recv2 := NewEvent("recv 2", []*Event{send}, Recv{c, 1})
-// Perform(0, []*Event{send, recv1, recv2})
-//
-// At first, only the send event would be in the ready set and thus Perform will
-// send a value to the input channel. Now the two receive events are ready and
-// Perform will match each of them against the values read from the output channels.
-//
-// It would be invalid to list one of the receive events as a predecessor of
-// the other. At each receive step, all the receive channels are considered,
-// thus Perform may see a value from a channel that is not in the current ready
-// set and fail.
-func Perform(seed int64, events []*Event) (err os.Error) {
- r := rand.New(rand.NewSource(seed))
-
- channels, err := getChannels(events)
- if err != nil {
- return
- }
- multiplex := make(chan interface{})
- for _, channel := range channels {
- go recvValues(multiplex, channel)
- }
-
-Outer:
- for {
- ready, err := readyEvents(events)
- if err != nil {
- return err
- }
-
- if len(ready) == 0 {
- // All events occurred.
- break
- }
-
- event := ready[r.Intn(len(ready))]
- if send := event.action.getSend(); send != nil {
- send.send()
- event.occurred = true
- continue
- }
-
- v := <-multiplex
- for _, event := range ready {
- if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {
- event.occurred = true
- continue Outer
- }
- }
-
- return ReceivedUnexpected{v, ready}
- }
-
- return nil
-}
-
-// getChannels returns all the channels listed in any receive events.
-func getChannels(events []*Event) ([]interface{}, os.Error) {
- channels := make([]interface{}, len(events))
-
- j := 0
- for _, event := range events {
- if recv := event.action.getRecv(); recv == nil {
- continue
- }
- c := event.action.getChannel()
- if reflect.ValueOf(c).Kind() != reflect.Chan {
- return nil, SetupError("one of the channel values is not a channel")
- }
-
- duplicate := false
- for _, other := range channels[0:j] {
- if c == other {
- duplicate = true
- break
- }
- }
-
- if !duplicate {
- channels[j] = c
- j++
- }
- }
-
- return channels[0:j], nil
-}
-
-// recvValues is a multiplexing helper function. It reads values from the given
-// channel repeatedly, wrapping them up as either a channelRecv or
-// channelClosed structure, and forwards them to the multiplex channel.
-func recvValues(multiplex chan<- interface{}, channel interface{}) {
- c := reflect.ValueOf(channel)
-
- for {
- v, ok := c.Recv()
- if !ok {
- multiplex <- channelClosed{channel}
- return
- }
-
- multiplex <- channelRecv{channel, v.Interface()}
- }
-}
-
-type channelClosed struct {
- channel interface{}
-}
-
-type channelRecv struct {
- channel interface{}
- value interface{}
-}
-
-// readyEvents returns the subset of events that are ready.
-func readyEvents(events []*Event) ([]*Event, os.Error) {
- ready := make([]*Event, len(events))
-
- j := 0
- eventsWaiting := false
- for _, event := range events {
- if event.occurred {
- continue
- }
-
- eventsWaiting = true
- if event.isReady() {
- ready[j] = event
- j++
- }
- }
-
- if j == 0 && eventsWaiting {
- names := make([]string, len(events))
- for _, event := range events {
- if event.occurred {
- continue
- }
- names[j] = event.name
- }
-
- return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "))
- }
-
- return ready[0:j], nil
-}
diff --git a/src/cmd/gofix/testdata/reflect.template.go.in b/src/cmd/gofix/testdata/reflect.template.go.in
deleted file mode 100644
index 1f5a8128f..000000000
--- a/src/cmd/gofix/testdata/reflect.template.go.in
+++ /dev/null
@@ -1,1043 +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.
-
-/*
- Data-driven templates for generating textual output such as
- HTML.
-
- Templates are executed by applying them to a data structure.
- Annotations in the template refer to elements of the data
- structure (typically a field of a struct or a key in a map)
- to control execution and derive values to be displayed.
- The template walks the structure as it executes and the
- "cursor" @ represents the value at the current location
- in the structure.
-
- Data items may be values or pointers; the interface hides the
- indirection.
-
- In the following, 'field' is one of several things, according to the data.
-
- - The name of a field of a struct (result = data.field),
- - The value stored in a map under that key (result = data[field]), or
- - The result of invoking a niladic single-valued method with that name
- (result = data.field())
-
- Major constructs ({} are the default delimiters for template actions;
- [] are the notation in this comment for optional elements):
-
- {# comment }
-
- A one-line comment.
-
- {.section field} XXX [ {.or} YYY ] {.end}
-
- Set @ to the value of the field. It may be an explicit @
- to stay at the same point in the data. If the field is nil
- or empty, execute YYY; otherwise execute XXX.
-
- {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end}
-
- Like .section, but field must be an array or slice. XXX
- is executed for each element. If the array is nil or empty,
- YYY is executed instead. If the {.alternates with} marker
- is present, ZZZ is executed between iterations of XXX.
-
- {field}
- {field1 field2 ...}
- {field|formatter}
- {field1 field2...|formatter}
- {field|formatter1|formatter2}
-
- Insert the value of the fields into the output. Each field is
- first looked for in the cursor, as in .section and .repeated.
- If it is not found, the search continues in outer sections
- until the top level is reached.
-
- If the field value is a pointer, leading asterisks indicate
- that the value to be inserted should be evaluated through the
- pointer. For example, if x.p is of type *int, {x.p} will
- insert the value of the pointer but {*x.p} will insert the
- value of the underlying integer. If the value is nil or not a
- pointer, asterisks have no effect.
-
- If a formatter is specified, it must be named in the formatter
- map passed to the template set up routines or in the default
- set ("html","str","") and is used to process the data for
- output. The formatter function has signature
- func(wr io.Writer, formatter string, data ...interface{})
- where wr is the destination for output, data holds the field
- values at the instantiation, and formatter is its name at
- the invocation site. The default formatter just concatenates
- the string representations of the fields.
-
- Multiple formatters separated by the pipeline character | are
- executed sequentially, with each formatter receiving the bytes
- emitted by the one to its left.
-
- The delimiter strings get their default value, "{" and "}", from
- JSON-template. They may be set to any non-empty, space-free
- string using the SetDelims method. Their value can be printed
- in the output using {.meta-left} and {.meta-right}.
-*/
-package template
-
-import (
- "bytes"
- "container/vector"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "reflect"
- "strings"
- "unicode"
- "utf8"
-)
-
-// Errors returned during parsing and execution. Users may extract the information and reformat
-// if they desire.
-type Error struct {
- Line int
- Msg string
-}
-
-func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
-
-// Most of the literals are aces.
-var lbrace = []byte{'{'}
-var rbrace = []byte{'}'}
-var space = []byte{' '}
-var tab = []byte{'\t'}
-
-// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
-const (
- tokAlternates = iota
- tokComment
- tokEnd
- tokLiteral
- tokOr
- tokRepeated
- tokSection
- tokText
- tokVariable
-)
-
-// FormatterMap is the type describing the mapping from formatter
-// names to the functions that implement them.
-type FormatterMap map[string]func(io.Writer, string, ...interface{})
-
-// Built-in formatters.
-var builtins = FormatterMap{
- "html": HTMLFormatter,
- "str": StringFormatter,
- "": StringFormatter,
-}
-
-// The parsed state of a template is a vector of xxxElement structs.
-// Sections have line numbers so errors can be reported better during execution.
-
-// Plain text.
-type textElement struct {
- text []byte
-}
-
-// A literal such as .meta-left or .meta-right
-type literalElement struct {
- text []byte
-}
-
-// A variable invocation to be evaluated
-type variableElement struct {
- linenum int
- word []string // The fields in the invocation.
- fmts []string // Names of formatters to apply. len(fmts) > 0
-}
-
-// A .section block, possibly with a .or
-type sectionElement struct {
- linenum int // of .section itself
- field string // cursor field for this block
- start int // first element
- or int // first element of .or block
- end int // one beyond last element
-}
-
-// A .repeated block, possibly with a .or and a .alternates
-type repeatedElement struct {
- sectionElement // It has the same structure...
- altstart int // ... except for alternates
- altend int
-}
-
-// Template is the type that represents a template definition.
-// It is unchanged after parsing.
-type Template struct {
- fmap FormatterMap // formatters for variables
- // Used during parsing:
- ldelim, rdelim []byte // delimiters; default {}
- buf []byte // input text to process
- p int // position in buf
- linenum int // position in input
- // Parsed results:
- elems *vector.Vector
-}
-
-// Internal state for executing a Template. As we evaluate the struct,
-// the data item descends into the fields associated with sections, etc.
-// Parent is used to walk upwards to find variables higher in the tree.
-type state struct {
- parent *state // parent in hierarchy
- data reflect.Value // the driver data for this section etc.
- wr io.Writer // where to send output
- buf [2]bytes.Buffer // alternating buffers used when chaining formatters
-}
-
-func (parent *state) clone(data reflect.Value) *state {
- return &state{parent: parent, data: data, wr: parent.wr}
-}
-
-// New creates a new template with the specified formatter map (which
-// may be nil) to define auxiliary functions for formatting variables.
-func New(fmap FormatterMap) *Template {
- t := new(Template)
- t.fmap = fmap
- t.ldelim = lbrace
- t.rdelim = rbrace
- t.elems = new(vector.Vector)
- return t
-}
-
-// Report error and stop executing. The line number must be provided explicitly.
-func (t *Template) execError(st *state, line int, err string, args ...interface{}) {
- panic(&Error{line, fmt.Sprintf(err, args...)})
-}
-
-// Report error, panic to terminate parsing.
-// The line number comes from the template state.
-func (t *Template) parseError(err string, args ...interface{}) {
- panic(&Error{t.linenum, fmt.Sprintf(err, args...)})
-}
-
-// Is this an exported - upper case - name?
-func isExported(name string) bool {
- rune, _ := utf8.DecodeRuneInString(name)
- return unicode.IsUpper(rune)
-}
-
-// -- Lexical analysis
-
-// Is c a white space character?
-func white(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' }
-
-// Safely, does s[n:n+len(t)] == t?
-func equal(s []byte, n int, t []byte) bool {
- b := s[n:]
- if len(t) > len(b) { // not enough space left for a match.
- return false
- }
- for i, c := range t {
- if c != b[i] {
- return false
- }
- }
- return true
-}
-
-// nextItem returns the next item from the input buffer. If the returned
-// item is empty, we are at EOF. The item will be either a
-// delimited string or a non-empty string between delimited
-// strings. Tokens stop at (but include, if plain text) a newline.
-// Action tokens on a line by themselves drop any space on
-// either side, up to and including the newline.
-func (t *Template) nextItem() []byte {
- startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
- start := t.p
- var i int
- newline := func() {
- t.linenum++
- i++
- }
- // Leading white space up to but not including newline
- for i = start; i < len(t.buf); i++ {
- if t.buf[i] == '\n' || !white(t.buf[i]) {
- break
- }
- }
- leadingSpace := i > start
- // What's left is nothing, newline, delimited string, or plain text
- switch {
- case i == len(t.buf):
- // EOF; nothing to do
- case t.buf[i] == '\n':
- newline()
- case equal(t.buf, i, t.ldelim):
- left := i // Start of left delimiter.
- right := -1 // Will be (immediately after) right delimiter.
- haveText := false // Delimiters contain text.
- i += len(t.ldelim)
- // Find the end of the action.
- for ; i < len(t.buf); i++ {
- if t.buf[i] == '\n' {
- break
- }
- if equal(t.buf, i, t.rdelim) {
- i += len(t.rdelim)
- right = i
- break
- }
- haveText = true
- }
- if right < 0 {
- t.parseError("unmatched opening delimiter")
- return nil
- }
- // Is this a special action (starts with '.' or '#') and the only thing on the line?
- if startOfLine && haveText {
- firstChar := t.buf[left+len(t.ldelim)]
- if firstChar == '.' || firstChar == '#' {
- // It's special and the first thing on the line. Is it the last?
- for j := right; j < len(t.buf) && white(t.buf[j]); j++ {
- if t.buf[j] == '\n' {
- // Yes it is. Drop the surrounding space and return the {.foo}
- t.linenum++
- t.p = j + 1
- return t.buf[left:right]
- }
- }
- }
- }
- // No it's not. If there's leading space, return that.
- if leadingSpace {
- // not trimming space: return leading white space if there is some.
- t.p = left
- return t.buf[start:left]
- }
- // Return the word, leave the trailing space.
- start = left
- break
- default:
- for ; i < len(t.buf); i++ {
- if t.buf[i] == '\n' {
- newline()
- break
- }
- if equal(t.buf, i, t.ldelim) {
- break
- }
- }
- }
- item := t.buf[start:i]
- t.p = i
- return item
-}
-
-// Turn a byte array into a white-space-split array of strings.
-func words(buf []byte) []string {
- s := make([]string, 0, 5)
- p := 0 // position in buf
- // one word per loop
- for i := 0; ; i++ {
- // skip white space
- for ; p < len(buf) && white(buf[p]); p++ {
- }
- // grab word
- start := p
- for ; p < len(buf) && !white(buf[p]); p++ {
- }
- if start == p { // no text left
- break
- }
- s = append(s, string(buf[start:p]))
- }
- return s
-}
-
-// Analyze an item and return its token type and, if it's an action item, an array of
-// its constituent words.
-func (t *Template) analyze(item []byte) (tok int, w []string) {
- // item is known to be non-empty
- if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
- tok = tokText
- return
- }
- if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
- t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
- return
- }
- if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
- t.parseError("empty directive")
- return
- }
- // Comment
- if item[len(t.ldelim)] == '#' {
- tok = tokComment
- return
- }
- // Split into words
- w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
- if len(w) == 0 {
- t.parseError("empty directive")
- return
- }
- if len(w) > 0 && w[0][0] != '.' {
- tok = tokVariable
- return
- }
- switch w[0] {
- case ".meta-left", ".meta-right", ".space", ".tab":
- tok = tokLiteral
- return
- case ".or":
- tok = tokOr
- return
- case ".end":
- tok = tokEnd
- return
- case ".section":
- if len(w) != 2 {
- t.parseError("incorrect fields for .section: %s", item)
- return
- }
- tok = tokSection
- return
- case ".repeated":
- if len(w) != 3 || w[1] != "section" {
- t.parseError("incorrect fields for .repeated: %s", item)
- return
- }
- tok = tokRepeated
- return
- case ".alternates":
- if len(w) != 2 || w[1] != "with" {
- t.parseError("incorrect fields for .alternates: %s", item)
- return
- }
- tok = tokAlternates
- return
- }
- t.parseError("bad directive: %s", item)
- return
-}
-
-// formatter returns the Formatter with the given name in the Template, or nil if none exists.
-func (t *Template) formatter(name string) func(io.Writer, string, ...interface{}) {
- if t.fmap != nil {
- if fn := t.fmap[name]; fn != nil {
- return fn
- }
- }
- return builtins[name]
-}
-
-// -- Parsing
-
-// Allocate a new variable-evaluation element.
-func (t *Template) newVariable(words []string) *variableElement {
- // After the final space-separated argument, formatters may be specified separated
- // by pipe symbols, for example: {a b c|d|e}
-
- // Until we learn otherwise, formatters contains a single name: "", the default formatter.
- formatters := []string{""}
- lastWord := words[len(words)-1]
- bar := strings.IndexRune(lastWord, '|')
- if bar >= 0 {
- words[len(words)-1] = lastWord[0:bar]
- formatters = strings.Split(lastWord[bar+1:], "|")
- }
-
- // We could remember the function address here and avoid the lookup later,
- // but it's more dynamic to let the user change the map contents underfoot.
- // We do require the name to be present, though.
-
- // Is it in user-supplied map?
- for _, f := range formatters {
- if t.formatter(f) == nil {
- t.parseError("unknown formatter: %q", f)
- }
- }
- return &variableElement{t.linenum, words, formatters}
-}
-
-// Grab the next item. If it's simple, just append it to the template.
-// Otherwise return its details.
-func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
- tok, w = t.analyze(item)
- done = true // assume for simplicity
- switch tok {
- case tokComment:
- return
- case tokText:
- t.elems.Push(&textElement{item})
- return
- case tokLiteral:
- switch w[0] {
- case ".meta-left":
- t.elems.Push(&literalElement{t.ldelim})
- case ".meta-right":
- t.elems.Push(&literalElement{t.rdelim})
- case ".space":
- t.elems.Push(&literalElement{space})
- case ".tab":
- t.elems.Push(&literalElement{tab})
- default:
- t.parseError("internal error: unknown literal: %s", w[0])
- }
- return
- case tokVariable:
- t.elems.Push(t.newVariable(w))
- return
- }
- return false, tok, w
-}
-
-// parseRepeated and parseSection are mutually recursive
-
-func (t *Template) parseRepeated(words []string) *repeatedElement {
- r := new(repeatedElement)
- t.elems.Push(r)
- r.linenum = t.linenum
- r.field = words[2]
- // Scan section, collecting true and false (.or) blocks.
- r.start = t.elems.Len()
- r.or = -1
- r.altstart = -1
- r.altend = -1
-Loop:
- for {
- item := t.nextItem()
- if len(item) == 0 {
- t.parseError("missing .end for .repeated section")
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokEnd:
- break Loop
- case tokOr:
- if r.or >= 0 {
- t.parseError("extra .or in .repeated section")
- break Loop
- }
- r.altend = t.elems.Len()
- r.or = t.elems.Len()
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- case tokAlternates:
- if r.altstart >= 0 {
- t.parseError("extra .alternates in .repeated section")
- break Loop
- }
- if r.or >= 0 {
- t.parseError(".alternates inside .or block in .repeated section")
- break Loop
- }
- r.altstart = t.elems.Len()
- default:
- t.parseError("internal error: unknown repeated section item: %s", item)
- break Loop
- }
- }
- if r.altend < 0 {
- r.altend = t.elems.Len()
- }
- r.end = t.elems.Len()
- return r
-}
-
-func (t *Template) parseSection(words []string) *sectionElement {
- s := new(sectionElement)
- t.elems.Push(s)
- s.linenum = t.linenum
- s.field = words[1]
- // Scan section, collecting true and false (.or) blocks.
- s.start = t.elems.Len()
- s.or = -1
-Loop:
- for {
- item := t.nextItem()
- if len(item) == 0 {
- t.parseError("missing .end for .section")
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokEnd:
- break Loop
- case tokOr:
- if s.or >= 0 {
- t.parseError("extra .or in .section")
- break Loop
- }
- s.or = t.elems.Len()
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- case tokAlternates:
- t.parseError(".alternates not in .repeated")
- default:
- t.parseError("internal error: unknown section item: %s", item)
- }
- }
- s.end = t.elems.Len()
- return s
-}
-
-func (t *Template) parse() {
- for {
- item := t.nextItem()
- if len(item) == 0 {
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokOr, tokEnd, tokAlternates:
- t.parseError("unexpected %s", w[0])
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- default:
- t.parseError("internal error: bad directive in parse: %s", item)
- }
- }
-}
-
-// -- Execution
-
-// Evaluate interfaces and pointers looking for a value that can look up the name, via a
-// struct field, method, or map key, and return the result of the lookup.
-func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
- for v != nil {
- typ := v.Type()
- if n := v.Type().NumMethod(); n > 0 {
- for i := 0; i < n; i++ {
- m := typ.Method(i)
- mtyp := m.Type
- if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
- if !isExported(name) {
- t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
- }
- return v.Method(i).Call(nil)[0]
- }
- }
- }
- switch av := v.(type) {
- case *reflect.PtrValue:
- v = av.Elem()
- case *reflect.InterfaceValue:
- v = av.Elem()
- case *reflect.StructValue:
- if !isExported(name) {
- t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
- }
- return av.FieldByName(name)
- case *reflect.MapValue:
- if v := av.Elem(reflect.NewValue(name)); v != nil {
- return v
- }
- return reflect.MakeZero(typ.(*reflect.MapType).Elem())
- default:
- return nil
- }
- }
- return v
-}
-
-// indirectPtr returns the item numLevels levels of indirection below the value.
-// It is forgiving: if the value is not a pointer, it returns it rather than giving
-// an error. If the pointer is nil, it is returned as is.
-func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
- for i := numLevels; v != nil && i > 0; i++ {
- if p, ok := v.(*reflect.PtrValue); ok {
- if p.IsNil() {
- return v
- }
- v = p.Elem()
- } else {
- break
- }
- }
- return v
-}
-
-// Walk v through pointers and interfaces, extracting the elements within.
-func indirect(v reflect.Value) reflect.Value {
-loop:
- for v != nil {
- switch av := v.(type) {
- case *reflect.PtrValue:
- v = av.Elem()
- case *reflect.InterfaceValue:
- v = av.Elem()
- default:
- break loop
- }
- }
- return v
-}
-
-// If the data for this template is a struct, find the named variable.
-// Names of the form a.b.c are walked down the data tree.
-// The special name "@" (the "cursor") denotes the current data.
-// The value coming in (st.data) might need indirecting to reach
-// a struct while the return value is not indirected - that is,
-// it represents the actual named field. Leading stars indicate
-// levels of indirection to be applied to the value.
-func (t *Template) findVar(st *state, s string) reflect.Value {
- data := st.data
- flattenedName := strings.TrimLeft(s, "*")
- numStars := len(s) - len(flattenedName)
- s = flattenedName
- if s == "@" {
- return indirectPtr(data, numStars)
- }
- for _, elem := range strings.Split(s, ".") {
- // Look up field; data must be a struct or map.
- data = t.lookup(st, data, elem)
- if data == nil {
- return nil
- }
- }
- return indirectPtr(data, numStars)
-}
-
-// Is there no data to look at?
-func empty(v reflect.Value) bool {
- v = indirect(v)
- if v == nil {
- return true
- }
- switch v := v.(type) {
- case *reflect.BoolValue:
- return v.Get() == false
- case *reflect.StringValue:
- return v.Get() == ""
- case *reflect.StructValue:
- return false
- case *reflect.MapValue:
- return false
- case *reflect.ArrayValue:
- return v.Len() == 0
- case *reflect.SliceValue:
- return v.Len() == 0
- }
- return false
-}
-
-// Look up a variable or method, up through the parent if necessary.
-func (t *Template) varValue(name string, st *state) reflect.Value {
- field := t.findVar(st, name)
- if field == nil {
- if st.parent == nil {
- t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
- }
- return t.varValue(name, st.parent)
- }
- return field
-}
-
-func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
- fn := t.formatter(fmt)
- if fn == nil {
- t.execError(st, v.linenum, "missing formatter %s for variable %s", fmt, v.word[0])
- }
- fn(wr, fmt, val...)
-}
-
-// Evaluate a variable, looking up through the parent if necessary.
-// If it has a formatter attached ({var|formatter}) run that too.
-func (t *Template) writeVariable(v *variableElement, st *state) {
- // Turn the words of the invocation into values.
- val := make([]interface{}, len(v.word))
- for i, word := range v.word {
- val[i] = t.varValue(word, st).Interface()
- }
-
- for i, fmt := range v.fmts[:len(v.fmts)-1] {
- b := &st.buf[i&1]
- b.Reset()
- t.format(b, fmt, val, v, st)
- val = val[0:1]
- val[0] = b.Bytes()
- }
- t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
-}
-
-// Execute element i. Return next index to execute.
-func (t *Template) executeElement(i int, st *state) int {
- switch elem := t.elems.At(i).(type) {
- case *textElement:
- st.wr.Write(elem.text)
- return i + 1
- case *literalElement:
- st.wr.Write(elem.text)
- return i + 1
- case *variableElement:
- t.writeVariable(elem, st)
- return i + 1
- case *sectionElement:
- t.executeSection(elem, st)
- return elem.end
- case *repeatedElement:
- t.executeRepeated(elem, st)
- return elem.end
- }
- e := t.elems.At(i)
- t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.NewValue(e).Interface(), e)
- return 0
-}
-
-// Execute the template.
-func (t *Template) execute(start, end int, st *state) {
- for i := start; i < end; {
- i = t.executeElement(i, st)
- }
-}
-
-// Execute a .section
-func (t *Template) executeSection(s *sectionElement, st *state) {
- // Find driver data for this section. It must be in the current struct.
- field := t.varValue(s.field, st)
- if field == nil {
- t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, st.data.Type())
- }
- st = st.clone(field)
- start, end := s.start, s.or
- if !empty(field) {
- // Execute the normal block.
- if end < 0 {
- end = s.end
- }
- } else {
- // Execute the .or block. If it's missing, do nothing.
- start, end = s.or, s.end
- if start < 0 {
- return
- }
- }
- for i := start; i < end; {
- i = t.executeElement(i, st)
- }
-}
-
-// Return the result of calling the Iter method on v, or nil.
-func iter(v reflect.Value) *reflect.ChanValue {
- for j := 0; j < v.Type().NumMethod(); j++ {
- mth := v.Type().Method(j)
- fv := v.Method(j)
- ft := fv.Type().(*reflect.FuncType)
- // TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
- if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
- continue
- }
- ct, ok := ft.Out(0).(*reflect.ChanType)
- if !ok || ct.Dir()&reflect.RecvDir == 0 {
- continue
- }
- return fv.Call(nil)[0].(*reflect.ChanValue)
- }
- return nil
-}
-
-// Execute a .repeated section
-func (t *Template) executeRepeated(r *repeatedElement, st *state) {
- // Find driver data for this section. It must be in the current struct.
- field := t.varValue(r.field, st)
- if field == nil {
- t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, st.data.Type())
- }
- field = indirect(field)
-
- start, end := r.start, r.or
- if end < 0 {
- end = r.end
- }
- if r.altstart >= 0 {
- end = r.altstart
- }
- first := true
-
- // Code common to all the loops.
- loopBody := func(newst *state) {
- // .alternates between elements
- if !first && r.altstart >= 0 {
- for i := r.altstart; i < r.altend; {
- i = t.executeElement(i, newst)
- }
- }
- first = false
- for i := start; i < end; {
- i = t.executeElement(i, newst)
- }
- }
-
- if array, ok := field.(reflect.ArrayOrSliceValue); ok {
- for j := 0; j < array.Len(); j++ {
- loopBody(st.clone(array.Elem(j)))
- }
- } else if m, ok := field.(*reflect.MapValue); ok {
- for _, key := range m.Keys() {
- loopBody(st.clone(m.Elem(key)))
- }
- } else if ch := iter(field); ch != nil {
- for {
- e, ok := ch.Recv()
- if !ok {
- break
- }
- loopBody(st.clone(e))
- }
- } else {
- t.execError(st, r.linenum, ".repeated: cannot repeat %s (type %s)",
- r.field, field.Type())
- }
-
- if first {
- // Empty. Execute the .or block, once. If it's missing, do nothing.
- start, end := r.or, r.end
- if start >= 0 {
- newst := st.clone(field)
- for i := start; i < end; {
- i = t.executeElement(i, newst)
- }
- }
- return
- }
-}
-
-// A valid delimiter must contain no white space and be non-empty.
-func validDelim(d []byte) bool {
- if len(d) == 0 {
- return false
- }
- for _, c := range d {
- if white(c) {
- return false
- }
- }
- return true
-}
-
-// checkError is a deferred function to turn a panic with type *Error into a plain error return.
-// Other panics are unexpected and so are re-enabled.
-func checkError(error *os.Error) {
- if v := recover(); v != nil {
- if e, ok := v.(*Error); ok {
- *error = e
- } else {
- // runtime errors should crash
- panic(v)
- }
- }
-}
-
-// -- Public interface
-
-// Parse initializes a Template by parsing its definition. The string
-// s contains the template text. If any errors occur, Parse returns
-// the error.
-func (t *Template) Parse(s string) (err os.Error) {
- if t.elems == nil {
- return &Error{1, "template not allocated with New"}
- }
- if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
- return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
- }
- defer checkError(&err)
- t.buf = []byte(s)
- t.p = 0
- t.linenum = 1
- t.parse()
- return nil
-}
-
-// ParseFile is like Parse but reads the template definition from the
-// named file.
-func (t *Template) ParseFile(filename string) (err os.Error) {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- return err
- }
- return t.Parse(string(b))
-}
-
-// Execute applies a parsed template to the specified data object,
-// generating output to wr.
-func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
- // Extract the driver data.
- val := reflect.NewValue(data)
- defer checkError(&err)
- t.p = 0
- t.execute(0, t.elems.Len(), &state{parent: nil, data: val, wr: wr})
- return nil
-}
-
-// SetDelims sets the left and right delimiters for operations in the
-// template. They are validated during parsing. They could be
-// validated here but it's better to keep the routine simple. The
-// delimiters are very rarely invalid and Parse has the necessary
-// error-handling interface already.
-func (t *Template) SetDelims(left, right string) {
- t.ldelim = []byte(left)
- t.rdelim = []byte(right)
-}
-
-// Parse creates a Template with default parameters (such as {} for
-// metacharacters). The string s contains the template text while
-// the formatter map fmap, which may be nil, defines auxiliary functions
-// for formatting variables. The template is returned. If any errors
-// occur, err will be non-nil.
-func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
- t = New(fmap)
- err = t.Parse(s)
- if err != nil {
- t = nil
- }
- return
-}
-
-// ParseFile is a wrapper function that creates a Template with default
-// parameters (such as {} for metacharacters). The filename identifies
-// a file containing the template text, while the formatter map fmap, which
-// may be nil, defines auxiliary functions for formatting variables.
-// The template is returned. If any errors occur, err will be non-nil.
-func ParseFile(filename string, fmap FormatterMap) (t *Template, err os.Error) {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return Parse(string(b), fmap)
-}
-
-// MustParse is like Parse but panics if the template cannot be parsed.
-func MustParse(s string, fmap FormatterMap) *Template {
- t, err := Parse(s, fmap)
- if err != nil {
- panic("template.MustParse error: " + err.String())
- }
- return t
-}
-
-// MustParseFile is like ParseFile but panics if the file cannot be read
-// or the template cannot be parsed.
-func MustParseFile(filename string, fmap FormatterMap) *Template {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- panic("template.MustParseFile error: " + err.String())
- }
- return MustParse(string(b), fmap)
-}
diff --git a/src/cmd/gofix/testdata/reflect.template.go.out b/src/cmd/gofix/testdata/reflect.template.go.out
deleted file mode 100644
index f2f56ef3c..000000000
--- a/src/cmd/gofix/testdata/reflect.template.go.out
+++ /dev/null
@@ -1,1044 +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.
-
-/*
- Data-driven templates for generating textual output such as
- HTML.
-
- Templates are executed by applying them to a data structure.
- Annotations in the template refer to elements of the data
- structure (typically a field of a struct or a key in a map)
- to control execution and derive values to be displayed.
- The template walks the structure as it executes and the
- "cursor" @ represents the value at the current location
- in the structure.
-
- Data items may be values or pointers; the interface hides the
- indirection.
-
- In the following, 'field' is one of several things, according to the data.
-
- - The name of a field of a struct (result = data.field),
- - The value stored in a map under that key (result = data[field]), or
- - The result of invoking a niladic single-valued method with that name
- (result = data.field())
-
- Major constructs ({} are the default delimiters for template actions;
- [] are the notation in this comment for optional elements):
-
- {# comment }
-
- A one-line comment.
-
- {.section field} XXX [ {.or} YYY ] {.end}
-
- Set @ to the value of the field. It may be an explicit @
- to stay at the same point in the data. If the field is nil
- or empty, execute YYY; otherwise execute XXX.
-
- {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end}
-
- Like .section, but field must be an array or slice. XXX
- is executed for each element. If the array is nil or empty,
- YYY is executed instead. If the {.alternates with} marker
- is present, ZZZ is executed between iterations of XXX.
-
- {field}
- {field1 field2 ...}
- {field|formatter}
- {field1 field2...|formatter}
- {field|formatter1|formatter2}
-
- Insert the value of the fields into the output. Each field is
- first looked for in the cursor, as in .section and .repeated.
- If it is not found, the search continues in outer sections
- until the top level is reached.
-
- If the field value is a pointer, leading asterisks indicate
- that the value to be inserted should be evaluated through the
- pointer. For example, if x.p is of type *int, {x.p} will
- insert the value of the pointer but {*x.p} will insert the
- value of the underlying integer. If the value is nil or not a
- pointer, asterisks have no effect.
-
- If a formatter is specified, it must be named in the formatter
- map passed to the template set up routines or in the default
- set ("html","str","") and is used to process the data for
- output. The formatter function has signature
- func(wr io.Writer, formatter string, data ...interface{})
- where wr is the destination for output, data holds the field
- values at the instantiation, and formatter is its name at
- the invocation site. The default formatter just concatenates
- the string representations of the fields.
-
- Multiple formatters separated by the pipeline character | are
- executed sequentially, with each formatter receiving the bytes
- emitted by the one to its left.
-
- The delimiter strings get their default value, "{" and "}", from
- JSON-template. They may be set to any non-empty, space-free
- string using the SetDelims method. Their value can be printed
- in the output using {.meta-left} and {.meta-right}.
-*/
-package template
-
-import (
- "bytes"
- "container/vector"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "reflect"
- "strings"
- "unicode"
- "utf8"
-)
-
-// Errors returned during parsing and execution. Users may extract the information and reformat
-// if they desire.
-type Error struct {
- Line int
- Msg string
-}
-
-func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
-
-// Most of the literals are aces.
-var lbrace = []byte{'{'}
-var rbrace = []byte{'}'}
-var space = []byte{' '}
-var tab = []byte{'\t'}
-
-// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
-const (
- tokAlternates = iota
- tokComment
- tokEnd
- tokLiteral
- tokOr
- tokRepeated
- tokSection
- tokText
- tokVariable
-)
-
-// FormatterMap is the type describing the mapping from formatter
-// names to the functions that implement them.
-type FormatterMap map[string]func(io.Writer, string, ...interface{})
-
-// Built-in formatters.
-var builtins = FormatterMap{
- "html": HTMLFormatter,
- "str": StringFormatter,
- "": StringFormatter,
-}
-
-// The parsed state of a template is a vector of xxxElement structs.
-// Sections have line numbers so errors can be reported better during execution.
-
-// Plain text.
-type textElement struct {
- text []byte
-}
-
-// A literal such as .meta-left or .meta-right
-type literalElement struct {
- text []byte
-}
-
-// A variable invocation to be evaluated
-type variableElement struct {
- linenum int
- word []string // The fields in the invocation.
- fmts []string // Names of formatters to apply. len(fmts) > 0
-}
-
-// A .section block, possibly with a .or
-type sectionElement struct {
- linenum int // of .section itself
- field string // cursor field for this block
- start int // first element
- or int // first element of .or block
- end int // one beyond last element
-}
-
-// A .repeated block, possibly with a .or and a .alternates
-type repeatedElement struct {
- sectionElement // It has the same structure...
- altstart int // ... except for alternates
- altend int
-}
-
-// Template is the type that represents a template definition.
-// It is unchanged after parsing.
-type Template struct {
- fmap FormatterMap // formatters for variables
- // Used during parsing:
- ldelim, rdelim []byte // delimiters; default {}
- buf []byte // input text to process
- p int // position in buf
- linenum int // position in input
- // Parsed results:
- elems *vector.Vector
-}
-
-// Internal state for executing a Template. As we evaluate the struct,
-// the data item descends into the fields associated with sections, etc.
-// Parent is used to walk upwards to find variables higher in the tree.
-type state struct {
- parent *state // parent in hierarchy
- data reflect.Value // the driver data for this section etc.
- wr io.Writer // where to send output
- buf [2]bytes.Buffer // alternating buffers used when chaining formatters
-}
-
-func (parent *state) clone(data reflect.Value) *state {
- return &state{parent: parent, data: data, wr: parent.wr}
-}
-
-// New creates a new template with the specified formatter map (which
-// may be nil) to define auxiliary functions for formatting variables.
-func New(fmap FormatterMap) *Template {
- t := new(Template)
- t.fmap = fmap
- t.ldelim = lbrace
- t.rdelim = rbrace
- t.elems = new(vector.Vector)
- return t
-}
-
-// Report error and stop executing. The line number must be provided explicitly.
-func (t *Template) execError(st *state, line int, err string, args ...interface{}) {
- panic(&Error{line, fmt.Sprintf(err, args...)})
-}
-
-// Report error, panic to terminate parsing.
-// The line number comes from the template state.
-func (t *Template) parseError(err string, args ...interface{}) {
- panic(&Error{t.linenum, fmt.Sprintf(err, args...)})
-}
-
-// Is this an exported - upper case - name?
-func isExported(name string) bool {
- rune, _ := utf8.DecodeRuneInString(name)
- return unicode.IsUpper(rune)
-}
-
-// -- Lexical analysis
-
-// Is c a white space character?
-func white(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' }
-
-// Safely, does s[n:n+len(t)] == t?
-func equal(s []byte, n int, t []byte) bool {
- b := s[n:]
- if len(t) > len(b) { // not enough space left for a match.
- return false
- }
- for i, c := range t {
- if c != b[i] {
- return false
- }
- }
- return true
-}
-
-// nextItem returns the next item from the input buffer. If the returned
-// item is empty, we are at EOF. The item will be either a
-// delimited string or a non-empty string between delimited
-// strings. Tokens stop at (but include, if plain text) a newline.
-// Action tokens on a line by themselves drop any space on
-// either side, up to and including the newline.
-func (t *Template) nextItem() []byte {
- startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
- start := t.p
- var i int
- newline := func() {
- t.linenum++
- i++
- }
- // Leading white space up to but not including newline
- for i = start; i < len(t.buf); i++ {
- if t.buf[i] == '\n' || !white(t.buf[i]) {
- break
- }
- }
- leadingSpace := i > start
- // What's left is nothing, newline, delimited string, or plain text
- switch {
- case i == len(t.buf):
- // EOF; nothing to do
- case t.buf[i] == '\n':
- newline()
- case equal(t.buf, i, t.ldelim):
- left := i // Start of left delimiter.
- right := -1 // Will be (immediately after) right delimiter.
- haveText := false // Delimiters contain text.
- i += len(t.ldelim)
- // Find the end of the action.
- for ; i < len(t.buf); i++ {
- if t.buf[i] == '\n' {
- break
- }
- if equal(t.buf, i, t.rdelim) {
- i += len(t.rdelim)
- right = i
- break
- }
- haveText = true
- }
- if right < 0 {
- t.parseError("unmatched opening delimiter")
- return nil
- }
- // Is this a special action (starts with '.' or '#') and the only thing on the line?
- if startOfLine && haveText {
- firstChar := t.buf[left+len(t.ldelim)]
- if firstChar == '.' || firstChar == '#' {
- // It's special and the first thing on the line. Is it the last?
- for j := right; j < len(t.buf) && white(t.buf[j]); j++ {
- if t.buf[j] == '\n' {
- // Yes it is. Drop the surrounding space and return the {.foo}
- t.linenum++
- t.p = j + 1
- return t.buf[left:right]
- }
- }
- }
- }
- // No it's not. If there's leading space, return that.
- if leadingSpace {
- // not trimming space: return leading white space if there is some.
- t.p = left
- return t.buf[start:left]
- }
- // Return the word, leave the trailing space.
- start = left
- break
- default:
- for ; i < len(t.buf); i++ {
- if t.buf[i] == '\n' {
- newline()
- break
- }
- if equal(t.buf, i, t.ldelim) {
- break
- }
- }
- }
- item := t.buf[start:i]
- t.p = i
- return item
-}
-
-// Turn a byte array into a white-space-split array of strings.
-func words(buf []byte) []string {
- s := make([]string, 0, 5)
- p := 0 // position in buf
- // one word per loop
- for i := 0; ; i++ {
- // skip white space
- for ; p < len(buf) && white(buf[p]); p++ {
- }
- // grab word
- start := p
- for ; p < len(buf) && !white(buf[p]); p++ {
- }
- if start == p { // no text left
- break
- }
- s = append(s, string(buf[start:p]))
- }
- return s
-}
-
-// Analyze an item and return its token type and, if it's an action item, an array of
-// its constituent words.
-func (t *Template) analyze(item []byte) (tok int, w []string) {
- // item is known to be non-empty
- if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
- tok = tokText
- return
- }
- if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
- t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
- return
- }
- if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
- t.parseError("empty directive")
- return
- }
- // Comment
- if item[len(t.ldelim)] == '#' {
- tok = tokComment
- return
- }
- // Split into words
- w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
- if len(w) == 0 {
- t.parseError("empty directive")
- return
- }
- if len(w) > 0 && w[0][0] != '.' {
- tok = tokVariable
- return
- }
- switch w[0] {
- case ".meta-left", ".meta-right", ".space", ".tab":
- tok = tokLiteral
- return
- case ".or":
- tok = tokOr
- return
- case ".end":
- tok = tokEnd
- return
- case ".section":
- if len(w) != 2 {
- t.parseError("incorrect fields for .section: %s", item)
- return
- }
- tok = tokSection
- return
- case ".repeated":
- if len(w) != 3 || w[1] != "section" {
- t.parseError("incorrect fields for .repeated: %s", item)
- return
- }
- tok = tokRepeated
- return
- case ".alternates":
- if len(w) != 2 || w[1] != "with" {
- t.parseError("incorrect fields for .alternates: %s", item)
- return
- }
- tok = tokAlternates
- return
- }
- t.parseError("bad directive: %s", item)
- return
-}
-
-// formatter returns the Formatter with the given name in the Template, or nil if none exists.
-func (t *Template) formatter(name string) func(io.Writer, string, ...interface{}) {
- if t.fmap != nil {
- if fn := t.fmap[name]; fn != nil {
- return fn
- }
- }
- return builtins[name]
-}
-
-// -- Parsing
-
-// Allocate a new variable-evaluation element.
-func (t *Template) newVariable(words []string) *variableElement {
- // After the final space-separated argument, formatters may be specified separated
- // by pipe symbols, for example: {a b c|d|e}
-
- // Until we learn otherwise, formatters contains a single name: "", the default formatter.
- formatters := []string{""}
- lastWord := words[len(words)-1]
- bar := strings.IndexRune(lastWord, '|')
- if bar >= 0 {
- words[len(words)-1] = lastWord[0:bar]
- formatters = strings.Split(lastWord[bar+1:], "|")
- }
-
- // We could remember the function address here and avoid the lookup later,
- // but it's more dynamic to let the user change the map contents underfoot.
- // We do require the name to be present, though.
-
- // Is it in user-supplied map?
- for _, f := range formatters {
- if t.formatter(f) == nil {
- t.parseError("unknown formatter: %q", f)
- }
- }
- return &variableElement{t.linenum, words, formatters}
-}
-
-// Grab the next item. If it's simple, just append it to the template.
-// Otherwise return its details.
-func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
- tok, w = t.analyze(item)
- done = true // assume for simplicity
- switch tok {
- case tokComment:
- return
- case tokText:
- t.elems.Push(&textElement{item})
- return
- case tokLiteral:
- switch w[0] {
- case ".meta-left":
- t.elems.Push(&literalElement{t.ldelim})
- case ".meta-right":
- t.elems.Push(&literalElement{t.rdelim})
- case ".space":
- t.elems.Push(&literalElement{space})
- case ".tab":
- t.elems.Push(&literalElement{tab})
- default:
- t.parseError("internal error: unknown literal: %s", w[0])
- }
- return
- case tokVariable:
- t.elems.Push(t.newVariable(w))
- return
- }
- return false, tok, w
-}
-
-// parseRepeated and parseSection are mutually recursive
-
-func (t *Template) parseRepeated(words []string) *repeatedElement {
- r := new(repeatedElement)
- t.elems.Push(r)
- r.linenum = t.linenum
- r.field = words[2]
- // Scan section, collecting true and false (.or) blocks.
- r.start = t.elems.Len()
- r.or = -1
- r.altstart = -1
- r.altend = -1
-Loop:
- for {
- item := t.nextItem()
- if len(item) == 0 {
- t.parseError("missing .end for .repeated section")
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokEnd:
- break Loop
- case tokOr:
- if r.or >= 0 {
- t.parseError("extra .or in .repeated section")
- break Loop
- }
- r.altend = t.elems.Len()
- r.or = t.elems.Len()
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- case tokAlternates:
- if r.altstart >= 0 {
- t.parseError("extra .alternates in .repeated section")
- break Loop
- }
- if r.or >= 0 {
- t.parseError(".alternates inside .or block in .repeated section")
- break Loop
- }
- r.altstart = t.elems.Len()
- default:
- t.parseError("internal error: unknown repeated section item: %s", item)
- break Loop
- }
- }
- if r.altend < 0 {
- r.altend = t.elems.Len()
- }
- r.end = t.elems.Len()
- return r
-}
-
-func (t *Template) parseSection(words []string) *sectionElement {
- s := new(sectionElement)
- t.elems.Push(s)
- s.linenum = t.linenum
- s.field = words[1]
- // Scan section, collecting true and false (.or) blocks.
- s.start = t.elems.Len()
- s.or = -1
-Loop:
- for {
- item := t.nextItem()
- if len(item) == 0 {
- t.parseError("missing .end for .section")
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokEnd:
- break Loop
- case tokOr:
- if s.or >= 0 {
- t.parseError("extra .or in .section")
- break Loop
- }
- s.or = t.elems.Len()
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- case tokAlternates:
- t.parseError(".alternates not in .repeated")
- default:
- t.parseError("internal error: unknown section item: %s", item)
- }
- }
- s.end = t.elems.Len()
- return s
-}
-
-func (t *Template) parse() {
- for {
- item := t.nextItem()
- if len(item) == 0 {
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokOr, tokEnd, tokAlternates:
- t.parseError("unexpected %s", w[0])
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- default:
- t.parseError("internal error: bad directive in parse: %s", item)
- }
- }
-}
-
-// -- Execution
-
-// Evaluate interfaces and pointers looking for a value that can look up the name, via a
-// struct field, method, or map key, and return the result of the lookup.
-func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
- for v.IsValid() {
- typ := v.Type()
- if n := v.Type().NumMethod(); n > 0 {
- for i := 0; i < n; i++ {
- m := typ.Method(i)
- mtyp := m.Type
- if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
- if !isExported(name) {
- t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
- }
- return v.Method(i).Call(nil)[0]
- }
- }
- }
- switch av := v; av.Kind() {
- case reflect.Ptr:
- v = av.Elem()
- case reflect.Interface:
- v = av.Elem()
- case reflect.Struct:
- if !isExported(name) {
- t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
- }
- return av.FieldByName(name)
- case reflect.Map:
- if v := av.MapIndex(reflect.ValueOf(name)); v.IsValid() {
- return v
- }
- return reflect.Zero(typ.Elem())
- default:
- return reflect.Value{}
- }
- }
- return v
-}
-
-// indirectPtr returns the item numLevels levels of indirection below the value.
-// It is forgiving: if the value is not a pointer, it returns it rather than giving
-// an error. If the pointer is nil, it is returned as is.
-func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
- for i := numLevels; v.IsValid() && i > 0; i++ {
- if p := v; p.Kind() == reflect.Ptr {
- if p.IsNil() {
- return v
- }
- v = p.Elem()
- } else {
- break
- }
- }
- return v
-}
-
-// Walk v through pointers and interfaces, extracting the elements within.
-func indirect(v reflect.Value) reflect.Value {
-loop:
- for v.IsValid() {
- switch av := v; av.Kind() {
- case reflect.Ptr:
- v = av.Elem()
- case reflect.Interface:
- v = av.Elem()
- default:
- break loop
- }
- }
- return v
-}
-
-// If the data for this template is a struct, find the named variable.
-// Names of the form a.b.c are walked down the data tree.
-// The special name "@" (the "cursor") denotes the current data.
-// The value coming in (st.data) might need indirecting to reach
-// a struct while the return value is not indirected - that is,
-// it represents the actual named field. Leading stars indicate
-// levels of indirection to be applied to the value.
-func (t *Template) findVar(st *state, s string) reflect.Value {
- data := st.data
- flattenedName := strings.TrimLeft(s, "*")
- numStars := len(s) - len(flattenedName)
- s = flattenedName
- if s == "@" {
- return indirectPtr(data, numStars)
- }
- for _, elem := range strings.Split(s, ".") {
- // Look up field; data must be a struct or map.
- data = t.lookup(st, data, elem)
- if !data.IsValid() {
- return reflect.Value{}
- }
- }
- return indirectPtr(data, numStars)
-}
-
-// Is there no data to look at?
-func empty(v reflect.Value) bool {
- v = indirect(v)
- if !v.IsValid() {
- return true
- }
- switch v.Kind() {
- case reflect.Bool:
- return v.Bool() == false
- case reflect.String:
- return v.String() == ""
- case reflect.Struct:
- return false
- case reflect.Map:
- return false
- case reflect.Array:
- return v.Len() == 0
- case reflect.Slice:
- return v.Len() == 0
- }
- return false
-}
-
-// Look up a variable or method, up through the parent if necessary.
-func (t *Template) varValue(name string, st *state) reflect.Value {
- field := t.findVar(st, name)
- if !field.IsValid() {
- if st.parent == nil {
- t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
- }
- return t.varValue(name, st.parent)
- }
- return field
-}
-
-func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
- fn := t.formatter(fmt)
- if fn == nil {
- t.execError(st, v.linenum, "missing formatter %s for variable %s", fmt, v.word[0])
- }
- fn(wr, fmt, val...)
-}
-
-// Evaluate a variable, looking up through the parent if necessary.
-// If it has a formatter attached ({var|formatter}) run that too.
-func (t *Template) writeVariable(v *variableElement, st *state) {
- // Turn the words of the invocation into values.
- val := make([]interface{}, len(v.word))
- for i, word := range v.word {
- val[i] = t.varValue(word, st).Interface()
- }
-
- for i, fmt := range v.fmts[:len(v.fmts)-1] {
- b := &st.buf[i&1]
- b.Reset()
- t.format(b, fmt, val, v, st)
- val = val[0:1]
- val[0] = b.Bytes()
- }
- t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
-}
-
-// Execute element i. Return next index to execute.
-func (t *Template) executeElement(i int, st *state) int {
- switch elem := t.elems.At(i).(type) {
- case *textElement:
- st.wr.Write(elem.text)
- return i + 1
- case *literalElement:
- st.wr.Write(elem.text)
- return i + 1
- case *variableElement:
- t.writeVariable(elem, st)
- return i + 1
- case *sectionElement:
- t.executeSection(elem, st)
- return elem.end
- case *repeatedElement:
- t.executeRepeated(elem, st)
- return elem.end
- }
- e := t.elems.At(i)
- t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.ValueOf(e).Interface(), e)
- return 0
-}
-
-// Execute the template.
-func (t *Template) execute(start, end int, st *state) {
- for i := start; i < end; {
- i = t.executeElement(i, st)
- }
-}
-
-// Execute a .section
-func (t *Template) executeSection(s *sectionElement, st *state) {
- // Find driver data for this section. It must be in the current struct.
- field := t.varValue(s.field, st)
- if !field.IsValid() {
- t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, st.data.Type())
- }
- st = st.clone(field)
- start, end := s.start, s.or
- if !empty(field) {
- // Execute the normal block.
- if end < 0 {
- end = s.end
- }
- } else {
- // Execute the .or block. If it's missing, do nothing.
- start, end = s.or, s.end
- if start < 0 {
- return
- }
- }
- for i := start; i < end; {
- i = t.executeElement(i, st)
- }
-}
-
-// Return the result of calling the Iter method on v, or nil.
-func iter(v reflect.Value) reflect.Value {
- for j := 0; j < v.Type().NumMethod(); j++ {
- mth := v.Type().Method(j)
- fv := v.Method(j)
- ft := fv.Type()
- // TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
- if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
- continue
- }
- ct := ft.Out(0)
- if ct.Kind() != reflect.Chan ||
- ct.ChanDir()&reflect.RecvDir == 0 {
- continue
- }
- return fv.Call(nil)[0]
- }
- return reflect.Value{}
-}
-
-// Execute a .repeated section
-func (t *Template) executeRepeated(r *repeatedElement, st *state) {
- // Find driver data for this section. It must be in the current struct.
- field := t.varValue(r.field, st)
- if !field.IsValid() {
- t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, st.data.Type())
- }
- field = indirect(field)
-
- start, end := r.start, r.or
- if end < 0 {
- end = r.end
- }
- if r.altstart >= 0 {
- end = r.altstart
- }
- first := true
-
- // Code common to all the loops.
- loopBody := func(newst *state) {
- // .alternates between elements
- if !first && r.altstart >= 0 {
- for i := r.altstart; i < r.altend; {
- i = t.executeElement(i, newst)
- }
- }
- first = false
- for i := start; i < end; {
- i = t.executeElement(i, newst)
- }
- }
-
- if array := field; array.Kind() == reflect.Array || array.Kind() == reflect.Slice {
- for j := 0; j < array.Len(); j++ {
- loopBody(st.clone(array.Index(j)))
- }
- } else if m := field; m.Kind() == reflect.Map {
- for _, key := range m.MapKeys() {
- loopBody(st.clone(m.MapIndex(key)))
- }
- } else if ch := iter(field); ch.IsValid() {
- for {
- e, ok := ch.Recv()
- if !ok {
- break
- }
- loopBody(st.clone(e))
- }
- } else {
- t.execError(st, r.linenum, ".repeated: cannot repeat %s (type %s)",
- r.field, field.Type())
- }
-
- if first {
- // Empty. Execute the .or block, once. If it's missing, do nothing.
- start, end := r.or, r.end
- if start >= 0 {
- newst := st.clone(field)
- for i := start; i < end; {
- i = t.executeElement(i, newst)
- }
- }
- return
- }
-}
-
-// A valid delimiter must contain no white space and be non-empty.
-func validDelim(d []byte) bool {
- if len(d) == 0 {
- return false
- }
- for _, c := range d {
- if white(c) {
- return false
- }
- }
- return true
-}
-
-// checkError is a deferred function to turn a panic with type *Error into a plain error return.
-// Other panics are unexpected and so are re-enabled.
-func checkError(error *os.Error) {
- if v := recover(); v != nil {
- if e, ok := v.(*Error); ok {
- *error = e
- } else {
- // runtime errors should crash
- panic(v)
- }
- }
-}
-
-// -- Public interface
-
-// Parse initializes a Template by parsing its definition. The string
-// s contains the template text. If any errors occur, Parse returns
-// the error.
-func (t *Template) Parse(s string) (err os.Error) {
- if t.elems == nil {
- return &Error{1, "template not allocated with New"}
- }
- if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
- return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
- }
- defer checkError(&err)
- t.buf = []byte(s)
- t.p = 0
- t.linenum = 1
- t.parse()
- return nil
-}
-
-// ParseFile is like Parse but reads the template definition from the
-// named file.
-func (t *Template) ParseFile(filename string) (err os.Error) {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- return err
- }
- return t.Parse(string(b))
-}
-
-// Execute applies a parsed template to the specified data object,
-// generating output to wr.
-func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
- // Extract the driver data.
- val := reflect.ValueOf(data)
- defer checkError(&err)
- t.p = 0
- t.execute(0, t.elems.Len(), &state{parent: nil, data: val, wr: wr})
- return nil
-}
-
-// SetDelims sets the left and right delimiters for operations in the
-// template. They are validated during parsing. They could be
-// validated here but it's better to keep the routine simple. The
-// delimiters are very rarely invalid and Parse has the necessary
-// error-handling interface already.
-func (t *Template) SetDelims(left, right string) {
- t.ldelim = []byte(left)
- t.rdelim = []byte(right)
-}
-
-// Parse creates a Template with default parameters (such as {} for
-// metacharacters). The string s contains the template text while
-// the formatter map fmap, which may be nil, defines auxiliary functions
-// for formatting variables. The template is returned. If any errors
-// occur, err will be non-nil.
-func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
- t = New(fmap)
- err = t.Parse(s)
- if err != nil {
- t = nil
- }
- return
-}
-
-// ParseFile is a wrapper function that creates a Template with default
-// parameters (such as {} for metacharacters). The filename identifies
-// a file containing the template text, while the formatter map fmap, which
-// may be nil, defines auxiliary functions for formatting variables.
-// The template is returned. If any errors occur, err will be non-nil.
-func ParseFile(filename string, fmap FormatterMap) (t *Template, err os.Error) {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return Parse(string(b), fmap)
-}
-
-// MustParse is like Parse but panics if the template cannot be parsed.
-func MustParse(s string, fmap FormatterMap) *Template {
- t, err := Parse(s, fmap)
- if err != nil {
- panic("template.MustParse error: " + err.String())
- }
- return t
-}
-
-// MustParseFile is like ParseFile but panics if the file cannot be read
-// or the template cannot be parsed.
-func MustParseFile(filename string, fmap FormatterMap) *Template {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- panic("template.MustParseFile error: " + err.String())
- }
- return MustParse(string(b), fmap)
-}
diff --git a/src/cmd/gofix/testdata/reflect.type.go.in b/src/cmd/gofix/testdata/reflect.type.go.in
deleted file mode 100644
index 305d41980..000000000
--- a/src/cmd/gofix/testdata/reflect.type.go.in
+++ /dev/null
@@ -1,789 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gob
-
-import (
- "fmt"
- "os"
- "reflect"
- "sync"
- "unicode"
- "utf8"
-)
-
-// userTypeInfo stores the information associated with a type the user has handed
-// to the package. It's computed once and stored in a map keyed by reflection
-// type.
-type userTypeInfo struct {
- user reflect.Type // the type the user handed us
- base reflect.Type // the base type after all indirections
- indir int // number of indirections to reach the base type
- isGobEncoder bool // does the type implement GobEncoder?
- isGobDecoder bool // does the type implement GobDecoder?
- encIndir int8 // number of indirections to reach the receiver type; may be negative
- decIndir int8 // number of indirections to reach the receiver type; may be negative
-}
-
-var (
- // Protected by an RWMutex because we read it a lot and write
- // it only when we see a new type, typically when compiling.
- userTypeLock sync.RWMutex
- userTypeCache = make(map[reflect.Type]*userTypeInfo)
-)
-
-// validType returns, and saves, the information associated with user-provided type rt.
-// If the user type is not valid, err will be non-nil. To be used when the error handler
-// is not set up.
-func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
- userTypeLock.RLock()
- ut = userTypeCache[rt]
- userTypeLock.RUnlock()
- if ut != nil {
- return
- }
- // Now set the value under the write lock.
- userTypeLock.Lock()
- defer userTypeLock.Unlock()
- if ut = userTypeCache[rt]; ut != nil {
- // Lost the race; not a problem.
- return
- }
- ut = new(userTypeInfo)
- ut.base = rt
- ut.user = rt
- // A type that is just a cycle of pointers (such as type T *T) cannot
- // be represented in gobs, which need some concrete data. We use a
- // cycle detection algorithm from Knuth, Vol 2, Section 3.1, Ex 6,
- // pp 539-540. As we step through indirections, run another type at
- // half speed. If they meet up, there's a cycle.
- slowpoke := ut.base // walks half as fast as ut.base
- for {
- pt, ok := ut.base.(*reflect.PtrType)
- if !ok {
- break
- }
- ut.base = pt.Elem()
- if ut.base == slowpoke { // ut.base lapped slowpoke
- // recursive pointer type.
- return nil, os.ErrorString("can't represent recursive pointer type " + ut.base.String())
- }
- if ut.indir%2 == 0 {
- slowpoke = slowpoke.(*reflect.PtrType).Elem()
- }
- ut.indir++
- }
- ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderCheck)
- ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderCheck)
- userTypeCache[rt] = ut
- return
-}
-
-const (
- gobEncodeMethodName = "GobEncode"
- gobDecodeMethodName = "GobDecode"
-)
-
-// implements returns whether the type implements the interface, as encoded
-// in the check function.
-func implements(typ reflect.Type, check func(typ reflect.Type) bool) bool {
- if typ.NumMethod() == 0 { // avoid allocations etc. unless there's some chance
- return false
- }
- return check(typ)
-}
-
-// gobEncoderCheck makes the type assertion a boolean function.
-func gobEncoderCheck(typ reflect.Type) bool {
- _, ok := reflect.MakeZero(typ).Interface().(GobEncoder)
- return ok
-}
-
-// gobDecoderCheck makes the type assertion a boolean function.
-func gobDecoderCheck(typ reflect.Type) bool {
- _, ok := reflect.MakeZero(typ).Interface().(GobDecoder)
- return ok
-}
-
-// implementsInterface reports whether the type implements the
-// interface. (The actual check is done through the provided function.)
-// It also returns the number of indirections required to get to the
-// implementation.
-func implementsInterface(typ reflect.Type, check func(typ reflect.Type) bool) (success bool, indir int8) {
- if typ == nil {
- return
- }
- rt := typ
- // The type might be a pointer and we need to keep
- // dereferencing to the base type until we find an implementation.
- for {
- if implements(rt, check) {
- return true, indir
- }
- if p, ok := rt.(*reflect.PtrType); ok {
- indir++
- if indir > 100 { // insane number of indirections
- return false, 0
- }
- rt = p.Elem()
- continue
- }
- break
- }
- // No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
- if _, ok := typ.(*reflect.PtrType); !ok {
- // Not a pointer, but does the pointer work?
- if implements(reflect.PtrTo(typ), check) {
- return true, -1
- }
- }
- return false, 0
-}
-
-// userType returns, and saves, the information associated with user-provided type rt.
-// If the user type is not valid, it calls error.
-func userType(rt reflect.Type) *userTypeInfo {
- ut, err := validUserType(rt)
- if err != nil {
- error(err)
- }
- return ut
-}
-// A typeId represents a gob Type as an integer that can be passed on the wire.
-// Internally, typeIds are used as keys to a map to recover the underlying type info.
-type typeId int32
-
-var nextId typeId // incremented for each new type we build
-var typeLock sync.Mutex // set while building a type
-const firstUserId = 64 // lowest id number granted to user
-
-type gobType interface {
- id() typeId
- setId(id typeId)
- name() string
- string() string // not public; only for debugging
- safeString(seen map[typeId]bool) string
-}
-
-var types = make(map[reflect.Type]gobType)
-var idToType = make(map[typeId]gobType)
-var builtinIdToType map[typeId]gobType // set in init() after builtins are established
-
-func setTypeId(typ gobType) {
- nextId++
- typ.setId(nextId)
- idToType[nextId] = typ
-}
-
-func (t typeId) gobType() gobType {
- if t == 0 {
- return nil
- }
- return idToType[t]
-}
-
-// string returns the string representation of the type associated with the typeId.
-func (t typeId) string() string {
- if t.gobType() == nil {
- return "<nil>"
- }
- return t.gobType().string()
-}
-
-// Name returns the name of the type associated with the typeId.
-func (t typeId) name() string {
- if t.gobType() == nil {
- return "<nil>"
- }
- return t.gobType().name()
-}
-
-// Common elements of all types.
-type CommonType struct {
- Name string
- Id typeId
-}
-
-func (t *CommonType) id() typeId { return t.Id }
-
-func (t *CommonType) setId(id typeId) { t.Id = id }
-
-func (t *CommonType) string() string { return t.Name }
-
-func (t *CommonType) safeString(seen map[typeId]bool) string {
- return t.Name
-}
-
-func (t *CommonType) name() string { return t.Name }
-
-// Create and check predefined types
-// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
-
-var (
- // Primordial types, needed during initialization.
- // Always passed as pointers so the interface{} type
- // goes through without losing its interfaceness.
- tBool = bootstrapType("bool", (*bool)(nil), 1)
- tInt = bootstrapType("int", (*int)(nil), 2)
- tUint = bootstrapType("uint", (*uint)(nil), 3)
- tFloat = bootstrapType("float", (*float64)(nil), 4)
- tBytes = bootstrapType("bytes", (*[]byte)(nil), 5)
- tString = bootstrapType("string", (*string)(nil), 6)
- tComplex = bootstrapType("complex", (*complex128)(nil), 7)
- tInterface = bootstrapType("interface", (*interface{})(nil), 8)
- // Reserve some Ids for compatible expansion
- tReserved7 = bootstrapType("_reserved1", (*struct{ r7 int })(nil), 9)
- tReserved6 = bootstrapType("_reserved1", (*struct{ r6 int })(nil), 10)
- tReserved5 = bootstrapType("_reserved1", (*struct{ r5 int })(nil), 11)
- tReserved4 = bootstrapType("_reserved1", (*struct{ r4 int })(nil), 12)
- tReserved3 = bootstrapType("_reserved1", (*struct{ r3 int })(nil), 13)
- tReserved2 = bootstrapType("_reserved1", (*struct{ r2 int })(nil), 14)
- tReserved1 = bootstrapType("_reserved1", (*struct{ r1 int })(nil), 15)
-)
-
-// Predefined because it's needed by the Decoder
-var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
-var wireTypeUserInfo *userTypeInfo // userTypeInfo of (*wireType)
-
-func init() {
- // Some magic numbers to make sure there are no surprises.
- checkId(16, tWireType)
- checkId(17, mustGetTypeInfo(reflect.Typeof(arrayType{})).id)
- checkId(18, mustGetTypeInfo(reflect.Typeof(CommonType{})).id)
- checkId(19, mustGetTypeInfo(reflect.Typeof(sliceType{})).id)
- checkId(20, mustGetTypeInfo(reflect.Typeof(structType{})).id)
- checkId(21, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
- checkId(23, mustGetTypeInfo(reflect.Typeof(mapType{})).id)
-
- builtinIdToType = make(map[typeId]gobType)
- for k, v := range idToType {
- builtinIdToType[k] = v
- }
-
- // Move the id space upwards to allow for growth in the predefined world
- // without breaking existing files.
- if nextId > firstUserId {
- panic(fmt.Sprintln("nextId too large:", nextId))
- }
- nextId = firstUserId
- registerBasics()
- wireTypeUserInfo = userType(reflect.Typeof((*wireType)(nil)))
-}
-
-// Array type
-type arrayType struct {
- CommonType
- Elem typeId
- Len int
-}
-
-func newArrayType(name string) *arrayType {
- a := &arrayType{CommonType{Name: name}, 0, 0}
- return a
-}
-
-func (a *arrayType) init(elem gobType, len int) {
- // Set our type id before evaluating the element's, in case it's our own.
- setTypeId(a)
- a.Elem = elem.id()
- a.Len = len
-}
-
-func (a *arrayType) safeString(seen map[typeId]bool) string {
- if seen[a.Id] {
- return a.Name
- }
- seen[a.Id] = true
- return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen))
-}
-
-func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) }
-
-// GobEncoder type (something that implements the GobEncoder interface)
-type gobEncoderType struct {
- CommonType
-}
-
-func newGobEncoderType(name string) *gobEncoderType {
- g := &gobEncoderType{CommonType{Name: name}}
- setTypeId(g)
- return g
-}
-
-func (g *gobEncoderType) safeString(seen map[typeId]bool) string {
- return g.Name
-}
-
-func (g *gobEncoderType) string() string { return g.Name }
-
-// Map type
-type mapType struct {
- CommonType
- Key typeId
- Elem typeId
-}
-
-func newMapType(name string) *mapType {
- m := &mapType{CommonType{Name: name}, 0, 0}
- return m
-}
-
-func (m *mapType) init(key, elem gobType) {
- // Set our type id before evaluating the element's, in case it's our own.
- setTypeId(m)
- m.Key = key.id()
- m.Elem = elem.id()
-}
-
-func (m *mapType) safeString(seen map[typeId]bool) string {
- if seen[m.Id] {
- return m.Name
- }
- seen[m.Id] = true
- key := m.Key.gobType().safeString(seen)
- elem := m.Elem.gobType().safeString(seen)
- return fmt.Sprintf("map[%s]%s", key, elem)
-}
-
-func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) }
-
-// Slice type
-type sliceType struct {
- CommonType
- Elem typeId
-}
-
-func newSliceType(name string) *sliceType {
- s := &sliceType{CommonType{Name: name}, 0}
- return s
-}
-
-func (s *sliceType) init(elem gobType) {
- // Set our type id before evaluating the element's, in case it's our own.
- setTypeId(s)
- s.Elem = elem.id()
-}
-
-func (s *sliceType) safeString(seen map[typeId]bool) string {
- if seen[s.Id] {
- return s.Name
- }
- seen[s.Id] = true
- return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen))
-}
-
-func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool)) }
-
-// Struct type
-type fieldType struct {
- Name string
- Id typeId
-}
-
-type structType struct {
- CommonType
- Field []*fieldType
-}
-
-func (s *structType) safeString(seen map[typeId]bool) string {
- if s == nil {
- return "<nil>"
- }
- if _, ok := seen[s.Id]; ok {
- return s.Name
- }
- seen[s.Id] = true
- str := s.Name + " = struct { "
- for _, f := range s.Field {
- str += fmt.Sprintf("%s %s; ", f.Name, f.Id.gobType().safeString(seen))
- }
- str += "}"
- return str
-}
-
-func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) }
-
-func newStructType(name string) *structType {
- s := &structType{CommonType{Name: name}, nil}
- // For historical reasons we set the id here rather than init.
- // See the comment in newTypeObject for details.
- setTypeId(s)
- return s
-}
-
-// newTypeObject allocates a gobType for the reflection type rt.
-// Unless ut represents a GobEncoder, rt should be the base type
-// of ut.
-// This is only called from the encoding side. The decoding side
-// works through typeIds and userTypeInfos alone.
-func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
- // Does this type implement GobEncoder?
- if ut.isGobEncoder {
- return newGobEncoderType(name), nil
- }
- var err os.Error
- var type0, type1 gobType
- defer func() {
- if err != nil {
- types[rt] = nil, false
- }
- }()
- // Install the top-level type before the subtypes (e.g. struct before
- // fields) so recursive types can be constructed safely.
- switch t := rt.(type) {
- // All basic types are easy: they are predefined.
- case *reflect.BoolType:
- return tBool.gobType(), nil
-
- case *reflect.IntType:
- return tInt.gobType(), nil
-
- case *reflect.UintType:
- return tUint.gobType(), nil
-
- case *reflect.FloatType:
- return tFloat.gobType(), nil
-
- case *reflect.ComplexType:
- return tComplex.gobType(), nil
-
- case *reflect.StringType:
- return tString.gobType(), nil
-
- case *reflect.InterfaceType:
- return tInterface.gobType(), nil
-
- case *reflect.ArrayType:
- at := newArrayType(name)
- types[rt] = at
- type0, err = getBaseType("", t.Elem())
- if err != nil {
- return nil, err
- }
- // Historical aside:
- // For arrays, maps, and slices, we set the type id after the elements
- // are constructed. This is to retain the order of type id allocation after
- // a fix made to handle recursive types, which changed the order in
- // which types are built. Delaying the setting in this way preserves
- // type ids while allowing recursive types to be described. Structs,
- // done below, were already handling recursion correctly so they
- // assign the top-level id before those of the field.
- at.init(type0, t.Len())
- return at, nil
-
- case *reflect.MapType:
- mt := newMapType(name)
- types[rt] = mt
- type0, err = getBaseType("", t.Key())
- if err != nil {
- return nil, err
- }
- type1, err = getBaseType("", t.Elem())
- if err != nil {
- return nil, err
- }
- mt.init(type0, type1)
- return mt, nil
-
- case *reflect.SliceType:
- // []byte == []uint8 is a special case
- if t.Elem().Kind() == reflect.Uint8 {
- return tBytes.gobType(), nil
- }
- st := newSliceType(name)
- types[rt] = st
- type0, err = getBaseType(t.Elem().Name(), t.Elem())
- if err != nil {
- return nil, err
- }
- st.init(type0)
- return st, nil
-
- case *reflect.StructType:
- st := newStructType(name)
- types[rt] = st
- idToType[st.id()] = st
- for i := 0; i < t.NumField(); i++ {
- f := t.Field(i)
- if !isExported(f.Name) {
- continue
- }
- typ := userType(f.Type).base
- tname := typ.Name()
- if tname == "" {
- t := userType(f.Type).base
- tname = t.String()
- }
- gt, err := getBaseType(tname, f.Type)
- if err != nil {
- return nil, err
- }
- st.Field = append(st.Field, &fieldType{f.Name, gt.id()})
- }
- return st, nil
-
- default:
- return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String())
- }
- return nil, nil
-}
-
-// isExported reports whether this is an exported - upper case - name.
-func isExported(name string) bool {
- rune, _ := utf8.DecodeRuneInString(name)
- return unicode.IsUpper(rune)
-}
-
-// getBaseType returns the Gob type describing the given reflect.Type's base type.
-// typeLock must be held.
-func getBaseType(name string, rt reflect.Type) (gobType, os.Error) {
- ut := userType(rt)
- return getType(name, ut, ut.base)
-}
-
-// getType returns the Gob type describing the given reflect.Type.
-// Should be called only when handling GobEncoders/Decoders,
-// which may be pointers. All other types are handled through the
-// base type, never a pointer.
-// typeLock must be held.
-func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
- typ, present := types[rt]
- if present {
- return typ, nil
- }
- typ, err := newTypeObject(name, ut, rt)
- if err == nil {
- types[rt] = typ
- }
- return typ, err
-}
-
-func checkId(want, got typeId) {
- if want != got {
- fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(got), int(want))
- panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())
- }
-}
-
-// used for building the basic types; called only from init(). the incoming
-// interface always refers to a pointer.
-func bootstrapType(name string, e interface{}, expect typeId) typeId {
- rt := reflect.Typeof(e).(*reflect.PtrType).Elem()
- _, present := types[rt]
- if present {
- panic("bootstrap type already present: " + name + ", " + rt.String())
- }
- typ := &CommonType{Name: name}
- types[rt] = typ
- setTypeId(typ)
- checkId(expect, nextId)
- userType(rt) // might as well cache it now
- return nextId
-}
-
-// Representation of the information we send and receive about this type.
-// Each value we send is preceded by its type definition: an encoded int.
-// However, the very first time we send the value, we first send the pair
-// (-id, wireType).
-// For bootstrapping purposes, we assume that the recipient knows how
-// to decode a wireType; it is exactly the wireType struct here, interpreted
-// using the gob rules for sending a structure, except that we assume the
-// ids for wireType and structType etc. are known. The relevant pieces
-// are built in encode.go's init() function.
-// To maintain binary compatibility, if you extend this type, always put
-// the new fields last.
-type wireType struct {
- ArrayT *arrayType
- SliceT *sliceType
- StructT *structType
- MapT *mapType
- GobEncoderT *gobEncoderType
-}
-
-func (w *wireType) string() string {
- const unknown = "unknown type"
- if w == nil {
- return unknown
- }
- switch {
- case w.ArrayT != nil:
- return w.ArrayT.Name
- case w.SliceT != nil:
- return w.SliceT.Name
- case w.StructT != nil:
- return w.StructT.Name
- case w.MapT != nil:
- return w.MapT.Name
- case w.GobEncoderT != nil:
- return w.GobEncoderT.Name
- }
- return unknown
-}
-
-type typeInfo struct {
- id typeId
- encoder *encEngine
- wire *wireType
-}
-
-var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
-
-// typeLock must be held.
-func getTypeInfo(ut *userTypeInfo) (*typeInfo, os.Error) {
- rt := ut.base
- if ut.isGobEncoder {
- // We want the user type, not the base type.
- rt = ut.user
- }
- info, ok := typeInfoMap[rt]
- if ok {
- return info, nil
- }
- info = new(typeInfo)
- gt, err := getBaseType(rt.Name(), rt)
- if err != nil {
- return nil, err
- }
- info.id = gt.id()
-
- if ut.isGobEncoder {
- userType, err := getType(rt.Name(), ut, rt)
- if err != nil {
- return nil, err
- }
- info.wire = &wireType{GobEncoderT: userType.id().gobType().(*gobEncoderType)}
- typeInfoMap[ut.user] = info
- return info, nil
- }
-
- t := info.id.gobType()
- switch typ := rt.(type) {
- case *reflect.ArrayType:
- info.wire = &wireType{ArrayT: t.(*arrayType)}
- case *reflect.MapType:
- info.wire = &wireType{MapT: t.(*mapType)}
- case *reflect.SliceType:
- // []byte == []uint8 is a special case handled separately
- if typ.Elem().Kind() != reflect.Uint8 {
- info.wire = &wireType{SliceT: t.(*sliceType)}
- }
- case *reflect.StructType:
- info.wire = &wireType{StructT: t.(*structType)}
- }
- typeInfoMap[rt] = info
- return info, nil
-}
-
-// Called only when a panic is acceptable and unexpected.
-func mustGetTypeInfo(rt reflect.Type) *typeInfo {
- t, err := getTypeInfo(userType(rt))
- if err != nil {
- panic("getTypeInfo: " + err.String())
- }
- return t
-}
-
-// GobEncoder is the interface describing data that provides its own
-// representation for encoding values for transmission to a GobDecoder.
-// A type that implements GobEncoder and GobDecoder has complete
-// control over the representation of its data and may therefore
-// contain things such as private fields, channels, and functions,
-// which are not usually transmissable in gob streams.
-//
-// Note: Since gobs can be stored permanently, It is good design
-// to guarantee the encoding used by a GobEncoder is stable as the
-// software evolves. For instance, it might make sense for GobEncode
-// to include a version number in the encoding.
-type GobEncoder interface {
- // GobEncode returns a byte slice representing the encoding of the
- // receiver for transmission to a GobDecoder, usually of the same
- // concrete type.
- GobEncode() ([]byte, os.Error)
-}
-
-// GobDecoder is the interface describing data that provides its own
-// routine for decoding transmitted values sent by a GobEncoder.
-type GobDecoder interface {
- // GobDecode overwrites the receiver, which must be a pointer,
- // with the value represented by the byte slice, which was written
- // by GobEncode, usually for the same concrete type.
- GobDecode([]byte) os.Error
-}
-
-var (
- nameToConcreteType = make(map[string]reflect.Type)
- concreteTypeToName = make(map[reflect.Type]string)
-)
-
-// RegisterName is like Register but uses the provided name rather than the
-// type's default.
-func RegisterName(name string, value interface{}) {
- if name == "" {
- // reserved for nil
- panic("attempt to register empty name")
- }
- base := userType(reflect.Typeof(value)).base
- // Check for incompatible duplicates.
- if t, ok := nameToConcreteType[name]; ok && t != base {
- panic("gob: registering duplicate types for " + name)
- }
- if n, ok := concreteTypeToName[base]; ok && n != name {
- panic("gob: registering duplicate names for " + base.String())
- }
- // Store the name and type provided by the user....
- nameToConcreteType[name] = reflect.Typeof(value)
- // but the flattened type in the type table, since that's what decode needs.
- concreteTypeToName[base] = name
-}
-
-// Register records a type, identified by a value for that type, under its
-// internal type name. That name will identify the concrete type of a value
-// sent or received as an interface variable. Only types that will be
-// transferred as implementations of interface values need to be registered.
-// Expecting to be used only during initialization, it panics if the mapping
-// between types and names is not a bijection.
-func Register(value interface{}) {
- // Default to printed representation for unnamed types
- rt := reflect.Typeof(value)
- name := rt.String()
-
- // But for named types (or pointers to them), qualify with import path.
- // Dereference one pointer looking for a named type.
- star := ""
- if rt.Name() == "" {
- if pt, ok := rt.(*reflect.PtrType); ok {
- star = "*"
- rt = pt
- }
- }
- if rt.Name() != "" {
- if rt.PkgPath() == "" {
- name = star + rt.Name()
- } else {
- name = star + rt.PkgPath() + "." + rt.Name()
- }
- }
-
- RegisterName(name, value)
-}
-
-func registerBasics() {
- Register(int(0))
- Register(int8(0))
- Register(int16(0))
- Register(int32(0))
- Register(int64(0))
- Register(uint(0))
- Register(uint8(0))
- Register(uint16(0))
- Register(uint32(0))
- Register(uint64(0))
- Register(float32(0))
- Register(float64(0))
- Register(complex64(0i))
- Register(complex128(0i))
- Register(false)
- Register("")
- Register([]byte(nil))
-}
diff --git a/src/cmd/gofix/testdata/reflect.type.go.out b/src/cmd/gofix/testdata/reflect.type.go.out
deleted file mode 100644
index 9cd78296d..000000000
--- a/src/cmd/gofix/testdata/reflect.type.go.out
+++ /dev/null
@@ -1,789 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gob
-
-import (
- "fmt"
- "os"
- "reflect"
- "sync"
- "unicode"
- "utf8"
-)
-
-// userTypeInfo stores the information associated with a type the user has handed
-// to the package. It's computed once and stored in a map keyed by reflection
-// type.
-type userTypeInfo struct {
- user reflect.Type // the type the user handed us
- base reflect.Type // the base type after all indirections
- indir int // number of indirections to reach the base type
- isGobEncoder bool // does the type implement GobEncoder?
- isGobDecoder bool // does the type implement GobDecoder?
- encIndir int8 // number of indirections to reach the receiver type; may be negative
- decIndir int8 // number of indirections to reach the receiver type; may be negative
-}
-
-var (
- // Protected by an RWMutex because we read it a lot and write
- // it only when we see a new type, typically when compiling.
- userTypeLock sync.RWMutex
- userTypeCache = make(map[reflect.Type]*userTypeInfo)
-)
-
-// validType returns, and saves, the information associated with user-provided type rt.
-// If the user type is not valid, err will be non-nil. To be used when the error handler
-// is not set up.
-func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
- userTypeLock.RLock()
- ut = userTypeCache[rt]
- userTypeLock.RUnlock()
- if ut != nil {
- return
- }
- // Now set the value under the write lock.
- userTypeLock.Lock()
- defer userTypeLock.Unlock()
- if ut = userTypeCache[rt]; ut != nil {
- // Lost the race; not a problem.
- return
- }
- ut = new(userTypeInfo)
- ut.base = rt
- ut.user = rt
- // A type that is just a cycle of pointers (such as type T *T) cannot
- // be represented in gobs, which need some concrete data. We use a
- // cycle detection algorithm from Knuth, Vol 2, Section 3.1, Ex 6,
- // pp 539-540. As we step through indirections, run another type at
- // half speed. If they meet up, there's a cycle.
- slowpoke := ut.base // walks half as fast as ut.base
- for {
- pt := ut.base
- if pt.Kind() != reflect.Ptr {
- break
- }
- ut.base = pt.Elem()
- if ut.base == slowpoke { // ut.base lapped slowpoke
- // recursive pointer type.
- return nil, os.NewError("can't represent recursive pointer type " + ut.base.String())
- }
- if ut.indir%2 == 0 {
- slowpoke = slowpoke.Elem()
- }
- ut.indir++
- }
- ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderCheck)
- ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderCheck)
- userTypeCache[rt] = ut
- return
-}
-
-const (
- gobEncodeMethodName = "GobEncode"
- gobDecodeMethodName = "GobDecode"
-)
-
-// implements returns whether the type implements the interface, as encoded
-// in the check function.
-func implements(typ reflect.Type, check func(typ reflect.Type) bool) bool {
- if typ.NumMethod() == 0 { // avoid allocations etc. unless there's some chance
- return false
- }
- return check(typ)
-}
-
-// gobEncoderCheck makes the type assertion a boolean function.
-func gobEncoderCheck(typ reflect.Type) bool {
- _, ok := reflect.Zero(typ).Interface().(GobEncoder)
- return ok
-}
-
-// gobDecoderCheck makes the type assertion a boolean function.
-func gobDecoderCheck(typ reflect.Type) bool {
- _, ok := reflect.Zero(typ).Interface().(GobDecoder)
- return ok
-}
-
-// implementsInterface reports whether the type implements the
-// interface. (The actual check is done through the provided function.)
-// It also returns the number of indirections required to get to the
-// implementation.
-func implementsInterface(typ reflect.Type, check func(typ reflect.Type) bool) (success bool, indir int8) {
- if typ == nil {
- return
- }
- rt := typ
- // The type might be a pointer and we need to keep
- // dereferencing to the base type until we find an implementation.
- for {
- if implements(rt, check) {
- return true, indir
- }
- if p := rt; p.Kind() == reflect.Ptr {
- indir++
- if indir > 100 { // insane number of indirections
- return false, 0
- }
- rt = p.Elem()
- continue
- }
- break
- }
- // No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
- if typ.Kind() != reflect.Ptr {
- // Not a pointer, but does the pointer work?
- if implements(reflect.PtrTo(typ), check) {
- return true, -1
- }
- }
- return false, 0
-}
-
-// userType returns, and saves, the information associated with user-provided type rt.
-// If the user type is not valid, it calls error.
-func userType(rt reflect.Type) *userTypeInfo {
- ut, err := validUserType(rt)
- if err != nil {
- error(err)
- }
- return ut
-}
-// A typeId represents a gob Type as an integer that can be passed on the wire.
-// Internally, typeIds are used as keys to a map to recover the underlying type info.
-type typeId int32
-
-var nextId typeId // incremented for each new type we build
-var typeLock sync.Mutex // set while building a type
-const firstUserId = 64 // lowest id number granted to user
-
-type gobType interface {
- id() typeId
- setId(id typeId)
- name() string
- string() string // not public; only for debugging
- safeString(seen map[typeId]bool) string
-}
-
-var types = make(map[reflect.Type]gobType)
-var idToType = make(map[typeId]gobType)
-var builtinIdToType map[typeId]gobType // set in init() after builtins are established
-
-func setTypeId(typ gobType) {
- nextId++
- typ.setId(nextId)
- idToType[nextId] = typ
-}
-
-func (t typeId) gobType() gobType {
- if t == 0 {
- return nil
- }
- return idToType[t]
-}
-
-// string returns the string representation of the type associated with the typeId.
-func (t typeId) string() string {
- if t.gobType() == nil {
- return "<nil>"
- }
- return t.gobType().string()
-}
-
-// Name returns the name of the type associated with the typeId.
-func (t typeId) name() string {
- if t.gobType() == nil {
- return "<nil>"
- }
- return t.gobType().name()
-}
-
-// Common elements of all types.
-type CommonType struct {
- Name string
- Id typeId
-}
-
-func (t *CommonType) id() typeId { return t.Id }
-
-func (t *CommonType) setId(id typeId) { t.Id = id }
-
-func (t *CommonType) string() string { return t.Name }
-
-func (t *CommonType) safeString(seen map[typeId]bool) string {
- return t.Name
-}
-
-func (t *CommonType) name() string { return t.Name }
-
-// Create and check predefined types
-// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
-
-var (
- // Primordial types, needed during initialization.
- // Always passed as pointers so the interface{} type
- // goes through without losing its interfaceness.
- tBool = bootstrapType("bool", (*bool)(nil), 1)
- tInt = bootstrapType("int", (*int)(nil), 2)
- tUint = bootstrapType("uint", (*uint)(nil), 3)
- tFloat = bootstrapType("float", (*float64)(nil), 4)
- tBytes = bootstrapType("bytes", (*[]byte)(nil), 5)
- tString = bootstrapType("string", (*string)(nil), 6)
- tComplex = bootstrapType("complex", (*complex128)(nil), 7)
- tInterface = bootstrapType("interface", (*interface{})(nil), 8)
- // Reserve some Ids for compatible expansion
- tReserved7 = bootstrapType("_reserved1", (*struct{ r7 int })(nil), 9)
- tReserved6 = bootstrapType("_reserved1", (*struct{ r6 int })(nil), 10)
- tReserved5 = bootstrapType("_reserved1", (*struct{ r5 int })(nil), 11)
- tReserved4 = bootstrapType("_reserved1", (*struct{ r4 int })(nil), 12)
- tReserved3 = bootstrapType("_reserved1", (*struct{ r3 int })(nil), 13)
- tReserved2 = bootstrapType("_reserved1", (*struct{ r2 int })(nil), 14)
- tReserved1 = bootstrapType("_reserved1", (*struct{ r1 int })(nil), 15)
-)
-
-// Predefined because it's needed by the Decoder
-var tWireType = mustGetTypeInfo(reflect.TypeOf(wireType{})).id
-var wireTypeUserInfo *userTypeInfo // userTypeInfo of (*wireType)
-
-func init() {
- // Some magic numbers to make sure there are no surprises.
- checkId(16, tWireType)
- checkId(17, mustGetTypeInfo(reflect.TypeOf(arrayType{})).id)
- checkId(18, mustGetTypeInfo(reflect.TypeOf(CommonType{})).id)
- checkId(19, mustGetTypeInfo(reflect.TypeOf(sliceType{})).id)
- checkId(20, mustGetTypeInfo(reflect.TypeOf(structType{})).id)
- checkId(21, mustGetTypeInfo(reflect.TypeOf(fieldType{})).id)
- checkId(23, mustGetTypeInfo(reflect.TypeOf(mapType{})).id)
-
- builtinIdToType = make(map[typeId]gobType)
- for k, v := range idToType {
- builtinIdToType[k] = v
- }
-
- // Move the id space upwards to allow for growth in the predefined world
- // without breaking existing files.
- if nextId > firstUserId {
- panic(fmt.Sprintln("nextId too large:", nextId))
- }
- nextId = firstUserId
- registerBasics()
- wireTypeUserInfo = userType(reflect.TypeOf((*wireType)(nil)))
-}
-
-// Array type
-type arrayType struct {
- CommonType
- Elem typeId
- Len int
-}
-
-func newArrayType(name string) *arrayType {
- a := &arrayType{CommonType{Name: name}, 0, 0}
- return a
-}
-
-func (a *arrayType) init(elem gobType, len int) {
- // Set our type id before evaluating the element's, in case it's our own.
- setTypeId(a)
- a.Elem = elem.id()
- a.Len = len
-}
-
-func (a *arrayType) safeString(seen map[typeId]bool) string {
- if seen[a.Id] {
- return a.Name
- }
- seen[a.Id] = true
- return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen))
-}
-
-func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) }
-
-// GobEncoder type (something that implements the GobEncoder interface)
-type gobEncoderType struct {
- CommonType
-}
-
-func newGobEncoderType(name string) *gobEncoderType {
- g := &gobEncoderType{CommonType{Name: name}}
- setTypeId(g)
- return g
-}
-
-func (g *gobEncoderType) safeString(seen map[typeId]bool) string {
- return g.Name
-}
-
-func (g *gobEncoderType) string() string { return g.Name }
-
-// Map type
-type mapType struct {
- CommonType
- Key typeId
- Elem typeId
-}
-
-func newMapType(name string) *mapType {
- m := &mapType{CommonType{Name: name}, 0, 0}
- return m
-}
-
-func (m *mapType) init(key, elem gobType) {
- // Set our type id before evaluating the element's, in case it's our own.
- setTypeId(m)
- m.Key = key.id()
- m.Elem = elem.id()
-}
-
-func (m *mapType) safeString(seen map[typeId]bool) string {
- if seen[m.Id] {
- return m.Name
- }
- seen[m.Id] = true
- key := m.Key.gobType().safeString(seen)
- elem := m.Elem.gobType().safeString(seen)
- return fmt.Sprintf("map[%s]%s", key, elem)
-}
-
-func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) }
-
-// Slice type
-type sliceType struct {
- CommonType
- Elem typeId
-}
-
-func newSliceType(name string) *sliceType {
- s := &sliceType{CommonType{Name: name}, 0}
- return s
-}
-
-func (s *sliceType) init(elem gobType) {
- // Set our type id before evaluating the element's, in case it's our own.
- setTypeId(s)
- s.Elem = elem.id()
-}
-
-func (s *sliceType) safeString(seen map[typeId]bool) string {
- if seen[s.Id] {
- return s.Name
- }
- seen[s.Id] = true
- return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen))
-}
-
-func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool)) }
-
-// Struct type
-type fieldType struct {
- Name string
- Id typeId
-}
-
-type structType struct {
- CommonType
- Field []*fieldType
-}
-
-func (s *structType) safeString(seen map[typeId]bool) string {
- if s == nil {
- return "<nil>"
- }
- if _, ok := seen[s.Id]; ok {
- return s.Name
- }
- seen[s.Id] = true
- str := s.Name + " = struct { "
- for _, f := range s.Field {
- str += fmt.Sprintf("%s %s; ", f.Name, f.Id.gobType().safeString(seen))
- }
- str += "}"
- return str
-}
-
-func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) }
-
-func newStructType(name string) *structType {
- s := &structType{CommonType{Name: name}, nil}
- // For historical reasons we set the id here rather than init.
- // See the comment in newTypeObject for details.
- setTypeId(s)
- return s
-}
-
-// newTypeObject allocates a gobType for the reflection type rt.
-// Unless ut represents a GobEncoder, rt should be the base type
-// of ut.
-// This is only called from the encoding side. The decoding side
-// works through typeIds and userTypeInfos alone.
-func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
- // Does this type implement GobEncoder?
- if ut.isGobEncoder {
- return newGobEncoderType(name), nil
- }
- var err os.Error
- var type0, type1 gobType
- defer func() {
- if err != nil {
- types[rt] = nil, false
- }
- }()
- // Install the top-level type before the subtypes (e.g. struct before
- // fields) so recursive types can be constructed safely.
- switch t := rt; t.Kind() {
- // All basic types are easy: they are predefined.
- case reflect.Bool:
- return tBool.gobType(), nil
-
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return tInt.gobType(), nil
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return tUint.gobType(), nil
-
- case reflect.Float32, reflect.Float64:
- return tFloat.gobType(), nil
-
- case reflect.Complex64, reflect.Complex128:
- return tComplex.gobType(), nil
-
- case reflect.String:
- return tString.gobType(), nil
-
- case reflect.Interface:
- return tInterface.gobType(), nil
-
- case reflect.Array:
- at := newArrayType(name)
- types[rt] = at
- type0, err = getBaseType("", t.Elem())
- if err != nil {
- return nil, err
- }
- // Historical aside:
- // For arrays, maps, and slices, we set the type id after the elements
- // are constructed. This is to retain the order of type id allocation after
- // a fix made to handle recursive types, which changed the order in
- // which types are built. Delaying the setting in this way preserves
- // type ids while allowing recursive types to be described. Structs,
- // done below, were already handling recursion correctly so they
- // assign the top-level id before those of the field.
- at.init(type0, t.Len())
- return at, nil
-
- case reflect.Map:
- mt := newMapType(name)
- types[rt] = mt
- type0, err = getBaseType("", t.Key())
- if err != nil {
- return nil, err
- }
- type1, err = getBaseType("", t.Elem())
- if err != nil {
- return nil, err
- }
- mt.init(type0, type1)
- return mt, nil
-
- case reflect.Slice:
- // []byte == []uint8 is a special case
- if t.Elem().Kind() == reflect.Uint8 {
- return tBytes.gobType(), nil
- }
- st := newSliceType(name)
- types[rt] = st
- type0, err = getBaseType(t.Elem().Name(), t.Elem())
- if err != nil {
- return nil, err
- }
- st.init(type0)
- return st, nil
-
- case reflect.Struct:
- st := newStructType(name)
- types[rt] = st
- idToType[st.id()] = st
- for i := 0; i < t.NumField(); i++ {
- f := t.Field(i)
- if !isExported(f.Name) {
- continue
- }
- typ := userType(f.Type).base
- tname := typ.Name()
- if tname == "" {
- t := userType(f.Type).base
- tname = t.String()
- }
- gt, err := getBaseType(tname, f.Type)
- if err != nil {
- return nil, err
- }
- st.Field = append(st.Field, &fieldType{f.Name, gt.id()})
- }
- return st, nil
-
- default:
- return nil, os.NewError("gob NewTypeObject can't handle type: " + rt.String())
- }
- return nil, nil
-}
-
-// isExported reports whether this is an exported - upper case - name.
-func isExported(name string) bool {
- rune, _ := utf8.DecodeRuneInString(name)
- return unicode.IsUpper(rune)
-}
-
-// getBaseType returns the Gob type describing the given reflect.Type's base type.
-// typeLock must be held.
-func getBaseType(name string, rt reflect.Type) (gobType, os.Error) {
- ut := userType(rt)
- return getType(name, ut, ut.base)
-}
-
-// getType returns the Gob type describing the given reflect.Type.
-// Should be called only when handling GobEncoders/Decoders,
-// which may be pointers. All other types are handled through the
-// base type, never a pointer.
-// typeLock must be held.
-func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
- typ, present := types[rt]
- if present {
- return typ, nil
- }
- typ, err := newTypeObject(name, ut, rt)
- if err == nil {
- types[rt] = typ
- }
- return typ, err
-}
-
-func checkId(want, got typeId) {
- if want != got {
- fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(got), int(want))
- panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())
- }
-}
-
-// used for building the basic types; called only from init(). the incoming
-// interface always refers to a pointer.
-func bootstrapType(name string, e interface{}, expect typeId) typeId {
- rt := reflect.TypeOf(e).Elem()
- _, present := types[rt]
- if present {
- panic("bootstrap type already present: " + name + ", " + rt.String())
- }
- typ := &CommonType{Name: name}
- types[rt] = typ
- setTypeId(typ)
- checkId(expect, nextId)
- userType(rt) // might as well cache it now
- return nextId
-}
-
-// Representation of the information we send and receive about this type.
-// Each value we send is preceded by its type definition: an encoded int.
-// However, the very first time we send the value, we first send the pair
-// (-id, wireType).
-// For bootstrapping purposes, we assume that the recipient knows how
-// to decode a wireType; it is exactly the wireType struct here, interpreted
-// using the gob rules for sending a structure, except that we assume the
-// ids for wireType and structType etc. are known. The relevant pieces
-// are built in encode.go's init() function.
-// To maintain binary compatibility, if you extend this type, always put
-// the new fields last.
-type wireType struct {
- ArrayT *arrayType
- SliceT *sliceType
- StructT *structType
- MapT *mapType
- GobEncoderT *gobEncoderType
-}
-
-func (w *wireType) string() string {
- const unknown = "unknown type"
- if w == nil {
- return unknown
- }
- switch {
- case w.ArrayT != nil:
- return w.ArrayT.Name
- case w.SliceT != nil:
- return w.SliceT.Name
- case w.StructT != nil:
- return w.StructT.Name
- case w.MapT != nil:
- return w.MapT.Name
- case w.GobEncoderT != nil:
- return w.GobEncoderT.Name
- }
- return unknown
-}
-
-type typeInfo struct {
- id typeId
- encoder *encEngine
- wire *wireType
-}
-
-var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
-
-// typeLock must be held.
-func getTypeInfo(ut *userTypeInfo) (*typeInfo, os.Error) {
- rt := ut.base
- if ut.isGobEncoder {
- // We want the user type, not the base type.
- rt = ut.user
- }
- info, ok := typeInfoMap[rt]
- if ok {
- return info, nil
- }
- info = new(typeInfo)
- gt, err := getBaseType(rt.Name(), rt)
- if err != nil {
- return nil, err
- }
- info.id = gt.id()
-
- if ut.isGobEncoder {
- userType, err := getType(rt.Name(), ut, rt)
- if err != nil {
- return nil, err
- }
- info.wire = &wireType{GobEncoderT: userType.id().gobType().(*gobEncoderType)}
- typeInfoMap[ut.user] = info
- return info, nil
- }
-
- t := info.id.gobType()
- switch typ := rt; typ.Kind() {
- case reflect.Array:
- info.wire = &wireType{ArrayT: t.(*arrayType)}
- case reflect.Map:
- info.wire = &wireType{MapT: t.(*mapType)}
- case reflect.Slice:
- // []byte == []uint8 is a special case handled separately
- if typ.Elem().Kind() != reflect.Uint8 {
- info.wire = &wireType{SliceT: t.(*sliceType)}
- }
- case reflect.Struct:
- info.wire = &wireType{StructT: t.(*structType)}
- }
- typeInfoMap[rt] = info
- return info, nil
-}
-
-// Called only when a panic is acceptable and unexpected.
-func mustGetTypeInfo(rt reflect.Type) *typeInfo {
- t, err := getTypeInfo(userType(rt))
- if err != nil {
- panic("getTypeInfo: " + err.String())
- }
- return t
-}
-
-// GobEncoder is the interface describing data that provides its own
-// representation for encoding values for transmission to a GobDecoder.
-// A type that implements GobEncoder and GobDecoder has complete
-// control over the representation of its data and may therefore
-// contain things such as private fields, channels, and functions,
-// which are not usually transmissable in gob streams.
-//
-// Note: Since gobs can be stored permanently, It is good design
-// to guarantee the encoding used by a GobEncoder is stable as the
-// software evolves. For instance, it might make sense for GobEncode
-// to include a version number in the encoding.
-type GobEncoder interface {
- // GobEncode returns a byte slice representing the encoding of the
- // receiver for transmission to a GobDecoder, usually of the same
- // concrete type.
- GobEncode() ([]byte, os.Error)
-}
-
-// GobDecoder is the interface describing data that provides its own
-// routine for decoding transmitted values sent by a GobEncoder.
-type GobDecoder interface {
- // GobDecode overwrites the receiver, which must be a pointer,
- // with the value represented by the byte slice, which was written
- // by GobEncode, usually for the same concrete type.
- GobDecode([]byte) os.Error
-}
-
-var (
- nameToConcreteType = make(map[string]reflect.Type)
- concreteTypeToName = make(map[reflect.Type]string)
-)
-
-// RegisterName is like Register but uses the provided name rather than the
-// type's default.
-func RegisterName(name string, value interface{}) {
- if name == "" {
- // reserved for nil
- panic("attempt to register empty name")
- }
- base := userType(reflect.TypeOf(value)).base
- // Check for incompatible duplicates.
- if t, ok := nameToConcreteType[name]; ok && t != base {
- panic("gob: registering duplicate types for " + name)
- }
- if n, ok := concreteTypeToName[base]; ok && n != name {
- panic("gob: registering duplicate names for " + base.String())
- }
- // Store the name and type provided by the user....
- nameToConcreteType[name] = reflect.TypeOf(value)
- // but the flattened type in the type table, since that's what decode needs.
- concreteTypeToName[base] = name
-}
-
-// Register records a type, identified by a value for that type, under its
-// internal type name. That name will identify the concrete type of a value
-// sent or received as an interface variable. Only types that will be
-// transferred as implementations of interface values need to be registered.
-// Expecting to be used only during initialization, it panics if the mapping
-// between types and names is not a bijection.
-func Register(value interface{}) {
- // Default to printed representation for unnamed types
- rt := reflect.TypeOf(value)
- name := rt.String()
-
- // But for named types (or pointers to them), qualify with import path.
- // Dereference one pointer looking for a named type.
- star := ""
- if rt.Name() == "" {
- if pt := rt; pt.Kind() == reflect.Ptr {
- star = "*"
- rt = pt
- }
- }
- if rt.Name() != "" {
- if rt.PkgPath() == "" {
- name = star + rt.Name()
- } else {
- name = star + rt.PkgPath() + "." + rt.Name()
- }
- }
-
- RegisterName(name, value)
-}
-
-func registerBasics() {
- Register(int(0))
- Register(int8(0))
- Register(int16(0))
- Register(int32(0))
- Register(int64(0))
- Register(uint(0))
- Register(uint8(0))
- Register(uint16(0))
- Register(uint32(0))
- Register(uint64(0))
- Register(float32(0))
- Register(float64(0))
- Register(complex64(0i))
- Register(complex128(0i))
- Register(false)
- Register("")
- Register([]byte(nil))
-}
diff --git a/src/cmd/gofix/typecheck.go b/src/cmd/gofix/typecheck.go
deleted file mode 100644
index 2d81b9710..000000000
--- a/src/cmd/gofix/typecheck.go
+++ /dev/null
@@ -1,584 +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 main
-
-import (
- "fmt"
- "go/ast"
- "go/token"
- "os"
- "reflect"
- "strings"
-)
-
-// Partial type checker.
-//
-// The fact that it is partial is very important: the input is
-// an AST and a description of some type information to
-// assume about one or more packages, but not all the
-// packages that the program imports. The checker is
-// expected to do as much as it can with what it has been
-// given. There is not enough information supplied to do
-// a full type check, but the type checker is expected to
-// apply information that can be derived from variable
-// declarations, function and method returns, and type switches
-// as far as it can, so that the caller can still tell the types
-// of expression relevant to a particular fix.
-//
-// TODO(rsc,gri): Replace with go/typechecker.
-// Doing that could be an interesting test case for go/typechecker:
-// the constraints about working with partial information will
-// likely exercise it in interesting ways. The ideal interface would
-// be to pass typecheck a map from importpath to package API text
-// (Go source code), but for now we use data structures (TypeConfig, Type).
-//
-// The strings mostly use gofmt form.
-//
-// A Field or FieldList has as its type a comma-separated list
-// of the types of the fields. For example, the field list
-// x, y, z int
-// has type "int, int, int".
-
-// The prefix "type " is the type of a type.
-// For example, given
-// var x int
-// type T int
-// x's type is "int" but T's type is "type int".
-// mkType inserts the "type " prefix.
-// getType removes it.
-// isType tests for it.
-
-func mkType(t string) string {
- return "type " + t
-}
-
-func getType(t string) string {
- if !isType(t) {
- return ""
- }
- return t[len("type "):]
-}
-
-func isType(t string) bool {
- return strings.HasPrefix(t, "type ")
-}
-
-// TypeConfig describes the universe of relevant types.
-// For ease of creation, the types are all referred to by string
-// name (e.g., "reflect.Value"). TypeByName is the only place
-// where the strings are resolved.
-
-type TypeConfig struct {
- Type map[string]*Type
- Var map[string]string
- Func map[string]string
-}
-
-// typeof returns the type of the given name, which may be of
-// the form "x" or "p.X".
-func (cfg *TypeConfig) typeof(name string) string {
- if cfg.Var != nil {
- if t := cfg.Var[name]; t != "" {
- return t
- }
- }
- if cfg.Func != nil {
- if t := cfg.Func[name]; t != "" {
- return "func()" + t
- }
- }
- return ""
-}
-
-// Type describes the Fields and Methods of a type.
-// If the field or method cannot be found there, it is next
-// looked for in the Embed list.
-type Type struct {
- Field map[string]string // map field name to type
- Method map[string]string // map method name to comma-separated return types
- Embed []string // list of types this type embeds (for extra methods)
-}
-
-// dot returns the type of "typ.name", making its decision
-// using the type information in cfg.
-func (typ *Type) dot(cfg *TypeConfig, name string) string {
- if typ.Field != nil {
- if t := typ.Field[name]; t != "" {
- return t
- }
- }
- if typ.Method != nil {
- if t := typ.Method[name]; t != "" {
- return t
- }
- }
-
- for _, e := range typ.Embed {
- etyp := cfg.Type[e]
- if etyp != nil {
- if t := etyp.dot(cfg, name); t != "" {
- return t
- }
- }
- }
-
- return ""
-}
-
-// typecheck type checks the AST f assuming the information in cfg.
-// It returns a map from AST nodes to type information in gofmt string form.
-func typecheck(cfg *TypeConfig, f *ast.File) map[interface{}]string {
- typeof := make(map[interface{}]string)
-
- // gather function declarations
- for _, decl := range f.Decls {
- fn, ok := decl.(*ast.FuncDecl)
- if !ok {
- continue
- }
- typecheck1(cfg, fn.Type, typeof)
- t := typeof[fn.Type]
- if fn.Recv != nil {
- // The receiver must be a type.
- rcvr := typeof[fn.Recv]
- if !isType(rcvr) {
- if len(fn.Recv.List) != 1 {
- continue
- }
- rcvr = mkType(gofmt(fn.Recv.List[0].Type))
- typeof[fn.Recv.List[0].Type] = rcvr
- }
- rcvr = getType(rcvr)
- if rcvr != "" && rcvr[0] == '*' {
- rcvr = rcvr[1:]
- }
- typeof[rcvr+"."+fn.Name.Name] = t
- } else {
- if isType(t) {
- t = getType(t)
- } else {
- t = gofmt(fn.Type)
- }
- typeof[fn.Name] = t
-
- // Record typeof[fn.Name.Obj] for future references to fn.Name.
- typeof[fn.Name.Obj] = t
- }
- }
-
- typecheck1(cfg, f, typeof)
- return typeof
-}
-
-func makeExprList(a []*ast.Ident) []ast.Expr {
- var b []ast.Expr
- for _, x := range a {
- b = append(b, x)
- }
- return b
-}
-
-// Typecheck1 is the recursive form of typecheck.
-// It is like typecheck but adds to the information in typeof
-// instead of allocating a new map.
-func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
- // set sets the type of n to typ.
- // If isDecl is true, n is being declared.
- set := func(n ast.Expr, typ string, isDecl bool) {
- if typeof[n] != "" || typ == "" {
- return
- }
- typeof[n] = typ
-
- // If we obtained typ from the declaration of x
- // propagate the type to all the uses.
- // The !isDecl case is a cheat here, but it makes
- // up in some cases for not paying attention to
- // struct fields. The real type checker will be
- // more accurate so we won't need the cheat.
- if id, ok := n.(*ast.Ident); ok && id.Obj != nil && (isDecl || typeof[id.Obj] == "") {
- typeof[id.Obj] = typ
- }
- }
-
- // Type-check an assignment lhs = rhs.
- // If isDecl is true, this is := so we can update
- // the types of the objects that lhs refers to.
- typecheckAssign := func(lhs, rhs []ast.Expr, isDecl bool) {
- if len(lhs) > 1 && len(rhs) == 1 {
- if _, ok := rhs[0].(*ast.CallExpr); ok {
- t := split(typeof[rhs[0]])
- // Lists should have same length but may not; pair what can be paired.
- for i := 0; i < len(lhs) && i < len(t); i++ {
- set(lhs[i], t[i], isDecl)
- }
- return
- }
- }
- if len(lhs) == 1 && len(rhs) == 2 {
- // x = y, ok
- rhs = rhs[:1]
- } else if len(lhs) == 2 && len(rhs) == 1 {
- // x, ok = y
- lhs = lhs[:1]
- }
-
- // Match as much as we can.
- for i := 0; i < len(lhs) && i < len(rhs); i++ {
- x, y := lhs[i], rhs[i]
- if typeof[y] != "" {
- set(x, typeof[y], isDecl)
- } else {
- set(y, typeof[x], false)
- }
- }
- }
-
- // The main type check is a recursive algorithm implemented
- // by walkBeforeAfter(n, before, after).
- // Most of it is bottom-up, but in a few places we need
- // to know the type of the function we are checking.
- // The before function records that information on
- // the curfn stack.
- var curfn []*ast.FuncType
-
- before := func(n interface{}) {
- // push function type on stack
- switch n := n.(type) {
- case *ast.FuncDecl:
- curfn = append(curfn, n.Type)
- case *ast.FuncLit:
- curfn = append(curfn, n.Type)
- }
- }
-
- // After is the real type checker.
- after := func(n interface{}) {
- if n == nil {
- return
- }
- if false && reflect.TypeOf(n).Kind() == reflect.Ptr { // debugging trace
- defer func() {
- if t := typeof[n]; t != "" {
- pos := fset.Position(n.(ast.Node).Pos())
- fmt.Fprintf(os.Stderr, "%s: typeof[%s] = %s\n", pos.String(), gofmt(n), t)
- }
- }()
- }
-
- switch n := n.(type) {
- case *ast.FuncDecl, *ast.FuncLit:
- // pop function type off stack
- curfn = curfn[:len(curfn)-1]
-
- case *ast.FuncType:
- typeof[n] = mkType(joinFunc(split(typeof[n.Params]), split(typeof[n.Results])))
-
- case *ast.FieldList:
- // Field list is concatenation of sub-lists.
- t := ""
- for _, field := range n.List {
- if t != "" {
- t += ", "
- }
- t += typeof[field]
- }
- typeof[n] = t
-
- case *ast.Field:
- // Field is one instance of the type per name.
- all := ""
- t := typeof[n.Type]
- if !isType(t) {
- // Create a type, because it is typically *T or *p.T
- // and we might care about that type.
- t = mkType(gofmt(n.Type))
- typeof[n.Type] = t
- }
- t = getType(t)
- if len(n.Names) == 0 {
- all = t
- } else {
- for _, id := range n.Names {
- if all != "" {
- all += ", "
- }
- all += t
- typeof[id.Obj] = t
- typeof[id] = t
- }
- }
- typeof[n] = all
-
- case *ast.ValueSpec:
- // var declaration. Use type if present.
- if n.Type != nil {
- t := typeof[n.Type]
- if !isType(t) {
- t = mkType(gofmt(n.Type))
- typeof[n.Type] = t
- }
- t = getType(t)
- for _, id := range n.Names {
- set(id, t, true)
- }
- }
- // Now treat same as assignment.
- typecheckAssign(makeExprList(n.Names), n.Values, true)
-
- case *ast.AssignStmt:
- typecheckAssign(n.Lhs, n.Rhs, n.Tok == token.DEFINE)
-
- case *ast.Ident:
- // Identifier can take its type from underlying object.
- if t := typeof[n.Obj]; t != "" {
- typeof[n] = t
- }
-
- case *ast.SelectorExpr:
- // Field or method.
- name := n.Sel.Name
- if t := typeof[n.X]; t != "" {
- if strings.HasPrefix(t, "*") {
- t = t[1:] // implicit *
- }
- if typ := cfg.Type[t]; typ != nil {
- if t := typ.dot(cfg, name); t != "" {
- typeof[n] = t
- return
- }
- }
- tt := typeof[t+"."+name]
- if isType(tt) {
- typeof[n] = getType(tt)
- return
- }
- }
- // Package selector.
- if x, ok := n.X.(*ast.Ident); ok && x.Obj == nil {
- str := x.Name + "." + name
- if cfg.Type[str] != nil {
- typeof[n] = mkType(str)
- return
- }
- if t := cfg.typeof(x.Name + "." + name); t != "" {
- typeof[n] = t
- return
- }
- }
-
- case *ast.CallExpr:
- // make(T) has type T.
- if isTopName(n.Fun, "make") && len(n.Args) >= 1 {
- typeof[n] = gofmt(n.Args[0])
- return
- }
- // new(T) has type *T
- if isTopName(n.Fun, "new") && len(n.Args) == 1 {
- typeof[n] = "*" + gofmt(n.Args[0])
- return
- }
- // Otherwise, use type of function to determine arguments.
- t := typeof[n.Fun]
- in, out := splitFunc(t)
- if in == nil && out == nil {
- return
- }
- typeof[n] = join(out)
- for i, arg := range n.Args {
- if i >= len(in) {
- break
- }
- if typeof[arg] == "" {
- typeof[arg] = in[i]
- }
- }
-
- case *ast.TypeAssertExpr:
- // x.(type) has type of x.
- if n.Type == nil {
- typeof[n] = typeof[n.X]
- return
- }
- // x.(T) has type T.
- if t := typeof[n.Type]; isType(t) {
- typeof[n] = getType(t)
- }
-
- case *ast.SliceExpr:
- // x[i:j] has type of x.
- typeof[n] = typeof[n.X]
-
- case *ast.IndexExpr:
- // x[i] has key type of x's type.
- t := typeof[n.X]
- if strings.HasPrefix(t, "[") || strings.HasPrefix(t, "map[") {
- // Lazy: assume there are no nested [] in the array
- // length or map key type.
- if i := strings.Index(t, "]"); i >= 0 {
- typeof[n] = t[i+1:]
- }
- }
-
- case *ast.StarExpr:
- // *x for x of type *T has type T when x is an expr.
- // We don't use the result when *x is a type, but
- // compute it anyway.
- t := typeof[n.X]
- if isType(t) {
- typeof[n] = "type *" + getType(t)
- } else if strings.HasPrefix(t, "*") {
- typeof[n] = t[len("*"):]
- }
-
- case *ast.UnaryExpr:
- // &x for x of type T has type *T.
- t := typeof[n.X]
- if t != "" && n.Op == token.AND {
- typeof[n] = "&" + t
- }
-
- case *ast.CompositeLit:
- // T{...} has type T.
- typeof[n] = gofmt(n.Type)
-
- case *ast.ParenExpr:
- // (x) has type of x.
- typeof[n] = typeof[n.X]
-
- case *ast.TypeSwitchStmt:
- // Type of variable changes for each case in type switch,
- // but go/parser generates just one variable.
- // Repeat type check for each case with more precise
- // type information.
- as, ok := n.Assign.(*ast.AssignStmt)
- if !ok {
- return
- }
- varx, ok := as.Lhs[0].(*ast.Ident)
- if !ok {
- return
- }
- t := typeof[varx]
- for _, cas := range n.Body.List {
- cas := cas.(*ast.CaseClause)
- if len(cas.List) == 1 {
- // Variable has specific type only when there is
- // exactly one type in the case list.
- if tt := typeof[cas.List[0]]; isType(tt) {
- tt = getType(tt)
- typeof[varx] = tt
- typeof[varx.Obj] = tt
- typecheck1(cfg, cas.Body, typeof)
- }
- }
- }
- // Restore t.
- typeof[varx] = t
- typeof[varx.Obj] = t
-
- case *ast.ReturnStmt:
- if len(curfn) == 0 {
- // Probably can't happen.
- return
- }
- f := curfn[len(curfn)-1]
- res := n.Results
- if f.Results != nil {
- t := split(typeof[f.Results])
- for i := 0; i < len(res) && i < len(t); i++ {
- set(res[i], t[i], false)
- }
- }
- }
- }
- walkBeforeAfter(f, before, after)
-}
-
-// Convert between function type strings and lists of types.
-// Using strings makes this a little harder, but it makes
-// a lot of the rest of the code easier. This will all go away
-// when we can use go/typechecker directly.
-
-// splitFunc splits "func(x,y,z) (a,b,c)" into ["x", "y", "z"] and ["a", "b", "c"].
-func splitFunc(s string) (in, out []string) {
- if !strings.HasPrefix(s, "func(") {
- return nil, nil
- }
-
- i := len("func(") // index of beginning of 'in' arguments
- nparen := 0
- for j := i; j < len(s); j++ {
- switch s[j] {
- case '(':
- nparen++
- case ')':
- nparen--
- if nparen < 0 {
- // found end of parameter list
- out := strings.TrimSpace(s[j+1:])
- if len(out) >= 2 && out[0] == '(' && out[len(out)-1] == ')' {
- out = out[1 : len(out)-1]
- }
- return split(s[i:j]), split(out)
- }
- }
- }
- return nil, nil
-}
-
-// joinFunc is the inverse of splitFunc.
-func joinFunc(in, out []string) string {
- outs := ""
- if len(out) == 1 {
- outs = " " + out[0]
- } else if len(out) > 1 {
- outs = " (" + join(out) + ")"
- }
- return "func(" + join(in) + ")" + outs
-}
-
-// split splits "int, float" into ["int", "float"] and splits "" into [].
-func split(s string) []string {
- out := []string{}
- i := 0 // current type being scanned is s[i:j].
- nparen := 0
- for j := 0; j < len(s); j++ {
- switch s[j] {
- case ' ':
- if i == j {
- i++
- }
- case '(':
- nparen++
- case ')':
- nparen--
- if nparen < 0 {
- // probably can't happen
- return nil
- }
- case ',':
- if nparen == 0 {
- if i < j {
- out = append(out, s[i:j])
- }
- i = j + 1
- }
- }
- }
- if nparen != 0 {
- // probably can't happen
- return nil
- }
- if i < len(s) {
- out = append(out, s[i:])
- }
- return out
-}
-
-// join is the inverse of split.
-func join(x []string) string {
- return strings.Join(x, ", ")
-}
diff --git a/src/cmd/gofmt/Makefile b/src/cmd/gofmt/Makefile
deleted file mode 100644
index dc5b060e6..000000000
--- a/src/cmd/gofmt/Makefile
+++ /dev/null
@@ -1,19 +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 ../../Make.inc
-
-TARG=gofmt
-GOFILES=\
- gofmt.go\
- rewrite.go\
- simplify.go\
-
-include ../../Make.cmd
-
-test: $(TARG)
- ./test.sh
-
-testshort:
- gotest -test.short
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
deleted file mode 100644
index 1373b2657..000000000
--- a/src/cmd/gofmt/doc.go
+++ /dev/null
@@ -1,69 +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.
-
-/*
-Gofmt formats Go programs.
-
-Without an explicit path, it processes the standard input. Given a file,
-it operates on that file; given a directory, it operates on all .go files in
-that directory, recursively. (Files starting with a period are ignored.)
-By default, gofmt prints the reformatted sources to standard output.
-
-Usage:
- gofmt [flags] [path ...]
-
-The flags are:
-
- -d
- Do not print reformatted sources to standard output.
- If a file's formatting is different than gofmt's, print diffs
- to standard output.
- -l
- Do not print reformatted sources to standard output.
- If a file's formatting is different from gofmt's, print its name
- to standard output.
- -r rule
- Apply the rewrite rule to the source before reformatting.
- -s
- Try to simplify code (after applying the rewrite rule, if any).
- -w
- Do not print reformatted sources to standard output.
- If a file's formatting is different from gofmt's, overwrite it
- with gofmt's version.
- -comments=true
- Print comments; if false, all comments are elided from the output.
- -spaces
- Align with spaces instead of tabs.
- -tabindent
- Indent with tabs independent of -spaces.
- -tabwidth=8
- Tab width in spaces.
-
-The rewrite rule specified with the -r flag must be a string of the form:
-
- pattern -> replacement
-
-Both pattern and replacement must be valid Go expressions.
-In the pattern, single-character lowercase identifiers serve as
-wildcards matching arbitrary sub-expressions; those expressions
-will be substituted for the same identifiers in the replacement.
-
-
-Examples
-
-To check files for unnecessary parentheses:
-
- gofmt -r '(a) -> a' -l *.go
-
-To remove the parentheses:
-
- gofmt -r '(a) -> a' -w *.go
-
-To convert the package tree from explicit slice upper bounds to implicit ones:
-
- gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src/pkg
-*/
-package documentation
-
-// BUG(rsc): The implementation of -r is a bit slow.
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
deleted file mode 100644
index ea1c1b00f..000000000
--- a/src/cmd/gofmt/gofmt.go
+++ /dev/null
@@ -1,271 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "bytes"
- "exec"
- "flag"
- "fmt"
- "go/ast"
- "go/parser"
- "go/printer"
- "go/scanner"
- "go/token"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "runtime/pprof"
- "strings"
-)
-
-
-var (
- // main operation modes
- list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
- write = flag.Bool("w", false, "write result to (source) file instead of stdout")
- rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
- simplifyAST = flag.Bool("s", false, "simplify code")
- doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
-
- // layout control
- comments = flag.Bool("comments", true, "print comments")
- tabWidth = flag.Int("tabwidth", 8, "tab width")
- tabIndent = flag.Bool("tabindent", true, "indent with tabs independent of -spaces")
- useSpaces = flag.Bool("spaces", true, "align with spaces instead of tabs")
-
- // debugging
- cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
-)
-
-
-var (
- fset = token.NewFileSet()
- exitCode = 0
- rewrite func(*ast.File) *ast.File
- parserMode uint
- printerMode uint
-)
-
-
-func report(err os.Error) {
- scanner.PrintError(os.Stderr, err)
- exitCode = 2
-}
-
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-
-func initParserMode() {
- parserMode = uint(0)
- if *comments {
- parserMode |= parser.ParseComments
- }
-}
-
-
-func initPrinterMode() {
- printerMode = uint(0)
- if *tabIndent {
- printerMode |= printer.TabIndent
- }
- if *useSpaces {
- printerMode |= printer.UseSpaces
- }
-}
-
-
-func isGoFile(f *os.FileInfo) bool {
- // ignore non-Go files
- return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
-}
-
-
-// If in == nil, the source is the contents of the file with the given filename.
-func processFile(filename string, in io.Reader, out io.Writer) os.Error {
- if in == nil {
- f, err := os.Open(filename)
- if err != nil {
- return err
- }
- defer f.Close()
- in = f
- }
-
- src, err := ioutil.ReadAll(in)
- if err != nil {
- return err
- }
-
- file, err := parser.ParseFile(fset, filename, src, parserMode)
- if err != nil {
- return err
- }
-
- if rewrite != nil {
- file = rewrite(file)
- }
-
- if *simplifyAST {
- simplify(file)
- }
-
- var buf bytes.Buffer
- _, err = (&printer.Config{printerMode, *tabWidth}).Fprint(&buf, fset, file)
- if err != nil {
- return err
- }
- res := buf.Bytes()
-
- if !bytes.Equal(src, res) {
- // formatting has changed
- if *list {
- fmt.Fprintln(out, filename)
- }
- if *write {
- err = ioutil.WriteFile(filename, res, 0)
- if err != nil {
- return err
- }
- }
- if *doDiff {
- data, err := diff(src, res)
- if err != nil {
- return fmt.Errorf("computing diff: %s", err)
- }
- fmt.Printf("diff %s gofmt/%s\n", filename, filename)
- out.Write(data)
- }
- }
-
- if !*list && !*write && !*doDiff {
- _, err = out.Write(res)
- }
-
- return err
-}
-
-
-type fileVisitor chan os.Error
-
-func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
- return true
-}
-
-
-func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
- if isGoFile(f) {
- v <- nil // synchronize error handler
- if err := processFile(path, nil, os.Stdout); err != nil {
- v <- err
- }
- }
-}
-
-
-func walkDir(path string) {
- v := make(fileVisitor)
- go func() {
- filepath.Walk(path, v, v)
- close(v)
- }()
- for err := range v {
- if err != nil {
- report(err)
- }
- }
-}
-
-
-func main() {
- // call gofmtMain in a separate function
- // so that it can use defer and have them
- // run before the exit.
- gofmtMain()
- os.Exit(exitCode)
-}
-
-
-func gofmtMain() {
- flag.Usage = usage
- flag.Parse()
- if *tabWidth < 0 {
- fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", *tabWidth)
- exitCode = 2
- return
- }
-
- if *cpuprofile != "" {
- f, err := os.Create(*cpuprofile)
- if err != nil {
- fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err)
- exitCode = 2
- return
- }
- defer f.Close()
- pprof.StartCPUProfile(f)
- defer pprof.StopCPUProfile()
- }
-
- initParserMode()
- initPrinterMode()
- initRewrite()
-
- if flag.NArg() == 0 {
- if err := processFile("<standard input>", os.Stdin, os.Stdout); err != nil {
- report(err)
- }
- return
- }
-
- for i := 0; i < flag.NArg(); i++ {
- path := flag.Arg(i)
- switch dir, err := os.Stat(path); {
- case err != nil:
- report(err)
- case dir.IsRegular():
- if err := processFile(path, nil, os.Stdout); err != nil {
- report(err)
- }
- case dir.IsDirectory():
- walkDir(path)
- }
- }
-}
-
-
-func diff(b1, b2 []byte) (data []byte, err os.Error) {
- f1, err := ioutil.TempFile("", "gofmt")
- if err != nil {
- return
- }
- defer os.Remove(f1.Name())
- defer f1.Close()
-
- f2, err := ioutil.TempFile("", "gofmt")
- if err != nil {
- return
- }
- defer os.Remove(f2.Name())
- defer f2.Close()
-
- f1.Write(b1)
- f2.Write(b2)
-
- data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
- if len(data) > 0 {
- // diff exits with a non-zero status when the files don't match.
- // Ignore that failure as long as we get output.
- err = nil
- }
- return
-
-}
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
deleted file mode 100644
index 70700554b..000000000
--- a/src/cmd/gofmt/gofmt_test.go
+++ /dev/null
@@ -1,82 +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 main
-
-import (
- "bytes"
- "io/ioutil"
- "path/filepath"
- "strings"
- "testing"
-)
-
-
-func runTest(t *testing.T, dirname, in, out, flags string) {
- in = filepath.Join(dirname, in)
- out = filepath.Join(dirname, out)
-
- // process flags
- *simplifyAST = false
- *rewriteRule = ""
- for _, flag := range strings.Split(flags, " ") {
- elts := strings.SplitN(flag, "=", 2)
- name := elts[0]
- value := ""
- if len(elts) == 2 {
- value = elts[1]
- }
- switch name {
- case "":
- // no flags
- case "-r":
- *rewriteRule = value
- case "-s":
- *simplifyAST = true
- default:
- t.Errorf("unrecognized flag name: %s", name)
- }
- }
-
- initParserMode()
- initPrinterMode()
- initRewrite()
-
- var buf bytes.Buffer
- err := processFile(in, nil, &buf)
- if err != nil {
- t.Error(err)
- return
- }
-
- expected, err := ioutil.ReadFile(out)
- if err != nil {
- t.Error(err)
- return
- }
-
- if got := buf.Bytes(); bytes.Compare(got, expected) != 0 {
- t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
- ioutil.WriteFile(in+".gofmt", got, 0666)
- }
-}
-
-
-// TODO(gri) Add more test cases!
-var tests = []struct {
- dirname, in, out, flags string
-}{
- {".", "gofmt.go", "gofmt.go", ""},
- {".", "gofmt_test.go", "gofmt_test.go", ""},
- {"testdata", "composites.input", "composites.golden", "-s"},
- {"testdata", "rewrite1.input", "rewrite1.golden", "-r=Foo->Bar"},
- {"testdata", "rewrite2.input", "rewrite2.golden", "-r=int->bool"},
-}
-
-
-func TestRewrite(t *testing.T) {
- for _, test := range tests {
- runTest(t, test.dirname, test.in, test.out, test.flags)
- }
-}
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
deleted file mode 100644
index f7f1fe824..000000000
--- a/src/cmd/gofmt/rewrite.go
+++ /dev/null
@@ -1,301 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "os"
- "reflect"
- "strings"
- "unicode"
- "utf8"
-)
-
-
-func initRewrite() {
- if *rewriteRule == "" {
- rewrite = nil // disable any previous rewrite
- return
- }
- f := strings.Split(*rewriteRule, "->")
- if len(f) != 2 {
- fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
- os.Exit(2)
- }
- pattern := parseExpr(f[0], "pattern")
- replace := parseExpr(f[1], "replacement")
- rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
-}
-
-
-// parseExpr parses s as an expression.
-// It might make sense to expand this to allow statement patterns,
-// but there are problems with preserving formatting and also
-// with what a wildcard for a statement looks like.
-func parseExpr(s string, what string) ast.Expr {
- x, err := parser.ParseExpr(fset, "input", s)
- if err != nil {
- fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
- os.Exit(2)
- }
- return x
-}
-
-
-// Keep this function for debugging.
-/*
-func dump(msg string, val reflect.Value) {
- fmt.Printf("%s:\n", msg)
- ast.Print(fset, val.Interface())
- fmt.Println()
-}
-*/
-
-
-// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
-func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
- m := make(map[string]reflect.Value)
- pat := reflect.ValueOf(pattern)
- repl := reflect.ValueOf(replace)
- var f func(val reflect.Value) reflect.Value // f is recursive
- f = func(val reflect.Value) reflect.Value {
- // don't bother if val is invalid to start with
- if !val.IsValid() {
- return reflect.Value{}
- }
- for k := range m {
- m[k] = reflect.Value{}, false
- }
- val = apply(f, val)
- if match(m, pat, val) {
- val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
- }
- return val
- }
- return apply(f, reflect.ValueOf(p)).Interface().(*ast.File)
-}
-
-
-// setValue is a wrapper for x.SetValue(y); it protects
-// the caller from panics if x cannot be changed to y.
-func setValue(x, y reflect.Value) {
- // don't bother if y is invalid to start with
- if !y.IsValid() {
- return
- }
- defer func() {
- if x := recover(); x != nil {
- if s, ok := x.(string); ok && strings.HasPrefix(s, "type mismatch") {
- // x cannot be set to y - ignore this rewrite
- return
- }
- panic(x)
- }
- }()
- x.Set(y)
-}
-
-
-// Values/types for special cases.
-var (
- objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
- scopePtrNil = reflect.ValueOf((*ast.Scope)(nil))
-
- identType = reflect.TypeOf((*ast.Ident)(nil))
- objectPtrType = reflect.TypeOf((*ast.Object)(nil))
- positionType = reflect.TypeOf(token.NoPos)
- scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
-)
-
-
-// apply replaces each AST field x in val with f(x), returning val.
-// To avoid extra conversions, f operates on the reflect.Value form.
-func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
- if !val.IsValid() {
- return reflect.Value{}
- }
-
- // *ast.Objects introduce cycles and are likely incorrect after
- // rewrite; don't follow them but replace with nil instead
- if val.Type() == objectPtrType {
- return objectPtrNil
- }
-
- // similarly for scopes: they are likely incorrect after a rewrite;
- // replace them with nil
- if val.Type() == scopePtrType {
- return scopePtrNil
- }
-
- switch v := reflect.Indirect(val); v.Kind() {
- case reflect.Slice:
- for i := 0; i < v.Len(); i++ {
- e := v.Index(i)
- setValue(e, f(e))
- }
- case reflect.Struct:
- for i := 0; i < v.NumField(); i++ {
- e := v.Field(i)
- setValue(e, f(e))
- }
- case reflect.Interface:
- e := v.Elem()
- setValue(v, f(e))
- }
- return val
-}
-
-
-func isWildcard(s string) bool {
- rune, size := utf8.DecodeRuneInString(s)
- return size == len(s) && unicode.IsLower(rune)
-}
-
-
-// match returns true if pattern matches val,
-// recording wildcard submatches in m.
-// If m == nil, match checks whether pattern == val.
-func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
- // Wildcard matches any expression. If it appears multiple
- // times in the pattern, it must match the same expression
- // each time.
- if m != nil && pattern.IsValid() && pattern.Type() == identType {
- name := pattern.Interface().(*ast.Ident).Name
- if isWildcard(name) && val.IsValid() {
- // wildcards only match expressions
- if _, ok := val.Interface().(ast.Expr); ok {
- if old, ok := m[name]; ok {
- return match(nil, old, val)
- }
- m[name] = val
- return true
- }
- }
- }
-
- // Otherwise, pattern and val must match recursively.
- if !pattern.IsValid() || !val.IsValid() {
- return !pattern.IsValid() && !val.IsValid()
- }
- if pattern.Type() != val.Type() {
- return false
- }
-
- // Special cases.
- switch pattern.Type() {
- case identType:
- // For identifiers, only the names need to match
- // (and none of the other *ast.Object information).
- // This is a common case, handle it all here instead
- // of recursing down any further via reflection.
- p := pattern.Interface().(*ast.Ident)
- v := val.Interface().(*ast.Ident)
- return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
- case objectPtrType, positionType:
- // object pointers and token positions don't need to match
- return true
- }
-
- p := reflect.Indirect(pattern)
- v := reflect.Indirect(val)
- if !p.IsValid() || !v.IsValid() {
- return !p.IsValid() && !v.IsValid()
- }
-
- switch p.Kind() {
- case reflect.Slice:
- if p.Len() != v.Len() {
- return false
- }
- for i := 0; i < p.Len(); i++ {
- if !match(m, p.Index(i), v.Index(i)) {
- return false
- }
- }
- return true
-
- case reflect.Struct:
- if p.NumField() != v.NumField() {
- return false
- }
- for i := 0; i < p.NumField(); i++ {
- if !match(m, p.Field(i), v.Field(i)) {
- return false
- }
- }
- return true
-
- case reflect.Interface:
- return match(m, p.Elem(), v.Elem())
- }
-
- // Handle token integers, etc.
- return p.Interface() == v.Interface()
-}
-
-
-// subst returns a copy of pattern with values from m substituted in place
-// of wildcards and pos used as the position of tokens from the pattern.
-// if m == nil, subst returns a copy of pattern and doesn't change the line
-// number information.
-func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
- if !pattern.IsValid() {
- return reflect.Value{}
- }
-
- // Wildcard gets replaced with map value.
- if m != nil && pattern.Type() == identType {
- name := pattern.Interface().(*ast.Ident).Name
- if isWildcard(name) {
- if old, ok := m[name]; ok {
- return subst(nil, old, reflect.Value{})
- }
- }
- }
-
- if pos.IsValid() && pattern.Type() == positionType {
- // use new position only if old position was valid in the first place
- if old := pattern.Interface().(token.Pos); !old.IsValid() {
- return pattern
- }
- return pos
- }
-
- // Otherwise copy.
- switch p := pattern; p.Kind() {
- case reflect.Slice:
- v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
- for i := 0; i < p.Len(); i++ {
- v.Index(i).Set(subst(m, p.Index(i), pos))
- }
- return v
-
- case reflect.Struct:
- v := reflect.New(p.Type()).Elem()
- for i := 0; i < p.NumField(); i++ {
- v.Field(i).Set(subst(m, p.Field(i), pos))
- }
- return v
-
- case reflect.Ptr:
- v := reflect.New(p.Type()).Elem()
- if elem := p.Elem(); elem.IsValid() {
- v.Set(subst(m, elem, pos).Addr())
- }
- return v
-
- case reflect.Interface:
- v := reflect.New(p.Type()).Elem()
- if elem := p.Elem(); elem.IsValid() {
- v.Set(subst(m, elem, pos))
- }
- return v
- }
-
- return pattern
-}
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go
deleted file mode 100644
index 40a9f8f17..000000000
--- a/src/cmd/gofmt/simplify.go
+++ /dev/null
@@ -1,67 +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.
-
-package main
-
-import (
- "go/ast"
- "reflect"
-)
-
-
-type simplifier struct{}
-
-func (s *simplifier) Visit(node ast.Node) ast.Visitor {
- switch n := node.(type) {
- case *ast.CompositeLit:
- // array, slice, and map composite literals may be simplified
- outer := n
- var eltType ast.Expr
- switch typ := outer.Type.(type) {
- case *ast.ArrayType:
- eltType = typ.Elt
- case *ast.MapType:
- eltType = typ.Value
- }
-
- if eltType != nil {
- typ := reflect.ValueOf(eltType)
- for _, x := range outer.Elts {
- // look at value of indexed/named elements
- if t, ok := x.(*ast.KeyValueExpr); ok {
- x = t.Value
- }
- simplify(x)
- // if the element is a composite literal and its literal type
- // matches the outer literal's element type exactly, the inner
- // literal type may be omitted
- if inner, ok := x.(*ast.CompositeLit); ok {
- if match(nil, typ, reflect.ValueOf(inner.Type)) {
- inner.Type = nil
- }
- }
- }
-
- // node was simplified - stop walk (there are no subnodes to simplify)
- return nil
- }
-
- case *ast.RangeStmt:
- // range of the form: for x, _ = range v {...}
- // can be simplified to: for x = range v {...}
- if n.Value != nil {
- if ident, ok := n.Value.(*ast.Ident); ok && ident.Name == "_" {
- n.Value = nil
- }
- }
- }
-
- return s
-}
-
-
-func simplify(node ast.Node) {
- var s simplifier
- ast.Walk(&s, node)
-}
diff --git a/src/cmd/gofmt/test.sh b/src/cmd/gofmt/test.sh
deleted file mode 100755
index 5dce2ed7a..000000000
--- a/src/cmd/gofmt/test.sh
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-eval $(gomake --no-print-directory -f ../../Make.inc go-env)
-if [ -z "$O" ]; then
- echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
- exit 1
-fi
-
-CMD="./gofmt"
-TMP1=test_tmp1.go
-TMP2=test_tmp2.go
-TMP3=test_tmp3.go
-COUNT=0
-
-count() {
- #echo $1
- let COUNT=$COUNT+1
- let M=$COUNT%10
- if [ $M == 0 ]; then
- echo -n "."
- fi
-}
-
-
-error() {
- echo $1
- exit 1
-}
-
-
-# apply to one file
-apply1() {
- # the following files are skipped because they are test cases
- # for syntax errors and thus won't parse in the first place:
- case `basename "$F"` in
- func3.go | const2.go | char_lit1.go | blank1.go | ddd1.go | \
- bug014.go | bug050.go | bug068.go | bug083.go | bug088.go | \
- bug106.go | bug121.go | bug125.go | bug133.go | bug160.go | \
- bug163.go | bug166.go | bug169.go | bug217.go | bug222.go | \
- bug226.go | bug228.go | bug248.go | bug274.go | bug280.go | \
- bug282.go | bug287.go | bug298.go | bug299.go | bug300.go | \
- bug302.go | bug306.go | bug322.go | bug324.go | bug335.go | \
- bug340.go ) return ;;
- esac
- # the following directories are skipped because they contain test
- # cases for syntax errors and thus won't parse in the first place:
- case `dirname "$F"` in
- $GOROOT/test/syntax ) return ;;
- esac
- #echo $1 $2
- "$1" "$2"; count "$F"
-}
-
-
-# apply to local files
-applydot() {
- for F in `find . -name "*.go" | grep -v "._"`; do
- apply1 "$1" $F
- done
-}
-
-
-# apply to all .go files we can find
-apply() {
- for F in `find "$GOROOT" -name "*.go" | grep -v "._"`; do
- apply1 "$1" $F
- done
-}
-
-
-cleanup() {
- rm -f $TMP1 $TMP2 $TMP3
-}
-
-
-silent() {
- cleanup
- $CMD "$1" > /dev/null 2> $TMP1
- if [ $? != 0 ]; then
- cat $TMP1
- error "Error (silent mode test): test.sh $1"
- fi
-}
-
-
-idempotent() {
- cleanup
- $CMD "$1" > $TMP1
- if [ $? != 0 ]; then
- error "Error (step 1 of idempotency test): test.sh $1"
- fi
-
- $CMD $TMP1 > $TMP2
- if [ $? != 0 ]; then
- error "Error (step 2 of idempotency test): test.sh $1"
- fi
-
- $CMD $TMP2 > $TMP3
- if [ $? != 0 ]; then
- error "Error (step 3 of idempotency test): test.sh $1"
- fi
-
- cmp -s $TMP2 $TMP3
- if [ $? != 0 ]; then
- diff $TMP2 $TMP3
- error "Error (step 4 of idempotency test): test.sh $1"
- fi
-}
-
-
-valid() {
- cleanup
- $CMD "$1" > $TMP1
- if [ $? != 0 ]; then
- error "Error (step 1 of validity test): test.sh $1"
- fi
-
- $GC -o /dev/null $TMP1
- if [ $? != 0 ]; then
- error "Error (step 2 of validity test): test.sh $1"
- fi
-}
-
-
-runtest() {
- #echo "Testing silent mode"
- cleanup
- "$1" silent "$2"
-
- #echo "Testing idempotency"
- cleanup
- "$1" idempotent "$2"
-}
-
-
-runtests() {
- if [ $# = 0 ]; then
- runtest apply
- # verify the pretty-printed files can be compiled with $GC again
- # do it in local directory only because of the prerequisites required
- #echo "Testing validity"
- # Disabled for now due to dependency problems
- # cleanup
- # applydot valid
- else
- for F in "$@"; do
- runtest apply1 "$F"
- done
- fi
-}
-
-
-# run over all .go files
-runtests "$@"
-cleanup
-
-# done
-echo
-echo "PASSED ($COUNT tests)"
diff --git a/src/cmd/gofmt/testdata/composites.golden b/src/cmd/gofmt/testdata/composites.golden
deleted file mode 100644
index 1fd5847c1..000000000
--- a/src/cmd/gofmt/testdata/composites.golden
+++ /dev/null
@@ -1,104 +0,0 @@
-package P
-
-type T struct {
- x, y int
-}
-
-var _ = [42]T{
- {},
- {1, 2},
- {3, 4},
-}
-
-var _ = [...]T{
- {},
- {1, 2},
- {3, 4},
-}
-
-var _ = []T{
- {},
- {1, 2},
- {3, 4},
-}
-
-var _ = []T{
- {},
- 10: {1, 2},
- 20: {3, 4},
-}
-
-var _ = []struct {
- x, y int
-}{
- {},
- 10: {1, 2},
- 20: {3, 4},
-}
-
-var _ = []interface{}{
- T{},
- 10: T{1, 2},
- 20: T{3, 4},
-}
-
-var _ = [][]int{
- {},
- {1, 2},
- {3, 4},
-}
-
-var _ = [][]int{
- ([]int{}),
- ([]int{1, 2}),
- {3, 4},
-}
-
-var _ = [][][]int{
- {},
- {
- {},
- {0, 1, 2, 3},
- {4, 5},
- },
-}
-
-var _ = map[string]T{
- "foo": {},
- "bar": {1, 2},
- "bal": {3, 4},
-}
-
-var _ = map[string]struct {
- x, y int
-}{
- "foo": {},
- "bar": {1, 2},
- "bal": {3, 4},
-}
-
-var _ = map[string]interface{}{
- "foo": T{},
- "bar": T{1, 2},
- "bal": T{3, 4},
-}
-
-var _ = map[string][]int{
- "foo": {},
- "bar": {1, 2},
- "bal": {3, 4},
-}
-
-var _ = map[string][]int{
- "foo": ([]int{}),
- "bar": ([]int{1, 2}),
- "bal": {3, 4},
-}
-
-// from exp/4s/data.go
-var pieces4 = []Piece{
- {0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
- {1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
- {2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
- {3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
-}
diff --git a/src/cmd/gofmt/testdata/composites.input b/src/cmd/gofmt/testdata/composites.input
deleted file mode 100644
index 15afd9e5c..000000000
--- a/src/cmd/gofmt/testdata/composites.input
+++ /dev/null
@@ -1,104 +0,0 @@
-package P
-
-type T struct {
- x, y int
-}
-
-var _ = [42]T{
- T{},
- T{1, 2},
- T{3, 4},
-}
-
-var _ = [...]T{
- T{},
- T{1, 2},
- T{3, 4},
-}
-
-var _ = []T{
- T{},
- T{1, 2},
- T{3, 4},
-}
-
-var _ = []T{
- T{},
- 10: T{1, 2},
- 20: T{3, 4},
-}
-
-var _ = []struct {
- x, y int
-}{
- struct{ x, y int }{},
- 10: struct{ x, y int }{1, 2},
- 20: struct{ x, y int }{3, 4},
-}
-
-var _ = []interface{}{
- T{},
- 10: T{1, 2},
- 20: T{3, 4},
-}
-
-var _ = [][]int{
- []int{},
- []int{1, 2},
- []int{3, 4},
-}
-
-var _ = [][]int{
- ([]int{}),
- ([]int{1, 2}),
- []int{3, 4},
-}
-
-var _ = [][][]int{
- [][]int{},
- [][]int{
- []int{},
- []int{0, 1, 2, 3},
- []int{4, 5},
- },
-}
-
-var _ = map[string]T{
- "foo": T{},
- "bar": T{1, 2},
- "bal": T{3, 4},
-}
-
-var _ = map[string]struct {
- x, y int
-}{
- "foo": struct{ x, y int }{},
- "bar": struct{ x, y int }{1, 2},
- "bal": struct{ x, y int }{3, 4},
-}
-
-var _ = map[string]interface{}{
- "foo": T{},
- "bar": T{1, 2},
- "bal": T{3, 4},
-}
-
-var _ = map[string][]int{
- "foo": []int{},
- "bar": []int{1, 2},
- "bal": []int{3, 4},
-}
-
-var _ = map[string][]int{
- "foo": ([]int{}),
- "bar": ([]int{1, 2}),
- "bal": []int{3, 4},
-}
-
-// from exp/4s/data.go
-var pieces4 = []Piece{
- Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
- Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
-}
diff --git a/src/cmd/gofmt/testdata/rewrite1.golden b/src/cmd/gofmt/testdata/rewrite1.golden
deleted file mode 100644
index d9beb3705..000000000
--- a/src/cmd/gofmt/testdata/rewrite1.golden
+++ /dev/null
@@ -1,12 +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 main
-
-type Bar int
-
-func main() {
- var a Bar
- println(a)
-}
diff --git a/src/cmd/gofmt/testdata/rewrite1.input b/src/cmd/gofmt/testdata/rewrite1.input
deleted file mode 100644
index bdb894320..000000000
--- a/src/cmd/gofmt/testdata/rewrite1.input
+++ /dev/null
@@ -1,12 +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 main
-
-type Foo int
-
-func main() {
- var a Foo
- println(a)
-}
diff --git a/src/cmd/gofmt/testdata/rewrite2.golden b/src/cmd/gofmt/testdata/rewrite2.golden
deleted file mode 100644
index 64c67ffa6..000000000
--- a/src/cmd/gofmt/testdata/rewrite2.golden
+++ /dev/null
@@ -1,10 +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 p
-
-// Slices have nil Len values in the corresponding ast.ArrayType
-// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
-// The rewriter must not crash in that case. Was issue 1696.
-func f() []bool {}
diff --git a/src/cmd/gofmt/testdata/rewrite2.input b/src/cmd/gofmt/testdata/rewrite2.input
deleted file mode 100644
index 21171447a..000000000
--- a/src/cmd/gofmt/testdata/rewrite2.input
+++ /dev/null
@@ -1,10 +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 p
-
-// Slices have nil Len values in the corresponding ast.ArrayType
-// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
-// The rewriter must not crash in that case. Was issue 1696.
-func f() []int {}
diff --git a/src/cmd/goinstall/Makefile b/src/cmd/goinstall/Makefile
deleted file mode 100644
index f61354f39..000000000
--- a/src/cmd/goinstall/Makefile
+++ /dev/null
@@ -1,13 +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 ../../Make.inc
-
-TARG=goinstall
-GOFILES=\
- download.go\
- main.go\
- make.go\
-
-include ../../Make.cmd
diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go
deleted file mode 100644
index a5df7b3bd..000000000
--- a/src/cmd/goinstall/doc.go
+++ /dev/null
@@ -1,191 +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.
-
-/*
-Goinstall is an experiment in automatic package installation.
-It installs packages, possibly downloading them from the internet.
-It maintains a list of public Go packages at
-http://godashboard.appspot.com/package.
-
-Usage:
- goinstall [flags] importpath...
- goinstall [flags] -a
-
-Flags and default settings:
- -a=false install all previously installed packages
- -clean=false clean the package directory before installing
- -dashboard=true tally public packages on godashboard.appspot.com
- -install=true build and install the package and its dependencies
- -log=true log installed packages to $GOROOT/goinstall.log for use by -a
- -nuke=false remove the target object and clean before installing
- -u=false update already-downloaded packages
- -v=false verbose operation
-
-Goinstall installs each of the packages identified on the command line. It
-installs a package's prerequisites before trying to install the package
-itself. Unless -log=false is specified, goinstall logs the import path of each
-installed package to $GOROOT/goinstall.log for use by goinstall -a.
-
-If the -a flag is given, goinstall reinstalls all previously installed
-packages, reading the list from $GOROOT/goinstall.log. After updating to a
-new Go release, which deletes all package binaries, running
-
- goinstall -a
-
-will recompile and reinstall goinstalled packages.
-
-Another common idiom is to use
-
- goinstall -a -u
-
-to update, recompile, and reinstall all goinstalled packages.
-
-The source code for a package with import path foo/bar is expected
-to be in the directory $GOROOT/src/pkg/foo/bar/ or $GOPATH/src/foo/bar/.
-See "The GOPATH Environment Variable" for more about GOPATH.
-
-By default, goinstall prints output only when it encounters an error.
-The -v flag causes goinstall to print information about packages
-being considered and installed.
-
-Goinstall ignores Makefiles.
-
-
-Remote Repositories
-
-If a package import path refers to a remote repository, goinstall will
-download the code if necessary.
-
-Goinstall recognizes packages from a few common code hosting sites:
-
- BitBucket (Mercurial)
-
- import "bitbucket.org/user/project"
- import "bitbucket.org/user/project/sub/directory"
-
- GitHub (Git)
-
- import "github.com/user/project"
- import "github.com/user/project/sub/directory"
-
- Google Code Project Hosting (Mercurial, Subversion)
-
- import "project.googlecode.com/hg"
- import "project.googlecode.com/hg/sub/directory"
-
- import "project.googlecode.com/svn/trunk"
- import "project.googlecode.com/svn/trunk/sub/directory"
-
- Launchpad (Bazaar)
-
- import "launchpad.net/project"
- import "launchpad.net/project/series"
- import "launchpad.net/project/series/sub/directory"
-
- import "launchpad.net/~user/project/branch"
- import "launchpad.net/~user/project/branch/sub/directory"
-
-If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project)
-already exists and contains an appropriate checkout, goinstall will not
-attempt to fetch updates. The -u flag changes this behavior,
-causing goinstall to update all remote packages encountered during
-the installation.
-
-When downloading or updating, goinstall first looks for a tag or branch
-named "release". If there is one, it uses that version of the code.
-Otherwise it uses the default version selected by the version control
-system, typically HEAD for git, tip for Mercurial.
-
-After a successful download and installation of one of these import paths,
-goinstall reports the installation to godashboard.appspot.com, which
-increments a count associated with the package and the time of its most
-recent installation. This mechanism powers the package list at
-http://godashboard.appspot.com/package, allowing Go programmers to learn about
-popular packages that might be worth looking at.
-The -dashboard=false flag disables this reporting.
-
-For code hosted on other servers, goinstall recognizes the general form
-
- repository.vcs/path
-
-as denoting the given repository, with or without the .vcs suffix, using
-the named version control system, and then the path inside that repository.
-The supported version control systems are:
-
- Bazaar .bzr
- Git .git
- Mercurial .hg
- Subversion .svn
-
-For example,
-
- import "example.org/user/foo.hg"
-
-denotes the root directory of the Mercurial repository at example.org/user/foo
-or foo.hg, and
-
- import "example.org/repo.git/foo/bar"
-
-denotes the foo/bar directory of the Git repository at example.com/repo or
-repo.git.
-
-When a version control system supports multiple protocols, goinstall tries each
-in turn.
-For example, for Git it tries git://, then https://, then http://.
-
-
-The GOPATH Environment Variable
-
-GOPATH may be set to a colon-separated list of paths inside which Go code,
-package objects, and executables may be found.
-
-Set a GOPATH to use goinstall to build and install your own code and
-external libraries outside of the Go tree (and to avoid writing Makefiles).
-
-The top-level directory structure of a GOPATH is prescribed:
-
-The 'src' directory is for source code. The directory naming inside 'src'
-determines the package import path or executable name.
-
-The 'pkg' directory is for package objects. Like the Go tree, package objects
-are stored inside a directory named after the target operating system and
-processor architecture ('pkg/$GOOS_$GOARCH').
-A package whose source is located at '$GOPATH/src/foo/bar' would be imported
-as 'foo/bar' and installed as '$GOPATH/pkg/$GOOS_$GOARCH/foo/bar.a'.
-
-The 'bin' directory is for executable files.
-Goinstall installs program binaries using the name of the source folder.
-A binary whose source is at 'src/foo/qux' would be built and installed to
-'$GOPATH/bin/qux'. (Note 'bin/qux', not 'bin/foo/qux' - this is such that
-you can put the bin directory in your PATH.)
-
-Here's an example directory layout:
-
- GOPATH=/home/user/gocode
-
- /home/user/gocode/
- src/foo/
- bar/ (go code in package bar)
- qux/ (go code in package main)
- bin/qux (executable file)
- pkg/linux_amd64/foo/bar.a (object file)
-
-Run 'goinstall foo/bar' to build and install the package 'foo/bar'
-(and its dependencies).
-Goinstall will search each GOPATH (in order) for 'src/foo/bar'.
-If the directory cannot be found, goinstall will attempt to fetch the
-source from a remote repository and write it to the 'src' directory of the
-first GOPATH (or $GOROOT/src/pkg if GOPATH is not set).
-
-Goinstall recognizes relative and absolute paths (paths beginning with / or .).
-The following commands would build our example packages:
-
- goinstall /home/user/gocode/src/foo/bar # build and install foo/bar
- cd /home/user/gocode/src/foo
- goinstall ./bar # build and install foo/bar (again)
- cd qux
- goinstall . # build and install foo/qux
-
-*/
-package documentation
diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go
deleted file mode 100644
index da892a69d..000000000
--- a/src/cmd/goinstall/download.go
+++ /dev/null
@@ -1,306 +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.
-
-// Download remote packages.
-
-package main
-
-import (
- "exec"
- "fmt"
- "http"
- "os"
- "path/filepath"
- "regexp"
- "strings"
-)
-
-const dashboardURL = "http://godashboard.appspot.com/package"
-
-// maybeReportToDashboard reports path to dashboard unless
-// -dashboard=false is on command line. It ignores errors.
-func maybeReportToDashboard(path string) {
- // if -dashboard=false was on command line, do nothing
- if !*reportToDashboard {
- return
- }
-
- // otherwise lob url to dashboard
- r, _ := http.Post(dashboardURL, "application/x-www-form-urlencoded", strings.NewReader("path="+path))
- if r != nil && r.Body != nil {
- r.Body.Close()
- }
-}
-
-// a vcs represents a version control system
-// like Mercurial, Git, or Subversion.
-type vcs struct {
- name string
- cmd string
- metadir string
- checkout string
- clone string
- update string
- updateReleaseFlag string
- pull string
- pullForceFlag string
- log string
- logLimitFlag string
- logReleaseFlag string
- check string
- protocols []string
- suffix string
- defaultHosts []host
-}
-
-type host struct {
- pattern *regexp.Regexp
- protocol string
- suffix string
-}
-
-var hg = vcs{
- name: "Mercurial",
- cmd: "hg",
- metadir: ".hg",
- checkout: "checkout",
- clone: "clone",
- update: "update",
- updateReleaseFlag: "release",
- pull: "pull",
- log: "log",
- logLimitFlag: "-l1",
- logReleaseFlag: "-rrelease",
- check: "identify",
- protocols: []string{"https", "http"},
- suffix: ".hg",
- defaultHosts: []host{
- {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
- {regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ""},
- },
-}
-
-var git = vcs{
- name: "Git",
- cmd: "git",
- metadir: ".git",
- checkout: "checkout",
- clone: "clone",
- update: "pull",
- updateReleaseFlag: "release",
- pull: "fetch",
- log: "show-ref",
- logLimitFlag: "",
- logReleaseFlag: "release",
- check: "ls-remote",
- protocols: []string{"git", "https", "http"},
- suffix: ".git",
- defaultHosts: []host{
- {regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ".git"},
- },
-}
-
-var svn = vcs{
- name: "Subversion",
- cmd: "svn",
- metadir: ".svn",
- checkout: "checkout",
- clone: "checkout",
- update: "update",
- updateReleaseFlag: "release",
- log: "log",
- logLimitFlag: "-l1",
- logReleaseFlag: "release",
- check: "info",
- protocols: []string{"https", "http", "svn"},
- suffix: ".svn",
- defaultHosts: []host{
- {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
- },
-}
-
-var bzr = vcs{
- name: "Bazaar",
- cmd: "bzr",
- metadir: ".bzr",
- checkout: "update",
- clone: "branch",
- update: "update",
- updateReleaseFlag: "-rrelease",
- pull: "pull",
- pullForceFlag: "--overwrite",
- log: "log",
- logLimitFlag: "-l1",
- logReleaseFlag: "-rrelease",
- check: "info",
- protocols: []string{"https", "http", "bzr"},
- suffix: ".bzr",
- defaultHosts: []host{
- {regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https", ""},
- },
-}
-
-var vcsList = []*vcs{&git, &hg, &bzr, &svn}
-
-type vcsMatch struct {
- *vcs
- prefix, repo string
-}
-
-// findHostedRepo checks whether pkg is located at one of
-// the supported code hosting sites and, if so, returns a match.
-func findHostedRepo(pkg string) (*vcsMatch, os.Error) {
- for _, v := range vcsList {
- for _, host := range v.defaultHosts {
- if hm := host.pattern.FindStringSubmatch(pkg); hm != nil {
- if host.suffix != "" && strings.HasSuffix(hm[1], host.suffix) {
- return nil, os.NewError("repository " + pkg + " should not have " + v.suffix + " suffix")
- }
- repo := host.protocol + "://" + hm[1] + host.suffix
- return &vcsMatch{v, hm[1], repo}, nil
- }
- }
- }
- return nil, nil
-}
-
-// findAnyRepo looks for a vcs suffix in pkg (.git, etc) and returns a match.
-func findAnyRepo(pkg string) (*vcsMatch, os.Error) {
- for _, v := range vcsList {
- i := strings.Index(pkg+"/", v.suffix+"/")
- if i < 0 {
- continue
- }
- if !strings.Contains(pkg[:i], "/") {
- continue // don't match vcs suffix in the host name
- }
- if m := v.find(pkg[:i]); m != nil {
- return m, nil
- }
- return nil, fmt.Errorf("couldn't find %s repository", v.name)
- }
- return nil, nil
-}
-
-func (v *vcs) find(pkg string) *vcsMatch {
- for _, proto := range v.protocols {
- for _, suffix := range []string{"", v.suffix} {
- repo := proto + "://" + pkg + suffix
- out, err := exec.Command(v.cmd, v.check, repo).CombinedOutput()
- if err == nil {
- printf("find %s: found %s\n", pkg, repo)
- return &vcsMatch{v, pkg + v.suffix, repo}
- }
- printf("find %s: %s %s %s: %v\n%s\n", pkg, v.cmd, v.check, repo, err, out)
- }
- }
- return nil
-}
-
-// isRemote returns true if the first part of the package name looks like a
-// hostname - i.e. contains at least one '.' and the last part is at least 2
-// characters.
-func isRemote(pkg string) bool {
- parts := strings.SplitN(pkg, "/", 2)
- if len(parts) != 2 {
- return false
- }
- parts = strings.Split(parts[0], ".")
- if len(parts) < 2 || len(parts[len(parts)-1]) < 2 {
- return false
- }
- return true
-}
-
-// download checks out or updates pkg from the remote server.
-func download(pkg, srcDir string) (dashReport bool, err os.Error) {
- if strings.Contains(pkg, "..") {
- err = os.NewError("invalid path (contains ..)")
- return
- }
- m, err := findHostedRepo(pkg)
- if err != nil {
- return
- }
- if m != nil {
- dashReport = true // only report public code hosting sites
- } else {
- m, err = findAnyRepo(pkg)
- if err != nil {
- return
- }
- }
- if m == nil {
- err = os.NewError("cannot download: " + pkg)
- return
- }
- installed, err := m.checkoutRepo(srcDir, m.prefix, m.repo)
- if err != nil {
- return
- }
- if !installed {
- dashReport = false
- }
- return
-}
-
-// Try to detect if a "release" tag exists. If it does, update
-// to the tagged version, otherwise just update the current branch.
-// NOTE(_nil): svn will always fail because it is trying to get
-// the revision history of a file named "release" instead of
-// looking for a commit with a release tag
-func (v *vcs) updateRepo(dst string) os.Error {
- if err := quietRun(dst, nil, v.cmd, v.log, v.logLimitFlag, v.logReleaseFlag); err == nil {
- if err := run(dst, nil, v.cmd, v.checkout, v.updateReleaseFlag); err != nil {
- return err
- }
- } else if err := run(dst, nil, v.cmd, v.update); err != nil {
- return err
- }
- return nil
-}
-
-// checkoutRepo checks out repo into dst using vcs.
-// It tries to check out (or update, if the dst already
-// exists and -u was specified on the command line)
-// the repository at tag/branch "release". If there is no
-// such tag or branch, it falls back to the repository tip.
-func (vcs *vcs) checkoutRepo(srcDir, pkgprefix, repo string) (installed bool, err os.Error) {
- dst := filepath.Join(srcDir, filepath.FromSlash(pkgprefix))
- dir, err := os.Stat(filepath.Join(dst, vcs.metadir))
- if err == nil && !dir.IsDirectory() {
- err = os.NewError("not a directory: " + dst)
- return
- }
- if err != nil {
- parent, _ := filepath.Split(dst)
- if err = os.MkdirAll(parent, 0777); err != nil {
- return
- }
- if err = run(string(filepath.Separator), nil, vcs.cmd, vcs.clone, repo, dst); err != nil {
- return
- }
- if err = vcs.updateRepo(dst); err != nil {
- return
- }
- installed = true
- } else if *update {
- // Retrieve new revisions from the remote branch, if the VCS
- // supports this operation independently (e.g. svn doesn't)
- if vcs.pull != "" {
- if vcs.pullForceFlag != "" {
- if err = run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil {
- return
- }
- } else if err = run(dst, nil, vcs.cmd, vcs.pull); err != nil {
- return
- }
- }
- // Update to release or latest revision
- if err = vcs.updateRepo(dst); err != nil {
- return
- }
- }
- return
-}
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
deleted file mode 100644
index 5cdf0f18e..000000000
--- a/src/cmd/goinstall/main.go
+++ /dev/null
@@ -1,298 +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.
-
-package main
-
-import (
- "bytes"
- "exec"
- "flag"
- "fmt"
- "go/build"
- "go/token"
- "io/ioutil"
- "os"
- "path/filepath"
- "runtime"
- "strings"
-)
-
-func usage() {
- fmt.Fprint(os.Stderr, "usage: goinstall importpath...\n")
- fmt.Fprintf(os.Stderr, "\tgoinstall -a\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-var (
- fset = token.NewFileSet()
- argv0 = os.Args[0]
- errors = false
- parents = make(map[string]string)
- visit = make(map[string]status)
- logfile = filepath.Join(runtime.GOROOT(), "goinstall.log")
- installedPkgs = make(map[string]bool)
-
- allpkg = flag.Bool("a", false, "install all previously installed packages")
- reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL)
- logPkgs = flag.Bool("log", true, "log installed packages to $GOROOT/goinstall.log for use by -a")
- update = flag.Bool("u", false, "update already-downloaded packages")
- doInstall = flag.Bool("install", true, "build and install")
- clean = flag.Bool("clean", false, "clean the package directory before installing")
- nuke = flag.Bool("nuke", false, "clean the package directory and target before installing")
- useMake = flag.Bool("make", true, "use make to build and install")
- verbose = flag.Bool("v", false, "verbose")
-)
-
-type status int // status for visited map
-const (
- unvisited status = iota
- visiting
- done
-)
-
-func logf(format string, args ...interface{}) {
- format = "%s: " + format
- args = append([]interface{}{argv0}, args...)
- fmt.Fprintf(os.Stderr, format, args...)
-}
-
-func printf(format string, args ...interface{}) {
- if *verbose {
- logf(format, args...)
- }
-}
-
-func errorf(format string, args ...interface{}) {
- errors = true
- logf(format, args...)
-}
-
-func main() {
- flag.Usage = usage
- flag.Parse()
- if runtime.GOROOT() == "" {
- fmt.Fprintf(os.Stderr, "%s: no $GOROOT\n", argv0)
- os.Exit(1)
- }
-
- // special case - "unsafe" is already installed
- visit["unsafe"] = done
-
- args := flag.Args()
- if *allpkg || *logPkgs {
- readPackageList()
- }
- if *allpkg {
- if len(args) != 0 {
- usage() // -a and package list both provided
- }
- // install all packages that were ever installed
- if len(installedPkgs) == 0 {
- fmt.Fprintf(os.Stderr, "%s: no installed packages\n", argv0)
- os.Exit(1)
- }
- args = make([]string, len(installedPkgs), len(installedPkgs))
- i := 0
- for pkg := range installedPkgs {
- args[i] = pkg
- i++
- }
- }
- if len(args) == 0 {
- usage()
- }
- for _, path := range args {
- if strings.HasPrefix(path, "http://") {
- errorf("'http://' used in remote path, try '%s'\n", path[7:])
- continue
- }
-
- install(path, "")
- }
- if errors {
- os.Exit(1)
- }
-}
-
-// printDeps prints the dependency path that leads to pkg.
-func printDeps(pkg string) {
- if pkg == "" {
- return
- }
- if visit[pkg] != done {
- printDeps(parents[pkg])
- }
- fmt.Fprintf(os.Stderr, "\t%s ->\n", pkg)
-}
-
-// readPackageList reads the list of installed packages from goinstall.log
-func readPackageList() {
- pkglistdata, _ := ioutil.ReadFile(logfile)
- pkglist := strings.Fields(string(pkglistdata))
- for _, pkg := range pkglist {
- installedPkgs[pkg] = true
- }
-}
-
-// logPackage logs the named package as installed in goinstall.log, if the package is not found in there
-func logPackage(pkg string) {
- if installedPkgs[pkg] {
- return
- }
- fout, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
- if err != nil {
- fmt.Fprintf(os.Stderr, "%s: %s\n", argv0, err)
- return
- }
- fmt.Fprintf(fout, "%s\n", pkg)
- fout.Close()
-}
-
-// install installs the package named by path, which is needed by parent.
-func install(pkg, parent string) {
- // Make sure we're not already trying to install pkg.
- switch visit[pkg] {
- case done:
- return
- case visiting:
- fmt.Fprintf(os.Stderr, "%s: package dependency cycle\n", argv0)
- printDeps(parent)
- fmt.Fprintf(os.Stderr, "\t%s\n", pkg)
- os.Exit(2)
- }
- parents[pkg] = parent
- visit[pkg] = visiting
- defer func() {
- visit[pkg] = done
- }()
-
- // Check whether package is local or remote.
- // If remote, download or update it.
- tree, pkg, err := build.FindTree(pkg)
- // Don't build the standard library.
- if err == nil && tree.Goroot && isStandardPath(pkg) {
- if parent == "" {
- errorf("%s: can not goinstall the standard library\n", pkg)
- } else {
- printf("%s: skipping standard library\n", pkg)
- }
- return
- }
- // Download remote packages if not found or forced with -u flag.
- remote := isRemote(pkg)
- dashReport := false
- if remote && (err == build.ErrNotFound || (err == nil && *update)) {
- printf("%s: download\n", pkg)
- dashReport, err = download(pkg, tree.SrcDir())
- }
- if err != nil {
- errorf("%s: %v\n", pkg, err)
- return
- }
- dir := filepath.Join(tree.SrcDir(), pkg)
-
- // Install prerequisites.
- dirInfo, err := build.ScanDir(dir, parent == "")
- if err != nil {
- errorf("%s: %v\n", pkg, err)
- return
- }
- if len(dirInfo.GoFiles)+len(dirInfo.CgoFiles) == 0 {
- errorf("%s: package has no files\n", pkg)
- return
- }
- for _, p := range dirInfo.Imports {
- if p != "C" {
- install(p, pkg)
- }
- }
- if errors {
- return
- }
-
- // Install this package.
- if *useMake {
- err := domake(dir, pkg, tree, dirInfo.IsCommand())
- if err != nil {
- errorf("%s: install: %v\n", pkg, err)
- return
- }
- } else {
- script, err := build.Build(tree, pkg, dirInfo)
- if err != nil {
- errorf("%s: install: %v\n", pkg, err)
- return
- }
- if *nuke {
- printf("%s: nuke\n", pkg)
- script.Nuke()
- } else if *clean {
- printf("%s: clean\n", pkg)
- script.Clean()
- }
- if *doInstall {
- if script.Stale() {
- printf("%s: install\n", pkg)
- if err := script.Run(); err != nil {
- errorf("%s: install: %v\n", pkg, err)
- return
- }
- } else {
- printf("%s: up-to-date\n", pkg)
- }
- }
- }
- if dashReport {
- maybeReportToDashboard(pkg)
- }
- if remote {
- // mark package as installed in $GOROOT/goinstall.log
- logPackage(pkg)
- }
- return
-}
-
-
-// Is this a standard package path? strings container/vector etc.
-// Assume that if the first element has a dot, it's a domain name
-// and is not the standard package path.
-func isStandardPath(s string) bool {
- dot := strings.Index(s, ".")
- slash := strings.Index(s, "/")
- return dot < 0 || 0 < slash && slash < dot
-}
-
-// run runs the command cmd in directory dir with standard input stdin.
-// If the command fails, run prints the command and output on standard error
-// in addition to returning a non-nil os.Error.
-func run(dir string, stdin []byte, cmd ...string) os.Error {
- return genRun(dir, stdin, cmd, false)
-}
-
-// quietRun is like run but prints nothing on failure unless -v is used.
-func quietRun(dir string, stdin []byte, cmd ...string) os.Error {
- return genRun(dir, stdin, cmd, true)
-}
-
-// genRun implements run and quietRun.
-func genRun(dir string, stdin []byte, arg []string, quiet bool) os.Error {
- cmd := exec.Command(arg[0], arg[1:]...)
- cmd.Stdin = bytes.NewBuffer(stdin)
- cmd.Dir = dir
- printf("%s: %s %s\n", dir, cmd.Path, strings.Join(arg[1:], " "))
- out, err := cmd.CombinedOutput()
- if err != nil {
- if !quiet || *verbose {
- if dir != "" {
- dir = "cd " + dir + "; "
- }
- fmt.Fprintf(os.Stderr, "%s: === %s%s\n", cmd.Path, dir, strings.Join(cmd.Args, " "))
- os.Stderr.Write(out)
- fmt.Fprintf(os.Stderr, "--- %s\n", err)
- }
- return os.NewError("running " + arg[0] + ": " + err.String())
- }
- return nil
-}
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
deleted file mode 100644
index 0fd9b02a8..000000000
--- a/src/cmd/goinstall/make.go
+++ /dev/null
@@ -1,180 +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.
-
-// Run "make install" to build package.
-
-package main
-
-import (
- "bytes"
- "go/build"
- "os"
- "path/filepath"
- "strings"
- "template"
-)
-
-// domake builds the package in dir.
-// domake generates a standard Makefile and passes it
-// to make on standard input.
-func domake(dir, pkg string, tree *build.Tree, isCmd bool) (err os.Error) {
- makefile, err := makeMakefile(dir, pkg, tree, isCmd)
- if err != nil {
- return err
- }
- cmd := []string{"bash", "gomake", "-f-"}
- if *nuke {
- cmd = append(cmd, "nuke")
- } else if *clean {
- cmd = append(cmd, "clean")
- }
- cmd = append(cmd, "install")
- return run(dir, makefile, cmd...)
-}
-
-// makeMakefile computes the standard Makefile for the directory dir
-// installing as package pkg. It includes all *.go files in the directory
-// except those in package main and those ending in _test.go.
-func makeMakefile(dir, pkg string, tree *build.Tree, isCmd bool) ([]byte, os.Error) {
- if !safeName(pkg) {
- return nil, os.NewError("unsafe name: " + pkg)
- }
- targ := pkg
- targDir := tree.PkgDir()
- if isCmd {
- // use the last part of the package name for targ
- _, targ = filepath.Split(pkg)
- targDir = tree.BinDir()
- }
- dirInfo, err := build.ScanDir(dir, isCmd)
- if err != nil {
- return nil, err
- }
-
- cgoFiles := dirInfo.CgoFiles
- isCgo := make(map[string]bool, len(cgoFiles))
- for _, file := range cgoFiles {
- if !safeName(file) {
- return nil, os.NewError("bad name: " + file)
- }
- isCgo[file] = true
- }
-
- goFiles := make([]string, 0, len(dirInfo.GoFiles))
- for _, file := range dirInfo.GoFiles {
- if !safeName(file) {
- return nil, os.NewError("unsafe name: " + file)
- }
- if !isCgo[file] {
- goFiles = append(goFiles, file)
- }
- }
-
- oFiles := make([]string, 0, len(dirInfo.CFiles)+len(dirInfo.SFiles))
- cgoOFiles := make([]string, 0, len(dirInfo.CFiles))
- for _, file := range dirInfo.CFiles {
- if !safeName(file) {
- return nil, os.NewError("unsafe name: " + file)
- }
- // When cgo is in use, C files are compiled with gcc,
- // otherwise they're compiled with gc.
- if len(cgoFiles) > 0 {
- cgoOFiles = append(cgoOFiles, file[:len(file)-2]+".o")
- } else {
- oFiles = append(oFiles, file[:len(file)-2]+".$O")
- }
- }
-
- for _, file := range dirInfo.SFiles {
- if !safeName(file) {
- return nil, os.NewError("unsafe name: " + file)
- }
- oFiles = append(oFiles, file[:len(file)-2]+".$O")
- }
-
- var imports []string
- for _, t := range build.Path {
- imports = append(imports, t.PkgDir())
- }
-
- var buf bytes.Buffer
- md := makedata{targ, targDir, "pkg", goFiles, oFiles, cgoFiles, cgoOFiles, imports}
- if isCmd {
- md.Type = "cmd"
- }
- if err := makefileTemplate.Execute(&buf, &md); err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
-}
-
-var safeBytes = []byte("+-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
-
-func safeName(s string) bool {
- if s == "" {
- return false
- }
- if strings.Contains(s, "..") {
- return false
- }
- for i := 0; i < len(s); i++ {
- if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
- return false
- }
- }
- return true
-}
-
-// makedata is the data type for the makefileTemplate.
-type makedata struct {
- Targ string // build target
- TargDir string // build target directory
- Type string // build type: "pkg" or "cmd"
- GoFiles []string // list of non-cgo .go files
- OFiles []string // list of .$O files
- CgoFiles []string // list of cgo .go files
- CgoOFiles []string // list of cgo .o files, without extension
- Imports []string // gc/ld import paths
-}
-
-var makefileTemplate = template.MustParse(`
-include $(GOROOT)/src/Make.inc
-
-TARG={Targ}
-TARGDIR={TargDir}
-
-{.section GoFiles}
-GOFILES=\
-{.repeated section @}
- {@}\
-{.end}
-
-{.end}
-{.section OFiles}
-OFILES=\
-{.repeated section @}
- {@}\
-{.end}
-
-{.end}
-{.section CgoFiles}
-CGOFILES=\
-{.repeated section @}
- {@}\
-{.end}
-
-{.end}
-{.section CgoOFiles}
-CGO_OFILES=\
-{.repeated section @}
- {@}\
-{.end}
-
-{.end}
-GCIMPORTS={.repeated section Imports}-I "{@}" {.end}
-LDIMPORTS={.repeated section Imports}-L "{@}" {.end}
-
-include $(GOROOT)/src/Make.{Type}
-`,
- nil)
diff --git a/src/cmd/gomake/doc.go b/src/cmd/gomake/doc.go
deleted file mode 100644
index 2f35fd9dd..000000000
--- a/src/cmd/gomake/doc.go
+++ /dev/null
@@ -1,36 +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.
-
-/*
-The gomake command runs GNU make with an appropriate environment
-for using the conventional Go makefiles. If $GOROOT is already
-set in the environment, running gomake is exactly the same
-as running make (or, on BSD systems, running gmake).
-
-Usage: gomake [ target ... ]
-
-Common targets are:
-
- all (default)
- build the package or command, but do not install it.
-
- install
- build and install the package or command
-
- test
- run the tests (packages only)
-
- bench
- run benchmarks (packages only)
-
- clean
- remove object files from the current directory
-
- nuke
- make clean and remove the installed package or command
-
-See http://golang.org/doc/code.html for information about
-writing makefiles.
-*/
-package documentation
diff --git a/src/cmd/gopack/Makefile b/src/cmd/gopack/Makefile
deleted file mode 100644
index 91a8ac2df..000000000
--- a/src/cmd/gopack/Makefile
+++ /dev/null
@@ -1,12 +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 ../../Make.inc
-O:=$(HOST_O)
-
-TARG=gopack
-OFILES=\
- ar.$O\
-
-include ../../Make.ccmd
diff --git a/src/cmd/gopack/ar.c b/src/cmd/gopack/ar.c
deleted file mode 100644
index 0b5e608c7..000000000
--- a/src/cmd/gopack/ar.c
+++ /dev/null
@@ -1,1717 +0,0 @@
-// Inferno utils/iar/ar.c
-// http://code.google.com/p/inferno-os/source/browse/utils/iar/ar.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.
-
-/*
- * ar - portable (ascii) format version
- */
-
-/* protect a couple of our names */
-#define select your_select
-#define rcmd your_rcmd
-
-#include <u.h>
-#include <time.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include "../../libmach/obj.h"
-#include <ar.h>
-
-#undef select
-#undef rcmd
-
-/*
- * The algorithm uses up to 3 temp files. The "pivot member" is the
- * archive member specified by and a, b, or i option. The temp files are
- * astart - contains existing members up to and including the pivot member.
- * amiddle - contains new files moved or inserted behind the pivot.
- * aend - contains the existing members that follow the pivot member.
- * When all members have been processed, function 'install' streams the
- * temp files, in order, back into the archive.
- */
-
-typedef struct Arsymref
-{
- char *name;
- char *file;
- int type;
- int len;
- vlong offset;
- struct Arsymref *next;
-} Arsymref;
-
-typedef struct Armember /* Temp file entry - one per archive member */
-{
- struct Armember *next;
- struct ar_hdr hdr;
- long size;
- long date;
- void *member;
-} Armember;
-
-typedef struct Arfile /* Temp file control block - one per tempfile */
-{
- int paged; /* set when some data paged to disk */
- char *fname; /* paging file name */
- int fd; /* paging file descriptor */
- vlong size;
- Armember *head; /* head of member chain */
- Armember *tail; /* tail of member chain */
- Arsymref *sym; /* head of defined symbol chain */
-} Arfile;
-
-typedef struct Hashchain
-{
- char *name;
- char *file;
- struct Hashchain *next;
-} Hashchain;
-
-#define NHASH 1024
-
-/*
- * macro to portably read/write archive header.
- * 'cmd' is read/write/Bread/Bwrite, etc.
- */
-#define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
- || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
- || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
- || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
- || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
- || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
- || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
-
- /* constants and flags */
-char *man = "mrxtdpq";
-char *opt = "uvnbailogS";
-char artemp[] = "/tmp/vXXXXX";
-char movtemp[] = "/tmp/v1XXXXX";
-char tailtemp[] = "/tmp/v2XXXXX";
-char symdef[] = "__.SYMDEF";
-char pkgdef[] = "__.PKGDEF";
-
-int aflag; /* command line flags */
-int bflag;
-int cflag;
-int gflag;
-int oflag;
-int uflag;
-int vflag;
-int Pflag; /* remove leading file prefix */
-int Sflag; /* force mark Go package as safe */
-
-int errors;
-
-Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */
-int allobj = 1; /* set when all members are object files of the same type */
-int symdefsize; /* size of symdef file */
-char *pkgstmt; /* string "package foo" */
-char *objhdr; /* string "go object darwin 386 release.2010-01-01 2345+" */
-int dupfound; /* flag for duplicate symbol */
-Hashchain *hash[NHASH]; /* hash table of text symbols */
-
-#define ARNAMESIZE sizeof(astart->tail->hdr.name)
-
-char poname[ARNAMESIZE+1]; /* name of pivot member */
-char *file; /* current file or member being worked on */
-Biobuf bout;
-Biobuf bar;
-char *prefix;
-int pkgdefsafe; /* was __.PKGDEF marked safe? */
-
-void arcopy(Biobuf*, Arfile*, Armember*);
-int arcreate(char*);
-void arfree(Arfile*);
-void arinsert(Arfile*, Armember*);
-void *armalloc(int);
-char *arstrdup(char*);
-void armove(Biobuf*, Arfile*, Armember*);
-void arread(Biobuf*, Armember*);
-void arstream(int, Arfile*);
-int arwrite(int, Armember*);
-int bamatch(char*, char*);
-int duplicate(char*, char**);
-Armember *getdir(Biobuf*);
-void getpkgdef(char**, int*);
-int getspace(void);
-void install(char*, Arfile*, Arfile*, Arfile*, int);
-void loadpkgdata(char*, int);
-void longt(Armember*);
-int match(int, char**);
-void mesg(int, char*);
-Arfile *newtempfile(char*);
-Armember *newmember(void);
-void objsym(Sym*, void*);
-int openar(char*, int, int);
-int page(Arfile*);
-void pmode(long);
-void rl(int);
-void scanobj(Biobuf*, Arfile*, long);
-void scanpkg(Biobuf*, long);
-void select(int*, long);
-void setcom(void(*)(char*, int, char**));
-void skip(Biobuf*, vlong);
-void checksafe(Biobuf*, vlong);
-int symcomp(void*, void*);
-void trim(char*, char*, int);
-void usage(void);
-void wrerr(void);
-void wrsym(Biobuf*, long, Arsymref*);
-int arread_cutprefix(Biobuf*, Armember*);
-
-void rcmd(char*, int, char**); /* command processing */
-void dcmd(char*, int, char**);
-void xcmd(char*, int, char**);
-void tcmd(char*, int, char**);
-void pcmd(char*, int, char**);
-void mcmd(char*, int, char**);
-void qcmd(char*, int, char**);
-void (*comfun)(char*, int, char**);
-
-void
-main(int argc, char *argv[])
-{
- char *cp;
-
- Binit(&bout, 1, OWRITE);
- if(argc < 3)
- usage();
- for (cp = argv[1]; *cp; cp++) {
- switch(*cp) {
- case 'a': aflag = 1; break;
- case 'b': bflag = 1; break;
- case 'c': cflag = 1; break;
- case 'd': setcom(dcmd); break;
- case 'g': gflag = 1; break;
- case 'i': bflag = 1; break;
- case 'l':
- strcpy(artemp, "vXXXXX");
- strcpy(movtemp, "v1XXXXX");
- strcpy(tailtemp, "v2XXXXX");
- break;
- case 'm': setcom(mcmd); break;
- case 'o': oflag = 1; break;
- case 'p': setcom(pcmd); break;
- case 'q': setcom(qcmd); break;
- case 'r': setcom(rcmd); break;
- case 't': setcom(tcmd); break;
- case 'u': uflag = 1; break;
- case 'v': vflag = 1; break;
- case 'x': setcom(xcmd); break;
- case 'S': Sflag = 1; break;
- case 'P': Pflag = 1; break;
- default:
- fprint(2, "gopack: bad option `%c'\n", *cp);
- exits("error");
- }
- }
- if (aflag && bflag) {
- fprint(2, "gopack: only one of 'a' and 'b' can be specified\n");
- usage();
- }
- if(aflag || bflag) {
- trim(argv[2], poname, sizeof(poname));
- argv++;
- argc--;
- if(argc < 3)
- usage();
- }
- if(Pflag) {
- if(argc < 4) {
- fprint(2, "gopack: P flag requires prefix argument\n");
- usage();
- }
- prefix = argv[2];
- argv++;
- argc--;
- }
- if(comfun == 0) {
- if(uflag == 0) {
- fprint(2, "gopack: one of [%s] must be specified\n", man);
- usage();
- }
- setcom(rcmd);
- }
- cp = argv[2];
- argc -= 3;
- argv += 3;
- (*comfun)(cp, argc, argv); /* do the command */
- if(errors && cflag)
- remove(cp);
- cp = 0;
- while (argc--) {
- if (*argv) {
- fprint(2, "gopack: %s not found\n", *argv);
- cp = "error";
- }
- argv++;
- }
- if (errors)
- cp = "error";
- exits(cp);
-}
-/*
- * select a command
- */
-void
-setcom(void (*fun)(char *, int, char**))
-{
-
- if(comfun != 0) {
- fprint(2, "gopack: only one of [%s] allowed\n", man);
- usage();
- }
- comfun = fun;
-}
-/*
- * perform the 'r' and 'u' commands
- */
-void
-rcmd(char *arname, int count, char **files)
-{
- int fd;
- int i;
- Arfile *ap;
- Armember *bp;
- Dir *d;
- Biobuf *bfile;
-
- fd = openar(arname, ORDWR, 1);
- if (fd >= 0) {
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- }
- astart = newtempfile(artemp);
- ap = astart;
- aend = 0;
- for(i = 0; fd >= 0; i++) {
- bp = getdir(&bar);
- if (!bp)
- break;
- if (bamatch(file, poname)) { /* check for pivot */
- aend = newtempfile(tailtemp);
- ap = aend;
- }
- /* pitch symdef file */
- if (i == 0 && strcmp(file, symdef) == 0) {
- skip(&bar, bp->size);
- continue;
- }
- /* pitch pkgdef file but remember whether it was marked safe */
- if (gflag && strcmp(file, pkgdef) == 0) {
- checksafe(&bar, bp->size);
- continue;
- }
- /*
- * the plan 9 ar treats count == 0 as equivalent
- * to listing all the archive's files on the command line:
- * it will try to open every file name in the archive
- * and copy that file into the archive if it exists.
- * for go we disable that behavior, because we use
- * r with no files to make changes to the archive itself,
- * using the S or P flags.
- */
- if (!match(count, files)) {
- scanobj(&bar, ap, bp->size);
- arcopy(&bar, ap, bp);
- continue;
- }
- bfile = Bopen(file, OREAD);
- if (!bfile) {
- if (count != 0) {
- fprint(2, "gopack: cannot open %s\n", file);
- errors++;
- }
- scanobj(&bar, ap, bp->size);
- arcopy(&bar, ap, bp);
- continue;
- }
- d = dirfstat(Bfildes(bfile));
- if(d == nil)
- fprint(2, "gopack: cannot stat %s: %r\n", file);
- if (uflag && (d==nil || d->mtime <= bp->date)) {
- scanobj(&bar, ap, bp->size);
- arcopy(&bar, ap, bp);
- Bterm(bfile);
- free(d);
- continue;
- }
- mesg('r', file);
- skip(&bar, bp->size);
- scanobj(bfile, ap, d->length);
- free(d);
- armove(bfile, ap, bp);
- Bterm(bfile);
- }
- if(fd >= 0)
- close(fd);
- /* copy in remaining files named on command line */
- for (i = 0; i < count; i++) {
- file = files[i];
- if(file == 0)
- continue;
- files[i] = 0;
- bfile = Bopen(file, OREAD);
- if (!bfile) {
- fprint(2, "gopack: cannot open %s\n", file);
- errors++;
- } else {
- mesg('a', file);
- d = dirfstat(Bfildes(bfile));
- if (d == nil)
- fprint(2, "can't stat %s\n", file);
- else {
- scanobj(bfile, astart, d->length);
- armove(bfile, astart, newmember());
- free(d);
- }
- Bterm(bfile);
- }
- }
- if(fd < 0 && !cflag)
- install(arname, astart, 0, aend, 1); /* issue 'creating' msg */
- else
- install(arname, astart, 0, aend, 0);
-}
-
-void
-dcmd(char *arname, int count, char **files)
-{
- Armember *bp;
- int fd, i;
-
- if (!count)
- return;
- fd = openar(arname, ORDWR, 0);
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- astart = newtempfile(artemp);
- for (i = 0; bp = getdir(&bar); i++) {
- if(match(count, files)) {
- mesg('d', file);
- skip(&bar, bp->size);
- if (strcmp(file, symdef) == 0)
- allobj = 0;
- } else if (i == 0 && strcmp(file, symdef) == 0) {
- skip(&bar, bp->size);
- } else if (gflag && strcmp(file, pkgdef) == 0) {
- skip(&bar, bp->size);
- } else {
- scanobj(&bar, astart, bp->size);
- arcopy(&bar, astart, bp);
- }
- }
- close(fd);
- install(arname, astart, 0, 0, 0);
-}
-
-void
-xcmd(char *arname, int count, char **files)
-{
- int fd, f, mode, i;
- Armember *bp;
- Dir dx;
-
- fd = openar(arname, OREAD, 0);
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- i = 0;
- while (bp = getdir(&bar)) {
- if(count == 0 || match(count, files)) {
- mode = strtoul(bp->hdr.mode, 0, 8) & 0777;
- f = create(file, OWRITE, mode);
- if(f < 0) {
- fprint(2, "gopack: %s cannot create\n", file);
- skip(&bar, bp->size);
- } else {
- mesg('x', file);
- arcopy(&bar, 0, bp);
- if (write(f, bp->member, bp->size) < 0)
- wrerr();
- if(oflag && bp->date != 0) {
- nulldir(&dx);
- dx.atime = bp->date;
- dx.mtime = bp->date;
- if(dirwstat(file, &dx) < 0)
- perror(file);
- }
- free(bp->member);
- close(f);
- }
- free(bp);
- if (count && ++i >= count)
- break;
- } else {
- skip(&bar, bp->size);
- free(bp);
- }
- }
- close(fd);
-}
-void
-pcmd(char *arname, int count, char **files)
-{
- int fd;
- Armember *bp;
-
- fd = openar(arname, OREAD, 0);
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- while(bp = getdir(&bar)) {
- if(count == 0 || match(count, files)) {
- if(vflag)
- print("\n<%s>\n\n", file);
- arcopy(&bar, 0, bp);
- if (write(1, bp->member, bp->size) < 0)
- wrerr();
- } else
- skip(&bar, bp->size);
- free(bp);
- }
- close(fd);
-}
-void
-mcmd(char *arname, int count, char **files)
-{
- int fd, i;
- Arfile *ap;
- Armember *bp;
-
- if (count == 0)
- return;
- fd = openar(arname, ORDWR, 0);
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- astart = newtempfile(artemp);
- amiddle = newtempfile(movtemp);
- aend = 0;
- ap = astart;
- for (i = 0; bp = getdir(&bar); i++) {
- if (bamatch(file, poname)) {
- aend = newtempfile(tailtemp);
- ap = aend;
- }
- if(match(count, files)) {
- mesg('m', file);
- scanobj(&bar, amiddle, bp->size);
- arcopy(&bar, amiddle, bp);
- } else if (ap == astart && i == 0 && strcmp(file, symdef) == 0) {
- /*
- * pitch the symdef file if it is at the beginning
- * of the archive and we aren't inserting in front
- * of it (ap == astart).
- */
- skip(&bar, bp->size);
- } else if (ap == astart && gflag && strcmp(file, pkgdef) == 0) {
- /*
- * pitch the pkgdef file if we aren't inserting in front
- * of it (ap == astart).
- */
- skip(&bar, bp->size);
- } else {
- scanobj(&bar, ap, bp->size);
- arcopy(&bar, ap, bp);
- }
- }
- close(fd);
- if (poname[0] && aend == 0)
- fprint(2, "gopack: %s not found - files moved to end.\n", poname);
- install(arname, astart, amiddle, aend, 0);
-}
-void
-tcmd(char *arname, int count, char **files)
-{
- int fd;
- Armember *bp;
- char name[ARNAMESIZE+1];
-
- fd = openar(arname, OREAD, 0);
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- while(bp = getdir(&bar)) {
- if(count == 0 || match(count, files)) {
- if(vflag)
- longt(bp);
- trim(file, name, ARNAMESIZE);
- Bprint(&bout, "%s\n", name);
- }
- skip(&bar, bp->size);
- free(bp);
- }
- close(fd);
-}
-void
-qcmd(char *arname, int count, char **files)
-{
- int fd, i;
- Armember *bp;
- Biobuf *bfile;
-
- if(aflag || bflag) {
- fprint(2, "gopack: abi not allowed with q\n");
- exits("error");
- }
- fd = openar(arname, ORDWR, 1);
- if (fd < 0) {
- if(!cflag)
- fprint(2, "gopack: creating %s\n", arname);
- fd = arcreate(arname);
- }
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- /* leave note group behind when writing archive; i.e. sidestep interrupts */
- rfork(RFNOTEG);
- Bseek(&bar, 0, 2);
- bp = newmember();
- for(i=0; i<count && files[i]; i++) {
- file = files[i];
- files[i] = 0;
- bfile = Bopen(file, OREAD);
- if(!bfile) {
- fprint(2, "gopack: cannot open %s\n", file);
- errors++;
- } else {
- mesg('q', file);
- armove(bfile, 0, bp);
- if (!arwrite(fd, bp))
- wrerr();
- free(bp->member);
- bp->member = 0;
- Bterm(bfile);
- }
- }
- free(bp);
- close(fd);
-}
-
-/*
- * extract the symbol references from an object file
- */
-void
-scanobj(Biobuf *b, Arfile *ap, long size)
-{
- int obj;
- vlong offset, offset1;
- Dir *d;
- static int lastobj = -1;
- uchar buf[4];
- char *p;
-
- if (!allobj) /* non-object file encountered */
- return;
- offset = Boffset(b);
- obj = objtype(b, 0);
- if (obj < 0) { /* not an object file */
- /* maybe a foreign object file */
- Bseek(b, offset, 0);
- memset(buf, 0, sizeof buf);
- Bread(b, buf, 4);
-
- /* maybe a foreign object file? that's okay */
- if((buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' && buf[3] == 'F') || // ELF
- (buf[0] == 0x4c && buf[1] == 0x01 || buf[0] == 0x64 && buf[1] == 0x86) || // Windows PE
- (buf[0] == 0xFE && buf[1] == 0xED && buf[2] == 0xFA && (buf[3]&~1) == 0xCE) || // Mach-O big-endian
- (buf[3] == 0xFE && buf[2] == 0xED && buf[1] == 0xFA && (buf[0]&~1) == 0xCE)) { // Mach-O little-endian
- Bseek(b, offset, 0);
- return;
- }
-
- if (!gflag || strcmp(file, pkgdef) != 0) { /* don't clear allobj if it's pkg defs */
- fprint(2, "gopack: non-object file %s\n", file);
- errors++;
- allobj = 0;
- }
- d = dirfstat(Bfildes(b));
- if (d != nil && d->length == 0) {
- fprint(2, "gopack: zero length file %s\n", file);
- errors++;
- }
- free(d);
- Bseek(b, offset, 0);
- return;
- }
-
- offset1 = Boffset(b);
- Bseek(b, offset, 0);
- p = Brdstr(b, '\n', 1);
- Bseek(b, offset1, 0);
- if(p == nil || strncmp(p, "go object ", 10) != 0) {
- fprint(2, "gopack: malformed object file %s\n", file);
- errors++;
- Bseek(b, offset, 0);
- free(p);
- return;
- }
-
- if ((lastobj >= 0 && obj != lastobj) || (objhdr != nil && strcmp(p, objhdr) != 0)) {
- fprint(2, "gopack: inconsistent object file %s\n", file);
- errors++;
- allobj = 0;
- free(p);
- return;
- }
- lastobj = obj;
- if(objhdr == nil)
- objhdr = p;
- else
- free(p);
-
- if (!readar(b, obj, offset+size, 0)) {
- fprint(2, "gopack: invalid symbol reference in file %s\n", file);
- errors++;
- allobj = 0;
- Bseek(b, offset, 0);
- return;
- }
- Bseek(b, offset, 0);
- objtraverse(objsym, ap);
- if (gflag) {
- scanpkg(b, size);
- Bseek(b, offset, 0);
- }
-}
-
-/*
- * does line contain substring (length-limited)
- */
-int
-strstrn(char *line, int len, char *sub)
-{
- int i;
- int sublen;
-
- sublen = strlen(sub);
- for (i = 0; i < len - sublen; i++)
- if (memcmp(line+i, sub, sublen) == 0)
- return 1;
- return 0;
-}
-
-/*
- * package import data
- */
-int safe = 1;
-char* pkgname;
-char* importblock;
-
-void
-getpkgdef(char **datap, int *lenp)
-{
- char *tag, *hdr;
-
- if(pkgname == nil) {
- pkgname = "__emptyarchive__";
- importblock = "";
- }
-
- tag = "";
- if(safe || Sflag)
- tag = "safe";
-
- hdr = "empty archive";
- if(objhdr != nil)
- hdr = objhdr;
-
- *datap = smprint("%s\nimport\n$$\npackage %s %s\n%s\n$$\n", hdr, pkgname, tag, importblock);
- *lenp = strlen(*datap);
-}
-
-/*
- * extract the package definition data from an object file.
- * there can be only one.
- */
-void
-scanpkg(Biobuf *b, long size)
-{
- long n;
- int c;
- long start, end, pkgsize;
- char *data, *line, pkgbuf[1024], *pkg;
- int first;
-
- /*
- * scan until $$
- */
- for (n=0; n<size; ) {
- c = Bgetc(b);
- if(c == Beof)
- break;
- n++;
- if(c != '$')
- continue;
- c = Bgetc(b);
- if(c == Beof)
- break;
- n++;
- if(c != '$')
- continue;
- goto foundstart;
- }
- // fprint(2, "gopack: warning: no package import section in %s\n", file);
- if(b != &bar || !pkgdefsafe)
- safe = 0; // non-Go file (C or assembly)
- return;
-
-foundstart:
- /* found $$; skip rest of line */
- while((c = Bgetc(b)) != '\n')
- if(c == Beof)
- goto bad;
-
- /* how big is it? */
- pkg = nil;
- first = 1;
- start = end = 0;
- for (n=0; n<size; n+=Blinelen(b)) {
- line = Brdstr(b, '\n', 0);
- if (line == nil)
- goto bad;
- if (first && strstrn(line, Blinelen(b), "package ")) {
- if (Blinelen(b) > sizeof(pkgbuf)-1)
- goto bad;
- memmove(pkgbuf, line, Blinelen(b));
- pkgbuf[Blinelen(b)] = '\0';
- pkg = pkgbuf;
- while(*pkg == ' ' || *pkg == '\t')
- pkg++;
- if(strncmp(pkg, "package ", 8) != 0)
- goto bad;
- pkg += 8;
- data = pkg;
- while(*pkg != ' ' && *pkg != '\n' && *pkg != '\0')
- pkg++;
- pkgname = armalloc(pkg - data + 1);
- memmove(pkgname, data, pkg - data);
- pkgname[pkg-data] = '\0';
- if(strcmp(pkg, " safe\n") != 0 && (b != &bar || !pkgdefsafe))
- safe = 0;
- start = Boffset(b); // after package statement
- first = 0;
- free(line);
- continue;
- }
- if(line[0] == '$' && line[1] == '$') {
- free(line);
- goto foundend;
- }
- end = Boffset(b); // before closing $$
- free(line);
- }
-bad:
- fprint(2, "gopack: bad package import section in %s\n", file);
- errors++;
- return;
-
-foundend:
- if (start == 0)
- return;
- if (end == 0)
- goto bad;
- if(importblock != nil) {
- fprint(2, "gopack: multiple Go object files\n");
- errors++;
- return;
- }
- pkgsize = end-start;
- data = armalloc(end - start + 1);
- Bseek(b, start, 0);
- if (Bread(b, data, pkgsize) != pkgsize) {
- fprint(2, "gopack: error reading package import section in %s\n", file);
- errors++;
- return;
- }
- data[end-start] = '\0';
- importblock = data;
-}
-
-/*
- * add text and data symbols to the symbol list
- */
-void
-objsym(Sym *s, void *p)
-{
- int n;
- Arsymref *as;
- Arfile *ap;
- char *ofile;
-
- if (s->type != 'T' && s->type != 'D')
- return;
- ap = (Arfile*)p;
- as = armalloc(sizeof(Arsymref));
- as->offset = ap->size;
- as->name = arstrdup(s->name);
- as->file = arstrdup(file);
- if(s->type == 'T' && duplicate(as->name, &ofile)) {
- dupfound = 1;
- fprint(2, "duplicate text symbol: %s and %s: %s\n", as->file, ofile, as->name);
- errors++;
- free(as->name);
- free(as);
- return;
- }
- as->type = s->type;
- n = strlen(s->name);
- symdefsize += 4+(n+1)+1;
- as->len = n;
- as->next = ap->sym;
- ap->sym = as;
-}
-
-/*
- * Check the symbol table for duplicate text symbols
- */
-int
-hashstr(char *name)
-{
- int h;
- char *cp;
-
- h = 0;
- for(cp = name; *cp; h += *cp++)
- h *= 1119;
-
- // the code used to say
- // if(h < 0)
- // h = ~h;
- // but on gcc 4.3 with -O2 on some systems,
- // the if(h < 0) gets compiled away as not possible.
- // use a mask instead, leaving plenty of bits but
- // definitely not the sign bit.
-
- return h & 0xfffffff;
-}
-
-int
-duplicate(char *name, char **ofile)
-{
- Hashchain *p;
- int h;
-
- h = hashstr(name) % NHASH;
-
- for(p = hash[h]; p; p = p->next)
- if(strcmp(p->name, name) == 0) {
- *ofile = p->file;
- return 1;
- }
- p = armalloc(sizeof(Hashchain));
- p->next = hash[h];
- p->name = name;
- p->file = file;
- hash[h] = p;
- *ofile = nil;
- return 0;
-}
-
-/*
- * open an archive and validate its header
- */
-int
-openar(char *arname, int mode, int errok)
-{
- int fd;
- char mbuf[SARMAG];
-
- fd = open(arname, mode);
- if(fd >= 0){
- if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
- fprint(2, "gopack: %s not in archive format\n", arname);
- exits("error");
- }
- }else if(!errok){
- fprint(2, "gopack: cannot open %s: %r\n", arname);
- exits("error");
- }
- return fd;
-}
-
-/*
- * create an archive and set its header
- */
-int
-arcreate(char *arname)
-{
- int fd;
-
- fd = create(arname, OWRITE, 0664);
- if(fd < 0){
- fprint(2, "gopack: cannot create %s: %r\n", arname);
- exits("error");
- }
- if(write(fd, ARMAG, SARMAG) != SARMAG)
- wrerr();
- return fd;
-}
-
-/*
- * error handling
- */
-void
-wrerr(void)
-{
- perror("gopack: write error");
- exits("error");
-}
-
-void
-rderr(void)
-{
- perror("gopack: read error");
- exits("error");
-}
-
-void
-phaseerr(int offset)
-{
- fprint(2, "gopack: phase error at offset %d\n", offset);
- exits("error");
-}
-
-void
-usage(void)
-{
- fprint(2, "usage: gopack [%s][%s][P prefix] archive files ...\n", opt, man);
- exits("error");
-}
-
-/*
- * read the header for the next archive member
- */
-Armember *
-getdir(Biobuf *b)
-{
- Armember *bp;
- char *cp;
- static char name[ARNAMESIZE+1];
-
- bp = newmember();
- if(HEADER_IO(Bread, b, bp->hdr)) {
- free(bp);
- return 0;
- }
- if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag)))
- phaseerr(Boffset(b));
- strncpy(name, bp->hdr.name, sizeof(bp->hdr.name));
- cp = name+sizeof(name)-1;
- while(*--cp==' ')
- ;
- cp[1] = '\0';
- file = arstrdup(name);
- bp->date = strtol(bp->hdr.date, 0, 0);
- bp->size = strtol(bp->hdr.size, 0, 0);
- return bp;
-}
-
-/*
- * Copy the file referenced by fd to the temp file
- */
-void
-armove(Biobuf *b, Arfile *ap, Armember *bp)
-{
- char *cp;
- Dir *d;
- vlong n;
-
- d = dirfstat(Bfildes(b));
- if (d == nil) {
- fprint(2, "gopack: cannot stat %s\n", file);
- return;
- }
-
- trim(file, bp->hdr.name, sizeof(bp->hdr.name));
- for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */
- cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
- *cp = ' ';
- sprint(bp->hdr.date, "%-12ld", 0); // was d->mtime but removed for idempotent builds
- sprint(bp->hdr.uid, "%-6d", 0);
- sprint(bp->hdr.gid, "%-6d", 0);
- sprint(bp->hdr.mode, "%-8lo", d->mode);
- sprint(bp->hdr.size, "%-10lld", d->length);
- strncpy(bp->hdr.fmag, ARFMAG, 2);
- bp->size = d->length;
- arread(b, bp);
- n = bp->size;
- if (n&1)
- n++;
- if (ap) {
- arinsert(ap, bp);
- ap->size += n+SAR_HDR;
- }
- free(d);
-}
-
-/*
- * Copy the archive member at the current offset into the temp file.
- */
-void
-arcopy(Biobuf *b, Arfile *ap, Armember *bp)
-{
- long n;
-
- arread(b, bp);
- n = bp->size;
- if (n & 01)
- n++;
- if (ap) {
- arinsert(ap, bp);
- ap->size += n+SAR_HDR;
- }
-}
-
-/*
- * Skip an archive member
- */
-void
-skip(Biobuf *bp, vlong len)
-{
- if (len & 01)
- len++;
- Bseek(bp, len, 1);
-}
-
-void
-checksafe(Biobuf *bp, vlong len)
-{
- char *p;
- vlong end;
-
- if (len & 01)
- len++;
- end = Boffset(bp) + len;
-
- p = Brdline(bp, '\n');
- if(p == nil || strncmp(p, "go object ", 10) != 0)
- goto done;
- for(;;) {
- p = Brdline(bp, '\n');
- if(p == nil || Boffset(bp) >= end)
- goto done;
- if(strncmp(p, "$$\n", 3) == 0)
- break;
- }
- p = Brdline(bp, '\n');
- if(p == nil || Boffset(bp) > end)
- goto done;
- if(Blinelen(bp) > 8+6 && strncmp(p, "package ", 8) == 0 && strncmp(p+Blinelen(bp)-6, " safe\n", 6) == 0)
- pkgdefsafe = 1;
-
-done:
- Bseek(bp, end, 0);
-}
-
-/*
- * Stream the three temp files to an archive
- */
-void
-install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag)
-{
- int fd;
-
- if(allobj && dupfound) {
- fprint(2, "%s not changed\n", arname);
- return;
- }
- /* leave note group behind when copying back; i.e. sidestep interrupts */
- rfork(RFNOTEG);
-
- if(createflag)
- fprint(2, "gopack: creating %s\n", arname);
- fd = arcreate(arname);
-
- if(allobj)
- rl(fd);
-
- if (astart) {
- arstream(fd, astart);
- arfree(astart);
- }
- if (amiddle) {
- arstream(fd, amiddle);
- arfree(amiddle);
- }
- if (aend) {
- arstream(fd, aend);
- arfree(aend);
- }
- close(fd);
-}
-
-void
-rl(int fd)
-{
- Biobuf b;
- char *cp;
- struct ar_hdr a;
- long len;
- int headlen;
- char *pkgdefdata;
- int pkgdefsize;
-
- pkgdefdata = nil;
- pkgdefsize = 0;
-
- Binit(&b, fd, OWRITE);
- Bseek(&b,seek(fd,0,1), 0);
-
- len = symdefsize;
- if(len&01)
- len++;
- sprint(a.date, "%-12ld", 0); // time(0)
- sprint(a.uid, "%-6d", 0);
- sprint(a.gid, "%-6d", 0);
- sprint(a.mode, "%-8lo", 0644L);
- sprint(a.size, "%-10ld", len);
- strncpy(a.fmag, ARFMAG, 2);
- strcpy(a.name, symdef);
- for (cp = strchr(a.name, 0); /* blank pad on right */
- cp < a.name+sizeof(a.name); cp++)
- *cp = ' ';
- if(HEADER_IO(Bwrite, &b, a))
- wrerr();
-
- headlen = Boffset(&b);
- len += headlen;
- if (gflag) {
- getpkgdef(&pkgdefdata, &pkgdefsize);
- len += SAR_HDR + pkgdefsize;
- if (len & 1)
- len++;
- }
- if (astart) {
- wrsym(&b, len, astart->sym);
- len += astart->size;
- }
- if(amiddle) {
- wrsym(&b, len, amiddle->sym);
- len += amiddle->size;
- }
- if(aend)
- wrsym(&b, len, aend->sym);
-
- if(symdefsize&0x01)
- Bputc(&b, 0);
-
- if (gflag) {
- len = pkgdefsize;
- sprint(a.date, "%-12ld", 0); // time(0)
- sprint(a.uid, "%-6d", 0);
- sprint(a.gid, "%-6d", 0);
- sprint(a.mode, "%-8lo", 0644L);
- sprint(a.size, "%-10ld", (len + 1) & ~1);
- strncpy(a.fmag, ARFMAG, 2);
- strcpy(a.name, pkgdef);
- for (cp = strchr(a.name, 0); /* blank pad on right */
- cp < a.name+sizeof(a.name); cp++)
- *cp = ' ';
- if(HEADER_IO(Bwrite, &b, a))
- wrerr();
-
- if (Bwrite(&b, pkgdefdata, pkgdefsize) != pkgdefsize)
- wrerr();
- if(len&0x01)
- Bputc(&b, 0);
- }
- Bterm(&b);
-}
-
-/*
- * Write the defined symbols to the symdef file
- */
-void
-wrsym(Biobuf *bp, long offset, Arsymref *as)
-{
- int off;
-
- while(as) {
- Bputc(bp, as->type);
- off = as->offset+offset;
- Bputc(bp, off);
- Bputc(bp, off>>8);
- Bputc(bp, off>>16);
- Bputc(bp, off>>24);
- if (Bwrite(bp, as->name, as->len+1) != as->len+1)
- wrerr();
- as = as->next;
- }
-}
-
-/*
- * Check if the archive member matches an entry on the command line.
- */
-int
-match(int count, char **files)
-{
- int i;
- char name[ARNAMESIZE+1];
-
- for(i=0; i<count; i++) {
- if(files[i] == 0)
- continue;
- trim(files[i], name, ARNAMESIZE);
- if(strncmp(name, file, ARNAMESIZE) == 0) {
- file = files[i];
- files[i] = 0;
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * compare the current member to the name of the pivot member
- */
-int
-bamatch(char *file, char *pivot)
-{
- static int state = 0;
-
- switch(state)
- {
- case 0: /* looking for position file */
- if (aflag) {
- if (strncmp(file, pivot, ARNAMESIZE) == 0)
- state = 1;
- } else if (bflag) {
- if (strncmp(file, pivot, ARNAMESIZE) == 0) {
- state = 2; /* found */
- return 1;
- }
- }
- break;
- case 1: /* found - after previous file */
- state = 2;
- return 1;
- case 2: /* already found position file */
- break;
- }
- return 0;
-}
-
-/*
- * output a message, if 'v' option was specified
- */
-void
-mesg(int c, char *file)
-{
-
- if(vflag)
- Bprint(&bout, "%c - %s\n", c, file);
-}
-
-/*
- * isolate file name by stripping leading directories and trailing slashes
- */
-void
-trim(char *s, char *buf, int n)
-{
- char *p;
-
- for(;;) {
- p = strrchr(s, '/');
- if (!p) { /* no slash in name */
- strncpy(buf, s, n);
- return;
- }
- if (p[1] != 0) { /* p+1 is first char of file name */
- strncpy(buf, p+1, n);
- return;
- }
- *p = 0; /* strip trailing slash */
- }
-}
-
-/*
- * utilities for printing long form of 't' command
- */
-#define SUID 04000
-#define SGID 02000
-#define ROWN 0400
-#define WOWN 0200
-#define XOWN 0100
-#define RGRP 040
-#define WGRP 020
-#define XGRP 010
-#define ROTH 04
-#define WOTH 02
-#define XOTH 01
-#define STXT 01000
-
-void
-longt(Armember *bp)
-{
- char *cp;
- time_t date;
-
- pmode(strtoul(bp->hdr.mode, 0, 8));
- Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0));
- Bprint(&bout, "%7ld", bp->size);
- date = bp->date;
- cp = ctime(&date);
- /* using unix ctime, not plan 9 time, so cp+20 for year, not cp+24 */
- Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+20);
-}
-
-int m1[] = { 1, ROWN, 'r', '-' };
-int m2[] = { 1, WOWN, 'w', '-' };
-int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
-int m4[] = { 1, RGRP, 'r', '-' };
-int m5[] = { 1, WGRP, 'w', '-' };
-int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
-int m7[] = { 1, ROTH, 'r', '-' };
-int m8[] = { 1, WOTH, 'w', '-' };
-int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
-
-int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
-
-void
-pmode(long mode)
-{
- int **mp;
-
- for(mp = &m[0]; mp < &m[9];)
- select(*mp++, mode);
-}
-
-void
-select(int *ap, long mode)
-{
- int n;
-
- n = *ap++;
- while(--n>=0 && (mode&*ap++)==0)
- ap++;
- Bputc(&bout, *ap);
-}
-
-/*
- * Temp file I/O subsystem. We attempt to cache all three temp files in
- * core. When we run out of memory we spill to disk.
- * The I/O model assumes that temp files:
- * 1) are only written on the end
- * 2) are only read from the beginning
- * 3) are only read after all writing is complete.
- * The architecture uses one control block per temp file. Each control
- * block anchors a chain of buffers, each containing an archive member.
- */
-Arfile *
-newtempfile(char *name) /* allocate a file control block */
-{
- Arfile *ap;
-
- ap = armalloc(sizeof(Arfile));
- ap->fname = name;
- return ap;
-}
-
-Armember *
-newmember(void) /* allocate a member buffer */
-{
- return armalloc(sizeof(Armember));
-}
-
-void
-arread(Biobuf *b, Armember *bp) /* read an image into a member buffer */
-{
- int i;
- vlong off;
-
- bp->member = armalloc(bp->size);
-
- // If P flag is set, let arread_cutprefix try.
- // If it succeeds, we're done. If not, fall back
- // to a direct copy.
- off = Boffset(b);
- if(Pflag && arread_cutprefix(b, bp))
- return;
- Bseek(b, off, 0);
-
- i = Bread(b, bp->member, bp->size);
- if (i < 0) {
- free(bp->member);
- bp->member = 0;
- rderr();
- }
- if(bp->size&1)
- Bgetc(b);
-}
-
-/*
- * insert a member buffer into the member chain
- */
-void
-arinsert(Arfile *ap, Armember *bp)
-{
- bp->next = 0;
- if (!ap->tail)
- ap->head = bp;
- else
- ap->tail->next = bp;
- ap->tail = bp;
-}
-
-/*
- * stream the members in a temp file to the file referenced by 'fd'.
- */
-void
-arstream(int fd, Arfile *ap)
-{
- Armember *bp;
- int i;
- char buf[8192];
-
- if (ap->paged) { /* copy from disk */
- seek(ap->fd, 0, 0);
- for (;;) {
- i = read(ap->fd, buf, sizeof(buf));
- if (i < 0)
- rderr();
- if (i == 0)
- break;
- if (write(fd, buf, i) != i)
- wrerr();
- }
- close(ap->fd);
- ap->paged = 0;
- }
- /* dump the in-core buffers */
- for (bp = ap->head; bp; bp = bp->next) {
- if (!arwrite(fd, bp))
- wrerr();
- }
-}
-
-/*
- * write a member to 'fd'.
- */
-int
-arwrite(int fd, Armember *bp)
-{
- int len;
-
- if(HEADER_IO(write, fd, bp->hdr))
- return 0;
- len = bp->size;
- if (len & 01)
- len++;
- if (write(fd, bp->member, len) != len)
- return 0;
- return 1;
-}
-
-/*
- * Spill a member to a disk copy of a temp file
- */
-int
-page(Arfile *ap)
-{
- sysfatal("page");
- return 1;
-}
-
-/*
- * try to reclaim space by paging. we try to spill the start, middle,
- * and end files, in that order. there is no particular reason for the
- * ordering.
- */
-int
-getspace(void)
-{
-fprint(2, "IN GETSPACE\n");
- if (astart && astart->head && page(astart))
- return 1;
- if (amiddle && amiddle->head && page(amiddle))
- return 1;
- if (aend && aend->head && page(aend))
- return 1;
- return 0;
-}
-
-void
-arfree(Arfile *ap) /* free a member buffer */
-{
- Armember *bp, *next;
-
- for (bp = ap->head; bp; bp = next) {
- next = bp->next;
- if (bp->member)
- free(bp->member);
- free(bp);
- }
- free(ap);
-}
-
-/*
- * allocate space for a control block or member buffer. if the malloc
- * fails we try to reclaim space by spilling previously allocated
- * member buffers.
- */
-void *
-armalloc(int n)
-{
- char *cp;
-
- // bump so that arwrite can do the same
- if(n&1)
- n++;
-
- do {
- cp = malloc(n);
- if (cp) {
- memset(cp, 0, n);
- return cp;
- }
- } while (getspace());
- fprint(2, "gopack: out of memory\n");
- exits("malloc");
- return 0;
-}
-
-char *
-arstrdup(char *s)
-{
- char *t;
-
- t = armalloc(strlen(s) + 1);
- strcpy(t, s);
- return t;
-}
-
-
-/*
- * Parts of libmach we're not supposed
- * to look at but need for arread_cutprefix.
- */
-extern int _read5(Biobuf*, Prog*);
-extern int _read6(Biobuf*, Prog*);
-extern int _read8(Biobuf*, Prog*);
-int (*reader[256])(Biobuf*, Prog*) = {
- [ObjArm] = _read5,
- [ObjAmd64] = _read6,
- [Obj386] = _read8,
-};
-
-/*
- * copy b into bp->member but rewrite object
- * during copy to drop prefix from all file names.
- * return 1 if b was recognized as an object file
- * and copied successfully, 0 otherwise.
- */
-int
-arread_cutprefix(Biobuf *b, Armember *bp)
-{
- vlong offset, o, end;
- int n, t;
- int (*rd)(Biobuf*, Prog*);
- char *w, *inprefix;
- Prog p;
-
- offset = Boffset(b);
- end = offset + bp->size;
- t = objtype(b, nil);
- if(t < 0)
- return 0;
- if((rd = reader[t]) == nil)
- return 0;
-
- // copy header
- w = bp->member;
- n = Boffset(b) - offset;
- Bseek(b, -n, 1);
- if(Bread(b, w, n) != n)
- return 0;
- offset += n;
- w += n;
-
- // read object file one pseudo-instruction at a time,
- // eliding the file name instructions that refer to
- // the prefix.
- memset(&p, 0, sizeof p);
- inprefix = nil;
- while(Boffset(b) < end && rd(b, &p)) {
- if(p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') {
- // part of a file path.
- // we'll keep continuing (skipping the copy)
- // around the loop until either we get to a
- // name piece that should be kept or we see
- // the whole prefix.
-
- if(inprefix == nil && prefix[0] == '/' && p.id[1] == '/' && p.id[2] == '\0') {
- // leading /
- inprefix = prefix+1;
- } else if(inprefix != nil) {
- // handle subsequent elements
- n = strlen(p.id+1);
- if(strncmp(p.id+1, inprefix, n) == 0 && (inprefix[n] == '/' || inprefix[n] == '\0')) {
- inprefix += n;
- if(inprefix[0] == '/')
- inprefix++;
- }
- }
-
- if(inprefix && inprefix[0] == '\0') {
- // reached end of prefix.
- // if we another path element follows,
- // nudge the offset to skip over the prefix we saw.
- // if not, leave offset alone, to emit the whole name.
- // additional name elements will not be skipped
- // because inprefix is now nil and we won't see another
- // leading / in this name.
- inprefix = nil;
- o = Boffset(b);
- if(o < end && rd(b, &p) && p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') {
- // print("skip %lld-%lld\n", offset, o);
- offset = o;
- }
- }
- } else {
- // didn't find the whole prefix.
- // give up and let it emit the entire name.
- inprefix = nil;
- }
-
- // copy instructions
- if(!inprefix) {
- n = Boffset(b) - offset;
- Bseek(b, -n, 1);
- if(Bread(b, w, n) != n)
- return 0;
- offset += n;
- w += n;
- }
- }
- bp->size = w - (char*)bp->member;
- sprint(bp->hdr.size, "%-10lld", (vlong)bp->size);
- strncpy(bp->hdr.fmag, ARFMAG, 2);
- Bseek(b, end, 0);
- if(Boffset(b)&1)
- Bgetc(b);
- return 1;
-}
diff --git a/src/cmd/gopack/doc.go b/src/cmd/gopack/doc.go
deleted file mode 100644
index 1551a275f..000000000
--- a/src/cmd/gopack/doc.go
+++ /dev/null
@@ -1,26 +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.
-
-/*
-
-Gopack is a variant of the Plan 9 ar tool. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/ar
-
-It adds a special Go-specific section __.PKGDEF that collects all the
-Go type information from the files in the archive; that section is
-used by the compiler when importing the package during compilation.
-
-Usage: gopack [uvnbailogS][mrxtdpq][P prefix] archive files ...
-
-The new option 'g' causes gopack to maintain the __.PKGDEF section
-as files are added to the archive.
-
-The new option 'S' forces gopack to mark the archive as safe.
-
-The new option 'P' causes gopack to remove the given prefix
-from file names in the line number information in object files
-that are already stored in or added to the archive.
-*/
-package documentation
diff --git a/src/cmd/gotest/Makefile b/src/cmd/gotest/Makefile
deleted file mode 100644
index 5c1154537..000000000
--- a/src/cmd/gotest/Makefile
+++ /dev/null
@@ -1,12 +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 ../../Make.inc
-
-TARG=gotest
-GOFILES=\
- flag.go\
- gotest.go\
-
-include ../../Make.cmd
diff --git a/src/cmd/gotest/doc.go b/src/cmd/gotest/doc.go
deleted file mode 100644
index 5be06f817..000000000
--- a/src/cmd/gotest/doc.go
+++ /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.
-
-/*
-
-Gotest is an automated testing tool for Go packages.
-
-Normally a Go package is compiled without its test files. Gotest is a
-tool that recompiles the package whose source is in the current
-directory, along with any files whose names match the pattern
-"[^.]*_test.go". Functions in the test source named TestXXX (where
-XXX is any alphanumeric string not starting with a lower case letter)
-will be run when the binary is executed. Gotest requires that the
-package have a standard package Makefile, one that includes
-go/src/Make.pkg.
-
-The test functions are run in the order they appear in the source.
-They should have the signature,
-
- func TestXXX(t *testing.T) { ... }
-
-Benchmark functions can be written as well; they will be run only when
-the -test.bench flag is provided. Benchmarks should have the
-signature,
-
- func BenchmarkXXX(b *testing.B) { ... }
-
-See the documentation of the testing package for more information.
-
-By default, gotest needs no arguments. It compiles all the .go files
-in the directory, including tests, and runs the tests. If file names
-are given (with flag -file=test.go, one per extra test source file),
-only those test files are added to the package. (The non-test files
-are always compiled.)
-
-The package is built in a special subdirectory so it does not
-interfere with the non-test installation.
-
-Usage:
- gotest [-file a.go -file b.go ...] [-c] [-x] [args for test binary]
-
-The flags specific to gotest are:
- -c Compile the test binary but do not run it.
- -file a.go Use only the tests in the source file a.go.
- Multiple -file flags may be provided.
- -x Print each subcommand gotest executes.
-
-Everything else on the command line is passed to the test binary.
-
-The resulting test binary, called (for amd64) 6.out, has several flags.
-
-Usage:
- 6.out [-test.v] [-test.run pattern] [-test.bench pattern] \
- [-test.cpuprofile=cpu.out] \
- [-test.memprofile=mem.out] [-test.memprofilerate=1] \
- [-test.timeout=10] [-test.short] \
- [-test.benchtime=3] [-test.cpu=1,2,3,4]
-
-The -test.v flag causes the tests to be logged as they run. The
--test.run flag causes only those tests whose names match the regular
-expression pattern to be run. By default all tests are run silently.
-
-If all specified tests pass, 6.out prints the word PASS and exits with
-a 0 exit code. If any tests fail, it prints error details, the word
-FAIL, and exits with a non-zero code. The -test.bench flag is
-analogous to the -test.run flag, but applies to benchmarks. No
-benchmarks run by default.
-
-The -test.cpuprofile flag causes the testing software to write a CPU
-profile to the specified file before exiting.
-
-The -test.memprofile flag causes the testing software to write a
-memory profile to the specified file when all tests are complete. The
--test.memprofilerate flag enables more precise (and expensive)
-profiles by setting runtime.MemProfileRate; run
- godoc runtime MemProfileRate
-for details. The defaults are no memory profile and the standard
-setting of MemProfileRate. The memory profile records a sampling of
-the memory in use at the end of the test. To profile all memory
-allocations, use -test.memprofilerate=1 to sample every byte and set
-the environment variable GOGC=off to disable the garbage collector,
-provided the test can run in the available memory without garbage
-collection.
-
-Use -test.run or -test.bench to limit profiling to a particular test
-or benchmark.
-
-The -test.short flag tells long-running tests to shorten their run
-time. It is off by default but set by all.bash so installations of
-the Go tree can do a sanity check but not spend time running
-exhaustive tests.
-
-The -test.timeout flag sets a timeout for the test in seconds. If the
-test runs for longer than that, it will panic, dumping a stack trace
-of all existing goroutines.
-
-The -test.benchtime flag specifies the number of seconds to run each benchmark.
-The default is one second.
-
-The -test.cpu flag specifies a list of GOMAXPROCS values for which
-the tests or benchmarks are executed. The default is the current
-value of GOMAXPROCS.
-
-For convenience, each of these -test.X flags of the test binary is
-also available as the flag -X in gotest itself. Flags not listed here
-are unaffected. For instance, the command
- gotest -x -v -cpuprofile=prof.out -dir=testdata -update -file x_test.go
-will compile the test binary using x_test.go and then run it as
- 6.out -test.v -test.cpuprofile=prof.out -dir=testdata -update
-
-*/
-package documentation
diff --git a/src/cmd/gotest/flag.go b/src/cmd/gotest/flag.go
deleted file mode 100644
index c3a28f9a3..000000000
--- a/src/cmd/gotest/flag.go
+++ /dev/null
@@ -1,159 +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 main
-
-import (
- "fmt"
- "os"
- "strconv"
- "strings"
-)
-
-// The flag handling part of gotest is large and distracting.
-// We can't use the flag package because some of the flags from
-// our command line are for us, and some are for 6.out, and
-// some are for both.
-
-var usageMessage = `Usage of %s:
- -c=false: compile but do not run the test binary
- -file=file:
- -x=false: print command lines as they are executed
-
- // These flags can be passed with or without a "test." prefix: -v or -test.v.
- -bench="": passes -test.bench to test
- -benchtime=1: passes -test.benchtime to test
- -cpu="": passes -test.cpu to test
- -cpuprofile="": passes -test.cpuprofile to test
- -memprofile="": passes -test.memprofile to test
- -memprofilerate=0: passes -test.memprofilerate to test
- -run="": passes -test.run to test
- -short=false: passes -test.short to test
- -timeout=0: passes -test.timeout to test
- -v=false: passes -test.v to test
-`
-
-// usage prints a usage message and exits.
-func usage() {
- fmt.Fprintf(os.Stdout, usageMessage, os.Args[0])
- os.Exit(2)
-}
-
-// flagSpec defines a flag we know about.
-type flagSpec struct {
- name string
- isBool bool
- passToTest bool // pass to Test
- multiOK bool // OK to have multiple instances
- present bool // flag has been seen
-}
-
-// flagDefn is the set of flags we process.
-var flagDefn = []*flagSpec{
- // gotest-local.
- &flagSpec{name: "c", isBool: true},
- &flagSpec{name: "file", multiOK: true},
- &flagSpec{name: "x", isBool: true},
-
- // passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
- &flagSpec{name: "bench", passToTest: true},
- &flagSpec{name: "benchtime", passToTest: true},
- &flagSpec{name: "cpu", passToTest: true},
- &flagSpec{name: "cpuprofile", passToTest: true},
- &flagSpec{name: "memprofile", passToTest: true},
- &flagSpec{name: "memprofilerate", passToTest: true},
- &flagSpec{name: "run", passToTest: true},
- &flagSpec{name: "short", isBool: true, passToTest: true},
- &flagSpec{name: "timeout", passToTest: true},
- &flagSpec{name: "v", isBool: true, passToTest: true},
-}
-
-// flags processes the command line, grabbing -x and -c, rewriting known flags
-// to have "test" before them, and reading the command line for the 6.out.
-// Unfortunately for us, we need to do our own flag processing because gotest
-// grabs some flags but otherwise its command line is just a holding place for
-// 6.out's arguments.
-func flags() {
- for i := 1; i < len(os.Args); i++ {
- arg := os.Args[i]
- f, value, extraWord := flag(i)
- if f == nil {
- args = append(args, arg)
- continue
- }
- switch f.name {
- case "c":
- setBoolFlag(&cFlag, value)
- case "x":
- setBoolFlag(&xFlag, value)
- case "file":
- fileNames = append(fileNames, value)
- }
- if extraWord {
- i++
- }
- if f.passToTest {
- args = append(args, "-test."+f.name+"="+value)
- }
- }
-}
-
-// flag sees if argument i is a known flag and returns its definition, value, and whether it consumed an extra word.
-func flag(i int) (f *flagSpec, value string, extra bool) {
- arg := os.Args[i]
- if strings.HasPrefix(arg, "--") { // reduce two minuses to one
- arg = arg[1:]
- }
- if arg == "" || arg[0] != '-' {
- return
- }
- name := arg[1:]
- // If there's already "test.", drop it for now.
- if strings.HasPrefix(name, "test.") {
- name = name[5:]
- }
- equals := strings.Index(name, "=")
- if equals >= 0 {
- value = name[equals+1:]
- name = name[:equals]
- }
- for _, f = range flagDefn {
- if name == f.name {
- // Booleans are special because they have modes -x, -x=true, -x=false.
- if f.isBool {
- if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
- value = "true"
- } else {
- // verify it parses
- setBoolFlag(new(bool), value)
- }
- } else { // Non-booleans must have a value.
- extra = equals < 0
- if extra {
- if i+1 >= len(os.Args) {
- usage()
- }
- value = os.Args[i+1]
- }
- }
- if f.present && !f.multiOK {
- usage()
- }
- f.present = true
- return
- }
- }
- f = nil
- return
-}
-
-// setBoolFlag sets the addressed boolean to the value.
-func setBoolFlag(flag *bool, value string) {
- x, err := strconv.Atob(value)
- if err != nil {
- fmt.Fprintf(os.Stderr, "gotest: illegal bool flag value %s\n", value)
- usage()
- }
- *flag = x
-}
diff --git a/src/cmd/gotest/gotest.go b/src/cmd/gotest/gotest.go
deleted file mode 100644
index 4cb3da23c..000000000
--- a/src/cmd/gotest/gotest.go
+++ /dev/null
@@ -1,435 +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 main
-
-import (
- "bufio"
- "exec"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "io/ioutil"
- "os"
- "path/filepath"
- "runtime"
- "strings"
- "time"
- "unicode"
- "utf8"
-)
-
-// Environment for commands.
-var (
- XGC []string // 6g -I _test -o _xtest_.6
- GC []string // 6g -I _test _testmain.go
- GL []string // 6l -L _test _testmain.6
- GOARCH string
- GOROOT string
- GORUN string
- O string
- args []string // arguments passed to gotest; also passed to the binary
- fileNames []string
- env = os.Environ()
-)
-
-// These strings are created by getTestNames.
-var (
- insideFileNames []string // list of *.go files inside the package.
- outsideFileNames []string // list of *.go files outside the package (in package foo_test).
-)
-
-var (
- files []*File
- importPath string
-)
-
-// Flags for our own purposes. We do our own flag processing.
-var (
- cFlag bool
- xFlag bool
-)
-
-// elapsed returns the number of seconds since gotest started.
-func elapsed() float64 {
- return float64(time.Nanoseconds()-start) / 1e9
-}
-
-var start = time.Nanoseconds()
-
-// File represents a file that contains tests.
-type File struct {
- name string
- pkg string
- file *os.File
- astFile *ast.File
- tests []string // The names of the TestXXXs.
- benchmarks []string // The names of the BenchmarkXXXs.
-}
-
-func main() {
- flags()
- needMakefile()
- setEnvironment()
- getTestFileNames()
- parseFiles()
- getTestNames()
- run("gomake", "testpackage-clean")
- run("gomake", "testpackage", fmt.Sprintf("GOTESTFILES=%s", strings.Join(insideFileNames, " ")))
- if len(outsideFileNames) > 0 {
- run(append(XGC, outsideFileNames...)...)
- }
- importPath = runWithStdout("gomake", "-s", "importpath")
- writeTestmainGo()
- run(GC...)
- run(GL...)
- if !cFlag {
- runTestWithArgs("./" + O + ".out")
- }
- if xFlag {
- fmt.Printf("gotest %.2fs: done\n", elapsed())
- }
-}
-
-// needMakefile tests that we have a Makefile in this directory.
-func needMakefile() {
- if _, err := os.Stat("Makefile"); err != nil {
- Fatalf("please create a Makefile for gotest; see http://golang.org/doc/code.html for details")
- }
-}
-
-// Fatalf formats its arguments, prints the message with a final newline, and exits.
-func Fatalf(s string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "gotest: "+s+"\n", args...)
- os.Exit(2)
-}
-
-// theChar is the map from architecture to object character.
-var theChar = map[string]string{
- "arm": "5",
- "amd64": "6",
- "386": "8",
-}
-
-// addEnv adds a name=value pair to the environment passed to subcommands.
-// If the item is already in the environment, addEnv replaces the value.
-func addEnv(name, value string) {
- for i := 0; i < len(env); i++ {
- if strings.HasPrefix(env[i], name+"=") {
- env[i] = name + "=" + value
- return
- }
- }
- env = append(env, name+"="+value)
-}
-
-// setEnvironment assembles the configuration for gotest and its subcommands.
-func setEnvironment() {
- // Basic environment.
- GOROOT = runtime.GOROOT()
- addEnv("GOROOT", GOROOT)
- GOARCH = os.Getenv("GOARCH")
- if GOARCH == "" {
- GOARCH = runtime.GOARCH
- }
- addEnv("GOARCH", GOARCH)
- O = theChar[GOARCH]
- if O == "" {
- Fatalf("unknown architecture %s", GOARCH)
- }
-
- // Commands and their flags.
- gc := os.Getenv("GC")
- if gc == "" {
- gc = O + "g"
- }
- XGC = []string{gc, "-I", "_test", "-o", "_xtest_." + O}
- GC = []string{gc, "-I", "_test", "_testmain.go"}
- gl := os.Getenv("GL")
- if gl == "" {
- gl = O + "l"
- }
- GL = []string{gl, "-L", "_test", "_testmain." + O}
-
- // Silence make on Linux
- addEnv("MAKEFLAGS", "")
- addEnv("MAKELEVEL", "")
-}
-
-// getTestFileNames gets the set of files we're looking at.
-// If gotest has no arguments, it scans for file names matching "[^.]*_test.go".
-func getTestFileNames() {
- names := fileNames
- if len(names) == 0 {
- var err os.Error
- names, err = filepath.Glob("[^.]*_test.go")
- if err != nil {
- Fatalf("Glob pattern error: %s", err)
- }
- if len(names) == 0 {
- Fatalf(`no test files found: no match for "[^.]*_test.go"`)
- }
- }
- for _, n := range names {
- fd, err := os.Open(n)
- if err != nil {
- Fatalf("%s: %s", n, err)
- }
- f := &File{name: n, file: fd}
- files = append(files, f)
- }
-}
-
-// parseFiles parses the files and remembers the packages we find.
-func parseFiles() {
- fileSet := token.NewFileSet()
- for _, f := range files {
- // Report declaration errors so we can abort if the files are incorrect Go.
- file, err := parser.ParseFile(fileSet, f.name, nil, parser.DeclarationErrors)
- if err != nil {
- Fatalf("parse error: %s", err)
- }
- f.astFile = file
- f.pkg = file.Name.String()
- if f.pkg == "" {
- Fatalf("cannot happen: no package name in %s", f.name)
- }
- }
-}
-
-// getTestNames extracts the names of tests and benchmarks. They are all
-// top-level functions that are not methods.
-func getTestNames() {
- for _, f := range files {
- for _, d := range f.astFile.Decls {
- n, ok := d.(*ast.FuncDecl)
- if !ok {
- continue
- }
- if n.Recv != nil { // a method, not a function.
- continue
- }
- name := n.Name.String()
- if isTest(name, "Test") {
- f.tests = append(f.tests, name)
- } else if isTest(name, "Benchmark") {
- f.benchmarks = append(f.benchmarks, name)
- }
- // TODO: worth checking the signature? Probably not.
- }
- if strings.HasSuffix(f.pkg, "_test") {
- outsideFileNames = append(outsideFileNames, f.name)
- } else {
- insideFileNames = append(insideFileNames, f.name)
- }
- }
-}
-
-// isTest tells whether name looks like a test (or benchmark, according to prefix).
-// It is a Test (say) if there is a character after Test that is not a lower-case letter.
-// We don't want TesticularCancer.
-func isTest(name, prefix string) bool {
- if !strings.HasPrefix(name, prefix) {
- return false
- }
- if len(name) == len(prefix) { // "Test" is ok
- return true
- }
- rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
- return !unicode.IsLower(rune)
-}
-
-func run(args ...string) {
- doRun(args, false)
-}
-
-// runWithStdout is like run, but returns the text of standard output with the last newline dropped.
-func runWithStdout(argv ...string) string {
- s := doRun(argv, true)
- if strings.HasSuffix(s, "\r\n") {
- s = s[:len(s)-2]
- } else if strings.HasSuffix(s, "\n") {
- s = s[:len(s)-1]
- }
- if len(s) == 0 {
- Fatalf("no output from command %s", strings.Join(argv, " "))
- }
- return s
-}
-
-// runTestWithArgs appends gotest's runs the provided binary with the args passed on the command line.
-func runTestWithArgs(binary string) {
- doRun(append([]string{binary}, args...), false)
-}
-
-// doRun is the general command runner. The flag says whether we want to
-// retrieve standard output.
-func doRun(argv []string, returnStdout bool) string {
- if xFlag {
- fmt.Printf("gotest %.2fs: %s\n", elapsed(), strings.Join(argv, " "))
- t := -time.Nanoseconds()
- defer func() {
- t += time.Nanoseconds()
- fmt.Printf(" [+%.2fs]\n", float64(t)/1e9)
- }()
- }
- command := argv[0]
- if runtime.GOOS == "windows" && command == "gomake" {
- // gomake is a shell script and it cannot be executed directly on Windows.
- cmd := ""
- for i, v := range argv {
- if i > 0 {
- cmd += " "
- }
- cmd += `"` + v + `"`
- }
- command = "bash"
- argv = []string{"bash", "-c", cmd}
- }
- var err os.Error
- argv[0], err = exec.LookPath(argv[0])
- if err != nil {
- Fatalf("can't find %s: %s", command, err)
- }
- procAttr := &os.ProcAttr{
- Env: env,
- Files: []*os.File{
- os.Stdin,
- os.Stdout,
- os.Stderr,
- },
- }
- var r, w *os.File
- if returnStdout {
- r, w, err = os.Pipe()
- if err != nil {
- Fatalf("can't create pipe: %s", err)
- }
- procAttr.Files[1] = w
- }
- proc, err := os.StartProcess(argv[0], argv, procAttr)
- if err != nil {
- Fatalf("%s failed to start: %s", command, err)
- }
- if returnStdout {
- defer r.Close()
- w.Close()
- }
- waitMsg, err := proc.Wait(0)
- if err != nil || waitMsg == nil {
- Fatalf("%s failed: %s", command, err)
- }
- if !waitMsg.Exited() || waitMsg.ExitStatus() != 0 {
- Fatalf("%q failed: %s", strings.Join(argv, " "), waitMsg)
- }
- if returnStdout {
- b, err := ioutil.ReadAll(r)
- if err != nil {
- Fatalf("can't read output from command: %s", err)
- }
- return string(b)
- }
- return ""
-}
-
-// writeTestmainGo generates the test program to be compiled, "./_testmain.go".
-func writeTestmainGo() {
- f, err := os.Create("_testmain.go")
- if err != nil {
- Fatalf("can't create _testmain.go: %s", err)
- }
- defer f.Close()
- b := bufio.NewWriter(f)
- defer b.Flush()
-
- // Package and imports.
- fmt.Fprint(b, "package main\n\n")
- // Are there tests from a package other than the one we're testing?
- // We can't just use file names because some of the things we compiled
- // contain no tests.
- outsideTests := false
- insideTests := false
- for _, f := range files {
- //println(f.name, f.pkg)
- if len(f.tests) == 0 && len(f.benchmarks) == 0 {
- continue
- }
- if strings.HasSuffix(f.pkg, "_test") {
- outsideTests = true
- } else {
- insideTests = true
- }
- }
- if insideTests {
- switch importPath {
- case "testing":
- case "main":
- // Import path main is reserved, so import with
- // explicit reference to ./_test/main instead.
- // Also, the file we are writing defines a function named main,
- // so rename this import to __main__ to avoid name conflict.
- fmt.Fprintf(b, "import __main__ %q\n", "./_test/main")
- default:
- fmt.Fprintf(b, "import %q\n", importPath)
- }
- }
- if outsideTests {
- fmt.Fprintf(b, "import %q\n", "./_xtest_")
- }
- fmt.Fprintf(b, "import %q\n", "testing")
- fmt.Fprintf(b, "import __os__ %q\n", "os") // rename in case tested package is called os
- fmt.Fprintf(b, "import __regexp__ %q\n", "regexp") // rename in case tested package is called regexp
- fmt.Fprintln(b) // for gofmt
-
- // Tests.
- fmt.Fprintln(b, "var tests = []testing.InternalTest{")
- for _, f := range files {
- for _, t := range f.tests {
- fmt.Fprintf(b, "\t{\"%s.%s\", %s.%s},\n", f.pkg, t, notMain(f.pkg), t)
- }
- }
- fmt.Fprintln(b, "}")
- fmt.Fprintln(b)
-
- // Benchmarks.
- fmt.Fprintf(b, "var benchmarks = []testing.InternalBenchmark{")
- for _, f := range files {
- for _, bm := range f.benchmarks {
- fmt.Fprintf(b, "\t{\"%s.%s\", %s.%s},\n", f.pkg, bm, notMain(f.pkg), bm)
- }
- }
- fmt.Fprintln(b, "}")
-
- // Body.
- fmt.Fprintln(b, testBody)
-}
-
-// notMain returns the package, renaming as appropriate if it's "main".
-func notMain(pkg string) string {
- if pkg == "main" {
- return "__main__"
- }
- return pkg
-}
-
-// testBody is just copied to the output. It's the code that runs the tests.
-var testBody = `
-var matchPat string
-var matchRe *__regexp__.Regexp
-
-func matchString(pat, str string) (result bool, err __os__.Error) {
- if matchRe == nil || matchPat != pat {
- matchPat = pat
- matchRe, err = __regexp__.Compile(matchPat)
- if err != nil {
- return
- }
- }
- return matchRe.MatchString(str), nil
-}
-
-func main() {
- testing.Main(matchString, tests, benchmarks)
-}`
diff --git a/src/cmd/gotry/Makefile b/src/cmd/gotry/Makefile
deleted file mode 100644
index 6a32bbf2d..000000000
--- a/src/cmd/gotry/Makefile
+++ /dev/null
@@ -1,18 +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 ../../Make.inc
-
-TARG=install
-
-clean:
- @true
-
-install: install-gotry
-
-install-%: %
- ! test -f "$(GOBIN)"/$* || chmod u+w "$(GOBIN)"/$*
- sed 's`@@GOROOT@@`$(GOROOT_FINAL)`' $* >"$(GOBIN)"/$*
- chmod +x "$(GOBIN)"/$*
-
diff --git a/src/cmd/gotry/gotry b/src/cmd/gotry/gotry
deleted file mode 100755
index 52c5d2d58..000000000
--- a/src/cmd/gotry/gotry
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-# Using all the non-test *.go files in the named directory, write
-# out a file /tmp/$USER.try.go to evaluate the expressions on the
-# command line, perhaps to discover a function or method that
-# gives the desired results. See usage message.
-# Compile the program and run it.
-
-# Makes egrep,grep work better in general if we put them
-# in ordinary C mode instead of what the current language is.
-unset LANG
-export LC_ALL=C
-export LC_CTYPE=C
-
-export GOROOT=${GOROOT:-"@@GOROOT@@"}
-eval $(gomake -j1 --no-print-directory -f "$GOROOT"/src/Make.inc go-env)
-if [ -z "$O" ]; then
- echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
- exit 2
-fi
-
-# Allow overrides
-GC="${_GC:-$GC} -I _test"
-GL="${GL:-$LD} -L _test"
-AS="$AS"
-CC="$CC"
-LD="$LD"
-export GC GL O AS CC LD
-
-# Macros for tab and quotes for easier readability.
-T=' '
-BQ='`'
-SQ="'"
-DQ='"'
-SD="$SQ$DQ"
-DS="$DQ$SQ"
-
-usage="usage: gotry [packagedirectory] expression ...
-Given one expression, gotry attempts to evaluate that expression.
-Given multiple expressions, gotry treats them as a list of arguments
-and result values and attempts to find a function in the package
-that, given the first few expressions as arguments, evaluates to
-the remaining expressions as results. If the first expression has
-methods, it will also search for applicable methods.
-
-If there are multiple expressions, a package directory must be
-specified. If there is a package argument, the expressions are
-evaluated in an environment that includes
- import . ${DQ}packagedirectory${DQ}
-
-Examples:
- gotry 3+4
- # evaluates to 7
- gotry strings ${SD}abc${DS} ${SD}c${DS} 7-5
- # finds strings.Index etc.
- gotry regexp ${SQ}MustCompile(${DQ}^[0-9]+${DQ})${SQ} ${SD}12345${DS} true
- # finds Regexp.MatchString
-
-"
-
-function fail() {
- echo 2>&1 "$@"
- exit 2
-}
-
-case $# in
- 0)
- fail "$usage"
- ;;
- *)
- case "$1" in
- -*help|-*'?'|'?')
- fail "$usage"
- esac
- if test -d "$GOROOT/src/pkg/$1"
- then
- pkg=$(basename $1)
- dir=$GOROOT/src/pkg/$1
- importdir=$1
- shift
- case "$pkg" in
- os|syscall)
- fail "gotry: cannot try packages os or syscall; they are too dangerous"
- esac
- fi
- ;;
-esac
-
-spaces='[ ][ ]*'
-
-function getFunctions() {
- if [ "$pkg" = "" ]
- then
- return
- fi
- for file in $dir/*.go
- do
- case $file in
- *_test*)
- continue
- esac
- grep "func$spaces[A-Z]" $file | # TODO: should be Unicode upper case
- sed "s/func$spaces//;s/(.*//"
- done | sort -u
-}
-
-# Generate list of public functions.
-functions=$(getFunctions)
-
-# Write file to compile
-rm -f /tmp/$USER.try.go
-(
-cat <<'!'
-package main
-
-import (
- "os"
- "try"
-!
-
-if [ "$pkg" != "" ]
-then
- echo "$T" . '"'$importdir'"'
-fi
-
-cat <<!
-)
-func main() {
- try.Main("$pkg", firstArg, functions, args)
-}
-var functions = map[string] interface{}{
-!
-
-for i in $functions
-do
- echo "$T"'"'$i'": '$i','
-done
-echo "}"
-
-echo 'var args = []interface{}{'
-
-if [ $# = 1 ]
-then
- echo "${T}toSlice($1)",
-else
-for i
- do
- echo "$T$i",
- done
-fi
-echo "}"
-
-cat <<!
-var firstArg = $BQ$1$BQ
-var _ os.Error
-func toSlice(a ...interface{}) []interface{} { return a }
-!
-
-)>/tmp/$USER.try.go
-
-$GC -o /tmp/$USER.try.$O /tmp/$USER.try.go &&
-$GL -o /tmp/$USER.try /tmp/$USER.try.$O &&
-/tmp/$USER.try "_$@"
-rm -f /tmp/$USER.try /tmp/$USER.try.go /tmp/$USER.try.$O
diff --git a/src/cmd/gotype/Makefile b/src/cmd/gotype/Makefile
deleted file mode 100644
index 18171945d..000000000
--- a/src/cmd/gotype/Makefile
+++ /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.
-
-include ../../Make.inc
-
-TARG=gotype
-GOFILES=\
- gotype.go\
-
-include ../../Make.cmd
-
-test:
- gotest
-
-testshort:
- gotest -test.short
diff --git a/src/cmd/gotype/doc.go b/src/cmd/gotype/doc.go
deleted file mode 100644
index ec4eb7c24..000000000
--- a/src/cmd/gotype/doc.go
+++ /dev/null
@@ -1,59 +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.
-
-/*
-The gotype command does syntactic and semantic analysis of Go files
-and packages similar to the analysis performed by the front-end of
-a Go compiler. Errors are reported if the analysis fails; otherwise
-gotype is quiet (unless -v is set).
-
-Without a list of paths, gotype processes the standard input, which must
-be the source of a single package file.
-
-Given a list of file names, each file must be a source file belonging to
-the same package unless the package name is explicitly specified with the
--p flag.
-
-Given a directory name, gotype collects all .go files in the directory
-and processes them as if they were provided as an explicit list of file
-names. Each directory is processed independently. Files starting with .
-or not ending in .go are ignored.
-
-Usage:
- gotype [flags] [path ...]
-
-The flags are:
- -p pkgName
- process only those files in package pkgName.
- -r
- recursively process subdirectories.
- -v
- verbose mode.
-
-Debugging flags:
- -trace
- print parse trace (disables concurrent parsing).
- -ast
- print AST (disables concurrent parsing).
-
-
-Examples
-
-To check the files file.go, old.saved, and .ignored:
-
- gotype file.go old.saved .ignored
-
-To check all .go files belonging to package main in the current directory
-and recursively in all subdirectories:
-
- gotype -p main -r .
-
-To verify the output of a pipe:
-
- echo "package foo" | gotype
-
-*/
-package documentation
-
-// BUG(gri): At the moment, only single-file scope analysis is performed.
diff --git a/src/cmd/gotype/gotype.go b/src/cmd/gotype/gotype.go
deleted file mode 100644
index 501ead443..000000000
--- a/src/cmd/gotype/gotype.go
+++ /dev/null
@@ -1,200 +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 main
-
-import (
- "flag"
- "fmt"
- "go/ast"
- "go/parser"
- "go/scanner"
- "go/token"
- "go/types"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-)
-
-
-var (
- // main operation modes
- pkgName = flag.String("p", "", "process only those files in package pkgName")
- recursive = flag.Bool("r", false, "recursively process subdirectories")
- verbose = flag.Bool("v", false, "verbose mode")
-
- // debugging support
- printTrace = flag.Bool("trace", false, "print parse trace")
- printAST = flag.Bool("ast", false, "print AST")
-)
-
-
-var exitCode = 0
-
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: gotype [flags] [path ...]\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-
-func report(err os.Error) {
- scanner.PrintError(os.Stderr, err)
- exitCode = 2
-}
-
-
-// parse returns the AST for the Go source src.
-// The filename is for error reporting only.
-// The result is nil if there were errors or if
-// the file does not belong to the -p package.
-func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
- if *verbose {
- fmt.Println(filename)
- }
-
- // ignore files with different package name
- if *pkgName != "" {
- file, err := parser.ParseFile(fset, filename, src, parser.PackageClauseOnly)
- if err != nil {
- report(err)
- return nil
- }
- if file.Name.Name != *pkgName {
- if *verbose {
- fmt.Printf("\tignored (package %s)\n", file.Name.Name)
- }
- return nil
- }
- }
-
- // parse entire file
- mode := parser.DeclarationErrors
- if *printTrace {
- mode |= parser.Trace
- }
- file, err := parser.ParseFile(fset, filename, src, mode)
- if err != nil {
- report(err)
- return nil
- }
- if *printAST {
- ast.Print(fset, file)
- }
-
- return file
-}
-
-
-func parseStdin(fset *token.FileSet) (files map[string]*ast.File) {
- files = make(map[string]*ast.File)
- src, err := ioutil.ReadAll(os.Stdin)
- if err != nil {
- report(err)
- return
- }
- const filename = "<standard input>"
- if file := parse(fset, filename, src); file != nil {
- files[filename] = file
- }
- return
-}
-
-
-func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.File) {
- files = make(map[string]*ast.File)
- for _, filename := range filenames {
- src, err := ioutil.ReadFile(filename)
- if err != nil {
- report(err)
- continue
- }
- if file := parse(fset, filename, src); file != nil {
- if files[filename] != nil {
- report(os.NewError(fmt.Sprintf("%q: duplicate file", filename)))
- continue
- }
- files[filename] = file
- }
- }
- return
-}
-
-
-func isGoFilename(filename string) bool {
- // ignore non-Go files
- return !strings.HasPrefix(filename, ".") && strings.HasSuffix(filename, ".go")
-}
-
-
-func processDirectory(dirname string) {
- f, err := os.Open(dirname)
- if err != nil {
- report(err)
- return
- }
- filenames, err := f.Readdirnames(-1)
- f.Close()
- if err != nil {
- report(err)
- // continue since filenames may not be empty
- }
- for i, filename := range filenames {
- filenames[i] = filepath.Join(dirname, filename)
- }
- processFiles(filenames, false)
-}
-
-
-func processFiles(filenames []string, allFiles bool) {
- i := 0
- for _, filename := range filenames {
- switch info, err := os.Stat(filename); {
- case err != nil:
- report(err)
- case info.IsRegular():
- if allFiles || isGoFilename(info.Name) {
- filenames[i] = filename
- i++
- }
- case info.IsDirectory():
- if allFiles || *recursive {
- processDirectory(filename)
- }
- }
- }
- fset := token.NewFileSet()
- processPackage(fset, parseFiles(fset, filenames[0:i]))
-}
-
-
-func processPackage(fset *token.FileSet, files map[string]*ast.File) {
- // make a package (resolve all identifiers)
- pkg, err := ast.NewPackage(fset, files, types.GcImporter, types.Universe)
- if err != nil {
- report(err)
- return
- }
- _, err = types.Check(fset, pkg)
- if err != nil {
- report(err)
- }
-}
-
-
-func main() {
- flag.Usage = usage
- flag.Parse()
-
- if flag.NArg() == 0 {
- fset := token.NewFileSet()
- processPackage(fset, parseStdin(fset))
- } else {
- processFiles(flag.Args(), true)
- }
-
- os.Exit(exitCode)
-}
diff --git a/src/cmd/gotype/gotype_test.go b/src/cmd/gotype/gotype_test.go
deleted file mode 100644
index 9c8f8f2a7..000000000
--- a/src/cmd/gotype/gotype_test.go
+++ /dev/null
@@ -1,52 +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 main
-
-import (
- "path/filepath"
- "runtime"
- "testing"
-)
-
-
-func runTest(t *testing.T, path, pkg string) {
- exitCode = 0
- *pkgName = pkg
- *recursive = false
-
- if pkg == "" {
- processFiles([]string{path}, true)
- } else {
- processDirectory(path)
- }
-
- if exitCode != 0 {
- t.Errorf("processing %s failed: exitCode = %d", path, exitCode)
- }
-}
-
-
-var tests = []struct {
- path string
- pkg string
-}{
- // individual files
- {"testdata/test1.go", ""},
-
- // directories
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/ast"), "ast"},
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/doc"), "doc"},
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/token"), "scanner"},
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/scanner"), "scanner"},
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/parser"), "parser"},
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/types"), "types"},
-}
-
-
-func Test(t *testing.T) {
- for _, test := range tests {
- runTest(t, test.path, test.pkg)
- }
-}
diff --git a/src/cmd/gotype/testdata/test1.go b/src/cmd/gotype/testdata/test1.go
deleted file mode 100644
index 0bd46568d..000000000
--- a/src/cmd/gotype/testdata/test1.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package p
-
-func _() {
- // the scope of a local type declaration starts immediately after the type name
- type T struct{ _ *T }
-}
diff --git a/src/cmd/govet/Makefile b/src/cmd/govet/Makefile
deleted file mode 100644
index f565b78f5..000000000
--- a/src/cmd/govet/Makefile
+++ /dev/null
@@ -1,14 +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 ../../Make.inc
-
-TARG=govet
-GOFILES=\
- govet.go\
-
-include ../../Make.cmd
-
-test testshort: $(TARG)
- ../../../test/errchk $(TARG) -printfuncs='Warn:1,Warnf:1' govet.go
diff --git a/src/cmd/govet/doc.go b/src/cmd/govet/doc.go
deleted file mode 100644
index 5a2489fca..000000000
--- a/src/cmd/govet/doc.go
+++ /dev/null
@@ -1,38 +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.
-
-/*
-
-Govet does simple checking of Go source code.
-
-It checks for simple errors in calls to functions named
- Print Printf Println
- Fprint Fprintf Fprintln
- Sprint Sprintf Sprintln
- Error Errorf
- Fatal Fatalf
-If the function name ends with an 'f', the function is assumed to take
-a format descriptor string in the manner of fmt.Printf. If not, govet
-complains about arguments that look like format descriptor strings.
-
-Usage:
-
- govet [flag] [file.go ...]
- govet [flag] [directory ...] # Scan all .go files under directory, recursively
-
-The flags are:
- -v
- Verbose mode
- -printfuncs
- A comma-separated list of print-like functions to supplement
- the standard list. Each entry is in the form Name:N where N
- is the zero-based argument position of the first argument
- involved in the print: either the format or the first print
- argument for non-formatted prints. For example,
- if you have Warn and Warnf functions that take an
- io.Writer as their first argument, like Fprintf,
- -printfuncs=Warn:1,Warnf:1
-
-*/
-package documentation
diff --git a/src/cmd/govet/govet.go b/src/cmd/govet/govet.go
deleted file mode 100644
index 5b24d2ff0..000000000
--- a/src/cmd/govet/govet.go
+++ /dev/null
@@ -1,405 +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.
-
-// Govet is a simple checker for static errors in Go source code.
-// See doc.go for more information.
-package main
-
-import (
- "flag"
- "fmt"
- "io"
- "go/ast"
- "go/parser"
- "go/token"
- "os"
- "path/filepath"
- "reflect"
- "strconv"
- "strings"
- "utf8"
-)
-
-var verbose = flag.Bool("v", false, "verbose")
-var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")
-var exitCode = 0
-
-// setExit sets the value for os.Exit when it is called, later. It
-// remembers the highest value.
-func setExit(err int) {
- if err > exitCode {
- exitCode = err
- }
-}
-
-// Usage is a replacement usage function for the flags package.
-func Usage() {
- fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-// File is a wrapper for the state of a file used in the parser.
-// The parse tree walkers are all methods of this type.
-type File struct {
- file *token.File
-}
-
-func main() {
- flag.Usage = Usage
- flag.Parse()
-
- if *printfuncs != "" {
- for _, name := range strings.Split(*printfuncs, ",") {
- if len(name) == 0 {
- flag.Usage()
- }
- skip := 0
- if colon := strings.LastIndex(name, ":"); colon > 0 {
- var err os.Error
- skip, err = strconv.Atoi(name[colon+1:])
- if err != nil {
- errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
- }
- name = name[:colon]
- }
- name = strings.ToLower(name)
- if name[len(name)-1] == 'f' {
- printfList[name] = skip
- } else {
- printList[name] = skip
- }
- }
- }
-
- if flag.NArg() == 0 {
- doFile("stdin", os.Stdin)
- } else {
- for _, name := range flag.Args() {
- // Is it a directory?
- if fi, err := os.Stat(name); err == nil && fi.IsDirectory() {
- walkDir(name)
- } else {
- doFile(name, nil)
- }
- }
- }
- os.Exit(exitCode)
-}
-
-// doFile analyzes one file. If the reader is nil, the source code is read from the
-// named file.
-func doFile(name string, reader io.Reader) {
- fs := token.NewFileSet()
- parsedFile, err := parser.ParseFile(fs, name, reader, 0)
- if err != nil {
- errorf("%s: %s", name, err)
- return
- }
- file := &File{fs.File(parsedFile.Pos())}
- file.checkFile(name, parsedFile)
-}
-
-// Visitor for filepath.Walk - trivial. Just calls doFile on each file.
-// TODO: if govet becomes richer, might want to process
-// a directory (package) at a time.
-type V struct{}
-
-func (v V) VisitDir(path string, f *os.FileInfo) bool {
- return true
-}
-
-func (v V) VisitFile(path string, f *os.FileInfo) {
- if strings.HasSuffix(path, ".go") {
- doFile(path, nil)
- }
-}
-
-// walkDir recursively walks the tree looking for .go files.
-func walkDir(root string) {
- errors := make(chan os.Error)
- done := make(chan bool)
- go func() {
- for e := range errors {
- errorf("walk error: %s", e)
- }
- done <- true
- }()
- filepath.Walk(root, V{}, errors)
- close(errors)
- <-done
-}
-
-// error formats the error to standard error, adding program
-// identification and a newline
-func errorf(format string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "govet: "+format+"\n", args...)
- setExit(2)
-}
-
-// Println is fmt.Println guarded by -v.
-func Println(args ...interface{}) {
- if !*verbose {
- return
- }
- fmt.Println(args...)
-}
-
-// Printf is fmt.Printf guarded by -v.
-func Printf(format string, args ...interface{}) {
- if !*verbose {
- return
- }
- fmt.Printf(format+"\n", args...)
-}
-
-// Bad reports an error and sets the exit code..
-func (f *File) Bad(pos token.Pos, args ...interface{}) {
- f.Warn(pos, args...)
- setExit(1)
-}
-
-// Badf reports a formatted error and sets the exit code.
-func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
- f.Warnf(pos, format, args...)
- setExit(1)
-}
-
-// Warn reports an error but does not set the exit code.
-func (f *File) Warn(pos token.Pos, args ...interface{}) {
- loc := f.file.Position(pos).String() + ": "
- fmt.Fprint(os.Stderr, loc+fmt.Sprintln(args...))
-}
-
-// Warnf reports a formatted error but does not set the exit code.
-func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
- loc := f.file.Position(pos).String() + ": "
- fmt.Fprintf(os.Stderr, loc+format+"\n", args...)
-}
-
-// checkFile checks all the top-level declarations in a file.
-func (f *File) checkFile(name string, file *ast.File) {
- Println("Checking file", name)
- ast.Walk(f, file)
-}
-
-// Visit implements the ast.Visitor interface.
-func (f *File) Visit(node ast.Node) ast.Visitor {
- switch n := node.(type) {
- case *ast.CallExpr:
- f.checkCallExpr(n)
- case *ast.Field:
- f.checkFieldTag(n)
- }
- return f
-}
-
-// checkField checks a struct field tag.
-func (f *File) checkFieldTag(field *ast.Field) {
- if field.Tag == nil {
- return
- }
-
- tag, err := strconv.Unquote(field.Tag.Value)
- if err != nil {
- f.Warnf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
- return
- }
-
- // Check tag for validity by appending
- // new key:value to end and checking that
- // the tag parsing code can find it.
- if reflect.StructTag(tag+` _gofix:"_magic"`).Get("_gofix") != "_magic" {
- f.Warnf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get", field.Tag.Value)
- return
- }
-}
-
-// checkCallExpr checks a call expression.
-func (f *File) checkCallExpr(call *ast.CallExpr) {
- switch x := call.Fun.(type) {
- case *ast.Ident:
- f.checkCall(call, x.Name)
- case *ast.SelectorExpr:
- f.checkCall(call, x.Sel.Name)
- }
-}
-
-// printfList records the formatted-print functions. The value is the location
-// of the format parameter. Names are lower-cased so the lookup is
-// case insensitive.
-var printfList = map[string]int{
- "errorf": 0,
- "fatalf": 0,
- "fprintf": 1,
- "panicf": 0,
- "printf": 0,
- "sprintf": 0,
-}
-
-// printList records the unformatted-print functions. The value is the location
-// of the first parameter to be printed. Names are lower-cased so the lookup is
-// case insensitive.
-var printList = map[string]int{
- "error": 0,
- "fatal": 0,
- "fprint": 1, "fprintln": 1,
- "panic": 0, "panicln": 0,
- "print": 0, "println": 0,
- "sprint": 0, "sprintln": 0,
-}
-
-// checkCall triggers the print-specific checks if the call invokes a print function.
-func (f *File) checkCall(call *ast.CallExpr, Name string) {
- name := strings.ToLower(Name)
- if skip, ok := printfList[name]; ok {
- f.checkPrintf(call, Name, skip)
- return
- }
- if skip, ok := printList[name]; ok {
- f.checkPrint(call, Name, skip)
- return
- }
-}
-
-// checkPrintf checks a call to a formatted print routine such as Printf.
-// The skip argument records how many arguments to ignore; that is,
-// call.Args[skip] is (well, should be) the format argument.
-func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
- if len(call.Args) <= skip {
- return
- }
- // Common case: literal is first argument.
- arg := call.Args[skip]
- lit, ok := arg.(*ast.BasicLit)
- if !ok {
- // Too hard to check.
- if *verbose {
- f.Warn(call.Pos(), "can't check args for call to", name)
- }
- return
- }
- if lit.Kind == token.STRING {
- if !strings.Contains(lit.Value, "%") {
- if len(call.Args) > skip+1 {
- f.Badf(call.Pos(), "no formatting directive in %s call", name)
- }
- return
- }
- }
- // Hard part: check formats against args.
- // Trivial but useful test: count.
- numArgs := 0
- for i, w := 0, 0; i < len(lit.Value); i += w {
- w = 1
- if lit.Value[i] == '%' {
- nbytes, nargs := parsePrintfVerb(lit.Value[i:])
- w = nbytes
- numArgs += nargs
- }
- }
- expect := len(call.Args) - (skip + 1)
- if numArgs != expect {
- f.Badf(call.Pos(), "wrong number of args in %s call: %d needed but %d args", name, numArgs, expect)
- }
-}
-
-// parsePrintfVerb returns the number of bytes and number of arguments
-// consumed by the Printf directive that begins s, including its percent sign
-// and verb.
-func parsePrintfVerb(s string) (nbytes, nargs int) {
- // There's guaranteed a percent sign.
- nbytes = 1
- end := len(s)
- // There may be flags.
-FlagLoop:
- for nbytes < end {
- switch s[nbytes] {
- case '#', '0', '+', '-', ' ':
- nbytes++
- default:
- break FlagLoop
- }
- }
- getNum := func() {
- if nbytes < end && s[nbytes] == '*' {
- nbytes++
- nargs++
- } else {
- for nbytes < end && '0' <= s[nbytes] && s[nbytes] <= '9' {
- nbytes++
- }
- }
- }
- // There may be a width.
- getNum()
- // If there's a period, there may be a precision.
- if nbytes < end && s[nbytes] == '.' {
- nbytes++
- getNum()
- }
- // Now a verb.
- c, w := utf8.DecodeRuneInString(s[nbytes:])
- nbytes += w
- if c != '%' {
- nargs++
- }
- return
-}
-
-
-// checkPrint checks a call to an unformatted print routine such as Println.
-// The skip argument records how many arguments to ignore; that is,
-// call.Args[skip] is the first argument to be printed.
-func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) {
- isLn := strings.HasSuffix(name, "ln")
- args := call.Args
- if len(args) <= skip {
- if *verbose && !isLn {
- f.Badf(call.Pos(), "no args in %s call", name)
- }
- return
- }
- arg := args[skip]
- if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
- if strings.Contains(lit.Value, "%") {
- f.Badf(call.Pos(), "possible formatting directive in %s call", name)
- }
- }
- if isLn {
- // The last item, if a string, should not have a newline.
- arg = args[len(call.Args)-1]
- if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
- if strings.HasSuffix(lit.Value, `\n"`) {
- f.Badf(call.Pos(), "%s call ends with newline", name)
- }
- }
- }
-}
-
-// This function never executes, but it serves as a simple test for the program.
-// Test with make test.
-func BadFunctionUsedInTests() {
- fmt.Println() // not an error
- fmt.Println("%s", "hi") // ERROR "possible formatting directive in Println call"
- fmt.Printf("%s", "hi", 3) // ERROR "wrong number of args in Printf call"
- fmt.Printf("%s%%%d", "hi", 3) // correct
- fmt.Printf("%.*d", 3, 3) // correct
- fmt.Printf("%.*d", 3, 3, 3) // ERROR "wrong number of args in Printf call"
- printf("now is the time", "buddy") // ERROR "no formatting directive"
- Printf("now is the time", "buddy") // ERROR "no formatting directive"
- Printf("hi") // ok
- f := new(File)
- f.Warn(0, "%s", "hello", 3) // ERROR "possible formatting directive in Warn call"
- f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args in Warnf call"
-}
-
-type BadTypeUsedInTests struct {
- X int "hello" // ERROR "struct field tag"
-}
-
-// printf is used by the test.
-func printf(format string, args ...interface{}) {
- panic("don't call - testing only")
-}
diff --git a/src/cmd/goyacc/Makefile b/src/cmd/goyacc/Makefile
deleted file mode 100644
index ac0f427cc..000000000
--- a/src/cmd/goyacc/Makefile
+++ /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 ../../Make.inc
-
-TARG=goyacc
-GOFILES=\
- goyacc.go\
-
-include ../../Make.cmd
-
-units: goyacc units.y
- ./goyacc -p units_ units.y
- $(GC) y.go
- $(LD) -o units y.$O
-
diff --git a/src/cmd/goyacc/doc.go b/src/cmd/goyacc/doc.go
deleted file mode 100644
index 5dd6abe69..000000000
--- a/src/cmd/goyacc/doc.go
+++ /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.
-
-/*
-
-Goyacc is a version of yacc for Go.
-It is written in Go and generates parsers written in Go.
-
-It is largely transliterated from the Inferno version written in Limbo
-which in turn was largely transliterated from the Plan 9 version
-written in C and documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/yacc
-
-Yacc adepts will have no trouble adapting to this form of the tool.
-
-The file units.y in this directory is a yacc grammar for a version of
-the Unix tool units, also written in Go and largely transliterated
-from the Plan 9 C version. It needs the flag "-p units_" (see
-below).
-
-The generated parser is reentrant. Parse expects to be given an
-argument that conforms to the following interface:
-
- type yyLexer interface {
- Lex(lval *yySymType) int
- Error(e string)
- }
-
-Lex should return the token identifier, and place other token
-information in lval (which replaces the usual yylval).
-Error is equivalent to yyerror in the original yacc.
-
-Code inside the parser may refer to the variable yylex,
-which holds the yyLexer passed to Parse.
-
-Multiple grammars compiled into a single program should be placed in
-distinct packages. If that is impossible, the "-p prefix" flag to
-goyacc sets the prefix, by default yy, that begins the names of
-symbols, including types, the parser, and the lexer, generated and
-referenced by goyacc's generated code. Setting it to distinct values
-allows multiple grammars to be placed in a single package.
-
-*/
-package documentation
diff --git a/src/cmd/goyacc/goyacc.go b/src/cmd/goyacc/goyacc.go
deleted file mode 100644
index 543f8b1e8..000000000
--- a/src/cmd/goyacc/goyacc.go
+++ /dev/null
@@ -1,3311 +0,0 @@
-/*
-Derived from Inferno's utils/iyacc/yacc.c
-http://code.google.com/p/inferno-os/source/browse/utils/iyacc/yacc.c
-
-This copyright NOTICE applies to all files in this directory and
-subdirectories, unless another copyright notice appears in a given
-file or subdirectory. If you take substantial code from this software to use in
-other programs, you must somehow include with it an appropriate
-copyright notice that includes the copyright notice and the other
-notices below. It is fine (and often tidier) to do that in a separate
-file such as NOTICE, LICENCE or COPYING.
-
- 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.
-*/
-
-package main
-
-// yacc
-// major difference is lack of stem ("y" variable)
-//
-
-import (
- "flag"
- "fmt"
- "bufio"
- "os"
- "strings"
- "bytes"
-)
-
-// the following are adjustable
-// according to memory size
-const (
- ACTSIZE = 30000
- NSTATES = 2000
- TEMPSIZE = 2000
-
- SYMINC = 50 // increase for non-term or term
- RULEINC = 50 // increase for max rule length prodptr[i]
- PRODINC = 100 // increase for productions prodptr
- WSETINC = 50 // increase for working sets wsets
- STATEINC = 200 // increase for states statemem
-
- NAMESIZE = 50
- NTYPES = 63
- ISIZE = 400
-
- PRIVATE = 0xE000 // unicode private use
-
- // relationships which must hold:
- // TEMPSIZE >= NTERMS + NNONTERM + 1;
- // TEMPSIZE >= NSTATES;
- //
-
- NTBASE = 010000
- ERRCODE = 8190
- ACCEPTCODE = 8191
- YYLEXUNK = 3
- TOKSTART = 4 //index of first defined token
-)
-
-// no, left, right, binary assoc.
-const (
- NOASC = iota
- LASC
- RASC
- BASC
-)
-
-// flags for state generation
-const (
- DONE = iota
- MUSTDO
- MUSTLOOKAHEAD
-)
-
-// flags for a rule having an action, and being reduced
-const (
- ACTFLAG = 1 << (iota + 2)
- REDFLAG
-)
-
-// output parser flags
-const yyFlag = -1000
-
-// parse tokens
-const (
- IDENTIFIER = PRIVATE + iota
- MARK
- TERM
- LEFT
- RIGHT
- BINARY
- PREC
- LCURLY
- IDENTCOLON
- NUMBER
- START
- TYPEDEF
- TYPENAME
- UNION
-)
-
-const ENDFILE = 0
-const EMPTY = 1
-const WHOKNOWS = 0
-const OK = 1
-const NOMORE = -1000
-
-// macros for getting associativity and precedence levels
-func ASSOC(i int) int { return i & 3 }
-
-func PLEVEL(i int) int { return (i >> 4) & 077 }
-
-func TYPE(i int) int { return (i >> 10) & 077 }
-
-// macros for setting associativity and precedence levels
-func SETASC(i, j int) int { return i | j }
-
-func SETPLEV(i, j int) int { return i | (j << 4) }
-
-func SETTYPE(i, j int) int { return i | (j << 10) }
-
-// I/O descriptors
-var finput *bufio.Reader // input file
-var stderr *bufio.Writer
-var ftable *bufio.Writer // y.go file
-var fcode = &bytes.Buffer{} // saved code
-var foutput *bufio.Writer // y.output file
-
-var oflag string // -o [y.go] - y.go file
-var vflag string // -v [y.output] - y.output file
-var lflag bool // -l - disable line directives
-var prefix string // name prefix for identifiers, default yy
-
-func init() {
- flag.StringVar(&oflag, "o", "y.go", "parser output")
- flag.StringVar(&prefix, "p", "yy", "name prefix to use in generated code")
- flag.StringVar(&vflag, "v", "y.output", "create parsing tables")
- flag.BoolVar(&lflag, "l", false, "disable line directives")
-}
-
-var stacksize = 200
-
-// communication variables between various I/O routines
-var infile string // input file name
-var numbval int // value of an input number
-var tokname string // input token name, slop for runes and 0
-var tokflag = false
-
-// structure declarations
-type Lkset []int
-
-type Pitem struct {
- prod []int
- off int // offset within the production
- first int // first term or non-term in item
- prodno int // production number for sorting
-}
-
-type Item struct {
- pitem Pitem
- look Lkset
-}
-
-type Symb struct {
- name string
- value int
-}
-
-type Wset struct {
- pitem Pitem
- flag int
- ws Lkset
-}
-
-// storage of types
-var ntypes int // number of types defined
-var typeset [NTYPES]string // pointers to type tags
-
-// token information
-
-var ntokens = 0 // number of tokens
-var tokset []Symb
-var toklev []int // vector with the precedence of the terminals
-
-// nonterminal information
-
-var nnonter = -1 // the number of nonterminals
-var nontrst []Symb
-var start int // start symbol
-
-// state information
-
-var nstate = 0 // number of states
-var pstate = make([]int, NSTATES+2) // index into statemem to the descriptions of the states
-var statemem []Item
-var tystate = make([]int, NSTATES) // contains type information about the states
-var tstates []int // states generated by terminal gotos
-var ntstates []int // states generated by nonterminal gotos
-var mstates = make([]int, NSTATES) // chain of overflows of term/nonterm generation lists
-var lastred int // number of last reduction of a state
-var defact = make([]int, NSTATES) // default actions of states
-
-// lookahead set information
-
-var lkst []Lkset
-var nolook = 0 // flag to turn off lookahead computations
-var tbitset = 0 // size of lookahead sets
-var clset Lkset // temporary storage for lookahead computations
-
-// working set information
-
-var wsets []Wset
-var cwp int
-
-// storage for action table
-
-var amem []int // action table storage
-var memp int // next free action table position
-var indgo = make([]int, NSTATES) // index to the stored goto table
-
-// temporary vector, indexable by states, terms, or ntokens
-
-var temp1 = make([]int, TEMPSIZE) // temporary storage, indexed by terms + ntokens or states
-var lineno = 1 // current input line number
-var fatfl = 1 // if on, error is fatal
-var nerrors = 0 // number of errors
-
-// assigned token type values
-
-var extval = 0
-
-// grammar rule information
-
-var nprod = 1 // number of productions
-var prdptr [][]int // pointers to descriptions of productions
-var levprd []int // precedence levels for the productions
-var rlines []int // line number for this rule
-
-// statistics collection variables
-
-var zzgoent = 0
-var zzgobest = 0
-var zzacent = 0
-var zzexcp = 0
-var zzclose = 0
-var zzrrconf = 0
-var zzsrconf = 0
-var zzstate = 0
-
-// optimizer arrays
-
-var yypgo [][]int
-var optst [][]int
-var ggreed []int
-var pgo []int
-
-var maxspr int // maximum spread of any entry
-var maxoff int // maximum offset into a array
-var maxa int
-
-// storage for information about the nonterminals
-
-var pres [][][]int // vector of pointers to productions yielding each nonterminal
-var pfirst []Lkset
-var pempty []int // vector of nonterminals nontrivially deriving e
-
-// random stuff picked out from between functions
-
-var indebug = 0 // debugging flag for cpfir
-var pidebug = 0 // debugging flag for putitem
-var gsdebug = 0 // debugging flag for stagen
-var cldebug = 0 // debugging flag for closure
-var pkdebug = 0 // debugging flag for apack
-var g2debug = 0 // debugging for go2gen
-var adb = 0 // debugging for callopt
-
-type Resrv struct {
- name string
- value int
-}
-
-var resrv = []Resrv{
- {"binary", BINARY},
- {"left", LEFT},
- {"nonassoc", BINARY},
- {"prec", PREC},
- {"right", RIGHT},
- {"start", START},
- {"term", TERM},
- {"token", TERM},
- {"type", TYPEDEF},
- {"union", UNION},
- {"struct", UNION},
-}
-
-var zznewstate = 0
-
-const EOF = -1
-const UTFmax = 0x3f
-
-func main() {
-
- setup() // initialize and read productions
-
- tbitset = (ntokens + 32) / 32
- cpres() // make table of which productions yield a given nonterminal
- cempty() // make a table of which nonterminals can match the empty string
- cpfir() // make a table of firsts of nonterminals
-
- stagen() // generate the states
-
- yypgo = make([][]int, nnonter+1)
- optst = make([][]int, nstate)
- output() // write the states and the tables
- go2out()
-
- hideprod()
- summary()
-
- callopt()
-
- others()
-
- exit(0)
-}
-
-func setup() {
- var j, ty int
-
- stderr = bufio.NewWriter(os.NewFile(2, "stderr"))
- foutput = nil
-
- flag.Parse()
- if flag.NArg() != 1 {
- usage()
- }
- if stacksize < 1 {
- // never set so cannot happen
- fmt.Fprintf(stderr, "yacc: stack size too small\n")
- usage()
- }
- yaccpar = strings.Replace(yaccpartext, "$$", prefix, -1)
- openup()
-
- defin(0, "$end")
- extval = PRIVATE // tokens start in unicode 'private use'
- defin(0, "error")
- defin(1, "$accept")
- defin(0, "$unk")
- i := 0
-
- t := gettok()
-
-outer:
- for {
- switch t {
- default:
- errorf("syntax error tok=%v", t-PRIVATE)
-
- case MARK, ENDFILE:
- break outer
-
- case ';':
-
- case START:
- t = gettok()
- if t != IDENTIFIER {
- errorf("bad %%start construction")
- }
- start = chfind(1, tokname)
-
- case TYPEDEF:
- t = gettok()
- if t != TYPENAME {
- errorf("bad syntax in %%type")
- }
- ty = numbval
- for {
- t = gettok()
- switch t {
- case IDENTIFIER:
- t = chfind(1, tokname)
- if t < NTBASE {
- j = TYPE(toklev[t])
- if j != 0 && j != ty {
- errorf("type redeclaration of token ",
- tokset[t].name)
- } else {
- toklev[t] = SETTYPE(toklev[t], ty)
- }
- } else {
- j = nontrst[t-NTBASE].value
- if j != 0 && j != ty {
- errorf("type redeclaration of nonterminal %v",
- nontrst[t-NTBASE].name)
- } else {
- nontrst[t-NTBASE].value = ty
- }
- }
- continue
-
- case ',':
- continue
- }
- break
- }
- continue
-
- case UNION:
- cpyunion()
-
- case LEFT, BINARY, RIGHT, TERM:
- // nonzero means new prec. and assoc.
- lev := t - TERM
- if lev != 0 {
- i++
- }
- ty = 0
-
- // get identifiers so defined
- t = gettok()
-
- // there is a type defined
- if t == TYPENAME {
- ty = numbval
- t = gettok()
- }
- for {
- switch t {
- case ',':
- t = gettok()
- continue
-
- case ';':
- break
-
- case IDENTIFIER:
- j = chfind(0, tokname)
- if j >= NTBASE {
- errorf("%v defined earlier as nonterminal", tokname)
- }
- if lev != 0 {
- if ASSOC(toklev[j]) != 0 {
- errorf("redeclaration of precedence of %v", tokname)
- }
- toklev[j] = SETASC(toklev[j], lev)
- toklev[j] = SETPLEV(toklev[j], i)
- }
- if ty != 0 {
- if TYPE(toklev[j]) != 0 {
- errorf("redeclaration of type of %v", tokname)
- }
- toklev[j] = SETTYPE(toklev[j], ty)
- }
- t = gettok()
- if t == NUMBER {
- tokset[j].value = numbval
- t = gettok()
- }
-
- continue
- }
- break
- }
- continue
-
- case LCURLY:
- cpycode()
- }
- t = gettok()
- }
-
- if t == ENDFILE {
- errorf("unexpected EOF before %%")
- }
-
- // put out non-literal terminals
- for i := TOKSTART; i <= ntokens; i++ {
- // non-literals
- c := tokset[i].name[0]
- if c != ' ' && c != '$' {
- fmt.Fprintf(ftable, "const\t%v\t= %v\n", tokset[i].name, tokset[i].value)
- }
- }
-
- // put out names of token names
- fmt.Fprintf(ftable, "var\t%sToknames\t =[]string {\n", prefix)
- for i := TOKSTART; i <= ntokens; i++ {
- fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name)
- }
- fmt.Fprintf(ftable, "}\n")
-
- // put out names of state names
- fmt.Fprintf(ftable, "var\t%sStatenames\t =[]string {\n", prefix)
- // for i:=TOKSTART; i<=ntokens; i++ {
- // fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
- // }
- fmt.Fprintf(ftable, "}\n")
-
- fmt.Fprintf(fcode, "switch %snt {\n", prefix)
-
- moreprod()
- prdptr[0] = []int{NTBASE, start, 1, 0}
-
- nprod = 1
- curprod := make([]int, RULEINC)
- t = gettok()
- if t != IDENTCOLON {
- errorf("bad syntax on first rule")
- }
-
- if start == 0 {
- prdptr[0][1] = chfind(1, tokname)
- }
-
- // read rules
- // put into prdptr array in the format
- // target
- // followed by id's of terminals and non-terminals
- // followd by -nprod
-
- for t != MARK && t != ENDFILE {
- mem := 0
-
- // process a rule
- rlines[nprod] = lineno
- if t == '|' {
- curprod[mem] = prdptr[nprod-1][0]
- mem++
- } else if t == IDENTCOLON {
- curprod[mem] = chfind(1, tokname)
- if curprod[mem] < NTBASE {
- errorf("token illegal on LHS of grammar rule")
- }
- mem++
- } else {
- errorf("illegal rule: missing semicolon or | ?")
- }
-
- // read rule body
- t = gettok()
- for {
- for t == IDENTIFIER {
- curprod[mem] = chfind(1, tokname)
- if curprod[mem] < NTBASE {
- levprd[nprod] = toklev[curprod[mem]]
- }
- mem++
- if mem >= len(curprod) {
- ncurprod := make([]int, mem+RULEINC)
- copy(ncurprod, curprod)
- curprod = ncurprod
- }
- t = gettok()
- }
- if t == PREC {
- if gettok() != IDENTIFIER {
- errorf("illegal %%prec syntax")
- }
- j = chfind(2, tokname)
- if j >= NTBASE {
- errorf("nonterminal " + nontrst[j-NTBASE].name + " illegal after %%prec")
- }
- levprd[nprod] = toklev[j]
- t = gettok()
- }
- if t != '=' {
- break
- }
- levprd[nprod] |= ACTFLAG
- fmt.Fprintf(fcode, "\ncase %v:", nprod)
- cpyact(curprod, mem)
-
- // action within rule...
- t = gettok()
- if t == IDENTIFIER {
- // make it a nonterminal
- j = chfind(1, fmt.Sprintf("$$%v", nprod))
-
- //
- // the current rule will become rule number nprod+1
- // enter null production for action
- //
- prdptr[nprod] = make([]int, 2)
- prdptr[nprod][0] = j
- prdptr[nprod][1] = -nprod
-
- // update the production information
- nprod++
- moreprod()
- levprd[nprod] = levprd[nprod-1] & ^ACTFLAG
- levprd[nprod-1] = ACTFLAG
- rlines[nprod] = lineno
-
- // make the action appear in the original rule
- curprod[mem] = j
- mem++
- if mem >= len(curprod) {
- ncurprod := make([]int, mem+RULEINC)
- copy(ncurprod, curprod)
- curprod = ncurprod
- }
- }
- }
-
- for t == ';' {
- t = gettok()
- }
- curprod[mem] = -nprod
- mem++
-
- // check that default action is reasonable
- if ntypes != 0 && (levprd[nprod]&ACTFLAG) == 0 &&
- nontrst[curprod[0]-NTBASE].value != 0 {
- // no explicit action, LHS has value
- tempty := curprod[1]
- if tempty < 0 {
- errorf("must return a value, since LHS has a type")
- }
- if tempty >= NTBASE {
- tempty = nontrst[tempty-NTBASE].value
- } else {
- tempty = TYPE(toklev[tempty])
- }
- if tempty != nontrst[curprod[0]-NTBASE].value {
- errorf("default action causes potential type clash")
- }
- fmt.Fprintf(fcode, "\ncase %v:", nprod)
- fmt.Fprintf(fcode, "\n\t%sVAL.%v = %sS[%spt-0].%v;",
- prefix, typeset[tempty], prefix, prefix, typeset[tempty])
- }
- moreprod()
- prdptr[nprod] = make([]int, mem)
- copy(prdptr[nprod], curprod)
- nprod++
- moreprod()
- levprd[nprod] = 0
- }
-
- //
- // end of all rules
- // dump out the prefix code
- //
-
- fmt.Fprintf(fcode, "\n\t}")
-
- fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
- fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
- fmt.Fprintf(ftable, "const %sMaxDepth = %v\n", prefix, stacksize)
-
- //
- // copy any postfix code
- //
- if t == MARK {
- if !lflag {
- fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
- }
- for {
- c := getrune(finput)
- if c == EOF {
- break
- }
- ftable.WriteRune(c)
- }
- }
-}
-
-//
-// allocate enough room to hold another production
-//
-func moreprod() {
- n := len(prdptr)
- if nprod >= n {
- nn := n + PRODINC
- aprod := make([][]int, nn)
- alevprd := make([]int, nn)
- arlines := make([]int, nn)
-
- copy(aprod, prdptr)
- copy(alevprd, levprd)
- copy(arlines, rlines)
-
- prdptr = aprod
- levprd = alevprd
- rlines = arlines
- }
-}
-
-//
-// define s to be a terminal if t=0
-// or a nonterminal if t=1
-//
-func defin(nt int, s string) int {
- val := 0
- if nt != 0 {
- nnonter++
- if nnonter >= len(nontrst) {
- anontrst := make([]Symb, nnonter+SYMINC)
- copy(anontrst, nontrst)
- nontrst = anontrst
- }
- nontrst[nnonter] = Symb{s, 0}
- return NTBASE + nnonter
- }
-
- // must be a token
- ntokens++
- if ntokens >= len(tokset) {
- nn := ntokens + SYMINC
- atokset := make([]Symb, nn)
- atoklev := make([]int, nn)
-
- copy(atoklev, toklev)
- copy(atokset, tokset)
-
- tokset = atokset
- toklev = atoklev
- }
- tokset[ntokens].name = s
- toklev[ntokens] = 0
-
- // establish value for token
- // single character literal
- if s[0] == ' ' && len(s) == 1+1 {
- val = int(s[1])
- } else if s[0] == ' ' && s[1] == '\\' { // escape sequence
- if len(s) == 2+1 {
- // single character escape sequence
- switch s[2] {
- case '\'':
- val = '\''
- case '"':
- val = '"'
- case '\\':
- val = '\\'
- case 'a':
- val = '\a'
- case 'b':
- val = '\b'
- case 'n':
- val = '\n'
- case 'r':
- val = '\r'
- case 't':
- val = '\t'
- case 'v':
- val = '\v'
- default:
- errorf("invalid escape %v", s[1:3])
- }
- } else if s[2] == 'u' && len(s) == 2+1+4 { // \unnnn sequence
- val = 0
- s = s[3:]
- for s != "" {
- c := int(s[0])
- switch {
- case c >= '0' && c <= '9':
- c -= '0'
- case c >= 'a' && c <= 'f':
- c -= 'a' - 10
- case c >= 'A' && c <= 'F':
- c -= 'A' - 10
- default:
- errorf("illegal \\unnnn construction")
- }
- val = val*16 + c
- s = s[1:]
- }
- if val == 0 {
- errorf("'\\u0000' is illegal")
- }
- } else {
- errorf("unknown escape")
- }
- } else {
- val = extval
- extval++
- }
-
- tokset[ntokens].value = val
- return ntokens
-}
-
-var peekline = 0
-
-func gettok() int {
- var i, match, c int
-
- tokname = ""
- for {
- lineno += peekline
- peekline = 0
- c = getrune(finput)
- for c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\r' {
- if c == '\n' {
- lineno++
- }
- c = getrune(finput)
- }
-
- // skip comment -- fix
- if c != '/' {
- break
- }
- lineno += skipcom()
- }
-
- switch c {
- case EOF:
- if tokflag {
- fmt.Printf(">>> ENDFILE %v\n", lineno)
- }
- return ENDFILE
-
- case '{':
- ungetrune(finput, c)
- if tokflag {
- fmt.Printf(">>> ={ %v\n", lineno)
- }
- return '='
-
- case '<':
- // get, and look up, a type name (union member name)
- c = getrune(finput)
- for c != '>' && c != EOF && c != '\n' {
- tokname += string(c)
- c = getrune(finput)
- }
-
- if c != '>' {
- errorf("unterminated < ... > clause")
- }
-
- for i = 1; i <= ntypes; i++ {
- if typeset[i] == tokname {
- numbval = i
- if tokflag {
- fmt.Printf(">>> TYPENAME old <%v> %v\n", tokname, lineno)
- }
- return TYPENAME
- }
- }
- ntypes++
- numbval = ntypes
- typeset[numbval] = tokname
- if tokflag {
- fmt.Printf(">>> TYPENAME new <%v> %v\n", tokname, lineno)
- }
- return TYPENAME
-
- case '"', '\'':
- match = c
- tokname = " "
- for {
- c = getrune(finput)
- if c == '\n' || c == EOF {
- errorf("illegal or missing ' or \"")
- }
- if c == '\\' {
- tokname += string('\\')
- c = getrune(finput)
- } else if c == match {
- if tokflag {
- fmt.Printf(">>> IDENTIFIER \"%v\" %v\n", tokname, lineno)
- }
- return IDENTIFIER
- }
- tokname += string(c)
- }
-
- case '%':
- c = getrune(finput)
- switch c {
- case '%':
- if tokflag {
- fmt.Printf(">>> MARK %%%% %v\n", lineno)
- }
- return MARK
- case '=':
- if tokflag {
- fmt.Printf(">>> PREC %%= %v\n", lineno)
- }
- return PREC
- case '{':
- if tokflag {
- fmt.Printf(">>> LCURLY %%{ %v\n", lineno)
- }
- return LCURLY
- }
-
- getword(c)
- // find a reserved word
- for c = 0; c < len(resrv); c++ {
- if tokname == resrv[c].name {
- if tokflag {
- fmt.Printf(">>> %%%v %v %v\n", tokname,
- resrv[c].value-PRIVATE, lineno)
- }
- return resrv[c].value
- }
- }
- errorf("invalid escape, or illegal reserved word: %v", tokname)
-
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- numbval = c - '0'
- for {
- c = getrune(finput)
- if !isdigit(c) {
- break
- }
- numbval = numbval*10 + c - '0'
- }
- ungetrune(finput, c)
- if tokflag {
- fmt.Printf(">>> NUMBER %v %v\n", numbval, lineno)
- }
- return NUMBER
-
- default:
- if isword(c) || c == '.' || c == '$' {
- getword(c)
- break
- }
- if tokflag {
- fmt.Printf(">>> OPERATOR %v %v\n", string(c), lineno)
- }
- return c
- }
-
- // look ahead to distinguish IDENTIFIER from IDENTCOLON
- c = getrune(finput)
- for c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\r' || c == '/' {
- if c == '\n' {
- peekline++
- }
- // look for comments
- if c == '/' {
- peekline += skipcom()
- }
- c = getrune(finput)
- }
- if c == ':' {
- if tokflag {
- fmt.Printf(">>> IDENTCOLON %v: %v\n", tokname, lineno)
- }
- return IDENTCOLON
- }
-
- ungetrune(finput, c)
- if tokflag {
- fmt.Printf(">>> IDENTIFIER %v %v\n", tokname, lineno)
- }
- return IDENTIFIER
-}
-
-func getword(c int) {
- tokname = ""
- for isword(c) || isdigit(c) || c == '_' || c == '.' || c == '$' {
- tokname += string(c)
- c = getrune(finput)
- }
- ungetrune(finput, c)
-}
-
-//
-// determine the type of a symbol
-//
-func fdtype(t int) int {
- var v int
- var s string
-
- if t >= NTBASE {
- v = nontrst[t-NTBASE].value
- s = nontrst[t-NTBASE].name
- } else {
- v = TYPE(toklev[t])
- s = tokset[t].name
- }
- if v <= 0 {
- errorf("must specify type for %v", s)
- }
- return v
-}
-
-func chfind(t int, s string) int {
- if s[0] == ' ' {
- t = 0
- }
- for i := 0; i <= ntokens; i++ {
- if s == tokset[i].name {
- return i
- }
- }
- for i := 0; i <= nnonter; i++ {
- if s == nontrst[i].name {
- return NTBASE + i
- }
- }
-
- // cannot find name
- if t > 1 {
- errorf("%v should have been defined earlier", s)
- }
- return defin(t, s)
-}
-
-//
-// copy the union declaration to the output, and the define file if present
-//
-func cpyunion() {
-
- if !lflag {
- fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
- }
- fmt.Fprintf(ftable, "type\t%sSymType\tstruct", prefix)
-
- level := 0
-
-out:
- for {
- c := getrune(finput)
- if c == EOF {
- errorf("EOF encountered while processing %%union")
- }
- ftable.WriteRune(c)
- switch c {
- case '\n':
- lineno++
- case '{':
- if level == 0 {
- fmt.Fprintf(ftable, "\n\tyys\tint;")
- }
- level++
- case '}':
- level--
- if level == 0 {
- break out
- }
- }
- }
- fmt.Fprintf(ftable, "\n")
-}
-
-//
-// saves code between %{ and %}
-//
-func cpycode() {
- lno := lineno
-
- c := getrune(finput)
- if c == '\n' {
- c = getrune(finput)
- lineno++
- }
- if !lflag {
- fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
- }
- for c != EOF {
- if c == '%' {
- c = getrune(finput)
- if c == '}' {
- return
- }
- ftable.WriteRune('%')
- }
- ftable.WriteRune(c)
- if c == '\n' {
- lineno++
- }
- c = getrune(finput)
- }
- lineno = lno
- errorf("eof before %%}")
-}
-
-//
-// skip over comments
-// skipcom is called after reading a '/'
-//
-func skipcom() int {
- var c int
-
- c = getrune(finput)
- if c == '/' {
- for c != EOF {
- if c == '\n' {
- return 1
- }
- c = getrune(finput)
- }
- errorf("EOF inside comment")
- return 0
- }
- if c != '*' {
- errorf("illegal comment")
- }
-
- nl := 0 // lines skipped
- c = getrune(finput)
-
-l1:
- switch c {
- case '*':
- c = getrune(finput)
- if c == '/' {
- break
- }
- goto l1
-
- case '\n':
- nl++
- fallthrough
-
- default:
- c = getrune(finput)
- goto l1
- }
- return nl
-}
-
-func dumpprod(curprod []int, max int) {
- fmt.Printf("\n")
- for i := 0; i < max; i++ {
- p := curprod[i]
- if p < 0 {
- fmt.Printf("[%v] %v\n", i, p)
- } else {
- fmt.Printf("[%v] %v\n", i, symnam(p))
- }
- }
-}
-
-//
-// copy action to the next ; or closing }
-//
-func cpyact(curprod []int, max int) {
-
- if !lflag {
- fmt.Fprintf(fcode, "\n//line %v:%v\n", infile, lineno)
- }
-
- lno := lineno
- brac := 0
-
-loop:
- for {
- c := getrune(finput)
-
- swt:
- switch c {
- case ';':
- if brac == 0 {
- ftable.WriteRune(c)
- return
- }
-
- case '{':
- if brac == 0 {
- }
- ftable.WriteRune('\t')
- brac++
-
- case '$':
- s := 1
- tok := -1
- c = getrune(finput)
-
- // type description
- if c == '<' {
- ungetrune(finput, c)
- if gettok() != TYPENAME {
- errorf("bad syntax on $<ident> clause")
- }
- tok = numbval
- c = getrune(finput)
- }
- if c == '$' {
- fmt.Fprintf(fcode, "%sVAL", prefix)
-
- // put out the proper tag...
- if ntypes != 0 {
- if tok < 0 {
- tok = fdtype(curprod[0])
- }
- fmt.Fprintf(fcode, ".%v", typeset[tok])
- }
- continue loop
- }
- if c == '-' {
- s = -s
- c = getrune(finput)
- }
- j := 0
- if isdigit(c) {
- for isdigit(c) {
- j = j*10 + c - '0'
- c = getrune(finput)
- }
- ungetrune(finput, c)
- j = j * s
- if j >= max {
- errorf("Illegal use of $%v", j)
- }
- } else if isword(c) || c == '_' || c == '.' {
- // look for $name
- ungetrune(finput, c)
- if gettok() != IDENTIFIER {
- errorf("$ must be followed by an identifier")
- }
- tokn := chfind(2, tokname)
- fnd := -1
- c = getrune(finput)
- if c != '@' {
- ungetrune(finput, c)
- } else if gettok() != NUMBER {
- errorf("@ must be followed by number")
- } else {
- fnd = numbval
- }
- for j = 1; j < max; j++ {
- if tokn == curprod[j] {
- fnd--
- if fnd <= 0 {
- break
- }
- }
- }
- if j >= max {
- errorf("$name or $name@number not found")
- }
- } else {
- fcode.WriteRune('$')
- if s < 0 {
- fcode.WriteRune('-')
- }
- ungetrune(finput, c)
- continue loop
- }
- fmt.Fprintf(fcode, "%sS[%spt-%v]", prefix, prefix, max-j-1)
-
- // put out the proper tag
- if ntypes != 0 {
- if j <= 0 && tok < 0 {
- errorf("must specify type of $%v", j)
- }
- if tok < 0 {
- tok = fdtype(curprod[j])
- }
- fmt.Fprintf(fcode, ".%v", typeset[tok])
- }
- continue loop
-
- case '}':
- brac--
- if brac != 0 {
- break
- }
- fcode.WriteRune(c)
- return
-
- case '/':
- nc := getrune(finput)
- if nc != '/' && nc != '*' {
- ungetrune(finput, nc)
- break
- }
- // a comment
- fcode.WriteRune(c)
- fcode.WriteRune(nc)
- c = getrune(finput)
- for c != EOF {
- switch {
- case c == '\n':
- lineno++
- if nc == '/' { // end of // comment
- break swt
- }
- case c == '*' && nc == '*': // end of /* comment?
- nnc := getrune(finput)
- if nnc == '/' {
- fcode.WriteRune('*')
- fcode.WriteRune('/')
- c = getrune(finput)
- break swt
- }
- ungetrune(finput, nnc)
- }
- fcode.WriteRune(c)
- c = getrune(finput)
- }
- errorf("EOF inside comment")
-
- case '\'', '"':
- // character string or constant
- match := c
- fcode.WriteRune(c)
- c = getrune(finput)
- for c != EOF {
- if c == '\\' {
- fcode.WriteRune(c)
- c = getrune(finput)
- if c == '\n' {
- lineno++
- }
- } else if c == match {
- break swt
- }
- if c == '\n' {
- errorf("newline in string or char const")
- }
- fcode.WriteRune(c)
- c = getrune(finput)
- }
- errorf("EOF in string or character constant")
-
- case EOF:
- lineno = lno
- errorf("action does not terminate")
-
- case '\n':
- lineno++
- }
-
- fcode.WriteRune(c)
- }
-}
-
-func openup() {
- infile = flag.Arg(0)
- finput = open(infile)
- if finput == nil {
- errorf("cannot open %v", infile)
- }
-
- foutput = nil
- if vflag != "" {
- foutput = create(vflag)
- if foutput == nil {
- errorf("can't create file %v", vflag)
- }
- }
-
- ftable = nil
- if oflag == "" {
- oflag = "y.go"
- }
- ftable = create(oflag)
- if ftable == nil {
- errorf("can't create file %v", oflag)
- }
-
-}
-
-//
-// return a pointer to the name of symbol i
-//
-func symnam(i int) string {
- var s string
-
- if i >= NTBASE {
- s = nontrst[i-NTBASE].name
- } else {
- s = tokset[i].name
- }
- if s[0] == ' ' {
- s = s[1:]
- }
- return s
-}
-
-//
-// set elements 0 through n-1 to c
-//
-func aryfil(v []int, n, c int) {
- for i := 0; i < n; i++ {
- v[i] = c
- }
-}
-
-//
-// compute an array with the beginnings of productions yielding given nonterminals
-// The array pres points to these lists
-// the array pyield has the lists: the total size is only NPROD+1
-//
-func cpres() {
- pres = make([][][]int, nnonter+1)
- curres := make([][]int, nprod)
-
- if false {
- for j := 0; j <= nnonter; j++ {
- fmt.Printf("nnonter[%v] = %v\n", j, nontrst[j].name)
- }
- for j := 0; j < nprod; j++ {
- fmt.Printf("prdptr[%v][0] = %v+NTBASE\n", j, prdptr[j][0]-NTBASE)
- }
- }
-
- fatfl = 0 // make undefined symbols nonfatal
- for i := 0; i <= nnonter; i++ {
- n := 0
- c := i + NTBASE
- for j := 0; j < nprod; j++ {
- if prdptr[j][0] == c {
- curres[n] = prdptr[j][1:]
- n++
- }
- }
- if n == 0 {
- errorf("nonterminal %v not defined", nontrst[i].name)
- continue
- }
- pres[i] = make([][]int, n)
- copy(pres[i], curres)
- }
- fatfl = 1
- if nerrors != 0 {
- summary()
- exit(1)
- }
-}
-
-func dumppres() {
- for i := 0; i <= nnonter; i++ {
- print("nonterm %d\n", i)
- curres := pres[i]
- for j := 0; j < len(curres); j++ {
- print("\tproduction %d:", j)
- prd := curres[j]
- for k := 0; k < len(prd); k++ {
- print(" %d", prd[k])
- }
- print("\n")
- }
- }
-}
-
-//
-// mark nonterminals which derive the empty string
-// also, look for nonterminals which don't derive any token strings
-//
-func cempty() {
- var i, p, np int
- var prd []int
-
- pempty = make([]int, nnonter+1)
-
- // first, use the array pempty to detect productions that can never be reduced
- // set pempty to WHONOWS
- aryfil(pempty, nnonter+1, WHOKNOWS)
-
- // now, look at productions, marking nonterminals which derive something
-more:
- for {
- for i = 0; i < nprod; i++ {
- prd = prdptr[i]
- if pempty[prd[0]-NTBASE] != 0 {
- continue
- }
- np = len(prd) - 1
- for p = 1; p < np; p++ {
- if prd[p] >= NTBASE && pempty[prd[p]-NTBASE] == WHOKNOWS {
- break
- }
- }
- // production can be derived
- if p == np {
- pempty[prd[0]-NTBASE] = OK
- continue more
- }
- }
- break
- }
-
- // now, look at the nonterminals, to see if they are all OK
- for i = 0; i <= nnonter; i++ {
- // the added production rises or falls as the start symbol ...
- if i == 0 {
- continue
- }
- if pempty[i] != OK {
- fatfl = 0
- errorf("nonterminal " + nontrst[i].name + " never derives any token string")
- }
- }
-
- if nerrors != 0 {
- summary()
- exit(1)
- }
-
- // now, compute the pempty array, to see which nonterminals derive the empty string
- // set pempty to WHOKNOWS
- aryfil(pempty, nnonter+1, WHOKNOWS)
-
- // loop as long as we keep finding empty nonterminals
-
-again:
- for {
- next:
- for i = 1; i < nprod; i++ {
- // not known to be empty
- prd = prdptr[i]
- if pempty[prd[0]-NTBASE] != WHOKNOWS {
- continue
- }
- np = len(prd) - 1
- for p = 1; p < np; p++ {
- if prd[p] < NTBASE || pempty[prd[p]-NTBASE] != EMPTY {
- continue next
- }
- }
-
- // we have a nontrivially empty nonterminal
- pempty[prd[0]-NTBASE] = EMPTY
-
- // got one ... try for another
- continue again
- }
- return
- }
-}
-
-func dumpempty() {
- for i := 0; i <= nnonter; i++ {
- if pempty[i] == EMPTY {
- print("non-term %d %s matches empty\n", i, symnam(i+NTBASE))
- }
- }
-}
-
-//
-// compute an array with the first of nonterminals
-//
-func cpfir() {
- var s, n, p, np, ch, i int
- var curres [][]int
- var prd []int
-
- wsets = make([]Wset, nnonter+WSETINC)
- pfirst = make([]Lkset, nnonter+1)
- for i = 0; i <= nnonter; i++ {
- wsets[i].ws = mkset()
- pfirst[i] = mkset()
- curres = pres[i]
- n = len(curres)
-
- // initially fill the sets
- for s = 0; s < n; s++ {
- prd = curres[s]
- np = len(prd) - 1
- for p = 0; p < np; p++ {
- ch = prd[p]
- if ch < NTBASE {
- setbit(pfirst[i], ch)
- break
- }
- if pempty[ch-NTBASE] == 0 {
- break
- }
- }
- }
- }
-
- // now, reflect transitivity
- changes := 1
- for changes != 0 {
- changes = 0
- for i = 0; i <= nnonter; i++ {
- curres = pres[i]
- n = len(curres)
- for s = 0; s < n; s++ {
- prd = curres[s]
- np = len(prd) - 1
- for p = 0; p < np; p++ {
- ch = prd[p] - NTBASE
- if ch < 0 {
- break
- }
- changes |= setunion(pfirst[i], pfirst[ch])
- if pempty[ch] == 0 {
- break
- }
- }
- }
- }
- }
-
- if indebug == 0 {
- return
- }
- if foutput != nil {
- for i = 0; i <= nnonter; i++ {
- fmt.Fprintf(foutput, "\n%v: %v %v\n",
- nontrst[i].name, pfirst[i], pempty[i])
- }
- }
-}
-
-//
-// generate the states
-//
-func stagen() {
- // initialize
- nstate = 0
- tstates = make([]int, ntokens+1) // states generated by terminal gotos
- ntstates = make([]int, nnonter+1) // states generated by nonterminal gotos
- amem = make([]int, ACTSIZE)
- memp = 0
-
- clset = mkset()
- pstate[0] = 0
- pstate[1] = 0
- aryfil(clset, tbitset, 0)
- putitem(Pitem{prdptr[0], 0, 0, 0}, clset)
- tystate[0] = MUSTDO
- nstate = 1
- pstate[2] = pstate[1]
-
- //
- // now, the main state generation loop
- // first pass generates all of the states
- // later passes fix up lookahead
- // could be sped up a lot by remembering
- // results of the first pass rather than recomputing
- //
- first := 1
- for more := 1; more != 0; first = 0 {
- more = 0
- for i := 0; i < nstate; i++ {
- if tystate[i] != MUSTDO {
- continue
- }
-
- tystate[i] = DONE
- aryfil(temp1, nnonter+1, 0)
-
- // take state i, close it, and do gotos
- closure(i)
-
- // generate goto's
- for p := 0; p < cwp; p++ {
- pi := wsets[p]
- if pi.flag != 0 {
- continue
- }
- wsets[p].flag = 1
- c := pi.pitem.first
- if c <= 1 {
- if pstate[i+1]-pstate[i] <= p {
- tystate[i] = MUSTLOOKAHEAD
- }
- continue
- }
-
- // do a goto on c
- putitem(wsets[p].pitem, wsets[p].ws)
- for q := p + 1; q < cwp; q++ {
- // this item contributes to the goto
- if c == wsets[q].pitem.first {
- putitem(wsets[q].pitem, wsets[q].ws)
- wsets[q].flag = 1
- }
- }
-
- if c < NTBASE {
- state(c) // register new state
- } else {
- temp1[c-NTBASE] = state(c)
- }
- }
-
- if gsdebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "%v: ", i)
- for j := 0; j <= nnonter; j++ {
- if temp1[j] != 0 {
- fmt.Fprintf(foutput, "%v %v,", nontrst[j].name, temp1[j])
- }
- }
- fmt.Fprintf(foutput, "\n")
- }
-
- if first != 0 {
- indgo[i] = apack(temp1[1:], nnonter-1) - 1
- }
-
- more++
- }
- }
-}
-
-//
-// generate the closure of state i
-//
-func closure(i int) {
- zzclose++
-
- // first, copy kernel of state i to wsets
- cwp = 0
- q := pstate[i+1]
- for p := pstate[i]; p < q; p++ {
- wsets[cwp].pitem = statemem[p].pitem
- wsets[cwp].flag = 1 // this item must get closed
- copy(wsets[cwp].ws, statemem[p].look)
- cwp++
- }
-
- // now, go through the loop, closing each item
- work := 1
- for work != 0 {
- work = 0
- for u := 0; u < cwp; u++ {
- if wsets[u].flag == 0 {
- continue
- }
-
- // dot is before c
- c := wsets[u].pitem.first
- if c < NTBASE {
- wsets[u].flag = 0
- // only interesting case is where . is before nonterminal
- continue
- }
-
- // compute the lookahead
- aryfil(clset, tbitset, 0)
-
- // find items involving c
- for v := u; v < cwp; v++ {
- if wsets[v].flag != 1 || wsets[v].pitem.first != c {
- continue
- }
- pi := wsets[v].pitem.prod
- ipi := wsets[v].pitem.off + 1
-
- wsets[v].flag = 0
- if nolook != 0 {
- continue
- }
-
- ch := pi[ipi]
- ipi++
- for ch > 0 {
- // terminal symbol
- if ch < NTBASE {
- setbit(clset, ch)
- break
- }
-
- // nonterminal symbol
- setunion(clset, pfirst[ch-NTBASE])
- if pempty[ch-NTBASE] == 0 {
- break
- }
- ch = pi[ipi]
- ipi++
- }
- if ch <= 0 {
- setunion(clset, wsets[v].ws)
- }
- }
-
- //
- // now loop over productions derived from c
- //
- curres := pres[c-NTBASE]
- n := len(curres)
-
- nexts:
- // initially fill the sets
- for s := 0; s < n; s++ {
- prd := curres[s]
-
- //
- // put these items into the closure
- // is the item there
- //
- for v := 0; v < cwp; v++ {
- // yes, it is there
- if wsets[v].pitem.off == 0 &&
- aryeq(wsets[v].pitem.prod, prd) != 0 {
- if nolook == 0 &&
- setunion(wsets[v].ws, clset) != 0 {
- wsets[v].flag = 1
- work = 1
- }
- continue nexts
- }
- }
-
- // not there; make a new entry
- if cwp >= len(wsets) {
- awsets := make([]Wset, cwp+WSETINC)
- copy(awsets, wsets)
- wsets = awsets
- }
- wsets[cwp].pitem = Pitem{prd, 0, prd[0], -prd[len(prd)-1]}
- wsets[cwp].flag = 1
- wsets[cwp].ws = mkset()
- if nolook == 0 {
- work = 1
- copy(wsets[cwp].ws, clset)
- }
- cwp++
- }
- }
- }
-
- // have computed closure; flags are reset; return
- if cldebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "\nState %v, nolook = %v\n", i, nolook)
- for u := 0; u < cwp; u++ {
- if wsets[u].flag != 0 {
- fmt.Fprintf(foutput, "flag set\n")
- }
- wsets[u].flag = 0
- fmt.Fprintf(foutput, "\t%v", writem(wsets[u].pitem))
- prlook(wsets[u].ws)
- fmt.Fprintf(foutput, "\n")
- }
- }
-}
-
-//
-// sorts last state,and sees if it equals earlier ones. returns state number
-//
-func state(c int) int {
- zzstate++
- p1 := pstate[nstate]
- p2 := pstate[nstate+1]
- if p1 == p2 {
- return 0 // null state
- }
-
- // sort the items
- var k, l int
- for k = p1 + 1; k < p2; k++ { // make k the biggest
- for l = k; l > p1; l-- {
- if statemem[l].pitem.prodno < statemem[l-1].pitem.prodno ||
- statemem[l].pitem.prodno == statemem[l-1].pitem.prodno &&
- statemem[l].pitem.off < statemem[l-1].pitem.off {
- s := statemem[l]
- statemem[l] = statemem[l-1]
- statemem[l-1] = s
- } else {
- break
- }
- }
- }
-
- size1 := p2 - p1 // size of state
-
- var i int
- if c >= NTBASE {
- i = ntstates[c-NTBASE]
- } else {
- i = tstates[c]
- }
-
-look:
- for ; i != 0; i = mstates[i] {
- // get ith state
- q1 := pstate[i]
- q2 := pstate[i+1]
- size2 := q2 - q1
- if size1 != size2 {
- continue
- }
- k = p1
- for l = q1; l < q2; l++ {
- if aryeq(statemem[l].pitem.prod, statemem[k].pitem.prod) == 0 ||
- statemem[l].pitem.off != statemem[k].pitem.off {
- continue look
- }
- k++
- }
-
- // found it
- pstate[nstate+1] = pstate[nstate] // delete last state
-
- // fix up lookaheads
- if nolook != 0 {
- return i
- }
- k = p1
- for l = q1; l < q2; l++ {
- if setunion(statemem[l].look, statemem[k].look) != 0 {
- tystate[i] = MUSTDO
- }
- k++
- }
- return i
- }
-
- // state is new
- zznewstate++
- if nolook != 0 {
- errorf("yacc state/nolook error")
- }
- pstate[nstate+2] = p2
- if nstate+1 >= NSTATES {
- errorf("too many states")
- }
- if c >= NTBASE {
- mstates[nstate] = ntstates[c-NTBASE]
- ntstates[c-NTBASE] = nstate
- } else {
- mstates[nstate] = tstates[c]
- tstates[c] = nstate
- }
- tystate[nstate] = MUSTDO
- nstate++
- return nstate - 1
-}
-
-func putitem(p Pitem, set Lkset) {
- p.off++
- p.first = p.prod[p.off]
-
- if pidebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "putitem(%v), state %v\n", writem(p), nstate)
- }
- j := pstate[nstate+1]
- if j >= len(statemem) {
- asm := make([]Item, j+STATEINC)
- copy(asm, statemem)
- statemem = asm
- }
- statemem[j].pitem = p
- if nolook == 0 {
- s := mkset()
- copy(s, set)
- statemem[j].look = s
- }
- j++
- pstate[nstate+1] = j
-}
-
-//
-// creates output string for item pointed to by pp
-//
-func writem(pp Pitem) string {
- var i int
-
- p := pp.prod
- q := chcopy(nontrst[prdptr[pp.prodno][0]-NTBASE].name) + ": "
- npi := pp.off
-
- pi := aryeq(p, prdptr[pp.prodno])
-
- for {
- c := ' '
- if pi == npi {
- c = '.'
- }
- q += string(c)
-
- i = p[pi]
- pi++
- if i <= 0 {
- break
- }
- q += chcopy(symnam(i))
- }
-
- // an item calling for a reduction
- i = p[npi]
- if i < 0 {
- q += fmt.Sprintf(" (%v)", -i)
- }
-
- return q
-}
-
-//
-// pack state i from temp1 into amem
-//
-func apack(p []int, n int) int {
- //
- // we don't need to worry about checking because
- // we will only look at entries known to be there...
- // eliminate leading and trailing 0's
- //
- off := 0
- pp := 0
- for ; pp <= n && p[pp] == 0; pp++ {
- off--
- }
-
- // no actions
- if pp > n {
- return 0
- }
- for ; n > pp && p[n] == 0; n-- {
- }
- p = p[pp : n+1]
-
- // now, find a place for the elements from p to q, inclusive
- r := len(amem) - len(p)
-
-nextk:
- for rr := 0; rr <= r; rr++ {
- qq := rr
- for pp = 0; pp < len(p); pp++ {
- if p[pp] != 0 {
- if p[pp] != amem[qq] && amem[qq] != 0 {
- continue nextk
- }
- }
- qq++
- }
-
- // we have found an acceptable k
- if pkdebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "off = %v, k = %v\n", off+rr, rr)
- }
- qq = rr
- for pp = 0; pp < len(p); pp++ {
- if p[pp] != 0 {
- if qq > memp {
- memp = qq
- }
- amem[qq] = p[pp]
- }
- qq++
- }
- if pkdebug != 0 && foutput != nil {
- for pp = 0; pp <= memp; pp += 10 {
- fmt.Fprintf(foutput, "\n")
- for qq = pp; qq <= pp+9; qq++ {
- fmt.Fprintf(foutput, "%v ", amem[qq])
- }
- fmt.Fprintf(foutput, "\n")
- }
- }
- return off + rr
- }
- errorf("no space in action table")
- return 0
-}
-
-//
-// print the output for the states
-//
-func output() {
- var c, u, v int
-
- fmt.Fprintf(ftable, "\n//line yacctab:1\n")
- fmt.Fprintf(ftable, "var\t%sExca = []int {\n", prefix)
-
- noset := mkset()
-
- // output the stuff for state i
- for i := 0; i < nstate; i++ {
- nolook = 0
- if tystate[i] != MUSTLOOKAHEAD {
- nolook = 1
- }
- closure(i)
-
- // output actions
- nolook = 1
- aryfil(temp1, ntokens+nnonter+1, 0)
- for u = 0; u < cwp; u++ {
- c = wsets[u].pitem.first
- if c > 1 && c < NTBASE && temp1[c] == 0 {
- for v = u; v < cwp; v++ {
- if c == wsets[v].pitem.first {
- putitem(wsets[v].pitem, noset)
- }
- }
- temp1[c] = state(c)
- } else if c > NTBASE {
- c -= NTBASE
- if temp1[c+ntokens] == 0 {
- temp1[c+ntokens] = amem[indgo[i]+c]
- }
- }
- }
- if i == 1 {
- temp1[1] = ACCEPTCODE
- }
-
- // now, we have the shifts; look at the reductions
- lastred = 0
- for u = 0; u < cwp; u++ {
- c = wsets[u].pitem.first
-
- // reduction
- if c > 0 {
- continue
- }
- lastred = -c
- us := wsets[u].ws
- for k := 0; k <= ntokens; k++ {
- if bitset(us, k) == 0 {
- continue
- }
- if temp1[k] == 0 {
- temp1[k] = c
- } else if temp1[k] < 0 { // reduce/reduce conflict
- if foutput != nil {
- fmt.Fprintf(foutput,
- "\n %v: reduce/reduce conflict (red'ns "+
- "%v and %v) on %v",
- i, -temp1[k], lastred, symnam(k))
- }
- if -temp1[k] > lastred {
- temp1[k] = -lastred
- }
- zzrrconf++
- } else {
- // potential shift/reduce conflict
- precftn(lastred, k, i)
- }
- }
- }
- wract(i)
- }
-
- fmt.Fprintf(ftable, "}\n")
- fmt.Fprintf(ftable, "const\t%sNprod\t= %v\n", prefix, nprod)
- fmt.Fprintf(ftable, "const\t%sPrivate\t= %v\n", prefix, PRIVATE)
- fmt.Fprintf(ftable, "var\t%sTokenNames []string\n", prefix)
- fmt.Fprintf(ftable, "var\t%sStates []string\n", prefix)
-}
-
-//
-// decide a shift/reduce conflict by precedence.
-// r is a rule number, t a token number
-// the conflict is in state s
-// temp1[t] is changed to reflect the action
-//
-func precftn(r, t, s int) {
- var action int
-
- lp := levprd[r]
- lt := toklev[t]
- if PLEVEL(lt) == 0 || PLEVEL(lp) == 0 {
- // conflict
- if foutput != nil {
- fmt.Fprintf(foutput,
- "\n%v: shift/reduce conflict (shift %v(%v), red'n %v(%v)) on %v",
- s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t))
- }
- zzsrconf++
- return
- }
- if PLEVEL(lt) == PLEVEL(lp) {
- action = ASSOC(lt)
- } else if PLEVEL(lt) > PLEVEL(lp) {
- action = RASC // shift
- } else {
- action = LASC
- } // reduce
- switch action {
- case BASC: // error action
- temp1[t] = ERRCODE
- case LASC: // reduce
- temp1[t] = -r
- }
-}
-
-//
-// output state i
-// temp1 has the actions, lastred the default
-//
-func wract(i int) {
- var p, p1 int
-
- // find the best choice for lastred
- lastred = 0
- ntimes := 0
- for j := 0; j <= ntokens; j++ {
- if temp1[j] >= 0 {
- continue
- }
- if temp1[j]+lastred == 0 {
- continue
- }
- // count the number of appearances of temp1[j]
- count := 0
- tred := -temp1[j]
- levprd[tred] |= REDFLAG
- for p = 0; p <= ntokens; p++ {
- if temp1[p]+tred == 0 {
- count++
- }
- }
- if count > ntimes {
- lastred = tred
- ntimes = count
- }
- }
-
- //
- // for error recovery, arrange that, if there is a shift on the
- // error recovery token, `error', that the default be the error action
- //
- if temp1[2] > 0 {
- lastred = 0
- }
-
- // clear out entries in temp1 which equal lastred
- // count entries in optst table
- n := 0
- for p = 0; p <= ntokens; p++ {
- p1 = temp1[p]
- if p1+lastred == 0 {
- temp1[p] = 0
- p1 = 0
- }
- if p1 > 0 && p1 != ACCEPTCODE && p1 != ERRCODE {
- n++
- }
- }
-
- wrstate(i)
- defact[i] = lastred
- flag := 0
- os := make([]int, n*2)
- n = 0
- for p = 0; p <= ntokens; p++ {
- p1 = temp1[p]
- if p1 != 0 {
- if p1 < 0 {
- p1 = -p1
- } else if p1 == ACCEPTCODE {
- p1 = -1
- } else if p1 == ERRCODE {
- p1 = 0
- } else {
- os[n] = p
- n++
- os[n] = p1
- n++
- zzacent++
- continue
- }
- if flag == 0 {
- fmt.Fprintf(ftable, "-1, %v,\n", i)
- }
- flag++
- fmt.Fprintf(ftable, "\t%v, %v,\n", p, p1)
- zzexcp++
- }
- }
- if flag != 0 {
- defact[i] = -2
- fmt.Fprintf(ftable, "\t-2, %v,\n", lastred)
- }
- optst[i] = os
-}
-
-//
-// writes state i
-//
-func wrstate(i int) {
- var j0, j1, u int
- var pp, qq int
-
- if foutput == nil {
- return
- }
- fmt.Fprintf(foutput, "\nstate %v\n", i)
- qq = pstate[i+1]
- for pp = pstate[i]; pp < qq; pp++ {
- fmt.Fprintf(foutput, "\t%v\n", writem(statemem[pp].pitem))
- }
- if tystate[i] == MUSTLOOKAHEAD {
- // print out empty productions in closure
- for u = pstate[i+1] - pstate[i]; u < cwp; u++ {
- if wsets[u].pitem.first < 0 {
- fmt.Fprintf(foutput, "\t%v\n", writem(wsets[u].pitem))
- }
- }
- }
-
- // check for state equal to another
- for j0 = 0; j0 <= ntokens; j0++ {
- j1 = temp1[j0]
- if j1 != 0 {
- fmt.Fprintf(foutput, "\n\t%v ", symnam(j0))
-
- // shift, error, or accept
- if j1 > 0 {
- if j1 == ACCEPTCODE {
- fmt.Fprintf(foutput, "accept")
- } else if j1 == ERRCODE {
- fmt.Fprintf(foutput, "error")
- } else {
- fmt.Fprintf(foutput, "shift %v", j1)
- }
- } else {
- fmt.Fprintf(foutput, "reduce %v (src line %v)", -j1, rlines[-j1])
- }
- }
- }
-
- // output the final production
- if lastred != 0 {
- fmt.Fprintf(foutput, "\n\t. reduce %v (src line %v)\n\n",
- lastred, rlines[lastred])
- } else {
- fmt.Fprintf(foutput, "\n\t. error\n\n")
- }
-
- // now, output nonterminal actions
- j1 = ntokens
- for j0 = 1; j0 <= nnonter; j0++ {
- j1++
- if temp1[j1] != 0 {
- fmt.Fprintf(foutput, "\t%v goto %v\n", symnam(j0+NTBASE), temp1[j1])
- }
- }
-}
-
-//
-// output the gotos for the nontermninals
-//
-func go2out() {
- for i := 1; i <= nnonter; i++ {
- go2gen(i)
-
- // find the best one to make default
- best := -1
- times := 0
-
- // is j the most frequent
- for j := 0; j < nstate; j++ {
- if tystate[j] == 0 {
- continue
- }
- if tystate[j] == best {
- continue
- }
-
- // is tystate[j] the most frequent
- count := 0
- cbest := tystate[j]
- for k := j; k < nstate; k++ {
- if tystate[k] == cbest {
- count++
- }
- }
- if count > times {
- best = cbest
- times = count
- }
- }
-
- // best is now the default entry
- zzgobest += times - 1
- n := 0
- for j := 0; j < nstate; j++ {
- if tystate[j] != 0 && tystate[j] != best {
- n++
- }
- }
- goent := make([]int, 2*n+1)
- n = 0
- for j := 0; j < nstate; j++ {
- if tystate[j] != 0 && tystate[j] != best {
- goent[n] = j
- n++
- goent[n] = tystate[j]
- n++
- zzgoent++
- }
- }
-
- // now, the default
- if best == -1 {
- best = 0
- }
-
- zzgoent++
- goent[n] = best
- yypgo[i] = goent
- }
-}
-
-//
-// output the gotos for nonterminal c
-//
-func go2gen(c int) {
- var i, cc, p, q int
-
- // first, find nonterminals with gotos on c
- aryfil(temp1, nnonter+1, 0)
- temp1[c] = 1
- work := 1
- for work != 0 {
- work = 0
- for i = 0; i < nprod; i++ {
- // cc is a nonterminal with a goto on c
- cc = prdptr[i][1] - NTBASE
- if cc >= 0 && temp1[cc] != 0 {
- // thus, the left side of production i does too
- cc = prdptr[i][0] - NTBASE
- if temp1[cc] == 0 {
- work = 1
- temp1[cc] = 1
- }
- }
- }
- }
-
- // now, we have temp1[c] = 1 if a goto on c in closure of cc
- if g2debug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "%v: gotos on ", nontrst[c].name)
- for i = 0; i <= nnonter; i++ {
- if temp1[i] != 0 {
- fmt.Fprintf(foutput, "%v ", nontrst[i].name)
- }
- }
- fmt.Fprintf(foutput, "\n")
- }
-
- // now, go through and put gotos into tystate
- aryfil(tystate, nstate, 0)
- for i = 0; i < nstate; i++ {
- q = pstate[i+1]
- for p = pstate[i]; p < q; p++ {
- cc = statemem[p].pitem.first
- if cc >= NTBASE {
- // goto on c is possible
- if temp1[cc-NTBASE] != 0 {
- tystate[i] = amem[indgo[i]+c]
- break
- }
- }
- }
- }
-}
-
-//
-// in order to free up the mem and amem arrays for the optimizer,
-// and still be able to output yyr1, etc., after the sizes of
-// the action array is known, we hide the nonterminals
-// derived by productions in levprd.
-//
-func hideprod() {
- nred := 0
- levprd[0] = 0
- for i := 1; i < nprod; i++ {
- if (levprd[i] & REDFLAG) == 0 {
- if foutput != nil {
- fmt.Fprintf(foutput, "Rule not reduced: %v\n",
- writem(Pitem{prdptr[i], 0, 0, i}))
- }
- fmt.Printf("rule %v never reduced\n", writem(Pitem{prdptr[i], 0, 0, i}))
- nred++
- }
- levprd[i] = prdptr[i][0] - NTBASE
- }
- if nred != 0 {
- fmt.Printf("%v rules never reduced\n", nred)
- }
-}
-
-func callopt() {
- var j, k, p, q, i int
- var v []int
-
- pgo = make([]int, nnonter+1)
- pgo[0] = 0
- maxoff = 0
- maxspr = 0
- for i = 0; i < nstate; i++ {
- k = 32000
- j = 0
- v = optst[i]
- q = len(v)
- for p = 0; p < q; p += 2 {
- if v[p] > j {
- j = v[p]
- }
- if v[p] < k {
- k = v[p]
- }
- }
-
- // nontrivial situation
- if k <= j {
- // j is now the range
- // j -= k; // call scj
- if k > maxoff {
- maxoff = k
- }
- }
- tystate[i] = q + 2*j
- if j > maxspr {
- maxspr = j
- }
- }
-
- // initialize ggreed table
- ggreed = make([]int, nnonter+1)
- for i = 1; i <= nnonter; i++ {
- ggreed[i] = 1
- j = 0
-
- // minimum entry index is always 0
- v = yypgo[i]
- q = len(v) - 1
- for p = 0; p < q; p += 2 {
- ggreed[i] += 2
- if v[p] > j {
- j = v[p]
- }
- }
- ggreed[i] = ggreed[i] + 2*j
- if j > maxoff {
- maxoff = j
- }
- }
-
- // now, prepare to put the shift actions into the amem array
- for i = 0; i < ACTSIZE; i++ {
- amem[i] = 0
- }
- maxa = 0
- for i = 0; i < nstate; i++ {
- if tystate[i] == 0 && adb > 1 {
- fmt.Fprintf(ftable, "State %v: null\n", i)
- }
- indgo[i] = yyFlag
- }
-
- i = nxti()
- for i != NOMORE {
- if i >= 0 {
- stin(i)
- } else {
- gin(-i)
- }
- i = nxti()
- }
-
- // print amem array
- if adb > 2 {
- for p = 0; p <= maxa; p += 10 {
- fmt.Fprintf(ftable, "%v ", p)
- for i = 0; i < 10; i++ {
- fmt.Fprintf(ftable, "%v ", amem[p+i])
- }
- ftable.WriteRune('\n')
- }
- }
-
- aoutput()
- osummary()
-}
-
-//
-// finds the next i
-//
-func nxti() int {
- max := 0
- maxi := 0
- for i := 1; i <= nnonter; i++ {
- if ggreed[i] >= max {
- max = ggreed[i]
- maxi = -i
- }
- }
- for i := 0; i < nstate; i++ {
- if tystate[i] >= max {
- max = tystate[i]
- maxi = i
- }
- }
- if max == 0 {
- return NOMORE
- }
- return maxi
-}
-
-func gin(i int) {
- var s int
-
- // enter gotos on nonterminal i into array amem
- ggreed[i] = 0
-
- q := yypgo[i]
- nq := len(q) - 1
-
- // now, find amem place for it
-nextgp:
- for p := 0; p < ACTSIZE; p++ {
- if amem[p] != 0 {
- continue
- }
- for r := 0; r < nq; r += 2 {
- s = p + q[r] + 1
- if s > maxa {
- maxa = s
- if maxa >= ACTSIZE {
- errorf("a array overflow")
- }
- }
- if amem[s] != 0 {
- continue nextgp
- }
- }
-
- // we have found amem spot
- amem[p] = q[nq]
- if p > maxa {
- maxa = p
- }
- for r := 0; r < nq; r += 2 {
- s = p + q[r] + 1
- amem[s] = q[r+1]
- }
- pgo[i] = p
- if adb > 1 {
- fmt.Fprintf(ftable, "Nonterminal %v, entry at %v\n", i, pgo[i])
- }
- return
- }
- errorf("cannot place goto %v\n", i)
-}
-
-func stin(i int) {
- var s int
-
- tystate[i] = 0
-
- // enter state i into the amem array
- q := optst[i]
- nq := len(q)
-
-nextn:
- // find an acceptable place
- for n := -maxoff; n < ACTSIZE; n++ {
- flag := 0
- for r := 0; r < nq; r += 2 {
- s = q[r] + n
- if s < 0 || s > ACTSIZE {
- continue nextn
- }
- if amem[s] == 0 {
- flag++
- } else if amem[s] != q[r+1] {
- continue nextn
- }
- }
-
- // check the position equals another only if the states are identical
- for j := 0; j < nstate; j++ {
- if indgo[j] == n {
-
- // we have some disagreement
- if flag != 0 {
- continue nextn
- }
- if nq == len(optst[j]) {
-
- // states are equal
- indgo[i] = n
- if adb > 1 {
- fmt.Fprintf(ftable, "State %v: entry at"+
- "%v equals state %v\n",
- i, n, j)
- }
- return
- }
-
- // we have some disagreement
- continue nextn
- }
- }
-
- for r := 0; r < nq; r += 2 {
- s = q[r] + n
- if s > maxa {
- maxa = s
- }
- if amem[s] != 0 && amem[s] != q[r+1] {
- errorf("clobber of a array, pos'n %v, by %v", s, q[r+1])
- }
- amem[s] = q[r+1]
- }
- indgo[i] = n
- if adb > 1 {
- fmt.Fprintf(ftable, "State %v: entry at %v\n", i, indgo[i])
- }
- return
- }
- errorf("Error; failure to place state %v", i)
-}
-
-//
-// this version is for limbo
-// write out the optimized parser
-//
-func aoutput() {
- fmt.Fprintf(ftable, "const\t%sLast\t= %v\n", prefix, maxa+1)
- arout("Act", amem, maxa+1)
- arout("Pact", indgo, nstate)
- arout("Pgo", pgo, nnonter+1)
-}
-
-//
-// put out other arrays, copy the parsers
-//
-func others() {
- var i, j int
-
- arout("R1", levprd, nprod)
- aryfil(temp1, nprod, 0)
-
- //
- //yyr2 is the number of rules for each production
- //
- for i = 1; i < nprod; i++ {
- temp1[i] = len(prdptr[i]) - 2
- }
- arout("R2", temp1, nprod)
-
- aryfil(temp1, nstate, -1000)
- for i = 0; i <= ntokens; i++ {
- for j := tstates[i]; j != 0; j = mstates[j] {
- temp1[j] = i
- }
- }
- for i = 0; i <= nnonter; i++ {
- for j = ntstates[i]; j != 0; j = mstates[j] {
- temp1[j] = -i
- }
- }
- arout("Chk", temp1, nstate)
- arout("Def", defact, nstate)
-
- // put out token translation tables
- // table 1 has 0-256
- aryfil(temp1, 256, 0)
- c := 0
- for i = 1; i <= ntokens; i++ {
- j = tokset[i].value
- if j >= 0 && j < 256 {
- if temp1[j] != 0 {
- print("yacc bug -- cant have 2 different Ts with same value\n")
- print(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
- nerrors++
- }
- temp1[j] = i
- if j > c {
- c = j
- }
- }
- }
- for i = 0; i <= c; i++ {
- if temp1[i] == 0 {
- temp1[i] = YYLEXUNK
- }
- }
- arout("Tok1", temp1, c+1)
-
- // table 2 has PRIVATE-PRIVATE+256
- aryfil(temp1, 256, 0)
- c = 0
- for i = 1; i <= ntokens; i++ {
- j = tokset[i].value - PRIVATE
- if j >= 0 && j < 256 {
- if temp1[j] != 0 {
- print("yacc bug -- cant have 2 different Ts with same value\n")
- print(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
- nerrors++
- }
- temp1[j] = i
- if j > c {
- c = j
- }
- }
- }
- arout("Tok2", temp1, c+1)
-
- // table 3 has everything else
- fmt.Fprintf(ftable, "var\t%sTok3\t= []int {\n", prefix)
- c = 0
- for i = 1; i <= ntokens; i++ {
- j = tokset[i].value
- if j >= 0 && j < 256 {
- continue
- }
- if j >= PRIVATE && j < 256+PRIVATE {
- continue
- }
-
- fmt.Fprintf(ftable, "%4d,%4d,", j, i)
- c++
- if c%5 == 0 {
- ftable.WriteRune('\n')
- }
- }
- fmt.Fprintf(ftable, "%4d,\n };\n", 0)
-
- // copy parser text
- c = getrune(finput)
- for c != EOF {
- ftable.WriteRune(c)
- c = getrune(finput)
- }
-
- // copy yaccpar
- fmt.Fprintf(ftable, "\n//line yaccpar:1\n")
-
- parts := strings.SplitN(yaccpar, prefix+"run()", 2)
- fmt.Fprintf(ftable, "%v", parts[0])
- ftable.Write(fcode.Bytes())
- fmt.Fprintf(ftable, "%v", parts[1])
-}
-
-func arout(s string, v []int, n int) {
- s = prefix + s
- fmt.Fprintf(ftable, "var\t%v\t= []int {\n", s)
- for i := 0; i < n; i++ {
- if i%10 == 0 {
- ftable.WriteRune('\n')
- }
- fmt.Fprintf(ftable, "%4d", v[i])
- ftable.WriteRune(',')
- }
- fmt.Fprintf(ftable, "\n};\n")
-}
-
-//
-// output the summary on y.output
-//
-func summary() {
- if foutput != nil {
- fmt.Fprintf(foutput, "\n%v terminals, %v nonterminals\n", ntokens, nnonter+1)
- fmt.Fprintf(foutput, "%v grammar rules, %v/%v states\n", nprod, nstate, NSTATES)
- fmt.Fprintf(foutput, "%v shift/reduce, %v reduce/reduce conflicts reported\n", zzsrconf, zzrrconf)
- fmt.Fprintf(foutput, "%v working sets used\n", len(wsets))
- fmt.Fprintf(foutput, "memory: parser %v/%v\n", memp, ACTSIZE)
- fmt.Fprintf(foutput, "%v extra closures\n", zzclose-2*nstate)
- fmt.Fprintf(foutput, "%v shift entries, %v exceptions\n", zzacent, zzexcp)
- fmt.Fprintf(foutput, "%v goto entries\n", zzgoent)
- fmt.Fprintf(foutput, "%v entries saved by goto default\n", zzgobest)
- }
- if zzsrconf != 0 || zzrrconf != 0 {
- fmt.Printf("\nconflicts: ")
- if zzsrconf != 0 {
- fmt.Printf("%v shift/reduce", zzsrconf)
- }
- if zzsrconf != 0 && zzrrconf != 0 {
- fmt.Printf(", ")
- }
- if zzrrconf != 0 {
- fmt.Printf("%v reduce/reduce", zzrrconf)
- }
- fmt.Printf("\n")
- }
-}
-
-//
-// write optimizer summary
-//
-func osummary() {
- if foutput == nil {
- return
- }
- i := 0
- for p := maxa; p >= 0; p-- {
- if amem[p] == 0 {
- i++
- }
- }
-
- fmt.Fprintf(foutput, "Optimizer space used: output %v/%v\n", maxa+1, ACTSIZE)
- fmt.Fprintf(foutput, "%v table entries, %v zero\n", maxa+1, i)
- fmt.Fprintf(foutput, "maximum spread: %v, maximum offset: %v\n", maxspr, maxoff)
-}
-
-//
-// copies and protects "'s in q
-//
-func chcopy(q string) string {
- s := ""
- i := 0
- j := 0
- for i = 0; i < len(q); i++ {
- if q[i] == '"' {
- s += q[j:i] + "\\"
- j = i
- }
- }
- return s + q[j:i]
-}
-
-func usage() {
- fmt.Fprintf(stderr, "usage: goyacc [-o output] [-v parsetable] input\n")
- exit(1)
-}
-
-func bitset(set Lkset, bit int) int { return set[bit>>5] & (1 << uint(bit&31)) }
-
-func setbit(set Lkset, bit int) { set[bit>>5] |= (1 << uint(bit&31)) }
-
-func mkset() Lkset { return make([]int, tbitset) }
-
-//
-// set a to the union of a and b
-// return 1 if b is not a subset of a, 0 otherwise
-//
-func setunion(a, b []int) int {
- sub := 0
- for i := 0; i < tbitset; i++ {
- x := a[i]
- y := x | b[i]
- a[i] = y
- if y != x {
- sub = 1
- }
- }
- return sub
-}
-
-func prlook(p Lkset) {
- if p == nil {
- fmt.Fprintf(foutput, "\tNULL")
- return
- }
- fmt.Fprintf(foutput, " { ")
- for j := 0; j <= ntokens; j++ {
- if bitset(p, j) != 0 {
- fmt.Fprintf(foutput, "%v ", symnam(j))
- }
- }
- fmt.Fprintf(foutput, "}")
-}
-
-//
-// utility routines
-//
-var peekrune int
-
-func isdigit(c int) bool { return c >= '0' && c <= '9' }
-
-func isword(c int) bool {
- return c >= 0xa0 || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
-}
-
-func mktemp(t string) string { return t }
-
-//
-// return 1 if 2 arrays are equal
-// return 0 if not equal
-//
-func aryeq(a []int, b []int) int {
- n := len(a)
- if len(b) != n {
- return 0
- }
- for ll := 0; ll < n; ll++ {
- if a[ll] != b[ll] {
- return 0
- }
- }
- return 1
-}
-
-func putrune(f *bufio.Writer, c int) {
- s := string(c)
- for i := 0; i < len(s); i++ {
- f.WriteByte(s[i])
- }
-}
-
-func getrune(f *bufio.Reader) int {
- var r int
-
- if peekrune != 0 {
- if peekrune == EOF {
- return EOF
- }
- r = peekrune
- peekrune = 0
- return r
- }
-
- c, n, err := f.ReadRune()
- if n == 0 {
- return EOF
- }
- if err != nil {
- errorf("read error: %v", err)
- }
- //fmt.Printf("rune = %v n=%v\n", string(c), n);
- return c
-}
-
-func ungetrune(f *bufio.Reader, c int) {
- if f != finput {
- panic("ungetc - not finput")
- }
- if peekrune != 0 {
- panic("ungetc - 2nd unget")
- }
- peekrune = c
-}
-
-func write(f *bufio.Writer, b []byte, n int) int {
- panic("write")
- return 0
-}
-
-func open(s string) *bufio.Reader {
- fi, err := os.Open(s)
- if err != nil {
- errorf("error opening %v: %v", s, err)
- }
- //fmt.Printf("open %v\n", s);
- return bufio.NewReader(fi)
-}
-
-func create(s string) *bufio.Writer {
- fo, err := os.Create(s)
- if err != nil {
- errorf("error creating %v: %v", s, err)
- }
- //fmt.Printf("create %v mode %v\n", s);
- return bufio.NewWriter(fo)
-}
-
-//
-// write out error comment
-//
-func errorf(s string, v ...interface{}) {
- nerrors++
- fmt.Fprintf(stderr, s, v...)
- fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno)
- if fatfl != 0 {
- summary()
- exit(1)
- }
-}
-
-func exit(status int) {
- if ftable != nil {
- ftable.Flush()
- ftable = nil
- }
- if foutput != nil {
- foutput.Flush()
- foutput = nil
- }
- if stderr != nil {
- stderr.Flush()
- stderr = nil
- }
- os.Exit(status)
-}
-
-var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
-var yaccpartext = `
-/* parser for yacc output */
-
-var $$Debug = 0
-
-type $$Lexer interface {
- Lex(lval *$$SymType) int
- Error(s string)
-}
-
-const $$Flag = -1000
-
-func $$Tokname(c int) string {
- if c > 0 && c <= len($$Toknames) {
- if $$Toknames[c-1] != "" {
- return $$Toknames[c-1]
- }
- }
- return fmt.Sprintf("tok-%v", c)
-}
-
-func $$Statname(s int) string {
- if s >= 0 && s < len($$Statenames) {
- if $$Statenames[s] != "" {
- return $$Statenames[s]
- }
- }
- return fmt.Sprintf("state-%v", s)
-}
-
-func $$lex1(lex $$Lexer, lval *$$SymType) int {
- c := 0
- char := lex.Lex(lval)
- if char <= 0 {
- c = $$Tok1[0]
- goto out
- }
- if char < len($$Tok1) {
- c = $$Tok1[char]
- goto out
- }
- if char >= $$Private {
- if char < $$Private+len($$Tok2) {
- c = $$Tok2[char-$$Private]
- goto out
- }
- }
- for i := 0; i < len($$Tok3); i += 2 {
- c = $$Tok3[i+0]
- if c == char {
- c = $$Tok3[i+1]
- goto out
- }
- }
-
-out:
- if c == 0 {
- c = $$Tok2[1] /* unknown char */
- }
- if $$Debug >= 3 {
- fmt.Printf("lex %U %s\n", uint(char), $$Tokname(c))
- }
- return c
-}
-
-func $$Parse($$lex $$Lexer) int {
- var $$n int
- var $$lval $$SymType
- var $$VAL $$SymType
- $$S := make([]$$SymType, $$MaxDepth)
-
- Nerrs := 0 /* number of errors */
- Errflag := 0 /* error recovery flag */
- $$state := 0
- $$char := -1
- $$p := -1
- goto $$stack
-
-ret0:
- return 0
-
-ret1:
- return 1
-
-$$stack:
- /* put a state and value onto the stack */
- if $$Debug >= 4 {
- fmt.Printf("char %v in %v\n", $$Tokname($$char), $$Statname($$state))
- }
-
- $$p++
- if $$p >= len($$S) {
- nyys := make([]$$SymType, len($$S)*2)
- copy(nyys, $$S)
- $$S = nyys
- }
- $$S[$$p] = $$VAL
- $$S[$$p].yys = $$state
-
-$$newstate:
- $$n = $$Pact[$$state]
- if $$n <= $$Flag {
- goto $$default /* simple state */
- }
- if $$char < 0 {
- $$char = $$lex1($$lex, &$$lval)
- }
- $$n += $$char
- if $$n < 0 || $$n >= $$Last {
- goto $$default
- }
- $$n = $$Act[$$n]
- if $$Chk[$$n] == $$char { /* valid shift */
- $$char = -1
- $$VAL = $$lval
- $$state = $$n
- if Errflag > 0 {
- Errflag--
- }
- goto $$stack
- }
-
-$$default:
- /* default state action */
- $$n = $$Def[$$state]
- if $$n == -2 {
- if $$char < 0 {
- $$char = $$lex1($$lex, &$$lval)
- }
-
- /* look through exception table */
- xi := 0
- for {
- if $$Exca[xi+0] == -1 && $$Exca[xi+1] == $$state {
- break
- }
- xi += 2
- }
- for xi += 2; ; xi += 2 {
- $$n = $$Exca[xi+0]
- if $$n < 0 || $$n == $$char {
- break
- }
- }
- $$n = $$Exca[xi+1]
- if $$n < 0 {
- goto ret0
- }
- }
- if $$n == 0 {
- /* error ... attempt to resume parsing */
- switch Errflag {
- case 0: /* brand new error */
- $$lex.Error("syntax error")
- Nerrs++
- if $$Debug >= 1 {
- fmt.Printf("%s", $$Statname($$state))
- fmt.Printf("saw %s\n", $$Tokname($$char))
- }
- fallthrough
-
- case 1, 2: /* incompletely recovered error ... try again */
- Errflag = 3
-
- /* find a state where "error" is a legal shift action */
- for $$p >= 0 {
- $$n = $$Pact[$$S[$$p].yys] + $$ErrCode
- if $$n >= 0 && $$n < $$Last {
- $$state = $$Act[$$n] /* simulate a shift of "error" */
- if $$Chk[$$state] == $$ErrCode {
- goto $$stack
- }
- }
-
- /* the current p has no shift onn "error", pop stack */
- if $$Debug >= 2 {
- fmt.Printf("error recovery pops state %d, uncovers %d\n",
- $$S[$$p].yys, $$S[$$p-1].yys)
- }
- $$p--
- }
- /* there is no state on the stack with an error shift ... abort */
- goto ret1
-
- case 3: /* no shift yet; clobber input char */
- if $$Debug >= 2 {
- fmt.Printf("error recovery discards %s\n", $$Tokname($$char))
- }
- if $$char == $$EofCode {
- goto ret1
- }
- $$char = -1
- goto $$newstate /* try again in the same state */
- }
- }
-
- /* reduction by production $$n */
- if $$Debug >= 2 {
- fmt.Printf("reduce %v in:\n\t%v\n", $$n, $$Statname($$state))
- }
-
- $$nt := $$n
- $$pt := $$p
- _ = $$pt // guard against "declared and not used"
-
- $$p -= $$R2[$$n]
- $$VAL = $$S[$$p+1]
-
- /* consult goto table to find next state */
- $$n = $$R1[$$n]
- $$g := $$Pgo[$$n]
- $$j := $$g + $$S[$$p].yys + 1
-
- if $$j >= $$Last {
- $$state = $$Act[$$g]
- } else {
- $$state = $$Act[$$j]
- if $$Chk[$$state] != -$$n {
- $$state = $$Act[$$g]
- }
- }
- // dummy call; replaced with literal code
- $$run()
- goto $$stack /* stack new state and value */
-}
-`
diff --git a/src/cmd/goyacc/units.txt b/src/cmd/goyacc/units.txt
deleted file mode 100644
index ddb2bc294..000000000
--- a/src/cmd/goyacc/units.txt
+++ /dev/null
@@ -1,576 +0,0 @@
-/ Plan 9's /lib/units
-/ http://plan9.bell-labs.com/sources/plan9/lib/units
-/
-/ Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
-/ Distributed under the terms of the Lucent Public License Version 1.02
-/ See http://plan9.bell-labs.com/plan9/license.html
-/
-/order of evaluation
-/ + -
-/ * /
-/ juxtaposition (meaning *)
-/ ¹ ² ³ ^
-/ | (meaning /)
-/ name number ()
-
-/dimensions
-m #
-kg #
-sec #
-coul #
-candela #
-$ #
-radian #
-bit #
-erlang #
-°K #
-°C #
-°F #
-
-/constants
-
-π 3.14159265358979323846
-pi π
-c 2.997925e+8 m/sec
-g 9.80665 m/sec²
-au 1.49597871e+11 m
-mole 6.022169e+23
-e 1.6021917e-19 coul
-energy c²
-force g
-mercury 1.33322e+5 kg/m²sec²
-hg mercury
-h 6.62620e-34 m²kg/sec
-ℏ h/2 π
-hbar ℏ
-nonillion 1e30
-octillion 1e27
-septillion 1e24
-sextillion 1e21
-pentillion 1e18
-quadrillion 1e15
-trillion 1e12
-billion 1e9
-million 1e6
-thousand 1e3
-hundred 1e2
-
-/dimensionless
-
-° 1|180 π radian
-degree °
-circle 2 π radian
-turn 2 π radian
-grad .9 °
-arcdeg 1 °
-arcmin 1|60 °
-arcsec 1|3600 °
-ccs 1|36 erlang
-
-steradian radian²
-sphere 4 π steradian
-sr steradian
-giga 1024 1024 1024
-
-/Time
-
-second sec
-s sec
-minute 60 sec
-min minute
-hour 60 min
-hr hour
-day 24 hr
-da day
-week 7 day
-year 365.24219879 day
-yr year
-month 1|12 year
-ms millisec
-us microsec
-
-/Mass
-
-gram millikg
-gm gram
-mg milligram
-metricton kilokg
-
-/Avoirdupois
-
-lb .45359237 kg
-lbf lb g
-pound lb
-ounce 1|16 lb
-oz ounce
-dram 1|16 oz
-dr dram
-grain 1|7000 lb
-gr grain
-shortton 2000 lb
-ton shortton
-longton 2240 lb
-
-/Apothecary
-
-scruple 20 grain
-apdram 60 grain
-apounce 480 grain
-troyounce apounce
-appound 5760 grain
-troypound appound
-
-/Length
-
-meter m
-cm centimeter
-mm millimeter
-km kilometer
-nm nanometer
-micron micrometer
-µ micrometer
-Å decinanometer
-angstrom Å
-
-inch 2.54 cm
-" inch
-in inch
-inches inch
-' 12"
-foot 12 in
-feet foot
-ft foot
-yard 3 ft
-yd yard
-rod 5.5 yd
-rd rod
-mile 5280 ft
-mi mile
-
-british 1200|3937 m/ft
-nmile 1852 m
-
-acre 4840 yd²
-
-cc cm³
-liter kilocc
-ml milliliter
-
-/US Liquid
-
-gallon 231 in³
-imperial 1.20095
-epa 0.8
-gal gallon
-quart 1|4 gal
-qt quart
-pint 1|2 qt
-pt pint
-
-floz 1|16 pt
-fldr 1|8 floz
-
-/US Dry
-
-dry 268.8025 in³/gallon
-peck 8 dry quart
-pk peck
-bushel 4 peck
-bu bushel
-
-/British
-
-brgallon 277.420 in³
-brquart 1|4 brgallon
-brpint 1|2 brquart
-brfloz 1|20 brpint
-brpeck 554.84 in³
-brbushel 4 brpeck
-
-/Energy Work
-
-newton kg m/sec²
-nt newton
-joule nt m
-cal 4.1868 joule
-
-/Electrical
-
-coulomb coul
-ampere coul/sec
-amp ampere
-watt joule/sec
-volt watt/amp
-Ω volt/amp
-ohm Ω
-mho 1/Ω
-farad coul/volt
-henry sec²/farad
-weber volt sec
-
-/Light
-
-cd candela
-lumen cd sr
-lux cd sr/m²
-
-/ MONEY DATE
-/ Thu Sep 10 2009
-
-argentinapeso 1 | 0.2595 $
-australiadollar 1 | 0.8618 $
-boliviaboliviano 1 | 0.1425 $
-brazilreal 1 | 0.5522 $
-britainpound 1 | 1.6651 $
-canadadollar 1 | 0.9277 $
-chilepeso 1 | 0.0018 $
-chinayuan 1 | 0.1464 $
-colombiapeso 1 | 0.0005 $
-czechkoruna 1 | 0.0572 $
-denmarkkrone 1 | 0.1958 $
-dominicanpeso 1 | 0.0278 $
-egyptpound 1 | 0.181 $
-elsalvadorcolon 1 | 0.1143 $
-europeuro 1 | 1.4577 $
-guatemalaquetzal 1 | 0.121 $
-honduraslempira 1 | 0.0529 $
-hongkongdollar 1 | 0.129 $
-hungaryforint 1 | 0.0054 $
-indiarupee 1 | 0.0207 $
-indonesiarupiah 1 | 0.0001 $
-israelshekel 1 | 0.2643 $
-japanyen 1 | 0.0109 $
-kenyashilling 1 | 0.0132 $
-kuwaitdinar 1 | 3.4854 $
-lebanonpound 1 | 0.0007 $
-malaysiaringgit 1 | 0.286 $
-mexicopeso 1 | 0.0748 $
-newzealanddollar 1 | 0.7028 $
-nicaraguacordoba 1 | 0.0487 $
-norwaykrone 1 | 0.1681 $
-pakistanrupee 1 | 0.0121 $
-paraguayguarani 1 | 0.0002 $
-perunewsol 1 | 0.3384 $
-philippinespeso 1 | 0.0207 $
-polandzloty 1 | 0.352 $
-russiaruble 1 | 0.0324 $
-saudiarabiariyal 1 | 0.2666 $
-singaporedollar 1 | 0.7018 $
-slovakkoruna 1 | 0.0484 $
-southafricarand 1 | 0.132 $
-southkoreawon 1 | 0.0008 $
-swedenkrona 1 | 0.1429 $
-switzerlandfranc 1 | 0.9627 $
-taiwandollar 1 | 0.0306 $
-thailandbaht 1 | 0.0294 $
-turkeynewlira 1 | 0.6678 $
-uaedirham 1 | 0.2722 $
-uruguaynewpeso 1 | 0.0451 $
-vietnamdong 1 | 0.0001 $
-
-/ END MONEY
-
-€ europeuro
-£ britainpound
-¥ japanyen
-dollar $
-
-baht thailandbaht
-brpound britainpound
-dirham uaedirham
-euro europeuro
-forint hungaryforint
-krona swedenkrona
-peso mexicopeso
-rand southafricarand
-real brazilreal
-yuan chinayuan
-ringgit malaysiaringgit
-riyal saudiarabiariyal
-ruble russiaruble
-rupee indiarupee
-rupiah indonesiarupiah
-shekel israelshekel
-sol perunewsol
-won southkoreawon
-yen japanyen
-zloty polandzloty
-
-usdollar dollar
-sterling britainpound | pound
-poundsterling britainpound
-
-/bits
-
-baud bit/sec
-byte 8 bit
-short 2 byte
-long 4 byte
-vlong 8 bytes
-frame 2352 byte
-
-/Australian liquid measure
-
-pony 7 brfloz
-midie 10 brfloz
-pot midie
-handle midie
-schooner 15 brfloz
-jug 40 brfloz
-resch midie
-alf midie
-tinny 13 brfloz
-stubby tinny
-twisty 250 ml
-longneck 2 tinny
-slab 24 tinny
-sixpack 6 tinny
-nip brfloz
-
-/wine
-winebottle 750 ml
-balthazar 16 winebottle
-jeroboam 4 winebottle
-magnum 2 winebottle
-mathusalem 8 winebottle
-methuselah 8 winebottle
-nebuchadnezzar 20 winebottle
-rehoboam 6 winebottle
-salmanazar 12 winebottle
-split 0.25 winebottle
-jigger 1.5 floz
-
-/Trivia
-
-% 1|100
-admiraltyknot 6080 ft/hr
-ε₀ (1e-9/36π) farad/m
-α (1/4π ε₀) e²/ℏ c
-alpha α
-apostilb cd/π m²
-are 1e+2 m²
-arpentcan 27.52 mi
-arpentlin 191.835 ft
-astronomicalunit au
-atmosphere 1.01325e+5 nt/m²
-atm atmosphere
-atomicmassunit 1.66044e-27 kg
-amu atomicmassunit
-bag 94 lb
-bakersdozen 13
-bar 1e+5 nt/m²
-barie 1e-1 nt/m²
-barleycorn 1|3 in
-barn 1e-28 m²
-barrel 42 gal
-barye 1e-1 nt/m²
-bev 1e+9 e volt
-biot 10 amp
-blondel cd/π m²
-boardfoot 144 in³
-bolt 40 yd
-bottommeasure 1|40 in
-britishthermalunit 1.05506e+3 joule
-btu britishthermalunit
-quad 1.0e+15 btu
-refrigeration 12000 btu/ton hour
-buck dollar
-cable 720 ft
-caliber 1e-2 in
-calorie cal
-carat 205 mg
-cent centidollar
-cental 100 lb
-centesimalminute 1e-2 grad
-centesimalsecond 1e-4 grad
-century 100 year
-cfs ft³/sec
-chain 66 ft
-circularinch 1|4 π in²
-circularmil 1e-6|4 π in²
-clusec 1e-8 mm hg m³/s
-coomb 4 bu
-cord 128 ft³
-cordfoot cord
-crith 9.06e-2 gm
-cubit 18 in
-cup 1|2 pt
-curie 3.7e+10/sec
-cusec ft³/sec
-dalton amu
-decade 10 yr
-degK °K
-degC °C
-degF °F
-dipotre 1/m
-displacementton 35 ft³
-doppelzentner 100 kg
-dozen 12
-drop .03 cm³
-dyne cm gm/sec²
-electronvolt e volt
-ell 45 in
-engineerschain 100 ft
-engineerslink 100|100 ft
-equivalentfootcandle lumen/π ft²
-equivalentlux lumen/π m²
-equivalentphot cd/π cm²
-erg cm²gm/sec²
-ev e volt
-faraday 9.652e+4 coul
-fathom 6 ft
-fermi 1e-15 m
-fifth 4|5 qt
-fin 5 dollar
-finger 7|8 in
-firkin 9 gal
-footcandle lumen/ft²
-footlambert cd/π ft²
-fortnight 14 da
-franklin 3.33564e-10 coul
-frigorie kilocal
-furlong 220 yd
-galileo 1e-2 m/sec²
-gamma 1e-9 weber/m²
-gauss 1e-4 weber/m²
-geodeticfoot british ft
-geographicalmile 1852 m
-gilbert 7.95775e-1 amp
-gill 1|4 pt
-gross 144
-gunterschain 22 yd
-hand 4 in
-hectare 1e+4 m²
-hefnercandle .92 cd
-hertz 1/sec
-hogshead 2 barrel
-hd hogshead
-homestead 1|4 mi²
-horsepower 550 ft lb g/sec
-hp horsepower
-hyl gm force sec²/m
-hz 1/sec
-imaginarycubicfoot 1.4 ft³
-karat 1|24
-kcal kilocal
-kcalorie kilocal
-kev 1e+3 e volt
-key kg
-khz 1e+3/sec
-kilderkin 18 gal
-knot nmile/hr
-kwh kilowatt hour
-lambert cd/π cm²
-langley cal/cm²
-last 80 bu
-league 3 mi
-lightyear c yr
-ly lightyear
-lightsecond c sec
-line 1|12 in
-link 66|100 ft
-longhundredweight 112 lb
-longquarter 28 lb
-lusec 1e-6 mm hg m³/s
-mach 331.46 m/sec
-marineleague 3 nmile
-maxwell 1e-8 weber
-metriccarat 200 mg
-mev 1e+6 e volt
-mgd megagal/day
-mh millihenry
-mhz 1e+6/sec
-mil 1e-3 in
-millenium 1000 year
-minersinch 1.5 ft³/min
-minim 1|60 fldr
-mo month
-mpg mile/gal
-mph mile/hr
-nail 1|16 yd
-nauticalmile nmile
-nit cd/m²
-noggin 1|8 qt
-nox 1e-3 lux
-ns nanosec
-oersted 2.5e+2 amp/m π
-oe oersted
-pace 36 in
-palm 3 in
-parasang 3.5 mi
-parsec au radian/arcsec
-pascal nt/m²
-pc parsec
-pennyweight 1|20 oz
-percent %
-perch rd
-pf picofarad
-phot lumen/cm²
-pica 1|6 in
-pieze 1e+3 nt/m²
-pipe 4 barrel
-point 1|72 in
-poise gm/cm sec
-pole rd
-poundal ft lb/sec²
-pdl poundal
-proof 1/200
-psi lb g/in²
-quarter 9 in
-quartersection 1|4 mi²
-quintal 100 kg
-quire 25
-rad 100 erg/gm
-ream 500
-registerton 100 ft³
-rhe 10 m²/nt sec
-rontgen 2.58e-4 curie/kg
-rood 1.21e+3 yd
-rope 20 ft
-rutherford 1e+6/sec
-rydberg 1.36054e+1 ev
-sabin 1 ft²
-sack 3 bu
-seam 8 bu
-section mi²
-shippington 40 ft³
-shorthundredweight 100 lb
-shortquarter 25 lb
-siemens 1/Ω
-σ 5.66956e-5 erg/cm² °K^4 sec
-sigma σ
-skein 120 yd
-skot 1e-3 apostilb
-slug lb g sec²/ft
-span 9 in
-spat 4 π sr
-spindle 14400 yd
-square 100 ft²
-squidge 1|972 inch
-catsquidge 1|432 inch
-stere m³
-sthene 1e+3 nt
-stilb cd/cm²
-stoke 1e-4 m²/sec
-stone 14 lb
-strike 2 bu
-surveyfoot british ft
-surveyorschain 66 ft
-surveyorslink 66|100 ft
-tablespoon 4 fldr
-teaspoon 4|3 fldr
-tesla weber/m²
-therm 1e+5 btu
-thermie 1e+6 cal
-timberfoot ft³
-tnt 4.6e+6 m²/sec²
-tonne 1e+6 gm
-torr mm hg
-township 36 mi²
-tun 8 barrel
-water .22491|2.54 kg/m²sec²
-wey 40 bu
-weymass 252 lb
-Xunit 1.00202e-13 m
-k 1.38047e-16 erg/°K
-foal 9223372036854775807
diff --git a/src/cmd/goyacc/units.y b/src/cmd/goyacc/units.y
deleted file mode 100644
index 06ce11693..000000000
--- a/src/cmd/goyacc/units.y
+++ /dev/null
@@ -1,761 +0,0 @@
-// Derived from Plan 9's /sys/src/cmd/units.y
-// http://plan9.bell-labs.com/sources/plan9/sys/src/cmd/units.y
-//
-// Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
-// Portions Copyright 2009 The Go Authors. All Rights Reserved.
-// Distributed under the terms of the Lucent Public License Version 1.02
-// See http://plan9.bell-labs.com/plan9/license.html
-
-// Generate parser with prefix "units_":
-// goyacc -p "units_"
-
-%{
-
-// units.y
-// example of a goyacc program
-// usage is
-// goyacc units.y (produces y.go)
-// 6g y.go
-// 6l y.6
-// ./6.out $GOROOT/src/cmd/goyacc/units
-// you have: c
-// you want: furlongs/fortnight
-// * 1.8026178e+12
-// / 5.5474878e-13
-// you have:
-
-package main
-
-import (
- "flag"
- "fmt"
- "bufio"
- "os"
- "math"
- "strconv"
- "utf8"
-)
-
-const (
- Ndim = 15 // number of dimensions
- Maxe = 695 // log of largest number
-)
-
-type Node struct {
- vval float64
- dim [Ndim]int8
-}
-
-type Var struct {
- name string
- node Node
-}
-
-var fi *bufio.Reader // input
-var fund [Ndim]*Var // names of fundamental units
-var line string // current input line
-var lineno int // current input line number
-var linep int // index to next rune in unput
-var nerrors int // error count
-var one Node // constant one
-var peekrune int // backup runt from input
-var retnode1 Node
-var retnode2 Node
-var retnode Node
-var sym string
-var vflag bool
-
-%}
-
-%union
-{
- node Node;
- vvar *Var;
- numb int;
- vval float64;
-}
-
-%type <node> prog expr expr0 expr1 expr2 expr3 expr4
-
-%token <vval> VAL
-%token <vvar> VAR
-%token <numb> SUP
-%%
-prog:
- ':' VAR expr
- {
- var f int;
-
- f = int($2.node.dim[0]);
- $2.node = $3;
- $2.node.dim[0] = 1;
- if f != 0 {
- Errorf("redefinition of %v", $2.name);
- } else
- if vflag {
- fmt.Printf("%v\t%v\n", $2.name, &$2.node);
- }
- }
-| ':' VAR '#'
- {
- var f, i int;
-
- for i=1; i<Ndim; i++ {
- if fund[i] == nil {
- break;
- }
- }
- if i >= Ndim {
- Errorf("too many dimensions");
- i = Ndim-1;
- }
- fund[i] = $2;
-
- f = int($2.node.dim[0]);
- $2.node = one;
- $2.node.dim[0] = 1;
- $2.node.dim[i] = 1;
- if f != 0 {
- Errorf("redefinition of %v", $2.name);
- } else
- if vflag {
- fmt.Printf("%v\t#\n", $2.name);
- }
- }
-| ':'
- {
- }
-| '?' expr
- {
- retnode1 = $2;
- }
-| '?'
- {
- retnode1 = one;
- }
-
-expr:
- expr4
-| expr '+' expr4
- {
- add(&$$, &$1, &$3);
- }
-| expr '-' expr4
- {
- sub(&$$, &$1, &$3);
- }
-
-expr4:
- expr3
-| expr4 '*' expr3
- {
- mul(&$$, &$1, &$3);
- }
-| expr4 '/' expr3
- {
- div(&$$, &$1, &$3);
- }
-
-expr3:
- expr2
-| expr3 expr2
- {
- mul(&$$, &$1, &$2);
- }
-
-expr2:
- expr1
-| expr2 SUP
- {
- xpn(&$$, &$1, $2);
- }
-| expr2 '^' expr1
- {
- var i int;
-
- for i=1; i<Ndim; i++ {
- if $3.dim[i] != 0 {
- Errorf("exponent has units");
- $$ = $1;
- break;
- }
- }
- if i >= Ndim {
- i = int($3.vval);
- if float64(i) != $3.vval {
- Errorf("exponent not integral");
- }
- xpn(&$$, &$1, i);
- }
- }
-
-expr1:
- expr0
-| expr1 '|' expr0
- {
- div(&$$, &$1, &$3);
- }
-
-expr0:
- VAR
- {
- if $1.node.dim[0] == 0 {
- Errorf("undefined %v", $1.name);
- $$ = one;
- } else
- $$ = $1.node;
- }
-| VAL
- {
- $$ = one;
- $$.vval = $1;
- }
-| '(' expr ')'
- {
- $$ = $2;
- }
-%%
-
-type UnitsLex int
-
-func (UnitsLex) Lex(yylval *units_SymType) int {
- var c, i int
-
- c = peekrune
- peekrune = ' '
-
-loop:
- if (c >= '0' && c <= '9') || c == '.' {
- goto numb
- }
- if ralpha(c) {
- goto alpha
- }
- switch c {
- case ' ', '\t':
- c = getrune()
- goto loop
- case '×':
- return '*'
- case '÷':
- return '/'
- case '¹', 'ⁱ':
- yylval.numb = 1
- return SUP
- case '²', '⁲':
- yylval.numb = 2
- return SUP
- case '³', '⁳':
- yylval.numb = 3
- return SUP
- }
- return c
-
-alpha:
- sym = ""
- for i = 0; ; i++ {
- sym += string(c)
- c = getrune()
- if !ralpha(c) {
- break
- }
- }
- peekrune = c
- yylval.vvar = lookup(0)
- return VAR
-
-numb:
- sym = ""
- for i = 0; ; i++ {
- sym += string(c)
- c = getrune()
- if !rdigit(c) {
- break
- }
- }
- peekrune = c
- f, err := strconv.Atof64(sym)
- if err != nil {
- fmt.Printf("error converting %v\n", sym)
- f = 0
- }
- yylval.vval = f
- return VAL
-}
-
-func (UnitsLex) Error(s string) {
- Errorf("syntax error, last name: %v", sym)
-}
-
-func main() {
- var file string
-
- flag.BoolVar(&vflag, "v", false, "verbose")
-
- flag.Parse()
-
- file = os.Getenv("GOROOT") + "/src/cmd/goyacc/units.txt"
- if flag.NArg() > 0 {
- file = flag.Arg(0)
- }
-
- f, err := os.Open(file)
- if err != nil {
- fmt.Fprintf(os.Stderr, "error opening %v: %v\n", file, err)
- os.Exit(1)
- }
- fi = bufio.NewReader(f)
-
- one.vval = 1
-
- /*
- * read the 'units' file to
- * develope a database
- */
- lineno = 0
- for {
- lineno++
- if readline() {
- break
- }
- if len(line) == 0 || line[0] == '/' {
- continue
- }
- peekrune = ':'
- units_Parse(UnitsLex(0))
- }
-
- /*
- * read the console to
- * print ratio of pairs
- */
- fi = bufio.NewReader(os.NewFile(0, "stdin"))
-
- lineno = 0
- for {
- if (lineno & 1) != 0 {
- fmt.Printf("you want: ")
- } else {
- fmt.Printf("you have: ")
- }
- if readline() {
- break
- }
- peekrune = '?'
- nerrors = 0
- units_Parse(UnitsLex(0))
- if nerrors != 0 {
- continue
- }
- if (lineno & 1) != 0 {
- if specialcase(&retnode, &retnode2, &retnode1) {
- fmt.Printf("\tis %v\n", &retnode)
- } else {
- div(&retnode, &retnode2, &retnode1)
- fmt.Printf("\t* %v\n", &retnode)
- div(&retnode, &retnode1, &retnode2)
- fmt.Printf("\t/ %v\n", &retnode)
- }
- } else {
- retnode2 = retnode1
- }
- lineno++
- }
- fmt.Printf("\n")
- os.Exit(0)
-}
-
-/*
- * all characters that have some
- * meaning. rest are usable as names
- */
-func ralpha(c int) bool {
- switch c {
- case 0, '+', '-', '*', '/', '[', ']', '(', ')',
- '^', ':', '?', ' ', '\t', '.', '|', '#',
- '×', '÷', '¹', 'ⁱ', '²', '⁲', '³', '⁳':
- return false
- }
- return true
-}
-
-/*
- * number forming character
- */
-func rdigit(c int) bool {
- switch c {
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '.', 'e', '+', '-':
- return true
- }
- return false
-}
-
-func Errorf(s string, v ...interface{}) {
- fmt.Printf("%v: %v\n\t", lineno, line)
- fmt.Printf(s, v...)
- fmt.Printf("\n")
-
- nerrors++
- if nerrors > 5 {
- fmt.Printf("too many errors\n")
- os.Exit(1)
- }
-}
-
-func add(c, a, b *Node) {
- var i int
- var d int8
-
- for i = 0; i < Ndim; i++ {
- d = a.dim[i]
- c.dim[i] = d
- if d != b.dim[i] {
- Errorf("add must be like units")
- }
- }
- c.vval = fadd(a.vval, b.vval)
-}
-
-func sub(c, a, b *Node) {
- var i int
- var d int8
-
- for i = 0; i < Ndim; i++ {
- d = a.dim[i]
- c.dim[i] = d
- if d != b.dim[i] {
- Errorf("sub must be like units")
- }
- }
- c.vval = fadd(a.vval, -b.vval)
-}
-
-func mul(c, a, b *Node) {
- var i int
-
- for i = 0; i < Ndim; i++ {
- c.dim[i] = a.dim[i] + b.dim[i]
- }
- c.vval = fmul(a.vval, b.vval)
-}
-
-func div(c, a, b *Node) {
- var i int
-
- for i = 0; i < Ndim; i++ {
- c.dim[i] = a.dim[i] - b.dim[i]
- }
- c.vval = fdiv(a.vval, b.vval)
-}
-
-func xpn(c, a *Node, b int) {
- var i int
-
- *c = one
- if b < 0 {
- b = -b
- for i = 0; i < b; i++ {
- div(c, c, a)
- }
- } else {
- for i = 0; i < b; i++ {
- mul(c, c, a)
- }
- }
-}
-
-func specialcase(c, a, b *Node) bool {
- var i int
- var d, d1, d2 int8
-
- d1 = 0
- d2 = 0
- for i = 1; i < Ndim; i++ {
- d = a.dim[i]
- if d != 0 {
- if d != 1 || d1 != 0 {
- return false
- }
- d1 = int8(i)
- }
- d = b.dim[i]
- if d != 0 {
- if d != 1 || d2 != 0 {
- return false
- }
- d2 = int8(i)
- }
- }
- if d1 == 0 || d2 == 0 {
- return false
- }
-
- if fund[d1].name == "°C" && fund[d2].name == "°F" &&
- b.vval == 1 {
- for ll := 0; ll < len(c.dim); ll++ {
- c.dim[ll] = b.dim[ll]
- }
- c.vval = a.vval*9./5. + 32.
- return true
- }
-
- if fund[d1].name == "°F" && fund[d2].name == "°C" &&
- b.vval == 1 {
- for ll := 0; ll < len(c.dim); ll++ {
- c.dim[ll] = b.dim[ll]
- }
- c.vval = (a.vval - 32.) * 5. / 9.
- return true
- }
- return false
-}
-
-func printdim(str string, d, n int) string {
- var v *Var
-
- if n != 0 {
- v = fund[d]
- if v != nil {
- str += fmt.Sprintf("%v", v.name)
- } else {
- str += fmt.Sprintf("[%d]", d)
- }
- switch n {
- case 1:
- break
- case 2:
- str += "²"
- case 3:
- str += "³"
- default:
- str += fmt.Sprintf("^%d", n)
- }
- }
- return str
-}
-
-func (n Node) String() string {
- var str string
- var f, i, d int
-
- str = fmt.Sprintf("%.7e ", n.vval)
-
- f = 0
- for i = 1; i < Ndim; i++ {
- d = int(n.dim[i])
- if d > 0 {
- str = printdim(str, i, d)
- } else if d < 0 {
- f = 1
- }
- }
-
- if f != 0 {
- str += " /"
- for i = 1; i < Ndim; i++ {
- d = int(n.dim[i])
- if d < 0 {
- str = printdim(str, i, -d)
- }
- }
- }
-
- return str
-}
-
-func (v *Var) String() string {
- var str string
- str = fmt.Sprintf("%v %v", v.name, v.node)
- return str
-}
-
-func readline() bool {
- s, err := fi.ReadString('\n')
- if err != nil {
- return true
- }
- line = s
- linep = 0
- return false
-}
-
-func getrune() int {
- var c, n int
-
- if linep >= len(line) {
- return 0
- }
- c, n = utf8.DecodeRuneInString(line[linep:len(line)])
- linep += n
- if c == '\n' {
- c = 0
- }
- return c
-}
-
-var symmap = make(map[string]*Var) // symbol table
-
-func lookup(f int) *Var {
- var p float64
- var w *Var
-
- v, ok := symmap[sym]
- if ok {
- return v
- }
- if f != 0 {
- return nil
- }
- v = new(Var)
- v.name = sym
- symmap[sym] = v
-
- p = 1
- for {
- p = fmul(p, pname())
- if p == 0 {
- break
- }
- w = lookup(1)
- if w != nil {
- v.node = w.node
- v.node.vval = fmul(v.node.vval, p)
- break
- }
- }
- return v
-}
-
-type Prefix struct {
- vval float64
- name string
-}
-
-var prefix = []Prefix{ // prefix table
- Prefix{1e-24, "yocto"},
- Prefix{1e-21, "zepto"},
- Prefix{1e-18, "atto"},
- Prefix{1e-15, "femto"},
- Prefix{1e-12, "pico"},
- Prefix{1e-9, "nano"},
- Prefix{1e-6, "micro"},
- Prefix{1e-6, "μ"},
- Prefix{1e-3, "milli"},
- Prefix{1e-2, "centi"},
- Prefix{1e-1, "deci"},
- Prefix{1e1, "deka"},
- Prefix{1e2, "hecta"},
- Prefix{1e2, "hecto"},
- Prefix{1e3, "kilo"},
- Prefix{1e6, "mega"},
- Prefix{1e6, "meg"},
- Prefix{1e9, "giga"},
- Prefix{1e12, "tera"},
- Prefix{1e15, "peta"},
- Prefix{1e18, "exa"},
- Prefix{1e21, "zetta"},
- Prefix{1e24, "yotta"},
-}
-
-func pname() float64 {
- var i, j, n int
- var s string
-
- /*
- * rip off normal prefixs
- */
- n = len(sym)
- for i = 0; i < len(prefix); i++ {
- s = prefix[i].name
- j = len(s)
- if j < n && sym[0:j] == s {
- sym = sym[j:n]
- return prefix[i].vval
- }
- }
-
- /*
- * rip off 's' suffixes
- */
- if n > 2 && sym[n-1] == 's' {
- sym = sym[0 : n-1]
- return 1
- }
-
- return 0
-}
-
-
-// careful multiplication
-// exponents (log) are checked before multiply
-func fmul(a, b float64) float64 {
- var l float64
-
- if b <= 0 {
- if b == 0 {
- return 0
- }
- l = math.Log(-b)
- } else {
- l = math.Log(b)
- }
-
- if a <= 0 {
- if a == 0 {
- return 0
- }
- l += math.Log(-a)
- } else {
- l += math.Log(a)
- }
-
- if l > Maxe {
- Errorf("overflow in multiply")
- return 1
- }
- if l < -Maxe {
- Errorf("underflow in multiply")
- return 0
- }
- return a * b
-}
-
-// careful division
-// exponents (log) are checked before divide
-func fdiv(a, b float64) float64 {
- var l float64
-
- if b <= 0 {
- if b == 0 {
- Errorf("division by zero: %v %v", a, b)
- return 1
- }
- l = math.Log(-b)
- } else {
- l = math.Log(b)
- }
-
- if a <= 0 {
- if a == 0 {
- return 0
- }
- l -= math.Log(-a)
- } else {
- l -= math.Log(a)
- }
-
- if l < -Maxe {
- Errorf("overflow in divide")
- return 1
- }
- if l > Maxe {
- Errorf("underflow in divide")
- return 0
- }
- return a / b
-}
-
-func fadd(a, b float64) float64 {
- return a + b
-}
diff --git a/src/cmd/hgpatch/Makefile b/src/cmd/hgpatch/Makefile
deleted file mode 100644
index 1ef98d7f9..000000000
--- a/src/cmd/hgpatch/Makefile
+++ /dev/null
@@ -1,11 +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 ../../Make.inc
-
-TARG=hgpatch
-GOFILES=\
- main.go\
-
-include ../../Make.cmd
diff --git a/src/cmd/hgpatch/doc.go b/src/cmd/hgpatch/doc.go
deleted file mode 100644
index 1e0f1da38..000000000
--- a/src/cmd/hgpatch/doc.go
+++ /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.
-
-/*
-
-Hgpatch applies a patch to the local Mercurial repository.
-The patch should have been been generated by
-a version control system like CVS, Git, Mercurial, or Subversion.
-If successful, hgpatch writes a list of affected files to standard output.
-
-Hgpatch is meant to be used by the Mercurial codereview extension.
-
-Usage:
- hgpatch [patchfile]
-
-*/
-package documentation
diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go
deleted file mode 100644
index 4f7aec22b..000000000
--- a/src/cmd/hgpatch/main.go
+++ /dev/null
@@ -1,361 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "bytes"
- "container/vector"
- "exec"
- "flag"
- "fmt"
- "io/ioutil"
- "os"
- "patch"
- "path/filepath"
- "sort"
- "strings"
-)
-
-var checkSync = flag.Bool("checksync", true, "check whether repository is out of sync")
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: hgpatch [options] [patchfile]\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-func main() {
- flag.Usage = usage
- flag.Parse()
-
- args := flag.Args()
- var data []byte
- var err os.Error
- switch len(args) {
- case 0:
- data, err = ioutil.ReadAll(os.Stdin)
- case 1:
- data, err = ioutil.ReadFile(args[0])
- default:
- usage()
- }
- chk(err)
-
- pset, err := patch.Parse(data)
- chk(err)
-
- // Change to hg root directory, because
- // patch paths are relative to root.
- root, err := hgRoot()
- chk(err)
- chk(os.Chdir(root))
-
- // Make sure there are no pending changes on the server.
- if *checkSync && hgIncoming() {
- fmt.Fprintf(os.Stderr, "incoming changes waiting; run hg sync first\n")
- os.Exit(2)
- }
-
- // Make sure we won't be editing files with local pending changes.
- dirtylist, err := hgModified()
- chk(err)
- dirty := make(map[string]bool)
- for _, f := range dirtylist {
- dirty[f] = true
- }
- conflict := make(map[string]bool)
- for _, f := range pset.File {
- if f.Verb == patch.Delete || f.Verb == patch.Rename {
- if dirty[f.Src] {
- conflict[f.Src] = true
- }
- }
- if f.Verb != patch.Delete {
- if dirty[f.Dst] {
- conflict[f.Dst] = true
- }
- }
- }
- if len(conflict) > 0 {
- fmt.Fprintf(os.Stderr, "cannot apply patch to locally modified files:\n")
- for name := range conflict {
- fmt.Fprintf(os.Stderr, "\t%s\n", name)
- }
- os.Exit(2)
- }
-
- // Apply changes in memory.
- op, err := pset.Apply(ioutil.ReadFile)
- chk(err)
-
- // Write changes to disk copy: order of commands matters.
- // Accumulate undo log as we go, in case there is an error.
- // Also accumulate list of modified files to print at end.
- changed := make(map[string]int)
-
- // Copy, Rename create the destination file, so they
- // must happen before we write the data out.
- // A single patch may have a Copy and a Rename
- // with the same source, so we have to run all the
- // Copy in one pass, then all the Rename.
- for i := range op {
- o := &op[i]
- if o.Verb == patch.Copy {
- makeParent(o.Dst)
- chk(hgCopy(o.Dst, o.Src))
- undoRevert(o.Dst)
- changed[o.Dst] = 1
- }
- }
- for i := range op {
- o := &op[i]
- if o.Verb == patch.Rename {
- makeParent(o.Dst)
- chk(hgRename(o.Dst, o.Src))
- undoRevert(o.Dst)
- undoRevert(o.Src)
- changed[o.Src] = 1
- changed[o.Dst] = 1
- }
- }
-
- // Run Delete before writing to files in case one of the
- // deleted paths is becoming a directory.
- for i := range op {
- o := &op[i]
- if o.Verb == patch.Delete {
- chk(hgRemove(o.Src))
- undoRevert(o.Src)
- changed[o.Src] = 1
- }
- }
-
- // Write files.
- for i := range op {
- o := &op[i]
- if o.Verb == patch.Delete {
- continue
- }
- if o.Verb == patch.Add {
- makeParent(o.Dst)
- changed[o.Dst] = 1
- }
- if o.Data != nil {
- chk(ioutil.WriteFile(o.Dst, o.Data, 0644))
- if o.Verb == patch.Add {
- undoRm(o.Dst)
- } else {
- undoRevert(o.Dst)
- }
- changed[o.Dst] = 1
- }
- if o.Mode != 0 {
- chk(os.Chmod(o.Dst, uint32(o.Mode&0755)))
- undoRevert(o.Dst)
- changed[o.Dst] = 1
- }
- }
-
- // hg add looks at the destination file, so it must happen
- // after we write the data out.
- for i := range op {
- o := &op[i]
- if o.Verb == patch.Add {
- chk(hgAdd(o.Dst))
- undoRevert(o.Dst)
- changed[o.Dst] = 1
- }
- }
-
- // Finished editing files. Write the list of changed files to stdout.
- list := make([]string, len(changed))
- i := 0
- for f := range changed {
- list[i] = f
- i++
- }
- sort.Strings(list)
- for _, f := range list {
- fmt.Printf("%s\n", f)
- }
-}
-
-
-// make parent directory for name, if necessary
-func makeParent(name string) {
- parent, _ := filepath.Split(name)
- chk(mkdirAll(parent, 0755))
-}
-
-// Copy of os.MkdirAll but adds to undo log after
-// creating a directory.
-func mkdirAll(path string, perm uint32) os.Error {
- dir, err := os.Lstat(path)
- if err == nil {
- if dir.IsDirectory() {
- return nil
- }
- return &os.PathError{"mkdir", path, os.ENOTDIR}
- }
-
- i := len(path)
- for i > 0 && path[i-1] == '/' { // Skip trailing slashes.
- i--
- }
-
- j := i
- for j > 0 && path[j-1] != '/' { // Scan backward over element.
- j--
- }
-
- if j > 0 {
- err = mkdirAll(path[0:j-1], perm)
- if err != nil {
- return err
- }
- }
-
- err = os.Mkdir(path, perm)
- if err != nil {
- // Handle arguments like "foo/." by
- // double-checking that directory doesn't exist.
- dir, err1 := os.Lstat(path)
- if err1 == nil && dir.IsDirectory() {
- return nil
- }
- return err
- }
- undoRm(path)
- return nil
-}
-
-// If err != nil, process the undo log and exit.
-func chk(err os.Error) {
- if err != nil {
- fmt.Fprintf(os.Stderr, "%s\n", err)
- runUndo()
- os.Exit(2)
- }
-}
-
-
-// Undo log
-type undo func() os.Error
-
-var undoLog vector.Vector // vector of undo
-
-func undoRevert(name string) { undoLog.Push(undo(func() os.Error { return hgRevert(name) })) }
-
-func undoRm(name string) { undoLog.Push(undo(func() os.Error { return os.Remove(name) })) }
-
-func runUndo() {
- for i := undoLog.Len() - 1; i >= 0; i-- {
- if err := undoLog.At(i).(undo)(); err != nil {
- fmt.Fprintf(os.Stderr, "%s\n", err)
- }
- }
-}
-
-
-// hgRoot returns the root directory of the repository.
-func hgRoot() (string, os.Error) {
- out, err := run([]string{"hg", "root"}, nil)
- if err != nil {
- return "", err
- }
- return strings.TrimSpace(out), nil
-}
-
-// hgIncoming returns true if hg sync will pull in changes.
-func hgIncoming() bool {
- // hg -q incoming exits 0 when there is nothing incoming, 1 otherwise.
- _, err := run([]string{"hg", "-q", "incoming"}, nil)
- return err == nil
-}
-
-// hgModified returns a list of the modified files in the
-// repository.
-func hgModified() ([]string, os.Error) {
- out, err := run([]string{"hg", "status", "-n"}, nil)
- if err != nil {
- return nil, err
- }
- return strings.Split(strings.TrimSpace(out), "\n"), nil
-}
-
-// hgAdd adds name to the repository.
-func hgAdd(name string) os.Error {
- _, err := run([]string{"hg", "add", name}, nil)
- return err
-}
-
-// hgRemove removes name from the repository.
-func hgRemove(name string) os.Error {
- _, err := run([]string{"hg", "rm", name}, nil)
- return err
-}
-
-// hgRevert reverts name.
-func hgRevert(name string) os.Error {
- _, err := run([]string{"hg", "revert", name}, nil)
- return err
-}
-
-// hgCopy copies src to dst in the repository.
-// Note that the argument order matches io.Copy, not "hg cp".
-func hgCopy(dst, src string) os.Error {
- _, err := run([]string{"hg", "cp", src, dst}, nil)
- return err
-}
-
-// hgRename renames src to dst in the repository.
-// Note that the argument order matches io.Copy, not "hg mv".
-func hgRename(dst, src string) os.Error {
- _, err := run([]string{"hg", "mv", src, dst}, nil)
- return err
-}
-
-func dup(a []string) []string {
- b := make([]string, len(a))
- copy(b, a)
- return b
-}
-
-var lookPathCache = make(map[string]string)
-
-// run runs the command argv, resolving argv[0] if necessary by searching $PATH.
-// It provides input on standard input to the command.
-func run(argv []string, input []byte) (out string, err os.Error) {
- if len(argv) < 1 {
- return "", &runError{dup(argv), os.EINVAL}
- }
-
- prog, ok := lookPathCache[argv[0]]
- if !ok {
- prog, err = exec.LookPath(argv[0])
- if err != nil {
- return "", &runError{dup(argv), err}
- }
- lookPathCache[argv[0]] = prog
- }
-
- cmd := exec.Command(prog, argv[1:]...)
- if len(input) > 0 {
- cmd.Stdin = bytes.NewBuffer(input)
- }
- bs, err := cmd.CombinedOutput()
- if err != nil {
- return "", &runError{dup(argv), err}
- }
- return string(bs), nil
-}
-
-// A runError represents an error that occurred while running a command.
-type runError struct {
- cmd []string
- err os.Error
-}
-
-func (e *runError) String() string { return strings.Join(e.cmd, " ") + ": " + e.err.String() }
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
deleted file mode 100644
index f1132fc8b..000000000
--- a/src/cmd/ld/data.c
+++ /dev/null
@@ -1,970 +0,0 @@
-// Inferno utils/8l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/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.
-
-// Data layout and relocation.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-#include "../ld/pe.h"
-
-void dynreloc(void);
-
-/*
- * divide-and-conquer list-link
- * sort of Sym* structures.
- * Used for the data block.
- */
-int
-datcmp(Sym *s1, Sym *s2)
-{
- if(s1->type != s2->type)
- return (int)s1->type - (int)s2->type;
- if(s1->size != s2->size) {
- if(s1->size < s2->size)
- return -1;
- return +1;
- }
- return strcmp(s1->name, s2->name);
-}
-
-Sym*
-datsort(Sym *l)
-{
- Sym *l1, *l2, *le;
-
- if(l == 0 || l->next == 0)
- return l;
-
- l1 = l;
- l2 = l;
- for(;;) {
- l2 = l2->next;
- if(l2 == 0)
- break;
- l2 = l2->next;
- if(l2 == 0)
- break;
- l1 = l1->next;
- }
-
- l2 = l1->next;
- l1->next = 0;
- l1 = datsort(l);
- l2 = datsort(l2);
-
- /* set up lead element */
- if(datcmp(l1, l2) < 0) {
- l = l1;
- l1 = l1->next;
- } else {
- l = l2;
- l2 = l2->next;
- }
- le = l;
-
- for(;;) {
- if(l1 == 0) {
- while(l2) {
- le->next = l2;
- le = l2;
- l2 = l2->next;
- }
- le->next = 0;
- break;
- }
- if(l2 == 0) {
- while(l1) {
- le->next = l1;
- le = l1;
- l1 = l1->next;
- }
- break;
- }
- if(datcmp(l1, l2) < 0) {
- le->next = l1;
- le = l1;
- l1 = l1->next;
- } else {
- le->next = l2;
- le = l2;
- l2 = l2->next;
- }
- }
- le->next = 0;
- return l;
-}
-
-Reloc*
-addrel(Sym *s)
-{
- if(s->nr >= s->maxr) {
- if(s->maxr == 0)
- s->maxr = 4;
- else
- s->maxr <<= 1;
- s->r = realloc(s->r, s->maxr*sizeof s->r[0]);
- if(s->r == 0) {
- diag("out of memory");
- errorexit();
- }
- memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
- }
- return &s->r[s->nr++];
-}
-
-void
-relocsym(Sym *s)
-{
- Reloc *r;
- Prog p;
- int32 i, off, siz, fl;
- vlong o;
- uchar *cast;
-
- cursym = s;
- memset(&p, 0, sizeof p);
- for(r=s->r; r<s->r+s->nr; r++) {
- off = r->off;
- siz = r->siz;
- if(off < 0 || off+(siz&~Rbig) > s->np) {
- diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz&~Rbig, 0, s->np);
- continue;
- }
- if(r->sym != S && (r->sym->type == 0 || r->sym->type == SXREF)) {
- diag("%s: not defined", r->sym->name);
- continue;
- }
- if(r->type >= 256)
- continue;
-
- if(r->sym != S && r->sym->type == SDYNIMPORT)
- diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type);
-
- if(r->sym != S && !r->sym->reachable)
- diag("unreachable sym in relocation: %s %s", s->name, r->sym->name);
-
- switch(r->type) {
- default:
- o = 0;
- if(archreloc(r, s, &o) < 0)
- diag("unknown reloc %d", r->type);
- break;
- case D_ADDR:
- o = symaddr(r->sym) + r->add;
- break;
- case D_PCREL:
- o = symaddr(r->sym) + r->add - (s->value + r->off + r->siz);
- break;
- case D_SIZE:
- o = r->sym->size + r->add;
- break;
- }
-//print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o);
- switch(siz) {
- default:
- cursym = s;
- diag("bad reloc size %#ux for %s", siz, r->sym->name);
- case 4 + Rbig:
- fl = o;
- s->p[off] = fl>>24;
- s->p[off+1] = fl>>16;
- s->p[off+2] = fl>>8;
- s->p[off+3] = fl;
- break;
- case 4 + Rlittle:
- fl = o;
- s->p[off] = fl;
- s->p[off+1] = fl>>8;
- s->p[off+2] = fl>>16;
- s->p[off+3] = fl>>24;
- break;
- case 4:
- fl = o;
- cast = (uchar*)&fl;
- for(i=0; i<4; i++)
- s->p[off+i] = cast[inuxi4[i]];
- break;
- case 8:
- cast = (uchar*)&o;
- for(i=0; i<8; i++)
- s->p[off+i] = cast[inuxi8[i]];
- break;
- }
- }
-}
-
-void
-reloc(void)
-{
- Sym *s;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f reloc\n", cputime());
- Bflush(&bso);
-
- for(s=textp; s!=S; s=s->next)
- relocsym(s);
- for(s=datap; s!=S; s=s->next)
- relocsym(s);
-}
-
-void
-dynrelocsym(Sym *s)
-{
- Reloc *r;
-
- if(HEADTYPE == Hwindows) {
- Sym *rel, *targ;
-
- rel = lookup(".rel", 0);
- if(s == rel)
- return;
- for(r=s->r; r<s->r+s->nr; r++) {
- targ = r->sym;
- if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files.
- targ->plt = rel->size;
- r->sym = rel;
- r->add = targ->plt;
-
- // jmp *addr
- adduint8(rel, 0xff);
- adduint8(rel, 0x25);
- addaddr(rel, targ);
- adduint8(rel, 0x90);
- adduint8(rel, 0x90);
- } else if(r->sym->plt >= 0) {
- r->sym = rel;
- r->add = targ->plt;
- }
- }
- return;
- }
-
- for(r=s->r; r<s->r+s->nr; r++)
- if(r->sym->type == SDYNIMPORT || r->type >= 256)
- adddynrel(s, r);
-}
-
-void
-dynreloc(void)
-{
- Sym *s;
-
- // -d supresses dynamic loader format, so we may as well not
- // compute these sections or mark their symbols as reachable.
- if(debug['d'] && HEADTYPE != Hwindows)
- return;
- if(debug['v'])
- Bprint(&bso, "%5.2f reloc\n", cputime());
- Bflush(&bso);
-
- for(s=textp; s!=S; s=s->next)
- dynrelocsym(s);
- for(s=datap; s!=S; s=s->next)
- dynrelocsym(s);
- if(iself)
- elfdynhash();
-}
-
-void
-symgrow(Sym *s, int32 siz)
-{
- if(s->np >= siz)
- return;
-
- if(s->maxp < siz) {
- if(s->maxp == 0)
- s->maxp = 8;
- while(s->maxp < siz)
- s->maxp <<= 1;
- s->p = realloc(s->p, s->maxp);
- if(s->p == nil) {
- diag("out of memory");
- errorexit();
- }
- memset(s->p+s->np, 0, s->maxp-s->np);
- }
- s->np = siz;
-}
-
-void
-savedata(Sym *s, Prog *p, char *pn)
-{
- int32 off, siz, i, fl;
- uchar *cast;
- vlong o;
- Reloc *r;
-
- off = p->from.offset;
- siz = p->datasize;
- if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
- mangle(pn);
- symgrow(s, off+siz);
-
- switch(p->to.type) {
- default:
- diag("bad data: %P", p);
- break;
-
- case D_FCONST:
- switch(siz) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (uchar*)&fl;
- for(i=0; i<4; i++)
- s->p[off+i] = cast[fnuxi4[i]];
- break;
- case 8:
- cast = (uchar*)&p->to.ieee;
- for(i=0; i<8; i++)
- s->p[off+i] = cast[fnuxi8[i]];
- break;
- }
- break;
-
- case D_SCONST:
- for(i=0; i<siz; i++)
- s->p[off+i] = p->to.scon[i];
- break;
-
- case D_CONST:
- if(p->to.sym)
- goto Addr;
- o = p->to.offset;
- fl = o;
- cast = (uchar*)&fl;
- switch(siz) {
- default:
- diag("bad nuxi %d\n%P", siz, p);
- break;
- case 1:
- s->p[off] = cast[inuxi1[0]];
- break;
- case 2:
- for(i=0; i<2; i++)
- s->p[off+i] = cast[inuxi2[i]];
- break;
- case 4:
- for(i=0; i<4; i++)
- s->p[off+i] = cast[inuxi4[i]];
- break;
- case 8:
- cast = (uchar*)&o;
- for(i=0; i<8; i++)
- s->p[off+i] = cast[inuxi8[i]];
- break;
- }
- break;
-
- case D_ADDR:
- case D_SIZE:
- Addr:
- r = addrel(s);
- r->off = off;
- r->siz = siz;
- r->sym = p->to.sym;
- r->type = p->to.type;
- if(r->type != D_SIZE)
- r->type = D_ADDR;
- r->add = p->to.offset;
- break;
- }
-}
-
-static void
-blk(Sym *allsym, int32 addr, int32 size)
-{
- Sym *sym;
- int32 eaddr;
- uchar *p, *ep;
-
- for(sym = allsym; sym != nil; sym = sym->next)
- if(!(sym->type&SSUB) && sym->value >= addr)
- break;
-
- eaddr = addr+size;
- for(; sym != nil; sym = sym->next) {
- if(sym->type&SSUB)
- continue;
- if(sym->value >= eaddr)
- break;
- if(sym->value < addr) {
- diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type);
- errorexit();
- }
- cursym = sym;
- for(; addr < sym->value; addr++)
- cput(0);
- p = sym->p;
- ep = p + sym->np;
- while(p < ep)
- cput(*p++);
- addr += sym->np;
- for(; addr < sym->value+sym->size; addr++)
- cput(0);
- if(addr != sym->value+sym->size) {
- diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size);
- errorexit();
- }
- }
-
- for(; addr < eaddr; addr++)
- cput(0);
- cflush();
-}
-
-void
-codeblk(int32 addr, int32 size)
-{
- Sym *sym;
- int32 eaddr, n, epc;
- Prog *p;
- uchar *q;
-
- if(debug['a'])
- Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, seek(cout, 0, 1));
-
- blk(textp, addr, size);
-
- /* again for printing */
- if(!debug['a'])
- return;
-
- for(sym = textp; sym != nil; sym = sym->next) {
- if(!sym->reachable)
- continue;
- if(sym->value >= addr)
- break;
- }
-
- eaddr = addr + size;
- for(; sym != nil; sym = sym->next) {
- if(!sym->reachable)
- continue;
- if(sym->value >= eaddr)
- break;
-
- if(addr < sym->value) {
- Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
- for(; addr < sym->value; addr++)
- Bprint(&bso, " %.2ux", 0);
- Bprint(&bso, "\n");
- }
- p = sym->text;
- if(p == nil) {
- Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name);
- n = sym->size;
- q = sym->p;
-
- while(n >= 16) {
- Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
- addr += 16;
- q += 16;
- n -= 16;
- }
- if(n > 0)
- Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q);
- addr += n;
- continue;
- }
-
- Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p);
- for(p = p->link; p != P; p = p->link) {
- if(p->link != P)
- epc = p->link->pc;
- else
- epc = sym->value + sym->size;
- Bprint(&bso, "%.6ux\t", p->pc);
- q = sym->p + p->pc - sym->value;
- n = epc - p->pc;
- Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p);
- addr += n;
- }
- }
-
- if(addr < eaddr) {
- Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
- for(; addr < eaddr; addr++)
- Bprint(&bso, " %.2ux", 0);
- }
- Bflush(&bso);
-}
-
-void
-datblk(int32 addr, int32 size)
-{
- Sym *sym;
- int32 eaddr;
- uchar *p, *ep;
-
- if(debug['a'])
- Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, seek(cout, 0, 1));
-
- blk(datap, addr, size);
-
- /* again for printing */
- if(!debug['a'])
- return;
-
- for(sym = datap; sym != nil; sym = sym->next)
- if(sym->value >= addr)
- break;
-
- eaddr = addr + size;
- for(; sym != nil; sym = sym->next) {
- if(sym->value >= eaddr)
- break;
- if(addr < sym->value) {
- Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(pre-pad)", addr);
- addr = sym->value;
- }
- Bprint(&bso, "%-20s %.8ux|", sym->name, (uint)addr);
- p = sym->p;
- ep = p + sym->np;
- while(p < ep)
- Bprint(&bso, " %.2ux", *p++);
- addr += sym->np;
- for(; addr < sym->value+sym->size; addr++)
- Bprint(&bso, " %.2ux", 0);
- Bprint(&bso, "\n");
- }
-
- if(addr < eaddr)
- Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(post-pad)", (uint)addr);
- Bprint(&bso, "%-20s %.8ux|\n", "", (uint)eaddr);
-}
-
-void
-strnput(char *s, int n)
-{
- for(; *s && n > 0; s++) {
- cput(*s);
- n--;
- }
- while(n > 0) {
- cput(0);
- n--;
- }
-}
-
-vlong
-addstring(Sym *s, char *str)
-{
- int n;
- int32 r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->size;
- n = strlen(str)+1;
- if(strcmp(s->name, ".shstrtab") == 0)
- elfsetstring(str, r);
- symgrow(s, r+n);
- memmove(s->p+r, str, n);
- s->size += n;
- return r;
-}
-
-vlong
-adduintxx(Sym *s, uint64 v, int wid)
-{
- int32 i, r, fl;
- vlong o;
- uchar *cast;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->size;
- s->size += wid;
- symgrow(s, s->size);
- assert(r+wid <= s->size);
- fl = v;
- cast = (uchar*)&fl;
- switch(wid) {
- case 1:
- s->p[r] = cast[inuxi1[0]];
- break;
- case 2:
- for(i=0; i<2; i++)
- s->p[r+i] = cast[inuxi2[i]];
- break;
- case 4:
- for(i=0; i<4; i++)
- s->p[r+i] = cast[inuxi4[i]];
- break;
- case 8:
- o = v;
- cast = (uchar*)&o;
- for(i=0; i<8; i++)
- s->p[r+i] = cast[inuxi8[i]];
- break;
- }
- return r;
-}
-
-vlong
-adduint8(Sym *s, uint8 v)
-{
- return adduintxx(s, v, 1);
-}
-
-vlong
-adduint16(Sym *s, uint16 v)
-{
- return adduintxx(s, v, 2);
-}
-
-vlong
-adduint32(Sym *s, uint32 v)
-{
- return adduintxx(s, v, 4);
-}
-
-vlong
-adduint64(Sym *s, uint64 v)
-{
- return adduintxx(s, v, 8);
-}
-
-vlong
-addaddrplus(Sym *s, Sym *t, int32 add)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += PtrSize;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->siz = PtrSize;
- r->type = D_ADDR;
- r->add = add;
- return i;
-}
-
-vlong
-addpcrelplus(Sym *s, Sym *t, int32 add)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += 4;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->add = add;
- r->type = D_PCREL;
- r->siz = 4;
- return i;
-}
-
-vlong
-addaddr(Sym *s, Sym *t)
-{
- return addaddrplus(s, t, 0);
-}
-
-vlong
-addsize(Sym *s, Sym *t)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += PtrSize;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->siz = PtrSize;
- r->type = D_SIZE;
- return i;
-}
-
-void
-dodata(void)
-{
- int32 t, datsize;
- Section *sect;
- Sym *s, *last, **l;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dodata\n", cputime());
- Bflush(&bso);
-
- last = nil;
- datap = nil;
-
- for(s=allsym; s!=S; s=s->allsym) {
- if(!s->reachable || s->special)
- continue;
- if(STEXT < s->type && s->type < SXREF) {
- if(last == nil)
- datap = s;
- else
- last->next = s;
- s->next = nil;
- last = s;
- }
- }
-
- for(s = datap; s != nil; s = s->next) {
- if(s->np > 0 && s->type == SBSS)
- s->type = SDATA;
- if(s->np > s->size)
- diag("%s: initialize bounds (%lld < %d)",
- s->name, (vlong)s->size, s->np);
- }
-
- /*
- * now that we have the datap list, but before we start
- * to assign addresses, record all the necessary
- * dynamic relocations. these will grow the relocation
- * symbol, which is itself data.
- */
- dynreloc();
-
- /* some symbols may no longer belong in datap (Mach-O) */
- for(l=&datap; (s=*l) != nil; ) {
- if(s->type <= STEXT || SXREF <= s->type)
- *l = s->next;
- else
- l = &s->next;
- }
- *l = nil;
-
- datap = datsort(datap);
-
- /*
- * allocate data sections. list is sorted by type,
- * so we can just walk it for each piece we want to emit.
- */
-
- /* read-only data */
- sect = addsection(&segtext, ".rodata", 04);
- sect->vaddr = 0;
- datsize = 0;
- s = datap;
- for(; s != nil && s->type < SSYMTAB; s = s->next) {
- s->type = SRODATA;
- t = rnd(s->size, PtrSize);
- s->value = datsize;
- datsize += t;
- }
- sect->len = datsize - sect->vaddr;
-
- /* gosymtab */
- sect = addsection(&segtext, ".gosymtab", 04);
- sect->vaddr = datsize;
- for(; s != nil && s->type < SPCLNTAB; s = s->next) {
- s->type = SRODATA;
- s->value = datsize;
- datsize += s->size;
- }
- sect->len = datsize - sect->vaddr;
-
- /* gopclntab */
- sect = addsection(&segtext, ".gopclntab", 04);
- sect->vaddr = datsize;
- for(; s != nil && s->type < SDATA; s = s->next) {
- s->type = SRODATA;
- s->value = datsize;
- datsize += s->size;
- }
- sect->len = datsize - sect->vaddr;
-
- /* data */
- datsize = 0;
- sect = addsection(&segdata, ".data", 06);
- sect->vaddr = 0;
- for(; s != nil && s->type < SBSS; s = s->next) {
- s->type = SDATA;
- t = s->size;
- if(t == 0 && s->name[0] != '.') {
- diag("%s: no size", s->name);
- t = 1;
- }
- if(t >= PtrSize)
- t = rnd(t, PtrSize);
- else if(t > 2)
- t = rnd(t, 4);
- if(t & 1) {
- ;
- } else if(t & 2)
- datsize = rnd(datsize, 2);
- else if(t & 4)
- datsize = rnd(datsize, 4);
- else
- datsize = rnd(datsize, 8);
- s->value = datsize;
- datsize += t;
- }
- sect->len = datsize - sect->vaddr;
-
- /* bss */
- sect = addsection(&segdata, ".bss", 06);
- sect->vaddr = datsize;
- for(; s != nil; s = s->next) {
- if(s->type != SBSS) {
- cursym = s;
- diag("unexpected symbol type %d", s->type);
- }
- t = s->size;
- if(t >= PtrSize)
- t = rnd(t, PtrSize);
- else if(t > 2)
- t = rnd(t, 4);
- if(t & 1) {
- ;
- } else if(t & 2)
- datsize = rnd(datsize, 2);
- else if(t & 4)
- datsize = rnd(datsize, 4);
- else
- datsize = rnd(datsize, 8);
- s->value = datsize;
- datsize += t;
- }
- sect->len = datsize - sect->vaddr;
-}
-
-// assign addresses to text
-void
-textaddress(void)
-{
- uvlong va;
- Prog *p;
- Section *sect;
- Sym *sym, *sub;
-
- addsection(&segtext, ".text", 05);
-
- // Assign PCs in text segment.
- // Could parallelize, by assigning to text
- // and then letting threads copy down, but probably not worth it.
- sect = segtext.sect;
- va = INITTEXT;
- sect->vaddr = va;
- for(sym = textp; sym != nil; sym = sym->next) {
- if(sym->type & SSUB)
- continue;
- sym->value = 0;
- for(sub = sym; sub != S; sub = sub->sub) {
- sub->value += va;
- for(p = sub->text; p != P; p = p->link)
- p->pc += sub->value;
- }
- if(sym->size == 0 && sym->sub != S) {
- cursym = sym;
- }
- va += sym->size;
- }
- sect->len = va - sect->vaddr;
-}
-
-// assign addresses
-void
-address(void)
-{
- Section *s, *text, *data, *rodata, *symtab, *pclntab;
- Sym *sym, *sub;
- uvlong va;
-
- va = INITTEXT;
- segtext.rwx = 05;
- segtext.vaddr = va;
- segtext.fileoff = HEADR;
- for(s=segtext.sect; s != nil; s=s->next) {
- s->vaddr = va;
- va += s->len;
- segtext.len = va - INITTEXT;
- va = rnd(va, INITRND);
- }
- segtext.filelen = segtext.len;
-
- segdata.rwx = 06;
- segdata.vaddr = va;
- segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
- if(HEADTYPE == Hwindows)
- segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
- if(HEADTYPE == Hplan9x32)
- segdata.fileoff = segtext.fileoff + segtext.filelen;
- for(s=segdata.sect; s != nil; s=s->next) {
- s->vaddr = va;
- va += s->len;
- segdata.len = va - segdata.vaddr;
- }
- segdata.filelen = segdata.sect->len; // assume .data is first
-
- text = segtext.sect;
- rodata = text->next;
- symtab = rodata->next;
- pclntab = symtab->next;
- data = segdata.sect;
-
- for(sym = datap; sym != nil; sym = sym->next) {
- cursym = sym;
- if(sym->type < SDATA)
- sym->value += rodata->vaddr;
- else
- sym->value += data->vaddr;
- for(sub = sym->sub; sub != nil; sub = sub->sub)
- sub->value += sym->value;
- }
-
- xdefine("text", STEXT, text->vaddr);
- xdefine("etext", STEXT, text->vaddr + text->len);
- xdefine("rodata", SRODATA, rodata->vaddr);
- xdefine("erodata", SRODATA, rodata->vaddr + rodata->len);
- xdefine("symtab", SRODATA, symtab->vaddr);
- xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);
- xdefine("pclntab", SRODATA, pclntab->vaddr);
- xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len);
- xdefine("data", SBSS, data->vaddr);
- xdefine("edata", SBSS, data->vaddr + data->len);
- xdefine("end", SBSS, segdata.vaddr + segdata.len);
-}
diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go
deleted file mode 100644
index 972e2a32c..000000000
--- a/src/cmd/ld/doc.go
+++ /dev/null
@@ -1,11 +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.
-
-/*
-
-This directory contains the portable section of the Plan 9 C linkers.
-See ../6l, ../8l, and ../5l for more information.
-
-*/
-package documentation
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
deleted file mode 100644
index 1c10dc796..000000000
--- a/src/cmd/ld/dwarf.c
+++ /dev/null
@@ -1,2598 +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.
-
-// TODO/NICETOHAVE:
-// - eliminate DW_CLS_ if not used
-// - package info in compilation units
-// - assign global variables and types to their packages
-// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
-// ptype struct '[]uint8' and qualifiers need to be quoted away
-// - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean.
-// - file:line info for variables
-// - make strings a typedef so prettyprinters can see the underlying string type
-//
-#include "l.h"
-#include "lib.h"
-#include "../ld/dwarf.h"
-#include "../ld/dwarf_defs.h"
-#include "../ld/elf.h"
-#include "../ld/macho.h"
-#include "../ld/pe.h"
-
-/*
- * Offsets and sizes of the debug_* sections in the cout file.
- */
-
-static vlong abbrevo;
-static vlong abbrevsize;
-static vlong lineo;
-static vlong linesize;
-static vlong infoo; // also the base for DWDie->offs and reference attributes.
-static vlong infosize;
-static vlong frameo;
-static vlong framesize;
-static vlong pubnameso;
-static vlong pubnamessize;
-static vlong pubtypeso;
-static vlong pubtypessize;
-static vlong arangeso;
-static vlong arangessize;
-static vlong gdbscripto;
-static vlong gdbscriptsize;
-
-static char gdbscript[1024];
-
-/*
- * Basic I/O
- */
-
-static void
-addrput(vlong addr)
-{
- switch(PtrSize) {
- case 4:
- LPUT(addr);
- break;
- case 8:
- VPUT(addr);
- break;
- }
-}
-
-static int
-uleb128enc(uvlong v, char* dst)
-{
- uint8 c, len;
-
- len = 0;
- do {
- c = v & 0x7f;
- v >>= 7;
- if (v)
- c |= 0x80;
- if (dst)
- *dst++ = c;
- len++;
- } while (c & 0x80);
- return len;
-};
-
-static int
-sleb128enc(vlong v, char *dst)
-{
- uint8 c, s, len;
-
- len = 0;
- do {
- c = v & 0x7f;
- s = v & 0x40;
- v >>= 7;
- if ((v != -1 || !s) && (v != 0 || s))
- c |= 0x80;
- if (dst)
- *dst++ = c;
- len++;
- } while(c & 0x80);
- return len;
-}
-
-static void
-uleb128put(vlong v)
-{
- char buf[10];
- strnput(buf, uleb128enc(v, buf));
-}
-
-static void
-sleb128put(vlong v)
-{
- char buf[10];
- strnput(buf, sleb128enc(v, buf));
-}
-
-/*
- * Defining Abbrevs. This is hardcoded, and there will be
- * only a handful of them. The DWARF spec places no restriction on
- * the ordering of atributes in the Abbrevs and DIEs, and we will
- * always write them out in the order of declaration in the abbrev.
- * This implementation relies on tag, attr < 127, so they serialize as
- * a char. Higher numbered user-defined tags or attributes can be used
- * for storing internal data but won't be serialized.
- */
-typedef struct DWAttrForm DWAttrForm;
-struct DWAttrForm {
- uint8 attr;
- uint8 form;
-};
-
-// Index into the abbrevs table below.
-// Keep in sync with ispubname() and ispubtype() below.
-// ispubtype considers >= NULLTYPE public
-enum
-{
- DW_ABRV_NULL,
- DW_ABRV_COMPUNIT,
- DW_ABRV_FUNCTION,
- DW_ABRV_VARIABLE,
- DW_ABRV_AUTO,
- DW_ABRV_PARAM,
- DW_ABRV_STRUCTFIELD,
- DW_ABRV_FUNCTYPEPARAM,
- DW_ABRV_DOTDOTDOT,
- DW_ABRV_ARRAYRANGE,
- DW_ABRV_NULLTYPE,
- DW_ABRV_BASETYPE,
- DW_ABRV_ARRAYTYPE,
- DW_ABRV_CHANTYPE,
- DW_ABRV_FUNCTYPE,
- DW_ABRV_IFACETYPE,
- DW_ABRV_MAPTYPE,
- DW_ABRV_PTRTYPE,
- DW_ABRV_SLICETYPE,
- DW_ABRV_STRINGTYPE,
- DW_ABRV_STRUCTTYPE,
- DW_ABRV_TYPEDECL,
- DW_NABRV
-};
-
-typedef struct DWAbbrev DWAbbrev;
-static struct DWAbbrev {
- uint8 tag;
- uint8 children;
- DWAttrForm attr[30];
-} abbrevs[DW_NABRV] = {
- /* The mandatory DW_ABRV_NULL entry. */
- { 0 },
- /* COMPUNIT */
- {
- DW_TAG_compile_unit, DW_CHILDREN_yes,
- DW_AT_name, DW_FORM_string,
- DW_AT_language, DW_FORM_data1,
- DW_AT_low_pc, DW_FORM_addr,
- DW_AT_high_pc, DW_FORM_addr,
- DW_AT_stmt_list, DW_FORM_data4,
- 0, 0
- },
- /* FUNCTION */
- {
- DW_TAG_subprogram, DW_CHILDREN_yes,
- DW_AT_name, DW_FORM_string,
- DW_AT_low_pc, DW_FORM_addr,
- DW_AT_high_pc, DW_FORM_addr,
- DW_AT_external, DW_FORM_flag,
- 0, 0
- },
- /* VARIABLE */
- {
- DW_TAG_variable, DW_CHILDREN_no,
- DW_AT_name, DW_FORM_string,
- DW_AT_location, DW_FORM_block1,
- DW_AT_type, DW_FORM_ref_addr,
- DW_AT_external, DW_FORM_flag,
- 0, 0
- },
- /* AUTO */
- {
- DW_TAG_variable, DW_CHILDREN_no,
- DW_AT_name, DW_FORM_string,
- DW_AT_location, DW_FORM_block1,
- DW_AT_type, DW_FORM_ref_addr,
- 0, 0
- },
- /* PARAM */
- {
- DW_TAG_formal_parameter, DW_CHILDREN_no,
- DW_AT_name, DW_FORM_string,
- DW_AT_location, DW_FORM_block1,
- DW_AT_type, DW_FORM_ref_addr,
- 0, 0
- },
- /* STRUCTFIELD */
- {
- DW_TAG_member, DW_CHILDREN_no,
- DW_AT_name, DW_FORM_string,
- DW_AT_data_member_location, DW_FORM_block1,
- DW_AT_type, DW_FORM_ref_addr,
- 0, 0
- },
- /* FUNCTYPEPARAM */
- {
- DW_TAG_formal_parameter, DW_CHILDREN_no,
- // No name!
- DW_AT_type, DW_FORM_ref_addr,
- 0, 0
- },
-
- /* DOTDOTDOT */
- {
- DW_TAG_unspecified_parameters, DW_CHILDREN_no,
- 0, 0
- },
- /* ARRAYRANGE */
- {
- DW_TAG_subrange_type, DW_CHILDREN_no,
- // No name!
- DW_AT_type, DW_FORM_ref_addr,
- DW_AT_upper_bound, DW_FORM_data1,
- 0, 0
- },
-
- // Below here are the types considered public by ispubtype
- /* NULLTYPE */
- {
- DW_TAG_unspecified_type, DW_CHILDREN_no,
- DW_AT_name, DW_FORM_string,
- 0, 0
- },
- /* BASETYPE */
- {
- DW_TAG_base_type, DW_CHILDREN_no,
- DW_AT_name, DW_FORM_string,
- DW_AT_encoding, DW_FORM_data1,
- DW_AT_byte_size, DW_FORM_data1,
- 0, 0
- },
- /* ARRAYTYPE */
- // child is subrange with upper bound
- {
- DW_TAG_array_type, DW_CHILDREN_yes,
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref_addr,
- DW_AT_byte_size, DW_FORM_udata,
- 0, 0
- },
-
- /* CHANTYPE */
- {
- DW_TAG_typedef, DW_CHILDREN_no,
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref_addr,
- 0, 0
- },
-
- /* FUNCTYPE */
- {
- DW_TAG_subroutine_type, DW_CHILDREN_yes,
- DW_AT_name, DW_FORM_string,
-// DW_AT_type, DW_FORM_ref_addr,
- 0, 0
- },
-
- /* IFACETYPE */
- {
- DW_TAG_typedef, DW_CHILDREN_yes,
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref_addr,
- 0, 0
- },
-
- /* MAPTYPE */
- {
- DW_TAG_typedef, DW_CHILDREN_no,
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref_addr,
- 0, 0
- },
-
- /* PTRTYPE */
- {
- DW_TAG_pointer_type, DW_CHILDREN_no,
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref_addr,
- 0, 0
- },
-
- /* SLICETYPE */
- {
- DW_TAG_structure_type, DW_CHILDREN_yes,
- DW_AT_name, DW_FORM_string,
- DW_AT_byte_size, DW_FORM_udata,
- 0, 0
- },
-
- /* STRINGTYPE */
- {
- DW_TAG_structure_type, DW_CHILDREN_yes,
- DW_AT_name, DW_FORM_string,
- DW_AT_byte_size, DW_FORM_udata,
- 0, 0
- },
-
- /* STRUCTTYPE */
- {
- DW_TAG_structure_type, DW_CHILDREN_yes,
- DW_AT_name, DW_FORM_string,
- DW_AT_byte_size, DW_FORM_udata,
- 0, 0
- },
-
- /* TYPEDECL */
- {
- DW_TAG_typedef, DW_CHILDREN_no,
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref_addr,
- 0, 0
- },
-};
-
-static void
-writeabbrev(void)
-{
- int i, n;
-
- abbrevo = cpos();
- for (i = 1; i < DW_NABRV; i++) {
- // See section 7.5.3
- uleb128put(i);
- uleb128put(abbrevs[i].tag);
- cput(abbrevs[i].children);
- // 0 is not a valid attr or form, and DWAbbrev.attr is
- // 0-terminated, so we can treat it as a string
- n = strlen((char*)abbrevs[i].attr) / 2;
- strnput((char*)abbrevs[i].attr,
- (n+1) * sizeof(DWAttrForm));
- }
- cput(0);
- abbrevsize = cpos() - abbrevo;
-}
-
-/*
- * Debugging Information Entries and their attributes.
- */
-
-enum
-{
- HASHSIZE = 107
-};
-
-static uint32
-hashstr(char* s)
-{
- uint32 h;
-
- h = 0;
- while (*s)
- h = h+h+h + *s++;
- return h % HASHSIZE;
-}
-
-// For DW_CLS_string and _block, value should contain the length, and
-// data the data, for _reference, value is 0 and data is a DWDie* to
-// the referenced instance, for all others, value is the whole thing
-// and data is null.
-
-typedef struct DWAttr DWAttr;
-struct DWAttr {
- DWAttr *link;
- uint8 atr; // DW_AT_
- uint8 cls; // DW_CLS_
- vlong value;
- char *data;
-};
-
-typedef struct DWDie DWDie;
-struct DWDie {
- int abbrev;
- DWDie *link;
- DWDie *child;
- DWAttr *attr;
- // offset into .debug_info section, i.e relative to
- // infoo. only valid after call to putdie()
- vlong offs;
- DWDie **hash; // optional index of children by name, enabled by mkindex()
- DWDie *hlink; // bucket chain in parent's index
-};
-
-/*
- * Root DIEs for compilation units, types and global variables.
- */
-
-static DWDie dwroot;
-static DWDie dwtypes;
-static DWDie dwglobals;
-
-static DWAttr*
-newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data)
-{
- DWAttr *a;
-
- a = mal(sizeof *a);
- a->link = die->attr;
- die->attr = a;
- a->atr = attr;
- a->cls = cls;
- a->value = value;
- a->data = data;
- return a;
-}
-
-// Each DIE (except the root ones) has at least 1 attribute: its
-// name. getattr moves the desired one to the front so
-// frequently searched ones are found faster.
-static DWAttr*
-getattr(DWDie *die, uint8 attr)
-{
- DWAttr *a, *b;
-
- if (die->attr->atr == attr)
- return die->attr;
-
- a = die->attr;
- b = a->link;
- while (b != nil) {
- if (b->atr == attr) {
- a->link = b->link;
- b->link = die->attr;
- die->attr = b;
- return b;
- }
- a = b;
- b = b->link;
- }
- return nil;
-}
-
-// Every DIE has at least a DW_AT_name attribute (but it will only be
-// written out if it is listed in the abbrev). If its parent is
-// keeping an index, the new DIE will be inserted there.
-static DWDie*
-newdie(DWDie *parent, int abbrev, char *name)
-{
- DWDie *die;
- int h;
-
- die = mal(sizeof *die);
- die->abbrev = abbrev;
- die->link = parent->child;
- parent->child = die;
-
- newattr(die, DW_AT_name, DW_CLS_STRING, strlen(name), name);
-
- if (parent->hash) {
- h = hashstr(name);
- die->hlink = parent->hash[h];
- parent->hash[h] = die;
- }
-
- return die;
-}
-
-static void
-mkindex(DWDie *die)
-{
- die->hash = mal(HASHSIZE * sizeof(DWDie*));
-}
-
-// Find child by AT_name using hashtable if available or linear scan
-// if not.
-static DWDie*
-find(DWDie *die, char* name)
-{
- DWDie *a, *b;
- int h;
-
- if (die->hash == nil) {
- for (a = die->child; a != nil; a = a->link)
- if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
- return a;
- return nil;
- }
-
- h = hashstr(name);
- a = die->hash[h];
-
- if (a == nil)
- return nil;
-
-
- if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
- return a;
-
- // Move found ones to head of the list.
- b = a->hlink;
- while (b != nil) {
- if (strcmp(name, getattr(b, DW_AT_name)->data) == 0) {
- a->hlink = b->hlink;
- b->hlink = die->hash[h];
- die->hash[h] = b;
- return b;
- }
- a = b;
- b = b->hlink;
- }
- return nil;
-}
-
-static DWDie*
-find_or_diag(DWDie *die, char* name)
-{
- DWDie *r;
- r = find(die, name);
- if (r == nil) {
- diag("dwarf find: %s has no %s", getattr(die, DW_AT_name)->data, name);
- errorexit();
- }
- return r;
-}
-
-static DWAttr*
-newrefattr(DWDie *die, uint8 attr, DWDie* ref)
-{
- if (ref == nil)
- return nil;
- return newattr(die, attr, DW_CLS_REFERENCE, 0, (char*)ref);
-}
-
-static int fwdcount;
-
-static void
-putattr(int form, int cls, vlong value, char *data)
-{
- switch(form) {
- case DW_FORM_addr: // address
- addrput(value);
- break;
-
- case DW_FORM_block1: // block
- value &= 0xff;
- cput(value);
- while(value--)
- cput(*data++);
- break;
-
- case DW_FORM_block2: // block
- value &= 0xffff;
- WPUT(value);
- while(value--)
- cput(*data++);
- break;
-
- case DW_FORM_block4: // block
- value &= 0xffffffff;
- LPUT(value);
- while(value--)
- cput(*data++);
- break;
-
- case DW_FORM_block: // block
- uleb128put(value);
- while(value--)
- cput(*data++);
- break;
-
- case DW_FORM_data1: // constant
- cput(value);
- break;
-
- case DW_FORM_data2: // constant
- WPUT(value);
- break;
-
- case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
- LPUT(value);
- break;
-
- case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
- VPUT(value);
- break;
-
- case DW_FORM_sdata: // constant
- sleb128put(value);
- break;
-
- case DW_FORM_udata: // constant
- uleb128put(value);
- break;
-
- case DW_FORM_string: // string
- strnput(data, value+1);
- break;
-
- case DW_FORM_flag: // flag
- cput(value?1:0);
- break;
-
- case DW_FORM_ref_addr: // reference to a DIE in the .info section
- if (data == nil) {
- diag("dwarf: null reference");
- LPUT(0); // invalid dwarf, gdb will complain.
- } else {
- if (((DWDie*)data)->offs == 0)
- fwdcount++;
- LPUT(((DWDie*)data)->offs);
- }
- break;
-
- case DW_FORM_ref1: // reference within the compilation unit
- case DW_FORM_ref2: // reference
- case DW_FORM_ref4: // reference
- case DW_FORM_ref8: // reference
- case DW_FORM_ref_udata: // reference
-
- case DW_FORM_strp: // string
- case DW_FORM_indirect: // (see Section 7.5.3)
- default:
- diag("dwarf: unsupported attribute form %d / class %d", form, cls);
- errorexit();
- }
-}
-
-// Note that we can (and do) add arbitrary attributes to a DIE, but
-// only the ones actually listed in the Abbrev will be written out.
-static void
-putattrs(int abbrev, DWAttr* attr)
-{
- DWAttr *attrs[DW_AT_recursive + 1];
- DWAttrForm* af;
-
- memset(attrs, 0, sizeof attrs);
- for( ; attr; attr = attr->link)
- if (attr->atr < nelem(attrs))
- attrs[attr->atr] = attr;
-
- for(af = abbrevs[abbrev].attr; af->attr; af++)
- if (attrs[af->attr])
- putattr(af->form,
- attrs[af->attr]->cls,
- attrs[af->attr]->value,
- attrs[af->attr]->data);
- else
- putattr(af->form, 0, 0, 0);
-}
-
-static void putdie(DWDie* die);
-
-static void
-putdies(DWDie* die)
-{
- for(; die; die = die->link)
- putdie(die);
-}
-
-static void
-putdie(DWDie* die)
-{
- die->offs = cpos() - infoo;
- uleb128put(die->abbrev);
- putattrs(die->abbrev, die->attr);
- if (abbrevs[die->abbrev].children) {
- putdies(die->child);
- cput(0);
- }
-}
-
-static void
-reverselist(DWDie** list)
-{
- DWDie *curr, *prev;
-
- curr = *list;
- prev = nil;
- while(curr != nil) {
- DWDie* next = curr->link;
- curr->link = prev;
- prev = curr;
- curr = next;
- }
- *list = prev;
-}
-
-static void
-reversetree(DWDie** list)
-{
- DWDie *die;
-
- reverselist(list);
- for (die = *list; die != nil; die = die->link)
- if (abbrevs[die->abbrev].children)
- reversetree(&die->child);
-}
-
-static void
-newmemberoffsetattr(DWDie *die, int32 offs)
-{
- char block[10];
- int i;
-
- i = 0;
- if (offs != 0) {
- block[i++] = DW_OP_consts;
- i += sleb128enc(offs, block+i);
- block[i++] = DW_OP_plus;
- }
- newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, i, mal(i));
- memmove(die->attr->data, block, i);
-}
-
-// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
-// location expression that evals to a const.
-static void
-newabslocexprattr(DWDie *die, vlong addr)
-{
- char block[10];
- int i;
-
- i = 0;
- block[i++] = DW_OP_constu;
- i += uleb128enc(addr, block+i);
- newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
- memmove(die->attr->data, block, i);
-}
-
-// Decoding the type.* symbols. This has to be in sync with
-// ../../pkg/runtime/type.go, or more specificaly, with what
-// ../gc/reflect.c stuffs in these.
-
-enum {
- KindBool = 1,
- 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,
-
- KindNoPointers = 1<<7,
-
- // size of Type interface header + CommonType structure.
- CommonSize = 2*PtrSize+ 4*PtrSize + 8,
-};
-
-static Reloc*
-decode_reloc(Sym *s, int32 off)
-{
- int i;
-
- for (i = 0; i < s->nr; i++)
- if (s->r[i].off == off)
- return s->r + i;
- return nil;
-}
-
-static Sym*
-decode_reloc_sym(Sym *s, int32 off)
-{
- Reloc *r;
-
- r = decode_reloc(s,off);
- if (r == nil)
- return nil;
- return r->sym;
-}
-
-static uvlong
-decode_inuxi(uchar* p, int sz)
-{
- uint64 v;
- uint32 l;
- uchar *cast, *inuxi;
- int i;
-
- v = l = 0;
- cast = nil;
- inuxi = nil;
- switch (sz) {
- case 2:
- cast = (uchar*)&l;
- inuxi = inuxi2;
- break;
- case 4:
- cast = (uchar*)&l;
- inuxi = inuxi4;
- break;
- case 8:
- cast = (uchar*)&v;
- inuxi = inuxi8;
- break;
- default:
- diag("dwarf: decode inuxi %d", sz);
- errorexit();
- }
- for (i = 0; i < sz; i++)
- cast[inuxi[i]] = p[i];
- if (sz == 8)
- return v;
- return l;
-}
-
-// Type.commonType.kind
-static uint8
-decodetype_kind(Sym *s)
-{
- return s->p[3*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f
-}
-
-// Type.commonType.size
-static vlong
-decodetype_size(Sym *s)
-{
- return decode_inuxi(s->p + 2*PtrSize, PtrSize); // 0x8 / 0x10
-}
-
-// Type.ArrayType.elem and Type.SliceType.Elem
-static Sym*
-decodetype_arrayelem(Sym *s)
-{
- return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
-}
-
-static vlong
-decodetype_arraylen(Sym *s)
-{
- return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize);
-}
-
-// Type.PtrType.elem
-static Sym*
-decodetype_ptrelem(Sym *s)
-{
- return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
-}
-
-// Type.MapType.key, elem
-static Sym*
-decodetype_mapkey(Sym *s)
-{
- return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
-}
-static Sym*
-decodetype_mapvalue(Sym *s)
-{
- return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38
-}
-
-// Type.ChanType.elem
-static Sym*
-decodetype_chanelem(Sym *s)
-{
- return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
-}
-
-// Type.FuncType.dotdotdot
-static int
-decodetype_funcdotdotdot(Sym *s)
-{
- return s->p[CommonSize];
-}
-
-// Type.FuncType.in.len
-static int
-decodetype_funcincount(Sym *s)
-{
- return decode_inuxi(s->p + CommonSize+2*PtrSize, 4);
-}
-
-static int
-decodetype_funcoutcount(Sym *s)
-{
- return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*4, 4);
-}
-
-static Sym*
-decodetype_funcintype(Sym *s, int i)
-{
- Reloc *r;
-
- r = decode_reloc(s, CommonSize + PtrSize);
- if (r == nil)
- return nil;
- return decode_reloc_sym(r->sym, r->add + i * PtrSize);
-}
-
-static Sym*
-decodetype_funcouttype(Sym *s, int i)
-{
- Reloc *r;
-
- r = decode_reloc(s, CommonSize + 2*PtrSize + 2*4);
- if (r == nil)
- return nil;
- return decode_reloc_sym(r->sym, r->add + i * PtrSize);
-}
-
-// Type.StructType.fields.Slice::len
-static int
-decodetype_structfieldcount(Sym *s)
-{
- return decode_inuxi(s->p + CommonSize + PtrSize, 4);
-}
-
-enum {
- StructFieldSize = 5*PtrSize
-};
-// Type.StructType.fields[]-> name, typ and offset.
-static char*
-decodetype_structfieldname(Sym *s, int i)
-{
- Reloc *r;
-
- // go.string."foo" 0x28 / 0x40
- s = decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize);
- if (s == nil) // embedded structs have a nil name.
- return nil;
- r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0
- if (r == nil) // shouldn't happen.
- return nil;
- return (char*) r->sym->p + r->add; // the c-string
-}
-
-static Sym*
-decodetype_structfieldtype(Sym *s, int i)
-{
- return decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize + 2*PtrSize);
-}
-
-static vlong
-decodetype_structfieldoffs(Sym *s, int i)
-{
- return decode_inuxi(s->p + CommonSize + PtrSize + 2*4 + i*StructFieldSize + 4*PtrSize, 4);
-}
-
-// InterfaceTYpe.methods.len
-static vlong
-decodetype_ifacemethodcount(Sym *s)
-{
- return decode_inuxi(s->p + CommonSize + PtrSize, 4);
-}
-
-
-// Fake attributes for slices, maps and channel
-enum {
- DW_AT_internal_elem_type = 250, // channels and slices
- DW_AT_internal_key_type = 251, // maps
- DW_AT_internal_val_type = 252, // maps
- DW_AT_internal_location = 253, // params and locals
-};
-
-static DWDie* defptrto(DWDie *dwtype); // below
-
-// Lookup predefined types
-static Sym*
-lookup_or_diag(char *n)
-{
- Sym *s;
-
- s = rlookup(n, 0);
- if (s == nil || s->size == 0) {
- diag("dwarf: missing type: %s", n);
- errorexit();
- }
- return s;
-}
-
-// Define gotype, for composite ones recurse into constituents.
-static DWDie*
-defgotype(Sym *gotype)
-{
- DWDie *die, *fld;
- Sym *s;
- char *name, *f;
- uint8 kind;
- vlong bytesize;
- int i, nfields;
-
- if (gotype == nil)
- return find_or_diag(&dwtypes, "<unspecified>");
-
- if (strncmp("type.", gotype->name, 5) != 0) {
- diag("dwarf: type name doesn't start with \".type\": %s", gotype->name);
- return find_or_diag(&dwtypes, "<unspecified>");
- }
- name = gotype->name + 5; // could also decode from Type.string
-
- die = find(&dwtypes, name);
- if (die != nil)
- return die;
-
- if (0 && debug['v'] > 2)
- print("new type: %Y\n", gotype);
-
- kind = decodetype_kind(gotype);
- bytesize = decodetype_size(gotype);
-
- switch (kind) {
- case KindBool:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- break;
-
- case KindInt:
- case KindInt8:
- case KindInt16:
- case KindInt32:
- case KindInt64:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- break;
-
- case KindUint:
- case KindUint8:
- case KindUint16:
- case KindUint32:
- case KindUint64:
- case KindUintptr:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- break;
-
- case KindFloat32:
- case KindFloat64:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- break;
-
- case KindComplex64:
- case KindComplex128:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- break;
-
- case KindArray:
- die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- s = decodetype_arrayelem(gotype);
- newrefattr(die, DW_AT_type, defgotype(s));
- fld = newdie(die, DW_ABRV_ARRAYRANGE, "range");
- newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0);
- newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
- break;
-
- case KindChan:
- die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- s = decodetype_chanelem(gotype);
- newrefattr(die, DW_AT_internal_elem_type, defgotype(s));
- break;
-
- case KindFunc:
- die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name);
- newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void"));
- nfields = decodetype_funcincount(gotype);
- for (i = 0; i < nfields; i++) {
- s = decodetype_funcintype(gotype, i);
- fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
- newrefattr(fld, DW_AT_type, defgotype(s));
- }
- if (decodetype_funcdotdotdot(gotype))
- newdie(die, DW_ABRV_DOTDOTDOT, "...");
- nfields = decodetype_funcoutcount(gotype);
- for (i = 0; i < nfields; i++) {
- s = decodetype_funcouttype(gotype, i);
- fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
- newrefattr(fld, DW_AT_type, defptrto(defgotype(s)));
- }
- break;
-
- case KindInterface:
- die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- nfields = decodetype_ifacemethodcount(gotype);
- if (nfields == 0)
- s = lookup_or_diag("type.runtime.eface");
- else
- s = lookup_or_diag("type.runtime.iface");
- newrefattr(die, DW_AT_type, defgotype(s));
- break;
-
- case KindMap:
- die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name);
- s = decodetype_mapkey(gotype);
- newrefattr(die, DW_AT_internal_key_type, defgotype(s));
- s = decodetype_mapvalue(gotype);
- newrefattr(die, DW_AT_internal_val_type, defgotype(s));
- break;
-
- case KindPtr:
- die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
- s = decodetype_ptrelem(gotype);
- newrefattr(die, DW_AT_type, defgotype(s));
- break;
-
- case KindSlice:
- die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- s = decodetype_arrayelem(gotype);
- newrefattr(die, DW_AT_internal_elem_type, defgotype(s));
- break;
-
- case KindString:
- die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- break;
-
- case KindStruct:
- die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
- nfields = decodetype_structfieldcount(gotype);
- for (i = 0; i < nfields; i++) {
- f = decodetype_structfieldname(gotype, i);
- s = decodetype_structfieldtype(gotype, i);
- if (f == nil)
- f = s->name + 5; // skip "type."
- fld = newdie(die, DW_ABRV_STRUCTFIELD, f);
- newrefattr(fld, DW_AT_type, defgotype(s));
- newmemberoffsetattr(fld, decodetype_structfieldoffs(gotype, i));
- }
- break;
-
- case KindUnsafePointer:
- die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
- newrefattr(die, DW_AT_type, find(&dwtypes, "void"));
- break;
-
- default:
- diag("dwarf: definition of unknown kind %d: %s", kind, gotype->name);
- die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name);
- newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>"));
- }
-
- return die;
-}
-
-// Find or construct *T given T.
-static DWDie*
-defptrto(DWDie *dwtype)
-{
- char ptrname[1024];
- DWDie *die;
-
- snprint(ptrname, sizeof ptrname, "*%s", getattr(dwtype, DW_AT_name)->data);
- die = find(&dwtypes, ptrname);
- if (die == nil) {
- die = newdie(&dwtypes, DW_ABRV_PTRTYPE,
- strcpy(mal(strlen(ptrname)+1), ptrname));
- newrefattr(die, DW_AT_type, dwtype);
- }
- return die;
-}
-
-// Copies src's children into dst. Copies attributes by value.
-// DWAttr.data is copied as pointer only.
-static void
-copychildren(DWDie *dst, DWDie *src)
-{
- DWDie *c;
- DWAttr *a;
-
- for (src = src->child; src != nil; src = src->link) {
- c = newdie(dst, src->abbrev, getattr(src, DW_AT_name)->data);
- for (a = src->attr; a != nil; a = a->link)
- newattr(c, a->atr, a->cls, a->value, a->data);
- copychildren(c, src);
- }
- reverselist(&dst->child);
-}
-
-// Search children (assumed to have DW_TAG_member) for the one named
-// field and set it's DW_AT_type to dwtype
-static void
-substitutetype(DWDie *structdie, char *field, DWDie* dwtype)
-{
- DWDie *child;
- DWAttr *a;
-
- child = find_or_diag(structdie, field);
- if (child == nil)
- return;
-
- a = getattr(child, DW_AT_type);
- if (a != nil)
- a->data = (char*) dwtype;
- else
- newrefattr(child, DW_AT_type, dwtype);
-}
-
-static void
-synthesizestringtypes(DWDie* die)
-{
- DWDie *prototype;
-
- prototype = defgotype(lookup_or_diag("type.runtime._string"));
- if (prototype == nil)
- return;
-
- for (; die != nil; die = die->link) {
- if (die->abbrev != DW_ABRV_STRINGTYPE)
- continue;
- copychildren(die, prototype);
- }
-}
-
-static void
-synthesizeslicetypes(DWDie *die)
-{
- DWDie *prototype, *elem;
-
- prototype = defgotype(lookup_or_diag("type.runtime.slice"));
- if (prototype == nil)
- return;
-
- for (; die != nil; die = die->link) {
- if (die->abbrev != DW_ABRV_SLICETYPE)
- continue;
- copychildren(die, prototype);
- elem = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data;
- substitutetype(die, "array", defptrto(elem));
- }
-}
-
-static char*
-mkinternaltypename(char *base, char *arg1, char *arg2)
-{
- char buf[1024];
- char *n;
-
- if (arg2 == nil)
- snprint(buf, sizeof buf, "%s<%s>", base, arg1);
- else
- snprint(buf, sizeof buf, "%s<%s,%s>", base, arg1, arg2);
- n = mal(strlen(buf) + 1);
- memmove(n, buf, strlen(buf));
- return n;
-}
-
-
-// synthesizemaptypes is way too closely married to runtime/hashmap.c
-enum {
- MaxValsize = 256 - 64
-};
-
-static void
-synthesizemaptypes(DWDie *die)
-{
-
- DWDie *hash, *hash_subtable, *hash_entry,
- *dwh, *dwhs, *dwhe, *dwhash, *keytype, *valtype, *fld;
- int hashsize, keysize, valsize, datsize, valsize_in_hash, datavo;
- DWAttr *a;
-
- hash = defgotype(lookup_or_diag("type.runtime.hmap"));
- hash_subtable = defgotype(lookup_or_diag("type.runtime.hash_subtable"));
- hash_entry = defgotype(lookup_or_diag("type.runtime.hash_entry"));
-
- if (hash == nil || hash_subtable == nil || hash_entry == nil)
- return;
-
- dwhash = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data;
- if (dwhash == nil)
- return;
-
- hashsize = getattr(dwhash, DW_AT_byte_size)->value;
-
- for (; die != nil; die = die->link) {
- if (die->abbrev != DW_ABRV_MAPTYPE)
- continue;
-
- keytype = (DWDie*) getattr(die, DW_AT_internal_key_type)->data;
- valtype = (DWDie*) getattr(die, DW_AT_internal_val_type)->data;
-
- a = getattr(keytype, DW_AT_byte_size);
- keysize = a ? a->value : PtrSize; // We don't store size with Pointers
-
- a = getattr(valtype, DW_AT_byte_size);
- valsize = a ? a->value : PtrSize;
-
- // This is what happens in hash_init and makemap_c
- valsize_in_hash = valsize;
- if (valsize > MaxValsize)
- valsize_in_hash = PtrSize;
- datavo = keysize;
- if (valsize_in_hash >= PtrSize)
- datavo = rnd(keysize, PtrSize);
- datsize = datavo + valsize_in_hash;
- if (datsize < PtrSize)
- datsize = PtrSize;
- datsize = rnd(datsize, PtrSize);
-
- // Construct struct hash_entry<K,V>
- dwhe = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("hash_entry",
- getattr(keytype, DW_AT_name)->data,
- getattr(valtype, DW_AT_name)->data));
-
- fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "hash");
- newrefattr(fld, DW_AT_type, dwhash);
- newmemberoffsetattr(fld, 0);
-
- fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "key");
- newrefattr(fld, DW_AT_type, keytype);
- newmemberoffsetattr(fld, hashsize);
-
- fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "val");
- if (valsize > MaxValsize)
- valtype = defptrto(valtype);
- newrefattr(fld, DW_AT_type, valtype);
- newmemberoffsetattr(fld, hashsize + datavo);
- newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, nil);
-
- // Construct hash_subtable<hash_entry<K,V>>
- dwhs = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("hash_subtable",
- getattr(keytype, DW_AT_name)->data,
- getattr(valtype, DW_AT_name)->data));
- copychildren(dwhs, hash_subtable);
- substitutetype(dwhs, "end", defptrto(dwhe));
- substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size
- newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hash_subtable, DW_AT_byte_size)->value, nil);
-
- // Construct hash<K,V>
- dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("hash",
- getattr(keytype, DW_AT_name)->data,
- getattr(valtype, DW_AT_name)->data));
- copychildren(dwh, hash);
- substitutetype(dwh, "st", defptrto(dwhs));
- newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hash, DW_AT_byte_size)->value, nil);
-
- newrefattr(die, DW_AT_type, defptrto(dwh));
- }
-}
-
-static void
-synthesizechantypes(DWDie *die)
-{
- DWDie *sudog, *waitq, *hchan,
- *dws, *dww, *dwh, *elemtype;
- DWAttr *a;
- int elemsize, sudogsize;
-
- sudog = defgotype(lookup_or_diag("type.runtime.sudog"));
- waitq = defgotype(lookup_or_diag("type.runtime.waitq"));
- hchan = defgotype(lookup_or_diag("type.runtime.hchan"));
- if (sudog == nil || waitq == nil || hchan == nil)
- return;
-
- sudogsize = getattr(sudog, DW_AT_byte_size)->value;
-
- for (; die != nil; die = die->link) {
- if (die->abbrev != DW_ABRV_CHANTYPE)
- continue;
- elemtype = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data;
- a = getattr(elemtype, DW_AT_byte_size);
- elemsize = a ? a->value : PtrSize;
-
- // sudog<T>
- dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("sudog",
- getattr(elemtype, DW_AT_name)->data, nil));
- copychildren(dws, sudog);
- substitutetype(dws, "elem", elemtype);
- newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT,
- sudogsize + (elemsize > 8 ? elemsize - 8 : 0), nil);
-
- // waitq<T>
- dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil));
- copychildren(dww, waitq);
- substitutetype(dww, "first", defptrto(dws));
- substitutetype(dww, "last", defptrto(dws));
- newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(waitq, DW_AT_byte_size)->value, nil);
-
- // hchan<T>
- dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil));
- copychildren(dwh, hchan);
- substitutetype(dwh, "recvq", dww);
- substitutetype(dwh, "sendq", dww);
- substitutetype(dwh, "free", defptrto(dws));
- newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hchan, DW_AT_byte_size)->value, nil);
-
- newrefattr(die, DW_AT_type, defptrto(dwh));
- }
-}
-
-// For use with pass.c::genasmsym
-static void
-defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
-{
- DWDie *dv, *dt;
-
- USED(size);
- if (strncmp(s, "go.string.", 10) == 0)
- return;
-
- if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0) {
- defgotype(sym);
- return;
- }
-
- dv = nil;
-
- switch (t) {
- default:
- return;
- case 'd':
- case 'b':
- case 'D':
- case 'B':
- dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s);
- newabslocexprattr(dv, v);
- if (ver == 0)
- newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0);
- // fallthrough
- case 'a':
- case 'p':
- dt = defgotype(gotype);
- }
-
- if (dv != nil)
- newrefattr(dv, DW_AT_type, dt);
-}
-
-// TODO(lvd) For now, just append them all to the first compilation
-// unit (that should be main), in the future distribute them to the
-// appropriate compilation units.
-static void
-movetomodule(DWDie *parent)
-{
- DWDie *die;
-
- for (die = dwroot.child->child; die->link != nil; die = die->link) /* nix */;
- die->link = parent->child;
-}
-
-/*
- * Filename fragments for the line history stack.
- */
-
-static char **ftab;
-static int ftabsize;
-
-void
-dwarfaddfrag(int n, char *frag)
-{
- int s;
-
- if (n >= ftabsize) {
- s = ftabsize;
- ftabsize = 1 + n + (n >> 2);
- ftab = realloc(ftab, ftabsize * sizeof(ftab[0]));
- memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0]));
- }
-
- if (*frag == '<')
- frag++;
- ftab[n] = frag;
-}
-
-// Returns a malloc'ed string, piecewise copied from the ftab.
-static char *
-decodez(char *s)
-{
- int len, o;
- char *ss, *f;
- char *r, *rb, *re;
-
- len = 0;
- ss = s + 1; // first is 0
- while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) {
- if (o < 0 || o >= ftabsize) {
- diag("dwarf: corrupt z entry");
- return 0;
- }
- f = ftab[o];
- if (f == nil) {
- diag("dwarf: corrupt z entry");
- return 0;
- }
- len += strlen(f) + 1; // for the '/'
- ss += 2;
- }
-
- if (len == 0)
- return 0;
-
- r = malloc(len + 1);
- rb = r;
- re = rb + len + 1;
-
- s++;
- while((o = ((uint8)s[0] << 8) | (uint8)s[1]) != 0) {
- f = ftab[o];
- if (rb == r || rb[-1] == '/')
- rb = seprint(rb, re, "%s", f);
- else
- rb = seprint(rb, re, "/%s", f);
- s += 2;
- }
- return r;
-}
-
-/*
- * The line history itself
- */
-
-static char **histfile; // [0] holds "<eof>", DW_LNS_set_file arguments must be > 0.
-static int histfilesize;
-static int histfilecap;
-
-static void
-clearhistfile(void)
-{
- int i;
-
- // [0] holds "<eof>"
- for (i = 1; i < histfilesize; i++)
- free(histfile[i]);
- histfilesize = 0;
-}
-
-static int
-addhistfile(char *zentry)
-{
- char *fname;
-
- if (histfilesize == histfilecap) {
- histfilecap = 2 * histfilecap + 2;
- histfile = realloc(histfile, histfilecap * sizeof(char*));
- }
- if (histfilesize == 0)
- histfile[histfilesize++] = "<eof>";
-
- fname = decodez(zentry);
- if (fname == 0)
- return -1;
- // Don't fill with duplicates (check only top one).
- if (strcmp(fname, histfile[histfilesize-1]) == 0) {
- free(fname);
- return histfilesize - 1;
- }
- histfile[histfilesize++] = fname;
- return histfilesize - 1;
-}
-
-// if the histfile stack contains ..../runtime/runtime_defs.go
-// use that to set gdbscript
-static void
-finddebugruntimepath(void)
-{
- int i, l;
- char *c;
-
- for (i = 1; i < histfilesize; i++) {
- if ((c = strstr(histfile[i], "runtime/runtime_defs.go")) != nil) {
- l = c - histfile[i];
- memmove(gdbscript, histfile[i], l);
- memmove(gdbscript + l, "runtime/runtime-gdb.py", strlen("runtime/runtime-gdb.py") + 1);
- break;
- }
- }
-}
-
-// Go's runtime C sources are sane, and Go sources nest only 1 level,
-// so 16 should be plenty.
-static struct {
- int file;
- vlong line;
-} includestack[16];
-static int includetop;
-static vlong absline;
-
-typedef struct Linehist Linehist;
-struct Linehist {
- Linehist *link;
- vlong absline;
- vlong line;
- int file;
-};
-
-static Linehist *linehist;
-
-static void
-checknesting(void)
-{
- int i;
-
- if (includetop < 0) {
- diag("dwarf: corrupt z stack");
- errorexit();
- }
- if (includetop >= nelem(includestack)) {
- diag("dwarf: nesting too deep");
- for (i = 0; i < nelem(includestack); i++)
- diag("\t%s", histfile[includestack[i].file]);
- errorexit();
- }
-}
-
-/*
- * Return false if the a->link chain contains no history, otherwise
- * returns true and finds z and Z entries in the Auto list (of a
- * Prog), and resets the history stack
- */
-static int
-inithist(Auto *a)
-{
- Linehist *lh;
-
- for (; a; a = a->link)
- if (a->type == D_FILE)
- break;
- if (a==nil)
- return 0;
-
- // We have a new history. They are guaranteed to come completely
- // at the beginning of the compilation unit.
- if (a->aoffset != 1) {
- diag("dwarf: stray 'z' with offset %d", a->aoffset);
- return 0;
- }
-
- // Clear the history.
- clearhistfile();
- includetop = 0;
- includestack[includetop].file = 0;
- includestack[includetop].line = -1;
- absline = 0;
- while (linehist != nil) {
- lh = linehist->link;
- free(linehist);
- linehist = lh;
- }
-
- // Construct the new one.
- for (; a; a = a->link) {
- if (a->type == D_FILE) { // 'z'
- int f = addhistfile(a->asym->name);
- if (f < 0) { // pop file
- includetop--;
- checknesting();
- } else if(f != includestack[includetop].file) { // pushed a new file
- includestack[includetop].line += a->aoffset - absline;
- includetop++;
- checknesting();
- includestack[includetop].file = f;
- includestack[includetop].line = 1;
- }
- absline = a->aoffset;
- } else if (a->type == D_FILE1) { // 'Z'
- // We could just fixup the current
- // linehist->line, but there doesn't appear to
- // be a guarantee that every 'Z' is preceded
- // by it's own 'z', so do the safe thing and
- // update the stack and push a new Linehist
- // entry
- includestack[includetop].line = a->aoffset;
- } else
- continue;
- if (linehist == 0 || linehist->absline != absline) {
- Linehist* lh = malloc(sizeof *lh);
- lh->link = linehist;
- lh->absline = absline;
- linehist = lh;
- }
- linehist->file = includestack[includetop].file;
- linehist->line = includestack[includetop].line;
- }
- return 1;
-}
-
-static Linehist *
-searchhist(vlong absline)
-{
- Linehist *lh;
-
- for (lh = linehist; lh; lh = lh->link)
- if (lh->absline <= absline)
- break;
- return lh;
-}
-
-static int
-guesslang(char *s)
-{
- if(strlen(s) >= 3 && strcmp(s+strlen(s)-3, ".go") == 0)
- return DW_LANG_Go;
-
- return DW_LANG_C;
-}
-
-/*
- * Generate short opcodes when possible, long ones when neccesary.
- * See section 6.2.5
- */
-
-enum {
- LINE_BASE = -1,
- LINE_RANGE = 4,
- OPCODE_BASE = 5
-};
-
-static void
-putpclcdelta(vlong delta_pc, vlong delta_lc)
-{
- if (LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE) {
- vlong opcode = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc);
- if (OPCODE_BASE <= opcode && opcode < 256) {
- cput(opcode);
- return;
- }
- }
-
- if (delta_pc) {
- cput(DW_LNS_advance_pc);
- sleb128put(delta_pc);
- }
-
- cput(DW_LNS_advance_line);
- sleb128put(delta_lc);
- cput(DW_LNS_copy);
-}
-
-static void
-newcfaoffsetattr(DWDie *die, int32 offs)
-{
- char block[10];
- int i;
-
- i = 0;
-
- block[i++] = DW_OP_call_frame_cfa;
- if (offs != 0) {
- block[i++] = DW_OP_consts;
- i += sleb128enc(offs, block+i);
- block[i++] = DW_OP_plus;
- }
- newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
- memmove(die->attr->data, block, i);
-}
-
-static char*
-mkvarname(char* name, int da)
-{
- char buf[1024];
- char *n;
-
- snprint(buf, sizeof buf, "%s#%d", name, da);
- n = mal(strlen(buf) + 1);
- memmove(n, buf, strlen(buf));
- return n;
-}
-
-/*
- * Walk prog table, emit line program and build DIE tree.
- */
-
-// flush previous compilation unit.
-static void
-flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length)
-{
- vlong here;
-
- if (dwinfo != nil && pc != 0) {
- newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, 0);
- }
-
- if (unitstart >= 0) {
- cput(0); // start extended opcode
- uleb128put(1);
- cput(DW_LNE_end_sequence);
- cflush();
-
- here = cpos();
- seek(cout, unitstart, 0);
- LPUT(here - unitstart - sizeof(int32)); // unit_length
- WPUT(3); // dwarf version
- LPUT(header_length); // header length starting here
- cflush();
- seek(cout, here, 0);
- }
-}
-
-static void
-writelines(void)
-{
- Prog *q;
- Sym *s;
- Auto *a;
- vlong unitstart, headerend, offs;
- vlong pc, epc, lc, llc, lline;
- int currfile;
- int i, lang, da, dt;
- Linehist *lh;
- DWDie *dwinfo, *dwfunc, *dwvar, **dws;
- DWDie *varhash[HASHSIZE];
- char *n, *nn;
-
- unitstart = -1;
- headerend = -1;
- pc = 0;
- epc = 0;
- lc = 1;
- llc = 1;
- currfile = -1;
- lineo = cpos();
- dwinfo = nil;
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- s = cursym;
- if(s->text == P)
- continue;
-
- // Look for history stack. If we find one,
- // we're entering a new compilation unit
-
- if (inithist(s->autom)) {
- flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
- unitstart = cpos();
-
- if(debug['v'] > 1) {
- print("dwarf writelines found %s\n", histfile[1]);
- Linehist* lh;
- for (lh = linehist; lh; lh = lh->link)
- print("\t%8lld: [%4lld]%s\n",
- lh->absline, lh->line, histfile[lh->file]);
- }
-
- lang = guesslang(histfile[1]);
- finddebugruntimepath();
-
- dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, strdup(histfile[1]));
- newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0);
- newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
- newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, 0);
-
- // Write .debug_line Line Number Program Header (sec 6.2.4)
- // Fields marked with (*) must be changed for 64-bit dwarf
- LPUT(0); // unit_length (*), will be filled in by flushunit.
- WPUT(3); // dwarf version (appendix F)
- LPUT(0); // header_length (*), filled in by flushunit.
- // cpos == unitstart + 4 + 2 + 4
- cput(1); // minimum_instruction_length
- cput(1); // default_is_stmt
- cput(LINE_BASE); // line_base
- cput(LINE_RANGE); // line_range
- cput(OPCODE_BASE); // opcode_base (we only use 1..4)
- cput(0); // standard_opcode_lengths[1]
- cput(1); // standard_opcode_lengths[2]
- cput(1); // standard_opcode_lengths[3]
- cput(1); // standard_opcode_lengths[4]
- cput(0); // include_directories (empty)
-
- for (i=1; i < histfilesize; i++) {
- strnput(histfile[i], strlen(histfile[i]) + 4);
- // 4 zeros: the string termination + 3 fields.
- }
-
- cput(0); // terminate file_names.
- headerend = cpos();
-
- pc = s->text->pc;
- epc = pc;
- currfile = 1;
- lc = 1;
- llc = 1;
-
- cput(0); // start extended opcode
- uleb128put(1 + PtrSize);
- cput(DW_LNE_set_address);
- addrput(pc);
- }
- if(s->text == nil)
- continue;
-
- if (unitstart < 0) {
- diag("dwarf: reachable code before seeing any history: %P", s->text);
- continue;
- }
-
- dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name);
- newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, 0);
- epc = s->value + s->size;
- newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, 0);
- if (s->version == 0)
- newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0);
-
- if(s->text->link == nil)
- continue;
-
- for(q = s->text; q != P; q = q->link) {
- lh = searchhist(q->line);
- if (lh == nil) {
- diag("dwarf: corrupt history or bad absolute line: %P", q);
- continue;
- }
-
- if (lh->file < 1) { // 0 is the past-EOF entry.
- // diag("instruction with line number past EOF in %s: %P", histfile[1], q);
- continue;
- }
-
- lline = lh->line + q->line - lh->absline;
- if (debug['v'] > 1)
- print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q);
-
- if (q->line == lc)
- continue;
- if (currfile != lh->file) {
- currfile = lh->file;
- cput(DW_LNS_set_file);
- uleb128put(currfile);
- }
- putpclcdelta(q->pc - pc, lline - llc);
- pc = q->pc;
- lc = q->line;
- llc = lline;
- }
-
- da = 0;
- dwfunc->hash = varhash; // enable indexing of children by name
- memset(varhash, 0, sizeof varhash);
- for(a = s->autom; a; a = a->link) {
- switch (a->type) {
- case D_AUTO:
- dt = DW_ABRV_AUTO;
- offs = a->aoffset - PtrSize;
- break;
- case D_PARAM:
- dt = DW_ABRV_PARAM;
- offs = a->aoffset;
- break;
- default:
- continue;
- }
- if (strstr(a->asym->name, ".autotmp_"))
- continue;
- if (find(dwfunc, a->asym->name) != nil)
- n = mkvarname(a->asym->name, da);
- else
- n = a->asym->name;
- // Drop the package prefix from locals and arguments.
- nn = strrchr(n, '.');
- if (nn)
- n = nn + 1;
-
- dwvar = newdie(dwfunc, dt, n);
- newcfaoffsetattr(dwvar, offs);
- newrefattr(dwvar, DW_AT_type, defgotype(a->gotype));
-
- // push dwvar down dwfunc->child to preserve order
- newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil);
- dwfunc->child = dwvar->link; // take dwvar out from the top of the list
- for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link)
- if (offs > getattr(*dws, DW_AT_internal_location)->value)
- break;
- dwvar->link = *dws;
- *dws = dwvar;
-
- da++;
- }
-
- dwfunc->hash = nil;
- }
-
- flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
- linesize = cpos() - lineo;
-}
-
-/*
- * Emit .debug_frame
- */
-enum
-{
- CIERESERVE = 16,
- DATAALIGNMENTFACTOR = -4, // TODO -PtrSize?
- FAKERETURNCOLUMN = 16 // TODO gdb6 doesnt like > 15?
-};
-
-static void
-putpccfadelta(vlong deltapc, vlong cfa)
-{
- if (deltapc < 0x40) {
- cput(DW_CFA_advance_loc + deltapc);
- } else if (deltapc < 0x100) {
- cput(DW_CFA_advance_loc1);
- cput(deltapc);
- } else if (deltapc < 0x10000) {
- cput(DW_CFA_advance_loc2);
- WPUT(deltapc);
- } else {
- cput(DW_CFA_advance_loc4);
- LPUT(deltapc);
- }
-
- cput(DW_CFA_def_cfa_offset_sf);
- sleb128put(cfa / DATAALIGNMENTFACTOR);
-}
-
-static void
-writeframes(void)
-{
- Prog *p, *q;
- Sym *s;
- vlong fdeo, fdesize, pad, cfa, pc;
-
- frameo = cpos();
-
- // Emit the CIE, Section 6.4.1
- LPUT(CIERESERVE); // initial length, must be multiple of PtrSize
- LPUT(0xffffffff); // cid.
- cput(3); // dwarf version (appendix F)
- cput(0); // augmentation ""
- uleb128put(1); // code_alignment_factor
- sleb128put(DATAALIGNMENTFACTOR); // guess
- uleb128put(FAKERETURNCOLUMN); // return_address_register
-
- cput(DW_CFA_def_cfa);
- uleb128put(DWARFREGSP); // register SP (**ABI-dependent, defined in l.h)
- uleb128put(PtrSize); // offset
-
- cput(DW_CFA_offset + FAKERETURNCOLUMN); // return address
- uleb128put(-PtrSize / DATAALIGNMENTFACTOR); // at cfa - x*4
-
- // 4 is to exclude the length field.
- pad = CIERESERVE + frameo + 4 - cpos();
- if (pad < 0) {
- diag("dwarf: CIERESERVE too small by %lld bytes.", -pad);
- errorexit();
- }
- strnput("", pad);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- s = cursym;
- if(s->text == nil)
- continue;
-
- fdeo = cpos();
- // Emit a FDE, Section 6.4.1, starting wit a placeholder.
- LPUT(0); // length, must be multiple of PtrSize
- LPUT(0); // Pointer to the CIE above, at offset 0
- addrput(0); // initial location
- addrput(0); // address range
-
- cfa = PtrSize; // CFA starts at sp+PtrSize
- p = s->text;
- pc = p->pc;
-
- for(q = p; q->link != P; q = q->link) {
- if (q->spadj == 0)
- continue;
- cfa += q->spadj;
- putpccfadelta(q->link->pc - pc, cfa);
- pc = q->link->pc;
- }
-
- fdesize = cpos() - fdeo - 4; // exclude the length field.
- pad = rnd(fdesize, PtrSize) - fdesize;
- strnput("", pad);
- fdesize += pad;
- cflush();
-
- // Emit the FDE header for real, Section 6.4.1.
- seek(cout, fdeo, 0);
- LPUT(fdesize);
- LPUT(0);
- addrput(p->pc);
- addrput(s->size);
-
- cflush();
- seek(cout, fdeo + 4 + fdesize, 0);
- }
-
- cflush();
- framesize = cpos() - frameo;
-}
-
-/*
- * Walk DWarfDebugInfoEntries, and emit .debug_info
- */
-enum
-{
- COMPUNITHEADERSIZE = 4+2+4+1
-};
-
-static void
-writeinfo(void)
-{
- DWDie *compunit;
- vlong unitstart, here;
-
- fwdcount = 0;
-
- for (compunit = dwroot.child; compunit; compunit = compunit->link) {
- unitstart = cpos();
-
- // Write .debug_info Compilation Unit Header (sec 7.5.1)
- // Fields marked with (*) must be changed for 64-bit dwarf
- // This must match COMPUNITHEADERSIZE above.
- LPUT(0); // unit_length (*), will be filled in later.
- WPUT(3); // dwarf version (appendix F)
- LPUT(0); // debug_abbrev_offset (*)
- cput(PtrSize); // address_size
-
- putdie(compunit);
-
- cflush();
- here = cpos();
- seek(cout, unitstart, 0);
- LPUT(here - unitstart - 4); // exclude the length field.
- cflush();
- seek(cout, here, 0);
- }
-
-}
-
-/*
- * Emit .debug_pubnames/_types. _info must have been written before,
- * because we need die->offs and infoo/infosize;
- */
-static int
-ispubname(DWDie *die) {
- DWAttr *a;
-
- switch(die->abbrev) {
- case DW_ABRV_FUNCTION:
- case DW_ABRV_VARIABLE:
- a = getattr(die, DW_AT_external);
- return a && a->value;
- }
- return 0;
-}
-
-static int
-ispubtype(DWDie *die) {
- return die->abbrev >= DW_ABRV_NULLTYPE;
-}
-
-static vlong
-writepub(int (*ispub)(DWDie*))
-{
- DWDie *compunit, *die;
- DWAttr *dwa;
- vlong unitstart, unitend, sectionstart, here;
-
- sectionstart = cpos();
-
- for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
- unitstart = compunit->offs - COMPUNITHEADERSIZE;
- if (compunit->link != nil)
- unitend = compunit->link->offs - COMPUNITHEADERSIZE;
- else
- unitend = infoo + infosize;
-
- // Write .debug_pubnames/types Header (sec 6.1.1)
- LPUT(0); // unit_length (*), will be filled in later.
- WPUT(2); // dwarf version (appendix F)
- LPUT(unitstart); // debug_info_offset (of the Comp unit Header)
- LPUT(unitend - unitstart); // debug_info_length
-
- for (die = compunit->child; die != nil; die = die->link) {
- if (!ispub(die)) continue;
- LPUT(die->offs - unitstart);
- dwa = getattr(die, DW_AT_name);
- strnput(dwa->data, dwa->value + 1);
- }
- LPUT(0);
-
- cflush();
- here = cpos();
- seek(cout, sectionstart, 0);
- LPUT(here - sectionstart - 4); // exclude the length field.
- cflush();
- seek(cout, here, 0);
-
- }
-
- return sectionstart;
-}
-
-/*
- * emit .debug_aranges. _info must have been written before,
- * because we need die->offs of dw_globals.
- */
-static vlong
-writearanges(void)
-{
- DWDie *compunit;
- DWAttr *b, *e;
- int headersize;
- vlong sectionstart;
-
- sectionstart = cpos();
- headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself
-
- for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
- b = getattr(compunit, DW_AT_low_pc);
- if (b == nil)
- continue;
- e = getattr(compunit, DW_AT_high_pc);
- if (e == nil)
- continue;
-
- // Write .debug_aranges Header + entry (sec 6.1.2)
- LPUT(headersize + 4*PtrSize - 4); // unit_length (*)
- WPUT(2); // dwarf version (appendix F)
- LPUT(compunit->offs - COMPUNITHEADERSIZE); // debug_info_offset
- cput(PtrSize); // address_size
- cput(0); // segment_size
- strnput("", headersize - (4+2+4+1+1)); // align to PtrSize
-
- addrput(b->value);
- addrput(e->value - b->value);
- addrput(0);
- addrput(0);
- }
- cflush();
- return sectionstart;
-}
-
-static vlong
-writegdbscript(void)
-{
- vlong sectionstart;
-
- sectionstart = cpos();
-
- if (gdbscript[0]) {
- cput(1); // magic 1 byte?
- strnput(gdbscript, strlen(gdbscript)+1);
- cflush();
- }
- return sectionstart;
-}
-
-static void
-align(vlong size)
-{
- if(HEADTYPE == Hwindows) // Only Windows PE need section align.
- strnput("", rnd(size, PEFILEALIGN) - size);
-}
-
-/*
- * This is the main entry point for generating dwarf. After emitting
- * the mandatory debug_abbrev section, it calls writelines() to set up
- * the per-compilation unit part of the DIE tree, while simultaneously
- * emitting the debug_line section. When the final tree contains
- * forward references, it will write the debug_info section in 2
- * passes.
- *
- */
-void
-dwarfemitdebugsections(void)
-{
- vlong infoe;
- DWDie* die;
-
- if(debug['w']) // disable dwarf
- return;
-
- // For diagnostic messages.
- newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes");
-
- mkindex(&dwroot);
- mkindex(&dwtypes);
- mkindex(&dwglobals);
-
- // Some types that must exist to define other ones.
- newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>");
- newdie(&dwtypes, DW_ABRV_NULLTYPE, "void");
- newrefattr(newdie(&dwtypes, DW_ABRV_PTRTYPE, "unsafe.Pointer"),
- DW_AT_type, find(&dwtypes, "void"));
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr"); // needed for array size
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
-
- // Needed by the prettyprinter code for interface inspection.
- defgotype(lookup_or_diag("type.runtime.commonType"));
- defgotype(lookup_or_diag("type.runtime.InterfaceType"));
- defgotype(lookup_or_diag("type.runtime.itab"));
-
- genasmsym(defdwsymb);
-
- writeabbrev();
- align(abbrevsize);
- writelines();
- align(linesize);
- writeframes();
- align(framesize);
-
- synthesizestringtypes(dwtypes.child);
- synthesizeslicetypes(dwtypes.child);
- synthesizemaptypes(dwtypes.child);
- synthesizechantypes(dwtypes.child);
-
- reversetree(&dwroot.child);
- reversetree(&dwtypes.child);
- reversetree(&dwglobals.child);
-
- movetomodule(&dwtypes);
- movetomodule(&dwglobals);
-
- infoo = cpos();
- writeinfo();
- infoe = cpos();
- pubnameso = infoe;
- pubtypeso = infoe;
- arangeso = infoe;
- gdbscripto = infoe;
-
- if (fwdcount > 0) {
- if (debug['v'])
- Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime());
- seek(cout, infoo, 0);
- writeinfo();
- if (fwdcount > 0) {
- diag("dwarf: unresolved references after first dwarf info pass");
- errorexit();
- }
- if (infoe != cpos()) {
- diag("dwarf: inconsistent second dwarf info pass");
- errorexit();
- }
- }
- infosize = infoe - infoo;
- align(infosize);
-
- pubnameso = writepub(ispubname);
- pubnamessize = cpos() - pubnameso;
- align(pubnamessize);
-
- pubtypeso = writepub(ispubtype);
- pubtypessize = cpos() - pubtypeso;
- align(pubtypessize);
-
- arangeso = writearanges();
- arangessize = cpos() - arangeso;
- align(arangessize);
-
- gdbscripto = writegdbscript();
- gdbscriptsize = cpos() - gdbscripto;
- align(gdbscriptsize);
-}
-
-/*
- * Elf.
- */
-enum
-{
- ElfStrDebugAbbrev,
- ElfStrDebugAranges,
- ElfStrDebugFrame,
- ElfStrDebugInfo,
- ElfStrDebugLine,
- ElfStrDebugLoc,
- ElfStrDebugMacinfo,
- ElfStrDebugPubNames,
- ElfStrDebugPubTypes,
- ElfStrDebugRanges,
- ElfStrDebugStr,
- ElfStrGDBScripts,
- NElfStrDbg
-};
-
-vlong elfstrdbg[NElfStrDbg];
-
-void
-dwarfaddshstrings(Sym *shstrtab)
-{
- if(debug['w']) // disable dwarf
- return;
-
- elfstrdbg[ElfStrDebugAbbrev] = addstring(shstrtab, ".debug_abbrev");
- elfstrdbg[ElfStrDebugAranges] = addstring(shstrtab, ".debug_aranges");
- elfstrdbg[ElfStrDebugFrame] = addstring(shstrtab, ".debug_frame");
- elfstrdbg[ElfStrDebugInfo] = addstring(shstrtab, ".debug_info");
- elfstrdbg[ElfStrDebugLine] = addstring(shstrtab, ".debug_line");
- elfstrdbg[ElfStrDebugLoc] = addstring(shstrtab, ".debug_loc");
- elfstrdbg[ElfStrDebugMacinfo] = addstring(shstrtab, ".debug_macinfo");
- elfstrdbg[ElfStrDebugPubNames] = addstring(shstrtab, ".debug_pubnames");
- elfstrdbg[ElfStrDebugPubTypes] = addstring(shstrtab, ".debug_pubtypes");
- elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges");
- elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str");
- elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts");
-}
-
-void
-dwarfaddelfheaders(void)
-{
- ElfShdr *sh;
-
- if(debug['w']) // disable dwarf
- return;
-
- sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]);
- sh->type = SHT_PROGBITS;
- sh->off = abbrevo;
- sh->size = abbrevsize;
- sh->addralign = 1;
-
- sh = newElfShdr(elfstrdbg[ElfStrDebugLine]);
- sh->type = SHT_PROGBITS;
- sh->off = lineo;
- sh->size = linesize;
- sh->addralign = 1;
-
- sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]);
- sh->type = SHT_PROGBITS;
- sh->off = frameo;
- sh->size = framesize;
- sh->addralign = 1;
-
- sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]);
- sh->type = SHT_PROGBITS;
- sh->off = infoo;
- sh->size = infosize;
- sh->addralign = 1;
-
- if (pubnamessize > 0) {
- sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]);
- sh->type = SHT_PROGBITS;
- sh->off = pubnameso;
- sh->size = pubnamessize;
- sh->addralign = 1;
- }
-
- if (pubtypessize > 0) {
- sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes]);
- sh->type = SHT_PROGBITS;
- sh->off = pubtypeso;
- sh->size = pubtypessize;
- sh->addralign = 1;
- }
-
- if (arangessize) {
- sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]);
- sh->type = SHT_PROGBITS;
- sh->off = arangeso;
- sh->size = arangessize;
- sh->addralign = 1;
- }
-
- if (gdbscriptsize) {
- sh = newElfShdr(elfstrdbg[ElfStrGDBScripts]);
- sh->type = SHT_PROGBITS;
- sh->off = gdbscripto;
- sh->size = gdbscriptsize;
- sh->addralign = 1;
- }
-}
-
-/*
- * Macho
- */
-void
-dwarfaddmachoheaders(void)
-{
- MachoSect *msect;
- MachoSeg *ms;
- vlong fakestart;
- int nsect;
-
- if(debug['w']) // disable dwarf
- return;
-
- // Zero vsize segments won't be loaded in memory, even so they
- // have to be page aligned in the file.
- fakestart = abbrevo & ~0xfff;
-
- nsect = 4;
- if (pubnamessize > 0)
- nsect++;
- if (pubtypessize > 0)
- nsect++;
- if (arangessize > 0)
- nsect++;
- if (gdbscriptsize > 0)
- nsect++;
-
- ms = newMachoSeg("__DWARF", nsect);
- ms->fileoffset = fakestart;
- ms->filesize = abbrevo-fakestart;
-
- msect = newMachoSect(ms, "__debug_abbrev");
- msect->off = abbrevo;
- msect->size = abbrevsize;
- ms->filesize += msect->size;
-
- msect = newMachoSect(ms, "__debug_line");
- msect->off = lineo;
- msect->size = linesize;
- ms->filesize += msect->size;
-
- msect = newMachoSect(ms, "__debug_frame");
- msect->off = frameo;
- msect->size = framesize;
- ms->filesize += msect->size;
-
- msect = newMachoSect(ms, "__debug_info");
- msect->off = infoo;
- msect->size = infosize;
- ms->filesize += msect->size;
-
- if (pubnamessize > 0) {
- msect = newMachoSect(ms, "__debug_pubnames");
- msect->off = pubnameso;
- msect->size = pubnamessize;
- ms->filesize += msect->size;
- }
-
- if (pubtypessize > 0) {
- msect = newMachoSect(ms, "__debug_pubtypes");
- msect->off = pubtypeso;
- msect->size = pubtypessize;
- ms->filesize += msect->size;
- }
-
- if (arangessize > 0) {
- msect = newMachoSect(ms, "__debug_aranges");
- msect->off = arangeso;
- msect->size = arangessize;
- ms->filesize += msect->size;
- }
-
- // TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
- if (gdbscriptsize > 0) {
- msect = newMachoSect(ms, "__debug_gdb_scripts");
- msect->off = gdbscripto;
- msect->size = gdbscriptsize;
- ms->filesize += msect->size;
- }
-}
-
-/*
- * Windows PE
- */
-void
-dwarfaddpeheaders(void)
-{
- if(debug['w']) // disable dwarf
- return;
-
- newPEDWARFSection(".debug_abbrev", abbrevsize);
- newPEDWARFSection(".debug_line", linesize);
- newPEDWARFSection(".debug_frame", framesize);
- newPEDWARFSection(".debug_info", infosize);
- newPEDWARFSection(".debug_pubnames", pubnamessize);
- newPEDWARFSection(".debug_pubtypes", pubtypessize);
- newPEDWARFSection(".debug_aranges", arangessize);
- newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize);
-}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
deleted file mode 100644
index f0df2f9b1..000000000
--- a/src/cmd/ld/dwarf.h
+++ /dev/null
@@ -1,30 +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.
-
-/*
- * Register 'f' symbol file fragments. Doing this while parsing the
- * .6 input saves a pass over the symbol table later.
- */
-void dwarfaddfrag(int n, char* frag);
-
-/*
- * Emit debug_abbrevs, debug_info and debug_line sections to current
- * offset in cout.
- */
-void dwarfemitdebugsections(void);
-
-/*
- * Add the dwarf section names to the ELF
- * s[ection]h[eader]str[ing]tab. Prerequisite for
- * dwarfaddelfheaders().
- */
-void dwarfaddshstrings(Sym *shstrtab);
-
-/*
- * Add section headers pointing to the sections emitted in
- * dwarfemitdebugsections.
- */
-void dwarfaddelfheaders(void);
-void dwarfaddmachoheaders(void);
-void dwarfaddpeheaders(void);
diff --git a/src/cmd/ld/dwarf_defs.h b/src/cmd/ld/dwarf_defs.h
deleted file mode 100644
index eed143dff..000000000
--- a/src/cmd/ld/dwarf_defs.h
+++ /dev/null
@@ -1,503 +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.
-
-// Cut, pasted, tr-and-awk'ed from tables in
-// http://dwarfstd.org/doc/Dwarf3.pdf
-
-// Table 18
-enum
-{
- DW_TAG_array_type = 0x01,
- DW_TAG_class_type = 0x02,
- DW_TAG_entry_point = 0x03,
- DW_TAG_enumeration_type = 0x04,
- DW_TAG_formal_parameter = 0x05,
- DW_TAG_imported_declaration = 0x08,
- DW_TAG_label = 0x0a,
- DW_TAG_lexical_block = 0x0b,
- DW_TAG_member = 0x0d,
- DW_TAG_pointer_type = 0x0f,
- DW_TAG_reference_type = 0x10,
- DW_TAG_compile_unit = 0x11,
- DW_TAG_string_type = 0x12,
- DW_TAG_structure_type = 0x13,
- DW_TAG_subroutine_type = 0x15,
- DW_TAG_typedef = 0x16,
- DW_TAG_union_type = 0x17,
- DW_TAG_unspecified_parameters = 0x18,
- DW_TAG_variant = 0x19,
- DW_TAG_common_block = 0x1a,
- DW_TAG_common_inclusion = 0x1b,
- DW_TAG_inheritance = 0x1c,
- DW_TAG_inlined_subroutine = 0x1d,
- DW_TAG_module = 0x1e,
- DW_TAG_ptr_to_member_type = 0x1f,
- DW_TAG_set_type = 0x20,
- DW_TAG_subrange_type = 0x21,
- DW_TAG_with_stmt = 0x22,
- DW_TAG_access_declaration = 0x23,
- DW_TAG_base_type = 0x24,
- DW_TAG_catch_block = 0x25,
- DW_TAG_const_type = 0x26,
- DW_TAG_constant = 0x27,
- DW_TAG_enumerator = 0x28,
- DW_TAG_file_type = 0x29,
- DW_TAG_friend = 0x2a,
- DW_TAG_namelist = 0x2b,
- DW_TAG_namelist_item = 0x2c,
- DW_TAG_packed_type = 0x2d,
- DW_TAG_subprogram = 0x2e,
- DW_TAG_template_type_parameter = 0x2f,
- DW_TAG_template_value_parameter = 0x30,
- DW_TAG_thrown_type = 0x31,
- DW_TAG_try_block = 0x32,
- DW_TAG_variant_part = 0x33,
- DW_TAG_variable = 0x34,
- DW_TAG_volatile_type = 0x35,
- // Dwarf3
- DW_TAG_dwarf_procedure = 0x36,
- DW_TAG_restrict_type = 0x37,
- DW_TAG_interface_type = 0x38,
- DW_TAG_namespace = 0x39,
- DW_TAG_imported_module = 0x3a,
- DW_TAG_unspecified_type = 0x3b,
- DW_TAG_partial_unit = 0x3c,
- DW_TAG_imported_unit = 0x3d,
- DW_TAG_condition = 0x3f,
- DW_TAG_shared_type = 0x40,
- // Dwarf4
- DW_TAG_type_unit = 0x41,
- DW_TAG_rvalue_reference_type = 0x42,
- DW_TAG_template_alias = 0x43,
-
- // User defined
- DW_TAG_lo_user = 0x4080,
- DW_TAG_hi_user = 0xffff,
-
-};
-
-// Table 19
-enum
-{
- DW_CHILDREN_no = 0x00,
- DW_CHILDREN_yes = 0x01,
-};
-
-// Not from the spec, but logicaly belongs here
-enum
-{
- DW_CLS_ADDRESS = 0x01,
- DW_CLS_BLOCK,
- DW_CLS_CONSTANT,
- DW_CLS_FLAG,
- DW_CLS_PTR, // lineptr, loclistptr, macptr, rangelistptr
- DW_CLS_REFERENCE,
- DW_CLS_STRING
-};
-
-// Table 20
-enum
-{
- DW_AT_sibling = 0x01, // reference
- DW_AT_location = 0x02, // block, loclistptr
- DW_AT_name = 0x03, // string
- DW_AT_ordering = 0x09, // constant
- DW_AT_byte_size = 0x0b, // block, constant, reference
- DW_AT_bit_offset = 0x0c, // block, constant, reference
- DW_AT_bit_size = 0x0d, // block, constant, reference
- DW_AT_stmt_list = 0x10, // lineptr
- DW_AT_low_pc = 0x11, // address
- DW_AT_high_pc = 0x12, // address
- DW_AT_language = 0x13, // constant
- DW_AT_discr = 0x15, // reference
- DW_AT_discr_value = 0x16, // constant
- DW_AT_visibility = 0x17, // constant
- DW_AT_import = 0x18, // reference
- DW_AT_string_length = 0x19, // block, loclistptr
- DW_AT_common_reference = 0x1a, // reference
- DW_AT_comp_dir = 0x1b, // string
- DW_AT_const_value = 0x1c, // block, constant, string
- DW_AT_containing_type = 0x1d, // reference
- DW_AT_default_value = 0x1e, // reference
- DW_AT_inline = 0x20, // constant
- DW_AT_is_optional = 0x21, // flag
- DW_AT_lower_bound = 0x22, // block, constant, reference
- DW_AT_producer = 0x25, // string
- DW_AT_prototyped = 0x27, // flag
- DW_AT_return_addr = 0x2a, // block, loclistptr
- DW_AT_start_scope = 0x2c, // constant
- DW_AT_bit_stride = 0x2e, // constant
- DW_AT_upper_bound = 0x2f, // block, constant, reference
- DW_AT_abstract_origin = 0x31, // reference
- DW_AT_accessibility = 0x32, // constant
- DW_AT_address_class = 0x33, // constant
- DW_AT_artificial = 0x34, // flag
- DW_AT_base_types = 0x35, // reference
- DW_AT_calling_convention = 0x36, // constant
- DW_AT_count = 0x37, // block, constant, reference
- DW_AT_data_member_location = 0x38, // block, constant, loclistptr
- DW_AT_decl_column = 0x39, // constant
- DW_AT_decl_file = 0x3a, // constant
- DW_AT_decl_line = 0x3b, // constant
- DW_AT_declaration = 0x3c, // flag
- DW_AT_discr_list = 0x3d, // block
- DW_AT_encoding = 0x3e, // constant
- DW_AT_external = 0x3f, // flag
- DW_AT_frame_base = 0x40, // block, loclistptr
- DW_AT_friend = 0x41, // reference
- DW_AT_identifier_case = 0x42, // constant
- DW_AT_macro_info = 0x43, // macptr
- DW_AT_namelist_item = 0x44, // block
- DW_AT_priority = 0x45, // reference
- DW_AT_segment = 0x46, // block, loclistptr
- DW_AT_specification = 0x47, // reference
- DW_AT_static_link = 0x48, // block, loclistptr
- DW_AT_type = 0x49, // reference
- DW_AT_use_location = 0x4a, // block, loclistptr
- DW_AT_variable_parameter = 0x4b, // flag
- DW_AT_virtuality = 0x4c, // constant
- DW_AT_vtable_elem_location = 0x4d, // block, loclistptr
- // Dwarf3
- DW_AT_allocated = 0x4e, // block, constant, reference
- DW_AT_associated = 0x4f, // block, constant, reference
- DW_AT_data_location = 0x50, // block
- DW_AT_byte_stride = 0x51, // block, constant, reference
- DW_AT_entry_pc = 0x52, // address
- DW_AT_use_UTF8 = 0x53, // flag
- DW_AT_extension = 0x54, // reference
- DW_AT_ranges = 0x55, // rangelistptr
- DW_AT_trampoline = 0x56, // address, flag, reference, string
- DW_AT_call_column = 0x57, // constant
- DW_AT_call_file = 0x58, // constant
- DW_AT_call_line = 0x59, // constant
- DW_AT_description = 0x5a, // string
- DW_AT_binary_scale = 0x5b, // constant
- DW_AT_decimal_scale = 0x5c, // constant
- DW_AT_small = 0x5d, // reference
- DW_AT_decimal_sign = 0x5e, // constant
- DW_AT_digit_count = 0x5f, // constant
- DW_AT_picture_string = 0x60, // string
- DW_AT_mutable = 0x61, // flag
- DW_AT_threads_scaled = 0x62, // flag
- DW_AT_explicit = 0x63, // flag
- DW_AT_object_pointer = 0x64, // reference
- DW_AT_endianity = 0x65, // constant
- DW_AT_elemental = 0x66, // flag
- DW_AT_pure = 0x67, // flag
- DW_AT_recursive = 0x68, // flag
-
- DW_AT_lo_user = 0x2000, // ---
- DW_AT_hi_user = 0x3fff, // ---
-
-};
-
-// Table 21
-enum
-{
- DW_FORM_addr = 0x01, // address
- DW_FORM_block2 = 0x03, // block
- DW_FORM_block4 = 0x04, // block
- DW_FORM_data2 = 0x05, // constant
- DW_FORM_data4 = 0x06, // constant, lineptr, loclistptr, macptr, rangelistptr
- DW_FORM_data8 = 0x07, // constant, lineptr, loclistptr, macptr, rangelistptr
- DW_FORM_string = 0x08, // string
- DW_FORM_block = 0x09, // block
- DW_FORM_block1 = 0x0a, // block
- DW_FORM_data1 = 0x0b, // constant
- DW_FORM_flag = 0x0c, // flag
- DW_FORM_sdata = 0x0d, // constant
- DW_FORM_strp = 0x0e, // string
- DW_FORM_udata = 0x0f, // constant
- DW_FORM_ref_addr = 0x10, // reference
- DW_FORM_ref1 = 0x11, // reference
- DW_FORM_ref2 = 0x12, // reference
- DW_FORM_ref4 = 0x13, // reference
- DW_FORM_ref8 = 0x14, // reference
- DW_FORM_ref_udata = 0x15, // reference
- DW_FORM_indirect = 0x16, // (see Section 7.5.3)
-};
-
-// Table 24 (#operands, notes)
-enum
-{
- DW_OP_addr = 0x03, // 1 constant address (size target specific)
- DW_OP_deref = 0x06, // 0
- DW_OP_const1u = 0x08, // 1 1-byte constant
- DW_OP_const1s = 0x09, // 1 1-byte constant
- DW_OP_const2u = 0x0a, // 1 2-byte constant
- DW_OP_const2s = 0x0b, // 1 2-byte constant
- DW_OP_const4u = 0x0c, // 1 4-byte constant
- DW_OP_const4s = 0x0d, // 1 4-byte constant
- DW_OP_const8u = 0x0e, // 1 8-byte constant
- DW_OP_const8s = 0x0f, // 1 8-byte constant
- DW_OP_constu = 0x10, // 1 ULEB128 constant
- DW_OP_consts = 0x11, // 1 SLEB128 constant
- DW_OP_dup = 0x12, // 0
- DW_OP_drop = 0x13, // 0
- DW_OP_over = 0x14, // 0
- DW_OP_pick = 0x15, // 1 1-byte stack index
- DW_OP_swap = 0x16, // 0
- DW_OP_rot = 0x17, // 0
- DW_OP_xderef = 0x18, // 0
- DW_OP_abs = 0x19, // 0
- DW_OP_and = 0x1a, // 0
- DW_OP_div = 0x1b, // 0
- DW_OP_minus = 0x1c, // 0
- DW_OP_mod = 0x1d, // 0
- DW_OP_mul = 0x1e, // 0
- DW_OP_neg = 0x1f, // 0
- DW_OP_not = 0x20, // 0
- DW_OP_or = 0x21, // 0
- DW_OP_plus = 0x22, // 0
- DW_OP_plus_uconst = 0x23, // 1 ULEB128 addend
- DW_OP_shl = 0x24, // 0
- DW_OP_shr = 0x25, // 0
- DW_OP_shra = 0x26, // 0
- DW_OP_xor = 0x27, // 0
- DW_OP_skip = 0x2f, // 1 signed 2-byte constant
- DW_OP_bra = 0x28, // 1 signed 2-byte constant
- DW_OP_eq = 0x29, // 0
- DW_OP_ge = 0x2a, // 0
- DW_OP_gt = 0x2b, // 0
- DW_OP_le = 0x2c, // 0
- DW_OP_lt = 0x2d, // 0
- DW_OP_ne = 0x2e, // 0
- DW_OP_lit0 = 0x30, // 0 ...
- DW_OP_lit31 = 0x4f, // 0 literals 0..31 = (DW_OP_lit0 +
- // literal)
- DW_OP_reg0 = 0x50, // 0 ..
- DW_OP_reg31 = 0x6f, // 0 reg 0..31 = (DW_OP_reg0 + regnum)
- DW_OP_breg0 = 0x70, // 1 ...
- DW_OP_breg31 = 0x8f, // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum)
- DW_OP_regx = 0x90, // 1 ULEB128 register
- DW_OP_fbreg = 0x91, // 1 SLEB128 offset
- DW_OP_bregx = 0x92, // 2 ULEB128 register followed by SLEB128 offset
- DW_OP_piece = 0x93, // 1 ULEB128 size of piece addressed
- DW_OP_deref_size = 0x94, // 1 1-byte size of data retrieved
- DW_OP_xderef_size = 0x95, // 1 1-byte size of data retrieved
- DW_OP_nop = 0x96, // 0
- DW_OP_push_object_address = 0x97, // 0
- DW_OP_call2 = 0x98, // 1 2-byte offset of DIE
- DW_OP_call4 = 0x99, // 1 4-byte offset of DIE
- DW_OP_call_ref = 0x9a, // 1 4- or 8-byte offset of DIE
- DW_OP_form_tls_address = 0x9b, // 0
- DW_OP_call_frame_cfa = 0x9c, // 0
- DW_OP_bit_piece = 0x9d, // 2
- DW_OP_lo_user = 0xe0,
- DW_OP_hi_user = 0xff,
-};
-
-// Table 25
-enum
-{
- DW_ATE_address = 0x01,
- DW_ATE_boolean = 0x02,
- DW_ATE_complex_float = 0x03,
- DW_ATE_float = 0x04,
- DW_ATE_signed = 0x05,
- DW_ATE_signed_char = 0x06,
- DW_ATE_unsigned = 0x07,
- DW_ATE_unsigned_char = 0x08,
- DW_ATE_imaginary_float = 0x09,
- DW_ATE_packed_decimal = 0x0a,
- DW_ATE_numeric_string = 0x0b,
- DW_ATE_edited = 0x0c,
- DW_ATE_signed_fixed = 0x0d,
- DW_ATE_unsigned_fixed = 0x0e,
- DW_ATE_decimal_float = 0x0f,
- DW_ATE_lo_user = 0x80,
- DW_ATE_hi_user = 0xff,
-};
-
-// Table 26
-enum
-{
- DW_DS_unsigned = 0x01,
- DW_DS_leading_overpunch = 0x02,
- DW_DS_trailing_overpunch = 0x03,
- DW_DS_leading_separate = 0x04,
- DW_DS_trailing_separate = 0x05,
-};
-
-// Table 27
-enum
-{
- DW_END_default = 0x00,
- DW_END_big = 0x01,
- DW_END_little = 0x02,
- DW_END_lo_user = 0x40,
- DW_END_hi_user = 0xff,
-};
-
-// Table 28
-enum
-{
- DW_ACCESS_public = 0x01,
- DW_ACCESS_protected = 0x02,
- DW_ACCESS_private = 0x03,
-};
-
-// Table 29
-enum
-{
- DW_VIS_local = 0x01,
- DW_VIS_exported = 0x02,
- DW_VIS_qualified = 0x03,
-};
-
-// Table 30
-enum
-{
- DW_VIRTUALITY_none = 0x00,
- DW_VIRTUALITY_virtual = 0x01,
- DW_VIRTUALITY_pure_virtual = 0x02,
-};
-
-// Table 31
-enum
-{
- DW_LANG_C89 = 0x0001,
- DW_LANG_C = 0x0002,
- DW_LANG_Ada83 = 0x0003,
- DW_LANG_C_plus_plus = 0x0004,
- DW_LANG_Cobol74 = 0x0005,
- DW_LANG_Cobol85 = 0x0006,
- DW_LANG_Fortran77 = 0x0007,
- DW_LANG_Fortran90 = 0x0008,
- DW_LANG_Pascal83 = 0x0009,
- DW_LANG_Modula2 = 0x000a,
- // Dwarf3
- DW_LANG_Java = 0x000b,
- DW_LANG_C99 = 0x000c,
- DW_LANG_Ada95 = 0x000d,
- DW_LANG_Fortran95 = 0x000e,
- DW_LANG_PLI = 0x000f,
- DW_LANG_ObjC = 0x0010,
- DW_LANG_ObjC_plus_plus = 0x0011,
- DW_LANG_UPC = 0x0012,
- DW_LANG_D = 0x0013,
- // Dwarf4
- DW_LANG_Python = 0x0014,
- // Dwarf5
- DW_LANG_Go = 0x0016,
-
- DW_LANG_lo_user = 0x8000,
- DW_LANG_hi_user = 0xffff,
-};
-
-// Table 32
-enum
-{
- DW_ID_case_sensitive = 0x00,
- DW_ID_up_case = 0x01,
- DW_ID_down_case = 0x02,
- DW_ID_case_insensitive = 0x03,
-};
-
-// Table 33
-enum
-{
- DW_CC_normal = 0x01,
- DW_CC_program = 0x02,
- DW_CC_nocall = 0x03,
- DW_CC_lo_user = 0x40,
- DW_CC_hi_user = 0xff,
-};
-
-// Table 34
-enum
-{
- DW_INL_not_inlined = 0x00,
- DW_INL_inlined = 0x01,
- DW_INL_declared_not_inlined = 0x02,
- DW_INL_declared_inlined = 0x03,
-};
-
-// Table 35
-enum
-{
- DW_ORD_row_major = 0x00,
- DW_ORD_col_major = 0x01,
-};
-
-// Table 36
-enum
-{
- DW_DSC_label = 0x00,
- DW_DSC_range = 0x01,
-};
-
-// Table 37
-enum
-{
- DW_LNS_copy = 0x01,
- DW_LNS_advance_pc = 0x02,
- DW_LNS_advance_line = 0x03,
- DW_LNS_set_file = 0x04,
- DW_LNS_set_column = 0x05,
- DW_LNS_negate_stmt = 0x06,
- DW_LNS_set_basic_block = 0x07,
- DW_LNS_const_add_pc = 0x08,
- DW_LNS_fixed_advance_pc = 0x09,
- // Dwarf3
- DW_LNS_set_prologue_end = 0x0a,
- DW_LNS_set_epilogue_begin = 0x0b,
- DW_LNS_set_isa = 0x0c,
-};
-
-// Table 38
-enum
-{
- DW_LNE_end_sequence = 0x01,
- DW_LNE_set_address = 0x02,
- DW_LNE_define_file = 0x03,
- DW_LNE_lo_user = 0x80,
- DW_LNE_hi_user = 0xff,
-};
-
-// Table 39
-enum
-{
- DW_MACINFO_define = 0x01,
- DW_MACINFO_undef = 0x02,
- DW_MACINFO_start_file = 0x03,
- DW_MACINFO_end_file = 0x04,
- DW_MACINFO_vendor_ext = 0xff,
-};
-
-// Table 40.
-enum
-{ // operand,...
- DW_CFA_nop = 0x00,
- DW_CFA_set_loc = 0x01, // address
- DW_CFA_advance_loc1 = 0x02, // 1-byte delta
- DW_CFA_advance_loc2 = 0x03, // 2-byte delta
- DW_CFA_advance_loc4 = 0x04, // 4-byte delta
- DW_CFA_offset_extended = 0x05, // ULEB128 register, ULEB128 offset
- DW_CFA_restore_extended = 0x06, // ULEB128 register
- DW_CFA_undefined = 0x07, // ULEB128 register
- DW_CFA_same_value = 0x08, // ULEB128 register
- DW_CFA_register = 0x09, // ULEB128 register, ULEB128 register
- DW_CFA_remember_state = 0x0a,
- DW_CFA_restore_state = 0x0b,
- DW_CFA_def_cfa = 0x0c, // ULEB128 register, ULEB128 offset
- DW_CFA_def_cfa_register = 0x0d, // ULEB128 register
- DW_CFA_def_cfa_offset = 0x0e, // ULEB128 offset
- DW_CFA_def_cfa_expression = 0x0f, // BLOCK
- DW_CFA_expression = 0x10, // ULEB128 register, BLOCK
- DW_CFA_offset_extended_sf = 0x11, // ULEB128 register, SLEB128 offset
- DW_CFA_def_cfa_sf = 0x12, // ULEB128 register, SLEB128 offset
- DW_CFA_def_cfa_offset_sf = 0x13, // SLEB128 offset
- DW_CFA_val_offset = 0x14, // ULEB128, ULEB128
- DW_CFA_val_offset_sf = 0x15, // ULEB128, SLEB128
- DW_CFA_val_expression = 0x16, // ULEB128, BLOCK
-
- DW_CFA_lo_user = 0x1c,
- DW_CFA_hi_user = 0x3f,
-
- // Opcodes that take an addend operand.
- DW_CFA_advance_loc = 0x1<<6, // +delta
- DW_CFA_offset = 0x2<<6, // +register (ULEB128 offset)
- DW_CFA_restore = 0x3<<6, // +register
-};
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
deleted file mode 100644
index fc917b203..000000000
--- a/src/cmd/ld/elf.c
+++ /dev/null
@@ -1,558 +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 "l.h"
-#include "lib.h"
-#include "../ld/elf.h"
-
-/*
- * We use the 64-bit data structures on both 32- and 64-bit machines
- * in order to write the code just once. The 64-bit data structure is
- * written in the 32-bit format on the 32-bit machines.
- */
-#define NSECT 32
-
-int iself;
-
-static int elf64;
-static ElfEhdr hdr;
-static ElfPhdr *phdr[NSECT];
-static ElfShdr *shdr[NSECT];
-static char *interp;
-
-typedef struct Elfstring Elfstring;
-struct Elfstring
-{
- char *s;
- int off;
-};
-
-static Elfstring elfstr[100];
-static int nelfstr;
-
-/*
- Initialize the global variable that describes the ELF header. It will be updated as
- we write section and prog headers.
- */
-void
-elfinit(void)
-{
- iself = 1;
-
- switch(thechar) {
- // 64-bit architectures
- case '6':
- elf64 = 1;
- hdr.phoff = ELF64HDRSIZE; /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
- hdr.shoff = ELF64HDRSIZE; /* Will move as we add PHeaders */
- hdr.ehsize = ELF64HDRSIZE; /* Must be ELF64HDRSIZE */
- hdr.phentsize = ELF64PHDRSIZE; /* Must be ELF64PHDRSIZE */
- hdr.shentsize = ELF64SHDRSIZE; /* Must be ELF64SHDRSIZE */
- break;
-
- // 32-bit architectures
- default:
- hdr.phoff = ELF32HDRSIZE; /* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
- hdr.shoff = ELF32HDRSIZE; /* Will move as we add PHeaders */
- hdr.ehsize = ELF32HDRSIZE; /* Must be ELF32HDRSIZE */
- hdr.phentsize = ELF32PHDRSIZE; /* Must be ELF32PHDRSIZE */
- hdr.shentsize = ELF32SHDRSIZE; /* Must be ELF32SHDRSIZE */
- }
-}
-
-void
-elf64phdr(ElfPhdr *e)
-{
- LPUT(e->type);
- LPUT(e->flags);
- VPUT(e->off);
- VPUT(e->vaddr);
- VPUT(e->paddr);
- VPUT(e->filesz);
- VPUT(e->memsz);
- VPUT(e->align);
-}
-
-void
-elf32phdr(ElfPhdr *e)
-{
- LPUT(e->type);
- LPUT(e->off);
- LPUT(e->vaddr);
- LPUT(e->paddr);
- LPUT(e->filesz);
- LPUT(e->memsz);
- LPUT(e->flags);
- LPUT(e->align);
-}
-
-void
-elf64shdr(ElfShdr *e)
-{
- LPUT(e->name);
- LPUT(e->type);
- VPUT(e->flags);
- VPUT(e->addr);
- VPUT(e->off);
- VPUT(e->size);
- LPUT(e->link);
- LPUT(e->info);
- VPUT(e->addralign);
- VPUT(e->entsize);
-}
-
-void
-elf32shdr(ElfShdr *e)
-{
- LPUT(e->name);
- LPUT(e->type);
- LPUT(e->flags);
- LPUT(e->addr);
- LPUT(e->off);
- LPUT(e->size);
- LPUT(e->link);
- LPUT(e->info);
- LPUT(e->addralign);
- LPUT(e->entsize);
-}
-
-uint32
-elfwriteshdrs(void)
-{
- int i;
-
- if (elf64) {
- for (i = 0; i < hdr.shnum; i++)
- elf64shdr(shdr[i]);
- return hdr.shnum * ELF64SHDRSIZE;
- }
- for (i = 0; i < hdr.shnum; i++)
- elf32shdr(shdr[i]);
- return hdr.shnum * ELF32SHDRSIZE;
-}
-
-void
-elfsetstring(char *s, int off)
-{
- if(nelfstr >= nelem(elfstr)) {
- diag("too many elf strings");
- errorexit();
- }
- elfstr[nelfstr].s = s;
- elfstr[nelfstr].off = off;
- nelfstr++;
-}
-
-uint32
-elfwritephdrs(void)
-{
- int i;
-
- if (elf64) {
- for (i = 0; i < hdr.phnum; i++)
- elf64phdr(phdr[i]);
- return hdr.phnum * ELF64PHDRSIZE;
- }
- for (i = 0; i < hdr.phnum; i++)
- elf32phdr(phdr[i]);
- return hdr.phnum * ELF32PHDRSIZE;
-}
-
-ElfPhdr*
-newElfPhdr(void)
-{
- ElfPhdr *e;
-
- e = mal(sizeof *e);
- if (hdr.phnum >= NSECT)
- diag("too many phdrs");
- else
- phdr[hdr.phnum++] = e;
- if (elf64)
- hdr.shoff += ELF64PHDRSIZE;
- else
- hdr.shoff += ELF32PHDRSIZE;
- return e;
-}
-
-ElfShdr*
-newElfShstrtab(vlong name)
-{
- hdr.shstrndx = hdr.shnum;
- return newElfShdr(name);
-}
-
-ElfShdr*
-newElfShdr(vlong name)
-{
- ElfShdr *e;
-
- e = mal(sizeof *e);
- e->name = name;
- if (hdr.shnum >= NSECT) {
- diag("too many shdrs");
- } else {
- shdr[hdr.shnum++] = e;
- }
- return e;
-}
-
-ElfEhdr*
-getElfEhdr(void)
-{
- return &hdr;
-}
-
-uint32
-elf64writehdr(void)
-{
- int i;
-
- for (i = 0; i < EI_NIDENT; i++)
- cput(hdr.ident[i]);
- WPUT(hdr.type);
- WPUT(hdr.machine);
- LPUT(hdr.version);
- VPUT(hdr.entry);
- VPUT(hdr.phoff);
- VPUT(hdr.shoff);
- LPUT(hdr.flags);
- WPUT(hdr.ehsize);
- WPUT(hdr.phentsize);
- WPUT(hdr.phnum);
- WPUT(hdr.shentsize);
- WPUT(hdr.shnum);
- WPUT(hdr.shstrndx);
- return ELF64HDRSIZE;
-}
-
-uint32
-elf32writehdr(void)
-{
- int i;
-
- for (i = 0; i < EI_NIDENT; i++)
- cput(hdr.ident[i]);
- WPUT(hdr.type);
- WPUT(hdr.machine);
- LPUT(hdr.version);
- LPUT(hdr.entry);
- LPUT(hdr.phoff);
- LPUT(hdr.shoff);
- LPUT(hdr.flags);
- WPUT(hdr.ehsize);
- WPUT(hdr.phentsize);
- WPUT(hdr.phnum);
- WPUT(hdr.shentsize);
- WPUT(hdr.shnum);
- WPUT(hdr.shstrndx);
- return ELF32HDRSIZE;
-}
-
-uint32
-elfwritehdr(void)
-{
- if(elf64)
- return elf64writehdr();
- return elf32writehdr();
-}
-
-/* Taken directly from the definition document for ELF64 */
-uint32
-elfhash(uchar *name)
-{
- uint32 h = 0, g;
- while (*name) {
- h = (h << 4) + *name++;
- if (g = h & 0xf0000000)
- h ^= g >> 24;
- h &= 0x0fffffff;
- }
- return h;
-}
-
-void
-elfwritedynent(Sym *s, int tag, uint64 val)
-{
- if(elf64) {
- adduint64(s, tag);
- adduint64(s, val);
- } else {
- adduint32(s, tag);
- adduint32(s, val);
- }
-}
-
-void
-elfwritedynentsym(Sym *s, int tag, Sym *t)
-{
- if(elf64)
- adduint64(s, tag);
- else
- adduint32(s, tag);
- addaddr(s, t);
-}
-
-void
-elfwritedynentsymsize(Sym *s, int tag, Sym *t)
-{
- if(elf64)
- adduint64(s, tag);
- else
- adduint32(s, tag);
- addsize(s, t);
-}
-
-int
-elfwriteinterp(void)
-{
- int n;
-
- if(interp == nil)
- return 0;
-
- n = strlen(interp)+1;
- seek(cout, ELFRESERVE-n, 0);
- ewrite(cout, interp, n);
- return n;
-}
-
-void
-elfinterp(ElfShdr *sh, uint64 startva, char *p)
-{
- int n;
-
- interp = p;
- n = strlen(interp)+1;
- sh->addr = startva + ELFRESERVE - n;
- sh->off = ELFRESERVE - n;
- sh->size = n;
-}
-
-extern int nelfsym;
-int elfverneed;
-
-typedef struct Elfaux Elfaux;
-typedef struct Elflib Elflib;
-
-struct Elflib
-{
- Elflib *next;
- Elfaux *aux;
- char *file;
-};
-
-struct Elfaux
-{
- Elfaux *next;
- int num;
- char *vers;
-};
-
-Elfaux*
-addelflib(Elflib **list, char *file, char *vers)
-{
- Elflib *lib;
- Elfaux *aux;
-
- for(lib=*list; lib; lib=lib->next)
- if(strcmp(lib->file, file) == 0)
- goto havelib;
- lib = mal(sizeof *lib);
- lib->next = *list;
- lib->file = file;
- *list = lib;
-havelib:
- for(aux=lib->aux; aux; aux=aux->next)
- if(strcmp(aux->vers, vers) == 0)
- goto haveaux;
- aux = mal(sizeof *aux);
- aux->next = lib->aux;
- aux->vers = vers;
- lib->aux = aux;
-haveaux:
- return aux;
-}
-
-void
-elfdynhash(void)
-{
- Sym *s, *sy, *dynstr;
- int i, j, nbucket, b, nfile;
- uint32 hc, *chain, *buckets;
- int nsym;
- char *name;
- Elfaux **need;
- Elflib *needlib;
- Elflib *l;
- Elfaux *x;
-
- if(!iself)
- return;
-
- nsym = nelfsym;
- s = lookup(".hash", 0);
- s->type = SELFDATA;
- s->reachable = 1;
-
- i = nsym;
- nbucket = 1;
- while(i > 0) {
- ++nbucket;
- i >>= 1;
- }
-
- needlib = nil;
- need = malloc(nsym * sizeof need[0]);
- chain = malloc(nsym * sizeof chain[0]);
- buckets = malloc(nbucket * sizeof buckets[0]);
- if(need == nil || chain == nil || buckets == nil) {
- cursym = nil;
- diag("out of memory");
- errorexit();
- }
- memset(need, 0, nsym * sizeof need[0]);
- memset(chain, 0, nsym * sizeof chain[0]);
- memset(buckets, 0, nbucket * sizeof buckets[0]);
- for(sy=allsym; sy!=S; sy=sy->allsym) {
- if (sy->dynid <= 0)
- continue;
-
- if(sy->dynimpvers)
- need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers);
-
- name = sy->dynimpname;
- if(name == nil)
- name = sy->name;
- hc = elfhash((uchar*)name);
-
- b = hc % nbucket;
- chain[sy->dynid] = buckets[b];
- buckets[b] = sy->dynid;
- }
-
- adduint32(s, nbucket);
- adduint32(s, nsym);
- for(i = 0; i<nbucket; i++)
- adduint32(s, buckets[i]);
- for(i = 0; i<nsym; i++)
- adduint32(s, chain[i]);
-
- free(chain);
- free(buckets);
-
- // version symbols
- dynstr = lookup(".dynstr", 0);
- s = lookup(".gnu.version_r", 0);
- i = 2;
- nfile = 0;
- for(l=needlib; l; l=l->next) {
- nfile++;
- // header
- adduint16(s, 1); // table version
- j = 0;
- for(x=l->aux; x; x=x->next)
- j++;
- adduint16(s, j); // aux count
- adduint32(s, addstring(dynstr, l->file)); // file string offset
- adduint32(s, 16); // offset from header to first aux
- if(l->next)
- adduint32(s, 16+j*16); // offset from this header to next
- else
- adduint32(s, 0);
-
- for(x=l->aux; x; x=x->next) {
- x->num = i++;
- // aux struct
- adduint32(s, elfhash((uchar*)x->vers)); // hash
- adduint16(s, 0); // flags
- adduint16(s, x->num); // other - index we refer to this by
- adduint32(s, addstring(dynstr, x->vers)); // version string offset
- if(x->next)
- adduint32(s, 16); // offset from this aux to next
- else
- adduint32(s, 0);
- }
- }
-
- // version references
- s = lookup(".gnu.version", 0);
- for(i=0; i<nsym; i++) {
- if(i == 0)
- adduint16(s, 0); // first entry - no symbol
- else if(need[i] == nil)
- adduint16(s, 1); // global
- else
- adduint16(s, need[i]->num);
- }
-
- free(need);
-
- s = lookup(".dynamic", 0);
- elfverneed = nfile;
- if(elfverneed) {
- elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0));
- elfwritedynent(s, DT_VERNEEDNUM, nfile);
- elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0));
- }
- elfwritedynent(s, DT_NULL, 0);
-}
-
-ElfPhdr*
-elfphload(Segment *seg)
-{
- ElfPhdr *ph;
-
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- if(seg->rwx & 4)
- ph->flags |= PF_R;
- if(seg->rwx & 2)
- ph->flags |= PF_W;
- if(seg->rwx & 1)
- ph->flags |= PF_X;
- ph->vaddr = seg->vaddr;
- ph->paddr = seg->vaddr;
- ph->memsz = seg->len;
- ph->off = seg->fileoff;
- ph->filesz = seg->filelen;
- ph->align = INITRND;
-
- return ph;
-}
-
-ElfShdr*
-elfshbits(Section *sect)
-{
- int i, off;
- ElfShdr *sh;
-
- for(i=0; i<nelfstr; i++) {
- if(strcmp(sect->name, elfstr[i].s) == 0) {
- off = elfstr[i].off;
- goto found;
- }
- }
- diag("cannot find elf name %s", sect->name);
- errorexit();
- return nil;
-
-found:
- sh = newElfShdr(off);
- if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen)
- sh->type = SHT_PROGBITS;
- else
- sh->type = SHT_NOBITS;
- sh->flags = SHF_ALLOC;
- if(sect->rwx & 1)
- sh->flags |= SHF_EXECINSTR;
- if(sect->rwx & 2)
- sh->flags |= SHF_WRITE;
- sh->addr = sect->vaddr;
- sh->addralign = PtrSize;
- sh->size = sect->len;
- sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
-
- return sh;
-}
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
deleted file mode 100644
index c63df2241..000000000
--- a/src/cmd/ld/elf.h
+++ /dev/null
@@ -1,989 +0,0 @@
-/*
- * Derived from:
- * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
- * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
- * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
- * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
- * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
- * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
- *
- * Copyright (c) 1996-1998 John D. Polstra. All rights reserved.
- * Copyright (c) 2001 David E. O'Brien
- * Portions Copyright 2009 The Go Authors. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-/*
- * ELF definitions that are independent of architecture or word size.
- */
-
-/*
- * Note header. The ".note" section contains an array of notes. Each
- * begins with this header, aligned to a word boundary. Immediately
- * following the note header is n_namesz bytes of name, padded to the
- * next word boundary. Then comes n_descsz bytes of descriptor, again
- * padded to a word boundary. The values of n_namesz and n_descsz do
- * not include the padding.
- */
-
-typedef struct {
- uint32 n_namesz; /* Length of name. */
- uint32 n_descsz; /* Length of descriptor. */
- uint32 n_type; /* Type of this note. */
-} Elf_Note;
-
-/* Indexes into the e_ident array. Keep synced with
- http://www.sco.com/developer/gabi/ch4.eheader.html */
-#define EI_MAG0 0 /* Magic number, byte 0. */
-#define EI_MAG1 1 /* Magic number, byte 1. */
-#define EI_MAG2 2 /* Magic number, byte 2. */
-#define EI_MAG3 3 /* Magic number, byte 3. */
-#define EI_CLASS 4 /* Class of machine. */
-#define EI_DATA 5 /* Data format. */
-#define EI_VERSION 6 /* ELF format version. */
-#define EI_OSABI 7 /* Operating system / ABI identification */
-#define EI_ABIVERSION 8 /* ABI version */
-#define OLD_EI_BRAND 8 /* Start of architecture identification. */
-#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */
-#define EI_NIDENT 16 /* Size of e_ident array. */
-
-/* Values for the magic number bytes. */
-#define ELFMAG0 0x7f
-#define ELFMAG1 'E'
-#define ELFMAG2 'L'
-#define ELFMAG3 'F'
-#define ELFMAG "\177ELF" /* magic string */
-#define SELFMAG 4 /* magic string size */
-
-/* Values for e_ident[EI_VERSION] and e_version. */
-#define EV_NONE 0
-#define EV_CURRENT 1
-
-/* Values for e_ident[EI_CLASS]. */
-#define ELFCLASSNONE 0 /* Unknown class. */
-#define ELFCLASS32 1 /* 32-bit architecture. */
-#define ELFCLASS64 2 /* 64-bit architecture. */
-
-/* Values for e_ident[EI_DATA]. */
-#define ELFDATANONE 0 /* Unknown data format. */
-#define ELFDATA2LSB 1 /* 2's complement little-endian. */
-#define ELFDATA2MSB 2 /* 2's complement big-endian. */
-
-/* Values for e_ident[EI_OSABI]. */
-#define ELFOSABI_NONE 0 /* UNIX System V ABI */
-#define ELFOSABI_HPUX 1 /* HP-UX operating system */
-#define ELFOSABI_NETBSD 2 /* NetBSD */
-#define ELFOSABI_LINUX 3 /* GNU/Linux */
-#define ELFOSABI_HURD 4 /* GNU/Hurd */
-#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */
-#define ELFOSABI_SOLARIS 6 /* Solaris */
-#define ELFOSABI_AIX 7 /* AIX */
-#define ELFOSABI_IRIX 8 /* IRIX */
-#define ELFOSABI_FREEBSD 9 /* FreeBSD */
-#define ELFOSABI_TRU64 10 /* TRU64 UNIX */
-#define ELFOSABI_MODESTO 11 /* Novell Modesto */
-#define ELFOSABI_OPENBSD 12 /* OpenBSD */
-#define ELFOSABI_OPENVMS 13 /* Open VMS */
-#define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */
-#define ELFOSABI_ARM 97 /* ARM */
-#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
-
-#define ELFOSABI_SYSV ELFOSABI_NONE /* symbol used in old spec */
-#define ELFOSABI_MONTEREY ELFOSABI_AIX /* Monterey */
-
-/* e_ident */
-#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
- (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
- (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
- (ehdr).e_ident[EI_MAG3] == ELFMAG3)
-
-/* Values for e_type. */
-#define ET_NONE 0 /* Unknown type. */
-#define ET_REL 1 /* Relocatable. */
-#define ET_EXEC 2 /* Executable. */
-#define ET_DYN 3 /* Shared object. */
-#define ET_CORE 4 /* Core file. */
-#define ET_LOOS 0xfe00 /* First operating system specific. */
-#define ET_HIOS 0xfeff /* Last operating system-specific. */
-#define ET_LOPROC 0xff00 /* First processor-specific. */
-#define ET_HIPROC 0xffff /* Last processor-specific. */
-
-/* Values for e_machine. */
-#define EM_NONE 0 /* Unknown machine. */
-#define EM_M32 1 /* AT&T WE32100. */
-#define EM_SPARC 2 /* Sun SPARC. */
-#define EM_386 3 /* Intel i386. */
-#define EM_68K 4 /* Motorola 68000. */
-#define EM_88K 5 /* Motorola 88000. */
-#define EM_860 7 /* Intel i860. */
-#define EM_MIPS 8 /* MIPS R3000 Big-Endian only. */
-#define EM_S370 9 /* IBM System/370. */
-#define EM_MIPS_RS3_LE 10 /* MIPS R3000 Little-Endian. */
-#define EM_PARISC 15 /* HP PA-RISC. */
-#define EM_VPP500 17 /* Fujitsu VPP500. */
-#define EM_SPARC32PLUS 18 /* SPARC v8plus. */
-#define EM_960 19 /* Intel 80960. */
-#define EM_PPC 20 /* PowerPC 32-bit. */
-#define EM_PPC64 21 /* PowerPC 64-bit. */
-#define EM_S390 22 /* IBM System/390. */
-#define EM_V800 36 /* NEC V800. */
-#define EM_FR20 37 /* Fujitsu FR20. */
-#define EM_RH32 38 /* TRW RH-32. */
-#define EM_RCE 39 /* Motorola RCE. */
-#define EM_ARM 40 /* ARM. */
-#define EM_SH 42 /* Hitachi SH. */
-#define EM_SPARCV9 43 /* SPARC v9 64-bit. */
-#define EM_TRICORE 44 /* Siemens TriCore embedded processor. */
-#define EM_ARC 45 /* Argonaut RISC Core. */
-#define EM_H8_300 46 /* Hitachi H8/300. */
-#define EM_H8_300H 47 /* Hitachi H8/300H. */
-#define EM_H8S 48 /* Hitachi H8S. */
-#define EM_H8_500 49 /* Hitachi H8/500. */
-#define EM_IA_64 50 /* Intel IA-64 Processor. */
-#define EM_MIPS_X 51 /* Stanford MIPS-X. */
-#define EM_COLDFIRE 52 /* Motorola ColdFire. */
-#define EM_68HC12 53 /* Motorola M68HC12. */
-#define EM_MMA 54 /* Fujitsu MMA. */
-#define EM_PCP 55 /* Siemens PCP. */
-#define EM_NCPU 56 /* Sony nCPU. */
-#define EM_NDR1 57 /* Denso NDR1 microprocessor. */
-#define EM_STARCORE 58 /* Motorola Star*Core processor. */
-#define EM_ME16 59 /* Toyota ME16 processor. */
-#define EM_ST100 60 /* STMicroelectronics ST100 processor. */
-#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */
-#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */
-
-/* Non-standard or deprecated. */
-#define EM_486 6 /* Intel i486. */
-#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */
-#define EM_ALPHA_STD 41 /* Digital Alpha (standard value). */
-#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI) */
-
-/* Special section indexes. */
-#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */
-#define SHN_LORESERVE 0xff00 /* First of reserved range. */
-#define SHN_LOPROC 0xff00 /* First processor-specific. */
-#define SHN_HIPROC 0xff1f /* Last processor-specific. */
-#define SHN_LOOS 0xff20 /* First operating system-specific. */
-#define SHN_HIOS 0xff3f /* Last operating system-specific. */
-#define SHN_ABS 0xfff1 /* Absolute values. */
-#define SHN_COMMON 0xfff2 /* Common data. */
-#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */
-#define SHN_HIRESERVE 0xffff /* Last of reserved range. */
-
-/* sh_type */
-#define SHT_NULL 0 /* inactive */
-#define SHT_PROGBITS 1 /* program defined information */
-#define SHT_SYMTAB 2 /* symbol table section */
-#define SHT_STRTAB 3 /* string table section */
-#define SHT_RELA 4 /* relocation section with addends */
-#define SHT_HASH 5 /* symbol hash table section */
-#define SHT_DYNAMIC 6 /* dynamic section */
-#define SHT_NOTE 7 /* note section */
-#define SHT_NOBITS 8 /* no space section */
-#define SHT_REL 9 /* relocation section - no addends */
-#define SHT_SHLIB 10 /* reserved - purpose unknown */
-#define SHT_DYNSYM 11 /* dynamic symbol table section */
-#define SHT_INIT_ARRAY 14 /* Initialization function pointers. */
-#define SHT_FINI_ARRAY 15 /* Termination function pointers. */
-#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */
-#define SHT_GROUP 17 /* Section group. */
-#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */
-#define SHT_LOOS 0x60000000 /* First of OS specific semantics */
-#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */
-#define SHT_GNU_VERDEF 0x6ffffffd
-#define SHT_GNU_VERNEED 0x6ffffffe
-#define SHT_GNU_VERSYM 0x6fffffff
-#define SHT_LOPROC 0x70000000 /* reserved range for processor */
-#define SHT_HIPROC 0x7fffffff /* specific section header types */
-#define SHT_LOUSER 0x80000000 /* reserved range for application */
-#define SHT_HIUSER 0xffffffff /* specific indexes */
-
-/* Flags for sh_flags. */
-#define SHF_WRITE 0x1 /* Section contains writable data. */
-#define SHF_ALLOC 0x2 /* Section occupies memory. */
-#define SHF_EXECINSTR 0x4 /* Section contains instructions. */
-#define SHF_MERGE 0x10 /* Section may be merged. */
-#define SHF_STRINGS 0x20 /* Section contains strings. */
-#define SHF_INFO_LINK 0x40 /* sh_info holds section index. */
-#define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */
-#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */
-#define SHF_GROUP 0x200 /* Member of section group. */
-#define SHF_TLS 0x400 /* Section contains TLS data. */
-#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */
-#define SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */
-
-/* Values for p_type. */
-#define PT_NULL 0 /* Unused entry. */
-#define PT_LOAD 1 /* Loadable segment. */
-#define PT_DYNAMIC 2 /* Dynamic linking information segment. */
-#define PT_INTERP 3 /* Pathname of interpreter. */
-#define PT_NOTE 4 /* Auxiliary information. */
-#define PT_SHLIB 5 /* Reserved (not used). */
-#define PT_PHDR 6 /* Location of program header itself. */
-#define PT_TLS 7 /* Thread local storage segment */
-#define PT_LOOS 0x60000000 /* First OS-specific. */
-#define PT_HIOS 0x6fffffff /* Last OS-specific. */
-#define PT_LOPROC 0x70000000 /* First processor-specific type. */
-#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */
-#define PT_GNU_STACK 0x6474e551
-
-/* Values for p_flags. */
-#define PF_X 0x1 /* Executable. */
-#define PF_W 0x2 /* Writable. */
-#define PF_R 0x4 /* Readable. */
-#define PF_MASKOS 0x0ff00000 /* Operating system-specific. */
-#define PF_MASKPROC 0xf0000000 /* Processor-specific. */
-
-/* Values for d_tag. */
-#define DT_NULL 0 /* Terminating entry. */
-/* String table offset of a needed shared library. */
-#define DT_NEEDED 1
-#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */
-#define DT_PLTGOT 3 /* Processor-dependent address. */
-#define DT_HASH 4 /* Address of symbol hash table. */
-#define DT_STRTAB 5 /* Address of string table. */
-#define DT_SYMTAB 6 /* Address of symbol table. */
-#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */
-#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */
-#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */
-#define DT_STRSZ 10 /* Size of string table. */
-#define DT_SYMENT 11 /* Size of each symbol table entry. */
-#define DT_INIT 12 /* Address of initialization function. */
-#define DT_FINI 13 /* Address of finalization function. */
-/* String table offset of shared object name. */
-#define DT_SONAME 14
-#define DT_RPATH 15 /* String table offset of library path. [sup] */
-#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */
-#define DT_REL 17 /* Address of ElfNN_Rel relocations. */
-#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */
-#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */
-#define DT_PLTREL 20 /* Type of relocation used for PLT. */
-#define DT_DEBUG 21 /* Reserved (not used). */
-/* Indicates there may be relocations in non-writable segments. [sup] */
-#define DT_TEXTREL 22
-#define DT_JMPREL 23 /* Address of PLT relocations. */
-#define DT_BIND_NOW 24 /* [sup] */
-/* Address of the array of pointers to initialization functions */
-#define DT_INIT_ARRAY 25
-/* Address of the array of pointers to termination functions */
-#define DT_FINI_ARRAY 26
-/* Size in bytes of the array of initialization functions. */
-#define DT_INIT_ARRAYSZ 27
-/* Size in bytes of the array of terminationfunctions. */
-#define DT_FINI_ARRAYSZ 28
-/* String table offset of a null-terminated library search path string. */
-#define DT_RUNPATH 29
-#define DT_FLAGS 30 /* Object specific flag values. */
-/* Values greater than or equal to DT_ENCODING and less than
- DT_LOOS follow the rules for the interpretation of the d_un
- union as follows: even == 'd_ptr', even == 'd_val' or none */
-#define DT_ENCODING 32
-/* Address of the array of pointers to pre-initialization functions. */
-#define DT_PREINIT_ARRAY 32
-/* Size in bytes of the array of pre-initialization functions. */
-#define DT_PREINIT_ARRAYSZ 33
-#define DT_LOOS 0x6000000d /* First OS-specific */
-#define DT_HIOS 0x6ffff000 /* Last OS-specific */
-#define DT_LOPROC 0x70000000 /* First processor-specific type. */
-#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */
-
-#define DT_VERNEED 0x6ffffffe
-#define DT_VERNEEDNUM 0x6fffffff
-#define DT_VERSYM 0x6ffffff0
-
-/* Values for DT_FLAGS */
-/* Indicates that the object being loaded may make reference to
- the $ORIGIN substitution string */
-#define DF_ORIGIN 0x0001
-#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */
-/* Indicates there may be relocations in non-writable segments. */
-#define DF_TEXTREL 0x0004
-/* Indicates that the dynamic linker should process all
- relocations for the object containing this entry before
- transferring control to the program. */
-#define DF_BIND_NOW 0x0008
-/* Indicates that the shared object or executable contains code
- using a static thread-local storage scheme. */
-#define DF_STATIC_TLS 0x0010
-
-/* Values for n_type. Used in core files. */
-#define NT_PRSTATUS 1 /* Process status. */
-#define NT_FPREGSET 2 /* Floating point registers. */
-#define NT_PRPSINFO 3 /* Process state info. */
-
-/* Symbol Binding - ELFNN_ST_BIND - st_info */
-#define STB_LOCAL 0 /* Local symbol */
-#define STB_GLOBAL 1 /* Global symbol */
-#define STB_WEAK 2 /* like global - lower precedence */
-#define STB_LOOS 10 /* Reserved range for operating system */
-#define STB_HIOS 12 /* specific semantics. */
-#define STB_LOPROC 13 /* reserved range for processor */
-#define STB_HIPROC 15 /* specific semantics. */
-
-/* Symbol type - ELFNN_ST_TYPE - st_info */
-#define STT_NOTYPE 0 /* Unspecified type. */
-#define STT_OBJECT 1 /* Data object. */
-#define STT_FUNC 2 /* Function. */
-#define STT_SECTION 3 /* Section. */
-#define STT_FILE 4 /* Source file. */
-#define STT_COMMON 5 /* Uninitialized common block. */
-#define STT_TLS 6 /* TLS object. */
-#define STT_LOOS 10 /* Reserved range for operating system */
-#define STT_HIOS 12 /* specific semantics. */
-#define STT_LOPROC 13 /* reserved range for processor */
-#define STT_HIPROC 15 /* specific semantics. */
-
-/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */
-#define STV_DEFAULT 0x0 /* Default visibility (see binding). */
-#define STV_INTERNAL 0x1 /* Special meaning in relocatable objects. */
-#define STV_HIDDEN 0x2 /* Not visible. */
-#define STV_PROTECTED 0x3 /* Visible but not preemptible. */
-
-/* Special symbol table indexes. */
-#define STN_UNDEF 0 /* Undefined symbol index. */
-
-/*
- * ELF definitions common to all 32-bit architectures.
- */
-
-typedef uint32 Elf32_Addr;
-typedef uint16 Elf32_Half;
-typedef uint32 Elf32_Off;
-typedef int32 Elf32_Sword;
-typedef uint32 Elf32_Word;
-
-typedef Elf32_Word Elf32_Hashelt;
-
-/* Non-standard class-dependent datatype used for abstraction. */
-typedef Elf32_Word Elf32_Size;
-typedef Elf32_Sword Elf32_Ssize;
-
-/*
- * ELF header.
- */
-
-typedef struct {
- unsigned char ident[EI_NIDENT]; /* File identification. */
- Elf32_Half type; /* File type. */
- Elf32_Half machine; /* Machine architecture. */
- Elf32_Word version; /* ELF format version. */
- Elf32_Addr entry; /* Entry point. */
- Elf32_Off phoff; /* Program header file offset. */
- Elf32_Off shoff; /* Section header file offset. */
- Elf32_Word flags; /* Architecture-specific flags. */
- Elf32_Half ehsize; /* Size of ELF header in bytes. */
- Elf32_Half phentsize; /* Size of program header entry. */
- Elf32_Half phnum; /* Number of program header entries. */
- Elf32_Half shentsize; /* Size of section header entry. */
- Elf32_Half shnum; /* Number of section header entries. */
- Elf32_Half shstrndx; /* Section name strings section. */
-} Elf32_Ehdr;
-
-/*
- * Section header.
- */
-
-typedef struct {
- Elf32_Word name; /* Section name (index into the
- section header string table). */
- Elf32_Word type; /* Section type. */
- Elf32_Word flags; /* Section flags. */
- Elf32_Addr vaddr; /* Address in memory image. */
- Elf32_Off off; /* Offset in file. */
- Elf32_Word size; /* Size in bytes. */
- Elf32_Word link; /* Index of a related section. */
- Elf32_Word info; /* Depends on section type. */
- Elf32_Word addralign; /* Alignment in bytes. */
- Elf32_Word entsize; /* Size of each entry in section. */
-} Elf32_Shdr;
-
-/*
- * Program header.
- */
-
-typedef struct {
- Elf32_Word type; /* Entry type. */
- Elf32_Off off; /* File offset of contents. */
- Elf32_Addr vaddr; /* Virtual address in memory image. */
- Elf32_Addr paddr; /* Physical address (not used). */
- Elf32_Word filesz; /* Size of contents in file. */
- Elf32_Word memsz; /* Size of contents in memory. */
- Elf32_Word flags; /* Access permission flags. */
- Elf32_Word align; /* Alignment in memory and file. */
-} Elf32_Phdr;
-
-/*
- * Dynamic structure. The ".dynamic" section contains an array of them.
- */
-
-typedef struct {
- Elf32_Sword d_tag; /* Entry type. */
- union {
- Elf32_Word d_val; /* Integer value. */
- Elf32_Addr d_ptr; /* Address value. */
- } d_un;
-} Elf32_Dyn;
-
-/*
- * Relocation entries.
- */
-
-/* Relocations that don't need an addend field. */
-typedef struct {
- Elf32_Addr off; /* Location to be relocated. */
- Elf32_Word info; /* Relocation type and symbol index. */
-} Elf32_Rel;
-
-/* Relocations that need an addend field. */
-typedef struct {
- Elf32_Addr off; /* Location to be relocated. */
- Elf32_Word info; /* Relocation type and symbol index. */
- Elf32_Sword addend; /* Addend. */
-} Elf32_Rela;
-
-/* Macros for accessing the fields of r_info. */
-#define ELF32_R_SYM(info) ((info) >> 8)
-#define ELF32_R_TYPE(info) ((unsigned char)(info))
-
-/* Macro for constructing r_info from field values. */
-#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type))
-
-/*
- * Relocation types.
- */
-
-#define R_X86_64_NONE 0 /* No relocation. */
-#define R_X86_64_64 1 /* Add 64 bit symbol value. */
-#define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */
-#define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */
-#define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */
-#define R_X86_64_COPY 5 /* Copy data from shared object. */
-#define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */
-#define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */
-#define R_X86_64_RELATIVE 8 /* Add load address of shared object. */
-#define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */
-#define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */
-#define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */
-#define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */
-#define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */
-#define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */
-#define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */
-#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
-#define R_X86_64_DTPOFF64 17 /* Offset in TLS block */
-#define R_X86_64_TPOFF64 18 /* Offset in static TLS block */
-#define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */
-#define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */
-#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
-#define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */
-#define R_X86_64_TPOFF32 23 /* Offset in static TLS block */
-
-#define R_X86_64_COUNT 24 /* Count of defined relocation types. */
-
-
-#define R_ALPHA_NONE 0 /* No reloc */
-#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
-#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
-#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
-#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
-#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
-#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
-#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
-#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
-#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
-#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
-#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
-#define R_ALPHA_OP_PUSH 12 /* OP stack push */
-#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */
-#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */
-#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */
-#define R_ALPHA_GPVALUE 16
-#define R_ALPHA_GPRELHIGH 17
-#define R_ALPHA_GPRELLOW 18
-#define R_ALPHA_IMMED_GP_16 19
-#define R_ALPHA_IMMED_GP_HI32 20
-#define R_ALPHA_IMMED_SCN_HI32 21
-#define R_ALPHA_IMMED_BR_HI32 22
-#define R_ALPHA_IMMED_LO32 23
-#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
-#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
-#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
-#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
-
-#define R_ALPHA_COUNT 28
-
-
-#define R_ARM_NONE 0 /* No relocation. */
-#define R_ARM_PC24 1
-#define R_ARM_ABS32 2
-#define R_ARM_REL32 3
-#define R_ARM_PC13 4
-#define R_ARM_ABS16 5
-#define R_ARM_ABS12 6
-#define R_ARM_THM_ABS5 7
-#define R_ARM_ABS8 8
-#define R_ARM_SBREL32 9
-#define R_ARM_THM_PC22 10
-#define R_ARM_THM_PC8 11
-#define R_ARM_AMP_VCALL9 12
-#define R_ARM_SWI24 13
-#define R_ARM_THM_SWI8 14
-#define R_ARM_XPC25 15
-#define R_ARM_THM_XPC22 16
-#define R_ARM_COPY 20 /* Copy data from shared object. */
-#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */
-#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */
-#define R_ARM_RELATIVE 23 /* Add load address of shared object. */
-#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */
-#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */
-#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */
-#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */
-#define R_ARM_GNU_VTENTRY 100
-#define R_ARM_GNU_VTINHERIT 101
-#define R_ARM_RSBREL32 250
-#define R_ARM_THM_RPC22 251
-#define R_ARM_RREL32 252
-#define R_ARM_RABS32 253
-#define R_ARM_RPC24 254
-#define R_ARM_RBASE 255
-
-#define R_ARM_COUNT 33 /* Count of defined relocation types. */
-
-
-#define R_386_NONE 0 /* No relocation. */
-#define R_386_32 1 /* Add symbol value. */
-#define R_386_PC32 2 /* Add PC-relative symbol value. */
-#define R_386_GOT32 3 /* Add PC-relative GOT offset. */
-#define R_386_PLT32 4 /* Add PC-relative PLT offset. */
-#define R_386_COPY 5 /* Copy data from shared object. */
-#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */
-#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */
-#define R_386_RELATIVE 8 /* Add load address of shared object. */
-#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */
-#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */
-#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */
-#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */
-#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */
-#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */
-#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */
-#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */
-#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */
-#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */
-#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */
-#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */
-#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */
-#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */
-#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */
-#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */
-#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */
-#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */
-#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */
-#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */
-#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */
-#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */
-
-#define R_386_COUNT 38 /* Count of defined relocation types. */
-
-#define R_PPC_NONE 0 /* No relocation. */
-#define R_PPC_ADDR32 1
-#define R_PPC_ADDR24 2
-#define R_PPC_ADDR16 3
-#define R_PPC_ADDR16_LO 4
-#define R_PPC_ADDR16_HI 5
-#define R_PPC_ADDR16_HA 6
-#define R_PPC_ADDR14 7
-#define R_PPC_ADDR14_BRTAKEN 8
-#define R_PPC_ADDR14_BRNTAKEN 9
-#define R_PPC_REL24 10
-#define R_PPC_REL14 11
-#define R_PPC_REL14_BRTAKEN 12
-#define R_PPC_REL14_BRNTAKEN 13
-#define R_PPC_GOT16 14
-#define R_PPC_GOT16_LO 15
-#define R_PPC_GOT16_HI 16
-#define R_PPC_GOT16_HA 17
-#define R_PPC_PLTREL24 18
-#define R_PPC_COPY 19
-#define R_PPC_GLOB_DAT 20
-#define R_PPC_JMP_SLOT 21
-#define R_PPC_RELATIVE 22
-#define R_PPC_LOCAL24PC 23
-#define R_PPC_UADDR32 24
-#define R_PPC_UADDR16 25
-#define R_PPC_REL32 26
-#define R_PPC_PLT32 27
-#define R_PPC_PLTREL32 28
-#define R_PPC_PLT16_LO 29
-#define R_PPC_PLT16_HI 30
-#define R_PPC_PLT16_HA 31
-#define R_PPC_SDAREL16 32
-#define R_PPC_SECTOFF 33
-#define R_PPC_SECTOFF_LO 34
-#define R_PPC_SECTOFF_HI 35
-#define R_PPC_SECTOFF_HA 36
-
-#define R_PPC_COUNT 37 /* Count of defined relocation types. */
-
-#define R_PPC_TLS 67
-#define R_PPC_DTPMOD32 68
-#define R_PPC_TPREL16 69
-#define R_PPC_TPREL16_LO 70
-#define R_PPC_TPREL16_HI 71
-#define R_PPC_TPREL16_HA 72
-#define R_PPC_TPREL32 73
-#define R_PPC_DTPREL16 74
-#define R_PPC_DTPREL16_LO 75
-#define R_PPC_DTPREL16_HI 76
-#define R_PPC_DTPREL16_HA 77
-#define R_PPC_DTPREL32 78
-#define R_PPC_GOT_TLSGD16 79
-#define R_PPC_GOT_TLSGD16_LO 80
-#define R_PPC_GOT_TLSGD16_HI 81
-#define R_PPC_GOT_TLSGD16_HA 82
-#define R_PPC_GOT_TLSLD16 83
-#define R_PPC_GOT_TLSLD16_LO 84
-#define R_PPC_GOT_TLSLD16_HI 85
-#define R_PPC_GOT_TLSLD16_HA 86
-#define R_PPC_GOT_TPREL16 87
-#define R_PPC_GOT_TPREL16_LO 88
-#define R_PPC_GOT_TPREL16_HI 89
-#define R_PPC_GOT_TPREL16_HA 90
-
-#define R_PPC_EMB_NADDR32 101
-#define R_PPC_EMB_NADDR16 102
-#define R_PPC_EMB_NADDR16_LO 103
-#define R_PPC_EMB_NADDR16_HI 104
-#define R_PPC_EMB_NADDR16_HA 105
-#define R_PPC_EMB_SDAI16 106
-#define R_PPC_EMB_SDA2I16 107
-#define R_PPC_EMB_SDA2REL 108
-#define R_PPC_EMB_SDA21 109
-#define R_PPC_EMB_MRKREF 110
-#define R_PPC_EMB_RELSEC16 111
-#define R_PPC_EMB_RELST_LO 112
-#define R_PPC_EMB_RELST_HI 113
-#define R_PPC_EMB_RELST_HA 114
-#define R_PPC_EMB_BIT_FLD 115
-#define R_PPC_EMB_RELSDA 116
-
- /* Count of defined relocation types. */
-#define R_PPC_EMB_COUNT (R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1)
-
-
-#define R_SPARC_NONE 0
-#define R_SPARC_8 1
-#define R_SPARC_16 2
-#define R_SPARC_32 3
-#define R_SPARC_DISP8 4
-#define R_SPARC_DISP16 5
-#define R_SPARC_DISP32 6
-#define R_SPARC_WDISP30 7
-#define R_SPARC_WDISP22 8
-#define R_SPARC_HI22 9
-#define R_SPARC_22 10
-#define R_SPARC_13 11
-#define R_SPARC_LO10 12
-#define R_SPARC_GOT10 13
-#define R_SPARC_GOT13 14
-#define R_SPARC_GOT22 15
-#define R_SPARC_PC10 16
-#define R_SPARC_PC22 17
-#define R_SPARC_WPLT30 18
-#define R_SPARC_COPY 19
-#define R_SPARC_GLOB_DAT 20
-#define R_SPARC_JMP_SLOT 21
-#define R_SPARC_RELATIVE 22
-#define R_SPARC_UA32 23
-#define R_SPARC_PLT32 24
-#define R_SPARC_HIPLT22 25
-#define R_SPARC_LOPLT10 26
-#define R_SPARC_PCPLT32 27
-#define R_SPARC_PCPLT22 28
-#define R_SPARC_PCPLT10 29
-#define R_SPARC_10 30
-#define R_SPARC_11 31
-#define R_SPARC_64 32
-#define R_SPARC_OLO10 33
-#define R_SPARC_HH22 34
-#define R_SPARC_HM10 35
-#define R_SPARC_LM22 36
-#define R_SPARC_PC_HH22 37
-#define R_SPARC_PC_HM10 38
-#define R_SPARC_PC_LM22 39
-#define R_SPARC_WDISP16 40
-#define R_SPARC_WDISP19 41
-#define R_SPARC_GLOB_JMP 42
-#define R_SPARC_7 43
-#define R_SPARC_5 44
-#define R_SPARC_6 45
-#define R_SPARC_DISP64 46
-#define R_SPARC_PLT64 47
-#define R_SPARC_HIX22 48
-#define R_SPARC_LOX10 49
-#define R_SPARC_H44 50
-#define R_SPARC_M44 51
-#define R_SPARC_L44 52
-#define R_SPARC_REGISTER 53
-#define R_SPARC_UA64 54
-#define R_SPARC_UA16 55
-
-
-/*
- * Magic number for the elf trampoline, chosen wisely to be an immediate
- * value.
- */
-#define ARM_MAGIC_TRAMP_NUMBER 0x5c000003
-
-
-/*
- * Symbol table entries.
- */
-
-typedef struct {
- Elf32_Word name; /* String table index of name. */
- Elf32_Addr value; /* Symbol value. */
- Elf32_Word size; /* Size of associated object. */
- unsigned char info; /* Type and binding information. */
- unsigned char other; /* Reserved (not used). */
- Elf32_Half shndx; /* Section index of symbol. */
-} Elf32_Sym;
-
-/* Macros for accessing the fields of st_info. */
-#define ELF32_ST_BIND(info) ((info) >> 4)
-#define ELF32_ST_TYPE(info) ((info) & 0xf)
-
-/* Macro for constructing st_info from field values. */
-#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
-
-/* Macro for accessing the fields of st_other. */
-#define ELF32_ST_VISIBILITY(oth) ((oth) & 0x3)
-
-/*
- * ELF definitions common to all 64-bit architectures.
- */
-
-typedef uint64 Elf64_Addr;
-typedef uint16 Elf64_Half;
-typedef uint64 Elf64_Off;
-typedef int32 Elf64_Sword;
-typedef int64 Elf64_Sxword;
-typedef uint32 Elf64_Word;
-typedef uint64 Elf64_Xword;
-
-/*
- * Types of dynamic symbol hash table bucket and chain elements.
- *
- * This is inconsistent among 64 bit architectures, so a machine dependent
- * typedef is required.
- */
-
-#ifdef __alpha__
-typedef Elf64_Off Elf64_Hashelt;
-#else
-typedef Elf64_Word Elf64_Hashelt;
-#endif
-
-/* Non-standard class-dependent datatype used for abstraction. */
-typedef Elf64_Xword Elf64_Size;
-typedef Elf64_Sxword Elf64_Ssize;
-
-/*
- * ELF header.
- */
-
-typedef struct {
- unsigned char ident[EI_NIDENT]; /* File identification. */
- Elf64_Half type; /* File type. */
- Elf64_Half machine; /* Machine architecture. */
- Elf64_Word version; /* ELF format version. */
- Elf64_Addr entry; /* Entry point. */
- Elf64_Off phoff; /* Program header file offset. */
- Elf64_Off shoff; /* Section header file offset. */
- Elf64_Word flags; /* Architecture-specific flags. */
- Elf64_Half ehsize; /* Size of ELF header in bytes. */
- Elf64_Half phentsize; /* Size of program header entry. */
- Elf64_Half phnum; /* Number of program header entries. */
- Elf64_Half shentsize; /* Size of section header entry. */
- Elf64_Half shnum; /* Number of section header entries. */
- Elf64_Half shstrndx; /* Section name strings section. */
-} Elf64_Ehdr;
-
-/*
- * Section header.
- */
-
-typedef struct {
- Elf64_Word name; /* Section name (index into the
- section header string table). */
- Elf64_Word type; /* Section type. */
- Elf64_Xword flags; /* Section flags. */
- Elf64_Addr addr; /* Address in memory image. */
- Elf64_Off off; /* Offset in file. */
- Elf64_Xword size; /* Size in bytes. */
- Elf64_Word link; /* Index of a related section. */
- Elf64_Word info; /* Depends on section type. */
- Elf64_Xword addralign; /* Alignment in bytes. */
- Elf64_Xword entsize; /* Size of each entry in section. */
-} Elf64_Shdr;
-
-/*
- * Program header.
- */
-
-typedef struct {
- Elf64_Word type; /* Entry type. */
- Elf64_Word flags; /* Access permission flags. */
- Elf64_Off off; /* File offset of contents. */
- Elf64_Addr vaddr; /* Virtual address in memory image. */
- Elf64_Addr paddr; /* Physical address (not used). */
- Elf64_Xword filesz; /* Size of contents in file. */
- Elf64_Xword memsz; /* Size of contents in memory. */
- Elf64_Xword align; /* Alignment in memory and file. */
-} Elf64_Phdr;
-
-/*
- * Dynamic structure. The ".dynamic" section contains an array of them.
- */
-
-typedef struct {
- Elf64_Sxword d_tag; /* Entry type. */
- union {
- Elf64_Xword d_val; /* Integer value. */
- Elf64_Addr d_ptr; /* Address value. */
- } d_un;
-} Elf64_Dyn;
-
-/*
- * Relocation entries.
- */
-
-/* Relocations that don't need an addend field. */
-typedef struct {
- Elf64_Addr off; /* Location to be relocated. */
- Elf64_Xword info; /* Relocation type and symbol index. */
-} Elf64_Rel;
-
-/* Relocations that need an addend field. */
-typedef struct {
- Elf64_Addr off; /* Location to be relocated. */
- Elf64_Xword info; /* Relocation type and symbol index. */
- Elf64_Sxword addend; /* Addend. */
-} Elf64_Rela;
-
-/* Macros for accessing the fields of r_info. */
-#define ELF64_R_SYM(info) ((info) >> 32)
-#define ELF64_R_TYPE(info) ((info) & 0xffffffffL)
-
-/* Macro for constructing r_info from field values. */
-#define ELF64_R_INFO(sym, type) ((((uint64)(sym)) << 32) + (((uint64)(type)) & 0xffffffffULL))
-
-/*
- * Symbol table entries.
- */
-
-typedef struct {
- Elf64_Word name; /* String table index of name. */
- unsigned char info; /* Type and binding information. */
- unsigned char other; /* Reserved (not used). */
- Elf64_Half shndx; /* Section index of symbol. */
- Elf64_Addr value; /* Symbol value. */
- Elf64_Xword size; /* Size of associated object. */
-} Elf64_Sym;
-
-/* Macros for accessing the fields of st_info. */
-#define ELF64_ST_BIND(info) ((info) >> 4)
-#define ELF64_ST_TYPE(info) ((info) & 0xf)
-
-/* Macro for constructing st_info from field values. */
-#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
-
-/* Macro for accessing the fields of st_other. */
-#define ELF64_ST_VISIBILITY(oth) ((oth) & 0x3)
-
-/*
- * Go linker interface
- */
-
-#define ELF64HDRSIZE 64
-#define ELF64PHDRSIZE 56
-#define ELF64SHDRSIZE 64
-#define ELF64RELSIZE 16
-#define ELF64RELASIZE 24
-#define ELF64SYMSIZE sizeof(Elf64_Sym)
-
-#define ELF32HDRSIZE sizeof(Elf32_Ehdr)
-#define ELF32PHDRSIZE sizeof(Elf32_Phdr)
-#define ELF32SHDRSIZE sizeof(Elf32_Shdr)
-#define ELF32SYMSIZE sizeof(Elf32_Sym)
-#define ELF32RELSIZE 8
-
-/*
- * The interface uses the 64-bit structures always,
- * to avoid code duplication. The writers know how to
- * marshal a 32-bit representation from the 64-bit structure.
- */
-typedef Elf64_Ehdr ElfEhdr;
-typedef Elf64_Shdr ElfShdr;
-typedef Elf64_Phdr ElfPhdr;
-
-void elfinit(void);
-ElfEhdr *getElfEhdr(void);
-ElfShdr *newElfShstrtab(vlong);
-ElfShdr *newElfShdr(vlong);
-ElfPhdr *newElfPhdr(void);
-uint32 elfwritehdr(void);
-uint32 elfwritephdrs(void);
-uint32 elfwriteshdrs(void);
-void elfwritedynent(Sym*, int, uint64);
-void elfwritedynentsym(Sym*, int, Sym*);
-void elfwritedynentsymsize(Sym*, int, Sym*);
-uint32 elfhash(uchar*);
-uint64 startelf(void);
-uint64 endelf(void);
-extern int numelfphdr;
-extern int numelfshdr;
-extern int iself;
-extern int elfverneed;
-int elfwriteinterp(void);
-void elfinterp(ElfShdr*, uint64, char*);
-void elfdynhash(void);
-ElfPhdr* elfphload(Segment*);
-ElfShdr* elfshbits(Section*);
-void elfsetstring(char*, int);
-void elfaddverneed(Sym*);
-
-EXTERN int elfstrsize;
-EXTERN char* elfstrdat;
-EXTERN int elftextsh;
-
-/*
- * Total amount of space to reserve at the start of the file
- * for Header, PHeaders, SHeaders, and interp.
- * May waste some.
- * On FreeBSD, cannot be larger than a page.
- */
-#define ELFRESERVE 3072
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
deleted file mode 100644
index 05d1cc136..000000000
--- a/src/cmd/ld/go.c
+++ /dev/null
@@ -1,710 +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.
-
-// go-specific code shared across loaders (5l, 6l, 8l).
-
-#include "l.h"
-#include "../ld/lib.h"
-
-// accumulate all type information from .6 files.
-// check for inconsistencies.
-
-// TODO:
-// generate debugging section in binary.
-// once the dust settles, try to move some code to
-// libmach, so that other linkers and ar can share.
-
-/*
- * package import data
- */
-typedef struct Import Import;
-struct Import
-{
- Import *hash; // next in hash table
- char *prefix; // "type", "var", "func", "const"
- char *name;
- char *def;
- char *file;
-};
-enum {
- NIHASH = 1024
-};
-static Import *ihash[NIHASH];
-static int nimport;
-
-static int
-hashstr(char *name)
-{
- int h;
- char *cp;
-
- h = 0;
- for(cp = name; *cp; h += *cp++)
- h *= 1119;
- // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
- h &= 0xffffff;
- return h;
-}
-
-static Import *
-ilookup(char *name)
-{
- int h;
- Import *x;
-
- h = hashstr(name) % NIHASH;
- for(x=ihash[h]; x; x=x->hash)
- if(x->name[0] == name[0] && strcmp(x->name, name) == 0)
- return x;
- x = mal(sizeof *x);
- x->name = strdup(name);
- x->hash = ihash[h];
- ihash[h] = x;
- nimport++;
- return x;
-}
-
-static void loadpkgdata(char*, char*, char*, int);
-static void loaddynimport(char*, char*, char*, int);
-static void loaddynexport(char*, char*, char*, int);
-static int parsemethod(char**, char*, char**);
-static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
-
-static Sym **dynexp;
-
-void
-ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
-{
- char *data, *p0, *p1, *name;
-
- if(debug['g'])
- return;
-
- if((int)len != len) {
- fprint(2, "%s: too much pkg data in %s\n", argv0, filename);
- if(debug['u'])
- errorexit();
- return;
- }
- data = mal(len+1);
- if(Bread(f, data, len) != len) {
- fprint(2, "%s: short pkg read %s\n", argv0, filename);
- if(debug['u'])
- errorexit();
- return;
- }
- data[len] = '\0';
-
- // first \n$$ marks beginning of exports - skip rest of line
- p0 = strstr(data, "\n$$");
- if(p0 == nil) {
- if(debug['u'] && whence != ArchiveObj) {
- fprint(2, "%s: cannot find export data in %s\n", argv0, filename);
- errorexit();
- }
- return;
- }
- p0 += 3;
- while(*p0 != '\n' && *p0 != '\0')
- p0++;
-
- // second marks end of exports / beginning of local data
- p1 = strstr(p0, "\n$$");
- if(p1 == nil) {
- fprint(2, "%s: cannot find end of exports in %s\n", argv0, filename);
- if(debug['u'])
- errorexit();
- return;
- }
- while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n'))
- p0++;
- if(p0 < p1) {
- if(strncmp(p0, "package ", 8) != 0) {
- fprint(2, "%s: bad package section in %s - %s\n", argv0, filename, p0);
- if(debug['u'])
- errorexit();
- return;
- }
- p0 += 8;
- while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n'))
- p0++;
- name = p0;
- while(p0 < p1 && *p0 != ' ' && *p0 != '\t' && *p0 != '\n')
- p0++;
- if(debug['u'] && whence != ArchiveObj &&
- (p0+6 > p1 || memcmp(p0, " safe\n", 6) != 0)) {
- fprint(2, "%s: load of unsafe package %s\n", argv0, filename);
- nerrors++;
- errorexit();
- }
- if(p0 < p1) {
- if(*p0 == '\n')
- *p0++ = '\0';
- else {
- *p0++ = '\0';
- while(p0 < p1 && *p0++ != '\n')
- ;
- }
- }
- if(strcmp(pkg, "main") == 0 && strcmp(name, "main") != 0)
- fprint(2, "%s: %s: not package main (package %s)\n", argv0, filename, name);
- loadpkgdata(filename, pkg, p0, p1 - p0);
- }
-
- // The __.PKGDEF archive summary has no local types.
- if(whence == Pkgdef)
- return;
-
- // local types begin where exports end.
- // skip rest of line after $$ we found above
- p0 = p1 + 3;
- while(*p0 != '\n' && *p0 != '\0')
- p0++;
-
- // local types end at next \n$$.
- p1 = strstr(p0, "\n$$");
- if(p1 == nil) {
- fprint(2, "%s: cannot find end of local types in %s\n", argv0, filename);
- if(debug['u'])
- errorexit();
- return;
- }
-
- loadpkgdata(filename, pkg, p0, p1 - p0);
-
- // look for dynimport section
- p0 = strstr(p1, "\n$$ // dynimport");
- if(p0 != nil) {
- p0 = strchr(p0+1, '\n');
- if(p0 == nil) {
- fprint(2, "%s: found $$ // dynimport but no newline in %s\n", argv0, filename);
- if(debug['u'])
- errorexit();
- return;
- }
- p1 = strstr(p0, "\n$$");
- if(p1 == nil)
- p1 = strstr(p0, "\n!\n");
- if(p1 == nil) {
- fprint(2, "%s: cannot find end of // dynimport section in %s\n", argv0, filename);
- if(debug['u'])
- errorexit();
- return;
- }
- loaddynimport(filename, pkg, p0 + 1, p1 - (p0+1));
- }
-
- // look for dynexp section
- p0 = strstr(p1, "\n$$ // dynexport");
- if(p0 != nil) {
- p0 = strchr(p0+1, '\n');
- if(p0 == nil) {
- fprint(2, "%s: found $$ // dynexporg but no newline in %s\n", argv0, filename);
- if(debug['u'])
- errorexit();
- return;
- }
- p1 = strstr(p0, "\n$$");
- if(p1 == nil)
- p1 = strstr(p0, "\n!\n");
- if(p1 == nil) {
- fprint(2, "%s: cannot find end of // dynexporg section in %s\n", argv0, filename);
- if(debug['u'])
- errorexit();
- return;
- }
- loaddynexport(filename, pkg, p0 + 1, p1 - (p0+1));
- }
-}
-
-static void
-loadpkgdata(char *file, char *pkg, char *data, int len)
-{
- char *p, *ep, *prefix, *name, *def;
- Import *x;
-
- file = strdup(file);
- p = data;
- ep = data + len;
- while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) {
- x = ilookup(name);
- if(x->prefix == nil) {
- x->prefix = prefix;
- x->def = def;
- x->file = file;
- } else if(strcmp(x->prefix, prefix) != 0) {
- fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
- fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name);
- fprint(2, "%s:\t%s %s ...\n", file, prefix, name);
- nerrors++;
- } else if(strcmp(x->def, def) != 0) {
- fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
- fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def);
- fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def);
- nerrors++;
- }
- }
-}
-
-// replace all "". with pkg.
-char*
-expandpkg(char *t0, char *pkg)
-{
- int n;
- char *p;
- char *w, *w0, *t;
-
- n = 0;
- for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3)
- n++;
-
- if(n == 0)
- return t0;
-
- // use malloc, not mal, so that caller can free
- w0 = malloc(strlen(t0) + strlen(pkg)*n);
- if(w0 == nil) {
- diag("out of memory");
- errorexit();
- }
- w = w0;
- for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) {
- memmove(w, t, p - t);
- w += p-t;
- strcpy(w, pkg);
- w += strlen(pkg);
- t = p+2;
- }
- strcpy(w, t);
- return w0;
-}
-
-static int
-parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp)
-{
- char *p, *prefix, *name, *def, *edef, *meth;
- int n, inquote;
-
- // skip white space
- p = *pp;
-loop:
- while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n'))
- p++;
- if(p == ep || strncmp(p, "$$\n", 3) == 0)
- return 0;
-
- // prefix: (var|type|func|const)
- prefix = p;
- if(p + 7 > ep)
- return -1;
- if(strncmp(p, "var ", 4) == 0)
- p += 4;
- else if(strncmp(p, "type ", 5) == 0)
- p += 5;
- else if(strncmp(p, "func ", 5) == 0)
- p += 5;
- else if(strncmp(p, "const ", 6) == 0)
- p += 6;
- else if(strncmp(p, "import ", 7) == 0) {
- p += 7;
- while(p < ep && *p != '\n')
- p++;
- goto loop;
- }
- else {
- fprint(2, "%s: confused in pkg data near <<%.40s>>\n", argv0, prefix);
- nerrors++;
- return -1;
- }
- p[-1] = '\0';
-
- // name: a.b followed by space
- name = p;
- inquote = 0;
- while(p < ep) {
- if (*p == ' ' && !inquote)
- break;
-
- if(*p == '\\')
- p++;
- else if(*p == '"')
- inquote = !inquote;
-
- p++;
- }
-
- if(p >= ep)
- return -1;
- *p++ = '\0';
-
- // def: free form to new line
- def = p;
- while(p < ep && *p != '\n')
- p++;
- if(p >= ep)
- return -1;
- edef = p;
- *p++ = '\0';
-
- // include methods on successive lines in def of named type
- while(parsemethod(&p, ep, &meth) > 0) {
- *edef++ = '\n'; // overwrites '\0'
- if(edef+1 > meth) {
- // We want to indent methods with a single \t.
- // 6g puts at least one char of indent before all method defs,
- // so there will be room for the \t. If the method def wasn't
- // indented we could do something more complicated,
- // but for now just diagnose the problem and assume
- // 6g will keep indenting for us.
- fprint(2, "%s: %s: expected methods to be indented %p %p %.10s\n", argv0,
- file, edef, meth, meth);
- nerrors++;
- return -1;
- }
- *edef++ = '\t';
- n = strlen(meth);
- memmove(edef, meth, n);
- edef += n;
- }
-
- name = expandpkg(name, pkg);
- def = expandpkg(def, pkg);
-
- // done
- *pp = p;
- *prefixp = prefix;
- *namep = name;
- *defp = def;
- return 1;
-}
-
-static int
-parsemethod(char **pp, char *ep, char **methp)
-{
- char *p;
-
- // skip white space
- p = *pp;
- while(p < ep && (*p == ' ' || *p == '\t'))
- p++;
- if(p == ep)
- return 0;
-
- // if it says "func (", it's a method
- if(p + 6 >= ep || strncmp(p, "func (", 6) != 0)
- return 0;
-
- // definition to end of line
- *methp = p;
- while(p < ep && *p != '\n')
- p++;
- if(p >= ep) {
- fprint(2, "%s: lost end of line in method definition\n", argv0);
- *pp = ep;
- return -1;
- }
- *p++ = '\0';
- *pp = p;
- return 1;
-}
-
-static void
-loaddynimport(char *file, char *pkg, char *p, int n)
-{
- char *pend, *next, *name, *def, *p0, *lib, *q;
- Sym *s;
-
- USED(file);
- pend = p + n;
- for(; p<pend; p=next) {
- next = strchr(p, '\n');
- if(next == nil)
- next = "";
- else
- *next++ = '\0';
- p0 = p;
- if(strncmp(p, "dynimport ", 10) != 0)
- goto err;
- p += 10;
- name = p;
- p = strchr(name, ' ');
- if(p == nil)
- goto err;
- while(*p == ' ')
- p++;
- def = p;
- p = strchr(def, ' ');
- if(p == nil)
- goto err;
- while(*p == ' ')
- p++;
- lib = p;
-
- // successful parse: now can edit the line
- *strchr(name, ' ') = 0;
- *strchr(def, ' ') = 0;
-
- if(debug['d']) {
- fprint(2, "%s: %s: cannot use dynamic imports with -d flag\n", argv0, file);
- nerrors++;
- return;
- }
-
- if(strcmp(name, "_") == 0 && strcmp(def, "_") == 0) {
- // allow #pragma dynimport _ _ "foo.so"
- // to force a link of foo.so.
- havedynamic = 1;
- adddynlib(lib);
- continue;
- }
-
- name = expandpkg(name, pkg);
- q = strchr(def, '@');
- if(q)
- *q++ = '\0';
- s = lookup(name, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->dynimplib = lib;
- s->dynimpname = def;
- s->dynimpvers = q;
- s->type = SDYNIMPORT;
- havedynamic = 1;
- }
- }
- return;
-
-err:
- fprint(2, "%s: %s: invalid dynimport line: %s\n", argv0, file, p0);
- nerrors++;
-}
-
-static void
-loaddynexport(char *file, char *pkg, char *p, int n)
-{
- char *pend, *next, *local, *elocal, *remote, *p0;
- Sym *s;
-
- USED(file);
- pend = p + n;
- for(; p<pend; p=next) {
- next = strchr(p, '\n');
- if(next == nil)
- next = "";
- else
- *next++ = '\0';
- p0 = p;
- if(strncmp(p, "dynexport ", 10) != 0)
- goto err;
- p += 10;
- local = p;
- p = strchr(local, ' ');
- if(p == nil)
- goto err;
- while(*p == ' ')
- p++;
- remote = p;
-
- // successful parse: now can edit the line
- *strchr(local, ' ') = 0;
-
- elocal = expandpkg(local, pkg);
-
- s = lookup(elocal, 0);
- if(s->dynimplib != nil) {
- fprint(2, "%s: symbol is both dynimport and dynexport %s\n", argv0, local);
- nerrors++;
- }
- s->dynimpname = remote;
- s->dynexport = 1;
-
- if(ndynexp%32 == 0)
- dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
- dynexp[ndynexp++] = s;
-
- if (elocal != local)
- free(elocal);
- }
- return;
-
-err:
- fprint(2, "%s: invalid dynexport line: %s\n", argv0, p0);
- nerrors++;
-}
-
-static int markdepth;
-
-static void
-marktext(Sym *s)
-{
- Auto *a;
- Prog *p;
-
- if(s == S)
- return;
- markdepth++;
- if(debug['v'] > 1)
- Bprint(&bso, "%d marktext %s\n", markdepth, s->name);
- for(a=s->autom; a; a=a->link)
- mark(a->gotype);
- for(p=s->text; p != P; p=p->link) {
- if(p->from.sym)
- mark(p->from.sym);
- if(p->to.sym)
- mark(p->to.sym);
- }
- markdepth--;
-}
-
-void
-mark(Sym *s)
-{
- int i;
-
- if(s == S || s->reachable)
- return;
- if(strncmp(s->name, "weak.", 5) == 0)
- return;
- s->reachable = 1;
- if(s->text)
- marktext(s);
- for(i=0; i<s->nr; i++)
- mark(s->r[i].sym);
- if(s->gotype)
- mark(s->gotype);
- if(s->sub)
- mark(s->sub);
- if(s->outer)
- mark(s->outer);
-}
-
-static char*
-morename[] =
-{
- "runtime.morestack",
- "runtime.morestackx",
-
- "runtime.morestack00",
- "runtime.morestack10",
- "runtime.morestack01",
- "runtime.morestack11",
-
- "runtime.morestack8",
- "runtime.morestack16",
- "runtime.morestack24",
- "runtime.morestack32",
- "runtime.morestack40",
- "runtime.morestack48",
-};
-
-static int
-isz(Auto *a)
-{
- for(; a; a=a->link)
- if(a->type == D_FILE || a->type == D_FILE1)
- return 1;
- return 0;
-}
-
-static void
-addz(Sym *s, Auto *z)
-{
- Auto *a, *last;
-
- // strip out non-z
- last = nil;
- for(a = z; a != nil; a = a->link) {
- if(a->type == D_FILE || a->type == D_FILE1) {
- if(last == nil)
- z = a;
- else
- last->link = a;
- last = a;
- }
- }
- if(last) {
- last->link = s->autom;
- s->autom = z;
- }
-}
-
-void
-deadcode(void)
-{
- int i;
- Sym *s, *last;
- Auto *z;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f deadcode\n", cputime());
-
- mark(lookup(INITENTRY, 0));
- for(i=0; i<nelem(morename); i++)
- mark(lookup(morename[i], 0));
-
- for(i=0; i<ndynexp; i++)
- mark(dynexp[i]);
-
- // remove dead text but keep file information (z symbols).
- last = nil;
- z = nil;
- for(s = textp; s != nil; s = s->next) {
- if(!s->reachable) {
- if(isz(s->autom))
- z = s->autom;
- continue;
- }
- if(last == nil)
- textp = s;
- else
- last->next = s;
- last = s;
- if(z != nil) {
- if(!isz(s->autom))
- addz(s, z);
- z = nil;
- }
- }
- if(last == nil)
- textp = nil;
- else
- last->next = nil;
-
- for(s = allsym; s != S; s = s->allsym)
- if(strncmp(s->name, "weak.", 5) == 0) {
- s->special = 1; // do not lay out in data segment
- s->reachable = 1;
- s->hide = 1;
- }
-}
-
-void
-doweak(void)
-{
- Sym *s, *t;
-
- // resolve weak references only if
- // target symbol will be in binary anyway.
- for(s = allsym; s != S; s = s->allsym) {
- if(strncmp(s->name, "weak.", 5) == 0) {
- t = rlookup(s->name+5, s->version);
- if(t && t->type != 0 && t->reachable) {
- s->value = t->value;
- s->type = t->type;
- } else {
- s->type = SCONST;
- s->value = 0;
- }
- continue;
- }
- }
-}
-
-void
-addexport(void)
-{
- int i;
-
- for(i=0; i<ndynexp; i++)
- adddynsym(dynexp[i]);
-}
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
deleted file mode 100644
index 8334e988e..000000000
--- a/src/cmd/ld/ldelf.c
+++ /dev/null
@@ -1,816 +0,0 @@
-/*
-Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
-http://code.swtch.com/plan9port/src/tip/src/libmach/
-
- Copyright © 2004 Russ Cox.
- Portions Copyright © 2008-2010 Google Inc.
- Portions Copyright © 2010 The Go Authors.
-
-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 "l.h"
-#include "lib.h"
-#include "../ld/elf.h"
-
-enum
-{
- ElfClassNone = 0,
- ElfClass32,
- ElfClass64,
-
- ElfDataNone = 0,
- ElfDataLsb,
- ElfDataMsb,
-
- ElfTypeNone = 0,
- ElfTypeRelocatable,
- ElfTypeExecutable,
- ElfTypeSharedObject,
- ElfTypeCore,
- /* 0xFF00 - 0xFFFF reserved for processor-specific types */
-
- ElfMachNone = 0,
- ElfMach32100, /* AT&T WE 32100 */
- ElfMachSparc, /* SPARC */
- ElfMach386, /* Intel 80386 */
- ElfMach68000, /* Motorola 68000 */
- ElfMach88000, /* Motorola 88000 */
- ElfMach486, /* Intel 80486, no longer used */
- ElfMach860, /* Intel 80860 */
- ElfMachMips, /* MIPS RS3000 */
- ElfMachS370, /* IBM System/370 */
- ElfMachMipsLe, /* MIPS RS3000 LE */
- ElfMachParisc = 15, /* HP PA RISC */
- ElfMachVpp500 = 17, /* Fujitsu VPP500 */
- ElfMachSparc32Plus, /* SPARC V8+ */
- ElfMach960, /* Intel 80960 */
- ElfMachPower, /* PowerPC */
- ElfMachPower64, /* PowerPC 64 */
- ElfMachS390, /* IBM System/390 */
- ElfMachV800 = 36, /* NEC V800 */
- ElfMachFr20, /* Fujitsu FR20 */
- ElfMachRh32, /* TRW RH-32 */
- ElfMachRce, /* Motorola RCE */
- ElfMachArm, /* ARM */
- ElfMachAlpha, /* Digital Alpha */
- ElfMachSH, /* Hitachi SH */
- ElfMachSparc9, /* SPARC V9 */
- ElfMachAmd64 = 62,
- /* and the list goes on... */
-
- ElfAbiNone = 0,
- ElfAbiSystemV = 0, /* [sic] */
- ElfAbiHPUX,
- ElfAbiNetBSD,
- ElfAbiLinux,
- ElfAbiSolaris = 6,
- ElfAbiAix,
- ElfAbiIrix,
- ElfAbiFreeBSD,
- ElfAbiTru64,
- ElfAbiModesto,
- ElfAbiOpenBSD,
- ElfAbiARM = 97,
- ElfAbiEmbedded = 255,
-
- /* some of sections 0xFF00 - 0xFFFF reserved for various things */
- ElfSectNone = 0,
- ElfSectProgbits,
- ElfSectSymtab,
- ElfSectStrtab,
- ElfSectRela,
- ElfSectHash,
- ElfSectDynamic,
- ElfSectNote,
- ElfSectNobits,
- ElfSectRel,
- ElfSectShlib,
- ElfSectDynsym,
-
- ElfSectFlagWrite = 0x1,
- ElfSectFlagAlloc = 0x2,
- ElfSectFlagExec = 0x4,
- /* 0xF0000000 are reserved for processor specific */
-
- ElfSymBindLocal = 0,
- ElfSymBindGlobal,
- ElfSymBindWeak,
- /* 13-15 reserved */
-
- ElfSymTypeNone = 0,
- ElfSymTypeObject,
- ElfSymTypeFunc,
- ElfSymTypeSection,
- ElfSymTypeFile,
- /* 13-15 reserved */
-
- ElfSymShnNone = 0,
- ElfSymShnAbs = 0xFFF1,
- ElfSymShnCommon = 0xFFF2,
- /* 0xFF00-0xFF1F reserved for processors */
- /* 0xFF20-0xFF3F reserved for operating systems */
-
- ElfProgNone = 0,
- ElfProgLoad,
- ElfProgDynamic,
- ElfProgInterp,
- ElfProgNote,
- ElfProgShlib,
- ElfProgPhdr,
-
- ElfProgFlagExec = 0x1,
- ElfProgFlagWrite = 0x2,
- ElfProgFlagRead = 0x4,
-
- ElfNotePrStatus = 1,
- ElfNotePrFpreg = 2,
- ElfNotePrPsinfo = 3,
- ElfNotePrTaskstruct = 4,
- ElfNotePrAuxv = 6,
- ElfNotePrXfpreg = 0x46e62b7f /* for gdb/386 */
-};
-
-typedef struct ElfHdrBytes ElfHdrBytes;
-typedef struct ElfSectBytes ElfSectBytes;
-typedef struct ElfProgBytes ElfProgBytes;
-typedef struct ElfSymBytes ElfSymBytes;
-
-typedef struct ElfHdrBytes64 ElfHdrBytes64;
-typedef struct ElfSectBytes64 ElfSectBytes64;
-typedef struct ElfProgBytes64 ElfProgBytes64;
-typedef struct ElfSymBytes64 ElfSymBytes64;
-
-struct ElfHdrBytes
-{
- uchar ident[16];
- uchar type[2];
- uchar machine[2];
- uchar version[4];
- uchar entry[4];
- uchar phoff[4];
- uchar shoff[4];
- uchar flags[4];
- uchar ehsize[2];
- uchar phentsize[2];
- uchar phnum[2];
- uchar shentsize[2];
- uchar shnum[2];
- uchar shstrndx[2];
-};
-
-struct ElfHdrBytes64
-{
- uchar ident[16];
- uchar type[2];
- uchar machine[2];
- uchar version[4];
- uchar entry[8];
- uchar phoff[8];
- uchar shoff[8];
- uchar flags[4];
- uchar ehsize[2];
- uchar phentsize[2];
- uchar phnum[2];
- uchar shentsize[2];
- uchar shnum[2];
- uchar shstrndx[2];
-};
-
-struct ElfSectBytes
-{
- uchar name[4];
- uchar type[4];
- uchar flags[4];
- uchar addr[4];
- uchar off[4];
- uchar size[4];
- uchar link[4];
- uchar info[4];
- uchar align[4];
- uchar entsize[4];
-};
-
-struct ElfSectBytes64
-{
- uchar name[4];
- uchar type[4];
- uchar flags[8];
- uchar addr[8];
- uchar off[8];
- uchar size[8];
- uchar link[4];
- uchar info[4];
- uchar align[8];
- uchar entsize[8];
-};
-
-struct ElfSymBytes
-{
- uchar name[4];
- uchar value[4];
- uchar size[4];
- uchar info; /* top4: bind, bottom4: type */
- uchar other;
- uchar shndx[2];
-};
-
-struct ElfSymBytes64
-{
- uchar name[4];
- uchar info; /* top4: bind, bottom4: type */
- uchar other;
- uchar shndx[2];
- uchar value[8];
- uchar size[8];
-};
-
-typedef struct ElfSect ElfSect;
-typedef struct ElfObj ElfObj;
-typedef struct ElfSym ElfSym;
-
-struct ElfSect
-{
- char *name;
- uint32 type;
- uint64 flags;
- uint64 addr;
- uint64 off;
- uint64 size;
- uint32 link;
- uint32 info;
- uint64 align;
- uint64 entsize;
- uchar *base;
- Sym *sym;
-};
-
-struct ElfObj
-{
- Biobuf *f;
- int64 base; // offset in f where ELF begins
- int64 len; // length of ELF
- int is64;
- char *name;
-
- Endian *e;
- ElfSect *sect;
- uint nsect;
- char *shstrtab;
- int nsymtab;
- ElfSect *symtab;
- ElfSect *symstr;
-
- uint32 type;
- uint32 machine;
- uint32 version;
- uint64 entry;
- uint64 phoff;
- uint64 shoff;
- uint32 flags;
- uint32 ehsize;
- uint32 phentsize;
- uint32 phnum;
- uint32 shentsize;
- uint32 shnum;
- uint32 shstrndx;
-};
-
-struct ElfSym
-{
- char* name;
- uint64 value;
- uint64 size;
- uchar bind;
- uchar type;
- uchar other;
- uint16 shndx;
- Sym* sym;
-};
-
-uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
-
-static ElfSect* section(ElfObj*, char*);
-static int map(ElfObj*, ElfSect*);
-static int readsym(ElfObj*, int i, ElfSym*);
-static int reltype(char*, int, uchar*);
-
-void
-ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- int32 base;
- uint64 add, info;
- char *name;
- int i, j, rela, is64, n;
- uchar hdrbuf[64];
- uchar *p;
- ElfHdrBytes *hdr;
- ElfObj *obj;
- ElfSect *sect, *rsect;
- ElfSym sym;
- Endian *e;
- Reloc *r, *rp;
- Sym *s;
-
- USED(pkg);
- if(debug['v'])
- Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);
-
- version++;
- base = Boffset(f);
-
- if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
- goto bad;
- hdr = (ElfHdrBytes*)hdrbuf;
- if(memcmp(hdr->ident, ElfMagic, 4) != 0)
- goto bad;
- switch(hdr->ident[5]) {
- case ElfDataLsb:
- e = &le;
- break;
- case ElfDataMsb:
- e = &be;
- break;
- default:
- goto bad;
- }
-
- // read header
- obj = mal(sizeof *obj);
- obj->e = e;
- obj->f = f;
- obj->base = base;
- obj->len = len;
- obj->name = pn;
-
- is64 = 0;
- if(hdr->ident[4] == ElfClass64) {
- ElfHdrBytes64* hdr;
-
- is64 = 1;
- hdr = (ElfHdrBytes64*)hdrbuf;
- obj->type = e->e16(hdr->type);
- obj->machine = e->e16(hdr->machine);
- obj->version = e->e32(hdr->version);
- obj->phoff = e->e64(hdr->phoff);
- obj->shoff = e->e64(hdr->shoff);
- obj->flags = e->e32(hdr->flags);
- obj->ehsize = e->e16(hdr->ehsize);
- obj->phentsize = e->e16(hdr->phentsize);
- obj->phnum = e->e16(hdr->phnum);
- obj->shentsize = e->e16(hdr->shentsize);
- obj->shnum = e->e16(hdr->shnum);
- obj->shstrndx = e->e16(hdr->shstrndx);
- } else {
- obj->type = e->e16(hdr->type);
- obj->machine = e->e16(hdr->machine);
- obj->version = e->e32(hdr->version);
- obj->entry = e->e32(hdr->entry);
- obj->phoff = e->e32(hdr->phoff);
- obj->shoff = e->e32(hdr->shoff);
- obj->flags = e->e32(hdr->flags);
- obj->ehsize = e->e16(hdr->ehsize);
- obj->phentsize = e->e16(hdr->phentsize);
- obj->phnum = e->e16(hdr->phnum);
- obj->shentsize = e->e16(hdr->shentsize);
- obj->shnum = e->e16(hdr->shnum);
- obj->shstrndx = e->e16(hdr->shstrndx);
- }
- obj->is64 = is64;
-
- if(hdr->ident[6] != obj->version)
- goto bad;
-
- if(e->e16(hdr->type) != ElfTypeRelocatable) {
- diag("%s: elf but not elf relocatable object");
- return;
- }
-
- switch(thechar) {
- default:
- diag("%s: elf %s unimplemented", thestring);
- return;
- case '5':
- if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) {
- diag("%s: elf object but not arm", pn);
- return;
- }
- break;
- case '6':
- if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) {
- diag("%s: elf object but not amd64", pn);
- return;
- }
- break;
- case '8':
- if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) {
- diag("%s: elf object but not 386", pn);
- return;
- }
- break;
- }
-
- // load section list into memory.
- obj->sect = mal(obj->shnum*sizeof obj->sect[0]);
- obj->nsect = obj->shnum;
- for(i=0; i<obj->nsect; i++) {
- if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0)
- goto bad;
- sect = &obj->sect[i];
- if(is64) {
- ElfSectBytes64 b;
-
- werrstr("short read");
- if(Bread(f, &b, sizeof b) != sizeof b)
- goto bad;
-
- sect->name = (char*)(uintptr)e->e32(b.name);
- sect->type = e->e32(b.type);
- sect->flags = e->e64(b.flags);
- sect->addr = e->e64(b.addr);
- sect->off = e->e64(b.off);
- sect->size = e->e64(b.size);
- sect->link = e->e32(b.link);
- sect->info = e->e32(b.info);
- sect->align = e->e64(b.align);
- sect->entsize = e->e64(b.entsize);
- } else {
- ElfSectBytes b;
-
- werrstr("short read");
- if(Bread(f, &b, sizeof b) != sizeof b)
- goto bad;
-
- sect->name = (char*)(uintptr)e->e32(b.name);
- sect->type = e->e32(b.type);
- sect->flags = e->e32(b.flags);
- sect->addr = e->e32(b.addr);
- sect->off = e->e32(b.off);
- sect->size = e->e32(b.size);
- sect->link = e->e32(b.link);
- sect->info = e->e32(b.info);
- sect->align = e->e32(b.align);
- sect->entsize = e->e32(b.entsize);
- }
- }
-
- // read section string table and translate names
- if(obj->shstrndx >= obj->nsect) {
- werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect);
- goto bad;
- }
- sect = &obj->sect[obj->shstrndx];
- if(map(obj, sect) < 0)
- goto bad;
- for(i=0; i<obj->nsect; i++)
- if(obj->sect[i].name != nil)
- obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name;
-
- // load string table for symbols into memory.
- obj->symtab = section(obj, ".symtab");
- if(obj->symtab == nil) {
- // our work is done here - no symbols means nothing can refer to this file
- return;
- }
- if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) {
- diag("%s: elf object has symbol table with invalid string table link", pn);
- return;
- }
- obj->symstr = &obj->sect[obj->symtab->link];
- if(is64)
- obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64);
- else
- obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes);
-
- if(map(obj, obj->symtab) < 0)
- goto bad;
- if(map(obj, obj->symstr) < 0)
- goto bad;
-
- // load text and data segments into memory.
- // they are not as small as the section lists, but we'll need
- // the memory anyway for the symbol images, so we might
- // as well use one large chunk.
-
- // create symbols for mapped sections
- for(i=0; i<obj->nsect; i++) {
- sect = &obj->sect[i];
- if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc))
- continue;
- if(sect->type != ElfSectNobits && map(obj, sect) < 0)
- goto bad;
-
- name = smprint("%s(%s)", pn, sect->name);
- s = lookup(name, version);
- free(name);
- switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
- default:
- werrstr("unexpected flags for ELF section %s", sect->name);
- goto bad;
- case ElfSectFlagAlloc:
- s->type = SRODATA;
- break;
- case ElfSectFlagAlloc + ElfSectFlagWrite:
- s->type = SDATA;
- break;
- case ElfSectFlagAlloc + ElfSectFlagExec:
- s->type = STEXT;
- break;
- }
- if(sect->type == ElfSectProgbits) {
- s->p = sect->base;
- s->np = sect->size;
- }
- s->size = sect->size;
- if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- }
- sect->sym = s;
- }
-
- // load relocations
- for(i=0; i<obj->nsect; i++) {
- rsect = &obj->sect[i];
- if(rsect->type != ElfSectRela && rsect->type != ElfSectRel)
- continue;
- if(rsect->info >= obj->nsect || obj->sect[rsect->info].base == nil)
- continue;
- sect = &obj->sect[rsect->info];
- if(map(obj, rsect) < 0)
- goto bad;
- rela = rsect->type == ElfSectRela;
- n = rsect->size/(4+4*is64)/(2+rela);
- r = mal(n*sizeof r[0]);
- p = rsect->base;
- for(j=0; j<n; j++) {
- add = 0;
- rp = &r[j];
- if(is64) {
- // 64-bit rel/rela
- rp->off = e->e64(p);
- p += 8;
- info = e->e64(p);
- p += 8;
- if(rela) {
- add = e->e64(p);
- p += 8;
- }
- } else {
- // 32-bit rel/rela
- rp->off = e->e32(p);
- p += 4;
- info = e->e32(p);
- info = info>>8<<32 | (info&0xff); // convert to 64-bit info
- p += 4;
- if(rela) {
- add = e->e32(p);
- p += 4;
- }
- }
- if(readsym(obj, info>>32, &sym) < 0)
- goto bad;
- if(sym.sym == nil) {
- werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
- sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
- goto bad;
- }
- rp->sym = sym.sym;
- rp->type = reltype(pn, (uint32)info, &rp->siz);
- if(rela)
- rp->add = add;
- else {
- // load addend from image
- if(rp->siz == 4)
- rp->add = e->e32(sect->base+rp->off);
- else if(rp->siz == 8)
- rp->add = e->e64(sect->base+rp->off);
- else
- diag("invalid rela size %d", rp->siz);
- }
- }
- qsort(r, n, sizeof r[0], rbyoff); // just in case
-
- s = sect->sym;
- s->r = r;
- s->nr = n;
- }
-
- // enter sub-symbols into symbol table.
- // symbol 0 is the null symbol.
- for(i=1; i<obj->nsymtab; i++) {
- if(readsym(obj, i, &sym) < 0)
- goto bad;
- if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone)
- continue;
- if(sym.shndx == ElfSymShnCommon) {
- s = sym.sym;
- if(s->size < sym.size)
- s->size = sym.size;
- if(s->type == 0 || s->type == SXREF)
- s->type = SBSS;
- continue;
- }
- if(sym.shndx >= obj->nsect || sym.shndx == 0)
- continue;
- sect = obj->sect+sym.shndx;
- if(sect->sym == nil) {
- diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
- continue;
- }
- s = sym.sym;
- s->sub = sect->sym->sub;
- sect->sym->sub = s;
- s->type = sect->sym->type | SSUB;
- if(!s->dynexport) {
- s->dynimplib = nil; // satisfy dynimport
- s->dynimpname = nil; // satisfy dynimport
- }
- s->value = sym.value;
- s->size = sym.size;
- s->outer = sect->sym;
- if(sect->sym->type == STEXT) {
- Prog *p;
-
- if(s->text != P)
- diag("%s: duplicate definition of %s", pn, s->name);
- // build a TEXT instruction with a unique pc
- // just to make the rest of the linker happy.
- p = prg();
- p->as = ATEXT;
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->textflag = 7;
- p->to.type = D_CONST;
- p->link = nil;
- p->pc = pc++;
- s->text = p;
-
- etextp->next = s;
- etextp = s;
- }
- }
- return;
-
-bad:
- diag("%s: malformed elf file: %r", pn);
-}
-
-static ElfSect*
-section(ElfObj *obj, char *name)
-{
- int i;
-
- for(i=0; i<obj->nsect; i++)
- if(obj->sect[i].name && name && strcmp(obj->sect[i].name, name) == 0)
- return &obj->sect[i];
- return nil;
-}
-
-static int
-map(ElfObj *obj, ElfSect *sect)
-{
- if(sect->base != nil)
- return 0;
-
- if(sect->off+sect->size > obj->len) {
- werrstr("elf section past end of file");
- return -1;
- }
-
- sect->base = mal(sect->size);
- werrstr("short read");
- if(Bseek(obj->f, obj->base+sect->off, 0) < 0 || Bread(obj->f, sect->base, sect->size) != sect->size)
- return -1;
-
- return 0;
-}
-
-static int
-readsym(ElfObj *obj, int i, ElfSym *sym)
-{
- Sym *s;
-
- if(i >= obj->nsymtab || i < 0) {
- werrstr("invalid elf symbol index");
- return -1;
- }
-
- if(obj->is64) {
- ElfSymBytes64 *b;
-
- b = (ElfSymBytes64*)(obj->symtab->base + i*sizeof *b);
- sym->name = (char*)obj->symstr->base + obj->e->e32(b->name);
- sym->value = obj->e->e64(b->value);
- sym->size = obj->e->e64(b->size);
- sym->shndx = obj->e->e16(b->shndx);
- sym->bind = b->info>>4;
- sym->type = b->info&0xf;
- sym->other = b->other;
- } else {
- ElfSymBytes *b;
-
- b = (ElfSymBytes*)(obj->symtab->base + i*sizeof *b);
- sym->name = (char*)obj->symstr->base + obj->e->e32(b->name);
- sym->value = obj->e->e32(b->value);
- sym->size = obj->e->e32(b->size);
- sym->shndx = obj->e->e16(b->shndx);
- sym->bind = b->info>>4;
- sym->type = b->info&0xf;
- sym->other = b->other;
- }
-
- s = nil;
- if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0)
- sym->name = ".got";
- if(strcmp(sym->name, "__stack_chk_fail_local") == 0)
- sym->other = 0; // rewrite hidden -> default visibility
- switch(sym->type) {
- case ElfSymTypeSection:
- s = obj->sect[sym->shndx].sym;
- break;
- case ElfSymTypeObject:
- case ElfSymTypeFunc:
- case ElfSymTypeNone:
- switch(sym->bind) {
- case ElfSymBindGlobal:
- if(sym->other != 2) {
- s = lookup(sym->name, 0);
- break;
- }
- // fall through
- case ElfSymBindLocal:
- s = lookup(sym->name, version);
- break;
- default:
- werrstr("%s: invalid symbol binding %d", sym->name, sym->bind);
- return -1;
- }
- break;
- }
- if(s != nil && s->type == 0 && sym->type != ElfSymTypeSection)
- s->type = SXREF;
- sym->sym = s;
-
- return 0;
-}
-
-int
-rbyoff(const void *va, const void *vb)
-{
- Reloc *a, *b;
-
- a = (Reloc*)va;
- b = (Reloc*)vb;
- if(a->off < b->off)
- return -1;
- if(a->off > b->off)
- return +1;
- return 0;
-}
-
-#define R(x, y) ((x)|((y)<<24))
-
-static int
-reltype(char *pn, int elftype, uchar *siz)
-{
- switch(R(thechar, elftype)) {
- default:
- diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype);
- case R('6', R_X86_64_PC32):
- case R('6', R_X86_64_PLT32):
- case R('6', R_X86_64_GOTPCREL):
- case R('8', R_386_32):
- case R('8', R_386_PC32):
- case R('8', R_386_GOT32):
- case R('8', R_386_PLT32):
- case R('8', R_386_GOTOFF):
- case R('8', R_386_GOTPC):
- *siz = 4;
- break;
- case R('6', R_X86_64_64):
- *siz = 8;
- break;
- }
-
- return 256+elftype;
-}
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
deleted file mode 100644
index abbc3b3cd..000000000
--- a/src/cmd/ld/ldmacho.c
+++ /dev/null
@@ -1,821 +0,0 @@
-/*
-Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
-http://code.swtch.com/plan9port/src/tip/src/libmach/
-
- Copyright © 2004 Russ Cox.
- Portions Copyright © 2008-2010 Google Inc.
- Portions Copyright © 2010 The Go Authors.
-
-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 "l.h"
-#include "lib.h"
-
-enum {
- MACHO_FAKE_GOTPCREL = 100, // from macho.h
-
- N_EXT = 0x01,
- N_TYPE = 0x1e,
- N_STAB = 0xe0,
-};
-
-typedef struct MachoObj MachoObj;
-typedef struct MachoCmd MachoCmd;
-typedef struct MachoSeg MachoSeg;
-typedef struct MachoSect MachoSect;
-typedef struct MachoRel MachoRel;
-typedef struct MachoSymtab MachoSymtab;
-typedef struct MachoSym MachoSym;
-typedef struct MachoDysymtab MachoDysymtab;
-
-enum
-{
- MachoCpuVax = 1,
- MachoCpu68000 = 6,
- MachoCpu386 = 7,
- MachoCpuAmd64 = 0x1000007,
- MachoCpuMips = 8,
- MachoCpu98000 = 10,
- MachoCpuHppa = 11,
- MachoCpuArm = 12,
- MachoCpu88000 = 13,
- MachoCpuSparc = 14,
- MachoCpu860 = 15,
- MachoCpuAlpha = 16,
- MachoCpuPower = 18,
-
- MachoCmdSegment = 1,
- MachoCmdSymtab = 2,
- MachoCmdSymseg = 3,
- MachoCmdThread = 4,
- MachoCmdDysymtab = 11,
- MachoCmdSegment64 = 25,
-
- MachoFileObject = 1,
- MachoFileExecutable = 2,
- MachoFileFvmlib = 3,
- MachoFileCore = 4,
- MachoFilePreload = 5,
-};
-
-struct MachoSeg
-{
- char name[16+1];
- uint64 vmaddr;
- uint64 vmsize;
- uint32 fileoff;
- uint32 filesz;
- uint32 maxprot;
- uint32 initprot;
- uint32 nsect;
- uint32 flags;
- MachoSect *sect;
-};
-
-struct MachoSect
-{
- char name[16+1];
- char segname[16+1];
- uint64 addr;
- uint64 size;
- uint32 off;
- uint32 align;
- uint32 reloff;
- uint32 nreloc;
- uint32 flags;
- uint32 res1;
- uint32 res2;
- Sym *sym;
-
- MachoRel *rel;
-};
-
-struct MachoRel
-{
- uint32 addr;
- uint32 symnum;
- uint8 pcrel;
- uint8 length;
- uint8 extrn;
- uint8 type;
- uint8 scattered;
- uint32 value;
-};
-
-struct MachoSymtab
-{
- uint32 symoff;
- uint32 nsym;
- uint32 stroff;
- uint32 strsize;
-
- char *str;
- MachoSym *sym;
-};
-
-struct MachoSym
-{
- char *name;
- uint8 type;
- uint8 sectnum;
- uint16 desc;
- char kind;
- uint64 value;
- Sym *sym;
-};
-
-struct MachoDysymtab
-{
- uint32 ilocalsym;
- uint32 nlocalsym;
- uint32 iextdefsym;
- uint32 nextdefsym;
- uint32 iundefsym;
- uint32 nundefsym;
- uint32 tocoff;
- uint32 ntoc;
- uint32 modtaboff;
- uint32 nmodtab;
- uint32 extrefsymoff;
- uint32 nextrefsyms;
- uint32 indirectsymoff;
- uint32 nindirectsyms;
- uint32 extreloff;
- uint32 nextrel;
- uint32 locreloff;
- uint32 nlocrel;
- uint32 *indir;
-};
-
-struct MachoCmd
-{
- int type;
- uint32 off;
- uint32 size;
- MachoSeg seg;
- MachoSymtab sym;
- MachoDysymtab dsym;
-};
-
-struct MachoObj
-{
- Biobuf *f;
- int64 base; // off in f where Mach-O begins
- int64 len; // length of Mach-O
- int is64;
- char *name;
-
- Endian *e;
- uint cputype;
- uint subcputype;
- uint32 filetype;
- uint32 flags;
- MachoCmd *cmd;
- uint ncmd;
-};
-
-static int
-unpackcmd(uchar *p, MachoObj *m, MachoCmd *c, uint type, uint sz)
-{
- uint32 (*e4)(uchar*);
- uint64 (*e8)(uchar*);
- MachoSect *s;
- int i;
-
- e4 = m->e->e32;
- e8 = m->e->e64;
-
- c->type = type;
- c->size = sz;
- switch(type){
- default:
- return -1;
- case MachoCmdSegment:
- if(sz < 56)
- return -1;
- strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
- c->seg.vmaddr = e4(p+24);
- c->seg.vmsize = e4(p+28);
- c->seg.fileoff = e4(p+32);
- c->seg.filesz = e4(p+36);
- c->seg.maxprot = e4(p+40);
- c->seg.initprot = e4(p+44);
- c->seg.nsect = e4(p+48);
- c->seg.flags = e4(p+52);
- c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
- if(sz < 56+c->seg.nsect*68)
- return -1;
- p += 56;
- for(i=0; i<c->seg.nsect; i++) {
- s = &c->seg.sect[i];
- strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
- strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
- s->addr = e4(p+32);
- s->size = e4(p+36);
- s->off = e4(p+40);
- s->align = e4(p+44);
- s->reloff = e4(p+48);
- s->nreloc = e4(p+52);
- s->flags = e4(p+56);
- s->res1 = e4(p+60);
- s->res2 = e4(p+64);
- p += 68;
- }
- break;
- case MachoCmdSegment64:
- if(sz < 72)
- return -1;
- strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
- c->seg.vmaddr = e8(p+24);
- c->seg.vmsize = e8(p+32);
- c->seg.fileoff = e8(p+40);
- c->seg.filesz = e8(p+48);
- c->seg.maxprot = e4(p+56);
- c->seg.initprot = e4(p+60);
- c->seg.nsect = e4(p+64);
- c->seg.flags = e4(p+68);
- c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
- if(sz < 72+c->seg.nsect*80)
- return -1;
- p += 72;
- for(i=0; i<c->seg.nsect; i++) {
- s = &c->seg.sect[i];
- strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
- strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
- s->addr = e8(p+32);
- s->size = e8(p+40);
- s->off = e4(p+48);
- s->align = e4(p+52);
- s->reloff = e4(p+56);
- s->nreloc = e4(p+60);
- s->flags = e4(p+64);
- s->res1 = e4(p+68);
- s->res2 = e4(p+72);
- // p+76 is reserved
- p += 80;
- }
- break;
- case MachoCmdSymtab:
- if(sz < 24)
- return -1;
- c->sym.symoff = e4(p+8);
- c->sym.nsym = e4(p+12);
- c->sym.stroff = e4(p+16);
- c->sym.strsize = e4(p+20);
- break;
- case MachoCmdDysymtab:
- if(sz < 80)
- return -1;
- c->dsym.ilocalsym = e4(p+8);
- c->dsym.nlocalsym = e4(p+12);
- c->dsym.iextdefsym = e4(p+16);
- c->dsym.nextdefsym = e4(p+20);
- c->dsym.iundefsym = e4(p+24);
- c->dsym.nundefsym = e4(p+28);
- c->dsym.tocoff = e4(p+32);
- c->dsym.ntoc = e4(p+36);
- c->dsym.modtaboff = e4(p+40);
- c->dsym.nmodtab = e4(p+44);
- c->dsym.extrefsymoff = e4(p+48);
- c->dsym.nextrefsyms = e4(p+52);
- c->dsym.indirectsymoff = e4(p+56);
- c->dsym.nindirectsyms = e4(p+60);
- c->dsym.extreloff = e4(p+64);
- c->dsym.nextrel = e4(p+68);
- c->dsym.locreloff = e4(p+72);
- c->dsym.nlocrel = e4(p+76);
- break;
- }
- return 0;
-}
-
-static int
-macholoadrel(MachoObj *m, MachoSect *sect)
-{
- MachoRel *rel, *r;
- uchar *buf, *p;
- int i, n;
- uint32 v;
-
- if(sect->rel != nil || sect->nreloc == 0)
- return 0;
- rel = mal(sect->nreloc * sizeof r[0]);
- n = sect->nreloc * 8;
- buf = mal(n);
- if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n)
- return -1;
- for(i=0; i<sect->nreloc; i++) {
- r = &rel[i];
- p = buf+i*8;
- r->addr = m->e->e32(p);
-
- // TODO(rsc): Wrong interpretation for big-endian bitfields?
- if(r->addr & 0x80000000) {
- // scatterbrained relocation
- r->scattered = 1;
- v = r->addr >> 24;
- r->addr &= 0xFFFFFF;
- r->type = v & 0xF;
- v >>= 4;
- r->length = 1<<(v&3);
- v >>= 2;
- r->pcrel = v & 1;
- r->value = m->e->e32(p+4);
- } else {
- v = m->e->e32(p+4);
- r->symnum = v & 0xFFFFFF;
- v >>= 24;
- r->pcrel = v&1;
- v >>= 1;
- r->length = 1<<(v&3);
- v >>= 2;
- r->extrn = v&1;
- v >>= 1;
- r->type = v;
- }
- }
- sect->rel = rel;
- return 0;
-}
-
-static int
-macholoaddsym(MachoObj *m, MachoDysymtab *d)
-{
- uchar *p;
- int i, n;
-
- n = d->nindirectsyms;
-
- p = mal(n*4);
- if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4)
- return -1;
-
- d->indir = (uint32*)p;
- for(i=0; i<n; i++)
- d->indir[i] = m->e->e32(p+4*i);
- return 0;
-}
-
-static int
-macholoadsym(MachoObj *m, MachoSymtab *symtab)
-{
- char *strbuf;
- uchar *symbuf, *p;
- int i, n, symsize;
- MachoSym *sym, *s;
- uint32 v;
-
- if(symtab->sym != nil)
- return 0;
-
- strbuf = mal(symtab->strsize);
- if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize)
- return -1;
-
- symsize = 12;
- if(m->is64)
- symsize = 16;
- n = symtab->nsym * symsize;
- symbuf = mal(n);
- if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n)
- return -1;
- sym = mal(symtab->nsym * sizeof sym[0]);
- p = symbuf;
- for(i=0; i<symtab->nsym; i++) {
- s = &sym[i];
- v = m->e->e32(p);
- if(v >= symtab->strsize)
- return -1;
- s->name = strbuf + v;
- s->type = p[4];
- s->sectnum = p[5];
- s->desc = m->e->e16(p+6);
- if(m->is64)
- s->value = m->e->e64(p+8);
- else
- s->value = m->e->e32(p+8);
- p += symsize;
- }
- symtab->str = strbuf;
- symtab->sym = sym;
- return 0;
-}
-
-void
-ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- int i, j, is64;
- uint64 secaddr;
- uchar hdr[7*4], *cmdp;
- uchar tmp[4];
- uchar *dat;
- ulong ncmd, cmdsz, ty, sz, off;
- MachoObj *m;
- Endian *e;
- int64 base;
- MachoSect *sect;
- MachoRel *rel;
- Sym *s, *outer;
- MachoCmd *c;
- MachoSymtab *symtab;
- MachoDysymtab *dsymtab;
- MachoSym *sym;
- Reloc *r, *rp;
- char *name;
-
- USED(pkg);
- version++;
- base = Boffset(f);
- if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
- goto bad;
-
- if((be.e32(hdr)&~1) == 0xFEEDFACE){
- e = &be;
- }else if((le.e32(hdr)&~1) == 0xFEEDFACE){
- e = &le;
- }else{
- werrstr("bad magic - not mach-o file");
- goto bad;
- }
-
- is64 = e->e32(hdr) == 0xFEEDFACF;
- ncmd = e->e32(hdr+4*4);
- cmdsz = e->e32(hdr+5*4);
- if(ncmd > 0x10000 || cmdsz >= 0x01000000){
- werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz);
- goto bad;
- }
- if(is64)
- Bread(f, tmp, 4); // skip reserved word in header
-
- m = mal(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz);
- m->f = f;
- m->e = e;
- m->cputype = e->e32(hdr+1*4);
- m->subcputype = e->e32(hdr+2*4);
- m->filetype = e->e32(hdr+3*4);
- m->ncmd = ncmd;
- m->flags = e->e32(hdr+6*4);
- m->is64 = is64;
- m->base = base;
- m->len = len;
- m->name = pn;
-
- switch(thechar) {
- default:
- diag("%s: mach-o %s unimplemented", thestring);
- return;
- case '6':
- if(e != &le || m->cputype != MachoCpuAmd64) {
- diag("%s: mach-o object but not amd64", pn);
- return;
- }
- break;
- case '8':
- if(e != &le || m->cputype != MachoCpu386) {
- diag("%s: mach-o object but not 386", pn);
- return;
- }
- break;
- }
-
- m->cmd = (MachoCmd*)(m+1);
- off = sizeof hdr;
- cmdp = (uchar*)(m->cmd+ncmd);
- if(Bread(f, cmdp, cmdsz) != cmdsz){
- werrstr("reading cmds: %r");
- goto bad;
- }
-
- // read and parse load commands
- c = nil;
- symtab = nil;
- dsymtab = nil;
- for(i=0; i<ncmd; i++){
- ty = e->e32(cmdp);
- sz = e->e32(cmdp+4);
- m->cmd[i].off = off;
- unpackcmd(cmdp, m, &m->cmd[i], ty, sz);
- cmdp += sz;
- off += sz;
- if(ty == MachoCmdSymtab) {
- if(symtab != nil) {
- werrstr("multiple symbol tables");
- goto bad;
- }
- symtab = &m->cmd[i].sym;
- macholoadsym(m, symtab);
- }
- if(ty == MachoCmdDysymtab) {
- dsymtab = &m->cmd[i].dsym;
- macholoaddsym(m, dsymtab);
- }
- if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) {
- if(c != nil) {
- werrstr("multiple load commands");
- goto bad;
- }
- c = &m->cmd[i];
- }
- }
-
- // load text and data segments into memory.
- // they are not as small as the load commands, but we'll need
- // the memory anyway for the symbol images, so we might
- // as well use one large chunk.
- if(c == nil) {
- werrstr("no load command");
- goto bad;
- }
- if(symtab == nil) {
- // our work is done here - no symbols means nothing can refer to this file
- return;
- }
-
- if(c->seg.fileoff+c->seg.filesz >= len) {
- werrstr("load segment out of range");
- goto bad;
- }
-
- dat = mal(c->seg.filesz);
- if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) {
- werrstr("cannot load object data: %r");
- goto bad;
- }
-
- for(i=0; i<c->seg.nsect; i++) {
- sect = &c->seg.sect[i];
- if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0)
- continue;
- if(strcmp(sect->name, "__eh_frame") == 0)
- continue;
- name = smprint("%s(%s/%s)", pn, sect->segname, sect->name);
- s = lookup(name, version);
- if(s->type != 0) {
- werrstr("duplicate %s/%s", sect->segname, sect->name);
- goto bad;
- }
- free(name);
- s->p = dat + sect->addr - c->seg.vmaddr;
- s->np = sect->size;
- s->size = s->np;
-
- if(strcmp(sect->segname, "__TEXT") == 0) {
- if(strcmp(sect->name, "__text") == 0)
- s->type = STEXT;
- else
- s->type = SRODATA;
- } else {
- if (strcmp(sect->name, "__bss") == 0) {
- s->type = SBSS;
- s->np = 0;
- } else
- s->type = SDATA;
- }
- if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- }
- sect->sym = s;
- }
-
- // enter sub-symbols into symbol table.
- // have to guess sizes from next symbol.
- for(i=0; i<symtab->nsym; i++) {
- int v;
- sym = &symtab->sym[i];
- if(sym->type&N_STAB)
- continue;
- // TODO: check sym->type against outer->type.
- name = sym->name;
- if(name[0] == '_' && name[1] != '\0')
- name++;
- v = 0;
- if(!(sym->type&N_EXT))
- v = version;
- s = lookup(name, v);
- sym->sym = s;
- if(sym->sectnum == 0) // undefined
- continue;
- if(sym->sectnum > c->seg.nsect) {
- werrstr("reference to invalid section %d", sym->sectnum);
- goto bad;
- }
- sect = &c->seg.sect[sym->sectnum-1];
- outer = sect->sym;
- if(outer == nil) {
- werrstr("reference to invalid section %s/%s", sect->segname, sect->name);
- continue;
- }
- s->type = outer->type | SSUB;
- s->sub = outer->sub;
- outer->sub = s;
- s->outer = outer;
- s->value = sym->value - sect->addr;
- if(i+1 < symtab->nsym)
- s->size = (sym+1)->value - sym->value;
- else
- s->size = sect->addr + sect->size - sym->value;
- if(!s->dynexport) {
- s->dynimplib = nil; // satisfy dynimport
- s->dynimpname = nil; // satisfy dynimport
- }
- if(outer->type == STEXT) {
- Prog *p;
-
- if(s->text != P)
- diag("%s sym#%d: duplicate definition of %s", pn, i, s->name);
- // build a TEXT instruction with a unique pc
- // just to make the rest of the linker happy.
- // TODO: this is too 6l-specific ?
- p = prg();
- p->as = ATEXT;
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->textflag = 7;
- p->to.type = D_CONST;
- p->link = nil;
- p->pc = pc++;
- s->text = p;
-
- etextp->next = s;
- etextp = s;
- }
- sym->sym = s;
- }
-
- // load relocations
- for(i=0; i<c->seg.nsect; i++) {
- sect = &c->seg.sect[i];
- if((s = sect->sym) == S)
- continue;
- macholoadrel(m, sect);
- if(sect->rel == nil)
- continue;
- r = mal(sect->nreloc*sizeof r[0]);
- rp = r;
- rel = sect->rel;
- for(j=0; j<sect->nreloc; j++, rel++) {
- if(rel->scattered) {
- int k;
- MachoSect *ks;
-
- if(thechar != '8')
- diag("unexpected scattered relocation");
-
- // on 386, rewrite scattered 4/1 relocation into
- // the pseudo-pc-relative reference that it is.
- // assume that the second in the pair is in this section
- // and use that as the pc-relative base.
- if(thechar != '8' || rel->type != 4 || j+1 >= sect->nreloc ||
- !(rel+1)->scattered || (rel+1)->type != 1 ||
- (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) {
- werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type);
- goto bad;
- }
- rp->siz = rel->length;
- rp->off = rel->addr;
-
- // NOTE(rsc): I haven't worked out why (really when)
- // we should ignore the addend on a
- // scattered relocation, but it seems that the
- // common case is we ignore it.
- // It's likely that this is not strictly correct
- // and that the math should look something
- // like the non-scattered case below.
- rp->add = 0;
-
- // want to make it pc-relative aka relative to rp->off+4
- // but the scatter asks for relative to off = (rel+1)->value - sect->addr.
- // adjust rp->add accordingly.
- rp->type = D_PCREL;
- rp->add += (rp->off+4) - ((rel+1)->value - sect->addr);
-
- // now consider the desired symbol.
- // find the section where it lives.
- for(k=0; k<c->seg.nsect; k++) {
- ks = &c->seg.sect[k];
- if(ks->addr <= rel->value && rel->value < ks->addr+ks->size)
- goto foundk;
- }
- werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr);
- goto bad;
- foundk:
- if(ks->sym != S) {
- rp->sym = ks->sym;
- rp->add += rel->value - ks->addr;
- } else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) {
- // handle reference to __IMPORT/__pointers.
- // how much worse can this get?
- // why are we supporting 386 on the mac anyway?
- rp->type = 512 + MACHO_FAKE_GOTPCREL;
- // figure out which pointer this is a reference to.
- k = ks->res1 + (rel->value - ks->addr) / 4;
- // load indirect table for __pointers
- // fetch symbol number
- if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) {
- werrstr("invalid scattered relocation: indirect symbol reference out of range");
- goto bad;
- }
- k = dsymtab->indir[k];
- if(k < 0 || k >= symtab->nsym) {
- werrstr("invalid scattered relocation: symbol reference out of range");
- goto bad;
- }
- rp->sym = symtab->sym[k].sym;
- } else {
- werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name);
- goto bad;
- }
- rp++;
- // skip #1 of 2 rel; continue skips #2 of 2.
- rel++;
- j++;
- continue;
- }
-
- rp->siz = rel->length;
- rp->type = 512 + (rel->type<<1) + rel->pcrel;
- rp->off = rel->addr;
-
- // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
- if (thechar == '6' && rel->extrn == 0 && rel->type == 1) {
- // Calculate the addend as the offset into the section.
- //
- // The rip-relative offset stored in the object file is encoded
- // as follows:
- //
- // movsd 0x00000360(%rip),%xmm0
- //
- // To get the absolute address of the value this rip-relative address is pointing
- // to, we must add the address of the next instruction to it. This is done by
- // taking the address of the relocation and adding 4 to it (since the rip-relative
- // offset can at most be 32 bits long). To calculate the offset into the section the
- // relocation is referencing, we subtract the vaddr of the start of the referenced
- // section found in the original object file.
- //
- // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
- secaddr = c->seg.sect[rel->symnum-1].addr;
- rp->add = e->e32(s->p+rp->off) + rp->off + 4 - secaddr;
- } else
- rp->add = e->e32(s->p+rp->off);
-
- // For i386 Mach-O PC-relative, the addend is written such that
- // it *is* the PC being subtracted. Use that to make
- // it match our version of PC-relative.
- if(rel->pcrel && thechar == '8')
- rp->add += rp->off+rp->siz;
- if(!rel->extrn) {
- if(rel->symnum < 1 || rel->symnum > c->seg.nsect) {
- werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect);
- goto bad;
- }
- rp->sym = c->seg.sect[rel->symnum-1].sym;
- if(rp->sym == nil) {
- werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name);
- goto bad;
- }
- // References to symbols in other sections
- // include that information in the addend.
- // We only care about the delta from the
- // section base.
- if(thechar == '8')
- rp->add -= c->seg.sect[rel->symnum-1].addr;
- } else {
- if(rel->symnum >= symtab->nsym) {
- werrstr("invalid relocation: symbol reference out of range");
- goto bad;
- }
- rp->sym = symtab->sym[rel->symnum].sym;
- }
- rp++;
- }
- qsort(r, rp - r, sizeof r[0], rbyoff);
- s->r = r;
- s->nr = rp - r;
- }
- return;
-
-bad:
- diag("%s: malformed mach-o file: %r", pn);
-}
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
deleted file mode 100644
index 98c866fee..000000000
--- a/src/cmd/ld/ldpe.c
+++ /dev/null
@@ -1,415 +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 "l.h"
-#include "lib.h"
-#include "../ld/pe.h"
-
-#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
-
-#define IMAGE_SYM_UNDEFINED 0
-#define IMAGE_SYM_ABSOLUTE (-1)
-#define IMAGE_SYM_DEBUG (-2)
-#define IMAGE_SYM_TYPE_NULL 0
-#define IMAGE_SYM_TYPE_VOID 1
-#define IMAGE_SYM_TYPE_CHAR 2
-#define IMAGE_SYM_TYPE_SHORT 3
-#define IMAGE_SYM_TYPE_INT 4
-#define IMAGE_SYM_TYPE_LONG 5
-#define IMAGE_SYM_TYPE_FLOAT 6
-#define IMAGE_SYM_TYPE_DOUBLE 7
-#define IMAGE_SYM_TYPE_STRUCT 8
-#define IMAGE_SYM_TYPE_UNION 9
-#define IMAGE_SYM_TYPE_ENUM 10
-#define IMAGE_SYM_TYPE_MOE 11
-#define IMAGE_SYM_TYPE_BYTE 12
-#define IMAGE_SYM_TYPE_WORD 13
-#define IMAGE_SYM_TYPE_UINT 14
-#define IMAGE_SYM_TYPE_DWORD 15
-#define IMAGE_SYM_TYPE_PCODE 32768
-#define IMAGE_SYM_DTYPE_NULL 0
-#define IMAGE_SYM_DTYPE_POINTER 0x10
-#define IMAGE_SYM_DTYPE_FUNCTION 0x20
-#define IMAGE_SYM_DTYPE_ARRAY 0x30
-#define IMAGE_SYM_CLASS_END_OF_FUNCTION (-1)
-#define IMAGE_SYM_CLASS_NULL 0
-#define IMAGE_SYM_CLASS_AUTOMATIC 1
-#define IMAGE_SYM_CLASS_EXTERNAL 2
-#define IMAGE_SYM_CLASS_STATIC 3
-#define IMAGE_SYM_CLASS_REGISTER 4
-#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5
-#define IMAGE_SYM_CLASS_LABEL 6
-#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
-#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
-#define IMAGE_SYM_CLASS_ARGUMENT 9
-#define IMAGE_SYM_CLASS_STRUCT_TAG 10
-#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
-#define IMAGE_SYM_CLASS_UNION_TAG 12
-#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13
-#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
-#define IMAGE_SYM_CLASS_ENUM_TAG 15
-#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
-#define IMAGE_SYM_CLASS_REGISTER_PARAM 17
-#define IMAGE_SYM_CLASS_BIT_FIELD 18
-#define IMAGE_SYM_CLASS_FAR_EXTERNAL 68 /* Not in PECOFF v8 spec */
-#define IMAGE_SYM_CLASS_BLOCK 100
-#define IMAGE_SYM_CLASS_FUNCTION 101
-#define IMAGE_SYM_CLASS_END_OF_STRUCT 102
-#define IMAGE_SYM_CLASS_FILE 103
-#define IMAGE_SYM_CLASS_SECTION 104
-#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
-#define IMAGE_SYM_CLASS_CLR_TOKEN 107
-
-#define IMAGE_REL_I386_ABSOLUTE 0x0000
-#define IMAGE_REL_I386_DIR16 0x0001
-#define IMAGE_REL_I386_REL16 0x0002
-#define IMAGE_REL_I386_DIR32 0x0006
-#define IMAGE_REL_I386_DIR32NB 0x0007
-#define IMAGE_REL_I386_SEG12 0x0009
-#define IMAGE_REL_I386_SECTION 0x000A
-#define IMAGE_REL_I386_SECREL 0x000B
-#define IMAGE_REL_I386_TOKEN 0x000C
-#define IMAGE_REL_I386_SECREL7 0x000D
-#define IMAGE_REL_I386_REL32 0x0014
-
-typedef struct PeSym PeSym;
-typedef struct PeSect PeSect;
-typedef struct PeObj PeObj;
-
-struct PeSym {
- char* name;
- uint32 value;
- uint16 sectnum;
- uint16 type;
- uint8 sclass;
- uint8 aux;
- Sym* sym;
-};
-
-struct PeSect {
- char* name;
- uchar* base;
- uint64 size;
- Sym* sym;
- IMAGE_SECTION_HEADER sh;
-};
-
-struct PeObj {
- Biobuf *f;
- char *name;
- uint32 base;
-
- PeSect *sect;
- uint nsect;
- PeSym *pesym;
- uint npesym;
-
- IMAGE_FILE_HEADER fh;
- char* snames;
-};
-
-static int map(PeObj *obj, PeSect *sect);
-static int readsym(PeObj *obj, int i, PeSym **sym);
-
-void
-ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- char *name;
- int32 base;
- int i, j, l, numaux;
- PeObj *obj;
- PeSect *sect, *rsect;
- IMAGE_SECTION_HEADER sh;
- uchar symbuf[18];
- Sym *s;
- Reloc *r, *rp;
- PeSym *sym;
-
- USED(len);
- USED(pkg);
- if(debug['v'])
- Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
-
- sect = nil;
- version++;
- base = Boffset(f);
-
- obj = mal(sizeof *obj);
- obj->f = f;
- obj->base = base;
- obj->name = pn;
- // read header
- if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
- goto bad;
- // load section list
- obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
- obj->nsect = obj->fh.NumberOfSections;
- for(i=0; i < obj->fh.NumberOfSections; i++) {
- if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
- goto bad;
- obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
- obj->sect[i].name = (char*)obj->sect[i].sh.Name;
- // TODO return error if found .cormeta
- }
- // load string table
- Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
- if(Bread(f, &l, sizeof l) != sizeof l)
- goto bad;
- obj->snames = mal(l);
- Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
- if(Bread(f, obj->snames, l) != l)
- goto bad;
- // read symbols
- obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
- obj->npesym = obj->fh.NumberOfSymbols;
- Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
- for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
- Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
- if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
- goto bad;
-
- if((symbuf[0] == 0) && (symbuf[1] == 0) &&
- (symbuf[2] == 0) && (symbuf[3] == 0)) {
- l = le32(&symbuf[4]);
- obj->pesym[i].name = (char*)&obj->snames[l];
- } else { // sym name length <= 8
- obj->pesym[i].name = mal(9);
- strncpy(obj->pesym[i].name, (char*)symbuf, 8);
- obj->pesym[i].name[8] = 0;
- }
- obj->pesym[i].value = le32(&symbuf[8]);
- obj->pesym[i].sectnum = le16(&symbuf[12]);
- obj->pesym[i].sclass = symbuf[16];
- obj->pesym[i].aux = symbuf[17];
- obj->pesym[i].type = le16(&symbuf[14]);
- numaux = obj->pesym[i].aux;
- if (numaux < 0)
- numaux = 0;
- }
- // create symbols for mapped sections
- for(i=0; i<obj->nsect; i++) {
- sect = &obj->sect[i];
- if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
- continue;
- if(map(obj, sect) < 0)
- goto bad;
-
- name = smprint("%s(%s)", pn, sect->name);
- s = lookup(name, version);
- free(name);
- switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
- IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
- case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
- s->type = SRODATA;
- break;
- case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
- case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
- s->type = SDATA;
- break;
- case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
- s->type = STEXT;
- break;
- default:
- werrstr("unexpected flags for PE section %s", sect->name);
- goto bad;
- }
- s->p = sect->base;
- s->np = sect->size;
- s->size = sect->size;
- if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- }
- sect->sym = s;
- if(strcmp(sect->name, ".rsrc") == 0)
- setpersrc(sect->sym);
- }
-
- // load relocations
- for(i=0; i<obj->nsect; i++) {
- rsect = &obj->sect[i];
- if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
- continue;
- if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
- continue;
- r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
- Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
- for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
- rp = &r[j];
- if(Bread(f, symbuf, 10) != 10)
- goto bad;
-
- uint32 rva, symindex;
- uint16 type;
- rva = le32(&symbuf[0]);
- symindex = le32(&symbuf[4]);
- type = le16(&symbuf[8]);
- if(readsym(obj, symindex, &sym) < 0)
- goto bad;
- if(sym->sym == nil) {
- werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
- goto bad;
- }
- rp->sym = sym->sym;
- rp->siz = 4;
- rp->off = rva;
- switch(type) {
- default:
- diag("%s: unknown relocation type %d;", pn, type);
- case IMAGE_REL_I386_REL32:
- rp->type = D_PCREL;
- rp->add = 0;
- break;
- case IMAGE_REL_I386_DIR32NB:
- case IMAGE_REL_I386_DIR32:
- rp->type = D_ADDR;
- // load addend from image
- rp->add = le32(rsect->base+rp->off);
- break;
- }
- }
- qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
-
- s = rsect->sym;
- s->r = r;
- s->nr = rsect->sh.NumberOfRelocations;
- }
-
- // enter sub-symbols into symbol table.
- // frist 2 entry is file name.
- for(i=2; i<obj->npesym; i++) {
- if(obj->pesym[i].name == 0)
- continue;
- if(obj->pesym[i].name[0] == '.') //skip section
- continue;
- if(obj->pesym[i].sectnum > 0) {
- sect = &obj->sect[obj->pesym[i].sectnum-1];
- if(sect->sym == 0)
- continue;
- }
- if(readsym(obj, i, &sym) < 0)
- goto bad;
-
- s = sym->sym;
- if(sym->sectnum == 0) {// extern
- if(s->type == SDYNIMPORT)
- s->plt = -2; // flag for dynimport in PE object files.
- continue;
- } else if (sym->sectnum > 0) {
- sect = &obj->sect[sym->sectnum-1];
- if(sect->sym == 0)
- diag("%s: %s sym == 0!", pn, s->name);
- } else {
- diag("%s: %s sectnum <0!", pn, s->name, sym->sectnum);
- }
-
- if(sect == nil)
- return;
- s->sub = sect->sym->sub;
- sect->sym->sub = s;
- s->type = sect->sym->type | SSUB;
- s->value = sym->value;
- s->size = 4;
- s->outer = sect->sym;
- if(sect->sym->type == STEXT) {
- Prog *p;
-
- if(s->text != P)
- diag("%s: duplicate definition of %s", pn, s->name);
- // build a TEXT instruction with a unique pc
- // just to make the rest of the linker happy.
- p = prg();
- p->as = ATEXT;
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->textflag = 7;
- p->to.type = D_CONST;
- p->link = nil;
- p->pc = pc++;
- s->text = p;
-
- etextp->next = s;
- etextp = s;
- }
- }
-
- return;
-bad:
- diag("%s: malformed pe file: %r", pn);
-}
-
-static int
-map(PeObj *obj, PeSect *sect)
-{
- if(sect->base != nil)
- return 0;
-
- sect->base = mal(sect->sh.SizeOfRawData);
- werrstr("short read");
- if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 ||
- Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData)
- return -1;
-
- return 0;
-}
-
-static int
-readsym(PeObj *obj, int i, PeSym **y)
-{
- Sym *s;
- PeSym *sym;
- char *name, *p;
-
- if(i >= obj->npesym || i < 0) {
- werrstr("invalid pe symbol index");
- return -1;
- }
-
- sym = &obj->pesym[i];
- *y = sym;
-
- name = sym->name;
- if(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0) // section
- name = obj->sect[sym->sectnum-1].sym->name;
- if(strncmp(sym->name, "__imp__", 7) == 0)
- name = &sym->name[7]; // __imp__Name => Name
- else if(sym->name[0] == '_')
- name = &sym->name[1]; // _Name => Name
- // remove last @XXX
- p = strchr(name, '@');
- if(p)
- *p = 0;
-
- switch(sym->type) {
- default:
- werrstr("%s: invalid symbol type %d", sym->name, sym->type);
- return -1;
- case IMAGE_SYM_DTYPE_FUNCTION:
- case IMAGE_SYM_DTYPE_NULL:
- switch(sym->sclass) {
- case IMAGE_SYM_CLASS_EXTERNAL: //global
- s = lookup(name, 0);
- break;
- case IMAGE_SYM_CLASS_NULL:
- case IMAGE_SYM_CLASS_STATIC:
- s = lookup(name, version);
- break;
- default:
- werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass);
- return -1;
- }
- break;
- }
-
- if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0))
- s->type = SXREF;
- if(strncmp(sym->name, "__imp__", 7) == 0)
- s->got = -2; // flag for __imp__
- sym->sym = s;
-
- return 0;
-}
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
deleted file mode 100644
index 77a62f5de..000000000
--- a/src/cmd/ld/lib.c
+++ /dev/null
@@ -1,1361 +0,0 @@
-// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.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 "l.h"
-#include "lib.h"
-#include "../../pkg/runtime/stack.h"
-
-#include <ar.h>
-
-int iconv(Fmt*);
-
-char symname[] = SYMDEF;
-char pkgname[] = "__.PKGDEF";
-char* libdir[16];
-int nlibdir = 0;
-int cout = -1;
-
-char* goroot;
-char* goarch;
-char* goos;
-
-void
-Lflag(char *arg)
-{
- if(nlibdir >= nelem(libdir)-1) {
- print("too many -L's: %d\n", nlibdir);
- usage();
- }
- libdir[nlibdir++] = arg;
-}
-
-void
-libinit(void)
-{
- fmtinstall('i', iconv);
- fmtinstall('Y', Yconv);
- mywhatsys(); // get goroot, goarch, goos
- if(strcmp(goarch, thestring) != 0)
- print("goarch is not known: %s\n", goarch);
-
- // add goroot to the end of the libdir list.
- libdir[nlibdir++] = smprint("%s/pkg/%s_%s", goroot, goos, goarch);
-
- remove(outfile);
- cout = create(outfile, 1, 0775);
- if(cout < 0) {
- diag("cannot create %s", outfile);
- errorexit();
- }
-
- if(INITENTRY == nil) {
- INITENTRY = mal(strlen(goarch)+strlen(goos)+10);
- sprint(INITENTRY, "_rt0_%s_%s", goarch, goos);
- }
- lookup(INITENTRY, 0)->type = SXREF;
-}
-
-void
-errorexit(void)
-{
- if(nerrors) {
- if(cout >= 0)
- remove(outfile);
- exits("error");
- }
- exits(0);
-}
-
-void
-addlib(char *src, char *obj)
-{
- char name[1024], pname[1024], comp[256], *p;
- int i, search;
-
- if(histfrogp <= 0)
- return;
-
- search = 0;
- if(histfrog[0]->name[1] == '/') {
- sprint(name, "");
- i = 1;
- } else
- if(isalpha(histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') {
- strcpy(name, histfrog[0]->name+1);
- i = 1;
- } else
- if(histfrog[0]->name[1] == '.') {
- sprint(name, ".");
- i = 0;
- } else {
- sprint(name, "");
- i = 0;
- search = 1;
- }
-
- for(; i<histfrogp; i++) {
- snprint(comp, sizeof comp, "%s", histfrog[i]->name+1);
- for(;;) {
- p = strstr(comp, "$O");
- if(p == 0)
- break;
- memmove(p+1, p+2, strlen(p+2)+1);
- p[0] = thechar;
- }
- for(;;) {
- p = strstr(comp, "$M");
- if(p == 0)
- break;
- if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
- diag("library component too long");
- return;
- }
- memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
- memmove(p, thestring, strlen(thestring));
- }
- if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
- diag("library component too long");
- return;
- }
- if(i > 0 || !search)
- strcat(name, "/");
- strcat(name, comp);
- }
- cleanname(name);
-
- // runtime.a -> runtime
- p = nil;
- if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
- p = name+strlen(name)-2;
- *p = '\0';
- }
-
- // already loaded?
- for(i=0; i<libraryp; i++)
- if(strcmp(library[i].pkg, name) == 0)
- return;
-
- // runtime -> runtime.a for search
- if(p != nil)
- *p = '.';
-
- if(search) {
- // try dot, -L "libdir", and then goroot.
- for(i=0; i<nlibdir; i++) {
- snprint(pname, sizeof pname, "%s/%s", libdir[i], name);
- if(access(pname, AEXIST) >= 0)
- break;
- }
- }else
- strcpy(pname, name);
- cleanname(pname);
-
- /* runtime.a -> runtime */
- if(p != nil)
- *p = '\0';
-
- if(debug['v'])
- Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
-
- addlibpath(src, obj, pname, name);
-}
-
-/*
- * add library to library list.
- * srcref: src file referring to package
- * objref: object file referring to package
- * file: object file, e.g., /home/rsc/go/pkg/container/vector.a
- * pkg: package import path, e.g. container/vector
- */
-void
-addlibpath(char *srcref, char *objref, char *file, char *pkg)
-{
- int i;
- Library *l;
- char *p;
-
- for(i=0; i<libraryp; i++)
- if(strcmp(file, library[i].file) == 0)
- return;
-
- if(debug['v'] > 1)
- Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
- cputime(), srcref, objref, file, pkg);
-
- if(libraryp == nlibrary){
- nlibrary = 50 + 2*libraryp;
- library = realloc(library, sizeof library[0] * nlibrary);
- }
-
- l = &library[libraryp++];
-
- p = mal(strlen(objref) + 1);
- strcpy(p, objref);
- l->objref = p;
-
- p = mal(strlen(srcref) + 1);
- strcpy(p, srcref);
- l->srcref = p;
-
- p = mal(strlen(file) + 1);
- strcpy(p, file);
- l->file = p;
-
- p = mal(strlen(pkg) + 1);
- strcpy(p, pkg);
- l->pkg = p;
-}
-
-void
-loadinternal(char *name)
-{
- char pname[1024];
- int i, found;
-
- found = 0;
- for(i=0; i<nlibdir; i++) {
- snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name);
- if(debug['v'])
- Bprint(&bso, "searching for %s.a in %s\n", name, pname);
- if(access(pname, AEXIST) >= 0) {
- addlibpath("internal", "internal", pname, name);
- found = 1;
- break;
- }
- }
- if(!found)
- Bprint(&bso, "warning: unable to find %s.a\n", name);
-}
-
-void
-loadlib(void)
-{
- int i;
-
- loadinternal("runtime");
- if(thechar == '5')
- loadinternal("math");
-
- for(i=0; i<libraryp; i++) {
- if(debug['v'])
- Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref);
- objfile(library[i].file, library[i].pkg);
- }
-
- // We've loaded all the code now.
- // If there are no dynamic libraries needed, gcc disables dynamic linking.
- // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
- // assumes that a dynamic binary always refers to at least one dynamic library.
- // Rather than be a source of test cases for glibc, disable dynamic linking
- // the same way that gcc would.
- //
- // Exception: on OS X, programs such as Shark only work with dynamic
- // binaries, so leave it enabled on OS X (Mach-O) binaries.
- if(!havedynamic && HEADTYPE != Hdarwin)
- debug['d'] = 1;
-}
-
-/*
- * look for the next file in an archive.
- * adapted from libmach.
- */
-int
-nextar(Biobuf *bp, int off, struct ar_hdr *a)
-{
- int r;
- int32 arsize;
-
- if (off&01)
- off++;
- Bseek(bp, off, 0);
- r = Bread(bp, a, SAR_HDR);
- if(r != SAR_HDR)
- return 0;
- if(strncmp(a->fmag, ARFMAG, sizeof(a->fmag)))
- return -1;
- arsize = strtol(a->size, 0, 0);
- if (arsize&1)
- arsize++;
- return arsize + SAR_HDR;
-}
-
-void
-objfile(char *file, char *pkg)
-{
- int32 off, l;
- Biobuf *f;
- char magbuf[SARMAG];
- char pname[150];
- struct ar_hdr arhdr;
-
- pkg = smprint("%i", pkg);
-
- if(debug['v'])
- Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg);
- Bflush(&bso);
- f = Bopen(file, 0);
- if(f == nil) {
- diag("cannot open file: %s", file);
- errorexit();
- }
- l = Bread(f, magbuf, SARMAG);
- if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
- /* load it as a regular file */
- l = Bseek(f, 0L, 2);
- Bseek(f, 0L, 0);
- ldobj(f, pkg, l, file, FileObj);
- Bterm(f);
- return;
- }
-
- /* skip over __.SYMDEF */
- off = Boffset(f);
- if((l = nextar(f, off, &arhdr)) <= 0) {
- diag("%s: short read on archive file symbol header", file);
- goto out;
- }
- if(strncmp(arhdr.name, symname, strlen(symname))) {
- diag("%s: first entry not symbol header", file);
- goto out;
- }
- off += l;
-
- /* skip over (or process) __.PKGDEF */
- if((l = nextar(f, off, &arhdr)) <= 0) {
- diag("%s: short read on archive file symbol header", file);
- goto out;
- }
- if(strncmp(arhdr.name, pkgname, strlen(pkgname))) {
- diag("%s: second entry not package header", file);
- goto out;
- }
- off += l;
-
- if(debug['u'])
- ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef);
-
- /*
- * load all the object files from the archive now.
- * this gives us sequential file access and keeps us
- * from needing to come back later to pick up more
- * objects. it breaks the usual C archive model, but
- * this is Go, not C. the common case in Go is that
- * we need to load all the objects, and then we throw away
- * the individual symbols that are unused.
- *
- * loading every object will also make it possible to
- * load foreign objects not referenced by __.SYMDEF.
- */
- for(;;) {
- l = nextar(f, off, &arhdr);
- if(l == 0)
- break;
- if(l < 0) {
- diag("%s: malformed archive", file);
- goto out;
- }
- off += l;
-
- l = SARNAME;
- while(l > 0 && arhdr.name[l-1] == ' ')
- l--;
- snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
- l = atolwhex(arhdr.size);
- ldobj(f, pkg, l, pname, ArchiveObj);
- }
-
-out:
- Bterm(f);
-}
-
-void
-ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
-{
- char *line;
- int n, c1, c2, c3, c4;
- uint32 magic;
- vlong import0, import1, eof;
- char *t;
-
- eof = Boffset(f) + len;
-
- pn = strdup(pn);
-
- c1 = Bgetc(f);
- c2 = Bgetc(f);
- c3 = Bgetc(f);
- c4 = Bgetc(f);
- Bungetc(f);
- Bungetc(f);
- Bungetc(f);
- Bungetc(f);
-
- magic = c1<<24 | c2<<16 | c3<<8 | c4;
- if(magic == 0x7f454c46) { // \x7F E L F
- ldelf(f, pkg, len, pn);
- return;
- }
- if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
- ldmacho(f, pkg, len, pn);
- return;
- }
- if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
- ldpe(f, pkg, len, pn);
- return;
- }
-
- /* check the header */
- line = Brdline(f, '\n');
- if(line == nil) {
- if(Blinelen(f) > 0) {
- diag("%s: not an object file", pn);
- return;
- }
- goto eof;
- }
- n = Blinelen(f) - 1;
- line[n] = '\0';
- if(strncmp(line, "go object ", 10) != 0) {
- if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) {
- print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thechar, pn, thechar, thechar);
- errorexit();
- }
- if(strcmp(line, thestring) == 0) {
- // old header format: just $GOOS
- diag("%s: stale object file", pn);
- return;
- }
- diag("%s: not an object file", pn);
- return;
- }
- t = smprint("%s %s %s", getgoos(), thestring, getgoversion());
- if(strcmp(line+10, t) != 0 && !debug['f']) {
- diag("%s: object is [%s] expected [%s]", pn, line+10, t);
- free(t);
- return;
- }
- free(t);
- line[n] = '\n';
-
- /* skip over exports and other info -- ends with \n!\n */
- import0 = Boffset(f);
- c1 = '\n'; // the last line ended in \n
- c2 = Bgetc(f);
- c3 = Bgetc(f);
- while(c1 != '\n' || c2 != '!' || c3 != '\n') {
- c1 = c2;
- c2 = c3;
- c3 = Bgetc(f);
- if(c3 == Beof)
- goto eof;
- }
- import1 = Boffset(f);
-
- Bseek(f, import0, 0);
- ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n
- Bseek(f, import1, 0);
-
- ldobj1(f, pkg, eof - Boffset(f), pn);
- return;
-
-eof:
- diag("truncated object file: %s", pn);
-}
-
-static Sym*
-_lookup(char *symb, int v, int creat)
-{
- Sym *s;
- char *p;
- int32 h;
- int l, c;
-
- h = v;
- for(p=symb; c = *p; p++)
- h = h+h+h + c;
- l = (p - symb) + 1;
- // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
- h &= 0xffffff;
- h %= NHASH;
- for(s = hash[h]; s != S; s = s->hash)
- if(memcmp(s->name, symb, l) == 0)
- return s;
- if(!creat)
- return nil;
-
- s = mal(sizeof(*s));
- if(debug['v'] > 1)
- Bprint(&bso, "lookup %s\n", symb);
-
- s->dynid = -1;
- s->plt = -1;
- s->got = -1;
- s->name = mal(l + 1);
- memmove(s->name, symb, l);
-
- s->hash = hash[h];
- s->type = 0;
- s->version = v;
- s->value = 0;
- s->sig = 0;
- s->size = 0;
- hash[h] = s;
- nsymbol++;
-
- s->allsym = allsym;
- allsym = s;
- return s;
-}
-
-Sym*
-lookup(char *name, int v)
-{
- return _lookup(name, v, 1);
-}
-
-// read-only lookup
-Sym*
-rlookup(char *name, int v)
-{
- return _lookup(name, v, 0);
-}
-
-void
-copyhistfrog(char *buf, int nbuf)
-{
- char *p, *ep;
- int i;
-
- p = buf;
- ep = buf + nbuf;
- for(i=0; i<histfrogp; i++) {
- p = seprint(p, ep, "%s", histfrog[i]->name+1);
- if(i+1<histfrogp && (p == buf || p[-1] != '/'))
- p = seprint(p, ep, "/");
- }
-}
-
-void
-addhist(int32 line, int type)
-{
- Auto *u;
- Sym *s;
- int i, j, k;
-
- u = mal(sizeof(Auto));
- s = mal(sizeof(Sym));
- s->name = mal(2*(histfrogp+1) + 1);
-
- u->asym = s;
- u->type = type;
- u->aoffset = line;
- u->link = curhist;
- curhist = u;
-
- s->name[0] = 0;
- j = 1;
- for(i=0; i<histfrogp; i++) {
- k = histfrog[i]->value;
- s->name[j+0] = k>>8;
- s->name[j+1] = k;
- j += 2;
- }
- s->name[j] = 0;
- s->name[j+1] = 0;
-}
-
-void
-histtoauto(void)
-{
- Auto *l;
-
- while(l = curhist) {
- curhist = l->link;
- l->link = curauto;
- curauto = l;
- }
-}
-
-void
-collapsefrog(Sym *s)
-{
- int i;
-
- /*
- * bad encoding of path components only allows
- * MAXHIST components. if there is an overflow,
- * first try to collapse xxx/..
- */
- for(i=1; i<histfrogp; i++)
- if(strcmp(histfrog[i]->name+1, "..") == 0) {
- memmove(histfrog+i-1, histfrog+i+1,
- (histfrogp-i-1)*sizeof(histfrog[0]));
- histfrogp--;
- goto out;
- }
-
- /*
- * next try to collapse .
- */
- for(i=0; i<histfrogp; i++)
- if(strcmp(histfrog[i]->name+1, ".") == 0) {
- memmove(histfrog+i, histfrog+i+1,
- (histfrogp-i-1)*sizeof(histfrog[0]));
- goto out;
- }
-
- /*
- * last chance, just truncate from front
- */
- memmove(histfrog+0, histfrog+1,
- (histfrogp-1)*sizeof(histfrog[0]));
-
-out:
- histfrog[histfrogp-1] = s;
-}
-
-void
-nuxiinit(void)
-{
- int i, c;
-
- for(i=0; i<4; i++) {
- c = find1(0x04030201L, i+1);
- if(i < 2)
- inuxi2[i] = c;
- if(i < 1)
- inuxi1[i] = c;
- inuxi4[i] = c;
- if(c == i) {
- inuxi8[i] = c;
- inuxi8[i+4] = c+4;
- } else {
- inuxi8[i] = c+4;
- inuxi8[i+4] = c;
- }
- fnuxi4[i] = c;
- fnuxi8[i] = c;
- fnuxi8[i+4] = c+4;
- }
- if(debug['v']) {
- Bprint(&bso, "inuxi = ");
- for(i=0; i<1; i++)
- Bprint(&bso, "%d", inuxi1[i]);
- Bprint(&bso, " ");
- for(i=0; i<2; i++)
- Bprint(&bso, "%d", inuxi2[i]);
- Bprint(&bso, " ");
- for(i=0; i<4; i++)
- Bprint(&bso, "%d", inuxi4[i]);
- Bprint(&bso, " ");
- for(i=0; i<8; i++)
- Bprint(&bso, "%d", inuxi8[i]);
- Bprint(&bso, "\nfnuxi = ");
- for(i=0; i<4; i++)
- Bprint(&bso, "%d", fnuxi4[i]);
- Bprint(&bso, " ");
- for(i=0; i<8; i++)
- Bprint(&bso, "%d", fnuxi8[i]);
- Bprint(&bso, "\n");
- }
- Bflush(&bso);
-}
-
-int
-find1(int32 l, int c)
-{
- char *p;
- int i;
-
- p = (char*)&l;
- for(i=0; i<4; i++)
- if(*p++ == c)
- return i;
- return 0;
-}
-
-int
-find2(int32 l, int c)
-{
- union {
- int32 l;
- short p[2];
- } u;
- short *p;
- int i;
-
- u.l = l;
- p = u.p;
- for(i=0; i<4; i+=2) {
- if(((*p >> 8) & 0xff) == c)
- return i;
- if((*p++ & 0xff) == c)
- return i+1;
- }
- return 0;
-}
-
-int32
-ieeedtof(Ieee *e)
-{
- int exp;
- int32 v;
-
- if(e->h == 0)
- return 0;
- exp = (e->h>>20) & ((1L<<11)-1L);
- exp -= (1L<<10) - 2L;
- v = (e->h & 0xfffffL) << 3;
- v |= (e->l >> 29) & 0x7L;
- if((e->l >> 28) & 1) {
- v++;
- if(v & 0x800000L) {
- v = (v & 0x7fffffL) >> 1;
- exp++;
- }
- }
- if(-148 <= exp && exp <= -126) {
- v |= 1<<23;
- v >>= -125 - exp;
- exp = -126;
- }
- else if(exp < -148 || exp >= 130)
- diag("double fp to single fp overflow: %.17g", ieeedtod(e));
- v |= ((exp + 126) & 0xffL) << 23;
- v |= e->h & 0x80000000L;
- return v;
-}
-
-double
-ieeedtod(Ieee *ieeep)
-{
- Ieee e;
- double fr;
- int exp;
-
- if(ieeep->h & (1L<<31)) {
- e.h = ieeep->h & ~(1L<<31);
- e.l = ieeep->l;
- return -ieeedtod(&e);
- }
- if(ieeep->l == 0 && ieeep->h == 0)
- return 0;
- exp = (ieeep->h>>20) & ((1L<<11)-1L);
- exp -= (1L<<10) - 2L;
- fr = ieeep->l & ((1L<<16)-1L);
- fr /= 1L<<16;
- fr += (ieeep->l>>16) & ((1L<<16)-1L);
- fr /= 1L<<16;
- if(exp == -(1L<<10) - 2L) {
- fr += (ieeep->h & (1L<<20)-1L);
- exp++;
- } else
- fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
- fr /= 1L<<21;
- return ldexp(fr, exp);
-}
-
-void
-zerosig(char *sp)
-{
- Sym *s;
-
- s = lookup(sp, 0);
- s->sig = 0;
-}
-
-int32
-Bget4(Biobuf *f)
-{
- uchar p[4];
-
- if(Bread(f, p, 4) != 4)
- return 0;
- return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
-}
-
-void
-mywhatsys(void)
-{
- goroot = getgoroot();
- goos = getgoos();
- goarch = thestring; // ignore $GOARCH - we know who we are
-}
-
-int
-pathchar(void)
-{
- return '/';
-}
-
-static uchar* hunk;
-static uint32 nhunk;
-#define NHUNK (10UL<<20)
-
-void*
-mal(uint32 n)
-{
- void *v;
-
- n = (n+7)&~7;
- if(n > NHUNK) {
- v = malloc(n);
- if(v == nil) {
- diag("out of memory");
- errorexit();
- }
- memset(v, 0, n);
- return v;
- }
- if(n > nhunk) {
- hunk = malloc(NHUNK);
- if(hunk == nil) {
- diag("out of memory");
- errorexit();
- }
- nhunk = NHUNK;
- }
-
- v = hunk;
- nhunk -= n;
- hunk += n;
-
- memset(v, 0, n);
- return v;
-}
-
-void
-unmal(void *v, uint32 n)
-{
- n = (n+7)&~7;
- if(hunk - n == v) {
- hunk -= n;
- nhunk += n;
- }
-}
-
-// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
-/*
- * Convert raw string to the prefix that will be used in the symbol table.
- * Invalid bytes turn into %xx. Right now the only bytes that need
- * escaping are %, ., and ", but we escape all control characters too.
- */
-static char*
-pathtoprefix(char *s)
-{
- static char hex[] = "0123456789abcdef";
- char *p, *r, *w;
- int n;
-
- // check for chars that need escaping
- n = 0;
- for(r=s; *r; r++)
- if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"')
- n++;
-
- // quick exit
- if(n == 0)
- return s;
-
- // escape
- p = mal((r-s)+1+2*n);
- for(r=s, w=p; *r; r++) {
- if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') {
- *w++ = '%';
- *w++ = hex[(*r>>4)&0xF];
- *w++ = hex[*r&0xF];
- } else
- *w++ = *r;
- }
- *w = '\0';
- return p;
-}
-
-int
-iconv(Fmt *fp)
-{
- char *p;
-
- p = va_arg(fp->args, char*);
- if(p == nil) {
- fmtstrcpy(fp, "<nil>");
- return 0;
- }
- p = pathtoprefix(p);
- fmtstrcpy(fp, p);
- return 0;
-}
-
-void
-mangle(char *file)
-{
- fprint(2, "%s: mangled input file\n", file);
- errorexit();
-}
-
-Section*
-addsection(Segment *seg, char *name, int rwx)
-{
- Section **l;
- Section *sect;
-
- for(l=&seg->sect; *l; l=&(*l)->next)
- ;
- sect = mal(sizeof *sect);
- sect->rwx = rwx;
- sect->name = name;
- sect->seg = seg;
- *l = sect;
- return sect;
-}
-
-void
-ewrite(int fd, void *buf, int n)
-{
- if(write(fd, buf, n) < 0) {
- diag("write error: %r");
- errorexit();
- }
-}
-
-void
-pclntab(void)
-{
- vlong oldpc;
- Prog *p;
- int32 oldlc, v, s;
- Sym *sym;
- uchar *bp;
-
- sym = lookup("pclntab", 0);
- sym->type = SPCLNTAB;
- sym->reachable = 1;
- if(debug['s'])
- return;
-
- oldpc = INITTEXT;
- oldlc = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
- if(debug['O'])
- Bprint(&bso, "%6llux %P\n",
- (vlong)p->pc, p);
- continue;
- }
- if(debug['O'])
- Bprint(&bso, "\t\t%6d", lcsize);
- v = (p->pc - oldpc) / MINLC;
- while(v) {
- s = 127;
- if(v < 127)
- s = v;
- symgrow(sym, lcsize+1);
- bp = sym->p + lcsize;
- *bp = s+128; /* 129-255 +pc */
- if(debug['O'])
- Bprint(&bso, " pc+%d*%d(%d)", s, MINLC, s+128);
- v -= s;
- lcsize++;
- }
- s = p->line - oldlc;
- oldlc = p->line;
- oldpc = p->pc + MINLC;
- if(s > 64 || s < -64) {
- symgrow(sym, lcsize+5);
- bp = sym->p + lcsize;
- *bp++ = 0; /* 0 vv +lc */
- *bp++ = s>>24;
- *bp++ = s>>16;
- *bp++ = s>>8;
- *bp = s;
- if(debug['O']) {
- if(s > 0)
- Bprint(&bso, " lc+%d(%d,%d)\n",
- s, 0, s);
- else
- Bprint(&bso, " lc%d(%d,%d)\n",
- s, 0, s);
- Bprint(&bso, "%6llux %P\n",
- (vlong)p->pc, p);
- }
- lcsize += 5;
- continue;
- }
- symgrow(sym, lcsize+1);
- bp = sym->p + lcsize;
- if(s > 0) {
- *bp = 0+s; /* 1-64 +lc */
- if(debug['O']) {
- Bprint(&bso, " lc+%d(%d)\n", s, 0+s);
- Bprint(&bso, "%6llux %P\n",
- (vlong)p->pc, p);
- }
- } else {
- *bp = 64-s; /* 65-128 -lc */
- if(debug['O']) {
- Bprint(&bso, " lc%d(%d)\n", s, 64-s);
- Bprint(&bso, "%6llux %P\n",
- (vlong)p->pc, p);
- }
- }
- lcsize++;
- }
- }
- if(lcsize & 1) {
- symgrow(sym, lcsize+1);
- sym->p[lcsize] = 129;
- lcsize++;
- }
- sym->size = lcsize;
- lcsize = 0;
-
- if(debug['v'] || debug['O'])
- Bprint(&bso, "lcsize = %d\n", lcsize);
- Bflush(&bso);
-}
-
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int i;
- int32 dwn[LOG], cnt[LOG];
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1;
- else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- if(p->link == P) {
- if(cursym->next)
- p->forwd = cursym->next->text;
- break;
- }
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
- }
- }
- }
-}
-
-uint16
-le16(uchar *b)
-{
- return b[0] | b[1]<<8;
-}
-
-uint32
-le32(uchar *b)
-{
- return b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
-}
-
-uint64
-le64(uchar *b)
-{
- return le32(b) | (uint64)le32(b+4)<<32;
-}
-
-uint16
-be16(uchar *b)
-{
- return b[0]<<8 | b[1];
-}
-
-uint32
-be32(uchar *b)
-{
- return b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3];
-}
-
-uint64
-be64(uchar *b)
-{
- return (uvlong)be32(b)<<32 | be32(b+4);
-}
-
-Endian be = { be16, be32, be64 };
-Endian le = { le16, le32, le64 };
-
-typedef struct Chain Chain;
-struct Chain
-{
- Sym *sym;
- Chain *up;
- int limit; // limit on entry to sym
-};
-
-static int stkcheck(Chain*, int);
-static void stkprint(Chain*, int);
-static void stkbroke(Chain*, int);
-static Sym *morestack;
-static Sym *newstack;
-
-enum
-{
- HasLinkRegister = (thechar == '5'),
- CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call
-};
-
-void
-dostkcheck(void)
-{
- Chain ch;
- Sym *s;
-
- morestack = lookup("runtime.morestack", 0);
- newstack = lookup("runtime.newstack", 0);
-
- // First the nosplits on their own.
- for(s = textp; s != nil; s = s->next) {
- if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0)
- continue;
- cursym = s;
- ch.up = nil;
- ch.sym = s;
- ch.limit = StackLimit - CallSize;
- stkcheck(&ch, 0);
- s->stkcheck = 1;
- }
-
- // Check calling contexts.
- // Some nosplits get called a little further down,
- // like newproc and deferproc. We could hard-code
- // that knowledge but it's more robust to look at
- // the actual call sites.
- for(s = textp; s != nil; s = s->next) {
- if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0)
- continue;
- cursym = s;
- ch.up = nil;
- ch.sym = s;
- ch.limit = StackLimit - CallSize;
- stkcheck(&ch, 0);
- }
-}
-
-static int
-stkcheck(Chain *up, int depth)
-{
- Chain ch, ch1;
- Prog *p;
- Sym *s;
- int limit, prolog;
-
- limit = up->limit;
- s = up->sym;
- p = s->text;
-
- // Small optimization: don't repeat work at top.
- if(s->stkcheck && limit == StackLimit-CallSize)
- return 0;
-
- if(depth > 100) {
- diag("nosplit stack check too deep");
- stkbroke(up, 0);
- return -1;
- }
-
- if(p == nil || p->link == nil) {
- // external function.
- // should never be called directly.
- // only diagnose the direct caller.
- if(depth == 1)
- diag("call to external function %s", s->name);
- return -1;
- }
-
- if(limit < 0) {
- stkbroke(up, limit);
- return -1;
- }
-
- // morestack looks like it calls functions,
- // but it switches the stack pointer first.
- if(s == morestack)
- return 0;
-
- ch.up = up;
- prolog = (s->text->textflag & NOSPLIT) == 0;
- for(p = s->text; p != P; p = p->link) {
- limit -= p->spadj;
- if(prolog && p->spadj != 0) {
- // The first stack adjustment in a function with a
- // split-checking prologue marks the end of the
- // prologue. Assuming the split check is correct,
- // after the adjustment there should still be at least
- // StackLimit bytes available below the stack pointer.
- // If this is not the top call in the chain, no need
- // to duplicate effort, so just stop.
- if(depth > 0)
- return 0;
- prolog = 0;
- limit = StackLimit;
- }
- if(limit < 0) {
- stkbroke(up, limit);
- return -1;
- }
- if(iscall(p)) {
- limit -= CallSize;
- ch.limit = limit;
- if(p->to.type == D_BRANCH) {
- // Direct call.
- ch.sym = p->to.sym;
- if(stkcheck(&ch, depth+1) < 0)
- return -1;
- } else {
- // Indirect call. Assume it is a splitting function,
- // so we have to make sure it can call morestack.
- limit -= CallSize;
- ch.sym = nil;
- ch1.limit = limit;
- ch1.up = &ch;
- ch1.sym = morestack;
- if(stkcheck(&ch1, depth+2) < 0)
- return -1;
- limit += CallSize;
- }
- limit += CallSize;
- }
-
- }
- return 0;
-}
-
-static void
-stkbroke(Chain *ch, int limit)
-{
- diag("nosplit stack overflow");
- stkprint(ch, limit);
-}
-
-static void
-stkprint(Chain *ch, int limit)
-{
- char *name;
-
- if(ch->sym)
- name = ch->sym->name;
- else
- name = "function pointer";
-
- if(ch->up == nil) {
- // top of chain. ch->sym != nil.
- if(ch->sym->text->textflag & NOSPLIT)
- print("\t%d\tassumed on entry to %s\n", ch->limit, name);
- else
- print("\t%d\tguaranteed after split check in %s\n", ch->limit, name);
- } else {
- stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize);
- if(!HasLinkRegister)
- print("\t%d\ton entry to %s\n", ch->limit, name);
- }
- if(ch->limit != limit)
- print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit);
-}
-
-int
-headtype(char *name)
-{
- int i;
-
- for(i=0; headers[i].name; i++)
- if(strcmp(name, headers[i].name) == 0) {
- headstring = headers[i].name;
- return headers[i].val;
- }
- fprint(2, "unknown header type -H %s\n", name);
- errorexit();
- return -1; // not reached
-}
-
-void
-undef(void)
-{
- Sym *s;
-
- for(s = allsym; s != S; s = s->allsym)
- if(s->type == SXREF)
- diag("%s(%d): not defined", s->name, s->version);
-}
-
-int
-Yconv(Fmt *fp)
-{
- Sym *s;
- Fmt fmt;
- int i;
- char *str;
-
- s = va_arg(fp->args, Sym*);
- if (s == S) {
- fmtprint(fp, "<nil>");
- } else {
- fmtstrinit(&fmt);
- fmtprint(&fmt, "%s @0x%08x [%d]", s->name, s->value, s->size);
- for (i = 0; i < s->size; i++) {
- if (!(i%8)) fmtprint(&fmt, "\n\t0x%04x ", i);
- fmtprint(&fmt, "%02x ", s->p[i]);
- }
- fmtprint(&fmt, "\n");
- for (i = 0; i < s->nr; i++) {
- fmtprint(&fmt, "\t0x%04x[%x] %d %s[%llx]\n",
- s->r[i].off,
- s->r[i].siz,
- s->r[i].type,
- s->r[i].sym->name,
- (vlong)s->r[i].add);
- }
- str = fmtstrflush(&fmt);
- fmtstrcpy(fp, str);
- free(str);
- }
-
- return 0;
-}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
deleted file mode 100644
index 347987195..000000000
--- a/src/cmd/ld/lib.h
+++ /dev/null
@@ -1,281 +0,0 @@
-// Derived from Inferno utils/6l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.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.
-
-enum
-{
- Sxxx,
-
- /* order here is order in output file */
- STEXT,
- SELFDATA,
- SMACHOPLT,
- STYPE,
- SSTRING,
- SGOSTRING,
- SRODATA,
- SSYMTAB,
- SPCLNTAB,
- SDATA,
- SMACHO, /* Mach-O __nl_symbol_ptr */
- SMACHOGOT,
- SWINDOWS,
- SBSS,
-
- SXREF,
- SMACHODYNSTR,
- SMACHODYNSYM,
- SMACHOINDIRECTPLT,
- SMACHOINDIRECTGOT,
- SFILE,
- SCONST,
- SDYNIMPORT,
-
- SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
-
- NHASH = 100003,
-};
-
-typedef struct Library Library;
-struct Library
-{
- char *objref; // object where we found the reference
- char *srcref; // src file where we found the reference
- char *file; // object file
- char *pkg; // import path
-};
-
-// Terrible but standard terminology.
-// A segment describes a block of file to load into memory.
-// A section further describes the pieces of that block for
-// use in debuggers and such.
-
-typedef struct Segment Segment;
-typedef struct Section Section;
-
-struct Segment
-{
- uchar rwx; // permission as usual unix bits (5 = r-x etc)
- uvlong vaddr; // virtual address
- uvlong len; // length in memory
- uvlong fileoff; // file offset
- uvlong filelen; // length on disk
- Section* sect;
-};
-
-struct Section
-{
- uchar rwx;
- char *name;
- uvlong vaddr;
- uvlong len;
- Section *next; // in segment list
- Segment *seg;
-};
-
-extern char symname[];
-extern char *libdir[];
-extern int nlibdir;
-extern int cout;
-
-EXTERN char* INITENTRY;
-EXTERN char* thestring;
-EXTERN Library* library;
-EXTERN int libraryp;
-EXTERN int nlibrary;
-EXTERN Sym* hash[NHASH];
-EXTERN Sym* allsym;
-EXTERN Sym* histfrog[MAXHIST];
-EXTERN uchar fnuxi8[8];
-EXTERN uchar fnuxi4[4];
-EXTERN int histfrogp;
-EXTERN int histgen;
-EXTERN uchar inuxi1[1];
-EXTERN uchar inuxi2[2];
-EXTERN uchar inuxi4[4];
-EXTERN uchar inuxi8[8];
-EXTERN char* outfile;
-EXTERN int32 nsymbol;
-EXTERN char* thestring;
-EXTERN int ndynexp;
-EXTERN int havedynamic;
-
-EXTERN Segment segtext;
-EXTERN Segment segdata;
-EXTERN Segment segsym;
-
-void addlib(char *src, char *obj);
-void addlibpath(char *srcref, char *objref, char *file, char *pkg);
-Section* addsection(Segment*, char*, int);
-void copyhistfrog(char *buf, int nbuf);
-void addhist(int32 line, int type);
-void asmlc(void);
-void histtoauto(void);
-void collapsefrog(Sym *s);
-Sym* lookup(char *symb, int v);
-Sym* rlookup(char *symb, int v);
-void nuxiinit(void);
-int find1(int32 l, int c);
-int find2(int32 l, int c);
-int32 ieeedtof(Ieee *e);
-double ieeedtod(Ieee *e);
-void undefsym(Sym *s);
-void zerosig(char *sp);
-void readundefs(char *f, int t);
-int32 Bget4(Biobuf *f);
-void loadlib(void);
-void errorexit(void);
-void mangle(char*);
-void objfile(char *file, char *pkg);
-void libinit(void);
-void pclntab(void);
-void symtab(void);
-void Lflag(char *arg);
-void usage(void);
-void adddynrel(Sym*, Reloc*);
-void ldobj1(Biobuf *f, char*, int64 len, char *pn);
-void ldobj(Biobuf*, char*, int64, char*, int);
-void ldelf(Biobuf*, char*, int64, char*);
-void ldmacho(Biobuf*, char*, int64, char*);
-void ldpe(Biobuf*, char*, int64, char*);
-void ldpkg(Biobuf*, char*, int64, char*, int);
-void mark(Sym *s);
-void mkfwd(void);
-char* expandpkg(char*, char*);
-void deadcode(void);
-void ewrite(int, void*, int);
-Reloc* addrel(Sym*);
-void codeblk(int32, int32);
-void datblk(int32, int32);
-Sym* datsort(Sym*);
-void reloc(void);
-void relocsym(Sym*);
-void savedata(Sym*, Prog*, char*);
-void symgrow(Sym*, int32);
-vlong addstring(Sym*, char*);
-vlong adduint32(Sym*, uint32);
-vlong adduint64(Sym*, uint64);
-vlong addaddr(Sym*, Sym*);
-vlong addaddrplus(Sym*, Sym*, int32);
-vlong addpcrelplus(Sym*, Sym*, int32);
-vlong addsize(Sym*, Sym*);
-vlong adduint8(Sym*, uint8);
-vlong adduint16(Sym*, uint16);
-void asmsym(void);
-void asmelfsym(void);
-void asmplan9sym(void);
-void strnput(char*, int);
-void dodata(void);
-void address(void);
-void textaddress(void);
-void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*));
-vlong datoff(vlong);
-void adddynlib(char*);
-int archreloc(Reloc*, Sym*, vlong*);
-void adddynsym(Sym*);
-void addexport(void);
-void dostkcheck(void);
-void undef(void);
-void doweak(void);
-void setpersrc(Sym*);
-
-int pathchar(void);
-void* mal(uint32);
-void unmal(void*, uint32);
-void mywhatsys(void);
-int rbyoff(const void*, const void*);
-
-uint16 le16(uchar*);
-uint32 le32(uchar*);
-uint64 le64(uchar*);
-uint16 be16(uchar*);
-uint32 be32(uchar*);
-uint64 be64(uchar*);
-
-typedef struct Endian Endian;
-struct Endian
-{
- uint16 (*e16)(uchar*);
- uint32 (*e32)(uchar*);
- uint64 (*e64)(uchar*);
-};
-
-extern Endian be, le;
-
-// relocation size bits
-enum {
- Rbig = 128,
- Rlittle = 64,
-};
-
-/* set by call to mywhatsys() */
-extern char* goroot;
-extern char* goarch;
-extern char* goos;
-
-/* whence for ldpkg */
-enum {
- FileObj = 0,
- ArchiveObj,
- Pkgdef
-};
-
-/* executable header types */
-enum {
- Hgarbunix = 0, // garbage unix
- Hnoheader, // no header
- Hunixcoff, // unix coff
- Hrisc, // aif for risc os
- Hplan9x32, // plan 9 32-bit format
- Hplan9x64, // plan 9 64-bit format
- Hmsdoscom, // MS-DOS .COM
- Hnetbsd, // NetBSD
- Hmsdosexe, // fake MS-DOS .EXE
- Hixp1200, // IXP1200 (raw)
- Helf, // ELF32
- Hipaq, // ipaq
- Hdarwin, // Apple Mach-O
- Hlinux, // Linux ELF
- Hfreebsd, // FreeBSD ELF
- Hwindows, // MS Windows PE
-};
-
-typedef struct Header Header;
-struct Header {
- char *name;
- int val;
-};
-
-EXTERN char* headstring;
-extern Header headers[];
-
-int headtype(char*);
-
-int Yconv(Fmt*);
-#pragma varargck type "Y" Sym*
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
deleted file mode 100644
index 0b12ac17b..000000000
--- a/src/cmd/ld/macho.c
+++ /dev/null
@@ -1,518 +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.
-
-// Mach-O file writing
-// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
-
-#include "l.h"
-#include "../ld/dwarf.h"
-#include "../ld/lib.h"
-#include "../ld/macho.h"
-
-static int macho64;
-static MachoHdr hdr;
-static MachoLoad *load;
-static MachoSeg seg[16];
-static MachoDebug xdebug[16];
-static int nload, mload, nseg, ndebug, nsect;
-
-// Amount of space left for adding load commands
-// that refer to dynamic libraries. Because these have
-// to go in the Mach-O header, we can't just pick a
-// "big enough" header size. The initial header is
-// one page, the non-dynamic library stuff takes
-// up about 1300 bytes; we overestimate that as 2k.
-static int load_budget = INITIAL_MACHO_HEADR - 2*1024;
-
-void
-machoinit(void)
-{
- switch(thechar) {
- // 64-bit architectures
- case '6':
- macho64 = 1;
- break;
-
- // 32-bit architectures
- default:
- break;
- }
-}
-
-MachoHdr*
-getMachoHdr(void)
-{
- return &hdr;
-}
-
-MachoLoad*
-newMachoLoad(uint32 type, uint32 ndata)
-{
- MachoLoad *l;
-
- if(nload >= mload) {
- if(mload == 0)
- mload = 1;
- else
- mload *= 2;
- load = realloc(load, mload*sizeof load[0]);
- if(load == nil) {
- diag("out of memory");
- errorexit();
- }
- }
-
- if(macho64 && (ndata & 1))
- ndata++;
-
- l = &load[nload++];
- l->type = type;
- l->ndata = ndata;
- l->data = mal(ndata*4);
- return l;
-}
-
-MachoSeg*
-newMachoSeg(char *name, int msect)
-{
- MachoSeg *s;
-
- if(nseg >= nelem(seg)) {
- diag("too many segs");
- errorexit();
- }
- s = &seg[nseg++];
- s->name = name;
- s->msect = msect;
- s->sect = mal(msect*sizeof s->sect[0]);
- return s;
-}
-
-MachoSect*
-newMachoSect(MachoSeg *seg, char *name)
-{
- MachoSect *s;
-
- if(seg->nsect >= seg->msect) {
- diag("too many sects in segment %s", seg->name);
- errorexit();
- }
- s = &seg->sect[seg->nsect++];
- s->name = name;
- nsect++;
- return s;
-}
-
-MachoDebug*
-newMachoDebug(void)
-{
- if(ndebug >= nelem(xdebug)) {
- diag("too many debugs");
- errorexit();
- }
- return &xdebug[ndebug++];
-}
-
-
-// Generic linking code.
-
-static char **dylib;
-static int ndylib;
-
-static vlong linkoff;
-
-int
-machowrite(void)
-{
- vlong o1;
- int loadsize;
- int i, j;
- MachoSeg *s;
- MachoSect *t;
- MachoDebug *d;
- MachoLoad *l;
-
- o1 = cpos();
-
- loadsize = 4*4*ndebug;
- for(i=0; i<nload; i++)
- loadsize += 4*(load[i].ndata+2);
- if(macho64) {
- loadsize += 18*4*nseg;
- loadsize += 20*4*nsect;
- } else {
- loadsize += 14*4*nseg;
- loadsize += 17*4*nsect;
- }
-
- if(macho64)
- LPUT(0xfeedfacf);
- else
- LPUT(0xfeedface);
- LPUT(hdr.cpu);
- LPUT(hdr.subcpu);
- LPUT(2); /* file type - mach executable */
- LPUT(nload+nseg+ndebug);
- LPUT(loadsize);
- LPUT(1); /* flags - no undefines */
- if(macho64)
- LPUT(0); /* reserved */
-
- for(i=0; i<nseg; i++) {
- s = &seg[i];
- if(macho64) {
- LPUT(25); /* segment 64 */
- LPUT(72+80*s->nsect);
- strnput(s->name, 16);
- VPUT(s->vaddr);
- VPUT(s->vsize);
- VPUT(s->fileoffset);
- VPUT(s->filesize);
- LPUT(s->prot1);
- LPUT(s->prot2);
- LPUT(s->nsect);
- LPUT(s->flag);
- } else {
- LPUT(1); /* segment 32 */
- LPUT(56+68*s->nsect);
- strnput(s->name, 16);
- LPUT(s->vaddr);
- LPUT(s->vsize);
- LPUT(s->fileoffset);
- LPUT(s->filesize);
- LPUT(s->prot1);
- LPUT(s->prot2);
- LPUT(s->nsect);
- LPUT(s->flag);
- }
- for(j=0; j<s->nsect; j++) {
- t = &s->sect[j];
- if(macho64) {
- strnput(t->name, 16);
- strnput(s->name, 16);
- VPUT(t->addr);
- VPUT(t->size);
- LPUT(t->off);
- LPUT(t->align);
- LPUT(t->reloc);
- LPUT(t->nreloc);
- LPUT(t->flag);
- LPUT(t->res1); /* reserved */
- LPUT(t->res2); /* reserved */
- LPUT(0); /* reserved */
- } else {
- strnput(t->name, 16);
- strnput(s->name, 16);
- LPUT(t->addr);
- LPUT(t->size);
- LPUT(t->off);
- LPUT(t->align);
- LPUT(t->reloc);
- LPUT(t->nreloc);
- LPUT(t->flag);
- LPUT(t->res1); /* reserved */
- LPUT(t->res2); /* reserved */
- }
- }
- }
-
- for(i=0; i<nload; i++) {
- l = &load[i];
- LPUT(l->type);
- LPUT(4*(l->ndata+2));
- for(j=0; j<l->ndata; j++)
- LPUT(l->data[j]);
- }
-
- for(i=0; i<ndebug; i++) {
- d = &xdebug[i];
- LPUT(3); /* obsolete gdb debug info */
- LPUT(16); /* size of symseg command */
- LPUT(d->fileoffset);
- LPUT(d->filesize);
- }
-
- return cpos() - o1;
-}
-
-void
-domacho(void)
-{
- Sym *s;
-
- if(debug['d'])
- return;
-
- // empirically, string table must begin with " \x00".
- s = lookup(".dynstr", 0);
- s->type = SMACHODYNSTR;
- s->reachable = 1;
- adduint8(s, ' ');
- adduint8(s, '\0');
-
- s = lookup(".dynsym", 0);
- s->type = SMACHODYNSYM;
- s->reachable = 1;
-
- s = lookup(".plt", 0); // will be __symbol_stub
- s->type = SMACHOPLT;
- s->reachable = 1;
-
- s = lookup(".got", 0); // will be __nl_symbol_ptr
- s->type = SMACHOGOT;
- s->reachable = 1;
-
- s = lookup(".linkedit.plt", 0); // indirect table for .plt
- s->type = SMACHOINDIRECTPLT;
- s->reachable = 1;
-
- s = lookup(".linkedit.got", 0); // indirect table for .got
- s->type = SMACHOINDIRECTGOT;
- s->reachable = 1;
-}
-
-void
-machoadddynlib(char *lib)
-{
- // Will need to store the library name rounded up
- // and 24 bytes of header metadata. If not enough
- // space, grab another page of initial space at the
- // beginning of the output file.
- load_budget -= (strlen(lib)+7)/8*8 + 24;
- if(load_budget < 0) {
- HEADR += 4096;
- INITTEXT += 4096;
- load_budget += 4096;
- }
-
- if(ndylib%32 == 0) {
- dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
- if(dylib == nil) {
- diag("out of memory");
- errorexit();
- }
- }
- dylib[ndylib++] = lib;
-}
-
-void
-asmbmacho(void)
-{
- vlong v, w;
- vlong va;
- int a, i;
- MachoHdr *mh;
- MachoSect *msect;
- MachoSeg *ms;
- MachoDebug *md;
- MachoLoad *ml;
- Sym *s;
-
- /* apple MACH */
- va = INITTEXT - HEADR;
- mh = getMachoHdr();
- switch(thechar){
- default:
- diag("unknown mach architecture");
- errorexit();
- case '6':
- mh->cpu = MACHO_CPU_AMD64;
- mh->subcpu = MACHO_SUBCPU_X86;
- break;
- case '8':
- mh->cpu = MACHO_CPU_386;
- mh->subcpu = MACHO_SUBCPU_X86;
- break;
- }
-
- /* segment for zero page */
- ms = newMachoSeg("__PAGEZERO", 0);
- ms->vsize = va;
-
- /* text */
- v = rnd(HEADR+segtext.len, INITRND);
- ms = newMachoSeg("__TEXT", 2);
- ms->vaddr = va;
- ms->vsize = v;
- ms->filesize = v;
- ms->prot1 = 7;
- ms->prot2 = 5;
-
- msect = newMachoSect(ms, "__text");
- msect->addr = INITTEXT;
- msect->size = segtext.sect->len;
- msect->off = INITTEXT - va;
- msect->flag = 0x400; /* flag - some instructions */
-
- s = lookup(".plt", 0);
- if(s->size > 0) {
- msect = newMachoSect(ms, "__symbol_stub1");
- msect->addr = symaddr(s);
- msect->size = s->size;
- msect->off = ms->fileoffset + msect->addr - ms->vaddr;
- msect->flag = 0x80000408; /* flag */
- msect->res1 = 0; /* index into indirect symbol table */
- msect->res2 = 6; /* size of stubs */
- }
-
- /* data */
- w = segdata.len;
- ms = newMachoSeg("__DATA", 3);
- ms->vaddr = va+v;
- ms->vsize = w;
- ms->fileoffset = v;
- ms->filesize = segdata.filelen;
- ms->prot1 = 7;
- ms->prot2 = 3;
-
- msect = newMachoSect(ms, "__data");
- msect->addr = va+v;
- msect->off = v;
- msect->size = segdata.filelen;
-
- s = lookup(".got", 0);
- if(s->size > 0) {
- msect->size = symaddr(s) - msect->addr;
-
- msect = newMachoSect(ms, "__nl_symbol_ptr");
- msect->addr = symaddr(s);
- msect->size = s->size;
- msect->off = datoff(msect->addr);
- msect->align = 2;
- msect->flag = 6; /* section with nonlazy symbol pointers */
- msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
- }
-
- msect = newMachoSect(ms, "__bss");
- msect->addr = va+v+segdata.filelen;
- msect->size = segdata.len - segdata.filelen;
- msect->flag = 1; /* flag - zero fill */
-
- switch(thechar) {
- default:
- diag("unknown macho architecture");
- errorexit();
- case '6':
- ml = newMachoLoad(5, 42+2); /* unix thread */
- ml->data[0] = 4; /* thread type */
- ml->data[1] = 42; /* word count */
- ml->data[2+32] = entryvalue(); /* start pc */
- ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l
- break;
- case '8':
- ml = newMachoLoad(5, 16+2); /* unix thread */
- ml->data[0] = 1; /* thread type */
- ml->data[1] = 16; /* word count */
- ml->data[2+10] = entryvalue(); /* start pc */
- break;
- }
-
- if(!debug['d']) {
- Sym *s1, *s2, *s3, *s4;
-
- // must match domacholink below
- s1 = lookup(".dynsym", 0);
- s2 = lookup(".dynstr", 0);
- s3 = lookup(".linkedit.plt", 0);
- s4 = lookup(".linkedit.got", 0);
-
- ms = newMachoSeg("__LINKEDIT", 0);
- ms->vaddr = va+v+rnd(segdata.len, INITRND);
- ms->vsize = s1->size + s2->size + s3->size + s4->size;
- ms->fileoffset = linkoff;
- ms->filesize = ms->vsize;
- ms->prot1 = 7;
- ms->prot2 = 3;
-
- ml = newMachoLoad(2, 4); /* LC_SYMTAB */
- ml->data[0] = linkoff; /* symoff */
- ml->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */
- ml->data[2] = linkoff + s1->size; /* stroff */
- ml->data[3] = s2->size; /* strsize */
-
- ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
- ml->data[0] = 0; /* ilocalsym */
- ml->data[1] = 0; /* nlocalsym */
- ml->data[2] = 0; /* iextdefsym */
- ml->data[3] = ndynexp; /* nextdefsym */
- ml->data[4] = ndynexp; /* iundefsym */
- ml->data[5] = (s1->size / (macho64 ? 16 : 12)) - ndynexp; /* nundefsym */
- ml->data[6] = 0; /* tocoffset */
- ml->data[7] = 0; /* ntoc */
- ml->data[8] = 0; /* modtaboff */
- ml->data[9] = 0; /* nmodtab */
- ml->data[10] = 0; /* extrefsymoff */
- ml->data[11] = 0; /* nextrefsyms */
- ml->data[12] = linkoff + s1->size + s2->size; /* indirectsymoff */
- ml->data[13] = (s3->size + s4->size) / 4; /* nindirectsyms */
- ml->data[14] = 0; /* extreloff */
- ml->data[15] = 0; /* nextrel */
- ml->data[16] = 0; /* locreloff */
- ml->data[17] = 0; /* nlocrel */
-
- ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */
- ml->data[0] = 12; /* offset to string */
- strcpy((char*)&ml->data[1], "/usr/lib/dyld");
-
- for(i=0; i<ndylib; i++) {
- ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */
- ml->data[0] = 24; /* offset of string from beginning of load */
- ml->data[1] = 0; /* time stamp */
- ml->data[2] = 0; /* version */
- ml->data[3] = 0; /* compatibility version */
- strcpy((char*)&ml->data[4], dylib[i]);
- }
- }
-
- if(!debug['s']) {
- Sym *s;
-
- md = newMachoDebug();
- s = lookup("symtab", 0);
- md->fileoffset = datoff(s->value);
- md->filesize = s->size;
-
- md = newMachoDebug();
- s = lookup("pclntab", 0);
- md->fileoffset = datoff(s->value);
- md->filesize = s->size;
-
- dwarfaddmachoheaders();
- }
-
- a = machowrite();
- if(a > HEADR)
- diag("HEADR too small: %d > %d", a, HEADR);
-}
-
-vlong
-domacholink(void)
-{
- int size;
- Sym *s1, *s2, *s3, *s4;
-
- // write data that will be linkedit section
- s1 = lookup(".dynsym", 0);
- relocsym(s1);
- s2 = lookup(".dynstr", 0);
- s3 = lookup(".linkedit.plt", 0);
- s4 = lookup(".linkedit.got", 0);
-
- while(s2->size%4)
- adduint8(s2, 0);
-
- size = s1->size + s2->size + s3->size + s4->size;
-
- if(size > 0) {
- linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
- seek(cout, linkoff, 0);
-
- ewrite(cout, s1->p, s1->size);
- ewrite(cout, s2->p, s2->size);
- ewrite(cout, s3->p, s3->size);
- ewrite(cout, s4->p, s4->size);
- }
-
- return rnd(size, INITRND);
-}
diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h
deleted file mode 100644
index f55104150..000000000
--- a/src/cmd/ld/macho.h
+++ /dev/null
@@ -1,94 +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 struct MachoHdr MachoHdr;
-struct MachoHdr {
- uint32 cpu;
- uint32 subcpu;
-};
-
-typedef struct MachoSect MachoSect;
-struct MachoSect {
- char* name;
- uint64 addr;
- uint64 size;
- uint32 off;
- uint32 align;
- uint32 reloc;
- uint32 nreloc;
- uint32 flag;
- uint32 res1;
- uint32 res2;
-};
-
-typedef struct MachoSeg MachoSeg;
-struct MachoSeg {
- char* name;
- uint64 vsize;
- uint64 vaddr;
- uint64 fileoffset;
- uint64 filesize;
- uint32 prot1;
- uint32 prot2;
- uint32 nsect;
- uint32 msect;
- MachoSect *sect;
- uint32 flag;
-};
-
-typedef struct MachoLoad MachoLoad;
-struct MachoLoad {
- uint32 type;
- uint32 ndata;
- uint32 *data;
-};
-
-typedef struct MachoDebug MachoDebug;
-struct MachoDebug {
- uint32 fileoffset;
- uint32 filesize;
-};
-
-MachoHdr* getMachoHdr();
-MachoSeg* newMachoSeg(char*, int);
-MachoSect* newMachoSect(MachoSeg*, char*);
-MachoLoad* newMachoLoad(uint32, uint32);
-MachoDebug* newMachoDebug(void);
-int machowrite(void);
-void machoinit(void);
-
-/*
- * Total amount of space to reserve at the start of the file
- * for Header, PHeaders, and SHeaders.
- * May waste some.
- */
-#define INITIAL_MACHO_HEADR 4*1024
-
-enum {
- MACHO_CPU_AMD64 = (1<<24)|7,
- MACHO_CPU_386 = 7,
- MACHO_SUBCPU_X86 = 3,
-
- MACHO32SYMSIZE = 12,
- MACHO64SYMSIZE = 16,
-
- MACHO_X86_64_RELOC_UNSIGNED = 0,
- MACHO_X86_64_RELOC_SIGNED = 1,
- MACHO_X86_64_RELOC_BRANCH = 2,
- MACHO_X86_64_RELOC_GOT_LOAD = 3,
- MACHO_X86_64_RELOC_GOT = 4,
- MACHO_X86_64_RELOC_SUBTRACTOR = 5,
- MACHO_X86_64_RELOC_SIGNED_1 = 6,
- MACHO_X86_64_RELOC_SIGNED_2 = 7,
- MACHO_X86_64_RELOC_SIGNED_4 = 8,
-
- MACHO_GENERIC_RELOC_VANILLA = 0,
-
- MACHO_FAKE_GOTPCREL = 100,
-};
-
-void domacho(void);
-vlong domacholink(void);
-void asmbmacho(void);
-void machoadddynlib(char*);
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
deleted file mode 100644
index 9ac0a50d8..000000000
--- a/src/cmd/ld/pe.c
+++ /dev/null
@@ -1,583 +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.
-
-// PE (Portable Executable) file writing
-// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/pe.h"
-#include "../ld/dwarf.h"
-
-// DOS stub that prints out
-// "This program cannot be run in DOS mode."
-static char dosstub[] =
-{
- 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
- 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
- 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,
- 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
- 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
- 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
- 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,
- 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
- 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
- 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static Sym *rsrcsym;
-
-static char symnames[256];
-static int nextsymoff;
-
-int32 PESECTHEADR;
-int32 PEFILEHEADR;
-
-static int pe64;
-static int nsect;
-static int nextsectoff;
-static int nextfileoff;
-
-static IMAGE_FILE_HEADER fh;
-static IMAGE_OPTIONAL_HEADER oh;
-static PE64_IMAGE_OPTIONAL_HEADER oh64;
-static IMAGE_SECTION_HEADER sh[16];
-static IMAGE_DATA_DIRECTORY* dd;
-
-#define set(n, v) (pe64 ? (oh64.n = v) : (oh.n = v))
-#define put(v) (pe64 ? vputl(v) : lputl(v))
-
-typedef struct Imp Imp;
-struct Imp {
- Sym* s;
- uvlong off;
- Imp* next;
-};
-
-typedef struct Dll Dll;
-struct Dll {
- char* name;
- uvlong nameoff;
- uvlong thunkoff;
- Imp* ms;
- Dll* next;
-};
-
-static Dll* dr;
-
-static Sym *dexport[1024];
-static int nexport;
-
-static IMAGE_SECTION_HEADER*
-addpesection(char *name, int sectsize, int filesize, Segment *s)
-{
- IMAGE_SECTION_HEADER *h;
-
- if(nsect == 16) {
- diag("too many sections");
- errorexit();
- }
- h = &sh[nsect++];
- strncpy((char*)h->Name, name, sizeof(h->Name));
- h->VirtualSize = sectsize;
- h->VirtualAddress = nextsectoff;
- nextsectoff = rnd(nextsectoff+sectsize, PESECTALIGN);
- h->PointerToRawData = nextfileoff;
- if(filesize > 0) {
- h->SizeOfRawData = rnd(filesize, PEFILEALIGN);
- nextfileoff += h->SizeOfRawData;
- }
- if(s) {
- if(s->vaddr-PEBASE != h->VirtualAddress) {
- diag("%s.VirtualAddress = %#llux, want %#llux", name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE));
- errorexit();
- }
- if(s->fileoff != h->PointerToRawData) {
- diag("%s.PointerToRawData = %#llux, want %#llux", name, (vlong)h->PointerToRawData, (vlong)(s->fileoff));
- errorexit();
- }
- }
- return h;
-}
-
-void
-peinit(void)
-{
- int32 l;
-
- switch(thechar) {
- // 64-bit architectures
- case '6':
- pe64 = 1;
- l = sizeof(oh64);
- dd = oh64.DataDirectory;
- break;
- // 32-bit architectures
- default:
- l = sizeof(oh);
- dd = oh.DataDirectory;
- break;
- }
-
- PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN);
- PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN);
- nextsectoff = PESECTHEADR;
- nextfileoff = PEFILEHEADR;
-}
-
-static void
-pewrite(void)
-{
- seek(cout, 0, 0);
- ewrite(cout, dosstub, sizeof dosstub);
- strnput("PE", 4);
- cflush();
- // TODO: This code should not assume that the
- // memory representation is little-endian or
- // that the structs are packed identically to
- // their file representation.
- ewrite(cout, &fh, sizeof fh);
- if(pe64)
- ewrite(cout, &oh64, sizeof oh64);
- else
- ewrite(cout, &oh, sizeof oh);
- ewrite(cout, sh, nsect * sizeof sh[0]);
-}
-
-static void
-strput(char *s)
-{
- int n;
-
- for(n=0; *s; n++)
- cput(*s++);
- cput('\0');
- n++;
- // string must be padded to even size
- if(n%2)
- cput('\0');
-}
-
-static Dll*
-initdynimport(void)
-{
- Imp *m;
- Dll *d;
- Sym *s, *dynamic;
-
- dr = nil;
- m = nil;
- for(s = allsym; s != S; s = s->allsym) {
- if(!s->reachable || !s->dynimpname || s->dynexport)
- continue;
- for(d = dr; d != nil; d = d->next) {
- if(strcmp(d->name,s->dynimplib) == 0) {
- m = mal(sizeof *m);
- break;
- }
- }
- if(d == nil) {
- d = mal(sizeof *d);
- d->name = s->dynimplib;
- d->next = dr;
- dr = d;
- m = mal(sizeof *m);
- }
- m->s = s;
- m->next = d->ms;
- d->ms = m;
- }
-
- dynamic = lookup(".windynamic", 0);
- dynamic->reachable = 1;
- dynamic->type = SWINDOWS;
- for(d = dr; d != nil; d = d->next) {
- for(m = d->ms; m != nil; m = m->next) {
- m->s->type = SWINDOWS | SSUB;
- m->s->sub = dynamic->sub;
- dynamic->sub = m->s;
- m->s->value = dynamic->size;
- dynamic->size += PtrSize;
- }
- dynamic->size += PtrSize;
- }
-
- return dr;
-}
-
-static void
-addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect)
-{
- IMAGE_SECTION_HEADER *isect;
- uvlong n, oftbase, ftbase;
- Imp *m;
- Dll *d;
- Sym* dynamic;
-
- dynamic = lookup(".windynamic", 0);
-
- // skip import descriptor table (will write it later)
- n = 0;
- for(d = dr; d != nil; d = d->next)
- n++;
- seek(cout, fileoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1), 0);
-
- // write dll names
- for(d = dr; d != nil; d = d->next) {
- d->nameoff = cpos() - fileoff;
- strput(d->name);
- }
-
- // write function names
- for(d = dr; d != nil; d = d->next) {
- for(m = d->ms; m != nil; m = m->next) {
- m->off = nextsectoff + cpos() - fileoff;
- wputl(0); // hint
- strput(m->s->dynimpname);
- }
- }
-
- // write OriginalFirstThunks
- oftbase = cpos() - fileoff;
- n = cpos();
- for(d = dr; d != nil; d = d->next) {
- d->thunkoff = cpos() - n;
- for(m = d->ms; m != nil; m = m->next)
- put(m->off);
- put(0);
- }
-
- // add pe section and pad it at the end
- n = cpos() - fileoff;
- isect = addpesection(".idata", n, n, 0);
- isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
- IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
- strnput("", isect->SizeOfRawData - n);
- cflush();
-
- // write FirstThunks (allocated in .data section)
- ftbase = dynamic->value - datsect->VirtualAddress - PEBASE;
- seek(cout, datsect->PointerToRawData + ftbase, 0);
- for(d = dr; d != nil; d = d->next) {
- for(m = d->ms; m != nil; m = m->next)
- put(m->off);
- put(0);
- }
- cflush();
-
- // finally write import descriptor table
- seek(cout, fileoff, 0);
- for(d = dr; d != nil; d = d->next) {
- lputl(isect->VirtualAddress + oftbase + d->thunkoff);
- lputl(0);
- lputl(0);
- lputl(isect->VirtualAddress + d->nameoff);
- lputl(datsect->VirtualAddress + ftbase + d->thunkoff);
- }
- lputl(0); //end
- lputl(0);
- lputl(0);
- lputl(0);
- lputl(0);
- cflush();
-
- // update data directory
- dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress;
- dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
- dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE;
- dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
-
- seek(cout, 0, 2);
-}
-
-static int
-scmp(const void *p1, const void *p2)
-{
- Sym *s1, *s2;
-
- s1 = *(Sym**)p1;
- s2 = *(Sym**)p2;
- return strcmp(s1->dynimpname, s2->dynimpname);
-}
-
-static void
-initdynexport(void)
-{
- Sym *s;
-
- nexport = 0;
- for(s = allsym; s != S; s = s->allsym) {
- if(!s->reachable || !s->dynimpname || !s->dynexport)
- continue;
- if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
- diag("pe dynexport table is full");
- errorexit();
- }
-
- dexport[nexport] = s;
- nexport++;
- }
-
- qsort(dexport, nexport, sizeof dexport[0], scmp);
-}
-
-void
-addexports(vlong fileoff)
-{
- IMAGE_SECTION_HEADER *sect;
- IMAGE_EXPORT_DIRECTORY e;
- int size, i, va, va_name, va_addr, va_na, v;
-
- size = sizeof e + 10*nexport + strlen(outfile) + 1;
- for(i=0; i<nexport; i++)
- size += strlen(dexport[i]->dynimpname) + 1;
-
- if (nexport == 0)
- return;
-
- sect = addpesection(".edata", size, size, 0);
- sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ;
- va = sect->VirtualAddress;
- dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va;
- dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize;
-
- seek(cout, fileoff, 0);
- va_name = va + sizeof e + nexport*4;
- va_addr = va + sizeof e;
- va_na = va + sizeof e + nexport*8;
-
- e.Characteristics = 0;
- e.MajorVersion = 0;
- e.MinorVersion = 0;
- e.NumberOfFunctions = nexport;
- e.NumberOfNames = nexport;
- e.Name = va + sizeof e + nexport*10; // Program names.
- e.Base = 1;
- e.AddressOfFunctions = va_addr;
- e.AddressOfNames = va_name;
- e.AddressOfNameOrdinals = va_na;
- // put IMAGE_EXPORT_DIRECTORY
- for (i=0; i<sizeof(e); i++)
- cput(((char*)&e)[i]);
- // put EXPORT Address Table
- for(i=0; i<nexport; i++)
- lputl(dexport[i]->value - PEBASE);
- // put EXPORT Name Pointer Table
- v = e.Name + strlen(outfile)+1;
- for(i=0; i<nexport; i++) {
- lputl(v);
- v += strlen(dexport[i]->dynimpname)+1;
- }
- // put EXPORT Ordinal Table
- for(i=0; i<nexport; i++)
- wputl(i);
- // put Names
- strnput(outfile, strlen(outfile)+1);
- for(i=0; i<nexport; i++)
- strnput(dexport[i]->dynimpname, strlen(dexport[i]->dynimpname)+1);
- strnput("", sect->SizeOfRawData - size);
- cflush();
-
- seek(cout, 0, 2);
-}
-
-void
-dope(void)
-{
- Sym *rel;
-
- /* relocation table */
- rel = lookup(".rel", 0);
- rel->reachable = 1;
- rel->type = SELFDATA;
-
- initdynimport();
- initdynexport();
-}
-
-/*
- * For more than 8 characters section names, name contains a slash (/) that is
- * followed by an ASCII representation of a decimal number that is an offset into
- * the string table.
- * reference: pecoff_v8.docx Page 24.
- * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
- */
-IMAGE_SECTION_HEADER*
-newPEDWARFSection(char *name, vlong size)
-{
- IMAGE_SECTION_HEADER *h;
- char s[8];
-
- if(size == 0)
- return nil;
-
- if(nextsymoff+strlen(name)+1 > sizeof(symnames)) {
- diag("pe string table is full");
- errorexit();
- }
-
- strcpy(&symnames[nextsymoff], name);
- sprint(s, "/%d\0", nextsymoff+4);
- nextsymoff += strlen(name);
- symnames[nextsymoff] = 0;
- nextsymoff ++;
- h = addpesection(s, size, size, 0);
- h->Characteristics = IMAGE_SCN_MEM_READ|
- IMAGE_SCN_MEM_DISCARDABLE;
-
- return h;
-}
-
-static void
-addsymtable(void)
-{
- IMAGE_SECTION_HEADER *h;
- int i, size;
-
- if(nextsymoff == 0)
- return;
-
- size = nextsymoff + 4;
- h = addpesection(".symtab", size, size, 0);
- h->Characteristics = IMAGE_SCN_MEM_READ|
- IMAGE_SCN_MEM_DISCARDABLE;
- fh.PointerToSymbolTable = cpos();
- fh.NumberOfSymbols = 0;
- // put symbol string table
- lputl(size);
- for (i=0; i<nextsymoff; i++)
- cput(symnames[i]);
- strnput("", h->SizeOfRawData - size);
- cflush();
-}
-
-void
-setpersrc(Sym *sym)
-{
- if(rsrcsym != nil)
- diag("too many .rsrc sections");
-
- rsrcsym = sym;
-}
-
-void
-addpersrc(void)
-{
- IMAGE_SECTION_HEADER *h;
- uchar *p;
- uint32 val;
- Reloc *r;
-
- if(rsrcsym == nil)
- return;
-
- h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size, 0);
- h->Characteristics = IMAGE_SCN_MEM_READ|
- IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA;
- // relocation
- for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) {
- p = rsrcsym->p + r->off;
- val = h->VirtualAddress + r->add;
- // 32-bit little-endian
- p[0] = val;
- p[1] = val>>8;
- p[2] = val>>16;
- p[3] = val>>24;
- }
- ewrite(cout, rsrcsym->p, rsrcsym->size);
- strnput("", h->SizeOfRawData - rsrcsym->size);
- cflush();
-
- // update data directory
- dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress;
- dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize;
-}
-
-void
-asmbpe(void)
-{
- IMAGE_SECTION_HEADER *t, *d;
-
- switch(thechar) {
- default:
- diag("unknown PE architecture");
- errorexit();
- case '6':
- fh.Machine = IMAGE_FILE_MACHINE_AMD64;
- break;
- case '8':
- fh.Machine = IMAGE_FILE_MACHINE_I386;
- break;
- }
-
- t = addpesection(".text", segtext.len, segtext.len, &segtext);
- t->Characteristics = IMAGE_SCN_CNT_CODE|
- IMAGE_SCN_CNT_INITIALIZED_DATA|
- IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
-
- d = addpesection(".data", segdata.len, segdata.filelen, &segdata);
- d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
- IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
-
- if(!debug['s'])
- dwarfaddpeheaders();
-
- addimports(nextfileoff, d);
-
- addexports(nextfileoff);
-
- addsymtable();
-
- addpersrc();
-
- fh.NumberOfSections = nsect;
- fh.TimeDateStamp = time(0);
- fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
- IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED;
- if (pe64) {
- fh.SizeOfOptionalHeader = sizeof(oh64);
- fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
- set(Magic, 0x20b); // PE32+
- } else {
- fh.SizeOfOptionalHeader = sizeof(oh);
- fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE;
- set(Magic, 0x10b); // PE32
- oh.BaseOfData = d->VirtualAddress;
- }
- set(MajorLinkerVersion, 1);
- set(MinorLinkerVersion, 0);
- set(SizeOfCode, t->SizeOfRawData);
- set(SizeOfInitializedData, d->SizeOfRawData);
- set(SizeOfUninitializedData, 0);
- set(AddressOfEntryPoint, entryvalue()-PEBASE);
- set(BaseOfCode, t->VirtualAddress);
- set(ImageBase, PEBASE);
- set(SectionAlignment, PESECTALIGN);
- set(FileAlignment, PEFILEALIGN);
- set(MajorOperatingSystemVersion, 4);
- set(MinorOperatingSystemVersion, 0);
- set(MajorImageVersion, 1);
- set(MinorImageVersion, 0);
- set(MajorSubsystemVersion, 4);
- set(MinorSubsystemVersion, 0);
- set(SizeOfImage, nextsectoff);
- set(SizeOfHeaders, PEFILEHEADR);
- if(strcmp(headstring, "windowsgui") == 0)
- set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
- else
- set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI);
- set(SizeOfStackReserve, 0x0040000);
- set(SizeOfStackCommit, 0x00001000);
- set(SizeOfHeapReserve, 0x00100000);
- set(SizeOfHeapCommit, 0x00001000);
- set(NumberOfRvaAndSizes, 16);
-
- pewrite();
-}
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
deleted file mode 100644
index 7aa938829..000000000
--- a/src/cmd/ld/pe.h
+++ /dev/null
@@ -1,179 +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 struct {
- uint16 Machine;
- uint16 NumberOfSections;
- uint32 TimeDateStamp;
- uint32 PointerToSymbolTable;
- uint32 NumberOfSymbols;
- uint16 SizeOfOptionalHeader;
- uint16 Characteristics;
-} IMAGE_FILE_HEADER;
-
-typedef struct {
- uint32 VirtualAddress;
- uint32 Size;
-} IMAGE_DATA_DIRECTORY;
-
-typedef struct {
- uint16 Magic;
- uint8 MajorLinkerVersion;
- uint8 MinorLinkerVersion;
- uint32 SizeOfCode;
- uint32 SizeOfInitializedData;
- uint32 SizeOfUninitializedData;
- uint32 AddressOfEntryPoint;
- uint32 BaseOfCode;
- uint32 BaseOfData;
- uint32 ImageBase;
- uint32 SectionAlignment;
- uint32 FileAlignment;
- uint16 MajorOperatingSystemVersion;
- uint16 MinorOperatingSystemVersion;
- uint16 MajorImageVersion;
- uint16 MinorImageVersion;
- uint16 MajorSubsystemVersion;
- uint16 MinorSubsystemVersion;
- uint32 Win32VersionValue;
- uint32 SizeOfImage;
- uint32 SizeOfHeaders;
- uint32 CheckSum;
- uint16 Subsystem;
- uint16 DllCharacteristics;
- uint32 SizeOfStackReserve;
- uint32 SizeOfStackCommit;
- uint32 SizeOfHeapReserve;
- uint32 SizeOfHeapCommit;
- uint32 LoaderFlags;
- uint32 NumberOfRvaAndSizes;
- IMAGE_DATA_DIRECTORY DataDirectory[16];
-} IMAGE_OPTIONAL_HEADER;
-
-typedef struct {
- uint8 Name[8];
- uint32 VirtualSize;
- uint32 VirtualAddress;
- uint32 SizeOfRawData;
- uint32 PointerToRawData;
- uint32 PointerToRelocations;
- uint32 PointerToLineNumbers;
- uint16 NumberOfRelocations;
- uint16 NumberOfLineNumbers;
- uint32 Characteristics;
-} IMAGE_SECTION_HEADER;
-
-typedef struct {
- uint32 OriginalFirstThunk;
- uint32 TimeDateStamp;
- uint32 ForwarderChain;
- uint32 Name;
- uint32 FirstThunk;
-} IMAGE_IMPORT_DESCRIPTOR;
-
-typedef struct _IMAGE_EXPORT_DIRECTORY {
- uint32 Characteristics;
- uint32 TimeDateStamp;
- uint16 MajorVersion;
- uint16 MinorVersion;
- uint32 Name;
- uint32 Base;
- uint32 NumberOfFunctions;
- uint32 NumberOfNames;
- uint32 AddressOfFunctions;
- uint32 AddressOfNames;
- uint32 AddressOfNameOrdinals;
-} IMAGE_EXPORT_DIRECTORY;
-
-#define PEBASE 0x00400000
-// SectionAlignment must be greater than or equal to FileAlignment.
-// The default is the page size for the architecture.
-#define PESECTALIGN 0x1000
-// FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
-// The default is 512. If the SectionAlignment is less than
-// the architecture's page size, then FileAlignment must match SectionAlignment.
-#define PEFILEALIGN (2<<8)
-extern int32 PESECTHEADR;
-extern int32 PEFILEHEADR;
-
-enum {
- IMAGE_FILE_MACHINE_I386 = 0x14c,
- IMAGE_FILE_MACHINE_AMD64 = 0x8664,
-
- IMAGE_FILE_RELOCS_STRIPPED = 0x0001,
- IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002,
- IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020,
- IMAGE_FILE_32BIT_MACHINE = 0x0100,
- IMAGE_FILE_DEBUG_STRIPPED = 0x0200,
-
- IMAGE_SCN_CNT_CODE = 0x00000020,
- IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040,
- IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080,
- IMAGE_SCN_MEM_EXECUTE = 0x20000000,
- IMAGE_SCN_MEM_READ = 0x40000000,
- IMAGE_SCN_MEM_WRITE = 0x80000000,
- IMAGE_SCN_MEM_DISCARDABLE = 0x2000000,
-
- IMAGE_DIRECTORY_ENTRY_EXPORT = 0,
- IMAGE_DIRECTORY_ENTRY_IMPORT = 1,
- IMAGE_DIRECTORY_ENTRY_RESOURCE = 2,
- IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3,
- IMAGE_DIRECTORY_ENTRY_SECURITY = 4,
- IMAGE_DIRECTORY_ENTRY_BASERELOC = 5,
- IMAGE_DIRECTORY_ENTRY_DEBUG = 6,
- IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7,
- IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7,
- IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8,
- IMAGE_DIRECTORY_ENTRY_TLS = 9,
- IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10,
- IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11,
- IMAGE_DIRECTORY_ENTRY_IAT = 12,
- IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13,
- IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14,
-
- IMAGE_SUBSYSTEM_WINDOWS_GUI = 2,
- IMAGE_SUBSYSTEM_WINDOWS_CUI = 3,
-};
-
-void peinit(void);
-void asmbpe(void);
-void dope(void);
-
-IMAGE_SECTION_HEADER* newPEDWARFSection(char *name, vlong size);
-
-// X64
-typedef struct {
- uint16 Magic;
- uint8 MajorLinkerVersion;
- uint8 MinorLinkerVersion;
- uint32 SizeOfCode;
- uint32 SizeOfInitializedData;
- uint32 SizeOfUninitializedData;
- uint32 AddressOfEntryPoint;
- uint32 BaseOfCode;
- uint64 ImageBase;
- uint32 SectionAlignment;
- uint32 FileAlignment;
- uint16 MajorOperatingSystemVersion;
- uint16 MinorOperatingSystemVersion;
- uint16 MajorImageVersion;
- uint16 MinorImageVersion;
- uint16 MajorSubsystemVersion;
- uint16 MinorSubsystemVersion;
- uint32 Win32VersionValue;
- uint32 SizeOfImage;
- uint32 SizeOfHeaders;
- uint32 CheckSum;
- uint16 Subsystem;
- uint16 DllCharacteristics;
- uint64 SizeOfStackReserve;
- uint64 SizeOfStackCommit;
- uint64 SizeOfHeapReserve;
- uint64 SizeOfHeapCommit;
- uint32 LoaderFlags;
- uint32 NumberOfRvaAndSizes;
- IMAGE_DATA_DIRECTORY DataDirectory[16];
-} PE64_IMAGE_OPTIONAL_HEADER;
-
-void setpersrc(Sym *sym);
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
deleted file mode 100644
index 60e146b35..000000000
--- a/src/cmd/ld/symtab.c
+++ /dev/null
@@ -1,378 +0,0 @@
-// Inferno utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.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.
-
-// Symbol table.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-
-char *elfstrdat;
-int elfstrsize;
-int maxelfstr;
-int elftextsh;
-
-int
-putelfstr(char *s)
-{
- int off, n;
-
- if(elfstrsize == 0 && s[0] != 0) {
- // first entry must be empty string
- putelfstr("");
- }
-
- n = strlen(s)+1;
- if(elfstrsize+n > maxelfstr) {
- maxelfstr = 2*(elfstrsize+n+(1<<20));
- elfstrdat = realloc(elfstrdat, maxelfstr);
- }
- off = elfstrsize;
- elfstrsize += n;
- memmove(elfstrdat+off, s, n);
- return off;
-}
-
-void
-putelfsyment(int off, vlong addr, vlong size, int info, int shndx)
-{
- switch(thechar) {
- case '6':
- LPUT(off);
- cput(info);
- cput(0);
- WPUT(shndx);
- VPUT(addr);
- VPUT(size);
- symsize += ELF64SYMSIZE;
- break;
- default:
- LPUT(off);
- LPUT(addr);
- LPUT(size);
- cput(info);
- cput(0);
- WPUT(shndx);
- symsize += ELF32SYMSIZE;
- break;
- }
-}
-
-void
-putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
-{
- int bind, type, shndx, off;
-
- USED(go);
- switch(t) {
- default:
- return;
- case 'T':
- type = STT_FUNC;
- shndx = elftextsh + 0;
- break;
- case 'D':
- type = STT_OBJECT;
- if((x->type&~SSUB) == SRODATA)
- shndx = elftextsh + 1;
- else
- shndx = elftextsh + 2;
- break;
- case 'B':
- type = STT_OBJECT;
- shndx = elftextsh + 3;
- break;
- }
- bind = ver ? STB_LOCAL : STB_GLOBAL;
- off = putelfstr(s);
- putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx);
-}
-
-void
-asmelfsym(void)
-{
- // the first symbol entry is reserved
- putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0);
- genasmsym(putelfsym);
-}
-
-void
-putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
-{
- int i;
-
- USED(go);
- USED(ver);
- USED(size);
- USED(x);
- switch(t) {
- case 'T':
- case 'L':
- case 'D':
- case 'B':
- if(ver)
- t += 'a' - 'A';
- case 'a':
- case 'p':
- case 'f':
- case 'z':
- case 'Z':
- case 'm':
- lputb(addr);
- cput(t+0x80); /* 0x80 is variable length */
-
- if(t == 'z' || t == 'Z') {
- cput(s[0]);
- for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
- cput(s[i]);
- cput(s[i+1]);
- }
- cput(0);
- cput(0);
- i++;
- } else {
- /* skip the '<' in filenames */
- if(t == 'f')
- s++;
- for(i=0; s[i]; i++)
- cput(s[i]);
- cput(0);
- }
- symsize += 4 + 1 + i + 1;
- break;
- default:
- return;
- };
-}
-
-void
-asmplan9sym(void)
-{
- genasmsym(putplan9sym);
-}
-
-static Sym *symt;
-
-static void
-scput(int b)
-{
- uchar *p;
-
- symgrow(symt, symt->size+1);
- p = symt->p + symt->size;
- *p = b;
- symt->size++;
-}
-
-static void
-slputb(int32 v)
-{
- uchar *p;
-
- symgrow(symt, symt->size+4);
- p = symt->p + symt->size;
- *p++ = v>>24;
- *p++ = v>>16;
- *p++ = v>>8;
- *p = v;
- symt->size += 4;
-}
-
-void
-wputl(ushort w)
-{
- cput(w);
- cput(w>>8);
-}
-
-void
-wputb(ushort w)
-{
- cput(w>>8);
- cput(w);
-}
-
-void
-lputb(int32 l)
-{
- cput(l>>24);
- cput(l>>16);
- cput(l>>8);
- cput(l);
-}
-
-void
-lputl(int32 l)
-{
- cput(l);
- cput(l>>8);
- cput(l>>16);
- cput(l>>24);
-}
-
-void
-vputb(uint64 v)
-{
- lputb(v>>32);
- lputb(v);
-}
-
-void
-vputl(uint64 v)
-{
- lputl(v);
- lputl(v >> 32);
-}
-
-void
-putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
-{
- int i, f, l;
- Reloc *rel;
-
- USED(size);
- if(t == 'f')
- name++;
- l = 4;
-// if(!debug['8'])
-// l = 8;
- if(s != nil) {
- rel = addrel(symt);
- rel->siz = l + Rbig;
- rel->sym = s;
- rel->type = D_ADDR;
- rel->off = symt->size;
- v = 0;
- }
- if(l == 8)
- slputb(v>>32);
- slputb(v);
- if(ver)
- t += 'a' - 'A';
- scput(t+0x80); /* 0x80 is variable length */
-
- if(t == 'Z' || t == 'z') {
- scput(name[0]);
- for(i=1; name[i] != 0 || name[i+1] != 0; i += 2) {
- scput(name[i]);
- scput(name[i+1]);
- }
- scput(0);
- scput(0);
- }
- else {
- for(i=0; name[i]; i++)
- scput(name[i]);
- scput(0);
- }
- if(typ) {
- if(!typ->reachable)
- diag("unreachable type %s", typ->name);
- rel = addrel(symt);
- rel->siz = l;
- rel->sym = typ;
- rel->type = D_ADDR;
- rel->off = symt->size;
- }
- if(l == 8)
- slputb(0);
- slputb(0);
-
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8llux ", t, v);
- for(i=1; name[i] != 0 || name[i+1] != 0; i+=2) {
- f = ((name[i]&0xff) << 8) | (name[i+1]&0xff);
- Bprint(&bso, "/%x", f);
- }
- Bprint(&bso, "\n");
- return;
- }
- if(ver)
- Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, s->name, ver, typ ? typ->name : "");
- else
- Bprint(&bso, "%c %.8llux %s %s\n", t, v, s->name, typ ? typ->name : "");
- }
-}
-
-void
-symtab(void)
-{
- Sym *s;
-
- // Define these so that they'll get put into the symbol table.
- // data.c:/^address will provide the actual values.
- xdefine("text", STEXT, 0);
- xdefine("etext", STEXT, 0);
- xdefine("rodata", SRODATA, 0);
- xdefine("erodata", SRODATA, 0);
- xdefine("data", SBSS, 0);
- xdefine("edata", SBSS, 0);
- xdefine("end", SBSS, 0);
- xdefine("epclntab", SRODATA, 0);
- xdefine("esymtab", SRODATA, 0);
-
- // pseudo-symbols to mark locations of type, string, and go string data.
- s = lookup("type.*", 0);
- s->type = STYPE;
- s->size = 0;
- s->reachable = 1;
-
- s = lookup("go.string.*", 0);
- s->type = SGOSTRING;
- s->size = 0;
- s->reachable = 1;
-
- symt = lookup("symtab", 0);
- symt->type = SSYMTAB;
- symt->size = 0;
- symt->reachable = 1;
-
- // assign specific types so that they sort together.
- // within a type they sort by size, so the .* symbols
- // just defined above will be first.
- // hide the specific symbols.
- for(s = allsym; s != S; s = s->allsym) {
- if(!s->reachable || s->special || s->type != SRODATA)
- continue;
- if(strncmp(s->name, "type.", 5) == 0) {
- s->type = STYPE;
- s->hide = 1;
- }
- if(strncmp(s->name, "go.string.", 10) == 0) {
- s->type = SGOSTRING;
- s->hide = 1;
- }
- }
-
- if(debug['s'])
- return;
- genasmsym(putsymb);
-}
diff --git a/src/cmd/nm/Makefile b/src/cmd/nm/Makefile
deleted file mode 100644
index 81bc348de..000000000
--- a/src/cmd/nm/Makefile
+++ /dev/null
@@ -1,15 +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 ../../Make.inc
-O:=$(HOST_O)
-
-# The directory is nm because the source is portable and general.
-# We call the binary 6nm to avoid confusion with the host nm.
-
-TARG=6nm
-OFILES=\
- nm.$O\
-
-include ../../Make.ccmd
diff --git a/src/cmd/nm/doc.go b/src/cmd/nm/doc.go
deleted file mode 100644
index 2a37dd835..000000000
--- a/src/cmd/nm/doc.go
+++ /dev/null
@@ -1,21 +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.
-
-/*
-
-Nm is a version of the Plan 9 nm command. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/nm
-
-It prints the name list (symbol table) for programs compiled by gc as well as the
-Plan 9 C compiler.
-
-This implementation adds the flag -S, which prints each symbol's size
-in decimal after its address.
-
-For reasons of disambiguation it is installed as 6nm although it also serves
-as an 8nm and a 5nm.
-
-*/
-package documentation
diff --git a/src/cmd/nm/nm.c b/src/cmd/nm/nm.c
deleted file mode 100644
index 845b6c773..000000000
--- a/src/cmd/nm/nm.c
+++ /dev/null
@@ -1,368 +0,0 @@
-// Inferno utils/nm/nm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/nm/nm.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.
-
-/*
- * nm.c -- drive nm
- */
-#include <u.h>
-#include <libc.h>
-#include <ar.h>
-#include <bio.h>
-#include <mach.h>
-
-enum{
- CHUNK = 256 /* must be power of 2 */
-};
-
-char *errs; /* exit status */
-char *filename; /* current file */
-char symname[]="__.SYMDEF"; /* table of contents file name */
-int multifile; /* processing multiple files */
-int aflag;
-int gflag;
-int hflag;
-int nflag;
-int sflag;
-int Sflag;
-int uflag;
-int Tflag;
-int tflag;
-
-Sym **fnames; /* file path translation table */
-Sym **symptr;
-int nsym;
-Biobuf bout;
-
-int cmp(void*, void*);
-void error(char*, ...);
-void execsyms(int);
-void psym(Sym*, void*);
-void printsyms(Sym**, long);
-void doar(Biobuf*);
-void dofile(Biobuf*);
-void zenter(Sym*);
-
-void
-usage(void)
-{
- fprint(2, "usage: nm [-aghnsTu] file ...\n");
- exits("usage");
-}
-
-void
-main(int argc, char *argv[])
-{
- int i;
- Biobuf *bin;
-
- Binit(&bout, 1, OWRITE);
- argv0 = argv[0];
- ARGBEGIN {
- default: usage();
- case 'a': aflag = 1; break;
- case 'g': gflag = 1; break;
- case 'h': hflag = 1; break;
- case 'n': nflag = 1; break;
- case 's': sflag = 1; break;
- case 'S': nflag = Sflag = 1; break;
- case 'u': uflag = 1; break;
- case 't': tflag = 1; break;
- case 'T': Tflag = 1; break;
- } ARGEND
- if (argc == 0)
- usage();
- if (argc > 1)
- multifile++;
- for(i=0; i<argc; i++){
- filename = argv[i];
- bin = Bopen(filename, OREAD);
- if(bin == 0){
- error("cannot open %s", filename);
- continue;
- }
- if (isar(bin))
- doar(bin);
- else{
- Bseek(bin, 0, 0);
- dofile(bin);
- }
- Bterm(bin);
- }
- exits(errs);
-}
-
-/*
- * read an archive file,
- * processing the symbols for each intermediate file in it.
- */
-void
-doar(Biobuf *bp)
-{
- int offset, size, obj;
- char name[SARNAME];
-
- multifile = 1;
- for (offset = Boffset(bp);;offset += size) {
- size = nextar(bp, offset, name);
- if (size < 0) {
- error("phase error on ar header %d", offset);
- return;
- }
- if (size == 0)
- return;
- if (strcmp(name, symname) == 0)
- continue;
- obj = objtype(bp, 0);
- if (obj < 0) {
- // perhaps foreign object
- if(strlen(name) > 2 && strcmp(name+strlen(name)-2, ".o") == 0)
- return;
- error("inconsistent file %s in %s",
- name, filename);
- return;
- }
- if (!readar(bp, obj, offset+size, 1)) {
- error("invalid symbol reference in file %s",
- name);
- return;
- }
- filename = name;
- nsym=0;
- objtraverse(psym, 0);
- printsyms(symptr, nsym);
- }
-}
-
-/*
- * process symbols in a file
- */
-void
-dofile(Biobuf *bp)
-{
- int obj;
-
- obj = objtype(bp, 0);
- if (obj < 0)
- execsyms(Bfildes(bp));
- else
- if (readobj(bp, obj)) {
- nsym = 0;
- objtraverse(psym, 0);
- printsyms(symptr, nsym);
- }
-}
-
-/*
- * comparison routine for sorting the symbol table
- * this screws up on 'z' records when aflag == 1
- */
-int
-cmp(void *vs, void *vt)
-{
- Sym **s, **t;
-
- s = vs;
- t = vt;
- if(nflag) // sort on address (numeric) order
- if((*s)->value < (*t)->value)
- return -1;
- else
- return (*s)->value > (*t)->value;
- if(sflag) // sort on file order (sequence)
- return (*s)->sequence - (*t)->sequence;
- return strcmp((*s)->name, (*t)->name);
-}
-/*
- * enter a symbol in the table of filename elements
- */
-void
-zenter(Sym *s)
-{
- static int maxf = 0;
-
- if (s->value > maxf) {
- maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
- fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
- if(fnames == 0) {
- error("out of memory", argv0);
- exits("memory");
- }
- }
- fnames[s->value] = s;
-}
-
-/*
- * get the symbol table from an executable file, if it has one
- */
-void
-execsyms(int fd)
-{
- Fhdr f;
- Sym *s;
- int32 n;
-
- seek(fd, 0, 0);
- if (crackhdr(fd, &f) == 0) {
- error("Can't read header for %s", filename);
- return;
- }
- if (syminit(fd, &f) < 0)
- return;
- s = symbase(&n);
- nsym = 0;
- while(n--)
- psym(s++, 0);
-
- printsyms(symptr, nsym);
-}
-
-void
-psym(Sym *s, void* p)
-{
- USED(p);
- switch(s->type) {
- case 'T':
- case 'L':
- case 'D':
- case 'B':
- if (uflag)
- return;
- if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
- return;
- break;
- case 'b':
- case 'd':
- case 'l':
- case 't':
- if (uflag || gflag)
- return;
- if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
- return;
- break;
- case 'U':
- if (gflag)
- return;
- break;
- case 'Z':
- if (!aflag)
- return;
- break;
- case 'm':
- case 'f': /* we only see a 'z' when the following is true*/
- if(!aflag || uflag || gflag)
- return;
- if (strcmp(s->name, ".frame"))
- zenter(s);
- break;
- case 'a':
- case 'p':
- case 'z':
- default:
- if(!aflag || uflag || gflag)
- return;
- break;
- }
- symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
- if (symptr == 0) {
- error("out of memory");
- exits("memory");
- }
- symptr[nsym++] = s;
-}
-
-void
-printsyms(Sym **symptr, long nsym)
-{
- int i, j, wid;
- Sym *s;
- char *cp;
- char path[512];
-
- qsort(symptr, nsym, sizeof(*symptr), (void*)cmp);
-
- wid = 0;
- for (i=0; i<nsym; i++) {
- s = symptr[i];
- if (s->value && wid == 0)
- wid = 8;
- else if (s->value >= 0x100000000LL && wid == 8)
- wid = 16;
- }
- for (i=0; i<nsym; i++) {
- s = symptr[i];
- if (multifile && !hflag)
- Bprint(&bout, "%s:", filename);
- if (s->type == 'z') {
- fileelem(fnames, (uchar *) s->name, path, 512);
- cp = path;
- } else
- cp = s->name;
- if (Tflag)
- Bprint(&bout, "%8ux ", s->sig);
- if (s->value || s->type == 'a' || s->type == 'p')
- Bprint(&bout, "%*llux ", wid, s->value);
- else
- Bprint(&bout, "%*s ", wid, "");
- if(Sflag) {
- vlong siz;
-
- siz = 0;
- for(j=i+1; j<nsym; j++) {
- if(symptr[j]->type != 'a' && symptr[j]->type != 'p') {
- siz = symptr[j]->value - s->value;
- break;
- }
- }
- if(siz > 0)
- Bprint(&bout, "%*llud ", wid, siz);
- }
- Bprint(&bout, "%c %s", s->type, cp);
- if(tflag && s->gotype)
- Bprint(&bout, " %*llux", wid, s->gotype);
- Bprint(&bout, "\n");
- }
-}
-
-void
-error(char *fmt, ...)
-{
- Fmt f;
- char buf[128];
- va_list arg;
-
- fmtfdinit(&f, 2, buf, sizeof buf);
- fmtprint(&f, "%s: ", argv0);
- va_start(arg, fmt);
- fmtvprint(&f, fmt, arg);
- va_end(arg);
- fmtprint(&f, "\n");
- fmtfdflush(&f);
- errs = "errors";
-}
diff --git a/src/cmd/prof/Makefile b/src/cmd/prof/Makefile
deleted file mode 100644
index 8a1a2f308..000000000
--- a/src/cmd/prof/Makefile
+++ /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 ../../Make.inc
-O:=$(HOST_O)
-
-# The directory is prof because the source is portable and general.
-# We call the binary 6prof to avoid confusion and because this binary
-# is linked only with amd64 and x86 support.
-
-TARG=6prof
-OFILES=\
- main.$O\
-
-NOINSTALL=1
-include ../../Make.ccmd
-
-ifeq ($(GOOS),windows)
-NAME=windows
-else
-NAME=$(shell uname | tr A-Z a-z)
-endif
-
-install: install-$(NAME) install-pprof
-install-linux: install-default
-install-freebsd: install-default
-install-windows: install-default
-
-# on Darwin, have to install and setgid; see $GOROOT/src/sudo.bash
-install-darwin: $(TARG)
- @true
-
-install-default: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
-
-install-pprof: gopprof
- cp gopprof "$(GOBIN)"/gopprof
diff --git a/src/cmd/prof/doc.go b/src/cmd/prof/doc.go
deleted file mode 100644
index 1f2209f04..000000000
--- a/src/cmd/prof/doc.go
+++ /dev/null
@@ -1,48 +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.
-
-/*
-
-Prof is a rudimentary real-time profiler.
-
-Given a command to run or the process id (pid) of a command already
-running, it samples the program's state at regular intervals and reports
-on its behavior. With no options, it prints a histogram of the locations
-in the code that were sampled during execution.
-
-Since it is a real-time profiler, unlike a traditional profiler it samples
-the program's state even when it is not running, such as when it is
-asleep or waiting for I/O. Each thread contributes equally to the
-statistics.
-
-
-Usage: prof -p pid [-t total_secs] [-d delta_msec] [6.out args ...]
-
-The output modes (default -h) are:
-
- -P file.prof:
- Write the profile information to file.prof, in the format used by pprof.
- At the moment, this only works on Linux amd64 binaries and requires that the
- binary be written using 6l -e to produce ELF debug info.
- See http://code.google.com/p/google-perftools for details.
- -h: histograms
- How many times a sample occurred at each location.
- -f: dynamic functions
- At each sample period, print the name of the executing function.
- -l: dynamic file and line numbers
- At each sample period, print the file and line number of the executing instruction.
- -r: dynamic registers
- At each sample period, print the register contents.
- -s: dynamic function stack traces
- At each sample period, print the symbolic stack trace.
-
-Flag -t sets the maximum real time to sample, in seconds, and -d
-sets the sampling interval in milliseconds. The default is to sample
-every 100ms until the program completes.
-
-For reasons of disambiguation it is installed as 6prof although it also serves
-as an 8prof and a 5prof.
-
-*/
-package documentation
diff --git a/src/cmd/prof/gopprof b/src/cmd/prof/gopprof
deleted file mode 100755
index be5f84e9e..000000000
--- a/src/cmd/prof/gopprof
+++ /dev/null
@@ -1,4975 +0,0 @@
-#! /usr/bin/env perl
-
-# This is a copy of http://google-perftools.googlecode.com/svn/trunk/src/pprof
-# with local modifications to handle generation of SVG images and
-# the Go-style pprof paths. These modifications will probably filter
-# back into the official source before long.
-# It's convenient to have a copy here because we need just the one
-# Perl script, not all the C++ libraries that surround it.
-
-# Copyright (c) 1998-2007, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# ---
-# Program for printing the profile generated by common/profiler.cc,
-# or by the heap profiler (common/debugallocation.cc)
-#
-# The profile contains a sequence of entries of the form:
-# <count> <stack trace>
-# This program parses the profile, and generates user-readable
-# output.
-#
-# Examples:
-#
-# % tools/pprof "program" "profile"
-# Enters "interactive" mode
-#
-# % tools/pprof --text "program" "profile"
-# Generates one line per procedure
-#
-# % tools/pprof --gv "program" "profile"
-# Generates annotated call-graph and displays via "gv"
-#
-# % tools/pprof --gv --focus=Mutex "program" "profile"
-# Restrict to code paths that involve an entry that matches "Mutex"
-#
-# % tools/pprof --gv --focus=Mutex --ignore=string "program" "profile"
-# Restrict to code paths that involve an entry that matches "Mutex"
-# and does not match "string"
-#
-# % tools/pprof --list=IBF_CheckDocid "program" "profile"
-# Generates disassembly listing of all routines with at least one
-# sample that match the --list=<regexp> pattern. The listing is
-# annotated with the flat and cumulative sample counts at each line.
-#
-# % tools/pprof --disasm=IBF_CheckDocid "program" "profile"
-# Generates disassembly listing of all routines with at least one
-# sample that match the --disasm=<regexp> pattern. The listing is
-# annotated with the flat and cumulative sample counts at each PC value.
-#
-# TODO: Use color to indicate files?
-
-use strict;
-use warnings;
-use Getopt::Long;
-
-my $PPROF_VERSION = "1.5";
-
-# These are the object tools we use which can come from a
-# user-specified location using --tools, from the PPROF_TOOLS
-# environment variable, or from the environment.
-my %obj_tool_map = (
- "objdump" => "objdump",
- "nm" => "nm",
- "addr2line" => "addr2line",
- "c++filt" => "c++filt",
- ## ConfigureObjTools may add architecture-specific entries:
- #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables
- #"addr2line_pdb" => "addr2line-pdb", # ditto
- #"otool" => "otool", # equivalent of objdump on OS X
-);
-my $DOT = "dot"; # leave non-absolute, since it may be in /usr/local
-my $GV = "gv";
-my $KCACHEGRIND = "kcachegrind";
-my $PS2PDF = "ps2pdf";
-# These are used for dynamic profiles
-my $CURL = "curl";
-
-# These are the web pages that servers need to support for dynamic profiles
-my $HEAP_PAGE = "/pprof/heap";
-my $PROFILE_PAGE = "/pprof/profile"; # must support cgi-param "?seconds=#"
-my $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param
- # ?seconds=#&event=x&period=n
-my $GROWTH_PAGE = "/pprof/growth";
-my $CONTENTION_PAGE = "/pprof/contention";
-my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter
-my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?";
-my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST
-my $PROGRAM_NAME_PAGE = "/pprof/cmdline";
-
-# default binary name
-my $UNKNOWN_BINARY = "(unknown)";
-
-# There is a pervasive dependency on the length (in hex characters,
-# i.e., nibbles) of an address, distinguishing between 32-bit and
-# 64-bit profiles. To err on the safe size, default to 64-bit here:
-my $address_length = 16;
-
-# A list of paths to search for shared object files
-my @prefix_list = ();
-
-# Special routine name that should not have any symbols.
-# Used as separator to parse "addr2line -i" output.
-my $sep_symbol = '_fini';
-my $sep_address = undef;
-
-##### Argument parsing #####
-
-sub usage_string {
- return <<EOF;
-Usage:
-pprof [options] <program> <profiles>
- <profiles> is a space separated list of profile names.
-pprof [options] <symbolized-profiles>
- <symbolized-profiles> is a list of profile files where each file contains
- the necessary symbol mappings as well as profile data (likely generated
- with --raw).
-pprof [options] <profile>
- <profile> is a remote form. Symbols are obtained from host:port$SYMBOL_PAGE
-
- Each name can be:
- /path/to/profile - a path to a profile file
- host:port[/<service>] - a location of a service to get profile from
-
- The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
- $GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
- or /pprof/filteredprofile.
- For instance:
- pprof http://myserver.com:80$HEAP_PAGE
- If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
-pprof --symbols <program>
- Maps addresses to symbol names. In this mode, stdin should be a
- list of library mappings, in the same format as is found in the heap-
- and cpu-profile files (this loosely matches that of /proc/self/maps
- on linux), followed by a list of hex addresses to map, one per line.
-
- For more help with querying remote servers, including how to add the
- necessary server-side support code, see this filename (or one like it):
-
- /usr/doc/google-perftools-$PPROF_VERSION/pprof_remote_servers.html
-
-Options:
- --cum Sort by cumulative data
- --base=<base> Subtract <base> from <profile> before display
- --interactive Run in interactive mode (interactive "help" gives help) [default]
- --seconds=<n> Length of time for dynamic profiles [default=30 secs]
- --add_lib=<file> Read additional symbols and line info from the given library
- --lib_prefix=<dir> Comma separated list of library path prefixes
-
-Reporting Granularity:
- --addresses Report at address level
- --lines Report at source line level
- --functions Report at function level [default]
- --files Report at source file level
-
-Output type:
- --text Generate text report
- --callgrind Generate callgrind format to stdout
- --gv Generate Postscript and display
- --web Generate SVG and display
- --list=<regexp> Generate source listing of matching routines
- --disasm=<regexp> Generate disassembly of matching routines
- --symbols Print demangled symbol names found at given addresses
- --dot Generate DOT file to stdout
- --ps Generate Postcript to stdout
- --pdf Generate PDF to stdout
- --svg Generate SVG to stdout
- --gif Generate GIF to stdout
- --raw Generate symbolized pprof data (useful with remote fetch)
-
-Heap-Profile Options:
- --inuse_space Display in-use (mega)bytes [default]
- --inuse_objects Display in-use objects
- --alloc_space Display allocated (mega)bytes
- --alloc_objects Display allocated objects
- --show_bytes Display space in bytes
- --drop_negative Ignore negative differences
-
-Contention-profile options:
- --total_delay Display total delay at each region [default]
- --contentions Display number of delays at each region
- --mean_delay Display mean delay at each region
-
-Call-graph Options:
- --nodecount=<n> Show at most so many nodes [default=80]
- --nodefraction=<f> Hide nodes below <f>*total [default=.005]
- --edgefraction=<f> Hide edges below <f>*total [default=.001]
- --focus=<regexp> Focus on nodes matching <regexp>
- --ignore=<regexp> Ignore nodes matching <regexp>
- --scale=<n> Set GV scaling [default=0]
- --heapcheck Make nodes with non-0 object counts
- (i.e. direct leak generators) more visible
-
-Miscellaneous:
- --tools=<prefix> Prefix for object tool pathnames
- --test Run unit tests
- --help This message
- --version Version information
-
-Environment Variables:
- PPROF_TMPDIR Profiles directory. Defaults to \$HOME/pprof
- PPROF_TOOLS Prefix for object tools pathnames
-
-Examples:
-
-pprof /bin/ls ls.prof
- Enters "interactive" mode
-pprof --text /bin/ls ls.prof
- Outputs one line per procedure
-pprof --web /bin/ls ls.prof
- Displays annotated call-graph in web browser
-pprof --gv /bin/ls ls.prof
- Displays annotated call-graph via 'gv'
-pprof --gv --focus=Mutex /bin/ls ls.prof
- Restricts to code paths including a .*Mutex.* entry
-pprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof
- Code paths including Mutex but not string
-pprof --list=getdir /bin/ls ls.prof
- (Per-line) annotated source listing for getdir()
-pprof --disasm=getdir /bin/ls ls.prof
- (Per-PC) annotated disassembly for getdir()
-
-pprof http://localhost:1234/
- Enters "interactive" mode
-pprof --text localhost:1234
- Outputs one line per procedure for localhost:1234
-pprof --raw localhost:1234 > ./local.raw
-pprof --text ./local.raw
- Fetches a remote profile for later analysis and then
- analyzes it in text mode.
-EOF
-}
-
-sub version_string {
- return <<EOF
-pprof (part of google-perftools $PPROF_VERSION)
-
-Copyright 1998-2007 Google Inc.
-
-This is BSD licensed software; see the source for copying conditions
-and license information.
-There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE.
-EOF
-}
-
-sub usage {
- my $msg = shift;
- print STDERR "$msg\n\n";
- print STDERR usage_string();
- print STDERR "\nFATAL ERROR: $msg\n"; # just as a reminder
- exit(1);
-}
-
-sub Init() {
- # Setup tmp-file name and handler to clean it up.
- # We do this in the very beginning so that we can use
- # error() and cleanup() function anytime here after.
- $main::tmpfile_sym = "/tmp/pprof$$.sym";
- $main::tmpfile_ps = "/tmp/pprof$$";
- $main::next_tmpfile = 0;
- $SIG{'INT'} = \&sighandler;
-
- # Cache from filename/linenumber to source code
- $main::source_cache = ();
-
- $main::opt_help = 0;
- $main::opt_version = 0;
-
- $main::opt_cum = 0;
- $main::opt_base = '';
- $main::opt_addresses = 0;
- $main::opt_lines = 0;
- $main::opt_functions = 0;
- $main::opt_files = 0;
- $main::opt_lib_prefix = "";
-
- $main::opt_text = 0;
- $main::opt_callgrind = 0;
- $main::opt_list = "";
- $main::opt_disasm = "";
- $main::opt_symbols = 0;
- $main::opt_gv = 0;
- $main::opt_web = 0;
- $main::opt_dot = 0;
- $main::opt_ps = 0;
- $main::opt_pdf = 0;
- $main::opt_gif = 0;
- $main::opt_svg = 0;
- $main::opt_raw = 0;
-
- $main::opt_nodecount = 80;
- $main::opt_nodefraction = 0.005;
- $main::opt_edgefraction = 0.001;
- $main::opt_focus = '';
- $main::opt_ignore = '';
- $main::opt_scale = 0;
- $main::opt_heapcheck = 0;
- $main::opt_seconds = 30;
- $main::opt_lib = "";
-
- $main::opt_inuse_space = 0;
- $main::opt_inuse_objects = 0;
- $main::opt_alloc_space = 0;
- $main::opt_alloc_objects = 0;
- $main::opt_show_bytes = 0;
- $main::opt_drop_negative = 0;
- $main::opt_interactive = 0;
-
- $main::opt_total_delay = 0;
- $main::opt_contentions = 0;
- $main::opt_mean_delay = 0;
-
- $main::opt_tools = "";
- $main::opt_debug = 0;
- $main::opt_test = 0;
-
- # These are undocumented flags used only by unittests.
- $main::opt_test_stride = 0;
-
- # Are we using $SYMBOL_PAGE?
- $main::use_symbol_page = 0;
-
- # Files returned by TempName.
- %main::tempnames = ();
-
- # Type of profile we are dealing with
- # Supported types:
- # cpu
- # heap
- # growth
- # contention
- $main::profile_type = ''; # Empty type means "unknown"
-
- GetOptions("help!" => \$main::opt_help,
- "version!" => \$main::opt_version,
- "cum!" => \$main::opt_cum,
- "base=s" => \$main::opt_base,
- "seconds=i" => \$main::opt_seconds,
- "add_lib=s" => \$main::opt_lib,
- "lib_prefix=s" => \$main::opt_lib_prefix,
- "functions!" => \$main::opt_functions,
- "lines!" => \$main::opt_lines,
- "addresses!" => \$main::opt_addresses,
- "files!" => \$main::opt_files,
- "text!" => \$main::opt_text,
- "callgrind!" => \$main::opt_callgrind,
- "list=s" => \$main::opt_list,
- "disasm=s" => \$main::opt_disasm,
- "symbols!" => \$main::opt_symbols,
- "gv!" => \$main::opt_gv,
- "web!" => \$main::opt_web,
- "dot!" => \$main::opt_dot,
- "ps!" => \$main::opt_ps,
- "pdf!" => \$main::opt_pdf,
- "svg!" => \$main::opt_svg,
- "gif!" => \$main::opt_gif,
- "raw!" => \$main::opt_raw,
- "interactive!" => \$main::opt_interactive,
- "nodecount=i" => \$main::opt_nodecount,
- "nodefraction=f" => \$main::opt_nodefraction,
- "edgefraction=f" => \$main::opt_edgefraction,
- "focus=s" => \$main::opt_focus,
- "ignore=s" => \$main::opt_ignore,
- "scale=i" => \$main::opt_scale,
- "heapcheck" => \$main::opt_heapcheck,
- "inuse_space!" => \$main::opt_inuse_space,
- "inuse_objects!" => \$main::opt_inuse_objects,
- "alloc_space!" => \$main::opt_alloc_space,
- "alloc_objects!" => \$main::opt_alloc_objects,
- "show_bytes!" => \$main::opt_show_bytes,
- "drop_negative!" => \$main::opt_drop_negative,
- "total_delay!" => \$main::opt_total_delay,
- "contentions!" => \$main::opt_contentions,
- "mean_delay!" => \$main::opt_mean_delay,
- "tools=s" => \$main::opt_tools,
- "test!" => \$main::opt_test,
- "debug!" => \$main::opt_debug,
- # Undocumented flags used only by unittests:
- "test_stride=i" => \$main::opt_test_stride,
- ) || usage("Invalid option(s)");
-
- # Deal with the standard --help and --version
- if ($main::opt_help) {
- print usage_string();
- exit(0);
- }
-
- if ($main::opt_version) {
- print version_string();
- exit(0);
- }
-
- # Disassembly/listing/symbols mode requires address-level info
- if ($main::opt_disasm || $main::opt_list || $main::opt_symbols) {
- $main::opt_functions = 0;
- $main::opt_lines = 0;
- $main::opt_addresses = 1;
- $main::opt_files = 0;
- }
-
- # Check heap-profiling flags
- if ($main::opt_inuse_space +
- $main::opt_inuse_objects +
- $main::opt_alloc_space +
- $main::opt_alloc_objects > 1) {
- usage("Specify at most on of --inuse/--alloc options");
- }
-
- # Check output granularities
- my $grains =
- $main::opt_functions +
- $main::opt_lines +
- $main::opt_addresses +
- $main::opt_files +
- 0;
- if ($grains > 1) {
- usage("Only specify one output granularity option");
- }
- if ($grains == 0) {
- $main::opt_functions = 1;
- }
-
- # Check output modes
- my $modes =
- $main::opt_text +
- $main::opt_callgrind +
- ($main::opt_list eq '' ? 0 : 1) +
- ($main::opt_disasm eq '' ? 0 : 1) +
- ($main::opt_symbols == 0 ? 0 : 1) +
- $main::opt_gv +
- $main::opt_web +
- $main::opt_dot +
- $main::opt_ps +
- $main::opt_pdf +
- $main::opt_svg +
- $main::opt_gif +
- $main::opt_raw +
- $main::opt_interactive +
- 0;
- if ($modes > 1) {
- usage("Only specify one output mode");
- }
- if ($modes == 0) {
- if (-t STDOUT) { # If STDOUT is a tty, activate interactive mode
- $main::opt_interactive = 1;
- } else {
- $main::opt_text = 1;
- }
- }
-
- if ($main::opt_test) {
- RunUnitTests();
- # Should not return
- exit(1);
- }
-
- # Binary name and profile arguments list
- $main::prog = "";
- @main::pfile_args = ();
-
- # Remote profiling without a binary (using $SYMBOL_PAGE instead)
- if (IsProfileURL($ARGV[0])) {
- $main::use_symbol_page = 1;
- } elsif (IsSymbolizedProfileFile($ARGV[0])) {
- $main::use_symbolized_profile = 1;
- $main::prog = $UNKNOWN_BINARY; # will be set later from the profile file
- }
-
- if ($main::use_symbol_page || $main::use_symbolized_profile) {
- # We don't need a binary!
- my %disabled = ('--lines' => $main::opt_lines,
- '--disasm' => $main::opt_disasm);
- for my $option (keys %disabled) {
- usage("$option cannot be used without a binary") if $disabled{$option};
- }
- # Set $main::prog later...
- scalar(@ARGV) || usage("Did not specify profile file");
- } elsif ($main::opt_symbols) {
- # --symbols needs a binary-name (to run nm on, etc) but not profiles
- $main::prog = shift(@ARGV) || usage("Did not specify program");
- } else {
- $main::prog = shift(@ARGV) || usage("Did not specify program");
- scalar(@ARGV) || usage("Did not specify profile file");
- }
-
- # Parse profile file/location arguments
- foreach my $farg (@ARGV) {
- if ($farg =~ m/(.*)\@([0-9]+)(|\/.*)$/ ) {
- my $machine = $1;
- my $num_machines = $2;
- my $path = $3;
- for (my $i = 0; $i < $num_machines; $i++) {
- unshift(@main::pfile_args, "$i.$machine$path");
- }
- } else {
- unshift(@main::pfile_args, $farg);
- }
- }
-
- if ($main::use_symbol_page) {
- unless (IsProfileURL($main::pfile_args[0])) {
- error("The first profile should be a remote form to use $SYMBOL_PAGE\n");
- }
- CheckSymbolPage();
- $main::prog = FetchProgramName();
- } elsif (!$main::use_symbolized_profile) { # may not need objtools!
- ConfigureObjTools($main::prog)
- }
-
- # Break the opt_lib_prefix into the prefix_list array
- @prefix_list = split (',', $main::opt_lib_prefix);
-
- # Remove trailing / from the prefixes, in the list to prevent
- # searching things like /my/path//lib/mylib.so
- foreach (@prefix_list) {
- s|/+$||;
- }
-}
-
-sub Main() {
- Init();
- $main::collected_profile = undef;
- @main::profile_files = ();
- $main::op_time = time();
-
- # Printing symbols is special and requires a lot less info that most.
- if ($main::opt_symbols) {
- PrintSymbols(*STDIN); # Get /proc/maps and symbols output from stdin
- return;
- }
-
- # Fetch all profile data
- FetchDynamicProfiles();
-
- # this will hold symbols that we read from the profile files
- my $symbol_map = {};
-
- # Read one profile, pick the last item on the list
- my $data = ReadProfile($main::prog, pop(@main::profile_files));
- my $profile = $data->{profile};
- my $pcs = $data->{pcs};
- my $libs = $data->{libs}; # Info about main program and shared libraries
- $symbol_map = MergeSymbols($symbol_map, $data->{symbols});
-
- # Add additional profiles, if available.
- if (scalar(@main::profile_files) > 0) {
- foreach my $pname (@main::profile_files) {
- my $data2 = ReadProfile($main::prog, $pname);
- $profile = AddProfile($profile, $data2->{profile});
- $pcs = AddPcs($pcs, $data2->{pcs});
- $symbol_map = MergeSymbols($symbol_map, $data2->{symbols});
- }
- }
-
- # Subtract base from profile, if specified
- if ($main::opt_base ne '') {
- my $base = ReadProfile($main::prog, $main::opt_base);
- $profile = SubtractProfile($profile, $base->{profile});
- $pcs = AddPcs($pcs, $base->{pcs});
- $symbol_map = MergeSymbols($symbol_map, $base->{symbols});
- }
-
- # Get total data in profile
- my $total = TotalProfile($profile);
-
- # Collect symbols
- my $symbols;
- if ($main::use_symbolized_profile) {
- $symbols = FetchSymbols($pcs, $symbol_map);
- } elsif ($main::use_symbol_page) {
- $symbols = FetchSymbols($pcs);
- } else {
- $symbols = ExtractSymbols($libs, $pcs);
- }
-
- # Remove uniniteresting stack items
- $profile = RemoveUninterestingFrames($symbols, $profile);
-
- # Focus?
- if ($main::opt_focus ne '') {
- $profile = FocusProfile($symbols, $profile, $main::opt_focus);
- }
-
- # Ignore?
- if ($main::opt_ignore ne '') {
- $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore);
- }
-
- my $calls = ExtractCalls($symbols, $profile);
-
- # Reduce profiles to required output granularity, and also clean
- # each stack trace so a given entry exists at most once.
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- # Print
- if (!$main::opt_interactive) {
- if ($main::opt_disasm) {
- PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm, $total);
- } elsif ($main::opt_list) {
- PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
- } elsif ($main::opt_text) {
- # Make sure the output is empty when have nothing to report
- # (only matters when --heapcheck is given but we must be
- # compatible with old branches that did not pass --heapcheck always):
- if ($total != 0) {
- printf("Total: %s %s\n", Unparse($total), Units());
- }
- PrintText($symbols, $flat, $cumulative, $total, -1);
- } elsif ($main::opt_raw) {
- PrintSymbolizedProfile($symbols, $profile, $main::prog);
- } elsif ($main::opt_callgrind) {
- PrintCallgrind($calls);
- } else {
- if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
- if ($main::opt_gv) {
- RunGV(TempName($main::next_tmpfile, "ps"), "");
- } elsif ($main::opt_web) {
- my $tmp = TempName($main::next_tmpfile, "svg");
- RunWeb($tmp);
- # The command we run might hand the file name off
- # to an already running browser instance and then exit.
- # Normally, we'd remove $tmp on exit (right now),
- # but fork a child to remove $tmp a little later, so that the
- # browser has time to load it first.
- delete $main::tempnames{$tmp};
- if (fork() == 0) {
- sleep 5;
- unlink($tmp);
- exit(0);
- }
- }
- } else {
- exit(1);
- }
- }
- } else {
- InteractiveMode($profile, $symbols, $libs, $total);
- }
-
- cleanup();
- exit(0);
-}
-
-##### Entry Point #####
-
-Main();
-
-# Temporary code to detect if we're running on a Goobuntu system.
-# These systems don't have the right stuff installed for the special
-# Readline libraries to work, so as a temporary workaround, we default
-# to using the normal stdio code, rather than the fancier readline-based
-# code
-sub ReadlineMightFail {
- if (-e '/lib/libtermcap.so.2') {
- return 0; # libtermcap exists, so readline should be okay
- } else {
- return 1;
- }
-}
-
-sub RunGV {
- my $fname = shift;
- my $bg = shift; # "" or " &" if we should run in background
- if (!system("$GV --version >/dev/null 2>&1")) {
- # Options using double dash are supported by this gv version.
- # Also, turn on noantialias to better handle bug in gv for
- # postscript files with large dimensions.
- # TODO: Maybe we should not pass the --noantialias flag
- # if the gv version is known to work properly without the flag.
- system("$GV --scale=$main::opt_scale --noantialias " . $fname . $bg);
- } else {
- # Old gv version - only supports options that use single dash.
- print STDERR "$GV -scale $main::opt_scale\n";
- system("$GV -scale $main::opt_scale " . $fname . $bg);
- }
-}
-
-sub RunWeb {
- my $fname = shift;
- print STDERR "Loading web page file:///$fname\n";
-
- if (`uname` =~ /Darwin/) {
- # OS X: open will use standard preference for SVG files.
- system("/usr/bin/open", $fname);
- return;
- }
-
- # Some kind of Unix; try generic symlinks, then specific browsers.
- # (Stop once we find one.)
- # Works best if the browser is already running.
- my @alt = (
- "/etc/alternatives/gnome-www-browser",
- "/etc/alternatives/x-www-browser",
- "google-chrome",
- "firefox",
- );
- foreach my $b (@alt) {
- if (-f $b) {
- if (system($b, $fname) == 0) {
- return;
- }
- }
- }
-
- print STDERR "Could not load web browser.\n";
-}
-
-sub RunKcachegrind {
- my $fname = shift;
- my $bg = shift; # "" or " &" if we should run in background
- print STDERR "Starting '$KCACHEGRIND " . $fname . $bg . "'\n";
- system("$KCACHEGRIND " . $fname . $bg);
-}
-
-
-##### Interactive helper routines #####
-
-sub InteractiveMode {
- $| = 1; # Make output unbuffered for interactive mode
- my ($orig_profile, $symbols, $libs, $total) = @_;
-
- print STDERR "Welcome to pprof! For help, type 'help'.\n";
-
- # Use ReadLine if it's installed and input comes from a console.
- if ( -t STDIN &&
- !ReadlineMightFail() &&
- defined(eval {require Term::ReadLine}) ) {
- my $term = new Term::ReadLine 'pprof';
- while ( defined ($_ = $term->readline('(pprof) '))) {
- $term->addhistory($_) if /\S/;
- if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
- last; # exit when we get an interactive command to quit
- }
- }
- } else { # don't have readline
- while (1) {
- print STDERR "(pprof) ";
- $_ = <STDIN>;
- last if ! defined $_ ;
- s/\r//g; # turn windows-looking lines into unix-looking lines
-
- # Save some flags that might be reset by InteractiveCommand()
- my $save_opt_lines = $main::opt_lines;
-
- if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
- last; # exit when we get an interactive command to quit
- }
-
- # Restore flags
- $main::opt_lines = $save_opt_lines;
- }
- }
-}
-
-# Takes two args: orig profile, and command to run.
-# Returns 1 if we should keep going, or 0 if we were asked to quit
-sub InteractiveCommand {
- my($orig_profile, $symbols, $libs, $total, $command) = @_;
- $_ = $command; # just to make future m//'s easier
- if (!defined($_)) {
- print STDERR "\n";
- return 0;
- }
- if (m/^\s*quit/) {
- return 0;
- }
- if (m/^\s*help/) {
- InteractiveHelpMessage();
- return 1;
- }
- # Clear all the mode options -- mode is controlled by "$command"
- $main::opt_text = 0;
- $main::opt_callgrind = 0;
- $main::opt_disasm = 0;
- $main::opt_list = 0;
- $main::opt_gv = 0;
- $main::opt_cum = 0;
-
- if (m/^\s*(text|top)(\d*)\s*(.*)/) {
- $main::opt_text = 1;
-
- my $line_limit = ($2 ne "") ? int($2) : 10;
-
- my $routine;
- my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($3);
-
- my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- PrintText($symbols, $flat, $cumulative, $total, $line_limit);
- return 1;
- }
- if (m/^\s*callgrind\s*([^ \n]*)/) {
- $main::opt_callgrind = 1;
-
- # Get derived profiles
- my $calls = ExtractCalls($symbols, $orig_profile);
- my $filename = $1;
- if ( $1 eq '' ) {
- $filename = TempName($main::next_tmpfile, "callgrind");
- }
- PrintCallgrind($calls, $filename);
- if ( $1 eq '' ) {
- RunKcachegrind($filename, " & ");
- $main::next_tmpfile++;
- }
-
- return 1;
- }
- if (m/^\s*(web)?list\s*(.+)/) {
- my $html = (defined($1) && ($1 eq "web"));
- $main::opt_list = 1;
-
- my $routine;
- my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($2);
-
- my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
- return 1;
- }
- if (m/^\s*disasm\s*(.+)/) {
- $main::opt_disasm = 1;
-
- my $routine;
- my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($1);
-
- # Process current profile to account for various settings
- my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- PrintDisassembly($libs, $flat, $cumulative, $routine, $total);
- return 1;
- }
- if (m/^\s*(gv|web)\s*(.*)/) {
- $main::opt_gv = 0;
- $main::opt_web = 0;
- if ($1 eq "gv") {
- $main::opt_gv = 1;
- } elsif ($1 eq "web") {
- $main::opt_web = 1;
- }
-
- my $focus;
- my $ignore;
- ($focus, $ignore) = ParseInteractiveArgs($2);
-
- # Process current profile to account for various settings
- my $profile = ProcessProfile($total, $orig_profile, $symbols, $focus, $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
- if ($main::opt_gv) {
- RunGV(TempName($main::next_tmpfile, "ps"), " &");
- } elsif ($main::opt_web) {
- RunWeb(TempName($main::next_tmpfile, "svg"));
- }
- $main::next_tmpfile++;
- }
- return 1;
- }
- if (m/^\s*$/) {
- return 1;
- }
- print STDERR "Unknown command: try 'help'.\n";
- return 1;
-}
-
-
-sub ProcessProfile {
- my $total_count = shift;
- my $orig_profile = shift;
- my $symbols = shift;
- my $focus = shift;
- my $ignore = shift;
-
- # Process current profile to account for various settings
- my $profile = $orig_profile;
- printf("Total: %s %s\n", Unparse($total_count), Units());
- if ($focus ne '') {
- $profile = FocusProfile($symbols, $profile, $focus);
- my $focus_count = TotalProfile($profile);
- printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n",
- $focus,
- Unparse($focus_count), Units(),
- Unparse($total_count), ($focus_count*100.0) / $total_count);
- }
- if ($ignore ne '') {
- $profile = IgnoreProfile($symbols, $profile, $ignore);
- my $ignore_count = TotalProfile($profile);
- printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n",
- $ignore,
- Unparse($ignore_count), Units(),
- Unparse($total_count),
- ($ignore_count*100.0) / $total_count);
- }
-
- return $profile;
-}
-
-sub InteractiveHelpMessage {
- print STDERR <<ENDOFHELP;
-Interactive pprof mode
-
-Commands:
- gv
- gv [focus] [-ignore1] [-ignore2]
- Show graphical hierarchical display of current profile. Without
- any arguments, shows all samples in the profile. With the optional
- "focus" argument, restricts the samples shown to just those where
- the "focus" regular expression matches a routine name on the stack
- trace.
-
- web
- web [focus] [-ignore1] [-ignore2]
- Like GV, but displays profile in your web browser instead of using
- Ghostview. Works best if your web browser is already running.
- To change the browser that gets used:
- On Linux, set the /etc/alternatives/gnome-www-browser symlink.
- On OS X, change the Finder association for SVG files.
-
- list [routine_regexp] [-ignore1] [-ignore2]
- Show source listing of routines whose names match "routine_regexp"
-
- weblist [routine_regexp] [-ignore1] [-ignore2]
- Displays a source listing of routines whose names match "routine_regexp"
- in a web browser. You can click on source lines to view the
- corresponding disassembly.
-
- top [--cum] [-ignore1] [-ignore2]
- top20 [--cum] [-ignore1] [-ignore2]
- top37 [--cum] [-ignore1] [-ignore2]
- Show top lines ordered by flat profile count, or cumulative count
- if --cum is specified. If a number is present after 'top', the
- top K routines will be shown (defaults to showing the top 10)
-
- disasm [routine_regexp] [-ignore1] [-ignore2]
- Show disassembly of routines whose names match "routine_regexp",
- annotated with sample counts.
-
- callgrind
- callgrind [filename]
- Generates callgrind file. If no filename is given, kcachegrind is called.
-
- help - This listing
- quit or ^D - End pprof
-
-For commands that accept optional -ignore tags, samples where any routine in
-the stack trace matches the regular expression in any of the -ignore
-parameters will be ignored.
-
-Further pprof details are available at this location (or one similar):
-
- /usr/doc/google-perftools-$PPROF_VERSION/cpu_profiler.html
- /usr/doc/google-perftools-$PPROF_VERSION/heap_profiler.html
-
-ENDOFHELP
-}
-sub ParseInteractiveArgs {
- my $args = shift;
- my $focus = "";
- my $ignore = "";
- my @x = split(/ +/, $args);
- foreach $a (@x) {
- if ($a =~ m/^(--|-)lines$/) {
- $main::opt_lines = 1;
- } elsif ($a =~ m/^(--|-)cum$/) {
- $main::opt_cum = 1;
- } elsif ($a =~ m/^-(.*)/) {
- $ignore .= (($ignore ne "") ? "|" : "" ) . $1;
- } else {
- $focus .= (($focus ne "") ? "|" : "" ) . $a;
- }
- }
- if ($ignore ne "") {
- print STDERR "Ignoring samples in call stacks that match '$ignore'\n";
- }
- return ($focus, $ignore);
-}
-
-##### Output code #####
-
-sub TempName {
- my $fnum = shift;
- my $ext = shift;
- my $file = "$main::tmpfile_ps.$fnum.$ext";
- $main::tempnames{$file} = 1;
- return $file;
-}
-
-# Print profile data in packed binary format (64-bit) to standard out
-sub PrintProfileData {
- my $profile = shift;
-
- # print header (64-bit style)
- # (zero) (header-size) (version) (sample-period) (zero)
- print pack('L*', 0, 0, 3, 0, 0, 0, 1, 0, 0, 0);
-
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- if ($#addrs >= 0) {
- my $depth = $#addrs + 1;
- # int(foo / 2**32) is the only reliable way to get rid of bottom
- # 32 bits on both 32- and 64-bit systems.
- print pack('L*', $count & 0xFFFFFFFF, int($count / 2**32));
- print pack('L*', $depth & 0xFFFFFFFF, int($depth / 2**32));
-
- foreach my $full_addr (@addrs) {
- my $addr = $full_addr;
- $addr =~ s/0x0*//; # strip off leading 0x, zeroes
- if (length($addr) > 16) {
- print STDERR "Invalid address in profile: $full_addr\n";
- next;
- }
- my $low_addr = substr($addr, -8); # get last 8 hex chars
- my $high_addr = substr($addr, -16, 8); # get up to 8 more hex chars
- print pack('L*', hex('0x' . $low_addr), hex('0x' . $high_addr));
- }
- }
- }
-}
-
-# Print symbols and profile data
-sub PrintSymbolizedProfile {
- my $symbols = shift;
- my $profile = shift;
- my $prog = shift;
-
- $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $symbol_marker = $&;
-
- print '--- ', $symbol_marker, "\n";
- if (defined($prog)) {
- print 'binary=', $prog, "\n";
- }
- while (my ($pc, $name) = each(%{$symbols})) {
- my $sep = ' ';
- print '0x', $pc;
- # We have a list of function names, which include the inlined
- # calls. They are separated (and terminated) by --, which is
- # illegal in function names.
- for (my $j = 2; $j <= $#{$name}; $j += 3) {
- print $sep, $name->[$j];
- $sep = '--';
- }
- print "\n";
- }
- print '---', "\n";
-
- $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $profile_marker = $&;
- print '--- ', $profile_marker, "\n";
- if (defined($main::collected_profile)) {
- # if used with remote fetch, simply dump the collected profile to output.
- open(SRC, "<$main::collected_profile");
- while (<SRC>) {
- print $_;
- }
- close(SRC);
- } else {
- # dump a cpu-format profile to standard out
- PrintProfileData($profile);
- }
-}
-
-# Print text output
-sub PrintText {
- my $symbols = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $total = shift;
- my $line_limit = shift;
-
- # Which profile to sort by?
- my $s = $main::opt_cum ? $cumulative : $flat;
-
- my $running_sum = 0;
- my $lines = 0;
- foreach my $k (sort { GetEntry($s, $b) <=> GetEntry($s, $a) || $a cmp $b }
- keys(%{$cumulative})) {
- my $f = GetEntry($flat, $k);
- my $c = GetEntry($cumulative, $k);
- $running_sum += $f;
-
- my $sym = $k;
- if (exists($symbols->{$k})) {
- $sym = $symbols->{$k}->[0] . " " . $symbols->{$k}->[1];
- if ($main::opt_addresses) {
- $sym = $k . " " . $sym;
- }
- }
-
- if ($f != 0 || $c != 0) {
- printf("%8s %6s %6s %8s %6s %s\n",
- Unparse($f),
- Percent($f, $total),
- Percent($running_sum, $total),
- Unparse($c),
- Percent($c, $total),
- $sym);
- }
- $lines++;
- last if ($line_limit >= 0 && $lines >= $line_limit);
- }
-}
-
-# Print the call graph in a way that's suiteable for callgrind.
-sub PrintCallgrind {
- my $calls = shift;
- my $filename;
- if ($main::opt_interactive) {
- $filename = shift;
- print STDERR "Writing callgrind file to '$filename'.\n"
- } else {
- $filename = "&STDOUT";
- }
- open(CG, ">".$filename );
- printf CG ("events: Hits\n\n");
- foreach my $call ( map { $_->[0] }
- sort { $a->[1] cmp $b ->[1] ||
- $a->[2] <=> $b->[2] }
- map { /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
- [$_, $1, $2] }
- keys %$calls ) {
- my $count = int($calls->{$call});
- $call =~ /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
- my ( $caller_file, $caller_line, $caller_function,
- $callee_file, $callee_line, $callee_function ) =
- ( $1, $2, $3, $5, $6, $7 );
-
- printf CG ("fl=$caller_file\nfn=$caller_function\n");
- if (defined $6) {
- printf CG ("cfl=$callee_file\n");
- printf CG ("cfn=$callee_function\n");
- printf CG ("calls=$count $callee_line\n");
- }
- printf CG ("$caller_line $count\n\n");
- }
-}
-
-# Print disassembly for all all routines that match $main::opt_disasm
-sub PrintDisassembly {
- my $libs = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $disasm_opts = shift;
- my $total = shift;
-
- foreach my $lib (@{$libs}) {
- my $symbol_table = GetProcedureBoundaries($lib->[0], $disasm_opts);
- my $offset = AddressSub($lib->[1], $lib->[3]);
- foreach my $routine (sort ByName keys(%{$symbol_table})) {
- my $start_addr = $symbol_table->{$routine}->[0];
- my $end_addr = $symbol_table->{$routine}->[1];
- # See if there are any samples in this routine
- my $length = hex(AddressSub($end_addr, $start_addr));
- my $addr = AddressAdd($start_addr, $offset);
- for (my $i = 0; $i < $length; $i++) {
- if (defined($cumulative->{$addr})) {
- PrintDisassembledFunction($lib->[0], $offset,
- $routine, $flat, $cumulative,
- $start_addr, $end_addr, $total);
- last;
- }
- $addr = AddressInc($addr);
- }
- }
- }
-}
-
-# Return reference to array of tuples of the form:
-# [start_address, filename, linenumber, instruction, limit_address]
-# E.g.,
-# ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"]
-sub Disassemble {
- my $prog = shift;
- my $offset = shift;
- my $start_addr = shift;
- my $end_addr = shift;
-
- my $objdump = $obj_tool_map{"objdump"};
- my $cmd = sprintf("$objdump -C -d -l --no-show-raw-insn " .
- "--start-address=0x$start_addr " .
- "--stop-address=0x$end_addr $prog");
- open(OBJDUMP, "$cmd |") || error("$objdump: $!\n");
- my @result = ();
- my $filename = "";
- my $linenumber = -1;
- my $last = ["", "", "", ""];
- while (<OBJDUMP>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- chop;
- if (m|\s*([^:\s]+):(\d+)\s*$|) {
- # Location line of the form:
- # <filename>:<linenumber>
- $filename = $1;
- $linenumber = $2;
- } elsif (m/^ +([0-9a-f]+):\s*(.*)/) {
- # Disassembly line -- zero-extend address to full length
- my $addr = HexExtend($1);
- my $k = AddressAdd($addr, $offset);
- $last->[4] = $k; # Store ending address for previous instruction
- $last = [$k, $filename, $linenumber, $2, $end_addr];
- push(@result, $last);
- }
- }
- close(OBJDUMP);
- return @result;
-}
-
-# The input file should contain lines of the form /proc/maps-like
-# output (same format as expected from the profiles) or that looks
-# like hex addresses (like "0xDEADBEEF"). We will parse all
-# /proc/maps output, and for all the hex addresses, we will output
-# "short" symbol names, one per line, in the same order as the input.
-sub PrintSymbols {
- my $maps_and_symbols_file = shift;
-
- # ParseLibraries expects pcs to be in a set. Fine by us...
- my @pclist = (); # pcs in sorted order
- my $pcs = {};
- my $map = "";
- foreach my $line (<$maps_and_symbols_file>) {
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- if ($line =~ /\b(0x[0-9a-f]+)\b/i) {
- push(@pclist, HexExtend($1));
- $pcs->{$pclist[-1]} = 1;
- } else {
- $map .= $line;
- }
- }
-
- my $libs = ParseLibraries($main::prog, $map, $pcs);
- my $symbols = ExtractSymbols($libs, $pcs);
-
- foreach my $pc (@pclist) {
- # ->[0] is the shortname, ->[2] is the full name
- print(($symbols->{$pc}->[0] || "??") . "\n");
- }
-}
-
-
-# For sorting functions by name
-sub ByName {
- return ShortFunctionName($a) cmp ShortFunctionName($b);
-}
-
-# Print source-listing for all all routines that match $main::opt_list
-sub PrintListing {
- my $total = shift;
- my $libs = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $list_opts = shift;
- my $html = shift;
-
- my $output = \*STDOUT;
- my $fname = "";
-
-
- if ($html) {
- # Arrange to write the output to a temporary file
- $fname = TempName($main::next_tmpfile, "html");
- $main::next_tmpfile++;
- if (!open(TEMP, ">$fname")) {
- print STDERR "$fname: $!\n";
- return;
- }
- $output = \*TEMP;
- print $output HtmlListingHeader();
- printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
- $main::prog, Unparse($total), Units());
- }
-
- my $listed = 0;
- foreach my $lib (@{$libs}) {
- my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
- my $offset = AddressSub($lib->[1], $lib->[3]);
- foreach my $routine (sort ByName keys(%{$symbol_table})) {
- # Print if there are any samples in this routine
- my $start_addr = $symbol_table->{$routine}->[0];
- my $end_addr = $symbol_table->{$routine}->[1];
- my $length = hex(AddressSub($end_addr, $start_addr));
- my $addr = AddressAdd($start_addr, $offset);
- for (my $i = 0; $i < $length; $i++) {
- if (defined($cumulative->{$addr})) {
- $listed += PrintSource(
- $lib->[0], $offset,
- $routine, $flat, $cumulative,
- $start_addr, $end_addr,
- $html,
- $output);
- last;
- }
- $addr = AddressInc($addr);
- }
- }
- }
-
- if ($html) {
- if ($listed > 0) {
- print $output HtmlListingFooter();
- close($output);
- RunWeb($fname);
- } else {
- close($output);
- unlink($fname);
- }
- }
-}
-
-sub HtmlListingHeader {
- return <<'EOF';
-<DOCTYPE html>
-<html>
-<head>
-<title>Pprof listing</title>
-<style type="text/css">
-body {
- font-family: sans-serif;
-}
-h1 {
- font-size: 1.5em;
- margin-bottom: 4px;
-}
-.legend {
- font-size: 1.25em;
-}
-.line {
- color: #aaaaaa;
-}
-.livesrc {
- color: #0000ff;
- cursor: pointer;
-}
-.livesrc:hover {
- background-color: #cccccc;
-}
-.asm {
- color: #888888;
- display: none;
-}
-</style>
-<script type="text/javascript">
-function pprof_toggle_asm(e) {
- var target;
- if (!e) e = window.event;
- if (e.target) target = e.target;
- else if (e.srcElement) target = e.srcElement;
-
- if (target && target.className == "livesrc") {
- var asm = target.nextSibling;
- if (asm && asm.className == "asm") {
- asm.style.display = (asm.style.display == "block" ? "none" : "block");
- e.preventDefault();
- return false;
- }
- }
-}
-</script>
-</head>
-<body>
-EOF
-}
-
-sub HtmlListingFooter {
- return <<'EOF';
-</body>
-</html>
-EOF
-}
-
-sub HtmlEscape {
- my $text = shift;
- $text =~ s/&/&amp;/g;
- $text =~ s/</&lt;/g;
- $text =~ s/>/&gt;/g;
- return $text;
-}
-
-# Returns the indentation of the line, if it has any non-whitespace
-# characters. Otherwise, returns -1.
-sub Indentation {
- my $line = shift;
- if (m/^(\s*)\S/) {
- return length($1);
- } else {
- return -1;
- }
-}
-
-# Print source-listing for one routine
-sub PrintSource {
- my $prog = shift;
- my $offset = shift;
- my $routine = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $start_addr = shift;
- my $end_addr = shift;
- my $html = shift;
- my $output = shift;
-
- # Disassemble all instructions (just to get line numbers)
- my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
-
- # Hack 1: assume that the first source file encountered in the
- # disassembly contains the routine
- my $filename = undef;
- for (my $i = 0; $i <= $#instructions; $i++) {
- if ($instructions[$i]->[2] >= 0) {
- $filename = $instructions[$i]->[1];
- last;
- }
- }
- if (!defined($filename)) {
- print STDERR "no filename found in $routine\n";
- return 0;
- }
-
- # Hack 2: assume that the largest line number from $filename is the
- # end of the procedure. This is typically safe since if P1 contains
- # an inlined call to P2, then P2 usually occurs earlier in the
- # source file. If this does not work, we might have to compute a
- # density profile or just print all regions we find.
- my $lastline = 0;
- for (my $i = 0; $i <= $#instructions; $i++) {
- my $f = $instructions[$i]->[1];
- my $l = $instructions[$i]->[2];
- if (($f eq $filename) && ($l > $lastline)) {
- $lastline = $l;
- }
- }
-
- # Hack 3: assume the first source location from "filename" is the start of
- # the source code.
- my $firstline = 1;
- for (my $i = 0; $i <= $#instructions; $i++) {
- if ($instructions[$i]->[1] eq $filename) {
- $firstline = $instructions[$i]->[2];
- last;
- }
- }
-
- # Hack 4: Extend last line forward until its indentation is less than
- # the indentation we saw on $firstline
- my $oldlastline = $lastline;
- {
- if (!open(FILE, "<$filename")) {
- print STDERR "$filename: $!\n";
- return 0;
- }
- my $l = 0;
- my $first_indentation = -1;
- while (<FILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- $l++;
- my $indent = Indentation($_);
- if ($l >= $firstline) {
- if ($first_indentation < 0 && $indent >= 0) {
- $first_indentation = $indent;
- last if ($first_indentation == 0);
- }
- }
- if ($l >= $lastline && $indent >= 0) {
- if ($indent >= $first_indentation) {
- $lastline = $l+1;
- } else {
- last;
- }
- }
- }
- close(FILE);
- }
-
- # Assign all samples to the range $firstline,$lastline,
- # Hack 4: If an instruction does not occur in the range, its samples
- # are moved to the next instruction that occurs in the range.
- my $samples1 = {}; # Map from line number to flat count
- my $samples2 = {}; # Map from line number to cumulative count
- my $running1 = 0; # Unassigned flat counts
- my $running2 = 0; # Unassigned cumulative counts
- my $total1 = 0; # Total flat counts
- my $total2 = 0; # Total cumulative counts
- my %disasm = (); # Map from line number to disassembly
- my $running_disasm = ""; # Unassigned disassembly
- my $skip_marker = "---\n";
- if ($html) {
- $skip_marker = "";
- for (my $l = $firstline; $l <= $lastline; $l++) {
- $disasm{$l} = "";
- }
- }
- foreach my $e (@instructions) {
- # Add up counts for all address that fall inside this instruction
- my $c1 = 0;
- my $c2 = 0;
- for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
- $c1 += GetEntry($flat, $a);
- $c2 += GetEntry($cumulative, $a);
- }
-
- if ($html) {
- $running_disasm .= sprintf(" %6s %6s \t\t%8s: %s\n",
- HtmlPrintNumber($c1),
- HtmlPrintNumber($c2),
- $e->[0],
- CleanDisassembly($e->[3]));
- }
-
- $running1 += $c1;
- $running2 += $c2;
- $total1 += $c1;
- $total2 += $c2;
- my $file = $e->[1];
- my $line = $e->[2];
- if (($file eq $filename) &&
- ($line >= $firstline) &&
- ($line <= $lastline)) {
- # Assign all accumulated samples to this line
- AddEntry($samples1, $line, $running1);
- AddEntry($samples2, $line, $running2);
- $running1 = 0;
- $running2 = 0;
- if ($html) {
- $disasm{$line} .= $running_disasm;
- $running_disasm = '';
- }
- }
- }
-
- # Assign any leftover samples to $lastline
- AddEntry($samples1, $lastline, $running1);
- AddEntry($samples2, $lastline, $running2);
-
- if ($html) {
- printf $output (
- "<h1>%s</h1>%s\n<pre onClick=\"pprof_toggle_asm()\">\n" .
- "Total:%6s %6s (flat / cumulative %s)\n",
- HtmlEscape(ShortFunctionName($routine)),
- HtmlEscape($filename),
- Unparse($total1),
- Unparse($total2),
- Units());
- } else {
- printf $output (
- "ROUTINE ====================== %s in %s\n" .
- "%6s %6s Total %s (flat / cumulative)\n",
- ShortFunctionName($routine),
- $filename,
- Unparse($total1),
- Unparse($total2),
- Units());
- }
- if (!open(FILE, "<$filename")) {
- print STDERR "$filename: $!\n";
- return 0;
- }
- my $l = 0;
- while (<FILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- $l++;
- if ($l >= $firstline - 5 &&
- (($l <= $oldlastline + 5) || ($l <= $lastline))) {
- chop;
- my $text = $_;
- if ($l == $firstline) { print $output $skip_marker; }
- my $n1 = GetEntry($samples1, $l);
- my $n2 = GetEntry($samples2, $l);
- if ($html) {
- my $dis = $disasm{$l};
- if (!defined($dis) || $n1 + $n2 == 0) {
- # No samples/disassembly for this source line
- printf $output (
- "<span class=\"line\">%5d</span> " .
- "<span class=\"deadsrc\">%6s %6s %s</span>\n",
- $l,
- HtmlPrintNumber($n1),
- HtmlPrintNumber($n2),
- HtmlEscape($text));
- } else {
- printf $output (
- "<span class=\"line\">%5d</span> " .
- "<span class=\"livesrc\">%6s %6s %s</span>" .
- "<span class=\"asm\">%s</span>\n",
- $l,
- HtmlPrintNumber($n1),
- HtmlPrintNumber($n2),
- HtmlEscape($text),
- HtmlEscape($dis));
- }
- } else {
- printf $output(
- "%6s %6s %4d: %s\n",
- UnparseAlt($n1),
- UnparseAlt($n2),
- $l,
- $text);
- }
- if ($l == $lastline) { print $output $skip_marker; }
- };
- }
- close(FILE);
- if ($html) {
- print $output "</pre>\n";
- }
- return 1;
-}
-
-# Return the source line for the specified file/linenumber.
-# Returns undef if not found.
-sub SourceLine {
- my $file = shift;
- my $line = shift;
-
- # Look in cache
- if (!defined($main::source_cache{$file})) {
- if (100 < scalar keys(%main::source_cache)) {
- # Clear the cache when it gets too big
- $main::source_cache = ();
- }
-
- # Read all lines from the file
- if (!open(FILE, "<$file")) {
- print STDERR "$file: $!\n";
- $main::source_cache{$file} = []; # Cache the negative result
- return undef;
- }
- my $lines = [];
- push(@{$lines}, ""); # So we can use 1-based line numbers as indices
- while (<FILE>) {
- push(@{$lines}, $_);
- }
- close(FILE);
-
- # Save the lines in the cache
- $main::source_cache{$file} = $lines;
- }
-
- my $lines = $main::source_cache{$file};
- if (($line < 0) || ($line > $#{$lines})) {
- return undef;
- } else {
- return $lines->[$line];
- }
-}
-
-# Print disassembly for one routine with interspersed source if available
-sub PrintDisassembledFunction {
- my $prog = shift;
- my $offset = shift;
- my $routine = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $start_addr = shift;
- my $end_addr = shift;
- my $total = shift;
-
- # Disassemble all instructions
- my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
-
- # Make array of counts per instruction
- my @flat_count = ();
- my @cum_count = ();
- my $flat_total = 0;
- my $cum_total = 0;
- foreach my $e (@instructions) {
- # Add up counts for all address that fall inside this instruction
- my $c1 = 0;
- my $c2 = 0;
- for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
- $c1 += GetEntry($flat, $a);
- $c2 += GetEntry($cumulative, $a);
- }
- push(@flat_count, $c1);
- push(@cum_count, $c2);
- $flat_total += $c1;
- $cum_total += $c2;
- }
-
- # Print header with total counts
- printf("ROUTINE ====================== %s\n" .
- "%6s %6s %s (flat, cumulative) %.1f%% of total\n",
- ShortFunctionName($routine),
- Unparse($flat_total),
- Unparse($cum_total),
- Units(),
- ($cum_total * 100.0) / $total);
-
- # Process instructions in order
- my $current_file = "";
- for (my $i = 0; $i <= $#instructions; ) {
- my $e = $instructions[$i];
-
- # Print the new file name whenever we switch files
- if ($e->[1] ne $current_file) {
- $current_file = $e->[1];
- my $fname = $current_file;
- $fname =~ s|^\./||; # Trim leading "./"
-
- # Shorten long file names
- if (length($fname) >= 58) {
- $fname = "..." . substr($fname, -55);
- }
- printf("-------------------- %s\n", $fname);
- }
-
- # TODO: Compute range of lines to print together to deal with
- # small reorderings.
- my $first_line = $e->[2];
- my $last_line = $first_line;
- my %flat_sum = ();
- my %cum_sum = ();
- for (my $l = $first_line; $l <= $last_line; $l++) {
- $flat_sum{$l} = 0;
- $cum_sum{$l} = 0;
- }
-
- # Find run of instructions for this range of source lines
- my $first_inst = $i;
- while (($i <= $#instructions) &&
- ($instructions[$i]->[2] >= $first_line) &&
- ($instructions[$i]->[2] <= $last_line)) {
- $e = $instructions[$i];
- $flat_sum{$e->[2]} += $flat_count[$i];
- $cum_sum{$e->[2]} += $cum_count[$i];
- $i++;
- }
- my $last_inst = $i - 1;
-
- # Print source lines
- for (my $l = $first_line; $l <= $last_line; $l++) {
- my $line = SourceLine($current_file, $l);
- if (!defined($line)) {
- $line = "?\n";
- next;
- } else {
- $line =~ s/^\s+//;
- }
- printf("%6s %6s %5d: %s",
- UnparseAlt($flat_sum{$l}),
- UnparseAlt($cum_sum{$l}),
- $l,
- $line);
- }
-
- # Print disassembly
- for (my $x = $first_inst; $x <= $last_inst; $x++) {
- my $e = $instructions[$x];
- my $address = $e->[0];
- $address = AddressSub($address, $offset); # Make relative to section
- $address =~ s/^0x//;
- $address =~ s/^0*//;
-
- printf("%6s %6s %8s: %6s\n",
- UnparseAlt($flat_count[$x]),
- UnparseAlt($cum_count[$x]),
- $address,
- CleanDisassembly($e->[3]));
- }
- }
-}
-
-# Print DOT graph
-sub PrintDot {
- my $prog = shift;
- my $symbols = shift;
- my $raw = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $overall_total = shift;
-
- # Get total
- my $local_total = TotalProfile($flat);
- my $nodelimit = int($main::opt_nodefraction * $local_total);
- my $edgelimit = int($main::opt_edgefraction * $local_total);
- my $nodecount = $main::opt_nodecount;
-
- # Find nodes to include
- my @list = (sort { abs(GetEntry($cumulative, $b)) <=>
- abs(GetEntry($cumulative, $a))
- || $a cmp $b }
- keys(%{$cumulative}));
- my $last = $nodecount - 1;
- if ($last > $#list) {
- $last = $#list;
- }
- while (($last >= 0) &&
- (abs(GetEntry($cumulative, $list[$last])) <= $nodelimit)) {
- $last--;
- }
- if ($last < 0) {
- print STDERR "No nodes to print\n";
- cleanup();
- return 0;
- }
-
- if ($nodelimit > 0 || $edgelimit > 0) {
- printf STDERR ("Dropping nodes with <= %s %s; edges with <= %s abs(%s)\n",
- Unparse($nodelimit), Units(),
- Unparse($edgelimit), Units());
- }
-
- # Open DOT output file
- my $output;
- if ($main::opt_gv) {
- $output = "| $DOT -Tps2 >" . TempName($main::next_tmpfile, "ps");
- } elsif ($main::opt_ps) {
- $output = "| $DOT -Tps2";
- } elsif ($main::opt_pdf) {
- $output = "| $DOT -Tps2 | $PS2PDF - -";
- } elsif ($main::opt_web || $main::opt_svg) {
- # We need to post-process the SVG, so write to a temporary file always.
- $output = "| $DOT -Tsvg >" . TempName($main::next_tmpfile, "svg");
- } elsif ($main::opt_gif) {
- $output = "| $DOT -Tgif";
- } else {
- $output = ">&STDOUT";
- }
- open(DOT, $output) || error("$output: $!\n");
-
- # Title
- printf DOT ("digraph \"%s; %s %s\" {\n",
- $prog,
- Unparse($overall_total),
- Units());
- if ($main::opt_pdf) {
- # The output is more printable if we set the page size for dot.
- printf DOT ("size=\"8,11\"\n");
- }
- printf DOT ("node [width=0.375,height=0.25];\n");
-
- # Print legend
- printf DOT ("Legend [shape=box,fontsize=24,shape=plaintext," .
- "label=\"%s\\l%s\\l%s\\l%s\\l%s\\l\"];\n",
- $prog,
- sprintf("Total %s: %s", Units(), Unparse($overall_total)),
- sprintf("Focusing on: %s", Unparse($local_total)),
- sprintf("Dropped nodes with <= %s abs(%s)",
- Unparse($nodelimit), Units()),
- sprintf("Dropped edges with <= %s %s",
- Unparse($edgelimit), Units())
- );
-
- # Print nodes
- my %node = ();
- my $nextnode = 1;
- foreach my $a (@list[0..$last]) {
- # Pick font size
- my $f = GetEntry($flat, $a);
- my $c = GetEntry($cumulative, $a);
-
- my $fs = 8;
- if ($local_total > 0) {
- $fs = 8 + (50.0 * sqrt(abs($f * 1.0 / $local_total)));
- }
-
- $node{$a} = $nextnode++;
- my $sym = $a;
- $sym =~ s/\s+/\\n/g;
- $sym =~ s/::/\\n/g;
-
- # Extra cumulative info to print for non-leaves
- my $extra = "";
- if ($f != $c) {
- $extra = sprintf("\\rof %s (%s)",
- Unparse($c),
- Percent($c, $overall_total));
- }
- my $style = "";
- if ($main::opt_heapcheck) {
- if ($f > 0) {
- # make leak-causing nodes more visible (add a background)
- $style = ",style=filled,fillcolor=gray"
- } elsif ($f < 0) {
- # make anti-leak-causing nodes (which almost never occur)
- # stand out as well (triple border)
- $style = ",peripheries=3"
- }
- }
-
- printf DOT ("N%d [label=\"%s\\n%s (%s)%s\\r" .
- "\",shape=box,fontsize=%.1f%s];\n",
- $node{$a},
- $sym,
- Unparse($f),
- Percent($f, $overall_total),
- $extra,
- $fs,
- $style,
- );
- }
-
- # Get edges and counts per edge
- my %edge = ();
- my $n;
- foreach my $k (keys(%{$raw})) {
- # TODO: omit low %age edges
- $n = $raw->{$k};
- my @translated = TranslateStack($symbols, $k);
- for (my $i = 1; $i <= $#translated; $i++) {
- my $src = $translated[$i];
- my $dst = $translated[$i-1];
- #next if ($src eq $dst); # Avoid self-edges?
- if (exists($node{$src}) && exists($node{$dst})) {
- my $edge_label = "$src\001$dst";
- if (!exists($edge{$edge_label})) {
- $edge{$edge_label} = 0;
- }
- $edge{$edge_label} += $n;
- }
- }
- }
-
- # Print edges
- foreach my $e (keys(%edge)) {
- my @x = split(/\001/, $e);
- $n = $edge{$e};
-
- if (abs($n) > $edgelimit) {
- # Compute line width based on edge count
- my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0);
- if ($fraction > 1) { $fraction = 1; }
- my $w = $fraction * 2;
- if ($w < 1 && ($main::opt_web || $main::opt_svg)) {
- # SVG output treats line widths < 1 poorly.
- $w = 1;
- }
-
- # Dot sometimes segfaults if given edge weights that are too large, so
- # we cap the weights at a large value
- my $edgeweight = abs($n) ** 0.7;
- if ($edgeweight > 100000) { $edgeweight = 100000; }
- $edgeweight = int($edgeweight);
-
- my $style = sprintf("setlinewidth(%f)", $w);
- if ($x[1] =~ m/\(inline\)/) {
- $style .= ",dashed";
- }
-
- # Use a slightly squashed function of the edge count as the weight
- printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n",
- $node{$x[0]},
- $node{$x[1]},
- Unparse($n),
- $edgeweight,
- $style);
- }
- }
-
- print DOT ("}\n");
- close(DOT);
-
- if ($main::opt_web || $main::opt_svg) {
- # Rewrite SVG to be more usable inside web browser.
- RewriteSvg(TempName($main::next_tmpfile, "svg"));
- }
-
- return 1;
-}
-
-sub RewriteSvg {
- my $svgfile = shift;
-
- open(SVG, $svgfile) || die "open temp svg: $!";
- my @svg = <SVG>;
- close(SVG);
- unlink $svgfile;
- my $svg = join('', @svg);
-
- # Dot's SVG output is
- #
- # <svg width="___" height="___"
- # viewBox="___" xmlns=...>
- # <g id="graph0" transform="...">
- # ...
- # </g>
- # </svg>
- #
- # Change it to
- #
- # <svg width="100%" height="100%"
- # xmlns=...>
- # $svg_javascript
- # <g id="viewport" transform="translate(0,0)">
- # <g id="graph0" transform="...">
- # ...
- # </g>
- # </g>
- # </svg>
-
- # Fix width, height; drop viewBox.
- $svg =~ s/(?s)<svg width="[^"]+" height="[^"]+"(.*?)viewBox="[^"]+"/<svg width="100%" height="100%"$1/;
-
- # Insert script, viewport <g> above first <g>
- my $svg_javascript = SvgJavascript();
- my $viewport = "<g id=\"viewport\" transform=\"translate(0,0)\">\n";
- $svg =~ s/<g id="graph\d"/$svg_javascript$viewport$&/;
-
- # Insert final </g> above </svg>.
- $svg =~ s/(.*)(<\/svg>)/$1<\/g>$2/;
- $svg =~ s/<g id="graph\d"(.*?)/<g id="viewport"$1/;
-
- if ($main::opt_svg) {
- # --svg: write to standard output.
- print $svg;
- } else {
- # Write back to temporary file.
- open(SVG, ">$svgfile") || die "open $svgfile: $!";
- print SVG $svg;
- close(SVG);
- }
-}
-
-sub SvgJavascript {
- return <<'EOF';
-<script type="text/ecmascript"><![CDATA[
-// SVGPan
-// http://www.cyberz.org/blog/2009/12/08/svgpan-a-javascript-svg-panzoomdrag-library/
-// Local modification: if(true || ...) below to force panning, never moving.
-// Local modification: add clamping to fix bug in handleMouseWheel.
-
-/**
- * SVGPan library 1.2
- * ====================
- *
- * Given an unique existing element with id "viewport", including the
- * the library into any SVG adds the following capabilities:
- *
- * - Mouse panning
- * - Mouse zooming (using the wheel)
- * - Object dargging
- *
- * Known issues:
- *
- * - Zooming (while panning) on Safari has still some issues
- *
- * Releases:
- *
- * 1.2, Sat Mar 20 08:42:50 GMT 2010, Zeng Xiaohui
- * Fixed a bug with browser mouse handler interaction
- *
- * 1.1, Wed Feb 3 17:39:33 GMT 2010, Zeng Xiaohui
- * Updated the zoom code to support the mouse wheel on Safari/Chrome
- *
- * 1.0, Andrea Leofreddi
- * First release
- *
- * This code is licensed under the following BSD license:
- *
- * Copyright 2009-2010 Andrea Leofreddi <a.leofreddi@itcharm.com>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY Andrea Leofreddi ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andrea Leofreddi OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of Andrea Leofreddi.
- */
-
-var root = document.documentElement;
-
-var state = 'none', stateTarget, stateOrigin, stateTf;
-
-setupHandlers(root);
-
-/**
- * Register handlers
- */
-function setupHandlers(root){
- setAttributes(root, {
- "onmouseup" : "add(evt)",
- "onmousedown" : "handleMouseDown(evt)",
- "onmousemove" : "handleMouseMove(evt)",
- "onmouseup" : "handleMouseUp(evt)",
- //"onmouseout" : "handleMouseUp(evt)", // Decomment this to stop the pan functionality when dragging out of the SVG element
- });
-
- if(navigator.userAgent.toLowerCase().indexOf('webkit') >= 0)
- window.addEventListener('mousewheel', handleMouseWheel, false); // Chrome/Safari
- else
- window.addEventListener('DOMMouseScroll', handleMouseWheel, false); // Others
-
- var g = svgDoc.getElementById("svg");
- g.width = "100%";
- g.height = "100%";
-}
-
-/**
- * Instance an SVGPoint object with given event coordinates.
- */
-function getEventPoint(evt) {
- var p = root.createSVGPoint();
-
- p.x = evt.clientX;
- p.y = evt.clientY;
-
- return p;
-}
-
-/**
- * Sets the current transform matrix of an element.
- */
-function setCTM(element, matrix) {
- var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
-
- element.setAttribute("transform", s);
-}
-
-/**
- * Dumps a matrix to a string (useful for debug).
- */
-function dumpMatrix(matrix) {
- var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n 0, 0, 1 ]";
-
- return s;
-}
-
-/**
- * Sets attributes of an element.
- */
-function setAttributes(element, attributes){
- for (i in attributes)
- element.setAttributeNS(null, i, attributes[i]);
-}
-
-/**
- * Handle mouse move event.
- */
-function handleMouseWheel(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- var delta;
-
- if(evt.wheelDelta)
- delta = evt.wheelDelta / 3600; // Chrome/Safari
- else
- delta = evt.detail / -90; // Mozilla
-
- var z = 1 + delta; // Zoom factor: 0.9/1.1
-
- // Clamp to reasonable values.
- // The 0.1 check is important because
- // a very large scroll can turn into a
- // negative z, which rotates the image 180 degrees.
- if(z < 0.1)
- z = 0.1;
- if(z > 10.0)
- z = 10.0;
-
- var g = svgDoc.getElementById("viewport");
-
- var p = getEventPoint(evt);
-
- p = p.matrixTransform(g.getCTM().inverse());
-
- // Compute new scale matrix in current mouse position
- var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
-
- setCTM(g, g.getCTM().multiply(k));
-
- stateTf = stateTf.multiply(k.inverse());
-}
-
-/**
- * Handle mouse move event.
- */
-function handleMouseMove(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- var g = svgDoc.getElementById("viewport");
-
- if(state == 'pan') {
- // Pan mode
- var p = getEventPoint(evt).matrixTransform(stateTf);
-
- setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y));
- } else if(state == 'move') {
- // Move mode
- var p = getEventPoint(evt).matrixTransform(g.getCTM().inverse());
-
- setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).multiply(g.getCTM().inverse()).multiply(stateTarget.getCTM()));
-
- stateOrigin = p;
- }
-}
-
-/**
- * Handle click event.
- */
-function handleMouseDown(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- var g = svgDoc.getElementById("viewport");
-
- if(true || evt.target.tagName == "svg") {
- // Pan mode
- state = 'pan';
-
- stateTf = g.getCTM().inverse();
-
- stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
- } else {
- // Move mode
- state = 'move';
-
- stateTarget = evt.target;
-
- stateTf = g.getCTM().inverse();
-
- stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
- }
-}
-
-/**
- * Handle mouse button release event.
- */
-function handleMouseUp(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- if(state == 'pan' || state == 'move') {
- // Quit pan mode
- state = '';
- }
-}
-
-]]></script>
-EOF
-}
-
-# Translate a stack of addresses into a stack of symbols
-sub TranslateStack {
- my $symbols = shift;
- my $k = shift;
-
- my @addrs = split(/\n/, $k);
- my @result = ();
- for (my $i = 0; $i <= $#addrs; $i++) {
- my $a = $addrs[$i];
-
- # Skip large addresses since they sometimes show up as fake entries on RH9
- if (length($a) > 8 && $a gt "7fffffffffffffff") {
- next;
- }
-
- if ($main::opt_disasm || $main::opt_list) {
- # We want just the address for the key
- push(@result, $a);
- next;
- }
-
- my $symlist = $symbols->{$a};
- if (!defined($symlist)) {
- $symlist = [$a, "", $a];
- }
-
- # We can have a sequence of symbols for a particular entry
- # (more than one symbol in the case of inlining). Callers
- # come before callees in symlist, so walk backwards since
- # the translated stack should contain callees before callers.
- for (my $j = $#{$symlist}; $j >= 2; $j -= 3) {
- my $func = $symlist->[$j-2];
- my $fileline = $symlist->[$j-1];
- my $fullfunc = $symlist->[$j];
- if ($j > 2) {
- $func = "$func (inline)";
- }
- if ($main::opt_addresses) {
- push(@result, "$a $func $fileline");
- } elsif ($main::opt_lines) {
- if ($func eq '??' && $fileline eq '??:0') {
- push(@result, "$a");
- } else {
- push(@result, "$func $fileline");
- }
- } elsif ($main::opt_functions) {
- if ($func eq '??') {
- push(@result, "$a");
- } else {
- push(@result, $func);
- }
- } elsif ($main::opt_files) {
- if ($fileline eq '??:0' || $fileline eq '') {
- push(@result, "$a");
- } else {
- my $f = $fileline;
- $f =~ s/:\d+$//;
- push(@result, $f);
- }
- } else {
- push(@result, $a);
- last; # Do not print inlined info
- }
- }
- }
-
- # print join(",", @addrs), " => ", join(",", @result), "\n";
- return @result;
-}
-
-# Generate percent string for a number and a total
-sub Percent {
- my $num = shift;
- my $tot = shift;
- if ($tot != 0) {
- return sprintf("%.1f%%", $num * 100.0 / $tot);
- } else {
- return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf");
- }
-}
-
-# Generate pretty-printed form of number
-sub Unparse {
- my $num = shift;
- if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
- if ($main::opt_inuse_objects || $main::opt_alloc_objects) {
- return sprintf("%d", $num);
- } else {
- if ($main::opt_show_bytes) {
- return sprintf("%d", $num);
- } else {
- return sprintf("%.1f", $num / 1048576.0);
- }
- }
- } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) {
- return sprintf("%.3f", $num / 1e9); # Convert nanoseconds to seconds
- } else {
- return sprintf("%d", $num);
- }
-}
-
-# Alternate pretty-printed form: 0 maps to "."
-sub UnparseAlt {
- my $num = shift;
- if ($num == 0) {
- return ".";
- } else {
- return Unparse($num);
- }
-}
-
-# Alternate pretty-printed form: 0 maps to ""
-sub HtmlPrintNumber {
- my $num = shift;
- if ($num == 0) {
- return "";
- } else {
- return Unparse($num);
- }
-}
-
-# Return output units
-sub Units {
- if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
- if ($main::opt_inuse_objects || $main::opt_alloc_objects) {
- return "objects";
- } else {
- if ($main::opt_show_bytes) {
- return "B";
- } else {
- return "MB";
- }
- }
- } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) {
- return "seconds";
- } else {
- return "samples";
- }
-}
-
-##### Profile manipulation code #####
-
-# Generate flattened profile:
-# If count is charged to stack [a,b,c,d], in generated profile,
-# it will be charged to [a]
-sub FlatProfile {
- my $profile = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- if ($#addrs >= 0) {
- AddEntry($result, $addrs[0], $count);
- }
- }
- return $result;
-}
-
-# Generate cumulative profile:
-# If count is charged to stack [a,b,c,d], in generated profile,
-# it will be charged to [a], [b], [c], [d]
-sub CumulativeProfile {
- my $profile = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- foreach my $a (@addrs) {
- AddEntry($result, $a, $count);
- }
- }
- return $result;
-}
-
-# If the second-youngest PC on the stack is always the same, returns
-# that pc. Otherwise, returns undef.
-sub IsSecondPcAlwaysTheSame {
- my $profile = shift;
-
- my $second_pc = undef;
- foreach my $k (keys(%{$profile})) {
- my @addrs = split(/\n/, $k);
- if ($#addrs < 1) {
- return undef;
- }
- if (not defined $second_pc) {
- $second_pc = $addrs[1];
- } else {
- if ($second_pc ne $addrs[1]) {
- return undef;
- }
- }
- }
- return $second_pc;
-}
-
-sub ExtractSymbolLocation {
- my $symbols = shift;
- my $address = shift;
- # 'addr2line' outputs "??:0" for unknown locations; we do the
- # same to be consistent.
- my $location = "??:0:unknown";
- if (exists $symbols->{$address}) {
- my $file = $symbols->{$address}->[1];
- if ($file eq "?") {
- $file = "??:0"
- }
- $location = $file . ":" . $symbols->{$address}->[0];
- }
- return $location;
-}
-
-# Extracts a graph of calls.
-sub ExtractCalls {
- my $symbols = shift;
- my $profile = shift;
-
- my $calls = {};
- while( my ($stack_trace, $count) = each %$profile ) {
- my @address = split(/\n/, $stack_trace);
- my $destination = ExtractSymbolLocation($symbols, $address[0]);
- AddEntry($calls, $destination, $count);
- for (my $i = 1; $i <= $#address; $i++) {
- my $source = ExtractSymbolLocation($symbols, $address[$i]);
- my $call = "$source -> $destination";
- AddEntry($calls, $call, $count);
- $destination = $source;
- }
- }
-
- return $calls;
-}
-
-sub RemoveUninterestingFrames {
- my $symbols = shift;
- my $profile = shift;
-
- # List of function names to skip
- my %skip = ();
- my $skip_regexp = 'NOMATCH';
- if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
- foreach my $name ('calloc',
- 'cfree',
- 'malloc',
- 'free',
- 'memalign',
- 'posix_memalign',
- 'pvalloc',
- 'valloc',
- 'realloc',
- 'tc_calloc',
- 'tc_cfree',
- 'tc_malloc',
- 'tc_free',
- 'tc_memalign',
- 'tc_posix_memalign',
- 'tc_pvalloc',
- 'tc_valloc',
- 'tc_realloc',
- 'tc_new',
- 'tc_delete',
- 'tc_newarray',
- 'tc_deletearray',
- 'tc_new_nothrow',
- 'tc_newarray_nothrow',
- 'do_malloc',
- '::do_malloc', # new name -- got moved to an unnamed ns
- '::do_malloc_or_cpp_alloc',
- 'DoSampledAllocation',
- 'simple_alloc::allocate',
- '__malloc_alloc_template::allocate',
- '__builtin_delete',
- '__builtin_new',
- '__builtin_vec_delete',
- '__builtin_vec_new',
- 'operator new',
- 'operator new[]',
- # Go
- 'catstring',
- 'copyin',
- 'gostring',
- 'gostringsize',
- 'growslice1',
- 'appendslice1',
- 'hash_init',
- 'hash_subtable_new',
- 'hash_conv',
- 'hash_grow',
- 'hash_insert_internal',
- 'hash_insert',
- 'mapassign',
- 'runtime.mapassign',
- 'runtime.appendslice',
- 'runtime.mapassign1',
- 'makechan',
- 'makemap',
- 'mal',
- 'runtime.new',
- 'makeslice1',
- 'runtime.gostringsize',
- 'runtime.malloc',
- 'unsafe.New',
- 'runtime.mallocgc',
- 'runtime.catstring',
- 'runtime.growslice',
- 'runtime.ifaceT2E',
- 'runtime.ifaceT2I',
- 'runtime.makechan',
- 'runtime.makechan_c',
- 'runtime.makemap',
- 'runtime.makemap_c',
- 'runtime.makeslice',
- 'runtime.mal',
- 'runtime.slicebytetostring',
- 'runtime.sliceinttostring',
- 'runtime.stringtoslicebyte',
- 'runtime.stringtosliceint',
- # These mark the beginning/end of our custom sections
- '__start_google_malloc',
- '__stop_google_malloc',
- '__start_malloc_hook',
- '__stop_malloc_hook') {
- $skip{$name} = 1;
- $skip{"_" . $name} = 1; # Mach (OS X) adds a _ prefix to everything
- }
- # TODO: Remove TCMalloc once everything has been
- # moved into the tcmalloc:: namespace and we have flushed
- # old code out of the system.
- $skip_regexp = "TCMalloc|^tcmalloc::";
- } elsif ($main::profile_type eq 'contention') {
- foreach my $vname ('Mutex::Unlock', 'Mutex::UnlockSlow') {
- $skip{$vname} = 1;
- }
- } elsif ($main::profile_type eq 'cpu') {
- # Drop signal handlers used for CPU profile collection
- # TODO(dpeng): this should not be necessary; it's taken
- # care of by the general 2nd-pc mechanism below.
- foreach my $name ('ProfileData::Add', # historical
- 'ProfileData::prof_handler', # historical
- 'CpuProfiler::prof_handler',
- '__FRAME_END__',
- '__pthread_sighandler',
- '__restore') {
- $skip{$name} = 1;
- }
- } else {
- # Nothing skipped for unknown types
- }
-
- # Go doesn't have the problem that this heuristic tries to fix. Disable.
- if (0 && $main::profile_type eq 'cpu') {
- # If all the second-youngest program counters are the same,
- # this STRONGLY suggests that it is an artifact of measurement,
- # i.e., stack frames pushed by the CPU profiler signal handler.
- # Hence, we delete them.
- # (The topmost PC is read from the signal structure, not from
- # the stack, so it does not get involved.)
- while (my $second_pc = IsSecondPcAlwaysTheSame($profile)) {
- my $result = {};
- my $func = '';
- if (exists($symbols->{$second_pc})) {
- $second_pc = $symbols->{$second_pc}->[0];
- }
- print STDERR "Removing $second_pc from all stack traces.\n";
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- splice @addrs, 1, 1;
- my $reduced_path = join("\n", @addrs);
- AddEntry($result, $reduced_path, $count);
- }
- $profile = $result;
- }
- }
-
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- my @path = ();
- foreach my $a (@addrs) {
- if (exists($symbols->{$a})) {
- my $func = $symbols->{$a}->[0];
- if ($skip{$func} || ($func =~ m/$skip_regexp/)) {
- next;
- }
- }
- push(@path, $a);
- }
- my $reduced_path = join("\n", @path);
- AddEntry($result, $reduced_path, $count);
- }
- return $result;
-}
-
-# Reduce profile to granularity given by user
-sub ReduceProfile {
- my $symbols = shift;
- my $profile = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @translated = TranslateStack($symbols, $k);
- my @path = ();
- my %seen = ();
- $seen{''} = 1; # So that empty keys are skipped
- foreach my $e (@translated) {
- # To avoid double-counting due to recursion, skip a stack-trace
- # entry if it has already been seen
- if (!$seen{$e}) {
- $seen{$e} = 1;
- push(@path, $e);
- }
- }
- my $reduced_path = join("\n", @path);
- AddEntry($result, $reduced_path, $count);
- }
- return $result;
-}
-
-# Does the specified symbol array match the regexp?
-sub SymbolMatches {
- my $sym = shift;
- my $re = shift;
- if (defined($sym)) {
- for (my $i = 0; $i < $#{$sym}; $i += 3) {
- if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) {
- return 1;
- }
- }
- }
- return 0;
-}
-
-# Focus only on paths involving specified regexps
-sub FocusProfile {
- my $symbols = shift;
- my $profile = shift;
- my $focus = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- foreach my $a (@addrs) {
- # Reply if it matches either the address/shortname/fileline
- if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) {
- AddEntry($result, $k, $count);
- last;
- }
- }
- }
- return $result;
-}
-
-# Focus only on paths not involving specified regexps
-sub IgnoreProfile {
- my $symbols = shift;
- my $profile = shift;
- my $ignore = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- my $matched = 0;
- foreach my $a (@addrs) {
- # Reply if it matches either the address/shortname/fileline
- if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) {
- $matched = 1;
- last;
- }
- }
- if (!$matched) {
- AddEntry($result, $k, $count);
- }
- }
- return $result;
-}
-
-# Get total count in profile
-sub TotalProfile {
- my $profile = shift;
- my $result = 0;
- foreach my $k (keys(%{$profile})) {
- $result += $profile->{$k};
- }
- return $result;
-}
-
-# Add A to B
-sub AddProfile {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- # add all keys in A
- foreach my $k (keys(%{$A})) {
- my $v = $A->{$k};
- AddEntry($R, $k, $v);
- }
- # add all keys in B
- foreach my $k (keys(%{$B})) {
- my $v = $B->{$k};
- AddEntry($R, $k, $v);
- }
- return $R;
-}
-
-# Merges symbol maps
-sub MergeSymbols {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- foreach my $k (keys(%{$A})) {
- $R->{$k} = $A->{$k};
- }
- if (defined($B)) {
- foreach my $k (keys(%{$B})) {
- $R->{$k} = $B->{$k};
- }
- }
- return $R;
-}
-
-
-# Add A to B
-sub AddPcs {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- # add all keys in A
- foreach my $k (keys(%{$A})) {
- $R->{$k} = 1
- }
- # add all keys in B
- foreach my $k (keys(%{$B})) {
- $R->{$k} = 1
- }
- return $R;
-}
-
-# Subtract B from A
-sub SubtractProfile {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- foreach my $k (keys(%{$A})) {
- my $v = $A->{$k} - GetEntry($B, $k);
- if ($v < 0 && $main::opt_drop_negative) {
- $v = 0;
- }
- AddEntry($R, $k, $v);
- }
- if (!$main::opt_drop_negative) {
- # Take care of when subtracted profile has more entries
- foreach my $k (keys(%{$B})) {
- if (!exists($A->{$k})) {
- AddEntry($R, $k, 0 - $B->{$k});
- }
- }
- }
- return $R;
-}
-
-# Get entry from profile; zero if not present
-sub GetEntry {
- my $profile = shift;
- my $k = shift;
- if (exists($profile->{$k})) {
- return $profile->{$k};
- } else {
- return 0;
- }
-}
-
-# Add entry to specified profile
-sub AddEntry {
- my $profile = shift;
- my $k = shift;
- my $n = shift;
- if (!exists($profile->{$k})) {
- $profile->{$k} = 0;
- }
- $profile->{$k} += $n;
-}
-
-# Add a stack of entries to specified profile, and add them to the $pcs
-# list.
-sub AddEntries {
- my $profile = shift;
- my $pcs = shift;
- my $stack = shift;
- my $count = shift;
- my @k = ();
-
- foreach my $e (split(/\s+/, $stack)) {
- my $pc = HexExtend($e);
- $pcs->{$pc} = 1;
- push @k, $pc;
- }
- AddEntry($profile, (join "\n", @k), $count);
-}
-
-sub IsSymbolizedProfileFile {
- my $file_name = shift;
-
- if (!(-e $file_name) || !(-r $file_name)) {
- return 0;
- }
-
- $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $symbol_marker = $&;
- # Check if the file contains a symbol-section marker.
- open(TFILE, "<$file_name");
- my @lines = <TFILE>;
- my $result = grep(/^--- *$symbol_marker/, @lines);
- close(TFILE);
- return $result > 0;
-}
-
-##### Code to profile a server dynamically #####
-
-sub CheckSymbolPage {
- my $url = SymbolPageURL();
-print STDERR "Read $url\n";
- open(SYMBOL, "$CURL -s '$url' |");
- my $line = <SYMBOL>;
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- close(SYMBOL);
- unless (defined($line)) {
- error("$url doesn't exist\n");
- }
-
- if ($line =~ /^num_symbols:\s+(\d+)$/) {
- if ($1 == 0) {
- error("Stripped binary. No symbols available.\n");
- }
- } else {
- error("Failed to get the number of symbols from $url\n");
- }
-}
-
-sub IsProfileURL {
- my $profile_name = shift;
- my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
- return defined($host) and defined($port) and defined($path);
-}
-
-sub ParseProfileURL {
- my $profile_name = shift;
- if (defined($profile_name) &&
- $profile_name =~ m,^(http://|)([^/:]+):(\d+)(|\@\d+)(|/|(.*?)($PROFILE_PAGE|$PMUPROFILE_PAGE|$HEAP_PAGE|$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|$FILTEREDPROFILE_PAGE))$,o) {
- # $7 is $PROFILE_PAGE/$HEAP_PAGE/etc. $5 is *everything* after
- # the hostname, as long as that everything is the empty string,
- # a slash, or something ending in $PROFILE_PAGE/$HEAP_PAGE/etc.
- # So "$7 || $5" is $PROFILE_PAGE/etc if there, or else it's "/" or "".
- return ($2, $3, $6, $7 || $5);
- }
- return ();
-}
-
-# We fetch symbols from the first profile argument.
-sub SymbolPageURL {
- my ($host, $port, $prefix, $path) = ParseProfileURL($main::pfile_args[0]);
- return "http://$host:$port$prefix$SYMBOL_PAGE";
-}
-
-sub FetchProgramName() {
- my ($host, $port, $prefix, $path) = ParseProfileURL($main::pfile_args[0]);
- my $url = "http://$host:$port$prefix$PROGRAM_NAME_PAGE";
- my $command_line = "$CURL -s '$url'";
- open(CMDLINE, "$command_line |") or error($command_line);
- my $cmdline = <CMDLINE>;
- $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- close(CMDLINE);
- error("Failed to get program name from $url\n") unless defined($cmdline);
- $cmdline =~ s/\x00.+//; # Remove argv[1] and latters.
- $cmdline =~ s!\n!!g; # Remove LFs.
- return $cmdline;
-}
-
-# Gee, curl's -L (--location) option isn't reliable at least
-# with its 7.12.3 version. Curl will forget to post data if
-# there is a redirection. This function is a workaround for
-# curl. Redirection happens on borg hosts.
-sub ResolveRedirectionForCurl {
- my $url = shift;
- my $command_line = "$CURL -s --head '$url'";
- open(CMDLINE, "$command_line |") or error($command_line);
- while (<CMDLINE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- if (/^Location: (.*)/) {
- $url = $1;
- }
- }
- close(CMDLINE);
- return $url;
-}
-
-# Reads a symbol map from the file handle name given as $1, returning
-# the resulting symbol map. Also processes variables relating to symbols.
-# Currently, the only variable processed is 'binary=<value>' which updates
-# $main::prog to have the correct program name.
-sub ReadSymbols {
- my $in = shift;
- my $map = shift;
- while (<$in>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- # Removes all the leading zeroes from the symbols, see comment below.
- if (m/^0x0*([0-9a-f]+)\s+(.+)/) {
- $map->{$1} = $2;
- } elsif (m/^---/) {
- last;
- } elsif (m/^([a-z][^=]*)=(.*)$/ ) {
- my ($variable, $value) = ($1, $2);
- for ($variable, $value) {
- s/^\s+//;
- s/\s+$//;
- }
- if ($variable eq "binary") {
- if ($main::prog ne $UNKNOWN_BINARY && $main::prog ne $value) {
- printf STDERR ("Warning: Mismatched binary name '%s', using '%s'.\n",
- $main::prog, $value);
- }
- $main::prog = $value;
- } else {
- printf STDERR ("Ignoring unknown variable in symbols list: " .
- "'%s' = '%s'\n", $variable, $value);
- }
- }
- }
- return $map;
-}
-
-# Fetches and processes symbols to prepare them for use in the profile output
-# code. If the optional 'symbol_map' arg is not given, fetches symbols from
-# $SYMBOL_PAGE for all PC values found in profile. Otherwise, the raw symbols
-# are assumed to have already been fetched into 'symbol_map' and are simply
-# extracted and processed.
-sub FetchSymbols {
- my $pcset = shift;
- my $symbol_map = shift;
-
- my %seen = ();
- my @pcs = grep { !$seen{$_}++ } keys(%$pcset); # uniq
-
- if (!defined($symbol_map)) {
- $symbol_map = {};
- my @toask = @pcs;
- while (@toask > 0) {
- my $n = @toask;
- # NOTE(rsc): Limiting the number of PCs requested per round
- # used to be necessary, but I think it was a bug in
- # debug/pprof/symbol's implementation. Leaving here
- # in case I am wrong.
- # if ($n > 49) { $n = 49; }
- my @thisround = @toask[0..$n];
- @toask = @toask[($n+1)..(@toask-1)];
- my $post_data = join("+", sort((map {"0x" . "$_"} @thisround)));
- open(POSTFILE, ">$main::tmpfile_sym");
- print POSTFILE $post_data;
- close(POSTFILE);
-
- my $url = SymbolPageURL();
- $url = ResolveRedirectionForCurl($url);
- my $command_line = "$CURL -sd '\@$main::tmpfile_sym' '$url'";
- # We use c++filt in case $SYMBOL_PAGE gives us mangled symbols.
- my $cppfilt = $obj_tool_map{"c++filt"};
- open(SYMBOL, "$command_line | $cppfilt |") or error($command_line);
- ReadSymbols(*SYMBOL{IO}, $symbol_map);
- close(SYMBOL);
- }
- }
-
- my $symbols = {};
- foreach my $pc (@pcs) {
- my $fullname;
- # For 64 bits binaries, symbols are extracted with 8 leading zeroes.
- # Then /symbol reads the long symbols in as uint64, and outputs
- # the result with a "0x%08llx" format which get rid of the zeroes.
- # By removing all the leading zeroes in both $pc and the symbols from
- # /symbol, the symbols match and are retrievable from the map.
- my $shortpc = $pc;
- $shortpc =~ s/^0*//;
- # Each line may have a list of names, which includes the function
- # and also other functions it has inlined. They are separated
- # (in PrintSymbolizedFile), by --, which is illegal in function names.
- my $fullnames;
- if (defined($symbol_map->{$shortpc})) {
- $fullnames = $symbol_map->{$shortpc};
- } else {
- $fullnames = "0x" . $pc; # Just use addresses
- }
- my $sym = [];
- $symbols->{$pc} = $sym;
- foreach my $fullname (split("--", $fullnames)) {
- my $name = ShortFunctionName($fullname);
- push(@{$sym}, $name, "?", $fullname);
- }
- }
- return $symbols;
-}
-
-sub BaseName {
- my $file_name = shift;
- $file_name =~ s!^.*/!!; # Remove directory name
- return $file_name;
-}
-
-sub MakeProfileBaseName {
- my ($binary_name, $profile_name) = @_;
- my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
- my $binary_shortname = BaseName($binary_name);
- return sprintf("%s.%s.%s-port%s",
- $binary_shortname, $main::op_time, $host, $port);
-}
-
-sub FetchDynamicProfile {
- my $binary_name = shift;
- my $profile_name = shift;
- my $fetch_name_only = shift;
- my $encourage_patience = shift;
-
- if (!IsProfileURL($profile_name)) {
- return $profile_name;
- } else {
- my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
- if ($path eq "" || $path eq "/") {
- # Missing type specifier defaults to cpu-profile
- $path = $PROFILE_PAGE;
- }
-
- my $profile_file = MakeProfileBaseName($binary_name, $profile_name);
-
- my $url;
- my $curl_timeout;
- if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)) {
- if ($path =~ m/$PROFILE_PAGE/) {
- $url = sprintf("http://$host:$port$prefix$path?seconds=%d",
- $main::opt_seconds);
- } else {
- if ($profile_name =~ m/[?]/) {
- $profile_name .= "&"
- } else {
- $profile_name .= "?"
- }
- $url = sprintf("http://$profile_name" . "seconds=%d",
- $main::opt_seconds);
- }
- $curl_timeout = sprintf("--max-time %d",
- int($main::opt_seconds * 1.01 + 60));
- } else {
- # For non-CPU profiles, we add a type-extension to
- # the target profile file name.
- my $suffix = $path;
- $suffix =~ s,/,.,g;
- $profile_file .= "$suffix";
- $url = "http://$host:$port$prefix$path";
- $curl_timeout = "";
- }
-
- my $profile_dir = $ENV{"PPROF_TMPDIR"} || ($ENV{HOME} . "/pprof");
- if (!(-d $profile_dir)) {
- mkdir($profile_dir)
- || die("Unable to create profile directory $profile_dir: $!\n");
- }
- my $tmp_profile = "$profile_dir/.tmp.$profile_file";
- my $real_profile = "$profile_dir/$profile_file";
-
- if ($fetch_name_only > 0) {
- return $real_profile;
- }
-
- my $cmd = "$CURL $curl_timeout -s -o $tmp_profile '$url'";
- if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)){
- print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n";
- if ($encourage_patience) {
- print STDERR "Be patient...\n";
- }
- } else {
- print STDERR "Fetching $path profile from $host:$port to\n ${real_profile}\n";
- }
-
- (system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n");
- (system("mv $tmp_profile $real_profile") == 0) || error("Unable to rename profile\n");
- print STDERR "Wrote profile to $real_profile\n";
- $main::collected_profile = $real_profile;
- return $main::collected_profile;
- }
-}
-
-# Collect profiles in parallel
-sub FetchDynamicProfiles {
- my $items = scalar(@main::pfile_args);
- my $levels = log($items) / log(2);
-
- if ($items == 1) {
- $main::profile_files[0] = FetchDynamicProfile($main::prog, $main::pfile_args[0], 0, 1);
- } else {
- # math rounding issues
- if ((2 ** $levels) < $items) {
- $levels++;
- }
- my $count = scalar(@main::pfile_args);
- for (my $i = 0; $i < $count; $i++) {
- $main::profile_files[$i] = FetchDynamicProfile($main::prog, $main::pfile_args[$i], 1, 0);
- }
- print STDERR "Fetching $count profiles, Be patient...\n";
- FetchDynamicProfilesRecurse($levels, 0, 0);
- $main::collected_profile = join(" \\\n ", @main::profile_files);
- }
-}
-
-# Recursively fork a process to get enough processes
-# collecting profiles
-sub FetchDynamicProfilesRecurse {
- my $maxlevel = shift;
- my $level = shift;
- my $position = shift;
-
- if (my $pid = fork()) {
- $position = 0 | ($position << 1);
- TryCollectProfile($maxlevel, $level, $position);
- wait;
- } else {
- $position = 1 | ($position << 1);
- TryCollectProfile($maxlevel, $level, $position);
- exit(0);
- }
-}
-
-# Collect a single profile
-sub TryCollectProfile {
- my $maxlevel = shift;
- my $level = shift;
- my $position = shift;
-
- if ($level >= ($maxlevel - 1)) {
- if ($position < scalar(@main::pfile_args)) {
- FetchDynamicProfile($main::prog, $main::pfile_args[$position], 0, 0);
- }
- } else {
- FetchDynamicProfilesRecurse($maxlevel, $level+1, $position);
- }
-}
-
-##### Parsing code #####
-
-# Provide a small streaming-read module to handle very large
-# cpu-profile files. Stream in chunks along a sliding window.
-# Provides an interface to get one 'slot', correctly handling
-# endian-ness differences. A slot is one 32-bit or 64-bit word
-# (depending on the input profile). We tell endianness and bit-size
-# for the profile by looking at the first 8 bytes: in cpu profiles,
-# the second slot is always 3 (we'll accept anything that's not 0).
-BEGIN {
- package CpuProfileStream;
-
- sub new {
- my ($class, $file, $fname) = @_;
- my $self = { file => $file,
- base => 0,
- stride => 512 * 1024, # must be a multiple of bitsize/8
- slots => [],
- unpack_code => "", # N for big-endian, V for little
- };
- bless $self, $class;
- # Let unittests adjust the stride
- if ($main::opt_test_stride > 0) {
- $self->{stride} = $main::opt_test_stride;
- }
- # Read the first two slots to figure out bitsize and endianness.
- my $slots = $self->{slots};
- my $str;
- read($self->{file}, $str, 8);
- # Set the global $address_length based on what we see here.
- # 8 is 32-bit (8 hexadecimal chars); 16 is 64-bit (16 hexadecimal chars).
- $address_length = ($str eq (chr(0)x8)) ? 16 : 8;
- if ($address_length == 8) {
- if (substr($str, 6, 2) eq chr(0)x2) {
- $self->{unpack_code} = 'V'; # Little-endian.
- } elsif (substr($str, 4, 2) eq chr(0)x2) {
- $self->{unpack_code} = 'N'; # Big-endian
- } else {
- ::error("$fname: header size >= 2**16\n");
- }
- @$slots = unpack($self->{unpack_code} . "*", $str);
- } else {
- # If we're a 64-bit profile, make sure we're a 64-bit-capable
- # perl. Otherwise, each slot will be represented as a float
- # instead of an int64, losing precision and making all the
- # 64-bit addresses right. We *could* try to handle this with
- # software emulation of 64-bit ints, but that's added complexity
- # for no clear benefit (yet). We use 'Q' to test for 64-bit-ness;
- # perl docs say it's only available on 64-bit perl systems.
- my $has_q = 0;
- eval { $has_q = pack("Q", "1") ? 1 : 1; };
- if (!$has_q) {
- ::error("$fname: need a 64-bit perl to process this 64-bit profile.\n");
- }
- read($self->{file}, $str, 8);
- if (substr($str, 4, 4) eq chr(0)x4) {
- # We'd love to use 'Q', but it's a) not universal, b) not endian-proof.
- $self->{unpack_code} = 'V'; # Little-endian.
- } elsif (substr($str, 0, 4) eq chr(0)x4) {
- $self->{unpack_code} = 'N'; # Big-endian
- } else {
- ::error("$fname: header size >= 2**32\n");
- }
- my @pair = unpack($self->{unpack_code} . "*", $str);
- # Since we know one of the pair is 0, it's fine to just add them.
- @$slots = (0, $pair[0] + $pair[1]);
- }
- return $self;
- }
-
- # Load more data when we access slots->get(X) which is not yet in memory.
- sub overflow {
- my ($self) = @_;
- my $slots = $self->{slots};
- $self->{base} += $#$slots + 1; # skip over data we're replacing
- my $str;
- read($self->{file}, $str, $self->{stride});
- if ($address_length == 8) { # the 32-bit case
- # This is the easy case: unpack provides 32-bit unpacking primitives.
- @$slots = unpack($self->{unpack_code} . "*", $str);
- } else {
- # We need to unpack 32 bits at a time and combine.
- my @b32_values = unpack($self->{unpack_code} . "*", $str);
- my @b64_values = ();
- for (my $i = 0; $i < $#b32_values; $i += 2) {
- # TODO(csilvers): if this is a 32-bit perl, the math below
- # could end up in a too-large int, which perl will promote
- # to a double, losing necessary precision. Deal with that.
- if ($self->{unpack_code} eq 'V') { # little-endian
- push(@b64_values, $b32_values[$i] + $b32_values[$i+1] * (2**32));
- } else {
- push(@b64_values, $b32_values[$i] * (2**32) + $b32_values[$i+1]);
- }
- }
- @$slots = @b64_values;
- }
- }
-
- # Access the i-th long in the file (logically), or -1 at EOF.
- sub get {
- my ($self, $idx) = @_;
- my $slots = $self->{slots};
- while ($#$slots >= 0) {
- if ($idx < $self->{base}) {
- # The only time we expect a reference to $slots[$i - something]
- # after referencing $slots[$i] is reading the very first header.
- # Since $stride > |header|, that shouldn't cause any lookback
- # errors. And everything after the header is sequential.
- print STDERR "Unexpected look-back reading CPU profile";
- return -1; # shrug, don't know what better to return
- } elsif ($idx > $self->{base} + $#$slots) {
- $self->overflow();
- } else {
- return $slots->[$idx - $self->{base}];
- }
- }
- # If we get here, $slots is [], which means we've reached EOF
- return -1; # unique since slots is supposed to hold unsigned numbers
- }
-}
-
-# Parse profile generated by common/profiler.cc and return a reference
-# to a map:
-# $result->{version} Version number of profile file
-# $result->{period} Sampling period (in microseconds)
-# $result->{profile} Profile object
-# $result->{map} Memory map info from profile
-# $result->{pcs} Hash of all PC values seen, key is hex address
-sub ReadProfile {
- my $prog = shift;
- my $fname = shift;
-
- if (IsSymbolizedProfileFile($fname) && !$main::use_symbolized_profile) {
- # we have both a binary and symbolized profiles, abort
- usage("Symbolized profile '$fname' cannot be used with a binary arg. " .
- "Try again without passing '$prog'.");
- }
-
- $main::profile_type = '';
-
- $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $contention_marker = $&;
- $GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $growth_marker = $&;
- $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $symbol_marker = $&;
- $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $profile_marker = $&;
-
- # Look at first line to see if it is a heap or a CPU profile.
- # CPU profile may start with no header at all, and just binary data
- # (starting with \0\0\0\0) -- in that case, don't try to read the
- # whole firstline, since it may be gigabytes(!) of data.
- open(PROFILE, "<$fname") || error("$fname: $!\n");
- binmode PROFILE; # New perls do UTF-8 processing
- my $firstchar = "";
- my $header = "";
- read(PROFILE, $firstchar, 1);
- seek(PROFILE, -1, 1); # unread the firstchar
- if ($firstchar ne "\0") {
- $header = <PROFILE>;
- if (!defined($header)) {
- error("Profile is empty.\n");
- }
- $header =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- }
-
- my $symbols;
- if ($header =~ m/^--- *$symbol_marker/o) {
- # read the symbol section of the symbolized profile file
- $symbols = ReadSymbols(*PROFILE{IO});
-
- # read the next line to get the header for the remaining profile
- $header = "";
- read(PROFILE, $firstchar, 1);
- seek(PROFILE, -1, 1); # unread the firstchar
- if ($firstchar ne "\0") {
- $header = <PROFILE>;
- $header =~ s/\r//g;
- }
- }
-
- my $result;
-
- if ($header =~ m/^heap profile:.*$growth_marker/o) {
- $main::profile_type = 'growth';
- $result = ReadHeapProfile($prog, $fname, $header);
- } elsif ($header =~ m/^heap profile:/) {
- $main::profile_type = 'heap';
- $result = ReadHeapProfile($prog, $fname, $header);
- } elsif ($header =~ m/^--- *$contention_marker/o) {
- $main::profile_type = 'contention';
- $result = ReadSynchProfile($prog, $fname);
- } elsif ($header =~ m/^--- *Stacks:/) {
- print STDERR
- "Old format contention profile: mistakenly reports " .
- "condition variable signals as lock contentions.\n";
- $main::profile_type = 'contention';
- $result = ReadSynchProfile($prog, $fname);
- } elsif ($header =~ m/^--- *$profile_marker/) {
- # the binary cpu profile data starts immediately after this line
- $main::profile_type = 'cpu';
- $result = ReadCPUProfile($prog, $fname);
- } else {
- if (defined($symbols)) {
- # a symbolized profile contains a format we don't recognize, bail out
- error("$fname: Cannot recognize profile section after symbols.\n");
- }
- # no ascii header present -- must be a CPU profile
- $main::profile_type = 'cpu';
- $result = ReadCPUProfile($prog, $fname);
- }
-
- # if we got symbols along with the profile, return those as well
- if (defined($symbols)) {
- $result->{symbols} = $symbols;
- }
-
- return $result;
-}
-
-# Subtract one from caller pc so we map back to call instr.
-# However, don't do this if we're reading a symbolized profile
-# file, in which case the subtract-one was done when the file
-# was written.
-#
-# We apply the same logic to all readers, though ReadCPUProfile uses an
-# independent implementation.
-sub FixCallerAddresses {
- my $stack = shift;
- if ($main::use_symbolized_profile) {
- return $stack;
- } else {
- $stack =~ /(\s)/;
- my $delimiter = $1;
- my @addrs = split(' ', $stack);
- my @fixedaddrs;
- $#fixedaddrs = $#addrs;
- if ($#addrs >= 0) {
- $fixedaddrs[0] = $addrs[0];
- }
- for (my $i = 1; $i <= $#addrs; $i++) {
- $fixedaddrs[$i] = AddressSub($addrs[$i], "0x1");
- }
- return join $delimiter, @fixedaddrs;
- }
-}
-
-# CPU profile reader
-sub ReadCPUProfile {
- my $prog = shift;
- my $fname = shift;
- my $version;
- my $period;
- my $i;
- my $profile = {};
- my $pcs = {};
-
- # Parse string into array of slots.
- my $slots = CpuProfileStream->new(*PROFILE, $fname);
-
- # Read header. The current header version is a 5-element structure
- # containing:
- # 0: header count (always 0)
- # 1: header "words" (after this one: 3)
- # 2: format version (0)
- # 3: sampling period (usec)
- # 4: unused padding (always 0)
- if ($slots->get(0) != 0 ) {
- error("$fname: not a profile file, or old format profile file\n");
- }
- $i = 2 + $slots->get(1);
- $version = $slots->get(2);
- $period = $slots->get(3);
- # Do some sanity checking on these header values.
- if ($version > (2**32) || $period > (2**32) || $i > (2**32) || $i < 5) {
- error("$fname: not a profile file, or corrupted profile file\n");
- }
-
- # Parse profile
- while ($slots->get($i) != -1) {
- my $n = $slots->get($i++);
- my $d = $slots->get($i++);
- if ($d > (2**16)) { # TODO(csilvers): what's a reasonable max-stack-depth?
- my $addr = sprintf("0%o", $i * ($address_length == 8 ? 4 : 8));
- print STDERR "At index $i (address $addr):\n";
- error("$fname: stack trace depth >= 2**32\n");
- }
- if ($slots->get($i) == 0) {
- # End of profile data marker
- $i += $d;
- last;
- }
-
- # Make key out of the stack entries
- my @k = ();
- for (my $j = 0; $j < $d; $j++) {
- my $pc = $slots->get($i+$j);
- # Subtract one from caller pc so we map back to call instr.
- # However, don't do this if we're reading a symbolized profile
- # file, in which case the subtract-one was done when the file
- # was written.
- if ($j > 0 && !$main::use_symbolized_profile) {
- $pc--;
- }
- $pc = sprintf("%0*x", $address_length, $pc);
- $pcs->{$pc} = 1;
- push @k, $pc;
- }
-
- AddEntry($profile, (join "\n", @k), $n);
- $i += $d;
- }
-
- # Parse map
- my $map = '';
- seek(PROFILE, $i * 4, 0);
- read(PROFILE, $map, (stat PROFILE)[7]);
- close(PROFILE);
-
- my $r = {};
- $r->{version} = $version;
- $r->{period} = $period;
- $r->{profile} = $profile;
- $r->{libs} = ParseLibraries($prog, $map, $pcs);
- $r->{pcs} = $pcs;
-
- return $r;
-}
-
-sub ReadHeapProfile {
- my $prog = shift;
- my $fname = shift;
- my $header = shift;
-
- my $index = 1;
- if ($main::opt_inuse_space) {
- $index = 1;
- } elsif ($main::opt_inuse_objects) {
- $index = 0;
- } elsif ($main::opt_alloc_space) {
- $index = 3;
- } elsif ($main::opt_alloc_objects) {
- $index = 2;
- }
-
- # Find the type of this profile. The header line looks like:
- # heap profile: 1246: 8800744 [ 1246: 8800744] @ <heap-url>/266053
- # There are two pairs <count: size>, the first inuse objects/space, and the
- # second allocated objects/space. This is followed optionally by a profile
- # type, and if that is present, optionally by a sampling frequency.
- # For remote heap profiles (v1):
- # The interpretation of the sampling frequency is that the profiler, for
- # each sample, calculates a uniformly distributed random integer less than
- # the given value, and records the next sample after that many bytes have
- # been allocated. Therefore, the expected sample interval is half of the
- # given frequency. By default, if not specified, the expected sample
- # interval is 128KB. Only remote-heap-page profiles are adjusted for
- # sample size.
- # For remote heap profiles (v2):
- # The sampling frequency is the rate of a Poisson process. This means that
- # the probability of sampling an allocation of size X with sampling rate Y
- # is 1 - exp(-X/Y)
- # For version 2, a typical header line might look like this:
- # heap profile: 1922: 127792360 [ 1922: 127792360] @ <heap-url>_v2/524288
- # the trailing number (524288) is the sampling rate. (Version 1 showed
- # double the 'rate' here)
- my $sampling_algorithm = 0;
- my $sample_adjustment = 0;
- chomp($header);
- my $type = "unknown";
- if ($header =~ m"^heap profile:\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\](\s*@\s*([^/]*)(/(\d+))?)?") {
- if (defined($6) && ($6 ne '')) {
- $type = $6;
- my $sample_period = $8;
- # $type is "heapprofile" for profiles generated by the
- # heap-profiler, and either "heap" or "heap_v2" for profiles
- # generated by sampling directly within tcmalloc. It can also
- # be "growth" for heap-growth profiles. The first is typically
- # found for profiles generated locally, and the others for
- # remote profiles.
- if (($type eq "heapprofile") || ($type !~ /heap/) ) {
- # No need to adjust for the sampling rate with heap-profiler-derived data
- $sampling_algorithm = 0;
- } elsif ($type =~ /_v2/) {
- $sampling_algorithm = 2; # version 2 sampling
- if (defined($sample_period) && ($sample_period ne '')) {
- $sample_adjustment = int($sample_period);
- }
- } else {
- $sampling_algorithm = 1; # version 1 sampling
- if (defined($sample_period) && ($sample_period ne '')) {
- $sample_adjustment = int($sample_period)/2;
- }
- }
- } else {
- # We detect whether or not this is a remote-heap profile by checking
- # that the total-allocated stats ($n2,$s2) are exactly the
- # same as the in-use stats ($n1,$s1). It is remotely conceivable
- # that a non-remote-heap profile may pass this check, but it is hard
- # to imagine how that could happen.
- # In this case it's so old it's guaranteed to be remote-heap version 1.
- my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
- if (($n1 == $n2) && ($s1 == $s2)) {
- # This is likely to be a remote-heap based sample profile
- $sampling_algorithm = 1;
- }
- }
- }
-
- if ($sampling_algorithm > 0) {
- # For remote-heap generated profiles, adjust the counts and sizes to
- # account for the sample rate (we sample once every 128KB by default).
- if ($sample_adjustment == 0) {
- # Turn on profile adjustment.
- $sample_adjustment = 128*1024;
- print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n";
- } else {
- printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n",
- $sample_adjustment);
- }
- if ($sampling_algorithm > 1) {
- # We don't bother printing anything for the original version (version 1)
- printf STDERR "Heap version $sampling_algorithm\n";
- }
- }
-
- my $profile = {};
- my $pcs = {};
- my $map = "";
-
- while (<PROFILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- if (/^MAPPED_LIBRARIES:/) {
- # Read the /proc/self/maps data
- while (<PROFILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- $map .= $_;
- }
- last;
- }
-
- if (/^--- Memory map:/) {
- # Read /proc/self/maps data as formatted by DumpAddressMap()
- my $buildvar = "";
- while (<PROFILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- # Parse "build=<dir>" specification if supplied
- if (m/^\s*build=(.*)\n/) {
- $buildvar = $1;
- }
-
- # Expand "$build" variable if available
- $_ =~ s/\$build\b/$buildvar/g;
-
- $map .= $_;
- }
- last;
- }
-
- # Read entry of the form:
- # <count1>: <bytes1> [<count2>: <bytes2>] @ a1 a2 a3 ... an
- s/^\s*//;
- s/\s*$//;
- if (m/^\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]\s+@\s+(.*)$/) {
- my $stack = $5;
- my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
-
- if ($sample_adjustment) {
- if ($sampling_algorithm == 2) {
- # Remote-heap version 2
- # The sampling frequency is the rate of a Poisson process.
- # This means that the probability of sampling an allocation of
- # size X with sampling rate Y is 1 - exp(-X/Y)
- my $ratio;
- $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
- my $scale_factor;
- $scale_factor = 1/(1 - exp(-$ratio));
- $n1 *= $scale_factor;
- $s1 *= $scale_factor;
- $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
- $scale_factor = 1/(1 - exp(-$ratio));
- $n2 *= $scale_factor;
- $s2 *= $scale_factor;
- } else {
- # Remote-heap version 1
- my $ratio;
- $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
- if ($ratio < 1) {
- $n1 /= $ratio;
- $s1 /= $ratio;
- }
- $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
- if ($ratio < 1) {
- $n2 /= $ratio;
- $s2 /= $ratio;
- }
- }
- }
-
- my @counts = ($n1, $s1, $n2, $s2);
- AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]);
- }
- }
-
- my $r = {};
- $r->{version} = "heap";
- $r->{period} = 1;
- $r->{profile} = $profile;
- $r->{libs} = ParseLibraries($prog, $map, $pcs);
- $r->{pcs} = $pcs;
- return $r;
-}
-
-sub ReadSynchProfile {
- my ($prog, $fname, $header) = @_;
-
- my $map = '';
- my $profile = {};
- my $pcs = {};
- my $sampling_period = 1;
- my $cyclespernanosec = 2.8; # Default assumption for old binaries
- my $seen_clockrate = 0;
- my $line;
-
- my $index = 0;
- if ($main::opt_total_delay) {
- $index = 0;
- } elsif ($main::opt_contentions) {
- $index = 1;
- } elsif ($main::opt_mean_delay) {
- $index = 2;
- }
-
- while ( $line = <PROFILE> ) {
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- if ( $line =~ /^\s*(\d+)\s+(\d+) \@\s*(.*?)\s*$/ ) {
- my ($cycles, $count, $stack) = ($1, $2, $3);
-
- # Convert cycles to nanoseconds
- $cycles /= $cyclespernanosec;
-
- # Adjust for sampling done by application
- $cycles *= $sampling_period;
- $count *= $sampling_period;
-
- my @values = ($cycles, $count, $cycles / $count);
- AddEntries($profile, $pcs, FixCallerAddresses($stack), $values[$index]);
-
- } elsif ( $line =~ /^(slow release).*thread \d+ \@\s*(.*?)\s*$/ ||
- $line =~ /^\s*(\d+) \@\s*(.*?)\s*$/ ) {
- my ($cycles, $stack) = ($1, $2);
- if ($cycles !~ /^\d+$/) {
- next;
- }
-
- # Convert cycles to nanoseconds
- $cycles /= $cyclespernanosec;
-
- # Adjust for sampling done by application
- $cycles *= $sampling_period;
-
- AddEntries($profile, $pcs, FixCallerAddresses($stack), $cycles);
-
- } elsif ( $line =~ m/^([a-z][^=]*)=(.*)$/ ) {
- my ($variable, $value) = ($1,$2);
- for ($variable, $value) {
- s/^\s+//;
- s/\s+$//;
- }
- if ($variable eq "cycles/second") {
- $cyclespernanosec = $value / 1e9;
- $seen_clockrate = 1;
- } elsif ($variable eq "sampling period") {
- $sampling_period = $value;
- } elsif ($variable eq "ms since reset") {
- # Currently nothing is done with this value in pprof
- # So we just silently ignore it for now
- } elsif ($variable eq "discarded samples") {
- # Currently nothing is done with this value in pprof
- # So we just silently ignore it for now
- } else {
- printf STDERR ("Ignoring unnknown variable in /contention output: " .
- "'%s' = '%s'\n",$variable,$value);
- }
- } else {
- # Memory map entry
- $map .= $line;
- }
- }
- close PROFILE;
-
- if (!$seen_clockrate) {
- printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n",
- $cyclespernanosec);
- }
-
- my $r = {};
- $r->{version} = 0;
- $r->{period} = $sampling_period;
- $r->{profile} = $profile;
- $r->{libs} = ParseLibraries($prog, $map, $pcs);
- $r->{pcs} = $pcs;
- return $r;
-}
-
-# Given a hex value in the form "0x1abcd" return "0001abcd" or
-# "000000000001abcd", depending on the current address length.
-# There's probably a more idiomatic (or faster) way to do this...
-sub HexExtend {
- my $addr = shift;
-
- $addr =~ s/^0x//;
-
- if (length $addr > $address_length) {
- printf STDERR "Warning: address $addr is longer than address length $address_length\n";
- }
-
- return substr("000000000000000".$addr, -$address_length);
-}
-
-##### Symbol extraction #####
-
-# Aggressively search the lib_prefix values for the given library
-# If all else fails, just return the name of the library unmodified.
-# If the lib_prefix is "/my/path,/other/path" and $file is "/lib/dir/mylib.so"
-# it will search the following locations in this order, until it finds a file:
-# /my/path/lib/dir/mylib.so
-# /other/path/lib/dir/mylib.so
-# /my/path/dir/mylib.so
-# /other/path/dir/mylib.so
-# /my/path/mylib.so
-# /other/path/mylib.so
-# /lib/dir/mylib.so (returned as last resort)
-sub FindLibrary {
- my $file = shift;
- my $suffix = $file;
-
- # Search for the library as described above
- do {
- foreach my $prefix (@prefix_list) {
- my $fullpath = $prefix . $suffix;
- if (-e $fullpath) {
- return $fullpath;
- }
- }
- } while ($suffix =~ s|^/[^/]+/|/|);
- return $file;
-}
-
-# Return path to library with debugging symbols.
-# For libc libraries, the copy in /usr/lib/debug contains debugging symbols
-sub DebuggingLibrary {
- my $file = shift;
- if ($file =~ m|^/| && -f "/usr/lib/debug$file") {
- return "/usr/lib/debug$file";
- }
- return undef;
-}
-
-# Parse text section header of a library using objdump
-sub ParseTextSectionHeaderFromObjdump {
- my $lib = shift;
-
- my $size = undef;
- my $vma;
- my $file_offset;
- # Get objdump output from the library file to figure out how to
- # map between mapped addresses and addresses in the library.
- my $objdump = $obj_tool_map{"objdump"};
- open(OBJDUMP, "$objdump -h $lib |")
- || error("$objdump $lib: $!\n");
- while (<OBJDUMP>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- # Idx Name Size VMA LMA File off Algn
- # 10 .text 00104b2c 420156f0 420156f0 000156f0 2**4
- # For 64-bit objects, VMA and LMA will be 16 hex digits, size and file
- # offset may still be 8. But AddressSub below will still handle that.
- my @x = split;
- if (($#x >= 6) && ($x[1] eq '.text')) {
- $size = $x[2];
- $vma = $x[3];
- $file_offset = $x[5];
- last;
- }
- }
- close(OBJDUMP);
-
- if (!defined($size)) {
- return undef;
- }
-
- my $r = {};
- $r->{size} = $size;
- $r->{vma} = $vma;
- $r->{file_offset} = $file_offset;
-
- return $r;
-}
-
-# Parse text section header of a library using otool (on OS X)
-sub ParseTextSectionHeaderFromOtool {
- my $lib = shift;
-
- my $size = undef;
- my $vma = undef;
- my $file_offset = undef;
- # Get otool output from the library file to figure out how to
- # map between mapped addresses and addresses in the library.
- my $otool = $obj_tool_map{"otool"};
- open(OTOOL, "$otool -l $lib |")
- || error("$otool $lib: $!\n");
- my $cmd = "";
- my $sectname = "";
- my $segname = "";
- foreach my $line (<OTOOL>) {
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- # Load command <#>
- # cmd LC_SEGMENT
- # [...]
- # Section
- # sectname __text
- # segname __TEXT
- # addr 0x000009f8
- # size 0x00018b9e
- # offset 2552
- # align 2^2 (4)
- # We will need to strip off the leading 0x from the hex addresses,
- # and convert the offset into hex.
- if ($line =~ /Load command/) {
- $cmd = "";
- $sectname = "";
- $segname = "";
- } elsif ($line =~ /Section/) {
- $sectname = "";
- $segname = "";
- } elsif ($line =~ /cmd (\w+)/) {
- $cmd = $1;
- } elsif ($line =~ /sectname (\w+)/) {
- $sectname = $1;
- } elsif ($line =~ /segname (\w+)/) {
- $segname = $1;
- } elsif (!(($cmd eq "LC_SEGMENT" || $cmd eq "LC_SEGMENT_64") &&
- $sectname eq "__text" &&
- $segname eq "__TEXT")) {
- next;
- } elsif ($line =~ /\baddr 0x([0-9a-fA-F]+)/) {
- $vma = $1;
- } elsif ($line =~ /\bsize 0x([0-9a-fA-F]+)/) {
- $size = $1;
- } elsif ($line =~ /\boffset ([0-9]+)/) {
- $file_offset = sprintf("%016x", $1);
- }
- if (defined($vma) && defined($size) && defined($file_offset)) {
- last;
- }
- }
- close(OTOOL);
-
- if (!defined($vma) || !defined($size) || !defined($file_offset)) {
- return undef;
- }
-
- my $r = {};
- $r->{size} = $size;
- $r->{vma} = $vma;
- $r->{file_offset} = $file_offset;
-
- return $r;
-}
-
-sub ParseTextSectionHeader {
- # obj_tool_map("otool") is only defined if we're in a Mach-O environment
- if (defined($obj_tool_map{"otool"})) {
- my $r = ParseTextSectionHeaderFromOtool(@_);
- if (defined($r)){
- return $r;
- }
- }
- # If otool doesn't work, or we don't have it, fall back to objdump
- return ParseTextSectionHeaderFromObjdump(@_);
-}
-
-# Split /proc/pid/maps dump into a list of libraries
-sub ParseLibraries {
- return if $main::use_symbol_page; # We don't need libraries info.
- my $prog = shift;
- my $map = shift;
- my $pcs = shift;
-
- my $result = [];
- my $h = "[a-f0-9]+";
- my $zero_offset = HexExtend("0");
-
- my $buildvar = "";
- foreach my $l (split("\n", $map)) {
- if ($l =~ m/^\s*build=(.*)$/) {
- $buildvar = $1;
- }
-
- my $start;
- my $finish;
- my $offset;
- my $lib;
- if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*(\.\d+){0,3})?)$/i) {
- # Full line from /proc/self/maps. Example:
- # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so
- $start = HexExtend($1);
- $finish = HexExtend($2);
- $offset = HexExtend($3);
- $lib = $4;
- $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths
- } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) {
- # Cooked line from DumpAddressMap. Example:
- # 40000000-40015000: /lib/ld-2.3.2.so
- $start = HexExtend($1);
- $finish = HexExtend($2);
- $offset = $zero_offset;
- $lib = $3;
- } else {
- next;
- }
-
- # Expand "$build" variable if available
- $lib =~ s/\$build\b/$buildvar/g;
-
- $lib = FindLibrary($lib);
-
- # Check for pre-relocated libraries, which use pre-relocated symbol tables
- # and thus require adjusting the offset that we'll use to translate
- # VM addresses into symbol table addresses.
- # Only do this if we're not going to fetch the symbol table from a
- # debugging copy of the library.
- if (!DebuggingLibrary($lib)) {
- my $text = ParseTextSectionHeader($lib);
- if (defined($text)) {
- my $vma_offset = AddressSub($text->{vma}, $text->{file_offset});
- $offset = AddressAdd($offset, $vma_offset);
- }
- }
-
- push(@{$result}, [$lib, $start, $finish, $offset]);
- }
-
- # Append special entry for additional library (not relocated)
- if ($main::opt_lib ne "") {
- my $text = ParseTextSectionHeader($main::opt_lib);
- if (defined($text)) {
- my $start = $text->{vma};
- my $finish = AddressAdd($start, $text->{size});
-
- push(@{$result}, [$main::opt_lib, $start, $finish, $start]);
- }
- }
-
- # Append special entry for the main program. This covers
- # 0..max_pc_value_seen, so that we assume pc values not found in one
- # of the library ranges will be treated as coming from the main
- # program binary.
- my $min_pc = HexExtend("0");
- my $max_pc = $min_pc; # find the maximal PC value in any sample
- foreach my $pc (keys(%{$pcs})) {
- if (HexExtend($pc) gt $max_pc) { $max_pc = HexExtend($pc); }
- }
- push(@{$result}, [$prog, $min_pc, $max_pc, $zero_offset]);
-
- return $result;
-}
-
-# Add two hex addresses of length $address_length.
-# Run pprof --test for unit test if this is changed.
-sub AddressAdd {
- my $addr1 = shift;
- my $addr2 = shift;
- my $sum;
-
- if ($address_length == 8) {
- # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
- $sum = (hex($addr1)+hex($addr2)) % (0x10000000 * 16);
- return sprintf("%08x", $sum);
-
- } else {
- # Do the addition in 7-nibble chunks to trivialize carry handling.
-
- if ($main::opt_debug and $main::opt_test) {
- print STDERR "AddressAdd $addr1 + $addr2 = ";
- }
-
- my $a1 = substr($addr1,-7);
- $addr1 = substr($addr1,0,-7);
- my $a2 = substr($addr2,-7);
- $addr2 = substr($addr2,0,-7);
- $sum = hex($a1) + hex($a2);
- my $c = 0;
- if ($sum > 0xfffffff) {
- $c = 1;
- $sum -= 0x10000000;
- }
- my $r = sprintf("%07x", $sum);
-
- $a1 = substr($addr1,-7);
- $addr1 = substr($addr1,0,-7);
- $a2 = substr($addr2,-7);
- $addr2 = substr($addr2,0,-7);
- $sum = hex($a1) + hex($a2) + $c;
- $c = 0;
- if ($sum > 0xfffffff) {
- $c = 1;
- $sum -= 0x10000000;
- }
- $r = sprintf("%07x", $sum) . $r;
-
- $sum = hex($addr1) + hex($addr2) + $c;
- if ($sum > 0xff) { $sum -= 0x100; }
- $r = sprintf("%02x", $sum) . $r;
-
- if ($main::opt_debug and $main::opt_test) { print STDERR "$r\n"; }
-
- return $r;
- }
-}
-
-
-# Subtract two hex addresses of length $address_length.
-# Run pprof --test for unit test if this is changed.
-sub AddressSub {
- my $addr1 = shift;
- my $addr2 = shift;
- my $diff;
-
- if ($address_length == 8) {
- # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
- $diff = (hex($addr1)-hex($addr2)) % (0x10000000 * 16);
- return sprintf("%08x", $diff);
-
- } else {
- # Do the addition in 7-nibble chunks to trivialize borrow handling.
- # if ($main::opt_debug) { print STDERR "AddressSub $addr1 - $addr2 = "; }
-
- my $a1 = hex(substr($addr1,-7));
- $addr1 = substr($addr1,0,-7);
- my $a2 = hex(substr($addr2,-7));
- $addr2 = substr($addr2,0,-7);
- my $b = 0;
- if ($a2 > $a1) {
- $b = 1;
- $a1 += 0x10000000;
- }
- $diff = $a1 - $a2;
- my $r = sprintf("%07x", $diff);
-
- $a1 = hex(substr($addr1,-7));
- $addr1 = substr($addr1,0,-7);
- $a2 = hex(substr($addr2,-7)) + $b;
- $addr2 = substr($addr2,0,-7);
- $b = 0;
- if ($a2 > $a1) {
- $b = 1;
- $a1 += 0x10000000;
- }
- $diff = $a1 - $a2;
- $r = sprintf("%07x", $diff) . $r;
-
- $a1 = hex($addr1);
- $a2 = hex($addr2) + $b;
- if ($a2 > $a1) { $a1 += 0x100; }
- $diff = $a1 - $a2;
- $r = sprintf("%02x", $diff) . $r;
-
- # if ($main::opt_debug) { print STDERR "$r\n"; }
-
- return $r;
- }
-}
-
-# Increment a hex addresses of length $address_length.
-# Run pprof --test for unit test if this is changed.
-sub AddressInc {
- my $addr = shift;
- my $sum;
-
- if ($address_length == 8) {
- # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
- $sum = (hex($addr)+1) % (0x10000000 * 16);
- return sprintf("%08x", $sum);
-
- } else {
- # Do the addition in 7-nibble chunks to trivialize carry handling.
- # We are always doing this to step through the addresses in a function,
- # and will almost never overflow the first chunk, so we check for this
- # case and exit early.
-
- # if ($main::opt_debug) { print STDERR "AddressInc $addr1 = "; }
-
- my $a1 = substr($addr,-7);
- $addr = substr($addr,0,-7);
- $sum = hex($a1) + 1;
- my $r = sprintf("%07x", $sum);
- if ($sum <= 0xfffffff) {
- $r = $addr . $r;
- # if ($main::opt_debug) { print STDERR "$r\n"; }
- return HexExtend($r);
- } else {
- $r = "0000000";
- }
-
- $a1 = substr($addr,-7);
- $addr = substr($addr,0,-7);
- $sum = hex($a1) + 1;
- $r = sprintf("%07x", $sum) . $r;
- if ($sum <= 0xfffffff) {
- $r = $addr . $r;
- # if ($main::opt_debug) { print STDERR "$r\n"; }
- return HexExtend($r);
- } else {
- $r = "00000000000000";
- }
-
- $sum = hex($addr) + 1;
- if ($sum > 0xff) { $sum -= 0x100; }
- $r = sprintf("%02x", $sum) . $r;
-
- # if ($main::opt_debug) { print STDERR "$r\n"; }
- return $r;
- }
-}
-
-# Extract symbols for all PC values found in profile
-sub ExtractSymbols {
- my $libs = shift;
- my $pcset = shift;
-
- my $symbols = {};
-
- # Map each PC value to the containing library
- my %seen = ();
- foreach my $lib (@{$libs}) {
- my $libname = $lib->[0];
- my $start = $lib->[1];
- my $finish = $lib->[2];
- my $offset = $lib->[3];
-
- # Get list of pcs that belong in this library.
- my $contained = [];
- foreach my $pc (keys(%{$pcset})) {
- if (!$seen{$pc} && ($pc ge $start) && ($pc le $finish)) {
- $seen{$pc} = 1;
- push(@{$contained}, $pc);
- }
- }
- # Map to symbols
- MapToSymbols($libname, AddressSub($start, $offset), $contained, $symbols);
- }
-
- return $symbols;
-}
-
-# Map list of PC values to symbols for a given image
-sub MapToSymbols {
- my $image = shift;
- my $offset = shift;
- my $pclist = shift;
- my $symbols = shift;
-
- my $debug = 0;
-
- # Ignore empty binaries
- if ($#{$pclist} < 0) { return; }
-
- # Figure out the addr2line command to use
- my $addr2line = $obj_tool_map{"addr2line"};
- my $cmd = "$addr2line -f -C -e $image";
- if (exists $obj_tool_map{"addr2line_pdb"}) {
- $addr2line = $obj_tool_map{"addr2line_pdb"};
- $cmd = "$addr2line --demangle -f -C -e $image";
- }
-
- # If "addr2line" isn't installed on the system at all, just use
- # nm to get what info we can (function names, but not line numbers).
- if (system("$addr2line --help >/dev/null 2>&1") != 0) {
- MapSymbolsWithNM($image, $offset, $pclist, $symbols);
- return;
- }
-
- # "addr2line -i" can produce a variable number of lines per input
- # address, with no separator that allows us to tell when data for
- # the next address starts. So we find the address for a special
- # symbol (_fini) and interleave this address between all real
- # addresses passed to addr2line. The name of this special symbol
- # can then be used as a separator.
- $sep_address = undef; # May be filled in by MapSymbolsWithNM()
- my $nm_symbols = {};
- MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols);
- # TODO(csilvers): only add '-i' if addr2line supports it.
- if (defined($sep_address)) {
- # Only add " -i" to addr2line if the binary supports it.
- # addr2line --help returns 0, but not if it sees an unknown flag first.
- if (system("$cmd -i --help >/dev/null 2>&1") == 0) {
- $cmd .= " -i";
- } else {
- $sep_address = undef; # no need for sep_address if we don't support -i
- }
- }
-
- # Make file with all PC values with intervening 'sep_address' so
- # that we can reliably detect the end of inlined function list
- open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n");
- if ($debug) { print("---- $image ---\n"); }
- for (my $i = 0; $i <= $#{$pclist}; $i++) {
- # addr2line always reads hex addresses, and does not need '0x' prefix.
- if ($debug) { printf STDERR ("%s\n", $pclist->[$i]); }
- printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset));
- if (defined($sep_address)) {
- printf ADDRESSES ("%s\n", $sep_address);
- }
- }
- close(ADDRESSES);
- if ($debug) {
- print("----\n");
- system("cat $main::tmpfile_sym");
- print("----\n");
- system("$cmd <$main::tmpfile_sym");
- print("----\n");
- }
-
- open(SYMBOLS, "$cmd <$main::tmpfile_sym |") || error("$cmd: $!\n");
- my $count = 0; # Index in pclist
- while (<SYMBOLS>) {
- # Read fullfunction and filelineinfo from next pair of lines
- s/\r?\n$//g;
- my $fullfunction = $_;
- $_ = <SYMBOLS>;
- s/\r?\n$//g;
- my $filelinenum = $_;
-
- if (defined($sep_address) && $fullfunction eq $sep_symbol) {
- # Terminating marker for data for this address
- $count++;
- next;
- }
-
- $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths
-
- my $pcstr = $pclist->[$count];
- my $function = ShortFunctionName($fullfunction);
- if ($fullfunction eq '??') {
- # See if nm found a symbol
- my $nms = $nm_symbols->{$pcstr};
- if (defined($nms)) {
- $function = $nms->[0];
- $fullfunction = $nms->[2];
- }
- }
-
- # Prepend to accumulated symbols for pcstr
- # (so that caller comes before callee)
- my $sym = $symbols->{$pcstr};
- if (!defined($sym)) {
- $sym = [];
- $symbols->{$pcstr} = $sym;
- }
- unshift(@{$sym}, $function, $filelinenum, $fullfunction);
- if ($debug) { printf STDERR ("%s => [%s]\n", $pcstr, join(" ", @{$sym})); }
- if (!defined($sep_address)) {
- # Inlining is off, se this entry ends immediately
- $count++;
- }
- }
- close(SYMBOLS);
-}
-
-# Use nm to map the list of referenced PCs to symbols. Return true iff we
-# are able to read procedure information via nm.
-sub MapSymbolsWithNM {
- my $image = shift;
- my $offset = shift;
- my $pclist = shift;
- my $symbols = shift;
-
- # Get nm output sorted by increasing address
- my $symbol_table = GetProcedureBoundaries($image, ".");
- if (!%{$symbol_table}) {
- return 0;
- }
- # Start addresses are already the right length (8 or 16 hex digits).
- my @names = sort { $symbol_table->{$a}->[0] cmp $symbol_table->{$b}->[0] }
- keys(%{$symbol_table});
-
- if ($#names < 0) {
- # No symbols: just use addresses
- foreach my $pc (@{$pclist}) {
- my $pcstr = "0x" . $pc;
- $symbols->{$pc} = [$pcstr, "?", $pcstr];
- }
- return 0;
- }
-
- # Sort addresses so we can do a join against nm output
- my $index = 0;
- my $fullname = $names[0];
- my $name = ShortFunctionName($fullname);
- foreach my $pc (sort { $a cmp $b } @{$pclist}) {
- # Adjust for mapped offset
- my $mpc = AddressSub($pc, $offset);
- while (($index < $#names) && ($mpc ge $symbol_table->{$fullname}->[1])){
- $index++;
- $fullname = $names[$index];
- $name = ShortFunctionName($fullname);
- }
- if ($mpc lt $symbol_table->{$fullname}->[1]) {
- $symbols->{$pc} = [$name, "?", $fullname];
- } else {
- my $pcstr = "0x" . $pc;
- $symbols->{$pc} = [$pcstr, "?", $pcstr];
- }
- }
- return 1;
-}
-
-sub ShortFunctionName {
- my $function = shift;
- while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types
- while ($function =~ s/<[^<>]*>//g) { } # Remove template arguments
- $function =~ s/^.*\s+(\w+::)/$1/; # Remove leading type
- return $function;
-}
-
-# Trim overly long symbols found in disassembler output
-sub CleanDisassembly {
- my $d = shift;
- while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
- while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
- return $d;
-}
-
-##### Miscellaneous #####
-
-# Find the right versions of the above object tools to use. The
-# argument is the program file being analyzed, and should be an ELF
-# 32-bit or ELF 64-bit executable file. The location of the tools
-# is determined by considering the following options in this order:
-# 1) --tools option, if set
-# 2) PPROF_TOOLS environment variable, if set
-# 3) the environment
-sub ConfigureObjTools {
- my $prog_file = shift;
-
- # Check for the existence of $prog_file because /usr/bin/file does not
- # predictably return error status in prod.
- (-e $prog_file) || error("$prog_file does not exist.\n");
-
- # Follow symlinks (at least for systems where "file" supports that)
- my $file_type = `/usr/bin/file -L $prog_file 2>/dev/null || /usr/bin/file $prog_file`;
- if ($file_type =~ /64-bit/) {
- # Change $address_length to 16 if the program file is ELF 64-bit.
- # We can't detect this from many (most?) heap or lock contention
- # profiles, since the actual addresses referenced are generally in low
- # memory even for 64-bit programs.
- $address_length = 16;
- }
-
- if ($file_type =~ /MS Windows/) {
- # For windows, we provide a version of nm and addr2line as part of
- # the opensource release, which is capable of parsing
- # Windows-style PDB executables. It should live in the path, or
- # in the same directory as pprof.
- $obj_tool_map{"nm_pdb"} = "nm-pdb";
- $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb";
- }
-
- if ($file_type =~ /Mach-O/) {
- # OS X uses otool to examine Mach-O files, rather than objdump.
- $obj_tool_map{"otool"} = "otool";
- $obj_tool_map{"addr2line"} = "false"; # no addr2line
- $obj_tool_map{"objdump"} = "false"; # no objdump
- }
-
- # Go fill in %obj_tool_map with the pathnames to use:
- foreach my $tool (keys %obj_tool_map) {
- $obj_tool_map{$tool} = ConfigureTool($obj_tool_map{$tool});
- }
-}
-
-# Returns the path of a caller-specified object tool. If --tools or
-# PPROF_TOOLS are specified, then returns the full path to the tool
-# with that prefix. Otherwise, returns the path unmodified (which
-# means we will look for it on PATH).
-sub ConfigureTool {
- my $tool = shift;
- my $path;
-
- if ($main::opt_tools ne "") {
- # Use a prefix specified by the --tools option...
- $path = $main::opt_tools . $tool;
- if (!-x $path) {
- error("No '$tool' found with prefix specified by --tools $main::opt_tools\n");
- }
- } elsif (exists $ENV{"PPROF_TOOLS"} &&
- $ENV{"PPROF_TOOLS"} ne "") {
- #... or specified with the PPROF_TOOLS environment variable...
- $path = $ENV{"PPROF_TOOLS"} . $tool;
- if (!-x $path) {
- error("No '$tool' found with prefix specified by PPROF_TOOLS=$ENV{PPROF_TOOLS}\n");
- }
- } else {
- # ... otherwise use the version that exists in the same directory as
- # pprof. If there's nothing there, use $PATH.
- $0 =~ m,[^/]*$,; # this is everything after the last slash
- my $dirname = $`; # this is everything up to and including the last slash
- if (-x "$dirname$tool") {
- $path = "$dirname$tool";
- } else {
- $path = $tool;
- }
- }
- if ($main::opt_debug) { print STDERR "Using '$path' for '$tool'.\n"; }
- return $path;
-}
-
-sub cleanup {
- unlink($main::tmpfile_sym);
- unlink(keys %main::tempnames);
-
- # We leave any collected profiles in $HOME/pprof in case the user wants
- # to look at them later. We print a message informing them of this.
- if ((scalar(@main::profile_files) > 0) &&
- defined($main::collected_profile)) {
- if (scalar(@main::profile_files) == 1) {
- print STDERR "Dynamically gathered profile is in $main::collected_profile\n";
- }
- print STDERR "If you want to investigate this profile further, you can do:\n";
- print STDERR "\n";
- print STDERR " pprof \\\n";
- print STDERR " $main::prog \\\n";
- print STDERR " $main::collected_profile\n";
- print STDERR "\n";
- }
-}
-
-sub sighandler {
- cleanup();
- exit(1);
-}
-
-sub error {
- my $msg = shift;
- print STDERR $msg;
- cleanup();
- exit(1);
-}
-
-
-# Run $nm_command and get all the resulting procedure boundaries whose
-# names match "$regexp" and returns them in a hashtable mapping from
-# procedure name to a two-element vector of [start address, end address]
-sub GetProcedureBoundariesViaNm {
- my $nm_command = shift;
- my $regexp = shift;
-
- my $symbol_table = {};
- open(NM, "$nm_command |") || error("$nm_command: $!\n");
- my $last_start = "0";
- my $routine = "";
- while (<NM>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- if (m/^\s*([0-9a-f]+) (.) (..*)/) {
- my $start_val = $1;
- my $type = $2;
- my $this_routine = $3;
-
- # It's possible for two symbols to share the same address, if
- # one is a zero-length variable (like __start_google_malloc) or
- # one symbol is a weak alias to another (like __libc_malloc).
- # In such cases, we want to ignore all values except for the
- # actual symbol, which in nm-speak has type "T". The logic
- # below does this, though it's a bit tricky: what happens when
- # we have a series of lines with the same address, is the first
- # one gets queued up to be processed. However, it won't
- # *actually* be processed until later, when we read a line with
- # a different address. That means that as long as we're reading
- # lines with the same address, we have a chance to replace that
- # item in the queue, which we do whenever we see a 'T' entry --
- # that is, a line with type 'T'. If we never see a 'T' entry,
- # we'll just go ahead and process the first entry (which never
- # got touched in the queue), and ignore the others.
- if ($start_val eq $last_start && $type =~ /t/i) {
- # We are the 'T' symbol at this address, replace previous symbol.
- $routine = $this_routine;
- next;
- } elsif ($start_val eq $last_start) {
- # We're not the 'T' symbol at this address, so ignore us.
- next;
- }
-
- if ($this_routine eq $sep_symbol) {
- $sep_address = HexExtend($start_val);
- }
-
- # Tag this routine with the starting address in case the image
- # has multiple occurrences of this routine. We use a syntax
- # that resembles template paramters that are automatically
- # stripped out by ShortFunctionName()
- $this_routine .= "<$start_val>";
-
- if (defined($routine) && $routine =~ m/$regexp/) {
- $symbol_table->{$routine} = [HexExtend($last_start),
- HexExtend($start_val)];
- }
- $last_start = $start_val;
- $routine = $this_routine;
- } elsif (m/^Loaded image name: (.+)/) {
- # The win32 nm workalike emits information about the binary it is using.
- if ($main::opt_debug) { print STDERR "Using Image $1\n"; }
- } elsif (m/^PDB file name: (.+)/) {
- # The win32 nm workalike emits information about the pdb it is using.
- if ($main::opt_debug) { print STDERR "Using PDB $1\n"; }
- }
- }
- close(NM);
- # Handle the last line in the nm output. Unfortunately, we don't know
- # how big this last symbol is, because we don't know how big the file
- # is. For now, we just give it a size of 0.
- # TODO(csilvers): do better here.
- if (defined($routine) && $routine =~ m/$regexp/) {
- $symbol_table->{$routine} = [HexExtend($last_start),
- HexExtend($last_start)];
- }
- return $symbol_table;
-}
-
-# Gets the procedure boundaries for all routines in "$image" whose names
-# match "$regexp" and returns them in a hashtable mapping from procedure
-# name to a two-element vector of [start address, end address].
-# Will return an empty map if nm is not installed or not working properly.
-sub GetProcedureBoundaries {
- my $image = shift;
- my $regexp = shift;
-
- # For libc libraries, the copy in /usr/lib/debug contains debugging symbols
- my $debugging = DebuggingLibrary($image);
- if ($debugging) {
- $image = $debugging;
- }
-
- my $nm = $obj_tool_map{"nm"};
- my $cppfilt = $obj_tool_map{"c++filt"};
-
- # nm can fail for two reasons: 1) $image isn't a debug library; 2) nm
- # binary doesn't support --demangle. In addition, for OS X we need
- # to use the -f flag to get 'flat' nm output (otherwise we don't sort
- # properly and get incorrect results). Unfortunately, GNU nm uses -f
- # in an incompatible way. So first we test whether our nm supports
- # --demangle and -f.
- my $demangle_flag = "";
- my $cppfilt_flag = "";
- if (system("$nm --demangle $image >/dev/null 2>&1") == 0) {
- # In this mode, we do "nm --demangle <foo>"
- $demangle_flag = "--demangle";
- $cppfilt_flag = "";
- } elsif (system("$cppfilt $image >/dev/null 2>&1") == 0) {
- # In this mode, we do "nm <foo> | c++filt"
- $cppfilt_flag = " | $cppfilt";
- };
- my $flatten_flag = "";
- if (system("$nm -f $image >/dev/null 2>&1") == 0) {
- $flatten_flag = "-f";
- }
-
- # Finally, in the case $imagie isn't a debug library, we try again with
- # -D to at least get *exported* symbols. If we can't use --demangle,
- # we use c++filt instead, if it exists on this system.
- my @nm_commands = ("$nm -n $flatten_flag $demangle_flag" .
- " $image 2>/dev/null $cppfilt_flag",
- "$nm -D -n $flatten_flag $demangle_flag" .
- " $image 2>/dev/null $cppfilt_flag",
- # 6nm is for Go binaries
- "6nm $image 2>/dev/null | sort");
-
- # If the executable is an MS Windows PDB-format executable, we'll
- # have set up obj_tool_map("nm_pdb"). In this case, we actually
- # want to use both unix nm and windows-specific nm_pdb, since
- # PDB-format executables can apparently include dwarf .o files.
- if (exists $obj_tool_map{"nm_pdb"}) {
- my $nm_pdb = $obj_tool_map{"nm_pdb"};
- push(@nm_commands, "$nm_pdb --demangle $image 2>/dev/null");
- }
-
- foreach my $nm_command (@nm_commands) {
- my $symbol_table = GetProcedureBoundariesViaNm($nm_command, $regexp);
- return $symbol_table if (%{$symbol_table});
- }
- my $symbol_table = {};
- return $symbol_table;
-}
-
-
-# The test vectors for AddressAdd/Sub/Inc are 8-16-nibble hex strings.
-# To make them more readable, we add underscores at interesting places.
-# This routine removes the underscores, producing the canonical representation
-# used by pprof to represent addresses, particularly in the tested routines.
-sub CanonicalHex {
- my $arg = shift;
- return join '', (split '_',$arg);
-}
-
-
-# Unit test for AddressAdd:
-sub AddressAddUnitTest {
- my $test_data_8 = shift;
- my $test_data_16 = shift;
- my $error_count = 0;
- my $fail_count = 0;
- my $pass_count = 0;
- # print STDERR "AddressAddUnitTest: ", 1+$#{$test_data_8}, " tests\n";
-
- # First a few 8-nibble addresses. Note that this implementation uses
- # plain old arithmetic, so a quick sanity check along with verifying what
- # happens to overflow (we want it to wrap):
- $address_length = 8;
- foreach my $row (@{$test_data_8}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressAdd ($row->[0], $row->[1]);
- if ($sum ne $row->[2]) {
- printf STDERR "ERROR: %s != %s + %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[2];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressAdd 32-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count = $fail_count;
- $fail_count = 0;
- $pass_count = 0;
-
- # Now 16-nibble addresses.
- $address_length = 16;
- foreach my $row (@{$test_data_16}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressAdd (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
- my $expected = join '', (split '_',$row->[2]);
- if ($sum ne CanonicalHex($row->[2])) {
- printf STDERR "ERROR: %s != %s + %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[2];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressAdd 64-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count += $fail_count;
-
- return $error_count;
-}
-
-
-# Unit test for AddressSub:
-sub AddressSubUnitTest {
- my $test_data_8 = shift;
- my $test_data_16 = shift;
- my $error_count = 0;
- my $fail_count = 0;
- my $pass_count = 0;
- # print STDERR "AddressSubUnitTest: ", 1+$#{$test_data_8}, " tests\n";
-
- # First a few 8-nibble addresses. Note that this implementation uses
- # plain old arithmetic, so a quick sanity check along with verifying what
- # happens to overflow (we want it to wrap):
- $address_length = 8;
- foreach my $row (@{$test_data_8}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressSub ($row->[0], $row->[1]);
- if ($sum ne $row->[3]) {
- printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[3];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressSub 32-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count = $fail_count;
- $fail_count = 0;
- $pass_count = 0;
-
- # Now 16-nibble addresses.
- $address_length = 16;
- foreach my $row (@{$test_data_16}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressSub (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
- if ($sum ne CanonicalHex($row->[3])) {
- printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[3];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressSub 64-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count += $fail_count;
-
- return $error_count;
-}
-
-
-# Unit test for AddressInc:
-sub AddressIncUnitTest {
- my $test_data_8 = shift;
- my $test_data_16 = shift;
- my $error_count = 0;
- my $fail_count = 0;
- my $pass_count = 0;
- # print STDERR "AddressIncUnitTest: ", 1+$#{$test_data_8}, " tests\n";
-
- # First a few 8-nibble addresses. Note that this implementation uses
- # plain old arithmetic, so a quick sanity check along with verifying what
- # happens to overflow (we want it to wrap):
- $address_length = 8;
- foreach my $row (@{$test_data_8}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressInc ($row->[0]);
- if ($sum ne $row->[4]) {
- printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum,
- $row->[0], $row->[4];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressInc 32-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count = $fail_count;
- $fail_count = 0;
- $pass_count = 0;
-
- # Now 16-nibble addresses.
- $address_length = 16;
- foreach my $row (@{$test_data_16}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressInc (CanonicalHex($row->[0]));
- if ($sum ne CanonicalHex($row->[4])) {
- printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum,
- $row->[0], $row->[4];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressInc 64-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count += $fail_count;
-
- return $error_count;
-}
-
-
-# Driver for unit tests.
-# Currently just the address add/subtract/increment routines for 64-bit.
-sub RunUnitTests {
- my $error_count = 0;
-
- # This is a list of tuples [a, b, a+b, a-b, a+1]
- my $unit_test_data_8 = [
- [qw(aaaaaaaa 50505050 fafafafa 5a5a5a5a aaaaaaab)],
- [qw(50505050 aaaaaaaa fafafafa a5a5a5a6 50505051)],
- [qw(ffffffff aaaaaaaa aaaaaaa9 55555555 00000000)],
- [qw(00000001 ffffffff 00000000 00000002 00000002)],
- [qw(00000001 fffffff0 fffffff1 00000011 00000002)],
- ];
- my $unit_test_data_16 = [
- # The implementation handles data in 7-nibble chunks, so those are the
- # interesting boundaries.
- [qw(aaaaaaaa 50505050
- 00_000000f_afafafa 00_0000005_a5a5a5a 00_000000a_aaaaaab)],
- [qw(50505050 aaaaaaaa
- 00_000000f_afafafa ff_ffffffa_5a5a5a6 00_0000005_0505051)],
- [qw(ffffffff aaaaaaaa
- 00_000001a_aaaaaa9 00_0000005_5555555 00_0000010_0000000)],
- [qw(00000001 ffffffff
- 00_0000010_0000000 ff_ffffff0_0000002 00_0000000_0000002)],
- [qw(00000001 fffffff0
- 00_000000f_ffffff1 ff_ffffff0_0000011 00_0000000_0000002)],
-
- [qw(00_a00000a_aaaaaaa 50505050
- 00_a00000f_afafafa 00_a000005_a5a5a5a 00_a00000a_aaaaaab)],
- [qw(0f_fff0005_0505050 aaaaaaaa
- 0f_fff000f_afafafa 0f_ffefffa_5a5a5a6 0f_fff0005_0505051)],
- [qw(00_000000f_fffffff 01_800000a_aaaaaaa
- 01_800001a_aaaaaa9 fe_8000005_5555555 00_0000010_0000000)],
- [qw(00_0000000_0000001 ff_fffffff_fffffff
- 00_0000000_0000000 00_0000000_0000002 00_0000000_0000002)],
- [qw(00_0000000_0000001 ff_fffffff_ffffff0
- ff_fffffff_ffffff1 00_0000000_0000011 00_0000000_0000002)],
- ];
-
- $error_count += AddressAddUnitTest($unit_test_data_8, $unit_test_data_16);
- $error_count += AddressSubUnitTest($unit_test_data_8, $unit_test_data_16);
- $error_count += AddressIncUnitTest($unit_test_data_8, $unit_test_data_16);
- if ($error_count > 0) {
- print STDERR $error_count, " errors: FAILED\n";
- } else {
- print STDERR "PASS\n";
- }
- exit ($error_count);
-}
diff --git a/src/cmd/prof/main.c b/src/cmd/prof/main.c
deleted file mode 100644
index f36759cd3..000000000
--- a/src/cmd/prof/main.c
+++ /dev/null
@@ -1,895 +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 <u.h>
-#include <time.h>
-#include <libc.h>
-#include <bio.h>
-#include <ctype.h>
-
-#define Ureg Ureg_amd64
- #include <ureg_amd64.h>
-#undef Ureg
-#define Ureg Ureg_x86
- #include <ureg_x86.h>
-#undef Ureg
-#include <mach.h>
-
-char* file = "6.out";
-static Fhdr fhdr;
-int have_syms;
-int fd;
-struct Ureg_amd64 ureg_amd64;
-struct Ureg_x86 ureg_x86;
-int total_sec = 0;
-int delta_msec = 100;
-int nsample;
-int nsamplethread;
-
-// pprof data, stored as sequences of N followed by N PC values.
-// See http://code.google.com/p/google-perftools .
-uvlong *ppdata; // traces
-Biobuf* pproffd; // file descriptor to write trace info
-long ppstart; // start position of current trace
-long nppdata; // length of data
-long ppalloc; // size of allocated data
-char ppmapdata[10*1024]; // the map information for the output file
-
-// output formats
-int pprof; // print pprof output to named file
-int functions; // print functions
-int histograms; // print histograms
-int linenums; // print file and line numbers rather than function names
-int registers; // print registers
-int stacks; // print stack traces
-
-int pid; // main process pid
-
-int nthread; // number of threads
-int thread[32]; // thread pids
-Map *map[32]; // thread maps
-
-void
-Usage(void)
-{
- fprint(2, "Usage: prof -p pid [-t total_secs] [-d delta_msec]\n");
- fprint(2, " prof [-t total_secs] [-d delta_msec] 6.out args ...\n");
- fprint(2, "\tformats (default -h):\n");
- fprint(2, "\t\t-P file.prof: write [c]pprof output to file.prof\n");
- fprint(2, "\t\t-h: histograms\n");
- fprint(2, "\t\t-f: dynamic functions\n");
- fprint(2, "\t\t-l: dynamic file and line numbers\n");
- fprint(2, "\t\t-r: dynamic registers\n");
- fprint(2, "\t\t-s: dynamic function stack traces\n");
- fprint(2, "\t\t-hs: include stack info in histograms\n");
- exit(2);
-}
-
-typedef struct PC PC;
-struct PC {
- uvlong pc;
- uvlong callerpc;
- unsigned int count;
- PC* next;
-};
-
-enum {
- Ncounters = 256
-};
-
-PC *counters[Ncounters];
-
-// Set up by setarch() to make most of the code architecture-independent.
-typedef struct Arch Arch;
-struct Arch {
- char* name;
- void (*regprint)(void);
- int (*getregs)(Map*);
- int (*getPC)(Map*);
- int (*getSP)(Map*);
- uvlong (*uregPC)(void);
- uvlong (*uregSP)(void);
- void (*ppword)(uvlong w);
-};
-
-void
-amd64_regprint(void)
-{
- fprint(2, "ax\t0x%llux\n", ureg_amd64.ax);
- fprint(2, "bx\t0x%llux\n", ureg_amd64.bx);
- fprint(2, "cx\t0x%llux\n", ureg_amd64.cx);
- fprint(2, "dx\t0x%llux\n", ureg_amd64.dx);
- fprint(2, "si\t0x%llux\n", ureg_amd64.si);
- fprint(2, "di\t0x%llux\n", ureg_amd64.di);
- fprint(2, "bp\t0x%llux\n", ureg_amd64.bp);
- fprint(2, "r8\t0x%llux\n", ureg_amd64.r8);
- fprint(2, "r9\t0x%llux\n", ureg_amd64.r9);
- fprint(2, "r10\t0x%llux\n", ureg_amd64.r10);
- fprint(2, "r11\t0x%llux\n", ureg_amd64.r11);
- fprint(2, "r12\t0x%llux\n", ureg_amd64.r12);
- fprint(2, "r13\t0x%llux\n", ureg_amd64.r13);
- fprint(2, "r14\t0x%llux\n", ureg_amd64.r14);
- fprint(2, "r15\t0x%llux\n", ureg_amd64.r15);
- fprint(2, "ds\t0x%llux\n", ureg_amd64.ds);
- fprint(2, "es\t0x%llux\n", ureg_amd64.es);
- fprint(2, "fs\t0x%llux\n", ureg_amd64.fs);
- fprint(2, "gs\t0x%llux\n", ureg_amd64.gs);
- fprint(2, "type\t0x%llux\n", ureg_amd64.type);
- fprint(2, "error\t0x%llux\n", ureg_amd64.error);
- fprint(2, "pc\t0x%llux\n", ureg_amd64.ip);
- fprint(2, "cs\t0x%llux\n", ureg_amd64.cs);
- fprint(2, "flags\t0x%llux\n", ureg_amd64.flags);
- fprint(2, "sp\t0x%llux\n", ureg_amd64.sp);
- fprint(2, "ss\t0x%llux\n", ureg_amd64.ss);
-}
-
-int
-amd64_getregs(Map *map)
-{
- int i;
- union {
- uvlong regs[1];
- struct Ureg_amd64 ureg;
- } u;
-
- for(i = 0; i < sizeof ureg_amd64; i+=8) {
- if(get8(map, (uvlong)i, &u.regs[i/8]) < 0)
- return -1;
- }
- ureg_amd64 = u.ureg;
- return 0;
-}
-
-int
-amd64_getPC(Map *map)
-{
- uvlong x;
- int r;
-
- r = get8(map, offsetof(struct Ureg_amd64, ip), &x);
- ureg_amd64.ip = x;
- return r;
-}
-
-int
-amd64_getSP(Map *map)
-{
- uvlong x;
- int r;
-
- r = get8(map, offsetof(struct Ureg_amd64, sp), &x);
- ureg_amd64.sp = x;
- return r;
-}
-
-uvlong
-amd64_uregPC(void)
-{
- return ureg_amd64.ip;
-}
-
-uvlong
-amd64_uregSP(void) {
- return ureg_amd64.sp;
-}
-
-void
-amd64_ppword(uvlong w)
-{
- uchar buf[8];
-
- buf[0] = w;
- buf[1] = w >> 8;
- buf[2] = w >> 16;
- buf[3] = w >> 24;
- buf[4] = w >> 32;
- buf[5] = w >> 40;
- buf[6] = w >> 48;
- buf[7] = w >> 56;
- Bwrite(pproffd, buf, 8);
-}
-
-void
-x86_regprint(void)
-{
- fprint(2, "ax\t0x%ux\n", ureg_x86.ax);
- fprint(2, "bx\t0x%ux\n", ureg_x86.bx);
- fprint(2, "cx\t0x%ux\n", ureg_x86.cx);
- fprint(2, "dx\t0x%ux\n", ureg_x86.dx);
- fprint(2, "si\t0x%ux\n", ureg_x86.si);
- fprint(2, "di\t0x%ux\n", ureg_x86.di);
- fprint(2, "bp\t0x%ux\n", ureg_x86.bp);
- fprint(2, "ds\t0x%ux\n", ureg_x86.ds);
- fprint(2, "es\t0x%ux\n", ureg_x86.es);
- fprint(2, "fs\t0x%ux\n", ureg_x86.fs);
- fprint(2, "gs\t0x%ux\n", ureg_x86.gs);
- fprint(2, "cs\t0x%ux\n", ureg_x86.cs);
- fprint(2, "flags\t0x%ux\n", ureg_x86.flags);
- fprint(2, "pc\t0x%ux\n", ureg_x86.pc);
- fprint(2, "sp\t0x%ux\n", ureg_x86.sp);
- fprint(2, "ss\t0x%ux\n", ureg_x86.ss);
-}
-
-int
-x86_getregs(Map *map)
-{
- int i;
-
- for(i = 0; i < sizeof ureg_x86; i+=4) {
- if(get4(map, (uvlong)i, &((uint32*)&ureg_x86)[i/4]) < 0)
- return -1;
- }
- return 0;
-}
-
-int
-x86_getPC(Map* map)
-{
- return get4(map, offsetof(struct Ureg_x86, pc), &ureg_x86.pc);
-}
-
-int
-x86_getSP(Map* map)
-{
- return get4(map, offsetof(struct Ureg_x86, sp), &ureg_x86.sp);
-}
-
-uvlong
-x86_uregPC(void)
-{
- return (uvlong)ureg_x86.pc;
-}
-
-uvlong
-x86_uregSP(void)
-{
- return (uvlong)ureg_x86.sp;
-}
-
-void
-x86_ppword(uvlong w)
-{
- uchar buf[4];
-
- buf[0] = w;
- buf[1] = w >> 8;
- buf[2] = w >> 16;
- buf[3] = w >> 24;
- Bwrite(pproffd, buf, 4);
-}
-
-Arch archtab[] = {
- {
- "amd64",
- amd64_regprint,
- amd64_getregs,
- amd64_getPC,
- amd64_getSP,
- amd64_uregPC,
- amd64_uregSP,
- amd64_ppword,
- },
- {
- "386",
- x86_regprint,
- x86_getregs,
- x86_getPC,
- x86_getSP,
- x86_uregPC,
- x86_uregSP,
- x86_ppword,
- },
- {
- nil
- }
-};
-
-Arch *arch;
-
-int
-setarch(void)
-{
- int i;
-
- if(mach != nil) {
- for(i = 0; archtab[i].name != nil; i++) {
- if (strcmp(mach->name, archtab[i].name) == 0) {
- arch = &archtab[i];
- return 0;
- }
- }
- }
- return -1;
-}
-
-int
-getthreads(void)
-{
- int i, j, curn, found;
- Map *curmap[nelem(map)];
- int curthread[nelem(map)];
- static int complained = 0;
-
- curn = procthreadpids(pid, curthread, nelem(curthread));
- if(curn <= 0)
- return curn;
-
- if(curn > nelem(map)) {
- if(complained == 0) {
- fprint(2, "prof: too many threads; limiting to %d\n", nthread, nelem(map));
- complained = 1;
- }
- curn = nelem(map);
- }
- if(curn == nthread && memcmp(thread, curthread, curn*sizeof(*thread)) == 0)
- return curn; // no changes
-
- // Number of threads has changed (might be the init case).
- // A bit expensive but rare enough not to bother being clever.
- for(i = 0; i < curn; i++) {
- found = 0;
- for(j = 0; j < nthread; j++) {
- if(curthread[i] == thread[j]) {
- found = 1;
- curmap[i] = map[j];
- map[j] = nil;
- break;
- }
- }
- if(found)
- continue;
-
- // map new thread
- curmap[i] = attachproc(curthread[i], &fhdr);
- if(curmap[i] == nil) {
- fprint(2, "prof: can't attach to %d: %r\n", curthread[i]);
- return -1;
- }
- }
-
- for(j = 0; j < nthread; j++)
- if(map[j] != nil)
- detachproc(map[j]);
-
- nthread = curn;
- memmove(thread, curthread, nthread*sizeof thread[0]);
- memmove(map, curmap, sizeof map);
- return nthread;
-}
-
-int
-sample(Map *map)
-{
- static int n;
-
- n++;
- if(registers) {
- if(arch->getregs(map) < 0)
- goto bad;
- } else {
- // we need only two registers
- if(arch->getPC(map) < 0)
- goto bad;
- if(arch->getSP(map) < 0)
- goto bad;
- }
- return 1;
-bad:
- if(n == 1)
- fprint(2, "prof: can't read registers: %r\n");
- return 0;
-}
-
-void
-addtohistogram(uvlong pc, uvlong callerpc, uvlong sp)
-{
- int h;
- PC *x;
-
- h = (pc + callerpc*101) % Ncounters;
- for(x = counters[h]; x != NULL; x = x->next) {
- if(x->pc == pc && x->callerpc == callerpc) {
- x->count++;
- return;
- }
- }
- x = malloc(sizeof(PC));
- x->pc = pc;
- x->callerpc = callerpc;
- x->count = 1;
- x->next = counters[h];
- counters[h] = x;
-}
-
-void
-addppword(uvlong pc)
-{
- if(pc == 0) {
- return;
- }
- if(nppdata == ppalloc) {
- ppalloc = (1000+nppdata)*2;
- ppdata = realloc(ppdata, ppalloc * sizeof ppdata[0]);
- if(ppdata == nil) {
- fprint(2, "prof: realloc failed: %r\n");
- exit(2);
- }
- }
- ppdata[nppdata++] = pc;
-}
-
-void
-startpptrace()
-{
- ppstart = nppdata;
- addppword(~0);
-}
-
-void
-endpptrace()
-{
- ppdata[ppstart] = nppdata-ppstart-1;
-}
-
-uvlong nextpc;
-
-void
-xptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
-{
- char buf[1024];
- if(sym == nil){
- fprint(2, "syms\n");
- return;
- }
- if(histograms)
- addtohistogram(nextpc, pc, sp);
- if(!histograms || stacks > 1 || pprof) {
- if(nextpc == 0)
- nextpc = sym->value;
- if(stacks){
- fprint(2, "%s(", sym->name);
- fprint(2, ")");
- if(nextpc != sym->value)
- fprint(2, "+%#llux ", nextpc - sym->value);
- if(have_syms && linenums && fileline(buf, sizeof buf, pc)) {
- fprint(2, " %s", buf);
- }
- fprint(2, "\n");
- }
- if (pprof) {
- addppword(nextpc);
- }
- }
- nextpc = pc;
-}
-
-void
-stacktracepcsp(Map *map, uvlong pc, uvlong sp)
-{
- nextpc = pc;
- if(pprof){
- startpptrace();
- }
- if(machdata->ctrace==nil)
- fprint(2, "no machdata->ctrace\n");
- else if(machdata->ctrace(map, pc, sp, 0, xptrace) <= 0)
- fprint(2, "no stack frame: pc=%#p sp=%#p\n", pc, sp);
- else {
- addtohistogram(nextpc, 0, sp);
- if(stacks)
- fprint(2, "\n");
- }
- if(pprof){
- endpptrace();
- }
-}
-
-void
-printpc(Map *map, uvlong pc, uvlong sp)
-{
- char buf[1024];
- if(registers)
- arch->regprint();
- if(have_syms > 0 && linenums && fileline(buf, sizeof buf, pc))
- fprint(2, "%s\n", buf);
- if(have_syms > 0 && functions) {
- symoff(buf, sizeof(buf), pc, CANY);
- fprint(2, "%s\n", buf);
- }
- if(stacks || pprof){
- stacktracepcsp(map, pc, sp);
- }
- else if(histograms){
- addtohistogram(pc, 0, sp);
- }
-}
-
-void
-ppmaps(void)
-{
- int fd, n;
- char tmp[100];
- Seg *seg;
-
- // If it's Linux, the info is in /proc/$pid/maps
- snprint(tmp, sizeof tmp, "/proc/%d/maps", pid);
- fd = open(tmp, 0);
- if(fd >= 0) {
- n = read(fd, ppmapdata, sizeof ppmapdata - 1);
- close(fd);
- if(n < 0) {
- fprint(2, "prof: can't read %s: %r\n", tmp);
- exit(2);
- }
- ppmapdata[n] = 0;
- return;
- }
-
- // It's probably a mac. Synthesize an entry for the text file.
- // The register segment may come first but it has a zero offset, so grab the first non-zero offset segment.
- for(n = 0; n < 3; n++){
- seg = &map[0]->seg[n];
- if(seg->b == 0) {
- continue;
- }
- snprint(ppmapdata, sizeof ppmapdata,
- "%.16x-%.16x r-xp %d 00:00 34968549 %s\n",
- seg->b, seg->e, seg->f, "/home/r/6.out"
- );
- return;
- }
- fprint(2, "prof: no text segment in maps for %s\n", file);
- exit(2);
-}
-
-void
-samples(void)
-{
- int i, pid, msec;
- struct timespec req;
- int getmaps;
-
- req.tv_sec = delta_msec/1000;
- req.tv_nsec = 1000000*(delta_msec % 1000);
- getmaps = 0;
- if(pprof)
- getmaps= 1;
- for(msec = 0; total_sec <= 0 || msec < 1000*total_sec; msec += delta_msec) {
- nsample++;
- nsamplethread += nthread;
- for(i = 0; i < nthread; i++) {
- pid = thread[i];
- if(ctlproc(pid, "stop") < 0)
- return;
- if(!sample(map[i])) {
- ctlproc(pid, "start");
- return;
- }
- printpc(map[i], arch->uregPC(), arch->uregSP());
- ctlproc(pid, "start");
- }
- nanosleep(&req, NULL);
- getthreads();
- if(nthread == 0)
- break;
- if(getmaps) {
- getmaps = 0;
- ppmaps();
- }
- }
-}
-
-typedef struct Func Func;
-struct Func
-{
- Func *next;
- Symbol s;
- uint onstack;
- uint leaf;
-};
-
-Func *func[257];
-int nfunc;
-
-Func*
-findfunc(uvlong pc)
-{
- Func *f;
- uint h;
- Symbol s;
-
- if(pc == 0)
- return nil;
-
- if(!findsym(pc, CTEXT, &s))
- return nil;
-
- h = s.value % nelem(func);
- for(f = func[h]; f != NULL; f = f->next)
- if(f->s.value == s.value)
- return f;
-
- f = malloc(sizeof *f);
- memset(f, 0, sizeof *f);
- f->s = s;
- f->next = func[h];
- func[h] = f;
- nfunc++;
- return f;
-}
-
-int
-compareleaf(const void *va, const void *vb)
-{
- Func *a, *b;
-
- a = *(Func**)va;
- b = *(Func**)vb;
- if(a->leaf != b->leaf)
- return b->leaf - a->leaf;
- if(a->onstack != b->onstack)
- return b->onstack - a->onstack;
- return strcmp(a->s.name, b->s.name);
-}
-
-void
-dumphistogram()
-{
- int i, h, n;
- PC *x;
- Func *f, **ff;
-
- if(!histograms)
- return;
-
- // assign counts to functions.
- for(h = 0; h < Ncounters; h++) {
- for(x = counters[h]; x != NULL; x = x->next) {
- f = findfunc(x->pc);
- if(f) {
- f->onstack += x->count;
- f->leaf += x->count;
- }
- f = findfunc(x->callerpc);
- if(f)
- f->leaf -= x->count;
- }
- }
-
- // build array
- ff = malloc(nfunc*sizeof ff[0]);
- n = 0;
- for(h = 0; h < nelem(func); h++)
- for(f = func[h]; f != NULL; f = f->next)
- ff[n++] = f;
-
- // sort by leaf counts
- qsort(ff, nfunc, sizeof ff[0], compareleaf);
-
- // print.
- fprint(2, "%d samples (avg %.1g threads)\n", nsample, (double)nsamplethread/nsample);
- for(i = 0; i < nfunc; i++) {
- f = ff[i];
- fprint(2, "%6.2f%%\t", 100.0*(double)f->leaf/nsample);
- if(stacks)
- fprint(2, "%6.2f%%\t", 100.0*(double)f->onstack/nsample);
- fprint(2, "%s\n", f->s.name);
- }
-}
-
-typedef struct Trace Trace;
-struct Trace {
- int count;
- int npc;
- uvlong *pc;
- Trace *next;
-};
-
-void
-dumppprof()
-{
- uvlong i, n, *p, *e;
- int ntrace;
- Trace *trace, *tp, *up, *prev;
-
- if(!pprof)
- return;
- e = ppdata + nppdata;
- // Create list of traces. First, count the traces
- ntrace = 0;
- for(p = ppdata; p < e;) {
- n = *p++;
- p += n;
- if(n == 0)
- continue;
- ntrace++;
- }
- if(ntrace <= 0)
- return;
- // Allocate and link the traces together.
- trace = malloc(ntrace * sizeof(Trace));
- tp = trace;
- for(p = ppdata; p < e;) {
- n = *p++;
- if(n == 0)
- continue;
- tp->count = 1;
- tp->npc = n;
- tp->pc = p;
- tp->next = tp+1;
- tp++;
- p += n;
- }
- trace[ntrace-1].next = nil;
- // Eliminate duplicates. Lousy algorithm, although not as bad as it looks because
- // the list collapses fast.
- for(tp = trace; tp != nil; tp = tp->next) {
- prev = tp;
- for(up = tp->next; up != nil; up = up->next) {
- if(up->npc == tp->npc && memcmp(up->pc, tp->pc, up->npc*sizeof up->pc[0]) == 0) {
- tp->count++;
- prev->next = up->next;
- } else {
- prev = up;
- }
- }
- }
- // Write file.
- // See http://code.google.com/p/google-perftools/source/browse/trunk/doc/cpuprofile-fileformat.html
- // 1) Header
- arch->ppword(0); // must be zero
- arch->ppword(3); // 3 words follow in header
- arch->ppword(0); // must be zero
- arch->ppword(delta_msec * 1000); // sampling period in microseconds
- arch->ppword(0); // must be zero (padding)
- // 2) One record for each trace.
- for(tp = trace; tp != nil; tp = tp->next) {
- arch->ppword(tp->count);
- arch->ppword(tp->npc);
- for(i = 0; i < tp->npc; i++) {
- arch->ppword(tp->pc[i]);
- }
- }
- // 3) Binary trailer
- arch->ppword(0); // must be zero
- arch->ppword(1); // must be one
- arch->ppword(0); // must be zero
- // 4) Mapped objects.
- Bwrite(pproffd, ppmapdata, strlen(ppmapdata));
- // 5) That's it.
- Bterm(pproffd);
-}
-
-int
-startprocess(char **argv)
-{
- int pid;
-
- if((pid = fork()) == 0) {
- pid = getpid();
- if(ctlproc(pid, "hang") < 0){
- fprint(2, "prof: child process could not hang\n");
- exits(0);
- }
- execv(argv[0], argv);
- fprint(2, "prof: could not exec %s: %r\n", argv[0]);
- exits(0);
- }
-
- if(pid == -1) {
- fprint(2, "prof: could not fork\n");
- exit(1);
- }
- if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0) {
- fprint(2, "prof: could not attach to child process: %r\n");
- exit(1);
- }
- return pid;
-}
-
-void
-detach(void)
-{
- int i;
-
- for(i = 0; i < nthread; i++)
- detachproc(map[i]);
-}
-
-int
-main(int argc, char *argv[])
-{
- int i;
- char *ppfile;
-
- ARGBEGIN{
- case 'P':
- pprof =1;
- ppfile = EARGF(Usage());
- pproffd = Bopen(ppfile, OWRITE);
- if(pproffd == nil) {
- fprint(2, "prof: cannot open %s: %r\n", ppfile);
- exit(2);
- }
- break;
- case 'd':
- delta_msec = atoi(EARGF(Usage()));
- break;
- case 't':
- total_sec = atoi(EARGF(Usage()));
- break;
- case 'p':
- pid = atoi(EARGF(Usage()));
- break;
- case 'f':
- functions = 1;
- break;
- case 'h':
- histograms = 1;
- break;
- case 'l':
- linenums = 1;
- break;
- case 'r':
- registers = 1;
- break;
- case 's':
- stacks++;
- break;
- default:
- Usage();
- }ARGEND
- if(pid <= 0 && argc == 0)
- Usage();
- if(functions+linenums+registers+stacks+pprof == 0)
- histograms = 1;
- if(!machbyname("amd64")) {
- fprint(2, "prof: no amd64 support\n", pid);
- exit(1);
- }
- if(argc > 0)
- file = argv[0];
- else if(pid) {
- file = proctextfile(pid);
- if (file == NULL) {
- fprint(2, "prof: can't find file for pid %d: %r\n", pid);
- fprint(2, "prof: on Darwin, need to provide file name explicitly\n");
- exit(1);
- }
- }
- fd = open(file, 0);
- if(fd < 0) {
- fprint(2, "prof: can't open %s: %r\n", file);
- exit(1);
- }
- if(crackhdr(fd, &fhdr)) {
- have_syms = syminit(fd, &fhdr);
- if(!have_syms) {
- fprint(2, "prof: no symbols for %s: %r\n", file);
- }
- } else {
- fprint(2, "prof: crack header for %s: %r\n", file);
- exit(1);
- }
- if(pid <= 0)
- pid = startprocess(argv);
- attachproc(pid, &fhdr); // initializes thread list
- if(setarch() < 0) {
- detach();
- fprint(2, "prof: can't identify binary architecture for pid %d\n", pid);
- exit(1);
- }
- if(getthreads() <= 0) {
- detach();
- fprint(2, "prof: can't find threads for pid %d\n", pid);
- exit(1);
- }
- for(i = 0; i < nthread; i++)
- ctlproc(thread[i], "start");
- samples();
- detach();
- dumphistogram();
- dumppprof();
- exit(0);
-}