diff options
| author | Keith Randall <khr@golang.org> | 2015-05-28 13:49:20 -0700 |
|---|---|---|
| committer | Keith Randall <khr@golang.org> | 2015-05-28 13:51:18 -0700 |
| commit | 067e8dfd82163ddcbde248dbe5a1187a417e5d36 (patch) | |
| tree | 7bfb46b901d03498c7739c92bec21d81d3a2c485 /src/cmd | |
| parent | 247786c1745abc0c7185f7c15ca256edf68ed6d6 (diff) | |
| parent | ccc037699e2966b7c79ba84c67471cef5e67a3b8 (diff) | |
| download | go-067e8dfd82163ddcbde248dbe5a1187a417e5d36.tar.xz | |
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
Semi-regular merge of tip to dev.ssa.
Complicated a bit by the move of cmd/internal/* to cmd/compile/internal/*.
Change-Id: I1c66d3c29bb95cce4a53c5a3476373aa5245303d
Diffstat (limited to 'src/cmd')
| -rw-r--r-- | src/cmd/6l/z.go | 1 | ||||
| -rw-r--r-- | src/cmd/asm/internal/asm/asm.go | 5 | ||||
| -rw-r--r-- | src/cmd/asm/internal/flags/flags.go | 4 | ||||
| -rw-r--r-- | src/cmd/asm/internal/lex/input.go | 3 | ||||
| -rw-r--r-- | src/cmd/asm/internal/lex/tokenizer.go | 6 | ||||
| -rw-r--r-- | src/cmd/asm/main.go | 2 | ||||
| -rw-r--r-- | src/cmd/cgo/out.go | 15 | ||||
| -rw-r--r-- | src/cmd/compile/internal/amd64/cgen.go (renamed from src/cmd/6g/cgen.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/amd64/galign.go (renamed from src/cmd/6g/galign.go) | 7 | ||||
| -rw-r--r-- | src/cmd/compile/internal/amd64/ggen.go (renamed from src/cmd/6g/ggen.go) | 18 | ||||
| -rw-r--r-- | src/cmd/compile/internal/amd64/gsubr.go (renamed from src/cmd/6g/gsubr.go) | 82 | ||||
| -rw-r--r-- | src/cmd/compile/internal/amd64/peep.go (renamed from src/cmd/6g/peep.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/amd64/prog.go (renamed from src/cmd/6g/prog.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/amd64/reg.go (renamed from src/cmd/6g/reg.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm/cgen.go (renamed from src/cmd/5g/cgen.go) | 26 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm/cgen64.go (renamed from src/cmd/5g/cgen64.go) | 10 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm/galign.go (renamed from src/cmd/5g/galign.go) | 7 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm/ggen.go (renamed from src/cmd/5g/ggen.go) | 36 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm/gsubr.go (renamed from src/cmd/5g/gsubr.go) | 20 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm/peep.go (renamed from src/cmd/5g/peep.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm/prog.go (renamed from src/cmd/5g/prog.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm/reg.go (renamed from src/cmd/5g/reg.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm64/cgen.go (renamed from src/cmd/7g/cgen.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm64/galign.go (renamed from src/cmd/7g/galign.go) | 7 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm64/ggen.go (renamed from src/cmd/7g/ggen.go) | 12 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm64/gsubr.go (renamed from src/cmd/7g/gsubr.go) | 51 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm64/peep.go (renamed from src/cmd/7g/peep.go) | 8 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm64/prog.go (renamed from src/cmd/7g/prog.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/arm64/reg.go (renamed from src/cmd/7g/reg.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/accuracy_string.go (renamed from src/cmd/internal/gc/big/accuracy_string.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/arith.go (renamed from src/cmd/internal/gc/big/arith.go) | 1 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/arith_decl.go (renamed from src/cmd/internal/gc/big/arith_decl.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/arith_test.go (renamed from src/cmd/internal/gc/big/arith_test.go) | 1 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/bits_test.go (renamed from src/cmd/internal/gc/big/bits_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/calibrate_test.go (renamed from src/cmd/internal/gc/big/calibrate_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/decimal.go (renamed from src/cmd/internal/gc/big/decimal.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/decimal_test.go (renamed from src/cmd/internal/gc/big/decimal_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/example_test.go (renamed from src/cmd/internal/gc/big/example_test.go) | 2 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/float.go (renamed from src/cmd/internal/gc/big/float.go) | 151 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/float_test.go (renamed from src/cmd/internal/gc/big/float_test.go) | 185 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/floatconv.go (renamed from src/cmd/internal/gc/big/floatconv.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/floatconv_test.go (renamed from src/cmd/internal/gc/big/floatconv_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/floatexample_test.go (renamed from src/cmd/internal/gc/big/floatexample_test.go) | 2 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/ftoa.go (renamed from src/cmd/internal/gc/big/ftoa.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/gcd_test.go (renamed from src/cmd/internal/gc/big/gcd_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/hilbert_test.go (renamed from src/cmd/internal/gc/big/hilbert_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/int.go (renamed from src/cmd/internal/gc/big/int.go) | 118 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/int_test.go (renamed from src/cmd/internal/gc/big/int_test.go) | 138 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/intconv.go (renamed from src/cmd/internal/gc/big/intconv.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/intconv_test.go (renamed from src/cmd/internal/gc/big/intconv_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/nat.go (renamed from src/cmd/internal/gc/big/nat.go) | 121 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/nat_test.go (renamed from src/cmd/internal/gc/big/nat_test.go) | 61 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/natconv.go (renamed from src/cmd/internal/gc/big/natconv.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/natconv_test.go (renamed from src/cmd/internal/gc/big/natconv_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/rat.go (renamed from src/cmd/internal/gc/big/rat.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/rat_test.go (renamed from src/cmd/internal/gc/big/rat_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/ratconv.go (renamed from src/cmd/internal/gc/big/ratconv.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/ratconv_test.go (renamed from src/cmd/internal/gc/big/ratconv_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/big/roundingmode_string.go (renamed from src/cmd/internal/gc/big/roundingmode_string.go) | 0 | ||||
| -rwxr-xr-x | src/cmd/compile/internal/big/vendor.bash (renamed from src/cmd/internal/gc/big/vendor.bash) | 8 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/align.go (renamed from src/cmd/internal/gc/align.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/builtin.go (renamed from src/cmd/internal/gc/builtin.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/builtin/runtime.go (renamed from src/cmd/internal/gc/builtin/runtime.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/builtin/unsafe.go (renamed from src/cmd/internal/gc/builtin/unsafe.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/bv.go (renamed from src/cmd/internal/gc/bv.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/cgen.go (renamed from src/cmd/internal/gc/cgen.go) | 927 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/closure.go (renamed from src/cmd/internal/gc/closure.go) | 76 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/const.go (renamed from src/cmd/internal/gc/const.go) | 282 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/cplx.go (renamed from src/cmd/internal/gc/cplx.go) | 6 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/dcl.go (renamed from src/cmd/internal/gc/dcl.go) | 47 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/esc.go (renamed from src/cmd/internal/gc/esc.go) | 198 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/export.go (renamed from src/cmd/internal/gc/export.go) | 2 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/fmt.go (renamed from src/cmd/internal/gc/fmt.go) | 44 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/gen.go (renamed from src/cmd/internal/gc/gen.go) | 163 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/go.go (renamed from src/cmd/internal/gc/go.go) | 34 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/go.y (renamed from src/cmd/internal/gc/go.y) | 100 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/gsubr.go (renamed from src/cmd/internal/gc/gsubr.go) | 20 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/init.go (renamed from src/cmd/internal/gc/init.go) | 2 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/inl.go (renamed from src/cmd/internal/gc/inl.go) | 22 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/lex.go (renamed from src/cmd/internal/gc/lex.go) | 103 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/mkbuiltin.go (renamed from src/cmd/internal/gc/mkbuiltin.go) | 17 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/mparith2.go (renamed from src/cmd/internal/gc/mparith2.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/mparith3.go (renamed from src/cmd/internal/gc/mparith3.go) | 36 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/obj.go (renamed from src/cmd/internal/gc/obj.go) | 7 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/opnames.go (renamed from src/cmd/internal/gc/opnames.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/order.go (renamed from src/cmd/internal/gc/order.go) | 157 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/pgen.go (renamed from src/cmd/internal/gc/pgen.go) | 25 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/plive.go (renamed from src/cmd/internal/gc/plive.go) | 6 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/popt.go (renamed from src/cmd/internal/gc/popt.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/racewalk.go (renamed from src/cmd/internal/gc/racewalk.go) | 30 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/range.go (renamed from src/cmd/internal/gc/range.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/reflect.go (renamed from src/cmd/internal/gc/reflect.go) | 425 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/reg.go (renamed from src/cmd/internal/gc/reg.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/select.go (renamed from src/cmd/internal/gc/select.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/sinit.go (renamed from src/cmd/internal/gc/sinit.go) | 28 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/ssa.go (renamed from src/cmd/internal/gc/ssa.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/subr.go (renamed from src/cmd/internal/gc/subr.go) | 121 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/swt.go (renamed from src/cmd/internal/gc/swt.go) | 14 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/syntax.go (renamed from src/cmd/internal/gc/syntax.go) | 133 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/type.go (renamed from src/cmd/internal/gc/type.go) | 2 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/typecheck.go (renamed from src/cmd/internal/gc/typecheck.go) | 165 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/unsafe.go (renamed from src/cmd/internal/gc/unsafe.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/util.go (renamed from src/cmd/internal/gc/util.go) | 3 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/walk.go (renamed from src/cmd/internal/gc/walk.go) | 506 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/y.go (renamed from src/cmd/internal/gc/y.go) | 623 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/y.output (renamed from src/cmd/internal/gc/y.output) | 972 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ppc64/cgen.go (renamed from src/cmd/9g/cgen.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ppc64/galign.go (renamed from src/cmd/9g/galign.go) | 7 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ppc64/ggen.go (renamed from src/cmd/9g/ggen.go) | 12 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ppc64/gsubr.go (renamed from src/cmd/9g/gsubr.go) | 80 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ppc64/opt.go (renamed from src/cmd/9g/opt.go) | 2 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ppc64/peep.go (renamed from src/cmd/9g/peep.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ppc64/prog.go (renamed from src/cmd/9g/prog.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ppc64/reg.go (renamed from src/cmd/9g/reg.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/TODO (renamed from src/cmd/internal/ssa/TODO) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/block.go (renamed from src/cmd/internal/ssa/block.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/blockkind_string.go (renamed from src/cmd/internal/ssa/blockkind_string.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/cgen.go (renamed from src/cmd/internal/ssa/cgen.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/check.go (renamed from src/cmd/internal/ssa/check.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/compile.go (renamed from src/cmd/internal/ssa/compile.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/config.go (renamed from src/cmd/internal/ssa/config.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/copyelim.go (renamed from src/cmd/internal/ssa/copyelim.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/critical.go (renamed from src/cmd/internal/ssa/critical.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/cse.go (renamed from src/cmd/internal/ssa/cse.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/deadcode.go (renamed from src/cmd/internal/ssa/deadcode.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/deadcode_test.go (renamed from src/cmd/internal/ssa/deadcode_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/dom.go (renamed from src/cmd/internal/ssa/dom.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/export_test.go (renamed from src/cmd/internal/ssa/export_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/func.go (renamed from src/cmd/internal/ssa/func.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/func_test.go (renamed from src/cmd/internal/ssa/func_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/fuse.go (renamed from src/cmd/internal/ssa/fuse.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/generic.go (renamed from src/cmd/internal/ssa/generic.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/id.go (renamed from src/cmd/internal/ssa/id.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/layout.go (renamed from src/cmd/internal/ssa/layout.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/location.go (renamed from src/cmd/internal/ssa/location.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/lower.go (renamed from src/cmd/internal/ssa/lower.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/lowerAmd64.go (renamed from src/cmd/internal/ssa/lowerAmd64.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/op.go (renamed from src/cmd/internal/ssa/op.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/op_string.go (renamed from src/cmd/internal/ssa/op_string.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/opamd64.go (renamed from src/cmd/internal/ssa/opamd64.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/opt.go (renamed from src/cmd/internal/ssa/opt.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/phielim.go (renamed from src/cmd/internal/ssa/phielim.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/print.go (renamed from src/cmd/internal/ssa/print.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/regalloc.go (renamed from src/cmd/internal/ssa/regalloc.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/rewrite.go (renamed from src/cmd/internal/ssa/rewrite.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/rulegen/generic.rules (renamed from src/cmd/internal/ssa/rulegen/generic.rules) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules (renamed from src/cmd/internal/ssa/rulegen/lower_amd64.rules) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/rulegen/rulegen.go (renamed from src/cmd/internal/ssa/rulegen/rulegen.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/schedule.go (renamed from src/cmd/internal/ssa/schedule.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/sparseset.go (renamed from src/cmd/internal/ssa/sparseset.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/stackalloc.go (renamed from src/cmd/internal/ssa/stackalloc.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/type.go (renamed from src/cmd/internal/ssa/type.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/value.go (renamed from src/cmd/internal/ssa/value.go) | 0 | ||||
| -rw-r--r-- | src/cmd/compile/internal/x86/cgen.go (renamed from src/cmd/8g/cgen.go) | 6 | ||||
| -rw-r--r-- | src/cmd/compile/internal/x86/cgen64.go (renamed from src/cmd/8g/cgen64.go) | 15 | ||||
| -rw-r--r-- | src/cmd/compile/internal/x86/galign.go (renamed from src/cmd/8g/galign.go) | 7 | ||||
| -rw-r--r-- | src/cmd/compile/internal/x86/ggen.go (renamed from src/cmd/8g/ggen.go) | 12 | ||||
| -rw-r--r-- | src/cmd/compile/internal/x86/gsubr.go (renamed from src/cmd/8g/gsubr.go) | 102 | ||||
| -rw-r--r-- | src/cmd/compile/internal/x86/peep.go (renamed from src/cmd/8g/peep.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/x86/prog.go (renamed from src/cmd/8g/prog.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/x86/reg.go (renamed from src/cmd/8g/reg.go) | 4 | ||||
| -rw-r--r-- | src/cmd/compile/main.go | 34 | ||||
| -rw-r--r-- | src/cmd/dist/build.go | 69 | ||||
| -rw-r--r-- | src/cmd/dist/buildtool.go | 31 | ||||
| -rw-r--r-- | src/cmd/dist/test.go | 197 | ||||
| -rw-r--r-- | src/cmd/doc/main.go | 3 | ||||
| -rw-r--r-- | src/cmd/doc/pkg.go | 72 | ||||
| -rw-r--r-- | src/cmd/go/alldocs.go | 3 | ||||
| -rw-r--r-- | src/cmd/go/build.go | 70 | ||||
| -rw-r--r-- | src/cmd/go/env.go | 4 | ||||
| -rw-r--r-- | src/cmd/go/fmt.go | 28 | ||||
| -rw-r--r-- | src/cmd/go/help.go | 2 | ||||
| -rw-r--r-- | src/cmd/go/pkg.go | 19 | ||||
| -rw-r--r-- | src/cmd/go/vcs.go | 8 | ||||
| -rw-r--r-- | src/cmd/internal/asm/lexbody.go | 4 | ||||
| -rw-r--r-- | src/cmd/internal/asm/macbody.go | 5 | ||||
| -rw-r--r-- | src/cmd/internal/gc/go.errors | 81 | ||||
| -rw-r--r-- | src/cmd/internal/gc/yaccerrors.go | 194 | ||||
| -rw-r--r-- | src/cmd/internal/gc/yymsg.go | 83 | ||||
| -rw-r--r-- | src/cmd/internal/gcprog/gcprog.go | 298 | ||||
| -rw-r--r-- | src/cmd/internal/obj/arm64/asm7.go | 4 | ||||
| -rw-r--r-- | src/cmd/internal/obj/line_test.go | 14 | ||||
| -rw-r--r-- | src/cmd/internal/obj/link.go | 3 | ||||
| -rw-r--r-- | src/cmd/internal/obj/mgc0.go | 10 | ||||
| -rw-r--r-- | src/cmd/internal/obj/obj.go | 33 | ||||
| -rw-r--r-- | src/cmd/internal/obj/util.go | 17 | ||||
| -rw-r--r-- | src/cmd/internal/obj/x86/asm6.go | 5 | ||||
| -rw-r--r-- | src/cmd/internal/obj/x86/obj6.go | 3 | ||||
| -rw-r--r-- | src/cmd/internal/objfile/macho.go | 11 | ||||
| -rw-r--r-- | src/cmd/link/internal/amd64/asm.go (renamed from src/cmd/6l/asm.go) | 110 | ||||
| -rw-r--r-- | src/cmd/link/internal/amd64/l.go (renamed from src/cmd/6l/l.go) | 5 | ||||
| -rw-r--r-- | src/cmd/link/internal/amd64/obj.go (renamed from src/cmd/6l/obj.go) | 19 | ||||
| -rw-r--r-- | src/cmd/link/internal/amd64/z.go | 1 | ||||
| -rw-r--r-- | src/cmd/link/internal/arm/asm.go (renamed from src/cmd/5l/asm.go) | 112 | ||||
| -rw-r--r-- | src/cmd/link/internal/arm/l.go (renamed from src/cmd/5l/l.go) | 5 | ||||
| -rw-r--r-- | src/cmd/link/internal/arm/obj.go (renamed from src/cmd/5l/obj.go) | 9 | ||||
| -rw-r--r-- | src/cmd/link/internal/arm64/asm.go (renamed from src/cmd/7l/asm.go) | 62 | ||||
| -rw-r--r-- | src/cmd/link/internal/arm64/l.go (renamed from src/cmd/7l/l.go) | 5 | ||||
| -rw-r--r-- | src/cmd/link/internal/arm64/obj.go (renamed from src/cmd/7l/obj.go) | 9 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/ar.go (renamed from src/cmd/internal/ld/ar.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/arch.go (renamed from src/cmd/internal/ld/arch.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/data.go (renamed from src/cmd/internal/ld/data.go) | 232 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/decodesym.go (renamed from src/cmd/internal/ld/decodesym.go) | 59 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/dwarf.go (renamed from src/cmd/internal/ld/dwarf.go) | 188 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/dwarf_defs.go (renamed from src/cmd/internal/ld/dwarf_defs.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/elf.go (renamed from src/cmd/internal/ld/elf.go) | 212 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/go.go (renamed from src/cmd/internal/ld/go.go) | 57 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/ld.go (renamed from src/cmd/internal/ld/ld.go) | 4 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/ldelf.go (renamed from src/cmd/internal/ld/ldelf.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/ldmacho.go (renamed from src/cmd/internal/ld/ldmacho.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/ldpe.go (renamed from src/cmd/internal/ld/ldpe.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/lib.go (renamed from src/cmd/internal/ld/lib.go) | 280 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/link.go (renamed from src/cmd/internal/ld/link.go) | 23 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/macho.go (renamed from src/cmd/internal/ld/macho.go) | 10 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/macho_combine_dwarf.go | 369 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/objfile.go (renamed from src/cmd/internal/ld/objfile.go) | 2 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/pcln.go (renamed from src/cmd/internal/ld/pcln.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/pe.go (renamed from src/cmd/internal/ld/pe.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/pobj.go (renamed from src/cmd/internal/ld/pobj.go) | 5 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/sym.go (renamed from src/cmd/internal/ld/sym.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/symtab.go (renamed from src/cmd/internal/ld/symtab.go) | 63 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/textflag.go (renamed from src/cmd/internal/ld/textflag.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/util.go (renamed from src/cmd/internal/ld/util.go) | 0 | ||||
| -rw-r--r-- | src/cmd/link/internal/ppc64/asm.go (renamed from src/cmd/9l/asm.go) | 90 | ||||
| -rw-r--r-- | src/cmd/link/internal/ppc64/l.go (renamed from src/cmd/9l/l.go) | 5 | ||||
| -rw-r--r-- | src/cmd/link/internal/ppc64/obj.go (renamed from src/cmd/9l/obj.go) | 9 | ||||
| -rw-r--r-- | src/cmd/link/internal/x86/asm.go (renamed from src/cmd/8l/asm.go) | 106 | ||||
| -rw-r--r-- | src/cmd/link/internal/x86/l.go (renamed from src/cmd/8l/l.go) | 5 | ||||
| -rw-r--r-- | src/cmd/link/internal/x86/obj.go (renamed from src/cmd/8l/obj.go) | 9 | ||||
| -rw-r--r-- | src/cmd/link/main.go | 33 | ||||
| -rw-r--r-- | src/cmd/newlink/auto.go (renamed from src/cmd/link/auto.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/auto_test.go (renamed from src/cmd/link/auto_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/dead.go (renamed from src/cmd/link/dead.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/dead_test.go (renamed from src/cmd/link/dead_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/debug.go (renamed from src/cmd/link/debug.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/hex_test.go (renamed from src/cmd/link/hex_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/layout.go (renamed from src/cmd/link/layout.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/layout_test.go (renamed from src/cmd/link/layout_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/link_test.go (renamed from src/cmd/link/link_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/load.go (renamed from src/cmd/link/load.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/macho.go (renamed from src/cmd/link/macho.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/macho_test.go (renamed from src/cmd/link/macho_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/main.go | 9 | ||||
| -rw-r--r-- | src/cmd/newlink/pclntab.go (renamed from src/cmd/link/pclntab.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/pclntab_test.go (renamed from src/cmd/link/pclntab_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/prog.go (renamed from src/cmd/link/prog.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/prog_test.go (renamed from src/cmd/link/prog_test.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/runtime.go (renamed from src/cmd/link/runtime.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/scan.go (renamed from src/cmd/link/scan.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/Makefile (renamed from src/cmd/link/testdata/Makefile) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/autosection.6 (renamed from src/cmd/link/testdata/autosection.6) | bin | 937 -> 937 bytes | |||
| -rw-r--r-- | src/cmd/newlink/testdata/autosection.s (renamed from src/cmd/link/testdata/autosection.s) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/autoweak.6 (renamed from src/cmd/link/testdata/autoweak.6) | bin | 386 -> 386 bytes | |||
| -rw-r--r-- | src/cmd/newlink/testdata/autoweak.s (renamed from src/cmd/link/testdata/autoweak.s) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/dead.6 (renamed from src/cmd/link/testdata/dead.6) | bin | 849 -> 849 bytes | |||
| -rw-r--r-- | src/cmd/newlink/testdata/dead.s (renamed from src/cmd/link/testdata/dead.s) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/genpcln.go (renamed from src/cmd/link/testdata/genpcln.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/hello.6 (renamed from src/cmd/link/testdata/hello.6) | bin | 229 -> 229 bytes | |||
| -rw-r--r-- | src/cmd/newlink/testdata/hello.s (renamed from src/cmd/link/testdata/hello.s) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/layout.6 (renamed from src/cmd/link/testdata/layout.6) | bin | 396 -> 396 bytes | |||
| -rw-r--r-- | src/cmd/newlink/testdata/layout.s (renamed from src/cmd/link/testdata/layout.s) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/link.hello.darwin.amd64 (renamed from src/cmd/link/testdata/link.hello.darwin.amd64) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/macho.amd64.exit9 (renamed from src/cmd/link/testdata/macho.amd64.exit9) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/macho.amd64.hello (renamed from src/cmd/link/testdata/macho.amd64.hello) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/macho.amd64.helloro (renamed from src/cmd/link/testdata/macho.amd64.helloro) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/testdata/pclntab.6 (renamed from src/cmd/link/testdata/pclntab.6) | bin | 3804 -> 3804 bytes | |||
| -rw-r--r-- | src/cmd/newlink/testdata/pclntab.s (renamed from src/cmd/link/testdata/pclntab.s) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/util.go (renamed from src/cmd/link/util.go) | 0 | ||||
| -rw-r--r-- | src/cmd/newlink/write.go (renamed from src/cmd/link/write.go) | 0 | ||||
| -rw-r--r-- | src/cmd/pack/pack_test.go | 33 | ||||
| -rw-r--r-- | src/cmd/pprof/internal/profile/legacy_profile.go | 3 | ||||
| -rw-r--r-- | src/cmd/yacc/yacc.go | 128 |
272 files changed, 5962 insertions, 4345 deletions
diff --git a/src/cmd/6l/z.go b/src/cmd/6l/z.go deleted file mode 100644 index 06ab7d0f9a..0000000000 --- a/src/cmd/6l/z.go +++ /dev/null @@ -1 +0,0 @@ -package main diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go index 725c6352cb..d5d2772ef3 100644 --- a/src/cmd/asm/internal/asm/asm.go +++ b/src/cmd/asm/internal/asm/asm.go @@ -493,7 +493,10 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) { if arch.IsARM64STLXR(op) { prog.From = a[0] prog.To = a[1] - prog.To2 = a[2] + if a[2].Type != obj.TYPE_REG { + p.errorf("invalid addressing modes for third operand to %s instruction, must be register", obj.Aconv(op)) + } + prog.RegTo2 = a[2].Reg break } prog.From = a[0] diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go index c74f26974a..bf5cb1eef3 100644 --- a/src/cmd/asm/internal/flags/flags.go +++ b/src/cmd/asm/internal/flags/flags.go @@ -51,7 +51,7 @@ func Usage() { os.Exit(2) } -func Parse(theChar int) { +func Parse() { flag.Usage = Usage flag.Parse() if flag.NArg() != 1 { @@ -64,6 +64,6 @@ func Parse(theChar int) { if strings.HasSuffix(input, ".s") { input = input[:len(input)-2] } - *OutputFile = fmt.Sprintf("%s.%c", input, theChar) + *OutputFile = fmt.Sprintf("%s.o", input) } } diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go index 730042b149..7e495b8edf 100644 --- a/src/cmd/asm/internal/lex/input.go +++ b/src/cmd/asm/internal/lex/input.go @@ -13,7 +13,6 @@ import ( "text/scanner" "cmd/asm/internal/flags" - "cmd/internal/obj" ) // Input is the main input: a stack of readers and some macro definitions. @@ -436,7 +435,7 @@ func (in *Input) line() { if tok != '\n' { in.Error("unexpected token at end of #line: ", tok) } - obj.Linklinehist(linkCtxt, histLine, file, line) + linkCtxt.LineHist.Update(histLine, file, line) in.Stack.SetPos(line, file) } diff --git a/src/cmd/asm/internal/lex/tokenizer.go b/src/cmd/asm/internal/lex/tokenizer.go index 28a4b85253..6a4d95491f 100644 --- a/src/cmd/asm/internal/lex/tokenizer.go +++ b/src/cmd/asm/internal/lex/tokenizer.go @@ -10,8 +10,6 @@ import ( "strings" "text/scanner" "unicode" - - "cmd/internal/obj" ) // A Tokenizer is a simple wrapping of text/scanner.Scanner, configured @@ -40,7 +38,7 @@ func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer { s.Position.Filename = name s.IsIdentRune = isIdentRune if file != nil { - obj.Linklinehist(linkCtxt, histLine, name, 0) + linkCtxt.LineHist.Push(histLine, name) } return &Tokenizer{ s: &s, @@ -149,6 +147,6 @@ func (t *Tokenizer) Close() { if t.file != nil { t.file.Close() // It's an open file, so pop the line history. - obj.Linklinehist(linkCtxt, histLine, "<pop>", 0) + linkCtxt.LineHist.Pop(histLine) } } diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go index 32bdee6624..db0e28e2e5 100644 --- a/src/cmd/asm/main.go +++ b/src/cmd/asm/main.go @@ -29,7 +29,7 @@ func main() { log.Fatalf("asm: unrecognized architecture %s", GOARCH) } - flags.Parse(architecture.Thechar) + flags.Parse() // Create object file, write header. fd, err := os.Create(*flags.OutputFile) diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 30f828c4e9..87f21ed822 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -846,6 +846,8 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprint(fgo2, "}\n") } } + + fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog) } // Write out the C header allowing C code to call exported gccgo functions. @@ -1009,6 +1011,8 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprint(fgo2, ")\n") fmt.Fprint(fgo2, "}\n") } + + fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog) } // writeExportHeader writes out the start of the _cgo_export.h file. @@ -1374,6 +1378,17 @@ typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; #endif /* End of boilerplate cgo prologue. */ + +#ifdef __cplusplus +extern "C" { +#endif +` + +// gccExportHeaderEpilog goes at the end of the generated header file. +const gccExportHeaderEpilog = ` +#ifdef __cplusplus +} +#endif ` // gccgoExportFileProlog is written to the _cgo_export.c file when diff --git a/src/cmd/6g/cgen.go b/src/cmd/compile/internal/amd64/cgen.go index 23e2d1b57f..71f8f88322 100644 --- a/src/cmd/6g/cgen.go +++ b/src/cmd/compile/internal/amd64/cgen.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package amd64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" ) diff --git a/src/cmd/6g/galign.go b/src/cmd/compile/internal/amd64/galign.go index 0ca87537ff..79bf94a075 100644 --- a/src/cmd/6g/galign.go +++ b/src/cmd/compile/internal/amd64/galign.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package amd64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" ) @@ -65,7 +65,7 @@ func betypeinit() { } } -func main() { +func Main() { if obj.Getgoos() == "nacl" { resvd = append(resvd, x86.REG_BP, x86.REG_R15) } else if obj.Framepointer_enabled != 0 { @@ -101,6 +101,7 @@ func main() { gc.Thearch.Getg = getg gc.Thearch.Gins = gins gc.Thearch.Ginsboolval = ginsboolval + gc.Thearch.Ginscmp = ginscmp gc.Thearch.Ginscon = ginscon gc.Thearch.Ginsnop = ginsnop gc.Thearch.Gmove = gmove diff --git a/src/cmd/6g/ggen.go b/src/cmd/compile/internal/amd64/ggen.go index 6e5e6bc4ca..6425633818 100644 --- a/src/cmd/6g/ggen.go +++ b/src/cmd/compile/internal/amd64/ggen.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package amd64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" ) @@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) { // iterate through declarations - they are sorted in decreasing xoffset order. for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next { n = l.N - if !n.Needzero { + if !n.Name.Needzero { continue } if n.Class != gc.PAUTO { @@ -190,9 +190,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { check := 0 if gc.Issigned[t.Etype] { check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) { + if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) { check = 0 - } else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 { + } else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 { check = 0 } } @@ -306,7 +306,7 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { * known to be dead. */ func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) { - r := int(reg[dr]) + r := reg[dr] // save current ax and dx if they are live // and not the destination @@ -318,7 +318,7 @@ func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) { x.Type = gc.Types[gc.TINT64] gmove(x, oldx) x.Type = t - oldx.Ostk = int32(r) // squirrel away old r value + oldx.Etype = r // squirrel away old r value reg[dr] = 1 } } @@ -326,7 +326,7 @@ func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) { func restx(x *gc.Node, oldx *gc.Node) { if oldx.Op != 0 { x.Type = gc.Types[gc.TINT64] - reg[x.Reg] = uint8(oldx.Ostk) + reg[x.Reg] = oldx.Etype gmove(oldx, x) gc.Regfree(oldx) } @@ -381,7 +381,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { var n1 gc.Node gc.Regalloc(&n1, nl.Type, res) gc.Cgen(nl, &n1) - sc := uint64(gc.Mpgetfix(nr.Val.U.Xval)) + sc := uint64(nr.Int()) if sc >= uint64(nl.Type.Width*8) { // large shift gets 2 shifts by width-1 var n3 gc.Node diff --git a/src/cmd/6g/gsubr.go b/src/cmd/compile/internal/amd64/gsubr.go index 53d0f038d9..a8e4170bee 100644 --- a/src/cmd/6g/gsubr.go +++ b/src/cmd/compile/internal/amd64/gsubr.go @@ -28,10 +28,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package amd64 import ( - "cmd/internal/gc" + "cmd/compile/internal/big" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" "fmt" @@ -99,33 +100,67 @@ func ginscon(as int, c int64, n2 *gc.Node) { gins(as, &n1, n2) } +func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { + if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && gc.Smallintconst(n1) && n2.Op != gc.OLITERAL { + // Reverse comparison to place constant last. + op = gc.Brrev(op) + n1, n2 = n2, n1 + } + // General case. + var r1, r2, g1, g2 gc.Node + if n1.Op == gc.ONAME && n1.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG { + r1 = *n1 + } else { + gc.Regalloc(&r1, t, n1) + gc.Regalloc(&g1, n1.Type, &r1) + gc.Cgen(n1, &g1) + gmove(&g1, &r1) + } + if n2.Op == gc.OLITERAL && gc.Isint[t.Etype] && gc.Smallintconst(n2) { + r2 = *n2 + } else { + gc.Regalloc(&r2, t, n2) + gc.Regalloc(&g2, n1.Type, &r2) + gc.Cgen(n2, &g2) + gmove(&g2, &r2) + } + gins(optoas(gc.OCMP, t), &r1, &r2) + if r1.Op == gc.OREGISTER { + gc.Regfree(&g1) + gc.Regfree(&r1) + } + if r2.Op == gc.OREGISTER { + gc.Regfree(&g2) + gc.Regfree(&r2) + } + return gc.Gbranch(optoas(op, t), nil, likely) +} + func ginsboolval(a int, n *gc.Node) { gins(jmptoset(a), nil, n) } -/* - * set up nodes representing 2^63 - */ -var bigi gc.Node - -var bigf gc.Node - -var bignodes_did int +// set up nodes representing 2^63 +var ( + bigi gc.Node + bigf gc.Node + bignodes_did bool +) func bignodes() { - if bignodes_did != 0 { + if bignodes_did { return } - bignodes_did = 1 + bignodes_did = true + + var i big.Int + i.SetInt64(1) + i.Lsh(&i, 63) - gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1) - gc.Mpshiftfix(bigi.Val.U.Xval, 63) + gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) + bigi.SetBigInt(&i) - bigf = bigi - bigf.Type = gc.Types[gc.TFLOAT64] - bigf.Val.Ctype = gc.CTFLT - bigf.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval) + bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64]) } /* @@ -156,7 +191,7 @@ func gmove(f *gc.Node, t *gc.Node) { // convert constant to desired type if f.Op == gc.OLITERAL { var con gc.Node - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) f = &con ft = tt // so big switch will choose a simple mov @@ -170,10 +205,7 @@ func gmove(f *gc.Node, t *gc.Node) { // 64-bit immediates are really 32-bit sign-extended // unless moving into a register. if gc.Isint[tt] { - if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Minintval[gc.TINT32]) < 0 { - goto hard - } - if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Maxintval[gc.TINT32]) > 0 { + if i := con.Int(); int64(int32(i)) != i { goto hard } } @@ -1237,7 +1269,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { if !gc.Isconst(n, gc.CTINT) { break } - v := gc.Mpgetfix(n.Val.U.Xval) + v := n.Int() if v >= 32000 || v <= -32000 { break } diff --git a/src/cmd/6g/peep.go b/src/cmd/compile/internal/amd64/peep.go index cd07199ed1..19db68e944 100644 --- a/src/cmd/6g/peep.go +++ b/src/cmd/compile/internal/amd64/peep.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package amd64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" "fmt" diff --git a/src/cmd/6g/prog.go b/src/cmd/compile/internal/amd64/prog.go index 5f604742c3..00918c8691 100644 --- a/src/cmd/6g/prog.go +++ b/src/cmd/compile/internal/amd64/prog.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package amd64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" ) diff --git a/src/cmd/6g/reg.go b/src/cmd/compile/internal/amd64/reg.go index cab07b5b4e..7d4f40641d 100644 --- a/src/cmd/6g/reg.go +++ b/src/cmd/compile/internal/amd64/reg.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package amd64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" ) diff --git a/src/cmd/5g/cgen.go b/src/cmd/compile/internal/arm/cgen.go index 2e922391cb..8ea6c5f3f2 100644 --- a/src/cmd/5g/cgen.go +++ b/src/cmd/compile/internal/arm/cgen.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package arm import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm" ) @@ -53,28 +53,6 @@ func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog { return cgenindex(n, res, bounded) } -func gencmp0(n *gc.Node, t *gc.Type, o int, likely int, to *obj.Prog) { - var n1 gc.Node - - gc.Regalloc(&n1, t, nil) - gc.Cgen(n, &n1) - a := optoas(gc.OCMP, t) - if a != arm.ACMP { - var n2 gc.Node - gc.Nodconst(&n2, t, 0) - var n3 gc.Node - gc.Regalloc(&n3, t, nil) - gmove(&n2, &n3) - gins(a, &n1, &n3) - gc.Regfree(&n3) - } else { - gins(arm.ATST, &n1, nil) - } - a = optoas(o, t) - gc.Patch(gc.Gbranch(a, t, likely), to) - gc.Regfree(&n1) -} - func blockcopy(n, res *gc.Node, osrc, odst, w int64) { // determine alignment. // want to avoid unaligned access, so have to use diff --git a/src/cmd/5g/cgen64.go b/src/cmd/compile/internal/arm/cgen64.go index 699e555f71..6c88b76e20 100644 --- a/src/cmd/5g/cgen64.go +++ b/src/cmd/compile/internal/arm/cgen64.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package arm import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm" ) @@ -237,7 +237,7 @@ func cgen64(n *gc.Node, res *gc.Node) { // shld hi:lo, c // shld lo:t, c case gc.OLROT: - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) var bl gc.Node gc.Regalloc(&bl, lo1.Type, nil) @@ -291,7 +291,7 @@ func cgen64(n *gc.Node, res *gc.Node) { var p4 *obj.Prog var p5 *obj.Prog if r.Op == gc.OLITERAL { - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) if v >= 64 { // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al) // here and below (verify it optimizes to EOR) @@ -452,7 +452,7 @@ func cgen64(n *gc.Node, res *gc.Node) { var creg gc.Node var p3 *obj.Prog if r.Op == gc.OLITERAL { - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) if v >= 64 { if bh.Type.Etype == gc.TINT32 { // MOVW bh->31, al diff --git a/src/cmd/5g/galign.go b/src/cmd/compile/internal/arm/galign.go index 3c8ba519eb..60a39d3fe4 100644 --- a/src/cmd/5g/galign.go +++ b/src/cmd/compile/internal/arm/galign.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package arm import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm" ) @@ -37,7 +37,7 @@ func betypeinit() { gc.Widthreg = 4 } -func main() { +func Main() { gc.Thearch.Thechar = thechar gc.Thearch.Thestring = thestring gc.Thearch.Thelinkarch = thelinkarch @@ -65,6 +65,7 @@ func main() { gc.Thearch.Expandchecks = expandchecks gc.Thearch.Getg = getg gc.Thearch.Gins = gins + gc.Thearch.Ginscmp = ginscmp gc.Thearch.Ginscon = ginscon gc.Thearch.Ginsnop = ginsnop gc.Thearch.Gmove = gmove diff --git a/src/cmd/5g/ggen.go b/src/cmd/compile/internal/arm/ggen.go index 0cf0d9299c..6633351032 100644 --- a/src/cmd/5g/ggen.go +++ b/src/cmd/compile/internal/arm/ggen.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package arm import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm" ) @@ -30,7 +30,7 @@ func defframe(ptxt *obj.Prog) { r0 := uint32(0) for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next { n = l.N - if !n.Needzero { + if !n.Name.Needzero { continue } if n.Class != gc.PAUTO { @@ -183,7 +183,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { w := int(nl.Type.Width * 8) if op == gc.OLROT { - v := int(gc.Mpgetfix(nr.Val.U.Xval)) + v := nr.Int() var n1 gc.Node gc.Regalloc(&n1, nl.Type, res) if w == 32 { @@ -210,7 +210,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { var n1 gc.Node gc.Regalloc(&n1, nl.Type, res) gc.Cgen(nl, &n1) - sc := uint64(gc.Mpgetfix(nr.Val.U.Xval)) + sc := uint64(nr.Int()) if sc == 0 { } else // nothing to do if sc >= uint64(nl.Type.Width*8) { @@ -479,6 +479,32 @@ func ginscon(as int, c int64, n *gc.Node) { gc.Regfree(&n2) } +func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { + if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n1.Int() == 0 && n2.Op != gc.OLITERAL { + op = gc.Brrev(op) + n1, n2 = n2, n1 + } + var r1, r2, g1, g2 gc.Node + gc.Regalloc(&r1, t, n1) + gc.Regalloc(&g1, n1.Type, &r1) + gc.Cgen(n1, &g1) + gmove(&g1, &r1) + if gc.Isint[t.Etype] && n2.Op == gc.OLITERAL && n2.Int() == 0 { + gins(arm.ACMP, &r1, n2) + } else { + gc.Regalloc(&r2, t, n2) + gc.Regalloc(&g2, n1.Type, &r2) + gc.Cgen(n2, &g2) + gmove(&g2, &r2) + gins(optoas(gc.OCMP, t), &r1, &r2) + gc.Regfree(&g2) + gc.Regfree(&r2) + } + gc.Regfree(&g1) + gc.Regfree(&r1) + return gc.Gbranch(optoas(op, t), nil, likely) +} + // addr += index*width if possible. func addindex(index *gc.Node, width int64, addr *gc.Node) bool { switch width { diff --git a/src/cmd/5g/gsubr.go b/src/cmd/compile/internal/arm/gsubr.go index 57d511e6f6..5263f15ac2 100644 --- a/src/cmd/5g/gsubr.go +++ b/src/cmd/compile/internal/arm/gsubr.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm" "fmt" @@ -53,7 +53,7 @@ func ncon(i uint32) *gc.Node { if ncon_n.Type == nil { gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0) } - gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i)) + ncon_n.SetInt(int64(i)) return &ncon_n } @@ -89,7 +89,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { case gc.ONAME: if n.Class == gc.PPARAMREF { var n1 gc.Node - gc.Cgen(n.Heapaddr, &n1) + gc.Cgen(n.Name.Heapaddr, &n1) sclean[nsclean-1] = n1 n = &n1 } @@ -111,8 +111,8 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { case gc.OLITERAL: var n1 gc.Node - gc.Convconst(&n1, n.Type, &n.Val) - i := gc.Mpgetfix(n1.Val.U.Xval) + n.Convconst(&n1, n.Type) + i := n1.Int() gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i))) i >>= 32 if n.Type.Etype == gc.TINT64 { @@ -160,12 +160,12 @@ func gmove(f *gc.Node, t *gc.Node) { var con gc.Node switch tt { default: - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) case gc.TINT16, gc.TINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TINT32], &f.Val) + f.Convconst(&con, gc.Types[gc.TINT32]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(arm.AMOVW, &con, &r1) @@ -176,7 +176,7 @@ func gmove(f *gc.Node, t *gc.Node) { case gc.TUINT16, gc.TUINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TUINT32], &f.Val) + f.Convconst(&con, gc.Types[gc.TUINT32]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(arm.AMOVW, &con, &r1) @@ -1118,7 +1118,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { if !gc.Isconst(n, gc.CTINT) { break } - v := gc.Mpgetfix(n.Val.U.Xval) + v := n.Int() if v >= 32000 || v <= -32000 { break } diff --git a/src/cmd/5g/peep.go b/src/cmd/compile/internal/arm/peep.go index b76719d74e..66eba417c0 100644 --- a/src/cmd/5g/peep.go +++ b/src/cmd/compile/internal/arm/peep.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm" "fmt" diff --git a/src/cmd/5g/prog.go b/src/cmd/compile/internal/arm/prog.go index c472cdf042..cdf9d29192 100644 --- a/src/cmd/5g/prog.go +++ b/src/cmd/compile/internal/arm/prog.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package arm import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm" ) diff --git a/src/cmd/5g/reg.go b/src/cmd/compile/internal/arm/reg.go index 2afdf12416..b72ccc9815 100644 --- a/src/cmd/5g/reg.go +++ b/src/cmd/compile/internal/arm/reg.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm import "cmd/internal/obj/arm" -import "cmd/internal/gc" +import "cmd/compile/internal/gc" const ( NREGVAR = 32 diff --git a/src/cmd/7g/cgen.go b/src/cmd/compile/internal/arm64/cgen.go index 6f268b4185..30326d73e2 100644 --- a/src/cmd/7g/cgen.go +++ b/src/cmd/compile/internal/arm64/cgen.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package arm64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm64" ) diff --git a/src/cmd/7g/galign.go b/src/cmd/compile/internal/arm64/galign.go index 34b4ab6142..38def8f5a4 100644 --- a/src/cmd/7g/galign.go +++ b/src/cmd/compile/internal/arm64/galign.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package arm64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm64" ) @@ -37,7 +37,7 @@ func betypeinit() { gc.Widthreg = 8 } -func main() { +func Main() { gc.Thearch.Thechar = thechar gc.Thearch.Thestring = thestring gc.Thearch.Thelinkarch = thelinkarch @@ -65,6 +65,7 @@ func main() { gc.Thearch.Expandchecks = expandchecks gc.Thearch.Getg = getg gc.Thearch.Gins = gins + gc.Thearch.Ginscmp = ginscmp gc.Thearch.Ginscon = ginscon gc.Thearch.Ginsnop = ginsnop gc.Thearch.Gmove = gmove diff --git a/src/cmd/7g/ggen.go b/src/cmd/compile/internal/arm64/ggen.go index b824a3a18c..851ca4e30f 100644 --- a/src/cmd/7g/ggen.go +++ b/src/cmd/compile/internal/arm64/ggen.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package arm64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm64" "fmt" @@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) { // iterate through declarations - they are sorted in decreasing xoffset order. for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next { n = l.N - if !n.Needzero { + if !n.Name.Needzero { continue } if n.Class != gc.PAUTO { @@ -147,9 +147,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { check := 0 if gc.Issigned[t.Etype] { check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) { + if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) { check = 0 - } else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 { + } else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 { check = 0 } } @@ -312,7 +312,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { var n1 gc.Node gc.Regalloc(&n1, nl.Type, res) gc.Cgen(nl, &n1) - sc := uint64(uint64(gc.Mpgetfix(nr.Val.U.Xval))) + sc := uint64(nr.Int()) if sc >= uint64(nl.Type.Width*8) { // large shift gets 2 shifts by width-1 var n3 gc.Node diff --git a/src/cmd/7g/gsubr.go b/src/cmd/compile/internal/arm64/gsubr.go index a34a4306ae..0a14654d83 100644 --- a/src/cmd/7g/gsubr.go +++ b/src/cmd/compile/internal/arm64/gsubr.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm64" "fmt" @@ -102,6 +102,34 @@ func ginscon2(as int, n2 *gc.Node, c int64) { gc.Regfree(&ntmp) } +func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { + if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL { + // Reverse comparison to place constant last. + op = gc.Brrev(op) + n1, n2 = n2, n1 + } + + var r1, r2, g1, g2 gc.Node + gc.Regalloc(&r1, t, n1) + gc.Regalloc(&g1, n1.Type, &r1) + gc.Cgen(n1, &g1) + gmove(&g1, &r1) + if gc.Isint[t.Etype] && gc.Isconst(n2, gc.CTINT) { + ginscon2(optoas(gc.OCMP, t), &r1, n2.Int()) + } else { + gc.Regalloc(&r2, t, n2) + gc.Regalloc(&g2, n1.Type, &r2) + gc.Cgen(n2, &g2) + gmove(&g2, &r2) + gcmp(optoas(gc.OCMP, t), &r1, &r2) + gc.Regfree(&g2) + gc.Regfree(&r2) + } + gc.Regfree(&g1) + gc.Regfree(&r1) + return gc.Gbranch(optoas(op, t), nil, likely) +} + /* * generate move: * t = f @@ -133,13 +161,13 @@ func gmove(f *gc.Node, t *gc.Node) { var con gc.Node switch tt { default: - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) case gc.TINT32, gc.TINT16, gc.TINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val) + f.Convconst(&con, gc.Types[gc.TINT64]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(arm64.AMOVD, &con, &r1) @@ -151,7 +179,7 @@ func gmove(f *gc.Node, t *gc.Node) { gc.TUINT16, gc.TUINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val) + f.Convconst(&con, gc.Types[gc.TUINT64]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(arm64.AMOVD, &con, &r1) @@ -440,14 +468,13 @@ hard: } func intLiteral(n *gc.Node) (x int64, ok bool) { - if n == nil || n.Op != gc.OLITERAL { + switch { + case n == nil: return - } - switch n.Val.Ctype { - case gc.CTINT, gc.CTRUNE: - return gc.Mpgetfix(n.Val.U.Xval), true - case gc.CTBOOL: - return int64(obj.Bool2int(n.Val.U.Bval)), true + case gc.Isconst(n, gc.CTINT): + return n.Int(), true + case gc.Isconst(n, gc.CTBOOL): + return int64(obj.Bool2int(n.Bool())), true } return } diff --git a/src/cmd/7g/peep.go b/src/cmd/compile/internal/arm64/peep.go index 49bc69b132..3dbccb70b2 100644 --- a/src/cmd/7g/peep.go +++ b/src/cmd/compile/internal/arm64/peep.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm64" "fmt" @@ -422,9 +422,9 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { // 7g never generates a from3 fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(&p.From3)) } - if p.To2.Type != obj.TYPE_NONE { + if p.RegTo2 != obj.REG_NONE { // 7g never generates a to2 - fmt.Printf("copyu: to2 (%v) not implemented\n", gc.Ctxt.Dconv(&p.To2)) + fmt.Printf("copyu: RegTo2 (%v) not implemented\n", obj.Rconv(int(p.RegTo2))) } switch p.As { diff --git a/src/cmd/7g/prog.go b/src/cmd/compile/internal/arm64/prog.go index 023f302e14..1106e788a5 100644 --- a/src/cmd/7g/prog.go +++ b/src/cmd/compile/internal/arm64/prog.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package arm64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/arm64" ) diff --git a/src/cmd/7g/reg.go b/src/cmd/compile/internal/arm64/reg.go index 0e5ac73499..7bc756b7bf 100644 --- a/src/cmd/7g/reg.go +++ b/src/cmd/compile/internal/arm64/reg.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj/arm64" ) diff --git a/src/cmd/internal/gc/big/accuracy_string.go b/src/cmd/compile/internal/big/accuracy_string.go index 24ef7f1077..24ef7f1077 100644 --- a/src/cmd/internal/gc/big/accuracy_string.go +++ b/src/cmd/compile/internal/big/accuracy_string.go diff --git a/src/cmd/internal/gc/big/arith.go b/src/cmd/compile/internal/big/arith.go index 328c85c4f7..1ff6349d9d 100644 --- a/src/cmd/internal/gc/big/arith.go +++ b/src/cmd/compile/internal/big/arith.go @@ -196,7 +196,6 @@ func subVV_g(z, x, y []Word) (c Word) { return } -// Argument y must be either 0 or 1. // The resulting carry c is either 0 or 1. func addVW_g(z, x []Word, y Word) (c Word) { if use_addWW_g { diff --git a/src/cmd/internal/gc/big/arith_decl.go b/src/cmd/compile/internal/big/arith_decl.go index fe13577203..fe13577203 100644 --- a/src/cmd/internal/gc/big/arith_decl.go +++ b/src/cmd/compile/internal/big/arith_decl.go diff --git a/src/cmd/internal/gc/big/arith_test.go b/src/cmd/compile/internal/big/arith_test.go index cd92dd7173..f46a494f17 100644 --- a/src/cmd/internal/gc/big/arith_test.go +++ b/src/cmd/compile/internal/big/arith_test.go @@ -155,6 +155,7 @@ var sumVW = []argVW{ {nat{1}, nat{1}, 0, 0}, {nat{0}, nat{_M}, 1, 1}, {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1}, + {nat{585}, nat{314}, 271, 0}, } var prodVW = []argVW{ diff --git a/src/cmd/internal/gc/big/bits_test.go b/src/cmd/compile/internal/big/bits_test.go index 3ce24222d7..3ce24222d7 100644 --- a/src/cmd/internal/gc/big/bits_test.go +++ b/src/cmd/compile/internal/big/bits_test.go diff --git a/src/cmd/internal/gc/big/calibrate_test.go b/src/cmd/compile/internal/big/calibrate_test.go index f69ffbf5cf..f69ffbf5cf 100644 --- a/src/cmd/internal/gc/big/calibrate_test.go +++ b/src/cmd/compile/internal/big/calibrate_test.go diff --git a/src/cmd/internal/gc/big/decimal.go b/src/cmd/compile/internal/big/decimal.go index 3d024dce68..3d024dce68 100644 --- a/src/cmd/internal/gc/big/decimal.go +++ b/src/cmd/compile/internal/big/decimal.go diff --git a/src/cmd/internal/gc/big/decimal_test.go b/src/cmd/compile/internal/big/decimal_test.go index 81e022a47d..81e022a47d 100644 --- a/src/cmd/internal/gc/big/decimal_test.go +++ b/src/cmd/compile/internal/big/decimal_test.go diff --git a/src/cmd/internal/gc/big/example_test.go b/src/cmd/compile/internal/big/example_test.go index 078be47f95..cb91bc23bd 100644 --- a/src/cmd/internal/gc/big/example_test.go +++ b/src/cmd/compile/internal/big/example_test.go @@ -5,9 +5,9 @@ package big_test import ( + "cmd/compile/internal/big" "fmt" "log" - "math/big" ) func ExampleRat_SetString() { diff --git a/src/cmd/internal/gc/big/float.go b/src/cmd/compile/internal/big/float.go index ed55e8e513..dcb72c5754 100644 --- a/src/cmd/internal/gc/big/float.go +++ b/src/cmd/compile/internal/big/float.go @@ -65,12 +65,16 @@ type Float struct { exp int32 } -// Float operations that would lead to a NaN under IEEE-754 rules cause -// a run-time panic of ErrNaN type. +// An ErrNaN panic is raised by a Float operation that would lead to +// a NaN under IEEE-754 rules. An ErrNaN implements the error interface. type ErrNaN struct { msg string } +func (err ErrNaN) Error() string { + return err.msg +} + // NewFloat allocates and returns a new Float set to x, // with precision 53 and rounding mode ToNearestEven. // NewFloat panics with ErrNaN if x is a NaN. @@ -849,9 +853,6 @@ func (x *Float) Int64() (int64, Accuracy) { panic("unreachable") } -// TODO(gri) Float32 and Float64 are very similar internally but for the -// floatxx parameters and some conversions. Should factor out shared code. - // Float32 returns the float32 value nearest to x. If x is too small to be // represented by a float32 (|x| < math.SmallestNonzeroFloat32), the result // is (0, Below) or (-0, Above), respectively, depending on the sign of x. @@ -876,64 +877,70 @@ func (x *Float) Float32() (float32, Accuracy) { emax = bias // 127 largest unbiased exponent (normal) ) - // Float mantissae m have an explicit msb and are in the range 0.5 <= m < 1.0. - // floatxx mantissae have an implicit msb and are in the range 1.0 <= m < 2.0. - // For a given mantissa m, we need to add 1 to a floatxx exponent to get the - // corresponding Float exponent. - // (see also implementation of math.Ldexp for similar code) + // Float mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa. + e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0 + p := mbits + 1 // precision of normal float - if x.exp < dmin+1 { - // underflow - if x.neg { - var z float32 - return -z, Above + // If the exponent is too small, we may have a denormal number + // in which case we have fewer mantissa bits available: reduce + // precision accordingly. + if e < emin { + p -= emin - int(e) + // Make sure we have at least 1 bit so that we don't + // lose numbers rounded up to the smallest denormal. + if p < 1 { + p = 1 } - return 0.0, Below } - // x.exp >= dmin+1 + // round var r Float - r.prec = mbits + 1 // +1 for implicit msb - if x.exp < emin+1 { - // denormal number - round to fewer bits - r.prec = uint32(x.exp - dmin) - } + r.prec = uint32(p) r.Set(x) + e = r.exp - 1 // Rounding may have caused r to overflow to ±Inf // (rounding never causes underflows to 0). if r.form == inf { - r.exp = emax + 2 // cause overflow below + e = emax + 1 // cause overflow below } - if r.exp > emax+1 { + // If the exponent is too large, overflow to ±Inf. + if e > emax { // overflow if x.neg { return float32(math.Inf(-1)), Below } return float32(math.Inf(+1)), Above } - // dmin+1 <= r.exp <= emax+1 - var s uint32 - if r.neg { - s = 1 << (fbits - 1) + // Determine sign, biased exponent, and mantissa. + var sign, bexp, mant uint32 + if x.neg { + sign = 1 << (fbits - 1) } - m := high32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit) - // Rounding may have caused a denormal number to // become normal. Check again. - c := float32(1.0) - if r.exp < emin+1 { + if e < emin { // denormal number - r.exp += mbits - c = 1.0 / (1 << mbits) // 2**-mbits + if e < dmin { + // underflow to ±0 + if x.neg { + var z float32 + return -z, Above + } + return 0.0, Below + } + // bexp = 0 + mant = high32(r.mant) >> (fbits - r.prec) + } else { + // normal number: emin <= e <= emax + bexp = uint32(e+bias) << mbits + mant = high32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit) } - // emin+1 <= r.exp <= emax+1 - e := uint32(r.exp-emin) << mbits - return c * math.Float32frombits(s|e|m), r.acc + return math.Float32frombits(sign | bexp | mant), r.acc case zero: if x.neg { @@ -976,64 +983,70 @@ func (x *Float) Float64() (float64, Accuracy) { emax = bias // 1023 largest unbiased exponent (normal) ) - // Float mantissae m have an explicit msb and are in the range 0.5 <= m < 1.0. - // floatxx mantissae have an implicit msb and are in the range 1.0 <= m < 2.0. - // For a given mantissa m, we need to add 1 to a floatxx exponent to get the - // corresponding Float exponent. - // (see also implementation of math.Ldexp for similar code) + // Float mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa. + e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0 + p := mbits + 1 // precision of normal float - if x.exp < dmin+1 { - // underflow - if x.neg { - var z float64 - return -z, Above + // If the exponent is too small, we may have a denormal number + // in which case we have fewer mantissa bits available: reduce + // precision accordingly. + if e < emin { + p -= emin - int(e) + // Make sure we have at least 1 bit so that we don't + // lose numbers rounded up to the smallest denormal. + if p < 1 { + p = 1 } - return 0.0, Below } - // x.exp >= dmin+1 + // round var r Float - r.prec = mbits + 1 // +1 for implicit msb - if x.exp < emin+1 { - // denormal number - round to fewer bits - r.prec = uint32(x.exp - dmin) - } + r.prec = uint32(p) r.Set(x) + e = r.exp - 1 // Rounding may have caused r to overflow to ±Inf // (rounding never causes underflows to 0). if r.form == inf { - r.exp = emax + 2 // cause overflow below + e = emax + 1 // cause overflow below } - if r.exp > emax+1 { + // If the exponent is too large, overflow to ±Inf. + if e > emax { // overflow if x.neg { return math.Inf(-1), Below } return math.Inf(+1), Above } - // dmin+1 <= r.exp <= emax+1 - var s uint64 - if r.neg { - s = 1 << (fbits - 1) + // Determine sign, biased exponent, and mantissa. + var sign, bexp, mant uint64 + if x.neg { + sign = 1 << (fbits - 1) } - m := high64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit) - // Rounding may have caused a denormal number to // become normal. Check again. - c := 1.0 - if r.exp < emin+1 { + if e < emin { // denormal number - r.exp += mbits - c = 1.0 / (1 << mbits) // 2**-mbits + if e < dmin { + // underflow to ±0 + if x.neg { + var z float64 + return -z, Above + } + return 0.0, Below + } + // bexp = 0 + mant = high64(r.mant) >> (fbits - r.prec) + } else { + // normal number: emin <= e <= emax + bexp = uint64(e+bias) << mbits + mant = high64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit) } - // emin+1 <= r.exp <= emax+1 - e := uint64(r.exp-emin) << mbits - return c * math.Float64frombits(s|e|m), r.acc + return math.Float64frombits(sign | bexp | mant), r.acc case zero: if x.neg { diff --git a/src/cmd/internal/gc/big/float_test.go b/src/cmd/compile/internal/big/float_test.go index 2a48ec4465..8bd3a9c8c9 100644 --- a/src/cmd/internal/gc/big/float_test.go +++ b/src/cmd/compile/internal/big/float_test.go @@ -12,6 +12,9 @@ import ( "testing" ) +// Verify that ErrNaN implements the error interface. +var _ error = ErrNaN{} + func (x *Float) uint64() uint64 { u, acc := x.Uint64() if acc != Exact { @@ -200,6 +203,18 @@ func alike(x, y *Float) bool { return x.Cmp(y) == 0 && x.Signbit() == y.Signbit() } +func alike32(x, y float32) bool { + // we can ignore NaNs + return x == y && math.Signbit(float64(x)) == math.Signbit(float64(y)) + +} + +func alike64(x, y float64) bool { + // we can ignore NaNs + return x == y && math.Signbit(x) == math.Signbit(y) + +} + func TestFloatMantExp(t *testing.T) { for _, test := range []struct { x string @@ -825,52 +840,69 @@ func TestFloatFloat32(t *testing.T) { out float32 acc Accuracy }{ - {"-Inf", float32(math.Inf(-1)), Exact}, - {"-0x1.ffffff0p2147483646", float32(-math.Inf(+1)), Below}, // overflow in rounding - {"-1e10000", float32(math.Inf(-1)), Below}, // overflow - {"-0x1p128", float32(math.Inf(-1)), Below}, // overflow - {"-0x1.ffffff0p127", float32(-math.Inf(+1)), Below}, // overflow - {"-0x1.fffffe8p127", -math.MaxFloat32, Above}, - {"-0x1.fffffe0p127", -math.MaxFloat32, Exact}, - {"-12345.000000000000000000001", -12345, Above}, - {"-12345.0", -12345, Exact}, - {"-1.000000000000000000001", -1, Above}, - {"-1", -1, Exact}, - {"-0x0.000002p-126", -math.SmallestNonzeroFloat32, Exact}, - {"-0x0.000002p-127", -0, Above}, // underflow - {"-1e-1000", -0, Above}, // underflow {"0", 0, Exact}, - {"1e-1000", 0, Below}, // underflow - {"0x0.000002p-127", 0, Below}, // underflow - {"0x0.000002p-126", math.SmallestNonzeroFloat32, Exact}, + + // underflow + {"1e-1000", 0, Below}, + {"0x0.000002p-127", 0, Below}, + {"0x.0000010p-126", 0, Below}, + + // denormals + {"1.401298464e-45", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal + {"0x.ffffff8p-149", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal + {"0x.0000018p-126", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal + {"0x.0000020p-126", math.SmallestNonzeroFloat32, Exact}, + {"0x.8p-148", math.SmallestNonzeroFloat32, Exact}, + {"1p-149", math.SmallestNonzeroFloat32, Exact}, + {"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal + + // normals + {"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal + {"1p-126", math.Float32frombits(0x00800000), Exact}, // smallest normal + {"0x1.fffffep-126", math.Float32frombits(0x00ffffff), Exact}, + {"0x1.ffffffp-126", math.Float32frombits(0x01000000), Above}, // rounded up {"1", 1, Exact}, {"1.000000000000000000001", 1, Below}, {"12345.0", 12345, Exact}, {"12345.000000000000000000001", 12345, Below}, {"0x1.fffffe0p127", math.MaxFloat32, Exact}, {"0x1.fffffe8p127", math.MaxFloat32, Below}, - {"0x1.ffffff0p127", float32(math.Inf(+1)), Above}, // overflow - {"0x1p128", float32(math.Inf(+1)), Above}, // overflow - {"1e10000", float32(math.Inf(+1)), Above}, // overflow + + // overflow + {"0x1.ffffff0p127", float32(math.Inf(+1)), Above}, + {"0x1p128", float32(math.Inf(+1)), Above}, + {"1e10000", float32(math.Inf(+1)), Above}, {"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, // overflow in rounding - {"+Inf", float32(math.Inf(+1)), Exact}, + + // inf + {"Inf", float32(math.Inf(+1)), Exact}, } { - // conversion should match strconv where syntax is agreeable - if f, err := strconv.ParseFloat(test.x, 32); err == nil && float32(f) != test.out { - t.Errorf("%s: got %g; want %g (incorrect test data)", test.x, f, test.out) - } + for i := 0; i < 2; i++ { + // test both signs + tx, tout, tacc := test.x, test.out, test.acc + if i != 0 { + tx = "-" + tx + tout = -tout + tacc = -tacc + } - x := makeFloat(test.x) - out, acc := x.Float32() - if out != test.out || acc != test.acc { - t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", test.x, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), test.acc) - } + // conversion should match strconv where syntax is agreeable + if f, err := strconv.ParseFloat(tx, 32); err == nil && !alike32(float32(f), tout) { + t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout) + } + + x := makeFloat(tx) + out, acc := x.Float32() + if !alike32(out, tout) || acc != tacc { + t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc) + } - // test that x.SetFloat64(float64(f)).Float32() == f - var x2 Float - out2, acc2 := x2.SetFloat64(float64(out)).Float32() - if out2 != out || acc2 != Exact { - t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out) + // test that x.SetFloat64(float64(f)).Float32() == f + var x2 Float + out2, acc2 := x2.SetFloat64(float64(out)).Float32() + if !alike32(out2, out) || acc2 != Exact { + t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out) + } } } } @@ -882,35 +914,36 @@ func TestFloatFloat64(t *testing.T) { out float64 acc Accuracy }{ - {"-Inf", math.Inf(-1), Exact}, - {"-0x1.fffffffffffff8p2147483646", -math.Inf(+1), Below}, // overflow in rounding - {"-1e10000", math.Inf(-1), Below}, // overflow - {"-0x1p1024", math.Inf(-1), Below}, // overflow - {"-0x1.fffffffffffff8p1023", -math.Inf(+1), Below}, // overflow - {"-0x1.fffffffffffff4p1023", -math.MaxFloat64, Above}, - {"-0x1.fffffffffffff0p1023", -math.MaxFloat64, Exact}, - {"-12345.000000000000000000001", -12345, Above}, - {"-12345.0", -12345, Exact}, - {"-1.000000000000000000001", -1, Above}, - {"-1", -1, Exact}, - {"-0x0.0000000000001p-1022", -math.SmallestNonzeroFloat64, Exact}, - {"-0x0.0000000000001p-1023", -0, Above}, // underflow - {"-1e-1000", -0, Above}, // underflow {"0", 0, Exact}, - {"1e-1000", 0, Below}, // underflow - {"0x0.0000000000001p-1023", 0, Below}, // underflow - {"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact}, + + // underflow + {"1e-1000", 0, Below}, + {"0x0.0000000000001p-1023", 0, Below}, + {"0x0.00000000000008p-1022", 0, Below}, + + // denormals + {"0x0.0000000000000cp-1022", math.SmallestNonzeroFloat64, Above}, // rounded up to smallest denormal + {"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact}, // smallest denormal + {"0x.8p-1073", math.SmallestNonzeroFloat64, Exact}, + {"1p-1074", math.SmallestNonzeroFloat64, Exact}, + {"0x.fffffffffffffp-1022", math.Float64frombits(0x000fffffffffffff), Exact}, // largest denormal + + // normals + {"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal + {"1p-1022", math.Float64frombits(0x0010000000000000), Exact}, // smallest normal {"1", 1, Exact}, {"1.000000000000000000001", 1, Below}, {"12345.0", 12345, Exact}, {"12345.000000000000000000001", 12345, Below}, {"0x1.fffffffffffff0p1023", math.MaxFloat64, Exact}, {"0x1.fffffffffffff4p1023", math.MaxFloat64, Below}, - {"0x1.fffffffffffff8p1023", math.Inf(+1), Above}, // overflow - {"0x1p1024", math.Inf(+1), Above}, // overflow - {"1e10000", math.Inf(+1), Above}, // overflow + + // overflow + {"0x1.fffffffffffff8p1023", math.Inf(+1), Above}, + {"0x1p1024", math.Inf(+1), Above}, + {"1e10000", math.Inf(+1), Above}, {"0x1.fffffffffffff8p2147483646", math.Inf(+1), Above}, // overflow in rounding - {"+Inf", math.Inf(+1), Exact}, + {"Inf", math.Inf(+1), Exact}, // selected denormalized values that were handled incorrectly in the past {"0x.fffffffffffffp-1022", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact}, @@ -921,22 +954,32 @@ func TestFloatFloat64(t *testing.T) { // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ {"2.2250738585072012e-308", 2.2250738585072014e-308, Above}, } { - // conversion should match strconv where syntax is agreeable - if f, err := strconv.ParseFloat(test.x, 64); err == nil && f != test.out { - t.Errorf("%s: got %g; want %g (incorrect test data)", test.x, f, test.out) - } + for i := 0; i < 2; i++ { + // test both signs + tx, tout, tacc := test.x, test.out, test.acc + if i != 0 { + tx = "-" + tx + tout = -tout + tacc = -tacc + } - x := makeFloat(test.x) - out, acc := x.Float64() - if out != test.out || acc != test.acc { - t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", test.x, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), test.acc) - } + // conversion should match strconv where syntax is agreeable + if f, err := strconv.ParseFloat(tx, 64); err == nil && !alike64(f, tout) { + t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout) + } - // test that x.SetFloat64(f).Float64() == f - var x2 Float - out2, acc2 := x2.SetFloat64(out).Float64() - if out2 != out || acc2 != Exact { - t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out) + x := makeFloat(tx) + out, acc := x.Float64() + if !alike64(out, tout) || acc != tacc { + t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc) + } + + // test that x.SetFloat64(f).Float64() == f + var x2 Float + out2, acc2 := x2.SetFloat64(out).Float64() + if !alike64(out2, out) || acc2 != Exact { + t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out) + } } } } @@ -1656,7 +1699,7 @@ func TestFloatCmpSpecialValues(t *testing.T) { want = +1 } if got != want { - t.Errorf("(%g).Cmp(%g) = %s; want %s", x, y, got, want) + t.Errorf("(%g).Cmp(%g) = %v; want %v", x, y, got, want) } } } diff --git a/src/cmd/internal/gc/big/floatconv.go b/src/cmd/compile/internal/big/floatconv.go index b929d1202c..b929d1202c 100644 --- a/src/cmd/internal/gc/big/floatconv.go +++ b/src/cmd/compile/internal/big/floatconv.go diff --git a/src/cmd/internal/gc/big/floatconv_test.go b/src/cmd/compile/internal/big/floatconv_test.go index 96c01eed81..96c01eed81 100644 --- a/src/cmd/internal/gc/big/floatconv_test.go +++ b/src/cmd/compile/internal/big/floatconv_test.go diff --git a/src/cmd/internal/gc/big/floatexample_test.go b/src/cmd/compile/internal/big/floatexample_test.go index 7db10238bc..0ac9617c06 100644 --- a/src/cmd/internal/gc/big/floatexample_test.go +++ b/src/cmd/compile/internal/big/floatexample_test.go @@ -5,9 +5,9 @@ package big_test import ( + "cmd/compile/internal/big" "fmt" "math" - "math/big" ) func ExampleFloat_Add() { diff --git a/src/cmd/internal/gc/big/ftoa.go b/src/cmd/compile/internal/big/ftoa.go index 0a9edfd7b2..0a9edfd7b2 100644 --- a/src/cmd/internal/gc/big/ftoa.go +++ b/src/cmd/compile/internal/big/ftoa.go diff --git a/src/cmd/internal/gc/big/gcd_test.go b/src/cmd/compile/internal/big/gcd_test.go index c0b9f58300..c0b9f58300 100644 --- a/src/cmd/internal/gc/big/gcd_test.go +++ b/src/cmd/compile/internal/big/gcd_test.go diff --git a/src/cmd/internal/gc/big/hilbert_test.go b/src/cmd/compile/internal/big/hilbert_test.go index 1a84341b3c..1a84341b3c 100644 --- a/src/cmd/internal/gc/big/hilbert_test.go +++ b/src/cmd/compile/internal/big/hilbert_test.go diff --git a/src/cmd/internal/gc/big/int.go b/src/cmd/compile/internal/big/int.go index 7b419bf688..5e3125375b 100644 --- a/src/cmd/internal/gc/big/int.go +++ b/src/cmd/compile/internal/big/int.go @@ -583,6 +583,124 @@ func (z *Int) ModInverse(g, n *Int) *Int { return z } +// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0. +// The y argument must be an odd integer. +func Jacobi(x, y *Int) int { + if len(y.abs) == 0 || y.abs[0]&1 == 0 { + panic(fmt.Sprintf("big: invalid 2nd argument to Int.Jacobi: need odd integer but got %s", y)) + } + + // We use the formulation described in chapter 2, section 2.4, + // "The Yacas Book of Algorithms": + // http://yacas.sourceforge.net/Algo.book.pdf + + var a, b, c Int + a.Set(x) + b.Set(y) + j := 1 + + if b.neg { + if a.neg { + j = -1 + } + b.neg = false + } + + for { + if b.Cmp(intOne) == 0 { + return j + } + if len(a.abs) == 0 { + return 0 + } + a.Mod(&a, &b) + if len(a.abs) == 0 { + return 0 + } + // a > 0 + + // handle factors of 2 in 'a' + s := a.abs.trailingZeroBits() + if s&1 != 0 { + bmod8 := b.abs[0] & 7 + if bmod8 == 3 || bmod8 == 5 { + j = -j + } + } + c.Rsh(&a, s) // a = 2^s*c + + // swap numerator and denominator + if b.abs[0]&3 == 3 && c.abs[0]&3 == 3 { + j = -j + } + a.Set(&b) + b.Set(&c) + } +} + +// ModSqrt sets z to a square root of x mod p if such a square root exists, and +// returns z. The modulus p must be an odd prime. If x is not a square mod p, +// ModSqrt leaves z unchanged and returns nil. This function panics if p is +// not an odd integer. +func (z *Int) ModSqrt(x, p *Int) *Int { + switch Jacobi(x, p) { + case -1: + return nil // x is not a square mod p + case 0: + return z.SetInt64(0) // sqrt(0) mod p = 0 + case 1: + break + } + if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p + x = new(Int).Mod(x, p) + } + + // Break p-1 into s*2^e such that s is odd. + var s Int + s.Sub(p, intOne) + e := s.abs.trailingZeroBits() + s.Rsh(&s, e) + + // find some non-square n + var n Int + n.SetInt64(2) + for Jacobi(&n, p) != -1 { + n.Add(&n, intOne) + } + + // Core of the Tonelli-Shanks algorithm. Follows the description in + // section 6 of "Square roots from 1; 24, 51, 10 to Dan Shanks" by Ezra + // Brown: + // https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf + var y, b, g, t Int + y.Add(&s, intOne) + y.Rsh(&y, 1) + y.Exp(x, &y, p) // y = x^((s+1)/2) + b.Exp(x, &s, p) // b = x^s + g.Exp(&n, &s, p) // g = n^s + r := e + for { + // find the least m such that ord_p(b) = 2^m + var m uint + t.Set(&b) + for t.Cmp(intOne) != 0 { + t.Mul(&t, &t).Mod(&t, p) + m++ + } + + if m == 0 { + return z.Set(&y) + } + + t.SetInt64(0).SetBit(&t, int(r-m-1), 1).Exp(&g, &t, p) + // t = g^(2^(r-m-1)) mod p + g.Mul(&t, &t).Mod(&g, p) // g = g^(2^(r-m)) mod p + y.Mul(&y, &t).Mod(&y, p) + b.Mul(&b, &g).Mod(&b, p) + r = m + } +} + // Lsh sets z = x << n and returns z. func (z *Int) Lsh(x *Int, n uint) *Int { z.abs = z.abs.shl(x.abs, n) diff --git a/src/cmd/internal/gc/big/int_test.go b/src/cmd/compile/internal/big/int_test.go index a972a7249b..c19e88addb 100644 --- a/src/cmd/internal/gc/big/int_test.go +++ b/src/cmd/compile/internal/big/int_test.go @@ -525,6 +525,7 @@ var expTests = []struct { {"1234", "-1", "1", "0"}, // misc + {"5", "1", "3", "2"}, {"5", "-7", "", "1"}, {"-5", "-7", "", "1"}, {"5", "0", "", "1"}, @@ -703,6 +704,13 @@ var primes = []string{ "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593", "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993", "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123", + + // ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02 + "3618502788666131106986593281521497120414687020801267626233049500247285301239", // Curve1174: 2^251-9 + "57896044618658097711785492504343953926634992332820282019728792003956564819949", // Curve25519: 2^255-19 + "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599", // E-382: 2^382-105 + "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367", // Curve41417: 2^414-17 + "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1 } var composites = []string{ @@ -1248,6 +1256,136 @@ func TestModInverse(t *testing.T) { } } +// testModSqrt is a helper for TestModSqrt, +// which checks that ModSqrt can compute a square-root of elt^2. +func testModSqrt(t *testing.T, elt, mod, sq, sqrt *Int) bool { + var sqChk, sqrtChk, sqrtsq Int + sq.Mul(elt, elt) + sq.Mod(sq, mod) + z := sqrt.ModSqrt(sq, mod) + if z != sqrt { + t.Errorf("ModSqrt returned wrong value %s", z) + } + + // test ModSqrt arguments outside the range [0,mod) + sqChk.Add(sq, mod) + z = sqrtChk.ModSqrt(&sqChk, mod) + if z != &sqrtChk || z.Cmp(sqrt) != 0 { + t.Errorf("ModSqrt returned inconsistent value %s", z) + } + sqChk.Sub(sq, mod) + z = sqrtChk.ModSqrt(&sqChk, mod) + if z != &sqrtChk || z.Cmp(sqrt) != 0 { + t.Errorf("ModSqrt returned inconsistent value %s", z) + } + + // make sure we actually got a square root + if sqrt.Cmp(elt) == 0 { + return true // we found the "desired" square root + } + sqrtsq.Mul(sqrt, sqrt) // make sure we found the "other" one + sqrtsq.Mod(&sqrtsq, mod) + return sq.Cmp(&sqrtsq) == 0 +} + +func TestModSqrt(t *testing.T) { + var elt, mod, modx4, sq, sqrt Int + r := rand.New(rand.NewSource(9)) + for i, s := range primes[1:] { // skip 2, use only odd primes + mod.SetString(s, 10) + modx4.Lsh(&mod, 2) + + // test a few random elements per prime + for x := 1; x < 5; x++ { + elt.Rand(r, &modx4) + elt.Sub(&elt, &mod) // test range [-mod, 3*mod) + if !testModSqrt(t, &elt, &mod, &sq, &sqrt) { + t.Errorf("#%d: failed (sqrt(e) = %s)", i, &sqrt) + } + } + } + + // exhaustive test for small values + for n := 3; n < 100; n++ { + mod.SetInt64(int64(n)) + if !mod.ProbablyPrime(10) { + continue + } + isSquare := make([]bool, n) + + // test all the squares + for x := 1; x < n; x++ { + elt.SetInt64(int64(x)) + if !testModSqrt(t, &elt, &mod, &sq, &sqrt) { + t.Errorf("#%d: failed (sqrt(%d,%d) = %s)", x, &elt, &mod, &sqrt) + } + isSquare[sq.Uint64()] = true + } + + // test all non-squares + for x := 1; x < n; x++ { + sq.SetInt64(int64(x)) + z := sqrt.ModSqrt(&sq, &mod) + if !isSquare[x] && z != nil { + t.Errorf("#%d: failed (sqrt(%d,%d) = nil)", x, &sqrt, &mod) + } + } + } +} + +func TestJacobi(t *testing.T) { + testCases := []struct { + x, y int64 + result int + }{ + {0, 1, 1}, + {0, -1, 1}, + {1, 1, 1}, + {1, -1, 1}, + {0, 5, 0}, + {1, 5, 1}, + {2, 5, -1}, + {-2, 5, -1}, + {2, -5, -1}, + {-2, -5, 1}, + {3, 5, -1}, + {5, 5, 0}, + {-5, 5, 0}, + {6, 5, 1}, + {6, -5, 1}, + {-6, 5, 1}, + {-6, -5, -1}, + } + + var x, y Int + + for i, test := range testCases { + x.SetInt64(test.x) + y.SetInt64(test.y) + expected := test.result + actual := Jacobi(&x, &y) + if actual != expected { + t.Errorf("#%d: Jacobi(%d, %d) = %d, but expected %d", i, test.x, test.y, actual, expected) + } + } +} + +func TestJacobiPanic(t *testing.T) { + const failureMsg = "test failure" + defer func() { + msg := recover() + if msg == nil || msg == failureMsg { + panic(msg) + } + t.Log(msg) + }() + x := NewInt(1) + y := NewInt(2) + // Jacobi should panic when the second argument is even. + Jacobi(x, y) + panic(failureMsg) +} + var encodingTests = []string{ "-539345864568634858364538753846587364875430589374589", "-678645873", diff --git a/src/cmd/internal/gc/big/intconv.go b/src/cmd/compile/internal/big/intconv.go index 9c68a22bed..9c68a22bed 100644 --- a/src/cmd/internal/gc/big/intconv.go +++ b/src/cmd/compile/internal/big/intconv.go diff --git a/src/cmd/internal/gc/big/intconv_test.go b/src/cmd/compile/internal/big/intconv_test.go index 2deb84b48f..2deb84b48f 100644 --- a/src/cmd/internal/gc/big/intconv_test.go +++ b/src/cmd/compile/internal/big/intconv_test.go diff --git a/src/cmd/internal/gc/big/nat.go b/src/cmd/compile/internal/big/nat.go index 2a279d186c..c3eef76fa1 100644 --- a/src/cmd/internal/gc/big/nat.go +++ b/src/cmd/compile/internal/big/nat.go @@ -216,6 +216,34 @@ func basicMul(z, x, y nat) { } } +// montgomery computes x*y*2^(-n*_W) mod m, +// assuming k = -1/m mod 2^_W. +// z is used for storing the result which is returned; +// z must not alias x, y or m. +func (z nat) montgomery(x, y, m nat, k Word, n int) nat { + var c1, c2 Word + z = z.make(n) + z.clear() + for i := 0; i < n; i++ { + d := y[i] + c1 += addMulVVW(z, x, d) + t := z[0] * k + c2 = addMulVVW(z, m, t) + + copy(z, z[1:]) + z[n-1] = c1 + c2 + if z[n-1] < c1 { + c1 = 1 + } else { + c1 = 0 + } + } + if c1 != 0 { + subVV(z, z, m) + } + return z +} + // Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks. // Factored out for readability - do not use outside karatsuba. func karatsubaAdd(z, x nat, n int) { @@ -888,6 +916,13 @@ func (z nat) expNN(x, y, m nat) nat { } // y > 0 + // x**1 mod m == x mod m + if len(y) == 1 && y[0] == 1 && len(m) != 0 { + _, z = z.div(z, x, m) + return z + } + // y > 1 + if len(m) != 0 { // We likely end up being as long as the modulus. z = z.make(len(m)) @@ -898,8 +933,11 @@ func (z nat) expNN(x, y, m nat) nat { // 4-bit, windowed exponentiation. This involves precomputing 14 values // (x^2...x^15) but then reduces the number of multiply-reduces by a // third. Even for a 32-bit exponent, this reduces the number of - // operations. + // operations. Uses Montgomery method for odd moduli. if len(x) > 1 && len(y) > 1 && len(m) > 0 { + if m[0]&1 == 1 { + return z.expNNMontgomery(x, y, m) + } return z.expNNWindowed(x, y, m) } @@ -1022,6 +1060,87 @@ func (z nat) expNNWindowed(x, y, m nat) nat { return z.norm() } +// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window. +// Uses Montgomery representation. +func (z nat) expNNMontgomery(x, y, m nat) nat { + var zz, one, rr, RR nat + + numWords := len(m) + + // We want the lengths of x and m to be equal. + if len(x) > numWords { + _, rr = rr.div(rr, x, m) + } else if len(x) < numWords { + rr = rr.make(numWords) + rr.clear() + for i := range x { + rr[i] = x[i] + } + } else { + rr = x + } + x = rr + + // Ideally the precomputations would be performed outside, and reused + // k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson + // Iteration for Multiplicative Inverses Modulo Prime Powers". + k0 := 2 - m[0] + t := m[0] - 1 + for i := 1; i < _W; i <<= 1 { + t *= t + k0 *= (t + 1) + } + k0 = -k0 + + // RR = 2ˆ(2*_W*len(m)) mod m + RR = RR.setWord(1) + zz = zz.shl(RR, uint(2*numWords*_W)) + _, RR = RR.div(RR, zz, m) + if len(RR) < numWords { + zz = zz.make(numWords) + copy(zz, RR) + RR = zz + } + // one = 1, with equal length to that of m + one = one.make(numWords) + one.clear() + one[0] = 1 + + const n = 4 + // powers[i] contains x^i + var powers [1 << n]nat + powers[0] = powers[0].montgomery(one, RR, m, k0, numWords) + powers[1] = powers[1].montgomery(x, RR, m, k0, numWords) + for i := 2; i < 1<<n; i++ { + powers[i] = powers[i].montgomery(powers[i-1], powers[1], m, k0, numWords) + } + + // initialize z = 1 (Montgomery 1) + z = z.make(numWords) + copy(z, powers[0]) + + zz = zz.make(numWords) + + // same windowed exponent, but with Montgomery multiplications + for i := len(y) - 1; i >= 0; i-- { + yi := y[i] + for j := 0; j < _W; j += n { + if i != len(y)-1 || j != 0 { + zz = zz.montgomery(z, z, m, k0, numWords) + z = z.montgomery(zz, zz, m, k0, numWords) + zz = zz.montgomery(z, z, m, k0, numWords) + z = z.montgomery(zz, zz, m, k0, numWords) + } + zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords) + z, zz = zz, z + yi <<= n + } + } + // convert to regular number + zz = zz.montgomery(z, one, m, k0, numWords) + return zz.norm() +} + // probablyPrime performs reps Miller-Rabin tests to check whether n is prime. // If it returns true, n is prime with probability 1 - 1/4^reps. // If it returns false, n is not prime. diff --git a/src/cmd/internal/gc/big/nat_test.go b/src/cmd/compile/internal/big/nat_test.go index b25a89f731..a15a2bcac0 100644 --- a/src/cmd/internal/gc/big/nat_test.go +++ b/src/cmd/compile/internal/big/nat_test.go @@ -332,6 +332,67 @@ func TestTrailingZeroBits(t *testing.T) { } } +var montgomeryTests = []struct { + x, y, m string + k0 uint64 + out32, out64 string +}{ + { + "0xffffffffffffffffffffffffffffffffffffffffffffffffe", + "0xffffffffffffffffffffffffffffffffffffffffffffffffe", + "0xfffffffffffffffffffffffffffffffffffffffffffffffff", + 0x0000000000000000, + "0xffffffffffffffffffffffffffffffffffffffffff", + "0xffffffffffffffffffffffffffffffffff", + }, + { + "0x0000000080000000", + "0x00000000ffffffff", + "0x0000000010000001", + 0xff0000000fffffff, + "0x0000000088000000", + "0x0000000007800001", + }, + { + "0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444", + "0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc", + "0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1", + 0xdecc8f1249812adf, + "0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79", + "0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd", + }, + { + "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444", + "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1", + 0xdecc8f1249812adf, + "0x5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d7a11c7772cba02c22f9711078d51a3797eb18e691295293284d988e349fa6deba46b25a4ecd9f715", + "0x92fcad4b5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d799c32fe2f3cc5422f9711078d51a3797eb18e691295293284d8f5e69caf6decddfe1df6", + }, +} + +func TestMontgomery(t *testing.T) { + for i, test := range montgomeryTests { + x := natFromString(test.x) + y := natFromString(test.y) + m := natFromString(test.m) + + var out nat + if _W == 32 { + out = natFromString(test.out32) + } else { + out = natFromString(test.out64) + } + + k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems. + z := nat(nil).montgomery(x, y, m, k0, len(m)) + z = z.norm() + if z.cmp(out) != 0 { + t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString()) + } + } +} + var expNNTests = []struct { x, y, m string out string diff --git a/src/cmd/internal/gc/big/natconv.go b/src/cmd/compile/internal/big/natconv.go index 022dcfe38c..022dcfe38c 100644 --- a/src/cmd/internal/gc/big/natconv.go +++ b/src/cmd/compile/internal/big/natconv.go diff --git a/src/cmd/internal/gc/big/natconv_test.go b/src/cmd/compile/internal/big/natconv_test.go index f321fbc2df..f321fbc2df 100644 --- a/src/cmd/internal/gc/big/natconv_test.go +++ b/src/cmd/compile/internal/big/natconv_test.go diff --git a/src/cmd/internal/gc/big/rat.go b/src/cmd/compile/internal/big/rat.go index fb16f18a96..fb16f18a96 100644 --- a/src/cmd/internal/gc/big/rat.go +++ b/src/cmd/compile/internal/big/rat.go diff --git a/src/cmd/internal/gc/big/rat_test.go b/src/cmd/compile/internal/big/rat_test.go index 012d0c47ec..012d0c47ec 100644 --- a/src/cmd/internal/gc/big/rat_test.go +++ b/src/cmd/compile/internal/big/rat_test.go diff --git a/src/cmd/internal/gc/big/ratconv.go b/src/cmd/compile/internal/big/ratconv.go index 778077b96e..778077b96e 100644 --- a/src/cmd/internal/gc/big/ratconv.go +++ b/src/cmd/compile/internal/big/ratconv.go diff --git a/src/cmd/internal/gc/big/ratconv_test.go b/src/cmd/compile/internal/big/ratconv_test.go index 16b3a19418..16b3a19418 100644 --- a/src/cmd/internal/gc/big/ratconv_test.go +++ b/src/cmd/compile/internal/big/ratconv_test.go diff --git a/src/cmd/internal/gc/big/roundingmode_string.go b/src/cmd/compile/internal/big/roundingmode_string.go index 05024b8065..05024b8065 100644 --- a/src/cmd/internal/gc/big/roundingmode_string.go +++ b/src/cmd/compile/internal/big/roundingmode_string.go diff --git a/src/cmd/internal/gc/big/vendor.bash b/src/cmd/compile/internal/big/vendor.bash index 84aa750462..1b191ccb8f 100755 --- a/src/cmd/internal/gc/big/vendor.bash +++ b/src/cmd/compile/internal/big/vendor.bash @@ -15,9 +15,15 @@ rm *.go cp $BIGDIR/*.go . # Use pure Go arith ops w/o build tag. -sed 's/^\/\/ \+build math_big_pure_go$//' arith_decl_pure.go > arith_decl.go +sed 's|^// \+build math_big_pure_go$||' arith_decl_pure.go > arith_decl.go rm arith_decl_pure.go +# Import vendored math/big in external tests (e.g., floatexample_test.go). +for f in *_test.go; do + sed 's|"math/big"|"cmd/compile/internal/big"|' $f > foo.go + mv foo.go $f +done + # gofmt to clean up after sed gofmt -w . diff --git a/src/cmd/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go index 789e59bfd0..892595a214 100644 --- a/src/cmd/internal/gc/align.go +++ b/src/cmd/compile/internal/gc/align.go @@ -71,8 +71,8 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 { // 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 != nil { - f.Nname.Stackparam.Xoffset = o + if f.Nname.Param.Stackparam != nil { + f.Nname.Param.Stackparam.Xoffset = o f.Nname.Xoffset = 0 } else { f.Nname.Xoffset = o diff --git a/src/cmd/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 6bdf78c8ab..6bdf78c8ab 100644 --- a/src/cmd/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go diff --git a/src/cmd/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index 179a4ddd9a..179a4ddd9a 100644 --- a/src/cmd/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go diff --git a/src/cmd/internal/gc/builtin/unsafe.go b/src/cmd/compile/internal/gc/builtin/unsafe.go index ce508692eb..ce508692eb 100644 --- a/src/cmd/internal/gc/builtin/unsafe.go +++ b/src/cmd/compile/internal/gc/builtin/unsafe.go diff --git a/src/cmd/internal/gc/bv.go b/src/cmd/compile/internal/gc/bv.go index 2b988e6547..2b988e6547 100644 --- a/src/cmd/internal/gc/bv.go +++ b/src/cmd/compile/internal/gc/bv.go diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go index 501cdcb1c8..ca58b1c6a3 100644 --- a/src/cmd/internal/gc/cgen.go +++ b/src/cmd/compile/internal/gc/cgen.go @@ -43,14 +43,7 @@ func cgen_wb(n, res *Node, wb bool) { switch n.Op { case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: - if res.Op != ONAME || !res.Addable || wb { - var n1 Node - Tempname(&n1, n.Type) - Cgen_slice(n, &n1) - cgen_wb(&n1, res, wb) - } else { - Cgen_slice(n, res) - } + cgen_slice(n, res, wb) return case OEFACE: @@ -67,6 +60,10 @@ func cgen_wb(n, res *Node, wb bool) { case ODOTTYPE: cgen_dottype(n, res, nil, wb) return + + case OAPPEND: + cgen_append(n, res) + return } if n.Ullman >= UINF { @@ -545,7 +542,7 @@ func cgen_wb(n, res *Node, wb bool) { var n1 Node Regalloc(&n1, Types[Tptr], res) p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1) - Datastring(nl.Val.U.Sval, &p1.From) + Datastring(nl.Val.U.(string), &p1.From) p1.From.Type = obj.TYPE_ADDR Thearch.Gmove(&n1, res) Regfree(&n1) @@ -569,8 +566,7 @@ func cgen_wb(n, res *Node, wb bool) { var n2 Node Nodconst(&n2, Types[Tptr], 0) - Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2) - p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0) + p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 0) n2 = n1 n2.Op = OINDREG @@ -610,8 +606,7 @@ func cgen_wb(n, res *Node, wb bool) { var n2 Node Nodconst(&n2, Types[Tptr], 0) - Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2) - p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0) + p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 0) n2 = n1 n2.Op = OINDREG @@ -790,6 +785,9 @@ abop: // asymmetric binary var sys_wbptr *Node func cgen_wbptr(n, res *Node) { + if Curfn != nil && Curfn.Func.Nowritebarrier { + Yyerror("write barrier prohibited") + } if Debug_wb > 0 { Warn("write barrier") } @@ -804,19 +802,7 @@ func cgen_wbptr(n, res *Node) { } wbEnabled := syslook("writeBarrierEnabled", 0) - switch Ctxt.Arch.Thechar { - default: - Fatal("cgen_wbptr: unknown architecture") - case '5', '7', '9': - var tmp Node - Regalloc(&tmp, Types[TUINT8], nil) - Thearch.Gmove(wbEnabled, &tmp) - Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT8]), &tmp, Nodintconst(0)) - Regfree(&tmp) - case '6', '8': - Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT8]), wbEnabled, Nodintconst(0)) - } - pbr := Gbranch(Thearch.Optoas(ONE, Types[TUINT8]), nil, -1) + pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1) Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst) pjmp := Gbranch(obj.AJMP, nil, 0) Patch(pbr, Pc) @@ -845,6 +831,9 @@ func cgen_wbptr(n, res *Node) { } func cgen_wbfat(n, res *Node) { + if Curfn != nil && Curfn.Func.Nowritebarrier { + Yyerror("write barrier prohibited") + } if Debug_wb > 0 { Warn("write barrier") } @@ -1047,7 +1036,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Fatal("constant string constant index") } - v := uint64(Mpgetfix(nr.Val.U.Xval)) + v := uint64(Mpgetfix(nr.Val.U.(*Mpint))) var n2 Node if Isslice(nl.Type) || nl.Type.Etype == TSTRING { if Debug['B'] == 0 && !n.Bounded { @@ -1055,14 +1044,9 @@ func Agenr(n *Node, a *Node, res *Node) { n1.Op = OINDREG n1.Type = Types[Tptr] n1.Xoffset = int64(Array_nel) - var n4 Node - Regalloc(&n4, n1.Type, nil) - Thearch.Gmove(&n1, &n4) Nodconst(&n2, Types[TUINT32], int64(v)) - Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n4, &n2) - Regfree(&n4) - p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1) - Ginscall(Panicindex, 0) + p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &n1, &n2, +1) + Ginscall(Panicindex, -1) Patch(p1, Pc) } @@ -1088,7 +1072,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Debug['B'] == 0 && !n.Bounded { // check bounds if Isconst(nl, CTSTR) { - Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.Sval))) + Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.(string)))) } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { n1 = n3 n1.Op = OINDREG @@ -1099,23 +1083,21 @@ func Agenr(n *Node, a *Node, res *Node) { } else { Nodconst(&n4, Types[TUINT32], nl.Type.Bound) } - - Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n2, &n4) + p1 := Thearch.Ginscmp(OLT, Types[TUINT32], &n2, &n4, +1) if n4.Op == OREGISTER { Regfree(&n4) } - p1 := Gbranch(Thearch.Optoas(OLT, Types[TUINT32]), nil, +1) if p2 != nil { Patch(p2, Pc) } - Ginscall(Panicindex, 0) + Ginscall(Panicindex, -1) Patch(p1, Pc) } if Isconst(nl, CTSTR) { Regalloc(&n3, Types[Tptr], res) p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3) - Datastring(nl.Val.U.Sval, &p1.From) + Datastring(nl.Val.U.(string), &p1.From) p1.From.Type = obj.TYPE_ADDR } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { n1 = n3 @@ -1206,15 +1188,14 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Fatal("constant string constant index") // front end should handle } - v := uint64(Mpgetfix(nr.Val.U.Xval)) + v := uint64(Mpgetfix(nr.Val.U.(*Mpint))) if Isslice(nl.Type) || nl.Type.Etype == TSTRING { if Debug['B'] == 0 && !n.Bounded { nlen := n3 nlen.Type = Types[TUINT32] nlen.Xoffset += int64(Array_nel) Nodconst(&n2, Types[TUINT32], int64(v)) - Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &nlen, &n2) - p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1) + p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &nlen, &n2, +1) Ginscall(Panicindex, -1) Patch(p1, Pc) } @@ -1252,7 +1233,7 @@ func Agenr(n *Node, a *Node, res *Node) { var nlen Node if Isconst(nl, CTSTR) { - Nodconst(&nlen, t, int64(len(nl.Val.U.Sval))) + Nodconst(&nlen, t, int64(len(nl.Val.U.(string)))) } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { nlen = n3 nlen.Type = t @@ -1261,8 +1242,7 @@ func Agenr(n *Node, a *Node, res *Node) { Nodconst(&nlen, t, nl.Type.Bound) } - Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen) - p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1) + p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1) if p2 != nil { Patch(p2, Pc) } @@ -1273,7 +1253,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Regalloc(&n3, Types[Tptr], res) p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3) - Datastring(nl.Val.U.Sval, &p1.From) + Datastring(nl.Val.U.(string), &p1.From) p1.From.Type = obj.TYPE_ADDR Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3) goto indexdone1 @@ -1398,28 +1378,10 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Fatal("constant string constant index") // front end should handle } - v := uint64(Mpgetfix(nr.Val.U.Xval)) + v := uint64(Mpgetfix(nr.Val.U.(*Mpint))) if Isslice(nl.Type) || nl.Type.Etype == TSTRING { if Debug['B'] == 0 && !n.Bounded { - if nlen.Op != OREGISTER && (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') { - var tmp2 Node - Regalloc(&tmp2, Types[Simtype[TUINT]], nil) - Thearch.Gmove(&nlen, &tmp2) - Regfree(&nlen) // in case it is OINDREG - nlen = tmp2 - } - var n2 Node - Nodconst(&n2, Types[Simtype[TUINT]], int64(v)) - if Smallintconst(nr) { - Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &n2) - } else { - Regalloc(&tmp, Types[Simtype[TUINT]], nil) - Thearch.Gmove(&n2, &tmp) - Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &tmp) - Regfree(&tmp) - } - - p1 := Gbranch(Thearch.Optoas(OGT, Types[Simtype[TUINT]]), nil, +1) + p1 := Thearch.Ginscmp(OGT, Types[Simtype[TUINT]], &nlen, Nodintconst(int64(v)), +1) Ginscall(Panicindex, -1) Patch(p1, Pc) } @@ -1454,28 +1416,14 @@ func Agenr(n *Node, a *Node, res *Node) { t = Types[TUINT64] } if Isconst(nl, CTSTR) { - Nodconst(&nlen, t, int64(len(nl.Val.U.Sval))) + Nodconst(&nlen, t, int64(len(nl.Val.U.(string)))) } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { - if Is64(nr.Type) || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { - var n5 Node - Regalloc(&n5, t, nil) - Thearch.Gmove(&nlen, &n5) - Regfree(&nlen) - nlen = n5 - } + // nlen already initialized } else { Nodconst(&nlen, t, nl.Type.Bound) - if !Smallintconst(&nlen) { - var n5 Node - Regalloc(&n5, t, nil) - Thearch.Gmove(&nlen, &n5) - nlen = n5 - freelen = 1 - } } - Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen) - p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1) + p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1) Ginscall(Panicindex, -1) Patch(p1, Pc) } @@ -1483,7 +1431,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Regalloc(&n3, Types[Tptr], res) p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ! - Datastring(nl.Val.U.Sval, &p1.From) + Datastring(nl.Val.U.(string), &p1.From) p1.From.Type = obj.TYPE_ADDR Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3) goto indexdone @@ -1637,7 +1585,7 @@ func Agen(n *Node, res *Node) { Fatal("agen: bad ONAME class %#x", n.Class) } - Cgen(n.Heapaddr, res) + Cgen(n.Name.Heapaddr, res) if n.Xoffset != 0 { addOffset(res, n.Xoffset) } @@ -1770,7 +1718,7 @@ func Igen(n *Node, a *Node, res *Node) { // Compute &a[i] as &a + i*width. a.Type = n.Type - a.Xoffset += Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width + a.Xoffset += Mpgetfix(n.Right.Val.U.(*Mpint)) * n.Type.Width Fixlargeoffset(a) return } @@ -1920,11 +1868,11 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { Fatal("bgen: non-bool const %v\n", Nconv(n, obj.FmtLong)) } if genval { - Cgen(Nodbool(wantTrue == n.Val.U.Bval), res) + Cgen(Nodbool(wantTrue == n.Val.U.(bool)), res) return } // If n == wantTrue, jump; otherwise do nothing. - if wantTrue == n.Val.U.Bval { + if wantTrue == n.Val.U.(bool) { Patch(Gbranch(obj.AJMP, nil, likely), to) } return @@ -2214,14 +2162,27 @@ func bins(typ *Type, res *Node, a, likely int, to *obj.Prog) { } } -/* - * n is on stack, either local variable - * or return value from function call. - * return n's offset from SP. - */ +// stkof returns n's offset from SP if n is on the stack +// (either a local variable or the return value from a function call +// or the arguments to a function call). +// If n is not on the stack, stkof returns -1000. +// If n is on the stack but in an unknown location +// (due to array index arithmetic), stkof returns +1000. +// +// NOTE(rsc): It is possible that the ODOT and OINDEX cases +// are not relevant here, since it shouldn't be possible for them +// to be involved in an overlapping copy. Only function results +// from one call and the arguments to the next can overlap in +// any non-trivial way. If they can be dropped, then this function +// becomes much simpler and also more trustworthy. +// The fact that it works at all today is probably due to the fact +// that ODOT and OINDEX are irrelevant. func stkof(n *Node) int64 { switch n.Op { case OINDREG: + if n.Reg != int16(Thearch.REGSP) { + return -1000 // not on stack + } return n.Xoffset case ODOT: @@ -2230,7 +2191,7 @@ func stkof(n *Node) int64 { break } off := stkof(n.Left) - if off == -1000 || off == 1000 { + if off == -1000 || off == +1000 { return off } return off + n.Xoffset @@ -2241,13 +2202,13 @@ func stkof(n *Node) int64 { break } off := stkof(n.Left) - if off == -1000 || off == 1000 { + if off == -1000 || off == +1000 { return off } if Isconst(n.Right, CTINT) { - return off + t.Type.Width*Mpgetfix(n.Right.Val.U.Xval) + return off + t.Type.Width*Mpgetfix(n.Right.Val.U.(*Mpint)) } - return 1000 + return +1000 // on stack but not sure exactly where case OCALLMETH, OCALLINTER, OCALLFUNC: t := n.Left.Type @@ -2268,7 +2229,7 @@ func stkof(n *Node) int64 { // botch - probably failing to recognize address // arithmetic on the above. eg INDEX and DOT - return -1000 + return -1000 // not on stack } /* @@ -2446,8 +2407,7 @@ func Ginscall(f *Node, proc int) { if proc == 2 { Nodreg(®, Types[TINT32], Thearch.REGRETURN) - Thearch.Gins(Thearch.Optoas(OCMP, Types[TINT32]), ®, Nodintconst(0)) - p := Gbranch(Thearch.Optoas(OEQ, Types[TINT32]), nil, +1) + p := Thearch.Ginscmp(OEQ, Types[TINT32], ®, Nodintconst(0), +1) cgen_ret(nil) Patch(p, Pc) } @@ -2576,7 +2536,7 @@ func cgen_call(n *Node, proc int) { } // call direct - n.Left.Method = true + n.Left.Name.Method = true Ginscall(n.Left, proc) } @@ -2701,7 +2661,7 @@ func cgen_div(op int, nl *Node, nr *Node, res *Node) { case TUINT64: var m Magic m.W = w - m.Ud = uint64(Mpgetfix(nr.Val.U.Xval)) + m.Ud = uint64(Mpgetfix(nr.Val.U.(*Mpint))) Umagic(&m) if m.Bad != 0 { break @@ -2739,7 +2699,7 @@ func cgen_div(op int, nl *Node, nr *Node, res *Node) { case TINT64: var m Magic m.W = w - m.Sd = Mpgetfix(nr.Val.U.Xval) + m.Sd = Mpgetfix(nr.Val.U.(*Mpint)) Smagic(&m) if m.Bad != 0 { break @@ -2843,3 +2803,762 @@ func Fixlargeoffset(n *Node) { n.Xoffset = 0 } } + +func cgen_append(n, res *Node) { + if Debug['g'] != 0 { + Dump("cgen_append-n", n) + Dump("cgen_append-res", res) + } + if res.Op != ONAME && !samesafeexpr(res, n.List.N) { + Dump("cgen_append-n", n) + Dump("cgen_append-res", res) + Fatal("append not lowered") + } + for l := n.List; l != nil; l = l.Next { + if l.N.Ullman >= UINF { + Fatal("append with function call arguments") + } + } + + // res = append(src, x, y, z) + // + // If res and src are the same, we can avoid writing to base and cap + // unless we grow the underlying array. + needFullUpdate := !samesafeexpr(res, n.List.N) + + // Copy src triple into base, len, cap. + base := temp(Types[Tptr]) + len := temp(Types[TUINT]) + cap := temp(Types[TUINT]) + + var src Node + Igen(n.List.N, &src, nil) + src.Type = Types[Tptr] + Thearch.Gmove(&src, base) + src.Type = Types[TUINT] + src.Xoffset += int64(Widthptr) + Thearch.Gmove(&src, len) + src.Xoffset += int64(Widthptr) + Thearch.Gmove(&src, cap) + + // if len+argc <= cap goto L1 + var rlen Node + Regalloc(&rlen, Types[TUINT], nil) + Thearch.Gmove(len, &rlen) + Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(count(n.List)-1), &rlen) + p := Thearch.Ginscmp(OLE, Types[TUINT], &rlen, cap, +1) + // Note: rlen and src are Regrealloc'ed below at the target of the + // branch we just emitted; do not reuse these Go variables for + // other purposes. They need to still describe the same things + // below that they describe right here. + Regfree(&src) + + // base, len, cap = growslice(type, base, len, cap, newlen) + var arg Node + arg.Op = OINDREG + arg.Reg = int16(Thearch.REGSP) + arg.Addable = true + arg.Xoffset = 0 + if HasLinkRegister() { + arg.Xoffset = int64(Ctxt.Arch.Ptrsize) + } + arg.Type = Ptrto(Types[TUINT8]) + Cgen(typename(res.Type), &arg) + arg.Xoffset += int64(Widthptr) + + arg.Type = Types[Tptr] + Cgen(base, &arg) + arg.Xoffset += int64(Widthptr) + + arg.Type = Types[TUINT] + Cgen(len, &arg) + arg.Xoffset += int64(Widthptr) + + arg.Type = Types[TUINT] + Cgen(cap, &arg) + arg.Xoffset += int64(Widthptr) + + arg.Type = Types[TUINT] + Cgen(&rlen, &arg) + arg.Xoffset += int64(Widthptr) + Regfree(&rlen) + + fn := syslook("growslice", 1) + substArgTypes(fn, res.Type.Type, res.Type.Type) + Ginscall(fn, 0) + + if Widthptr == 4 && Widthreg == 8 { + arg.Xoffset += 4 + } + + arg.Type = Types[Tptr] + Cgen(&arg, base) + arg.Xoffset += int64(Widthptr) + + arg.Type = Types[TUINT] + Cgen(&arg, len) + arg.Xoffset += int64(Widthptr) + + arg.Type = Types[TUINT] + Cgen(&arg, cap) + + // Update res with base, len+argc, cap. + if needFullUpdate { + if Debug_append > 0 { + Warn("append: full update") + } + Patch(p, Pc) + } + if res.Op == ONAME { + Gvardef(res) + } + var dst, r1 Node + Igen(res, &dst, nil) + dst.Type = Types[TUINT] + dst.Xoffset += int64(Widthptr) + Regalloc(&r1, Types[TUINT], nil) + Thearch.Gmove(len, &r1) + Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(count(n.List)-1), &r1) + Thearch.Gmove(&r1, &dst) + Regfree(&r1) + dst.Xoffset += int64(Widthptr) + Thearch.Gmove(cap, &dst) + dst.Type = Types[Tptr] + dst.Xoffset -= 2 * int64(Widthptr) + cgen_wb(base, &dst, needwritebarrier(&dst, base)) + Regfree(&dst) + + if !needFullUpdate { + if Debug_append > 0 { + Warn("append: len-only update") + } + // goto L2; + // L1: + // update len only + // L2: + q := Gbranch(obj.AJMP, nil, 0) + Patch(p, Pc) + // At the goto above, src refers to cap and rlen holds the new len + if src.Op == OREGISTER || src.Op == OINDREG { + Regrealloc(&src) + } + Regrealloc(&rlen) + src.Xoffset -= int64(Widthptr) + Thearch.Gmove(&rlen, &src) + Regfree(&src) + Regfree(&rlen) + Patch(q, Pc) + } + + // Copy data into place. + // Could do write barrier check around entire copy instead of each element. + // Could avoid reloading registers on each iteration if we know the cgen_wb + // is not going to use a write barrier. + i := 0 + var r2 Node + for l := n.List.Next; l != nil; l = l.Next { + Regalloc(&r1, Types[Tptr], nil) + Thearch.Gmove(base, &r1) + Regalloc(&r2, Types[TUINT], nil) + Thearch.Gmove(len, &r2) + if i > 0 { + Thearch.Gins(Thearch.Optoas(OADD, Types[TUINT]), Nodintconst(int64(i)), &r2) + } + w := res.Type.Type.Width + if Thearch.AddIndex != nil && Thearch.AddIndex(&r2, w, &r1) { + // r1 updated by back end + } else if w == 1 { + Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1) + } else { + Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT]), int64(w), &r2) + Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1) + } + Regfree(&r2) + + r1.Op = OINDREG + r1.Type = res.Type.Type + cgen_wb(l.N, &r1, needwritebarrier(&r1, l.N)) + Regfree(&r1) + i++ + } +} + +// Generate res = n, where n is x[i:j] or x[i:j:k]. +// If wb is true, need write barrier updating res's base pointer. +// On systems with 32-bit ints, i, j, k are guaranteed to be 32-bit values. +func cgen_slice(n, res *Node, wb bool) { + if Debug['g'] != 0 { + Dump("cgen_slice-n", n) + Dump("cgen_slice-res", res) + } + + needFullUpdate := !samesafeexpr(n.Left, res) + + // orderexpr has made sure that x is safe (but possibly expensive) + // and i, j, k are cheap. On a system with registers (anything but 386) + // we can evaluate x first and then know we have enough registers + // for i, j, k as well. + var x, xbase, xlen, xcap, i, j, k Node + if n.Op != OSLICEARR && n.Op != OSLICE3ARR { + Igen(n.Left, &x, nil) + } + + indexRegType := Types[TUINT] + if Widthreg > Widthptr { // amd64p32 + indexRegType = Types[TUINT64] + } + + // On most systems, we use registers. + // The 386 has basically no registers, so substitute functions + // that can work with temporaries instead. + regalloc := Regalloc + ginscon := Thearch.Ginscon + gins := Thearch.Gins + if Thearch.Thechar == '8' { + regalloc = func(n *Node, t *Type, reuse *Node) { + Tempname(n, t) + } + ginscon = func(as int, c int64, n *Node) { + var n1 Node + Regalloc(&n1, n.Type, n) + Thearch.Gmove(n, &n1) + Thearch.Ginscon(as, c, &n1) + Thearch.Gmove(&n1, n) + Regfree(&n1) + } + gins = func(as int, f, t *Node) *obj.Prog { + var n1 Node + Regalloc(&n1, t.Type, t) + Thearch.Gmove(t, &n1) + Thearch.Gins(as, f, &n1) + Thearch.Gmove(&n1, t) + Regfree(&n1) + return nil + } + } + + panics := make([]*obj.Prog, 0, 6) // 3 loads + 3 checks + + loadlen := func() { + if xlen.Op != 0 { + return + } + if n.Op == OSLICEARR || n.Op == OSLICE3ARR { + Nodconst(&xlen, indexRegType, n.Left.Type.Type.Bound) + return + } + if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) { + Nodconst(&xlen, indexRegType, int64(len(n.Left.Val.U.(string)))) + return + } + regalloc(&xlen, indexRegType, nil) + x.Xoffset += int64(Widthptr) + x.Type = Types[TUINT] + Thearch.Gmove(&x, &xlen) + x.Xoffset -= int64(Widthptr) + } + + loadcap := func() { + if xcap.Op != 0 { + return + } + if n.Op == OSLICEARR || n.Op == OSLICE3ARR || n.Op == OSLICESTR { + loadlen() + xcap = xlen + if xcap.Op == OREGISTER { + Regrealloc(&xcap) + } + return + } + regalloc(&xcap, indexRegType, nil) + x.Xoffset += 2 * int64(Widthptr) + x.Type = Types[TUINT] + Thearch.Gmove(&x, &xcap) + x.Xoffset -= 2 * int64(Widthptr) + } + + var x1, x2, x3 *Node // unevaluated index arguments + x1 = n.Right.Left + switch n.Op { + default: + x2 = n.Right.Right + case OSLICE3, OSLICE3ARR: + x2 = n.Right.Right.Left + x3 = n.Right.Right.Right + } + + // load computes src into targ, but if src refers to the len or cap of n.Left, + // load copies those from xlen, xcap, loading xlen if needed. + // If targ.Op == OREGISTER on return, it must be Regfreed, + // but it should not be modified without first checking whether it is + // xlen or xcap's register. + load := func(src, targ *Node) { + if src == nil { + return + } + switch src.Op { + case OLITERAL: + *targ = *src + return + case OLEN: + // NOTE(rsc): This doesn't actually trigger, because order.go + // has pulled all the len and cap calls into separate assignments + // to temporaries. There are tests in test/sliceopt.go that could + // be enabled if this is fixed. + if samesafeexpr(n.Left, src.Left) { + if Debug_slice > 0 { + Warn("slice: reuse len") + } + loadlen() + *targ = xlen + if targ.Op == OREGISTER { + Regrealloc(targ) + } + return + } + case OCAP: + // NOTE(rsc): This doesn't actually trigger; see note in case OLEN above. + if samesafeexpr(n.Left, src.Left) { + if Debug_slice > 0 { + Warn("slice: reuse cap") + } + loadcap() + *targ = xcap + if targ.Op == OREGISTER { + Regrealloc(targ) + } + return + } + } + if i.Op != 0 && samesafeexpr(x1, src) { + if Debug_slice > 0 { + Warn("slice: reuse 1st index") + } + *targ = i + if targ.Op == OREGISTER { + Regrealloc(targ) + } + return + } + if j.Op != 0 && samesafeexpr(x2, src) { + if Debug_slice > 0 { + Warn("slice: reuse 2nd index") + } + *targ = j + if targ.Op == OREGISTER { + Regrealloc(targ) + } + return + } + if Thearch.Cgenindex != nil { + regalloc(targ, indexRegType, nil) + p := Thearch.Cgenindex(src, targ, false) + if p != nil { + panics = append(panics, p) + } + } else if Thearch.Igenindex != nil { + p := Thearch.Igenindex(src, targ, false) + if p != nil { + panics = append(panics, p) + } + } else { + regalloc(targ, indexRegType, nil) + var tmp Node + Cgenr(src, &tmp, targ) + Thearch.Gmove(&tmp, targ) + Regfree(&tmp) + } + } + + load(x1, &i) + load(x2, &j) + load(x3, &k) + + // i defaults to 0. + if i.Op == 0 { + Nodconst(&i, indexRegType, 0) + } + + // j defaults to len(x) + if j.Op == 0 { + loadlen() + j = xlen + if j.Op == OREGISTER { + Regrealloc(&j) + } + } + + // k defaults to cap(x) + // Only need to load it if we're recalculating cap or doing a full update. + if k.Op == 0 && n.Op != OSLICESTR && (!iszero(&i) || needFullUpdate) { + loadcap() + k = xcap + if k.Op == OREGISTER { + Regrealloc(&k) + } + } + + // Check constant indexes for negative values, and against constant length if known. + // The func obvious below checks for out-of-order constant indexes. + var bound int64 = -1 + if n.Op == OSLICEARR || n.Op == OSLICE3ARR { + bound = n.Left.Type.Type.Bound + } else if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) { + bound = int64(len(n.Left.Val.U.(string))) + } + if Isconst(&i, CTINT) { + if mpcmpfixc(i.Val.U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(i.Val.U.(*Mpint), bound) > 0 { + Yyerror("slice index out of bounds") + } + } + if Isconst(&j, CTINT) { + if mpcmpfixc(j.Val.U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(j.Val.U.(*Mpint), bound) > 0 { + Yyerror("slice index out of bounds") + } + } + if Isconst(&k, CTINT) { + if mpcmpfixc(k.Val.U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(k.Val.U.(*Mpint), bound) > 0 { + Yyerror("slice index out of bounds") + } + } + + // same reports whether n1 and n2 are the same register or constant. + same := func(n1, n2 *Node) bool { + return n1.Op == OREGISTER && n2.Op == OREGISTER && n1.Reg == n2.Reg || + n1.Op == ONAME && n2.Op == ONAME && n1.Orig == n2.Orig && n1.Type == n2.Type && n1.Xoffset == n2.Xoffset || + n1.Op == OLITERAL && n2.Op == OLITERAL && Mpcmpfixfix(n1.Val.U.(*Mpint), n2.Val.U.(*Mpint)) == 0 + } + + // obvious reports whether n1 <= n2 is obviously true, + // and it calls Yyerror if n1 <= n2 is obviously false. + obvious := func(n1, n2 *Node) bool { + if Debug['B'] != 0 { // -B disables bounds checks + return true + } + if same(n1, n2) { + return true // n1 == n2 + } + if iszero(n1) { + return true // using unsigned compare, so 0 <= n2 always true + } + if xlen.Op != 0 && same(n1, &xlen) && xcap.Op != 0 && same(n2, &xcap) { + return true // len(x) <= cap(x) always true + } + if Isconst(n1, CTINT) && Isconst(n2, CTINT) { + if Mpcmpfixfix(n1.Val.U.(*Mpint), n2.Val.U.(*Mpint)) <= 0 { + return true // n1, n2 constants such that n1 <= n2 + } + Yyerror("slice index out of bounds") + return true + } + return false + } + + compare := func(n1, n2 *Node) { + // n1 might be a 64-bit constant, even on 32-bit architectures, + // but it will be represented in 32 bits. + if Ctxt.Arch.Regsize == 4 && Is64(n1.Type) { + if mpcmpfixc(n1.Val.U.(*Mpint), 1<<31) >= 0 { + Fatal("missed slice out of bounds check") + } + var tmp Node + Nodconst(&tmp, indexRegType, Mpgetfix(n1.Val.U.(*Mpint))) + n1 = &tmp + } + p := Thearch.Ginscmp(OGT, indexRegType, n1, n2, -1) + panics = append(panics, p) + } + + loadcap() + max := &xcap + if k.Op != 0 && (n.Op == OSLICE3 || n.Op == OSLICE3ARR) { + if obvious(&k, max) { + if Debug_slice > 0 { + Warn("slice: omit check for 3rd index") + } + } else { + compare(&k, max) + } + max = &k + } + if j.Op != 0 { + if obvious(&j, max) { + if Debug_slice > 0 { + Warn("slice: omit check for 2nd index") + } + } else { + compare(&j, max) + } + max = &j + } + if i.Op != 0 { + if obvious(&i, max) { + if Debug_slice > 0 { + Warn("slice: omit check for 1st index") + } + } else { + compare(&i, max) + } + max = &i + } + if k.Op != 0 && i.Op != 0 { + obvious(&i, &k) // emit compile-time error for x[3:n:2] + } + + if len(panics) > 0 { + p := Gbranch(obj.AJMP, nil, 0) + for _, q := range panics { + Patch(q, Pc) + } + Ginscall(panicslice, -1) + Patch(p, Pc) + } + + // Checks are done. + // Compute new len as j-i, cap as k-i. + // If i and j are same register, len is constant 0. + // If i and k are same register, cap is constant 0. + // If j and k are same register, len and cap are same. + + // Done with xlen and xcap. + // Now safe to modify j and k even if they alias xlen, xcap. + if xlen.Op == OREGISTER { + Regfree(&xlen) + } + if xcap.Op == OREGISTER { + Regfree(&xcap) + } + + // are j and k the same value? + sameJK := same(&j, &k) + + if i.Op != 0 { + // j -= i + if same(&i, &j) { + if Debug_slice > 0 { + Warn("slice: result len == 0") + } + if j.Op == OREGISTER { + Regfree(&j) + } + Nodconst(&j, indexRegType, 0) + } else { + switch j.Op { + case OLITERAL: + if Isconst(&i, CTINT) { + Nodconst(&j, indexRegType, Mpgetfix(j.Val.U.(*Mpint))-Mpgetfix(i.Val.U.(*Mpint))) + if Debug_slice > 0 { + Warn("slice: result len == %d", Mpgetfix(j.Val.U.(*Mpint))) + } + break + } + fallthrough + case ONAME: + if !istemp(&j) { + var r Node + regalloc(&r, indexRegType, nil) + Thearch.Gmove(&j, &r) + j = r + } + fallthrough + case OREGISTER: + if i.Op == OLITERAL { + v := Mpgetfix(i.Val.U.(*Mpint)) + if v != 0 { + ginscon(Thearch.Optoas(OSUB, indexRegType), v, &j) + } + } else { + gins(Thearch.Optoas(OSUB, indexRegType), &i, &j) + } + } + } + + // k -= i if k different from j and cap is needed.j + // (The modifications to j above cannot affect i: if j and i were aliased, + // we replace j with a constant 0 instead of doing a subtraction, + // leaving i unmodified.) + if k.Op == 0 { + if Debug_slice > 0 && n.Op != OSLICESTR { + Warn("slice: result cap not computed") + } + // no need + } else if same(&i, &k) { + if k.Op == OREGISTER { + Regfree(&k) + } + Nodconst(&k, indexRegType, 0) + if Debug_slice > 0 { + Warn("slice: result cap == 0") + } + } else if sameJK { + if Debug_slice > 0 { + Warn("slice: result cap == result len") + } + // k and j were the same value; make k-i the same as j-i. + if k.Op == OREGISTER { + Regfree(&k) + } + k = j + if k.Op == OREGISTER { + Regrealloc(&k) + } + } else { + switch k.Op { + case OLITERAL: + if Isconst(&i, CTINT) { + Nodconst(&k, indexRegType, Mpgetfix(k.Val.U.(*Mpint))-Mpgetfix(i.Val.U.(*Mpint))) + if Debug_slice > 0 { + Warn("slice: result cap == %d", Mpgetfix(k.Val.U.(*Mpint))) + } + break + } + fallthrough + case ONAME: + if !istemp(&k) { + var r Node + regalloc(&r, indexRegType, nil) + Thearch.Gmove(&k, &r) + k = r + } + fallthrough + case OREGISTER: + if same(&i, &k) { + Regfree(&k) + Nodconst(&k, indexRegType, 0) + if Debug_slice > 0 { + Warn("slice: result cap == 0") + } + } else if i.Op == OLITERAL { + v := Mpgetfix(i.Val.U.(*Mpint)) + if v != 0 { + ginscon(Thearch.Optoas(OSUB, indexRegType), v, &k) + } + } else { + gins(Thearch.Optoas(OSUB, indexRegType), &i, &k) + } + } + } + } + + adjustBase := true + if i.Op == 0 || iszero(&i) { + if Debug_slice > 0 { + Warn("slice: skip base adjustment for 1st index 0") + } + adjustBase = false + } else if k.Op != 0 && iszero(&k) || k.Op == 0 && iszero(&j) { + if Debug_slice > 0 { + if n.Op == OSLICESTR { + Warn("slice: skip base adjustment for string len == 0") + } else { + Warn("slice: skip base adjustment for cap == 0") + } + } + adjustBase = false + } + + if !adjustBase && !needFullUpdate { + if Debug_slice > 0 { + if k.Op != 0 { + Warn("slice: len/cap-only update") + } else { + Warn("slice: len-only update") + } + } + if i.Op == OREGISTER { + Regfree(&i) + } + // Write len (and cap if needed) back to x. + x.Xoffset += int64(Widthptr) + x.Type = Types[TUINT] + Thearch.Gmove(&j, &x) + x.Xoffset -= int64(Widthptr) + if k.Op != 0 { + x.Xoffset += 2 * int64(Widthptr) + x.Type = Types[TUINT] + Thearch.Gmove(&k, &x) + x.Xoffset -= 2 * int64(Widthptr) + } + Regfree(&x) + } else { + // Compute new base. May smash i. + if n.Op == OSLICEARR || n.Op == OSLICE3ARR { + Cgenr(n.Left, &xbase, nil) + Cgen_checknil(&xbase) + } else { + regalloc(&xbase, Ptrto(res.Type.Type), nil) + x.Type = xbase.Type + Thearch.Gmove(&x, &xbase) + Regfree(&x) + } + if i.Op != 0 && adjustBase { + // Branch around the base adjustment if the resulting cap will be 0. + var p *obj.Prog + size := &k + if k.Op == 0 { + size = &j + } + if Isconst(size, CTINT) { + // zero was checked above, must be non-zero. + } else { + var tmp Node + Nodconst(&tmp, indexRegType, 0) + p = Thearch.Ginscmp(OEQ, indexRegType, size, &tmp, -1) + } + var w int64 + if n.Op == OSLICESTR { + w = 1 // res is string, elem size is 1 (byte) + } else { + w = res.Type.Type.Width // res is []T, elem size is T.width + } + if Isconst(&i, CTINT) { + ginscon(Thearch.Optoas(OADD, xbase.Type), Mpgetfix(i.Val.U.(*Mpint))*w, &xbase) + } else if Thearch.AddIndex != nil && Thearch.AddIndex(&i, w, &xbase) { + // done by back end + } else if w == 1 { + gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase) + } else { + if i.Op == ONAME && !istemp(&i) { + var tmp Node + Tempname(&tmp, i.Type) + Thearch.Gmove(&i, &tmp) + i = tmp + } + ginscon(Thearch.Optoas(OMUL, i.Type), w, &i) + gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase) + } + if p != nil { + Patch(p, Pc) + } + } + if i.Op == OREGISTER { + Regfree(&i) + } + + // Write len, cap, base to result. + if res.Op == ONAME { + Gvardef(res) + } + Igen(res, &x, nil) + x.Xoffset += int64(Widthptr) + x.Type = Types[TUINT] + Thearch.Gmove(&j, &x) + x.Xoffset -= int64(Widthptr) + if k.Op != 0 { + x.Xoffset += 2 * int64(Widthptr) + Thearch.Gmove(&k, &x) + x.Xoffset -= 2 * int64(Widthptr) + } + x.Type = xbase.Type + cgen_wb(&xbase, &x, wb) + Regfree(&xbase) + Regfree(&x) + } + + if j.Op == OREGISTER { + Regfree(&j) + } + if k.Op == OREGISTER { + Regfree(&k) + } +} diff --git a/src/cmd/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go index 8d5fd5a600..64cd97206c 100644 --- a/src/cmd/internal/gc/closure.go +++ b/src/cmd/compile/internal/gc/closure.go @@ -17,7 +17,7 @@ func closurehdr(ntype *Node) { var a *Node n := Nod(OCLOSURE, nil, nil) - n.Ntype = ntype + n.Param.Ntype = ntype n.Funcdepth = Funcdepth n.Func.Outerfunc = Curfn @@ -72,8 +72,8 @@ func closurebody(body *NodeList) *Node { var v *Node for l := func_.Func.Cvars; l != nil; l = l.Next { v = l.N - v.Closure.Closure = v.Outer - v.Outerexpr = oldname(v.Sym) + v.Param.Closure.Param.Closure = v.Param.Outer + v.Param.Outerexpr = oldname(v.Sym) } return func_ @@ -83,16 +83,16 @@ func typecheckclosure(func_ *Node, top int) { var n *Node for l := func_.Func.Cvars; l != nil; l = l.Next { - n = l.N.Closure - if !n.Captured { - n.Captured = true - if n.Decldepth == 0 { + n = l.N.Param.Closure + if !n.Name.Captured { + n.Name.Captured = true + if n.Name.Decldepth == 0 { Fatal("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, obj.FmtShort)) } // Ignore assignments to the variable in straightline code // preceding the first capturing by a closure. - if n.Decldepth == decldepth { + if n.Name.Decldepth == decldepth { n.Assigned = false } } @@ -100,14 +100,14 @@ func typecheckclosure(func_ *Node, top int) { for l := func_.Func.Dcl; l != nil; l = l.Next { if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) { - l.N.Decldepth = 1 + l.N.Name.Decldepth = 1 } } oldfn := Curfn - typecheck(&func_.Ntype, Etype) - func_.Type = func_.Ntype.Type - func_.Top = top + typecheck(&func_.Param.Ntype, Etype) + func_.Type = func_.Param.Ntype.Type + func_.Param.Top = top // Type check the body now, but only if we're inside a function. // At top level (in a variable initialization: curfn==nil) we're not @@ -193,7 +193,7 @@ func makeclosure(func_ *Node) *Node { xfunc.Nname = newfuncname(closurename(func_)) xfunc.Nname.Sym.Flags |= SymExported // disable export - xfunc.Nname.Ntype = xtype + xfunc.Nname.Param.Ntype = xtype xfunc.Nname.Defn = xfunc declare(xfunc.Nname, PFUNC) xfunc.Nname.Funcdepth = func_.Funcdepth @@ -207,8 +207,8 @@ func makeclosure(func_ *Node) *Node { } typecheck(&xfunc, Etop) - xfunc.Closure = func_ - func_.Closure = xfunc + xfunc.Param.Closure = func_ + func_.Param.Closure = xfunc func_.Nbody = nil func_.List = nil @@ -229,7 +229,7 @@ func capturevars(xfunc *Node) { lno := int(lineno) lineno = xfunc.Lineno - func_ := xfunc.Closure + func_ := xfunc.Param.Closure func_.Func.Enter = nil for l := func_.Func.Cvars; l != nil; l = l.Next { v = l.N @@ -249,14 +249,14 @@ func capturevars(xfunc *Node) { // so that the outer frame also grabs them and knows they escape. dowidth(v.Type) - outer = v.Outerexpr - v.Outerexpr = nil + outer = v.Param.Outerexpr + v.Param.Outerexpr = nil // out parameters will be assigned to implicitly upon return. - if outer.Class != PPARAMOUT && !v.Closure.Addrtaken && !v.Closure.Assigned && v.Type.Width <= 128 { - v.Byval = true + if outer.Class != PPARAMOUT && !v.Param.Closure.Addrtaken && !v.Param.Closure.Assigned && v.Type.Width <= 128 { + v.Name.Byval = true } else { - v.Closure.Addrtaken = true + v.Param.Closure.Addrtaken = true outer = Nod(OADDR, outer, nil) } @@ -266,10 +266,10 @@ func capturevars(xfunc *Node) { name = v.Curfn.Nname.Sym } how := "ref" - if v.Byval { + if v.Name.Byval { how = "value" } - Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Closure.Addrtaken, v.Closure.Assigned, int32(v.Type.Width)) + Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Param.Closure.Addrtaken, v.Param.Closure.Assigned, int32(v.Type.Width)) } typecheck(&outer, Erv) @@ -284,9 +284,9 @@ func capturevars(xfunc *Node) { func transformclosure(xfunc *Node) { lno := int(lineno) lineno = xfunc.Lineno - func_ := xfunc.Closure + func_ := xfunc.Param.Closure - if func_.Top&Ecall != 0 { + if func_.Param.Top&Ecall != 0 { // If the closure is directly called, we transform it to a plain function call // with variables passed as args. This avoids allocation of a closure object. // Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE) @@ -321,7 +321,7 @@ func transformclosure(xfunc *Node) { } fld = typ(TFIELD) fld.Funarg = 1 - if v.Byval { + if v.Name.Byval { // If v is captured by value, we merely downgrade it to PPARAM. v.Class = PPARAM @@ -335,7 +335,7 @@ func transformclosure(xfunc *Node) { addr = newname(Lookupf("&%s", v.Sym.Name)) addr.Type = Ptrto(v.Type) addr.Class = PPARAM - v.Heapaddr = addr + v.Name.Heapaddr = addr fld.Nname = addr } @@ -375,14 +375,14 @@ func transformclosure(xfunc *Node) { cv = Nod(OCLOSUREVAR, nil, nil) cv.Type = v.Type - if !v.Byval { + if !v.Name.Byval { cv.Type = Ptrto(v.Type) } offset = Rnd(offset, int64(cv.Type.Align)) cv.Xoffset = offset offset += cv.Type.Width - if v.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' { + if v.Name.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' { // If it is a small variable captured by value, downgrade it to PAUTO. // This optimization is currently enabled only for amd64, see: // https://github.com/golang/go/issues/9865 @@ -395,13 +395,13 @@ func transformclosure(xfunc *Node) { // Declare variable holding addresses taken from closure // and initialize in entry prologue. addr = newname(Lookupf("&%s", v.Sym.Name)) - addr.Ntype = Nod(OIND, typenod(v.Type), nil) + addr.Param.Ntype = Nod(OIND, typenod(v.Type), nil) addr.Class = PAUTO addr.Used = true addr.Curfn = xfunc xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr) - v.Heapaddr = addr - if v.Byval { + v.Name.Heapaddr = addr + if v.Name.Byval { cv = Nod(OADDR, cv, nil) } body = list(body, Nod(OAS, addr, cv)) @@ -420,7 +420,7 @@ func transformclosure(xfunc *Node) { func walkclosure(func_ *Node, init **NodeList) *Node { // If no closure vars, don't bother wrapping. if func_.Func.Cvars == nil { - return func_.Closure.Nname + return func_.Param.Closure.Nname } // Create closure in the form of a composite literal. @@ -448,7 +448,7 @@ func walkclosure(func_ *Node, init **NodeList) *Node { continue } typ1 = typenod(v.Type) - if !v.Byval { + if !v.Name.Byval { typ1 = Nod(OIND, typ1, nil) } typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1)) @@ -457,7 +457,7 @@ func walkclosure(func_ *Node, init **NodeList) *Node { clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil)) clos.Esc = func_.Esc clos.Right.Implicit = true - clos.List = concat(list1(Nod(OCFUNC, func_.Closure.Nname, nil)), func_.Func.Enter) + clos.List = concat(list1(Nod(OCFUNC, func_.Param.Closure.Nname, nil)), func_.Func.Enter) // Force type conversion from *struct to the func type. clos = Nod(OCONVNOP, clos, nil) @@ -583,7 +583,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node { xfunc.Func.Dupok = true xfunc.Nname = newfuncname(sym) xfunc.Nname.Sym.Flags |= SymExported // disable export - xfunc.Nname.Ntype = xtype + xfunc.Nname.Param.Ntype = xtype xfunc.Nname.Defn = xfunc declare(xfunc.Nname, PFUNC) @@ -606,10 +606,10 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node { xfunc.Func.Dcl = list(xfunc.Func.Dcl, ptr) var body *NodeList if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) { - ptr.Ntype = typenod(rcvrtype) + ptr.Param.Ntype = typenod(rcvrtype) body = list(body, Nod(OAS, ptr, cv)) } else { - ptr.Ntype = typenod(Ptrto(rcvrtype)) + ptr.Param.Ntype = typenod(Ptrto(rcvrtype)) body = list(body, Nod(OAS, ptr, Nod(OADDR, cv, nil))) } diff --git a/src/cmd/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go index ad2915812e..b3605ab206 100644 --- a/src/cmd/internal/gc/const.go +++ b/src/cmd/compile/internal/gc/const.go @@ -5,10 +5,47 @@ package gc import ( + "cmd/compile/internal/big" "cmd/internal/obj" "strings" ) +// Int returns n as an int. +// n must be an integer constant. +func (n *Node) Int() int64 { + if !Isconst(n, CTINT) { + Fatal("Int(%v)", n) + } + return Mpgetfix(n.Val.U.(*Mpint)) +} + +// SetInt sets n's value to i. +// n must be an integer constant. +func (n *Node) SetInt(i int64) { + if !Isconst(n, CTINT) { + Fatal("SetInt(%v)", n) + } + Mpmovecfix(n.Val.U.(*Mpint), i) +} + +// SetBigInt sets n's value to x. +// n must be an integer constant. +func (n *Node) SetBigInt(x *big.Int) { + if !Isconst(n, CTINT) { + Fatal("SetBigInt(%v)", n) + } + n.Val.U.(*Mpint).Val.Set(x) +} + +// Bool returns n as an bool. +// n must be an boolean constant. +func (n *Node) Bool() bool { + if !Isconst(n, CTBOOL) { + Fatal("Int(%v)", n) + } + return n.Val.U.(bool) +} + /* * truncate float literal fv to 32-bit or 64-bit precision * according to type; return truncated value. @@ -20,7 +57,7 @@ func truncfltlit(oldv *Mpflt, t *Type) *Mpflt { var v Val v.Ctype = CTFLT - v.U.Fval = oldv + v.U = oldv overflow(v, t) fv := newMpflt() @@ -190,8 +227,8 @@ func convlit1(np **Node, t *Type, explicit bool) { // if it is an unsafe.Pointer case TUINTPTR: if n.Type.Etype == TUNSAFEPTR { - n.Val.U.Xval = new(Mpint) - Mpmovecfix(n.Val.U.Xval, 0) + n.Val.U = new(Mpint) + Mpmovecfix(n.Val.U.(*Mpint), 0) n.Val.Ctype = CTINT } else { goto bad @@ -204,6 +241,9 @@ func convlit1(np **Node, t *Type, explicit bool) { } case CTINT, CTRUNE, CTFLT, CTCPLX: + if n.Type.Etype == TUNSAFEPTR && t.Etype != TUINTPTR { + goto bad + } ct := int(n.Val.Ctype) if Isint[et] { switch ct { @@ -229,7 +269,7 @@ func convlit1(np **Node, t *Type, explicit bool) { // flowthrough case CTFLT: - n.Val.U.Fval = truncfltlit(n.Val.U.Fval, t) + n.Val.U = truncfltlit(n.Val.U.(*Mpflt), t) } } else if Iscomplex[et] { switch ct { @@ -264,27 +304,25 @@ bad: defaultlit(&n, nil) *np = n } - - return } func copyval(v Val) Val { switch v.Ctype { case CTINT, CTRUNE: i := new(Mpint) - mpmovefixfix(i, v.U.Xval) - v.U.Xval = i + mpmovefixfix(i, v.U.(*Mpint)) + v.U = i case CTFLT: f := newMpflt() - mpmovefltflt(f, v.U.Fval) - v.U.Fval = f + mpmovefltflt(f, v.U.(*Mpflt)) + v.U = f case CTCPLX: c := new(Mpcplx) - mpmovefltflt(&c.Real, &v.U.Cval.Real) - mpmovefltflt(&c.Imag, &v.U.Cval.Imag) - v.U.Cval = c + mpmovefltflt(&c.Real, &v.U.(*Mpcplx).Real) + mpmovefltflt(&c.Imag, &v.U.(*Mpcplx).Imag) + v.U = c } return v @@ -294,17 +332,17 @@ func tocplx(v Val) Val { switch v.Ctype { case CTINT, CTRUNE: c := new(Mpcplx) - Mpmovefixflt(&c.Real, v.U.Xval) + Mpmovefixflt(&c.Real, v.U.(*Mpint)) Mpmovecflt(&c.Imag, 0.0) v.Ctype = CTCPLX - v.U.Cval = c + v.U = c case CTFLT: c := new(Mpcplx) - mpmovefltflt(&c.Real, v.U.Fval) + mpmovefltflt(&c.Real, v.U.(*Mpflt)) Mpmovecflt(&c.Imag, 0.0) v.Ctype = CTCPLX - v.U.Cval = c + v.U = c } return v @@ -314,18 +352,18 @@ func toflt(v Val) Val { switch v.Ctype { case CTINT, CTRUNE: f := newMpflt() - Mpmovefixflt(f, v.U.Xval) + Mpmovefixflt(f, v.U.(*Mpint)) v.Ctype = CTFLT - v.U.Fval = f + v.U = f case CTCPLX: f := newMpflt() - mpmovefltflt(f, &v.U.Cval.Real) - if mpcmpfltc(&v.U.Cval.Imag, 0) != 0 { - Yyerror("constant %v%vi truncated to real", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign)) + mpmovefltflt(f, &v.U.(*Mpcplx).Real) + if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 { + Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign)) } v.Ctype = CTFLT - v.U.Fval = f + v.U = f } return v @@ -338,22 +376,22 @@ func toint(v Val) Val { case CTFLT: i := new(Mpint) - if mpmovefltfix(i, v.U.Fval) < 0 { - Yyerror("constant %v truncated to integer", Fconv(v.U.Fval, obj.FmtSharp)) + if mpmovefltfix(i, v.U.(*Mpflt)) < 0 { + Yyerror("constant %v truncated to integer", Fconv(v.U.(*Mpflt), obj.FmtSharp)) } v.Ctype = CTINT - v.U.Xval = i + v.U = i case CTCPLX: i := new(Mpint) - if mpmovefltfix(i, &v.U.Cval.Real) < 0 { - Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign)) + if mpmovefltfix(i, &v.U.(*Mpcplx).Real) < 0 { + Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign)) } - if mpcmpfltc(&v.U.Cval.Imag, 0) != 0 { - Yyerror("constant %v%vi truncated to real", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign)) + if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 { + Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign)) } v.Ctype = CTINT - v.U.Xval = i + v.U = i } return v @@ -365,7 +403,7 @@ func doesoverflow(v Val, t *Type) bool { if !Isint[t.Etype] { Fatal("overflow: %v integer constant", t) } - if Mpcmpfixfix(v.U.Xval, Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[t.Etype]) > 0 { + if Mpcmpfixfix(v.U.(*Mpint), Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[t.Etype]) > 0 { return true } @@ -373,7 +411,7 @@ func doesoverflow(v Val, t *Type) bool { if !Isfloat[t.Etype] { Fatal("overflow: %v floating-point constant", t) } - if mpcmpfltflt(v.U.Fval, minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.Fval, maxfltval[t.Etype]) >= 0 { + if mpcmpfltflt(v.U.(*Mpflt), minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.(*Mpflt), maxfltval[t.Etype]) >= 0 { return true } @@ -381,7 +419,7 @@ func doesoverflow(v Val, t *Type) bool { if !Iscomplex[t.Etype] { Fatal("overflow: %v 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 { + if mpcmpfltflt(&v.U.(*Mpcplx).Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, maxfltval[t.Etype]) >= 0 { return true } } @@ -396,32 +434,37 @@ func overflow(v Val, t *Type) { return } + // Only uintptrs may be converted to unsafe.Pointer, which cannot overflow. + if t.Etype == TUNSAFEPTR { + return + } + if !doesoverflow(v, t) { return } switch v.Ctype { case CTINT, CTRUNE: - Yyerror("constant %v overflows %v", v.U.Xval, t) + Yyerror("constant %v overflows %v", v.U.(*Mpint), t) case CTFLT: - Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), t) + Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t) case CTCPLX: - Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), t) + Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t) } } func tostr(v Val) Val { switch v.Ctype { case CTINT, CTRUNE: - if Mpcmpfixfix(v.U.Xval, Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[TINT]) > 0 { + if Mpcmpfixfix(v.U.(*Mpint), Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("overflow in int -> string") } - r := uint(Mpgetfix(v.U.Xval)) + r := uint(Mpgetfix(v.U.(*Mpint))) v = Val{} v.Ctype = CTSTR - v.U.Sval = string(r) + v.U = string(r) case CTFLT: Yyerror("no float -> string") @@ -430,7 +473,7 @@ func tostr(v Val) Val { case CTNIL: v = Val{} v.Ctype = CTSTR - v.U.Sval = "" + v.U = "" } return v @@ -519,7 +562,7 @@ func evconst(n *Node) { l2 = l1 for l2 != nil && Isconst(l2.N, CTSTR) { nr = l2.N - strs = append(strs, nr.Val.U.Sval) + strs = append(strs, nr.Val.U.(string)) l2 = l2.Next } @@ -527,7 +570,7 @@ func evconst(n *Node) { *nl = *l1.N nl.Orig = nl nl.Val.Ctype = CTSTR - nl.Val.U.Sval = strings.Join(strs, "") + nl.Val.U = strings.Join(strs, "") l1.N = nl l1.Next = l2 } @@ -607,7 +650,7 @@ func evconst(n *Node) { case OMINUS<<16 | CTINT, OMINUS<<16 | CTRUNE: - mpnegfix(v.U.Xval) + mpnegfix(v.U.(*Mpint)) case OCOM<<16 | CTINT, OCOM<<16 | CTRUNE: @@ -634,23 +677,23 @@ func evconst(n *Node) { mpmovefixfix(&b, Maxintval[et]) } - mpxorfixfix(v.U.Xval, &b) + mpxorfixfix(v.U.(*Mpint), &b) case OPLUS<<16 | CTFLT: break case OMINUS<<16 | CTFLT: - mpnegflt(v.U.Fval) + mpnegflt(v.U.(*Mpflt)) case OPLUS<<16 | CTCPLX: break case OMINUS<<16 | CTCPLX: - mpnegflt(&v.U.Cval.Real) - mpnegflt(&v.U.Cval.Imag) + mpnegflt(&v.U.(*Mpcplx).Real) + mpnegflt(&v.U.(*Mpcplx).Imag) case ONOT<<16 | CTBOOL: - if !v.U.Bval { + if !v.U.(bool) { goto settrue } goto setfalse @@ -754,77 +797,77 @@ func evconst(n *Node) { case OADD<<16 | CTINT, OADD<<16 | CTRUNE: - mpaddfixfix(v.U.Xval, rv.U.Xval, 0) + mpaddfixfix(v.U.(*Mpint), rv.U.(*Mpint), 0) case OSUB<<16 | CTINT, OSUB<<16 | CTRUNE: - mpsubfixfix(v.U.Xval, rv.U.Xval) + mpsubfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OMUL<<16 | CTINT, OMUL<<16 | CTRUNE: - mpmulfixfix(v.U.Xval, rv.U.Xval) + mpmulfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case ODIV<<16 | CTINT, ODIV<<16 | CTRUNE: - if mpcmpfixc(rv.U.Xval, 0) == 0 { + if mpcmpfixc(rv.U.(*Mpint), 0) == 0 { Yyerror("division by zero") - Mpmovecfix(v.U.Xval, 1) + mpsetovf(v.U.(*Mpint)) break } - mpdivfixfix(v.U.Xval, rv.U.Xval) + mpdivfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OMOD<<16 | CTINT, OMOD<<16 | CTRUNE: - if mpcmpfixc(rv.U.Xval, 0) == 0 { + if mpcmpfixc(rv.U.(*Mpint), 0) == 0 { Yyerror("division by zero") - Mpmovecfix(v.U.Xval, 1) + mpsetovf(v.U.(*Mpint)) break } - mpmodfixfix(v.U.Xval, rv.U.Xval) + mpmodfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OLSH<<16 | CTINT, OLSH<<16 | CTRUNE: - mplshfixfix(v.U.Xval, rv.U.Xval) + mplshfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case ORSH<<16 | CTINT, ORSH<<16 | CTRUNE: - mprshfixfix(v.U.Xval, rv.U.Xval) + mprshfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OOR<<16 | CTINT, OOR<<16 | CTRUNE: - mporfixfix(v.U.Xval, rv.U.Xval) + mporfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OAND<<16 | CTINT, OAND<<16 | CTRUNE: - mpandfixfix(v.U.Xval, rv.U.Xval) + mpandfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OANDNOT<<16 | CTINT, OANDNOT<<16 | CTRUNE: - mpandnotfixfix(v.U.Xval, rv.U.Xval) + mpandnotfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OXOR<<16 | CTINT, OXOR<<16 | CTRUNE: - mpxorfixfix(v.U.Xval, rv.U.Xval) + mpxorfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OADD<<16 | CTFLT: - mpaddfltflt(v.U.Fval, rv.U.Fval) + mpaddfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) case OSUB<<16 | CTFLT: - mpsubfltflt(v.U.Fval, rv.U.Fval) + mpsubfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) case OMUL<<16 | CTFLT: - mpmulfltflt(v.U.Fval, rv.U.Fval) + mpmulfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) case ODIV<<16 | CTFLT: - if mpcmpfltc(rv.U.Fval, 0) == 0 { + if mpcmpfltc(rv.U.(*Mpflt), 0) == 0 { Yyerror("division by zero") - Mpmovecflt(v.U.Fval, 1.0) + Mpmovecflt(v.U.(*Mpflt), 1.0) break } - mpdivfltflt(v.U.Fval, rv.U.Fval) + mpdivfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) // The default case above would print 'ideal % ideal', // which is not quite an ideal error. @@ -837,25 +880,25 @@ func evconst(n *Node) { return case OADD<<16 | CTCPLX: - mpaddfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) - mpaddfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) + mpaddfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) + mpaddfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) case OSUB<<16 | CTCPLX: - mpsubfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) - mpsubfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) + mpsubfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) + mpsubfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) case OMUL<<16 | CTCPLX: - cmplxmpy(v.U.Cval, rv.U.Cval) + cmplxmpy(v.U.(*Mpcplx), rv.U.(*Mpcplx)) case ODIV<<16 | CTCPLX: - if mpcmpfltc(&rv.U.Cval.Real, 0) == 0 && mpcmpfltc(&rv.U.Cval.Imag, 0) == 0 { + if mpcmpfltc(&rv.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&rv.U.(*Mpcplx).Imag, 0) == 0 { Yyerror("complex division by zero") - Mpmovecflt(&rv.U.Cval.Real, 1.0) - Mpmovecflt(&rv.U.Cval.Imag, 0.0) + Mpmovecflt(&rv.U.(*Mpcplx).Real, 1.0) + Mpmovecflt(&rv.U.(*Mpcplx).Imag, 0.0) break } - cmplxdiv(v.U.Cval, rv.U.Cval) + cmplxdiv(v.U.(*Mpcplx), rv.U.(*Mpcplx)) case OEQ<<16 | CTNIL: goto settrue @@ -865,90 +908,90 @@ func evconst(n *Node) { case OEQ<<16 | CTINT, OEQ<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) == 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) == 0 { goto settrue } goto setfalse case ONE<<16 | CTINT, ONE<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) != 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) != 0 { goto settrue } goto setfalse case OLT<<16 | CTINT, OLT<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) < 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) < 0 { goto settrue } goto setfalse case OLE<<16 | CTINT, OLE<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) <= 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) <= 0 { goto settrue } goto setfalse case OGE<<16 | CTINT, OGE<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) >= 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) >= 0 { goto settrue } goto setfalse case OGT<<16 | CTINT, OGT<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) > 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) > 0 { goto settrue } goto setfalse case OEQ<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) == 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) == 0 { goto settrue } goto setfalse case ONE<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) != 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) != 0 { goto settrue } goto setfalse case OLT<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) < 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) < 0 { goto settrue } goto setfalse case OLE<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) <= 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) <= 0 { goto settrue } goto setfalse case OGE<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) >= 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) >= 0 { goto settrue } goto setfalse case OGT<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) > 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) > 0 { goto settrue } goto setfalse case OEQ<<16 | CTCPLX: - if mpcmpfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) == 0 && mpcmpfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) == 0 { + if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) == 0 && mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) == 0 { goto settrue } goto setfalse case ONE<<16 | CTCPLX: - if mpcmpfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) != 0 || mpcmpfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) != 0 { + if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) != 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) != 0 { goto settrue } goto setfalse @@ -990,25 +1033,25 @@ func evconst(n *Node) { goto setfalse case OOROR<<16 | CTBOOL: - if v.U.Bval || rv.U.Bval { + if v.U.(bool) || rv.U.(bool) { goto settrue } goto setfalse case OANDAND<<16 | CTBOOL: - if v.U.Bval && rv.U.Bval { + if v.U.(bool) && rv.U.(bool) { goto settrue } goto setfalse case OEQ<<16 | CTBOOL: - if v.U.Bval == rv.U.Bval { + if v.U.(bool) == rv.U.(bool) { goto settrue } goto setfalse case ONE<<16 | CTBOOL: - if v.U.Bval != rv.U.Bval { + if v.U.(bool) != rv.U.(bool) { goto settrue } goto setfalse @@ -1033,7 +1076,7 @@ ret: // truncate precision for non-ideal float. if v.Ctype == CTFLT && n.Type.Etype != TIDEAL { - n.Val.U.Fval = truncfltlit(v.U.Fval, n.Type) + n.Val.U = truncfltlit(v.U.(*Mpflt), n.Type) } return @@ -1088,15 +1131,15 @@ func nodcplxlit(r Val, i Val) *Node { c := new(Mpcplx) n := Nod(OLITERAL, nil, nil) n.Type = Types[TIDEAL] - n.Val.U.Cval = c + n.Val.U = 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) + mpmovefltflt(&c.Real, r.U.(*Mpflt)) + mpmovefltflt(&c.Imag, i.U.(*Mpflt)) return n } @@ -1311,7 +1354,7 @@ func defaultlit2(lp **Node, rp **Node, force int) { } func cmpslit(l, r *Node) int { - return stringsCompare(l.Val.U.Sval, r.Val.U.Sval) + return stringsCompare(l.Val.U.(string), r.Val.U.(string)) } func Smallintconst(n *Node) bool { @@ -1328,7 +1371,7 @@ func Smallintconst(n *Node) bool { return true case TIDEAL, TINT64, TUINT64, TPTR64: - if Mpcmpfixfix(n.Val.U.Xval, Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 { + if Mpcmpfixfix(n.Val.U.(*Mpint), Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT32]) > 0 { break } return true @@ -1351,10 +1394,10 @@ func nonnegconst(n *Node) int { TINT64, TUINT64, TIDEAL: - if Mpcmpfixfix(n.Val.U.Xval, Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 { + if Mpcmpfixfix(n.Val.U.(*Mpint), Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT32]) > 0 { break } - return int(Mpgetfix(n.Val.U.Xval)) + return int(Mpgetfix(n.Val.U.(*Mpint))) } } @@ -1392,39 +1435,37 @@ func iconv(x int64, et int) int64 { return x } -/* - * convert constant val to type t; leave in con. - * for back end. - */ -func Convconst(con *Node, t *Type, val *Val) { +// Convconst converts constant node n to type t and +// places the result in con. +func (n *Node) Convconst(con *Node, t *Type) { tt := Simsimtype(t) // copy the constant for conversion Nodconst(con, Types[TINT8], 0) con.Type = t - con.Val = *val + con.Val = n.Val if Isint[tt] { con.Val.Ctype = CTINT - con.Val.U.Xval = new(Mpint) + con.Val.U = new(Mpint) var i int64 - switch val.Ctype { + switch n.Val.Ctype { default: - Fatal("convconst ctype=%d %v", val.Ctype, Tconv(t, obj.FmtLong)) + Fatal("convconst ctype=%d %v", n.Val.Ctype, Tconv(t, obj.FmtLong)) case CTINT, CTRUNE: - i = Mpgetfix(val.U.Xval) + i = Mpgetfix(n.Val.U.(*Mpint)) case CTBOOL: - i = int64(obj.Bool2int(val.U.Bval)) + i = int64(obj.Bool2int(n.Val.U.(bool))) case CTNIL: i = 0 } i = iconv(i, tt) - Mpmovecfix(con.Val.U.Xval, i) + Mpmovecfix(con.Val.U.(*Mpint), i) return } @@ -1434,7 +1475,7 @@ func Convconst(con *Node, t *Type, val *Val) { Fatal("convconst ctype=%d %v", con.Val.Ctype, t) } if tt == TFLOAT32 { - con.Val.U.Fval = truncfltlit(con.Val.U.Fval, t) + con.Val.U = truncfltlit(con.Val.U.(*Mpflt), t) } return } @@ -1442,10 +1483,9 @@ func Convconst(con *Node, t *Type, val *Val) { 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]) + con.Val.U.(*Mpcplx).Real = *truncfltlit(&con.Val.U.(*Mpcplx).Real, Types[TFLOAT32]) + con.Val.U.(*Mpcplx).Imag = *truncfltlit(&con.Val.U.(*Mpcplx).Imag, Types[TFLOAT32]) } - return } diff --git a/src/cmd/internal/gc/cplx.go b/src/cmd/compile/internal/gc/cplx.go index cf48c922d7..56a4892636 100644 --- a/src/cmd/internal/gc/cplx.go +++ b/src/cmd/compile/internal/gc/cplx.go @@ -89,8 +89,8 @@ func subnode(nr *Node, ni *Node, nc *Node) { t := Types[tc] if nc.Op == OLITERAL { - nodfconst(nr, t, &nc.Val.U.Cval.Real) - nodfconst(ni, t, &nc.Val.U.Cval.Imag) + nodfconst(nr, t, &nc.Val.U.(*Mpcplx).Real) + nodfconst(ni, t, &nc.Val.U.(*Mpcplx).Imag) return } @@ -226,7 +226,7 @@ func nodfconst(n *Node, t *Type, fval *Mpflt) { n.Op = OLITERAL n.Addable = true ullmancalc(n) - n.Val.U.Fval = fval + n.Val.U = fval n.Val.Ctype = CTFLT n.Type = t diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index 08d2469094..4a9cb295c8 100644 --- a/src/cmd/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -183,7 +183,7 @@ func declare(n *Node, ctxt uint8) { } if ctxt == PEXTERN && s.Name == "init" { - Yyerror("cannot declare init - must be func", s) + Yyerror("cannot declare init - must be func") } gen := 0 @@ -260,7 +260,7 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList { v = vl.N v.Op = ONAME declare(v, dclcontext) - v.Ntype = t + v.Param.Ntype = t v.Defn = as2 if Funcdepth > 0 { init = list(init, Nod(ODCL, v, nil)) @@ -288,7 +288,7 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList { v = vl.N v.Op = ONAME declare(v, dclcontext) - v.Ntype = t + v.Param.Ntype = t if e != nil || Funcdepth > 0 || isblank(v) { if Funcdepth > 0 { @@ -313,18 +313,19 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList { * new_name_list [[type] = expr_list] */ func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList { + lno := int32(0) // default is to leave line number alone in listtreecopy if cl == nil { if t != nil { Yyerror("const declaration cannot have type without expression") } cl = lastconst t = lasttype + lno = vl.N.Lineno } else { lastconst = cl lasttype = t } - - cl = listtreecopy(cl) + cl = listtreecopy(cl, lno) var v *Node var c *Node @@ -342,7 +343,7 @@ func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList { v.Op = OLITERAL declare(v, dclcontext) - v.Ntype = t + v.Param.Ntype = t v.Defn = c vv = list(vv, Nod(ODCLCONST, v, nil)) @@ -430,7 +431,7 @@ func oldname(s *Sym) *Node { // 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 == nil || n.Closure.Funcdepth != Funcdepth { + if n.Param.Closure == nil || n.Param.Closure.Funcdepth != Funcdepth { // create new closure var. c := Nod(ONAME, nil, nil) @@ -441,15 +442,15 @@ func oldname(s *Sym) *Node { c.Addable = false c.Ullman = 2 c.Funcdepth = Funcdepth - c.Outer = n.Closure - n.Closure = c - c.Closure = n + c.Param.Outer = n.Param.Closure + n.Param.Closure = c + c.Param.Closure = n c.Xoffset = 0 Curfn.Func.Cvars = list(Curfn.Func.Cvars, c) } // return ref to closure var, not original - return n.Closure + return n.Param.Closure } return n @@ -554,7 +555,7 @@ func ifacedcl(n *Node) { dclcontext = PPARAM markdcl() Funcdepth++ - n.Outer = Curfn + n.Param.Outer = Curfn Curfn = n funcargs(n.Right) @@ -583,13 +584,13 @@ func funchdr(n *Node) { markdcl() Funcdepth++ - n.Outer = Curfn + n.Param.Outer = Curfn Curfn = n if n.Nname != nil { - funcargs(n.Nname.Ntype) - } else if n.Ntype != nil { - funcargs(n.Ntype) + funcargs(n.Nname.Param.Ntype) + } else if n.Param.Ntype != nil { + funcargs(n.Param.Ntype) } else { funcargs2(n.Type) } @@ -615,7 +616,7 @@ func funcargs(nt *Node) { } if n.Left != nil { n.Left.Op = ONAME - n.Left.Ntype = n.Right + n.Left.Param.Ntype = n.Right declare(n.Left, PPARAM) if dclcontext == PAUTO { vargen++ @@ -632,7 +633,7 @@ func funcargs(nt *Node) { } if n.Left != nil { n.Left.Op = ONAME - n.Left.Ntype = n.Right + n.Left.Param.Ntype = n.Right declare(n.Left, PPARAM) if dclcontext == PAUTO { vargen++ @@ -679,7 +680,7 @@ func funcargs(nt *Node) { n.Left = nn } - n.Left.Ntype = n.Right + n.Left.Param.Ntype = n.Right declare(n.Left, PPARAMOUT) if dclcontext == PAUTO { i++ @@ -747,8 +748,8 @@ func funcbody(n *Node) { } popdcl() Funcdepth-- - Curfn = n.Outer - n.Outer = nil + Curfn = n.Param.Outer + n.Param.Outer = nil if Funcdepth == 0 { dclcontext = PEXTERN } @@ -770,7 +771,7 @@ func typedcl0(s *Sym) *Node { * return the ODCLTYPE node to use. */ func typedcl1(n *Node, t *Node, local bool) *Node { - n.Ntype = t + n.Param.Ntype = t n.Local = local return Nod(ODCLTYPE, n, nil) } @@ -830,7 +831,7 @@ func structfield(n *Node) *Type { switch n.Val.Ctype { case CTSTR: f.Note = new(string) - *f.Note = n.Val.U.Sval + *f.Note = n.Val.U.(string) default: Yyerror("field annotation must be string") diff --git a/src/cmd/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index c816feaa7f..2c134933c4 100644 --- a/src/cmd/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -154,7 +154,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 { } if n.Op == OCLOSURE { - m := v.visit(n.Closure) + m := v.visit(n.Param.Closure) if m < min { min = m } @@ -379,7 +379,7 @@ type EscState struct { theSink Node dsts *NodeList // all dst nodes - loopdepth int // for detecting nested loop scopes + loopdepth int32 // for detecting nested loop scopes pdepth int // for debug printing in recursions. dstcount int // diagnostic edgecount int // diagnostic @@ -387,6 +387,19 @@ type EscState struct { recursive bool // recursive function or group of mutually recursive functions. } +// funcSym returns n.Nname.Sym if no nils are encountered along the way. +func funcSym(n *Node) *Sym { + if n == nil || n.Nname == nil { + return nil + } + return n.Nname.Sym +} + +// curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way. +func curfnSym(n *Node) *Sym { + return funcSym(n.Curfn) +} + func escAnalyze(all *NodeList, recursive bool) { var es EscState e := &es @@ -428,13 +441,7 @@ func escAnalyze(all *NodeList, recursive bool) { if Debug['m'] != 0 { for l := e.noesc; l != nil; l = l.Next { if l.N.Esc == EscNone { - var tmp *Sym - if l.N.Curfn != nil && l.N.Curfn.Nname != nil { - tmp = l.N.Curfn.Nname.Sym - } else { - tmp = nil - } - Warnl(int(l.N.Lineno), "%v %v does not escape", tmp, Nconv(l.N, obj.FmtShort)) + Warnl(int(l.N.Lineno), "%v %v does not escape", curfnSym(l.N), Nconv(l.N, obj.FmtShort)) } } } @@ -579,6 +586,19 @@ func esc(e *EscState, n *Node, up *Node) { } } + // Big stuff escapes unconditionally + // "Big" conditions that were scattered around in walk have been gathered here + if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize || + n.Op == ONEW && n.Type.Type.Width >= 1<<16 || + n.Op == OMAKESLICE && !isSmallMakeSlice(n)) { + if Debug['m'] > 1 { + Warnl(int(n.Lineno), "%v is too large for stack", n) + } + n.Esc = EscHeap + addrescapes(n) + escassign(e, &e.theSink, n) + } + esc(e, n.Left, n) esc(e, n.Right, n) esc(e, n.Ntest, n) @@ -593,13 +613,7 @@ func esc(e *EscState, n *Node, up *Node) { } if Debug['m'] > 1 { - var tmp *Sym - if Curfn != nil && Curfn.Nname != nil { - tmp = Curfn.Nname.Sym - } else { - tmp = nil - } - fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, tmp, n) + fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), n) } switch n.Op { @@ -629,8 +643,12 @@ func esc(e *EscState, n *Node, up *Node) { // Everything but fixed array is a dereference. case ORANGE: - if Isfixedarray(n.Type) && n.List != nil && n.List.Next != nil { - escassign(e, n.List.Next.N, n.Right) + if n.List != nil && n.List.Next != nil { + if Isfixedarray(n.Type) { + escassign(e, n.List.Next.N, n.Right) + } else { + escassign(e, n.List.Next.N, addDereference(n.Right)) + } } case OSWITCH: @@ -670,13 +688,7 @@ func esc(e *EscState, n *Node, up *Node) { // b escapes as well. If we ignore such OSLICEARR, we will conclude // that b does not escape when b contents do. if Debug['m'] != 0 { - var tmp *Sym - if n.Curfn != nil && n.Curfn.Nname != nil { - tmp = n.Curfn.Nname.Sym - } else { - tmp = nil - } - Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", tmp, Nconv(n.Left, obj.FmtShort)) + Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", curfnSym(n), Nconv(n.Left, obj.FmtShort)) } break @@ -763,7 +775,15 @@ func esc(e *EscState, n *Node, up *Node) { for ll := n.List.Next; ll != nil; ll = ll.Next { escassign(e, &e.theSink, ll.N) // lose track of assign to dereference } + } else { + // append(slice1, slice2...) -- slice2 itself does not escape, but contents do. + slice2 := n.List.Next.N + escassign(e, &e.theSink, addDereference(slice2)) // lose track of assign of dereference + if Debug['m'] > 2 { + Warnl(int(n.Lineno), "%v special treatment of append(slice1, slice2...) %v", curfnSym(n), Nconv(n, obj.FmtShort)) + } } + escassign(e, &e.theSink, addDereference(n.List.N)) // The original elements are now leaked, too case OCONV, OCONVNOP: escassign(e, n, n.Left) @@ -776,19 +796,15 @@ func esc(e *EscState, n *Node, up *Node) { case OARRAYLIT: if Isslice(n.Type) { - n.Esc = EscNone // until proven otherwise + // Slice itself is not leaked until proven otherwise + n.Esc = EscNone e.noesc = list(e.noesc, n) n.Escloopdepth = e.loopdepth + } - // Values make it to memory, lose track. - for ll := n.List; ll != nil; ll = ll.Next { - escassign(e, &e.theSink, ll.N.Right) - } - } else { - // Link values to array. - for ll := n.List; ll != nil; ll = ll.Next { - escassign(e, n, ll.N.Right) - } + // Link values to array/slice + for ll := n.List; ll != nil; ll = ll.Next { + escassign(e, n, ll.N.Right) } // Link values to struct. @@ -833,8 +849,8 @@ func esc(e *EscState, n *Node, up *Node) { if v.Op == OXXX { // unnamed out argument; see dcl.c:/^funcargs continue } - a = v.Closure - if !v.Byval { + a = v.Param.Closure + if !v.Name.Byval { a = Nod(OADDR, a, nil) a.Lineno = v.Lineno a.Escloopdepth = e.loopdepth @@ -909,14 +925,8 @@ func escassign(e *EscState, dst *Node, src *Node) { } if Debug['m'] > 1 { - var tmp *Sym - if Curfn != nil && Curfn.Nname != nil { - tmp = Curfn.Nname.Sym - } else { - tmp = nil - } fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n", - Ctxt.Line(int(lineno)), e.loopdepth, tmp, + Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Oconv(int(dst.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Oconv(int(src.Op), 0)) } @@ -1038,12 +1048,15 @@ func escassign(e *EscState, dst *Node, src *Node) { case OAPPEND: // Append returns first argument. + // Subsequent arguments are already leaked because they are operands to append. escassign(e, dst, src.List.N) case OINDEX: // Index of array preserves input value. if Isfixedarray(src.Left.Type) { escassign(e, dst, src.Left) + } else { + escflows(e, dst, src) } // Might be pointer arithmetic, in which case @@ -1269,6 +1282,24 @@ func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 { return (e &^ (bitsMaskForTag << shift)) | encodedFlow } +func initEscretval(e *EscState, n *Node, fntype *Type) { + i := 0 + n.Escretval = nil // Suspect this is not nil for indirect calls. + for t := getoutargx(fntype).Type; t != nil; t = t.Down { + src := Nod(ONAME, nil, nil) + buf := fmt.Sprintf(".out%d", i) + i++ + src.Sym = Lookup(buf) + src.Type = t.Type + src.Class = PAUTO + src.Curfn = Curfn + src.Escloopdepth = e.loopdepth + src.Used = true + src.Lineno = n.Lineno + n.Escretval = list(n.Escretval, src) + } +} + // This is a bit messier than fortunate, pulled out of esc's big // switch for clarity. We either have the paramnodes, which may be // connected to other things through flows or we have the parameter type @@ -1277,7 +1308,7 @@ func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 { // this-package func esccall(e *EscState, n *Node, up *Node) { var fntype *Type - + var indirect bool var fn *Node switch n.Op { default: @@ -1286,6 +1317,7 @@ func esccall(e *EscState, n *Node, up *Node) { case OCALLFUNC: fn = n.Left fntype = fn.Type + indirect = fn.Op != ONAME || fn.Class != PFUNC case OCALLMETH: fn = n.Left.Right.Sym.Def @@ -1297,6 +1329,7 @@ func esccall(e *EscState, n *Node, up *Node) { case OCALLINTER: fntype = n.Left.Type + indirect = true } ll := n.List @@ -1307,8 +1340,30 @@ func esccall(e *EscState, n *Node, up *Node) { } } + if indirect { + // We know nothing! + // Leak all the parameters + for ; ll != nil; ll = ll.Next { + escassign(e, &e.theSink, ll.N) + if Debug['m'] > 2 { + fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort)) + } + } + // Set up bogus outputs + initEscretval(e, n, fntype) + // If there is a receiver, it also leaks to heap. + if n.Op != OCALLFUNC { + t := getthisx(fntype).Type + src := n.Left.Left + if haspointers(t.Type) { + escassign(e, &e.theSink, src) + } + } + return + } + if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && - fn.Defn != nil && fn.Defn.Nbody != nil && fn.Ntype != nil && fn.Defn.Esc < EscFuncTagged { + fn.Defn != nil && fn.Defn.Nbody != nil && fn.Param.Ntype != nil && fn.Defn.Esc < EscFuncTagged { if Debug['m'] > 2 { fmt.Printf("%v::esccall:: %v in recursive group\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort)) } @@ -1320,17 +1375,17 @@ func esccall(e *EscState, n *Node, up *Node) { } // set up out list on this call node - for lr := fn.Ntype.Rlist; lr != nil; lr = lr.Next { + for lr := fn.Param.Ntype.Rlist; lr != nil; lr = lr.Next { n.Escretval = list(n.Escretval, lr.N.Left) // type.rlist -> dclfield -> ONAME (PPARAMOUT) } // Receiver. if n.Op != OCALLFUNC { - escassign(e, fn.Ntype.Left.Left, n.Left.Left) + escassign(e, fn.Param.Ntype.Left.Left, n.Left.Left) } var src *Node - for lr := fn.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next { + for lr := fn.Param.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next { src = ll.N if lr.N.Isddd && !n.Isddd { // Introduce ODDDARG node to represent ... allocation. @@ -1376,23 +1431,7 @@ func esccall(e *EscState, n *Node, up *Node) { } // set up out list on this call node with dummy auto ONAMES in the current (calling) function. - i := 0 - - var src *Node - var buf string - for t := getoutargx(fntype).Type; t != nil; t = t.Down { - src = Nod(ONAME, nil, nil) - buf = fmt.Sprintf(".out%d", i) - i++ - src.Sym = Lookup(buf) - src.Type = t.Type - src.Class = PAUTO - src.Curfn = Curfn - src.Escloopdepth = e.loopdepth - src.Used = true - src.Lineno = n.Lineno - n.Escretval = list(n.Escretval, src) - } + initEscretval(e, n, fntype) // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval); @@ -1405,9 +1444,8 @@ func esccall(e *EscState, n *Node, up *Node) { } } - var a *Node for t := getinargx(fntype).Type; ll != nil; ll = ll.Next { - src = ll.N + src := ll.N if t.Isddd && !n.Isddd { // Introduce ODDDARG node to represent ... allocation. src = Nod(ODDDARG, nil, nil) @@ -1425,7 +1463,7 @@ func esccall(e *EscState, n *Node, up *Node) { if haspointers(t.Type) { if escassignfromtag(e, t.Note, n.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC { - a = src + a := src for a.Op == OCONVNOP { a = a.Left } @@ -1510,13 +1548,7 @@ func escflood(e *EscState, dst *Node) { } if Debug['m'] > 1 { - var tmp *Sym - if dst.Curfn != nil && dst.Curfn.Nname != nil { - tmp = dst.Curfn.Nname.Sym - } else { - tmp = nil - } - fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", walkgen, Nconv(dst, obj.FmtShort), tmp, dst.Escloopdepth) + fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", walkgen, Nconv(dst, obj.FmtShort), curfnSym(dst), dst.Escloopdepth) } for l := dst.Escflowsrc; l != nil; l = l.Next { @@ -1548,14 +1580,8 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) { src.Esclevel = level if Debug['m'] > 1 { - var tmp *Sym - if src.Curfn != nil && src.Curfn.Nname != nil { - tmp = src.Curfn.Nname.Sym - } else { - tmp = nil - } fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d]\n", - level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), tmp, src.Escloopdepth) + level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), curfnSym(src), src.Escloopdepth) } e.pdepth++ @@ -1627,7 +1653,7 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) { if leaks && Debug['m'] != 0 { Warnl(int(src.Lineno), "leaking closure reference %v", Nconv(src, obj.FmtShort)) } - escwalk(e, level, dst, src.Closure) + escwalk(e, level, dst, src.Param.Closure) } case OPTRLIT, OADDR: @@ -1657,6 +1683,10 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) { if Isfixedarray(src.Type) { break } + for ll := src.List; ll != nil; ll = ll.Next { + escwalk(e, level.dec(), dst, ll.N.Right) + } + fallthrough case ODDDARG, diff --git a/src/cmd/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index 1efc8150c5..5117490ac8 100644 --- a/src/cmd/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -64,7 +64,7 @@ func autoexport(n *Node, ctxt uint8) { if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN { return } - if n.Ntype != nil && n.Ntype.Op == OTFUNC && n.Ntype.Left != nil { // method + if n.Param != nil && n.Param.Ntype != nil && n.Param.Ntype.Op == OTFUNC && n.Param.Ntype.Left != nil { // method return } diff --git a/src/cmd/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 1a991a0a65..4b93363c73 100644 --- a/src/cmd/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -302,12 +302,12 @@ func Vconv(v *Val, flag int) string { switch v.Ctype { case CTINT: if (flag&obj.FmtSharp != 0) || fmtmode == FExp { - return Bconv(v.U.Xval, obj.FmtSharp) + return Bconv(v.U.(*Mpint), obj.FmtSharp) } - return Bconv(v.U.Xval, 0) + return Bconv(v.U.(*Mpint), 0) case CTRUNE: - x := Mpgetfix(v.U.Xval) + x := Mpgetfix(v.U.(*Mpint)) if ' ' <= x && x < 0x80 && x != '\\' && x != '\'' { return fmt.Sprintf("'%c'", int(x)) } @@ -317,34 +317,34 @@ func Vconv(v *Val, flag int) string { if 0 <= x && x <= utf8.MaxRune { return fmt.Sprintf("'\\U%08x'", uint64(x)) } - return fmt.Sprintf("('\\x00' + %v)", v.U.Xval) + return fmt.Sprintf("('\\x00' + %v)", v.U.(*Mpint)) case CTFLT: if (flag&obj.FmtSharp != 0) || fmtmode == FExp { - return Fconv(v.U.Fval, 0) + return Fconv(v.U.(*Mpflt), 0) } - return Fconv(v.U.Fval, obj.FmtSharp) + return Fconv(v.U.(*Mpflt), obj.FmtSharp) case CTCPLX: if (flag&obj.FmtSharp != 0) || fmtmode == FExp { - return fmt.Sprintf("(%v+%vi)", &v.U.Cval.Real, &v.U.Cval.Imag) + return fmt.Sprintf("(%v+%vi)", &v.U.(*Mpcplx).Real, &v.U.(*Mpcplx).Imag) } - if mpcmpfltc(&v.U.Cval.Real, 0) == 0 { - return fmt.Sprintf("%vi", Fconv(&v.U.Cval.Imag, obj.FmtSharp)) + if mpcmpfltc(&v.U.(*Mpcplx).Real, 0) == 0 { + return fmt.Sprintf("%vi", Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp)) } - if mpcmpfltc(&v.U.Cval.Imag, 0) == 0 { - return Fconv(&v.U.Cval.Real, obj.FmtSharp) + if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) == 0 { + return Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp) } - if mpcmpfltc(&v.U.Cval.Imag, 0) < 0 { - return fmt.Sprintf("(%v%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp)) + if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) < 0 { + return fmt.Sprintf("(%v%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp)) } - return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp)) + return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp)) case CTSTR: - return strconv.Quote(v.U.Sval) + return strconv.Quote(v.U.(string)) case CTBOOL: - if v.U.Bval { + if v.U.(bool) { return "true" } return "false" @@ -1127,7 +1127,7 @@ func exprfmt(n *Node, prec int) string { // Special case: name used as local variable in export. // _ becomes ~b%d internally; print as _ for export case ONAME: - if fmtmode == FExp && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' { + if (fmtmode == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' { return "_" } if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Vargen > 0 { @@ -1199,7 +1199,7 @@ func exprfmt(n *Node, prec int) string { if n.Nbody != nil { return fmt.Sprintf("%v { %v }", n.Type, n.Nbody) } - return fmt.Sprintf("%v { %v }", n.Type, n.Closure.Nbody) + return fmt.Sprintf("%v { %v }", n.Type, n.Param.Closure.Nbody) case OCOMPLIT: ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && Isptr[n.Right.Type.Etype] @@ -1521,9 +1521,9 @@ func nodedump(n *Node, flag int) string { } else { fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0)) } - if recur && n.Type == nil && n.Ntype != nil { + if recur && n.Type == nil && n.Param.Ntype != nil { indent(&buf) - fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Ntype) + fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Param.Ntype) } case OASOP: @@ -1531,9 +1531,9 @@ func nodedump(n *Node, flag int) string { case OTYPE: fmt.Fprintf(&buf, "%v %v%v type=%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0), n.Type) - if recur && n.Type == nil && n.Ntype != nil { + if recur && n.Type == nil && n.Param.Ntype != nil { indent(&buf) - fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Ntype) + fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Param.Ntype) } } diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go index e6af897033..c0dd9964ea 100644 --- a/src/cmd/internal/gc/gen.go +++ b/src/cmd/compile/internal/gc/gen.go @@ -57,14 +57,14 @@ func addrescapes(n *Node) { // expression to refer to stack copy case PPARAM, PPARAMOUT: - n.Stackparam = Nod(OPARAM, n, nil) + n.Param.Stackparam = Nod(OPARAM, n, nil) - n.Stackparam.Type = n.Type - n.Stackparam.Addable = true + n.Param.Stackparam.Type = n.Type + n.Param.Stackparam.Addable = true if n.Xoffset == BADWIDTH { Fatal("addrescapes before param assignment") } - n.Stackparam.Xoffset = n.Xoffset + n.Param.Stackparam.Xoffset = n.Xoffset fallthrough case PAUTO: @@ -78,10 +78,10 @@ func addrescapes(n *Node) { oldfn := Curfn Curfn = n.Curfn - n.Heapaddr = temp(Ptrto(n.Type)) + n.Name.Heapaddr = temp(Ptrto(n.Type)) buf := fmt.Sprintf("&%v", n.Sym) - n.Heapaddr.Sym = Lookup(buf) - n.Heapaddr.Orig.Sym = n.Heapaddr.Sym + n.Name.Heapaddr.Sym = Lookup(buf) + n.Name.Heapaddr.Orig.Sym = n.Name.Heapaddr.Sym n.Esc = EscHeap if Debug['m'] != 0 { fmt.Printf("%v: moved to heap: %v\n", n.Line(), n) @@ -262,7 +262,7 @@ func cgen_dcl(n *Node) { if n.Alloc == nil { n.Alloc = callnew(n.Type) } - Cgen_as(n.Heapaddr, n.Alloc) + Cgen_as(n.Name.Heapaddr, n.Alloc) } /* @@ -333,21 +333,22 @@ func Clearslim(n *Node) { switch Simtype[n.Type.Etype] { case TCOMPLEX64, TCOMPLEX128: - z.Val.U.Cval = new(Mpcplx) - Mpmovecflt(&z.Val.U.Cval.Real, 0.0) - Mpmovecflt(&z.Val.U.Cval.Imag, 0.0) + z.Val.U = new(Mpcplx) + Mpmovecflt(&z.Val.U.(*Mpcplx).Real, 0.0) + Mpmovecflt(&z.Val.U.(*Mpcplx).Imag, 0.0) case TFLOAT32, TFLOAT64: var zero Mpflt Mpmovecflt(&zero, 0.0) z.Val.Ctype = CTFLT - z.Val.U.Fval = &zero + z.Val.U = &zero case TPTR32, TPTR64, TCHAN, TMAP: z.Val.Ctype = CTNIL case TBOOL: z.Val.Ctype = CTBOOL + z.Val.U = false case TINT8, TINT16, @@ -358,8 +359,8 @@ func Clearslim(n *Node) { TUINT32, TUINT64: z.Val.Ctype = CTINT - z.Val.U.Xval = new(Mpint) - Mpmovecfix(z.Val.U.Xval, 0) + z.Val.U = new(Mpint) + Mpmovecfix(z.Val.U.(*Mpint), 0) default: Fatal("clearslim called on type %v", n.Type) @@ -428,8 +429,7 @@ func cgen_dottype(n *Node, res, resok *Node, wb bool) { Cgen(&iface, &r1) if !isnilinter(n.Left.Type) { // Holding itab, want concrete type in second word. - Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, Nodintconst(0)) - p := Gbranch(Thearch.Optoas(OEQ, byteptr), nil, -1) + p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1) r2 = r1 r2.Op = OINDREG r2.Xoffset = int64(Widthptr) @@ -438,8 +438,7 @@ func cgen_dottype(n *Node, res, resok *Node, wb bool) { } Regalloc(&r2, byteptr, nil) Cgen(typename(n.Type), &r2) - Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2) - p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1) + p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1) Regfree(&r2) // not needed for success path; reclaimed on one failure path iface.Xoffset += int64(Widthptr) Cgen(&iface, &r1) @@ -521,8 +520,7 @@ func Cgen_As2dottype(n, res, resok *Node) { Cgen(&iface, &r1) if !isnilinter(n.Left.Type) { // Holding itab, want concrete type in second word. - Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, Nodintconst(0)) - p := Gbranch(Thearch.Optoas(OEQ, byteptr), nil, -1) + p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1) r2 = r1 r2.Op = OINDREG r2.Xoffset = int64(Widthptr) @@ -531,8 +529,7 @@ func Cgen_As2dottype(n, res, resok *Node) { } Regalloc(&r2, byteptr, nil) Cgen(typename(n.Type), &r2) - Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2) - p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1) + p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1) iface.Type = n.Type iface.Xoffset += int64(Widthptr) Cgen(&iface, &r1) @@ -556,122 +553,6 @@ func Cgen_As2dottype(n, res, resok *Node) { } /* - * generate: - * res = s[lo, hi]; - * n->left is s - * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)]) - * caller (cgen) guarantees res is an addable ONAME. - * - * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR. - */ -func Cgen_slice(n *Node, res *Node) { - cap := n.List.N - len := n.List.Next.N - var offs *Node - if n.List.Next.Next != nil { - offs = n.List.Next.Next.N - } - - // evaluate base pointer first, because it is the only - // possibly complex expression. once that is evaluated - // and stored, updating the len and cap can be done - // without making any calls, so without doing anything that - // might cause preemption or garbage collection. - // this makes the whole slice update atomic as far as the - // garbage collector can see. - base := temp(Types[TUINTPTR]) - - tmplen := temp(Types[TINT]) - var tmpcap *Node - if n.Op != OSLICESTR { - tmpcap = temp(Types[TINT]) - } else { - tmpcap = tmplen - } - - var src Node - if isnil(n.Left) { - Tempname(&src, n.Left.Type) - Cgen(n.Left, &src) - } else { - src = *n.Left - } - if n.Op == OSLICE || n.Op == OSLICE3 || n.Op == OSLICESTR { - src.Xoffset += int64(Array_array) - } - - if n.Op == OSLICEARR || n.Op == OSLICE3ARR { - if !Isptr[n.Left.Type.Etype] { - Fatal("slicearr is supposed to work on pointer: %v\n", Nconv(n, obj.FmtSign)) - } - Cgen(&src, base) - Cgen_checknil(base) - } else { - src.Type = Types[Tptr] - Cgen(&src, base) - } - - // committed to the update - Gvardef(res) - - // compute len and cap. - // len = n-i, cap = m-i, and offs = i*width. - // computing offs last lets the multiply overwrite i. - Cgen((*Node)(len), tmplen) - - if n.Op != OSLICESTR { - Cgen(cap, tmpcap) - } - - // if new cap != 0 { base += add } - // This avoids advancing base past the end of the underlying array/string, - // so that it cannot point at the next object in memory. - // If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero. - // In essence we are replacing x[i:j:k] where i == j == k - // or x[i:j] where i == j == cap(x) with x[0:0:0]. - if offs != nil { - p1 := gjmp(nil) - p2 := gjmp(nil) - Patch(p1, Pc) - - var con Node - Nodconst(&con, tmpcap.Type, 0) - cmp := Nod(OEQ, tmpcap, &con) - typecheck(&cmp, Erv) - Bgen(cmp, true, -1, p2) - - add := Nod(OADD, base, offs) - typecheck(&add, Erv) - Cgen(add, base) - - Patch(p2, Pc) - } - - // dst.array = src.array [ + lo *width ] - dst := *res - - dst.Xoffset += int64(Array_array) - dst.Type = Types[Tptr] - Cgen(base, &dst) - - // dst.len = hi [ - lo ] - dst = *res - - dst.Xoffset += int64(Array_nel) - dst.Type = Types[Simtype[TUINT]] - Cgen(tmplen, &dst) - - if n.Op != OSLICESTR { - // dst.cap = cap [ - lo ] - dst = *res - - dst.Xoffset += int64(Array_cap) - dst.Type = Types[Simtype[TUINT]] - Cgen(tmpcap, &dst) - } -} - -/* * gather series of offsets * >=0 is direct addressed field * <0 is pointer to next field (+1) @@ -1085,7 +966,7 @@ func cgen_callmeth(n *Node, proc int) { l := n.Left if l.Op != ODOTMETH { - Fatal("cgen_callmeth: not dotmethod: %v") + Fatal("cgen_callmeth: not dotmethod: %v", l) } n2 := *n @@ -1241,7 +1122,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool { nodl.Type = Ptrto(Types[TUINT8]) Regalloc(&nodr, Types[Tptr], nil) p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr) - Datastring(nr.Val.U.Sval, &p.From) + Datastring(nr.Val.U.(string), &p.From) p.From.Type = obj.TYPE_ADDR Thearch.Gmove(&nodr, &nodl) Regfree(&nodr) @@ -1249,7 +1130,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool { // length nodl.Type = Types[Simtype[TUINT]] nodl.Xoffset += int64(Array_nel) - int64(Array_array) - Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.Sval))) + Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.(string)))) Thearch.Gmove(&nodr, &nodl) return true } diff --git a/src/cmd/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 71bce0bf2c..dc33f62ba4 100644 --- a/src/cmd/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -6,7 +6,7 @@ package gc import ( "bytes" - "cmd/internal/gc/big" + "cmd/compile/internal/big" "cmd/internal/obj" ) @@ -83,13 +83,13 @@ type Mpcplx struct { type Val struct { Ctype int16 - U struct { - Bval bool // bool value CTBOOL - Xval *Mpint // int CTINT, rune CTRUNE - Fval *Mpflt // float CTFLT - Cval *Mpcplx // float CTCPLX - Sval string // string CTSTR - } + // U contains one of: + // bool bool when Ctype == CTBOOL + // *Mpint int when Ctype == CTINT, rune when Ctype == CTRUNE + // *Mpflt float when Ctype == CTFLT + // *Mpcplx pair of floats when Ctype == CTCPLX + // string string when Ctype == CTSTR + U interface{} } type Pkg struct { @@ -448,7 +448,7 @@ var nsavederrors int var nsyntaxerrors int -var decldepth int +var decldepth int32 var safemode int @@ -778,13 +778,27 @@ type Arch struct { Expandchecks func(*obj.Prog) Getg func(*Node) Gins func(int, *Node, *Node) *obj.Prog + + // Ginscmp generates code comparing n1 to n2 and jumping away if op is satisfied. + // The returned prog should be Patch'ed with the jump target. + // If op is not satisfied, code falls through to the next emitted instruction. + // Likely is the branch prediction hint: +1 for likely, -1 for unlikely, 0 for no opinion. + // + // Ginscmp must be able to handle all kinds of arguments for n1 and n2, + // not just simple registers, although it can assume that there are no + // function calls needed during the evaluation, and on 32-bit systems + // the values are guaranteed not to be 64-bit values, so no in-memory + // temporaries are necessary. + Ginscmp func(op int, t *Type, n1, n2 *Node, likely int) *obj.Prog + // Ginsboolval inserts instructions to convert the result // of a just-completed comparison to a boolean value. // The first argument is the conditional jump instruction // corresponding to the desired value. // The second argument is the destination. // If not present, Ginsboolval will be emulated with jumps. - Ginsboolval func(int, *Node) + Ginsboolval func(int, *Node) + Ginscon func(int, int64, *Node) Ginsnop func() Gmove func(*Node, *Node) diff --git a/src/cmd/internal/gc/go.y b/src/cmd/compile/internal/gc/go.y index f1904b0085..ae2e7613ab 100644 --- a/src/cmd/internal/gc/go.y +++ b/src/cmd/compile/internal/gc/go.y @@ -21,6 +21,7 @@ package gc import ( + "fmt" "strings" ) %} @@ -116,7 +117,68 @@ import ( %left ')' %left PreferToRightParen -// TODO(rsc): Add %error-verbose +%error loadsys package LIMPORT '(' LLITERAL import_package import_there ',': + "unexpected comma during import block" + +%error loadsys package LIMPORT LNAME ';': + "missing import path; require quoted string" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';': + "missing { after if clause" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';': + "missing { after switch clause" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';': + "missing { after for clause" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY: + "missing { after for clause" + +%error loadsys package imports LFUNC LNAME '(' ')' ';' '{': + "unexpected semicolon or newline before {" + +%error loadsys package imports LTYPE LNAME ';': + "unexpected semicolon or newline in type declaration" + +%error loadsys package imports LCHAN '}': + "unexpected } in channel type" + +%error loadsys package imports LCHAN ')': + "unexpected ) in channel type" + +%error loadsys package imports LCHAN ',': + "unexpected comma in channel type" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE: + "unexpected semicolon or newline before else" + +%error loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME: + "name list not allowed in interface type" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME: + "var declaration not allowed in for initializer" + +%error loadsys package imports LVAR LNAME '[' ']' LNAME '{': + "unexpected { at end of statement" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{': + "unexpected { at end of statement" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';': + "argument to go/defer must be function call" + +%error loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';': + "need trailing comma before newline in composite literal" + +%error loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';': + "need trailing comma before newline in composite literal" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME: + "nested func not allowed" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';': + "else must be followed by if or statement block" %% file: @@ -1130,13 +1192,13 @@ hidden_importsym: { var p *Pkg - if $2.U.Sval == "" { + if $2.U.(string) == "" { p = importpkg; } else { - if isbadimport($2.U.Sval) { + if isbadimport($2.U.(string)) { errorexit(); } - p = mkpkg($2.U.Sval); + p = mkpkg($2.U.(string)); } $$ = Pkglookup($4.Name, p); } @@ -1144,13 +1206,13 @@ hidden_importsym: { var p *Pkg - if $2.U.Sval == "" { + if $2.U.(string) == "" { p = importpkg; } else { - if isbadimport($2.U.Sval) { + if isbadimport($2.U.(string)) { errorexit(); } - p = mkpkg($2.U.Sval); + p = mkpkg($2.U.(string)); } $$ = Pkglookup("?", p); } @@ -1360,7 +1422,7 @@ fndcl: $$ = Nod(ODCLFUNC, nil, nil); $$.Nname = newfuncname($1); $$.Nname.Defn = $$; - $$.Nname.Ntype = t; // TODO: check if nname already has an ntype + $$.Nname.Param.Ntype = t; // TODO: check if nname already has an ntype declare($$.Nname, PFUNC); funchdr($$); @@ -1395,7 +1457,7 @@ fndcl: $$.Func.Shortname = newfuncname($4); $$.Nname = methodname1($$.Func.Shortname, rcvr.Right); $$.Nname.Defn = $$; - $$.Nname.Ntype = t; + $$.Nname.Param.Ntype = t; $$.Nname.Nointerface = nointerface; declare($$.Nname, PFUNC); @@ -1944,7 +2006,7 @@ oliteral: hidden_import: LIMPORT LNAME LLITERAL ';' { - importimport($2, $3.U.Sval); + importimport($2, $3.U.(string)); } | LVAR hidden_pkg_importsym hidden_type ';' { @@ -1975,9 +2037,9 @@ hidden_import: importlist = list(importlist, $2); if Debug['E'] > 0 { - print("import [%q] func %lN \n", importpkg.Path, $2); + fmt.Printf("import [%q] func %v \n", importpkg.Path, $2) if Debug['m'] > 2 && $2.Func.Inl != nil { - print("inl body:%+H\n", $2.Func.Inl); + fmt.Printf("inl body:%v\n", $2.Func.Inl) } } } @@ -2171,14 +2233,14 @@ hidden_literal: $$ = nodlit($2); switch($$.Val.Ctype){ case CTINT, CTRUNE: - mpnegfix($$.Val.U.Xval); + mpnegfix($$.Val.U.(*Mpint)); break; case CTFLT: - mpnegflt($$.Val.U.Fval); + mpnegflt($$.Val.U.(*Mpflt)); break; case CTCPLX: - mpnegflt(&$$.Val.U.Cval.Real); - mpnegflt(&$$.Val.U.Cval.Imag); + mpnegflt(&$$.Val.U.(*Mpcplx).Real); + mpnegflt(&$$.Val.U.(*Mpcplx).Imag); break; default: Yyerror("bad negated constant"); @@ -2198,11 +2260,11 @@ hidden_constant: { if $2.Val.Ctype == CTRUNE && $4.Val.Ctype == CTINT { $$ = $2; - mpaddfixfix($2.Val.U.Xval, $4.Val.U.Xval, 0); + mpaddfixfix($2.Val.U.(*Mpint), $4.Val.U.(*Mpint), 0); break; } - $4.Val.U.Cval.Real = $4.Val.U.Cval.Imag; - Mpmovecflt(&$4.Val.U.Cval.Imag, 0.0); + $4.Val.U.(*Mpcplx).Real = $4.Val.U.(*Mpcplx).Imag; + Mpmovecflt(&$4.Val.U.(*Mpcplx).Imag, 0.0); $$ = nodcplxlit($2.Val, $4.Val); } diff --git a/src/cmd/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go index 53b3f6c41d..5ec4587e74 100644 --- a/src/cmd/internal/gc/gsubr.go +++ b/src/cmd/compile/internal/gc/gsubr.go @@ -90,6 +90,10 @@ func Gbranch(as int, t *Type, likely int) *obj.Prog { p.From.Offset = int64(obj.Bool2int(likely > 0)) } + if Debug['g'] != 0 { + fmt.Printf("%v\n", p) + } + return p } @@ -210,7 +214,7 @@ func ggloblnod(nam *Node) { p.To.Sym = nil p.To.Type = obj.TYPE_CONST p.To.Offset = nam.Type.Width - if nam.Readonly { + if nam.Name.Readonly { p.From3.Offset = obj.RODATA } if nam.Type != nil && !haspointers(nam.Type) { @@ -365,7 +369,7 @@ func Naddr(a *obj.Addr, n *Node) { if s == nil { s = Lookup(".noname") } - if n.Method { + if n.Name.Method { if n.Type != nil { if n.Type.Sym != nil { if n.Type.Sym.Pkg != nil { @@ -408,20 +412,20 @@ func Naddr(a *obj.Addr, n *Node) { case CTFLT: a.Type = obj.TYPE_FCONST - a.Val = mpgetflt(n.Val.U.Fval) + a.Val = mpgetflt(n.Val.U.(*Mpflt)) case CTINT, CTRUNE: a.Sym = nil a.Type = obj.TYPE_CONST - a.Offset = Mpgetfix(n.Val.U.Xval) + a.Offset = Mpgetfix(n.Val.U.(*Mpint)) case CTSTR: - datagostring(n.Val.U.Sval, a) + datagostring(n.Val.U.(string), a) case CTBOOL: a.Sym = nil a.Type = obj.TYPE_CONST - a.Offset = int64(obj.Bool2int(n.Val.U.Bval)) + a.Offset = int64(obj.Bool2int(n.Val.U.(bool))) case CTNIL: a.Sym = nil @@ -621,20 +625,20 @@ func gclean() { for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { n := reg[r-Thearch.REGMIN] if n != 0 { - Yyerror("reg %v left allocated", obj.Rconv(r)) if Debug['v'] != 0 { Regdump() } + Yyerror("reg %v left allocated", obj.Rconv(r)) } } for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { n := reg[r-Thearch.REGMIN] if n != 0 { - Yyerror("reg %v left allocated", obj.Rconv(r)) if Debug['v'] != 0 { Regdump() } + Yyerror("reg %v left allocated", obj.Rconv(r)) } } } diff --git a/src/cmd/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go index b5d1e505a5..92bfeecdef 100644 --- a/src/cmd/internal/gc/init.go +++ b/src/cmd/compile/internal/gc/init.go @@ -116,7 +116,7 @@ func fninit(n *NodeList) { initsym := Lookup("init") fn.Nname = newname(initsym) fn.Nname.Defn = fn - fn.Nname.Ntype = Nod(OTFUNC, nil, nil) + fn.Nname.Param.Ntype = Nod(OTFUNC, nil, nil) declare(fn.Nname, PFUNC) funchdr(fn) diff --git a/src/cmd/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index dd2087dec3..22a5d3d9fe 100644 --- a/src/cmd/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -511,10 +511,10 @@ func mkinlcall(np **Node, fn *Node, isddd bool) { func tinlvar(t *Type) *Node { if t.Nname != nil && !isblank(t.Nname) { - if t.Nname.Inlvar == nil { + if t.Nname.Name.Inlvar == nil { Fatal("missing inlvar for %v\n", t.Nname) } - return t.Nname.Inlvar + return t.Nname.Name.Inlvar } typecheck(&nblank, Erv|Easgn) @@ -577,13 +577,13 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) { continue } if ll.N.Op == ONAME { - ll.N.Inlvar = inlvar(ll.N) + ll.N.Name.Inlvar = inlvar(ll.N) // Typecheck because inlvar is not necessarily a function parameter. - typecheck(&ll.N.Inlvar, Erv) + typecheck(&ll.N.Name.Inlvar, Erv) if ll.N.Class&^PHEAP != PAUTO { - ninit = list(ninit, Nod(ODCL, ll.N.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs + ninit = list(ninit, Nod(ODCL, ll.N.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs } } } @@ -594,7 +594,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) { if t != nil && t.Nname != nil && !isblank(t.Nname) { m = inlvar(t.Nname) typecheck(&m, Erv) - t.Nname.Inlvar = m + t.Nname.Name.Inlvar = m } else { // anonymous return values, synthesize names for use in assignment that replaces return m = retvar(t, i) @@ -611,7 +611,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) { // method call with a receiver. t := getthisx(fn.Type).Type - if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Inlvar == nil { + if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil { Fatal("missing inlvar for %v\n", t.Nname) } if n.Left.Left == nil { @@ -680,7 +680,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) { // append receiver inlvar to LHS. t := getthisx(fn.Type).Type - if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Inlvar == nil { + if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil { Fatal("missing inlvar for %v\n", t.Nname) } if t == nil { @@ -907,11 +907,11 @@ func inlsubst(n *Node) *Node { switch n.Op { case ONAME: - if n.Inlvar != nil { // These will be set during inlnode + if n.Name.Inlvar != nil { // These will be set during inlnode if Debug['m'] > 2 { - fmt.Printf("substituting name %v -> %v\n", Nconv(n, obj.FmtSign), Nconv(n.Inlvar, obj.FmtSign)) + fmt.Printf("substituting name %v -> %v\n", Nconv(n, obj.FmtSign), Nconv(n.Name.Inlvar, obj.FmtSign)) } - return n.Inlvar + return n.Name.Inlvar } if Debug['m'] > 2 { diff --git a/src/cmd/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 4bbda957a5..cf41c40964 100644 --- a/src/cmd/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:generate go tool yacc go.y -//go:generate go run yaccerrors.go //go:generate go run mkbuiltin.go runtime unsafe package gc @@ -35,7 +34,11 @@ var goarch string var goroot string -var Debug_wb int +var ( + Debug_wb int + Debug_append int + Debug_slice int +) // Debug arguments. // These can be specified with the -d flag, as in "-d nil" @@ -45,9 +48,12 @@ var debugtab = []struct { name string val *int }{ + {"append", &Debug_append}, // print information about append compilation + {"disablenil", &Disable_checknil}, // disable nil checks + {"gcprog", &Debug_gcprog}, // print dump of GC programs {"nil", &Debug_checknil}, // print information about nil checks + {"slice", &Debug_slice}, // print information about slice compilation {"typeassert", &Debug_typeassert}, // print information about type assertion inlining - {"disablenil", &Disable_checknil}, // disable nil checks {"wb", &Debug_wb}, // print information about write barriers } @@ -308,7 +314,7 @@ func Main() { lexlineno = 1 for _, infile = range flag.Args() { - linehist(infile, 0, 0) + linehistpush(infile) curio.infile = infile var err error @@ -339,7 +345,7 @@ func Main() { errorexit() } - linehist("<pop>", 0, 0) + linehistpop() if curio.bin != nil { obj.Bterm(curio.bin) } @@ -394,7 +400,7 @@ func Main() { // This needs to run before escape analysis, // because variables captured by value do not escape. for l := xtop; l != nil; l = l.Next { - if l.N.Op == ODCLFUNC && l.N.Closure != nil { + if l.N.Op == ODCLFUNC && l.N.Param.Closure != nil { Curfn = l.N capturevars(l.N) } @@ -440,17 +446,15 @@ func Main() { // which stores the addresses of stack variables into the closure. // If the closure does not escape, it needs to be on the stack // or else the stack copier will not update it. + // Large values are also moved off stack in escape analysis; + // because large values may contain pointers, it must happen early. escapes(xtop) - // Escape analysis moved escaped values off stack. - // Move large values off stack too. - movelarge(xtop) - // Phase 7: Transform closure bodies to properly reference captured variables. // This needs to happen before walk, because closures must be transformed // before walk reaches a call of a closure. for l := xtop; l != nil; l = l.Next { - if l.N.Op == ODCLFUNC && l.N.Closure != nil { + if l.N.Op == ODCLFUNC && l.N.Param.Closure != nil { Curfn = l.N transformclosure(l.N) } @@ -577,7 +581,7 @@ func findpkg(name string) (file string, ok bool) { if obj.Access(file, 0) >= 0 { return file, true } - file = fmt.Sprintf("%s.%c", name, Thearch.Thechar) + file = fmt.Sprintf("%s.o", name) if obj.Access(file, 0) >= 0 { return file, true } @@ -599,7 +603,7 @@ func findpkg(name string) (file string, ok bool) { if obj.Access(file, 0) >= 0 { return file, true } - file = fmt.Sprintf("%s/%s.%c", p.dir, name, Thearch.Thechar) + file = fmt.Sprintf("%s/%s.o", p.dir, name) if obj.Access(file, 0) >= 0 { return file, true } @@ -620,7 +624,7 @@ func findpkg(name string) (file string, ok bool) { if obj.Access(file, 0) >= 0 { return file, true } - file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.%c", goroot, goos, goarch, suffixsep, suffix, name, Thearch.Thechar) + file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", goroot, goos, goarch, suffixsep, suffix, name) if obj.Access(file, 0) >= 0 { return file, true } @@ -631,7 +635,7 @@ func findpkg(name string) (file string, ok bool) { func fakeimport() { importpkg = mkpkg("fake") - cannedimports("fake.6", "$$\n") + cannedimports("fake.o", "$$\n") } func importfile(f *Val, line int) { @@ -641,13 +645,13 @@ func importfile(f *Val, line int) { return } - if len(f.U.Sval) == 0 { + if len(f.U.(string)) == 0 { Yyerror("import path is empty") fakeimport() return } - if isbadimport(f.U.Sval) { + if isbadimport(f.U.(string)) { fakeimport() return } @@ -656,29 +660,29 @@ func importfile(f *Val, line int) { // 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 f.U.Sval == "main" { + if f.U.(string) == "main" { Yyerror("cannot import \"main\"") errorexit() } - if myimportpath != "" && f.U.Sval == myimportpath { - Yyerror("import %q while compiling that package (import cycle)", f.U.Sval) + if myimportpath != "" && f.U.(string) == myimportpath { + Yyerror("import %q while compiling that package (import cycle)", f.U.(string)) errorexit() } - if f.U.Sval == "unsafe" { + if f.U.(string) == "unsafe" { if safemode != 0 { Yyerror("cannot import package unsafe") errorexit() } - importpkg = mkpkg(f.U.Sval) - cannedimports("unsafe.6", unsafeimport) + importpkg = mkpkg(f.U.(string)) + cannedimports("unsafe.o", unsafeimport) imported_unsafe = 1 return } - path_ := f.U.Sval + path_ := f.U.(string) if islocalname(path_) { if path_[0] == '/' { Yyerror("import path cannot be absolute path") @@ -704,7 +708,7 @@ func importfile(f *Val, line int) { file, found := findpkg(path_) if !found { - Yyerror("can't find import: %q", f.U.Sval) + Yyerror("can't find import: %q", f.U.(string)) errorexit() } @@ -729,7 +733,7 @@ func importfile(f *Val, line int) { var imp *obj.Biobuf imp, err = obj.Bopenr(file) if err != nil { - Yyerror("can't open import: %q: %v", f.U.Sval, err) + Yyerror("can't open import: %q: %v", f.U.(string), err) errorexit() } @@ -758,7 +762,7 @@ func importfile(f *Val, line int) { // assume files move (get installed) // so don't record the full path. - linehist(file[len(file)-len(path_)-2:], -1, 1) // acts as #pragma lib + linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib /* * position the input right @@ -792,7 +796,7 @@ func importfile(f *Val, line int) { return } - Yyerror("no import in %q", f.U.Sval) + Yyerror("no import in %q", f.U.(string)) unimportfile() } @@ -1060,8 +1064,8 @@ l0: ungetc(int(v)) } - yylval.val.U.Xval = new(Mpint) - Mpmovecfix(yylval.val.U.Xval, v) + yylval.val.U = new(Mpint) + Mpmovecfix(yylval.val.U.(*Mpint), v) yylval.val.Ctype = CTRUNE if Debug['x'] != 0 { fmt.Printf("lex: codepoint literal\n") @@ -1399,11 +1403,11 @@ ncu: ungetc(c) str = lexbuf.String() - yylval.val.U.Xval = new(Mpint) - mpatofix(yylval.val.U.Xval, str) - if yylval.val.U.Xval.Ovf { + yylval.val.U = new(Mpint) + mpatofix(yylval.val.U.(*Mpint), str) + if yylval.val.U.(*Mpint).Ovf { Yyerror("overflow in constant") - Mpmovecfix(yylval.val.U.Xval, 0) + Mpmovecfix(yylval.val.U.(*Mpint), 0) } yylval.val.Ctype = CTINT @@ -1430,6 +1434,11 @@ casedot: } caseep: + if importpkg == nil && (c == 'p' || c == 'P') { + // <mantissa>p<base-2-exponent> is allowed in .a/.o imports, + // but not in .go sources. See #9036. + Yyerror("malformed floating point constant") + } cp.WriteByte(byte(c)) c = getc() if c == '+' || c == '-' { @@ -1438,7 +1447,7 @@ caseep: } if !yy_isdigit(c) { - Yyerror("malformed fp constant exponent") + Yyerror("malformed floating point constant exponent") } for yy_isdigit(c) { cp.WriteByte(byte(c)) @@ -1455,12 +1464,12 @@ casei: cp = nil str = lexbuf.String() - yylval.val.U.Cval = new(Mpcplx) - Mpmovecflt(&yylval.val.U.Cval.Real, 0.0) - mpatoflt(&yylval.val.U.Cval.Imag, str) - if yylval.val.U.Cval.Imag.Val.IsInf() { + yylval.val.U = new(Mpcplx) + Mpmovecflt(&yylval.val.U.(*Mpcplx).Real, 0.0) + mpatoflt(&yylval.val.U.(*Mpcplx).Imag, str) + if yylval.val.U.(*Mpcplx).Imag.Val.IsInf() { Yyerror("overflow in imaginary constant") - Mpmovecflt(&yylval.val.U.Cval.Real, 0.0) + Mpmovecflt(&yylval.val.U.(*Mpcplx).Real, 0.0) } yylval.val.Ctype = CTCPLX @@ -1475,11 +1484,11 @@ caseout: ungetc(c) str = lexbuf.String() - yylval.val.U.Fval = newMpflt() - mpatoflt(yylval.val.U.Fval, str) - if yylval.val.U.Fval.Val.IsInf() { + yylval.val.U = newMpflt() + mpatoflt(yylval.val.U.(*Mpflt), str) + if yylval.val.U.(*Mpflt).Val.IsInf() { Yyerror("overflow in float constant") - Mpmovecflt(yylval.val.U.Fval, 0.0) + Mpmovecflt(yylval.val.U.(*Mpflt), 0.0) } yylval.val.Ctype = CTFLT @@ -1490,7 +1499,7 @@ caseout: return LLITERAL strlit: - yylval.val.U.Sval = internString(cp.Bytes()) + yylval.val.U = internString(cp.Bytes()) yylval.val.Ctype = CTSTR if Debug['x'] != 0 { fmt.Printf("lex: string literal\n") @@ -1649,7 +1658,7 @@ func getlinepragma() int { } name = text[:linep-1] - linehist(name, int32(n), 0) + linehistupdate(name, n) return c out: @@ -2590,6 +2599,6 @@ func mkpackage(pkgname string) { if i := strings.LastIndex(p, "."); i >= 0 { p = p[:i] } - outfile = fmt.Sprintf("%s.%c", p, Thearch.Thechar) + outfile = fmt.Sprintf("%s.o", p) } } diff --git a/src/cmd/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go index b2362a6f01..f4569b48c2 100644 --- a/src/cmd/internal/gc/mkbuiltin.go +++ b/src/cmd/compile/internal/gc/mkbuiltin.go @@ -13,21 +13,14 @@ package main import ( "bufio" "fmt" - "go/build" "io" "log" "os" "os/exec" - "runtime" "strings" ) func main() { - gochar, err := build.ArchChar(runtime.GOARCH) - if err != nil { - log.Fatal(err) - } - f, err := os.Create("builtin.go") if err != nil { log.Fatal(err) @@ -40,7 +33,7 @@ func main() { fmt.Fprintln(w, "package gc") for _, name := range os.Args[1:] { - mkbuiltin(w, gochar, name) + mkbuiltin(w, name) } if err := w.Flush(); err != nil { @@ -49,11 +42,11 @@ func main() { } // Compile .go file, import data from .6 file, and write Go string version. -func mkbuiltin(w io.Writer, gochar string, name string) { - if err := exec.Command("go", "tool", gochar+"g", "-A", "builtin/"+name+".go").Run(); err != nil { +func mkbuiltin(w io.Writer, name string) { + if err := exec.Command("go", "tool", "compile", "-A", "builtin/"+name+".go").Run(); err != nil { log.Fatal(err) } - obj := fmt.Sprintf("%s.%s", name, gochar) + obj := "name.o" defer os.Remove(obj) r, err := os.Open(obj) @@ -77,7 +70,7 @@ Begin: fmt.Fprintf(w, "\nconst %simport = \"\" +\n", name) // sys.go claims to be in package PACKAGE to avoid - // conflicts during "6g sys.go". Rename PACKAGE to $2. + // conflicts during "go tool compile sys.go". Rename PACKAGE to $2. replacer := strings.NewReplacer("PACKAGE", name) // Process imports, stopping at $$ that closes them. diff --git a/src/cmd/internal/gc/mparith2.go b/src/cmd/compile/internal/gc/mparith2.go index de96e97809..2c7e5176ac 100644 --- a/src/cmd/internal/gc/mparith2.go +++ b/src/cmd/compile/internal/gc/mparith2.go @@ -5,7 +5,7 @@ package gc import ( - "cmd/internal/gc/big" + "cmd/compile/internal/big" "cmd/internal/obj" "fmt" ) @@ -13,7 +13,7 @@ import ( /// implements fix arithmetic func mpsetovf(a *Mpint) { - a.Val.SetUint64(0) + a.Val.SetUint64(1) // avoid spurious div-zero errors a.Ovf = true } diff --git a/src/cmd/internal/gc/mparith3.go b/src/cmd/compile/internal/gc/mparith3.go index 2700b64a89..0e0b626475 100644 --- a/src/cmd/internal/gc/mparith3.go +++ b/src/cmd/compile/internal/gc/mparith3.go @@ -5,7 +5,7 @@ package gc import ( - "cmd/internal/gc/big" + "cmd/compile/internal/big" "cmd/internal/obj" "fmt" "math" @@ -105,24 +105,8 @@ func mpcmpfltc(b *Mpflt, c float64) int { return mpcmpfltflt(b, &a) } -func mpgetfltN(a *Mpflt, prec int, bias int) float64 { - var x float64 - switch prec { - case 53: - x, _ = a.Val.Float64() - case 24: - // We should be using a.Val.Float32() here but that seems incorrect - // for certain denormal values (all.bash fails). The current code - // appears to work for all existing test cases, though there ought - // to be issues with denormal numbers that are incorrectly rounded. - // TODO(gri) replace with a.Val.Float32() once correctly working - // See also: https://github.com/golang/go/issues/10321 - var t Mpflt - t.Val.SetPrec(24).Set(&a.Val) - x, _ = t.Val.Float64() - default: - panic("unreachable") - } +func mpgetflt(a *Mpflt) float64 { + x, _ := a.Val.Float64() // check for overflow if math.IsInf(x, 0) && nsavederrors+nerrors == 0 { @@ -132,12 +116,16 @@ func mpgetfltN(a *Mpflt, prec int, bias int) float64 { return x } -func mpgetflt(a *Mpflt) float64 { - return mpgetfltN(a, 53, -1023) -} - func mpgetflt32(a *Mpflt) float64 { - return mpgetfltN(a, 24, -127) + x32, _ := a.Val.Float32() + x := float64(x32) + + // check for overflow + if math.IsInf(x, 0) && nsavederrors+nerrors == 0 { + Yyerror("mpgetflt32 ovf") + } + + return x } func Mpmovecflt(a *Mpflt, c float64) { diff --git a/src/cmd/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 05c5b1a811..9bb334ca34 100644 --- a/src/cmd/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -102,8 +102,7 @@ func dumpobj() { obj.Bputc(bout, 0) } obj.Bseek(bout, startobj-ArhdrSize, 0) - name := fmt.Sprintf("_go_.%c", Thearch.Thechar) - formathdr(arhdr[:], name, size) + formathdr(arhdr[:], "_go_.o", size) bout.Write(arhdr[:]) } @@ -382,11 +381,11 @@ func gdata(nam *Node, nr *Node, wid int) { if nr.Op == OLITERAL { switch nr.Val.Ctype { case CTCPLX: - gdatacomplex(nam, nr.Val.U.Cval) + gdatacomplex(nam, nr.Val.U.(*Mpcplx)) return case CTSTR: - gdatastring(nam, nr.Val.U.Sval) + gdatastring(nam, nr.Val.U.(string)) return } } diff --git a/src/cmd/internal/gc/opnames.go b/src/cmd/compile/internal/gc/opnames.go index fc03ec6666..fc03ec6666 100644 --- a/src/cmd/internal/gc/opnames.go +++ b/src/cmd/compile/internal/gc/opnames.go diff --git a/src/cmd/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index f08f5f20fe..ee0ec52e7b 100644 --- a/src/cmd/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -104,9 +104,23 @@ func ordercopyexpr(n *Node, t *Type, order *Order, clear int) *Node { // If not, ordercheapexpr allocates a new tmp, emits tmp = n, // and then returns tmp. func ordercheapexpr(n *Node, order *Order) *Node { + if n == nil { + return nil + } switch n.Op { case ONAME, OLITERAL: return n + case OLEN, OCAP: + l := ordercheapexpr(n.Left, order) + if l == n.Left { + return n + } + a := Nod(OXXX, nil, nil) + *a = *n + a.Orig = a + a.Left = l + typecheck(&a, Erv) + return a } return ordercopyexpr(n, n.Type, order, 0) @@ -124,7 +138,7 @@ func ordersafeexpr(n *Node, order *Order) *Node { case ONAME, OLITERAL: return n - case ODOT: + case ODOT, OLEN, OCAP: l := ordersafeexpr(n.Left, order) if l == n.Left { return n @@ -264,7 +278,7 @@ func orderblock(l **NodeList) { func orderexprinplace(np **Node, outer *Order) { n := *np var order Order - orderexpr(&n, &order) + orderexpr(&n, &order, nil) addinit(&n, order.out) // insert new temporaries from order @@ -358,8 +372,8 @@ func ordercallargs(l **NodeList, order *Order) { // Ordercall orders the call expression n. // n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY. func ordercall(n *Node, order *Order) { - orderexpr(&n.Left, order) - orderexpr(&n.Right, order) // ODDDARG temp + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right, order, nil) // ODDDARG temp ordercallargs(&n.List, order) } @@ -447,8 +461,14 @@ func orderstmt(n *Node, order *Order) { case OVARKILL: order.out = list(order.out, n) - case OAS, - OAS2, + case OAS: + t := marktemp(order) + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right, order, n.Left) + ordermapassign(n, order) + cleantemp(t, order) + + case OAS2, OCLOSE, OCOPY, OPRINT, @@ -456,38 +476,36 @@ func orderstmt(n *Node, order *Order) { ORECOVER, ORECV: t := marktemp(order) - orderexpr(&n.Left, order) - orderexpr(&n.Right, order) + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right, order, nil) orderexprlist(n.List, order) orderexprlist(n.Rlist, order) switch n.Op { - case OAS, OAS2, OAS2DOTTYPE: + case OAS2, OAS2DOTTYPE: ordermapassign(n, order) - default: order.out = list(order.out, n) } - cleantemp(t, order) - // Special: rewrite l op= r into l = l op r. - // This simplies quite a few operations; - // most important is that it lets us separate - // out map read from map write when l is - // a map index expression. case OASOP: + // Special: rewrite l op= r into l = l op r. + // This simplies quite a few operations; + // most important is that it lets us separate + // out map read from map write when l is + // a map index expression. t := marktemp(order) - orderexpr(&n.Left, order) + orderexpr(&n.Left, order, nil) n.Left = ordersafeexpr(n.Left, order) - tmp1 := treecopy(n.Left) + tmp1 := treecopy(n.Left, 0) if tmp1.Op == OINDEXMAP { tmp1.Etype = 0 // now an rvalue not an lvalue } tmp1 = ordercopyexpr(tmp1, n.Left.Type, order, 0) n.Right = Nod(int(n.Etype), tmp1, n.Right) typecheck(&n.Right, Erv) - orderexpr(&n.Right, order) + orderexpr(&n.Right, order, nil) n.Etype = 0 n.Op = OAS ordermapassign(n, order) @@ -500,8 +518,8 @@ func orderstmt(n *Node, order *Order) { orderexprlist(n.List, order) r := n.Rlist.N - orderexpr(&r.Left, order) - orderexpr(&r.Right, order) + orderexpr(&r.Left, order, nil) + orderexpr(&r.Right, order, nil) // See case OINDEXMAP below. if r.Right.Op == OARRAYBYTESTR { @@ -527,7 +545,7 @@ func orderstmt(n *Node, order *Order) { t := marktemp(order) orderexprlist(n.List, order) - orderexpr(&n.Rlist.N.Left, order) // i in i.(T) + orderexpr(&n.Rlist.N.Left, order, nil) // i in i.(T) if isblank(n.List.N) { order.out = list(order.out, n) } else { @@ -548,7 +566,7 @@ func orderstmt(n *Node, order *Order) { t := marktemp(order) orderexprlist(n.List, order) - orderexpr(&n.Rlist.N.Left, order) // arg to recv + orderexpr(&n.Rlist.N.Left, order, nil) // arg to recv ch := n.Rlist.N.Left.Type tmp1 := ordertemp(ch.Type, order, haspointers(ch.Type)) var tmp2 *Node @@ -617,8 +635,8 @@ func orderstmt(n *Node, order *Order) { case ODELETE: t := marktemp(order) - orderexpr(&n.List.N, order) - orderexpr(&n.List.Next.N, order) + orderexpr(&n.List.N, order, nil) + orderexpr(&n.List.Next.N, order, nil) orderaddrtemp(&n.List.Next.N, order) // map key order.out = list(order.out, n) cleantemp(t, order) @@ -659,7 +677,7 @@ func orderstmt(n *Node, order *Order) { case OPANIC: t := marktemp(order) - orderexpr(&n.Left, order) + orderexpr(&n.Left, order, nil) if !Isinter(n.Left.Type) { orderaddrtemp(&n.Left, order) } @@ -677,7 +695,7 @@ func orderstmt(n *Node, order *Order) { case ORANGE: t := marktemp(order) - orderexpr(&n.Right, order) + orderexpr(&n.Right, order, nil) switch n.Type.Etype { default: Fatal("orderstmt range %v", n.Type) @@ -793,7 +811,7 @@ func orderstmt(n *Node, order *Order) { // r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c. // r->left == N means 'case <-c'. // c is always evaluated; x and ok are only evaluated when assigned. - orderexpr(&r.Right.Left, order) + orderexpr(&r.Right.Left, order, nil) if r.Right.Left.Op != ONAME { r.Right.Left = ordercopyexpr(r.Right.Left, r.Right.Left.Type, order, 0) @@ -853,12 +871,12 @@ func orderstmt(n *Node, order *Order) { // case c <- x // r->left is c, r->right is x, both are always evaluated. - orderexpr(&r.Left, order) + orderexpr(&r.Left, order, nil) if !istemp(r.Left) { r.Left = ordercopyexpr(r.Left, r.Left.Type, order, 0) } - orderexpr(&r.Right, order) + orderexpr(&r.Right, order, nil) if !istemp(r.Right) { r.Right = ordercopyexpr(r.Right, r.Right.Type, order, 0) } @@ -884,8 +902,8 @@ func orderstmt(n *Node, order *Order) { case OSEND: t := marktemp(order) - orderexpr(&n.Left, order) - orderexpr(&n.Right, order) + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right, order, nil) orderaddrtemp(&n.Right, order) order.out = list(order.out, n) cleantemp(t, order) @@ -900,7 +918,7 @@ func orderstmt(n *Node, order *Order) { case OSWITCH: t := marktemp(order) - orderexpr(&n.Ntest, order) + orderexpr(&n.Ntest, order, nil) for l := n.List; l != nil; l = l.Next { if l.N.Op != OXCASE { Fatal("order switch case %v", Oconv(int(l.N.Op), 0)) @@ -919,7 +937,7 @@ func orderstmt(n *Node, order *Order) { // Orderexprlist orders the expression list l into order. func orderexprlist(l *NodeList, order *Order) { for ; l != nil; l = l.Next { - orderexpr(&l.N, order) + orderexpr(&l.N, order, nil) } } @@ -933,7 +951,10 @@ func orderexprlistinplace(l *NodeList, order *Order) { // Orderexpr orders a single expression, appending side // effects to order->out as needed. -func orderexpr(np **Node, order *Order) { +// If this is part of an assignment lhs = *np, lhs is given. +// Otherwise lhs == nil. (When lhs != nil it may be possible +// to avoid copying the result of the expression to a temporary.) +func orderexpr(np **Node, order *Order, lhs *Node) { n := *np if n == nil { return @@ -944,8 +965,8 @@ func orderexpr(np **Node, order *Order) { switch n.Op { default: - orderexpr(&n.Left, order) - orderexpr(&n.Right, order) + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right, order, nil) orderexprlist(n.List, order) orderexprlist(n.Rlist, order) @@ -974,7 +995,7 @@ func orderexpr(np **Node, order *Order) { haslit := false for l := n.List; l != nil; l = l.Next { hasbyte = hasbyte || l.N.Op == OARRAYBYTESTR - haslit = haslit || l.N.Op == OLITERAL && len(l.N.Val.U.Sval) != 0 + haslit = haslit || l.N.Op == OLITERAL && len(l.N.Val.U.(string)) != 0 } if haslit && hasbyte { @@ -986,8 +1007,8 @@ func orderexpr(np **Node, order *Order) { } case OCMPSTR: - orderexpr(&n.Left, order) - orderexpr(&n.Right, order) + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right, order, nil) // Mark string(byteSlice) arguments to reuse byteSlice backing // buffer during conversion. String comparison does not @@ -1001,9 +1022,9 @@ func orderexpr(np **Node, order *Order) { // key must be addressable case OINDEXMAP: - orderexpr(&n.Left, order) + orderexpr(&n.Left, order, nil) - orderexpr(&n.Right, order) + orderexpr(&n.Right, order, nil) // For x = m[string(k)] where k is []byte, the allocation of // backing bytes for the string can be avoided by reusing @@ -1029,7 +1050,7 @@ func orderexpr(np **Node, order *Order) { // concrete type (not interface) argument must be addressable // temporary to pass to runtime. case OCONVIFACE: - orderexpr(&n.Left, order) + orderexpr(&n.Left, order, nil) if !Isinter(n.Left.Type) { orderaddrtemp(&n.Left, order) @@ -1037,7 +1058,7 @@ func orderexpr(np **Node, order *Order) { case OANDAND, OOROR: mark := marktemp(order) - orderexpr(&n.Left, order) + orderexpr(&n.Left, order, nil) // Clean temporaries from first branch at beginning of second. // Leave them on the stack so that they can be killed in the outer @@ -1048,8 +1069,7 @@ func orderexpr(np **Node, order *Order) { n.Right.Ninit = concat(l, n.Right.Ninit) orderexprinplace(&n.Right, order) - case OAPPEND, - OCALLFUNC, + case OCALLFUNC, OCALLINTER, OCALLMETH, OCAP, @@ -1064,7 +1084,37 @@ func orderexpr(np **Node, order *Order) { OREAL, ORECOVER: ordercall(n, order) - n = ordercopyexpr(n, n.Type, order, 0) + if lhs == nil || lhs.Op != ONAME || flag_race != 0 { + n = ordercopyexpr(n, n.Type, order, 0) + } + + case OAPPEND: + ordercallargs(&n.List, order) + if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.N) { + n = ordercopyexpr(n, n.Type, order, 0) + } + + case OSLICE, OSLICEARR, OSLICESTR: + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right.Left, order, nil) + n.Right.Left = ordercheapexpr(n.Right.Left, order) + orderexpr(&n.Right.Right, order, nil) + n.Right.Right = ordercheapexpr(n.Right.Right, order) + if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { + n = ordercopyexpr(n, n.Type, order, 0) + } + + case OSLICE3, OSLICE3ARR: + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right.Left, order, nil) + n.Right.Left = ordercheapexpr(n.Right.Left, order) + orderexpr(&n.Right.Right.Left, order, nil) + n.Right.Right.Left = ordercheapexpr(n.Right.Right.Left, order) + orderexpr(&n.Right.Right.Right, order, nil) + n.Right.Right.Right = ordercheapexpr(n.Right.Right.Right, order) + if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { + n = ordercopyexpr(n, n.Type, order, 0) + } case OCLOSURE: if n.Noescape && n.Func.Cvars != nil { @@ -1072,8 +1122,8 @@ func orderexpr(np **Node, order *Order) { } case OARRAYLIT, OCALLPART: - orderexpr(&n.Left, order) - orderexpr(&n.Right, order) + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right, order, nil) orderexprlist(n.List, order) orderexprlist(n.Rlist, order) if n.Noescape { @@ -1090,7 +1140,7 @@ func orderexpr(np **Node, order *Order) { } case ODOTTYPE, ODOTTYPE2: - orderexpr(&n.Left, order) + orderexpr(&n.Left, order, nil) // TODO(rsc): The Isfat is for consistency with componentgen and walkexpr. // It needs to be removed in all three places. // That would allow inlining x.(struct{*int}) the same as x.(*int). @@ -1099,18 +1149,17 @@ func orderexpr(np **Node, order *Order) { } case ORECV: - orderexpr(&n.Left, order) + orderexpr(&n.Left, order, nil) n = ordercopyexpr(n, n.Type, order, 1) case OEQ, ONE: - orderexpr(&n.Left, order) - orderexpr(&n.Right, order) + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right, order, nil) t := n.Left.Type if t.Etype == TSTRUCT || Isfixedarray(t) { // for complex comparisons, we need both args to be // addressable so we can pass them to the runtime. orderaddrtemp(&n.Left, order) - orderaddrtemp(&n.Right, order) } } diff --git a/src/cmd/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index 2c225c8778..c170060896 100644 --- a/src/cmd/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -5,8 +5,8 @@ package gc import ( + "cmd/compile/internal/ssa" "cmd/internal/obj" - "cmd/internal/ssa" "crypto/md5" "fmt" "strings" @@ -201,8 +201,8 @@ func cmpstackvar(a *Node, b *Node) int { return bp - ap } - ap = obj.Bool2int(a.Needzero) - bp = obj.Bool2int(b.Needzero) + ap = obj.Bool2int(a.Name.Needzero) + bp = obj.Bool2int(b.Name.Needzero) if ap != bp { return bp - ap } @@ -302,25 +302,6 @@ func allocauto(ptxt *obj.Prog) { } } -func movelarge(l *NodeList) { - for ; l != nil; l = l.Next { - if l.N.Op == ODCLFUNC { - movelargefn(l.N) - } - } -} - -func movelargefn(fn *Node) { - var n *Node - - for l := fn.Func.Dcl; l != nil; l = l.Next { - n = l.N - if n.Class == PAUTO && n.Type != nil && n.Type.Width > MaxStackVarSize { - addrescapes(n) - } - } -} - func Cgen_checknil(n *Node) { if Disable_checknil != 0 { return diff --git a/src/cmd/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index 040a77814e..b4d0699d1f 100644 --- a/src/cmd/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -944,7 +944,7 @@ func onebitwalktype1(t *Type, xoffset *int64, bv Bvec) { *xoffset += t.Width case TARRAY: - // The value of t->bound is -1 for slices types and >0 for + // The value of t->bound is -1 for slices types and >=0 for // for fixed array types. All other values are invalid. if t.Bound < -1 { Fatal("onebitwalktype1: invalid bound, %v", t) @@ -1281,8 +1281,8 @@ func livenessepilogue(lv *Liveness) { } bvset(all, pos) // silence future warnings in this block n = lv.vars[pos] - if !n.Needzero { - n.Needzero = true + if !n.Name.Needzero { + n.Name.Needzero = true if debuglive >= 1 { Warnl(int(p.Lineno), "%v: %v is ambiguously live", Curfn.Nname, Nconv(n, obj.FmtLong)) } diff --git a/src/cmd/internal/gc/popt.go b/src/cmd/compile/internal/gc/popt.go index ce904e155b..ce904e155b 100644 --- a/src/cmd/internal/gc/popt.go +++ b/src/cmd/compile/internal/gc/popt.go diff --git a/src/cmd/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index e7f35006dc..05a902e8c1 100644 --- a/src/cmd/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -186,31 +186,6 @@ func racewalknode(np **Node, init **NodeList, wr int, skip int) { // as we do not instrument runtime code. // typedslicecopy is instrumented in runtime. case OCALLFUNC: - if n.Left.Sym != nil && n.Left.Sym.Pkg == Runtimepkg && (strings.HasPrefix(n.Left.Sym.Name, "writebarrier") || n.Left.Sym.Name == "typedmemmove") { - // Find the dst argument. - // The list can be reordered, so it's not necessary just the first or the second element. - var l *NodeList - for l = n.List; l != nil; l = l.Next { - if n.Left.Sym.Name == "typedmemmove" { - if l.N.Left.Xoffset == int64(Widthptr) { - break - } - } else { - if l.N.Left.Xoffset == 0 { - break - } - } - } - - if l == nil { - Fatal("racewalk: writebarrier no arg") - } - if l.N.Right.Op != OADDR { - Fatal("racewalk: writebarrier bad arg") - } - callinstr(&l.N.Right.Left, init, 1, 0) - } - racewalknode(&n.Left, init, 0, 0) goto ret @@ -324,9 +299,8 @@ func racewalknode(np **Node, init **NodeList, wr int, skip int) { } goto ret - // Seems to only lead to double instrumentation. - //racewalknode(&n->left, init, 0, 0); case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR: + racewalknode(&n.Left, init, 0, 0) goto ret case OADDR: @@ -509,7 +483,7 @@ func callinstr(np **Node, init **NodeList, wr int, skip int) bool { *np = n } - n = treecopy(n) + n = treecopy(n, 0) makeaddable(n) var f *Node if t.Etype == TSTRUCT || Isfixedarray(t) { diff --git a/src/cmd/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go index 03beb1c673..03beb1c673 100644 --- a/src/cmd/internal/gc/range.go +++ b/src/cmd/compile/internal/gc/range.go diff --git a/src/cmd/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index 9979fe85fd..6c0962f258 100644 --- a/src/cmd/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -5,8 +5,10 @@ package gc import ( + "cmd/internal/gcprog" "cmd/internal/obj" "fmt" + "os" ) /* @@ -687,7 +689,7 @@ func haspointers(t *Type) bool { // typeptrdata returns the length in bytes of the prefix of t // containing pointer data. Anything after this offset is scalar data. -func typeptrdata(t *Type) uint64 { +func typeptrdata(t *Type) int64 { if !haspointers(t) { return 0 } @@ -699,24 +701,24 @@ func typeptrdata(t *Type) uint64 { TFUNC, TCHAN, TMAP: - return uint64(Widthptr) + return int64(Widthptr) case TSTRING: // struct { byte *str; intgo len; } - return uint64(Widthptr) + return int64(Widthptr) case TINTER: // struct { Itab *tab; void *data; } or // struct { Type *type; void *data; } - return 2 * uint64(Widthptr) + return 2 * int64(Widthptr) case TARRAY: if Isslice(t) { // struct { byte *array; uintgo len; uintgo cap; } - return uint64(Widthptr) + return int64(Widthptr) } // haspointers already eliminated t.Bound == 0. - return uint64(t.Bound-1)*uint64(t.Type.Width) + typeptrdata(t.Type) + return (t.Bound-1)*t.Type.Width + typeptrdata(t.Type) case TSTRUCT: // Find the last field that has pointers. @@ -726,7 +728,7 @@ func typeptrdata(t *Type) uint64 { lastPtrField = t1 } } - return uint64(lastPtrField.Width) + typeptrdata(lastPtrField.Type) + return lastPtrField.Width + typeptrdata(lastPtrField.Type) default: Fatal("typeptrdata: unexpected type, %v", t) @@ -771,6 +773,8 @@ func dcommontype(s *Sym, ot int, t *Type) int { // The linker magically takes the max of all the sizes. zero := Pkglookup("zerovalue", Runtimepkg) + gcsym, useGCProg, ptrdata := dgcsym(t) + // We use size 0 here so we get the pointer to the zero value, // but don't allocate space for the zero value unless we need it. // TODO: how do we get this symbol into bss? We really want @@ -787,14 +791,14 @@ func dcommontype(s *Sym, ot int, t *Type) int { // fieldAlign uint8 // kind uint8 // alg unsafe.Pointer - // gc unsafe.Pointer + // gcdata unsafe.Pointer // string *string // *extraType // ptrToThis *Type // zero unsafe.Pointer // } ot = duintptr(s, ot, uint64(t.Width)) - ot = duintptr(s, ot, typeptrdata(t)) + ot = duintptr(s, ot, uint64(ptrdata)) ot = duint32(s, ot, typehash(t)) ot = duint8(s, ot, 0) // unused @@ -811,8 +815,6 @@ func dcommontype(s *Sym, ot int, t *Type) int { ot = duint8(s, ot, t.Align) // align ot = duint8(s, ot, t.Align) // fieldAlign - gcprog := usegcprog(t) - i = kinds[t.Etype] if t.Etype == TARRAY && t.Bound < 0 { i = obj.KindSlice @@ -823,7 +825,7 @@ func dcommontype(s *Sym, ot int, t *Type) int { if isdirectiface(t) { i |= obj.KindDirectIface } - if gcprog { + if useGCProg { i |= obj.KindGCProg } ot = duint8(s, ot, uint8(i)) // kind @@ -832,48 +834,7 @@ func dcommontype(s *Sym, ot int, t *Type) int { } else { ot = dsymptr(s, ot, algsym, 0) } - - // gc - if gcprog { - var gcprog1 *Sym - var gcprog0 *Sym - gengcprog(t, &gcprog0, &gcprog1) - if gcprog0 != nil { - ot = dsymptr(s, ot, gcprog0, 0) - } else { - ot = duintptr(s, ot, 0) - } - ot = dsymptr(s, ot, gcprog1, 0) - } else { - var gcmask [16]uint8 - gengcmask(t, gcmask[:]) - x1 := uint64(0) - for i := 0; i < 8; i++ { - x1 = x1<<8 | uint64(gcmask[i]) - } - var p string - if Widthptr == 4 { - p = fmt.Sprintf("gcbits.0x%016x", x1) - } else { - x2 := uint64(0) - for i := 0; i < 8; i++ { - x2 = x2<<8 | uint64(gcmask[i+8]) - } - p = fmt.Sprintf("gcbits.0x%016x%016x", x1, x2) - } - - sbits := Pkglookup(p, Runtimepkg) - if sbits.Flags&SymUniq == 0 { - sbits.Flags |= SymUniq - for i := 0; i < 2*Widthptr; i++ { - duint8(sbits, i, gcmask[i]) - } - ggloblsym(sbits, 2*int32(Widthptr), obj.DUPOK|obj.RODATA|obj.LOCAL) - } - - ot = dsymptr(s, ot, sbits, 0) - ot = duintptr(s, ot, 0) - } + ot = dsymptr(s, ot, gcsym, 0) p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned) @@ -1419,269 +1380,193 @@ func dalgsym(t *Type) *Sym { return s } -func usegcprog(t *Type) bool { - if !haspointers(t) { - return false - } - if t.Width == BADWIDTH { - dowidth(t) +// maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap, +// which holds 1-bit entries describing where pointers are in a given type. +// 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes +// depending on the system. Above this length, the GC information is +// recorded as a GC program, which can express repetition compactly. +// In either form, the information is used by the runtime to initialize the +// heap bitmap, and for large types (like 128 or more words), they are +// roughly the same speed. GC programs are never much larger and often +// more compact. (If large arrays are involved, they can be arbitrarily more +// compact.) +// +// The cutoff must be large enough that any allocation large enough to +// use a GC program is large enough that it does not share heap bitmap +// bytes with any other objects, allowing the GC program execution to +// assume an aligned start and not use atomic operations. In the current +// runtime, this means all malloc size classes larger than the cutoff must +// be multiples of four words. On 32-bit systems that's 16 bytes, and +// all size classes >= 16 bytes are 16-byte aligned, so no real constraint. +// On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed +// for size classes >= 256 bytes. On a 64-bit sytem, 256 bytes allocated +// is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes +// must be >= 4. +// +// We use 16 because the GC programs do have some constant overhead +// to get started, and processing 128 pointers seems to be enough to +// amortize that overhead well. +const maxPtrmaskBytes = 16 + +// dgcsym emits and returns a data symbol containing GC information for type t, +// along with a boolean reporting whether the UseGCProg bit should be set in +// the type kind, and the ptrdata field to record in the reflect type information. +func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) { + ptrdata = typeptrdata(t) + if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 { + sym = dgcptrmask(t) + return } - // Calculate size of the unrolled GC mask. - nptr := (t.Width + int64(Widthptr) - 1) / int64(Widthptr) + useGCProg = true + sym, ptrdata = dgcprog(t) + return +} + +// dgcptrmask emits and returns the symbol containing a pointer mask for type t. +func dgcptrmask(t *Type) *Sym { + ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8) + fillptrmask(t, ptrmask) + p := fmt.Sprintf("gcbits.%x", ptrmask) - size := nptr - if size%2 != 0 { - size *= 2 // repeated + sym := Pkglookup(p, Runtimepkg) + if sym.Flags&SymUniq == 0 { + sym.Flags |= SymUniq + for i, x := range ptrmask { + duint8(sym, i, x) + } + ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL) } - size = size * obj.GcBits / 8 // 4 bits per word - - // Decide whether to use unrolled GC mask or GC program. - // We could use a more elaborate condition, but this seems to work well in practice. - // For small objects GC program can't give significant reduction. - // While large objects usually contain arrays; and even if it don't - // the program uses 2-bits per word while mask uses 4-bits per word, - // so the program is still smaller. - return size > int64(2*Widthptr) + return sym } -// Generates sparse GC bitmask (4 bits per word). -func gengcmask(t *Type, gcmask []byte) { - for i := int64(0); i < 16; i++ { - gcmask[i] = 0 +// fillptrmask fills in ptrmask with 1s corresponding to the +// word offsets in t that hold pointers. +// ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits. +func fillptrmask(t *Type, ptrmask []byte) { + for i := range ptrmask { + ptrmask[i] = 0 } if !haspointers(t) { return } - // Generate compact mask as stacks use. + vec := bvalloc(8 * int32(len(ptrmask))) xoffset := int64(0) - - vec := bvalloc(2 * int32(Widthptr) * 8) onebitwalktype1(t, &xoffset, vec) - // Unfold the mask for the GC bitmap format: - // 4 bits per word, 2 high bits encode pointer info. - pos := gcmask - - nptr := (t.Width + int64(Widthptr) - 1) / int64(Widthptr) - half := false - - // If number of words is odd, repeat the mask. - // This makes simpler handling of arrays in runtime. - var i int64 - var bits uint8 - for j := int64(0); j <= (nptr % 2); j++ { - for i = 0; i < nptr; i++ { - // convert 0=scalar / 1=pointer to GC bit encoding - if bvget(vec, int32(i)) == 0 { - bits = obj.BitsScalar - } else { - bits = obj.BitsPointer - } - bits <<= 2 - if half { - bits <<= 4 - } - pos[0] |= byte(bits) - half = !half - if !half { - pos = pos[1:] - } + nptr := typeptrdata(t) / int64(Widthptr) + for i := int64(0); i < nptr; i++ { + if bvget(vec, int32(i)) == 1 { + ptrmask[i/8] |= 1 << (uint(i) % 8) } } } -// Helper object for generation of GC programs. -type ProgGen struct { - s *Sym - datasize int32 - data [256 / obj.PointersPerByte]uint8 - ot int64 -} - -func proggeninit(g *ProgGen, s *Sym) { - g.s = s - g.datasize = 0 - g.ot = 0 - g.data = [256 / obj.PointersPerByte]uint8{} -} - -func proggenemit(g *ProgGen, v uint8) { - g.ot = int64(duint8(g.s, int(g.ot), v)) -} - -// Emits insData block from g->data. -func proggendataflush(g *ProgGen) { - if g.datasize == 0 { - return +// dgcprog emits and returns the symbol containing a GC program for type t +// along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]). +// In practice, the size is typeptrdata(t) except for non-trivial arrays. +// For non-trivial arrays, the program describes the full t.Width size. +func dgcprog(t *Type) (*Sym, int64) { + dowidth(t) + if t.Width == BADWIDTH { + Fatal("dgcprog: %v badwidth", t) } - proggenemit(g, obj.InsData) - proggenemit(g, uint8(g.datasize)) - s := (g.datasize + obj.PointersPerByte - 1) / obj.PointersPerByte - for i := int32(0); i < s; i++ { - proggenemit(g, g.data[i]) + sym := typesymprefix(".gcprog", t) + var p GCProg + p.init(sym) + p.emit(t, 0) + offset := p.w.BitIndex() * int64(Widthptr) + p.end() + if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width { + Fatal("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width) } - g.datasize = 0 - g.data = [256 / obj.PointersPerByte]uint8{} + return sym, offset } -func proggendata(g *ProgGen, d uint8) { - g.data[g.datasize/obj.PointersPerByte] |= d << uint((g.datasize%obj.PointersPerByte)*obj.BitsPerPointer) - g.datasize++ - if g.datasize == 255 { - proggendataflush(g) - } +type GCProg struct { + sym *Sym + symoff int + w gcprog.Writer } -// Skip v bytes due to alignment, etc. -func proggenskip(g *ProgGen, off int64, v int64) { - for i := off; i < off+v; i++ { - if (i % int64(Widthptr)) == 0 { - proggendata(g, obj.BitsScalar) - } - } -} +var Debug_gcprog int // set by -d gcprog -// Emit insArray instruction. -func proggenarray(g *ProgGen, len int64) { - proggendataflush(g) - proggenemit(g, obj.InsArray) - for i := int32(0); i < int32(Widthptr); i, len = i+1, len>>8 { - proggenemit(g, uint8(len)) +func (p *GCProg) init(sym *Sym) { + p.sym = sym + p.symoff = 4 // first 4 bytes hold program length + p.w.Init(p.writeByte) + if Debug_gcprog > 0 { + fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym) + p.w.Debug(os.Stderr) } } -func proggenarrayend(g *ProgGen) { - proggendataflush(g) - proggenemit(g, obj.InsArrayEnd) +func (p *GCProg) writeByte(x byte) { + p.symoff = duint8(p.sym, p.symoff, x) } -func proggenfini(g *ProgGen) int64 { - proggendataflush(g) - proggenemit(g, obj.InsEnd) - return g.ot +func (p *GCProg) end() { + p.w.End() + duint32(p.sym, 0, uint32(p.symoff-4)) + ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL) + if Debug_gcprog > 0 { + fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym) + } } -// Generates GC program for large types. -func gengcprog(t *Type, pgc0 **Sym, pgc1 **Sym) { - nptr := (t.Width + int64(Widthptr) - 1) / int64(Widthptr) - size := nptr - if size%2 != 0 { - size *= 2 // repeated twice +func (p *GCProg) emit(t *Type, offset int64) { + dowidth(t) + if !haspointers(t) { + return } - size = size * obj.PointersPerByte / 8 // 4 bits per word - size++ // unroll flag in the beginning, used by runtime (see runtime.markallocated) - - // emity space in BSS for unrolled program - *pgc0 = nil - - // Don't generate it if it's too large, runtime will unroll directly into GC bitmap. - if size <= obj.MaxGCMask { - gc0 := typesymprefix(".gc", t) - ggloblsym(gc0, int32(size), obj.DUPOK|obj.NOPTR) - *pgc0 = gc0 + if t.Width == int64(Widthptr) { + p.w.Ptr(offset / int64(Widthptr)) + return } - - // program in RODATA - gc1 := typesymprefix(".gcprog", t) - - var g ProgGen - proggeninit(&g, gc1) - xoffset := int64(0) - gengcprog1(&g, t, &xoffset) - ot := proggenfini(&g) - ggloblsym(gc1, int32(ot), obj.DUPOK|obj.RODATA) - *pgc1 = gc1 -} - -// Recursively walks type t and writes GC program into g. -func gengcprog1(g *ProgGen, t *Type, xoffset *int64) { switch t.Etype { - case TINT8, - TUINT8, - TINT16, - TUINT16, - TINT32, - TUINT32, - TINT64, - TUINT64, - TINT, - TUINT, - TUINTPTR, - TBOOL, - TFLOAT32, - TFLOAT64, - TCOMPLEX64, - TCOMPLEX128: - proggenskip(g, *xoffset, t.Width) - *xoffset += t.Width - - case TPTR32, - TPTR64, - TUNSAFEPTR, - TFUNC, - TCHAN, - TMAP: - proggendata(g, obj.BitsPointer) - *xoffset += t.Width + default: + Fatal("GCProg.emit: unexpected type %v", t) case TSTRING: - proggendata(g, obj.BitsPointer) - proggendata(g, obj.BitsScalar) - *xoffset += t.Width + p.w.Ptr(offset / int64(Widthptr)) - // Assuming IfacePointerOnly=1. case TINTER: - proggendata(g, obj.BitsPointer) - - proggendata(g, obj.BitsPointer) - *xoffset += t.Width + p.w.Ptr(offset / int64(Widthptr)) + p.w.Ptr(offset/int64(Widthptr) + 1) case TARRAY: if Isslice(t) { - proggendata(g, obj.BitsPointer) - proggendata(g, obj.BitsScalar) - proggendata(g, obj.BitsScalar) - } else { - t1 := t.Type - if t1.Width == 0 { - } - // ignore - if t.Bound <= 1 || t.Bound*t1.Width < int64(32*Widthptr) { - for i := int64(0); i < t.Bound; i++ { - gengcprog1(g, t1, xoffset) - } - } else if !haspointers(t1) { - n := t.Width - n -= -*xoffset & (int64(Widthptr) - 1) // skip to next ptr boundary - proggenarray(g, (n+int64(Widthptr)-1)/int64(Widthptr)) - proggendata(g, obj.BitsScalar) - proggenarrayend(g) - *xoffset -= (n+int64(Widthptr)-1)/int64(Widthptr)*int64(Widthptr) - t.Width - } else { - proggenarray(g, t.Bound) - gengcprog1(g, t1, xoffset) - *xoffset += (t.Bound - 1) * t1.Width - proggenarrayend(g) + p.w.Ptr(offset / int64(Widthptr)) + return + } + if t.Bound == 0 { + // should have been handled by haspointers check above + Fatal("GCProg.emit: empty array") + } + + // Flatten array-of-array-of-array to just a big array by multiplying counts. + count := t.Bound + elem := t.Type + for Isfixedarray(elem) { + count *= elem.Bound + elem = elem.Type + } + + if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) { + // Cheaper to just emit the bits. + for i := int64(0); i < count; i++ { + p.emit(elem, offset+i*elem.Width) } + return } + p.emit(elem, offset) + p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr)) + p.w.Repeat(elem.Width/int64(Widthptr), count-1) case TSTRUCT: - o := int64(0) - var fieldoffset int64 for t1 := t.Type; t1 != nil; t1 = t1.Down { - fieldoffset = t1.Width - proggenskip(g, *xoffset, fieldoffset-o) - *xoffset += fieldoffset - o - gengcprog1(g, t1.Type, xoffset) - o = fieldoffset + t1.Type.Width + p.emit(t1.Type, offset+t1.Width) } - - proggenskip(g, *xoffset, t.Width-o) - *xoffset += t.Width - o - - default: - Fatal("gengcprog1: unexpected type, %v", t) } } diff --git a/src/cmd/internal/gc/reg.go b/src/cmd/compile/internal/gc/reg.go index afe95230c7..afe95230c7 100644 --- a/src/cmd/internal/gc/reg.go +++ b/src/cmd/compile/internal/gc/reg.go diff --git a/src/cmd/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go index 3a28ea3c77..3a28ea3c77 100644 --- a/src/cmd/internal/gc/select.go +++ b/src/cmd/compile/internal/gc/select.go diff --git a/src/cmd/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go index a9af9450ae..b5427a338c 100644 --- a/src/cmd/internal/gc/sinit.go +++ b/src/cmd/compile/internal/gc/sinit.go @@ -221,7 +221,7 @@ func init2(n *Node, out **NodeList) { init2list(n.Nelse, out) if n.Op == OCLOSURE { - init2list(n.Closure.Nbody, out) + init2list(n.Param.Closure.Nbody, out) } if n.Op == ODOTMETH || n.Op == OCALLPART { init2(n.Type.Nname, out) @@ -437,7 +437,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool { case OSTRARRAYBYTE: if l.Class == PEXTERN && r.Left.Op == OLITERAL { - sval := r.Left.Val.U.Sval + sval := r.Left.Val.U.(string) slicebytes(l, sval, len(sval)) return true } @@ -449,7 +449,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool { ta := typ(TARRAY) ta.Type = r.Type.Type - ta.Bound = Mpgetfix(r.Right.Val.U.Xval) + ta.Bound = Mpgetfix(r.Right.Val.U.(*Mpint)) a := staticname(ta, 1) r.Nname = a n1 = *l @@ -510,7 +510,7 @@ func staticname(t *Type, ctxt int) *Node { n := newname(Lookupf("statictmp_%.4d", statuniqgen)) statuniqgen++ if ctxt == 0 { - n.Readonly = true + n.Name.Readonly = true } addvar(n, t, PEXTERN) return n @@ -722,7 +722,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) { // make an array type t := shallow(n.Type) - t.Bound = Mpgetfix(n.Right.Val.U.Xval) + t.Bound = Mpgetfix(n.Right.Val.U.(*Mpint)) t.Width = 0 t.Sym = nil t.Haspointers = 0 @@ -1226,7 +1226,7 @@ func oaslit(n *Node, init **NodeList) bool { func getlit(lit *Node) int { if Smallintconst(lit) { - return int(Mpgetfix(lit.Val.U.Xval)) + return int(Mpgetfix(lit.Val.U.(*Mpint))) } return -1 } @@ -1290,7 +1290,7 @@ func initplan(n *Node) { if a.Op != OKEY || !Smallintconst(a.Left) { Fatal("initplan arraylit") } - addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val.U.Xval), nil, a.Right) + addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val.U.(*Mpint)), nil, a.Right) } case OSTRUCTLIT: @@ -1360,19 +1360,19 @@ func iszero(n *Node) bool { return true case CTSTR: - return n.Val.U.Sval == "" + return n.Val.U.(string) == "" case CTBOOL: - return !n.Val.U.Bval + return !n.Val.U.(bool) case CTINT, CTRUNE: - return mpcmpfixc(n.Val.U.Xval, 0) == 0 + return mpcmpfixc(n.Val.U.(*Mpint), 0) == 0 case CTFLT: - return mpcmpfltc(n.Val.U.Fval, 0) == 0 + return mpcmpfltc(n.Val.U.(*Mpflt), 0) == 0 case CTCPLX: - return mpcmpfltc(&n.Val.U.Cval.Real, 0) == 0 && mpcmpfltc(&n.Val.U.Cval.Imag, 0) == 0 + return mpcmpfltc(&n.Val.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&n.Val.U.(*Mpcplx).Imag, 0) == 0 } case OARRAYLIT: @@ -1510,10 +1510,10 @@ func gen_as_init(n *Node) bool { gdata(&nam, nr, int(nr.Type.Width)) case TCOMPLEX64, TCOMPLEX128: - gdatacomplex(&nam, nr.Val.U.Cval) + gdatacomplex(&nam, nr.Val.U.(*Mpcplx)) case TSTRING: - gdatastring(&nam, nr.Val.U.Sval) + gdatastring(&nam, nr.Val.U.(string)) } return true diff --git a/src/cmd/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index bb4d278383..7f78fce17e 100644 --- a/src/cmd/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -7,9 +7,9 @@ package gc import ( "log" + "cmd/compile/internal/ssa" "cmd/internal/obj" "cmd/internal/obj/x86" // TODO: remove - "cmd/internal/ssa" ) func buildssa(fn *Node) *ssa.Func { @@ -267,7 +267,7 @@ func (s *state) expr(n *Node) *ssa.Value { case OLITERAL: switch n.Val.Ctype { case CTINT: - return s.f.ConstInt(n.Type, Mpgetfix(n.Val.U.Xval)) + return s.f.ConstInt(n.Type, Mpgetfix(n.Val.U.(*Mpint))) default: log.Fatalf("unhandled OLITERAL %v", n.Val.Ctype) return nil diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 06ceff5844..ed5001a983 100644 --- a/src/cmd/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -125,13 +125,6 @@ func Yyerror(format string, args ...interface{}) { if strings.HasPrefix(msg, "syntax error") { nsyntaxerrors++ - yystate := theparser.(*yyParserImpl).state() - yychar := theparser.Lookahead() - - if Debug['x'] != 0 { - fmt.Printf("yyerror: yystate=%d yychar=%d\n", yystate, yychar) - } - // An unexpected EOF caused a syntax error. Use the previous // line number since getc generated a fake newline character. if curio.eofnl != 0 { @@ -144,14 +137,6 @@ func Yyerror(format string, args ...interface{}) { } yyerror_lastsyntax = int(lexlineno) - // look for parse state-specific errors in list (see go.errors). - for i := range yymsg { - if yymsg[i].yystate == yystate && yymsg[i].yychar == yychar { - yyerrorl(int(lexlineno), "syntax error: %s", yymsg[i].msg) - return - } - } - // plain "syntax error" gets "near foo" added if msg == "syntax error" { yyerrorl(int(lexlineno), "syntax error near %s", lexbuf.String()) @@ -214,26 +199,32 @@ func Fatal(fmt_ string, args ...interface{}) { errorexit() } -func linehist(file string, off int32, relative int) { +func linehistpragma(file string) { if Debug['i'] != 0 { - if file != "" { - if off < 0 { - fmt.Printf("pragma %s", file) - } else if off > 0 { - fmt.Printf("line %s", file) - } else { - fmt.Printf("import %s", file) - } - } else { - fmt.Printf("end of import") - } - fmt.Printf(" at line %v\n", Ctxt.Line(int(lexlineno))) + fmt.Printf("pragma %s at line %v\n", file, Ctxt.Line(int(lexlineno))) + } + Ctxt.AddImport(file) +} + +func linehistpush(file string) { + if Debug['i'] != 0 { + fmt.Printf("import %s at line %v\n", file, Ctxt.Line(int(lexlineno))) } + Ctxt.LineHist.Push(int(lexlineno), file) +} - if off < 0 && file[0] != '/' && relative == 0 { - file = fmt.Sprintf("%s/%s", Ctxt.Pathname, file) +func linehistpop() { + if Debug['i'] != 0 { + fmt.Printf("end of import at line %v\n", Ctxt.Line(int(lexlineno))) } - obj.Linklinehist(Ctxt, int(lexlineno), file, int(off)) + Ctxt.LineHist.Pop(int(lexlineno)) +} + +func linehistupdate(file string, off int) { + if Debug['i'] != 0 { + fmt.Printf("line %s at line %v\n", file, Ctxt.Line(int(lexlineno))) + } + Ctxt.LineHist.Update(int(lexlineno), file, off) } func setlineno(n *Node) int32 { @@ -380,6 +371,12 @@ func Nod(op int, nleft *Node, nright *Node) *Node { switch op { case OCLOSURE, ODCLFUNC: n.Func = new(Func) + n.Param = new(Param) + case ONAME: + n.Name = new(Name) + n.Param = new(Param) + case ODCLFIELD: + n.Param = new(Param) } return n } @@ -666,8 +663,8 @@ func sortinter(t *Type) *Type { func Nodintconst(v int64) *Node { c := Nod(OLITERAL, nil, nil) c.Addable = true - c.Val.U.Xval = new(Mpint) - Mpmovecfix(c.Val.U.Xval, v) + c.Val.U = new(Mpint) + Mpmovecfix(c.Val.U.(*Mpint), v) c.Val.Ctype = CTINT c.Type = Types[TIDEAL] ullmancalc(c) @@ -677,8 +674,8 @@ func Nodintconst(v int64) *Node { func nodfltconst(v *Mpflt) *Node { c := Nod(OLITERAL, nil, nil) c.Addable = true - c.Val.U.Fval = newMpflt() - mpmovefltflt(c.Val.U.Fval, v) + c.Val.U = newMpflt() + mpmovefltflt(c.Val.U.(*Mpflt), v) c.Val.Ctype = CTFLT c.Type = Types[TIDEAL] ullmancalc(c) @@ -690,8 +687,8 @@ func Nodconst(n *Node, t *Type, v int64) { n.Op = OLITERAL n.Addable = true ullmancalc(n) - n.Val.U.Xval = new(Mpint) - Mpmovecfix(n.Val.U.Xval, v) + n.Val.U = new(Mpint) + Mpmovecfix(n.Val.U.(*Mpint), v) n.Val.Ctype = CTINT n.Type = t @@ -710,7 +707,7 @@ func nodnil() *Node { func Nodbool(b bool) *Node { c := Nodintconst(0) c.Val.Ctype = CTBOOL - c.Val.U.Bval = b + c.Val.U = b c.Type = idealbool return c } @@ -724,7 +721,7 @@ func aindex(b *Node, t *Type) *Type { Yyerror("array bound must be an integer expression") case CTINT, CTRUNE: - bound = Mpgetfix(b.Val.U.Xval) + bound = Mpgetfix(b.Val.U.(*Mpint)) if bound < 0 { Yyerror("array bound must be non negative") } @@ -739,7 +736,12 @@ func aindex(b *Node, t *Type) *Type { return r } -func treecopy(n *Node) *Node { +// treecopy recursively copies n, with the exception of +// ONAME, OLITERAL, OTYPE, and non-iota ONONAME leaves. +// Copies of iota ONONAME nodes are assigned the current +// value of iota_. If lineno != 0, it sets the line number +// of newly allocated nodes to lineno. +func treecopy(n *Node, lineno int32) *Node { if n == nil { return nil } @@ -750,9 +752,12 @@ func treecopy(n *Node) *Node { m = Nod(OXXX, nil, nil) *m = *n m.Orig = m - m.Left = treecopy(n.Left) - m.Right = treecopy(n.Right) - m.List = listtreecopy(n.List) + m.Left = treecopy(n.Left, lineno) + m.Right = treecopy(n.Right, lineno) + m.List = listtreecopy(n.List, lineno) + if lineno != -1 { + m.Lineno = lineno + } if m.Defn != nil { panic("abort") } @@ -767,11 +772,13 @@ func treecopy(n *Node) *Node { *m = *n m.Iota = iota_ + if lineno != 0 { + m.Lineno = lineno + } break } fallthrough - // fall through case ONAME, OLITERAL, OTYPE: m = n } @@ -1898,7 +1905,7 @@ func safeexpr(n *Node, init **NodeList) *Node { case ONAME, OLITERAL: return n - case ODOT: + case ODOT, OLEN, OCAP: l := safeexpr(n.Left, init) if l == n.Left { return n @@ -2359,7 +2366,7 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) { lineno = lexlineno if genwrapper_linehistdone == 0 { // All the wrappers can share the same linehist entry. - linehist("<autogenerated>", 0, 0) + linehistpush("<autogenerated>") genwrapper_linehistdone = 1 } @@ -2368,7 +2375,7 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) { markdcl() this := Nod(ODCLFIELD, newname(Lookup(".this")), typenod(rcvr)) - this.Left.Ntype = this.Right + this.Left.Param.Ntype = this.Right in := structargs(getinarg(method.Type), 1) out := structargs(Getoutarg(method.Type), 0) @@ -2394,7 +2401,7 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) { fn := Nod(ODCLFUNC, nil, nil) fn.Nname = newname(newnam) fn.Nname.Defn = fn - fn.Nname.Ntype = t + fn.Nname.Param.Ntype = t declare(fn.Nname, PFUNC) funchdr(fn) @@ -2422,11 +2429,11 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) { var v Val v.Ctype = CTSTR - v.U.Sval = rcvr.Type.Sym.Pkg.Name // package name + v.U = rcvr.Type.Sym.Pkg.Name // package name l = list(l, nodlit(v)) - v.U.Sval = rcvr.Type.Sym.Name // type name + v.U = rcvr.Type.Sym.Name // type name l = list(l, nodlit(v)) - v.U.Sval = method.Sym.Name + v.U = method.Sym.Name l = list(l, nodlit(v)) // method name call := Nod(OCALL, syslook("panicwrap", 0), nil) call.List = l @@ -2568,7 +2575,7 @@ func genhash(sym *Sym, t *Type) { fn.Nname = newname(sym) fn.Nname.Class = PFUNC tfn := Nod(OTFUNC, nil, nil) - fn.Nname.Ntype = tfn + fn.Nname.Param.Ntype = tfn n := Nod(ODCLFIELD, newname(Lookup("p")), typenod(Ptrto(t))) tfn.List = list(tfn.List, n) @@ -2580,7 +2587,7 @@ func genhash(sym *Sym, t *Type) { tfn.Rlist = list(tfn.Rlist, n) funchdr(fn) - typecheck(&fn.Nname.Ntype, Etype) + typecheck(&fn.Nname.Param.Ntype, Etype) // genhash is only called for types that have equality but // cannot be handled by the standard algorithms, @@ -2820,7 +2827,7 @@ func geneq(sym *Sym, t *Type) { fn.Nname = newname(sym) fn.Nname.Class = PFUNC tfn := Nod(OTFUNC, nil, nil) - fn.Nname.Ntype = tfn + fn.Nname.Param.Ntype = tfn n := Nod(ODCLFIELD, newname(Lookup("p")), typenod(Ptrto(t))) tfn.List = list(tfn.List, n) @@ -3096,10 +3103,10 @@ func Simsimtype(t *Type) int { return et } -func listtreecopy(l *NodeList) *NodeList { +func listtreecopy(l *NodeList, lineno int32) *NodeList { var out *NodeList for ; l != nil; l = l.Next { - out = list(out, treecopy(l.N)) + out = list(out, treecopy(l.N, lineno)) } return out } @@ -3139,7 +3146,7 @@ func powtwo(n *Node) int { return -1 } - v := uint64(Mpgetfix(n.Val.U.Xval)) + v := uint64(Mpgetfix(n.Val.U.(*Mpint))) b := uint64(1) for i := 0; i < 64; i++ { if b == v { diff --git a/src/cmd/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go index 7cb632cebe..221b1f43eb 100644 --- a/src/cmd/internal/gc/swt.go +++ b/src/cmd/compile/internal/gc/swt.go @@ -169,10 +169,10 @@ func typecheckswitch(n *Node) { if nvar != nil { if ll != nil && ll.Next == nil && ll.N.Type != nil && !Istype(ll.N.Type, TNIL) { // single entry type switch - nvar.Ntype = typenod(ll.N.Type) + nvar.Param.Ntype = typenod(ll.N.Type) } else { // multiple entry type switch or default - nvar.Ntype = typenod(n.Type) + nvar.Param.Ntype = typenod(n.Type) } typecheck(&nvar, Erv|Easgn) @@ -218,7 +218,7 @@ func (s *exprSwitch) walk(sw *Node) { s.kind = switchKindExpr if Isconst(sw.Ntest, CTBOOL) { s.kind = switchKindTrue - if !sw.Ntest.Val.U.Bval { + if !sw.Ntest.Val.U.(bool) { s.kind = switchKindFalse } } @@ -755,16 +755,16 @@ func exprcmp(c1, c2 *caseClause) int { // sort by constant value to enable binary search switch ct { case CTFLT: - return mpcmpfltflt(n1.Val.U.Fval, n2.Val.U.Fval) + return mpcmpfltflt(n1.Val.U.(*Mpflt), n2.Val.U.(*Mpflt)) case CTINT, CTRUNE: - return Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval) + return Mpcmpfixfix(n1.Val.U.(*Mpint), n2.Val.U.(*Mpint)) case CTSTR: // Sort strings by length and then by value. // It is much cheaper to compare lengths than values, // and all we need here is consistency. // We respect this sorting in exprSwitch.walkCases. - a := n1.Val.U.Sval - b := n2.Val.U.Sval + a := n1.Val.U.(string) + b := n2.Val.U.(string) if len(a) < len(b) { return -1 } diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index 7c9fb8d2b8..be4307690d 100644 --- a/src/cmd/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -23,14 +23,67 @@ type Node struct { List *NodeList Rlist *NodeList + // most nodes + Type *Type + Orig *Node // original form, for printing, and tracking copies of ONAMEs + Nname *Node + + // func + Func *Func + + // ONAME + Name *Name + Defn *Node // ONAME: initializing assignment; OLABEL: labeled statement + Pack *Node // real package for import . names + Curfn *Node // function for local variables + Paramfld *Type // TFIELD for this PPARAM; also for ODOT, curfn + Alloc *Node // allocation call + Param *Param + + // OPACK + Pkg *Pkg + + // OARRAYLIT, OMAPLIT, OSTRUCTLIT. + Initplan *InitPlan + + // Escape analysis. + Escflowsrc *NodeList // flow(this, src) + Escretval *NodeList // on OCALLxxx, list of dummy return values + + Sym *Sym // various + + Opt interface{} // for optimization passes + + // OLITERAL + Val Val + + Xoffset int64 + Stkdelta int64 // offset added by stack frame compaction phase. + + // Escape analysis. + Escloopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes + + Vargen int32 // unique name for OTYPE/ONAME within a function. Function outputs are numbered starting at one. + Lineno int32 + Iota int32 + Walkgen uint32 + + Funcdepth int32 + + // OREGISTER, OINDREG + Reg int16 + + // most nodes - smaller fields + Esclevel Level + Esc uint16 // EscXXX + Op uint8 Nointerface bool Ullman uint8 // sethi/ullman number Addable bool // addressable - Etype uint8 // op for OASOP, etype for OTYPE, exclam for export + Etype uint8 // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg Bounded bool // bounds check unnecessary Class uint8 // PPARAM, PAUTO, PEXTERN, etc - Method bool // OCALLMETH is direct method call Embedded uint8 // ODCLFIELD embedded type Colas bool // OAS resulting from := Diag uint8 // already printed error about this @@ -42,76 +95,36 @@ type Node struct { Initorder uint8 Used bool Isddd bool // is the argument variadic - Readonly bool Implicit bool - Addrtaken bool // address taken, even if not moved to heap - Assigned bool // is the variable ever assigned to - Captured bool // is the variable captured by a closure - Byval bool // is the variable captured by value or by reference - Reslice bool // this is a reslice x = x[0:y] or x = append(x, ...) - Likely int8 // likeliness of if statement - Hasbreak bool // has break statement - Needzero bool // if it contains pointers, needs to be zeroed on function entry - Esc uint16 // EscXXX - Funcdepth int32 - - // most nodes - Type *Type - Orig *Node // original form, for printing, and tracking copies of ONAMEs - Nname *Node - - // func - Func *Func - - // OLITERAL - Val Val + Addrtaken bool // address taken, even if not moved to heap + Assigned bool // is the variable ever assigned to + Likely int8 // likeliness of if statement + Hasbreak bool // has break statement +} - // OREGISTER, OINDREG - Reg int16 +// Name holds Node fields used only by ONAME nodes. +type Name struct { + Heapaddr *Node // temp holding heap address of param + Inlvar *Node // ONAME substitute while inlining + Decldepth int32 // declaration loop depth, increased for every loop or label + Method bool // OCALLMETH name + Readonly bool + Captured bool // is the variable captured by a closure + Byval bool // is the variable captured by value or by reference + Needzero bool // if it contains pointers, needs to be zeroed on function entry +} - // ONAME - Ntype *Node - Defn *Node // ONAME: initializing assignment; OLABEL: labeled statement - Pack *Node // real package for import . names - Curfn *Node // function for local variables - Paramfld *Type // TFIELD for this PPARAM; also for ODOT, curfn - Decldepth int // declaration loop depth, increased for every loop or label +type Param struct { + Ntype *Node // ONAME func param with PHEAP - Heapaddr *Node // temp holding heap address of param Outerexpr *Node // expression copied into closure for variable Stackparam *Node // OPARAM node referring to stack copy of param - Alloc *Node // allocation call // ONAME closure param with PPARAMREF Outer *Node // outer PPARAMREF in nested closure Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF Top int // top context (Ecall, Eproc, etc) - - // ONAME substitute while inlining - Inlvar *Node - - // OPACK - Pkg *Pkg - - // OARRAYLIT, OMAPLIT, OSTRUCTLIT. - Initplan *InitPlan - - // Escape analysis. - Escflowsrc *NodeList // flow(this, src) - Escretval *NodeList // on OCALLxxx, list of dummy return values - Escloopdepth int // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes - - Sym *Sym // various - Vargen int32 // unique name for OTYPE/ONAME within a function. Function outputs are numbered starting at one. - Lineno int32 - Xoffset int64 - Stkdelta int64 // offset added by stack frame compaction phase. - Ostk int32 // 6g only - Iota int32 - Walkgen uint32 - Esclevel Level - Opt interface{} // for optimization passes } // Func holds Node fields used only with function-like nodes. diff --git a/src/cmd/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go index 6f7830d70a..cf1589eb03 100644 --- a/src/cmd/internal/gc/type.go +++ b/src/cmd/compile/internal/gc/type.go @@ -10,7 +10,7 @@ package gc import ( - "cmd/internal/ssa" + "cmd/compile/internal/ssa" ) func (t *Type) Size() int64 { diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 6daf842474..2900da8be7 100644 --- a/src/cmd/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -311,8 +311,8 @@ OpSwitch: break OpSwitch case ONAME: - if n.Decldepth == 0 { - n.Decldepth = decldepth + if n.Name.Decldepth == 0 { + n.Name.Decldepth = decldepth } if n.Etype != 0 { ok |= Ecall @@ -392,7 +392,7 @@ OpSwitch: return } - t.Bound = Mpgetfix(v.U.Xval) + t.Bound = Mpgetfix(v.U.(*Mpint)) if doesoverflow(v, Types[TINT]) { Yyerror("array bound is too large") n.Type = nil @@ -770,7 +770,7 @@ OpSwitch: } if (op == ODIV || op == OMOD) && Isconst(r, CTINT) { - if mpcmpfixc(r.Val.U.Xval, 0) == 0 { + if mpcmpfixc(r.Val.U.(*Mpint), 0) == 0 { Yyerror("division by zero") n.Type = nil return @@ -813,8 +813,8 @@ OpSwitch: var l *Node for l = n.Left; l != r; l = l.Left { l.Addrtaken = true - if l.Closure != nil { - l.Closure.Addrtaken = true + if l.Param != nil && l.Param.Closure != nil { + l.Param.Closure.Addrtaken = true } } @@ -822,8 +822,8 @@ OpSwitch: Fatal("found non-orig name node %v", l) } l.Addrtaken = true - if l.Closure != nil { - l.Closure.Addrtaken = true + if l.Param != nil && l.Param.Closure != nil { + l.Param.Closure.Addrtaken = true } defaultlit(&n.Left, nil) l = n.Left @@ -891,6 +891,9 @@ OpSwitch: } n.Op = ONAME + if n.Name == nil { + n.Name = new(Name) + } n.Sym = n.Right.Sym n.Type = methodfunc(n.Type, n.Left.Type) n.Xoffset = 0 @@ -1024,7 +1027,7 @@ OpSwitch: case TSTRING, TARRAY: indexlit(&n.Right) if t.Etype == TSTRING { - n.Type = Types[TUINT8] + n.Type = bytetype } else { n.Type = t.Type } @@ -1043,14 +1046,14 @@ OpSwitch: } if Isconst(n.Right, CTINT) { - x := Mpgetfix(n.Right.Val.U.Xval) + x := Mpgetfix(n.Right.Val.U.(*Mpint)) if x < 0 { Yyerror("invalid %s index %v (index must be non-negative)", why, n.Right) } else if Isfixedarray(t) && t.Bound > 0 && x >= t.Bound { Yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.Bound) - } else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.Val.U.Sval)) { - Yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.Val.U.Sval)) - } else if Mpcmpfixfix(n.Right.Val.U.Xval, Maxintval[TINT]) > 0 { + } else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.Val.U.(string))) { + Yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.Val.U.(string))) + } else if Mpcmpfixfix(n.Right.Val.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("invalid %s index %v (index too large)", why, n.Right) } } @@ -1303,7 +1306,7 @@ OpSwitch: if l.Op == OTYPE { if n.Isddd || l.Type.Bound == -100 { if l.Type.Broke == 0 { - Yyerror("invalid use of ... in type conversion", l) + Yyerror("invalid use of ... in type conversion to %v", l.Type) } n.Diag = 1 } @@ -1435,9 +1438,9 @@ OpSwitch: if Isconst(l, CTCPLX) { r := n if n.Op == OREAL { - n = nodfltconst(&l.Val.U.Cval.Real) + n = nodfltconst(&l.Val.U.(*Mpcplx).Real) } else { - n = nodfltconst(&l.Val.U.Cval.Imag) + n = nodfltconst(&l.Val.U.(*Mpcplx).Imag) } n.Orig = r } @@ -1451,7 +1454,7 @@ OpSwitch: case TSTRING: if Isconst(l, CTSTR) { r := Nod(OXXX, nil, nil) - Nodconst(r, Types[TINT], int64(len(l.Val.U.Sval))) + Nodconst(r, Types[TINT], int64(len(l.Val.U.(string)))) r.Orig = n n = r } @@ -1528,7 +1531,7 @@ OpSwitch: var t *Type switch l.Type.Etype { default: - Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type, r.Type) + Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type) n.Type = nil return @@ -1636,17 +1639,16 @@ OpSwitch: } // Unpack multiple-return result before type-checking. + var funarg *Type if Istype(t, TSTRUCT) && t.Funarg != 0 { - t = t.Type - if Istype(t, TFIELD) { - t = t.Type - } + funarg = t + t = t.Type.Type } n.Type = t if !Isslice(t) { if Isconst(args.N, CTNIL) { - Yyerror("first argument to append must be typed slice; have untyped nil", t) + Yyerror("first argument to append must be typed slice; have untyped nil") n.Type = nil return } @@ -1678,11 +1680,19 @@ OpSwitch: break OpSwitch } - for args = args.Next; args != nil; args = args.Next { - if args.N.Type == nil { - continue + if funarg != nil { + for t := funarg.Type.Down; t != nil; t = t.Down { + if assignop(t.Type, n.Type.Type, nil) == 0 { + Yyerror("cannot append %v value to []%v", t.Type, n.Type.Type) + } + } + } else { + for args = args.Next; args != nil; args = args.Next { + if args.N.Type == nil { + continue + } + args.N = assignconv(args.N, t.Type, "append") } - args.N = assignconv(args.N, t.Type, "append") } break OpSwitch @@ -1852,7 +1862,7 @@ OpSwitch: n.Type = nil return } - if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val.U.Xval, r.Val.U.Xval) > 0 { + if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val.U.(*Mpint), r.Val.U.(*Mpint)) > 0 { Yyerror("len larger than cap in make(%v)", t) n.Type = nil return @@ -2248,16 +2258,16 @@ func checksliceindex(l *Node, r *Node, tp *Type) int { } if r.Op == OLITERAL { - if Mpgetfix(r.Val.U.Xval) < 0 { + if Mpgetfix(r.Val.U.(*Mpint)) < 0 { Yyerror("invalid slice index %v (index must be non-negative)", r) return -1 - } else if tp != nil && tp.Bound > 0 && Mpgetfix(r.Val.U.Xval) > tp.Bound { + } else if tp != nil && tp.Bound > 0 && Mpgetfix(r.Val.U.(*Mpint)) > tp.Bound { Yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.Bound) return -1 - } else if Isconst(l, CTSTR) && Mpgetfix(r.Val.U.Xval) > int64(len(l.Val.U.Sval)) { - Yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.Val.U.Sval)) + } else if Isconst(l, CTSTR) && Mpgetfix(r.Val.U.(*Mpint)) > int64(len(l.Val.U.(string))) { + Yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.Val.U.(string))) return -1 - } else if Mpcmpfixfix(r.Val.U.Xval, Maxintval[TINT]) > 0 { + } else if Mpcmpfixfix(r.Val.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("invalid slice index %v (index too large)", r) return -1 } @@ -2267,7 +2277,7 @@ func checksliceindex(l *Node, r *Node, tp *Type) int { } func checksliceconst(lo *Node, hi *Node) int { - if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && Mpcmpfixfix(lo.Val.U.Xval, hi.Val.U.Xval) > 0 { + if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && Mpcmpfixfix(lo.Val.U.(*Mpint), hi.Val.U.(*Mpint)) > 0 { Yyerror("invalid slice index: %v > %v", lo, hi) return -1 } @@ -2817,10 +2827,10 @@ func keydup(n *Node, hash []*Node) { b = 23 case CTINT, CTRUNE: - b = uint32(Mpgetfix(n.Val.U.Xval)) + b = uint32(Mpgetfix(n.Val.U.(*Mpint))) case CTFLT: - d := mpgetflt(n.Val.U.Fval) + d := mpgetflt(n.Val.U.(*Mpflt)) x := math.Float64bits(d) for i := 0; i < 8; i++ { b = b*PRIME1 + uint32(x&0xFF) @@ -2829,8 +2839,8 @@ func keydup(n *Node, hash []*Node) { case CTSTR: b = 0 - s := n.Val.U.Sval - for i := len(n.Val.U.Sval); i > 0; i-- { + s := n.Val.U.(string) + for i := len(n.Val.U.(string)); i > 0; i-- { b = b*PRIME1 + uint32(s[0]) s = s[1:] } @@ -2846,12 +2856,12 @@ func keydup(n *Node, hash []*Node) { if Eqtype(a.Left.Type, n.Type) { cmp.Right = a.Left evconst(&cmp) - b = uint32(obj.Bool2int(cmp.Val.U.Bval)) + b = uint32(obj.Bool2int(cmp.Val.U.(bool))) } } else if Eqtype(a.Type, n.Type) { cmp.Right = a evconst(&cmp) - b = uint32(obj.Bool2int(cmp.Val.U.Bval)) + b = uint32(obj.Bool2int(cmp.Val.U.(bool))) } if b != 0 { @@ -2869,11 +2879,11 @@ func indexdup(n *Node, hash []*Node) { Fatal("indexdup: not OLITERAL") } - b := uint32(Mpgetfix(n.Val.U.Xval)) + b := uint32(Mpgetfix(n.Val.U.(*Mpint))) h := uint(b % uint32(len(hash))) var c uint32 for a := hash[h]; a != nil; a = a.Ntest { - c = uint32(Mpgetfix(a.Val.U.Xval)) + c = uint32(Mpgetfix(a.Val.U.(*Mpint))) if b == c { Yyerror("duplicate index in array literal: %d", b) return @@ -3263,14 +3273,14 @@ func checkassign(stmt *Node, n *Node) { var l *Node for l = n; l != r; l = l.Left { l.Assigned = true - if l.Closure != nil { - l.Closure.Assigned = true + if l.Param != nil && l.Param.Closure != nil { + l.Param.Closure.Assigned = true } } l.Assigned = true - if l.Closure != nil { - l.Closure.Assigned = true + if l.Param != nil && l.Param.Closure != nil { + l.Param.Closure.Assigned = true } } @@ -3335,7 +3345,7 @@ func typecheckas(n *Node) { // so that the conversion below happens). n.Left = resolve(n.Left) - if n.Left.Defn != n || n.Left.Ntype != nil { + if n.Left.Defn != n || n.Left.Param.Ntype != nil { typecheck(&n.Left, Erv|Easgn) } @@ -3347,7 +3357,7 @@ func typecheckas(n *Node) { } } - if n.Left.Defn == n && n.Left.Ntype == nil { + if n.Left.Defn == n && n.Left.Param.Ntype == nil { defaultlit(&n.Right, nil) n.Left.Type = n.Right.Type } @@ -3360,29 +3370,6 @@ func typecheckas(n *Node) { if n.Left.Typecheck == 0 { typecheck(&n.Left, Erv|Easgn) } - - // Recognize slices being updated in place, for better code generation later. - // Don't rewrite if using race detector, to avoid needing to teach race detector - // about this optimization. - if n.Left != nil && n.Left.Op != OINDEXMAP && n.Right != nil && flag_race == 0 { - switch n.Right.Op { - // For x = x[0:y], x can be updated in place, without touching pointer. - // TODO(rsc): Reenable once it is actually updated in place without touching the pointer. - case OSLICE, OSLICE3, OSLICESTR: - if false && samesafeexpr(n.Left, n.Right.Left) && (n.Right.Right.Left == nil || iszero(n.Right.Right.Left)) { - n.Right.Reslice = true - } - - // For x = append(x, ...), x can be updated in place when there is capacity, - // without touching the pointer; otherwise the emitted code to growslice - // can take care of updating the pointer, and only in that case. - // TODO(rsc): Reenable once the emitted code does update the pointer. - case OAPPEND: - if false && n.Right.List != nil && samesafeexpr(n.Left, n.Right.List.N) { - n.Right.Reslice = true - } - } - } } func checkassignto(src *Type, dst *Node) { @@ -3399,7 +3386,7 @@ func typecheckas2(n *Node) { // delicate little dance. ll.N = resolve(ll.N) - if ll.N.Defn != n || ll.N.Ntype != nil { + if ll.N.Defn != n || ll.N.Param.Ntype != nil { typecheck(&ll.N, Erv|Easgn) } } @@ -3423,7 +3410,7 @@ func typecheckas2(n *Node) { if ll.N.Type != nil && lr.N.Type != nil { lr.N = assignconv(lr.N, ll.N.Type, "assignment") } - if ll.N.Defn == n && ll.N.Ntype == nil { + if ll.N.Defn == n && ll.N.Param.Ntype == nil { defaultlit(&lr.N, nil) ll.N.Type = lr.N.Type } @@ -3456,7 +3443,7 @@ func typecheckas2(n *Node) { if t.Type != nil && ll.N.Type != nil { checkassignto(t.Type, ll.N) } - if ll.N.Defn == n && ll.N.Ntype == nil { + if ll.N.Defn == n && ll.N.Param.Ntype == nil { ll.N.Type = t.Type } t = structnext(&s) @@ -3495,7 +3482,7 @@ func typecheckas2(n *Node) { if l.Type != nil && l.Type.Etype != TBOOL { checkassignto(Types[TBOOL], l) } - if l.Defn == n && l.Ntype == nil { + if l.Defn == n && l.Param.Ntype == nil { l.Type = Types[TBOOL] } goto out @@ -3534,7 +3521,7 @@ func typecheckfunc(n *Node) { for l := n.Func.Dcl; l != nil; l = l.Next { if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) { - l.N.Decldepth = 1 + l.N.Name.Decldepth = 1 } } } @@ -3542,10 +3529,10 @@ func typecheckfunc(n *Node) { func stringtoarraylit(np **Node) { n := *np if n.Left.Op != OLITERAL || n.Left.Val.Ctype != CTSTR { - Fatal("stringtoarraylit %N", n) + Fatal("stringtoarraylit %v", n) } - s := n.Left.Val.U.Sval + s := n.Left.Val.U.(string) var l *NodeList if n.Type.Type.Etype == TUINT8 { // []byte @@ -3659,8 +3646,8 @@ func typecheckdeftype(n *Node) { setlineno(n) n.Type.Sym = n.Sym n.Typecheck = 1 - typecheck(&n.Ntype, Etype) - t := n.Ntype.Type + typecheck(&n.Param.Ntype, Etype) + t := n.Param.Ntype.Type if t == nil { n.Diag = 1 n.Type = nil @@ -3770,10 +3757,10 @@ func typecheckdef(n *Node) *Node { break case OLITERAL: - if n.Ntype != nil { - typecheck(&n.Ntype, Etype) - n.Type = n.Ntype.Type - n.Ntype = nil + if n.Param.Ntype != nil { + typecheck(&n.Param.Ntype, Etype) + n.Type = n.Param.Ntype.Type + n.Param.Ntype = nil if n.Type == nil { n.Diag = 1 goto ret @@ -3822,9 +3809,9 @@ func typecheckdef(n *Node) *Node { n.Type = e.Type case ONAME: - if n.Ntype != nil { - typecheck(&n.Ntype, Etype) - n.Type = n.Ntype.Type + if n.Param.Ntype != nil { + typecheck(&n.Param.Ntype, Etype) + n.Type = n.Param.Ntype.Type if n.Type == nil { n.Diag = 1 @@ -3902,12 +3889,12 @@ func checkmake(t *Type, arg string, n *Node) int { switch n.Val.Ctype { case CTINT, CTRUNE, CTFLT, CTCPLX: n.Val = toint(n.Val) - if mpcmpfixc(n.Val.U.Xval, 0) < 0 { + if mpcmpfixc(n.Val.U.(*Mpint), 0) < 0 { Yyerror("negative %s argument in make(%v)", arg, t) return -1 } - if Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT]) > 0 { + if Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("%s argument too large in make(%v)", arg, t) return -1 } diff --git a/src/cmd/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go index aa90a19308..824ecd0339 100644 --- a/src/cmd/internal/gc/unsafe.go +++ b/src/cmd/compile/internal/gc/unsafe.go @@ -140,8 +140,8 @@ ret: var val Val val.Ctype = CTINT - val.U.Xval = new(Mpint) - Mpmovecfix(val.U.Xval, v) + val.U = new(Mpint) + Mpmovecfix(val.U.(*Mpint), v) n := Nod(OLITERAL, nil, nil) n.Orig = nn n.Val = val diff --git a/src/cmd/internal/gc/util.go b/src/cmd/compile/internal/gc/util.go index 5dc6561b48..c59af0665b 100644 --- a/src/cmd/internal/gc/util.go +++ b/src/cmd/compile/internal/gc/util.go @@ -1,7 +1,6 @@ package gc import ( - "cmd/internal/obj" "os" "runtime" "runtime/pprof" @@ -10,7 +9,7 @@ import ( ) func (n *Node) Line() string { - return obj.Linklinefmt(Ctxt, int(n.Lineno), false, false) + return Ctxt.LineHist.LineString(int(n.Lineno)) } func atoi(s string) int { diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index c32a8137d6..d5eb44c0bb 100644 --- a/src/cmd/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -352,6 +352,20 @@ func walkstmt(np **Node) { *np = n } +func isSmallMakeSlice(n *Node) bool { + if n.Op != OMAKESLICE { + return false + } + l := n.Left + r := n.Right + if r == nil { + r = l + } + t := n.Type + + return Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val.U.(*Mpint)) < (1<<16)/t.Type.Width) +} + /* * walk the whole tree of the body of an * expression or simple statement. @@ -601,7 +615,7 @@ func walkexpr(np **Node, init **NodeList) { n.Left.Func.Enter = nil // Replace OCLOSURE with ONAME/PFUNC. - n.Left = n.Left.Closure.Nname + n.Left = n.Left.Param.Closure.Nname // Update type of OCALLFUNC node. // Output arguments had not changed, but their offsets could. @@ -711,6 +725,23 @@ func walkexpr(np **Node, init **NodeList) { n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1) walkexpr(&n, init) goto ret + + case OAPPEND: + // x = append(...) + r := n.Right + if r.Isddd { + r = appendslice(r, init) // also works for append(slice, string). + } else { + r = walkappend(r, init, n) + } + n.Right = r + if r.Op == OAPPEND { + // Left in place for back end. + // Do not add a new write barrier. + goto ret + } + // Otherwise, lowered for race detector. + // Treat as ordinary assignment. } if n.Left != nil && n.Right != nil { @@ -1189,7 +1220,7 @@ func walkexpr(np **Node, init **NodeList) { Yyerror("index out of bounds") } } else if Isconst(n.Left, CTSTR) { - n.Bounded = bounded(r, int64(len(n.Left.Val.U.Sval))) + n.Bounded = bounded(r, int64(len(n.Left.Val.U.(string)))) if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) { Warn("index bounds check elided") } @@ -1200,16 +1231,16 @@ func walkexpr(np **Node, init **NodeList) { // replace "abc"[1] with 'b'. // delayed until now because "abc"[1] is not // an ideal constant. - v := Mpgetfix(n.Right.Val.U.Xval) + v := Mpgetfix(n.Right.Val.U.(*Mpint)) - Nodconst(n, n.Type, int64(n.Left.Val.U.Sval[v])) + Nodconst(n, n.Type, int64(n.Left.Val.U.(string)[v])) n.Typecheck = 1 } } } if Isconst(n.Right, CTINT) { - if Mpcmpfixfix(n.Right.Val.U.Xval, &mpzero) < 0 || Mpcmpfixfix(n.Right.Val.U.Xval, Maxintval[TINT]) > 0 { + if Mpcmpfixfix(n.Right.Val.U.(*Mpint), &mpzero) < 0 || Mpcmpfixfix(n.Right.Val.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("index out of bounds") } } @@ -1263,56 +1294,39 @@ func walkexpr(np **Node, init **NodeList) { case ORECV: Fatal("walkexpr ORECV") // should see inside OAS only - case OSLICE: - if n.Right != nil && n.Right.Left == nil && n.Right.Right == nil { // noop - walkexpr(&n.Left, init) - n = n.Left - goto ret - } - fallthrough - - case OSLICEARR, OSLICESTR: - if n.Right == nil { // already processed - goto ret - } - + case OSLICE, OSLICEARR, OSLICESTR: walkexpr(&n.Left, init) - - // cgen_slice can't handle string literals as source - // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi] - if (n.Op == OSLICESTR && n.Left.Op == OLITERAL) || (n.Left.Op == OINDEX) { - n.Left = copyexpr(n.Left, n.Left.Type, init) - } else { - n.Left = safeexpr(n.Left, init) - } walkexpr(&n.Right.Left, init) - n.Right.Left = safeexpr(n.Right.Left, init) + if n.Right.Left != nil && iszero(n.Right.Left) { + // Reduce x[0:j] to x[:j]. + n.Right.Left = nil + } walkexpr(&n.Right.Right, init) - n.Right.Right = safeexpr(n.Right.Right, init) - n = sliceany(n, init) // chops n.Right, sets n.List + n = reduceSlice(n) goto ret case OSLICE3, OSLICE3ARR: - if n.Right == nil { // already processed - goto ret - } - walkexpr(&n.Left, init) - - // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi] - // TODO the comment on the previous line was copied from case OSLICE. it might not even be true. - if n.Left.Op == OINDEX { - n.Left = copyexpr(n.Left, n.Left.Type, init) - } else { - n.Left = safeexpr(n.Left, init) - } walkexpr(&n.Right.Left, init) - n.Right.Left = safeexpr(n.Right.Left, init) + if n.Right.Left != nil && iszero(n.Right.Left) { + // Reduce x[0:j:k] to x[:j:k]. + n.Right.Left = nil + } walkexpr(&n.Right.Right.Left, init) - n.Right.Right.Left = safeexpr(n.Right.Right.Left, init) walkexpr(&n.Right.Right.Right, init) - n.Right.Right.Right = safeexpr(n.Right.Right.Right, init) - n = sliceany(n, init) // chops n.Right, sets n.List + + r := n.Right.Right.Right + if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) { + // Reduce x[i:j:cap(x)] to x[i:j]. + n.Right.Right = n.Right.Right.Left + if n.Op == OSLICE3 { + n.Op = OSLICE + } else { + n.Op = OSLICEARR + } + n = reduceSlice(n) + goto ret + } goto ret case OADDR: @@ -1320,7 +1334,10 @@ func walkexpr(np **Node, init **NodeList) { goto ret case ONEW: - if n.Esc == EscNone && n.Type.Type.Width < 1<<16 { + if n.Esc == EscNone { + if n.Type.Type.Width >= 1<<16 { + Fatal("Large ONEW with EscNone, %v", n) + } r := temp(n.Type.Type) r = Nod(OAS, r, nil) // zero temp typecheck(&r, Etop) @@ -1338,7 +1355,7 @@ func walkexpr(np **Node, init **NodeList) { // comparing the lengths instead will yield the same result // without the function call. case OCMPSTR: - if (Isconst(n.Left, CTSTR) && len(n.Left.Val.U.Sval) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val.U.Sval) == 0) { + if (Isconst(n.Left, CTSTR) && len(n.Left.Val.U.(string)) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val.U.(string)) == 0) { r := Nod(int(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)) typecheck(&r, Erv) walkexpr(&r, init) @@ -1400,12 +1417,8 @@ func walkexpr(np **Node, init **NodeList) { goto ret case OAPPEND: - if n.Isddd { - n = appendslice(n, init) // also works for append(slice, string). - } else { - n = walkappend(n, init) - } - goto ret + // order should make sure we only see OAS(node, OAPPEND), which we handle above. + Fatal("append outside assignment") case OCOPY: n = copyany(n, init, flag_race) @@ -1462,7 +1475,10 @@ func walkexpr(np **Node, init **NodeList) { l = r } t := n.Type - if n.Esc == EscNone && Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val.U.Xval) < (1<<16)/t.Type.Width) { + if n.Esc == EscNone { + if !isSmallMakeSlice(n) { + Fatal("Non-small OMAKESLICE with EscNone, %v", n) + } // var arr [r]T // n = arr[:l] t = aindex(r, t.Type) // [r]T @@ -1647,6 +1663,22 @@ ret: *np = n } +func reduceSlice(n *Node) *Node { + r := n.Right.Right + if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) { + // Reduce x[i:len(x)] to x[i:]. + n.Right.Right = nil + } + if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil { + // Reduce x[:] to x. + if Debug_slice > 0 { + Warn("slice: omit slice operation") + } + return n.Left + } + return n +} + func ascompatee1(op int, l *Node, r *Node, init **NodeList) *Node { // convas will turn map assigns into function calls, // making it impossible for reorder3 to work. @@ -2108,9 +2140,8 @@ func isstack(n *Node) bool { } switch n.Op { - // OINDREG only ends up in walk if it's indirect of SP. case OINDREG: - return true + return n.Reg == int16(Thearch.REGSP) case ONAME: switch n.Class { @@ -2185,26 +2216,6 @@ func needwritebarrier(l *Node, r *Node) bool { return false } - // No write barrier for reslice: x = x[0:y] or x = append(x, ...). - // Both are compiled to modify x directly. - // In the case of append, a write barrier may still be needed - // if the underlying array grows, but the append code can - // generate the write barrier directly in that case. - // (It does not yet, but the cost of the write barrier will be - // small compared to the cost of the allocation.) - if r.Reslice { - switch r.Op { - case OSLICE, OSLICE3, OSLICESTR, OAPPEND: - break - - default: - Dump("bad reslice-l", l) - Dump("bad reslice-r", r) - } - - return false - } - // Otherwise, be conservative and use write barrier. return true } @@ -2215,65 +2226,11 @@ var applywritebarrier_bv Bvec func applywritebarrier(n *Node, init **NodeList) *Node { if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) { - if Curfn != nil && Curfn.Func.Nowritebarrier { - Yyerror("write barrier prohibited") - } - if flag_race == 0 { - if Debug_wb > 1 { - Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0)) - } - n.Op = OASWB - return n - } - // Use slow path always for race detector. - if Debug_wb > 0 { - Warnl(int(n.Lineno), "write barrier") - } - t := n.Left.Type - l := Nod(OADDR, n.Left, nil) - l.Etype = 1 // addr does not escape - if t.Width == int64(Widthptr) { - n = mkcall1(writebarrierfn("writebarrierptr", t, n.Right.Type), nil, init, l, n.Right) - } else if t.Etype == TSTRING { - n = mkcall1(writebarrierfn("writebarrierstring", t, n.Right.Type), nil, init, l, n.Right) - } else if Isslice(t) { - n = mkcall1(writebarrierfn("writebarrierslice", t, n.Right.Type), nil, init, l, n.Right) - } else if Isinter(t) { - n = mkcall1(writebarrierfn("writebarrieriface", t, n.Right.Type), nil, init, l, n.Right) - } else if t.Width <= int64(4*Widthptr) { - x := int64(0) - if applywritebarrier_bv.b == nil { - applywritebarrier_bv = bvalloc(4) - } - bvresetall(applywritebarrier_bv) - onebitwalktype1(t, &x, applywritebarrier_bv) - var name string - switch t.Width / int64(Widthptr) { - default: - Fatal("found writebarrierfat for %d-byte object of type %v", int(t.Width), t) - - case 2: - name = fmt.Sprintf("writebarrierfat%d%d", bvget(applywritebarrier_bv, 0), bvget(applywritebarrier_bv, 1)) - - case 3: - name = fmt.Sprintf("writebarrierfat%d%d%d", bvget(applywritebarrier_bv, 0), bvget(applywritebarrier_bv, 1), bvget(applywritebarrier_bv, 2)) - - case 4: - name = fmt.Sprintf("writebarrierfat%d%d%d%d", bvget(applywritebarrier_bv, 0), bvget(applywritebarrier_bv, 1), bvget(applywritebarrier_bv, 2), bvget(applywritebarrier_bv, 3)) - } - - n = mkcall1(writebarrierfn(name, t, n.Right.Type), nil, init, l, Nodintconst(0), n.Right) - } else { - r := n.Right - for r.Op == OCONVNOP { - r = r.Left - } - r = Nod(OADDR, r, nil) - r.Etype = 1 // addr does not escape - - //warnl(n->lineno, "typedmemmove %T %N", t, r); - n = mkcall1(writebarrierfn("typedmemmove", t, r.Left.Type), nil, init, typename(t), l, r) + if Debug_wb > 1 { + Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0)) } + n.Op = OASWB + return n } return n } @@ -2728,10 +2685,10 @@ func paramstoheap(argin **Type, out int) *NodeList { if v.Alloc == nil { v.Alloc = callnew(v.Type) } - nn = list(nn, Nod(OAS, v.Heapaddr, v.Alloc)) + nn = list(nn, Nod(OAS, v.Name.Heapaddr, v.Alloc)) if v.Class&^PHEAP != PPARAMOUT { - as = Nod(OAS, v, v.Stackparam) - v.Stackparam.Typecheck = 1 + as = Nod(OAS, v, v.Param.Stackparam) + v.Param.Stackparam.Typecheck = 1 typecheck(&as, Etop) as = applywritebarrier(as, &nn) nn = list(nn, as) @@ -2754,7 +2711,7 @@ func returnsfromheap(argin **Type) *NodeList { if v == nil || v.Class != PHEAP|PPARAMOUT { continue } - nn = list(nn, Nod(OAS, v.Stackparam, v)) + nn = list(nn, Nod(OAS, v.Param.Stackparam, v)) } return nn @@ -2871,7 +2828,7 @@ func addstr(n *Node, init **NodeList) *Node { sz := int64(0) for l := n.List; l != nil; l = l.Next { if n.Op == OLITERAL { - sz += int64(len(n.Val.U.Sval)) + sz += int64(len(n.Val.U.(string))) } } @@ -3026,7 +2983,13 @@ func appendslice(n *Node, init **NodeList) *Node { return s } -// expand append(src, a [, b]* ) to +// Rewrite append(src, x, y, z) so that any side effects in +// x, y, z (including runtime panics) are evaluated in +// initialization statements before the append. +// For normal code generation, stop there and leave the +// rest to cgen_append. +// +// For race detector, expand append(src, a [, b]* ) to // // init { // s := src @@ -3041,13 +3004,21 @@ func appendslice(n *Node, init **NodeList) *Node { // ... // } // s -func walkappend(n *Node, init **NodeList) *Node { - walkexprlistsafe(n.List, init) +func walkappend(n *Node, init **NodeList, dst *Node) *Node { + if !samesafeexpr(dst, n.List.N) { + l := n.List + l.N = safeexpr(l.N, init) + walkexpr(&l.N, init) + } + walkexprlistsafe(n.List.Next, init) // walkexprlistsafe will leave OINDEX (s[n]) alone if both s // and n are name or literal, but those may index the slice we're // modifying here. Fix explicitly. - for l := n.List; l != nil; l = l.Next { + // Using cheapexpr also makes sure that the evaluation + // of all arguments (and especially any panics) happen + // before we begin to modify the slice in a visible way. + for l := n.List.Next; l != nil; l = l.Next { l.N = cheapexpr(l.N, init) } @@ -3062,6 +3033,12 @@ func walkappend(n *Node, init **NodeList) *Node { return nsrc } + // General case, with no function calls left as arguments. + // Leave for gen, except that race detector requires old form + if flag_race == 0 { + return n + } + var l *NodeList ns := temp(nsrc.Type) @@ -3166,213 +3143,6 @@ func copyany(n *Node, init **NodeList, runtimecall int) *Node { return nlen } -// Generate frontend part for OSLICE[3][ARR|STR] -// -func sliceany(n *Node, init **NodeList) *Node { - var hb *Node - var cb *Node - - // print("before sliceany: %+N\n", n); - - src := n.Left - - lb := n.Right.Left - slice3 := n.Op == OSLICE3 || n.Op == OSLICE3ARR - if slice3 { - hb = n.Right.Right.Left - cb = n.Right.Right.Right - } else { - hb = n.Right.Right - cb = nil - } - - bounded := int(n.Etype) - - var bound *Node - if n.Op == OSLICESTR { - bound = Nod(OLEN, src, nil) - } else { - bound = Nod(OCAP, src, nil) - } - - typecheck(&bound, Erv) - walkexpr(&bound, init) // if src is an array, bound will be a const now. - - // static checks if possible - bv := int64(1 << 50) - - if Isconst(bound, CTINT) { - if !Smallintconst(bound) { - Yyerror("array len too large") - } else { - bv = Mpgetfix(bound.Val.U.Xval) - } - } - - if Isconst(cb, CTINT) { - cbv := Mpgetfix(cb.Val.U.Xval) - if cbv < 0 || cbv > bv { - Yyerror("slice index out of bounds") - } - } - - if Isconst(hb, CTINT) { - hbv := Mpgetfix(hb.Val.U.Xval) - if hbv < 0 || hbv > bv { - Yyerror("slice index out of bounds") - } - } - - if Isconst(lb, CTINT) { - lbv := Mpgetfix(lb.Val.U.Xval) - if lbv < 0 || lbv > bv { - Yyerror("slice index out of bounds") - lbv = -1 - } - - if lbv == 0 { - lb = nil - } - } - - // Checking src[lb:hb:cb] or src[lb:hb]. - // if chk0 || chk1 || chk2 { panicslice() } - - // All comparisons are unsigned to avoid testing < 0. - bt := Types[Simtype[TUINT]] - - if cb != nil && cb.Type.Width > 4 { - bt = Types[TUINT64] - } - if hb != nil && hb.Type.Width > 4 { - bt = Types[TUINT64] - } - if lb != nil && lb.Type.Width > 4 { - bt = Types[TUINT64] - } - - bound = cheapexpr(conv(bound, bt), init) - - var chk0 *Node // cap(src) < cb - if cb != nil { - cb = cheapexpr(conv(cb, bt), init) - if bounded == 0 { - chk0 = Nod(OLT, bound, cb) - } - } else if slice3 { - // When we figure out what this means, implement it. - Fatal("slice3 with cb == N") // rejected by parser - } - - var chk1 *Node // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb] - if hb != nil { - hb = cheapexpr(conv(hb, bt), init) - if bounded == 0 { - if cb != nil { - chk1 = Nod(OLT, cb, hb) - } else { - chk1 = Nod(OLT, bound, hb) - } - } - } else if slice3 { - // When we figure out what this means, implement it. - Fatal("slice3 with hb == N") // rejected by parser - } else if n.Op == OSLICEARR { - hb = bound - } else { - hb = Nod(OLEN, src, nil) - typecheck(&hb, Erv) - walkexpr(&hb, init) - hb = cheapexpr(conv(hb, bt), init) - } - - var chk2 *Node // hb < lb - if lb != nil { - lb = cheapexpr(conv(lb, bt), init) - if bounded == 0 { - chk2 = Nod(OLT, hb, lb) - } - } - - if chk0 != nil || chk1 != nil || chk2 != nil { - chk := Nod(OIF, nil, nil) - chk.Nbody = list1(mkcall("panicslice", nil, init)) - chk.Likely = -1 - if chk0 != nil { - chk.Ntest = chk0 - } - if chk1 != nil { - if chk.Ntest == nil { - chk.Ntest = chk1 - } else { - chk.Ntest = Nod(OOROR, chk.Ntest, chk1) - } - } - - if chk2 != nil { - if chk.Ntest == nil { - chk.Ntest = chk2 - } else { - chk.Ntest = Nod(OOROR, chk.Ntest, chk2) - } - } - - typecheck(&chk, Etop) - walkstmt(&chk) - *init = concat(*init, chk.Ninit) - chk.Ninit = nil - *init = list(*init, chk) - } - - // prepare new cap, len and offs for backend cgen_slice - // cap = bound [ - lo ] - n.Right = nil - - n.List = nil - if !slice3 { - cb = bound - } - if lb == nil { - bound = conv(cb, Types[Simtype[TUINT]]) - } else { - bound = Nod(OSUB, conv(cb, Types[Simtype[TUINT]]), conv(lb, Types[Simtype[TUINT]])) - } - typecheck(&bound, Erv) - walkexpr(&bound, init) - n.List = list(n.List, bound) - - // len = hi [ - lo] - if lb == nil { - hb = conv(hb, Types[Simtype[TUINT]]) - } else { - hb = Nod(OSUB, conv(hb, Types[Simtype[TUINT]]), conv(lb, Types[Simtype[TUINT]])) - } - typecheck(&hb, Erv) - walkexpr(&hb, init) - n.List = list(n.List, hb) - - // offs = [width *] lo, but omit if zero - if lb != nil { - var w int64 - if n.Op == OSLICESTR { - w = 1 - } else { - w = n.Type.Type.Width - } - lb = conv(lb, Types[TUINTPTR]) - if w > 1 { - lb = Nod(OMUL, Nodintconst(w), lb) - } - typecheck(&lb, Erv) - walkexpr(&lb, init) - n.List = list(n.List, lb) - } - - // print("after sliceany: %+N\n", n); - - return n -} - func eqfor(t *Type, needsize *int) *Node { // Should only arrive here with large memory or // a struct/array containing a non-memory field/element. @@ -3611,7 +3381,7 @@ func samecheap(a *Node, b *Node) bool { case OINDEX: ar = a.Right br = b.Right - if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val.U.Xval, br.Val.U.Xval) != 0 { + if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val.U.(*Mpint), br.Val.U.(*Mpint)) != 0 { return false } } @@ -3647,9 +3417,9 @@ func walkrotate(np **Node) { w := int(l.Type.Width * 8) if Smallintconst(l.Right) && Smallintconst(r.Right) { - sl := int(Mpgetfix(l.Right.Val.U.Xval)) + sl := int(Mpgetfix(l.Right.Val.U.(*Mpint))) if sl >= 0 { - sr := int(Mpgetfix(r.Right.Val.U.Xval)) + sr := int(Mpgetfix(r.Right.Val.U.(*Mpint))) if sr >= 0 && sl+sr == w { // Rewrite left shift half to left rotate. if l.Op == OLSH { @@ -3660,7 +3430,7 @@ func walkrotate(np **Node) { n.Op = OLROT // Remove rotate 0 and rotate w. - s := int(Mpgetfix(n.Right.Val.U.Xval)) + s := int(Mpgetfix(n.Right.Val.U.(*Mpint))) if s == 0 || s == w { n = n.Left @@ -3703,7 +3473,7 @@ func walkmul(np **Node, init **NodeList) { // x*0 is 0 (and side effects of x). var pow int var w int - if Mpgetfix(nr.Val.U.Xval) == 0 { + if Mpgetfix(nr.Val.U.(*Mpint)) == 0 { cheapexpr(nl, init) Nodconst(n, n.Type, 0) goto ret @@ -3796,10 +3566,10 @@ func walkdiv(np **Node, init **NodeList) { m.W = w if Issigned[nl.Type.Etype] { - m.Sd = Mpgetfix(nr.Val.U.Xval) + m.Sd = Mpgetfix(nr.Val.U.(*Mpint)) Smagic(&m) } else { - m.Ud = uint64(Mpgetfix(nr.Val.U.Xval)) + m.Ud = uint64(Mpgetfix(nr.Val.U.(*Mpint))) Umagic(&m) } @@ -3993,7 +3763,7 @@ func walkdiv(np **Node, init **NodeList) { // n = nl & (nr-1) n.Op = OAND - Nodconst(nc, nl.Type, Mpgetfix(nr.Val.U.Xval)-1) + Nodconst(nc, nl.Type, Mpgetfix(nr.Val.U.(*Mpint))-1) } else { // n = nl >> pow n.Op = ORSH @@ -4023,7 +3793,7 @@ func bounded(n *Node, max int64) bool { bits := int32(8 * n.Type.Width) if Smallintconst(n) { - v := Mpgetfix(n.Val.U.Xval) + v := Mpgetfix(n.Val.U.(*Mpint)) return 0 <= v && v < max } @@ -4031,9 +3801,9 @@ func bounded(n *Node, max int64) bool { case OAND: v := int64(-1) if Smallintconst(n.Left) { - v = Mpgetfix(n.Left.Val.U.Xval) + v = Mpgetfix(n.Left.Val.U.(*Mpint)) } else if Smallintconst(n.Right) { - v = Mpgetfix(n.Right.Val.U.Xval) + v = Mpgetfix(n.Right.Val.U.(*Mpint)) } if 0 <= v && v < max { @@ -4042,7 +3812,7 @@ func bounded(n *Node, max int64) bool { case OMOD: if !sign && Smallintconst(n.Right) { - v := Mpgetfix(n.Right.Val.U.Xval) + v := Mpgetfix(n.Right.Val.U.(*Mpint)) if 0 <= v && v <= max { return true } @@ -4050,7 +3820,7 @@ func bounded(n *Node, max int64) bool { case ODIV: if !sign && Smallintconst(n.Right) { - v := Mpgetfix(n.Right.Val.U.Xval) + v := Mpgetfix(n.Right.Val.U.(*Mpint)) for bits > 0 && v >= 2 { bits-- v >>= 1 @@ -4059,7 +3829,7 @@ func bounded(n *Node, max int64) bool { case ORSH: if !sign && Smallintconst(n.Right) { - v := Mpgetfix(n.Right.Val.U.Xval) + v := Mpgetfix(n.Right.Val.U.(*Mpint)) if v > int64(bits) { return true } @@ -4192,17 +3962,17 @@ func candiscard(n *Node) bool { // Discardable as long as we know it's not division by zero. case ODIV, OMOD: - if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val.U.Xval, 0) != 0 { + if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val.U.(*Mpint), 0) != 0 { break } - if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val.U.Fval, 0) != 0 { + if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val.U.(*Mpflt), 0) != 0 { break } return false // Discardable as long as we know it won't fail because of a bad size. case OMAKECHAN, OMAKEMAP: - if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val.U.Xval, 0) == 0 { + if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val.U.(*Mpint), 0) == 0 { break } return false @@ -4256,7 +4026,7 @@ func walkprintfunc(np **Node, init **NodeList) { buf = fmt.Sprintf("print·%d", walkprintfunc_prgen) fn.Nname = newname(Lookup(buf)) fn.Nname.Defn = fn - fn.Nname.Ntype = t + fn.Nname.Param.Ntype = t declare(fn.Nname, PFUNC) oldfn := Curfn diff --git a/src/cmd/internal/gc/y.go b/src/cmd/compile/internal/gc/y.go index f2c8b96982..56b9d04ecb 100644 --- a/src/cmd/internal/gc/y.go +++ b/src/cmd/compile/internal/gc/y.go @@ -5,10 +5,11 @@ import __yyfmt__ "fmt" //line go.y:21 import ( + "fmt" "strings" ) -//line go.y:27 +//line go.y:28 type yySymType struct { yys int node *Node @@ -153,7 +154,7 @@ const yyEofCode = 1 const yyErrCode = 2 const yyMaxDepth = 200 -//line go.y:2242 +//line go.y:2304 func fixlbrace(lbr int) { // If the opening brace was an LBODY, // set up for another one now that we're done. @@ -856,6 +857,34 @@ var yyTok3 = [...]int{ 0, } +var yyErrorMessages = [...]struct { + state int + token int + msg string +}{ + {332, 76, "unexpected comma during import block"}, + {89, 63, "missing import path; require quoted string"}, + {390, 63, "missing { after if clause"}, + {387, 63, "missing { after switch clause"}, + {279, 63, "missing { after for clause"}, + {498, 36, "missing { after for clause"}, + {17, 68, "unexpected semicolon or newline before {"}, + {111, 63, "unexpected semicolon or newline in type declaration"}, + {78, 69, "unexpected } in channel type"}, + {78, 61, "unexpected ) in channel type"}, + {78, 76, "unexpected comma in channel type"}, + {416, 15, "unexpected semicolon or newline before else"}, + {329, 76, "name list not allowed in interface type"}, + {279, 33, "var declaration not allowed in for initializer"}, + {25, 68, "unexpected { at end of statement"}, + {371, 68, "unexpected { at end of statement"}, + {122, 63, "argument to go/defer must be function call"}, + {398, 63, "need trailing comma before newline in composite literal"}, + {414, 63, "need trailing comma before newline in composite literal"}, + {124, 25, "nested func not allowed"}, + {650, 63, "else must be followed by if or statement block"}, +} + //line yaccpar:1 /* parser for yacc output */ @@ -877,7 +906,6 @@ type yyParser interface { type yyParserImpl struct { lookahead func() int - state func() int } func (p *yyParserImpl) Lookahead() int { @@ -887,7 +915,6 @@ func (p *yyParserImpl) Lookahead() int { func yyNewParser() yyParser { p := &yyParserImpl{ lookahead: func() int { return -1 }, - state: func() int { return -1 }, } return p } @@ -918,6 +945,13 @@ func yyErrorMessage(state, lookAhead int) string { if !yyErrorVerbose { return "syntax error" } + + for _, e := range yyErrorMessages { + if e.state == state && e.token == lookAhead { + return "syntax error: " + e.msg + } + } + res := "syntax error: unexpected " + yyTokname(lookAhead) // To match Bison, suggest at most four expected tokens. @@ -1020,7 +1054,6 @@ func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int { yystate := 0 yychar := -1 yytoken := -1 // yychar translated into internal numbering - yyrcvr.state = func() int { return yystate } yyrcvr.lookahead = func() int { return yychar } defer func() { // Make sure we report no lookahead when not parsing. @@ -1187,13 +1220,13 @@ yydefault: case 1: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:127 + //line go.y:189 { xtop = concat(xtop, yyDollar[4].list) } case 2: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:133 + //line go.y:195 { prevlineno = lineno Yyerror("package statement must be first") @@ -1201,13 +1234,13 @@ yydefault: } case 3: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:139 + //line go.y:201 { mkpackage(yyDollar[2].sym.Name) } case 4: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:149 + //line go.y:211 { importpkg = Runtimepkg @@ -1220,13 +1253,13 @@ yydefault: } case 5: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:161 + //line go.y:223 { importpkg = nil } case 11: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:175 + //line go.y:237 { ipkg := importpkg my := importmyname @@ -1263,7 +1296,7 @@ yydefault: } case 12: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:210 + //line go.y:272 { // When an invalid import path is passed to importfile, // it calls Yyerror and then sets up a fake import with @@ -1275,7 +1308,7 @@ yydefault: } case 15: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:226 + //line go.y:288 { // import with original name yyVAL.i = parserline() @@ -1284,7 +1317,7 @@ yydefault: } case 16: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:233 + //line go.y:295 { // import with given name yyVAL.i = parserline() @@ -1293,7 +1326,7 @@ yydefault: } case 17: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:240 + //line go.y:302 { // import into my name space yyVAL.i = parserline() @@ -1302,7 +1335,7 @@ yydefault: } case 18: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:249 + //line go.y:311 { if importpkg.Name == "" { importpkg.Name = yyDollar[2].sym.Name @@ -1319,7 +1352,7 @@ yydefault: } case 20: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:266 + //line go.y:328 { if yyDollar[1].sym.Name == "safe" { curio.importsafe = true @@ -1327,64 +1360,64 @@ yydefault: } case 21: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:273 + //line go.y:335 { defercheckwidth() } case 22: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:277 + //line go.y:339 { resumecheckwidth() unimportfile() } case 23: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:286 + //line go.y:348 { Yyerror("empty top-level declaration") yyVAL.list = nil } case 25: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:292 + //line go.y:354 { yyVAL.list = list1(yyDollar[1].node) } case 26: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:296 + //line go.y:358 { Yyerror("non-declaration statement outside function body") yyVAL.list = nil } case 27: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:301 + //line go.y:363 { yyVAL.list = nil } case 28: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:307 + //line go.y:369 { yyVAL.list = yyDollar[2].list } case 29: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:311 + //line go.y:373 { yyVAL.list = yyDollar[3].list } case 30: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:315 + //line go.y:377 { yyVAL.list = nil } case 31: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:319 + //line go.y:381 { yyVAL.list = yyDollar[2].list iota_ = -100000 @@ -1392,7 +1425,7 @@ yydefault: } case 32: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:325 + //line go.y:387 { yyVAL.list = yyDollar[3].list iota_ = -100000 @@ -1400,7 +1433,7 @@ yydefault: } case 33: yyDollar = yyS[yypt-7 : yypt+1] - //line go.y:331 + //line go.y:393 { yyVAL.list = concat(yyDollar[3].list, yyDollar[5].list) iota_ = -100000 @@ -1408,80 +1441,80 @@ yydefault: } case 34: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:337 + //line go.y:399 { yyVAL.list = nil iota_ = -100000 } case 35: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:342 + //line go.y:404 { yyVAL.list = list1(yyDollar[2].node) } case 36: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:346 + //line go.y:408 { yyVAL.list = yyDollar[3].list } case 37: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:350 + //line go.y:412 { yyVAL.list = nil } case 38: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:356 + //line go.y:418 { iota_ = 0 } case 39: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:362 + //line go.y:424 { yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, nil) } case 40: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:366 + //line go.y:428 { yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list) } case 41: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:370 + //line go.y:432 { yyVAL.list = variter(yyDollar[1].list, nil, yyDollar[3].list) } case 42: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:376 + //line go.y:438 { yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list) } case 43: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:380 + //line go.y:442 { yyVAL.list = constiter(yyDollar[1].list, nil, yyDollar[3].list) } case 45: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:387 + //line go.y:449 { yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, nil) } case 46: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:391 + //line go.y:453 { yyVAL.list = constiter(yyDollar[1].list, nil, nil) } case 47: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:397 + //line go.y:459 { // different from dclname because the name // becomes visible right here, not at the end @@ -1490,13 +1523,13 @@ yydefault: } case 48: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:406 + //line go.y:468 { yyVAL.node = typedcl1(yyDollar[1].node, yyDollar[2].node, true) } case 49: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:412 + //line go.y:474 { yyVAL.node = yyDollar[1].node @@ -1512,14 +1545,14 @@ yydefault: } case 50: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:426 + //line go.y:488 { yyVAL.node = Nod(OASOP, yyDollar[1].node, yyDollar[3].node) yyVAL.node.Etype = uint8(yyDollar[2].i) // rathole to pass opcode } case 51: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:431 + //line go.y:493 { if yyDollar[1].list.Next == nil && yyDollar[3].list.Next == nil { // simple @@ -1533,7 +1566,7 @@ yydefault: } case 52: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:443 + //line go.y:505 { if yyDollar[3].list.N.Op == OTYPESW { yyVAL.node = Nod(OTYPESW, nil, yyDollar[3].list.N.Right) @@ -1553,7 +1586,7 @@ yydefault: } case 53: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:461 + //line go.y:523 { yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1)) yyVAL.node.Implicit = true @@ -1561,7 +1594,7 @@ yydefault: } case 54: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:467 + //line go.y:529 { yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1)) yyVAL.node.Implicit = true @@ -1569,7 +1602,7 @@ yydefault: } case 55: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:475 + //line go.y:537 { var n, nn *Node @@ -1594,7 +1627,7 @@ yydefault: } case 56: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:498 + //line go.y:560 { var n *Node @@ -1614,7 +1647,7 @@ yydefault: } case 57: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:516 + //line go.y:578 { // will be converted to OCASE // right will point to next case @@ -1625,7 +1658,7 @@ yydefault: } case 58: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:525 + //line go.y:587 { var n, nn *Node @@ -1646,13 +1679,13 @@ yydefault: } case 59: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:546 + //line go.y:608 { markdcl() } case 60: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:550 + //line go.y:612 { if yyDollar[3].list == nil { yyVAL.node = Nod(OEMPTY, nil, nil) @@ -1663,7 +1696,7 @@ yydefault: } case 61: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:561 + //line go.y:623 { // If the last token read by the lexer was consumed // as part of the case, clear it (parser has cleared yychar). @@ -1676,7 +1709,7 @@ yydefault: } case 62: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:572 + //line go.y:634 { // This is the only place in the language where a statement // list is not allowed to drop the final semicolon, because @@ -1696,32 +1729,32 @@ yydefault: } case 63: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:591 + //line go.y:653 { yyVAL.list = nil } case 64: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:595 + //line go.y:657 { yyVAL.list = list(yyDollar[1].list, yyDollar[2].node) } case 65: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:601 + //line go.y:663 { markdcl() } case 66: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:605 + //line go.y:667 { yyVAL.list = yyDollar[3].list popdcl() } case 67: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:612 + //line go.y:674 { yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node) yyVAL.node.List = yyDollar[1].list @@ -1729,7 +1762,7 @@ yydefault: } case 68: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:618 + //line go.y:680 { yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node) yyVAL.node.List = yyDollar[1].list @@ -1738,14 +1771,14 @@ yydefault: } case 69: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:625 + //line go.y:687 { yyVAL.node = Nod(ORANGE, nil, yyDollar[2].node) yyVAL.node.Etype = 0 // := flag } case 70: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:632 + //line go.y:694 { // init ; test ; incr if yyDollar[5].node != nil && yyDollar[5].node.Colas { @@ -1760,7 +1793,7 @@ yydefault: } case 71: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:645 + //line go.y:707 { // normal test yyVAL.node = Nod(OFOR, nil, nil) @@ -1768,27 +1801,27 @@ yydefault: } case 73: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:654 + //line go.y:716 { yyVAL.node = yyDollar[1].node yyVAL.node.Nbody = concat(yyVAL.node.Nbody, yyDollar[2].list) } case 74: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:661 + //line go.y:723 { markdcl() } case 75: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:665 + //line go.y:727 { yyVAL.node = yyDollar[3].node popdcl() } case 76: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:672 + //line go.y:734 { // test yyVAL.node = Nod(OIF, nil, nil) @@ -1796,7 +1829,7 @@ yydefault: } case 77: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:678 + //line go.y:740 { // init ; test yyVAL.node = Nod(OIF, nil, nil) @@ -1807,13 +1840,13 @@ yydefault: } case 78: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:690 + //line go.y:752 { markdcl() } case 79: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:694 + //line go.y:756 { if yyDollar[3].node.Ntest == nil { Yyerror("missing condition in if statement") @@ -1821,13 +1854,13 @@ yydefault: } case 80: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:700 + //line go.y:762 { yyDollar[3].node.Nbody = yyDollar[5].list } case 81: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:704 + //line go.y:766 { var n *Node var nn *NodeList @@ -1845,13 +1878,13 @@ yydefault: } case 82: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:722 + //line go.y:784 { markdcl() } case 83: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:726 + //line go.y:788 { if yyDollar[4].node.Ntest == nil { Yyerror("missing condition in if statement") @@ -1861,25 +1894,25 @@ yydefault: } case 84: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:735 + //line go.y:797 { yyVAL.list = nil } case 85: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:739 + //line go.y:801 { yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list) } case 86: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:744 + //line go.y:806 { yyVAL.list = nil } case 87: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:748 + //line go.y:810 { l := &NodeList{N: yyDollar[2].node} l.End = l @@ -1887,13 +1920,13 @@ yydefault: } case 88: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:756 + //line go.y:818 { markdcl() } case 89: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:760 + //line go.y:822 { var n *Node n = yyDollar[3].node.Ntest @@ -1904,7 +1937,7 @@ yydefault: } case 90: yyDollar = yyS[yypt-7 : yypt+1] - //line go.y:769 + //line go.y:831 { yyVAL.node = yyDollar[3].node yyVAL.node.Op = OSWITCH @@ -1914,13 +1947,13 @@ yydefault: } case 91: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:779 + //line go.y:841 { typesw = Nod(OXXX, typesw, nil) } case 92: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:783 + //line go.y:845 { yyVAL.node = Nod(OSELECT, nil, nil) yyVAL.node.Lineno = typesw.Lineno @@ -1929,133 +1962,133 @@ yydefault: } case 94: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:796 + //line go.y:858 { yyVAL.node = Nod(OOROR, yyDollar[1].node, yyDollar[3].node) } case 95: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:800 + //line go.y:862 { yyVAL.node = Nod(OANDAND, yyDollar[1].node, yyDollar[3].node) } case 96: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:804 + //line go.y:866 { yyVAL.node = Nod(OEQ, yyDollar[1].node, yyDollar[3].node) } case 97: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:808 + //line go.y:870 { yyVAL.node = Nod(ONE, yyDollar[1].node, yyDollar[3].node) } case 98: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:812 + //line go.y:874 { yyVAL.node = Nod(OLT, yyDollar[1].node, yyDollar[3].node) } case 99: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:816 + //line go.y:878 { yyVAL.node = Nod(OLE, yyDollar[1].node, yyDollar[3].node) } case 100: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:820 + //line go.y:882 { yyVAL.node = Nod(OGE, yyDollar[1].node, yyDollar[3].node) } case 101: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:824 + //line go.y:886 { yyVAL.node = Nod(OGT, yyDollar[1].node, yyDollar[3].node) } case 102: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:828 + //line go.y:890 { yyVAL.node = Nod(OADD, yyDollar[1].node, yyDollar[3].node) } case 103: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:832 + //line go.y:894 { yyVAL.node = Nod(OSUB, yyDollar[1].node, yyDollar[3].node) } case 104: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:836 + //line go.y:898 { yyVAL.node = Nod(OOR, yyDollar[1].node, yyDollar[3].node) } case 105: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:840 + //line go.y:902 { yyVAL.node = Nod(OXOR, yyDollar[1].node, yyDollar[3].node) } case 106: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:844 + //line go.y:906 { yyVAL.node = Nod(OMUL, yyDollar[1].node, yyDollar[3].node) } case 107: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:848 + //line go.y:910 { yyVAL.node = Nod(ODIV, yyDollar[1].node, yyDollar[3].node) } case 108: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:852 + //line go.y:914 { yyVAL.node = Nod(OMOD, yyDollar[1].node, yyDollar[3].node) } case 109: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:856 + //line go.y:918 { yyVAL.node = Nod(OAND, yyDollar[1].node, yyDollar[3].node) } case 110: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:860 + //line go.y:922 { yyVAL.node = Nod(OANDNOT, yyDollar[1].node, yyDollar[3].node) } case 111: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:864 + //line go.y:926 { yyVAL.node = Nod(OLSH, yyDollar[1].node, yyDollar[3].node) } case 112: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:868 + //line go.y:930 { yyVAL.node = Nod(ORSH, yyDollar[1].node, yyDollar[3].node) } case 113: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:873 + //line go.y:935 { yyVAL.node = Nod(OSEND, yyDollar[1].node, yyDollar[3].node) } case 115: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:880 + //line go.y:942 { yyVAL.node = Nod(OIND, yyDollar[2].node, nil) } case 116: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:884 + //line go.y:946 { if yyDollar[2].node.Op == OCOMPLIT { // Special case for &T{...}: turn into (*T){...}. @@ -2068,57 +2101,57 @@ yydefault: } case 117: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:895 + //line go.y:957 { yyVAL.node = Nod(OPLUS, yyDollar[2].node, nil) } case 118: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:899 + //line go.y:961 { yyVAL.node = Nod(OMINUS, yyDollar[2].node, nil) } case 119: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:903 + //line go.y:965 { yyVAL.node = Nod(ONOT, yyDollar[2].node, nil) } case 120: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:907 + //line go.y:969 { Yyerror("the bitwise complement operator is ^") yyVAL.node = Nod(OCOM, yyDollar[2].node, nil) } case 121: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:912 + //line go.y:974 { yyVAL.node = Nod(OCOM, yyDollar[2].node, nil) } case 122: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:916 + //line go.y:978 { yyVAL.node = Nod(ORECV, yyDollar[2].node, nil) } case 123: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:926 + //line go.y:988 { yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) } case 124: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:930 + //line go.y:992 { yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) yyVAL.node.List = yyDollar[3].list } case 125: yyDollar = yyS[yypt-6 : yypt+1] - //line go.y:935 + //line go.y:997 { yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) yyVAL.node.List = yyDollar[3].list @@ -2126,13 +2159,13 @@ yydefault: } case 126: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:943 + //line go.y:1005 { yyVAL.node = nodlit(yyDollar[1].val) } case 128: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:948 + //line go.y:1010 { if yyDollar[1].node.Op == OPACK { var s *Sym @@ -2145,31 +2178,31 @@ yydefault: } case 129: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:959 + //line go.y:1021 { yyVAL.node = Nod(ODOTTYPE, yyDollar[1].node, yyDollar[4].node) } case 130: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:963 + //line go.y:1025 { yyVAL.node = Nod(OTYPESW, nil, yyDollar[1].node) } case 131: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:967 + //line go.y:1029 { yyVAL.node = Nod(OINDEX, yyDollar[1].node, yyDollar[3].node) } case 132: yyDollar = yyS[yypt-6 : yypt+1] - //line go.y:971 + //line go.y:1033 { yyVAL.node = Nod(OSLICE, yyDollar[1].node, Nod(OKEY, yyDollar[3].node, yyDollar[5].node)) } case 133: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:975 + //line go.y:1037 { if yyDollar[5].node == nil { Yyerror("middle index required in 3-index slice") @@ -2181,7 +2214,7 @@ yydefault: } case 135: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:986 + //line go.y:1048 { // conversion yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) @@ -2189,7 +2222,7 @@ yydefault: } case 136: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:992 + //line go.y:1054 { yyVAL.node = yyDollar[3].node yyVAL.node.Right = yyDollar[1].node @@ -2198,7 +2231,7 @@ yydefault: } case 137: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:999 + //line go.y:1061 { yyVAL.node = yyDollar[3].node yyVAL.node.Right = yyDollar[1].node @@ -2206,7 +2239,7 @@ yydefault: } case 138: yyDollar = yyS[yypt-7 : yypt+1] - //line go.y:1005 + //line go.y:1067 { Yyerror("cannot parenthesize type in composite literal") yyVAL.node = yyDollar[5].node @@ -2215,7 +2248,7 @@ yydefault: } case 140: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1014 + //line go.y:1076 { // composite expression. // make node early so we get the right line number. @@ -2223,13 +2256,13 @@ yydefault: } case 141: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1022 + //line go.y:1084 { yyVAL.node = Nod(OKEY, yyDollar[1].node, yyDollar[3].node) } case 142: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1028 + //line go.y:1090 { // These nodes do not carry line numbers. // Since a composite literal commonly spans several lines, @@ -2244,21 +2277,21 @@ yydefault: } case 143: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1041 + //line go.y:1103 { yyVAL.node = yyDollar[2].node yyVAL.node.List = yyDollar[3].list } case 145: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1049 + //line go.y:1111 { yyVAL.node = yyDollar[2].node yyVAL.node.List = yyDollar[3].list } case 147: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1057 + //line go.y:1119 { yyVAL.node = yyDollar[2].node @@ -2272,19 +2305,19 @@ yydefault: } case 151: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1078 + //line go.y:1140 { yyVAL.i = LBODY } case 152: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1082 + //line go.y:1144 { yyVAL.i = '{' } case 153: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1093 + //line go.y:1155 { if yyDollar[1].sym == nil { yyVAL.node = nil @@ -2294,19 +2327,19 @@ yydefault: } case 154: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1103 + //line go.y:1165 { yyVAL.node = dclname(yyDollar[1].sym) } case 155: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1108 + //line go.y:1170 { yyVAL.node = nil } case 157: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1115 + //line go.y:1177 { yyVAL.sym = yyDollar[1].sym // during imports, unqualified non-exported identifiers are from builtinpkg @@ -2316,45 +2349,45 @@ yydefault: } case 159: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1124 + //line go.y:1186 { yyVAL.sym = nil } case 160: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1130 + //line go.y:1192 { var p *Pkg - if yyDollar[2].val.U.Sval == "" { + if yyDollar[2].val.U.(string) == "" { p = importpkg } else { - if isbadimport(yyDollar[2].val.U.Sval) { + if isbadimport(yyDollar[2].val.U.(string)) { errorexit() } - p = mkpkg(yyDollar[2].val.U.Sval) + p = mkpkg(yyDollar[2].val.U.(string)) } yyVAL.sym = Pkglookup(yyDollar[4].sym.Name, p) } case 161: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1144 + //line go.y:1206 { var p *Pkg - if yyDollar[2].val.U.Sval == "" { + if yyDollar[2].val.U.(string) == "" { p = importpkg } else { - if isbadimport(yyDollar[2].val.U.Sval) { + if isbadimport(yyDollar[2].val.U.(string)) { errorexit() } - p = mkpkg(yyDollar[2].val.U.Sval) + p = mkpkg(yyDollar[2].val.U.(string)) } yyVAL.sym = Pkglookup("?", p) } case 162: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1160 + //line go.y:1222 { yyVAL.node = oldname(yyDollar[1].sym) if yyVAL.node.Pack != nil { @@ -2363,38 +2396,38 @@ yydefault: } case 164: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1181 + //line go.y:1243 { Yyerror("final argument in variadic function missing type") yyVAL.node = Nod(ODDD, typenod(typ(TINTER)), nil) } case 165: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1186 + //line go.y:1248 { yyVAL.node = Nod(ODDD, yyDollar[2].node, nil) } case 171: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1197 + //line go.y:1259 { yyVAL.node = yyDollar[2].node } case 175: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1206 + //line go.y:1268 { yyVAL.node = Nod(OIND, yyDollar[2].node, nil) } case 180: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1216 + //line go.y:1278 { yyVAL.node = yyDollar[2].node } case 190: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1237 + //line go.y:1299 { if yyDollar[1].node.Op == OPACK { var s *Sym @@ -2407,53 +2440,53 @@ yydefault: } case 191: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1250 + //line go.y:1312 { yyVAL.node = Nod(OTARRAY, yyDollar[2].node, yyDollar[4].node) } case 192: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1254 + //line go.y:1316 { // array literal of nelem yyVAL.node = Nod(OTARRAY, Nod(ODDD, nil, nil), yyDollar[4].node) } case 193: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1259 + //line go.y:1321 { yyVAL.node = Nod(OTCHAN, yyDollar[2].node, nil) yyVAL.node.Etype = Cboth } case 194: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1264 + //line go.y:1326 { yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil) yyVAL.node.Etype = Csend } case 195: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1269 + //line go.y:1331 { yyVAL.node = Nod(OTMAP, yyDollar[3].node, yyDollar[5].node) } case 198: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1277 + //line go.y:1339 { yyVAL.node = Nod(OIND, yyDollar[2].node, nil) } case 199: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1283 + //line go.y:1345 { yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil) yyVAL.node.Etype = Crecv } case 200: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1290 + //line go.y:1352 { yyVAL.node = Nod(OTSTRUCT, nil, nil) yyVAL.node.List = yyDollar[3].list @@ -2461,14 +2494,14 @@ yydefault: } case 201: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1296 + //line go.y:1358 { yyVAL.node = Nod(OTSTRUCT, nil, nil) fixlbrace(yyDollar[2].i) } case 202: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1303 + //line go.y:1365 { yyVAL.node = Nod(OTINTER, nil, nil) yyVAL.node.List = yyDollar[3].list @@ -2476,14 +2509,14 @@ yydefault: } case 203: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1309 + //line go.y:1371 { yyVAL.node = Nod(OTINTER, nil, nil) fixlbrace(yyDollar[2].i) } case 204: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1320 + //line go.y:1382 { yyVAL.node = yyDollar[2].node if yyVAL.node == nil { @@ -2501,7 +2534,7 @@ yydefault: } case 205: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1338 + //line go.y:1400 { var t *Node @@ -2527,14 +2560,14 @@ yydefault: yyVAL.node = Nod(ODCLFUNC, nil, nil) yyVAL.node.Nname = newfuncname(yyDollar[1].sym) yyVAL.node.Nname.Defn = yyVAL.node - yyVAL.node.Nname.Ntype = t // TODO: check if nname already has an ntype + yyVAL.node.Nname.Param.Ntype = t // TODO: check if nname already has an ntype declare(yyVAL.node.Nname, PFUNC) funchdr(yyVAL.node) } case 206: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:1369 + //line go.y:1431 { var rcvr, t *Node @@ -2564,7 +2597,7 @@ yydefault: yyVAL.node.Func.Shortname = newfuncname(yyDollar[4].sym) yyVAL.node.Nname = methodname1(yyVAL.node.Func.Shortname, rcvr.Right) yyVAL.node.Nname.Defn = yyVAL.node - yyVAL.node.Nname.Ntype = t + yyVAL.node.Nname.Param.Ntype = t yyVAL.node.Nname.Nointerface = nointerface declare(yyVAL.node.Nname, PFUNC) @@ -2572,7 +2605,7 @@ yydefault: } case 207: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1407 + //line go.y:1469 { var s *Sym var t *Type @@ -2599,7 +2632,7 @@ yydefault: } case 208: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:1432 + //line go.y:1494 { yyVAL.node = methodname1(newname(yyDollar[4].sym), yyDollar[2].list.N.Right) yyVAL.node.Type = functype(yyDollar[2].list.N, yyDollar[6].list, yyDollar[8].list) @@ -2617,7 +2650,7 @@ yydefault: } case 209: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1450 + //line go.y:1512 { yyDollar[3].list = checkarglist(yyDollar[3].list, 1) yyVAL.node = Nod(OTFUNC, nil, nil) @@ -2626,13 +2659,13 @@ yydefault: } case 210: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1458 + //line go.y:1520 { yyVAL.list = nil } case 211: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1462 + //line go.y:1524 { yyVAL.list = yyDollar[2].list if yyVAL.list == nil { @@ -2641,51 +2674,51 @@ yydefault: } case 212: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1471 + //line go.y:1533 { yyVAL.list = nil } case 213: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1475 + //line go.y:1537 { yyVAL.list = list1(Nod(ODCLFIELD, nil, yyDollar[1].node)) } case 214: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1479 + //line go.y:1541 { yyDollar[2].list = checkarglist(yyDollar[2].list, 0) yyVAL.list = yyDollar[2].list } case 215: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1486 + //line go.y:1548 { closurehdr(yyDollar[1].node) } case 216: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1492 + //line go.y:1554 { yyVAL.node = closurebody(yyDollar[3].list) fixlbrace(yyDollar[2].i) } case 217: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1497 + //line go.y:1559 { yyVAL.node = closurebody(nil) } case 218: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1508 + //line go.y:1570 { yyVAL.list = nil } case 219: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1512 + //line go.y:1574 { yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list) if nsyntaxerrors == 0 { @@ -2698,49 +2731,49 @@ yydefault: } case 221: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1526 + //line go.y:1588 { yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list) } case 223: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1533 + //line go.y:1595 { yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list) } case 224: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1539 + //line go.y:1601 { yyVAL.list = list1(yyDollar[1].node) } case 225: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1543 + //line go.y:1605 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 227: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1550 + //line go.y:1612 { yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list) } case 228: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1556 + //line go.y:1618 { yyVAL.list = list1(yyDollar[1].node) } case 229: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1560 + //line go.y:1622 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 230: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1566 + //line go.y:1628 { var l *NodeList @@ -2766,14 +2799,14 @@ yydefault: } case 231: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1590 + //line go.y:1652 { yyDollar[1].node.Val = yyDollar[2].val yyVAL.list = list1(yyDollar[1].node) } case 232: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1595 + //line go.y:1657 { yyDollar[2].node.Val = yyDollar[4].val yyVAL.list = list1(yyDollar[2].node) @@ -2781,7 +2814,7 @@ yydefault: } case 233: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1601 + //line go.y:1663 { yyDollar[2].node.Right = Nod(OIND, yyDollar[2].node.Right, nil) yyDollar[2].node.Val = yyDollar[3].val @@ -2789,7 +2822,7 @@ yydefault: } case 234: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1607 + //line go.y:1669 { yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil) yyDollar[3].node.Val = yyDollar[5].val @@ -2798,7 +2831,7 @@ yydefault: } case 235: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1614 + //line go.y:1676 { yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil) yyDollar[3].node.Val = yyDollar[5].val @@ -2807,7 +2840,7 @@ yydefault: } case 236: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1623 + //line go.y:1685 { var n *Node @@ -2819,7 +2852,7 @@ yydefault: } case 237: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1633 + //line go.y:1695 { var pkg *Pkg @@ -2834,33 +2867,33 @@ yydefault: } case 238: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1648 + //line go.y:1710 { yyVAL.node = embedded(yyDollar[1].sym, localpkg) } case 239: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1654 + //line go.y:1716 { yyVAL.node = Nod(ODCLFIELD, yyDollar[1].node, yyDollar[2].node) ifacedcl(yyVAL.node) } case 240: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1659 + //line go.y:1721 { yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[1].sym)) } case 241: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1663 + //line go.y:1725 { yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[2].sym)) Yyerror("cannot parenthesize embedded type") } case 242: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1670 + //line go.y:1732 { // without func keyword yyDollar[2].list = checkarglist(yyDollar[2].list, 1) @@ -2870,7 +2903,7 @@ yydefault: } case 244: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1684 + //line go.y:1746 { yyVAL.node = Nod(ONONAME, nil, nil) yyVAL.node.Sym = yyDollar[1].sym @@ -2878,7 +2911,7 @@ yydefault: } case 245: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1690 + //line go.y:1752 { yyVAL.node = Nod(ONONAME, nil, nil) yyVAL.node.Sym = yyDollar[1].sym @@ -2886,56 +2919,56 @@ yydefault: } case 247: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1699 + //line go.y:1761 { yyVAL.list = list1(yyDollar[1].node) } case 248: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1703 + //line go.y:1765 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 249: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1708 + //line go.y:1770 { yyVAL.list = nil } case 250: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1712 + //line go.y:1774 { yyVAL.list = yyDollar[1].list } case 251: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1720 + //line go.y:1782 { yyVAL.node = nil } case 253: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1725 + //line go.y:1787 { yyVAL.node = liststmt(yyDollar[1].list) } case 255: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1730 + //line go.y:1792 { yyVAL.node = nil } case 261: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1741 + //line go.y:1803 { yyDollar[1].node = Nod(OLABEL, yyDollar[1].node, nil) yyDollar[1].node.Sym = dclstack // context, for goto restrictions } case 262: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1746 + //line go.y:1808 { var l *NodeList @@ -2948,7 +2981,7 @@ yydefault: } case 263: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1757 + //line go.y:1819 { // will be converted to OFALL yyVAL.node = Nod(OXFALL, nil, nil) @@ -2956,38 +2989,38 @@ yydefault: } case 264: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1763 + //line go.y:1825 { yyVAL.node = Nod(OBREAK, yyDollar[2].node, nil) } case 265: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1767 + //line go.y:1829 { yyVAL.node = Nod(OCONTINUE, yyDollar[2].node, nil) } case 266: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1771 + //line go.y:1833 { yyVAL.node = Nod(OPROC, yyDollar[2].node, nil) } case 267: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1775 + //line go.y:1837 { yyVAL.node = Nod(ODEFER, yyDollar[2].node, nil) } case 268: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1779 + //line go.y:1841 { yyVAL.node = Nod(OGOTO, yyDollar[2].node, nil) yyVAL.node.Sym = dclstack // context, for goto restrictions } case 269: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1784 + //line go.y:1846 { yyVAL.node = Nod(ORETURN, nil, nil) yyVAL.node.List = yyDollar[2].list @@ -3009,7 +3042,7 @@ yydefault: } case 270: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1806 + //line go.y:1868 { yyVAL.list = nil if yyDollar[1].node != nil { @@ -3018,7 +3051,7 @@ yydefault: } case 271: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1813 + //line go.y:1875 { yyVAL.list = yyDollar[1].list if yyDollar[3].node != nil { @@ -3027,163 +3060,163 @@ yydefault: } case 272: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1822 + //line go.y:1884 { yyVAL.list = list1(yyDollar[1].node) } case 273: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1826 + //line go.y:1888 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 274: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1832 + //line go.y:1894 { yyVAL.list = list1(yyDollar[1].node) } case 275: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1836 + //line go.y:1898 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 276: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1842 + //line go.y:1904 { yyVAL.list = list1(yyDollar[1].node) } case 277: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1846 + //line go.y:1908 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 278: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1852 + //line go.y:1914 { yyVAL.list = list1(yyDollar[1].node) } case 279: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1856 + //line go.y:1918 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 280: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1865 + //line go.y:1927 { yyVAL.list = list1(yyDollar[1].node) } case 281: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1869 + //line go.y:1931 { yyVAL.list = list1(yyDollar[1].node) } case 282: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1873 + //line go.y:1935 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 283: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1877 + //line go.y:1939 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 284: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1882 + //line go.y:1944 { yyVAL.list = nil } case 285: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1886 + //line go.y:1948 { yyVAL.list = yyDollar[1].list } case 290: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1900 + //line go.y:1962 { yyVAL.node = nil } case 292: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1906 + //line go.y:1968 { yyVAL.list = nil } case 294: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1912 + //line go.y:1974 { yyVAL.node = nil } case 296: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1918 + //line go.y:1980 { yyVAL.list = nil } case 298: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1924 + //line go.y:1986 { yyVAL.list = nil } case 300: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1930 + //line go.y:1992 { yyVAL.list = nil } case 302: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1936 + //line go.y:1998 { yyVAL.val.Ctype = CTxxx } case 304: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1946 + //line go.y:2008 { - importimport(yyDollar[2].sym, yyDollar[3].val.U.Sval) + importimport(yyDollar[2].sym, yyDollar[3].val.U.(string)) } case 305: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1950 + //line go.y:2012 { importvar(yyDollar[2].sym, yyDollar[3].typ) } case 306: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1954 + //line go.y:2016 { importconst(yyDollar[2].sym, Types[TIDEAL], yyDollar[4].node) } case 307: yyDollar = yyS[yypt-6 : yypt+1] - //line go.y:1958 + //line go.y:2020 { importconst(yyDollar[2].sym, yyDollar[3].typ, yyDollar[5].node) } case 308: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1962 + //line go.y:2024 { importtype(yyDollar[2].typ, yyDollar[3].typ) } case 309: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1966 + //line go.y:2028 { if yyDollar[2].node == nil { dclcontext = PEXTERN // since we skip the funcbody below @@ -3196,35 +3229,35 @@ yydefault: importlist = list(importlist, yyDollar[2].node) if Debug['E'] > 0 { - print("import [%q] func %lN \n", importpkg.Path, yyDollar[2].node) + fmt.Printf("import [%q] func %v \n", importpkg.Path, yyDollar[2].node) if Debug['m'] > 2 && yyDollar[2].node.Func.Inl != nil { - print("inl body:%+H\n", yyDollar[2].node.Func.Inl) + fmt.Printf("inl body:%v\n", yyDollar[2].node.Func.Inl) } } } case 310: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1987 + //line go.y:2049 { yyVAL.sym = yyDollar[1].sym structpkg = yyVAL.sym.Pkg } case 311: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1994 + //line go.y:2056 { yyVAL.typ = pkgtype(yyDollar[1].sym) importsym(yyDollar[1].sym, OTYPE) } case 317: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2014 + //line go.y:2076 { yyVAL.typ = pkgtype(yyDollar[1].sym) } case 318: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2018 + //line go.y:2080 { // predefined name like uint8 yyDollar[1].sym = Pkglookup(yyDollar[1].sym.Name, builtinpkg) @@ -3237,43 +3270,43 @@ yydefault: } case 319: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2029 + //line go.y:2091 { yyVAL.typ = aindex(nil, yyDollar[3].typ) } case 320: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2033 + //line go.y:2095 { yyVAL.typ = aindex(nodlit(yyDollar[2].val), yyDollar[4].typ) } case 321: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2037 + //line go.y:2099 { yyVAL.typ = maptype(yyDollar[3].typ, yyDollar[5].typ) } case 322: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2041 + //line go.y:2103 { yyVAL.typ = tostruct(yyDollar[3].list) } case 323: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2045 + //line go.y:2107 { yyVAL.typ = tointerface(yyDollar[3].list) } case 324: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:2049 + //line go.y:2111 { yyVAL.typ = Ptrto(yyDollar[2].typ) } case 325: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:2053 + //line go.y:2115 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[2].typ @@ -3281,7 +3314,7 @@ yydefault: } case 326: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2059 + //line go.y:2121 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[3].typ @@ -3289,7 +3322,7 @@ yydefault: } case 327: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2065 + //line go.y:2127 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[3].typ @@ -3297,7 +3330,7 @@ yydefault: } case 328: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2073 + //line go.y:2135 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[3].typ @@ -3305,13 +3338,13 @@ yydefault: } case 329: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2081 + //line go.y:2143 { yyVAL.typ = functype(nil, yyDollar[3].list, yyDollar[5].list) } case 330: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2087 + //line go.y:2149 { yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[2].typ)) if yyDollar[1].sym != nil { @@ -3321,7 +3354,7 @@ yydefault: } case 331: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2095 + //line go.y:2157 { var t *Type @@ -3338,7 +3371,7 @@ yydefault: } case 332: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2112 + //line go.y:2174 { var s *Sym var p *Pkg @@ -3362,55 +3395,55 @@ yydefault: } case 333: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2136 + //line go.y:2198 { yyVAL.node = Nod(ODCLFIELD, newname(yyDollar[1].sym), typenod(functype(fakethis(), yyDollar[3].list, yyDollar[5].list))) } case 334: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2140 + //line go.y:2202 { yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ)) } case 335: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:2145 + //line go.y:2207 { yyVAL.list = nil } case 337: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2152 + //line go.y:2214 { yyVAL.list = yyDollar[2].list } case 338: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2156 + //line go.y:2218 { yyVAL.list = list1(Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ))) } case 339: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2166 + //line go.y:2228 { yyVAL.node = nodlit(yyDollar[1].val) } case 340: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:2170 + //line go.y:2232 { yyVAL.node = nodlit(yyDollar[2].val) switch yyVAL.node.Val.Ctype { case CTINT, CTRUNE: - mpnegfix(yyVAL.node.Val.U.Xval) + mpnegfix(yyVAL.node.Val.U.(*Mpint)) break case CTFLT: - mpnegflt(yyVAL.node.Val.U.Fval) + mpnegflt(yyVAL.node.Val.U.(*Mpflt)) break case CTCPLX: - mpnegflt(&yyVAL.node.Val.U.Cval.Real) - mpnegflt(&yyVAL.node.Val.U.Cval.Imag) + mpnegflt(&yyVAL.node.Val.U.(*Mpcplx).Real) + mpnegflt(&yyVAL.node.Val.U.(*Mpcplx).Imag) break default: Yyerror("bad negated constant") @@ -3418,7 +3451,7 @@ yydefault: } case 341: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2188 + //line go.y:2250 { yyVAL.node = oldname(Pkglookup(yyDollar[1].sym.Name, builtinpkg)) if yyVAL.node.Op != OLITERAL { @@ -3427,50 +3460,50 @@ yydefault: } case 343: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2198 + //line go.y:2260 { if yyDollar[2].node.Val.Ctype == CTRUNE && yyDollar[4].node.Val.Ctype == CTINT { yyVAL.node = yyDollar[2].node - mpaddfixfix(yyDollar[2].node.Val.U.Xval, yyDollar[4].node.Val.U.Xval, 0) + mpaddfixfix(yyDollar[2].node.Val.U.(*Mpint), yyDollar[4].node.Val.U.(*Mpint), 0) break } - yyDollar[4].node.Val.U.Cval.Real = yyDollar[4].node.Val.U.Cval.Imag - Mpmovecflt(&yyDollar[4].node.Val.U.Cval.Imag, 0.0) + yyDollar[4].node.Val.U.(*Mpcplx).Real = yyDollar[4].node.Val.U.(*Mpcplx).Imag + Mpmovecflt(&yyDollar[4].node.Val.U.(*Mpcplx).Imag, 0.0) yyVAL.node = nodcplxlit(yyDollar[2].node.Val, yyDollar[4].node.Val) } case 346: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2214 + //line go.y:2276 { yyVAL.list = list1(yyDollar[1].node) } case 347: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2218 + //line go.y:2280 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 348: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2224 + //line go.y:2286 { yyVAL.list = list1(yyDollar[1].node) } case 349: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2228 + //line go.y:2290 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 350: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2234 + //line go.y:2296 { yyVAL.list = list1(yyDollar[1].node) } case 351: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2238 + //line go.y:2300 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } diff --git a/src/cmd/internal/gc/y.output b/src/cmd/compile/internal/gc/y.output index e4a5e5c212..2821702aea 100644 --- a/src/cmd/internal/gc/y.output +++ b/src/cmd/compile/internal/gc/y.output @@ -3,7 +3,7 @@ state 0 $accept: .file $end $$4: . (4) - . reduce 4 (src line 148) + . reduce 4 (src line 210) file goto 1 loadsys goto 2 @@ -21,7 +21,7 @@ state 2 package: . (2) LPACKAGE shift 5 - . reduce 2 (src line 131) + . reduce 2 (src line 193) package goto 4 @@ -37,7 +37,7 @@ state 4 file: loadsys package.imports xdcl_list imports: . (6) - . reduce 6 (src line 165) + . reduce 6 (src line 227) imports goto 8 @@ -56,7 +56,7 @@ state 6 loadsys: $$4 import_package.import_there $$21: . (21) - . reduce 21 (src line 272) + . reduce 21 (src line 334) import_there goto 14 $$21 goto 15 @@ -74,7 +74,7 @@ state 8 xdcl_list: . (218) LIMPORT shift 19 - . reduce 218 (src line 1507) + . reduce 218 (src line 1569) xdcl_list goto 17 import goto 18 @@ -89,19 +89,19 @@ state 9 state 10 sym: LNAME. (157) - . reduce 157 (src line 1113) + . reduce 157 (src line 1175) state 11 sym: hidden_importsym. (158) - . reduce 158 (src line 1122) + . reduce 158 (src line 1184) state 12 sym: '?'. (159) - . reduce 159 (src line 1123) + . reduce 159 (src line 1185) state 13 @@ -115,14 +115,14 @@ state 13 state 14 loadsys: $$4 import_package import_there. (5) - . reduce 5 (src line 159) + . reduce 5 (src line 221) state 15 import_there: $$21.hidden_import_list '$' '$' hidden_import_list: . (344) - . reduce 344 (src line 2209) + . reduce 344 (src line 2271) hidden_import_list goto 22 @@ -131,7 +131,7 @@ state 16 import_safety: . (19) LNAME shift 24 - . reduce 19 (src line 264) + . reduce 19 (src line 326) import_safety goto 23 @@ -140,7 +140,7 @@ state 17 xdcl_list: xdcl_list.xdcl ';' xdcl: . (23) - $end reduce 1 (src line 122) + $end reduce 1 (src line 184) error shift 29 LLITERAL shift 68 LBREAK shift 41 @@ -170,7 +170,7 @@ state 17 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 23 (src line 285) + ';' reduce 23 (src line 347) '!' shift 62 '~' shift 63 '[' shift 77 @@ -236,7 +236,7 @@ state 19 state 20 package: LPACKAGE sym ';'. (3) - . reduce 3 (src line 138) + . reduce 3 (src line 200) state 21 @@ -271,7 +271,7 @@ state 23 state 24 import_safety: LNAME. (20) - . reduce 20 (src line 265) + . reduce 20 (src line 327) state 25 @@ -284,25 +284,25 @@ state 25 state 26 xdcl: common_dcl. (24) - . reduce 24 (src line 290) + . reduce 24 (src line 352) state 27 xdcl: xfndcl. (25) - . reduce 25 (src line 291) + . reduce 25 (src line 353) state 28 xdcl: non_dcl_stmt. (26) - . reduce 26 (src line 295) + . reduce 26 (src line 357) state 29 xdcl: error. (27) - . reduce 27 (src line 300) + . reduce 27 (src line 362) state 30 @@ -373,31 +373,31 @@ state 33 state 34 non_dcl_stmt: simple_stmt. (256) - . reduce 256 (src line 1734) + . reduce 256 (src line 1796) state 35 non_dcl_stmt: for_stmt. (257) - . reduce 257 (src line 1736) + . reduce 257 (src line 1798) state 36 non_dcl_stmt: switch_stmt. (258) - . reduce 258 (src line 1737) + . reduce 258 (src line 1799) state 37 non_dcl_stmt: select_stmt. (259) - . reduce 259 (src line 1738) + . reduce 259 (src line 1800) state 38 non_dcl_stmt: if_stmt. (260) - . reduce 260 (src line 1739) + . reduce 260 (src line 1801) state 39 @@ -410,7 +410,7 @@ state 39 state 40 non_dcl_stmt: LFALL. (263) - . reduce 263 (src line 1756) + . reduce 263 (src line 1818) state 41 @@ -420,7 +420,7 @@ state 41 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 155 (src line 1107) + . reduce 155 (src line 1169) sym goto 119 new_name goto 118 @@ -434,7 +434,7 @@ state 42 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 155 (src line 1107) + . reduce 155 (src line 1169) sym goto 119 new_name goto 118 @@ -538,7 +538,7 @@ state 46 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 292 (src line 1905) + . reduce 292 (src line 1967) sym goto 123 expr goto 129 @@ -562,7 +562,7 @@ state 46 state 47 lconst: LCONST. (38) - . reduce 38 (src line 354) + . reduce 38 (src line 416) state 48 @@ -593,7 +593,7 @@ state 48 expr_list: expr. (276) LASOP shift 130 - LCOLAS reduce 276 (src line 1840) + LCOLAS reduce 276 (src line 1902) LANDAND shift 134 LANDNOT shift 149 LCOMM shift 152 @@ -616,9 +616,9 @@ state 48 '/' shift 146 '%' shift 147 '&' shift 148 - '=' reduce 276 (src line 1840) - ',' reduce 276 (src line 1840) - . reduce 49 (src line 410) + '=' reduce 276 (src line 1902) + ',' reduce 276 (src line 1902) + . reduce 49 (src line 472) state 49 @@ -636,7 +636,7 @@ state 50 for_stmt: LFOR.$$74 for_body $$74: . (74) - . reduce 74 (src line 659) + . reduce 74 (src line 721) $$74 goto 156 @@ -644,7 +644,7 @@ state 51 switch_stmt: LSWITCH.$$88 if_header $$89 LBODY caseblock_list '}' $$88: . (88) - . reduce 88 (src line 754) + . reduce 88 (src line 816) $$88 goto 157 @@ -652,7 +652,7 @@ state 52 select_stmt: LSELECT.$$91 LBODY caseblock_list '}' $$91: . (91) - . reduce 91 (src line 777) + . reduce 91 (src line 839) $$91 goto 158 @@ -660,28 +660,28 @@ state 53 if_stmt: LIF.$$78 if_header $$79 loop_body $$80 elseif_list else $$78: . (78) - . reduce 78 (src line 688) + . reduce 78 (src line 750) $$78 goto 159 state 54 labelname: new_name. (163) - . reduce 163 (src line 1167) + . reduce 163 (src line 1229) state 55 expr: uexpr. (93) - . reduce 93 (src line 793) + . reduce 93 (src line 855) state 56 new_name: sym. (153) name: sym. (162) - ':' reduce 153 (src line 1091) - . reduce 162 (src line 1158) + ':' reduce 153 (src line 1153) + . reduce 162 (src line 1220) state 57 @@ -699,7 +699,7 @@ state 57 '(' shift 160 '.' shift 161 '[' shift 162 - . reduce 114 (src line 877) + . reduce 114 (src line 939) state 58 @@ -1027,7 +1027,7 @@ state 66 pexpr: pexpr_no_paren. (146) '{' shift 171 - . reduce 146 (src line 1054) + . reduce 146 (src line 1116) state 67 @@ -1078,19 +1078,19 @@ state 67 state 68 pexpr_no_paren: LLITERAL. (126) - . reduce 126 (src line 941) + . reduce 126 (src line 1003) state 69 pexpr_no_paren: name. (127) - . reduce 127 (src line 946) + . reduce 127 (src line 1008) state 70 pexpr_no_paren: pseudocall. (134) - . reduce 134 (src line 984) + . reduce 134 (src line 1046) state 71 @@ -1112,23 +1112,23 @@ state 72 state 73 pexpr_no_paren: fnliteral. (139) - . reduce 139 (src line 1011) + . reduce 139 (src line 1073) state 74 convtype: fntype. (181) fnlitdcl: fntype. (215) - '(' reduce 181 (src line 1220) - . reduce 215 (src line 1484) + '(' reduce 181 (src line 1282) + . reduce 215 (src line 1546) state 75 convtype: othertype. (182) comptype: othertype. (183) - '(' reduce 182 (src line 1222) - . reduce 183 (src line 1224) + '(' reduce 182 (src line 1284) + . reduce 183 (src line 1286) state 76 @@ -1167,7 +1167,7 @@ state 77 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1899) + . reduce 290 (src line 1961) sym goto 123 expr goto 188 @@ -1226,13 +1226,13 @@ state 79 state 80 othertype: structtype. (196) - . reduce 196 (src line 1272) + . reduce 196 (src line 1334) state 81 othertype: interfacetype. (197) - . reduce 197 (src line 1273) + . reduce 197 (src line 1335) state 82 @@ -1258,13 +1258,13 @@ state 83 state 84 imports: imports import ';'. (7) - . reduce 7 (src line 166) + . reduce 7 (src line 228) state 85 import: LIMPORT import_stmt. (8) - . reduce 8 (src line 168) + . reduce 8 (src line 230) state 86 @@ -1291,7 +1291,7 @@ state 87 $$21: . (21) LPACKAGE shift 7 - . reduce 21 (src line 272) + . reduce 21 (src line 334) import_package goto 204 import_there goto 205 @@ -1300,7 +1300,7 @@ state 87 state 88 import_here: LLITERAL. (15) - . reduce 15 (src line 224) + . reduce 15 (src line 286) state 89 @@ -1336,7 +1336,7 @@ state 92 state 93 hidden_import_list: hidden_import_list hidden_import. (345) - . reduce 345 (src line 2210) + . reduce 345 (src line 2272) state 94 @@ -1389,19 +1389,19 @@ state 98 state 99 import_package: LPACKAGE LNAME import_safety ';'. (18) - . reduce 18 (src line 247) + . reduce 18 (src line 309) state 100 xdcl_list: xdcl_list xdcl ';'. (219) - . reduce 219 (src line 1511) + . reduce 219 (src line 1573) state 101 common_dcl: LVAR vardcl. (28) - . reduce 28 (src line 305) + . reduce 28 (src line 367) state 102 @@ -1458,19 +1458,19 @@ state 103 state 104 dcl_name_list: dcl_name. (274) - . reduce 274 (src line 1830) + . reduce 274 (src line 1892) state 105 dcl_name: sym. (154) - . reduce 154 (src line 1101) + . reduce 154 (src line 1163) state 106 common_dcl: lconst constdcl. (31) - . reduce 31 (src line 318) + . reduce 31 (src line 380) state 107 @@ -1526,7 +1526,7 @@ state 108 state 109 common_dcl: LTYPE typedcl. (35) - . reduce 35 (src line 341) + . reduce 35 (src line 403) state 110 @@ -1577,7 +1577,7 @@ state 111 state 112 typedclname: sym. (47) - . reduce 47 (src line 395) + . reduce 47 (src line 457) state 113 @@ -1585,7 +1585,7 @@ state 113 fnbody: . (210) '{' shift 242 - . reduce 210 (src line 1457) + . reduce 210 (src line 1519) fnbody goto 241 @@ -1607,7 +1607,7 @@ state 114 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -1637,43 +1637,43 @@ state 116 non_dcl_stmt: labelname ':'.$$261 stmt $$261: . (261) - . reduce 261 (src line 1740) + . reduce 261 (src line 1802) $$261 goto 252 state 117 non_dcl_stmt: LBREAK onew_name. (264) - . reduce 264 (src line 1762) + . reduce 264 (src line 1824) state 118 onew_name: new_name. (156) - . reduce 156 (src line 1111) + . reduce 156 (src line 1173) state 119 new_name: sym. (153) - . reduce 153 (src line 1091) + . reduce 153 (src line 1153) state 120 non_dcl_stmt: LCONTINUE onew_name. (265) - . reduce 265 (src line 1766) + . reduce 265 (src line 1828) state 121 pexpr_no_paren: pseudocall. (134) non_dcl_stmt: LGO pseudocall. (266) - '(' reduce 134 (src line 984) - '.' reduce 134 (src line 984) - '{' reduce 134 (src line 984) - '[' reduce 134 (src line 984) - . reduce 266 (src line 1770) + '(' reduce 134 (src line 1046) + '.' reduce 134 (src line 1046) + '{' reduce 134 (src line 1046) + '[' reduce 134 (src line 1046) + . reduce 266 (src line 1832) state 122 @@ -1696,7 +1696,7 @@ state 122 state 123 name: sym. (162) - . reduce 162 (src line 1158) + . reduce 162 (src line 1220) state 124 @@ -1710,23 +1710,23 @@ state 125 pexpr_no_paren: pseudocall. (134) non_dcl_stmt: LDEFER pseudocall. (267) - '(' reduce 134 (src line 984) - '.' reduce 134 (src line 984) - '{' reduce 134 (src line 984) - '[' reduce 134 (src line 984) - . reduce 267 (src line 1774) + '(' reduce 134 (src line 1046) + '.' reduce 134 (src line 1046) + '{' reduce 134 (src line 1046) + '[' reduce 134 (src line 1046) + . reduce 267 (src line 1836) state 126 non_dcl_stmt: LGOTO new_name. (268) - . reduce 268 (src line 1778) + . reduce 268 (src line 1840) state 127 non_dcl_stmt: LRETURN oexpr_list. (269) - . reduce 269 (src line 1783) + . reduce 269 (src line 1845) state 128 @@ -1734,7 +1734,7 @@ state 128 oexpr_list: expr_list. (293) ',' shift 155 - . reduce 293 (src line 1909) + . reduce 293 (src line 1971) state 129 @@ -1780,7 +1780,7 @@ state 129 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 276 (src line 1840) + . reduce 276 (src line 1902) state 130 @@ -1827,13 +1827,13 @@ state 130 state 131 simple_stmt: expr LINC. (53) - . reduce 53 (src line 460) + . reduce 53 (src line 522) state 132 simple_stmt: expr LDEC. (54) - . reduce 54 (src line 466) + . reduce 54 (src line 528) state 133 @@ -2805,7 +2805,7 @@ state 156 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -2853,7 +2853,7 @@ state 157 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -2906,7 +2906,7 @@ state 159 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -3016,7 +3016,7 @@ state 162 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1899) + . reduce 290 (src line 1961) sym goto 123 expr goto 294 @@ -3039,56 +3039,56 @@ state 162 state 163 uexpr: '*' uexpr. (115) - . reduce 115 (src line 879) + . reduce 115 (src line 941) state 164 uexpr: '&' uexpr. (116) - . reduce 116 (src line 883) + . reduce 116 (src line 945) state 165 uexpr: '+' uexpr. (117) - . reduce 117 (src line 894) + . reduce 117 (src line 956) state 166 uexpr: '-' uexpr. (118) - . reduce 118 (src line 898) + . reduce 118 (src line 960) state 167 uexpr: '!' uexpr. (119) - . reduce 119 (src line 902) + . reduce 119 (src line 964) state 168 uexpr: '~' uexpr. (120) - . reduce 120 (src line 906) + . reduce 120 (src line 968) state 169 uexpr: '^' uexpr. (121) - . reduce 121 (src line 911) + . reduce 121 (src line 973) state 170 uexpr: LCOMM uexpr. (122) - . reduce 122 (src line 915) + . reduce 122 (src line 977) state 171 pexpr_no_paren: pexpr_no_paren '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1013) + . reduce 140 (src line 1075) start_complit goto 296 @@ -3143,19 +3143,19 @@ state 173 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 148 (src line 1069) + . reduce 148 (src line 1131) state 174 expr_or_type: non_expr_type. (149) - . reduce 149 (src line 1071) + . reduce 149 (src line 1133) state 175 non_expr_type: recvchantype. (172) - . reduce 172 (src line 1201) + . reduce 172 (src line 1263) state 176 @@ -3163,11 +3163,11 @@ state 176 convtype: fntype. (181) fnlitdcl: fntype. (215) - error reduce 215 (src line 1484) - LBODY reduce 215 (src line 1484) - '(' reduce 181 (src line 1220) - '{' reduce 215 (src line 1484) - . reduce 173 (src line 1203) + error reduce 215 (src line 1546) + LBODY reduce 215 (src line 1546) + '(' reduce 181 (src line 1282) + '{' reduce 215 (src line 1546) + . reduce 173 (src line 1265) state 177 @@ -3175,10 +3175,10 @@ state 177 convtype: othertype. (182) comptype: othertype. (183) - LBODY reduce 183 (src line 1224) - '(' reduce 182 (src line 1222) - '{' reduce 183 (src line 1224) - . reduce 174 (src line 1204) + LBODY reduce 183 (src line 1286) + '(' reduce 182 (src line 1284) + '{' reduce 183 (src line 1286) + . reduce 174 (src line 1266) state 178 @@ -3310,20 +3310,20 @@ state 181 pexpr_no_paren: comptype lbrace.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1013) + . reduce 140 (src line 1075) start_complit goto 301 state 182 lbrace: LBODY. (151) - . reduce 151 (src line 1076) + . reduce 151 (src line 1138) state 183 lbrace: '{'. (152) - . reduce 152 (src line 1081) + . reduce 152 (src line 1143) state 184 @@ -3359,9 +3359,9 @@ state 184 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -3403,7 +3403,7 @@ state 184 state 185 fnliteral: fnlitdcl error. (217) - . reduce 217 (src line 1496) + . reduce 217 (src line 1558) state 186 @@ -3463,13 +3463,13 @@ state 188 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 291 (src line 1903) + . reduce 291 (src line 1965) state 189 othertype: LCHAN non_recvchantype. (193) - . reduce 193 (src line 1258) + . reduce 193 (src line 1320) state 190 @@ -3504,25 +3504,25 @@ state 190 state 191 non_recvchantype: fntype. (176) - . reduce 176 (src line 1210) + . reduce 176 (src line 1272) state 192 non_recvchantype: othertype. (177) - . reduce 177 (src line 1212) + . reduce 177 (src line 1274) state 193 non_recvchantype: ptrtype. (178) - . reduce 178 (src line 1213) + . reduce 178 (src line 1275) state 194 non_recvchantype: dotname. (179) - . reduce 179 (src line 1214) + . reduce 179 (src line 1276) state 195 @@ -3588,7 +3588,7 @@ state 197 dotname: name.'.' sym '.' shift 314 - . reduce 189 (src line 1234) + . reduce 189 (src line 1296) state 198 @@ -3665,27 +3665,27 @@ state 201 osemi: . (286) ';' shift 333 - . reduce 286 (src line 1893) + . reduce 286 (src line 1955) osemi goto 332 state 202 import: LIMPORT '(' ')'. (10) - . reduce 10 (src line 171) + . reduce 10 (src line 233) state 203 import_stmt_list: import_stmt. (13) - . reduce 13 (src line 220) + . reduce 13 (src line 282) state 204 import_stmt: import_here import_package.import_there $$21: . (21) - . reduce 21 (src line 272) + . reduce 21 (src line 334) import_there goto 334 $$21 goto 15 @@ -3693,37 +3693,37 @@ state 204 state 205 import_stmt: import_here import_there. (12) - . reduce 12 (src line 209) + . reduce 12 (src line 271) state 206 import_here: sym LLITERAL. (16) - . reduce 16 (src line 232) + . reduce 16 (src line 294) state 207 import_here: '.' LLITERAL. (17) - . reduce 17 (src line 239) + . reduce 17 (src line 301) state 208 hidden_importsym: '@' LLITERAL '.' LNAME. (160) - . reduce 160 (src line 1128) + . reduce 160 (src line 1190) state 209 hidden_importsym: '@' LLITERAL '.' '?'. (161) - . reduce 161 (src line 1143) + . reduce 161 (src line 1205) state 210 import_there: $$21 hidden_import_list '$' '$'. (22) - . reduce 22 (src line 276) + . reduce 22 (src line 338) state 211 @@ -3757,7 +3757,7 @@ state 212 state 213 hidden_pkg_importsym: hidden_importsym. (310) - . reduce 310 (src line 1985) + . reduce 310 (src line 2047) state 214 @@ -3807,7 +3807,7 @@ state 215 state 216 hidden_pkgtype: hidden_pkg_importsym. (311) - . reduce 311 (src line 1992) + . reduce 311 (src line 2054) state 217 @@ -3815,7 +3815,7 @@ state 217 fnbody: . (210) '{' shift 242 - . reduce 210 (src line 1457) + . reduce 210 (src line 1519) fnbody goto 353 @@ -3845,20 +3845,20 @@ state 220 osemi: . (286) ';' shift 359 - . reduce 286 (src line 1893) + . reduce 286 (src line 1955) osemi goto 358 state 221 common_dcl: LVAR '(' ')'. (30) - . reduce 30 (src line 314) + . reduce 30 (src line 376) state 222 vardcl_list: vardcl. (220) - . reduce 220 (src line 1523) + . reduce 220 (src line 1585) state 223 @@ -3866,7 +3866,7 @@ state 223 vardcl: dcl_name_list ntype.'=' expr_list '=' shift 360 - . reduce 39 (src line 360) + . reduce 39 (src line 422) state 224 @@ -3926,31 +3926,31 @@ state 225 state 226 ntype: recvchantype. (166) - . reduce 166 (src line 1190) + . reduce 166 (src line 1252) state 227 ntype: fntype. (167) - . reduce 167 (src line 1192) + . reduce 167 (src line 1254) state 228 ntype: othertype. (168) - . reduce 168 (src line 1193) + . reduce 168 (src line 1255) state 229 ntype: ptrtype. (169) - . reduce 169 (src line 1194) + . reduce 169 (src line 1256) state 230 ntype: dotname. (170) - . reduce 170 (src line 1195) + . reduce 170 (src line 1257) state 231 @@ -3995,14 +3995,14 @@ state 233 osemi: . (286) ';' shift 366 - . reduce 286 (src line 1893) + . reduce 286 (src line 1955) osemi goto 365 state 234 common_dcl: lconst '(' ')'. (34) - . reduce 34 (src line 336) + . reduce 34 (src line 398) state 235 @@ -4060,32 +4060,32 @@ state 237 osemi: . (286) ';' shift 370 - . reduce 286 (src line 1893) + . reduce 286 (src line 1955) osemi goto 369 state 238 common_dcl: LTYPE '(' ')'. (37) - . reduce 37 (src line 349) + . reduce 37 (src line 411) state 239 typedcl_list: typedcl. (224) - . reduce 224 (src line 1537) + . reduce 224 (src line 1599) state 240 typedcl: typedclname ntype. (48) - . reduce 48 (src line 404) + . reduce 48 (src line 466) state 241 xfndcl: LFUNC fndcl fnbody. (204) - . reduce 204 (src line 1318) + . reduce 204 (src line 1380) state 242 @@ -4121,9 +4121,9 @@ state 242 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -4176,20 +4176,20 @@ state 244 ocomma: . (288) ',' shift 373 - . reduce 288 (src line 1896) + . reduce 288 (src line 1958) ocomma goto 374 state 245 arg_type_list: arg_type. (247) - . reduce 247 (src line 1697) + . reduce 247 (src line 1759) state 246 arg_type: name_or_type. (243) - . reduce 243 (src line 1681) + . reduce 243 (src line 1743) state 247 @@ -4210,7 +4210,7 @@ state 247 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 162 (src line 1158) + . reduce 162 (src line 1220) sym goto 123 ntype goto 249 @@ -4229,13 +4229,13 @@ state 247 state 248 arg_type: dotdotdot. (246) - . reduce 246 (src line 1695) + . reduce 246 (src line 1757) state 249 name_or_type: ntype. (150) - . reduce 150 (src line 1073) + . reduce 150 (src line 1135) state 250 @@ -4254,7 +4254,7 @@ state 250 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 164 (src line 1179) + . reduce 164 (src line 1241) sym goto 123 ntype goto 377 @@ -4285,7 +4285,7 @@ state 251 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -4311,11 +4311,11 @@ state 252 error shift 307 LLITERAL shift 68 LBREAK shift 41 - LCASE reduce 251 (src line 1719) + LCASE reduce 251 (src line 1781) LCHAN shift 78 LCONST shift 47 LCONTINUE shift 42 - LDEFAULT reduce 251 (src line 1719) + LDEFAULT reduce 251 (src line 1781) LDEFER shift 44 LFALL shift 40 LFOR shift 50 @@ -4339,9 +4339,9 @@ state 252 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -4396,7 +4396,7 @@ state 253 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -4458,7 +4458,7 @@ state 254 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 50 (src line 425) + . reduce 50 (src line 487) state 255 @@ -4502,7 +4502,7 @@ state 255 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 94 (src line 795) + . reduce 94 (src line 857) state 256 @@ -4545,7 +4545,7 @@ state 256 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 95 (src line 799) + . reduce 95 (src line 861) state 257 @@ -4582,7 +4582,7 @@ state 257 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 96 (src line 803) + . reduce 96 (src line 865) state 258 @@ -4619,7 +4619,7 @@ state 258 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 97 (src line 807) + . reduce 97 (src line 869) state 259 @@ -4656,7 +4656,7 @@ state 259 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 98 (src line 811) + . reduce 98 (src line 873) state 260 @@ -4693,7 +4693,7 @@ state 260 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 99 (src line 815) + . reduce 99 (src line 877) state 261 @@ -4730,7 +4730,7 @@ state 261 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 100 (src line 819) + . reduce 100 (src line 881) state 262 @@ -4767,7 +4767,7 @@ state 262 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 101 (src line 823) + . reduce 101 (src line 885) state 263 @@ -4800,7 +4800,7 @@ state 263 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 102 (src line 827) + . reduce 102 (src line 889) state 264 @@ -4833,7 +4833,7 @@ state 264 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 103 (src line 831) + . reduce 103 (src line 893) state 265 @@ -4866,7 +4866,7 @@ state 265 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 104 (src line 835) + . reduce 104 (src line 897) state 266 @@ -4899,7 +4899,7 @@ state 266 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 105 (src line 839) + . reduce 105 (src line 901) state 267 @@ -4925,7 +4925,7 @@ state 267 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 106 (src line 843) + . reduce 106 (src line 905) state 268 @@ -4951,7 +4951,7 @@ state 268 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 107 (src line 847) + . reduce 107 (src line 909) state 269 @@ -4977,7 +4977,7 @@ state 269 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 108 (src line 851) + . reduce 108 (src line 913) state 270 @@ -5003,7 +5003,7 @@ state 270 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 109 (src line 855) + . reduce 109 (src line 917) state 271 @@ -5029,7 +5029,7 @@ state 271 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 110 (src line 859) + . reduce 110 (src line 921) state 272 @@ -5055,7 +5055,7 @@ state 272 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 111 (src line 863) + . reduce 111 (src line 925) state 273 @@ -5081,7 +5081,7 @@ state 273 expr: expr LRSH expr. (112) expr: expr.LCOMM expr - . reduce 112 (src line 867) + . reduce 112 (src line 929) state 274 @@ -5126,7 +5126,7 @@ state 274 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 113 (src line 872) + . reduce 113 (src line 934) state 275 @@ -5134,7 +5134,7 @@ state 275 expr_list: expr_list.',' expr ',' shift 155 - . reduce 51 (src line 430) + . reduce 51 (src line 492) state 276 @@ -5142,7 +5142,7 @@ state 276 expr_list: expr_list.',' expr ',' shift 155 - . reduce 52 (src line 442) + . reduce 52 (src line 504) state 277 @@ -5188,13 +5188,13 @@ state 277 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 277 (src line 1845) + . reduce 277 (src line 1907) state 278 for_stmt: LFOR $$74 for_body. (75) - . reduce 75 (src line 664) + . reduce 75 (src line 726) state 279 @@ -5210,19 +5210,19 @@ state 280 for_header: osimple_stmt. (71) ';' shift 383 - . reduce 71 (src line 644) + . reduce 71 (src line 706) state 281 for_header: range_stmt. (72) - . reduce 72 (src line 650) + . reduce 72 (src line 712) state 282 osimple_stmt: simple_stmt. (295) - . reduce 295 (src line 1915) + . reduce 295 (src line 1977) state 283 @@ -5283,7 +5283,7 @@ state 285 switch_stmt: LSWITCH $$88 if_header.$$89 LBODY caseblock_list '}' $$89: . (89) - . reduce 89 (src line 759) + . reduce 89 (src line 821) $$89 goto 387 @@ -5292,14 +5292,14 @@ state 286 if_header: osimple_stmt.';' osimple_stmt ';' shift 388 - . reduce 76 (src line 670) + . reduce 76 (src line 732) state 287 select_stmt: LSELECT $$91 LBODY.caseblock_list '}' caseblock_list: . (63) - . reduce 63 (src line 590) + . reduce 63 (src line 652) caseblock_list goto 389 @@ -5307,14 +5307,14 @@ state 288 if_stmt: LIF $$78 if_header.$$79 loop_body $$80 elseif_list else $$79: . (79) - . reduce 79 (src line 693) + . reduce 79 (src line 755) $$79 goto 390 state 289 pseudocall: pexpr '(' ')'. (123) - . reduce 123 (src line 924) + . reduce 123 (src line 986) state 290 @@ -5325,20 +5325,20 @@ state 290 LDDD shift 392 ',' shift 393 - . reduce 288 (src line 1896) + . reduce 288 (src line 1958) ocomma goto 391 state 291 expr_or_type_list: expr_or_type. (278) - . reduce 278 (src line 1850) + . reduce 278 (src line 1912) state 292 pexpr_no_paren: pexpr '.' sym. (128) - . reduce 128 (src line 947) + . reduce 128 (src line 1009) state 293 @@ -5432,7 +5432,7 @@ state 294 '%' shift 147 '&' shift 148 ']' shift 396 - . reduce 291 (src line 1903) + . reduce 291 (src line 1965) state 295 @@ -5467,7 +5467,7 @@ state 296 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1881) + . reduce 284 (src line 1943) sym goto 123 expr goto 402 @@ -5495,13 +5495,13 @@ state 297 pexpr: '(' expr_or_type ')'. (147) '{' shift 404 - . reduce 147 (src line 1056) + . reduce 147 (src line 1118) state 298 non_expr_type: '*' non_expr_type. (175) - . reduce 175 (src line 1205) + . reduce 175 (src line 1267) state 299 @@ -5581,7 +5581,7 @@ state 300 '%' shift 147 '&' shift 148 ',' shift 413 - . reduce 288 (src line 1896) + . reduce 288 (src line 1958) ocomma goto 412 @@ -5609,7 +5609,7 @@ state 301 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1881) + . reduce 284 (src line 1943) sym goto 123 expr goto 402 @@ -5644,38 +5644,38 @@ state 302 state 303 stmt_list: stmt. (270) - . reduce 270 (src line 1804) + . reduce 270 (src line 1866) state 304 stmt: compound_stmt. (252) - . reduce 252 (src line 1723) + . reduce 252 (src line 1785) state 305 stmt: common_dcl. (253) - . reduce 253 (src line 1724) + . reduce 253 (src line 1786) state 306 stmt: non_dcl_stmt. (254) - . reduce 254 (src line 1728) + . reduce 254 (src line 1790) state 307 stmt: error. (255) - . reduce 255 (src line 1729) + . reduce 255 (src line 1791) state 308 compound_stmt: '{'.$$59 stmt_list '}' $$59: . (59) - . reduce 59 (src line 544) + . reduce 59 (src line 606) $$59 goto 417 @@ -5740,7 +5740,7 @@ state 310 state 311 othertype: LCHAN LCOMM ntype. (194) - . reduce 194 (src line 1263) + . reduce 194 (src line 1325) state 312 @@ -5753,7 +5753,7 @@ state 312 state 313 ptrtype: '*' ntype. (198) - . reduce 198 (src line 1275) + . reduce 198 (src line 1337) state 314 @@ -5780,20 +5780,20 @@ state 316 osemi: . (286) ';' shift 424 - . reduce 286 (src line 1893) + . reduce 286 (src line 1955) osemi goto 423 state 317 structtype: LSTRUCT lbrace '}'. (201) - . reduce 201 (src line 1295) + . reduce 201 (src line 1357) state 318 structdcl_list: structdcl. (226) - . reduce 226 (src line 1547) + . reduce 226 (src line 1609) state 319 @@ -5832,7 +5832,7 @@ state 320 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1997) oliteral goto 427 @@ -5861,13 +5861,13 @@ state 322 state 323 new_name_list: new_name. (272) - . reduce 272 (src line 1820) + . reduce 272 (src line 1882) state 324 embed: packname. (238) - . reduce 238 (src line 1646) + . reduce 238 (src line 1708) state 325 @@ -5875,11 +5875,11 @@ state 325 packname: LNAME. (236) packname: LNAME.'.' sym - LLITERAL reduce 236 (src line 1621) - ';' reduce 236 (src line 1621) + LLITERAL reduce 236 (src line 1683) + ';' reduce 236 (src line 1683) '.' shift 434 - '}' reduce 236 (src line 1621) - . reduce 157 (src line 1113) + '}' reduce 236 (src line 1683) + . reduce 157 (src line 1175) state 326 @@ -5888,20 +5888,20 @@ state 326 osemi: . (286) ';' shift 436 - . reduce 286 (src line 1893) + . reduce 286 (src line 1955) osemi goto 435 state 327 interfacetype: LINTERFACE lbrace '}'. (203) - . reduce 203 (src line 1308) + . reduce 203 (src line 1370) state 328 interfacedcl_list: interfacedcl. (228) - . reduce 228 (src line 1554) + . reduce 228 (src line 1616) state 329 @@ -5915,7 +5915,7 @@ state 329 state 330 interfacedcl: packname. (240) - . reduce 240 (src line 1658) + . reduce 240 (src line 1720) state 331 @@ -5942,7 +5942,7 @@ state 333 '.' shift 90 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1956) import_here goto 87 sym goto 89 @@ -5952,7 +5952,7 @@ state 333 state 334 import_stmt: import_here import_package import_there. (11) - . reduce 11 (src line 173) + . reduce 11 (src line 235) state 335 @@ -5972,31 +5972,31 @@ state 336 state 337 hidden_type: hidden_type_misc. (312) - . reduce 312 (src line 2003) + . reduce 312 (src line 2065) state 338 hidden_type: hidden_type_recv_chan. (313) - . reduce 313 (src line 2005) + . reduce 313 (src line 2067) state 339 hidden_type: hidden_type_func. (314) - . reduce 314 (src line 2006) + . reduce 314 (src line 2068) state 340 hidden_type_misc: hidden_importsym. (317) - . reduce 317 (src line 2012) + . reduce 317 (src line 2074) state 341 hidden_type_misc: LNAME. (318) - . reduce 318 (src line 2017) + . reduce 318 (src line 2079) state 342 @@ -6131,7 +6131,7 @@ state 354 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1917) + . reduce 296 (src line 1979) sym goto 357 hidden_importsym goto 11 @@ -6151,7 +6151,7 @@ state 355 state 356 hidden_funarg_list: hidden_funarg. (346) - . reduce 346 (src line 2212) + . reduce 346 (src line 2274) state 357 @@ -6191,7 +6191,7 @@ state 359 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1956) sym goto 105 dcl_name goto 104 @@ -6246,13 +6246,13 @@ state 361 expr_list: expr_list.',' expr ',' shift 155 - . reduce 41 (src line 369) + . reduce 41 (src line 431) state 362 dcl_name_list: dcl_name_list ',' dcl_name. (275) - . reduce 275 (src line 1835) + . reduce 275 (src line 1897) state 363 @@ -6305,7 +6305,7 @@ state 366 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1956) sym goto 105 dcl_name goto 104 @@ -6362,7 +6362,7 @@ state 368 expr_list: expr_list.',' expr ',' shift 155 - . reduce 43 (src line 379) + . reduce 43 (src line 441) state 369 @@ -6379,7 +6379,7 @@ state 370 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1956) sym goto 112 typedclname goto 111 @@ -6412,7 +6412,7 @@ state 372 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1469) + . reduce 212 (src line 1531) sym goto 485 dotname goto 493 @@ -6444,7 +6444,7 @@ state 373 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 289 (src line 1897) + . reduce 289 (src line 1959) sym goto 247 ntype goto 249 @@ -6464,25 +6464,25 @@ state 373 state 374 oarg_type_list_ocomma: arg_type_list ocomma. (250) - . reduce 250 (src line 1711) + . reduce 250 (src line 1773) state 375 arg_type: sym name_or_type. (244) - . reduce 244 (src line 1683) + . reduce 244 (src line 1745) state 376 arg_type: sym dotdotdot. (245) - . reduce 245 (src line 1689) + . reduce 245 (src line 1751) state 377 dotdotdot: LDDD ntype. (165) - . reduce 165 (src line 1185) + . reduce 165 (src line 1247) state 378 @@ -6495,7 +6495,7 @@ state 378 state 379 non_dcl_stmt: labelname ':' $$261 stmt. (262) - . reduce 262 (src line 1745) + . reduce 262 (src line 1807) state 380 @@ -6508,14 +6508,14 @@ state 380 state 381 for_body: for_header loop_body. (73) - . reduce 73 (src line 652) + . reduce 73 (src line 714) state 382 loop_body: LBODY.$$65 stmt_list '}' $$65: . (65) - . reduce 65 (src line 599) + . reduce 65 (src line 661) $$65 goto 497 @@ -6542,7 +6542,7 @@ state 383 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -6695,7 +6695,7 @@ state 386 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 69 (src line 624) + . reduce 69 (src line 686) state 387 @@ -6728,7 +6728,7 @@ state 388 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -6782,7 +6782,7 @@ state 392 ocomma: . (288) ',' shift 413 - . reduce 288 (src line 1896) + . reduce 288 (src line 1958) ocomma goto 510 @@ -6809,7 +6809,7 @@ state 393 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 289 (src line 1897) + . reduce 289 (src line 1959) sym goto 123 expr goto 173 @@ -6848,7 +6848,7 @@ state 395 state 396 pexpr_no_paren: pexpr '[' expr ']'. (131) - . reduce 131 (src line 966) + . reduce 131 (src line 1028) state 397 @@ -6875,7 +6875,7 @@ state 397 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1899) + . reduce 290 (src line 1961) sym goto 123 expr goto 188 @@ -6909,20 +6909,20 @@ state 399 ocomma: . (288) ',' shift 516 - . reduce 288 (src line 1896) + . reduce 288 (src line 1958) ocomma goto 517 state 400 keyval_list: keyval. (280) - . reduce 280 (src line 1863) + . reduce 280 (src line 1925) state 401 keyval_list: bare_complitexpr. (281) - . reduce 281 (src line 1868) + . reduce 281 (src line 1930) state 402 @@ -6970,14 +6970,14 @@ state 402 '%' shift 147 '&' shift 148 ':' shift 518 - . reduce 142 (src line 1026) + . reduce 142 (src line 1088) state 403 bare_complitexpr: '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1013) + . reduce 140 (src line 1075) start_complit goto 519 @@ -6985,7 +6985,7 @@ state 404 pexpr_no_paren: '(' expr_or_type ')' '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1013) + . reduce 140 (src line 1075) start_complit goto 520 @@ -7022,47 +7022,47 @@ state 405 state 406 recvchantype: LCOMM LCHAN ntype. (199) - . reduce 199 (src line 1281) + . reduce 199 (src line 1343) state 407 ntype: fntype. (167) non_recvchantype: fntype. (176) - LBODY reduce 176 (src line 1210) - '(' reduce 176 (src line 1210) - '{' reduce 176 (src line 1210) - . reduce 167 (src line 1192) + LBODY reduce 176 (src line 1272) + '(' reduce 176 (src line 1272) + '{' reduce 176 (src line 1272) + . reduce 167 (src line 1254) state 408 ntype: othertype. (168) non_recvchantype: othertype. (177) - LBODY reduce 177 (src line 1212) - '(' reduce 177 (src line 1212) - '{' reduce 177 (src line 1212) - . reduce 168 (src line 1193) + LBODY reduce 177 (src line 1274) + '(' reduce 177 (src line 1274) + '{' reduce 177 (src line 1274) + . reduce 168 (src line 1255) state 409 ntype: ptrtype. (169) non_recvchantype: ptrtype. (178) - LBODY reduce 178 (src line 1213) - '(' reduce 178 (src line 1213) - '{' reduce 178 (src line 1213) - . reduce 169 (src line 1194) + LBODY reduce 178 (src line 1275) + '(' reduce 178 (src line 1275) + '{' reduce 178 (src line 1275) + . reduce 169 (src line 1256) state 410 ntype: dotname. (170) non_recvchantype: dotname. (179) - LBODY reduce 179 (src line 1214) - '(' reduce 179 (src line 1214) - '{' reduce 179 (src line 1214) - . reduce 170 (src line 1195) + LBODY reduce 179 (src line 1276) + '(' reduce 179 (src line 1276) + '{' reduce 179 (src line 1276) + . reduce 170 (src line 1257) state 411 @@ -7105,7 +7105,7 @@ state 412 state 413 ocomma: ','. (289) - . reduce 289 (src line 1897) + . reduce 289 (src line 1959) state 414 @@ -7118,7 +7118,7 @@ state 414 state 415 fnliteral: fnlitdcl lbrace stmt_list '}'. (216) - . reduce 216 (src line 1490) + . reduce 216 (src line 1552) state 416 @@ -7128,11 +7128,11 @@ state 416 error shift 307 LLITERAL shift 68 LBREAK shift 41 - LCASE reduce 251 (src line 1719) + LCASE reduce 251 (src line 1781) LCHAN shift 78 LCONST shift 47 LCONTINUE shift 42 - LDEFAULT reduce 251 (src line 1719) + LDEFAULT reduce 251 (src line 1781) LDEFER shift 44 LFALL shift 40 LFOR shift 50 @@ -7156,9 +7156,9 @@ state 416 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -7229,9 +7229,9 @@ state 417 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -7273,25 +7273,25 @@ state 417 state 418 othertype: '[' oexpr ']' ntype. (191) - . reduce 191 (src line 1248) + . reduce 191 (src line 1310) state 419 othertype: '[' LDDD ']' ntype. (192) - . reduce 192 (src line 1253) + . reduce 192 (src line 1315) state 420 non_recvchantype: '(' ntype ')'. (180) - . reduce 180 (src line 1215) + . reduce 180 (src line 1277) state 421 dotname: name '.' sym. (190) - . reduce 190 (src line 1236) + . reduce 190 (src line 1298) state 422 @@ -7339,7 +7339,7 @@ state 424 '(' shift 321 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1956) sym goto 119 packname goto 324 @@ -7354,7 +7354,7 @@ state 425 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1997) oliteral goto 529 @@ -7373,13 +7373,13 @@ state 426 state 427 structdcl: embed oliteral. (231) - . reduce 231 (src line 1589) + . reduce 231 (src line 1651) state 428 oliteral: LLITERAL. (303) - . reduce 303 (src line 1939) + . reduce 303 (src line 2001) state 429 @@ -7403,7 +7403,7 @@ state 431 packname: LNAME.'.' sym '.' shift 434 - . reduce 236 (src line 1621) + . reduce 236 (src line 1683) state 432 @@ -7411,7 +7411,7 @@ state 432 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1997) oliteral goto 533 @@ -7450,7 +7450,7 @@ state 436 '(' shift 331 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1956) sym goto 119 packname goto 330 @@ -7461,7 +7461,7 @@ state 436 state 437 interfacedcl: new_name indcl. (239) - . reduce 239 (src line 1652) + . reduce 239 (src line 1714) state 438 @@ -7481,7 +7481,7 @@ state 438 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -7510,25 +7510,25 @@ state 439 state 440 import: LIMPORT '(' import_stmt_list osemi ')'. (9) - . reduce 9 (src line 170) + . reduce 9 (src line 232) state 441 import_stmt_list: import_stmt_list ';' import_stmt. (14) - . reduce 14 (src line 222) + . reduce 14 (src line 284) state 442 hidden_import: LIMPORT LNAME LLITERAL ';'. (304) - . reduce 304 (src line 1944) + . reduce 304 (src line 2006) state 443 hidden_import: LVAR hidden_pkg_importsym hidden_type ';'. (305) - . reduce 305 (src line 1949) + . reduce 305 (src line 2011) state 444 @@ -7587,7 +7587,7 @@ state 447 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 298 (src line 1923) + . reduce 298 (src line 1985) sym goto 546 hidden_importsym goto 11 @@ -7610,7 +7610,7 @@ state 448 '[' shift 342 '?' shift 12 '@' shift 13 - . reduce 300 (src line 1929) + . reduce 300 (src line 1991) sym goto 550 hidden_importsym goto 553 @@ -7625,13 +7625,13 @@ state 448 state 449 hidden_type_misc: '*' hidden_type. (324) - . reduce 324 (src line 2048) + . reduce 324 (src line 2110) state 450 hidden_type_misc: LCHAN hidden_type_non_recv_chan. (325) - . reduce 325 (src line 2052) + . reduce 325 (src line 2114) state 451 @@ -7666,13 +7666,13 @@ state 452 state 453 hidden_type_non_recv_chan: hidden_type_misc. (315) - . reduce 315 (src line 2008) + . reduce 315 (src line 2070) state 454 hidden_type_non_recv_chan: hidden_type_func. (316) - . reduce 316 (src line 2010) + . reduce 316 (src line 2072) state 455 @@ -7703,7 +7703,7 @@ state 456 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1917) + . reduce 296 (src line 1979) sym goto 357 hidden_importsym goto 11 @@ -7721,7 +7721,7 @@ state 457 state 458 hidden_constant: hidden_literal. (342) - . reduce 342 (src line 2195) + . reduce 342 (src line 2257) state 459 @@ -7741,7 +7741,7 @@ state 459 state 460 hidden_literal: LLITERAL. (339) - . reduce 339 (src line 2164) + . reduce 339 (src line 2226) state 461 @@ -7754,7 +7754,7 @@ state 461 state 462 hidden_literal: sym. (341) - . reduce 341 (src line 2187) + . reduce 341 (src line 2249) state 463 @@ -7776,13 +7776,13 @@ state 463 state 464 hidden_import: LTYPE hidden_pkgtype hidden_type ';'. (308) - . reduce 308 (src line 1961) + . reduce 308 (src line 2023) state 465 hidden_import: LFUNC hidden_fndcl fnbody ';'. (309) - . reduce 309 (src line 1965) + . reduce 309 (src line 2027) state 466 @@ -7797,7 +7797,7 @@ state 467 hidden_funarg_list: hidden_funarg_list.',' hidden_funarg ',' shift 469 - . reduce 297 (src line 1921) + . reduce 297 (src line 1983) state 468 @@ -7828,7 +7828,7 @@ state 470 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1997) oliteral goto 565 @@ -7856,13 +7856,13 @@ state 471 state 472 common_dcl: LVAR '(' vardcl_list osemi ')'. (29) - . reduce 29 (src line 310) + . reduce 29 (src line 372) state 473 vardcl_list: vardcl_list ';' vardcl. (221) - . reduce 221 (src line 1525) + . reduce 221 (src line 1587) state 474 @@ -7870,19 +7870,19 @@ state 474 expr_list: expr_list.',' expr ',' shift 155 - . reduce 40 (src line 365) + . reduce 40 (src line 427) state 475 ntype: '(' ntype ')'. (171) - . reduce 171 (src line 1196) + . reduce 171 (src line 1258) state 476 common_dcl: lconst '(' constdcl osemi ')'. (32) - . reduce 32 (src line 324) + . reduce 32 (src line 386) state 477 @@ -7891,20 +7891,20 @@ state 477 osemi: . (286) ';' shift 568 - . reduce 286 (src line 1893) + . reduce 286 (src line 1955) osemi goto 567 state 478 constdcl_list: constdcl1. (222) - . reduce 222 (src line 1530) + . reduce 222 (src line 1592) state 479 constdcl1: constdcl. (44) - . reduce 44 (src line 384) + . reduce 44 (src line 446) state 480 @@ -7928,7 +7928,7 @@ state 480 '?' shift 12 '@' shift 13 ',' shift 225 - . reduce 46 (src line 390) + . reduce 46 (src line 452) sym goto 123 ntype goto 569 @@ -7947,25 +7947,25 @@ state 481 expr_list: expr_list.',' expr ',' shift 155 - . reduce 42 (src line 374) + . reduce 42 (src line 436) state 482 common_dcl: LTYPE '(' typedcl_list osemi ')'. (36) - . reduce 36 (src line 345) + . reduce 36 (src line 407) state 483 typedcl_list: typedcl_list ';' typedcl. (225) - . reduce 225 (src line 1542) + . reduce 225 (src line 1604) state 484 fnbody: '{' stmt_list '}'. (211) - . reduce 211 (src line 1461) + . reduce 211 (src line 1523) state 485 @@ -7973,19 +7973,19 @@ state 485 fndcl: '(' oarg_type_list_ocomma ')' sym.'(' oarg_type_list_ocomma ')' fnres '(' shift 570 - . reduce 162 (src line 1158) + . reduce 162 (src line 1220) state 486 fntype: LFUNC '(' oarg_type_list_ocomma ')' fnres. (209) - . reduce 209 (src line 1448) + . reduce 209 (src line 1510) state 487 fnres: fnret_type. (213) - . reduce 213 (src line 1474) + . reduce 213 (src line 1536) state 488 @@ -8005,7 +8005,7 @@ state 488 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -8027,37 +8027,37 @@ state 488 state 489 fnret_type: recvchantype. (184) - . reduce 184 (src line 1227) + . reduce 184 (src line 1289) state 490 fnret_type: fntype. (185) - . reduce 185 (src line 1229) + . reduce 185 (src line 1291) state 491 fnret_type: othertype. (186) - . reduce 186 (src line 1230) + . reduce 186 (src line 1292) state 492 fnret_type: ptrtype. (187) - . reduce 187 (src line 1231) + . reduce 187 (src line 1293) state 493 fnret_type: dotname. (188) - . reduce 188 (src line 1232) + . reduce 188 (src line 1294) state 494 arg_type_list: arg_type_list ',' arg_type. (248) - . reduce 248 (src line 1702) + . reduce 248 (src line 1764) state 495 @@ -8076,7 +8076,7 @@ state 495 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1469) + . reduce 212 (src line 1531) sym goto 123 dotname goto 493 @@ -8107,7 +8107,7 @@ state 496 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1469) + . reduce 212 (src line 1531) sym goto 123 dotname goto 493 @@ -8155,9 +8155,9 @@ state 497 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -8289,33 +8289,33 @@ state 501 switch_stmt: LSWITCH $$88 if_header $$89 LBODY.caseblock_list '}' caseblock_list: . (63) - . reduce 63 (src line 590) + . reduce 63 (src line 652) caseblock_list goto 577 state 502 if_header: osimple_stmt ';' osimple_stmt. (77) - . reduce 77 (src line 677) + . reduce 77 (src line 739) state 503 caseblock_list: caseblock_list caseblock. (64) - . reduce 64 (src line 594) + . reduce 64 (src line 656) state 504 select_stmt: LSELECT $$91 LBODY caseblock_list '}'. (92) - . reduce 92 (src line 782) + . reduce 92 (src line 844) state 505 caseblock: case.$$61 stmt_list $$61: . (61) - . reduce 61 (src line 559) + . reduce 61 (src line 621) $$61 goto 578 @@ -8377,14 +8377,14 @@ state 508 if_stmt: LIF $$78 if_header $$79 loop_body.$$80 elseif_list else $$80: . (80) - . reduce 80 (src line 699) + . reduce 80 (src line 761) $$80 goto 581 state 509 pseudocall: pexpr '(' expr_or_type_list ocomma ')'. (124) - . reduce 124 (src line 929) + . reduce 124 (src line 991) state 510 @@ -8397,19 +8397,19 @@ state 510 state 511 expr_or_type_list: expr_or_type_list ',' expr_or_type. (279) - . reduce 279 (src line 1855) + . reduce 279 (src line 1917) state 512 pexpr_no_paren: pexpr '.' '(' expr_or_type ')'. (129) - . reduce 129 (src line 958) + . reduce 129 (src line 1020) state 513 pexpr_no_paren: pexpr '.' '(' LTYPE ')'. (130) - . reduce 130 (src line 962) + . reduce 130 (src line 1024) state 514 @@ -8424,7 +8424,7 @@ state 514 state 515 pexpr_no_paren: pexpr_no_paren '{' start_complit braced_keyval_list '}'. (137) - . reduce 137 (src line 998) + . reduce 137 (src line 1060) state 516 @@ -8452,7 +8452,7 @@ state 516 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 289 (src line 1897) + . reduce 289 (src line 1959) sym goto 123 expr goto 402 @@ -8476,7 +8476,7 @@ state 516 state 517 braced_keyval_list: keyval_list ocomma. (285) - . reduce 285 (src line 1885) + . reduce 285 (src line 1947) state 518 @@ -8546,7 +8546,7 @@ state 519 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1881) + . reduce 284 (src line 1943) sym goto 123 expr goto 402 @@ -8593,7 +8593,7 @@ state 520 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1881) + . reduce 284 (src line 1943) sym goto 123 expr goto 402 @@ -8627,19 +8627,19 @@ state 521 state 522 pexpr_no_paren: convtype '(' expr ocomma ')'. (135) - . reduce 135 (src line 985) + . reduce 135 (src line 1047) state 523 pexpr_no_paren: comptype lbrace start_complit braced_keyval_list '}'. (136) - . reduce 136 (src line 991) + . reduce 136 (src line 1053) state 524 stmt_list: stmt_list ';' stmt. (271) - . reduce 271 (src line 1812) + . reduce 271 (src line 1874) state 525 @@ -8654,31 +8654,31 @@ state 525 state 526 othertype: LMAP '[' ntype ']' ntype. (195) - . reduce 195 (src line 1268) + . reduce 195 (src line 1330) state 527 structtype: LSTRUCT lbrace structdcl_list osemi '}'. (200) - . reduce 200 (src line 1288) + . reduce 200 (src line 1350) state 528 structdcl_list: structdcl_list ';' structdcl. (227) - . reduce 227 (src line 1549) + . reduce 227 (src line 1611) state 529 structdcl: new_name_list ntype oliteral. (230) - . reduce 230 (src line 1564) + . reduce 230 (src line 1626) state 530 new_name_list: new_name_list ',' new_name. (273) - . reduce 273 (src line 1825) + . reduce 273 (src line 1887) state 531 @@ -8686,7 +8686,7 @@ state 531 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1997) oliteral goto 594 @@ -8700,7 +8700,7 @@ state 532 state 533 structdcl: '*' embed oliteral. (233) - . reduce 233 (src line 1600) + . reduce 233 (src line 1662) state 534 @@ -8713,19 +8713,19 @@ state 534 state 535 packname: LNAME '.' sym. (237) - . reduce 237 (src line 1632) + . reduce 237 (src line 1694) state 536 interfacetype: LINTERFACE lbrace interfacedcl_list osemi '}'. (202) - . reduce 202 (src line 1301) + . reduce 202 (src line 1363) state 537 interfacedcl_list: interfacedcl_list ';' interfacedcl. (229) - . reduce 229 (src line 1559) + . reduce 229 (src line 1621) state 538 @@ -8738,13 +8738,13 @@ state 538 state 539 interfacedcl: '(' packname ')'. (241) - . reduce 241 (src line 1662) + . reduce 241 (src line 1724) state 540 hidden_type_misc: '[' ']' hidden_type. (319) - . reduce 319 (src line 2028) + . reduce 319 (src line 2090) state 541 @@ -8787,13 +8787,13 @@ state 544 hidden_structdcl_list: hidden_structdcl_list.';' hidden_structdcl ';' shift 601 - . reduce 299 (src line 1927) + . reduce 299 (src line 1989) state 545 hidden_structdcl_list: hidden_structdcl. (348) - . reduce 348 (src line 2222) + . reduce 348 (src line 2284) state 546 @@ -8829,13 +8829,13 @@ state 548 hidden_interfacedcl_list: hidden_interfacedcl_list.';' hidden_interfacedcl ';' shift 604 - . reduce 301 (src line 1933) + . reduce 301 (src line 1995) state 549 hidden_interfacedcl_list: hidden_interfacedcl. (350) - . reduce 350 (src line 2232) + . reduce 350 (src line 2294) state 550 @@ -8848,23 +8848,23 @@ state 550 state 551 hidden_interfacedcl: hidden_type. (334) - . reduce 334 (src line 2139) + . reduce 334 (src line 2201) state 552 sym: LNAME. (157) hidden_type_misc: LNAME. (318) - '(' reduce 157 (src line 1113) - . reduce 318 (src line 2017) + '(' reduce 157 (src line 1175) + . reduce 318 (src line 2079) state 553 sym: hidden_importsym. (158) hidden_type_misc: hidden_importsym. (317) - '(' reduce 158 (src line 1122) - . reduce 317 (src line 2012) + '(' reduce 158 (src line 1184) + . reduce 317 (src line 2074) state 554 @@ -8877,13 +8877,13 @@ state 554 state 555 hidden_type_misc: LCHAN LCOMM hidden_type. (327) - . reduce 327 (src line 2064) + . reduce 327 (src line 2126) state 556 hidden_type_recv_chan: LCOMM LCHAN hidden_type. (328) - . reduce 328 (src line 2071) + . reduce 328 (src line 2133) state 557 @@ -8896,7 +8896,7 @@ state 557 state 558 hidden_import: LCONST hidden_pkg_importsym '=' hidden_constant ';'. (306) - . reduce 306 (src line 1953) + . reduce 306 (src line 2015) state 559 @@ -8909,7 +8909,7 @@ state 559 state 560 hidden_literal: '-' LLITERAL. (340) - . reduce 340 (src line 2169) + . reduce 340 (src line 2231) state 561 @@ -8934,7 +8934,7 @@ state 562 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2144) + . reduce 335 (src line 2206) hidden_importsym goto 340 hidden_funres goto 611 @@ -8954,13 +8954,13 @@ state 563 state 564 hidden_funarg_list: hidden_funarg_list ',' hidden_funarg. (347) - . reduce 347 (src line 2217) + . reduce 347 (src line 2279) state 565 hidden_funarg: sym hidden_type oliteral. (330) - . reduce 330 (src line 2085) + . reduce 330 (src line 2147) state 566 @@ -8968,7 +8968,7 @@ state 566 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1997) oliteral goto 615 @@ -8986,7 +8986,7 @@ state 568 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1956) sym goto 105 dcl_name goto 104 @@ -9000,7 +9000,7 @@ state 569 constdcl1: dcl_name_list ntype. (45) '=' shift 367 - . reduce 45 (src line 386) + . reduce 45 (src line 448) state 570 @@ -9020,7 +9020,7 @@ state 570 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -9049,7 +9049,7 @@ state 571 state 572 fndcl: sym '(' oarg_type_list_ocomma ')' fnres. (205) - . reduce 205 (src line 1336) + . reduce 205 (src line 1398) state 573 @@ -9084,7 +9084,7 @@ state 574 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -9149,7 +9149,7 @@ state 575 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 67 (src line 610) + . reduce 67 (src line 672) state 576 @@ -9195,7 +9195,7 @@ state 576 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 68 (src line 617) + . reduce 68 (src line 679) state 577 @@ -9217,11 +9217,11 @@ state 578 error shift 307 LLITERAL shift 68 LBREAK shift 41 - LCASE reduce 251 (src line 1719) + LCASE reduce 251 (src line 1781) LCHAN shift 78 LCONST shift 47 LCONTINUE shift 42 - LDEFAULT reduce 251 (src line 1719) + LDEFAULT reduce 251 (src line 1781) LDEFER shift 44 LFALL shift 40 LFOR shift 50 @@ -9245,9 +9245,9 @@ state 578 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -9302,27 +9302,27 @@ state 579 state 580 case: LDEFAULT ':'. (58) - . reduce 58 (src line 524) + . reduce 58 (src line 586) state 581 if_stmt: LIF $$78 if_header $$79 loop_body $$80.elseif_list else elseif_list: . (84) - . reduce 84 (src line 734) + . reduce 84 (src line 796) elseif_list goto 628 state 582 pseudocall: pexpr '(' expr_or_type_list LDDD ocomma ')'. (125) - . reduce 125 (src line 934) + . reduce 125 (src line 996) state 583 pexpr_no_paren: pexpr '[' oexpr ':' oexpr ']'. (132) - . reduce 132 (src line 970) + . reduce 132 (src line 1032) state 584 @@ -9348,7 +9348,7 @@ state 584 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1899) + . reduce 290 (src line 1961) sym goto 123 expr goto 188 @@ -9371,19 +9371,19 @@ state 584 state 585 keyval_list: keyval_list ',' keyval. (282) - . reduce 282 (src line 1872) + . reduce 282 (src line 1934) state 586 keyval_list: keyval_list ',' bare_complitexpr. (283) - . reduce 283 (src line 1876) + . reduce 283 (src line 1938) state 587 keyval: expr ':' complitexpr. (141) - . reduce 141 (src line 1020) + . reduce 141 (src line 1082) state 588 @@ -9429,14 +9429,14 @@ state 588 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 144 (src line 1046) + . reduce 144 (src line 1108) state 589 complitexpr: '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1013) + . reduce 140 (src line 1075) start_complit goto 630 @@ -9458,22 +9458,22 @@ state 592 ntype: '(' ntype ')'. (171) non_recvchantype: '(' ntype ')'. (180) - LBODY reduce 180 (src line 1215) - '(' reduce 180 (src line 1215) - '{' reduce 180 (src line 1215) - . reduce 171 (src line 1196) + LBODY reduce 180 (src line 1277) + '(' reduce 180 (src line 1277) + '{' reduce 180 (src line 1277) + . reduce 171 (src line 1258) state 593 compound_stmt: '{' $$59 stmt_list '}'. (60) - . reduce 60 (src line 549) + . reduce 60 (src line 611) state 594 structdcl: '(' embed ')' oliteral. (232) - . reduce 232 (src line 1594) + . reduce 232 (src line 1656) state 595 @@ -9481,7 +9481,7 @@ state 595 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1997) oliteral goto 633 @@ -9490,7 +9490,7 @@ state 596 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1997) oliteral goto 634 @@ -9510,7 +9510,7 @@ state 597 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1469) + . reduce 212 (src line 1531) sym goto 123 dotname goto 493 @@ -9528,7 +9528,7 @@ state 597 state 598 hidden_type_misc: '[' LLITERAL ']' hidden_type. (320) - . reduce 320 (src line 2032) + . reduce 320 (src line 2094) state 599 @@ -9555,7 +9555,7 @@ state 599 state 600 hidden_type_misc: LSTRUCT '{' ohidden_structdcl_list '}'. (322) - . reduce 322 (src line 2040) + . reduce 322 (src line 2102) state 601 @@ -9575,14 +9575,14 @@ state 602 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1997) oliteral goto 638 state 603 hidden_type_misc: LINTERFACE '{' ohidden_interfacedcl_list '}'. (323) - . reduce 323 (src line 2044) + . reduce 323 (src line 2106) state 604 @@ -9616,7 +9616,7 @@ state 605 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1917) + . reduce 296 (src line 1979) sym goto 357 hidden_importsym goto 11 @@ -9627,7 +9627,7 @@ state 605 state 606 hidden_type_misc: LCHAN '(' hidden_type_recv_chan ')'. (326) - . reduce 326 (src line 2058) + . reduce 326 (src line 2120) state 607 @@ -9645,7 +9645,7 @@ state 607 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2144) + . reduce 335 (src line 2206) hidden_importsym goto 340 hidden_funres goto 611 @@ -9672,19 +9672,19 @@ state 608 state 609 hidden_import: LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'. (307) - . reduce 307 (src line 1957) + . reduce 307 (src line 2019) state 610 hidden_fndcl: hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres. (207) - . reduce 207 (src line 1405) + . reduce 207 (src line 1467) state 611 ohidden_funres: hidden_funres. (336) - . reduce 336 (src line 2148) + . reduce 336 (src line 2210) state 612 @@ -9694,7 +9694,7 @@ state 612 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1917) + . reduce 296 (src line 1979) sym goto 357 hidden_importsym goto 11 @@ -9705,7 +9705,7 @@ state 612 state 613 hidden_funres: hidden_type. (338) - . reduce 338 (src line 2155) + . reduce 338 (src line 2217) state 614 @@ -9715,7 +9715,7 @@ state 614 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1917) + . reduce 296 (src line 1979) sym goto 357 hidden_importsym goto 11 @@ -9726,19 +9726,19 @@ state 614 state 615 hidden_funarg: sym LDDD hidden_type oliteral. (331) - . reduce 331 (src line 2094) + . reduce 331 (src line 2156) state 616 common_dcl: lconst '(' constdcl ';' constdcl_list osemi ')'. (33) - . reduce 33 (src line 330) + . reduce 33 (src line 392) state 617 constdcl_list: constdcl_list ';' constdcl1. (223) - . reduce 223 (src line 1532) + . reduce 223 (src line 1594) state 618 @@ -9751,25 +9751,25 @@ state 618 state 619 fnres: '(' oarg_type_list_ocomma ')'. (214) - . reduce 214 (src line 1478) + . reduce 214 (src line 1540) state 620 loop_body: LBODY $$65 stmt_list '}'. (66) - . reduce 66 (src line 604) + . reduce 66 (src line 666) state 621 for_header: osimple_stmt ';' osimple_stmt ';' osimple_stmt. (70) - . reduce 70 (src line 630) + . reduce 70 (src line 692) state 622 switch_stmt: LSWITCH $$88 if_header $$89 LBODY caseblock_list '}'. (90) - . reduce 90 (src line 768) + . reduce 90 (src line 830) state 623 @@ -9777,13 +9777,13 @@ state 623 stmt_list: stmt_list.';' stmt ';' shift 416 - . reduce 62 (src line 571) + . reduce 62 (src line 633) state 624 case: LCASE expr_or_type_list ':'. (55) - . reduce 55 (src line 473) + . reduce 55 (src line 535) state 625 @@ -9918,7 +9918,7 @@ state 628 else: . (86) LELSE shift 650 - . reduce 86 (src line 743) + . reduce 86 (src line 805) elseif goto 649 else goto 648 @@ -9954,7 +9954,7 @@ state 630 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1881) + . reduce 284 (src line 1943) sym goto 123 expr goto 402 @@ -9980,55 +9980,55 @@ state 630 state 631 bare_complitexpr: '{' start_complit braced_keyval_list '}'. (143) - . reduce 143 (src line 1040) + . reduce 143 (src line 1102) state 632 pexpr_no_paren: '(' expr_or_type ')' '{' start_complit braced_keyval_list '}'. (138) - . reduce 138 (src line 1004) + . reduce 138 (src line 1066) state 633 structdcl: '(' '*' embed ')' oliteral. (234) - . reduce 234 (src line 1606) + . reduce 234 (src line 1668) state 634 structdcl: '*' '(' embed ')' oliteral. (235) - . reduce 235 (src line 1613) + . reduce 235 (src line 1675) state 635 indcl: '(' oarg_type_list_ocomma ')' fnres. (242) - . reduce 242 (src line 1668) + . reduce 242 (src line 1730) state 636 hidden_type_misc: LMAP '[' hidden_type ']' hidden_type. (321) - . reduce 321 (src line 2036) + . reduce 321 (src line 2098) state 637 hidden_structdcl_list: hidden_structdcl_list ';' hidden_structdcl. (349) - . reduce 349 (src line 2227) + . reduce 349 (src line 2289) state 638 hidden_structdcl: sym hidden_type oliteral. (332) - . reduce 332 (src line 2110) + . reduce 332 (src line 2172) state 639 hidden_interfacedcl_list: hidden_interfacedcl_list ';' hidden_interfacedcl. (351) - . reduce 351 (src line 2237) + . reduce 351 (src line 2299) state 640 @@ -10041,7 +10041,7 @@ state 640 state 641 hidden_type_func: LFUNC '(' ohidden_funarg_list ')' ohidden_funres. (329) - . reduce 329 (src line 2079) + . reduce 329 (src line 2141) state 642 @@ -10081,7 +10081,7 @@ state 645 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1469) + . reduce 212 (src line 1531) sym goto 123 dotname goto 493 @@ -10193,13 +10193,13 @@ state 647 state 648 if_stmt: LIF $$78 if_header $$79 loop_body $$80 elseif_list else. (81) - . reduce 81 (src line 703) + . reduce 81 (src line 765) state 649 elseif_list: elseif_list elseif. (85) - . reduce 85 (src line 738) + . reduce 85 (src line 800) state 650 @@ -10215,7 +10215,7 @@ state 650 state 651 pexpr_no_paren: pexpr '[' oexpr ':' oexpr ':' oexpr ']'. (133) - . reduce 133 (src line 974) + . reduce 133 (src line 1036) state 652 @@ -10240,7 +10240,7 @@ state 653 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2144) + . reduce 335 (src line 2206) hidden_importsym goto 340 hidden_funres goto 611 @@ -10253,13 +10253,13 @@ state 653 state 654 hidden_constant: '(' hidden_literal '+' hidden_literal ')'. (343) - . reduce 343 (src line 2197) + . reduce 343 (src line 2259) state 655 hidden_funres: '(' ohidden_funarg_list ')'. (337) - . reduce 337 (src line 2150) + . reduce 337 (src line 2212) state 656 @@ -10277,7 +10277,7 @@ state 656 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2144) + . reduce 335 (src line 2206) hidden_importsym goto 340 hidden_funres goto 611 @@ -10290,51 +10290,51 @@ state 656 state 657 fndcl: '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres. (206) - . reduce 206 (src line 1368) + . reduce 206 (src line 1430) state 658 case: LCASE expr_or_type_list '=' expr ':'. (56) - . reduce 56 (src line 497) + . reduce 56 (src line 559) state 659 case: LCASE expr_or_type_list LCOLAS expr ':'. (57) - . reduce 57 (src line 515) + . reduce 57 (src line 577) state 660 elseif: LELSE LIF.$$82 if_header loop_body $$82: . (82) - . reduce 82 (src line 720) + . reduce 82 (src line 782) $$82 goto 665 state 661 else: LELSE compound_stmt. (87) - . reduce 87 (src line 747) + . reduce 87 (src line 809) state 662 complitexpr: '{' start_complit braced_keyval_list '}'. (145) - . reduce 145 (src line 1048) + . reduce 145 (src line 1110) state 663 hidden_interfacedcl: sym '(' ohidden_funarg_list ')' ohidden_funres. (333) - . reduce 333 (src line 2134) + . reduce 333 (src line 2196) state 664 hidden_fndcl: '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres. (208) - . reduce 208 (src line 1431) + . reduce 208 (src line 1493) state 665 @@ -10360,7 +10360,7 @@ state 665 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -10394,7 +10394,7 @@ state 666 state 667 elseif: LELSE LIF $$82 if_header loop_body. (83) - . reduce 83 (src line 725) + . reduce 83 (src line 787) 76 terminals, 142 nonterminals diff --git a/src/cmd/9g/cgen.go b/src/cmd/compile/internal/ppc64/cgen.go index 5d24a6ff67..37dd6cefb2 100644 --- a/src/cmd/9g/cgen.go +++ b/src/cmd/compile/internal/ppc64/cgen.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package ppc64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/ppc64" ) diff --git a/src/cmd/9g/galign.go b/src/cmd/compile/internal/ppc64/galign.go index a2f4a0ef89..73aef6fde9 100644 --- a/src/cmd/9g/galign.go +++ b/src/cmd/compile/internal/ppc64/galign.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package ppc64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/ppc64" ) @@ -45,7 +45,7 @@ func betypeinit() { gc.Widthreg = 8 } -func main() { +func Main() { gc.Thearch.Thechar = thechar gc.Thearch.Thestring = thestring gc.Thearch.Thelinkarch = thelinkarch @@ -72,6 +72,7 @@ func main() { gc.Thearch.Expandchecks = expandchecks gc.Thearch.Getg = getg gc.Thearch.Gins = gins + gc.Thearch.Ginscmp = ginscmp gc.Thearch.Ginscon = ginscon gc.Thearch.Ginsnop = ginsnop gc.Thearch.Gmove = gmove diff --git a/src/cmd/9g/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go index 28ebd9cc01..1b936b8a5f 100644 --- a/src/cmd/9g/ggen.go +++ b/src/cmd/compile/internal/ppc64/ggen.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package ppc64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/ppc64" "fmt" @@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) { // iterate through declarations - they are sorted in decreasing xoffset order. for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next { n = l.N - if !n.Needzero { + if !n.Name.Needzero { continue } if n.Class != gc.PAUTO { @@ -141,9 +141,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { check := 0 if gc.Issigned[t.Etype] { check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) { + if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) { check = 0 - } else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 { + } else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 { check = 0 } } @@ -308,7 +308,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { var n1 gc.Node gc.Regalloc(&n1, nl.Type, res) gc.Cgen(nl, &n1) - sc := uint64(uint64(gc.Mpgetfix(nr.Val.U.Xval))) + sc := uint64(nr.Int()) if sc >= uint64(nl.Type.Width*8) { // large shift gets 2 shifts by width-1 var n3 gc.Node diff --git a/src/cmd/9g/gsubr.go b/src/cmd/compile/internal/ppc64/gsubr.go index 8223fe70b1..2501972846 100644 --- a/src/cmd/9g/gsubr.go +++ b/src/cmd/compile/internal/ppc64/gsubr.go @@ -28,10 +28,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package ppc64 import ( - "cmd/internal/gc" + "cmd/compile/internal/big" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/ppc64" "fmt" @@ -116,29 +117,55 @@ func ginscon2(as int, n2 *gc.Node, c int64) { gc.Regfree(&ntmp) } -/* - * set up nodes representing 2^63 - */ -var bigi gc.Node +func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { + if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL { + // Reverse comparison to place constant last. + op = gc.Brrev(op) + n1, n2 = n2, n1 + } -var bigf gc.Node + var r1, r2, g1, g2 gc.Node + gc.Regalloc(&r1, t, n1) + gc.Regalloc(&g1, n1.Type, &r1) + gc.Cgen(n1, &g1) + gmove(&g1, &r1) + if gc.Isint[t.Etype] && gc.Isconst(n2, gc.CTINT) { + ginscon2(optoas(gc.OCMP, t), &r1, n2.Int()) + } else { + gc.Regalloc(&r2, t, n2) + gc.Regalloc(&g2, n1.Type, &r2) + gc.Cgen(n2, &g2) + gmove(&g2, &r2) + rawgins(optoas(gc.OCMP, t), &r1, &r2) + gc.Regfree(&g2) + gc.Regfree(&r2) + } + gc.Regfree(&g1) + gc.Regfree(&r1) + return gc.Gbranch(optoas(op, t), nil, likely) +} -var bignodes_did int +// set up nodes representing 2^63 +var ( + bigi gc.Node + bigf gc.Node + bignodes_did bool +) func bignodes() { - if bignodes_did != 0 { + if bignodes_did { return } - bignodes_did = 1 + bignodes_did = true - gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1) - gc.Mpshiftfix(bigi.Val.U.Xval, 63) + var i big.Int + i.SetInt64(1) + i.Lsh(&i, 63) - bigf = bigi - bigf.Type = gc.Types[gc.TFLOAT64] - bigf.Val.Ctype = gc.CTFLT - bigf.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval) + gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) + bigi.SetBigInt(&i) + + bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64]) } /* @@ -173,13 +200,13 @@ func gmove(f *gc.Node, t *gc.Node) { var con gc.Node switch tt { default: - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) case gc.TINT32, gc.TINT16, gc.TINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val) + f.Convconst(&con, gc.Types[gc.TINT64]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(ppc64.AMOVD, &con, &r1) @@ -191,7 +218,7 @@ func gmove(f *gc.Node, t *gc.Node) { gc.TUINT16, gc.TUINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val) + f.Convconst(&con, gc.Types[gc.TUINT64]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(ppc64.AMOVD, &con, &r1) @@ -519,14 +546,13 @@ hard: } func intLiteral(n *gc.Node) (x int64, ok bool) { - if n == nil || n.Op != gc.OLITERAL { + switch { + case n == nil: return - } - switch n.Val.Ctype { - case gc.CTINT, gc.CTRUNE: - return gc.Mpgetfix(n.Val.U.Xval), true - case gc.CTBOOL: - return int64(obj.Bool2int(n.Val.U.Bval)), true + case gc.Isconst(n, gc.CTINT): + return n.Int(), true + case gc.Isconst(n, gc.CTBOOL): + return int64(obj.Bool2int(n.Bool())), true } return } diff --git a/src/cmd/9g/opt.go b/src/cmd/compile/internal/ppc64/opt.go index 4a134f134f..1704f63c48 100644 --- a/src/cmd/9g/opt.go +++ b/src/cmd/compile/internal/ppc64/opt.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package ppc64 // Many Power ISA arithmetic and logical instructions come in four // standard variants. These bits let us map between variants. diff --git a/src/cmd/9g/peep.go b/src/cmd/compile/internal/ppc64/peep.go index 94c9b1554b..16eeb39097 100644 --- a/src/cmd/9g/peep.go +++ b/src/cmd/compile/internal/ppc64/peep.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package ppc64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/ppc64" "fmt" diff --git a/src/cmd/9g/prog.go b/src/cmd/compile/internal/ppc64/prog.go index e28e389fac..c7e182769d 100644 --- a/src/cmd/9g/prog.go +++ b/src/cmd/compile/internal/ppc64/prog.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package ppc64 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/ppc64" ) diff --git a/src/cmd/9g/reg.go b/src/cmd/compile/internal/ppc64/reg.go index fb0c2e37ec..fa1cb71975 100644 --- a/src/cmd/9g/reg.go +++ b/src/cmd/compile/internal/ppc64/reg.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package ppc64 import "cmd/internal/obj/ppc64" -import "cmd/internal/gc" +import "cmd/compile/internal/gc" const ( NREGVAR = 64 /* 32 general + 32 floating */ diff --git a/src/cmd/internal/ssa/TODO b/src/cmd/compile/internal/ssa/TODO index afb723ae4c..afb723ae4c 100644 --- a/src/cmd/internal/ssa/TODO +++ b/src/cmd/compile/internal/ssa/TODO diff --git a/src/cmd/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go index dcf3676bc2..dcf3676bc2 100644 --- a/src/cmd/internal/ssa/block.go +++ b/src/cmd/compile/internal/ssa/block.go diff --git a/src/cmd/internal/ssa/blockkind_string.go b/src/cmd/compile/internal/ssa/blockkind_string.go index 6204f1948f..6204f1948f 100644 --- a/src/cmd/internal/ssa/blockkind_string.go +++ b/src/cmd/compile/internal/ssa/blockkind_string.go diff --git a/src/cmd/internal/ssa/cgen.go b/src/cmd/compile/internal/ssa/cgen.go index 51c72aacd9..51c72aacd9 100644 --- a/src/cmd/internal/ssa/cgen.go +++ b/src/cmd/compile/internal/ssa/cgen.go diff --git a/src/cmd/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 667313ad9f..667313ad9f 100644 --- a/src/cmd/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go diff --git a/src/cmd/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index c1f7956791..c1f7956791 100644 --- a/src/cmd/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go diff --git a/src/cmd/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 9f1d2a8593..9f1d2a8593 100644 --- a/src/cmd/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go diff --git a/src/cmd/internal/ssa/copyelim.go b/src/cmd/compile/internal/ssa/copyelim.go index 10c2dcc440..10c2dcc440 100644 --- a/src/cmd/internal/ssa/copyelim.go +++ b/src/cmd/compile/internal/ssa/copyelim.go diff --git a/src/cmd/internal/ssa/critical.go b/src/cmd/compile/internal/ssa/critical.go index 503681ffd3..503681ffd3 100644 --- a/src/cmd/internal/ssa/critical.go +++ b/src/cmd/compile/internal/ssa/critical.go diff --git a/src/cmd/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go index aba24aeabc..aba24aeabc 100644 --- a/src/cmd/internal/ssa/cse.go +++ b/src/cmd/compile/internal/ssa/cse.go diff --git a/src/cmd/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index a805861489..a805861489 100644 --- a/src/cmd/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go diff --git a/src/cmd/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index ced46e524b..ced46e524b 100644 --- a/src/cmd/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go diff --git a/src/cmd/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go index aaf3ab3da1..aaf3ab3da1 100644 --- a/src/cmd/internal/ssa/dom.go +++ b/src/cmd/compile/internal/ssa/dom.go diff --git a/src/cmd/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index ab4ab82345..ab4ab82345 100644 --- a/src/cmd/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go diff --git a/src/cmd/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 3e41ef3bc1..3e41ef3bc1 100644 --- a/src/cmd/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go diff --git a/src/cmd/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index e7619ca4f8..e7619ca4f8 100644 --- a/src/cmd/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go diff --git a/src/cmd/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go index af3e8a8e14..af3e8a8e14 100644 --- a/src/cmd/internal/ssa/fuse.go +++ b/src/cmd/compile/internal/ssa/fuse.go diff --git a/src/cmd/internal/ssa/generic.go b/src/cmd/compile/internal/ssa/generic.go index 91f9c17d11..91f9c17d11 100644 --- a/src/cmd/internal/ssa/generic.go +++ b/src/cmd/compile/internal/ssa/generic.go diff --git a/src/cmd/internal/ssa/id.go b/src/cmd/compile/internal/ssa/id.go index 3f53e1a434..3f53e1a434 100644 --- a/src/cmd/internal/ssa/id.go +++ b/src/cmd/compile/internal/ssa/id.go diff --git a/src/cmd/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go index 7123397c4c..7123397c4c 100644 --- a/src/cmd/internal/ssa/layout.go +++ b/src/cmd/compile/internal/ssa/layout.go diff --git a/src/cmd/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go index 1b6f6d66c1..1b6f6d66c1 100644 --- a/src/cmd/internal/ssa/location.go +++ b/src/cmd/compile/internal/ssa/location.go diff --git a/src/cmd/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index 44f0b83fa8..44f0b83fa8 100644 --- a/src/cmd/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go diff --git a/src/cmd/internal/ssa/lowerAmd64.go b/src/cmd/compile/internal/ssa/lowerAmd64.go index 51cef97b30..51cef97b30 100644 --- a/src/cmd/internal/ssa/lowerAmd64.go +++ b/src/cmd/compile/internal/ssa/lowerAmd64.go diff --git a/src/cmd/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index f02c1ae0c0..f02c1ae0c0 100644 --- a/src/cmd/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go diff --git a/src/cmd/internal/ssa/op_string.go b/src/cmd/compile/internal/ssa/op_string.go index c8f27bb2e4..c8f27bb2e4 100644 --- a/src/cmd/internal/ssa/op_string.go +++ b/src/cmd/compile/internal/ssa/op_string.go diff --git a/src/cmd/internal/ssa/opamd64.go b/src/cmd/compile/internal/ssa/opamd64.go index 46a0069a18..46a0069a18 100644 --- a/src/cmd/internal/ssa/opamd64.go +++ b/src/cmd/compile/internal/ssa/opamd64.go diff --git a/src/cmd/internal/ssa/opt.go b/src/cmd/compile/internal/ssa/opt.go index ea2bcf0e98..ea2bcf0e98 100644 --- a/src/cmd/internal/ssa/opt.go +++ b/src/cmd/compile/internal/ssa/opt.go diff --git a/src/cmd/internal/ssa/phielim.go b/src/cmd/compile/internal/ssa/phielim.go index 19c0d077e5..19c0d077e5 100644 --- a/src/cmd/internal/ssa/phielim.go +++ b/src/cmd/compile/internal/ssa/phielim.go diff --git a/src/cmd/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go index eeea30d970..eeea30d970 100644 --- a/src/cmd/internal/ssa/print.go +++ b/src/cmd/compile/internal/ssa/print.go diff --git a/src/cmd/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index c798d2e936..c798d2e936 100644 --- a/src/cmd/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go diff --git a/src/cmd/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 671270d7f2..671270d7f2 100644 --- a/src/cmd/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go diff --git a/src/cmd/internal/ssa/rulegen/generic.rules b/src/cmd/compile/internal/ssa/rulegen/generic.rules index c49d9d9f2e..c49d9d9f2e 100644 --- a/src/cmd/internal/ssa/rulegen/generic.rules +++ b/src/cmd/compile/internal/ssa/rulegen/generic.rules diff --git a/src/cmd/internal/ssa/rulegen/lower_amd64.rules b/src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules index dc910b70b1..dc910b70b1 100644 --- a/src/cmd/internal/ssa/rulegen/lower_amd64.rules +++ b/src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules diff --git a/src/cmd/internal/ssa/rulegen/rulegen.go b/src/cmd/compile/internal/ssa/rulegen/rulegen.go index 4ac930298b..4ac930298b 100644 --- a/src/cmd/internal/ssa/rulegen/rulegen.go +++ b/src/cmd/compile/internal/ssa/rulegen/rulegen.go diff --git a/src/cmd/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go index 0a89ac3773..0a89ac3773 100644 --- a/src/cmd/internal/ssa/schedule.go +++ b/src/cmd/compile/internal/ssa/schedule.go diff --git a/src/cmd/internal/ssa/sparseset.go b/src/cmd/compile/internal/ssa/sparseset.go index b79aee8497..b79aee8497 100644 --- a/src/cmd/internal/ssa/sparseset.go +++ b/src/cmd/compile/internal/ssa/sparseset.go diff --git a/src/cmd/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index ab686470be..ab686470be 100644 --- a/src/cmd/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go diff --git a/src/cmd/internal/ssa/type.go b/src/cmd/compile/internal/ssa/type.go index 611c85834a..611c85834a 100644 --- a/src/cmd/internal/ssa/type.go +++ b/src/cmd/compile/internal/ssa/type.go diff --git a/src/cmd/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index dab6239dee..dab6239dee 100644 --- a/src/cmd/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go diff --git a/src/cmd/8g/cgen.go b/src/cmd/compile/internal/x86/cgen.go index dfbdafefe3..1768674e42 100644 --- a/src/cmd/8g/cgen.go +++ b/src/cmd/compile/internal/x86/cgen.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package x86 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" ) @@ -17,7 +17,7 @@ import ( */ func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog { if !gc.Is64(n.Type) { - if n.Addable { + if n.Addable && (gc.Simtype[n.Etype] == gc.TUINT32 || gc.Simtype[n.Etype] == gc.TINT32) { // nothing to do. *res = *n } else { diff --git a/src/cmd/8g/cgen64.go b/src/cmd/compile/internal/x86/cgen64.go index a682e2fb44..0b061ffb60 100644 --- a/src/cmd/8g/cgen64.go +++ b/src/cmd/compile/internal/x86/cgen64.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package x86 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" ) @@ -162,7 +162,7 @@ func cgen64(n *gc.Node, res *gc.Node) { // shld hi:lo, c // shld lo:t, c case gc.OLROT: - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) if v >= 32 { // reverse during load to do the first 32 bits of rotate @@ -189,7 +189,7 @@ func cgen64(n *gc.Node, res *gc.Node) { case gc.OLSH: if r.Op == gc.OLITERAL { - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) if v >= 64 { if gc.Is64(r.Type) { splitclean() @@ -278,7 +278,7 @@ func cgen64(n *gc.Node, res *gc.Node) { case gc.ORSH: if r.Op == gc.OLITERAL { - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) if v >= 64 { if gc.Is64(r.Type) { splitclean() @@ -400,9 +400,8 @@ func cgen64(n *gc.Node, res *gc.Node) { if lo2.Op == gc.OLITERAL { // special cases for constants. - lv := uint32(gc.Mpgetfix(lo2.Val.U.Xval)) - - hv := uint32(gc.Mpgetfix(hi2.Val.U.Xval)) + lv := uint32(lo2.Int()) + hv := uint32(hi2.Int()) splitclean() // right side split64(res, &lo2, &hi2) switch n.Op { diff --git a/src/cmd/8g/galign.go b/src/cmd/compile/internal/x86/galign.go index e96b628dcc..2b602e1bb3 100644 --- a/src/cmd/8g/galign.go +++ b/src/cmd/compile/internal/x86/galign.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package x86 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" "fmt" @@ -39,7 +39,7 @@ func betypeinit() { gc.Widthreg = 4 } -func main() { +func Main() { gc.Thearch.Thechar = thechar gc.Thearch.Thestring = thestring gc.Thearch.Thelinkarch = thelinkarch @@ -81,6 +81,7 @@ func main() { gc.Thearch.Expandchecks = expandchecks gc.Thearch.Getg = getg gc.Thearch.Gins = gins + gc.Thearch.Ginscmp = ginscmp gc.Thearch.Ginscon = ginscon gc.Thearch.Ginsnop = ginsnop gc.Thearch.Gmove = gmove diff --git a/src/cmd/8g/ggen.go b/src/cmd/compile/internal/x86/ggen.go index 59025525fa..dabc139f30 100644 --- a/src/cmd/8g/ggen.go +++ b/src/cmd/compile/internal/x86/ggen.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package x86 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" ) @@ -30,7 +30,7 @@ func defframe(ptxt *obj.Prog) { ax := uint32(0) for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next { n = l.N - if !n.Needzero { + if !n.Name.Needzero { continue } if n.Class != gc.PAUTO { @@ -216,9 +216,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node, ax *gc.Node, dx *gc.N check := 0 if gc.Issigned[t.Etype] { check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -1<<uint64(t.Width*8-1) { + if gc.Isconst(nl, gc.CTINT) && nl.Int() != -1<<uint64(t.Width*8-1) { check = 0 - } else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 { + } else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 { check = 0 } } @@ -391,7 +391,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { var n1 gc.Node gc.Regalloc(&n1, nl.Type, res) gmove(&n2, &n1) - sc := uint64(gc.Mpgetfix(nr.Val.U.Xval)) + sc := uint64(nr.Int()) if sc >= uint64(nl.Type.Width*8) { // large shift gets 2 shifts by width-1 gins(a, ncon(uint32(w)-1), &n1) diff --git a/src/cmd/8g/gsubr.go b/src/cmd/compile/internal/x86/gsubr.go index 34ddfe0619..baf251781c 100644 --- a/src/cmd/8g/gsubr.go +++ b/src/cmd/compile/internal/x86/gsubr.go @@ -28,10 +28,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package x86 import ( - "cmd/internal/gc" + "cmd/compile/internal/big" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" "fmt" @@ -582,6 +583,45 @@ func ginscon(as int, c int64, n2 *gc.Node) { gins(as, &n1, n2) } +func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { + if gc.Isint[t.Etype] || int(t.Etype) == gc.Tptr { + if (n1.Op == gc.OLITERAL || n1.Op == gc.OADDR && n1.Left.Op == gc.ONAME) && n2.Op != gc.OLITERAL { + // Reverse comparison to place constant (including address constant) last. + op = gc.Brrev(op) + n1, n2 = n2, n1 + } + } + + // General case. + var r1, r2, g1, g2 gc.Node + if n1.Op == gc.ONAME && n1.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG { + r1 = *n1 + } else { + gc.Regalloc(&r1, t, n1) + gc.Regalloc(&g1, n1.Type, &r1) + gc.Cgen(n1, &g1) + gmove(&g1, &r1) + } + if n2.Op == gc.OLITERAL && gc.Isint[t.Etype] || n2.Op == gc.OADDR && n2.Left.Op == gc.ONAME && n2.Left.Class == gc.PEXTERN { + r2 = *n2 + } else { + gc.Regalloc(&r2, t, n2) + gc.Regalloc(&g2, n1.Type, &r2) + gc.Cgen(n2, &g2) + gmove(&g2, &r2) + } + gins(optoas(gc.OCMP, t), &r1, &r2) + if r1.Op == gc.OREGISTER { + gc.Regfree(&g1) + gc.Regfree(&r1) + } + if r2.Op == gc.OREGISTER { + gc.Regfree(&g2) + gc.Regfree(&r2) + } + return gc.Gbranch(optoas(op, t), nil, likely) +} + /* * swap node contents */ @@ -602,7 +642,7 @@ func ncon(i uint32) *gc.Node { if ncon_n.Type == nil { gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0) } - gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i)) + ncon_n.SetInt(int64(i)) return &ncon_n } @@ -638,7 +678,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { case gc.ONAME: if n.Class == gc.PPARAMREF { var n1 gc.Node - gc.Cgen(n.Heapaddr, &n1) + gc.Cgen(n.Name.Heapaddr, &n1) sclean[nsclean-1] = n1 n = &n1 } @@ -660,8 +700,8 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { case gc.OLITERAL: var n1 gc.Node - gc.Convconst(&n1, n.Type, &n.Val) - i := gc.Mpgetfix(n1.Val.U.Xval) + n.Convconst(&n1, n.Type) + i := n1.Int() gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i))) i >>= 32 if n.Type.Etype == gc.TINT64 { @@ -682,36 +722,36 @@ func splitclean() { } } -/* - * set up nodes representing fp constants - */ -var zerof gc.Node - -var two64f gc.Node - -var two63f gc.Node - -var bignodes_did int +// set up nodes representing fp constants +var ( + zerof gc.Node + two63f gc.Node + two64f gc.Node + bignodes_did bool +) func bignodes() { - if bignodes_did != 0 { + if bignodes_did { return } - bignodes_did = 1 + bignodes_did = true + + gc.Nodconst(&zerof, gc.Types[gc.TINT64], 0) + zerof.Convconst(&zerof, gc.Types[gc.TFLOAT64]) - two64f = *ncon(0) - two64f.Type = gc.Types[gc.TFLOAT64] - two64f.Val.Ctype = gc.CTFLT - two64f.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovecflt(two64f.Val.U.Fval, 18446744073709551616.) + var i big.Int + i.SetInt64(1) + i.Lsh(&i, 63) + var bigi gc.Node - two63f = two64f - two63f.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovecflt(two63f.Val.U.Fval, 9223372036854775808.) + gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) + bigi.SetBigInt(&i) + bigi.Convconst(&two63f, gc.Types[gc.TFLOAT64]) - zerof = two64f - zerof.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovecflt(zerof.Val.U.Fval, 0) + gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) + i.Lsh(&i, 1) + bigi.SetBigInt(&i) + bigi.Convconst(&two64f, gc.Types[gc.TFLOAT64]) } func memname(n *gc.Node, t *gc.Type) { @@ -750,7 +790,7 @@ func gmove(f *gc.Node, t *gc.Node) { // convert constant to desired type if f.Op == gc.OLITERAL { var con gc.Node - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) f = &con ft = gc.Simsimtype(con.Type) } @@ -1021,7 +1061,7 @@ func floatmove(f *gc.Node, t *gc.Node) { // convert constant to desired type if f.Op == gc.OLITERAL { var con gc.Node - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) f = &con ft = gc.Simsimtype(con.Type) diff --git a/src/cmd/8g/peep.go b/src/cmd/compile/internal/x86/peep.go index e309aea785..8b50eab077 100644 --- a/src/cmd/8g/peep.go +++ b/src/cmd/compile/internal/x86/peep.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package x86 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" "fmt" diff --git a/src/cmd/8g/prog.go b/src/cmd/compile/internal/x86/prog.go index 1346c20f2b..f96a1aa945 100644 --- a/src/cmd/8g/prog.go +++ b/src/cmd/compile/internal/x86/prog.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package x86 import ( - "cmd/internal/gc" + "cmd/compile/internal/gc" "cmd/internal/obj" "cmd/internal/obj/x86" ) diff --git a/src/cmd/8g/reg.go b/src/cmd/compile/internal/x86/reg.go index 50b5b97ab1..8c97171e47 100644 --- a/src/cmd/8g/reg.go +++ b/src/cmd/compile/internal/x86/reg.go @@ -28,10 +28,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package x86 import "cmd/internal/obj/x86" -import "cmd/internal/gc" +import "cmd/compile/internal/gc" const ( NREGVAR = 16 /* 8 integer + 8 floating */ diff --git a/src/cmd/compile/main.go b/src/cmd/compile/main.go new file mode 100644 index 0000000000..7b69c34424 --- /dev/null +++ b/src/cmd/compile/main.go @@ -0,0 +1,34 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/compile/internal/amd64" + "cmd/compile/internal/arm" + "cmd/compile/internal/arm64" + "cmd/compile/internal/ppc64" + "cmd/compile/internal/x86" + "cmd/internal/obj" + "fmt" + "os" +) + +func main() { + switch obj.Getgoarch() { + default: + fmt.Fprintf(os.Stderr, "compile: unknown architecture %q\n", obj.Getgoarch()) + os.Exit(2) + case "386": + x86.Main() + case "amd64", "amd64p32": + amd64.Main() + case "arm": + arm.Main() + case "arm64": + arm64.Main() + case "ppc64", "ppc64le": + ppc64.Main() + } +} diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 64b2399972..0cdb7d69f7 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -20,7 +20,6 @@ var ( goarch string gobin string gohostarch string - gohostchar string gohostos string goos string goarm string @@ -30,10 +29,8 @@ var ( goextlinkenabled string workdir string tooldir string - gochar string oldgoos string oldgoarch string - oldgochar string slash string exe string defaultcc string @@ -48,17 +45,13 @@ var ( vflag int // verbosity ) -// The known architecture letters. -var gochars = "5667899" - // The known architectures. var okgoarch = []string{ - // same order as gochars - "arm", + "386", "amd64", "amd64p32", + "arm", "arm64", - "386", "ppc64", "ppc64le", } @@ -147,22 +140,18 @@ func xinit() { gohostarch = b } - i := find(gohostarch, okgoarch) - if i < 0 { + if find(gohostarch, okgoarch) < 0 { fatal("unknown $GOHOSTARCH %s", gohostarch) } - gohostchar = gochars[i : i+1] b = os.Getenv("GOARCH") if b == "" { b = gohostarch } goarch = b - i = find(goarch, okgoarch) - if i < 0 { + if find(goarch, okgoarch) < 0 { fatal("unknown $GOARCH %s", goarch) } - gochar = gochars[i : i+1] b = os.Getenv("GO_EXTLINK_ENABLED") if b != "" { @@ -374,7 +363,7 @@ var oldtool = []string{ // Unreleased directories (relative to $GOROOT) that should // not be in release branches. var unreleased = []string{ - "src/cmd/link", + "src/cmd/newlink", "src/cmd/objwriter", "src/debug/goobj", "src/old", @@ -436,7 +425,7 @@ func setup() { } // If $GOBIN is set and has a Go compiler, it must be cleaned. - for _, char := range gochars { + for _, char := range "56789" { if isfile(pathf("%s%s%c%s", gobin, slash, char, "g")) { for _, old := range oldtool { xremove(pathf("%s/%s", gobin, old)) @@ -540,7 +529,7 @@ func install(dir string) { if elem == "go" { elem = "go_bootstrap" } - link = []string{fmt.Sprintf("%s/%sl", tooldir, gochar), "-o", pathf("%s/%s%s", tooldir, elem, exe)} + link = []string{pathf("%s/link", tooldir), "-o", pathf("%s/%s%s", tooldir, elem, exe)} targ = len(link) - 1 } ttarg := mtime(link[targ]) @@ -675,7 +664,7 @@ func install(dir string) { } else { archive = b } - compile := []string{pathf("%s/%sg", tooldir, gochar), "-pack", "-o", b, "-p", pkg} + compile := []string{pathf("%s/compile", tooldir), "-pack", "-o", b, "-p", pkg} if dir == "runtime" { compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir)) } @@ -703,11 +692,7 @@ func install(dir string) { b := pathf("%s/%s", workdir, filepath.Base(p)) // Change the last character of the output file (which was c or s). - if gohostos == "plan9" { - b = b[:len(b)-1] + gohostchar - } else { - b = b[:len(b)-1] + "o" - } + b = b[:len(b)-1] + "o" compile = append(compile, "-o", b, p) bgrun(path, compile...) @@ -897,17 +882,9 @@ var buildorder = []string{ // compilers but build only the $GOARCH ones. var cleantab = []string{ // Commands and C libraries. - "cmd/5g", - "cmd/5l", - "cmd/6g", - "cmd/6l", - "cmd/7g", - "cmd/7l", - "cmd/8g", - "cmd/8l", - "cmd/9g", - "cmd/9l", + "cmd/compile", "cmd/go", + "cmd/link", "cmd/old5a", "cmd/old6a", "cmd/old8a", @@ -1043,7 +1020,6 @@ func cmdenv() { xprintf(format, "GOHOSTARCH", gohostarch) xprintf(format, "GOHOSTOS", gohostos) xprintf(format, "GOTOOLDIR", tooldir) - xprintf(format, "GOCHAR", gochar) if goarch == "arm" { xprintf(format, "GOARM", goarm) } @@ -1088,10 +1064,8 @@ func cmdbootstrap() { // For the main bootstrap, building for host os/arch. oldgoos = goos oldgoarch = goarch - oldgochar = gochar goos = gohostos goarch = gohostarch - gochar = gohostchar os.Setenv("GOHOSTARCH", gohostarch) os.Setenv("GOHOSTOS", gohostos) os.Setenv("GOARCH", goarch) @@ -1105,37 +1079,22 @@ func cmdbootstrap() { // than in a standard release like Go 1.4, so don't do this rebuild by default. if false { xprintf("##### Building Go toolchain using itself.\n") - for _, pattern := range buildorder { - if pattern == "cmd/go" { + for _, dir := range buildorder { + if dir == "cmd/go" { break } - dir := pattern - if strings.Contains(pattern, "%s") { - dir = fmt.Sprintf(pattern, gohostchar) - } install(dir) - if oldgochar != gohostchar && strings.Contains(pattern, "%s") { - install(fmt.Sprintf(pattern, oldgochar)) - } } xprintf("\n") } xprintf("##### Building compilers and go_bootstrap for host, %s/%s.\n", gohostos, gohostarch) - for _, pattern := range buildorder { - dir := pattern - if strings.Contains(pattern, "%s") { - dir = fmt.Sprintf(pattern, gohostchar) - } + for _, dir := range buildorder { install(dir) - if oldgochar != gohostchar && strings.Contains(pattern, "%s") { - install(fmt.Sprintf(pattern, oldgochar)) - } } goos = oldgoos goarch = oldgoarch - gochar = oldgochar os.Setenv("GOARCH", goarch) os.Setenv("GOOS", goos) diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go index f5037fab88..7988129868 100644 --- a/src/cmd/dist/buildtool.go +++ b/src/cmd/dist/buildtool.go @@ -23,31 +23,34 @@ import ( // which are commands, and entries beginning with internal/, which are // packages supporting the commands. var bootstrapDirs = []string{ - "5g", - "5l", - "6g", - "6l", - "7g", - "7l", - "8g", - "8l", - "9g", - "9l", "asm", "asm/internal/arch", "asm/internal/asm", "asm/internal/flags", "asm/internal/lex", + "compile", + "compile/internal/amd64", + "compile/internal/arm", + "compile/internal/arm64", + "compile/internal/big", + "compile/internal/gc", + "compile/internal/ppc64", + "compile/internal/ssa", + "compile/internal/x86", "internal/asm", - "internal/gc/big", - "internal/gc", - "internal/ld", + "internal/gcprog", "internal/obj", "internal/obj/arm", "internal/obj/arm64", "internal/obj/ppc64", "internal/obj/x86", - "internal/ssa", + "link", + "link/internal/amd64", + "link/internal/arm", + "link/internal/arm64", + "link/internal/ld", + "link/internal/ppc64", + "link/internal/x86", "old5a", "old6a", "old8a", diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 1ed099583e..f5a0dc50f1 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -14,6 +14,7 @@ import ( "os/exec" "path/filepath" "regexp" + "runtime" "strconv" "strings" "time" @@ -23,8 +24,11 @@ func cmdtest() { var t tester flag.BoolVar(&t.listMode, "list", false, "list available tests") flag.BoolVar(&t.noRebuild, "no-rebuild", false, "don't rebuild std and cmd packages") + flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred") flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners") - flag.StringVar(&t.runRxStr, "run", "", "run only those tests matching the regular expression; empty means to run all") + flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"), + "run only those tests matching the regular expression; empty means to run all. "+ + "Special exception: if the string begins with '!', the match is inverted.") xflagparse(0) t.run() } @@ -33,8 +37,10 @@ func cmdtest() { type tester struct { listMode bool noRebuild bool + keepGoing bool runRxStr string runRx *regexp.Regexp + runRxWant bool banner string // prefix, or "" for none goroot string @@ -129,6 +135,19 @@ func (t *tester) run() { } if t.runRxStr != "" { + // Temporary (2015-05-14) special case for "std", + // which the plan9 builder was using for ages. Delete + // this once we update dashboard/builders.go to use a + // regexp instead. + if runtime.GOOS == "plan9" && t.runRxStr == "std" { + t.runRxStr = "^go_test:" + } + if t.runRxStr[0] == '!' { + t.runRxWant = false + t.runRxStr = t.runRxStr[1:] + } else { + t.runRxWant = true + } t.runRx = regexp.MustCompile(t.runRxStr) } @@ -146,8 +165,9 @@ func (t *tester) run() { os.Unsetenv("GOROOT_FINAL") var lastHeading string + ok := true for _, dt := range t.tests { - if t.runRx != nil && !t.runRx.MatchString(dt.name) { + if t.runRx != nil && (t.runRx.MatchString(dt.name) != t.runRxWant) { t.partial = true continue } @@ -159,10 +179,18 @@ func (t *tester) run() { fmt.Printf("# go tool dist test -run=^%s$\n", dt.name) } if err := dt.fn(); err != nil { - log.Fatalf("Failed: %v", err) + ok = false + if t.keepGoing { + log.Printf("Failed: %v", err) + } else { + log.Fatalf("Failed: %v", err) + } } } - if t.partial { + if !ok { + fmt.Println("\nFAILED") + os.Exit(1) + } else if t.partial { fmt.Println("\nALL TESTS PASSED (some were excluded)") } else { fmt.Println("\nALL TESTS PASSED") @@ -173,52 +201,71 @@ func (t *tester) timeout(sec int) string { return "-timeout=" + fmt.Sprint(time.Duration(sec)*time.Second*time.Duration(t.timeoutScale)) } -func (t *tester) registerTests() { - // Register a separate logical test for each package in the standard library - // but actually group them together at execution time to share the cost of - // building packages shared between them. - all, err := exec.Command("go", "list", "std", "cmd").Output() - if err != nil { - log.Fatalf("Error running go list std cmd: %v", err) +// ranGoTest and stdMatches are state closed over by the stdlib +// testing func in registerStdTest below. The tests are run +// sequentially, so there's no need for locks. +var ( + ranGoTest bool + stdMatches []string +) + +func (t *tester) registerStdTest(pkg string) { + testName := "go_test:" + pkg + if t.runRx == nil || t.runRx.MatchString(testName) { + stdMatches = append(stdMatches, pkg) + } + t.tests = append(t.tests, distTest{ + name: testName, + heading: "Testing packages.", + fn: func() error { + if ranGoTest { + return nil + } + ranGoTest = true + cmd := exec.Command("go", append([]string{ + "test", + "-short", + t.timeout(120), + "-gcflags=" + os.Getenv("GO_GCFLAGS"), + }, stdMatches...)...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() + }, + }) +} + +// validStdPkg reports whether pkg looks like a standard library package name. +// Notably, it's not blank and doesn't contain regexp characters. +func validStdPkg(pkg string) bool { + if pkg == "" { + return false } - // ranGoTest and stdMatches are state closed over by the - // stdlib testing func below. The tests are run sequentially, - // so there's no need for locks. - var ( - ranGoTest bool - stdMatches []string - ) - for _, pkg := range strings.Fields(string(all)) { - testName := "go_test:" + pkg - if t.runRx == nil || t.runRx.MatchString(testName) { - stdMatches = append(stdMatches, pkg) + for _, r := range pkg { + switch { + case 'a' <= r && r <= 'z': + case 'A' <= r && r <= 'Z': + case '0' <= r && r <= '9': + case r == '_': + case r == '/': + default: + return false } - t.tests = append(t.tests, distTest{ - name: testName, - heading: "Testing packages.", - fn: func() error { - if ranGoTest { - return nil - } - ranGoTest = true - cmd := exec.Command("go", append([]string{ - "test", - "-short", - t.timeout(120), - "-gcflags=" + os.Getenv("GO_GCFLAGS"), - }, stdMatches...)...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() - }, - }) } + return true +} - // Old hack for when Plan 9 on GCE was too slow. - // We're keeping this until test sharding (Issue 10029) is finished, though. - if os.Getenv("GOTESTONLY") == "std" { - t.partial = true - return +func (t *tester) registerTests() { + // Fast path to avoid the ~1 second of `go list std cmd` when + // the caller passed -run=^go_test:foo/bar$ (as the continuous + // build coordinator does). + if strings.HasPrefix(t.runRxStr, "^go_test:") && strings.HasSuffix(t.runRxStr, "$") { + pkg := strings.TrimPrefix(t.runRxStr, "^go_test:") + pkg = strings.TrimSuffix(pkg, "$") + if validStdPkg(pkg) { + t.registerStdTest(pkg) + return + } } // Runtime CPU tests. @@ -244,9 +291,7 @@ func (t *tester) registerTests() { }, }) - iOS := t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64") - - if t.cgoEnabled && t.goos != "android" && !iOS { + if t.cgoEnabled && t.goos != "android" && !t.iOS() { // Disabled on android and iOS. golang.org/issue/8345 t.tests = append(t.tests, distTest{ name: "cgo_stdio", @@ -265,7 +310,7 @@ func (t *tester) registerTests() { }, }) } - if t.cgoEnabled && t.goos != "android" && !iOS { + if t.cgoEnabled && t.goos != "android" && !t.iOS() { // TODO(crawshaw): reenable on android and iOS // golang.org/issue/8345 // @@ -295,7 +340,7 @@ func (t *tester) registerTests() { heading: "../misc/cgo/testso", fn: t.cgoTestSOWindows, }) - } else if t.hasBash() && t.goos != "android" && !iOS { + } else if t.hasBash() && t.goos != "android" && !t.iOS() { t.registerTest("testso", "../misc/cgo/testso", "./test.bash") } if t.supportedBuildmode("c-archive") { @@ -305,28 +350,28 @@ func (t *tester) registerTests() { t.registerTest("testcshared", "../misc/cgo/testcshared", "./test.bash") } if t.supportedBuildmode("shared") { - t.registerTest("testshared", "../misc/cgo/testshared", "./test.bash") + t.registerTest("testshared", "../misc/cgo/testshared", "go", "test") } if t.gohostos == "linux" && t.goarch == "amd64" { t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go") } - if t.hasBash() && t.goos != "android" && !iOS && t.gohostos != "windows" { + if t.hasBash() && t.goos != "android" && !t.iOS() && t.gohostos != "windows" { t.registerTest("cgo_errors", "../misc/cgo/errors", "./test.bash") } if t.gohostos == "linux" && t.extLink() { t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", "main.go") } } - if t.hasBash() && t.goos != "nacl" && t.goos != "android" && !iOS { + if t.hasBash() && t.goos != "nacl" && t.goos != "android" && !t.iOS() { t.registerTest("doc_progs", "../doc/progs", "time", "go", "run", "run.go") t.registerTest("wiki", "../doc/articles/wiki", "./test.bash") t.registerTest("codewalk", "../doc/codewalk", "time", "./run") t.registerTest("shootout", "../test/bench/shootout", "time", "./timing.sh", "-test") } - if t.goos != "android" && !iOS { + if t.goos != "android" && !t.iOS() { t.registerTest("bench_go1", "../test/bench/go1", "go", "test") } - if t.goos != "android" && !iOS { + if t.goos != "android" && !t.iOS() { // TODO(bradfitz): shard down into these tests, as // this is one of the slowest (and most shardable) // tests. @@ -336,7 +381,7 @@ func (t *tester) registerTests() { fn: t.testDirTest, }) } - if t.goos != "nacl" && t.goos != "android" && !iOS { + if t.goos != "nacl" && t.goos != "android" && !t.iOS() { t.tests = append(t.tests, distTest{ name: "api", heading: "API check", @@ -346,6 +391,44 @@ func (t *tester) registerTests() { }) } + // Register the standard library tests lasts, to avoid the ~1 second latency + // of running `go list std cmd` if we're running a specific test. + // Now we know the names of all the other tests registered so far. + if !t.wantSpecificRegisteredTest() { + all, err := exec.Command("go", "list", "std", "cmd").Output() + if err != nil { + log.Fatalf("Error running go list std cmd: %v", err) + } + // Put the standard library tests first. + orig := t.tests + t.tests = nil + for _, pkg := range strings.Fields(string(all)) { + t.registerStdTest(pkg) + } + t.tests = append(t.tests, orig...) + } +} + +// wantSpecificRegisteredTest reports whether the caller is requesting a +// run of a specific test via the flag -run=^TESTNAME$ (as is done by the +// continuous build coordinator). +func (t *tester) wantSpecificRegisteredTest() bool { + if !strings.HasPrefix(t.runRxStr, "^") || !strings.HasSuffix(t.runRxStr, "$") { + return false + } + test := t.runRxStr[1 : len(t.runRxStr)-1] + return t.isRegisteredTestName(test) +} + +// isRegisteredTestName reports whether a test named testName has already +// been registered. +func (t *tester) isRegisteredTestName(testName string) bool { + for _, tt := range t.tests { + if tt.name == testName { + return true + } + } + return false } func (t *tester) registerTest(name, dirBanner, bin string, args ...string) { diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go index b3be2a975b..18dafc298c 100644 --- a/src/cmd/doc/main.go +++ b/src/cmd/doc/main.go @@ -132,11 +132,12 @@ func parseArgs() (*build.Package, string, string) { // slash+1: if there's no slash, the value is -1 and start is 0; otherwise // start is the byte after the slash. for start := slash + 1; start < len(arg); start = period + 1 { - period = start + strings.Index(arg[start:], ".") + period = strings.Index(arg[start:], ".") symbol := "" if period < 0 { period = len(arg) } else { + period += start symbol = arg[period+1:] } // Have we identified a package already? diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index 3a0aa7ff89..5c8976b663 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -115,7 +115,7 @@ func (pkg *Package) emit(comment string, node ast.Node) { log.Fatal(err) } if comment != "" { - pkg.newlines(1) + pkg.newlines(2) // Guarantee blank line before comment. doc.ToText(&pkg.buf, comment, " ", "\t", 80) } pkg.newlines(1) @@ -190,6 +190,7 @@ func (pkg *Package) packageDoc() { pkg.valueSummary(pkg.doc.Vars) pkg.funcSummary(pkg.doc.Funcs) pkg.typeSummary() + pkg.bugs() } // packageClause prints the package clause. @@ -253,6 +254,18 @@ func (pkg *Package) typeSummary() { } } +// bugs prints the BUGS information for the package. +// TODO: Provide access to TODOs and NOTEs as well (very noisy so off by default)? +func (pkg *Package) bugs() { + if pkg.doc.Notes["BUG"] == nil { + return + } + pkg.Printf("\n") + for _, note := range pkg.doc.Notes["BUG"] { + pkg.Printf("%s: %v\n", "BUG", note.Body) + } +} + // findValues finds the doc.Values that describe the symbol. func (pkg *Package) findValues(symbol string, docValues []*doc.Value) (values []*doc.Value) { for _, value := range docValues { @@ -332,13 +345,16 @@ func (pkg *Package) symbolDoc(symbol string) { } decl := typ.Decl spec := pkg.findTypeSpec(decl, typ.Name) - trimUnexportedFields(spec) + trimUnexportedElems(spec) // If there are multiple types defined, reduce to just this one. if len(decl.Specs) > 1 { decl.Specs = []ast.Spec{spec} } pkg.emit(typ.Doc, decl) // Show associated methods, constants, etc. + if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 { + pkg.Printf("\n") + } pkg.valueSummary(typ.Consts) pkg.valueSummary(typ.Vars) pkg.funcSummary(typ.Funcs) @@ -353,22 +369,26 @@ func (pkg *Package) symbolDoc(symbol string) { } } -// trimUnexportedFields modifies spec in place to elide unexported fields (unless -// the unexported flag is set). If spec is not a structure declartion, nothing happens. -func trimUnexportedFields(spec *ast.TypeSpec) { +// trimUnexportedElems modifies spec in place to elide unexported fields from +// structs and methods from interfaces (unless the unexported flag is set). +func trimUnexportedElems(spec *ast.TypeSpec) { if *unexported { - // We're printing all fields. return } - // It must be a struct for us to care. (We show unexported methods in interfaces.) - structType, ok := spec.Type.(*ast.StructType) - if !ok { - return + switch typ := spec.Type.(type) { + case *ast.StructType: + typ.Fields = trimUnexportedFields(typ.Fields, "fields") + case *ast.InterfaceType: + typ.Methods = trimUnexportedFields(typ.Methods, "methods") } +} + +// trimUnexportedFields returns the field list trimmed of unexported fields. +func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList { trimmed := false - list := make([]*ast.Field, 0, len(structType.Fields.List)) - for _, field := range structType.Fields.List { - // Trims if any is unexported. Fine in practice. + list := make([]*ast.Field, 0, len(fields.List)) + for _, field := range fields.List { + // Trims if any is unexported. Good enough in practice. ok := true for _, name := range field.Names { if !isExported(name.Name) { @@ -381,19 +401,23 @@ func trimUnexportedFields(spec *ast.TypeSpec) { list = append(list, field) } } - if trimmed { - unexportedField := &ast.Field{ - Type: ast.NewIdent(""), // Hack: printer will treat this as a field with a named type. - Comment: &ast.CommentGroup{ - List: []*ast.Comment{ - &ast.Comment{ - Text: "// Has unexported fields.\n", - }, + if !trimmed { + return fields + } + unexportedField := &ast.Field{ + Type: ast.NewIdent(""), // Hack: printer will treat this as a field with a named type. + Comment: &ast.CommentGroup{ + List: []*ast.Comment{ + &ast.Comment{ + Text: fmt.Sprintf("// Has unexported %s.\n", what), }, }, - } - list = append(list, unexportedField) - structType.Fields.List = list + }, + } + return &ast.FieldList{ + Opening: fields.Opening, + List: append(list, unexportedField), + Closing: fields.Closing, } } diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index e0d4a6c0fe..2b1cbf98ec 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -503,6 +503,7 @@ syntax of package template. The default output is equivalent to -f Name string // package name Doc string // package documentation string Target string // install path + Shlib string // the shared library that contains this package (only set when -linkshared) Goroot bool // is this package in the Go root? Standard bool // is this package part of the standard Go library? Stale bool // would 'go install' do anything for this package? @@ -1053,7 +1054,7 @@ environment variable (see 'go help gopath'). If no import paths are given, the action applies to the package in the current directory. -There are three reserved names for paths that should not be used +There are four reserved names for paths that should not be used for packages to be built with the go tool: - "main" denotes the top-level package in a stand-alone executable. diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index fda126b008..17ff7e0cbb 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -547,9 +547,6 @@ var ( goarch string goos string exeSuffix string - - archCharVal string - archCharErr error ) func init() { @@ -558,16 +555,6 @@ func init() { if goos == "windows" { exeSuffix = ".exe" } - archCharVal, archCharErr = build.ArchChar(goarch) -} - -// archChar returns the architecture character. This is only needed -// for the gc toolchain, so only fail if we actually need it. -func archChar() string { - if archCharErr != nil { - fatalf("%s", archCharErr) - } - return archCharVal } // A builder holds global state about a build. @@ -782,8 +769,8 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha b.actionCache[key] = a return a } - pkgs := readpkglist(filepath.Join(p.build.PkgTargetRoot, shlib)) - a = b.libaction(shlib, pkgs, modeInstall, depMode) + pkgs := readpkglist(shlib) + a = b.libaction(filepath.Base(shlib), pkgs, modeInstall, depMode) b.actionCache[key2] = a b.actionCache[key] = a return a @@ -1208,7 +1195,7 @@ func (b *builder) build(a *action) (err error) { fmt.Fprintf(os.Stderr, "%s\n", a.p.ImportPath) } - if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" && archChar() != "" && + if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" && (!hasString(a.p.GoFiles, "zgoos_"+buildContext.GOOS+".go") || !hasString(a.p.GoFiles, "zgoarch_"+buildContext.GOARCH+".go")) { return fmt.Errorf("%s/%s must be bootstrapped using make%v", buildContext.GOOS, buildContext.GOARCH, defaultSuffix()) @@ -1371,15 +1358,8 @@ func (b *builder) build(a *action) (err error) { } } - var objExt string - if _, ok := buildToolchain.(gccgoToolchain); ok { - objExt = "o" - } else { - objExt = archChar() - } - for _, file := range cfiles { - out := file[:len(file)-len(".c")] + "." + objExt + out := file[:len(file)-len(".c")] + ".o" if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil { return err } @@ -1388,7 +1368,7 @@ func (b *builder) build(a *action) (err error) { // Assemble .s files. for _, file := range sfiles { - out := file[:len(file)-len(".s")] + "." + objExt + out := file[:len(file)-len(".s")] + ".o" if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil { return err } @@ -1532,7 +1512,7 @@ func (b *builder) linkShared(a *action) (err error) { } ldflags = append(ldflags, d.p.ImportPath+"="+d.target) } - return b.run(".", a.target, nil, buildToolExec, tool(archChar()+"l"), "-o", a.target, importArgs, ldflags) + return b.run(".", a.target, nil, buildToolExec, tool("link"), "-o", a.target, importArgs, ldflags) } // install is the action for installing a single package or executable. @@ -2109,18 +2089,18 @@ func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error type gcToolchain struct{} func (gcToolchain) compiler() string { - return tool(archChar() + "g") + return tool("compile") } func (gcToolchain) linker() string { - return tool(archChar() + "l") + return tool("link") } func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { if archive != "" { ofile = archive } else { - out := "_go_." + archChar() + out := "_go_.o" ofile = obj + out } @@ -2152,7 +2132,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix) } - args := []interface{}{buildToolExec, tool(archChar() + "g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs} + args := []interface{}{buildToolExec, tool("compile"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs} if ofile == archive { args = append(args, "-pack") } @@ -2182,9 +2162,22 @@ func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { } // Disable checks when additional flags are passed, as the old assemblers // don't implement some of them (e.g., -shared). - if verifyAsm && goarch != "arm64" && len(buildAsmflags) == 0 { - if err := toolVerify(b, p, "old"+archChar()+"a", ofile, args); err != nil { - return err + if verifyAsm && len(buildAsmflags) == 0 { + old := "" + switch goarch { + case "arm": + old = "old5a" + case "amd64", "amd64p32": + old = "old6a" + case "386": + old = "old8a" + case "ppc64", "ppc64le": + old = "old9a" + } + if old != "" { + if err := toolVerify(b, p, old, ofile, args); err != nil { + return err + } } } return nil @@ -2333,7 +2326,7 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, ldflags = setextld(ldflags, compiler) ldflags = append(ldflags, "-buildmode="+ldBuildmode) ldflags = append(ldflags, buildLdflags...) - return b.run(".", p.ImportPath, nil, buildToolExec, tool(archChar()+"l"), "-o", out, importArgs, ldflags, mainpkg) + return b.run(".", p.ImportPath, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags, mainpkg) } func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { @@ -2785,13 +2778,6 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi cgoflags := []string{} // TODO: make cgo not depend on $GOARCH? - var objExt string - if _, ok := buildToolchain.(gccgoToolchain); ok { - objExt = "o" - } else { - objExt = archChar() - } - if p.Standard && p.ImportPath == "runtime/cgo" { cgoflags = append(cgoflags, "-import_runtime_cgo=false") } @@ -2836,7 +2822,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi // cc _cgo_defun.c _, gccgo := buildToolchain.(gccgoToolchain) if gccgo { - defunObj := obj + "_cgo_defun." + objExt + defunObj := obj + "_cgo_defun.o" if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil { return nil, nil, err } diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go index 863eb4d26e..8d427b37c2 100644 --- a/src/cmd/go/env.go +++ b/src/cmd/go/env.go @@ -49,10 +49,6 @@ func mkEnv() []envVar { {"TERM", "dumb"}, } - if archCharErr == nil { - env = append(env, envVar{"GOCHAR", archChar()}) - } - if goos != "plan9" { cmd := b.gccCmd(".") env = append(env, envVar{"CC", cmd[0]}) diff --git a/src/cmd/go/fmt.go b/src/cmd/go/fmt.go index 65dc3ca599..1722b9d568 100644 --- a/src/cmd/go/fmt.go +++ b/src/cmd/go/fmt.go @@ -4,6 +4,11 @@ package main +import ( + "os" + "path/filepath" +) + func init() { addBuildFlagsNX(cmdFmt) } @@ -29,10 +34,31 @@ See also: go fix, go vet. } func runFmt(cmd *Command, args []string) { + gofmt := gofmtPath() for _, pkg := range packages(args) { // Use pkg.gofiles instead of pkg.Dir so that // the command only applies to this package, // not to packages in subdirectories. - run(stringList("gofmt", "-l", "-w", relPaths(pkg.allgofiles))) + run(stringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles))) } } + +func gofmtPath() string { + gofmt := "gofmt" + if toolIsWindows { + gofmt += toolWindowsExtension + } + + gofmtPath := filepath.Join(gobin, gofmt) + if _, err := os.Stat(gofmtPath); err == nil { + return gofmtPath + } + + gofmtPath = filepath.Join(goroot, "bin", gofmt) + if _, err := os.Stat(gofmtPath); err == nil { + return gofmtPath + } + + // fallback to looking for gofmt in $PATH + return "gofmt" +} diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go index 56e8493e1a..2062f0c4ee 100644 --- a/src/cmd/go/help.go +++ b/src/cmd/go/help.go @@ -47,7 +47,7 @@ environment variable (see 'go help gopath'). If no import paths are given, the action applies to the package in the current directory. -There are three reserved names for paths that should not be used +There are four reserved names for paths that should not be used for packages to be built with the go tool: - "main" denotes the top-level package in a stand-alone executable. diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index 9466aad6a6..601c30362f 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -394,25 +394,17 @@ const ( // goTools is a map of Go program import path to install target directory. var goTools = map[string]targetDir{ - "cmd/5g": toTool, - "cmd/5l": toTool, - "cmd/6g": toTool, - "cmd/6l": toTool, - "cmd/7g": toTool, - "cmd/7l": toTool, - "cmd/8g": toTool, - "cmd/8l": toTool, - "cmd/9g": toTool, - "cmd/9l": toTool, "cmd/addr2line": toTool, "cmd/api": toTool, "cmd/asm": toTool, + "cmd/compile": toTool, "cmd/cgo": toTool, "cmd/cover": toTool, "cmd/dist": toTool, "cmd/doc": toTool, "cmd/fix": toTool, "cmd/link": toTool, + "cmd/newlink": toTool, "cmd/nm": toTool, "cmd/objdump": toTool, "cmd/old5a": toTool, @@ -536,7 +528,8 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package shlibnamefile := p.target[:len(p.target)-2] + ".shlibname" shlib, err := ioutil.ReadFile(shlibnamefile) if err == nil { - p.Shlib = strings.TrimSpace(string(shlib)) + libname := strings.TrimSpace(string(shlib)) + p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname) } else if !os.IsNotExist(err) { fatalf("unexpected error reading %s: %v", shlibnamefile, err) } @@ -680,10 +673,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package p.Target = p.target // The gc toolchain only permits C source files with cgo. - if len(p.CFiles) > 0 && !p.usesCgo() && buildContext.Compiler == "gc" { + if len(p.CFiles) > 0 && !p.usesCgo() && !p.usesSwig() && buildContext.Compiler == "gc" { p.Error = &PackageError{ ImportStack: stk.copy(), - Err: fmt.Sprintf("C source files not allowed when not using cgo: %s", strings.Join(p.CFiles, " ")), + Err: fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")), } return p } diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 408104d776..2179000afd 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -115,8 +115,12 @@ var vcsGit = &vcsCmd{ tagLookupCmd: []tagCmd{ {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`}, }, - tagSyncCmd: "checkout {tag}", - tagSyncDefault: "checkout master", + tagSyncCmd: "checkout {tag}", + // both createCmd and downloadCmd update the working dir. + // No need to do more here. We used to 'checkout master' + // but that doesn't work if the default branch is not named master. + // See golang.org/issue/9032. + tagSyncDefault: "", scheme: []string{"git", "https", "http", "git+ssh"}, pingCmd: "ls-remote {scheme}://{repo}", diff --git a/src/cmd/internal/asm/lexbody.go b/src/cmd/internal/asm/lexbody.go index b5e5d1eee2..a1519c8566 100644 --- a/src/cmd/internal/asm/lexbody.go +++ b/src/cmd/internal/asm/lexbody.go @@ -149,7 +149,7 @@ func newfile(s string, f *os.File) { } fi.P = nil - obj.Linklinehist(Ctxt, int(Lineno), s, 0) + Ctxt.LineHist.Push(int(Lineno), s) } var thetext *obj.LSym @@ -630,7 +630,7 @@ loop: n, _ = i.F.Read(i.B[:]) if n == 0 { i.F.Close() - obj.Linklinehist(Ctxt, int(Lineno), "<pop>", 0) + Ctxt.LineHist.Pop(int(Lineno)) goto pop } fi.P = i.B[1:n] diff --git a/src/cmd/internal/asm/macbody.go b/src/cmd/internal/asm/macbody.go index c488ea1e56..4565d3a37f 100644 --- a/src/cmd/internal/asm/macbody.go +++ b/src/cmd/internal/asm/macbody.go @@ -32,7 +32,6 @@ package asm import ( "bytes" - "cmd/internal/obj" "fmt" "os" "strings" @@ -683,7 +682,7 @@ func maclin() { } nn: - obj.Linklinehist(Ctxt, int(Lineno), symb, int(n)) + Ctxt.LineHist.Update(int(Lineno), symb, int(n)) return bad: @@ -796,7 +795,7 @@ func macprag() { /* * put pragma-line in as a funny history */ - obj.Linklinehist(Ctxt, int(Lineno), symb, -1) + Ctxt.AddImport(symb) return } if s != nil && s.Name == "pack" { diff --git a/src/cmd/internal/gc/go.errors b/src/cmd/internal/gc/go.errors deleted file mode 100644 index 8370a2007d..0000000000 --- a/src/cmd/internal/gc/go.errors +++ /dev/null @@ -1,81 +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 yaccerrors.go. - -package gc - -var yymsg = []struct { - yystate int - yychar int - msg string -}{ - // Each line of the form % token list - // is converted by yaccerrors.go 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 LIMPORT LNAME ';' - "missing import path; require quoted string"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';' - "missing { after if clause"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';' - "missing { after switch clause"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';' - "missing { after for clause"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY - "missing { after for clause"}, - - % 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 LVAR LNAME '=' comptype '{' LNAME ';' - "need trailing comma before newline in composite literal"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME - "nested func not allowed"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';' - "else must be followed by if or statement block"}, -} diff --git a/src/cmd/internal/gc/yaccerrors.go b/src/cmd/internal/gc/yaccerrors.go deleted file mode 100644 index 9dc54d9c8c..0000000000 --- a/src/cmd/internal/gc/yaccerrors.go +++ /dev/null @@ -1,194 +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. - -// +build ignore - -// 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. - -package main - -import ( - "bufio" - "fmt" - "io" - "log" - "os" - "strconv" - "strings" -) - -func xatoi(s string) int { - n, err := strconv.Atoi(s) - if err != nil { - log.Fatal(err) - } - return n -} - -func trimParen(s string) string { - s = strings.TrimPrefix(s, "(") - s = strings.TrimSuffix(s, ")") - return s -} - -type action struct { - token string - n int -} - -var shift = map[int][]action{} -var reduce = map[int][]action{} - -type rule struct { - lhs string - size int -} - -var rules = map[int]rule{} - -func readYaccOutput() { - r, err := os.Open("y.output") - if err != nil { - log.Fatal(err) - } - defer r.Close() - - var state int - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - f := strings.Fields(scanner.Text()) - nf := len(f) - - if nf >= 4 && f[1] == "terminals," && f[3] == "nonterminals" { - // We're done. - break - } - - if nf >= 2 && f[0] == "state" { - state = xatoi(f[1]) - continue - } - if nf >= 3 && (f[1] == "shift" || f[1] == "goto") { - shift[state] = append(shift[state], action{f[0], xatoi(f[2])}) - continue - } - if nf >= 3 && f[1] == "reduce" { - reduce[state] = append(reduce[state], action{f[0], xatoi(f[2])}) - continue - } - if nf >= 3 && strings.HasSuffix(f[0], ":") && strings.HasPrefix(f[nf-1], "(") && strings.HasSuffix(f[nf-1], ")") { - n := xatoi(trimParen(f[nf-1])) - - size := nf - 2 - if size == 1 && f[1] == "." { - size = 0 - } - - rules[n] = rule{strings.TrimSuffix(f[0], ":"), size} - continue - } - } -} - -func runMachine(w io.Writer, s string) { - f := strings.Fields(s) - - // Run it through the LR machine and print the induced "yystate, yychar," - // at the point where the error happens. - - var stack []int - state := 0 - i := 1 - tok := "" - -Loop: - if tok == "" && i < len(f) { - tok = f[i] - i++ - } - - for _, a := range shift[state] { - if a.token == tok { - if false { - fmt.Println("SHIFT ", tok, " ", state, " -> ", a) - } - stack = append(stack, state) - state = a.n - tok = "" - goto Loop - } - } - - for _, a := range reduce[state] { - if a.token == tok || a.token == "." { - stack = append(stack, state) - rule, ok := rules[a.n] - if !ok { - log.Fatal("missing rule") - } - stack = stack[:len(stack)-rule.size] - state = stack[len(stack)-1] - stack = stack[:len(stack)-1] - if tok != "" { - i-- - } - tok = rule.lhs - if false { - fmt.Println("REDUCE ", stack, " ", state, " ", tok, " rule ", rule) - } - goto Loop - } - } - - // No shift or reduce applied - found the error. - fmt.Fprintf(w, "\t{%d, %s,\n", state, tok) -} - -func processGoErrors() { - r, err := os.Open("go.errors") - if err != nil { - log.Fatal(err) - } - defer r.Close() - - w, err := os.Create("yymsg.go") - if err != nil { - log.Fatal(err) - } - defer w.Close() - - fmt.Fprintf(w, "// DO NOT EDIT - generated with go generate\n\n") - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - s := scanner.Text() - - // Treat % as first field on line as introducing a pattern (token sequence). - if strings.HasPrefix(strings.TrimSpace(s), "%") { - runMachine(w, s) - continue - } - - fmt.Fprintln(w, s) - } -} - -func main() { - readYaccOutput() - processGoErrors() -} diff --git a/src/cmd/internal/gc/yymsg.go b/src/cmd/internal/gc/yymsg.go deleted file mode 100644 index cb45cb8d1b..0000000000 --- a/src/cmd/internal/gc/yymsg.go +++ /dev/null @@ -1,83 +0,0 @@ -// DO NOT EDIT - generated with go generate - -// 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 yaccerrors.go. - -package gc - -var yymsg = []struct { - yystate int - yychar int - msg string -}{ - // Each line of the form % token list - // is converted by yaccerrors.go into the yystate and yychar caused - // by that token list. - - {332, ',', - "unexpected comma during import block"}, - - {89, ';', - "missing import path; require quoted string"}, - - {390, ';', - "missing { after if clause"}, - - {387, ';', - "missing { after switch clause"}, - - {279, ';', - "missing { after for clause"}, - - {498, LBODY, - "missing { after for clause"}, - - {17, '{', - "unexpected semicolon or newline before {"}, - - {111, ';', - "unexpected semicolon or newline in type declaration"}, - - {78, '}', - "unexpected } in channel type"}, - - {78, ')', - "unexpected ) in channel type"}, - - {78, ',', - "unexpected comma in channel type"}, - - {416, LELSE, - "unexpected semicolon or newline before else"}, - - {329, ',', - "name list not allowed in interface type"}, - - {279, LVAR, - "var declaration not allowed in for initializer"}, - - {25, '{', - "unexpected { at end of statement"}, - - {371, '{', - "unexpected { at end of statement"}, - - {122, ';', - "argument to go/defer must be function call"}, - - {398, ';', - "need trailing comma before newline in composite literal"}, - - {414, ';', - "need trailing comma before newline in composite literal"}, - - {124, LNAME, - "nested func not allowed"}, - - {650, ';', - "else must be followed by if or statement block"}, -} diff --git a/src/cmd/internal/gcprog/gcprog.go b/src/cmd/internal/gcprog/gcprog.go new file mode 100644 index 0000000000..5845f7d65e --- /dev/null +++ b/src/cmd/internal/gcprog/gcprog.go @@ -0,0 +1,298 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package gcprog implements an encoder for packed GC pointer bitmaps, +// known as GC programs. +// +// Program Format +// +// The GC program encodes a sequence of 0 and 1 bits indicating scalar or pointer words in an object. +// The encoding is a simple Lempel-Ziv program, with codes to emit literal bits and to repeat the +// last n bits c times. +// +// The possible codes are: +// +// 00000000: stop +// 0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes, least significant bit first +// 10000000 n c: repeat the previous n bits c times; n, c are varints +// 1nnnnnnn c: repeat the previous n bits c times; c is a varint +// +// The numbers n and c, when they follow a code, are encoded as varints +// using the same encoding as encoding/binary's Uvarint. +// +package gcprog + +import ( + "fmt" + "io" +) + +const progMaxLiteral = 127 // maximum n for literal n bit code + +// A Writer is an encoder for GC programs. +// +// The typical use of a Writer is to call Init, maybe call Debug, +// make a sequence of Ptr, Advance, Repeat, and Append calls +// to describe the data type, and then finally call End. +type Writer struct { + writeByte func(byte) + symoff int + index int64 + b [progMaxLiteral]byte + nb int + debug io.Writer + debugBuf []byte +} + +// Init initializes w to write a new GC program +// by calling writeByte for each byte in the program. +func (w *Writer) Init(writeByte func(byte)) { + w.writeByte = writeByte +} + +// Debug causes the writer to print a debugging trace to out +// during future calls to methods like Ptr, Advance, and End. +// It also enables debugging checks during the encoding. +func (w *Writer) Debug(out io.Writer) { + w.debug = out +} + +// BitIndex returns the number of bits written to the bit stream so far. +func (w *Writer) BitIndex() int64 { + return w.index +} + +// byte writes the byte x to the output. +func (w *Writer) byte(x byte) { + if w.debug != nil { + w.debugBuf = append(w.debugBuf, x) + } + w.writeByte(x) +} + +// End marks the end of the program, writing any remaining bytes. +func (w *Writer) End() { + w.flushlit() + w.byte(0) + if w.debug != nil { + index := progbits(w.debugBuf) + if index != w.index { + println("gcprog: End wrote program for", index, "bits, but current index is", w.index) + panic("gcprog: out of sync") + } + } +} + +// Ptr emits a 1 into the bit stream at the given bit index. +// that is, it records that the index'th word in the object memory is a pointer. +// Any bits between the current index and the new index +// are set to zero, meaning the corresponding words are scalars. +func (w *Writer) Ptr(index int64) { + if index < w.index { + println("gcprog: Ptr at index", index, "but current index is", w.index) + panic("gcprog: invalid Ptr index") + } + w.ZeroUntil(index) + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: ptr at %d\n", index) + } + w.lit(1) +} + +// ShouldRepeat reports whether it would be worthwhile to +// use a Repeat to describe c elements of n bits each, +// compared to just emitting c copies of the n-bit description. +func (w *Writer) ShouldRepeat(n, c int64) bool { + // Should we lay out the bits directly instead of + // encoding them as a repetition? Certainly if count==1, + // since there's nothing to repeat, but also if the total + // size of the plain pointer bits for the type will fit in + // 4 or fewer bytes, since using a repetition will require + // flushing the current bits plus at least one byte for + // the repeat size and one for the repeat count. + return c > 1 && c*n > 4*8 +} + +// Repeat emits an instruction to repeat the description +// of the last n words c times (including the initial description, c+1 times in total). +func (w *Writer) Repeat(n, c int64) { + if n == 0 || c == 0 { + return + } + w.flushlit() + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: repeat %d × %d\n", n, c) + } + if n < 128 { + w.byte(0x80 | byte(n)) + } else { + w.byte(0x80) + w.varint(n) + } + w.varint(c) + w.index += n * c +} + +// ZeroUntil adds zeros to the bit stream until reaching the given index; +// that is, it records that the words from the most recent pointer until +// the index'th word are scalars. +// ZeroUntil is usually called in preparation for a call to Repeat, Append, or End. +func (w *Writer) ZeroUntil(index int64) { + if index < w.index { + println("gcprog: Advance", index, "but index is", w.index) + panic("gcprog: invalid Advance index") + } + skip := (index - w.index) + if skip == 0 { + return + } + if skip < 4*8 { + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: advance to %d by literals\n", index) + } + for i := int64(0); i < skip; i++ { + w.lit(0) + } + return + } + + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: advance to %d by repeat\n", index) + } + w.lit(0) + w.flushlit() + w.Repeat(1, skip-1) +} + +// Append emits the given GC program into the current output. +// The caller asserts that the program emits n bits (describes n words), +// and Append panics if that is not true. +func (w *Writer) Append(prog []byte, n int64) { + w.flushlit() + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: append prog for %d ptrs\n", n) + fmt.Fprintf(w.debug, "\t") + } + n1 := progbits(prog) + if n1 != n { + panic("gcprog: wrong bit count in append") + } + // The last byte of the prog terminates the program. + // Don't emit that, or else our own program will end. + for i, x := range prog[:len(prog)-1] { + if w.debug != nil { + if i > 0 { + fmt.Fprintf(w.debug, " ") + } + fmt.Fprintf(w.debug, "%02x", x) + } + w.byte(x) + } + if w.debug != nil { + fmt.Fprintf(w.debug, "\n") + } + w.index += n +} + +// progbits returns the length of the bit stream encoded by the program p. +func progbits(p []byte) int64 { + var n int64 + for len(p) > 0 { + x := p[0] + p = p[1:] + if x == 0 { + break + } + if x&0x80 == 0 { + count := x &^ 0x80 + n += int64(count) + p = p[(count+7)/8:] + continue + } + nbit := int64(x &^ 0x80) + if nbit == 0 { + nbit, p = readvarint(p) + } + var count int64 + count, p = readvarint(p) + n += nbit * count + } + if len(p) > 0 { + println("gcprog: found end instruction after", n, "ptrs, with", len(p), "bytes remaining") + panic("gcprog: extra data at end of program") + } + return n +} + +// readvarint reads a varint from p, returning the value and the remainder of p. +func readvarint(p []byte) (int64, []byte) { + var v int64 + var nb uint + for { + c := p[0] + p = p[1:] + v |= int64(c&^0x80) << nb + nb += 7 + if c&0x80 == 0 { + break + } + } + return v, p +} + +// lit adds a single literal bit to w. +func (w *Writer) lit(x byte) { + if w.nb == progMaxLiteral { + w.flushlit() + } + w.b[w.nb] = x + w.nb++ + w.index++ +} + +// varint emits the varint encoding of x. +func (w *Writer) varint(x int64) { + if x < 0 { + panic("gcprog: negative varint") + } + for x >= 0x80 { + w.byte(byte(0x80 | x)) + x >>= 7 + } + w.byte(byte(x)) +} + +// flushlit flushes any pending literal bits. +func (w *Writer) flushlit() { + if w.nb == 0 { + return + } + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: flush %d literals\n", w.nb) + fmt.Fprintf(w.debug, "\t%v\n", w.b[:w.nb]) + fmt.Fprintf(w.debug, "\t%02x", byte(w.nb)) + } + w.byte(byte(w.nb)) + var bits uint8 + for i := 0; i < w.nb; i++ { + bits |= w.b[i] << uint(i%8) + if (i+1)%8 == 0 { + if w.debug != nil { + fmt.Fprintf(w.debug, " %02x", bits) + } + w.byte(bits) + bits = 0 + } + } + if w.nb%8 != 0 { + if w.debug != nil { + fmt.Fprintf(w.debug, " %02x", bits) + } + w.byte(bits) + } + if w.debug != nil { + fmt.Fprintf(w.debug, "\n") + } + w.nb = 0 +} diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index 6e00cb55ab..9e643932be 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -2677,8 +2677,8 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { case 59: /* stxr/stlxr */ o1 = opstore(ctxt, int(p.As)) - if p.To2.Type != obj.TYPE_NONE { - o1 |= uint32(p.To2.Reg&31) << 16 + if p.RegTo2 != obj.REG_NONE { + o1 |= uint32(p.RegTo2&31) << 16 } else { o1 |= 0x1F << 16 } diff --git a/src/cmd/internal/obj/line_test.go b/src/cmd/internal/obj/line_test.go index dde5d64e17..5486f0d648 100644 --- a/src/cmd/internal/obj/line_test.go +++ b/src/cmd/internal/obj/line_test.go @@ -13,13 +13,13 @@ func TestLineHist(t *testing.T) { ctxt := new(Link) ctxt.Hash = make(map[SymVer]*LSym) - Linklinehist(ctxt, 1, "a.c", 0) - Linklinehist(ctxt, 3, "a.h", 0) - Linklinehist(ctxt, 5, "<pop>", 0) - Linklinehist(ctxt, 7, "linedir", 2) - Linklinehist(ctxt, 9, "<pop>", 0) - Linklinehist(ctxt, 11, "b.c", 0) - Linklinehist(ctxt, 13, "<pop>", 0) + ctxt.LineHist.Push(1, "a.c") + ctxt.LineHist.Push(3, "a.h") + ctxt.LineHist.Pop(5) + ctxt.LineHist.Update(7, "linedir", 2) + ctxt.LineHist.Pop(9) + ctxt.LineHist.Push(11, "b.c") + ctxt.LineHist.Pop(13) var expect = []string{ 0: "??:0", diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 9f5e87b4c3..2fc12c1eb1 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -206,7 +206,6 @@ type Prog struct { From Addr From3 Addr To Addr - To2 Addr Opt interface{} Forwd *Prog Pcond *Prog @@ -217,12 +216,12 @@ type Prog struct { Spadj int32 As int16 Reg int16 + RegTo2 int16 // 2nd register output operand Mark uint16 Optab uint16 Scond uint8 Back uint8 Ft uint8 - F3t uint8 Tt uint8 Isize uint8 Printed uint8 diff --git a/src/cmd/internal/obj/mgc0.go b/src/cmd/internal/obj/mgc0.go index 2407deaf32..a385d607bb 100644 --- a/src/cmd/internal/obj/mgc0.go +++ b/src/cmd/internal/obj/mgc0.go @@ -22,16 +22,6 @@ package obj // Used by cmd/gc. const ( - GcBits = 4 - BitsPerPointer = 2 - BitsDead = 0 - BitsScalar = 1 - BitsPointer = 2 - BitsMask = 3 - PointersPerByte = 8 / BitsPerPointer -) - -const ( InsData = 1 + iota InsArray InsArrayEnd diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go index 39db2396e7..af3290d3a5 100644 --- a/src/cmd/internal/obj/obj.go +++ b/src/cmd/internal/obj/obj.go @@ -241,12 +241,6 @@ func (h *LineHist) LineString(lineno int) string { return text } -// TODO(rsc): Replace call sites with use of ctxt.LineHist. -// Note that all call sites use showAll=false, showFullPath=false. -func Linklinefmt(ctxt *Link, lineno int, showAll, showFullPath bool) string { - return ctxt.LineHist.LineString(lineno) -} - // FileLine returns the file name and line number // at the top of the stack for the given lineno. func (h *LineHist) FileLine(lineno int) (file string, line int) { @@ -287,30 +281,3 @@ func linkgetline(ctxt *Link, lineno int32, f **LSym, l *int32) { func Linkprfile(ctxt *Link, line int) { fmt.Printf("%s ", ctxt.LineHist.LineString(line)) } - -// Linklinehist pushes, amends, or pops an entry on the line history stack. -// If f != "<pop>" and n == 0, the call pushes the start of a new file named f at lineno. -// If f != "<pop>" and n > 0, the call amends the top of the stack to record that lineno -// now corresponds to f at line n. -// If f == "<pop>", the call pops the topmost entry from the stack, picking up -// the parent file at the line following the one where the corresponding push occurred. -// -// If n < 0, linklinehist records f as a package required by the current compilation -// (nothing to do with line numbers). -// -// TODO(rsc): Replace uses with direct calls to ctxt.Hist methods. -func Linklinehist(ctxt *Link, lineno int, f string, n int) { - switch { - case n < 0: - ctxt.AddImport(f) - - case f == "<pop>": - ctxt.LineHist.Pop(lineno) - - case n == 0: - ctxt.LineHist.Push(lineno, f) - - default: - ctxt.LineHist.Update(lineno, f, n) - } -} diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index b0b209184f..efecae62ac 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -213,10 +213,17 @@ func Getgoos() string { } func Getgoarm() string { - return envOr("GOARM", defaultGOARM) + switch v := envOr("GOARM", defaultGOARM); v { + case "5", "6", "7": + return v + } + // Fail here, rather than validate at multiple call sites. + log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.") + panic("unreachable") } func Getgo386() string { + // Validated by cmd/8g. return envOr("GO386", defaultGO386) } @@ -234,7 +241,7 @@ func Atoi(s string) int { } func (p *Prog) Line() string { - return Linklinefmt(p.Ctxt, int(p.Lineno), false, false) + return p.Ctxt.LineHist.LineString(int(p.Lineno)) } var armCondCode = []string{ @@ -320,8 +327,8 @@ func (p *Prog) String() string { if p.To.Type != TYPE_NONE { fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To)) } - if p.To2.Type != TYPE_NONE { - fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To2)) + if p.RegTo2 != REG_NONE { + fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2))) } return buf.String() } @@ -333,7 +340,7 @@ func (ctxt *Link) NewProg() *Prog { } func (ctxt *Link) Line(n int) string { - return Linklinefmt(ctxt, n, false, false) + return ctxt.LineHist.LineString(n) } func Getcallerpc(interface{}) uintptr { diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 0c0cc04548..2b9c2670df 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -2974,15 +2974,12 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { if p.Ft == 0 { p.Ft = uint8(oclass(ctxt, p, &p.From)) } - if p.F3t == 0 { - p.F3t = uint8(oclass(ctxt, p, &p.From3)) - } if p.Tt == 0 { p.Tt = uint8(oclass(ctxt, p, &p.To)) } ft := int(p.Ft) * Ymax - f3t := int(p.F3t) * Ymax + f3t := oclass(ctxt, p, &p.From3) * Ymax tt := int(p.Tt) * Ymax xo := obj.Bool2int(o.op[0] == 0x0f) diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index 7a4fc128e6..4798c8f7fb 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -350,9 +350,6 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { if p.From3.Name == obj.NAME_EXTERN { ctxt.Diag("don't know how to handle %v with -dynlink", p) } - if p.To2.Name == obj.NAME_EXTERN { - ctxt.Diag("don't know how to handle %v with -dynlink", p) - } var source *obj.Addr if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { diff --git a/src/cmd/internal/objfile/macho.go b/src/cmd/internal/objfile/macho.go index a6cd02b930..7371c0d9d1 100644 --- a/src/cmd/internal/objfile/macho.go +++ b/src/cmd/internal/objfile/macho.go @@ -13,6 +13,8 @@ import ( "sort" ) +const stabTypeMask = 0xe0 + type machoFile struct { macho *macho.File } @@ -34,12 +36,19 @@ func (f *machoFile) symbols() ([]Sym, error) { // We infer the size of a symbol by looking at where the next symbol begins. var addrs []uint64 for _, s := range f.macho.Symtab.Syms { - addrs = append(addrs, s.Value) + // Skip stab debug info. + if s.Type&stabTypeMask == 0 { + addrs = append(addrs, s.Value) + } } sort.Sort(uint64s(addrs)) var syms []Sym for _, s := range f.macho.Symtab.Syms { + if s.Type&stabTypeMask != 0 { + // Skip stab debug info. + continue + } sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'} i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) if i < len(addrs) { diff --git a/src/cmd/6l/asm.go b/src/cmd/link/internal/amd64/asm.go index a025ce6ea6..74ec9dd3ea 100644 --- a/src/cmd/6l/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -28,11 +28,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package amd64 import ( - "cmd/internal/ld" "cmd/internal/obj" + "cmd/link/internal/ld" "debug/elf" "fmt" "log" @@ -44,24 +44,6 @@ func PADDR(x uint32) uint32 { var zeroes string -func needlib(name string) int { - if name[0] == '\x00' { - return 0 - } - - /* reuse hash code in symbol table */ - p := fmt.Sprintf(".elfload.%s", name) - - s := ld.Linklookup(ld.Ctxt, p, 0) - - if s.Type == 0 { - s.Type = 100 // avoid SDATA, etc. - return 1 - } - - return 0 -} - func Addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) int64 { s.Reachable = true i := s.Size @@ -292,7 +274,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { break } if ld.Iself { - adddynsym(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) rela := ld.Linklookup(ld.Ctxt, ".rela", 0) ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off)) if r.Siz == 8 { @@ -316,7 +298,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { // 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(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) got := ld.Linklookup(ld.Ctxt, ".got", 0) s.Type = got.Type | obj.SSUB @@ -423,9 +405,9 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int { v = uint32(rs.Dynid) v |= 1 << 27 // external relocation } else { - v = uint32((rs.Sect.(*ld.Section)).Extnum) + v = uint32(rs.Sect.Extnum) if v == 0 { - ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type) + ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type) return -1 } } @@ -544,7 +526,7 @@ func addpltsym(s *ld.LSym) { return } - adddynsym(ld.Ctxt, s) + ld.Adddynsym(ld.Ctxt, s) if ld.Iself { plt := ld.Linklookup(ld.Ctxt, ".plt", 0) @@ -612,7 +594,7 @@ func addgotsym(s *ld.LSym) { return } - adddynsym(ld.Ctxt, s) + ld.Adddynsym(ld.Ctxt, s) got := ld.Linklookup(ld.Ctxt, ".got", 0) s.Got = int32(got.Size) ld.Adduint64(ld.Ctxt, got, 0) @@ -629,80 +611,6 @@ func addgotsym(s *ld.LSym) { } } -func adddynsym(ctxt *ld.Link, s *ld.LSym) { - if s.Dynid >= 0 { - return - } - - if ld.Iself { - s.Dynid = int32(ld.Nelfsym) - ld.Nelfsym++ - - d := ld.Linklookup(ctxt, ".dynsym", 0) - - name := s.Extname - ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name))) - - /* type */ - t := ld.STB_GLOBAL << 4 - - if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT { - t |= ld.STT_FUNC - } else { - t |= ld.STT_OBJECT - } - ld.Adduint8(ctxt, d, uint8(t)) - - /* reserved */ - ld.Adduint8(ctxt, d, 0) - - /* section where symbol is defined */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint16(ctxt, d, ld.SHN_UNDEF) - } else { - ld.Adduint16(ctxt, d, 1) - } - - /* value */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint64(ctxt, d, 0) - } else { - ld.Addaddr(ctxt, d, s) - } - - /* size of object */ - ld.Adduint64(ctxt, d, uint64(s.Size)) - - if s.Cgoexport&ld.CgoExportDynamic == 0 && s.Dynimplib != "" && needlib(s.Dynimplib) != 0 { - ld.Elfwritedynent(ld.Linklookup(ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), s.Dynimplib))) - } - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname) - } else if ld.HEADTYPE == obj.Hwindows { - } else // already taken care of - { - ld.Diag("adddynsym: unsupported binary format") - } -} - -func adddynlib(lib string) { - if needlib(lib) == 0 { - return - } - - if ld.Iself { - s := ld.Linklookup(ld.Ctxt, ".dynstr", 0) - if s.Size == 0 { - ld.Addstring(s, "") - } - ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib))) - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Machoadddynlib(lib) - } else { - ld.Diag("adddynlib: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) @@ -802,7 +710,7 @@ func asmb() { symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = int64(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink)) + symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) case obj.Hlinux, obj.Hfreebsd, diff --git a/src/cmd/6l/l.go b/src/cmd/link/internal/amd64/l.go index 6b42088de3..2537419eff 100644 --- a/src/cmd/6l/l.go +++ b/src/cmd/link/internal/amd64/l.go @@ -28,7 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package amd64 const ( thechar = '6' @@ -40,7 +40,8 @@ const ( MINLC = 1 ) -/* Used by ../ld/dwarf.c */ +/* Used by ../internal/ld/dwarf.go */ const ( DWARFREGSP = 7 + DWARFREGLR = 16 ) diff --git a/src/cmd/6l/obj.go b/src/cmd/link/internal/amd64/obj.go index 9e6dc60e2d..1aa4422ed9 100644 --- a/src/cmd/6l/obj.go +++ b/src/cmd/link/internal/amd64/obj.go @@ -28,18 +28,18 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package amd64 import ( - "cmd/internal/ld" "cmd/internal/obj" + "cmd/link/internal/ld" "fmt" "log" ) // Reading object files. -func main() { +func Main() { linkarchinit() ld.Ldmain() } @@ -59,10 +59,9 @@ func linkarchinit() { ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP + ld.Thearch.Dwarfreglr = DWARFREGLR - ld.Thearch.Adddynlib = adddynlib ld.Thearch.Adddynrel = adddynrel - ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant @@ -91,7 +90,7 @@ func archinit() { ld.Linkmode = ld.LinkInternal } - if ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() { + if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() { ld.Linkmode = ld.LinkExternal } @@ -169,14 +168,6 @@ func archinit() { ld.Elfinit() ld.HEADR = ld.ELFRESERVE - if ld.Buildmode == ld.BuildmodeShared { - // When building a shared library we write a package list - // note that can get quite large. The external linker will - // re-layout all the sections anyway, so making this larger - // just wastes a little space in the intermediate object - // file, not the final shared library. - ld.HEADR *= 3 - } if ld.INITTEXT == -1 { ld.INITTEXT = (1 << 22) + int64(ld.HEADR) } diff --git a/src/cmd/link/internal/amd64/z.go b/src/cmd/link/internal/amd64/z.go new file mode 100644 index 0000000000..f70035b9e3 --- /dev/null +++ b/src/cmd/link/internal/amd64/z.go @@ -0,0 +1 @@ +package amd64 diff --git a/src/cmd/5l/asm.go b/src/cmd/link/internal/arm/asm.go index 85ea684fc7..39d4550917 100644 --- a/src/cmd/5l/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -28,33 +28,15 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm import ( - "cmd/internal/ld" "cmd/internal/obj" + "cmd/link/internal/ld" "fmt" "log" ) -func needlib(name string) int { - if name[0] == '\x00' { - return 0 - } - - /* reuse hash code in symbol table */ - p := fmt.Sprintf(".dynlib.%s", name) - - s := ld.Linklookup(ld.Ctxt, p, 0) - - if s.Type == 0 { - s.Type = 100 // avoid SDATA, etc. - return 1 - } - - return 0 -} - func gentext() { } @@ -194,7 +176,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { break } if ld.Iself { - adddynsym(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) rel := ld.Linklookup(ld.Ctxt, ".rel", 0) ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off)) ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynmic reloc @@ -297,9 +279,9 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int { v = uint32(rs.Dynid) v |= 1 << 27 // external relocation } else { - v = uint32((rs.Sect.(*ld.Section)).Extnum) + v = uint32(rs.Sect.Extnum) if v == 0 { - ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type) + ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type) return -1 } } @@ -440,7 +422,7 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) { return } - adddynsym(ctxt, s) + ld.Adddynsym(ctxt, s) if ld.Iself { plt := ld.Linklookup(ctxt, ".plt", 0) @@ -495,7 +477,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) { return } - adddynsym(ctxt, s) + ld.Adddynsym(ctxt, s) got := ld.Linklookup(ctxt, ".got", 0) s.Got = int32(got.Size) ld.Adduint32(ctxt, got, 0) @@ -509,72 +491,6 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) { } } -func adddynsym(ctxt *ld.Link, s *ld.LSym) { - if s.Dynid >= 0 { - return - } - - if ld.Iself { - s.Dynid = int32(ld.Nelfsym) - ld.Nelfsym++ - - d := ld.Linklookup(ctxt, ".dynsym", 0) - - /* name */ - name := s.Extname - - ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name))) - - /* value */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint32(ctxt, d, 0) - } else { - ld.Addaddr(ctxt, d, s) - } - - /* size */ - ld.Adduint32(ctxt, d, 0) - - /* type */ - t := ld.STB_GLOBAL << 4 - - if (s.Cgoexport&ld.CgoExportDynamic != 0) && s.Type&obj.SMASK == obj.STEXT { - t |= ld.STT_FUNC - } else { - t |= ld.STT_OBJECT - } - ld.Adduint8(ctxt, d, uint8(t)) - ld.Adduint8(ctxt, d, 0) - - /* shndx */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint16(ctxt, d, ld.SHN_UNDEF) - } else { - ld.Adduint16(ctxt, d, 1) - } - } else { - ld.Diag("adddynsym: unsupported binary format") - } -} - -func adddynlib(lib string) { - if needlib(lib) == 0 { - return - } - - if ld.Iself { - s := ld.Linklookup(ld.Ctxt, ".dynstr", 0) - if s.Size == 0 { - ld.Addstring(s, "") - } - ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib))) - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Machoadddynlib(lib) - } else { - ld.Diag("adddynlib: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) @@ -617,14 +533,12 @@ func asmb() { fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - if ld.Debug['w'] == 0 { // TODO(minux): enable DWARF Support - dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) - ld.Cseek(int64(dwarfoff)) + dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + ld.Cseek(int64(dwarfoff)) - ld.Segdwarf.Fileoff = uint64(ld.Cpos()) - ld.Dwarfemitdebugsections() - ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff - } + ld.Segdwarf.Fileoff = uint64(ld.Cpos()) + ld.Dwarfemitdebugsections() + ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff machlink = uint32(ld.Domacholink()) } @@ -651,7 +565,7 @@ func asmb() { symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink)) + symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) } ld.Cseek(int64(symo)) diff --git a/src/cmd/5l/l.go b/src/cmd/link/internal/arm/l.go index a52154594d..4973772163 100644 --- a/src/cmd/5l/l.go +++ b/src/cmd/link/internal/arm/l.go @@ -28,7 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm // Writing object files. @@ -72,7 +72,8 @@ const ( MINLC = 4 ) -/* Used by ../ld/dwarf.c */ +/* Used by ../internal/ld/dwarf.go */ const ( DWARFREGSP = 13 + DWARFREGLR = 14 ) diff --git a/src/cmd/5l/obj.go b/src/cmd/link/internal/arm/obj.go index fa74908005..14fe7a64eb 100644 --- a/src/cmd/5l/obj.go +++ b/src/cmd/link/internal/arm/obj.go @@ -28,18 +28,18 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm import ( - "cmd/internal/ld" "cmd/internal/obj" + "cmd/link/internal/ld" "fmt" "log" ) // Reading object files. -func main() { +func Main() { linkarchinit() ld.Ldmain() } @@ -56,10 +56,9 @@ func linkarchinit() { ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP + ld.Thearch.Dwarfreglr = DWARFREGLR - ld.Thearch.Adddynlib = adddynlib ld.Thearch.Adddynrel = adddynrel - ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant diff --git a/src/cmd/7l/asm.go b/src/cmd/link/internal/arm64/asm.go index a17899dcf0..3aebd8a223 100644 --- a/src/cmd/7l/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -28,11 +28,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm64 import ( - "cmd/internal/ld" "cmd/internal/obj" + "cmd/link/internal/ld" "encoding/binary" "fmt" "log" @@ -40,24 +40,6 @@ import ( func gentext() {} -func needlib(name string) int { - if name[0] == '\x00' { - return 0 - } - - /* reuse hash code in symbol table */ - p := fmt.Sprintf(".dynlib.%s", name) - - s := ld.Linklookup(ld.Ctxt, p, 0) - - if s.Type == 0 { - s.Type = 100 // avoid SDATA, etc. - return 1 - } - - return 0 -} - func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) { log.Fatalf("adddynrela not implemented") } @@ -125,9 +107,9 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int { v = uint32(rs.Dynid) v |= 1 << 27 // external relocation } else { - v = uint32((rs.Sect.(*ld.Section)).Extnum) + v = uint32(rs.Sect.Extnum) if v == 0 { - ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type) + ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type) return -1 } } @@ -293,28 +275,6 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 { return -1 } -func adddynsym(ctxt *ld.Link, s *ld.LSym) { - // TODO(minux): implement when needed. -} - -func adddynlib(lib string) { - if needlib(lib) == 0 { - return - } - - if ld.Iself { - s := ld.Linklookup(ld.Ctxt, ".dynstr", 0) - if s.Size == 0 { - ld.Addstring(s, "") - } - ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib))) - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Machoadddynlib(lib) - } else { - ld.Diag("adddynlib: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) @@ -357,14 +317,12 @@ func asmb() { fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - if ld.Debug['w'] == 0 { // TODO(minux): enable DWARF Support - dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) - ld.Cseek(int64(dwarfoff)) + dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + ld.Cseek(int64(dwarfoff)) - ld.Segdwarf.Fileoff = uint64(ld.Cpos()) - ld.Dwarfemitdebugsections() - ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff - } + ld.Segdwarf.Fileoff = uint64(ld.Cpos()) + ld.Dwarfemitdebugsections() + ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff machlink = uint32(ld.Domacholink()) } @@ -391,7 +349,7 @@ func asmb() { symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink)) + symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) } ld.Cseek(int64(symo)) diff --git a/src/cmd/7l/l.go b/src/cmd/link/internal/arm64/l.go index 6f90acb107..8d0d57e72a 100644 --- a/src/cmd/7l/l.go +++ b/src/cmd/link/internal/arm64/l.go @@ -28,7 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm64 // Writing object files. @@ -71,7 +71,8 @@ const ( MINLC = 4 ) -/* Used by ../ld/dwarf.c */ +/* Used by ../internal/ld/dwarf.go */ const ( DWARFREGSP = 31 + DWARFREGLR = 30 ) diff --git a/src/cmd/7l/obj.go b/src/cmd/link/internal/arm64/obj.go index f8ac7d33ea..56f5815903 100644 --- a/src/cmd/7l/obj.go +++ b/src/cmd/link/internal/arm64/obj.go @@ -28,18 +28,18 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package arm64 import ( - "cmd/internal/ld" "cmd/internal/obj" + "cmd/link/internal/ld" "fmt" "log" ) // Reading object files. -func main() { +func Main() { linkarchinit() ld.Ldmain() } @@ -56,10 +56,9 @@ func linkarchinit() { ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP + ld.Thearch.Dwarfreglr = DWARFREGLR - ld.Thearch.Adddynlib = adddynlib ld.Thearch.Adddynrel = adddynrel - ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant diff --git a/src/cmd/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go index 0e59016edb..0e59016edb 100644 --- a/src/cmd/internal/ld/ar.go +++ b/src/cmd/link/internal/ld/ar.go diff --git a/src/cmd/internal/ld/arch.go b/src/cmd/link/internal/ld/arch.go index 1b8e1b19ba..1b8e1b19ba 100644 --- a/src/cmd/internal/ld/arch.go +++ b/src/cmd/link/internal/ld/arch.go diff --git a/src/cmd/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 3194bd568e..fd1cdd64bb 100644 --- a/src/cmd/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -32,9 +32,11 @@ package ld import ( + "cmd/internal/gcprog" "cmd/internal/obj" "fmt" "log" + "os" "strings" ) @@ -520,7 +522,7 @@ func relocsym(s *LSym) { } else if HEADTYPE == obj.Hdarwin { if r.Type == obj.R_CALL { if rs.Type != obj.SHOSTOBJ { - o += int64(uint64(Symaddr(rs)) - (rs.Sect.(*Section)).Vaddr) + o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr) } o -= int64(r.Off) // relative to section offset, not symbol } else { @@ -532,7 +534,7 @@ func relocsym(s *LSym) { o += int64(r.Siz) // GNU ld always add VirtualAddress of the .text section to the // relocated address, compensate that. - o -= int64(s.Sect.(*Section).Vaddr - PEBASE) + o -= int64(s.Sect.Vaddr - PEBASE) } else { Diag("unhandled pcrel relocation for %s", headstring) } @@ -963,6 +965,22 @@ func Addstring(s *LSym, str string) int64 { return int64(r) } +// addgostring adds str, as a Go string value, to s. symname is the name of the +// symbol used to define the string data and must be unique per linked object. +func addgostring(s *LSym, symname, str string) { + sym := Linklookup(Ctxt, symname, 0) + if sym.Type != obj.Sxxx { + Diag("duplicate symname in addgostring: %s", symname) + } + sym.Reachable = true + sym.Local = true + sym.Type = obj.SRODATA + sym.Size = int64(len(str)) + sym.P = []byte(str) + Addaddr(Ctxt, s, sym) + adduint(Ctxt, s, uint64(len(str))) +} + func addinitarrdata(s *LSym) { p := s.Name + ".ptr" sp := Linklookup(Ctxt, p, 0) @@ -1028,165 +1046,65 @@ func maxalign(s *LSym, type_ int) int32 { return max } -// Helper object for building GC type programs. -type ProgGen struct { - s *LSym - datasize int32 - data [256 / obj.PointersPerByte]uint8 - pos int64 -} - -func proggeninit(g *ProgGen, s *LSym) { - g.s = s - g.datasize = 0 - g.pos = 0 - g.data = [256 / obj.PointersPerByte]uint8{} -} +const debugGCProg = false -func proggenemit(g *ProgGen, v uint8) { - Adduint8(Ctxt, g.s, v) +type GCProg struct { + sym *LSym + w gcprog.Writer } -// Writes insData block from g->data. -func proggendataflush(g *ProgGen) { - if g.datasize == 0 { - return - } - proggenemit(g, obj.InsData) - proggenemit(g, uint8(g.datasize)) - s := (g.datasize + obj.PointersPerByte - 1) / obj.PointersPerByte - for i := int32(0); i < s; i++ { - proggenemit(g, g.data[i]) +func (p *GCProg) Init(name string) { + p.sym = Linklookup(Ctxt, name, 0) + p.w.Init(p.writeByte) + if debugGCProg { + fmt.Fprintf(os.Stderr, "ld: start GCProg %s\n", name) + p.w.Debug(os.Stderr) } - g.datasize = 0 - g.data = [256 / obj.PointersPerByte]uint8{} } -func proggendata(g *ProgGen, d uint8) { - g.data[g.datasize/obj.PointersPerByte] |= d << uint((g.datasize%obj.PointersPerByte)*obj.BitsPerPointer) - g.datasize++ - if g.datasize == 255 { - proggendataflush(g) - } +func (p *GCProg) writeByte(x byte) { + Adduint8(Ctxt, p.sym, x) } -// Skip v bytes due to alignment, etc. -func proggenskip(g *ProgGen, off int64, v int64) { - for i := off; i < off+v; i++ { - if (i % int64(Thearch.Ptrsize)) == 0 { - proggendata(g, obj.BitsScalar) - } +func (p *GCProg) End(size int64) { + p.w.ZeroUntil(size / int64(Thearch.Ptrsize)) + p.w.End() + if debugGCProg { + fmt.Fprintf(os.Stderr, "ld: end GCProg\n") } } -// Emit insArray instruction. -func proggenarray(g *ProgGen, length int64) { - var i int32 - - proggendataflush(g) - proggenemit(g, obj.InsArray) - for i = 0; i < int32(Thearch.Ptrsize); i, length = i+1, length>>8 { - proggenemit(g, uint8(length)) - } -} - -func proggenarrayend(g *ProgGen) { - proggendataflush(g) - proggenemit(g, obj.InsArrayEnd) -} - -func proggenfini(g *ProgGen, size int64) { - proggenskip(g, g.pos, size-g.pos) - proggendataflush(g) - proggenemit(g, obj.InsEnd) -} - -// This function generates GC pointer info for global variables. -func proggenaddsym(g *ProgGen, s *LSym) { - if s.Size == 0 { +func (p *GCProg) AddSym(s *LSym) { + typ := s.Gotype + // Things without pointers should be in SNOPTRDATA or SNOPTRBSS; + // everything we see should have pointers and should therefore have a type. + if typ == nil { + Diag("missing Go type information for global symbol: %s size %d", s.Name, int(s.Size)) return } - // Skip alignment hole from the previous symbol. - proggenskip(g, g.pos, s.Value-g.pos) - - g.pos += s.Value - g.pos - - // The test for names beginning with . here is meant - // to keep .dynamic and .dynsym from turning up as - // conservative symbols. They should be marked SELFSECT - // and not SDATA, but sometimes that doesn't happen. - // Leave debugging the SDATA issue for the Go rewrite. + ptrsize := int64(Thearch.Ptrsize) + nptr := decodetype_ptrdata(typ) / ptrsize - if s.Gotype == nil && s.Size >= int64(Thearch.Ptrsize) && s.Name[0] != '.' { - // conservative scan - Diag("missing Go type information for global symbol: %s size %d", s.Name, int(s.Size)) - - if (s.Size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) { - Diag("proggenaddsym: unaligned conservative symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos) - } - size := (s.Size + int64(Thearch.Ptrsize) - 1) / int64(Thearch.Ptrsize) * int64(Thearch.Ptrsize) - if size < int64(32*Thearch.Ptrsize) { - // Emit small symbols as data. - for i := int64(0); i < size/int64(Thearch.Ptrsize); i++ { - proggendata(g, obj.BitsPointer) - } - } else { - // Emit large symbols as array. - proggenarray(g, size/int64(Thearch.Ptrsize)) - - proggendata(g, obj.BitsPointer) - proggenarrayend(g) - } + if debugGCProg { + fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr) + } - g.pos = s.Value + size - } else if s.Gotype == nil || decodetype_noptr(s.Gotype) != 0 || s.Size < int64(Thearch.Ptrsize) || s.Name[0] == '.' { - // no scan - if s.Size < int64(32*Thearch.Ptrsize) { - // Emit small symbols as data. - // This case also handles unaligned and tiny symbols, so tread carefully. - for i := s.Value; i < s.Value+s.Size; i++ { - if (i % int64(Thearch.Ptrsize)) == 0 { - proggendata(g, obj.BitsScalar) - } + if decodetype_usegcprog(typ) == 0 { + // Copy pointers from mask into program. + mask := decodetype_gcmask(typ) + for i := int64(0); i < nptr; i++ { + if (mask[i/8]>>uint(i%8))&1 != 0 { + p.w.Ptr(s.Value/ptrsize + i) } - } else { - // Emit large symbols as array. - if (s.Size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) { - Diag("proggenaddsym: unaligned noscan symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos) - } - proggenarray(g, s.Size/int64(Thearch.Ptrsize)) - proggendata(g, obj.BitsScalar) - proggenarrayend(g) - } - - g.pos = s.Value + s.Size - } else if decodetype_usegcprog(s.Gotype) != 0 { - // gc program, copy directly - proggendataflush(g) - - gcprog := decodetype_gcprog(s.Gotype) - size := decodetype_size(s.Gotype) - if (size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) { - Diag("proggenaddsym: unaligned gcprog symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos) - } - for i := int64(0); i < int64(len(gcprog.P)-1); i++ { - proggenemit(g, uint8(gcprog.P[i])) } - g.pos = s.Value + size - } else { - // gc mask, it's small so emit as data - mask := decodetype_gcmask(s.Gotype) - - size := decodetype_size(s.Gotype) - if (size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) { - Diag("proggenaddsym: unaligned gcmask symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos) - } - for i := int64(0); i < size; i += int64(Thearch.Ptrsize) { - proggendata(g, uint8((mask[i/int64(Thearch.Ptrsize)/2]>>uint64((i/int64(Thearch.Ptrsize)%2)*4+2))&obj.BitsMask)) - } - g.pos = s.Value + size + return } + + // Copy program. + prog := decodetype_gcprog(typ) + p.w.ZeroUntil(s.Value / ptrsize) + p.w.Append(prog[4:], nptr) } func growdatsize(datsizep *int64, s *LSym) { @@ -1394,15 +1312,13 @@ func dodata() { /* data */ sect = addsection(&Segdata, ".data", 06) - sect.Align = maxalign(s, obj.SBSS-1) datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.data", 0).Sect = sect Linklookup(Ctxt, "runtime.edata", 0).Sect = sect - gcdata := Linklookup(Ctxt, "runtime.gcdata", 0) - var gen ProgGen - proggeninit(&gen, gcdata) + var gc GCProg + gc.Init("runtime.gcdata") for ; s != nil && s.Type < obj.SBSS; s = s.Next { if s.Type == obj.SINITARR { Ctxt.Cursym = s @@ -1413,33 +1329,30 @@ func dodata() { s.Type = obj.SDATA datsize = aligndatsize(datsize, s) s.Value = int64(uint64(datsize) - sect.Vaddr) - proggenaddsym(&gen, s) // gc + gc.AddSym(s) growdatsize(&datsize, s) } - sect.Length = uint64(datsize) - sect.Vaddr - proggenfini(&gen, int64(sect.Length)) // gc + gc.End(int64(sect.Length)) /* bss */ sect = addsection(&Segdata, ".bss", 06) - sect.Align = maxalign(s, obj.SNOPTRBSS-1) datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.bss", 0).Sect = sect Linklookup(Ctxt, "runtime.ebss", 0).Sect = sect - gcbss := Linklookup(Ctxt, "runtime.gcbss", 0) - proggeninit(&gen, gcbss) + gc = GCProg{} + gc.Init("runtime.gcbss") for ; s != nil && s.Type < obj.SNOPTRBSS; s = s.Next { s.Sect = sect datsize = aligndatsize(datsize, s) s.Value = int64(uint64(datsize) - sect.Vaddr) - proggenaddsym(&gen, s) // gc + gc.AddSym(s) growdatsize(&datsize, s) } - sect.Length = uint64(datsize) - sect.Vaddr - proggenfini(&gen, int64(sect.Length)) // gc + gc.End(int64(sect.Length)) /* pointer-free bss */ sect = addsection(&Segdata, ".noptrbss", 06) @@ -1768,13 +1681,20 @@ func address() { for sym := datap; sym != nil; sym = sym.Next { Ctxt.Cursym = sym if sym.Sect != nil { - sym.Value += int64((sym.Sect.(*Section)).Vaddr) + sym.Value += int64(sym.Sect.Vaddr) } for sub = sym.Sub; sub != nil; sub = sub.Sub { sub.Value += sym.Value } } + if Buildmode == BuildmodeShared { + s := Linklookup(Ctxt, "go.link.abihashbytes", 0) + sectSym := Linklookup(Ctxt, ".note.go.abihash", 0) + s.Sect = sectSym.Sect + s.Value = int64(sectSym.Sect.Vaddr + 16) + } + xdefine("runtime.text", obj.STEXT, int64(text.Vaddr)) xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length)) xdefine("runtime.rodata", obj.SRODATA, int64(rodata.Vaddr)) diff --git a/src/cmd/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 754c89f12b..c1cf4d7181 100644 --- a/src/cmd/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -4,7 +4,10 @@ package ld -import "cmd/internal/obj" +import ( + "cmd/internal/obj" + "debug/elf" +) // Decoding the type.* symbols. This has to be in sync with // ../../runtime/type.go, or more specifically, with what @@ -44,7 +47,7 @@ func decode_inuxi(p []byte, sz int) uint64 { // commonsize returns the size of the common prefix for all type // structures (runtime._type). func commonsize() int { - return 9*Thearch.Ptrsize + 8 + return 8*Thearch.Ptrsize + 8 } // Type.commonType.kind @@ -67,14 +70,43 @@ func decodetype_size(s *LSym) int64 { return int64(decode_inuxi(s.P, Thearch.Ptrsize)) // 0x8 / 0x10 } +// Type.commonType.ptrdata +func decodetype_ptrdata(s *LSym) int64 { + return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10 +} + +// Find the elf.Section of a given shared library that contains a given address. +func findShlibSection(path string, addr uint64) *elf.Section { + for _, shlib := range Ctxt.Shlibs { + if shlib.Path == path { + for _, sect := range shlib.File.Sections { + if sect.Addr <= addr && addr <= sect.Addr+sect.Size { + return sect + } + } + } + } + return nil +} + // Type.commonType.gc -func decodetype_gcprog(s *LSym) *LSym { +func decodetype_gcprog(s *LSym) []byte { if s.Type == obj.SDYNIMPORT { - // The gcprog for "type.$name" is calle "type..gcprog.$name". - x := "type..gcprog." + s.Name[5:] - return Linklookup(Ctxt, x, 0) + addr := decodetype_gcprog_shlib(s) + sect := findShlibSection(s.File, addr) + if sect != nil { + // A gcprog is a 4-byte uint32 indicating length, followed by + // the actual program. + progsize := make([]byte, 4) + sect.ReadAt(progsize, int64(addr-sect.Addr)) + progbytes := make([]byte, Ctxt.Arch.ByteOrder.Uint32(progsize)) + sect.ReadAt(progbytes, int64(addr-sect.Addr+4)) + return append(progsize, progbytes...) + } + Exitf("cannot find gcprog for %s", s.Name) + return nil } - return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize)) + return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)).P } func decodetype_gcprog_shlib(s *LSym) uint64 { @@ -83,9 +115,16 @@ func decodetype_gcprog_shlib(s *LSym) uint64 { func decodetype_gcmask(s *LSym) []byte { if s.Type == obj.SDYNIMPORT { - // ldshlibsyms makes special efforts to read the value - // of gcmask for types defined in that shared library. - return s.gcmask + addr := decodetype_gcprog_shlib(s) + ptrdata := decodetype_ptrdata(s) + sect := findShlibSection(s.File, addr) + if sect != nil { + r := make([]byte, ptrdata/int64(Thearch.Ptrsize)) + sect.ReadAt(r, int64(addr-sect.Addr)) + return r + } + Exitf("cannot find gcmask for %s", s.Name) + return nil } mask := decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)) return mask.P diff --git a/src/cmd/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 6d90404b13..b8fb2e6b55 100644 --- a/src/cmd/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -17,6 +17,7 @@ package ld import ( "cmd/internal/obj" "fmt" + "os" "strings" ) @@ -240,6 +241,7 @@ var abbrevs = [DW_NABRV]DWAbbrev{ {DW_AT_low_pc, DW_FORM_addr}, {DW_AT_high_pc, DW_FORM_addr}, {DW_AT_stmt_list, DW_FORM_data4}, + {DW_AT_comp_dir, DW_FORM_string}, }, }, @@ -694,6 +696,9 @@ func adddwarfrel(sec *LSym, sym *LSym, offsetbase int64, siz int, addend int64) if Iself && Thearch.Thechar == '6' { addend = 0 } + if HEADTYPE == obj.Hdarwin { + addend += sym.Value + } switch siz { case 4: Thearch.Lput(uint32(addend)) @@ -1547,6 +1552,13 @@ func flushunit(dwinfo *DWDie, pc int64, pcsym *LSym, unitstart int64, header_len } } +func getCompilationDir() string { + if dir, err := os.Getwd(); err == nil { + return dir + } + return "/" +} + func writelines() { if linesec == nil { linesec = Linklookup(Ctxt, ".dwarfline", 0) @@ -1571,6 +1583,9 @@ func writelines() { newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, int64(lang), 0) newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart-lineo, 0) newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s) + // OS X linker requires compilation dir or absolute path in comp unit name to output debug info. + compDir := getCompilationDir() + newattr(dwinfo, DW_AT_comp_dir, DW_CLS_STRING, int64(len(compDir)), compDir) // Write .debug_line Line Number Program Header (sec 6.2.4) // Fields marked with (*) must be changed for 64-bit dwarf @@ -1692,11 +1707,17 @@ func writelines() { switch a.Name { case obj.A_AUTO: dt = DW_ABRV_AUTO - offs = int64(a.Aoffset) - int64(Thearch.Ptrsize) + offs = int64(a.Aoffset) + if !haslinkregister() { + offs -= int64(Thearch.Ptrsize) + } case obj.A_PARAM: dt = DW_ABRV_PARAM offs = int64(a.Aoffset) + if haslinkregister() { + offs += int64(Thearch.Ptrsize) + } default: continue @@ -1749,7 +1770,6 @@ func writelines() { const ( CIERESERVE = 16 DATAALIGNMENTFACTOR = -4 - FAKERETURNCOLUMN = 16 // TODO gdb6 doesn't like > 15? ) func putpccfadelta(deltapc int64, cfa int64) { @@ -1778,21 +1798,30 @@ func writeframes() { frameo = Cpos() // Emit the CIE, Section 6.4.1 - Thearch.Lput(CIERESERVE) // initial length, must be multiple of thearch.ptrsize - Thearch.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 + Thearch.Lput(CIERESERVE) // initial length, must be multiple of thearch.ptrsize + Thearch.Lput(0xffffffff) // cid. + Cput(3) // dwarf version (appendix F) + Cput(0) // augmentation "" + uleb128put(1) // code_alignment_factor + sleb128put(DATAALIGNMENTFACTOR) // guess + uleb128put(int64(Thearch.Dwarfreglr)) // return_address_register Cput(DW_CFA_def_cfa) uleb128put(int64(Thearch.Dwarfregsp)) // register SP (**ABI-dependent, defined in l.h) - uleb128put(int64(Thearch.Ptrsize)) // offset + if haslinkregister() { + uleb128put(int64(0)) // offset + } else { + uleb128put(int64(Thearch.Ptrsize)) // offset + } - Cput(DW_CFA_offset + FAKERETURNCOLUMN) // return address - uleb128put(int64(-Thearch.Ptrsize) / DATAALIGNMENTFACTOR) // at cfa - x*4 + Cput(DW_CFA_offset_extended) + uleb128put(int64(Thearch.Dwarfreglr)) // return address + if haslinkregister() { + uleb128put(int64(0) / DATAALIGNMENTFACTOR) // at cfa - 0 + } else { + uleb128put(int64(-Thearch.Ptrsize) / DATAALIGNMENTFACTOR) // at cfa - x*4 + } // 4 is to exclude the length field. pad := CIERESERVE + frameo + 4 - Cpos() @@ -1834,7 +1863,11 @@ func writeframes() { } } - putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value)) + if haslinkregister() { + putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(pcsp.value)) + } else { + putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value)) + } } fdesize = Cpos() - fdeo - 4 // exclude the length field. @@ -2065,6 +2098,14 @@ func writedwarfreloc(s *LSym) int64 { return start } +func addmachodwarfsect(prev *Section, name string) *Section { + sect := addsection(&Segdwarf, name, 04) + sect.Extnum = prev.Extnum + 1 + sym := Linklookup(Ctxt, name, 0) + sym.Sect = sect + return sect +} + /* * This is the main entry point for generating dwarf. After emitting * the mandatory debug_abbrev section, it calls writelines() to set up @@ -2079,8 +2120,33 @@ func Dwarfemitdebugsections() { return } - if Linkmode == LinkExternal && !Iself { - return + if Linkmode == LinkExternal { + if !Iself && HEADTYPE != obj.Hdarwin { + return + } + if HEADTYPE == obj.Hdarwin { + sect := Segdata.Sect + // find the last section. + for sect.Next != nil { + sect = sect.Next + } + sect = addmachodwarfsect(sect, ".debug_abbrev") + sect = addmachodwarfsect(sect, ".debug_line") + sect = addmachodwarfsect(sect, ".debug_frame") + sect = addmachodwarfsect(sect, ".debug_info") + + infosym = Linklookup(Ctxt, ".debug_info", 0) + infosym.Hide = 1 + + abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0) + abbrevsym.Hide = 1 + + linesym = Linklookup(Ctxt, ".debug_line", 0) + linesym.Hide = 1 + + framesym = Linklookup(Ctxt, ".debug_frame", 0) + framesym.Hide = 1 + } } // For diagnostic messages. @@ -2173,6 +2239,15 @@ func Dwarfemitdebugsections() { for Cpos()&7 != 0 { Cput(0) } + if HEADTYPE != obj.Hdarwin { + dwarfemitreloc() + } +} + +func dwarfemitreloc() { + if Debug['w'] != 0 { // disable dwarf + return + } inforeloco = writedwarfreloc(infosec) inforelocsize = Cpos() - inforeloco align(inforelocsize) @@ -2402,14 +2477,15 @@ func dwarfaddelfheaders() { /* * Macho */ -func dwarfaddmachoheaders() { +func dwarfaddmachoheaders(ms *MachoSeg) { if Debug['w'] != 0 { // 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 + fakestart := Rnd(int64(Segdwarf.Fileoff), 0x1000) + addr := Segdata.Vaddr + Segdata.Length nsect := 4 if pubnamessize > 0 { @@ -2425,57 +2501,94 @@ func dwarfaddmachoheaders() { nsect++ } - ms := newMachoSeg("__DWARF", nsect) - ms.fileoffset = uint64(fakestart) - ms.filesize = uint64(abbrevo) - uint64(fakestart) - ms.vaddr = ms.fileoffset + Segdata.Vaddr - Segdata.Fileoff + if Linkmode != LinkExternal { + ms = newMachoSeg("__DWARF", nsect) + ms.fileoffset = uint64(fakestart) + ms.filesize = Segdwarf.Filelen + ms.vaddr = addr + } msect := newMachoSect(ms, "__debug_abbrev", "__DWARF") msect.off = uint32(abbrevo) msect.size = uint64(abbrevsize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 + if abbrevsym != nil { + abbrevsym.Value = int64(msect.addr) + } msect = newMachoSect(ms, "__debug_line", "__DWARF") msect.off = uint32(lineo) msect.size = uint64(linesize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 + if linesym != nil { + linesym.Value = int64(msect.addr) + } + if linerelocsize > 0 { + msect.nreloc = uint32(len(linesec.R)) + msect.reloc = uint32(linereloco) + } msect = newMachoSect(ms, "__debug_frame", "__DWARF") msect.off = uint32(frameo) msect.size = uint64(framesize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 + if framesym != nil { + framesym.Value = int64(msect.addr) + } + if framerelocsize > 0 { + msect.nreloc = uint32(len(framesec.R)) + msect.reloc = uint32(framereloco) + } msect = newMachoSect(ms, "__debug_info", "__DWARF") msect.off = uint32(infoo) msect.size = uint64(infosize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 + if infosym != nil { + infosym.Value = int64(msect.addr) + } + if inforelocsize > 0 { + msect.nreloc = uint32(len(infosec.R)) + msect.reloc = uint32(inforeloco) + } if pubnamessize > 0 { msect := newMachoSect(ms, "__debug_pubnames", "__DWARF") msect.off = uint32(pubnameso) msect.size = uint64(pubnamessize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 } if pubtypessize > 0 { msect := newMachoSect(ms, "__debug_pubtypes", "__DWARF") msect.off = uint32(pubtypeso) msect.size = uint64(pubtypessize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 } if arangessize > 0 { msect := newMachoSect(ms, "__debug_aranges", "__DWARF") msect.off = uint32(arangeso) msect.size = uint64(arangessize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 + if arangesrelocsize > 0 { + msect.nreloc = uint32(len(arangessec.R)) + msect.reloc = uint32(arangesreloco) + } } // TODO(lvd) fix gdb/python to load MachO (16 char section name limit) @@ -2483,8 +2596,9 @@ func dwarfaddmachoheaders() { msect := newMachoSect(ms, "__debug_gdb_scripts", "__DWARF") msect.off = uint32(gdbscripto) msect.size = uint64(gdbscriptsize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 } } diff --git a/src/cmd/internal/ld/dwarf_defs.go b/src/cmd/link/internal/ld/dwarf_defs.go index 61389d9218..61389d9218 100644 --- a/src/cmd/internal/ld/dwarf_defs.go +++ b/src/cmd/link/internal/ld/dwarf_defs.go diff --git a/src/cmd/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 5c17b2da6f..68d21f415c 100644 --- a/src/cmd/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -6,8 +6,12 @@ package ld import ( "cmd/internal/obj" + "crypto/sha1" "encoding/binary" "fmt" + "path/filepath" + "sort" + "strings" ) /* @@ -1199,32 +1203,15 @@ func elfwritebuildinfo() int { return int(sh.size) } -// Go package list note +// Go specific notes const ( ELF_NOTE_GOPKGLIST_TAG = 1 + ELF_NOTE_GOABIHASH_TAG = 2 + ELF_NOTE_GODEPS_TAG = 3 ) var ELF_NOTE_GO_NAME = []byte("GO\x00\x00") -func elfgopkgnote(sh *ElfShdr, startva uint64, resoff uint64) int { - n := len(ELF_NOTE_GO_NAME) + int(Rnd(int64(len(pkglistfornote)), 4)) - return elfnote(sh, startva, resoff, n, false) -} - -func elfwritegopkgnote() int { - sh := elfwritenotehdr(".note.go.pkg-list", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(pkglistfornote)), ELF_NOTE_GOPKGLIST_TAG) - if sh == nil { - return 0 - } - - Cwrite(ELF_NOTE_GO_NAME) - Cwrite(pkglistfornote) - var zero = make([]byte, 4) - Cwrite(zero[:int(Rnd(int64(len(pkglistfornote)), 4)-int64(len(pkglistfornote)))]) - - return int(sh.size) -} - var elfverneed int type Elfaux struct { @@ -1455,6 +1442,24 @@ func elfshalloc(sect *Section) *ElfShdr { func elfshbits(sect *Section) *ElfShdr { sh := elfshalloc(sect) + // If this section has already been set up as a note, we assume type_ and + // flags are already correct, but the other fields still need filling in. + if sh.type_ == SHT_NOTE { + if Linkmode != LinkExternal { + // TODO(mwhudson): the approach here will work OK when + // linking internally for notes that we want to be included + // in a loadable segment (e.g. the abihash note) but not for + // notes that we do not want to be mapped (e.g. the package + // list note). The real fix is probably to define new values + // for LSym.Type corresponding to mapped and unmapped notes + // and handle them in dodata(). + Diag("sh.type_ == SHT_NOTE in elfshbits when linking internally") + } + sh.addralign = uint64(sect.Align) + sh.size = sect.Length + sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr + return sh + } if sh.type_ > 0 { return sh } @@ -1490,13 +1495,16 @@ func elfshbits(sect *Section) *ElfShdr { func elfshreloc(sect *Section) *ElfShdr { // If main section is SHT_NOBITS, nothing to relocate. - // Also nothing to relocate in .shstrtab. + // Also nothing to relocate in .shstrtab or notes. if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { return nil } if sect.Name == ".shstrtab" || sect.Name == ".tbss" { return nil } + if sect.Elfsect.type_ == SHT_NOTE { + return nil + } var prefix string var typ int @@ -1517,7 +1525,7 @@ func elfshreloc(sect *Section) *ElfShdr { sh.entsize += uint64(Thearch.Regsize) } sh.link = uint32(elfshname(".symtab").shnum) - sh.info = uint32((sect.Elfsect.(*ElfShdr)).shnum) + sh.info = uint32(sect.Elfsect.shnum) sh.off = sect.Reloff sh.size = sect.Rellen sh.addralign = uint64(Thearch.Regsize) @@ -1596,6 +1604,29 @@ func Elfemitreloc() { } } +func addgonote(sectionName string, tag uint32, desc []byte) { + s := Linklookup(Ctxt, sectionName, 0) + s.Reachable = true + s.Type = obj.SELFROSECT + // namesz + Adduint32(Ctxt, s, uint32(len(ELF_NOTE_GO_NAME))) + // descsz + Adduint32(Ctxt, s, uint32(len(desc))) + // tag + Adduint32(Ctxt, s, tag) + // name + padding + s.P = append(s.P, ELF_NOTE_GO_NAME...) + for len(s.P)%4 != 0 { + s.P = append(s.P, 0) + } + // desc + padding + s.P = append(s.P, desc...) + for len(s.P)%4 != 0 { + s.P = append(s.P, 0) + } + s.Size = int64(len(s.P)) +} + func doelf() { if !Iself { return @@ -1632,9 +1663,6 @@ func doelf() { if len(buildinfo) > 0 { Addstring(shstrtab, ".note.gnu.build-id") } - if Buildmode == BuildmodeShared { - Addstring(shstrtab, ".note.go.pkg-list") - } Addstring(shstrtab, ".elfdata") Addstring(shstrtab, ".rodata") Addstring(shstrtab, ".typelink") @@ -1668,6 +1696,12 @@ func doelf() { // add a .note.GNU-stack section to mark the stack as non-executable Addstring(shstrtab, ".note.GNU-stack") + + if Buildmode == BuildmodeShared { + Addstring(shstrtab, ".note.go.abihash") + Addstring(shstrtab, ".note.go.pkg-list") + Addstring(shstrtab, ".note.go.deps") + } } hasinitarr := Linkshared @@ -1856,6 +1890,30 @@ func doelf() { // size of .rel(a).plt section. Elfwritedynent(s, DT_DEBUG, 0) } + + if Buildmode == BuildmodeShared { + // The go.link.abihashbytes symbol will be pointed at the appropriate + // part of the .note.go.abihash section in data.go:func address(). + s := Linklookup(Ctxt, "go.link.abihashbytes", 0) + s.Local = true + s.Type = obj.SRODATA + s.Special = 1 + s.Reachable = true + s.Size = int64(sha1.Size) + + sort.Sort(byPkg(Ctxt.Library)) + h := sha1.New() + for _, l := range Ctxt.Library { + h.Write(l.hash) + } + addgonote(".note.go.abihash", ELF_NOTE_GOABIHASH_TAG, h.Sum([]byte{})) + addgonote(".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, []byte(pkglistfornote)) + var deplist []string + for _, shlib := range Ctxt.Shlibs { + deplist = append(deplist, filepath.Base(shlib.Path)) + } + addgonote(".note.go.deps", ELF_NOTE_GODEPS_TAG, []byte(strings.Join(deplist, "\n"))) + } } // Do not write DT_NULL. elfdynhash will finish it. @@ -1922,15 +1980,13 @@ func Asmbelf(symo int64) { eh.phentsize = 0 if Buildmode == BuildmodeShared { - // The package list note we make space for here can get quite - // large. The external linker will re-layout all the sections - // anyway, so making this larger just wastes a little space - // in the intermediate object file, not the final shared - // library. - elfreserve *= 3 - resoff = elfreserve sh := elfshname(".note.go.pkg-list") - resoff -= int64(elfgopkgnote(sh, uint64(startva), uint64(resoff))) + sh.type_ = SHT_NOTE + sh = elfshname(".note.go.abihash") + sh.type_ = SHT_NOTE + sh.flags = SHF_ALLOC + sh = elfshname(".note.go.deps") + sh.type_ = SHT_NOTE } goto elfobj } @@ -2340,15 +2396,99 @@ elfobj: a += int64(elfwritebuildinfo()) } } - if Buildmode == BuildmodeShared { - a += int64(elfwritegopkgnote()) - } if a > elfreserve { Diag("ELFRESERVE too small: %d > %d", a, elfreserve) } } +func Elfadddynsym(ctxt *Link, s *LSym) { + if elf64 { + s.Dynid = int32(Nelfsym) + Nelfsym++ + + d := Linklookup(ctxt, ".dynsym", 0) + + name := s.Extname + Adduint32(ctxt, d, uint32(Addstring(Linklookup(ctxt, ".dynstr", 0), name))) + + /* type */ + t := STB_GLOBAL << 4 + + if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT { + t |= STT_FUNC + } else { + t |= STT_OBJECT + } + Adduint8(ctxt, d, uint8(t)) + + /* reserved */ + Adduint8(ctxt, d, 0) + + /* section where symbol is defined */ + if s.Type == obj.SDYNIMPORT { + Adduint16(ctxt, d, SHN_UNDEF) + } else { + Adduint16(ctxt, d, 1) + } + + /* value */ + if s.Type == obj.SDYNIMPORT { + Adduint64(ctxt, d, 0) + } else { + Addaddr(ctxt, d, s) + } + + /* size of object */ + Adduint64(ctxt, d, uint64(s.Size)) + + if Thearch.Thechar == '6' && s.Cgoexport&CgoExportDynamic == 0 && s.Dynimplib != "" && !seenlib[s.Dynimplib] { + Elfwritedynent(Linklookup(ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(Linklookup(ctxt, ".dynstr", 0), s.Dynimplib))) + } + } else { + s.Dynid = int32(Nelfsym) + Nelfsym++ + + d := Linklookup(ctxt, ".dynsym", 0) + + /* name */ + name := s.Extname + + Adduint32(ctxt, d, uint32(Addstring(Linklookup(ctxt, ".dynstr", 0), name))) + + /* value */ + if s.Type == obj.SDYNIMPORT { + Adduint32(ctxt, d, 0) + } else { + Addaddr(ctxt, d, s) + } + + /* size */ + Adduint32(ctxt, d, 0) + + /* type */ + t := STB_GLOBAL << 4 + + // TODO(mwhudson): presumably the behaviour should actually be the same on both arm and 386. + if Thearch.Thechar == '8' && s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT { + t |= STT_FUNC + } else if Thearch.Thechar == '5' && s.Cgoexport&CgoExportDynamic != 0 && s.Type&obj.SMASK == obj.STEXT { + t |= STT_FUNC + } else { + t |= STT_OBJECT + } + Adduint8(ctxt, d, uint8(t)) + Adduint8(ctxt, d, 0) + + /* shndx */ + if s.Type == obj.SDYNIMPORT { + Adduint16(ctxt, d, SHN_UNDEF) + } else { + Adduint16(ctxt, d, 1) + } + } +} + func ELF32_R_SYM(info uint32) uint32 { return info >> 8 } diff --git a/src/cmd/internal/ld/go.go b/src/cmd/link/internal/ld/go.go index 0223bfae9d..80a6c6ed7d 100644 --- a/src/cmd/internal/ld/go.go +++ b/src/cmd/link/internal/ld/go.go @@ -416,7 +416,11 @@ func loadcgo(file string, pkg string, p string) { // to force a link of foo.so. havedynamic = 1 - Thearch.Adddynlib(lib) + if HEADTYPE == obj.Hdarwin { + Machoadddynlib(lib) + } else { + dynlib = append(dynlib, lib) + } continue } @@ -534,6 +538,41 @@ err: nerrors++ } +var seenlib = make(map[string]bool) + +func adddynlib(lib string) { + if seenlib[lib] || Linkmode == LinkExternal { + return + } + seenlib[lib] = true + + if Iself { + s := Linklookup(Ctxt, ".dynstr", 0) + if s.Size == 0 { + Addstring(s, "") + } + Elfwritedynent(Linklookup(Ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib))) + } else { + Diag("adddynlib: unsupported binary format") + } +} + +func Adddynsym(ctxt *Link, s *LSym) { + if s.Dynid >= 0 || Linkmode == LinkExternal { + return + } + + if Iself { + Elfadddynsym(ctxt, s) + } else if HEADTYPE == obj.Hdarwin { + Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname) + } else if HEADTYPE == obj.Hwindows { + // already taken care of + } else { + Diag("adddynsym: unsupported binary format") + } +} + var markq *LSym var emarkq *LSym @@ -614,15 +653,14 @@ func deadcode() { } if Buildmode == BuildmodeShared { - // Mark all symbols as reachable when building a - // shared library. + // Mark all symbols defined in this library as reachable when + // building a shared library. for s := Ctxt.Allsym; s != nil; s = s.Allsym { - if s.Type != 0 { + if s.Type != 0 && s.Type != obj.SDYNIMPORT { mark(s) } } - mark(Linkrlookup(Ctxt, "main.main", 0)) - mark(Linkrlookup(Ctxt, "main.init", 0)) + markflood() } else { mark(Linklookup(Ctxt, INITENTRY, 0)) if Linkshared && Buildmode == BuildmodeExe { @@ -737,8 +775,11 @@ func addexport() { return } - for i := 0; i < len(dynexp); i++ { - Thearch.Adddynsym(Ctxt, dynexp[i]) + for _, exp := range dynexp { + Adddynsym(Ctxt, exp) + } + for _, lib := range dynlib { + adddynlib(lib) } } diff --git a/src/cmd/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go index 7242301d0f..1068bdd767 100644 --- a/src/cmd/internal/ld/ld.go +++ b/src/cmd/link/internal/ld/ld.go @@ -109,8 +109,8 @@ func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg strin fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlibnamefile: %s\n", obj.Cputime(), srcref, objref, file, pkg, shlibnamefile) } - ctxt.Library = append(ctxt.Library, Library{}) - l := &ctxt.Library[len(ctxt.Library)-1] + ctxt.Library = append(ctxt.Library, &Library{}) + l := ctxt.Library[len(ctxt.Library)-1] l.Objref = objref l.Srcref = srcref l.File = file diff --git a/src/cmd/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index 3efdb75b89..3efdb75b89 100644 --- a/src/cmd/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go diff --git a/src/cmd/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go index 2abfa3336f..2abfa3336f 100644 --- a/src/cmd/internal/ld/ldmacho.go +++ b/src/cmd/link/internal/ld/ldmacho.go diff --git a/src/cmd/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go index b98cf0206b..b98cf0206b 100644 --- a/src/cmd/internal/ld/ldpe.go +++ b/src/cmd/link/internal/ld/ldpe.go diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 184175e026..d87f1801f0 100644 --- a/src/cmd/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -34,7 +34,9 @@ import ( "bufio" "bytes" "cmd/internal/obj" + "crypto/sha1" "debug/elf" + "encoding/binary" "fmt" "io" "io/ioutil" @@ -86,15 +88,14 @@ type Arch struct { Maxalign int Minlc int Dwarfregsp int + Dwarfreglr int Linuxdynld string Freebsddynld string Netbsddynld string Openbsddynld string Dragonflydynld string Solarisdynld string - Adddynlib func(string) Adddynrel func(*LSym, *Reloc) - Adddynsym func(*Link, *LSym) Archinit func() Archreloc func(*Reloc, *LSym, *int64) int Archrelocvariant func(*Reloc, *LSym, int64) int64 @@ -162,7 +163,7 @@ type Section struct { Length uint64 Next *Section Seg *Segment - Elfsect interface{} + Elfsect *ElfShdr Reloff uint64 Rellen uint64 } @@ -178,6 +179,7 @@ var ( Thelinkarch *LinkArch outfile string dynexp []*LSym + dynlib []string ldflag []string havedynamic int Funcalign int @@ -473,7 +475,7 @@ func loadlib() { if Ctxt.Library[i].Shlib != "" { ldshlibsyms(Ctxt.Library[i].Shlib) } else { - objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg) + objfile(Ctxt.Library[i]) } } @@ -519,7 +521,7 @@ func loadlib() { if DynlinkingGo() { Exitf("cannot implicitly include runtime/cgo in a shared library") } - objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg) + objfile(Ctxt.Library[i]) } } } @@ -630,18 +632,18 @@ func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 { return int64(arsize) + SAR_HDR } -func objfile(file string, pkg string) { - pkg = pathtoprefix(pkg) +func objfile(lib *Library) { + pkg := pathtoprefix(lib.Pkg) if Debug['v'] > 1 { - fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), file, pkg) + fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg) } Bso.Flush() var err error var f *obj.Biobuf - f, err = obj.Bopenr(file) + f, err = obj.Bopenr(lib.File) if err != nil { - Exitf("cannot open file %s: %v", file, err) + Exitf("cannot open file %s: %v", lib.File, err) } magbuf := make([]byte, len(ARMAG)) @@ -650,7 +652,7 @@ func objfile(file string, pkg string) { l := obj.Bseek(f, 0, 2) obj.Bseek(f, 0, 0) - ldobj(f, pkg, l, file, file, FileObj) + ldobj(f, pkg, l, lib.File, lib.File, FileObj) obj.Bterm(f) return @@ -663,7 +665,7 @@ func objfile(file string, pkg string) { l := nextar(f, off, &arhdr) var pname string if l <= 0 { - Diag("%s: short read on archive file symbol header", file) + Diag("%s: short read on archive file symbol header", lib.File) goto out } @@ -671,20 +673,29 @@ func objfile(file string, pkg string) { off += l l = nextar(f, off, &arhdr) if l <= 0 { - Diag("%s: short read on archive file symbol header", file) + Diag("%s: short read on archive file symbol header", lib.File) goto out } } if !strings.HasPrefix(arhdr.name, pkgname) { - Diag("%s: cannot find package header", file) + Diag("%s: cannot find package header", lib.File) goto out } + if Buildmode == BuildmodeShared { + before := obj.Boffset(f) + pkgdefBytes := make([]byte, atolwhex(arhdr.size)) + obj.Bread(f, pkgdefBytes) + hash := sha1.Sum(pkgdefBytes) + lib.hash = hash[:] + obj.Bseek(f, before, 0) + } + off += l if Debug['u'] != 0 { - ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef) + ldpkg(f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef) } /* @@ -705,14 +716,14 @@ func objfile(file string, pkg string) { break } if l < 0 { - Exitf("%s: malformed archive", file) + Exitf("%s: malformed archive", lib.File) } off += l - pname = fmt.Sprintf("%s(%s)", file, arhdr.name) + pname = fmt.Sprintf("%s(%s)", lib.File, arhdr.name) l = atolwhex(arhdr.size) - ldobj(f, pkg, l, pname, file, ArchiveObj) + ldobj(f, pkg, l, pname, lib.File, ArchiveObj) } out: @@ -912,7 +923,7 @@ func hostlink() { } if HEADTYPE == obj.Hdarwin { - argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000") + argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000,-headerpad,1144") } if HEADTYPE == obj.Hopenbsd { argv = append(argv, "-Wl,-nopie") @@ -972,15 +983,35 @@ func hostlink() { argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir)) if Linkshared { - for _, shlib := range Ctxt.Shlibs { - dir, base := filepath.Split(shlib) - argv = append(argv, "-L"+dir) - if !rpath.set { - argv = append(argv, "-Wl,-rpath="+dir) + seenDirs := make(map[string]bool) + seenLibs := make(map[string]bool) + addshlib := func(path string) { + dir, base := filepath.Split(path) + if !seenDirs[dir] { + argv = append(argv, "-L"+dir) + if !rpath.set { + argv = append(argv, "-Wl,-rpath="+dir) + } + seenDirs[dir] = true } base = strings.TrimSuffix(base, ".so") base = strings.TrimPrefix(base, "lib") - argv = append(argv, "-l"+base) + if !seenLibs[base] { + argv = append(argv, "-l"+base) + seenLibs[base] = true + } + } + for _, shlib := range Ctxt.Shlibs { + addshlib(shlib.Path) + for _, dep := range shlib.Deps { + if dep == "" { + continue + } + libpath := findshlib(dep) + if libpath != "" { + addshlib(libpath) + } + } } } @@ -1018,6 +1049,31 @@ func hostlink() { if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil { Exitf("running %s failed: %v\n%s", argv[0], err, out) + } else if Debug['v'] != 0 && len(out) > 0 { + fmt.Fprintf(&Bso, "%s", out) + Bso.Flush() + } + + if Debug['s'] == 0 && debug_s == 0 && HEADTYPE == obj.Hdarwin { + // Skip combining dwarf on arm. + if Thearch.Thechar != '5' && Thearch.Thechar != '7' { + dsym := fmt.Sprintf("%s/go.dwarf", tmpdir) + if out, err := exec.Command("dsymutil", "-f", outfile, "-o", dsym).CombinedOutput(); err != nil { + Ctxt.Cursym = nil + Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out) + } + combinedOutput := fmt.Sprintf("%s/go.combined", tmpdir) + if err := machoCombineDwarf(outfile, dsym, combinedOutput); err != nil { + Ctxt.Cursym = nil + Exitf("%s: combining dwarf failed: %v", os.Args[0], err) + } + origOutput := fmt.Sprintf("%s/go.orig", tmpdir) + os.Rename(outfile, origOutput) + if err := os.Rename(combinedOutput, outfile); err != nil { + Ctxt.Cursym = nil + Exitf("%s: rename(%s, %s) failed: %v", os.Args[0], combinedOutput, outfile, err) + } + } } } @@ -1119,22 +1175,86 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when ldobjfile(Ctxt, f, pkg, eof-obj.Boffset(f), pn) } -func ldshlibsyms(shlib string) { - found := false - libpath := "" +func readelfsymboldata(f *elf.File, sym *elf.Symbol) []byte { + data := make([]byte, sym.Size) + sect := f.Sections[sym.Section] + if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE { + Diag("reading %s from non-data section", sym.Name) + } + n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr)) + if uint64(n) != sym.Size { + Diag("reading contents of %s: %v", sym.Name, err) + } + return data +} + +func readwithpad(r io.Reader, sz int32) ([]byte, error) { + data := make([]byte, Rnd(int64(sz), 4)) + _, err := io.ReadFull(r, data) + if err != nil { + return nil, err + } + data = data[:sz] + return data, nil +} + +func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) { + for _, sect := range f.Sections { + if sect.Type != elf.SHT_NOTE { + continue + } + r := sect.Open() + for { + var namesize, descsize, noteType int32 + err := binary.Read(r, f.ByteOrder, &namesize) + if err != nil { + if err == io.EOF { + break + } + return nil, fmt.Errorf("read namesize failed:", err) + } + err = binary.Read(r, f.ByteOrder, &descsize) + if err != nil { + return nil, fmt.Errorf("read descsize failed:", err) + } + err = binary.Read(r, f.ByteOrder, ¬eType) + if err != nil { + return nil, fmt.Errorf("read type failed:", err) + } + noteName, err := readwithpad(r, namesize) + if err != nil { + return nil, fmt.Errorf("read name failed:", err) + } + desc, err := readwithpad(r, descsize) + if err != nil { + return nil, fmt.Errorf("read desc failed:", err) + } + if string(name) == string(noteName) && typ == noteType { + return desc, nil + } + } + } + return nil, nil +} + +func findshlib(shlib string) string { for _, libdir := range Ctxt.Libdir { - libpath = filepath.Join(libdir, shlib) + libpath := filepath.Join(libdir, shlib) if _, err := os.Stat(libpath); err == nil { - found = true - break + return libpath } } - if !found { - Diag("cannot find shared library: %s", shlib) + Diag("cannot find shared library: %s", shlib) + return "" +} + +func ldshlibsyms(shlib string) { + libpath := findshlib(shlib) + if libpath == "" { return } - for _, processedname := range Ctxt.Shlibs { - if processedname == libpath { + for _, processedlib := range Ctxt.Shlibs { + if processedlib.Path == libpath { return } } @@ -1148,85 +1268,48 @@ func ldshlibsyms(shlib string) { Diag("cannot open shared library: %s", libpath) return } - defer f.Close() - syms, err := f.Symbols() + + hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG) + if err != nil { + Diag("cannot read ABI hash from shared library %s: %v", libpath, err) + return + } + + depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG) + if err != nil { + Diag("cannot read dep list from shared library %s: %v", libpath, err) + return + } + deps := strings.Split(string(depsbytes), "\n") + + syms, err := f.DynamicSymbols() if err != nil { Diag("cannot read symbols from shared library: %s", libpath) return } - // If a package has a global variable of a type defined in another shared - // library, we need to know the gcmask used by the type, if any. To support - // this, we read all the runtime.gcbits.* symbols, keep a map of address to - // gcmask, and after we're read all the symbols, read the addresses of the - // gcmasks symbols out of the type data to look up the gcmask for each type. - // This depends on the fact that the runtime.gcbits.* symbols are local (so - // the address is actually present in the type data and we don't have to - // search all relocations to find the ones which correspond to gcmasks) and - // also that the shared library we are linking against has not had the symbol - // table removed. - gcmasks := make(map[uint64][]byte) - types := []*LSym{} for _, s := range syms { if elf.ST_TYPE(s.Info) == elf.STT_NOTYPE || elf.ST_TYPE(s.Info) == elf.STT_SECTION { continue } - if s.Section == elf.SHN_UNDEF { - continue - } - if strings.HasPrefix(s.Name, "_") { - continue - } - if strings.HasPrefix(s.Name, "runtime.gcbits.0x") { - data := make([]byte, s.Size) - sect := f.Sections[s.Section] - if sect.Type == elf.SHT_PROGBITS { - n, err := sect.ReadAt(data, int64(s.Value-sect.Offset)) - if uint64(n) != s.Size { - Diag("Error reading contents of %s: %v", s.Name, err) - } - } - gcmasks[s.Value] = data - } - if elf.ST_BIND(s.Info) != elf.STB_GLOBAL { - continue - } lsym := Linklookup(Ctxt, s.Name, 0) - if lsym.Type != 0 && lsym.Dupok == 0 { + if lsym.Type != 0 && lsym.Type != obj.SDYNIMPORT && lsym.Dupok == 0 { Diag( "Found duplicate symbol %s reading from %s, first found in %s", s.Name, shlib, lsym.File) } lsym.Type = obj.SDYNIMPORT lsym.ElfType = elf.ST_TYPE(s.Info) - lsym.File = libpath - if strings.HasPrefix(lsym.Name, "type.") { - data := make([]byte, s.Size) - sect := f.Sections[s.Section] - if sect.Type == elf.SHT_PROGBITS { - n, err := sect.ReadAt(data, int64(s.Value-sect.Offset)) - if uint64(n) != s.Size { - Diag("Error reading contents of %s: %v", s.Name, err) - } - lsym.P = data - } - if !strings.HasPrefix(lsym.Name, "type..") { - types = append(types, lsym) + if s.Section != elf.SHN_UNDEF { + // Set .File for the library that actually defines the symbol. + lsym.File = libpath + // The decodetype_* functions in decodetype.go need access to + // the type data. + if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") { + lsym.P = readelfsymboldata(f, &s) } } } - for _, t := range types { - if decodetype_noptr(t) != 0 || decodetype_usegcprog(t) != 0 { - continue - } - addr := decodetype_gcprog_shlib(t) - tgcmask, ok := gcmasks[addr] - if !ok { - Diag("bits not found for %s at %d", t.Name, addr) - } - t.gcmask = tgcmask - } - // We might have overwritten some functions above (this tends to happen for the // autogenerated type equality/hashing functions) and we don't want to generated // pcln table entries for these any more so unstitch them from the Textp linked @@ -1254,7 +1337,7 @@ func ldshlibsyms(shlib string) { Ctxt.Etextp = last } - Ctxt.Shlibs = append(Ctxt.Shlibs, libpath) + Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f}) } func mywhatsys() { @@ -1572,12 +1655,11 @@ func Cflush() { } func Cpos() int64 { - Cflush() off, err := coutbuf.f.Seek(0, 1) if err != nil { Exitf("seeking in output [0, 1]: %v", err) } - return off + return off + int64(coutbuf.Buffered()) } func Cseek(p int64) { @@ -1596,7 +1678,7 @@ func Cput(c uint8) { } func usage() { - fmt.Fprintf(os.Stderr, "usage: %cl [options] obj.%c\n", Thearch.Thechar, Thearch.Thechar) + fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n") obj.Flagprint(2) Exit(2) } diff --git a/src/cmd/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index 03da52a981..33b17c5985 100644 --- a/src/cmd/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -34,6 +34,7 @@ import ( "cmd/internal/obj" "debug/elf" "encoding/binary" + "fmt" ) type LSym struct { @@ -77,13 +78,19 @@ type LSym struct { File string Dynimplib string Dynimpvers string - Sect interface{} + Sect *Section Autom *Auto Pcln *Pcln P []byte R []Reloc Local bool - gcmask []byte +} + +func (s *LSym) String() string { + if s.Version == 0 { + return s.Name + } + return fmt.Sprintf("%s<%d>", s.Name, s.Version) } type Reloc struct { @@ -106,6 +113,13 @@ type Auto struct { Gotype *LSym } +type Shlib struct { + Path string + Hash []byte + Deps []string + File *elf.File +} + type Link struct { Thechar int32 Thestring string @@ -122,8 +136,8 @@ type Link struct { Nsymbol int32 Tlsg *LSym Libdir []string - Library []Library - Shlibs []string + Library []*Library + Shlibs []Shlib Tlsoffset int Diag func(string, ...interface{}) Cursym *LSym @@ -149,6 +163,7 @@ type Library struct { File string Pkg string Shlib string + hash []byte } type Pcln struct { diff --git a/src/cmd/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index ceeb7b0f5d..3a8a881d97 100644 --- a/src/cmd/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -443,7 +443,8 @@ func Asmbmacho() { ms = newMachoSeg("", 40) ms.fileoffset = Segtext.Fileoff - ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff + ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff + ms.vsize = ms.filesize } /* segment for zero page */ @@ -561,8 +562,8 @@ func Asmbmacho() { } // TODO: dwarf headers go in ms too - if Debug['s'] == 0 && Linkmode != LinkExternal { - dwarfaddmachoheaders() + if Debug['s'] == 0 { + dwarfaddmachoheaders(ms) } a := machowrite() @@ -705,7 +706,7 @@ func machosymtab() { Diag("missing section for %s", s.Name) Adduint8(Ctxt, symtab, 0) } else { - Adduint8(Ctxt, symtab, uint8((o.Sect.(*Section)).Extnum)) + Adduint8(Ctxt, symtab, uint8(o.Sect.Extnum)) } Adduint16(Ctxt, symtab, 0) // desc adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize) @@ -850,4 +851,5 @@ func Machoemitreloc() { for sect := Segdata.Sect; sect != nil; sect = sect.Next { machorelocsect(sect, datap) } + dwarfemitreloc() } diff --git a/src/cmd/link/internal/ld/macho_combine_dwarf.go b/src/cmd/link/internal/ld/macho_combine_dwarf.go new file mode 100644 index 0000000000..9134373a52 --- /dev/null +++ b/src/cmd/link/internal/ld/macho_combine_dwarf.go @@ -0,0 +1,369 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ld + +import ( + "bytes" + "debug/macho" + "encoding/binary" + "fmt" + "io" + "os" + "reflect" + "unsafe" +) + +var fakedwarf, realdwarf, linkseg *macho.Segment +var dwarfstart, linkstart int64 +var linkoffset uint32 +var machHeader *macho.FileHeader +var mappedHeader []byte + +const ( + LC_LOAD_DYLINKER = 0xe + LC_PREBOUND_DYLIB = 0x10 + LC_LOAD_WEAK_DYLIB = 0x18 + LC_UUID = 0x1b + LC_RPATH = 0x8000001c + LC_CODE_SIGNATURE = 0x1d + LC_SEGMENT_SPLIT_INFO = 0x1e + LC_REEXPORT_DYLIB = 0x8000001f + LC_ENCRYPTION_INFO = 0x21 + LC_DYLD_INFO = 0x22 + LC_DYLD_INFO_ONLY = 0x80000022 + LC_VERSION_MIN_MACOSX = 0x24 + LC_VERSION_MIN_IPHONEOS = 0x25 + LC_FUNCTION_STARTS = 0x26 + LC_MAIN = 0x80000028 + LC_DATA_IN_CODE = 0x29 + LC_SOURCE_VERSION = 0x2A + LC_DYLIB_CODE_SIGN_DRS = 0x2B + LC_ENCRYPTION_INFO_64 = 0x2C + + dwarfMinAlign = 6 // 64 = 1 << 6 + pageAlign = 12 // 4096 = 1 << 12 +) + +type loadCmd struct { + Cmd macho.LoadCmd + Len uint32 +} + +type dyldInfoCmd struct { + Cmd macho.LoadCmd + Len uint32 + RebaseOff, RebaseLen uint32 + BindOff, BindLen uint32 + WeakBindOff, WeakBindLen uint32 + LazyBindOff, LazyBindLen uint32 + ExportOff, ExportLen uint32 +} + +type linkEditDataCmd struct { + Cmd macho.LoadCmd + Len uint32 + DataOff, DataLen uint32 +} + +type encryptionInfoCmd struct { + Cmd macho.LoadCmd + Len uint32 + CryptOff, CryptLen uint32 + CryptId uint32 +} + +type loadCmdReader struct { + offset, next int64 + f *os.File + order binary.ByteOrder +} + +func (r *loadCmdReader) Next() (cmd loadCmd, err error) { + r.offset = r.next + if _, err = r.f.Seek(r.offset, 0); err != nil { + return + } + if err = binary.Read(r.f, r.order, &cmd); err != nil { + return + } + r.next = r.offset + int64(cmd.Len) + return +} + +func (r loadCmdReader) ReadAt(offset int64, data interface{}) error { + if _, err := r.f.Seek(r.offset+offset, 0); err != nil { + return err + } + return binary.Read(r.f, r.order, data) +} + +func (r loadCmdReader) WriteAt(offset int64, data interface{}) error { + if _, err := r.f.Seek(r.offset+offset, 0); err != nil { + return err + } + return binary.Write(r.f, r.order, data) +} + +// machoCombineDwarf merges dwarf info generated by dsymutil into a macho executable. +// With internal linking, DWARF is embedded into the executable, this lets us do the +// same for external linking. +// inexe is the path to the executable with no DWARF. It must have enough room in the macho +// header to add the DWARF sections. (Use ld's -headerpad option) +// dsym is the path to the macho file containing DWARF from dsymutil. +// outexe is the path where the combined executable should be saved. +func machoCombineDwarf(inexe, dsym, outexe string) error { + exef, err := os.Open(inexe) + if err != nil { + return err + } + dwarff, err := os.Open(dsym) + if err != nil { + return err + } + outf, err := os.Create(outexe) + if err != nil { + return err + } + outf.Chmod(0755) + + exem, err := macho.NewFile(exef) + if err != nil { + return err + } + dwarfm, err := macho.NewFile(dwarff) + if err != nil { + return err + } + + // The string table needs to be the last thing in the file + // for code signing to work. So we'll need to move the + // linkedit section, but all the others can be copied directly. + linkseg = exem.Segment("__LINKEDIT") + if linkseg == nil { + return fmt.Errorf("missing __LINKEDIT segment") + } + + if _, err = exef.Seek(0, 0); err != nil { + return err + } + if _, err := io.CopyN(outf, exef, int64(linkseg.Offset)); err != nil { + return err + } + + realdwarf = dwarfm.Segment("__DWARF") + if realdwarf == nil { + return fmt.Errorf("missing __DWARF segment") + } + + // Now copy the dwarf data into the output. + maxalign := uint32(dwarfMinAlign) // + for _, sect := range dwarfm.Sections { + if sect.Align > maxalign { + maxalign = sect.Align + } + } + dwarfstart = machoCalcStart(realdwarf.Offset, linkseg.Offset, maxalign) + if _, err = outf.Seek(dwarfstart, 0); err != nil { + return err + } + + if _, err = dwarff.Seek(int64(realdwarf.Offset), 0); err != nil { + return err + } + if _, err := io.CopyN(outf, dwarff, int64(realdwarf.Filesz)); err != nil { + return err + } + + // And finally the linkedit section. + if _, err = exef.Seek(int64(linkseg.Offset), 0); err != nil { + return err + } + linkstart = machoCalcStart(linkseg.Offset, uint64(dwarfstart)+realdwarf.Filesz, pageAlign) + linkoffset = uint32(linkstart - int64(linkseg.Offset)) + if _, err = outf.Seek(linkstart, 0); err != nil { + return err + } + if _, err := io.Copy(outf, exef); err != nil { + return err + } + + // Now we need to update the headers. + cmdOffset := unsafe.Sizeof(exem.FileHeader) + is64bit := exem.Magic == macho.Magic64 + if is64bit { + // mach_header_64 has one extra uint32. + cmdOffset += unsafe.Sizeof(exem.Magic) + } + + textsect := exem.Section("__text") + if linkseg == nil { + return fmt.Errorf("missing __text section") + } + + dwarfCmdOffset := int64(cmdOffset) + int64(exem.FileHeader.Cmdsz) + availablePadding := int64(textsect.Offset) - dwarfCmdOffset + if availablePadding < int64(realdwarf.Len) { + return fmt.Errorf("No room to add dwarf info. Need at least %d padding bytes, found %d", realdwarf.Len, availablePadding) + } + // First, copy the dwarf load command into the header + if _, err = outf.Seek(dwarfCmdOffset, 0); err != nil { + return err + } + if _, err := io.CopyN(outf, bytes.NewReader(realdwarf.Raw()), int64(realdwarf.Len)); err != nil { + return err + } + + if _, err = outf.Seek(int64(unsafe.Offsetof(exem.FileHeader.Ncmd)), 0); err != nil { + return err + } + if err = binary.Write(outf, exem.ByteOrder, exem.Ncmd+1); err != nil { + return err + } + if err = binary.Write(outf, exem.ByteOrder, exem.Cmdsz+realdwarf.Len); err != nil { + return err + } + + reader := loadCmdReader{next: int64(cmdOffset), f: outf, order: exem.ByteOrder} + for i := uint32(0); i < exem.Ncmd; i++ { + cmd, err := reader.Next() + if err != nil { + return err + } + switch cmd.Cmd { + case macho.LoadCmdSegment64: + err = machoUpdateSegment(reader, &macho.Segment64{}, &macho.Section64{}) + case macho.LoadCmdSegment: + err = machoUpdateSegment(reader, &macho.Segment32{}, &macho.Section32{}) + case LC_DYLD_INFO, LC_DYLD_INFO_ONLY: + err = machoUpdateLoadCommand(reader, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff") + case macho.LoadCmdSymtab: + err = machoUpdateLoadCommand(reader, &macho.SymtabCmd{}, "Symoff", "Stroff") + case macho.LoadCmdDysymtab: + err = machoUpdateLoadCommand(reader, &macho.DysymtabCmd{}, "Tocoffset", "Modtaboff", "Extrefsymoff", "Indirectsymoff", "Extreloff", "Locreloff") + case LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS: + err = machoUpdateLoadCommand(reader, &linkEditDataCmd{}, "DataOff") + case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64: + err = machoUpdateLoadCommand(reader, &encryptionInfoCmd{}, "CryptOff") + case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH: + // Nothing to update + default: + err = fmt.Errorf("Unknown load command 0x%x (%s)\n", int(cmd.Cmd), cmd.Cmd) + } + if err != nil { + return err + } + } + return machoUpdateDwarfHeader(&reader) +} + +// machoUpdateSegment updates the load command for a moved segment. +// Only the linkedit segment should move, and it should have 0 sections. +// seg should be a macho.Segment32 or macho.Segment64 as appropriate. +// sect should be a macho.Section32 or macho.Section64 as appropriate. +func machoUpdateSegment(r loadCmdReader, seg, sect interface{}) error { + if err := r.ReadAt(0, seg); err != nil { + return err + } + segValue := reflect.ValueOf(seg) + offset := reflect.Indirect(segValue).FieldByName("Offset") + + // Only the linkedit segment moved, any thing before that is fine. + if offset.Uint() < linkseg.Offset { + return nil + } + offset.SetUint(offset.Uint() + uint64(linkoffset)) + if err := r.WriteAt(0, seg); err != nil { + return err + } + // There shouldn't be any sections, but just to make sure... + return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset)) +} + +func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, delta uint64) error { + iseg := reflect.Indirect(seg) + nsect := iseg.FieldByName("Nsect").Uint() + if nsect == 0 { + return nil + } + sectOffset := int64(iseg.Type().Size()) + + isect := reflect.Indirect(sect) + offsetField := isect.FieldByName("Offset") + reloffField := isect.FieldByName("Reloff") + sectSize := int64(isect.Type().Size()) + for i := uint64(0); i < nsect; i++ { + if err := r.ReadAt(sectOffset, sect.Interface()); err != nil { + return err + } + if offsetField.Uint() != 0 { + offsetField.SetUint(offsetField.Uint() + delta) + } + if reloffField.Uint() != 0 { + reloffField.SetUint(reloffField.Uint() + delta) + } + if err := r.WriteAt(sectOffset, sect.Interface()); err != nil { + return err + } + sectOffset += sectSize + } + return nil +} + +// machoUpdateDwarfHeader updates the DWARF segment load command. +func machoUpdateDwarfHeader(r *loadCmdReader) error { + var seg, sect interface{} + cmd, err := r.Next() + if err != nil { + return err + } + if cmd.Cmd == macho.LoadCmdSegment64 { + seg = new(macho.Segment64) + sect = new(macho.Section64) + } else { + seg = new(macho.Segment32) + sect = new(macho.Section32) + } + if err := r.ReadAt(0, seg); err != nil { + return err + } + segValue := reflect.ValueOf(seg) + offset := reflect.Indirect(segValue).FieldByName("Offset") + + delta := uint64(dwarfstart) - realdwarf.Offset + offset.SetUint(offset.Uint() + delta) + if err := r.WriteAt(0, seg); err != nil { + return err + } + return machoUpdateSections(*r, segValue, reflect.ValueOf(sect), delta) +} + +func machoUpdateLoadCommand(r loadCmdReader, cmd interface{}, fields ...string) error { + if err := r.ReadAt(0, cmd); err != nil { + return err + } + value := reflect.Indirect(reflect.ValueOf(cmd)) + + for _, name := range fields { + field := value.FieldByName(name) + fieldval := field.Uint() + if fieldval >= linkseg.Offset { + field.SetUint(fieldval + uint64(linkoffset)) + } + } + if err := r.WriteAt(0, cmd); err != nil { + return err + } + return nil +} + +func machoCalcStart(origAddr, newAddr uint64, alignExp uint32) int64 { + align := uint64(1 << alignExp) + if (origAddr % align) == (newAddr % align) { + return int64(newAddr) + } + padding := (align - (newAddr % align)) + padding += origAddr % align + return int64(padding + newAddr) +} diff --git a/src/cmd/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index 3d59323dba..613fcb2a40 100644 --- a/src/cmd/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -347,7 +347,7 @@ func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym { s.Reachable = false } } - if v == 0 && strings.HasPrefix(s.Name, "runtime.gcbits.0x") { + if v == 0 && strings.HasPrefix(s.Name, "runtime.gcbits.") { s.Local = true } return s diff --git a/src/cmd/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index be2568d3b9..be2568d3b9 100644 --- a/src/cmd/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go diff --git a/src/cmd/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index cb82c053d8..cb82c053d8 100644 --- a/src/cmd/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go diff --git a/src/cmd/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go index 8568744c3d..5b24428059 100644 --- a/src/cmd/internal/ld/pobj.go +++ b/src/cmd/link/internal/ld/pobj.go @@ -160,10 +160,9 @@ func Ldmain() { } if outfile == "" { + outfile = "a.out" if HEADTYPE == obj.Hwindows { - outfile = fmt.Sprintf("%c.out.exe", Thearch.Thechar) - } else { - outfile = fmt.Sprintf("%c.out", Thearch.Thechar) + outfile += ".exe" } } diff --git a/src/cmd/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go index 652109d3e3..652109d3e3 100644 --- a/src/cmd/internal/ld/sym.go +++ b/src/cmd/link/internal/ld/sym.go diff --git a/src/cmd/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index d6e79dc00f..7ceb64f941 100644 --- a/src/cmd/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -32,6 +32,8 @@ package ld import ( "cmd/internal/obj" + "fmt" + "path/filepath" "strings" ) @@ -128,12 +130,12 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L Diag("missing section in putelfsym") return } - if xo.Sect.(*Section).Elfsect == nil { + if xo.Sect.Elfsect == nil { Ctxt.Cursym = x Diag("missing ELF section in putelfsym") return } - elfshnum = xo.Sect.(*Section).Elfsect.(*ElfShdr).shnum + elfshnum = xo.Sect.Elfsect.shnum } // One pass for each binding: STB_LOCAL, STB_GLOBAL, @@ -159,7 +161,7 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L off := putelfstr(s) if Linkmode == LinkExternal && elfshnum != SHN_UNDEF { - addr -= int64(xo.Sect.(*Section).Vaddr) + addr -= int64(xo.Sect.Vaddr) } other := STV_DEFAULT if x.Type&obj.SHIDDEN != 0 { @@ -294,6 +296,20 @@ func Vputl(v uint64) { Lputl(uint32(v >> 32)) } +type byPkg []*Library + +func (libs byPkg) Len() int { + return len(libs) +} + +func (libs byPkg) Less(a, b int) bool { + return libs[a].Pkg < libs[b].Pkg +} + +func (libs byPkg) Swap(a, b int) { + libs[a], libs[b] = libs[b], libs[a] +} + func symtab() { dosymtype() @@ -410,6 +426,15 @@ func symtab() { } } + if Buildmode == BuildmodeShared { + abihashgostr := Linklookup(Ctxt, "go.link.abihash."+filepath.Base(outfile), 0) + abihashgostr.Reachable = true + abihashgostr.Type = obj.SRODATA + hashsym := Linklookup(Ctxt, "go.link.abihashbytes", 0) + Addaddr(Ctxt, abihashgostr, hashsym) + adduint(Ctxt, abihashgostr, uint64(hashsym.Size)) + } + // Information about the layout of the executable image for the // runtime to use. Any changes here must be matched by changes to // the definition of moduledata in runtime/symtab.go. @@ -454,6 +479,38 @@ func symtab() { Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0)) adduint(Ctxt, moduledata, uint64(ntypelinks)) adduint(Ctxt, moduledata, uint64(ntypelinks)) + if len(Ctxt.Shlibs) > 0 { + thismodulename := filepath.Base(outfile) + if Buildmode == BuildmodeExe { + // When linking an executable, outfile is just "a.out". Make + // it something slightly more comprehensible. + thismodulename = "the executable" + } + addgostring(moduledata, "go.link.thismodulename", thismodulename) + + modulehashes := Linklookup(Ctxt, "go.link.abihashes", 0) + modulehashes.Reachable = true + modulehashes.Local = true + modulehashes.Type = obj.SRODATA + + for i, shlib := range Ctxt.Shlibs { + // modulehashes[i].modulename + modulename := filepath.Base(shlib.Path) + addgostring(modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename) + + // modulehashes[i].linktimehash + addgostring(modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash)) + + // modulehashes[i].runtimehash + abihash := Linklookup(Ctxt, "go.link.abihash."+modulename, 0) + abihash.Reachable = true + Addaddr(Ctxt, modulehashes, abihash) + } + + Addaddr(Ctxt, moduledata, modulehashes) + adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs))) + adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs))) + } // The rest of moduledata is zero initialized. // When linking an object that does not contain the runtime we are // creating the moduledata from scratch and it does not have a diff --git a/src/cmd/internal/ld/textflag.go b/src/cmd/link/internal/ld/textflag.go index 335f20d21d..335f20d21d 100644 --- a/src/cmd/internal/ld/textflag.go +++ b/src/cmd/link/internal/ld/textflag.go diff --git a/src/cmd/internal/ld/util.go b/src/cmd/link/internal/ld/util.go index f38f05ce9d..f38f05ce9d 100644 --- a/src/cmd/internal/ld/util.go +++ b/src/cmd/link/internal/ld/util.go diff --git a/src/cmd/9l/asm.go b/src/cmd/link/internal/ppc64/asm.go index 257f23e2ab..f070921ecf 100644 --- a/src/cmd/9l/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -28,34 +28,16 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package ppc64 import ( - "cmd/internal/ld" "cmd/internal/obj" + "cmd/link/internal/ld" "encoding/binary" "fmt" "log" ) -func needlib(name string) int { - if name[0] == '\x00' { - return 0 - } - - /* reuse hash code in symbol table */ - p := fmt.Sprintf(".dynlib.%s", name) - - s := ld.Linklookup(ld.Ctxt, p, 0) - - if s.Type == 0 { - s.Type = 100 // avoid SDATA, etc. - return 1 - } - - return 0 -} - func gentext() { var s *ld.LSym var stub *ld.LSym @@ -240,7 +222,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { r.Type = obj.R_ADDR if targ.Type == obj.SDYNIMPORT { // These happen in .toc sections - adddynsym(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) rela := ld.Linklookup(ld.Ctxt, ".rela", 0) ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off)) @@ -520,7 +502,7 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) { return } - adddynsym(ctxt, s) + ld.Adddynsym(ctxt, s) if ld.Iself { plt := ld.Linklookup(ctxt, ".plt", 0) @@ -622,70 +604,6 @@ func ensureglinkresolver() *ld.LSym { return glink } -func adddynsym(ctxt *ld.Link, s *ld.LSym) { - if s.Dynid >= 0 { - return - } - - if ld.Iself { - s.Dynid = int32(ld.Nelfsym) - ld.Nelfsym++ - - d := ld.Linklookup(ctxt, ".dynsym", 0) - - name := s.Extname - ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name))) - - /* type */ - t := ld.STB_GLOBAL << 4 - - if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT { - t |= ld.STT_FUNC - } else { - t |= ld.STT_OBJECT - } - ld.Adduint8(ctxt, d, uint8(t)) - - /* reserved */ - ld.Adduint8(ctxt, d, 0) - - /* section where symbol is defined */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint16(ctxt, d, ld.SHN_UNDEF) - } else { - ld.Adduint16(ctxt, d, 1) - } - - /* value */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint64(ctxt, d, 0) - } else { - ld.Addaddr(ctxt, d, s) - } - - /* size of object */ - ld.Adduint64(ctxt, d, uint64(s.Size)) - } else { - ld.Diag("adddynsym: unsupported binary format") - } -} - -func adddynlib(lib string) { - if needlib(lib) == 0 { - return - } - - if ld.Iself { - s := ld.Linklookup(ld.Ctxt, ".dynstr", 0) - if s.Size == 0 { - ld.Addstring(s, "") - } - ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib))) - } else { - ld.Diag("adddynlib: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/9l/l.go b/src/cmd/link/internal/ppc64/l.go index e7dc102af2..1275a34dbb 100644 --- a/src/cmd/9l/l.go +++ b/src/cmd/link/internal/ppc64/l.go @@ -28,7 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package ppc64 // Writing object files. @@ -71,7 +71,8 @@ const ( MINLC = 4 ) -/* Used by ../ld/dwarf.c */ +/* Used by ../internal/ld/dwarf.go */ const ( DWARFREGSP = 1 + DWARFREGLR = 65 ) diff --git a/src/cmd/9l/obj.go b/src/cmd/link/internal/ppc64/obj.go index 46a92396e4..d663b6ebae 100644 --- a/src/cmd/9l/obj.go +++ b/src/cmd/link/internal/ppc64/obj.go @@ -28,18 +28,18 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package ppc64 import ( - "cmd/internal/ld" "cmd/internal/obj" + "cmd/link/internal/ld" "fmt" "log" ) // Reading object files. -func main() { +func Main() { linkarchinit() ld.Ldmain() } @@ -60,10 +60,9 @@ func linkarchinit() { ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP + ld.Thearch.Dwarfreglr = DWARFREGLR - ld.Thearch.Adddynlib = adddynlib ld.Thearch.Adddynrel = adddynrel - ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant diff --git a/src/cmd/8l/asm.go b/src/cmd/link/internal/x86/asm.go index 7231379108..d30bd48b4e 100644 --- a/src/cmd/8l/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -28,33 +28,15 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package x86 import ( - "cmd/internal/ld" "cmd/internal/obj" + "cmd/link/internal/ld" "fmt" "log" ) -func needlib(name string) int { - if name[0] == '\x00' { - return 0 - } - - /* reuse hash code in symbol table */ - p := fmt.Sprintf(".dynlib.%s", name) - - s := ld.Linklookup(ld.Ctxt, p, 0) - - if s.Type == 0 { - s.Type = 100 // avoid SDATA, etc. - return 1 - } - - return 0 -} - func gentext() { } @@ -202,7 +184,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { break } if ld.Iself { - adddynsym(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) rel := ld.Linklookup(ld.Ctxt, ".rel", 0) ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off)) ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32)) @@ -222,7 +204,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { // 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(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) got := ld.Linklookup(ld.Ctxt, ".got", 0) s.Type = got.Type | obj.SSUB @@ -294,9 +276,9 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int { v = uint32(rs.Dynid) v |= 1 << 27 // external relocation } else { - v = uint32((rs.Sect.(*ld.Section)).Extnum) + v = uint32(rs.Sect.Extnum) if v == 0 { - ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type) + ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type) return -1 } } @@ -420,7 +402,7 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) { return } - adddynsym(ctxt, s) + ld.Adddynsym(ctxt, s) if ld.Iself { plt := ld.Linklookup(ctxt, ".plt", 0) @@ -480,7 +462,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) { return } - adddynsym(ctxt, s) + ld.Adddynsym(ctxt, s) got := ld.Linklookup(ctxt, ".got", 0) s.Got = int32(got.Size) ld.Adduint32(ctxt, got, 0) @@ -496,76 +478,6 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) { } } -func adddynsym(ctxt *ld.Link, s *ld.LSym) { - if s.Dynid >= 0 { - return - } - - if ld.Iself { - s.Dynid = int32(ld.Nelfsym) - ld.Nelfsym++ - - d := ld.Linklookup(ctxt, ".dynsym", 0) - - /* name */ - name := s.Extname - - ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name))) - - /* value */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint32(ctxt, d, 0) - } else { - ld.Addaddr(ctxt, d, s) - } - - /* size */ - ld.Adduint32(ctxt, d, 0) - - /* type */ - t := ld.STB_GLOBAL << 4 - - if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT { - t |= ld.STT_FUNC - } else { - t |= ld.STT_OBJECT - } - ld.Adduint8(ctxt, d, uint8(t)) - ld.Adduint8(ctxt, d, 0) - - /* shndx */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint16(ctxt, d, ld.SHN_UNDEF) - } else { - ld.Adduint16(ctxt, d, 1) - } - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname) - } else if ld.HEADTYPE == obj.Hwindows { - } else // already taken care of - { - ld.Diag("adddynsym: unsupported binary format") - } -} - -func adddynlib(lib string) { - if needlib(lib) == 0 { - return - } - - if ld.Iself { - s := ld.Linklookup(ld.Ctxt, ".dynstr", 0) - if s.Size == 0 { - ld.Addstring(s, "") - } - ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib))) - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Machoadddynlib(lib) - } else if ld.HEADTYPE != obj.Hwindows { - ld.Diag("adddynlib: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) @@ -639,7 +551,7 @@ func asmb() { symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = uint32(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink)) + symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) case obj.Hwindows: symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) diff --git a/src/cmd/8l/l.go b/src/cmd/link/internal/x86/l.go index 60050857c4..8a811ff0a2 100644 --- a/src/cmd/8l/l.go +++ b/src/cmd/link/internal/x86/l.go @@ -28,7 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package x86 const ( thechar = '8' @@ -40,7 +40,8 @@ const ( MINLC = 1 ) -/* Used by ../ld/dwarf.c */ +/* Used by ../internal/ld/dwarf.go */ const ( DWARFREGSP = 4 + DWARFREGLR = 8 ) diff --git a/src/cmd/8l/obj.go b/src/cmd/link/internal/x86/obj.go index 7b490ae87c..ee408f70c6 100644 --- a/src/cmd/8l/obj.go +++ b/src/cmd/link/internal/x86/obj.go @@ -28,18 +28,18 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package main +package x86 import ( - "cmd/internal/ld" "cmd/internal/obj" + "cmd/link/internal/ld" "fmt" "log" ) // Reading object files. -func main() { +func Main() { linkarchinit() ld.Ldmain() } @@ -56,10 +56,9 @@ func linkarchinit() { ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP + ld.Thearch.Dwarfreglr = DWARFREGLR - ld.Thearch.Adddynlib = adddynlib ld.Thearch.Adddynrel = adddynrel - ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant diff --git a/src/cmd/link/main.go b/src/cmd/link/main.go index b23f3f87b0..0e6c34ee0a 100644 --- a/src/cmd/link/main.go +++ b/src/cmd/link/main.go @@ -1,9 +1,34 @@ -// Copyright 2014 The Go Authors. All rights reserved. +// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Placeholder to keep build building. - package main -func main() {} +import ( + "cmd/internal/obj" + "cmd/link/internal/amd64" + "cmd/link/internal/arm" + "cmd/link/internal/arm64" + "cmd/link/internal/ppc64" + "cmd/link/internal/x86" + "fmt" + "os" +) + +func main() { + switch obj.Getgoarch() { + default: + fmt.Fprintf(os.Stderr, "link: unknown architecture %q\n", obj.Getgoarch()) + os.Exit(2) + case "386": + x86.Main() + case "amd64", "amd64p32": + amd64.Main() + case "arm": + arm.Main() + case "arm64": + arm64.Main() + case "ppc64", "ppc64le": + ppc64.Main() + } +} diff --git a/src/cmd/link/auto.go b/src/cmd/newlink/auto.go index 21f6d60827..21f6d60827 100644 --- a/src/cmd/link/auto.go +++ b/src/cmd/newlink/auto.go diff --git a/src/cmd/link/auto_test.go b/src/cmd/newlink/auto_test.go index f99e097a9c..f99e097a9c 100644 --- a/src/cmd/link/auto_test.go +++ b/src/cmd/newlink/auto_test.go diff --git a/src/cmd/link/dead.go b/src/cmd/newlink/dead.go index ee23a61f81..ee23a61f81 100644 --- a/src/cmd/link/dead.go +++ b/src/cmd/newlink/dead.go diff --git a/src/cmd/link/dead_test.go b/src/cmd/newlink/dead_test.go index eb34d0580d..eb34d0580d 100644 --- a/src/cmd/link/dead_test.go +++ b/src/cmd/newlink/dead_test.go diff --git a/src/cmd/link/debug.go b/src/cmd/newlink/debug.go index ee20644fd0..ee20644fd0 100644 --- a/src/cmd/link/debug.go +++ b/src/cmd/newlink/debug.go diff --git a/src/cmd/link/hex_test.go b/src/cmd/newlink/hex_test.go index b76b266558..b76b266558 100644 --- a/src/cmd/link/hex_test.go +++ b/src/cmd/newlink/hex_test.go diff --git a/src/cmd/link/layout.go b/src/cmd/newlink/layout.go index d5c291e255..d5c291e255 100644 --- a/src/cmd/link/layout.go +++ b/src/cmd/newlink/layout.go diff --git a/src/cmd/link/layout_test.go b/src/cmd/newlink/layout_test.go index e5513af35e..e5513af35e 100644 --- a/src/cmd/link/layout_test.go +++ b/src/cmd/newlink/layout_test.go diff --git a/src/cmd/link/link_test.go b/src/cmd/newlink/link_test.go index b5ae15fc71..b5ae15fc71 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/newlink/link_test.go diff --git a/src/cmd/link/load.go b/src/cmd/newlink/load.go index 50602b82a1..50602b82a1 100644 --- a/src/cmd/link/load.go +++ b/src/cmd/newlink/load.go diff --git a/src/cmd/link/macho.go b/src/cmd/newlink/macho.go index 4e5524be9b..4e5524be9b 100644 --- a/src/cmd/link/macho.go +++ b/src/cmd/newlink/macho.go diff --git a/src/cmd/link/macho_test.go b/src/cmd/newlink/macho_test.go index 37c4418b77..37c4418b77 100644 --- a/src/cmd/link/macho_test.go +++ b/src/cmd/newlink/macho_test.go diff --git a/src/cmd/newlink/main.go b/src/cmd/newlink/main.go new file mode 100644 index 0000000000..b23f3f87b0 --- /dev/null +++ b/src/cmd/newlink/main.go @@ -0,0 +1,9 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Placeholder to keep build building. + +package main + +func main() {} diff --git a/src/cmd/link/pclntab.go b/src/cmd/newlink/pclntab.go index 7f8bf52a9b..7f8bf52a9b 100644 --- a/src/cmd/link/pclntab.go +++ b/src/cmd/newlink/pclntab.go diff --git a/src/cmd/link/pclntab_test.go b/src/cmd/newlink/pclntab_test.go index ea80806742..ea80806742 100644 --- a/src/cmd/link/pclntab_test.go +++ b/src/cmd/newlink/pclntab_test.go diff --git a/src/cmd/link/prog.go b/src/cmd/newlink/prog.go index 77fb1ece5b..77fb1ece5b 100644 --- a/src/cmd/link/prog.go +++ b/src/cmd/newlink/prog.go diff --git a/src/cmd/link/prog_test.go b/src/cmd/newlink/prog_test.go index 0853506957..0853506957 100644 --- a/src/cmd/link/prog_test.go +++ b/src/cmd/newlink/prog_test.go diff --git a/src/cmd/link/runtime.go b/src/cmd/newlink/runtime.go index acda2d24d6..acda2d24d6 100644 --- a/src/cmd/link/runtime.go +++ b/src/cmd/newlink/runtime.go diff --git a/src/cmd/link/scan.go b/src/cmd/newlink/scan.go index 7feb0d8900..7feb0d8900 100644 --- a/src/cmd/link/scan.go +++ b/src/cmd/newlink/scan.go diff --git a/src/cmd/link/testdata/Makefile b/src/cmd/newlink/testdata/Makefile index 83e8a05195..83e8a05195 100644 --- a/src/cmd/link/testdata/Makefile +++ b/src/cmd/newlink/testdata/Makefile diff --git a/src/cmd/link/testdata/autosection.6 b/src/cmd/newlink/testdata/autosection.6 Binary files differindex 34aa5d3dbb..34aa5d3dbb 100644 --- a/src/cmd/link/testdata/autosection.6 +++ b/src/cmd/newlink/testdata/autosection.6 diff --git a/src/cmd/link/testdata/autosection.s b/src/cmd/newlink/testdata/autosection.s index e0cb21723e..e0cb21723e 100644 --- a/src/cmd/link/testdata/autosection.s +++ b/src/cmd/newlink/testdata/autosection.s diff --git a/src/cmd/link/testdata/autoweak.6 b/src/cmd/newlink/testdata/autoweak.6 Binary files differindex a86b841171..a86b841171 100644 --- a/src/cmd/link/testdata/autoweak.6 +++ b/src/cmd/newlink/testdata/autoweak.6 diff --git a/src/cmd/link/testdata/autoweak.s b/src/cmd/newlink/testdata/autoweak.s index 2d11330db2..2d11330db2 100644 --- a/src/cmd/link/testdata/autoweak.s +++ b/src/cmd/newlink/testdata/autoweak.s diff --git a/src/cmd/link/testdata/dead.6 b/src/cmd/newlink/testdata/dead.6 Binary files differindex 5e9b09c03e..5e9b09c03e 100644 --- a/src/cmd/link/testdata/dead.6 +++ b/src/cmd/newlink/testdata/dead.6 diff --git a/src/cmd/link/testdata/dead.s b/src/cmd/newlink/testdata/dead.s index 86f31360fa..86f31360fa 100644 --- a/src/cmd/link/testdata/dead.s +++ b/src/cmd/newlink/testdata/dead.s diff --git a/src/cmd/link/testdata/genpcln.go b/src/cmd/newlink/testdata/genpcln.go index c10eaeae91..c10eaeae91 100644 --- a/src/cmd/link/testdata/genpcln.go +++ b/src/cmd/newlink/testdata/genpcln.go diff --git a/src/cmd/link/testdata/hello.6 b/src/cmd/newlink/testdata/hello.6 Binary files differindex 890cbbd016..890cbbd016 100644 --- a/src/cmd/link/testdata/hello.6 +++ b/src/cmd/newlink/testdata/hello.6 diff --git a/src/cmd/link/testdata/hello.s b/src/cmd/newlink/testdata/hello.s index 32ed675033..32ed675033 100644 --- a/src/cmd/link/testdata/hello.s +++ b/src/cmd/newlink/testdata/hello.s diff --git a/src/cmd/link/testdata/layout.6 b/src/cmd/newlink/testdata/layout.6 Binary files differindex 748c836255..748c836255 100644 --- a/src/cmd/link/testdata/layout.6 +++ b/src/cmd/newlink/testdata/layout.6 diff --git a/src/cmd/link/testdata/layout.s b/src/cmd/newlink/testdata/layout.s index c3e55ef49a..c3e55ef49a 100644 --- a/src/cmd/link/testdata/layout.s +++ b/src/cmd/newlink/testdata/layout.s diff --git a/src/cmd/link/testdata/link.hello.darwin.amd64 b/src/cmd/newlink/testdata/link.hello.darwin.amd64 index 4c62eb19b4..4c62eb19b4 100644 --- a/src/cmd/link/testdata/link.hello.darwin.amd64 +++ b/src/cmd/newlink/testdata/link.hello.darwin.amd64 diff --git a/src/cmd/link/testdata/macho.amd64.exit9 b/src/cmd/newlink/testdata/macho.amd64.exit9 index 1adc814c33..1adc814c33 100644 --- a/src/cmd/link/testdata/macho.amd64.exit9 +++ b/src/cmd/newlink/testdata/macho.amd64.exit9 diff --git a/src/cmd/link/testdata/macho.amd64.hello b/src/cmd/newlink/testdata/macho.amd64.hello index 45e70d0ac5..45e70d0ac5 100644 --- a/src/cmd/link/testdata/macho.amd64.hello +++ b/src/cmd/newlink/testdata/macho.amd64.hello diff --git a/src/cmd/link/testdata/macho.amd64.helloro b/src/cmd/newlink/testdata/macho.amd64.helloro index 4b70fbd0fa..4b70fbd0fa 100644 --- a/src/cmd/link/testdata/macho.amd64.helloro +++ b/src/cmd/newlink/testdata/macho.amd64.helloro diff --git a/src/cmd/link/testdata/pclntab.6 b/src/cmd/newlink/testdata/pclntab.6 Binary files differindex 8156698265..8156698265 100644 --- a/src/cmd/link/testdata/pclntab.6 +++ b/src/cmd/newlink/testdata/pclntab.6 diff --git a/src/cmd/link/testdata/pclntab.s b/src/cmd/newlink/testdata/pclntab.s index 12dac70b0c..12dac70b0c 100644 --- a/src/cmd/link/testdata/pclntab.s +++ b/src/cmd/newlink/testdata/pclntab.s diff --git a/src/cmd/link/util.go b/src/cmd/newlink/util.go index b8a6b2cb30..b8a6b2cb30 100644 --- a/src/cmd/link/util.go +++ b/src/cmd/newlink/util.go diff --git a/src/cmd/link/write.go b/src/cmd/newlink/write.go index 7e11b2fe71..7e11b2fe71 100644 --- a/src/cmd/link/write.go +++ b/src/cmd/newlink/write.go diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go index 9c33f4f98b..cd32020501 100644 --- a/src/cmd/pack/pack_test.go +++ b/src/cmd/pack/pack_test.go @@ -13,7 +13,6 @@ import ( "os" "os/exec" "path/filepath" - "regexp" "runtime" "testing" "time" @@ -223,16 +222,14 @@ func TestHello(t *testing.T) { t.Fatal(err) } - char := findChar(t, dir) - run := func(args ...string) string { return doRun(t, dir, args...) } run("go", "build", "cmd/pack") // writes pack binary to dir - run("go", "tool", char+"g", "hello.go") - run("./pack", "grc", "hello.a", "hello."+char) - run("go", "tool", char+"l", "-o", "a.out", "hello.a") + run("go", "tool", "compile", "hello.go") + run("./pack", "grc", "hello.a", "hello.o") + run("go", "tool", "link", "-o", "a.out", "hello.a") out := run("./a.out") if out != "hello world\n" { t.Fatalf("incorrect output: %q, want %q", out, "hello world\n") @@ -297,17 +294,15 @@ func TestLargeDefs(t *testing.T) { t.Fatal(err) } - char := findChar(t, dir) - run := func(args ...string) string { return doRun(t, dir, args...) } run("go", "build", "cmd/pack") // writes pack binary to dir - run("go", "tool", char+"g", "large.go") - run("./pack", "grc", "large.a", "large."+char) - run("go", "tool", char+"g", "-I", ".", "main.go") - run("go", "tool", char+"l", "-L", ".", "-o", "a.out", "main."+char) + run("go", "tool", "compile", "large.go") + run("./pack", "grc", "large.a", "large.o") + run("go", "tool", "compile", "-I", ".", "main.go") + run("go", "tool", "link", "-L", ".", "-o", "a.out", "main.o") out := run("./a.out") if out != "ok\n" { t.Fatalf("incorrect output: %q, want %q", out, "ok\n") @@ -325,20 +320,6 @@ func doRun(t *testing.T, dir string, args ...string) string { return string(out) } -// findChar returns the architecture character for the go command. -func findChar(t *testing.T, dir string) string { - out := doRun(t, dir, "go", "env") - re, err := regexp.Compile(`\s*GOCHAR=['"]?(\w)['"]?`) - if err != nil { - t.Fatal(err) - } - fields := re.FindStringSubmatch(out) - if fields == nil { - t.Fatal("cannot find GOCHAR in 'go env' output:\n", out) - } - return fields[1] -} - // Fake implementation of files. var helloFile = &FakeFile{ diff --git a/src/cmd/pprof/internal/profile/legacy_profile.go b/src/cmd/pprof/internal/profile/legacy_profile.go index bfc8110e45..e4c92cdd19 100644 --- a/src/cmd/pprof/internal/profile/legacy_profile.go +++ b/src/cmd/pprof/internal/profile/legacy_profile.go @@ -554,9 +554,10 @@ func parseHeap(b []byte) (p *Profile, err error) { } } - if l = strings.TrimSpace(l); l == "" { + if isSpaceOrComment(l) { continue } + l = strings.TrimSpace(l) if sectionTrigger(l) != unrecognizedSection { break diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go index 5c7b0b71b1..53c0fab174 100644 --- a/src/cmd/yacc/yacc.go +++ b/src/cmd/yacc/yacc.go @@ -128,6 +128,7 @@ const ( TYPEDEF TYPENAME UNION + ERROR ) const ENDFILE = 0 @@ -325,8 +326,24 @@ var resrv = []Resrv{ {"type", TYPEDEF}, {"union", UNION}, {"struct", UNION}, + {"error", ERROR}, } +type Error struct { + lineno int + tokens []string + msg string +} + +var errors []Error + +type Row struct { + actions []int + defaultAction int +} + +var stateTable []Row + var zznewstate = 0 const EOF = -1 @@ -402,6 +419,27 @@ outer: } start = chfind(1, tokname) + case ERROR: + lno := lineno + var tokens []string + for { + t := gettok() + if t == ':' { + break + } + if t != IDENTIFIER && t != IDENTCOLON { + errorf("bad syntax in %%error") + } + tokens = append(tokens, tokname) + if t == IDENTCOLON { + break + } + } + if gettok() != IDENTIFIER { + errorf("bad syntax in %%error") + } + errors = append(errors, Error{lno, tokens, tokname}) + case TYPEDEF: t = gettok() if t != TYPENAME { @@ -2155,6 +2193,10 @@ func output() { } fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix) + if len(errors) > 0 { + stateTable = make([]Row, nstate) + } + noset := mkset() // output the stuff for state i @@ -2368,6 +2410,15 @@ func wrstate(i int) { var j0, j1, u int var pp, qq int + if len(errors) > 0 { + actions := append([]int(nil), temp1...) + defaultAction := ERRCODE + if lastred != 0 { + defaultAction = -lastred + } + stateTable[i] = Row{actions, defaultAction} + } + if foutput == nil { return } @@ -2914,6 +2965,20 @@ func others() { } fmt.Fprintf(ftable, "%d,\n}\n", 0) + // Custom error messages. + fmt.Fprintf(ftable, "\n") + fmt.Fprintf(ftable, "var %sErrorMessages = [...]struct {\n", prefix) + fmt.Fprintf(ftable, "\tstate int\n") + fmt.Fprintf(ftable, "\ttoken int\n") + fmt.Fprintf(ftable, "\tmsg string\n") + fmt.Fprintf(ftable, "}{\n") + for _, error := range errors { + lineno = error.lineno + state, token := runMachine(error.tokens) + fmt.Fprintf(ftable, "\t{%v, %v, %s},\n", state, token, error.msg) + } + fmt.Fprintf(ftable, "}\n") + // copy parser text ch := getrune(finput) for ch != EOF { @@ -2932,6 +2997,59 @@ func others() { fmt.Fprintf(ftable, "%v", parts[1]) } +func runMachine(tokens []string) (state, token int) { + var stack []int + i := 0 + token = -1 + +Loop: + if token < 0 { + token = chfind(2, tokens[i]) + i++ + } + + row := stateTable[state] + + c := token + if token >= NTBASE { + c = token - NTBASE + ntokens + } + action := row.actions[c] + if action == 0 { + action = row.defaultAction + } + + switch { + case action == ACCEPTCODE: + errorf("tokens are accepted") + return + case action == ERRCODE: + if token >= NTBASE { + errorf("error at non-terminal token %s", symnam(token)) + } + return + case action > 0: + // Shift to state action. + stack = append(stack, state) + state = action + token = -1 + goto Loop + default: + // Reduce by production -action. + prod := prdptr[-action] + if rhsLen := len(prod) - 2; rhsLen > 0 { + n := len(stack) - rhsLen + state = stack[n] + stack = stack[:n] + } + if token >= 0 { + i-- + } + token = prod[0] + goto Loop + } +} + func arout(s string, v []int, n int) { s = prefix + s fmt.Fprintf(ftable, "var %v = [...]int{\n", s) @@ -3212,7 +3330,6 @@ type $$Parser interface { type $$ParserImpl struct { lookahead func() int - state func() int } func (p *$$ParserImpl) Lookahead() int { @@ -3222,7 +3339,6 @@ func (p *$$ParserImpl) Lookahead() int { func $$NewParser() $$Parser { p := &$$ParserImpl{ lookahead: func() int { return -1 }, - state: func() int { return -1 }, } return p } @@ -3253,6 +3369,13 @@ func $$ErrorMessage(state, lookAhead int) string { if !$$ErrorVerbose { return "syntax error" } + + for _, e := range $$ErrorMessages { + if e.state == state && e.token == lookAhead { + return "syntax error: " + e.msg + } + } + res := "syntax error: unexpected " + $$Tokname(lookAhead) // To match Bison, suggest at most four expected tokens. @@ -3355,7 +3478,6 @@ func ($$rcvr *$$ParserImpl) Parse($$lex $$Lexer) int { $$state := 0 $$char := -1 $$token := -1 // $$char translated into internal numbering - $$rcvr.state = func() int { return $$state } $$rcvr.lookahead = func() int { return $$char } defer func() { // Make sure we report no lookahead when not parsing. |
